Merge remote-tracking branch 'origin/GP-1082_ghidravore_improving_symbol_table_performance'

This commit is contained in:
Ryan Kurtz 2021-09-28 12:52:32 -04:00
commit 156ce7ef80
32 changed files with 1938 additions and 821 deletions

View file

@ -526,7 +526,7 @@ class SymbolMerger extends AbstractListingMerger {
renamed = true; renamed = true;
} }
// boolean commentChanged = // boolean commentChanged =
// !SystemUtilities.isEqual(newSym.getSymbolData3(), oldSym.getSymbolData3()); // !SystemUtilities.isEqual(newSym.getSymbolStringData(), oldSym.getSymbolStringData());
boolean sourceChanged = newSym.getSource() != oldSym.getSource(); boolean sourceChanged = newSym.getSource() != oldSym.getSource();
// if (commentChanged) { // if (commentChanged) {
// commentChanges.add(id); // commentChanges.add(id);
@ -920,12 +920,12 @@ class SymbolMerger extends AbstractListingMerger {
// if (commentChangedInMy) { // if (commentChangedInMy) {
// if (!commentChangedInLatest) { // if (!commentChangedInLatest) {
// if (resultSym != null) { // if (resultSym != null) {
// resultSym.setSymbolData3(mySym.getSymbolData3()); // resultSym.setSymbolStringData(mySym.getSymbolStringData());
// } // }
// } // }
// else { // else {
// Symbol latestSym = latestSymTab.getSymbol(id); // Symbol latestSym = latestSymTab.getSymbol(id);
// if (!SystemUtilities.isEqual(latestSym.getSymbolData3(), mySym.getSymbolData3())) { // if (!SystemUtilities.isEqual(latestSym.getSymbolStringData(), mySym.getSymbolStringData())) {
// saveCommentConflict(id); // saveCommentConflict(id);
// } // }
// } // }
@ -1008,11 +1008,11 @@ class SymbolMerger extends AbstractListingMerger {
// if (commentChangedInMy) { // if (commentChangedInMy) {
// if (!commentChangedInLatest) { // if (!commentChangedInLatest) {
// // Use My version's comment since Latest didn't change it. // // Use My version's comment since Latest didn't change it.
// resultSym.setSymbolData3(mySym.getSymbolData3()); // resultSym.setSymbolStringData(mySym.getSymbolStringData());
// } // }
// else { // else {
// Symbol latestSym = latestSymTab.getSymbol(id); // 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. // saveFunctionCommentConflict(id); // My & Latest changed comment differently.
// } // }
// } // }
@ -1181,11 +1181,11 @@ class SymbolMerger extends AbstractListingMerger {
// Handle Symbol comments. // Handle Symbol comments.
// if (commentChangedInMy) { // if (commentChangedInMy) {
// if (!commentChangedInLatest) { // 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 { // else {
// Symbol latestSym = latestSymTab.getSymbol(id); // 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. // saveAddFunctionCommentConflict(id); // My & Latest changed comment differently.
// } // }
// } // }
@ -1372,8 +1372,8 @@ class SymbolMerger extends AbstractListingMerger {
// private void processAddedSymbolComment(Symbol resultSym, Symbol mySym) { // private void processAddedSymbolComment(Symbol resultSym, Symbol mySym) {
// // My version added a symbol that matches on in the result version. // // My version added a symbol that matches on in the result version.
// String resultComment = resultSym.getSymbolData3(); // String resultComment = resultSym.getSymbolStringData();
// String myComment = mySym.getSymbolData3(); // String myComment = mySym.getSymbolStringData();
// if (SystemUtilities.isEqual(resultComment, myComment)) { // if (SystemUtilities.isEqual(resultComment, myComment)) {
// return; // Already has My symbol comment. // return; // Already has My symbol comment.
// } // }
@ -1381,7 +1381,7 @@ class SymbolMerger extends AbstractListingMerger {
// return; // My version isn't setting a symbol comment. // return; // My version isn't setting a symbol comment.
// } // }
// if (resultComment == null) { // 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)) { // else if (!myComment.equals(resultComment)) {
// saveAddCommentConflict(mySym.getID()); // Both set a different symbol comment, so conflict // saveAddCommentConflict(mySym.getID()); // Both set a different symbol comment, so conflict
@ -1711,7 +1711,7 @@ class SymbolMerger extends AbstractListingMerger {
// currentAddress = addr; // currentAddress = addr;
// currentSymbol = mySym; // currentSymbol = mySym;
// Symbol resultSym = getResultSymbolFromMySymbol(mySym); // Symbol resultSym = getResultSymbolFromMySymbol(mySym);
// currentSymbolComment = (resultSym != null) ? resultSym.getSymbolData3() : ""; // currentSymbolComment = (resultSym != null) ? resultSym.getSymbolStringData() : "";
// currentBackgroundSet = new AddressSet(resultAddressFactory, addr, addr); // currentBackgroundSet = new AddressSet(resultAddressFactory, addr, addr);
// if (askUser && mergeManager != null) { // if (askUser && mergeManager != null) {
// boolean useForAll = (symbolAddCommentChoice != ASK_USER); // boolean useForAll = (symbolAddCommentChoice != ASK_USER);
@ -1912,10 +1912,10 @@ class SymbolMerger extends AbstractListingMerger {
// return; // return;
// } // }
// if ((chosenConflictOption & KEEP_LATEST) != 0) { // if ((chosenConflictOption & KEEP_LATEST) != 0) {
// result.setSymbolData3(latest.getSymbolData3()); // result.setSymbolStringData(latest.getSymbolStringData());
// } // }
// else if ((chosenConflictOption & KEEP_MY) != 0) { // else if ((chosenConflictOption & KEEP_MY) != 0) {
// result.setSymbolData3(my.getSymbolData3()); // result.setSymbolStringData(my.getSymbolStringData());
// } // }
// } // }
@ -1933,10 +1933,10 @@ class SymbolMerger extends AbstractListingMerger {
// return; // return;
// } // }
// if ((chosenConflictOption & KEEP_RESULT) != 0) { // if ((chosenConflictOption & KEEP_RESULT) != 0) {
// result.setSymbolData3(currentSymbolComment); // result.setSymbolStringData(currentSymbolComment);
// } // }
// else if ((chosenConflictOption & KEEP_MY) != 0) { // else if ((chosenConflictOption & KEEP_MY) != 0) {
// result.setSymbolData3(my.getSymbolData3()); // result.setSymbolStringData(my.getSymbolStringData());
// } // }
// } // }
@ -2253,7 +2253,7 @@ class SymbolMerger extends AbstractListingMerger {
Symbol newSymbol) Symbol newSymbol)
throws DuplicateNameException, InvalidInputException, CircularDependencyException { throws DuplicateNameException, InvalidInputException, CircularDependencyException {
renameSymbol(oldProgram, oldSymbol, newProgram, newSymbol); renameSymbol(oldProgram, oldSymbol, newProgram, newSymbol);
// oldSymbol.setSymbolData3(newSymbol.getSymbolData3()); // oldSymbol.setSymbolStringData(newSymbol.getSymbolStringData());
// Handle primary. // Handle primary.
if (newSymbol.isPrimary() && !oldSymbol.isPrimary()) { if (newSymbol.isPrimary() && !oldSymbol.isPrimary()) {
oldSymbol.setPrimary(); oldSymbol.setPrimary();
@ -2446,7 +2446,7 @@ class SymbolMerger extends AbstractListingMerger {
private Symbol createSymbol(String name, SymbolType type, Address resultAddr, private Symbol createSymbol(String name, SymbolType type, Address resultAddr,
Namespace resultParentNs, Program srcPgm, long srcSymID, SourceType source) Namespace resultParentNs, Program srcPgm, long srcSymID, SourceType source)
throws DuplicateNameException, InvalidInputException { throws DuplicateNameException, InvalidInputException {
// String comment = srcSymbol.getSymbolData3(); // String comment = srcSymbol.getSymbolStringData();
Symbol symbol = null; Symbol symbol = null;
if (type == SymbolType.LABEL) { if (type == SymbolType.LABEL) {
symbol = resultSymTab.createLabel(resultAddr, name, resultParentNs, source); symbol = resultSymTab.createLabel(resultAddr, name, resultParentNs, source);
@ -2468,7 +2468,7 @@ class SymbolMerger extends AbstractListingMerger {
symbol = resultSymTab.getLibrarySymbol(name); symbol = resultSymTab.getLibrarySymbol(name);
} }
if (symbol != null) { if (symbol != null) {
// symbol.setSymbolData3(comment); // symbol.setSymbolStringData(comment);
if (symbol.getParentNamespace().equals(resultParentNs)) { if (symbol.getParentNamespace().equals(resultParentNs)) {
long resolveSymID = symbol.getID(); long resolveSymID = symbol.getID();
updateResolveIDs(srcPgm, srcSymID, resolveSymID); updateResolveIDs(srcPgm, srcSymID, resolveSymID);
@ -2671,7 +2671,7 @@ class SymbolMerger extends AbstractListingMerger {
String symbolName, ChangeListener listener) { String symbolName, ChangeListener listener) {
Symbol latest = Symbol latest =
latestSymTab.getNamespace(symbolName, DiffUtility.getNamespace(myNamespace, latestPgm)) latestSymTab.getNamespace(symbolName, DiffUtility.getNamespace(myNamespace, latestPgm))
.getSymbol(); .getSymbol();
Symbol my = mySymTab.getNamespace(symbolName, myNamespace).getSymbol(); Symbol my = mySymTab.getNamespace(symbolName, myNamespace).getSymbol();
String text = "Namespace Conflict"; String text = "Namespace Conflict";
conflictPanel.clear(); conflictPanel.clear();
@ -2864,7 +2864,7 @@ class SymbolMerger extends AbstractListingMerger {
// info[1] = s.getName(false); // info[1] = s.getName(false);
// info[2] = s.getParentNamespace().getSymbol().getName(); // info[2] = s.getParentNamespace().getSymbol().getName();
// info[3] = s.getSymbolType().toString(); // info[3] = s.getSymbolType().toString();
// info[4] = ConflictUtility.getTruncatedHTMLString(s.getSymbolData3(), TRUNCATE_LENGTH); // info[4] = ConflictUtility.getTruncatedHTMLString(s.getSymbolStringData(), TRUNCATE_LENGTH);
// return info; // return info;
// } // }

View file

@ -391,8 +391,8 @@ class SymbolMerge {
if (replace && toSymbol.isPinned() != pinned) { if (replace && toSymbol.isPinned() != pinned) {
toSymbol.setPinned(pinned); toSymbol.setPinned(pinned);
} }
// String fromComment = fromSymbol.getSymbolData3(); // String fromComment = fromSymbol.getSymbolStringData();
// String toComment = toSymbol.getSymbolData3(); // String toComment = toSymbol.getSymbolStringData();
// if (!SystemUtilities.isEqual(fromComment, toComment)) { // if (!SystemUtilities.isEqual(fromComment, toComment)) {
// String newComment; // String newComment;
// if (replace) { // if (replace) {
@ -401,7 +401,7 @@ class SymbolMerge {
// else { // else {
// newComment = StringUtilities.mergeStrings(fromComment, toComment); // newComment = StringUtilities.mergeStrings(fromComment, toComment);
// } // }
// toSymbol.setSymbolData3(newComment); // toSymbol.setSymbolStringData(newComment);
// } // }
} }
} }
@ -462,7 +462,7 @@ class SymbolMerge {
boolean isFromDefaultThunk = FunctionMerge.isDefaultThunk(fromFunc); boolean isFromDefaultThunk = FunctionMerge.isDefaultThunk(fromFunc);
String fromName = fromSymbol.getName(); String fromName = fromSymbol.getName();
Namespace fromNamespace = // default thunks will lie about their namespace Namespace fromNamespace = // default thunks will lie about their namespace
isFromDefaultThunk ? fromProgram.getGlobalNamespace() : fromSymbol.getParentNamespace(); isFromDefaultThunk ? fromProgram.getGlobalNamespace() : fromSymbol.getParentNamespace();
Symbol toSymbol; Symbol toSymbol;
if (toFunc == null) { if (toFunc == null) {
@ -551,7 +551,8 @@ class SymbolMerge {
boolean fromDefault = fromSymbol.getSource() == SourceType.DEFAULT; boolean fromDefault = fromSymbol.getSource() == SourceType.DEFAULT;
boolean isFromDefaultThunk = FunctionMerge.isDefaultThunk(fromFunc); boolean isFromDefaultThunk = FunctionMerge.isDefaultThunk(fromFunc);
Namespace fromNamespace = // default thunks will lie about their namespace Namespace fromNamespace = // default thunks will lie about their namespace
isFromDefaultThunk ? fromProgram.getGlobalNamespace() : fromSymbol.getParentNamespace(); isFromDefaultThunk ? fromProgram.getGlobalNamespace()
: fromSymbol.getParentNamespace();
Namespace resolveNamespace = resolveNamespace(fromNamespace, conflictSymbolIDMap); Namespace resolveNamespace = resolveNamespace(fromNamespace, conflictSymbolIDMap);
if ((toFunc != null) && replacePrimary && !fromDefault) { if ((toFunc != null) && replacePrimary && !fromDefault) {
@ -573,7 +574,7 @@ class SymbolMerge {
if (isFromDefaultThunk && FunctionMerge.isDefaultThunk(toFunc)) { if (isFromDefaultThunk && FunctionMerge.isDefaultThunk(toFunc)) {
return; return;
} }
if (toFunc.getSymbol().getSource() == SourceType.DEFAULT) { if (toFunc.getSymbol().getSource() == SourceType.DEFAULT) {
// Default "to" function so replace // Default "to" function so replace
replaceFunctionSymbol(fromEntryPoint, toEntryPoint, conflictSymbolIDMap, replaceFunctionSymbol(fromEntryPoint, toEntryPoint, conflictSymbolIDMap,

View file

@ -81,8 +81,9 @@ public class SymbolMergeManagerSourceTest extends AbstractListingMergeManagerTes
int txId = program.startTransaction("Modify My Program"); int txId = program.startTransaction("Modify My Program");
boolean commit = false; boolean commit = false;
try { try {
program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Lucy", null, program.getSymbolTable()
SourceType.USER_DEFINED); .createLabel(addr(program, "0x10032a7"), "Lucy", null,
SourceType.USER_DEFINED);
commit = true; commit = true;
} }
catch (Exception e) { catch (Exception e) {
@ -101,8 +102,9 @@ public class SymbolMergeManagerSourceTest extends AbstractListingMergeManagerTes
int txId = program.startTransaction("Modify My Program"); int txId = program.startTransaction("Modify My Program");
boolean commit = false; boolean commit = false;
try { try {
program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Lucy", null, program.getSymbolTable()
SourceType.USER_DEFINED); .createLabel(addr(program, "0x10032a7"), "Lucy", null,
SourceType.USER_DEFINED);
commit = true; commit = true;
} }
catch (Exception e) { catch (Exception e) {
@ -141,11 +143,11 @@ public class SymbolMergeManagerSourceTest extends AbstractListingMergeManagerTes
// try { // try {
// Symbol s = program.getSymbolTable().createSymbol(addr(program, "0x10032a7"), // Symbol s = program.getSymbolTable().createSymbol(addr(program, "0x10032a7"),
// "Lucy", null, SourceType.USER_DEFINED); // "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"), // s = program.getSymbolTable().createSymbol(addr(program, "0x1004bf4"),
// "red", null, SourceType.IMPORTED); // "red", null, SourceType.IMPORTED);
// s.setSymbolData3(longComment1); // s.setSymbolStringData(longComment1);
// commit = true; // commit = true;
// } catch (Exception e) { // } catch (Exception e) {
// Assert.fail(e.getMessage()); // Assert.fail(e.getMessage());
@ -163,11 +165,11 @@ public class SymbolMergeManagerSourceTest extends AbstractListingMergeManagerTes
// try { // try {
// Symbol s = program.getSymbolTable().createSymbol(addr(program, "0x10032a7"), "Lucy", null, // Symbol s = program.getSymbolTable().createSymbol(addr(program, "0x10032a7"), "Lucy", null,
// SourceType.USER_DEFINED); // SourceType.USER_DEFINED);
// s.setSymbolData3("This is a symbol comment."); // s.setSymbolStringData("This is a symbol comment.");
// //
// s = program.getSymbolTable().createSymbol(addr(program, "0x1004bf4"), // s = program.getSymbolTable().createSymbol(addr(program, "0x1004bf4"),
// "red", null, SourceType.IMPORTED); // "red", null, SourceType.IMPORTED);
// s.setSymbolData3(longComment1); // s.setSymbolStringData(longComment1);
// commit = true; // commit = true;
// } catch (Exception e) { // } catch (Exception e) {
// Assert.fail(e.getMessage()); // Assert.fail(e.getMessage());
@ -186,13 +188,13 @@ public class SymbolMergeManagerSourceTest extends AbstractListingMergeManagerTes
// checkSymbol(s, "Lucy", true); // checkSymbol(s, "Lucy", true);
// assertTrue(s.isPrimary()); // assertTrue(s.isPrimary());
// assertEquals(SourceType.USER_DEFINED, s.getSource()); // 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")); // s = symtab.getPrimarySymbol(addr("0x1004bf4"));
// checkSymbol(s, "red", true); // checkSymbol(s, "red", true);
// assertTrue(s.isPrimary()); // assertTrue(s.isPrimary());
// assertEquals(SourceType.IMPORTED, s.getSource()); // 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. */ /** Test add of same symbol and source to both Latest and My, but different symbol comments. */
@ -351,12 +353,15 @@ public class SymbolMergeManagerSourceTest extends AbstractListingMergeManagerTes
int txId = program.startTransaction("Modify My Program"); int txId = program.startTransaction("Modify My Program");
boolean commit = false; boolean commit = false;
try { try {
program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Charlie", program.getSymbolTable()
null, SourceType.ANALYSIS); .createLabel(addr(program, "0x10032a7"), "Charlie",
program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Lucy", null, null, SourceType.ANALYSIS);
SourceType.IMPORTED); program.getSymbolTable()
program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Linus", null, .createLabel(addr(program, "0x10032a7"), "Lucy", null,
SourceType.USER_DEFINED); SourceType.IMPORTED);
program.getSymbolTable()
.createLabel(addr(program, "0x10032a7"), "Linus", null,
SourceType.USER_DEFINED);
commit = true; commit = true;
} }
catch (Exception e) { catch (Exception e) {
@ -375,12 +380,15 @@ public class SymbolMergeManagerSourceTest extends AbstractListingMergeManagerTes
int txId = program.startTransaction("Modify My Program"); int txId = program.startTransaction("Modify My Program");
boolean commit = false; boolean commit = false;
try { try {
program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Charlie", program.getSymbolTable()
null, SourceType.USER_DEFINED); .createLabel(addr(program, "0x10032a7"), "Charlie",
program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Lucy", null, null, SourceType.USER_DEFINED);
SourceType.ANALYSIS); program.getSymbolTable()
program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Linus", null, .createLabel(addr(program, "0x10032a7"), "Lucy", null,
SourceType.IMPORTED); SourceType.ANALYSIS);
program.getSymbolTable()
.createLabel(addr(program, "0x10032a7"), "Linus", null,
SourceType.IMPORTED);
commit = true; commit = true;
} }
catch (Exception e) { catch (Exception e) {
@ -426,12 +434,15 @@ public class SymbolMergeManagerSourceTest extends AbstractListingMergeManagerTes
int txId = program.startTransaction("Modify My Program"); int txId = program.startTransaction("Modify My Program");
boolean commit = false; boolean commit = false;
try { try {
program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Lucy", null, program.getSymbolTable()
SourceType.IMPORTED); .createLabel(addr(program, "0x10032a7"), "Lucy", null,
program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Linus", null, SourceType.IMPORTED);
SourceType.ANALYSIS); program.getSymbolTable()
program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Sally", null, .createLabel(addr(program, "0x10032a7"), "Linus", null,
SourceType.USER_DEFINED); SourceType.ANALYSIS);
program.getSymbolTable()
.createLabel(addr(program, "0x10032a7"), "Sally", null,
SourceType.USER_DEFINED);
commit = true; commit = true;
} }
catch (Exception e) { catch (Exception e) {
@ -493,12 +504,15 @@ public class SymbolMergeManagerSourceTest extends AbstractListingMergeManagerTes
int txId = program.startTransaction("Modify My Program"); int txId = program.startTransaction("Modify My Program");
boolean commit = false; boolean commit = false;
try { try {
program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Charlie", program.getSymbolTable()
null, SourceType.USER_DEFINED); .createLabel(addr(program, "0x10032a7"), "Charlie",
program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Lucy", null, null, SourceType.USER_DEFINED);
SourceType.ANALYSIS); program.getSymbolTable()
program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Linus", null, .createLabel(addr(program, "0x10032a7"), "Lucy", null,
SourceType.IMPORTED); SourceType.ANALYSIS);
program.getSymbolTable()
.createLabel(addr(program, "0x10032a7"), "Linus", null,
SourceType.IMPORTED);
commit = true; commit = true;
} }
catch (Exception e) { catch (Exception e) {

View file

@ -32,7 +32,6 @@ import ghidra.program.model.lang.PrototypeModel;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
import ghidra.program.model.symbol.*; import ghidra.program.model.symbol.*;
import ghidra.test.AbstractGhidraHeadedIntegrationTest; import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.exception.InvalidInputException; import ghidra.util.exception.InvalidInputException;
import ghidra.util.task.TaskMonitorAdapter; import ghidra.util.task.TaskMonitorAdapter;
@ -53,8 +52,9 @@ public class FunctionManagerTest extends AbstractGhidraHeadedIntegrationTest {
space = program.getAddressFactory().getDefaultAddressSpace(); space = program.getAddressFactory().getDefaultAddressSpace();
functionManager = program.getFunctionManager(); functionManager = program.getFunctionManager();
transactionID = program.startTransaction("Test"); transactionID = program.startTransaction("Test");
program.getMemory().createInitializedBlock("temp", addr(0), 10000, (byte) 0, program.getMemory()
TaskMonitorAdapter.DUMMY_MONITOR, false); .createInitializedBlock("temp", addr(0), 10000, (byte) 0,
TaskMonitorAdapter.DUMMY_MONITOR, false);
} }
@After @After
@ -71,7 +71,7 @@ public class FunctionManagerTest extends AbstractGhidraHeadedIntegrationTest {
} }
private Function createFunction(String name, Address entryPt, AddressSetView body) private Function createFunction(String name, Address entryPt, AddressSetView body)
throws DuplicateNameException, InvalidInputException, OverlappingFunctionException { throws InvalidInputException, OverlappingFunctionException {
functionManager.createFunction(name, entryPt, body, SourceType.USER_DEFINED); functionManager.createFunction(name, entryPt, body, SourceType.USER_DEFINED);
Function f = functionManager.getFunctionAt(entryPt); Function f = functionManager.getFunctionAt(entryPt);
@ -209,8 +209,10 @@ public class FunctionManagerTest extends AbstractGhidraHeadedIntegrationTest {
f = functionManager.getFunctionAt(addr(250)); f = functionManager.getFunctionAt(addr(250));
assertEquals(new AddressSet(addr(250), addr(350)), f.getBody()); assertEquals(new AddressSet(addr(250), addr(350)), f.getBody());
assertTrue(program.getSymbolTable().getPrimarySymbol( assertTrue(program.getSymbolTable()
addr(201)).getSymbolType() != SymbolType.FUNCTION); .getPrimarySymbol(
addr(201))
.getSymbolType() != SymbolType.FUNCTION);
} }
@Test @Test
@ -301,16 +303,19 @@ public class FunctionManagerTest extends AbstractGhidraHeadedIntegrationTest {
createFunction("foo1", addr(250), new AddressSet(addr(250), addr(350))); createFunction("foo1", addr(250), new AddressSet(addr(250), addr(350)));
Function foo2 = createFunction("foo2", addr(201), new AddressSet(addr(201), addr(249))); Function foo2 = createFunction("foo2", addr(201), new AddressSet(addr(201), addr(249)));
Function fum = program.getExternalManager().addExtLocation("lib", "fum", null, Function fum = program.getExternalManager()
SourceType.USER_DEFINED).createFunction(); .addExtLocation("lib", "fum", null,
SourceType.USER_DEFINED)
.createFunction();
program.getMemory().setInt(addr(50), 201); program.getMemory().setInt(addr(50), 201);
program.getListing().createData(addr(50), PointerDataType.dataType); program.getListing().createData(addr(50), PointerDataType.dataType);
assertEquals(foo2, program.getFunctionManager().getReferencedFunction(addr(50))); assertEquals(foo2, program.getFunctionManager().getReferencedFunction(addr(50)));
program.getReferenceManager().addExternalReference(addr(50), 0, program.getReferenceManager()
program.getExternalManager().getExternalLocation(fum.getSymbol()), .addExternalReference(addr(50), 0,
SourceType.USER_DEFINED, RefType.DATA); program.getExternalManager().getExternalLocation(fum.getSymbol()),
SourceType.USER_DEFINED, RefType.DATA);
assertEquals(fum, program.getFunctionManager().getReferencedFunction(addr(50))); assertEquals(fum, program.getFunctionManager().getReferencedFunction(addr(50)));

View file

@ -27,9 +27,9 @@ import ghidra.app.cmd.function.CreateFunctionCmd;
import ghidra.program.database.ProgramBuilder; import ghidra.program.database.ProgramBuilder;
import ghidra.program.database.ProgramDB; import ghidra.program.database.ProgramDB;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.data.ByteDataType; import ghidra.program.model.data.*;
import ghidra.program.model.data.WordDataType;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
import ghidra.program.model.listing.Function.FunctionUpdateType;
import ghidra.program.model.mem.Memory; import ghidra.program.model.mem.Memory;
import ghidra.program.model.mem.MemoryBlock; import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.symbol.*; import ghidra.program.model.symbol.*;
@ -52,6 +52,7 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
private NamespaceManager scopeMgr; private NamespaceManager scopeMgr;
private int transactionID; private int transactionID;
private Namespace globalScope; private Namespace globalScope;
private Listing listing;
public SymbolManagerTest() { public SymbolManagerTest() {
super(); super();
@ -69,6 +70,7 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
st = program.getSymbolTable(); st = program.getSymbolTable();
refMgr = program.getReferenceManager(); refMgr = program.getReferenceManager();
scopeMgr = program.getNamespaceManager(); scopeMgr = program.getNamespaceManager();
listing = program.getListing();
} }
@After @After
@ -224,26 +226,26 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
Symbol[] s = st.getSymbols(addr(256)); Symbol[] s = st.getSymbols(addr(256));
assertEquals(1, s.length); assertEquals(1, s.length);
assertEquals("LAB_00000100", s[0].getName()); 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()); assertEquals("BYTE_00000100", s[0].getName());
} }
@Test @Test
public void testDynamicNameChangesWhenDataCleared() throws Exception { public void testDynamicNameChangesWhenDataCleared() throws Exception {
refMgr.addMemoryReference(addr(512), addr(256), RefType.FLOW, SourceType.USER_DEFINED, -1); 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)); Symbol[] s = st.getSymbols(addr(256));
assertEquals(1, s.length); assertEquals(1, s.length);
assertEquals("BYTE_00000100", s[0].getName()); 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()); assertEquals("LAB_00000100", s[0].getName());
} }
@Test @Test
public void testDynamicOffcutNameChangesWhenSymbolCreated() throws Exception { public void testDynamicOffcutNameChangesWhenSymbolCreated() throws Exception {
refMgr.addMemoryReference(addr(512), addr(257), RefType.FLOW, SourceType.USER_DEFINED, -1); 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)); Symbol[] s = st.getSymbols(addr(257));
assertEquals(1, s.length); assertEquals(1, s.length);
@ -255,7 +257,7 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
@Test @Test
public void testDynamicOffcutNameChangesWhenSymbolRenamed() throws Exception { public void testDynamicOffcutNameChangesWhenSymbolRenamed() throws Exception {
refMgr.addMemoryReference(addr(512), addr(257), RefType.FLOW, SourceType.USER_DEFINED, -1); 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 label = st.createLabel(addr(256), "bob", SourceType.USER_DEFINED);
Symbol[] s = st.getSymbols(addr(257)); Symbol[] s = st.getSymbols(addr(257));
@ -268,7 +270,7 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
@Test @Test
public void testDynamicOffcutNameChangesWhenSymbolRemoved() throws Exception { public void testDynamicOffcutNameChangesWhenSymbolRemoved() throws Exception {
refMgr.addMemoryReference(addr(512), addr(257), RefType.FLOW, SourceType.USER_DEFINED, -1); 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 label = st.createLabel(addr(256), "bob", SourceType.USER_DEFINED);
Symbol[] s = st.getSymbols(addr(257)); Symbol[] s = st.getSymbols(addr(257));
@ -277,6 +279,7 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
label.delete(); label.delete();
assertEquals("WORD_00000100+1", s[0].getName()); assertEquals("WORD_00000100+1", s[0].getName());
} }
@Test @Test
public void testDynamicNameChangesWhenOffcutByInstruction() throws Exception { public void testDynamicNameChangesWhenOffcutByInstruction() throws Exception {
refMgr.addMemoryReference(addr(512), addr(257), RefType.FLOW, SourceType.USER_DEFINED, -1); 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(1, s.length);
assertEquals("LAB_00000101", s[0].getName()); assertEquals("LAB_00000101", s[0].getName());
createInstruction(addr(256)); createInstruction(addr(256));
CodeUnit codeUnitAt = program.getListing().getCodeUnitAt(addr(256)); CodeUnit codeUnitAt = listing.getCodeUnitAt(addr(256));
assertTrue(codeUnitAt instanceof Instruction); assertTrue(codeUnitAt instanceof Instruction);
assertEquals(2, codeUnitAt.getLength()); assertEquals(2, codeUnitAt.getLength());
@ -320,7 +323,6 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
assertEquals("LAB_00000100", s[0].getName()); assertEquals("LAB_00000100", s[0].getName());
} }
private void createInstruction(Address addr) throws Exception { private void createInstruction(Address addr) throws Exception {
int tx = program.startTransaction("test"); int tx = program.startTransaction("test");
try { try {
@ -338,7 +340,6 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
@Test @Test
public void testGetDefaultFunctionSymbolByName() throws Exception { public void testGetDefaultFunctionSymbolByName() throws Exception {
Listing listing = program.getListing();
AddressSet set = new AddressSet(); AddressSet set = new AddressSet();
set.addRange(addr(100), addr(150)); set.addRange(addr(100), addr(150));
@ -398,8 +399,6 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
Address ovAddress = block.getStart(); Address ovAddress = block.getStart();
assertEquals("ov_12::00000000", ovAddress.toString()); assertEquals("ov_12::00000000", ovAddress.toString());
Listing listing = program.getListing();
AddressSet set = new AddressSet(ovAddress, ovAddress); AddressSet set = new AddressSet(ovAddress, ovAddress);
Function f = listing.createFunction("fredFunc", ovAddress, set, SourceType.DEFAULT); Function f = listing.createFunction("fredFunc", ovAddress, set, SourceType.DEFAULT);
assertNotNull(f); assertNotNull(f);
@ -426,7 +425,7 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
Address ovAddress = block.getStart(); Address ovAddress = block.getStart();
assertEquals("ov12::00000000", ovAddress.toString()); assertEquals("ov12::00000000", ovAddress.toString());
ovAddress = ovAddress.add(2); ovAddress = ovAddress.add(2);
Listing listing = p.getListing(); listing = p.getListing();
st = p.getSymbolTable(); st = p.getSymbolTable();
AddressSet set = new AddressSet(ovAddress, ovAddress); AddressSet set = new AddressSet(ovAddress, ovAddress);
@ -681,9 +680,8 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
@Test @Test
public void testRemoveFunctionSymbolAfterFunction() throws Exception { 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); new AddressSet(addr(0x0200), addr(0x0280)), SourceType.USER_DEFINED);
assertTrue(cmd.applyTo(program));
program.getFunctionManager().removeFunction(addr(0x0200)); program.getFunctionManager().removeFunction(addr(0x0200));
Symbol s = st.getPrimarySymbol(addr(0x0200)); Symbol s = st.getPrimarySymbol(addr(0x0200));
assertNotNull(s); assertNotNull(s);
@ -695,9 +693,8 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
@Test @Test
public void testRemoveFunctionBecomesCodeSymbol() throws Exception { 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); new AddressSet(addr(0x0200), addr(0x0280)), SourceType.USER_DEFINED);
assertTrue(cmd.applyTo(program));
Symbol s = st.getPrimarySymbol(addr(0x0200)); Symbol s = st.getPrimarySymbol(addr(0x0200));
assertEquals(SymbolType.FUNCTION, s.getSymbolType()); assertEquals(SymbolType.FUNCTION, s.getSymbolType());
@ -719,9 +716,8 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
@Test @Test
public void testRemoveFunctionSymbolBecomesExistingCodeSymbol() throws Exception { public void testRemoveFunctionSymbolBecomesExistingCodeSymbol() throws Exception {
Address entryPt = addr(0x0200); Address entryPt = addr(0x0200);
CreateFunctionCmd cmd = new CreateFunctionCmd("MyFunction", entryPt, createFunction("MyFunction", entryPt,
new AddressSet(addr(0x0200), addr(0x0280)), SourceType.USER_DEFINED); new AddressSet(addr(0x0200), addr(0x0280)), SourceType.USER_DEFINED);
assertTrue(cmd.applyTo(program));
st.createLabel(entryPt, "Bob", SourceType.USER_DEFINED); 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 oldNamespace = st.createNameSpace(null, "OldNameSpace", SourceType.USER_DEFINED);
Namespace newNamespace = st.createNameSpace(null, "NewNameSpace", SourceType.USER_DEFINED); Namespace newNamespace = st.createNameSpace(null, "NewNameSpace", SourceType.USER_DEFINED);
Address entryPt = addr(0x0200); Address entryPt = addr(0x0200);
CreateFunctionCmd cmd = new CreateFunctionCmd("MyFunction", entryPt, createFunction("MyFunction", entryPt, new AddressSet(addr(0x0200), addr(0x0280)),
new AddressSet(addr(0x0200), addr(0x0280)), SourceType.USER_DEFINED); SourceType.USER_DEFINED);
assertTrue(cmd.applyTo(program));
Symbol functionSym = program.getFunctionManager().getFunctionAt(entryPt).getSymbol(); Symbol functionSym = program.getFunctionManager().getFunctionAt(entryPt).getSymbol();
Symbol conflictSym = st.createLabel(addr(0x0230), "Bob", SourceType.USER_DEFINED);// put a conflict symbol in. Symbol conflictSym = st.createLabel(addr(0x0230), "Bob", SourceType.USER_DEFINED);// put a conflict symbol in.
conflictSym.setNamespace(oldNamespace); conflictSym.setNamespace(oldNamespace);
@ -794,9 +789,8 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
@Test @Test
public void testRemoveFunctionSymbolBecomesDefault() throws Exception { 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); new AddressSet(addr(0x0200), addr(0x0280)), SourceType.USER_DEFINED);
assertTrue(cmd.applyTo(program));
Symbol s = st.getPrimarySymbol(addr(0x0200)); Symbol s = st.getPrimarySymbol(addr(0x0200));
assertEquals(SymbolType.FUNCTION, s.getSymbolType()); 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. 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 @Test
public void testRenameSymbol() throws Exception { public void testRenameSymbol() throws Exception {
Symbol s = createSymbol(addr(100), "primary"); Symbol s = createSymbol(addr(100), "primary");
@ -1271,6 +1371,48 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
assertEquals("1", s.getName()); 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 @Test
public void testAddReference() throws Exception { public void testAddReference() throws Exception {
refMgr.addMemoryReference(addr(512), addr(256), RefType.CONDITIONAL_CALL, refMgr.addMemoryReference(addr(512), addr(256), RefType.CONDITIONAL_CALL,
@ -1321,7 +1463,6 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
@Test @Test
public void testCreateFunction() throws Exception { public void testCreateFunction() throws Exception {
Listing listing = program.getListing();
Symbol s = createSymbol(addr(100), "fred"); Symbol s = createSymbol(addr(100), "fred");
assertTrue(s.isPrimary()); assertTrue(s.isPrimary());
@ -1330,7 +1471,7 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
set.addRange(addr(100), addr(150)); set.addRange(addr(100), addr(150));
set.addRange(addr(300), addr(310)); set.addRange(addr(300), addr(310));
set.addRange(addr(320), addr(330)); 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)); Symbol s1 = st.getPrimarySymbol(addr(100));
assertNotNull(s1); assertNotNull(s1);
@ -1349,7 +1490,6 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
@Test @Test
public void testPromoteLabelToFunctionWithMultipleLabels() throws Exception { public void testPromoteLabelToFunctionWithMultipleLabels() throws Exception {
Listing listing = program.getListing();
Symbol s = createSymbol(addr(100), "fred"); Symbol s = createSymbol(addr(100), "fred");
assertTrue(s.isPrimary()); assertTrue(s.isPrimary());
@ -1367,7 +1507,6 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
@Test @Test
public void testRenameFunctionToExistingName() throws Exception { public void testRenameFunctionToExistingName() throws Exception {
Listing listing = program.getListing();
AddressSet set1 = new AddressSet(); AddressSet set1 = new AddressSet();
set1.addRange(addr(100), addr(150)); set1.addRange(addr(100), addr(150));
@ -1386,7 +1525,6 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
@Test @Test
public void testRemoveFunction() throws Exception { public void testRemoveFunction() throws Exception {
Listing listing = program.getListing();
Symbol s = createSymbol(addr(100), "fred"); Symbol s = createSymbol(addr(100), "fred");
assertFalse(s.isDeleted()); 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 @Test
public void testDuplicateSymbol() throws Exception { public void testDuplicateSymbol() throws Exception {
st.createNameSpace(null, "MySpace1", SourceType.USER_DEFINED); st.createNameSpace(null, "MySpace1", SourceType.USER_DEFINED);
st.createNameSpace(null, "MySpace2", SourceType.USER_DEFINED); st.createNameSpace(null, "MySpace2", SourceType.USER_DEFINED);
try { try {
@ -1704,12 +2110,10 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
catch (DuplicateNameException e) { catch (DuplicateNameException e) {
// good // good
} }
} }
@Test @Test
public void testDuplicateFunctionNames() throws Exception { public void testDuplicateFunctionNames() throws Exception {
Listing listing = program.getListing();
AddressSet set1 = new AddressSet(); AddressSet set1 = new AddressSet();
set1.addRange(addr(100), addr(150)); set1.addRange(addr(100), addr(150));
@ -1722,7 +2126,6 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
assertNotNull(f2); assertNotNull(f2);
List<Symbol> symbols = st.getGlobalSymbols("fredFunc"); List<Symbol> symbols = st.getGlobalSymbols("fredFunc");
assertEquals(2, symbols.size()); assertEquals(2, symbols.size());
} }
@Test @Test
@ -1773,8 +2176,9 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
assertTrue(s.isValidParent(subspace1)); assertTrue(s.isValidParent(subspace1));
AddressSet set = new AddressSet(addr(0x100), addr(0x150)); AddressSet set = new AddressSet(addr(0x100), addr(0x150));
Function f = program.getFunctionManager().createFunction("function_1", addr(0x100), set, Function f = program.getFunctionManager()
SourceType.USER_DEFINED); .createFunction("function_1", addr(0x100), set,
SourceType.USER_DEFINED);
assertTrue(s.isValidParent(f)); assertTrue(s.isValidParent(f));
Namespace scope = st.createClass(null, "TestScope", SourceType.USER_DEFINED); Namespace scope = st.createClass(null, "TestScope", SourceType.USER_DEFINED);
@ -1791,11 +2195,13 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
Namespace subspace1 = st.createNameSpace(namespace, "MySpace1", SourceType.USER_DEFINED); Namespace subspace1 = st.createNameSpace(namespace, "MySpace1", SourceType.USER_DEFINED);
AddressSet set = new AddressSet(addr(0x100), addr(0x150)); AddressSet set = new AddressSet(addr(0x100), addr(0x150));
Function f1 = program.getFunctionManager().createFunction("function_1", addr(0x100), set, Function f1 = program.getFunctionManager()
SourceType.USER_DEFINED); .createFunction("function_1", addr(0x100), set,
SourceType.USER_DEFINED);
set = new AddressSet(addr(0x200), addr(0x250)); set = new AddressSet(addr(0x200), addr(0x250));
Function f2 = program.getFunctionManager().createFunction("function_2", addr(0x200), set, Function f2 = program.getFunctionManager()
SourceType.USER_DEFINED); .createFunction("function_2", addr(0x200), set,
SourceType.USER_DEFINED);
assertTrue(f1.getSymbol().isValidParent(subspace1));// TestNameSpace::MySpace1::function_1 is OK assertTrue(f1.getSymbol().isValidParent(subspace1));// TestNameSpace::MySpace1::function_1 is OK
@ -1823,8 +2229,9 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
public void testIsValidParentForNamespace() throws Exception { public void testIsValidParentForNamespace() throws Exception {
AddressSet set = new AddressSet(addr(0x100), addr(0x150)); AddressSet set = new AddressSet(addr(0x100), addr(0x150));
Function f1 = program.getFunctionManager().createFunction("function_1", addr(0x100), set, Function f1 = program.getFunctionManager()
SourceType.USER_DEFINED); .createFunction("function_1", addr(0x100), set,
SourceType.USER_DEFINED);
Namespace namespace = st.createNameSpace(null, "TestNameSpace", SourceType.USER_DEFINED); Namespace namespace = st.createNameSpace(null, "TestNameSpace", SourceType.USER_DEFINED);
Namespace subspace1 = st.createNameSpace(null, "MySpace1", SourceType.USER_DEFINED); Namespace subspace1 = st.createNameSpace(null, "MySpace1", SourceType.USER_DEFINED);
@ -1857,8 +2264,9 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest {
public void testInvalidExternalScope() throws Exception { public void testInvalidExternalScope() throws Exception {
Library lib = st.createExternalLibrary("extLib", SourceType.USER_DEFINED); Library lib = st.createExternalLibrary("extLib", SourceType.USER_DEFINED);
ExternalLocation extLoc = program.getExternalManager().addExtFunction("extLib", "printf", ExternalLocation extLoc = program.getExternalManager()
null, SourceType.USER_DEFINED); .addExtFunction("extLib", "printf",
null, SourceType.USER_DEFINED);
Symbol extSym = extLoc.getSymbol(); Symbol extSym = extLoc.getSymbol();
assertEquals(SymbolType.FUNCTION, extSym.getSymbolType()); assertEquals(SymbolType.FUNCTION, extSym.getSymbolType());
Function extFunc = (Function) extSym.getObject(); Function extFunc = (Function) extSym.getObject();

View file

@ -59,7 +59,7 @@ public class BinaryField extends Field {
} }
@Override @Override
boolean isNull() { public boolean isNull() {
return data == null; return data == null;
} }

View file

@ -112,7 +112,7 @@ public abstract class Field implements Comparable<Field> {
* is reserved for use in the special-purpose byte value 0x88. * is reserved for use in the special-purpose byte value 0x88.
* (see {@link LegacyIndexField}) * (see {@link LegacyIndexField})
*/ */
static final byte LEGACY_INDEX_LONG_TYPE = 8; static final byte LEGACY_INDEX_LONG_TYPE = 8;
// Available field types (6): 0x9..0xE // Available field types (6): 0x9..0xE
@ -424,7 +424,7 @@ public abstract class Field implements Comparable<Field> {
* Determine if the field has been set to a null-state or value. * 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 * @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 * Set this field to its null-state. For variable-length field this will

View file

@ -47,7 +47,7 @@ abstract class FixedField extends BinaryField {
} }
@Override @Override
final boolean isNull() { public final boolean isNull() {
return isNull; return isNull;
} }

View file

@ -56,7 +56,7 @@ class IndexField extends Field {
} }
@Override @Override
boolean isNull() { public boolean isNull() {
return false; // not-applicable return false; // not-applicable
} }

View file

@ -42,7 +42,7 @@ abstract class PrimitiveField extends Field {
} }
@Override @Override
final boolean isNull() { public final boolean isNull() {
return isNull; return isNull;
} }

View file

@ -67,7 +67,7 @@ public final class StringField extends Field {
} }
@Override @Override
boolean isNull() { public boolean isNull() {
return bytes == null; return bytes == null;
} }

View file

@ -98,7 +98,7 @@ public class ExternalLocationDB implements ExternalLocation {
@Override @Override
public String getOriginalImportedName() { public String getOriginalImportedName() {
return getExternalData3(symbol).getOriginalImportedName(); return getExternalData(symbol).getOriginalImportedName();
} }
@Override @Override
@ -111,7 +111,7 @@ public class ExternalLocationDB implements ExternalLocation {
*/ */
@Override @Override
public Address getAddress() { 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 @Override
public DataType getDataType() { public DataType getDataType() {
long dataTypeID = symbol.getSymbolData1(); long dataTypeID = symbol.getDataTypeId();
if (dataTypeID < 0) { if (dataTypeID < 0) {
return null; return null;
} }
@ -154,7 +154,7 @@ public class ExternalLocationDB implements ExternalLocation {
@Override @Override
public void setDataType(DataType dt) { public void setDataType(DataType dt) {
long dataTypeID = extMgr.getProgram().getDataTypeManager().getResolvedID(dt); long dataTypeID = extMgr.getProgram().getDataTypeManager().getResolvedID(dt);
symbol.setSymbolData1(dataTypeID); symbol.setDataTypeId(dataTypeID);
// TODO: change notification may be required // TODO: change notification may be required
} }
@ -227,7 +227,7 @@ public class ExternalLocationDB implements ExternalLocation {
if (addressString == null && getSource() == SourceType.DEFAULT) { if (addressString == null && getSource() == SourceType.DEFAULT) {
throw new InvalidInputException("Either an external label or address is required"); throw new InvalidInputException("Either an external label or address is required");
} }
updateSymbolData3(symbol, getExternalData3(symbol).getOriginalImportedName(), updateSymbolData(symbol, getExternalData(symbol).getOriginalImportedName(),
addressString); addressString);
} }
@ -365,18 +365,18 @@ public class ExternalLocationDB implements ExternalLocation {
} }
static ExternalData3 getExternalData3(SymbolDB extSymbol) { static ExternalData getExternalData(SymbolDB extSymbol) {
return new ExternalData3(extSymbol.getSymbolData3()); return new ExternalData(extSymbol.getSymbolStringData());
} }
static void setOriginalImportedName(SymbolDB extSymbol, String name) { 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) { String addressString) {
if (addressString == null && originalImportedName == null) { if (addressString == null && originalImportedName == null) {
extSymbol.setSymbolData3(null); extSymbol.setSymbolStringData(null);
} }
StringBuilder buf = new StringBuilder(); StringBuilder buf = new StringBuilder();
if (addressString != null) { if (addressString != null) {
@ -386,18 +386,18 @@ public class ExternalLocationDB implements ExternalLocation {
buf.append(ORIGINAL_IMPORTED_DELIMITER); buf.append(ORIGINAL_IMPORTED_DELIMITER);
buf.append(originalImportedName); buf.append(originalImportedName);
} }
extSymbol.setSymbolData3(buf.toString()); extSymbol.setSymbolStringData(buf.toString());
} }
static class ExternalData3 { static class ExternalData {
private String originalImportedName; private String originalImportedName;
private String addressString; private String addressString;
ExternalData3(String data3) { ExternalData(String stringData) {
if (data3 != null) { if (stringData != null) {
int indexOf = data3.indexOf(ORIGINAL_IMPORTED_DELIMITER); int indexOf = stringData.indexOf(ORIGINAL_IMPORTED_DELIMITER);
originalImportedName = indexOf >= 0 ? data3.substring(indexOf + 1) : null; originalImportedName = indexOf >= 0 ? stringData.substring(indexOf + 1) : null;
addressString = indexOf >= 0 ? data3.substring(0, indexOf) : data3; addressString = indexOf >= 0 ? stringData.substring(0, indexOf) : stringData;
} }
} }

View file

@ -22,7 +22,7 @@ import db.*;
import ghidra.framework.store.FileSystem; import ghidra.framework.store.FileSystem;
import ghidra.program.database.ManagerDB; import ghidra.program.database.ManagerDB;
import ghidra.program.database.ProgramDB; 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.function.FunctionManagerDB;
import ghidra.program.database.map.AddressMap; import ghidra.program.database.map.AddressMap;
import ghidra.program.database.symbol.*; import ghidra.program.database.symbol.*;
@ -556,15 +556,15 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
if ((type != SymbolType.LABEL && type != SymbolType.FUNCTION) || !sym.isExternal()) { if ((type != SymbolType.LABEL && type != SymbolType.FUNCTION) || !sym.isExternal()) {
throw new AssertException(); throw new AssertException();
} }
ExternalData3 externalData3 = ExternalLocationDB.getExternalData3(sym); ExternalData externalData = ExternalLocationDB.getExternalData(sym);
Address addr = externalData3.getAddress(sym.getProgram().getAddressFactory()); Address addr = externalData.getAddress(sym.getProgram().getAddressFactory());
if (addr == null) { if (addr == null) {
throw new AssertException("External should not be default without memory address"); throw new AssertException("External should not be default without memory address");
} }
if (type == SymbolType.FUNCTION) { if (type == SymbolType.FUNCTION) {
return SymbolUtilities.getDefaultExternalFunctionName(addr); return SymbolUtilities.getDefaultExternalFunctionName(addr);
} }
long dataTypeID = sym.getSymbolData1(); long dataTypeID = sym.getDataTypeId();
DataType dt = DataType dt =
(dataTypeID < 0) ? null : sym.getProgram().getDataTypeManager().getDataType(dataTypeID); (dataTypeID < 0) ? null : sym.getProgram().getDataTypeManager().getDataType(dataTypeID);
return SymbolUtilities.getDefaultExternalName(addr, dt); return SymbolUtilities.getDefaultExternalName(addr, dt);
@ -695,7 +695,7 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
private Library addExternalName(String name, String pathname, SourceType source) private Library addExternalName(String name, String pathname, SourceType source)
throws DuplicateNameException, InvalidInputException { throws DuplicateNameException, InvalidInputException {
SymbolDB s = symbolMgr.createSpecialSymbol(Address.NO_ADDRESS, name, 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(); return (Library) s.getObject();
} }
@ -742,7 +742,7 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
public String getExternalLibraryPath(String externalName) { public String getExternalLibraryPath(String externalName) {
SymbolDB s = (SymbolDB) symbolMgr.getLibrarySymbol(externalName); SymbolDB s = (SymbolDB) symbolMgr.getLibrarySymbol(externalName);
if (s instanceof LibrarySymbol) { if (s instanceof LibrarySymbol) {
return s.getSymbolData3(); return s.getSymbolStringData();
} }
return null; return null;
} }
@ -771,7 +771,7 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
} }
} }
else if (s instanceof LibrarySymbol) { else if (s instanceof LibrarySymbol) {
s.setSymbolData3(externalPath); s.setSymbolStringData(externalPath);
} }
} }
finally { finally {
@ -802,7 +802,7 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
return null; return null;
} }
//long dtId = symbol.getSymbolData1(); //long dtId = symbol.getSymbolData1();
String extData3 = symbol.getSymbolData3(); String extData = symbol.getSymbolStringData();
String name = symbol.getName(); String name = symbol.getName();
Namespace namespace = symbol.getParentNamespace(); Namespace namespace = symbol.getParentNamespace();
Address extAddr = symbol.getAddress(); Address extAddr = symbol.getAddress();
@ -810,7 +810,7 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
((CodeSymbol) symbol).delete(true); ((CodeSymbol) symbol).delete(true);
return functionMgr.createExternalFunction(extAddr, name, namespace, extData3, source); return functionMgr.createExternalFunction(extAddr, name, namespace, extData, source);
} }
catch (Exception e) { catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
@ -927,8 +927,8 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
while (externalSymbols.hasNext()) { while (externalSymbols.hasNext()) {
monitor.checkCanceled(); monitor.checkCanceled();
SymbolDB s = (SymbolDB) externalSymbols.next(); SymbolDB s = (SymbolDB) externalSymbols.next();
ExternalData3 externalData3 = ExternalLocationDB.getExternalData3(s); ExternalData externalData = ExternalLocationDB.getExternalData(s);
String addrStr = externalData3.getAddressString(); String addrStr = externalData.getAddressString();
if (addrStr == null) { if (addrStr == null) {
continue; continue;
} }
@ -947,7 +947,7 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
addr = newAddressSpace.getAddress(addr.getOffset()); addr = newAddressSpace.getAddress(addr.getOffset());
String newAddrStr = addr.toString(); String newAddrStr = addr.toString();
if (!newAddrStr.equals(addrStr)) { if (!newAddrStr.equals(addrStr)) {
ExternalLocationDB.updateSymbolData3(s, externalData3.getOriginalImportedName(), ExternalLocationDB.updateSymbolData(s, externalData.getOriginalImportedName(),
newAddrStr); // store translated external location address newAddrStr); // store translated external location address
} }
} }

View file

@ -990,7 +990,7 @@ public class FunctionDB extends DatabaseObject implements Function {
symbolMap.put(v.symbol, v); symbolMap.put(v.symbol, v);
} }
if (var.getComment() != null) { if (var.getComment() != null) {
v.symbol.setSymbolData3(var.getComment()); v.symbol.setSymbolStringData(var.getComment());
} }
manager.functionChanged(this, 0); manager.functionChanged(this, 0);
return v; return v;
@ -1678,7 +1678,7 @@ public class FunctionDB extends DatabaseObject implements Function {
manager.functionChanged(this, ChangeManager.FUNCTION_CHANGED_PARAMETERS); manager.functionChanged(this, ChangeManager.FUNCTION_CHANGED_PARAMETERS);
} }
if (var.getComment() != null) { if (var.getComment() != null) {
p.symbol.setSymbolData3(var.getComment()); p.symbol.setSymbolStringData(var.getComment());
} }
updateSignatureSourceAfterVariableChange(source, p.getDataType()); updateSignatureSourceAfterVariableChange(source, p.getDataType());
return p; return p;

View file

@ -273,22 +273,22 @@ public class FunctionManagerDB implements FunctionManager {
* Transform an existing external symbol into an external function. * Transform an existing external symbol into an external function.
* This method should only be invoked by an ExternalSymbol * This method should only be invoked by an ExternalSymbol
* @param extSpaceAddr the external space address to use when creating this external. * @param extSpaceAddr the external space address to use when creating this external.
* @param name * @param name the external function name
* @param nameSpace * @param nameSpace the external function namespace
* @param extData3 internal symbol-data-3 string (see {@link ExternalLocationDB}) * @param extData the external data string to store additional info (see {@link ExternalLocationDB})
* @param source the source of this external. * @param source the source of this external.
* @return external function * @return external function
* @throws InvalidInputException * @throws InvalidInputException if the name is invalid
* @throws DuplicateNameException * @throws DuplicateNameException if the name is an invalid duplicate
*/ */
public Function createExternalFunction(Address extSpaceAddr, String name, Namespace nameSpace, public Function createExternalFunction(Address extSpaceAddr, String name, Namespace nameSpace,
String extData3, SourceType source) String extData, SourceType source)
throws DuplicateNameException, InvalidInputException { throws DuplicateNameException, InvalidInputException {
lock.acquire(); lock.acquire();
try { try {
Symbol symbol = symbolMgr.createSpecialSymbol(extSpaceAddr, name, nameSpace, 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); long returnDataTypeId = program.getDataTypeManager().getResolvedID(DataType.DEFAULT);

View file

@ -167,12 +167,12 @@ public abstract class VariableDB implements Variable {
@Override @Override
public String getComment() { public String getComment() {
return symbol.getSymbolData3(); return symbol.getSymbolStringData();
} }
@Override @Override
public void setComment(String comment) { public void setComment(String comment) {
symbol.setSymbolData3(comment); symbol.setSymbolStringData(comment);
functionMgr.functionChanged(function, 0); functionMgr.functionChanged(function, 0);
} }

View file

@ -20,26 +20,21 @@ import java.util.Iterator;
import db.DBRecord; import db.DBRecord;
import db.RecordIterator; import db.RecordIterator;
import ghidra.program.database.util.Query; import ghidra.program.database.util.*;
import ghidra.program.database.util.QueryRecordIterator; import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.address.*;
import ghidra.program.model.symbol.Symbol; import ghidra.program.model.symbol.Symbol;
import ghidra.program.model.symbol.SymbolIterator; 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 { class AddressSetFilteredSymbolIterator implements SymbolIterator {
private SymbolManager symbolMgr; private SymbolManager symbolMgr;
private AddressRangeIterator rangeIter;
private QueryRecordIterator recIter; private QueryRecordIterator recIter;
private Symbol currentSymbol;
private SymbolDatabaseAdapter adapter; private SymbolDatabaseAdapter adapter;
private boolean forward;
private Query query;
/** /**
* Construct a new AddressSetFilteredSymbolIterator. * Construct a new AddressSetFilteredSymbolIterator.
@ -51,53 +46,40 @@ class AddressSetFilteredSymbolIterator implements SymbolIterator {
AddressSetFilteredSymbolIterator(SymbolManager symbolMgr, AddressSetView set, Query query, AddressSetFilteredSymbolIterator(SymbolManager symbolMgr, AddressSetView set, Query query,
boolean forward) { boolean forward) {
this.symbolMgr = symbolMgr; this.symbolMgr = symbolMgr;
rangeIter = set.getAddressRanges(forward);
adapter = symbolMgr.getDatabaseAdapter(); adapter = symbolMgr.getDatabaseAdapter();
this.forward = forward; try {
this.query = query; 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 @Override
public boolean hasNext() { public boolean hasNext() {
if (currentSymbol == null) { try {
try { return recIter.hasNext();
findNext();
}
catch (IOException e) {
symbolMgr.dbError(e);
}
} }
return currentSymbol != null; catch (IOException e) {
symbolMgr.dbError(e);
}
return false;
} }
@Override @Override
public Symbol next() { public Symbol next() {
if (hasNext()) { if (hasNext()) {
Symbol s = currentSymbol; try {
currentSymbol = null; DBRecord rec = recIter.next();
return s; return symbolMgr.getSymbol(rec);
} }
return null; catch (IOException e) {
} symbolMgr.dbError(e);
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;
}
} }
} }
return null;
} }
@Override @Override

View file

@ -30,10 +30,7 @@ import ghidra.program.util.ProgramLocation;
* *
* Symbol data usage: * Symbol data usage:
* EXTERNAL: * EXTERNAL:
* long data1 - external data type * String stringData - external memory address/label
* String data3 - external memory address
* NON-EXTERNAL:
* int data2 - primary flag
*/ */
public class CodeSymbol extends SymbolDB { public class CodeSymbol extends SymbolDB {
@ -162,7 +159,7 @@ public class CodeSymbol extends SymbolDB {
if (getSource() == SourceType.DEFAULT || isExternal()) { if (getSource() == SourceType.DEFAULT || isExternal()) {
return true; return true;
} }
return getSymbolData2() == 1; return doCheckIsPrimary();
} }
/** /**
@ -201,7 +198,7 @@ public class CodeSymbol extends SymbolDB {
} }
void setPrimary(boolean primary) { void setPrimary(boolean primary) {
setSymbolData2(primary ? 1 : 0); doSetPrimary(primary);
} }
/** /**

View file

@ -39,10 +39,7 @@ import ghidra.util.task.TaskMonitor;
* *
* Symbol Data Usage: * Symbol Data Usage:
* EXTERNAL: * EXTERNAL:
* long data1 - external data type * String stringData - external memory address/label
* String data3 - external memory address
* NON-EXTERNAL:
* - not used -
*/ */
public class FunctionSymbol extends SymbolDB { public class FunctionSymbol extends SymbolDB {
@ -103,9 +100,9 @@ public class FunctionSymbol extends SymbolDB {
try { try {
boolean restoreLabel = isExternal() || (getSource() != SourceType.DEFAULT); boolean restoreLabel = isExternal() || (getSource() != SourceType.DEFAULT);
String symName = getName(); String symName = getName();
String extData3 = null; String extData = null;
if (isExternal()) { if (isExternal()) {
extData3 = getSymbolData3(); // preserve external data extData = getSymbolStringData(); // preserve external data
} }
Namespace namespace = getParentNamespace(); Namespace namespace = getParentNamespace();
SourceType source = getSource(); SourceType source = getSource();
@ -120,7 +117,7 @@ public class FunctionSymbol extends SymbolDB {
if (super.delete()) { if (super.delete()) {
if (restoreLabel) { if (restoreLabel) {
boolean restored = createLabelForDeletedFunctionName(address, symName, extData3, boolean restored = createLabelForDeletedFunctionName(address, symName, extData,
namespace, source, pinned); namespace, source, pinned);
if (!restored && isExternal()) { if (!restored && isExternal()) {
removeAllReferencesTo(); 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). * does not mean that we want to lose the function name (that is our policy).
*/ */
private boolean createLabelForDeletedFunctionName(Address entryPoint, String symName, 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()) { if (isExternal()) {
SymbolDB parent = (SymbolDB) namespace.getSymbol(); SymbolDB parent = (SymbolDB) namespace.getSymbol();
if (parent.isDeleting()) { if (parent.isDeleting()) {
@ -151,7 +148,7 @@ public class FunctionSymbol extends SymbolDB {
SymbolDB newSym; SymbolDB newSym;
try { try {
newSym = symbolMgr.createSpecialSymbol(entryPoint, symName, namespace, newSym = symbolMgr.createSpecialSymbol(entryPoint, symName, namespace,
SymbolType.LABEL, -1, -1, data3, source); SymbolType.LABEL, null, null, stringData, source);
if (pinned) { if (pinned) {
newSym.setPinned(true); newSym.setPinned(true);
} }
@ -161,7 +158,7 @@ public class FunctionSymbol extends SymbolDB {
newSym = (SymbolDB) symbolMgr.createLabel(entryPoint, symName, newSym = (SymbolDB) symbolMgr.createLabel(entryPoint, symName,
program.getGlobalNamespace(), source); program.getGlobalNamespace(), source);
} }
newSym.setSymbolData3(data3); // reserved for external location use newSym.setSymbolStringData(stringData);
newSym.setPrimary(); newSym.setPrimary();
return true; return true;
} }
@ -275,56 +272,11 @@ public class FunctionSymbol extends SymbolDB {
return super.doGetParentNamespace(); 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() { private Symbol getThunkedSymbol() {
long thunkedFunctionId = functionMgr.getThunkedFunctionId(key); long thunkedFunctionId = functionMgr.getThunkedFunctionId(key);
return (thunkedFunctionId >= 0) ? symbolMgr.getSymbol(thunkedFunctionId) : null; 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 @Override
protected SourceType validateNameSource(String newName, SourceType source) { protected SourceType validateNameSource(String newName, SourceType source) {
// if (isThunk()) { // if (isThunk()) {

View file

@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -109,7 +108,7 @@ class LibraryDB implements Library {
@Override @Override
public String getAssociatedProgramPath() { public String getAssociatedProgramPath() {
return symbol.getSymbolData3(); return symbol.getSymbolStringData();
} }
@Override @Override

View file

@ -31,8 +31,7 @@ import ghidra.util.exception.InvalidInputException;
* Class for library symbols. * Class for library symbols.
* *
* Symbol data usage: * Symbol data usage:
* int data2 - set to 0 (not used) * String stringData - associated program project file path
* String data3 - associated program project file path
*/ */
public class LibrarySymbol extends SymbolDB { public class LibrarySymbol extends SymbolDB {
@ -64,8 +63,9 @@ public class LibrarySymbol extends SymbolDB {
super.setName(newName, source); super.setName(newName, source);
if (!oldName.equals(getName())) { if (!oldName.equals(getName())) {
symbolMgr.getProgram().setObjChanged(ChangeManager.DOCR_EXTERNAL_NAME_CHANGED, symbolMgr.getProgram()
(Address) null, null, oldName, newName); .setObjChanged(ChangeManager.DOCR_EXTERNAL_NAME_CHANGED,
(Address) null, null, oldName, newName);
} }
} }
@ -77,19 +77,21 @@ public class LibrarySymbol extends SymbolDB {
super.setNameAndNamespace(newName, newNamespace, source); super.setNameAndNamespace(newName, newNamespace, source);
if (!oldName.equals(getName())) { if (!oldName.equals(getName())) {
symbolMgr.getProgram().setObjChanged(ChangeManager.DOCR_EXTERNAL_NAME_CHANGED, symbolMgr.getProgram()
(Address) null, null, oldName, newName); .setObjChanged(ChangeManager.DOCR_EXTERNAL_NAME_CHANGED,
(Address) null, null, oldName, newName);
} }
} }
@Override @Override
public void setSymbolData3(String newPath) { public void setSymbolStringData(String newPath) {
String oldPath = getSymbolData3(); String oldPath = getSymbolStringData();
super.setSymbolData3(newPath); super.setSymbolStringData(newPath);
symbolMgr.getProgram().setObjChanged(ChangeManager.DOCR_EXTERNAL_PATH_CHANGED, getName(), symbolMgr.getProgram()
oldPath, newPath); .setObjChanged(ChangeManager.DOCR_EXTERNAL_PATH_CHANGED, getName(),
oldPath, newPath);
} }
public SymbolType getSymbolType() { public SymbolType getSymbolType() {

View file

@ -16,10 +16,10 @@
package ghidra.program.database.symbol; package ghidra.program.database.symbol;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.*;
import java.util.List;
import db.DBRecord; import db.DBRecord;
import db.Field;
import ghidra.program.database.*; import ghidra.program.database.*;
import ghidra.program.database.external.ExternalLocationDB; import ghidra.program.database.external.ExternalLocationDB;
import ghidra.program.database.external.ExternalManagerDB; 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 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 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 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, protected void moveLowLevel(Address newAddress, String newName, Namespace newNamespace,
SourceType newSource, boolean pinned) { SourceType newSource, boolean pinned) {
lock.acquire(); lock.acquire();
try { try {
checkDeleted(); checkDeleted();
Address oldAddress = address;
record.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL, // update the address to the new location
symbolMgr.getAddressMap().getKey(newAddress, true)); 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) { if (newName != null) {
record.setString(SymbolDatabaseAdapter.SYMBOL_NAME_COL, newName); record.setString(SymbolDatabaseAdapter.SYMBOL_NAME_COL, newName);
if (newName.length() == 0) {
setSourceFlagBit(SourceType.DEFAULT);
}
} }
if (newNamespace != null) { if (newNamespace != null) {
record.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL, newNamespace.getID()); 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(); lock.acquire();
try { try {
checkIsValid(); checkIsValid();
if (record == null) { if (record == null) {
return null; return null;
} }
return record.getString(SymbolDatabaseAdapter.SYMBOL_DATA3_COL); return record.getString(SymbolDatabaseAdapter.SYMBOL_STRING_DATA_COL);
} }
finally { finally {
lock.release(); 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(); lock.acquire();
try { try {
checkDeleted(); checkDeleted();
if (record == null) { if (record == null) {
return; return;
} }
String oldData = record.getString(SymbolDatabaseAdapter.SYMBOL_DATA3_COL); String oldData = record.getString(SymbolDatabaseAdapter.SYMBOL_STRING_DATA_COL);
if (SystemUtilities.isEqual(data3, oldData)) { if (Objects.equals(stringData, oldData)) {
return; return;
} }
record.setString(SymbolDatabaseAdapter.SYMBOL_DATA3_COL, data3); record.setString(SymbolDatabaseAdapter.SYMBOL_STRING_DATA_COL, stringData);
updateRecord(); updateRecord();
symbolMgr.symbolDataChanged(this); symbolMgr.symbolDataChanged(this);
} }
@ -836,14 +850,18 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
} }
} }
public long getSymbolData1() { public long getDataTypeId() {
lock.acquire(); lock.acquire();
try { try {
checkIsValid(); checkIsValid();
if (record != null) { if (record != null) {
return record.getLongValue(SymbolDatabaseAdapter.SYMBOL_DATA1_COL); Field value = record.getFieldValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL);
if (value.isNull()) {
return -1;
}
return value.getLongValue();
} }
return 0; return -1;
} }
finally { finally {
lock.release(); lock.release();
@ -854,12 +872,12 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
* Sets the generic symbol data 1. * Sets the generic symbol data 1.
* @param value the value to set as 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(); lock.acquire();
try { try {
checkDeleted(); checkDeleted();
if (record != null) { if (record != null) {
record.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATA1_COL, value); record.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL, value);
updateRecord(); updateRecord();
symbolMgr.symbolDataChanged(this); symbolMgr.symbolDataChanged(this);
} }
@ -873,12 +891,12 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
* gets the generic symbol data 2 data. * gets the generic symbol data 2 data.
* @return the symbol data * @return the symbol data
*/ */
public int getSymbolData2() { protected int getVariableOffset() {
lock.acquire(); lock.acquire();
try { try {
checkIsValid(); checkIsValid();
if (record != null) { if (record != null) {
return record.getIntValue(SymbolDatabaseAdapter.SYMBOL_DATA2_COL); return record.getIntValue(SymbolDatabaseAdapter.SYMBOL_VAROFFSET_COL);
} }
return 0; return 0;
} }
@ -888,15 +906,16 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol {
} }
/** /**
* Sets the generic symbol data 2 data * Sets the symbol's variable offset. For parameters, this is the ordinal, for locals, it is
* @param value the value to set as the symbols data 2 value. * 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(); lock.acquire();
try { try {
checkDeleted(); checkDeleted();
if (record != null) { if (record != null) {
record.setIntValue(SymbolDatabaseAdapter.SYMBOL_DATA2_COL, value); record.setIntValue(SymbolDatabaseAdapter.SYMBOL_VAROFFSET_COL, offset);
updateRecord(); updateRecord();
symbolMgr.symbolDataChanged(this); 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 @Override
public boolean delete() { public boolean delete() {
lock.acquire(); lock.acquire();

View file

@ -16,14 +16,16 @@
package ghidra.program.database.symbol; package ghidra.program.database.symbol;
import java.io.IOException; import java.io.IOException;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import db.*; import db.*;
import ghidra.program.database.map.AddressMap; import ghidra.program.database.map.AddressMap;
import ghidra.program.model.address.Address; import ghidra.program.database.util.*;
import ghidra.program.model.address.AddressSpace; import ghidra.program.model.address.*;
import ghidra.program.model.symbol.SourceType; import ghidra.program.model.symbol.*;
import ghidra.program.model.symbol.SymbolType;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.exception.VersionException; import ghidra.util.exception.VersionException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
@ -32,24 +34,23 @@ import ghidra.util.task.TaskMonitor;
* Adapter to access records in the symbol table. * Adapter to access records in the symbol table.
*/ */
abstract class SymbolDatabaseAdapter { abstract class SymbolDatabaseAdapter {
static final String SYMBOL_TABLE_NAME = "Symbols"; 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_NAME_COL = 0;
static final int SYMBOL_ADDR_COL = 1; static final int SYMBOL_ADDR_COL = 1;
static final int SYMBOL_PARENT_COL = 2; static final int SYMBOL_PARENT_COL = 2;
static final int SYMBOL_TYPE_COL = 3; static final int SYMBOL_TYPE_COL = 3;
static final int SYMBOL_DATA1_COL = 4; static final int SYMBOL_STRING_DATA_COL = 4;
static final int SYMBOL_DATA2_COL = 5; static final int SYMBOL_FLAGS_COL = 5;
static final int SYMBOL_DATA3_COL = 6;
static final int SYMBOL_FLAGS_COL = 7; // 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. // Bits 0 & 1 are used for the source of the symbol.
static final byte SYMBOL_SOURCE_BITS = (byte) 0x3; static final byte SYMBOL_SOURCE_BITS = (byte) 0x3;
@ -59,26 +60,24 @@ abstract class SymbolDatabaseAdapter {
/** /**
* Gets a new SymbolDatabaseAdapter * Gets a new SymbolDatabaseAdapter
* @param dbHandle the database handle. * @param dbHandle the database handle
* @param openMode the openmode * @param openMode the open mode. See {@link DBConstants}
* @param addrMap the address map * @param addrMap the address map
* @param monitor the progress monitor. * @param monitor the progress monitor
* @throws VersionException if the database table does not match the adapter. * @return a new SymbolDatabaseAdapter
* @throws CancelledException if the user cancels an upgrade. * @throws VersionException if the database table does not match the adapter
* @throws IOException if a database io error occurs. * @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, static SymbolDatabaseAdapter getAdapter(DBHandle dbHandle, int openMode, AddressMap addrMap,
TaskMonitor monitor) throws VersionException, CancelledException, IOException { TaskMonitor monitor) throws VersionException, CancelledException, IOException {
if (openMode == DBConstants.CREATE) { if (openMode == DBConstants.CREATE) {
return new SymbolDatabaseAdapterV2(dbHandle, addrMap, true); return new SymbolDatabaseAdapterV3(dbHandle, addrMap, true);
} }
try { try {
SymbolDatabaseAdapter adapter = new SymbolDatabaseAdapterV2(dbHandle, addrMap, false); SymbolDatabaseAdapter adapter = new SymbolDatabaseAdapterV3(dbHandle, addrMap, false);
if (addrMap.isUpgraded()) {
throw new VersionException(true);
}
return adapter; return adapter;
} }
catch (VersionException e) { catch (VersionException e) {
@ -87,7 +86,7 @@ abstract class SymbolDatabaseAdapter {
} }
SymbolDatabaseAdapter adapter = findReadOnlyAdapter(dbHandle, addrMap); SymbolDatabaseAdapter adapter = findReadOnlyAdapter(dbHandle, addrMap);
if (openMode == DBConstants.UPGRADE) { if (openMode == DBConstants.UPGRADE) {
adapter = SymbolDatabaseAdapterV2.upgrade(dbHandle, addrMap, adapter, monitor); adapter = upgrade(dbHandle, addrMap, adapter, monitor);
} }
else if (adapter instanceof SymbolDatabaseAdapterV0) { else if (adapter instanceof SymbolDatabaseAdapterV0) {
// Upgrade required - read-only use not supported // Upgrade required - read-only use not supported
@ -101,39 +100,125 @@ abstract class SymbolDatabaseAdapter {
throws VersionException, IOException { throws VersionException, IOException {
try { try {
return new SymbolDatabaseAdapterV2(handle, addrMap.getOldAddressMap(), false); return new SymbolDatabaseAdapterV2(handle, addrMap.getOldAddressMap());
} }
catch (VersionException e1) { catch (VersionException e1) {
// failed try older version
} }
try { try {
return new SymbolDatabaseAdapterV1(handle, addrMap.getOldAddressMap()); return new SymbolDatabaseAdapterV1(handle, addrMap.getOldAddressMap());
} }
catch (VersionException e1) { 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 * Create a new symbol
* @param name name of the symbol * @param name name of the symbol
* @param addr address of the symbol * @param address the address for the symbol
* @param parentSymbolID the id of the containing namespace symbol * @param namespaceID the id of the containing namespace symbol
* @param symbolType the type of this symbol * @param symbolType the type of this symbol
* @param data1 place to store a long value that depends on the symbol type * @param stringData place to store a String value that depends on the symbol type
* @param data2 place to store an int value that depends on the symbol type * @param source the source type of this symbol
* @param data3 place to store a String value that depends on the symbol type * Some symbol types, such as function symbols, can set the source to Symbol.DEFAULT
* @param source the source of this symbol * @param dataTypeId the id of an associated datatype or null if there is no associated datatype
* <br>Some symbol types, such as function symbols, can set the source to Symbol.DEFAULT. * @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 * @return the new record
* @throws IOException if there was a problem accessing the database * @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 * @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, abstract DBRecord createSymbol(String name, Address address, long namespaceID,
SymbolType symbolType, long data1, int data2, String data3, SourceType source) SymbolType symbolType, String stringData, Long dataTypeId, Integer varOffset,
throws IOException; SourceType source, boolean isPrimary) throws IOException;
/** /**
* Get the record with the given symbol ID * Get the record with the given symbol ID
@ -160,58 +245,96 @@ abstract class SymbolDatabaseAdapter {
abstract boolean hasSymbol(Address addr) throws IOException; 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 * @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 * @throws IOException if there was a problem accessing the database
*/ */
abstract Field[] getSymbolIDs(Address addr) throws IOException; 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(); abstract int getSymbolCount();
/** /**
* Get an iterator over all the symbols in ascending address order. * Get an iterator over all the symbols in ascending address order
* @return * @param forward the direction to iterator
* @return a record iterator over all symbols
* @throws IOException if there was a problem accessing the database * @throws IOException if there was a problem accessing the database
*/ */
abstract RecordIterator getSymbolsByAddress(boolean forward) throws IOException; 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 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 * @throws IOException if there was a problem accessing the database
*/ */
abstract RecordIterator getSymbolsByAddress(Address startAddr, boolean forward) abstract RecordIterator getSymbolsByAddress(Address startAddr, boolean forward)
throws IOException; throws IOException;
/** /**
* Update the table with the given record. * Update the table with the given record
* @param record * @param record the record to update in the database
* @throws IOException if there was a problem accessing the database * @throws IOException if there was a problem accessing the database
*/ */
abstract void updateSymbolRecord(DBRecord record) throws IOException; abstract void updateSymbolRecord(DBRecord record) throws IOException;
/** /**
* Get all of the symbols. * Get all of the symbols.
* @return a record iterator over all symbols
* @throws IOException if there was a problem accessing the database * @throws IOException if there was a problem accessing the database
*/ */
abstract RecordIterator getSymbols() throws IOException; abstract RecordIterator getSymbols() throws IOException;
/** /**
* Get symbols in the given range. * Get symbols in the given range
* @throws IOException if there was a problem accessing the database * @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) abstract RecordIterator getSymbols(Address start, Address end, boolean forward)
throws IOException; 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. * Update the address in all records to reflect the movement of a symbol address.
* @param oldAddr the original symbol address * @param oldAddr the original symbol address
* @param newAddr the new 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; abstract void moveAddress(Address oldAddr, Address newAddr) throws IOException;
@ -221,38 +344,125 @@ abstract class SymbolDatabaseAdapter {
* @param endAddr maximum address in range * @param endAddr maximum address in range
* @param monitor progress monitor * @param monitor progress monitor
* @return returns the set of addresses where symbols where not deleted because they were anchored * @return returns the set of addresses where symbols where not deleted because they were anchored
* @throws CancelledException * @throws CancelledException if the user cancels the operation
* @throws IOException * @throws IOException if a database io error occurs
*/ */
abstract Set<Address> deleteAddressRange(Address startAddr, Address endAddr, abstract Set<Address> deleteAddressRange(Address startAddr, Address endAddr,
TaskMonitor monitor) throws CancelledException, IOException; TaskMonitor monitor) throws CancelledException, IOException;
/** /**
* Get all symbols contained within the specified namespace * Get all symbols contained within the specified namespace
* @param id the namespace id. * @param id the namespace id
* @return an iterator over all symbols in the given namespace. * @return an iterator over all symbols in the given namespace
* @throws IOException * @throws IOException if a database io error occurs
*/ */
abstract RecordIterator getSymbolsByNamespace(long id) throws IOException; abstract RecordIterator getSymbolsByNamespace(long id) throws IOException;
/** /**
* Get symbols starting with the specified name in name order * Get symbols that have the specified name
* @param name name to start with. * @param name name to search
* @return a record iterator over the symbols. * @return a record iterator over the symbols with the given name
* @throws IOException if a database io error occurs. * @throws IOException if a database io error occurs
*/ */
abstract RecordIterator getSymbolsByName(String name) throws IOException; abstract RecordIterator getSymbolsByName(String name) throws IOException;
/** /**
* Returns the maximum symbol address within the specified address space. * Get all symbols contained in the given {@link Namespace} that have the given name
* Intended for update use only. * @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 * @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; 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(); 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);
}
} }

View file

@ -21,8 +21,7 @@ import java.util.Set;
import db.*; import db.*;
import ghidra.program.database.map.AddressIndexPrimaryKeyIterator; import ghidra.program.database.map.AddressIndexPrimaryKeyIterator;
import ghidra.program.database.map.AddressMap; import ghidra.program.database.map.AddressMap;
import ghidra.program.model.address.Address; import ghidra.program.model.address.*;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.symbol.*; import ghidra.program.model.symbol.*;
import ghidra.util.exception.*; import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
@ -58,13 +57,10 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter {
private AddressMap addrMap; private AddressMap addrMap;
/** /**
* Construct a Version-0 Symbol Table adadpter. * Construct a Version-0 Symbol Table adapter.
* @param handle the database handle. * @param handle the database handle.
* @param addrMap the address map * @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 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 { SymbolDatabaseAdapterV0(DBHandle handle, AddressMap addrMap) throws VersionException {
this.addrMap = addrMap.getOldAddressMap(); 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) long extractLocalSymbols(DBHandle handle, TaskMonitor monitor)
throws IOException, CancelledException { throws IOException, CancelledException {
monitor.setMessage("Extracting Local and Dynamic Symbols..."); monitor.setMessage("Extracting Local Symbols...");
monitor.initialize(symbolTable.getRecordCount()); monitor.initialize(symbolTable.getRecordCount());
int cnt = 0; int cnt = 0;
RecordIterator iter = symbolTable.iterator(); RecordIterator iter = symbolTable.iterator();
@ -106,22 +114,36 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter {
throw new AssertException("Unexpected Symbol"); throw new AssertException("Unexpected Symbol");
} }
DBRecord rec = SymbolDatabaseAdapter.SYMBOL_SCHEMA.createRecord(record.getKey()); 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, rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL,
record.getLongValue(V0_SYMBOL_ADDR_COL)); addressKey);
rec.setIntValue(SymbolDatabaseAdapter.SYMBOL_DATA2_COL,
record.getBooleanValue(V0_SYMBOL_PRIMARY_COL) ? 1 : 0); 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.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, rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL,
(byte) SourceType.USER_DEFINED.ordinal()); (byte) SourceType.USER_DEFINED.ordinal());
Field hash = computeLocatorHash(symbolName, namespaceId, addressKey);
rec.setField(SymbolDatabaseAdapter.SYMBOL_HASH_COL, hash);
return rec; return rec;
} }
@Override @Override
DBRecord createSymbol(String name, Address address, long namespaceID, SymbolType symbolType, 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(); throw new UnsupportedOperationException();
} }
@ -175,16 +197,37 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter {
@Override @Override
RecordIterator getSymbols(Address start, Address end, boolean forward) throws IOException { 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( return new V0ConvertedRecordIterator(
new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable, new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
V0_SYMBOL_ADDR_COL, addrMap, start, end, forward))); 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 @Override
void moveAddress(Address oldAddr, Address newAddr) throws IOException { void moveAddress(Address oldAddr, Address newAddr) throws IOException {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
@ -219,8 +262,7 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter {
/** /**
* Construct a symbol filtered record iterator * Construct a symbol filtered record iterator
* @param iter * @param symIter the {@link RecordIterator} to wrap so that records are adapter to new schema
* @param locals if true
*/ */
V0ConvertedRecordIterator(RecordIterator symIter) { V0ConvertedRecordIterator(RecordIterator symIter) {
this.symIter = symIter; this.symIter = symIter;
@ -277,4 +319,23 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter {
throw new UnsupportedOperationException(); 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;
}
} }

View file

@ -21,8 +21,7 @@ import java.util.Set;
import db.*; import db.*;
import ghidra.program.database.map.AddressIndexPrimaryKeyIterator; import ghidra.program.database.map.AddressIndexPrimaryKeyIterator;
import ghidra.program.database.map.AddressMap; import ghidra.program.database.map.AddressMap;
import ghidra.program.model.address.Address; import ghidra.program.model.address.*;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.symbol.*; import ghidra.program.model.symbol.*;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.exception.VersionException; import ghidra.util.exception.VersionException;
@ -72,7 +71,8 @@ class SymbolDatabaseAdapterV1 extends SymbolDatabaseAdapter {
@Override @Override
DBRecord createSymbol(String name, Address address, long namespaceID, SymbolType symbolType, 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(); throw new UnsupportedOperationException();
} }
@ -116,20 +116,21 @@ class SymbolDatabaseAdapterV1 extends SymbolDatabaseAdapter {
DBRecord rec = SymbolDatabaseAdapter.SYMBOL_SCHEMA.createRecord(record.getKey()); DBRecord rec = SymbolDatabaseAdapter.SYMBOL_SCHEMA.createRecord(record.getKey());
String symbolName = record.getString(V1_SYMBOL_NAME_COL); String symbolName = record.getString(V1_SYMBOL_NAME_COL);
rec.setString(SymbolDatabaseAdapter.SYMBOL_NAME_COL, symbolName); rec.setString(SymbolDatabaseAdapter.SYMBOL_NAME_COL, symbolName);
long symbolAddrKey = record.getLongValue(V1_SYMBOL_ADDR_COL); long symbolAddrKey = record.getLongValue(V1_SYMBOL_ADDR_COL);
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL, symbolAddrKey); rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL, symbolAddrKey);
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL,
record.getLongValue(V1_SYMBOL_PARENT_COL)); long namespaceId = record.getLongValue(V1_SYMBOL_PARENT_COL);
byte symbolType = record.getByteValue(V1_SYMBOL_TYPE_COL); rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL, namespaceId);
rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_TYPE_COL, symbolType);
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATA1_COL, byte symbolTypeId = record.getByteValue(V1_SYMBOL_TYPE_COL);
record.getLongValue(V1_SYMBOL_DATA1_COL)); rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_TYPE_COL, symbolTypeId);
rec.setIntValue(SymbolDatabaseAdapter.SYMBOL_DATA2_COL,
record.getIntValue(V1_SYMBOL_DATA2_COL)); rec.setString(SymbolDatabaseAdapter.SYMBOL_STRING_DATA_COL,
rec.setString(SymbolDatabaseAdapter.SYMBOL_DATA3_COL,
record.getString(V1_SYMBOL_COMMENT_COL)); record.getString(V1_SYMBOL_COMMENT_COL));
SourceType source = SourceType.USER_DEFINED; SourceType source = SourceType.USER_DEFINED;
if (symbolType == SymbolType.FUNCTION.getID()) { if (symbolTypeId == SymbolType.FUNCTION.getID()) {
Address symbolAddress = addrMap.decodeAddress(symbolAddrKey); Address symbolAddress = addrMap.decodeAddress(symbolAddrKey);
String defaultName = SymbolUtilities.getDefaultFunctionName(symbolAddress); String defaultName = SymbolUtilities.getDefaultFunctionName(symbolAddress);
if (symbolName.equals(defaultName)) { if (symbolName.equals(defaultName)) {
@ -137,6 +138,33 @@ class SymbolDatabaseAdapterV1 extends SymbolDatabaseAdapter {
} }
} }
rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL, (byte) source.ordinal()); 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; return rec;
} }
@ -175,8 +203,30 @@ class SymbolDatabaseAdapterV1 extends SymbolDatabaseAdapter {
V1_SYMBOL_ADDR_COL, addrMap, start, end, forward))); V1_SYMBOL_ADDR_COL, addrMap, start, end, forward)));
} }
RecordIterator getSymbolsByName() throws IOException { @Override
return new V1ConvertedRecordIterator(symbolTable.indexIterator(V1_SYMBOL_NAME_COL)); 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 @Override
@ -225,4 +275,23 @@ class SymbolDatabaseAdapterV1 extends SymbolDatabaseAdapter {
Address getMaxSymbolAddress(AddressSpace space) throws IOException { Address getMaxSymbolAddress(AddressSpace space) throws IOException {
throw new UnsupportedOperationException(); 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;
}
} }

View file

@ -22,10 +22,11 @@ import java.util.Set;
import db.*; import db.*;
import ghidra.program.database.map.*; import ghidra.program.database.map.*;
import ghidra.program.database.util.RecordFilter; import ghidra.program.database.util.RecordFilter;
import ghidra.program.model.address.Address; import ghidra.program.model.address.*;
import ghidra.program.model.address.AddressSpace; import ghidra.program.model.symbol.SourceType;
import ghidra.program.model.symbol.*; import ghidra.program.model.symbol.SymbolType;
import ghidra.util.exception.*; import ghidra.util.exception.CancelledException;
import ghidra.util.exception.VersionException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
/** /**
@ -33,185 +34,54 @@ import ghidra.util.task.TaskMonitor;
*/ */
class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter { 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 static final int SYMBOL_VERSION = 2;
private Table symbolTable; private Table symbolTable;
private AddressMap addrMap; private AddressMap addrMap;
SymbolDatabaseAdapterV2(DBHandle handle, AddressMap addrMap, boolean create) static final int V2_SYMBOL_NAME_COL = 0;
throws VersionException, IOException { 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; this.addrMap = addrMap;
if (create) { symbolTable = handle.getTable(SYMBOL_TABLE_NAME);
if (symbolTable == null) {
symbolTable = handle.createTable(SYMBOL_TABLE_NAME, SYMBOL_SCHEMA, throw new VersionException("Missing Table: " + SYMBOL_TABLE_NAME);
new int[] { SYMBOL_ADDR_COL, SYMBOL_NAME_COL, SYMBOL_PARENT_COL });
} }
else { if (symbolTable.getSchema().getVersion() != SYMBOL_VERSION) {
symbolTable = handle.getTable(SYMBOL_TABLE_NAME); int version = symbolTable.getSchema().getVersion();
if (symbolTable == null) { if (version < SYMBOL_VERSION) {
throw new VersionException("Missing Table: " + SYMBOL_TABLE_NAME); throw new VersionException(true);
}
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);
}
}
}
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);
} }
throw new VersionException(VersionException.NEWER_VERSION, false);
} }
} }
@Override @Override
DBRecord createSymbol(String name, Address address, long namespaceID, SymbolType symbolType, DBRecord createSymbol(String name, Address address, long namespaceID, SymbolType symbolType,
long data1, int data2, String data3, SourceType source) throws IOException { String stringData, Long dataTypeId, Integer varOffset, SourceType source,
long nextID = symbolTable.getKey(); boolean isPrimary) throws IOException {
throw new UnsupportedOperationException();
// 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;
} }
@Override @Override
void removeSymbol(long symbolID) throws IOException { void removeSymbol(long symbolID) throws IOException {
symbolTable.deleteRecord(symbolID); throw new UnsupportedOperationException();
} }
@Override @Override
@ -234,7 +104,7 @@ class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter {
@Override @Override
DBRecord getSymbolRecord(long symbolID) throws IOException { DBRecord getSymbolRecord(long symbolID) throws IOException {
return symbolTable.getRecord(symbolID); return convertV2Record(symbolTable.getRecord(symbolID));
} }
@Override @Override
@ -244,30 +114,62 @@ class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter {
@Override @Override
RecordIterator getSymbolsByAddress(boolean forward) throws IOException { RecordIterator getSymbolsByAddress(boolean forward) throws IOException {
return new KeyToRecordIterator(symbolTable, KeyToRecordIterator it = new KeyToRecordIterator(symbolTable,
new AddressIndexPrimaryKeyIterator(symbolTable, SYMBOL_ADDR_COL, addrMap, forward)); new AddressIndexPrimaryKeyIterator(symbolTable, SYMBOL_ADDR_COL, addrMap, forward));
return new V2ConvertedRecordIterator(it);
} }
@Override @Override
RecordIterator getSymbolsByAddress(Address startAddr, boolean forward) throws IOException { RecordIterator getSymbolsByAddress(Address startAddr, boolean forward) throws IOException {
return new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable, KeyToRecordIterator it =
SYMBOL_ADDR_COL, addrMap, startAddr, forward)); new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable,
SYMBOL_ADDR_COL, addrMap, startAddr, forward));
return new V2ConvertedRecordIterator(it);
} }
@Override @Override
void updateSymbolRecord(DBRecord record) throws IOException { void updateSymbolRecord(DBRecord record) throws IOException {
symbolTable.putRecord(record); throw new UnsupportedOperationException();
} }
@Override @Override
RecordIterator getSymbols() throws IOException { RecordIterator getSymbols() throws IOException {
return symbolTable.iterator(); return new V2ConvertedRecordIterator(symbolTable.iterator());
} }
@Override @Override
RecordIterator getSymbols(Address start, Address end, boolean forward) throws IOException { RecordIterator getSymbols(Address start, Address end, boolean forward) throws IOException {
return new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable, KeyToRecordIterator it =
SYMBOL_ADDR_COL, addrMap, start, end, forward)); 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 @Override
@ -316,13 +218,15 @@ class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter {
@Override @Override
RecordIterator getSymbolsByNamespace(long id) throws IOException { RecordIterator getSymbolsByNamespace(long id) throws IOException {
LongField field = new LongField(id); 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 @Override
RecordIterator getSymbolsByName(String name) throws IOException { RecordIterator getSymbolsByName(String name) throws IOException {
StringField field = new StringField(name); 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 @Override
@ -353,4 +257,97 @@ class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter {
Table getTable() { Table getTable() {
return symbolTable; 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);
}
}
} }

View file

@ -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;
}
}
}

View file

@ -73,7 +73,6 @@ public class SymbolManager implements SymbolTable, ManagerDB {
private Lock lock; private Lock lock;
final static Symbol[] NO_SYMBOLS = new SymbolDB[0]; final static Symbol[] NO_SYMBOLS = new SymbolDB[0];
private static final int MAX_DUPLICATE_COUNT = 10;
/** /**
* Creates a new Symbol manager. * Creates a new Symbol manager.
@ -211,7 +210,6 @@ public class SymbolManager implements SymbolTable, ManagerDB {
refMgr.moveReferencesTo(oldAddr, nextExtAddr, monitor); refMgr.moveReferencesTo(oldAddr, nextExtAddr, monitor);
nextExtAddr = nextExtAddr.next(); nextExtAddr = nextExtAddr.next();
} }
libSym.setSymbolData2(0);
} }
return true; return true;
@ -275,7 +273,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
try { try {
Address variableAddr = getUpgradedVariableAddress(storageAddr, Address variableAddr = getUpgradedVariableAddress(storageAddr,
rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_DATA1_COL)); rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL));
// fix symbol address // fix symbol address
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL, rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL,
@ -321,12 +319,12 @@ public class SymbolManager implements SymbolTable, ManagerDB {
throw new RuntimeException("Unexpected"); 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) { if (curVarAddr == null || !addr.equals(curVarAddr) || dataTypeId != curDataTypeId) {
curVarAddr = addr; curVarAddr = addr;
curDataTypeId = rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_DATA1_COL); curDataTypeId = rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL);
Address storageAddr = oldVariableStorageMgr.getStorageAddress(addr); Address storageAddr = oldVariableStorageMgr.getStorageAddress(addr);
@ -450,7 +448,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
* @param isPrimary true if symbol is primary at oldAddr * @param isPrimary true if symbol is primary at oldAddr
* @throws IOException if there is database exception * @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 { boolean isPrimary) throws IOException {
Table table = tmpHandle.getTable(OLD_LOCAL_SYMBOLS_TABLE); Table table = tmpHandle.getTable(OLD_LOCAL_SYMBOLS_TABLE);
if (table == null) { if (table == null) {
@ -506,8 +504,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
symbolRemoved(symbol, address, symbol.getName(), oldKey, Namespace.GLOBAL_NAMESPACE_ID, symbolRemoved(symbol, address, symbol.getName(), oldKey, Namespace.GLOBAL_NAMESPACE_ID,
null); null);
DBRecord record = DBRecord record =
adapter.createSymbol(newName, address, newParentID, SymbolType.LABEL, 0, adapter.createSymbol(newName, address, newParentID, SymbolType.LABEL, null,
1, null, source); null, null, source, true);
symbol.setRecord(record);// symbol object was morphed symbol.setRecord(record);// symbol object was morphed
symbolAdded(symbol); symbolAdded(symbol);
} }
@ -548,12 +546,15 @@ public class SymbolManager implements SymbolTable, ManagerDB {
DBRecord rec = SymbolDatabaseAdapter.SYMBOL_SCHEMA.createRecord(symbolID); DBRecord rec = SymbolDatabaseAdapter.SYMBOL_SCHEMA.createRecord(symbolID);
rec.setString(SymbolDatabaseAdapter.SYMBOL_NAME_COL, name); 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.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL, namespace.getID());
rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_TYPE_COL, type.getID()); rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_TYPE_COL, type.getID());
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATA1_COL, -1); if (isPrimary) {
rec.setIntValue(SymbolDatabaseAdapter.SYMBOL_DATA2_COL, isPrimary ? 1 : 0); rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL, addressKey);
}
rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL, (byte) source.ordinal()); rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL, (byte) source.ordinal());
adapter.updateSymbolRecord(rec); adapter.updateSymbolRecord(rec);
} }
@ -868,38 +869,51 @@ public class SymbolManager implements SymbolTable, ManagerDB {
} }
@Override @Override
public Symbol getSymbol(String name, Address addr, Namespace namespace) { public Symbol getSymbol(String name, Address address, Namespace namespace) {
if (namespace == null) { if (namespace == null) {
namespace = program.getGlobalNamespace(); namespace = program.getGlobalNamespace();
} }
if (addr instanceof SpecialAddress) { long namespaceId = namespace.getID();
List<Symbol> symbols = getSymbols(name, namespace);
for (Symbol symbol : symbols) { lock.acquire();
if (symbol.getAddress().equals(addr)) { try {
return symbol; DBRecord record = adapter.getSymbolRecord(address, name, namespaceId);
} if (record != null) {
return getSymbol(record);
} }
return null; }
catch (IOException e) {
program.dbError(e);
}
finally {
lock.release();
} }
return getSymbol(name, addr, namespace.getID()); // 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;
} }
/** private Symbol searchNamespaceForSymbol(Namespace namespace, String name, Address address) {
* Gets the symbol with the given info. for (Symbol symbol : getSymbols(namespace)) {
* @param name the name of the symbol if (address.equals(symbol.getAddress()) && name.equals(symbol.getName())) {
* @param addr the address of the symbol return 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;
} }
} }
return null; return null;
@ -916,13 +930,6 @@ public class SymbolManager implements SymbolTable, ManagerDB {
return symbols.isEmpty() ? null : symbols.get(0); 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 @Override
public Symbol getGlobalSymbol(String name, Address addr) { public Symbol getGlobalSymbol(String name, Address addr) {
Symbol[] symbols = getSymbols(addr); Symbol[] symbols = getSymbols(addr);
@ -981,38 +988,60 @@ public class SymbolManager implements SymbolTable, ManagerDB {
namespace = namespaceMgr.getGlobalNamespace(); 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(); lock.acquire();
try { try {
if (namespace.isExternal() && RecordIterator it = adapter.getSymbolsByNameAndNamespace(name, namespace.getID());
SymbolUtilities.isReservedExternalDefaultName(name, program.getAddressFactory())) { while (it.hasNext()) {
return searchSymbolsByNamespaceFirst(name, namespace); list.add(getSymbol(it.next()));
} }
}
if (namespace instanceof Function && hasDefaultVariablePrefix(name)) { catch (IOException e) {
return searchSymbolsByNamespaceFirst(name, namespace); program.dbError(e);
}
// 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);
}
}
return list;
} }
finally { finally {
lock.release(); 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 // 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) { if (namespace == null) {
namespace = namespaceMgr.getGlobalNamespace(); namespace = namespaceMgr.getGlobalNamespace();
} }
lock.acquire();
if (namespace.isExternal() && try {
SymbolUtilities.isReservedExternalDefaultName(name, program.getAddressFactory())) { RecordIterator it = adapter.getSymbolsByNameAndNamespace(name, namespace.getID());
return findFirstSymbol(name, namespace, test); while (it.hasNext()) {
} SymbolDB symbol = getSymbol(it.next());
if (test.test(symbol)) {
else if (namespace instanceof Function && hasDefaultVariablePrefix(name)) { return symbol;
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) && // didn't find one in the database, see if it is a default dynamic name
test.test(s)) { Symbol symbol = getSymbolForDynamicName(name);
return s; if (symbol != null && symbol.getParentNamespace().equals(namespace) &&
test.test(symbol)) {
return symbol;
} }
} }
catch (IOException e) {
program.dbError(e);
}
finally {
lock.release();
}
return null; 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 @Override
public Namespace getNamespace(String name, Namespace namespace) { public Namespace getNamespace(String name, Namespace namespace) {
List<Symbol> symbols = getSymbols(name, namespace); List<Symbol> symbols = getSymbols(name, namespace);
@ -1107,16 +1110,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
try { try {
SymbolIterator symIter = new SymbolNameRecordIterator(name); SymbolIterator symIter = new SymbolNameRecordIterator(name);
if (!symIter.hasNext()) { if (!symIter.hasNext()) {
Address addr = SymbolUtilities.parseDynamicName(addrMap.getAddressFactory(), name); Symbol symbol = getSymbolForDynamicName(name);
if (addr != null) { return new SingleSymbolIterator(symbol); // this handles a null symbol
Symbol[] symbols = getSymbols(addr);
for (Symbol symbol : symbols) {
if (name.equals(symbol.getName())) {
return new SingleSymbolIterator(symbol);
}
}
return new SingleSymbolIterator(null);
}
} }
return symIter; return symIter;
} }
@ -1134,19 +1129,28 @@ public class SymbolManager implements SymbolTable, ManagerDB {
if (!addr.isMemoryAddress() && !addr.isExternalAddress()) { if (!addr.isMemoryAddress() && !addr.isExternalAddress()) {
return null; return null;
} }
if (addr.isExternalAddress()) {
Symbol[] symbols = getSymbols(addr);
return symbols.length > 0 ? symbols[0] : null;
}
lock.acquire(); lock.acquire();
try { try {
Symbol[] symbols = getSymbols(addr); DBRecord record = adapter.getPrimarySymbol(addr);
for (Symbol element : symbols) { if (record != null) {
if (element.isPrimary()) { return getSymbol(record);
return element;
}
} }
return null; if (addr.isMemoryAddress() && refManager.hasReferencesTo(addr)) {
return getDynamicSymbol(addr);
}
}
catch (IOException e) {
program.dbError(e);
} }
finally { finally {
lock.release(); lock.release();
} }
return null;
} }
@Override @Override
@ -1207,14 +1211,14 @@ public class SymbolManager implements SymbolTable, ManagerDB {
if (set.isEmpty()) { if (set.isEmpty()) {
return SymbolIterator.EMPTY_ITERATOR; return SymbolIterator.EMPTY_ITERATOR;
} }
Query query1 = new FieldMatchQuery(SymbolDatabaseAdapter.SYMBOL_DATA2_COL, new IntField(1)); try {
Query query2 = new FieldMatchQuery(SymbolDatabaseAdapter.SYMBOL_TYPE_COL, RecordIterator recordIterator = adapter.getPrimarySymbols(set, forward);
new ByteField(SymbolType.LABEL.getID())); return new SymbolRecordIterator(recordIterator, true, forward);
Query query3 = new FieldMatchQuery(SymbolDatabaseAdapter.SYMBOL_TYPE_COL, }
new ByteField(SymbolType.FUNCTION.getID())); catch (IOException e) {
Query query4 = new AndQuery(query1, query2); program.dbError(e);
Query query5 = new OrQuery(query3, query4); }
return new AddressSetFilteredSymbolIterator(this, set, query5, forward); return new SymbolRecordIterator(new EmptyRecordIterator(), true, forward);
} }
@Override @Override
@ -2130,9 +2134,9 @@ public class SymbolManager implements SymbolTable, ManagerDB {
continue; continue;
} }
} }
long id = rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_DATA1_COL); long id = rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL);
if (id == oldDataTypeID) { if (id == oldDataTypeID) {
rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATA1_COL, newDataTypeID); rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL, newDataTypeID);
adapter.updateSymbolRecord(rec); adapter.updateSymbolRecord(rec);
symbolDataChanged(getSymbol(rec)); symbolDataChanged(getSymbol(rec));
} }
@ -2157,14 +2161,14 @@ public class SymbolManager implements SymbolTable, ManagerDB {
lock.acquire(); lock.acquire();
try { try {
invalidateCache(true); invalidateCache(true);
Address lastAddress = fromAddr.add(length-1); Address lastAddress = fromAddr.add(length - 1);
AddressRange range = new AddressRangeImpl(fromAddr, lastAddress); AddressRange range = new AddressRangeImpl(fromAddr, lastAddress);
// in order to handle overlapping ranges, need to iterate in the correct direction // in order to handle overlapping ranges, need to iterate in the correct direction
SymbolIterator symbolIterator = (fromAddr.compareTo(toAddr) > 0) ? SymbolIterator symbolIterator =
getSymbolIterator(fromAddr, true) : (fromAddr.compareTo(toAddr) > 0) ? getSymbolIterator(fromAddr, true)
getSymbolIterator(lastAddress, false); : getSymbolIterator(lastAddress, false);
for (Symbol symbol : symbolIterator) { for (Symbol symbol : symbolIterator) {
if (!range.contains(symbol.getAddress())) { if (!range.contains(symbol.getAddress())) {
break; break;
@ -2174,7 +2178,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
// any address that has symbols added or removed may have a corrupted primary (too many or non-existent) // any address that has symbols added or removed may have a corrupted primary (too many or non-existent)
primaryFixups.add(symbol.getAddress()); primaryFixups.add(symbol.getAddress());
primaryFixups.add(newAddress); primaryFixups.add(newAddress);
moveSymbolForMemoryBlockMove((SymbolDB) symbol, newAddress); moveSymbolForMemoryBlockMove((SymbolDB) symbol, newAddress);
} }
// go back and make sure there is a valid primary symbol at touched addressess // go back and make sure there is a valid primary symbol at touched addressess
@ -2386,7 +2390,7 @@ public class SymbolManager implements SymbolTable, ManagerDB {
try { try {
Symbol newLabel = Symbol newLabel =
createLabel(newAddress, symbol.getName(), symbol.getParentNamespace(), createLabel(newAddress, symbol.getName(), symbol.getParentNamespace(),
symbol.getSource()); symbol.getSource());
newLabel.setPinned(true); newLabel.setPinned(true);
} }
catch (InvalidInputException e) { catch (InvalidInputException e) {
@ -2479,8 +2483,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
try { try {
source = adjustSourceTypeIfNecessary(name, type, source, storage); source = adjustSourceTypeIfNecessary(name, type, source, storage);
Address varAddr = variableStorageMgr.getVariableStorageAddress(storage, true); Address varAddr = variableStorageMgr.getVariableStorageAddress(storage, true);
return (VariableSymbolDB) createSpecialSymbol(varAddr, name, namespace, type, -1, return (VariableSymbolDB) createSpecialSymbol(varAddr, name, namespace, type,
firstUseOffsetOrOrdinal, null, source); null, Integer.valueOf(firstUseOffsetOrOrdinal), null, source);
} }
catch (IOException e) { catch (IOException e) {
dbError(e); dbError(e);
@ -2506,8 +2510,9 @@ public class SymbolManager implements SymbolTable, ManagerDB {
@Override @Override
public GhidraClass createClass(Namespace parent, String name, SourceType source) public GhidraClass createClass(Namespace parent, String name, SourceType source)
throws DuplicateNameException, InvalidInputException { throws DuplicateNameException, InvalidInputException {
SymbolDB s = createSpecialSymbol(Address.NO_ADDRESS, name, parent, SymbolType.CLASS, -1, -1, SymbolDB s =
null, source); createSpecialSymbol(Address.NO_ADDRESS, name, parent, SymbolType.CLASS, null, null,
null, source);
return new GhidraClassDB(s, namespaceMgr); return new GhidraClassDB(s, namespaceMgr);
} }
@ -2515,8 +2520,9 @@ public class SymbolManager implements SymbolTable, ManagerDB {
public Library createExternalLibrary(String name, SourceType source) public Library createExternalLibrary(String name, SourceType source)
throws DuplicateNameException, InvalidInputException { throws DuplicateNameException, InvalidInputException {
SymbolDB s = createSpecialSymbol(Address.NO_ADDRESS, name, null, SymbolType.LIBRARY, -1, -1, SymbolDB s =
null, source); createSpecialSymbol(Address.NO_ADDRESS, name, null, SymbolType.LIBRARY, null, null,
null, source);
return new LibraryDB(s, namespaceMgr); return new LibraryDB(s, namespaceMgr);
} }
@ -2524,8 +2530,9 @@ public class SymbolManager implements SymbolTable, ManagerDB {
public Namespace createNameSpace(Namespace parent, String name, SourceType source) public Namespace createNameSpace(Namespace parent, String name, SourceType source)
throws DuplicateNameException, InvalidInputException { throws DuplicateNameException, InvalidInputException {
SymbolDB s = createSpecialSymbol(Address.NO_ADDRESS, name, parent, SymbolType.NAMESPACE, -1, SymbolDB s =
-1, null, source); createSpecialSymbol(Address.NO_ADDRESS, name, parent, SymbolType.NAMESPACE, null,
null, null, source);
return new NamespaceDB(s, namespaceMgr); return new NamespaceDB(s, namespaceMgr);
} }
@ -2549,7 +2556,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
String tempName = "_temp_" + System.nanoTime(); String tempName = "_temp_" + System.nanoTime();
SymbolDB classSymbol = SymbolDB classSymbol =
doCreateSpecialSymbol(Address.NO_ADDRESS, tempName, namespace.getParentNamespace(), 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); GhidraClassDB classNamespace = new GhidraClassDB(classSymbol, namespaceMgr);
// move everything from old namespace into new class namespace // 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 // 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. // duplicates? Assuming yes, as another symbol type may exist with this name.
SymbolDB s = SymbolDB s =
doCreateSpecialSymbol(Address.NO_ADDRESS, name, parent, SymbolType.NAMESPACE, -1, doCreateSpecialSymbol(Address.NO_ADDRESS, name, parent, SymbolType.NAMESPACE, null,
-1, null, source, true /*check for duplicates*/); null, null, source, true /*check for duplicates*/);
return new NamespaceDB(s, namespaceMgr); return new NamespaceDB(s, namespaceMgr);
} }
@ -2643,9 +2651,9 @@ public class SymbolManager implements SymbolTable, ManagerDB {
* @param name the name of the symbol * @param name the name of the symbol
* @param parent the namespace for the symbol * @param parent the namespace for the symbol
* @param symbolType the type of the symbol * @param symbolType the type of the symbol
* @param data1 long value whose meaning depends on the symbol type. * @param dataTypeId the id for an associated datatype or null
* @param data2 int value whose meaning depends on the symbol type. * @param variableOffset this is the ordinal for params and firstUseOffset for locals
* @param data3 string value whose meaning depends on the symbol type. * @param stringData value whose meaning depends on the symbol type.
* @param source the SourceType for the new symbol * @param source the SourceType for the new symbol
* @return the newly created symbol * @return the newly created symbol
* @throws DuplicateNameException if the symbol type must be unique and another already has that name * @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) * @throws InvalidInputException if the name contains any illegal characters (i.e. space)
*/ */
public SymbolDB createSpecialSymbol(Address addr, String name, Namespace parent, 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 { throws DuplicateNameException, InvalidInputException {
return doCreateSpecialSymbol(addr, name, parent, symbolType, data1, data2, data3, source, return doCreateSpecialSymbol(addr, name, parent, symbolType, stringData, dataTypeId,
true); variableOffset, source, true);
} }
private SymbolDB doCreateSpecialSymbol(Address addr, String name, Namespace parent, 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) boolean checkForDuplicates)
throws DuplicateNameException, InvalidInputException { throws DuplicateNameException, InvalidInputException {
@ -2675,7 +2685,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
checkDuplicateSymbolName(addr, name, parent, symbolType); 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 { finally {
lock.release(); lock.release();
@ -2713,12 +2724,12 @@ public class SymbolManager implements SymbolTable, ManagerDB {
* @param name the name of the new symbol * @param name the name of the new symbol
* @param namespace the namespace for the new symbol * @param namespace the namespace for the new symbol
* @param source the SourceType of 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 * @return the new symbol
* @throws InvalidInputException if the name contains illegal characters (i.e. space) * @throws InvalidInputException if the name contains illegal characters (i.e. space)
*/ */
public Symbol createCodeSymbol(Address addr, String name, Namespace namespace, public Symbol createCodeSymbol(Address addr, String name, Namespace namespace,
SourceType source, String data3) throws InvalidInputException { SourceType source, String stringData) throws InvalidInputException {
lock.acquire(); lock.acquire();
try { try {
namespace = validateNamespace(namespace, addr, SymbolType.LABEL); namespace = validateNamespace(namespace, addr, SymbolType.LABEL);
@ -2744,8 +2755,8 @@ public class SymbolManager implements SymbolTable, ManagerDB {
} }
boolean makePrimary = primary == null; boolean makePrimary = primary == null;
return doCreateSymbol(name, addr, namespace, SymbolType.LABEL, -1, makePrimary ? 1 : 0, return doCreateSymbol(name, addr, namespace, SymbolType.LABEL, stringData, null, null,
data3, source); source, makePrimary);
} }
finally { finally {
lock.release(); lock.release();
@ -2759,34 +2770,32 @@ public class SymbolManager implements SymbolTable, ManagerDB {
* @param name the name of the new symbol * @param name the name of the new symbol
* @param namespace the namespace for the new symbol * @param namespace the namespace for the new symbol
* @param source the SourceType of 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 * @return the new symbol
* @throws InvalidInputException if the name contains illegal characters (i.e. space) * @throws InvalidInputException if the name contains illegal characters (i.e. space)
*/ */
public Symbol createFunctionSymbol(Address addr, String name, Namespace namespace, 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); namespace = validateNamespace(namespace, addr, SymbolType.FUNCTION);
source = validateSource(source, name, addr, SymbolType.FUNCTION); source = validateSource(source, name, addr, SymbolType.FUNCTION);
name = validateName(name, source); name = validateName(name, source);
Symbol[] symbols = getSymbols(addr);
// if there is already a FUNCTION symbol with that name and namespace here, just return it. // if there is already a FUNCTION symbol with that name and namespace here, just return it.
Symbol matching = Symbol matching = getSymbol(name, addr, namespace);
findMatchingSymbol(symbols, new SymbolMatcher(name, namespace, SymbolType.FUNCTION)); if (matching != null && matching.getSymbolType() == SymbolType.FUNCTION) {
if (matching != null) {
return matching; return matching;
} }
// if there is another function at the same address, throw InvalidInputException // 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); throw new InvalidInputException("Function already exists at: " + addr);
} }
// See if there is a symbol we want to change into the function symbol // See if there is a symbol we want to change into the function symbol
Symbol symbolToPromote = findSymbolToPromote(symbols, name, namespace, source); Symbol symbolToPromote = findSymbolToPromote(matching, primary, source);
if (symbolToPromote != null) { if (symbolToPromote != null && !symbolToPromote.isDynamic()) {
name = symbolToPromote.getName(); name = symbolToPromote.getName();
namespace = symbolToPromote.getParentNamespace(); namespace = symbolToPromote.getParentNamespace();
source = symbolToPromote.getSource(); 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. // If promoting a pinned symbol, we need to pin the new function symbol.
boolean needsPinning = symbolToPromote == null ? false : symbolToPromote.isPinned(); boolean needsPinning = symbolToPromote == null ? false : symbolToPromote.isPinned();
// delete any promoted symbol, dynamic symbol, and make sure any others are not primary // delete any promoted symbol, dynamic symbol, and make sure all others are not primary
cleanUpSymbols(symbols, symbolToPromote); cleanUpSymbols(addr, symbolToPromote, primary);
Symbol symbol = 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) { if (needsPinning) {
symbol.setPinned(true); symbol.setPinned(true);
@ -2809,48 +2819,45 @@ public class SymbolManager implements SymbolTable, ManagerDB {
} }
/** /**
* If the new symbol is Default, returns the primary symbol if it is dynamic. Otherwise * Finds the appropriate symbol to promote when function is created. And by promote, we really
* returns any Code symbol with the same name and namespace. * 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, private Symbol findSymbolToPromote(Symbol matching, Symbol primary, SourceType source) {
SourceType source) { // if the function is default, then the primary will be promoted
if (source == SourceType.DEFAULT) { if (source == SourceType.DEFAULT) {
Symbol primary = findMatchingSymbol(symbols, s -> s.isPrimary()); return primary;
if (primary != null && !primary.isDynamic()) {
return primary;
}
return null;
} }
// Even though this doesn't change the name or namespace, return this so it will be deleted later. // if the primary is a default, it needs to be deleted, so return it as the "promoted" symbol
return findMatchingSymbol(symbols, new SymbolMatcher(name, namespace, SymbolType.LABEL)); if (primary != null && primary.isDynamic()) {
return primary;
}
// 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 != null) {
if (symbolToPromote.isDynamic()) { if (symbolToPromote.isDynamic()) {
deleteDynamicSymbol(symbolToPromote); deleteDynamicSymbol(symbolToPromote);
primary = null;
} }
else { else {
symbolToPromote.delete(); symbolToPromote.delete();
primary = getPrimarySymbol(address);
if (primary != null && primary.isDynamic()) {
deleteDynamicSymbol(primary);
primary = null;
}
} }
} }
// clean up any symbol that may have been made primary when we deleted the symbolToPromote // clear the primary symbol during cleanup because a new symbol is about to be created
for (Symbol symbol : symbols) { // that will be the primary symbol
if (symbol != symbolToPromote && symbol.isPrimary()) { if (primary != null && !primary.isDynamic()) {
((CodeSymbol) symbol).setPrimary(false); ((CodeSymbol) primary).setPrimary(false);
}
} }
} }
private Symbol findMatchingSymbol(Symbol[] symbols, Predicate<Symbol> matcher) {
for (Symbol symbol : symbols) {
if (matcher.test(symbol)) {
return symbol;
}
}
return null;
}
private Namespace validateNamespace(Namespace namespace, Address addr, SymbolType type) private Namespace validateNamespace(Namespace namespace, Address addr, SymbolType type)
throws InvalidInputException { throws InvalidInputException {
@ -2862,12 +2869,13 @@ public class SymbolManager implements SymbolTable, ManagerDB {
} }
private SymbolDB doCreateSymbol(String name, Address addr, Namespace namespace, SymbolType type, 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 { try {
DBRecord record = DBRecord record =
adapter.createSymbol(name, addr, namespace.getID(), type, data1, data2, adapter.createSymbol(name, addr, namespace.getID(), type, stringData, dataTypeId,
data3, source); variableOffset, source, isPrimary);
SymbolDB newSymbol = makeSymbol(addr, record, type); SymbolDB newSymbol = makeSymbol(addr, record, type);
symbolAdded(newSymbol); symbolAdded(newSymbol);
@ -3019,21 +3027,6 @@ public class SymbolManager implements SymbolTable, ManagerDB {
private Symbol getSpecificSymbol(String name, Namespace namespace, SymbolType type) { private Symbol getSpecificSymbol(String name, Namespace namespace, SymbolType type) {
return getFirstSymbol(name, namespace, s -> s.getSymbolType() == 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> { class SymbolMatcher implements Predicate<Symbol> {

View file

@ -36,9 +36,7 @@ import ghidra.util.task.TaskMonitor;
* Symbol class for function variables. * Symbol class for function variables.
* *
* Symbol Data Usage: * Symbol Data Usage:
* long data1 - data type ID * String stringData - variable comment
* int data2 - first-use-offset / ordinal
* String data3 - variable comment
*/ */
public class VariableSymbolDB extends SymbolDB { public class VariableSymbolDB extends SymbolDB {
@ -174,8 +172,9 @@ public class VariableSymbolDB extends SymbolDB {
} }
public FunctionDB getFunction() { public FunctionDB getFunction() {
return (FunctionDB) symbolMgr.getFunctionManager().getFunction( return (FunctionDB) symbolMgr.getFunctionManager()
getParentNamespace().getID()); .getFunction(
getParentNamespace().getID());
} }
/** /**
@ -252,7 +251,7 @@ public class VariableSymbolDB extends SymbolDB {
} }
public DataType getDataType() { public DataType getDataType() {
DataType dt = symbolMgr.getDataType(getSymbolData1()); DataType dt = symbolMgr.getDataType(getDataTypeId());
if (dt == null) { if (dt == null) {
VariableStorage storage = getVariableStorage(); VariableStorage storage = getVariableStorage();
if (storage == null) { if (storage == null) {
@ -286,8 +285,8 @@ public class VariableSymbolDB extends SymbolDB {
Address newAddr = variableMgr.getVariableStorageAddress(newStorage, true); Address newAddr = variableMgr.getVariableStorageAddress(newStorage, true);
setAddress(newAddr); // this may be the only symbol which changes its address setAddress(newAddr); // this may be the only symbol which changes its address
if (dataTypeID != getSymbolData1()) { if (dataTypeID != getDataTypeId()) {
setSymbolData1(dataTypeID); setDataTypeId(dataTypeID);
} }
else { else {
symbolMgr.symbolDataChanged(this); symbolMgr.symbolDataChanged(this);
@ -302,22 +301,22 @@ public class VariableSymbolDB extends SymbolDB {
} }
public int getFirstUseOffset() { public int getFirstUseOffset() {
return type == SymbolType.PARAMETER ? 0 : getSymbolData2(); return type == SymbolType.PARAMETER ? 0 : getVariableOffset();
} }
public void setFirstUseOffset(int firstUseOffset) { public void setFirstUseOffset(int firstUseOffset) {
if (type == SymbolType.LOCAL_VAR) { if (type == SymbolType.LOCAL_VAR) {
setSymbolData2(firstUseOffset); setVariableOffset(firstUseOffset);
} }
} }
public int getOrdinal() { public int getOrdinal() {
return type == SymbolType.PARAMETER ? getSymbolData2() : Integer.MIN_VALUE; return type == SymbolType.PARAMETER ? getVariableOffset() : Integer.MIN_VALUE;
} }
public void setOrdinal(int ordinal) { public void setOrdinal(int ordinal) {
if (type == SymbolType.PARAMETER) { if (type == SymbolType.PARAMETER) {
setSymbolData2(ordinal); setVariableOffset(ordinal);
} }
} }

View file

@ -23,7 +23,9 @@ import db.RecordIterator;
/** /**
* Implementation of a RecordIterator that is always empty. * Implementation of a RecordIterator that is always empty.
*/ */
public class EmptyRecordIterator implements RecordIterator { public class EmptyRecordIterator implements RecordIterator {
public static final RecordIterator INSTANCE = new EmptyRecordIterator();
/** /**
* @see db.RecordIterator#hasNext() * @see db.RecordIterator#hasNext()

View file

@ -760,6 +760,29 @@ public class SymbolUtilities {
return addr.getAddressSpace().getName() + Long.toHexString(addr.getOffset()); 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) { public static boolean isDefaultLocalStackName(String name) {
if (name == null || name.length() == 0) { if (name == null || name.length() == 0) {
return true; return true;
@ -1042,4 +1065,5 @@ public class SymbolUtilities {
public static Comparator<Symbol> getSymbolNameComparator() { public static Comparator<Symbol> getSymbolNameComparator() {
return CASE_INSENSITIVE_SYMBOL_NAME_COMPARATOR; return CASE_INSENSITIVE_SYMBOL_NAME_COMPARATOR;
} }
} }

View file

@ -193,8 +193,8 @@ public interface ChangeManager {
public static final int DOCR_SYMBOL_ASSOCIATION_REMOVED = 51; public static final int DOCR_SYMBOL_ASSOCIATION_REMOVED = 51;
/** /**
* Symbol data changed. This corresponds to unspecified data * Symbol data changed. This corresponds to various
* changes within the symbol (e.g., Data1, Data2, Data3, or VariableStorage). * changes within the symbol (e.g., primary status, datatype, external path or VariableStorage).
*/ */
public static final int DOCR_SYMBOL_DATA_CHANGED = 52; 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; public final static int DOCR_TAG_REMOVED_FROM_FUNCTION = 157;
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// //
// DOCR_FUNCTION_CHANGED - Sub Event Types // DOCR_FUNCTION_CHANGED - Sub Event Types