mcghidra/src/main/java/eu/starsong/ghidra/endpoints/SymbolEndpoints.java
2025-04-10 14:42:53 +02:00

143 lines
6.3 KiB
Java

package eu.starsong.ghidra.endpoints;
import com.google.gson.JsonObject;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpServer;
import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.Symbol;
import ghidra.program.model.symbol.SymbolIterator;
import ghidra.program.model.symbol.SymbolTable;
import ghidra.util.Msg;
import java.io.IOException;
import java.util.*;
public class SymbolEndpoints extends AbstractEndpoint {
// Updated constructor to accept port
public SymbolEndpoints(Program program, int port) {
super(program, port); // Call super constructor
}
@Override
public void registerEndpoints(HttpServer server) {
server.createContext("/symbols/imports", this::handleImports);
server.createContext("/symbols/exports", this::handleExports);
}
private void handleImports(HttpExchange exchange) throws IOException {
try {
if ("GET".equals(exchange.getRequestMethod())) {
Map<String, String> qparams = parseQueryParams(exchange);
int offset = parseIntOrDefault(qparams.get("offset"), 0); // Inherited
int limit = parseIntOrDefault(qparams.get("limit"), 100); // Inherited
Object resultData = listImports(offset, limit);
// Check if helper returned an error object
if (resultData instanceof JsonObject && !((JsonObject)resultData).get("success").getAsBoolean()) {
sendJsonResponse(exchange, (JsonObject)resultData, 400); // Use base sendJsonResponse
} else {
sendSuccessResponse(exchange, resultData); // Use success helper
}
} else {
sendErrorResponse(exchange, 405, "Method Not Allowed"); // Inherited
}
} catch (Exception e) {
Msg.error(this, "Error in /symbols/imports endpoint", e);
sendErrorResponse(exchange, 500, "Internal server error: " + e.getMessage()); // Inherited
}
}
private void handleExports(HttpExchange exchange) throws IOException {
try {
if ("GET".equals(exchange.getRequestMethod())) {
Map<String, String> qparams = parseQueryParams(exchange);
int offset = parseIntOrDefault(qparams.get("offset"), 0); // Inherited
int limit = parseIntOrDefault(qparams.get("limit"), 100); // Inherited
Object resultData = listExports(offset, limit);
// Check if helper returned an error object
if (resultData instanceof JsonObject && !((JsonObject)resultData).get("success").getAsBoolean()) {
sendJsonResponse(exchange, (JsonObject)resultData, 400); // Use base sendJsonResponse
} else {
sendSuccessResponse(exchange, resultData); // Use success helper
}
} else {
sendErrorResponse(exchange, 405, "Method Not Allowed"); // Inherited
}
} catch (Exception e) {
Msg.error(this, "Error in /symbols/exports endpoint", e);
sendErrorResponse(exchange, 500, "Internal server error: " + e.getMessage()); // Inherited
}
}
// --- Methods moved from GhydraMCPPlugin ---
private JsonObject listImports(int offset, int limit) {
if (currentProgram == null) {
return createErrorResponse("No program loaded", 400);
}
List<Map<String, String>> imports = new ArrayList<>();
for (Symbol symbol : currentProgram.getSymbolTable().getExternalSymbols()) {
Map<String, String> imp = new HashMap<>();
imp.put("name", symbol.getName());
imp.put("address", symbol.getAddress().toString());
// Add library name if needed: symbol.getLibraryName()
imports.add(imp);
}
// Apply pagination
int start = Math.max(0, offset);
int end = Math.min(imports.size(), offset + limit);
List<Map<String, String>> paginated = imports.subList(start, end);
return createSuccessResponse(paginated);
}
private JsonObject listExports(int offset, int limit) {
if (currentProgram == null) {
return createErrorResponse("No program loaded", 400);
}
List<Map<String, String>> exports = new ArrayList<>();
SymbolTable table = currentProgram.getSymbolTable();
SymbolIterator it = table.getAllSymbols(true);
while (it.hasNext()) {
Symbol s = it.next();
if (s.isExternalEntryPoint()) {
Map<String, String> exp = new HashMap<>();
exp.put("name", s.getName());
exp.put("address", s.getAddress().toString());
exports.add(exp);
}
}
// Apply pagination
int start = Math.max(0, offset);
int end = Math.min(exports.size(), offset + limit);
List<Map<String, String>> paginated = exports.subList(start, end);
return createSuccessResponse(paginated); // Keep internal helper for now
}
// --- Helper Methods (Keep internal for now, refactor later if needed) ---
// Note: These might differ slightly from AbstractEndpoint/ResponseBuilder, review needed.
private JsonObject createSuccessResponse(Object resultData) {
JsonObject response = new JsonObject();
response.addProperty("success", true);
response.add("result", gson.toJsonTree(resultData));
return response;
}
private JsonObject createErrorResponse(String errorMessage, int statusCode) {
JsonObject response = new JsonObject();
response.addProperty("success", false);
response.addProperty("error", errorMessage);
response.addProperty("status_code", statusCode);
return response;
}
// parseIntOrDefault is inherited from AbstractEndpoint
}