Skip to content
This repository was archived by the owner on Nov 16, 2025. It is now read-only.

Commit 531161c

Browse files
committed
Refactor label and data renaming utilities
Moved label creation and data renaming logic from handlers to GhidraUtils for reuse and maintainability. Added new handlers: RenameOrLabel for conditional data/label renaming and GetBulkXrefs for retrieving cross-references in bulk. Updated existing handlers to use the new utility methods and improved response handling.
1 parent 4f28450 commit 531161c

6 files changed

Lines changed: 369 additions & 164 deletions

File tree

src/main/java/com/lauriewired/handlers/globals/RenameData.java

Lines changed: 1 addition & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,11 @@
33
import com.lauriewired.handlers.Handler;
44
import com.sun.net.httpserver.HttpExchange;
55
import ghidra.framework.plugintool.PluginTool;
6-
import ghidra.program.model.address.Address;
7-
import ghidra.program.model.listing.Data;
8-
import ghidra.program.model.listing.Listing;
9-
import ghidra.program.model.listing.Program;
10-
import ghidra.program.model.symbol.SourceType;
11-
import ghidra.program.model.symbol.Symbol;
12-
import ghidra.program.model.symbol.SymbolTable;
13-
import ghidra.util.Msg;
146

15-
import javax.swing.*;
167
import java.io.IOException;
17-
import java.lang.reflect.InvocationTargetException;
188
import java.util.Map;
199

10+
import static com.lauriewired.util.GhidraUtils.renameDataAtAddress;
2011
import static com.lauriewired.util.ParseUtils.parsePostParams;
2112
import static com.lauriewired.util.ParseUtils.sendResponse;
2213
import static ghidra.program.util.GhidraProgramUtilities.getCurrentProgram;
@@ -49,43 +40,4 @@ public void handle(HttpExchange exchange) throws IOException {
4940
String result = renameDataAtAddress(params.get("address"), params.get("newName"));
5041
sendResponse(exchange, result);
5142
}
52-
53-
/**
54-
* Renames the data at the specified address in the current program.
55-
* If the data exists, it updates its name; otherwise, it creates a new label.
56-
*
57-
* @param addressStr the address of the data as a string
58-
* @param newName the new name for the data
59-
*/
60-
private void renameDataAtAddress(String addressStr, String newName) {
61-
Program program = getCurrentProgram(tool);
62-
if (program == null)
63-
return;
64-
65-
try {
66-
SwingUtilities.invokeAndWait(() -> {
67-
int tx = program.startTransaction("Rename data");
68-
try {
69-
Address addr = program.getAddressFactory().getAddress(addressStr);
70-
Listing listing = program.getListing();
71-
Data data = listing.getDefinedDataAt(addr);
72-
if (data != null) {
73-
SymbolTable symTable = program.getSymbolTable();
74-
Symbol symbol = symTable.getPrimarySymbol(addr);
75-
if (symbol != null) {
76-
symbol.setName(newName, SourceType.USER_DEFINED);
77-
} else {
78-
symTable.createLabel(addr, newName, SourceType.USER_DEFINED);
79-
}
80-
}
81-
} catch (Exception e) {
82-
Msg.error(this, "Rename data error", e);
83-
} finally {
84-
program.endTransaction(tx, true);
85-
}
86-
});
87-
} catch (InterruptedException | InvocationTargetException e) {
88-
Msg.error(this, "Failed to execute rename data on Swing thread", e);
89-
}
90-
}
9143
}

src/main/java/com/lauriewired/handlers/globals/RenameGlobalVariable.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ public void handle(HttpExchange exchange) throws IOException {
4242
Map<String, String> params = parsePostParams(exchange);
4343
String oldName = params.get("old_name");
4444
String newName = params.get("new_name");
45-
boolean success = renameGlobalVariable(oldName, newName);
46-
sendResponse(exchange, success ? "Global variable renamed successfully" : "Failed to rename global variable");
45+
String result = renameGlobalVariable(oldName, newName);
46+
sendResponse(exchange, result);
4747
}
4848

