From 2e5d98f478357087ce5fb4308b0fe4e623824abc Mon Sep 17 00:00:00 2001 From: ghidra_red Date: Tue, 23 Jun 2026 16:55:54 +0000 Subject: [PATCH] GP-6990: Add docs for BreakpointTimelinePlugin --- Ghidra/Debug/Debugger/certification.manifest | 4 + .../src/main/help/help/TOC_Source.xml | 4 + .../BreakpointTimelinePlugin.html | 216 +++++++++++++++++ .../images/BreakpointTimelinePlugin.png | Bin 0 -> 6678 bytes .../images/BreakpointTimelinePluginNoGrid.png | Bin 0 -> 6414 bytes .../BreakpointTimelinePluginSingleColumn.png | Bin 0 -> 4234 bytes .../DebuggerListingPlugin.html | 2 +- .../timeline/BreakpointTimelineActions.java | 68 +++--- .../timeline/BreakpointTimelinePlugin.java | 2 + .../timeline/BreakpointTimelineProvider.java | 27 ++- .../BreakpointTimelinePluginScreenShots.java | 219 ++++++++++++++++++ 11 files changed, 496 insertions(+), 46 deletions(-) create mode 100644 Ghidra/Debug/Debugger/src/main/help/help/topics/BreakpointTimelinePlugin/BreakpointTimelinePlugin.html create mode 100644 Ghidra/Debug/Debugger/src/main/help/help/topics/BreakpointTimelinePlugin/images/BreakpointTimelinePlugin.png create mode 100644 Ghidra/Debug/Debugger/src/main/help/help/topics/BreakpointTimelinePlugin/images/BreakpointTimelinePluginNoGrid.png create mode 100644 Ghidra/Debug/Debugger/src/main/help/help/topics/BreakpointTimelinePlugin/images/BreakpointTimelinePluginSingleColumn.png create mode 100644 Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/breakpoint/timeline/BreakpointTimelinePluginScreenShots.java diff --git a/Ghidra/Debug/Debugger/certification.manifest b/Ghidra/Debug/Debugger/certification.manifest index 96169f2e80..f92184a6a1 100644 --- a/Ghidra/Debug/Debugger/certification.manifest +++ b/Ghidra/Debug/Debugger/certification.manifest @@ -9,6 +9,10 @@ README.md||GHIDRA||||END| data/ExtensionPoint.manifest||GHIDRA||||END| data/debugger.theme.properties||GHIDRA||||END| src/main/help/help/TOC_Source.xml||GHIDRA||||END| +src/main/help/help/topics/BreakpointTimelinePlugin/BreakpointTimelinePlugin.html||GHIDRA||||END| +src/main/help/help/topics/BreakpointTimelinePlugin/images/BreakpointTimelinePlugin.png||GHIDRA||||END| +src/main/help/help/topics/BreakpointTimelinePlugin/images/BreakpointTimelinePluginNoGrid.png||GHIDRA||||END| +src/main/help/help/topics/BreakpointTimelinePlugin/images/BreakpointTimelinePluginSingleColumn.png||GHIDRA||||END| src/main/help/help/topics/Debugger/Debugger.html||GHIDRA||||END| src/main/help/help/topics/Debugger/GettingStarted.html||GHIDRA||||END| src/main/help/help/topics/Debugger/Troubleshooting.html||GHIDRA||||END| diff --git a/Ghidra/Debug/Debugger/src/main/help/help/TOC_Source.xml b/Ghidra/Debug/Debugger/src/main/help/help/TOC_Source.xml index 3b751e1cf5..ff425d4024 100644 --- a/Ghidra/Debug/Debugger/src/main/help/help/TOC_Source.xml +++ b/Ghidra/Debug/Debugger/src/main/help/help/TOC_Source.xml @@ -72,6 +72,10 @@ text="In the Listings" sortgroup="a" target="help/topics/DebuggerBreakpointMarkerPlugin/DebuggerBreakpointMarkerPlugin.html" /> + + + + + + + + Debugger: Breakpoint Timeline + + + + + +

Debugger: Breakpoint Timeline

+ +
+ +
+ +

