Fixed the flattening algorithm, which contemplated only the situation
where the node head of the `Check` chain was directly preceded by only
`Set` nodes.
In reality we may also have in the middle `Dummy` nodes, and for this
reason we need to explore upwards the chain of node until we find all
the `Set` nodes. The implementation takes care of verifying that during
the upwards exploration we only encounter `Set` and `Dummy` nodes.
Add the `IfCheckNode` AST node type, which represents the `Check` nodes
in the RegionCFG. We need an explicit type in the AST since, with the
enforce pass drop before decompilation, we need to handle the code
emission for these type of nodes.
The type has been implemented as a derived type from the `IfNode`, since
they share a lot of similarities, in order to avoid modifications to the
AST simplification functions.
The methods that should not be invoked have been (as the ones that
modify the conditions of the nodes) override and implemented with an
`revng_abort` function
Add a new AST node type for representing the nodes which set the value
for the state variable before an entry or exit dispatcher.
In this way, when printing the decompiled code we do not need to inspect
the node further.
Removed the `Switch` BBNode, which was used to create the intermediates
nodes for making an original `switch` node a nested tree of `if` checks.
Also removed the `IfEqual` AST node, which was used to represent the
intermediate check nodes in the AST, for later reconstructing the
original `Switch` node in the AST, when possible.
Match `SwitchNode` on the AST, starting from the `IfNode` nested tree
structure which is generated during the preprocessing.
We basically match a consecutive chain of `IfNode`, checking that the
corresponding original `BasicBlock`s are composed by a couple of compare
and branch instructions, all over the same `Value`.
Remove from the `IfEqualNode` the reference to the BBNode corresponding
to the original `switch`, since we cannot have the guarantee that this
node will remain allocated in the same place (the pointer could be
invalidated).
Also insert other fixes.
Improved the method for matching the `then` and `else` branches when
creating the AST node for the `IfEqualNode`.
Also converted the name of an auxiliary pass to the convention.
Add a new AST node type for representing the nodes created starting from
the dummy nodes built in place of a `switch` statement.
These nodes contain also the information needed for emitting the code
relative to the checks performed by the node (the condition and the case
value).
This node type inherits from the `IfNode` node type, to avoid
reimplementing all the methods for its handling and transformation.
Add a pass which removes the `unexpectedpc` as successor of the `switch`
instructions. This simplifies the subsequent analyses.
This pass also removes the unreachable basic blocks dandling around (as
the `unexpectedpc` and `anypc` blocks when they are not needed).
Now considering the fact that the body of a loop may become empty if
some simplification take place (e.g. we match a `while` whose body is
composed only by a check with `break` and `continue` branches).
When a `while` loop is matched and promoted, add to every `continue`
node in the current scope the instructions needed for the computation of
the loop condition.
Match `do-while` and `while` loops, transform the in our AST preserving the
information about the `IfNode` which computes the condition of loop, and
emit them in the decompiled code.
Also added a pass which removes useless continue nodes.
Register marked as explicitly callee saved in a function used to be
marked as No both for the current function and all of its function
calls. However, the latter action is not accurate.
In certain locations we were using a `std::vector`, taking a reference
to it, adding elements and ending up in a reference invalidation issue.
This commit replaces those `std::vectors` with `std::deque` which do not
present this issue.
The ABI analysis used to ignore actions happening in CFG-level infinite
loops due to the fact that they had no exists. This commits detects
infinite loops and marks certain nodes as exits.
This commit introduces the `enforce-abi` pass, which consumes the
information provided by the ABI analysis and enforces them in the
isolated functions adding actual arguments.
This commit also rewrites the logic of `ResultsPool::finalize` and
changes the semantic of `Yes` statements on arguments to `YesOrDead`.
In the Decompiler::HandleTranslationUnit method we abuse clang::tooling
to call clang on an empty file, each time a new Function is decompiled.
To do this we use clang::tooling's CommonOptionParser, which appends the
names of the parsed files to a static cl::list. The fact that this list
is static, means that it is never cleaned between calls to
DecompilationPass, which means that at each successive call
clang::tooling thinks we have more and more input files, meaning that it
creates multiple translation units. For each translation unit we run a
DecompilationAction, hence we emit multiple identical copies of the same
function. To disable this we have to create CommonOptionParser only
once, making it static as well.
With this commit, only the necessary global declarations are emitted for
each decompiled function.
This means that, for each decompiled function, only the used functions
and global variables are forward declared in the emitted C.
`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.
`ZipMapIterator` allows you to iterate in parallel over two
`std::map`-like containers.
In the ABI analysis, this allows us to be much more efficient. In
practice, if we have two maps with M and N elements, we pass from
performing N*log(N) + M*log(M) queries to the size of the union of the
set of keys of the two maps.
In the stack analysis, we used to consider helper functions as indirect
calls. However, the `CPUStateAccessAnalysis` provides us accurate
information about what an helper function does.
This commit transforms calls to helper functions in a series of ABI IR
instructions reading all the input registers of the helper functions and
a series of instructions writing the output registers.
Note that, while this is a serious improvement over considering them
indirect function calls, it's still suboptimal since
`CPUStateAccessAnalysis` doesn't provide us information as fine-grained
as the ABI analysis.