WIP
This commit is contained in:
parent
16e5456079
commit
e19a123b94
|
@ -9,6 +9,7 @@ import java.util.List;
|
||||||
import ghidra.app.script.GhidraScript;
|
import ghidra.app.script.GhidraScript;
|
||||||
import ghidra.pcodeCPort.address.Address;
|
import ghidra.pcodeCPort.address.Address;
|
||||||
import ghidra.program.model.listing.Function;
|
import ghidra.program.model.listing.Function;
|
||||||
|
import re3lib.FunctionDatabase;
|
||||||
import re3lib.FunctionDumper;
|
import re3lib.FunctionDumper;
|
||||||
import re3lib.GlobalDumper;
|
import re3lib.GlobalDumper;
|
||||||
import re3lib.PCallTracer;
|
import re3lib.PCallTracer;
|
||||||
|
@ -19,26 +20,26 @@ public class DumpCurrentFunctionN extends GhidraScript {
|
||||||
final int NumFunctions = 8;
|
final int NumFunctions = 8;
|
||||||
|
|
||||||
// class Entry {
|
// class Entry {
|
||||||
// Function function;
|
// Function function;
|
||||||
// }
|
// }
|
||||||
// class QueueEntry {
|
// class QueueEntry {
|
||||||
// Function function;
|
// Function function;
|
||||||
// List<Function> callees;
|
// List<Function> callees;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// HashSet<Address> visited = new HashSet<>();
|
// HashSet<Address> visited = new HashSet<>();
|
||||||
|
|
||||||
// QueueEntry enter(Function function) {
|
// QueueEntry enter(Function function) {
|
||||||
// if (visited.contains(function.getEntryPoint()))
|
// if (visited.contains(function.getEntryPoint()))
|
||||||
// return null;
|
// return null;
|
||||||
|
|
||||||
// visited.add(function.getEntryPoint());
|
// visited.add(function.getEntryPoint());
|
||||||
|
|
||||||
// QueueEntry entry = new QueueEntry();
|
// QueueEntry entry = new QueueEntry();
|
||||||
// entry.function = function;
|
// entry.function = function;
|
||||||
|
|
||||||
|
// function.getCalledFunctions(monitor);
|
||||||
|
|
||||||
// function.getCalledFunctions(monitor);
|
|
||||||
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -46,62 +47,66 @@ public class DumpCurrentFunctionN extends GhidraScript {
|
||||||
RemanConfig.INSTANCE = new RemanConfig(this);
|
RemanConfig.INSTANCE = new RemanConfig(this);
|
||||||
RemanConfig.INSTANCE.createDirectories();
|
RemanConfig.INSTANCE.createDirectories();
|
||||||
|
|
||||||
GlobalDumper globalDumper = new GlobalDumper(this);
|
try (FunctionDatabase functionDatabase = new FunctionDatabase(this)) {
|
||||||
globalDumper.loadGlobalManifest();
|
|
||||||
|
|
||||||
FunctionDumper functionDumper = new FunctionDumper(this, globalDumper);
|
GlobalDumper globalDumper = new GlobalDumper(this, functionDatabase);
|
||||||
|
globalDumper.loadGlobalManifest();
|
||||||
|
|
||||||
PCallTracer tracer = new PCallTracer();
|
FunctionDumper functionDumper = new FunctionDumper(this, functionDatabase, globalDumper);
|
||||||
tracer.setBlacklist(functionDumper.functionAddrBlackList);
|
|
||||||
tracer.traceCalls(getFunctionContaining(currentAddress));
|
|
||||||
|
|
||||||
List<Address> queue = new ArrayList<>();
|
PCallTracer tracer = new PCallTracer();
|
||||||
|
tracer.setBlacklist(functionDumper.functionAddrBlackList);
|
||||||
|
tracer.traceCalls(getFunctionContaining(currentAddress));
|
||||||
|
|
||||||
// List<Function> functionsToDump = new ArrayList<>();
|
List<Address> queue = new ArrayList<>();
|
||||||
// List<Function> functionsToDumpNew = new ArrayList<>();
|
|
||||||
// for (Function func : tracer.out) {
|
|
||||||
// if (FunctionDumper.isDumpedFix(func))
|
|
||||||
// continue;
|
|
||||||
|
|
||||||
// println("Dump: " + func.getName());
|
// List<Function> functionsToDump = new ArrayList<>();
|
||||||
// functionsToDump.add(func);
|
// List<Function> functionsToDumpNew = new ArrayList<>();
|
||||||
|
// for (Function func : tracer.out) {
|
||||||
|
// if (FunctionDumper.isDumpedFix(func))
|
||||||
|
// continue;
|
||||||
|
|
||||||
// if (!FunctionDumper.isDumpedAuto(func))
|
// println("Dump: " + func.getName());
|
||||||
// functionsToDumpNew.add(func);
|
// functionsToDump.add(func);
|
||||||
// }
|
|
||||||
|
|
||||||
// if (!functionsToDump.isEmpty()) {
|
// if (!FunctionDumper.isDumpedAuto(func))
|
||||||
// String newOpt = "Only new (" + functionsToDumpNew.size() + ")";
|
// functionsToDumpNew.add(func);
|
||||||
// String okOpt = "Yes (" + functionsToDump.size() + ")";
|
// }
|
||||||
// String choice = askChoice("Confirmation", "About to generate " + functionsToDump.size() + " functions ("
|
|
||||||
// + functionsToDumpNew.size() + " new), continue?",
|
|
||||||
// new ArrayList<String>() {
|
|
||||||
// {
|
|
||||||
// add(okOpt);
|
|
||||||
// add(newOpt);
|
|
||||||
// add("No");
|
|
||||||
// }
|
|
||||||
// }, okOpt);
|
|
||||||
// if (choice == okOpt) {
|
|
||||||
// } else if (choice == newOpt) {
|
|
||||||
// functionsToDump = functionsToDumpNew;
|
|
||||||
// } else {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// for (Function func : functionsToDump) {
|
// if (!functionsToDump.isEmpty()) {
|
||||||
// functionDumper.dump(func);
|
// String newOpt = "Only new (" + functionsToDumpNew.size() + ")";
|
||||||
// }
|
// String okOpt = "Yes (" + functionsToDump.size() + ")";
|
||||||
|
// String choice = askChoice("Confirmation", "About to generate " +
|
||||||
|
// functionsToDump.size() + " functions ("
|
||||||
|
// + functionsToDumpNew.size() + " new), continue?",
|
||||||
|
// new ArrayList<String>() {
|
||||||
|
// {
|
||||||
|
// add(okOpt);
|
||||||
|
// add(newOpt);
|
||||||
|
// add("No");
|
||||||
|
// }
|
||||||
|
// }, okOpt);
|
||||||
|
// if (choice == okOpt) {
|
||||||
|
// } else if (choice == newOpt) {
|
||||||
|
// functionsToDump = functionsToDumpNew;
|
||||||
|
// } else {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
// if (functionDumper.createdFile)
|
// for (Function func : functionsToDump) {
|
||||||
// RecompileConfig.INSTANCE.touchCMakeTimestamp();
|
// functionDumper.dump(func);
|
||||||
|
// }
|
||||||
|
|
||||||
// globalDumper.dumpGlobals();
|
// if (functionDumper.createdFile)
|
||||||
// globalDumper.saveGlobalManifest();
|
// RecompileConfig.INSTANCE.touchCMakeTimestamp();
|
||||||
// }
|
|
||||||
|
|
||||||
// // Dump types
|
// globalDumper.dumpGlobals();
|
||||||
// TypeDumper dumper = new TypeDumper(this);
|
// globalDumper.saveGlobalManifest();
|
||||||
// dumper.run();
|
// }
|
||||||
|
|
||||||
|
// // Dump types
|
||||||
|
// TypeDumper dumper = new TypeDumper(this);
|
||||||
|
// dumper.run();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import java.util.List;
|
||||||
|
|
||||||
import ghidra.app.script.GhidraScript;
|
import ghidra.app.script.GhidraScript;
|
||||||
import ghidra.program.model.listing.Function;
|
import ghidra.program.model.listing.Function;
|
||||||
|
import re3lib.FunctionDatabase;
|
||||||
import re3lib.FunctionDumper;
|
import re3lib.FunctionDumper;
|
||||||
import re3lib.GlobalDumper;
|
import re3lib.GlobalDumper;
|
||||||
import re3lib.PCallTracer;
|
import re3lib.PCallTracer;
|
||||||
|
@ -19,60 +20,62 @@ public class DumpCurrentFunctionRecursive extends GhidraScript {
|
||||||
RemanConfig.INSTANCE = new RemanConfig(this);
|
RemanConfig.INSTANCE = new RemanConfig(this);
|
||||||
RemanConfig.INSTANCE.createDirectories();
|
RemanConfig.INSTANCE.createDirectories();
|
||||||
|
|
||||||
GlobalDumper globalDumper = new GlobalDumper(this);
|
try (FunctionDatabase functionDatabase = new FunctionDatabase(this)) {
|
||||||
globalDumper.loadGlobalManifest();
|
GlobalDumper globalDumper = new GlobalDumper(this, functionDatabase);
|
||||||
|
globalDumper.loadGlobalManifest();
|
||||||
|
|
||||||
FunctionDumper functionDumper = new FunctionDumper(this, globalDumper);
|
FunctionDumper functionDumper = new FunctionDumper(this, functionDatabase, globalDumper);
|
||||||
|
|
||||||
PCallTracer tracer = new PCallTracer();
|
PCallTracer tracer = new PCallTracer();
|
||||||
tracer.setBlacklist(functionDumper.functionAddrBlackList);
|
tracer.setBlacklist(functionDumper.functionAddrBlackList);
|
||||||
tracer.traceCalls(getFunctionContaining(currentAddress));
|
tracer.traceCalls(getFunctionContaining(currentAddress));
|
||||||
|
|
||||||
List<Function> functionsToDump = new ArrayList<>();
|
List<Function> functionsToDump = new ArrayList<>();
|
||||||
List<Function> functionsToDumpNew = new ArrayList<>();
|
List<Function> functionsToDumpNew = new ArrayList<>();
|
||||||
for (Function func : tracer.out) {
|
for (Function func : tracer.out) {
|
||||||
if (FunctionDumper.isDumpedFix(func))
|
if (FunctionDumper.isDumpedFix(func))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
println("Dump: " + func.getName());
|
println("Dump: " + func.getName());
|
||||||
functionsToDump.add(func);
|
functionsToDump.add(func);
|
||||||
|
|
||||||
if (!FunctionDumper.isDumpedAuto(func))
|
if (!FunctionDumper.isDumpedAuto(func))
|
||||||
functionsToDumpNew.add(func);
|
functionsToDumpNew.add(func);
|
||||||
}
|
|
||||||
|
|
||||||
if (!functionsToDump.isEmpty()) {
|
|
||||||
String newOpt = "Only new (" + functionsToDumpNew.size() + ")";
|
|
||||||
String okOpt = "Yes (" + functionsToDump.size() + ")";
|
|
||||||
String choice = askChoice("Confirmation", "About to generate " + functionsToDump.size() + " functions ("
|
|
||||||
+ functionsToDumpNew.size() + " new), continue?",
|
|
||||||
new ArrayList<String>() {
|
|
||||||
{
|
|
||||||
add(okOpt);
|
|
||||||
add(newOpt);
|
|
||||||
add("No");
|
|
||||||
}
|
|
||||||
}, okOpt);
|
|
||||||
if (choice == okOpt) {
|
|
||||||
} else if (choice == newOpt) {
|
|
||||||
functionsToDump = functionsToDumpNew;
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Function func : functionsToDump) {
|
if (!functionsToDump.isEmpty()) {
|
||||||
functionDumper.dump(func);
|
String newOpt = "Only new (" + functionsToDumpNew.size() + ")";
|
||||||
|
String okOpt = "Yes (" + functionsToDump.size() + ")";
|
||||||
|
String choice = askChoice("Confirmation", "About to generate " + functionsToDump.size() + " functions ("
|
||||||
|
+ functionsToDumpNew.size() + " new), continue?",
|
||||||
|
new ArrayList<String>() {
|
||||||
|
{
|
||||||
|
add(okOpt);
|
||||||
|
add(newOpt);
|
||||||
|
add("No");
|
||||||
|
}
|
||||||
|
}, okOpt);
|
||||||
|
if (choice == okOpt) {
|
||||||
|
} else if (choice == newOpt) {
|
||||||
|
functionsToDump = functionsToDumpNew;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Function func : functionsToDump) {
|
||||||
|
functionDumper.dump(func);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (functionDumper.createdFile)
|
||||||
|
RemanConfig.INSTANCE.touchCMakeTimestamp();
|
||||||
|
|
||||||
|
globalDumper.dumpGlobals();
|
||||||
|
globalDumper.saveGlobalManifest();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (functionDumper.createdFile)
|
// Dump types
|
||||||
RemanConfig.INSTANCE.touchCMakeTimestamp();
|
TypeDumper dumper = new TypeDumper(this);
|
||||||
|
dumper.run();
|
||||||
globalDumper.dumpGlobals();
|
|
||||||
globalDumper.saveGlobalManifest();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dump types
|
|
||||||
TypeDumper dumper = new TypeDumper(this);
|
|
||||||
dumper.run();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,8 +15,8 @@ public class Test extends GhidraScript {
|
||||||
|
|
||||||
// Example SQLite usage
|
// Example SQLite usage
|
||||||
try (FunctionDatabase db = new FunctionDatabase(this)) {
|
try (FunctionDatabase db = new FunctionDatabase(this)) {
|
||||||
List<FunctionDatabase.Entry> entries = db.loadAllEntries();
|
List<FunctionDatabase.FunctionEntry> entries = db.loadAllEntries();
|
||||||
for (FunctionDatabase.Entry entry : entries) {
|
for (FunctionDatabase.FunctionEntry entry : entries) {
|
||||||
println("entry.name: " + entry.name + " entry.address: " + entry.address + " entry.type: " + entry.type);
|
println("entry.name: " + entry.name + " entry.address: " + entry.address + " entry.type: " + entry.type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.listing.Function;
|
import ghidra.program.model.listing.Function;
|
||||||
|
|
||||||
public class FunctionDatabase implements AutoCloseable {
|
public class FunctionDatabase implements AutoCloseable {
|
||||||
public enum Type {
|
public static enum Type {
|
||||||
Auto(0),
|
Auto(0),
|
||||||
Fix(1),
|
Fix(1),
|
||||||
Stub(2),
|
Stub(2),
|
||||||
|
@ -46,13 +46,13 @@ public class FunctionDatabase implements AutoCloseable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Entry {
|
public static class FunctionEntry {
|
||||||
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 Entry(Address address, String name, File file, Type type) {
|
public FunctionEntry(Address address, String name, File file, Type type) {
|
||||||
this.address = address;
|
this.address = address;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.file = file;
|
this.file = file;
|
||||||
|
@ -60,6 +60,20 @@ public class FunctionDatabase implements AutoCloseable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class GlobalEntry {
|
||||||
|
public Address address;
|
||||||
|
public String name;
|
||||||
|
public String dataType;
|
||||||
|
public File file;
|
||||||
|
|
||||||
|
public GlobalEntry(Address address, String name, String dataType, File file) {
|
||||||
|
this.address = address;
|
||||||
|
this.name = name;
|
||||||
|
this.dataType = dataType;
|
||||||
|
this.file = file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private File dbFile;
|
private File dbFile;
|
||||||
private transient GhidraScript script;
|
private transient GhidraScript script;
|
||||||
private Connection connection;
|
private Connection connection;
|
||||||
|
@ -75,6 +89,13 @@ public class FunctionDatabase implements AutoCloseable {
|
||||||
private PreparedStatement loadAllFunctions;
|
private PreparedStatement loadAllFunctions;
|
||||||
private PreparedStatement loadAllImports;
|
private PreparedStatement loadAllImports;
|
||||||
|
|
||||||
|
// Add these prepared statements after the existing ones
|
||||||
|
private PreparedStatement findByNameGlobals;
|
||||||
|
private PreparedStatement findByAddressGlobals;
|
||||||
|
private PreparedStatement insertOrReplaceGlobals;
|
||||||
|
private PreparedStatement deleteByFilepathGlobals;
|
||||||
|
private PreparedStatement loadAllGlobals;
|
||||||
|
|
||||||
public FunctionDatabase(GhidraScript script) {
|
public FunctionDatabase(GhidraScript script) {
|
||||||
this.script = script;
|
this.script = script;
|
||||||
dbFile = RemanConfig.INSTANCE.databasePath;
|
dbFile = RemanConfig.INSTANCE.databasePath;
|
||||||
|
@ -155,6 +176,18 @@ public class FunctionDatabase implements AutoCloseable {
|
||||||
"SELECT filepath, name, address, type FROM Functions");
|
"SELECT filepath, name, address, type FROM Functions");
|
||||||
loadAllImports = connection.prepareStatement(
|
loadAllImports = connection.prepareStatement(
|
||||||
"SELECT filepath, name, address, type FROM Imports");
|
"SELECT filepath, name, address, type FROM Imports");
|
||||||
|
|
||||||
|
// Global statements
|
||||||
|
findByNameGlobals = connection.prepareStatement(
|
||||||
|
"SELECT filepath, name, address, type FROM Globals WHERE name = ?");
|
||||||
|
findByAddressGlobals = connection.prepareStatement(
|
||||||
|
"SELECT filepath, name, address, type FROM Globals WHERE address = ?");
|
||||||
|
insertOrReplaceGlobals = connection.prepareStatement(
|
||||||
|
"INSERT OR REPLACE INTO Globals (filepath, name, address, type) VALUES (?, ?, ?, ?)");
|
||||||
|
deleteByFilepathGlobals = connection.prepareStatement(
|
||||||
|
"DELETE FROM Globals WHERE filepath = ?");
|
||||||
|
loadAllGlobals = connection.prepareStatement(
|
||||||
|
"SELECT filepath, name, address, type FROM Globals");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void closePreparedStatements() throws SQLException {
|
private void closePreparedStatements() throws SQLException {
|
||||||
|
@ -176,17 +209,28 @@ public class FunctionDatabase implements AutoCloseable {
|
||||||
loadAllFunctions.close();
|
loadAllFunctions.close();
|
||||||
if (loadAllImports != null)
|
if (loadAllImports != null)
|
||||||
loadAllImports.close();
|
loadAllImports.close();
|
||||||
|
|
||||||
|
if (findByNameGlobals != null)
|
||||||
|
findByNameGlobals.close();
|
||||||
|
if (findByAddressGlobals != null)
|
||||||
|
findByAddressGlobals.close();
|
||||||
|
if (insertOrReplaceGlobals != null)
|
||||||
|
insertOrReplaceGlobals.close();
|
||||||
|
if (deleteByFilepathGlobals != null)
|
||||||
|
deleteByFilepathGlobals.close();
|
||||||
|
if (loadAllGlobals != null)
|
||||||
|
loadAllGlobals.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Entry> loadAllEntries() throws Exception {
|
public List<FunctionEntry> loadAllEntries() throws Exception {
|
||||||
ensureConnection();
|
ensureConnection();
|
||||||
List<Entry> entries = new ArrayList<>();
|
List<FunctionEntry> entries = new ArrayList<>();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Load from Functions table
|
// Load from Functions table
|
||||||
try (ResultSet rs = loadAllFunctions.executeQuery()) {
|
try (ResultSet rs = loadAllFunctions.executeQuery()) {
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
Entry entry = createEntryFromResultSet(rs);
|
FunctionEntry entry = createEntryFromResultSet(rs);
|
||||||
if (entry != null) {
|
if (entry != null) {
|
||||||
entries.add(entry);
|
entries.add(entry);
|
||||||
}
|
}
|
||||||
|
@ -201,7 +245,7 @@ public class FunctionDatabase implements AutoCloseable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Entry createEntryFromResultSet(ResultSet rs) throws SQLException {
|
private FunctionEntry createEntryFromResultSet(ResultSet rs) throws SQLException {
|
||||||
String filepath = rs.getString("filepath");
|
String filepath = rs.getString("filepath");
|
||||||
String name = rs.getString("name");
|
String name = rs.getString("name");
|
||||||
String addressStr = rs.getString("address");
|
String addressStr = rs.getString("address");
|
||||||
|
@ -212,7 +256,7 @@ public class FunctionDatabase implements AutoCloseable {
|
||||||
File file = new File(RemanConfig.INSTANCE.outputDir, filepath);
|
File file = new File(RemanConfig.INSTANCE.outputDir, filepath);
|
||||||
Type type = Type.fromValue(typeValue);
|
Type type = Type.fromValue(typeValue);
|
||||||
|
|
||||||
return new Entry(address, name, file, type);
|
return new FunctionEntry(address, name, file, type);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -236,21 +280,31 @@ public class FunctionDatabase implements AutoCloseable {
|
||||||
PRIMARY KEY (name, filepath)
|
PRIMARY KEY (name, filepath)
|
||||||
)""";
|
)""";
|
||||||
|
|
||||||
|
String createGlobals = """
|
||||||
|
CREATE TABLE IF NOT EXISTS Globals (
|
||||||
|
filepath TEXT,
|
||||||
|
name TEXT,
|
||||||
|
address TEXT,
|
||||||
|
type TEXT,
|
||||||
|
PRIMARY KEY (name, filepath)
|
||||||
|
)""";
|
||||||
|
|
||||||
connection.prepareStatement(createFunctions).executeUpdate();
|
connection.prepareStatement(createFunctions).executeUpdate();
|
||||||
connection.prepareStatement(createImports).executeUpdate();
|
connection.prepareStatement(createImports).executeUpdate();
|
||||||
|
connection.prepareStatement(createGlobals).executeUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper method to find entries by name
|
// Helper method to find entries by name
|
||||||
public List<Entry> findEntriesByName(String name) throws Exception {
|
public List<FunctionEntry> findEntriesByName(String name) throws Exception {
|
||||||
ensureConnection();
|
ensureConnection();
|
||||||
List<Entry> results = new ArrayList<>();
|
List<FunctionEntry> results = new ArrayList<>();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Search Functions table
|
// Search Functions table
|
||||||
findByNameFunctions.setString(1, name);
|
findByNameFunctions.setString(1, name);
|
||||||
try (ResultSet rs = findByNameFunctions.executeQuery()) {
|
try (ResultSet rs = findByNameFunctions.executeQuery()) {
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
Entry entry = createEntryFromResultSet(rs);
|
FunctionEntry entry = createEntryFromResultSet(rs);
|
||||||
if (entry != null) {
|
if (entry != null) {
|
||||||
results.add(entry);
|
results.add(entry);
|
||||||
}
|
}
|
||||||
|
@ -261,7 +315,7 @@ public class FunctionDatabase implements AutoCloseable {
|
||||||
findByNameImports.setString(1, name);
|
findByNameImports.setString(1, name);
|
||||||
try (ResultSet rs = findByNameImports.executeQuery()) {
|
try (ResultSet rs = findByNameImports.executeQuery()) {
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
Entry entry = createEntryFromResultSet(rs);
|
FunctionEntry entry = createEntryFromResultSet(rs);
|
||||||
if (entry != null) {
|
if (entry != null) {
|
||||||
results.add(entry);
|
results.add(entry);
|
||||||
}
|
}
|
||||||
|
@ -276,9 +330,9 @@ public class FunctionDatabase implements AutoCloseable {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper method to find entries by address
|
// Helper method to find entries by address
|
||||||
public List<Entry> findEntriesByAddress(Address address) throws Exception {
|
public List<FunctionEntry> findEntriesByAddress(Address address) throws Exception {
|
||||||
ensureConnection();
|
ensureConnection();
|
||||||
List<Entry> results = new ArrayList<>();
|
List<FunctionEntry> results = new ArrayList<>();
|
||||||
String addressStr = address.toString();
|
String addressStr = address.toString();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -286,7 +340,7 @@ public class FunctionDatabase implements AutoCloseable {
|
||||||
findByAddressFunctions.setString(1, addressStr);
|
findByAddressFunctions.setString(1, addressStr);
|
||||||
try (ResultSet rs = findByAddressFunctions.executeQuery()) {
|
try (ResultSet rs = findByAddressFunctions.executeQuery()) {
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
Entry entry = createEntryFromResultSet(rs);
|
FunctionEntry entry = createEntryFromResultSet(rs);
|
||||||
if (entry != null) {
|
if (entry != null) {
|
||||||
results.add(entry);
|
results.add(entry);
|
||||||
}
|
}
|
||||||
|
@ -297,7 +351,7 @@ public class FunctionDatabase implements AutoCloseable {
|
||||||
findByAddressImports.setString(1, addressStr);
|
findByAddressImports.setString(1, addressStr);
|
||||||
try (ResultSet rs = findByAddressImports.executeQuery()) {
|
try (ResultSet rs = findByAddressImports.executeQuery()) {
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
Entry entry = createEntryFromResultSet(rs);
|
FunctionEntry entry = createEntryFromResultSet(rs);
|
||||||
if (entry != null) {
|
if (entry != null) {
|
||||||
results.add(entry);
|
results.add(entry);
|
||||||
}
|
}
|
||||||
|
@ -312,7 +366,7 @@ public class FunctionDatabase implements AutoCloseable {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper method to add/update entry (insert or replace based on filename)
|
// Helper method to add/update entry (insert or replace based on filename)
|
||||||
public void addEntryAt(Entry entry) throws Exception {
|
public void addEntryAt(FunctionEntry entry) throws Exception {
|
||||||
ensureConnection();
|
ensureConnection();
|
||||||
|
|
||||||
String relativePath = new File(RemanConfig.INSTANCE.outputDir).toPath()
|
String relativePath = new File(RemanConfig.INSTANCE.outputDir).toPath()
|
||||||
|
@ -353,7 +407,7 @@ public class FunctionDatabase implements AutoCloseable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add(Entry entry) throws Exception {
|
public void add(FunctionEntry entry) throws Exception {
|
||||||
// Add entry directly to database
|
// Add entry directly to database
|
||||||
addEntryAt(entry);
|
addEntryAt(entry);
|
||||||
}
|
}
|
||||||
|
@ -369,12 +423,12 @@ public class FunctionDatabase implements AutoCloseable {
|
||||||
boolean madeAnyChanges = false;
|
boolean madeAnyChanges = false;
|
||||||
|
|
||||||
// Load all entries from database
|
// Load all entries from database
|
||||||
List<Entry> entries = loadAllEntries();
|
List<FunctionEntry> 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 (FunctionEntry entry : entries) {
|
||||||
Function function = script.getFunctionAt(entry.address);
|
Function function = script.getFunctionAt(entry.address);
|
||||||
if (function != null) {
|
if (function != null) {
|
||||||
boolean isAuto = entry.type == Type.Auto;
|
boolean isAuto = entry.type == Type.Auto;
|
||||||
|
@ -398,9 +452,9 @@ public class FunctionDatabase implements AutoCloseable {
|
||||||
|
|
||||||
HashSet<Function> functionsToRegenerate = new HashSet<>();
|
HashSet<Function> functionsToRegenerate = new HashSet<>();
|
||||||
|
|
||||||
Iterator<Entry> iterator = entries.iterator();
|
Iterator<FunctionEntry> iterator = entries.iterator();
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
Entry entry = iterator.next();
|
FunctionEntry entry = iterator.next();
|
||||||
Function function = script.getFunctionAt(entry.address);
|
Function function = script.getFunctionAt(entry.address);
|
||||||
|
|
||||||
boolean pendingDelete = false;
|
boolean pendingDelete = false;
|
||||||
|
@ -485,6 +539,142 @@ public class FunctionDatabase implements AutoCloseable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Global-specific methods
|
||||||
|
public List<GlobalEntry> loadAllGlobals() throws Exception {
|
||||||
|
ensureConnection();
|
||||||
|
List<GlobalEntry> globals = new ArrayList<>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
try (ResultSet rs = loadAllGlobals.executeQuery()) {
|
||||||
|
while (rs.next()) {
|
||||||
|
GlobalEntry entry = createGlobalEntryFromResultSet(rs);
|
||||||
|
if (entry != null) {
|
||||||
|
globals.add(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
script.println("Loaded " + globals.size() + " global entries from database");
|
||||||
|
return globals;
|
||||||
|
} catch (SQLException e) {
|
||||||
|
script.println("Error loading globals: " + e.getMessage());
|
||||||
|
throw new Exception("Failed to load globals", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private GlobalEntry createGlobalEntryFromResultSet(ResultSet rs) throws SQLException {
|
||||||
|
String filepath = rs.getString("filepath");
|
||||||
|
String name = rs.getString("name");
|
||||||
|
String addressStr = rs.getString("address");
|
||||||
|
String typeStr = rs.getString("type");
|
||||||
|
|
||||||
|
if (addressStr != null && !addressStr.isEmpty()) {
|
||||||
|
Address address = script.getCurrentProgram().getAddressFactory().getAddress(addressStr);
|
||||||
|
File file = new File(RemanConfig.INSTANCE.outputDir, filepath);
|
||||||
|
|
||||||
|
return new GlobalEntry(address, name, typeStr, file);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<GlobalEntry> findGlobalsByName(String name) throws Exception {
|
||||||
|
ensureConnection();
|
||||||
|
List<GlobalEntry> results = new ArrayList<>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
findByNameGlobals.setString(1, name);
|
||||||
|
try (ResultSet rs = findByNameGlobals.executeQuery()) {
|
||||||
|
while (rs.next()) {
|
||||||
|
GlobalEntry entry = createGlobalEntryFromResultSet(rs);
|
||||||
|
if (entry != null) {
|
||||||
|
results.add(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
} catch (SQLException e) {
|
||||||
|
script.println("Error finding globals by name: " + e.getMessage());
|
||||||
|
throw new Exception("Failed to find globals by name", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<GlobalEntry> findGlobalsByAddress(Address address) throws Exception {
|
||||||
|
ensureConnection();
|
||||||
|
List<GlobalEntry> results = new ArrayList<>();
|
||||||
|
String addressStr = address.toString();
|
||||||
|
|
||||||
|
try {
|
||||||
|
findByAddressGlobals.setString(1, addressStr);
|
||||||
|
try (ResultSet rs = findByAddressGlobals.executeQuery()) {
|
||||||
|
while (rs.next()) {
|
||||||
|
GlobalEntry entry = createGlobalEntryFromResultSet(rs);
|
||||||
|
if (entry != null) {
|
||||||
|
results.add(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
} catch (SQLException e) {
|
||||||
|
script.println("Error finding globals by address: " + e.getMessage());
|
||||||
|
throw new Exception("Failed to find globals by address", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addGlobal(Address address, String name, String dataType) throws Exception {
|
||||||
|
ensureConnection();
|
||||||
|
|
||||||
|
String filepath = "globals.h"; // Default filepath for globals
|
||||||
|
String addressStr = address.toString();
|
||||||
|
|
||||||
|
try {
|
||||||
|
insertOrReplaceGlobals.setString(1, filepath);
|
||||||
|
insertOrReplaceGlobals.setString(2, name);
|
||||||
|
insertOrReplaceGlobals.setString(3, addressStr);
|
||||||
|
insertOrReplaceGlobals.setString(4, dataType);
|
||||||
|
insertOrReplaceGlobals.executeUpdate();
|
||||||
|
|
||||||
|
script.println("Added/updated global: " + name + " at " + address + " with type " + dataType);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
script.println("Error adding global: " + e.getMessage());
|
||||||
|
throw new Exception("Failed to add global", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeGlobalsByFilepath(String filePath) throws Exception {
|
||||||
|
ensureConnection();
|
||||||
|
|
||||||
|
String relativePath;
|
||||||
|
|
||||||
|
// Check if filePath is already a relative path or just a filename
|
||||||
|
File inputFile = new File(filePath);
|
||||||
|
if (inputFile.isAbsolute()) {
|
||||||
|
// Convert absolute path to relative
|
||||||
|
try {
|
||||||
|
relativePath = new File(RemanConfig.INSTANCE.outputDir).toPath()
|
||||||
|
.relativize(inputFile.toPath()).toString().replace('\\', '/');
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
// Fallback if paths can't be relativized (different drives, etc.)
|
||||||
|
script.println("Warning: Could not relativize path: " + filePath + ", using as-is");
|
||||||
|
relativePath = filePath.replace('\\', '/');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Already relative or just a filename, use as-is
|
||||||
|
relativePath = filePath.replace('\\', '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
deleteByFilepathGlobals.setString(1, relativePath);
|
||||||
|
int deletedCount = deleteByFilepathGlobals.executeUpdate();
|
||||||
|
|
||||||
|
script.println("Removed " + deletedCount + " global entries for file: " + relativePath);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
script.println("Error removing global entries: " + e.getMessage());
|
||||||
|
throw new Exception("Failed to remove global entries", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() throws Exception {
|
public void close() throws Exception {
|
||||||
this.disconnect();
|
this.disconnect();
|
||||||
|
|
|
@ -5,7 +5,6 @@ import java.io.PrintWriter;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Hashtable;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
|
@ -23,7 +22,6 @@ import ghidra.program.model.pcode.HighFunction;
|
||||||
import ghidra.program.model.pcode.HighSymbol;
|
import ghidra.program.model.pcode.HighSymbol;
|
||||||
import ghidra.program.model.pcode.PcodeOp;
|
import ghidra.program.model.pcode.PcodeOp;
|
||||||
import ghidra.program.model.pcode.Varnode;
|
import ghidra.program.model.pcode.Varnode;
|
||||||
import re3lib.GlobalDumper.GlobalRec;
|
|
||||||
|
|
||||||
public class FunctionDumper {
|
public class FunctionDumper {
|
||||||
GhidraScript script;
|
GhidraScript script;
|
||||||
|
@ -125,30 +123,49 @@ public class FunctionDumper {
|
||||||
String sanitizedFunctionName = Utils.sanitizeIdentifier(function.getName());
|
String sanitizedFunctionName = Utils.sanitizeIdentifier(function.getName());
|
||||||
String fileName = sanitizedFunctionName + ".cxx";
|
String fileName = sanitizedFunctionName + ".cxx";
|
||||||
|
|
||||||
|
Address entrypoint = function.getEntryPoint();
|
||||||
// Remove the stub file, since we now use the decompiled file
|
List<FunctionDatabase.FunctionEntry> entries = functionDatabase.findEntriesByAddress(entrypoint);
|
||||||
File stubFile = new File(RemanConfig.INSTANCE.dirDecompStub, fileName);
|
FunctionDatabase.Type targetType = FunctionDatabase.Type.Auto;
|
||||||
if (stubFile.exists()) {
|
for (FunctionDatabase.FunctionEntry entry : entries) {
|
||||||
script.println("Removing function stub " + stubFile);
|
script.println("Found existing decompiled entry at " + entry.file + " - " + entry.name);
|
||||||
stubFile.delete();
|
if (targetType != FunctionDatabase.Type.Ref) {
|
||||||
createdFile = true;
|
if (entry.type == FunctionDatabase.Type.Fix) {
|
||||||
}
|
targetType = FunctionDatabase.Type.Ref;
|
||||||
|
}
|
||||||
File f0 = new File(RemanConfig.INSTANCE.dirDecompFix, fileName);
|
}
|
||||||
if (f0.exists()) {
|
if (entry.type == FunctionDatabase.Type.Stub) {
|
||||||
script.println("Func " + function.getName() + " skipped (gh_fix)");
|
// Remove the stub file, since we now use the decompiled file
|
||||||
f0 = new File(RemanConfig.INSTANCE.dirDecompRef, fileName);
|
File stubFile = entry.file;
|
||||||
} else {
|
if (stubFile.exists()) {
|
||||||
f0 = new File(RemanConfig.INSTANCE.dirDecompAuto, fileName);
|
script.println("Removing function stub " + stubFile);
|
||||||
if (f0.exists()) {
|
stubFile.delete();
|
||||||
f0.delete();
|
createdFile = true;
|
||||||
} else {
|
functionDatabase.removeEntryAt(entry.file.toString());
|
||||||
createdFile = true;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File targetFilename = null;
|
||||||
|
if (targetType == FunctionDatabase.Type.Ref) {
|
||||||
|
targetFilename = new File(RemanConfig.INSTANCE.dirDecompRef, fileName);
|
||||||
|
} else {
|
||||||
|
targetFilename = new File(RemanConfig.INSTANCE.dirDecompAuto, fileName);
|
||||||
|
}
|
||||||
|
if (targetFilename.exists()) {
|
||||||
|
targetFilename.delete();
|
||||||
|
script.println("Overwriting existing file " + targetFilename);
|
||||||
|
} else {
|
||||||
|
createdFile = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
File f0 = targetFilename;
|
||||||
script.println("Processing " + function.getName() + " => " + f0.toString());
|
script.println("Processing " + function.getName() + " => " + f0.toString());
|
||||||
|
|
||||||
|
// Update database
|
||||||
|
FunctionDatabase.FunctionEntry newEntry = new FunctionDatabase.FunctionEntry(entrypoint, function.getName(), f0,
|
||||||
|
targetType);
|
||||||
|
functionDatabase.addEntryAt(newEntry);
|
||||||
|
|
||||||
List<Function> externalFunctionCalls = new ArrayList<>();
|
List<Function> externalFunctionCalls = new ArrayList<>();
|
||||||
|
|
||||||
DecompileResults decompRes = RemanConfig.INSTANCE.decompCache.getOrInsert(function);
|
DecompileResults decompRes = RemanConfig.INSTANCE.decompCache.getOrInsert(function);
|
||||||
|
@ -293,15 +310,20 @@ public class FunctionDumper {
|
||||||
// Possibly generate stubs for external functions
|
// Possibly generate stubs for external functions
|
||||||
for (Function externalFunction : externalFunctionCalls) {
|
for (Function externalFunction : externalFunctionCalls) {
|
||||||
String sanitizedExtFunctionName = Utils.sanitizeIdentifier(externalFunction.getName());
|
String sanitizedExtFunctionName = Utils.sanitizeIdentifier(externalFunction.getName());
|
||||||
fileName = sanitizedExtFunctionName + ".cxx";
|
|
||||||
File f2 = new File(RemanConfig.INSTANCE.dirDecompFix, fileName);
|
|
||||||
File f3 = new File(RemanConfig.INSTANCE.dirDecompAuto, fileName);
|
|
||||||
if (f2.exists() || f3.exists()) {
|
|
||||||
// script.println("Skipping external function: " + externalFunction.getName() +
|
|
||||||
// " - " + externalFunction.getEntryPoint());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
List<FunctionDatabase.FunctionEntry> entries1 = functionDatabase
|
||||||
|
.findEntriesByAddress(externalFunction.getEntryPoint());
|
||||||
|
boolean needStub = true;
|
||||||
|
for (FunctionDatabase.FunctionEntry entry : entries1) {
|
||||||
|
if (entry.type == FunctionDatabase.Type.Auto || entry.type == FunctionDatabase.Type.Fix) {
|
||||||
|
needStub = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!needStub)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
fileName = sanitizedExtFunctionName + ".cxx";
|
||||||
File f4 = new File(RemanConfig.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());
|
||||||
|
|
||||||
|
|
|
@ -47,91 +47,58 @@ public class GlobalDumper {
|
||||||
};
|
};
|
||||||
|
|
||||||
GhidraScript script;
|
GhidraScript script;
|
||||||
File manifestFile;
|
|
||||||
FunctionDatabase functionDatabase;
|
FunctionDatabase functionDatabase;
|
||||||
HashMap<Address, GlobalRec> globalAddrs = new HashMap<>();
|
HashMap<Address, GlobalRec> globalAddrs = new HashMap<>();
|
||||||
|
|
||||||
public GlobalDumper(GhidraScript script, FunctionDatabase functionDatabase) {
|
public GlobalDumper(GhidraScript script, FunctionDatabase functionDatabase) {
|
||||||
this.script = script;
|
this.script = script;
|
||||||
this.functionDatabase = functionDatabase;
|
this.functionDatabase = functionDatabase;
|
||||||
manifestFile = new File(RemanConfig.INSTANCE.outputDir, "globals.txt");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeGlobalManifest() {
|
public void removeGlobalManifest() {
|
||||||
if (manifestFile.exists()) {
|
// Remove globals from database instead of file
|
||||||
manifestFile.delete();
|
try {
|
||||||
|
functionDatabase.removeGlobalsByFilepath("globals.h");
|
||||||
|
globalAddrs.clear();
|
||||||
|
} catch (Exception e) {
|
||||||
|
script.println("Error removing global manifest: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean loadGlobalManifest() throws Exception {
|
public boolean loadGlobalManifest() throws Exception {
|
||||||
// Globals are stored in the format of
|
globalAddrs.clear();
|
||||||
// <address> || <name> || <type>
|
|
||||||
|
// Load globals from database
|
||||||
if (!manifestFile.exists()) {
|
List<FunctionDatabase.GlobalEntry> dbGlobals = functionDatabase.loadAllGlobals();
|
||||||
script.println("Global manifest file not found: " + manifestFile);
|
|
||||||
return false;
|
// Get the dataTypeManagerService for parsing types
|
||||||
}
|
|
||||||
|
|
||||||
// Get the dataTypeManagerService
|
|
||||||
DataTypeManagerService dataTypeManagerService = (DataTypeManagerService) script.getState().getTool()
|
DataTypeManagerService dataTypeManagerService = (DataTypeManagerService) script.getState().getTool()
|
||||||
.getService(DataTypeManagerService.class);
|
.getService(DataTypeManagerService.class);
|
||||||
DataTypeManager dtm = script.getCurrentProgram().getDataTypeManager();
|
DataTypeManager dtm = script.getCurrentProgram().getDataTypeManager();
|
||||||
DataTypeParser dtp = new DataTypeParser(dataTypeManagerService, AllowedDataTypes.ALL);
|
DataTypeParser dtp = new DataTypeParser(dataTypeManagerService, AllowedDataTypes.ALL);
|
||||||
try (BufferedReader reader = new BufferedReader(new FileReader(manifestFile))) {
|
|
||||||
String line;
|
for (FunctionDatabase.GlobalEntry entry : dbGlobals) {
|
||||||
while ((line = reader.readLine()) != null) {
|
// Note: The database stores type as string, need to reconstruct DataType
|
||||||
String[] parts = line.split("\\|\\|");
|
// For now, we'll parse it back from the type string stored in database
|
||||||
if (parts.length == 4) {
|
// This is a limitation of moving from the manifest format
|
||||||
Address address = script.parseAddress(parts[0].trim());
|
DataType type = null;
|
||||||
String name = parts[1].trim();
|
|
||||||
String categoryPath = parts[2].trim();
|
// Try to get from existing data at address
|
||||||
String dataTypePath = parts[3].trim();
|
Data data = script.getDataAt(entry.address);
|
||||||
DataTypePath typePath = new DataTypePath(categoryPath, dataTypePath);
|
|
||||||
DataType type = null;
|
|
||||||
type = dtm.getDataType(typePath);
|
|
||||||
if (type == null) {
|
|
||||||
// script.println("Parsing type: " + dataTypePath);
|
|
||||||
type = dtp.parse(dataTypePath);
|
|
||||||
}
|
|
||||||
if (type == null) {
|
|
||||||
script.println("WARNING: Failed to find type: " + dataTypePath + " for global: " + name + " at " + address);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
globalAddrs.put(address, new GlobalRec(address, name, type));
|
|
||||||
} else {
|
|
||||||
script.println("Invalid global manifest line: " + line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
script.println("Loaded " + globalAddrs.size() + " globals from " + manifestFile);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addGlobal(Address addr, HighSymbol sym) throws Exception {
|
|
||||||
if (addr.compareTo(RemanConfig.INSTANCE.staticMemoryBlockStart) < 0
|
|
||||||
|| addr.compareTo(RemanConfig.INSTANCE.staticMemoryBlockEnd) > 0) {
|
|
||||||
throw new Exception("Global address out of range: " + addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
DataType dt = sym.getDataType();
|
|
||||||
// if(symb.get
|
|
||||||
if (sym.getDataType().getName() == "undefined") {
|
|
||||||
// script.println("UNDEFINED: " + addr + " - " + dt.getDisplayName() + " - " +
|
|
||||||
// dt.getClass().getName());
|
|
||||||
Data data = script.getDataAt(addr);
|
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
dt = data.getDataType();
|
type = data.getDataType();
|
||||||
// script.println("DATA: " + addr + " - " + dt.getDisplayName());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type == null) {
|
||||||
|
script.println("WARNING: Could not reconstruct type for global: " + entry.name + " at " + entry.address);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
globalAddrs.put(entry.address, new GlobalRec(entry.address, entry.name, type));
|
||||||
}
|
}
|
||||||
if (dt == null) {
|
|
||||||
script.println("WARNING: Missing type for global: " + sym.getName() + " at " + addr);
|
script.println("Loaded " + globalAddrs.size() + " globals from database");
|
||||||
return;
|
return !globalAddrs.isEmpty();
|
||||||
}
|
|
||||||
// script.println("Global: " + addr + " - " + sym.getName() + " - " +
|
|
||||||
// dt.getDisplayName());
|
|
||||||
globalAddrs.put(addr, new GlobalRec(addr, sym.getName(), dt));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String escapeCString(String str) {
|
String escapeCString(String str) {
|
||||||
|
@ -245,28 +212,43 @@ public class GlobalDumper {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void saveGlobalManifest() throws Exception {
|
public void saveGlobalManifest() throws Exception {
|
||||||
File backupFile = new File(manifestFile.getParentFile(), manifestFile.getName() + ".bak");
|
// Save globals to database instead of file
|
||||||
if (backupFile.exists()) {
|
script.println("Saving globals to database");
|
||||||
if (!backupFile.delete()) {
|
|
||||||
throw new Exception("Failed to delete backup file: " + backupFile + ", globals will not be saved!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (manifestFile.exists()) {
|
// Clear existing globals for the default filepath
|
||||||
if (!manifestFile.renameTo(backupFile))
|
functionDatabase.removeGlobalsByFilepath("globals.h");
|
||||||
throw new Exception("Failed to rename manifest file: " + manifestFile + ", globals will not be saved!");
|
|
||||||
|
// Add all current globals to database
|
||||||
|
for (GlobalRec global : globalAddrs.values()) {
|
||||||
|
String dataTypeName = global.type.getDisplayName();
|
||||||
|
functionDatabase.addGlobal(global.address, global.name, dataTypeName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addGlobal(Address addr, HighSymbol sym) throws Exception {
|
||||||
|
if (addr.compareTo(RemanConfig.INSTANCE.staticMemoryBlockStart) < 0
|
||||||
|
|| addr.compareTo(RemanConfig.INSTANCE.staticMemoryBlockEnd) > 0) {
|
||||||
|
throw new Exception("Global address out of range: " + addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
try (PrintWriter writer = new PrintWriter(manifestFile)) {
|
DataType dt = sym.getDataType();
|
||||||
script.println("Saving global manifest to " + manifestFile);
|
// if(symb.get
|
||||||
GlobalRec[] globals = globalAddrs.values().toArray(new GlobalRec[0]);
|
if (sym.getDataType().getName() == "undefined") {
|
||||||
Arrays.sort(globals, (a, b) -> a.address.compareTo(b.address));
|
// script.println("UNDEFINED: " + addr + " - " + dt.getDisplayName() + " - " +
|
||||||
for (GlobalRec global : globals) {
|
// dt.getClass().getName());
|
||||||
DataTypePath path = global.type.getDataTypePath();
|
Data data = script.getDataAt(addr);
|
||||||
writer.println(global.address.toString() + " || " + global.name + " || " + path.getCategoryPath() + " || "
|
if (data != null) {
|
||||||
+ path.getDataTypeName());
|
dt = data.getDataType();
|
||||||
|
// script.println("DATA: " + addr + " - " + dt.getDisplayName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (dt == null) {
|
||||||
|
script.println("WARNING: Missing type for global: " + sym.getName() + " at " + addr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// script.println("Global: " + addr + " - " + sym.getName() + " - " +
|
||||||
|
// dt.getDisplayName());
|
||||||
|
globalAddrs.put(addr, new GlobalRec(addr, sym.getName(), dt));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sanitizeGlobalSymbols() {
|
public void sanitizeGlobalSymbols() {
|
||||||
|
@ -288,3 +270,4 @@ public class GlobalDumper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue