mcghidra/src/main/java/eu/starsong/ghidra/endpoints/SegmentEndpoints.java
2025-04-14 00:08:10 +02:00

116 lines
5.0 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 eu.starsong.ghidra.api.ResponseBuilder;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.util.Msg;
import java.io.IOException;
import java.util.*;
public class SegmentEndpoints extends AbstractEndpoint {
private PluginTool tool;
// Updated constructor to accept port
public SegmentEndpoints(Program program, int port) {
super(program, port); // Call super constructor
}
public SegmentEndpoints(Program program, int port, PluginTool tool) {
super(program, port);
this.tool = tool;
}
@Override
protected PluginTool getTool() {
return tool;
}
@Override
public void registerEndpoints(HttpServer server) {
server.createContext("/segments", this::handleSegments);
}
public void handleSegments(HttpExchange exchange) throws IOException {
try {
if ("GET".equals(exchange.getRequestMethod())) {
Map<String, String> qparams = parseQueryParams(exchange);
int offset = parseIntOrDefault(qparams.get("offset"), 0);
int limit = parseIntOrDefault(qparams.get("limit"), 100);
String nameFilter = qparams.get("name");
Program program = getCurrentProgram();
if (program == null) {
sendErrorResponse(exchange, 400, "No program loaded", "NO_PROGRAM_LOADED");
return;
}
List<Map<String, Object>> segments = new ArrayList<>();
for (MemoryBlock block : program.getMemory().getBlocks()) {
// Apply name filter if present
if (nameFilter != null && !block.getName().contains(nameFilter)) {
continue;
}
Map<String, Object> segment = new HashMap<>();
segment.put("name", block.getName());
segment.put("start", block.getStart().toString());
segment.put("end", block.getEnd().toString());
segment.put("size", block.getSize());
// Add permissions
segment.put("readable", block.isRead());
segment.put("writable", block.isWrite());
segment.put("executable", block.isExecute());
segment.put("initialized", block.isInitialized());
// Add HATEOAS links for this segment
Map<String, Object> links = new HashMap<>();
Map<String, String> selfLink = new HashMap<>();
selfLink.put("href", "/segments/" + block.getName());
links.put("self", selfLink);
Map<String, String> memoryLink = new HashMap<>();
memoryLink.put("href", "/memory/" + block.getStart());
links.put("memory", memoryLink);
segment.put("_links", links);
segments.add(segment);
}
// Build response with HATEOAS links
ResponseBuilder builder = new ResponseBuilder(exchange, port)
.success(true);
// Handle optional name filter
String queryParams = nameFilter != null ? "name=" + nameFilter : null;
// Apply pagination and get paginated items
List<Map<String, Object>> paginatedSegments = applyPagination(
segments, offset, limit, builder, "/segments", queryParams);
// Set the paginated result
builder.result(paginatedSegments);
// Add program link
builder.addLink("program", "/program");
sendJsonResponse(exchange, builder.build(), 200);
} else {
sendErrorResponse(exchange, 405, "Method Not Allowed", "METHOD_NOT_ALLOWED");
}
} catch (Exception e) {
Msg.error(this, "Error in /segments endpoint", e);
sendErrorResponse(exchange, 500, "Internal server error: " + e.getMessage(), "INTERNAL_ERROR");
}
}
// parseIntOrDefault is inherited from AbstractEndpoint
}