This commit further reduces the time spent in AVI by considering all the
function calls as indirect. In fact, we currently don't handle indirect
jumps whose target is affected by computation happening before a
function call.
This commit greatly improves the performance by ensuring that, when
computing the set of nodes we want to consider for AVI, we do not
traverse the dispatcher.
Doing so, means including *a lot* of irrelevant nodes and wasting a lot
of computation, since the CFG usually is not influenced by stuff
happening before an indirect jump.
In at least a situation the speedup is in the order of 20x, however this
depends on the size of the binary, since traversing the dispatcher means
including all the binary in the computations (as opposed to just the set
of blocks involved in the dataflow to compute a certain expression).
QEMU helpers are compiled with -O0. This led the functions in the QEMU
helper module to have the `optnone` attribute, preventing any
optimization.
This has now been fixed on the QEMU side with the following flags:
clang -Xclang -disable-O0-optnone
We used to stop the harvesting process when the harvesting process was
no longer able to identify new jump targets, even if new CFG edges have
been identified.
This approach prevented to discover additional parts of the CFG thanks
to the increased accuracy gained by a more accurate CFG. This effect is
particularly visible when we have jump tables that can be reached only
through other jump tables.
This enables us to handle situations where the comparison against the
switch value is performed on the lower 32 bits, but the address
computations uses the full 64 bits.
cmp edi,0x23
ja ...
movsxd rdx,DWORD PTR [rcx+rdi*4]
Note that this does not solve all these situations yet.
This commit also introduces a reference output for the new
switch-jump-table-32-bit-comparison test case.
AVI used to work on a cloned root that was initializing the pc to the
program entry point. Under certain conditions, this led to DCE almost
all of the code.
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 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
After the discovery of new code to be translated, the calls to `newpc`
can be stripped of their variadic arguments (reference to local vars)
in order to let SROA perform more optimization.
Sorting the BasicBlocks on which DisjointRanges works is detrimental for
performance. Using a random order takes less time. This is due to the
fact that the number of BasicBlocks to analyze is significantly smaller
than the whole list of BasicBlocks.
This simple commit reduces the number of times we query the size of the
`BasicBlock` list of a `Function` during the final reodering of blocks
before emission.
This change introduces a 25% speedup when lifting `/bin/bash`.
It is important to let the pass manager go out of scope ASAP:
LazyValueInfo registers a lot of callbacks to get notified when a Value
is destroyed, slowing down OptimizedFunction->eraseFromParent
enormously.
This commit introduces a speedup of approximately 25% when lifting
`/bin/bash`.
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.
Rationale: it is a widespread practice, both in revng and in projects
that depend on it, to write verification functions that check specific
properties hold after different transformations on various data
structures.
Often, these verification function are very useful for debugging and
during development, but they can be very costly and we don't want to
always execute them at runtime.
This patch adds a global public Logger, called VerifyLog, that can be
enabled with the --debug-log=verify command line argument.
This Logger is intended to be used in revng and in projects that depend
on it, as a guard for costly calls to verification functions that do not
need to be performed on a typical execution, but only when debugging.
For now the only user is JumpTargetManager, but other uses are already
envisioned.
This commit adds calls to
`legacy::FunctionPassManager::doInitialization()` and
`legacy::FunctionPassManager::doFinalization()` before and after calls
to `legacy::FunctionPassManager::run()`.
`legacy::FunctionPassManager`s must be explicitly initialized before
running and finalized after running.
Given that we used these managers only in two places and their are the
only ones that need explicit initialization and finalization, we forgot
to do it.
This caused problems with recent versions of llvm.
In particular, when compiled with aggressive optimizations (at least
`-O2`), missed initialization resulted in null pointers being
dereferenced, causing crashes.
The crashes were caused by the compiler optimizing away `nullptr` checks
on values returned from `getPSI`.