GP-1821: Reword breakpoint states, toggles, and icons

This commit is contained in:
Dan
2022-04-04 17:05:29 -04:00
parent 20706efea3
commit a0f6b67dc4
93 changed files with 1683 additions and 1467 deletions
+14 -29
View File
@@ -29,12 +29,12 @@ src/main/help/help/topics/DebuggerBreakpointMarkerPlugin/images/breakpoint-disab
src/main/help/help/topics/DebuggerBreakpointMarkerPlugin/images/breakpoint-enable.png||GHIDRA||||END|
src/main/help/help/topics/DebuggerBreakpointsPlugin/DebuggerBreakpointsPlugin.html||GHIDRA||||END|
src/main/help/help/topics/DebuggerBreakpointsPlugin/images/DebuggerBreakpointsPlugin.png||GHIDRA||||END|
src/main/help/help/topics/DebuggerBreakpointsPlugin/images/breakpoint-clear.png||GHIDRA||||END|
src/main/help/help/topics/DebuggerBreakpointsPlugin/images/breakpoint-disable.png||GHIDRA||||END|
src/main/help/help/topics/DebuggerBreakpointsPlugin/images/breakpoint-enable-ineff.png||GHIDRA||||END|
src/main/help/help/topics/DebuggerBreakpointsPlugin/images/breakpoint-enable.png||GHIDRA||||END|
src/main/help/help/topics/DebuggerBreakpointsPlugin/images/breakpoint-ineffective-d.png||GHIDRA||||END|
src/main/help/help/topics/DebuggerBreakpointsPlugin/images/breakpoint-ineffective-e.png||GHIDRA||||END|
src/main/help/help/topics/DebuggerBreakpointsPlugin/images/breakpoint-mixed-de.png||GHIDRA||||END|
src/main/help/help/topics/DebuggerBreakpointsPlugin/images/breakpoint-mixed-ed.png||GHIDRA||||END|
src/main/help/help/topics/DebuggerBreakpointsPlugin/images/breakpoint-mixed.png||GHIDRA||||END|
src/main/help/help/topics/DebuggerBreakpointsPlugin/images/breakpoint-overlay-inconsistent.png||GHIDRA||||END|
src/main/help/help/topics/DebuggerBreakpointsPlugin/images/breakpoints-clear-all.png||GHIDRA||||END|
src/main/help/help/topics/DebuggerBreakpointsPlugin/images/breakpoints-disable-all.png||GHIDRA||||END|
src/main/help/help/topics/DebuggerBreakpointsPlugin/images/breakpoints-enable-all.png||GHIDRA||||END|
@@ -132,35 +132,21 @@ src/main/help/help/topics/DebuggerWatchesPlugin/DebuggerWatchesPlugin.html||GHID
src/main/help/help/topics/DebuggerWatchesPlugin/images/DebuggerWatchesPlugin.png||GHIDRA||||END|
src/main/resources/defaultTools/Debugger.tool||GHIDRA||||END|
src/main/resources/images/add.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END|
src/main/resources/images/alt-breakpoint-clear.png||GHIDRA||||END|
src/main/resources/images/alt-breakpoint-disable.png||GHIDRA||||END|
src/main/resources/images/alt-breakpoint-enable.png||GHIDRA||||END|
src/main/resources/images/alt-breakpoint-ineffective-d.png||GHIDRA||||END|
src/main/resources/images/alt-breakpoint-ineffective-e.png||GHIDRA||||END|
src/main/resources/images/alt-breakpoint-mixed-de.png||GHIDRA||||END|
src/main/resources/images/alt-breakpoint-mixed-ed.png||GHIDRA||||END|
src/main/resources/images/alt-breakpoint-set.png||GHIDRA||||END|
src/main/resources/images/alt-breakpoints-clear-all.png||GHIDRA||||END|
src/main/resources/images/alt-breakpoints-disable-all.png||GHIDRA||||END|
src/main/resources/images/alt-breakpoints-enable-all.png||GHIDRA||||END|
src/main/resources/images/alt-breakpoints-make-effective.png||GHIDRA||||END|
src/main/resources/images/alt-breakpoints.png||GHIDRA||||END|
src/main/resources/images/attach.png||GHIDRA||||END|
src/main/resources/images/autoread.png||GHIDRA||||END|
src/main/resources/images/blank.png||GHIDRA||||END|
src/main/resources/images/breakpoint-clear.png||GHIDRA||||END|
src/main/resources/images/breakpoint-disable-ineff.png||GHIDRA||||END|
src/main/resources/images/breakpoint-disable.png||GHIDRA||||END|
src/main/resources/images/breakpoint-enable-ineff.png||GHIDRA||||END|
src/main/resources/images/breakpoint-enable.png||GHIDRA||||END|
src/main/resources/images/breakpoint-ineffective-d.png||GHIDRA||||END|
src/main/resources/images/breakpoint-ineffective-e.png||GHIDRA||||END|
src/main/resources/images/breakpoint-mixed-de.png||GHIDRA||||END|
src/main/resources/images/breakpoint-mixed-ed.png||GHIDRA||||END|
src/main/resources/images/breakpoint-set.png||GHIDRA||||END|
src/main/resources/images/breakpoint-mixed-ineff.png||GHIDRA||||END|
src/main/resources/images/breakpoint-mixed.png||GHIDRA||||END|
src/main/resources/images/breakpoint-overlay-inconsistent.png||GHIDRA||||END|
src/main/resources/images/breakpoints-clear-all.png||GHIDRA||||END|
src/main/resources/images/breakpoints-disable-all.png||GHIDRA||||END|
src/main/resources/images/breakpoints-enable-all.png||GHIDRA||||END|
src/main/resources/images/breakpoints-make-effective.png||GHIDRA||||END|
src/main/resources/images/breakpoints.png||GHIDRA||||END|
src/main/resources/images/closedFolder.png||Modified Nuvola Icons - LGPL 2.1||||END|
src/main/resources/images/conf.png||GHIDRA||||END|
src/main/resources/images/connect.png||GHIDRA||||END|
@@ -204,18 +190,17 @@ src/main/resources/images/write-trace.png||Tango Icons - Public Domain||||END|
src/main/svg/attach.svg||GHIDRA||||END|
src/main/svg/blank.svg||GHIDRA||||END|
src/main/svg/breakpoint-clear.svg||GHIDRA||||END|
src/main/svg/breakpoint-disable-ineff.svg||GHIDRA||||END|
src/main/svg/breakpoint-disable.svg||GHIDRA||||END|
src/main/svg/breakpoint-enable-ineff.svg||GHIDRA||||END|
src/main/svg/breakpoint-enable.svg||GHIDRA||||END|
src/main/svg/breakpoint-ineffective-d.svg||GHIDRA||||END|
src/main/svg/breakpoint-ineffective-e.svg||GHIDRA||||END|
src/main/svg/breakpoint-mixed-de.svg||GHIDRA||||END|
src/main/svg/breakpoint-mixed-ed.svg||GHIDRA||||END|
src/main/svg/breakpoint-set.svg||GHIDRA||||END|
src/main/svg/breakpoint-mixed-ineff.svg||GHIDRA||||END|
src/main/svg/breakpoint-mixed.svg||GHIDRA||||END|
src/main/svg/breakpoint-overlay-inconsistent.svg||GHIDRA||||END|
src/main/svg/breakpoints-clear-all.svg||GHIDRA||||END|
src/main/svg/breakpoints-disable-all.svg||GHIDRA||||END|
src/main/svg/breakpoints-enable-all.svg||GHIDRA||||END|
src/main/svg/breakpoints-make-effective.svg||GHIDRA||||END|
src/main/svg/breakpoints.svg||GHIDRA||||END|
src/main/svg/connect.svg||GHIDRA||||END|
src/main/svg/console.svg||GHIDRA||||END|
src/main/svg/continue.svg||GHIDRA||||END|
@@ -24,38 +24,41 @@
<P>For a description of how breakpoints are managed logically in Ghidra, please read about the
<A href="help/topics/DebuggerBreakpointsPlugin/DebuggerBreakpointsPlugin.html">Breakpoints</A>
window. Each individual breakpoint location is placed in its respective listing. By default,
disabled breakpoints are not readily visible in the dynamic listing. Breakpoints are best
controlled using the static program listing, where they are stored as bookmarks. When this
plugin is active, additional actions are available for managing those bookmarks and their
mapped breakpoints on target, when applicable. The actions in the listing manipulate the
logical breakpoint as a whole, not just the individual location. Furthermore, depending on the
target, locations' states may be bound to others' via a common breakpoint specification.</P>
window. Each individual breakpoint location is placed in its respective listing. Breakpoints
are best controlled using the static program listing, where they are stored as bookmarks. When
this plugin is active, additional actions are available for managing breakpoints and their
locations on target. The actions in the static listing manipulate the logical breakpoint as a
whole; whereas, the actions in the dynamic listing tend to manipulate just the locations for
the current target. <B>NOTE:</B> Depending on the connected debugger, locations resulting from
a common specification may not be independently manipulated.</P>
<H2>Actions</H2>
<P>The following actions are added to all listings by the breakpoint marker plugin. They allow
the placement and toggling of breakpoints by address, kind, and length. To set breakpoints on
arbitrary expressions, use the <A href=
<P>The following actions are added to all disassembly listings by the breakpoint marker plugin.
They allow the placement and toggling of breakpoints by address, kind, and length. To set
breakpoints on arbitrary expressions, use the <A href=
"help/topics/DebuggerObjectsPlugin/DebuggerObjectsPlugin.html#set_breakpoint">Set
Breakpoint</A> action of the Commands and Objects window.</P>
Breakpoint</A> action of the Objects window. <B>NOTE:</B> These actions may also appear in
other address-based contexts, e.g., the decompiler listing; however, those contexts often lack
any indication of breakpoint presence or state.</P>
<H3><A name="toggle_breakpoint"></A><IMG alt="" src="images/breakpoint-enable.png"> Toggle
<H3><A name="toggle_breakpoint"></A><IMG alt="" src="images/breakpoint-mixed.png"> Toggle
Breakpoint (K)</H3>
<P>This action is always available, and it is suitable for almost all cases. If there is a
breakpoint at the cursor, this simply toggles its state. If there is no breakpoint at the
cursor, this will prompt to set one, giving a reasonable set of default parameters based on the
context at the cursor. At an instruction, it will prefer to set a Software Execution
breakpoint. At defined data, it will prefer to set a Read/Write breakpoint of the size of data.
At undefined data, or if the target does not support the suggested default, the default kind is
left unselected. Please use one of the Set Breakpoint actions to force specific commands.
Please beware: the default parameters are not always acceptable to the connected debugger.</P>
cursor, this will behave like <B>Set Breakpoint</B>, giving a reasonable set of default
parameters based on the context at the cursor. At an instruction, it will prefer to set a
Software Execution breakpoint. At defined data, it will prefer to set a Read/Write breakpoint
of the size of data. At undefined data, or if the target does not support the suggested
default, the default kind is left unselected. Please use one of the <B>Set Breakpoint</B>
actions to force specific commands. <B>NOTE:</B> The default parameters are not guaranteed to
be accepted by the connected debugger.</P>
<H3><A name="set_breakpoint"></A><IMG alt="" src="images/breakpoint-enable.png"> Set
Breakpoint</H3>
<P>This action is available on the dynamic listing when the target supports at least one
<P>This menu is available on the dynamic listing when the target supports at least one
breakpoint kind. This menu is always available on the static listing. It displays set
breakpoint actions for each reasonable combination of kinds supported by the target. In the
static listing, all reasonable combinations are available, regardless of target support;
@@ -74,19 +77,19 @@
</TABLE>
<UL>
<LI>Address - the starting address of the breakpoint. It defaults to the starting address of
the instruction or data at the cursor.</LI>
<LI>Address - the address of the breakpoint. It defaults to the address of the instruction or
data at the cursor.</LI>
<LI>Length - the length in bytes of the breakpoint. Some debuggers for some kinds of
breakpoints may not allow a value other than 1. For execution breakpoints, this defaults to
1; for access breakpoints, this defaults to the size of the data at the cursor.</LI>
<LI>Length - the length in bytes of the breakpoint. For execution breakpoints, this defaults
to 1 &mdash; often the required value. For access breakpoints, this defaults to the size of
the data at the cursor.</LI>
<LI>Kinds - the kind(s) of breakpoint. Only the reasonable combinations are presented, but
the user may type any desired combination. A connected debugger may not support the desired
combination.</LI>
<LI>Name - the user-defined name of the breakpoint. The name is saved to the program
containing its static location, if applicable.</LI>
<LI>Name - the user-defined name of the breakpoint. The name is set on the bookmark at its
static location, if applicable.</LI>
</UL>
<H3><A name="enable_breakpoint"></A><IMG alt="" src="images/breakpoint-enable.png"> Enable
@@ -111,7 +114,7 @@
<P>The background coloring of enabled and disabled, effective and ineffective breakpoints can
be configured in the tool's options. By default, enabled breakpoints are colored a desaturated
red, ineffective breakpoints are colored grey, and disabled breakpoints have no background at
blue, ineffective breakpoints are colored grey, and disabled breakpoints have no background at
all.</P>
</BODY>
</HTML>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 365 B

After

Width:  |  Height:  |  Size: 665 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 295 B

After

Width:  |  Height:  |  Size: 684 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 269 B

After

Width:  |  Height:  |  Size: 561 B

@@ -22,18 +22,27 @@
</TBODY>
</TABLE>
<P>Breakpoints refer to any mechanism which may trap execution based on an address. The
breakpoints manager presents all active breakpoints among all open programs and live traces.
Note that dead traces are not considered, and only the breakpoints at the present are
displayed, even if the user has stepped a trace backward. Breakpoints which map to the same
address in the same module, i.e., program image, and otherwise share the same attributes, are
grouped into a logical breakpoint. <B>NOTE:</B> The breakpoints window cannot display or
manipulate breakpoints from a target until that target is recorded into a trace. See the <A
href="help/topics/DebuggerStaticMappingPlugin/DebuggerStaticMappingPlugin.html">Static
Mappings</A> window for the finer details of mapping traces to imported modules. In this
manner, breakpoints stored in Ghidra programs comprise the current breakpoint set, organized by
address &mdash; except for breakpoints outside a known imported module. The top table of the
provider displays logical breakpoints; the bottom table displays breakpoint locations.</P>
<P>The breakpoints window tabulates and manipulates breakpoints among all live and traced
targets. Only address-based breakpoints are tabulated. For other traps, e.g., "break on
exception," see the <A href=
"help/topics/DebuggerObjectsPlugin/DebuggerObjectsPlugin.html">Objects Window</A>. Breakpoints
can also be manipulated from address-based views, especially the disassembly listings. See <A
href=
"help/topics/DebuggerBreakpointMarkerPlugin/DebuggerBreakpointMarkerPlugin.html">Breakpoints in
the Listings</A>. Display of breakpoints in other views, e.g., the decompiler, is not yet
implemented.</P>
<P>Individual breakpoint locations from among the targets are consolidated into logical
breakpoints, based on their addresses in the static listing. The static locations are typically
stored as bookmarks in their respective Ghidra programs, comprising the current breakpoint set.
See the <A href=
"help/topics/DebuggerStaticMappingPlugin/DebuggerStaticMappingPlugin.html">Static Mappings</A>
window for the finer details of address mapping. A breakpoint which cannot be mapped to a
static address becomes its own logical breakpoint at its dynamic address. The top table of the
provider displays logical breakpoints; the bottom table displays breakpoint locations.
<B>NOTE:</B> The breakpoints window cannot display or manipulate breakpoints from a target
until that target is recorded into a trace. Furthermore, dead traces are not included. Nor are
breakpoints from the past included, even when viewing past machine state.</P>
<P>Depending on what is supported by the connected debugger, breakpoints can trap a target when
an address or range is executed, read, or written; using software or hardware mechanisms. In
@@ -54,75 +63,84 @@
mixed or inconsistent state. This happens quite commonly, e.g., when a breakpoint is placed in
a Ghidra program before that program is mapped in any traced target. Once mapped in, the
location of that breakpoint in the trace is computed and noted as missing. A logical breakpoint
without any location in a trace (i.e., on an actual target) is called "ineffective" and is
drawn in grey. An enabled logical breakpoint having a disabled location is called
"inconsistent" and its icon will indicate that state. A disabled logical breakpoint having an
enabled location is similarly "inconsistent." Toggling ineffective or inconsistent breakpoints
enables and/or places all locations, bringing it into a consistent enabled state. Toggling it
again disables all locations.</P>
without any location in a trace (i.e., on an actual target) is called <EM>ineffective</EM> and
is drawn in grey, e.g.: <IMG alt="" src="images/breakpoint-enable-ineff.png">. An enabled
logical breakpoint having a disabled location is called <EM>inconsistent</EM> and its icon will
include an exclamation mark: <IMG alt="" src="images/breakpoint-overlay-inconsistent.png">. A
disabled logical breakpoint having an enabled location is similarly inconsistent. Toggling an
ineffective or inconsistent logical breakpoint enables and/or places all its locations, aiming
for a consistent enabled state. Toggling it again disables all locations.</P>
<H2>Tables and Columns</H2>
<P>The top table, which lists logical breakpoints, has the following columns:</P>
<UL>
<LI>Enabled - displays an icon indicating the state of the breakpoint. Clicking the icon
toggles the breakpoint.</LI>
<LI>State - displays an icon indicating the state of the breakpoint. If rendered in grey, the
breakpoint has no locations, i.e., it is ineffective. If rendered with an exclamation mark
overlay, the breakpoint is inconsistent. Clicking the icon toggles the breakpoint.</LI>
<UL style="list-style-type: none">
<LI><IMG alt="" src="images/breakpoint-enable.png"> Enabled</LI>
<LI><IMG alt="" src="images/breakpoint-enable.png"> Enabled: The logical breakpoint,
including all its locations, is enabled.</LI>
<LI><IMG alt="" src="images/breakpoint-disable.png"> Disabled</LI>
<LI><IMG alt="" src="images/breakpoint-disable.png"> Disabled: The logical breakpoint,
including all its locations, is disabled.</LI>
<LI><IMG alt="" src="images/breakpoint-mixed-ed.png"> Inconsistent: Enabled with disabled
locations</LI>
<LI><IMG alt="" src="images/breakpoint-mixed-de.png"> Inconsistent: Disabled with enabled
locations</LI>
<LI><IMG alt="" src="images/breakpoint-ineffective-e.png"> Enabled but ineffective</LI>
<LI><IMG alt="" src="images/breakpoint-ineffective-d.png"> Disabled and ineffective</LI>
<LI><IMG alt="" src="images/breakpoint-mixed.png"> Mixed: (Listing only) Two logical
breakpoints at the same address have different states.</LI>
</UL>
<LI>Name - gives the user-defined name of the breakpoint. This cell is only populated and
modifiable when the breakpoint is mapped and saved to a program, since the name is associated
with the static location.</LI>
modifiable when the breakpoint is bookmarked in a program, since the name is associated with
the static location.</LI>
<LI>Address - gives the address of the breakpoint. For a breakpoint mapped to a program, this
gives the address in that program. For a breakpoint not mapped, this gives the address in its
trace.</LI>
<LI>Address - gives the address of the breakpoint. This is typically the static address. If
the breakpoint cannot be mapped to a static address, this is its dynamic address.</LI>
<LI>Image - gives the name of the program, if the breakpoint is mapped to one.</LI>
<LI>Image - gives the name of the static image, i.e., Ghidra program. If the breakpoint
cannot be mapped to a static location, this is blank.</LI>
<LI>Length - usually 1. For access breakpoints, this notes the length in bytes of the address
range.</LI>
<LI>Length - usually 1. For access breakpoints, this is the length of the address range (in
bytes).</LI>
<LI>Kinds - indicates the kind(s) of breakpoint: SW_EXECUTE, HW_EXECUTE, READ, and/or
WRITE.</LI>
<LI>Locations - counts the number of trace locations mapped to this logical breakpoint,
applying the trace filter if active. Note that a logical breakpoint with 0 locations is
<LI>Locations - counts the number of locations included in this logical breakpoint, applying
the trace filter if active. Note that a logical breakpoint with 0 locations is
ineffective.</LI>
</UL>
<P>The bottom table, which lists trace breakpoint locations, has the following columns:</P>
<P>The bottom table, which lists breakpoint locations, has the following columns:</P>
<UL>
<LI>Enabled - displays an icon indicating the state of the location. Clicking the icon
toggles the location.</LI>
<LI>State - displays an icon indicating the state of the location. If rendered with an
exclamation mark overlay, the location does not agree with its logical breakpoint, or it
cannot be bookmarked. Clicking the icon toggles the location.</LI>
<UL style="list-style-type: none">
<LI><IMG alt="" src="images/breakpoint-enable.png"> Enabled: The location is
enabled.</LI>
<LI><IMG alt="" src="images/breakpoint-disable.png"> Disabled: The location is
disabled.</LI>
<LI><IMG alt="" src="images/breakpoint-mixed.png"> Mixed: (Listing only) Two locations at
the same address have different states.</LI>
</UL>
<LI>Name - displays the name given to the location by the connected debugger. This field is
user modifiable.</LI>
<LI>Address - gives the address of this location in its trace.</LI>
<LI>Address - gives the dynamic address of this location.</LI>
<LI>Trace - gives the name of the location's trace &mdash; the target path by default.</LI>
<LI>Trace - gives the name of the location's trace.</LI>
<LI>Threads - if the breakpoint applies to a limited set of threads, gives the list of
threads.</LI>
<LI>Threads - (hidden by default) if the breakpoint applies to a limited set of threads,
gives the list of threads.</LI>
<LI>Comment - gives a user comment &mdash; the specification expression by default. This
<LI>Comment - gives a user comment &mdash; the specification's expression by default. This
field is user modifiable.</LI>
</UL>
@@ -131,10 +149,10 @@
<P>The primary purpose of this provider is to manipulate existing breakpoints. It provides the
following actions to that end. Breakpoints can also be managed via the <A href=
"help/topics/DebuggerBreakpointMarkerPlugin/DebuggerBreakpointMarkerPlugin.html">Breakpoint
Marker Actions</A> in the disassembly listings.</P>
Marker Actions</A> in the listings.</P>
<H3><A name="enable_breakpoints"></A><IMG alt="" src="images/breakpoint-enable.png"> Enable
Selected Breakpoints</H3>
<H3><A name="enable_breakpoints"></A><IMG alt="" src="images/breakpoint-enable.png">
Enable</H3>
<P>This action is available when one or more breakpoints or locations are selected. It enables
each selected breakpoint. For any breakpoint that is already enabled, no action is taken.</P>
@@ -145,8 +163,8 @@
<P>This action is always available. It enables every breakpoint. For any breakpoint that is
already enabled, no action is taken.</P>
<H3><A name="disable_breakpoints"></A><IMG alt="" src="images/breakpoint-disable.png"> Disable
Selected Breakpoints</H3>
<H3><A name="disable_breakpoints"></A><IMG alt="" src="images/breakpoint-disable.png">
Disable</H3>
<P>This action is available when one or more breakpoints or locations are selected. It disables
each selected breakpoint. For any breakpoint that is already disabled, no action is taken.</P>
@@ -165,8 +183,7 @@
breakpoints where possible. This action is also offered as a resolution in the console. It
appears in the log any time this action is available.</P>
<H3><A name="clear_breakpoints"></A><IMG alt="" src="images/breakpoint-clear.png"> Clear
Selected Breakpoints</H3>
<H3><A name="clear_breakpoints"></A><IMG alt="" src="images/breakpoint-clear.png"> Clear</H3>
<P>This action is available when one or more breakpoints or locations are selected. It clears
(deletes) each selected breakpoint.</P>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 665 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 295 B

After

Width:  |  Height:  |  Size: 684 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 513 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 269 B

After

Width:  |  Height:  |  Size: 561 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 353 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 302 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 368 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 373 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 681 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 504 B

After

Width:  |  Height:  |  Size: 732 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 420 B

After

Width:  |  Height:  |  Size: 732 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 329 B

After

Width:  |  Height:  |  Size: 626 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 381 B

After

Width:  |  Height:  |  Size: 402 B

