botw/tools/ghidra_scripts/RenameFunctionsInGhidra.java

119 lines
4.1 KiB
Java

// Script to load BotW CSV data into Ghidra
//@author AlexApps99
//@category BotW
import ghidra.app.script.GhidraScript;
import ghidra.program.model.symbol.SourceType;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.File;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.FunctionManager;
import ghidra.app.cmd.label.DemanglerCmd;
import ghidra.program.model.address.AddressSet;
import ghidra.util.NumericUtilities;
import ghidra.app.cmd.label.DemanglerCmd;
import ghidra.program.model.listing.FunctionTag;
import ghidra.util.exception.DuplicateNameException;
import ghidra.program.model.listing.FunctionTagManager;
public class RenameFunctionsInGhidra extends GhidraScript {
private FunctionManager func_mgr;
private FunctionTagManager func_tag_mgr;
private String ok;
private String minor;
private String major;
private String wip;
private String undecompiled;
private String lib;
private FunctionTag getOrMake(String name) {
FunctionTag f = func_tag_mgr.getFunctionTag(name);
if (f == null) f = func_tag_mgr.createFunctionTag(name, null);
return f;
}
@Override
public void run() throws Exception {
func_mgr = currentProgram.getFunctionManager();
func_tag_mgr = func_mgr.getFunctionTagManager();
ok = getOrMake("OK").getName();
minor = getOrMake("MINOR").getName();
major = getOrMake("MAJOR").getName();
wip = getOrMake("WIP").getName();
undecompiled = getOrMake("UNDECOMPILED").getName();
lib = getOrMake("LIBRARY").getName();
File input_csv = askFile("uking_functions.csv", "Go");
try (BufferedReader br = new BufferedReader(new FileReader(input_csv))) {
// Skip header
String line = br.readLine();
while ((line = br.readLine()) != null) {
String[] pieces = line.split(",", -4); // Don't skip empty last column
if (pieces.length != 4) throw new Exception("Invalid CSV row: " + line);
Address addr = toAddr(pieces[0]);
String status = pieces[1];
long func_size = func_size = NumericUtilities.parseLong(pieces[2].strip());
String name = pieces[3].strip();
Function func = applyFunction(addr, status, name, func_size);
}
}
}
// TODO the j_ prefix probably breaks demangling
private Function applyFunction(Address addr, String status, String name, long func_size) throws Exception {
if (name.isEmpty()) name = null;
Function func = func_mgr.getFunctionAt(addr);
AddressSet body = new AddressSet(addr, addr.addNoWrap(func_size - 1));
if (func != null) {
// Demangling can break this, hence the try-catch
try {
if (func.getName() != name) func.setName(name, SourceType.IMPORTED);
} catch (DuplicateNameException e) {}
if (!func.getBody().hasSameAddresses(body)) {
func.setBody(body);
}
} else {
func = func_mgr.createFunction(name, addr, body, SourceType.IMPORTED);
}
if (name != null) {
DemanglerCmd cmd = new DemanglerCmd(addr, name);
if (!cmd.applyTo(currentProgram, monitor)) {
// Something that isn't mangled
}
}
func.removeTag(ok);
func.removeTag(minor);
func.removeTag(major);
func.removeTag(wip);
func.removeTag(undecompiled);
func.removeTag(lib);
if (status.equals("O")) {
func.addTag(ok);
} else if (status.equals("m")) {
func.addTag(minor);
} else if (status.equals("M")) {
func.addTag(major);
} else if (status.equals("W")) {
func.addTag(wip);
} else if (status.equals("L")) {
func.addTag(lib);
func.addTag(undecompiled);
} else {
func.addTag(undecompiled);
}
return func;
}
}