Files
git.stella-ops.org/src/BinaryIndex/__Libraries/StellaOps.BinaryIndex.Decompiler/GhidraDecompilerAdapter.Decompile.cs
2026-02-04 19:59:20 +02:00

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);
}
}