This commit does the following:
* It drops `revamb-dump` and transforms all the passes it featured in
passes that can be used directly from `opt`.
* It rename `revamb` to `revng-lift`.
* It introduces a script called `revng` which acts as a driver for the
whole rev.ng project. It replaces `translate`, `revcc`,
`csv-to-ld-options` and `revamb-dump`, since it offers an `opt`
subcommand which allows to easily invoke all the analysis passes.
* It makes the project a CMake package that can be easily used
externally.
* It allows to easily create libraries of analysis to use through
`revng-opt`.
The `FunctionCallIdentification` analysis now provides a custom view on
the CFG where 1) dispatcher-related basic blocks are absent, 2) nodes
performing functions calls have an edge to their return address and 3)
nodes ending with a return instruction have no successor.
This CFG is now employed by the reaching definitions analysis and OSRA.
Additionally, the implementation of the `visitSuccessors` and
`visitPredecessors` method has been reviewed. It now consists in a class
that needs to be inherited and for which two methods should be
implemented, one to perform the visit of a block and another one to
enumerate the successors.
In addition, all the users of `visitSuccessors`/`visitPredecessors` have
been updated, a simple set of tests has been introduced and
`GeneratedCodeBasicInfo::visitPredecessors` has been dropped.
This commit fixes a problem that led to use SET to discover very very
simple jump targets: the return addresses of functions call.
Since in this situation, for each call, we needed to run SET, this
commit leads to a *huge* improvements in terms of translation
performance.
This commit also enforces renaming of the translated basic blocks after
they get split and update the ground truth for several analysis tests.
Programs without code (e.g., no executable segment) led to miss the
`env` variable, making the `CpuLoopExitPass` fail. This commit, fixes
the problem by simply populating the `cpu_loop_exit` function with a
`ret`.
In function isolation, every time we met a jump to an unexpected basic
block (i.e., a basic block that is not part of the current function), we
used to throw an exception. However this is unnecessary since oftentimes
it is sufficient to call the `function_dispatcher` or even perform a
regular function call.
The most obvious example is the case of a direct tail call. In this
situation performing a function call to the corresponding isolated
function is the most appopriate thing to do.
We used to black list memory portions target of memory read, so that
they couldn't become function entry points. However, this led to false
positives, in particular with functions that are explicitly called.
This commit ensures that we black list those addresses only if they are
not targets of function calls.
When optimizing a module to which function isolation has been applied the
`prune-eh` pass lead to several issues, specifically:
* `support.c` is now compiled with support for exceptions, to prevent
`raise_exception_helper` from being marked `nounwind` during the
link phase.
* Added a fake `ret` at the end of the `catchblock` to avoid promotion
of `invoke`s to regular `call`s.
* Marked the `invoke` instructions as `noinline`.
This commit fixes an issue in OSRA with computations on constants. If a
constant was added to another constant, a new constant bounded value
would be created. However, such bounded value wouldn't get propagated
further. This commit fixes the problem by creating an OSRA relative to
the original constant plus an offset.
This commit forces the function call identification analysis during
harvesting of new basic blocks. Additionally, the appropriate jump
target reasons are associated to the involved basic blocks.
`BinaryFile::readRawValue` scans the segment list to identify which
segment contains a certain address. However, it was failing if the
target address was in `.bss`, i.e., the portion of a segment after
`p_filesz` but `before `p_memsz`.
This commit lets `BinaryFile::readRawValue` return 0 in that situation.
Fix for a situation where the fallthrough basic block of an instruction
calling a helper function is not in an executable segment and therefore
not created.
This commit fixes a huge performance issue due to performing a orphan
basic block cleanup every time `JumpTargetManager::peek` was called
instead of only when actual harvesting was required.
Now using the `root` function of the cloned module as a starting point
for the isolation process.
In this way we can ignore the old module, and in particular we can
drop the `ModuleCloningVMap`, a giant map that was used to keep the
match between old and new global objects and was used in the instruction
cloning phase.
Also changed the creation of the trampoline for the isolated function,
using a new basic block and later purging all the unreachable basic
blocks in the `root` function.
This commit uses SET, information about canonical values and labels to
detect if an indirect function call is targeting an external symbol.
The strings used for the name of external symbols are uniqued global
variables. This commit also uses this approach for the disassembly of
original instructions, which used to be metadata.
So far we've been tracking only base-relative relocations in an ad-hoc
fashion. This commit introduces a data structure that can describe the
most common relocations, including those for `.got`, `.got.plt`,
base-relative and `R_*_COPY`.
A label describes a range of the binary. A label can be generated from a
symbol (basically assigning a name to range of the binary) or from a
relocation, describing the content of a certain range.
This commit generates labels from symbols and relocations, including
MIPS implicit relocations.
This commit also introduces canonical values.
A register can have a canonical value, i.e., a value that register will
assume when the analyzed module is being run. This is typically useful
for the value of the global pointer, which is different from one module
to another but, within a module, is stable.
This commit registers the canonical value of `gp` (in MIPS), if
available.
`segments_count` provides a way for the runtime to know how many
executable segments the original program had. This is used to implement
the `is_executable` function.
While the `segment_boundaries` contained only the executable segments,
`segments_count` included non-executable segments too, leading to an
out-of-bound read which sometimes led to a spurious `Unknown PC` error.
While translating the code, it might happen that a basic block needs to
be splitted and the second part to be revisited. In such cases, the
second part is register for being "purged" at the next iteration.
Translation failed if we met such a basic block before purging. This
commit correctly handles such situations.
We used to check if the address associated to the `PT_DYNAMIC` program
header matched the one of the `.dynamic` section. However, we were not
recording it, which is required in case sections headers are
missing/corrupt.
Updating to LLVM 7 mainly involved the following steps:
* Upgrade APIs for folding ConstantExpr.
* Upgrade APIs for GraphTraits.
* Upgrade APIs for DominatorTreeBase.
* Upgrade APIs for BinaryFormat to parse ELFs.
* Fix the LLVM Linker to properly link the QEMU helpers.
* Disable the new optnone attribute even with optimization -O0. This is
necessary to allow SROA to do its job properly.
* Upgrade APIs to delete Instructions.
* Properly cleaning up orphaned metadata still referring to Instructions
that have been destroyed. Recent versions of LLVM are more strict in
this respect, and will assert when compiled in debug.
* Avoid using LLVM `getGlobalContext` which has been removed from newer
versions of LLVM.
* Upgrade tests to use the new APIs.
* Upgrade APIs for instruction iterators and reverse iterators.
This commit reimplements the (conditional) reaching definitions passes
as an instance of a monotone framework.
The `ConditionNumberingPass` has also been reworked in the way it
exposes its results, but it's otherwise unchanged.
A proper unit testing framework is also available to ensure everything
works as supposed to.
Through `JumpTargetManager::setCFGForm` the `root` function CFG can be
changed so that the `dispatcher` is minimized, i.e., it jumps only to
those basic blocks that would be otherwise unreachable. This allows us
to perform more accurate and simpler analyses.
To bring the function in this state we used to check if there was at
least a non-dispatcher predecessor, however this did not work with loops
reachable only from the dispatcher, since they had a predecessor, but
that didn't mean it was reachable from the entry.
This commit fixes the problem by navigating the CFG in reverse-post
order, registering all the reachable blocks and then restoring the edge
from the dispatcher to those that are not reachable.
Additionally:
* Basic blocks with no predecessors are now purged before
`JumpTargetManager::harvest`.
* The `CFGForm` enum is now a namespace.
`InlineAsm` instructions resemble function calls. You also have to
provide the prototype of the called function. Before this commit, we
were employing `void(void)`, which was wrong since we were passing in a
CSV.
In this commit we add a pointer argument to this prototype, which
prevents an assertion in LLVM from being triggered.
Update an assertion trying to enforce the fact that `alloca`s copied
from `root` where in the original entry block, while they should be in
the `dummy` entry block.
Additionally, an improvement has been introduced which ensures only one
`alloca` is copied per-function, while, before, we were creating a new
`alloca` for each use in that function.
This commit dismisses the `argparse` library (the only non-runtime C
component of rev.ng) in favor of LLVM's CommandLine library, which
offers several benefits. Among others, now command line arguments can be
easily specified as a global variable, decentralizing their management
and avoiding the long list of arguments in the constructor of singleton
objects such as `CodeGenerator`.
This commit introduces `revng_log`, a macro analagous to `revng_assert`,
which basically allows to have the benefit of the `Logger` class without
having to compute the expression to log if the logger is disabled.
This commit also completely dismisses the `DBG` macro, converting all
the old code to `Logger` + `revng_log`.
This commit moves around most files. The new directory structure is as
follows:
* `lib/$LIBRARY/`: contains a library, i.e., a set of `.cpp` files used
by multiple libraries/tools.
* `include/revng/$LIBRARY/`: contains the public headers associated to
the library in `lib/$LIBRARY/`.
* `tools/$TOOL/`: directory where all the `.cpp` files (and private
headers) for a tool reside. Currently we have two tools: `revamb` and
`revamb-dump`.
On top of this, all file names are now in camel case.