mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 10:49:34 +02:00
GP-2243: Add some status messages when breakpoints don't enable.
This commit is contained in:
parent
d4a3e091f6
commit
6266ecbea4
8 changed files with 149 additions and 8 deletions
|
@ -532,7 +532,12 @@ public class DebuggerBreakpointMarkerPlugin extends Plugin
|
||||||
}
|
}
|
||||||
ProgramLocation location = getLocationFromContext(context);
|
ProgramLocation location = getLocationFromContext(context);
|
||||||
Set<LogicalBreakpoint> col = breakpointService.getBreakpointsAt(location);
|
Set<LogicalBreakpoint> col = breakpointService.getBreakpointsAt(location);
|
||||||
breakpointService.enableAll(col, getTraceFromContext(context)).exceptionally(ex -> {
|
Trace trace = getTraceFromContext(context);
|
||||||
|
String status = breakpointService.generateStatusEnable(col, trace);
|
||||||
|
if (status != null) {
|
||||||
|
tool.setStatusInfo(status, true);
|
||||||
|
}
|
||||||
|
breakpointService.enableAll(col, trace).exceptionally(ex -> {
|
||||||
breakpointError(NAME, "Could not enable breakpoint", ex);
|
breakpointError(NAME, "Could not enable breakpoint", ex);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
@ -869,6 +874,10 @@ public class DebuggerBreakpointMarkerPlugin extends Plugin
|
||||||
if (loc == null) {
|
if (loc == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
String status = breakpointService.generateStatusToggleAt(loc);
|
||||||
|
if (status != null) {
|
||||||
|
tool.setStatusInfo(status, true);
|
||||||
|
}
|
||||||
breakpointService.toggleBreakpointsAt(loc, () -> {
|
breakpointService.toggleBreakpointsAt(loc, () -> {
|
||||||
Set<TraceBreakpointKind> supported = getSupportedKindsFromContext(context);
|
Set<TraceBreakpointKind> supported = getSupportedKindsFromContext(context);
|
||||||
if (supported.isEmpty()) {
|
if (supported.isEmpty()) {
|
||||||
|
|
|
@ -267,7 +267,12 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
|
||||||
DebuggerLogicalBreakpointsActionContext ctx =
|
DebuggerLogicalBreakpointsActionContext ctx =
|
||||||
(DebuggerLogicalBreakpointsActionContext) context;
|
(DebuggerLogicalBreakpointsActionContext) context;
|
||||||
Collection<LogicalBreakpoint> sel = ctx.getBreakpoints();
|
Collection<LogicalBreakpoint> sel = ctx.getBreakpoints();
|
||||||
breakpointService.enableAll(sel, null).exceptionally(ex -> {
|
Trace trace = isFilterByCurrentTrace() ? currentTrace : null;
|
||||||
|
String status = breakpointService.generateStatusEnable(sel, trace);
|
||||||
|
if (status != null) {
|
||||||
|
tool.setStatusInfo(status, true);
|
||||||
|
}
|
||||||
|
breakpointService.enableAll(sel, trace).exceptionally(ex -> {
|
||||||
breakpointError("Enable Breakpoints", "Could not enable breakpoints", ex);
|
breakpointError("Enable Breakpoints", "Could not enable breakpoints", ex);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
@ -309,7 +314,12 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionContext context) {
|
public void actionPerformed(ActionContext context) {
|
||||||
Set<LogicalBreakpoint> all = breakpointService.getAllBreakpoints();
|
Set<LogicalBreakpoint> all = breakpointService.getAllBreakpoints();
|
||||||
breakpointService.enableAll(all, null).exceptionally(ex -> {
|
Trace trace = isFilterByCurrentTrace() ? currentTrace : null;
|
||||||
|
String status = breakpointService.generateStatusEnable(all, trace);
|
||||||
|
if (status != null) {
|
||||||
|
tool.setStatusInfo(status, true);
|
||||||
|
}
|
||||||
|
breakpointService.enableAll(all, trace).exceptionally(ex -> {
|
||||||
breakpointError("Enable All Breakpoints", "Could not enable breakpoints", ex);
|
breakpointError("Enable All Breakpoints", "Could not enable breakpoints", ex);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
@ -996,7 +1006,12 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
|
||||||
new DebuggerBreakpointStateTableCellEditor<>(breakpointFilterPanel) {
|
new DebuggerBreakpointStateTableCellEditor<>(breakpointFilterPanel) {
|
||||||
@Override
|
@Override
|
||||||
protected State getToggledState(LogicalBreakpointRow row, State current) {
|
protected State getToggledState(LogicalBreakpointRow row, State current) {
|
||||||
return current.getToggled(row.isMapped());
|
boolean mapped = row.isMapped();
|
||||||
|
if (!mapped) {
|
||||||
|
tool.setStatusInfo(
|
||||||
|
"Breakpoint has no locations. Only toggling its bookmark.", true);
|
||||||
|
}
|
||||||
|
return current.getToggled(mapped);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
bptEnCol.setMaxWidth(24);
|
bptEnCol.setMaxWidth(24);
|
||||||
|
|
|
@ -60,8 +60,14 @@ public class LogicalBreakpointRow {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setEnabled(boolean enabled) {
|
public void setEnabled(boolean enabled) {
|
||||||
|
boolean filter = provider.isFilterByCurrentTrace();
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
CompletableFuture<Void> future = provider.isFilterByCurrentTrace()
|
String status = lb.generateStatusEnable(filter ? provider.currentTrace : null);
|
||||||
|
if (status != null) {
|
||||||
|
provider.getTool().setStatusInfo(status, true);
|
||||||
|
}
|
||||||
|
lb.enableForProgram();
|
||||||
|
CompletableFuture<Void> future = filter
|
||||||
? lb.enableForTrace(provider.currentTrace)
|
? lb.enableForTrace(provider.currentTrace)
|
||||||
: lb.enable();
|
: lb.enable();
|
||||||
future.exceptionally(ex -> {
|
future.exceptionally(ex -> {
|
||||||
|
@ -70,7 +76,8 @@ public class LogicalBreakpointRow {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
CompletableFuture<Void> future = provider.isFilterByCurrentTrace()
|
lb.disableForProgram();
|
||||||
|
CompletableFuture<Void> future = filter
|
||||||
? lb.disableForTrace(provider.currentTrace)
|
? lb.disableForTrace(provider.currentTrace)
|
||||||
: lb.disable();
|
: lb.disable();
|
||||||
future.exceptionally(ex -> {
|
future.exceptionally(ex -> {
|
||||||
|
@ -139,6 +146,9 @@ public class LogicalBreakpointRow {
|
||||||
*/
|
*/
|
||||||
public boolean isMapped() {
|
public boolean isMapped() {
|
||||||
if (provider.isFilterByCurrentTrace()) {
|
if (provider.isFilterByCurrentTrace()) {
|
||||||
|
if (provider.currentTrace == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return lb.getMappedTraces().contains(provider.currentTrace);
|
return lb.getMappedTraces().contains(provider.currentTrace);
|
||||||
}
|
}
|
||||||
return !lb.getMappedTraces().isEmpty();
|
return !lb.getMappedTraces().isEmpty();
|
||||||
|
|
|
@ -1131,15 +1131,25 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin
|
||||||
if (trace == null || participants.isEmpty() || participants.equals(Set.of(trace))) {
|
if (trace == null || participants.isEmpty() || participants.equals(Set.of(trace))) {
|
||||||
consumerForProgram.accept(lb);
|
consumerForProgram.accept(lb);
|
||||||
}
|
}
|
||||||
if (!(lb instanceof LogicalBreakpointInternal)) {
|
if (!(lb instanceof LogicalBreakpointInternal lbi)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
LogicalBreakpointInternal lbi = (LogicalBreakpointInternal) lb;
|
|
||||||
consumerForTarget.accept(actions, lbi);
|
consumerForTarget.accept(actions, lbi);
|
||||||
}
|
}
|
||||||
return actions.execute();
|
return actions.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String generateStatusEnable(Collection<LogicalBreakpoint> col, Trace trace) {
|
||||||
|
String message;
|
||||||
|
for (LogicalBreakpoint lb : col) {
|
||||||
|
if ((message = lb.generateStatusEnable(trace)) != null) {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Void> enableAll(Collection<LogicalBreakpoint> col, Trace trace) {
|
public CompletableFuture<Void> enableAll(Collection<LogicalBreakpoint> col, Trace trace) {
|
||||||
return actOnAll(col, trace, LogicalBreakpoint::enableForProgram,
|
return actOnAll(col, trace, LogicalBreakpoint::enableForProgram,
|
||||||
|
@ -1205,6 +1215,32 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String generateStatusToggleAt(ProgramLocation loc) {
|
||||||
|
Set<LogicalBreakpoint> bs = getBreakpointsAt(loc);
|
||||||
|
if (bs == null || bs.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
State state = computeState(bs, loc);
|
||||||
|
Trace trace =
|
||||||
|
DebuggerLogicalBreakpointService.programOrTrace(loc, (p, a) -> null, (t, a) -> t);
|
||||||
|
/**
|
||||||
|
* TODO: If we have a trace here, then there are mapped breakpoints, no? We should never
|
||||||
|
* expect a status message in that case. I don't suppose it hurts to check, though, since
|
||||||
|
* the rules could change later.
|
||||||
|
*/
|
||||||
|
boolean mapped = anyMapped(bs, trace);
|
||||||
|
if (!mapped) {
|
||||||
|
return "No breakpoint at this location is mapped to a live trace. " +
|
||||||
|
"Cannot toggle on target. Is there a target? Check your module map.";
|
||||||
|
}
|
||||||
|
State toggled = state.getToggled(mapped);
|
||||||
|
if (!toggled.isEnabled()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return generateStatusEnable(bs, trace);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Set<LogicalBreakpoint>> toggleBreakpointsAt(ProgramLocation loc,
|
public CompletableFuture<Set<LogicalBreakpoint>> toggleBreakpointsAt(ProgramLocation loc,
|
||||||
Supplier<CompletableFuture<Set<LogicalBreakpoint>>> placer) {
|
Supplier<CompletableFuture<Set<LogicalBreakpoint>>> placer) {
|
||||||
|
|
|
@ -211,6 +211,14 @@ public class LoneLogicalBreakpoint implements LogicalBreakpointInternal {
|
||||||
breaks.planEnable(actions, length, kinds);
|
breaks.planEnable(actions, length, kinds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String generateStatusEnable(Trace trace) {
|
||||||
|
if (trace == null || trace == breaks.getTrace()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return "A breakpoint is not in this trace. Is there a target? Check your module map.";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Void> enable() {
|
public CompletableFuture<Void> enable() {
|
||||||
BreakpointActionSet actions = new BreakpointActionSet();
|
BreakpointActionSet actions = new BreakpointActionSet();
|
||||||
|
|
|
@ -192,6 +192,25 @@ public class MappedLogicalBreakpoint implements LogicalBreakpointInternal {
|
||||||
return enableForTraces();
|
return enableForTraces();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String generateStatusEnable(Trace trace) {
|
||||||
|
if (trace == null) {
|
||||||
|
for (TraceBreakpointSet breaks : traceBreaks.values()) {
|
||||||
|
if (!breaks.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "A breakpoint is not mapped to any live trace. Cannot enable it on target. " +
|
||||||
|
"Is there a target? Check your module map.";
|
||||||
|
}
|
||||||
|
TraceBreakpointSet breaks = traceBreaks.get(trace);
|
||||||
|
if (breaks != null && !breaks.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return "A breakpoint is not mapped to the trace, or the trace is not live. " +
|
||||||
|
"Cannot enable it on target. Is there a target? Check your module map.";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Void> enable() {
|
public CompletableFuture<Void> enable() {
|
||||||
enableForProgram();
|
enableForProgram();
|
||||||
|
|
|
@ -292,6 +292,23 @@ public interface DebuggerLogicalBreakpointService {
|
||||||
CompletableFuture<Void> placeBreakpointAt(ProgramLocation loc, long length,
|
CompletableFuture<Void> placeBreakpointAt(ProgramLocation loc, long length,
|
||||||
Collection<TraceBreakpointKind> kinds, String name);
|
Collection<TraceBreakpointKind> kinds, String name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate an informational status message when enabling the selected breakpoints
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Breakpoint enabling may fail for a variety of reasons. Some of those reasons deal with the
|
||||||
|
* trace database and GUI rather than with the target. When enabling will not likely behave in
|
||||||
|
* the manner expected by the user, this should provide a message explaining why. For example,
|
||||||
|
* if a breakpoint has no locations on a target, then we already know "enable" will not work.
|
||||||
|
* This should explain the situation to the user. If enabling is expected to work, then this
|
||||||
|
* should return null.
|
||||||
|
*
|
||||||
|
* @param col the collection we're about to enable
|
||||||
|
* @param trace a trace, if the command will be limited to the given trace
|
||||||
|
* @return the status message, or null
|
||||||
|
*/
|
||||||
|
String generateStatusEnable(Collection<LogicalBreakpoint> col, Trace trace);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable a collection of logical breakpoints on target, if applicable
|
* Enable a collection of logical breakpoints on target, if applicable
|
||||||
*
|
*
|
||||||
|
@ -353,6 +370,21 @@ public interface DebuggerLogicalBreakpointService {
|
||||||
*/
|
*/
|
||||||
CompletableFuture<Void> deleteLocs(Collection<TraceBreakpoint> col);
|
CompletableFuture<Void> deleteLocs(Collection<TraceBreakpoint> col);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate an informational message when toggling the breakpoints at the given location
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This works in the same manner as {@link #generateStatusEnable(Collection)}, except it is for
|
||||||
|
* toggling breakpoints at a given location. If there are no breakpoints at the location, this
|
||||||
|
* should return null, since the usual behavior in that case is to prompt to place a new
|
||||||
|
* breakpoint.
|
||||||
|
*
|
||||||
|
* @see #generateStatusEnable(Collection)
|
||||||
|
* @param loc the location
|
||||||
|
* @return the status message, or null
|
||||||
|
*/
|
||||||
|
String generateStatusToggleAt(ProgramLocation loc);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Toggle the breakpoints at the given location
|
* Toggle the breakpoints at the given location
|
||||||
*
|
*
|
||||||
|
|
|
@ -790,6 +790,18 @@ public interface LogicalBreakpoint {
|
||||||
*/
|
*/
|
||||||
CompletableFuture<Void> deleteForTrace(Trace trace);
|
CompletableFuture<Void> deleteForTrace(Trace trace);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a status message for enabling this breakpoint
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* If this breakpoint has no locations in the given trace, then the status message should
|
||||||
|
* explain that it cannot actually enable the breakpoint.
|
||||||
|
*
|
||||||
|
* @param trace optional to limit scope of message to locations in the given trace
|
||||||
|
* @return the status message, or null
|
||||||
|
*/
|
||||||
|
String generateStatusEnable(Trace trace);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable (or create) this breakpoint everywhere in the tool.
|
* Enable (or create) this breakpoint everywhere in the tool.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue