This was broken after the introduction of `SwitchDispatcherNode`,
because
both `SwitchDispatcherNode` and `RegularSwitchNode` used the `isEqual`
method from `SwitchNode`.
Now the `isEqual` method is implemented only for the `ASTNode` base
class, and each leaf of the llvm-RTTI hierarchy of `ASTNode` properly
implements the comparison.
In presence of a switch node, which contains a case made up of
entirely a sequence of empty nodes (simplified by the
`simplifyAtomicSequence` recursive function), enable the removal of the
aforementioned case from the switch node.
This commit removes a call to untangle() that was performed before the
whole combing algorithm on the root RegionCFG.
The call was redundant before introducing the weaving, and became
plainly wrong after adding the weaving, because it ended up trying to
untangle the root RegionCFG before weaving (which is supposed to run
first).
Removing the dedicated call fixes the bug, because weaving is performed
first as part of the call to generateAst().
`llvm::removeUnreachableBlocks` doesn't just drop dead basic blocks,
it also turns certain `SwitchInst` into `BranchInst`, which leads to
hard-to-debug issues in parts of the code where we don't assume
unexpected changes such as this.
Function isolation used to mishandle blocks of type
`BlockType::IndirectBranchDispatcherHelperBlock`. This led to have
empty basic blocks instead of the dispatcher for handling indirect
branches.
We now emit `RegularSwitch` node type creating the vector containing the
case values by inspecting the actual values of the `ConstantInt` in the
IR.
Due to the introduction of weaving, we can have a cascade of switches,
and in this case the top switch should bring to a certain weaving switch
for multiple values of the case label.
For this reason, switch case are now represented by sets, which are
usually populated by a single value, but in presence of a weaving
switches they can represent the fact that for each value contained in
the set we must take a certain case label.
The backend of the decompiler has been updated to reflect this change,
in order to emit all the values for a certain `CaseSet` in `or` if the
size of the seat is greater than 1.
Reorganize attribute `Kind` incorporating it into the `Type` attribute,
by lowering its memory footprint.
Modified the constructors, some accessors and helpers accordingly.
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 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.
Add EdgeRef and ChildEdgeIteratorType to GraphTraits<DotNode *> and to
GraphTraits<const DotNode *>.
This allows iterating on edges of DotGraphs, which will be useful for
some testing on edge properties.
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
Introduced various untangle algorithm improvements:
- Improve untangle edge reorganization: improve the criterion used for
reorganizing the edges between the old postdominator and the cloned
one, after an inline procedure is attempted during the untangle.
- Untangle counter: introduce two new counters which take into account
the number of times the untangle procedure is attempted and the actual
times it is performed.
- Disable not dominated restriction: disable the criterion which
restricts the untangle opportunities if we do not dominate entirely
at least one of the two branches. This has likely broken the
assumption that the postdominators of nodes do not changes after each
untangle step has been carried out.
- Change dominance criterion: the dominance of the nodes belonging to
the `then` and `else` nodes is now checked not with respect to the
conditional node, but to the `then` and `else` edges of the conditional
node.
- Untangle eager inlining: now, when the untangle procedure finds a
suitable candidate for the inlining, proceed the complete inlining
starting from the selected branch. By default new clones of all the
nodes till the exit are created and attached to the branch, while the
original nodes are detached. An additional pass which removes eventual
dandling nodes (nodes which are not reachable from the entry node of
the graph) is performed after the eager inlining. This means that if
no other incoming edges to this group of nodes is present the original
nodes will be purged.
The post dominator now is updated during the inlining analysis, and
the paths conducting to inlined exits are not taken into account for
the post dominator computation.
- Enable untangle for mixed branches: perform the untangle even if the
`then` and `else` branches share nodes. This was not feasible before
because without the eager inlining we couldn't decide which edge to
attach to the new postdominator clone. This problem is not present
anymore, so we can handle any kind of topology in the untangle.
- Improved also the analysis information serialized by the decompiler.
Add a flag to enable the decompilation of a single function.
In order to have a single flag shared between the `RestructureCFGPass`
and the `CDecompilerPass`, we added a new dedicated decompilation unit
called `TargetFunctionOption`.