Skip to content

Commit

Permalink
Update DFG docs on new API changes.
Browse files Browse the repository at this point in the history
  • Loading branch information
Washi1337 committed Jul 30, 2024
1 parent f5157d6 commit 4e61985
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 14 deletions.
10 changes: 6 additions & 4 deletions docs/guides/core/cfg-basics.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ foreach (var node in cfg.Nodes)
Console.WriteLine($"{node.Offset:X8}");
```

Individual nodes can also be obtained by looking them up by offset:
Individual nodes can be obtained by looking them up by offset:

```csharp
var node = cfg.Nodes.GetByOffset(offset: 0x1234);
Expand All @@ -50,11 +50,13 @@ To ensure all nodes have updated offsets according to their contents, use the `U
cfg.Nodes.UpdateOffsets();
```

If many nodes are supposed to be queried by offset, consider first creating an offset map; a dictionary that maps all basic block header offsets to their corresponding nodes:
When doing many lookups by offset, consider first creating an offset map for faster lookups.

```csharp
var offsetMap = cfg.Nodes.CreateOffsetMap();
var node = cfg.Nodes[0x1234];
var n1 = offsetMap[0x0001];
var n2 = offsetMap[0x0004];
var n3 = offsetMap[0x0010];
```

Every node exposes a basic block containing the instructions it executes:
Expand Down Expand Up @@ -118,7 +120,7 @@ If only interested in the target nodes, `GetSuccessors()` can be used instead:
```csharp
foreach (var successor in node.GetSuccessors())
Console.WriteLine(successor);
```
```[dfg-basics.md](dfg-basics.md)

Similarly, incoming edges can also be obtained using `GetIncomingEdges()` and `GetPredecessors()`:

Expand Down
16 changes: 15 additions & 1 deletion docs/guides/core/cfg-construction.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ Each architecture that supports static control flow graph building implements th
A graph can then be constructed using the `StaticFlowGraphBuilder` class:

```csharp
using Echo.ControlFlow.Construction;

IArchitecture<TInstruction> architecture = ...;
IStaticSuccessorResolver<TInstruction> resolver = ...;

Expand Down Expand Up @@ -66,6 +68,8 @@ This interface takes a symbolic input state, and transforms it into a set of all
```csharp
using Echo.DataFlow.Construction;
IArchitecture<TInstruction> architecture = ...;
StateTransitioner<TInstruction> transitioner = ...;
Expand All @@ -90,4 +94,14 @@ var dfg = transitioner.DataFlowGraph;
```
> [!WARNING]
> While symbolic graph construction usually is more accurate, it is significantly slower than static graph construction and can take a lot of memory.
> While symbolic graph construction usually is more accurate, it is significantly slower than static graph construction and can take a lot of memory.
> [!NOTE]
> Often, a backend platform has this boilerplate already implemented by extension methods.
> For instance, `Echo.Platforms.AsmResolver` defines an extension method on `CilMethodBody` called `ConstructStaticFlowGraph`.
> ```csharp
> CilMethodBody methodBody = ...;
> var cfg = methodBody.ConstructSymbolicFlowGraph(out var dfg);
> ```
> Refer to the platform-specific documentation to see how these graphs can be constructed easily.
23 changes: 15 additions & 8 deletions docs/guides/core/dfg-basics.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,23 +37,30 @@ DataFlowGraph<TInstruction> dfg = ...;

// Iterate over all nodes in a data flow graph:
foreach (var node in dfg.Nodes)
Console.WriteLine(node.Contents);
Console.WriteLine(node.Instruction);
```

Nodes are indexed by offset.
They can be obtained via the `GetNodeById` method:
Individual nodes can be obtained by looking them up by offset:

```csharp
var node = dfg.GetNodeById(id: 0x1234);
var node = dfg.Nodes.GetByOffset(offset: 0x1234);
```

Every node exposes a basic blockc containing the instructions that introduces or requires dependencies:
This performs a linear search through all the nodes, and finds the first node that matches in offset.
To ensure all nodes have updated offsets according to their contents, use the `UpdateOffsets` method:

```csharp
DataFlowNode<TInstruction> node = ...;
var instruction = node.Contents;
dfg.Nodes.UpdateOffsets();
```

When doing many lookups by offset, consider first creating an offset map for faster lookups.

```csharp
var offsetMap = dfg.Nodes.CreateOffsetMap();
var n1 = offsetMap[0x0001];
var n2 = offsetMap[0x0004];
var n3 = offsetMap[0x0010];
```

## Edges

Expand Down Expand Up @@ -105,7 +112,7 @@ var dependencies = node.GetOrderedDependencies();

By default, `GetOrderedDependencies` traverses all edges in the data flow graph.
This includes variable dependencies that were registered in the graph.
If only the stack dependnecies are meant to be traversed (e.g. to get the instructions that make up a single expression), additional flags can be specified to alter the behaviour of the traversal.
If only the stack dependencies are meant to be traversed (e.g. to get the instructions that make up a single expression), additional flags can be specified to alter the behaviour of the traversal.

```csharp
DataFlowGraph<TInstruction> node = ...
Expand Down
4 changes: 4 additions & 0 deletions src/Core/Echo.ControlFlow/Collections/NodeCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,10 @@ public IDictionary<long, ControlFlowNode<TInstruction>> CreateOffsetMap()
/// </summary>
/// <param name="offset">The offset.</param>
/// <returns>The node, or <c>null</c> if no node was found with the provided offset.</returns>
/// <remarks>
/// This is a linear lookup. For many lookups by offset, consider first creating an offset map using
/// <see cref="CreateOffsetMap"/>.
/// </remarks>
public ControlFlowNode<TInstruction>? GetByOffset(long offset) => _nodes.FirstOrDefault(x => x.Contents.Offset == offset);

/// <inheritdoc />
Expand Down
13 changes: 12 additions & 1 deletion src/Core/Echo.DataFlow/Collections/NodeCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ public void UpdateOffsets()
}

/// <summary>
/// Constructs a mapping from basic block header offsets to their respective nodes.
/// Constructs a mapping from instruction offsets to their respective nodes.
/// </summary>
/// <returns>The mapping</returns>
/// <exception cref="ArgumentException">The control flow graph contains nodes with duplicated offsets.</exception>
Expand All @@ -127,6 +127,17 @@ public IDictionary<long, DataFlowNode<TInstruction>> CreateOffsetMap()
.ToDictionary(x => x.Offset, x => x);
}

/// <summary>
/// Finds a node by its instruction offset.
/// </summary>
/// <param name="offset">The offset.</param>
/// <returns>The node, or <c>null</c> if no node was found with the provided offset.</returns>
/// <remarks>
/// This is a linear lookup. For many lookups by offset, consider first creating an offset map using
/// <see cref="CreateOffsetMap"/>.
/// </remarks>
public DataFlowNode<TInstruction>? GetByOffset(long offset) => _nodes.FirstOrDefault(x => x.Offset == offset);

/// <inheritdoc />
public IEnumerator<DataFlowNode<TInstruction>> GetEnumerator() => _nodes.GetEnumerator();

Expand Down

0 comments on commit 4e61985

Please sign in to comment.