The Breakpoint Timeline window provides a visual overview of all snapshots in the current + trace, highlighting snapshots where breakpoints were hit. Each cell in the grid represents one + or more consecutive snapshots. Cells are ordered left to right, top to bottom starting from the + lowest snapshot to the highest. Cells are colored according to the type of breakpoint hit + recorded in those snapshots. Clicking a cell navigates to the earliest hit or snapshot in the + cell. A click and drag across cells opens another Timeline window zoomed on the selected + snapshot range.

+ +

Breakpoint hits are detected by examining the trace's recorded data. For execution + breakpoints (hardware or software), the plugin searches for stack frames whose program counter + falls within the breakpoint's address range. For memory read and write breakpoints, it searches + for trace memory references to the breakpoint's address range with the corresponding reference + type. The plugin listens for changes to breakpoints and snapshots and updates the display + automatically. NOTE: R/W breakpoints are only supported for connectors and/or importers + that record memory references to the trace. At this time, that includes only the TENET and + TENET++ loaders.

+ +

The timeline panel fills the window with a grid of cells. Each cell covers a contiguous + range of snapshots. The number of snapshots per cell is determined automatically so that all + snapshots from 0 to the maximum snapshot (or from the start to the stop snapshot of a zoomed + window) fit within the visible area.

+ +

Cell Colors

+ +

Each cell is filled with a color indicating the breakpoint activity in its snapshot + range:

+ + + +

In addition, three overlay colors indicate interactive state:

+ + + +

Tooltips

+ +

Hovering over a cell shows a tooltip with:

+ + + +

Navigation and Interaction

+ +

Click to Navigate

+ +

Clicking a cell activates the snapshot associated with the first breakpoint hit event in + that cell. If the cell contains no breakpoint hit, the first snapshot in the cell's range is + activated.

+ +

Click and Drag to Zoom

+ +

Clicking and dragging across a range of cells opens a new zoom window focused on the + snapshot range covered by the drag selection. The zoom window is a separate Breakpoint + Timeline provider showing only the selected sub-range. Zoom windows are trace specific and + are hidden when a different trace is activated and restored when the original trace is + reactivated.

+ +

Mouse Wheel

+ +

Scrolling the mouse wheel over the timeline panel activates the next (wheel down) or + previous (wheel up) snapshot.

+ +

Toolbar Actions

+ +

+ Toggle between Grid and + Single Column

+ +
+ +
+ +

Switches the layout between a 2D grid and a single vertical column. In column mode, each + cell occupies the full width of the panel and cells are stacked vertically from top (earliest + snapshot) to bottom (latest snapshot).

+ +

Toggle Grid Outline

+ +
+ +
+ +

Shows or hides the border drawn around each cell. When the grid outline is enabled, cell + boundaries are drawn in the disabled foreground color.

+ +

Zoom In + (Increase Cell Size)

+ +

Increases the default cell size by one pixel in each dimension. The grid is recalculated + after each step.

+ +

Zoom + Out (Decrease Cell Size)

+ +

Decreases the default cell size by one pixel in each dimension, down to a minimum of one + pixel.

+ +

Set Default Cell Size to the Smallest

+ +

Sets the default cell size to the minimum (one pixel).

+ +

Close All Zoom Windows

+ +

Closes all zoom sub-windows that were created for the current trace. This action has no + effect on the main Breakpoint Timeline window itself.

+ +

Context Menu Actions

+ +

The Breakpoint Timeline plugin adds context menu actions to the following views: the Static Listing, the Dynamic Listing, the Registers window, + and the Byte + Viewer. These actions search the current trace for breakpoint hits at the address or + address range selected in the active view and navigate to or list the matching snapshots.

+ +

The address range used for the search is determined from the current selection in the active + view. If there is no selection, the single address at the cursor is used.

+ +

Actions are organized into two top-level menu groups:

+ +

Go to...

+ +

These actions navigate to a single snapshot. They appear as submenus under Go to..., + grouped by search direction:

+ + + +

Each submenu contains one entry per breakpoint type:

+ + + +

Show All...

+ +

These actions open a table window listing every snapshot in the trace where the selected + address was hit, for the chosen breakpoint type. The table has two columns: Snap (the + snapshot number) and Address (the PC when the hit occurred). Double-clicking a row in + the table navigates to that snapshot. The same four breakpoint type entries (Execution, Memory + Read, Memory Write, Memory Access) are used for this action.

+ + diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/BreakpointTimelinePlugin/images/BreakpointTimelinePlugin.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/BreakpointTimelinePlugin/images/BreakpointTimelinePlugin.png new file mode 100644 index 0000000000000000000000000000000000000000..bbe053a25d37f7bebb5242001a44f97159e3d4f6 GIT binary patch literal 6678 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 literal 0 HcmV?d00001 diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/BreakpointTimelinePlugin/images/BreakpointTimelinePluginSingleColumn.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/BreakpointTimelinePlugin/images/BreakpointTimelinePluginSingleColumn.png new file mode 100644 index 0000000000000000000000000000000000000000..0d4f3129d3e346673401804850335232f35f70a3 GIT binary patch literal 4234 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 literal 0 HcmV?d00001 diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerListingPlugin/DebuggerListingPlugin.html b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerListingPlugin/DebuggerListingPlugin.html index 842597dcd8..41ab8e0c50 100644 --- a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerListingPlugin/DebuggerListingPlugin.html +++ b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerListingPlugin/DebuggerListingPlugin.html @@ -191,7 +191,7 @@ debugger. This failure can be overcome by enabling Force Full View.

-

Some examples (in Hex mode):

+

Some examples (in Hex mode):

  • 00401234 — A constant address
  • diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/timeline/BreakpointTimelineActions.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/timeline/BreakpointTimelineActions.java index 7a6a2333d8..d8eef4fb18 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/timeline/BreakpointTimelineActions.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/timeline/BreakpointTimelineActions.java @@ -31,14 +31,14 @@ import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingActionContext; import ghidra.app.plugin.core.debug.gui.register.DebuggerRegisterActionContext; import ghidra.app.services.DebuggerStaticMappingService; import ghidra.app.services.DebuggerTraceManagerService; +import ghidra.debug.api.modules.MappedAddressRange; import ghidra.framework.plugintool.PluginTool; import ghidra.program.model.address.*; -import ghidra.program.util.ProgramLocation; -import ghidra.trace.model.Lifespan; -import ghidra.trace.model.Trace; +import ghidra.trace.model.*; import ghidra.trace.model.stack.TraceStackFrame; import ghidra.trace.model.symbol.TraceReference; import ghidra.trace.model.target.TraceObjectValue; +import ghidra.util.HelpLocation; import ghidra.util.Msg; public class BreakpointTimelineActions { @@ -145,11 +145,13 @@ public class BreakpointTimelineActions { new String[] { "Go to...", searchType.menuGroup, breakType.menuName }, null, BreakpointTimelineActions.this.name)); + setHelpLocation(new HelpLocation("BreakpointTimelinePlugin", "goto_actions")); } else { setPopupMenuData( new MenuData(new String[] { searchType.menuGroup, breakType.menuName }, null, BreakpointTimelineActions.this.name)); + setHelpLocation(new HelpLocation("BreakpointTimelinePlugin", "show_all_actions")); } } @@ -282,52 +284,39 @@ public class BreakpointTimelineActions { } private AddressSet getAddressRangeFromCodeViewerActionContext(CodeViewerActionContext c) { - final Trace trace = - tool.getService(DebuggerTraceManagerService.class).getCurrentTrace(); final DebuggerStaticMappingService staticMappingService = tool.getService(DebuggerStaticMappingService.class); final AddressSet dynamicSet = new AddressSet(); - String noMapping = "No mapping"; - String noMappingFormat = "No mapping for %s @ 0x%x"; + List addressRanges = new ArrayList<>(); if (c.getSelection().isEmpty()) { - final ProgramLocation dynamicLocation = - staticMappingService.getDynamicLocationFromStatic(trace.getProgramView(), - new ProgramLocation(c.getProgram(), c.getAddress())); - if (dynamicLocation == null) { - Msg.showInfo(null, null, noMapping, - noMappingFormat.formatted(c.getProgram(), c.getAddress().getOffset())); - } - else { - dynamicSet.add(dynamicLocation.getAddress()); - } + addressRanges.add(new AddressRangeImpl(c.getAddress(), c.getAddress())); } else { - for (final AddressRange range : c.getSelection().getAddressRanges()) { - final ProgramLocation startDynamicLocation = - staticMappingService.getDynamicLocationFromStatic( - trace.getProgramView(), - new ProgramLocation(c.getProgram(), range.getMinAddress())); - if (startDynamicLocation == null) { - Msg.showInfo(null, null, noMapping, - noMappingFormat.formatted(c.getProgram(), - range.getMinAddress().getOffset())); + c.getSelection().getAddressRanges().forEachRemaining(addressRanges::add); + } + + for (final AddressRange range : addressRanges) { + Map> openMappedViews = + staticMappingService.getOpenMappedViews(c.getProgram(), + new AddressSet(range)); + for (Map.Entry> entry : + openMappedViews.entrySet()) { + if (entry.getKey().getTrace() != currentTrace) { continue; } - final ProgramLocation endDynamicLocation = - staticMappingService.getDynamicLocationFromStatic( - trace.getProgramView(), - new ProgramLocation(c.getProgram(), range.getMaxAddress())); - if (endDynamicLocation == null) { - Msg.showInfo(null, null, noMapping, - noMappingFormat.formatted(c.getProgram(), - range.getMaxAddress().getOffset())); - continue; + for (MappedAddressRange addressRange : entry.getValue()) { + dynamicSet.add(addressRange.getDestinationAddressRange().getMinAddress(), + addressRange.getDestinationAddressRange().getMaxAddress()); } - dynamicSet.add(startDynamicLocation.getAddress(), - endDynamicLocation.getAddress()); } } + + if (dynamicSet.isEmpty()) { + Msg.showInfo(null, null, "No mapping", + "No mapping for %s @ 0x%x".formatted(c.getProgram(), + c.getAddress().getOffset())); + } return dynamicSet; } @@ -380,6 +369,7 @@ public class BreakpointTimelineActions { private final PluginTool tool; String name = this.getClass().getSimpleName(); List actions; + private Trace currentTrace; BreakpointTimelineActions(PluginTool tool) { this.tool = tool; @@ -397,4 +387,8 @@ public class BreakpointTimelineActions { tool.removeAction(action); } } + + public void setTrace(Trace t) { + currentTrace = t; + } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/timeline/BreakpointTimelinePlugin.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/timeline/BreakpointTimelinePlugin.java index 4e0654a9d2..fde5447f44 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/timeline/BreakpointTimelinePlugin.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/timeline/BreakpointTimelinePlugin.java @@ -93,6 +93,7 @@ public class BreakpointTimelinePlugin extends AbstractDebuggerPlugin { if (currentTrace == t) { currentTrace = null; provider.setTrace(null); + actions.setTrace(null); } removeZoomProviders(t); } @@ -110,6 +111,7 @@ public class BreakpointTimelinePlugin extends AbstractDebuggerPlugin { else { refreshAllProviders(null); } + actions.setTrace(t); } default -> { } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/timeline/BreakpointTimelineProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/timeline/BreakpointTimelineProvider.java index 1193568997..ebc1c31f14 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/timeline/BreakpointTimelineProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/timeline/BreakpointTimelineProvider.java @@ -15,11 +15,10 @@ */ package ghidra.app.plugin.core.debug.gui.breakpoint.timeline; -import java.awt.BorderLayout; +import javax.swing.*; +import java.awt.*; import java.util.*; - -import javax.swing.JComponent; -import javax.swing.JPanel; +import java.util.List; import docking.ActionContext; import docking.ComponentProvider; @@ -37,6 +36,7 @@ import ghidra.trace.model.stack.TraceStackFrame; import ghidra.trace.model.symbol.TraceReference; import ghidra.trace.model.target.TraceObjectValue; import ghidra.trace.util.TraceEvents; +import ghidra.util.HelpLocation; public class BreakpointTimelineProvider extends ComponentProvider { record BreakpointHitEvent(long snap, TraceBreakpointKind breakType, String breakpointName) {} @@ -78,6 +78,7 @@ public class BreakpointTimelineProvider extends ComponentProvider { super("Close all zoom windows", provider.getOwner()); setEnabled(true); setToolBarData(new ToolBarData(ICON, "1")); + setHelpLocation(new HelpLocation("BreakpointTimelinePlugin", "close_zoom_windows")); } @Override @@ -93,6 +94,7 @@ public class BreakpointTimelineProvider extends ComponentProvider { super("Set default cell size to the smallest", provider.getOwner()); setEnabled(true); setToolBarData(new ToolBarData(ICON, "zoom")); + setHelpLocation(new HelpLocation("BreakpointTimelinePlugin", "smallest_cell")); } @Override @@ -111,6 +113,7 @@ public class BreakpointTimelineProvider extends ComponentProvider { super("Toggle Grid Outline", provider.getOwner()); setEnabled(true); setToolBarData(new ToolBarData(OUTLINE_ICON, "2")); + setHelpLocation(new HelpLocation("BreakpointTimelinePlugin", "toggle_grid_outline")); } @Override @@ -119,7 +122,6 @@ public class BreakpointTimelineProvider extends ComponentProvider { getToolBarData().setIcon(grid ? OUTLINE_ICON : NO_OUTLINE_ICON); breakpointTimelinePanel.toggleGridOutline(); breakpointTimelinePlugin.refreshAllProviders(BreakpointTimelineProvider.this); - } } @@ -133,6 +135,7 @@ public class BreakpointTimelineProvider extends ComponentProvider { super("Toggle between grid and single column", provider.getOwner()); setEnabled(true); setToolBarData(new ToolBarData(GRID_ICON, "2")); + setHelpLocation(new HelpLocation("BreakpointTimelinePlugin", "toggle_grid_column")); } @Override @@ -151,6 +154,7 @@ public class BreakpointTimelineProvider extends ComponentProvider { super("Increase cell size", provider.getOwner()); setEnabled(true); setToolBarData(new ToolBarData(ICON, "zoom")); + setHelpLocation(new HelpLocation("BreakpointTimelinePlugin", "zoom_in")); } @Override @@ -166,6 +170,7 @@ public class BreakpointTimelineProvider extends ComponentProvider { super("Decrease cell size", provider.getOwner()); setEnabled(true); setToolBarData(new ToolBarData(ICON, "zoom")); + setHelpLocation(new HelpLocation("BreakpointTimelinePlugin", "zoom_out")); } @Override @@ -174,6 +179,9 @@ public class BreakpointTimelineProvider extends ComponentProvider { } } + ToggleGridOrColumnAction toggleGridOrColumnAction; + ToggleGridAction toggleGridAction; + @Internal public static Iterator getTraceObjectValuesWithPCsIntersectingRange( Trace trace, AddressRange range) { @@ -208,6 +216,7 @@ public class BreakpointTimelineProvider extends ComponentProvider { boolean makeTransient) { super(breakpointTimelinePlugin.getTool(), "Breakpoint Timeline", breakpointTimelinePlugin.getName()); + setHelpLocation(new HelpLocation("BreakpointTimelinePlugin", "plugin")); this.breakpointTimelinePlugin = breakpointTimelinePlugin; wrapperPanel = new JPanel(new BorderLayout()); breakpointTimelinePanel = new BreakpointTimelinePanel(this); @@ -234,8 +243,10 @@ public class BreakpointTimelineProvider extends ComponentProvider { } private void createActions() { - dockingTool.addLocalAction(this, new ToggleGridOrColumnAction(this)); - dockingTool.addLocalAction(this, new ToggleGridAction(this)); + toggleGridOrColumnAction = new ToggleGridOrColumnAction(this); + dockingTool.addLocalAction(this, toggleGridOrColumnAction); + toggleGridAction = new ToggleGridAction(this); + dockingTool.addLocalAction(this, toggleGridAction); dockingTool.addLocalAction(this, new ZoomInAction(this)); dockingTool.addLocalAction(this, new ZoomOutAction(this)); dockingTool.addLocalAction(this, new CloseAllZoomWindowsAction(this)); @@ -301,7 +312,7 @@ public class BreakpointTimelineProvider extends ComponentProvider { breakpointTimelinePanel.refresh(); } - private void refreshBreakpointHits() { + /*testing*/ void refreshBreakpointHits() { breakpointHits.clear(); if (currentTrace == null) { diff --git a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/breakpoint/timeline/BreakpointTimelinePluginScreenShots.java b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/breakpoint/timeline/BreakpointTimelinePluginScreenShots.java new file mode 100644 index 0000000000..1c4fa9d8b2 --- /dev/null +++ b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/breakpoint/timeline/BreakpointTimelinePluginScreenShots.java @@ -0,0 +1,219 @@ +/* ### + * 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.app.plugin.core.debug.gui.breakpoint.timeline; + +import java.io.IOException; +import java.util.*; +import java.util.concurrent.TimeUnit; + +import db.Transaction; +import generic.test.category.NightlyCategory; +import ghidra.app.plugin.core.debug.service.emulation.ProgramEmulationUtils; +import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingServicePlugin; +import ghidra.app.plugin.core.debug.service.tracemgr.DebuggerTraceManagerServicePlugin; +import ghidra.app.plugin.core.progmgr.ProgramManagerPlugin; +import ghidra.async.AsyncTestUtils; +import ghidra.framework.model.DomainFolder; +import ghidra.framework.model.DomainObject; +import ghidra.program.model.address.Address; +import ghidra.program.model.listing.Program; +import ghidra.program.model.symbol.RefType; +import ghidra.program.model.symbol.SourceType; +import ghidra.test.ToyProgramBuilder; +import ghidra.trace.database.ToyDBTraceBuilder; +import ghidra.trace.database.breakpoint.DBTraceBreakpointManager; +import ghidra.trace.model.Lifespan; +import ghidra.trace.model.breakpoint.TraceBreakpointKind; +import ghidra.trace.model.stack.TraceStack; +import ghidra.trace.model.stack.TraceStackFrame; +import ghidra.trace.model.target.TraceObject; +import ghidra.trace.model.target.path.KeyPath; +import ghidra.trace.model.thread.TraceThread; +import ghidra.trace.model.time.TraceSnapshot; +import ghidra.util.InvalidNameException; +import ghidra.util.exception.CancelledException; +import ghidra.util.task.ConsoleTaskMonitor; +import ghidra.util.task.TaskMonitor; +import help.screenshot.GhidraScreenShotGenerator; +import org.junit.*; +import org.junit.experimental.categories.Category; + +@Category(NightlyCategory.class) // this may actually be an @PortSensitive test +public class BreakpointTimelinePluginScreenShots extends GhidraScreenShotGenerator + implements AsyncTestUtils { + + private static final TaskMonitor MONITOR = new ConsoleTaskMonitor(); + ToyDBTraceBuilder tb; + Program progHw; + Program progLibc; + private ProgramManagerPlugin programManager; + private DebuggerTraceManagerServicePlugin traceManager; + private BreakpointTimelineProvider provider; + private DebuggerStaticMappingServicePlugin mappingService; + + @Before + public void setUpMine() throws Exception { + programManager = addPlugin(tool, ProgramManagerPlugin.class); + traceManager = addPlugin(tool, DebuggerTraceManagerServicePlugin.class); + mappingService = addPlugin(tool, DebuggerStaticMappingServicePlugin.class); + + addPlugin(tool, BreakpointTimelinePlugin.class); + + tb = new ToyDBTraceBuilder("toy", ToyProgramBuilder._X64); + provider = waitForComponentProvider(BreakpointTimelineProvider.class); + + populateTraceAndPrograms(); + } + + private void populateTraceAndPrograms() throws Exception { + ToyProgramBuilder helloworld_builder = new ToyProgramBuilder("helloworld", false, this); + helloworld_builder.createMemory(".text", "0x00400000", 0x2000); + helloworld_builder.createLabel("0x00401234", "main"); + helloworld_builder.createFunction("0x00401234"); + progHw = helloworld_builder.getProgram(); + + ToyProgramBuilder libc_builder = new ToyProgramBuilder("libc", false, this); + libc_builder.createMemory(".text", "0x7fff0000", 0x2000); + libc_builder.createLabel("0x7fff0110", "puts"); + libc_builder.createFunction("0x7fff0110"); + progLibc = libc_builder.getProgram(); + + intoProject(progHw); + intoProject(progLibc); + intoProject(tb.trace); + programManager.openProgram(progLibc); + programManager.openProgram(progHw); + traceManager.openTrace(tb.trace); + mappingService.changesSettled().get(1, TimeUnit.SECONDS); + + try (Transaction tx = tb.startTransaction()) { + tb.trace.getObjectManager().createRootObject(ProgramEmulationUtils.EMU_SESSION_SCHEMA); + + tb.trace.getModuleManager() + .addLoadedModule("Modules[helloword]", "helloworld", + tb.range(0x00400000, 0x00402000), 0); + tb.trace.getModuleManager() + .addLoadedModule("Modules[libc]", "libc", tb.range(0x7fff0000, 0x7fff2000), 0); + + mappingService.addIdentityMapping(tb.trace, progHw, Lifespan.nowOn(0), true); + mappingService.addIdentityMapping(tb.trace, progLibc, Lifespan.nowOn(0), true); + + TraceThread thread = tb.getOrAddThread("Threads[1]", 0); + tb.trace.getObjectManager() + .createObject(KeyPath.parse("Threads[1].Registers")) + .insert(Lifespan.nowOn(0), TraceObject.ConflictResolution.DENY); + thread.setName(0, "1 main"); + + List
    pcs = + Arrays.asList(tb.addr(0x00401234), tb.addr(0x7fff0110), tb.addr(0x7fff0113), + tb.addr(0x7fff0115)); + List
    memRefs = + Arrays.asList(tb.addr(0x11111), tb.addr(0x22222), tb.addr(0x33333), null, null, + null, null); + List refTypes = List.of(RefType.READ, RefType.WRITE); + Random rand = new Random(1337); + + for (int i = 0; i < 200; i++) { + addSnap(thread, pcs.get(rand.nextInt(pcs.size())), i, + memRefs.get(rand.nextInt(memRefs.size())), + refTypes.get(rand.nextInt(refTypes.size()))); + + } + + DBTraceBreakpointManager bm = tb.trace.getBreakpointManager(); + bm.placeBreakpoint("Breakpoints[1]", 0, tb.addr(0x00401234), List.of(), + TraceBreakpointKind.CommonSet.SWX.kinds(), true, ""); + bm.placeBreakpoint("Breakpoints[2]", 0, tb.addr(0x11111), List.of(), + TraceBreakpointKind.CommonSet.READ.kinds(), true, ""); + bm.placeBreakpoint("Breakpoints[3]", 0, tb.addr(0x22222), List.of(), + TraceBreakpointKind.CommonSet.WRITE.kinds(), true, ""); + } + + mappingService.changesSettled().get(1, TimeUnit.SECONDS); + + traceManager.activateTrace(tb.trace); + traceManager.activateSnap(0); + } + + protected void intoProject(DomainObject obj) { + waitForDomainObject(obj); + DomainFolder rootFolder = tool.getProject().getProjectData().getRootFolder(); + waitForCondition(() -> { + try { + rootFolder.createFile(obj.getName(), obj, MONITOR); + return true; + } + catch (InvalidNameException | CancelledException e) { + throw new AssertionError(e); + } + catch (IOException e) { + // Usually "object is busy". Try again. + return false; + } + }); + } + + private void addSnap(TraceThread thread, Address address, int num, Address memRef, + RefType refType) { + TraceSnapshot snap = tb.trace.getTimeManager().createSnapshot(Integer.toString(num)); + snap.setEventThread(thread); + TraceStack latestStack = tb.trace.getStackManager().getStack(thread, snap.getKey(), true); + TraceStackFrame frame = latestStack.getFrame(0, 0, true); + frame.setProgramCounter(Lifespan.nowOn(snap.getKey()), address); + + if (memRef != null) { + tb.trace.getReferenceManager() + .addMemoryReference(Lifespan.at(snap.getKey()), address, memRef, refType, + SourceType.ANALYSIS, 0); + } + } + + public static void waitForDomainObject(DomainObject object) { + object.flushEvents(); + waitForSwing(); + } + + @After + public void tearDownMine() { + tb.close(); + + if (progHw != null) { + progHw.release(this); + progHw = null; + } + if (progLibc != null) { + progLibc.release(this); + progLibc = null; + } + } + + @Test + public void testCaptureBreakpointTimelinePluginSingleColumn() { + performAction(provider.toggleGridOrColumnAction, true); + captureIsolatedProvider(provider, 300, 300); + } + + @Test + public void testCaptureBreakpointTimelinePlugin() { + captureIsolatedProvider(provider, 300, 300); + } + + @Test + public void testCaptureBreakpointTimelinePluginNoGrid() { + performAction(provider.toggleGridAction, true); + captureIsolatedProvider(provider, 300, 300); + } +}