GP-1821: Reword breakpoint states, toggles, and icons
@@ -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 — 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>
|
||||
|
||||
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 63 KiB |
|
Before Width: | Height: | Size: 365 B After Width: | Height: | Size: 665 B |
|
Before Width: | Height: | Size: 295 B After Width: | Height: | Size: 684 B |
|
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 — 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 — 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 — the specification expression by default. This
|
||||
<LI>Comment - gives a user comment — 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>
|
||||
|
||||
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 665 B |
|
Before Width: | Height: | Size: 295 B After Width: | Height: | Size: 684 B |
|
After Width: | Height: | Size: 513 B |
|
Before Width: | Height: | Size: 269 B After Width: | Height: | Size: 561 B |
|
Before Width: | Height: | Size: 353 B |
|
Before Width: | Height: | Size: 302 B |
|
Before Width: | Height: | Size: 368 B |
|
Before Width: | Height: | Size: 373 B |
|
After Width: | Height: | Size: 681 B |
|
After Width: | Height: | Size: 305 B |
|
Before Width: | Height: | Size: 504 B After Width: | Height: | Size: 732 B |
|
Before Width: | Height: | Size: 420 B After Width: | Height: | Size: 732 B |
|
Before Width: | Height: | Size: 329 B After Width: | Height: | Size: 626 B |
|
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.
|
||||
|
||||
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 353 B |
|
Before Width: | Height: | Size: 302 B |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |