Update readme and rename config java
This commit is contained in:
parent
d7de3deb59
commit
647e3668a0
|
@ -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
1759
game_re/gh_global.h
1759
game_re/gh_global.h
File diff suppressed because it is too large
Load Diff
9458
game_re/gh_types.h
9458
game_re/gh_types.h
File diff suppressed because it is too large
Load Diff
|
@ -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 */
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
#include "r3/config/static.hpp"
|
||||||
|
|
||||||
|
void gh_init_dbg_loader() {
|
||||||
|
}
|
|
@ -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 */
|
|
@ -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 */
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
|
GHStubException::GHStubException(const char *msg) : std::exception(msg) {
|
||||||
|
SPDLOG_ERROR("{}", msg);
|
||||||
|
}
|
|
@ -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 */
|
|
@ -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 */
|
|
|
@ -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) {
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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")) {
|
||||||
|
|
|
@ -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>");
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
|
@ -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 ");
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
|
@ -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)
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
Loading…
Reference in New Issue