Skip to main content
Glama
DecompilationService.java12.5 kB
package com.ghidramcp.services; import ghidra.app.decompiler.DecompInterface; import ghidra.app.decompiler.DecompileOptions; import ghidra.app.decompiler.DecompileResults; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressIterator; import ghidra.program.model.address.AddressSetView; import ghidra.program.model.listing.*; import ghidra.program.model.symbol.*; import ghidra.util.Msg; import ghidra.util.task.ConsoleTaskMonitor; import java.util.*; /** * Service for decompilation and data reference operations */ public class DecompilationService { private final FunctionNavigator navigator; private final int decompileTimeout; public DecompilationService(FunctionNavigator navigator, int decompileTimeout) { this.navigator = navigator; this.decompileTimeout = decompileTimeout; } /** * Decompile a function by name * @param name Function name * @return Decompiled C code or error message */ public String decompileFunctionByName(String name) { Program program = navigator.getCurrentProgram(); if (program == null) return "No program loaded"; DecompInterface decomp = new DecompInterface(); DecompileOptions options = new DecompileOptions(); decomp.setOptions(options); decomp.openProgram(program); for (Function func : program.getFunctionManager().getFunctions(true)) { if (func.getName().equals(name)) { DecompileResults result = decomp.decompileFunction(func, this.decompileTimeout, new ConsoleTaskMonitor()); decomp.flushCache(); if (result != null && result.decompileCompleted()) { return result.getDecompiledFunction().getC(); } else { return "Decompilation failed"; } } } return "Function not found"; } /** * Decompile a function by address * @param addressStr Address as string * @return Decompiled C code or error message */ public String decompileFunctionByAddress(String addressStr) { Program program = navigator.getCurrentProgram(); if (program == null) return "No program loaded"; if (addressStr == null || addressStr.isEmpty()) return "Address is required"; try { Address addr = program.getAddressFactory().getAddress(addressStr); Function func = navigator.getFunctionForAddress(program, addr); if (func == null) return "No function found at or containing address " + addressStr; String decompCode = decompileFunctionInProgram(func, program); return (decompCode != null && !decompCode.isEmpty()) ? decompCode : "Decompilation failed"; } catch (Exception e) { return "Error decompiling function: " + e.getMessage(); } } /** * Decompile a function within a program * @param func Function to decompile * @param program Program containing the function * @return Decompiled C code or null */ public String decompileFunctionInProgram(Function func, Program program) { try { DecompInterface decomp = new DecompInterface(); DecompileOptions options = new DecompileOptions(); decomp.setOptions(options); decomp.openProgram(program); DecompileResults result = decomp.decompileFunction(func, this.decompileTimeout, new ConsoleTaskMonitor()); decomp.flushCache(); if (result != null && result.decompileCompleted()) { return result.getDecompiledFunction().getC(); } } catch (Exception e) { Msg.error(this, "Error decompiling function in external program", e); } return null; } /** * Helper method to decompile a function and return results * @param func Function to decompile * @param program Program containing the function * @return Decompilation results or null */ public DecompileResults decompileFunction(Function func, Program program) { // Set up decompiler for accessing the decompiled function DecompInterface decomp = new DecompInterface(); DecompileOptions options = new DecompileOptions(); decomp.setOptions(options); decomp.openProgram(program); decomp.setSimplificationStyle("decompile"); // Full decompilation // Decompile the function DecompileResults results = decomp.decompileFunction(func, this.decompileTimeout, new ConsoleTaskMonitor()); decomp.flushCache(); if (!results.decompileCompleted()) { Msg.error(this, "Could not decompile function: " + results.getErrorMessage()); return null; } return results; } // ==================== DATA REFERENCES ==================== /** * Container for data reference information */ public static class DataReference { public final Address fromAddress; // Where the reference originates public final Address toAddress; // Where the data is located public final Reference reference; // The reference object public final Data data; // The data object public final String label; // Symbol/label (e.g., "DAT_0022d5f6") public final String dataType; // Data type (e.g., "dword", "char[10]") public final Object value; // Data value (if available) public DataReference(Address from, Address to, Reference ref, Data data) { this.fromAddress = from; this.toAddress = to; this.reference = ref; this.data = data; // Get label/symbol Symbol symbol = data.getProgram().getSymbolTable().getPrimarySymbol(to); this.label = symbol != null ? symbol.getName() : to.toString(); // Get data type this.dataType = data.getDataType().getDisplayName(); // Get value (may be null for some types) Object tempValue; try { tempValue = data.getValue(); } catch (Exception e) { tempValue = null; } this.value = tempValue; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(label); sb.append(" (").append(toAddress).append(")"); sb.append(" - Type: ").append(dataType); if (value != null) { sb.append(", Value: ").append(value); } return sb.toString(); } } /** * Get all data references from a function * @param func Function to analyze * @param program Program containing the function * @return List of data references with details */ public List<DataReference> getDataReferencesFromFunction(Function func, Program program) { List<DataReference> dataRefs = new ArrayList<>(); ReferenceManager refMgr = program.getReferenceManager(); Listing listing = program.getListing(); Set<Address> seenAddresses = new HashSet<>(); // Avoid duplicates // Get all addresses in the function body AddressSetView functionBody = func.getBody(); // Iterate through all addresses in the function AddressIterator addrIter = functionBody.getAddresses(true); while (addrIter.hasNext()) { Address fromAddr = addrIter.next(); // Get all references FROM this address Reference[] refs = refMgr.getReferencesFrom(fromAddr); for (Reference ref : refs) { // Skip if not a memory reference if (!ref.isMemoryReference()) { continue; } Address toAddr = ref.getToAddress(); // Skip if we've already seen this data address if (seenAddresses.contains(toAddr)) { continue; } // Check if the destination is data (not an instruction) Data data = listing.getDataAt(toAddr); if (data == null) { continue; } seenAddresses.add(toAddr); dataRefs.add(new DataReference(fromAddr, toAddr, ref, data)); } } // Sort by data address for consistent output dataRefs.sort((a, b) -> a.toAddress.compareTo(b.toAddress)); return dataRefs; } /** * Get data references from a function as formatted text * @param func Function to analyze * @param program Program containing the function * @return Formatted string with data references */ public String getDataReferencesAsText(Function func, Program program) { List<DataReference> dataRefs = getDataReferencesFromFunction(func, program); StringBuilder result = new StringBuilder(); result.append("Data references from ").append(func.getName()); result.append(" (").append(func.getEntryPoint()).append("):\n\n"); if (dataRefs.isEmpty()) { result.append(" No data references found.\n"); return result.toString(); } // Calculate column widths for alignment int maxLabelLen = 20; for (DataReference ref : dataRefs) { maxLabelLen = Math.max(maxLabelLen, ref.label.length()); } // Header result.append(String.format(" %-" + maxLabelLen + "s %-12s %-20s %-12s %s\n", "Symbol", "Address", "Type", "RefFrom", "Value")); result.append(" " + "-".repeat(maxLabelLen + 70) + "\n"); // Data references for (DataReference ref : dataRefs) { String valueStr = ref.value != null ? ref.value.toString() : ""; // Handle string values specially if (ref.data.hasStringValue()) { try { Object strValue = ref.data.getValue(); if (strValue != null) { valueStr = "\"" + strValue.toString() + "\""; } } catch (Exception e) { // Keep default valueStr } } if (valueStr.length() > 40) { valueStr = valueStr.substring(0, 37) + "..."; } result.append(String.format(" %-" + maxLabelLen + "s %-12s %-20s %-12s %s\n", ref.label, ref.toAddress.toString(), ref.dataType, ref.fromAddress.toString(), valueStr)); } result.append("\n Total: ").append(dataRefs.size()).append(" data references\n"); return result.toString(); } /** * Get data references from a function by name * @param functionName Function name * @return Formatted string with data references */ public String getDataReferencesFromFunctionByName(String functionName) { Program program = navigator.getCurrentProgram(); if (program == null) return "No program loaded"; for (Function func : program.getFunctionManager().getFunctions(true)) { if (func.getName().equals(functionName)) { return getDataReferencesAsText(func, program); } } return "Function not found: " + functionName; } /** * Get data references from a function by address * @param addressStr Address as string * @return Formatted string with data references */ public String getDataReferencesFromFunctionByAddress(String addressStr) { Program program = navigator.getCurrentProgram(); if (program == null) return "No program loaded"; if (addressStr == null || addressStr.isEmpty()) return "Address is required"; try { Address addr = program.getAddressFactory().getAddress(addressStr); Function func = navigator.getFunctionForAddress(program, addr); if (func == null) return "No function found at or containing address " + addressStr; return getDataReferencesAsText(func, program); } catch (Exception e) { return "Error getting data references: " + e.getMessage(); } } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/HK47196/GhidraMCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server