@@ -52,7 +52,6 @@ import ghidra.app.plugin.core.debug.gui.watch.DebuggerWatchesPlugin;
import ghidra.app.plugin.core.debug.service.model.launch.DebuggerProgramLaunchOffer;
import ghidra.app.services.DebuggerStateEditingService.StateEditingMode;
import ghidra.app.services.DebuggerTraceManagerService.BooleanChangeAdapter;
import ghidra.app.services.MarkerService;
import ghidra.async.AsyncUtils;
import ghidra.framework.plugintool.Plugin;
import ghidra.framework.plugintool.util.PluginUtils;
@@ -94,32 +93,18 @@ public interface DebuggerResources {
ImageIcon ICON_SNAP_BACKWARD = ResourceManager.loadImage("images/2leftarrow.png");
ImageIcon ICON_SEEK_PRESENT = ICON_RESUME;
boolean altIcons = Boolean.getBoolean("debugger.breakpoints.alt.icons");
ImageIcon ICON_SET_BREAKPOINT =
altIcons ? ResourceManager.loadImage("images/alt-breakpoint-set.png")
: ResourceManager.loadImage("images/breakpoint-set.png");
ImageIcon ICON_CLEAR_BREAKPOINT =
altIcons ? ResourceManager.loadImage("images/alt-breakpoint-clear.png")
: ResourceManager.loadImage("images/breakpoint-clear.png");
ImageIcon ICON_ENABLE_BREAKPOINT =
altIcons ? ResourceManager.loadImage("images/alt-breakpoint-enable.png")
: ResourceManager.loadImage("images/breakpoint-enable.png");
ImageIcon ICON_SET_BREAKPOINT = ResourceManager.loadImage("images/breakpoint-enable.png");
ImageIcon ICON_CLEAR_BREAKPOINT = ResourceManager.loadImage("images/breakpoint-clear.png");
ImageIcon ICON_ENABLE_BREAKPOINT = ResourceManager.loadImage("images/breakpoint-enable.png");
ImageIcon ICON_ENABLE_ALL_BREAKPOINTS =
altIcons ? ResourceManager.loadImage("images/alt-breakpoints-enable-all.png")
: ResourceManager.loadImage("images/breakpoints-enable-all.png");
ImageIcon ICON_DISABLE_BREAKPOINT =
altIcons ? ResourceManager.loadImage("images/alt-breakpoint-disable.png")
: ResourceManager.loadImage("images/breakpoint-disable.png");
ResourceManager.loadImage("images/breakpoints-enable-all.png");
ImageIcon ICON_DISABLE_BREAKPOINT = ResourceManager.loadImage("images/breakpoint-disable.png");
ImageIcon ICON_DISABLE_ALL_BREAKPOINTS =
altIcons ? ResourceManager.loadImage("images/alt-breakpoints-disable-all.png")
: ResourceManager.loadImage("images/breakpoints-disable-all.png");
ResourceManager.loadImage("images/breakpoints-disable-all.png");
ImageIcon ICON_CLEAR_ALL_BREAKPOINTS =
altIcons ? ResourceManager.loadImage("images/alt-breakpoints-clear-all.png")
: ResourceManager.loadImage("images/breakpoints-clear-all.png");
ResourceManager.loadImage("images/breakpoints-clear-all.png");
ImageIcon ICON_MAKE_BREAKPOINTS_EFFECTIVE =
altIcons ? ResourceManager.loadImage("images/alt-breakpoints-make-effective.png")
: ResourceManager.loadImage("images/breakpoints-make-effective.png");
ResourceManager.loadImage("images/breakpoints-make-effective.png");
// TODO: Some overlay to indicate dynamic, or new icon altogether
ImageIcon ICON_LISTING = ResourceManager.loadImage("images/Browser.gif");
@@ -127,7 +112,7 @@ public interface DebuggerResources {
ImageIcon ICON_CONSOLE = ResourceManager.loadImage("images/console.png");
ImageIcon ICON_REGISTERS = ResourceManager.loadImage("images/registers.png");
ImageIcon ICON_STACK = ResourceManager.loadImage("images/stack.png");
ImageIcon ICON_BREAKPOINTS = ResourceManager.loadImage("images/breakpoints.png");
ImageIcon ICON_BREAKPOINTS = ResourceManager.loadImage("images/breakpoint-mixed.png");
ImageIcon ICON_MODULES = ResourceManager.loadImage("images/modules.png");
ImageIcon ICON_MAPPINGS = ICON_PROGRAM; // TODO: A better icon
ImageIcon ICON_PCODE = ResourceManager.loadImage("images/stepinto.png"); // TODO
@@ -312,33 +297,36 @@ public interface DebuggerResources {
String OPTION_NAME_COLORS_PCODE_COUNTER = "Colors.Pcode Counter";
Color DEFAULT_COLOR_PCODE_COUNTER = new Color(0.75f, 0.875f, 0.75f);
String MARKER_NAME_BREAKPOINT_ENABLED = "Enabled Breakpoint";
String MARKER_NAME_BREAKPOINT_DISABLED = "Disabled Breakpoint";
String MARKER_NAME_BREAKPOINT_INEFFECTIVE_E = "Ineffective Enabled Breakpoint";
String MARKER_NAME_BREAKPOINT_INEFFECTIVE_D = "Ineffective Disabled Breakpoint";
String MARKER_NAME_BREAKPOINT_MIXED_ED = "Mixed Enabled-Disabled Breakpont";
String MARKER_NAME_BREAKPOINT_MIXED_DE = "Mixed Disabled-Enabled Breakpont";
int PRIORITY_BREAKPOINT_ENABLED_MARKER = MarkerService.BREAKPOINT_PRIORITY;
int PRIORITY_BREAKPOINT_DISABLED_MARKER = MarkerService.BREAKPOINT_PRIORITY;
int PRIORITY_BREAKPOINT_INEFFECTIVE_E_MARKER = MarkerService.BREAKPOINT_PRIORITY;
int PRIORITY_BREAKPOINT_INEFFECTIVE_D_MARKER = MarkerService.BREAKPOINT_PRIORITY;
int PRIORITY_BREAKPOINT_MIXED_ED_MARKER = MarkerService.BREAKPOINT_PRIORITY;
int PRIORITY_BREAKPOINT_MIXED_DE_MARKER = MarkerService.BREAKPOINT_PRIORITY;
String NAME_BREAKPOINT_MARKER_ENABLED = "Enabled Breakpoint";
String NAME_BREAKPOINT_MARKER_DISABLED = "Disabled Breakpoint";
String NAME_BREAKPOINT_MARKER_MIXED = "Mixed Breakpoint";
String NAME_BREAKPOINT_MARKER_INEFF_EN = "Ineffective Enabled Breakpoint";
String NAME_BREAKPOINT_MARKER_INEFF_DIS = "Ineffective Disabled Breakpoint";
String NAME_BREAKPOINT_MARKER_INEFF_MIX = "Ineffective Mixed Breakpoint";
String NAME_BREAKPOINT_MARKER_INCON_EN = "Inconsistent Enabled Breakpoint";
String NAME_BREAKPOINT_MARKER_INCON_DIS = "Inconsistent Disabled Breakpoint";
String NAME_BREAKPOINT_MARKER_INCON_MIX = "Inconsistent Mixed Breakpoint";
ImageIcon ICON_BREAKPOINT_ENABLED_MARKER = ICON_ENABLE_BREAKPOINT;
ImageIcon ICON_BREAKPOINT_DISABLED_MARKER = ICON_DISABLE_BREAKPOINT;
ImageIcon ICON_BREAKPOINT_MIXED_ED_MARKER =
altIcons ? ResourceManager.loadImage("images/alt-breakpoint-mixed-ed.png")
: ResourceManager.loadImage("images/breakpoint-mixed-ed.png");
ImageIcon ICON_BREAKPOINT_MIXED_DE_MARKER =
altIcons ? ResourceManager.loadImage("images/alt-breakpoint-mixed-de.png")
: ResourceManager.loadImage("images/breakpoint-mixed-de.png");
ImageIcon ICON_BREAKPOINT_INEFFECTIVE_E_MARKER =
altIcons ? ResourceManager.loadImage("images/alt-breakpoint-ineffective-e.png")
: ResourceManager.loadImage("images/breakpoint-ineffective-e.png");
ImageIcon ICON_BREAKPOINT_INEFFECTIVE_D_MARKER =
altIcons ? ResourceManager.loadImage("images/alt-breakpoint-ineffective-d.png")
: ResourceManager.loadImage("images/breakpoint-ineffective-d.png");
ImageIcon ICON_BREAKPOINT_OVERLAY_INCONSISTENT =
ResourceManager.loadImage("images/breakpoint-overlay-inconsistent.png");
ImageIcon ICON_BREAKPOINT_MARKER_ENABLED = ICON_ENABLE_BREAKPOINT;
ImageIcon ICON_BREAKPOINT_MARKER_DISABLED = ICON_DISABLE_BREAKPOINT;
ImageIcon ICON_BREAKPOINT_MARKER_MIXED =
ResourceManager.loadImage("images/breakpoint-mixed.png");
ImageIcon ICON_BREAKPOINT_MARKER_INEFF_EN =
ResourceManager.loadImage("images/breakpoint-enable-ineff.png");
ImageIcon ICON_BREAKPOINT_MARKER_INEFF_DIS =
ResourceManager.loadImage("images/breakpoint-disable-ineff.png");
ImageIcon ICON_BREAKPOINT_MARKER_INEFF_MIX =
ResourceManager.loadImage("images/breakpoint-mixed-ineff.png");
Icon ICON_BREAKPOINT_MARKER_INCON_EN =
new MultiIcon(ICON_BREAKPOINT_MARKER_ENABLED, ICON_BREAKPOINT_OVERLAY_INCONSISTENT);
Icon ICON_BREAKPOINT_MARKER_INCON_DIS =
new MultiIcon(ICON_BREAKPOINT_MARKER_DISABLED, ICON_BREAKPOINT_OVERLAY_INCONSISTENT);
Icon ICON_BREAKPOINT_MARKER_INCON_MIX =
new MultiIcon(ICON_BREAKPOINT_MARKER_MIXED, ICON_BREAKPOINT_OVERLAY_INCONSISTENT);
Icon ICON_UNIQUE_REF_READ =
new RotateIcon(ResourceManager.loadImage("images/cursor_arrow.gif"), 180); // TODO
@@ -346,16 +334,16 @@ public interface DebuggerResources {
Icon ICON_UNIQUE_REF_RW = new MultiIcon(ICON_UNIQUE_REF_READ, ICON_UNIQUE_REF_WRITE); // TODO
String OPTION_NAME_COLORS_ENABLED_BREAKPOINT_MARKERS = "Colors.Enabled Breakpoint Markers";
Color DEFAULT_COLOR_ENABLED_BREAKPOINT_MARKERS = new Color(0.875f, 0.75f, 0.75f);
Color DEFAULT_COLOR_ENABLED_BREAKPOINT_MARKERS = new Color(0.75f, 0.75f, 0.875f);
String OPTION_NAME_COLORS_DISABLED_BREAKPOINT_MARKERS = "Colors.Disabled Breakpoint Markers";
Color DEFAULT_COLOR_DISABLED_BREAKPOINT_MARKERS = DEFAULT_COLOR_ENABLED_BREAKPOINT_MARKERS;
String OPTION_NAME_COLORS_INEFFECTIVE_E_BREAKPOINT_MARKERS =
String OPTION_NAME_COLORS_INEFF_EN_BREAKPOINT_MARKERS =
"Colors.Ineffective Enabled Breakpoint Markers";
Color DEFAULT_COLOR_INEFFECTIVE_E_BREAKPOINT_MARKERS = new Color(0.75f, 0.75f, 0.75f);
String OPTION_NAME_COLORS_INEFFECTIVE_D_BREAKPOINT_MARKERS =
Color DEFAULT_COLOR_INEFF_EN_BREAKPOINT_MARKERS = new Color(0.75f, 0.75f, 0.75f);
String OPTION_NAME_COLORS_INEFF_DIS_BREAKPOINT_MARKERS =
"Colors.Ineffective Disabled Breakpoint Markers";
Color DEFAULT_COLOR_INEFFECTIVE_D_BREAKPOINT_MARKERS =
DEFAULT_COLOR_INEFFECTIVE_E_BREAKPOINT_MARKERS;
Color DEFAULT_COLOR_INEFF_DIS_BREAKPOINT_MARKERS =
DEFAULT_COLOR_INEFF_EN_BREAKPOINT_MARKERS;
String OPTION_NAME_COLORS_ENABLED_BREAKPOINT_COLORING_BACKGROUND =
"Colors.Enabled Breakpoint Markers Have Background";
@@ -365,13 +353,13 @@ public interface DebuggerResources {
"Colors.Disabled Breakpoint Markers Have Background";
boolean DEFAULT_COLOR_DISABLED_BREAKPOINT_COLORING_BACKGROUND = false;
String OPTION_NAME_COLORS_INEFFECTIVE_E_BREAKPOINT_COLORING_BACKGROUND =
String OPTION_NAME_COLORS_INEFF_EN_BREAKPOINT_COLORING_BACKGROUND =
"Colors.Ineffective Enabled Breakpoint Markers Have Background";
boolean DEFAULT_COLOR_INEFFECTIVE_E_BREAKPOINT_COLORING_BACKGROUND = true;
boolean DEFAULT_COLOR_INEFF_EN_BREAKPOINT_COLORING_BACKGROUND = true;
String OPTION_NAME_COLORS_INEFFECTIVE_D_BREAKPOINT_COLORING_BACKGROUND =
String OPTION_NAME_COLORS_INEFF_DIS_BREAKPOINT_COLORING_BACKGROUND =
"Colors.Ineffective Disabled Breakpoint Markers Have Background";
boolean DEFAULT_COLOR_INEFFECTIVE_D_BREAKPOINT_COLORING_BACKGROUND = false;
boolean DEFAULT_COLOR_INEFF_DIS_BREAKPOINT_COLORING_BACKGROUND = false;
String OPTION_NAME_LOG_BUFFER_LIMIT = "Log Buffer Size";
int DEFAULT_LOG_BUFFER_LIMIT = 100;
@@ -1165,7 +1153,7 @@ public interface DebuggerResources {
abstract class AbstractToggleBreakpointAction extends DockingAction {
public static final String NAME = "Toggle Breakpoint";
// TODO: A "toggle breakpoint" icon
public static final Icon ICON = ICON_BREAKPOINT_MIXED_ED_MARKER;
public static final Icon ICON = ICON_BREAKPOINT_MARKER_MIXED;
public static final String HELP_ANCHOR = "toggle_breakpoint";
public AbstractToggleBreakpointAction(Plugin owner) {
@@ -1210,7 +1198,7 @@ public interface DebuggerResources {
}
abstract class AbstractEnableSelectedBreakpointsAction extends DockingAction {
public static final String NAME = "Enable Breakpoints";
public static final String NAME = "Enable";
public static final Icon ICON = ICON_ENABLE_BREAKPOINT;
public static final String HELP_ANCHOR = "enable_breakpoints";
@@ -1247,7 +1235,7 @@ public interface DebuggerResources {
}
abstract class AbstractDisableSelectedBreakpointsAction extends DockingAction {
public static final String NAME = "Disable Breakpoints";
public static final String NAME = "Disable";
public static final Icon ICON = ICON_DISABLE_BREAKPOINT;
public static final String HELP_ANCHOR = "disable_breakpoints";
@@ -1286,7 +1274,7 @@ public interface DebuggerResources {
}
abstract class AbstractClearSelectedBreakpointsAction extends DockingAction {
public static final String NAME = "Clear Breakpoints";
public static final String NAME = "Clear";
public static final Icon ICON = ICON_CLEAR_BREAKPOINT;
public static final String HELP_ANCHOR = "clear_breakpoints";
@@ -15,10 +15,12 @@
*/
package ghidra.app.plugin.core.debug.gui.breakpoint;
import java.util.Set;
import java.util.stream.Collectors;
import ghidra.app.services.LogicalBreakpoint;
import ghidra.app.services.LogicalBreakpoint.State;
import ghidra.app.services.TraceRecorder;
import ghidra.dbg.target.TargetBreakpointLocation;
import ghidra.program.model.address.Address;
import ghidra.trace.model.breakpoint.TraceBreakpoint;
import ghidra.trace.model.thread.TraceThread;
@@ -42,24 +44,34 @@ public class BreakpointLocationRow {
return recorder != null && loc.isEnabled(recorder.getSnap());
}
public State getState() {
LogicalBreakpoint lb = provider.breakpointService.getBreakpoint(loc);
if (lb == null) {
return State.NONE; // Should only happen in transition
}
return lb.computeStateForLocation(loc);
}
public void setEnabled(boolean enabled) {
// TODO: Make this toggle the individual location, if possible, not the whole spec.
TraceRecorder recorder = provider.modelService.getRecorder(loc.getTrace());
TargetBreakpointLocation bpt = recorder.getTargetBreakpoint(loc);
if (enabled) {
bpt.getSpecification().enable().exceptionally(ex -> {
provider.breakpointService.enableLocs(Set.of(loc)).exceptionally(ex -> {
provider.breakpointError("Toggle breakpoint", "Could not enable breakpoint", ex);
return null;
});
}
else {
bpt.getSpecification().disable().exceptionally(ex -> {
provider.breakpointService.disableLocs(Set.of(loc)).exceptionally(ex -> {
provider.breakpointError("Toggle breakpoint", "Could not disable breakpoint", ex);
return null;
});
}
}
public void setState(State state) {
assert state.isNormal();
setEnabled(state.isEnabled());
}
public void setName(String name) {
try (UndoableTransaction tid =
UndoableTransaction.start(loc.getTrace(), "Set breakpoint name", true)) {
@@ -1,72 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.plugin.core.debug.gui.breakpoint;
import java.awt.Component;
import javax.swing.Icon;
import javax.swing.SwingConstants;
import docking.widgets.table.GTableCellRenderingData;
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
import ghidra.app.services.LogicalBreakpoint.Enablement;
import ghidra.docking.settings.Settings;
import ghidra.util.table.column.AbstractGColumnRenderer;
public class DebuggerBreakpointEnablementTableCellRenderer
extends AbstractGColumnRenderer<Enablement> {
protected static Icon iconForEnablement(Enablement en) {
switch (en) {
case NONE:
return null;
case ENABLED:
return DebuggerResources.ICON_BREAKPOINT_ENABLED_MARKER;
case DISABLED:
return DebuggerResources.ICON_BREAKPOINT_DISABLED_MARKER;
case INEFFECTIVE_ENABLED:
return DebuggerResources.ICON_BREAKPOINT_INEFFECTIVE_E_MARKER;
case INEFFECTIVE_DISABLED:
return DebuggerResources.ICON_BREAKPOINT_INEFFECTIVE_D_MARKER;
case ENABLED_DISABLED:
return DebuggerResources.ICON_BREAKPOINT_MIXED_ED_MARKER;
case DISABLED_ENABLED:
return DebuggerResources.ICON_BREAKPOINT_MIXED_DE_MARKER;
default:
throw new AssertionError(en);
}
}
public DebuggerBreakpointEnablementTableCellRenderer() {
setHorizontalAlignment(SwingConstants.CENTER);
}
@Override
public Component getTableCellRendererComponent(GTableCellRenderingData data) {
super.getTableCellRendererComponent(data);
Enablement en = (Enablement) data.getValue();
setIcon(iconForEnablement(en));
setHorizontalAlignment(SwingConstants.CENTER);
setText("");
setToolTipText(en.name());
return this;
}
@Override
public String getFilterString(Enablement t, Settings settings) {
return t.name();
}
}
@@ -1,67 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.plugin.core.debug.gui.breakpoint;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.plaf.basic.BasicButtonUI;
import javax.swing.table.TableCellEditor;
public class DebuggerBreakpointLocEnabledTableCellEditor extends AbstractCellEditor
implements TableCellEditor, ActionListener {
protected final JButton button = new JButton();
private Boolean value = false;
public DebuggerBreakpointLocEnabledTableCellEditor() {
button.setHorizontalAlignment(SwingConstants.CENTER);
button.setOpaque(true);
button.setBorder(BorderFactory.createEmptyBorder());
button.setUI(new BasicButtonUI());
button.addActionListener(this);
}
@Override
public Object getCellEditorValue() {
return value;
}
@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected,
int row, int column) {
if (isSelected) {
button.setBackground(table.getSelectionBackground());
}
else {
// TODO: Alternating colors? Can't inherit GTableCellRenderer....
button.setBackground(table.getBackground());
}
this.value = (Boolean) value;
button.setIcon(DebuggerBreakpointLocEnabledTableCellRenderer.iconForEnabled(this.value));
button.setHorizontalAlignment(SwingConstants.CENTER);
return button;
}
@Override
public void actionPerformed(ActionEvent e) {
value = value == null ? true : !value;
fireEditingStopped();
}
}
@@ -16,18 +16,23 @@
package ghidra.app.plugin.core.debug.gui.breakpoint;
import java.util.Collection;
import java.util.stream.Collectors;
import docking.ActionContext;
import ghidra.trace.model.breakpoint.TraceBreakpoint;
public class DebuggerBreakpointLocationsActionContext extends ActionContext {
private final Collection<TraceBreakpoint> selection;
private final Collection<BreakpointLocationRow> selection;
public DebuggerBreakpointLocationsActionContext(Collection<TraceBreakpoint> selection) {
public DebuggerBreakpointLocationsActionContext(Collection<BreakpointLocationRow> selection) {
this.selection = selection;
}
public Collection<TraceBreakpoint> getSelection() {
public Collection<BreakpointLocationRow> getSelection() {
return selection;
}
public Collection<TraceBreakpoint> getLocations() {
return selection.stream().map(row -> row.getTraceBreakpoint()).collect(Collectors.toList());
}
}
@@ -24,18 +24,18 @@ import javax.swing.plaf.basic.BasicButtonUI;
import javax.swing.table.TableCellEditor;
import docking.widgets.table.GTableFilterPanel;
import ghidra.app.services.LogicalBreakpoint.Enablement;
import ghidra.app.services.LogicalBreakpoint.State;
public class DebuggerBreakpointEnablementTableCellEditor extends AbstractCellEditor
public abstract class DebuggerBreakpointStateTableCellEditor<T> extends AbstractCellEditor
implements TableCellEditor, ActionListener {
private final GTableFilterPanel<LogicalBreakpointRow> filterPanel;
private final GTableFilterPanel<T> filterPanel;
protected final JButton button = new JButton();
private Enablement value = Enablement.NONE;
private LogicalBreakpointRow row;
private State value = State.NONE;
private T row;
public DebuggerBreakpointEnablementTableCellEditor(
GTableFilterPanel<LogicalBreakpointRow> filterPanel) {
public DebuggerBreakpointStateTableCellEditor(
GTableFilterPanel<T> filterPanel) {
this.filterPanel = filterPanel;
button.setHorizontalAlignment(SwingConstants.CENTER);
@@ -62,16 +62,17 @@ public class DebuggerBreakpointEnablementTableCellEditor extends AbstractCellEdi
button.setBackground(table.getBackground());
}
this.row = filterPanel.getRowObject(row);
this.value = (Enablement) value;
button.setIcon(DebuggerBreakpointEnablementTableCellRenderer.iconForEnablement(this.value));
this.value = (State) value;
button.setIcon(this.value.icon);
button.setHorizontalAlignment(SwingConstants.CENTER);
return button;
}
@Override
public void actionPerformed(ActionEvent e) {
boolean mapped = row.isMapped();
value = value.getToggled(mapped);
value = getToggledState(row, value);
fireEditingStopped();
}
protected abstract State getToggledState(T row, State current);
}
@@ -17,41 +17,32 @@ package ghidra.app.plugin.core.debug.gui.breakpoint;
import java.awt.Component;
import javax.swing.Icon;
import javax.swing.SwingConstants;
import docking.widgets.table.GTableCellRenderingData;
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
import ghidra.app.services.LogicalBreakpoint.State;
import ghidra.docking.settings.Settings;
import ghidra.util.table.column.AbstractGColumnRenderer;
public class DebuggerBreakpointLocEnabledTableCellRenderer
extends AbstractGColumnRenderer<Boolean> {
public class DebuggerBreakpointStateTableCellRenderer extends AbstractGColumnRenderer<State> {
protected static Icon iconForEnabled(Boolean enabled) {
return enabled == null ? null
: enabled
? DebuggerResources.ICON_BREAKPOINT_ENABLED_MARKER
: DebuggerResources.ICON_BREAKPOINT_DISABLED_MARKER;
}
public DebuggerBreakpointLocEnabledTableCellRenderer() {
public DebuggerBreakpointStateTableCellRenderer() {
setHorizontalAlignment(SwingConstants.CENTER);
}
@Override
public Component getTableCellRendererComponent(GTableCellRenderingData data) {
super.getTableCellRendererComponent(data);
Boolean en = (Boolean) data.getValue();
setIcon(iconForEnabled(en));
State state = (State) data.getValue();
setIcon(state.icon);
setHorizontalAlignment(SwingConstants.CENTER);
setText("");
setToolTipText(en ? "ENABLED" : "DISABLED");
setToolTipText(state.name());
return this;
}
@Override
public String getFilterString(Boolean t, Settings settings) {
return t == null ? "null" : t ? "enabled" : "disabled";
public String getFilterString(State t, Settings settings) {
return t.name();
}
}
@@ -36,7 +36,7 @@ import ghidra.app.plugin.core.debug.DebuggerPluginPackage;
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
import ghidra.app.plugin.core.debug.gui.DebuggerResources.*;
import ghidra.app.services.*;
import ghidra.app.services.LogicalBreakpoint.Enablement;
import ghidra.app.services.LogicalBreakpoint.State;
import ghidra.framework.model.DomainObject;
import ghidra.framework.plugintool.AutoService;
import ghidra.framework.plugintool.ComponentProviderAdapter;
@@ -59,8 +59,7 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
protected enum LogicalBreakpointTableColumns
implements EnumeratedTableColumn<LogicalBreakpointTableColumns, LogicalBreakpointRow> {
ENABLED("", Enablement.class, LogicalBreakpointRow::getEnablement, //
LogicalBreakpointRow::setEnablement, true),
STATE("State", State.class, LogicalBreakpointRow::getState, LogicalBreakpointRow::setState, true),
NAME("Name", String.class, LogicalBreakpointRow::getName, LogicalBreakpointRow::setName, //
LogicalBreakpointRow::isNamable, true),
ADDRESS("Address", Address.class, LogicalBreakpointRow::getAddress, true),
@@ -147,7 +146,7 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
protected enum BreakpointLocationTableColumns
implements EnumeratedTableColumn<BreakpointLocationTableColumns, BreakpointLocationRow> {
ENABLED("", Boolean.class, BreakpointLocationRow::isEnabled, BreakpointLocationRow::setEnabled, true),
STATE("State", State.class, BreakpointLocationRow::getState, BreakpointLocationRow::setState, true),
NAME("Name", String.class, BreakpointLocationRow::getName, BreakpointLocationRow::setName, true),
ADDRESS("Address", Address.class, BreakpointLocationRow::getAddress, true),
TRACE("Trace", String.class, BreakpointLocationRow::getTraceName, true),
@@ -222,23 +221,29 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
}
}
protected static boolean contextIsNonEmptyBreakpoints(ActionContext context) {
protected static boolean contextHasMatchingBreakpoints(ActionContext context,
Predicate<? super LogicalBreakpointRow> logicalCase,
Predicate<? super BreakpointLocationRow> locationCase) {
if (context == null) {
return false;
}
if (context instanceof DebuggerLogicalBreakpointsActionContext) {
DebuggerLogicalBreakpointsActionContext ctx =
(DebuggerLogicalBreakpointsActionContext) context;
return !ctx.getSelection().isEmpty();
return ctx.getSelection().stream().anyMatch(logicalCase);
}
if (context instanceof DebuggerBreakpointLocationsActionContext) {
DebuggerBreakpointLocationsActionContext ctx =
(DebuggerBreakpointLocationsActionContext) context;
return !ctx.getSelection().isEmpty();
return ctx.getSelection().stream().anyMatch(locationCase);
}
return false;
}
protected static boolean contextIsNonEmptyBreakpoints(ActionContext context) {
return contextHasMatchingBreakpoints(context, lb -> true, loc -> true);
}
protected class EnableSelectedBreakpointsAction
extends AbstractEnableSelectedBreakpointsAction {
public static final String GROUP = DebuggerResources.GROUP_BREAKPOINTS;
@@ -246,7 +251,7 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
public EnableSelectedBreakpointsAction() {
super(plugin);
setToolBarData(new ToolBarData(ICON, GROUP));
setPopupMenuData(new MenuData(new String[] { NAME }, GROUP));
setPopupMenuData(new MenuData(new String[] { NAME }, ICON, GROUP));
addLocalAction(this);
setEnabled(true);
}
@@ -259,7 +264,7 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
if (context instanceof DebuggerLogicalBreakpointsActionContext) {
DebuggerLogicalBreakpointsActionContext ctx =
(DebuggerLogicalBreakpointsActionContext) context;
Collection<LogicalBreakpoint> sel = ctx.getSelection();
Collection<LogicalBreakpoint> sel = ctx.getBreakpoints();
breakpointService.enableAll(sel, null).exceptionally(ex -> {
breakpointError("Enable Breakpoints", "Could not enable breakpoints", ex);
return null;
@@ -268,7 +273,7 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
if (context instanceof DebuggerBreakpointLocationsActionContext) {
DebuggerBreakpointLocationsActionContext ctx =
(DebuggerBreakpointLocationsActionContext) context;
Collection<TraceBreakpoint> sel = ctx.getSelection();
Collection<TraceBreakpoint> sel = ctx.getLocations();
breakpointService.enableLocs(sel).exceptionally(ex -> {
breakpointError("Enable Breakpoints", "Could not enable breakpoints", ex);
return null;
@@ -278,7 +283,14 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
@Override
public boolean isEnabledForContext(ActionContext context) {
return contextIsNonEmptyBreakpoints(context);
return contextHasMatchingBreakpoints(context,
row -> row.getState() != State.ENABLED,
row -> row.getState() != State.ENABLED);
}
@Override
public boolean isAddToPopup(ActionContext context) {
return isEnabledForContext(context);
}
}
@@ -314,7 +326,7 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
public DisableSelectedBreakpointsAction() {
super(plugin);
setToolBarData(new ToolBarData(ICON, GROUP));
setPopupMenuData(new MenuData(new String[] { NAME }, GROUP));
setPopupMenuData(new MenuData(new String[] { NAME }, ICON, GROUP));
addLocalAction(this);
setEnabled(true);
}
@@ -327,7 +339,7 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
if (context instanceof DebuggerLogicalBreakpointsActionContext) {
DebuggerLogicalBreakpointsActionContext ctx =
(DebuggerLogicalBreakpointsActionContext) context;
Collection<LogicalBreakpoint> sel = ctx.getSelection();
Collection<LogicalBreakpoint> sel = ctx.getBreakpoints();
breakpointService.disableAll(sel, null).exceptionally(ex -> {
breakpointError("Disable Breakpoints", "Could not disable breakpoints", ex);
return null;
@@ -336,7 +348,7 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
if (context instanceof DebuggerBreakpointLocationsActionContext) {
DebuggerBreakpointLocationsActionContext ctx =
(DebuggerBreakpointLocationsActionContext) context;
Collection<TraceBreakpoint> sel = ctx.getSelection();
Collection<TraceBreakpoint> sel = ctx.getLocations();
breakpointService.disableLocs(sel).exceptionally(ex -> {
breakpointError("Disable Breakpoints", "Could not disable breakpoints", ex);
return null;
@@ -346,8 +358,16 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
@Override
public boolean isEnabledForContext(ActionContext context) {
return contextIsNonEmptyBreakpoints(context);
return contextHasMatchingBreakpoints(context,
row -> row.getState() != State.DISABLED,
row -> row.getState() != State.DISABLED);
}
@Override
public boolean isAddToPopup(ActionContext context) {
return isEnabledForContext(context);
}
}
protected class DisableAllBreakpointsAction extends AbstractDisableAllBreakpointsAction {
@@ -381,7 +401,7 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
public ClearSelectedBreakpointsAction() {
super(plugin);
setToolBarData(new ToolBarData(ICON, GROUP));
setPopupMenuData(new MenuData(new String[] { NAME }, GROUP));
setPopupMenuData(new MenuData(new String[] { NAME }, ICON, GROUP));
addLocalAction(this);
setEnabled(true);
}
@@ -391,7 +411,7 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
if (context instanceof DebuggerLogicalBreakpointsActionContext) {
DebuggerLogicalBreakpointsActionContext ctx =
(DebuggerLogicalBreakpointsActionContext) context;
Collection<LogicalBreakpoint> sel = ctx.getSelection();
Collection<LogicalBreakpoint> sel = ctx.getBreakpoints();
breakpointService.deleteAll(sel, null).exceptionally(ex -> {
breakpointError("Clear Breakpoints", "Could not clear breakpoints", ex);
return null;
@@ -400,7 +420,7 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
if (context instanceof DebuggerBreakpointLocationsActionContext) {
DebuggerBreakpointLocationsActionContext ctx =
(DebuggerBreakpointLocationsActionContext) context;
Collection<TraceBreakpoint> sel = ctx.getSelection();
Collection<TraceBreakpoint> sel = ctx.getLocations();
breakpointService.deleteLocs(sel).exceptionally(ex -> {
breakpointError("Clear Breakpoints", "Could not clear breakpoints", ex);
return null;
@@ -452,7 +472,7 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
public void actionPerformed(ActionContext context) {
Set<LogicalBreakpoint> enablable = breakpointService.getAllBreakpoints()
.stream()
.filter(lb -> lb.computeEnablement() == Enablement.INEFFECTIVE_ENABLED &&
.filter(lb -> lb.computeState() == State.INEFFECTIVE_ENABLED &&
!lb.getMappedTraces().isEmpty())
.collect(Collectors.toSet());
breakpointService.enableAll(enablable, null).exceptionally(ex -> {
@@ -476,7 +496,7 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
}
Set<LogicalBreakpoint> all = breakpointService.getAllBreakpoints();
for (LogicalBreakpoint lb : all) {
if (lb.computeEnablement() != Enablement.INEFFECTIVE_ENABLED) {
if (lb.computeState() != State.INEFFECTIVE_ENABLED) {
continue;
}
if (lb.getMappedTraces().isEmpty()) {
@@ -609,7 +629,7 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
private final DebuggerBreakpointsPlugin plugin;
// @AutoServiceConsumed via method
private DebuggerLogicalBreakpointService breakpointService;
DebuggerLogicalBreakpointService breakpointService;
// @AutoServiceConsumed via method, package access for BreakpointLogicalRow
DebuggerModelService modelService;
@AutoServiceConsumed
@@ -763,6 +783,7 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
public void breakpointUpdated(LogicalBreakpoint lb) {
Swing.runIfSwingOrRunLater(() -> {
breakpointTableModel.updateItem(lb);
breakpointLocationsUpdated(lb.getTraceBreakpoints());
contextChanged();
});
}
@@ -771,6 +792,9 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
public void breakpointsUpdated(Collection<LogicalBreakpoint> clb) {
Swing.runIfSwingOrRunLater(() -> {
breakpointTableModel.updateAllItems(clb);
breakpointLocationsUpdated(clb.stream()
.flatMap(lb -> lb.getTraceBreakpoints().stream())
.collect(Collectors.toSet()));
contextChanged();
});
}
@@ -817,6 +841,10 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
locationTableModel.updateItem(location);
}
private void breakpointLocationsUpdated(Collection<TraceBreakpoint> locations) {
locationTableModel.updateAllItems(locations);
}
private void breakpointLocationRemoved(TraceBreakpoint location) {
locationTableModel.deleteItem(location);
}
@@ -891,16 +919,13 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
mainPanel.setResizeWeight(0.5);
breakpointTable.getSelectionModel().addListSelectionListener(evt -> {
List<LogicalBreakpoint> set = breakpointFilterPanel.getSelectedItems()
.stream()
.map(LogicalBreakpointRow::getLogicalBreakpoint)
.collect(Collectors.toList());
List<LogicalBreakpointRow> sel = breakpointFilterPanel.getSelectedItems();
// Do this first to prevent overriding context in event chain
if (!set.isEmpty()) {
if (!sel.isEmpty()) {
locationTable.clearSelection();
locationTable.getSelectionManager().clearSavedSelection();
}
myActionContext = new DebuggerLogicalBreakpointsActionContext(set);
myActionContext = new DebuggerLogicalBreakpointsActionContext(sel);
if (isFilterLocationsByBreakpoints()) {
locationTableModel.fireTableDataChanged();
}
@@ -930,16 +955,13 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
});
locationTable.getSelectionModel().addListSelectionListener(evt -> {
List<TraceBreakpoint> set = locationFilterPanel.getSelectedItems()
.stream()
.map(BreakpointLocationRow::getTraceBreakpoint)
.collect(Collectors.toList());
List<BreakpointLocationRow> sel = locationFilterPanel.getSelectedItems();
// Do this first to avoid overriding context in event chain
if (!set.isEmpty()) {
if (!sel.isEmpty()) {
breakpointTable.clearSelection();
breakpointTable.getSelectionManager().clearSavedSelection();
}
myActionContext = new DebuggerBreakpointLocationsActionContext(set);
myActionContext = new DebuggerBreakpointLocationsActionContext(sel);
contextChanged();
});
locationTable.addMouseListener(new MouseAdapter() {
@@ -966,10 +988,15 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
TableColumnModel bptColModel = breakpointTable.getColumnModel();
TableColumn bptEnCol =
bptColModel.getColumn(LogicalBreakpointTableColumns.ENABLED.ordinal());
bptEnCol.setCellRenderer(new DebuggerBreakpointEnablementTableCellRenderer());
bptColModel.getColumn(LogicalBreakpointTableColumns.STATE.ordinal());
bptEnCol.setCellRenderer(new DebuggerBreakpointStateTableCellRenderer());
bptEnCol.setCellEditor(
new DebuggerBreakpointEnablementTableCellEditor(breakpointFilterPanel));
new DebuggerBreakpointStateTableCellEditor<>(breakpointFilterPanel) {
@Override
protected State getToggledState(LogicalBreakpointRow row, State current) {
return current.getToggled(row.isMapped());
}
});
bptEnCol.setMaxWidth(24);
bptEnCol.setMinWidth(24);
TableColumn bptNameCol =
@@ -991,16 +1018,24 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
bptColModel.getColumn(LogicalBreakpointTableColumns.LOCATIONS.ordinal());
locsCol.setPreferredWidth(20);
TableColumnModel locColModel = locationTable.getColumnModel();
GTableColumnModel locColModel = (GTableColumnModel) locationTable.getColumnModel();
TableColumn locEnCol =
locColModel.getColumn(BreakpointLocationTableColumns.ENABLED.ordinal());
locEnCol.setCellRenderer(new DebuggerBreakpointLocEnabledTableCellRenderer());
locEnCol.setCellEditor(new DebuggerBreakpointLocEnabledTableCellEditor());
locColModel.getColumn(BreakpointLocationTableColumns.STATE.ordinal());
locEnCol.setCellRenderer(new DebuggerBreakpointStateTableCellRenderer());
locEnCol.setCellEditor(new DebuggerBreakpointStateTableCellEditor<>(locationFilterPanel) {
@Override
protected State getToggledState(BreakpointLocationRow row, State current) {
return current.getToggled(false);
}
});
locEnCol.setMaxWidth(24);
locEnCol.setMinWidth(24);
TableColumn locAddrCol =
locColModel.getColumn(BreakpointLocationTableColumns.ADDRESS.ordinal());
locAddrCol.setCellRenderer(CustomToStringCellRenderer.MONO_OBJECT);
TableColumn locThreadsCol =
locColModel.getColumn(BreakpointLocationTableColumns.THREADS.ordinal());
locColModel.setVisible(locThreadsCol, false);
}
protected void navigateToSelectedBreakpoint() {
@@ -16,18 +16,25 @@
package ghidra.app.plugin.core.debug.gui.breakpoint;
import java.util.Collection;
import java.util.stream.Collectors;
import docking.ActionContext;
import ghidra.app.services.LogicalBreakpoint;
public class DebuggerLogicalBreakpointsActionContext extends ActionContext {
private final Collection<LogicalBreakpoint> selection;
private final Collection<LogicalBreakpointRow> selection;
public DebuggerLogicalBreakpointsActionContext(Collection<LogicalBreakpoint> selection) {
public DebuggerLogicalBreakpointsActionContext(Collection<LogicalBreakpointRow> selection) {
this.selection = selection;
}
public Collection<LogicalBreakpoint> getSelection() {
public Collection<LogicalBreakpointRow> getSelection() {
return selection;
}
public Collection<LogicalBreakpoint> getBreakpoints() {
return selection.stream()
.map(row -> row.getLogicalBreakpoint())
.collect(Collectors.toList());
}
}
@@ -18,7 +18,8 @@ package ghidra.app.plugin.core.debug.gui.breakpoint;
import java.util.concurrent.CompletableFuture;
import ghidra.app.services.LogicalBreakpoint;
import ghidra.app.services.LogicalBreakpoint.Enablement;
import ghidra.app.services.LogicalBreakpoint.Mode;
import ghidra.app.services.LogicalBreakpoint.State;
import ghidra.framework.model.DomainFile;
import ghidra.framework.model.DomainObject;
import ghidra.program.model.address.Address;
@@ -43,23 +44,19 @@ public class LogicalBreakpointRow {
return lb;
}
public Enablement getEnablement() {
public State getState() {
return provider.isFilterByCurrentTrace() && provider.currentTrace != null
? lb.computeEnablementForTrace(provider.currentTrace)
: lb.computeEnablement();
? lb.computeStateForTrace(provider.currentTrace)
: lb.computeState();
}
public void setEnablement(Enablement en) {
assert en.consistent && en.effective;
setEnabled(en.enabled);
public void setState(State state) {
assert state.isNormal();
setEnabled(state.isEnabled());
}
public Boolean isEnabled() {
Enablement en = getEnablement();
if (!en.consistent) {
return null;
}
return en.enabled && en.effective;
public Mode getMode() {
return getState().mode;
}
public void setEnabled(boolean enabled) {
@@ -47,7 +47,7 @@ import resources.ResourceManager;
public class ObjectTree implements ObjectPane {
public static final ImageIcon ICON_TREE =
ResourceManager.loadImage("images/breakpoint-disable.png");
ResourceManager.loadImage("images/object-unpopulated.png");
private ObjectNode root;
private GTree tree;
@@ -19,6 +19,7 @@ import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import org.apache.commons.collections4.IteratorUtils;
@@ -33,6 +34,7 @@ import ghidra.app.plugin.core.debug.event.TraceClosedPluginEvent;
import ghidra.app.plugin.core.debug.event.TraceOpenedPluginEvent;
import ghidra.app.plugin.core.debug.service.breakpoint.LogicalBreakpointInternal.ProgramBreakpoint;
import ghidra.app.services.*;
import ghidra.app.services.LogicalBreakpoint.State;
import ghidra.dbg.target.TargetBreakpointLocation;
import ghidra.dbg.target.TargetObject;
import ghidra.dbg.util.PathUtils;
@@ -368,7 +370,7 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin
public AbstractInfo() {
}
protected abstract void dispose();
protected abstract void dispose(RemoveCollector r);
protected abstract LogicalBreakpointInternal createLogicalBreakpoint(Address address,
long length, Collection<TraceBreakpointKind> kinds);
@@ -489,12 +491,9 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin
}
@Override
protected void dispose() {
protected void dispose(RemoveCollector r) {
trace.removeListener(breakpointListener);
try (RemoveCollector r = new RemoveCollector(changeListeners.fire)) {
forgetAllBreakpoints(r);
}
forgetAllBreakpoints(r);
}
protected void reloadBreakpoints() {
@@ -559,7 +558,8 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin
trackTraceBreakpoint(b, collector, false);
}
catch (TrackedTooSoonException e) {
throw new AssertionError(e);
// This can still happen during reload (on OBJECT_RESTORED)
Msg.warn(this, "Might have lost track of a breakpoint: " + b);
}
}
}
@@ -592,7 +592,7 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin
lb = getOrCreateLogicalBreakpointFor(traceAddr, breakpoint, c);
}
assert breakpointsByAddress.get(traceAddr).contains(lb);
if (forceUpdate || lb.trackBreakpoint(breakpoint)) {
if (lb.trackBreakpoint(breakpoint) || forceUpdate) {
c.updated(lb);
}
}
@@ -691,12 +691,9 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin
}
@Override
protected void dispose() {
protected void dispose(RemoveCollector r) {
program.removeListener(breakpointListener);
try (RemoveCollector r = new RemoveCollector(changeListeners.fire)) {
forgetAllBreakpoints(r);
}
forgetAllBreakpoints(r);
}
protected void reloadBreakpoints() {
@@ -877,8 +874,11 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin
if (program instanceof TraceProgramView) {
return;
}
programInfos.remove(program).dispose();
// The mapping removals, if applicable, will clean up related traces
try (RemoveCollector r = new RemoveCollector(changeListeners.fire)) {
programInfos.remove(program).dispose(r);
}
// The mapping removals, if any, will clean up related traces
}
}
@@ -894,9 +894,20 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin
private void doUntrackTrace(Trace trace) {
synchronized (lock) {
InfoPerTrace info = traceInfos.remove(trace);
if (info != null) { // Could be from trace close or recorder stop
info.dispose();
InfoPerTrace tInfo = traceInfos.remove(trace);
if (tInfo == null) { // Could be from trace close or recorder stop
return;
}
try (RemoveCollector r = new RemoveCollector(changeListeners.fire)) {
tInfo.dispose(r);
for (InfoPerProgram pInfo : programInfos.values()) {
for (Set<LogicalBreakpointInternal> set : pInfo.breakpointsByAddress.values()) {
for (LogicalBreakpointInternal lb : set) {
lb.removeTrace(trace);
r.updated(lb);
}
}
}
}
}
}
@@ -1001,10 +1012,25 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin
if (info == null) {
return Set.of();
}
return doGetBreakpointsAt(info, address);
return doGetBreakpointsAt(info, address).stream()
.filter(lb -> lb.computeStateForTrace(trace) != State.NONE)
.collect(Collectors.toSet());
}
}
@Override
public LogicalBreakpoint getBreakpoint(TraceBreakpoint bpt) {
Trace trace = bpt.getTrace();
synchronized (lock) {
for (LogicalBreakpoint lb : getBreakpointsAt(trace, bpt.getMinAddress())) {
if (lb.getTraceBreakpoints(trace).contains(bpt)) {
return lb;
}
}
}
return null;
}
@Override
public Set<LogicalBreakpoint> getBreakpointsAt(ProgramLocation loc) {
return DebuggerLogicalBreakpointService.programOrTrace(loc,
@@ -1022,13 +1048,13 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin
changeListeners.remove(l);
}
@Override
public CompletableFuture<Void> placeBreakpointAt(Program program, Address address, long length,
Collection<TraceBreakpointKind> kinds, String name) {
protected MappedLogicalBreakpoint synthesizeLogicalBreakpoint(Program program, Address address,
long length, Collection<TraceBreakpointKind> kinds) {
/**
* TODO: This is quite a waste, but it gets the job done. The instance created here is
* dropped. It's just used for its breakpoint placement logic, part of which I had to
* re-implement here, anyway. The actual logical breakpoint is created by event processors.
* TODO: This is a bit of a waste, but it gets the job done. The instance created here is
* dropped by its caller. It's just used for its breakpoint placement logic, part of which I
* had to re-implement here, anyway. The actual logical breakpoint is created by event
* processors.
*/
MappedLogicalBreakpoint lb = new MappedLogicalBreakpoint(program, address, length, kinds);
synchronized (lock) {
@@ -1040,21 +1066,36 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin
lb.setTraceAddress(ti.recorder, loc.getAddress());
}
}
return lb;
}
@Override
public CompletableFuture<Void> placeBreakpointAt(Program program, Address address, long length,
Collection<TraceBreakpointKind> kinds, String name) {
MappedLogicalBreakpoint lb = synthesizeLogicalBreakpoint(program, address, length, kinds);
return lb.enableWithName(name);
}
@Override
public CompletableFuture<Void> placeBreakpointAt(Trace trace, Address address, long length,
Collection<TraceBreakpointKind> kinds) {
Collection<TraceBreakpointKind> kinds, String name) {
TraceRecorder recorder = modelService.getRecorder(trace);
if (recorder == null) {
throw new IllegalArgumentException("Given trace is not live");
}
/**
* TODO: This is similarly wasteful, but given the complexity of the breakpoint placement
* logic it offers, this works really well, and is probably justified.
*/
return new LoneLogicalBreakpoint(recorder, address, length, kinds).enableForTrace(trace);
ProgramLocation staticLocation = mappingService.getOpenMappedLocation(
new DefaultTraceLocation(trace, null, Range.singleton(recorder.getSnap()), address));
if (staticLocation == null) {
return new LoneLogicalBreakpoint(recorder, address, length, kinds)
.enableForTrace(trace);
}
MappedLogicalBreakpoint lb = new MappedLogicalBreakpoint(staticLocation.getProgram(),
staticLocation.getAddress(), length, kinds);
lb.setTraceAddress(recorder, address);
lb.enableForProgramWithName(name);
return lb.enableForTrace(trace);
}
@Override
@@ -1062,7 +1103,7 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin
Collection<TraceBreakpointKind> kinds, String name) {
return DebuggerLogicalBreakpointService.programOrTrace(loc,
(p, a) -> placeBreakpointAt(p, a, length, kinds, name),
(t, a) -> placeBreakpointAt(t, a, length, kinds));
(t, a) -> placeBreakpointAt(t, a, length, kinds, name));
}
protected CompletableFuture<Void> actOnAll(Collection<LogicalBreakpoint> col, Trace trace,
@@ -1070,7 +1111,8 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin
BiConsumer<BreakpointActionSet, LogicalBreakpointInternal> consumerForTarget) {
BreakpointActionSet actions = new BreakpointActionSet();
for (LogicalBreakpoint lb : col) {
if (trace == null) {
Set<Trace> participants = lb.getParticipatingTraces();
if (trace == null || participants.isEmpty() || participants.equals(Set.of(trace))) {
consumerForProgram.accept(lb);
}
if (!(lb instanceof LogicalBreakpointInternal)) {
@@ -1096,14 +1138,23 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin
@Override
public CompletableFuture<Void> deleteAll(Collection<LogicalBreakpoint> col, Trace trace) {
return actOnAll(col, trace, LogicalBreakpoint::deleteForProgram,
(actions, lbi) -> lbi.planDelete(actions, trace));
return actOnAll(col, trace, lb -> {
// Do not delete bookmark from dynamic context
if (trace == null) {
lb.deleteForProgram();
}
}, (actions, lbi) -> lbi.planDelete(actions, trace));
}
protected CompletableFuture<Void> actOnLocs(Collection<TraceBreakpoint> col,
BiConsumer<BreakpointActionSet, TargetBreakpointLocation> consumer) {
BiConsumer<BreakpointActionSet, TargetBreakpointLocation> locConsumer,
Consumer<LogicalBreakpoint> progConsumer) {
BreakpointActionSet actions = new BreakpointActionSet();
for (TraceBreakpoint tb : col) {
LogicalBreakpoint lb = getBreakpoint(tb);
if (col.containsAll(lb.getTraceBreakpoints())) {
progConsumer.accept(lb);
}
TraceRecorder recorder = modelService.getRecorder(tb.getTrace());
if (recorder == null) {
continue;
@@ -1115,24 +1166,27 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin
continue;
}
TargetBreakpointLocation loc = (TargetBreakpointLocation) object;
consumer.accept(actions, loc);
locConsumer.accept(actions, loc);
}
return actions.execute();
}
@Override
public CompletableFuture<Void> enableLocs(Collection<TraceBreakpoint> col) {
return actOnLocs(col, BreakpointActionSet::planEnable);
return actOnLocs(col, BreakpointActionSet::planEnable, LogicalBreakpoint::enableForProgram);
}
@Override
public CompletableFuture<Void> disableLocs(Collection<TraceBreakpoint> col) {
return actOnLocs(col, BreakpointActionSet::planDisable);
return actOnLocs(col, BreakpointActionSet::planDisable,
LogicalBreakpoint::disableForProgram);
}
@Override
public CompletableFuture<Void> deleteLocs(Collection<TraceBreakpoint> col) {
return actOnLocs(col, BreakpointActionSet::planDelete);
return actOnLocs(col, BreakpointActionSet::planDelete, lb -> {
// Never delete bookmark when user requests deleting locations
});
}
@Override
@@ -134,15 +134,15 @@ public interface LogicalBreakpointInternal extends LogicalBreakpoint {
}
}
public ProgramEnablement computeEnablement() {
public ProgramMode computeMode() {
if (eBookmark != null) {
return ProgramEnablement.ENABLED;
return ProgramMode.ENABLED;
}
if (dBookmark != null) {
return ProgramEnablement.DISABLED;
return ProgramMode.DISABLED;
}
else {
return ProgramEnablement.MISSING;
return ProgramMode.MISSING;
}
}
@@ -233,11 +233,11 @@ public interface LogicalBreakpointInternal extends LogicalBreakpoint {
}
public boolean isEnabled() {
return computeEnablement() == ProgramEnablement.ENABLED;
return computeMode() == ProgramMode.ENABLED;
}
public boolean isDisabled() {
return computeEnablement() == ProgramEnablement.DISABLED;
return computeMode() == ProgramMode.DISABLED;
}
public String computeCategory() {
@@ -313,19 +313,22 @@ public interface LogicalBreakpointInternal extends LogicalBreakpoint {
}
public Address computeTargetAddress() {
// TODO: Can this change? If not, can compute in constructor.
return recorder.getMemoryMapper().traceToTarget(address);
}
public TraceEnablement computeEnablement() {
TraceEnablement en = TraceEnablement.MISSING;
public TraceMode computeMode() {
TraceMode mode = TraceMode.NONE;
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
en = en.combine(TraceEnablement.fromBool(bpt.obj.isEnabled(recorder.getSnap())));
if (en == TraceEnablement.MIXED) {
return en;
mode = mode.combine(computeMode(bpt.obj));
if (mode == TraceMode.MISSING) {
return mode;
}
}
return en;
return mode;
}
public TraceMode computeMode(TraceBreakpoint bpt) {
return TraceMode.fromBool(bpt.isEnabled(recorder.getSnap()));
}
public boolean isEmpty() {
@@ -446,6 +449,16 @@ public interface LogicalBreakpointInternal extends LogicalBreakpoint {
*/
void setTraceAddress(TraceRecorder recorder, Address address);
/**
* Remove the given trace from this set
*
* <p>
* This happens when a trace's recorder stops or when a trace is closed.
*
* @param trace the trace no longer participating
*/
void removeTrace(Trace trace);
boolean canMerge(Program program, Bookmark bookmark);
/**
@@ -89,6 +89,11 @@ public class LoneLogicalBreakpoint implements LogicalBreakpointInternal {
throw new AssertionError();
}
@Override
public void removeTrace(Trace trace) {
throw new AssertionError();
}
@Override
public Set<TraceBreakpoint> getTraceBreakpoints() {
return new HashSet<>(breaks.getBreakpoints());
@@ -131,21 +136,29 @@ public class LoneLogicalBreakpoint implements LogicalBreakpointInternal {
}
@Override
public Enablement computeEnablementForProgram(Program program) {
return Enablement.NONE;
public State computeStateForProgram(Program program) {
return State.NONE;
}
@Override
public Enablement computeEnablementForTrace(Trace trace) {
public State computeStateForTrace(Trace trace) {
if (trace != breaks.getTrace()) {
return Enablement.NONE;
return State.NONE;
}
return ProgramEnablement.NONE.combineTrace(breaks.computeEnablement());
return ProgramMode.NONE.combineTrace(breaks.computeMode(), Perspective.TRACE);
}
@Override
public Enablement computeEnablement() {
return ProgramEnablement.NONE.combineTrace(breaks.computeEnablement());
public State computeStateForLocation(TraceBreakpoint loc) {
if (!breaks.getBreakpoints().contains(loc)) {
return State.NONE;
}
return ProgramMode.NONE.combineTrace(breaks.computeMode(loc), Perspective.TRACE);
}
@Override
public State computeState() {
return ProgramMode.NONE.combineTrace(breaks.computeMode(), Perspective.LOGICAL);
}
@Override
@@ -40,7 +40,6 @@ public class MappedLogicalBreakpoint implements LogicalBreakpointInternal {
// Debuggers tend to allow multiple breakpoints (even of the same kind) at the same address
// They may have different names and/or different conditions
private final Map<Trace, TraceBreakpointSet> traceBreaks = new HashMap<>();
private final Set<Trace> tracesView = Collections.unmodifiableSet(traceBreaks.keySet());
protected MappedLogicalBreakpoint(Program program, Address progAddr, long length,
Collection<TraceBreakpointKind> kinds) {
@@ -51,8 +50,10 @@ public class MappedLogicalBreakpoint implements LogicalBreakpointInternal {
@Override
public String toString() {
return String.format("<%s prog=%s, traces=%s>", getClass().getSimpleName(), progBreak,
traceBreaks.values());
synchronized (traceBreaks) {
return String.format("<%s prog=%s, traces=%s>", getClass().getSimpleName(), progBreak,
traceBreaks.values());
}
}
protected boolean hasProgramBreakpoint() {
@@ -64,9 +65,11 @@ public class MappedLogicalBreakpoint implements LogicalBreakpointInternal {
if (!progBreak.isEmpty()) {
return false;
}
for (TraceBreakpointSet breaks : traceBreaks.values()) {
if (!breaks.isEmpty()) {
return false;
synchronized (traceBreaks) {
for (TraceBreakpointSet breaks : traceBreaks.values()) {
if (!breaks.isEmpty()) {
return false;
}
}
}
return true;
@@ -100,6 +103,10 @@ public class MappedLogicalBreakpoint implements LogicalBreakpointInternal {
progBreak.enable();
}
public void enableForProgramWithName(String name) {
progBreak.enableWithComment(name);
}
@Override
public void disableForProgram() {
progBreak.disable();
@@ -113,7 +120,10 @@ public class MappedLogicalBreakpoint implements LogicalBreakpointInternal {
@Override
public CompletableFuture<Void> enableForTrace(Trace trace) {
BreakpointActionSet actions = new BreakpointActionSet();
TraceBreakpointSet breaks = traceBreaks.get(trace);
TraceBreakpointSet breaks;
synchronized (traceBreaks) {
breaks = traceBreaks.get(trace);
}
if (breaks == null) {
return AsyncUtils.NIL;
}
@@ -124,7 +134,10 @@ public class MappedLogicalBreakpoint implements LogicalBreakpointInternal {
@Override
public CompletableFuture<Void> disableForTrace(Trace trace) {
BreakpointActionSet actions = new BreakpointActionSet();
TraceBreakpointSet breaks = traceBreaks.get(trace);
TraceBreakpointSet breaks;
synchronized (traceBreaks) {
breaks = traceBreaks.get(trace);
}
if (breaks == null) {
return AsyncUtils.NIL;
}
@@ -135,7 +148,10 @@ public class MappedLogicalBreakpoint implements LogicalBreakpointInternal {
@Override
public CompletableFuture<Void> deleteForTrace(Trace trace) {
BreakpointActionSet actions = new BreakpointActionSet();
TraceBreakpointSet breaks = traceBreaks.get(trace);
TraceBreakpointSet breaks;
synchronized (traceBreaks) {
breaks = traceBreaks.get(trace);
}
if (breaks == null) {
return AsyncUtils.NIL;
}
@@ -146,15 +162,20 @@ public class MappedLogicalBreakpoint implements LogicalBreakpointInternal {
@Override
public void planEnable(BreakpointActionSet actions, Trace trace) {
if (trace != null) {
TraceBreakpointSet breaks = traceBreaks.get(trace);
TraceBreakpointSet breaks;
synchronized (traceBreaks) {
breaks = traceBreaks.get(trace);
}
if (breaks == null) {
return;
}
breaks.planEnable(actions, length, kinds);
return;
}
for (TraceBreakpointSet breaks : traceBreaks.values()) {
breaks.planEnable(actions, length, kinds);
synchronized (traceBreaks) {
for (TraceBreakpointSet breaks : traceBreaks.values()) {
breaks.planEnable(actions, length, kinds);
}
}
}
@@ -167,28 +188,33 @@ public class MappedLogicalBreakpoint implements LogicalBreakpointInternal {
public CompletableFuture<Void> enableWithName(String name) {
// TODO: Consider more fields than name in comment
progBreak.enableWithComment(name);
enableForProgramWithName(name);
return enableForTraces();
}
@Override
public CompletableFuture<Void> enable() {
progBreak.enable();
enableForProgram();
return enableForTraces();
}
@Override
public void planDisable(BreakpointActionSet actions, Trace trace) {
if (trace != null) {
TraceBreakpointSet breaks = traceBreaks.get(trace);
TraceBreakpointSet breaks;
synchronized (traceBreaks) {
breaks = traceBreaks.get(trace);
}
if (breaks == null) {
return;
}
breaks.planDisable(actions, length, kinds);
return;
}
for (TraceBreakpointSet breaks : traceBreaks.values()) {
breaks.planDisable(actions, length, kinds);
synchronized (traceBreaks) {
for (TraceBreakpointSet breaks : traceBreaks.values()) {
breaks.planDisable(actions, length, kinds);
}
}
}
@@ -204,15 +230,20 @@ public class MappedLogicalBreakpoint implements LogicalBreakpointInternal {
@Override
public void planDelete(BreakpointActionSet actions, Trace trace) {
if (trace != null) {
TraceBreakpointSet breaks = traceBreaks.get(trace);
TraceBreakpointSet breaks;
synchronized (traceBreaks) {
breaks = traceBreaks.get(trace);
}
if (breaks == null) {
return;
}
breaks.planDelete(actions, length, kinds);
return;
}
for (TraceBreakpointSet breaks : traceBreaks.values()) {
breaks.planDelete(actions, length, kinds);
synchronized (traceBreaks) {
for (TraceBreakpointSet breaks : traceBreaks.values()) {
breaks.planDelete(actions, length, kinds);
}
}
}
@@ -247,44 +278,65 @@ public class MappedLogicalBreakpoint implements LogicalBreakpointInternal {
@Override
public void setTraceAddress(TraceRecorder recorder, Address address) {
traceBreaks.put(recorder.getTrace(), new TraceBreakpointSet(recorder, address));
synchronized (traceBreaks) {
traceBreaks.put(recorder.getTrace(), new TraceBreakpointSet(recorder, address));
}
}
@Override
public void removeTrace(Trace trace) {
synchronized (traceBreaks) {
traceBreaks.remove(trace);
}
}
@Override
public Set<TraceBreakpoint> getTraceBreakpoints() {
Set<TraceBreakpoint> result = new HashSet<>();
for (TraceBreakpointSet breaks : traceBreaks.values()) {
result.addAll(breaks.getBreakpoints());
synchronized (traceBreaks) {
for (TraceBreakpointSet breaks : traceBreaks.values()) {
result.addAll(breaks.getBreakpoints());
}
}
return result;
}
@Override
public Set<TraceBreakpoint> getTraceBreakpoints(Trace trace) {
TraceBreakpointSet breaks = traceBreaks.get(trace);
TraceBreakpointSet breaks;
synchronized (traceBreaks) {
breaks = traceBreaks.get(trace);
}
return breaks == null ? Set.of() : new HashSet<>(breaks.getBreakpoints());
}
@Override
public Set<Trace> getMappedTraces() {
return tracesView;
synchronized (traceBreaks) {
return Set.copyOf(traceBreaks.keySet());
}
}
@Override
public Set<Trace> getParticipatingTraces() {
Set<Trace> result = new HashSet<>();
for (TraceBreakpointSet breaks : traceBreaks.values()) {
if (breaks.isEmpty()) {
continue;
synchronized (traceBreaks) {
for (TraceBreakpointSet breaks : traceBreaks.values()) {
if (breaks.isEmpty()) {
continue;
}
result.add(breaks.getTrace());
}
result.add(breaks.getTrace());
}
return result;
}
@Override
public Address getTraceAddress(Trace trace) {
TraceBreakpointSet breaks = traceBreaks.get(trace);
TraceBreakpointSet breaks;
synchronized (traceBreaks) {
breaks = traceBreaks.get(trace);
}
if (breaks == null) {
return null;
}
@@ -312,36 +364,61 @@ public class MappedLogicalBreakpoint implements LogicalBreakpointInternal {
}
@Override
public Enablement computeEnablementForProgram(Program program) {
public State computeStateForProgram(Program program) {
if (progBreak.getProgram() != program) {
return Enablement.NONE;
return State.NONE;
}
return computeEnablement();
return computeState();
}
@Override
public Enablement computeEnablementForTrace(Trace trace) {
TraceBreakpointSet breaks = traceBreaks.get(trace);
ProgramEnablement progEn = progBreak.computeEnablement();
if (breaks == null) {
return TraceEnablement.MISSING.combineProgram(progEn);
public State computeStateForTrace(Trace trace) {
TraceBreakpointSet breaks;
synchronized (traceBreaks) {
breaks = traceBreaks.get(trace);
}
// NB: Order matters. Trace is primary
return breaks.computeEnablement().combineProgram(progEn);
ProgramMode progMode = progBreak.computeMode();
TraceMode traceMode = breaks == null ? TraceMode.NONE : breaks.computeMode();
return progMode.combineTrace(traceMode, Perspective.TRACE);
}
protected TraceMode computeTraceModeForLocation(TraceBreakpoint loc) {
TraceBreakpointSet breaks;
synchronized (traceBreaks) {
breaks = traceBreaks.get(loc.getTrace());
}
if (breaks == null || !breaks.getBreakpoints().contains(loc)) {
return TraceMode.NONE;
}
return breaks.computeMode(loc);
}
@Override
public Enablement computeEnablement() {
ProgramEnablement progEn = progBreak.computeEnablement();
TraceEnablement traceEn = TraceEnablement.NONE;
for (TraceBreakpointSet breaks : traceBreaks.values()) {
TraceEnablement tEn = breaks.computeEnablement();
traceEn = traceEn.combine(tEn);
if (traceEn == TraceEnablement.MIXED) {
break;
public State computeStateForLocation(TraceBreakpoint loc) {
ProgramMode progMode = progBreak.computeMode();
TraceMode traceMode = computeTraceModeForLocation(loc);
return progMode.combineTrace(traceMode, Perspective.TRACE);
}
protected TraceMode computeTraceMode() {
TraceMode traceMode = TraceMode.NONE;
synchronized (traceBreaks) {
for (TraceBreakpointSet breaks : traceBreaks.values()) {
TraceMode tm = breaks.computeMode();
traceMode = traceMode.combine(tm);
if (traceMode == TraceMode.MISSING) {
break;
}
}
}
return progEn.combineTrace(traceEn);
return traceMode;
}
@Override
public State computeState() {
ProgramMode progMode = progBreak.computeMode();
TraceMode traceMode = computeTraceMode();
return progMode.combineTrace(traceMode, Perspective.LOGICAL);
}
@Override
@@ -351,7 +428,10 @@ public class MappedLogicalBreakpoint implements LogicalBreakpointInternal {
@Override
public boolean canMerge(TraceBreakpoint breakpoint) throws TrackedTooSoonException {
TraceBreakpointSet breaks = traceBreaks.get(breakpoint.getTrace());
TraceBreakpointSet breaks;
synchronized (traceBreaks) {
breaks = traceBreaks.get(breakpoint.getTrace());
}
if (breaks == null) {
/**
* This happens when the trace is first added to the manager, between the listener being
@@ -377,10 +457,25 @@ public class MappedLogicalBreakpoint implements LogicalBreakpointInternal {
return progBreak.add(bookmark);
}
protected void makeBookmarkConsistent() {
TraceMode traceMode = computeTraceMode();
if (traceMode == TraceMode.ENABLED) {
progBreak.enable();
}
else if (traceMode == TraceMode.DISABLED) {
progBreak.disable();
}
}
@Override
public boolean trackBreakpoint(TraceBreakpoint breakpoint) {
TraceBreakpointSet breaks = traceBreaks.get(breakpoint.getTrace());
return breaks.add(breakpoint);
TraceBreakpointSet breaks;
synchronized (traceBreaks) {
breaks = traceBreaks.get(breakpoint.getTrace());
}
boolean result = breaks.add(breakpoint);
makeBookmarkConsistent();
return result;
}
@Override
@@ -391,11 +486,16 @@ public class MappedLogicalBreakpoint implements LogicalBreakpointInternal {
@Override
public boolean untrackBreakpoint(TraceBreakpoint breakpoint) {
TraceBreakpointSet breaks = traceBreaks.get(breakpoint.getTrace());
TraceBreakpointSet breaks;
synchronized (traceBreaks) {
breaks = traceBreaks.get(breakpoint.getTrace());
}
if (breaks == null) {
return false;
}
return breaks.remove(breakpoint);
boolean result = breaks.remove(breakpoint);
makeBookmarkConsistent();
return result;
}
public boolean appliesTo(Program program) {
@@ -403,7 +503,10 @@ public class MappedLogicalBreakpoint implements LogicalBreakpointInternal {
}
public boolean appliesTo(Trace trace) {
TraceBreakpointSet breaks = traceBreaks.get(Objects.requireNonNull(trace));
TraceBreakpointSet breaks;
synchronized (traceBreaks) {
breaks = traceBreaks.get(Objects.requireNonNull(trace));
}
return !breaks.isEmpty();
}
}
@@ -20,7 +20,7 @@ import java.util.concurrent.CompletableFuture;
import java.util.function.BiFunction;
import ghidra.app.plugin.core.debug.service.breakpoint.DebuggerLogicalBreakpointServicePlugin;
import ghidra.app.services.LogicalBreakpoint.Enablement;
import ghidra.app.services.LogicalBreakpoint.State;
import ghidra.framework.plugintool.ServiceInfo;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;
@@ -90,6 +90,18 @@ public interface DebuggerLogicalBreakpointService {
*/
Set<LogicalBreakpoint> getBreakpointsAt(Trace trace, Address address);
/**
* Get the logical breakpoint of which the given trace breakpoint is a part
*
* <p>
* If the given trace breakpoint is not part of any logical breakpoint, e.g., because it is not
* on a live target, then null is returned.
*
* @param bpt the trace breakpoint
* @return the logical breakpoint, or null
*/
LogicalBreakpoint getBreakpoint(TraceBreakpoint bpt);
/**
* Get the collected logical breakpoints (at present) at the given location.
*
@@ -146,39 +158,45 @@ public interface DebuggerLogicalBreakpointService {
return progFunc.apply(progOrView, loc.getByteAddress());
}
default Enablement computeEnablement(Collection<LogicalBreakpoint> col) {
Enablement en = Enablement.NONE;
default State computeState(Collection<LogicalBreakpoint> col) {
State state = State.NONE;
for (LogicalBreakpoint lb : col) {
en = en.sameAdddress(lb.computeEnablement());
state = state.sameAdddress(lb.computeState());
}
return en;
return state;
}
default Enablement computeEnablement(Collection<LogicalBreakpoint> col, Program program) {
Enablement en = Enablement.NONE;
default State computeState(Collection<LogicalBreakpoint> col, Program program) {
State state = State.NONE;
for (LogicalBreakpoint lb : col) {
en = en.sameAdddress(lb.computeEnablementForProgram(program));
state = state.sameAdddress(lb.computeStateForProgram(program));
}
return en;
return state;
}
default Enablement computeEnablement(Collection<LogicalBreakpoint> col, Trace trace) {
Enablement en = Enablement.NONE;
default State computeState(Collection<LogicalBreakpoint> col, Trace trace) {
State state = State.NONE;
for (LogicalBreakpoint lb : col) {
en = en.sameAdddress(lb.computeEnablementForTrace(trace));
state = state.sameAdddress(lb.computeStateForTrace(trace));
}
return en;
return state;
}
default Enablement computeEnablement(Collection<LogicalBreakpoint> col, ProgramLocation loc) {
default State computeState(Collection<LogicalBreakpoint> col, ProgramLocation loc) {
return programOrTrace(loc,
(p, a) -> computeEnablement(col, p),
(t, a) -> computeEnablement(col, t));
(p, a) -> computeState(col, p),
(t, a) -> computeState(col, t));
}
default Enablement computeEnablement(ProgramLocation loc) {
/**
* Compute the state for a given address and program or trace view
*
* @param loc the location
* @return the breakpoint state
*/
default State computeState(ProgramLocation loc) {
Set<LogicalBreakpoint> col = getBreakpointsAt(loc);
return computeEnablement(col, loc);
return computeState(col, loc);
}
default boolean anyMapped(Collection<LogicalBreakpoint> col, Trace trace) {
@@ -222,11 +240,11 @@ public interface DebuggerLogicalBreakpointService {
Collection<TraceBreakpointKind> kinds, String name);
/**
* Create an enabled breakpoint at the given trace location only.
* Create an enabled breakpoint at the given trace location and its mapped program location.
*
* <p>
* If the given location is mapped to a static module, this still only creates the breakpoint in
* the given trace. However, a logical breakpoint mark will appear at all mapped locations.
* If the breakpoint has no static location, then only the trace location is placed. Note, if
* this is the case, the breakpoint will have no name.
*
* <p>
* Note, the debugger ultimately determines the placement behavior. If it is managing multiple
@@ -238,10 +256,11 @@ public interface DebuggerLogicalBreakpointService {
* @param address the address in the trace (as viewed in the present)
* @param length size of the breakpoint, may be ignored by debugger
* @param kinds the kinds of breakpoint
* @param name a name for the breakpoint
* @return a future which completes when the breakpoint has been placed
*/
CompletableFuture<Void> placeBreakpointAt(Trace trace, Address address, long length,
Collection<TraceBreakpointKind> kinds);
Collection<TraceBreakpointKind> kinds, String name);
/**
* Create an enabled breakpoint at the given location.
File diff suppressed because it is too large Load Diff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 353 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 302 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Some files were not shown because too many files have changed in this diff Show More