mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-08-08 07:40:39 -09:00
Merge remote-tracking branch 'origin/GP-6990_ghidra_red_BreakpointTimelineDocs--SQUASHED'
This commit is contained in:
@@ -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|
|
||||
|
||||
@@ -72,6 +72,10 @@
|
||||
text="In the Listings"
|
||||
sortgroup="a"
|
||||
target="help/topics/DebuggerBreakpointMarkerPlugin/DebuggerBreakpointMarkerPlugin.html" />
|
||||
|
||||
<tocdef id="BreakpointTimelinePlugin" text="Breakpoint Timeline"
|
||||
sortgroup="b"
|
||||
target="help/topics/BreakpointTimelinePlugin/BreakpointTimelinePlugin.html" />
|
||||
</tocdef>
|
||||
|
||||
<tocdef id="DebuggerRegionsPlugin" text="Memory Regions"
|
||||
|
||||
@@ -0,0 +1,216 @@
|
||||
<!DOCTYPE doctype PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN">
|
||||
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META name="generator" content=
|
||||
"HTML Tidy for Java (vers. 2009-12-01), see jtidy.sourceforge.net">
|
||||
|
||||
<TITLE>Debugger: Breakpoint Timeline</TITLE>
|
||||
<META http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||
<LINK rel="stylesheet" type="text/css" href="help/shared/DefaultStyle.css">
|
||||
</HEAD>
|
||||
|
||||
<BODY lang="EN-US">
|
||||
<H1><A name="plugin"></A>Debugger: Breakpoint Timeline</H1>
|
||||
|
||||
<DIV class="image">
|
||||
<IMG alt="" src="images/BreakpointTimelinePlugin.png">
|
||||
</DIV>
|
||||
|
||||
<P>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.</P>
|
||||
|
||||
<P>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. <B>NOTE:</B> 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.</P>
|
||||
|
||||
<P>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.</P>
|
||||
|
||||
<H3>Cell Colors</H3>
|
||||
|
||||
<P>Each cell is filled with a color indicating the breakpoint activity in its snapshot
|
||||
range:</P>
|
||||
|
||||
<UL>
|
||||
<LI><B>Empty (Background color)</B> - No breakpoint hit was recorded in this range.</LI>
|
||||
|
||||
<LI><B>Instruction hit (Red by default)</B> - An execution breakpoint was hit in this
|
||||
range.</LI>
|
||||
|
||||
<LI><B>Memory read (Blue by default)</B> - A memory read breakpoint was hit in this
|
||||
range.</LI>
|
||||
|
||||
<LI><B>Memory write (Yellow by default)</B> - A memory write breakpoint was hit in this
|
||||
range.</LI>
|
||||
|
||||
<LI><B>Multiple hits (Colors of hits are blended)</B> - Multiple breakpoint types were hit in
|
||||
this range.</LI>
|
||||
</UL>
|
||||
|
||||
<P>In addition, three overlay colors indicate interactive state:</P>
|
||||
|
||||
<UL>
|
||||
<LI><B>Current snapshot (Green by default)</B> - The cell containing the active snapshot is
|
||||
highlighted.</LI>
|
||||
|
||||
<LI><B>Hover (Green by default)</B> - The cell under the mouse cursor is highlighted.</LI>
|
||||
|
||||
<LI><B>Selection (Green by default)</B> - Cells covered by an active drag selection are
|
||||
highlighted.</LI>
|
||||
</UL>
|
||||
|
||||
<H3>Tooltips</H3>
|
||||
|
||||
<P>Hovering over a cell shows a tooltip with:</P>
|
||||
|
||||
<UL>
|
||||
<LI>The snapshot range covered by the cell (start and end snapshot numbers).</LI>
|
||||
|
||||
<LI>The snapshot the cell will navigate to when clicked.</LI>
|
||||
|
||||
<LI>The breakpoint type of the first event in the cell (if any).</LI>
|
||||
|
||||
<LI>The name of the breakpoint that was hit (if any).</LI>
|
||||
</UL>
|
||||
|
||||
<H2>Navigation and Interaction</H2>
|
||||
|
||||
<H3>Click to Navigate</H3>
|
||||
|
||||
<P>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.</P>
|
||||
|
||||
<H3>Click and Drag to Zoom</H3>
|
||||
|
||||
<P>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 <B>Breakpoint
|
||||
Timeline</B> 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.</P>
|
||||
|
||||
<H3>Mouse Wheel</H3>
|
||||
|
||||
<P>Scrolling the mouse wheel over the timeline panel activates the next (wheel down) or
|
||||
previous (wheel up) snapshot.</P>
|
||||
|
||||
<H2>Toolbar Actions</H2>
|
||||
|
||||
<H3><A name="toggle_grid_column"></A> <IMG alt="" src="icon.debugger.breakpoint.timeline.grid">
|
||||
<IMG alt="" src="icon.debugger.breakpoint.timeline.single_column">Toggle between Grid and
|
||||
Single Column</H3>
|
||||
|
||||
<DIV class="image">
|
||||
<IMG alt="" src="images/BreakpointTimelinePluginSingleColumn.png">
|
||||
</DIV>
|
||||
|
||||
<P>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).</P>
|
||||
|
||||
<H3><A name="toggle_grid_outline"></A> <IMG alt="" src=
|
||||
"icon.debugger.breakpoint.timeline.outline"> <IMG alt="" src=
|
||||
"icon.debugger.breakpoint.timeline.no_outline">Toggle Grid Outline</H3>
|
||||
|
||||
<DIV class="image">
|
||||
<IMG alt="" src="images/BreakpointTimelinePluginNoGrid.png">
|
||||
</DIV>
|
||||
|
||||
<P>Shows or hides the border drawn around each cell. When the grid outline is enabled, cell
|
||||
boundaries are drawn in the disabled foreground color.</P>
|
||||
|
||||
<H3><A name="zoom_in"></A> <IMG alt="" src="icon.debugger.breakpoint.timeline.zoom_in">Zoom In
|
||||
(Increase Cell Size)</H3>
|
||||
|
||||
<P>Increases the default cell size by one pixel in each dimension. The grid is recalculated
|
||||
after each step.</P>
|
||||
|
||||
<H3><A name="zoom_out"></A> <IMG alt="" src="icon.debugger.breakpoint.timeline.zoom_out">Zoom
|
||||
Out (Decrease Cell Size)</H3>
|
||||
|
||||
<P>Decreases the default cell size by one pixel in each dimension, down to a minimum of one
|
||||
pixel.</P>
|
||||
|
||||
<H3><A name="smallest_cell"></A> <IMG alt="" src=
|
||||
"icon.debugger.breakpoint.timeline.zoom_out_max">Set Default Cell Size to the Smallest</H3>
|
||||
|
||||
<P>Sets the default cell size to the minimum (one pixel).</P>
|
||||
|
||||
<H3><A name="close_zoom_windows"></A> <IMG alt="" src=
|
||||
"icon.debugger.breakpoint.timeline.close_all_zoom_windows">Close All Zoom Windows</H3>
|
||||
|
||||
<P>Closes all zoom sub-windows that were created for the current trace. This action has no
|
||||
effect on the main Breakpoint Timeline window itself.</P>
|
||||
|
||||
<H2>Context Menu Actions</H2>
|
||||
|
||||
<P>The Breakpoint Timeline plugin adds context menu actions to the following views: the <A
|
||||
href="help/topics/CodeBrowserPlugin/CodeBrowser.htm">Static Listing</A>, the <A href=
|
||||
"help/topics/DebuggerListingPlugin/DebuggerListingPlugin.html">Dynamic Listing</A>, the <A
|
||||
href="help/topics/DebuggerRegistersPlugin/DebuggerRegistersPlugin.html">Registers</A> window,
|
||||
and the <A href="help/topics/DebuggerMemoryBytesPlugin/DebuggerMemoryBytesPlugin.html">Byte
|
||||
Viewer</A>. 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.</P>
|
||||
|
||||
<P>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.</P>
|
||||
|
||||
<P>Actions are organized into two top-level menu groups:</P>
|
||||
|
||||
<H3><A name="goto_actions"></A>Go to...</H3>
|
||||
|
||||
<P>These actions navigate to a single snapshot. They appear as submenus under <B>Go to...</B>,
|
||||
grouped by search direction:</P>
|
||||
|
||||
<UL>
|
||||
<LI><B>First...</B> - Navigate to the earliest snapshot in the entire trace where the
|
||||
selected address was hit.</LI>
|
||||
|
||||
<LI><B>Previous...</B> - Navigate to the latest snapshot <EM>before</EM> the current snapshot
|
||||
where the selected address was hit.</LI>
|
||||
|
||||
<LI><B>Next...</B> - Navigate to the earliest snapshot <EM>after</EM> the current snapshot
|
||||
where the selected address was hit.</LI>
|
||||
|
||||
<LI><B>Final...</B> - Navigate to the latest snapshot in the entire trace where the selected
|
||||
address was hit.</LI>
|
||||
</UL>
|
||||
|
||||
<P>Each submenu contains one entry per breakpoint type:</P>
|
||||
|
||||
<UL>
|
||||
<LI><B>Execution</B> - Search for execution breakpoint hits at the selected address
|
||||
range.</LI>
|
||||
|
||||
<LI><B>Memory Read</B> - Search for memory read breakpoint hits at the selected address
|
||||
range.</LI>
|
||||
|
||||
<LI><B>Memory Write</B> - Search for memory write breakpoint hits at the selected address
|
||||
range.</LI>
|
||||
|
||||
<LI><B>Memory Access</B> - Search for any memory access (read or write) breakpoint hits at
|
||||
the selected address range.</LI>
|
||||
</UL>
|
||||
|
||||
<H3><A name="show_all_actions"></A>Show All...</H3>
|
||||
|
||||
<P>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: <B>Snap</B> (the
|
||||
snapshot number) and <B>Address</B> (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.</P>
|
||||
</BODY>
|
||||
</HTML>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 6.5 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 6.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 4.1 KiB |
@@ -191,7 +191,7 @@
|
||||
debugger. This failure can be overcome by enabling <A href=
|
||||
"help/topics/DebuggerRegionsPlugin/DebuggerRegionsPlugin.html">Force Full View</A>.</P>
|
||||
|
||||
<P>Some examples (in <b>Hex</b> mode):</P>
|
||||
<P>Some examples (in <B>Hex</B> mode):</P>
|
||||
|
||||
<UL>
|
||||
<LI><CODE>00401234</CODE> — A constant address</LI>
|
||||
|
||||
@@ -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<AddressRange> 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<TraceSpan, Collection<MappedAddressRange>> openMappedViews =
|
||||
staticMappingService.getOpenMappedViews(c.getProgram(),
|
||||
new AddressSet(range));
|
||||
for (Map.Entry<TraceSpan, Collection<MappedAddressRange>> 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<TimelineAction> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 -> {
|
||||
}
|
||||
|
||||
@@ -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<? extends TraceObjectValue> 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) {
|
||||
|
||||
@@ -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<Address> pcs =
|
||||
Arrays.asList(tb.addr(0x00401234), tb.addr(0x7fff0110), tb.addr(0x7fff0113),
|
||||
tb.addr(0x7fff0115));
|
||||
List<Address> memRefs =
|
||||
Arrays.asList(tb.addr(0x11111), tb.addr(0x22222), tb.addr(0x33333), null, null,
|
||||
null, null);
|
||||
List<RefType> 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user