Update readme and rename config java

This commit is contained in:
Guus Waals 2025-05-29 16:31:55 +08:00
parent d7de3deb59
commit 647e3668a0
28 changed files with 562 additions and 13162 deletions

View File

@ -1,7 +1,6 @@
function(setup_target TARGET) function(setup_target TARGET DBG_MODE)
add_executable(${TARGET} add_executable(${TARGET}
r3/main.cpp r3/main.cxx
r3/binders/static_mem.cxx
gh_global.cxx gh_global.cxx
) )
@ -63,9 +62,18 @@ function(setup_target TARGET)
target_precompile_headers(${TARGET} PRIVATE target_precompile_headers(${TARGET} PRIVATE
"$<$<COMPILE_LANGUAGE:CXX>:${CMAKE_CURRENT_SOURCE_DIR}/r3/binders/auto_pch.cxx>" "$<$<COMPILE_LANGUAGE:CXX>:${CMAKE_CURRENT_SOURCE_DIR}/r3/binders/auto_pch.cxx>"
) )
if(DBG_MODE)
target_sources(${TARGET} PRIVATE
r3/binders/dbg_mem.cxx
)
target_compile_definitions(game_dbg PRIVATE RE_DBG_INJECTED=1)
else()
target_sources(${TARGET} PRIVATE
r3/binders/static_mem.cxx
)
endif()
endfunction() endfunction()
setup_target(game_re) setup_target(game_re OFF)
setup_target(game_dbg ON)
setup_target(game_dbg)
target_compile_definitions(game_dbg PRIVATE RE_DBG_INJECTED=1)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,12 @@
#ifndef B8D59B54_1674_4C0F_AA2C_611385FF5D03 #ifndef B8D59B54_1674_4C0F_AA2C_611385FF5D03
#define B8D59B54_1674_4C0F_AA2C_611385FF5D03 #define B8D59B54_1674_4C0F_AA2C_611385FF5D03
#if RE_DBG_INJECTED
#include "dbg_mem.h"
#else
#include "static_mem.h" #include "static_mem.h"
#endif
#include "base.h" #include "base.h"
#include <gh_types.h> #include <gh_types.h>
@ -108,6 +113,6 @@ inline longlong r3_ftol(float a) { return (longlong)a; }
constexpr byte R3ModId_not_initialized = 0xff; constexpr byte R3ModId_not_initialized = 0xff;
#include "stubexcept.h" #include "stub.h"
#endif /* B8D59B54_1674_4C0F_AA2C_611385FF5D03 */ #endif /* B8D59B54_1674_4C0F_AA2C_611385FF5D03 */

View File

@ -0,0 +1,4 @@
#include "r3/config/static.hpp"
void gh_init_dbg_loader() {
}

View File

@ -0,0 +1,15 @@
#ifndef BD364AE6_AD96_4DEA_9D6B_B237BC1E2C6A
#define BD364AE6_AD96_4DEA_9D6B_B237BC1E2C6A
#include <gh_datasegment.h>
template <size_t addr> inline constexpr void checkMappedMemory() {
static_assert(addr >= GH_DATA_START, "Address outside lower bound");
static_assert(addr < GH_DATA_END, "Address outside upper bound");
}
void gh_init_dbg_loader();
#define GH_MEM(addr) (checkMappedMemory<addr>(), *memoryMapSafe(addr))
#endif /* BD364AE6_AD96_4DEA_9D6B_B237BC1E2C6A */

View File

@ -4,7 +4,11 @@
#define EDBE48FC_B879_4985_9274_B7ACF24AD024 #define EDBE48FC_B879_4985_9274_B7ACF24AD024
#include "base.h" #include "base.h"
#if RE_DBG_INJECTED
#include "dbg_mem.h"
#else
#include "static_mem.h" #include "static_mem.h"
#endif
#include <gh_types.h> #include <gh_types.h>
#endif /* EDBE48FC_B879_4985_9274_B7ACF24AD024 */ #endif /* EDBE48FC_B879_4985_9274_B7ACF24AD024 */

View File

@ -0,0 +1,5 @@
#include <spdlog/spdlog.h>
GHStubException::GHStubException(const char *msg) : std::exception(msg) {
SPDLOG_ERROR("{}", msg);
}

34
game_re/r3/binders/stub.h Normal file
View File

@ -0,0 +1,34 @@
#ifndef AE625BF8_B0F9_452E_8772_8819F311CB57
#define AE625BF8_B0F9_452E_8772_8819F311CB57
#include <stdexcept>
struct GHStubException : public std::exception {
GHStubException(const char *msg);
};
void *gh_stub_impl_ptr(void *ptr);
template <typename T, typename... Args>
T gh_stub_impl_cdecl(void *ptr, Args... args) {
#if RE_DBG_INJECTED
using Callable = __cdecl T (*)(Args...);
static Callable *ptr = (Callable *)gh_stub_impl_ptr(ptr);
return ptr(args...);
#else
throw GHStubException("Function not implemented");
#endif
}
template <typename T, typename... Args>
T gh_stub_impl_stdcall(void *ptr, Args... args) {
#if RE_DBG_INJECTED
using Callable = __stdcall T (*)(Args...);
static Callable *ptr = (Callable *)gh_stub_impl_ptr(ptr);
return ptr(args...);
#else
throw GHStubException("Function not implemented");
#endif
}
#endif /* AE625BF8_B0F9_452E_8772_8819F311CB57 */

View File

@ -1,10 +0,0 @@
#ifndef AE625BF8_B0F9_452E_8772_8819F311CB57
#define AE625BF8_B0F9_452E_8772_8819F311CB57
#include <stdexcept>
struct GHStubException : public std::exception {
GHStubException(const char *msg);
};
#endif /* AE625BF8_B0F9_452E_8772_8819F311CB57 */

View File

