Separate `ModelToHeader.cpp` into 3 different files:
1. DependencyGraph, used to calculate the precedence between
type declarations
2. ModelTypeNames, that holds all the naming logic, whose
primitives are accessible from other modules through a
public header
3. ModelToHeader, that now contains only the logic to print
out declarations and definitions
Also add a compilation test for the headers generated by this pass.
**Symptoms**: a correct visit of the GHAST resulted in an incorrect
visit order of the CFG (some instructions were visited before their
operands)
**Causes**: When creating the tile of a dispatcher with an inline
successor and a fallthrough, the predecessors of the dispatcher
were correctly connected to the new tile, but the fallthrough
was not, leading to a split in the GHAST between nodes that should
have been connected
**Solution**: Setting `PostDomBB = Fallthrough` if there is a
fallthrough just before calling `createTile()` corrects
this behavior, connecting the tile to its fallthrough node
We should never be changing the nature of a `while` node into a
`doWhile` and vice-versa: we only upgrade standard nodes in
either a `while` or a `doWhile`.
Remove the logic for detecting Instructions with duplicated uses
introduced by control-flow restructuring (the use is duplicated, but the
instruction is not).
By dropping this detection, we'll end up not marking for serialization
some Instructions. Hence, when emitting C code, such Instructions will
just be emitted as inline expressions, without declaring a dedicated
local variable to hold their value. This is somehow suboptimal w.r.t the
fact that the expression will be emitted many times, one for each
duplicated use. However, this is not semantically incorrect, just
verbose.
On the other hand, the logic for detecting Instructions with duplicated
uses has always been subtly broken, because it only looked at the number
of duplicates for a given basic block introduced by control-flow
restructuring.
This information is not enough to detect Instructions with duplicated
uses. Proper detection should actually be based on GHAST.
Add `MakeModelTypes` and `UpdateFuncPrototypes` to the DLA backend:
* `MakeModelTypes` adds to the model all the types recovered by the DLA
* `UpdateFuncPrototypes` updates function prototypes in the model that
have generic return values or arguments to use the types recovered by
the DLA
* Changes to the `LayoutTypeSystem` graph
Pointers are identified in the TypeSystem graph as leaf nodes which
have a new type of edge (PointerEdge) that connects them to another
node of the graph. The destination of the edge represents the layout of
the pointed type.
* Changes to the Front-end
Pointer edges, and their destination nodes, are created by the DLA
front-end (`DLACreateIntraProceduralTypes`) whenever an access node has
a size that is compatible with the size of a pointer in the current
Architecture.
Successors might then be added to the newly generated node, if any,
by looking up the llvm::Value it is attached to.
* Changes to the Middle-end
Most of the DLA passes should ignore Pointer Edges, so they are modified
accordingly. Most notably, nodes that represent pointed layouts should
never be merged/pruned-off.
* Changes to the Back-end
The `TypeDeclCreationAction` of the decompiler and the `DLAMakeLayouts`
step of the DLA back-end are modified to take into account the new
information about pointers.
⚠️ There is a known issue with this version of the decompiler,
namely the fact that type loops are not detected and can cause the
emitter to enter an infinite loop.
We introduce a new tile, for matching if node with a single and inlined
then/else. In these case, the not inlined successor should be connected
with the tile node.
Handle switch nodes with all but one case edges inlined, by electing the
not inlined edge as the path conducting to the postdominator, and
avoiding parts of the graph disconnecting during the tiling procedure.
Add a step that recognizes if two subtrees of a union node are
topologically equivalent and merges them. This corresponds to removing
duplicate fields in unions.
This deduplication was prevously done while emitting layouts.
A check is inserted into DLAMakeLayouts to assert that, after
constructing unions, no union has only one child, which could be the
case if we didn't deduplicate union fields in the graph.
`moveEdgeTarget` and `moveEdgeSource` now directly modify the
successor/predecessor field in place in the edge data structure, instead
of extracting and reinserting later the edge.
This avoid a subtle bug, found in the `createTile` helper function, that
caused the swap of a `then` and `else` branch during a tile creation
step, that consequently broke the semantics in the recovered GHAST.
Break node creation is now improved to avoid edge index swapping that
can cause inversion of conditions later on in the decompilation
pipeline.
To do this, the creation and connection of the break nodes is done
during the bulk insertion of nodes in a collapsed region.
* Inheritance straight lines are now collapsed by CollapseSingleChild
* Don't collapse if parent has more than one parent or if the child has
more than one parent
* Allow the possibility to construct single-member struct: if this
struct is inherited by many other structs, "flattening" the struct is not
the most sensible thing to do, since inheritance information is something
we want to preserve in these cases.
During combing, GCBI's BlockType was used to detect unexpectedPC and
anyPC. This method is does not work anymore (since revng started
dropping such info from isolated functions and replacing that with
llvm::unreachable instructions).
This commit drops the dependency on GCBI and BlockType, and starts
detecting blocks to inline by simply looking at their terminator. If
it's an llvm::unreachable, the block is detected as inlineable.
While doing thie, also drop `printAccessNode()` from DLA DebugPrinter.
The information about which LLVM instruction originated a given access
node is already available in the csv generated by the `dla-accesses-log`
logger.
- Remove `CreateInterProceduralTypes` and `CreateIntraProceduralTypes`
from the StepManager and put them in a separate
`DLATypeSystemLLVMBuilder` object that is in charge of initializing
the DLATypeSystem graph.
- Remove `MakeLayouts` from the StepManager and split into two free
functions: `makeLayouts` and `makeLayoutMap()`
- Remove all LLVM-related stuff (Module, LayoutTypePtrs and mappings
between these and DLATypeSystemNodes) from DLATypeSystem
- Add an IntEqClasses member to DLATypeSystem, to use to map between
LayoutTypePtrs and Layouts
- Add a TSDebugPrinter object inside the DLATypeSystem, which by default
prints only IDs
- Define an LLVMTSDebugPrinter inside DLATypeSystemBuilder which
overrides the default printer's behavior, printing LLVM-related info.
- Add the possibility to dump into a .csv file the bindings between
Nodes in the TypeSystem and `llvm::Value`s
Before this commit DLATypeSystem used a
std::set<std::unique_ptr<LayoutTypeSystemNode> to hold nodes, allowing
heterogenous lookup with bare pointers, fast removal being a set,
and providing address stability without requiring an ordering between
LayoutTypeSystemNodes.
The same requirements is now obtained more cleanly using with a
BumpPtrAllocator for nodes, and a set of naked pointers to them to
enable fast lookup and removal.