diff --git a/Ghidra/Debug/Debugger/certification.manifest b/Ghidra/Debug/Debugger/certification.manifest index eab950b8d5..1e12776852 100644 --- a/Ghidra/Debug/Debugger/certification.manifest +++ b/Ghidra/Debug/Debugger/certification.manifest @@ -31,6 +31,9 @@ src/main/help/help/topics/DebuggerBreakpointsPlugin/DebuggerBreakpointsPlugin.ht src/main/help/help/topics/DebuggerBreakpointsPlugin/images/DebuggerBreakpointsPlugin.png||GHIDRA||||END| src/main/help/help/topics/DebuggerBreakpointsPlugin/images/breakpoint-disable.png||GHIDRA||||END| src/main/help/help/topics/DebuggerBreakpointsPlugin/images/breakpoint-enable.png||GHIDRA||||END| +src/main/help/help/topics/DebuggerBreakpointsPlugin/images/breakpoint-ineffective-d.png||GHIDRA||||END| +src/main/help/help/topics/DebuggerBreakpointsPlugin/images/breakpoint-ineffective-e.png||GHIDRA||||END| +src/main/help/help/topics/DebuggerBreakpointsPlugin/images/breakpoint-mixed-de.png||GHIDRA||||END| src/main/help/help/topics/DebuggerBreakpointsPlugin/images/breakpoint-mixed-ed.png||GHIDRA||||END| src/main/help/help/topics/DebuggerBreakpointsPlugin/images/breakpoints-clear-all.png||GHIDRA||||END| src/main/help/help/topics/DebuggerBreakpointsPlugin/images/breakpoints-disable-all.png||GHIDRA||||END| @@ -120,6 +123,8 @@ src/main/resources/images/blank.png||GHIDRA||||END| src/main/resources/images/breakpoint-clear.png||GHIDRA||||END| src/main/resources/images/breakpoint-disable.png||GHIDRA||||END| src/main/resources/images/breakpoint-enable.png||GHIDRA||||END| +src/main/resources/images/breakpoint-ineffective-d.png||GHIDRA||||END| +src/main/resources/images/breakpoint-ineffective-e.png||GHIDRA||||END| src/main/resources/images/breakpoint-mixed-de.png||GHIDRA||||END| src/main/resources/images/breakpoint-mixed-ed.png||GHIDRA||||END| src/main/resources/images/breakpoint-set.png||GHIDRA||||END| @@ -165,6 +170,8 @@ src/main/svg/blank.svg||GHIDRA||||END| src/main/svg/breakpoint-clear.svg||GHIDRA||||END| src/main/svg/breakpoint-disable.svg||GHIDRA||||END| src/main/svg/breakpoint-enable.svg||GHIDRA||||END| +src/main/svg/breakpoint-ineffective-d.svg||GHIDRA||||END| +src/main/svg/breakpoint-ineffective-e.svg||GHIDRA||||END| src/main/svg/breakpoint-mixed-de.svg||GHIDRA||||END| src/main/svg/breakpoint-mixed-ed.svg||GHIDRA||||END| src/main/svg/breakpoint-set.svg||GHIDRA||||END| diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerBreakpointMarkerPlugin/images/DebuggerPlaceBreakpointDialog.png b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerBreakpointMarkerPlugin/images/DebuggerPlaceBreakpointDialog.png index a7a15a84b9..87db1282ca 100644 Binary files a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerBreakpointMarkerPlugin/images/DebuggerPlaceBreakpointDialog.png and b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerBreakpointMarkerPlugin/images/DebuggerPlaceBreakpointDialog.png differ diff --git a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerBreakpointsPlugin/DebuggerBreakpointsPlugin.html b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerBreakpointsPlugin/DebuggerBreakpointsPlugin.html index 746711b1b8..b26b6b1eeb 100644 --- a/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerBreakpointsPlugin/DebuggerBreakpointsPlugin.html +++ b/Ghidra/Debug/Debugger/src/main/help/help/topics/DebuggerBreakpointsPlugin/DebuggerBreakpointsPlugin.html @@ -25,7 +25,7 @@
Breakpoints refer to any mechanism which may trap execution based on an address. The breakpoints manager presents all active breakpoints among all open programs and live traces. Note that dead traces are not considered, and only the breakpoints at the present are - considered, even if the user has stepped a trace backward. Breakpoints which map to the same + displayed, even if the user has stepped a trace backward. Breakpoints which map to the same address in the same module, i.e., program image, and otherwise share the same attributes, are grouped into a logical breakpoint. NOTE: The breakpoints window cannot display or manipulate breakpoints from a target until that target is recorded into a trace. See the without respect to the specifications. Often the specification is at a higher stratum than Ghidra natively understands, e.g., the source filename and line number, and so such - specifications are not relevant. Note, however, that the model may not permit locations to be + specifications are not relevant. Note, however, that the model might not permit locations to be manipulated independently of their specification, which may limit how the manager can operate on each breakpoint location.
Because of the logical grouping of breakpoints, it is possible for a breakpoint to be in a mixed or inconsistent state. This happens quite commonly, e.g., when a breakpoint is placed in a Ghidra program before that program is mapped in any traced target. Once mapped in, the - location of that breakpoint in the trace is computed and noted as missing. A missing location - in a logical breakpoint is treated the same as a disabled breakpoint. Thus, the logical - breakpoint enters an inconsistent state, because it is "enabled" in the program, but "disabled" - in the trace. Toggling such a breakpoint enables all missing locations, bringing it into a - consistent enabled state. Toggling it again will disable all locations.
+ location of that breakpoint in the trace is computed and noted as missing. A logical breakpoint + without any location in a trace (i.e., on an actual target) is called "ineffective" and is + drawn in grey. An enabled logical breakpoint having a disabled location is called + "inconsistent" and its icon will indicate that state. A disabled logical breakpoint having an + enabled location is similarly "inconsistent." Toggling ineffective or inconsistent breakpoints + enables and/or places all locations, bringing it into a consistent enabled state. Toggling it + again disables all locations.The top table, which lists logical breakpoints, has the following columns:
- Disabled, or
Inconsistent. Clicking the
- icon toggles the breakpoint.
Enabled
Disabled
Inconsistent: Enabled with disabled
+ locations
Inconsistent: Disabled with enabled
+ locations
Enabled but ineffective
Disabled and ineffectiveThe bottom table, which lists trace breakpoint locations, has the following columns:
* This is a little different from that in the breakpoint service.
*
* @param loc
@@ -657,30 +733,62 @@ public class DebuggerBreakpointMarkerPlugin extends Plugin
@SuppressWarnings("unused")
private final AutoService.Wiring autoServiceWiring;
- @AutoOptionDefined(name = DebuggerResources.OPTION_NAME_COLORS_ENABLED_BREAKPOINT_MARKERS, //
- description = "Background color for memory at an enabled breakpoint", //
- help = @HelpInfo(anchor = "colors"))
+ @AutoOptionDefined(
+ name = DebuggerResources.OPTION_NAME_COLORS_ENABLED_BREAKPOINT_MARKERS, //
+ description = "Background color for memory at an enabled breakpoint", //
+ help = @HelpInfo(anchor = "colors"))
private Color breakpointEnabledMarkerColor =
DebuggerResources.DEFAULT_COLOR_ENABLED_BREAKPOINT_MARKERS;
- @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"))
+ @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"))
private boolean breakpointEnabledColoringBackground =
DebuggerResources.DEFAULT_COLOR_ENABLED_BREAKPOINT_COLORING_BACKGROUND;
- @AutoOptionDefined(name = DebuggerResources.OPTION_NAME_COLORS_DISABLED_BREAKPOINT_MARKERS, //
- description = "Background color for memory at a disabled breakpoint", //
- help = @HelpInfo(anchor = "colors"))
+ @AutoOptionDefined(
+ name = DebuggerResources.OPTION_NAME_COLORS_DISABLED_BREAKPOINT_MARKERS, //
+ description = "Background color for memory at a disabled breakpoint", //
+ help = @HelpInfo(anchor = "colors"))
private Color breakpointDisabledMarkerColor =
DebuggerResources.DEFAULT_COLOR_DISABLED_BREAKPOINT_MARKERS;
- @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"))
+ @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"))
private boolean breakpointDisabledColoringBackground =
DebuggerResources.DEFAULT_COLOR_DISABLED_BREAKPOINT_COLORING_BACKGROUND;
+ @AutoOptionDefined(
+ name = DebuggerResources.OPTION_NAME_COLORS_INEFFECTIVE_E_BREAKPOINT_MARKERS, //
+ description = "Background color for memory at an enabled, but ineffective, breakpoint", //
+ help = @HelpInfo(anchor = "colors"))
+ private Color breakpointIneffectiveEMarkerColor =
+ DebuggerResources.DEFAULT_COLOR_INEFFECTIVE_E_BREAKPOINT_MARKERS;
+
+ @AutoOptionDefined(
+ name = DebuggerResources.OPTION_NAME_COLORS_INEFFECTIVE_E_BREAKPOINT_COLORING_BACKGROUND, //
+ description = "Whether or not to color background for memory at an enabled, but ineffective, breakpoint", //
+ help = @HelpInfo(anchor = "colors"))
+ private boolean breakpointIneffectiveEColoringBackground =
+ DebuggerResources.DEFAULT_COLOR_INEFFECTIVE_E_BREAKPOINT_COLORING_BACKGROUND;
+
+ @AutoOptionDefined(
+ name = DebuggerResources.OPTION_NAME_COLORS_INEFFECTIVE_D_BREAKPOINT_MARKERS, //
+ description = "Background color for memory at an disabled, but ineffective, breakpoint", //
+ help = @HelpInfo(anchor = "colors"))
+ private Color breakpointIneffectiveDMarkerColor =
+ DebuggerResources.DEFAULT_COLOR_INEFFECTIVE_D_BREAKPOINT_MARKERS;
+
+ @AutoOptionDefined(
+ name = DebuggerResources.OPTION_NAME_COLORS_INEFFECTIVE_D_BREAKPOINT_COLORING_BACKGROUND, //
+ description = "Whether or not to color background for memory at an disabled, but ineffective, breakpoint", //
+ help = @HelpInfo(anchor = "colors"))
+ private boolean breakpointIneffectiveDColoringBackground =
+ DebuggerResources.DEFAULT_COLOR_INEFFECTIVE_D_BREAKPOINT_COLORING_BACKGROUND;
+
@SuppressWarnings("unused")
private final AutoOptions.Wiring autoOptionsWiring;
@@ -728,7 +836,8 @@ public class DebuggerBreakpointMarkerPlugin extends Plugin
}
}
- @AutoOptionConsumed(name = DebuggerResources.OPTION_NAME_COLORS_ENABLED_BREAKPOINT_COLORING_BACKGROUND)
+ @AutoOptionConsumed(
+ name = DebuggerResources.OPTION_NAME_COLORS_ENABLED_BREAKPOINT_COLORING_BACKGROUND)
private void setEnabledBreakpointMarkerBackground(boolean breakpointColoringBackground) {
for (BreakpointMarkerSets markers : markersByProgram.values()) {
markers.setEnabledColoringBackground(breakpointColoringBackground);
@@ -742,13 +851,46 @@ public class DebuggerBreakpointMarkerPlugin extends Plugin
}
}
- @AutoOptionConsumed(name = DebuggerResources.OPTION_NAME_COLORS_DISABLED_BREAKPOINT_COLORING_BACKGROUND)
+ @AutoOptionConsumed(
+ name = DebuggerResources.OPTION_NAME_COLORS_DISABLED_BREAKPOINT_COLORING_BACKGROUND)
private void setDisabledBreakpointMarkerBackground(boolean breakpointColoringBackground) {
for (BreakpointMarkerSets markers : markersByProgram.values()) {
markers.setDisabledColoringBackground(breakpointColoringBackground);
}
}
+ @AutoOptionConsumed(
+ name = DebuggerResources.OPTION_NAME_COLORS_INEFFECTIVE_E_BREAKPOINT_MARKERS)
+ private void setIneffectiveEBreakpointMarkerColor(Color breakpointMarkerColor) {
+ for (BreakpointMarkerSets markers : markersByProgram.values()) {
+ markers.setIneffectiveEnabledMarkerColor(breakpointMarkerColor);
+ }
+ }
+
+ @AutoOptionConsumed(
+ name = DebuggerResources.OPTION_NAME_COLORS_INEFFECTIVE_E_BREAKPOINT_COLORING_BACKGROUND)
+ private void setIneffectiveEBreakpointMarkerBackground(boolean breakpointColoringBackground) {
+ for (BreakpointMarkerSets markers : markersByProgram.values()) {
+ markers.setIneffectiveEnabledColoringBackground(breakpointColoringBackground);
+ }
+ }
+
+ @AutoOptionConsumed(
+ name = DebuggerResources.OPTION_NAME_COLORS_INEFFECTIVE_D_BREAKPOINT_MARKERS)
+ private void setIneffectiveDBreakpointMarkerColor(Color breakpointMarkerColor) {
+ for (BreakpointMarkerSets markers : markersByProgram.values()) {
+ markers.setIneffectiveDisabledMarkerColor(breakpointMarkerColor);
+ }
+ }
+
+ @AutoOptionConsumed(
+ name = DebuggerResources.OPTION_NAME_COLORS_INEFFECTIVE_D_BREAKPOINT_COLORING_BACKGROUND)
+ private void setIneffectiveDBreakpointMarkerBackground(boolean breakpointColoringBackground) {
+ for (BreakpointMarkerSets markers : markersByProgram.values()) {
+ markers.setIneffectiveDisabledColoringBackground(breakpointColoringBackground);
+ }
+ }
+
protected TraceRecorder getRecorderFromContext(ActionContext context) {
if (modelService == null) {
return null;
@@ -879,8 +1021,10 @@ public class DebuggerBreakpointMarkerPlugin extends Plugin
}
protected void createActions() {
- actionSetSoftwareBreakpoint = new SetBreakpointAction(Set.of(TraceBreakpointKind.SOFTWARE));
- actionSetExecuteBreakpoint = new SetBreakpointAction(Set.of(TraceBreakpointKind.EXECUTE));
+ 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));
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsProvider.java
index 964075033e..f5bff9e76e 100644
--- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsProvider.java
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsProvider.java
@@ -39,6 +39,7 @@ import ghidra.app.plugin.core.debug.DebuggerPluginPackage;
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
import ghidra.app.plugin.core.debug.gui.DebuggerResources.*;
import ghidra.app.services.*;
+import ghidra.app.services.LogicalBreakpoint.Enablement;
import ghidra.framework.model.DomainObject;
import ghidra.framework.plugintool.AutoService;
import ghidra.framework.plugintool.ComponentProviderAdapter;
@@ -61,7 +62,7 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
protected enum LogicalBreakpointTableColumns
implements EnumeratedTableColumn
* The program ought to be a program database, not a view of a trace.
*
* @param program the program database
@@ -54,6 +55,7 @@ public interface DebuggerLogicalBreakpointService {
/**
* Get a map of addresses to collected logical breakpoints (at present) for a given trace.
*
+ *
* The trace must be associated with a live target. The returned map collects live breakpoints
* in the recorded target, using trace breakpoints from the recorder's current snapshot.
*
@@ -65,6 +67,7 @@ public interface DebuggerLogicalBreakpointService {
/**
* Get the collected logical breakpoints at the given program location.
*
+ *
* The program ought to be a program database, not a view of a trace.
*
* @param program the program database
@@ -76,6 +79,7 @@ public interface DebuggerLogicalBreakpointService {
/**
* Get the collected logical breakpoints (at present) at the given trace location.
*
+ *
* The trace must be associated with a live target. The returned collection includes live
* breakpoints in the recorded target, using trace breakpoints from the recorders' current
* snapshot.
@@ -89,10 +93,12 @@ public interface DebuggerLogicalBreakpointService {
/**
* Get the collected logical breakpoints (at present) at the given location.
*
+ *
* The {@code program} field for the location may be either a program database (static image) or
* a view for a trace associated with a live target. If it is the latter, the view's current
* snapshot is ignored, in favor of the associated recorder's current snapshot.
*
+ *
* If {@code program} is a static image, this is equivalent to using
* {@link #getBreakpointsAt(Program, Address)}. If {@code program} is a trace view, this is
* equivalent to using {@link #getBreakpointsAt(Trace, Address)}.
@@ -105,11 +111,13 @@ public interface DebuggerLogicalBreakpointService {
/**
* Add a listener for logical breakpoint changes.
*
+ *
* Logical breakpoints may change from time to time for a variety of reasons: A new trace is
* started; a static image is opened; the user adds or removes breakpoints; mappings change;
* etc. The service reacts to these events, reconciles the breakpoints, and invokes callbacks
* for the changes, allowing other UI components and services to update accordingly.
*
+ *
* The listening component must maintain a strong reference to the listener, otherwise it will
* be removed and garbage collected. Automatic removal is merely a resource-management
* protection; the listening component should politely remove its listener (see
@@ -177,6 +185,7 @@ public interface DebuggerLogicalBreakpointService {
* Create an enabled breakpoint at the given program location and each mapped live trace
* location.
*
+ *
* The implementation should take care not to create the same breakpoint multiple times. The
* risk of this happening derives from the possibility of one module mapped to multiple targets
* which are all managed by the same debugger, having a single breakpoint container.
@@ -193,9 +202,11 @@ public interface DebuggerLogicalBreakpointService {
/**
* Create an enabled breakpoint at the given trace location only.
*
+ *
* If the given location is mapped to a static module, this still only creates the breakpoint in
* the given trace. However, a logical breakpoint mark will appear at all mapped locations.
*
+ *
* Note, the debugger ultimately determines the placement behavior. If it is managing multiple
* targets, it is possible the breakpoint will be effective in another trace. This fact should
* be reflected correctly in the resulting logical markings once all resulting events have been
@@ -213,6 +224,7 @@ public interface DebuggerLogicalBreakpointService {
/**
* Create an enabled breakpoint at the given location.
*
+ *
* If the given location refers to a static image, this behaves as in
* {@link #placeBreakpointAt(Program, Address, TraceBreakpointKind)}. If it refers to a trace
* view, this behaves as in {@link #placeBreakpointAt(Trace, Address, TraceBreakpointKind)},
@@ -229,6 +241,7 @@ public interface DebuggerLogicalBreakpointService {
/**
* Enable a collection of logical breakpoints on target, if applicable
*
+ *
* This method is preferable to calling {@link LogicalBreakpoint#enable()} on each logical
* breakpoint, because depending on the debugger, a single breakpoint specification may produce
* several effective breakpoints, perhaps spanning multiple targets. While not terribly
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/services/LogicalBreakpoint.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/services/LogicalBreakpoint.java
index 59973cb57c..13c9eae987 100644
--- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/services/LogicalBreakpoint.java
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/services/LogicalBreakpoint.java
@@ -32,56 +32,260 @@ public interface LogicalBreakpoint {
String BREAKPOINT_ENABLED_BOOKMARK_TYPE = "BreakpointEnabled";
String BREAKPOINT_DISABLED_BOOKMARK_TYPE = "BreakpointDisabled";
+ public enum ProgramEnablement {
+ NONE {
+ @Override
+ public Enablement combineTrace(TraceEnablement traceEn) {
+ switch (traceEn) {
+ case NONE:
+ return Enablement.NONE;
+ case MISSING:
+ return Enablement.NONE;
+ case ENABLED:
+ return Enablement.ENABLED;
+ case MIXED:
+ return Enablement.DISABLED_ENABLED;
+ case DISABLED:
+ return Enablement.DISABLED;
+ default:
+ throw new AssertionError();
+ }
+ }
+ },
+ MISSING {
+ @Override
+ public Enablement combineTrace(TraceEnablement traceEn) {
+ switch (traceEn) {
+ case NONE:
+ return Enablement.NONE;
+ case MISSING:
+ return Enablement.NONE;
+ case ENABLED:
+ case MIXED:
+ return Enablement.DISABLED_ENABLED;
+ case DISABLED:
+ return Enablement.DISABLED;
+ default:
+ throw new AssertionError();
+ }
+ }
+ },
+ ENABLED {
+ @Override
+ public Enablement combineTrace(TraceEnablement traceEn) {
+ switch (traceEn) {
+ case NONE:
+ case MISSING:
+ return Enablement.INEFFECTIVE_ENABLED;
+ case ENABLED:
+ return Enablement.ENABLED;
+ case DISABLED:
+ case MIXED:
+ return Enablement.ENABLED_DISABLED;
+ default:
+ throw new AssertionError();
+ }
+ }
+ },
+ DISABLED {
+ @Override
+ public Enablement combineTrace(TraceEnablement traceEn) {
+ switch (traceEn) {
+ case NONE:
+ case MISSING:
+ return Enablement.INEFFECTIVE_DISABLED;
+ case ENABLED:
+ case MIXED:
+ return Enablement.DISABLED_ENABLED;
+ case DISABLED:
+ return Enablement.DISABLED;
+ default:
+ throw new AssertionError();
+ }
+ }
+ };
+
+ public abstract Enablement combineTrace(TraceEnablement traceEn);
+ }
+
+ public enum TraceEnablement {
+ NONE {
+ @Override
+ public TraceEnablement combine(TraceEnablement that) {
+ return that;
+ }
+
+ @Override
+ public Enablement combineProgram(ProgramEnablement progEn) {
+ switch (progEn) {
+ case NONE:
+ case MISSING:
+ return Enablement.NONE;
+ case ENABLED:
+ return Enablement.INEFFECTIVE_ENABLED;
+ case DISABLED:
+ return Enablement.INEFFECTIVE_DISABLED;
+ default:
+ throw new AssertionError();
+ }
+ }
+ },
+ MISSING {
+ @Override
+ public TraceEnablement combine(TraceEnablement that) {
+ return that;
+ }
+
+ @Override
+ public Enablement combineProgram(ProgramEnablement progEn) {
+ switch (progEn) {
+ case NONE:
+ case MISSING:
+ return Enablement.NONE;
+ case ENABLED:
+ return Enablement.INEFFECTIVE_ENABLED;
+ case DISABLED:
+ return Enablement.INEFFECTIVE_DISABLED;
+ default:
+ throw new AssertionError();
+ }
+ }
+ },
+ ENABLED {
+ @Override
+ public TraceEnablement combine(TraceEnablement that) {
+ switch (that) {
+ case NONE:
+ case MISSING:
+ case ENABLED:
+ return ENABLED;
+ case DISABLED:
+ case MIXED:
+ return MIXED;
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ @Override
+ public Enablement combineProgram(ProgramEnablement progEn) {
+ switch (progEn) {
+ case NONE:
+ case MISSING:
+ case DISABLED:
+ return Enablement.ENABLED_DISABLED;
+ case ENABLED:
+ return Enablement.ENABLED;
+ default:
+ throw new AssertionError();
+ }
+ }
+ },
+ DISABLED {
+ @Override
+ public TraceEnablement combine(TraceEnablement that) {
+ switch (that) {
+ case NONE:
+ case MISSING:
+ case DISABLED:
+ return DISABLED;
+ case ENABLED:
+ case MIXED:
+ return MIXED;
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ @Override
+ public Enablement combineProgram(ProgramEnablement progEn) {
+ switch (progEn) {
+ case NONE:
+ case MISSING:
+ case DISABLED:
+ return Enablement.DISABLED;
+ case ENABLED:
+ return Enablement.DISABLED_ENABLED;
+ default:
+ throw new AssertionError();
+ }
+ }
+ },
+ MIXED {
+ @Override
+ public TraceEnablement combine(TraceEnablement that) {
+ return MIXED;
+ }
+
+ @Override
+ public Enablement combineProgram(ProgramEnablement progEn) {
+ return Enablement.ENABLED_DISABLED;
+ }
+ };
+
+ public static TraceEnablement fromBool(boolean en) {
+ return en ? ENABLED : DISABLED;
+ }
+
+ public abstract TraceEnablement combine(TraceEnablement that);
+
+ public abstract Enablement combineProgram(ProgramEnablement progEn);
+ }
+
public enum Enablement {
- NONE(false, false, true) {
+ NONE(false, false, true, false) {
@Override
public Enablement getPrimary() {
return NONE;
}
},
- ENABLED(true, false, true) {
+ ENABLED(true, false, true, true) {
@Override
public Enablement getPrimary() {
return ENABLED;
}
},
- DISABLED(false, true, true) {
+ DISABLED(false, true, true, true) {
@Override
public Enablement getPrimary() {
return DISABLED;
}
},
- ENABLED_DISABLED(true, false, false) {
+ INEFFECTIVE_ENABLED(true, false, true, false) {
@Override
public Enablement getPrimary() {
return ENABLED;
}
},
- DISABLED_ENABLED(false, true, false) {
+ INEFFECTIVE_DISABLED(false, true, true, false) {
+ @Override
+ public Enablement getPrimary() {
+ return DISABLED;
+ }
+ },
+ ENABLED_DISABLED(true, false, false, true) {
+ @Override
+ public Enablement getPrimary() {
+ return ENABLED;
+ }
+ },
+ DISABLED_ENABLED(false, true, false, true) {
@Override
public Enablement getPrimary() {
return DISABLED;
}
};
- public final boolean enabled;
- public final boolean disabled;
- public final boolean consistent;
+ public final boolean enabled; // indicates any enabled location
+ public final boolean disabled; // indicates any disabled location
+ public final boolean consistent; // bookmark and target locations all agree
+ public final boolean effective; // has a target location, even if disabled
- Enablement(boolean enabled, boolean disabled, boolean consistent) {
+ Enablement(boolean enabled, boolean disabled, boolean consistent, boolean effective) {
this.enabled = enabled;
this.disabled = disabled;
this.consistent = consistent;
- }
-
- public Enablement combine(Enablement that) {
- if (this == NONE) {
- return that;
- }
- if (that == NONE) {
- return this;
- }
- return fromBools(this.enabled, that.enabled);
+ this.effective = effective;
}
public Enablement sameAdddress(Enablement that) {
@@ -91,6 +295,9 @@ public interface LogicalBreakpoint {
if (that == NONE) {
return this;
}
+ if (!this.effective && !that.effective) {
+ return this.enabled || that.enabled ? INEFFECTIVE_ENABLED : INEFFECTIVE_DISABLED;
+ }
return fromBools(this.enabled || that.enabled, this.enabled && that.enabled);
}
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/services/TraceRecorder.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/services/TraceRecorder.java
index b41c6f0003..2eed943eb1 100644
--- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/services/TraceRecorder.java
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/services/TraceRecorder.java
@@ -76,9 +76,9 @@ public interface TraceRecorder {
case WRITE:
return TraceBreakpointKind.WRITE;
case HW_EXECUTE:
- return TraceBreakpointKind.EXECUTE;
+ return TraceBreakpointKind.HW_EXECUTE;
case SW_EXECUTE:
- return TraceBreakpointKind.SOFTWARE;
+ return TraceBreakpointKind.SW_EXECUTE;
default:
throw new AssertionError();
}
@@ -109,9 +109,9 @@ public interface TraceRecorder {
return TargetBreakpointKind.READ;
case WRITE:
return TargetBreakpointKind.WRITE;
- case EXECUTE:
+ case HW_EXECUTE:
return TargetBreakpointKind.HW_EXECUTE;
- case SOFTWARE:
+ case SW_EXECUTE:
return TargetBreakpointKind.SW_EXECUTE;
default:
throw new AssertionError();
diff --git a/Ghidra/Debug/Debugger/src/main/resources/images/breakpoint-ineffective-d.png b/Ghidra/Debug/Debugger/src/main/resources/images/breakpoint-ineffective-d.png
new file mode 100644
index 0000000000..cb1d378235
Binary files /dev/null and b/Ghidra/Debug/Debugger/src/main/resources/images/breakpoint-ineffective-d.png differ
diff --git a/Ghidra/Debug/Debugger/src/main/resources/images/breakpoint-ineffective-e.png b/Ghidra/Debug/Debugger/src/main/resources/images/breakpoint-ineffective-e.png
new file mode 100644
index 0000000000..43fb693a6a
Binary files /dev/null and b/Ghidra/Debug/Debugger/src/main/resources/images/breakpoint-ineffective-e.png differ
diff --git a/Ghidra/Debug/Debugger/src/main/svg/breakpoint-ineffective-d.svg b/Ghidra/Debug/Debugger/src/main/svg/breakpoint-ineffective-d.svg
new file mode 100644
index 0000000000..980d822578
--- /dev/null
+++ b/Ghidra/Debug/Debugger/src/main/svg/breakpoint-ineffective-d.svg
@@ -0,0 +1,34 @@
+
+
diff --git a/Ghidra/Debug/Debugger/src/main/svg/breakpoint-ineffective-e.svg b/Ghidra/Debug/Debugger/src/main/svg/breakpoint-ineffective-e.svg
new file mode 100644
index 0000000000..e0732afc1e
--- /dev/null
+++ b/Ghidra/Debug/Debugger/src/main/svg/breakpoint-ineffective-e.svg
@@ -0,0 +1,36 @@
+
+
diff --git a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointMarkerPluginScreenShots.java b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointMarkerPluginScreenShots.java
index 39198d047c..2acb848337 100644
--- a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointMarkerPluginScreenShots.java
+++ b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointMarkerPluginScreenShots.java
@@ -70,7 +70,7 @@ public class DebuggerBreakpointMarkerPluginScreenShots extends GhidraScreenShotG
Msg.debug(this, "Placing breakpoint");
breakpointService.placeBreakpointAt(program, addr(program, 0x00401c60), 1,
- Set.of(TraceBreakpointKind.SOFTWARE));
+ Set.of(TraceBreakpointKind.SW_EXECUTE));
Msg.debug(this, "Disabling breakpoint");
LogicalBreakpoint lb = waitForValue(() -> Unique.assertAtMostOne(
@@ -79,7 +79,7 @@ public class DebuggerBreakpointMarkerPluginScreenShots extends GhidraScreenShotG
Msg.debug(this, "Placing another");
breakpointService.placeBreakpointAt(program, addr(program, 0x00401c63), 1,
- Set.of(TraceBreakpointKind.SOFTWARE));
+ Set.of(TraceBreakpointKind.SW_EXECUTE));
Msg.debug(this, "Saving program");
program.save("Placed breakpoints", TaskMonitor.DUMMY);
diff --git a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsPluginScreenShots.java b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsPluginScreenShots.java
index 632a33b9bd..959367c1d2 100644
--- a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsPluginScreenShots.java
+++ b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsPluginScreenShots.java
@@ -17,6 +17,7 @@ package ghidra.app.plugin.core.debug.gui.breakpoint;
import static ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest.waitForPass;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import java.util.Set;
@@ -138,7 +139,8 @@ public class DebuggerBreakpointsPluginScreenShots extends GhidraScreenShotGenera
waitOn(bc3.placeBreakpoint(mb.addr(0x7fac1234), Set.of(TargetBreakpointKind.SW_EXECUTE)));
TraceBreakpoint bpt = waitForValue(() -> Unique.assertAtMostOne(
- trace3.getBreakpointManager().getBreakpointsAt(0, addr(trace3, 0x7fac1234))));
+ trace3.getBreakpointManager()
+ .getBreakpointsAt(recorder3.getSnap(), addr(trace3, 0x7fac1234))));
try (UndoableTransaction tid =
UndoableTransaction.start(trace3, "Disable breakpoint", true)) {
bpt.setEnabled(false);
@@ -147,14 +149,15 @@ public class DebuggerBreakpointsPluginScreenShots extends GhidraScreenShotGenera
try (UndoableTransaction tid = UndoableTransaction.start(program, "Add breakpoint", true)) {
program.getBookmarkManager()
.setBookmark(addr(program, 0x00401234),
- LogicalBreakpoint.BREAKPOINT_ENABLED_BOOKMARK_TYPE, "SOFTWARE;1", "");
+ LogicalBreakpoint.BREAKPOINT_ENABLED_BOOKMARK_TYPE, "SW_EXECUTE;1", "");
program.getBookmarkManager()
.setBookmark(addr(program, 0x00402345),
- LogicalBreakpoint.BREAKPOINT_DISABLED_BOOKMARK_TYPE, "SOFTWARE;1", "");
+ LogicalBreakpoint.BREAKPOINT_DISABLED_BOOKMARK_TYPE, "SW_EXECUTE;1", "");
}
waitForPass(() -> {
assertEquals(3, breakpointService.getAllBreakpoints().size());
+ assertFalse(bpt.isEnabled());
});
captureIsolatedProvider(provider, 600, 600);
diff --git a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/memview/DebuggerMemviewPluginScreenShots.java b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/memview/DebuggerMemviewPluginScreenShots.java
index 822fc5ab31..706d6e72f2 100644
--- a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/memview/DebuggerMemviewPluginScreenShots.java
+++ b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/memview/DebuggerMemviewPluginScreenShots.java
@@ -115,7 +115,7 @@ public class DebuggerMemviewPluginScreenShots extends GhidraScreenShotGenerator
Set
* This identifies the sort of access that would trap execution
*
+ *
* TODO: This is identical to {@code TargetBreakpointKind} (not in the classpath here). Is there a
* common place we could factor both? Should we? CAUTION: Encoding in a trace database depends on
* this enum's {@code bits} field, so we must take care not to introduce a dependency that would
@@ -32,8 +34,8 @@ import org.apache.commons.collections4.set.AbstractSetDecorator;
public enum TraceBreakpointKind {
READ(1 << 0),
WRITE(1 << 1),
- EXECUTE(1 << 2),
- SOFTWARE(1 << 3);
+ HW_EXECUTE(1 << 2),
+ SW_EXECUTE(1 << 3);
public static class TraceBreakpointKindSet extends AbstractSetDecorator