feat: add line filtering to decompile for context management
Add start_line, end_line, and max_lines parameters to decompile functions, allowing AI models to retrieve only specific portions of decompiled code for better context management. Parameters: - start_line: Start at this line number (1-indexed) - end_line: End at this line number (inclusive) - max_lines: Maximum lines to return (overrides end_line) Response includes filter metadata with total_lines when filtering is applied, helping models understand what portion they're viewing. Examples: - Get first 20 lines: max_lines=20 - Get lines 10-30: start_line=10, end_line=30 - Get 15 lines from line 25: start_line=25, max_lines=15
This commit is contained in:
parent
60124d2315
commit
662e202482
@ -1351,20 +1351,35 @@ def functions_get(name: str = None, address: str = None, port: int = None) -> di
|
|||||||
return simplify_response(response)
|
return simplify_response(response)
|
||||||
|
|
||||||
@mcp.tool()
|
@mcp.tool()
|
||||||
def functions_decompile(name: str = None, address: str = None,
|
def functions_decompile(name: str = None, address: str = None,
|
||||||
syntax_tree: bool = False, style: str = "normalize",
|
syntax_tree: bool = False, style: str = "normalize",
|
||||||
|
start_line: int = None, end_line: int = None, max_lines: int = None,
|
||||||
port: int = None) -> dict:
|
port: int = None) -> dict:
|
||||||
"""Get decompiled code for a function
|
"""Get decompiled code for a function with optional line filtering for context management
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
name: Function name (mutually exclusive with address)
|
name: Function name (mutually exclusive with address)
|
||||||
address: Function address in hex format (mutually exclusive with name)
|
address: Function address in hex format (mutually exclusive with name)
|
||||||
syntax_tree: Include syntax tree (default: False)
|
syntax_tree: Include syntax tree (default: False)
|
||||||
style: Decompiler style (default: "normalize")
|
style: Decompiler style (default: "normalize")
|
||||||
|
start_line: Start at this line number (1-indexed, optional)
|
||||||
|
end_line: End at this line number (inclusive, optional)
|
||||||
|
max_lines: Maximum number of lines to return (optional, takes precedence over end_line)
|
||||||
port: Specific Ghidra instance port (optional)
|
port: Specific Ghidra instance port (optional)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: Contains function information and decompiled code
|
dict: Contains function information and decompiled code (potentially filtered).
|
||||||
|
If filtering is applied, includes a 'filter' object with total_lines and applied parameters.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
# Get first 20 lines of decompiled code
|
||||||
|
functions_decompile(name="main", max_lines=20)
|
||||||
|
|
||||||
|
# Get lines 10-30
|
||||||
|
functions_decompile(name="main", start_line=10, end_line=30)
|
||||||
|
|
||||||
|
# Get 15 lines starting from line 25
|
||||||
|
functions_decompile(name="main", start_line=25, max_lines=15)
|
||||||
"""
|
"""
|
||||||
if not name and not address:
|
if not name and not address:
|
||||||
return {
|
return {
|
||||||
@ -1375,22 +1390,30 @@ def functions_decompile(name: str = None, address: str = None,
|
|||||||
},
|
},
|
||||||
"timestamp": int(time.time() * 1000)
|
"timestamp": int(time.time() * 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
port = _get_instance_port(port)
|
port = _get_instance_port(port)
|
||||||
|
|
||||||
params = {
|
params = {
|
||||||
"syntax_tree": str(syntax_tree).lower(),
|
"syntax_tree": str(syntax_tree).lower(),
|
||||||
"style": style
|
"style": style
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Add line filtering parameters if provided
|
||||||
|
if start_line is not None:
|
||||||
|
params["start_line"] = str(start_line)
|
||||||
|
if end_line is not None:
|
||||||
|
params["end_line"] = str(end_line)
|
||||||
|
if max_lines is not None:
|
||||||
|
params["max_lines"] = str(max_lines)
|
||||||
|
|
||||||
if address:
|
if address:
|
||||||
endpoint = f"functions/{address}/decompile"
|
endpoint = f"functions/{address}/decompile"
|
||||||
else:
|
else:
|
||||||
endpoint = f"functions/by-name/{quote(name)}/decompile"
|
endpoint = f"functions/by-name/{quote(name)}/decompile"
|
||||||
|
|
||||||
response = safe_get(port, endpoint, params)
|
response = safe_get(port, endpoint, params)
|
||||||
simplified = simplify_response(response)
|
simplified = simplify_response(response)
|
||||||
|
|
||||||
return simplified
|
return simplified
|
||||||
|
|
||||||
@mcp.tool()
|
@mcp.tool()
|
||||||
|
|||||||
@ -1090,20 +1090,67 @@ public class FunctionEndpoints extends AbstractEndpoint {
|
|||||||
String style = params.getOrDefault("style", "normalize");
|
String style = params.getOrDefault("style", "normalize");
|
||||||
String format = params.getOrDefault("format", "structured");
|
String format = params.getOrDefault("format", "structured");
|
||||||
int timeout = parseIntOrDefault(params.get("timeout"), 30);
|
int timeout = parseIntOrDefault(params.get("timeout"), 30);
|
||||||
|
|
||||||
|
// Line filtering parameters for context management
|
||||||
|
int startLine = parseIntOrDefault(params.get("start_line"), -1);
|
||||||
|
int endLine = parseIntOrDefault(params.get("end_line"), -1);
|
||||||
|
int maxLines = parseIntOrDefault(params.get("max_lines"), -1);
|
||||||
|
|
||||||
// Decompile function
|
// Decompile function
|
||||||
String decompilation = GhidraUtil.decompileFunction(function);
|
String decompilation = GhidraUtil.decompileFunction(function);
|
||||||
|
|
||||||
|
// Apply line filtering if requested
|
||||||
|
String filteredDecompilation = decompilation;
|
||||||
|
int totalLines = 0;
|
||||||
|
if (decompilation != null) {
|
||||||
|
String[] lines = decompilation.split("\n");
|
||||||
|
totalLines = lines.length;
|
||||||
|
|
||||||
|
// Apply line range filtering
|
||||||
|
if (startLine > 0 || endLine > 0 || maxLines > 0) {
|
||||||
|
int start = startLine > 0 ? Math.max(0, startLine - 1) : 0;
|
||||||
|
int end = endLine > 0 ? Math.min(lines.length, endLine) : lines.length;
|
||||||
|
|
||||||
|
// If maxLines is specified, limit the range
|
||||||
|
if (maxLines > 0) {
|
||||||
|
end = Math.min(end, start + maxLines);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start < lines.length) {
|
||||||
|
StringBuilder filtered = new StringBuilder();
|
||||||
|
for (int i = start; i < end && i < lines.length; i++) {
|
||||||
|
if (i > start) {
|
||||||
|
filtered.append("\n");
|
||||||
|
}
|
||||||
|
filtered.append(lines[i]);
|
||||||
|
}
|
||||||
|
filteredDecompilation = filtered.toString();
|
||||||
|
} else {
|
||||||
|
filteredDecompilation = "// No lines in specified range";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create function info
|
// Create function info
|
||||||
Map<String, Object> functionInfo = new HashMap<>();
|
Map<String, Object> functionInfo = new HashMap<>();
|
||||||
functionInfo.put("address", function.getEntryPoint().toString());
|
functionInfo.put("address", function.getEntryPoint().toString());
|
||||||
functionInfo.put("name", function.getName());
|
functionInfo.put("name", function.getName());
|
||||||
|
|
||||||
// Create the result structure according to GHIDRA_HTTP_API.md
|
// Create the result structure according to GHIDRA_HTTP_API.md
|
||||||
Map<String, Object> result = new HashMap<>();
|
Map<String, Object> result = new HashMap<>();
|
||||||
result.put("function", functionInfo);
|
result.put("function", functionInfo);
|
||||||
result.put("decompiled", decompilation != null ? decompilation : "// Decompilation failed");
|
result.put("decompiled", filteredDecompilation != null ? filteredDecompilation : "// Decompilation failed");
|
||||||
|
|
||||||
|
// Add metadata about line filtering if applied
|
||||||
|
if (startLine > 0 || endLine > 0 || maxLines > 0) {
|
||||||
|
Map<String, Object> filterInfo = new HashMap<>();
|
||||||
|
filterInfo.put("total_lines", totalLines);
|
||||||
|
if (startLine > 0) filterInfo.put("start_line", startLine);
|
||||||
|
if (endLine > 0) filterInfo.put("end_line", endLine);
|
||||||
|
if (maxLines > 0) filterInfo.put("max_lines", maxLines);
|
||||||
|
result.put("filter", filterInfo);
|
||||||
|
}
|
||||||
|
|
||||||
// Add syntax tree if requested
|
// Add syntax tree if requested
|
||||||
if (syntaxTree) {
|
if (syntaxTree) {
|
||||||
result.put("syntax_tree", "Syntax tree not implemented");
|
result.put("syntax_tree", "Syntax tree not implemented");
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user