diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/record/ObjectBasedTraceRecorder.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/record/ObjectBasedTraceRecorder.java index c5e0324ce9..e60aae77e5 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/record/ObjectBasedTraceRecorder.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/record/ObjectBasedTraceRecorder.java @@ -470,7 +470,7 @@ public class ObjectBasedTraceRecorder implements TraceRecorder { public Set getLiveTargetThreads() { return trace.getObjectManager() .getRootObject() - .querySuccessorsInterface(Lifespan.at(getSnap()), TraceObjectThread.class) + .querySuccessorsInterface(Lifespan.at(getSnap()), TraceObjectThread.class, true) .map(t -> objectRecorder.getTargetInterface(t.getObject(), TargetThread.class)) .collect(Collectors.toSet()); } @@ -673,9 +673,10 @@ public class ObjectBasedTraceRecorder implements TraceRecorder { public List collectBreakpointContainers(TargetThread thread) { if (thread == null) { return objectRecorder.collectTargetSuccessors(target, - TargetBreakpointSpecContainer.class); + TargetBreakpointSpecContainer.class, false); } - return objectRecorder.collectTargetSuccessors(thread, TargetBreakpointSpecContainer.class); + return objectRecorder.collectTargetSuccessors(thread, TargetBreakpointSpecContainer.class, + false); } private class BreakpointConvention { @@ -711,7 +712,8 @@ public class ObjectBasedTraceRecorder implements TraceRecorder { @Override public List collectBreakpoints(TargetThread thread) { if (thread == null) { - return objectRecorder.collectTargetSuccessors(target, TargetBreakpointLocation.class); + return objectRecorder.collectTargetSuccessors(target, TargetBreakpointLocation.class, + true); } BreakpointConvention convention = new BreakpointConvention( objectRecorder.getTraceInterface(thread, TraceObjectThread.class)); @@ -725,7 +727,8 @@ public class ObjectBasedTraceRecorder implements TraceRecorder { @Override public Set getSupportedBreakpointKinds() { - return objectRecorder.collectTargetSuccessors(target, TargetBreakpointSpecContainer.class) + return objectRecorder + .collectTargetSuccessors(target, TargetBreakpointSpecContainer.class, false) .stream() .flatMap(c -> c.getSupportedBreakpointKinds().stream()) .map(k -> TraceRecorder.targetToTraceBreakpointKind(k)) @@ -750,7 +753,7 @@ public class ObjectBasedTraceRecorder implements TraceRecorder { @Override public CompletableFuture requestFocus(TargetObject focus) { for (TargetFocusScope scope : objectRecorder.collectTargetSuccessors(target, - TargetFocusScope.class)) { + TargetFocusScope.class, false)) { if (PathUtils.isAncestor(scope.getPath(), focus.getPath())) { return scope.requestFocus(focus).thenApply(__ -> true).exceptionally(ex -> { ex = AsyncUtils.unwrapThrowable(ex); @@ -772,7 +775,7 @@ public class ObjectBasedTraceRecorder implements TraceRecorder { @Override public CompletableFuture requestActivation(TargetObject active) { for (TargetActiveScope scope : objectRecorder.collectTargetSuccessors(target, - TargetActiveScope.class)) { + TargetActiveScope.class, false)) { if (PathUtils.isAncestor(scope.getPath(), active.getPath())) { return scope.requestActivation(active).thenApply(__ -> true).exceptionally(ex -> { ex = AsyncUtils.unwrapThrowable(ex); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/record/ObjectRecorder.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/record/ObjectRecorder.java index 5dd7e7c1b5..5699e78fcc 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/record/ObjectRecorder.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/record/ObjectRecorder.java @@ -314,13 +314,14 @@ class ObjectRecorder { } protected List collectTargetSuccessors(TargetObject targetSeed, - Class targetIf) { + Class targetIf, boolean requireCanonical) { // TODO: Should this really go through the database? TraceObject seed = toTrace(targetSeed); if (seed == null) { return List.of(); } - return seed.querySuccessorsTargetInterface(Lifespan.at(recorder.getSnap()), targetIf) + return seed.querySuccessorsTargetInterface(Lifespan.at(recorder.getSnap()), targetIf, + requireCanonical) .map(p -> toTarget(p.getDestination(seed)).as(targetIf)) .collect(Collectors.toList()); } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/tracemgr/DebuggerTraceManagerServicePlugin.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/tracemgr/DebuggerTraceManagerServicePlugin.java index 8ba1a2c617..0c0b328239 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/tracemgr/DebuggerTraceManagerServicePlugin.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/tracemgr/DebuggerTraceManagerServicePlugin.java @@ -47,10 +47,9 @@ import ghidra.framework.plugintool.annotation.AutoConfigStateField; import ghidra.framework.plugintool.annotation.AutoServiceConsumed; import ghidra.framework.plugintool.util.PluginStatus; import ghidra.lifecycle.Internal; -import ghidra.trace.model.Trace; +import ghidra.trace.model.*; import ghidra.trace.model.Trace.TraceObjectChangeType; import ghidra.trace.model.Trace.TraceThreadChangeType; -import ghidra.trace.model.TraceDomainObjectListener; import ghidra.trace.model.guest.TracePlatform; import ghidra.trace.model.program.TraceProgramView; import ghidra.trace.model.program.TraceVariableSnapProgramView; @@ -641,7 +640,13 @@ public class DebuggerTraceManagerServicePlugin extends Plugin inactive = curForTrace.snapNoResolve(snap); lastCoordsByTrace.put(trace, inactive); } - trace.getProgramView().setSnap(snap); + try { + trace.getProgramView().setSnap(snap); + } + catch (TraceClosedException e) { + // Whatever. Presumably, a closed event is already queued.... + Msg.warn(this, "Ignoring snapshot advance for closed trace: " + e); + } firePluginEvent(new TraceInactiveCoordinatesPluginEvent(getName(), inactive)); return; } diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesProviderTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesProviderTest.java index b0c0515e4a..826a33e3eb 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesProviderTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesProviderTest.java @@ -186,13 +186,13 @@ public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerGUI try (UndoableTransaction tid = tb.startTransaction()) { TraceObject root = om.getRootObject(); for (TraceObject module : (Iterable) () -> root - .querySuccessorsTargetInterface(Lifespan.at(0), TargetModule.class) + .querySuccessorsTargetInterface(Lifespan.at(0), TargetModule.class, true) .map(p -> p.getDestination(root)) .iterator()) { String moduleName = module.getCanonicalPath().index(); Lifespan span = module.getLife().bound(); for (TraceObject section : (Iterable) () -> module - .querySuccessorsTargetInterface(Lifespan.at(0), TargetSection.class) + .querySuccessorsTargetInterface(Lifespan.at(0), TargetSection.class, true) .map(p -> p.getDestination(root)) .iterator()) { String sectionName = section.getCanonicalPath().index(); diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/model/record/ObjectBasedTraceRecorderTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/model/record/ObjectBasedTraceRecorderTest.java index 243047b4f0..c29638c7dc 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/model/record/ObjectBasedTraceRecorderTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/model/record/ObjectBasedTraceRecorderTest.java @@ -517,7 +517,7 @@ public class ObjectBasedTraceRecorderTest extends AbstractGhidraHeadedDebuggerGU TraceObject traceBank = thread.getObject() .querySuccessorsTargetInterface(Lifespan.at(recorder.getSnap()), - TargetRegisterBank.class) + TargetRegisterBank.class, false) .map(p -> p.getDestination(thread.getObject())) .findAny() .orElseThrow(); diff --git a/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/schema/TargetObjectSchema.java b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/schema/TargetObjectSchema.java index 8ca0547562..1bb65a4cf2 100644 --- a/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/schema/TargetObjectSchema.java +++ b/Ghidra/Debug/Framework-Debugging/src/main/java/ghidra/dbg/target/schema/TargetObjectSchema.java @@ -618,6 +618,7 @@ public interface TargetObjectSchema { } if (sch.getInterfaces().contains(type) && (parentIsCanonical || !requireCanonical)) { result.addPattern(prefix); + return; } if (!visited.add(sch)) { return; diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/breakpoint/DBTraceObjectBreakpointLocation.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/breakpoint/DBTraceObjectBreakpointLocation.java index 22e46a0df4..d436ff605f 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/breakpoint/DBTraceObjectBreakpointLocation.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/breakpoint/DBTraceObjectBreakpointLocation.java @@ -283,7 +283,7 @@ public class DBTraceObjectBreakpointLocation return object.getAncestorsRoot(getLifespan(), procMatcher) .flatMap(proc -> proc.getSource(object) .querySuccessorsInterface(getLifespan(), - TraceObjectThread.class)) + TraceObjectThread.class, true)) .collect(Collectors.toSet()); } } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/breakpoint/DBTraceObjectBreakpointSpec.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/breakpoint/DBTraceObjectBreakpointSpec.java index 4adde4af9a..a769e9c2d8 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/breakpoint/DBTraceObjectBreakpointSpec.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/breakpoint/DBTraceObjectBreakpointSpec.java @@ -226,9 +226,8 @@ public class DBTraceObjectBreakpointSpec @Override public Collection getLocations() { try (LockHold hold = object.getTrace().lockRead()) { - return object - .querySuccessorsInterface(getLifespan(), TraceObjectBreakpointLocation.class) - .collect(Collectors.toSet()); + return object.querySuccessorsInterface(getLifespan(), + TraceObjectBreakpointLocation.class, true).collect(Collectors.toSet()); } } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/guest/DBTraceObjectRegisterSupport.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/guest/DBTraceObjectRegisterSupport.java index 2a4fb2688d..6636cd865c 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/guest/DBTraceObjectRegisterSupport.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/guest/DBTraceObjectRegisterSupport.java @@ -242,7 +242,8 @@ public enum DBTraceObjectRegisterSupport { protected void onSpaceAddedCheckTransferToPlatformRegisters(TracePlatform platform, TraceObject regContainer, TraceMemorySpace mem) { for (TraceObjectValPath path : it( - regContainer.querySuccessorsTargetInterface(Lifespan.ALL, TargetRegister.class))) { + regContainer.querySuccessorsTargetInterface(Lifespan.ALL, TargetRegister.class, + true))) { TraceObject registerObject = path.getDestination(platform.getTrace().getObjectManager().getRootObject()); onSpaceAddedCheckTransferObjectToPlatformRegister(registerObject, platform, mem); @@ -437,7 +438,7 @@ public enum DBTraceObjectRegisterSupport { public void onMappingAddedCheckTransferMemoryMapped(TraceObject root, TraceGuestPlatformMappedRange mapped) { for (TraceObjectValPath path : it( - root.querySuccessorsTargetInterface(Lifespan.ALL, TargetRegister.class))) { + root.querySuccessorsTargetInterface(Lifespan.ALL, TargetRegister.class, true))) { TraceObject registerObject = path.getDestination(root); onMappingAddedCheckTransferRegisterObjectMemoryMapped(registerObject, mapped); } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceObjectModule.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceObjectModule.java index d109e3a87f..ce7812657e 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceObjectModule.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceObjectModule.java @@ -240,7 +240,7 @@ public class DBTraceObjectModule implements TraceObjectModule, DBTraceObjectInte @Override public Collection getSections() { try (LockHold hold = object.getTrace().lockRead()) { - return object.querySuccessorsInterface(getLifespan(), TraceObjectSection.class) + return object.querySuccessorsInterface(getLifespan(), TraceObjectSection.class, true) .collect(Collectors.toSet()); } } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/stack/DBTraceObjectStack.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/stack/DBTraceObjectStack.java index 242f63ec15..0590fd0fa3 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/stack/DBTraceObjectStack.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/stack/DBTraceObjectStack.java @@ -93,8 +93,7 @@ public class DBTraceObjectStack implements TraceObjectStack, DBTraceObjectInterf @Override public int getDepth() { try (LockHold hold = object.getTrace().lockRead()) { - return object - .querySuccessorsInterface(computeSpan(), TraceObjectStackFrame.class) + return object.querySuccessorsInterface(computeSpan(), TraceObjectStackFrame.class, true) .map(f -> f.getLevel()) .reduce(Integer::max) .map(m -> m + 1) @@ -210,8 +209,7 @@ public class DBTraceObjectStack implements TraceObjectStack, DBTraceObjectInterf } protected Stream doGetFrames(long snap) { - return object - .querySuccessorsInterface(Lifespan.at(snap), TraceObjectStackFrame.class) + return object.querySuccessorsInterface(Lifespan.at(snap), TraceObjectStackFrame.class, true) .sorted(Comparator.comparing(f -> f.getLevel())); } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/target/DBTraceObject.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/target/DBTraceObject.java index 04abde49da..16b45f10b7 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/target/DBTraceObject.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/target/DBTraceObject.java @@ -876,16 +876,16 @@ public class DBTraceObject extends DBAnnotatedObject implements TraceObject { @Override public Stream querySuccessorsTargetInterface(Lifespan span, - Class targetIf) { - PathMatcher matcher = getTargetSchema().searchFor(targetIf, true); + Class targetIf, boolean requireCanonical) { + PathMatcher matcher = getTargetSchema().searchFor(targetIf, requireCanonical); return getSuccessors(span, matcher).filter(p -> isActuallyInterface(p, targetIf)); } @Override public Stream querySuccessorsInterface(Lifespan span, - Class ifClass) { - return querySuccessorsTargetInterface(span, TraceObjectInterfaceUtils.toTargetIf(ifClass)) - .map(p -> p.getDestination(this).queryInterface(ifClass)); + Class ifClass, boolean requireCanonical) { + return querySuccessorsTargetInterface(span, TraceObjectInterfaceUtils.toTargetIf(ifClass), + requireCanonical).map(p -> p.getDestination(this).queryInterface(ifClass)); } protected void doDelete() { diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/target/TraceObject.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/target/TraceObject.java index 806d5f11e7..138ceb64ec 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/target/TraceObject.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/target/TraceObject.java @@ -466,10 +466,11 @@ public interface TraceObject extends TraceUniqueObject { * * @param span the span which the found paths must intersect * @param targetIf the target interface class + * @param requireCanonical if the objects must be found within their canonical container * @return the stream of found paths to values */ Stream querySuccessorsTargetInterface(Lifespan span, - Class targetIf); + Class targetIf, boolean requireCanonical); /** * Search for successors providing the given interface and retrieve those interfaces @@ -477,10 +478,11 @@ public interface TraceObject extends TraceUniqueObject { * @param the interface type * @param span the span which the found objects must intersect * @param ifClass the interface class + * @param requireCanonical if the objects must be found within their canonical container * @return the stream of interfaces */ Stream querySuccessorsInterface(Lifespan span, - Class ifClass); + Class ifClass, boolean requireCanonical); /** * Delete this object along with parent and child value entries referring to it