diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/listing/SymbolMerger.java b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/listing/SymbolMerger.java index 0199747732..d142c9c3ca 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/listing/SymbolMerger.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/listing/SymbolMerger.java @@ -526,7 +526,7 @@ class SymbolMerger extends AbstractListingMerger { renamed = true; } // boolean commentChanged = -// !SystemUtilities.isEqual(newSym.getSymbolData3(), oldSym.getSymbolData3()); +// !SystemUtilities.isEqual(newSym.getSymbolStringData(), oldSym.getSymbolStringData()); boolean sourceChanged = newSym.getSource() != oldSym.getSource(); // if (commentChanged) { // commentChanges.add(id); @@ -920,12 +920,12 @@ class SymbolMerger extends AbstractListingMerger { // if (commentChangedInMy) { // if (!commentChangedInLatest) { // if (resultSym != null) { -// resultSym.setSymbolData3(mySym.getSymbolData3()); +// resultSym.setSymbolStringData(mySym.getSymbolStringData()); // } // } // else { // Symbol latestSym = latestSymTab.getSymbol(id); -// if (!SystemUtilities.isEqual(latestSym.getSymbolData3(), mySym.getSymbolData3())) { +// if (!SystemUtilities.isEqual(latestSym.getSymbolStringData(), mySym.getSymbolStringData())) { // saveCommentConflict(id); // } // } @@ -1008,11 +1008,11 @@ class SymbolMerger extends AbstractListingMerger { // if (commentChangedInMy) { // if (!commentChangedInLatest) { // // Use My version's comment since Latest didn't change it. -// resultSym.setSymbolData3(mySym.getSymbolData3()); +// resultSym.setSymbolStringData(mySym.getSymbolStringData()); // } // else { // Symbol latestSym = latestSymTab.getSymbol(id); -// if (!SystemUtilities.isEqual(latestSym.getSymbolData3(), mySym.getSymbolData3())) { +// if (!SystemUtilities.isEqual(latestSym.getSymbolStringData(), mySym.getSymbolStringData())) { // saveFunctionCommentConflict(id); // My & Latest changed comment differently. // } // } @@ -1181,11 +1181,11 @@ class SymbolMerger extends AbstractListingMerger { // Handle Symbol comments. // if (commentChangedInMy) { // if (!commentChangedInLatest) { -// resultSym.setSymbolData3(mySym.getSymbolData3()); // Use My version's comment since Latest didn't change it. +// resultSym.setSymbolStringData(mySym.getSymbolStringData()); // Use My version's comment since Latest didn't change it. // } // else { // Symbol latestSym = latestSymTab.getSymbol(id); -// if (!SystemUtilities.isEqual(latestSym.getSymbolData3(), mySym.getSymbolData3())) { +// if (!SystemUtilities.isEqual(latestSym.getSymbolStringData(), mySym.getSymbolStringData())) { // saveAddFunctionCommentConflict(id); // My & Latest changed comment differently. // } // } @@ -1372,8 +1372,8 @@ class SymbolMerger extends AbstractListingMerger { // private void processAddedSymbolComment(Symbol resultSym, Symbol mySym) { // // My version added a symbol that matches on in the result version. -// String resultComment = resultSym.getSymbolData3(); -// String myComment = mySym.getSymbolData3(); +// String resultComment = resultSym.getSymbolStringData(); +// String myComment = mySym.getSymbolStringData(); // if (SystemUtilities.isEqual(resultComment, myComment)) { // return; // Already has My symbol comment. // } @@ -1381,7 +1381,7 @@ class SymbolMerger extends AbstractListingMerger { // return; // My version isn't setting a symbol comment. // } // if (resultComment == null) { -// resultSym.setSymbolData3(myComment); // Latest didn't set a comment, but My did so use My symbol comment. +// resultSym.setSymbolStringData(myComment); // Latest didn't set a comment, but My did so use My symbol comment. // } // else if (!myComment.equals(resultComment)) { // saveAddCommentConflict(mySym.getID()); // Both set a different symbol comment, so conflict @@ -1711,7 +1711,7 @@ class SymbolMerger extends AbstractListingMerger { // currentAddress = addr; // currentSymbol = mySym; // Symbol resultSym = getResultSymbolFromMySymbol(mySym); -// currentSymbolComment = (resultSym != null) ? resultSym.getSymbolData3() : ""; +// currentSymbolComment = (resultSym != null) ? resultSym.getSymbolStringData() : ""; // currentBackgroundSet = new AddressSet(resultAddressFactory, addr, addr); // if (askUser && mergeManager != null) { // boolean useForAll = (symbolAddCommentChoice != ASK_USER); @@ -1912,10 +1912,10 @@ class SymbolMerger extends AbstractListingMerger { // return; // } // if ((chosenConflictOption & KEEP_LATEST) != 0) { -// result.setSymbolData3(latest.getSymbolData3()); +// result.setSymbolStringData(latest.getSymbolStringData()); // } // else if ((chosenConflictOption & KEEP_MY) != 0) { -// result.setSymbolData3(my.getSymbolData3()); +// result.setSymbolStringData(my.getSymbolStringData()); // } // } @@ -1933,10 +1933,10 @@ class SymbolMerger extends AbstractListingMerger { // return; // } // if ((chosenConflictOption & KEEP_RESULT) != 0) { -// result.setSymbolData3(currentSymbolComment); +// result.setSymbolStringData(currentSymbolComment); // } // else if ((chosenConflictOption & KEEP_MY) != 0) { -// result.setSymbolData3(my.getSymbolData3()); +// result.setSymbolStringData(my.getSymbolStringData()); // } // } @@ -2253,7 +2253,7 @@ class SymbolMerger extends AbstractListingMerger { Symbol newSymbol) throws DuplicateNameException, InvalidInputException, CircularDependencyException { renameSymbol(oldProgram, oldSymbol, newProgram, newSymbol); -// oldSymbol.setSymbolData3(newSymbol.getSymbolData3()); +// oldSymbol.setSymbolStringData(newSymbol.getSymbolStringData()); // Handle primary. if (newSymbol.isPrimary() && !oldSymbol.isPrimary()) { oldSymbol.setPrimary(); @@ -2446,7 +2446,7 @@ class SymbolMerger extends AbstractListingMerger { private Symbol createSymbol(String name, SymbolType type, Address resultAddr, Namespace resultParentNs, Program srcPgm, long srcSymID, SourceType source) throws DuplicateNameException, InvalidInputException { -// String comment = srcSymbol.getSymbolData3(); +// String comment = srcSymbol.getSymbolStringData(); Symbol symbol = null; if (type == SymbolType.LABEL) { symbol = resultSymTab.createLabel(resultAddr, name, resultParentNs, source); @@ -2468,7 +2468,7 @@ class SymbolMerger extends AbstractListingMerger { symbol = resultSymTab.getLibrarySymbol(name); } if (symbol != null) { -// symbol.setSymbolData3(comment); +// symbol.setSymbolStringData(comment); if (symbol.getParentNamespace().equals(resultParentNs)) { long resolveSymID = symbol.getID(); updateResolveIDs(srcPgm, srcSymID, resolveSymID); @@ -2671,7 +2671,7 @@ class SymbolMerger extends AbstractListingMerger { String symbolName, ChangeListener listener) { Symbol latest = latestSymTab.getNamespace(symbolName, DiffUtility.getNamespace(myNamespace, latestPgm)) - .getSymbol(); + .getSymbol(); Symbol my = mySymTab.getNamespace(symbolName, myNamespace).getSymbol(); String text = "Namespace Conflict"; conflictPanel.clear(); @@ -2864,7 +2864,7 @@ class SymbolMerger extends AbstractListingMerger { // info[1] = s.getName(false); // info[2] = s.getParentNamespace().getSymbol().getName(); // info[3] = s.getSymbolType().toString(); -// info[4] = ConflictUtility.getTruncatedHTMLString(s.getSymbolData3(), TRUNCATE_LENGTH); +// info[4] = ConflictUtility.getTruncatedHTMLString(s.getSymbolStringData(), TRUNCATE_LENGTH); // return info; // } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolMerge.java b/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolMerge.java index 8f5e44ab1b..a401b5943a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolMerge.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolMerge.java @@ -391,8 +391,8 @@ class SymbolMerge { if (replace && toSymbol.isPinned() != pinned) { toSymbol.setPinned(pinned); } -// String fromComment = fromSymbol.getSymbolData3(); -// String toComment = toSymbol.getSymbolData3(); +// String fromComment = fromSymbol.getSymbolStringData(); +// String toComment = toSymbol.getSymbolStringData(); // if (!SystemUtilities.isEqual(fromComment, toComment)) { // String newComment; // if (replace) { @@ -401,7 +401,7 @@ class SymbolMerge { // else { // newComment = StringUtilities.mergeStrings(fromComment, toComment); // } -// toSymbol.setSymbolData3(newComment); +// toSymbol.setSymbolStringData(newComment); // } } } @@ -462,7 +462,7 @@ class SymbolMerge { boolean isFromDefaultThunk = FunctionMerge.isDefaultThunk(fromFunc); String fromName = fromSymbol.getName(); Namespace fromNamespace = // default thunks will lie about their namespace - isFromDefaultThunk ? fromProgram.getGlobalNamespace() : fromSymbol.getParentNamespace(); + isFromDefaultThunk ? fromProgram.getGlobalNamespace() : fromSymbol.getParentNamespace(); Symbol toSymbol; if (toFunc == null) { @@ -551,7 +551,8 @@ class SymbolMerge { boolean fromDefault = fromSymbol.getSource() == SourceType.DEFAULT; boolean isFromDefaultThunk = FunctionMerge.isDefaultThunk(fromFunc); Namespace fromNamespace = // default thunks will lie about their namespace - isFromDefaultThunk ? fromProgram.getGlobalNamespace() : fromSymbol.getParentNamespace(); + isFromDefaultThunk ? fromProgram.getGlobalNamespace() + : fromSymbol.getParentNamespace(); Namespace resolveNamespace = resolveNamespace(fromNamespace, conflictSymbolIDMap); if ((toFunc != null) && replacePrimary && !fromDefault) { @@ -573,7 +574,7 @@ class SymbolMerge { if (isFromDefaultThunk && FunctionMerge.isDefaultThunk(toFunc)) { return; } - + if (toFunc.getSymbol().getSource() == SourceType.DEFAULT) { // Default "to" function so replace replaceFunctionSymbol(fromEntryPoint, toEntryPoint, conflictSymbolIDMap, diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/SymbolMergeManagerSourceTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/SymbolMergeManagerSourceTest.java index dab491e17f..11f546c359 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/SymbolMergeManagerSourceTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/SymbolMergeManagerSourceTest.java @@ -81,8 +81,9 @@ public class SymbolMergeManagerSourceTest extends AbstractListingMergeManagerTes int txId = program.startTransaction("Modify My Program"); boolean commit = false; try { - program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Lucy", null, - SourceType.USER_DEFINED); + program.getSymbolTable() + .createLabel(addr(program, "0x10032a7"), "Lucy", null, + SourceType.USER_DEFINED); commit = true; } catch (Exception e) { @@ -101,8 +102,9 @@ public class SymbolMergeManagerSourceTest extends AbstractListingMergeManagerTes int txId = program.startTransaction("Modify My Program"); boolean commit = false; try { - program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Lucy", null, - SourceType.USER_DEFINED); + program.getSymbolTable() + .createLabel(addr(program, "0x10032a7"), "Lucy", null, + SourceType.USER_DEFINED); commit = true; } catch (Exception e) { @@ -141,11 +143,11 @@ public class SymbolMergeManagerSourceTest extends AbstractListingMergeManagerTes // try { // Symbol s = program.getSymbolTable().createSymbol(addr(program, "0x10032a7"), // "Lucy", null, SourceType.USER_DEFINED); -// s.setSymbolData3("This is a symbol comment."); +// s.setSymbolStringData("This is a symbol comment."); // // s = program.getSymbolTable().createSymbol(addr(program, "0x1004bf4"), // "red", null, SourceType.IMPORTED); -// s.setSymbolData3(longComment1); +// s.setSymbolStringData(longComment1); // commit = true; // } catch (Exception e) { // Assert.fail(e.getMessage()); @@ -163,11 +165,11 @@ public class SymbolMergeManagerSourceTest extends AbstractListingMergeManagerTes // try { // Symbol s = program.getSymbolTable().createSymbol(addr(program, "0x10032a7"), "Lucy", null, // SourceType.USER_DEFINED); -// s.setSymbolData3("This is a symbol comment."); +// s.setSymbolStringData("This is a symbol comment."); // // s = program.getSymbolTable().createSymbol(addr(program, "0x1004bf4"), // "red", null, SourceType.IMPORTED); -// s.setSymbolData3(longComment1); +// s.setSymbolStringData(longComment1); // commit = true; // } catch (Exception e) { // Assert.fail(e.getMessage()); @@ -186,13 +188,13 @@ public class SymbolMergeManagerSourceTest extends AbstractListingMergeManagerTes // checkSymbol(s, "Lucy", true); // assertTrue(s.isPrimary()); // assertEquals(SourceType.USER_DEFINED, s.getSource()); -// assertEquals("This is a symbol comment.", s.getSymbolData3()); +// assertEquals("This is a symbol comment.", s.getSymbolStringData()); // // s = symtab.getPrimarySymbol(addr("0x1004bf4")); // checkSymbol(s, "red", true); // assertTrue(s.isPrimary()); // assertEquals(SourceType.IMPORTED, s.getSource()); -// assertEquals(longComment1, s.getSymbolData3()); +// assertEquals(longComment1, s.getSymbolStringData()); // } /** Test add of same symbol and source to both Latest and My, but different symbol comments. */ @@ -351,12 +353,15 @@ public class SymbolMergeManagerSourceTest extends AbstractListingMergeManagerTes int txId = program.startTransaction("Modify My Program"); boolean commit = false; try { - program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Charlie", - null, SourceType.ANALYSIS); - program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Lucy", null, - SourceType.IMPORTED); - program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Linus", null, - SourceType.USER_DEFINED); + program.getSymbolTable() + .createLabel(addr(program, "0x10032a7"), "Charlie", + null, SourceType.ANALYSIS); + program.getSymbolTable() + .createLabel(addr(program, "0x10032a7"), "Lucy", null, + SourceType.IMPORTED); + program.getSymbolTable() + .createLabel(addr(program, "0x10032a7"), "Linus", null, + SourceType.USER_DEFINED); commit = true; } catch (Exception e) { @@ -375,12 +380,15 @@ public class SymbolMergeManagerSourceTest extends AbstractListingMergeManagerTes int txId = program.startTransaction("Modify My Program"); boolean commit = false; try { - program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Charlie", - null, SourceType.USER_DEFINED); - program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Lucy", null, - SourceType.ANALYSIS); - program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Linus", null, - SourceType.IMPORTED); + program.getSymbolTable() + .createLabel(addr(program, "0x10032a7"), "Charlie", + null, SourceType.USER_DEFINED); + program.getSymbolTable() + .createLabel(addr(program, "0x10032a7"), "Lucy", null, + SourceType.ANALYSIS); + program.getSymbolTable() + .createLabel(addr(program, "0x10032a7"), "Linus", null, + SourceType.IMPORTED); commit = true; } catch (Exception e) { @@ -426,12 +434,15 @@ public class SymbolMergeManagerSourceTest extends AbstractListingMergeManagerTes int txId = program.startTransaction("Modify My Program"); boolean commit = false; try { - program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Lucy", null, - SourceType.IMPORTED); - program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Linus", null, - SourceType.ANALYSIS); - program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Sally", null, - SourceType.USER_DEFINED); + program.getSymbolTable() + .createLabel(addr(program, "0x10032a7"), "Lucy", null, + SourceType.IMPORTED); + program.getSymbolTable() + .createLabel(addr(program, "0x10032a7"), "Linus", null, + SourceType.ANALYSIS); + program.getSymbolTable() + .createLabel(addr(program, "0x10032a7"), "Sally", null, + SourceType.USER_DEFINED); commit = true; } catch (Exception e) { @@ -493,12 +504,15 @@ public class SymbolMergeManagerSourceTest extends AbstractListingMergeManagerTes int txId = program.startTransaction("Modify My Program"); boolean commit = false; try { - program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Charlie", - null, SourceType.USER_DEFINED); - program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Lucy", null, - SourceType.ANALYSIS); - program.getSymbolTable().createLabel(addr(program, "0x10032a7"), "Linus", null, - SourceType.IMPORTED); + program.getSymbolTable() + .createLabel(addr(program, "0x10032a7"), "Charlie", + null, SourceType.USER_DEFINED); + program.getSymbolTable() + .createLabel(addr(program, "0x10032a7"), "Lucy", null, + SourceType.ANALYSIS); + program.getSymbolTable() + .createLabel(addr(program, "0x10032a7"), "Linus", null, + SourceType.IMPORTED); commit = true; } catch (Exception e) { diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/function/FunctionManagerTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/function/FunctionManagerTest.java index 50452f7fde..5180c01bd8 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/function/FunctionManagerTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/function/FunctionManagerTest.java @@ -32,7 +32,6 @@ import ghidra.program.model.lang.PrototypeModel; import ghidra.program.model.listing.*; import ghidra.program.model.symbol.*; import ghidra.test.AbstractGhidraHeadedIntegrationTest; -import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.InvalidInputException; import ghidra.util.task.TaskMonitorAdapter; @@ -53,8 +52,9 @@ public class FunctionManagerTest extends AbstractGhidraHeadedIntegrationTest { space = program.getAddressFactory().getDefaultAddressSpace(); functionManager = program.getFunctionManager(); transactionID = program.startTransaction("Test"); - program.getMemory().createInitializedBlock("temp", addr(0), 10000, (byte) 0, - TaskMonitorAdapter.DUMMY_MONITOR, false); + program.getMemory() + .createInitializedBlock("temp", addr(0), 10000, (byte) 0, + TaskMonitorAdapter.DUMMY_MONITOR, false); } @After @@ -71,7 +71,7 @@ public class FunctionManagerTest extends AbstractGhidraHeadedIntegrationTest { } private Function createFunction(String name, Address entryPt, AddressSetView body) - throws DuplicateNameException, InvalidInputException, OverlappingFunctionException { + throws InvalidInputException, OverlappingFunctionException { functionManager.createFunction(name, entryPt, body, SourceType.USER_DEFINED); Function f = functionManager.getFunctionAt(entryPt); @@ -209,8 +209,10 @@ public class FunctionManagerTest extends AbstractGhidraHeadedIntegrationTest { f = functionManager.getFunctionAt(addr(250)); assertEquals(new AddressSet(addr(250), addr(350)), f.getBody()); - assertTrue(program.getSymbolTable().getPrimarySymbol( - addr(201)).getSymbolType() != SymbolType.FUNCTION); + assertTrue(program.getSymbolTable() + .getPrimarySymbol( + addr(201)) + .getSymbolType() != SymbolType.FUNCTION); } @Test @@ -301,16 +303,19 @@ public class FunctionManagerTest extends AbstractGhidraHeadedIntegrationTest { createFunction("foo1", addr(250), new AddressSet(addr(250), addr(350))); Function foo2 = createFunction("foo2", addr(201), new AddressSet(addr(201), addr(249))); - Function fum = program.getExternalManager().addExtLocation("lib", "fum", null, - SourceType.USER_DEFINED).createFunction(); + Function fum = program.getExternalManager() + .addExtLocation("lib", "fum", null, + SourceType.USER_DEFINED) + .createFunction(); program.getMemory().setInt(addr(50), 201); program.getListing().createData(addr(50), PointerDataType.dataType); assertEquals(foo2, program.getFunctionManager().getReferencedFunction(addr(50))); - program.getReferenceManager().addExternalReference(addr(50), 0, - program.getExternalManager().getExternalLocation(fum.getSymbol()), - SourceType.USER_DEFINED, RefType.DATA); + program.getReferenceManager() + .addExternalReference(addr(50), 0, + program.getExternalManager().getExternalLocation(fum.getSymbol()), + SourceType.USER_DEFINED, RefType.DATA); assertEquals(fum, program.getFunctionManager().getReferencedFunction(addr(50))); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/symbol/SymbolManagerTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/symbol/SymbolManagerTest.java index 1125ccc692..f43a560bb9 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/symbol/SymbolManagerTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/symbol/SymbolManagerTest.java @@ -27,9 +27,9 @@ import ghidra.app.cmd.function.CreateFunctionCmd; import ghidra.program.database.ProgramBuilder; import ghidra.program.database.ProgramDB; import ghidra.program.model.address.*; -import ghidra.program.model.data.ByteDataType; -import ghidra.program.model.data.WordDataType; +import ghidra.program.model.data.*; import ghidra.program.model.listing.*; +import ghidra.program.model.listing.Function.FunctionUpdateType; import ghidra.program.model.mem.Memory; import ghidra.program.model.mem.MemoryBlock; import ghidra.program.model.symbol.*; @@ -52,6 +52,7 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest { private NamespaceManager scopeMgr; private int transactionID; private Namespace globalScope; + private Listing listing; public SymbolManagerTest() { super(); @@ -69,6 +70,7 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest { st = program.getSymbolTable(); refMgr = program.getReferenceManager(); scopeMgr = program.getNamespaceManager(); + listing = program.getListing(); } @After @@ -224,26 +226,26 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest { Symbol[] s = st.getSymbols(addr(256)); assertEquals(1, s.length); assertEquals("LAB_00000100", s[0].getName()); - program.getListing().createData(addr(256), new ByteDataType()); + listing.createData(addr(256), new ByteDataType()); assertEquals("BYTE_00000100", s[0].getName()); } @Test public void testDynamicNameChangesWhenDataCleared() throws Exception { refMgr.addMemoryReference(addr(512), addr(256), RefType.FLOW, SourceType.USER_DEFINED, -1); - program.getListing().createData(addr(256), new ByteDataType()); + listing.createData(addr(256), new ByteDataType()); Symbol[] s = st.getSymbols(addr(256)); assertEquals(1, s.length); assertEquals("BYTE_00000100", s[0].getName()); - program.getListing().clearCodeUnits(addr(256), addr(256), false); + listing.clearCodeUnits(addr(256), addr(256), false); assertEquals("LAB_00000100", s[0].getName()); } @Test public void testDynamicOffcutNameChangesWhenSymbolCreated() throws Exception { refMgr.addMemoryReference(addr(512), addr(257), RefType.FLOW, SourceType.USER_DEFINED, -1); - program.getListing().createData(addr(256), new WordDataType()); + listing.createData(addr(256), new WordDataType()); Symbol[] s = st.getSymbols(addr(257)); assertEquals(1, s.length); @@ -255,7 +257,7 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest { @Test public void testDynamicOffcutNameChangesWhenSymbolRenamed() throws Exception { refMgr.addMemoryReference(addr(512), addr(257), RefType.FLOW, SourceType.USER_DEFINED, -1); - program.getListing().createData(addr(256), new WordDataType()); + listing.createData(addr(256), new WordDataType()); Symbol label = st.createLabel(addr(256), "bob", SourceType.USER_DEFINED); Symbol[] s = st.getSymbols(addr(257)); @@ -268,7 +270,7 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest { @Test public void testDynamicOffcutNameChangesWhenSymbolRemoved() throws Exception { refMgr.addMemoryReference(addr(512), addr(257), RefType.FLOW, SourceType.USER_DEFINED, -1); - program.getListing().createData(addr(256), new WordDataType()); + listing.createData(addr(256), new WordDataType()); Symbol label = st.createLabel(addr(256), "bob", SourceType.USER_DEFINED); Symbol[] s = st.getSymbols(addr(257)); @@ -277,6 +279,7 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest { label.delete(); assertEquals("WORD_00000100+1", s[0].getName()); } + @Test public void testDynamicNameChangesWhenOffcutByInstruction() throws Exception { refMgr.addMemoryReference(addr(512), addr(257), RefType.FLOW, SourceType.USER_DEFINED, -1); @@ -285,7 +288,7 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest { assertEquals(1, s.length); assertEquals("LAB_00000101", s[0].getName()); createInstruction(addr(256)); - CodeUnit codeUnitAt = program.getListing().getCodeUnitAt(addr(256)); + CodeUnit codeUnitAt = listing.getCodeUnitAt(addr(256)); assertTrue(codeUnitAt instanceof Instruction); assertEquals(2, codeUnitAt.getLength()); @@ -320,7 +323,6 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest { assertEquals("LAB_00000100", s[0].getName()); } - private void createInstruction(Address addr) throws Exception { int tx = program.startTransaction("test"); try { @@ -338,7 +340,6 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest { @Test public void testGetDefaultFunctionSymbolByName() throws Exception { - Listing listing = program.getListing(); AddressSet set = new AddressSet(); set.addRange(addr(100), addr(150)); @@ -398,8 +399,6 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest { Address ovAddress = block.getStart(); assertEquals("ov_12::00000000", ovAddress.toString()); - Listing listing = program.getListing(); - AddressSet set = new AddressSet(ovAddress, ovAddress); Function f = listing.createFunction("fredFunc", ovAddress, set, SourceType.DEFAULT); assertNotNull(f); @@ -426,7 +425,7 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest { Address ovAddress = block.getStart(); assertEquals("ov12::00000000", ovAddress.toString()); ovAddress = ovAddress.add(2); - Listing listing = p.getListing(); + listing = p.getListing(); st = p.getSymbolTable(); AddressSet set = new AddressSet(ovAddress, ovAddress); @@ -681,9 +680,8 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest { @Test public void testRemoveFunctionSymbolAfterFunction() throws Exception { - CreateFunctionCmd cmd = new CreateFunctionCmd("MyFunction", addr(0x0200), + createFunction("MyFunction", addr(0x0200), new AddressSet(addr(0x0200), addr(0x0280)), SourceType.USER_DEFINED); - assertTrue(cmd.applyTo(program)); program.getFunctionManager().removeFunction(addr(0x0200)); Symbol s = st.getPrimarySymbol(addr(0x0200)); assertNotNull(s); @@ -695,9 +693,8 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest { @Test public void testRemoveFunctionBecomesCodeSymbol() throws Exception { - CreateFunctionCmd cmd = new CreateFunctionCmd("MyFunction", addr(0x0200), + createFunction("MyFunction", addr(0x0200), new AddressSet(addr(0x0200), addr(0x0280)), SourceType.USER_DEFINED); - assertTrue(cmd.applyTo(program)); Symbol s = st.getPrimarySymbol(addr(0x0200)); assertEquals(SymbolType.FUNCTION, s.getSymbolType()); @@ -719,9 +716,8 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest { @Test public void testRemoveFunctionSymbolBecomesExistingCodeSymbol() throws Exception { Address entryPt = addr(0x0200); - CreateFunctionCmd cmd = new CreateFunctionCmd("MyFunction", entryPt, + createFunction("MyFunction", entryPt, new AddressSet(addr(0x0200), addr(0x0280)), SourceType.USER_DEFINED); - assertTrue(cmd.applyTo(program)); st.createLabel(entryPt, "Bob", SourceType.USER_DEFINED); @@ -754,9 +750,8 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest { Namespace oldNamespace = st.createNameSpace(null, "OldNameSpace", SourceType.USER_DEFINED); Namespace newNamespace = st.createNameSpace(null, "NewNameSpace", SourceType.USER_DEFINED); Address entryPt = addr(0x0200); - CreateFunctionCmd cmd = new CreateFunctionCmd("MyFunction", entryPt, - new AddressSet(addr(0x0200), addr(0x0280)), SourceType.USER_DEFINED); - assertTrue(cmd.applyTo(program)); + createFunction("MyFunction", entryPt, new AddressSet(addr(0x0200), addr(0x0280)), + SourceType.USER_DEFINED); Symbol functionSym = program.getFunctionManager().getFunctionAt(entryPt).getSymbol(); Symbol conflictSym = st.createLabel(addr(0x0230), "Bob", SourceType.USER_DEFINED);// put a conflict symbol in. conflictSym.setNamespace(oldNamespace); @@ -794,9 +789,8 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest { @Test public void testRemoveFunctionSymbolBecomesDefault() throws Exception { - CreateFunctionCmd cmd = new CreateFunctionCmd("MyFunction", addr(0x0200), + createFunction("MyFunction", addr(0x0200), new AddressSet(addr(0x0200), addr(0x0280)), SourceType.USER_DEFINED); - assertTrue(cmd.applyTo(program)); Symbol s = st.getPrimarySymbol(addr(0x0200)); assertEquals(SymbolType.FUNCTION, s.getSymbolType()); @@ -814,6 +808,112 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest { assertEquals(false, removed);// Should not be able to remove default function symbol. } + private Function createFunction(String name, Address entry, AddressSetView body, + SourceType type) { + CreateFunctionCmd cmd = new CreateFunctionCmd(name, entry, body, type); + assertTrue(cmd.applyTo(program)); + return cmd.getFunction(); + } + + private Function createFunction(String name, Address entry) { + AddressSet set = new AddressSet(entry, entry); + return createFunction(name, entry, set, SourceType.USER_DEFINED); + } + + @Test + public void testPrimarySymbolBecomesNonPrimaryAfterFunctionCreated() throws Exception { + Address addr = addr(256); + Symbol sym1 = createSymbol(addr, "TEST1"); + Symbol sym2 = createSymbol(addr, "TEST2"); + Symbol sym3 = createSymbol(addr, "TEST3"); + + assertEquals(sym1, st.getPrimarySymbol(addr)); + + createFunction("TEST_FUN", addr, new AddressSet(addr, addr), SourceType.USER_DEFINED); + Symbol primary = st.getPrimarySymbol(addr); + assertEquals("TEST_FUN", primary.getName()); + assertEquals(SymbolType.FUNCTION, primary.getSymbolType()); + + Symbol[] symbols = st.getSymbols(addr); + assertEquals(4, symbols.length); + + List 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 list = Arrays.asList(symbols); + assertFalse(list.contains(sym1)); // sym1 was deleted and recreated as a function symbol + assertTrue(list.contains(primary)); + assertTrue(list.contains(sym2)); + assertTrue(list.contains(sym3)); + + assertTrue(primary.isPrimary()); + assertFalse(sym2.isPrimary()); + assertFalse(sym3.isPrimary()); + + } + + @Test + public void testCreateDefaultFunctionWhereDefaultLableExists() { + Address addr = addr(256); + refMgr.addMemoryReference(addr(784), addr, RefType.FLOW, SourceType.USER_DEFINED, 2); + Symbol primary = st.getPrimarySymbol(addr); + assertNotNull(primary); + assertEquals(SymbolType.LABEL, primary.getSymbolType()); + assertTrue(primary.getName().startsWith("LAB")); + + createFunction(null, addr, new AddressSet(addr, addr), SourceType.DEFAULT); + Symbol newPrimary = st.getPrimarySymbol(addr); + assertTrue(primary != newPrimary); + assertEquals(SymbolType.FUNCTION, newPrimary.getSymbolType()); + assertTrue(newPrimary.getName().startsWith("FUN")); + assertTrue(primary.isDeleted()); + assertEquals(1, st.getSymbols(addr).length); + } + + @Test + public void testCreateNonDefaultFunctionWhereDefaultLableExists() { + Address addr = addr(256); + refMgr.addMemoryReference(addr(784), addr, RefType.FLOW, SourceType.USER_DEFINED, 2); + Symbol primary = st.getPrimarySymbol(addr); + assertNotNull(primary); + assertEquals(SymbolType.LABEL, primary.getSymbolType()); + assertTrue(primary.getName().startsWith("LAB")); + + createFunction("AAA", addr, new AddressSet(addr, addr), SourceType.USER_DEFINED); + Symbol newPrimary = st.getPrimarySymbol(addr); + assertTrue(primary != newPrimary); + assertEquals(SymbolType.FUNCTION, newPrimary.getSymbolType()); + assertEquals("AAA", newPrimary.getName()); + assertTrue(primary.isDeleted()); + assertEquals(1, st.getSymbols(addr).length); + } + @Test public void testRenameSymbol() throws Exception { Symbol s = createSymbol(addr(100), "primary"); @@ -1271,6 +1371,48 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest { assertEquals("1", s.getName()); } + @Test + public void testSymbolIteratorByType() throws Exception { + createSymbol(addr(100), "1"); + createSymbol(addr(200), "2"); + createSymbol(addr(300), "3"); + + Function f1 = createFunction("A", addr(150)); + Function f2 = createFunction("B", addr(250)); + + SymbolIterator it = + st.getSymbols(new AddressSet(addr(0), addr(5000)), SymbolType.FUNCTION, true); + + assertTrue(it.hasNext()); + assertEquals(f1.getSymbol(), it.next()); + + assertTrue(it.hasNext()); + assertEquals(f2.getSymbol(), it.next()); + + assertFalse(it.hasNext()); + } + + @Test + public void testSymbolIteratorByTypeBackward() throws Exception { + createSymbol(addr(100), "1"); + createSymbol(addr(200), "2"); + createSymbol(addr(300), "3"); + + Function f1 = createFunction("A", addr(150)); + Function f2 = createFunction("B", addr(250)); + + SymbolIterator it = + st.getSymbols(new AddressSet(addr(0), addr(5000)), SymbolType.FUNCTION, false); + + assertTrue(it.hasNext()); + assertEquals(f2.getSymbol(), it.next()); + + assertTrue(it.hasNext()); + assertEquals(f1.getSymbol(), it.next()); + + assertFalse(it.hasNext()); + } + @Test public void testAddReference() throws Exception { refMgr.addMemoryReference(addr(512), addr(256), RefType.CONDITIONAL_CALL, @@ -1321,7 +1463,6 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest { @Test public void testCreateFunction() throws Exception { - Listing listing = program.getListing(); Symbol s = createSymbol(addr(100), "fred"); assertTrue(s.isPrimary()); @@ -1330,7 +1471,7 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest { set.addRange(addr(100), addr(150)); set.addRange(addr(300), addr(310)); set.addRange(addr(320), addr(330)); - Function f = listing.createFunction("fredFunc", addr(100), set, SourceType.USER_DEFINED); + Function f = createFunction("fredFunc", addr(100), set, SourceType.USER_DEFINED); Symbol s1 = st.getPrimarySymbol(addr(100)); assertNotNull(s1); @@ -1349,7 +1490,6 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest { @Test public void testPromoteLabelToFunctionWithMultipleLabels() throws Exception { - Listing listing = program.getListing(); Symbol s = createSymbol(addr(100), "fred"); assertTrue(s.isPrimary()); @@ -1367,7 +1507,6 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest { @Test public void testRenameFunctionToExistingName() throws Exception { - Listing listing = program.getListing(); AddressSet set1 = new AddressSet(); set1.addRange(addr(100), addr(150)); @@ -1386,7 +1525,6 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest { @Test public void testRemoveFunction() throws Exception { - Listing listing = program.getListing(); Symbol s = createSymbol(addr(100), "fred"); assertFalse(s.isDeleted()); @@ -1690,11 +1828,279 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest { } + @Test + public void testGetSymbolByNameAndNamespace() throws Exception { + Namespace namespace1 = st.createNameSpace(null, "MySpace1", SourceType.USER_DEFINED); + Symbol s1 = st.createLabel(addr(0x100), "Symbol", namespace1, SourceType.USER_DEFINED); + + List 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 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 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 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 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 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 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 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 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 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 symbols = st.getSymbols("param_1", f); + assertEquals(1, symbols.size()); + assertEquals(parameter.getSymbol(), symbols.get(0)); + } + + @Test + public void testGetSymbolByNameNamespaceAddress() throws Exception { + Namespace namespace1 = st.createNameSpace(null, "MySpace1", SourceType.USER_DEFINED); + Symbol s1 = st.createLabel(addr(0x100), "Symbol", namespace1, SourceType.USER_DEFINED); + + Symbol symbol = st.getSymbol("Symbol", addr(0x100), namespace1); + assertEquals(s1, symbol); + } + + @Test + public void testGetSymbolByNameNamespaceAddressForDefaultFunction() throws Exception { + Namespace namespace1 = st.createNameSpace(null, "MySpace1", SourceType.USER_DEFINED); + AddressSet set = new AddressSet(); + set.addRange(addr(0x100), addr(0x150)); + Function f = + listing.createFunction(null, namespace1, addr(0x100), set, SourceType.DEFAULT); + assertNotNull(f); + + Symbol symbol = st.getSymbol("FUN_00000100", addr(0x100), namespace1); + assertEquals(f.getSymbol(), symbol); + } + + @Test + public void testGetSymbolByNameNamespaceAddressForLocalVar() throws Exception { + Namespace namespace1 = st.createNameSpace(null, "MySpace1", SourceType.USER_DEFINED); + AddressSet set = new AddressSet(); + set.addRange(addr(0x100), addr(0x150)); + Function f = + listing.createFunction(null, namespace1, addr(0x100), set, SourceType.DEFAULT); + assertNotNull(f); + + Variable var = + f.addLocalVariable(new LocalVariableImpl("Bob", new IntegerDataType(), 0x8, program), + SourceType.USER_DEFINED); + Address address = var.getSymbol().getAddress(); + + Symbol symbol = st.getSymbol("Bob", address, f); + assertEquals(var.getSymbol(), symbol); + } + + @Test + public void testGetSymbolByNameNamespaceAddressForDefaultLocalVar() throws Exception { + Namespace namespace1 = st.createNameSpace(null, "MySpace1", SourceType.USER_DEFINED); + AddressSet set = new AddressSet(); + set.addRange(addr(0x100), addr(0x150)); + Function f = + listing.createFunction(null, namespace1, addr(0x100), set, SourceType.DEFAULT); + assertNotNull(f); + + Variable var = + f.addLocalVariable(new LocalVariableImpl(null, new IntegerDataType(), 0x8, program), + SourceType.DEFAULT); + Address address = var.getSymbol().getAddress(); + Symbol symbol = st.getSymbol(var.getName(), address, f); + assertEquals(var.getSymbol(), symbol); + } + + @Test + public void testGetSymbolByNameNamespaceAddressForParam() throws Exception { + Namespace namespace1 = st.createNameSpace(null, "MySpace1", SourceType.USER_DEFINED); + AddressSet set = new AddressSet(); + DataType dt = new IntegerDataType(); + Variable param = new ParameterImpl("Bob", dt, program); + set.addRange(addr(0x100), addr(0x150)); + Function f = + listing.createFunction(null, namespace1, addr(0x100), set, SourceType.DEFAULT); + assertNotNull(f); + f.updateFunction(f.getCallingConventionName(), null, + FunctionUpdateType.DYNAMIC_STORAGE_FORMAL_PARAMS, true, SourceType.USER_DEFINED, param); + + Parameter parameter = f.getParameter(0); + Address address = parameter.getSymbol().getAddress(); + Symbol symbol = st.getSymbol("Bob", address, f); + assertEquals(parameter.getSymbol(), symbol); + } + + @Test + public void testGetSymbolByNameNamespaceAddressForDefaultParam() throws Exception { + Namespace namespace1 = st.createNameSpace(null, "MySpace1", SourceType.USER_DEFINED); + AddressSet set = new AddressSet(); + DataType dt = new IntegerDataType(); + Variable param = new ParameterImpl(null, dt, program); + set.addRange(addr(0x100), addr(0x150)); + Function f = + listing.createFunction(null, namespace1, addr(0x100), set, SourceType.DEFAULT); + assertNotNull(f); + f.updateFunction(f.getCallingConventionName(), null, + FunctionUpdateType.DYNAMIC_STORAGE_FORMAL_PARAMS, true, SourceType.DEFAULT, param); + + Parameter parameter = f.getParameter(0); + Address address = parameter.getSymbol().getAddress(); + Symbol symbol = st.getSymbol("param_1", address, f); + assertEquals(parameter.getSymbol(), symbol); + } + @Test public void testDuplicateSymbol() throws Exception { - st.createNameSpace(null, "MySpace1", SourceType.USER_DEFINED); - st.createNameSpace(null, "MySpace2", SourceType.USER_DEFINED); try { @@ -1704,12 +2110,10 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest { catch (DuplicateNameException e) { // good } - } @Test public void testDuplicateFunctionNames() throws Exception { - Listing listing = program.getListing(); AddressSet set1 = new AddressSet(); set1.addRange(addr(100), addr(150)); @@ -1722,7 +2126,6 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest { assertNotNull(f2); List symbols = st.getGlobalSymbols("fredFunc"); assertEquals(2, symbols.size()); - } @Test @@ -1773,8 +2176,9 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest { assertTrue(s.isValidParent(subspace1)); AddressSet set = new AddressSet(addr(0x100), addr(0x150)); - Function f = program.getFunctionManager().createFunction("function_1", addr(0x100), set, - SourceType.USER_DEFINED); + Function f = program.getFunctionManager() + .createFunction("function_1", addr(0x100), set, + SourceType.USER_DEFINED); assertTrue(s.isValidParent(f)); 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); AddressSet set = new AddressSet(addr(0x100), addr(0x150)); - Function f1 = program.getFunctionManager().createFunction("function_1", addr(0x100), set, - SourceType.USER_DEFINED); + Function f1 = program.getFunctionManager() + .createFunction("function_1", addr(0x100), set, + SourceType.USER_DEFINED); set = new AddressSet(addr(0x200), addr(0x250)); - Function f2 = program.getFunctionManager().createFunction("function_2", addr(0x200), set, - SourceType.USER_DEFINED); + Function f2 = program.getFunctionManager() + .createFunction("function_2", addr(0x200), set, + SourceType.USER_DEFINED); assertTrue(f1.getSymbol().isValidParent(subspace1));// TestNameSpace::MySpace1::function_1 is OK @@ -1823,8 +2229,9 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest { public void testIsValidParentForNamespace() throws Exception { AddressSet set = new AddressSet(addr(0x100), addr(0x150)); - Function f1 = program.getFunctionManager().createFunction("function_1", addr(0x100), set, - SourceType.USER_DEFINED); + Function f1 = program.getFunctionManager() + .createFunction("function_1", addr(0x100), set, + SourceType.USER_DEFINED); Namespace namespace = st.createNameSpace(null, "TestNameSpace", 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 { Library lib = st.createExternalLibrary("extLib", SourceType.USER_DEFINED); - ExternalLocation extLoc = program.getExternalManager().addExtFunction("extLib", "printf", - null, SourceType.USER_DEFINED); + ExternalLocation extLoc = program.getExternalManager() + .addExtFunction("extLib", "printf", + null, SourceType.USER_DEFINED); Symbol extSym = extLoc.getSymbol(); assertEquals(SymbolType.FUNCTION, extSym.getSymbolType()); Function extFunc = (Function) extSym.getObject(); diff --git a/Ghidra/Framework/DB/src/main/java/db/BinaryField.java b/Ghidra/Framework/DB/src/main/java/db/BinaryField.java index 0b1238f2b7..9955ae8541 100644 --- a/Ghidra/Framework/DB/src/main/java/db/BinaryField.java +++ b/Ghidra/Framework/DB/src/main/java/db/BinaryField.java @@ -59,7 +59,7 @@ public class BinaryField extends Field { } @Override - boolean isNull() { + public boolean isNull() { return data == null; } diff --git a/Ghidra/Framework/DB/src/main/java/db/Field.java b/Ghidra/Framework/DB/src/main/java/db/Field.java index 77529f9394..2e7b20cd0d 100644 --- a/Ghidra/Framework/DB/src/main/java/db/Field.java +++ b/Ghidra/Framework/DB/src/main/java/db/Field.java @@ -112,7 +112,7 @@ public abstract class Field implements Comparable { * is reserved for use in the special-purpose byte value 0x88. * (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 @@ -424,7 +424,7 @@ public abstract class Field implements Comparable { * Determine if the field has been set to a null-state or value. * @return true if field has been set to a null state or value, else false */ - abstract boolean isNull(); + public abstract boolean isNull(); /** * Set this field to its null-state. For variable-length field this will diff --git a/Ghidra/Framework/DB/src/main/java/db/FixedField.java b/Ghidra/Framework/DB/src/main/java/db/FixedField.java index 7d6b36b477..2f8434e21a 100644 --- a/Ghidra/Framework/DB/src/main/java/db/FixedField.java +++ b/Ghidra/Framework/DB/src/main/java/db/FixedField.java @@ -47,7 +47,7 @@ abstract class FixedField extends BinaryField { } @Override - final boolean isNull() { + public final boolean isNull() { return isNull; } diff --git a/Ghidra/Framework/DB/src/main/java/db/IndexField.java b/Ghidra/Framework/DB/src/main/java/db/IndexField.java index 1c1487e439..44cafbc278 100644 --- a/Ghidra/Framework/DB/src/main/java/db/IndexField.java +++ b/Ghidra/Framework/DB/src/main/java/db/IndexField.java @@ -56,7 +56,7 @@ class IndexField extends Field { } @Override - boolean isNull() { + public boolean isNull() { return false; // not-applicable } diff --git a/Ghidra/Framework/DB/src/main/java/db/PrimitiveField.java b/Ghidra/Framework/DB/src/main/java/db/PrimitiveField.java index 384edc5980..0c1a05f051 100644 --- a/Ghidra/Framework/DB/src/main/java/db/PrimitiveField.java +++ b/Ghidra/Framework/DB/src/main/java/db/PrimitiveField.java @@ -42,7 +42,7 @@ abstract class PrimitiveField extends Field { } @Override - final boolean isNull() { + public final boolean isNull() { return isNull; } diff --git a/Ghidra/Framework/DB/src/main/java/db/StringField.java b/Ghidra/Framework/DB/src/main/java/db/StringField.java index e7cb1c0cd2..ee8ca798b6 100644 --- a/Ghidra/Framework/DB/src/main/java/db/StringField.java +++ b/Ghidra/Framework/DB/src/main/java/db/StringField.java @@ -67,7 +67,7 @@ public final class StringField extends Field { } @Override - boolean isNull() { + public boolean isNull() { return bytes == null; } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/external/ExternalLocationDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/external/ExternalLocationDB.java index 64d5574bed..2b88d8fdd1 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/external/ExternalLocationDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/external/ExternalLocationDB.java @@ -98,7 +98,7 @@ public class ExternalLocationDB implements ExternalLocation { @Override public String getOriginalImportedName() { - return getExternalData3(symbol).getOriginalImportedName(); + return getExternalData(symbol).getOriginalImportedName(); } @Override @@ -111,7 +111,7 @@ public class ExternalLocationDB implements ExternalLocation { */ @Override public Address getAddress() { - return getExternalData3(symbol).getAddress(extMgr.getAddressMap().getAddressFactory()); + return getExternalData(symbol).getAddress(extMgr.getAddressMap().getAddressFactory()); } /** @@ -141,7 +141,7 @@ public class ExternalLocationDB implements ExternalLocation { */ @Override public DataType getDataType() { - long dataTypeID = symbol.getSymbolData1(); + long dataTypeID = symbol.getDataTypeId(); if (dataTypeID < 0) { return null; } @@ -154,7 +154,7 @@ public class ExternalLocationDB implements ExternalLocation { @Override public void setDataType(DataType dt) { long dataTypeID = extMgr.getProgram().getDataTypeManager().getResolvedID(dt); - symbol.setSymbolData1(dataTypeID); + symbol.setDataTypeId(dataTypeID); // TODO: change notification may be required } @@ -227,7 +227,7 @@ public class ExternalLocationDB implements ExternalLocation { if (addressString == null && getSource() == SourceType.DEFAULT) { throw new InvalidInputException("Either an external label or address is required"); } - updateSymbolData3(symbol, getExternalData3(symbol).getOriginalImportedName(), + updateSymbolData(symbol, getExternalData(symbol).getOriginalImportedName(), addressString); } @@ -365,18 +365,18 @@ public class ExternalLocationDB implements ExternalLocation { } - static ExternalData3 getExternalData3(SymbolDB extSymbol) { - return new ExternalData3(extSymbol.getSymbolData3()); + static ExternalData getExternalData(SymbolDB extSymbol) { + return new ExternalData(extSymbol.getSymbolStringData()); } static void setOriginalImportedName(SymbolDB extSymbol, String name) { - updateSymbolData3(extSymbol, name, getExternalData3(extSymbol).getAddressString()); + updateSymbolData(extSymbol, name, getExternalData(extSymbol).getAddressString()); } - static void updateSymbolData3(SymbolDB extSymbol, String originalImportedName, + static void updateSymbolData(SymbolDB extSymbol, String originalImportedName, String addressString) { if (addressString == null && originalImportedName == null) { - extSymbol.setSymbolData3(null); + extSymbol.setSymbolStringData(null); } StringBuilder buf = new StringBuilder(); if (addressString != null) { @@ -386,18 +386,18 @@ public class ExternalLocationDB implements ExternalLocation { buf.append(ORIGINAL_IMPORTED_DELIMITER); buf.append(originalImportedName); } - extSymbol.setSymbolData3(buf.toString()); + extSymbol.setSymbolStringData(buf.toString()); } - static class ExternalData3 { + static class ExternalData { private String originalImportedName; private String addressString; - ExternalData3(String data3) { - if (data3 != null) { - int indexOf = data3.indexOf(ORIGINAL_IMPORTED_DELIMITER); - originalImportedName = indexOf >= 0 ? data3.substring(indexOf + 1) : null; - addressString = indexOf >= 0 ? data3.substring(0, indexOf) : data3; + ExternalData(String stringData) { + if (stringData != null) { + int indexOf = stringData.indexOf(ORIGINAL_IMPORTED_DELIMITER); + originalImportedName = indexOf >= 0 ? stringData.substring(indexOf + 1) : null; + addressString = indexOf >= 0 ? stringData.substring(0, indexOf) : stringData; } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/external/ExternalManagerDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/external/ExternalManagerDB.java index f3f38b0e65..aa49076e44 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/external/ExternalManagerDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/external/ExternalManagerDB.java @@ -22,7 +22,7 @@ import db.*; import ghidra.framework.store.FileSystem; import ghidra.program.database.ManagerDB; import ghidra.program.database.ProgramDB; -import ghidra.program.database.external.ExternalLocationDB.ExternalData3; +import ghidra.program.database.external.ExternalLocationDB.ExternalData; import ghidra.program.database.function.FunctionManagerDB; import ghidra.program.database.map.AddressMap; import ghidra.program.database.symbol.*; @@ -556,15 +556,15 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager { if ((type != SymbolType.LABEL && type != SymbolType.FUNCTION) || !sym.isExternal()) { throw new AssertException(); } - ExternalData3 externalData3 = ExternalLocationDB.getExternalData3(sym); - Address addr = externalData3.getAddress(sym.getProgram().getAddressFactory()); + ExternalData externalData = ExternalLocationDB.getExternalData(sym); + Address addr = externalData.getAddress(sym.getProgram().getAddressFactory()); if (addr == null) { throw new AssertException("External should not be default without memory address"); } if (type == SymbolType.FUNCTION) { return SymbolUtilities.getDefaultExternalFunctionName(addr); } - long dataTypeID = sym.getSymbolData1(); + long dataTypeID = sym.getDataTypeId(); DataType dt = (dataTypeID < 0) ? null : sym.getProgram().getDataTypeManager().getDataType(dataTypeID); return SymbolUtilities.getDefaultExternalName(addr, dt); @@ -695,7 +695,7 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager { private Library addExternalName(String name, String pathname, SourceType source) throws DuplicateNameException, InvalidInputException { SymbolDB s = symbolMgr.createSpecialSymbol(Address.NO_ADDRESS, name, - scopeMgr.getGlobalNamespace(), SymbolType.LIBRARY, -1, 0, pathname, source); // 0 set first id for external names + scopeMgr.getGlobalNamespace(), SymbolType.LIBRARY, null, null, pathname, source); return (Library) s.getObject(); } @@ -742,7 +742,7 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager { public String getExternalLibraryPath(String externalName) { SymbolDB s = (SymbolDB) symbolMgr.getLibrarySymbol(externalName); if (s instanceof LibrarySymbol) { - return s.getSymbolData3(); + return s.getSymbolStringData(); } return null; } @@ -771,7 +771,7 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager { } } else if (s instanceof LibrarySymbol) { - s.setSymbolData3(externalPath); + s.setSymbolStringData(externalPath); } } finally { @@ -802,7 +802,7 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager { return null; } //long dtId = symbol.getSymbolData1(); - String extData3 = symbol.getSymbolData3(); + String extData = symbol.getSymbolStringData(); String name = symbol.getName(); Namespace namespace = symbol.getParentNamespace(); Address extAddr = symbol.getAddress(); @@ -810,7 +810,7 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager { ((CodeSymbol) symbol).delete(true); - return functionMgr.createExternalFunction(extAddr, name, namespace, extData3, source); + return functionMgr.createExternalFunction(extAddr, name, namespace, extData, source); } catch (Exception e) { e.printStackTrace(); @@ -927,8 +927,8 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager { while (externalSymbols.hasNext()) { monitor.checkCanceled(); SymbolDB s = (SymbolDB) externalSymbols.next(); - ExternalData3 externalData3 = ExternalLocationDB.getExternalData3(s); - String addrStr = externalData3.getAddressString(); + ExternalData externalData = ExternalLocationDB.getExternalData(s); + String addrStr = externalData.getAddressString(); if (addrStr == null) { continue; } @@ -947,7 +947,7 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager { addr = newAddressSpace.getAddress(addr.getOffset()); String newAddrStr = addr.toString(); if (!newAddrStr.equals(addrStr)) { - ExternalLocationDB.updateSymbolData3(s, externalData3.getOriginalImportedName(), + ExternalLocationDB.updateSymbolData(s, externalData.getOriginalImportedName(), newAddrStr); // store translated external location address } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionDB.java index 9eaffd17e2..72b1583da7 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionDB.java @@ -990,7 +990,7 @@ public class FunctionDB extends DatabaseObject implements Function { symbolMap.put(v.symbol, v); } if (var.getComment() != null) { - v.symbol.setSymbolData3(var.getComment()); + v.symbol.setSymbolStringData(var.getComment()); } manager.functionChanged(this, 0); return v; @@ -1678,7 +1678,7 @@ public class FunctionDB extends DatabaseObject implements Function { manager.functionChanged(this, ChangeManager.FUNCTION_CHANGED_PARAMETERS); } if (var.getComment() != null) { - p.symbol.setSymbolData3(var.getComment()); + p.symbol.setSymbolStringData(var.getComment()); } updateSignatureSourceAfterVariableChange(source, p.getDataType()); return p; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionManagerDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionManagerDB.java index 6a4da88407..bdee0c1002 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionManagerDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionManagerDB.java @@ -273,22 +273,22 @@ public class FunctionManagerDB implements FunctionManager { * Transform an existing external symbol into an external function. * This method should only be invoked by an ExternalSymbol * @param extSpaceAddr the external space address to use when creating this external. - * @param name - * @param nameSpace - * @param extData3 internal symbol-data-3 string (see {@link ExternalLocationDB}) + * @param name the external function name + * @param nameSpace the external function namespace + * @param extData the external data string to store additional info (see {@link ExternalLocationDB}) * @param source the source of this external. * @return external function - * @throws InvalidInputException - * @throws DuplicateNameException + * @throws InvalidInputException if the name is invalid + * @throws DuplicateNameException if the name is an invalid duplicate */ public Function createExternalFunction(Address extSpaceAddr, String name, Namespace nameSpace, - String extData3, SourceType source) + String extData, SourceType source) throws DuplicateNameException, InvalidInputException { lock.acquire(); try { Symbol symbol = symbolMgr.createSpecialSymbol(extSpaceAddr, name, nameSpace, - SymbolType.FUNCTION, -1, -1, extData3, source); + SymbolType.FUNCTION, null, null, extData, source); long returnDataTypeId = program.getDataTypeManager().getResolvedID(DataType.DEFAULT); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/VariableDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/VariableDB.java index 61e1662eea..10d90674e4 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/VariableDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/VariableDB.java @@ -167,12 +167,12 @@ public abstract class VariableDB implements Variable { @Override public String getComment() { - return symbol.getSymbolData3(); + return symbol.getSymbolStringData(); } @Override public void setComment(String comment) { - symbol.setSymbolData3(comment); + symbol.setSymbolStringData(comment); functionMgr.functionChanged(function, 0); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/AddressSetFilteredSymbolIterator.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/AddressSetFilteredSymbolIterator.java index e4c2068d19..6e78cfaea6 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/AddressSetFilteredSymbolIterator.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/AddressSetFilteredSymbolIterator.java @@ -20,26 +20,21 @@ import java.util.Iterator; import db.DBRecord; import db.RecordIterator; -import ghidra.program.database.util.Query; -import ghidra.program.database.util.QueryRecordIterator; -import ghidra.program.model.address.*; +import ghidra.program.database.util.*; +import ghidra.program.model.address.AddressSetView; import ghidra.program.model.symbol.Symbol; import ghidra.program.model.symbol.SymbolIterator; /** * - * Iterator (in address order) over primary symbols in an address set. + * Iterator (in address order) over all symbols that match the given query in an address set. * * */ class AddressSetFilteredSymbolIterator implements SymbolIterator { private SymbolManager symbolMgr; - private AddressRangeIterator rangeIter; private QueryRecordIterator recIter; - private Symbol currentSymbol; private SymbolDatabaseAdapter adapter; - private boolean forward; - private Query query; /** * Construct a new AddressSetFilteredSymbolIterator. @@ -51,53 +46,40 @@ class AddressSetFilteredSymbolIterator implements SymbolIterator { AddressSetFilteredSymbolIterator(SymbolManager symbolMgr, AddressSetView set, Query query, boolean forward) { this.symbolMgr = symbolMgr; - rangeIter = set.getAddressRanges(forward); adapter = symbolMgr.getDatabaseAdapter(); - this.forward = forward; - this.query = query; + try { + RecordIterator it = adapter.getSymbols(set, forward); + recIter = new QueryRecordIterator(it, query, forward); + } + catch (IOException e) { + symbolMgr.dbError(e); + recIter = new QueryRecordIterator(new EmptyRecordIterator(), query, forward); + } } @Override public boolean hasNext() { - if (currentSymbol == null) { - try { - findNext(); - } - catch (IOException e) { - symbolMgr.dbError(e); - } + try { + return recIter.hasNext(); } - return currentSymbol != null; + catch (IOException e) { + symbolMgr.dbError(e); + } + return false; } @Override public Symbol next() { if (hasNext()) { - Symbol s = currentSymbol; - currentSymbol = null; - return s; - } - return null; - } - - private void findNext() throws IOException { - if (recIter != null && recIter.hasNext()) { - DBRecord rec = recIter.next(); - currentSymbol = symbolMgr.getSymbol(rec); - } - else { - while (rangeIter.hasNext()) { - AddressRange range = rangeIter.next(); - RecordIterator it = - adapter.getSymbols(range.getMinAddress(), range.getMaxAddress(), forward); - recIter = new QueryRecordIterator(it, query, forward); - if (recIter.hasNext()) { - DBRecord rec = recIter.next(); - currentSymbol = symbolMgr.getSymbol(rec); - break; - } + try { + DBRecord rec = recIter.next(); + return symbolMgr.getSymbol(rec); + } + catch (IOException e) { + symbolMgr.dbError(e); } } + return null; } @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/CodeSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/CodeSymbol.java index 7e546f831e..8b56aa1733 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/CodeSymbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/CodeSymbol.java @@ -30,10 +30,7 @@ import ghidra.program.util.ProgramLocation; * * Symbol data usage: * EXTERNAL: - * long data1 - external data type - * String data3 - external memory address - * NON-EXTERNAL: - * int data2 - primary flag + * String stringData - external memory address/label */ public class CodeSymbol extends SymbolDB { @@ -162,7 +159,7 @@ public class CodeSymbol extends SymbolDB { if (getSource() == SourceType.DEFAULT || isExternal()) { return true; } - return getSymbolData2() == 1; + return doCheckIsPrimary(); } /** @@ -201,7 +198,7 @@ public class CodeSymbol extends SymbolDB { } void setPrimary(boolean primary) { - setSymbolData2(primary ? 1 : 0); + doSetPrimary(primary); } /** diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/FunctionSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/FunctionSymbol.java index b227ff890a..1737333534 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/FunctionSymbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/FunctionSymbol.java @@ -39,10 +39,7 @@ import ghidra.util.task.TaskMonitor; * * Symbol Data Usage: * EXTERNAL: - * long data1 - external data type - * String data3 - external memory address - * NON-EXTERNAL: - * - not used - + * String stringData - external memory address/label */ public class FunctionSymbol extends SymbolDB { @@ -103,9 +100,9 @@ public class FunctionSymbol extends SymbolDB { try { boolean restoreLabel = isExternal() || (getSource() != SourceType.DEFAULT); String symName = getName(); - String extData3 = null; + String extData = null; if (isExternal()) { - extData3 = getSymbolData3(); // preserve external data + extData = getSymbolStringData(); // preserve external data } Namespace namespace = getParentNamespace(); SourceType source = getSource(); @@ -120,7 +117,7 @@ public class FunctionSymbol extends SymbolDB { if (super.delete()) { if (restoreLabel) { - boolean restored = createLabelForDeletedFunctionName(address, symName, extData3, + boolean restored = createLabelForDeletedFunctionName(address, symName, extData, namespace, source, pinned); if (!restored && isExternal()) { removeAllReferencesTo(); @@ -140,7 +137,7 @@ public class FunctionSymbol extends SymbolDB { * does not mean that we want to lose the function name (that is our policy). */ private boolean createLabelForDeletedFunctionName(Address entryPoint, String symName, - String data3, Namespace namespace, SourceType source, boolean pinned) { + String stringData, Namespace namespace, SourceType source, boolean pinned) { if (isExternal()) { SymbolDB parent = (SymbolDB) namespace.getSymbol(); if (parent.isDeleting()) { @@ -151,7 +148,7 @@ public class FunctionSymbol extends SymbolDB { SymbolDB newSym; try { newSym = symbolMgr.createSpecialSymbol(entryPoint, symName, namespace, - SymbolType.LABEL, -1, -1, data3, source); + SymbolType.LABEL, null, null, stringData, source); if (pinned) { newSym.setPinned(true); } @@ -161,7 +158,7 @@ public class FunctionSymbol extends SymbolDB { newSym = (SymbolDB) symbolMgr.createLabel(entryPoint, symName, program.getGlobalNamespace(), source); } - newSym.setSymbolData3(data3); // reserved for external location use + newSym.setSymbolStringData(stringData); newSym.setPrimary(); return true; } @@ -275,56 +272,11 @@ public class FunctionSymbol extends SymbolDB { return super.doGetParentNamespace(); } -// @Override -// public void setNameAndNamespace(String newName, Namespace newNamespace, SourceType source) -// throws DuplicateNameException, InvalidInputException, CircularDependencyException { -// -// if (!isExternal()) { -// -// // Check thunk function name - if name matches thunked function -// // name switch to using DEFAULT name -// -// // NOTE: Removed this since this prevents having a second symbol -// -// Symbol thunkedSymbol = getThunkedSymbol(); -// if (thunkedSymbol != null) { -// String thunkedName = thunkedSymbol.getName(); -// if (thunkedName.equals(newName)) { -// newName = ""; -// source = SourceType.DEFAULT; -// } -// } -// } -// -// super.setNameAndNamespace(newName, newNamespace, source); -// } - private Symbol getThunkedSymbol() { long thunkedFunctionId = functionMgr.getThunkedFunctionId(key); return (thunkedFunctionId >= 0) ? symbolMgr.getSymbol(thunkedFunctionId) : null; } -// @Override -// public void setNameAndNamespace(String newName, Namespace newNamespace, SourceType source) -// throws DuplicateNameException, InvalidInputException, CircularDependencyException { -// -// long thunkedFunctionId = functionMgr.getThunkedFunctionId(key); -// if (thunkedFunctionId >= 0) { -// if (!newName.startsWith(Function.THUNK_PREFIX)) { -// // ignore -// return; -// } -// // rename thunked function based on thunk name specified -// Symbol s = symbolMgr.getSymbol(thunkedFunctionId); -// if (s != null) { -// s.setName(newName.substring(Function.THUNK_PREFIX.length()), source); -// } -// return; -// } -// -// super.setNameAndNamespace(newName, newNamespace, source); -// } - @Override protected SourceType validateNameSource(String newName, SourceType source) { // if (isThunk()) { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/LibraryDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/LibraryDB.java index 825ad182c7..65afcc3e1e 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/LibraryDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/LibraryDB.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -109,7 +108,7 @@ class LibraryDB implements Library { @Override public String getAssociatedProgramPath() { - return symbol.getSymbolData3(); + return symbol.getSymbolStringData(); } @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/LibrarySymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/LibrarySymbol.java index 3e76380be1..506b1c885c 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/LibrarySymbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/LibrarySymbol.java @@ -31,8 +31,7 @@ import ghidra.util.exception.InvalidInputException; * Class for library symbols. * * Symbol data usage: - * int data2 - set to 0 (not used) - * String data3 - associated program project file path + * String stringData - associated program project file path */ public class LibrarySymbol extends SymbolDB { @@ -64,8 +63,9 @@ public class LibrarySymbol extends SymbolDB { super.setName(newName, source); if (!oldName.equals(getName())) { - symbolMgr.getProgram().setObjChanged(ChangeManager.DOCR_EXTERNAL_NAME_CHANGED, - (Address) null, null, oldName, newName); + symbolMgr.getProgram() + .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); if (!oldName.equals(getName())) { - symbolMgr.getProgram().setObjChanged(ChangeManager.DOCR_EXTERNAL_NAME_CHANGED, - (Address) null, null, oldName, newName); + symbolMgr.getProgram() + .setObjChanged(ChangeManager.DOCR_EXTERNAL_NAME_CHANGED, + (Address) null, null, oldName, newName); } } @Override - public void setSymbolData3(String newPath) { - String oldPath = getSymbolData3(); + public void setSymbolStringData(String newPath) { + String oldPath = getSymbolStringData(); - super.setSymbolData3(newPath); + super.setSymbolStringData(newPath); - symbolMgr.getProgram().setObjChanged(ChangeManager.DOCR_EXTERNAL_PATH_CHANGED, getName(), - oldPath, newPath); + symbolMgr.getProgram() + .setObjChanged(ChangeManager.DOCR_EXTERNAL_PATH_CHANGED, getName(), + oldPath, newPath); } public SymbolType getSymbolType() { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDB.java index e8a3ff8aa5..a53e3cea87 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDB.java @@ -16,10 +16,10 @@ package ghidra.program.database.symbol; import java.io.IOException; -import java.util.ArrayList; -import java.util.List; +import java.util.*; import db.DBRecord; +import db.Field; import ghidra.program.database.*; import ghidra.program.database.external.ExternalLocationDB; import ghidra.program.database.external.ExternalManagerDB; @@ -141,21 +141,25 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol { * @param newAddress the new address for the symbol * @param newName the new name for the symbol (or null if the name should stay the same) * @param newNamespace the new namespace for the symbol (or null if it should stay the same) - * @param newSource + * @param newSource the new SourceType for the symbol (or null if it should stay the same) + * @param pinned the new pinned state */ protected void moveLowLevel(Address newAddress, String newName, Namespace newNamespace, SourceType newSource, boolean pinned) { lock.acquire(); try { checkDeleted(); - Address oldAddress = address; - record.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL, - symbolMgr.getAddressMap().getKey(newAddress, true)); + + // update the address to the new location + long newAddressKey = symbolMgr.getAddressMap().getKey(newAddress, true); + record.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL, newAddressKey); + + // if the primary field is set, be sure to update it to the new address as well + if (record.getFieldValue(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL) != null) { + record.setLongValue(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL, newAddressKey); + } if (newName != null) { record.setString(SymbolDatabaseAdapter.SYMBOL_NAME_COL, newName); - if (newName.length() == 0) { - setSourceFlagBit(SourceType.DEFAULT); - } } if (newNamespace != null) { record.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL, newNamespace.getID()); @@ -793,32 +797,42 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol { } } - public String getSymbolData3() { + /** + * Returns the symbol's string data which has different meanings depending on the symbol type + * and whether or not it is external + * @return the symbol's string data + */ + public String getSymbolStringData() { lock.acquire(); try { checkIsValid(); if (record == null) { return null; } - return record.getString(SymbolDatabaseAdapter.SYMBOL_DATA3_COL); + return record.getString(SymbolDatabaseAdapter.SYMBOL_STRING_DATA_COL); } finally { lock.release(); } } - public void setSymbolData3(String data3) { + /** + * Sets the symbol's string data field. This field's data has different uses depending on the + * symbol type and whether or not it is external. + * @param stringData the string to store in the string data field + */ + public void setSymbolStringData(String stringData) { lock.acquire(); try { checkDeleted(); if (record == null) { return; } - String oldData = record.getString(SymbolDatabaseAdapter.SYMBOL_DATA3_COL); - if (SystemUtilities.isEqual(data3, oldData)) { + String oldData = record.getString(SymbolDatabaseAdapter.SYMBOL_STRING_DATA_COL); + if (Objects.equals(stringData, oldData)) { return; } - record.setString(SymbolDatabaseAdapter.SYMBOL_DATA3_COL, data3); + record.setString(SymbolDatabaseAdapter.SYMBOL_STRING_DATA_COL, stringData); updateRecord(); symbolMgr.symbolDataChanged(this); } @@ -836,14 +850,18 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol { } } - public long getSymbolData1() { + public long getDataTypeId() { lock.acquire(); try { checkIsValid(); if (record != null) { - return record.getLongValue(SymbolDatabaseAdapter.SYMBOL_DATA1_COL); + Field value = record.getFieldValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL); + if (value.isNull()) { + return -1; + } + return value.getLongValue(); } - return 0; + return -1; } finally { lock.release(); @@ -854,12 +872,12 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol { * Sets the generic symbol data 1. * @param value the value to set as symbol data 1. */ - public void setSymbolData1(long value) { + public void setDataTypeId(long value) { lock.acquire(); try { checkDeleted(); if (record != null) { - record.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATA1_COL, value); + record.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL, value); updateRecord(); symbolMgr.symbolDataChanged(this); } @@ -873,12 +891,12 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol { * gets the generic symbol data 2 data. * @return the symbol data */ - public int getSymbolData2() { + protected int getVariableOffset() { lock.acquire(); try { checkIsValid(); if (record != null) { - return record.getIntValue(SymbolDatabaseAdapter.SYMBOL_DATA2_COL); + return record.getIntValue(SymbolDatabaseAdapter.SYMBOL_VAROFFSET_COL); } return 0; } @@ -888,15 +906,16 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol { } /** - * Sets the generic symbol data 2 data - * @param value the value to set as the symbols data 2 value. + * Sets the symbol's variable offset. For parameters, this is the ordinal, for locals, it is + * the first use offset + * @param offset the value to set as the symbols variable offset. */ - public void setSymbolData2(int value) { + public void setVariableOffset(int offset) { lock.acquire(); try { checkDeleted(); if (record != null) { - record.setIntValue(SymbolDatabaseAdapter.SYMBOL_DATA2_COL, value); + record.setIntValue(SymbolDatabaseAdapter.SYMBOL_VAROFFSET_COL, offset); updateRecord(); symbolMgr.symbolDataChanged(this); } @@ -906,6 +925,42 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol { } } + protected void doSetPrimary(boolean primary) { + lock.acquire(); + try { + checkDeleted(); + if (record != null) { + if (primary) { + long addrKey = record.getLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL); + record.setLongValue(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL, addrKey); + } + else { + record.setField(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL, null); + } + updateRecord(); + symbolMgr.symbolDataChanged(this); + } + } + finally { + lock.release(); + } + + } + + protected boolean doCheckIsPrimary() { + lock.acquire(); + try { + checkIsValid(); + if (record != null) { + return !record.getFieldValue(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL).isNull(); + } + return false; + } + finally { + lock.release(); + } + } + @Override public boolean delete() { lock.acquire(); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDatabaseAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDatabaseAdapter.java index 621326f352..f64799b909 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDatabaseAdapter.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDatabaseAdapter.java @@ -16,14 +16,16 @@ package ghidra.program.database.symbol; import java.io.IOException; +import java.util.Objects; import java.util.Set; +import org.apache.commons.lang3.StringUtils; + import db.*; import ghidra.program.database.map.AddressMap; -import ghidra.program.model.address.Address; -import ghidra.program.model.address.AddressSpace; -import ghidra.program.model.symbol.SourceType; -import ghidra.program.model.symbol.SymbolType; +import ghidra.program.database.util.*; +import ghidra.program.model.address.*; +import ghidra.program.model.symbol.*; import ghidra.util.exception.CancelledException; import ghidra.util.exception.VersionException; import ghidra.util.task.TaskMonitor; @@ -32,24 +34,23 @@ import ghidra.util.task.TaskMonitor; * Adapter to access records in the symbol table. */ abstract class SymbolDatabaseAdapter { - static final String SYMBOL_TABLE_NAME = "Symbols"; - static final Schema SYMBOL_SCHEMA = new Schema(2, "Key", - new Field[] { StringField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE, - ByteField.INSTANCE, LongField.INSTANCE, IntField.INSTANCE, StringField.INSTANCE, - ByteField.INSTANCE }, - new String[] { "Name", "Address", "Parent", "Symbol Type", "SymbolData1", "SymbolData2", - "SymbolData3", "Flags" }); - static final int SYMBOL_NAME_COL = 0; static final int SYMBOL_ADDR_COL = 1; static final int SYMBOL_PARENT_COL = 2; static final int SYMBOL_TYPE_COL = 3; - static final int SYMBOL_DATA1_COL = 4; - static final int SYMBOL_DATA2_COL = 5; - static final int SYMBOL_DATA3_COL = 6; - static final int SYMBOL_FLAGS_COL = 7; + static final int SYMBOL_STRING_DATA_COL = 4; + static final int SYMBOL_FLAGS_COL = 5; + + // sparse fields - the following fields are not always applicable so they are optional and + // don't consume space in the database if they aren't used. + static final int SYMBOL_HASH_COL = 6; + static final int SYMBOL_PRIMARY_COL = 7; + static final int SYMBOL_DATATYPE_COL = 8; + static final int SYMBOL_VAROFFSET_COL = 9; + + static final Schema SYMBOL_SCHEMA = SymbolDatabaseAdapterV3.V3_SYMBOL_SCHEMA; // Bits 0 & 1 are used for the source of the symbol. static final byte SYMBOL_SOURCE_BITS = (byte) 0x3; @@ -59,26 +60,24 @@ abstract class SymbolDatabaseAdapter { /** * Gets a new SymbolDatabaseAdapter - * @param dbHandle the database handle. - * @param openMode the openmode + * @param dbHandle the database handle + * @param openMode the open mode. See {@link DBConstants} * @param addrMap the address map - * @param monitor the progress monitor. - * @throws VersionException if the database table does not match the adapter. - * @throws CancelledException if the user cancels an upgrade. - * @throws IOException if a database io error occurs. + * @param monitor the progress monitor + * @return a new SymbolDatabaseAdapter + * @throws VersionException if the database table does not match the adapter + * @throws CancelledException if the user cancels an upgrade + * @throws IOException if a database io error occurs */ static SymbolDatabaseAdapter getAdapter(DBHandle dbHandle, int openMode, AddressMap addrMap, TaskMonitor monitor) throws VersionException, CancelledException, IOException { if (openMode == DBConstants.CREATE) { - return new SymbolDatabaseAdapterV2(dbHandle, addrMap, true); + return new SymbolDatabaseAdapterV3(dbHandle, addrMap, true); } try { - SymbolDatabaseAdapter adapter = new SymbolDatabaseAdapterV2(dbHandle, addrMap, false); - if (addrMap.isUpgraded()) { - throw new VersionException(true); - } + SymbolDatabaseAdapter adapter = new SymbolDatabaseAdapterV3(dbHandle, addrMap, false); return adapter; } catch (VersionException e) { @@ -87,7 +86,7 @@ abstract class SymbolDatabaseAdapter { } SymbolDatabaseAdapter adapter = findReadOnlyAdapter(dbHandle, addrMap); if (openMode == DBConstants.UPGRADE) { - adapter = SymbolDatabaseAdapterV2.upgrade(dbHandle, addrMap, adapter, monitor); + adapter = upgrade(dbHandle, addrMap, adapter, monitor); } else if (adapter instanceof SymbolDatabaseAdapterV0) { // Upgrade required - read-only use not supported @@ -101,39 +100,125 @@ abstract class SymbolDatabaseAdapter { throws VersionException, IOException { try { - return new SymbolDatabaseAdapterV2(handle, addrMap.getOldAddressMap(), false); + return new SymbolDatabaseAdapterV2(handle, addrMap.getOldAddressMap()); } catch (VersionException e1) { + // failed try older version } try { return new SymbolDatabaseAdapterV1(handle, addrMap.getOldAddressMap()); } catch (VersionException e1) { + // failed try older version } - return new SymbolDatabaseAdapterV0(handle, addrMap); + try { + return new SymbolDatabaseAdapterV0(handle, addrMap.getOldAddressMap()); + } + catch (VersionException e1) { + // failed - can't handle whatever version this is trying to open + } + + throw new VersionException(false); + } + + static SymbolDatabaseAdapter upgrade(DBHandle dbHandle, AddressMap addrMap, + SymbolDatabaseAdapter oldAdapter, TaskMonitor monitor) + throws VersionException, IOException, CancelledException { + + monitor.setMessage("Upgrading Symbol Table..."); + monitor.initialize(oldAdapter.getSymbolCount() * 2); + + DBHandle tmpHandle = dbHandle.getScratchPad(); + + try { + SymbolDatabaseAdapter tmpAdapter = + copyToTempAndFixupRecords(addrMap, oldAdapter, tmpHandle, monitor); + + dbHandle.deleteTable(SYMBOL_TABLE_NAME); + + SymbolDatabaseAdapter newAdapter = + new SymbolDatabaseAdapterV3(dbHandle, addrMap, true); + + copyTempToNewAdapter(tmpAdapter, newAdapter, monitor); + return newAdapter; + } + finally { + tmpHandle.deleteTable(SYMBOL_TABLE_NAME); + } + } + + private static SymbolDatabaseAdapter copyToTempAndFixupRecords(AddressMap addrMap, + SymbolDatabaseAdapter oldAdapter, DBHandle tmpHandle, TaskMonitor monitor) + throws IOException, CancelledException, VersionException { + + AddressMap oldAddrMap = addrMap.getOldAddressMap(); + + long nextKey = 1; // only used for V0 upgrade if a record with key 0 is encountered + if (oldAdapter instanceof SymbolDatabaseAdapterV0) { + // V0 is so old that there is not enough info in the current record to create new + // records. So store the current info in a temp database table and complete the upgrade + // when SymbolManager.programReady() is called. The missing info can be retrieved from + // other managers in the program at that point. + nextKey = + ((SymbolDatabaseAdapterV0) oldAdapter).extractLocalSymbols(tmpHandle, monitor); + } + + SymbolDatabaseAdapterV3 tmpAdapter = new SymbolDatabaseAdapterV3(tmpHandle, addrMap, true); + RecordIterator iter = oldAdapter.getSymbols(); + while (iter.hasNext()) { + monitor.checkCanceled(); + DBRecord rec = iter.next(); + Address addr = oldAddrMap.decodeAddress(rec.getLongValue(SYMBOL_ADDR_COL)); + rec.setLongValue(SYMBOL_ADDR_COL, addrMap.getKey(addr, true)); + + // We don't allow 0 keys starting with V1, set its key to next available + // which we got from the call to extractLocalSymbols() above + if (rec.getKey() == 0) { + rec.setKey(Math.max(1, nextKey)); + } + + tmpAdapter.updateSymbolRecord(rec); + monitor.incrementProgress(1); + } + + return tmpAdapter; + } + + private static void copyTempToNewAdapter(SymbolDatabaseAdapter tmpAdapter, + SymbolDatabaseAdapter newAdapter, TaskMonitor monitor) + throws IOException, CancelledException { + + RecordIterator iter = tmpAdapter.getSymbols(); + while (iter.hasNext()) { + monitor.checkCanceled(); + newAdapter.updateSymbolRecord(iter.next()); + monitor.incrementProgress(1); + } } /** * Create a new symbol * @param name name of the symbol - * @param addr address of the symbol - * @param parentSymbolID the id of the containing namespace symbol + * @param address the address for the symbol + * @param namespaceID the id of the containing namespace symbol * @param symbolType the type of this symbol - * @param data1 place to store a long value that depends on the symbol type - * @param data2 place to store an int value that depends on the symbol type - * @param data3 place to store a String value that depends on the symbol type - * @param source the source of this symbol - *
Some symbol types, such as function symbols, can set the source to Symbol.DEFAULT. + * @param stringData place to store a String value that depends on the symbol type + * @param source the source type of this symbol + * Some symbol types, such as function symbols, can set the source to Symbol.DEFAULT + * @param dataTypeId the id of an associated datatype or null if there is no associated datatype + * @param varOffset the variable offset will be the ordinal for a parameter or first use offset + * for a local variable + * @param isPrimary true if the symbol is primary. Only applicable for labels and functions * @return the new record * @throws IOException if there was a problem accessing the database * @throws IllegalArgumentException if you try to set the source to DEFAULT for a symbol type - * that doesn't allow it. + * that doesn't allow it */ - abstract DBRecord createSymbol(String name, Address address, long parentSymbolID, - SymbolType symbolType, long data1, int data2, String data3, SourceType source) - throws IOException; + abstract DBRecord createSymbol(String name, Address address, long namespaceID, + SymbolType symbolType, String stringData, Long dataTypeId, Integer varOffset, + SourceType source, boolean isPrimary) throws IOException; /** * Get the record with the given symbol ID @@ -160,58 +245,96 @@ abstract class SymbolDatabaseAdapter { abstract boolean hasSymbol(Address addr) throws IOException; /** - * Get the symbolIDs at the given address. + * Get the symbolIDs at the given address * @param addr address to filter on - * @return array of database LongField keys contained within a Field array. + * @return array of database LongField keys contained within a Field array * @throws IOException if there was a problem accessing the database */ abstract Field[] getSymbolIDs(Address addr) throws IOException; /** - * Get the number of symbols. + * Get the number of symbols + * @return the number of symbols */ abstract int getSymbolCount(); /** - * Get an iterator over all the symbols in ascending address order. - * @return + * Get an iterator over all the symbols in ascending address order + * @param forward the direction to iterator + * @return a record iterator over all symbols * @throws IOException if there was a problem accessing the database */ abstract RecordIterator getSymbolsByAddress(boolean forward) throws IOException; /** - * Get an iterator over all the symbols starting at startAddr. + * Get an iterator over all the symbols starting at startAddr * @param startAddr start address of where to get symbols + * @param forward true to iterate from low to high addresses + * @return a record iterator over all symbols starting at the given start address * @throws IOException if there was a problem accessing the database */ abstract RecordIterator getSymbolsByAddress(Address startAddr, boolean forward) throws IOException; /** - * Update the table with the given record. - * @param record + * Update the table with the given record + * @param record the record to update in the database * @throws IOException if there was a problem accessing the database */ abstract void updateSymbolRecord(DBRecord record) throws IOException; /** * Get all of the symbols. + * @return a record iterator over all symbols * @throws IOException if there was a problem accessing the database */ abstract RecordIterator getSymbols() throws IOException; /** - * Get symbols in the given range. - * @throws IOException if there was a problem accessing the database + * Get symbols in the given range + * @param start the start address of the range + * @param end the last address of the range + * @param forward true if iterating from start to end, otherwise iterate from end to start + * @return a record iterator for all symbols in the range + * @throws IOException if a database io error occurs */ abstract RecordIterator getSymbols(Address start, Address end, boolean forward) throws IOException; + /** + * Get symbols in the given range + * @param set the set of addresses to iterate over + * @param forward true if iterating from start to end, otherwise iterate from end to start + * @return a record iterator for all symbols in the range + * @throws IOException if a database io error occurs + */ + abstract RecordIterator getSymbols(AddressSetView set, boolean forward) + throws IOException; + + /** + * Returns an iterator over the primary symbols in the given range + * @param set the address set to iterator over when getting primary symbol records + * @param forward true if iterating from start to end, otherwise iterate from end to start + * @return a record iterator for all symbols in the range + * @throws IOException if a database io error occurs + */ + abstract RecordIterator getPrimarySymbols(AddressSetView set, boolean forward) + throws IOException; + + /** + * Returns the symbol record for the primary symbol at the given address + * @param address the address to get its primary symbol record + * @return the primary symbol record at the given address or null if no label or function + * exists at that address + * @throws IOException if a database io error occurs + */ + abstract DBRecord getPrimarySymbol(Address address) throws IOException; + /** * Update the address in all records to reflect the movement of a symbol address. * @param oldAddr the original symbol address * @param newAddr the new symbol address - * @throws IOException + * @throws IOException if a database io error occurs */ abstract void moveAddress(Address oldAddr, Address newAddr) throws IOException; @@ -221,38 +344,125 @@ abstract class SymbolDatabaseAdapter { * @param endAddr maximum address in range * @param monitor progress monitor * @return returns the set of addresses where symbols where not deleted because they were anchored - * @throws CancelledException - * @throws IOException + * @throws CancelledException if the user cancels the operation + * @throws IOException if a database io error occurs */ abstract Set
deleteAddressRange(Address startAddr, Address endAddr, TaskMonitor monitor) throws CancelledException, IOException; /** * Get all symbols contained within the specified namespace - * @param id the namespace id. - * @return an iterator over all symbols in the given namespace. - * @throws IOException + * @param id the namespace id + * @return an iterator over all symbols in the given namespace + * @throws IOException if a database io error occurs */ abstract RecordIterator getSymbolsByNamespace(long id) throws IOException; /** - * Get symbols starting with the specified name in name order - * @param name name to start with. - * @return a record iterator over the symbols. - * @throws IOException if a database io error occurs. + * Get symbols that have the specified name + * @param name name to search + * @return a record iterator over the symbols with the given name + * @throws IOException if a database io error occurs */ abstract RecordIterator getSymbolsByName(String name) throws IOException; /** - * Returns the maximum symbol address within the specified address space. - * Intended for update use only. + * Get all symbols contained in the given {@link Namespace} that have the given name + * @param name the symbol name + * @param id the id of the parent namespace + * @return a record iterator all the symbols in the given namespace with the given name + * @throws IOException if a database io error occurs + */ + abstract RecordIterator getSymbolsByNameAndNamespace(String name, long id) throws IOException; + + /** + * Get the symbol Record with the given address, name, and namespace id or null if there is + * no match + * @param address the symbol address + * @param name the symbol name + * @param namespaceId the id of the parent namespace of the symbol + * @return a record that matches the address, name, and namespaceId or null if there is no match + * @throws IOException if a database io error occurs + */ + abstract DBRecord getSymbolRecord(Address address, String name, long namespaceId) + throws IOException; + + /** + * Returns the maximum symbol address within the specified address space + * Intended for update use only * @param space address space - * @return maximum symbol address within space or null if none are found. + * @return maximum symbol address within space or null if none are found + * @throws IOException if a database io error occurs */ abstract Address getMaxSymbolAddress(AddressSpace space) throws IOException; /** - * Returns the underlying symbol table (for upgrade use only). + * Returns the underlying symbol table (for upgrade use only) + * @return the database table for this adapter */ abstract Table getTable(); + + /** + * Computes a hash value for a symbol that facilitates fast lookups of symbols given + * a name, namespace, and address. The hash is formed so that it can also be used for fast + * lookups of all symbols that have the same name and namespace regardless of address. + * @param name the symbol name + * @param namespaceID the namespace id + * @param addressKey the encoded address + * @return a database Long field containing the computed hash + */ + protected static LongField computeLocatorHash(String name, long namespaceID, + long addressKey) { + // Default functions have no name, no point in storing a hash for those. + if (StringUtils.isEmpty(name)) { + return null; + } + + // store the name/namespace hash in upper 32 bits of the resulting hash and the + // addressKey's lower 32 bits in the lower 32 bits of the resulting hash + long nameNamespaceHash = Objects.hash(name, namespaceID); + long combinedHash = (nameNamespaceHash << 32) | (addressKey & 0xFFFFFFFFL); + return new LongField(combinedHash); + } + + // This wraps a record iterator to make sure it only returns records for symbols that match + // the given name and name space. + protected static RecordIterator getNameAndNamespaceFilterIterator(String name, + long namespaceId, RecordIterator it) { + Query nameQuery = new FieldMatchQuery(SYMBOL_NAME_COL, new StringField(name)); + Query namespaceQuery = new FieldMatchQuery(SYMBOL_PARENT_COL, new LongField(namespaceId)); + Query nameAndNamespaceQuery = new AndQuery(nameQuery, namespaceQuery); + return new QueryRecordIterator(it, nameAndNamespaceQuery); + } + + /** + * Wraps a record iterator to make sure it only returns records for symbols that match + * the given name and name space and address + * @param name the name of the symbol + * @param namespaceId the name space id of the symbol + * @param addressKey the address key of the symbol + * @param it the record iterator to wrap with the query + * @return a filtered RecordIterator that only returns records that match the name, name space, + * and address + */ + protected static RecordIterator getNameNamespaceAddressFilterIterator(String name, + long namespaceId, long addressKey, RecordIterator it) { + Query nameQuery = new FieldMatchQuery(SYMBOL_NAME_COL, new StringField(name)); + Query namespaceQuery = new FieldMatchQuery(SYMBOL_PARENT_COL, new LongField(namespaceId)); + Query addressQuery = new FieldMatchQuery(SYMBOL_ADDR_COL, new LongField(addressKey)); + Query nameAndNamespaceQuery = new AndQuery(nameQuery, namespaceQuery); + Query fullQuery = new AndQuery(nameAndNamespaceQuery, addressQuery); + return new QueryRecordIterator(it, fullQuery); + } + + /** + * Wraps a record iterator to filter out any symbols that are not primary + * @param it the record iterator to wrap + * @return a record iterator that only returns primary symbols + */ + protected static RecordIterator getPrimaryFilterRecordIterator(RecordIterator it) { + Query query = record -> !record.getFieldValue(SYMBOL_PRIMARY_COL).isNull(); + return new QueryRecordIterator(it, query); + } + } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDatabaseAdapterV0.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDatabaseAdapterV0.java index 4fb38fcbcc..f5826bfad5 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDatabaseAdapterV0.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDatabaseAdapterV0.java @@ -21,8 +21,7 @@ import java.util.Set; import db.*; import ghidra.program.database.map.AddressIndexPrimaryKeyIterator; import ghidra.program.database.map.AddressMap; -import ghidra.program.model.address.Address; -import ghidra.program.model.address.AddressSpace; +import ghidra.program.model.address.*; import ghidra.program.model.symbol.*; import ghidra.util.exception.*; import ghidra.util.task.TaskMonitor; @@ -58,13 +57,10 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter { private AddressMap addrMap; /** - * Construct a Version-0 Symbol Table adadpter. + * Construct a Version-0 Symbol Table adapter. * @param handle the database handle. * @param addrMap the address map - * @param namespaceMgr namespace manager which already contains function namespaces * @throws VersionException if the database version doesn't match this adapter. - * @throws IOException if a database io error occurs. - * @throws CancelledException if the user cancels the upgrade. */ SymbolDatabaseAdapterV0(DBHandle handle, AddressMap addrMap) throws VersionException { this.addrMap = addrMap.getOldAddressMap(); @@ -77,10 +73,22 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter { } } + /** + * Stores local symbols information in a temporary database table because this version + * is so old, we don't have enough information in the record to upgrade during the normal + * upgrade time. So we store off the information and will complete this upgrade when + * {@link SymbolManager#programReady(int, int, TaskMonitor)} is called + * + * @param handle handle to temporary database + * @param monitor the {@link TaskMonitor} + * @return the next available database key after all the records are store + * @throws IOException if a database I/O error occurs + * @throws CancelledException if the user cancels the upgrade + */ long extractLocalSymbols(DBHandle handle, TaskMonitor monitor) throws IOException, CancelledException { - monitor.setMessage("Extracting Local and Dynamic Symbols..."); + monitor.setMessage("Extracting Local Symbols..."); monitor.initialize(symbolTable.getRecordCount()); int cnt = 0; RecordIterator iter = symbolTable.iterator(); @@ -106,22 +114,36 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter { throw new AssertException("Unexpected Symbol"); } DBRecord rec = SymbolDatabaseAdapter.SYMBOL_SCHEMA.createRecord(record.getKey()); - rec.setString(SymbolDatabaseAdapter.SYMBOL_NAME_COL, record.getString(V0_SYMBOL_NAME_COL)); + + String symbolName = record.getString(V0_SYMBOL_NAME_COL); + rec.setString(SymbolDatabaseAdapter.SYMBOL_NAME_COL, symbolName); + long addressKey = record.getLongValue(V0_SYMBOL_ADDR_COL); rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL, - record.getLongValue(V0_SYMBOL_ADDR_COL)); - rec.setIntValue(SymbolDatabaseAdapter.SYMBOL_DATA2_COL, - record.getBooleanValue(V0_SYMBOL_PRIMARY_COL) ? 1 : 0); + addressKey); + + boolean isPrimary = record.getBooleanValue(V0_SYMBOL_PRIMARY_COL); + if (isPrimary) { + rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL, addressKey); + } + rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_TYPE_COL, SymbolType.LABEL.getID()); - rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATA1_COL, -1); // not applicable - rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL, Namespace.GLOBAL_NAMESPACE_ID); + + long namespaceId = Namespace.GLOBAL_NAMESPACE_ID; + rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL, namespaceId); + rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL, (byte) SourceType.USER_DEFINED.ordinal()); + + Field hash = computeLocatorHash(symbolName, namespaceId, addressKey); + rec.setField(SymbolDatabaseAdapter.SYMBOL_HASH_COL, hash); + return rec; } @Override DBRecord createSymbol(String name, Address address, long namespaceID, SymbolType symbolType, - long data1, int data2, String data3, SourceType source) { + String stringData, Long dataTypeId, Integer varOffset, SourceType source, + boolean isPrimary) throws IOException { throw new UnsupportedOperationException(); } @@ -175,16 +197,37 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter { @Override RecordIterator getSymbols(Address start, Address end, boolean forward) throws IOException { - - if (!forward) - throw new UnsupportedOperationException(); -//TODO: Is there any reason we need to support reverse symbol iteration ??? - // Yes, to search text backwards! return new V0ConvertedRecordIterator( new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable, V0_SYMBOL_ADDR_COL, addrMap, start, end, forward))); } + @Override + RecordIterator getSymbols(AddressSetView set, boolean forward) throws IOException { + return new V0ConvertedRecordIterator( + new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable, + V0_SYMBOL_ADDR_COL, addrMap, set, forward))); + } + + @Override + RecordIterator getPrimarySymbols(AddressSetView set, boolean forward) + throws IOException { + KeyToRecordIterator it = + new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable, + SYMBOL_ADDR_COL, addrMap, set, forward)); + + return getPrimaryFilterRecordIterator(new V0ConvertedRecordIterator(it)); + } + + @Override + DBRecord getPrimarySymbol(Address address) throws IOException { + RecordIterator it = getPrimarySymbols(new AddressSet(address, address), true); + if (it.hasNext()) { + return it.next(); + } + return null; + } + @Override void moveAddress(Address oldAddr, Address newAddr) throws IOException { throw new UnsupportedOperationException(); @@ -219,8 +262,7 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter { /** * Construct a symbol filtered record iterator - * @param iter - * @param locals if true + * @param symIter the {@link RecordIterator} to wrap so that records are adapter to new schema */ V0ConvertedRecordIterator(RecordIterator symIter) { this.symIter = symIter; @@ -277,4 +319,23 @@ class SymbolDatabaseAdapterV0 extends SymbolDatabaseAdapter { throw new UnsupportedOperationException(); } + @Override + RecordIterator getSymbolsByNameAndNamespace(String name, long id) throws IOException { + RecordIterator symbolsByName = getSymbolsByName(name); + return getNameAndNamespaceFilterIterator(name, id, symbolsByName); + } + + @Override + DBRecord getSymbolRecord(Address address, String name, long id) throws IOException { + StringField value = new StringField(name); + RecordIterator it = symbolTable.indexIterator(SYMBOL_NAME_COL, value, value, true); + long addressKey = addrMap.getKey(address, false); + RecordIterator filtered = + getNameNamespaceAddressFilterIterator(name, id, addressKey, it); + if (filtered.hasNext()) { + return filtered.next(); + } + return null; + } + } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDatabaseAdapterV1.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDatabaseAdapterV1.java index d40944165b..25ad0d7ccd 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDatabaseAdapterV1.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDatabaseAdapterV1.java @@ -21,8 +21,7 @@ import java.util.Set; import db.*; import ghidra.program.database.map.AddressIndexPrimaryKeyIterator; import ghidra.program.database.map.AddressMap; -import ghidra.program.model.address.Address; -import ghidra.program.model.address.AddressSpace; +import ghidra.program.model.address.*; import ghidra.program.model.symbol.*; import ghidra.util.exception.CancelledException; import ghidra.util.exception.VersionException; @@ -72,7 +71,8 @@ class SymbolDatabaseAdapterV1 extends SymbolDatabaseAdapter { @Override DBRecord createSymbol(String name, Address address, long namespaceID, SymbolType symbolType, - long data1, int data2, String data3, SourceType source) { + String stringData, Long dataTypeId, Integer varOffset, SourceType source, + boolean isPrimary) throws IOException { throw new UnsupportedOperationException(); } @@ -116,20 +116,21 @@ class SymbolDatabaseAdapterV1 extends SymbolDatabaseAdapter { DBRecord rec = SymbolDatabaseAdapter.SYMBOL_SCHEMA.createRecord(record.getKey()); String symbolName = record.getString(V1_SYMBOL_NAME_COL); rec.setString(SymbolDatabaseAdapter.SYMBOL_NAME_COL, symbolName); + long symbolAddrKey = record.getLongValue(V1_SYMBOL_ADDR_COL); rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL, symbolAddrKey); - rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL, - record.getLongValue(V1_SYMBOL_PARENT_COL)); - byte symbolType = record.getByteValue(V1_SYMBOL_TYPE_COL); - rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_TYPE_COL, symbolType); - rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATA1_COL, - record.getLongValue(V1_SYMBOL_DATA1_COL)); - rec.setIntValue(SymbolDatabaseAdapter.SYMBOL_DATA2_COL, - record.getIntValue(V1_SYMBOL_DATA2_COL)); - rec.setString(SymbolDatabaseAdapter.SYMBOL_DATA3_COL, + + long namespaceId = record.getLongValue(V1_SYMBOL_PARENT_COL); + rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL, namespaceId); + + byte symbolTypeId = record.getByteValue(V1_SYMBOL_TYPE_COL); + rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_TYPE_COL, symbolTypeId); + + rec.setString(SymbolDatabaseAdapter.SYMBOL_STRING_DATA_COL, record.getString(V1_SYMBOL_COMMENT_COL)); + SourceType source = SourceType.USER_DEFINED; - if (symbolType == SymbolType.FUNCTION.getID()) { + if (symbolTypeId == SymbolType.FUNCTION.getID()) { Address symbolAddress = addrMap.decodeAddress(symbolAddrKey); String defaultName = SymbolUtilities.getDefaultFunctionName(symbolAddress); if (symbolName.equals(defaultName)) { @@ -137,6 +138,33 @@ class SymbolDatabaseAdapterV1 extends SymbolDatabaseAdapter { } } rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL, (byte) source.ordinal()); + + long dataTypeId = record.getLongValue(V1_SYMBOL_DATA1_COL); + if (dataTypeId != -1) { + rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL, dataTypeId); + } + + SymbolType type = SymbolType.getSymbolType(symbolTypeId); + int data2 = record.getIntValue(V1_SYMBOL_DATA2_COL); + // The data1 field was used in two ways for label symbols, it stored a 1 for primary and 0 + // for non-primary. If the type was a parameter or variable, it stored the ordinal or + // first use offset respectively. + if (SymbolType.LABEL.equals(type)) { + if (data2 == 1) { // if it was primary, put the address in the indexed primary col + rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL, symbolAddrKey); + } + } + else if (SymbolType.PARAMETER.equals(type) || SymbolType.LOCAL_VAR.equals(type)) { + rec.setIntValue(SymbolDatabaseAdapter.SYMBOL_VAROFFSET_COL, data2); + } + + // also need to store primary for functions + if (SymbolType.FUNCTION.equals(type)) { + rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL, symbolAddrKey); + } + Field hash = computeLocatorHash(symbolName, namespaceId, symbolAddrKey); + rec.setField(SymbolDatabaseAdapter.SYMBOL_HASH_COL, hash); + return rec; } @@ -175,8 +203,30 @@ class SymbolDatabaseAdapterV1 extends SymbolDatabaseAdapter { V1_SYMBOL_ADDR_COL, addrMap, start, end, forward))); } - RecordIterator getSymbolsByName() throws IOException { - return new V1ConvertedRecordIterator(symbolTable.indexIterator(V1_SYMBOL_NAME_COL)); + @Override + RecordIterator getSymbols(AddressSetView set, boolean forward) throws IOException { + return new V1ConvertedRecordIterator( + new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable, + V1_SYMBOL_ADDR_COL, addrMap, set, forward))); + } + + @Override + RecordIterator getPrimarySymbols(AddressSetView set, boolean forward) + throws IOException { + KeyToRecordIterator it = + new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable, + SYMBOL_ADDR_COL, addrMap, set, forward)); + + return getPrimaryFilterRecordIterator(new V1ConvertedRecordIterator(it)); + } + + @Override + DBRecord getPrimarySymbol(Address address) throws IOException { + RecordIterator it = getPrimarySymbols(new AddressSet(address, address), true); + if (it.hasNext()) { + return it.next(); + } + return null; } @Override @@ -225,4 +275,23 @@ class SymbolDatabaseAdapterV1 extends SymbolDatabaseAdapter { Address getMaxSymbolAddress(AddressSpace space) throws IOException { throw new UnsupportedOperationException(); } + + @Override + RecordIterator getSymbolsByNameAndNamespace(String name, long id) throws IOException { + RecordIterator symbolsByName = getSymbolsByName(name); + return getNameAndNamespaceFilterIterator(name, id, symbolsByName); + } + + @Override + DBRecord getSymbolRecord(Address address, String name, long id) throws IOException { + RecordIterator it = getSymbolsByName(name); + long addressKey = addrMap.getKey(address, false); + RecordIterator filtered = + getNameNamespaceAddressFilterIterator(name, id, addressKey, it); + if (filtered.hasNext()) { + return filtered.next(); + } + return null; + } + } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDatabaseAdapterV2.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDatabaseAdapterV2.java index 748aec873a..e6f249b2c7 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDatabaseAdapterV2.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDatabaseAdapterV2.java @@ -22,10 +22,11 @@ import java.util.Set; import db.*; import ghidra.program.database.map.*; import ghidra.program.database.util.RecordFilter; -import ghidra.program.model.address.Address; -import ghidra.program.model.address.AddressSpace; -import ghidra.program.model.symbol.*; -import ghidra.util.exception.*; +import ghidra.program.model.address.*; +import ghidra.program.model.symbol.SourceType; +import ghidra.program.model.symbol.SymbolType; +import ghidra.util.exception.CancelledException; +import ghidra.util.exception.VersionException; import ghidra.util.task.TaskMonitor; /** @@ -33,185 +34,54 @@ import ghidra.util.task.TaskMonitor; */ class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter { +/* Do not remove the following commented out schema! It shows the version 2 symbol table schema. */ +// static final Schema SYMBOL_SCHEMA = new Schema(2, "Key", +// new Field[] { StringField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE, +// ByteField.INSTANCE, LongField.INSTANCE, IntField.INSTANCE, StringField.INSTANCE, +// ByteField.INSTANCE }, +// new String[] { "Name", "Address", "Parent", "Symbol Type", "SymbolData1", "SymbolData2", +// "SymbolData3", "Flags" }); + private static final int SYMBOL_VERSION = 2; private Table symbolTable; private AddressMap addrMap; - SymbolDatabaseAdapterV2(DBHandle handle, AddressMap addrMap, boolean create) - throws VersionException, IOException { + static final int V2_SYMBOL_NAME_COL = 0; + static final int V2_SYMBOL_ADDR_COL = 1; + static final int V2_SYMBOL_PARENT_COL = 2; + static final int V2_SYMBOL_TYPE_COL = 3; + static final int V2_SYMBOL_DATA1_COL = 4; + static final int V2_SYMBOL_DATA2_COL = 5; + static final int V2_SYMBOL_DATA3_COL = 6; + static final int V2_SYMBOL_FLAGS_COL = 7; + + SymbolDatabaseAdapterV2(DBHandle handle, AddressMap addrMap) + throws VersionException { this.addrMap = addrMap; - if (create) { - - symbolTable = handle.createTable(SYMBOL_TABLE_NAME, SYMBOL_SCHEMA, - new int[] { SYMBOL_ADDR_COL, SYMBOL_NAME_COL, SYMBOL_PARENT_COL }); + symbolTable = handle.getTable(SYMBOL_TABLE_NAME); + if (symbolTable == null) { + throw new VersionException("Missing Table: " + SYMBOL_TABLE_NAME); } - 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); - } - } - } - - 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); + 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, - long data1, int data2, String data3, SourceType source) throws IOException { - long nextID = symbolTable.getKey(); - - // avoiding key 0, because we use the negative of the address offset as keys for dynamic symbols - if (nextID == 0) { - nextID++; - } - return createSymbol(nextID, name, address, namespaceID, symbolType, data1, data2, data3, - (byte) source.ordinal()); - } - - private DBRecord createSymbol(long id, String name, Address address, long namespaceID, - SymbolType symbolType, long data1, int data2, String data3, byte flags) - throws IOException { - - DBRecord rec = symbolTable.getSchema().createRecord(id); - rec.setString(SYMBOL_NAME_COL, name); - rec.setLongValue(SYMBOL_ADDR_COL, addrMap.getKey(address, true)); - rec.setLongValue(SYMBOL_PARENT_COL, namespaceID); - rec.setByteValue(SYMBOL_TYPE_COL, symbolType.getID()); - rec.setLongValue(SYMBOL_DATA1_COL, data1); - rec.setIntValue(SYMBOL_DATA2_COL, data2); - rec.setString(SYMBOL_DATA3_COL, data3); - rec.setByteValue(SYMBOL_FLAGS_COL, flags); - symbolTable.putRecord(rec); - return rec; + String stringData, Long dataTypeId, Integer varOffset, SourceType source, + boolean isPrimary) throws IOException { + throw new UnsupportedOperationException(); } @Override void removeSymbol(long symbolID) throws IOException { - symbolTable.deleteRecord(symbolID); + throw new UnsupportedOperationException(); } @Override @@ -234,7 +104,7 @@ class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter { @Override DBRecord getSymbolRecord(long symbolID) throws IOException { - return symbolTable.getRecord(symbolID); + return convertV2Record(symbolTable.getRecord(symbolID)); } @Override @@ -244,30 +114,62 @@ class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter { @Override RecordIterator getSymbolsByAddress(boolean forward) throws IOException { - return new KeyToRecordIterator(symbolTable, + KeyToRecordIterator it = new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable, SYMBOL_ADDR_COL, addrMap, forward)); + return new V2ConvertedRecordIterator(it); } @Override RecordIterator getSymbolsByAddress(Address startAddr, boolean forward) throws IOException { - return new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable, - SYMBOL_ADDR_COL, addrMap, startAddr, forward)); + KeyToRecordIterator it = + new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable, + SYMBOL_ADDR_COL, addrMap, startAddr, forward)); + return new V2ConvertedRecordIterator(it); } @Override void updateSymbolRecord(DBRecord record) throws IOException { - symbolTable.putRecord(record); + throw new UnsupportedOperationException(); } @Override RecordIterator getSymbols() throws IOException { - return symbolTable.iterator(); + return new V2ConvertedRecordIterator(symbolTable.iterator()); } @Override RecordIterator getSymbols(Address start, Address end, boolean forward) throws IOException { - return new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable, - SYMBOL_ADDR_COL, addrMap, start, end, forward)); + KeyToRecordIterator it = + new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable, + SYMBOL_ADDR_COL, addrMap, start, end, forward)); + return new V2ConvertedRecordIterator(it); + } + + @Override + RecordIterator getSymbols(AddressSetView set, boolean forward) throws IOException { + KeyToRecordIterator it = + new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable, + SYMBOL_ADDR_COL, addrMap, set, forward)); + return new V2ConvertedRecordIterator(it); + } + + @Override + RecordIterator getPrimarySymbols(AddressSetView set, boolean forward) + throws IOException { + KeyToRecordIterator it = + new KeyToRecordIterator(symbolTable, new AddressIndexPrimaryKeyIterator(symbolTable, + SYMBOL_ADDR_COL, addrMap, set, forward)); + + return getPrimaryFilterRecordIterator(new V2ConvertedRecordIterator(it)); + } + + @Override + DBRecord getPrimarySymbol(Address address) throws IOException { + RecordIterator it = getPrimarySymbols(new AddressSet(address, address), true); + if (it.hasNext()) { + return it.next(); + } + return null; } @Override @@ -316,13 +218,15 @@ class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter { @Override RecordIterator getSymbolsByNamespace(long id) throws IOException { LongField field = new LongField(id); - return symbolTable.indexIterator(SYMBOL_PARENT_COL, field, field, true); + RecordIterator it = symbolTable.indexIterator(SYMBOL_PARENT_COL, field, field, true); + return new V2ConvertedRecordIterator(it); } @Override RecordIterator getSymbolsByName(String name) throws IOException { StringField field = new StringField(name); - return symbolTable.indexIterator(SYMBOL_NAME_COL, field, field, true); + RecordIterator it = symbolTable.indexIterator(SYMBOL_NAME_COL, field, field, true); + return new V2ConvertedRecordIterator(it); } @Override @@ -353,4 +257,97 @@ class SymbolDatabaseAdapterV2 extends SymbolDatabaseAdapter { Table getTable() { return symbolTable; } + + @Override + RecordIterator getSymbolsByNameAndNamespace(String name, long id) throws IOException { + StringField value = new StringField(name); + RecordIterator it = symbolTable.indexIterator(SYMBOL_NAME_COL, value, value, true); + RecordIterator filtered = getNameAndNamespaceFilterIterator(name, id, it); + return new V2ConvertedRecordIterator(filtered); + } + + @Override + DBRecord getSymbolRecord(Address address, String name, long id) throws IOException { + StringField value = new StringField(name); + RecordIterator it = symbolTable.indexIterator(SYMBOL_NAME_COL, value, value, true); + long addressKey = addrMap.getKey(address, false); + RecordIterator filtered = + getNameNamespaceAddressFilterIterator(name, id, addressKey, it); + if (filtered.hasNext()) { + return filtered.next(); + } + return null; + } + + /** + * Returns a record matching the current database schema from the version 2 record. + * @param record the record matching the version 2 schema. + * @return a current symbol record. + */ + private DBRecord convertV2Record(DBRecord record) { + if (record == null) { + return null; + } + DBRecord rec = SymbolDatabaseAdapter.SYMBOL_SCHEMA.createRecord(record.getKey()); + + String symbolName = record.getString(V2_SYMBOL_NAME_COL); + rec.setString(SymbolDatabaseAdapter.SYMBOL_NAME_COL, symbolName); + + long symbolAddrKey = record.getLongValue(V2_SYMBOL_ADDR_COL); + rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL, symbolAddrKey); + + long namespaceId = record.getLongValue(V2_SYMBOL_PARENT_COL); + rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL, namespaceId); + + byte symbolTypeId = record.getByteValue(V2_SYMBOL_TYPE_COL); + rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_TYPE_COL, symbolTypeId); + + rec.setString(SymbolDatabaseAdapter.SYMBOL_STRING_DATA_COL, + record.getString(V2_SYMBOL_DATA3_COL)); + + Field hash = computeLocatorHash(symbolName, namespaceId, symbolAddrKey); + rec.setField(SymbolDatabaseAdapter.SYMBOL_HASH_COL, hash); + + rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL, + record.getByteValue(V2_SYMBOL_FLAGS_COL)); + + long dataTypeId = record.getLongValue(V2_SYMBOL_DATA1_COL); + if (dataTypeId != -1) { + rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL, dataTypeId); + } + + SymbolType type = SymbolType.getSymbolType(symbolTypeId); + int data2 = record.getIntValue(V2_SYMBOL_DATA2_COL); + // The data1 field was used in two ways for label symbols, it stored a 1 for primary and 0 + // for non-primary. If the type was a parameter or variable, it stored the ordinal or + // first use offset respectively + if (SymbolType.LABEL.equals(type)) { + if (data2 == 1) { // if it was primary, put the address in the indexed primary col + rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL, symbolAddrKey); + } + } + else if (SymbolType.PARAMETER.equals(type) || SymbolType.LOCAL_VAR.equals(type)) { + rec.setIntValue(SymbolDatabaseAdapter.SYMBOL_VAROFFSET_COL, data2); + } + + // also need to store primary for functions + if (SymbolType.FUNCTION.equals(type)) { + rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL, symbolAddrKey); + } + + return rec; + } + + private class V2ConvertedRecordIterator extends ConvertedRecordIterator { + + V2ConvertedRecordIterator(RecordIterator originalIterator) { + super(originalIterator, false); + } + + @Override + protected DBRecord convertRecord(DBRecord record) { + return convertV2Record(record); + } + } + } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDatabaseAdapterV3.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDatabaseAdapterV3.java new file mode 100644 index 0000000000..633f622ae1 --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolDatabaseAdapterV3.java @@ -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
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
set = new HashSet
(); + + @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
getAddressesForSkippedRecords() { + return set; + } + } + +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolManager.java index 897233a3e9..a904d25e26 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolManager.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/SymbolManager.java @@ -73,7 +73,6 @@ public class SymbolManager implements SymbolTable, ManagerDB { private Lock lock; final static Symbol[] NO_SYMBOLS = new SymbolDB[0]; - private static final int MAX_DUPLICATE_COUNT = 10; /** * Creates a new Symbol manager. @@ -211,7 +210,6 @@ public class SymbolManager implements SymbolTable, ManagerDB { refMgr.moveReferencesTo(oldAddr, nextExtAddr, monitor); nextExtAddr = nextExtAddr.next(); } - libSym.setSymbolData2(0); } return true; @@ -275,7 +273,7 @@ public class SymbolManager implements SymbolTable, ManagerDB { try { Address variableAddr = getUpgradedVariableAddress(storageAddr, - rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_DATA1_COL)); + rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL)); // fix symbol address rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL, @@ -321,12 +319,12 @@ public class SymbolManager implements SymbolTable, ManagerDB { throw new RuntimeException("Unexpected"); } - long dataTypeId = rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_DATA1_COL); + long dataTypeId = rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL); if (curVarAddr == null || !addr.equals(curVarAddr) || dataTypeId != curDataTypeId) { curVarAddr = addr; - curDataTypeId = rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_DATA1_COL); + curDataTypeId = rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL); Address storageAddr = oldVariableStorageMgr.getStorageAddress(addr); @@ -450,7 +448,7 @@ public class SymbolManager implements SymbolTable, ManagerDB { * @param isPrimary true if symbol is primary at oldAddr * @throws IOException if there is database exception */ - public static void saveLocalSymbol(DBHandle tmpHandle, long symbolID, long oldAddr, String name, + static void saveLocalSymbol(DBHandle tmpHandle, long symbolID, long oldAddr, String name, boolean isPrimary) throws IOException { Table table = tmpHandle.getTable(OLD_LOCAL_SYMBOLS_TABLE); if (table == null) { @@ -506,8 +504,8 @@ public class SymbolManager implements SymbolTable, ManagerDB { symbolRemoved(symbol, address, symbol.getName(), oldKey, Namespace.GLOBAL_NAMESPACE_ID, null); DBRecord record = - adapter.createSymbol(newName, address, newParentID, SymbolType.LABEL, 0, - 1, null, source); + adapter.createSymbol(newName, address, newParentID, SymbolType.LABEL, null, + null, null, source, true); symbol.setRecord(record);// symbol object was morphed symbolAdded(symbol); } @@ -548,12 +546,15 @@ public class SymbolManager implements SymbolTable, ManagerDB { DBRecord rec = SymbolDatabaseAdapter.SYMBOL_SCHEMA.createRecord(symbolID); rec.setString(SymbolDatabaseAdapter.SYMBOL_NAME_COL, name); - rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL, addrMap.getKey(addr, true)); + long addressKey = addrMap.getKey(addr, true); + rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_ADDR_COL, addressKey); rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PARENT_COL, namespace.getID()); rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_TYPE_COL, type.getID()); - rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATA1_COL, -1); - rec.setIntValue(SymbolDatabaseAdapter.SYMBOL_DATA2_COL, isPrimary ? 1 : 0); + if (isPrimary) { + rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_PRIMARY_COL, addressKey); + } rec.setByteValue(SymbolDatabaseAdapter.SYMBOL_FLAGS_COL, (byte) source.ordinal()); + adapter.updateSymbolRecord(rec); } @@ -868,38 +869,51 @@ public class SymbolManager implements SymbolTable, ManagerDB { } @Override - public Symbol getSymbol(String name, Address addr, Namespace namespace) { + public Symbol getSymbol(String name, Address address, Namespace namespace) { if (namespace == null) { namespace = program.getGlobalNamespace(); } - if (addr instanceof SpecialAddress) { - List symbols = getSymbols(name, namespace); - for (Symbol symbol : symbols) { - if (symbol.getAddress().equals(addr)) { - return symbol; - } + long namespaceId = namespace.getID(); + + lock.acquire(); + try { + DBRecord record = adapter.getSymbolRecord(address, name, namespaceId); + if (record != null) { + return getSymbol(record); } - 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; } - /** - * Gets the symbol with the given info. - * @param name the name of the symbol - * @param addr the address of the symbol - * @param parentID the id of the namespace symbol that the symbol belongs to. - */ - private Symbol getSymbol(String name, Address addr, long parentID) { - Symbol[] symbols = getSymbols(addr); - for (Symbol sym : symbols) { - if (parentID != ((SymbolDB) sym).getParentID()) { - continue; - } - if (!isDefaultThunk(sym) && sym.getName().equals(name)) { - return sym; + private Symbol searchNamespaceForSymbol(Namespace namespace, String name, Address address) { + for (Symbol symbol : getSymbols(namespace)) { + if (address.equals(symbol.getAddress()) && name.equals(symbol.getName())) { + return symbol; } } return null; @@ -916,13 +930,6 @@ public class SymbolManager implements SymbolTable, ManagerDB { return symbols.isEmpty() ? null : symbols.get(0); } - private boolean hasDefaultVariablePrefix(String name) { - return name.startsWith(Function.DEFAULT_LOCAL_PREFIX) || - name.startsWith(Function.DEFAULT_LOCAL_RESERVED_PREFIX) || - name.startsWith(Function.DEFAULT_LOCAL_TEMP_PREFIX) || - name.startsWith(Function.DEFAULT_PARAM_PREFIX) || name.equals("this"); - } - @Override public Symbol getGlobalSymbol(String name, Address addr) { Symbol[] symbols = getSymbols(addr); @@ -981,38 +988,60 @@ public class SymbolManager implements SymbolTable, ManagerDB { namespace = namespaceMgr.getGlobalNamespace(); } + // if name is possible default parameter or local variable name, must do brute force search + if (namespace instanceof Function && + SymbolUtilities.isPossibleDefaultLocalOrParamName(name)) { + return searchNamespaceForSymbols(name, namespace); + } + + // if the name is a possible default external name, do brute force search + if (namespace.isExternal() && SymbolUtilities.isPossibleDefaultExternalName(name)) { + return searchNamespaceForSymbols(name, namespace); + } + + List list = new ArrayList<>(); lock.acquire(); try { - if (namespace.isExternal() && - SymbolUtilities.isReservedExternalDefaultName(name, program.getAddressFactory())) { - return searchSymbolsByNamespaceFirst(name, namespace); + RecordIterator it = adapter.getSymbolsByNameAndNamespace(name, namespace.getID()); + while (it.hasNext()) { + list.add(getSymbol(it.next())); } - - if (namespace instanceof Function && hasDefaultVariablePrefix(name)) { - return searchSymbolsByNamespaceFirst(name, namespace); - } - - // Try to find the symbols by searching through all the symbols with the given name - // and including only those in the specified namespace. If there are too many symbols - // with the same name and we are not in the global space, abandon this approach and - // instead search through all the symbols in the namespace and only include those with - // the specified name. - int count = 0; - List 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; + } + catch (IOException e) { + program.dbError(e); } finally { lock.release(); } + + // also check if the given name could be a default symbol + Symbol symbol = getSymbolForDynamicName(name); + if (symbol != null && symbol.getParentNamespace().equals(namespace)) { + list.add(symbol); + } + + return list; + } + + private List searchNamespaceForSymbols(String name, Namespace namespace) { + List list = new ArrayList<>(); + for (Symbol symbol : getSymbols(namespace)) { + if (name.equals(symbol.getName())) { + list.add(symbol); + } + } + return list; + } + + private Symbol getSymbolForDynamicName(String name) { + Address address = SymbolUtilities.parseDynamicName(addrMap.getAddressFactory(), name); + if (address != null) { + Symbol primarySymbol = getPrimarySymbol(address); + if (primarySymbol != null && primarySymbol.getSource() == SourceType.DEFAULT) { + return primarySymbol; + } + } + return null; } // note: this could be public; adding it may be confusing due to the potential for having @@ -1021,57 +1050,31 @@ public class SymbolManager implements SymbolTable, ManagerDB { if (namespace == null) { namespace = namespaceMgr.getGlobalNamespace(); } - - if (namespace.isExternal() && - SymbolUtilities.isReservedExternalDefaultName(name, program.getAddressFactory())) { - return findFirstSymbol(name, namespace, test); - } - - else if (namespace instanceof Function && hasDefaultVariablePrefix(name)) { - return findFirstSymbol(name, namespace, test); - } - - // Try to find the symbols by searching through all the symbols with the given name - // and including only those in the specified namespace. If there are too many symbols - // with the same name and we are not in the global space, abandon this approach and - // instead search through all the symbols in the namespace and only include those with - // the specified name. - int count = 0; - SymbolIterator symbols = getSymbols(name); - for (Symbol s : symbols) { - if (++count == MAX_DUPLICATE_COUNT && !namespace.isGlobal()) { - return findFirstSymbol(name, namespace, test); + lock.acquire(); + try { + RecordIterator it = adapter.getSymbolsByNameAndNamespace(name, namespace.getID()); + while (it.hasNext()) { + SymbolDB symbol = getSymbol(it.next()); + if (test.test(symbol)) { + return symbol; + } } - if (s.getParentNamespace().equals(namespace) && - test.test(s)) { - return s; + // didn't find one in the database, see if it is a default dynamic name + Symbol symbol = getSymbolForDynamicName(name); + if (symbol != null && symbol.getParentNamespace().equals(namespace) && + test.test(symbol)) { + return symbol; } } - + catch (IOException e) { + program.dbError(e); + } + finally { + lock.release(); + } return null; } - /** - * Returns the list of symbols with the given name and namespace. - * - *

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 searchSymbolsByNamespaceFirst(String name, Namespace namespace) { - List list = new ArrayList<>(); - SymbolIterator symbols = getSymbols(namespace); - for (Symbol symbol : symbols) { - if (symbol.getName().equals(name)) { - list.add(symbol); - } - } - return list; - } - @Override public Namespace getNamespace(String name, Namespace namespace) { List symbols = getSymbols(name, namespace); @@ -1107,16 +1110,8 @@ public class SymbolManager implements SymbolTable, ManagerDB { try { SymbolIterator symIter = new SymbolNameRecordIterator(name); if (!symIter.hasNext()) { - Address addr = SymbolUtilities.parseDynamicName(addrMap.getAddressFactory(), name); - if (addr != null) { - Symbol[] symbols = getSymbols(addr); - for (Symbol symbol : symbols) { - if (name.equals(symbol.getName())) { - return new SingleSymbolIterator(symbol); - } - } - return new SingleSymbolIterator(null); - } + Symbol symbol = getSymbolForDynamicName(name); + return new SingleSymbolIterator(symbol); // this handles a null symbol } return symIter; } @@ -1134,19 +1129,28 @@ public class SymbolManager implements SymbolTable, ManagerDB { if (!addr.isMemoryAddress() && !addr.isExternalAddress()) { return null; } + if (addr.isExternalAddress()) { + Symbol[] symbols = getSymbols(addr); + return symbols.length > 0 ? symbols[0] : null; + } + lock.acquire(); try { - Symbol[] symbols = getSymbols(addr); - for (Symbol element : symbols) { - if (element.isPrimary()) { - return element; - } + DBRecord record = adapter.getPrimarySymbol(addr); + if (record != null) { + return getSymbol(record); } - return null; + if (addr.isMemoryAddress() && refManager.hasReferencesTo(addr)) { + return getDynamicSymbol(addr); + } + } + catch (IOException e) { + program.dbError(e); } finally { lock.release(); } + return null; } @Override @@ -1207,14 +1211,14 @@ public class SymbolManager implements SymbolTable, ManagerDB { if (set.isEmpty()) { return SymbolIterator.EMPTY_ITERATOR; } - Query query1 = new FieldMatchQuery(SymbolDatabaseAdapter.SYMBOL_DATA2_COL, new IntField(1)); - Query query2 = new FieldMatchQuery(SymbolDatabaseAdapter.SYMBOL_TYPE_COL, - new ByteField(SymbolType.LABEL.getID())); - Query query3 = new FieldMatchQuery(SymbolDatabaseAdapter.SYMBOL_TYPE_COL, - new ByteField(SymbolType.FUNCTION.getID())); - Query query4 = new AndQuery(query1, query2); - Query query5 = new OrQuery(query3, query4); - return new AddressSetFilteredSymbolIterator(this, set, query5, forward); + try { + RecordIterator recordIterator = adapter.getPrimarySymbols(set, forward); + return new SymbolRecordIterator(recordIterator, true, forward); + } + catch (IOException e) { + program.dbError(e); + } + return new SymbolRecordIterator(new EmptyRecordIterator(), true, forward); } @Override @@ -2130,9 +2134,9 @@ public class SymbolManager implements SymbolTable, ManagerDB { continue; } } - long id = rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_DATA1_COL); + long id = rec.getLongValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL); if (id == oldDataTypeID) { - rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATA1_COL, newDataTypeID); + rec.setLongValue(SymbolDatabaseAdapter.SYMBOL_DATATYPE_COL, newDataTypeID); adapter.updateSymbolRecord(rec); symbolDataChanged(getSymbol(rec)); } @@ -2157,14 +2161,14 @@ public class SymbolManager implements SymbolTable, ManagerDB { lock.acquire(); try { invalidateCache(true); - Address lastAddress = fromAddr.add(length-1); + Address lastAddress = fromAddr.add(length - 1); AddressRange range = new AddressRangeImpl(fromAddr, lastAddress); // in order to handle overlapping ranges, need to iterate in the correct direction - SymbolIterator symbolIterator = (fromAddr.compareTo(toAddr) > 0) ? - getSymbolIterator(fromAddr, true) : - getSymbolIterator(lastAddress, false); - + SymbolIterator symbolIterator = + (fromAddr.compareTo(toAddr) > 0) ? getSymbolIterator(fromAddr, true) + : getSymbolIterator(lastAddress, false); + for (Symbol symbol : symbolIterator) { if (!range.contains(symbol.getAddress())) { 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) primaryFixups.add(symbol.getAddress()); primaryFixups.add(newAddress); - + moveSymbolForMemoryBlockMove((SymbolDB) symbol, newAddress); } // 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 { Symbol newLabel = createLabel(newAddress, symbol.getName(), symbol.getParentNamespace(), - symbol.getSource()); + symbol.getSource()); newLabel.setPinned(true); } catch (InvalidInputException e) { @@ -2479,8 +2483,8 @@ public class SymbolManager implements SymbolTable, ManagerDB { try { source = adjustSourceTypeIfNecessary(name, type, source, storage); Address varAddr = variableStorageMgr.getVariableStorageAddress(storage, true); - return (VariableSymbolDB) createSpecialSymbol(varAddr, name, namespace, type, -1, - firstUseOffsetOrOrdinal, null, source); + return (VariableSymbolDB) createSpecialSymbol(varAddr, name, namespace, type, + null, Integer.valueOf(firstUseOffsetOrOrdinal), null, source); } catch (IOException e) { dbError(e); @@ -2506,8 +2510,9 @@ public class SymbolManager implements SymbolTable, ManagerDB { @Override public GhidraClass createClass(Namespace parent, String name, SourceType source) throws DuplicateNameException, InvalidInputException { - SymbolDB s = createSpecialSymbol(Address.NO_ADDRESS, name, parent, SymbolType.CLASS, -1, -1, - null, source); + SymbolDB s = + createSpecialSymbol(Address.NO_ADDRESS, name, parent, SymbolType.CLASS, null, null, + null, source); return new GhidraClassDB(s, namespaceMgr); } @@ -2515,8 +2520,9 @@ public class SymbolManager implements SymbolTable, ManagerDB { public Library createExternalLibrary(String name, SourceType source) throws DuplicateNameException, InvalidInputException { - SymbolDB s = createSpecialSymbol(Address.NO_ADDRESS, name, null, SymbolType.LIBRARY, -1, -1, - null, source); + SymbolDB s = + createSpecialSymbol(Address.NO_ADDRESS, name, null, SymbolType.LIBRARY, null, null, + null, source); return new LibraryDB(s, namespaceMgr); } @@ -2524,8 +2530,9 @@ public class SymbolManager implements SymbolTable, ManagerDB { public Namespace createNameSpace(Namespace parent, String name, SourceType source) throws DuplicateNameException, InvalidInputException { - SymbolDB s = createSpecialSymbol(Address.NO_ADDRESS, name, parent, SymbolType.NAMESPACE, -1, - -1, null, source); + SymbolDB s = + createSpecialSymbol(Address.NO_ADDRESS, name, parent, SymbolType.NAMESPACE, null, + null, null, source); return new NamespaceDB(s, namespaceMgr); } @@ -2549,7 +2556,8 @@ public class SymbolManager implements SymbolTable, ManagerDB { String tempName = "_temp_" + System.nanoTime(); SymbolDB classSymbol = doCreateSpecialSymbol(Address.NO_ADDRESS, tempName, namespace.getParentNamespace(), - SymbolType.CLASS, -1, -1, null, originalSource, false /*check for duplicate */); + SymbolType.CLASS, null, null, null, originalSource, + false /*check for duplicate */); GhidraClassDB classNamespace = new GhidraClassDB(classSymbol, namespaceMgr); // move everything from old namespace into new class namespace @@ -2624,8 +2632,8 @@ public class SymbolManager implements SymbolTable, ManagerDB { // Note: We know there are no namespaces with the name; do we still have to check for // duplicates? Assuming yes, as another symbol type may exist with this name. SymbolDB s = - doCreateSpecialSymbol(Address.NO_ADDRESS, name, parent, SymbolType.NAMESPACE, -1, - -1, null, source, true /*check for duplicates*/); + doCreateSpecialSymbol(Address.NO_ADDRESS, name, parent, SymbolType.NAMESPACE, null, + null, null, source, true /*check for duplicates*/); return new NamespaceDB(s, namespaceMgr); } @@ -2643,9 +2651,9 @@ public class SymbolManager implements SymbolTable, ManagerDB { * @param name the name of the symbol * @param parent the namespace for the symbol * @param symbolType the type of the symbol - * @param data1 long value whose meaning depends on the symbol type. - * @param data2 int value whose meaning depends on the symbol type. - * @param data3 string value whose meaning depends on the symbol type. + * @param dataTypeId the id for an associated datatype or null + * @param variableOffset this is the ordinal for params and firstUseOffset for locals + * @param stringData value whose meaning depends on the symbol type. * @param source the SourceType for the new symbol * @return the newly created symbol * @throws DuplicateNameException if the symbol type must be unique and another already has that name @@ -2653,15 +2661,17 @@ public class SymbolManager implements SymbolTable, ManagerDB { * @throws InvalidInputException if the name contains any illegal characters (i.e. space) */ public SymbolDB createSpecialSymbol(Address addr, String name, Namespace parent, - SymbolType symbolType, long data1, int data2, String data3, SourceType source) + SymbolType symbolType, Long dataTypeId, Integer variableOffset, String stringData, + SourceType source) throws DuplicateNameException, InvalidInputException { - return doCreateSpecialSymbol(addr, name, parent, symbolType, data1, data2, data3, source, - true); + return doCreateSpecialSymbol(addr, name, parent, symbolType, stringData, dataTypeId, + variableOffset, source, true); } private SymbolDB doCreateSpecialSymbol(Address addr, String name, Namespace parent, - SymbolType symbolType, long data1, int data2, String data3, SourceType source, + SymbolType symbolType, String stringData, Long dataTypeId, Integer variableOffset, + SourceType source, boolean checkForDuplicates) throws DuplicateNameException, InvalidInputException { @@ -2675,7 +2685,8 @@ public class SymbolManager implements SymbolTable, ManagerDB { checkDuplicateSymbolName(addr, name, parent, symbolType); } - return doCreateSymbol(name, addr, parent, symbolType, data1, data2, data3, source); + return doCreateSymbol(name, addr, parent, symbolType, stringData, dataTypeId, + variableOffset, source, false); } finally { lock.release(); @@ -2713,12 +2724,12 @@ public class SymbolManager implements SymbolTable, ManagerDB { * @param name the name of the new symbol * @param namespace the namespace for the new symbol * @param source the SourceType of the new symbol - * @param data3 special use depending on the symbol type and whether or not it is external + * @param stringData special use depending on the symbol type and whether or not it is external * @return the new symbol * @throws InvalidInputException if the name contains illegal characters (i.e. space) */ public Symbol createCodeSymbol(Address addr, String name, Namespace namespace, - SourceType source, String data3) throws InvalidInputException { + SourceType source, String stringData) throws InvalidInputException { lock.acquire(); try { namespace = validateNamespace(namespace, addr, SymbolType.LABEL); @@ -2744,8 +2755,8 @@ public class SymbolManager implements SymbolTable, ManagerDB { } boolean makePrimary = primary == null; - return doCreateSymbol(name, addr, namespace, SymbolType.LABEL, -1, makePrimary ? 1 : 0, - data3, source); + return doCreateSymbol(name, addr, namespace, SymbolType.LABEL, stringData, null, null, + source, makePrimary); } finally { lock.release(); @@ -2759,34 +2770,32 @@ public class SymbolManager implements SymbolTable, ManagerDB { * @param name the name of the new symbol * @param namespace the namespace for the new symbol * @param source the SourceType of the new symbol - * @param data3 special use depending on the symbol type and whether or not it is external. + * @param stringData special use depending on the symbol type and whether or not it is external. * @return the new symbol * @throws InvalidInputException if the name contains illegal characters (i.e. space) */ public Symbol createFunctionSymbol(Address addr, String name, Namespace namespace, - SourceType source, String data3) throws InvalidInputException { + SourceType source, String stringData) throws InvalidInputException { namespace = validateNamespace(namespace, addr, SymbolType.FUNCTION); source = validateSource(source, name, addr, SymbolType.FUNCTION); name = validateName(name, source); - Symbol[] symbols = getSymbols(addr); - // if there is already a FUNCTION symbol with that name and namespace here, just return it. - Symbol matching = - findMatchingSymbol(symbols, new SymbolMatcher(name, namespace, SymbolType.FUNCTION)); - if (matching != null) { + Symbol matching = getSymbol(name, addr, namespace); + if (matching != null && matching.getSymbolType() == SymbolType.FUNCTION) { return matching; } // if there is another function at the same address, throw InvalidInputException - if (findMatchingSymbol(symbols, s -> s.getSymbolType() == SymbolType.FUNCTION) != null) { + Symbol primary = getPrimarySymbol(addr); + if (primary != null && primary.getSymbolType() == SymbolType.FUNCTION) { throw new InvalidInputException("Function already exists at: " + addr); } // See if there is a symbol we want to change into the function symbol - Symbol symbolToPromote = findSymbolToPromote(symbols, name, namespace, source); - if (symbolToPromote != null) { + Symbol symbolToPromote = findSymbolToPromote(matching, primary, source); + if (symbolToPromote != null && !symbolToPromote.isDynamic()) { name = symbolToPromote.getName(); namespace = symbolToPromote.getParentNamespace(); source = symbolToPromote.getSource(); @@ -2795,11 +2804,12 @@ public class SymbolManager implements SymbolTable, ManagerDB { // If promoting a pinned symbol, we need to pin the new function symbol. boolean needsPinning = symbolToPromote == null ? false : symbolToPromote.isPinned(); - // delete any promoted symbol, dynamic symbol, and make sure any others are not primary - cleanUpSymbols(symbols, symbolToPromote); + // delete any promoted symbol, dynamic symbol, and make sure all others are not primary + cleanUpSymbols(addr, symbolToPromote, primary); Symbol symbol = - doCreateSymbol(name, addr, namespace, SymbolType.FUNCTION, -1, -1, data3, source); + doCreateSymbol(name, addr, namespace, SymbolType.FUNCTION, stringData, null, null, + source, true); if (needsPinning) { symbol.setPinned(true); @@ -2809,48 +2819,45 @@ public class SymbolManager implements SymbolTable, ManagerDB { } /** - * If the new symbol is Default, returns the primary symbol if it is dynamic. Otherwise - * returns any Code symbol with the same name and namespace. + * Finds the appropriate symbol to promote when function is created. And by promote, we really + * mean find the symbol that needs to be deleted before creating the function symbol. If the + * found symbol is not dynamic, the function symbol will assume its name and namespace. */ - private Symbol findSymbolToPromote(Symbol[] symbols, String name, Namespace namespace, - SourceType source) { + private Symbol findSymbolToPromote(Symbol matching, Symbol primary, SourceType source) { + // if the function is default, then the primary will be promoted if (source == SourceType.DEFAULT) { - Symbol primary = findMatchingSymbol(symbols, s -> s.isPrimary()); - if (primary != null && !primary.isDynamic()) { - return primary; - } - return null; + return primary; } - // Even though this doesn't change the name or namespace, return this so it will be deleted later. - return findMatchingSymbol(symbols, new SymbolMatcher(name, namespace, SymbolType.LABEL)); + // if the primary is a default, it needs to be deleted, so return it as the "promoted" symbol + if (primary != null && primary.isDynamic()) { + return primary; + } + // otherwise return a symbol that has the same name and namespce as the function (if it exists) + return matching; } - private void cleanUpSymbols(Symbol[] symbols, Symbol symbolToPromote) { + private void cleanUpSymbols(Address address, Symbol symbolToPromote, Symbol primary) { if (symbolToPromote != null) { if (symbolToPromote.isDynamic()) { deleteDynamicSymbol(symbolToPromote); + primary = null; } else { symbolToPromote.delete(); + 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 - for (Symbol symbol : symbols) { - if (symbol != symbolToPromote && symbol.isPrimary()) { - ((CodeSymbol) symbol).setPrimary(false); - } + // clear the primary symbol during cleanup because a new symbol is about to be created + // that will be the primary symbol + if (primary != null && !primary.isDynamic()) { + ((CodeSymbol) primary).setPrimary(false); } } - private Symbol findMatchingSymbol(Symbol[] symbols, Predicate matcher) { - for (Symbol symbol : symbols) { - if (matcher.test(symbol)) { - return symbol; - } - } - return null; - } - private Namespace validateNamespace(Namespace namespace, Address addr, SymbolType type) throws InvalidInputException { @@ -2862,12 +2869,13 @@ public class SymbolManager implements SymbolTable, ManagerDB { } private SymbolDB doCreateSymbol(String name, Address addr, Namespace namespace, SymbolType type, - long data1, int data2, String data3, SourceType source) { + String stringData, Long dataTypeId, Integer variableOffset, SourceType source, + boolean isPrimary) { try { DBRecord record = - adapter.createSymbol(name, addr, namespace.getID(), type, data1, data2, - data3, source); + adapter.createSymbol(name, addr, namespace.getID(), type, stringData, dataTypeId, + variableOffset, source, isPrimary); SymbolDB newSymbol = makeSymbol(addr, record, type); symbolAdded(newSymbol); @@ -3019,21 +3027,6 @@ public class SymbolManager implements SymbolTable, ManagerDB { private Symbol getSpecificSymbol(String name, Namespace namespace, SymbolType type) { return getFirstSymbol(name, namespace, s -> s.getSymbolType() == type); } - - private Symbol findFirstSymbol(String name, Namespace namespace, Predicate 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 { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableSymbolDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableSymbolDB.java index e9850bc765..5e5c30ef6e 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableSymbolDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/symbol/VariableSymbolDB.java @@ -36,9 +36,7 @@ import ghidra.util.task.TaskMonitor; * Symbol class for function variables. * * Symbol Data Usage: - * long data1 - data type ID - * int data2 - first-use-offset / ordinal - * String data3 - variable comment + * String stringData - variable comment */ public class VariableSymbolDB extends SymbolDB { @@ -174,8 +172,9 @@ public class VariableSymbolDB extends SymbolDB { } public FunctionDB getFunction() { - return (FunctionDB) symbolMgr.getFunctionManager().getFunction( - getParentNamespace().getID()); + return (FunctionDB) symbolMgr.getFunctionManager() + .getFunction( + getParentNamespace().getID()); } /** @@ -252,7 +251,7 @@ public class VariableSymbolDB extends SymbolDB { } public DataType getDataType() { - DataType dt = symbolMgr.getDataType(getSymbolData1()); + DataType dt = symbolMgr.getDataType(getDataTypeId()); if (dt == null) { VariableStorage storage = getVariableStorage(); if (storage == null) { @@ -286,8 +285,8 @@ public class VariableSymbolDB extends SymbolDB { Address newAddr = variableMgr.getVariableStorageAddress(newStorage, true); setAddress(newAddr); // this may be the only symbol which changes its address - if (dataTypeID != getSymbolData1()) { - setSymbolData1(dataTypeID); + if (dataTypeID != getDataTypeId()) { + setDataTypeId(dataTypeID); } else { symbolMgr.symbolDataChanged(this); @@ -302,22 +301,22 @@ public class VariableSymbolDB extends SymbolDB { } public int getFirstUseOffset() { - return type == SymbolType.PARAMETER ? 0 : getSymbolData2(); + return type == SymbolType.PARAMETER ? 0 : getVariableOffset(); } public void setFirstUseOffset(int firstUseOffset) { if (type == SymbolType.LOCAL_VAR) { - setSymbolData2(firstUseOffset); + setVariableOffset(firstUseOffset); } } public int getOrdinal() { - return type == SymbolType.PARAMETER ? getSymbolData2() : Integer.MIN_VALUE; + return type == SymbolType.PARAMETER ? getVariableOffset() : Integer.MIN_VALUE; } public void setOrdinal(int ordinal) { if (type == SymbolType.PARAMETER) { - setSymbolData2(ordinal); + setVariableOffset(ordinal); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/util/EmptyRecordIterator.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/util/EmptyRecordIterator.java index 3ea21042bf..c375046e05 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/util/EmptyRecordIterator.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/util/EmptyRecordIterator.java @@ -23,7 +23,9 @@ import db.RecordIterator; /** * Implementation of a RecordIterator that is always empty. */ + public class EmptyRecordIterator implements RecordIterator { + public static final RecordIterator INSTANCE = new EmptyRecordIterator(); /** * @see db.RecordIterator#hasNext() diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/symbol/SymbolUtilities.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/symbol/SymbolUtilities.java index 83250ca905..97ae28119e 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/symbol/SymbolUtilities.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/symbol/SymbolUtilities.java @@ -760,6 +760,29 @@ public class SymbolUtilities { return addr.getAddressSpace().getName() + Long.toHexString(addr.getOffset()); } + /** + * Returns true if the given name is a possible default parameter name or local variable name + * + * @param name the name to check to see if it is a possible default local or parameter name + * @return true if the given name is a possible default parameter name or local variable name + */ + public static boolean isPossibleDefaultLocalOrParamName(String name) { + if (isDefaultParameterName(name)) { + return true; + } + return name.startsWith(Function.DEFAULT_LOCAL_PREFIX); + } + + /** + * Checks if the given name could be a default external location name + * + * @param name the name to check + * @return true if the given name is a possible default external location name + */ + public static boolean isPossibleDefaultExternalName(String name) { + return name.startsWith(DEFAULT_EXTERNAL_ENTRY_PREFIX); + } + public static boolean isDefaultLocalStackName(String name) { if (name == null || name.length() == 0) { return true; @@ -1042,4 +1065,5 @@ public class SymbolUtilities { public static Comparator getSymbolNameComparator() { return CASE_INSENSITIVE_SYMBOL_NAME_COMPARATOR; } + } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/ChangeManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/ChangeManager.java index d8d9a8e938..26dc584901 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/ChangeManager.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/ChangeManager.java @@ -193,8 +193,8 @@ public interface ChangeManager { public static final int DOCR_SYMBOL_ASSOCIATION_REMOVED = 51; /** - * Symbol data changed. This corresponds to unspecified data - * changes within the symbol (e.g., Data1, Data2, Data3, or VariableStorage). + * Symbol data changed. This corresponds to various + * changes within the symbol (e.g., primary status, datatype, external path or VariableStorage). */ public static final int DOCR_SYMBOL_DATA_CHANGED = 52; @@ -592,7 +592,6 @@ public interface ChangeManager { */ public final static int DOCR_TAG_REMOVED_FROM_FUNCTION = 157; - //////////////////////////////////////////////////////////////////////////// // // DOCR_FUNCTION_CHANGED - Sub Event Types