Upgrade function dumper for cc
This commit is contained in:
parent
ac92d40671
commit
f6d2ec6efb
|
@ -46,17 +46,76 @@ public class FunctionDatabase implements AutoCloseable {
|
|||
}
|
||||
}
|
||||
|
||||
public static enum CallingConvention {
|
||||
Cdecl(0),
|
||||
Stdcall(1),
|
||||
Fastcall(2);
|
||||
|
||||
private final int value;
|
||||
|
||||
CallingConvention(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public static CallingConvention fromValue(int value) {
|
||||
for (CallingConvention conv : CallingConvention.values()) {
|
||||
if (conv.value == value) {
|
||||
return conv;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Unknown calling convention value: " + value);
|
||||
}
|
||||
|
||||
public static CallingConvention fromString(String convStr) {
|
||||
if (convStr == null) {
|
||||
return Cdecl; // Default
|
||||
}
|
||||
|
||||
String lower = convStr.toLowerCase();
|
||||
if (lower.contains("fastcall")) {
|
||||
return Fastcall;
|
||||
} else if (lower.contains("stdcall")) {
|
||||
return Stdcall;
|
||||
} else {
|
||||
return Cdecl; // Default
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
switch (this) {
|
||||
case Fastcall:
|
||||
return "fastcall";
|
||||
case Stdcall:
|
||||
return "stdcall";
|
||||
case Cdecl:
|
||||
default:
|
||||
return "cdecl";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class FunctionEntry {
|
||||
public Address address;
|
||||
public String name;
|
||||
public File file;
|
||||
public Type type;
|
||||
public CallingConvention callingConvention;
|
||||
|
||||
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) {
|
||||
this.address = address;
|
||||
this.name = name;
|
||||
this.file = file;
|
||||
this.type = type;
|
||||
this.callingConvention = callingConvention;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,6 +143,7 @@ public class FunctionDatabase implements AutoCloseable {
|
|||
private PreparedStatement findByAddressFunctions;
|
||||
private PreparedStatement findByAddressImports;
|
||||
private PreparedStatement insertOrReplaceFunctions;
|
||||
private PreparedStatement insertOrReplaceImports;
|
||||
private PreparedStatement deleteByFilepathFunctions;
|
||||
private PreparedStatement deleteByFilepathImports;
|
||||
private PreparedStatement loadAllFunctions;
|
||||
|
@ -151,19 +211,21 @@ public class FunctionDatabase implements AutoCloseable {
|
|||
private void prepareCachedStatements() throws SQLException {
|
||||
// Find by name
|
||||
findByNameFunctions = connection.prepareStatement(
|
||||
"SELECT filepath, name, address, type FROM Functions WHERE name = ?");
|
||||
"SELECT filepath, name, address, type, calling_convention FROM Functions WHERE name = ?");
|
||||
findByNameImports = connection.prepareStatement(
|
||||
"SELECT filepath, name, address, type FROM Imports WHERE name = ?");
|
||||
"SELECT filepath, name, address, type, calling_convention FROM Imports WHERE name = ?");
|
||||
|
||||
// Find by address
|
||||
findByAddressFunctions = connection.prepareStatement(
|
||||
"SELECT filepath, name, address, type FROM Functions WHERE address = ?");
|
||||
"SELECT filepath, name, address, type, calling_convention FROM Functions WHERE address = ?");
|
||||
findByAddressImports = connection.prepareStatement(
|
||||
"SELECT filepath, name, address, type FROM Imports WHERE address = ?");
|
||||
"SELECT filepath, name, address, type, calling_convention FROM Imports WHERE address = ?");
|
||||
|
||||
// Insert or replace
|
||||
insertOrReplaceFunctions = connection.prepareStatement(
|
||||
"INSERT OR REPLACE INTO Functions (filepath, name, address, type) VALUES (?, ?, ?, ?)");
|
||||
"INSERT OR REPLACE INTO Functions (filepath, name, address, type, calling_convention) VALUES (?, ?, ?, ?, ?)");
|
||||
insertOrReplaceImports = connection.prepareStatement(
|
||||
"INSERT OR REPLACE INTO Imports (filepath, name, address, type, calling_convention) VALUES (?, ?, ?, ?, ?)");
|
||||
|
||||
// Delete by filepath
|
||||
deleteByFilepathFunctions = connection.prepareStatement(
|
||||
|
@ -173,9 +235,9 @@ public class FunctionDatabase implements AutoCloseable {
|
|||
|
||||
// Load all entries
|
||||
loadAllFunctions = connection.prepareStatement(
|
||||
"SELECT filepath, name, address, type FROM Functions");
|
||||
"SELECT filepath, name, address, type, calling_convention FROM Functions");
|
||||
loadAllImports = connection.prepareStatement(
|
||||
"SELECT filepath, name, address, type FROM Imports");
|
||||
"SELECT filepath, name, address, type, calling_convention FROM Imports");
|
||||
|
||||
// Global statements
|
||||
findByNameGlobals = connection.prepareStatement(
|
||||
|
@ -201,6 +263,8 @@ public class FunctionDatabase implements AutoCloseable {
|
|||
findByAddressImports.close();
|
||||
if (insertOrReplaceFunctions != null)
|
||||
insertOrReplaceFunctions.close();
|
||||
if (insertOrReplaceImports != null)
|
||||
insertOrReplaceImports.close();
|
||||
if (deleteByFilepathFunctions != null)
|
||||
deleteByFilepathFunctions.close();
|
||||
if (deleteByFilepathImports != null)
|
||||
|
@ -250,13 +314,15 @@ public class FunctionDatabase implements AutoCloseable {
|
|||
String name = rs.getString("name");
|
||||
String addressStr = rs.getString("address");
|
||||
int typeValue = rs.getInt("type");
|
||||
int callingConventionValue = rs.getInt("calling_convention");
|
||||
|
||||
if (addressStr != null && !addressStr.isEmpty()) {
|
||||
Address address = script.getCurrentProgram().getAddressFactory().getAddress(addressStr);
|
||||
File file = new File(RemanConfig.INSTANCE.outputDir, filepath);
|
||||
Type type = Type.fromValue(typeValue);
|
||||
CallingConvention callingConvention = CallingConvention.fromValue(callingConventionValue);
|
||||
|
||||
return new FunctionEntry(address, name, file, type);
|
||||
return new FunctionEntry(address, name, file, type, callingConvention);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -267,7 +333,8 @@ public class FunctionDatabase implements AutoCloseable {
|
|||
filepath TEXT,
|
||||
name TEXT,
|
||||
address TEXT,
|
||||
type INTEGER,
|
||||
type INTEGER DEFAULT 0,
|
||||
calling_convention INTEGER DEFAULT 0,
|
||||
PRIMARY KEY (name, filepath)
|
||||
)""";
|
||||
|
||||
|
@ -276,7 +343,8 @@ public class FunctionDatabase implements AutoCloseable {
|
|||
filepath TEXT,
|
||||
name TEXT,
|
||||
address TEXT,
|
||||
type INTEGER,
|
||||
type INTEGER DEFAULT 0,
|
||||
calling_convention INTEGER DEFAULT 0,
|
||||
PRIMARY KEY (name, filepath)
|
||||
)""";
|
||||
|
||||
|
@ -377,15 +445,40 @@ public class FunctionDatabase implements AutoCloseable {
|
|||
insertOrReplaceFunctions.setString(2, entry.name);
|
||||
insertOrReplaceFunctions.setString(3, entry.address.toString());
|
||||
insertOrReplaceFunctions.setInt(4, entry.type.getValue());
|
||||
insertOrReplaceFunctions.setInt(5, entry.callingConvention.getValue());
|
||||
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 + ")");
|
||||
} 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.executeUpdate();
|
||||
|
||||
script.println("Added/updated import entry: " + entry.name + " at " + entry.address + " in " + relativePath
|
||||
+ " (calling convention: " + entry.callingConvention + ")");
|
||||
} 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();
|
||||
|
|
|
@ -131,6 +131,11 @@ public class FunctionDumper {
|
|||
File f4 = new File(RemanConfig.INSTANCE.dirDecompStub, fileName);
|
||||
script.println("Generating function stub for " + externalFunction.getName() + " => " + f4.toString());
|
||||
|
||||
// Extract calling convention from Ghidra function
|
||||
String callingConventionName = externalFunction.getCallingConventionName();
|
||||
FunctionDatabase.CallingConvention callingConvention = FunctionDatabase.CallingConvention.fromString(callingConventionName);
|
||||
script.println("Detected calling convention: " + callingConventionName + " -> " + callingConvention);
|
||||
|
||||
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");
|
||||
|
@ -141,14 +146,13 @@ public class FunctionDumper {
|
|||
writer2.println("#include <gh_global.h>");
|
||||
writer2.println();
|
||||
writer2.println("// " + externalFunction.getEntryPoint());
|
||||
writer2.println("// " + externalFunction.getName());
|
||||
writer2.println("// " + externalFunction.getName() + "(" + callingConvention + ")");
|
||||
|
||||
// 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 callingConvention = externalFunction.getCallingConventionName();
|
||||
String returnType = externalFunction.getReturnType().toString();
|
||||
|
||||
// Generate function stub using appropriate forwarding function
|
||||
|
@ -156,8 +160,10 @@ public class FunctionDumper {
|
|||
|
||||
// Determine which stub function to use based on calling convention
|
||||
String stubFunction;
|
||||
if (callingConvention != null && callingConvention.equals("__stdcall")) {
|
||||
if (callingConvention == FunctionDatabase.CallingConvention.Stdcall) {
|
||||
stubFunction = "gh_stub_impl_stdcall";
|
||||
} else if (callingConvention == FunctionDatabase.CallingConvention.Fastcall) {
|
||||
stubFunction = "gh_stub_impl_fastcall";
|
||||
} else {
|
||||
// Default to cdecl for most cases
|
||||
stubFunction = "gh_stub_impl_cdecl";
|
||||
|
@ -189,9 +195,9 @@ public class FunctionDumper {
|
|||
createdFile = true;
|
||||
}
|
||||
|
||||
// Add stub function to database
|
||||
// Add stub function to database with calling convention
|
||||
FunctionDatabase.FunctionEntry newEntry = new FunctionDatabase.FunctionEntry(externalFunction.getEntryPoint(),
|
||||
externalFunction.getName(), f4, FunctionDatabase.Type.Stub);
|
||||
externalFunction.getName(), f4, FunctionDatabase.Type.Stub, callingConvention);
|
||||
functionDatabase.addEntryAt(newEntry);
|
||||
}
|
||||
|
||||
|
@ -204,6 +210,11 @@ public class FunctionDumper {
|
|||
List<FunctionDatabase.FunctionEntry> entries = functionDatabase.findEntriesByAddress(entrypoint);
|
||||
FunctionDatabase.Type targetType = FunctionDatabase.Type.Auto;
|
||||
|
||||
// Extract calling convention from Ghidra function
|
||||
String callingConventionName = function.getCallingConventionName();
|
||||
FunctionDatabase.CallingConvention callingConvention = FunctionDatabase.CallingConvention.fromString(callingConventionName);
|
||||
script.println("Detected calling convention: " + callingConventionName + " -> " + callingConvention);
|
||||
|
||||
// Handle forceFixType flag
|
||||
if (forceFixType) {
|
||||
targetType = FunctionDatabase.Type.Fix;
|
||||
|
@ -271,9 +282,9 @@ public class FunctionDumper {
|
|||
File f0 = targetFilename;
|
||||
script.println("Processing " + function.getName() + " => " + f0.toString());
|
||||
|
||||
// Update database
|
||||
// Update database with calling convention
|
||||
FunctionDatabase.FunctionEntry newEntry = new FunctionDatabase.FunctionEntry(entrypoint, function.getName(), f0,
|
||||
targetType);
|
||||
targetType, callingConvention);
|
||||
functionDatabase.addEntryAt(newEntry);
|
||||
|
||||
List<Function> externalFunctionCalls = new ArrayList<>();
|
||||
|
@ -305,8 +316,8 @@ public class FunctionDumper {
|
|||
// Parse preliminary line tokens
|
||||
for (int i = 0; i < line.getNumTokens(); i++) {
|
||||
ClangToken token = line.getToken(i);
|
||||
if (token.getText().equals("__cdecl") || token.getText().equals("__thiscall")
|
||||
|| token.getText().equals("__stdcall")) {
|
||||
// Remove some of the calling conventions, keep __stdcall/fastcall
|
||||
if (token.getText().equals("__cdecl") || token.getText().equals("__thiscall")) {
|
||||
// Remove function declaration
|
||||
continue;
|
||||
}
|
||||
|
@ -410,9 +421,13 @@ public class FunctionDumper {
|
|||
String proto = externalFunction.getSignature().getPrototypeString(false);
|
||||
String name = externalFunction.getName();
|
||||
proto = proto.replace(name, Utils.sanitizeIdentifier(name));
|
||||
|
||||
// Add calling convention information to the comment
|
||||
String callingConv = externalFunction.getCallingConventionName();
|
||||
FunctionDatabase.CallingConvention conv = FunctionDatabase.CallingConvention.fromString(callingConv);
|
||||
headers.add("" + proto
|
||||
+ "; // " + externalFunction.getEntryPoint() + " // "
|
||||
+ name);
|
||||
+ name + " // " + conv);
|
||||
}
|
||||
|
||||
for (String header : headers) {
|
||||
|
|
Loading…
Reference in New Issue