// 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 { /// public async Task 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); } /// public async Task 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); } }