mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
Merge remote-tracking branch 'origin/GP-1082_ghidravore_improving_symbol_table_performance'
This commit is contained in:
commit
156ce7ef80
32 changed files with 1938 additions and 821 deletions
|
@ -526,7 +526,7 @@ class SymbolMerger extends AbstractListingMerger {
|
|||
renamed = true;
|
||||
}
|
||||
// boolean commentChanged =
|
||||
// !SystemUtilities.isEqual(newSym.getSymbolData3(), oldSym.getSymbolData3());
|
||||
// !SystemUtilities.isEqual(newSym.getSymbolStringData(), oldSym.getSymbolStringData());
|
||||
boolean sourceChanged = newSym.getSource() != oldSym.getSource();
|
||||
// if (commentChanged) {
|
||||
// commentChanges.add(id);
|
||||
|
@ -920,12 +920,12 @@ class SymbolMerger extends AbstractListingMerger {
|
|||
// if (commentChangedInMy) {
|
||||
// if (!commentChangedInLatest) {
|
||||
// if (resultSym != null) {
|
||||
// resultSym.setSymbolData3(mySym.getSymbolData3());
|
||||
// resultSym.setSymbolStringData(mySym.getSymbolStringData());
|
||||
// }
|
||||
// }
|
||||
// else {
|
||||
// Symbol latestSym = latestSymTab.getSymbol(id);
|
||||
// if (!SystemUtilities.isEqual(latestSym.getSymbolData3(), mySym.getSymbolData3())) {
|
||||
// if (!SystemUtilities.isEqual(latestSym.getSymbolStringData(), mySym.getSymbolStringData())) {
|
||||
// saveCommentConflict(id);
|
||||
// }
|
||||
// }
|
||||
|
@ -1008,11 +1008,11 @@ class SymbolMerger extends AbstractListingMerger {
|
|||
// if (commentChangedInMy) {
|
||||
// if (!commentChangedInLatest) {
|
||||
// // Use My version's comment since Latest didn't change it.
|
||||
// resultSym.setSymbolData3(mySym.getSymbolData3());
|
||||
// resultSym.setSymbolStringData(mySym.getSymbolStringData());
|
||||
// }
|
||||
// else {
|
||||
// Symbol latestSym = latestSymTab.getSymbol(id);
|
||||
// if (!SystemUtilities.isEqual(latestSym.getSymbolData3(), mySym.getSymbolData3())) {
|
||||
// if (!SystemUtilities.isEqual(latestSym.getSymbolStringData(), mySym.getSymbolStringData())) {
|
||||
// saveFunctionCommentConflict(id); // My & Latest changed comment differently.
|
||||
// }
|
||||
// }
|
||||
|
@ -1181,11 +1181,11 @@ class SymbolMerger extends AbstractListingMerger {
|
|||
// Handle Symbol comments.
|
||||
// if (commentChangedInMy) {
|
||||
// if (!commentChangedInLatest) {
|
||||
// resultSym.setSymbolData3(mySym.getSymbolData3()); // Use My version's comment since Latest didn't change it.
|
||||
// resultSym.setSymbolStringData(mySym.getSymbolStringData()); // Use My version's comment since Latest didn't change it.
|
||||
// }
|
||||
// else {
|
||||
// Symbol latestSym = latestSymTab.getSymbol(id);
|
||||
// if (!SystemUtilities.isEqual(latestSym.getSymbolData3(), mySym.getSymbolData3())) {
|
||||
// if (!SystemUtilities.isEqual(latestSym.getSymbolStringData(), mySym.getSymbolStringData())) {
|
||||
// saveAddFunctionCommentConflict(id); // My & Latest changed comment differently.
|
||||
// }
|
||||
// }
|
||||
|
@ -1372,8 +1372,8 @@ class SymbolMerger extends AbstractListingMerger {
|
|||
|
||||
// private void processAddedSymbolComment(Symbol resultSym, Symbol mySym) {
|
||||
// // My version added a symbol that matches on in the result version.
|
||||
// String resultComment = resultSym.getSymbolData3();
|
||||
// String myComment = mySym.getSymbolData3();
|
||||
// String resultComment = resultSym.getSymbolStringData();
|
||||
// String myComment = mySym.getSymbolStringData();
|
||||
// if (SystemUtilities.isEqual(resultComment, myComment)) {
|
||||
// return; // Already has My symbol comment.
|
||||
// }
|
||||
|
@ -1381,7 +1381,7 @@ class SymbolMerger extends AbstractListingMerger {
|
|||
// return; // My version isn't setting a symbol comment.
|
||||
// }
|
||||
// if (resultComment == null) {
|
||||
// resultSym.setSymbolData3(myComment); // Latest didn't set a comment, but My did so use My symbol comment.
|
||||
// resultSym.setSymbolStringData(myComment); // Latest didn't set a comment, but My did so use My symbol comment.
|
||||
// }
|
||||
// else if (!myComment.equals(resultComment)) {
|
||||
// saveAddCommentConflict(mySym.getID()); // Both set a different symbol comment, so conflict
|
||||
|
@ -1711,7 +1711,7 @@ class SymbolMerger extends AbstractListingMerger {
|
|||
// currentAddress = addr;
|
||||
// currentSymbol = mySym;
|
||||
// Symbol resultSym = getResultSymbolFromMySymbol(mySym);
|
||||
// currentSymbolComment = (resultSym != null) ? resultSym.getSymbolData3() : "";
|
||||
// currentSymbolComment = (resultSym != null) ? resultSym.getSymbolStringData() : "";
|
||||
// currentBackgroundSet = new AddressSet(resultAddressFactory, addr, addr);
|
||||
// if (askUser && mergeManager != null) {
|
||||
// boolean useForAll = (symbolAddCommentChoice != ASK_USER);
|
||||
|
@ -1912,10 +1912,10 @@ class SymbolMerger extends AbstractListingMerger {
|
|||
// return;
|
||||
// }
|
||||
// if ((chosenConflictOption & KEEP_LATEST) != 0) {
|
||||
// result.setSymbolData3(latest.getSymbolData3());
|
||||
// result.setSymbolStringData(latest.getSymbolStringData());
|
||||
// }
|
||||
// else if ((chosenConflictOption & KEEP_MY) != 0) {
|
||||
// result.setSymbolData3(my.getSymbolData3());
|
||||
// result.setSymbolStringData(my.getSymbolStringData());
|
||||
// }
|
||||
// }
|
||||
|
||||
|
@ -1933,10 +1933,10 @@ class SymbolMerger extends AbstractListingMerger {
|
|||
// return;
|
||||
// }
|
||||
// if ((chosenConflictOption & KEEP_RESULT) != 0) {
|
||||
// result.setSymbolData3(currentSymbolComment);
|
||||
// result.setSymbolStringData(currentSymbolComment);
|
||||
// }
|
||||
// else if ((chosenConflictOption & KEEP_MY) != 0) {
|
||||
// result.setSymbolData3(my.getSymbolData3());
|
||||
// result.setSymbolStringData(my.getSymbolStringData());
|
||||
// }
|
||||
// }
|
||||
|
||||
|
@ -2253,7 +2253,7 @@ class SymbolMerger extends AbstractListingMerger {
|
|||
Symbol newSymbol)
|
||||
throws DuplicateNameException, InvalidInputException, CircularDependencyException {
|
||||
renameSymbol(oldProgram, oldSymbol, newProgram, newSymbol);
|
||||
// oldSymbol.setSymbolData3(newSymbol.getSymbolData3());
|
||||
// oldSymbol.setSymbolStringData(newSymbol.getSymbolStringData());
|
||||
// Handle primary.
|
||||
if (newSymbol.isPrimary() && !oldSymbol.isPrimary()) {
|
||||
oldSymbol.setPrimary();
|
||||
|
@ -2446,7 +2446,7 @@ class SymbolMerger extends AbstractListingMerger {
|
|||
private Symbol createSymbol(String name, SymbolType type, Address resultAddr,
|
||||
Namespace resultParentNs, Program srcPgm, long srcSymID, SourceType source)
|
||||
throws DuplicateNameException, InvalidInputException {
|
||||
// String comment = srcSymbol.getSymbolData3();
|
||||
// String comment = srcSymbol.getSymbolStringData();
|
||||
Symbol symbol = null;
|
||||
if (type == SymbolType.LABEL) {
|
||||
symbol = resultSymTab.createLabel(resultAddr, name, resultParentNs, source);
|
||||
|
@ -2468,7 +2468,7 @@ class SymbolMerger extends AbstractListingMerger {
|
|||
symbol = resultSymTab.getLibrarySymbol(name);
|
||||
}
|
||||
if (symbol != null) {
|
||||
// symbol.setSymbolData3(comment);
|
||||
// symbol.setSymbolStringData(comment);
|
||||
if (symbol.getParentNamespace().equals(resultParentNs)) {
|
||||
long resolveSymID = symbol.getID();
|
||||
updateResolveIDs(srcPgm, srcSymID, resolveSymID);
|
||||
|
@ -2864,7 +2864,7 @@ class SymbolMerger extends AbstractListingMerger {
|
|||
// info[1] = s.getName(false);
|
||||
// info[2] = s.getParentNamespace().getSymbol().getName();
|
||||
// info[3] = s.getSymbolType().toString();
|
||||
// info[4] = ConflictUtility.getTruncatedHTMLString(s.getSymbolData3(), TRUNCATE_LENGTH);
|
||||
// info[4] = ConflictUtility.getTruncatedHTMLString(s.getSymbolStringData(), TRUNCATE_LENGTH);
|
||||
// return info;
|
||||
// }
|
||||
|
||||
|
|
|
@ -391,8 +391,8 @@ class SymbolMerge {
|
|||
if (replace && toSymbol.isPinned() != pinned) {
|
||||
toSymbol.setPinned(pinned);
|
||||
}
|
||||
// String fromComment = fromSymbol.getSymbolData3();
|
||||
// String toComment = toSymbol.getSymbolData3();
|
||||
// String fromComment = fromSymbol.getSymbolStringData();
|
||||
// String toComment = toSymbol.getSymbolStringData();
|
||||
// if (!SystemUtilities.isEqual(fromComment, toComment)) {
|
||||
// String newComment;
|
||||
// if (replace) {
|
||||
|
@ -401,7 +401,7 @@ class SymbolMerge {
|
|||
// else {
|
||||
// newComment = StringUtilities.mergeStrings(fromComment, toComment);
|
||||
// }
|
||||
// toSymbol.setSymbolData3(newComment);
|
||||
// toSymbol.setSymbolStringData(newComment);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
@ -551,7 +551,8 @@ class SymbolMerge {
|
|||
boolean fromDefault = fromSymbol.getSource() == SourceType.DEFAULT;
|
||||
boolean isFromDefaultThunk = FunctionMerge.isDefaultThunk(fromFunc);
|
||||
Namespace fromNamespace = // default thunks will lie about their namespace
|
||||
isFromDefaultThunk ? fromProgram.getGlobalNamespace() : fromSymbol.getParentNamespace();
|
||||
isFromDefaultThunk ? fromProgram.getGlobalNamespace()
|
||||
: fromSymbol.getParentNamespace();
|
||||
|
||||
Namespace resolveNamespace = resolveNamespace(fromNamespace, conflictSymbolIDMap);
|
||||
if ((toFunc != null) && replacePrimary && !fromDefault) {
|
||||
|
|
|
@ -81,7 +81,8 @@ public class SymbolMergeManagerSourceTest extends AbstractListingMergeManagerTes
|
|||
int txId = program.startTransaction("Modify My Program");
|
||||
boolean commit = false;
|
||||
try {
|
||||
program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Lucy", null,
|
||||
program.getSymbolTable()
|
||||
.createLabel(addr(program, "0x10032a7"), "Lucy", null,
|
||||
SourceType.USER_DEFINED);
|
||||
commit = true;
|
||||
}
|
||||
|
@ -101,7 +102,8 @@ public class SymbolMergeManagerSourceTest extends AbstractListingMergeManagerTes
|
|||
int txId = program.startTransaction("Modify My Program");
|
||||
boolean commit = false;
|
||||
try {
|
||||
program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Lucy", null,
|
||||
program.getSymbolTable()
|
||||
.createLabel(addr(program, "0x10032a7"), "Lucy", null,
|
||||
SourceType.USER_DEFINED);
|
||||
commit = true;
|
||||
}
|
||||
|
@ -141,11 +143,11 @@ public class SymbolMergeManagerSourceTest extends AbstractListingMergeManagerTes
|
|||
// try {
|
||||
// Symbol s = program.getSymbolTable().createSymbol(addr(program, "0x10032a7"),
|
||||
// "Lucy", null, SourceType.USER_DEFINED);
|
||||
// s.setSymbolData3("This is a symbol comment.");
|
||||
// s.setSymbolStringData("This is a symbol comment.");
|
||||
//
|
||||
// s = program.getSymbolTable().createSymbol(addr(program, "0x1004bf4"),
|
||||
// "red", null, SourceType.IMPORTED);
|
||||
// s.setSymbolData3(longComment1);
|
||||
// s.setSymbolStringData(longComment1);
|
||||
// commit = true;
|
||||
// } catch (Exception e) {
|
||||
// Assert.fail(e.getMessage());
|
||||
|
@ -163,11 +165,11 @@ public class SymbolMergeManagerSourceTest extends AbstractListingMergeManagerTes
|
|||
// try {
|
||||
// Symbol s = program.getSymbolTable().createSymbol(addr(program, "0x10032a7"), "Lucy", null,
|
||||
// SourceType.USER_DEFINED);
|
||||
// s.setSymbolData3("This is a symbol comment.");
|
||||
// s.setSymbolStringData("This is a symbol comment.");
|
||||
//
|
||||
// s = program.getSymbolTable().createSymbol(addr(program, "0x1004bf4"),
|
||||
// "red", null, SourceType.IMPORTED);
|
||||
// s.setSymbolData3(longComment1);
|
||||
// s.setSymbolStringData(longComment1);
|
||||
// commit = true;
|
||||
// } catch (Exception e) {
|
||||
// Assert.fail(e.getMessage());
|
||||
|
@ -186,13 +188,13 @@ public class SymbolMergeManagerSourceTest extends AbstractListingMergeManagerTes
|
|||
// checkSymbol(s, "Lucy", true);
|
||||
// assertTrue(s.isPrimary());
|
||||
// assertEquals(SourceType.USER_DEFINED, s.getSource());
|
||||
// assertEquals("This is a symbol comment.", s.getSymbolData3());
|
||||
// assertEquals("This is a symbol comment.", s.getSymbolStringData());
|
||||
//
|
||||
// s = symtab.getPrimarySymbol(addr("0x1004bf4"));
|
||||
// checkSymbol(s, "red", true);
|
||||
// assertTrue(s.isPrimary());
|
||||
// assertEquals(SourceType.IMPORTED, s.getSource());
|
||||
// assertEquals(longComment1, s.getSymbolData3());
|
||||
// assertEquals(longComment1, s.getSymbolStringData());
|
||||
// }
|
||||
|
||||
/** Test add of same symbol and source to both Latest and My, but different symbol comments. */
|
||||
|
@ -351,11 +353,14 @@ public class SymbolMergeManagerSourceTest extends AbstractListingMergeManagerTes
|
|||
int txId = program.startTransaction("Modify My Program");
|
||||
boolean commit = false;
|
||||
try {
|
||||
program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Charlie",
|
||||
program.getSymbolTable()
|
||||
.createLabel(addr(program, "0x10032a7"), "Charlie",
|
||||
null, SourceType.ANALYSIS);
|
||||
program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Lucy", null,
|
||||
program.getSymbolTable()
|
||||
.createLabel(addr(program, "0x10032a7"), "Lucy", null,
|
||||
SourceType.IMPORTED);
|
||||
program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Linus", null,
|
||||
program.getSymbolTable()
|
||||
.createLabel(addr(program, "0x10032a7"), "Linus", null,
|
||||
SourceType.USER_DEFINED);
|
||||
commit = true;
|
||||
}
|
||||
|
@ -375,11 +380,14 @@ public class SymbolMergeManagerSourceTest extends AbstractListingMergeManagerTes
|
|||
int txId = program.startTransaction("Modify My Program");
|
||||
boolean commit = false;
|
||||
try {
|
||||
program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Charlie",
|
||||
program.getSymbolTable()
|
||||
.createLabel(addr(program, "0x10032a7"), "Charlie",
|
||||
null, SourceType.USER_DEFINED);
|
||||
program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Lucy", null,
|
||||
program.getSymbolTable()
|
||||
.createLabel(addr(program, "0x10032a7"), "Lucy", null,
|
||||
SourceType.ANALYSIS);
|
||||
program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Linus", null,
|
||||
program.getSymbolTable()
|
||||
.createLabel(addr(program, "0x10032a7"), "Linus", null,
|
||||
SourceType.IMPORTED);
|
||||
commit = true;
|
||||
}
|
||||
|
@ -426,11 +434,14 @@ public class SymbolMergeManagerSourceTest extends AbstractListingMergeManagerTes
|
|||
int txId = program.startTransaction("Modify My Program");
|
||||
boolean commit = false;
|
||||
try {
|
||||
program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Lucy", null,
|
||||
program.getSymbolTable()
|
||||
.createLabel(addr(program, "0x10032a7"), "Lucy", null,
|
||||
SourceType.IMPORTED);
|
||||
program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Linus", null,
|
||||
program.getSymbolTable()
|
||||
.createLabel(addr(program, "0x10032a7"), "Linus", null,
|
||||
SourceType.ANALYSIS);
|
||||
program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Sally", null,
|
||||
program.getSymbolTable()
|
||||
.createLabel(addr(program, "0x10032a7"), "Sally", null,
|
||||
SourceType.USER_DEFINED);
|
||||
commit = true;
|
||||
}
|
||||
|
@ -493,11 +504,14 @@ public class SymbolMergeManagerSourceTest extends AbstractListingMergeManagerTes
|
|||
int txId = program.startTransaction("Modify My Program");
|
||||
boolean commit = false;
|
||||
try {
|
||||
program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Charlie",
|
||||
program.getSymbolTable()
|
||||
.createLabel(addr(program, "0x10032a7"), "Charlie",
|
||||
null, SourceType.USER_DEFINED);
|
||||
program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Lucy", null,
|
||||
program.getSymbolTable()
|
||||
.createLabel(addr(program, "0x10032a7"), "Lucy", null,
|
||||
SourceType.ANALYSIS);
|
||||
program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Linus", null,
|
||||
program.getSymbolTable()
|
||||
.createLabel(addr(program, "0x10032a7"), "Linus", null,
|
||||
SourceType.IMPORTED);
|
||||
commit = true;
|
||||
}
|
||||
|
|
|
@ -32,7 +32,6 @@ import ghidra.program.model.lang.PrototypeModel;
|
|||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
import ghidra.util.task.TaskMonitorAdapter;
|
||||
|
||||
|
@ -53,7 +52,8 @@ public class FunctionManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
space = program.getAddressFactory().getDefaultAddressSpace();
|
||||
functionManager = program.getFunctionManager();
|
||||
transactionID = program.startTransaction("Test");
|
||||
program.getMemory().createInitializedBlock("temp", addr(0), 10000, (byte) 0,
|
||||
program.getMemory()
|
||||
.createInitializedBlock("temp", addr(0), 10000, (byte) 0,
|
||||
TaskMonitorAdapter.DUMMY_MONITOR, false);
|
||||
}
|
||||
|
||||
|
@ -71,7 +71,7 @@ public class FunctionManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
}
|
||||
|
||||
private Function createFunction(String name, Address entryPt, AddressSetView body)
|
||||
throws DuplicateNameException, InvalidInputException, OverlappingFunctionException {
|
||||
throws InvalidInputException, OverlappingFunctionException {
|
||||
|
||||
functionManager.createFunction(name, entryPt, body, SourceType.USER_DEFINED);
|
||||
Function f = functionManager.getFunctionAt(entryPt);
|
||||
|
@ -209,8 +209,10 @@ public class FunctionManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
f = functionManager.getFunctionAt(addr(250));
|
||||
assertEquals(new AddressSet(addr(250), addr(350)), f.getBody());
|
||||
|
||||
assertTrue(program.getSymbolTable().getPrimarySymbol(
|
||||
addr(201)).getSymbolType() != SymbolType.FUNCTION);
|
||||
assertTrue(program.getSymbolTable()
|
||||
.getPrimarySymbol(
|
||||
addr(201))
|
||||
.getSymbolType() != SymbolType.FUNCTION);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -301,14 +303,17 @@ public class FunctionManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
createFunction("foo1", addr(250), new AddressSet(addr(250), addr(350)));
|
||||
Function foo2 = createFunction("foo2", addr(201), new AddressSet(addr(201), addr(249)));
|
||||
|
||||
Function fum = program.getExternalManager().addExtLocation("lib", "fum", null,
|
||||
SourceType.USER_DEFINED).createFunction();
|
||||
Function fum = program.getExternalManager()
|
||||
.addExtLocation("lib", "fum", null,
|
||||
SourceType.USER_DEFINED)
|
||||
.createFunction();
|
||||
|
||||
program.getMemory().setInt(addr(50), 201);
|
||||
program.getListing().createData(addr(50), PointerDataType.dataType);
|
||||
assertEquals(foo2, program.getFunctionManager().getReferencedFunction(addr(50)));
|
||||
|
||||
program.getReferenceManager().addExternalReference(addr(50), 0,
|
||||
program.getReferenceManager()
|
||||
.addExternalReference(addr(50), 0,
|
||||
program.getExternalManager().getExternalLocation(fum.getSymbol()),
|
||||
SourceType.USER_DEFINED, RefType.DATA);
|
||||
|
||||
|
|
|
@ -27,9 +27,9 @@ import ghidra.app.cmd.function.CreateFunctionCmd;
|
|||
import ghidra.program.database.ProgramBuilder;
|
||||
import ghidra.program.database.ProgramDB;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.ByteDataType;
|
||||
import ghidra.program.model.data.WordDataType;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.listing.Function.FunctionUpdateType;
|
||||
import ghidra.program.model.mem.Memory;
|
||||
import ghidra.program.model.mem.MemoryBlock;
|
||||
import ghidra.program.model.symbol.*;
|
||||
|
@ -52,6 +52,7 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
private NamespaceManager scopeMgr;
|
||||
private int transactionID;
|
||||
private Namespace globalScope;
|
||||
private Listing listing;
|
||||
|
||||
public SymbolManagerTest() {
|
||||
super();
|
||||
|
@ -69,6 +70,7 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
st = program.getSymbolTable();
|
||||
refMgr = program.getReferenceManager();
|
||||
scopeMgr = program.getNamespaceManager();
|
||||
listing = program.getListing();
|
||||
}
|
||||
|
||||
@After
|
||||
|
@ -224,26 +226,26 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
Symbol[] s = st.getSymbols(addr(256));
|
||||
assertEquals(1, s.length);
|
||||
assertEquals("LAB_00000100", s[0].getName());
|
||||
program.getListing().createData(addr(256), new ByteDataType());
|
||||
listing.createData(addr(256), new ByteDataType());
|
||||
assertEquals("BYTE_00000100", s[0].getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDynamicNameChangesWhenDataCleared() throws Exception {
|
||||
refMgr.addMemoryReference(addr(512), addr(256), RefType.FLOW, SourceType.USER_DEFINED, -1);
|
||||
program.getListing().createData(addr(256), new ByteDataType());
|
||||
listing.createData(addr(256), new ByteDataType());
|
||||
Symbol[] s = st.getSymbols(addr(256));
|
||||
assertEquals(1, s.length);
|
||||
assertEquals("BYTE_00000100", s[0].getName());
|
||||
|
||||
program.getListing().clearCodeUnits(addr(256), addr(256), false);
|
||||
listing.clearCodeUnits(addr(256), addr(256), false);
|
||||
assertEquals("LAB_00000100", s[0].getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDynamicOffcutNameChangesWhenSymbolCreated() throws Exception {
|
||||
refMgr.addMemoryReference(addr(512), addr(257), RefType.FLOW, SourceType.USER_DEFINED, -1);
|
||||
program.getListing().createData(addr(256), new WordDataType());
|
||||
listing.createData(addr(256), new WordDataType());
|
||||
|
||||
Symbol[] s = st.getSymbols(addr(257));
|
||||
assertEquals(1, s.length);
|
||||
|
@ -255,7 +257,7 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
@Test
|
||||
public void testDynamicOffcutNameChangesWhenSymbolRenamed() throws Exception {
|
||||
refMgr.addMemoryReference(addr(512), addr(257), RefType.FLOW, SourceType.USER_DEFINED, -1);
|
||||
program.getListing().createData(addr(256), new WordDataType());
|
||||
listing.createData(addr(256), new WordDataType());
|
||||
Symbol label = st.createLabel(addr(256), "bob", SourceType.USER_DEFINED);
|
||||
|
||||
Symbol[] s = st.getSymbols(addr(257));
|
||||
|
@ -268,7 +270,7 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
@Test
|
||||
public void testDynamicOffcutNameChangesWhenSymbolRemoved() throws Exception {
|
||||
refMgr.addMemoryReference(addr(512), addr(257), RefType.FLOW, SourceType.USER_DEFINED, -1);
|
||||
program.getListing().createData(addr(256), new WordDataType());
|
||||
listing.createData(addr(256), new WordDataType());
|
||||
Symbol label = st.createLabel(addr(256), "bob", SourceType.USER_DEFINED);
|
||||
|
||||
Symbol[] s = st.getSymbols(addr(257));
|
||||
|
@ -277,6 +279,7 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
label.delete();
|
||||
assertEquals("WORD_00000100+1", s[0].getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDynamicNameChangesWhenOffcutByInstruction() throws Exception {
|
||||
refMgr.addMemoryReference(addr(512), addr(257), RefType.FLOW, SourceType.USER_DEFINED, -1);
|
||||
|
@ -285,7 +288,7 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
assertEquals(1, s.length);
|
||||
assertEquals("LAB_00000101", s[0].getName());
|
||||
createInstruction(addr(256));
|
||||
CodeUnit codeUnitAt = program.getListing().getCodeUnitAt(addr(256));
|
||||
CodeUnit codeUnitAt = listing.getCodeUnitAt(addr(256));
|
||||
assertTrue(codeUnitAt instanceof Instruction);
|
||||
assertEquals(2, codeUnitAt.getLength());
|
||||
|
||||
|
@ -320,7 +323,6 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
assertEquals("LAB_00000100", s[0].getName());
|
||||
}
|
||||
|
||||
|
||||
private void createInstruction(Address addr) throws Exception {
|
||||
int tx = program.startTransaction("test");
|
||||
try {
|
||||
|
@ -338,7 +340,6 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testGetDefaultFunctionSymbolByName() throws Exception {
|
||||
Listing listing = program.getListing();
|
||||
|
||||
AddressSet set = new AddressSet();
|
||||
set.addRange(addr(100), addr(150));
|
||||
|
@ -398,8 +399,6 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
Address ovAddress = block.getStart();
|
||||
assertEquals("ov_12::00000000", ovAddress.toString());
|
||||
|
||||
Listing listing = program.getListing();
|
||||
|
||||
AddressSet set = new AddressSet(ovAddress, ovAddress);
|
||||
Function f = listing.createFunction("fredFunc", ovAddress, set, SourceType.DEFAULT);
|
||||
assertNotNull(f);
|
||||
|
@ -426,7 +425,7 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
Address ovAddress = block.getStart();
|
||||
assertEquals("ov12::00000000", ovAddress.toString());
|
||||
ovAddress = ovAddress.add(2);
|
||||
Listing listing = p.getListing();
|
||||
listing = p.getListing();
|
||||
st = p.getSymbolTable();
|
||||
|
||||
AddressSet set = new AddressSet(ovAddress, ovAddress);
|
||||
|
@ -681,9 +680,8 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testRemoveFunctionSymbolAfterFunction() throws Exception {
|
||||
CreateFunctionCmd cmd = new CreateFunctionCmd("MyFunction", addr(0x0200),
|
||||
createFunction("MyFunction", addr(0x0200),
|
||||
new AddressSet(addr(0x0200), addr(0x0280)), SourceType.USER_DEFINED);
|
||||
assertTrue(cmd.applyTo(program));
|
||||
program.getFunctionManager().removeFunction(addr(0x0200));
|
||||
Symbol s = st.getPrimarySymbol(addr(0x0200));
|
||||
assertNotNull(s);
|
||||
|
@ -695,9 +693,8 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testRemoveFunctionBecomesCodeSymbol() throws Exception {
|
||||
CreateFunctionCmd cmd = new CreateFunctionCmd("MyFunction", addr(0x0200),
|
||||
createFunction("MyFunction", addr(0x0200),
|
||||
new AddressSet(addr(0x0200), addr(0x0280)), SourceType.USER_DEFINED);
|
||||
assertTrue(cmd.applyTo(program));
|
||||
|
||||
Symbol s = st.getPrimarySymbol(addr(0x0200));
|
||||
assertEquals(SymbolType.FUNCTION, s.getSymbolType());
|
||||
|
@ -719,9 +716,8 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
@Test
|
||||
public void testRemoveFunctionSymbolBecomesExistingCodeSymbol() throws Exception {
|
||||
Address entryPt = addr(0x0200);
|
||||
CreateFunctionCmd cmd = new CreateFunctionCmd("MyFunction", entryPt,
|
||||
createFunction("MyFunction", entryPt,
|
||||
new AddressSet(addr(0x0200), addr(0x0280)), SourceType.USER_DEFINED);
|
||||
assertTrue(cmd.applyTo(program));
|
||||
|
||||
st.createLabel(entryPt, "Bob", SourceType.USER_DEFINED);
|
||||
|
||||
|
@ -754,9 +750,8 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
Namespace oldNamespace = st.createNameSpace(null, "OldNameSpace", SourceType.USER_DEFINED);
|
||||
Namespace newNamespace = st.createNameSpace(null, "NewNameSpace", SourceType.USER_DEFINED);
|
||||
Address entryPt = addr(0x0200);
|
||||
CreateFunctionCmd cmd = new CreateFunctionCmd("MyFunction", entryPt,
|
||||
new AddressSet(addr(0x0200), addr(0x0280)), SourceType.USER_DEFINED);
|
||||
assertTrue(cmd.applyTo(program));
|
||||
createFunction("MyFunction", entryPt, new AddressSet(addr(0x0200), addr(0x0280)),
|
||||
SourceType.USER_DEFINED);
|
||||
Symbol functionSym = program.getFunctionManager().getFunctionAt(entryPt).getSymbol();
|
||||
Symbol conflictSym = st.createLabel(addr(0x0230), "Bob", SourceType.USER_DEFINED);// put a conflict symbol in.
|
||||
conflictSym.setNamespace(oldNamespace);
|
||||
|
@ -794,9 +789,8 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testRemoveFunctionSymbolBecomesDefault() throws Exception {
|
||||
CreateFunctionCmd cmd = new CreateFunctionCmd("MyFunction", addr(0x0200),
|
||||
createFunction("MyFunction", addr(0x0200),
|
||||
new AddressSet(addr(0x0200), addr(0x0280)), SourceType.USER_DEFINED);
|
||||
assertTrue(cmd.applyTo(program));
|
||||
|
||||
Symbol s = st.getPrimarySymbol(addr(0x0200));
|
||||
assertEquals(SymbolType.FUNCTION, s.getSymbolType());
|
||||
|
@ -814,6 +808,112 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
assertEquals(false, removed);// Should not be able to remove default function symbol.
|
||||
}
|
||||
|
||||
private Function createFunction(String name, Address entry, AddressSetView body,
|
||||
SourceType type) {
|
||||
CreateFunctionCmd cmd = new CreateFunctionCmd(name, entry, body, type);
|
||||
assertTrue(cmd.applyTo(program));
|
||||
return cmd.getFunction();
|
||||
}
|
||||
|
||||
private Function createFunction(String name, Address entry) {
|
||||
AddressSet set = new AddressSet(entry, entry);
|
||||
return createFunction(name, entry, set, SourceType.USER_DEFINED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrimarySymbolBecomesNonPrimaryAfterFunctionCreated() throws Exception {
|
||||
Address addr = addr(256);
|
||||
Symbol sym1 = createSymbol(addr, "TEST1");
|
||||
Symbol sym2 = createSymbol(addr, "TEST2");
|
||||
Symbol sym3 = createSymbol(addr, "TEST3");
|
||||
|
||||
assertEquals(sym1, st.getPrimarySymbol(addr));
|
||||
|
||||
createFunction("TEST_FUN", addr, new AddressSet(addr, addr), SourceType.USER_DEFINED);
|
||||
Symbol primary = st.getPrimarySymbol(addr);
|
||||
assertEquals("TEST_FUN", primary.getName());
|
||||
assertEquals(SymbolType.FUNCTION, primary.getSymbolType());
|
||||
|
||||
Symbol[] symbols = st.getSymbols(addr);
|
||||
assertEquals(4, symbols.length);
|
||||
|
||||
List<Symbol> list = Arrays.asList(symbols);
|
||||
assertTrue(list.contains(primary));
|
||||
assertTrue(list.contains(sym1));
|
||||
assertTrue(list.contains(sym2));
|
||||
assertTrue(list.contains(sym3));
|
||||
|
||||
assertTrue(primary.isPrimary());
|
||||
assertFalse(sym1.isPrimary());
|
||||
assertFalse(sym2.isPrimary());
|
||||
assertFalse(sym3.isPrimary());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrimarySymbolGetsPromotedToFunction() throws Exception {
|
||||
Address addr = addr(256);
|
||||
Symbol sym1 = createSymbol(addr, "TEST1");
|
||||
Symbol sym2 = createSymbol(addr, "TEST2");
|
||||
Symbol sym3 = createSymbol(addr, "TEST3");
|
||||
|
||||
assertEquals(sym1, st.getPrimarySymbol(addr));
|
||||
|
||||
createFunction(null, addr, new AddressSet(addr, addr), SourceType.DEFAULT);
|
||||
Symbol primary = st.getPrimarySymbol(addr);
|
||||
assertEquals("TEST1", primary.getName());
|
||||
assertEquals(SymbolType.FUNCTION, primary.getSymbolType());
|
||||
|
||||
Symbol[] symbols = st.getSymbols(addr);
|
||||
assertEquals(3, symbols.length);
|
||||
|
||||
List<Symbol> list = Arrays.asList(symbols);
|
||||
assertFalse(list.contains(sym1)); // sym1 was deleted and recreated as a function symbol
|
||||
assertTrue(list.contains(primary));
|
||||
assertTrue(list.contains(sym2));
|
||||
assertTrue(list.contains(sym3));
|
||||
|
||||
assertTrue(primary.isPrimary());
|
||||
assertFalse(sym2.isPrimary());
|
||||
assertFalse(sym3.isPrimary());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateDefaultFunctionWhereDefaultLableExists() {
|
||||
Address addr = addr(256);
|
||||
refMgr.addMemoryReference(addr(784), addr, RefType.FLOW, SourceType.USER_DEFINED, 2);
|
||||
Symbol primary = st.getPrimarySymbol(addr);
|
||||
assertNotNull(primary);
|
||||
assertEquals(SymbolType.LABEL, primary.getSymbolType());
|
||||
assertTrue(primary.getName().startsWith("LAB"));
|
||||
|
||||
createFunction(null, addr, new AddressSet(addr, addr), SourceType.DEFAULT);
|
||||
Symbol newPrimary = st.getPrimarySymbol(addr);
|
||||
assertTrue(primary != newPrimary);
|
||||
assertEquals(SymbolType.FUNCTION, newPrimary.getSymbolType());
|
||||
assertTrue(newPrimary.getName().startsWith("FUN"));
|
||||
assertTrue(primary.isDeleted());
|
||||
assertEquals(1, st.getSymbols(addr).length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateNonDefaultFunctionWhereDefaultLableExists() {
|
||||
Address addr = addr(256);
|
||||
refMgr.addMemoryReference(addr(784), addr, RefType.FLOW, SourceType.USER_DEFINED, 2);
|
||||
Symbol primary = st.getPrimarySymbol(addr);
|
||||
assertNotNull(primary);
|
||||
assertEquals(SymbolType.LABEL, primary.getSymbolType());
|
||||
assertTrue(primary.getName().startsWith("LAB"));
|
||||
|
||||
createFunction("AAA", addr, new AddressSet(addr, addr), SourceType.USER_DEFINED);
|
||||
Symbol newPrimary = st.getPrimarySymbol(addr);
|
||||
assertTrue(primary != newPrimary);
|
||||
assertEquals(SymbolType.FUNCTION, newPrimary.getSymbolType());
|
||||
assertEquals("AAA", newPrimary.getName());
|
||||
assertTrue(primary.isDeleted());
|
||||
assertEquals(1, st.getSymbols(addr).length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRenameSymbol() throws Exception {
|
||||
Symbol s = createSymbol(addr(100), "primary");
|
||||
|
@ -1271,6 +1371,48 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
assertEquals("1", s.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSymbolIteratorByType() throws Exception {
|
||||
createSymbol(addr(100), "1");
|
||||
createSymbol(addr(200), "2");
|
||||
createSymbol(addr(300), "3");
|
||||
|
||||
Function f1 = createFunction("A", addr(150));
|
||||
Function f2 = createFunction("B", addr(250));
|
||||
|
||||
SymbolIterator it =
|
||||
st.getSymbols(new AddressSet(addr(0), addr(5000)), SymbolType.FUNCTION, true);
|
||||
|
||||
assertTrue(it.hasNext());
|
||||
assertEquals(f1.getSymbol(), it.next());
|
||||
|
||||
assertTrue(it.hasNext());
|
||||
assertEquals(f2.getSymbol(), it.next());
|
||||
|
||||
assertFalse(it.hasNext());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSymbolIteratorByTypeBackward() throws Exception {
|
||||
createSymbol(addr(100), "1");
|
||||
createSymbol(addr(200), "2");
|
||||
createSymbol(addr(300), "3");
|
||||
|
||||
Function f1 = createFunction("A", addr(150));
|
||||
Function f2 = createFunction("B", addr(250));
|
||||
|
||||
SymbolIterator it =
|
||||
st.getSymbols(new AddressSet(addr(0), addr(5000)), SymbolType.FUNCTION, false);
|
||||
|
||||
assertTrue(it.hasNext());
|
||||
assertEquals(f2.getSymbol(), it.next());
|
||||
|
||||
assertTrue(it.hasNext());
|
||||
assertEquals(f1.getSymbol(), it.next());
|
||||
|
||||
assertFalse(it.hasNext());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddReference() throws Exception {
|
||||
refMgr.addMemoryReference(addr(512), addr(256), RefType.CONDITIONAL_CALL,
|
||||
|
@ -1321,7 +1463,6 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testCreateFunction() throws Exception {
|
||||
Listing listing = program.getListing();
|
||||
|
||||
Symbol s = createSymbol(addr(100), "fred");
|
||||
assertTrue(s.isPrimary());
|
||||
|
@ -1330,7 +1471,7 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
set.addRange(addr(100), addr(150));
|
||||
set.addRange(addr(300), addr(310));
|
||||
set.addRange(addr(320), addr(330));
|
||||
Function f = listing.createFunction("fredFunc", addr(100), set, SourceType.USER_DEFINED);
|
||||
Function f = createFunction("fredFunc", addr(100), set, SourceType.USER_DEFINED);
|
||||
|
||||
Symbol s1 = st.getPrimarySymbol(addr(100));
|
||||
assertNotNull(s1);
|
||||
|
@ -1349,7 +1490,6 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testPromoteLabelToFunctionWithMultipleLabels() throws Exception {
|
||||
Listing listing = program.getListing();
|
||||
|
||||
Symbol s = createSymbol(addr(100), "fred");
|
||||
assertTrue(s.isPrimary());
|
||||
|
@ -1367,7 +1507,6 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testRenameFunctionToExistingName() throws Exception {
|
||||
Listing listing = program.getListing();
|
||||
|
||||
AddressSet set1 = new AddressSet();
|
||||
set1.addRange(addr(100), addr(150));
|
||||
|
@ -1386,7 +1525,6 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testRemoveFunction() throws Exception {
|
||||
Listing listing = program.getListing();
|
||||
|
||||
Symbol s = createSymbol(addr(100), "fred");
|
||||
assertFalse(s.isDeleted());
|
||||
|
@ -1690,11 +1828,279 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSymbolByNameAndNamespace() throws Exception {
|
||||
Namespace namespace1 = st.createNameSpace(null, "MySpace1", SourceType.USER_DEFINED);
|
||||
Symbol s1 = st.createLabel(addr(0x100), "Symbol", namespace1, SourceType.USER_DEFINED);
|
||||
|
||||
List<Symbol> symbols = st.getSymbols("Symbol", namespace1);
|
||||
assertEquals(1, symbols.size());
|
||||
assertEquals(s1, symbols.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSymbolByNameAndNamespaceWithDupNameInOtherNamespace() throws Exception {
|
||||
Namespace namespace1 = st.createNameSpace(null, "MySpace1", SourceType.USER_DEFINED);
|
||||
Symbol s1 = st.createLabel(addr(0x100), "Symbol", namespace1, SourceType.USER_DEFINED);
|
||||
|
||||
Namespace namespace2 = st.createNameSpace(null, "MySpace2", SourceType.USER_DEFINED);
|
||||
st.createLabel(addr(0x400), "Symbol", namespace2, SourceType.USER_DEFINED);
|
||||
|
||||
List<Symbol> symbols = st.getSymbols("Symbol", namespace1);
|
||||
assertEquals(1, symbols.size());
|
||||
assertEquals(s1, symbols.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSymbolByNameAndNamespaceWithDuplicates() throws Exception {
|
||||
Namespace namespace1 = st.createNameSpace(null, "MySpace1", SourceType.USER_DEFINED);
|
||||
st.createLabel(addr(0x100), "Symbol", namespace1, SourceType.USER_DEFINED);
|
||||
Symbol s2 = st.createLabel(addr(0x200), "SymbolDup", namespace1, SourceType.USER_DEFINED);
|
||||
Symbol s3 = st.createLabel(addr(0x300), "SymbolDup", namespace1, SourceType.USER_DEFINED);
|
||||
|
||||
List<Symbol> symbols = st.getSymbols("SymbolDup", namespace1);
|
||||
assertEquals(2, symbols.size());
|
||||
assertTrue(symbols.contains(s2));
|
||||
assertTrue(symbols.contains(s3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSymbolByNameAndNamespaceWithDuplicatesWithOtherDupsInOtherNamesapce()
|
||||
throws Exception {
|
||||
Namespace namespace1 = st.createNameSpace(null, "MySpace1", SourceType.USER_DEFINED);
|
||||
st.createLabel(addr(0x100), "Symbol", namespace1, SourceType.USER_DEFINED);
|
||||
Symbol s2 = st.createLabel(addr(0x200), "SymbolDup", namespace1, SourceType.USER_DEFINED);
|
||||
Symbol s3 = st.createLabel(addr(0x300), "SymbolDup", namespace1, SourceType.USER_DEFINED);
|
||||
|
||||
Namespace namespace2 = st.createNameSpace(null, "MySpace2", SourceType.USER_DEFINED);
|
||||
st.createLabel(addr(0x400), "Symbol", namespace2, SourceType.USER_DEFINED);
|
||||
st.createLabel(addr(0x500), "SymbolDup", namespace2, SourceType.USER_DEFINED);
|
||||
st.createLabel(addr(0x600), "SymbolDup", namespace2, SourceType.USER_DEFINED);
|
||||
|
||||
List<Symbol> symbols = st.getSymbols("SymbolDup", namespace1);
|
||||
assertEquals(2, symbols.size());
|
||||
assertTrue(symbols.contains(s2));
|
||||
assertTrue(symbols.contains(s3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSymbolByNameAndNamespaceWithDefaultFunctionNames() throws Exception {
|
||||
Namespace namespace = st.createNameSpace(null, "MySpace1", SourceType.USER_DEFINED);
|
||||
AddressSet body = new AddressSet(addr(0x100), addr(0x150));
|
||||
Function f1 =
|
||||
listing.createFunction(null, namespace, addr(0x100), body, SourceType.USER_DEFINED);
|
||||
|
||||
List<Symbol> symbols = st.getSymbols("FUN_00000100", namespace);
|
||||
assertEquals(1, symbols.size());
|
||||
assertEquals(f1.getSymbol(), symbols.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSymbolByNameAndNamespaceWithDefaultLableNames() {
|
||||
refMgr.addMemoryReference(addr(0x200), addr(0x100), RefType.FLOW, SourceType.USER_DEFINED,
|
||||
-1);
|
||||
Symbol[] symbolArray = st.getSymbols(addr(0x100));
|
||||
assertEquals(1, symbolArray.length);
|
||||
assertEquals("LAB_00000100", symbolArray[0].getName());
|
||||
|
||||
List<Symbol> symbols = st.getSymbols("LAB_00000100", null);
|
||||
assertEquals(1, symbols.size());
|
||||
assertEquals(symbolArray[0], symbols.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSymbolNameAndNamespaceInOverlaySpace() throws Exception {
|
||||
Namespace namespace1 = st.createNameSpace(null, "MySpace1", SourceType.USER_DEFINED);
|
||||
Memory memory = program.getMemory();
|
||||
MemoryBlock block = memory.createInitializedBlock("ov_12", addr(0), 5000, (byte) 0,
|
||||
TaskMonitorAdapter.DUMMY_MONITOR, true);
|
||||
Address ovAddress = block.getStart();
|
||||
assertEquals("ov_12::00000000", ovAddress.toString());
|
||||
|
||||
AddressSet set = new AddressSet(ovAddress, ovAddress);
|
||||
Function f = listing.createFunction(null, namespace1, ovAddress, set, SourceType.DEFAULT);
|
||||
assertNotNull(f);
|
||||
|
||||
String defaultName = "FUN_ov_12__00000000";
|
||||
|
||||
List<Symbol> symbols = st.getSymbols(defaultName, namespace1);
|
||||
assertEquals(1, symbols.size());
|
||||
assertEquals(f.getSymbol(), symbols.get(0));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSymbolsByNameNamespaceForLocalVars() throws Exception {
|
||||
Namespace namespace1 = st.createNameSpace(null, "MySpace1", SourceType.USER_DEFINED);
|
||||
AddressSet set = new AddressSet();
|
||||
set.addRange(addr(0x100), addr(0x150));
|
||||
Function f =
|
||||
listing.createFunction(null, namespace1, addr(0x100), set, SourceType.DEFAULT);
|
||||
assertNotNull(f);
|
||||
|
||||
Variable var1 =
|
||||
f.addLocalVariable(new LocalVariableImpl("Bob", new IntegerDataType(), 0x8, program),
|
||||
SourceType.USER_DEFINED);
|
||||
|
||||
List<Symbol> symbols = st.getSymbols("Bob", f);
|
||||
assertEquals(1, symbols.size());
|
||||
assertEquals(var1.getSymbol(), symbols.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSymbolsByNameNamespaceForDefaultLocalVars() throws Exception {
|
||||
Namespace namespace1 = st.createNameSpace(null, "MySpace1", SourceType.USER_DEFINED);
|
||||
AddressSet set = new AddressSet();
|
||||
set.addRange(addr(0x100), addr(0x150));
|
||||
Function f =
|
||||
listing.createFunction(null, namespace1, addr(0x100), set, SourceType.DEFAULT);
|
||||
assertNotNull(f);
|
||||
|
||||
Variable var =
|
||||
f.addLocalVariable(new LocalVariableImpl(null, new IntegerDataType(), -0x18, program),
|
||||
SourceType.DEFAULT);
|
||||
|
||||
List<Symbol> symbols = st.getSymbols("local_18", f);
|
||||
assertEquals(1, symbols.size());
|
||||
assertEquals(var.getSymbol(), symbols.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSymbolsByNameNamespaceForParams() throws Exception {
|
||||
Namespace namespace1 = st.createNameSpace(null, "MySpace1", SourceType.USER_DEFINED);
|
||||
AddressSet set = new AddressSet();
|
||||
DataType dt = new IntegerDataType();
|
||||
Variable param = new ParameterImpl("Bob", dt, program);
|
||||
set.addRange(addr(0x100), addr(0x150));
|
||||
Function f =
|
||||
listing.createFunction(null, namespace1, addr(0x100), set, SourceType.DEFAULT);
|
||||
assertNotNull(f);
|
||||
f.updateFunction(f.getCallingConventionName(), null,
|
||||
FunctionUpdateType.DYNAMIC_STORAGE_FORMAL_PARAMS, true, SourceType.USER_DEFINED, param);
|
||||
Parameter parameter = f.getParameter(0);
|
||||
|
||||
List<Symbol> symbols = st.getSymbols("Bob", f);
|
||||
assertEquals(1, symbols.size());
|
||||
assertEquals(parameter.getSymbol(), symbols.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSymbolsByNameNamespaceForDefaultParams() throws Exception {
|
||||
Namespace namespace1 = st.createNameSpace(null, "MySpace1", SourceType.USER_DEFINED);
|
||||
AddressSet set = new AddressSet();
|
||||
DataType dt = new IntegerDataType();
|
||||
Variable param = new ParameterImpl(null, dt, program);
|
||||
set.addRange(addr(0x100), addr(0x150));
|
||||
Function f =
|
||||
listing.createFunction(null, namespace1, addr(0x100), set, SourceType.DEFAULT);
|
||||
assertNotNull(f);
|
||||
f.updateFunction(f.getCallingConventionName(), null,
|
||||
FunctionUpdateType.DYNAMIC_STORAGE_FORMAL_PARAMS, true, SourceType.DEFAULT, param);
|
||||
|
||||
Parameter parameter = f.getParameter(0);
|
||||
List<Symbol> symbols = st.getSymbols("param_1", f);
|
||||
assertEquals(1, symbols.size());
|
||||
assertEquals(parameter.getSymbol(), symbols.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSymbolByNameNamespaceAddress() throws Exception {
|
||||
Namespace namespace1 = st.createNameSpace(null, "MySpace1", SourceType.USER_DEFINED);
|
||||
Symbol s1 = st.createLabel(addr(0x100), "Symbol", namespace1, SourceType.USER_DEFINED);
|
||||
|
||||
Symbol symbol = st.getSymbol("Symbol", addr(0x100), namespace1);
|
||||
assertEquals(s1, symbol);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSymbolByNameNamespaceAddressForDefaultFunction() throws Exception {
|
||||
Namespace namespace1 = st.createNameSpace(null, "MySpace1", SourceType.USER_DEFINED);
|
||||
AddressSet set = new AddressSet();
|
||||
set.addRange(addr(0x100), addr(0x150));
|
||||
Function f =
|
||||
listing.createFunction(null, namespace1, addr(0x100), set, SourceType.DEFAULT);
|
||||
assertNotNull(f);
|
||||
|
||||
Symbol symbol = st.getSymbol("FUN_00000100", addr(0x100), namespace1);
|
||||
assertEquals(f.getSymbol(), symbol);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSymbolByNameNamespaceAddressForLocalVar() throws Exception {
|
||||
Namespace namespace1 = st.createNameSpace(null, "MySpace1", SourceType.USER_DEFINED);
|
||||
AddressSet set = new AddressSet();
|
||||
set.addRange(addr(0x100), addr(0x150));
|
||||
Function f =
|
||||
listing.createFunction(null, namespace1, addr(0x100), set, SourceType.DEFAULT);
|
||||
assertNotNull(f);
|
||||
|
||||
Variable var =
|
||||
f.addLocalVariable(new LocalVariableImpl("Bob", new IntegerDataType(), 0x8, program),
|
||||
SourceType.USER_DEFINED);
|
||||
Address address = var.getSymbol().getAddress();
|
||||
|
||||
Symbol symbol = st.getSymbol("Bob", address, f);
|
||||
assertEquals(var.getSymbol(), symbol);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSymbolByNameNamespaceAddressForDefaultLocalVar() throws Exception {
|
||||
Namespace namespace1 = st.createNameSpace(null, "MySpace1", SourceType.USER_DEFINED);
|
||||
AddressSet set = new AddressSet();
|
||||
set.addRange(addr(0x100), addr(0x150));
|
||||
Function f =
|
||||
listing.createFunction(null, namespace1, addr(0x100), set, SourceType.DEFAULT);
|
||||
assertNotNull(f);
|
||||
|
||||
Variable var =
|
||||
f.addLocalVariable(new LocalVariableImpl(null, new IntegerDataType(), 0x8, program),
|
||||
SourceType.DEFAULT);
|
||||
Address address = var.getSymbol().getAddress();
|
||||
Symbol symbol = st.getSymbol(var.getName(), address, f);
|
||||
assertEquals(var.getSymbol(), symbol);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSymbolByNameNamespaceAddressForParam() throws Exception {
|
||||
Namespace namespace1 = st.createNameSpace(null, "MySpace1", SourceType.USER_DEFINED);
|
||||
AddressSet set = new AddressSet();
|
||||
DataType dt = new IntegerDataType();
|
||||
Variable param = new ParameterImpl("Bob", dt, program);
|
||||
set.addRange(addr(0x100), addr(0x150));
|
||||
Function f =
|
||||
listing.createFunction(null, namespace1, addr(0x100), set, SourceType.DEFAULT);
|
||||
assertNotNull(f);
|
||||
f.updateFunction(f.getCallingConventionName(), null,
|
||||
FunctionUpdateType.DYNAMIC_STORAGE_FORMAL_PARAMS, true, SourceType.USER_DEFINED, param);
|
||||
|
||||
Parameter parameter = f.getParameter(0);
|
||||
Address address = parameter.getSymbol().getAddress();
|
||||
Symbol symbol = st.getSymbol("Bob", address, f);
|
||||
assertEquals(parameter.getSymbol(), symbol);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSymbolByNameNamespaceAddressForDefaultParam() throws Exception {
|
||||
Namespace namespace1 = st.createNameSpace(null, "MySpace1", SourceType.USER_DEFINED);
|
||||
AddressSet set = new AddressSet();
|
||||
DataType dt = new IntegerDataType();
|
||||
Variable param = new ParameterImpl(null, dt, program);
|
||||
set.addRange(addr(0x100), addr(0x150));
|
||||
Function f =
|
||||
listing.createFunction(null, namespace1, addr(0x100), set, SourceType.DEFAULT);
|
||||
assertNotNull(f);
|
||||
f.updateFunction(f.getCallingConventionName(), null,
|
||||
FunctionUpdateType.DYNAMIC_STORAGE_FORMAL_PARAMS, true, SourceType.DEFAULT, param);
|
||||
|
||||
Parameter parameter = f.getParameter(0);
|
||||
Address address = parameter.getSymbol().getAddress();
|
||||
Symbol symbol = st.getSymbol("param_1", address, f);
|
||||
assertEquals(parameter.getSymbol(), symbol);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDuplicateSymbol() throws Exception {
|
||||
|
||||
st.createNameSpace(null, "MySpace1", SourceType.USER_DEFINED);
|
||||
|
||||
st.createNameSpace(null, "MySpace2", SourceType.USER_DEFINED);
|
||||
|
||||
try {
|
||||
|
@ -1704,12 +2110,10 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
catch (DuplicateNameException e) {
|
||||
// good
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDuplicateFunctionNames() throws Exception {
|
||||
Listing listing = program.getListing();
|
||||
|
||||
AddressSet set1 = new AddressSet();
|
||||
set1.addRange(addr(100), addr(150));
|
||||
|
@ -1722,7 +2126,6 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
assertNotNull(f2);
|
||||
List<Symbol> symbols = st.getGlobalSymbols("fredFunc");
|
||||
assertEquals(2, symbols.size());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1773,7 +2176,8 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
assertTrue(s.isValidParent(subspace1));
|
||||
|
||||
AddressSet set = new AddressSet(addr(0x100), addr(0x150));
|
||||
Function f = program.getFunctionManager().createFunction("function_1", addr(0x100), set,
|
||||
Function f = program.getFunctionManager()
|
||||
.createFunction("function_1", addr(0x100), set,
|
||||
SourceType.USER_DEFINED);
|
||||
assertTrue(s.isValidParent(f));
|
||||
|
||||
|
@ -1791,10 +2195,12 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
Namespace subspace1 = st.createNameSpace(namespace, "MySpace1", SourceType.USER_DEFINED);
|
||||
|
||||
AddressSet set = new AddressSet(addr(0x100), addr(0x150));
|
||||
Function f1 = program.getFunctionManager().createFunction("function_1", addr(0x100), set,
|
||||
Function f1 = program.getFunctionManager()
|
||||
.createFunction("function_1", addr(0x100), set,
|
||||
SourceType.USER_DEFINED);
|
||||
set = new AddressSet(addr(0x200), addr(0x250));
|
||||
Function f2 = program.getFunctionManager().createFunction("function_2", addr(0x200), set,
|
||||
Function f2 = program.getFunctionManager()
|
||||
.createFunction("function_2", addr(0x200), set,
|
||||
SourceType.USER_DEFINED);
|
||||
|
||||
assertTrue(f1.getSymbol().isValidParent(subspace1));// TestNameSpace::MySpace1::function_1 is OK
|
||||
|
@ -1823,7 +2229,8 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
public void testIsValidParentForNamespace() throws Exception {
|
||||
|
||||
AddressSet set = new AddressSet(addr(0x100), addr(0x150));
|
||||
Function f1 = program.getFunctionManager().createFunction("function_1", addr(0x100), set,
|
||||
Function f1 = program.getFunctionManager()
|
||||
.createFunction("function_1", addr(0x100), set,
|
||||
SourceType.USER_DEFINED);
|
||||
|
||||
Namespace namespace = st.createNameSpace(null, "TestNameSpace", SourceType.USER_DEFINED);
|
||||
|
@ -1857,7 +2264,8 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
public void testInvalidExternalScope() throws Exception {
|
||||
|
||||
Library lib = st.createExternalLibrary("extLib", SourceType.USER_DEFINED);
|
||||
ExternalLocation extLoc = program.getExternalManager().addExtFunction("extLib", "printf",
|
||||
ExternalLocation extLoc = program.getExternalManager()
|
||||
.addExtFunction("extLib", "printf",
|
||||
null, SourceType.USER_DEFINED);
|
||||
Symbol extSym = extLoc.getSymbol();
|
||||
assertEquals(SymbolType.FUNCTION, extSym.getSymbolType());
|
||||
|
|
|
@ -59,7 +59,7 @@ public class BinaryField extends Field {
|
|||
}
|
||||
|
||||
@Override
|
||||
boolean isNull() {
|
||||
public boolean isNull() {
|
||||
return data == null;
|
||||
}
|
||||
|
||||
|
|
|
@ -424,7 +424,7 @@ public abstract class Field implements Comparable<Field> {
|
|||
* Determine if the field has been set to a null-state or value.
|
||||
* @return true if field has been set to a null state or value, else false
|
||||
*/
|
||||
abstract boolean isNull();
|
||||
public abstract boolean isNull();
|
||||
|
||||
/**
|
||||
* Set this field to its null-state. For variable-length field this will
|
||||
|
|
|
@ -47,7 +47,7 @@ abstract class FixedField extends BinaryField {
|
|||
}
|
||||
|
||||
@Override
|
||||
final boolean isNull() {
|
||||
public final boolean isNull() {
|
||||
return isNull;
|
||||
}
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ class IndexField extends Field {
|
|||
}
|
||||
|
||||
@Override
|
||||
boolean isNull() {
|
||||
public boolean isNull() {
|
||||
return false; // not-applicable
|
||||
}
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ abstract class PrimitiveField extends Field {
|
|||
}
|
||||
|
||||
@Override
|
||||
final boolean isNull() {
|
||||
public final boolean isNull() {
|
||||
return isNull;
|
||||
}
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ public final class StringField extends Field {
|
|||
}
|
||||
|
||||
@Override
|
||||
boolean isNull() {
|
||||
public boolean isNull() {
|
||||
return bytes == null;
|
||||
}
|
||||
|
||||
|
|
|
@ -98,7 +98,7 @@ public class ExternalLocationDB implements ExternalLocation {
|
|||
|
||||
@Override
|
||||
public String getOriginalImportedName() {
|
||||
return getExternalData3(symbol).getOriginalImportedName();
|
||||
return getExternalData(symbol).getOriginalImportedName();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -111,7 +111,7 @@ public class ExternalLocationDB implements ExternalLocation {
|
|||
*/
|
||||
@Override
|
||||
public Address getAddress() {
|
||||
return getExternalData3(symbol).getAddress(extMgr.getAddressMap().getAddressFactory());
|
||||
return getExternalData(symbol).getAddress(extMgr.getAddressMap().getAddressFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -141,7 +141,7 @@ public class ExternalLocationDB implements ExternalLocation {
|
|||
*/
|
||||
@Override
|
||||
public DataType getDataType() {
|
||||
long dataTypeID = symbol.getSymbolData1();
|
||||
long dataTypeID = symbol.getDataTypeId();
|
||||
if (dataTypeID < 0) {
|
||||
return null;
|
||||
}
|
||||
|
@ -154,7 +154,7 @@ public class ExternalLocationDB implements ExternalLocation {
|
|||
@Override
|
||||
public void setDataType(DataType dt) {
|
||||
long dataTypeID = extMgr.getProgram().getDataTypeManager().getResolvedID(dt);
|
||||
symbol.setSymbolData1(dataTypeID);
|
||||
symbol.setDataTypeId(dataTypeID);
|
||||
|
||||
// TODO: change notification may be required
|
||||
}
|
||||
|
@ -227,7 +227,7 @@ public class ExternalLocationDB implements ExternalLocation {
|
|||
if (addressString == null && getSource() == SourceType.DEFAULT) {
|
||||
throw new InvalidInputException("Either an external label or address is required");
|
||||
}
|
||||
updateSymbolData3(symbol, getExternalData3(symbol).getOriginalImportedName(),
|
||||
updateSymbolData(symbol, getExternalData(symbol).getOriginalImportedName(),
|
||||
addressString);
|
||||
}
|
||||
|
||||
|
@ -365,18 +365,18 @@ public class ExternalLocationDB implements ExternalLocation {
|
|||
|
||||
}
|
||||
|
||||
static ExternalData3 getExternalData3(SymbolDB extSymbol) {
|
||||
return new ExternalData3(extSymbol.getSymbolData3());
|
||||
static ExternalData getExternalData(SymbolDB extSymbol) {
|
||||
return new ExternalData(extSymbol.getSymbolStringData());
|
||||
}
|
||||
|
||||
static void setOriginalImportedName(SymbolDB extSymbol, String name) {
|
||||
updateSymbolData3(extSymbol, name, getExternalData3(extSymbol).getAddressString());
|
||||
updateSymbolData(extSymbol, name, getExternalData(extSymbol).getAddressString());
|
||||
}
|
||||
|
||||
static void updateSymbolData3(SymbolDB extSymbol, String originalImportedName,
|
||||
static void updateSymbolData(SymbolDB extSymbol, String originalImportedName,
|
||||
String addressString) {
|
||||
if (addressString == null && originalImportedName == null) {
|
||||
extSymbol.setSymbolData3(null);
|
||||
extSymbol.setSymbolStringData(null);
|
||||
}
|
||||
StringBuilder buf = new StringBuilder();
|
||||
if (addressString != null) {
|
||||
|
@ -386,18 +386,18 @@ public class ExternalLocationDB implements ExternalLocation {
|
|||
buf.append(ORIGINAL_IMPORTED_DELIMITER);
|
||||
buf.append(originalImportedName);
|
||||
}
|
||||
extSymbol.setSymbolData3(buf.toString());
|
||||
extSymbol.setSymbolStringData(buf.toString());
|
||||
}
|
||||
|
||||
static class ExternalData3 {
|
||||
static class ExternalData {
|
||||
private String originalImportedName;
|
||||
private String addressString;
|
||||
|
||||
ExternalData3(String data3) {
|
||||
if (data3 != null) {
|
||||
int indexOf = data3.indexOf(ORIGINAL_IMPORTED_DELIMITER);
|
||||
originalImportedName = indexOf >= 0 ? data3.substring(indexOf + 1) : null;
|
||||
addressString = indexOf >= 0 ? data3.substring(0, indexOf) : data3;
|
||||
ExternalData(String stringData) {
|
||||
if (stringData != null) {
|
||||
int indexOf = stringData.indexOf(ORIGINAL_IMPORTED_DELIMITER);
|
||||
originalImportedName = indexOf >= 0 ? stringData.substring(indexOf + 1) : null;
|
||||
addressString = indexOf >= 0 ? stringData.substring(0, indexOf) : stringData;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ import db.*;
|
|||
import ghidra.framework.store.FileSystem;
|
||||
import ghidra.program.database.ManagerDB;
|
||||
import ghidra.program.database.ProgramDB;
|
||||
import ghidra.program.database.external.ExternalLocationDB.ExternalData3;
|
||||
import ghidra.program.database.external.ExternalLocationDB.ExternalData;
|
||||
import ghidra.program.database.function.FunctionManagerDB;
|
||||
import ghidra.program.database.map.AddressMap;
|
||||
import ghidra.program.database.symbol.*;
|
||||
|
@ -556,15 +556,15 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
if ((type != SymbolType.LABEL && type != SymbolType.FUNCTION) || !sym.isExternal()) {
|
||||
throw new AssertException();
|
||||
}
|
||||
ExternalData3 externalData3 = ExternalLocationDB.getExternalData3(sym);
|
||||
Address addr = externalData3.getAddress(sym.getProgram().getAddressFactory());
|
||||
ExternalData externalData = ExternalLocationDB.getExternalData(sym);
|
||||
Address addr = externalData.getAddress(sym.getProgram().getAddressFactory());
|
||||
if (addr == null) {
|
||||
throw new AssertException("External should not be default without memory address");
|
||||
}
|
||||
if (type == SymbolType.FUNCTION) {
|
||||
return SymbolUtilities.getDefaultExternalFunctionName(addr);
|
||||
}
|
||||
long dataTypeID = sym.getSymbolData1();
|
||||
long dataTypeID = sym.getDataTypeId();
|
||||
DataType dt =
|
||||
(dataTypeID < 0) ? null : sym.getProgram().getDataTypeManager().getDataType(dataTypeID);
|
||||
return SymbolUtilities.getDefaultExternalName(addr, dt);
|
||||
|
@ -695,7 +695,7 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
private Library addExternalName(String name, String pathname, SourceType source)
|
||||
throws DuplicateNameException, InvalidInputException {
|
||||
SymbolDB s = symbolMgr.createSpecialSymbol(Address.NO_ADDRESS, name,
|
||||
scopeMgr.getGlobalNamespace(), SymbolType.LIBRARY, -1, 0, pathname, source); // 0 set first id for external names
|
||||
scopeMgr.getGlobalNamespace(), SymbolType.LIBRARY, null, null, pathname, source);
|
||||
return (Library) s.getObject();
|
||||
}
|
||||
|
||||
|
@ -742,7 +742,7 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
public String getExternalLibraryPath(String externalName) {
|
||||
SymbolDB s = (SymbolDB) symbolMgr.getLibrarySymbol(externalName);
|
||||
if (s instanceof LibrarySymbol) {
|
||||
return s.getSymbolData3();
|
||||
return s.getSymbolStringData();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -771,7 +771,7 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
}
|
||||
}
|
||||
else if (s instanceof LibrarySymbol) {
|
||||
s.setSymbolData3(externalPath);
|
||||
s.setSymbolStringData(externalPath);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
|
@ -802,7 +802,7 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
return null;
|
||||
}
|
||||
//long dtId = symbol.getSymbolData1();
|
||||
String extData3 = symbol.getSymbolData3();
|
||||
String extData = symbol.getSymbolStringData();
|
||||
String name = symbol.getName();
|
||||
Namespace namespace = symbol.getParentNamespace();
|
||||
Address extAddr = symbol.getAddress();
|
||||
|
@ -810,7 +810,7 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
|
||||
((CodeSymbol) symbol).delete(true);
|
||||
|
||||
return functionMgr.createExternalFunction(extAddr, name, namespace, extData3, source);
|
||||
return functionMgr.createExternalFunction(extAddr, name, namespace, extData, source);
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
@ -927,8 +927,8 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
while (externalSymbols.hasNext()) {
|
||||
monitor.checkCanceled();
|
||||
SymbolDB s = (SymbolDB) externalSymbols.next();
|
||||
ExternalData3 externalData3 = ExternalLocationDB.getExternalData3(s);
|
||||
String addrStr = externalData3.getAddressString();
|
||||
ExternalData externalData = ExternalLocationDB.getExternalData(s);
|
||||
String addrStr = externalData.getAddressString();
|
||||
if (addrStr == null) {
|
||||
continue;
|
||||
}
|
||||
|
@ -947,7 +947,7 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
addr = newAddressSpace.getAddress(addr.getOffset());
|
||||
String newAddrStr = addr.toString();
|
||||
if (!newAddrStr.equals(addrStr)) {
|
||||
ExternalLocationDB.updateSymbolData3(s, externalData3.getOriginalImportedName(),
|
||||
ExternalLocationDB.updateSymbolData(s, externalData.getOriginalImportedName(),
|
||||
newAddrStr); // store translated external location address
|
||||
}
|
||||
}
|
||||
|
|
|
@ -990,7 +990,7 @@ public class FunctionDB extends DatabaseObject implements Function {
|
|||
symbolMap.put(v.symbol, v);
|
||||
}
|
||||
if (var.getComment() != null) {
|
||||
v.symbol.setSymbolData3(var.getComment());
|
||||
v.symbol.setSymbolStringData(var.getComment());
|
||||
}
|
||||
manager.functionChanged(this, 0);
|
||||
return v;
|
||||
|
@ -1678,7 +1678,7 @@ public class FunctionDB extends DatabaseObject implements Function {
|
|||
manager.functionChanged(this, ChangeManager.FUNCTION_CHANGED_PARAMETERS);
|
||||
}
|
||||
if (var.getComment() != null) {
|
||||
p.symbol.setSymbolData3(var.getComment());
|
||||
p.symbol.setSymbolStringData(var.getComment());
|
||||
}
|
||||
updateSignatureSourceAfterVariableChange(source, p.getDataType());
|
||||
return p;
|
||||
|
|
|
@ -273,22 +273,22 @@ public class FunctionManagerDB implements FunctionManager {
|
|||
* Transform an existing external symbol into an external function.
|
||||
* This method should only be invoked by an ExternalSymbol
|
||||
* @param extSpaceAddr the external space address to use when creating this external.
|
||||
* @param name
|
||||
* @param nameSpace
|
||||
* @param extData3 internal symbol-data-3 string (see {@link ExternalLocationDB})
|
||||
* @param name the external function name
|
||||
* @param nameSpace the external function namespace
|
||||
* @param extData the external data string to store additional info (see {@link ExternalLocationDB})
|
||||
* @param source the source of this external.
|
||||
* @return external function
|
||||
* @throws InvalidInputException
|
||||
* @throws DuplicateNameException
|
||||
* @throws InvalidInputException if the name is invalid
|
||||
* @throws DuplicateNameException if the name is an invalid duplicate
|
||||
*/
|
||||
public Function createExternalFunction(Address extSpaceAddr, String name, Namespace nameSpace,
|
||||
String extData3, SourceType source)
|
||||
String extData, SourceType source)
|
||||
throws DuplicateNameException, InvalidInputException {
|
||||
lock.acquire();
|
||||
try {
|
||||
|
||||
Symbol symbol = symbolMgr.createSpecialSymbol(extSpaceAddr, name, nameSpace,
|
||||
SymbolType.FUNCTION, -1, -1, extData3, source);
|
||||
SymbolType.FUNCTION, null, null, extData, source);
|
||||
|
||||
long returnDataTypeId = program.getDataTypeManager().getResolvedID(DataType.DEFAULT);
|
||||
|
||||
|
|
|
@ -167,12 +167,12 @@ public abstract class VariableDB implements Variable {
|
|||
|
||||
@Override
|
||||
public String getComment() {
|
||||
return symbol.getSymbolData3();
|
||||
return symbol.getSymbolStringData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setComment(String comment) {
|
||||
symbol.setSymbolData3(comment);
|
||||
symbol.setSymbolStringData(comment);
|
||||
functionMgr.functionChanged(function, 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -20,26 +20,21 @@ import java.util.Iterator;
|
|||
|
||||
import db.DBRecord;
|
||||
import db.RecordIterator;
|
||||
import ghidra.program.database.util.Query;
|
||||
import ghidra.program.database.util.QueryRecordIterator;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.database.util.*;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.program.model.symbol.Symbol;
|
||||
import ghidra.program.model.symbol.SymbolIterator;
|
||||
|
||||
/**
|
||||
*
|
||||
* Iterator (in address order) over primary symbols in an address set.
|
||||
* Iterator (in address order) over all symbols that match the given query in an address set.
|
||||
*
|
||||
*
|
||||
*/
|
||||
class AddressSetFilteredSymbolIterator implements SymbolIterator {
|
||||
private SymbolManager symbolMgr;
|
||||
private AddressRangeIterator rangeIter;
|
||||
private QueryRecordIterator recIter;
|
||||
private Symbol currentSymbol;
|
||||
private SymbolDatabaseAdapter adapter;
|
||||
private boolean forward;
|
||||
private Query query;
|
||||
|
||||
/**
|
||||
* Construct a new AddressSetFilteredSymbolIterator.
|
||||
|
@ -51,55 +46,42 @@ class AddressSetFilteredSymbolIterator implements SymbolIterator {
|
|||
AddressSetFilteredSymbolIterator(SymbolManager symbolMgr, AddressSetView set, Query query,
|
||||
boolean forward) {
|
||||
this.symbolMgr = symbolMgr;
|
||||
rangeIter = set.getAddressRanges(forward);
|
||||
adapter = symbolMgr.getDatabaseAdapter();
|
||||
this.forward = forward;
|
||||
this.query = query;
|
||||
try {
|
||||
RecordIterator it = adapter.getSymbols(set, forward);
|
||||
recIter = new QueryRecordIterator(it, query, forward);
|
||||
}
|
||||
catch (IOException e) {
|
||||
symbolMgr.dbError(e);
|
||||
recIter = new QueryRecordIterator(new EmptyRecordIterator(), query, forward);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
if (currentSymbol == null) {
|
||||
try {
|
||||
findNext();
|
||||
return recIter.hasNext();
|
||||
}
|
||||
catch (IOException e) {
|
||||
symbolMgr.dbError(e);
|
||||
}
|
||||
}
|
||||
return currentSymbol != null;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Symbol next() {
|
||||
if (hasNext()) {
|
||||
Symbol s = currentSymbol;
|
||||
currentSymbol = null;
|
||||
return s;
|
||||
try {
|
||||
DBRecord rec = recIter.next();
|
||||
return symbolMgr.getSymbol(rec);
|
||||
}
|
||||
catch (IOException e) {
|
||||
symbolMgr.dbError(e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void findNext() throws IOException {
|
||||
if (recIter != null && recIter.hasNext()) {
|
||||
DBRecord rec = recIter.next();
|
||||
currentSymbol = symbolMgr.getSymbol(rec);
|
||||
}
|
||||
else {
|
||||
while (rangeIter.hasNext()) {
|
||||
AddressRange range = rangeIter.next();
|
||||
RecordIterator it =
|
||||
adapter.getSymbols(range.getMinAddress(), range.getMaxAddress(), forward);
|
||||
recIter = new QueryRecordIterator(it, query, forward);
|
||||
if (recIter.hasNext()) {
|
||||
DBRecord rec = recIter.next();
|
||||
currentSymbol = symbolMgr.getSymbol(rec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
|
|
|
@ -30,10 +30,7 @@ import ghidra.program.util.ProgramLocation;
|
|||
*
|
||||
* Symbol data usage:
|
||||
* EXTERNAL:
|
||||
* long data1 - external data type
|
||||
* String data3 - external memory address
|
||||
* NON-EXTERNAL:
|
||||
* int data2 - primary flag
|
||||
* String stringData - external memory address/label
|
||||
*/
|
||||
|
||||
public class CodeSymbol extends SymbolDB {
|
||||
|
@ -162,7 +159,7 @@ public class CodeSymbol extends SymbolDB {
|
|||
if (getSource() == SourceType.DEFAULT || isExternal()) {
|
||||
return true;
|
||||
}
|
||||
return getSymbolData2() == 1;
|
||||
return doCheckIsPrimary();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -201,7 +198,7 @@ public class CodeSymbol extends SymbolDB {
|
|||
}
|
||||
|
||||
void setPrimary(boolean primary) {
|
||||
setSymbolData2(primary ? 1 : 0);
|
||||
doSetPrimary(primary);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -39,10 +39,7 @@ import ghidra.util.task.TaskMonitor;
|
|||
*
|
||||
* Symbol Data Usage:
|
||||
* EXTERNAL:
|
||||
* long data1 - external data type
|
||||
* String data3 - external memory address
|
||||
* NON-EXTERNAL:
|
||||
* - not used -
|
||||
* String stringData - external memory address/label
|
||||
*/
|
||||
public class FunctionSymbol extends SymbolDB {
|
||||
|
||||
|
@ -103,9 +100,9 @@ public class FunctionSymbol extends SymbolDB {
|
|||
try {
|
||||
boolean restoreLabel = isExternal() || (getSource() != SourceType.DEFAULT);
|
||||
String symName = getName();
|
||||
String extData3 = null;
|
||||
String extData = null;
|
||||
if (isExternal()) {
|
||||
extData3 = getSymbolData3(); // preserve external data
|
||||
extData = getSymbolStringData(); // preserve external data
|
||||
}
|
||||
Namespace namespace = getParentNamespace();
|
||||
SourceType source = getSource();
|
||||
|
@ -120,7 +117,7 @@ public class FunctionSymbol extends SymbolDB {
|
|||
|
||||
if (super.delete()) {
|
||||
if (restoreLabel) {
|
||||
boolean restored = createLabelForDeletedFunctionName(address, symName, extData3,
|
||||
boolean restored = createLabelForDeletedFunctionName(address, symName, extData,
|
||||
namespace, source, pinned);
|
||||
if (!restored && isExternal()) {
|
||||
removeAllReferencesTo();
|
||||
|
@ -140,7 +137,7 @@ public class FunctionSymbol extends SymbolDB {
|
|||
* does not mean that we want to lose the function name (that is our policy).
|
||||
*/
|
||||
private boolean createLabelForDeletedFunctionName(Address entryPoint, String symName,
|
||||
String data3, Namespace namespace, SourceType source, boolean pinned) {
|
||||
String stringData, Namespace namespace, SourceType source, boolean pinned) {
|
||||
if (isExternal()) {
|
||||
SymbolDB parent = (SymbolDB) namespace.getSymbol();
|
||||
if (parent.isDeleting()) {
|
||||
|
@ -151,7 +148,7 @@ public class FunctionSymbol extends SymbolDB {
|
|||
SymbolDB newSym;
|
||||
try {
|
||||
newSym = symbolMgr.createSpecialSymbol(entryPoint, symName, namespace,
|
||||
SymbolType.LABEL, -1, -1, data3, source);
|
||||
SymbolType.LABEL, null, null, stringData, source);
|
||||
if (pinned) {
|
||||
newSym.setPinned(true);
|
||||
}
|
||||
|
@ -161,7 +158,7 @@ public class FunctionSymbol extends SymbolDB {
|
|||
newSym = (SymbolDB) symbolMgr.createLabel(entryPoint, symName,
|
||||
program.getGlobalNamespace(), source);
|
||||
}
|
||||
newSym.setSymbolData3(data3); // reserved for external location use
|
||||
newSym.setSymbolStringData(stringData);
|
||||
newSym.setPrimary();
|
||||
return true;
|
||||
}
|
||||
|
@ -275,56 +272,11 @@ public class FunctionSymbol extends SymbolDB {
|
|||
return super.doGetParentNamespace();
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public void setNameAndNamespace(String newName, Namespace newNamespace, SourceType source)
|
||||
// throws DuplicateNameException, InvalidInputException, CircularDependencyException {
|
||||
//
|
||||
// if (!isExternal()) {
|
||||
//
|
||||
// // Check thunk function name - if name matches thunked function
|
||||
// // name switch to using DEFAULT name
|
||||
//
|
||||
// // NOTE: Removed this since this prevents having a second symbol
|
||||
//
|
||||
// Symbol thunkedSymbol = getThunkedSymbol();
|
||||
// if (thunkedSymbol != null) {
|
||||
// String thunkedName = thunkedSymbol.getName();
|
||||
// if (thunkedName.equals(newName)) {
|
||||
// newName = "";
|
||||
// source = SourceType.DEFAULT;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// super.setNameAndNamespace(newName, newNamespace, source);
|
||||
// }
|
||||
|
||||
private Symbol getThunkedSymbol() {
|
||||
long thunkedFunctionId = functionMgr.getThunkedFunctionId(key);
|
||||
return (thunkedFunctionId >= 0) ? symbolMgr.getSymbol(thunkedFunctionId) : null;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public void setNameAndNamespace(String newName, Namespace newNamespace, SourceType source)
|
||||
// throws DuplicateNameException, InvalidInputException, CircularDependencyException {
|
||||
//
|
||||
// long thunkedFunctionId = functionMgr.getThunkedFunctionId(key);
|
||||
// if (thunkedFunctionId >= 0) {
|
||||
// if (!newName.startsWith(Function.THUNK_PREFIX)) {
|
||||
// // ignore
|
||||
// return;
|
||||
// }
|
||||
// // rename thunked function based on thunk name specified
|
||||
// Symbol s = symbolMgr.getSymbol(thunkedFunctionId);
|
||||
// if (s != null) {
|
||||
// s.setName(newName.substring(Function.THUNK_PREFIX.length()), source);
|
||||
// }
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// super.setNameAndNamespace(newName, newNamespace, source);
|
||||
// }
|
||||
|
||||
@Override
|
||||
protected SourceType validateNameSource(String newName, SourceType source) {
|
||||
// if (isThunk()) {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -109,7 +108,7 @@ class LibraryDB implements Library {
|
|||
|
||||
@Override
|
||||
public String getAssociatedProgramPath() {
|
||||
return symbol.getSymbolData3();
|
||||
return symbol.getSymbolStringData();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -31,8 +31,7 @@ import ghidra.util.exception.InvalidInputException;
|
|||
* Class for library symbols.
|
||||
*
|
||||
* Symbol data usage:
|
||||
* int data2 - set to 0 (not used)
|
||||
* String data3 - associated program project file path
|
||||
* String stringData - associated program project file path
|
||||
*/
|
||||
|
||||
public class LibrarySymbol extends SymbolDB {
|
||||
|
@ -64,7 +63,8 @@ public class LibrarySymbol extends SymbolDB {
|
|||
super.setName(newName, source);
|
||||
|
||||
if (!oldName.equals(getName())) {
|
||||
symbolMgr.getProgram().setObjChanged(ChangeManager.DOCR_EXTERNAL_NAME_CHANGED,
|
||||
symbolMgr.getProgram()
|
||||
.setObjChanged(ChangeManager.DOCR_EXTERNAL_NAME_CHANGED,
|
||||
(Address) null, null, oldName, newName);
|
||||
}
|
||||
}
|
||||
|
@ -77,18 +77,20 @@ public class LibrarySymbol extends SymbolDB {
|
|||
super.setNameAndNamespace(newName, newNamespace, source);
|
||||
|
||||
if (!oldName.equals(getName())) {
|
||||
symbolMgr.getProgram().setObjChanged(ChangeManager.DOCR_EXTERNAL_NAME_CHANGED,
|
||||
symbolMgr.getProgram()
|
||||
.setObjChanged(ChangeManager.DOCR_EXTERNAL_NAME_CHANGED,
|
||||
(Address) null, null, oldName, newName);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSymbolData3(String newPath) {
|
||||
String oldPath = getSymbolData3();
|
||||
public void setSymbolStringData(String newPath) {
|
||||
String oldPath = getSymbolStringData();
|
||||
|
||||
super.setSymbolData3(newPath);
|
||||
super.setSymbolStringData(newPath);
|
||||
|
||||
symbolMgr.getProgram().setObjChanged(ChangeManager.DOCR_EXTERNAL_PATH_CHANGED, getName(),
|
||||
symbolMgr.getProgram()
|
||||
.setObjChanged(ChangeManager.DOCR_EXTERNAL_PATH_CHANGED, getName(),
|
||||
oldPath, newPath);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,10 +16,10 @@
|
|||
package ghidra.program.database.symbol;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
import db.DBRecord;
|
||||
import db.Field;
|
||||
import ghidra.program.database.*;
|
||||
import ghidra.program.database.external.ExternalLocationDB;
|
||||
import ghidra.program.database.external.ExternalManagerDB;
|
||||
|
@ -141,21 +141,25 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
|||
* @param newAddress the new address for the symbol
|
||||
* @param newName the new name for the symbol (or null if the name should stay the same)
|
||||
* @param newNamespace the new namespace for the symbol (or null if it should stay the same)
|
||||
* @param newSource
|
||||
* @param newSource the new SourceType for the symbol (or null if it should stay the same)
|
||||
* @param pinned the new pinned state
|
||||
*/
|
||||
protected void moveLowLevel(Address newAddress, String newName, Namespace newNamespace,
|
||||
SourceType newSource, boolean pinned) {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkDeleted();
|
||||
Address oldAddress = address;
|
||||
record.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL,
|
||||
symbolMgr.getAddressMap().getKey(newAddress, true));
|
||||
|
||||
// update the address to the new location
|
||||
long newAddressKey = symbolMgr.getAddressMap().getKey(newAddress, true);
|
||||
record.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL, newAddressKey);
|
||||
|
||||
// if the primary field is set, be sure to update it to the new address as well
|
||||
if (record.getFieldValue(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL) != null) {
|
||||
record.setLongValue(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL, newAddressKey);
|
||||
}
|
||||
if (newName != null) {
|
||||
record.setString(SymbolDatabaseAdapter.SYMBOL_NAME_COL, newName);
|
||||
if (newName.length() == 0) {
|
||||
setSourceFlagBit(SourceType.DEFAULT);
|
||||
}
|
||||
}
|
||||
if (newNamespace != null) {
|
||||
record.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL, newNamespace.getID());
|
||||
|
@ -793,32 +797,42 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
|||
}
|
||||
}
|
||||
|
||||
public String getSymbolData3() {
|
||||
/**
|
||||
* Returns the symbol's string data which has different meanings depending on the symbol type
|
||||
* and whether or not it is external
|
||||
* @return the symbol's string data
|
||||
*/
|
||||
public String getSymbolStringData() {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkIsValid();
|
||||
if (record == null) {
|
||||
return null;
|
||||
}
|
||||
return record.getString(SymbolDatabaseAdapter.SYMBOL_DATA3_COL);
|
||||
return record.getString(SymbolDatabaseAdapter.SYMBOL_STRING_DATA_COL);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
public void setSymbolData3(String data3) {
|
||||
/**
|
||||
* Sets the symbol's string data field. This field's data has different uses depending on the
|
||||
* symbol type and whether or not it is external.
|
||||
* @param stringData the string to store in the string data field
|
||||
*/
|
||||
public void setSymbolStringData(String stringData) {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkDeleted();
|
||||
if (record == null) {
|
||||
return;
|
||||
}
|
||||
String oldData = record.getString(SymbolDatabaseAdapter.SYMBOL_DATA3_COL);
|
||||
if (SystemUtilities.isEqual(data3, oldData)) {
|
||||
String oldData = record.getString(SymbolDatabaseAdapter.SYMBOL_STRING_DATA_COL);
|
||||
if (Objects.equals(stringData, oldData)) {
|
||||
return;
|
||||
}
|
||||
record.setString(SymbolDatabaseAdapter.SYMBOL_DATA3_COL, data3);
|
||||
record.setString(SymbolDatabaseAdapter.SYMBOL_STRING_DATA_COL, stringData);
|
||||
updateRecord();
|
||||
symbolMgr.symbolDataChanged(this);
|
||||
}
|
||||
|
@ -836,14 +850,18 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
|||
}
|
||||
}
|
||||
|
||||
public long getSymbolData1() {
|
||||
public long getDataTypeId() {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkIsValid();
|
||||
if (record != null) {
|
||||
return record.getLongValue(SymbolDatabaseAdapter.SYMBOL_DATA1_COL);
|
||||
Field value = record.getFieldValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL);
|
||||
if (value.isNull()) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
return value.getLongValue();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
|
@ -854,12 +872,12 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
|||
* Sets the generic symbol data 1.
|
||||
* @param value the value to set as symbol data 1.
|
||||
*/
|
||||
public void setSymbolData1(long value) {
|
||||
public void setDataTypeId(long value) {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkDeleted();
|
||||
if (record != null) {
|
||||
record.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATA1_COL, value);
|
||||
record.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL, value);
|
||||
updateRecord();
|
||||
symbolMgr.symbolDataChanged(this);
|
||||
}
|
||||
|
@ -873,12 +891,12 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
|||
* gets the generic symbol data 2 data.
|
||||
* @return the symbol data
|
||||
*/
|
||||
public int getSymbolData2() {
|
||||
protected int getVariableOffset() {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkIsValid();
|
||||
if (record != null) {
|
||||
return record.getIntValue(SymbolDatabaseAdapter.SYMBOL_DATA2_COL);
|
||||
return record.getIntValue(SymbolDatabaseAdapter.SYMBOL_VAROFFSET_COL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -888,15 +906,16 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the generic symbol data 2 data
|
||||
* @param value the value to set as the symbols data 2 value.
|
||||
* Sets the symbol's variable offset. For parameters, this is the ordinal, for locals, it is
|
||||
* the first use offset
|
||||
* @param offset the value to set as the symbols variable offset.
|
||||
*/
|
||||
public void setSymbolData2(int value) {
|
||||
public void setVariableOffset(int offset) {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkDeleted();
|
||||
if (record != null) {
|
||||
record.setIntValue(SymbolDatabaseAdapter.SYMBOL_DATA2_COL, value);
|
||||
record.setIntValue(SymbolDatabaseAdapter.SYMBOL_VAROFFSET_COL, offset);
|
||||
updateRecord();
|
||||
symbolMgr.symbolDataChanged(this);
|
||||
}
|
||||
|
@ -906,6 +925,42 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
|
|||
}
|
||||
}
|
||||
|
||||
protected void doSetPrimary(boolean primary) {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkDeleted();
|
||||
if (record != null) {
|
||||
if (primary) {
|
||||
long addrKey = record.getLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL);
|
||||
record.setLongValue(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL, addrKey);
|
||||
}
|
||||
else {
|
||||
record.setField(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL, null);
|
||||
}
|
||||
updateRecord();
|
||||
symbolMgr.symbolDataChanged(this);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected boolean doCheckIsPrimary() {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkIsValid();
|
||||
if (record != null) {
|
||||
return !record.getFieldValue(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL).isNull();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean delete() {
|
||||
lock.acquire();
|
||||
|
|
|
@ -16,14 +16,16 @@
|
|||
package ghidra.program.database.symbol;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import db.*;
|
||||
import ghidra.program.database.map.AddressMap;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.program.model.symbol.SymbolType;
|
||||
import ghidra.program.database.util.*;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.VersionException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
@ -32,24 +34,23 @@ import ghidra.util.task.TaskMonitor;
|
|||
* Adapter to access records in the symbol table.
|
||||
*/
|
||||
abstract class SymbolDatabaseAdapter {
|
||||
|
||||
static final String SYMBOL_TABLE_NAME = "Symbols";
|
||||
|
||||
static final Schema SYMBOL_SCHEMA = new Schema(2, "Key",
|
||||
new Field[] { StringField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE,
|
||||
ByteField.INSTANCE, LongField.INSTANCE, IntField.INSTANCE, StringField.INSTANCE,
|
||||
ByteField.INSTANCE },
|
||||
new String[] { "Name", "Address", "Parent", "Symbol Type", "SymbolData1", "SymbolData2",
|
||||
"SymbolData3", "Flags" });
|
||||
|
||||
static final int SYMBOL_NAME_COL = 0;
|
||||
static final int SYMBOL_ADDR_COL = 1;
|
||||
static final int SYMBOL_PARENT_COL = 2;
|
||||
static final int SYMBOL_TYPE_COL = 3;
|
||||
static final int SYMBOL_DATA1_COL = 4;
|
||||
static final int SYMBOL_DATA2_COL = 5;
|
||||
static final int SYMBOL_DATA3_COL = 6;
|
||||
static final int SYMBOL_FLAGS_COL = 7;
|
||||
static final int SYMBOL_STRING_DATA_COL = 4;
|
||||
static final int SYMBOL_FLAGS_COL = 5;
|
||||
|
||||
// sparse fields - the following fields are not always applicable so they are optional and
|
||||
// don't consume space in the database if they aren't used.
|
||||
static final int SYMBOL_HASH_COL = 6;
|
||||
static final int SYMBOL_PRIMARY_COL = 7;
|
||||
static final int SYMBOL_DATATYPE_COL = 8;
|
||||
static final int SYMBOL_VAROFFSET_COL = 9;
|
||||
|
||||
static final Schema SYMBOL_SCHEMA = SymbolDatabaseAdapterV3.V3_SYMBOL_SCHEMA;
|
||||
|
||||
// Bits 0 & 1 are used for the source of the symbol.
|
||||
static final byte SYMBOL_SOURCE_BITS = (byte) 0x3;
|
||||
|
@ -59,26 +60,24 @@ abstract class SymbolDatabaseAdapter {
|
|||
|
||||
/**
|
||||
* Gets a new SymbolDatabaseAdapter
|
||||
* @param dbHandle the database handle.
|
||||
* @param openMode the openmode
|
||||
* @param dbHandle the database handle
|
||||
* @param openMode the open mode. See {@link DBConstants}
|
||||
* @param addrMap the address map
|
||||
* @param monitor the progress monitor.
|
||||
* @throws VersionException if the database table does not match the adapter.
|
||||
* @throws CancelledException if the user cancels an upgrade.
|
||||
* @throws IOException if a database io error occurs.
|
||||
* @param monitor the progress monitor
|
||||
* @return a new SymbolDatabaseAdapter
|
||||
* @throws VersionException if the database table does not match the adapter
|
||||
* @throws CancelledException if the user cancels an upgrade
|
||||
* @throws IOException if a database io error occurs
|
||||
*/
|
||||
static SymbolDatabaseAdapter getAdapter(DBHandle dbHandle, int openMode, AddressMap addrMap,
|
||||
TaskMonitor monitor) throws VersionException, CancelledException, IOException {
|
||||
|
||||
if (openMode == DBConstants.CREATE) {
|
||||
return new SymbolDatabaseAdapterV2(dbHandle, addrMap, true);
|
||||
return new SymbolDatabaseAdapterV3(dbHandle, addrMap, true);
|
||||
}
|
||||
|
||||
try {
|
||||
SymbolDatabaseAdapter adapter = new SymbolDatabaseAdapterV2(dbHandle, addrMap, false);
|
||||
if (addrMap.isUpgraded()) {
|
||||
throw new VersionException(true);
|
||||
}
|
||||
SymbolDatabaseAdapter adapter = new SymbolDatabaseAdapterV3(dbHandle, addrMap, false);
|
||||
return adapter;
|
||||
}
|
||||
catch (VersionException e) {
|
||||
|
@ -87,7 +86,7 @@ abstract class SymbolDatabaseAdapter {
|
|||
}
|
||||
SymbolDatabaseAdapter adapter = findReadOnlyAdapter(dbHandle, addrMap);
|
||||
if (openMode == DBConstants.UPGRADE) {
|
||||
adapter = SymbolDatabaseAdapterV2.upgrade(dbHandle, addrMap, adapter, monitor);
|
||||
adapter = upgrade(dbHandle, addrMap, adapter, monitor);
|
||||
}
|
||||
else if (adapter instanceof SymbolDatabaseAdapterV0) {
|
||||
// Upgrade required - read-only use not supported
|
||||
|
@ -101,39 +100,125 @@ abstract class SymbolDatabaseAdapter {
|
|||
throws VersionException, IOException {
|
||||
|
||||
try {
|
||||
return new SymbolDatabaseAdapterV2(handle, addrMap.getOldAddressMap(), false);
|
||||
return new SymbolDatabaseAdapterV2(handle, addrMap.getOldAddressMap());
|
||||
}
|
||||
catch (VersionException e1) {
|
||||
// failed try older version
|
||||
}
|
||||
|
||||
try {
|
||||
return new SymbolDatabaseAdapterV1(handle, addrMap.getOldAddressMap());
|
||||
}
|
||||
catch (VersionException e1) {
|
||||
// failed try older version
|
||||
}
|
||||
|
||||
return new SymbolDatabaseAdapterV0(handle, addrMap);
|
||||
try {
|
||||
return new SymbolDatabaseAdapterV0(handle, addrMap.getOldAddressMap());
|
||||
}
|
||||
catch (VersionException e1) {
|
||||
// failed - can't handle whatever version this is trying to open
|
||||
}
|
||||
|
||||
throw new VersionException(false);
|
||||
}
|
||||
|
||||
static SymbolDatabaseAdapter upgrade(DBHandle dbHandle, AddressMap addrMap,
|
||||
SymbolDatabaseAdapter oldAdapter, TaskMonitor monitor)
|
||||
throws VersionException, IOException, CancelledException {
|
||||
|
||||
monitor.setMessage("Upgrading Symbol Table...");
|
||||
monitor.initialize(oldAdapter.getSymbolCount() * 2);
|
||||
|
||||
DBHandle tmpHandle = dbHandle.getScratchPad();
|
||||
|
||||
try {
|
||||
SymbolDatabaseAdapter tmpAdapter =
|
||||
copyToTempAndFixupRecords(addrMap, oldAdapter, tmpHandle, monitor);
|
||||
|
||||
dbHandle.deleteTable(SYMBOL_TABLE_NAME);
|
||||
|
||||
SymbolDatabaseAdapter newAdapter =
|
||||
new SymbolDatabaseAdapterV3(dbHandle, addrMap, true);
|
||||
|
||||
copyTempToNewAdapter(tmpAdapter, newAdapter, monitor);
|
||||
return newAdapter;
|
||||
}
|
||||
finally {
|
||||
tmpHandle.deleteTable(SYMBOL_TABLE_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
private static SymbolDatabaseAdapter copyToTempAndFixupRecords(AddressMap addrMap,
|
||||
SymbolDatabaseAdapter oldAdapter, DBHandle tmpHandle, TaskMonitor monitor)
|
||||
throws IOException, CancelledException, VersionException {
|
||||
|
||||
AddressMap oldAddrMap = addrMap.getOldAddressMap();
|
||||
|
||||
long nextKey = 1; // only used for V0 upgrade if a record with key 0 is encountered
|
||||
if (oldAdapter instanceof SymbolDatabaseAdapterV0) {
|
||||
// V0 is so old that there is not enough info in the current record to create new
|
||||
// records. So store the current info in a temp database table and complete the upgrade
|
||||
// when SymbolManager.programReady() is called. The missing info can be retrieved from
|
||||
// other managers in the program at that point.
|
||||
nextKey =
|
||||
((SymbolDatabaseAdapterV0) oldAdapter).extractLocalSymbols(tmpHandle, monitor);
|
||||
}
|
||||
|
||||
SymbolDatabaseAdapterV3 tmpAdapter = new SymbolDatabaseAdapterV3(tmpHandle, addrMap, true);
|
||||
RecordIterator iter = oldAdapter.getSymbols();
|
||||
while (iter.hasNext()) {
|
||||
monitor.checkCanceled();
|
||||
DBRecord rec = iter.next();
|
||||
Address addr = oldAddrMap.decodeAddress(rec.getLongValue(SYMBOL_ADDR_COL));
|
||||
rec.setLongValue(SYMBOL_ADDR_COL, addrMap.getKey(addr, true));
|
||||
|
||||
// We don't allow 0 keys starting with V1, set its key to next available
|
||||
// which we got from the call to extractLocalSymbols() above
|
||||
if (rec.getKey() == 0) {
|
||||
rec.setKey(Math.max(1, nextKey));
|
||||
}
|
||||
|
||||
tmpAdapter.updateSymbolRecord(rec);
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
|
||||
return tmpAdapter;
|
||||
}
|
||||
|
||||
private static void copyTempToNewAdapter(SymbolDatabaseAdapter tmpAdapter,
|
||||
SymbolDatabaseAdapter newAdapter, TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
|
||||
RecordIterator iter = tmpAdapter.getSymbols();
|
||||
while (iter.hasNext()) {
|
||||
monitor.checkCanceled();
|
||||
newAdapter.updateSymbolRecord(iter.next());
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new symbol
|
||||
* @param name name of the symbol
|
||||
* @param addr address of the symbol
|
||||
* @param parentSymbolID the id of the containing namespace symbol
|
||||
* @param address the address for the symbol
|
||||
* @param namespaceID the id of the containing namespace symbol
|
||||
* @param symbolType the type of this symbol
|
||||
* @param data1 place to store a long value that depends on the symbol type
|
||||
* @param data2 place to store an int value that depends on the symbol type
|
||||
* @param data3 place to store a String value that depends on the symbol type
|
||||
* @param source the source of this symbol
|
||||
* <br>Some symbol types, such as function symbols, can set the source to Symbol.DEFAULT.
|
||||
* @param stringData place to store a String value that depends on the symbol type
|
||||
* @param source the source type of this symbol
|
||||
* Some symbol types, such as function symbols, can set the source to Symbol.DEFAULT
|
||||
* @param dataTypeId the id of an associated datatype or null if there is no associated datatype
|
||||
* @param varOffset the variable offset will be the ordinal for a parameter or first use offset
|
||||
* for a local variable
|
||||
* @param isPrimary true if the symbol is primary. Only applicable for labels and functions
|
||||
* @return the new record
|
||||
* @throws IOException if there was a problem accessing the database
|
||||
* @throws IllegalArgumentException if you try to set the source to DEFAULT for a symbol type
|
||||
* that doesn't allow it.
|
||||
* that doesn't allow it
|
||||
*/
|
||||
abstract DBRecord createSymbol(String name, Address address, long parentSymbolID,
|
||||
SymbolType symbolType, long data1, int data2, String data3, SourceType source)
|
||||
throws IOException;
|
||||
abstract DBRecord createSymbol(String name, Address address, long namespaceID,
|
||||
SymbolType symbolType, String stringData, Long dataTypeId, Integer varOffset,
|
||||
SourceType source, boolean isPrimary) throws IOException;
|
||||
|
||||
/**
|
||||
* Get the record with the given symbol ID
|
||||
|
@ -160,58 +245,96 @@ abstract class SymbolDatabaseAdapter {
|
|||
abstract boolean hasSymbol(Address addr) throws IOException;
|
||||
|
||||
/**
|
||||
* Get the symbolIDs at the given address.
|
||||
* Get the symbolIDs at the given address
|
||||
* @param addr address to filter on
|
||||
* @return array of database LongField keys contained within a Field array.
|
||||
* @return array of database LongField keys contained within a Field array
|
||||
* @throws IOException if there was a problem accessing the database
|
||||
*/
|
||||
abstract Field[] getSymbolIDs(Address addr) throws IOException;
|
||||
|
||||
/**
|
||||
* Get the number of symbols.
|
||||
* Get the number of symbols
|
||||
* @return the number of symbols
|
||||
*/
|
||||
abstract int getSymbolCount();
|
||||
|
||||
/**
|
||||
* Get an iterator over all the symbols in ascending address order.
|
||||
* @return
|
||||
* Get an iterator over all the symbols in ascending address order
|
||||
* @param forward the direction to iterator
|
||||
* @return a record iterator over all symbols
|
||||
* @throws IOException if there was a problem accessing the database
|
||||
*/
|
||||
abstract RecordIterator getSymbolsByAddress(boolean forward) throws IOException;
|
||||
|
||||
/**
|
||||
* Get an iterator over all the symbols starting at startAddr.
|
||||
* Get an iterator over all the symbols starting at startAddr
|
||||
* @param startAddr start address of where to get symbols
|
||||
* @param forward true to iterate from low to high addresses
|
||||
* @return a record iterator over all symbols starting at the given start address
|
||||
* @throws IOException if there was a problem accessing the database
|
||||
*/
|
||||
abstract RecordIterator getSymbolsByAddress(Address startAddr, boolean forward)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Update the table with the given record.
|
||||
* @param record
|
||||
* Update the table with the given record
|
||||
* @param record the record to update in the database
|
||||
* @throws IOException if there was a problem accessing the database
|
||||
*/
|
||||
abstract void updateSymbolRecord(DBRecord record) throws IOException;
|
||||
|
||||
/**
|
||||
* Get all of the symbols.
|
||||
* @return a record iterator over all symbols
|
||||
* @throws IOException if there was a problem accessing the database
|
||||
*/
|
||||
abstract RecordIterator getSymbols() throws IOException;
|
||||
|
||||
/**
|
||||
* Get symbols in the given range.
|
||||
* @throws IOException if there was a problem accessing the database
|
||||
* Get symbols in the given range
|
||||
* @param start the start address of the range
|
||||
* @param end the last address of the range
|
||||
* @param forward true if iterating from start to end, otherwise iterate from end to start
|
||||
* @return a record iterator for all symbols in the range
|
||||
* @throws IOException if a database io error occurs
|
||||
*/
|
||||
abstract RecordIterator getSymbols(Address start, Address end, boolean forward)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Get symbols in the given range
|
||||
* @param set the set of addresses to iterate over
|
||||
* @param forward true if iterating from start to end, otherwise iterate from end to start
|
||||
* @return a record iterator for all symbols in the range
|
||||
* @throws IOException if a database io error occurs
|
||||
*/
|
||||
abstract RecordIterator getSymbols(AddressSetView set, boolean forward)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Returns an iterator over the primary symbols in the given range
|
||||
* @param set the address set to iterator over when getting primary symbol records
|
||||
* @param forward true if iterating from start to end, otherwise iterate from end to start
|
||||
* @return a record iterator for all symbols in the range
|
||||
* @throws IOException if a database io error occurs
|
||||
*/
|
||||
abstract RecordIterator getPrimarySymbols(AddressSetView set, boolean forward)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Returns the symbol record for the primary symbol at the given address
|
||||
* @param address the address to get its primary symbol record
|
||||
* @return the primary symbol record at the given address or null if no label or function
|
||||
* exists at that address
|
||||
* @throws IOException if a database io error occurs
|
||||
*/
|
||||
abstract DBRecord getPrimarySymbol(Address address) throws IOException;
|
||||
|
||||
/**
|
||||
* Update the address in all records to reflect the movement of a symbol address.
|
||||
* @param oldAddr the original symbol address
|
||||
* @param newAddr the new symbol address
|
||||
* @throws IOException
|
||||
* @throws IOException if a database io error occurs
|
||||
*/
|
||||
abstract void moveAddress(Address oldAddr, Address newAddr) throws IOException;
|
||||
|
||||
|
@ -221,38 +344,125 @@ abstract class SymbolDatabaseAdapter {
|
|||
* @param endAddr maximum address in range
|
||||
* @param monitor progress monitor
|
||||
* @return returns the set of addresses where symbols where not deleted because they were anchored
|
||||
* @throws CancelledException
|
||||
* @throws IOException
|
||||
* @throws CancelledException if the user cancels the operation
|
||||
* @throws IOException if a database io error occurs
|
||||
*/
|
||||
abstract Set<Address> deleteAddressRange(Address startAddr, Address endAddr,
|
||||
TaskMonitor monitor) throws CancelledException, IOException;
|
||||
|
||||
/**
|
||||
* Get all symbols contained within the specified namespace
|
||||
* @param id the namespace id.
|
||||
* @return an iterator over all symbols in the given namespace.
|
||||
* @throws IOException
|
||||
* @param id the namespace id
|
||||
* @return an iterator over all symbols in the given namespace
|
||||
* @throws IOException if a database io error occurs
|
||||
*/
|
||||
abstract RecordIterator getSymbolsByNamespace(long id) throws IOException;
|
||||
|
||||
/**
|
||||
* Get symbols starting with the specified name in name order
|
||||
* @param name name to start with.
|
||||
* @return a record iterator over the symbols.
|
||||
* @throws IOException if a database io error occurs.
|
||||
* Get symbols that have the specified name
|
||||
* @param name name to search
|
||||
* @return a record iterator over the symbols with the given name
|
||||
* @throws IOException if a database io error occurs
|
||||
*/
|
||||
abstract RecordIterator getSymbolsByName(String name) throws IOException;
|
||||
|
||||
/**
|
||||
* Returns the maximum symbol address within the specified address space.
|
||||
* Intended for update use only.
|
||||
* Get all symbols contained in the given {@link Namespace} that have the given name
|
||||
* @param name the symbol name
|
||||
* @param id the id of the parent namespace
|
||||
* @return a record iterator all the symbols in the given namespace with the given name
|
||||
* @throws IOException if a database io error occurs
|
||||
*/
|
||||
abstract RecordIterator getSymbolsByNameAndNamespace(String name, long id) throws IOException;
|
||||
|
||||
/**
|
||||
* Get the symbol Record with the given address, name, and namespace id or null if there is
|
||||
* no match
|
||||
* @param address the symbol address
|
||||
* @param name the symbol name
|
||||
* @param namespaceId the id of the parent namespace of the symbol
|
||||
* @return a record that matches the address, name, and namespaceId or null if there is no match
|
||||
* @throws IOException if a database io error occurs
|
||||
*/
|
||||
abstract DBRecord getSymbolRecord(Address address, String name, long namespaceId)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Returns the maximum symbol address within the specified address space
|
||||
* Intended for update use only
|
||||
* @param space address space
|
||||
* @return maximum symbol address within space or null if none are found.
|
||||
* @return maximum symbol address within space or null if none are found
|
||||
* @throws IOException if a database io error occurs
|
||||
*/
|
||||
abstract Address getMaxSymbolAddress(AddressSpace space) throws IOException;
|
||||
|
||||
/**
|
||||
* Returns the underlying symbol table (for upgrade use only).
|
||||
* Returns the underlying symbol table (for upgrade use only)
|
||||
* @return the database table for this adapter
|
||||
*/
|
||||
abstract Table getTable();
|
||||
|
||||
/**
|
||||
* Computes a hash value for a symbol that facilitates fast lookups of symbols given
|
||||
* a name, namespace, and address. The hash is formed so that it can also be used for fast
|
||||
* lookups of all symbols that have the same name and namespace regardless of address.
|
||||
* @param name the symbol name
|
||||
* @param namespaceID the namespace id
|
||||
* @param addressKey the encoded address
|
||||
* @return a database Long field containing the computed hash
|
||||
*/
|
||||
protected static LongField computeLocatorHash(String name, long namespaceID,
|
||||
long addressKey) {
|
||||
// Default functions have no name, no point in storing a hash for those.
|
||||
if (StringUtils.isEmpty(name)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// store the name/namespace hash in upper 32 bits of the resulting hash and the
|
||||
// addressKey's lower 32 bits in the lower 32 bits of the resulting hash
|
||||
long nameNamespaceHash = Objects.hash(name, namespaceID);
|
||||
long combinedHash = (nameNamespaceHash << 32) | (addressKey & 0xFFFFFFFFL);
|
||||
return new LongField(combinedHash);
|
||||
}
|
||||
|
||||
// This wraps a record iterator to make sure it only returns records for symbols that match
|
||||
// the given name and name space.
|
||||
protected static RecordIterator getNameAndNamespaceFilterIterator(String name,
|
||||
long namespaceId, RecordIterator it) {
|
||||
Query nameQuery = new FieldMatchQuery(SYMBOL_NAME_COL, new StringField(name));
|
||||
Query namespaceQuery = new FieldMatchQuery(SYMBOL_PARENT_COL, new LongField(namespaceId));
|
||||
Query nameAndNamespaceQuery = new AndQuery(nameQuery, namespaceQuery);
|
||||
return new QueryRecordIterator(it, nameAndNamespaceQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a record iterator to make sure it only returns records for symbols that match
|
||||
* the given name and name space and address
|
||||
* @param name the name of the symbol
|
||||
* @param namespaceId the name space id of the symbol
|
||||
* @param addressKey the address key of the symbol
|
||||
* @param it the record iterator to wrap with the query
|
||||
* @return a filtered RecordIterator that only returns records that match the name, name space,
|
||||
* and address
|
||||
*/
|
||||
protected static RecordIterator getNameNamespaceAddressFilterIterator(String name,
|
||||
long namespaceId, long addressKey, RecordIterator it) {
|
||||
Query nameQuery = new FieldMatchQuery(SYMBOL_NAME_COL, new StringField(name));
|
||||
Query namespaceQuery = new FieldMatchQuery(SYMBOL_PARENT_COL, new LongField(namespaceId));
|
||||
Query addressQuery = new FieldMatchQuery(SYMBOL_ADDR_COL, new LongField(addressKey));
|
||||
Query nameAndNamespaceQuery = new AndQuery(nameQuery, namespaceQuery);
|
||||
Query fullQuery = new AndQuery(nameAndNamespaceQuery, addressQuery);
|
||||
return new QueryRecordIterator(it, fullQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a record iterator to filter out any symbols that are not primary
|
||||
* @param it the record iterator to wrap
|
||||
* @return a record iterator that only returns primary symbols
|
||||
*/
|
||||
protected static RecordIterator getPrimaryFilterRecordIterator(RecordIterator it) {
|
||||
Query query = record -> !record.getFieldValue(SYMBOL_PRIMARY_COL).isNull();
|
||||
return new QueryRecordIterator(it, query);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,8 +21,7 @@ import java.util.Set;
|
|||
import db.*;
|
||||
import ghidra.program.database.map.AddressIndexPrimaryKeyIterator;
|
||||
import ghidra.program.database.map.AddressMap;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
@ -58,13 +57,10 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter {
|
|||
private AddressMap addrMap;
|
||||
|
||||
/**
|
||||
* Construct a Version-0 Symbol Table adadpter.
|
||||
* Construct a Version-0 Symbol Table adapter.
|
||||
* @param handle the database handle.
|
||||
* @param addrMap the address map
|
||||
* @param namespaceMgr namespace manager which already contains function namespaces
|
||||
* @throws VersionException if the database version doesn't match this adapter.
|
||||
* @throws IOException if a database io error occurs.
|
||||
* @throws CancelledException if the user cancels the upgrade.
|
||||
*/
|
||||
SymbolDatabaseAdapterV0(DBHandle handle, AddressMap addrMap) throws VersionException {
|
||||
this.addrMap = addrMap.getOldAddressMap();
|
||||
|
@ -77,10 +73,22 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores local symbols information in a temporary database table because this version
|
||||
* is so old, we don't have enough information in the record to upgrade during the normal
|
||||
* upgrade time. So we store off the information and will complete this upgrade when
|
||||
* {@link SymbolManager#programReady(int, int, TaskMonitor)} is called
|
||||
*
|
||||
* @param handle handle to temporary database
|
||||
* @param monitor the {@link TaskMonitor}
|
||||
* @return the next available database key after all the records are store
|
||||
* @throws IOException if a database I/O error occurs
|
||||
* @throws CancelledException if the user cancels the upgrade
|
||||
*/
|
||||
long extractLocalSymbols(DBHandle handle, TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
|
||||
monitor.setMessage("Extracting Local and Dynamic Symbols...");
|
||||
monitor.setMessage("Extracting Local Symbols...");
|
||||
monitor.initialize(symbolTable.getRecordCount());
|
||||
int cnt = 0;
|
||||
RecordIterator iter = symbolTable.iterator();
|
||||
|
@ -106,22 +114,36 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter {
|
|||
throw new AssertException("Unexpected Symbol");
|
||||
}
|
||||
DBRecord rec = SymbolDatabaseAdapter.SYMBOL_SCHEMA.createRecord(record.getKey());
|
||||
rec.setString(SymbolDatabaseAdapter.SYMBOL_NAME_COL, record.getString(V0_SYMBOL_NAME_COL));
|
||||
|
||||
String symbolName = record.getString(V0_SYMBOL_NAME_COL);
|
||||
rec.setString(SymbolDatabaseAdapter.SYMBOL_NAME_COL, symbolName);
|
||||
long addressKey = record.getLongValue(V0_SYMBOL_ADDR_COL);
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL,
|
||||
record.getLongValue(V0_SYMBOL_ADDR_COL));
|
||||
rec.setIntValue(SymbolDatabaseAdapter.SYMBOL_DATA2_COL,
|
||||
record.getBooleanValue(V0_SYMBOL_PRIMARY_COL) ? 1 : 0);
|
||||
addressKey);
|
||||
|
||||
boolean isPrimary = record.getBooleanValue(V0_SYMBOL_PRIMARY_COL);
|
||||
if (isPrimary) {
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL, addressKey);
|
||||
}
|
||||
|
||||
rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_TYPE_COL, SymbolType.LABEL.getID());
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATA1_COL, -1); // not applicable
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL, Namespace.GLOBAL_NAMESPACE_ID);
|
||||
|
||||
long namespaceId = Namespace.GLOBAL_NAMESPACE_ID;
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL, namespaceId);
|
||||
|
||||
rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL,
|
||||
(byte) SourceType.USER_DEFINED.ordinal());
|
||||
|
||||
Field hash = computeLocatorHash(symbolName, namespaceId, addressKey);
|
||||
rec.setField(SymbolDatabaseAdapter.SYMBOL_HASH_COL, hash);
|
||||
|
||||
return rec;
|
||||
}
|
||||
|
||||
@Override
|
||||
DBRecord createSymbol(String name, Address address, long namespaceID, SymbolType symbolType,
|
||||
long data1, int data2, String data3, SourceType source) {
|
||||
String stringData, Long dataTypeId, Integer varOffset, SourceType source,
|
||||
boolean isPrimary) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
@ -175,16 +197,37 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter {
|
|||
|
||||
@Override
|
||||
RecordIterator getSymbols(Address start, Address end, boolean forward) throws IOException {
|
||||
|
||||
if (!forward)
|
||||
throw new UnsupportedOperationException();
|
||||
//TODO: Is there any reason we need to support reverse symbol iteration ???
|
||||
// Yes, to search text backwards!
|
||||
return new V0ConvertedRecordIterator(
|
||||
new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
V0_SYMBOL_ADDR_COL, addrMap, start, end, forward)));
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbols(AddressSetView set, boolean forward) throws IOException {
|
||||
return new V0ConvertedRecordIterator(
|
||||
new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
V0_SYMBOL_ADDR_COL, addrMap, set, forward)));
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getPrimarySymbols(AddressSetView set, boolean forward)
|
||||
throws IOException {
|
||||
KeyToRecordIterator it =
|
||||
new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
SYMBOL_ADDR_COL, addrMap, set, forward));
|
||||
|
||||
return getPrimaryFilterRecordIterator(new V0ConvertedRecordIterator(it));
|
||||
}
|
||||
|
||||
@Override
|
||||
DBRecord getPrimarySymbol(Address address) throws IOException {
|
||||
RecordIterator it = getPrimarySymbols(new AddressSet(address, address), true);
|
||||
if (it.hasNext()) {
|
||||
return it.next();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
void moveAddress(Address oldAddr, Address newAddr) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
|
@ -219,8 +262,7 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter {
|
|||
|
||||
/**
|
||||
* Construct a symbol filtered record iterator
|
||||
* @param iter
|
||||
* @param locals if true
|
||||
* @param symIter the {@link RecordIterator} to wrap so that records are adapter to new schema
|
||||
*/
|
||||
V0ConvertedRecordIterator(RecordIterator symIter) {
|
||||
this.symIter = symIter;
|
||||
|
@ -277,4 +319,23 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter {
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbolsByNameAndNamespace(String name, long id) throws IOException {
|
||||
RecordIterator symbolsByName = getSymbolsByName(name);
|
||||
return getNameAndNamespaceFilterIterator(name, id, symbolsByName);
|
||||
}
|
||||
|
||||
@Override
|
||||
DBRecord getSymbolRecord(Address address, String name, long id) throws IOException {
|
||||
StringField value = new StringField(name);
|
||||
RecordIterator it = symbolTable.indexIterator(SYMBOL_NAME_COL, value, value, true);
|
||||
long addressKey = addrMap.getKey(address, false);
|
||||
RecordIterator filtered =
|
||||
getNameNamespaceAddressFilterIterator(name, id, addressKey, it);
|
||||
if (filtered.hasNext()) {
|
||||
return filtered.next();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,8 +21,7 @@ import java.util.Set;
|
|||
import db.*;
|
||||
import ghidra.program.database.map.AddressIndexPrimaryKeyIterator;
|
||||
import ghidra.program.database.map.AddressMap;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.VersionException;
|
||||
|
@ -72,7 +71,8 @@ class SymbolDatabaseAdapterV1 extends SymbolDatabaseAdapter {
|
|||
|
||||
@Override
|
||||
DBRecord createSymbol(String name, Address address, long namespaceID, SymbolType symbolType,
|
||||
long data1, int data2, String data3, SourceType source) {
|
||||
String stringData, Long dataTypeId, Integer varOffset, SourceType source,
|
||||
boolean isPrimary) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
@ -116,20 +116,21 @@ class SymbolDatabaseAdapterV1 extends SymbolDatabaseAdapter {
|
|||
DBRecord rec = SymbolDatabaseAdapter.SYMBOL_SCHEMA.createRecord(record.getKey());
|
||||
String symbolName = record.getString(V1_SYMBOL_NAME_COL);
|
||||
rec.setString(SymbolDatabaseAdapter.SYMBOL_NAME_COL, symbolName);
|
||||
|
||||
long symbolAddrKey = record.getLongValue(V1_SYMBOL_ADDR_COL);
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL, symbolAddrKey);
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL,
|
||||
record.getLongValue(V1_SYMBOL_PARENT_COL));
|
||||
byte symbolType = record.getByteValue(V1_SYMBOL_TYPE_COL);
|
||||
rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_TYPE_COL, symbolType);
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATA1_COL,
|
||||
record.getLongValue(V1_SYMBOL_DATA1_COL));
|
||||
rec.setIntValue(SymbolDatabaseAdapter.SYMBOL_DATA2_COL,
|
||||
record.getIntValue(V1_SYMBOL_DATA2_COL));
|
||||
rec.setString(SymbolDatabaseAdapter.SYMBOL_DATA3_COL,
|
||||
|
||||
long namespaceId = record.getLongValue(V1_SYMBOL_PARENT_COL);
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL, namespaceId);
|
||||
|
||||
byte symbolTypeId = record.getByteValue(V1_SYMBOL_TYPE_COL);
|
||||
rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_TYPE_COL, symbolTypeId);
|
||||
|
||||
rec.setString(SymbolDatabaseAdapter.SYMBOL_STRING_DATA_COL,
|
||||
record.getString(V1_SYMBOL_COMMENT_COL));
|
||||
|
||||
SourceType source = SourceType.USER_DEFINED;
|
||||
if (symbolType == SymbolType.FUNCTION.getID()) {
|
||||
if (symbolTypeId == SymbolType.FUNCTION.getID()) {
|
||||
Address symbolAddress = addrMap.decodeAddress(symbolAddrKey);
|
||||
String defaultName = SymbolUtilities.getDefaultFunctionName(symbolAddress);
|
||||
if (symbolName.equals(defaultName)) {
|
||||
|
@ -137,6 +138,33 @@ class SymbolDatabaseAdapterV1 extends SymbolDatabaseAdapter {
|
|||
}
|
||||
}
|
||||
rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL, (byte) source.ordinal());
|
||||
|
||||
long dataTypeId = record.getLongValue(V1_SYMBOL_DATA1_COL);
|
||||
if (dataTypeId != -1) {
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL, dataTypeId);
|
||||
}
|
||||
|
||||
SymbolType type = SymbolType.getSymbolType(symbolTypeId);
|
||||
int data2 = record.getIntValue(V1_SYMBOL_DATA2_COL);
|
||||
// The data1 field was used in two ways for label symbols, it stored a 1 for primary and 0
|
||||
// for non-primary. If the type was a parameter or variable, it stored the ordinal or
|
||||
// first use offset respectively.
|
||||
if (SymbolType.LABEL.equals(type)) {
|
||||
if (data2 == 1) { // if it was primary, put the address in the indexed primary col
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL, symbolAddrKey);
|
||||
}
|
||||
}
|
||||
else if (SymbolType.PARAMETER.equals(type) || SymbolType.LOCAL_VAR.equals(type)) {
|
||||
rec.setIntValue(SymbolDatabaseAdapter.SYMBOL_VAROFFSET_COL, data2);
|
||||
}
|
||||
|
||||
// also need to store primary for functions
|
||||
if (SymbolType.FUNCTION.equals(type)) {
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL, symbolAddrKey);
|
||||
}
|
||||
Field hash = computeLocatorHash(symbolName, namespaceId, symbolAddrKey);
|
||||
rec.setField(SymbolDatabaseAdapter.SYMBOL_HASH_COL, hash);
|
||||
|
||||
return rec;
|
||||
}
|
||||
|
||||
|
@ -175,8 +203,30 @@ class SymbolDatabaseAdapterV1 extends SymbolDatabaseAdapter {
|
|||
V1_SYMBOL_ADDR_COL, addrMap, start, end, forward)));
|
||||
}
|
||||
|
||||
RecordIterator getSymbolsByName() throws IOException {
|
||||
return new V1ConvertedRecordIterator(symbolTable.indexIterator(V1_SYMBOL_NAME_COL));
|
||||
@Override
|
||||
RecordIterator getSymbols(AddressSetView set, boolean forward) throws IOException {
|
||||
return new V1ConvertedRecordIterator(
|
||||
new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
V1_SYMBOL_ADDR_COL, addrMap, set, forward)));
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getPrimarySymbols(AddressSetView set, boolean forward)
|
||||
throws IOException {
|
||||
KeyToRecordIterator it =
|
||||
new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
SYMBOL_ADDR_COL, addrMap, set, forward));
|
||||
|
||||
return getPrimaryFilterRecordIterator(new V1ConvertedRecordIterator(it));
|
||||
}
|
||||
|
||||
@Override
|
||||
DBRecord getPrimarySymbol(Address address) throws IOException {
|
||||
RecordIterator it = getPrimarySymbols(new AddressSet(address, address), true);
|
||||
if (it.hasNext()) {
|
||||
return it.next();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -225,4 +275,23 @@ class SymbolDatabaseAdapterV1 extends SymbolDatabaseAdapter {
|
|||
Address getMaxSymbolAddress(AddressSpace space) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbolsByNameAndNamespace(String name, long id) throws IOException {
|
||||
RecordIterator symbolsByName = getSymbolsByName(name);
|
||||
return getNameAndNamespaceFilterIterator(name, id, symbolsByName);
|
||||
}
|
||||
|
||||
@Override
|
||||
DBRecord getSymbolRecord(Address address, String name, long id) throws IOException {
|
||||
RecordIterator it = getSymbolsByName(name);
|
||||
long addressKey = addrMap.getKey(address, false);
|
||||
RecordIterator filtered =
|
||||
getNameNamespaceAddressFilterIterator(name, id, addressKey, it);
|
||||
if (filtered.hasNext()) {
|
||||
return filtered.next();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,10 +22,11 @@ import java.util.Set;
|
|||
import db.*;
|
||||
import ghidra.program.database.map.*;
|
||||
import ghidra.program.database.util.RecordFilter;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.program.model.symbol.SymbolType;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.VersionException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
|
@ -33,20 +34,31 @@ import ghidra.util.task.TaskMonitor;
|
|||
*/
|
||||
class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter {
|
||||
|
||||
/* Do not remove the following commented out schema! It shows the version 2 symbol table schema. */
|
||||
// static final Schema SYMBOL_SCHEMA = new Schema(2, "Key",
|
||||
// new Field[] { StringField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE,
|
||||
// ByteField.INSTANCE, LongField.INSTANCE, IntField.INSTANCE, StringField.INSTANCE,
|
||||
// ByteField.INSTANCE },
|
||||
// new String[] { "Name", "Address", "Parent", "Symbol Type", "SymbolData1", "SymbolData2",
|
||||
// "SymbolData3", "Flags" });
|
||||
|
||||
private static final int SYMBOL_VERSION = 2;
|
||||
private Table symbolTable;
|
||||
private AddressMap addrMap;
|
||||
|
||||
SymbolDatabaseAdapterV2(DBHandle handle, AddressMap addrMap, boolean create)
|
||||
throws VersionException, IOException {
|
||||
static final int V2_SYMBOL_NAME_COL = 0;
|
||||
static final int V2_SYMBOL_ADDR_COL = 1;
|
||||
static final int V2_SYMBOL_PARENT_COL = 2;
|
||||
static final int V2_SYMBOL_TYPE_COL = 3;
|
||||
static final int V2_SYMBOL_DATA1_COL = 4;
|
||||
static final int V2_SYMBOL_DATA2_COL = 5;
|
||||
static final int V2_SYMBOL_DATA3_COL = 6;
|
||||
static final int V2_SYMBOL_FLAGS_COL = 7;
|
||||
|
||||
SymbolDatabaseAdapterV2(DBHandle handle, AddressMap addrMap)
|
||||
throws VersionException {
|
||||
|
||||
this.addrMap = addrMap;
|
||||
if (create) {
|
||||
|
||||
symbolTable = handle.createTable(SYMBOL_TABLE_NAME, SYMBOL_SCHEMA,
|
||||
new int[] { SYMBOL_ADDR_COL, SYMBOL_NAME_COL, SYMBOL_PARENT_COL });
|
||||
}
|
||||
else {
|
||||
symbolTable = handle.getTable(SYMBOL_TABLE_NAME);
|
||||
if (symbolTable == null) {
|
||||
throw new VersionException("Missing Table: " + SYMBOL_TABLE_NAME);
|
||||
|
@ -59,159 +71,17 @@ class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter {
|
|||
throw new VersionException(VersionException.NEWER_VERSION, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static SymbolDatabaseAdapter upgrade(DBHandle dbHandle, AddressMap addrMap,
|
||||
SymbolDatabaseAdapter oldAdapter, TaskMonitor monitor)
|
||||
throws VersionException, IOException, CancelledException {
|
||||
|
||||
AddressMap oldAddrMap = addrMap.getOldAddressMap();
|
||||
|
||||
DBHandle tmpHandle = dbHandle.getScratchPad();
|
||||
long nextKey = 1;
|
||||
try {
|
||||
if (oldAdapter instanceof SymbolDatabaseAdapterV0) {
|
||||
// Defer upgrade of local symbols and remove dynamic symbols
|
||||
nextKey =
|
||||
((SymbolDatabaseAdapterV0) oldAdapter).extractLocalSymbols(tmpHandle, monitor);
|
||||
}
|
||||
|
||||
monitor.setMessage("Upgrading Symbol Table...");
|
||||
monitor.initialize((oldAdapter.getSymbolCount()) * 2);
|
||||
int count = 0;
|
||||
|
||||
SymbolDatabaseAdapterV2 tmpAdapter =
|
||||
new SymbolDatabaseAdapterV2(tmpHandle, addrMap, true);
|
||||
RecordIterator iter = oldAdapter.getSymbols();
|
||||
DBRecord zeroRecord = null;
|
||||
while (iter.hasNext()) {
|
||||
if (monitor.isCancelled()) {
|
||||
throw new CancelledException();
|
||||
}
|
||||
DBRecord rec = iter.next();
|
||||
Address addr = oldAddrMap.decodeAddress(rec.getLongValue(SYMBOL_ADDR_COL));
|
||||
rec.setLongValue(SYMBOL_ADDR_COL, addrMap.getKey(addr, true));
|
||||
if (rec.getKey() == 0) {
|
||||
zeroRecord = rec;
|
||||
}
|
||||
else {
|
||||
tmpAdapter.symbolTable.putRecord(rec);
|
||||
}
|
||||
monitor.setProgress(++count);
|
||||
}
|
||||
if (zeroRecord != null) {
|
||||
tmpAdapter.createSymbol(Math.max(1, nextKey), zeroRecord);
|
||||
}
|
||||
// TODO keep this until I fix up SymbolManager
|
||||
// AddressKeyIterator entryPts = oldAdapter.getExternalEntryInterator();
|
||||
// while (entryPts.hasNext()) {
|
||||
// if (monitor.isCancelled()) {
|
||||
// throw new CancelledException();
|
||||
// }
|
||||
// Address addr = oldAddrMap.decodeAddress(entryPts.next());
|
||||
// tmpAdapter.setExternalEntry(addr);
|
||||
// monitor.setProgress(++count);
|
||||
// }
|
||||
|
||||
dbHandle.deleteTable(SYMBOL_TABLE_NAME);
|
||||
SymbolDatabaseAdapterV2 newAdapter =
|
||||
new SymbolDatabaseAdapterV2(dbHandle, addrMap, true);
|
||||
|
||||
iter = tmpAdapter.getSymbols();
|
||||
while (iter.hasNext()) {
|
||||
if (monitor.isCancelled()) {
|
||||
throw new CancelledException();
|
||||
}
|
||||
DBRecord rec = iter.next();
|
||||
|
||||
// Make sure user symbols do not start with reserved prefix
|
||||
String name = rec.getString(SYMBOL_NAME_COL);
|
||||
if (SymbolUtilities.startsWithDefaultDynamicPrefix(name)) {
|
||||
rec.setString(SYMBOL_NAME_COL,
|
||||
fixSymbolName(tmpAdapter, name, rec.getLongValue(SYMBOL_PARENT_COL)));
|
||||
}
|
||||
|
||||
// TODO May want to check for default name to set flags when upgrading.
|
||||
// long addr = rec.getLongValue(SYMBOL_ADDR_COL);
|
||||
// Address address = addrMap.decodeAddress(addr);
|
||||
// String defaultName = ???;
|
||||
// byte flags = name.equals(defaultName) ? SYMBOL_DEFAULT_FLAG : SYMBOL_USER_DEFINED_FLAG;
|
||||
// rec.setByteValue(SYMBOL_FLAGS_COL, SYMBOL_USER_DEFINED_FLAG);
|
||||
|
||||
newAdapter.symbolTable.putRecord(rec);
|
||||
monitor.setProgress(++count);
|
||||
}
|
||||
return newAdapter;
|
||||
}
|
||||
finally {
|
||||
tmpHandle.deleteTable(SYMBOL_TABLE_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param zeroRecord
|
||||
* @throws IOException
|
||||
*/
|
||||
private void createSymbol(long nextKey, DBRecord zeroRecord) throws IOException {
|
||||
zeroRecord.setKey(nextKey);
|
||||
symbolTable.putRecord(zeroRecord);
|
||||
}
|
||||
|
||||
private static String fixSymbolName(SymbolDatabaseAdapter tmpAdapter, String name,
|
||||
long namespaceId) throws IOException {
|
||||
String baseName = "_" + name; // dynamic prefix is reserved
|
||||
String newName = baseName;
|
||||
int cnt = 0;
|
||||
while (true) {
|
||||
try {
|
||||
RecordIterator iter = tmpAdapter.getSymbolsByName(newName);
|
||||
while (iter.hasNext()) {
|
||||
DBRecord otherRec = iter.next();
|
||||
if (namespaceId == otherRec.getLongValue(SYMBOL_PARENT_COL)) {
|
||||
throw new DuplicateNameException();
|
||||
}
|
||||
}
|
||||
return newName;
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
newName = baseName + "_" + (++cnt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
DBRecord createSymbol(String name, Address address, long namespaceID, SymbolType symbolType,
|
||||
long data1, int data2, String data3, SourceType source) throws IOException {
|
||||
long nextID = symbolTable.getKey();
|
||||
|
||||
// avoiding key 0, because we use the negative of the address offset as keys for dynamic symbols
|
||||
if (nextID == 0) {
|
||||
nextID++;
|
||||
}
|
||||
return createSymbol(nextID, name, address, namespaceID, symbolType, data1, data2, data3,
|
||||
(byte) source.ordinal());
|
||||
}
|
||||
|
||||
private DBRecord createSymbol(long id, String name, Address address, long namespaceID,
|
||||
SymbolType symbolType, long data1, int data2, String data3, byte flags)
|
||||
throws IOException {
|
||||
|
||||
DBRecord rec = symbolTable.getSchema().createRecord(id);
|
||||
rec.setString(SYMBOL_NAME_COL, name);
|
||||
rec.setLongValue(SYMBOL_ADDR_COL, addrMap.getKey(address, true));
|
||||
rec.setLongValue(SYMBOL_PARENT_COL, namespaceID);
|
||||
rec.setByteValue(SYMBOL_TYPE_COL, symbolType.getID());
|
||||
rec.setLongValue(SYMBOL_DATA1_COL, data1);
|
||||
rec.setIntValue(SYMBOL_DATA2_COL, data2);
|
||||
rec.setString(SYMBOL_DATA3_COL, data3);
|
||||
rec.setByteValue(SYMBOL_FLAGS_COL, flags);
|
||||
symbolTable.putRecord(rec);
|
||||
return rec;
|
||||
String stringData, Long dataTypeId, Integer varOffset, SourceType source,
|
||||
boolean isPrimary) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
void removeSymbol(long symbolID) throws IOException {
|
||||
symbolTable.deleteRecord(symbolID);
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -234,7 +104,7 @@ class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter {
|
|||
|
||||
@Override
|
||||
DBRecord getSymbolRecord(long symbolID) throws IOException {
|
||||
return symbolTable.getRecord(symbolID);
|
||||
return convertV2Record(symbolTable.getRecord(symbolID));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -244,30 +114,62 @@ class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter {
|
|||
|
||||
@Override
|
||||
RecordIterator getSymbolsByAddress(boolean forward) throws IOException {
|
||||
return new KeyToRecordIterator(symbolTable,
|
||||
KeyToRecordIterator it = new KeyToRecordIterator(symbolTable,
|
||||
new AddressIndexPrimaryKeyIterator(symbolTable, SYMBOL_ADDR_COL, addrMap, forward));
|
||||
return new V2ConvertedRecordIterator(it);
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbolsByAddress(Address startAddr, boolean forward) throws IOException {
|
||||
return new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
KeyToRecordIterator it =
|
||||
new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
SYMBOL_ADDR_COL, addrMap, startAddr, forward));
|
||||
return new V2ConvertedRecordIterator(it);
|
||||
}
|
||||
|
||||
@Override
|
||||
void updateSymbolRecord(DBRecord record) throws IOException {
|
||||
symbolTable.putRecord(record);
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbols() throws IOException {
|
||||
return symbolTable.iterator();
|
||||
return new V2ConvertedRecordIterator(symbolTable.iterator());
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbols(Address start, Address end, boolean forward) throws IOException {
|
||||
return new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
KeyToRecordIterator it =
|
||||
new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
SYMBOL_ADDR_COL, addrMap, start, end, forward));
|
||||
return new V2ConvertedRecordIterator(it);
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbols(AddressSetView set, boolean forward) throws IOException {
|
||||
KeyToRecordIterator it =
|
||||
new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
SYMBOL_ADDR_COL, addrMap, set, forward));
|
||||
return new V2ConvertedRecordIterator(it);
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getPrimarySymbols(AddressSetView set, boolean forward)
|
||||
throws IOException {
|
||||
KeyToRecordIterator it =
|
||||
new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
SYMBOL_ADDR_COL, addrMap, set, forward));
|
||||
|
||||
return getPrimaryFilterRecordIterator(new V2ConvertedRecordIterator(it));
|
||||
}
|
||||
|
||||
@Override
|
||||
DBRecord getPrimarySymbol(Address address) throws IOException {
|
||||
RecordIterator it = getPrimarySymbols(new AddressSet(address, address), true);
|
||||
if (it.hasNext()) {
|
||||
return it.next();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -316,13 +218,15 @@ class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter {
|
|||
@Override
|
||||
RecordIterator getSymbolsByNamespace(long id) throws IOException {
|
||||
LongField field = new LongField(id);
|
||||
return symbolTable.indexIterator(SYMBOL_PARENT_COL, field, field, true);
|
||||
RecordIterator it = symbolTable.indexIterator(SYMBOL_PARENT_COL, field, field, true);
|
||||
return new V2ConvertedRecordIterator(it);
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbolsByName(String name) throws IOException {
|
||||
StringField field = new StringField(name);
|
||||
return symbolTable.indexIterator(SYMBOL_NAME_COL, field, field, true);
|
||||
RecordIterator it = symbolTable.indexIterator(SYMBOL_NAME_COL, field, field, true);
|
||||
return new V2ConvertedRecordIterator(it);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -353,4 +257,97 @@ class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter {
|
|||
Table getTable() {
|
||||
return symbolTable;
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbolsByNameAndNamespace(String name, long id) throws IOException {
|
||||
StringField value = new StringField(name);
|
||||
RecordIterator it = symbolTable.indexIterator(SYMBOL_NAME_COL, value, value, true);
|
||||
RecordIterator filtered = getNameAndNamespaceFilterIterator(name, id, it);
|
||||
return new V2ConvertedRecordIterator(filtered);
|
||||
}
|
||||
|
||||
@Override
|
||||
DBRecord getSymbolRecord(Address address, String name, long id) throws IOException {
|
||||
StringField value = new StringField(name);
|
||||
RecordIterator it = symbolTable.indexIterator(SYMBOL_NAME_COL, value, value, true);
|
||||
long addressKey = addrMap.getKey(address, false);
|
||||
RecordIterator filtered =
|
||||
getNameNamespaceAddressFilterIterator(name, id, addressKey, it);
|
||||
if (filtered.hasNext()) {
|
||||
return filtered.next();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a record matching the current database schema from the version 2 record.
|
||||
* @param record the record matching the version 2 schema.
|
||||
* @return a current symbol record.
|
||||
*/
|
||||
private DBRecord convertV2Record(DBRecord record) {
|
||||
if (record == null) {
|
||||
return null;
|
||||
}
|
||||
DBRecord rec = SymbolDatabaseAdapter.SYMBOL_SCHEMA.createRecord(record.getKey());
|
||||
|
||||
String symbolName = record.getString(V2_SYMBOL_NAME_COL);
|
||||
rec.setString(SymbolDatabaseAdapter.SYMBOL_NAME_COL, symbolName);
|
||||
|
||||
long symbolAddrKey = record.getLongValue(V2_SYMBOL_ADDR_COL);
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL, symbolAddrKey);
|
||||
|
||||
long namespaceId = record.getLongValue(V2_SYMBOL_PARENT_COL);
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL, namespaceId);
|
||||
|
||||
byte symbolTypeId = record.getByteValue(V2_SYMBOL_TYPE_COL);
|
||||
rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_TYPE_COL, symbolTypeId);
|
||||
|
||||
rec.setString(SymbolDatabaseAdapter.SYMBOL_STRING_DATA_COL,
|
||||
record.getString(V2_SYMBOL_DATA3_COL));
|
||||
|
||||
Field hash = computeLocatorHash(symbolName, namespaceId, symbolAddrKey);
|
||||
rec.setField(SymbolDatabaseAdapter.SYMBOL_HASH_COL, hash);
|
||||
|
||||
rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL,
|
||||
record.getByteValue(V2_SYMBOL_FLAGS_COL));
|
||||
|
||||
long dataTypeId = record.getLongValue(V2_SYMBOL_DATA1_COL);
|
||||
if (dataTypeId != -1) {
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL, dataTypeId);
|
||||
}
|
||||
|
||||
SymbolType type = SymbolType.getSymbolType(symbolTypeId);
|
||||
int data2 = record.getIntValue(V2_SYMBOL_DATA2_COL);
|
||||
// The data1 field was used in two ways for label symbols, it stored a 1 for primary and 0
|
||||
// for non-primary. If the type was a parameter or variable, it stored the ordinal or
|
||||
// first use offset respectively
|
||||
if (SymbolType.LABEL.equals(type)) {
|
||||
if (data2 == 1) { // if it was primary, put the address in the indexed primary col
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL, symbolAddrKey);
|
||||
}
|
||||
}
|
||||
else if (SymbolType.PARAMETER.equals(type) || SymbolType.LOCAL_VAR.equals(type)) {
|
||||
rec.setIntValue(SymbolDatabaseAdapter.SYMBOL_VAROFFSET_COL, data2);
|
||||
}
|
||||
|
||||
// also need to store primary for functions
|
||||
if (SymbolType.FUNCTION.equals(type)) {
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL, symbolAddrKey);
|
||||
}
|
||||
|
||||
return rec;
|
||||
}
|
||||
|
||||
private class V2ConvertedRecordIterator extends ConvertedRecordIterator {
|
||||
|
||||
V2ConvertedRecordIterator(RecordIterator originalIterator) {
|
||||
super(originalIterator, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DBRecord convertRecord(DBRecord record) {
|
||||
return convertV2Record(record);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,348 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.database.symbol;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import db.*;
|
||||
import ghidra.program.database.map.*;
|
||||
import ghidra.program.database.util.EmptyRecordIterator;
|
||||
import ghidra.program.database.util.RecordFilter;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.program.model.symbol.SymbolType;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.VersionException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* SymbolDatabaseAdapter for version 3
|
||||
*
|
||||
* This version provides for fast symbol lookup by namespace and name.
|
||||
* It was created in June 2021 with ProgramDB version 24.
|
||||
* It will be included in Ghidra starting at version 10.1
|
||||
*/
|
||||
class SymbolDatabaseAdapterV3 extends SymbolDatabaseAdapter {
|
||||
|
||||
static final int SYMBOL_VERSION = 3;
|
||||
|
||||
// Used to create a range when searching symbols by name/namespace but don't care about address
|
||||
private static final long MIN_ADDRESS_OFFSET = 0;
|
||||
private static final long MAX_ADDRESS_OFFSET = -1;
|
||||
|
||||
// NOTE: the primary field duplicates the symbol's address when the symbol is primary. This
|
||||
// allows us to index this field and quickly find the primary symbols. The field is sparse
|
||||
// so that non-primary symbols don't consume any space for this field.
|
||||
|
||||
static final Schema V3_SYMBOL_SCHEMA = new Schema(SYMBOL_VERSION, "Key",
|
||||
new Field[] { StringField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE,
|
||||
ByteField.INSTANCE, StringField.INSTANCE, ByteField.INSTANCE,
|
||||
LongField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE, IntField.INSTANCE },
|
||||
new String[] { "Name", "Address", "Namespace", "Symbol Type", "String Data", "Flags",
|
||||
"Locator Hash", "Primary", "Datatype", "Variable Offset" },
|
||||
new int[] { SYMBOL_HASH_COL, SYMBOL_PRIMARY_COL, SYMBOL_DATATYPE_COL,
|
||||
SYMBOL_VAROFFSET_COL });
|
||||
|
||||
private Table symbolTable;
|
||||
private AddressMap addrMap;
|
||||
|
||||
SymbolDatabaseAdapterV3(DBHandle handle, AddressMap addrMap, boolean create)
|
||||
throws VersionException, IOException {
|
||||
|
||||
this.addrMap = addrMap;
|
||||
if (create) {
|
||||
symbolTable = handle.createTable(SYMBOL_TABLE_NAME, SYMBOL_SCHEMA,
|
||||
new int[] { SYMBOL_ADDR_COL, SYMBOL_NAME_COL, SYMBOL_PARENT_COL, SYMBOL_HASH_COL,
|
||||
SYMBOL_PRIMARY_COL });
|
||||
}
|
||||
else {
|
||||
symbolTable = handle.getTable(SYMBOL_TABLE_NAME);
|
||||
if (symbolTable == null) {
|
||||
throw new VersionException("Missing Table: " + SYMBOL_TABLE_NAME);
|
||||
}
|
||||
if (symbolTable.getSchema().getVersion() != SYMBOL_VERSION) {
|
||||
int version = symbolTable.getSchema().getVersion();
|
||||
if (version < SYMBOL_VERSION) {
|
||||
throw new VersionException(true);
|
||||
}
|
||||
throw new VersionException(VersionException.NEWER_VERSION, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
DBRecord createSymbol(String name, Address address, long namespaceID, SymbolType symbolType,
|
||||
String stringData, Long dataTypeId, Integer varOffset, SourceType source,
|
||||
boolean isPrimary) throws IOException {
|
||||
long nextID = symbolTable.getKey();
|
||||
|
||||
// avoiding key 0, as it is reserved for the global namespace
|
||||
if (nextID == 0) {
|
||||
nextID++;
|
||||
}
|
||||
return createSymbol(nextID, name, address, namespaceID, symbolType, stringData,
|
||||
(byte) source.ordinal(), dataTypeId, varOffset, isPrimary);
|
||||
}
|
||||
|
||||
private DBRecord createSymbol(long id, String name, Address address, long namespaceID,
|
||||
SymbolType symbolType, String stringData, byte flags,
|
||||
Long dataTypeId, Integer varOffset, boolean isPrimary) throws IOException {
|
||||
|
||||
long addressKey = addrMap.getKey(address, true);
|
||||
|
||||
DBRecord rec = symbolTable.getSchema().createRecord(id);
|
||||
rec.setString(SYMBOL_NAME_COL, name);
|
||||
rec.setLongValue(SYMBOL_ADDR_COL, addressKey);
|
||||
rec.setLongValue(SYMBOL_PARENT_COL, namespaceID);
|
||||
rec.setByteValue(SYMBOL_TYPE_COL, symbolType.getID());
|
||||
rec.setString(SYMBOL_STRING_DATA_COL, stringData);
|
||||
rec.setByteValue(SYMBOL_FLAGS_COL, flags);
|
||||
|
||||
// sparse columns - these columns don't apply to all symbols.
|
||||
// they default to null unless specifically set. Null values don't consume space.
|
||||
|
||||
rec.setField(SYMBOL_HASH_COL,
|
||||
computeLocatorHash(name, namespaceID, addressKey));
|
||||
|
||||
if (isPrimary) {
|
||||
rec.setLongValue(SYMBOL_PRIMARY_COL, addressKey);
|
||||
}
|
||||
|
||||
if (dataTypeId != null) {
|
||||
rec.setLongValue(SYMBOL_DATATYPE_COL, dataTypeId);
|
||||
}
|
||||
|
||||
if (varOffset != null) {
|
||||
rec.setIntValue(SYMBOL_VAROFFSET_COL, varOffset);
|
||||
}
|
||||
|
||||
symbolTable.putRecord(rec);
|
||||
return rec;
|
||||
}
|
||||
|
||||
@Override
|
||||
void removeSymbol(long symbolID) throws IOException {
|
||||
symbolTable.deleteRecord(symbolID);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean hasSymbol(Address addr) throws IOException {
|
||||
long key = addrMap.getKey(addr, false);
|
||||
if (key == AddressMap.INVALID_ADDRESS_KEY && !addr.equals(Address.NO_ADDRESS)) {
|
||||
return false;
|
||||
}
|
||||
return symbolTable.hasRecord(new LongField(key), SYMBOL_ADDR_COL);
|
||||
}
|
||||
|
||||
@Override
|
||||
Field[] getSymbolIDs(Address addr) throws IOException {
|
||||
long key = addrMap.getKey(addr, false);
|
||||
if (key == AddressMap.INVALID_ADDRESS_KEY && !addr.equals(Address.NO_ADDRESS)) {
|
||||
return Field.EMPTY_ARRAY;
|
||||
}
|
||||
return symbolTable.findRecords(new LongField(key), SYMBOL_ADDR_COL);
|
||||
}
|
||||
|
||||
@Override
|
||||
DBRecord getSymbolRecord(long symbolID) throws IOException {
|
||||
return symbolTable.getRecord(symbolID);
|
||||
}
|
||||
|
||||
@Override
|
||||
int getSymbolCount() {
|
||||
return symbolTable.getRecordCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbolsByAddress(boolean forward) throws IOException {
|
||||
return new KeyToRecordIterator(symbolTable,
|
||||
new AddressIndexPrimaryKeyIterator(symbolTable, SYMBOL_ADDR_COL, addrMap, forward));
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbolsByAddress(Address startAddr, boolean forward) throws IOException {
|
||||
return new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
SYMBOL_ADDR_COL, addrMap, startAddr, forward));
|
||||
}
|
||||
|
||||
@Override
|
||||
void updateSymbolRecord(DBRecord record) throws IOException {
|
||||
// make sure hash is updated to current name and name space
|
||||
String name = record.getString(SYMBOL_NAME_COL);
|
||||
long namespaceId = record.getLongValue(SYMBOL_PARENT_COL);
|
||||
long addressKey = record.getLongValue(SYMBOL_ADDR_COL);
|
||||
record.setField(SYMBOL_HASH_COL,
|
||||
computeLocatorHash(name, namespaceId, addressKey));
|
||||
symbolTable.putRecord(record);
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbols() throws IOException {
|
||||
return symbolTable.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbols(Address start, Address end, boolean forward) throws IOException {
|
||||
return new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
SYMBOL_ADDR_COL, addrMap, start, end, forward));
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbols(AddressSetView set, boolean forward) throws IOException {
|
||||
return new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
SYMBOL_ADDR_COL, addrMap, set, forward));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RecordIterator getPrimarySymbols(AddressSetView set, boolean forward)
|
||||
throws IOException {
|
||||
return new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
SYMBOL_PRIMARY_COL, addrMap, set, forward));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DBRecord getPrimarySymbol(Address address) throws IOException {
|
||||
AddressIndexPrimaryKeyIterator it = new AddressIndexPrimaryKeyIterator(symbolTable,
|
||||
SYMBOL_PRIMARY_COL, addrMap, address, address, true);
|
||||
if (it.hasNext()) {
|
||||
return symbolTable.getRecord(it.next());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void deleteExternalEntries(Address start, Address end) throws IOException {
|
||||
AddressRecordDeleter.deleteRecords(symbolTable, SYMBOL_ADDR_COL, addrMap, start, end, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
void moveAddress(Address oldAddr, Address newAddr) throws IOException {
|
||||
LongField oldKey = new LongField(addrMap.getKey(oldAddr, false));
|
||||
long newKey = addrMap.getKey(newAddr, true);
|
||||
Field[] keys = symbolTable.findRecords(oldKey, SYMBOL_ADDR_COL);
|
||||
for (Field key : keys) {
|
||||
DBRecord rec = symbolTable.getRecord(key);
|
||||
rec.setLongValue(SYMBOL_ADDR_COL, newKey);
|
||||
symbolTable.putRecord(rec);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
Set<Address> deleteAddressRange(Address startAddr, Address endAddr, TaskMonitor monitor)
|
||||
throws CancelledException, IOException {
|
||||
|
||||
AnchoredSymbolRecordFilter filter = new AnchoredSymbolRecordFilter();
|
||||
AddressRecordDeleter.deleteRecords(symbolTable, SYMBOL_ADDR_COL, addrMap, startAddr,
|
||||
endAddr, filter);
|
||||
|
||||
return filter.getAddressesForSkippedRecords();
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbolsByNamespace(long id) throws IOException {
|
||||
LongField field = new LongField(id);
|
||||
return symbolTable.indexIterator(SYMBOL_PARENT_COL, field, field, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbolsByName(String name) throws IOException {
|
||||
StringField field = new StringField(name);
|
||||
return symbolTable.indexIterator(SYMBOL_NAME_COL, field, field, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getSymbolsByNameAndNamespace(String name, long id) throws IOException {
|
||||
// create a range of hash fields for all symbols with this name and namespace id over all
|
||||
// possible addresses
|
||||
Field start = computeLocatorHash(name, id, MIN_ADDRESS_OFFSET);
|
||||
if (start == null) {
|
||||
return EmptyRecordIterator.INSTANCE;
|
||||
}
|
||||
|
||||
Field end = computeLocatorHash(name, id, MAX_ADDRESS_OFFSET);
|
||||
|
||||
RecordIterator it = symbolTable.indexIterator(SYMBOL_HASH_COL, start, end, true);
|
||||
return getNameAndNamespaceFilterIterator(name, id, it);
|
||||
}
|
||||
|
||||
@Override
|
||||
DBRecord getSymbolRecord(Address address, String name, long namespaceId) throws IOException {
|
||||
long addressKey = addrMap.getKey(address, false);
|
||||
Field search = computeLocatorHash(name, namespaceId, addressKey);
|
||||
if (search == null) {
|
||||
return null;
|
||||
}
|
||||
RecordIterator it = symbolTable.indexIterator(SYMBOL_HASH_COL, search, search, true);
|
||||
RecordIterator filtered =
|
||||
getNameNamespaceAddressFilterIterator(name, namespaceId, addressKey, it);
|
||||
if (filtered.hasNext()) {
|
||||
return filtered.next();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
Address getMaxSymbolAddress(AddressSpace space) throws IOException {
|
||||
if (space.isMemorySpace()) {
|
||||
AddressIndexKeyIterator addressKeyIterator = new AddressIndexKeyIterator(symbolTable,
|
||||
SYMBOL_ADDR_COL, addrMap, space.getMinAddress(), space.getMaxAddress(), false);
|
||||
if (addressKeyIterator.hasNext()) {
|
||||
return addrMap.decodeAddress(addressKeyIterator.next());
|
||||
}
|
||||
}
|
||||
else {
|
||||
LongField max = new LongField(addrMap.getKey(space.getMaxAddress(), false));
|
||||
DBFieldIterator iterator =
|
||||
symbolTable.indexFieldIterator(null, max, false, SYMBOL_ADDR_COL);
|
||||
if (iterator.hasPrevious()) {
|
||||
LongField val = (LongField) iterator.previous();
|
||||
Address addr = addrMap.decodeAddress(val.getLongValue());
|
||||
if (space.equals(addr.getAddressSpace())) {
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
Table getTable() {
|
||||
return symbolTable;
|
||||
}
|
||||
|
||||
private class AnchoredSymbolRecordFilter implements RecordFilter {
|
||||
private Set<Address> set = new HashSet<Address>();
|
||||
|
||||
@Override
|
||||
public boolean matches(DBRecord record) {
|
||||
// only move symbols whose anchor flag is not on
|
||||
Address addr = addrMap.decodeAddress(record.getLongValue(SYMBOL_ADDR_COL));
|
||||
byte flags = record.getByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL);
|
||||
boolean pinned = (flags & SymbolDatabaseAdapter.SYMBOL_PINNED_FLAG) != 0;
|
||||
if (!pinned) {
|
||||
return true;
|
||||
}
|
||||
set.add(addr);
|
||||
return false;
|
||||
}
|
||||
|
||||
Set<Address> getAddressesForSkippedRecords() {
|
||||
return set;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -73,7 +73,6 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
|
||||
private Lock lock;
|
||||
final static Symbol[] NO_SYMBOLS = new SymbolDB[0];
|
||||
private static final int MAX_DUPLICATE_COUNT = 10;
|
||||
|
||||
/**
|
||||
* Creates a new Symbol manager.
|
||||
|
@ -211,7 +210,6 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
refMgr.moveReferencesTo(oldAddr, nextExtAddr, monitor);
|
||||
nextExtAddr = nextExtAddr.next();
|
||||
}
|
||||
libSym.setSymbolData2(0);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -275,7 +273,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
|
||||
try {
|
||||
Address variableAddr = getUpgradedVariableAddress(storageAddr,
|
||||
rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_DATA1_COL));
|
||||
rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL));
|
||||
|
||||
// fix symbol address
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL,
|
||||
|
@ -321,12 +319,12 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
throw new RuntimeException("Unexpected");
|
||||
}
|
||||
|
||||
long dataTypeId = rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_DATA1_COL);
|
||||
long dataTypeId = rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL);
|
||||
|
||||
if (curVarAddr == null || !addr.equals(curVarAddr) || dataTypeId != curDataTypeId) {
|
||||
|
||||
curVarAddr = addr;
|
||||
curDataTypeId = rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_DATA1_COL);
|
||||
curDataTypeId = rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL);
|
||||
|
||||
Address storageAddr = oldVariableStorageMgr.getStorageAddress(addr);
|
||||
|
||||
|
@ -450,7 +448,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
* @param isPrimary true if symbol is primary at oldAddr
|
||||
* @throws IOException if there is database exception
|
||||
*/
|
||||
public static void saveLocalSymbol(DBHandle tmpHandle, long symbolID, long oldAddr, String name,
|
||||
static void saveLocalSymbol(DBHandle tmpHandle, long symbolID, long oldAddr, String name,
|
||||
boolean isPrimary) throws IOException {
|
||||
Table table = tmpHandle.getTable(OLD_LOCAL_SYMBOLS_TABLE);
|
||||
if (table == null) {
|
||||
|
@ -506,8 +504,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
symbolRemoved(symbol, address, symbol.getName(), oldKey, Namespace.GLOBAL_NAMESPACE_ID,
|
||||
null);
|
||||
DBRecord record =
|
||||
adapter.createSymbol(newName, address, newParentID, SymbolType.LABEL, 0,
|
||||
1, null, source);
|
||||
adapter.createSymbol(newName, address, newParentID, SymbolType.LABEL, null,
|
||||
null, null, source, true);
|
||||
symbol.setRecord(record);// symbol object was morphed
|
||||
symbolAdded(symbol);
|
||||
}
|
||||
|
@ -548,12 +546,15 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
|
||||
DBRecord rec = SymbolDatabaseAdapter.SYMBOL_SCHEMA.createRecord(symbolID);
|
||||
rec.setString(SymbolDatabaseAdapter.SYMBOL_NAME_COL, name);
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL, addrMap.getKey(addr, true));
|
||||
long addressKey = addrMap.getKey(addr, true);
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL, addressKey);
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL, namespace.getID());
|
||||
rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_TYPE_COL, type.getID());
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATA1_COL, -1);
|
||||
rec.setIntValue(SymbolDatabaseAdapter.SYMBOL_DATA2_COL, isPrimary ? 1 : 0);
|
||||
if (isPrimary) {
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL, addressKey);
|
||||
}
|
||||
rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL, (byte) source.ordinal());
|
||||
|
||||
adapter.updateSymbolRecord(rec);
|
||||
}
|
||||
|
||||
|
@ -868,38 +869,51 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Symbol getSymbol(String name, Address addr, Namespace namespace) {
|
||||
public Symbol getSymbol(String name, Address address, Namespace namespace) {
|
||||
if (namespace == null) {
|
||||
namespace = program.getGlobalNamespace();
|
||||
}
|
||||
|
||||
if (addr instanceof SpecialAddress) {
|
||||
List<Symbol> symbols = getSymbols(name, namespace);
|
||||
for (Symbol symbol : symbols) {
|
||||
if (symbol.getAddress().equals(addr)) {
|
||||
return symbol;
|
||||
long namespaceId = namespace.getID();
|
||||
|
||||
lock.acquire();
|
||||
try {
|
||||
DBRecord record = adapter.getSymbolRecord(address, name, namespaceId);
|
||||
if (record != null) {
|
||||
return getSymbol(record);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
program.dbError(e);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
|
||||
// check for default external symbol
|
||||
if (namespace.isExternal() && SymbolUtilities.isPossibleDefaultExternalName(name)) {
|
||||
return searchNamespaceForSymbol(namespace, name, address);
|
||||
}
|
||||
|
||||
// also check for possible default parameter or local variable symbol
|
||||
if (namespace instanceof Function &&
|
||||
SymbolUtilities.isPossibleDefaultLocalOrParamName(name)) {
|
||||
return searchNamespaceForSymbol(namespace, name, address);
|
||||
}
|
||||
|
||||
// check if name is a default name
|
||||
Symbol symbol = getSymbolForDynamicName(name);
|
||||
if (symbol != null && address.equals(symbol.getAddress()) &&
|
||||
namespace.equals(symbol.getParentNamespace())) {
|
||||
return symbol;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
return getSymbol(name, addr, namespace.getID());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the symbol with the given info.
|
||||
* @param name the name of the symbol
|
||||
* @param addr the address of the symbol
|
||||
* @param parentID the id of the namespace symbol that the symbol belongs to.
|
||||
*/
|
||||
private Symbol getSymbol(String name, Address addr, long parentID) {
|
||||
Symbol[] symbols = getSymbols(addr);
|
||||
for (Symbol sym : symbols) {
|
||||
if (parentID != ((SymbolDB) sym).getParentID()) {
|
||||
continue;
|
||||
}
|
||||
if (!isDefaultThunk(sym) && sym.getName().equals(name)) {
|
||||
return sym;
|
||||
private Symbol searchNamespaceForSymbol(Namespace namespace, String name, Address address) {
|
||||
for (Symbol symbol : getSymbols(namespace)) {
|
||||
if (address.equals(symbol.getAddress()) && name.equals(symbol.getName())) {
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -916,13 +930,6 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
return symbols.isEmpty() ? null : symbols.get(0);
|
||||
}
|
||||
|
||||
private boolean hasDefaultVariablePrefix(String name) {
|
||||
return name.startsWith(Function.DEFAULT_LOCAL_PREFIX) ||
|
||||
name.startsWith(Function.DEFAULT_LOCAL_RESERVED_PREFIX) ||
|
||||
name.startsWith(Function.DEFAULT_LOCAL_TEMP_PREFIX) ||
|
||||
name.startsWith(Function.DEFAULT_PARAM_PREFIX) || name.equals("this");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Symbol getGlobalSymbol(String name, Address addr) {
|
||||
Symbol[] symbols = getSymbols(addr);
|
||||
|
@ -981,38 +988,60 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
namespace = namespaceMgr.getGlobalNamespace();
|
||||
}
|
||||
|
||||
// if name is possible default parameter or local variable name, must do brute force search
|
||||
if (namespace instanceof Function &&
|
||||
SymbolUtilities.isPossibleDefaultLocalOrParamName(name)) {
|
||||
return searchNamespaceForSymbols(name, namespace);
|
||||
}
|
||||
|
||||
// if the name is a possible default external name, do brute force search
|
||||
if (namespace.isExternal() && SymbolUtilities.isPossibleDefaultExternalName(name)) {
|
||||
return searchNamespaceForSymbols(name, namespace);
|
||||
}
|
||||
|
||||
List<Symbol> list = new ArrayList<>();
|
||||
lock.acquire();
|
||||
try {
|
||||
if (namespace.isExternal() &&
|
||||
SymbolUtilities.isReservedExternalDefaultName(name, program.getAddressFactory())) {
|
||||
return searchSymbolsByNamespaceFirst(name, namespace);
|
||||
}
|
||||
|
||||
if (namespace instanceof Function && hasDefaultVariablePrefix(name)) {
|
||||
return searchSymbolsByNamespaceFirst(name, namespace);
|
||||
}
|
||||
|
||||
// Try to find the symbols by searching through all the symbols with the given name
|
||||
// and including only those in the specified namespace. If there are too many symbols
|
||||
// with the same name and we are not in the global space, abandon this approach and
|
||||
// instead search through all the symbols in the namespace and only include those with
|
||||
// the specified name.
|
||||
int count = 0;
|
||||
List<Symbol> list = new ArrayList<>();
|
||||
SymbolIterator symbols = getSymbols(name); // will not include default thunks
|
||||
for (Symbol s : symbols) {
|
||||
if (++count == MAX_DUPLICATE_COUNT && !namespace.isGlobal()) {
|
||||
return searchSymbolsByNamespaceFirst(name, namespace);
|
||||
}
|
||||
if (s.getParentNamespace().equals(namespace)) {
|
||||
list.add(s);
|
||||
RecordIterator it = adapter.getSymbolsByNameAndNamespace(name, namespace.getID());
|
||||
while (it.hasNext()) {
|
||||
list.add(getSymbol(it.next()));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
catch (IOException e) {
|
||||
program.dbError(e);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
|
||||
// also check if the given name could be a default symbol
|
||||
Symbol symbol = getSymbolForDynamicName(name);
|
||||
if (symbol != null && symbol.getParentNamespace().equals(namespace)) {
|
||||
list.add(symbol);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
private List<Symbol> searchNamespaceForSymbols(String name, Namespace namespace) {
|
||||
List<Symbol> list = new ArrayList<>();
|
||||
for (Symbol symbol : getSymbols(namespace)) {
|
||||
if (name.equals(symbol.getName())) {
|
||||
list.add(symbol);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private Symbol getSymbolForDynamicName(String name) {
|
||||
Address address = SymbolUtilities.parseDynamicName(addrMap.getAddressFactory(), name);
|
||||
if (address != null) {
|
||||
Symbol primarySymbol = getPrimarySymbol(address);
|
||||
if (primarySymbol != null && primarySymbol.getSource() == SourceType.DEFAULT) {
|
||||
return primarySymbol;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// note: this could be public; adding it may be confusing due to the potential for having
|
||||
|
@ -1021,57 +1050,31 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
if (namespace == null) {
|
||||
namespace = namespaceMgr.getGlobalNamespace();
|
||||
}
|
||||
|
||||
if (namespace.isExternal() &&
|
||||
SymbolUtilities.isReservedExternalDefaultName(name, program.getAddressFactory())) {
|
||||
return findFirstSymbol(name, namespace, test);
|
||||
}
|
||||
|
||||
else if (namespace instanceof Function && hasDefaultVariablePrefix(name)) {
|
||||
return findFirstSymbol(name, namespace, test);
|
||||
}
|
||||
|
||||
// Try to find the symbols by searching through all the symbols with the given name
|
||||
// and including only those in the specified namespace. If there are too many symbols
|
||||
// with the same name and we are not in the global space, abandon this approach and
|
||||
// instead search through all the symbols in the namespace and only include those with
|
||||
// the specified name.
|
||||
int count = 0;
|
||||
SymbolIterator symbols = getSymbols(name);
|
||||
for (Symbol s : symbols) {
|
||||
if (++count == MAX_DUPLICATE_COUNT && !namespace.isGlobal()) {
|
||||
return findFirstSymbol(name, namespace, test);
|
||||
}
|
||||
if (s.getParentNamespace().equals(namespace) &&
|
||||
test.test(s)) {
|
||||
return s;
|
||||
lock.acquire();
|
||||
try {
|
||||
RecordIterator it = adapter.getSymbolsByNameAndNamespace(name, namespace.getID());
|
||||
while (it.hasNext()) {
|
||||
SymbolDB symbol = getSymbol(it.next());
|
||||
if (test.test(symbol)) {
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
|
||||
// didn't find one in the database, see if it is a default dynamic name
|
||||
Symbol symbol = getSymbolForDynamicName(name);
|
||||
if (symbol != null && symbol.getParentNamespace().equals(namespace) &&
|
||||
test.test(symbol)) {
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
program.dbError(e);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of symbols with the given name and namespace.
|
||||
*
|
||||
* <P>This method works by examining all symbols in the given namespace for those with
|
||||
* the specified name.
|
||||
*
|
||||
* @param name the name of the symbols in include.
|
||||
* @param namespace the namespace of the symbols to include.
|
||||
* @return the list of symbols with the given name and namespace.
|
||||
*/
|
||||
private List<Symbol> searchSymbolsByNamespaceFirst(String name, Namespace namespace) {
|
||||
List<Symbol> list = new ArrayList<>();
|
||||
SymbolIterator symbols = getSymbols(namespace);
|
||||
for (Symbol symbol : symbols) {
|
||||
if (symbol.getName().equals(name)) {
|
||||
list.add(symbol);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Namespace getNamespace(String name, Namespace namespace) {
|
||||
List<Symbol> symbols = getSymbols(name, namespace);
|
||||
|
@ -1107,16 +1110,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
try {
|
||||
SymbolIterator symIter = new SymbolNameRecordIterator(name);
|
||||
if (!symIter.hasNext()) {
|
||||
Address addr = SymbolUtilities.parseDynamicName(addrMap.getAddressFactory(), name);
|
||||
if (addr != null) {
|
||||
Symbol[] symbols = getSymbols(addr);
|
||||
for (Symbol symbol : symbols) {
|
||||
if (name.equals(symbol.getName())) {
|
||||
return new SingleSymbolIterator(symbol);
|
||||
}
|
||||
}
|
||||
return new SingleSymbolIterator(null);
|
||||
}
|
||||
Symbol symbol = getSymbolForDynamicName(name);
|
||||
return new SingleSymbolIterator(symbol); // this handles a null symbol
|
||||
}
|
||||
return symIter;
|
||||
}
|
||||
|
@ -1134,19 +1129,28 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
if (!addr.isMemoryAddress() && !addr.isExternalAddress()) {
|
||||
return null;
|
||||
}
|
||||
if (addr.isExternalAddress()) {
|
||||
Symbol[] symbols = getSymbols(addr);
|
||||
return symbols.length > 0 ? symbols[0] : null;
|
||||
}
|
||||
|
||||
lock.acquire();
|
||||
try {
|
||||
Symbol[] symbols = getSymbols(addr);
|
||||
for (Symbol element : symbols) {
|
||||
if (element.isPrimary()) {
|
||||
return element;
|
||||
DBRecord record = adapter.getPrimarySymbol(addr);
|
||||
if (record != null) {
|
||||
return getSymbol(record);
|
||||
}
|
||||
if (addr.isMemoryAddress() && refManager.hasReferencesTo(addr)) {
|
||||
return getDynamicSymbol(addr);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
catch (IOException e) {
|
||||
program.dbError(e);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1207,14 +1211,14 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
if (set.isEmpty()) {
|
||||
return SymbolIterator.EMPTY_ITERATOR;
|
||||
}
|
||||
Query query1 = new FieldMatchQuery(SymbolDatabaseAdapter.SYMBOL_DATA2_COL, new IntField(1));
|
||||
Query query2 = new FieldMatchQuery(SymbolDatabaseAdapter.SYMBOL_TYPE_COL,
|
||||
new ByteField(SymbolType.LABEL.getID()));
|
||||
Query query3 = new FieldMatchQuery(SymbolDatabaseAdapter.SYMBOL_TYPE_COL,
|
||||
new ByteField(SymbolType.FUNCTION.getID()));
|
||||
Query query4 = new AndQuery(query1, query2);
|
||||
Query query5 = new OrQuery(query3, query4);
|
||||
return new AddressSetFilteredSymbolIterator(this, set, query5, forward);
|
||||
try {
|
||||
RecordIterator recordIterator = adapter.getPrimarySymbols(set, forward);
|
||||
return new SymbolRecordIterator(recordIterator, true, forward);
|
||||
}
|
||||
catch (IOException e) {
|
||||
program.dbError(e);
|
||||
}
|
||||
return new SymbolRecordIterator(new EmptyRecordIterator(), true, forward);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -2130,9 +2134,9 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
continue;
|
||||
}
|
||||
}
|
||||
long id = rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_DATA1_COL);
|
||||
long id = rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL);
|
||||
if (id == oldDataTypeID) {
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATA1_COL, newDataTypeID);
|
||||
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL, newDataTypeID);
|
||||
adapter.updateSymbolRecord(rec);
|
||||
symbolDataChanged(getSymbol(rec));
|
||||
}
|
||||
|
@ -2157,13 +2161,13 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
lock.acquire();
|
||||
try {
|
||||
invalidateCache(true);
|
||||
Address lastAddress = fromAddr.add(length-1);
|
||||
Address lastAddress = fromAddr.add(length - 1);
|
||||
AddressRange range = new AddressRangeImpl(fromAddr, lastAddress);
|
||||
|
||||
// in order to handle overlapping ranges, need to iterate in the correct direction
|
||||
SymbolIterator symbolIterator = (fromAddr.compareTo(toAddr) > 0) ?
|
||||
getSymbolIterator(fromAddr, true) :
|
||||
getSymbolIterator(lastAddress, false);
|
||||
SymbolIterator symbolIterator =
|
||||
(fromAddr.compareTo(toAddr) > 0) ? getSymbolIterator(fromAddr, true)
|
||||
: getSymbolIterator(lastAddress, false);
|
||||
|
||||
for (Symbol symbol : symbolIterator) {
|
||||
if (!range.contains(symbol.getAddress())) {
|
||||
|
@ -2479,8 +2483,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
try {
|
||||
source = adjustSourceTypeIfNecessary(name, type, source, storage);
|
||||
Address varAddr = variableStorageMgr.getVariableStorageAddress(storage, true);
|
||||
return (VariableSymbolDB) createSpecialSymbol(varAddr, name, namespace, type, -1,
|
||||
firstUseOffsetOrOrdinal, null, source);
|
||||
return (VariableSymbolDB) createSpecialSymbol(varAddr, name, namespace, type,
|
||||
null, Integer.valueOf(firstUseOffsetOrOrdinal), null, source);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dbError(e);
|
||||
|
@ -2506,7 +2510,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
@Override
|
||||
public GhidraClass createClass(Namespace parent, String name, SourceType source)
|
||||
throws DuplicateNameException, InvalidInputException {
|
||||
SymbolDB s = createSpecialSymbol(Address.NO_ADDRESS, name, parent, SymbolType.CLASS, -1, -1,
|
||||
SymbolDB s =
|
||||
createSpecialSymbol(Address.NO_ADDRESS, name, parent, SymbolType.CLASS, null, null,
|
||||
null, source);
|
||||
return new GhidraClassDB(s, namespaceMgr);
|
||||
}
|
||||
|
@ -2515,7 +2520,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
public Library createExternalLibrary(String name, SourceType source)
|
||||
throws DuplicateNameException, InvalidInputException {
|
||||
|
||||
SymbolDB s = createSpecialSymbol(Address.NO_ADDRESS, name, null, SymbolType.LIBRARY, -1, -1,
|
||||
SymbolDB s =
|
||||
createSpecialSymbol(Address.NO_ADDRESS, name, null, SymbolType.LIBRARY, null, null,
|
||||
null, source);
|
||||
return new LibraryDB(s, namespaceMgr);
|
||||
}
|
||||
|
@ -2524,8 +2530,9 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
public Namespace createNameSpace(Namespace parent, String name, SourceType source)
|
||||
throws DuplicateNameException, InvalidInputException {
|
||||
|
||||
SymbolDB s = createSpecialSymbol(Address.NO_ADDRESS, name, parent, SymbolType.NAMESPACE, -1,
|
||||
-1, null, source);
|
||||
SymbolDB s =
|
||||
createSpecialSymbol(Address.NO_ADDRESS, name, parent, SymbolType.NAMESPACE, null,
|
||||
null, null, source);
|
||||
return new NamespaceDB(s, namespaceMgr);
|
||||
}
|
||||
|
||||
|
@ -2549,7 +2556,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
String tempName = "_temp_" + System.nanoTime();
|
||||
SymbolDB classSymbol =
|
||||
doCreateSpecialSymbol(Address.NO_ADDRESS, tempName, namespace.getParentNamespace(),
|
||||
SymbolType.CLASS, -1, -1, null, originalSource, false /*check for duplicate */);
|
||||
SymbolType.CLASS, null, null, null, originalSource,
|
||||
false /*check for duplicate */);
|
||||
GhidraClassDB classNamespace = new GhidraClassDB(classSymbol, namespaceMgr);
|
||||
|
||||
// move everything from old namespace into new class namespace
|
||||
|
@ -2624,8 +2632,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
// Note: We know there are no namespaces with the name; do we still have to check for
|
||||
// duplicates? Assuming yes, as another symbol type may exist with this name.
|
||||
SymbolDB s =
|
||||
doCreateSpecialSymbol(Address.NO_ADDRESS, name, parent, SymbolType.NAMESPACE, -1,
|
||||
-1, null, source, true /*check for duplicates*/);
|
||||
doCreateSpecialSymbol(Address.NO_ADDRESS, name, parent, SymbolType.NAMESPACE, null,
|
||||
null, null, source, true /*check for duplicates*/);
|
||||
return new NamespaceDB(s, namespaceMgr);
|
||||
|
||||
}
|
||||
|
@ -2643,9 +2651,9 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
* @param name the name of the symbol
|
||||
* @param parent the namespace for the symbol
|
||||
* @param symbolType the type of the symbol
|
||||
* @param data1 long value whose meaning depends on the symbol type.
|
||||
* @param data2 int value whose meaning depends on the symbol type.
|
||||
* @param data3 string value whose meaning depends on the symbol type.
|
||||
* @param dataTypeId the id for an associated datatype or null
|
||||
* @param variableOffset this is the ordinal for params and firstUseOffset for locals
|
||||
* @param stringData value whose meaning depends on the symbol type.
|
||||
* @param source the SourceType for the new symbol
|
||||
* @return the newly created symbol
|
||||
* @throws DuplicateNameException if the symbol type must be unique and another already has that name
|
||||
|
@ -2653,15 +2661,17 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
* @throws InvalidInputException if the name contains any illegal characters (i.e. space)
|
||||
*/
|
||||
public SymbolDB createSpecialSymbol(Address addr, String name, Namespace parent,
|
||||
SymbolType symbolType, long data1, int data2, String data3, SourceType source)
|
||||
SymbolType symbolType, Long dataTypeId, Integer variableOffset, String stringData,
|
||||
SourceType source)
|
||||
throws DuplicateNameException, InvalidInputException {
|
||||
|
||||
return doCreateSpecialSymbol(addr, name, parent, symbolType, data1, data2, data3, source,
|
||||
true);
|
||||
return doCreateSpecialSymbol(addr, name, parent, symbolType, stringData, dataTypeId,
|
||||
variableOffset, source, true);
|
||||
}
|
||||
|
||||
private SymbolDB doCreateSpecialSymbol(Address addr, String name, Namespace parent,
|
||||
SymbolType symbolType, long data1, int data2, String data3, SourceType source,
|
||||
SymbolType symbolType, String stringData, Long dataTypeId, Integer variableOffset,
|
||||
SourceType source,
|
||||
boolean checkForDuplicates)
|
||||
throws DuplicateNameException, InvalidInputException {
|
||||
|
||||
|
@ -2675,7 +2685,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
checkDuplicateSymbolName(addr, name, parent, symbolType);
|
||||
}
|
||||
|
||||
return doCreateSymbol(name, addr, parent, symbolType, data1, data2, data3, source);
|
||||
return doCreateSymbol(name, addr, parent, symbolType, stringData, dataTypeId,
|
||||
variableOffset, source, false);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
|
@ -2713,12 +2724,12 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
* @param name the name of the new symbol
|
||||
* @param namespace the namespace for the new symbol
|
||||
* @param source the SourceType of the new symbol
|
||||
* @param data3 special use depending on the symbol type and whether or not it is external
|
||||
* @param stringData special use depending on the symbol type and whether or not it is external
|
||||
* @return the new symbol
|
||||
* @throws InvalidInputException if the name contains illegal characters (i.e. space)
|
||||
*/
|
||||
public Symbol createCodeSymbol(Address addr, String name, Namespace namespace,
|
||||
SourceType source, String data3) throws InvalidInputException {
|
||||
SourceType source, String stringData) throws InvalidInputException {
|
||||
lock.acquire();
|
||||
try {
|
||||
namespace = validateNamespace(namespace, addr, SymbolType.LABEL);
|
||||
|
@ -2744,8 +2755,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
}
|
||||
boolean makePrimary = primary == null;
|
||||
|
||||
return doCreateSymbol(name, addr, namespace, SymbolType.LABEL, -1, makePrimary ? 1 : 0,
|
||||
data3, source);
|
||||
return doCreateSymbol(name, addr, namespace, SymbolType.LABEL, stringData, null, null,
|
||||
source, makePrimary);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
|
@ -2759,34 +2770,32 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
* @param name the name of the new symbol
|
||||
* @param namespace the namespace for the new symbol
|
||||
* @param source the SourceType of the new symbol
|
||||
* @param data3 special use depending on the symbol type and whether or not it is external.
|
||||
* @param stringData special use depending on the symbol type and whether or not it is external.
|
||||
* @return the new symbol
|
||||
* @throws InvalidInputException if the name contains illegal characters (i.e. space)
|
||||
*/
|
||||
public Symbol createFunctionSymbol(Address addr, String name, Namespace namespace,
|
||||
SourceType source, String data3) throws InvalidInputException {
|
||||
SourceType source, String stringData) throws InvalidInputException {
|
||||
|
||||
namespace = validateNamespace(namespace, addr, SymbolType.FUNCTION);
|
||||
source = validateSource(source, name, addr, SymbolType.FUNCTION);
|
||||
name = validateName(name, source);
|
||||
|
||||
Symbol[] symbols = getSymbols(addr);
|
||||
|
||||
// if there is already a FUNCTION symbol with that name and namespace here, just return it.
|
||||
Symbol matching =
|
||||
findMatchingSymbol(symbols, new SymbolMatcher(name, namespace, SymbolType.FUNCTION));
|
||||
if (matching != null) {
|
||||
Symbol matching = getSymbol(name, addr, namespace);
|
||||
if (matching != null && matching.getSymbolType() == SymbolType.FUNCTION) {
|
||||
return matching;
|
||||
}
|
||||
|
||||
// if there is another function at the same address, throw InvalidInputException
|
||||
if (findMatchingSymbol(symbols, s -> s.getSymbolType() == SymbolType.FUNCTION) != null) {
|
||||
Symbol primary = getPrimarySymbol(addr);
|
||||
if (primary != null && primary.getSymbolType() == SymbolType.FUNCTION) {
|
||||
throw new InvalidInputException("Function already exists at: " + addr);
|
||||
}
|
||||
|
||||
// See if there is a symbol we want to change into the function symbol
|
||||
Symbol symbolToPromote = findSymbolToPromote(symbols, name, namespace, source);
|
||||
if (symbolToPromote != null) {
|
||||
Symbol symbolToPromote = findSymbolToPromote(matching, primary, source);
|
||||
if (symbolToPromote != null && !symbolToPromote.isDynamic()) {
|
||||
name = symbolToPromote.getName();
|
||||
namespace = symbolToPromote.getParentNamespace();
|
||||
source = symbolToPromote.getSource();
|
||||
|
@ -2795,11 +2804,12 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
// If promoting a pinned symbol, we need to pin the new function symbol.
|
||||
boolean needsPinning = symbolToPromote == null ? false : symbolToPromote.isPinned();
|
||||
|
||||
// delete any promoted symbol, dynamic symbol, and make sure any others are not primary
|
||||
cleanUpSymbols(symbols, symbolToPromote);
|
||||
// delete any promoted symbol, dynamic symbol, and make sure all others are not primary
|
||||
cleanUpSymbols(addr, symbolToPromote, primary);
|
||||
|
||||
Symbol symbol =
|
||||
doCreateSymbol(name, addr, namespace, SymbolType.FUNCTION, -1, -1, data3, source);
|
||||
doCreateSymbol(name, addr, namespace, SymbolType.FUNCTION, stringData, null, null,
|
||||
source, true);
|
||||
|
||||
if (needsPinning) {
|
||||
symbol.setPinned(true);
|
||||
|
@ -2809,47 +2819,44 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
}
|
||||
|
||||
/**
|
||||
* If the new symbol is Default, returns the primary symbol if it is dynamic. Otherwise
|
||||
* returns any Code symbol with the same name and namespace.
|
||||
* Finds the appropriate symbol to promote when function is created. And by promote, we really
|
||||
* mean find the symbol that needs to be deleted before creating the function symbol. If the
|
||||
* found symbol is not dynamic, the function symbol will assume its name and namespace.
|
||||
*/
|
||||
private Symbol findSymbolToPromote(Symbol[] symbols, String name, Namespace namespace,
|
||||
SourceType source) {
|
||||
private Symbol findSymbolToPromote(Symbol matching, Symbol primary, SourceType source) {
|
||||
// if the function is default, then the primary will be promoted
|
||||
if (source == SourceType.DEFAULT) {
|
||||
Symbol primary = findMatchingSymbol(symbols, s -> s.isPrimary());
|
||||
if (primary != null && !primary.isDynamic()) {
|
||||
return primary;
|
||||
}
|
||||
return null;
|
||||
// if the primary is a default, it needs to be deleted, so return it as the "promoted" symbol
|
||||
if (primary != null && primary.isDynamic()) {
|
||||
return primary;
|
||||
}
|
||||
// Even though this doesn't change the name or namespace, return this so it will be deleted later.
|
||||
return findMatchingSymbol(symbols, new SymbolMatcher(name, namespace, SymbolType.LABEL));
|
||||
// otherwise return a symbol that has the same name and namespce as the function (if it exists)
|
||||
return matching;
|
||||
}
|
||||
|
||||
private void cleanUpSymbols(Symbol[] symbols, Symbol symbolToPromote) {
|
||||
private void cleanUpSymbols(Address address, Symbol symbolToPromote, Symbol primary) {
|
||||
if (symbolToPromote != null) {
|
||||
if (symbolToPromote.isDynamic()) {
|
||||
deleteDynamicSymbol(symbolToPromote);
|
||||
primary = null;
|
||||
}
|
||||
else {
|
||||
symbolToPromote.delete();
|
||||
}
|
||||
}
|
||||
// clean up any symbol that may have been made primary when we deleted the symbolToPromote
|
||||
for (Symbol symbol : symbols) {
|
||||
if (symbol != symbolToPromote && symbol.isPrimary()) {
|
||||
((CodeSymbol) symbol).setPrimary(false);
|
||||
primary = getPrimarySymbol(address);
|
||||
if (primary != null && primary.isDynamic()) {
|
||||
deleteDynamicSymbol(primary);
|
||||
primary = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Symbol findMatchingSymbol(Symbol[] symbols, Predicate<Symbol> matcher) {
|
||||
for (Symbol symbol : symbols) {
|
||||
if (matcher.test(symbol)) {
|
||||
return symbol;
|
||||
// clear the primary symbol during cleanup because a new symbol is about to be created
|
||||
// that will be the primary symbol
|
||||
if (primary != null && !primary.isDynamic()) {
|
||||
((CodeSymbol) primary).setPrimary(false);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Namespace validateNamespace(Namespace namespace, Address addr, SymbolType type)
|
||||
throws InvalidInputException {
|
||||
|
@ -2862,12 +2869,13 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
}
|
||||
|
||||
private SymbolDB doCreateSymbol(String name, Address addr, Namespace namespace, SymbolType type,
|
||||
long data1, int data2, String data3, SourceType source) {
|
||||
String stringData, Long dataTypeId, Integer variableOffset, SourceType source,
|
||||
boolean isPrimary) {
|
||||
|
||||
try {
|
||||
DBRecord record =
|
||||
adapter.createSymbol(name, addr, namespace.getID(), type, data1, data2,
|
||||
data3, source);
|
||||
adapter.createSymbol(name, addr, namespace.getID(), type, stringData, dataTypeId,
|
||||
variableOffset, source, isPrimary);
|
||||
|
||||
SymbolDB newSymbol = makeSymbol(addr, record, type);
|
||||
symbolAdded(newSymbol);
|
||||
|
@ -3019,21 +3027,6 @@ public class SymbolManager implements SymbolTable, ManagerDB {
|
|||
private Symbol getSpecificSymbol(String name, Namespace namespace, SymbolType type) {
|
||||
return getFirstSymbol(name, namespace, s -> s.getSymbolType() == type);
|
||||
}
|
||||
|
||||
private Symbol findFirstSymbol(String name, Namespace namespace, Predicate<Symbol> test) {
|
||||
if (namespace == null) {
|
||||
namespace = namespaceMgr.getGlobalNamespace();
|
||||
}
|
||||
|
||||
SymbolIterator it = getSymbols(namespace);
|
||||
while (it.hasNext()) {
|
||||
Symbol s = it.next();
|
||||
if (s.getName().equals(name) && test.test(s)) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class SymbolMatcher implements Predicate<Symbol> {
|
||||
|
|
|
@ -36,9 +36,7 @@ import ghidra.util.task.TaskMonitor;
|
|||
* Symbol class for function variables.
|
||||
*
|
||||
* Symbol Data Usage:
|
||||
* long data1 - data type ID
|
||||
* int data2 - first-use-offset / ordinal
|
||||
* String data3 - variable comment
|
||||
* String stringData - variable comment
|
||||
*/
|
||||
public class VariableSymbolDB extends SymbolDB {
|
||||
|
||||
|
@ -174,7 +172,8 @@ public class VariableSymbolDB extends SymbolDB {
|
|||
}
|
||||
|
||||
public FunctionDB getFunction() {
|
||||
return (FunctionDB) symbolMgr.getFunctionManager().getFunction(
|
||||
return (FunctionDB) symbolMgr.getFunctionManager()
|
||||
.getFunction(
|
||||
getParentNamespace().getID());
|
||||
}
|
||||
|
||||
|
@ -252,7 +251,7 @@ public class VariableSymbolDB extends SymbolDB {
|
|||
}
|
||||
|
||||
public DataType getDataType() {
|
||||
DataType dt = symbolMgr.getDataType(getSymbolData1());
|
||||
DataType dt = symbolMgr.getDataType(getDataTypeId());
|
||||
if (dt == null) {
|
||||
VariableStorage storage = getVariableStorage();
|
||||
if (storage == null) {
|
||||
|
@ -286,8 +285,8 @@ public class VariableSymbolDB extends SymbolDB {
|
|||
Address newAddr = variableMgr.getVariableStorageAddress(newStorage, true);
|
||||
setAddress(newAddr); // this may be the only symbol which changes its address
|
||||
|
||||
if (dataTypeID != getSymbolData1()) {
|
||||
setSymbolData1(dataTypeID);
|
||||
if (dataTypeID != getDataTypeId()) {
|
||||
setDataTypeId(dataTypeID);
|
||||
}
|
||||
else {
|
||||
symbolMgr.symbolDataChanged(this);
|
||||
|
@ -302,22 +301,22 @@ public class VariableSymbolDB extends SymbolDB {
|
|||
}
|
||||
|
||||
public int getFirstUseOffset() {
|
||||
return type == SymbolType.PARAMETER ? 0 : getSymbolData2();
|
||||
return type == SymbolType.PARAMETER ? 0 : getVariableOffset();
|
||||
}
|
||||
|
||||
public void setFirstUseOffset(int firstUseOffset) {
|
||||
if (type == SymbolType.LOCAL_VAR) {
|
||||
setSymbolData2(firstUseOffset);
|
||||
setVariableOffset(firstUseOffset);
|
||||
}
|
||||
}
|
||||
|
||||
public int getOrdinal() {
|
||||
return type == SymbolType.PARAMETER ? getSymbolData2() : Integer.MIN_VALUE;
|
||||
return type == SymbolType.PARAMETER ? getVariableOffset() : Integer.MIN_VALUE;
|
||||
}
|
||||
|
||||
public void setOrdinal(int ordinal) {
|
||||
if (type == SymbolType.PARAMETER) {
|
||||
setSymbolData2(ordinal);
|
||||
setVariableOffset(ordinal);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,9 @@ import db.RecordIterator;
|
|||
/**
|
||||
* Implementation of a RecordIterator that is always empty.
|
||||
*/
|
||||
|
||||
public class EmptyRecordIterator implements RecordIterator {
|
||||
public static final RecordIterator INSTANCE = new EmptyRecordIterator();
|
||||
|
||||
/**
|
||||
* @see db.RecordIterator#hasNext()
|
||||
|
|
|
@ -760,6 +760,29 @@ public class SymbolUtilities {
|
|||
return addr.getAddressSpace().getName() + Long.toHexString(addr.getOffset());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given name is a possible default parameter name or local variable name
|
||||
*
|
||||
* @param name the name to check to see if it is a possible default local or parameter name
|
||||
* @return true if the given name is a possible default parameter name or local variable name
|
||||
*/
|
||||
public static boolean isPossibleDefaultLocalOrParamName(String name) {
|
||||
if (isDefaultParameterName(name)) {
|
||||
return true;
|
||||
}
|
||||
return name.startsWith(Function.DEFAULT_LOCAL_PREFIX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given name could be a default external location name
|
||||
*
|
||||
* @param name the name to check
|
||||
* @return true if the given name is a possible default external location name
|
||||
*/
|
||||
public static boolean isPossibleDefaultExternalName(String name) {
|
||||
return name.startsWith(DEFAULT_EXTERNAL_ENTRY_PREFIX);
|
||||
}
|
||||
|
||||
public static boolean isDefaultLocalStackName(String name) {
|
||||
if (name == null || name.length() == 0) {
|
||||
return true;
|
||||
|
@ -1042,4 +1065,5 @@ public class SymbolUtilities {
|
|||
public static Comparator<Symbol> getSymbolNameComparator() {
|
||||
return CASE_INSENSITIVE_SYMBOL_NAME_COMPARATOR;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -193,8 +193,8 @@ public interface ChangeManager {
|
|||
public static final int DOCR_SYMBOL_ASSOCIATION_REMOVED = 51;
|
||||
|
||||
/**
|
||||
* Symbol data changed. This corresponds to unspecified data
|
||||
* changes within the symbol (e.g., Data1, Data2, Data3, or VariableStorage).
|
||||
* Symbol data changed. This corresponds to various
|
||||
* changes within the symbol (e.g., primary status, datatype, external path or VariableStorage).
|
||||
*/
|
||||
public static final int DOCR_SYMBOL_DATA_CHANGED = 52;
|
||||
|
||||
|
@ -592,7 +592,6 @@ public interface ChangeManager {
|
|||
*/
|
||||
public final static int DOCR_TAG_REMOVED_FROM_FUNCTION = 157;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DOCR_FUNCTION_CHANGED - Sub Event Types
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue