Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
c351644
Stack analysis and dominance
ItsMilos Jun 24, 2025
f97691c
Added .vscode to gitignore, added some blacklisted exe names, renamed…
ItsMilos Jul 20, 2025
7630140
Make isil more verbose, less platform dependent, and make all side ef…
ItsMilos Jul 21, 2025
a4252a9
Remove unreachable blocks, nops, and merge call blocks
ItsMilos Jul 22, 2025
cea2a44
Remove redundant assignments
ItsMilos Jul 22, 2025
30cc2ff
SSA form
ItsMilos Jul 23, 2025
f69470c
Move analysis stuff into IAction classes
ItsMilos Jul 23, 2025
b5079d1
Support call [memory] x86 instructions
ItsMilos Jul 23, 2025
7205c7d
Type propagation
ItsMilos Jul 24, 2025
39373e6
Use move instead of load address
ItsMilos Jul 25, 2025
762e380
Resolve field offsets
ItsMilos Jul 25, 2025
ee56932
Remove unused locals
ItsMilos Jul 26, 2025
19212e6
Basic IL generation
ItsMilos Jul 27, 2025
08ba908
Fix exception in stack analyzer caused by indirect jumps
ItsMilos Jul 27, 2025
a655060
Generate IL for move and call ISIL instructions, updated opcode docs
ItsMilos Aug 7, 2025
69a92cd
Use ldarg when locals are args, resolve getters by name when offset d…
ItsMilos Aug 8, 2025
1f2d33c
Generate IL for all ISIL instructions
ItsMilos Aug 15, 2025
1f2d9c2
Update readme, and some small fixes
ItsMilos Aug 17, 2025
58b2792
Update readme
ItsMilos Aug 19, 2025
4cc040f
Merge branch 'SamboyCoding:development' into development
ItsMilos Aug 19, 2025
0b7f56d
Update readme
ItsMilos Aug 19, 2025
42542dd
Fix graph tests
ItsMilos Aug 20, 2025
b82763a
Fix analysis thread safety
ItsMilos Aug 25, 2025
508ddbf
Merge remote-tracking branch 'upstream/development' into development
ItsMilos Sep 24, 2025
eb1790a
Update IlGenerator.cs
ItsMilos Sep 24, 2025
be900a5
Collapse repeating stack traces in decompiler errors
ItsMilos Sep 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
packages/

\.idea/
.vscode/

bin/
obj/
Expand Down
48 changes: 28 additions & 20 deletions Cpp2IL.Core.Tests/Graphing/BasicGraph.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Collections.Generic;
using Cpp2IL.Core.Graphs;
using Cpp2IL.Core.ISIL;

Expand All @@ -10,29 +11,36 @@ public class BasicGraph
[SetUp]
public void Setup()
{
var isilBuilder = new IsilBuilder();
var instructions = new List<Instruction>();
void Add(int index, OpCode opCode, params object[] operands) => instructions.Add(new Instruction(index, opCode, operands));

isilBuilder.ShiftStack(0x0000, -40);
isilBuilder.Compare(0x0001, InstructionSetIndependentOperand.MakeRegister("test1"), InstructionSetIndependentOperand.MakeRegister("test2"));
isilBuilder.JumpIfNotEqual(0x0002, 0x0006);
isilBuilder.Move(0x0003, InstructionSetIndependentOperand.MakeRegister("test3"), InstructionSetIndependentOperand.MakeImmediate(0));
isilBuilder.Call(0x0004, 0xDEADBEEF);
isilBuilder.Move(0x0005, InstructionSetIndependentOperand.MakeRegister("test4"), InstructionSetIndependentOperand.MakeImmediate(0));
isilBuilder.Move(0x0006, InstructionSetIndependentOperand.MakeRegister("test5"), InstructionSetIndependentOperand.MakeImmediate(0));
isilBuilder.Compare(0x0007, InstructionSetIndependentOperand.MakeRegister("test1"), InstructionSetIndependentOperand.MakeRegister("test2"));
isilBuilder.JumpIfEqual(0x0008, 0x000C);
isilBuilder.Compare(0x0009, InstructionSetIndependentOperand.MakeRegister("test1"), InstructionSetIndependentOperand.MakeRegister("test2"));
isilBuilder.JumpIfNotEqual(0x000A, 0x000C);
isilBuilder.Call(0x000B, 0xDEADBEEF);
isilBuilder.Move(0x000C, InstructionSetIndependentOperand.MakeRegister("test4"), InstructionSetIndependentOperand.MakeImmediate(0));
isilBuilder.Move(0x000D, InstructionSetIndependentOperand.MakeRegister("test5"), InstructionSetIndependentOperand.MakeImmediate(0));
isilBuilder.ShiftStack(0x000E, 40);
isilBuilder.Call(0x000F, 0xDEADBEEF);
Add(00, OpCode.ShiftStack, -40);
Add(01, OpCode.CheckEqual, new Register(null, "zf"), new Register(null, "test1"), new Register(null, "test2"));
Add(02, OpCode.Not, new Register(null, "zf"), new Register(null, "zf"));
Add(03, OpCode.ConditionalJump, 7, new Register(null, "zf"));
Add(04, OpCode.Move, new Register(null, "test3"), 0);
Add(05, OpCode.Call, 0xDEADBEEF);
Add(06, OpCode.Move, new Register(null, "test4"), 0);
Add(07, OpCode.Move, new Register(null, "test5"), 0);
Add(08, OpCode.CheckEqual, new Register(null, "zf"), new Register(null, "test1"), new Register(null, "test2"));
Add(09, OpCode.ConditionalJump, 14, new Register(null, "zf"));
Add(10, OpCode.CheckEqual, new Register(null, "zf"), new Register(null, "test1"), new Register(null, "test2"));
Add(11, OpCode.Not, new Register(null, "zf"), new Register(null, "zf"));
Add(12, OpCode.ConditionalJump, 14, new Register(null, "zf"));
Add(13, OpCode.Call, 0xDEADBEEF);
Add(14, OpCode.Move, new Register(null, "test4"), 0);
Add(15, OpCode.Move, new Register(null, "test5"), 0);
Add(16, OpCode.ShiftStack, 40);
Add(17, OpCode.Call, 0xDEADBEEF);

isilBuilder.FixJumps();
foreach (var instruction in instructions)
{
if (instruction.OpCode != OpCode.Jump && instruction.OpCode != OpCode.ConditionalJump)
continue;
instruction.Operands[0] = instructions[(int)instruction.Operands[0]];
}

graph = new();
graph.Build(isilBuilder.BackingStatementList);
graph = new ISILControlFlowGraph(instructions);
}

