Before this commit, recursive coroutines did not work properly if they
had out arguments with reference type.
The reason is that `rc_run` was inferring the type of its arguments from
the arguments themselves, not from the prototype of the recursive
coroutine.
Hence, code snippets like the following did not work properly, because
`rc_run` was taking x by value, not by reference.
```
RecursiveCoroutine<void> accumulate_on_i(int &i) {
// ...
}
int f() {
int x = 0;
rc_run(accumulate_on_i, x);
return x;
}
```
This commit fixes the problem. Now the arguments of `rc_run` are
properly forwarded to the recursive coroutine.
Enable quotes around MetaAddress during serialization, since ':' is a
valid YAML separator, which causes wrong deserialization when a vector
of MetaAddress is serialized as a list
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.
This commit extends the support for the FOR_EACH macro used in
INTROSPECTION_NS to allow serialization of structs with more than
5 entries. Now it supports up to 16 entries.
This commit fixes a couple of bugs preventing SortedVector and
MutableSet from being serialized.
Also, it introduces minimal testing for serialization.
Changes include:
- `getFunctionCall` has been moved in IRHelpers.h
- `getFallthrough` and `getFunctionCallCallee`
have been simplified and added in IRHelpers.h (their old versions
have been removed respectively from FCI.h and revng.h)
- `FCI::getCall` and `FCI::isCall` have been removed
due to redundancy with `getFunctionCall`.
This commit fixes a bug that lead to be unable to instantiate from a
`Module` `ProgramCounterHandler`. The reason for this was that
`ProgramCounterHandler` was using `Module::getGlobalVariable` which, by
default, ignores variables with internal linkage.
These data structures are substitutes for a `std::map<Key, Value>` where
`Key` is embedded in `Value`. Their main goal is to be serializable in a
YAML sequence while preserving the order enforced by the key.
`MutableSet` is implemented using a map.
`SortedVector` is implemented using a sorted vector.
Problem:
1. `ForwardNode::getConstNeighbor` returns a reference to a non-`const`
object, but the referenced pointer is `const`
2. `FowardNode::toNeighborRange` checks if the type of the argument is
const, but since `Successors` is not declared const the resulting
`toNeighborRange(Successors)` is never executed in the const version
Solution:
1. Make `getConstNeighbor()` return a reference to a `const` pointer
2. Explicitly declare a separate `toNeighborRange()` function which
returns a `const_child_iterator` and remove the template parameter
RecursiveCoroutines are a facility intended to be used as-drop in
replacement of recursive functions.
They provide the following features.
- They can be written almost as regular recursive functions,
with 4 caveats.
1. A recursive coroutine that returns a type `T`, needs to be declared
to return a `RecursiveCoroutine<T>`.
2. Inside the body of a recursive coroutine, when recursively calling
another recursive coroutine, the recursive call needs to be
prepended by the new keyword `rc_recur`.
3. Inside the body of a recursive coroutine, the `return` statement
needs to be substituted with `rc_return`.
4. When launching a recursive coroutine `A` from a function that is
not a recursive coroutine, `A` needs to be called with the provided
dedicated template wrapper `rc_run`.
The syntax is the following `rc_run(A, arg0, arg1, ...)`.
This is necessary to enable swapping off recursive coroutine and
fall back to regular recursion for debug.
See below for how to do it.
- Unlike regular recursive functions, they don't use the system stack
for recursion. They use a custom heap-allocated stack to manage
recursion. This makes them more robust for implementing recursive
functions that manipulate user-defined input, because they are much
less likely to trigger stack overflow.
- They can be turned off compiling with
`-DDISABLE_RECURSIVE_COROUTINES`, falling back to regular recursion,
for debug purposes.
- They support both direct and indirect recursion, i.e. a recursive
coroutine A can recursively call itself, or it can recursively call
another recursive coroutine B, which in turns recursively calls A.