feat: Add decompiler configuration options

Add toggleCCode, toggleSyntaxTree and setSimplificationStyle controls to
the Java plugin. These allow controlling decompiler output format between
C code (default) and raw decompiler output with syntax trees.

Example usage:
decompile_function_by_address(port=8192, address='0x1000', cCode=True)
decompile_function_by_address(port=8192, address='0x1000', syntaxTree=True)
This commit is contained in:
Teal Bauer 2025-04-08 20:11:11 +02:00
parent bd56f5b6cc
commit 4fe3c16d25
3 changed files with 65 additions and 5 deletions

View File

@ -4,6 +4,30 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
## [Unreleased]
### Added
- Added decompiler output controls to customize analysis results:
- Choose between clean C-like pseudocode (default) or raw decompiler output
- Toggle syntax tree visibility for detailed analysis
- Select different simplification styles for alternate views
- Useful for comparing different decompilation approaches or focusing on specific aspects of the code
Example showing how to get raw decompiler output with syntax tree:
```xml
<use_mcp_tool>
<server_name>ghydra</server_name>
<tool_name>decompile_function_by_address</tool_name>
<arguments>
{
"address": "0x1000",
"cCode": false,
"syntaxTree": true
}
</arguments>
</use_mcp_tool>
```
## [1.4.0] - 2025-04-08
### Added

View File

@ -333,9 +333,24 @@ def list_classes(port: int = DEFAULT_GHIDRA_PORT, offset: int = 0, limit: int =
return safe_get(port, "classes", {"offset": offset, "limit": limit})
@mcp.tool()
def get_function(port: int = DEFAULT_GHIDRA_PORT, name: str = "") -> dict:
"""Get decompiled code for a specific function"""
response = safe_get(port, f"functions/{quote(name)}", {})
def get_function(port: int = DEFAULT_GHIDRA_PORT, name: str = "", cCode: bool = True, syntaxTree: bool = False, simplificationStyle: str = "normalize") -> dict:
"""Get decompiled code for a specific function
Args:
port: Ghidra instance port (default: 8192)
name: Name of the function to decompile
cCode: Whether to output C code (default: True)
syntaxTree: Whether to include syntax tree (default: False)
simplificationStyle: Decompiler analysis style (default: "normalize")
Returns:
Dict containing function details including decompiled code
"""
response = safe_get(port, f"functions/{quote(name)}", {
"cCode": str(cCode).lower(),
"syntaxTree": str(syntaxTree).lower(),
"simplificationStyle": simplificationStyle
})
# Check if the response is a string (old format) or already a dict with proper structure
if isinstance(response, dict) and "success" in response:
@ -524,17 +539,25 @@ def get_current_function(port: int = DEFAULT_GHIDRA_PORT) -> dict: # Return dict
return safe_get(port, "get_current_function")
@mcp.tool()
def decompile_function_by_address(port: int = DEFAULT_GHIDRA_PORT, address: str = "") -> dict:
def decompile_function_by_address(port: int = DEFAULT_GHIDRA_PORT, address: str = "", cCode: bool = True, syntaxTree: bool = False, simplificationStyle: str = "normalize") -> dict:
"""Decompile a function at a specific memory address
Args:
port: Ghidra instance port (default: 8192)
address: Memory address of the function (hex string)
cCode: Whether to output C code (default: True)
syntaxTree: Whether to include syntax tree (default: False)
simplificationStyle: Decompiler analysis style (default: "normalize")
Returns:
Dict containing the decompiled pseudocode in the 'result.decompilation' field
"""
response = safe_get(port, "decompile_function", {"address": address})
response = safe_get(port, "decompile_function", {
"address": address,
"cCode": str(cCode).lower(),
"syntaxTree": str(syntaxTree).lower(),
"simplificationStyle": simplificationStyle
})
# Check if the response is a string (old format) or already a dict with proper structure
if isinstance(response, dict) and "success" in response:

View File

@ -438,6 +438,9 @@ public class GhydraMCPPlugin extends Plugin implements ApplicationLevelPlugin {
if ("GET".equals(exchange.getRequestMethod())) {
Map<String, String> qparams = parseQueryParams(exchange);
String address = qparams.get("address");
boolean cCode = Boolean.parseBoolean(qparams.getOrDefault("cCode", "true"));
boolean syntaxTree = Boolean.parseBoolean(qparams.getOrDefault("syntaxTree", "false"));
String simplificationStyle = qparams.getOrDefault("simplificationStyle", "normalize");
if (address == null || address.isEmpty()) {
sendErrorResponse(exchange, 400, "Address parameter is required");
@ -472,6 +475,11 @@ public class GhydraMCPPlugin extends Plugin implements ApplicationLevelPlugin {
DecompInterface decomp = new DecompInterface();
try {
// Set decompilation options from parameters
decomp.toggleCCode(cCode);
decomp.setSimplificationStyle(simplificationStyle);
decomp.toggleSyntaxTree(syntaxTree);
if (!decomp.openProgram(program)) {
sendErrorResponse(exchange, 500, "Failed to initialize decompiler");
return;
@ -1105,6 +1113,11 @@ public class GhydraMCPPlugin extends Plugin implements ApplicationLevelPlugin {
DecompInterface decomp = new DecompInterface();
try {
// Default to C code output and no syntax tree for better readability
decomp.toggleCCode(true);
decomp.setSimplificationStyle("normalize");
decomp.toggleSyntaxTree(false);
if (!decomp.openProgram(program)) {
resultObj.addProperty("decompilation_error", "Failed to initialize decompiler");
} else {