From 4e33952b81448f0c98ec30aa39f51f8386cc7222 Mon Sep 17 00:00:00 2001 From: Dan <46821332+nsadeveloper789@users.noreply.github.com> Date: Thu, 20 May 2021 11:36:12 -0400 Subject: [PATCH] GP-0: Debugger test fixes --- .../debug/event/TraceClosedPluginEvent.java | 4 +- .../debug/event/TraceOpenedPluginEvent.java | 4 +- .../service/model/DefaultStackRecorder.java | 75 ++++++++++------- .../DebuggerStaticMappingServicePlugin.java | 8 ++ .../DebuggerTraceManagerServicePlugin.java | 3 + .../listing/DebuggerListingProviderTest.java | 36 ++++---- .../memory/DebuggerRegionsProviderTest.java | 2 + .../modules/DebuggerModulesProviderTest.java | 2 + .../DebuggerLogicalBreakpointServiceTest.java | 77 ++++++++++------- .../model/DebuggerModelServiceTest.java | 22 +++-- .../DebuggerTraceManagerServiceTest.java | 62 +++++++------- .../exec/TraceRecorderAsyncPcodeExecTest.java | 32 +++++-- .../trace/util/DefaultTraceTimeViewport.java | 25 +++++- .../RowWrappedEnumeratedColumnTableModel.java | 19 +++-- .../widgets/timeline/TimelinePanel.java | 83 +++++++++++-------- .../plugintool/mgr/EventManager.java | 40 +++++---- 16 files changed, 310 insertions(+), 184 deletions(-) diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/event/TraceClosedPluginEvent.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/event/TraceClosedPluginEvent.java index 935e60d472..ca4f07cb2b 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/event/TraceClosedPluginEvent.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/event/TraceClosedPluginEvent.java @@ -21,12 +21,12 @@ import ghidra.framework.plugintool.PluginEvent; import ghidra.trace.model.Trace; public class TraceClosedPluginEvent extends PluginEvent { - static final String NAME = "Trace Closed"; + static final String NAME = "Trace Closed @"; private final WeakReference traceRef; public TraceClosedPluginEvent(String source, Trace trace) { - super(source, NAME); + super(source, NAME + Integer.toHexString(System.identityHashCode(trace))); this.traceRef = new WeakReference<>(trace); } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/event/TraceOpenedPluginEvent.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/event/TraceOpenedPluginEvent.java index 466998e625..41f612089a 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/event/TraceOpenedPluginEvent.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/event/TraceOpenedPluginEvent.java @@ -21,12 +21,12 @@ import ghidra.framework.plugintool.PluginEvent; import ghidra.trace.model.Trace; public class TraceOpenedPluginEvent extends PluginEvent { - static final String NAME = "Trace Opened"; + static final String NAME = "Trace Opened @"; private final WeakReference newTraceRef; public TraceOpenedPluginEvent(String source, Trace trace) { - super(source, NAME); + super(source, NAME + Integer.toHexString(System.identityHashCode(trace))); this.newTraceRef = new WeakReference<>(trace); } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/DefaultStackRecorder.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/DefaultStackRecorder.java index 7d4ea2cf88..596c49cff9 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/DefaultStackRecorder.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/DefaultStackRecorder.java @@ -58,12 +58,15 @@ public class DefaultStackRecorder implements ManagedStackRecorder { @Override public void recordStack() { long snap = recorder.getSnap(); - Map pcsByLevel = stack.entrySet() - .stream() - .collect(Collectors.toMap(e -> e.getKey(), e -> { - return recorder.getMemoryMapper() - .targetToTrace(e.getValue().getProgramCounter()); - })); + DebuggerMemoryMapper mm = recorder.getMemoryMapper(); + Map pcsByLevel; + synchronized (stack) { + pcsByLevel = stack.entrySet() + .stream() + .collect(Collectors.toMap(e -> e.getKey(), e -> { + return mm.targetToTrace(e.getValue().getProgramCounter()); + })); + } recorder.parTx.execute("Stack changed", () -> { TraceStack traceStack = stackManager.getStack(thread, snap, true); traceStack.setDepth(stackDepth(), false); @@ -88,7 +91,9 @@ public class DefaultStackRecorder implements ManagedStackRecorder { public void recordFrame(TargetStackFrame frame) { long snap = recorder.getSnap(); - stack.put(getFrameLevel(frame), frame); + synchronized (stack) { + stack.put(getFrameLevel(frame), frame); + } recorder.parTx.execute("Stack frame added", () -> { DebuggerMemoryMapper memoryMapper = recorder.getMemoryMapper(); if (memoryMapper == null) { @@ -102,44 +107,48 @@ public class DefaultStackRecorder implements ManagedStackRecorder { } protected int stackDepth() { - return stack.isEmpty() ? 0 : stack.lastKey() + 1; + synchronized (stack) { + return stack.isEmpty() ? 0 : stack.lastKey() + 1; + } } @Override public int getSuccessorFrameLevel(TargetObject successor) { - NavigableSet observedPathLengths = new TreeSet<>(); - for (TargetStackFrame frame : stack.values()) { - observedPathLengths.add(frame.getPath().size()); - } - List path = successor.getPath(); - for (int l : observedPathLengths.descendingSet()) { - if (l > path.size()) { - continue; + for (TargetObject p = successor; p != null; p = p.getParent()) { + if (p instanceof TargetStackFrame) { + if (!PathUtils.isIndex(p.getPath())) { + return 0; + } + int index = Integer.decode(p.getIndex()); + TargetStackFrame frame; + synchronized (stack) { + frame = stack.get(index); + } + if (!Objects.equals(p, frame)) { + return 0; + } + return index; } - List sub = path.subList(0, l); - if (!PathUtils.isIndex(sub)) { - continue; - } - int index = Integer.decode(PathUtils.getIndex(sub)); - TargetStackFrame frame = stack.get(index); - if (frame == null || !Objects.equals(sub, frame.getPath())) { - continue; - } - return index; } return 0; } protected boolean checkStackFrameRemoved(TargetObject invalid) { - if (stack.values().remove(invalid)) { - popStack(); - return true; + boolean removed; + synchronized (stack) { + removed = stack.values().remove(invalid); } - return false; + if (removed) { + popStack(); + } + return removed; } public Address pcFromStack() { - TargetStackFrame frame = stack.get(0); + TargetStackFrame frame; + synchronized (stack) { + frame = stack.get(0); + } if (frame == null) { return null; } @@ -157,7 +166,9 @@ public class DefaultStackRecorder implements ManagedStackRecorder { @Override public TargetStackFrame getTargetStackFrame(int frameLevel) { - return stack.get(frameLevel); + synchronized (stack) { + return stack.get(frameLevel); + } } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingServicePlugin.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingServicePlugin.java index db35964926..8ee12f0c3b 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingServicePlugin.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingServicePlugin.java @@ -904,6 +904,10 @@ public class DebuggerStaticMappingServicePlugin extends Plugin private void traceOpened(Trace trace) { synchronized (lock) { + if (trace.isClosed()) { + Msg.warn(this, "Got traceOpened for a close trace"); + return; + } InfoPerTrace newInfo = new InfoPerTrace(trace); InfoPerTrace mustBeNull = trackedTraceInfo.put(trace, newInfo); assert mustBeNull == null; @@ -922,6 +926,10 @@ public class DebuggerStaticMappingServicePlugin extends Plugin private void traceClosed(Trace trace) { synchronized (lock) { InfoPerTrace traceInfo = trackedTraceInfo.remove(trace); + if (traceInfo == null) { + Msg.warn(this, "Got traceClosed without/before traceOpened"); + return; + } traceInfo.dispose(); doAffectedByTraceClosed(trace); } 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 cf3d8695b2..d0ae07028b 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 @@ -1006,6 +1006,9 @@ public class DebuggerTraceManagerServicePlugin extends Plugin return; } TraceRecorder recorder = resolved.getRecorder(); + if (recorder == null) { + return; + } TargetObject focus = translateToFocus(prev, resolved); if (focus == null) { return; diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProviderTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProviderTest.java index fc80668f95..35c24c2bd1 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProviderTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProviderTest.java @@ -103,12 +103,16 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI codeViewer = tool.getService(CodeViewerService.class); } - protected boolean goToDyn(Address address) { - return goToDyn(new ProgramLocation(traceManager.getCurrentView(), address)); + protected void goToDyn(Address address) { + goToDyn(new ProgramLocation(traceManager.getCurrentView(), address)); } - protected boolean goToDyn(ProgramLocation location) { - return listingProvider.goTo(location.getProgram(), location); + protected void goToDyn(ProgramLocation location) { + waitForPass(() -> { + runSwing(() -> listingProvider.goTo(location.getProgram(), location)); + ProgramLocation confirm = listingProvider.getLocation(); + assertEquals(location.getAddress(), confirm.getAddress()); + }); } protected static byte[] incBlock() { @@ -680,19 +684,14 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI trace.getMemoryManager().getBytes(recorder.getSnap(), addr(trace, 0x55550000), buf)); assertArrayEquals(zero, buf.array()); - runSwing(() -> goToDyn(addr(trace, 0x55550800))); + goToDyn(addr(trace, 0x55550800)); waitForDomainObject(trace); buf.clear(); assertEquals(data.length, trace.getMemoryManager().getBytes(recorder.getSnap(), addr(trace, 0x55550000), buf)); assertArrayEquals(zero, buf.array()); - runSwing(() -> goToDyn(addr(trace, 0x55551800))); - waitForPass(() -> { - ProgramLocation location = listingProvider.getLocation(); - assertNotNull(location); - assertEquals(addr(trace, 0x55551800), location.getAddress()); - }); + goToDyn(addr(trace, 0x55551800)); waitForDomainObject(trace); buf.clear(); assertEquals(data.length, @@ -713,13 +712,16 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI /** * We're now moving to the written block */ - runSwing(() -> goToDyn(addr(trace, 0x55550800))); + goToDyn(addr(trace, 0x55550800)); waitForSwing(); waitForDomainObject(trace); - buf.clear(); - assertEquals(data.length, - trace.getMemoryManager().getBytes(recorder.getSnap(), addr(trace, 0x55550000), buf)); - assertArrayEquals(data, buf.array()); + // NB. Recorder can delay writing in a thread / queue + waitForPass(() -> { + buf.clear(); + assertEquals(data.length, trace.getMemoryManager() + .getBytes(recorder.getSnap(), addr(trace, 0x55550000), buf)); + assertArrayEquals(data, buf.array()); + }); } @Test @@ -845,7 +847,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI assertEquals(trackPc, listingProvider.actionTrackLocation.getCurrentUserData()); assertEquals(tb.addr(0x00401234), listingProvider.getLocation().getAddress()); - runSwing(() -> goToDyn(tb.addr(0x00400000))); + goToDyn(tb.addr(0x00400000)); // Ensure it's changed so we know the action is effective waitForSwing(); assertEquals(tb.addr(0x00400000), listingProvider.getLocation().getAddress()); diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsProviderTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsProviderTest.java index c8c1458c19..1743bf7eb7 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsProviderTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsProviderTest.java @@ -249,6 +249,8 @@ public class DebuggerRegionsProviderTest extends AbstractGhidraHeadedDebuggerGUI waitForSwing(); RegionRow row = Unique.assertOne(provider.regionTableModel.getModelData()); + // NB. Table is debounced + waitForPass(() -> assertEquals(1, provider.regionTable.getRowCount())); assertEquals(region, row.getRegion()); assertFalse(tb.trace.getProgramView().getMemory().isEmpty()); 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 dc2da484c9..044a266bed 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 @@ -671,6 +671,8 @@ public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerGUI addModules(); traceManager.activateTrace(tb.trace); waitForSwing(); + // NB. Table is debounced + waitForPass(() -> assertEquals(2, modulesProvider.moduleTable.getRowCount())); clickTableCellWithButton(modulesProvider.moduleTable, 0, 0, MouseEvent.BUTTON3); waitForSwing(); diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/breakpoint/DebuggerLogicalBreakpointServiceTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/breakpoint/DebuggerLogicalBreakpointServiceTest.java index 4fe60d08f4..10bbe5fc39 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/breakpoint/DebuggerLogicalBreakpointServiceTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/breakpoint/DebuggerLogicalBreakpointServiceTest.java @@ -329,10 +329,10 @@ public class DebuggerLogicalBreakpointServiceTest extends AbstractGhidraHeadedDe try (UndoableTransaction tid = UndoableTransaction.start(p, "Create bookmarks", true)) { enBm = p.getBookmarkManager() .setBookmark(addr(p, 0x00400123), - LogicalBreakpoint.BREAKPOINT_ENABLED_BOOKMARK_TYPE, "SOFTWARE;1", ""); + LogicalBreakpoint.BREAKPOINT_ENABLED_BOOKMARK_TYPE, "SW_EXECUTE;1", ""); disBm = p.getBookmarkManager() .setBookmark(addr(p, 0x00400321), - LogicalBreakpoint.BREAKPOINT_DISABLED_BOOKMARK_TYPE, "SOFTWARE;1", ""); + LogicalBreakpoint.BREAKPOINT_DISABLED_BOOKMARK_TYPE, "SW_EXECUTE;1", ""); } } @@ -340,10 +340,10 @@ public class DebuggerLogicalBreakpointServiceTest extends AbstractGhidraHeadedDe // After a redo enBm = p.getBookmarkManager() .getBookmark(addr(p, 0x00400123), - LogicalBreakpoint.BREAKPOINT_ENABLED_BOOKMARK_TYPE, "SOFTWARE;1"); + LogicalBreakpoint.BREAKPOINT_ENABLED_BOOKMARK_TYPE, "SW_EXECUTE;1"); disBm = p.getBookmarkManager() .getBookmark(addr(p, 0x00400321), - LogicalBreakpoint.BREAKPOINT_DISABLED_BOOKMARK_TYPE, "SOFTWARE;1"); + LogicalBreakpoint.BREAKPOINT_DISABLED_BOOKMARK_TYPE, "SW_EXECUTE;1"); } protected void removeProgramBreakpoints(Program p) throws Throwable { @@ -950,16 +950,16 @@ public class DebuggerLogicalBreakpointServiceTest extends AbstractGhidraHeadedDe addProgramTextBlock(program); TestTargetMemoryRegion text1 = addTargetTextRegion(mb.testProcess1); TestTargetMemoryRegion text3 = addTargetTextRegion(mb.testProcess3, 0x55551000); + + addTextMapping(recorder1, text1, program); + addTextMapping(recorder3, text3, program); + waitForSwing(); waitForPass(() -> { - assertEquals(1, trace1.getMemoryManager().getAllRegions().size()); - assertEquals(1, trace3.getMemoryManager().getAllRegions().size()); + assertEquals(2, mappingService + .getOpenMappedLocations( + new ProgramLocation(program, addr(program, 0x00400123))) + .size()); }); - waitForLock(trace1); - waitForLock(trace3); - waitForDomainObject(trace1); - waitForDomainObject(trace3); - expectMappingChange(() -> addTextMapping(recorder1, text1, program)); - expectMappingChange(() -> addTextMapping(recorder3, text3, program)); waitForSwing(); addProgramBreakpoints(program); @@ -989,16 +989,16 @@ public class DebuggerLogicalBreakpointServiceTest extends AbstractGhidraHeadedDe addProgramTextBlock(program); TestTargetMemoryRegion text1 = addTargetTextRegion(mb.testProcess1); TestTargetMemoryRegion text3 = addTargetTextRegion(mb.testProcess3, 0x55551000); + + addTextMapping(recorder1, text1, program); + addTextMapping(recorder3, text3, program); + waitForSwing(); waitForPass(() -> { - assertEquals(1, trace1.getMemoryManager().getAllRegions().size()); - assertEquals(1, trace3.getMemoryManager().getAllRegions().size()); + assertEquals(2, mappingService + .getOpenMappedLocations( + new ProgramLocation(program, addr(program, 0x00400123))) + .size()); }); - waitForLock(trace1); - waitForLock(trace3); - waitForDomainObject(trace1); - waitForDomainObject(trace3); - expectMappingChange(() -> addTextMapping(recorder1, text1, program)); - expectMappingChange(() -> addTextMapping(recorder3, text3, program)); waitForSwing(); addProgramBreakpoints(program); @@ -1033,8 +1033,16 @@ public class DebuggerLogicalBreakpointServiceTest extends AbstractGhidraHeadedDe addProgramTextBlock(program); TestTargetMemoryRegion text1 = addTargetTextRegion(mb.testProcess1); TestTargetMemoryRegion text3 = addTargetTextRegion(mb.testProcess3, 0x55551000); - expectMappingChange(() -> addTextMapping(recorder1, text1, program)); - expectMappingChange(() -> addTextMapping(recorder3, text3, program)); + + addTextMapping(recorder1, text1, program); + addTextMapping(recorder3, text3, program); + waitForSwing(); + waitForPass(() -> { + assertEquals(2, mappingService + .getOpenMappedLocations( + new ProgramLocation(program, addr(program, 0x00400123))) + .size()); + }); waitForSwing(); addProgramBreakpoints(program); @@ -1048,13 +1056,17 @@ public class DebuggerLogicalBreakpointServiceTest extends AbstractGhidraHeadedDe expectMappingChange(() -> programManager.closeProgram(program, true)); waitForSwing(); - assertLogicalBreakpointForLoneSoftwareBreakpoint(trace1, 0x55550123, 2); - assertLogicalBreakpointForLoneSoftwareBreakpoint(trace3, 0x55551123, 2); + waitForPass(() -> { + assertLogicalBreakpointForLoneSoftwareBreakpoint(trace1, 0x55550123, 2); + assertLogicalBreakpointForLoneSoftwareBreakpoint(trace3, 0x55551123, 2); + }); expectMappingChange(() -> programManager.openProgram(program)); waitForSwing(); - assertLogicalBreakpointForMappedBookmarkAnd2TraceBreakpoints(trace1, trace3); + waitForPass(() -> { + assertLogicalBreakpointForMappedBookmarkAnd2TraceBreakpoints(trace1, trace3); + }); } @Test @@ -1074,8 +1086,16 @@ public class DebuggerLogicalBreakpointServiceTest extends AbstractGhidraHeadedDe addProgramTextBlock(program); TestTargetMemoryRegion text1 = addTargetTextRegion(mb.testProcess1); TestTargetMemoryRegion text3 = addTargetTextRegion(mb.testProcess3, 0x55551000); - expectMappingChange(() -> addTextMapping(recorder1, text1, program)); - expectMappingChange(() -> addTextMapping(recorder3, text3, program)); + + addTextMapping(recorder1, text1, program); + addTextMapping(recorder3, text3, program); + waitForSwing(); + waitForPass(() -> { + assertEquals(2, mappingService + .getOpenMappedLocations( + new ProgramLocation(program, addr(program, 0x00400123))) + .size()); + }); waitForSwing(); addProgramBreakpoints(program); @@ -1372,7 +1392,8 @@ public class DebuggerLogicalBreakpointServiceTest extends AbstractGhidraHeadedDe long oldSnap = recorder1.getSnap(); mb.testModel.session.simulateStep(mb.testThread1); waitOn(mb.testModel.flushEvents()); - assertEquals(oldSnap + 1, recorder1.getSnap()); + // NB. recorder may have its own threads / queues + waitForPass(() -> assertTrue(recorder1.getSnap() > oldSnap)); waitOn(lb.delete()); diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/model/DebuggerModelServiceTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/model/DebuggerModelServiceTest.java index 4725f34e88..d9cbbc59d1 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/model/DebuggerModelServiceTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/model/DebuggerModelServiceTest.java @@ -444,20 +444,26 @@ public class DebuggerModelServiceTest extends AbstractGhidraHeadedDebuggerGUITes assertNull(modelService.getTargetFocus(mb.testProcess3)); waitOn(mb.testModel.requestFocus(mb.testThread1)); - assertEquals(mb.testThread1, modelService.getTargetFocus(mb.testProcess1)); - assertNull(modelService.getTargetFocus(mb.testProcess3)); + waitForPass( + () -> assertEquals(mb.testThread1, modelService.getTargetFocus(mb.testProcess1))); + waitForPass(() -> assertNull(modelService.getTargetFocus(mb.testProcess3))); waitOn(mb.testModel.requestFocus(mb.testThread2)); - assertEquals(mb.testThread2, modelService.getTargetFocus(mb.testProcess1)); - assertNull(modelService.getTargetFocus(mb.testProcess3)); + waitForPass( + () -> assertEquals(mb.testThread2, modelService.getTargetFocus(mb.testProcess1))); + waitForPass(() -> assertNull(modelService.getTargetFocus(mb.testProcess3))); waitOn(mb.testModel.requestFocus(mb.testThread3)); - assertEquals(mb.testThread2, modelService.getTargetFocus(mb.testProcess1)); - assertEquals(mb.testThread3, modelService.getTargetFocus(mb.testProcess3)); + waitForPass( + () -> assertEquals(mb.testThread2, modelService.getTargetFocus(mb.testProcess1))); + waitForPass( + () -> assertEquals(mb.testThread3, modelService.getTargetFocus(mb.testProcess3))); waitOn(mb.testModel.requestFocus(mb.testThread4)); - assertEquals(mb.testThread2, modelService.getTargetFocus(mb.testProcess1)); - assertEquals(mb.testThread4, modelService.getTargetFocus(mb.testProcess3)); + waitForPass( + () -> assertEquals(mb.testThread2, modelService.getTargetFocus(mb.testProcess1))); + waitForPass( + () -> assertEquals(mb.testThread4, modelService.getTargetFocus(mb.testProcess3))); } @Test diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/tracemgr/DebuggerTraceManagerServiceTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/tracemgr/DebuggerTraceManagerServiceTest.java index b8fa475a49..fa90b81bce 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/tracemgr/DebuggerTraceManagerServiceTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/tracemgr/DebuggerTraceManagerServiceTest.java @@ -19,9 +19,7 @@ import static org.junit.Assert.*; import java.util.Collection; import java.util.Set; -import java.util.concurrent.TimeUnit; -import org.junit.Ignore; import org.junit.Test; import ghidra.app.plugin.core.debug.DebuggerCoordinates; @@ -29,16 +27,16 @@ import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest; import ghidra.app.services.TraceRecorder; import ghidra.dbg.model.TestTargetStack; import ghidra.dbg.model.TestTargetStackFrameHasRegisterBank; +import ghidra.dbg.testutil.DebuggerModelTestUtils; import ghidra.framework.model.DomainFile; import ghidra.trace.database.thread.DBTraceThread; import ghidra.trace.model.Trace; +import ghidra.trace.model.stack.TraceStack; import ghidra.trace.model.thread.TraceThread; -import ghidra.util.SystemUtilities; import ghidra.util.database.UndoableTransaction; -public class DebuggerTraceManagerServiceTest extends AbstractGhidraHeadedDebuggerGUITest { - protected static final long TIMEOUT_MILLIS = - SystemUtilities.isInTestingBatchMode() ? 5000 : Long.MAX_VALUE; +public class DebuggerTraceManagerServiceTest extends AbstractGhidraHeadedDebuggerGUITest + implements DebuggerModelTestUtils { @Test public void testGetOpenTraces() throws Exception { @@ -341,6 +339,8 @@ public class DebuggerTraceManagerServiceTest extends AbstractGhidraHeadedDebugge Trace trace = recorder.getTrace(); waitForValue(() -> modelService.getTarget(trace)); + // TODO: Fragile. This depends on the recorder advancing the snap for each thread + waitForPass(() -> assertEquals(2, trace.getTimeManager().getSnapshotCount())); traceManager.openTrace(trace); waitForSwing(); @@ -352,13 +352,13 @@ public class DebuggerTraceManagerServiceTest extends AbstractGhidraHeadedDebugge // No default thread/frame when live with focus support assertNull(traceManager.getCurrentThread()); - assertEquals(mb.testProcess1, mb.testModel.session.getFocus()); + waitForPass(() -> assertEquals(mb.testProcess1, mb.testModel.session.getFocus())); TraceThread thread = waitForValue(() -> recorder.getTraceThread(mb.testThread1)); traceManager.activateThread(thread); waitForSwing(); - assertEquals(mb.testThread1, mb.testModel.session.getFocus()); + waitForPass(() -> assertEquals(mb.testThread1, mb.testModel.session.getFocus())); TestTargetStack stack = mb.testThread1.addStack(); // Note, push simply moves the data, the new frame still has the higher index @@ -375,23 +375,22 @@ public class DebuggerTraceManagerServiceTest extends AbstractGhidraHeadedDebugge traceManager.activateFrame(1); waitForSwing(); - assertEquals(frame1, mb.testModel.session.getFocus()); + waitForPass(() -> assertEquals(frame1, mb.testModel.session.getFocus())); traceManager.activateFrame(0); waitForSwing(); - assertEquals(frame0, mb.testModel.session.getFocus()); + waitForPass(() -> assertEquals(frame0, mb.testModel.session.getFocus())); traceManager.setSynchronizeFocus(false); traceManager.activateFrame(1); waitForSwing(); - assertEquals(frame0, mb.testModel.session.getFocus()); + waitForPass(() -> assertEquals(frame0, mb.testModel.session.getFocus())); } @Test - @Ignore("TODO") // Not sure why this fails under Gradle but not my IDE - public void testSynchronizeFocusModelToTrace() throws Exception { + public void testSynchronizeFocusModelToTrace() throws Throwable { assertTrue(traceManager.isSynchronizeFocus()); createTestModel(); @@ -406,43 +405,40 @@ public class DebuggerTraceManagerServiceTest extends AbstractGhidraHeadedDebugge assertNull(traceManager.getCurrentTrace()); - mb.testModel.session.requestFocus(mb.testProcess1) - .get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); - waitForSwing(); + waitOn(mb.testModel.session.requestFocus(mb.testProcess1)); // No default thread/frame when live with focus support assertNull(traceManager.getCurrentThread()); - assertEquals(recorder.getTrace(), traceManager.getCurrentTrace()); + waitForPass(() -> assertEquals(recorder.getTrace(), traceManager.getCurrentTrace())); - mb.testModel.session.requestFocus(mb.testThread1) - .get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); - waitForSwing(); + waitOn(mb.testModel.session.requestFocus(mb.testThread1)); - assertEquals(recorder.getTraceThread(mb.testThread1), traceManager.getCurrentThread()); + TraceThread thread1 = recorder.getTraceThread(mb.testThread1); + waitForPass(() -> assertEquals(thread1, traceManager.getCurrentThread())); TestTargetStack stack = mb.testThread1.addStack(); // Note, push simply moves the data, the new frame still has the higher index TestTargetStackFrameHasRegisterBank frame0 = stack.pushFrameHasBank(mb.addr(0x00400000)); TestTargetStackFrameHasRegisterBank frame1 = stack.pushFrameHasBank(mb.addr(0x00400100)); - waitForDomainObject(trace); + waitForPass(() -> { + TraceStack s = trace.getStackManager().getLatestStack(thread1, recorder.getSnap()); + assertNotNull(s); + assertEquals(2, s.getDepth()); + }); // Starting with 0 results in no change in coordinates, so ignored - mb.testModel.session.requestFocus(frame1) - .get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); - waitForSwing(); + waitOn(mb.testModel.session.requestFocus(frame1)); - assertEquals(1, traceManager.getCurrentFrame()); + waitForPass(() -> assertEquals(1, traceManager.getCurrentFrame())); - mb.testModel.session.requestFocus(frame0) - .get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); - waitForSwing(); + waitOn(mb.testModel.session.requestFocus(frame0)); - assertEquals(0, traceManager.getCurrentFrame()); + waitForPass(() -> assertEquals(0, traceManager.getCurrentFrame())); traceManager.setSynchronizeFocus(false); - mb.testModel.session.requestFocus(frame1) - .get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); - waitForSwing(); + waitOn(mb.testModel.session.requestFocus(frame1)); + // Not super reliable, but at least wait for it to change in case it does + Thread.sleep(200); assertEquals(0, traceManager.getCurrentFrame()); } diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/pcode/exec/TraceRecorderAsyncPcodeExecTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/pcode/exec/TraceRecorderAsyncPcodeExecTest.java index f2c6f13daa..89d0fe60e9 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/pcode/exec/TraceRecorderAsyncPcodeExecTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/pcode/exec/TraceRecorderAsyncPcodeExecTest.java @@ -15,7 +15,7 @@ */ package ghidra.pcode.exec; -import static org.junit.Assert.assertEquals; +import static org.junit.Assert.*; import java.math.BigInteger; import java.util.List; @@ -24,6 +24,7 @@ import java.util.Map; import org.junit.Test; import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest; +import ghidra.app.plugin.core.debug.mapping.DebuggerRegisterMapper; import ghidra.app.plugin.processors.sleigh.SleighLanguage; import ghidra.app.services.TraceRecorder; import ghidra.dbg.model.TestTargetRegisterBankInThread; @@ -45,9 +46,9 @@ public class TraceRecorderAsyncPcodeExecTest extends AbstractGhidraHeadedDebugge mb.testProcess1.regs.addRegistersFromLanguage(getToyBE64Language(), Register::isBaseRegister); TestTargetRegisterBankInThread regs = mb.testThread1.addRegisterBank(); - regs.writeRegistersNamed(Map.of( + waitOn(regs.writeRegistersNamed(Map.of( "r0", new byte[] { 5 }, - "r1", new byte[] { 6 })); + "r1", new byte[] { 6 }))); TraceRecorder recorder = modelService.recordTarget(mb.testProcess1, new TestDebuggerTargetTraceMapper(mb.testProcess1)); @@ -62,8 +63,17 @@ public class TraceRecorderAsyncPcodeExecTest extends AbstractGhidraHeadedDebugge AsyncPcodeExecutor executor = new AsyncPcodeExecutor<>(language, AsyncWrappedPcodeArithmetic.forLanguage(language), new TraceRecorderAsyncPcodeExecutorState(recorder, recorder.getSnap(), thread, 0)); - byte[] result = waitOn(expr.evaluate(executor)); + Register r0 = language.getRegister("r0"); + Register r1 = language.getRegister("r1"); + waitForPass(() -> { + DebuggerRegisterMapper rm = recorder.getRegisterMapper(thread); + assertNotNull(rm); + assertTrue(rm.getRegistersOnTarget().contains(r0)); + assertTrue(rm.getRegistersOnTarget().contains(r1)); + }); + + byte[] result = waitOn(expr.evaluate(executor)); assertEquals(11, Utils.bytesToLong(result, result.length, language.isBigEndian())); } @@ -75,9 +85,9 @@ public class TraceRecorderAsyncPcodeExecTest extends AbstractGhidraHeadedDebugge mb.testProcess1.regs.addRegistersFromLanguage(getToyBE64Language(), Register::isBaseRegister); TestTargetRegisterBankInThread regs = mb.testThread1.addRegisterBank(); - regs.writeRegistersNamed(Map.of( + waitOn(regs.writeRegistersNamed(Map.of( "r0", new byte[] { 5 }, - "r1", new byte[] { 6 })); + "r1", new byte[] { 6 }))); TraceRecorder recorder = modelService.recordTarget(mb.testProcess1, new TestDebuggerTargetTraceMapper(mb.testProcess1)); @@ -93,6 +103,16 @@ public class TraceRecorderAsyncPcodeExecTest extends AbstractGhidraHeadedDebugge new TraceRecorderAsyncPcodeExecutorState(recorder, recorder.getSnap(), thread, 0); AsyncPcodeExecutor executor = new AsyncPcodeExecutor<>( language, AsyncWrappedPcodeArithmetic.forLanguage(language), asyncState); + + Register r0 = language.getRegister("r0"); + Register r1 = language.getRegister("r1"); + waitForPass(() -> { + DebuggerRegisterMapper rm = recorder.getRegisterMapper(thread); + assertNotNull(rm); + assertTrue(rm.getRegistersOnTarget().contains(r0)); + assertTrue(rm.getRegistersOnTarget().contains(r1)); + }); + waitOn(executor.executeAsync(prog, SleighUseropLibrary.nil())); waitOn(asyncState.getVar(language.getRegister("r2"))); diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/util/DefaultTraceTimeViewport.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/util/DefaultTraceTimeViewport.java index 8a23e06dfb..d275240fc1 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/util/DefaultTraceTimeViewport.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/util/DefaultTraceTimeViewport.java @@ -22,6 +22,7 @@ import java.util.stream.Collectors; import com.google.common.collect.*; import ghidra.framework.model.DomainObjectClosedListener; +import ghidra.framework.model.DomainObjectException; import ghidra.program.model.address.*; import ghidra.trace.model.Trace; import ghidra.trace.model.Trace.TraceSnapshotChangeType; @@ -30,6 +31,7 @@ import ghidra.trace.model.program.TraceProgramView; import ghidra.trace.model.time.*; import ghidra.util.*; import ghidra.util.datastruct.ListenerSet; +import ghidra.util.exception.ClosedException; /** * Computes and tracks the "viewport" resulting from forking patterns encoded in snapshot schedules @@ -50,9 +52,26 @@ public class DefaultTraceTimeViewport implements TraceTimeViewport { protected class ForSnapshotsListener extends TraceDomainObjectListener implements DomainObjectClosedListener { { - listenFor(TraceSnapshotChangeType.ADDED, this::snapshotAdded); - listenFor(TraceSnapshotChangeType.CHANGED, this::snapshotChanged); - listenFor(TraceSnapshotChangeType.DELETED, this::snapshotDeleted); + listenFor(TraceSnapshotChangeType.ADDED, ignoringClosed(this::snapshotAdded)); + listenFor(TraceSnapshotChangeType.CHANGED, ignoringClosed(this::snapshotChanged)); + listenFor(TraceSnapshotChangeType.DELETED, ignoringClosed(this::snapshotDeleted)); + } + + private AffectedObjectOnlyHandler ignoringClosed( + AffectedObjectOnlyHandler handler) { + return snapshot -> { + try { + handler.handle(snapshot); + } + catch (DomainObjectException e) { + if (e.getCause() instanceof ClosedException) { + Msg.warn(this, "Ignoring ClosedException in trace viewport update"); + } + else { + throw e; + } + } + }; } private void snapshotAdded(TraceSnapshot snapshot) { diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/docking/widgets/table/RowWrappedEnumeratedColumnTableModel.java b/Ghidra/Debug/ProposedUtils/src/main/java/docking/widgets/table/RowWrappedEnumeratedColumnTableModel.java index 42359588fb..40d30b7630 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/docking/widgets/table/RowWrappedEnumeratedColumnTableModel.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/docking/widgets/table/RowWrappedEnumeratedColumnTableModel.java @@ -18,6 +18,7 @@ package docking.widgets.table; import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; +import java.util.stream.Stream; import docking.widgets.table.DefaultEnumeratedColumnTableModel.EnumeratedTableColumn; @@ -47,7 +48,7 @@ public class RowWrappedEnumeratedColumnTableModel & Enumerated return map.computeIfAbsent(keyFunc.apply(t), k -> wrapper.apply(t)); } - protected R delFor(T t) { + protected synchronized R delFor(T t) { return delKey(keyFunc.apply(t)); } @@ -55,20 +56,28 @@ public class RowWrappedEnumeratedColumnTableModel & Enumerated return map.remove(k); } + protected synchronized List rowsFor(Stream s) { + return s.map(this::rowFor).collect(Collectors.toList()); + } + protected synchronized List rowsFor(Collection c) { - return c.stream().map(this::rowFor).collect(Collectors.toList()); + return rowsFor(c.stream()); } public synchronized R getRow(T t) { return map.get(keyFunc.apply(t)); } - public void addItem(T t) { + public synchronized void addItem(T t) { + if (map.containsKey(keyFunc.apply(t))) { + return; + } add(rowFor(t)); } - public void addAllItems(Collection c) { - addAll(rowsFor(c)); + public synchronized void addAllItems(Collection c) { + Stream s = c.stream().filter(t -> !map.containsKey(keyFunc.apply(t))); + addAll(rowsFor(s)); } public void updateItem(T t) { diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/docking/widgets/timeline/TimelinePanel.java b/Ghidra/Debug/ProposedUtils/src/main/java/docking/widgets/timeline/TimelinePanel.java index 4855f19c48..26b3a0a1b8 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/docking/widgets/timeline/TimelinePanel.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/docking/widgets/timeline/TimelinePanel.java @@ -391,36 +391,44 @@ public class TimelinePanel> extends JPanel { private final List trackedItems = new ArrayList<>(); public List itemsInserted(int firstIndex, int lastIndex) { - List inserted = - new ArrayList<>(tableModel.getModelData().subList(firstIndex, lastIndex + 1)); - trackedItems.addAll(firstIndex, inserted); - assert Objects.equals(tableModel.getModelData(), trackedItems); - return inserted; + synchronized (tableModel) { + List inserted = + new ArrayList<>(tableModel.getModelData().subList(firstIndex, lastIndex + 1)); + trackedItems.addAll(firstIndex, inserted); + assert Objects.equals(tableModel.getModelData(), trackedItems); + return inserted; + } } public List itemsUpdated(int firstIndex, int lastIndex) { - List updated = new ArrayList<>(lastIndex - firstIndex + 1); - for (int i = firstIndex; i <= lastIndex; i++) { - T t = tableModel.getModelData().get(i); - updated.add(t); - trackedItems.set(i, t); + synchronized (tableModel) { + List updated = new ArrayList<>(lastIndex - firstIndex + 1); + for (int i = firstIndex; i <= lastIndex; i++) { + T t = tableModel.getModelData().get(i); + updated.add(t); + trackedItems.set(i, t); + } + assert Objects.equals(tableModel.getModelData(), trackedItems); + return updated; } - assert Objects.equals(tableModel.getModelData(), trackedItems); - return updated; } public List itemsDeleted(int firstIndex, int lastIndex) { - List sub = trackedItems.subList(firstIndex, lastIndex + 1); - List deleted = new ArrayList<>(sub); - sub.clear(); - assert Objects.equals(tableModel.getModelData(), trackedItems); - return deleted; + synchronized (tableModel) { + List sub = trackedItems.subList(firstIndex, lastIndex + 1); + List deleted = new ArrayList<>(sub); + sub.clear(); + assert Objects.equals(tableModel.getModelData(), trackedItems); + return deleted; + } } public List itemsRefreshed() { - trackedItems.clear(); - trackedItems.addAll(tableModel.getModelData()); - return trackedItems; + synchronized (tableModel) { + trackedItems.clear(); + trackedItems.addAll(tableModel.getModelData()); + return trackedItems; + } } public void clear() { @@ -462,12 +470,12 @@ public class TimelinePanel> extends JPanel { protected class CellFocusListener extends FocusAdapter { @Override public void focusGained(FocusEvent e) { - recolor(); // TODO: Way to draconian + focusGainedOrLost(); } @Override public void focusLost(FocusEvent e) { - recolor(); // TODO: Way to draconian + focusGainedOrLost(); } } @@ -499,6 +507,10 @@ public class TimelinePanel> extends JPanel { setSelectionModel(new DefaultListSelectionModel()); } + private synchronized void focusGainedOrLost() { + recolor(); // TODO: Way too draconian + } + public void addTimelineListener(TimelineListener listener) { timelineListeners.add(listener); } @@ -544,7 +556,7 @@ public class TimelinePanel> extends JPanel { } } - protected void assignTrack(T t) { + protected synchronized void assignTrack(T t) { Range range = info.getRange(t); for (TimelineTrack track : tracks) { if (track.fits(range)) { @@ -568,7 +580,7 @@ public class TimelinePanel> extends JPanel { } } - protected void adjustTrack(T t) { + protected synchronized void adjustTrack(T t) { Range range = info.getRange(t); TimelineTrack track = trackMap.get(t); track.remove(t); @@ -579,11 +591,11 @@ public class TimelinePanel> extends JPanel { assignTrack(t); } - protected Component getComponent(T key) { + protected synchronized Component getComponent(T key) { return trackMap.get(key).componentMap.get(key); } - protected void reAssignTracks() { + protected synchronized void reAssignTracks() { for (T t : rows.items()) { // Prefer to move earlier rows to the top tracks TimelineTrack fromTrack = trackMap.get(t); for (TimelineTrack toTrack : tracks) { @@ -623,10 +635,11 @@ public class TimelinePanel> extends JPanel { reAssignTracks(); } - private void tableChanged(TableModelEvent e) { + private synchronized void tableChanged(TableModelEvent e) { switch (e.getType()) { case TableModelEvent.INSERT: - assignTracks(rows.itemsInserted(e.getFirstRow(), e.getLastRow())); + List itemsInserted = rows.itemsInserted(e.getFirstRow(), e.getLastRow()); + assignTracks(itemsInserted); reSortTracks(); fitView(); recolor(); @@ -640,7 +653,8 @@ public class TimelinePanel> extends JPanel { else { int column = e.getColumn(); if (info.columnAffectsBounds(column)) { - adjustTracks(rows.itemsUpdated(e.getFirstRow(), e.getLastRow())); + List itemsUpdated = rows.itemsUpdated(e.getFirstRow(), e.getLastRow()); + adjustTracks(itemsUpdated); reSortTracks(); fitView(); recolor(); @@ -648,7 +662,8 @@ public class TimelinePanel> extends JPanel { } break; case TableModelEvent.DELETE: - cleanTracks(rows.itemsDeleted(e.getFirstRow(), e.getLastRow())); + List itemsDeleted = rows.itemsDeleted(e.getFirstRow(), e.getLastRow()); + cleanTracks(itemsDeleted); reSortTracks(); fitView(); recolor(); @@ -717,14 +732,14 @@ public class TimelinePanel> extends JPanel { recolor(); } - protected void clear() { + protected synchronized void clear() { this.rows.clear(); this.tracks.clear(); this.trackMap.clear(); this.removeAll(); } - protected void reload() { + protected synchronized void reload() { clear(); if (tableModel == null) { return; @@ -733,7 +748,7 @@ public class TimelinePanel> extends JPanel { recolor(); } - protected void recolor() { + protected synchronized void recolor() { //dumpkeys(Border.class, Border::toString); List items = rows.items(); for (int i = 0; i < items.size(); i++) { @@ -814,7 +829,7 @@ public class TimelinePanel> extends JPanel { * @param t the item * @return the rectangle, or {@code null} if the given item is not present */ - public Rectangle getCellBounds(T t) { + public synchronized Rectangle getCellBounds(T t) { TimelineTrack track = trackMap.get(t); if (track == null) { return null; diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/mgr/EventManager.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/mgr/EventManager.java index c4b53e9c1e..00e5769685 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/mgr/EventManager.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/mgr/EventManager.java @@ -28,8 +28,8 @@ import ghidra.util.Msg; import ghidra.util.Swing; /** - * Helper class to manage the events that plugins consume and produce. This class keeps - * track of the last events that went out so that when a plugin is added, it receives those events. + * Helper class to manage the events that plugins consume and produce. This class keeps track of the + * last events that went out so that when a plugin is added, it receives those events. */ public class EventManager { private List toolListeners = new ArrayList<>(); @@ -51,6 +51,7 @@ public class EventManager { /** * Construct a new EventManager. + * * @param tool plugin tool associated with this EventManager */ public EventManager(PluginTool tool) { @@ -58,8 +59,9 @@ public class EventManager { } /** - * Add a plugin event listener that will be notified when an event of - * the given event class is generated. + * Add a plugin event listener that will be notified when an event of the given event class is + * generated. + * * @param eventClass class of the event of interest * @param listener listener to notify */ @@ -84,8 +86,9 @@ public class EventManager { } /** - * Remove the plugin event listener from the list of listeners notified - * when an event of the given event class is generated. + * Remove the plugin event listener from the list of listeners notified when an event of the + * given event class is generated. + * * @param eventClass class of the event of interest * @param listener listener to remove */ @@ -112,6 +115,7 @@ public class EventManager { /** * Add the given tool listener to be notified notified when tool events are generated + * * @param listener listener to add */ public void addToolListener(ToolListener listener) { @@ -120,6 +124,7 @@ public class EventManager { /** * Remove the given tool listener from the list of tool listeners + * * @param listener listener to remove */ public void removeToolListener(ToolListener listener) { @@ -127,7 +132,7 @@ public class EventManager { } /** - * Return whether there are any registered tool listeners for the tool associated with class + * Return whether there are any registered tool listeners for the tool associated with class * * @return true if there are any listeners */ @@ -137,6 +142,7 @@ public class EventManager { /** * Add the class for the PluginEvent that a plugin will produce + * * @param eventClass class for the PluginEvent */ public void addEventProducer(Class eventClass) { @@ -149,6 +155,7 @@ public class EventManager { /** * Remove the class of a PluginEvent that a plugin produces. + * * @param eventClass class for the PluginEvent */ public void removeEventProducer(Class eventClass) { @@ -165,6 +172,7 @@ public class EventManager { /** * Get the names of all events produced by plugins in the tool. + * * @return array of PluginEvent names */ public String[] getEventsProduced() { @@ -173,6 +181,7 @@ public class EventManager { /** * Get the names of all events consumed by plugins in the tool. + * * @return array of PluginEvent names */ public String[] getEventsConsumed() { @@ -180,8 +189,9 @@ public class EventManager { } /** - * Notify all plugin listeners that are registered to consume the given - * event. Events are fired in the SwingThread. + * Notify all plugin listeners that are registered to consume the given event. Events are fired + * in the SwingThread. + * * @param event event to fire */ public void fireEvent(PluginEvent event) { @@ -218,8 +228,9 @@ public class EventManager { } /** - * Convert the given tool event to a plugin event; notify the appropriate plugin listeners. - * This method allows one tool's event manager to send events to another connected tool. + * Convert the given tool event to a plugin event; notify the appropriate plugin listeners. This + * method allows one tool's event manager to send events to another connected tool. + * * @param event tool event */ public void processToolEvent(PluginEvent event) { @@ -249,7 +260,7 @@ public class EventManager { } /** - * Return an array of the last plugin events fired. EventManager maps the event class to the + * Return an array of the last plugin events fired. EventManager maps the event class to the * last event fired. * * @return array of plugin events @@ -326,8 +337,9 @@ public class EventManager { } /** - * Remove the event listener by className; the plugin registered for - * events, but the construction failed. + * Remove the event listener by className; the plugin registered for events, but the + * construction failed. + * * @param className class name of the plugin (event listener) */ public void removeEventListener(String className) {