4949
/**

src/main/java/com/lauriewired/handlers/labels/CreateLabel.java

Lines changed: 1 addition & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,12 @@
33
import com.lauriewired.handlers.Handler;
44
import com.sun.net.httpserver.HttpExchange;
55
import ghidra.framework.plugintool.PluginTool;
6-
import ghidra.program.model.address.Address;
7-
import ghidra.program.model.listing.Program;
8-
import ghidra.program.model.symbol.*;
9-
import ghidra.util.Msg;
106

117
import java.io.IOException;
128
import java.util.Map;
139

1410
import static com.lauriewired.util.GhidraUtils.*;
1511
import static com.lauriewired.util.ParseUtils.*;
16-
import static ghidra.program.util.GhidraProgramUtilities.getCurrentProgram;
17-
1812
/**
1913
* Handler to create a label at a specified address in the current program.
2014
* Expects POST parameters:
@@ -40,68 +34,7 @@ public void handle(HttpExchange exchange) throws IOException {
4034
Map<String, String> params = parsePostParams(exchange);
4135
String address = params.get("address");
4236
String name = params.get("name");
43-
String result = createLabel(address, name);
37+
String result = createLabel(tool, address, name);
4438
sendResponse(exchange, result);
4539
}
46-
47-
private String createLabel(String addressStr, String labelName) {
48-
Program program = getCurrentProgram(tool);
49-
if (program == null) {
50-
return "No program loaded";
51-
}
52-
53-
if (addressStr == null || addressStr.isEmpty()) {
54-
return "Address is required";
55-
}
56-
57-
if (labelName == null || labelName.isEmpty()) {
58-
return "Label name is required";
59-
}
60-
61-
try {
62-
Address address = program.getAddressFactory().getAddress(addressStr);
63-
if (address == null) {
64-
return "Invalid address: " + addressStr;
65-
}
66-
67-
SymbolTable symbolTable = program.getSymbolTable();
68-
69-
// Check if a label with this name already exists at this address
70-
Symbol[] existingSymbols = symbolTable.getSymbols(address);
71-
for (Symbol symbol : existingSymbols) {
72-
if (symbol.getName().equals(labelName) && symbol.getSymbolType() == SymbolType.LABEL) {
73-
return "Label '" + labelName + "' already exists at address " + addressStr;
74-
}
75-
}
76-
77-
// Check if the label name is already used elsewhere (optional warning)
78-
SymbolIterator existingLabels = symbolTable.getSymbolIterator(labelName, true);
79-
if (existingLabels.hasNext()) {
80-
Symbol existingSymbol = existingLabels.next();
81-
if (existingSymbol.getSymbolType() == SymbolType.LABEL) {
82-
// Allow creation but warn about duplicate name
83-
Msg.warn(this, "Label name '" + labelName + "' already exists at address " +
84-
existingSymbol.getAddress() + ". Creating duplicate at " + addressStr);
85-
}
86-
}
87-
88-
// Create the label
89-
int transactionId = program.startTransaction("Create Label");
90-
try {
91-
Symbol newSymbol = symbolTable.createLabel(address, labelName, SourceType.USER_DEFINED);
92-
if (newSymbol != null) {
93-
return "Successfully created label '" + labelName + "' at address " + addressStr;
94-
} else {
95-
return "Failed to create label '" + labelName + "' at address " + addressStr;
96-
}
97-
} catch (Exception e) {
98-
return "Error creating label: " + e.getMessage();
99-
} finally {
100-
program.endTransaction(transactionId, true);
101-
}
102-
103-
} catch (Exception e) {
104-
return "Error processing request: " + e.getMessage();
105-
}
106-
}
10740
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package com.lauriewired.handlers.labels;
2+
3+
import com.lauriewired.handlers.Handler;
4+
import com.sun.net.httpserver.HttpExchange;
5+
import ghidra.framework.plugintool.PluginTool;
6+
import ghidra.program.model.address.Address;
7+
import ghidra.program.model.listing.Data;
8+
import ghidra.program.model.listing.Listing;
9+
import ghidra.program.model.listing.Program;
10+
11+
import java.io.IOException;
12+
import java.util.Map;
13+
14+
import static com.lauriewired.util.GhidraUtils.*;
15+
import static com.lauriewired.util.ParseUtils.*;
16+
import static ghidra.program.util.GhidraProgramUtilities.getCurrentProgram;
17+
18+
/**
19+
* Handler for renaming data or creating a label at a specified address.
20+
* If data is defined at the address, it renames the data; otherwise, it creates a label.
21+
* Expects 'address' and 'name' parameters in the POST request.
22+
*/
23+
public final class RenameOrLabel extends Handler {
24+
/**
25+
* Constructor for the RenameOrLabel handler.
26+
*
27+
* @param tool the PluginTool instance
28+
*/
29+
public RenameOrLabel(PluginTool tool) {
30+
super(tool, "/rename_or_label");
31+
}
32+
33+
/**
34+
* Handles HTTP requests to rename data or create a label at a specified address.
35+
* Expects 'address' and 'name' parameters in the POST request.
36+
*
37+
* @param exchange the HttpExchange object representing the HTTP request and response
38+
* @throws IOException if an I/O error occurs
39+
*/
40+
@Override
41+
public void handle(HttpExchange exchange) throws IOException {
42+
Map<String, String> params = parsePostParams(exchange);
43+
String address = params.get("address");
44+
String name = params.get("name");
45+
String result = renameOrLabel(address, name);
46+
sendResponse(exchange, result);
47+
}
48+
49+
/**
50+
* Renames data at the specified address or creates a label if no data is defined.
51+
*
52+
* @param addressStr the address as a string
53+
* @param newName the new name for the data or label
54+
* @return a success message or an error message
55+
*/
56+
private String renameOrLabel(String addressStr, String newName) {
57+
Program program = getCurrentProgram(tool);
58+
if (program == null) {
59+
return "Error: No program loaded";
60+
}
61+
62+
if (addressStr == null || addressStr.isEmpty()) {
63+
return "Error: Address is required";
64+
}
65+
66+
if (newName == null || newName.isEmpty()) {
67+
return "Error: Name is required";
68+
}
69+
70+
try {
71+
Address address = program.getAddressFactory().getAddress(addressStr);
72+
if (address == null) {
73+
return "Error: Invalid address: " + addressStr;
74+
}
75+
76+
Listing listing = program.getListing();
77+
Data data = listing.getDefinedDataAt(address);
78+
79+
if (data != null) {
80+
// Defined data exists - use rename_data logic
81+
return renameDataAtAddress(addressStr, newName);
82+
} else {
83+
// No defined data - use create_label logic
84+
return createLabel(addressStr, newName);
85+
}
86+
87+
} catch (Exception e) {
88+
return "Error: " + e.getMessage();
89+
}
90+
}
91+
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
package com.lauriewired.handlers.xrefs;
2+
3+
import com.lauriewired.handlers.Handler;
4+
import com.sun.net.httpserver.HttpExchange;
5+
import ghidra.framework.plugintool.PluginTool;
6+
import ghidra.program.model.address.Address;
7+
import ghidra.program.model.listing.Program;
8+
import ghidra.program.model.symbol.Reference;
9+
import ghidra.program.model.symbol.ReferenceIterator;
10+
import ghidra.program.model.symbol.ReferenceManager;
11+
12+
import java.util.ArrayList;
13+
import java.util.List;
14+
import java.util.Map;
15+
16+
import static com.lauriewired.util.ParseUtils.*;
17+
import static ghidra.program.util.GhidraProgramUtilities.getCurrentProgram;
18+
19+
/**
20+
* Handler to retrieve bulk cross-references to a list of addresses in the current program.
21+
* Expects a JSON payload with an "addresses" field containing an array of address strings or a
22+
* comma-separated string of addresses.
23+
* Responds with a JSON object mapping each address to an array of its cross-references.
24+
*/
25+
public final class GetBulkXrefs extends Handler {
26+
/**
27+
* Constructor for the GetBulkXrefs handler.
28+
*
29+
* @param tool the Ghidra plugin tool
30+
*/
31+
public GetBulkXrefs(PluginTool tool) {
32+
super(tool, "/get_bulk_xrefs");
33+
}
34+
35+
/**
36+
* Handles HTTP requests to the /get_bulk_xrefs endpoint.
37+
*
38+
* @param exchange the HTTP exchange
39+
* @throws Exception if an error occurs
40+
*/
41+
@Override
42+
public void handle(HttpExchange exchange) throws Exception {
43+
Map<String, Object> params = parseJsonParams(exchange);
44+
Object addressesObj = params.get("addresses");
45+
String result = getBulkXrefs(addressesObj);
46+
sendResponse(exchange, result);
47+
}
48+
49+
/**
50+
* Retrieves cross-references for a list of addresses in the current program.
51+
*
52+
* @param addressesObj an object representing the list of addresses (array or comma-separated string)
53+
* @return a JSON string mapping each address to its cross-references
54+
*/
55+
private String getBulkXrefs(Object addressesObj) {
56+
Program program = getCurrentProgram(tool);
57+
if (program == null) return "{\"error\": \"No program loaded\"}";
58+
59+
StringBuilder json = new StringBuilder();
60+
json.append("{");
61+
62+
try {
63+
List<String> addresses = new ArrayList<>();
64+
65+
// Parse addresses array
66+
if (addressesObj instanceof List) {
67+
for (Object addr : (List<?>) addressesObj) {
68+
if (addr != null) {
69+
addresses.add(addr.toString());
70+
}
71+
}
72+
} else if (addressesObj instanceof String) {
73+
// Handle comma-separated string
74+
String[] parts = ((String) addressesObj).split(",");
75+
for (String part : parts) {
76+
addresses.add(part.trim());
77+
}
78+
}
79+
80+
ReferenceManager refMgr = program.getReferenceManager();
81+
boolean first = true;
82+
83+
for (String addrStr : addresses) {
84+
if (!first) json.append(",");
85+
first = false;
86+
87+
json.append("\"").append(addrStr).append("\": [");
88+
89+
try {
90+
Address addr = program.getAddressFactory().getAddress(addrStr);
91+
if (addr != null) {
92+
ReferenceIterator refIter = refMgr.getReferencesTo(addr);
93+
boolean firstRef = true;
94+
95+
while (refIter.hasNext()) {
96+
Reference ref = refIter.next();
97+
if (!firstRef) json.append(",");
98+
firstRef = false;
99+
100+
json.append("{");
101+
json.append("\"from\": \"").append(ref.getFromAddress().toString()).append("\",");
102+
json.append("\"type\": \"").append(ref.getReferenceType().getName()).append("\"");
103+
json.append("}");
104+
}
105+
}
106+
} catch (Exception e) {
107+
// Address parsing failed, return empty array
108+
}
109+
110+
json.append("]");
111+
}
112+
} catch (Exception e) {
113+
return "{\"error\": \"" + escapeJson(e.getMessage()) + "\"}";
114+
}
115+
116+
json.append("}");
117+
return json.toString();
118+
}
119+
}

0 commit comments

Comments
 (0)