diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionEditorModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionEditorModel.java index b35b86f87a..dc46d07bd9 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionEditorModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/editor/FunctionEditorModel.java @@ -986,7 +986,7 @@ public class FunctionEditorModel { if (!paramInfo.isAutoParameter() && paramInfo.isNameModified()) { Parameter param = paramInfo.getOriginalParameter(); if (param != null) { - if (!param.getSymbol().checkIsValid()) { + if (param.getSymbol().isDeleted()) { // concurrent removal of param - must do full update paramsOrReturnModified = true; break; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorModel.java index d4417e963d..ed3a55eefb 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorModel.java @@ -38,7 +38,6 @@ import ghidra.app.plugin.core.compositeeditor.CompositeEditorModel; import ghidra.app.plugin.core.compositeeditor.DataTypeHelper; import ghidra.app.util.datatype.EmptyCompositeException; import ghidra.framework.plugintool.Plugin; -import ghidra.program.database.DatabaseObject; import ghidra.program.model.data.*; import ghidra.program.model.listing.*; import ghidra.program.model.symbol.SourceType; @@ -1271,11 +1270,8 @@ class StackEditorModel extends CompositeEditorModel { for (int i = comps.length - 1; i >= 0; i--) { DataTypeComponent component = comps[i]; DataType compDt = component.getDataType(); - if (compDt instanceof DatabaseObject) { - DatabaseObject dbObj = (DatabaseObject) compDt; - if (!dbObj.checkIsValid()) { - clearComponent(component.getOrdinal()); - } + if (compDt.isDeleted()) { + clearComponent(component.getOrdinal()); } } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorPanel.java index a5d8ce4537..2561edee13 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorPanel.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. @@ -16,18 +15,16 @@ */ package ghidra.app.plugin.core.stackeditor; -import ghidra.app.plugin.core.compositeeditor.CompositeEditorPanel; -import ghidra.framework.plugintool.PluginTool; -import ghidra.program.database.DatabaseObject; -import ghidra.program.model.data.*; -import ghidra.program.model.listing.*; -import ghidra.util.exception.UsrException; - import java.awt.event.*; import javax.swing.*; import docking.widgets.OptionDialog; +import ghidra.app.plugin.core.compositeeditor.CompositeEditorPanel; +import ghidra.framework.plugintool.PluginTool; +import ghidra.program.model.data.*; +import ghidra.program.model.listing.*; +import ghidra.util.exception.UsrException; /** * Panel for editing a function stack. @@ -274,14 +271,12 @@ public class StackEditorPanel extends CompositeEditorPanel { if (originalDt instanceof StackFrameDataType) { StackFrameDataType sfdt = (StackFrameDataType) originalDt; Function function = sfdt.getFunction(); - if (function instanceof DatabaseObject) { - if (!((DatabaseObject) function).checkIsValid()) { - // Cancel Editor. - provider.dispose(); - PluginTool tool = ((StackEditorProvider) provider).getPlugin().getTool(); - tool.setStatusInfo("Stack Editor was closed for " + provider.getName()); - return; - } + if (function.isDeleted()) { + // Cancel Editor. + provider.dispose(); + PluginTool tool = ((StackEditorProvider) provider).getPlugin().getTool(); + tool.setStatusInfo("Stack Editor was closed for " + provider.getName()); + return; } StackFrame stack = function.getStackFrame(); StackFrameDataType newSfdt = new StackFrameDataType(stack, dtm); @@ -329,13 +324,10 @@ public class StackEditorPanel extends CompositeEditorPanel { super.dispose(); } - /** - * @param localSizeField - */ private void removeFocusListeners(JTextField textField) { FocusListener[] fl = textField.getFocusListeners(); - for (int i = 0; i < fl.length; i++) { - textField.removeFocusListener(fl[i]); + for (FocusListener element : fl) { + textField.removeFocusListener(element); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/SymbolTreeProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/SymbolTreeProvider.java index ab81ad4a09..84e1255168 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/SymbolTreeProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symboltree/SymbolTreeProvider.java @@ -568,7 +568,7 @@ public class SymbolTreeProvider extends ComponentProviderAdapter { SymbolTreeRootNode rootNode = (SymbolTreeRootNode) tree.getModelRoot(); // the symbol may have been deleted while we are processing bulk changes - if (symbol.checkIsValid()) { + if (!symbol.isDeleted()) { GTreeNode newNode = rootNode.symbolAdded(symbol); tree.refilterLater(newNode); } @@ -588,7 +588,7 @@ public class SymbolTreeProvider extends ComponentProviderAdapter { root.symbolRemoved(symbol, monitor); // the symbol may have been deleted while we are processing bulk changes - if (symbol.checkIsValid()) { + if (!symbol.isDeleted()) { root.symbolAdded(symbol); } tree.refilterLater(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/SymbolTableModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/SymbolTableModel.java index 365a3699ee..8e30e06a7e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/SymbolTableModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/SymbolTableModel.java @@ -379,7 +379,7 @@ class SymbolTableModel extends AddressBasedTableModel { public Symbol getValue(Symbol symbol, Settings settings, Program p, ServiceProvider svcProvider) throws IllegalArgumentException { - if (!symbol.checkIsValid()) { + if (symbol.isDeleted()) { return null; } return symbol; @@ -400,7 +400,7 @@ class SymbolTableModel extends AddressBasedTableModel { public Boolean getValue(Symbol symbol, Settings settings, Program p, ServiceProvider svcProvider) throws IllegalArgumentException { - if (!symbol.checkIsValid()) { + if (symbol.isDeleted()) { return null; } return symbol.isPinned(); @@ -435,7 +435,7 @@ class SymbolTableModel extends AddressBasedTableModel { public ProgramLocation getProgramLocation(Symbol symbol, Settings settings, Program p, ServiceProvider svcProvider) { - if (!symbol.checkIsValid()) { + if (symbol.isDeleted()) { return null; } return symbol.getProgramLocation(); @@ -454,7 +454,7 @@ class SymbolTableModel extends AddressBasedTableModel { public String getValue(Symbol symbol, Settings settings, Program p, ServiceProvider svcProvider) throws IllegalArgumentException { - if (!symbol.checkIsValid()) { + if (symbol.isDeleted()) { return null; } @@ -483,7 +483,7 @@ class SymbolTableModel extends AddressBasedTableModel { public String getValue(Symbol symbol, Settings settings, Program p, ServiceProvider svcProvider) throws IllegalArgumentException { - if (!symbol.checkIsValid()) { + if (symbol.isDeleted()) { return null; } @@ -520,7 +520,7 @@ class SymbolTableModel extends AddressBasedTableModel { public String getValue(Symbol symbol, Settings settings, Program p, ServiceProvider svcProvider) throws IllegalArgumentException { - if (!symbol.checkIsValid()) { + if (symbol.isDeleted()) { return null; } return symbol.getParentNamespace().getName(true); @@ -580,7 +580,7 @@ class SymbolTableModel extends AddressBasedTableModel { @Override public Integer getValue(Symbol symbol, Settings settings, Program p, ServiceProvider svcProvider) throws IllegalArgumentException { - if (!symbol.checkIsValid()) { + if (symbol.isDeleted()) { return null; } return Integer.valueOf(symbol.getReferenceCount()); @@ -612,7 +612,7 @@ class SymbolTableModel extends AddressBasedTableModel { @Override public Integer getValue(Symbol symbol, Settings settings, Program p, ServiceProvider svcProvider) throws IllegalArgumentException { - if (!symbol.checkIsValid()) { + if (symbol.isDeleted()) { return null; } @@ -665,7 +665,7 @@ class SymbolTableModel extends AddressBasedTableModel { public String getValue(Symbol symbol, Settings settings, Program p, ServiceProvider svcProvider) throws IllegalArgumentException { - if (!symbol.checkIsValid()) { + if (symbol.isDeleted()) { return null; } @@ -702,7 +702,7 @@ class SymbolTableModel extends AddressBasedTableModel { public String getValue(Symbol symbol, Settings settings, Program p, ServiceProvider svcProvider) throws IllegalArgumentException { - if (!symbol.checkIsValid()) { + if (symbol.isDeleted()) { return null; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/SymbolTablePlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/SymbolTablePlugin.java index 95d35fc0d6..6401c428fd 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/SymbolTablePlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/symtable/SymbolTablePlugin.java @@ -250,7 +250,7 @@ public class SymbolTablePlugin extends Plugin implements DomainObjectListener { case ChangeManager.DOCR_SYMBOL_SCOPE_CHANGED: case ChangeManager.DOCR_SYMBOL_DATA_CHANGED: symbol = (Symbol) rec.getObject(); - if (symbol.checkIsValid()) { // symbol may have been removed (e.g., parameter) + if (!symbol.isDeleted()) { // symbol may have been removed (e.g., parameter) symProvider.symbolChanged(symbol); refProvider.symbolChanged(symbol); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/util/UndefinedFunction.java b/Ghidra/Features/Base/src/main/java/ghidra/util/UndefinedFunction.java index a262b816f2..2fe52fce97 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/util/UndefinedFunction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/util/UndefinedFunction.java @@ -54,22 +54,28 @@ public class UndefinedFunction implements Function { frame = new StackFrameImpl(this); } + @Override + public boolean isDeleted() { + return false; + } + /** - * locates the function based on the location given at construction time. + * Identifies a UndefinedFunction based on the location given based upon the current + * listing disassembly at time of construction using a block model. + * @param program program to be searched + * @param address address within body of function + * @param monitor task monitor + * @return function or null if invalid parameters, not found, or cancelled */ public static UndefinedFunction findFunction(Program program, Address address, TaskMonitor monitor) { - if (program == null || address == null) { - return null; - } - - if (monitor.isCancelled()) { + if (program == null || address == null || monitor.isCancelled()) { return null; } // first try to walk back up to the top of the function UndefinedFunction function = findFunctionUsingSimpleBlockModel(program, address, monitor); - if (function != null) { + if (function != null || monitor.isCancelled()) { return function; } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/util/ObjectCacheTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/ObjectCacheTest.java similarity index 98% rename from Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/util/ObjectCacheTest.java rename to Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/ObjectCacheTest.java index 368191a1c5..3508f7600c 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/util/ObjectCacheTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/ObjectCacheTest.java @@ -16,7 +16,7 @@ /* * */ -package ghidra.program.database.util; +package ghidra.program.database; import static org.junit.Assert.*; diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/symbol/NamespaceManagerTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/symbol/NamespaceManagerTest.java index ba7826e4e0..b1d92557d8 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/symbol/NamespaceManagerTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/symbol/NamespaceManagerTest.java @@ -17,14 +17,12 @@ package ghidra.program.database.symbol; import static org.junit.Assert.*; -import java.util.ConcurrentModificationException; import java.util.Iterator; import org.junit.*; import ghidra.program.database.ProgramBuilder; import ghidra.program.database.ProgramDB; -import ghidra.program.database.function.FunctionDB; import ghidra.program.model.address.*; import ghidra.program.model.listing.*; import ghidra.program.model.mem.MemoryBlock; @@ -52,8 +50,8 @@ public class NamespaceManagerTest extends AbstractGhidraHeadedIntegrationTest { super(); } - @Before - public void setUp() throws Exception { + @Before + public void setUp() throws Exception { program = createDefaultProgram("Test", ProgramBuilder._TOY, this); space = program.getAddressFactory().getDefaultAddressSpace(); namespaceManager = program.getNamespaceManager(); @@ -65,14 +63,14 @@ public class NamespaceManagerTest extends AbstractGhidraHeadedIntegrationTest { addBlock("BlockTwo", addr(0x2000), 0x4000); } - @After - public void tearDown() throws Exception { + @After + public void tearDown() throws Exception { program.endTransaction(transactionID, true); program.release(this); } -@Test - public void testCreateSubNamespace() throws Exception { + @Test + public void testCreateSubNamespace() throws Exception { GhidraClass gc = symbolMgr.createClass(globalNamespace, "classNamespace", SourceType.USER_DEFINED); AddressSet set = new AddressSet(); @@ -85,9 +83,8 @@ public class NamespaceManagerTest extends AbstractGhidraHeadedIntegrationTest { AddressSet set2 = new AddressSet(); set2.addRange(addr(0x100), addr(0x130)); - Function f2 = - functionMgr.createFunction("TextFunctionNamespace", addr(0x100), set2, - SourceType.USER_DEFINED); + Function f2 = functionMgr.createFunction("TextFunctionNamespace", addr(0x100), set2, + SourceType.USER_DEFINED); f2.setParentNamespace(gc); assertTrue(gc.getBody().hasSameAddresses(set.union(set2))); @@ -99,8 +96,8 @@ public class NamespaceManagerTest extends AbstractGhidraHeadedIntegrationTest { assertEquals(f2, namespaceManager.getNamespaceContaining(addr(0x110))); } -@Test - public void testGetBody() throws Exception { + @Test + public void testGetBody() throws Exception { GhidraClass classNamespace = symbolMgr.createClass(null, "TestNamespaceClass", SourceType.USER_DEFINED); AddressSet set = new AddressSet(); @@ -139,8 +136,8 @@ public class NamespaceManagerTest extends AbstractGhidraHeadedIntegrationTest { assertTrue(gcSet.hasSameAddresses(newSet)); } -@Test - public void testFullName() throws Exception { + @Test + public void testFullName() throws Exception { GhidraClass classNamespace = symbolMgr.createClass(null, "TestNamespaceClass", SourceType.USER_DEFINED); AddressSet set = new AddressSet(); @@ -168,8 +165,8 @@ public class NamespaceManagerTest extends AbstractGhidraHeadedIntegrationTest { assertEquals("TestNamespaceClass::F3", f3.getName(true)); } -@Test - public void testRemoveNamespace() throws Exception { + @Test + public void testRemoveNamespace() throws Exception { GhidraClass classNamespace = symbolMgr.createClass(null, "TestNamespaceClass", SourceType.USER_DEFINED); @@ -206,22 +203,12 @@ public class NamespaceManagerTest extends AbstractGhidraHeadedIntegrationTest { assertEquals(globalNamespace, namespaceManager.getNamespaceContaining(addr(0x100))); assertEquals(globalNamespace, namespaceManager.getNamespaceContaining(addr(0x255))); - try { - ((FunctionDB) f2).checkDeleted(); - Assert.fail("Function 2 should be marked as deleted!"); - } - catch (ConcurrentModificationException e) { - } - try { - ((FunctionDB) f3).checkDeleted(); - Assert.fail("Function 3 should be marked as deleted!"); - } - catch (ConcurrentModificationException e) { - } + Assert.assertTrue("Function 2 should be marked as deleted!", f2.isDeleted()); + Assert.assertTrue("Function 3 should be marked as deleted!", f3.isDeleted()); } -@Test - public void testMoveNamespace() throws Exception { + @Test + public void testMoveNamespace() throws Exception { GhidraClass classNamespace = symbolMgr.createClass(null, "TestNamespaceClass", SourceType.USER_DEFINED); GhidraClass classNamespace2 = @@ -252,8 +239,8 @@ public class NamespaceManagerTest extends AbstractGhidraHeadedIntegrationTest { assertEquals(classNamespace3, f2.getParentNamespace()); } -@Test - public void testMoveAddressRange() throws Exception { + @Test + public void testMoveAddressRange() throws Exception { GhidraClass classNamespace = symbolMgr.createClass(null, "TestNamespaceClass", SourceType.USER_DEFINED); @@ -287,8 +274,8 @@ public class NamespaceManagerTest extends AbstractGhidraHeadedIntegrationTest { assertTrue(f2.getBody().hasSameAddresses(set2)); } -@Test - public void testMoveAddressRange2() throws Exception { + @Test + public void testMoveAddressRange2() throws Exception { GhidraClass classNamespace = symbolMgr.createClass(null, "TestNamespaceClass", SourceType.USER_DEFINED); @@ -319,8 +306,8 @@ public class NamespaceManagerTest extends AbstractGhidraHeadedIntegrationTest { assertTrue(f2.getBody().hasSameAddresses(set2)); } -@Test - public void testDeleteAddressRange() throws Exception { + @Test + public void testDeleteAddressRange() throws Exception { GhidraClass classNamespace = symbolMgr.createClass(null, "TestNamespaceClass", SourceType.USER_DEFINED); @@ -344,8 +331,8 @@ public class NamespaceManagerTest extends AbstractGhidraHeadedIntegrationTest { assertEquals(globalNamespace, namespaceManager.getNamespaceContaining(addr(0))); } -@Test - public void testIsOverlappedNamespace() throws Exception { + @Test + public void testIsOverlappedNamespace() throws Exception { GhidraClass classNamespace = symbolMgr.createClass(null, "TestNamespaceClass", SourceType.USER_DEFINED); @@ -376,7 +363,6 @@ public class NamespaceManagerTest extends AbstractGhidraHeadedIntegrationTest { Assert.fail("Should overlap!"); } - set2 = new AddressSet(); set.addRange(addr(0x200), addr(0x210)); set.addRange(addr(0x55), addr(0xff)); @@ -386,8 +372,8 @@ public class NamespaceManagerTest extends AbstractGhidraHeadedIntegrationTest { } } -@Test - public void testNamespaceIteratorForOverlaps() throws Exception { + @Test + public void testNamespaceIteratorForOverlaps() throws Exception { GhidraClass classNamespace = symbolMgr.createClass(null, "TestNamespaceClass", SourceType.USER_DEFINED); @@ -438,8 +424,8 @@ public class NamespaceManagerTest extends AbstractGhidraHeadedIntegrationTest { } -@Test - public void testNamespaceIteratorForOverlaps2() throws Exception { + @Test + public void testNamespaceIteratorForOverlaps2() throws Exception { GhidraClass classNamespace = symbolMgr.createClass(null, "TestNamespaceClass", SourceType.USER_DEFINED); @@ -497,7 +483,8 @@ public class NamespaceManagerTest extends AbstractGhidraHeadedIntegrationTest { } private void addBlock(String name, Address addr, int length) throws Exception { - program.getMemory().createInitializedBlock(name, addr, length, (byte) 0, - TaskMonitorAdapter.DUMMY_MONITOR, false); + program.getMemory() + .createInitializedBlock(name, addr, length, (byte) 0, + TaskMonitorAdapter.DUMMY_MONITOR, false); } } 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 bbca195866..1125ccc692 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 @@ -1389,7 +1389,7 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest { Listing listing = program.getListing(); Symbol s = createSymbol(addr(100), "fred"); - assertTrue(s.checkIsValid()); + assertFalse(s.isDeleted()); AddressSet set = new AddressSet(); set.addRange(addr(100), addr(150)); @@ -1400,11 +1400,11 @@ public class SymbolManagerTest extends AbstractGhidraHeadedIntegrationTest { Parameter p = f.addParameter(new ParameterImpl(null, ByteDataType.dataType, program), SourceType.DEFAULT); Symbol paramSym = p.getSymbol(); - assertTrue(paramSym.checkIsValid()); + assertFalse(paramSym.isDeleted()); listing.removeFunction(addr(100)); - assertTrue(!paramSym.checkIsValid()); + assertTrue(paramSym.isDeleted()); Symbol s1 = st.getPrimarySymbol(addr(100)); assertNotNull(s1); diff --git a/Ghidra/Features/Base/src/test/java/ghidra/program/database/code/DefaultDataCacheTest.java b/Ghidra/Features/Base/src/test/java/ghidra/program/database/code/DefaultDataCacheTest.java index d7d6a92c29..1ed130a622 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/program/database/code/DefaultDataCacheTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/program/database/code/DefaultDataCacheTest.java @@ -15,8 +15,7 @@ */ package ghidra.program.database.code; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; import org.junit.*; @@ -80,12 +79,12 @@ public class DefaultDataCacheTest extends AbstractGenericTest { assertTrue(cu instanceof Data); DataDB data = (DataDB) cu; assertTrue(!data.isDefined()); - assertTrue(!data.isInvalid()); + assertTrue(!((Boolean) invokeInstanceMethod("isInvalid", data))); AddressSet restrictedSet = new AddressSet(addr(0x1000), addr(0x1003)); Disassembler disassembler = Disassembler.getDisassembler(program, TaskMonitor.DUMMY, null); AddressSetView disAddrs = disassembler.disassemble(addr(0x1000), restrictedSet); assertTrue(!disAddrs.isEmpty()); - assertTrue(!data.checkIsValid()); + assertTrue(!((Boolean) invokeInstanceMethod("checkIsValid", data))); assertNull(listing.getCodeUnitAt(addr(0x1001))); } diff --git a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/TypeDescriptorModel.java b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/TypeDescriptorModel.java index be3f76b784..7de2248c3c 100644 --- a/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/TypeDescriptorModel.java +++ b/Ghidra/Features/MicrosoftCodeAnalyzer/src/main/java/ghidra/app/cmd/data/TypeDescriptorModel.java @@ -30,7 +30,6 @@ import ghidra.program.model.mem.Memory; import ghidra.program.model.scalar.Scalar; import ghidra.program.model.symbol.Namespace; import ghidra.program.model.symbol.Symbol; -import ghidra.program.model.util.AddressSetPropertyMap; import ghidra.util.exception.AssertException; import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; @@ -615,7 +614,7 @@ public class TypeDescriptorModel extends AbstractCreateDataTypeModel { if (nsSymbol == null) { return false; // global namespace. } - return !nsSymbol.checkIsValid(); + return nsSymbol.isDeleted(); } /** diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/DatabaseObject.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/DatabaseObject.java index 44b9fd4100..af82eeb060 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/DatabaseObject.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/DatabaseObject.java @@ -26,7 +26,7 @@ import ghidra.util.Lock; * been deleted. Instantiating an object will cause it to be added immediately to the associated * cache. */ -abstract public class DatabaseObject { +public abstract class DatabaseObject { protected long key; private volatile boolean deleted; @@ -41,7 +41,7 @@ abstract public class DatabaseObject { * @param key database key to uniquely identify this object */ @SuppressWarnings("unchecked") - public DatabaseObject(@SuppressWarnings("rawtypes") DBObjectCache cache, long key) { + protected DatabaseObject(@SuppressWarnings("rawtypes") DBObjectCache cache, long key) { this.key = key; this.cache = cache; if (cache != null) { @@ -64,17 +64,6 @@ abstract public class DatabaseObject { deleted = true; } - /** - * Returns true if this object has been deleted. Note: once an object has been deleted, it will - * never be "refreshed". For example, if an object is ever deleted and is resurrected via an - * "undo", you will have get a fresh instance of the object. - * - * @return true if this object has been deleted. - */ - public boolean isDeleted() { - return deleted; - } - /** * * Invalidate this object. This does not necessarily mean that this object can never be used @@ -101,21 +90,28 @@ abstract public class DatabaseObject { } /** - * Returns true if object is currently invalid. Calling checkIsValid may successfully refresh - * object making it valid. + * Returns true if object is currently invalid and must be validated prior to further use. + * An invalid object may result from a cache invalidation which corresponds to wide-spread + * record changes. A common situation where this can occur is an undo/redo operation + * against the underlying database. The methods {@link #checkIsValid()}, {@link #checkDeleted()}, + * {@link #validate(Lock)} and {@link #isDeleted(Lock)} are methods which will force + * a re-validation if required. * - * @see #checkIsValid() + * @return true if this object is invalid and must be re-validated, else false if object state + * is currently valid which may include a deleted state. */ - public boolean isInvalid() { - return invalidateCount != getCurrentValidationCount(); + protected boolean isInvalid() { + return !deleted && invalidateCount != getCurrentValidationCount(); } /** * Checks if this object has been deleted, in which case any use of the object is not allowed. + * This method should be invoked before any modifications to the object are performed to + * ensure it still exists and is in a valid state. * * @throws ConcurrentModificationException if the object has been deleted from the database. */ - public void checkDeleted() { + protected void checkDeleted() { if (!checkIsValid()) { throw new ConcurrentModificationException("Object has been deleted."); } @@ -125,9 +121,9 @@ abstract public class DatabaseObject { * Check whether this object is still valid. If the object is invalid, the object will attempt * to refresh itself. If the refresh fails, the object will be marked as deleted. * - * @return true if the object is valid. + * @return true if the object is valid, else false if deleted */ - public boolean checkIsValid() { + protected boolean checkIsValid() { return checkIsValid(null); } @@ -140,10 +136,7 @@ abstract public class DatabaseObject { * @param record optional record which may be used to refresh invalid object * @return true if the object is valid. */ - public boolean checkIsValid(DBRecord record) { - if (deleted) { - return false; - } + protected boolean checkIsValid(DBRecord record) { if (isInvalid()) { setValid();// prevent checkIsValid recursion during refresh if (!refresh(record)) { @@ -162,10 +155,10 @@ abstract public class DatabaseObject { * invalid, then the lock will be used to refresh as needed. * * @param lock the lock that will be used if the object needs to be refreshed. - * @return true if object is valid, else false + * @return true if object is valid, else false if deleted */ - public boolean validate(Lock lock) { - if (!deleted && !isInvalid()) { + protected boolean validate(Lock lock) { + if (!isInvalid()) { return true; } lock.acquire(); @@ -177,6 +170,18 @@ abstract public class DatabaseObject { } } + /** + * Returns true if this object has been deleted. Note: once an object has been deleted, it will + * never be "refreshed". For example, if an object is ever deleted and is resurrected via an + * "undo", you will have get a fresh instance of the object. + * + * @param lock object cache lock object + * @return true if this object has been deleted. + */ + public boolean isDeleted(Lock lock) { + return deleted || !validate(lock); + } + /** * Tells the object to refresh its state from the database. * diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CategoryDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CategoryDB.java index b9394d8b60..3ae42fb263 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CategoryDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CategoryDB.java @@ -19,8 +19,8 @@ import java.io.IOException; import java.util.*; import java.util.concurrent.ConcurrentHashMap; -import db.Field; import db.DBRecord; +import db.Field; import ghidra.program.database.DBObjectCache; import ghidra.program.database.DatabaseObject; import ghidra.program.model.data.*; @@ -92,8 +92,7 @@ class CategoryDB extends DatabaseObject implements Category { } mgr.lock.acquire(); try { - checkIsValid(); - if (isRoot() || isDeleted()) { + if (!checkIsValid() || isRoot()) { categoryPath = CategoryPath.ROOT; } if (categoryPath == null) { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeDB.java index f585736d45..385460394f 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeDB.java @@ -216,7 +216,7 @@ abstract class DataTypeDB extends DatabaseObject implements DataType, ChangeList */ @Override public boolean isDeleted() { - return !checkIsValid(); + return isDeleted(lock); } /** 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 29477489f2..ac3559ac57 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 @@ -95,6 +95,11 @@ public class FunctionDB extends DatabaseObject implements Function { frame = new FunctionStackFrame(this); } + @Override + public boolean isDeleted() { + return isDeleted(manager.lock); + } + public void setValidationEnabled(boolean state) { validateEnabled = state; } @@ -105,6 +110,12 @@ public class FunctionDB extends DatabaseObject implements Function { entryPoint = functionSymbol.getAddress(); } + @Override + protected void checkDeleted() { + // expose method to function package + super.checkDeleted(); + } + @Override public boolean isThunk() { manager.lock.acquire(); @@ -853,8 +864,7 @@ public class FunctionDB extends DatabaseObject implements Function { private void renumberParameterOrdinals() { int ordinal = autoParams != null ? autoParams.size() : 0; - for (int i = 0; i < params.size(); i++) { - ParameterDB param = params.get(i); + for (ParameterDB param : params) { param.setOrdinal(ordinal++); } } @@ -1096,21 +1106,18 @@ public class FunctionDB extends DatabaseObject implements Function { loadVariables(); ArrayList list = new ArrayList<>(); if (autoParams != null) { - for (int i = 0; i < autoParams.size(); i++) { - Parameter p = autoParams.get(i); + for (AutoParameterImpl p : autoParams) { if (filter == null || filter.matches(p)) { list.add(p); } } } - for (int i = 0; i < params.size(); i++) { - Parameter p = params.get(i); + for (ParameterDB p : params) { if (filter == null || filter.matches(p)) { list.add(p); } } - for (int i = 0; i < locals.size(); i++) { - Variable var = locals.get(i); + for (VariableDB var : locals) { if (filter == null || filter.matches(var)) { list.add(var); } @@ -1140,15 +1147,13 @@ public class FunctionDB extends DatabaseObject implements Function { loadVariables(); ArrayList list = new ArrayList<>(); if (autoParams != null) { - for (int i = 0; i < autoParams.size(); i++) { - Parameter p = autoParams.get(i); + for (AutoParameterImpl p : autoParams) { if (filter == null || filter.matches(p)) { list.add(p); } } } - for (int i = 0; i < params.size(); i++) { - Parameter p = params.get(i); + for (ParameterDB p : params) { if (filter == null || filter.matches(p)) { list.add(p); } @@ -1176,8 +1181,7 @@ public class FunctionDB extends DatabaseObject implements Function { } loadVariables(); ArrayList list = new ArrayList<>(); - for (int i = 0; i < locals.size(); i++) { - Variable var = locals.get(i); + for (VariableDB var : locals) { if (filter == null || filter.matches(var)) { list.add(var); } @@ -1657,8 +1661,7 @@ public class FunctionDB extends DatabaseObject implements Function { } if (ordinal != params.size()) { // shift params to make room for inserted param - for (int i = 0; i < params.size(); i++) { - ParameterDB param = params.get(i); + for (ParameterDB param : params) { int paramOrdinal = param.getOrdinal(); if (paramOrdinal >= ordinal) { param.setOrdinal(paramOrdinal + 1); 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 5388c282ae..172d26b91e 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 @@ -505,7 +505,7 @@ public class FunctionManagerDB implements FunctionManager { try { FunctionDB func = cache.get(key); if (func != null) { - func.checkIsValid(); + func.checkDeleted(); func.createClassStructIfNeeded(); func.updateParametersAndReturn(); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionStackFrame.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionStackFrame.java index f0f6d0b1d5..54d6a4636d 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionStackFrame.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionStackFrame.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. @@ -16,6 +15,8 @@ */ package ghidra.program.database.function; +import java.util.*; + import ghidra.program.model.data.DataType; import ghidra.program.model.listing.*; import ghidra.program.model.pcode.Varnode; @@ -23,8 +24,6 @@ import ghidra.program.model.symbol.SourceType; import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.InvalidInputException; -import java.util.*; - class FunctionStackFrame implements StackFrame { // NOTE: Program stack frame may contain compound variables which have a stack component @@ -46,17 +45,17 @@ class FunctionStackFrame implements StackFrame { } boolean checkIsValid() { - if (function.checkIsValid()) { - if (invalid) { - stackGrowsNegative = - function.getFunctionManager().getProgram().getCompilerSpec().stackGrowsNegative(); - variables = function.getVariables(VariableFilter.COMPOUND_STACK_VARIABLE_FILTER); - Arrays.sort(variables, StackVariableComparator.get()); - invalid = false; - } - return true; + if (function.isDeleted()) { + return false; } - return false; + if (invalid) { + stackGrowsNegative = + function.getFunctionManager().getProgram().getCompilerSpec().stackGrowsNegative(); + variables = function.getVariables(VariableFilter.COMPOUND_STACK_VARIABLE_FILTER); + Arrays.sort(variables, StackVariableComparator.get()); + invalid = false; + } + return true; } void checkDeleted() { @@ -101,9 +100,9 @@ class FunctionStackFrame implements StackFrame { } } else { - for (int i = 0; i < params.length; i++) { - if (offset >= params[i].getLastStorageVarnode().getOffset()) { - ordinal = params[i].getOrdinal(); + for (Parameter param : params) { + if (offset >= param.getLastStorageVarnode().getOffset()) { + ordinal = param.getOrdinal(); } } } @@ -159,9 +158,9 @@ class FunctionStackFrame implements StackFrame { try { checkIsValid(); ArrayList list = new ArrayList(); - for (int i = 0; i < variables.length; i++) { - if (!(variables[i] instanceof Parameter)) { - list.add(variables[i]); + for (Variable variable : variables) { + if (!(variable instanceof Parameter)) { + list.add(variable); } } Variable[] vars = new Variable[list.size()]; @@ -182,9 +181,9 @@ class FunctionStackFrame implements StackFrame { try { checkIsValid(); ArrayList list = new ArrayList(); - for (int i = 0; i < variables.length; i++) { - if (variables[i] instanceof Parameter) { - list.add((Parameter) variables[i]); + for (Variable variable : variables) { + if (variable instanceof Parameter) { + list.add((Parameter) variable); } } Parameter[] vars = new Parameter[list.size()]; @@ -329,8 +328,8 @@ class FunctionStackFrame implements StackFrame { try { checkIsValid(); int cnt = 0; - for (int i = 0; i < variables.length; i++) { - if (variables[i] instanceof Parameter) { + for (Variable variable : variables) { + if (variable instanceof Parameter) { ++cnt; } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/references/ReferenceDBManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/references/ReferenceDBManager.java index f3f47f5be9..d773e80928 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/references/ReferenceDBManager.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/references/ReferenceDBManager.java @@ -25,7 +25,6 @@ import db.*; import db.util.ErrorHandler; import ghidra.program.database.*; import ghidra.program.database.external.ExternalManagerDB; -import ghidra.program.database.function.FunctionDB; import ghidra.program.database.map.AddressMap; import ghidra.program.database.symbol.*; import ghidra.program.model.address.*; @@ -638,13 +637,12 @@ public class ReferenceDBManager implements ReferenceManager, ManagerDB, ErrorHan lock.acquire(); try { Function function = var.getFunction(); - if (!(function instanceof FunctionDB) || function.getProgram() != program || - !((FunctionDB) function).checkIsValid()) { + if (function.getProgram() != program || function.isDeleted()) { return NO_REFS; } SymbolDB varSymbol = (SymbolDB) var.getSymbol(); - if (varSymbol != null && !varSymbol.checkIsValid()) { + if (varSymbol != null && varSymbol.isDeleted()) { return NO_REFS; } 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 cef6893c50..46e9e6b08c 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 @@ -82,6 +82,17 @@ public abstract class SymbolDB extends DatabaseObject implements Symbol { lock = symbolMgr.getLock(); } + @Override + public boolean isDeleted() { + return isDeleted(lock); + } + + @Override + protected void checkDeleted() { + // expose method to symbol package + super.checkDeleted(); + } + @Override public String toString() { return getName(); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/address/GlobalSymbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/address/GlobalSymbol.java index e4d50835a1..ea6a46ba06 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/address/GlobalSymbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/address/GlobalSymbol.java @@ -34,8 +34,8 @@ public class GlobalSymbol implements Symbol { } @Override - public boolean checkIsValid() { - return true; + public boolean isDeleted() { + return false; } @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Function.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Function.java index d8e0f388b4..48b7745998 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Function.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Function.java @@ -711,4 +711,11 @@ public interface Function extends Namespace { * symbol will be removed. */ public void promoteLocalUserLabelsToGlobal(); + + /** + * Determine if this function object has been deleted. NOTE: the function could be + * deleted at anytime due to asynchronous activity. + * @return true if function has been deleted, false if not. + */ + public boolean isDeleted(); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Variable.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Variable.java index b4fff77ae6..ce21eaf9cc 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Variable.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Variable.java @@ -109,6 +109,7 @@ public interface Variable extends Comparable { /** * Returns the function that contains this Variable. May be null if the variable is not in * a function. + * @return containing function or null */ public Function getFunction(); @@ -190,7 +191,7 @@ public interface Variable extends Comparable { /** * @return true if this is a simple variable consisting of a single register varnode * which will be returned by either the {@link #getFirstStorageVarnode()} or - * {@link getLastStorageVarnode()} methods. The register can be obtained using the + * {@link #getLastStorageVarnode()} methods. The register can be obtained using the * {@link #getRegister()} method. */ public boolean isRegisterVariable(); @@ -262,11 +263,13 @@ public interface Variable extends Comparable { /** * @return the symbol associated with this variable or null if no symbol * associated. Certain dynamic variables such as auto-parameters do not - * have a symbol. + * have a symbol and will return null. */ public Symbol getSymbol(); /** + * Determine is another variable is equivalent to this variable. + * @param variable other variable * @return true if the specified variable is equivalent to this variable */ public boolean isEquivalent(Variable variable); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/symbol/Symbol.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/symbol/Symbol.java index 2a49b9c8fd..6e2b97eacd 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/symbol/Symbol.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/symbol/Symbol.java @@ -40,12 +40,6 @@ public interface Symbol { */ public String getName(); - /** - * Check whether this symbol is still valid (i.e., deleted). - * @return true if valid or false if deleted. - */ - public boolean checkIsValid(); - /** * Gets the full path name for this symbol as an ordered array of strings ending * with the symbol name. The global symbol will return an empty array. @@ -67,12 +61,14 @@ public interface Symbol { public String getName(boolean includeNamespace); /** - * @return the namespace that contains this symbol + * Return the parent namespace for this symbol. + * @return the namespace that contains this symbol. */ public Namespace getParentNamespace(); /** * Returns namespace symbol of the namespace containing this symbol + * @return parent namespace symbol */ public Symbol getParentSymbol(); @@ -84,14 +80,16 @@ public interface Symbol { public boolean isDescendant(Namespace namespace); /** - * Returns whether the given parent is valid for this Symbol. - * @param parent + * Determines if the given parent is valid for this Symbol. Specified namespace + * must belong to the same symbol table as this symbol. + * @param parent prospective parent namespace for this symbol * @return true if parent is valid */ public boolean isValidParent(Namespace parent); /** - * Returns the symbol type + * Returns this symbol's type + * @return symbol type */ public SymbolType getSymbolType(); @@ -273,4 +271,11 @@ public interface Symbol { * @return the source of this symbol */ public SourceType getSource(); + + /** + * Determine if this symbol object has been deleted. NOTE: the symbol could be + * deleted at anytime due to asynchronous activity. + * @return true if symbol has been deleted, false if not. + */ + public boolean isDeleted(); } diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/FunctionTestDouble.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/FunctionTestDouble.java index 15b92d9482..dc3359a2bd 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/FunctionTestDouble.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/FunctionTestDouble.java @@ -47,6 +47,11 @@ public class FunctionTestDouble implements Function { functionSignature = signature; } + @Override + public boolean isDeleted() { + return false; + } + @Override public String toString() { return name;