109 lines
3.1 KiB
C#
109 lines
3.1 KiB
C#
// Copyright (c) StellaOps. All rights reserved.
|
|
// Licensed under BUSL-1.1. See LICENSE in the project root.
|
|
using Microsoft.Extensions.Logging;
|
|
using StellaOps.BinaryIndex.Ghidra;
|
|
|
|
namespace StellaOps.BinaryIndex.Decompiler;
|
|
|
|
public sealed partial class GhidraDecompilerAdapter
|
|
{
|
|
/// <inheritdoc />
|
|
public async Task<DecompiledFunction> DecompileAsync(
|
|
GhidraFunction function,
|
|
DecompileOptions? options = null,
|
|
CancellationToken ct = default)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(function);
|
|
|
|
options ??= new DecompileOptions();
|
|
|
|
_logger.LogDebug(
|
|
"Decompiling function {Name} at 0x{Address:X}",
|
|
function.Name,
|
|
function.Address);
|
|
|
|
var code = function.DecompiledCode;
|
|
|
|
if (string.IsNullOrEmpty(code))
|
|
{
|
|
_logger.LogWarning(
|
|
"Function {Name} has no decompiled code, returning stub",
|
|
function.Name);
|
|
|
|
return new DecompiledFunction(
|
|
function.Name,
|
|
BuildSignature(function),
|
|
"/* Decompilation unavailable */",
|
|
null,
|
|
[],
|
|
[],
|
|
function.Address,
|
|
function.Size);
|
|
}
|
|
|
|
if (code.Length > options.MaxCodeLength)
|
|
{
|
|
code = code[..options.MaxCodeLength] + "\n/* ... truncated ... */";
|
|
}
|
|
|
|
DecompiledAst? ast = null;
|
|
try
|
|
{
|
|
ast = _parser.Parse(code);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogWarning(ex, "Failed to parse decompiled code for {Name}", function.Name);
|
|
}
|
|
|
|
var locals = _parser.ExtractVariables(code);
|
|
var calledFunctions = _parser.ExtractCalledFunctions(code);
|
|
|
|
return new DecompiledFunction(
|
|
function.Name,
|
|
BuildSignature(function),
|
|
code,
|
|
ast,
|
|
locals,
|
|
calledFunctions,
|
|
function.Address,
|
|
function.Size);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<DecompiledFunction> DecompileAtAddressAsync(
|
|
string binaryPath,
|
|
ulong address,
|
|
DecompileOptions? options = null,
|
|
CancellationToken ct = default)
|
|
{
|
|
ArgumentException.ThrowIfNullOrEmpty(binaryPath);
|
|
|
|
options ??= new DecompileOptions();
|
|
|
|
_logger.LogDebug(
|
|
"Decompiling function at 0x{Address:X} in {Binary}",
|
|
address,
|
|
Path.GetFileName(binaryPath));
|
|
|
|
using var stream = File.OpenRead(binaryPath);
|
|
var analysis = await _ghidraService.AnalyzeAsync(
|
|
stream,
|
|
new GhidraAnalysisOptions
|
|
{
|
|
IncludeDecompilation = true,
|
|
ExtractDecompilation = true
|
|
},
|
|
ct).ConfigureAwait(false);
|
|
|
|
var function = analysis.Functions.FirstOrDefault(f => f.Address == address);
|
|
|
|
if (function is null)
|
|
{
|
|
throw new InvalidOperationException($"No function found at address 0x{address:X}");
|
|
}
|
|
|
|
return await DecompileAsync(function, options, ct).ConfigureAwait(false);
|
|
}
|
|
}
|