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)) { try (FunctionDatabase db = new FunctionDatabase(this)) {
List<FunctionDatabase.FunctionEntry> entries = db.loadAllEntries(); List<FunctionDatabase.FunctionEntry> entries = db.loadAllEntries();
for (FunctionDatabase.FunctionEntry entry : entries) { 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 File file;
public Type type; public Type type;
public CallingConvention callingConvention; 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) { public FunctionEntry(Address address, String name, File file, Type type, CallingConvention callingConvention,
this(address, name, file, type, CallingConvention.Cdecl); String parameterNames, String parameterTypes, String returnType) {
}
public FunctionEntry(Address address, String name, File file, Type type, CallingConvention callingConvention) {
this.address = address; this.address = address;
this.name = name; this.name = name;
this.file = file; this.file = file;
this.type = type; this.type = type;
this.callingConvention = callingConvention; 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 { private void prepareCachedStatements() throws SQLException {
// Find by name // Find by name
findByNameFunctions = connection.prepareStatement( 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( 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 // Find by address
findByAddressFunctions = connection.prepareStatement( 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( 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 // Insert or replace
insertOrReplaceFunctions = connection.prepareStatement( 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( 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 // Delete by filepath
deleteByFilepathFunctions = connection.prepareStatement( deleteByFilepathFunctions = connection.prepareStatement(
@ -234,9 +268,9 @@ public class FunctionDatabase implements AutoCloseable {
// Load all entries // Load all entries
loadAllFunctions = connection.prepareStatement( 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( 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 // Global statements
findByNameGlobals = connection.prepareStatement( findByNameGlobals = connection.prepareStatement(
@ -314,6 +348,9 @@ public class FunctionDatabase implements AutoCloseable {
String addressStr = rs.getString("address"); String addressStr = rs.getString("address");
int typeValue = rs.getInt("type"); int typeValue = rs.getInt("type");
int callingConventionValue = rs.getInt("calling_convention"); 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()) { if (addressStr != null && !addressStr.isEmpty()) {
Address address = script.getCurrentProgram().getAddressFactory().getAddress(addressStr); Address address = script.getCurrentProgram().getAddressFactory().getAddress(addressStr);
@ -321,7 +358,8 @@ public class FunctionDatabase implements AutoCloseable {
Type type = Type.fromValue(typeValue); Type type = Type.fromValue(typeValue);
CallingConvention callingConvention = CallingConvention.fromValue(callingConventionValue); 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; return null;
} }
@ -334,6 +372,9 @@ public class FunctionDatabase implements AutoCloseable {
address TEXT, address TEXT,
type INTEGER DEFAULT 0, type INTEGER DEFAULT 0,
calling_convention INTEGER DEFAULT 0, calling_convention INTEGER DEFAULT 0,
parameter_names TEXT DEFAULT '',
parameter_types TEXT DEFAULT '',
return_type TEXT DEFAULT '',
PRIMARY KEY (name, filepath) PRIMARY KEY (name, filepath)
)"""; )""";
@ -344,6 +385,9 @@ public class FunctionDatabase implements AutoCloseable {
address TEXT, address TEXT,
type INTEGER DEFAULT 0, type INTEGER DEFAULT 0,
calling_convention INTEGER DEFAULT 0, calling_convention INTEGER DEFAULT 0,
parameter_names TEXT DEFAULT '',
parameter_types TEXT DEFAULT '',
return_type TEXT DEFAULT '',
PRIMARY KEY (name, filepath) PRIMARY KEY (name, filepath)
)"""; )""";
@ -444,16 +488,45 @@ public class FunctionDatabase implements AutoCloseable {
insertOrReplaceFunctions.setString(3, entry.address.toString()); insertOrReplaceFunctions.setString(3, entry.address.toString());
insertOrReplaceFunctions.setInt(4, entry.type.getValue()); insertOrReplaceFunctions.setInt(4, entry.type.getValue());
insertOrReplaceFunctions.setInt(5, entry.callingConvention.getValue()); insertOrReplaceFunctions.setInt(5, entry.callingConvention.getValue());
insertOrReplaceFunctions.setString(6, entry.parameterNames);
insertOrReplaceFunctions.setString(7, entry.parameterTypes);
insertOrReplaceFunctions.setString(8, entry.returnType);
insertOrReplaceFunctions.executeUpdate(); insertOrReplaceFunctions.executeUpdate();
script.println("Added/updated entry: " + entry.name + " at " + entry.address + " in " + relativePath 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) { } catch (SQLException e) {
script.println("Error adding entry: " + e.getMessage()); script.println("Error adding entry: " + e.getMessage());
throw new Exception("Failed to add entry", e); 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 // Helper method to remove entry by file path
public void removeEntryAt(String filePath) throws Exception { public void removeEntryAt(String filePath) throws Exception {
ensureConnection(); 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(); ensureConnection();
String filepath = RemanConfig.GLOBAL_H_FILE; // Default filepath for globals String filepath = RemanConfig.GLOBAL_H_FILE; // Default filepath for globals
@ -701,7 +774,7 @@ public class FunctionDatabase implements AutoCloseable {
insertOrReplaceGlobals.setString(3, addressStr); insertOrReplaceGlobals.setString(3, addressStr);
insertOrReplaceGlobals.executeUpdate(); insertOrReplaceGlobals.executeUpdate();
script.println("Added/updated global: " + name + " at " + address + " with type " + dataType); script.println("Added/updated global: " + name + " at " + address);
} catch (SQLException e) { } catch (SQLException e) {
script.println("Error adding global: " + e.getMessage()); script.println("Error adding global: " + e.getMessage());
throw new Exception("Failed to add global", e); throw new Exception("Failed to add global", e);

View File

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

View File

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