GP-6799: Improve display of breakpiont 'kinds' in the UI. Also shorter db/protocol encoding.

This commit is contained in:
Dan
2026-05-13 14:02:44 +00:00
parent 5b61b4fe6c
commit c7e16dd527
62 changed files with 492 additions and 514 deletions
@@ -1076,10 +1076,10 @@ def put_single_breakpoint(bp, ibobj, nproc: int, ikeys: List[str]) -> None:
if bp.GetType()[0] == DbgEng.DEBUG_BREAKPOINT_DATA:
width, prot = bp.GetDataParameters()
width = str(width)
prot = {4: 'HW_EXECUTE', 2: 'READ', 1: 'WRITE'}[prot]
prot = {4: 'X', 2: 'R', 1: 'W'}[prot]
else:
width = ' '
prot = 'SW_EXECUTE'
prot = 'x'
if address is not None: # Implies execution break
base, addr = mapper.map(nproc, address)
@@ -1101,22 +1101,22 @@ def put_single_breakpoint(b: gdb.Breakpoint, ibobj: TraceObject,
brkobj.set_value('Enabled', b.enabled)
if b.type == gdb.BP_BREAKPOINT:
brkobj.set_value('Expression', b.location)
brkobj.set_value('Kinds', 'SW_EXECUTE')
brkobj.set_value('Kinds', 'x')
elif b.type == gdb.BP_HARDWARE_BREAKPOINT:
brkobj.set_value('Expression', b.location)
brkobj.set_value('Kinds', 'HW_EXECUTE')
brkobj.set_value('Kinds', 'X')
elif b.type == gdb.BP_WATCHPOINT:
brkobj.set_value('Expression', b.expression)
brkobj.set_value('Kinds', 'WRITE')
brkobj.set_value('Kinds', 'W')
elif b.type == gdb.BP_HARDWARE_WATCHPOINT:
brkobj.set_value('Expression', b.expression)
brkobj.set_value('Kinds', 'WRITE')
brkobj.set_value('Kinds', 'W')
elif b.type == gdb.BP_READ_WATCHPOINT:
brkobj.set_value('Expression', b.expression)
brkobj.set_value('Kinds', 'READ')
brkobj.set_value('Kinds', 'R')
elif b.type == gdb.BP_ACCESS_WATCHPOINT:
brkobj.set_value('Expression', b.expression)
brkobj.set_value('Kinds', 'READ,WRITE')
brkobj.set_value('Kinds', 'RW')
else:
brkobj.set_value('Expression', '(unknown)')
brkobj.set_value('Kinds', '')
@@ -1536,10 +1536,10 @@ def put_single_breakpoint(b: lldb.SBBreakpoint, proc: lldb.SBProcess) -> None:
bpt_obj = trace.create_object(bpt_path)
if b.IsHardware():
bpt_obj.set_value('Expression', util.get_description(b))
bpt_obj.set_value('Kinds', 'HW_EXECUTE')
bpt_obj.set_value('Kinds', 'X')
else:
bpt_obj.set_value('Expression', util.get_description(b))
bpt_obj.set_value('Kinds', 'SW_EXECUTE')
bpt_obj.set_value('Kinds', 'x')
cmdList = lldb.SBStringList()
if b.GetCommandLineCommands(cmdList):
list = []
@@ -1580,11 +1580,11 @@ def put_single_watchpoint(w: lldb.SBWatchpoint, proc: lldb.SBProcess) -> None:
wpt_obj = trace.create_object(wpt_path)
desc = util.get_description(w, level=0)
wpt_obj.set_value('Expression', desc)
wpt_obj.set_value('Kinds', 'WRITE')
wpt_obj.set_value('Kinds', 'W')
if "type = r" in desc:
wpt_obj.set_value('Kinds', 'READ')
wpt_obj.set_value('Kinds', 'R')
if "type = rw" in desc:
wpt_obj.set_value('Kinds', 'READ,WRITE')
wpt_obj.set_value('Kinds', 'RW')
base, addr = mapper.map(proc, w.GetWatchAddress())
if base != addr.space:
trace.create_overlay_space(base, addr.space)
@@ -967,12 +967,12 @@ def put_single_breakpoint(bp, bpath, nproc: int, ikeys: List[int]) -> None:
brkobj.set_value('Range', addr.extend(bp.hwSize))
brkobj.set_value('HitCount', bp.hitCount)
if bp.type == BreakpointType.BpNormal:
brkobj.set_value('Kinds', 'SW_EXECUTE')
brkobj.set_value('Kinds', 'x')
if bp.type == BreakpointType.BpHardware:
prot = {0: 'READ', 1: 'WRITE', 2: 'HW_EXECUTE'}[bp.typeEx]
prot = {0: 'R', 1: 'W', 2: 'X'}[bp.typeEx]
brkobj.set_value('Kinds', prot)
if bp.type == BreakpointType.BpMemory:
prot = {0: 'READ', 1: 'WRITE', 2: 'HW_EXECUTE', 3: 'ACCESS'}[bp.typeEx]
prot = {0: 'R', 1: 'W', 2: 'X', 3: 'RW'}[bp.typeEx]
brkobj.set_value('Kinds', prot)
brkobj.insert()
@@ -45,6 +45,7 @@ import ghidra.program.model.lang.*;
import ghidra.program.model.listing.Program;
import ghidra.program.util.ProgramLocation;
import ghidra.trace.model.*;
import ghidra.trace.model.breakpoint.TraceBreakpointKind.CommonSet;
import ghidra.trace.model.breakpoint.TraceBreakpointKind.TraceBreakpointKindSet;
import ghidra.trace.model.guest.TracePlatform;
import ghidra.trace.model.memory.TraceMemoryOperations;
@@ -2174,7 +2175,7 @@ public interface FlatDebuggerAPI {
*/
default Set<LogicalBreakpoint> breakpointSetSoftwareExecute(ProgramLocation location,
String name) {
return breakpointSet(location, 1, TraceBreakpointKindSet.SW_EXECUTE, name);
return breakpointSet(location, 1, CommonSet.SWX.kinds(), name);
}
/**
@@ -2187,7 +2188,7 @@ public interface FlatDebuggerAPI {
*/
default Set<LogicalBreakpoint> breakpointSetHardwareExecute(ProgramLocation location,
String name) {
return breakpointSet(location, 1, TraceBreakpointKindSet.HW_EXECUTE, name);
return breakpointSet(location, 1, CommonSet.HWX.kinds(), name);
}
/**
@@ -2204,7 +2205,7 @@ public interface FlatDebuggerAPI {
*/
default Set<LogicalBreakpoint> breakpointSetRead(ProgramLocation location, int length,
String name) {
return breakpointSet(location, length, TraceBreakpointKindSet.READ, name);
return breakpointSet(location, length, CommonSet.READ.kinds(), name);
}
/**
@@ -2221,7 +2222,7 @@ public interface FlatDebuggerAPI {
*/
default Set<LogicalBreakpoint> breakpointSetWrite(ProgramLocation location, int length,
String name) {
return breakpointSet(location, length, TraceBreakpointKindSet.WRITE, name);
return breakpointSet(location, length, CommonSet.WRITE.kinds(), name);
}
/**
@@ -2238,7 +2239,7 @@ public interface FlatDebuggerAPI {
*/
default Set<LogicalBreakpoint> breakpointSetAccess(ProgramLocation location, int length,
String name) {
return breakpointSet(location, length, TraceBreakpointKindSet.ACCESS, name);
return breakpointSet(location, length, CommonSet.ACCESS.kinds(), name);
}
/**
@@ -48,7 +48,7 @@ import ghidra.program.model.lang.Register;
import ghidra.program.model.lang.RegisterValue;
import ghidra.trace.model.*;
import ghidra.trace.model.breakpoint.*;
import ghidra.trace.model.breakpoint.TraceBreakpointKind.TraceBreakpointKindSet;
import ghidra.trace.model.breakpoint.TraceBreakpointKind.CommonSet;
import ghidra.trace.model.guest.TracePlatform;
import ghidra.trace.model.memory.*;
import ghidra.trace.model.stack.TraceStack;
@@ -1542,21 +1542,21 @@ public class TraceRmiTarget extends AbstractTarget {
public CompletableFuture<Void> placeBreakpointAsync(AddressRange range,
Set<TraceBreakpointKind> kinds, String condition, String commands) {
Set<TraceBreakpointKind> copyKinds = Set.copyOf(kinds);
if (copyKinds.equals(TraceBreakpointKindSet.HW_EXECUTE)) {
if (copyKinds.equals(CommonSet.HWX.kinds())) {
return placeHwExecBreakAsync(expectSingleAddr(range, TraceBreakpointKind.HW_EXECUTE),
condition, commands);
}
if (copyKinds.equals(TraceBreakpointKindSet.SW_EXECUTE)) {
if (copyKinds.equals(CommonSet.SWX.kinds())) {
return placeSwExecBreakAsync(expectSingleAddr(range, TraceBreakpointKind.SW_EXECUTE),
condition, commands);
}
if (copyKinds.equals(TraceBreakpointKindSet.READ)) {
if (copyKinds.equals(CommonSet.READ.kinds())) {
return placeReadBreakAsync(range, condition, commands);
}
if (copyKinds.equals(TraceBreakpointKindSet.WRITE)) {
if (copyKinds.equals(CommonSet.WRITE.kinds())) {
return placeWriteBreakAsync(range, condition, commands);
}
if (copyKinds.equals(TraceBreakpointKindSet.ACCESS)) {
if (copyKinds.equals(CommonSet.ACCESS.kinds())) {
return placeAccessBreakAsync(range, condition, commands);
}
Msg.error(this, "Invalid kinds in combination: " + kinds);
@@ -22,9 +22,8 @@
<P>The first place to look when you're having trouble is the debugger's terminal. If you do not
see one, check the <B>Window &rarr; Terminals</B> menu. If there is not one there, then there
is no back-end debugger running &mdash; unless, perhaps, you are trying to use a Recorder-based
target. See <A href="#plugin_conf">Plugin Configuration</A> if you suspect this is the
case.</P>
is no back-end debugger running. See <A href="#plugin_conf">Plugin Configuration</A> in case
your Debugger tool is misconfigured.</P>
<P>If you already have the correct set of TraceRmi-based plugins enabled, but there is still no
terminal after attempting to launch, then the launcher is sorely mis-configured, or your system
@@ -52,9 +51,8 @@
<H2><A name="plugin_conf"></A>Plugin Configuration</H2>
<P>It is possible you have an old Debugger tool still configured for Recorder-based targets.
Recorder-based targets are being replaced by TraceRmi-based targets. Try re-importing the
default Debugger tool.</P>
<P>It is possible you have an old or misconfigured Debugger tool. Try re-importing the default
Debugger tool.</P>
<P>Alternatively, use <B>File &rarr; Configure</B> then click the plug <IMG alt="" src=
"icon.extension.configure"> icon near the top right to check your tool configuration. The
@@ -70,23 +68,6 @@
<LI>DebuggerModelPlugin</LI>
</UL>
<P>The following should be disabled:</P>
<UL>
<LI>DebuggerModelServicePlugin</LI>
<LI>DebuggerModelServiceProxyPlugin</LI>
<LI>DebuggerInterpretersPlugin</LI>
<LI>DebuggerObjectsPlugin</LI>
<LI>DebuggerTargetsPlugin</LI>
</UL>
<P>It is possible to leave both sets of plugins enabled, but this is by all means <EM>NOT</EM>
recommended.</P>
<H2>Tutorial</H2>
<P>Additional troubleshooting recommendations are given in the Debugger course materials.</P>
@@ -88,11 +88,10 @@
<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;
however, only those kinds supported by the target will be included in the resulting command.
Selecting one of the actions will display a prompt allowing adjustments to the parameters
before issuing the command.</P>
breakpoint actions for each kind supported by the target. In the static listing, all kinds are
available, regardless of target support; however, only those kinds supported by the target will
be included in the resulting command. Selecting one of the actions will display a prompt
allowing adjustments to the parameters before issuing the command.</P>
<DIV class="image">
<IMG alt="" src="images/DebuggerPlaceBreakpointDialog.png">
@@ -106,9 +105,9 @@
to 1 &mdash; often the required value. For access breakpoints, this defaults to the size of
the data at the cursor.</LI>
<LI>Kinds - the kind(s) of breakpoint. Only the reasonable combinations are presented, but
the user may type any desired combination. A connected debugger may not support the desired
combination.</LI>
<LI>Kind - the kind of breakpoint. Only Execute (hw or sw), Read, Write, and Access are
presented. A connected debugger may not support the requested kind, in which case it may
substitute a similar kind or fail.</LI>
<LI>Name - the user-defined name of the breakpoint. The name is set on the bookmark at its
static location, if applicable.</LI>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

@@ -109,8 +109,8 @@
<LI>Length - usually 1. For access breakpoints, this is the length in bytes of the address
range.</LI>
<LI>Kinds - indicates the kind(s) of breakpoint: SW_EXECUTE, HW_EXECUTE, READ, and/or
WRITE.</LI>
<LI>Kind - indicates the kind(s) of breakpoint: x, X, R, and/or W; respectively for software
execute, hardware execute, read, and/or write.</LI>
<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
Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

@@ -34,6 +34,11 @@
current trace. If the current trace is not in any project, it saves it under "New Traces" of
the current project.</P>
<H3><A name="save_trace_as"></A>Save Trace As</H3>
<P>This action is available whenever at least one trace is open and active. It prompts for a
destination file in the current project and saves the current trace to it.</P>
<H3><A name="close_trace"></A>Close Trace</H3>
<P>This action is available whenever at least one trace is open and active. It closes the
@@ -72,6 +72,8 @@
<UL>
<LI>Expression - the user-modifiable Sleigh expression defining this watch.</LI>
<LI>Comment - a user-specified comment to describe or identify this watch.</LI>
<LI>Address - when evaluation succeeds, the address of the watch's value. This field is
really only meaningful when the outermost operator of the expression is a memory dereference.
Double-clicking this cell will navigate the primary dynamic listing to this address, if
Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

@@ -16,7 +16,6 @@
package ghidra.app.plugin.core.debug.gui.breakpoint;
import java.util.Set;
import java.util.stream.Collectors;
import db.Transaction;
import ghidra.debug.api.breakpoint.LogicalBreakpoint;
@@ -95,15 +94,6 @@ public class BreakpointLocationRow {
return loc.getTrace().getName();
}
public String getThreads() {
long snap = getSnap();
return loc.getThreads(snap)
.stream()
.map(t -> t.getName(snap))
.collect(Collectors.toSet())
.toString();
}
public String getComment() {
return loc.getComment(getSnap());
}
@@ -4,9 +4,9 @@
* 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.
@@ -16,7 +16,8 @@
package ghidra.app.plugin.core.debug.gui.breakpoint;
import java.awt.*;
import java.awt.event.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.math.BigInteger;
import java.util.List;
import java.util.Set;
@@ -34,7 +35,7 @@ import ghidra.debug.api.breakpoint.LogicalBreakpoint;
import ghidra.debug.api.breakpoint.LogicalBreakpoint.State;
import ghidra.program.model.listing.Program;
import ghidra.program.util.ProgramLocation;
import ghidra.trace.model.breakpoint.TraceBreakpointKind;
import ghidra.trace.model.breakpoint.TraceBreakpointKind.CommonSet;
public class BreakpointsDecompilerMarginProvider extends JPanel
implements DecompilerMarginProvider, LayoutModelListener {
@@ -131,7 +132,7 @@ public class BreakpointsDecompilerMarginProvider extends JPanel
Set<LogicalBreakpoint> col = plugin.collectBreakpoints(locs);
plugin.breakpointService.toggleBreakpointsAt(col, locs.get(0), () -> {
plugin.placeBreakpointDialog.prompt(plugin.getTool(), plugin.breakpointService,
"Set breakpoint", locs.get(0), 1, Set.of(TraceBreakpointKind.SW_EXECUTE), "");
"Set breakpoint", locs.get(0), 1, CommonSet.SWX, "");
// Not great, but I'm not sticking around for the dialog
return CompletableFuture.completedFuture(Set.of());
});
@@ -65,7 +65,7 @@ import ghidra.program.util.*;
import ghidra.trace.model.Trace;
import ghidra.trace.model.TraceLocation;
import ghidra.trace.model.breakpoint.TraceBreakpointKind;
import ghidra.trace.model.breakpoint.TraceBreakpointKind.TraceBreakpointKindSet;
import ghidra.trace.model.breakpoint.TraceBreakpointKind.CommonSet;
import ghidra.trace.model.program.TraceProgramView;
import ghidra.util.HelpLocation;
import ghidra.util.Msg;
@@ -85,8 +85,7 @@ import ghidra.util.Msg;
servicesRequired = {
DebuggerLogicalBreakpointService.class,
MarkerService.class,
}
)
})
public class DebuggerBreakpointMarkerPlugin extends Plugin {
private static final Color COLOR_BREAKPOINT_ENABLED_MARKER =
@@ -260,20 +259,17 @@ public class DebuggerBreakpointMarkerPlugin extends Plugin {
return getTraceFromContext(context) != null;
}
protected static long computeDefaultLength(ActionContext context,
Collection<TraceBreakpointKind> selected) {
if (selected.isEmpty() ||
selected.contains(TraceBreakpointKind.HW_EXECUTE) ||
selected.contains(TraceBreakpointKind.SW_EXECUTE)) {
protected static long computeDefaultLength(ActionContext context, CommonSet kind) {
if (kind == null || kind == CommonSet.SWX || kind == CommonSet.HWX) {
return 1;
}
return computeLengthFromContext(context);
}
protected static Set<TraceBreakpointKind> computeDefaultKinds(ActionContext ctx,
protected static CommonSet computeDefaultKind(ActionContext ctx,
Collection<TraceBreakpointKind> supported) {
if (supported.isEmpty()) {
return Set.of();
return null;
}
long length = computeLengthFromContext(ctx);
if (length == 1) {
@@ -281,27 +277,36 @@ public class DebuggerBreakpointMarkerPlugin extends Plugin {
Listing listing = loc.getProgram().getListing();
CodeUnit cu = listing.getCodeUnitContaining(loc.getAddress());
if (cu instanceof Instruction) {
// It may contain both, but prefer SWX
if (supported.contains(TraceBreakpointKind.SW_EXECUTE)) {
return Set.of(TraceBreakpointKind.SW_EXECUTE);
return CommonSet.SWX;
}
else if (supported.contains(TraceBreakpointKind.HW_EXECUTE)) {
return Set.of(TraceBreakpointKind.HW_EXECUTE);
return CommonSet.HWX;
}
return Set.of();
return null;
}
Data data = (Data) cu;
if (!data.isDefined()) {
if (supported.size() == 1) {
return Set.copyOf(supported);
for (CommonSet kind : CommonSet.VALUES) {
if (kind.kinds().equals(supported)) {
return kind;
}
}
return Set.of();
return null;
}
}
// TODO: Consider memory protections?
Set<TraceBreakpointKind> result =
new HashSet<>(Set.of(TraceBreakpointKind.READ, TraceBreakpointKind.WRITE));
result.retainAll(supported);
return result;
// LATER: Consider memory protections?
if (supported.containsAll(CommonSet.ACCESS.kinds())) {
return CommonSet.ACCESS;
}
else if (supported.contains(TraceBreakpointKind.READ)) {
return CommonSet.READ;
}
else if (supported.contains(TraceBreakpointKind.WRITE)) {
return CommonSet.WRITE;
}
return null;
}
protected Color colorForState(State state) {
@@ -576,13 +581,12 @@ public class DebuggerBreakpointMarkerPlugin extends Plugin {
protected class SetBreakpointAction extends AbstractSetBreakpointAction {
public static final String GROUP = DebuggerResources.GROUP_BREAKPOINTS;
private final Set<TraceBreakpointKind> kinds;
private final CommonSet kind;
public SetBreakpointAction(Set<TraceBreakpointKind> kinds) {
public SetBreakpointAction(CommonSet kind) {
super(DebuggerBreakpointMarkerPlugin.this);
this.kinds = kinds;
setPopupMenuData(new MenuData(
new String[] { NAME, TraceBreakpointKindSet.encode(kinds) }, ICON, GROUP));
this.kind = kind;
setPopupMenuData(new MenuData(new String[] { NAME, kind.toString() }, ICON, GROUP));
tool.addAction(this);
setEnabled(true);
}
@@ -593,8 +597,8 @@ public class DebuggerBreakpointMarkerPlugin extends Plugin {
return;
}
ProgramLocation location = getSingleLocationFromContext(context);
long length = computeDefaultLength(context, kinds);
placeBreakpointDialog.prompt(tool, breakpointService, NAME, location, length, kinds,
long length = computeDefaultLength(context, kind);
placeBreakpointDialog.prompt(tool, breakpointService, NAME, location, length, kind,
"");
}
@@ -608,7 +612,7 @@ public class DebuggerBreakpointMarkerPlugin extends Plugin {
return true;
}
Set<TraceBreakpointKind> supported = getSupportedKindsFromTrace(view.getTrace());
return supported.containsAll(kinds);
return supported.containsAll(kind.kinds());
}
}
@@ -754,32 +758,28 @@ public class DebuggerBreakpointMarkerPlugin extends Plugin {
@AutoOptionDefined(
name = DebuggerResources.OPTION_NAME_COLORS_ENABLED_BREAKPOINT_COLORING_BACKGROUND,
description = "Whether or not to color background for memory at an enabled breakpoint",
help = @HelpInfo(anchor = "colors")
)
help = @HelpInfo(anchor = "colors"))
private boolean breakpointEnabledColoringBackground =
DebuggerResources.DEFAULT_COLOR_ENABLED_BREAKPOINT_COLORING_BACKGROUND;
@AutoOptionDefined(
name = DebuggerResources.OPTION_NAME_COLORS_DISABLED_BREAKPOINT_COLORING_BACKGROUND,
description = "Whether or not to color background for memory at a disabled breakpoint",
help = @HelpInfo(anchor = "colors")
)
help = @HelpInfo(anchor = "colors"))
private boolean breakpointDisabledColoringBackground =
DebuggerResources.DEFAULT_COLOR_DISABLED_BREAKPOINT_COLORING_BACKGROUND;
@AutoOptionDefined(
name = DebuggerResources.OPTION_NAME_COLORS_INEFF_EN_BREAKPOINT_COLORING_BACKGROUND,
description = "Whether or not to color background for memory at an enabled, but ineffective, breakpoint",
help = @HelpInfo(anchor = "colors")
)
help = @HelpInfo(anchor = "colors"))
private boolean breakpointIneffEnColoringBackground =
DebuggerResources.DEFAULT_COLOR_INEFF_EN_BREAKPOINT_COLORING_BACKGROUND;
@AutoOptionDefined(
name = DebuggerResources.OPTION_NAME_COLORS_INEFF_DIS_BREAKPOINT_COLORING_BACKGROUND,
description = "Whether or not to color background for memory at an disabled, but ineffective, breakpoint",
help = @HelpInfo(anchor = "colors")
)
help = @HelpInfo(anchor = "colors"))
private boolean breakpointIneffDisColoringBackground =
DebuggerResources.DEFAULT_COLOR_INEFF_DIS_BREAKPOINT_COLORING_BACKGROUND;
@@ -797,11 +797,7 @@ public class DebuggerBreakpointMarkerPlugin extends Plugin {
new AsyncDebouncer<>(AsyncTimer.DEFAULT_TIMER, 50);
// package access for testing
SetBreakpointAction actionSetSoftwareBreakpoint;
SetBreakpointAction actionSetExecuteBreakpoint;
SetBreakpointAction actionSetReadWriteBreakpoint;
SetBreakpointAction actionSetReadBreakpoint;
SetBreakpointAction actionSetWriteBreakpoint;
Map<CommonSet, SetBreakpointAction> actionsSetBreakpoint;
ToggleBreakpointAction actionToggleBreakpoint;
EnableBreakpointAction actionEnableBreakpoint;
DisableBreakpointAction actionDisableBreakpoint;
@@ -837,8 +833,7 @@ public class DebuggerBreakpointMarkerPlugin extends Plugin {
}
@AutoOptionConsumed(
name = DebuggerResources.OPTION_NAME_COLORS_ENABLED_BREAKPOINT_COLORING_BACKGROUND
)
name = DebuggerResources.OPTION_NAME_COLORS_ENABLED_BREAKPOINT_COLORING_BACKGROUND)
private void setEnabledBreakpointMarkerBackground(boolean breakpointColoringBackground) {
for (BreakpointMarkerSets markers : markersByProgram.values()) {
markers.setEnabledColoringBackground(breakpointColoringBackground);
@@ -846,8 +841,7 @@ public class DebuggerBreakpointMarkerPlugin extends Plugin {
}
@AutoOptionConsumed(
name = DebuggerResources.OPTION_NAME_COLORS_DISABLED_BREAKPOINT_COLORING_BACKGROUND
)
name = DebuggerResources.OPTION_NAME_COLORS_DISABLED_BREAKPOINT_COLORING_BACKGROUND)
private void setDisabledBreakpointMarkerBackground(boolean breakpointColoringBackground) {
for (BreakpointMarkerSets markers : markersByProgram.values()) {
markers.setDisabledColoringBackground(breakpointColoringBackground);
@@ -855,8 +849,7 @@ public class DebuggerBreakpointMarkerPlugin extends Plugin {
}
@AutoOptionConsumed(
name = DebuggerResources.OPTION_NAME_COLORS_INEFF_EN_BREAKPOINT_COLORING_BACKGROUND
)
name = DebuggerResources.OPTION_NAME_COLORS_INEFF_EN_BREAKPOINT_COLORING_BACKGROUND)
private void setIneffectiveEBreakpointMarkerBackground(boolean breakpointColoringBackground) {
for (BreakpointMarkerSets markers : markersByProgram.values()) {
markers.setIneffectiveEnabledColoringBackground(breakpointColoringBackground);
@@ -864,8 +857,7 @@ public class DebuggerBreakpointMarkerPlugin extends Plugin {
}
@AutoOptionConsumed(
name = DebuggerResources.OPTION_NAME_COLORS_INEFF_DIS_BREAKPOINT_COLORING_BACKGROUND
)
name = DebuggerResources.OPTION_NAME_COLORS_INEFF_DIS_BREAKPOINT_COLORING_BACKGROUND)
private void setIneffectiveDBreakpointMarkerBackground(boolean breakpointColoringBackground) {
for (BreakpointMarkerSets markers : markersByProgram.values()) {
markers.setIneffectiveDisabledColoringBackground(breakpointColoringBackground);
@@ -955,7 +947,7 @@ public class DebuggerBreakpointMarkerPlugin extends Plugin {
breakpointError(title, "It seems this target does not support breakpoints.");
return CompletableFuture.completedFuture(Set.of());
}
Set<TraceBreakpointKind> kinds = computeDefaultKinds(context, supported);
CommonSet kinds = computeDefaultKind(context, supported);
long length = computeDefaultLength(context, kinds);
placeBreakpointDialog.prompt(tool, breakpointService, title, loc, length, kinds,
"");
@@ -1085,14 +1077,8 @@ public class DebuggerBreakpointMarkerPlugin extends Plugin {
}
protected void createActions() {
actionSetSoftwareBreakpoint =
new SetBreakpointAction(Set.of(TraceBreakpointKind.SW_EXECUTE));
actionSetExecuteBreakpoint =
new SetBreakpointAction(Set.of(TraceBreakpointKind.HW_EXECUTE));
actionSetReadWriteBreakpoint =
new SetBreakpointAction(Set.of(TraceBreakpointKind.READ, TraceBreakpointKind.WRITE));
actionSetReadBreakpoint = new SetBreakpointAction(Set.of(TraceBreakpointKind.READ));
actionSetWriteBreakpoint = new SetBreakpointAction(Set.of(TraceBreakpointKind.WRITE));
actionsSetBreakpoint =
CommonSet.VALUES.stream().collect(Collectors.toMap(s -> s, SetBreakpointAction::new));
actionToggleBreakpoint = new ToggleBreakpointAction();
actionEnableBreakpoint = new EnableBreakpointAction();
actionDisableBreakpoint = new DisableBreakpointAction();
@@ -149,10 +149,10 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
return 60;
}
},
KINDS("Kinds", String.class, LogicalBreakpointRow::getKinds) {
KIND("Kind", String.class, LogicalBreakpointRow::getKind) {
@Override
public int getPreferredWidth() {
return 150;
return 50;
}
},
LOCATIONS("Locations", Integer.class, LogicalBreakpointRow::getLocationCount) {
@@ -276,12 +276,6 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
}
},
TRACE("Trace", String.class, BreakpointLocationRow::getTraceName),
THREADS("Threads", String.class, BreakpointLocationRow::getThreads) {
@Override
public boolean isVisible() {
return false;
}
},
COMMENT("Comment", String.class, BreakpointLocationRow::getComment,
BreakpointLocationRow::setComment),
EXPRESSION("Expression", String.class, BreakpointLocationRow::getExpression),
@@ -4,9 +4,9 @@
* 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.
@@ -15,11 +15,6 @@
*/
package ghidra.app.plugin.core.debug.gui.breakpoint;
import static ghidra.trace.model.breakpoint.TraceBreakpointKind.*;
import java.util.Collection;
import java.util.Set;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.event.DocumentEvent;
@@ -34,8 +29,7 @@ import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Instruction;
import ghidra.program.model.listing.Program;
import ghidra.program.util.ProgramLocation;
import ghidra.trace.model.breakpoint.TraceBreakpointKind;
import ghidra.trace.model.breakpoint.TraceBreakpointKind.TraceBreakpointKindSet;
import ghidra.trace.model.breakpoint.TraceBreakpointKind.CommonSet;
import ghidra.util.MessageType;
import ghidra.util.Swing;
import ghidra.util.layout.PairLayout;
@@ -45,12 +39,12 @@ public class DebuggerPlaceBreakpointDialog extends DialogComponentProvider {
private Program program;
private Address address;
private long length;
private Set<TraceBreakpointKind> kinds;
private CommonSet kind;
private String name;
private JTextField fieldAddress;
private JTextField fieldLength;
private JComboBox<String> fieldKinds;
private JComboBox<CommonSet> fieldKind;
private JTextField fieldName;
private PluginTool tool;
private String statusText = null;
@@ -119,20 +113,15 @@ public class DebuggerPlaceBreakpointDialog extends DialogComponentProvider {
panel.add(labelLength);
panel.add(fieldLength);
JLabel labelKinds = new JLabel("Kinds");
labelKinds.getAccessibleContext().setAccessibleName("Kinds");
DefaultComboBoxModel<String> kindModel = new DefaultComboBoxModel<>();
// TODO: Let user select whatever combo?
kindModel.addElement(TraceBreakpointKindSet.encode(Set.of(SW_EXECUTE)));
kindModel.addElement(TraceBreakpointKindSet.encode(Set.of(HW_EXECUTE)));
kindModel.addElement(TraceBreakpointKindSet.encode(Set.of(READ)));
kindModel.addElement(TraceBreakpointKindSet.encode(Set.of(WRITE)));
kindModel.addElement(TraceBreakpointKindSet.encode(Set.of(READ, WRITE)));
fieldKinds = new JComboBox<String>(kindModel);
fieldKinds.setEditable(true);
fieldKinds.getAccessibleContext().setAccessibleName("Kinds");
panel.add(labelKinds);
panel.add(fieldKinds);
JLabel labelKind = new JLabel("Kind");
labelKind.getAccessibleContext().setAccessibleName("Kind");
DefaultComboBoxModel<CommonSet> kindModel = new DefaultComboBoxModel<>();
kindModel.addAll(CommonSet.VALUES);
fieldKind = new JComboBox<CommonSet>(kindModel);
fieldKind.setEditable(false);
fieldKind.getAccessibleContext().setAccessibleName("Kind");
panel.add(labelKind);
panel.add(fieldKind);
JLabel labelName = new JLabel("Name");
fieldName = new JTextField();
@@ -148,17 +137,17 @@ public class DebuggerPlaceBreakpointDialog extends DialogComponentProvider {
}
public void prompt(PluginTool tool, DebuggerLogicalBreakpointService service, String title,
ProgramLocation loc, long length, Collection<TraceBreakpointKind> kinds, String name) {
ProgramLocation loc, long length, CommonSet kind, String name) {
this.service = service;
this.program = loc.getProgram();
this.address = DebuggerLogicalBreakpointService.addressFromLocation(loc);
this.length = length;
this.kinds = Set.copyOf(kinds);
this.kind = kind;
this.name = name;
this.fieldAddress.setText(address.toString());
this.fieldLength.setText(Long.toUnsignedString(length));
this.fieldKinds.setSelectedItem(TraceBreakpointKindSet.encode(kinds));
this.fieldKind.setSelectedItem(kind);
this.fieldName.setText("");
this.tool = tool;
@@ -182,18 +171,11 @@ public class DebuggerPlaceBreakpointDialog extends DialogComponentProvider {
return;
}
try {
kinds = TraceBreakpointKindSet.decode((String) fieldKinds.getSelectedItem(), true);
}
catch (IllegalArgumentException e) {
setStatusText("Invalid kinds: " + e);
return;
}
kind = ((CommonSet) fieldKind.getSelectedItem());
name = fieldName.getText();
ProgramLocation loc = new ProgramLocation(program, address);
service.placeBreakpointAt(loc, length, kinds, name).exceptionally(ex -> {
service.placeBreakpointAt(loc, length, kind.kinds(), name).exceptionally(ex -> {
ex = AsyncUtils.unwrapThrowable(ex);
statusText = ex.getMessage(); // will be set when dialog is shown later
tool.showDialog(this);
@@ -125,7 +125,7 @@ public class LogicalBreakpointRow {
return lb.getDomainObject();
}
public String getKinds() {
public String getKind() {
return TraceBreakpointKindSet.encode(lb.getKinds());
}
@@ -100,21 +100,21 @@ class BreakpointTimelinePanel extends JPanel {
private static boolean singleColumn = false;
private static boolean showGridOutline = true;
private static GColor BG_COLOR = Colors.BACKGROUND;
private static GColor GRID_COLOR = Colors.FOREGROUND_DISABLED;
private static GColor SELECTION_COLOR =
private static final GColor BG_COLOR = Colors.BACKGROUND;
private static final GColor GRID_COLOR = Colors.FOREGROUND_DISABLED;
private static final GColor SELECTION_COLOR =
new GColor("color.debugger.plugin.breakpoint.timeline.selection");
private static GColor HOVER_COLOR =
private static final GColor HOVER_COLOR =
new GColor("color.debugger.plugin.breakpoint.timeline.hover");
private static GColor CURRENT_SNAP_COLOR =
private static final GColor CURRENT_SNAP_COLOR =
new GColor("color.debugger.plugin.breakpoint.timeline.current");
private static GColor INSTRUCTION_HIT_COLOR =
private static final GColor INSTRUCTION_HIT_COLOR =
new GColor("color.debugger.plugin.breakpoint.timeline.type.instructions");
private static GColor MEMORY_READ_COLOR =
private static final GColor MEMORY_READ_COLOR =
new GColor("color.debugger.plugin.breakpoint.timeline.type.read.memory");
private static GColor MEMORY_WRITE_COLOR =
private static final GColor MEMORY_WRITE_COLOR =
new GColor("color.debugger.plugin.breakpoint.timeline.type.write.memory");
private static Map<TraceBreakpointKind, GColor> BREAKTYPE_TO_COLOR = Map.ofEntries(
private static final Map<TraceBreakpointKind, GColor> BREAKTYPE_TO_COLOR = Map.ofEntries(
Map.entry(TraceBreakpointKind.HW_EXECUTE, BreakpointTimelinePanel.INSTRUCTION_HIT_COLOR),
Map.entry(TraceBreakpointKind.SW_EXECUTE, BreakpointTimelinePanel.INSTRUCTION_HIT_COLOR),
Map.entry(TraceBreakpointKind.READ, BreakpointTimelinePanel.MEMORY_READ_COLOR),
@@ -44,8 +44,7 @@ public class MappedLogicalBreakpoint implements LogicalBreakpointInternal {
private final Map<Trace, TraceBreakpointSet> traceBreaks = new HashMap<>();
protected MappedLogicalBreakpoint(PluginTool tool, Program program, Address progAddr,
long length,
Collection<TraceBreakpointKind> kinds) {
long length, Collection<TraceBreakpointKind> kinds) {
this.tool = tool;
this.kinds = Set.copyOf(kinds);
this.length = length;
@@ -4,9 +4,9 @@
* 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.
@@ -16,6 +16,7 @@
package ghidra.app.plugin.core.debug.service.breakpoint;
import java.util.*;
import java.util.stream.Collectors;
import com.google.gson.*;
@@ -27,6 +28,7 @@ import ghidra.program.model.address.AddressSet;
import ghidra.program.model.listing.*;
import ghidra.program.util.ProgramLocation;
import ghidra.trace.model.breakpoint.TraceBreakpointKind;
import ghidra.trace.model.breakpoint.TraceBreakpointKind.CommonSet;
import ghidra.trace.model.breakpoint.TraceBreakpointKind.TraceBreakpointKindSet;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
@@ -69,8 +71,8 @@ public class ProgramBreakpoint {
Set<TraceBreakpointKind> result = TraceBreakpointKindSet.decode(parts[0], false);
if (result.isEmpty()) {
Msg.warn(TraceBreakpointKind.class,
"Decoded empty set of kinds from bookmark. Assuming SW_EXECUTE");
return Set.of(TraceBreakpointKind.SW_EXECUTE);
"Decoded empty set of kinds from bookmark. Assuming %s".formatted(CommonSet.SWX));
return CommonSet.SWX.kinds();
}
return result;
}
@@ -435,6 +437,21 @@ public class ProgramBreakpoint {
return TraceBreakpointKindSet.encode(kinds) + ";" + Long.toUnsignedString(length);
}
/**
* In case a program database with pre-Ghidra-12.2 breakpoint bookmarks comes along (this will
* happen for a while), we want to ensure the old encodings are deleted when the breakpoint is
* toggled. While we'd normally strive for perfect backward compatibility, it's not as important
* for breakpoints here. If this function is to be removed later (it probably should be), we can
* either: 1) ensure there's some upgrade process, on import or via a script; or 2) just
* instruct users on a case-by-case basis to delete the old breakpoints.
*
* @return the bookmark category for encoding the breakpoint kinds in versions prior to 12.2.
*/
protected String computeCategory_Pre12Dot2() {
return kinds.stream().map(k -> k.name()).collect(Collectors.joining(",")) + ";" +
Long.toUnsignedString(length);
}
/**
* Change the state of this breakpoint by manipulating bookmarks
*
@@ -458,9 +475,12 @@ public class ProgramBreakpoint {
try (Transaction tx = program.openTransaction("Toggle breakpoint")) {
BookmarkManager manager = program.getBookmarkManager();
String catStr = computeCategory();
String catStr_Pre12Dot2 = computeCategory_Pre12Dot2();
manager.setBookmark(address, addType, catStr, comment);
manager.removeBookmarks(new AddressSet(address), delType, catStr,
TaskMonitor.DUMMY);
manager.removeBookmarks(new AddressSet(address), delType, catStr_Pre12Dot2,
TaskMonitor.DUMMY);
}
catch (CancelledException e) {
throw new AssertionError(e);
@@ -66,6 +66,7 @@ import ghidra.program.model.listing.Program;
import ghidra.program.util.ProgramLocation;
import ghidra.trace.model.*;
import ghidra.trace.model.breakpoint.*;
import ghidra.trace.model.breakpoint.TraceBreakpointKind.CommonSet;
import ghidra.trace.model.guest.TracePlatform;
import ghidra.trace.model.program.TraceProgramView;
import ghidra.trace.model.thread.TraceThread;
@@ -664,12 +665,8 @@ public class DebuggerEmulationServicePlugin extends Plugin implements DebuggerEm
continue;
}
Set<TraceBreakpointKind> kinds = bpt.getKinds(snap);
boolean isExecute =
kinds.contains(TraceBreakpointKind.HW_EXECUTE) ||
kinds.contains(TraceBreakpointKind.SW_EXECUTE);
boolean isRead = kinds.contains(TraceBreakpointKind.READ);
boolean isWrite = kinds.contains(TraceBreakpointKind.WRITE);
if (isExecute) {
if (kinds.contains(TraceBreakpointKind.HW_EXECUTE) ||
kinds.contains(TraceBreakpointKind.SW_EXECUTE)) {
Address minAddress = bpt.getMinAddress(snap);
try {
emu.inject(minAddress, bpt.getEmuSleigh(snap));
@@ -679,13 +676,13 @@ public class DebuggerEmulationServicePlugin extends Plugin implements DebuggerEm
emu.inject(minAddress, "emu_injection_err();");
}
}
if (isRead && isWrite) {
if (kinds.equals(CommonSet.ACCESS.kinds())) {
emu.addAccessBreakpoint(bpt.getRange(snap), AccessKind.RW);
}
else if (isRead) {
else if (kinds.equals(CommonSet.READ.kinds())) {
emu.addAccessBreakpoint(bpt.getRange(snap), AccessKind.R);
}
else if (isWrite) {
else if (kinds.equals(CommonSet.WRITE.kinds())) {
emu.addAccessBreakpoint(bpt.getRange(snap), AccessKind.W);
}
}
@@ -45,7 +45,7 @@ import ghidra.program.model.pcode.*;
import ghidra.program.util.*;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.TraceAddressSnapRange;
import ghidra.trace.model.breakpoint.TraceBreakpointKind;
import ghidra.trace.model.breakpoint.TraceBreakpointKind.CommonSet;
import ghidra.trace.model.property.*;
import ghidra.util.HelpLocation;
import ghidra.util.Msg;
@@ -55,8 +55,8 @@ import sarif.export.WrappedLogicalLocation;
import sarif.managers.SarifMgr;
/**
* Container for all the decompiler elements the users "selects" via the menu.
* This data is used to build queries.
* Container for all the decompiler elements the users "selects" via the menu. This data is used to
* build queries.
*/
public class EmulatorTaintState extends AbstractTaintState {
@@ -164,8 +164,8 @@ public class EmulatorTaintState extends AbstractTaintState {
}
/**
* Build the query string, save it to a file the users selects, and run the
* engine using the index and the query that is saved to the file.
* Build the query string, save it to a file the users selects, and run the engine using the
* index and the query that is saved to the file.
*/
@Override
public boolean queryIndex(Program program, PluginTool tool, QueryType queryType) {
@@ -219,8 +219,7 @@ public class EmulatorTaintState extends AbstractTaintState {
private void injectTaint(Address target, String sleigh) {
PlaceEmuBreakpointActionItem item = new PlaceEmuBreakpointActionItem(current.getTrace(),
current.getSnap(), target, 1, Set.of(TraceBreakpointKind.SW_EXECUTE),
sleigh);
current.getSnap(), target, 1, CommonSet.SWX.kinds(), sleigh);
item.execute();
}
@@ -4,9 +4,9 @@
* 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.
@@ -15,7 +15,6 @@
*/
package ghidra.app.plugin.core.debug.gui.memview;
import java.util.HashSet;
import java.util.Set;
import org.junit.*;
@@ -29,7 +28,7 @@ import ghidra.program.model.listing.Program;
import ghidra.test.ToyProgramBuilder;
import ghidra.trace.database.ToyDBTraceBuilder;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.breakpoint.TraceBreakpointKind;
import ghidra.trace.model.breakpoint.TraceBreakpointKind.CommonSet;
import ghidra.trace.model.memory.TraceMemoryFlag;
import ghidra.trace.model.thread.TraceThread;
import help.screenshot.GhidraScreenShotGenerator;
@@ -109,13 +108,9 @@ public class DebuggerMemviewPluginScreenShots extends GhidraScreenShotGenerator
}
try (Transaction tx = tb.startTransaction()) {
Set<TraceThread> threads = new HashSet<TraceThread>();
Set<TraceBreakpointKind> kinds = new HashSet<TraceBreakpointKind>();
threads.add(thread1);
kinds.add(TraceBreakpointKind.HW_EXECUTE);
tb.trace.getBreakpointManager()
.addBreakpoint("bpt1", Lifespan.span(17, 25), tb.range(0x7fac1234, 0x7fc1238),
threads, kinds, true, "break here");
Set.of(thread1), CommonSet.HWX.kinds(), true, "break here");
}
/*
@@ -4,9 +4,9 @@
* 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.
@@ -22,11 +22,12 @@ import org.junit.*;
import db.Transaction;
import ghidra.app.plugin.core.debug.service.tracemgr.DebuggerTraceManagerServicePlugin;
import ghidra.app.services.DebuggerTraceManagerService;
import ghidra.program.model.data.PointerDataType;
import ghidra.program.model.data.*;
import ghidra.program.model.lang.Language;
import ghidra.program.model.lang.RegisterValue;
import ghidra.test.ToyProgramBuilder;
import ghidra.trace.database.ToyDBTraceBuilder;
import ghidra.trace.database.ToyDBTraceBuilder.ToySchemaBuilder;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.memory.TraceMemorySpace;
import ghidra.trace.model.thread.TraceThread;
@@ -57,10 +58,15 @@ public class DebuggerRegistersPluginScreenShots extends GhidraScreenShotGenerato
@Test
public void testCaptureDebuggerRegistersPlugin() throws Throwable {
try (Transaction tx = tb.startTransaction()) {
tb.createRootObject(new ToySchemaBuilder()
.useRegistersPerThread()
.noRegisterGroups()
.build());
long snap0 = tb.trace.getTimeManager().createSnapshot("First").getKey();
long snap1 = tb.trace.getTimeManager().createSnapshot("Second").getKey();
TraceThread thread = tb.getOrAddThread("[1]", snap0);
TraceThread thread = tb.getOrAddThread("Targets[1].Threads[1]", snap0);
tb.createObjectsRegsForThread(thread, Lifespan.nowOn(snap0), tb.host);
TraceMemorySpace regs =
tb.trace.getMemoryManager().getMemoryRegisterSpace(thread, true);
Language lang = tb.trace.getBaseLanguage();
@@ -90,11 +96,16 @@ public class DebuggerRegistersPluginScreenShots extends GhidraScreenShotGenerato
regs.setValue(snap1,
new RegisterValue(lang.getRegister("RDX"), BigInteger.valueOf(0x80)));
TypeDef pointerRam = tb.trace.getBaseDataTypeManager()
.resolveType(PointerDataType.dataType.typedefBuilder()
.addressSpace(tb.language.getDefaultDataSpace())
.build(),
DataTypeConflictHandler.DEFAULT_HANDLER);
tb.trace.getCodeManager()
.getCodeRegisterSpace(thread, true)
.definedData()
.create(Lifespan.nowOn(snap0), lang.getRegister("RIP"),
PointerDataType.dataType);
.create(Lifespan.nowOn(snap0), lang.getRegister("RIP"), pointerRam);
traceManager.openTrace(tb.trace);
traceManager.activateThread(thread);
@@ -60,7 +60,7 @@ import ghidra.trace.database.ToyDBTraceBuilder;
import ghidra.trace.database.target.DBTraceObjectManager;
import ghidra.trace.model.DefaultTraceLocation;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.breakpoint.TraceBreakpointKind;
import ghidra.trace.model.breakpoint.TraceBreakpointKind.CommonSet;
import ghidra.trace.model.stack.TraceStack;
import ghidra.trace.model.stack.TraceStackFrame;
import ghidra.trace.model.target.schema.SchemaContext;
@@ -125,11 +125,11 @@ public class DebuggerStackPluginScreenShots extends GhidraScreenShotGenerator
.createInitializedBlock(".text", addr(program, 0x00400000), 0x10000, (byte) 0,
TaskMonitor.DUMMY, false);
FunctionManager fMan = program.getFunctionManager();
fMan.createFunction("FUN_00401000", addr(0x00401000),
fMan.createFunction("FUN_00401000", addr(program, 0x00401000),
set(program, 0x00401000, 0x00401100), SourceType.USER_DEFINED);
fMan.createFunction("FUN_00401200", addr(0x00401200),
fMan.createFunction("FUN_00401200", addr(program, 0x00401200),
set(program, 0x00401200, 0x00401300), SourceType.USER_DEFINED);
fMan.createFunction("FUN_00404300", addr(0x00404300),
fMan.createFunction("FUN_00404300", addr(program, 0x00404300),
set(program, 0x00404300, 0x00404400), SourceType.USER_DEFINED);
}
@@ -328,8 +328,7 @@ public class DebuggerStackPluginScreenShots extends GhidraScreenShotGenerator
try (Transaction tx = tb.startTransaction()) {
tb.trace.getBreakpointManager()
.addBreakpoint("Breakpoints[0]", Lifespan.nowOn(0), retInstr,
Set.of(),
Set.of(TraceBreakpointKind.SW_EXECUTE), true, "unwind stack");
Set.of(), CommonSet.SWX.kinds(), true, "unwind stack");
}
EmulationResult result = emuService.run(atSetup.getPlatform(), atSetup.getTime(), monitor,
@@ -4,9 +4,9 @@
* 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.
@@ -67,7 +67,7 @@ import ghidra.program.model.symbol.SourceType;
import ghidra.program.util.GhidraProgramUtilities;
import ghidra.trace.database.ToyDBTraceBuilder;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.breakpoint.TraceBreakpointKind;
import ghidra.trace.model.breakpoint.TraceBreakpointKind.CommonSet;
import ghidra.trace.model.thread.TraceThread;
import ghidra.trace.model.time.schedule.Scheduler;
import ghidra.util.InvalidNameException;
@@ -276,8 +276,7 @@ public class VariableValueHoverPluginScreenShots extends GhidraScreenShotGenerat
try (Transaction tx = tb.startTransaction()) {
tb.trace.getBreakpointManager()
.addBreakpoint("Breakpoints[0]", Lifespan.nowOn(0), retInstr,
Set.of(),
Set.of(TraceBreakpointKind.SW_EXECUTE), true, "unwind stack");
Set.of(), CommonSet.SWX.kinds(), true, "unwind stack");
}
EmulationResult result = emuService.run(atSetup.getPlatform(), atSetup.getTime(), monitor,
@@ -27,6 +27,8 @@ import ghidra.program.model.data.LongDataType;
import ghidra.program.model.symbol.SourceType;
import ghidra.test.ToyProgramBuilder;
import ghidra.trace.database.ToyDBTraceBuilder;
import ghidra.trace.database.ToyDBTraceBuilder.ToySchemaBuilder;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.thread.TraceThread;
import help.screenshot.GhidraScreenShotGenerator;
@@ -57,6 +59,10 @@ public class DebuggerWatchesPluginScreenShots extends GhidraScreenShotGenerator
TraceThread thread;
long snap0, snap1;
try (Transaction tx = tb.startTransaction()) {
tb.createRootObject(new ToySchemaBuilder()
.useRegistersPerThread()
.noRegisterGroups()
.build());
snap0 = tb.trace.getTimeManager().createSnapshot("First").getKey();
snap1 = tb.trace.getTimeManager().createSnapshot("Second").getKey();
@@ -65,7 +71,8 @@ public class DebuggerWatchesPluginScreenShots extends GhidraScreenShotGenerator
.create(snap1, tb.addr(0x7fff0004), "fiveUp",
tb.trace.getSymbolManager().getGlobalNamespace(), SourceType.USER_DEFINED);
thread = tb.getOrAddThread("[1]", snap0);
thread = tb.getOrAddThread("Targets[1].Threads[1]", snap0);
tb.createObjectsRegsForThread(thread, Lifespan.nowOn(snap0), tb.host);
PcodeExecutor<byte[]> executor0 =
TraceSleighUtils.buildByteExecutor(tb.trace, snap0, thread, 0);
@@ -45,7 +45,7 @@ import ghidra.trace.database.memory.DBTraceMemoryManager;
import ghidra.trace.database.program.DBTraceVariableSnapProgramView;
import ghidra.trace.database.symbol.*;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.breakpoint.TraceBreakpointKind;
import ghidra.trace.model.breakpoint.TraceBreakpointKind.CommonSet;
import ghidra.trace.model.memory.TraceMemoryFlag;
import ghidra.trace.model.memory.TraceMemoryState;
import ghidra.util.task.TaskMonitor;
@@ -559,9 +559,9 @@ public class DebuggerCopyPlanTest extends AbstractGhidraHeadedDebuggerTest {
DBTraceBreakpointManager breakpoints = tb.trace.getBreakpointManager();
breakpoints.placeBreakpoint("Breakpoints[1]", 0, tb.addr(0x55550123), List.of(),
Set.of(TraceBreakpointKind.SW_EXECUTE), true, "Test-1");
CommonSet.SWX.kinds(), true, "Test-1");
breakpoints.placeBreakpoint("Breakpoints[2]", 0, tb.addr(0x55550321), List.of(),
Set.of(TraceBreakpointKind.SW_EXECUTE), false, "Test-2");
CommonSet.SWX.kinds(), false, "Test-2");
}
Address paddr = tb.addr(stSpace, 0x55550000);
@@ -571,8 +571,7 @@ public class DebuggerCopyPlanTest extends AbstractGhidraHeadedDebuggerTest {
false);
// Set up a collision. This is normal with relocations
program.getBookmarkManager()
.setBookmark(tb.addr(stSpace, 0x55550123), "BreakpointDisabled", "SW_EXECUTE;1",
"");
.setBookmark(tb.addr(stSpace, 0x55550123), "BreakpointDisabled", "x;1", "");
AllCopiers.BREAKPOINTS.copy(view, tb.range(0x55550000, 0x5555ffff), program, paddr,
TaskMonitor.DUMMY);
@@ -588,12 +587,12 @@ public class DebuggerCopyPlanTest extends AbstractGhidraHeadedDebuggerTest {
bm = bookmarks.get(0);
assertEquals(tb.addr(stSpace, 0x55550123), bm.getAddress());
assertEquals("BreakpointEnabled", bm.getTypeString());
assertEquals("SW_EXECUTE;1", bm.getCategory());
assertEquals("x;1", bm.getCategory());
bm = bookmarks.get(1);
assertEquals(tb.addr(stSpace, 0x55550321), bm.getAddress());
assertEquals("BreakpointDisabled", bm.getTypeString());
assertEquals("SW_EXECUTE;1", bm.getCategory());
assertEquals("x;1", bm.getCategory());
}
@Test
@@ -54,7 +54,7 @@ import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.util.ProgramLocation;
import ghidra.trace.database.ToyDBTraceBuilder.ToySchemaBuilder;
import ghidra.trace.model.*;
import ghidra.trace.model.breakpoint.TraceBreakpointKind;
import ghidra.trace.model.breakpoint.TraceBreakpointKind.CommonSet;
import ghidra.trace.model.breakpoint.TraceBreakpointLocation;
import ghidra.trace.model.guest.TracePlatform;
import ghidra.trace.model.memory.TraceMemoryManager;
@@ -448,7 +448,7 @@ public class DebuggerEmulationServiceTest extends AbstractGhidraHeadedDebuggerTe
try (Transaction tx = trace.openTransaction("Add breakpoint")) {
trace.getBreakpointManager()
.addBreakpoint("Breakpoints[0]", Lifespan.nowOn(0), addrI2, Set.of(thread),
Set.of(TraceBreakpointKind.SW_EXECUTE), true, "test");
CommonSet.SWX.kinds(), true, "test");
}
EmulationResult result = emulationPlugin.run(trace.getPlatformManager().getHostPlatform(),
@@ -506,10 +506,10 @@ public class DebuggerEmulationServiceTest extends AbstractGhidraHeadedDebuggerTe
try (Transaction tx = trace.openTransaction("Add breakpoint")) {
trace.getBreakpointManager()
.addBreakpoint("Breakpoints[0]", Lifespan.nowOn(0), addrText, Set.of(thread),
Set.of(TraceBreakpointKind.SW_EXECUTE), true, "test");
CommonSet.SWX.kinds(), true, "test");
TraceBreakpointLocation tb = trace.getBreakpointManager()
.addBreakpoint("Breakpoints[1]", Lifespan.nowOn(0), addrI1, Set.of(thread),
Set.of(TraceBreakpointKind.SW_EXECUTE), true, "test");
CommonSet.SWX.kinds(), true, "test");
// Force "partial instruction"
tb.setEmuSleigh(0, """
r1 = 0xbeef;
@@ -518,7 +518,7 @@ public class DebuggerEmulationServiceTest extends AbstractGhidraHeadedDebuggerTe
""");
trace.getBreakpointManager()
.addBreakpoint("Breakpoints[2]", Lifespan.nowOn(0), addrI2, Set.of(thread),
Set.of(TraceBreakpointKind.SW_EXECUTE), true, "test");
CommonSet.SWX.kinds(), true, "test");
}
assertEquals(0, emulationPlugin.cache.size());
@@ -580,10 +580,10 @@ public class DebuggerEmulationServiceTest extends AbstractGhidraHeadedDebuggerTe
try (Transaction tx = trace.openTransaction("Add breakpoint")) {
trace.getBreakpointManager()
.addBreakpoint("Breakpoints[0]", Lifespan.nowOn(0), addrText, Set.of(thread),
Set.of(TraceBreakpointKind.SW_EXECUTE), true, "test");
CommonSet.SWX.kinds(), true, "test");
TraceBreakpointLocation tb = trace.getBreakpointManager()
.addBreakpoint("Breakpoints[1]", Lifespan.nowOn(0), addrI1, Set.of(thread),
Set.of(TraceBreakpointKind.SW_EXECUTE), true, "test");
CommonSet.SWX.kinds(), true, "test");
// Force "partial instruction"
tb.setEmuSleigh(0, """
r1 = 0xbeef;
@@ -649,7 +649,7 @@ public class DebuggerEmulationServiceTest extends AbstractGhidraHeadedDebuggerTe
try (Transaction tx = trace.openTransaction("Add breakpoint")) {
TraceBreakpointLocation tb = trace.getBreakpointManager()
.addBreakpoint("Breakpoints[1]", Lifespan.nowOn(0), addrI1, Set.of(thread),
Set.of(TraceBreakpointKind.SW_EXECUTE), true, "test");
CommonSet.SWX.kinds(), true, "test");
// Force "partial instruction"
tb.setEmuSleigh(0, """
r1 = 0xbeef;
@@ -724,7 +724,7 @@ public class DebuggerEmulationServiceTest extends AbstractGhidraHeadedDebuggerTe
try (Transaction tx = trace.openTransaction("Add breakpoint")) {
TraceBreakpointLocation tb = trace.getBreakpointManager()
.addBreakpoint("Breakpoints[0]", Lifespan.nowOn(0), addrI2, Set.of(thread),
Set.of(TraceBreakpointKind.SW_EXECUTE), true, "test");
CommonSet.SWX.kinds(), true, "test");
tb.setEmuSleigh(0, """
r1 = 0x5678;
emu_swi();
@@ -791,7 +791,7 @@ public class DebuggerEmulationServiceTest extends AbstractGhidraHeadedDebuggerTe
try (Transaction tx = trace.openTransaction("Add breakpoint")) {
trace.getBreakpointManager()
.addBreakpoint("Breakpoints[0]", Lifespan.nowOn(0), addr(trace, 0x1234),
Set.of(thread), Set.of(TraceBreakpointKind.READ), true, "test");
Set.of(thread), CommonSet.READ.kinds(), true, "test");
}
EmulationResult result = emulationPlugin.run(trace.getPlatformManager().getHostPlatform(),
@@ -869,7 +869,7 @@ public class DebuggerEmulationServiceTest extends AbstractGhidraHeadedDebuggerTe
try (Transaction tx = trace.openTransaction("Add breakpoint")) {
TraceBreakpointLocation tb = trace.getBreakpointManager()
.addBreakpoint("Breakpoints[0]", Lifespan.nowOn(0), addrI2, Set.of(thread),
Set.of(TraceBreakpointKind.SW_EXECUTE), true, "test");
CommonSet.SWX.kinds(), true, "test");
tb.setEmuSleigh(0, """
r1 = 0x5678;
emu_exec_decoded();
@@ -80,7 +80,7 @@ import ghidra.program.model.symbol.SourceType;
import ghidra.program.util.*;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.TraceLocation;
import ghidra.trace.model.breakpoint.TraceBreakpointKind;
import ghidra.trace.model.breakpoint.TraceBreakpointKind.CommonSet;
import ghidra.trace.model.breakpoint.TraceBreakpointLocation;
import ghidra.trace.model.listing.TraceData;
import ghidra.trace.model.memory.TraceMemorySpace;
@@ -831,7 +831,7 @@ public class StackUnwinderTest extends AbstractGhidraHeadedDebuggerTest {
try (Transaction tx = tb.startTransaction()) {
tb.trace.getBreakpointManager()
.addBreakpoint("Breakpoints[0]", Lifespan.nowOn(0), retInstr, Set.of(),
Set.of(TraceBreakpointKind.SW_EXECUTE), true, "capture return value");
CommonSet.SWX.kinds(), true, "capture return value");
}
EmulationResult result = emuService.run(atSetup.getPlatform(), atSetup.getTime(), monitor,
@@ -892,10 +892,10 @@ public class StackUnwinderTest extends AbstractGhidraHeadedDebuggerTest {
try (Transaction tx = tb.startTransaction()) {
bptUnwind = tb.trace.getBreakpointManager()
.addBreakpoint("Breakpoints[0]", Lifespan.nowOn(0), retInstr, Set.of(),
Set.of(TraceBreakpointKind.SW_EXECUTE), true, "unwind stack");
CommonSet.SWX.kinds(), true, "unwind stack");
tb.trace.getBreakpointManager()
.addBreakpoint("Breakpoints[1]", Lifespan.nowOn(0), tb.addr(0xdeadbeef),
Set.of(), Set.of(TraceBreakpointKind.SW_EXECUTE), true,
Set.of(), CommonSet.SWX.kinds(), true,
"capture return value");
}
@@ -980,7 +980,7 @@ public class StackUnwinderTest extends AbstractGhidraHeadedDebuggerTest {
try (Transaction tx = tb.startTransaction()) {
bptUnwind = tb.trace.getBreakpointManager()
.addBreakpoint("Breakpoints[0]", Lifespan.nowOn(0), entry, Set.of(),
Set.of(TraceBreakpointKind.SW_EXECUTE), true, "unwind stack");
CommonSet.SWX.kinds(), true, "unwind stack");
bptUnwind.setEmuSleigh(0, """
if (%s >= 0x%x) goto <skip>;
emu_swi();
@@ -1121,7 +1121,7 @@ public class StackUnwinderTest extends AbstractGhidraHeadedDebuggerTest {
try (Transaction tx = tb.startTransaction()) {
tb.trace.getBreakpointManager()
.addBreakpoint("Breakpoints[0]", Lifespan.nowOn(0), retInstr, Set.of(),
Set.of(TraceBreakpointKind.SW_EXECUTE), true, "unwind stack");
CommonSet.SWX.kinds(), true, "unwind stack");
}
EmulationResult result = emuService.run(atSetup.getPlatform(), atSetup.getTime(), monitor,
@@ -1161,7 +1161,7 @@ public class StackUnwinderTest extends AbstractGhidraHeadedDebuggerTest {
try (Transaction tx = tb.startTransaction()) {
tb.trace.getBreakpointManager()
.addBreakpoint("Breakpoints[0]", Lifespan.nowOn(0), retInstr, Set.of(),
Set.of(TraceBreakpointKind.SW_EXECUTE), true, "unwind stack");
CommonSet.SWX.kinds(), true, "unwind stack");
}
DebuggerCoordinates atSetup = traceManager.getCurrent();
@@ -1202,7 +1202,7 @@ public class StackUnwinderTest extends AbstractGhidraHeadedDebuggerTest {
try (Transaction tx = tb.startTransaction()) {
tb.trace.getBreakpointManager()
.addBreakpoint("Breakpoints[0]", Lifespan.nowOn(0), retInstr, Set.of(),
Set.of(TraceBreakpointKind.SW_EXECUTE), true, "unwind stack");
CommonSet.SWX.kinds(), true, "unwind stack");
}
DebuggerCoordinates atSetup = traceManager.getCurrent();
@@ -1243,7 +1243,7 @@ public class StackUnwinderTest extends AbstractGhidraHeadedDebuggerTest {
try (Transaction tx = tb.startTransaction()) {
tb.trace.getBreakpointManager()
.addBreakpoint("Breakpoints[0]", Lifespan.nowOn(0), retInstr, Set.of(),
Set.of(TraceBreakpointKind.SW_EXECUTE), true, "unwind stack");
CommonSet.SWX.kinds(), true, "unwind stack");
}
DebuggerCoordinates atSetup = traceManager.getCurrent();
@@ -96,8 +96,6 @@ public class DBTraceBreakpointSpec implements TraceBreakpointSpec, DBTraceObject
@Override
public void setKinds(Lifespan lifespan, Collection<TraceBreakpointKind> kinds) {
// TODO: More efficient encoding
// TODO: Target-Trace mapping is implied by encoded name. Seems bad.
try (LockHold hold = object.getTrace().lockWrite()) {
object.setValue(lifespan, KEY_KINDS, TraceBreakpointKindSet.encode(kinds));
this.kinds = TraceBreakpointKindSet.copyOf(kinds);
@@ -4,9 +4,9 @@
* 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.
@@ -32,20 +32,16 @@ import org.apache.commons.collections4.set.AbstractSetDecorator;
* open us up to database breaks if the common enum changes.
*/
public enum TraceBreakpointKind {
READ(1 << 0),
WRITE(1 << 1),
HW_EXECUTE(1 << 2),
SW_EXECUTE(1 << 3);
READ('R'),
WRITE('W'),
HW_EXECUTE('X'),
SW_EXECUTE('x');
public static final int COUNT = values().length;
public static final List<TraceBreakpointKind> VALUES = List.of(values());
public static final int COUNT = VALUES.size();
public static class TraceBreakpointKindSet extends AbstractSetDecorator<TraceBreakpointKind> {
public static final TraceBreakpointKindSet SW_EXECUTE = of(TraceBreakpointKind.SW_EXECUTE);
public static final TraceBreakpointKindSet HW_EXECUTE = of(TraceBreakpointKind.HW_EXECUTE);
public static final TraceBreakpointKindSet READ = of(TraceBreakpointKind.READ);
public static final TraceBreakpointKindSet WRITE = of(TraceBreakpointKind.WRITE);
public static final TraceBreakpointKindSet ACCESS =
of(TraceBreakpointKind.READ, TraceBreakpointKind.WRITE);
public static final TraceBreakpointKindSet EMPTY = TraceBreakpointKindSet.of();
public static TraceBreakpointKindSet of(TraceBreakpointKind... kinds) {
return new TraceBreakpointKindSet(Set.of(kinds));
@@ -56,29 +52,60 @@ public enum TraceBreakpointKind {
}
/**
* Convert a comma-separated list of kind names to a set of kinds.
* Convert a string of flags to a set of kinds.
* <p>
* For backwards compatibility, this can also accept a comma-separated list of kind names.
* The backwards compatibility will eventually be removed. In the meantime, no string can
* exceed 3 flags, as this has to be able to distinguish which encoding to decode, and the
* shortest name is {@link #READ}.
*
* @param encoded the encoded list
* @param strict true to report unrecognized kinds, false to ignore
* @return the decoded set
*/
public static TraceBreakpointKindSet decode(String encoded, boolean strict) {
Set<TraceBreakpointKind> result = EnumSet.noneOf(TraceBreakpointKind.class);
Set<String> names = new HashSet<>(Set.of(encoded.toUpperCase().split(",")));
for (TraceBreakpointKind k : values()) {
if (names.remove(k.name())) {
result.add(k);
}
TraceBreakpointKindSet simple = switch (encoded) {
case "" -> EMPTY;
case "x", "SW_EXECUTE" -> CommonSet.SWX.kinds();
case "X", "HW_EXECUTE" -> CommonSet.HWX.kinds();
case "R", "READ" -> CommonSet.READ.kinds();
case "W", "WRITE" -> CommonSet.WRITE.kinds();
case "RW", "READ,WRITE", "WRITE,READ" -> CommonSet.ACCESS.kinds();
default -> null;
};
if (simple != null) {
return simple;
}
if (strict && !names.isEmpty()) {
throw new IllegalArgumentException(names.toString());
/**
* Distinguishes 3-flag encoding from shortest comma-names encoding. No sane system
* should apply all 4 flags, which would confuse this check.
*/
Set<TraceBreakpointKind> result = EnumSet.noneOf(TraceBreakpointKind.class);
if (encoded.length() < 4) {
for (TraceBreakpointKind k : VALUES) {
if (encoded.contains(k.flagStr)) {
result.add(k);
}
}
// I kind of don't care about "strict" anymore
}
else {
Set<String> names = new HashSet<>(Set.of(encoded.toUpperCase().split(",")));
for (TraceBreakpointKind k : VALUES) {
if (names.remove(k.name())) {
result.add(k);
}
}
if (strict && !names.isEmpty()) {
throw new IllegalArgumentException(names.toString());
}
}
return new TraceBreakpointKindSet(result);
}
/**
* Convert a set (or collection) of kinds to a comma-separated list of names.
*
* Convert a set (or collection) of kinds to a string of flags
* <p>
* The list is always encoded in order of the declaration of kinds (enum order).
*
* @param col the set
@@ -86,14 +113,9 @@ public enum TraceBreakpointKind {
*/
public static String encode(Collection<TraceBreakpointKind> col) {
StringBuilder sb = new StringBuilder();
boolean first = true;
for (TraceBreakpointKind k : values()) {
for (TraceBreakpointKind k : VALUES) {
if (col.contains(k)) {
if (!first) {
sb.append(',');
}
first = false;
sb.append(k.name());
sb.append(k.flag);
}
}
return sb.toString();
@@ -109,13 +131,39 @@ public enum TraceBreakpointKind {
}
}
private final byte bits;
public enum CommonSet {
SWX("Execute (sw)", TraceBreakpointKindSet.of(TraceBreakpointKind.SW_EXECUTE)),
HWX("Execute (hw)", TraceBreakpointKindSet.of(TraceBreakpointKind.HW_EXECUTE)),
READ("Read (hw)", TraceBreakpointKindSet.of(TraceBreakpointKind.READ)),
WRITE("Write (hw)", TraceBreakpointKindSet.of(TraceBreakpointKind.WRITE)),
ACCESS("Access (hw)", TraceBreakpointKindSet.of(
TraceBreakpointKind.READ, TraceBreakpointKind.WRITE));
TraceBreakpointKind(int mask) {
this.bits = (byte) mask;
public static final List<CommonSet> VALUES = List.of(values());
private final String display;
private final TraceBreakpointKindSet kinds;
private CommonSet(String display, TraceBreakpointKindSet kinds) {
this.display = display;
this.kinds = kinds;
}
@Override
public String toString() {
return display;
}
public TraceBreakpointKindSet kinds() {
return kinds;
}
}
public byte getBits() {
return bits;
private final char flag;
private final String flagStr;
TraceBreakpointKind(char flag) {
this.flag = flag;
this.flagStr = "" + flag;
}
}
@@ -29,7 +29,7 @@ import db.Transaction;
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
import ghidra.trace.database.ToyDBTraceBuilder;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.breakpoint.TraceBreakpointKind;
import ghidra.trace.model.breakpoint.TraceBreakpointKind.CommonSet;
import ghidra.trace.model.breakpoint.TraceBreakpointLocation;
import ghidra.trace.model.target.schema.TraceObjectSchema.SchemaName;
import ghidra.trace.model.target.schema.XmlSchemaContext;
@@ -93,7 +93,7 @@ public class DBTraceBreakpointManagerTest extends AbstractGhidraHeadlessIntegrat
try (Transaction tx = b.startTransaction()) {
breakpointManager.addBreakpoint("Breakpoints[0]", Lifespan.span(0, 10),
b.addr(0x00400000),
Set.of(), Set.of(TraceBreakpointKind.SW_EXECUTE), true, "main");
Set.of(), CommonSet.SWX.kinds(), true, "main");
}
try (Transaction tx = b.startTransaction()) {
@@ -114,13 +114,13 @@ public class DBTraceBreakpointManagerTest extends AbstractGhidraHeadlessIntegrat
// For table mode, ensure the answer is the same as object mode
breakMain = breakpointManager.addBreakpoint("Breakpoints[0]", Lifespan.span(0, 10),
b.addr(0x00400000),
Set.of(thread), Set.of(TraceBreakpointKind.SW_EXECUTE), true, "main");
Set.of(thread), CommonSet.SWX.kinds(), true, "main");
breakVarA = breakpointManager.addBreakpoint("Breakpoints[1]", Lifespan.span(0, 10),
b.range(0x00600010, 0x00600013),
Set.of(thread), Set.of(TraceBreakpointKind.WRITE), false, "varA");
Set.of(thread), CommonSet.WRITE.kinds(), false, "varA");
breakVarB = breakpointManager.addBreakpoint("Breakpoints[1]", Lifespan.span(11, 20),
b.range(0x00600020, 0x00600023),
Set.of(thread), Set.of(TraceBreakpointKind.WRITE), false, "varB");
Set.of(thread), CommonSet.WRITE.kinds(), false, "varB");
}
}
@@ -231,12 +231,12 @@ public class DBTraceBreakpointManagerTest extends AbstractGhidraHeadlessIntegrat
@Test
public void testSetGetKinds() throws Exception {
addBreakpoints();
assertEquals(Set.of(TraceBreakpointKind.SW_EXECUTE), Set.copyOf(breakMain.getKinds(0)));
assertEquals(CommonSet.SWX.kinds(), Set.copyOf(breakMain.getKinds(0)));
try (Transaction tx = b.startTransaction()) {
breakMain.getSpecification().setKinds(0, Set.of(TraceBreakpointKind.HW_EXECUTE));
assertEquals(Set.of(TraceBreakpointKind.HW_EXECUTE), Set.copyOf(breakMain.getKinds(0)));
breakMain.getSpecification().setKinds(0, CommonSet.HWX.kinds());
assertEquals(CommonSet.HWX.kinds(), Set.copyOf(breakMain.getKinds(0)));
}
assertEquals(Set.of(TraceBreakpointKind.HW_EXECUTE), Set.copyOf(breakMain.getKinds(0)));
assertEquals(CommonSet.HWX.kinds(), Set.copyOf(breakMain.getKinds(0)));
}
@Test
@@ -20,7 +20,6 @@ import static org.junit.Assert.assertNotNull;
import java.awt.event.MouseEvent;
import java.util.List;
import java.util.Set;
import org.junit.*;
@@ -59,7 +58,7 @@ import ghidra.trace.database.ToyDBTraceBuilder;
import ghidra.trace.database.target.DBTraceObject;
import ghidra.trace.model.DefaultTraceLocation;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.breakpoint.TraceBreakpointKind;
import ghidra.trace.model.breakpoint.TraceBreakpointKind.CommonSet;
import ghidra.trace.model.target.TraceObject.ConflictResolution;
import ghidra.trace.model.target.path.KeyPath;
import ghidra.util.Msg;
@@ -115,7 +114,7 @@ public class DebuggerBreakpointMarkerPluginScreenShots extends GhidraScreenShotG
DBTraceObject objBptLoc = tb.trace.getObjectManager().createObject(pathSpec.index(1));
objBptLoc.setAttribute(Lifespan.nowOn(0), "Range",
new AddressRangeImpl(dynAddr, dynAddr));
objBptSpec.setAttribute(Lifespan.nowOn(0), "Kinds", "SW_EXECUTE");
objBptSpec.setAttribute(Lifespan.nowOn(0), "Kinds", "x");
objBptSpec.setAttribute(Lifespan.nowOn(0), "Enabled", enabled);
objBptLoc.insert(Lifespan.nowOn(0), ConflictResolution.DENY);
}
@@ -150,7 +149,7 @@ public class DebuggerBreakpointMarkerPluginScreenShots extends GhidraScreenShotG
Msg.debug(this, "Placing disabled breakpoint");
breakpointService.placeBreakpointAt(program, addr(program, 0x00401c60), 1,
Set.of(TraceBreakpointKind.SW_EXECUTE), "");
CommonSet.SWX.kinds(), "");
LogicalBreakpoint lbDis = waitForValue(() -> Unique.assertAtMostOne(
breakpointService.getBreakpointsAt(program, addr(program, 0x00401c60))));
placeBreakpoint(1, lbDis.getTraceAddress(tb.trace), false);
@@ -158,7 +157,7 @@ public class DebuggerBreakpointMarkerPluginScreenShots extends GhidraScreenShotG
Msg.debug(this, "Placing enabled breakpoint");
breakpointService.placeBreakpointAt(program, addr(program, 0x00401c63), 1,
Set.of(TraceBreakpointKind.SW_EXECUTE), "");
CommonSet.SWX.kinds(), "");
LogicalBreakpoint lbEn = waitForValue(() -> Unique.assertAtMostOne(
breakpointService.getBreakpointsAt(program, addr(program, 0x00401c63))));
placeBreakpoint(2, lbEn.getTraceAddress(tb.trace), true);
@@ -296,7 +295,7 @@ public class DebuggerBreakpointMarkerPluginScreenShots extends GhidraScreenShotG
Msg.debug(this, "Placing breakpoint");
breakpointService.placeBreakpointAt(program, addr(program, 0x00401070), 1,
Set.of(TraceBreakpointKind.SW_EXECUTE), "");
CommonSet.SWX.kinds(), "");
LogicalBreakpoint lbEn = waitForValue(() -> Unique.assertAtMostOne(
breakpointService.getBreakpointsAt(program, addr(program, 0x00401070))));
placeBreakpoint(1, lbEn.getTraceAddress(tb.trace), true);
@@ -337,7 +336,7 @@ public class DebuggerBreakpointMarkerPluginScreenShots extends GhidraScreenShotG
Msg.debug(this, "Placing breakpoint");
breakpointService.placeBreakpointAt(program, addr(program, 0x00401070), 1,
Set.of(TraceBreakpointKind.SW_EXECUTE), "");
CommonSet.SWX.kinds(), "");
LogicalBreakpoint lbEn = waitForValue(() -> Unique.assertAtMostOne(
breakpointService.getBreakpointsAt(program, addr(program, 0x00401070))));
placeBreakpoint(1, lbEn.getTraceAddress(tb.trace), true);
@@ -357,11 +356,12 @@ public class DebuggerBreakpointMarkerPluginScreenShots extends GhidraScreenShotG
public void testCaptureDebuggerPlaceBreakpointDialog() throws Throwable {
runSwing(
() -> listing.goTo(program, new ProgramLocation(program, addr(program, 0x00401c63))));
performAction(breakpointMarkerPlugin.actionSetSoftwareBreakpoint, false);
performAction(breakpointMarkerPlugin.actionsSetBreakpoint.get(CommonSet.SWX), false);
DebuggerPlaceBreakpointDialog dialog =
waitForDialogComponent(DebuggerPlaceBreakpointDialog.class);
dialog.setName("After setup");
dialog.getComponent().grabFocus();
captureDialog(dialog);
}
}
@@ -45,6 +45,7 @@ import ghidra.trace.database.ToyDBTraceBuilder;
import ghidra.trace.database.breakpoint.DBTraceBreakpointManager;
import ghidra.trace.model.*;
import ghidra.trace.model.breakpoint.*;
import ghidra.trace.model.breakpoint.TraceBreakpointKind.CommonSet;
import ghidra.util.Msg;
import ghidra.util.task.TaskMonitor;
import help.screenshot.GhidraScreenShotGenerator;
@@ -137,12 +138,10 @@ public class DebuggerBreakpointsPluginScreenShots extends GhidraScreenShotGenera
try (Transaction tx = program.openTransaction("Add breakpoint")) {
program.getBookmarkManager()
.setBookmark(addr(program, 0x00401234),
LogicalBreakpoint.ENABLED_BOOKMARK_TYPE,
"SW_EXECUTE;1", "before connect");
LogicalBreakpoint.ENABLED_BOOKMARK_TYPE, "x;1", "before connect");
program.getBookmarkManager()
.setBookmark(addr(program, 0x00604321),
LogicalBreakpoint.ENABLED_BOOKMARK_TYPE,
"WRITE;4", "write version");
LogicalBreakpoint.ENABLED_BOOKMARK_TYPE, "W;4", "write version");
}
try (Transaction tx = tb1.startTransaction()) {
@@ -153,14 +152,14 @@ public class DebuggerBreakpointsPluginScreenShots extends GhidraScreenShotGenera
DBTraceBreakpointManager bm = tb1.trace.getBreakpointManager();
TraceBreakpointLocation locCx =
bm.placeBreakpoint("Breakpoints[1]", snap, tb1.addr(0x00401234), List.of(),
Set.of(TraceBreakpointKind.SW_EXECUTE), true, "");
CommonSet.SWX.kinds(), true, "");
locCx.getSpecification()
.getObject()
.setAttribute(Lifespan.nowOn(snap), TraceBreakpointSpec.KEY_EXPRESSION,
"*0x00401234");
TraceBreakpointLocation locWr =
bm.placeBreakpoint("Breakpoints[2]", snap, tb1.range(0x00604321, 0x00604324),
List.of(), Set.of(TraceBreakpointKind.WRITE), true, "");
List.of(), CommonSet.WRITE.kinds(), true, "");
locWr.getSpecification()
.getObject()
.setAttribute(Lifespan.nowOn(snap), TraceBreakpointSpec.KEY_EXPRESSION,
@@ -175,11 +174,11 @@ public class DebuggerBreakpointsPluginScreenShots extends GhidraScreenShotGenera
DBTraceBreakpointManager bm = tb2.trace.getBreakpointManager();
TraceBreakpointLocation locCx =
bm.placeBreakpoint("Breakpoints[1]", snap, tb2.addr(0x7fac1234), List.of(),
Set.of(TraceBreakpointKind.SW_EXECUTE), false, "");
CommonSet.SWX.kinds(), false, "");
locCx.getSpecification()
.getObject()
.setAttribute(Lifespan.nowOn(snap), TraceBreakpointSpec.KEY_EXPRESSION,
"*0x7fac1234");
.getObject()
.setAttribute(Lifespan.nowOn(snap), TraceBreakpointSpec.KEY_EXPRESSION,
"*0x7fac1234");
}
programManager.openProgram(program);
@@ -15,6 +15,7 @@
*/
package agent.dbgeng.rmi;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
@@ -41,7 +42,7 @@ import ghidra.program.model.lang.RegisterValue;
import ghidra.program.model.listing.CodeUnit;
import ghidra.trace.database.ToyDBTraceBuilder;
import ghidra.trace.model.*;
import ghidra.trace.model.breakpoint.TraceBreakpointKind;
import ghidra.trace.model.breakpoint.TraceBreakpointKind.CommonSet;
import ghidra.trace.model.listing.TraceCodeSpace;
import ghidra.trace.model.listing.TraceData;
import ghidra.trace.model.memory.*;
@@ -989,9 +990,9 @@ public class DbgEngCommandsTest extends AbstractDbgEngTraceRmiTest {
Address bp1 = rangeMain.getMinAddress();
assertBreakLoc(procBreakLocVals.get(0), "[0]", bp1, 1,
Set.of(TraceBreakpointKind.SW_EXECUTE), "ntdll!Ldr");
CommonSet.SWX.kinds(), "ntdll!Ldr");
assertBreakLoc(procBreakLocVals.get(1), "[1]", bp1.add(4), 1,
Set.of(TraceBreakpointKind.HW_EXECUTE), "ntdll!Ldr");
CommonSet.HWX.kinds(), "ntdll!Ldr");
}
}
@@ -1031,11 +1032,11 @@ public class DbgEngCommandsTest extends AbstractDbgEngTraceRmiTest {
Address main2 = rangeMain2.getMinAddress();
assertWatchLoc(procBreakVals.get(0), "[0]", main0, (int) rangeMain0.getLength(),
Set.of(TraceBreakpointKind.HW_EXECUTE), "ntdll!LdrInit");
CommonSet.HWX.kinds(), "ntdll!LdrInit");
assertWatchLoc(procBreakVals.get(1), "[1]", main1, (int) rangeMain1.getLength(),
Set.of(TraceBreakpointKind.WRITE), "ntdll!LdrInit");
CommonSet.WRITE.kinds(), "ntdll!LdrInit");
assertWatchLoc(procBreakVals.get(2), "[2]", main2, (int) rangeMain2.getLength(),
Set.of(TraceBreakpointKind.READ), "ntdll!LdrInit");
CommonSet.READ.kinds(), "ntdll!LdrInit");
}
}
@@ -15,7 +15,8 @@
*/
package agent.dbgeng.rmi;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.greaterThan;
import static org.junit.Assert.*;
import java.io.File;
@@ -38,7 +39,7 @@ import ghidra.pty.testutil.DummyProc;
import ghidra.trace.database.ToyDBTraceBuilder;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.Trace;
import ghidra.trace.model.breakpoint.TraceBreakpointKind;
import ghidra.trace.model.breakpoint.TraceBreakpointKind.CommonSet;
import ghidra.trace.model.memory.TraceMemoryRegion;
import ghidra.trace.model.memory.TraceMemorySpace;
import ghidra.trace.model.modules.TraceModule;
@@ -142,9 +143,9 @@ public class DbgEngMethodsTest extends AbstractDbgEngTraceRmiTest {
Address main = rangeMain.getMinAddress();
assertBreakLoc(procBreakLocVals.get(0), "[0]", main, 1,
Set.of(TraceBreakpointKind.SW_EXECUTE), "ntdll!Ldr");
CommonSet.SWX.kinds(), "ntdll!Ldr");
assertBreakLoc(procBreakLocVals.get(1), "[1]", main.add(4), 1,
Set.of(TraceBreakpointKind.HW_EXECUTE), "ntdll!Ldr");
CommonSet.HWX.kinds(), "ntdll!Ldr");
}
}
}
@@ -185,14 +186,11 @@ public class DbgEngMethodsTest extends AbstractDbgEngTraceRmiTest {
Address main2 = rangeMain2.getMinAddress();
assertWatchLoc(procBreakVals.get(0), "[0]", main0, (int) rangeMain0.getLength(),
Set.of(TraceBreakpointKind.HW_EXECUTE),
"main");
CommonSet.HWX.kinds(), "main");
assertWatchLoc(procBreakVals.get(1), "[1]", main1, (int) rangeMain1.getLength(),
Set.of(TraceBreakpointKind.WRITE),
"main+4");
CommonSet.WRITE.kinds(), "main+4");
assertWatchLoc(procBreakVals.get(2), "[2]", main2, (int) rangeMain1.getLength(),
Set.of(TraceBreakpointKind.READ),
"main+8");
CommonSet.READ.kinds(), "main+8");
}
}
}
@@ -44,7 +44,7 @@ import ghidra.program.model.lang.RegisterValue;
import ghidra.program.model.listing.CodeUnit;
import ghidra.trace.database.ToyDBTraceBuilder;
import ghidra.trace.model.*;
import ghidra.trace.model.breakpoint.TraceBreakpointKind;
import ghidra.trace.model.breakpoint.TraceBreakpointKind.CommonSet;
import ghidra.trace.model.listing.TraceCodeSpace;
import ghidra.trace.model.listing.TraceData;
import ghidra.trace.model.memory.*;
@@ -1071,20 +1071,15 @@ public class GdbCommandsTest extends AbstractGdbTraceRmiTest {
// NB. starti avoid use of temporary main breakpoint
assertBreakLoc(infBreakLocVals.get(0), "[1.1]", main, 1,
Set.of(TraceBreakpointKind.SW_EXECUTE),
"*main");
CommonSet.SWX.kinds(), "*main");
assertBreakLoc(infBreakLocVals.get(1), "[2.1]", main.add(10), 1,
Set.of(TraceBreakpointKind.HW_EXECUTE),
"*main+10");
CommonSet.HWX.kinds(), "*main+10");
assertBreakLoc(infBreakLocVals.get(2), "[3.1]", main.add(20), 1,
Set.of(TraceBreakpointKind.WRITE),
"-location *((char*)(&main+20))");
CommonSet.WRITE.kinds(), "-location *((char*)(&main+20))");
assertBreakLoc(infBreakLocVals.get(3), "[4.1]", main.add(30), 8,
Set.of(TraceBreakpointKind.READ),
"-location *((char(*)[8])(&main+30))");
CommonSet.READ.kinds(), "-location *((char(*)[8])(&main+30))");
assertBreakLoc(infBreakLocVals.get(4), "[5.1]", main.add(40), 5,
Set.of(TraceBreakpointKind.READ, TraceBreakpointKind.WRITE),
"-location *((char(*)[5])(&main+40))");
CommonSet.ACCESS.kinds(), "-location *((char(*)[5])(&main+40))");
}
}
@@ -43,7 +43,7 @@ import ghidra.pty.testutil.DummyProc;
import ghidra.trace.database.ToyDBTraceBuilder;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.Trace;
import ghidra.trace.model.breakpoint.TraceBreakpointKind;
import ghidra.trace.model.breakpoint.TraceBreakpointKind.CommonSet;
import ghidra.trace.model.listing.TraceCodeSpace;
import ghidra.trace.model.listing.TraceData;
import ghidra.trace.model.memory.TraceMemoryRegion;
@@ -146,20 +146,15 @@ public class GdbMethodsTest extends AbstractGdbTraceRmiTest {
// NB. starti avoid use of temporary main breakpoint
assertBreakLoc(infBreakLocVals.get(0), "[1.1]", main, 1,
Set.of(TraceBreakpointKind.SW_EXECUTE),
"*main");
CommonSet.SWX.kinds(), "*main");
assertBreakLoc(infBreakLocVals.get(1), "[2.1]", main.add(10), 1,
Set.of(TraceBreakpointKind.HW_EXECUTE),
"*main+10");
CommonSet.HWX.kinds(), "*main+10");
assertBreakLoc(infBreakLocVals.get(2), "[3.1]", main.add(20), 1,
Set.of(TraceBreakpointKind.WRITE),
"-location *((char*)(&main+20))");
CommonSet.WRITE.kinds(), "-location *((char*)(&main+20))");
assertBreakLoc(infBreakLocVals.get(3), "[4.1]", main.add(30), 8,
Set.of(TraceBreakpointKind.READ),
"-location *((char(*)[8])(&main+30))");
CommonSet.READ.kinds(), "-location *((char(*)[8])(&main+30))");
assertBreakLoc(infBreakLocVals.get(4), "[5.1]", main.add(40), 5,
Set.of(TraceBreakpointKind.READ, TraceBreakpointKind.WRITE),
"-location *((char(*)[5])(&main+40))");
CommonSet.ACCESS.kinds(), "-location *((char(*)[5])(&main+40))");
}
}
}
@@ -202,20 +197,15 @@ public class GdbMethodsTest extends AbstractGdbTraceRmiTest {
// NB. starti avoid use of temporary main breakpoint
assertBreakLoc(infBreakLocVals.get(0), "[1.1]", main, 1,
Set.of(TraceBreakpointKind.SW_EXECUTE),
"*main");
CommonSet.SWX.kinds(), "*main");
assertBreakLoc(infBreakLocVals.get(1), "[2.1]", main.add(10), 1,
Set.of(TraceBreakpointKind.HW_EXECUTE),
"*main+10");
CommonSet.HWX.kinds(), "*main+10");
assertBreakLoc(infBreakLocVals.get(2), "[3.1]", main.add(20), 1,
Set.of(TraceBreakpointKind.WRITE),
"-location *((char*)(&main+20))");
CommonSet.WRITE.kinds(), "-location *((char*)(&main+20))");
assertBreakLoc(infBreakLocVals.get(3), "[4.1]", main.add(30), 8,
Set.of(TraceBreakpointKind.READ),
"-location *((char(*)[8])(&main+30))");
CommonSet.READ.kinds(), "-location *((char(*)[8])(&main+30))");
assertBreakLoc(infBreakLocVals.get(4), "[5.1]", main.add(40), 5,
Set.of(TraceBreakpointKind.READ, TraceBreakpointKind.WRITE),
"-location *((char(*)[5])(&main+40))");
CommonSet.ACCESS.kinds(), "-location *((char(*)[5])(&main+40))");
}
}
}
@@ -15,6 +15,7 @@
*/
package agent.lldb.rmi;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.junit.Assume.assumeFalse;
@@ -45,7 +46,7 @@ import ghidra.program.model.lang.RegisterValue;
import ghidra.program.model.listing.CodeUnit;
import ghidra.trace.database.ToyDBTraceBuilder;
import ghidra.trace.model.*;
import ghidra.trace.model.breakpoint.TraceBreakpointKind;
import ghidra.trace.model.breakpoint.TraceBreakpointKind.CommonSet;
import ghidra.trace.model.listing.TraceCodeSpace;
import ghidra.trace.model.listing.TraceData;
import ghidra.trace.model.memory.*;
@@ -1075,11 +1076,9 @@ public class LldbCommandsTest extends AbstractLldbTraceRmiTest {
Address main = rangeMain.getMinAddress();
assertBreakLoc(procBreakLocVals.get(0), "[1]", main, 1,
Set.of(TraceBreakpointKind.SW_EXECUTE),
"main");
CommonSet.SWX.kinds(), "main");
assertBreakLoc(procBreakLocVals.get(1), "[1]", main, 1,
Set.of(TraceBreakpointKind.HW_EXECUTE),
"main");
CommonSet.HWX.kinds(), "main");
}
}
@@ -1121,11 +1120,11 @@ public class LldbCommandsTest extends AbstractLldbTraceRmiTest {
Address main2 = rangeMain2.getMinAddress();
assertWatchLoc(procWatchLocVals.get(0), "[1]", main0, (int) rangeMain0.getLength(),
Set.of(TraceBreakpointKind.WRITE), "main");
CommonSet.WRITE.kinds(), "main");
assertWatchLoc(procWatchLocVals.get(1), "[2]", main1, (int) rangeMain1.getLength(),
Set.of(TraceBreakpointKind.READ), "main");
CommonSet.READ.kinds(), "main");
assertWatchLoc(procWatchLocVals.get(2), "[3]", main2, (int) rangeMain2.getLength(),
Set.of(TraceBreakpointKind.READ, TraceBreakpointKind.WRITE), "main");
CommonSet.ACCESS.kinds(), "main");
}
}
@@ -18,7 +18,7 @@ package agent.lldb.rmi;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.junit.Assume.*;
import static org.junit.Assume.assumeTrue;
import java.util.*;
@@ -37,7 +37,7 @@ import ghidra.pty.testutil.DummyProc;
import ghidra.trace.database.ToyDBTraceBuilder;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.Trace;
import ghidra.trace.model.breakpoint.TraceBreakpointKind;
import ghidra.trace.model.breakpoint.TraceBreakpointKind.CommonSet;
import ghidra.trace.model.memory.TraceMemoryRegion;
import ghidra.trace.model.memory.TraceMemorySpace;
import ghidra.trace.model.modules.TraceModule;
@@ -129,11 +129,9 @@ public class LldbMethodsTest extends AbstractLldbTraceRmiTest {
Address main = rangeMain.getMinAddress();
assertBreakLoc(procBreakLocVals.get(0), "[1]", main, 1,
Set.of(TraceBreakpointKind.SW_EXECUTE),
"main");
CommonSet.SWX.kinds(), "main");
assertBreakLoc(procBreakLocVals.get(1), "[1]", main, 1,
Set.of(TraceBreakpointKind.HW_EXECUTE),
"main");
CommonSet.HWX.kinds(), "main");
}
conn.success();
}
@@ -176,14 +174,11 @@ public class LldbMethodsTest extends AbstractLldbTraceRmiTest {
Address main2 = rangeMain2.getMinAddress();
assertWatchLoc(procWatchLocVals.get(0), "[1]", main0, (int) rangeMain0.getLength(),
Set.of(TraceBreakpointKind.WRITE),
"main");
CommonSet.WRITE.kinds(), "main");
assertWatchLoc(procWatchLocVals.get(1), "[2]", main1, (int) rangeMain1.getLength(),
Set.of(TraceBreakpointKind.READ),
"main+0x20");
CommonSet.READ.kinds(), "main+0x20");
assertWatchLoc(procWatchLocVals.get(2), "[3]", main2, (int) rangeMain1.getLength(),
Set.of(TraceBreakpointKind.READ, TraceBreakpointKind.WRITE),
"main+0x30");
CommonSet.ACCESS.kinds(), "main+0x30");
}
conn.success();
}
@@ -62,7 +62,7 @@ import ghidra.program.model.symbol.SourceType;
import ghidra.program.util.ProgramLocation;
import ghidra.trace.model.*;
import ghidra.trace.model.breakpoint.TraceBreakpointKind;
import ghidra.trace.model.breakpoint.TraceBreakpointKind.TraceBreakpointKindSet;
import ghidra.trace.model.breakpoint.TraceBreakpointKind.CommonSet;
import ghidra.trace.model.breakpoint.TraceBreakpointLocation;
import ghidra.trace.model.program.TraceProgramView;
import ghidra.util.SystemUtilities;
@@ -83,7 +83,7 @@ public abstract class AbstractDebuggerBreakpointMarkerPluginTest<T>
AbstractDisableBreakpointAction.NAME, AbstractClearBreakpointAction.NAME);
protected static final Set<String> SET_ACTIONS =
Set.of("SW_EXECUTE", "HW_EXECUTE", "READ,WRITE", "READ", "WRITE");
Set.of("Execute (sw)", "Execute (hw)", "Access (hw)", "Read (hw)", "Write (hw)");
protected DebuggerBreakpointMarkerPlugin breakpointMarkerPlugin;
protected DebuggerListingPlugin listingPlugin;
@@ -201,7 +201,7 @@ public abstract class AbstractDebuggerBreakpointMarkerPluginTest<T>
TaskMonitor.DUMMY, false);
program.getBookmarkManager()
.setBookmark(addr(program, 0x00400123), LogicalBreakpoint.ENABLED_BOOKMARK_TYPE,
"SW_EXECUTE;1", "");
"x;1", "");
}
}
@@ -505,7 +505,7 @@ public abstract class AbstractDebuggerBreakpointMarkerPluginTest<T>
DebuggerPlaceBreakpointDialog dialog =
waitForDialogComponent(DebuggerPlaceBreakpointDialog.class);
runSwing(() -> dialog.okCallback());
handleSetBreakpointInvocation(TraceBreakpointKindSet.SW_EXECUTE, 0x55550123);
handleSetBreakpointInvocation(CommonSet.SWX.kinds(), 0x55550123);
waitForDomainObject(program);
waitForDomainObject(tb.trace);
waitOn(breakpointService.changesSettled());
@@ -514,7 +514,7 @@ public abstract class AbstractDebuggerBreakpointMarkerPluginTest<T>
LogicalBreakpoint lb = Unique.assertOne(breakpointService.getAllBreakpoints());
assertEquals(State.ENABLED, lb.computeState());
// TODO: Different cases for different expected default kinds?
assertEquals(Set.of(TraceBreakpointKind.SW_EXECUTE), lb.getKinds());
assertEquals(CommonSet.SWX.kinds(), lb.getKinds());
});
}
@@ -543,7 +543,7 @@ public abstract class AbstractDebuggerBreakpointMarkerPluginTest<T>
DebuggerPlaceBreakpointDialog dialog =
waitForDialogComponent(DebuggerPlaceBreakpointDialog.class);
runSwing(() -> dialog.okCallback());
handleSetBreakpointInvocation(TraceBreakpointKindSet.ACCESS, 0x55550123);
handleSetBreakpointInvocation(CommonSet.ACCESS.kinds(), 0x55550123);
waitForDomainObject(program);
waitForDomainObject(tb.trace);
waitOn(breakpointService.changesSettled());
@@ -552,7 +552,7 @@ public abstract class AbstractDebuggerBreakpointMarkerPluginTest<T>
LogicalBreakpoint lb = Unique.assertOne(breakpointService.getAllBreakpoints());
assertEquals(State.ENABLED, lb.computeState());
// TODO: Different cases for different expected default kinds?
assertEquals(TraceBreakpointKindSet.ACCESS, lb.getKinds());
assertEquals(CommonSet.ACCESS.kinds(), lb.getKinds());
});
}
@@ -621,8 +621,8 @@ public abstract class AbstractDebuggerBreakpointMarkerPluginTest<T>
waitForPass(() -> assertEquals(State.ENABLED, lb.computeStateForTrace(trace)));
}
protected void testActionSetBreakpointProgram(DockingAction action,
Set<TraceBreakpointKind> expectedKinds) throws Throwable {
protected void testActionSetBreakpointProgram(CommonSet kind) throws Throwable {
DockingAction action = breakpointMarkerPlugin.actionsSetBreakpoint.get(kind);
addMappedBreakpointOpenAndWait(); // Adds an unneeded breakpoint. Aw well.
ProgramLocationActionContext ctx = staticCtx(addr(program, 0x0400321));
@@ -635,19 +635,19 @@ public abstract class AbstractDebuggerBreakpointMarkerPluginTest<T>
dialog.okCallback();
});
handleSetBreakpointInvocation(expectedKinds, 0x55550321);
handleSetBreakpointInvocation(kind.kinds(), 0x55550321);
waitForPass(() -> {
LogicalBreakpoint lb = Unique.assertOne(
breakpointService.getBreakpointsAt(program, addr(program, 0x00400321)));
assertEquals(expectedKinds, lb.getKinds());
assertEquals(kind.kinds(), lb.getKinds());
assertEquals(State.ENABLED, lb.computeState());
assertEquals("Test name", lb.getName());
});
}
protected void testActionSetBreakpointTrace(DockingAction action,
Set<TraceBreakpointKind> expectedKinds) throws Throwable {
protected void testActionSetBreakpointTrace(CommonSet kind) throws Throwable {
DockingAction action = breakpointMarkerPlugin.actionsSetBreakpoint.get(kind);
T t = addMappedBreakpointOpenAndWait(); // Adds an unneeded breakpoint. Aw well.
Trace trace = getTrace(t);
@@ -657,12 +657,12 @@ public abstract class AbstractDebuggerBreakpointMarkerPluginTest<T>
DebuggerPlaceBreakpointDialog dialog =
waitForDialogComponent(DebuggerPlaceBreakpointDialog.class);
runSwing(() -> dialog.okCallback());
handleSetBreakpointInvocation(expectedKinds, 0x55550321);
handleSetBreakpointInvocation(kind.kinds(), 0x55550321);
waitForPass(() -> {
LogicalBreakpoint lb = Unique
.assertOne(breakpointService.getBreakpointsAt(trace, addr(trace, 0x55550321)));
assertEquals(expectedKinds, lb.getKinds());
assertEquals(kind.kinds(), lb.getKinds());
assertEquals(State.ENABLED, lb.computeStateForTrace(trace));
});
/**
@@ -672,63 +672,53 @@ public abstract class AbstractDebuggerBreakpointMarkerPluginTest<T>
}
@Test
public void testActionSetSoftwareBreakpointProgram() throws Throwable {
testActionSetBreakpointProgram(breakpointMarkerPlugin.actionSetSoftwareBreakpoint,
Set.of(TraceBreakpointKind.SW_EXECUTE));
public void testActionSetSwExecuteBreakpointProgram() throws Throwable {
testActionSetBreakpointProgram(CommonSet.SWX);
}
@Test
public void testActionSetSoftwareBreakpointTrace() throws Throwable {
testActionSetBreakpointTrace(breakpointMarkerPlugin.actionSetSoftwareBreakpoint,
Set.of(TraceBreakpointKind.SW_EXECUTE));
public void testActionSetSwExecuteBreakpointTrace() throws Throwable {
testActionSetBreakpointTrace(CommonSet.SWX);
}
@Test
public void testActionSetExecuteBreakpointProgram() throws Throwable {
testActionSetBreakpointProgram(breakpointMarkerPlugin.actionSetExecuteBreakpoint,
Set.of(TraceBreakpointKind.HW_EXECUTE));
public void testActionSetHwExecuteBreakpointProgram() throws Throwable {
testActionSetBreakpointProgram(CommonSet.HWX);
}
@Test
public void testActionSetExecuteBreakpointTrace() throws Throwable {
testActionSetBreakpointTrace(breakpointMarkerPlugin.actionSetExecuteBreakpoint,
Set.of(TraceBreakpointKind.HW_EXECUTE));
}
@Test
public void testActionSetReadWriteBreakpointProgram() throws Throwable {
testActionSetBreakpointProgram(breakpointMarkerPlugin.actionSetReadWriteBreakpoint,
Set.of(TraceBreakpointKind.READ, TraceBreakpointKind.WRITE));
}
@Test
public void testActionSetReadWriteBreakpointTrace() throws Throwable {
testActionSetBreakpointTrace(breakpointMarkerPlugin.actionSetReadWriteBreakpoint,
Set.of(TraceBreakpointKind.READ, TraceBreakpointKind.WRITE));
public void testActionSetHwExecuteBreakpointTrace() throws Throwable {
testActionSetBreakpointTrace(CommonSet.HWX);
}
@Test
public void testActionSetReadBreakpointProgram() throws Throwable {
testActionSetBreakpointProgram(breakpointMarkerPlugin.actionSetReadBreakpoint,
Set.of(TraceBreakpointKind.READ));
testActionSetBreakpointProgram(CommonSet.READ);
}
@Test
public void testActionSetReadBreakpointTrace() throws Throwable {
testActionSetBreakpointTrace(breakpointMarkerPlugin.actionSetReadBreakpoint,
Set.of(TraceBreakpointKind.READ));
testActionSetBreakpointTrace(CommonSet.READ);
}
@Test
public void testActionSetWriteBreakpointProgram() throws Throwable {
testActionSetBreakpointProgram(breakpointMarkerPlugin.actionSetWriteBreakpoint,
Set.of(TraceBreakpointKind.WRITE));
testActionSetBreakpointProgram(CommonSet.WRITE);
}
@Test
public void testActionSetWriteBreakpointTrace() throws Throwable {
testActionSetBreakpointTrace(breakpointMarkerPlugin.actionSetWriteBreakpoint,
Set.of(TraceBreakpointKind.WRITE));
testActionSetBreakpointTrace(CommonSet.WRITE);
}
@Test
public void testActionSetAccessBreakpointProgram() throws Throwable {
testActionSetBreakpointProgram(CommonSet.ACCESS);
}
@Test
public void testActionSetAccessBreakpointTrace() throws Throwable {
testActionSetBreakpointTrace(CommonSet.ACCESS);
}
@Test
@@ -867,7 +857,7 @@ public abstract class AbstractDebuggerBreakpointMarkerPluginTest<T>
waitForPass(() -> {
LogicalBreakpoint lb = Unique.assertOne(breakpointService.getAllBreakpoints());
assertEquals(State.INEFFECTIVE_ENABLED, lb.computeState());
assertEquals(Set.of(TraceBreakpointKind.SW_EXECUTE), lb.getKinds());
assertEquals(CommonSet.SWX.kinds(), lb.getKinds());
});
performEnabledAction(decompilerProvider, breakpointMarkerPlugin.actionToggleBreakpoint,
@@ -875,7 +865,7 @@ public abstract class AbstractDebuggerBreakpointMarkerPluginTest<T>
waitForPass(() -> {
LogicalBreakpoint lb = Unique.assertOne(breakpointService.getAllBreakpoints());
assertEquals(State.INEFFECTIVE_DISABLED, lb.computeState());
assertEquals(Set.of(TraceBreakpointKind.SW_EXECUTE), lb.getKinds());
assertEquals(CommonSet.SWX.kinds(), lb.getKinds());
});
}
@@ -891,9 +881,9 @@ public abstract class AbstractDebuggerBreakpointMarkerPluginTest<T>
runSwing(() -> decompilerProvider.getController().setDecompileData(mockData(results)));
waitOn(breakpointService.placeBreakpointAt(program, entry, 1,
Set.of(TraceBreakpointKind.SW_EXECUTE), ""));
CommonSet.SWX.kinds(), ""));
waitOn(breakpointService.placeBreakpointAt(program, entry.add(2), 1,
Set.of(TraceBreakpointKind.SW_EXECUTE), ""));
CommonSet.SWX.kinds(), ""));
waitForPass(() -> {
assertEquals(2, breakpointService.getAllBreakpoints().size());
});
@@ -50,7 +50,7 @@ import ghidra.program.model.mem.MemoryConflictException;
import ghidra.program.util.ProgramLocation;
import ghidra.trace.model.*;
import ghidra.trace.model.breakpoint.TraceBreakpointKind;
import ghidra.trace.model.breakpoint.TraceBreakpointKind.TraceBreakpointKindSet;
import ghidra.trace.model.breakpoint.TraceBreakpointKind.CommonSet;
import ghidra.trace.model.breakpoint.TraceBreakpointLocation;
import ghidra.trace.model.time.TraceSnapshot;
import ghidra.util.SystemUtilities;
@@ -107,7 +107,7 @@ public abstract class AbstractDebuggerBreakpointsProviderTest<T, P>
TaskMonitor.DUMMY, false);
program.getBookmarkManager()
.setBookmark(addr(program, 0x00400123), LogicalBreakpoint.ENABLED_BOOKMARK_TYPE,
"SW_EXECUTE;1", "");
"x;1", "");
}
}
@@ -153,7 +153,7 @@ public abstract class AbstractDebuggerBreakpointsProviderTest<T, P>
Unique.assertOne(breakpointsProvider.breakpointTableModel.getModelData());
assertEquals("55550123", row.getAddress().toString());
assertEquals(trace, row.getDomainObject());
assertEquals("SW_EXECUTE", row.getKinds());
assertEquals("x", row.getKind());
assertEquals(State.INCONSISTENT_ENABLED, row.getState());
}
@@ -197,7 +197,7 @@ public abstract class AbstractDebuggerBreakpointsProviderTest<T, P>
Unique.assertOne(breakpointsProvider.breakpointTableModel.getModelData());
assertEquals("00400123", row.getAddress().toString());
assertEquals(program, row.getDomainObject());
assertEquals("SW_EXECUTE", row.getKinds());
assertEquals("x", row.getKind());
assertEquals(State.INEFFECTIVE_ENABLED, row.getState());
}
@@ -534,7 +534,7 @@ public abstract class AbstractDebuggerBreakpointsProviderTest<T, P>
});
performAction(breakpointsProvider.actionMakeBreakpointsEffective);
handleSetBreakpointInvocation(TraceBreakpointKindSet.SW_EXECUTE, 0x55550123);
handleSetBreakpointInvocation(CommonSet.SWX.kinds(), 0x55550123);
waitForPass(() -> {
assertFalse(breakpointsProvider.actionMakeBreakpointsEffective.isEnabled());
@@ -29,7 +29,7 @@ import ghidra.trace.database.target.DBTraceObjectManager;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.Trace;
import ghidra.trace.model.breakpoint.TraceBreakpointKind;
import ghidra.trace.model.breakpoint.TraceBreakpointKind.TraceBreakpointKindSet;
import ghidra.trace.model.breakpoint.TraceBreakpointKind.CommonSet;
import ghidra.trace.model.breakpoint.TraceBreakpointLocation;
@Category(NightlyCategory.class)
@@ -76,8 +76,7 @@ public class DebuggerRmiBreakpointMarkerPluginTest
try (Transaction tx = tb.startTransaction()) {
DBTraceObjectManager objs = tb.trace.getObjectManager();
addMemoryRegion(objs, zeroOn, tb.range(0x55550000, 0x55550fff), "bin:.text", "rx");
addBreakpointAndLoc(objs, zeroOn, tb.range(0x55550123),
Set.of(TraceBreakpointKind.SW_EXECUTE));
addBreakpointAndLoc(objs, zeroOn, tb.range(0x55550123), CommonSet.SWX.kinds());
}
}
@@ -85,46 +84,46 @@ public class DebuggerRmiBreakpointMarkerPluginTest
protected void handleSetBreakpointInvocation(Set<TraceBreakpointKind> expectedKinds,
long dynOffset) throws Throwable {
Lifespan zeroOn = Lifespan.nowOn(0);
if (TraceBreakpointKindSet.READ.equals(expectedKinds)) {
if (CommonSet.READ.kinds().equals(expectedKinds)) {
Map<String, Object> args = rmiMethodSetReadBreak.expect();
addBreakpointAndLoc(tb.trace.getObjectManager(), zeroOn, tb.range(dynOffset),
TraceBreakpointKindSet.READ);
CommonSet.READ.kinds());
rmiMethodSetReadBreak.result(null);
assertEquals(Map.ofEntries(
Map.entry("process", tb.obj("Processes[1]")),
Map.entry("range", tb.range(dynOffset))), args);
}
else if (TraceBreakpointKindSet.WRITE.equals(expectedKinds)) {
else if (CommonSet.WRITE.kinds().equals(expectedKinds)) {
Map<String, Object> args = rmiMethodSetWriteBreak.expect();
addBreakpointAndLoc(tb.trace.getObjectManager(), zeroOn, tb.range(dynOffset),
TraceBreakpointKindSet.WRITE);
CommonSet.WRITE.kinds());
rmiMethodSetWriteBreak.result(null);
assertEquals(Map.ofEntries(
Map.entry("process", tb.obj("Processes[1]")),
Map.entry("range", tb.range(dynOffset))), args);
}
else if (TraceBreakpointKindSet.ACCESS.equals(expectedKinds)) {
else if (CommonSet.ACCESS.kinds().equals(expectedKinds)) {
Map<String, Object> args = rmiMethodSetAccessBreak.expect();
addBreakpointAndLoc(tb.trace.getObjectManager(), zeroOn, tb.range(dynOffset),
TraceBreakpointKindSet.ACCESS);
CommonSet.ACCESS.kinds());
rmiMethodSetAccessBreak.result(null);
assertEquals(Map.ofEntries(
Map.entry("process", tb.obj("Processes[1]")),
Map.entry("range", tb.range(dynOffset))), args);
}
else if (TraceBreakpointKindSet.SW_EXECUTE.equals(expectedKinds)) {
else if (CommonSet.SWX.kinds().equals(expectedKinds)) {
Map<String, Object> args = rmiMethodSetSwBreak.expect();
addBreakpointAndLoc(tb.trace.getObjectManager(), zeroOn, tb.range(dynOffset),
TraceBreakpointKindSet.SW_EXECUTE);
CommonSet.SWX.kinds());
rmiMethodSetSwBreak.result(null);
assertEquals(Map.ofEntries(
Map.entry("process", tb.obj("Processes[1]")),
Map.entry("address", tb.addr(dynOffset))), args);
}
else if (TraceBreakpointKindSet.HW_EXECUTE.equals(expectedKinds)) {
else if (CommonSet.HWX.kinds().equals(expectedKinds)) {
Map<String, Object> args = rmiMethodSetHwBreak.expect();
addBreakpointAndLoc(tb.trace.getObjectManager(), zeroOn, tb.range(dynOffset),
TraceBreakpointKindSet.HW_EXECUTE);
CommonSet.HWX.kinds());
rmiMethodSetHwBreak.result(null);
assertEquals(Map.ofEntries(
Map.entry("process", tb.obj("Processes[1]")),

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