From eeaa3486b8915c97eed192baf31fa2bc2ffa7d16 Mon Sep 17 00:00:00 2001 From: Dan <46821332+nsadeveloper789@users.noreply.github.com> Date: Wed, 2 Aug 2023 10:51:39 -0400 Subject: [PATCH] GP-3351: Purge TraceFunctionSymbol and related interfaces, impls, tables, etc. --- .../gui/listing/DebuggerListingProvider.java | 5 - .../ghidra/pcode/exec/DebuggerPcodeUtils.java | 10 +- .../listing/DBTraceCodeUnitAdapter.java | 16 +- .../AbstractDBTraceProgramViewListing.java | 22 +- .../database/program/DBTraceProgramView.java | 222 +- .../DBTraceProgramViewFunctionManager.java | 187 +- .../DBTraceProgramViewSymbolTable.java | 59 +- .../symbol/AbstractDBTraceVariableSymbol.java | 396 ---- .../symbol/DBTraceFunctionStackFrame.java | 329 --- .../symbol/DBTraceFunctionSymbol.java | 2009 ----------------- .../symbol/DBTraceFunctionSymbolView.java | 260 --- .../symbol/DBTraceGlobalVariableSymbol.java | 66 - .../DBTraceGlobalVariableSymbolView.java | 28 - .../database/symbol/DBTraceLabelSymbol.java | 5 - .../symbol/DBTraceLocalVariableSymbol.java | 123 - .../DBTraceLocalVariableSymbolView.java | 28 - .../symbol/DBTraceParameterSymbol.java | 220 -- .../symbol/DBTraceParameterSymbolView.java | 28 - .../database/symbol/DBTraceReference.java | 20 +- .../database/symbol/DBTraceSymbolManager.java | 359 +-- .../main/java/ghidra/trace/model/Trace.java | 38 - .../trace/model/symbol/TraceClassSymbol.java | 5 +- .../model/symbol/TraceClassSymbolView.java | 15 +- .../model/symbol/TraceFunctionSymbol.java | 81 - .../model/symbol/TraceFunctionSymbolView.java | 66 - .../symbol/TraceGlobalVariableSymbol.java | 21 - .../symbol/TraceGlobalVariableSymbolView.java | 21 - .../trace/model/symbol/TraceLabelSymbol.java | 10 +- .../model/symbol/TraceLabelSymbolView.java | 30 +- .../symbol/TraceLocalVariableSymbol.java | 22 - .../symbol/TraceLocalVariableSymbolView.java | 21 - .../model/symbol/TraceNamespaceSymbol.java | 8 + .../symbol/TraceNamespaceSymbolView.java | 14 +- .../model/symbol/TraceParameterSymbol.java | 22 - .../symbol/TraceParameterSymbolView.java | 21 - .../trace/model/symbol/TraceSymbol.java | 28 + .../model/symbol/TraceSymbolManager.java | 116 +- .../symbol/TraceSymbolNoDuplicatesView.java | 19 + .../trace/model/symbol/TraceSymbolView.java | 68 +- ...raceSymbolWithAddressNoDuplicatesView.java | 5 + .../symbol/TraceSymbolWithAddressView.java | 52 +- .../model/symbol/TraceSymbolWithLifespan.java | 23 + .../symbol/TraceSymbolWithLocationView.java | 65 +- .../model/symbol/TraceVariableSymbol.java | 23 - ...DBTraceProgramViewFunctionManagerTest.java | 435 ---- .../symbol/DBTraceFunctionSymbolTest.java | 1916 ---------------- .../symbol/DBTraceSymbolManagerTest.java | 36 +- .../core/codebrowser/CodeViewerProvider.java | 7 - .../plugin/core/function/FunctionPlugin.java | 5 +- .../ghidra/program/model/symbol/Symbol.java | 3 +- 50 files changed, 520 insertions(+), 7068 deletions(-) delete mode 100644 Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/AbstractDBTraceVariableSymbol.java delete mode 100644 Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceFunctionStackFrame.java delete mode 100644 Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceFunctionSymbol.java delete mode 100644 Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceFunctionSymbolView.java delete mode 100644 Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceGlobalVariableSymbol.java delete mode 100644 Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceGlobalVariableSymbolView.java delete mode 100644 Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceLocalVariableSymbol.java delete mode 100644 Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceLocalVariableSymbolView.java delete mode 100644 Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceParameterSymbol.java delete mode 100644 Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceParameterSymbolView.java delete mode 100644 Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceFunctionSymbol.java delete mode 100644 Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceFunctionSymbolView.java delete mode 100644 Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceGlobalVariableSymbol.java delete mode 100644 Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceGlobalVariableSymbolView.java delete mode 100644 Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceLocalVariableSymbol.java delete mode 100644 Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceLocalVariableSymbolView.java delete mode 100644 Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceParameterSymbol.java delete mode 100644 Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceParameterSymbolView.java delete mode 100644 Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceVariableSymbol.java delete mode 100644 Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceProgramViewFunctionManagerTest.java delete mode 100644 Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/symbol/DBTraceFunctionSymbolTest.java diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProvider.java index 07c0600635..6ca658c6a8 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProvider.java @@ -404,11 +404,6 @@ public class DebuggerListingProvider extends CodeViewerProvider { return !mode.canEdit(current); } - @Override - public boolean isDynamicListing() { - return true; - } - @Override public String getWindowGroup() { //TODO: Overriding this to align disconnected providers diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/pcode/exec/DebuggerPcodeUtils.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/pcode/exec/DebuggerPcodeUtils.java index d79cebc9f2..b31c7fd031 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/pcode/exec/DebuggerPcodeUtils.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/pcode/exec/DebuggerPcodeUtils.java @@ -102,9 +102,9 @@ public enum DebuggerPcodeUtils { * TODO: This may break things that check for the absence of a symbol * * I don't think it'll affect expressions, but it could later affect user Sleigh - * libraries than an expression might like to use. The better approach would be - * to incorporate a better error message into the Sleigh compiler, but it won't - * always know the use case for a clear message. + * libraries than an expression might like to use. The better approach would be to + * incorporate a better error message into the Sleigh compiler, but it won't always + * know the use case for a clear message. */ throw new SleighException("Unknown register or label: '" + nm + "'"); } @@ -114,9 +114,7 @@ public enum DebuggerPcodeUtils { protected SleighSymbol findUserSymbol(String nm) { Trace trace = coordinates.getTrace(); long snap = coordinates.getSnap(); - for (TraceSymbol symbol : trace.getSymbolManager() - .labelsAndFunctions() - .getNamed(nm)) { + for (TraceSymbol symbol : trace.getSymbolManager().labels().getNamed(nm)) { if (symbol instanceof TraceSymbolWithLifespan lifeSym && !lifeSym.getLifespan().contains(snap)) { continue; diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceCodeUnitAdapter.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceCodeUnitAdapter.java index 2d96c8a304..08f680b1e3 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceCodeUnitAdapter.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceCodeUnitAdapter.java @@ -224,11 +224,9 @@ public interface DBTraceCodeUnitAdapter extends TraceCodeUnit, MemBufferMixin { @Override default Symbol[] getSymbols() { try (LockHold hold = getTrace().lockRead()) { - Collection at = - getTrace().getSymbolManager() - .labelsAndFunctions() - .getAt(getStartSnap(), getThread(), - getAddress(), true); + Collection at = getTrace().getSymbolManager() + .labels() + .getAt(getStartSnap(), getThread(), getAddress(), true); return at.toArray(new TraceSymbol[at.size()]); } } @@ -236,11 +234,9 @@ public interface DBTraceCodeUnitAdapter extends TraceCodeUnit, MemBufferMixin { @Override default Symbol getPrimarySymbol() { try (LockHold hold = getTrace().lockRead()) { - Collection at = - getTrace().getSymbolManager() - .labelsAndFunctions() - .getAt(getStartSnap(), getThread(), - getAddress(), true); + Collection at = getTrace().getSymbolManager() + .labels() + .getAt(getStartSnap(), getThread(), getAddress(), true); if (at.isEmpty()) { return null; } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewListing.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewListing.java index 3a7ccd3573..22b316fd77 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewListing.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewListing.java @@ -37,7 +37,6 @@ import ghidra.trace.database.DBTrace; import ghidra.trace.database.guest.InternalTracePlatform; import ghidra.trace.database.listing.UndefinedDBTraceData; import ghidra.trace.database.memory.DBTraceMemorySpace; -import ghidra.trace.database.symbol.DBTraceFunctionSymbol; import ghidra.trace.database.thread.DBTraceThread; import ghidra.trace.model.*; import ghidra.trace.model.listing.*; @@ -45,7 +44,6 @@ import ghidra.trace.model.memory.TraceMemoryRegion; import ghidra.trace.model.program.TraceProgramView; import ghidra.trace.model.program.TraceProgramViewListing; import ghidra.trace.model.property.TracePropertyMapOperations; -import ghidra.trace.model.symbol.TraceFunctionSymbol; import ghidra.trace.util.*; import ghidra.util.*; import ghidra.util.AddressIteratorAdapter; @@ -867,13 +865,13 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV } @Override - public TraceFunctionSymbol createFunction(String name, Address entryPoint, AddressSetView body, + public Function createFunction(String name, Address entryPoint, AddressSetView body, SourceType source) throws InvalidInputException, OverlappingFunctionException { return program.functionManager.createFunction(name, entryPoint, body, source); } @Override - public TraceFunctionSymbol createFunction(String name, Namespace nameSpace, Address entryPoint, + public Function createFunction(String name, Namespace nameSpace, Address entryPoint, AddressSetView body, SourceType source) throws InvalidInputException, OverlappingFunctionException { return program.functionManager.createFunction(name, nameSpace, entryPoint, body, source); @@ -891,22 +889,12 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV @Override public List getGlobalFunctions(String name) { - return new ArrayList<>(program.trace.getSymbolManager().functions().getGlobalsNamed(name)); + return List.of(); } @Override public List getFunctions(String namespace, String name) { - // NOTE: This implementation allows namespaces to contain the separator symbol - List result = new ArrayList<>(); - for (DBTraceFunctionSymbol func : program.trace.getSymbolManager() - .functions() - .getNamed( - name)) { - if (namespace.equals(func.getParentNamespace().getName(true))) { - result.add(func); - } - } - return result; + return List.of(); } @Override @@ -916,7 +904,7 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV @Override public FunctionIterator getExternalFunctions() { - return program.functionManager.getExternalFunctions(); + return EmptyFunctionIterator.INSTANCE; } @Override diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramView.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramView.java index 32f694f636..66e28216e4 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramView.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramView.java @@ -47,10 +47,10 @@ import ghidra.trace.database.*; import ghidra.trace.database.listing.DBTraceCodeSpace; import ghidra.trace.database.listing.DBTraceDefinedUnitsView; import ghidra.trace.database.memory.DBTraceMemorySpace; -import ghidra.trace.database.symbol.DBTraceFunctionSymbolView; import ghidra.trace.model.*; import ghidra.trace.model.Trace.*; -import ghidra.trace.model.TraceTimeViewport.*; +import ghidra.trace.model.TraceTimeViewport.Occlusion; +import ghidra.trace.model.TraceTimeViewport.RangeQueryOcclusion; import ghidra.trace.model.bookmark.TraceBookmark; import ghidra.trace.model.bookmark.TraceBookmarkType; import ghidra.trace.model.data.TraceBasedDataTypeManager; @@ -129,22 +129,6 @@ public class DBTraceProgramView implements TraceProgramView { listenFor(TraceDataTypeChangeType.RENAMED, this::dataTypeRenamed); listenFor(TraceDataTypeChangeType.DELETED, this::dataTypeDeleted); - listenFor(TraceFunctionChangeType.CHANGED, this::functionChanged); - listenFor(TraceFunctionChangeType.CHANGED_PURGE, this::functionChangedPurge); - listenFor(TraceFunctionChangeType.CHANGED_INLINE, this::functionChangedInline); - listenFor(TraceFunctionChangeType.CHANGED_NORETURN, this::functionChangedNoReturn); - listenFor(TraceFunctionChangeType.CHANGED_CALL_FIXUP, this::functionChangedCallFixup); - listenFor(TraceFunctionChangeType.CHANGED_RETURN, this::functionChangedReturn); - listenFor(TraceFunctionChangeType.CHANGED_PARAMETERS, this::functionChangedParameters); - listenFor(TraceFunctionChangeType.CHANGED_THUNK, this::functionChangedThunk); - listenFor(TraceFunctionChangeType.CHANGED_BODY, this::functionChangedBody); - listenFor(TraceFunctionChangeType.TAG_APPLIED, this::functionChangedTagApplied); - listenFor(TraceFunctionChangeType.TAG_REMOVED, this::functionChangedTagRemoved); - - listenFor(TraceFunctionTagChangeType.ADDED, this::functionTagAdded); - listenFor(TraceFunctionTagChangeType.CHANGED, this::functionTagChanged); - listenFor(TraceFunctionTagChangeType.DELETED, this::functionTagDeleted); - listenFor(TraceInstructionChangeType.FLOW_OVERRIDE_CHANGED, this::instructionFlowOverrideChanged); listenFor(TraceInstructionChangeType.FALL_THROUGH_OVERRIDE_CHANGED, @@ -465,107 +449,6 @@ public class DBTraceProgramView implements TraceProgramView { null, null, oldPath, newIsNull)); } - private void gatherThunksTo(Collection into, - TraceFunctionSymbol function) { - into.add(function); - for (Address address : function.getFunctionThunkAddresses()) { - TraceFunctionSymbol thunkTo = functionManager.getFunctionAt(address); - if (thunkTo != null) { - gatherThunksTo(into, thunkTo); - } - } - } - - private Collection gatherThunksTo(TraceFunctionSymbol function) { - List result = new ArrayList<>(); - gatherThunksTo(result, function); - return result; - } - - private void functionChangedGeneric(TraceAddressSpace space, TraceFunctionSymbol function, - int type, int subType) { - DomainObjectEventQueues queues = isFunctionVisible(space, function); - if (queues == null) { - return; - } - for (TraceFunctionSymbol f : gatherThunksTo(function)) { - queues.fireEvent(new ProgramChangeRecord(type, subType, f.getEntryPoint(), - f.getEntryPoint(), f, null, null)); - } - } - - private void functionChanged(TraceAddressSpace space, TraceFunctionSymbol function) { - functionChangedGeneric(space, function, ChangeManager.DOCR_FUNCTION_CHANGED, 0); - } - - private void functionChangedPurge(TraceAddressSpace space, TraceFunctionSymbol function) { - functionChangedGeneric(space, function, ChangeManager.DOCR_FUNCTION_CHANGED, - ChangeManager.FUNCTION_CHANGED_PURGE); - } - - private void functionChangedInline(TraceAddressSpace space, TraceFunctionSymbol function) { - functionChangedGeneric(space, function, ChangeManager.DOCR_FUNCTION_CHANGED, - ChangeManager.FUNCTION_CHANGED_INLINE); - } - - private void functionChangedNoReturn(TraceAddressSpace space, - TraceFunctionSymbol function) { - functionChangedGeneric(space, function, ChangeManager.DOCR_FUNCTION_CHANGED, - ChangeManager.FUNCTION_CHANGED_NORETURN); - } - - private void functionChangedCallFixup(TraceAddressSpace space, - TraceFunctionSymbol function) { - functionChangedGeneric(space, function, ChangeManager.DOCR_FUNCTION_CHANGED, - ChangeManager.FUNCTION_CHANGED_CALL_FIXUP); - } - - private void functionChangedReturn(TraceAddressSpace space, TraceFunctionSymbol function) { - functionChangedGeneric(space, function, ChangeManager.DOCR_FUNCTION_CHANGED, - ChangeManager.FUNCTION_CHANGED_RETURN); - } - - private void functionChangedParameters(TraceAddressSpace space, - TraceFunctionSymbol function) { - functionChangedGeneric(space, function, ChangeManager.DOCR_FUNCTION_CHANGED, - ChangeManager.FUNCTION_CHANGED_PARAMETERS); - } - - private void functionChangedThunk(TraceAddressSpace space, TraceFunctionSymbol function) { - functionChangedGeneric(space, function, ChangeManager.DOCR_FUNCTION_CHANGED, - ChangeManager.FUNCTION_CHANGED_THUNK); - } - - private void functionChangedBody(TraceAddressSpace space, TraceFunctionSymbol function) { - functionChangedGeneric(space, function, ChangeManager.DOCR_FUNCTION_BODY_CHANGED, 0); - } - - private void functionChangedTagApplied(TraceAddressSpace space, - TraceFunctionSymbol function) { - functionChangedGeneric(space, function, ChangeManager.DOCR_TAG_ADDED_TO_FUNCTION, 0); - } - - private void functionChangedTagRemoved(TraceAddressSpace space, - TraceFunctionSymbol function) { - functionChangedGeneric(space, function, ChangeManager.DOCR_TAG_REMOVED_FROM_FUNCTION, - 0); - } - - private void functionTagAdded(FunctionTag tag) { - fireEventAllViews(new ProgramChangeRecord(ChangeManager.DOCR_FUNCTION_TAG_CREATED, null, - null, tag, null, null)); - } - - private void functionTagChanged(FunctionTag tag) { - fireEventAllViews(new ProgramChangeRecord(ChangeManager.DOCR_FUNCTION_TAG_CHANGED, null, - null, tag, null, null)); - } - - private void functionTagDeleted(FunctionTag tag) { - fireEventAllViews(new ProgramChangeRecord(ChangeManager.DOCR_FUNCTION_TAG_DELETED, null, - null, tag, null, null)); - } - private void instructionFlowOverrideChanged(TraceAddressSpace space, TraceInstruction instruction, FlowOverride oldOverride, FlowOverride newOverride) { DomainObjectEventQueues queues = isCodeVisible(space, instruction); @@ -667,39 +550,12 @@ public class DBTraceProgramView implements TraceProgramView { null, null, id, null, null)); } - private void checkVariableFunctionChanged(TraceAddressSpace space, TraceSymbol symbol) { - if (!(symbol instanceof TraceVariableSymbol)) { - return; - } - TraceFunctionSymbol function = ((TraceVariableSymbol) symbol).getFunction(); - if (function == null) { - return; - } - int subType = symbol instanceof TraceParameterSymbol ? // - ChangeManager.FUNCTION_CHANGED_PARAMETERS : 0; - for (TraceFunctionSymbol f : gatherThunksTo(function)) { - // NOTE: Should probably not see functions in register views anyway... - DomainObjectEventQueues queues = getEventQueues(space); - if (queues == null) { - continue; - } - queues.fireEvent(new ProgramChangeRecord(ChangeManager.DOCR_FUNCTION_CHANGED, - subType, f.getEntryPoint(), f.getEntryPoint(), f, null, null)); - } - } - private void symbolAdded(TraceAddressSpace space, TraceSymbol symbol) { DomainObjectEventQueues queues = isSymbolVisible(space, symbol); if (queues == null) { return; } fireSymbolAdded(queues, symbol); - if (symbol instanceof TraceFunctionSymbol) { - TraceFunctionSymbol function = (TraceFunctionSymbol) symbol; - queues.fireEvent(new ProgramChangeRecord(ChangeManager.DOCR_FUNCTION_ADDED, - function.getEntryPoint(), function.getEntryPoint(), function, null, null)); - } - checkVariableFunctionChanged(space, symbol); } public void fireSymbolAdded(DomainObjectEventQueues queues, TraceSymbol symbol) { @@ -714,7 +570,6 @@ public class DBTraceProgramView implements TraceProgramView { } queues.fireEvent(new ProgramChangeRecord(ChangeManager.DOCR_SYMBOL_SOURCE_CHANGED, symbol.getAddress(), symbol.getAddress(), symbol, null, null)); - checkVariableFunctionChanged(space, symbol); } private void symbolSetAsPrimary(TraceAddressSpace space, TraceSymbol symbol, @@ -731,7 +586,6 @@ public class DBTraceProgramView implements TraceProgramView { assert oldQueues == newQueues || oldQueues == null; newQueues.fireEvent(new ProgramChangeRecord(ChangeManager.DOCR_SYMBOL_SET_AS_PRIMARY, symbol.getAddress(), symbol.getAddress(), null, oldPrimary, newPrimary)); - checkVariableFunctionChanged(space, symbol); } private void symbolRenamed(TraceAddressSpace space, TraceSymbol symbol, String oldName, @@ -742,7 +596,6 @@ public class DBTraceProgramView implements TraceProgramView { } queues.fireEvent(new ProgramChangeRecord(ChangeManager.DOCR_SYMBOL_RENAMED, symbol.getAddress(), symbol.getAddress(), symbol, oldName, newName)); - checkVariableFunctionChanged(space, symbol); } private void symbolParentChanged(TraceAddressSpace space, TraceSymbol symbol, @@ -753,7 +606,6 @@ public class DBTraceProgramView implements TraceProgramView { } queues.fireEvent(new ProgramChangeRecord(ChangeManager.DOCR_SYMBOL_SCOPE_CHANGED, symbol.getAddress(), symbol.getAddress(), symbol, oldParent, newParent)); - checkVariableFunctionChanged(space, symbol); } private void symbolAssociationAdded(TraceAddressSpace space, TraceSymbol symbol, @@ -786,7 +638,6 @@ public class DBTraceProgramView implements TraceProgramView { } queues.fireEvent(new ProgramChangeRecord(ChangeManager.DOCR_SYMBOL_ADDRESS_CHANGED, oldAddress, oldAddress, symbol, oldAddress, newAddress)); - checkVariableFunctionChanged(space, symbol); } private void symbolLifespanChanged(TraceAddressSpace space, TraceSymbolWithLifespan symbol, @@ -799,20 +650,9 @@ public class DBTraceProgramView implements TraceProgramView { boolean inNew = isSymbolWithLifespanVisible(symbol, newSpan); if (inOld && !inNew) { fireSymbolRemoved(queues, symbol); - if (symbol instanceof TraceFunctionSymbol) { - TraceFunctionSymbol function = (TraceFunctionSymbol) symbol; - queues.fireEvent(new ProgramChangeRecord(ChangeManager.DOCR_FUNCTION_REMOVED, - function.getEntryPoint(), function.getEntryPoint(), function, - function.getBody(), null)); - } } if (!inOld && inNew) { fireSymbolAdded(queues, symbol); - if (symbol instanceof TraceFunctionSymbol) { - TraceFunctionSymbol function = (TraceFunctionSymbol) symbol; - queues.fireEvent(new ProgramChangeRecord(ChangeManager.DOCR_FUNCTION_ADDED, - function.getEntryPoint(), function.getEntryPoint(), function, null, null)); - } } } @@ -822,13 +662,6 @@ public class DBTraceProgramView implements TraceProgramView { return; } fireSymbolRemoved(queues, symbol); - if (symbol instanceof TraceFunctionSymbol) { - TraceFunctionSymbol function = (TraceFunctionSymbol) symbol; - queues.fireEvent(new ProgramChangeRecord(ChangeManager.DOCR_FUNCTION_REMOVED, - function.getEntryPoint(), function.getEntryPoint(), function, - function.getBody(), null)); - } - checkVariableFunctionChanged(space, symbol); } protected void fireSymbolRemoved(DomainObjectEventQueues queues, TraceSymbol symbol) { @@ -1775,51 +1608,8 @@ public class DBTraceProgramView implements TraceProgramView { return getEventQueues(space); } - protected Occlusion getFunctionOcclusion(TraceFunctionSymbol func) { - return new QueryOcclusion<>() { - DBTraceFunctionSymbolView functions = trace.getSymbolManager().functions(); - AddressSetView body = func.getBody(); - - @Override - public Iterable query(AddressRange range, - Lifespan span) { - // NB. No functions in register space! - return functions.getIntersecting(Lifespan.at(span.lmax()), null, range, false); - } - - public boolean itemOccludes(AddressRange range, TraceFunctionSymbol f) { - return body.intersects(f.getBody()); - } - - @Override - public void removeItem(AddressSet remains, TraceFunctionSymbol t) { - remains.delete(t.getBody()); - } - }; - } - - protected boolean isFunctionVisible(TraceFunctionSymbol function, Lifespan lifespan) { - AddressSetView body = function.getBody(); - AddressRange bodySpan = new AddressRangeImpl(body.getMinAddress(), body.getMaxAddress()); - return viewport.isCompletelyVisible(bodySpan, function.getLifespan(), function, - getFunctionOcclusion(function)); - } - - protected DomainObjectEventQueues isFunctionVisible(TraceAddressSpace space, - TraceFunctionSymbol function) { - DomainObjectEventQueues queues = getEventQueues(space); - if (queues == null) { - return null; - } - return isFunctionVisible(function, function.getLifespan()) ? queues : null; - } - protected boolean isSymbolWithLifespanVisible(TraceSymbolWithLifespan symbol, Lifespan lifespan) { - if (symbol instanceof TraceFunctionSymbol) { - TraceFunctionSymbol func = (TraceFunctionSymbol) symbol; - return isFunctionVisible(func, lifespan); - } if (!viewport.containsAnyUpper(lifespan)) { return false; } @@ -1832,14 +1622,6 @@ public class DBTraceProgramView implements TraceProgramView { if (queues == null) { return null; } - if (symbol instanceof TraceVariableSymbol) { - TraceVariableSymbol var = (TraceVariableSymbol) symbol; - TraceFunctionSymbol func = var.getFunction(); - if (func == null) { - return queues; - } - return isFunctionVisible(space, func); - } if (!(symbol instanceof TraceSymbolWithLifespan)) { return queues; } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewFunctionManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewFunctionManager.java index 216cf677c0..a205b4f14d 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewFunctionManager.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewFunctionManager.java @@ -15,28 +15,20 @@ */ package ghidra.trace.database.program; -import static ghidra.lifecycle.Unfinished.*; - import java.io.IOException; -import java.util.Collection; -import java.util.Iterator; +import java.util.*; +import java.util.stream.Stream; -import generic.NestedIterator; import ghidra.program.database.ProgramDB; import ghidra.program.database.function.OverlappingFunctionException; -import ghidra.program.model.address.*; +import ghidra.program.model.address.Address; +import ghidra.program.model.address.AddressSetView; import ghidra.program.model.lang.PrototypeModel; import ghidra.program.model.listing.*; import ghidra.program.model.symbol.Namespace; import ghidra.program.model.symbol.SourceType; -import ghidra.trace.database.DBTraceUtils; -import ghidra.trace.database.symbol.*; -import ghidra.trace.model.Lifespan; -import ghidra.trace.model.listing.TraceData; -import ghidra.trace.model.symbol.TraceFunctionSymbol; +import ghidra.trace.database.symbol.DBTraceNamespaceSymbol; import ghidra.trace.util.EmptyFunctionIterator; -import ghidra.trace.util.WrappingFunctionIterator; -import ghidra.util.LockHold; import ghidra.util.exception.CancelledException; import ghidra.util.exception.InvalidInputException; import ghidra.util.task.TaskMonitor; @@ -44,12 +36,10 @@ import ghidra.util.task.TaskMonitor; public class DBTraceProgramViewFunctionManager implements FunctionManager { protected final DBTraceProgramView program; - protected final DBTraceFunctionSymbolView functions; protected final DBTraceNamespaceSymbol global; public DBTraceProgramViewFunctionManager(DBTraceProgramView program) { this.program = program; - this.functions = program.trace.getSymbolManager().functions(); this.global = program.trace.getSymbolManager().getGlobalNamespace(); } @@ -60,135 +50,69 @@ public class DBTraceProgramViewFunctionManager implements FunctionManager { @Override public FunctionTagManager getFunctionTagManager() { - return TODO(); + throw new UnsupportedOperationException(); } @Override public Collection getCallingConventionNames() { - return functions.getCallingConventionNames(); + return Stream.of(program.trace.getBaseCompilerSpec().getCallingConventions()) + .map(PrototypeModel::getName) + .toList(); } @Override public PrototypeModel getDefaultCallingConvention() { - return functions.getDefaultCallingConvention(); + return program.trace.getBaseCompilerSpec().getDefaultCallingConvention(); } @Override public PrototypeModel getCallingConvention(String name) { - return functions.getCallingConvention(name); + return program.trace.getBaseCompilerSpec().getCallingConvention(name); } @Override - public TraceFunctionSymbol createFunction(String name, Address entryPoint, AddressSetView body, + public Function createFunction(String name, Address entryPoint, AddressSetView body, SourceType source) throws InvalidInputException, OverlappingFunctionException { - return functions.create(program.snap, entryPoint, body, name, null, global, source); - } - - protected static DBTraceNamespaceSymbol validateParent(Namespace nameSpace) { - if (!(nameSpace instanceof DBTraceNamespaceSymbol)) { - throw new IllegalArgumentException("Given namespace is not part of this trace"); - } - return (DBTraceNamespaceSymbol) nameSpace; - } - - protected static DBTraceFunctionSymbol validateThunked(Function thunked) { - if (!(thunked instanceof DBTraceFunctionSymbol)) { - throw new IllegalArgumentException("Given thunked function is not part of this trace"); - } - return (DBTraceFunctionSymbol) thunked; + throw new UnsupportedOperationException(); } @Override - public TraceFunctionSymbol createFunction(String name, Namespace nameSpace, Address entryPoint, + public Function createFunction(String name, Namespace nameSpace, Address entryPoint, AddressSetView body, SourceType source) throws InvalidInputException, OverlappingFunctionException { - return functions.create(program.snap, entryPoint, body, name, null, - validateParent(nameSpace), source); + throw new UnsupportedOperationException(); } @Override - public TraceFunctionSymbol createThunkFunction(String name, Namespace nameSpace, - Address entryPoint, AddressSetView body, Function thunkedFunction, SourceType source) + public Function createThunkFunction(String name, Namespace nameSpace, Address entryPoint, + AddressSetView body, Function thunkedFunction, SourceType source) throws OverlappingFunctionException { - try { - return functions.create(program.snap, entryPoint, body, name, - validateThunked(thunkedFunction), validateParent(nameSpace), source); - } - catch (InvalidInputException e) { - // TODO: Why not just declare this as thrown??? - throw new RuntimeException("Unexpected for default named function", e); - } + throw new UnsupportedOperationException(); } @Override public int getFunctionCount() { - return functions.size(false); // NOTE: May include those not at this snap + return 0; } @Override public boolean removeFunction(Address entryPoint) { - try (LockHold hold = program.trace.lockWrite()) { - TraceFunctionSymbol at = getFunctionAt(entryPoint); - if (at == null) { - return false; - } - at.delete(); - return true; - } + return false; } @Override - public TraceFunctionSymbol getFunctionAt(Address entryPoint) { - if (!entryPoint.getAddressSpace().isMemorySpace()) { - return null; - } - - for (long s : program.viewport.getOrderedSnaps()) { - // NOTE: There ought only to be one, since no overlaps allowed. - for (TraceFunctionSymbol at : functions.getAt(s, null, entryPoint, false)) { - if (entryPoint.equals(at.getEntryPoint())) { - return at; - } - else { - return null; // Anything below is occluded by the found function - } - } - } + public Function getFunctionAt(Address entryPoint) { return null; } @Override - public TraceFunctionSymbol getReferencedFunction(Address address) { - if (!address.getAddressSpace().isMemorySpace()) { - return null; - } - TraceFunctionSymbol found = getFunctionAt(address); - if (found != null) { - return found; - } - TraceData data = - program.getTopCode(address, (space, s) -> space.data().getContaining(s, address)); - if (data == null) { - return null; - } - DBTraceReference ref = program.trace.getReferenceManager() - .getPrimaryReferenceFrom(data.getStartSnap(), address, 0); - return ref == null ? null : getFunctionAt(ref.getToAddress()); - } - - @Override - public TraceFunctionSymbol getFunctionContaining(Address addr) { - // NOTE: There ought only to be one, since no overlaps allowed. - for (TraceFunctionSymbol at : functions.getAt(program.snap, null, addr, false)) { - return at; - } + public Function getReferencedFunction(Address address) { return null; } - protected Iterator getFunctionsInRange(AddressRange range, - boolean forward) { - return functions.getIntersecting(Lifespan.at(program.snap), null, range, false, - forward).iterator(); + @Override + public Function getFunctionContaining(Address addr) { + return null; } @Override @@ -198,52 +122,27 @@ public class DBTraceProgramViewFunctionManager implements FunctionManager { @Override public FunctionIterator getFunctions(Address start, boolean forward) { - return getFunctions(DBTraceUtils.getAddressSet(program.getAddressFactory(), start, forward), - forward); + return EmptyFunctionIterator.INSTANCE; } @Override public FunctionIterator getFunctions(AddressSetView asv, boolean forward) { - return new WrappingFunctionIterator( - NestedIterator.start(asv.iterator(forward), rng -> getFunctionsInRange(rng, forward)), - f -> { - if (!asv.contains(f.getEntryPoint())) { - return false; - } - return true; - }); + return EmptyFunctionIterator.INSTANCE; } @Override public FunctionIterator getFunctionsNoStubs(boolean forward) { - return getFunctionsNoStubs(program.getAddressFactory().getAddressSet(), forward); + return EmptyFunctionIterator.INSTANCE; } @Override public FunctionIterator getFunctionsNoStubs(Address start, boolean forward) { - return getFunctionsNoStubs( - DBTraceUtils.getAddressSet(program.getAddressFactory(), start, forward), forward); + return EmptyFunctionIterator.INSTANCE; } @Override public FunctionIterator getFunctionsNoStubs(AddressSetView asv, boolean forward) { - return new WrappingFunctionIterator( - NestedIterator.start(asv.iterator(forward), rng -> getFunctionsInRange(rng, forward)), - f -> { - if (f.isThunk()) { - return false; - } - if (!asv.contains(f.getEntryPoint())) { - return false; - } - if (program.trace.getCodeManager() - .instructions() - .getAt(program.snap, - f.getEntryPoint()) == null) { - return false; - } - return true; - }); + return EmptyFunctionIterator.INSTANCE; } @Override @@ -253,8 +152,7 @@ public class DBTraceProgramViewFunctionManager implements FunctionManager { @Override public boolean isInFunction(Address addr) { - // TODO: Could use idMap directly to avoid loading the function - return getFunctionContaining(addr) != null; + return false; } @Override @@ -266,12 +164,7 @@ public class DBTraceProgramViewFunctionManager implements FunctionManager { @Override public void deleteAddressRange(Address startAddr, Address endAddr, TaskMonitor monitor) throws CancelledException { - Iterator it = - getFunctionsInRange(new AddressRangeImpl(startAddr, endAddr), true); - while (it.hasNext()) { - monitor.checkCancelled(); - it.next().delete(); - } + // Do nothing } @Override @@ -287,28 +180,22 @@ public class DBTraceProgramViewFunctionManager implements FunctionManager { @Override public void invalidateCache(boolean all) { - throw new UnsupportedOperationException(); + // Do nothing } @Override public Iterator getFunctionsOverlapping(AddressSetView set) { - return new WrappingFunctionIterator( - NestedIterator.start(set.iterator(true), rng -> getFunctionsInRange(rng, true))); + return Collections.emptyIterator(); } @Override public Variable getReferencedVariable(Address instrAddr, Address storageAddr, int size, boolean isRead) { - TraceFunctionSymbol function = getFunctionContaining(instrAddr); - if (function == null) { - return null; - } - return DBTraceFunctionSymbolView.getReferencedVariable(function, instrAddr, storageAddr, - size, isRead, program.language); + return null; } @Override - public TraceFunctionSymbol getFunction(long key) { - return functions.getByKey(key); + public Function getFunction(long key) { + return null; } } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewSymbolTable.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewSymbolTable.java index 71fe609e2e..364cc20d26 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewSymbolTable.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewSymbolTable.java @@ -144,14 +144,9 @@ public class DBTraceProgramViewSymbolTable implements SymbolTable { } protected T requireVisible(T sym) { - if (!(sym instanceof TraceSymbolWithLifespan)) { + if (!(sym instanceof TraceSymbolWithLifespan wl)) { return sym; } - if (sym instanceof TraceFunctionSymbol) { - TraceFunctionSymbol function = (TraceFunctionSymbol) sym; - return program.isFunctionVisible(function, function.getLifespan()) ? sym : null; - } - TraceSymbolWithLifespan wl = (TraceSymbolWithLifespan) sym; if (program.viewport.containsAnyUpper(wl.getLifespan())) { return sym; } @@ -210,9 +205,7 @@ public class DBTraceProgramViewSymbolTable implements SymbolTable { TraceNamespaceSymbol parent = assertTraceNamespace(namespace); try (LockHold hold = program.trace.lockRead()) { List result = new ArrayList<>(); - for (TraceSymbol sym : symbolManager.labelsAndFunctions() - .getChildrenNamed(name, - parent)) { + for (TraceSymbol sym : symbolManager.labels().getChildrenNamed(name, parent)) { if (requireVisible(sym) != null) { result.add(sym); } @@ -239,17 +232,17 @@ public class DBTraceProgramViewSymbolTable implements SymbolTable { @Override public Symbol getParameterSymbol(String name, Namespace namespace) { - return symbolManager.parameters().getChildNamed(name, assertTraceNamespace(namespace)); + return null; } @Override public Symbol getLocalVariableSymbol(String name, Namespace namespace) { - return symbolManager.localVariables().getChildNamed(name, assertTraceNamespace(namespace)); + return null; } @Override public Symbol getVariableSymbol(String name, Function function) { - return symbolManager.allVariables().getChildNamed(name, assertTraceNamespace(function)); + return null; } @Override @@ -279,7 +272,7 @@ public class DBTraceProgramViewSymbolTable implements SymbolTable { public Symbol getPrimarySymbol(Address addr) { try (LockHold hold = program.trace.lockRead()) { Collection at = - symbolManager.labelsAndFunctions().getAt(program.snap, null, addr, true); + symbolManager.labels().getAt(program.snap, null, addr, true); if (at.isEmpty()) { return null; } @@ -291,7 +284,7 @@ public class DBTraceProgramViewSymbolTable implements SymbolTable { public Symbol[] getSymbols(Address addr) { try (LockHold hold = program.trace.lockRead()) { Collection at = - symbolManager.labelsAndFunctions().getAt(program.snap, null, addr, true); + symbolManager.labels().getAt(program.snap, null, addr, true); return at.toArray(new Symbol[at.size()]); } } @@ -307,7 +300,7 @@ public class DBTraceProgramViewSymbolTable implements SymbolTable { public Symbol[] getUserSymbols(Address addr) { try (LockHold hold = program.trace.lockRead()) { Collection at = - symbolManager.labelsAndFunctions().getAt(program.snap, null, addr, false); + symbolManager.labels().getAt(program.snap, null, addr, false); return at.toArray(new Symbol[at.size()]); } } @@ -331,10 +324,7 @@ public class DBTraceProgramViewSymbolTable implements SymbolTable { @Override public boolean hasSymbol(Address addr) { if (addr.isMemoryAddress()) { - return symbolManager.labelsAndFunctions().hasAt(program.snap, null, addr, true); - } - if (addr.getAddressSpace().isRegisterSpace() || addr.isStackAddress()) { - return symbolManager.allVariables().hasAt(addr, true); + return symbolManager.labels().hasAt(program.snap, null, addr, true); } return false; } @@ -360,23 +350,6 @@ public class DBTraceProgramViewSymbolTable implements SymbolTable { .getIntersecting(Lifespan.at(program.snap), null, range, true, forward) .iterator(); } - if (type == SymbolType.FUNCTION) { - return symbolManager.functions() - .getIntersecting(Lifespan.at(program.snap), null, range, true, forward) - .iterator(); - } - } - if (range.getAddressSpace().isRegisterSpace() || - range.getAddressSpace().isStackSpace()) { - if (type == SymbolType.PARAMETER) { - return symbolManager.parameters().getIntersecting(range, true).iterator(); - } - if (type == SymbolType.LOCAL_VAR) { - return symbolManager.localVariables().getIntersecting(range, true).iterator(); - } - if (type == SymbolType.GLOBAL_VAR) { - return symbolManager.globalVariables().getIntersecting(range, true).iterator(); - } } return Collections.emptyIterator(); })); @@ -437,8 +410,7 @@ public class DBTraceProgramViewSymbolTable implements SymbolTable { @Override public SymbolIterator getSymbolIterator(Address startAddr, boolean forward) { - return new SymbolIteratorAdapter(getSymbolIteratorAtMySnap( - symbolManager.labelsAndFunctions(), + return new SymbolIteratorAdapter(getSymbolIteratorAtMySnap(symbolManager.labels(), DBTraceUtils.getAddressSet(program.language.getAddressFactory(), startAddr, forward), true, forward)); } @@ -456,7 +428,7 @@ public class DBTraceProgramViewSymbolTable implements SymbolTable { @Override public SymbolIterator getPrimarySymbolIterator(AddressSetView asv, boolean forward) { return new PrimarySymbolIterator(NestedIterator.start(asv.iterator(forward), - range -> symbolManager.labelsAndFunctions() + range -> symbolManager.labels() .getIntersecting(Lifespan.at(program.snap), null, range, true, forward) .iterator())); } @@ -501,20 +473,13 @@ public class DBTraceProgramViewSymbolTable implements SymbolTable { // NOTE: Currently, traces do not allow namespaces to have arbitrary bodies. // Instead, their bodies are the union of addresses of their descendants. if (addr.isMemoryAddress()) { - for (TraceSymbol sym : symbolManager.labelsAndFunctions() - .getAt(program.snap, null, - addr, true)) { + for (TraceSymbol sym : symbolManager.labels().getAt(program.snap, null, addr, true)) { if (sym instanceof TraceNamespaceSymbol /* Function */) { return (TraceNamespaceSymbol) sym; } return sym.getParentNamespace(); } } - if (addr.getAddressSpace().isRegisterSpace() || addr.isStackAddress()) { - for (TraceSymbol sym : symbolManager.allVariables().getAt(addr, true)) { - return sym.getParentNamespace(); - } - } return symbolManager.getGlobalNamespace(); } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/AbstractDBTraceVariableSymbol.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/AbstractDBTraceVariableSymbol.java deleted file mode 100644 index 61ae964733..0000000000 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/AbstractDBTraceVariableSymbol.java +++ /dev/null @@ -1,396 +0,0 @@ -/* ### - * 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.trace.database.symbol; - -import java.io.IOException; -import java.util.List; -import java.util.Objects; - -import db.DBRecord; -import ghidra.program.database.data.DataTypeUtilities; -import ghidra.program.model.address.Address; -import ghidra.program.model.address.AddressSpace; -import ghidra.program.model.data.AbstractFloatDataType; -import ghidra.program.model.data.DataType; -import ghidra.program.model.lang.Register; -import ghidra.program.model.listing.*; -import ghidra.program.model.pcode.Varnode; -import ghidra.program.model.symbol.SourceType; -import ghidra.program.model.symbol.Symbol; -import ghidra.trace.database.symbol.DBTraceSymbolManager.DBTraceVariableStorageEntry; -import ghidra.trace.model.Trace.TraceSymbolChangeType; -import ghidra.trace.model.symbol.TraceVariableSymbol; -import ghidra.util.LockHold; -import ghidra.util.database.DBCachedObjectStore; -import ghidra.util.database.DBObjectColumn; -import ghidra.util.database.annot.DBAnnotatedColumn; -import ghidra.util.database.annot.DBAnnotatedField; -import ghidra.util.exception.InvalidInputException; - -/** - * TODO: Document me - * - * TODO: Somehow, this is supposed to generate {@link TraceSymbolChangeType#ADDRESS_CHANGED}. Find - * out how and be sure to implement it. - */ -public abstract class AbstractDBTraceVariableSymbol extends AbstractDBTraceSymbol - implements TraceVariableSymbol { - - static final String DATATYPE_COLUMN_NAME = "DataType"; - static final String STORAGE_COLUMN_NAME = "Storage"; - static final String COMMENT_COLUMN_NAME = "Comment"; - - @DBAnnotatedColumn(DATATYPE_COLUMN_NAME) - static DBObjectColumn DATATYPE_COLUMN; - @DBAnnotatedColumn(STORAGE_COLUMN_NAME) - static DBObjectColumn STORAGE_COLUMN; - @DBAnnotatedColumn(COMMENT_COLUMN_NAME) - static DBObjectColumn COMMENT_COLUMN; - - @DBAnnotatedField(column = DATATYPE_COLUMN_NAME) - private long dataTypeID; - @DBAnnotatedField(column = STORAGE_COLUMN_NAME) - private int storageID; - @DBAnnotatedField(column = COMMENT_COLUMN_NAME) - private String comment; - - protected DataType dataType; - protected VariableStorage storage; - protected Address address; - - public AbstractDBTraceVariableSymbol(DBTraceSymbolManager manager, DBCachedObjectStore store, - DBRecord record) { - super(manager, store, record); - } - - @Override - protected void fresh(boolean created) throws IOException { - super.fresh(created); - if (created) { - return; - } - dataType = manager.dataTypeManager.getDataType(dataTypeID); - DBTraceVariableStorageEntry storageEntry = manager.storageStore.getObjectAt(storageID); - if (storageEntry == null) { - throw new IOException( - "Database is corrupt. Cannot find VariableStorage entry " + storageID); - } - storage = storageEntry.getStorage(); - address = AddressSpace.VARIABLE_SPACE.getAddress(storageID); - } - - protected void set(String name, DBTraceNamespaceSymbol parent, DataType dt, - VariableStorage storage, SourceType source) { - super.set(name, parent, source); - this.dataTypeID = manager.dataTypeManager.getResolvedID(dt); - this.dataType = manager.dataTypeManager.getDataType(dataTypeID); - this.storageID = manager.findOrRecordVariableStorage(storage); - update(DATATYPE_COLUMN, STORAGE_COLUMN); - - this.storage = storage; - this.address = AddressSpace.VARIABLE_SPACE.getAddress(storageID); - } - - protected VariableStorage adjustStorage(VariableStorage s) { - return s; - } - - @Override - public String toString() { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - return String.format("[%s %s@%s]", getDataType().getName(), getName(), - getVariableStorage()); - } - } - - @Override - public Address getAddress() { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - return address; - } - } - - @Override - public Object getObject() { - return this; - } - - @Override - public Symbol getSymbol() { - return this; - } - - @Override - public int getLength() { - return getDataType().getLength(); - } - - @Override - public boolean isValid() { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - VariableStorage s = getVariableStorage(); // Overridden by DBTraceParameterSymbol - if (!s.isValid()) { - return false; - } - if (dataType instanceof AbstractFloatDataType) { - return true; - } - // NOTE: Use getDataType(), since storage may force indirection (pointer) - return s.size() == getDataType().getLength(); - } - } - - protected void doSetDataType(DataType dt) { - this.dataTypeID = manager.dataTypeManager.getResolvedID(dt); - this.dataType = manager.dataTypeManager.getDataType(dataTypeID); - update(DATATYPE_COLUMN); - } - - protected void doSetStorage(VariableStorage s) { - this.storage = s; - update(STORAGE_COLUMN); - } - - // NOTE: Must have the write lock - protected void doSetStorageAndDataType(VariableStorage s, DataType dt) { - doSetDataType(dt); - doSetStorage(adjustStorage(s)); - } - - protected void doUpdatesAfterSetDataType() { - // Extension point - } - - @Override - public void setDataType(DataType dt, VariableStorage s, boolean force, SourceType source) - throws InvalidInputException { - s = adjustStorage(s); - try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { - dt = VariableUtilities.checkDataType(dt, false, getLength(), getProgram()); - // NOTE: UNASSIGNED passes through - DBTraceFunctionSymbol function = getFunction(); - s = VariableUtilities.checkStorage(function, s, dt, force); - VariableUtilities.checkVariableConflict(function, this, s, force); - doSetStorageAndDataType(s, dt); - doUpdatesAfterSetDataType(); - } - } - - protected VariableStorage doDeriveStorageForSetDataType(DataType dt, boolean alignStack, - boolean force) throws InvalidInputException { - try { - VariableStorage s = VariableUtilities.resizeStorage(getVariableStorage(), dt, - alignStack, getFunction()); - VariableUtilities.checkStorage(s, dt, force); - VariableUtilities.checkVariableConflict(getFunction(), this, s, force); - return s; - } - catch (InvalidInputException e) { - if (!force) { - throw e; - } - return VariableStorage.UNASSIGNED_STORAGE; - } - } - - @Override - public void setDataType(DataType dt, boolean alignStack, boolean force, SourceType source) - throws InvalidInputException { - try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { - dt = VariableUtilities.checkDataType(dt, false, getLength(), getProgram()); - VariableStorage s = doDeriveStorageForSetDataType(dt, alignStack, force); - doSetStorageAndDataType(s, dt); - doUpdatesAfterSetDataType(); - } - } - - @Override - public void setDataType(DataType dt, SourceType source) throws InvalidInputException { - setDataType(dt, true, false, source); - } - - @Override - public DataType getDataType() { - return dataType; - } - - @Override - public abstract DBTraceFunctionSymbol getFunction(); - - @Override - public void setComment(String comment) { - try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { - this.comment = comment; - update(COMMENT_COLUMN); - } - } - - @Override - public String getComment() { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - return comment; - } - } - - @Override - public VariableStorage getVariableStorage() { - return storage; - } - - @Override - public Varnode getFirstStorageVarnode() { - VariableStorage s = getVariableStorage(); - return s == null ? null : s.getFirstVarnode(); - } - - @Override - public Varnode getLastStorageVarnode() { - VariableStorage s = getVariableStorage(); - return s == null ? null : s.getLastVarnode(); - } - - @Override - public boolean isStackVariable() { - VariableStorage s = getVariableStorage(); - return s == null ? false : s.isStackStorage(); - } - - @Override - public boolean hasStackStorage() { - VariableStorage s = getVariableStorage(); - return s == null ? false : s.hasStackStorage(); - } - - @Override - public boolean isRegisterVariable() { - VariableStorage s = getVariableStorage(); - return s == null ? false : s.isRegisterStorage(); - } - - @Override - public Register getRegister() { - VariableStorage s = getVariableStorage(); - return s == null ? null : s.getRegister(); - } - - @Override - public List getRegisters() { - VariableStorage s = getVariableStorage(); - return s == null ? null : s.getRegisters(); - } - - @Override - public Address getMinAddress() { - VariableStorage s = getVariableStorage(); - return s == null ? null : s.getMinAddress(); - } - - @Override - public int getStackOffset() { - VariableStorage s = getVariableStorage(); - if (s == null) { - throw new UnsupportedOperationException("Variable has no storage"); - } - return s.getStackOffset(); - } - - @Override - public boolean isMemoryVariable() { - VariableStorage s = getVariableStorage(); - return s == null ? false : s.isMemoryStorage(); - } - - @Override - public boolean isUniqueVariable() { - VariableStorage s = getVariableStorage(); - return s == null ? false : s.isHashStorage(); - } - - @Override - public boolean isCompoundVariable() { - VariableStorage s = getVariableStorage(); - return s == null ? false : s.isCompoundStorage(); - } - - @Override - public boolean hasAssignedStorage() { - VariableStorage s = getVariableStorage(); - return s == null ? false : !s.isUnassignedStorage(); - } - - protected static boolean doHasCustomStorage(Variable v) { - Function f = v.getFunction(); - return f == null || f.hasCustomVariableStorage(); - } - - public static boolean areEquivalent(Variable v1, Variable v2) { - if (v1 == null && v2 == null) { - return true; - } - if (v1 == null || v2 == null) { - return false; - } - if (v1 == v2) { - return true; - } - if ((v1 instanceof Parameter) != (v2 instanceof Parameter)) { - return false; - } - if (v1 instanceof Parameter) { - Parameter p1 = (Parameter) v1; - Parameter p2 = (Parameter) v2; - if (p1.getOrdinal() != p2.getOrdinal()) { - return false; - } - } - if (v1.getFirstUseOffset() != v2.getFirstUseOffset()) { - return false; - } - boolean eitherCustom = doHasCustomStorage(v1) || doHasCustomStorage(v2); - if (eitherCustom && !Objects.equals(v1.getVariableStorage(), v2.getVariableStorage())) { - return false; - } - if (!DataTypeUtilities.isSameOrEquivalentDataType(v1.getDataType(), v2.getDataType())) { - return false; - } - return true; - } - - @Override - public boolean isEquivalent(Variable variable) { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - return areEquivalent(this, variable); - } - } - - @Override - public int compareTo(Variable that) { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - return VariableUtilities.compare(this, that); - } - } - - @Override - public boolean delete() { - try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { - DBTraceFunctionSymbol function = getFunction(); - if (function != null) { - function.doDeleteVariable(this); - } - return super.delete(); - } - } -} diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceFunctionStackFrame.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceFunctionStackFrame.java deleted file mode 100644 index c971bc8802..0000000000 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceFunctionStackFrame.java +++ /dev/null @@ -1,329 +0,0 @@ -/* ### - * 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.trace.database.symbol; - -import static ghidra.lifecycle.Unfinished.TODO; - -import java.util.ArrayList; -import java.util.Arrays; - -import ghidra.lifecycle.Unfinished; -import ghidra.program.model.data.DataType; -import ghidra.program.model.listing.*; -import ghidra.program.model.pcode.Varnode; -import ghidra.program.model.symbol.SourceType; -import ghidra.util.LockHold; -import ghidra.util.exception.DuplicateNameException; -import ghidra.util.exception.InvalidInputException; - -public class DBTraceFunctionStackFrame implements StackFrame, Unfinished { - protected final DBTraceFunctionSymbol function; - protected Variable[] variables; - protected boolean growsNegative; - protected boolean valid; - - public DBTraceFunctionStackFrame(DBTraceFunctionSymbol function) { - this.function = function; - this.growsNegative = function.getTrace().getBaseCompilerSpec().stackGrowsNegative(); - this.valid = false; - } - - protected synchronized boolean checkIsValid() { - if (!function.isDeleted()) { - if (!valid) { - growsNegative = function.getTrace().getBaseCompilerSpec().stackGrowsNegative(); - variables = function.getVariables(VariableFilter.COMPOUND_STACK_VARIABLE_FILTER); - Arrays.sort(variables, StackVariableComparator.get()); - valid = true; - } - return true; - } - return false; - } - - @Override - public DBTraceFunctionSymbol getFunction() { - return function; - } - - @Override - public int getFrameSize() { - try (LockHold hold = LockHold.lock(function.manager.lock.readLock())) { - return getParameterSize() + getLocalSize(); - } - } - - @Override - public int getLocalSize() { - try (LockHold hold = LockHold.lock(function.manager.lock.readLock())) { - checkIsValid(); - - Integer base = VariableUtilities.getBaseStackParamOffset(function); - int baseOffset = base == null ? 0 : base.intValue(); - - if (growsNegative) { - if (variables.length == 0) { - return baseOffset; - } - Variable v = variables[0]; - if (!(v instanceof LocalVariable)) { - return baseOffset; - } - int offset = Math.max(0, (int) v.getLastStorageVarnode().getOffset()); - return baseOffset - offset; - } - // else Positive growth - if (variables.length == 0) { - return -baseOffset; - } - Variable v = variables[variables.length - 1]; - if (!(v instanceof LocalVariable)) { - return -baseOffset; - } - Varnode stackVarnode = v.getLastStorageVarnode(); - int len = stackVarnode.getSize(); - int offset = Math.max(0, (int) stackVarnode.getOffset()); - return offset - baseOffset + len; - } - } - - @Override - public int getParameterSize() { - try (LockHold hold = LockHold.lock(function.manager.lock.readLock())) { - checkIsValid(); - - Integer base = VariableUtilities.getBaseStackParamOffset(function); - int baseOffset = base == null ? 0 : base.intValue(); - - if (growsNegative) { - if (variables.length == 0) { - return 0; - } - Variable v = variables[variables.length - 1]; - if (!(v instanceof Parameter)) { - return 0; - } - Varnode stackVarnode = v.getLastStorageVarnode(); - int len = stackVarnode.getSize(); - int offset = (int) stackVarnode.getOffset(); - return offset - baseOffset + len; - } - // else Positive growth - if (variables.length == 0) { - return 0; - } - Variable v = variables[0]; - if (!(v instanceof Parameter)) { - return 0; - } - int offset = (int) v.getLastStorageVarnode().getOffset(); - return baseOffset - offset; - } - } - - @Override - public int getParameterOffset() { - Integer base = VariableUtilities.getBaseStackParamOffset(function); - return base == null ? UNKNOWN_PARAM_OFFSET : base.intValue(); - } - - @Override - public boolean isParameterOffset(int offset) { - Integer base = VariableUtilities.getBaseStackParamOffset(function); - if (base == null) { - return false; - } - if (growsNegative) { - return offset >= base.intValue(); - } - return offset < base.intValue(); - } - - @Override - public void setLocalSize(int size) { - // TODO: Is this ever called? - TODO(); - } - - @Override - public void setReturnAddressOffset(int offset) { - function.setReturnAddressOffset(offset); - } - - @Override - public int getReturnAddressOffset() { - return function.getReturnAddressOffset(); - } - - @Override - public Variable getVariableContaining(int offset) { - try (LockHold hold = LockHold.lock(function.manager.lock.readLock())) { - int index = Arrays.binarySearch(variables, offset, StackVariableComparator.get()); - if (index >= 0) { - return variables[index]; - } - /** - * index is -insertionPoint - 1 insertionPoint is index of first element greater than - * the key, i.e., where it would be inserted. We want the last element less than they - * key - */ - index = -index - 2; - if (index < 0) { - return null; - } - // We have the preceding variable. See if it contains the offset. - Variable var = variables[index]; - Varnode stackVarnode = var.getLastStorageVarnode(); - int varOffset = (int) stackVarnode.getOffset(); - if (offset < varOffset + stackVarnode.getSize()) { - return var; - } - return null; - } - } - - @Override - public AbstractDBTraceVariableSymbol createVariable(String name, int offset, DataType dataType, - SourceType source) throws DuplicateNameException, InvalidInputException { - try (LockHold hold = LockHold.lock(function.manager.lock.writeLock())) { - checkIsValid(); - if (dataType != null) { - dataType = dataType.clone(function.getTrace().getDataTypeManager()); - } - Variable var = new LocalVariableImpl(name, dataType, offset, function.getProgram()); - AbstractDBTraceVariableSymbol result; - if (isParameterOffset(offset)) { - // Compute ordinal - int ordinal = function.getParameterCount(); - Parameter[] params = getParameters(); - if (growsNegative) { - for (int i = params.length - 1; i >= 0; i--) { - Parameter p = params[i]; - if (offset <= p.getLastStorageVarnode().getOffset()) { - ordinal = p.getOrdinal(); - } - } - } - else { - for (int i = 0; i < params.length; i++) { - Parameter p = params[i]; - if (offset <= p.getLastStorageVarnode().getOffset()) { - ordinal = p.getOrdinal(); - } - } - } - - result = function.insertParameter(ordinal, var, source); - } - else { - result = function.addLocalVariable(var, source); - } - - /** - * TODO: The original implementation tries to implicitly enable custom storage if: - * - * 1) We're inserting a parameter, - * - * 2) Custom storage is not already enabled, and - * - * 3) The variable would not be stored where specified without custom storage - * - * Unless it is required or jarring to the user, I'm going to forego this rule. Let the - * user manually enable custom storage if precise parameter placement via this method is - * desired. - * - * The issue in the original implementation is: It detects (3) by inserting the variable - * and then checking where it was assigned storage. By this time, the function will have - * already re-assigned the other variables' storage. Despite that, the method re-assigns - * the new variable to the desired storage. This may leave the others in an unexpected - * or bad state. - * - * Perhaps it can be fixed: Instead of re-assigning the storage, deleting the new - * parameter, enable custom storage, and then re-insert the desired parameter. - */ - return result; - } - } - - @Override - public void clearVariable(int offset) { - try (LockHold hold = LockHold.lock(function.manager.lock.writeLock())) { - checkIsValid(); - Variable var = getVariableContaining(offset); - /** - * TODO: The original implementation implicitly enables custom storage if: - * - * 1) A variable exists at the given offset, and - * - * 2) Custom storage is not already enabled - * - * Unless it is required or jarring to the user, I'm going to forego this rule. Let the - * user manually enable custom storage if precise parameter placement via this method is - * desired. - */ - if (var != null) { - function.removeVariable(var); - } - } - } - - @Override - public Variable[] getStackVariables() { - try (LockHold hold = LockHold.lock(function.manager.lock.readLock())) { - checkIsValid(); - return Arrays.copyOf(variables, variables.length); - } - } - - @Override - public Parameter[] getParameters() { - try (LockHold hold = LockHold.lock(function.manager.lock.readLock())) { - checkIsValid(); - ArrayList list = new ArrayList(); - for (Variable v : variables) { - if (v instanceof Parameter) { - list.add((Parameter) v); - } - } - return list.toArray(new Parameter[list.size()]); - } - } - - @Override - public LocalVariable[] getLocals() { - try (LockHold hold = LockHold.lock(function.manager.lock.readLock())) { - checkIsValid(); - ArrayList list = new ArrayList(); - for (Variable v : variables) { - if (v instanceof LocalVariable) { - list.add((LocalVariable) v); - } - } - return list.toArray(new LocalVariable[list.size()]); - } - } - - @Override - public boolean growsNegative() { - try (LockHold hold = LockHold.lock(function.manager.lock.readLock())) { - return growsNegative; - } - } - - protected synchronized void invalidate() { - valid = false; - } -} diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceFunctionSymbol.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceFunctionSymbol.java deleted file mode 100644 index b3678a2333..0000000000 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceFunctionSymbol.java +++ /dev/null @@ -1,2009 +0,0 @@ -/* ### - * 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.trace.database.symbol; - -import java.io.IOException; -import java.util.*; - -import org.apache.commons.lang3.tuple.ImmutablePair; -import org.apache.commons.lang3.tuple.Pair; - -import db.DBRecord; -import ghidra.program.database.data.DataTypeManagerDB; -import ghidra.program.database.function.OverlappingFunctionException; -import ghidra.program.model.address.*; -import ghidra.program.model.data.*; -import ghidra.program.model.lang.CompilerSpec; -import ghidra.program.model.lang.PrototypeModel; -import ghidra.program.model.listing.*; -import ghidra.program.model.listing.VariableUtilities.VariableConflictHandler; -import ghidra.program.model.symbol.*; -import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter.AddressDBFieldCodec; -import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter.DecodesAddresses; -import ghidra.trace.database.bookmark.DBTraceBookmarkType; -import ghidra.trace.database.data.DBTraceDataTypeManager; -import ghidra.trace.database.listing.DBTraceCommentAdapter; -import ghidra.trace.database.listing.DBTraceData; -import ghidra.trace.database.program.DBTraceProgramView; -import ghidra.trace.database.symbol.DBTraceSymbolManager.DBTraceFunctionTag; -import ghidra.trace.database.symbol.DBTraceSymbolManager.DBTraceFunctionTagMapping; -import ghidra.trace.model.Lifespan; -import ghidra.trace.model.Trace.*; -import ghidra.trace.model.symbol.TraceFunctionSymbol; -import ghidra.trace.model.symbol.TraceLocalVariableSymbol; -import ghidra.trace.util.TraceChangeRecord; -import ghidra.util.LockHold; -import ghidra.util.Msg; -import ghidra.util.database.DBCachedObjectStore; -import ghidra.util.database.DBObjectColumn; -import ghidra.util.database.annot.*; -import ghidra.util.exception.DuplicateNameException; -import ghidra.util.exception.InvalidInputException; -import ghidra.util.task.TaskMonitor; - -/** - * The implementation of a function symbol, directly via a database object - * - *

- * Version history: - *

    - *
  • 1: Change {link #entryPoint} to 10-byte fixed encoding
  • - *
  • 0: Initial version and previous unversioned implementation
  • - *
- */ -@DBAnnotatedObjectInfo(version = 1) -public class DBTraceFunctionSymbol extends DBTraceNamespaceSymbol - implements TraceFunctionSymbol, DecodesAddresses { - @SuppressWarnings("hiding") - static final String TABLE_NAME = "Functions"; - - private static final byte CUSTOM_STORAGE_MASK = (byte) 0x80; - private static final byte CUSTOM_STORAGE_CLEAR = ~CUSTOM_STORAGE_MASK; - - private static final byte NO_RETURN_MASK = 0x40; - private static final byte NO_RETURN_CLEAR = ~NO_RETURN_MASK; - - private static final byte VAR_ARGS_MASK = 0x20; - private static final byte VAR_ARGS_CLEAR = ~VAR_ARGS_MASK; - - private static final byte INLINE_MASK = 0x10; - private static final byte INLINE_CLEAR = ~INLINE_MASK; - - static final String ENTRY_COLUMN_NAME = "Entry"; - static final String START_SNAP_COLUMN_NAME = "Start"; - static final String END_SNAP_COLUMN_NAME = "End"; - static final String THUNKED_COLUMN_NAME = "Thunked"; - // TODO: Why aren't fixups stored like calling conventions, by ID? Infrequent use? - static final String FIXUP_COLUMN_NAME = "Fixup"; - static final String CALLING_CONVENTION_COLUMN_NAME = "CallingConvention"; - static final String SIGNATURE_SOURCE_COLUMN_NAME = "SignatureSource"; - static final String STACK_PURGE_COLUMN_NAME = "StackPurge"; - static final String STACK_RETURN_OFFSET_COLUMN_NAME = "ReturnOffset"; - - @DBAnnotatedColumn(ENTRY_COLUMN_NAME) - static DBObjectColumn ENTRY_COLUMN; - @DBAnnotatedColumn(START_SNAP_COLUMN_NAME) - static DBObjectColumn START_SNAP_COLUMN; - @DBAnnotatedColumn(END_SNAP_COLUMN_NAME) - static DBObjectColumn END_SNAP_COLUMN; - @DBAnnotatedColumn(THUNKED_COLUMN_NAME) - static DBObjectColumn THUNKED_COLUMN; - @DBAnnotatedColumn(FIXUP_COLUMN_NAME) - static DBObjectColumn FIXUP_COLUMN; - @DBAnnotatedColumn(CALLING_CONVENTION_COLUMN_NAME) - static DBObjectColumn CALLING_CONVENTION_COLUMN; - @DBAnnotatedColumn(SIGNATURE_SOURCE_COLUMN_NAME) - static DBObjectColumn SIGNATURE_SOURCE_COLUMN; - @DBAnnotatedColumn(STACK_PURGE_COLUMN_NAME) - static DBObjectColumn STACK_PURGE_COLUMN; - @DBAnnotatedColumn(STACK_RETURN_OFFSET_COLUMN_NAME) - static DBObjectColumn STACK_RETURN_OFFSET_COLUMN; - - // Do I need to index entry, too? Not just body? - @DBAnnotatedField(column = ENTRY_COLUMN_NAME, codec = AddressDBFieldCodec.class) - protected Address entryPoint = Address.NO_ADDRESS; - @DBAnnotatedField(column = START_SNAP_COLUMN_NAME) - protected long startSnap; - @DBAnnotatedField(column = END_SNAP_COLUMN_NAME) - protected long endSnap; - @DBAnnotatedField(column = THUNKED_COLUMN_NAME, indexed = true) - protected long thunkedKey = -1; - @DBAnnotatedField(column = FIXUP_COLUMN_NAME) - protected String callFixup; - @DBAnnotatedField(column = CALLING_CONVENTION_COLUMN_NAME) - protected byte callingConventionID = DataTypeManagerDB.UNKNOWN_CALLING_CONVENTION_ID; - // TODO: Pack into flags if more bits needed - @DBAnnotatedField(column = SIGNATURE_SOURCE_COLUMN_NAME) - protected SourceType signatureSource = SourceType.ANALYSIS; // Assumed default, 0-ordinal - @DBAnnotatedField(column = STACK_PURGE_COLUMN_NAME) - protected int stackPurge; - @DBAnnotatedField(column = STACK_RETURN_OFFSET_COLUMN_NAME) - protected int stackReturnOffset; - - protected Lifespan lifespan; - protected DBTraceFunctionSymbol thunked; - - protected List locals; - protected List params; - protected DBTraceParameterSymbol ret; - protected List autoParams; - - protected final DBTraceFunctionStackFrame frame; - - protected boolean foundBadVariables = false; - - public DBTraceFunctionSymbol(DBTraceSymbolManager manager, DBCachedObjectStore store, - DBRecord record) { - super(manager, store, record); - this.frame = new DBTraceFunctionStackFrame(this); - } - - @Override - protected void fresh(boolean created) throws IOException { - super.fresh(created); - if (created) { - return; - } - - lifespan = Lifespan.span(startSnap, endSnap); - thunked = thunkedKey == -1 ? null : manager.functionStore.getObjectAt(thunkedKey); - } - - protected void set(Lifespan lifespan, Address entryPoint, String name, - DBTraceFunctionSymbol thunked, DBTraceNamespaceSymbol parent, SourceType source) { - // Recall: Signature source and symbol source are different fields - this.name = name; - this.parentID = parent.getID(); - doSetSource(source); - this.entryPoint = entryPoint; - this.startSnap = lifespan.lmin(); - this.endSnap = lifespan.lmax(); - this.thunkedKey = thunked == null ? -1 : thunked.getKey(); - - update(NAME_COLUMN, PARENT_COLUMN, START_SNAP_COLUMN, END_SNAP_COLUMN, FLAGS_COLUMN, - ENTRY_COLUMN, THUNKED_COLUMN); - - this.parent = parent; - this.lifespan = lifespan; - this.thunked = thunked; - } - - @Override - protected void validateNameAndParent(String newName, DBTraceNamespaceSymbol newParent) - throws DuplicateNameException { - /** - * Nothing. Since functions cannot overlap, and each's "address" is its entry point, there - * cannot possibly exist duplicate pairs. The existing checks subsume this - * check. - */ - } - - protected void doCreateReturnParameter() { - ret = manager.parameterStore.create(); - ret.set(Parameter.RETURN_NAME, this, DataType.DEFAULT, VariableStorage.UNASSIGNED_STORAGE, - Parameter.RETURN_ORIDINAL, SourceType.DEFAULT); - } - - protected static boolean isBadVariable(AbstractDBTraceVariableSymbol var) { - return var.getAddress() == Address.NO_ADDRESS || var.getVariableStorage().isBadStorage(); - } - - /** - * NOTE: Caller must have at least a read lock - */ - protected void doLoadVariables() { - if (!doLoadSymbolBasedVariables()) { - return; - } - // NOTE: Unlike FunctionDB, going to handle custom/dynamic storage at getters. - } - - protected boolean doLoadSymbolBasedVariables() { - if (locals != null) { - return false; - } - locals = new ArrayList<>(); - params = new ArrayList<>(); - for (DBTraceLocalVariableSymbol lVar : manager.localVars.getChildren(this)) { - // TODO: Check for bad variables / bad storage - locals.add(lVar); - } - for (DBTraceParameterSymbol pVar : manager.parameters.getChildren(this)) { - // TODO: Bad? - params.add(pVar); - } - // TODO: What is a bad variable? - locals.sort(VariableUtilities::compare); - params.sort(Comparator.comparing(DBTraceParameterSymbol::getOrdinal)); - ret = params.remove(0); - assert ret.getOrdinal() == Parameter.RETURN_ORIDINAL; - return true; - } - - protected void doRenumberParameterOrdinals() { - int ordinal = autoParams == null ? 0 : autoParams.size(); - for (DBTraceParameterSymbol param : params) { - param.setOrdinal(ordinal++); - } - } - - protected void doPurgeBadVariables() { - if (!foundBadVariables) { - return; - } - List badns = manager.allLocals.getChildren(this) - .stream() - .filter(DBTraceFunctionSymbol::isBadVariable) - .toList(); - if (badns.isEmpty()) { - return; - } - DBTraceBookmarkType errType = - manager.trace.getBookmarkManager().getOrDefineBookmarkType(BookmarkType.ERROR); - manager.trace.getBookmarkManager() - .addBookmark(getLifespan(), entryPoint, errType, "Bad Variables Removed", - "Removed " + badns.size() + " bad variables"); - for (AbstractDBTraceVariableSymbol s : badns) { - s.delete(); - } - if (hasCustomVariableStorage()) { - DBTraceParameterSymbol retVar = getReturn(); - if (retVar.getVariableStorage().isBadStorage()) { - DataType dt = retVar.getDataType(); - retVar.doSetStorageAndDataType(getDynamicReturnStorage(dt), dt); - } - } - } - - protected static SourceType max(SourceType a, SourceType b) { - return a == b || a.isHigherPriorityThan(b) ? a : b; - } - - protected void doUpdateSignatureSourceAfterVariableChange(SourceType source, DataType dt) { - if (Undefined.isUndefined(dt)) { - return; - } - SourceType highest = max(SourceType.ANALYSIS, max(source, signatureSource)); - if (signatureSource != highest) { - signatureSource = highest; - update(SIGNATURE_SOURCE_COLUMN); - } - } - - @Override - public Lifespan getLifespan() { - return lifespan; - } - - @Override - public long getStartSnap() { - return startSnap; - } - - @Override - public void setEndSnap(long endSnap) { - if (this.endSnap == endSnap) { - return; - } - try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { - Lifespan newLifespan = Lifespan.span(startSnap, endSnap); - this.endSnap = endSnap; - update(END_SNAP_COLUMN); - - Lifespan oldLifespan = lifespan; - this.lifespan = newLifespan; - - manager.trace.setChanged(new TraceChangeRecord<>(TraceSymbolChangeType.LIFESPAN_CHANGED, - getSpace(), this, oldLifespan, newLifespan)); - } - } - - @Override - public long getEndSnap() { - return endSnap; - } - - @Override - public SymbolType getSymbolType() { - return SymbolType.FUNCTION; - } - - @Override - protected Pair validateNameAndSource(String newName, SourceType newSource) - throws InvalidInputException { - if (newName == null || "".contentEquals(newName) || - SymbolUtilities.getDefaultFunctionName(entryPoint).equals(newName)) { - return new ImmutablePair<>("", SourceType.DEFAULT); - } - if (newSource == SourceType.DEFAULT) { - throw new IllegalArgumentException( - "Cannot assign non-default name with DEFAULT source"); - } - return new ImmutablePair<>(newName, newSource); - } - - @Override - public String getName() { - if (getSource() == SourceType.DEFAULT) { - if (thunked != null) { - if (thunked.getSource() == SourceType.DEFAULT && thunked.thunked == null) { - return "thunk_" + thunked.getName(); - } - return thunked.getName(); - } - return SymbolUtilities.getDefaultFunctionName(entryPoint); - } - return super.getName(); - } - - @Override - public Address getAddress() { - return entryPoint; - } - - @Override - public void setCallFixup(String newCallFixup) { - try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { - if (thunked != null) { - thunked.setCallFixup(newCallFixup); - return; - } - String oldCallFixup = this.callFixup; - if (Objects.equals(oldCallFixup, newCallFixup)) { - return; - } - this.callFixup = newCallFixup; - update(FIXUP_COLUMN); - manager.trace - .setChanged(new TraceChangeRecord<>(TraceFunctionChangeType.CHANGED_CALL_FIXUP, - getSpace(), this, oldCallFixup, newCallFixup)); - } - } - - @Override - public String getCallFixup() { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - if (thunked != null) { - return thunked.getCallFixup(); - } - return callFixup; - } - } - - public String getComment(int commentType) { - return manager.trace.getCommentAdapter().getComment(startSnap, entryPoint, commentType); - } - - @Override - public String getComment() { - return getComment(CodeUnit.PLATE_COMMENT); - } - - @Override - public String[] getCommentAsArray() { - return DBTraceCommentAdapter.arrayFromComment(getComment()); - } - - public void setComment(int commentType, String comment) { - manager.trace.getCommentAdapter().setComment(lifespan, entryPoint, commentType, comment); - } - - @Override - public void setComment(String comment) { - setComment(CodeUnit.PLATE_COMMENT, comment); - } - - @Override - public String getRepeatableComment() { - return getComment(CodeUnit.REPEATABLE_COMMENT); - } - - @Override - public String[] getRepeatableCommentAsArray() { - return DBTraceCommentAdapter.arrayFromComment(getRepeatableComment()); - } - - @Override - public void setRepeatableComment(String comment) { - setComment(CodeUnit.REPEATABLE_COMMENT, comment); - } - - @Override - public Address getEntryPoint() { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - return entryPoint; - } - } - - @Override - public DataType getReturnType() { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - return getReturn().getDataType(); - } - } - - @Override - public void setReturnType(DataType type, SourceType source) throws InvalidInputException { - try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { - getReturn().setDataType(type, source); - } - } - - @Override - public DBTraceParameterSymbol getReturn() { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - if (thunked != null) { - return thunked.getReturn(); - } - doLoadVariables(); - return ret; - } - } - - @Override - public void setReturn(DataType type, VariableStorage storage, SourceType source) - throws InvalidInputException { - try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { - if (thunked != null) { - thunked.setReturn(type, storage, source); - return; - } - type = type.clone(manager.dataTypeManager); - if (storage.isValid() && (storage.size() != type.getLength())) { - storage = VariableUtilities.resizeStorage(storage, type, true, this); - // TODO: Why does FunctionDB catch Exception and ignore here? - } - getReturn().setDataType(type, storage, true, source); - } - } - - @Override - public FunctionSignature getSignature() { - return getSignature(false); - } - - @Override - public FunctionSignature getSignature(boolean formalSignature) { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - if (thunked == null) { - doLoadVariables(); - } - return new FunctionDefinitionDataType(this, formalSignature); - } - } - - protected boolean hasExplicitCallingConvention() { - return callingConventionID != DataTypeManagerDB.DEFAULT_CALLING_CONVENTION_ID && - callingConventionID != DataTypeManagerDB.UNKNOWN_CALLING_CONVENTION_ID; - } - - @Override - public String getPrototypeString(boolean formalSignature, boolean includeCallingConvention) { - // TODO: Seems this could be extracted to a static utility.... - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - if (thunked == null) { - // NOTE: Can't use thunk's getPrototypeString, in case name is different. - doLoadVariables(); - } - StringBuilder sb = new StringBuilder(); - DBTraceParameterSymbol retVar = getReturn(); - sb.append((formalSignature ? retVar.getFormalDataType() : retVar.getDataType()) - .getDisplayName()); - sb.append(' '); - if (includeCallingConvention && hasExplicitCallingConvention()) { - String cc = getCallingConventionName(); - sb.append(cc); - sb.append(' '); - } - sb.append(getName()); - sb.append('('); - - Parameter[] parameters = getParameters(); - int n = parameters.length; - boolean emptyList = true; - for (int i = 0; i < n; i++) { - Parameter param = parameters[i]; - if (formalSignature && param.isAutoParameter()) { - continue; - } - DataType dt = formalSignature ? param.getFormalDataType() : param.getDataType(); - sb.append(dt.getDisplayName()); - sb.append(' '); - sb.append(param.getName()); - emptyList = false; - if (i < (n - 1)) { - sb.append(", "); - } - } - if (hasVarArgs()) { - sb.append(", "); - sb.append(FunctionSignature.VAR_ARGS_DISPLAY_STRING); - } - else if (emptyList && getSignatureSource() != SourceType.DEFAULT) { - sb.append(FunctionSignature.VOID_PARAM_DISPLAY_STRING); - } - sb.append(")"); - - return sb.toString(); - } - } - - @Override - public SourceType getSignatureSource() { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - if (thunked != null) { - return thunked.getSignatureSource(); - } - // Force DEFAULT if any param has unassigned storage - if (!getReturn().isValid()) { - return SourceType.DEFAULT; - } - for (Parameter param : getParameters()) { - if (!param.isValid()) { - return SourceType.DEFAULT; - } - } - return signatureSource; - } - } - - @Override - public void setSignatureSource(SourceType signatureSource) { - try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { - if (thunked != null) { - thunked.setSignatureSource(signatureSource); - return; - } - this.signatureSource = signatureSource; - update(SIGNATURE_SOURCE_COLUMN); - } - } - - @Override - public StackFrame getStackFrame() { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - if (thunked != null) { - return thunked.getStackFrame(); - } - return frame; - } - } - - @Override - public int getStackPurgeSize() { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - if (thunked != null) { - return thunked.getStackPurgeSize(); - } - return stackPurge; - } - } - - @Override - public Set getTags() { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - Set result = new HashSet<>(); - // TODO: Cache the result? - for (DBTraceFunctionTagMapping mapping : manager.tagMappingsByFunc.get(getKey())) { - result.add(manager.tagStore.getObjectAt(mapping.getTagKey())); - } - return result; - } - } - - @Override - public boolean addTag(String tagName) { - try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { - DBTraceFunctionTag tag = manager.tagsByName.getOne(tagName); - if (tag != null) { - for (DBTraceFunctionTagMapping mapping : manager.tagMappingsByFunc.get(getKey())) { - if (mapping.getTagKey() == tag.getKey()) { - return false; - } - } - } - else { - // TODO: Factor tag find/create to manager? - tag = manager.tagStore.create(); - tag.setName(tagName); - manager.trace.setChanged( - new TraceChangeRecord<>(TraceFunctionTagChangeType.ADDED, null, tag)); - } - DBTraceFunctionTagMapping mapping = manager.tagMappingStore.create(); - mapping.set(this, tag); - manager.trace.setChanged(new TraceChangeRecord<>(TraceFunctionChangeType.TAG_APPLIED, - getSpace(), this, null, tag)); - return true; - } - } - - @Override - public void removeTag(String tagName) { - try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { - DBTraceFunctionTag tag = manager.tagsByName.getOne(tagName); - if (tag == null) { - return; - } - for (DBTraceFunctionTagMapping mapping : manager.tagMappingsByFunc.get(getKey())) { - if (mapping.getTagKey() == tag.getKey()) { - manager.tagMappingStore.delete(mapping); - manager.trace.setChanged(new TraceChangeRecord<>( - TraceFunctionChangeType.TAG_REMOVED, getSpace(), this, tag, null)); - } - } - } - } - - @Override - public void setStackPurgeSize(int newStackPurge) { - try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { - if (thunked != null) { - thunked.setStackPurgeSize(newStackPurge); - return; - } - int oldStackPurge = this.stackPurge; - if (oldStackPurge == newStackPurge) { - return; - } - this.stackPurge = newStackPurge; - update(STACK_PURGE_COLUMN); - manager.trace.setChanged(new TraceChangeRecord<>(TraceFunctionChangeType.CHANGED_PURGE, - getSpace(), this, oldStackPurge, newStackPurge)); - } - } - - @Override - public boolean isStackPurgeSizeValid() { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - if (thunked != null) { - return thunked.isStackPurgeSizeValid(); - } - return stackPurge < 1 << 24; - } - } - - protected Variable resolveVariable(Variable var, boolean voidOK, boolean useUnassignedStorage) - throws InvalidInputException { - DataType dt = var.getDataType(); - if (var instanceof Parameter) { - dt = ((Parameter) var).getFormalDataType(); - } - DBTraceProgramView program = getProgram(); - dt = VariableUtilities.checkDataType(dt, voidOK, Math.min(1, var.getLength()), program); - DataType resolvedDt = manager.dataTypeManager.resolve(dt, null); - VariableStorage storage = VariableStorage.UNASSIGNED_STORAGE; - if (!useUnassignedStorage) { - storage = var.getVariableStorage(); - if (storage.isAutoStorage()) { - storage = new VariableStorage(program, storage.getVarnodes()); - } - if (resolvedDt.getLength() != storage.size()) { - storage = VariableUtilities.resizeStorage(storage, resolvedDt, true, this); - // TODO: Why does FunctionDB catch Exception and ignore? - } - } - - LocalVariableImpl resolvedVar = new LocalVariableImpl(var.getName(), - var.getFirstUseOffset(), resolvedDt, storage, true, program, var.getSource()); - resolvedVar.setComment(var.getComment()); - return resolvedVar; - } - - protected static VariableStorage getDynamicReturnStorage(DataType dt) { - DataType baseType = DBTraceData.getBaseDataType(dt); - return baseType instanceof VoidDataType ? VariableStorage.VOID_STORAGE - : VariableStorage.UNASSIGNED_STORAGE; - } - - protected void doUpdateParametersAndReturn() { - if (params == null) { - doLoadVariables(); - // Don't return, since my impl doesn't call me from load - } - - if (hasCustomVariableStorage()) { - autoParams = null; - doRenumberParameterOrdinals(); - return; - } - - DataType[] dataTypes = new DataType[params.size() + 1]; - // NOTE: Returned data type is affected by storage - // Set storage before getting data type. Can I use getFormalDataType instead. - for (int i = 0; i < params.size(); i++) { - DBTraceParameterSymbol param = params.get(i); - param.doSetDynamicStorage(VariableStorage.UNASSIGNED_STORAGE); - dataTypes[i + 1] = param.getDataType(); - } - - dataTypes[0] = ret.getFormalDataType(); - ret.doSetDynamicStorage(getDynamicReturnStorage(dataTypes[0])); - - PrototypeModel cc = getCallingConvention(); - if (cc == null) { - cc = manager.functions.getDefaultCallingConvention(); - } - if (cc == null) { - return; - } - - VariableStorage[] storages = cc.getStorageLocations(getProgram(), dataTypes, true); - ret.doSetDynamicStorage(storages[0]); - - int autoIndex = 0; - int paramIndex = 0; - - autoParams = null; - - for (int i = 1; i < storages.length; i++) { - VariableStorage s = storages[i]; - if (s.isAutoStorage()) { - if (autoParams == null) { - autoParams = new ArrayList<>(); - } - DataType dt = VariableUtilities.getAutoDataType(this, ret.getFormalDataType(), s); - try { - autoParams.add(new AutoParameterImpl(dt, autoIndex++, s, this)); - } - catch (InvalidInputException e) { - throw new AssertionError(e); - // TODO: Relax this? - } - } - else { - params.get(paramIndex++).doSetDynamicStorage(s); - } - } - doRenumberParameterOrdinals(); - } - - @Override - public DBTraceParameterSymbol addParameter(Variable var, SourceType source) - throws DuplicateNameException, InvalidInputException { - return insertParameter(getParameterCount(), var, source); - } - - @Override - public DBTraceParameterSymbol insertParameter(int ordinal, Variable var, SourceType source) - throws DuplicateNameException, InvalidInputException { - try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { - if (thunked != null) { - return thunked.insertParameter(ordinal, var, source); - } - doLoadVariables(); - doPurgeBadVariables(); - - int autoCnt = autoParams == null ? 0 : autoParams.size(); - - int index = ordinal - autoCnt; - if (index < 0 || index > params.size()) { - throw new IndexOutOfBoundsException("Ordinal value must be in [" + autoCnt + ".." + - (params.size() + autoCnt) + "]: " + ordinal); - } - assertNotUniqueSpace(var); - - boolean hasCustomStorage = hasCustomVariableStorage(); - if (hasCustomStorage) { - if (var.hasStackStorage()) { - int stackOffset = (int) var.getLastStorageVarnode().getOffset(); - if (!frame.isParameterOffset(stackOffset)) { - throw new InvalidInputException( - "Variable contains invalid stack parameter offset: " + var.getName() + - " offset " + stackOffset); - } - } - } - - var = resolveVariable(var, false, !hasCustomStorage); - - String varName = var.getName(); - SourceType paramSource = source; - // NOTE null and 0-length checks in isDefaultParameterName - if (paramSource == SourceType.DEFAULT || - SymbolUtilities.isDefaultParameterName(varName)) { - varName = ""; - paramSource = SourceType.DEFAULT; - } - - VariableStorage storage = var.getVariableStorage(); - if (!hasCustomStorage) { - storage = VariableStorage.UNASSIGNED_STORAGE; - } - else if (storage.isAutoStorage()) { - storage = new VariableStorage(getProgram(), storage.getVarnodes()); - } - - try { - // Check for overlapping parameter in storage - DBTraceParameterSymbol p = null; - if (storage != VariableStorage.UNASSIGNED_STORAGE) { - for (DBTraceParameterSymbol oldParam : params) { - if (oldParam.getVariableStorage().intersects(storage)) { - p = oldParam; - break; - } - VariableUtilities.checkVariableConflict(this, (p != null ? p : var), - storage, true); - } - } - if (p != null) { - // storage has been specified - // move and update existing parameter - if (index >= params.size()) { - index = params.size() - 1; - } - Msg.warn(this, "Inserting overlapping parameter for function " + this + " at " + - p.getVariableStorage() + " - Replacing existing parameter!"); - if (p.getOrdinal() - autoCnt != index) { - if (p != params.remove(p.getOrdinal() - autoCnt)) { - throw new AssertionError("Inconsistent function parameter cache"); - } - - params.add(index, p); - doUpdateParametersAndReturn(); - - manager.trace.setChanged( - new TraceChangeRecord<>(TraceSymbolChangeType.CHANGED, getSpace(), p)); - } - if (!"".equals(varName)) { - p.setName(varName, paramSource); - } - p.doSetStorageAndDataType(storage, var.getDataType()); - } - else { - // create a new parameter - if (index > params.size()) { - index = params.size(); - } - // NOTE: Removed ordinal modifications. Will be done in doUpdateParams... - p = manager.parameterStore.create(); - p.set(varName, this, var.getDataType(), storage, ordinal, paramSource); - params.add(index, p); - doUpdateParametersAndReturn(); - - manager.trace.setChanged( - new TraceChangeRecord<>(TraceSymbolChangeType.ADDED, getSpace(), p)); - } - if (var.getComment() != null) { - p.setComment(var.getComment()); - } - doUpdateSignatureSourceAfterVariableChange(source, p.getDataType()); - return p; - } - finally { - frame.invalidate(); - } - } - } - - @Override - public void replaceParameters(List newParams, FunctionUpdateType updateType, - boolean force, SourceType source) throws DuplicateNameException, InvalidInputException { - updateFunction(null, null, newParams, updateType, force, source); - } - - @Override - public void replaceParameters(FunctionUpdateType updateType, boolean force, SourceType source, - Variable... newParams) throws DuplicateNameException, InvalidInputException { - updateFunction(null, null, Arrays.asList(newParams), updateType, force, source); - } - - @Override - public void updateFunction(String callingConvention, Variable returnVar, - FunctionUpdateType updateType, boolean force, SourceType source, Variable... newParams) - throws DuplicateNameException, InvalidInputException { - updateFunction(callingConvention, returnVar, Arrays.asList(newParams), updateType, force, - source); - } - - protected static void doCheckForParameterNameConflict(Variable param, - Collection newParams, Collection nonParamNames) - throws DuplicateNameException { - String name = param.getName(); - - if (name == null || name.length() == 0 || SymbolUtilities.isDefaultParameterName(name)) { - return; - } - - for (Variable chk : newParams) { - if (param == chk) { - continue; - } - if (name.equals(chk.getName())) { - throw new DuplicateNameException("Duplicate parameter name '" + name + "'"); - } - } - if (nonParamNames.contains(name)) { - throw new DuplicateNameException("Duplicate variable name '" + name + "'"); - } - } - - protected void doCheckStorageConflicts(List newParams, - boolean removeConflictingLocals) throws VariableSizeException { - VariableConflictHandler localConflictHandler = removeConflictingLocals ? conflicts -> { - for (Variable var : conflicts) { - removeVariable(var); - } - return true; - } : null; - - for (Variable p : newParams) { - VariableUtilities.checkVariableConflict(newParams, p, p.getVariableStorage(), null); - VariableUtilities.checkVariableConflict(locals, p, p.getVariableStorage(), - localConflictHandler); - } - } - - protected static int findPointerParameterNamed(List params, String name) { - for (int i = 0; i < params.size(); i++) { - Variable p = params.get(i); - if (!(p.getDataType() instanceof Pointer)) { - continue; - } - if (!name.equals(p.getName())) { - continue; - } - return i; - } - return -1; - } - - protected static int findExplicitThisParameter(List params) { - return findPointerParameterNamed(params, THIS_PARAM_NAME); - } - - protected static boolean removeExplicitThisParameter(List params, - String callingConventionName) { - // TODO: Move this to VariableUtilities? - // TODO: Factor the one from FunctionDB, too. - if (!CompilerSpec.CALLING_CONVENTION_thiscall.equals(callingConventionName)) { - return false; - } - int thisIndex = findExplicitThisParameter(params); - if (thisIndex < 0) { - return false; - } - params.remove(thisIndex); - return true; - } - - protected boolean doRemoveExplicitThisParameter() { - if (!CompilerSpec.CALLING_CONVENTION_thiscall.equals(getCallingConventionName())) { - return false; - } - int thisIndex = findExplicitThisParameter(params); - if (thisIndex < 0) { - return false; - } - removeParameter(thisIndex); - return true; - } - - protected static int findExplicitReturnStorageParameter(List params) { - return findPointerParameterNamed(params, RETURN_PTR_PARAM_NAME); - } - - protected static boolean removeExplicitReturnStorageParameter(List params) { - int paramIndex = findExplicitReturnStorageParameter(params); - if (paramIndex < 0) { - return false; - } - params.remove(paramIndex); - return true; - } - - protected boolean doRemoveExplicitReturnStorageParameter() { - int paramIndex = findExplicitReturnStorageParameter(params); - if (paramIndex < 0) { - return false; - } - removeParameter(paramIndex); - return true; - } - - protected static Variable revertIndirectParameter(Variable param, boolean create) { - DataType dt = param.getDataType(); - if (!(dt instanceof Pointer)) { - return param; - } - Pointer pdt = (Pointer) dt; - try { - if (create) { - return new ParameterImpl(param.getName(), pdt.getDataType(), param.getProgram()); - } - else { - param.setDataType(pdt.getDataType(), VariableStorage.UNASSIGNED_STORAGE, false, - param.getSource()); - return param; - } - } - catch (InvalidInputException e) { - throw new AssertionError(e); - } - } - - protected static DataType revertTypeIfIndirect(DataType dt, VariableStorage s) { - if (!s.isForcedIndirect()) { - return dt; - } - if (!(dt instanceof Pointer)) { - return dt; - } - return ((Pointer) dt).getDataType(); - } - - protected static DataType getFormalDataTypeOf(Variable var) { - if (var instanceof Parameter) { - Parameter param = (Parameter) var; - return param.getFormalDataType(); - } - return var.getDataType(); - } - - protected static void assertNotUniqueSpace(Variable var) { - if (!var.isUniqueVariable()) { - return; - } - throw new IllegalArgumentException("Cannot use a unique-space variable"); - } - - @Override - public void updateFunction(String callingConvention, Variable returnVar, - List newParams, FunctionUpdateType updateType, boolean force, - SourceType source) throws DuplicateNameException, InvalidInputException { - try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { - if (thunked != null) { - thunked.updateFunction(callingConvention, returnVar, newParams, updateType, force, - source); - return; - } - doLoadVariables(); - doPurgeBadVariables(); - - boolean useCustomStorage = updateType == FunctionUpdateType.CUSTOM_STORAGE; - setCustomVariableStorage(useCustomStorage); - - if (callingConvention != null) { - setCallingConvention(callingConvention); - } - callingConvention = getCallingConventionName(); - - if (returnVar == null) { - returnVar = ret; - } - else if (returnVar == ret) { - // Do nothing - } - else { - returnVar.setName(Parameter.RETURN_NAME, returnVar.getSource()); - assertNotUniqueSpace(returnVar); - } - - DataType returnType = returnVar.getDataType(); - VariableStorage returnStorage = returnVar.getVariableStorage(); - - if (!useCustomStorage) { - // remove auto params and forced-indirect return - newParams = new ArrayList<>(newParams); // Going to edit - boolean thisParamRemoved = - removeExplicitThisParameter(newParams, callingConvention); - if (removeExplicitReturnStorageParameter(newParams)) { - returnVar = revertIndirectParameter(returnVar, true); - } - returnType = getFormalDataTypeOf(returnVar); - returnStorage = VariableStorage.UNASSIGNED_STORAGE; - - if (updateType == FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS && - !thisParamRemoved && - CompilerSpec.CALLING_CONVENTION_thiscall.contentEquals(callingConvention) && - newParams.size() != 0) { - // See FunctionDB's impl. It admits this is a hack. - // It'd be nice if all this fixing up were in some utilities.... - Variable firstParam = newParams.get(0); - if (firstParam.getSource() == SourceType.DEFAULT && - firstParam.getLength() == manager.dataTypeManager.getDataOrganization() - .getPointerSize()) { - newParams.remove(0); - } - } - } - - // Update return data type - getReturn().setDataType(returnType, returnStorage, true, source); - - Set nonParamNames = new HashSet<>(); - for (DBTraceLabelSymbol s : manager.labels.getChildren(this)) { - nonParamNames.add(s.getName()); - } - for (DBTraceLocalVariableSymbol s : manager.localVars.getChildren(this)) { - nonParamNames.add(s.getName()); - } - - // No conflicting names - // Resolve all types - List resolvedParams = new ArrayList<>(); - for (Variable p : newParams) { - if (!useCustomStorage && (p instanceof AutoParameterImpl)) { - continue; - } - assertNotUniqueSpace(p); - doCheckForParameterNameConflict(p, newParams, nonParamNames); - resolvedParams.add(resolveVariable(p, false, !useCustomStorage)); - } - newParams = resolvedParams; - - if (useCustomStorage) { - doCheckStorageConflicts(newParams, force); - } - - // Re-populate params list - List oldParams = params; - params = new ArrayList<>(); - - // Clear current param names - for (DBTraceParameterSymbol param : oldParams) { - param.setName(null, SourceType.DEFAULT); - } - - // Reassign old parameters if possible - int newParamIndex = 0; - for (; newParamIndex < oldParams.size() && - newParamIndex < newParams.size(); newParamIndex++) { - DBTraceParameterSymbol oldParam = oldParams.get(newParamIndex); - Variable newParam = newParams.get(newParamIndex); - DataType dt = getFormalDataTypeOf(newParam); - oldParam.setName(newParam.getName(), newParam.getSource()); - oldParam.doSetStorageAndDataType(newParam.getVariableStorage(), dt); - oldParam.setComment(newParam.getComment()); - params.add(oldParam); - manager.trace.setChanged( - new TraceChangeRecord<>(TraceSymbolChangeType.CHANGED, getSpace(), oldParam)); - } - // Remove unused old parameters - for (int i = newParamIndex; i < oldParams.size(); i++) { - oldParams.get(i).delete(); - // NOTE: Event produced by delete - } - // Append new parameters if needed - for (int i = newParamIndex; i < newParams.size(); i++) { - Variable newParam = newParams.get(i); - DataType dt = getFormalDataTypeOf(newParam); - VariableStorage storage = useCustomStorage ? newParam.getVariableStorage() - : VariableStorage.UNASSIGNED_STORAGE; - String newName = newParam.getName(); - if (newName == null || newName.length() == 0) { - newName = SymbolUtilities.getDefaultParamName(i); - } - DBTraceParameterSymbol s = manager.parameterStore.create(); - s.set(newName, this, dt, storage, i, newParam.getSource()); - s.setComment(newParam.getComment()); - params.add(s); - manager.trace.setChanged( - new TraceChangeRecord<>(TraceSymbolChangeType.ADDED, getSpace(), s)); - } - - if (source.isHigherPriorityThan(signatureSource)) { - signatureSource = source; - update(SIGNATURE_SOURCE_COLUMN); - } - - doUpdateParametersAndReturn(); - } - finally { - frame.invalidate(); - } - } - - // NOTE: Must be called with the write lock - protected void doDeleteVariable(AbstractDBTraceVariableSymbol var) { - if (isBadVariable(var)) { - return; // TODO: Investigate why - } - - doLoadVariables(); - - if (var instanceof DBTraceParameterSymbol) { - if (params.remove(var)) { - frame.invalidate(); - doUpdateParametersAndReturn(); - } - } - else { - if (locals.remove(var)) { - frame.invalidate(); - } - } - } - - @Override - public void removeParameter(int ordinal) { - try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { - if (thunked != null) { - thunked.removeParameter(ordinal); - return; - } - doLoadVariables(); - - int index = ordinal; - if (index < 0) { - throw new IndexOutOfBoundsException(ordinal); - } - if (autoParams != null) { - if (index < autoParams.size()) { - // Cannot remove auto parameter. Ignore - return; - } - index -= autoParams.size(); - } - if (index >= params.size()) { - throw new IndexOutOfBoundsException(ordinal); - } - params.get(ordinal).delete(); // Will call doDeleteVariable - } - } - - @Override - public Parameter moveParameter(int fromOrdinal, int toOrdinal) throws InvalidInputException { - if (toOrdinal < 0) { - throw new InvalidInputException("destination ordinal cannot be negative"); - } - try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { - if (thunked != null) { - return thunked.moveParameter(fromOrdinal, toOrdinal); - } - doLoadVariables(); - - if (fromOrdinal < 0) { - return null; - } - int autoCnt = autoParams == null ? 0 : autoParams.size(); - if (fromOrdinal < autoCnt || toOrdinal < autoCnt) { - throw new InvalidInputException( - "Neither source nor destination ordinal can be within auto-parameters"); - } - int fromIndex = fromOrdinal - autoCnt; - int toIndex = toOrdinal - autoCnt; - if (fromIndex > params.size()) { - return null; - } - DBTraceParameterSymbol param = params.get(fromIndex); - if (toIndex == fromIndex) { - return param; - } - params.remove(fromIndex); - if (toIndex >= params.size()) { - params.add(param); - } - else { - params.add(toIndex, param); - } - doUpdateParametersAndReturn(); - frame.invalidate(); - - manager.trace.setChanged(new TraceChangeRecord<>( - TraceFunctionChangeType.CHANGED_PARAMETERS, getSpace(), this)); - return param; - } - } - - @Override - public DBTraceLocalVariableSymbol addLocalVariable(Variable var, SourceType source) - throws DuplicateNameException, InvalidInputException { - try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { - if (thunked != null) { - return thunked.addLocalVariable(var, source); - } - doLoadVariables(); - doPurgeBadVariables(); - - var = resolveVariable(var, false, false); - - VariableStorage storage = var.getVariableStorage(); - int firstUseOffset = var.getFirstUseOffset(); - if (var.hasStackStorage() && firstUseOffset != 0) { - Msg.warn(this, "Stack variable first-use offset forced to 0 for function " + this + - " at " + storage); - firstUseOffset = 0; - } - - String varName = var.getName(); - // NOTE null and 0-length checks are in isDefaultLocalName - // NOTE: This is meant to be isDefaultParameterName - // The parameter names are protected for all variables - if (SymbolUtilities.isDefaultParameterName(varName)) { - varName = DEFAULT_LOCAL_PREFIX; - source = SourceType.DEFAULT; - } - - // Check for duplicate storage address - DBTraceLocalVariableSymbol lv = null; - for (DBTraceLocalVariableSymbol oldLocal : locals) { - if (oldLocal.getFirstUseOffset() == firstUseOffset && - oldLocal.getVariableStorage().intersects(storage)) { - lv = oldLocal; - break; - } - } - - try { - // TODO: validate enabled? - VariableUtilities.checkVariableConflict(this, (lv != null ? lv : var), storage, - true); - if (lv != null) { - // Update existing local - Msg.warn(this, "Adding overlapping local variable for function " + this + - " at " + lv.getVariableStorage() + " - Modifying existing variable!"); - if (!DEFAULT_LOCAL_PREFIX.equals(name)) { - lv.setName(varName, source); - } - lv.doSetStorageAndDataType(storage, var.getDataType()); - } - else { - // Create new local - lv = manager.localVarStore.create(); - lv.set(varName, this, var.getDataType(), storage, firstUseOffset, source); - locals.add(lv); - locals.sort(VariableUtilities::compare); - } - if (var.getComment() != null) { - lv.setComment(var.getComment()); - } - return lv; - } - finally { - frame.invalidate(); - } - } - } - - @Override - public void removeVariable(Variable var) { - try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { - if (thunked != null) { - thunked.removeVariable(var); - return; - } - doLoadVariables(); - - if (!(var instanceof AbstractDBTraceVariableSymbol)) { - return; - } - AbstractDBTraceVariableSymbol dbVar = (AbstractDBTraceVariableSymbol) var; - if (params.contains(dbVar) || locals.contains(dbVar)) { - dbVar.delete(); // Calls doDeleteVariable - } - } - } - - @Override - public Parameter getParameter(int ordinal) { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - if (thunked != null) { - return thunked.getParameter(ordinal); - } - doLoadVariables(); - if (ordinal == Parameter.RETURN_ORIDINAL) { - return ret; - } - if (autoParams != null) { - if (ordinal < autoParams.size()) { - return autoParams.get(ordinal); - } - ordinal -= autoParams.size(); - } - if (ordinal < params.size()) { - return params.get(ordinal); - } - return null; - } - } - - @Override - public int getParameterCount() { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - if (thunked != null) { - return thunked.getParameterCount(); - } - doLoadVariables(); - if (autoParams != null) { - return autoParams.size() + params.size(); - } - return params.size(); - } - } - - @Override - public int getAutoParameterCount() { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - if (thunked != null) { - return thunked.getAutoParameterCount(); - } - doLoadVariables(); - if (autoParams != null) { - return autoParams.size(); - } - return 0; - } - } - - @Override - public Parameter[] getParameters() { - return getParameters(null); - } - - protected void collect(Collection into, Collection from, - VariableFilter filter) { - if (from == null) { - return; - } - if (filter == null) { - into.addAll(from); - } - else { - from.stream().filter(v -> filter.matches(v)).forEach(into::add); - } - } - - @Override - public Parameter[] getParameters(VariableFilter filter) { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - if (thunked != null) { - return thunked.getParameters(filter); - } - doLoadVariables(); - List result = new ArrayList<>(); - collect(result, autoParams, filter); - collect(result, params, filter); - return result.toArray(new Parameter[result.size()]); - } - } - - @Override - public TraceLocalVariableSymbol[] getLocalVariables() { - return getLocalVariables(null); - } - - @Override - public TraceLocalVariableSymbol[] getLocalVariables(VariableFilter filter) { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - if (thunked != null) { - return thunked.getLocalVariables(filter); - } - doLoadVariables(); - List result = new ArrayList<>(); - collect(result, locals, filter); - return result.toArray(new TraceLocalVariableSymbol[result.size()]); - } - } - - @Override - public Variable[] getVariables(VariableFilter filter) { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - if (thunked != null) { - return thunked.getParameters(); - } - doLoadVariables(); - List result = new ArrayList<>(); - collect(result, autoParams, filter); - collect(result, params, filter); - collect(result, locals, filter); - return result.toArray(new Variable[result.size()]); - } - } - - @Override - public Variable[] getAllVariables() { - return getVariables(null); - } - - @Override - public void setBody(AddressSetView newBody) throws OverlappingFunctionException { - try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { - DBTraceFunctionSymbolView.assertProperSpace(entryPoint.getAddressSpace(), newBody); - if (!newBody.contains(entryPoint)) { - throw new IllegalArgumentException("Function body must contain the entry point"); - } - AddressSetView oldBody = this.getBody(); - if (oldBody.equals(newBody)) { - return; - } - manager.functions.assertNotOverlapping(this, getEntryPoint(), getLifespan(), newBody); - for (DBTraceLabelSymbol label : manager.labels.getChildren(this)) { - if (!newBody.contains(label.getAddress())) { - label.delete(); - } - } - long id = getID(); - manager.delID(null, entryPoint.getAddressSpace(), id); - for (AddressRange rng : newBody) { - manager.putID(lifespan, null, rng, id); - } - manager.trace.setChanged(new TraceChangeRecord<>(TraceFunctionChangeType.CHANGED_BODY, - getSpace(), this, oldBody, newBody)); - } - } - - protected byte getFlags() { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - if (thunked != null) { - return thunked.getFlags(); - } - return flags; - } - } - - protected void orFlags(byte with) { - try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { - if (thunked != null) { - thunked.orFlags(with); - return; - } - flags |= with; - update(FLAGS_COLUMN); - } - } - - protected void andFlags(byte with) { - try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { - if (thunked != null) { - thunked.orFlags(with); - return; - } - flags &= with; - update(FLAGS_COLUMN); - } - } - - @Override - public boolean hasVarArgs() { - return (getFlags() & VAR_ARGS_MASK) != 0; - } - - @Override - public void setVarArgs(boolean hasVarArgs) { - try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { - if (hasVarArgs() == hasVarArgs) { - return; - } - if (hasVarArgs) { - orFlags(VAR_ARGS_MASK); - } - else { - andFlags(VAR_ARGS_CLEAR); - } - manager.trace.setChanged(new TraceChangeRecord<>( - TraceFunctionChangeType.CHANGED_PARAMETERS, getSpace(), this)); - } - } - - @Override - public boolean isInline() { - return (getFlags() & INLINE_MASK) != 0; - } - - @Override - public void setInline(boolean isInline) { - try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { - if (isInline() == isInline) { - return; - } - if (isInline) { - orFlags(INLINE_MASK); - } - else { - andFlags(INLINE_CLEAR); - } - manager.trace.setChanged(new TraceChangeRecord<>(TraceFunctionChangeType.CHANGED_INLINE, - getSpace(), this, !isInline, isInline)); - } - } - - @Override - public boolean hasNoReturn() { - return (getFlags() & NO_RETURN_MASK) != 0; - } - - @Override - public void setNoReturn(boolean hasNoReturn) { - try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { - if (hasNoReturn() == hasNoReturn) { - return; - } - if (hasNoReturn) { - orFlags(NO_RETURN_MASK); - } - else { - andFlags(NO_RETURN_CLEAR); - } - manager.trace - .setChanged(new TraceChangeRecord<>(TraceFunctionChangeType.CHANGED_NORETURN, - getSpace(), this, !hasNoReturn, hasNoReturn)); - } - } - - @Override - public boolean hasCustomVariableStorage() { - return (getFlags() & CUSTOM_STORAGE_MASK) != 0; - } - - @Override - public void setCustomVariableStorage(boolean hasCustomVariableStorage) { - try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { - if (hasCustomVariableStorage == hasCustomVariableStorage()) { - return; - } - doLoadVariables(); - - if (!hasCustomVariableStorage) { - doRemoveExplicitThisParameter(); - if (doRemoveExplicitReturnStorageParameter()) { - revertIndirectParameter(ret, false); - } - } - - // get params and return prior to change - Parameter[] parameters = getParameters(); - HashMap oldStorages = new HashMap<>(params.size()); - HashMap oldFormalTypes = new HashMap<>(params.size()); - for (Parameter p : parameters) { - if (!p.isAutoParameter()) { - oldStorages.put(p, p.getVariableStorage()); - if (hasCustomVariableStorage == false) { - // Was custom - oldFormalTypes.put(p, - revertTypeIfIndirect(p.getFormalDataType(), p.getVariableStorage())); - } - else { - oldFormalTypes.put(p, p.getFormalDataType()); - } - } - } - - VariableStorage oldRetStorage = ret.getVariableStorage(); - DataType oldRetType = ret.getFormalDataType(); - - autoParams = null; - if (hasCustomVariableStorage) { - orFlags(CUSTOM_STORAGE_MASK); - } - else { - andFlags(CUSTOM_STORAGE_CLEAR); - } - - int ordinal = 0; - for (Parameter p : parameters) { - if (p.isAutoParameter()) { - // NOTE: If changing from custom to dynamic, we should encounter no auto params - try { - insertParameter(ordinal, new ParameterImpl(p, getProgram()), - SourceType.ANALYSIS); - ordinal++; - } - catch (DuplicateNameException e) { - Msg.info(this, - "Clobbered auto-parameter during transition to custom storage"); - // Otherwise, skip - } - } - else { - DBTraceParameterSymbol dbP = (DBTraceParameterSymbol) p; - VariableStorage oldStorage = oldStorages.get(p); - VariableStorage newStorage = - hasCustomVariableStorage ? oldStorage.clone(getProgram()) - : VariableStorage.UNASSIGNED_STORAGE; - DataType newType = manager.checkIndirection(oldStorage, oldFormalTypes.get(p)); - dbP.doSetStorageAndDataType(newStorage, newType); - } - } - - VariableStorage newRetStorage = - hasCustomVariableStorage ? oldRetStorage.clone(getProgram()) - : VariableStorage.UNASSIGNED_STORAGE; - DataType newRetType = manager.checkIndirection(oldRetStorage, oldRetType); - ret.doSetStorageAndDataType(newRetStorage, newRetType); - - if (!hasCustomVariableStorage) { - doUpdateParametersAndReturn(); - } - - manager.trace.setChanged(new TraceChangeRecord<>( - TraceFunctionChangeType.CHANGED_PARAMETERS, getSpace(), this)); - } - catch (InvalidInputException e) { - throw new AssertionError(e); - } - finally { - frame.invalidate(); - } - } - - @Override - public PrototypeModel getCallingConvention() { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - CompilerSpec cs = manager.trace.getBaseCompilerSpec(); - if (cs == null) { - return null; - } - DBTraceDataTypeManager dtm = manager.dataTypeManager; - if (callingConventionID == DataTypeManagerDB.UNKNOWN_CALLING_CONVENTION_ID) { - return null; - } - if (callingConventionID == DataTypeManagerDB.DEFAULT_CALLING_CONVENTION_ID) { - return cs.getDefaultCallingConvention(); - } - String ccName = dtm.getCallingConventionName(callingConventionID); - return cs.getCallingConvention(ccName); - } - } - - @Override - public String getCallingConventionName() { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - DBTraceDataTypeManager dtm = manager.dataTypeManager; - return dtm.getCallingConventionName(callingConventionID); - } - } - - @Override - public void setCallingConvention(String name) throws InvalidInputException { - try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { - if (thunked != null) { - thunked.setCallingConvention(name); - return; - } - - DBTraceDataTypeManager dtm = manager.dataTypeManager; - byte id = dtm.getCallingConventionID(name, true); - if (id == callingConventionID) { - return; // no change - } - - doLoadVariables(); - - callingConventionID = id; - update(CALLING_CONVENTION_COLUMN); - - boolean hasCustomStorage = hasCustomVariableStorage(); - if (!hasCustomStorage) { - doRemoveExplicitThisParameter(); - } - - frame.invalidate(); - - if (!hasCustomStorage) { - createClassStructIfNeeded(); // TODO: Ditto from FunctionDB - doLoadVariables(); // TODO: Why? - doRemoveExplicitThisParameter(); // Again, why? - doUpdateParametersAndReturn(); - manager.trace.setChanged(new TraceChangeRecord<>( - TraceFunctionChangeType.CHANGED_PARAMETERS, getSpace(), this)); - manager.trace.setChanged(new TraceChangeRecord<>( - TraceFunctionChangeType.CHANGED_RETURN, getSpace(), this)); - } - else { - manager.trace.setChanged( - new TraceChangeRecord<>(TraceFunctionChangeType.CHANGED, getSpace(), this)); - } - } - catch (IOException e) { - manager.dbError(e); - } - } - - protected void createClassStructIfNeeded() { - PrototypeModel cc = getCallingConvention(); - if (cc == null || !CompilerSpec.CALLING_CONVENTION_thiscall.equals(cc.getName())) { - return; - } - Namespace parentNS = getParentNamespace(); - if (!(parentNS instanceof GhidraClass)) { - return; - } - - DataTypeManager dtm = manager.dataTypeManager; - DataType classStruct = - VariableUtilities.findExistingClassStruct((GhidraClass) parentNS, dtm); - if (classStruct == null) { - // NOTE: Check for existence first, to avoid resolving unnecessarily. - // TODO: If ever struct-class are strongly related, fix that here, too. - classStruct = VariableUtilities.findOrCreateClassStruct((GhidraClass) parentNS, dtm); - if (classStruct != null) { - dtm.resolve(classStruct, null); - } - } - } - - @Override - public boolean isThunk() { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - return thunked != null; - } - } - - @Override - public DBTraceFunctionSymbol getThunkedFunction(boolean recursive) { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - if (recursive) { - if (thunked != null) { - return thunked.getThunkedFunction(recursive); - } - return this; - } - return thunked; - } - } - - private List
getFunctionThunkAddresses(long functionKey, boolean recursive) { - Collection thunkSymbols = manager.functionsByThunked.get(getKey()); - if (thunkSymbols == null || thunkSymbols.isEmpty()) { - return null; - } - List
result = new ArrayList<>(); - for (DBTraceFunctionSymbol thunkSymbol : thunkSymbols) { - result.add(thunkSymbol.entryPoint); - if (recursive) { - List
thunkAddrs = getFunctionThunkAddresses(thunkSymbol.getKey(), true); - if (thunkAddrs != null) { - result.addAll(thunkAddrs); - } - } - } - return result; - } - - @Override - public Address[] getFunctionThunkAddresses(boolean recursive) { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - List
result = getFunctionThunkAddresses(getKey(), recursive); - if (result == null) { - return null; - } - return result.toArray(new Address[result.size()]); - } - } - - @Override - public void setThunkedFunction(Function thunkedFunction) throws IllegalArgumentException { - try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { - DBTraceFunctionSymbol dbFunc = manager.assertIsMine(thunkedFunction); - if (getThunkedFunction(true) == dbFunc) { - throw new IllegalArgumentException("Cannot create circle of thunks"); - } - if (this.thunkedKey == dbFunc.getKey()) { - return; - } - TraceFunctionSymbol oldThunk = thunked; - this.thunkedKey = dbFunc.getKey(); - update(THUNKED_COLUMN); - this.thunked = dbFunc; - manager.trace.setChanged(new TraceChangeRecord<>(TraceFunctionChangeType.CHANGED_THUNK, - getSpace(), this, oldThunk, dbFunc)); - } - } - - @Override - public ExternalLocation getExternalLocation() { - return null; - } - - @Override - public Set getCallingFunctions(TaskMonitor monitor) { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - Set result = new HashSet<>(); - for (DBTraceReference ref : manager.trace.getReferenceManager() - .getReferencesToRange(lifespan, new AddressRangeImpl(entryPoint, entryPoint))) { - if (monitor.isCancelled()) { - break; - } - Address fromAddr = ref.getFromAddress(); - Lifespan span = lifespan.intersect(ref.getLifespan()); - /** - * NOTE: Could be zero, one, or more (because lifespans may be staggered). - * Logically, at the actual call time of any given call at most one function is - * present. However, it caller could be invoked under different conditions at - * different times, so abstractly, we still consider multiple a reasonable result. - */ - result.addAll(manager.functions.getIntersecting(span, getThread(), - new AddressRangeImpl(fromAddr, fromAddr), true, true)); - } - return result; - } - } - - @Override - public Set getCalledFunctions(TaskMonitor monitor) { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - Set result = new HashSet<>(); - for (AddressRange rng : getBody()) { - for (DBTraceReference ref : manager.trace.getReferenceManager() - .getReferencesFromRange(lifespan, rng)) { - if (monitor.isCancelled()) { - return result; - } - Address toAddr = ref.getToAddress(); - Lifespan span = lifespan.intersect(ref.getLifespan()); - /** - * NOTE: Could be zero, one, or more (because lifespans may be staggered). - * Logically, at the actual call time of any given call at most one function is - * present. However, it caller could be invoked under different conditions at - * different times, so abstractly, we still consider multiple a reasonable - * result. - */ - for (DBTraceFunctionSymbol function : manager.functions.getIntersecting(span, - getThread(), new AddressRangeImpl(toAddr, toAddr), true, true)) { - if (toAddr.equals(function.getEntryPoint())) { - result.add(function); - } - } - } - } - return result; - } - } - - @Override - public void promoteLocalUserLabelsToGlobal() { - try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { - List toPromote = manager.labels() - .getChildren(this) - .stream() - .filter(l -> l.getSource() == SourceType.USER_DEFINED) - .toList(); - for (DBTraceLabelSymbol label : toPromote) { - try { - label.setNamespace(manager.getGlobalNamespace()); - } - catch (DuplicateNameException e) { - label.delete(); - } - catch (InvalidInputException | CircularDependencyException e) { - throw new AssertionError(e); - } - } - } - } - - @Override - public boolean delete() { - // TODO: Prevent spurious update logic as the parameters/locals are all deleted - boolean result = super.delete(); - SourceType source = getSource(); - if (result && source != SourceType.DEFAULT) { - try { - manager.labels.add(lifespan, null, entryPoint, name, parent, source); - } - catch (InvalidInputException | IllegalArgumentException e) { - throw new AssertionError(e); // The fields have already been validated. - } - } - return result; - } - - protected void setReturnAddressOffset(int offset) { - try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { - this.stackReturnOffset = offset; - update(STACK_RETURN_OFFSET_COLUMN); - } - manager.trace.setChanged( - new TraceChangeRecord<>(TraceFunctionChangeType.CHANGED, getSpace(), this)); - } - - protected int getReturnAddressOffset() { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - return stackReturnOffset; - } - } -} diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceFunctionSymbolView.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceFunctionSymbolView.java deleted file mode 100644 index 7bda22e323..0000000000 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceFunctionSymbolView.java +++ /dev/null @@ -1,260 +0,0 @@ -/* ### - * 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.trace.database.symbol; - -import java.util.*; - -import ghidra.program.database.function.OverlappingFunctionException; -import ghidra.program.database.symbol.OverlappingNamespaceException; -import ghidra.program.model.address.*; -import ghidra.program.model.lang.*; -import ghidra.program.model.listing.*; -import ghidra.program.model.symbol.*; -import ghidra.trace.database.program.DBTraceProgramView; -import ghidra.trace.model.Lifespan; -import ghidra.trace.model.Trace.TraceSymbolChangeType; -import ghidra.trace.model.symbol.*; -import ghidra.trace.util.TraceChangeRecord; -import ghidra.util.LockHold; -import ghidra.util.exception.InvalidInputException; - -public class DBTraceFunctionSymbolView - extends AbstractDBTraceSymbolSingleTypeWithLocationView - implements TraceFunctionSymbolView { - protected static final PrototypeModel[] EMPTY_MODEL_LIST = new PrototypeModel[] {}; - - protected static void assertProperSpace(AddressSpace expected, AddressSetView body) { - if (!expected.isMemorySpace()) { - throw new IllegalArgumentException("Function must be in memory space"); - } - for (AddressRange rng : body) { - if (rng.getAddressSpace() != expected) { - throw new IllegalArgumentException( - "Function body must be in same space as entry point"); - } - } - } - - public DBTraceFunctionSymbolView(DBTraceSymbolManager manager) { - super(manager, SymbolType.FUNCTION.getID(), manager.functionStore); - } - - protected DBTraceNamespaceSymbol doValidateParentAndEntry(DBTraceNamespaceSymbol proposed, - Address entryPoint) { - if (proposed == null) { - return manager.globalNamespace; - } - DBTraceProgramView program = manager.trace.getProgramView(); - if (!SymbolType.FUNCTION.isValidAddress(program, entryPoint)) { - throw new IllegalArgumentException("Invalid function entry point: " + entryPoint); - } - if (!SymbolType.FUNCTION.isValidParent(program, proposed, entryPoint, false)) { - throw new IllegalArgumentException("Invalid function namespace: " + proposed); - } - - return proposed; - } - - protected SourceType doValidateSource(SourceType proposed, String name, Address entryPoint) { - if (!SymbolType.FUNCTION.isValidSourceType(proposed, entryPoint)) { - throw new IllegalArgumentException("Invalid function source type: " + proposed); - } - return proposed; - } - - protected String doValidateName(String proposed, Address entryPoint, SourceType source) - throws InvalidInputException { - if (source == SourceType.DEFAULT) { - return ""; - } - // TODO: Do entryPoint and source no longer matter? (see commit 898da2b) - SymbolUtilities.validateName(proposed); - return proposed; - } - - protected void assertNotOverlapping(DBTraceFunctionSymbol exclude, Address entryPoint, - Lifespan span, AddressSetView proposedBody) throws OverlappingFunctionException { - for (AddressRange rng : proposedBody) { - for (DBTraceFunctionSymbol overlap : manager.functions.getIntersecting(span, null, rng, - false, true)) { - if (overlap != exclude) { - throw new OverlappingFunctionException(entryPoint, - new OverlappingNamespaceException(rng.getMinAddress(), - rng.getMaxAddress())); - } - } - } - } - - @Override - public DBTraceFunctionSymbol add(Lifespan lifespan, Address entryPoint, AddressSetView body, - String name, TraceFunctionSymbol thunked, TraceNamespaceSymbol parent, - SourceType source) throws InvalidInputException, OverlappingFunctionException { - if (name == null || name.length() == 0 || SymbolUtilities.isReservedDynamicLabelName(name, - manager.trace.getBaseAddressFactory())) { - source = SourceType.DEFAULT; - name = ""; - } - else { - DBTraceSymbolManager.assertValidName(name); - } - if (!"".equals(name) && source == SourceType.DEFAULT) { - throw new IllegalArgumentException( - "Cannot create DEFAULT function with non-default name"); - } - if (!body.contains(entryPoint)) { - throw new IllegalArgumentException("Function body must contain the entry point"); - } - assertProperSpace(entryPoint.getAddressSpace(), body); - try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { - DBTraceNamespaceSymbol dbnsParent = - parent == null ? null : manager.assertIsMine((Namespace) parent); - manager.assertValidThreadAddress(null, entryPoint); - DBTraceFunctionSymbol dbThunked = - thunked == null ? null : manager.assertIsMine((Function) thunked); - - if (manager.trace.getCodeManager() - .definedData() - .getAt(lifespan.lmin(), entryPoint) != null) { - throw new IllegalArgumentException( - "Function entry point cannot be at defined data"); - } - - if (dbThunked != null && name.equals(dbThunked.getName())) { - source = SourceType.DEFAULT; - name = ""; - } - - assertNotOverlapping(null, entryPoint, lifespan, body); - dbnsParent = doValidateParentAndEntry(dbnsParent, entryPoint); - source = doValidateSource(source, name, entryPoint); - name = doValidateName(name, entryPoint, source); - - DBTraceLabelSymbol toPromote = manager.labels.getChildWithNameAt(name, - lifespan.lmin(), null, entryPoint, dbnsParent); - if (toPromote != null && toPromote.getLifespan().equals(lifespan)) { - toPromote.delete(); - } - - DBTraceFunctionSymbol function = store.create(); - function.set(lifespan, entryPoint, name, dbThunked, dbnsParent, source); - function.doCreateReturnParameter(); - for (AddressRange rng : body) { - manager.putID(lifespan, null, rng, function.getID()); - } - - cacheForAt.notifyNewEntries(lifespan, body, function); - - manager.trace.setChanged( - new TraceChangeRecord<>(TraceSymbolChangeType.ADDED, null, function)); - return function; - } - } - - @Override - public Collection getCallingConventionNames() { - return manager.dataTypeManager.getDefinedCallingConventionNames(); - } - - @Override - public PrototypeModel getDefaultCallingConvention() { - return manager.dataTypeManager.getDefaultCallingConvention(); - } - - @Override - public PrototypeModel getCallingConvention(String name) { - return manager.dataTypeManager.getCallingConvention(name); - } - - // TODO: Move this into a FunctionUtilities class? - public static Variable getReferencedVariable(Function function, Address instrAddr, - Address storageAddr, int size, boolean isRead, Language language) { - Variable variables[] = function.getAllVariables(); - - Parameter paramCandidate = null; - List localCandidates = null; - Variable firstCandidate = null; - - size = Math.min(1, size); - Register register = language.getRegister(storageAddr, size); - - for (Variable var : variables) { - VariableStorage varStorage = var.getVariableStorage(); - - // TODO: It seems this check will miss intersection if storageAddr precedes the - // variable, but size is large enough to intersect. - if ((register != null && varStorage.intersects(register)) || - (register == null && varStorage.contains(storageAddr))) { - - if (var instanceof Parameter) { - paramCandidate = (Parameter) var; - } - else if (firstCandidate != null) { - if (localCandidates == null) { - localCandidates = new ArrayList<>(); - localCandidates.add(firstCandidate); - } - localCandidates.add(var); - } - else { - firstCandidate = var; - } - } - } - - int useOffset = (int) instrAddr.subtract(function.getEntryPoint()); - if (isRead) { - if (useOffset == 0) { - return paramCandidate; - } - --useOffset; - } - if (useOffset < 0) { - // A bit of a hack to deal with negative offsets (from function entry) - useOffset = Integer.MAX_VALUE - useOffset; - } - - if (localCandidates == null) { - if (firstCandidate != null) { - int varFirstUse = firstCandidate.getFirstUseOffset(); - if (varFirstUse < 0) { - varFirstUse = Integer.MAX_VALUE - varFirstUse; - } - if (varFirstUse <= useOffset) { - return firstCandidate; - } - } - return null; - } - - Variable bestVar = null; - int bestFirstUse = 0; - for (Variable var : localCandidates) { - int varFirstUse = var.getFirstUseOffset(); - if (varFirstUse < 0) { - varFirstUse = Integer.MAX_VALUE - varFirstUse; - } - if (varFirstUse <= useOffset && (bestVar == null || bestFirstUse < varFirstUse)) { - bestVar = var; - bestFirstUse = varFirstUse; - } - } - if (bestVar == null) { - bestVar = paramCandidate; - } - return bestVar; - } -} diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceGlobalVariableSymbol.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceGlobalVariableSymbol.java deleted file mode 100644 index dc5d9a7d12..0000000000 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceGlobalVariableSymbol.java +++ /dev/null @@ -1,66 +0,0 @@ -/* ### - * 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.trace.database.symbol; - -import db.DBRecord; -import ghidra.program.model.address.Address; -import ghidra.program.model.symbol.SymbolType; -import ghidra.trace.model.symbol.TraceGlobalVariableSymbol; -import ghidra.util.database.DBCachedObjectStore; -import ghidra.util.database.annot.DBAnnotatedObjectInfo; - -@DBAnnotatedObjectInfo(version = 0) -public class DBTraceGlobalVariableSymbol extends AbstractDBTraceVariableSymbol - implements TraceGlobalVariableSymbol { - static final String TABLE_NAME = "GlobalVars"; - - public DBTraceGlobalVariableSymbol(DBTraceSymbolManager manager, DBCachedObjectStore store, - DBRecord record) { - super(manager, store, record); - } - - @Override - public SymbolType getSymbolType() { - return SymbolType.GLOBAL_VAR; - } - - @Override - public DBTraceFunctionSymbol getFunction() { - return null; - } - - @Override - public Address getAddress() { - // TODO: Reference implementation in Program is not complete. If ever, make this similar. - return getVariableStorage().getRegister().getAddress(); - } - - @Override - public boolean setPrimary() { - return false; - } - - @Override - public boolean isPrimary() { - return true; - } - - @Override - public int getFirstUseOffset() { - // TODO: Reference implementation in Program is not complete. If ever, make this similar. - return 0; - } -} diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceGlobalVariableSymbolView.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceGlobalVariableSymbolView.java deleted file mode 100644 index 3f27e13264..0000000000 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceGlobalVariableSymbolView.java +++ /dev/null @@ -1,28 +0,0 @@ -/* ### - * 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.trace.database.symbol; - -import ghidra.program.model.symbol.SymbolType; -import ghidra.trace.model.symbol.TraceGlobalVariableSymbolView; - -public class DBTraceGlobalVariableSymbolView - extends AbstractDBTraceSymbolSingleTypeWithAddressView - implements TraceGlobalVariableSymbolView { - - public DBTraceGlobalVariableSymbolView(DBTraceSymbolManager manager) { - super(manager, SymbolType.GLOBAL_VAR.getID(), manager.globalVarStore); - } -} diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceLabelSymbol.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceLabelSymbol.java index 73a8af8e90..25762134e1 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceLabelSymbol.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceLabelSymbol.java @@ -240,11 +240,6 @@ public class DBTraceLabelSymbol extends AbstractDBTraceSymbol public boolean setPrimary() { try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { AddressRangeImpl range = new AddressRangeImpl(address, address); - if (!manager.functions.getIntersecting(lifespan, thread, range, false, - true).isEmpty()) { - // Labels cannot supersede a function - return false; - } boolean result = doSetPrimary(true); if (!result) { return false; diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceLocalVariableSymbol.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceLocalVariableSymbol.java deleted file mode 100644 index 1cb3f09f17..0000000000 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceLocalVariableSymbol.java +++ /dev/null @@ -1,123 +0,0 @@ -/* ### - * 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.trace.database.symbol; - -import db.DBRecord; -import ghidra.program.model.data.DataType; -import ghidra.program.model.listing.VariableStorage; -import ghidra.program.model.symbol.SourceType; -import ghidra.program.model.symbol.SymbolType; -import ghidra.trace.model.Trace.TraceFunctionChangeType; -import ghidra.trace.model.symbol.TraceLocalVariableSymbol; -import ghidra.trace.util.TraceChangeRecord; -import ghidra.util.LockHold; -import ghidra.util.database.DBCachedObjectStore; -import ghidra.util.database.DBObjectColumn; -import ghidra.util.database.annot.*; - -@DBAnnotatedObjectInfo(version = 0) -public class DBTraceLocalVariableSymbol extends AbstractDBTraceVariableSymbol - implements TraceLocalVariableSymbol { - static final String TABLE_NAME = "LocalVars"; - - static final String FIRST_USE_COLUMN_NAME = "FirstUse"; - - @DBAnnotatedColumn(FIRST_USE_COLUMN_NAME) - static DBObjectColumn FIRST_USE_COLUMN; - - @DBAnnotatedField(column = FIRST_USE_COLUMN_NAME) - int firstUseOffset; - - public DBTraceLocalVariableSymbol(DBTraceSymbolManager manager, DBCachedObjectStore store, - DBRecord record) { - super(manager, store, record); - } - - protected void set(String name, DBTraceFunctionSymbol function, DataType dt, - VariableStorage storage, int firstUseOffset, SourceType source) { - super.set(name, function, dt, storage, source); - this.firstUseOffset = firstUseOffset; - update(FIRST_USE_COLUMN); - } - - @Override - public SymbolType getSymbolType() { - return SymbolType.LOCAL_VAR; - } - - @Override - public DBTraceFunctionSymbol getParentNamespace() { - return (DBTraceFunctionSymbol) super.getParentNamespace(); - } - - @Override - public DBTraceFunctionSymbol getParentSymbol() { - return (DBTraceFunctionSymbol) super.getParentSymbol(); - } - - @Override - public DBTraceFunctionSymbol getFunction() { - return getParentSymbol(); - } - - @Override - public boolean setPrimary() { - return false; - } - - @Override - public boolean isPrimary() { - return false; - } - - @Override - public boolean setFirstUseOffset(int firstUseOffset) { - try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { - if (this.firstUseOffset == firstUseOffset) { - return true; // ineffective, but successful - } - this.firstUseOffset = firstUseOffset; - update(FIRST_USE_COLUMN); - } - manager.trace.setChanged( - new TraceChangeRecord<>(TraceFunctionChangeType.CHANGED, getSpace(), getFunction())); - return true; - } - - @Override - public int getFirstUseOffset() { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - return firstUseOffset; - } - } - - @Override - protected void doUpdatesAfterSetDataType() { - super.doUpdatesAfterSetDataType(); - manager.trace.setChanged( - new TraceChangeRecord<>(TraceFunctionChangeType.CHANGED, getSpace(), getFunction())); - } - - @Override - public boolean delete() { - if (super.delete()) { - manager.trace.setChanged(new TraceChangeRecord<>(TraceFunctionChangeType.CHANGED, - getSpace(), getFunction())); - return true; - } - return false; - } -} diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceLocalVariableSymbolView.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceLocalVariableSymbolView.java deleted file mode 100644 index 1466e9245a..0000000000 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceLocalVariableSymbolView.java +++ /dev/null @@ -1,28 +0,0 @@ -/* ### - * 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.trace.database.symbol; - -import ghidra.program.model.symbol.SymbolType; -import ghidra.trace.model.symbol.TraceLocalVariableSymbolView; - -public class DBTraceLocalVariableSymbolView - extends AbstractDBTraceSymbolSingleTypeWithAddressView - implements TraceLocalVariableSymbolView { - - public DBTraceLocalVariableSymbolView(DBTraceSymbolManager manager) { - super(manager, SymbolType.LOCAL_VAR.getID(), manager.localVarStore); - } -} diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceParameterSymbol.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceParameterSymbol.java deleted file mode 100644 index 5249956120..0000000000 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceParameterSymbol.java +++ /dev/null @@ -1,220 +0,0 @@ -/* ### - * 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.trace.database.symbol; - -import org.apache.commons.lang3.tuple.ImmutablePair; -import org.apache.commons.lang3.tuple.Pair; - -import db.DBRecord; -import ghidra.program.model.data.DataType; -import ghidra.program.model.listing.*; -import ghidra.program.model.symbol.*; -import ghidra.trace.model.Trace.TraceFunctionChangeType; -import ghidra.trace.model.symbol.TraceParameterSymbol; -import ghidra.trace.util.TraceChangeRecord; -import ghidra.util.LockHold; -import ghidra.util.database.DBCachedObjectStore; -import ghidra.util.database.DBObjectColumn; -import ghidra.util.database.annot.*; -import ghidra.util.exception.InvalidInputException; - -@DBAnnotatedObjectInfo(version = 0) -public class DBTraceParameterSymbol extends AbstractDBTraceVariableSymbol - implements TraceParameterSymbol { - static final String TABLE_NAME = "Parameters"; - - static final String ORDINAL_COLUMN_NAME = "Ordinal"; - - @DBAnnotatedColumn(ORDINAL_COLUMN_NAME) - static DBObjectColumn ORDINAL_COLUMN; - - @DBAnnotatedField(column = ORDINAL_COLUMN_NAME) - int ordinal; - - // This is transient, when the function does not use custom parameter storage. - // It is unused if the function uses custom storage. - protected VariableStorage dynamicStorage = VariableStorage.UNASSIGNED_STORAGE; - - public DBTraceParameterSymbol(DBTraceSymbolManager manager, DBCachedObjectStore store, - DBRecord record) { - super(manager, store, record); - } - - protected void set(String name, DBTraceFunctionSymbol function, DataType dt, - VariableStorage storage, int ordinal, SourceType source) { - super.set(name, function, dt, storage, source); - this.ordinal = ordinal; - update(ORDINAL_COLUMN); - } - - @Override - protected VariableStorage adjustStorage(VariableStorage s) { - if (!getFunction().hasCustomVariableStorage()) { - return VariableStorage.UNASSIGNED_STORAGE; - } - return super.adjustStorage(s); - } - - @Override - public SymbolType getSymbolType() { - return SymbolType.PARAMETER; - } - - @Override - protected Pair validateNameAndSource(String newName, SourceType newSource) - throws InvalidInputException { - if (newSource == SourceType.DEFAULT || newName == null || "".equals(newName) || - SymbolUtilities.isDefaultParameterName(newName)) { - return new ImmutablePair<>("", SourceType.DEFAULT); - } - return new ImmutablePair<>(newName, newSource); - } - - @Override - public String getName() { - if (getSource() == SourceType.DEFAULT && ordinal != -1) { - return SymbolUtilities.getDefaultParamName(ordinal); - } - return super.getName(); - } - - @Override - public DBTraceFunctionSymbol getParentNamespace() { - return (DBTraceFunctionSymbol) super.getParentNamespace(); - } - - @Override - public DBTraceFunctionSymbol getParentSymbol() { - return (DBTraceFunctionSymbol) super.getParentSymbol(); - } - - @Override - public DBTraceFunctionSymbol getFunction() { - return getParentSymbol(); - } - - @Override - public boolean setPrimary() { - return false; - } - - @Override - public boolean isPrimary() { - return false; - } - - @Override - public VariableStorage getVariableStorage() { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - if (!getFunction().hasCustomVariableStorage()) { - return dynamicStorage; - } - return super.getVariableStorage(); - } - } - - // Internal - public void setOrdinal(int ordinal) { - try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { - this.ordinal = ordinal; - update(ORDINAL_COLUMN); - } - } - - @Override - public int getOrdinal() { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - return ordinal; - } - } - - @Override - public boolean isAutoParameter() { - return false; - } - - @Override - public AutoParameterType getAutoParameterType() { - return null; - } - - @Override - public boolean isForcedIndirect() { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - VariableStorage s = getVariableStorage(); - return s == null ? false : s.isForcedIndirect(); - } - } - - @Override - public DataType getDataType() { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - return manager.checkIndirection(getVariableStorage(), getFormalDataType()); - } - } - - @Override - public DataType getFormalDataType() { - return super.getDataType(); - } - - @Override - public int getFirstUseOffset() { - return 0; - } - - protected void doSetDynamicStorage(VariableStorage s) { - assert !getFunction().hasCustomVariableStorage(); - this.dynamicStorage = s; - } - - @Override - protected void doUpdatesAfterSetDataType() { - super.doUpdatesAfterSetDataType(); - DBTraceFunctionSymbol function = getFunction(); - if (!function.hasCustomVariableStorage()) { - function.doUpdateParametersAndReturn(); - } - function.doUpdateSignatureSourceAfterVariableChange(getSource(), getDataType()); - if (ordinal == Parameter.RETURN_ORIDINAL) { - manager.trace.setChanged(new TraceChangeRecord<>(TraceFunctionChangeType.CHANGED_RETURN, - getSpace(), getFunction())); - } - else { - manager.trace.setChanged(new TraceChangeRecord<>( - TraceFunctionChangeType.CHANGED_PARAMETERS, getSpace(), getFunction())); - } - } - - @Override - protected VariableStorage doDeriveStorageForSetDataType(DataType dt, boolean alignStack, - boolean force) throws InvalidInputException { - if (!getFunction().hasCustomVariableStorage()) { - return VariableStorage.UNASSIGNED_STORAGE; - } - return super.doDeriveStorageForSetDataType(dt, alignStack, force); - } - - @Override - public boolean delete() { - if (super.delete()) { - manager.trace.setChanged(new TraceChangeRecord<>( - TraceFunctionChangeType.CHANGED_PARAMETERS, getSpace(), getFunction())); - return true; - } - return false; - } -} diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceParameterSymbolView.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceParameterSymbolView.java deleted file mode 100644 index 265abdf09d..0000000000 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceParameterSymbolView.java +++ /dev/null @@ -1,28 +0,0 @@ -/* ### - * 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.trace.database.symbol; - -import ghidra.program.model.symbol.SymbolType; -import ghidra.trace.model.symbol.TraceParameterSymbolView; - -public class DBTraceParameterSymbolView - extends AbstractDBTraceSymbolSingleTypeWithAddressView - implements TraceParameterSymbolView { - - public DBTraceParameterSymbolView(DBTraceSymbolManager manager) { - super(manager, SymbolType.PARAMETER.getID(), manager.parameterStore); - } -} diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReference.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReference.java index 71a6f8ff2f..2861a0e251 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReference.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReference.java @@ -151,25 +151,7 @@ public class DBTraceReference implements TraceReference { return; } Address toAddress = getToAddress(); - if (dbSym instanceof AbstractDBTraceVariableSymbol) { - AbstractDBTraceVariableSymbol varSym = (AbstractDBTraceVariableSymbol) dbSym; - // Variables' lifespans are governed by the parent function. - // Globals span all time. - DBTraceNamespaceSymbol parent = varSym.getParentNamespace(); - if (parent instanceof TraceSymbolWithLifespan) { - TraceSymbolWithLifespan symWl = (TraceSymbolWithLifespan) parent; - if (!symWl.getLifespan().intersects(getLifespan())) { - throw new IllegalArgumentException( - "Associated symbol and reference must have connected lifespans"); - } - } - if (!varSym.getVariableStorage().contains(toAddress)) { - throw new IllegalArgumentException(String.format( - "Variable symbol storage of '%s' must contain Reference's to address (%s)", - varSym.getName(), toAddress)); - } - } - else if (!Objects.equals(symbol.getAddress(), toAddress)) { + if (!Objects.equals(symbol.getAddress(), toAddress)) { throw new IllegalArgumentException(String.format( "Symbol address (%s) of '%s' must match Reference's to address (%s)", symbol.getAddress(), symbol.getName(), toAddress)); diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceSymbolManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceSymbolManager.java index ff43266523..f5a861e559 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceSymbolManager.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceSymbolManager.java @@ -21,10 +21,12 @@ import java.util.*; import java.util.concurrent.locks.ReadWriteLock; import db.*; +import ghidra.lifecycle.Internal; import ghidra.program.model.address.*; import ghidra.program.model.data.DataType; import ghidra.program.model.lang.Language; -import ghidra.program.model.listing.*; +import ghidra.program.model.listing.Program; +import ghidra.program.model.listing.VariableStorage; import ghidra.program.model.symbol.*; import ghidra.trace.database.DBTrace; import ghidra.trace.database.DBTraceManager; @@ -37,7 +39,6 @@ import ghidra.trace.database.space.DBTraceSpaceKey; import ghidra.trace.database.thread.DBTraceThreadManager; import ghidra.trace.model.Lifespan; import ghidra.trace.model.Trace; -import ghidra.trace.model.Trace.TraceFunctionTagChangeType; import ghidra.trace.model.Trace.TraceSymbolChangeType; import ghidra.trace.model.symbol.*; import ghidra.trace.model.thread.TraceThread; @@ -93,164 +94,6 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager } } - @DBAnnotatedObjectInfo(version = 0) - public static class DBTraceFunctionTag extends DBAnnotatedObject implements FunctionTag { - - static final String TABLE_NAME = "FunctionTags"; - - static final String NAME_COLUMN_NAME = "Name"; - static final String COMMENT_COLUMN_NAME = "Comment"; - - @DBAnnotatedColumn(NAME_COLUMN_NAME) - static DBObjectColumn NAME_COLUMN; - @DBAnnotatedColumn(COMMENT_COLUMN_NAME) - static DBObjectColumn COMMENT_COLUMN; - - @DBAnnotatedField(column = NAME_COLUMN_NAME, indexed = true) - String name; - @DBAnnotatedField(column = COMMENT_COLUMN_NAME) - String comment; - - protected final DBTraceSymbolManager manager; - - public DBTraceFunctionTag(DBTraceSymbolManager manager, DBCachedObjectStore store, - DBRecord record) { - super(store, record); - this.manager = manager; - } - - protected void set(String name, String comment) { - this.name = name; - this.comment = comment; - update(NAME_COLUMN, COMMENT_COLUMN); - } - - @Override - public int hashCode() { - return Long.hashCode(key); - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof FunctionTag)) { - return false; - } - if (obj == this) { - return true; - } - FunctionTag that = (FunctionTag) obj; - if (!Objects.equals(this.getName(), that.getName())) { - return false; - } - if (!Objects.equals(this.getComment(), that.getComment())) { - return false; - } - return true; - } - - @Override - public int compareTo(FunctionTag o) { - int result; - result = this.getName().compareToIgnoreCase(o.getName()); - if (result != 0) { - return result; - } - result = this.getComment().compareToIgnoreCase(o.getComment()); - if (result != 0) { - return result; - } - return 0; - } - - @Override - public long getId() { - return key; - } - - @Override - public String getName() { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - return name; - } - } - - @Override - public String getComment() { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - return comment; - } - } - - @Override - public void setName(String name) { - try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { - this.name = name; - update(NAME_COLUMN); - } - manager.trace.setChanged( - new TraceChangeRecord<>(TraceFunctionTagChangeType.CHANGED, null, this)); - } - - @Override - public void setComment(String comment) { - try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { - this.comment = comment; - update(COMMENT_COLUMN); - } - manager.trace.setChanged( - new TraceChangeRecord<>(TraceFunctionTagChangeType.CHANGED, null, this)); - } - - @Override - public void delete() { - try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { - for (DBTraceFunctionTagMapping mapping : manager.tagMappingsByTag.get(key)) { - manager.tagMappingStore.delete(mapping); - } - manager.tagStore.delete(this); - } - manager.trace.setChanged( - new TraceChangeRecord<>(TraceFunctionTagChangeType.DELETED, null, this)); - } - } - - @DBAnnotatedObjectInfo(version = 0) - public static class DBTraceFunctionTagMapping extends DBAnnotatedObject { - - static final String TABLE_NAME = "FunctionTagMappings"; - - static final String FUNCTION_COLUMN_NAME = "Function"; - static final String TAG_COLUMN_NAME = "Tag"; - - @DBAnnotatedColumn(FUNCTION_COLUMN_NAME) - static DBObjectColumn FUNCTION_COLUMN; - @DBAnnotatedColumn(TAG_COLUMN_NAME) - static DBObjectColumn TAG_COLUMN; - - @DBAnnotatedField(column = FUNCTION_COLUMN_NAME, indexed = true) - private long functionKey; - @DBAnnotatedField(column = TAG_COLUMN_NAME, indexed = true) - private long tagKey; - - public DBTraceFunctionTagMapping(DBCachedObjectStore store, DBRecord record) { - super(store, record); - } - - protected void set(DBTraceFunctionSymbol function, DBTraceFunctionTag tag) { - this.functionKey = function.getKey(); - this.tagKey = tag.getKey(); - update(FUNCTION_COLUMN, TAG_COLUMN); - } - - public long getFunctionKey() { - return functionKey; - } - - public long getTagKey() { - return tagKey; - } - } - public static class VariableStorageDBFieldCodec extends AbstractDBFieldCodec { @@ -351,25 +194,7 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager CLASS { @Override boolean isValidParent(DBTraceNamespaceSymbol parent) { - return isNoFunctionAncestor(parent); - } - }, - FUNCTION { - @Override - boolean isValidParent(DBTraceNamespaceSymbol parent) { - return isNoFunctionAncestor(parent); - } - }, - PARAMETER { - @Override - boolean isValidParent(DBTraceNamespaceSymbol parent) { - return parent instanceof Function; - } - }, - LOCAL_VAR { - @Override - boolean isValidParent(DBTraceNamespaceSymbol parent) { - return parent instanceof Function; + return true; } }, GLOBAL_VAR { @@ -382,15 +207,6 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager public static final List VALUES = List.of(values()); abstract boolean isValidParent(DBTraceNamespaceSymbol parent); - - boolean isNoFunctionAncestor(DBTraceNamespaceSymbol parent) { - for (DBTraceNamespaceSymbol p = parent; p != null; p = p.parent) { - if (p instanceof Function) { - return false; - } - } - return true; - } } protected final DBTrace trace; @@ -401,41 +217,23 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager protected final DBTraceAddressSnapRangePropertyMap idMap; - protected final DBCachedObjectStore tagStore; - protected final DBCachedObjectIndex tagsByName; - - protected final DBCachedObjectStore tagMappingStore; - protected final DBCachedObjectIndex tagMappingsByFunc; - protected final DBCachedObjectIndex tagMappingsByTag; - + // NB. This is unused since the purging of trace function symbols + // In theory, may get used by global variables. protected final DBCachedObjectStore storageStore; protected final DBCachedObjectIndex storageByStorage; protected final DBCachedObjectStore labelStore; protected final DBCachedObjectStore namespaceStore; protected final DBCachedObjectStore classStore; - protected final DBCachedObjectStore functionStore; - protected final DBCachedObjectIndex functionsByThunked; - protected final DBCachedObjectStore parameterStore; - protected final DBCachedObjectStore localVarStore; - // Seems only for "global register" variables - protected final DBCachedObjectStore globalVarStore; protected final DBTraceNamespaceSymbol globalNamespace; protected final DBTraceLabelSymbolView labels; protected final DBTraceNamespaceSymbolView namespaces; protected final DBTraceClassSymbolView classes; - protected final DBTraceFunctionSymbolView functions; - protected final DBTraceParameterSymbolView parameters; - protected final DBTraceLocalVariableSymbolView localVars; - protected final DBTraceGlobalVariableSymbolView globalVars; protected final DBTraceSymbolMultipleTypesView allNamespaces; protected final DBTraceSymbolMultipleTypesNoDuplicatesView uniqueNamespaces; - protected final DBTraceSymbolMultipleTypesWithAddressNoDuplicatesView allLocals; - protected final DBTraceSymbolMultipleTypesWithAddressNoDuplicatesView allVariables; - protected final DBTraceSymbolMultipleTypesWithLocationView labelsAndFunctions; - protected final DBTraceSymbolMultipleTypesNoDuplicatesView notLabelsNorFunctions; + protected final DBTraceSymbolMultipleTypesNoDuplicatesView notLabels; protected final DBTraceSymbolMultipleTypesView allSymbols; protected final Map> symbolViews = new HashMap<>(); @@ -457,17 +255,6 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager baseLanguage, trace, threadManager, DBTraceSymbolIDEntry.class, DBTraceSymbolIDEntry::new); - tagStore = factory.getOrCreateCachedStore(DBTraceFunctionTag.TABLE_NAME, - DBTraceFunctionTag.class, (s, r) -> new DBTraceFunctionTag(this, s, r), true); - tagsByName = tagStore.getIndex(String.class, DBTraceFunctionTag.NAME_COLUMN); - - tagMappingStore = factory.getOrCreateCachedStore(DBTraceFunctionTagMapping.TABLE_NAME, - DBTraceFunctionTagMapping.class, DBTraceFunctionTagMapping::new, true); - tagMappingsByFunc = - tagMappingStore.getIndex(long.class, DBTraceFunctionTagMapping.FUNCTION_COLUMN); - tagMappingsByTag = - tagMappingStore.getIndex(long.class, DBTraceFunctionTagMapping.TAG_COLUMN); - storageStore = factory.getOrCreateCachedStore(DBTraceVariableStorageEntry.TABLE_NAME, DBTraceVariableStorageEntry.class, (s, r) -> new DBTraceVariableStorageEntry(this, s, r), true); @@ -480,18 +267,6 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager DBTraceNamespaceSymbol.class, (s, r) -> new DBTraceNamespaceSymbol(this, s, r), true); classStore = factory.getOrCreateCachedStore(DBTraceClassSymbol.TABLE_NAME, DBTraceClassSymbol.class, (s, r) -> new DBTraceClassSymbol(this, s, r), true); - functionStore = factory.getOrCreateCachedStore(DBTraceFunctionSymbol.TABLE_NAME, - DBTraceFunctionSymbol.class, (s, r) -> new DBTraceFunctionSymbol(this, s, r), true); - functionsByThunked = - functionStore.getIndex(long.class, DBTraceFunctionSymbol.THUNKED_COLUMN); - parameterStore = factory.getOrCreateCachedStore(DBTraceParameterSymbol.TABLE_NAME, - DBTraceParameterSymbol.class, (s, r) -> new DBTraceParameterSymbol(this, s, r), true); - localVarStore = factory.getOrCreateCachedStore(DBTraceLocalVariableSymbol.TABLE_NAME, - DBTraceLocalVariableSymbol.class, (s, r) -> new DBTraceLocalVariableSymbol(this, s, r), - true); - globalVarStore = factory.getOrCreateCachedStore(DBTraceGlobalVariableSymbol.TABLE_NAME, - DBTraceGlobalVariableSymbol.class, - (s, r) -> new DBTraceGlobalVariableSymbol(this, s, r), true); globalNamespace = getOrCreateGlobalNamespace(); @@ -499,25 +274,13 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager labels = putInMap(new DBTraceLabelSymbolView(this)); namespaces = putInMap(new DBTraceNamespaceSymbolView(this)); classes = putInMap(new DBTraceClassSymbolView(this)); - functions = putInMap(new DBTraceFunctionSymbolView(this)); - parameters = putInMap(new DBTraceParameterSymbolView(this)); - localVars = putInMap(new DBTraceLocalVariableSymbolView(this)); - globalVars = putInMap(new DBTraceGlobalVariableSymbolView(this)); - allNamespaces = new DBTraceSymbolMultipleTypesView<>(this, namespaces, classes, functions); + allNamespaces = new DBTraceSymbolMultipleTypesView<>(this, namespaces, classes); uniqueNamespaces = new DBTraceSymbolMultipleTypesNoDuplicatesView<>(this, namespaces, classes); - allLocals = new DBTraceSymbolMultipleTypesWithAddressNoDuplicatesView<>(this, parameters, - localVars); - allVariables = new DBTraceSymbolMultipleTypesWithAddressNoDuplicatesView<>(this, parameters, - localVars, globalVars); - labelsAndFunctions = new DBTraceSymbolMultipleTypesWithLocationView( - this, labels, functions); - notLabelsNorFunctions = new DBTraceSymbolMultipleTypesNoDuplicatesView<>(this, namespaces, - classes, parameters, localVars, globalVars); - allSymbols = new DBTraceSymbolMultipleTypesView<>(this, labels, namespaces, classes, - functions, parameters, localVars, globalVars); - + notLabels = + new DBTraceSymbolMultipleTypesNoDuplicatesView<>(this, namespaces, classes); + allSymbols = new DBTraceSymbolMultipleTypesView<>(this, labels, namespaces, classes); } protected DataType checkIndirection(VariableStorage s, DataType formal) { @@ -595,8 +358,7 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager // Internal public void replaceDataTypes(long oldID, long newID) { - // TODO Auto-generated method stub - // DataTypes of Function returns, params, locals, globalRegs + // Would apply to functions and variables, but those are not supported. } protected void assertValidThreadAddress(TraceThread thread, Address address) { @@ -644,26 +406,6 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager return classes; } - @Override - public DBTraceFunctionSymbolView functions() { - return functions; - } - - @Override - public DBTraceParameterSymbolView parameters() { - return parameters; - } - - @Override - public DBTraceLocalVariableSymbolView localVariables() { - return localVars; - } - - @Override - public DBTraceGlobalVariableSymbolView globalVariables() { - return globalVars; - } - @Override public TraceSymbolView allNamespaces() { return allNamespaces; @@ -674,23 +416,8 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager } @Override - public TraceSymbolWithAddressNoDuplicatesView allLocals() { - return allLocals; - } - - @Override - public TraceSymbolWithAddressNoDuplicatesView allVariables() { - return allVariables; - } - - @Override - public TraceSymbolWithLocationView labelsAndFunctions() { - return labelsAndFunctions; - } - - @Override - public TraceSymbolNoDuplicatesView notLabelsNorFunctions() { - return notLabelsNorFunctions; + public TraceSymbolNoDuplicatesView notLabels() { + return notLabels; } @Override @@ -700,10 +427,9 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager // Internal public DBTraceNamespaceSymbol checkIsMine(Namespace ns) { - if (!(ns instanceof DBTraceNamespaceSymbol)) { + if (!(ns instanceof DBTraceNamespaceSymbol dbns)) { return null; } - DBTraceNamespaceSymbol dbns = (DBTraceNamespaceSymbol) ns; if (dbns.manager != this) { return null; } @@ -713,13 +439,8 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager if (namespaceStore.contains(dbns)) { return dbns; } - if (dbns instanceof DBTraceClassSymbol) { - if (classStore.contains((DBTraceClassSymbol) dbns)) { - return dbns; - } - } - if (dbns instanceof DBTraceFunctionSymbol) { - if (functionStore.contains((DBTraceFunctionSymbol) dbns)) { + if (dbns instanceof DBTraceClassSymbol dbcs) { + if (classStore.contains(dbcs)) { return dbns; } } @@ -728,10 +449,9 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager // Internal public AbstractDBTraceSymbol checkIsMine(Symbol symbol) { - if (!(symbol instanceof AbstractDBTraceSymbol)) { + if (!(symbol instanceof AbstractDBTraceSymbol dbSym)) { return null; } - AbstractDBTraceSymbol dbSym = (AbstractDBTraceSymbol) symbol; if (dbSym.manager != this) { return null; } @@ -750,25 +470,7 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager return dbSym; } - // Internal - public DBTraceFunctionSymbol checkIsMine(Function function) { - if (!(function instanceof DBTraceFunctionSymbol)) { - return null; - } - DBTraceFunctionSymbol dbFunc = (DBTraceFunctionSymbol) function; - if (dbFunc.manager != this) { - return null; - } - if (dbFunc.isDeleted()) { - return null; - } - if (functionStore.contains(dbFunc)) { - return dbFunc; - } - return null; - } - - // Internal + @Internal public DBTraceNamespaceSymbol assertIsMine(Namespace ns) { DBTraceNamespaceSymbol dbns = checkIsMine(ns); if (dbns == null) { @@ -777,7 +479,7 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager return dbns; } - // Internal + @Internal public AbstractDBTraceSymbol assertIsMine(Symbol symbol) { AbstractDBTraceSymbol dbSym = checkIsMine(symbol); if (dbSym == null) { @@ -786,15 +488,6 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager return dbSym; } - // Internal - public DBTraceFunctionSymbol assertIsMine(Function function) { - DBTraceFunctionSymbol dbFunc = checkIsMine(function); - if (dbFunc == null) { - throw new IllegalArgumentException("Given function is not in this trace"); - } - return dbFunc; - } - protected static void assertValidName(String name) throws InvalidInputException { if (name == null || name.length() == 0 || !name.matches("\\p{Graph}+")) { throw new InvalidInputException(name); @@ -802,8 +495,7 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager } /** - * Checks for duplicate names, allowing {@link SymbolType#LABEL} and - * {@link SymbolType#FUNCTION}. + * Checks for duplicate names, allowing {@link SymbolType#LABEL} * * @param name the proposed name * @param parent the parent namespace @@ -811,7 +503,7 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager */ protected void assertUniqueName(String name, DBTraceNamespaceSymbol parent) throws DuplicateNameException { - for (AbstractDBTraceSymbol symbol : notLabelsNorFunctions.getChildren(parent)) { + for (AbstractDBTraceSymbol symbol : notLabels.getChildren(parent)) { if (name.equals(symbol.name)) { throw new DuplicateNameException(name); } @@ -866,8 +558,8 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager TraceThread thread, Address address, String name, DBTraceNamespaceSymbol parent) throws DuplicateNameException { if (address.isMemoryAddress()) { - for (AbstractDBTraceSymbol duplicate : labelsAndFunctions.getIntersecting(lifespan, - thread, new AddressRangeImpl(address, address), false, true)) { + for (AbstractDBTraceSymbol duplicate : labels.getIntersecting(lifespan, thread, + new AddressRangeImpl(address, address), false, true)) { if (duplicate == exclude) { continue; } @@ -885,8 +577,7 @@ public class DBTraceSymbolManager implements TraceSymbolManager, DBTraceManager protected void assertNotDuplicate(AbstractDBTraceSymbol exclude, String name, DBTraceNamespaceSymbol parent) throws DuplicateNameException { - for (AbstractDBTraceSymbol duplicate : notLabelsNorFunctions.getChildrenNamed(name, - parent)) { + for (AbstractDBTraceSymbol duplicate : notLabels.getChildrenNamed(name, parent)) { if (duplicate == exclude) { continue; } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/Trace.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/Trace.java index 1ac6f84f16..f3ec5693bf 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/Trace.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/Trace.java @@ -229,44 +229,6 @@ public interface Trace extends DataTypeManagerDomainObject { new TraceDataTypeChangeType<>(); } - public static final class TraceFunctionChangeType - extends DefaultTraceChangeType { - // NOTE: ADDED/DELETED/LIFESPAN_CHANGED are SymbolChangeTypes - public static final TraceFunctionChangeType CHANGED = new TraceFunctionChangeType<>(); - public static final TraceFunctionChangeType CHANGED_PURGE = - new TraceFunctionChangeType<>(); - public static final TraceFunctionChangeType CHANGED_INLINE = - new TraceFunctionChangeType<>(); - public static final TraceFunctionChangeType CHANGED_NORETURN = - new TraceFunctionChangeType<>(); - public static final TraceFunctionChangeType CHANGED_CALL_FIXUP = - new TraceFunctionChangeType<>(); - public static final TraceFunctionChangeType CHANGED_RETURN = - new TraceFunctionChangeType<>(); - public static final TraceFunctionChangeType CHANGED_PARAMETERS = - new TraceFunctionChangeType<>(); - public static final TraceFunctionChangeType CHANGED_THUNK = - new TraceFunctionChangeType<>(); - public static final TraceFunctionChangeType CHANGED_BODY = - new TraceFunctionChangeType<>(); - public static final TraceFunctionChangeType TAG_APPLIED = - new TraceFunctionChangeType<>(); - public static final TraceFunctionChangeType TAG_REMOVED = - new TraceFunctionChangeType<>(); - // TODO: VARIABLE_REFERENCE_ADDED? Or would these be reported by ref manager? - // TODO: VARIABLE_REFERENCE_DELETED? Or would these be reported by ref manager? - } - - public static final class TraceFunctionTagChangeType - extends DefaultTraceChangeType { - public static final TraceFunctionTagChangeType ADDED = - new TraceFunctionTagChangeType<>(); - public static final TraceFunctionTagChangeType CHANGED = - new TraceFunctionTagChangeType<>(); - public static final TraceFunctionTagChangeType DELETED = - new TraceFunctionTagChangeType<>(); - } - public static final class TraceInstructionChangeType extends DefaultTraceChangeType { public static final TraceInstructionChangeType FLOW_OVERRIDE_CHANGED = diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceClassSymbol.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceClassSymbol.java index 6ea3c588a5..8756a207d6 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceClassSymbol.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceClassSymbol.java @@ -17,6 +17,9 @@ package ghidra.trace.model.symbol; import ghidra.program.model.listing.GhidraClass; +/** + * A trace class symbol + */ public interface TraceClassSymbol extends TraceNamespaceSymbol, GhidraClass { - + // Nothing to add. } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceClassSymbolView.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceClassSymbolView.java index d70243cdd2..f13812dfbb 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceClassSymbolView.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceClassSymbolView.java @@ -19,8 +19,21 @@ import ghidra.program.model.symbol.SourceType; import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.InvalidInputException; +/** + * The class symbol view. + */ public interface TraceClassSymbolView extends TraceSymbolNoDuplicatesView { - + /** + * Add a new class symbol. + * + * @param name the name of the class + * @param parent the parent namespace + * @param source the source + * @return the new class symbol + * @throws DuplicateNameException if the name is duplicated in the parent namespace + * @throws InvalidInputException if the name is not valid + * @throws IllegalArgumentException if some other argument is not valid + */ TraceClassSymbol add(String name, TraceNamespaceSymbol parent, SourceType source) throws DuplicateNameException, InvalidInputException, IllegalArgumentException; } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceFunctionSymbol.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceFunctionSymbol.java deleted file mode 100644 index 86d2ecadaf..0000000000 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceFunctionSymbol.java +++ /dev/null @@ -1,81 +0,0 @@ -/* ### - * 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.trace.model.symbol; - -import ghidra.program.model.listing.*; -import ghidra.program.model.symbol.SourceType; -import ghidra.util.exception.DuplicateNameException; -import ghidra.util.exception.InvalidInputException; - -public interface TraceFunctionSymbol - extends TraceNamespaceSymbol, TraceSymbolWithLifespan, Function { - - // TODO: If possible, remove the DuplicateNameException on these three methods. - /* - @Override - void setName(String newName, SourceType source) throws InvalidInputException; - - @Override - void setNameAndNamespace(String newName, Namespace newNamespace, SourceType source) - throws InvalidInputException, CircularDependencyException; - - @Override - void setNamespace(Namespace newNamespace) - throws InvalidInputException, CircularDependencyException; - */ - - @Override - TraceParameterSymbol getReturn(); - - @Override - TraceParameterSymbol addParameter(Variable var, SourceType source) - throws DuplicateNameException, InvalidInputException; - - @Override - TraceParameterSymbol insertParameter(int ordinal, Variable var, SourceType source) - throws DuplicateNameException, InvalidInputException; - - @Override - Parameter getParameter(int ordinal); - - @Override - Parameter moveParameter(int fromOrdinal, int toOrdinal) throws InvalidInputException; - - @Override - Parameter[] getParameters(); - - @Override - Parameter[] getParameters(VariableFilter filter); - - @Override - TraceLocalVariableSymbol[] getLocalVariables(); - - @Override - TraceLocalVariableSymbol[] getLocalVariables(VariableFilter filter); - - @Override - Variable[] getAllVariables(); - - @Override - Variable[] getVariables(VariableFilter filter); - - @Override - TraceLocalVariableSymbol addLocalVariable(Variable var, SourceType source) - throws DuplicateNameException, InvalidInputException; - - @Override - TraceFunctionSymbol getThunkedFunction(boolean recursive); -} diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceFunctionSymbolView.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceFunctionSymbolView.java deleted file mode 100644 index 5fd3000820..0000000000 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceFunctionSymbolView.java +++ /dev/null @@ -1,66 +0,0 @@ -/* ### - * 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.trace.model.symbol; - -import java.util.Collection; - -import ghidra.program.database.function.OverlappingFunctionException; -import ghidra.program.model.address.Address; -import ghidra.program.model.address.AddressSetView; -import ghidra.program.model.lang.PrototypeModel; -import ghidra.program.model.symbol.SourceType; -import ghidra.trace.model.Lifespan; -import ghidra.util.exception.InvalidInputException; - -public interface TraceFunctionSymbolView extends TraceSymbolWithLocationView { - - TraceFunctionSymbol add(Lifespan lifespan, Address entryPoint, AddressSetView body, - String name, TraceFunctionSymbol thunked, TraceNamespaceSymbol parent, - SourceType source) throws InvalidInputException, OverlappingFunctionException; - - default TraceFunctionSymbol create(long snap, Address entryPoint, AddressSetView body, - String name, TraceFunctionSymbol thunked, TraceNamespaceSymbol parent, - SourceType source) throws InvalidInputException, OverlappingFunctionException { - return add(Lifespan.nowOn(snap), entryPoint, body, name, thunked, parent, source); - } - - /** - * Get the ordered unmodifiable set of defined calling convention names. The reserved names - * "unknown" and "default" are not included. The returned collection may not include all names - * referenced by various functions and function-definitions. This set is limited to - * those defined by the associated compiler specification. - * - * @return the set of defined calling convention names. - */ - Collection getCallingConventionNames(); - - /** - * Get the default calling convention's prototype model. - * - * @return the default calling convention prototype model. - */ - PrototypeModel getDefaultCallingConvention(); - - /** - * Get the prototype model of the calling convention with the specified name from the - * associated compiler specification. If {@link Function#DEFAULT_CALLING_CONVENTION_STRING} - * is specified {@link #getDefaultCallingConvention()} will be returned. - * - * @param name the calling convention name - * @return the named function calling convention prototype model or null if not defined. - */ - PrototypeModel getCallingConvention(String name); -} diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceGlobalVariableSymbol.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceGlobalVariableSymbol.java deleted file mode 100644 index dc3dae3876..0000000000 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceGlobalVariableSymbol.java +++ /dev/null @@ -1,21 +0,0 @@ -/* ### - * 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.trace.model.symbol; - -public interface TraceGlobalVariableSymbol extends TraceVariableSymbol /*, GlobalVariable, no? */ -{ - -} diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceGlobalVariableSymbolView.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceGlobalVariableSymbolView.java deleted file mode 100644 index 75cb91d140..0000000000 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceGlobalVariableSymbolView.java +++ /dev/null @@ -1,21 +0,0 @@ -/* ### - * 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.trace.model.symbol; - -public interface TraceGlobalVariableSymbolView - extends TraceSymbolWithAddressNoDuplicatesView { - -} diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceLabelSymbol.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceLabelSymbol.java index 06c4248b8c..3b0cb7e09f 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceLabelSymbol.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceLabelSymbol.java @@ -15,14 +15,16 @@ */ package ghidra.trace.model.symbol; -import ghidra.program.database.symbol.CodeSymbol; import ghidra.trace.model.listing.TraceCodeUnit; /** - * TODO: Document me - * - * See {@link CodeSymbol} + * A trace label symbol. */ public interface TraceLabelSymbol extends TraceSymbolWithLifespan { + /** + * Get the code unit at this label + * + * @return the code unit + */ TraceCodeUnit getCodeUnit(); } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceLabelSymbolView.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceLabelSymbolView.java index c87c2a25e1..175ee7c613 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceLabelSymbolView.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceLabelSymbolView.java @@ -21,11 +21,39 @@ import ghidra.trace.model.Lifespan; import ghidra.trace.model.thread.TraceThread; import ghidra.util.exception.InvalidInputException; +/** + * The label symbol view. + */ public interface TraceLabelSymbolView extends TraceSymbolWithLocationView { - + /** + * Add a new label symbol. + * + * @param lifespan the lifespan of the symbol + * @param thread the thread, if in register space + * @param address the address of the label + * @param name the name of the label + * @param parent the parent namespace + * @param source the source + * @return the new label symbol + * @throws InvalidInputException if the name is not valid + */ TraceLabelSymbol add(Lifespan lifespan, TraceThread thread, Address address, String name, TraceNamespaceSymbol parent, SourceType source) throws InvalidInputException; + /** + * A shorthand for + * {@link #add(Lifespan, TraceThread, Address, String, TraceNamespaceSymbol, SourceType)} where + * lifespan is from the given snap on. + * + * @param snap the starting snapshot key of the symbol + * @param thread the thread, if in register space + * @param address the address of the label + * @param name the name of the label + * @param parent the parent namespace + * @param source the source + * @return the new label symbol + * @throws InvalidInputException if the name is not valid + */ default TraceLabelSymbol create(long snap, TraceThread thread, Address address, String name, TraceNamespaceSymbol parent, SourceType source) throws InvalidInputException { return add(Lifespan.nowOn(snap), thread, address, name, parent, source); diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceLocalVariableSymbol.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceLocalVariableSymbol.java deleted file mode 100644 index 7440a379a3..0000000000 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceLocalVariableSymbol.java +++ /dev/null @@ -1,22 +0,0 @@ -/* ### - * 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.trace.model.symbol; - -import ghidra.program.model.listing.LocalVariable; - -public interface TraceLocalVariableSymbol extends TraceVariableSymbol, LocalVariable { - -} diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceLocalVariableSymbolView.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceLocalVariableSymbolView.java deleted file mode 100644 index 0f268e038d..0000000000 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceLocalVariableSymbolView.java +++ /dev/null @@ -1,21 +0,0 @@ -/* ### - * 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.trace.model.symbol; - -public interface TraceLocalVariableSymbolView - extends TraceSymbolWithAddressNoDuplicatesView { - -} diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceNamespaceSymbol.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceNamespaceSymbol.java index f3f1b35906..64928dcf9f 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceNamespaceSymbol.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceNamespaceSymbol.java @@ -20,6 +20,9 @@ import java.util.Collection; import ghidra.program.model.symbol.Namespace; import ghidra.trace.model.Trace; +/** + * A trace namespace symbol. + */ public interface TraceNamespaceSymbol extends TraceSymbol, Namespace { @Override Trace getTrace(); @@ -37,6 +40,11 @@ public interface TraceNamespaceSymbol extends TraceSymbol, Namespace { @Override TraceNamespaceSymbol getParentNamespace(); + /** + * Get the children of this namespace + * + * @return the children + */ Collection getChildren(); @Override diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceNamespaceSymbolView.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceNamespaceSymbolView.java index bcd894fd69..c8570a6491 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceNamespaceSymbolView.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceNamespaceSymbolView.java @@ -19,9 +19,21 @@ import ghidra.program.model.symbol.SourceType; import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.InvalidInputException; +/** + * The namespace symbol view. + */ public interface TraceNamespaceSymbolView extends TraceSymbolNoDuplicatesView { - + /** + * Add a new namespace symbol. + * + * @param name the name of the namespace + * @param parent the parent namespace + * @param source the source + * @return the new namespace symbol + * @throws DuplicateNameException if the name is duplicated in the parent namespace + * @throws InvalidInputException if the name is not valid + */ TraceNamespaceSymbol add(String name, TraceNamespaceSymbol parent, SourceType source) throws DuplicateNameException, InvalidInputException; } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceParameterSymbol.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceParameterSymbol.java deleted file mode 100644 index 469521d707..0000000000 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceParameterSymbol.java +++ /dev/null @@ -1,22 +0,0 @@ -/* ### - * 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.trace.model.symbol; - -import ghidra.program.model.listing.Parameter; - -public interface TraceParameterSymbol extends TraceSymbol, Parameter { - -} diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceParameterSymbolView.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceParameterSymbolView.java deleted file mode 100644 index e90711fc06..0000000000 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceParameterSymbolView.java +++ /dev/null @@ -1,21 +0,0 @@ -/* ### - * 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.trace.model.symbol; - -public interface TraceParameterSymbolView - extends TraceSymbolWithAddressNoDuplicatesView { - -} diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceSymbol.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceSymbol.java index 92145773f5..b3013ced39 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceSymbol.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceSymbol.java @@ -17,14 +17,37 @@ package ghidra.trace.model.symbol; import java.util.Collection; +import ghidra.program.model.listing.Program; +import ghidra.program.model.symbol.Namespace; import ghidra.program.model.symbol.Symbol; import ghidra.trace.model.Trace; import ghidra.trace.model.thread.TraceThread; import ghidra.util.task.TaskMonitor; +/** + * A trace symbol. + * + *

+ * This is essentially the equivalent concept of {@link Symbol} from a {@link Program}. One + * important distinction is that in the trace implementation, the symbol and the object it describes + * are the same. For example, in a {@link Program}, a {@link Namespace} and its symbol are two + * different things. To get the namespace, you would invoke {@link Symbol#getObject()}. That is + * unnecessary, though permissible, with a trace, because {@link TraceNamespaceSymbol} extends from + * both {@link Namespace} and {@link Symbol}. + */ public interface TraceSymbol extends Symbol { + /** + * Get the trace to which this symbol belongs. + * + * @return the trace + */ Trace getTrace(); + /** + * If in register space, get the thread associated with this symbol. + * + * @return the thread + */ TraceThread getThread(); @Override @@ -42,6 +65,11 @@ public interface TraceSymbol extends Symbol { @Override TraceReference[] getReferences(TaskMonitor monitor); + /** + * Get all memory references to the address of this symbol. + * + * @return the references + */ Collection getReferenceCollection(); /** diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceSymbolManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceSymbolManager.java index fedd56ad6c..fa00a407a1 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceSymbolManager.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceSymbolManager.java @@ -18,19 +18,32 @@ package ghidra.trace.model.symbol; import java.util.Collection; import java.util.Comparator; +import ghidra.program.model.listing.Program; import ghidra.trace.model.Trace; +/** + * The symbol table for traces. + * + *

+ * Currently, functions are not supported, so effectively, the only symbol types possible in a trace + * are: labels, namespaces, and classes. Global variables are partially implemented, but as they are + * not finished, even in {@link Program}, they are not available in traces, either. + * + *

+ * This manager supports a "fluid" API syntax. The methods on this manager narrow the scope in terms + * of the symbol type. Each returns a view, the methods of which operate on that type specifically. + * For example, to get the label at a specific address: + * + *

+ * trace.getSymbolManager().labels().getAt(0, null, addr, false);
+ * 
+ */ public interface TraceSymbolManager { + /** + * A comparator that sorts primary symbols first. + */ static Comparator PRIMALITY_COMPARATOR = (a, b) -> { - boolean aFunc = a instanceof TraceFunctionSymbol; - boolean bFunc = b instanceof TraceFunctionSymbol; - if (aFunc && !bFunc) { - return -1; - } - if (!aFunc && bFunc) { - return 1; - } boolean aPrim = a.isPrimary(); boolean bPrim = b.isPrimary(); if (aPrim && !bPrim) { @@ -42,47 +55,94 @@ public interface TraceSymbolManager { return 0; }; + /** + * Get the trace for this manager. + * + * @return the trace + */ Trace getTrace(); + /** + * Get a symbol by its unique identifier. + * + *

+ * The identifier is only unique within this trace. + * + * @param symbolID the id + * @return the symbol, or null + */ TraceSymbol getSymbolByID(long symbolID); + /** + * Get the trace's global namespace. + * + * @return the global namespace + */ TraceNamespaceSymbol getGlobalNamespace(); + /** + * Get a view of the labels in the trace. + * + * @return the labels view + */ TraceLabelSymbolView labels(); + /** + * Get a view of the namespaces in the trace. + * + * @return the namespaces view + */ TraceNamespaceSymbolView namespaces(); + /** + * Get a view of the classes in the trace. + * + * @return the classes view + */ TraceClassSymbolView classes(); - TraceFunctionSymbolView functions(); - - TraceParameterSymbolView parameters(); - - TraceLocalVariableSymbolView localVariables(); - - TraceGlobalVariableSymbolView globalVariables(); - /** - * TODO: Document me + * Get a view of all the namespaces (including classes) in the trace. * - * Note because functions are namespaces, and duplicate function names are allowed, this - * composed view may have duplicate names. - * - * @return + * @return the all-namespaces view */ TraceSymbolView allNamespaces(); - TraceSymbolWithAddressNoDuplicatesView allLocals(); - - TraceSymbolWithAddressNoDuplicatesView allVariables(); - - TraceSymbolWithLocationView labelsAndFunctions(); - - TraceSymbolNoDuplicatesView notLabelsNorFunctions(); + /** + * Get a view of all the symbols except labels in the trace. + * + *

+ * NOTE: This method is somewhat vestigial. At one point, functions were partially + * implemented, so this would have contained functions, variables, etc. As the manager now only + * supports labels, namespaces, and classes, this is essentially the same as + * {@link #allNamespaces()}. + * + * @return the not-labels view + */ + TraceSymbolNoDuplicatesView notLabels(); + /** + * Get a view of all symbols in the trace. + * + * @return the all-symbols view + */ TraceSymbolView allSymbols(); + /** + * Get the set of unique symbol IDs that are added going from one snapshot to another. + * + * @param from the first snapshot key + * @param to the second snapshot key + * @return the set of IDs absent in the first but present in the second + */ Collection getIDsAdded(long from, long to); + /** + * Get the set of unique symbol IDs that are removed going from one snapshot to another. + * + * @param from the first snapshot key + * @param to the second snapshot key + * @return the set of IDs present in the first but absent in the second + */ Collection getIDsRemoved(long from, long to); } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceSymbolNoDuplicatesView.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceSymbolNoDuplicatesView.java index f34af4a0a7..eb28f22a20 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceSymbolNoDuplicatesView.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceSymbolNoDuplicatesView.java @@ -17,8 +17,20 @@ package ghidra.trace.model.symbol; import ghidra.util.LockHold; +/** + * A symbol view where names cannot be duplicated within the same parent namespace + * + * @param the type of symbols in the view + */ public interface TraceSymbolNoDuplicatesView extends TraceSymbolView { + /** + * Get the child of the given parent having the given name. + * + * @param name the name of the symbol + * @param parent the parent namespace + * @return the symbol, or null + */ default T getChildNamed(String name, TraceNamespaceSymbol parent) { try (LockHold hold = getManager().getTrace().lockRead()) { for (T symbol : getChildrenNamed(name, parent)) { @@ -28,6 +40,13 @@ public interface TraceSymbolNoDuplicatesView extends Trac } } + /** + * A shorthand for {@link #getChildNamed(String, TraceNamespaceSymbol)} where parent is the + * global namespace. + * + * @param name the name of the symbol + * @return the symbol, or null + */ default T getGlobalNamed(String name) { return getChildNamed(name, getManager().getGlobalNamespace()); } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceSymbolView.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceSymbolView.java index 63e4f19aea..6dd60f0e15 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceSymbolView.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceSymbolView.java @@ -18,44 +18,102 @@ package ghidra.trace.model.symbol; import java.util.Collection; import java.util.Iterator; +/** + * A type-specific view in the trace symbol table + * + *

+ * The sub-interfaces of this handle the nuances for symbol types with more capabilities and/or + * restrictions. + * + * @param the type of symbols in the view + */ public interface TraceSymbolView { + /** + * Get the symbol manager for the trace. + * + * @return the symbol manager + */ TraceSymbolManager getManager(); + /** + * Get the number of symbols in this view. + * + * @param includeDynamicSymbols true to include dynamically-generated symbols + * @return the number of symbols + */ default int size(boolean includeDynamicSymbols) { return getAll(includeDynamicSymbols).size(); } + /** + * Get all the symbols in this view. + * + * @param includeDynamicSymbols true to include dynamically-generated symbols + * @return the symbols in this view satisfying the query + */ Collection getAll(boolean includeDynamicSymbols); + /** + * Get all children of the given parent namespace having the given name in this view. + * + * @param name the name of the symbols + * @param parent the parent namespace + * @return the symbols in this view satisfying the query + */ Collection getChildrenNamed(String name, TraceNamespaceSymbol parent); + /** + * Get all children of the given parent namespace in this view. + * + * @param parent the parent namespace + * @return the symbols in this view satisfying the query + */ Collection getChildren(TraceNamespaceSymbol parent); + /** + * A shorthand for {@link #getChildrenNamed(String, TraceNamespaceSymbol)} where parent is the + * global namespace. + * + * @param name the name of the symbols + * @return the symbols in this view satisfying the query + */ default Collection getGlobalsNamed(String name) { return getChildrenNamed(name, getManager().getGlobalNamespace()); } + /** + * A shorthand for {@link #getChildren(TraceNamespaceSymbol)} where parent is the global + * namespace. + * + * @return the symbols in this view satisfying the query + */ default Collection getGlobals() { return getChildren(getManager().getGlobalNamespace()); } /** - * Get symbols with the given name, regardless of parent namespace + * Get symbols in this view with the given name, regardless of parent namespace * - * @param name the name - * @return the collection of symbols with the given name + * @param name the name of the symbols + * @return the symbols in this view satisfying the query */ Collection getNamed(String name); /** - * Get symbols whose names match the given glob, regardless of parent namespace + * Get symbols in this view whose names match the given glob, regardless of parent namespace * * @param glob the glob (* matches zero-or-more, ? matches one character) * @param caseSensitive true to match case - * @return the collection of matching symbols + * @return the symbols in this view satisfying the query */ Collection getWithMatchingName(String glob, boolean caseSensitive); + /** + * Scan symbols in this view lexicographically by name starting at the given lower bound + * + * @param startName the starting lower bound + * @return an iterator over symbols in this view satisfying the query + */ Iterator scanByName(String startName); } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceSymbolWithAddressNoDuplicatesView.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceSymbolWithAddressNoDuplicatesView.java index fb8652eee2..4d5fac1106 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceSymbolWithAddressNoDuplicatesView.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceSymbolWithAddressNoDuplicatesView.java @@ -15,6 +15,11 @@ */ package ghidra.trace.model.symbol; +/** + * A symbol view where names cannot be duplicated and things have an address + * + * @param the type of symbols in the view + */ public interface TraceSymbolWithAddressNoDuplicatesView extends TraceSymbolWithAddressView, TraceSymbolNoDuplicatesView { // Just combine the interfaces diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceSymbolWithAddressView.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceSymbolWithAddressView.java index 53adaa78a1..b743d29ec5 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceSymbolWithAddressView.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceSymbolWithAddressView.java @@ -21,22 +21,70 @@ import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressRange; /** - * A view for symbols located in stack or register space not associated with a particular thread. + * A symbol view for things with an address in stack or register space, but not associated with a + * trace thread. * - * @param the type of symbol in the view + *

+ * NOTE: This class is somewhat vestigial. It would be used to index parameters, locals, and + * global variables by their storage addresses. However, functions (and thus parameters and locals) + * are no longer supported. Furthermore, global variables are not fully implemented, yet. + * + * @implNote If this is later used for global variables, we might need to consider that the variable + * is no longer implicitly bound in time by a parent function. We might remove this and + * use {@link TraceSymbolWithLocationView} instead. Even if we brought back function + * support, being able to query by those implicit bounds would probably be useful. + * + * @param the type of symbols in the view */ public interface TraceSymbolWithAddressView extends TraceSymbolView { + /** + * Get the child of the given parent having the given name at the given address. + * + * @param name the name of the symbol + * @param address the address of the symbol + * @param parent the parent namespace + * @return the symbol, or null + */ T getChildWithNameAt(String name, Address address, TraceNamespaceSymbol parent); + /** + * A shorthand for {@link #getChildWithNameAt(String, Address, TraceNamespaceSymbol)} where + * parent is the global namespace. + * + * @param name the name of the symbol + * @param address the address of the symbol + * @return the symbol, or null + */ default T getGlobalWithNameAt(String name, Address address) { return getChildWithNameAt(name, address, getManager().getGlobalNamespace()); } + /** + * Get symbols in this view intersecting the given address range. + * + * @param range the range + * @param includeDynamicSymbols true to include dynamically-generated symbols + * @return the symbols in this view satisfying the query + */ Collection getIntersecting(AddressRange range, boolean includeDynamicSymbols); + /** + * Get symbols in this view containing the given address. + * + * @param address the address of the symbol + * @param includeDynamicSymbols true to include dynamically-generated symbols + * @return the symbols in this view satisfying the query + */ Collection getAt(Address address, boolean includeDynamicSymbols); + /** + * Check if this view contains any symbols at the given address. + * + * @param address the address of the symbol + * @param includeDynamicSymbols true to include dynamically-generated symbols + * @return true if any symbols in this view satisfy the query + */ default boolean hasAt(Address address, boolean includeDynamicSymbols) { return !getAt(address, includeDynamicSymbols).isEmpty(); } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceSymbolWithLifespan.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceSymbolWithLifespan.java index 8cffe140e9..8895976876 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceSymbolWithLifespan.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceSymbolWithLifespan.java @@ -17,12 +17,35 @@ package ghidra.trace.model.symbol; import ghidra.trace.model.Lifespan; +/** + * A trace symbol having a lifespan. + */ public interface TraceSymbolWithLifespan extends TraceSymbol { + /** + * Get the lifespan of the symbol + * + * @return the lifespan + */ Lifespan getLifespan(); + /** + * Get the minimum snapshot key in the lifespan + * + * @return the minimum snapshot key + */ long getStartSnap(); + /** + * Set the maximum snapshot key in the lifespan + * + * @param snap the new maximum snapshot key + */ void setEndSnap(long snap); + /** + * Get the maximum snapshot key in the lifespan + * + * @return the maximum snapshot key + */ long getEndSnap(); } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceSymbolWithLocationView.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceSymbolWithLocationView.java index 3e424acc4b..81c92b5da4 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceSymbolWithLocationView.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceSymbolWithLocationView.java @@ -22,28 +22,70 @@ import ghidra.trace.model.Lifespan; import ghidra.trace.model.thread.TraceThread; import ghidra.util.LockHold; +/** + * A symbol view for things bound by an address range and lifespan. + * + *

+ * NOTE: We may eventually drop the {@code thread} parameter from these methods, as we + * transition to using register-space overlays. + * + * @param the type of symbols in the view + */ public interface TraceSymbolWithLocationView extends TraceSymbolView { + /** + * Get the child of the given parent having the given name at the given point. + * + * @param name the name of the symbol + * @param snap the snapshot key + * @param thread the thread, if in register space + * @param address the address of the symbol + * @param parent the parent namespace + * @return the symbol, or null + */ T getChildWithNameAt(String name, long snap, TraceThread thread, Address address, TraceNamespaceSymbol parent); + /** + * A shorthand for + * {@link #getChildWithNameAt(String, long, TraceThread, Address, TraceNamespaceSymbol)} where + * parent is the global namespace. + * + * @param name the name of the symbol + * @param snap the snapshot key + * @param thread the thread, if in register space + * @param address the address of the symbol + * @return the symbol, or null + */ default T getGlobalWithNameAt(String name, long snap, TraceThread thread, Address address) { return getChildWithNameAt(name, snap, thread, address, getManager().getGlobalNamespace()); } + /** + * Get symbols in this view intersecting the given box. + * + * @param span the time bound of the box + * @param thread the thread, if in register space + * @param range the address bound of the box + * @param includeDynamicSymbols true to include dynamically-generated symbols + * @param forward true if the collection should be ordered forward by address, false for + * backward by address. + * @return the symbols in this view satisfying the query + */ Collection getIntersecting(Lifespan span, TraceThread thread, AddressRange range, boolean includeDynamicSymbols, boolean forward); /** - * Get the symbols at the given snap and address, starting with the primary + * Get symbols in this view at the given point. * - * TODO: Document me + *

+ * The result will be ordered with the primary symbol first. * - * @param snap - * @param thread - * @param address - * @param includeDynamicSymbols - * @return + * @param snap the snapshot key + * @param thread the thread, if in register space + * @param address the address of the symbols + * @param includeDynamicSymbols true to include dynamically-generated symbols + * @return the symbols in this view satisfying the query */ default Collection getAt(long snap, TraceThread thread, Address address, boolean includeDynamicSymbols) { @@ -56,6 +98,15 @@ public interface TraceSymbolWithLocationView extends Trac } } + /** + * Check if this view contains any symbols at the given point. + * + * @param snap the snapshot key + * @param thread the thread, if in register space + * @param address the address of the symbols + * @param includeDynamicSymbols true to include dynamically-generated symbols + * @return true if any symbols in this view satisfy the query + */ default boolean hasAt(long snap, TraceThread thread, Address address, boolean includeDynamicSymbols) { try (LockHold hold = getManager().getTrace().lockRead()) { diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceVariableSymbol.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceVariableSymbol.java deleted file mode 100644 index ac7b972759..0000000000 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceVariableSymbol.java +++ /dev/null @@ -1,23 +0,0 @@ -/* ### - * 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.trace.model.symbol; - -import ghidra.program.model.listing.Variable; - -public interface TraceVariableSymbol extends TraceSymbol, Variable { - @Override - TraceFunctionSymbol getFunction(); -} diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceProgramViewFunctionManagerTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceProgramViewFunctionManagerTest.java deleted file mode 100644 index 7e1255b2e1..0000000000 --- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceProgramViewFunctionManagerTest.java +++ /dev/null @@ -1,435 +0,0 @@ -/* ### - * 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.trace.database.program; - -import static ghidra.lifecycle.Unfinished.*; -import static org.junit.Assert.*; - -import java.io.IOException; -import java.util.Collection; -import java.util.Iterator; - -import org.junit.*; - -import db.Transaction; -import ghidra.app.cmd.function.AddStackVarCmd; -import ghidra.app.cmd.refs.AddStackRefCmd; -import ghidra.program.database.ProgramBuilder; -import ghidra.program.database.function.OverlappingFunctionException; -import ghidra.program.model.address.*; -import ghidra.program.model.data.PointerDataType; -import ghidra.program.model.lang.PrototypeModel; -import ghidra.program.model.listing.*; -import ghidra.program.model.symbol.*; -import ghidra.test.AbstractGhidraHeadlessIntegrationTest; -import ghidra.trace.database.ToyDBTraceBuilder; -import ghidra.util.exception.InvalidInputException; - -public class DBTraceProgramViewFunctionManagerTest extends AbstractGhidraHeadlessIntegrationTest { - ToyDBTraceBuilder b; - FunctionManager functionManager; - Program program; - Transaction tx; - - @Before - public void setUpFunctionManagerTest() throws IOException { - b = new ToyDBTraceBuilder("Testing", ProgramBuilder._TOY); - program = b.trace.getFixedProgramView(0); - functionManager = program.getFunctionManager(); - tx = b.startTransaction(); - } - - @After - public void tearDownFunctionManagerTest() { - tx.close(); - b.close(); - } - - protected Function createFunction(String name, Address entry, AddressSetView body) - throws InvalidInputException, OverlappingFunctionException { - Function created = - functionManager.createFunction(name, entry, body, SourceType.USER_DEFINED); - Function found = functionManager.getFunctionAt(entry); - assertSame(created, found); - assertEquals(entry, created.getEntryPoint()); - assertEquals(body, created.getBody()); - return created; - } - - @Test - public void testCreateFunction() throws Exception { - - createFunction("foo", b.addr(100), b.set(b.range(100, 200))); - - // Overlapping functions - not allowed - try { - functionManager.createFunction("foo1", b.addr(50), b.set(b.range(50, 100)), - SourceType.USER_DEFINED); - Assert.fail(); - } - catch (OverlappingFunctionException e) { - // Expected - } - try { - functionManager.createFunction("foo2", b.addr(200), b.set(b.range(200, 250)), - SourceType.USER_DEFINED); - Assert.fail(); - } - catch (OverlappingFunctionException e) { - // Expected - } - try { - functionManager.createFunction("foo3", b.addr(150), b.set(b.range(150, 250)), - SourceType.USER_DEFINED); - Assert.fail(); - } - catch (OverlappingFunctionException e) { - // Expected - } - - // Invalid entry address - try { - createFunction("foo4", b.addr(250), b.set(b.range(300, 350))); - Assert.fail(); - } - catch (IllegalArgumentException e) { - // expected - } - - createFunction("foo4", b.addr(50), b.set(b.range(50, 99))); - createFunction("foo5", b.addr(201), b.set(b.range(201, 250))); - - // try duplicate name - createFunction("foo5", b.addr(500), b.set(b.range(500, 600))); - } - - @Test - public void testCreateVarArgFunction() throws Exception { - - Function f = createFunction("foo", b.addr(100), b.set(b.range(100, 200))); - f.setVarArgs(true); - assertEquals(true, f.hasVarArgs()); - f.setVarArgs(false); - assertEquals(false, f.hasVarArgs()); - } - - @Test - public void testCreateInlineFunction() throws Exception { - - Function f = createFunction("foo", b.addr(100), b.set(b.range(100, 200))); - assertEquals(false, f.isInline()); - f.setInline(true); - assertEquals(true, f.isInline()); - f.setInline(false); - assertEquals(false, f.isInline()); - } - - @Test - public void testCreateNoReturnFunction() throws Exception { - - Function f = createFunction("foo", b.addr(100), b.set(b.range(100, 200))); - assertEquals(false, f.hasNoReturn()); - f.setNoReturn(true); - assertEquals(true, f.hasNoReturn()); - f.setNoReturn(false); - assertEquals(false, f.hasNoReturn()); - } - - @Test - @Ignore("TODO, low priority") - public void testRemoveFunction() throws Exception { - createFunction("foo", b.addr(100), b.set(b.range(100, 200))); - createFunction("foo1", b.addr(250), b.set(b.range(250, 350))); - Function foo2 = createFunction("foo2", b.addr(201), b.set(b.range(201, 249))); - - // add stack references and make sure they get removed when the - // function is deleted - int transactionIDForTest = program.startTransaction("test"); - AddStackVarCmd cmd = new AddStackVarCmd(foo2.getEntryPoint(), -4, "local_var", null, - SourceType.USER_DEFINED); - assertTrue(cmd.applyTo(program)); - cmd = new AddStackVarCmd(foo2.getEntryPoint(), 4, "param_1", null, SourceType.USER_DEFINED); - assertTrue(cmd.applyTo(program)); - - AddStackRefCmd c = new AddStackRefCmd(b.addr(210), 0, -4, SourceType.USER_DEFINED); - assertTrue(c.applyTo(program)); - c = new AddStackRefCmd(b.addr(222), 1, 4, SourceType.USER_DEFINED); - assertTrue(c.applyTo(program)); - - program.endTransaction(transactionIDForTest, true); - - Variable[] vars = foo2.getLocalVariables(); - assertEquals(1, vars.length); - - ReferenceManager refMgr = program.getReferenceManager(); - TODO(); // TODO: Need to support variable references - Reference[] vrefs = refMgr.getReferencesTo(vars[0]); - assertEquals(1, vrefs.length); - assertEquals(b.addr(210), vrefs[0].getFromAddress()); - - Parameter[] params = foo2.getParameters(); - assertEquals(1, params.length); - vrefs = refMgr.getReferencesTo(params[0]); - assertEquals(1, vrefs.length); - assertEquals(b.addr(222), vrefs[0].getFromAddress()); - - functionManager.removeFunction(b.addr(201)); - - vrefs = refMgr.getReferencesTo(vars[0]); - assertEquals(0, vrefs.length); - - vrefs = refMgr.getReferencesTo(params[0]); - assertEquals(0, vrefs.length); - - Function f = functionManager.getFunctionAt(b.addr(100)); - assertEquals(b.set(b.range(100, 200)), f.getBody()); - assertNull(functionManager.getFunctionAt(b.addr(201))); - f = functionManager.getFunctionAt(b.addr(250)); - assertEquals(b.set(b.range(250, 350)), f.getBody()); - - assertTrue(program.getSymbolTable() - .getPrimarySymbol( - b.addr(201)) - .getSymbolType() != SymbolType.FUNCTION); - } - - @Test - public void testGetFirstFunctionContaining() throws Exception { - createFunction("foo", b.addr(100), b.set(b.range(100, 200))); - createFunction("foo1", b.addr(250), b.set(b.range(250, 350))); - createFunction("foo2", b.addr(201), b.set(b.range(201, 249))); - - Function f = functionManager.getFunctionContaining(b.addr(120)); - assertEquals(b.set(b.range(100, 200)), f.getBody()); - - f = functionManager.getFunctionContaining(b.addr(240)); - assertTrue(b.set(b.range(201, 249)).equals(f.getBody())); - - } - - @Test - public void testIsInFunction() throws Exception { - createFunction("foo", b.addr(100), b.set(b.range(100, 200))); - createFunction("foo1", b.addr(250), b.set(b.range(250, 350))); - createFunction("foo2", b.addr(201), b.set(b.range(201, 249))); - assertTrue(!functionManager.isInFunction(b.addr(95))); - assertTrue(functionManager.isInFunction(b.addr(100))); - assertTrue(functionManager.isInFunction(b.addr(250))); - assertTrue(functionManager.isInFunction(b.addr(240))); - assertTrue(!functionManager.isInFunction(b.addr(500))); - } - - @Test - public void testGetFunctionsContaining() throws Exception { - createFunction("foo", b.addr(100), b.set(b.range(100, 200))); - createFunction("foo1", b.addr(250), b.set(b.range(250, 350))); - createFunction("foo2", b.addr(201), b.set(b.range(201, 249))); - - Function function = functionManager.getFunctionContaining(b.addr(160)); - assertNotNull(function); - assertEquals(b.addr(100), function.getEntryPoint()); - function = functionManager.getFunctionContaining(b.addr(50)); - assertNull(function); - function = functionManager.getFunctionContaining(b.addr(100)); - assertNotNull(function); - assertEquals(b.addr(100), function.getEntryPoint()); - - } - - @Test - public void testGetFunctionsOverlapping() throws Exception { - createFunction("foo", b.addr(100), b.set(b.range(100, 200))); - createFunction("foo1", b.addr(250), b.set(b.range(250, 350))); - createFunction("foo2", b.addr(201), b.set(b.range(201, 249))); - - AddressSet set = new AddressSet(); - set.addRange(b.addr(50), b.addr(100)); - set.addRange(b.addr(350), b.addr(500)); - Iterator iter = functionManager.getFunctionsOverlapping(set); - assertEquals(b.addr(100), iter.next().getEntryPoint()); - assertEquals(b.addr(250), iter.next().getEntryPoint()); - assertTrue(!iter.hasNext()); - - iter = functionManager.getFunctionsOverlapping(b.set(b.range(99, 199))); - assertEquals(b.addr(100), iter.next().getEntryPoint()); - assertTrue(!iter.hasNext()); - } - - /* - * Test for FunctionIterator getFunctions() - */ - @Test - public void testGetFunctions() throws Exception { - createFunction("foo", b.addr(100), b.set(b.range(100, 200))); - createFunction("foo1", b.addr(250), b.set(b.range(250, 350))); - createFunction("foo2", b.addr(201), b.set(b.range(201, 249))); - - FunctionIterator iter = functionManager.getFunctions(true); - int cnt = 0; - while (iter.hasNext()) { - ++cnt; - assertNotNull(iter.next()); - } - assertEquals(3, cnt); - } - - @Test - public void testGetReferencedFunction() throws Exception { - createFunction("foo", b.addr(100), b.set(b.range(100, 200))); - createFunction("foo1", b.addr(250), b.set(b.range(250, 350))); - Function foo2 = createFunction("foo2", b.addr(201), b.set(b.range(201, 249))); - - program.getMemory().setInt(b.addr(50), 201); - program.getListing().createData(b.addr(50), PointerDataType.dataType); - // TODO: It seems this is failing because of a missing inferred reference. - Reference cheating = program.getReferenceManager() - .addMemoryReference(b.addr(50), - b.addr(201), RefType.DATA, SourceType.ANALYSIS, 0); - // TODO: Remove the explicit reference above and ensure this test still passes - program.getReferenceManager().setPrimary(cheating, true); - // TODO: Also remove explit set primary - assertEquals(foo2, program.getFunctionManager().getReferencedFunction(b.addr(50))); - } - - /* - * Test for FunctionIterator getFunctions(Address) - */ - @Test - public void testGetFunctionsAddress() throws Exception { - createFunction("foo", b.addr(100), b.set(b.range(100, 200))); - createFunction("foo1", b.addr(250), b.set(b.range(250, 350))); - createFunction("foo2", b.addr(201), b.set(b.range(201, 249))); - - FunctionIterator iter = functionManager.getFunctions(b.addr(125), true); - int cnt = 0; - while (iter.hasNext()) { - ++cnt; - assertNotNull(iter.next()); - } - assertEquals(2, cnt); - } - - /* - * Test for FunctionIterator getFunctions(AddressSetView) - */ - @Test - public void testGetFunctionsAddressSetView() throws Exception { - createFunction("foo", b.addr(100), b.set(b.range(100, 200))); - createFunction("foo1", b.addr(250), b.set(b.range(250, 350))); - createFunction("foo2", b.addr(201), b.set(b.range(201, 249))); - - AddressSet asv = new AddressSet(); - asv.addRange(b.addr(50), b.addr(60)); - asv.addRange(b.addr(70), b.addr(90)); - asv.addRange(b.addr(110), b.addr(160)); - asv.addRange(b.addr(200), b.addr(249)); - - FunctionIterator iter = functionManager.getFunctions(asv, true); - int cnt = 0; - while (iter.hasNext()) { - ++cnt; - Function f = iter.next(); - assertEquals(b.set(b.range(201, 249)), f.getBody()); - } - assertEquals(1, cnt); - - } - - @Test - public void testFunctionIteratorBackwards() throws Exception { - createFunction("foo", b.addr(100), b.set(b.range(100, 200))); - createFunction("foo1", b.addr(201), b.set(b.range(201, 249))); - createFunction("foo2", b.addr(250), b.set(b.range(250, 350))); - - FunctionIterator iter = functionManager.getFunctions(false); - assertTrue(iter.hasNext()); - Function f = iter.next(); - assertEquals("foo2", f.getName()); - - assertTrue(iter.hasNext()); - f = iter.next(); - assertEquals("foo1", f.getName()); - - assertTrue(iter.hasNext()); - f = iter.next(); - assertEquals("foo", f.getName()); - - assertTrue(!iter.hasNext()); - } - - @Test - public void testFunctionIteratorBackwards2() throws Exception { - createFunction("foo", b.addr(100), b.set(b.range(100, 200))); - createFunction("foo1", b.addr(201), b.set(b.range(201, 210))); - createFunction("foo2", b.addr(250), b.set(b.range(250, 350))); - - FunctionIterator iter = functionManager.getFunctions(b.addr(250), false); - assertTrue(iter.hasNext()); - Function f = iter.next(); - assertEquals("foo2", f.getName()); - - assertTrue(iter.hasNext()); - f = iter.next(); - assertEquals("foo1", f.getName()); - - assertTrue(iter.hasNext()); - f = iter.next(); - assertEquals("foo", f.getName()); - - assertTrue(!iter.hasNext()); - } - - @Test - public void testFunctionIteratorBackwards3() throws Exception { - createFunction("foo", b.addr(100), b.set(b.range(100, 200))); - createFunction("foo1", b.addr(201), b.set(b.range(201, 210))); - createFunction("foo2", b.addr(250), b.set(b.range(250, 350))); - - FunctionIterator iter = functionManager.getFunctions(b.addr(300), false); - assertTrue(iter.hasNext()); - Function f = iter.next(); - assertEquals("foo2", f.getName()); - - assertTrue(iter.hasNext()); - f = iter.next(); - assertEquals("foo1", f.getName()); - - assertTrue(iter.hasNext()); - f = iter.next(); - assertEquals("foo", f.getName()); - - assertTrue(!iter.hasNext()); - } - - @Test - public void testGetDefaultCallingConvention() throws Exception { - PrototypeModel protoModel = functionManager.getDefaultCallingConvention(); - assertEquals("__stdcall", protoModel.getName()); - - PrototypeModel defaultModel = functionManager.getCallingConvention("default"); - assertEquals(defaultModel, protoModel); - } - - @Test - public void testGetCallingConventionNames() throws Exception { - Collection names = functionManager.getCallingConventionNames(); - assertTrue(names.size() >= 1); - for (String name : names) { - assertNotNull(functionManager.getCallingConvention(name)); - } - } - -} diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/symbol/DBTraceFunctionSymbolTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/symbol/DBTraceFunctionSymbolTest.java deleted file mode 100644 index a8a1342289..0000000000 --- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/symbol/DBTraceFunctionSymbolTest.java +++ /dev/null @@ -1,1916 +0,0 @@ -/* ### - * 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.trace.database.symbol; - -import static ghidra.lifecycle.Unfinished.*; -import static org.junit.Assert.*; - -import java.io.IOException; -import java.util.*; - -import org.junit.*; - -import db.Transaction; -import ghidra.app.cmd.function.AddRegisterParameterCommand; -import ghidra.app.cmd.function.AddStackVarCmd; -import ghidra.app.cmd.refs.AddStackRefCmd; -import ghidra.program.database.ProgramBuilder; -import ghidra.program.database.function.OverlappingFunctionException; -import ghidra.program.model.address.Address; -import ghidra.program.model.address.AddressSetView; -import ghidra.program.model.data.*; -import ghidra.program.model.lang.Register; -import ghidra.program.model.listing.*; -import ghidra.program.model.listing.Function.FunctionUpdateType; -import ghidra.program.model.symbol.*; -import ghidra.test.AbstractGhidraHeadlessIntegrationTest; -import ghidra.trace.database.ToyDBTraceBuilder; -import ghidra.trace.database.program.DBTraceProgramView; -import ghidra.trace.model.Lifespan; -import ghidra.trace.model.memory.TraceOverlappedRegionException; -import ghidra.trace.model.symbol.*; -import ghidra.util.IntersectionAddressSetView; -import ghidra.util.exception.DuplicateNameException; -import ghidra.util.exception.InvalidInputException; -import ghidra.util.task.TaskMonitor; - -public class DBTraceFunctionSymbolTest extends AbstractGhidraHeadlessIntegrationTest { - ToyDBTraceBuilder b; - TraceFunctionSymbolView functions; - TraceParameterSymbolView parameters; - - @Before - public void setUpFunctionTest() - throws IOException, TraceOverlappedRegionException, DuplicateNameException { - b = new ToyDBTraceBuilder("Testing", ProgramBuilder._TOY); - try (Transaction tx = b.startTransaction()) { - b.trace.getMemoryManager().createRegion("test", 0, b.range(100, 599)); - } - functions = b.trace.getSymbolManager().functions(); - parameters = b.trace.getSymbolManager().parameters(); - } - - @After - public void tearDownFunctionTest() { - b.close(); - } - - protected TraceFunctionSymbol createTestFunction() throws DuplicateNameException, - InvalidInputException, IllegalArgumentException, OverlappingFunctionException { - TraceSymbolManager symbolManager = b.trace.getSymbolManager(); - TraceClassSymbol c = symbolManager.classes() - .add("MyClass", - symbolManager.getGlobalNamespace(), SourceType.USER_DEFINED); - - DBTraceProgramView view0 = b.trace.getFixedProgramView(0); - TraceFunctionSymbol f = functions.create(0, b.addr(100), b.set(b.range(100, 350)), "foo", - null, c, SourceType.USER_DEFINED); - f.updateFunction("__stdcall", // - new ParameterImpl(null, Undefined4DataType.dataType, view0), List.of( // - new ParameterImpl("p1", Undefined4DataType.dataType, view0), // - new ParameterImpl("p2", Undefined2DataType.dataType, view0), // - new ParameterImpl("p3", Undefined1DataType.dataType, view0), // - new ParameterImpl("p4", Undefined4DataType.dataType, view0), // - new ParameterImpl("p5", Undefined2DataType.dataType, view0) // - ), FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS, true, SourceType.USER_DEFINED); - - assertFalse(f.hasCustomVariableStorage()); - assertEquals("__stdcall", f.getCallingConventionName()); - assertEquals(5, f.getParameterCount()); - return f; - } - - protected static void assertParameter(boolean checkStorage, Parameter expected, - Parameter actual) { - assertEquals(expected.getName(), actual.getName()); - if (!expected.getDataType().isEquivalent(actual.getDataType())) { - fail("Expected parameter of type " + expected.getDataType().getName() + ", but got " + - actual.getDataType().getName()); - } - if (checkStorage) { - assertEquals(expected.getVariableStorage(), actual.getVariableStorage()); - } - } - - protected Parameter createParameter(String name, DataType dt) throws InvalidInputException { - return new ParameterImpl(name, dt, b.trace.getFixedProgramView(0)); - } - - protected Parameter createParameter(String name, DataType dt, VariableStorage storage) - throws InvalidInputException { - return new ParameterImpl(name, dt, storage, b.trace.getFixedProgramView(0)); - } - - protected Parameter createReturn(DataType dt, VariableStorage storage) - throws InvalidInputException { - return createParameter(Parameter.RETURN_NAME, dt, storage); - } - - protected LocalVariable createLocal(String name, DataType dt, int offset) - throws InvalidInputException { - return new LocalVariableImpl(name, dt, offset, b.trace.getFixedProgramView(0)); - } - - protected LocalVariable createLocal(String name, int firstUseOffset, DataType dt, - VariableStorage storage) throws InvalidInputException { - return new LocalVariableImpl(name, firstUseOffset, dt, storage, - b.trace.getFixedProgramView(0)); - } - - protected LocalVariable createLocal(String name, int firstUseOffset, DataType dt, Address addr) - throws InvalidInputException { - return new LocalVariableImpl(name, firstUseOffset, dt, addr, - b.trace.getFixedProgramView(0)); - } - - protected VariableStorage createRegStorage(String registerName, int size) - throws InvalidInputException { - return new VariableStorage(b.trace.getFixedProgramView(0), - b.trace.getBaseLanguage().getRegister(registerName).getAddress(), size); - } - - protected VariableStorage createRegStorage(String registerName) throws InvalidInputException { - return new VariableStorage(b.trace.getFixedProgramView(0), - b.trace.getBaseLanguage().getRegister(registerName)); - } - - protected VariableStorage createRegStorage(String registerName, String... more) - throws InvalidInputException { - List regs = new ArrayList<>(1 + more.length); - regs.add(b.trace.getBaseLanguage().getRegister(registerName)); - for (String rn : more) { - regs.add(b.trace.getBaseLanguage().getRegister(rn)); - } - return new VariableStorage(b.trace.getFixedProgramView(0), - regs.toArray(new Register[regs.size()])); - } - - protected VariableStorage createStackStorage(int offset, int size) - throws InvalidInputException { - return new VariableStorage(b.trace.getFixedProgramView(0), offset, size); - } - - @Test - public void testGetName() throws InvalidInputException, OverlappingFunctionException { - try (Transaction tx = b.startTransaction()) { - TraceFunctionSymbol f = functions.create(0, b.addr(100), b.set(b.range(100, 200)), - "foo", null, null, SourceType.USER_DEFINED); - assertEquals("foo", f.getName()); - } - } - - @Test - public void testSetNameUser() - throws InvalidInputException, OverlappingFunctionException, DuplicateNameException { - try (Transaction tx = b.startTransaction()) { - TraceFunctionSymbol f = functions.create(0, b.addr(100), b.set(b.range(100, 200)), - "foo", null, null, SourceType.USER_DEFINED); - // TODO: Monitor for event - f.setName("bar", SourceType.USER_DEFINED); - assertEquals("bar", f.getName()); - assertEquals(SourceType.USER_DEFINED, f.getSource()); - // TODO: Check that event records correct old and new values - } - } - - @Test - public void testSetNameAnalysis() - throws InvalidInputException, OverlappingFunctionException, DuplicateNameException { - try (Transaction tx = b.startTransaction()) { - TraceFunctionSymbol f = functions.create(0, b.addr(100), b.set(b.range(100, 200)), - "foo", null, null, SourceType.USER_DEFINED); - f.setName("bar", SourceType.ANALYSIS); - assertEquals("bar", f.getName()); - assertEquals(SourceType.ANALYSIS, f.getSource()); - } - } - - @Test - public void testSetNameImported() - throws InvalidInputException, OverlappingFunctionException, DuplicateNameException { - try (Transaction tx = b.startTransaction()) { - TraceFunctionSymbol f = functions.create(0, b.addr(100), b.set(b.range(100, 200)), - "foo", null, null, SourceType.USER_DEFINED); - f.setName("bar", SourceType.IMPORTED); - assertEquals("bar", f.getName()); - assertEquals(SourceType.IMPORTED, f.getSource()); - } - } - - @Test - public void testSetNameDefault() - throws InvalidInputException, OverlappingFunctionException, DuplicateNameException { - try (Transaction tx = b.startTransaction()) { - String defaultName = SymbolUtilities.getDefaultFunctionName(b.addr(100)); - TraceFunctionSymbol f = functions.create(0, b.addr(100), b.set(b.range(100, 200)), - "foo", null, null, SourceType.USER_DEFINED); - f.setName(defaultName, SourceType.DEFAULT); - assertEquals(defaultName, f.getName()); - assertEquals(SourceType.DEFAULT, f.getSource()); - } - } - - @Test - public void testSetNameDefaultError() - throws InvalidInputException, OverlappingFunctionException, DuplicateNameException { - try (Transaction tx = b.startTransaction()) { - TraceFunctionSymbol f = functions.create(0, b.addr(100), b.set(b.range(100, 200)), - "foo", null, null, SourceType.USER_DEFINED); - try { - f.setName("bar", SourceType.DEFAULT); - fail(); - } - catch (IllegalArgumentException e) { - assertEquals("foo", f.getName()); - assertEquals(SourceType.USER_DEFINED, f.getSource()); - } - } - } - - @Test - public void testSetComment() throws InvalidInputException, OverlappingFunctionException { - try (Transaction tx = b.startTransaction()) { - TraceFunctionSymbol f = functions.create(0, b.addr(100), b.set(b.range(100, 200)), - "foo", null, null, SourceType.USER_DEFINED); - f.setComment("Test Comment\nLine 2"); - assertEquals("Test Comment\nLine 2", f.getComment()); - assertArrayEquals(new String[] { "Test Comment", "Line 2" }, f.getCommentAsArray()); - assertNull(f.getRepeatableComment()); - } - } - - @Test - public void testSetRepeatable() throws InvalidInputException, OverlappingFunctionException { - try (Transaction tx = b.startTransaction()) { - TraceFunctionSymbol f = functions.create(0, b.addr(100), b.set(b.range(100, 200)), - "foo", null, null, SourceType.USER_DEFINED); - f.setRepeatableComment("Test Comment\nLine 2"); - assertEquals("Test Comment\nLine 2", f.getRepeatableComment()); - assertArrayEquals(new String[] { "Test Comment", "Line 2" }, - f.getRepeatableCommentAsArray()); - } - } - - @Test - public void testCreateFunction() throws InvalidInputException, OverlappingFunctionException { - try (Transaction tx = b.startTransaction()) { - // TODO: Monitor events - AddressSetView body = b.set(b.range(100, 350), b.range(400, 450), b.range(500, 550)); - TraceFunctionSymbol f = - functions.create(0, b.addr(100), body, "foo", null, null, SourceType.USER_DEFINED); - - assertEquals(Lifespan.nowOn(0), f.getLifespan()); - assertEquals(b.addr(100), f.getEntryPoint()); - assertEquals(body, f.getBody()); - assertEquals("foo", f.getName()); - assertNull(f.getThunkedFunction(false)); - assertTrue(f.getParentNamespace().isGlobal()); - assertEquals(SourceType.USER_DEFINED, f.getSource()); - // TODO: Check that event record includes the created function (assertSame) - } - } - - @Test - public void testSetBody() throws InvalidInputException, OverlappingFunctionException { - try (Transaction tx = b.startTransaction()) { - // TODO: Monitor events - AddressSetView body = b.set(b.range(100, 350), b.range(400, 450), b.range(500, 550)); - TraceFunctionSymbol f = - functions.create(0, b.addr(100), body, "foo", null, null, SourceType.USER_DEFINED); - - body = b.set(b.range(50, 120), b.range(300, 400), b.range(10, 20)); - f.setBody(body); - assertEquals(body, f.getBody()); - // TODO: Check that event record includes the modified function (assertSame) - } - } - - @Test - public void testSetBodyClearVarRefs() - throws InvalidInputException, OverlappingFunctionException { - try (Transaction tx = b.startTransaction()) { - AddressSetView body = b.set(b.range(100, 350), b.range(400, 450), b.range(500, 550)); - TraceFunctionSymbol f = - functions.create(0, b.addr(100), body, "foo", null, null, SourceType.USER_DEFINED); - - DBTraceProgramView view0 = b.trace.getFixedProgramView(0); - - assertTrue(new AddStackVarCmd(f.getEntryPoint(), -4, "local_var", null, - SourceType.USER_DEFINED).applyTo(view0)); - assertTrue(new AddStackVarCmd(f.getEntryPoint(), 4, "param_1", null, - SourceType.USER_DEFINED).applyTo(view0)); - - assertTrue( - new AddStackRefCmd(b.addr(210), 0, -4, SourceType.USER_DEFINED).applyTo(view0)); - assertTrue( - new AddStackRefCmd(b.addr(222), 1, 4, SourceType.USER_DEFINED).applyTo(view0)); - assertTrue( - new AddStackRefCmd(b.addr(250), 1, -8, SourceType.USER_DEFINED).applyTo(view0)); - - TraceVariableSymbol[] vars = f.getLocalVariables(); - assertEquals(2, vars.length); - - TraceReferenceManager refMgr = b.trace.getReferenceManager(); - - // TODO: ReferenceManager getReferencesTo(Variable) - /* - TraceReference[] vrefs = refMgr.getReferencesTo(0, vars[0]); - assertEquals(1, vrefs.length); - assertEquals(b.addr(210), vrefs[0].getFromAddress()); - */ - - for (Address fromAddr : new IntersectionAddressSetView( - refMgr.getReferenceSources(Lifespan.at(0)), body).getAddresses(true)) { - Collection refs = refMgr.getReferencesFrom(0, fromAddr); - assertEquals(1, refs.size()); - } - - body = b.set(b.range(50, 120), b.range(300, 400), b.range(10, 20)); - - f.setBody(body); - assertEquals(body, f.getBody()); - - for (Address fromAddr : new IntersectionAddressSetView( - refMgr.getReferenceSources(Lifespan.at(0)), body).getAddresses(true)) { - Collection refs = refMgr.getReferencesFrom(0, fromAddr); - assertTrue(refs.isEmpty()); - } - } - } - - @Test - public void testSetBodyClearVarRefsExceptOneInBoth() - throws InvalidInputException, OverlappingFunctionException { - try (Transaction tx = b.startTransaction()) { - AddressSetView body = b.set(b.range(100, 350), b.range(400, 450), b.range(500, 550)); - TraceFunctionSymbol f = - functions.create(0, b.addr(100), body, "foo", null, null, SourceType.USER_DEFINED); - - DBTraceProgramView view0 = b.trace.getFixedProgramView(0); - - assertTrue(new AddStackVarCmd(f.getEntryPoint(), -4, "local_var", null, - SourceType.USER_DEFINED).applyTo(view0)); - assertTrue(new AddStackVarCmd(f.getEntryPoint(), 4, "param_1", null, - SourceType.USER_DEFINED).applyTo(view0)); - - assertTrue( - new AddStackRefCmd(b.addr(210), 0, -4, SourceType.USER_DEFINED).applyTo(view0)); - assertTrue( - new AddStackRefCmd(b.addr(222), 1, 4, SourceType.USER_DEFINED).applyTo(view0)); - assertTrue( - new AddStackRefCmd(b.addr(250), 1, -8, SourceType.USER_DEFINED).applyTo(view0)); - - TraceVariableSymbol[] vars = f.getLocalVariables(); - assertEquals(2, vars.length); - - TraceReferenceManager refMgr = b.trace.getReferenceManager(); - - // TODO: ReferenceManager getReferencesTo(Variable) - /* - TraceReference[] vrefs = refMgr.getReferencesTo(0, vars[0]); - assertEquals(1, vrefs.length); - assertEquals(b.addr(210), vrefs[0].getFromAddress()); - */ - - for (Address fromAddr : new IntersectionAddressSetView( - refMgr.getReferenceSources(Lifespan.at(0)), body).getAddresses(true)) { - Collection refs = refMgr.getReferencesFrom(0, fromAddr); - assertEquals(1, refs.size()); - } - - // NOTE: This time, the old and new bodies intersect where a reference was - // That reference should remain - body = b.set(b.range(50, 120), b.range(250, 400), b.range(10, 20)); - - f.setBody(body); - assertEquals(body, f.getBody()); - - Collection refs = new ArrayList<>(); - for (Address fromAddr : new IntersectionAddressSetView( - refMgr.getReferenceSources(Lifespan.at(0)), body).getAddresses(true)) { - refs.addAll(refMgr.getReferencesFrom(0, fromAddr)); - } - assertEquals(1, refs.size()); - TraceReference oneRef = refs.iterator().next(); - assertEquals(b.addr(250), oneRef.getFromAddress()); - } - } - - @Test - public void testSetBodyInvalidEntryPoint() - throws InvalidInputException, OverlappingFunctionException { - try (Transaction tx = b.startTransaction()) { - AddressSetView body = b.set(b.range(100, 350), b.range(400, 450), b.range(500, 550)); - TraceFunctionSymbol f = - functions.create(0, b.addr(100), body, "foo", null, null, SourceType.USER_DEFINED); - - try { - f.setBody(b.set(b.range(110, 120), b.range(300, 400), b.range(10, 20))); - fail(); - } - catch (IllegalArgumentException e) { - // Verify it didn't change - assertEquals(body, f.getBody()); - } - } - } - - @Test - public void testSetBodyOverlapping() - throws InvalidInputException, OverlappingFunctionException { - try (Transaction tx = b.startTransaction()) { - AddressSetView body = b.set(b.range(100, 350), b.range(400, 450), b.range(500, 550)); - TraceFunctionSymbol f = - functions.create(0, b.addr(100), body, "foo", null, null, SourceType.USER_DEFINED); - - functions.create(0, b.addr(0), b.set(b.range(0, 50), b.range(75, 90)), "foo2", null, - null, SourceType.USER_DEFINED); - - try { - f.setBody(b.set(b.range(50, 120), b.range(300, 400), b.range(10, 20))); - fail(); - } - catch (OverlappingFunctionException e) { - assertEquals(body, f.getBody()); - } - - try { - f.setBody(b.set(b.range(80, 120), b.range(300, 400), b.range(10, 20))); - fail(); - } - catch (OverlappingFunctionException e) { - assertEquals(body, f.getBody()); - } - } - } - - @Test - public void testSetBodyClearSymbols() - throws InvalidInputException, OverlappingFunctionException { - try (Transaction tx = b.startTransaction()) { - AddressSetView body = b.set(b.range(100, 350), b.range(400, 450), b.range(500, 550)); - TraceFunctionSymbol f = - functions.create(0, b.addr(100), body, "foo", null, null, SourceType.USER_DEFINED); - - DBTraceSymbolManager symbolManager = b.trace.getSymbolManager(); - DBTraceLabelSymbolView labels = symbolManager.labels(); - TraceLabelSymbol l1 = - labels.create(0, null, b.addr(410), "fred", f, SourceType.USER_DEFINED); - TraceLabelSymbol l2 = - labels.create(0, null, b.addr(100), "bob", f, SourceType.USER_DEFINED); - TraceLabelSymbol l3 = - labels.create(0, null, b.addr(200), "joe", f, SourceType.USER_DEFINED); - TraceLabelSymbol l4 = - labels.create(0, null, b.addr(400), "ricky", f, SourceType.USER_DEFINED); - - // Should remove fred and joe - body = b.set(b.range(10, 20), b.range(50, 120), b.range(300, 400)); - f.setBody(body); - assertEquals(body, f.getBody()); - - assertNull(symbolManager.getSymbolByID(l1.getID())); - assertSame(l2, symbolManager.getSymbolByID(l2.getID())); - assertNull(symbolManager.getSymbolByID(l3.getID())); - assertSame(l4, symbolManager.getSymbolByID(l4.getID())); - } - } - - @Test - public void testGetVariables() throws InvalidInputException, OverlappingFunctionException { - try (Transaction tx = b.startTransaction()) { - AddressSetView body = b.set(b.range(100, 350), b.range(400, 450), b.range(500, 550)); - TraceFunctionSymbol f = - functions.create(0, b.addr(100), body, "foo", null, null, SourceType.USER_DEFINED); - - DBTraceProgramView view0 = b.trace.getFixedProgramView(0); - - assertTrue(new AddStackVarCmd(f.getEntryPoint(), 4, "param_1", null, - SourceType.USER_DEFINED).applyTo(view0)); - assertTrue(new AddStackVarCmd(f.getEntryPoint(), 8, "param_2", null, - SourceType.USER_DEFINED).applyTo(view0)); - - assertTrue(new AddStackVarCmd(f.getEntryPoint(), -4, "local_var_1", null, - SourceType.USER_DEFINED).applyTo(view0)); - assertTrue(new AddStackVarCmd(f.getEntryPoint(), -8, "local_var_2", null, - SourceType.USER_DEFINED).applyTo(view0)); - assertTrue(new AddStackVarCmd(f.getEntryPoint(), -12, "local_var_3", null, - SourceType.USER_DEFINED).applyTo(view0)); - assertTrue(new AddStackVarCmd(f.getEntryPoint(), -16, "local_var_4", null, - SourceType.USER_DEFINED).applyTo(view0)); - assertTrue(new AddStackVarCmd(f.getEntryPoint(), -20, "local_var_5", null, - SourceType.USER_DEFINED).applyTo(view0)); - - TraceVariableSymbol[] locals = f.getLocalVariables(); - assertEquals(5, locals.length); - for (int i = 0; i < locals.length; i++) { - assertEquals("local_var_" + (i + 1), locals[i].getName()); - } - - Parameter[] params = f.getParameters(); - assertEquals(2, params.length); - for (int i = 0; i < params.length; i++) { - assertEquals("param_" + (i + 1), params[i].getName()); - } - } - } - - @Test - public void testGetReturnType() throws InvalidInputException, OverlappingFunctionException { - try (Transaction tx = b.startTransaction()) { - AddressSetView body = b.set(b.range(100, 350), b.range(400, 450), b.range(500, 550)); - TraceFunctionSymbol f = - functions.create(0, b.addr(100), body, "foo", null, null, SourceType.USER_DEFINED); - - assertEquals(DataType.DEFAULT, f.getReturnType()); - } - } - - @Test - public void testSetReturnType() throws InvalidInputException, OverlappingFunctionException { - try (Transaction tx = b.startTransaction()) { - AddressSetView body = b.set(b.range(100, 350), b.range(400, 450), b.range(500, 550)); - TraceFunctionSymbol f = - functions.create(0, b.addr(100), body, "foo", null, null, SourceType.USER_DEFINED); - - TraceParameterSymbol ret = f.getReturn(); - assertTrue(Undefined.isUndefined(ret.getDataType())); - // TODO: Monitor events - - f.setReturnType(ByteDataType.dataType, SourceType.ANALYSIS); - assertTrue(ByteDataType.dataType.isEquivalent(ret.getDataType())); - // TODO: Check for expected event - } - } - - @Test - public void testSetCustomStorage() throws DuplicateNameException, InvalidInputException, - IllegalArgumentException, OverlappingFunctionException { - try (Transaction tx = b.startTransaction()) { - TraceFunctionSymbol f = createTestFunction(); - int initialParamCnt = f.getParameterCount(); - - Structure bar = new StructureDataType("bar", 20); - Pointer barPtr = b.trace.getDataTypeManager().getPointer(bar); - - TraceParameterSymbol ret = f.getReturn(); - Parameter p1 = f.getParameter(0); - Parameter p2 = f.getParameter(1); - p2.setDataType(bar, SourceType.USER_DEFINED); - - VariableStorage initialRetStorage = ret.getVariableStorage(); - VariableStorage initialP1Storage = p1.getVariableStorage(); - VariableStorage initialP2Storage = p2.getVariableStorage(); - assertTrue(p2.isForcedIndirect()); - - assertEquals("r12:4", initialRetStorage.toString()); - assertEquals("r12:4", initialP1Storage.toString()); - assertEquals("r11:4 (ptr)", initialP2Storage.toString()); - - f.setCustomVariableStorage(true); - - assertEquals(initialParamCnt, f.getParameterCount()); - - ret.setDataType(IntegerDataType.dataType, createRegStorage("r5"), false, - SourceType.USER_DEFINED); - assertSame(ret, f.getReturn()); - assertParameter(true, createReturn(IntegerDataType.dataType, createRegStorage("r5")), - ret); - - p1.setDataType(IntegerDataType.dataType, createRegStorage("r7"), false, - SourceType.USER_DEFINED); - assertSame(p1, f.getParameter(0)); - assertParameter(true, - createParameter("p1", IntegerDataType.dataType, createRegStorage("r7")), p1); - - assertSame(p2, f.getParameter(1)); - assertParameter(false, - createParameter("p2", barPtr, VariableStorage.UNASSIGNED_STORAGE), p2); - assertFalse(p2.isForcedIndirect()); - - f.setCustomVariableStorage(false); - - assertSame(ret, f.getReturn()); - assertParameter(true, createReturn(IntegerDataType.dataType, initialRetStorage), ret); - - assertSame(p1, f.getParameter(0)); - assertParameter(true, createParameter("p1", IntegerDataType.dataType, initialP1Storage), - p1); - - assertSame(p2, f.getParameter(1)); - /** - * NOTE: Could not use createParmater. initialP2Storage is still forcedIndirect, but its - * new storage is not. Just check the type directly. - */ - assertTrue(barPtr.isEquivalent(p2.getDataType())); - assertFalse(p2.isForcedIndirect()); - } - } - - @Test - public void testSetCallingConvention() throws DuplicateNameException, InvalidInputException, - IllegalArgumentException, OverlappingFunctionException { - try (Transaction tx = b.startTransaction()) { - TraceFunctionSymbol f = createTestFunction(); - - int initialParamCnt = f.getParameterCount(); - - Structure bar = new StructureDataType("bar", 20); - Pointer barPtr = b.trace.getDataTypeManager().getPointer(bar); - - Parameter returnVar = f.getReturn(); - Parameter p1 = f.getParameter(0); - Parameter p2 = f.getParameter(1); - p2.setDataType(bar, SourceType.USER_DEFINED); - - VariableStorage initialReturnStorage = f.getReturn().getVariableStorage(); - VariableStorage initialP1Storage = f.getParameter(0).getVariableStorage(); - - assertEquals("p1", p1.getName()); - assertEquals("p2", p2.getName()); - - assertEquals(0, p1.getOrdinal()); - assertEquals(1, p2.getOrdinal()); - - assertEquals("r12:4", initialReturnStorage.toString()); - assertEquals("r12:4", initialP1Storage.toString()); - assertEquals("r11:4 (ptr)", p2.getVariableStorage().toString()); - - assertTrue(p1.getDataType().isEquivalent(Undefined4DataType.dataType)); - assertTrue(p2.getDataType().isEquivalent(barPtr)); - - // switch to __stackcall - - f.setCallingConvention("__stackcall"); - assertEquals("__stackcall", f.getCallingConventionName()); - assertEquals(initialParamCnt, f.getParameterCount()); - - assertEquals("p1", p1.getName()); - assertEquals("p2", p2.getName()); - - assertEquals(0, p1.getOrdinal()); - assertEquals(1, p2.getOrdinal()); - - // TODO: need better test of return storage - no change in spec storage - assertEquals(createRegStorage("r12"), returnVar.getVariableStorage()); - assertEquals(createStackStorage(4, 4), p1.getVariableStorage()); - assertEquals(createStackStorage(8, 20), p2.getVariableStorage()); - - assertTrue(p1.getDataType().isEquivalent(Undefined4DataType.dataType)); - assertTrue(p2.getDataType().isEquivalent(bar)); - - f.setCallingConvention("__stdcall"); - assertEquals("__stdcall", f.getCallingConventionName()); - assertEquals(initialParamCnt, f.getParameterCount()); - - assertEquals("p1", f.getParameter(0).getName()); - assertEquals("p2", f.getParameter(1).getName()); - - assertEquals(0, p1.getOrdinal()); - assertEquals(1, p2.getOrdinal()); - - assertEquals(initialReturnStorage, returnVar.getVariableStorage());// TODO: need better test - no change - assertEquals(initialP1Storage, p1.getVariableStorage()); - assertEquals("r11:4 (ptr)", p2.getVariableStorage().toString()); - - assertTrue(p1.getDataType().isEquivalent(Undefined4DataType.dataType)); - assertTrue(p2.getDataType().isEquivalent(barPtr)); - - // switch to __thiscall - - f.setCallingConvention("__thiscall"); - assertEquals("__thiscall", f.getCallingConventionName()); - assertEquals(initialParamCnt + 1, f.getParameterCount()); - - Parameter thisParam = f.getParameter(0); - assertEquals(1, p1.getOrdinal()); - assertEquals(2, p2.getOrdinal()); - - p1 = f.getParameter(1); - p2 = f.getParameter(2); - - assertEquals("this", thisParam.getName()); - assertEquals("p1", p1.getName()); - assertEquals("p2", p2.getName()); - - assertEquals(initialReturnStorage, returnVar.getVariableStorage());// TODO: need better test - no change - assertEquals("r12:4 (auto)", thisParam.getVariableStorage().toString()); - assertEquals("r11:4", p1.getVariableStorage().toString()); - assertEquals("r10:4 (ptr)", p2.getVariableStorage().toString()); - - // the "this" param data type will be an empty unresolved Class structure - // if it did not already exist - String namespaceName = f.getSymbol().getParentNamespace().getName(); - DataType namespaceStruct = new StructureDataType(namespaceName, 0); - Pointer structPtr = b.trace.getDataTypeManager().getPointer(namespaceStruct); - - assertTrue(thisParam.getDataType().isEquivalent(structPtr)); - assertTrue(p1.getDataType().isEquivalent(Undefined4DataType.dataType)); - assertTrue(p2.getDataType().isEquivalent(barPtr)); - } - } - - @Test - public void testUpdateFunctionCustomStorage() throws DuplicateNameException, - InvalidInputException, IllegalArgumentException, OverlappingFunctionException { - try (Transaction tx = b.startTransaction()) { - Function f = createTestFunction(); - - Structure bigStruct = new StructureDataType("bigStruct", 20); - - Parameter returnVar = - createReturn(new PointerDataType(bigStruct), createRegStorage("r6")); - - Parameter p1 = createParameter(Function.RETURN_PTR_PARAM_NAME, - new PointerDataType(bigStruct), createRegStorage("r7")); - Parameter p2 = - createParameter("m2", LongLongDataType.dataType, createRegStorage("r12", "r11")); - Parameter p3 = createParameter("m3", ByteDataType.dataType, createRegStorage("r9", 1)); - - f.updateFunction("__stdcall", returnVar, FunctionUpdateType.CUSTOM_STORAGE, true, - SourceType.USER_DEFINED, p1, p2, p3); - - assertTrue(f.hasCustomVariableStorage()); - assertEquals("__stdcall", f.getCallingConventionName()); - - Parameter return1 = f.getReturn(); - assertParameter(true, returnVar, return1); - assertEquals("r6:4", return1.getVariableStorage().toString()); - - Parameter[] params = f.getParameters(); - assertEquals(3, params.length); - - assertParameter(true, p1, params[0]); - assertParameter(true, p2, params[1]); - assertParameter(true, p3, params[2]); - } - - } - - @Test - public void testUpdateFunctionDynamicStorage() throws DuplicateNameException, - InvalidInputException, IllegalArgumentException, OverlappingFunctionException { - try (Transaction tx = b.startTransaction()) { - - Function f = createTestFunction(); - - Structure bigStruct = new StructureDataType("bigStruct", 20); - - Parameter returnVar = createReturn(bigStruct, VariableStorage.UNASSIGNED_STORAGE); - - Parameter p1 = createParameter(Function.RETURN_PTR_PARAM_NAME, - new PointerDataType(bigStruct), createRegStorage("r7")); - Structure classStruct = VariableUtilities.findOrCreateClassStruct(f); - Parameter p2 = createParameter(Function.THIS_PARAM_NAME, - new PointerDataType(classStruct), createRegStorage("r8")); - Parameter p3 = - createParameter("m2", LongLongDataType.dataType, createRegStorage("r12", "r11")); - Parameter p4 = createParameter("m3", ByteDataType.dataType, createRegStorage("r9")); - - // function updated with formal signature - f.updateFunction("__thiscall", returnVar, FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS, - true, SourceType.USER_DEFINED, p3, p4); - - assertTrue(!f.hasCustomVariableStorage()); - assertEquals("__thiscall", f.getCallingConventionName()); - - Parameter return1 = f.getReturn(); - assertTrue(return1.isForcedIndirect()); - assertTrue(bigStruct.isEquivalent(return1.getFormalDataType())); - assertTrue(returnVar.getDataType().isEquivalent(returnVar.getDataType())); - assertEquals("r12:4 (ptr)", return1.getVariableStorage().toString()); - - Parameter[] params = f.getParameters(); - assertEquals(4, params.length); - - assertParameter(false, p1, params[0]); - assertEquals(0, params[0].getOrdinal()); - assertEquals("r12:4 (auto)", params[0].getVariableStorage().toString()); - assertParameter(false, p2, params[1]); - assertEquals(1, params[1].getOrdinal()); - assertEquals("r11:4 (auto)", params[1].getVariableStorage().toString()); - assertParameter(false, p3, params[2]); - assertEquals(2, params[2].getOrdinal()); - assertEquals("Stack[0x0]:8", params[2].getVariableStorage().toString()); - assertParameter(false, p4, params[3]); - assertEquals(3, params[3].getOrdinal()); - assertEquals("r10l:1", params[3].getVariableStorage().toString()); - } - } - - @Test - public void testUpdateFunctionDynamicStorage1() throws DuplicateNameException, - InvalidInputException, IllegalArgumentException, OverlappingFunctionException { - try (Transaction tx = b.startTransaction()) { - - Function f = createTestFunction(); - - Structure bigStruct = new StructureDataType("bigStruct", 20); - - Parameter returnVar = - createReturn(new PointerDataType(bigStruct), VariableStorage.UNASSIGNED_STORAGE); - - Parameter p1 = createParameter(Function.RETURN_PTR_PARAM_NAME, - new PointerDataType(bigStruct), createRegStorage("r7")); - Structure classStruct = VariableUtilities.findOrCreateClassStruct(f); - Parameter p2 = createParameter(Function.THIS_PARAM_NAME, - new PointerDataType(classStruct), createRegStorage("r8")); - Parameter p3 = - createParameter("m2", LongLongDataType.dataType, createRegStorage("r12", "r11")); - Parameter p4 = createParameter("m3", ByteDataType.dataType, createRegStorage("r9")); - - // function updated with auto parameters - f.updateFunction("__thiscall", returnVar, FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS, - true, SourceType.USER_DEFINED, p1, p2, p3, p4); - - assertFalse(f.hasCustomVariableStorage()); - assertEquals("__thiscall", f.getCallingConventionName()); - - Parameter return1 = f.getReturn(); - assertTrue(return1.isForcedIndirect()); - assertTrue(bigStruct.isEquivalent(return1.getFormalDataType())); - assertTrue(returnVar.getDataType().isEquivalent(returnVar.getDataType())); - assertEquals("r12:4 (ptr)", return1.getVariableStorage().toString()); - - Parameter[] params = f.getParameters(); - assertEquals(4, params.length); - - assertParameter(false, p1, params[0]); - assertEquals(0, params[0].getOrdinal()); - assertEquals("r12:4 (auto)", params[0].getVariableStorage().toString()); - assertParameter(false, p2, params[1]); - assertEquals(1, params[1].getOrdinal()); - assertEquals("r11:4 (auto)", params[1].getVariableStorage().toString()); - assertParameter(false, p3, params[2]); - assertEquals(2, params[2].getOrdinal()); - assertEquals("Stack[0x0]:8", params[2].getVariableStorage().toString()); - assertParameter(false, p4, params[3]); - assertEquals(3, params[3].getOrdinal()); - assertEquals("r10l:1", params[3].getVariableStorage().toString()); - } - } - - @Test - public void testUpdateFunctionDynamicStorage2() throws DuplicateNameException, - InvalidInputException, IllegalArgumentException, OverlappingFunctionException { - try (Transaction tx = b.startTransaction()) { - - Function f = createTestFunction(); - - Structure bigStruct = new StructureDataType("bigStruct", 20); - - Parameter returnVar = - createReturn(new PointerDataType(bigStruct), VariableStorage.UNASSIGNED_STORAGE); - - Parameter p1 = createParameter(Function.RETURN_PTR_PARAM_NAME, - new PointerDataType(bigStruct), createRegStorage("r7")); - Parameter p2 = - createParameter("m2", LongLongDataType.dataType, createRegStorage("r12", "r11")); - Parameter p3 = createParameter("m3", ByteDataType.dataType, createRegStorage("r9")); - - f.updateFunction("__thiscall", returnVar, FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS, - true, SourceType.USER_DEFINED, p1, p2, p3); - - assertTrue(!f.hasCustomVariableStorage()); - assertEquals("__thiscall", f.getCallingConventionName()); - - Parameter return1 = f.getReturn(); - assertTrue(bigStruct.isEquivalent(return1.getFormalDataType())); - assertTrue(returnVar.getDataType().isEquivalent(returnVar.getDataType())); - assertEquals("r12:4 (ptr)", return1.getVariableStorage().toString()); - - Parameter[] params = f.getParameters(); - assertEquals(4, params.length); - - Structure classStruct = VariableUtilities.findOrCreateClassStruct(f); - - Parameter thisParam = createParameter(Function.THIS_PARAM_NAME, - new PointerDataType(classStruct), VariableStorage.UNASSIGNED_STORAGE); - - assertParameter(false, p1, params[0]); - assertEquals("r12:4 (auto)", params[0].getVariableStorage().toString()); - assertParameter(false, thisParam, params[1]); - assertEquals("r11:4 (auto)", params[1].getVariableStorage().toString()); - assertParameter(false, p2, params[2]); - assertEquals("Stack[0x0]:8", params[2].getVariableStorage().toString()); - assertParameter(false, p3, params[3]); - assertEquals("r10l:1", params[3].getVariableStorage().toString()); - - // try again with DB params - - f.updateFunction("__thiscall", f.getReturn(), - FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS, true, SourceType.USER_DEFINED, - f.getParameters()); - - assertTrue(!f.hasCustomVariableStorage()); - assertEquals("__thiscall", f.getCallingConventionName()); - - return1 = f.getReturn(); - assertTrue(bigStruct.isEquivalent(return1.getFormalDataType())); - assertTrue(returnVar.getDataType().isEquivalent(returnVar.getDataType())); - assertEquals("r12:4 (ptr)", return1.getVariableStorage().toString()); - - params = f.getParameters(); - assertEquals(4, params.length); - - assertParameter(false, p1, params[0]); - assertEquals(0, params[0].getOrdinal()); - assertEquals("r12:4 (auto)", params[0].getVariableStorage().toString()); - assertParameter(false, thisParam, params[1]); - assertEquals(1, params[1].getOrdinal()); - assertEquals("r11:4 (auto)", params[1].getVariableStorage().toString()); - assertParameter(false, p2, params[2]); - assertEquals(2, params[2].getOrdinal()); - assertEquals("Stack[0x0]:8", params[2].getVariableStorage().toString()); - assertParameter(false, p3, params[3]); - assertEquals(3, params[3].getOrdinal()); - assertEquals("r10l:1", params[3].getVariableStorage().toString()); - - // try again with DB params and custom storage - - f.updateFunction("__thiscall", f.getReturn(), FunctionUpdateType.CUSTOM_STORAGE, true, - SourceType.USER_DEFINED, f.getParameters()); - - assertTrue(f.hasCustomVariableStorage()); - assertEquals("__thiscall", f.getCallingConventionName()); - - return1 = f.getReturn(); - assertParameter(false, returnVar, return1); - assertEquals("r12:4", return1.getVariableStorage().toString()); - - params = f.getParameters(); - assertEquals(4, params.length); - - assertParameter(false, p1, params[0]); - assertEquals(0, params[0].getOrdinal()); - assertEquals("r12:4", params[0].getVariableStorage().toString()); - assertParameter(false, thisParam, params[1]); - assertEquals(1, params[1].getOrdinal()); - assertEquals("r11:4", params[1].getVariableStorage().toString()); - assertParameter(false, p2, params[2]); - assertEquals(2, params[2].getOrdinal()); - assertEquals("Stack[0x0]:8", params[2].getVariableStorage().toString()); - assertParameter(false, p3, params[3]); - assertEquals(3, params[3].getOrdinal()); - assertEquals("r10l:1", params[3].getVariableStorage().toString()); - } - } - - @Test - public void testAutoAddingRemovingThisParameter() throws DuplicateNameException, - InvalidInputException, IllegalArgumentException, OverlappingFunctionException { - try (Transaction tx = b.startTransaction()) { - - TraceFunctionSymbol f = createTestFunction(); - assertEquals(5, f.getParameters().length); - - assertNull(parameters.getChildNamed("this", f)); - - f.setCallingConvention("__thiscall"); - assertEquals(6, f.getParameters().length); - assertEquals("this", f.getParameter(0).getName()); - assertTrue(Undefined4DataType.dataType.isEquivalent(f.getParameter(1).getDataType())); - - assertNull(parameters.getChildNamed("this", f)); - - f.setCallingConvention("__stdcall"); - assertEquals(5, f.getParameters().length); - assertTrue(Undefined4DataType.dataType.isEquivalent(f.getParameter(0).getDataType())); - - assertNull(parameters.getChildNamed("this", f)); - - f.setCallingConvention("__thiscall"); - assertEquals(6, f.getParameters().length); - Parameter param = f.getParameter(0); - assertTrue(param.isAutoParameter()); - assertEquals(Function.THIS_PARAM_NAME, param.getName()); - assertTrue(Undefined4DataType.dataType.isEquivalent(f.getParameter(1).getDataType())); - - assertNull(parameters.getChildNamed("this", f)); - - f.setCustomVariableStorage(true); - - assertNotNull(parameters.getChildNamed("this", f)); - - assertEquals(6, f.getParameters().length); - param = f.getParameter(0); - assertFalse(param.isAutoParameter()); - assertEquals(Function.THIS_PARAM_NAME, param.getName()); - assertTrue(Undefined4DataType.dataType.isEquivalent(f.getParameter(1).getDataType())); - - f.setCustomVariableStorage(false); - - assertNull(parameters.getChildNamed("this", f)); - - assertEquals(6, f.getParameters().length); - param = f.getParameter(0); - assertTrue(param.isAutoParameter()); - assertEquals(Function.THIS_PARAM_NAME, param.getName()); - assertTrue(Undefined4DataType.dataType.isEquivalent(f.getParameter(1).getDataType())); - - f.setCustomVariableStorage(true); - - assertNotNull(parameters.getChildNamed("this", f)); - - assertEquals(6, f.getParameters().length); - param = f.getParameter(0); - assertFalse(param.isAutoParameter()); - assertEquals(Function.THIS_PARAM_NAME, param.getName()); - assertTrue(Undefined4DataType.dataType.isEquivalent(f.getParameter(1).getDataType())); - - f.setCallingConvention("__stdcall"); - assertEquals(6, f.getParameters().length); - param = f.getParameter(0); - assertFalse(param.isAutoParameter()); - assertEquals(Function.THIS_PARAM_NAME, param.getName()); - assertTrue(Undefined4DataType.dataType.isEquivalent(f.getParameter(1).getDataType())); - - f.setCustomVariableStorage(false); - - assertNotNull(parameters.getChildNamed("this", f)); - - assertEquals(6, f.getParameters().length); - param = f.getParameter(0); - assertFalse(param.isAutoParameter()); - assertEquals(Function.THIS_PARAM_NAME, param.getName()); - assertTrue(Undefined4DataType.dataType.isEquivalent(f.getParameter(1).getDataType())); - - f.setCallingConvention("__thiscall"); - - assertNull(parameters.getChildNamed("this", f)); - - assertEquals(6, f.getParameters().length); - param = f.getParameter(0); - assertTrue(param.isAutoParameter()); - assertEquals(Function.THIS_PARAM_NAME, param.getName()); - assertTrue(Undefined4DataType.dataType.isEquivalent(f.getParameter(1).getDataType())); - - f.setCallingConvention("__stdcall"); - assertEquals(5, f.getParameters().length); - assertTrue(Undefined4DataType.dataType.isEquivalent(f.getParameter(0).getDataType())); - } - } - - /* - * Test for String getSignature(String) - */ - @Test - public void testGetSignatureString() - throws InvalidInputException, OverlappingFunctionException, DuplicateNameException { - try (Transaction tx = b.startTransaction()) { - TraceFunctionSymbol f = functions.create(0, b.addr(100), b.set(b.range(100, 200)), - "foo", null, null, SourceType.USER_DEFINED); - Structure s = new StructureDataType("bar", 20); - f.setReturnType(s, SourceType.ANALYSIS); - Parameter p = f.addParameter(createParameter("p1", s), SourceType.IMPORTED); - - assertEquals("bar foo(bar p1)", f.getPrototypeString(true, false)); - assertEquals("bar foo(bar p1)", f.getPrototypeString(true, true)); - assertEquals("bar * foo(bar * __return_storage_ptr__, bar * p1)", - f.getPrototypeString(false, false)); - assertEquals("bar * foo(bar * __return_storage_ptr__, bar * p1)", - f.getPrototypeString(false, true)); - - f.setCallingConvention("__thiscall"); - - assertEquals("bar foo(bar p1)", f.getPrototypeString(true, false)); - assertEquals("bar __thiscall foo(bar p1)", f.getPrototypeString(true, true)); - assertEquals("bar * foo(bar * __return_storage_ptr__, void * this, bar * p1)", - f.getPrototypeString(false, false)); - assertEquals( - "bar * __thiscall foo(bar * __return_storage_ptr__, void * this, bar * p1)", - f.getPrototypeString(false, true)); - - f.removeVariable(p); - - assertEquals("bar foo(void)", f.getPrototypeString(true, false)); - assertEquals("bar __thiscall foo(void)", f.getPrototypeString(true, true)); - assertEquals("bar * foo(bar * __return_storage_ptr__, void * this)", - f.getPrototypeString(false, false)); - assertEquals("bar * __thiscall foo(bar * __return_storage_ptr__, void * this)", - f.getPrototypeString(false, true)); - - p = f.addParameter(createParameter("p1", s), SourceType.ANALYSIS); - - assertEquals("bar foo(bar p1)", f.getPrototypeString(true, false)); - assertEquals("bar __thiscall foo(bar p1)", f.getPrototypeString(true, true)); - assertEquals("bar * foo(bar * __return_storage_ptr__, void * this, bar * p1)", - f.getPrototypeString(false, false)); - assertEquals( - "bar * __thiscall foo(bar * __return_storage_ptr__, void * this, bar * p1)", - f.getPrototypeString(false, true)); - - f.setCustomVariableStorage(true); - - assertEquals("bar * foo(bar * __return_storage_ptr__, void * this, bar * p1)", - f.getPrototypeString(true, false)); - assertEquals( - "bar * __thiscall foo(bar * __return_storage_ptr__, void * this, bar * p1)", - f.getPrototypeString(true, true)); - assertEquals("bar * foo(bar * __return_storage_ptr__, void * this, bar * p1)", - f.getPrototypeString(false, false)); - assertEquals( - "bar * __thiscall foo(bar * __return_storage_ptr__, void * this, bar * p1)", - f.getPrototypeString(false, true)); - - f.setCustomVariableStorage(false); - - // forced-indirect round trip not supported for parameter - assertEquals("bar foo(bar * p1)", f.getPrototypeString(true, false)); - assertEquals("bar __thiscall foo(bar * p1)", f.getPrototypeString(true, true)); - assertEquals("bar * foo(bar * __return_storage_ptr__, void * this, bar * p1)", - f.getPrototypeString(false, false)); - assertEquals( - "bar * __thiscall foo(bar * __return_storage_ptr__, void * this, bar * p1)", - f.getPrototypeString(false, true)); - - p.setDataType(s, SourceType.ANALYSIS); - f.setCallingConvention("__stackcall"); - - assertEquals("bar foo(bar p1)", f.getPrototypeString(true, false)); - assertEquals("bar __stackcall foo(bar p1)", f.getPrototypeString(true, true)); - assertEquals("bar * foo(bar * __return_storage_ptr__, bar p1)", - f.getPrototypeString(false, false)); - assertEquals("bar * __stackcall foo(bar * __return_storage_ptr__, bar p1)", - f.getPrototypeString(false, true)); - } - } - - @Test - @Ignore("TODO") - public void testDataTypeOnRegisterVariable() - throws InvalidInputException, OverlappingFunctionException { - try (Transaction tx = b.startTransaction()) { - - Register r7l = b.trace.getBaseLanguage().getRegister("r7l"); - assertNotNull(r7l); - - TraceFunctionSymbol f = functions.create(0, b.addr(100), b.set(b.range(100, 200)), - "foo", null, null, SourceType.USER_DEFINED); - f.setCustomVariableStorage(true); - - DataType dt; - - // TODO: Monitor events - - try (Transaction localTx = b.startTransaction()) { - DataType bdt = b.trace.getDataTypeManager() - .addDataType(ByteDataType.dataType, - DataTypeConflictHandler.DEFAULT_HANDLER); - dt = new TypedefDataType("byteTD", bdt); - dt = b.trace.getDataTypeManager() - .addDataType(dt, - DataTypeConflictHandler.DEFAULT_HANDLER); - AddRegisterParameterCommand cmd = new AddRegisterParameterCommand(f, r7l, - "reg_param_0", dt, 0, SourceType.USER_DEFINED); - cmd.applyTo(b.trace.getFixedProgramView(0)); - } - - // TODO: Check for expected event - - Parameter[] params = f.getParameters(); - assertEquals(1, params.length); - - Parameter rp = params[0]; - assertEquals(dt, rp.getDataType()); - assertEquals(r7l, rp.getRegister()); - - // delete the typedef data type - try (Transaction localTx = b.startTransaction()) { - b.trace.getDataTypeManager().remove(dt, TaskMonitor.DUMMY); - } - - params = f.getParameters(); - assertEquals(1, params.length); - assertTrue(params[0].isRegisterVariable()); - TODO(); // TODO: SymbolManager must process type deletion - assertEquals(Undefined1DataType.dataType, params[0].getDataType()); - assertEquals(r7l, params[0].getRegister()); - } - } - - @Test - public void testSetStackDepthChange() - throws InvalidInputException, OverlappingFunctionException { - try (Transaction tx = b.startTransaction()) { - TraceFunctionSymbol f = functions.create(0, b.addr(100), b.set(b.range(100, 200)), - "foo", null, null, SourceType.USER_DEFINED); - - // TODO: Monitor events - - f.setStackPurgeSize(20); - assertEquals(20, f.getStackPurgeSize()); - - // TODO: Check for expected event - } - } - - @Test - public void testSetStackParameter() - throws InvalidInputException, OverlappingFunctionException, DuplicateNameException { - try (Transaction tx = b.startTransaction()) { - TraceFunctionSymbol f = functions.create(0, b.addr(100), b.set(b.range(100, 200)), - "foo", null, null, SourceType.USER_DEFINED); - f.setCustomVariableStorage(true); - f.setCallingConvention("__stackcall"); - - DataType[] dt = - new DataType[] { new ByteDataType(), new WordDataType(), new Pointer16DataType() }; - - LocalVariable stackVar = createLocal("TestStack0", dt[0], 4); - stackVar.setComment("My Comment0"); - - // TODO: Monitor events - - // causes both symbol created and function change events - f.addParameter(stackVar, SourceType.USER_DEFINED); - - // TODO: Check for expected event - - stackVar = createLocal("TestStack1", dt[1], 8); - stackVar.setComment("My Comment1"); - - // causes both symbol created and function change events - f.addParameter(stackVar, SourceType.USER_DEFINED); - - // TODO: Check for expected event - - stackVar = createLocal("TestStack2", dt[2], 12); - stackVar.setComment("My Comment2"); - f.addParameter(stackVar, SourceType.USER_DEFINED); - - Parameter[] params = f.getParameters(); - assertEquals(3, params.length); - for (int i = 0; i < 3; i++) { - Parameter param = params[i]; - assertTrue(param.isStackVariable()); - int stackOffset = param.getStackOffset(); - assertEquals("TestStack" + i, param.getName()); - assertEquals(i, param.getOrdinal()); - assertEquals("My Comment" + i, param.getComment()); - assertEquals(f, param.getFunction()); - assertEquals((i * 4) + 4, stackOffset); - assertTrue(dt[i].isEquivalent(param.getDataType())); - } - - f.setCustomVariableStorage(false); - - params = f.getParameters(); - assertEquals(3, params.length); - int[] stackOffsets = new int[] { 7, 10, 14 }; - for (int i = 0; i < 3; i++) { - Parameter param = params[i]; - assertTrue(param.isStackVariable()); - int stackOffset = param.getStackOffset(); - assertEquals("TestStack" + i, param.getName()); - assertEquals(i, param.getOrdinal()); - assertEquals("My Comment" + i, param.getComment()); - assertEquals(f, param.getFunction()); - assertEquals(stackOffsets[i], stackOffset); - assertTrue(dt[i].isEquivalent(param.getDataType())); - } - } - } - - @Test - public void testSetDuplicateStackParameter() - throws InvalidInputException, OverlappingFunctionException, DuplicateNameException { - try (Transaction tx = b.startTransaction()) { - TraceFunctionSymbol f = functions.create(0, b.addr(100), b.set(b.range(100, 200)), - "foo", null, null, SourceType.USER_DEFINED); - f.setCustomVariableStorage(true); - - DataType[] dt = - new DataType[] { new ByteDataType(), new WordDataType(), new Pointer16DataType() }; - - LocalVariable stackVar = createLocal("TestStack0", dt[0], 4); - stackVar.setComment("My Comment0"); - f.addParameter(stackVar, SourceType.USER_DEFINED); - stackVar = createLocal("TestStack1", dt[1], 8); - stackVar.setComment("My Comment1"); - f.addParameter(stackVar, SourceType.USER_DEFINED); - stackVar = createLocal("TestStack2", dt[2], 4);// duplicate stack offset - stackVar.setComment("My Comment2"); - f.addParameter(stackVar, SourceType.USER_DEFINED); - - Parameter[] params = f.getParameters(); - assertEquals(2, params.length); - assertTrue(params[0].isStackVariable()); - assertTrue(params[1].isStackVariable()); - assertEquals(8, params[0].getStackOffset()); - assertEquals(4, params[1].getStackOffset()); - for (int i = 0; i < 2; i++) { - int n = i + 1; - Parameter param = params[i]; - assertEquals("TestStack" + n, param.getName()); - assertEquals(i, param.getOrdinal()); - assertEquals("My Comment" + n, param.getComment()); - assertEquals(f, param.getFunction()); - assertTrue(dt[n].isEquivalent(param.getDataType())); - } - } - } - - @Test - public void testSetStackVariable() - throws InvalidInputException, OverlappingFunctionException, DuplicateNameException { - try (Transaction tx = b.startTransaction()) { - TraceFunctionSymbol f = functions.create(0, b.addr(100), b.set(b.range(100, 200)), - "foo", null, null, SourceType.USER_DEFINED); - - DataType[] dt = - new DataType[] { new ByteDataType(), new WordDataType(), new Pointer16DataType() }; - - LocalVariable stackVar = createLocal("TestStack0", dt[0], -4); - stackVar.setComment("My Comment0"); - f.addLocalVariable(stackVar, SourceType.USER_DEFINED); - stackVar = createLocal("TestStack1", dt[1], -8); - stackVar.setComment("My Comment1"); - f.addLocalVariable(stackVar, SourceType.USER_DEFINED); - stackVar = createLocal("TestStack2", dt[2], -12); - stackVar.setComment("My Comment2"); - f.addLocalVariable(stackVar, SourceType.USER_DEFINED); - - Variable[] vars = f.getLocalVariables(); - assertEquals(3, vars.length); - for (int i = 0; i < 3; i++) { - Variable var = vars[i]; - assertTrue(var.isStackVariable()); - assertEquals("TestStack" + i, var.getName()); - assertEquals(0, var.getFirstUseOffset()); - assertEquals("My Comment" + i, var.getComment()); - assertEquals(f, var.getFunction()); - assertEquals(-(i * 4) - 4, var.getStackOffset()); - assertTrue(dt[i].isEquivalent(var.getDataType())); - } - } - } - - @Test - public void testSetStackVariableOverwrite() - throws InvalidInputException, OverlappingFunctionException, DuplicateNameException { - try (Transaction tx = b.startTransaction()) { - TraceFunctionSymbol f = functions.create(0, b.addr(100), b.set(b.range(100, 200)), - "foo", null, null, SourceType.USER_DEFINED); - - Structure dt = - b.trace.getDataTypeManager().addType(new StructureDataType("Struct1", 0), null); - - LocalVariable stackVar = createLocal("TestStack0", dt, -8); - stackVar.setComment("My Comment0"); - f.addLocalVariable(stackVar, SourceType.USER_DEFINED); - - // TODO: Argue for overrides on clone to more specific type - dt = dt.clone(b.trace.getDataTypeManager()); - dt.add(WordDataType.dataType); - - stackVar = createLocal("TestStack2", dt, -8); - stackVar.setComment("My Comment2"); - f.addLocalVariable(stackVar, SourceType.USER_DEFINED); - - Variable[] vars = f.getLocalVariables(); - assertEquals(1, vars.length); - - Variable var = vars[0]; - assertTrue(var.isStackVariable()); - assertEquals("TestStack2", var.getName()); - assertEquals(0, var.getFirstUseOffset()); - assertEquals("My Comment2", var.getComment()); - assertEquals(f, var.getFunction()); - assertEquals(-8, var.getStackOffset()); - assertTrue(dt.isEquivalent(var.getDataType())); - } - } - - @Test - public void testSetDuplicateStackVariable() - throws InvalidInputException, OverlappingFunctionException, DuplicateNameException { - try (Transaction tx = b.startTransaction()) { - TraceFunctionSymbol f = functions.create(0, b.addr(100), b.set(b.range(100, 200)), - "foo", null, null, SourceType.USER_DEFINED); - - DataType[] dt = - new DataType[] { new ByteDataType(), new WordDataType(), new Pointer16DataType() }; - - LocalVariable stackVar = createLocal("TestStack0", dt[0], -4); - stackVar.setComment("My Comment0"); - f.addLocalVariable(stackVar, SourceType.USER_DEFINED); - stackVar = createLocal("TestStack1", dt[1], -8); - stackVar.setComment("My Comment1"); - f.addLocalVariable(stackVar, SourceType.USER_DEFINED); - stackVar = createLocal("TestStack2", dt[2], -4);// duplicate stack offset - stackVar.setComment("My Comment2"); - f.addLocalVariable(stackVar, SourceType.USER_DEFINED); - - Variable[] vars = f.getLocalVariables(); - assertEquals(2, vars.length); - assertTrue(vars[0].isStackVariable()); - assertTrue(vars[1].isStackVariable()); - assertEquals(-4, vars[0].getStackOffset()); - assertEquals(-8, vars[1].getStackOffset()); - for (int i = 0; i < 2; i++) { - int n = 2 - i; - Variable var = vars[i]; - assertEquals("TestStack" + n, var.getName()); - assertEquals(0, var.getFirstUseOffset()); - assertEquals("My Comment" + n, var.getComment()); - assertEquals(f, var.getFunction()); - assertTrue(dt[n].isEquivalent(var.getDataType())); - } - } - } - - @Test - public void testSetRegisterParameter() - throws InvalidInputException, OverlappingFunctionException, DuplicateNameException { - try (Transaction tx = b.startTransaction()) { - TraceFunctionSymbol f = functions.create(0, b.addr(100), b.set(b.range(100, 200)), - "foo", null, null, SourceType.USER_DEFINED); - f.setCustomVariableStorage(true); - - LocalVariable regVar = - createLocal("TestReg0", 0, ByteDataType.dataType, createRegStorage("r1")); - regVar.setComment("My Comment0"); - f.addParameter(regVar, SourceType.USER_DEFINED); - regVar = createLocal("TestReg1", 0, WordDataType.dataType, createRegStorage("r2")); - regVar.setComment("My Comment1"); - f.addParameter(regVar, SourceType.USER_DEFINED); - regVar = createLocal("TestReg2", 0, Pointer16DataType.dataType, createRegStorage("r3")); - regVar.setComment("My Comment2"); - f.addParameter(regVar, SourceType.USER_DEFINED); - - Parameter[] params = f.getParameters(); - assertEquals(3, params.length); - for (int i = 0; i < 3; i++) { - Parameter param = params[i]; - assertTrue(param.isRegisterVariable()); - assertEquals("TestReg" + i, param.getName()); - assertEquals(i, param.getOrdinal()); - assertEquals("My Comment" + i, param.getComment()); - assertEquals(f, param.getFunction()); - assertEquals("r" + (i + 1) + "l", param.getRegister().getName()); - } - assertTrue(ByteDataType.dataType.isEquivalent(params[0].getDataType())); - assertTrue(WordDataType.dataType.isEquivalent(params[1].getDataType())); - assertTrue(Pointer16DataType.dataType.isEquivalent(params[2].getDataType())); - } - } - - @Test - public void testSetDuplicateRegisterParameter() - throws InvalidInputException, OverlappingFunctionException, DuplicateNameException { - try (Transaction tx = b.startTransaction()) { - TraceFunctionSymbol f = functions.create(0, b.addr(100), b.set(b.range(100, 200)), - "foo", null, null, SourceType.USER_DEFINED); - f.setCustomVariableStorage(true); - - LocalVariable regVar = - createLocal("TestReg0", 0, ByteDataType.dataType, createRegStorage("r1")); - regVar.setComment("My Comment0"); - f.addParameter(regVar, SourceType.USER_DEFINED); - regVar = createLocal("TestReg1", 0, WordDataType.dataType, createRegStorage("r2")); - regVar.setComment("My Comment1"); - f.addParameter(regVar, SourceType.USER_DEFINED); - // NOTE: This next is r1 instead of r3 - regVar = createLocal("TestReg2", 0, Pointer16DataType.dataType, createRegStorage("r1")); - regVar.setComment("My Comment2"); - f.addParameter(regVar, SourceType.USER_DEFINED); - - Parameter[] params = f.getParameters(); - assertEquals(2, params.length); - for (int i = 0; i < 2; i++) { - Parameter param = params[i]; - assertTrue(param.isRegisterVariable()); - assertEquals("TestReg" + (i + 1), param.getName()); - assertEquals(i, param.getOrdinal()); - assertEquals("My Comment" + (i + 1), param.getComment()); - assertEquals(f, param.getFunction()); - assertEquals("r" + (2 - i) + "l", param.getRegister().getName()); - } - assertTrue(WordDataType.dataType.isEquivalent(params[0].getDataType())); - assertTrue(Pointer16DataType.dataType.isEquivalent(params[1].getDataType())); - } - } - - @Test - public void testSetRegisterVariable() - throws InvalidInputException, OverlappingFunctionException, DuplicateNameException { - try (Transaction tx = b.startTransaction()) { - TraceFunctionSymbol f = functions.create(0, b.addr(100), b.set(b.range(100, 200)), - "foo", null, null, SourceType.USER_DEFINED); - - LocalVariable regVar = - createLocal("TestReg0", 0, ByteDataType.dataType, createRegStorage("r1")); - regVar.setComment("My Comment0"); - f.addLocalVariable(regVar, SourceType.USER_DEFINED); - regVar = createLocal("TestReg1", 4, WordDataType.dataType, createRegStorage("r2")); - regVar.setComment("My Comment1"); - f.addLocalVariable(regVar, SourceType.USER_DEFINED); - regVar = createLocal("TestReg2", 8, Pointer16DataType.dataType, createRegStorage("r3")); - regVar.setComment("My Comment2"); - f.addLocalVariable(regVar, SourceType.USER_DEFINED); - - Variable[] vars = f.getLocalVariables(); - assertEquals(3, vars.length); - Arrays.sort(vars); - for (int i = 0; i < 3; i++) { - Variable var = vars[i]; - assertTrue(var.isRegisterVariable()); - assertEquals("TestReg" + i, var.getName()); - assertEquals(i * 4, var.getFirstUseOffset()); - assertEquals("My Comment" + i, var.getComment()); - assertEquals(f, var.getFunction()); - assertEquals("r" + (i + 1) + "l", var.getRegister().getName()); - } - assertTrue(ByteDataType.dataType.isEquivalent(vars[0].getDataType())); - assertTrue(WordDataType.dataType.isEquivalent(vars[1].getDataType())); - assertTrue(Pointer16DataType.dataType.isEquivalent(vars[2].getDataType())); - } - } - - @Test - public void testSetDuplicateRegisterVariable() - throws InvalidInputException, OverlappingFunctionException, DuplicateNameException { - try (Transaction tx = b.startTransaction()) { - TraceFunctionSymbol f = functions.create(0, b.addr(100), b.set(b.range(100, 200)), - "foo", null, null, SourceType.USER_DEFINED); - - LocalVariable regVar = - createLocal("TestReg0", 4, ByteDataType.dataType, createRegStorage("r1")); - regVar.setComment("My Comment0"); - f.addLocalVariable(regVar, SourceType.USER_DEFINED); - // NOTE: This next one is r1 instead of r2 - regVar = createLocal("TestReg1", 4, WordDataType.dataType, createRegStorage("r1")); - regVar.setComment("My Comment1"); - f.addLocalVariable(regVar, SourceType.USER_DEFINED); - regVar = createLocal("TestReg2", 8, Pointer16DataType.dataType, createRegStorage("r3")); - regVar.setComment("My Comment2"); - f.addLocalVariable(regVar, SourceType.USER_DEFINED); - - Variable[] vars = f.getLocalVariables(); - assertEquals(2, vars.length); - for (int i = 0; i < 2; i++) { - Variable var = vars[i]; - assertTrue(var.isRegisterVariable()); - assertEquals("TestReg" + (i + 1), var.getName()); - assertEquals((i + 1) * 4, var.getFirstUseOffset()); - assertEquals("My Comment" + (i + 1), var.getComment()); - assertEquals(f, var.getFunction()); - assertEquals("r" + (i * 2 + 1) + "l", var.getRegister().getName()); - } - assertTrue(WordDataType.dataType.isEquivalent(vars[0].getDataType())); - assertTrue(Pointer16DataType.dataType.isEquivalent(vars[1].getDataType())); - } - } - - @Test - public void testSetMemoryParameter() - throws InvalidInputException, OverlappingFunctionException, DuplicateNameException { - try (Transaction tx = b.startTransaction()) { - TraceFunctionSymbol f = functions.create(0, b.addr(100), b.set(b.range(100, 200)), - "foo", null, null, SourceType.USER_DEFINED); - f.setCustomVariableStorage(true); - - LocalVariable memVar = createLocal("TestMem0", 0, ByteDataType.dataType, b.addr(0)); - memVar.setComment("My Comment0"); - f.addParameter(memVar, SourceType.USER_DEFINED); - memVar = createLocal("TestMem1", 0, WordDataType.dataType, b.addr(4)); - memVar.setComment("My Comment1"); - f.addParameter(memVar, SourceType.USER_DEFINED); - memVar = createLocal("TestMem2", 0, Pointer16DataType.dataType, b.addr(8)); - memVar.setComment("My Comment2"); - f.addParameter(memVar, SourceType.USER_DEFINED); - - Parameter[] params = f.getParameters(); - assertEquals(3, params.length); - for (int i = 0; i < 3; i++) { - Parameter param = params[i]; - assertTrue(param.isMemoryVariable()); - assertEquals("TestMem" + i, param.getName()); - assertEquals(i, param.getOrdinal()); - assertEquals("My Comment" + i, param.getComment()); - assertEquals(f, param.getFunction()); - assertEquals(b.addr(i * 4), param.getMinAddress()); - } - assertTrue(ByteDataType.dataType.isEquivalent(params[0].getDataType())); - assertTrue(WordDataType.dataType.isEquivalent(params[1].getDataType())); - assertTrue(Pointer16DataType.dataType.isEquivalent(params[2].getDataType())); - } - } - - @Test - public void testSetDuplicateMemoryParameter() - throws InvalidInputException, OverlappingFunctionException, DuplicateNameException { - try (Transaction tx = b.startTransaction()) { - TraceFunctionSymbol f = functions.create(0, b.addr(100), b.set(b.range(100, 200)), - "foo", null, null, SourceType.USER_DEFINED); - f.setCustomVariableStorage(true); - - LocalVariable memVar = createLocal("TestMem0", 0, ByteDataType.dataType, b.addr(0)); - memVar.setComment("My Comment0"); - f.addParameter(memVar, SourceType.USER_DEFINED); - memVar = createLocal("TestMem1", 0, WordDataType.dataType, b.addr(4)); - memVar.setComment("My Comment1"); - f.addParameter(memVar, SourceType.USER_DEFINED); - memVar = createLocal("TestMem2", 0, Pointer16DataType.dataType, b.addr(0)); - memVar.setComment("My Comment2"); - f.addParameter(memVar, SourceType.USER_DEFINED); - - Parameter[] params = f.getParameters(); - assertEquals(2, params.length); - assertTrue(params[0].isMemoryVariable()); - assertTrue(params[1].isMemoryVariable()); - assertEquals(b.addr(4), params[0].getMinAddress()); - assertEquals(b.addr(0), params[1].getMinAddress()); - for (int i = 0; i < 2; i++) { - Parameter param = params[i]; - assertEquals("TestMem" + (i + 1), param.getName()); - assertEquals(i, param.getOrdinal()); - assertEquals("My Comment" + (i + 1), param.getComment()); - assertEquals(f, param.getFunction()); - } - assertTrue(WordDataType.dataType.isEquivalent(params[0].getDataType())); - assertTrue(Pointer16DataType.dataType.isEquivalent(params[1].getDataType())); - } - } - - @Test - public void testRemoveRegisterParameter() - throws InvalidInputException, OverlappingFunctionException, DuplicateNameException { - try (Transaction tx = b.startTransaction()) { - TraceFunctionSymbol f = functions.create(0, b.addr(100), b.set(b.range(100, 200)), - "foo", null, null, SourceType.USER_DEFINED); - f.setCustomVariableStorage(true); - - LocalVariable regVar = - createLocal("TestReg0", 0, ByteDataType.dataType, createRegStorage("r1")); - regVar.setComment("My Comment0"); - f.addParameter(regVar, SourceType.USER_DEFINED); - regVar = createLocal("TestReg1", 0, WordDataType.dataType, createRegStorage("r2")); - regVar.setComment("My Comment1"); - f.addParameter(regVar, SourceType.USER_DEFINED); - regVar = createLocal("TestReg2", 0, Pointer16DataType.dataType, createRegStorage("r3")); - regVar.setComment("My Comment2"); - f.addParameter(regVar, SourceType.USER_DEFINED); - - // TODO: Change to update? - f.removeParameter(1); - - Parameter[] params = f.getParameters(); - assertEquals(2, params.length); - for (int i = 0; i < 2; i++) { - Parameter param = params[i]; - assertTrue(param.isRegisterVariable()); - assertEquals("TestReg" + (2 * i), param.getName()); - assertEquals(i, param.getOrdinal()); - assertEquals("My Comment" + (2 * i), param.getComment()); - assertEquals(f, param.getFunction()); - assertEquals("r" + (2 * i + 1) + "l", param.getRegister().getName()); - } - assertTrue(ByteDataType.dataType.isEquivalent(params[0].getDataType())); - assertTrue(Pointer16DataType.dataType.isEquivalent(params[1].getDataType())); - } - } - - @Test - public void testSetInline() throws InvalidInputException, OverlappingFunctionException { - try (Transaction tx = b.startTransaction()) { - - TraceFunctionSymbol f = functions.create(0, b.addr(100), b.set(b.range(100, 200)), - "foo", null, null, SourceType.USER_DEFINED); - assertTrue(!f.isInline()); - - // TODO: Monitor events - - f.setInline(true); - - // TODO: Check for expected event - - assertTrue(f.isInline()); - - f.setInline(false); - - // TODO: Check for expected event - - assertFalse(f.isInline()); - } - } - - @Test - public void testSetNoReturn() throws InvalidInputException, OverlappingFunctionException { - try (Transaction tx = b.startTransaction()) { - - TraceFunctionSymbol f = functions.create(0, b.addr(100), b.set(b.range(100, 200)), - "foo", null, null, SourceType.USER_DEFINED); - assertTrue(!f.hasNoReturn()); - - // TODO: Monitor events - - f.setNoReturn(true); - - // TODO: Check for expected event - - assertTrue(f.hasNoReturn()); - - f.setNoReturn(false); - - // TODO: Check for expected event - - assertFalse(f.hasNoReturn()); - } - } - - @Test - public void testSetCallFixup() throws InvalidInputException, OverlappingFunctionException { - try (Transaction tx = b.startTransaction()) { - - TraceFunctionSymbol f = functions.create(0, b.addr(100), b.set(b.range(100, 200)), - "foo", null, null, SourceType.USER_DEFINED); - assertNull(f.getCallFixup()); - - // TODO: Monitor events - - f.setCallFixup("TEST"); - - // TODO: Check for expected event - - assertEquals("TEST", f.getCallFixup()); - - f.setCallFixup(null); - - // TODO: Check for expected event - - assertNull(f.getCallFixup()); - } - } - - @Test - public void testSetThunkFunction() - throws InvalidInputException, OverlappingFunctionException, DuplicateNameException { - try (Transaction tx = b.startTransaction()) { - - Function f1 = functions.create(0, b.addr(0x100), b.set(b.range(0x100, 0x200)), "foo1", - null, null, SourceType.USER_DEFINED); - assertTrue(!f1.isThunk()); - assertNull(f1.getThunkedFunction(false)); - - Function f2 = functions.create(0, b.addr(0x300), b.set(b.range(0x300, 0x400)), null, - null, null, SourceType.DEFAULT); - assertEquals("FUN_00000300", f2.getName()); - assertTrue(!f2.isThunk()); - assertNull(f2.getThunkedFunction(false)); - - f1.setReturn(ByteDataType.dataType, VariableStorage.UNASSIGNED_STORAGE, - SourceType.USER_DEFINED); - - // TODO: Monitor events - - // TODO: Change to update? - f1.addParameter(createParameter("p1", IntegerDataType.dataType), - SourceType.USER_DEFINED); - - // TODO: Check for expected event - - f1.addParameter(createParameter("p2", IntegerDataType.dataType), - SourceType.USER_DEFINED); - - // TODO: Check for expected event - - assertEquals("byte foo1(int p1, int p2)", f1.getPrototypeString(false, false)); - assertEquals("undefined FUN_00000300()", f2.getPrototypeString(false, false)); - - f2.setThunkedFunction(f1); - - // TODO: Check for expected event - - assertEquals("foo1", f2.getName()); - assertTrue(f2.isThunk()); - assertEquals(f1, f2.getThunkedFunction(false)); - - assertEquals("byte foo1(int p1, int p2)", f1.getPrototypeString(false, false)); - // TODO: Not sure what the correct behavior should be? - assertEquals("byte foo1(int p1, int p2)", f2.getPrototypeString(false, false)); - - // Chum is fum - f1.setName("fum", SourceType.USER_DEFINED); - - // TODO: Check for expected event - // TODO: Should see an event for function and thunk - // TODO: Check event addresses show real addresses (different for thunk) - // TODO: Check that old and new names are given (same for real and thunk) - - f1.addParameter(createParameter("p3", IntegerDataType.dataType), - SourceType.USER_DEFINED);// add to "thunked" func - - // TODO: Check for expected event - // TODO: Should see event for both real and thunk - - f2.addParameter(createParameter("p4", IntegerDataType.dataType), - SourceType.USER_DEFINED);// add to thunk - - // TODO: Check for expected event - // TODO: Should see event for both real and thunk - - // Change thunk name (hides thunked function name) - f2.setName("test", SourceType.USER_DEFINED); - - // TODO: Check for expected event - // TODO: Only one name change of thunk - - assertEquals("test", f2.getName()); - assertEquals("fum", f1.getName()); - - assertEquals("byte test(int p1, int p2, int p3, int p4)", - f2.getPrototypeString(false, false)); - assertEquals("byte fum(int p1, int p2, int p3, int p4)", - f1.getPrototypeString(false, false)); - - // Restore thunk to name to its default (pass-thru thunked function name) - f2.setName(null, SourceType.DEFAULT); - - // TODO: Check for expected event - // TODO: Why does original test expect two events? - - assertEquals("fum", f2.getName()); - assertEquals("fum", f1.getName()); - - assertEquals("byte fum(int p1, int p2, int p3, int p4)", - f2.getPrototypeString(false, false)); - assertEquals("byte fum(int p1, int p2, int p3, int p4)", - f1.getPrototypeString(false, false)); - } - } - - @Test - public void testPromoteLocalUserLabelsToGlobal() - throws InvalidInputException, OverlappingFunctionException { - try (Transaction tx = b.startTransaction()) { - - TraceFunctionSymbol foo2 = functions.create(0, b.addr(201), b.set(b.range(201, 249)), - "foo2", null, null, SourceType.USER_DEFINED); - - // Add symbols to verify proper global conversion - TraceLabelSymbolView labels = b.trace.getSymbolManager().labels(); - TraceNamespaceSymbol global = b.trace.getSymbolManager().getGlobalNamespace(); - // global - should keep - labels.create(0, null, b.addr(220), "LAB_Test", global, SourceType.USER_DEFINED); - // local - should remove (because its name conflicts with an existing global) - labels.create(0, null, b.addr(220), "LAB_Test", foo2, SourceType.USER_DEFINED); - // local - should keep (because it has a different name) - labels.create(0, null, b.addr(220), "LAB_TestA", foo2, SourceType.USER_DEFINED); - // local - should remove (because it's not USER_DEFINED) - labels.create(0, null, b.addr(220), "LAB_TestB", foo2, SourceType.ANALYSIS); - // local - should keep (because it's at a different address) - labels.create(0, null, b.addr(224), "LAB_Test", foo2, SourceType.USER_DEFINED); - - assertNotNull(labels.getGlobalWithNameAt("LAB_Test", 0, null, b.addr(220))); - assertNotNull(labels.getChildWithNameAt("LAB_Test", 0, null, b.addr(220), foo2)); - assertNotNull(labels.getChildWithNameAt("LAB_TestA", 0, null, b.addr(220), foo2)); - assertNotNull(labels.getChildWithNameAt("LAB_TestB", 0, null, b.addr(220), foo2)); - assertNotNull(labels.getChildWithNameAt("LAB_Test", 0, null, b.addr(224), foo2)); - - foo2.promoteLocalUserLabelsToGlobal(); - - foo2.getSymbol().delete(); // remove function (any remaining local symbols will be removed as well) - - // verify that only two symbols reside at b.addr(220) - assertEquals(2, labels.getAt(0, null, b.addr(220), false).size()); - - assertNotNull(labels.getGlobalWithNameAt("LAB_Test", 0, null, b.addr(220))); - assertNotNull(labels.getGlobalWithNameAt("LAB_TestA", 0, null, b.addr(220))); - assertNotNull(labels.getGlobalWithNameAt("LAB_Test", 0, null, b.addr(224))); - - assertTrue(b.trace.getSymbolManager() - .labelsAndFunctions() - .getAt(0, null, b.addr(201), - false) - .iterator() - .next() - .getSymbolType() != SymbolType.FUNCTION); - } - } - - @Test - @Ignore("TODO") - public void testSaveAndLoad() { - TODO(); - } - - @Test - @Ignore("TODO") - public void testUndoThenRedo() { - TODO(); - } -} diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/symbol/DBTraceSymbolManagerTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/symbol/DBTraceSymbolManagerTest.java index 14e1555fbf..3825948501 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/symbol/DBTraceSymbolManagerTest.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/symbol/DBTraceSymbolManagerTest.java @@ -262,11 +262,10 @@ public class DBTraceSymbolManagerTest extends AbstractGhidraHeadlessIntegrationT assertEquals(Set.of(nsA, clsA), new HashSet<>(manager.allNamespaces().getAll(false))); assertEquals(2, manager.allNamespaces().size(false)); - assertEquals(Set.of(lab1, lab2), new HashSet<>(manager.labelsAndFunctions().getAll(false))); - assertEquals(2, manager.labelsAndFunctions().size(false)); - assertEquals(Set.of(nsA, clsA), - new HashSet<>(manager.notLabelsNorFunctions().getAll(false))); - assertEquals(2, manager.notLabelsNorFunctions().size(false)); + assertEquals(Set.of(lab1, lab2), new HashSet<>(manager.labels().getAll(false))); + assertEquals(2, manager.labels().size(false)); + assertEquals(Set.of(nsA, clsA), new HashSet<>(manager.notLabels().getAll(false))); + assertEquals(2, manager.notLabels().size(false)); // TODO: Remaining composites assertEquals(Set.of(nsA, clsA, lab1, lab2), new HashSet<>(manager.allSymbols().getAll(false))); @@ -297,8 +296,7 @@ public class DBTraceSymbolManagerTest extends AbstractGhidraHeadlessIntegrationT assertEquals(Set.of(clsA), new HashSet<>(manager.classes().getChildrenNamed("A", nsA))); assertEquals(clsA, manager.classes().getChildNamed("A", nsA)); assertEquals(Set.of(lab1), new HashSet<>(manager.labels().getChildrenNamed("LAB1", nsA))); - assertEquals(Set.of(lab2), - new HashSet<>(manager.labelsAndFunctions().getChildrenNamed("LAB2", clsA))); + assertEquals(Set.of(lab2), new HashSet<>(manager.labels().getChildrenNamed("LAB2", clsA))); assertEquals(Set.of(), new HashSet<>(manager.labels().getChildrenNamed("LAB2", nsA))); } @@ -405,9 +403,9 @@ public class DBTraceSymbolManagerTest extends AbstractGhidraHeadlessIntegrationT SourceType.USER_DEFINED); } assertEquals(Set.of(lab1), - new HashSet<>(manager.labelsAndFunctions().getWithMatchingName("LAB?", true))); + new HashSet<>(manager.labels().getWithMatchingName("LAB?", true))); assertEquals(Set.of(lab1, lab2), - new HashSet<>(manager.labelsAndFunctions().getWithMatchingName("LAB?", false))); + new HashSet<>(manager.labels().getWithMatchingName("LAB?", false))); } @Test @@ -440,21 +438,19 @@ public class DBTraceSymbolManagerTest extends AbstractGhidraHeadlessIntegrationT } assertEquals(lab1, manager.labels().getChildWithNameAt("LAB1", 4, null, b.addr(0x4000), nsA)); - assertNull(manager.functions().getChildWithNameAt("LAB1", 4, null, b.addr(0x4000), nsA)); assertNull(manager.labels().getChildWithNameAt("LAB2", 4, null, b.addr(0x4000), nsA)); assertNull(manager.labels().getChildWithNameAt("LAB1", 0, null, b.addr(0x4000), nsA)); assertNull(manager.labels() .getChildWithNameAt("LAB1", 4, thread, b.language.getRegister("r4").getAddress(), nsA)); assertNull(manager.labels().getChildWithNameAt("LAB1", 4, null, b.addr(0x4001), nsA)); - assertNull( - manager.labelsAndFunctions().getChildWithNameAt("LAB1", 4, null, b.addr(0x4000), clsA)); + assertNull(manager.labels().getChildWithNameAt("LAB1", 4, null, b.addr(0x4000), clsA)); assertEquals(lab2, - manager.labelsAndFunctions().getChildWithNameAt("lab2", 4, null, b.addr(0x4001), clsA)); + manager.labels().getChildWithNameAt("lab2", 4, null, b.addr(0x4001), clsA)); assertEquals(lab3, - manager.labelsAndFunctions().getChildWithNameAt("lab3", 4, null, b.addr(0x4001), clsA)); - assertEquals(lab4, manager.labelsAndFunctions() + manager.labels().getChildWithNameAt("lab3", 4, null, b.addr(0x4001), clsA)); + assertEquals(lab4, manager.labels() .getChildWithNameAt("lab4", 0, thread, b.language.getRegister("r4").getAddress(), nsA)); } @@ -468,8 +464,6 @@ public class DBTraceSymbolManagerTest extends AbstractGhidraHeadlessIntegrationT .create(4, null, b.addr(0x4000), "LAB1", global, SourceType.USER_DEFINED); } - assertEquals(lab1, - manager.labelsAndFunctions().getGlobalWithNameAt("LAB1", 4, null, b.addr(0x4000))); assertEquals(lab1, manager.labels().getGlobalWithNameAt("LAB1", 4, null, b.addr(0x4000))); } @@ -504,9 +498,9 @@ public class DBTraceSymbolManagerTest extends AbstractGhidraHeadlessIntegrationT // TODO: Test that functions are properly excluded from labels() // once I have a means of adding them. assertEquals(Set.of(), - new HashSet<>(manager.labelsAndFunctions() - .getIntersecting(Lifespan.span(0, 0), null, - b.range(0x0000, 0x4000), false, true))); + new HashSet<>(manager.labels() + .getIntersecting(Lifespan.span(0, 0), null, b.range(0x0000, 0x4000), false, + true))); assertEquals(Set.of(lab1, lab2, lab3), new HashSet<>(manager.labels() .getIntersecting(Lifespan.nowOn(0), null, @@ -549,7 +543,7 @@ public class DBTraceSymbolManagerTest extends AbstractGhidraHeadlessIntegrationT assertEquals(Set.of(lab1), new HashSet<>(manager.labels().getAt(4, null, b.addr(0x4000), false))); assertEquals(Set.of(lab2, lab3), - new HashSet<>(manager.labelsAndFunctions().getAt(4, null, b.addr(0x4001), false))); + new HashSet<>(manager.labels().getAt(4, null, b.addr(0x4001), false))); // TODO: Test ordering by setPrimary assertFalse(manager.labels().hasAt(0, null, b.addr(0x4000), false)); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/CodeViewerProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/CodeViewerProvider.java index b14c7ec1ae..7c4305c3b6 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/CodeViewerProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/CodeViewerProvider.java @@ -177,13 +177,6 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter return !isConnected(); } - /** - * @return true if this listing is backed by a dynamic data source (e.g., debugger) - */ - public boolean isDynamicListing() { - return false; - } - /** * TODO: Remove or rename this to something that accommodates redirecting writes, e.g., to a * debug target process, particularly for assembly, which may involve code unit modification diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/FunctionPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/FunctionPlugin.java index c625e6988c..4ffe3d3892 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/FunctionPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/FunctionPlugin.java @@ -432,7 +432,10 @@ public class FunctionPlugin extends Plugin implements DataService { public boolean isCreateFunctionAllowed(ListingActionContext context, boolean allowExisting, boolean createThunk) { - + // Debugger traces do not support functions + if (context.getNavigatable().isDynamic()) { + return false; + } // A program and location is needed for any create function action. Program program = context.getProgram(); if (program == null) { 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 8aac7d728f..8ff048cc84 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 @@ -22,7 +22,6 @@ import ghidra.program.util.ProgramLocation; import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.InvalidInputException; import ghidra.util.task.TaskMonitor; -import ghidra.util.task.TaskMonitorAdapter; /** * Interface for a symbol, which associates a string value with @@ -110,7 +109,7 @@ public interface Symbol { /** * Returns all memory references to the address of this symbol. If you do not have a - * {@link TaskMonitor} instance, then you can pass {@link TaskMonitorAdapter#DUMMY_MONITOR} or + * {@link TaskMonitor} instance, then you can pass {@link TaskMonitor#DUMMY} or * null. * * @return all memory references to the address of this symbol.