Update java code to include parameter names and types

This commit is contained in:
Guus Waals 2025-06-01 23:29:51 +08:00
parent cfb41094d5
commit bd98761921
4 changed files with 164 additions and 28 deletions

View File

@ -17,7 +17,11 @@ public class Test extends GhidraScript {
try (FunctionDatabase db = new FunctionDatabase(this)) {
List<FunctionDatabase.FunctionEntry> entries = db.loadAllEntries();
for (FunctionDatabase.FunctionEntry entry : entries) {
println("entry.name: " + entry.name + " entry.address: " + entry.address + " entry.type: " + entry.type);
println("entry.name: " + entry.name + " entry.address: " + entry.address + " entry.type: " + entry.type
+ " calling_convention: " + entry.callingConvention + " return_type: " + entry.returnType);
if (!entry.parameterNames.isEmpty()) {
println(" parameters: " + entry.parameterNames + " | types: " + entry.parameterTypes);
}
}
}
}

View File

@ -105,17 +105,51 @@ public class FunctionDatabase implements AutoCloseable {
public File file;
public Type type;
public CallingConvention callingConvention;
public String parameterNames; // Semicolon-separated parameter names
public String parameterTypes; // Semicolon-separated parameter types
public String returnType; // Function return type
public FunctionEntry(Address address, String name, File file, Type type) {
this(address, name, file, type, CallingConvention.Cdecl);
}
public FunctionEntry(Address address, String name, File file, Type type, CallingConvention callingConvention) {
public FunctionEntry(Address address, String name, File file, Type type, CallingConvention callingConvention,
String parameterNames, String parameterTypes, String returnType) {
this.address = address;
this.name = name;
this.file = file;
this.type = type;
this.callingConvention = callingConvention;
this.parameterNames = parameterNames != null ? parameterNames : "";
this.parameterTypes = parameterTypes != null ? parameterTypes : "";
this.returnType = returnType != null ? returnType : "void";
}
// Helper methods to work with semicolon-separated parameter lists
public String[] getParameterNamesArray() {
if (parameterNames == null || parameterNames.trim().isEmpty()) {
return new String[0];
}
return parameterNames.split(";");
}
public String[] getParameterTypesArray() {
if (parameterTypes == null || parameterTypes.trim().isEmpty()) {
return new String[0];
}
return parameterTypes.split(";");
}
public void setParameterNamesArray(String[] names) {
if (names == null || names.length == 0) {
this.parameterNames = "";
} else {
this.parameterNames = String.join(";", names);
}
}
public void setParameterTypesArray(String[] types) {
if (types == null || types.length == 0) {
this.parameterTypes = "";
} else {
this.parameterTypes = String.join(";", types);
}
}
}
@ -210,21 +244,21 @@ public class FunctionDatabase implements AutoCloseable {
private void prepareCachedStatements() throws SQLException {
// Find by name
findByNameFunctions = connection.prepareStatement(
"SELECT filepath, name, address, type, calling_convention FROM Functions WHERE name = ?");
"SELECT filepath, name, address, type, calling_convention, parameter_names, parameter_types, return_type FROM Functions WHERE name = ?");
findByNameImports = connection.prepareStatement(
"SELECT filepath, name, address, type, calling_convention FROM Imports WHERE name = ?");
"SELECT filepath, name, address, type, calling_convention, parameter_names, parameter_types, return_type FROM Imports WHERE name = ?");
// Find by address
findByAddressFunctions = connection.prepareStatement(
"SELECT filepath, name, address, type, calling_convention FROM Functions WHERE address = ?");
"SELECT filepath, name, address, type, calling_convention, parameter_names, parameter_types, return_type FROM Functions WHERE address = ?");
findByAddressImports = connection.prepareStatement(
"SELECT filepath, name, address, type, calling_convention FROM Imports WHERE address = ?");
"SELECT filepath, name, address, type, calling_convention, parameter_names, parameter_types, return_type FROM Imports WHERE address = ?");
// Insert or replace
insertOrReplaceFunctions = connection.prepareStatement(
"INSERT OR REPLACE INTO Functions (filepath, name, address, type, calling_convention) VALUES (?, ?, ?, ?, ?)");
"INSERT OR REPLACE INTO Functions (filepath, name, address, type, calling_convention, parameter_names, parameter_types, return_type) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
insertOrReplaceImports = connection.prepareStatement(
"INSERT OR REPLACE INTO Imports (filepath, name, address, type, calling_convention) VALUES (?, ?, ?, ?, ?)");
"INSERT OR REPLACE INTO Imports (filepath, name, address, type, calling_convention, parameter_names, parameter_types, return_type) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
// Delete by filepath
deleteByFilepathFunctions = connection.prepareStatement(
@ -234,9 +268,9 @@ public class FunctionDatabase implements AutoCloseable {
// Load all entries
loadAllFunctions = connection.prepareStatement(
"SELECT filepath, name, address, type, calling_convention FROM Functions");
"SELECT filepath, name, address, type, calling_convention, parameter_names, parameter_types, return_type FROM Functions");
loadAllImports = connection.prepareStatement(
"SELECT filepath, name, address, type, calling_convention FROM Imports");
"SELECT filepath, name, address, type, calling_convention, parameter_names, parameter_types, return_type FROM Imports");
// Global statements
findByNameGlobals = connection.prepareStatement(
@ -314,6 +348,9 @@ public class FunctionDatabase implements AutoCloseable {
String addressStr = rs.getString("address");
int typeValue = rs.getInt("type");
int callingConventionValue = rs.getInt("calling_convention");
String parameterNames = rs.getString("parameter_names");
String parameterTypes = rs.getString("parameter_types");
String returnType = rs.getString("return_type");
if (addressStr != null && !addressStr.isEmpty()) {
Address address = script.getCurrentProgram().getAddressFactory().getAddress(addressStr);
@ -321,7 +358,8 @@ public class FunctionDatabase implements AutoCloseable {
Type type = Type.fromValue(typeValue);
CallingConvention callingConvention = CallingConvention.fromValue(callingConventionValue);
return new FunctionEntry(address, name, file, type, callingConvention);
return new FunctionEntry(address, name, file, type, callingConvention,
parameterNames, parameterTypes, returnType);
}
return null;
}
@ -334,6 +372,9 @@ public class FunctionDatabase implements AutoCloseable {
address TEXT,
type INTEGER DEFAULT 0,
calling_convention INTEGER DEFAULT 0,
parameter_names TEXT DEFAULT '',
parameter_types TEXT DEFAULT '',
return_type TEXT DEFAULT '',
PRIMARY KEY (name, filepath)
)""";
@ -344,6 +385,9 @@ public class FunctionDatabase implements AutoCloseable {
address TEXT,
type INTEGER DEFAULT 0,
calling_convention INTEGER DEFAULT 0,
parameter_names TEXT DEFAULT '',
parameter_types TEXT DEFAULT '',
return_type TEXT DEFAULT '',
PRIMARY KEY (name, filepath)
)""";
@ -444,16 +488,45 @@ public class FunctionDatabase implements AutoCloseable {
insertOrReplaceFunctions.setString(3, entry.address.toString());
insertOrReplaceFunctions.setInt(4, entry.type.getValue());
insertOrReplaceFunctions.setInt(5, entry.callingConvention.getValue());
insertOrReplaceFunctions.setString(6, entry.parameterNames);
insertOrReplaceFunctions.setString(7, entry.parameterTypes);
insertOrReplaceFunctions.setString(8, entry.returnType);
insertOrReplaceFunctions.executeUpdate();
script.println("Added/updated entry: " + entry.name + " at " + entry.address + " in " + relativePath
+ " (calling convention: " + entry.callingConvention + ")");
+ " (calling convention: " + entry.callingConvention + ", return type: " + entry.returnType + ")");
} catch (SQLException e) {
script.println("Error adding entry: " + e.getMessage());
throw new Exception("Failed to add entry", e);
}
}
// Helper method to add import entry
public void addImportEntry(FunctionEntry entry) throws Exception {
ensureConnection();
String relativePath = new File(RemanConfig.INSTANCE.outputDir).toPath()
.relativize(entry.file.toPath()).toString().replace('\\', '/');
try {
insertOrReplaceImports.setString(1, relativePath);
insertOrReplaceImports.setString(2, entry.name);
insertOrReplaceImports.setString(3, entry.address.toString());
insertOrReplaceImports.setInt(4, entry.type.getValue());
insertOrReplaceImports.setInt(5, entry.callingConvention.getValue());
insertOrReplaceImports.setString(6, entry.parameterNames);
insertOrReplaceImports.setString(7, entry.parameterTypes);
insertOrReplaceImports.setString(8, entry.returnType);
insertOrReplaceImports.executeUpdate();
script.println("Added/updated import entry: " + entry.name + " at " + entry.address + " in " + relativePath
+ " (calling convention: " + entry.callingConvention + ", return type: " + entry.returnType + ")");
} catch (SQLException e) {
script.println("Error adding import entry: " + e.getMessage());
throw new Exception("Failed to add import entry", e);
}
}
// Helper method to remove entry by file path
public void removeEntryAt(String filePath) throws Exception {
ensureConnection();
@ -689,7 +762,7 @@ public class FunctionDatabase implements AutoCloseable {
}
}
public void addGlobal(Address address, String name, String dataType) throws Exception {
public void addGlobal(Address address, String name) throws Exception {
ensureConnection();
String filepath = RemanConfig.GLOBAL_H_FILE; // Default filepath for globals
@ -701,7 +774,7 @@ public class FunctionDatabase implements AutoCloseable {
insertOrReplaceGlobals.setString(3, addressStr);
insertOrReplaceGlobals.executeUpdate();
script.println("Added/updated global: " + name + " at " + address + " with type " + dataType);
script.println("Added/updated global: " + name + " at " + address);
} catch (SQLException e) {
script.println("Error adding global: " + e.getMessage());
throw new Exception("Failed to add global", e);

View File

@ -47,6 +47,44 @@ public class FunctionDumper {
initFunctionBlacklist();
}
// Helper method to extract parameter names from Ghidra function
private String extractParameterNames(Function function) {
var parameters = function.getParameters();
if (parameters.length == 0) {
return "";
}
StringBuilder names = new StringBuilder();
for (int i = 0; i < parameters.length; i++) {
if (i > 0) names.append(";");
String paramName = parameters[i].getName();
names.append(paramName != null ? paramName : "param" + i);
}
return names.toString();
}
// Helper method to extract parameter types from Ghidra function
private String extractParameterTypes(Function function) {
var parameters = function.getParameters();
if (parameters.length == 0) {
return "";
}
StringBuilder types = new StringBuilder();
for (int i = 0; i < parameters.length; i++) {
if (i > 0) types.append(";");
String paramType = parameters[i].getDataType().toString();
types.append(paramType != null ? paramType : "void*");
}
return types.toString();
}
// Helper method to extract return type from Ghidra function
private String extractReturnType(Function function) {
var returnType = function.getReturnType();
return returnType != null ? returnType.toString() : "void";
}
boolean isValidFunction(Function function) {
if (functionAddrBlackList.contains(function.getEntryPoint()))
return false;
@ -137,6 +175,13 @@ public class FunctionDumper {
.fromString(callingConventionName);
script.println("Detected calling convention: " + callingConventionName + " -> " + callingConvention);
// Extract parameter information and return type
String parameterNames = extractParameterNames(externalFunction);
String parameterTypes = extractParameterTypes(externalFunction);
String returnType = extractReturnType(externalFunction);
script.println("Parameters: " + parameterNames + " | Types: " + parameterTypes + " | Return: " + returnType);
try (PrintWriter writer2 = new PrintWriter(f4, "UTF-8")) {
writer2.println("// AUTO-GENERATED FILE!!!!");
writer2.println("// This function has yet to be decompiled using 'Dump Current Function' in ghidra");
@ -147,14 +192,13 @@ public class FunctionDumper {
writer2.println("#include <gh_global.h>");
writer2.println();
writer2.println("// " + externalFunction.getEntryPoint());
writer2.println("// " + externalFunction.getName() + "(" + callingConvention + ")");
writer2.println("// " + externalFunction.getName());
// Parse function signature to extract calling convention, return type, and
// parameters
String signature = externalFunction.getSignature().getPrototypeString(false);
signature = signature.replace(externalFunction.getName(), sanitizedExtFunctionName);
script.println("Santized Signature: " + signature);
String returnType = externalFunction.getReturnType().toString();
// Generate function stub using appropriate forwarding function
writer2.println("extern \"C\" " + signature + " {");
@ -196,9 +240,10 @@ public class FunctionDumper {
createdFile = true;
}
// Add stub function to database with calling convention
// Add stub function to database with calling convention and parameter information
FunctionDatabase.FunctionEntry newEntry = new FunctionDatabase.FunctionEntry(externalFunction.getEntryPoint(),
externalFunction.getName(), f4, FunctionDatabase.Type.Stub, callingConvention);
externalFunction.getName(), f4, FunctionDatabase.Type.Stub, callingConvention,
parameterNames, parameterTypes, returnType);
functionDatabase.addEntryAt(newEntry);
}
@ -217,6 +262,13 @@ public class FunctionDumper {
.fromString(callingConventionName);
script.println("Detected calling convention: " + callingConventionName + " -> " + callingConvention);
// Extract parameter information and return type
String parameterNames = extractParameterNames(function);
String parameterTypes = extractParameterTypes(function);
String returnType = extractReturnType(function);
script.println("Parameters: " + parameterNames + " | Types: " + parameterTypes + " | Return: " + returnType);
// Handle forceFixType flag
if (forceFixType) {
targetType = FunctionDatabase.Type.Fix;
@ -284,9 +336,9 @@ public class FunctionDumper {
File f0 = targetFilename;
script.println("Processing " + function.getName() + " => " + f0.toString());
// Update database with calling convention
// Update database with calling convention and parameter information
FunctionDatabase.FunctionEntry newEntry = new FunctionDatabase.FunctionEntry(entrypoint, function.getName(), f0,
targetType, callingConvention);
targetType, callingConvention, parameterNames, parameterTypes, returnType);
functionDatabase.addEntryAt(newEntry);
List<Function> externalFunctionCalls = new ArrayList<>();
@ -433,9 +485,15 @@ public class FunctionDumper {
// Add calling convention information to the comment
String callingConv = externalFunction.getCallingConventionName();
FunctionDatabase.CallingConvention conv = FunctionDatabase.CallingConvention.fromString(callingConv);
// Add parameter information to the comment
String extParamNames = extractParameterNames(externalFunction);
String extParamTypes = extractParameterTypes(externalFunction);
String extReturnType = extractReturnType(externalFunction);
headers.add("" + proto
+ "; // " + externalFunction.getEntryPoint() + " // "
+ name + " // " + conv);
+ name + " // " + conv + " // Params: " + extParamNames + " | Types: " + extParamTypes + " | Return: " + extReturnType);
}
for (String header : headers) {
@ -443,6 +501,8 @@ public class FunctionDumper {
}
writer2.println();
writer2.print("// " + function.getEntryPoint());
writer2.println(" // " + function.getName() + "(" + callingConvention + ")");
writer2.println("// Parameters: " + parameterNames + " | Types: " + parameterTypes + " | Return: " + returnType);
String codeString = codeWriter.toString();
for (HashMap.Entry<String, String> entry : replacementMap.entrySet()) {
String oldName = entry.getKey();

View File

@ -226,8 +226,7 @@ public class GlobalDumper {
// Add all current globals to database
for (GlobalRec global : globalAddrs.values()) {
String dataTypeName = global.type.getDisplayName();
functionDatabase.addGlobal(global.address, global.name, dataTypeName);
functionDatabase.addGlobal(global.address, global.name);
}
}