[Test]
Expand Down
123 changes: 67 additions & 56 deletions Cpp2IL.Core.Tests/Graphing/ExceptionThrowingGraph.cs
Original file line number Diff line number Diff line change
@@ -1,78 +1,89 @@
using System.Collections.Generic;
using Cpp2IL.Core.Graphs;
using Cpp2IL.Core.ISIL;

namespace Cpp2IL.Core.Tests.Graphing;

public class ExceptionThrowingGraph
{
ISILControlFlowGraph graph;

[SetUp]
public void Setup()
{
var isilBuilder = new IsilBuilder();
var instructions = new List<Instruction>();
void Add(int index, OpCode opCode, params object[] operands) => instructions.Add(new Instruction(index, opCode, operands));

isilBuilder.Push(001, InstructionSetIndependentOperand.MakeRegister("sp"), InstructionSetIndependentOperand.MakeRegister("reg1"));
isilBuilder.ShiftStack(002, -80);
isilBuilder.Compare(003, InstructionSetIndependentOperand.MakeRegister("reg2"), InstructionSetIndependentOperand.MakeImmediate(0));
isilBuilder.Move(004, InstructionSetIndependentOperand.MakeRegister("reg3"), InstructionSetIndependentOperand.MakeRegister("reg4"));
isilBuilder.JumpIfNotEqual(005, 9);
isilBuilder.Move(006, InstructionSetIndependentOperand.MakeRegister("reg5"), InstructionSetIndependentOperand.MakeImmediate(0));
isilBuilder.Call(007, 0xDEADBEEF);
isilBuilder.Move(008, InstructionSetIndependentOperand.MakeRegister("reg6"), InstructionSetIndependentOperand.MakeImmediate(1));
isilBuilder.Compare(009, InstructionSetIndependentOperand.MakeRegister("reg7"), InstructionSetIndependentOperand.MakeImmediate(0));
isilBuilder.JumpIfEqual(010, 35);
isilBuilder.Move(011, InstructionSetIndependentOperand.MakeRegister("reg8"), InstructionSetIndependentOperand.MakeImmediate(1));
isilBuilder.Move(012, InstructionSetIndependentOperand.MakeRegister("reg9"), InstructionSetIndependentOperand.MakeImmediate(2));
isilBuilder.Move(013, InstructionSetIndependentOperand.MakeRegister("reg10"), InstructionSetIndependentOperand.MakeImmediate(3));
isilBuilder.Move(014, InstructionSetIndependentOperand.MakeStack(0x40), InstructionSetIndependentOperand.MakeRegister("reg11"));
isilBuilder.Move(015, InstructionSetIndependentOperand.MakeRegister("reg12"), InstructionSetIndependentOperand.MakeImmediate("input"));
isilBuilder.Move(016, InstructionSetIndependentOperand.MakeStack(0x30), InstructionSetIndependentOperand.MakeRegister("reg13"));
isilBuilder.Compare(017, InstructionSetIndependentOperand.MakeRegister("reg14"), InstructionSetIndependentOperand.MakeImmediate(2));
isilBuilder.Move(018, InstructionSetIndependentOperand.MakeStack(0x20), InstructionSetIndependentOperand.MakeRegister("reg15"));
isilBuilder.Move(019, InstructionSetIndependentOperand.MakeStack(0x40), InstructionSetIndependentOperand.MakeImmediate(1));
isilBuilder.Move(020, InstructionSetIndependentOperand.MakeStack(0x38), InstructionSetIndependentOperand.MakeRegister("reg16"));
isilBuilder.JumpIfEqual(021, 25);
isilBuilder.Compare(022, InstructionSetIndependentOperand.MakeMemory(new IsilMemoryOperand(InstructionSetIndependentOperand.MakeRegister("reg17"), 224)), InstructionSetIndependentOperand.MakeImmediate(0));
isilBuilder.JumpIfNotEqual(023, 25);
isilBuilder.Call(024, 0xDEADBEEF);
isilBuilder.Move(025, InstructionSetIndependentOperand.MakeRegister("reg18"), InstructionSetIndependentOperand.MakeImmediate(0));
isilBuilder.LoadAddress(026, InstructionSetIndependentOperand.MakeRegister("reg19"), InstructionSetIndependentOperand.MakeStack(0x20));
isilBuilder.Move(027, InstructionSetIndependentOperand.MakeRegister("reg20"), InstructionSetIndependentOperand.MakeRegister("reg21"));
isilBuilder.Call(028, 0xDEADBEEF);
isilBuilder.Compare(029, InstructionSetIndependentOperand.MakeRegister("reg22"), InstructionSetIndependentOperand.MakeImmediate(0));
isilBuilder.JumpIfEqual(030, 46);
isilBuilder.Move(031, InstructionSetIndependentOperand.MakeRegister("reg23"), InstructionSetIndependentOperand.MakeStack(0x20));
isilBuilder.ShiftStack(032, 80);
isilBuilder.Pop(033, InstructionSetIndependentOperand.MakeRegister("sp"), InstructionSetIndependentOperand.MakeRegister("reg24"));
isilBuilder.Return(034, InstructionSetIndependentOperand.MakeRegister("reg25"));
isilBuilder.Move(035, InstructionSetIndependentOperand.MakeRegister("reg26"), InstructionSetIndependentOperand.MakeImmediate(0));
isilBuilder.Call(036, 0xDEADBEEF);
isilBuilder.Move(037, InstructionSetIndependentOperand.MakeRegister("reg27"), InstructionSetIndependentOperand.MakeImmediate("input"));
isilBuilder.Move(038, InstructionSetIndependentOperand.MakeRegister("reg28"), InstructionSetIndependentOperand.MakeImmediate(0));
isilBuilder.Move(039, InstructionSetIndependentOperand.MakeRegister("reg29"), InstructionSetIndependentOperand.MakeRegister("reg30"));
isilBuilder.Move(040, InstructionSetIndependentOperand.MakeRegister("reg31"), InstructionSetIndependentOperand.MakeRegister("reg32"));
isilBuilder.Call(041, 0xDEADBEEF);
isilBuilder.Move(042, InstructionSetIndependentOperand.MakeRegister("reg33"), InstructionSetIndependentOperand.MakeMemory(new IsilMemoryOperand(0xDEADBEEF)));
isilBuilder.Move(043, InstructionSetIndependentOperand.MakeRegister("reg34"), InstructionSetIndependentOperand.MakeRegister("reg35"));
isilBuilder.Call(044, 0xDEADBEEF);
isilBuilder.Interrupt(045);
isilBuilder.Move(046, InstructionSetIndependentOperand.MakeRegister("reg36"), InstructionSetIndependentOperand.MakeImmediate(0));
isilBuilder.LoadAddress(047, InstructionSetIndependentOperand.MakeRegister("reg37"), InstructionSetIndependentOperand.MakeStack(0x20));
isilBuilder.Call(048, 0xDEADBEEF);
isilBuilder.Move(049, InstructionSetIndependentOperand.MakeRegister("reg38"), InstructionSetIndependentOperand.MakeMemory(new IsilMemoryOperand(0x1809C39E0)));
isilBuilder.Move(050, InstructionSetIndependentOperand.MakeRegister("reg39"), InstructionSetIndependentOperand.MakeRegister("reg40"));
isilBuilder.Call(051, 0xDEADBEEF);
Add(001, OpCode.ShiftStack, -8);
Add(002, OpCode.Move, new StackOffset(0), new Register(null, "reg1"));
Add(003, OpCode.ShiftStack, -80);
Add(004, OpCode.CheckEqual, new Register(null, "zf"), new Register(null, "reg2"), 0);
Add(005, OpCode.Move, new Register(null, "reg3"), new Register(null, "reg4"));
Add(006, OpCode.Not, new Register(null, "zf"), new Register(null, "zf"));
Add(007, OpCode.ConditionalJump, 11, new Register(null, "zf"));
Add(008, OpCode.Move, new Register(null, "reg5"), 0);
Add(009, OpCode.Call, 0xDEADBEEF);
Add(010, OpCode.Move, new Register(null, "reg6"), 1);
Add(011, OpCode.CheckEqual, new Register(null, "zf"), new Register(null, "reg7"), 0);
Add(012, OpCode.ConditionalJump, 38, new Register(null, "zf"));
Add(013, OpCode.Move, new Register(null, "reg8"), 1);
Add(014, OpCode.Move, new Register(null, "reg9"), 2);
Add(015, OpCode.Move, new Register(null, "reg10"), 3);
Add(016, OpCode.Move, new StackOffset(0x40), new Register(null, "reg11"));
Add(017, OpCode.Move, new Register(null, "reg12"), "input");
Add(018, OpCode.Move, new StackOffset(0x30), new Register(null, "reg13"));
Add(019, OpCode.CheckEqual, new Register(null, "zf"), new Register(null, "reg14"), 2);
Add(020, OpCode.Move, new StackOffset(0x20), new Register(null, "reg15"));
Add(021, OpCode.Move, new StackOffset(0x40), 1);
Add(022, OpCode.Move, new StackOffset(0x38), new Register(null, "reg16"));
Add(023, OpCode.ConditionalJump, 28, new Register(null, "zf"));
Add(024, OpCode.CheckEqual, new Register(null, "zf"), new MemoryOperand(new Register(null, "reg17"), addend: 224), 0);
Add(025, OpCode.Not, new Register(null, "zf"), new Register(null, "zf"));
Add(026, OpCode.ConditionalJump, 28, new Register(null, "zf"));
Add(027, OpCode.Call, 0xDEADBEEF);
Add(028, OpCode.Move, new Register(null, "reg18"), 0);
Add(029, OpCode.Move, new Register(null, "reg19"), new StackOffset(0x20));
Add(030, OpCode.Move, new Register(null, "reg20"), new Register(null, "reg21"));
Add(031, OpCode.Call, 0xDEADBEEF);
Add(032, OpCode.CheckEqual, new Register(null, "zf"), new Register(null, "reg22"), 0);
Add(033, OpCode.ConditionalJump, 50, new Register(null, "zf"));
Add(034, OpCode.Move, new Register(null, "reg23"), new StackOffset(0x20));
Add(035, OpCode.ShiftStack, 80);
Add(036, OpCode.Move, new Register(null, "reg24"), new StackOffset(0));
Add(037, OpCode.ShiftStack, 8);
Add(038, OpCode.Return, new Register(null, "reg25"));
Add(039, OpCode.Move, new Register(null, "reg26"), 0);
Add(040, OpCode.Call, 0xDEADBEEF);
Add(041, OpCode.Move, new Register(null, "reg27"), "input");
Add(042, OpCode.Move, new Register(null, "reg28"), 0);
Add(043, OpCode.Move, new Register(null, "reg29"), new Register(null, "reg30"));
Add(044, OpCode.Move, new Register(null, "reg31"), new Register(null, "reg32"));
Add(045, OpCode.Call, 0xDEADBEEF);
Add(046, OpCode.Move, new Register(null, "reg33"), new MemoryOperand(addend: 0xDEADBEEF));
Add(047, OpCode.Move, new Register(null, "reg34"), new Register(null, "reg35"));
Add(048, OpCode.Call, 0xDEADBEEF);
Add(049, OpCode.Interrupt);
Add(050, OpCode.Move, new Register(null, "reg36"), 0);
Add(051, OpCode.Move, new Register(null, "reg37"), new StackOffset(0x20));
Add(052, OpCode.Call, 0xDEADBEEF);
Add(053, OpCode.Move, new Register(null, "reg38"), new MemoryOperand(addend: 0x1809C39E0));
Add(054, OpCode.Move, new Register(null, "reg39"), new Register(null, "reg40"));
Add(055, OpCode.Call, 0xDEADBEEF);

isilBuilder.FixJumps();
foreach (var instruction in instructions)
{
if (instruction.OpCode != OpCode.Jump && instruction.OpCode != OpCode.ConditionalJump)
continue;
instruction.Operands[0] = instructions[(int)instruction.Operands[0]];
}

graph = new();
graph.Build(isilBuilder.BackingStatementList);
graph = new ISILControlFlowGraph(instructions);
}

[Test]
public void VerifyNumberOfBlocks()
{
Assert.That(graph.Blocks.Count == 18);
Assert.That(graph.Blocks.Count == 19);
}

[Test]
Expand Down
Loading
Loading