package com.lauriewired.handlers.set;
import com.lauriewired.handlers.Handler;
import com.sun.net.httpserver.HttpExchange;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.SourceType;
import ghidra.util.Msg;
import javax.swing.*;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import static com.lauriewired.util.ParseUtils.parsePostParams;
import static com.lauriewired.util.ParseUtils.sendResponse;
import static ghidra.program.util.GhidraProgramUtilities.getCurrentProgram;
/**
* Handler to rename a function by its address
*/
public final class RenameFunctionByAddress extends Handler {
/**
* Constructor for the RenameFunctionByAddress handler
*
* @param tool the PluginTool instance
*/
public RenameFunctionByAddress(PluginTool tool) {
super(tool, "/rename_function_by_address");
}
/**
* Handle the HTTP request to rename a function by its address
*
* @param exchange the HttpExchange instance containing the request
* @throws Exception if an error occurs during processing
*/
@Override
public void handle(HttpExchange exchange) throws Exception {
Map<String, String> params = parsePostParams(exchange);
String functionAddress = params.get("function_address");
String newName = params.get("new_name");
String response = renameFunctionByAddress(functionAddress, newName);
sendResponse(exchange, response);
}
/**
* Renames a function by its address.
* Protects functions with names from the original symbol table (IMPORTED source).
*
* @param functionAddrStr the address of the function as a string
* @param newName the new name for the function
* @return result message indicating success, protection, or failure
*/
private String renameFunctionByAddress(String functionAddrStr, String newName) {
Program program = getCurrentProgram(tool);
if (program == null)
return "No program loaded";
if (functionAddrStr == null || functionAddrStr.isEmpty() ||
newName == null || newName.isEmpty()) {
return "Invalid parameters: function_address and new_name are required";
}
final StringBuilder result = new StringBuilder();
try {
SwingUtilities.invokeAndWait(() -> {
performFunctionRename(program, functionAddrStr, newName, result);
});
} catch (InterruptedException | InvocationTargetException e) {
return "Failed to execute rename function on Swing thread: " + e.getMessage();
}
return result.toString();
}
/**
* Performs the function renaming operation on the Swing thread.
* Protects functions with names from the original symbol table (IMPORTED source).
*
* @param program the current program
* @param functionAddrStr the address of the function as a string
* @param newName the new name for the function
* @param result StringBuilder to store the result message
*/
private void performFunctionRename(Program program, String functionAddrStr, String newName, StringBuilder result) {
int tx = program.startTransaction("Rename function by address");
boolean success = false;
try {
Address addr = program.getAddressFactory().getAddress(functionAddrStr);
if (addr == null) {
result.append("Invalid address: " + functionAddrStr);
return;
}
Function func = program.getListing().getFunctionContaining(addr);
if (func == null) {
result.append("No function found at address: " + functionAddrStr);
return;
}
// Check if the function name comes from the original symbol table
if (func.getSymbol().getSource() == SourceType.IMPORTED) {
result.append("Protected: Cannot rename function '" + func.getName() +
"' at " + functionAddrStr + " - name comes from original symbol table (imported symbols are protected)");
return;
}
func.setName(newName, SourceType.USER_DEFINED);
result.append("Successfully renamed function at " + functionAddrStr + " to '" + newName + "'");
success = true;
} catch (Exception e) {
result.append("Error renaming function: " + e.getMessage());
Msg.error(this, "Error renaming function by address", e);
} finally {
program.endTransaction(tx, success);
}
}
}