@ -2,22 +2,27 @@
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include <stdexcept> #include <stdexcept>
#include <stdio.h> #include <stdio.h>
#include <r3/binders/stub.h>
#if RE_DBG_INJECTED
#include <r3/binders/dbg_mem.h>
#else
#include <r3/binders/static_mem.h> #include <r3/binders/static_mem.h>
#include <r3/binders/stubexcept.h> #endif
// Error reporting and such // Error reporting and such
extern "C" void r3_noop(void*, void*) {} extern "C" void r3_noop(void *, void *) {}
extern "C" int r3_main(HINSTANCE hInstance, HINSTANCE hPrevInstance, extern "C" int r3_main(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR *cmdline, int showCmd); LPSTR *cmdline, int showCmd);
GHStubException::GHStubException(const char *msg) : std::exception(msg) {
SPDLOG_ERROR("{}", msg);
}
int main(int argc, char **argv) { int main(int argc, char **argv) {
try { try {
#if RE_DBG_INJECTED
gh_init_dbg_loader();
#else
gh_init_data_segment(); gh_init_data_segment();
#endif
r3_main(GetModuleHandle(NULL), NULL, argv, SW_SHOW); r3_main(GetModuleHandle(NULL), NULL, argv, SW_SHOW);
} catch (const std::exception &e) { } catch (const std::exception &e) {

View File

@ -150,16 +150,16 @@ public class Decompile extends GhidraScript {
return; return;
} }
RecompileConfig.INSTANCE = new RecompileConfig(this); RemanConfig.INSTANCE = new RemanConfig(this);
if (!new File(RecompileConfig.INSTANCE.outputDir).exists()) { if (!new File(RemanConfig.INSTANCE.outputDir).exists()) {
throw new Exception("Output directory does not exist: " + RecompileConfig.INSTANCE.outputDir); throw new Exception("Output directory does not exist: " + RemanConfig.INSTANCE.outputDir);
} }
// Make sure to create output folders // Make sure to create output folders
RecompileConfig.INSTANCE.dirDecompFix.mkdirs(); RemanConfig.INSTANCE.dirDecompFix.mkdirs();
RecompileConfig.INSTANCE.dirDecompAuto.mkdirs(); RemanConfig.INSTANCE.dirDecompAuto.mkdirs();
RecompileConfig.INSTANCE.dirDecompRef.mkdirs(); RemanConfig.INSTANCE.dirDecompRef.mkdirs();
// buildFunctionBlacklist(); // buildFunctionBlacklist();

View File

@ -6,13 +6,13 @@ import ghidra.app.script.GhidraScript;
import ghidra.program.model.listing.Function; import ghidra.program.model.listing.Function;
import re3lib.FunctionDumper; import re3lib.FunctionDumper;
import re3lib.GlobalDumper; import re3lib.GlobalDumper;
import re3lib.RecompileConfig; import re3lib.RemanConfig;
public class DumpCurrentFunction extends GhidraScript { public class DumpCurrentFunction extends GhidraScript {
@Override @Override
public void run() throws Exception { public void run() throws Exception {
RecompileConfig.INSTANCE = new RecompileConfig(this); RemanConfig.INSTANCE = new RemanConfig(this);
RecompileConfig.INSTANCE.createDirectories(); RemanConfig.INSTANCE.createDirectories();
GlobalDumper globalDumper = new GlobalDumper(this); GlobalDumper globalDumper = new GlobalDumper(this);
globalDumper.loadGlobalManifest(); globalDumper.loadGlobalManifest();
@ -26,7 +26,7 @@ public class DumpCurrentFunction extends GhidraScript {
} }
if (functionDumper.createdFile) if (functionDumper.createdFile)
RecompileConfig.INSTANCE.touchCMakeTimestamp(); RemanConfig.INSTANCE.touchCMakeTimestamp();
globalDumper.dumpGlobals(); globalDumper.dumpGlobals();
globalDumper.saveGlobalManifest(); globalDumper.saveGlobalManifest();

View File

@ -12,7 +12,7 @@ import ghidra.program.model.listing.Function;
import re3lib.FunctionDumper; import re3lib.FunctionDumper;
import re3lib.GlobalDumper; import re3lib.GlobalDumper;
import re3lib.PCallTracer; import re3lib.PCallTracer;
import re3lib.RecompileConfig; import re3lib.RemanConfig;
import re3lib.TypeDumper; import re3lib.TypeDumper;
public class DumpCurrentFunctionN extends GhidraScript { public class DumpCurrentFunctionN extends GhidraScript {
@ -43,8 +43,8 @@ public class DumpCurrentFunctionN extends GhidraScript {
@Override @Override
public void run() throws Exception { public void run() throws Exception {
RecompileConfig.INSTANCE = new RecompileConfig(this); RemanConfig.INSTANCE = new RemanConfig(this);
RecompileConfig.INSTANCE.createDirectories(); RemanConfig.INSTANCE.createDirectories();
GlobalDumper globalDumper = new GlobalDumper(this); GlobalDumper globalDumper = new GlobalDumper(this);
globalDumper.loadGlobalManifest(); globalDumper.loadGlobalManifest();

View File

@ -10,14 +10,14 @@ import ghidra.program.model.listing.Function;
import re3lib.FunctionDumper; import re3lib.FunctionDumper;
import re3lib.GlobalDumper; import re3lib.GlobalDumper;
import re3lib.PCallTracer; import re3lib.PCallTracer;
import re3lib.RecompileConfig; import re3lib.RemanConfig;
import re3lib.TypeDumper; import re3lib.TypeDumper;
public class DumpCurrentFunctionRecursive extends GhidraScript { public class DumpCurrentFunctionRecursive extends GhidraScript {
@Override @Override
public void run() throws Exception { public void run() throws Exception {
RecompileConfig.INSTANCE = new RecompileConfig(this); RemanConfig.INSTANCE = new RemanConfig(this);
RecompileConfig.INSTANCE.createDirectories(); RemanConfig.INSTANCE.createDirectories();
GlobalDumper globalDumper = new GlobalDumper(this); GlobalDumper globalDumper = new GlobalDumper(this);
globalDumper.loadGlobalManifest(); globalDumper.loadGlobalManifest();
@ -65,7 +65,7 @@ public class DumpCurrentFunctionRecursive extends GhidraScript {
} }
if (functionDumper.createdFile) if (functionDumper.createdFile)
RecompileConfig.INSTANCE.touchCMakeTimestamp(); RemanConfig.INSTANCE.touchCMakeTimestamp();
globalDumper.dumpGlobals(); globalDumper.dumpGlobals();
globalDumper.saveGlobalManifest(); globalDumper.saveGlobalManifest();

View File

@ -7,7 +7,7 @@ import java.io.FileOutputStream;
import java.io.PrintWriter; import java.io.PrintWriter;
import ghidra.app.script.GhidraScript; import ghidra.app.script.GhidraScript;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import re3lib.RecompileConfig; import re3lib.RemanConfig;
public class ExportData extends GhidraScript { public class ExportData extends GhidraScript {
@ -16,16 +16,16 @@ public class ExportData extends GhidraScript {
if (currentProgram == null) { if (currentProgram == null) {
return; return;
} }
RecompileConfig.INSTANCE = new RecompileConfig(this); RemanConfig.INSTANCE = new RemanConfig(this);
String dataFile = new File(RecompileConfig.INSTANCE.outputDir, "gh_datasegment.bin").toString(); String dataFile = new File(RemanConfig.INSTANCE.outputDir, "gh_datasegment.bin").toString();
String headerFile = new File(RecompileConfig.INSTANCE.outputDir, "gh_datasegment.h").toString(); String headerFile = new File(RemanConfig.INSTANCE.outputDir, "gh_datasegment.h").toString();
FileOutputStream dataOutputStream = new FileOutputStream(dataFile); FileOutputStream dataOutputStream = new FileOutputStream(dataFile);
PrintWriter headerWriter = new PrintWriter(headerFile, "UTF-8"); PrintWriter headerWriter = new PrintWriter(headerFile, "UTF-8");
Address startAddr = RecompileConfig.INSTANCE.staticMemoryBlockStart; Address startAddr = RemanConfig.INSTANCE.staticMemoryBlockStart;
Address endAddr = RecompileConfig.INSTANCE.staticMemoryBlockEnd; Address endAddr = RemanConfig.INSTANCE.staticMemoryBlockEnd;
// Dump all the memory to the bin file // Dump all the memory to the bin file
int numBytes = (int) endAddr.subtract(startAddr); int numBytes = (int) endAddr.subtract(startAddr);

View File

@ -4,13 +4,13 @@
import ghidra.app.script.GhidraScript; import ghidra.app.script.GhidraScript;
import re3lib.GlobalDumper; import re3lib.GlobalDumper;
import re3lib.RecompileConfig; import re3lib.RemanConfig;
public class SanitizeGlobalSymbols extends GhidraScript { public class SanitizeGlobalSymbols extends GhidraScript {
@Override @Override
public void run() throws Exception { public void run() throws Exception {
RecompileConfig.INSTANCE = new RecompileConfig(this); RemanConfig.INSTANCE = new RemanConfig(this);
RecompileConfig.INSTANCE.createDirectories(); RemanConfig.INSTANCE.createDirectories();
GlobalDumper globalDumper = new GlobalDumper(this); GlobalDumper globalDumper = new GlobalDumper(this);
globalDumper.loadGlobalManifest(); globalDumper.loadGlobalManifest();

View File

@ -2,83 +2,22 @@
// @menupath Reman3.Test // @menupath Reman3.Test
// @importpackage org.sqlite // @importpackage org.sqlite
import ghidra.app.script.GhidraScript;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.StandAloneDataTypeManager;
import re3lib.RecompileConfig;
import java.io.File;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
// SQLite imports import ghidra.app.script.GhidraScript;
import java.sql.Connection; import re3lib.FunctionDatabase;
import java.sql.DriverManager; import re3lib.RemanConfig;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.sqlite.JDBC;
public class Test extends GhidraScript { public class Test extends GhidraScript {
@Override @Override
public void run() throws Exception { public void run() throws Exception {
RecompileConfig.INSTANCE = new RecompileConfig(this); RemanConfig.INSTANCE = new RemanConfig(this);
java.sql.DriverManager.registerDriver(new JDBC());
// Example SQLite usage // Example SQLite usage
testSQLite(); FunctionDatabase db = new FunctionDatabase(this);
} List<FunctionDatabase.Entry> entries = db.loadAllEntries();
for (FunctionDatabase.Entry entry : entries) {
private void testSQLite() throws Exception { println("entry.name: " + entry.name + " entry.address: " + entry.address + " entry.type: " + entry.type);
String dbPath = "jdbc:sqlite:" + RecompileConfig.INSTANCE.outputDir + "/functions.db";
try (Connection conn = DriverManager.getConnection(dbPath)) {
println("Connected to SQLite database: " + dbPath);
// Create a simple table
try (Statement stmt = conn.createStatement()) {
stmt.execute("CREATE TABLE IF NOT EXISTS functions (" +
"id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"address TEXT NOT NULL, " +
"name TEXT NOT NULL, " +
"file_path TEXT)");
println("Functions table created/verified");
}
// Insert example data
String insertSQL = "INSERT INTO functions (address, name, file_path) VALUES (?, ?, ?)";
try (PreparedStatement pstmt = conn.prepareStatement(insertSQL)) {
pstmt.setString(1, "0x00401000");
pstmt.setString(2, "main");
pstmt.setString(3, "/path/to/main.cxx");
pstmt.executeUpdate();
println("Inserted example function");
}
// Query data
try (Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM functions")) {
while (rs.next()) {
println("Function: " + rs.getString("name") +
" at " + rs.getString("address") +
" in " + rs.getString("file_path"));
}
}
} catch (SQLException e) {
println("SQLite error: " + e.getMessage());
throw e;
} }
} }
} }

View File

@ -1,6 +1,11 @@
package re3lib; package re3lib;
import java.io.File; import java.io.File;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
@ -8,106 +13,349 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.sqlite.JDBC;
import ghidra.app.script.GhidraScript; import ghidra.app.script.GhidraScript;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Function; import ghidra.program.model.listing.Function;
public class FunctionDatabase { public class FunctionDatabase {
public enum Type { public enum Type {
Auto, Auto(0),
Fix, Fix(1),
Stub, Stub(2),
Ref Ref(3);
}
public class Dependency implements java.io.Serializable { private final int value;
private static final long serialVersionUID = 1L;
public Address address;
public String name;
public Dependency(Address address, String name) { Type(int value) {
this.address = address; this.value = value;
this.name = name;
} }
private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { public int getValue() {
out.writeObject(address != null ? address.toString() : null); return value;
out.writeObject(name);
} }
private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException { public static Type fromValue(int value) {
String addressString = (String) in.readObject(); for (Type type : Type.values()) {
if (addressString != null) { if (type.value == value) {
address = RecompileConfig.INSTANCE.script.getCurrentProgram().getAddressFactory().getAddress(addressString); return type;
}
} }
name = (String) in.readObject(); throw new IllegalArgumentException("Unknown type value: " + value);
} }
} }
public class Entry implements java.io.Serializable { public class Entry {
private static final long serialVersionUID = 1L;
public Address address; public Address address;
public String name; public String name;
public File file; public File file;
public Type type; public Type type;
public List<Dependency> dependencies = new ArrayList<>();
private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { public Entry(Address address, String name, File file, Type type) {
out.writeObject(address != null ? address.toString() : null); this.address = address;
out.writeObject(name); this.name = name;
out.writeObject(file != null ? file.toString() : null); this.file = file;
out.writeObject(type); this.type = type;
out.writeObject(dependencies);
}
private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException {
String addressString = (String) in.readObject();
if (addressString != null) {
address = RecompileConfig.INSTANCE.script.getCurrentProgram().getAddressFactory().getAddress(addressString);
}
name = (String) in.readObject();
String fileString = (String) in.readObject();
if (fileString != null) {
file = new File(fileString);
}
type = (Type) in.readObject();
dependencies = (List<Dependency>) in.readObject();
} }
} }
public List<Entry> entries = new ArrayList<>(); private File dbFile;
private File file;
private transient GhidraScript script; private transient GhidraScript script;
private Connection connection;
// Prepared statements for better performance
private PreparedStatement findByNameFunctions;
private PreparedStatement findByNameImports;
private PreparedStatement findByAddressFunctions;
private PreparedStatement findByAddressImports;
private PreparedStatement insertOrReplaceFunctions;
private PreparedStatement deleteByFilepathFunctions;
private PreparedStatement deleteByFilepathImports;
private PreparedStatement loadAllFunctions;
private PreparedStatement loadAllImports;
public FunctionDatabase(GhidraScript script) { public FunctionDatabase(GhidraScript script) {
this.script = script; this.script = script;
file = new File(RecompileConfig.INSTANCE.outputDir, "functions.dat"); dbFile = RemanConfig.INSTANCE.databasePath;
} try {
java.sql.DriverManager.registerDriver(new JDBC());
public void load() throws Exception { } catch (SQLException e) {
if (!file.exists()) { script.printerr("Error registering JDBC driver: " + e.getMessage());
return;
}
try (java.io.ObjectInputStream ois = new java.io.ObjectInputStream(new java.io.FileInputStream(file))) {
entries = (List<Entry>) ois.readObject();
script.println("Loaded " + entries.size() + " function entries from " + file);
} catch (java.io.IOException | ClassNotFoundException e) {
script.println("Error loading function database: " + e.getMessage());
} }
} }
public void save() throws Exception { public void connect() throws Exception {
try (java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(new java.io.FileOutputStream(file))) { if (connection != null && !connection.isClosed()) {
oos.writeObject(entries); return; // Already connected
script.println("Saved " + entries.size() + " function entries to " + file); }
} catch (java.io.IOException e) {
script.println("Error saving function database: " + e.getMessage()); if (!dbFile.exists()) {
script.println("Database file not found: " + dbFile);
// Create parent directories if they don't exist
dbFile.getParentFile().mkdirs();
}
try {
connection = DriverManager.getConnection("jdbc:sqlite:" + dbFile.getAbsolutePath());
createTablesIfNotExist();
prepareCachedStatements();
script.println("Connected to database: " + dbFile);
} catch (SQLException e) {
script.println("Error connecting to database: " + e.getMessage());
throw new Exception("Failed to connect to database", e);
} }
} }
public void add(Entry entry) { public void disconnect() throws Exception {
entries.add(entry); if (connection != null && !connection.isClosed()) {
try {
// Close prepared statements
closePreparedStatements();
connection.close();
script.println("Disconnected from database");
} catch (SQLException e) {
script.println("Error disconnecting from database: " + e.getMessage());
throw new Exception("Failed to disconnect from database", e);
}
}
}
private void ensureConnection() throws Exception {
if (connection == null || connection.isClosed()) {
connect();
}
}
private void prepareCachedStatements() throws SQLException {
// Find by name
findByNameFunctions = connection.prepareStatement(
"SELECT filepath, name, address, type FROM Functions WHERE name = ?");
findByNameImports = connection.prepareStatement(
"SELECT filepath, name, address, type FROM Imports WHERE name = ?");
// Find by address
findByAddressFunctions = connection.prepareStatement(
"SELECT filepath, name, address, type FROM Functions WHERE address = ?");
findByAddressImports = connection.prepareStatement(
"SELECT filepath, name, address, type FROM Imports WHERE address = ?");
// Insert or replace
insertOrReplaceFunctions = connection.prepareStatement(
"INSERT OR REPLACE INTO Functions (filepath, name, address, type) VALUES (?, ?, ?, ?)");
// Delete by filepath
deleteByFilepathFunctions = connection.prepareStatement(
"DELETE FROM Functions WHERE filepath = ?");
deleteByFilepathImports = connection.prepareStatement(
"DELETE FROM Imports WHERE filepath = ?");
// Load all entries
loadAllFunctions = connection.prepareStatement(
"SELECT filepath, name, address, type FROM Functions");
loadAllImports = connection.prepareStatement(
"SELECT filepath, name, address, type FROM Imports");
}
private void closePreparedStatements() throws SQLException {
if (findByNameFunctions != null)
findByNameFunctions.close();
if (findByNameImports != null)
findByNameImports.close();
if (findByAddressFunctions != null)
findByAddressFunctions.close();
if (findByAddressImports != null)
findByAddressImports.close();
if (insertOrReplaceFunctions != null)
insertOrReplaceFunctions.close();
if (deleteByFilepathFunctions != null)
deleteByFilepathFunctions.close();
if (deleteByFilepathImports != null)
deleteByFilepathImports.close();
if (loadAllFunctions != null)
loadAllFunctions.close();
if (loadAllImports != null)
loadAllImports.close();
}
public List<Entry> loadAllEntries() throws Exception {
ensureConnection();
List<Entry> entries = new ArrayList<>();
try {
// Load from Functions table
try (ResultSet rs = loadAllFunctions.executeQuery()) {
while (rs.next()) {
Entry entry = createEntryFromResultSet(rs);
if (entry != null) {
entries.add(entry);
}
}
}
script.println("Loaded " + entries.size() + " function entries from database");
return entries;
} catch (SQLException e) {
script.println("Error loading entries: " + e.getMessage());
throw new Exception("Failed to load entries", e);
}
}
private Entry createEntryFromResultSet(ResultSet rs) throws SQLException {
String filepath = rs.getString("filepath");
String name = rs.getString("name");
String addressStr = rs.getString("address");
int typeValue = rs.getInt("type");
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);
return new Entry(address, name, file, type);
}
return null;
}
private void createTablesIfNotExist() throws SQLException {
String createFunctions = """
CREATE TABLE IF NOT EXISTS Functions (
filepath TEXT,
name TEXT,
address TEXT,
type INTEGER,
PRIMARY KEY (name, filepath)
)""";
String createImports = """
CREATE TABLE IF NOT EXISTS Imports (
filepath TEXT,
name TEXT,
address TEXT,
type INTEGER,
PRIMARY KEY (name, filepath)
)""";
connection.prepareStatement(createFunctions).executeUpdate();
connection.prepareStatement(createImports).executeUpdate();
}
// Helper method to find entries by name
public List<Entry> findEntriesByName(String name) throws Exception {
ensureConnection();
List<Entry> results = new ArrayList<>();
try {
// Search Functions table
findByNameFunctions.setString(1, name);
try (ResultSet rs = findByNameFunctions.executeQuery()) {
while (rs.next()) {
Entry entry = createEntryFromResultSet(rs);
if (entry != null) {
results.add(entry);
}
}
}
// Search Imports table
findByNameImports.setString(1, name);
try (ResultSet rs = findByNameImports.executeQuery()) {
while (rs.next()) {
Entry entry = createEntryFromResultSet(rs);
if (entry != null) {
results.add(entry);
}
}
}
return results;
} catch (SQLException e) {
script.println("Error finding entries by name: " + e.getMessage());
throw new Exception("Failed to find entries by name", e);
}
}
// Helper method to find entries by address
public List<Entry> findEntriesByAddress(Address address) throws Exception {
ensureConnection();
List<Entry> results = new ArrayList<>();
String addressStr = address.toString();
try {
// Search Functions table
findByAddressFunctions.setString(1, addressStr);
try (ResultSet rs = findByAddressFunctions.executeQuery()) {
while (rs.next()) {
Entry entry = createEntryFromResultSet(rs);
if (entry != null) {
results.add(entry);
}
}
}
// Search Imports table
findByAddressImports.setString(1, addressStr);
try (ResultSet rs = findByAddressImports.executeQuery()) {
while (rs.next()) {
Entry entry = createEntryFromResultSet(rs);
if (entry != null) {
results.add(entry);
}
}
}
return results;
} catch (SQLException e) {
script.println("Error finding entries by address: " + e.getMessage());
throw new Exception("Failed to find entries by address", e);
}
}
// Helper method to add/update entry (insert or replace based on filename)
public void addEntryAt(Entry entry) throws Exception {
ensureConnection();
String relativePath = new File(RemanConfig.INSTANCE.outputDir).toPath()
.relativize(entry.file.toPath()).toString().replace('\\', '/');
try {
insertOrReplaceFunctions.setString(1, relativePath);
insertOrReplaceFunctions.setString(2, entry.name);
insertOrReplaceFunctions.setString(3, entry.address.toString());
insertOrReplaceFunctions.setInt(4, entry.type.getValue());
insertOrReplaceFunctions.executeUpdate();
script.println("Added/updated entry: " + entry.name + " at " + entry.address + " in " + relativePath);
} catch (SQLException e) {
script.println("Error adding entry: " + e.getMessage());
throw new Exception("Failed to add entry", e);
}
}
// Helper method to remove entry by file path
public void removeEntryAt(String filePath) throws Exception {
ensureConnection();
String relativePath = new File(RemanConfig.INSTANCE.outputDir).toPath()
.relativize(new File(filePath).toPath()).toString().replace('\\', '/');
try {
deleteByFilepathFunctions.setString(1, relativePath);
int deletedCount = deleteByFilepathFunctions.executeUpdate();
deleteByFilepathImports.setString(1, relativePath);
deletedCount += deleteByFilepathImports.executeUpdate();
script.println("Removed " + deletedCount + " entries for file: " + relativePath);
} catch (SQLException e) {
script.println("Error removing entries: " + e.getMessage());
throw new Exception("Failed to remove entries", e);
}
}
public void add(Entry entry) throws Exception {
// Add entry directly to database
addEntryAt(entry);
} }
public void applyDefaultFilters(boolean rebuildAllGlobals) throws Exception { public void applyDefaultFilters(boolean rebuildAllGlobals) throws Exception {
@ -120,13 +368,15 @@ public class FunctionDatabase {
boolean madeAnyChanges = false; boolean madeAnyChanges = false;
// Load all entries from database
List<Entry> entries = loadAllEntries();
// Create a hash map to store symbol names // Create a hash map to store symbol names
Map<Address, String> symbolNames = new HashMap<>(); Map<Address, String> symbolNames = new HashMap<>();
Map<String, File> exportedFunctionNames = new HashMap<>(); Map<String, File> exportedFunctionNames = new HashMap<>();
for (Entry entry : entries) { for (Entry entry : entries) {
Function function = script.getFunctionAt(entry.address); Function function = script.getFunctionAt(entry.address);
if (function != null) { if (function != null) {
String dirComponent = entry.file.getParent().toString();
boolean isAuto = entry.type == Type.Auto; boolean isAuto = entry.type == Type.Auto;
boolean isFix = entry.type == Type.Fix; boolean isFix = entry.type == Type.Fix;
// Get the actual symbol name and store it in the hash map // Get the actual symbol name and store it in the hash map
@ -197,21 +447,6 @@ public class FunctionDatabase {
} }
} }
// Check if dependencies are valid
for (Dependency dependency : entry.dependencies) {
Function depFunction = script.getFunctionAt(dependency.address);
if (depFunction == null) {
script.println(
"Dependency not found: " + dependency.name + " at " + dependency.address + " in " + entry.file);
pendingRegenerate = true;
} else if (!dumper.isValidFunction(depFunction) || !depFunction.getName().equals(dependency.name)) {
script
.println("Invalid dependency: " + dependency.name + " at " + dependency.address + " in " + entry.file
+ " should be " + dependency.name);
pendingRegenerate = true;
}
}
entry.name = actualSymbolName; // Update the entry name to match the actual symbol entry.name = actualSymbolName; // Update the entry name to match the actual symbol
madeAnyChanges = true; madeAnyChanges = true;
} }
@ -220,11 +455,15 @@ public class FunctionDatabase {
iterator.remove(); iterator.remove();
if (!dryMode) { if (!dryMode) {
entry.file.delete(); entry.file.delete();
// Remove from database
removeEntryAt(entry.file.getAbsolutePath());
madeAnyChanges = true; madeAnyChanges = true;
} }
} else if (pendingRegenerate && entry.type != Type.Stub) { } else if (pendingRegenerate && entry.type != Type.Stub) {
if (!dryMode) { if (!dryMode) {
functionsToRegenerate.add(function); functionsToRegenerate.add(function);
// Update entry in database with corrected name
addEntryAt(entry);
madeAnyChanges = true; madeAnyChanges = true;
} }
} }
@ -237,7 +476,7 @@ public class FunctionDatabase {
if (madeAnyChanges) { if (madeAnyChanges) {
// Update CMake timestamp // Update CMake timestamp
RecompileConfig.INSTANCE.touchCMakeTimestamp(); RemanConfig.INSTANCE.touchCMakeTimestamp();
globalDumper.dumpGlobals(); globalDumper.dumpGlobals();
globalDumper.saveGlobalManifest(); globalDumper.saveGlobalManifest();

View File

@ -28,6 +28,7 @@ import re3lib.GlobalDumper.GlobalRec;
public class FunctionDumper { public class FunctionDumper {
GhidraScript script; GhidraScript script;
GlobalDumper globalDumper; GlobalDumper globalDumper;
FunctionDatabase functionDatabase;
public HashSet<Address> functionAddrBlackList = new HashSet<>(); public HashSet<Address> functionAddrBlackList = new HashSet<>();
@ -37,8 +38,9 @@ public class FunctionDumper {
static final Pattern fieldAccessRegex = Pattern.compile("^_([0-9]+)_([0-9]+)_$"); static final Pattern fieldAccessRegex = Pattern.compile("^_([0-9]+)_([0-9]+)_$");
public FunctionDumper(GhidraScript script, GlobalDumper globalDumper) { public FunctionDumper(GhidraScript script, FunctionDatabase functionDatabase, GlobalDumper globalDumper) {
this.script = script; this.script = script;
this.functionDatabase = functionDatabase;
this.globalDumper = globalDumper; this.globalDumper = globalDumper;
initFunctionBlacklist(); initFunctionBlacklist();
} }
@ -58,7 +60,7 @@ public class FunctionDumper {
} }
void initFunctionBlacklist() { void initFunctionBlacklist() {
functionAddrBlackList = Utils.loadFunctionBlacklist(RecompileConfig.INSTANCE.functionBlacklistPath); functionAddrBlackList = Utils.loadFunctionBlacklist(RemanConfig.INSTANCE.functionBlacklistPath);
// Build blacklist if not loaded // Build blacklist if not loaded
if (functionAddrBlackList == null) { if (functionAddrBlackList == null) {
@ -99,7 +101,7 @@ public class FunctionDumper {
} }
if (modified) { if (modified) {
Utils.saveFunctionBlacklist(functionAddrBlackList, RecompileConfig.INSTANCE.functionBlacklistPath); Utils.saveFunctionBlacklist(functionAddrBlackList, RemanConfig.INSTANCE.functionBlacklistPath);
} }
} }
} }
@ -107,14 +109,14 @@ public class FunctionDumper {
public static boolean isDumpedFix(Function function) { public static boolean isDumpedFix(Function function) {
String sanitizedFunctionName = Utils.sanitizeIdentifier(function.getName()); String sanitizedFunctionName = Utils.sanitizeIdentifier(function.getName());
String fileName = sanitizedFunctionName + ".cxx"; String fileName = sanitizedFunctionName + ".cxx";
File f0 = new File(RecompileConfig.INSTANCE.dirDecompFix, fileName); File f0 = new File(RemanConfig.INSTANCE.dirDecompFix, fileName);
return f0.exists(); return f0.exists();
} }
public static boolean isDumpedAuto(Function function) { public static boolean isDumpedAuto(Function function) {
String sanitizedFunctionName = Utils.sanitizeIdentifier(function.getName()); String sanitizedFunctionName = Utils.sanitizeIdentifier(function.getName());
String fileName = sanitizedFunctionName + ".cxx"; String fileName = sanitizedFunctionName + ".cxx";
File f0 = new File(RecompileConfig.INSTANCE.dirDecompAuto, fileName); File f0 = new File(RemanConfig.INSTANCE.dirDecompAuto, fileName);
return f0.exists(); return f0.exists();
} }
@ -123,20 +125,21 @@ public class FunctionDumper {
String sanitizedFunctionName = Utils.sanitizeIdentifier(function.getName()); String sanitizedFunctionName = Utils.sanitizeIdentifier(function.getName());
String fileName = sanitizedFunctionName + ".cxx"; String fileName = sanitizedFunctionName + ".cxx";
// Remove the stub file, since we now use the decompiled file // Remove the stub file, since we now use the decompiled file
File stubFile = new File(RecompileConfig.INSTANCE.dirDecompStub, fileName); File stubFile = new File(RemanConfig.INSTANCE.dirDecompStub, fileName);
if (stubFile.exists()) { if (stubFile.exists()) {
script.println("Removing function stub " + stubFile); script.println("Removing function stub " + stubFile);
stubFile.delete(); stubFile.delete();
createdFile = true; createdFile = true;
} }
File f0 = new File(RecompileConfig.INSTANCE.dirDecompFix, fileName); File f0 = new File(RemanConfig.INSTANCE.dirDecompFix, fileName);
if (f0.exists()) { if (f0.exists()) {
script.println("Func " + function.getName() + " skipped (gh_fix)"); script.println("Func " + function.getName() + " skipped (gh_fix)");
f0 = new File(RecompileConfig.INSTANCE.dirDecompRef, fileName); f0 = new File(RemanConfig.INSTANCE.dirDecompRef, fileName);
} else { } else {
f0 = new File(RecompileConfig.INSTANCE.dirDecompAuto, fileName); f0 = new File(RemanConfig.INSTANCE.dirDecompAuto, fileName);
if (f0.exists()) { if (f0.exists()) {
f0.delete(); f0.delete();
} else { } else {
@ -148,7 +151,7 @@ public class FunctionDumper {
List<Function> externalFunctionCalls = new ArrayList<>(); List<Function> externalFunctionCalls = new ArrayList<>();
DecompileResults decompRes = RecompileConfig.INSTANCE.decompCache.getOrInsert(function); DecompileResults decompRes = RemanConfig.INSTANCE.decompCache.getOrInsert(function);
try (PrintWriter writer2 = new PrintWriter(f0, "UTF-8")) { try (PrintWriter writer2 = new PrintWriter(f0, "UTF-8")) {
writer2.println("// AUTO-GENERATED FILE, MOVE TO 'gh_fix' FOLDER PREVENT OVERWRITING!!!!! "); writer2.println("// AUTO-GENERATED FILE, MOVE TO 'gh_fix' FOLDER PREVENT OVERWRITING!!!!! ");
writer2.println(); writer2.println();
@ -291,15 +294,15 @@ public class FunctionDumper {
for (Function externalFunction : externalFunctionCalls) { for (Function externalFunction : externalFunctionCalls) {
String sanitizedExtFunctionName = Utils.sanitizeIdentifier(externalFunction.getName()); String sanitizedExtFunctionName = Utils.sanitizeIdentifier(externalFunction.getName());
fileName = sanitizedExtFunctionName + ".cxx"; fileName = sanitizedExtFunctionName + ".cxx";
File f2 = new File(RecompileConfig.INSTANCE.dirDecompFix, fileName); File f2 = new File(RemanConfig.INSTANCE.dirDecompFix, fileName);
File f3 = new File(RecompileConfig.INSTANCE.dirDecompAuto, fileName); File f3 = new File(RemanConfig.INSTANCE.dirDecompAuto, fileName);
if (f2.exists() || f3.exists()) { if (f2.exists() || f3.exists()) {
// script.println("Skipping external function: " + externalFunction.getName() + // script.println("Skipping external function: " + externalFunction.getName() +
// " - " + externalFunction.getEntryPoint()); // " - " + externalFunction.getEntryPoint());
continue; continue;
} }
File f4 = new File(RecompileConfig.INSTANCE.dirDecompStub, fileName); File f4 = new File(RemanConfig.INSTANCE.dirDecompStub, fileName);
script.println("Generating function stub for " + externalFunction.getName() + " => " + f4.toString()); script.println("Generating function stub for " + externalFunction.getName() + " => " + f4.toString());
try (PrintWriter writer2 = new PrintWriter(f4, "UTF-8")) { try (PrintWriter writer2 = new PrintWriter(f4, "UTF-8")) {

View File

@ -25,7 +25,6 @@ import ghidra.program.model.data.DataType;
import ghidra.program.model.data.DataTypeManager; import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.DataTypePath; import ghidra.program.model.data.DataTypePath;
import ghidra.program.model.data.PointerDataType; import ghidra.program.model.data.PointerDataType;
import ghidra.program.model.data.Undefined;
import ghidra.program.model.listing.Data; import ghidra.program.model.listing.Data;
import ghidra.program.model.pcode.HighSymbol; import ghidra.program.model.pcode.HighSymbol;
import ghidra.program.model.symbol.SourceType; import ghidra.program.model.symbol.SourceType;
@ -49,11 +48,13 @@ public class GlobalDumper {
GhidraScript script; GhidraScript script;
File manifestFile; File manifestFile;
FunctionDatabase functionDatabase;
HashMap<Address, GlobalRec> globalAddrs = new HashMap<>(); HashMap<Address, GlobalRec> globalAddrs = new HashMap<>();
public GlobalDumper(GhidraScript script) { public GlobalDumper(GhidraScript script, FunctionDatabase functionDatabase) {
this.script = script; this.script = script;
manifestFile = new File(RecompileConfig.INSTANCE.outputDir, "globals.txt"); this.functionDatabase = functionDatabase;
manifestFile = new File(RemanConfig.INSTANCE.outputDir, "globals.txt");
} }
public void removeGlobalManifest() { public void removeGlobalManifest() {
@ -108,8 +109,8 @@ public class GlobalDumper {
} }
public void addGlobal(Address addr, HighSymbol sym) throws Exception { public void addGlobal(Address addr, HighSymbol sym) throws Exception {
if (addr.compareTo(RecompileConfig.INSTANCE.staticMemoryBlockStart) < 0 if (addr.compareTo(RemanConfig.INSTANCE.staticMemoryBlockStart) < 0
|| addr.compareTo(RecompileConfig.INSTANCE.staticMemoryBlockEnd) > 0) { || addr.compareTo(RemanConfig.INSTANCE.staticMemoryBlockEnd) > 0) {
throw new Exception("Global address out of range: " + addr); throw new Exception("Global address out of range: " + addr);
} }
@ -162,14 +163,14 @@ public class GlobalDumper {
} }
public void dumpGlobals() throws Exception { public void dumpGlobals() throws Exception {
File globalSymbolsListH = new File(RecompileConfig.INSTANCE.outputDir, "gh_global.h"); File globalSymbolsListH = new File(RemanConfig.INSTANCE.outputDir, "gh_global.h");
PrintWriter hwriter = new PrintWriter(globalSymbolsListH, "UTF-8"); PrintWriter hwriter = new PrintWriter(globalSymbolsListH, "UTF-8");
hwriter.println("// AUTO-GENERATED FILE "); hwriter.println("// AUTO-GENERATED FILE ");
Utils.headerGuardPre(hwriter, "GLOBALS"); Utils.headerGuardPre(hwriter, "GLOBALS");
hwriter.println("#include <r3/binders/global.h>"); hwriter.println("#include <r3/binders/global.h>");
hwriter.println(); hwriter.println();
File globalSymbolsListC = new File(RecompileConfig.INSTANCE.outputDir, "gh_global.cxx"); File globalSymbolsListC = new File(RemanConfig.INSTANCE.outputDir, "gh_global.cxx");
PrintWriter cwriter = new PrintWriter(globalSymbolsListC, "UTF-8"); PrintWriter cwriter = new PrintWriter(globalSymbolsListC, "UTF-8");
cwriter.println("// AUTO-GENERATED FILE "); cwriter.println("// AUTO-GENERATED FILE ");
cwriter.println("#include <r3/binders/global.h>"); cwriter.println("#include <r3/binders/global.h>");

View File

@ -42,7 +42,7 @@ public class PCallTracer {
Program program; Program program;
public PCallTracer() { public PCallTracer() {
this.script = RecompileConfig.INSTANCE.script; this.script = RemanConfig.INSTANCE.script;
this.program = this.script.getCurrentProgram(); this.program = this.script.getCurrentProgram();
// this.decomp = RecompileConfig.INSTANCE.decompCache; // this.decomp = RecompileConfig.INSTANCE.decompCache;
} }

View File

@ -10,7 +10,9 @@ import ghidra.program.flatapi.FlatProgramAPI;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
public class RecompileConfig { // A general configuration for the reman project
// including all paths, specific addresses and stuff
public class RemanConfig {
private static final String RECOMPILE_PREFIX = "game_re"; private static final String RECOMPILE_PREFIX = "game_re";
// Version control project root // Version control project root
@ -24,6 +26,9 @@ public class RecompileConfig {
public final Address staticMemoryBlockStart; public final Address staticMemoryBlockStart;
public final Address staticMemoryBlockEnd; public final Address staticMemoryBlockEnd;
// The path to the database file
public final File databasePath;
// The automatically decompiled files // The automatically decompiled files
public final File dirDecompAuto; public final File dirDecompAuto;
// The manually decompiled files (will not be overwritten by the auto // The manually decompiled files (will not be overwritten by the auto
@ -48,9 +53,9 @@ public class RecompileConfig {
public final GhidraScript script; public final GhidraScript script;
public static RecompileConfig INSTANCE; public static RemanConfig INSTANCE;
public RecompileConfig(GhidraScript script) { public RemanConfig(GhidraScript script) {
staticMemoryBlockStart = script.getCurrentProgram().getAddressFactory().getAddress("00597000"); staticMemoryBlockStart = script.getCurrentProgram().getAddressFactory().getAddress("00597000");
staticMemoryBlockEnd = script.getCurrentProgram().getAddressFactory().getAddress("00843fff"); staticMemoryBlockEnd = script.getCurrentProgram().getAddressFactory().getAddress("00843fff");
@ -64,6 +69,8 @@ public class RecompileConfig {
categoryPathBlacklistPath = new File(outputDir, "type_path_blacklist.txt").toString(); categoryPathBlacklistPath = new File(outputDir, "type_path_blacklist.txt").toString();
functionBlacklistPath = new File(outputDir, "function_blacklist.txt").toString(); functionBlacklistPath = new File(outputDir, "function_blacklist.txt").toString();
databasePath = new File(outputDir, "gh.db");
dirDecompAuto = new File(outputDir, "gh_auto"); dirDecompAuto = new File(outputDir, "gh_auto");
dirDecompFix = new File(outputDir, "gh_fix"); dirDecompFix = new File(outputDir, "gh_fix");
dirDecompRef = new File(outputDir, "gh_ref"); dirDecompRef = new File(outputDir, "gh_ref");

View File

@ -25,15 +25,15 @@ public class TypeDumper {
public TypeDumper(GhidraScript script) { public TypeDumper(GhidraScript script) {
this.script = script; this.script = script;
currentProgram = script.getCurrentProgram(); currentProgram = script.getCurrentProgram();
RecompileConfig.INSTANCE = new RecompileConfig(script); RemanConfig.INSTANCE = new RemanConfig(script);
} }
public void run() throws Exception { public void run() throws Exception {
ProgramBasedDataTypeManager dtm = currentProgram.getDataTypeManager(); ProgramBasedDataTypeManager dtm = currentProgram.getDataTypeManager();
HashSet<String> typeBlacklist = Utils.loadSimpleBlacklist(RecompileConfig.INSTANCE.typeBlacklistPath); HashSet<String> typeBlacklist = Utils.loadSimpleBlacklist(RemanConfig.INSTANCE.typeBlacklistPath);
HashSet<String> categoryPathBlacklist = Utils HashSet<String> categoryPathBlacklist = Utils
.loadSimpleBlacklist(RecompileConfig.INSTANCE.categoryPathBlacklistPath); .loadSimpleBlacklist(RemanConfig.INSTANCE.categoryPathBlacklistPath);
if (typeBlacklist == null) { if (typeBlacklist == null) {
script.println("Building struct blacklist from existing data types"); script.println("Building struct blacklist from existing data types");
@ -45,7 +45,7 @@ public class TypeDumper {
typeBlacklist.add(dt.getDisplayName()); typeBlacklist.add(dt.getDisplayName());
} }
} }
Utils.saveStructBlacklist(typeBlacklist, RecompileConfig.INSTANCE.typeBlacklistPath); Utils.saveStructBlacklist(typeBlacklist, RemanConfig.INSTANCE.typeBlacklistPath);
} }
List<DataType> filteredTypes = new ArrayList<>(); List<DataType> filteredTypes = new ArrayList<>();
@ -92,7 +92,7 @@ public class TypeDumper {
} }
} }
try (PrintWriter writer = new PrintWriter(new File(RecompileConfig.INSTANCE.outputDir, "gh_types.h"), try (PrintWriter writer = new PrintWriter(new File(RemanConfig.INSTANCE.outputDir, "gh_types.h"),
"UTF-8")) { "UTF-8")) {
Utils.headerGuardPre(writer, "STRUCTS"); Utils.headerGuardPre(writer, "STRUCTS");
writer.println("// AUTO-GENERATED FILE "); writer.println("// AUTO-GENERATED FILE ");

View File

@ -51,7 +51,7 @@ public class Utils {
} }
public static HashSet<Address> loadFunctionBlacklist(String path) { public static HashSet<Address> loadFunctionBlacklist(String path) {
GhidraScript script = RecompileConfig.INSTANCE.script; GhidraScript script = RemanConfig.INSTANCE.script;
HashSet<Address> fnBlacklist = new HashSet<>(); HashSet<Address> fnBlacklist = new HashSet<>();
File blacklistFile = new File(path); File blacklistFile = new File(path);
try (Scanner scanner = new Scanner(blacklistFile)) { try (Scanner scanner = new Scanner(blacklistFile)) {
@ -60,7 +60,7 @@ public class Utils {
// Strip comment // Strip comment
String line1 = line.split("//")[0].trim(); String line1 = line.split("//")[0].trim();
// Deserialize address // Deserialize address
Address addr = RecompileConfig.INSTANCE.currentProgram.getAddressFactory().getAddress(line1); Address addr = RemanConfig.INSTANCE.currentProgram.getAddressFactory().getAddress(line1);
fnBlacklist.add(addr); fnBlacklist.add(addr);
} }
script.println("Loaded blacklist with " + fnBlacklist.size() + " entries"); script.println("Loaded blacklist with " + fnBlacklist.size() + " entries");
@ -71,7 +71,7 @@ public class Utils {
} }
public static void saveFunctionBlacklist(HashSet<Address> fnBlacklist, String path) { public static void saveFunctionBlacklist(HashSet<Address> fnBlacklist, String path) {
GhidraScript script = RecompileConfig.INSTANCE.script; GhidraScript script = RemanConfig.INSTANCE.script;
File blacklistFile = new File(path); File blacklistFile = new File(path);
try (PrintWriter writer = new PrintWriter(blacklistFile)) { try (PrintWriter writer = new PrintWriter(blacklistFile)) {
for (Address addr : fnBlacklist) { for (Address addr : fnBlacklist) {

View File

@ -11,3 +11,63 @@ The decompile database is a sqlite database that contains a list of all files th
To generate the database from the current set of files, run the scan_sources script in the /game_re folder. To generate the database from the current set of files, run the scan_sources script in the /game_re folder.
Make sure you have set up the tooling by running the /tooling/setup script. Make sure you have set up the tooling by running the /tooling/setup script.
## IDE Notes
This should work with the redhat java plugin for vscode, you however need to manually add the referenced libraries to the settings, like so:
```json
{
"java.project.referencedLibraries": [
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\Base\\lib\\Base.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\Decompiler\\lib\\Decompiler.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\BSim\\lib\\BSim.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\BSimFeatureVisualizer\\lib\\BSimFeatureVisualizer.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\Base\\lib\\Base.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\BytePatterns\\lib\\BytePatterns.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\ByteViewer\\lib\\ByteViewer.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\CodeCompare\\lib\\CodeCompare.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\DebugUtils\\lib\\DebugUtils.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\Decompiler\\lib\\Decompiler.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\DecompilerDependent\\lib\\DecompilerDependent.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\FileFormats\\lib\\FileFormats.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\FunctionGraph\\lib\\FunctionGraph.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\FunctionGraphDecompilerExtension\\lib\\FunctionGraphDecompilerExtension.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\FunctionID\\lib\\FunctionID.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\GhidraGo\\lib\\GhidraGo.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\GhidraServer\\lib\\GhidraServer.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\GnuDemangler\\lib\\GnuDemangler.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\GraphFunctionCalls\\lib\\GraphFunctionCalls.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\GraphServices\\lib\\GraphServices.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\MicrosoftCodeAnalyzer\\lib\\MicrosoftCodeAnalyzer.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\MicrosoftDemangler\\lib\\MicrosoftDemangler.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\MicrosoftDmang\\lib\\MicrosoftDmang.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\PDB\\lib\\PDB.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\ProgramDiff\\lib\\ProgramDiff.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\ProgramGraph\\lib\\ProgramGraph.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\Python\\lib\\Python.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\Recognizers\\lib\\Recognizers.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\Sarif\\lib\\Sarif.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\SourceCodeLookup\\lib\\SourceCodeLookup.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\SwiftDemangler\\lib\\SwiftDemangler.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\SystemEmulation\\lib\\SystemEmulation.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\VersionTracking\\lib\\VersionTracking.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\VersionTrackingBSim\\lib\\VersionTrackingBSim.jar",
"C:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Features\\WildcardAssembler\\lib\\WildcardAssembler.jar",
"c:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Framework\\DB\\lib\\DB.jar",
"c:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Framework\\Docking\\lib\\Docking.jar",
"c:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Framework\\Emulation\\lib\\Emulation.jar",
"c:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Framework\\FileSystem\\lib\\FileSystem.jar",
"c:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Framework\\Generic\\lib\\Generic.jar",
"c:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Framework\\Graph\\lib\\Graph.jar",
"c:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Framework\\Gui\\lib\\Gui.jar",
"c:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Framework\\Help\\lib\\Help.jar",
"c:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Framework\\Project\\lib\\Project.jar",
"c:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Framework\\Pty\\lib\\Pty.jar",
"c:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Framework\\SoftwareModeling\\lib\\SoftwareModeling.jar",
"c:\\Projects\\ghidra_11.3.2_PUBLIC\\Ghidra\\Framework\\Utility\\lib\\Utility.jar",
"c:\\Projects\\R3\\java\\ghidra\\sqlite-jdbc-3.49.1.0.jar"
]
}
```

View File

@ -13,10 +13,18 @@ CREATE TABLE Functions (
filepath TEXT, filepath TEXT,
name TEXT, name TEXT,
address TEXT, address TEXT,
type INTEGER,
PRIMARY KEY (name, filepath) PRIMARY KEY (name, filepath)
); );
``` ```
Where type is one of the following:
- 0: Auto
- 1: Fix
- 2: Stub
- 3: Ref
**Purpose**: Stores function definitions that have function bodies (actual implementations) **Purpose**: Stores function definitions that have function bodies (actual implementations)
- `filepath`: Source file path where the function is defined - `filepath`: Source file path where the function is defined
- `name`: Function name (identifier) - `name`: Function name (identifier)
@ -29,6 +37,7 @@ CREATE TABLE Imports (
filepath TEXT, filepath TEXT,
name TEXT, name TEXT,
address TEXT, address TEXT,
type INTEGER,
PRIMARY KEY (name, filepath) PRIMARY KEY (name, filepath)
); );
``` ```