We used to mark call to noreturn functions as killers, but this is not
correct.
Note that this is a temporary solution, we need to explicitly handle
such situations.
Generated code now either jumps to `anypc` or `unexpectedpc`. The latter
one is to be considered a safety measure and will be populated with an
unreachable instruction on the decompilation pipeline.
This commit makes `PCH::getUniqueJumpTarget` more robust:
1. We bail out only if we find a non-constant write to a field of
`MetaAddress` for which we already have a value. Before, any
non-constant write would lead to bailing out.
2. In case we meet an helper, we now bail out only if we didn't saw any
write to a portion of the `MetaAddress`.
This commit extracts a plain `struct` from the `MetaAddress` class. This
enables us to use `MetaAddress` from C and therefore, runtime.
The definition of such `struct`, `PlainMetaAddress`, is in
`PlainMetaAddress.h`, which is included by `early-linked.c`.
A function to print the content of a `PlainMetaAddress` has also been
introduced.
Also, anticipating the linkage of `early-linked.c` triggered a
superflous assertion in `CPUStateAccessAnalysis`. This commit removes
it.
* Introduce GCBI::buildDispatcher
* Introduce GCBI::getJumpTarget{,Block} and GCBI::getBlocksGeneratedByPC
to easily map `BasicBlock *` to jump targets and viceversa.
* PCH::buildDispatcher now returns a list of the newly created basic
blocks.
* Other minor changes
Changes include:
- `getFunctionCall` has been moved in IRHelpers.h
- `getFallthrough` and `getFunctionCallCallee`
have been simplified and added in IRHelpers.h (their old versions
have been removed respectively from FCI.h and revng.h)
- `FCI::getCall` and `FCI::isCall` have been removed
due to redundancy with `getFunctionCall`.
This commit fixes a bug that lead to be unable to instantiate from a
`Module` `ProgramCounterHandler`. The reason for this was that
`ProgramCounterHandler` was using `Module::getGlobalVariable` which, by
default, ignores variables with internal linkage.
This assertion was executed in the `runOnModule` method of the GCBI
pass, but it is too strict.
Asserting that Dispatcher != nullptr during the execution of the pass
prevents the pass from successfully running on a Module without a
Dispatcher.
This is unfortunate, because some passes that depend on GCBI in revng-c
actually do that. They do so because they are not really interested in
the Dispatcher at all. They only use GCBI to access information on the
Stack Pointer.
In fact, the check for Dispatcher being != from nullptr is already
performed also in the `dispatcher()` method which is the sane thing to
do. This commit removes the assertion from the `runOnModule` method and
leaves it in the `dispatcher` method.
This allows to run the pass successfully even on a Module without the
Dispatcher, while not changing the contract of this pass (i.e. that when
you call the `dispatcher` method you get a nonnull pointer).
This commit introduces the PruneRetSuccessors pass, whose role is to
identify all the indirect jumps whose devirtualized destinations
correspond to return addresses. In fact, they are most likely to be
return instructions and devirtualizing them is always detrimental.
After combining two AS objects, removing an ASOContent in the cleanup
phase may lead to a mismatch in the CSVs promoted to function argument,
with some registers actually being used. In most cases, this results in
promoting only one or few alive registers as function argument.
We used to accidentaly call `resetCacheMustHit` on the just popped
element of the set, resulting in an out-of-bounds access within the
container.
This bug has been spotted thanks to AddressSanitizer.
Add an additional opaque store the the `pc` after each function call in
the enforced functions. In this way, when the `pc` will be promoted to
an alloca, we won't have an inconsistent state of the IR (the callee
cannot propagate the correct value of pc, the safety check introduced by
the function isolation will always be false, and llvm will place a
`llvm.assume` which will in turn make the rest of the code dead and
purged by an additional `-simplifycfg`).
This commit drops the `--isolate-no-safety-checks` flags since we
adopted a new approach later on in the decompilation pipeline, i.e.,
dropping calls to `raise_exception_helper` and running dead code
elimination.
FunctionIsolation used to base its work on calls to the marker function
`function_call`, as opposed to information provided by the StackAnalysis
(i.e., `revng.member.type` along with `func.call`).
This also affected EnforceABI, which took care of finishing the work
left over by FunctionIsolation. This was hackish and inelegant.
This commit makes FunctionIsolation work exclusively employing
information from StackAnalysis and purges away code that is no longer
necessary from EnforceABI.
We used to detect callee-saved registers only by checking if their final
value was identical to the initial one. However, the need for a more
precise heuristic emerged: we now also check if at least on of the stack
slots contains that same value.
This commit fixes a subtle bug that was preventing us from correctly
considering the effects of function calls during ABI analysis.
Specifically, when merging information from the call site to the caller,
in case the caller did not provide any information about a certain
slots, we used the `DefaultMap::Default` field, which is the correct
thing to do, except for the fact that, in two methods, the `Default`
field was being updated to early.
This basically had the effect of not considering arguments of function
calls as used, e.g., in URAOF.
When the `--enforce-no-safety-checks` flag is passed during the
enforcing, we avoid emitting the inlined `function_dispatcher` and we
emit instead a call to an `indirect_handle` disposable call created on
the fly to respect the ABI information on the callsite.
Under certain conditions, we ended up having code in the ABI IR which
was not reachable. This was due to the fact that a certain instruction
was initially detected as an indirect call, triggering inclusion in the
function of the fallthrough code, and then as a return, which has no
successors within the function.
This commit simply prunes the ABI IR in the finalization method.
EnforceABI promotes global variables representing parts of the CPU
states to arguments and return values of isolated functions.
This commit enables the promotion of CSV that are used in isolated
functions only indirectly, through `ConstantExpr`s casts.