Previously, the `macaw-x86` semantics for `call` would retrieve the call target
*after* pushing the next instruction's address to the stack, but if the call
target involves the stack pointer, then this would mean that it would get the
next instruction's address when retrieving the call target. This is not what is
intended!
This patch fixes the issue by always retrieving the call target *before*
pushing the next instruction's address to the stack. I have added a test case
to the `macaw-x86-symbolic` test suite which demonstrates that this fix works
as intended.
Fixes#420.
GHC 9.8 is better about reporting orphan type family instances, which are used
in various spots in Macaw. Enable `-Wno-orphans` to suppress these warnings.
This adds the necessary changes to `macaw-ppc-symbolic` and `macaw-ppc` in
order to simulate system calls, similarly to how it is done when simulating
x86-64 and AArch32 code:
* In `macaw-ppc`, remove `PPCSyscall` from `TermStmt` and instead make it a
constructor for `PPCPrimFn`. (Note that there are some minor discrepancies
between which registers are used in PPC32 versus PPC64, which we explain in
the Haddocks for the new `PPCSyscall` constructor.)
* Update `macaw-ppc`'s `ppcInstructionMatcher` function so that calls to the
`sc` (system call) instruction make use of `PPCSyscall`.
* Update `macaw-ppc-symbolic`'s `ppcGenFn` function to make it possible to hook
into PPC system calls using `MacawLookupSyscallHandle`.
Fixes#387.
Now that we can load RISC-V relocations in `macaw` (building on top of the work
in GaloisInc/elf-edit#45), this patch adds PLT stub heuristics for RISC-V
binaries. I have added some test cases in `macaw-riscv-symbolic` which
demonstrate that the basic idea works.
Note that due to #416, these test cases will print warnings when loaded into
`macaw`. These warnings are ultimately harmless, however, as the same
relocations are loaded at the same addresses multiple times, which causes no
change in behavior.
Fixes#414.
This builds on top of the work in GaloisInc/elf-edit#45. For now, I only add
support for a select few relocation types, leaving the rest as future work.
This paves a way for an eventual fix for #414.
See https://github.com/GaloisInc/macaw/issues/412 for the remaining task of
allowing the return types of `GenArchVals`' `{lookup,update}Reg` functions to
indicate the possibility of an error.
This adds the necessary plumbing to simulate Macaw-lifted RISC-V binaries using
`macaw-symbolic`. This proves relatively straightforward, given that RISC-V
does not have a lot of special primitive functions or statements to deal with.
I have also added a basic test suite to ensure that `macaw-riscv-symbolic`
works on end-to-end examples.
Fixes#409.
Given some symbolic value, @x@, we'd like to compute its
possible upper and lower bounds after it is truncated to @w@ bits.
To do this, we first find the bound of x by (recursively) calling `exprRangePred`.
This bound is a statement of the following form (see `RangePred` for more info):
"r bits of x are bounded between @low@ and @high@".
Then, we check the following:
- If x has a bound (r, l, w)
AND
- If r is less than or equal to w
=> Pass-through the bound (r, l, w)
Otherwise, we deem x "unbounded"
Declaring x unbounded in the second case seems to throw away useful
information that causes many jump tables to remain unclassified.
We attempt to improve on that in this commit.
Consider an example where x is bounded by (64, 0, 10)
(that is, the 64 bits of x are constrained to be between 0 and 10)
and we want to find the bound of truncating x to 8 bits.
With the current logic, since 64 > 8, we'd declare x unbounded.
However, the bound (8, 0, 10) should also be valid: if 64 bits of
x are bounded to [0, 10], then surely 8 bits of x also lie between
0 and 10.
If the upper bound is instead larger than the largest 8-bit value, we
can truncate it to the largest value.
For example, (64, 0, 10000) becomes (8, 0, 255).
Instead of losing the bound completely, we're able to tighten it!
For some reason we were very conservative in our support or abstract
operations over the processor state in the `RegisterUse` analysis.
In particular, we were failing to process code such as:
r23 := (bv_and r21 (0xfffffffffffffff0 :: [64]))
whose goal is to align the value in r21 at a 16-byte boundary.
This resulted in us failing to analyze some code that was realigning its
stack pointer. With this change, the same code succeeds at propagating
the abstract stack pointer offset forward.
When converting a Macaw value with the Macaw type `TupleType [x_1, ..., x_n]`
to Crucible, the resulting Crucible value will have the Crucible type
`StructType (EmptyCtx ::> ToCrucibleType x_n ::> ... ::> ToCrucibleType x_1)`.
(See `macawListToCrucible(M)` in `Data.Macaw.Symbolic.PersistentState` for
where this is implemented.) Note that the order of the tuple's fields is
reversed in the process of converting it to a Crucible struct. This is a
convention that one must keep in mind when dealing with Macaw tuples at the
Crucible level.
As it turns out, the part of `macaw-x86-symbolic` reponsible for interpreting
the semantics of the `idiv` instruction (for signed quotient/remainder) and the
`div` instruction (for unsigned quotient/remainder) were _not_ respecting this
convention. This is because the `macaw-x86-symbolic` semantics were returning a
Crucible struct consisting of `Empty :> quotient :> remainder)`, but at the
Macaw level, this was interpreted as the tuple `(remainder, quotient)`, which
is the opposite of the intended order. This led to subtle bugs such as those
observed in #393.
The solution is straightforward: have the `macaw-x86-symbolic` semantics
compute `Empty :> remainder :> quotient` instead. Somewhat counterintuitive,
but it does work.
Fixes#393.
This bumps the `what4` submodule to the 1.6.* version series and updates the
`.cabal` files in the `macaw` repo accordingly.
Bumping the `what4` submodule also requires bringing in corresponding changes
in the `crucible`, `llvm-pretty`, and `llvm-pretty-bc-parser` submodules, so I
have done that as well.
Refinement frequently tried to add duplicate edges to the cfg
when encountering jump tables, since jump tables often have common targets
(e.g. because of a `default` case).
Instead of panicking, this is now handled as a benign case where no edge
insertion is needed.