save progress
This commit is contained in:
@@ -0,0 +1,208 @@
|
||||
// Copyright (c) StellaOps. All rights reserved.
|
||||
// Licensed under AGPL-3.0-or-later. See LICENSE in the project root.
|
||||
|
||||
using System.Collections.Immutable;
|
||||
using FluentAssertions;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using StellaOps.BinaryIndex.Disassembly;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.BinaryIndex.Semantic.Tests;
|
||||
|
||||
[Trait("Category", "Unit")]
|
||||
public class IrLiftingServiceTests
|
||||
{
|
||||
private readonly IrLiftingService _sut;
|
||||
|
||||
public IrLiftingServiceTests()
|
||||
{
|
||||
_sut = new IrLiftingService(NullLogger<IrLiftingService>.Instance);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(CpuArchitecture.X86)]
|
||||
[InlineData(CpuArchitecture.X86_64)]
|
||||
[InlineData(CpuArchitecture.ARM32)]
|
||||
[InlineData(CpuArchitecture.ARM64)]
|
||||
public void SupportsArchitecture_ShouldReturnTrue_ForSupportedArchitectures(CpuArchitecture arch)
|
||||
{
|
||||
// Act
|
||||
var result = _sut.SupportsArchitecture(arch);
|
||||
|
||||
// Assert
|
||||
result.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(CpuArchitecture.MIPS32)]
|
||||
[InlineData(CpuArchitecture.RISCV64)]
|
||||
[InlineData(CpuArchitecture.Unknown)]
|
||||
public void SupportsArchitecture_ShouldReturnFalse_ForUnsupportedArchitectures(CpuArchitecture arch)
|
||||
{
|
||||
// Act
|
||||
var result = _sut.SupportsArchitecture(arch);
|
||||
|
||||
// Assert
|
||||
result.Should().BeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task LiftToIrAsync_ShouldLiftSimpleInstructions()
|
||||
{
|
||||
// Arrange
|
||||
var instructions = new List<DisassembledInstruction>
|
||||
{
|
||||
CreateInstruction(0x1000, "MOV", InstructionKind.Move, "RAX", "RBX"),
|
||||
CreateInstruction(0x1004, "ADD", InstructionKind.Arithmetic, "RAX", "RCX"),
|
||||
CreateInstruction(0x1008, "RET", InstructionKind.Return)
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _sut.LiftToIrAsync(
|
||||
instructions,
|
||||
"test_func",
|
||||
0x1000,
|
||||
CpuArchitecture.X86_64);
|
||||
|
||||
// Assert
|
||||
result.Should().NotBeNull();
|
||||
result.Name.Should().Be("test_func");
|
||||
result.Address.Should().Be(0x1000);
|
||||
result.Statements.Should().HaveCount(3);
|
||||
result.BasicBlocks.Should().NotBeEmpty();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task LiftToIrAsync_ShouldCreateBasicBlocksOnBranches()
|
||||
{
|
||||
// Arrange
|
||||
var instructions = new List<DisassembledInstruction>
|
||||
{
|
||||
CreateInstruction(0x1000, "MOV", InstructionKind.Move, "RAX", "0"),
|
||||
CreateInstruction(0x1004, "CMP", InstructionKind.Compare, "RAX", "10"),
|
||||
CreateInstruction(0x1008, "JE", InstructionKind.ConditionalBranch, "0x1020"),
|
||||
CreateInstruction(0x100C, "ADD", InstructionKind.Arithmetic, "RAX", "1"),
|
||||
CreateInstruction(0x1010, "RET", InstructionKind.Return)
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _sut.LiftToIrAsync(
|
||||
instructions,
|
||||
"branch_func",
|
||||
0x1000,
|
||||
CpuArchitecture.X86_64);
|
||||
|
||||
// Assert
|
||||
result.BasicBlocks.Should().HaveCountGreaterThan(1);
|
||||
result.Cfg.Edges.Should().NotBeEmpty();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task LiftToIrAsync_ShouldThrow_ForUnsupportedArchitecture()
|
||||
{
|
||||
// Arrange
|
||||
var instructions = new List<DisassembledInstruction>
|
||||
{
|
||||
CreateInstruction(0x1000, "NOP", InstructionKind.Nop)
|
||||
};
|
||||
|
||||
// Act
|
||||
var act = () => _sut.LiftToIrAsync(
|
||||
instructions,
|
||||
"test",
|
||||
0x1000,
|
||||
CpuArchitecture.MIPS32);
|
||||
|
||||
// Assert
|
||||
await act.Should().ThrowAsync<NotSupportedException>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TransformToSsaAsync_ShouldVersionVariables()
|
||||
{
|
||||
// Arrange
|
||||
var instructions = new List<DisassembledInstruction>
|
||||
{
|
||||
CreateInstruction(0x1000, "MOV", InstructionKind.Move, "RAX", "0"),
|
||||
CreateInstruction(0x1004, "ADD", InstructionKind.Arithmetic, "RAX", "1"),
|
||||
CreateInstruction(0x1008, "ADD", InstructionKind.Arithmetic, "RAX", "2"),
|
||||
CreateInstruction(0x100C, "RET", InstructionKind.Return)
|
||||
};
|
||||
|
||||
var lifted = await _sut.LiftToIrAsync(
|
||||
instructions,
|
||||
"ssa_test",
|
||||
0x1000,
|
||||
CpuArchitecture.X86_64);
|
||||
|
||||
// Act
|
||||
var ssa = await _sut.TransformToSsaAsync(lifted);
|
||||
|
||||
// Assert
|
||||
ssa.Should().NotBeNull();
|
||||
ssa.Name.Should().Be("ssa_test");
|
||||
ssa.Statements.Should().HaveCount(4);
|
||||
|
||||
// RAX should have multiple versions
|
||||
var raxVersions = ssa.Statements
|
||||
.Where(s => s.Destination?.BaseName == "RAX")
|
||||
.Select(s => s.Destination!.Version)
|
||||
.Distinct()
|
||||
.ToList();
|
||||
|
||||
raxVersions.Should().HaveCountGreaterThan(1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TransformToSsaAsync_ShouldBuildDefUseChains()
|
||||
{
|
||||
// Arrange
|
||||
var instructions = new List<DisassembledInstruction>
|
||||
{
|
||||
CreateInstruction(0x1000, "MOV", InstructionKind.Move, "RAX", "0"),
|
||||
CreateInstruction(0x1004, "ADD", InstructionKind.Arithmetic, "RBX", "RAX"),
|
||||
CreateInstruction(0x1008, "RET", InstructionKind.Return)
|
||||
};
|
||||
|
||||
var lifted = await _sut.LiftToIrAsync(
|
||||
instructions,
|
||||
"defuse_test",
|
||||
0x1000,
|
||||
CpuArchitecture.X86_64);
|
||||
|
||||
// Act
|
||||
var ssa = await _sut.TransformToSsaAsync(lifted);
|
||||
|
||||
// Assert
|
||||
ssa.DefUse.Should().NotBeNull();
|
||||
ssa.DefUse.Definitions.Should().NotBeEmpty();
|
||||
}
|
||||
|
||||
private static DisassembledInstruction CreateInstruction(
|
||||
ulong address,
|
||||
string mnemonic,
|
||||
InstructionKind kind,
|
||||
params string[] operands)
|
||||
{
|
||||
var ops = operands.Select((o, i) =>
|
||||
{
|
||||
if (long.TryParse(o, out var val))
|
||||
{
|
||||
return new Operand(OperandType.Immediate, o, val);
|
||||
}
|
||||
if (o.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return new Operand(OperandType.Address, o);
|
||||
}
|
||||
return new Operand(OperandType.Register, o, Register: o);
|
||||
}).ToImmutableArray();
|
||||
|
||||
return new DisassembledInstruction(
|
||||
address,
|
||||
[0x90], // NOP placeholder
|
||||
mnemonic,
|
||||
string.Join(", ", operands),
|
||||
kind,
|
||||
ops);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user