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.
With this quarantine, when nodes are removed from RegionCFG, they are
not really freed, but they are held here until the RegionCFG itself goes
out of scope.
This is unfortunately necessary now, since the CFG restructuring
algorithm uses maps and sets (e.g. Backedges.) that are indexed using
a BasicBlockNodeT *.
If we don't hold the removed nodes in quarantine, the system allocator
can reuse the blocks, allocating new nodes at the same address, and
causing false-positive hits in some of the mentioned maps. This was the
most straightforward solution for now.
Other solutions we have considered:
- use a special monotonic allocator for BasicBlockNodes
- this should work, but in principle it gives the same results as the
current solution, with more boilerplate. Also, at the moment
std::unique_ptr is not allocator aware, so we would need to change
BlockNodes to not use them, and this would require even more
boilerplate.
- change the API for RegionCFG::removeNode, to take as arguments the
reference to the data structure and maps that must be updated, so that
when we remove the node from RegionCFG we also clear it from the maps.
However, this is very invasive, it requires changing the public facing
API, it requirese coupling the RegionCFG API with internal details,
and in the future it would need to be updated for every new map that
must be updated on removal of a node.
This commit fixes a bug causing a failing assertion on Backedges that
jump from an inner MetaRegion to an outer MetaRegion after region
collapsing.
Constructor declarations for `BasicBlockNode` were not consistent.
We had default-constructor, and move constructor explicitly deleted, but
the copy constructor was not explicitly deleted, even though it was
implicitly deleted. Make deletion explicit, in accordance to the fact
that all other special member functions for construction and assignment
are deleted.
Implement a beautify phase which does the following:
- Compute, for every scope in the AST, if that scope is `fallthrough`
or `nofallthrough` scope. Basically, the `nofallthrough` scopes are
scope which ends with a `return`, `continue', or `break`.
- Using the information computed before, we can promote the scope of an
`IfNode` using the following criterion: if one of the two branches of
the `IfNode` is a `nofallthrough` scope, we are sure that the other
branch is not reachable from the former one. We can therefore, promote
the latter as `fallthrough` block of the `IfNode` (of course taking care
of inverting the condition statement if we are promoting to
`fallthrough` the `then` branch.
If both the `then` and the `else` branches can be promoted as
`nofallthrough`, we have a function that evaluates the weight of the two
branches, and promotes the heavier one. This helps reducing the
Cognitive Complexity of the generated code
This library provides a thin locking wrapper around clang::tooling
invocations.
It should be used instead of performing direct clang::tooling
invocations by all programs that use revng-c and may run more than one
ClangTool concurrently.
This is necessary because clang::tooling internally uses llvm's cl::opt
for parsing command line options.
cl::opt uses a global variable for the parser under the hood so parsing
two command lines concurrently is not safe.
Similarly, cl::opt typically uses global variables to hold options, so
it is not safe to execute a ClangTool concurrently to another tool
that is parsing a new set of options, because there might be race
conditions between threads reading and writing the same options at the
same time.
The new library introduces a thin locking layer so that the end-user
does not need to know or worry about these details.
Actually remove dummy nodes that are purged during the `purgeDummies`
normalization phase (which is in charge of removing dummy nodes that are
not superfluos for our AST representation).
These dummies where laying around untouched, and caused errors when
iterating over all the AST while collecting the weight after the
combing.
This commits enable the emission of rich types associated with function
signatures. This types are forward-declared in the decompiled C code
before the definition of each decompiled function that uses them.
The types we emit for now are the types that the DLA is able to compute
(if any) for the return values and the arguments of the function.
Such types are not yet used in the body of the function, nor in the
function declaration. These are the next steps to come.
Before this commit, the MakeLayout step of the DLA used to deduplicate
structurally equal Layouts. This has turned out to be wrong when going
forward with the emission of types in C.
Being able to tell apart two different types that are structurally equal
is important for the emission of C types. Throwing this information away
with deduplication is bad. This commit disables such deduplication.
This is a utility class useful to make std::set<std::unique_ptr<T>>
searchable with raw pointers, by using
std::set<std::unique_ptr<T>, HeterogeneousPtrCompare<T>> instead.
Handling of command line options that specify paths for output files
have been improved in the following ways:
- If the CDecompilerPass is not default-constructed, it already has a
reference to the stream where outputs must be written. In this case,
it is wrong to use a command line option to specify the output
directory. If this happens the program is now able to detect it and to
terminate with an error.
- If some of the specified paths is not found or has the wrong
permission, the program fails early.
- On program failure because of one of the above safety checks, the
program terminates with an informative error message.
This class handles the creation of type declarations in clang's AST, and
holds the relationships between llvm Types and Values with those clang's
type declarations.
Add a pass that computes the lowest negative offset that is summed in
each isolated function to the local stack pointer returned by a call to
revng_init_local_sp (previously added by PromoteStackPointerPass).
After the computation, all the accesses relative to the stack pointer
are recomputed as if the stack pointer was lowered by the computed
amount.
This is useful to enable the DLA to easily recover layouts that are
placed at negative offsets from the stack pointer.
The reason is that the DLA in its current form does not handle negative
offsets, but at the same time negative offsets are important to recover
the layout of the local variables on the stack.
This pass implicitly depends on running PromoteStackPointerPass.
If PromoteStackPointerPass did not run before the execution of
AdjustStackPointerPass, the latter doesn't do anything.
For demonstration purposes, AdjustStackPointerPass has been implemented
both with LLVM's legacy PassManager and the new PassManager.
This commit updates the `DataFlowNode` data structure used in
`TypeShrinking` to be compatible with the newer version `GenericGraph`
provided by revng.
The change basically encompasses inverting the inheritance and dropping
CRTP.