This is a big step to split revng-lift in two parts: one that only
writes the model and one that actually lifts to LLVM IR.
* Introduce `revng import binary`
* Split off `BinaryFile.h`
* Drop `revng.h`
* `GeneratedCodeBasicInfo`: use model
* Reduce role of `GeneratedCodeBasicInfo` in favor of
`model::Architecture` and `model::Register` methods
* `CodeGenerator`: adopt `RawBinaryView` and model
* `JumpTargetManager`: adopt `RawBinaryView` and model
* `ExternalJumpsHandler`: adopt model
* `InstructionTranslator`: discard `Architecture` in favor of
`EndianessMismatch`
* Many other changes
Model classes are now described by a YAML document, which is used to
generate C++ headers containing classes and all the boilerplate
required for YAML serialization/deserialization, usage in
SortedVectors, etc. See the README in include/revng/Model for more
info.
This commit makes sure that GeneratedCodeBasicInfo can be used even in
absence of the `root`.
This also ensure that no time is wasted on brief/focused pipelines that
do not care about analyzing each basic block in the `root` function.
FunctionTags goal is to solve the long-standing problem of identifying
what type of function are we dealing with. Is it a lifted function? An
helper?
Now we have a sane way to determine this using Metadata and a proper
API.
* 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
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.
This commit makes possible to execute the GeneratedCodeBasicInfo (GCBI)
Pass even on LLVM IR where the AnyPC and UnexpectedPC BasicBlocks are
not present.
This makes the GCBI pass more flexible, enabling more other passes to
depend on it and to use it to retrieve informations on the generated
code without architecture-dependent hacks.
As an example, one can now use GCBI to retrieve the CSV representing the
Stack Pointer Register or the Program Counter Register without relying
on the register names (which are architecture-specific), even if some
optimization pass along the decompilation pipeline has removed AnyPC or
UnexpectedPC.
Notice that the contracts of GCBI's methods has not been changed.
Calling anyPC() or unexpectedPC() still asserts that those are not
nullptr.
The contract has just been moved from the execution stage of the pass
(basically runOnModule), to the APIs used to query the results.
Unlike the previous iteration of `MetaAddress`, which tried to stuff all
the parts of `MetaAddress` within the existing `PC` CSV, this
implementation adds a set of new CSVs (or marks some existing ones as) to
represent the four portions of the current PC's `MetaAddress`.
* Introduce `ProgramCounterHandler`: a class responsible to maintain the
PC-related CSVs. This class is also used to manipulate the new
dispatcher.
* `AdvancedValueInfo`: update for new MetaAddress.
* External jump handler: do not clobber registers.
When introducing support for dynamic binaries, we didn't realize that
in x86-64 we were clobbering `r11`. To avoid this, we have to jump to
an address stored in memory. However, due to the new `MetaAddress`,
obtaining a *jumpable* address from the PC-related CSVs might require
some computations (and it does in ARM). Therefore, we introduce a new
global variable, `jumpablepc`, whose only role is to contain the
jumpable version of the program counter and then be the target of the
memory-indirect jump instruction.
* Labels care only about absolute addresses.
* CSAA: mark call site, even if no accesses.
`MetaAddress` replaces all the `uint64_t` used to represent a virtual
address. Its main features are:
* It has a non-zero representation of invalid addresses.
* It supports tags to represent code that has different interpretations but
resides at the same address in memory (namely ARM vs Thumb).
* Arithmetic operations cannot overflow.
* It supports epochs, a way we intend to employ to handle self-modifying code
(i.e., different code at the same address at different times).
* It supports "address spaces", which enable handling architectures with
multiple address spaces.
* It fits in two 64-bit registers.
* Drop unused argument names from function prototypes
* Make `static` some methods
* Disable some copy constructors
* Fix casing of Doxygen `\file` directives
* Add some casts to make the compiler happy
* Initialize `hasRelocationAddend` for AArch64
* Use references in range-for where possible
* Drop default for `switch` statements covering all the entries of an `enum`
* Make some global variables `static`
* Drop dead functions
`empty-newpc` is a simple pass suppose to provide an empty body for
the `newpc` function, allowing further optimization pass to take out
all its calls.
Previously, to enumerate all the CSVs we had to go through the
`GlobalVariable` of a `Module` and see if the were being used in
rev.ng-generated code.
Now we have a named metadata for that: `revng.csv`.
We used to save the type of a block in the `revng.block.type` metadata
as a number. This commit serializes it as a string.
In order to do this, the `BlockType` enum has been promoted to a
namespace with the usual `getName` and `fromName` functions.
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`.
This commit lets the reaching definitions analysis employ results from
the stack analysis to propagate definitions across functions
calls. Specifically, the stack analysis provides a list of registers
that might be clobbered by the callee: definitions concerning those are
not propagated, all the others are propagated.
This change is key to detect jump tables whose address has been
materialized *before* a function call. A test for such situation has
been introduced.
To make this work, the RDA now works over the CFG provided by the
function identification analysis.
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.
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.
When going through basic blocks, FCI ignores basic blocks that have
already been identified as function calls. However, this lead to exclude
their fallthrough addresses from the list of fallthrough addresses.
This commit fixes this situation.
`getType` didn't have a `BlockType` to represent the entry basic block
of the `root` function. Therefore, such basic block was erroneously
identified as a translated basic block.
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.
In certain cases we find more than one instruction storing the return
address to a register. In particular, this happens with a `bltzal`
instruction in MIPS, where the return address is stored both in `ra` and
`btarget`.
For now, do not consider these as actual function calls.
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.
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.