Files
git.stella-ops.org/src/BinaryIndex/__Libraries/StellaOps.BinaryIndex.Semantic/Models/IrModels.cs
StellaOps Bot 37e11918e0 save progress
2026-01-06 09:42:20 +02:00

319 lines
9.2 KiB
C#

// Copyright (c) StellaOps. All rights reserved.
// Licensed under AGPL-3.0-or-later. See LICENSE in the project root.
using System.Collections.Immutable;
namespace StellaOps.BinaryIndex.Semantic;
/// <summary>
/// A function lifted to intermediate representation.
/// </summary>
/// <param name="Name">Function name (may be empty for unnamed functions).</param>
/// <param name="Address">Start address of the function.</param>
/// <param name="Statements">IR statements comprising the function body.</param>
/// <param name="BasicBlocks">Basic blocks in the function.</param>
/// <param name="Cfg">Control flow graph.</param>
public sealed record LiftedFunction(
string Name,
ulong Address,
ImmutableArray<IrStatement> Statements,
ImmutableArray<IrBasicBlock> BasicBlocks,
ControlFlowGraph Cfg);
/// <summary>
/// A function transformed to Static Single Assignment (SSA) form.
/// </summary>
/// <param name="Name">Function name.</param>
/// <param name="Address">Start address of the function.</param>
/// <param name="Statements">SSA statements comprising the function body.</param>
/// <param name="BasicBlocks">SSA basic blocks in the function.</param>
/// <param name="DefUse">Definition-use chains for dataflow analysis.</param>
public sealed record SsaFunction(
string Name,
ulong Address,
ImmutableArray<SsaStatement> Statements,
ImmutableArray<SsaBasicBlock> BasicBlocks,
DefUseChains DefUse);
/// <summary>
/// An intermediate representation statement.
/// </summary>
/// <param name="Id">Unique statement ID within the function.</param>
/// <param name="Address">Original instruction address.</param>
/// <param name="Kind">Statement kind.</param>
/// <param name="Operation">Operation name (e.g., add, sub, load).</param>
/// <param name="Destination">Destination operand (if any).</param>
/// <param name="Sources">Source operands.</param>
/// <param name="Metadata">Additional metadata.</param>
public sealed record IrStatement(
int Id,
ulong Address,
IrStatementKind Kind,
string Operation,
IrOperand? Destination,
ImmutableArray<IrOperand> Sources,
ImmutableDictionary<string, object>? Metadata = null);
/// <summary>
/// Kind of IR statement.
/// </summary>
public enum IrStatementKind
{
/// <summary>Unknown statement kind.</summary>
Unknown = 0,
/// <summary>Assignment: dest = expr.</summary>
Assign,
/// <summary>Binary operation: dest = src1 op src2.</summary>
BinaryOp,
/// <summary>Unary operation: dest = op src.</summary>
UnaryOp,
/// <summary>Memory load: dest = [addr].</summary>
Load,
/// <summary>Memory store: [addr] = src.</summary>
Store,
/// <summary>Unconditional jump.</summary>
Jump,
/// <summary>Conditional jump.</summary>
ConditionalJump,
/// <summary>Function call.</summary>
Call,
/// <summary>Function return.</summary>
Return,
/// <summary>No operation.</summary>
Nop,
/// <summary>PHI node (for SSA form).</summary>
Phi,
/// <summary>System call.</summary>
Syscall,
/// <summary>Interrupt.</summary>
Interrupt,
/// <summary>Cast/type conversion.</summary>
Cast,
/// <summary>Comparison.</summary>
Compare,
/// <summary>Sign/zero extension.</summary>
Extend
}
/// <summary>
/// An operand in an IR statement.
/// </summary>
/// <param name="Kind">Operand kind.</param>
/// <param name="Name">Name (for temporaries and registers).</param>
/// <param name="Value">Constant value (for immediates).</param>
/// <param name="BitSize">Size in bits.</param>
/// <param name="IsMemory">Whether this is a memory reference.</param>
public sealed record IrOperand(
IrOperandKind Kind,
string? Name,
long? Value,
int BitSize,
bool IsMemory = false);
/// <summary>
/// Kind of IR operand.
/// </summary>
public enum IrOperandKind
{
/// <summary>Unknown operand kind.</summary>
Unknown = 0,
/// <summary>CPU register.</summary>
Register,
/// <summary>IR temporary variable.</summary>
Temporary,
/// <summary>Immediate constant value.</summary>
Immediate,
/// <summary>Memory address.</summary>
Memory,
/// <summary>Program counter / instruction pointer.</summary>
ProgramCounter,
/// <summary>Stack pointer.</summary>
StackPointer,
/// <summary>Base pointer / frame pointer.</summary>
FramePointer,
/// <summary>Flags/condition register.</summary>
Flags,
/// <summary>Undefined value (for SSA).</summary>
Undefined,
/// <summary>Label / address reference.</summary>
Label
}
/// <summary>
/// A basic block in the intermediate representation.
/// </summary>
/// <param name="Id">Unique block ID within the function.</param>
/// <param name="Label">Block label/name.</param>
/// <param name="StartAddress">Start address of the block.</param>
/// <param name="EndAddress">End address of the block (exclusive).</param>
/// <param name="StatementIds">IDs of statements in this block.</param>
/// <param name="Predecessors">IDs of predecessor blocks.</param>
/// <param name="Successors">IDs of successor blocks.</param>
public sealed record IrBasicBlock(
int Id,
string Label,
ulong StartAddress,
ulong EndAddress,
ImmutableArray<int> StatementIds,
ImmutableArray<int> Predecessors,
ImmutableArray<int> Successors);
/// <summary>
/// Control flow graph for a function.
/// </summary>
/// <param name="EntryBlockId">ID of the entry block.</param>
/// <param name="ExitBlockIds">IDs of exit blocks.</param>
/// <param name="Edges">CFG edges.</param>
public sealed record ControlFlowGraph(
int EntryBlockId,
ImmutableArray<int> ExitBlockIds,
ImmutableArray<CfgEdge> Edges);
/// <summary>
/// An edge in the control flow graph.
/// </summary>
/// <param name="SourceBlockId">Source block ID.</param>
/// <param name="TargetBlockId">Target block ID.</param>
/// <param name="Kind">Edge kind.</param>
/// <param name="Condition">Condition for conditional edges.</param>
public sealed record CfgEdge(
int SourceBlockId,
int TargetBlockId,
CfgEdgeKind Kind,
string? Condition = null);
/// <summary>
/// Kind of CFG edge.
/// </summary>
public enum CfgEdgeKind
{
/// <summary>Sequential fall-through.</summary>
FallThrough,
/// <summary>Unconditional jump.</summary>
Jump,
/// <summary>Conditional branch taken.</summary>
ConditionalTrue,
/// <summary>Conditional branch not taken.</summary>
ConditionalFalse,
/// <summary>Function call edge.</summary>
Call,
/// <summary>Function return edge.</summary>
Return,
/// <summary>Indirect jump (computed target).</summary>
Indirect,
/// <summary>Exception/interrupt edge.</summary>
Exception
}
/// <summary>
/// An SSA statement with versioned variables.
/// </summary>
/// <param name="Id">Unique statement ID within the function.</param>
/// <param name="Address">Original instruction address.</param>
/// <param name="Kind">Statement kind.</param>
/// <param name="Operation">Operation name.</param>
/// <param name="Destination">Destination SSA variable (if any).</param>
/// <param name="Sources">Source SSA variables.</param>
/// <param name="PhiSources">For PHI nodes: mapping from predecessor block to variable version.</param>
public sealed record SsaStatement(
int Id,
ulong Address,
IrStatementKind Kind,
string Operation,
SsaVariable? Destination,
ImmutableArray<SsaVariable> Sources,
ImmutableDictionary<int, SsaVariable>? PhiSources = null);
/// <summary>
/// An SSA variable (versioned).
/// </summary>
/// <param name="BaseName">Original variable/register name.</param>
/// <param name="Version">SSA version number.</param>
/// <param name="BitSize">Size in bits.</param>
/// <param name="Kind">Variable kind.</param>
public sealed record SsaVariable(
string BaseName,
int Version,
int BitSize,
SsaVariableKind Kind);
/// <summary>
/// Kind of SSA variable.
/// </summary>
public enum SsaVariableKind
{
/// <summary>CPU register.</summary>
Register,
/// <summary>IR temporary.</summary>
Temporary,
/// <summary>Memory location.</summary>
Memory,
/// <summary>Immediate constant.</summary>
Constant,
/// <summary>PHI result.</summary>
Phi
}
/// <summary>
/// An SSA basic block.
/// </summary>
/// <param name="Id">Unique block ID.</param>
/// <param name="Label">Block label.</param>
/// <param name="PhiNodes">PHI nodes at block entry.</param>
/// <param name="Statements">Non-PHI statements.</param>
/// <param name="Predecessors">Predecessor block IDs.</param>
/// <param name="Successors">Successor block IDs.</param>
public sealed record SsaBasicBlock(
int Id,
string Label,
ImmutableArray<SsaStatement> PhiNodes,
ImmutableArray<SsaStatement> Statements,
ImmutableArray<int> Predecessors,
ImmutableArray<int> Successors);
/// <summary>
/// Definition-use chains for SSA form.
/// </summary>
/// <param name="Definitions">Maps variable to its defining statement.</param>
/// <param name="Uses">Maps variable to statements that use it.</param>
public sealed record DefUseChains(
ImmutableDictionary<SsaVariable, int> Definitions,
ImmutableDictionary<SsaVariable, ImmutableHashSet<int>> Uses);