mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-06-02 05:57:56 +08:00
Merge remote-tracking branch 'origin/debugger'
This commit is contained in:
@@ -54,7 +54,7 @@ jar {
|
|||||||
|
|
||||||
task configureNodepJar {
|
task configureNodepJar {
|
||||||
doLast {
|
doLast {
|
||||||
configurations.runtimeOnly.files.forEach {
|
configurations.default.files.forEach {
|
||||||
if (filterJar(it)) {
|
if (filterJar(it)) {
|
||||||
nodepJar.from(zipTree(it))
|
nodepJar.from(zipTree(it))
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-3
@@ -15,10 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
package agent.dbgeng.manager.cmd;
|
package agent.dbgeng.manager.cmd;
|
||||||
|
|
||||||
|
import agent.dbgeng.dbgeng.DebugControl;
|
||||||
import agent.dbgeng.manager.DbgEvent;
|
import agent.dbgeng.manager.DbgEvent;
|
||||||
import agent.dbgeng.manager.DbgManager;
|
import agent.dbgeng.manager.DbgManager;
|
||||||
import agent.dbgeng.manager.evt.AbstractDbgCompletedCommandEvent;
|
import agent.dbgeng.manager.evt.*;
|
||||||
import agent.dbgeng.manager.evt.DbgConsoleOutputEvent;
|
|
||||||
import agent.dbgeng.manager.impl.DbgManagerImpl;
|
import agent.dbgeng.manager.impl.DbgManagerImpl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -63,6 +63,8 @@ public class DbgConsoleExecCommand extends AbstractDbgCommand<String> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void invoke() {
|
public void invoke() {
|
||||||
manager.getControl().execute(command);
|
DebugControl control = manager.getControl();
|
||||||
|
control.execute(command);
|
||||||
|
manager.processEvent(new DbgPromptChangedEvent(control.getPromptText()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package agent.dbgeng.manager.evt;
|
||||||
|
|
||||||
|
public class DbgPromptChangedEvent extends AbstractDbgEvent<String> {
|
||||||
|
public DbgPromptChangedEvent(String prompt) {
|
||||||
|
super(prompt);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPrompt() {
|
||||||
|
return getInfo();
|
||||||
|
}
|
||||||
|
}
|
||||||
+12
-3
@@ -41,7 +41,8 @@ import agent.dbgeng.manager.breakpoint.DbgBreakpointInfo;
|
|||||||
import agent.dbgeng.manager.breakpoint.DbgBreakpointType;
|
import agent.dbgeng.manager.breakpoint.DbgBreakpointType;
|
||||||
import agent.dbgeng.manager.cmd.*;
|
import agent.dbgeng.manager.cmd.*;
|
||||||
import agent.dbgeng.manager.evt.*;
|
import agent.dbgeng.manager.evt.*;
|
||||||
import agent.dbgeng.model.iface1.*;
|
import agent.dbgeng.model.iface1.DbgModelTargetActiveScope;
|
||||||
|
import agent.dbgeng.model.iface1.DbgModelTargetFocusScope;
|
||||||
import agent.dbgeng.model.iface2.DbgModelTargetObject;
|
import agent.dbgeng.model.iface2.DbgModelTargetObject;
|
||||||
import agent.dbgeng.model.iface2.DbgModelTargetThread;
|
import agent.dbgeng.model.iface2.DbgModelTargetThread;
|
||||||
import ghidra.async.*;
|
import ghidra.async.*;
|
||||||
@@ -597,6 +598,7 @@ public class DbgManagerImpl implements DbgManager {
|
|||||||
handlerMap.putVoid(DbgStoppedEvent.class, this::processDefault);
|
handlerMap.putVoid(DbgStoppedEvent.class, this::processDefault);
|
||||||
handlerMap.putVoid(DbgRunningEvent.class, this::processDefault);
|
handlerMap.putVoid(DbgRunningEvent.class, this::processDefault);
|
||||||
handlerMap.putVoid(DbgConsoleOutputEvent.class, this::processConsoleOutput);
|
handlerMap.putVoid(DbgConsoleOutputEvent.class, this::processConsoleOutput);
|
||||||
|
handlerMap.putVoid(DbgPromptChangedEvent.class, this::processPromptChanged);
|
||||||
handlerMap.putVoid(DbgBreakpointCreatedEvent.class, this::processBreakpointCreated);
|
handlerMap.putVoid(DbgBreakpointCreatedEvent.class, this::processBreakpointCreated);
|
||||||
handlerMap.putVoid(DbgBreakpointModifiedEvent.class, this::processBreakpointModified);
|
handlerMap.putVoid(DbgBreakpointModifiedEvent.class, this::processBreakpointModified);
|
||||||
handlerMap.putVoid(DbgBreakpointDeletedEvent.class, this::processBreakpointDeleted);
|
handlerMap.putVoid(DbgBreakpointDeletedEvent.class, this::processBreakpointDeleted);
|
||||||
@@ -925,6 +927,7 @@ public class DbgManagerImpl implements DbgManager {
|
|||||||
dbgState = DbgState.STOPPED;
|
dbgState = DbgState.STOPPED;
|
||||||
//System.err.println("STOPPED " + id);
|
//System.err.println("STOPPED " + id);
|
||||||
processEvent(new DbgStoppedEvent(eventThread.getId()));
|
processEvent(new DbgStoppedEvent(eventThread.getId()));
|
||||||
|
processEvent(new DbgPromptChangedEvent(getControl().getPromptText()));
|
||||||
}
|
}
|
||||||
if (status.threadState.equals(ExecutionState.RUNNING)) {
|
if (status.threadState.equals(ExecutionState.RUNNING)) {
|
||||||
//System.err.println("RUNNING " + id);
|
//System.err.println("RUNNING " + id);
|
||||||
@@ -949,6 +952,7 @@ public class DbgManagerImpl implements DbgManager {
|
|||||||
if (process != null) {
|
if (process != null) {
|
||||||
processEvent(new DbgProcessSelectedEvent(process));
|
processEvent(new DbgProcessSelectedEvent(process));
|
||||||
}
|
}
|
||||||
|
processEvent(new DbgPromptChangedEvent(getControl().getPromptText()));
|
||||||
return DebugStatus.BREAK;
|
return DebugStatus.BREAK;
|
||||||
}
|
}
|
||||||
if (status.equals(DebugStatus.GO)) {
|
if (status.equals(DebugStatus.GO)) {
|
||||||
@@ -972,6 +976,7 @@ public class DbgManagerImpl implements DbgManager {
|
|||||||
if (thread != null) {
|
if (thread != null) {
|
||||||
getEventListeners().fire.threadSelected(thread, null, evt.getCause());
|
getEventListeners().fire.threadSelected(thread, null, evt.getCause());
|
||||||
}
|
}
|
||||||
|
processEvent(new DbgPromptChangedEvent(getControl().getPromptText()));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1033,6 +1038,10 @@ public class DbgManagerImpl implements DbgManager {
|
|||||||
getEventListeners().fire.consoleOutput(evt.getInfo(), evt.getMask());
|
getEventListeners().fire.consoleOutput(evt.getInfo(), evt.getMask());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void processPromptChanged(DbgPromptChangedEvent evt, Void v) {
|
||||||
|
getEventListeners().fire.promptChanged(evt.getPrompt());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler for breakpoint-created event
|
* Handler for breakpoint-created event
|
||||||
*
|
*
|
||||||
@@ -1480,8 +1489,8 @@ public class DbgManagerImpl implements DbgManager {
|
|||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Void> console(String command) {
|
public CompletableFuture<Void> console(String command) {
|
||||||
if (continuation != null) {
|
if (continuation != null) {
|
||||||
String prompt = command.equals("") ? DbgModelTargetInterpreter.DBG_PROMPT : ">>>";
|
//String prompt = command.equals("") ? DbgModelTargetInterpreter.DBG_PROMPT : ">>>";
|
||||||
getEventListeners().fire.promptChanged(prompt);
|
//getEventListeners().fire.promptChanged(prompt);
|
||||||
continuation.complete(command);
|
continuation.complete(command);
|
||||||
setContinuation(null);
|
setContinuation(null);
|
||||||
return AsyncUtils.NIL;
|
return AsyncUtils.NIL;
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ jar {
|
|||||||
|
|
||||||
task configureNodepJar {
|
task configureNodepJar {
|
||||||
doLast {
|
doLast {
|
||||||
configurations.runtimeOnly.files.forEach {
|
configurations.default.files.forEach {
|
||||||
if (filterJar(it)) {
|
if (filterJar(it)) {
|
||||||
nodepJar.from(zipTree(it))
|
nodepJar.from(zipTree(it))
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-7
@@ -18,6 +18,7 @@ package agent.dbgmodel.dbgmodel;
|
|||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@@ -44,7 +45,7 @@ public class DbgModelSetContextMWETest extends AbstractGhidraHeadlessIntegration
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMWE() {
|
public void testMWE() throws IOException {
|
||||||
HostDataModelAccess access = DbgModel.debugCreate();
|
HostDataModelAccess access = DbgModel.debugCreate();
|
||||||
DebugClient client = access.getClient();
|
DebugClient client = access.getClient();
|
||||||
DebugControl control = client.getControl();
|
DebugControl control = client.getControl();
|
||||||
@@ -272,12 +273,6 @@ public class DbgModelSetContextMWETest extends AbstractGhidraHeadlessIntegration
|
|||||||
DebugStatus status = super.exitThread(exitCode);
|
DebugStatus status = super.exitThread(exitCode);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public DebugStatus changeSymbolState(BitmaskSet<ChangeSymbolState> flags,
|
|
||||||
long argument) {
|
|
||||||
return defaultStatus;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
try (ProcMaker maker = new ProcMaker(client, "C:\\Software\\Winmine__XP.exe")) {
|
try (ProcMaker maker = new ProcMaker(client, "C:\\Software\\Winmine__XP.exe")) {
|
||||||
@@ -317,6 +312,17 @@ public class DbgModelSetContextMWETest extends AbstractGhidraHeadlessIntegration
|
|||||||
}
|
}
|
||||||
cb.dumpFrame0ViaDX();
|
cb.dumpFrame0ViaDX();
|
||||||
|
|
||||||
|
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
|
||||||
|
while (true) {
|
||||||
|
System.err.print(control.getPromptText());
|
||||||
|
//control.prompt(BitmaskSet.of(), "Hello?>");
|
||||||
|
String cmd = in.readLine();
|
||||||
|
control.execute(cmd);
|
||||||
|
if (control.getExecutionStatus().shouldWait) {
|
||||||
|
control.waitForEvent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: Didn't finish because the SetContext failed issue turned out to be mixed and/or
|
* TODO: Didn't finish because the SetContext failed issue turned out to be mixed and/or
|
||||||
* broken DLLs.
|
* broken DLLs.
|
||||||
|
|||||||
+5
@@ -1124,4 +1124,9 @@ public class DbgModelTest extends AbstractGhidraHeadlessIntegrationTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPrompt() throws Exception {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ jar {
|
|||||||
|
|
||||||
task configureNodepJar {
|
task configureNodepJar {
|
||||||
doLast {
|
doLast {
|
||||||
configurations.runtimeOnly.files.forEach {
|
configurations.default.files.forEach {
|
||||||
if (filterJar(it)) {
|
if (filterJar(it)) {
|
||||||
nodepJar.from(zipTree(it))
|
nodepJar.from(zipTree(it))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -132,6 +132,7 @@ src/main/resources/images/breakpoint-set.png||GHIDRA||||END|
|
|||||||
src/main/resources/images/breakpoints-clear-all.png||GHIDRA||||END|
|
src/main/resources/images/breakpoints-clear-all.png||GHIDRA||||END|
|
||||||
src/main/resources/images/breakpoints-disable-all.png||GHIDRA||||END|
|
src/main/resources/images/breakpoints-disable-all.png||GHIDRA||||END|
|
||||||
src/main/resources/images/breakpoints-enable-all.png||GHIDRA||||END|
|
src/main/resources/images/breakpoints-enable-all.png||GHIDRA||||END|
|
||||||
|
src/main/resources/images/breakpoints-make-effective.png||GHIDRA||||END|
|
||||||
src/main/resources/images/breakpoints.png||GHIDRA||||END|
|
src/main/resources/images/breakpoints.png||GHIDRA||||END|
|
||||||
src/main/resources/images/closedFolder.png||Modified Nuvola Icons - LGPL 2.1||||END|
|
src/main/resources/images/closedFolder.png||Modified Nuvola Icons - LGPL 2.1||||END|
|
||||||
src/main/resources/images/connect.png||GHIDRA||||END|
|
src/main/resources/images/connect.png||GHIDRA||||END|
|
||||||
@@ -179,6 +180,7 @@ src/main/svg/breakpoint-set.svg||GHIDRA||||END|
|
|||||||
src/main/svg/breakpoints-clear-all.svg||GHIDRA||||END|
|
src/main/svg/breakpoints-clear-all.svg||GHIDRA||||END|
|
||||||
src/main/svg/breakpoints-disable-all.svg||GHIDRA||||END|
|
src/main/svg/breakpoints-disable-all.svg||GHIDRA||||END|
|
||||||
src/main/svg/breakpoints-enable-all.svg||GHIDRA||||END|
|
src/main/svg/breakpoints-enable-all.svg||GHIDRA||||END|
|
||||||
|
src/main/svg/breakpoints-make-effective.svg||GHIDRA||||END|
|
||||||
src/main/svg/breakpoints.svg||GHIDRA||||END|
|
src/main/svg/breakpoints.svg||GHIDRA||||END|
|
||||||
src/main/svg/connect.svg||GHIDRA||||END|
|
src/main/svg/connect.svg||GHIDRA||||END|
|
||||||
src/main/svg/console.svg||GHIDRA||||END|
|
src/main/svg/console.svg||GHIDRA||||END|
|
||||||
|
|||||||
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
+31
-1
@@ -99,6 +99,8 @@ public interface DebuggerResources {
|
|||||||
ResourceManager.loadImage("images/breakpoints-disable-all.png");
|
ResourceManager.loadImage("images/breakpoints-disable-all.png");
|
||||||
ImageIcon ICON_CLEAR_ALL_BREAKPOINTS =
|
ImageIcon ICON_CLEAR_ALL_BREAKPOINTS =
|
||||||
ResourceManager.loadImage("images/breakpoints-clear-all.png");
|
ResourceManager.loadImage("images/breakpoints-clear-all.png");
|
||||||
|
ImageIcon ICON_MAKE_BREAKPOINTS_EFFECTIVE =
|
||||||
|
ResourceManager.loadImage("images/breakpoints-make-effective.png");
|
||||||
|
|
||||||
// TODO: Some overlay to indicate dynamic, or new icon altogether
|
// TODO: Some overlay to indicate dynamic, or new icon altogether
|
||||||
ImageIcon ICON_LISTING = ResourceManager.loadImage("images/Browser.gif");
|
ImageIcon ICON_LISTING = ResourceManager.loadImage("images/Browser.gif");
|
||||||
@@ -986,13 +988,29 @@ public interface DebuggerResources {
|
|||||||
|
|
||||||
static ActionBuilder builder(Plugin owner) {
|
static ActionBuilder builder(Plugin owner) {
|
||||||
String ownerName = owner.getName();
|
String ownerName = owner.getName();
|
||||||
return new ActionBuilder(NAME, ownerName).description(DESCRIPTION)
|
return new ActionBuilder(NAME, ownerName)
|
||||||
|
.description(DESCRIPTION)
|
||||||
.menuGroup(GROUP)
|
.menuGroup(GROUP)
|
||||||
.menuPath(NAME)
|
.menuPath(NAME)
|
||||||
.helpLocation(new HelpLocation(ownerName, HELP_ANCHOR));
|
.helpLocation(new HelpLocation(ownerName, HELP_ANCHOR));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface OpenProgramAction {
|
||||||
|
String NAME = "Open Program";
|
||||||
|
Icon ICON = ICON_PROGRAM;
|
||||||
|
String DESCRIPTION = "Open the program";
|
||||||
|
String HELP_ANCHOR = "open_program";
|
||||||
|
|
||||||
|
static ActionBuilder builder(Plugin owner) {
|
||||||
|
String ownerName = owner.getName();
|
||||||
|
return new ActionBuilder(NAME, ownerName)
|
||||||
|
.description(DESCRIPTION)
|
||||||
|
.toolBarIcon(ICON)
|
||||||
|
.helpLocation(new HelpLocation(ownerName, HELP_ANCHOR));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
abstract class AbstractToggleBreakpointAction extends DockingAction {
|
abstract class AbstractToggleBreakpointAction extends DockingAction {
|
||||||
public static final String NAME = "Toggle Breakpoint";
|
public static final String NAME = "Toggle Breakpoint";
|
||||||
// TODO: A "toggle breakpoint" icon
|
// TODO: A "toggle breakpoint" icon
|
||||||
@@ -1142,6 +1160,18 @@ public interface DebuggerResources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract class AbstractMakeBreakpointsEffectiveAction extends DockingAction {
|
||||||
|
public static final String NAME = "Make Breakpoints Effective";
|
||||||
|
public static final Icon ICON = ICON_MAKE_BREAKPOINTS_EFFECTIVE;
|
||||||
|
public static final String HELP_ANCHOR = "make_breakpoints_effective";
|
||||||
|
|
||||||
|
public AbstractMakeBreakpointsEffectiveAction(Plugin owner) {
|
||||||
|
super(NAME, owner.getName());
|
||||||
|
setDescription("Place enabled but ineffective breakpoints where possible");
|
||||||
|
setHelpLocation(new HelpLocation(owner.getName(), HELP_ANCHOR));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
interface MapModulesAction {
|
interface MapModulesAction {
|
||||||
String NAME = "Map Modules";
|
String NAME = "Map Modules";
|
||||||
String DESCRIPTION = "Map selected modules to program images";
|
String DESCRIPTION = "Map selected modules to program images";
|
||||||
|
|||||||
+3
-3
@@ -22,7 +22,6 @@ import ghidra.dbg.target.TargetBreakpointLocation;
|
|||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.trace.model.breakpoint.TraceBreakpoint;
|
import ghidra.trace.model.breakpoint.TraceBreakpoint;
|
||||||
import ghidra.trace.model.thread.TraceThread;
|
import ghidra.trace.model.thread.TraceThread;
|
||||||
import ghidra.util.Msg;
|
|
||||||
import ghidra.util.database.UndoableTransaction;
|
import ghidra.util.database.UndoableTransaction;
|
||||||
|
|
||||||
public class BreakpointLocationRow {
|
public class BreakpointLocationRow {
|
||||||
@@ -43,17 +42,18 @@ public class BreakpointLocationRow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setEnabled(boolean enabled) {
|
public void setEnabled(boolean enabled) {
|
||||||
|
// TODO: Make this toggle the individual location, if possible, not the whole spec.
|
||||||
TraceRecorder recorder = provider.modelService.getRecorder(loc.getTrace());
|
TraceRecorder recorder = provider.modelService.getRecorder(loc.getTrace());
|
||||||
TargetBreakpointLocation bpt = recorder.getTargetBreakpoint(loc);
|
TargetBreakpointLocation bpt = recorder.getTargetBreakpoint(loc);
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
bpt.getSpecification().enable().exceptionally(ex -> {
|
bpt.getSpecification().enable().exceptionally(ex -> {
|
||||||
Msg.showError(this, null, "Toggle breakpoint", "Could not enable breakpoint", ex);
|
provider.breakpointError("Toggle breakpoint", "Could not enable breakpoint", ex);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
bpt.getSpecification().disable().exceptionally(ex -> {
|
bpt.getSpecification().disable().exceptionally(ex -> {
|
||||||
Msg.showError(this, null, "Toggle breakpoint", "Could not disable breakpoint", ex);
|
provider.breakpointError("Toggle breakpoint", "Could not disable breakpoint", ex);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
+25
-6
@@ -532,7 +532,7 @@ public class DebuggerBreakpointMarkerPlugin extends Plugin
|
|||||||
if (bs == null || bs.isEmpty()) {
|
if (bs == null || bs.isEmpty()) {
|
||||||
Set<TraceBreakpointKind> supported = getSupportedKindsFromContext(context);
|
Set<TraceBreakpointKind> supported = getSupportedKindsFromContext(context);
|
||||||
if (supported.isEmpty()) {
|
if (supported.isEmpty()) {
|
||||||
Msg.showError(this, null, NAME,
|
breakpointError(NAME,
|
||||||
"It seems this target does not support breakpoints.");
|
"It seems this target does not support breakpoints.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -545,13 +545,13 @@ public class DebuggerBreakpointMarkerPlugin extends Plugin
|
|||||||
Trace trace = getTraceFromContext(context); // OK if null - means all traces
|
Trace trace = getTraceFromContext(context); // OK if null - means all traces
|
||||||
if (en.enabled) {
|
if (en.enabled) {
|
||||||
breakpointService.disableAll(bs, trace).exceptionally(ex -> {
|
breakpointService.disableAll(bs, trace).exceptionally(ex -> {
|
||||||
Msg.showError(this, null, NAME, "Could not disable breakpoints", ex);
|
breakpointError(NAME, "Could not disable breakpoints", ex);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
breakpointService.enableAll(bs, trace).exceptionally(ex -> {
|
breakpointService.enableAll(bs, trace).exceptionally(ex -> {
|
||||||
Msg.showError(this, null, NAME, "Could not enable breakpoints", ex);
|
breakpointError(NAME, "Could not enable breakpoints", ex);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -628,7 +628,7 @@ 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 -> {
|
breakpointService.enableAll(col, getTraceFromContext(context)).exceptionally(ex -> {
|
||||||
Msg.showError(this, null, NAME, "Could not enable breakpoint", ex);
|
breakpointError(NAME, "Could not enable breakpoint", ex);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -665,7 +665,7 @@ 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.disableAll(col, getTraceFromContext(context)).exceptionally(ex -> {
|
breakpointService.disableAll(col, getTraceFromContext(context)).exceptionally(ex -> {
|
||||||
Msg.showError(this, null, NAME, "Could not disable breakpoint", ex);
|
breakpointError(NAME, "Could not disable breakpoint", ex);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -704,7 +704,7 @@ 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.deleteAll(col, getTraceFromContext(context)).exceptionally(ex -> {
|
breakpointService.deleteAll(col, getTraceFromContext(context)).exceptionally(ex -> {
|
||||||
Msg.showError(this, null, NAME, "Could not delete breakpoint", ex);
|
breakpointError(NAME, "Could not delete breakpoint", ex);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -733,6 +733,8 @@ public class DebuggerBreakpointMarkerPlugin extends Plugin
|
|||||||
private DebuggerStaticMappingService mappingService;
|
private DebuggerStaticMappingService mappingService;
|
||||||
@AutoServiceConsumed
|
@AutoServiceConsumed
|
||||||
private DebuggerTraceManagerService traceManager;
|
private DebuggerTraceManagerService traceManager;
|
||||||
|
@AutoServiceConsumed
|
||||||
|
private DebuggerConsoleService consoleService;
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private final AutoService.Wiring autoServiceWiring;
|
private final AutoService.Wiring autoServiceWiring;
|
||||||
|
|
||||||
@@ -1084,4 +1086,21 @@ public class DebuggerBreakpointMarkerPlugin extends Plugin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void breakpointError(String title, String message) {
|
||||||
|
if (consoleService == null) {
|
||||||
|
Msg.showError(this, null, title, message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
consoleService.log(DebuggerResources.ICON_LOG_ERROR, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void breakpointError(String title, String message, Throwable ex) {
|
||||||
|
if (consoleService == null) {
|
||||||
|
Msg.showError(this, null, title, message, ex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Msg.error(this, message, ex);
|
||||||
|
consoleService.log(DebuggerResources.ICON_LOG_ERROR, message + " (" + ex + ")");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-1
@@ -33,7 +33,8 @@ import ghidra.framework.plugintool.util.PluginStatus;
|
|||||||
servicesRequired = { //
|
servicesRequired = { //
|
||||||
DebuggerLogicalBreakpointService.class, //
|
DebuggerLogicalBreakpointService.class, //
|
||||||
DebuggerModelService.class, //
|
DebuggerModelService.class, //
|
||||||
}, eventsConsumed = {
|
},
|
||||||
|
eventsConsumed = {
|
||||||
TraceOpenedPluginEvent.class, //
|
TraceOpenedPluginEvent.class, //
|
||||||
TraceClosedPluginEvent.class, //
|
TraceClosedPluginEvent.class, //
|
||||||
TraceActivatedPluginEvent.class, //
|
TraceActivatedPluginEvent.class, //
|
||||||
@@ -54,6 +55,7 @@ public class DebuggerBreakpointsPlugin extends AbstractDebuggerPlugin {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void dispose() {
|
protected void dispose() {
|
||||||
|
provider.dispose();
|
||||||
tool.removeComponentProvider(provider);
|
tool.removeComponentProvider(provider);
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|||||||
+136
-27
@@ -254,8 +254,7 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
|
|||||||
(DebuggerLogicalBreakpointsActionContext) context;
|
(DebuggerLogicalBreakpointsActionContext) context;
|
||||||
Collection<LogicalBreakpoint> sel = ctx.getSelection();
|
Collection<LogicalBreakpoint> sel = ctx.getSelection();
|
||||||
breakpointService.enableAll(sel, null).exceptionally(ex -> {
|
breakpointService.enableAll(sel, null).exceptionally(ex -> {
|
||||||
Msg.showError(this, getComponent(), "Enable Breakpoints",
|
breakpointError("Enable Breakpoints", "Could not enable breakpoints", ex);
|
||||||
"Could not enable breakpoints", ex);
|
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -286,8 +285,7 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
|
|||||||
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 -> {
|
breakpointService.enableAll(all, null).exceptionally(ex -> {
|
||||||
Msg.showError(this, getComponent(), "Enable All Breakpoints",
|
breakpointError("Enable All Breakpoints", "Could not enable breakpoints", ex);
|
||||||
"Could not enable breakpoints", ex);
|
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -320,8 +318,7 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
|
|||||||
(DebuggerLogicalBreakpointsActionContext) context;
|
(DebuggerLogicalBreakpointsActionContext) context;
|
||||||
Collection<LogicalBreakpoint> sel = ctx.getSelection();
|
Collection<LogicalBreakpoint> sel = ctx.getSelection();
|
||||||
breakpointService.disableAll(sel, null).exceptionally(ex -> {
|
breakpointService.disableAll(sel, null).exceptionally(ex -> {
|
||||||
Msg.showError(this, getComponent(), "Disable Breakpoints",
|
breakpointError("Disable Breakpoints", "Could not disable breakpoints", ex);
|
||||||
"Could not disable breakpoints", ex);
|
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -352,8 +349,7 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
|
|||||||
public void actionPerformed(ActionContext context) {
|
public void actionPerformed(ActionContext context) {
|
||||||
Set<LogicalBreakpoint> all = breakpointService.getAllBreakpoints();
|
Set<LogicalBreakpoint> all = breakpointService.getAllBreakpoints();
|
||||||
breakpointService.disableAll(all, null).exceptionally(ex -> {
|
breakpointService.disableAll(all, null).exceptionally(ex -> {
|
||||||
Msg.showError(this, getComponent(), "Disable All Breakpoints",
|
breakpointError("Disable All Breakpoints", "Could not disable breakpoints", ex);
|
||||||
"Could not disable breakpoints", ex);
|
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -365,7 +361,7 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected class ClearSelectedBreakpointsAction extends AbstractClearSelectedBreakpointsAction {
|
protected class ClearSelectedBreakpointsAction extends AbstractClearSelectedBreakpointsAction {
|
||||||
public static final String GROUP = DebuggerResources.GROUP_BREAKPOINTS;
|
public static final String GROUP = DebuggerResources.GROUP_BREAKPOINTS + "Clear";
|
||||||
|
|
||||||
public ClearSelectedBreakpointsAction() {
|
public ClearSelectedBreakpointsAction() {
|
||||||
super(plugin);
|
super(plugin);
|
||||||
@@ -382,8 +378,7 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
|
|||||||
(DebuggerLogicalBreakpointsActionContext) context;
|
(DebuggerLogicalBreakpointsActionContext) context;
|
||||||
Collection<LogicalBreakpoint> sel = ctx.getSelection();
|
Collection<LogicalBreakpoint> sel = ctx.getSelection();
|
||||||
breakpointService.deleteAll(sel, null).exceptionally(ex -> {
|
breakpointService.deleteAll(sel, null).exceptionally(ex -> {
|
||||||
Msg.showError(this, getComponent(), "Clear Breakpoints",
|
breakpointError("Clear Breakpoints", "Could not clear breakpoints", ex);
|
||||||
"Could not clear breakpoints", ex);
|
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -401,7 +396,7 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected class ClearAllBreakpointsAction extends AbstractClearAllBreakpointsAction {
|
protected class ClearAllBreakpointsAction extends AbstractClearAllBreakpointsAction {
|
||||||
public static final String GROUP = DebuggerResources.GROUP_BREAKPOINTS;
|
public static final String GROUP = DebuggerResources.GROUP_BREAKPOINTS + "Clear";
|
||||||
|
|
||||||
public ClearAllBreakpointsAction() {
|
public ClearAllBreakpointsAction() {
|
||||||
super(plugin);
|
super(plugin);
|
||||||
@@ -414,8 +409,7 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
|
|||||||
public void actionPerformed(ActionContext context) {
|
public void actionPerformed(ActionContext context) {
|
||||||
Set<LogicalBreakpoint> all = breakpointService.getAllBreakpoints();
|
Set<LogicalBreakpoint> all = breakpointService.getAllBreakpoints();
|
||||||
breakpointService.deleteAll(all, null).exceptionally(ex -> {
|
breakpointService.deleteAll(all, null).exceptionally(ex -> {
|
||||||
Msg.showError(this, getComponent(), "Clear All Breakpoints",
|
breakpointError("Clear All Breakpoints", "Could not clear breakpoints", ex);
|
||||||
"Could not clear breakpoints", ex);
|
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -426,6 +420,64 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected abstract class CommonMakeBreakpointsEffectiveAction
|
||||||
|
extends AbstractMakeBreakpointsEffectiveAction {
|
||||||
|
public static final String GROUP = DebuggerResources.GROUP_BREAKPOINTS;
|
||||||
|
|
||||||
|
public CommonMakeBreakpointsEffectiveAction() {
|
||||||
|
super(plugin);
|
||||||
|
setToolBarData(new ToolBarData(ICON, GROUP));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionContext context) {
|
||||||
|
Set<LogicalBreakpoint> all = breakpointService.getAllBreakpoints();
|
||||||
|
for (LogicalBreakpoint lb : all) {
|
||||||
|
if (lb.computeEnablement() != Enablement.INEFFECTIVE_ENABLED) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (lb.getMappedTraces().isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
lb.enable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected class MakeBreakpointsEffectiveAction extends CommonMakeBreakpointsEffectiveAction {
|
||||||
|
public MakeBreakpointsEffectiveAction() {
|
||||||
|
super();
|
||||||
|
addLocalAction(this);
|
||||||
|
setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabledForContext(ActionContext context) {
|
||||||
|
if (breakpointService == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Set<LogicalBreakpoint> all = breakpointService.getAllBreakpoints();
|
||||||
|
for (LogicalBreakpoint lb : all) {
|
||||||
|
if (lb.computeEnablement() != Enablement.INEFFECTIVE_ENABLED) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (lb.getMappedTraces().isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected class MakeBreakpointsEffectiveResolutionAction
|
||||||
|
extends CommonMakeBreakpointsEffectiveAction {
|
||||||
|
@Override
|
||||||
|
public boolean isValidContext(ActionContext context) {
|
||||||
|
return context instanceof DebuggerMakeBreakpointsEffectiveActionContext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class LocationsBySelectedBreakpointsTableFilter implements TableFilter<BreakpointLocationRow> {
|
class LocationsBySelectedBreakpointsTableFilter implements TableFilter<BreakpointLocationRow> {
|
||||||
@Override
|
@Override
|
||||||
public boolean acceptsRow(BreakpointLocationRow locationRow) {
|
public boolean acceptsRow(BreakpointLocationRow locationRow) {
|
||||||
@@ -540,13 +592,15 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
|
|||||||
|
|
||||||
// @AutoServiceConsumed via method
|
// @AutoServiceConsumed via method
|
||||||
private DebuggerLogicalBreakpointService breakpointService;
|
private DebuggerLogicalBreakpointService breakpointService;
|
||||||
// @AutoServiceConsumed via method
|
// @AutoServiceConsumed via method, package access for BreakpointLogicalRow
|
||||||
DebuggerModelService modelService;
|
DebuggerModelService modelService;
|
||||||
@AutoServiceConsumed
|
@AutoServiceConsumed
|
||||||
private DebuggerListingService listingService;
|
private DebuggerListingService listingService;
|
||||||
@AutoServiceConsumed
|
@AutoServiceConsumed
|
||||||
private DebuggerTraceManagerService traceManager;
|
private DebuggerTraceManagerService traceManager;
|
||||||
@AutoServiceConsumed
|
@AutoServiceConsumed
|
||||||
|
private DebuggerConsoleService consoleService;
|
||||||
|
@AutoServiceConsumed
|
||||||
private GoToService goToService;
|
private GoToService goToService;
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private AutoService.Wiring autoServiceWiring;
|
private AutoService.Wiring autoServiceWiring;
|
||||||
@@ -571,13 +625,18 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
|
|||||||
|
|
||||||
private ActionContext myActionContext;
|
private ActionContext myActionContext;
|
||||||
|
|
||||||
|
private final DebuggerMakeBreakpointsEffectiveActionContext makeEffectiveResolutionContext =
|
||||||
|
new DebuggerMakeBreakpointsEffectiveActionContext();
|
||||||
|
|
||||||
// package access for testing
|
// package access for testing
|
||||||
EnableSelectedBreakpointsAction actionEnableSelectedBreakpointsAction;
|
EnableSelectedBreakpointsAction actionEnableSelectedBreakpoints;
|
||||||
EnableAllBreakpointsAction actionEnableAllBreakpointsAction;
|
EnableAllBreakpointsAction actionEnableAllBreakpoints;
|
||||||
DisableSelectedBreakpointsAction actionDisableSelectedBreakpointsAction;
|
DisableSelectedBreakpointsAction actionDisableSelectedBreakpoints;
|
||||||
DisableAllBreakpointsAction actionDisableAllBreakpointsAction;
|
DisableAllBreakpointsAction actionDisableAllBreakpoints;
|
||||||
ClearSelectedBreakpointsAction actionClearSelectedBreakpointsAction;
|
ClearSelectedBreakpointsAction actionClearSelectedBreakpoints;
|
||||||
ClearAllBreakpointsAction actionClearAllBreakpointsAction;
|
ClearAllBreakpointsAction actionClearAllBreakpoints;
|
||||||
|
MakeBreakpointsEffectiveAction actionMakeBreakpointsEffective;
|
||||||
|
MakeBreakpointsEffectiveResolutionAction actionMakeBreakpointsEffectiveResolution;
|
||||||
ToggleDockingAction actionFilterByCurrentTrace;
|
ToggleDockingAction actionFilterByCurrentTrace;
|
||||||
ToggleDockingAction actionFilterLocationsByBreakpoints;
|
ToggleDockingAction actionFilterLocationsByBreakpoints;
|
||||||
|
|
||||||
@@ -598,6 +657,35 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
|
|||||||
createActions();
|
createActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void dispose() {
|
||||||
|
if (consoleService != null) {
|
||||||
|
if (actionMakeBreakpointsEffectiveResolution != null) {
|
||||||
|
consoleService.removeResolutionAction(actionMakeBreakpointsEffectiveResolution);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void contextChanged() {
|
||||||
|
super.contextChanged();
|
||||||
|
if (consoleService == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// TODO: This should probably check for its existence first
|
||||||
|
// Kind of a hack, but it works.
|
||||||
|
if (actionMakeBreakpointsEffective != null &&
|
||||||
|
actionMakeBreakpointsEffective.isEnabledForContext(myActionContext)) {
|
||||||
|
if (!consoleService.logContains(makeEffectiveResolutionContext)) {
|
||||||
|
consoleService.log(DebuggerResources.ICON_PROVIDER_BREAKPOINTS,
|
||||||
|
"There are ineffective breakpoints that can be placed",
|
||||||
|
makeEffectiveResolutionContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
consoleService.removeFromLog(makeEffectiveResolutionContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@AutoServiceConsumed
|
@AutoServiceConsumed
|
||||||
private void setBreakpointService(DebuggerLogicalBreakpointService breakpointService) {
|
private void setBreakpointService(DebuggerLogicalBreakpointService breakpointService) {
|
||||||
if (this.breakpointService != null) {
|
if (this.breakpointService != null) {
|
||||||
@@ -623,6 +711,15 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@AutoServiceConsumed
|
||||||
|
private void setConsoleService(DebuggerConsoleService consoleService) {
|
||||||
|
if (consoleService != null) {
|
||||||
|
if (actionMakeBreakpointsEffectiveResolution != null) {
|
||||||
|
consoleService.addResolutionAction(actionMakeBreakpointsEffectiveResolution);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected void loadBreakpoints() {
|
protected void loadBreakpoints() {
|
||||||
Set<LogicalBreakpoint> all = breakpointService.getAllBreakpoints();
|
Set<LogicalBreakpoint> all = breakpointService.getAllBreakpoints();
|
||||||
breakpointTableModel.addAllItems(all);
|
breakpointTableModel.addAllItems(all);
|
||||||
@@ -921,12 +1018,13 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void createActions() {
|
protected void createActions() {
|
||||||
actionEnableSelectedBreakpointsAction = new EnableSelectedBreakpointsAction();
|
actionEnableSelectedBreakpoints = new EnableSelectedBreakpointsAction();
|
||||||
actionEnableAllBreakpointsAction = new EnableAllBreakpointsAction();
|
actionEnableAllBreakpoints = new EnableAllBreakpointsAction();
|
||||||
actionDisableSelectedBreakpointsAction = new DisableSelectedBreakpointsAction();
|
actionDisableSelectedBreakpoints = new DisableSelectedBreakpointsAction();
|
||||||
actionDisableAllBreakpointsAction = new DisableAllBreakpointsAction();
|
actionDisableAllBreakpoints = new DisableAllBreakpointsAction();
|
||||||
actionClearSelectedBreakpointsAction = new ClearSelectedBreakpointsAction();
|
actionClearSelectedBreakpoints = new ClearSelectedBreakpointsAction();
|
||||||
actionClearAllBreakpointsAction = new ClearAllBreakpointsAction();
|
actionClearAllBreakpoints = new ClearAllBreakpointsAction();
|
||||||
|
actionMakeBreakpointsEffective = new MakeBreakpointsEffectiveAction();
|
||||||
actionFilterByCurrentTrace = FilterAction.builder(plugin)
|
actionFilterByCurrentTrace = FilterAction.builder(plugin)
|
||||||
.toolBarIcon(DebuggerResources.ICON_TRACE)
|
.toolBarIcon(DebuggerResources.ICON_TRACE)
|
||||||
.description("Filter locations to those in current trace")
|
.description("Filter locations to those in current trace")
|
||||||
@@ -938,6 +1036,8 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
|
|||||||
.helpLocation(new HelpLocation(plugin.getName(), "filter_by_logical"))
|
.helpLocation(new HelpLocation(plugin.getName(), "filter_by_logical"))
|
||||||
.onAction(this::toggledFilterLocationsByBreakpoints)
|
.onAction(this::toggledFilterLocationsByBreakpoints)
|
||||||
.buildAndInstallLocal(this);
|
.buildAndInstallLocal(this);
|
||||||
|
|
||||||
|
actionMakeBreakpointsEffectiveResolution = new MakeBreakpointsEffectiveResolutionAction();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void toggledFilterByCurrentTrace(ActionContext ignored) {
|
private void toggledFilterByCurrentTrace(ActionContext ignored) {
|
||||||
@@ -979,4 +1079,13 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter
|
|||||||
DebuggerResources.setSelectedRows(sel, locationTableModel::getRow, locationTable,
|
DebuggerResources.setSelectedRows(sel, locationTableModel::getRow, locationTable,
|
||||||
locationTableModel, locationFilterPanel);
|
locationTableModel, locationFilterPanel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void breakpointError(String title, String message, Throwable ex) {
|
||||||
|
if (consoleService == null) {
|
||||||
|
Msg.showError(this, null, title, message, ex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Msg.error(this, message, ex);
|
||||||
|
consoleService.log(DebuggerResources.ICON_LOG_ERROR, message + " (" + ex + ")");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.app.plugin.core.debug.gui.breakpoint;
|
||||||
|
|
||||||
|
import docking.ActionContext;
|
||||||
|
|
||||||
|
// TODO: Any granularity, or just one suggested action on the global tool?
|
||||||
|
public class DebuggerMakeBreakpointsEffectiveActionContext extends ActionContext {
|
||||||
|
// Nothing to add
|
||||||
|
}
|
||||||
+2
-3
@@ -24,7 +24,6 @@ import ghidra.framework.model.DomainObject;
|
|||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.trace.model.breakpoint.TraceBreakpointKind.TraceBreakpointKindSet;
|
import ghidra.trace.model.breakpoint.TraceBreakpointKind.TraceBreakpointKindSet;
|
||||||
import ghidra.util.Msg;
|
|
||||||
|
|
||||||
public class LogicalBreakpointRow {
|
public class LogicalBreakpointRow {
|
||||||
private final DebuggerBreakpointsProvider provider;
|
private final DebuggerBreakpointsProvider provider;
|
||||||
@@ -64,7 +63,7 @@ public class LogicalBreakpointRow {
|
|||||||
? lb.enableForTrace(provider.currentTrace)
|
? lb.enableForTrace(provider.currentTrace)
|
||||||
: lb.enable();
|
: lb.enable();
|
||||||
future.exceptionally(ex -> {
|
future.exceptionally(ex -> {
|
||||||
Msg.showError(this, null, "Toggle Breakpoint", "Could not enable breakpoint", ex);
|
provider.breakpointError("Toggle Breakpoint", "Could not enable breakpoint", ex);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -73,7 +72,7 @@ public class LogicalBreakpointRow {
|
|||||||
? lb.disableForTrace(provider.currentTrace)
|
? lb.disableForTrace(provider.currentTrace)
|
||||||
: lb.disable();
|
: lb.disable();
|
||||||
future.exceptionally(ex -> {
|
future.exceptionally(ex -> {
|
||||||
Msg.showError(this, null, "Toggle Breakpoint", "Could not disable breakpoint", ex);
|
provider.breakpointError("Toggle Breakpoint", "Could not disable breakpoint", ex);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-2
@@ -29,6 +29,7 @@ import docking.ActionContext;
|
|||||||
import docking.action.DockingActionIf;
|
import docking.action.DockingActionIf;
|
||||||
import ghidra.app.plugin.PluginCategoryNames;
|
import ghidra.app.plugin.PluginCategoryNames;
|
||||||
import ghidra.app.plugin.core.debug.DebuggerPluginPackage;
|
import ghidra.app.plugin.core.debug.DebuggerPluginPackage;
|
||||||
|
import ghidra.app.plugin.core.debug.gui.console.DebuggerConsoleProvider.LogRow;
|
||||||
import ghidra.app.services.DebuggerConsoleService;
|
import ghidra.app.services.DebuggerConsoleService;
|
||||||
import ghidra.framework.plugintool.*;
|
import ghidra.framework.plugintool.*;
|
||||||
import ghidra.framework.plugintool.util.PluginStatus;
|
import ghidra.framework.plugintool.util.PluginStatus;
|
||||||
@@ -99,14 +100,24 @@ public class DebuggerConsolePlugin extends Plugin implements DebuggerConsoleServ
|
|||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void log(Icon icon, String message) {
|
||||||
|
provider.log(icon, message);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void log(Icon icon, String message, ActionContext context) {
|
public void log(Icon icon, String message, ActionContext context) {
|
||||||
provider.log(icon, message, context);
|
provider.log(icon, message, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void remove(ActionContext context) {
|
public void removeFromLog(ActionContext context) {
|
||||||
provider.remove(context);
|
provider.removeFromLog(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean logContains(ActionContext context) {
|
||||||
|
return provider.logContains(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -127,4 +138,14 @@ public class DebuggerConsolePlugin extends Plugin implements DebuggerConsoleServ
|
|||||||
public long getRowCount(Class<? extends ActionContext> ctxCls) {
|
public long getRowCount(Class<? extends ActionContext> ctxCls) {
|
||||||
return provider.getRowCount(ctxCls);
|
return provider.getRowCount(ctxCls);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For testing: to verify the contents of a message delivered to the console log
|
||||||
|
*
|
||||||
|
* @param ctx the context
|
||||||
|
* @return the the log entry
|
||||||
|
*/
|
||||||
|
public LogRow getLogRow(ActionContext ctx) {
|
||||||
|
return provider.getLogRow(ctx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+44
-8
@@ -56,7 +56,7 @@ public class DebuggerConsoleProvider extends ComponentProviderAdapter
|
|||||||
static final int ACTION_BUTTON_SIZE = 32;
|
static final int ACTION_BUTTON_SIZE = 32;
|
||||||
static final Dimension ACTION_BUTTON_DIM =
|
static final Dimension ACTION_BUTTON_DIM =
|
||||||
new Dimension(ACTION_BUTTON_SIZE, ACTION_BUTTON_SIZE);
|
new Dimension(ACTION_BUTTON_SIZE, ACTION_BUTTON_SIZE);
|
||||||
static final int MAX_ROW_HEIGHT = 300;
|
static final int MIN_ROW_HEIGHT = 16;
|
||||||
|
|
||||||
protected enum LogTableColumns implements EnumeratedTableColumn<LogTableColumns, LogRow> {
|
protected enum LogTableColumns implements EnumeratedTableColumn<LogTableColumns, LogRow> {
|
||||||
LEVEL("Level", Icon.class, LogRow::getIcon, SortDirection.ASCENDING, false),
|
LEVEL("Level", Icon.class, LogRow::getIcon, SortDirection.ASCENDING, false),
|
||||||
@@ -109,9 +109,15 @@ public class DebuggerConsoleProvider extends ComponentProviderAdapter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static class BoundAction {
|
/**
|
||||||
protected final DockingActionIf action;
|
* An action bound to a context
|
||||||
protected final ActionContext context;
|
*
|
||||||
|
* <p>
|
||||||
|
* This class is public for access by test cases only.
|
||||||
|
*/
|
||||||
|
public static class BoundAction {
|
||||||
|
public final DockingActionIf action;
|
||||||
|
public final ActionContext context;
|
||||||
|
|
||||||
public BoundAction(DockingActionIf action, ActionContext context) {
|
public BoundAction(DockingActionIf action, ActionContext context) {
|
||||||
this.action = action;
|
this.action = action;
|
||||||
@@ -144,10 +150,22 @@ public class DebuggerConsoleProvider extends ComponentProviderAdapter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static class ActionList extends ArrayList<BoundAction> {
|
/**
|
||||||
|
* A list of bound actions
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This class is public for access by test cases only.
|
||||||
|
*/
|
||||||
|
public static class ActionList extends ArrayList<BoundAction> {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static class LogRow {
|
/**
|
||||||
|
* An entry in the console's log
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This class is public for access by test cases only.
|
||||||
|
*/
|
||||||
|
public static class LogRow {
|
||||||
private final Icon icon;
|
private final Icon icon;
|
||||||
private final String message;
|
private final String message;
|
||||||
private final Date date;
|
private final Date date;
|
||||||
@@ -224,7 +242,7 @@ public class DebuggerConsoleProvider extends ComponentProviderAdapter
|
|||||||
int rows = model.getRowCount();
|
int rows = model.getRowCount();
|
||||||
int cols = getColumnCount();
|
int cols = getColumnCount();
|
||||||
for (int r = 0; r < rows; r++) {
|
for (int r = 0; r < rows; r++) {
|
||||||
int height = 0;
|
int height = MIN_ROW_HEIGHT;
|
||||||
for (int c = 0; c < cols; c++) {
|
for (int c = 0; c < cols; c++) {
|
||||||
height = Math.max(height, computePreferredHeight(r, c));
|
height = Math.max(height, computePreferredHeight(r, c));
|
||||||
}
|
}
|
||||||
@@ -382,6 +400,10 @@ public class DebuggerConsoleProvider extends ComponentProviderAdapter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void log(Icon icon, String message) {
|
||||||
|
log(icon, message, new LogRowConsoleActionContext());
|
||||||
|
}
|
||||||
|
|
||||||
protected void log(Icon icon, String message, ActionContext context) {
|
protected void log(Icon icon, String message, ActionContext context) {
|
||||||
logRow(new LogRow(icon, message, new Date(), context, computeToolbarActions(context)));
|
logRow(new LogRow(icon, message, new Date(), context, computeToolbarActions(context)));
|
||||||
}
|
}
|
||||||
@@ -419,13 +441,19 @@ public class DebuggerConsoleProvider extends ComponentProviderAdapter
|
|||||||
new Date(event.getTimeMillis()), context, computeToolbarActions(context)));
|
new Date(event.getTimeMillis()), context, computeToolbarActions(context)));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void remove(ActionContext context) {
|
protected void removeFromLog(ActionContext context) {
|
||||||
synchronized (buffer) {
|
synchronized (buffer) {
|
||||||
LogRow r = logTableModel.deleteKey(context);
|
LogRow r = logTableModel.deleteKey(context);
|
||||||
buffer.remove(r);
|
buffer.remove(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean logContains(ActionContext context) {
|
||||||
|
synchronized (buffer) {
|
||||||
|
return logTableModel.getMap().containsKey(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected void addResolutionAction(DockingActionIf action) {
|
protected void addResolutionAction(DockingActionIf action) {
|
||||||
DockingActionIf replaced =
|
DockingActionIf replaced =
|
||||||
actionsByOwnerThenName.computeIfAbsent(action.getOwner(), o -> new LinkedHashMap<>())
|
actionsByOwnerThenName.computeIfAbsent(action.getOwner(), o -> new LinkedHashMap<>())
|
||||||
@@ -479,9 +507,17 @@ public class DebuggerConsoleProvider extends ComponentProviderAdapter
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected long getRowCount(Class<? extends ActionContext> ctxCls) {
|
protected long getRowCount(Class<? extends ActionContext> ctxCls) {
|
||||||
|
synchronized (buffer) {
|
||||||
return logTableModel.getModelData()
|
return logTableModel.getModelData()
|
||||||
.stream()
|
.stream()
|
||||||
.filter(r -> ctxCls.isInstance(r.context))
|
.filter(r -> ctxCls.isInstance(r.context))
|
||||||
.count();
|
.count();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public LogRow getLogRow(ActionContext ctx) {
|
||||||
|
synchronized (buffer) {
|
||||||
|
return logTableModel.getMap().get(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
@@ -65,6 +65,7 @@ import utilities.util.SuppressableCallback.Suppression;
|
|||||||
eventsConsumed = {
|
eventsConsumed = {
|
||||||
// ProgramSelectionPluginEvent.class, // TODO: Later or remove
|
// ProgramSelectionPluginEvent.class, // TODO: Later or remove
|
||||||
// ProgramHighlightPluginEvent.class, // TODO: Later or remove
|
// ProgramHighlightPluginEvent.class, // TODO: Later or remove
|
||||||
|
ProgramOpenedPluginEvent.class, // For auto-open log cleanup
|
||||||
ProgramClosedPluginEvent.class, // For marker set cleanup
|
ProgramClosedPluginEvent.class, // For marker set cleanup
|
||||||
ProgramLocationPluginEvent.class, // For static listing sync
|
ProgramLocationPluginEvent.class, // For static listing sync
|
||||||
TraceActivatedPluginEvent.class, // Trace/thread activation and register tracking
|
TraceActivatedPluginEvent.class, // Trace/thread activation and register tracking
|
||||||
@@ -275,6 +276,10 @@ public class DebuggerListingPlugin extends CodeBrowserPlugin implements Debugger
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (event instanceof ProgramOpenedPluginEvent) {
|
||||||
|
ProgramOpenedPluginEvent ev = (ProgramOpenedPluginEvent) event;
|
||||||
|
allProviders(p -> p.programOpened(ev.getProgram()));
|
||||||
|
}
|
||||||
if (event instanceof ProgramClosedPluginEvent) {
|
if (event instanceof ProgramClosedPluginEvent) {
|
||||||
ProgramClosedPluginEvent ev = (ProgramClosedPluginEvent) event;
|
ProgramClosedPluginEvent ev = (ProgramClosedPluginEvent) event;
|
||||||
allProviders(p -> p.programClosed(ev.getProgram()));
|
allProviders(p -> p.programClosed(ev.getProgram()));
|
||||||
|
|||||||
+101
-10
@@ -50,8 +50,7 @@ import ghidra.app.plugin.core.debug.gui.action.*;
|
|||||||
import ghidra.app.plugin.core.debug.gui.action.AutoReadMemorySpec.AutoReadMemorySpecConfigFieldCodec;
|
import ghidra.app.plugin.core.debug.gui.action.AutoReadMemorySpec.AutoReadMemorySpecConfigFieldCodec;
|
||||||
import ghidra.app.plugin.core.debug.gui.action.LocationTrackingSpec.TrackingSpecConfigFieldCodec;
|
import ghidra.app.plugin.core.debug.gui.action.LocationTrackingSpec.TrackingSpecConfigFieldCodec;
|
||||||
import ghidra.app.plugin.core.debug.gui.modules.DebuggerMissingModuleActionContext;
|
import ghidra.app.plugin.core.debug.gui.modules.DebuggerMissingModuleActionContext;
|
||||||
import ghidra.app.plugin.core.debug.utils.BackgroundUtils;
|
import ghidra.app.plugin.core.debug.utils.*;
|
||||||
import ghidra.app.plugin.core.debug.utils.ProgramURLUtils;
|
|
||||||
import ghidra.app.plugin.core.exporter.ExporterDialog;
|
import ghidra.app.plugin.core.exporter.ExporterDialog;
|
||||||
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
||||||
import ghidra.app.services.*;
|
import ghidra.app.services.*;
|
||||||
@@ -86,6 +85,9 @@ import ghidra.trace.model.thread.TraceThread;
|
|||||||
import ghidra.trace.model.time.TraceSnapshot;
|
import ghidra.trace.model.time.TraceSnapshot;
|
||||||
import ghidra.trace.util.TraceAddressSpace;
|
import ghidra.trace.util.TraceAddressSpace;
|
||||||
import ghidra.util.*;
|
import ghidra.util.*;
|
||||||
|
import ghidra.util.exception.CancelledException;
|
||||||
|
import ghidra.util.exception.VersionException;
|
||||||
|
import ghidra.util.task.*;
|
||||||
import utilities.util.SuppressableCallback;
|
import utilities.util.SuppressableCallback;
|
||||||
import utilities.util.SuppressableCallback.Suppression;
|
import utilities.util.SuppressableCallback.Suppression;
|
||||||
|
|
||||||
@@ -353,6 +355,7 @@ public class DebuggerListingProvider extends CodeViewerProvider implements Listi
|
|||||||
protected FollowsCurrentThreadAction actionFollowsCurrentThread;
|
protected FollowsCurrentThreadAction actionFollowsCurrentThread;
|
||||||
protected MultiStateDockingAction<AutoReadMemorySpec> actionAutoReadMemory;
|
protected MultiStateDockingAction<AutoReadMemorySpec> actionAutoReadMemory;
|
||||||
protected DockingAction actionExportView;
|
protected DockingAction actionExportView;
|
||||||
|
protected DockingAction actionOpenProgram;
|
||||||
|
|
||||||
protected final DebuggerGoToDialog goToDialog;
|
protected final DebuggerGoToDialog goToDialog;
|
||||||
|
|
||||||
@@ -586,6 +589,15 @@ public class DebuggerListingProvider extends CodeViewerProvider implements Listi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@AutoServiceConsumed
|
||||||
|
private void setConsoleService(DebuggerConsoleService consoleService) {
|
||||||
|
if (consoleService != null) {
|
||||||
|
if (actionOpenProgram != null) {
|
||||||
|
consoleService.addResolutionAction(actionOpenProgram);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected void markTrackedStaticLocation(ProgramLocation location) {
|
protected void markTrackedStaticLocation(ProgramLocation location) {
|
||||||
Swing.runIfSwingOrRunLater(() -> {
|
Swing.runIfSwingOrRunLater(() -> {
|
||||||
if (location == null) {
|
if (location == null) {
|
||||||
@@ -607,6 +619,17 @@ public class DebuggerListingProvider extends CodeViewerProvider implements Listi
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void programOpened(Program program) {
|
||||||
|
if (!isMainListing()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DomainFile df = program.getDomainFile();
|
||||||
|
DebuggerOpenProgramActionContext ctx = new DebuggerOpenProgramActionContext(df);
|
||||||
|
if (consoleService != null) {
|
||||||
|
consoleService.removeFromLog(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void programClosed(Program program) {
|
public void programClosed(Program program) {
|
||||||
if (program == markedProgram) {
|
if (program == markedProgram) {
|
||||||
removeOldStaticTrackingMarker();
|
removeOldStaticTrackingMarker();
|
||||||
@@ -784,6 +807,11 @@ public class DebuggerListingProvider extends CodeViewerProvider implements Listi
|
|||||||
.onAction(this::activatedExportView)
|
.onAction(this::activatedExportView)
|
||||||
.buildAndInstallLocal(this);
|
.buildAndInstallLocal(this);
|
||||||
|
|
||||||
|
actionOpenProgram = OpenProgramAction.builder(plugin)
|
||||||
|
.withContext(DebuggerOpenProgramActionContext.class)
|
||||||
|
.onAction(this::activatedOpenProgram)
|
||||||
|
.build();
|
||||||
|
|
||||||
contextChanged();
|
contextChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -813,6 +841,11 @@ public class DebuggerListingProvider extends CodeViewerProvider implements Listi
|
|||||||
tool.showDialog(dialog);
|
tool.showDialog(dialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void activatedOpenProgram(DebuggerOpenProgramActionContext context) {
|
||||||
|
programManager.openProgram(context.getDomainFile(), DomainFile.DEFAULT_VERSION,
|
||||||
|
ProgramManager.OPEN_CURRENT);
|
||||||
|
}
|
||||||
|
|
||||||
protected void activatedLocationTracking(ActionContext ctx) {
|
protected void activatedLocationTracking(ActionContext ctx) {
|
||||||
doTrackSpec();
|
doTrackSpec();
|
||||||
}
|
}
|
||||||
@@ -901,7 +934,7 @@ public class DebuggerListingProvider extends CodeViewerProvider implements Listi
|
|||||||
public void programLocationChanged(ProgramLocation location, EventTrigger trigger) {
|
public void programLocationChanged(ProgramLocation location, EventTrigger trigger) {
|
||||||
updateLocationLabel();
|
updateLocationLabel();
|
||||||
if (traceManager != null) {
|
if (traceManager != null) {
|
||||||
location = traceManager.fixLocation(location, false);
|
location = ProgramLocationUtils.fixLocation(location, false);
|
||||||
}
|
}
|
||||||
super.programLocationChanged(location, trigger);
|
super.programLocationChanged(location, trigger);
|
||||||
if (trigger == EventTrigger.GUI_ACTION) {
|
if (trigger == EventTrigger.GUI_ACTION) {
|
||||||
@@ -935,7 +968,7 @@ public class DebuggerListingProvider extends CodeViewerProvider implements Listi
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void doSyncToStatic(ProgramLocation location) {
|
protected void doSyncToStatic(ProgramLocation location) {
|
||||||
if (syncToStaticListing && location != null) {
|
if (isSyncToStaticListing() && location != null) {
|
||||||
ProgramLocation staticLoc = mappingService.getStaticLocationFromDynamic(location);
|
ProgramLocation staticLoc = mappingService.getStaticLocationFromDynamic(location);
|
||||||
if (staticLoc != null) {
|
if (staticLoc != null) {
|
||||||
Swing.runIfSwingOrRunLater(() -> plugin.fireStaticLocationEvent(staticLoc));
|
Swing.runIfSwingOrRunLater(() -> plugin.fireStaticLocationEvent(staticLoc));
|
||||||
@@ -943,8 +976,58 @@ public class DebuggerListingProvider extends CodeViewerProvider implements Listi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void doTryOpenProgram(DomainFile df, int version, int state) {
|
||||||
|
DebuggerOpenProgramActionContext ctx = new DebuggerOpenProgramActionContext(df);
|
||||||
|
if (consoleService != null && consoleService.logContains(ctx)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (df.canRecover()) {
|
||||||
|
if (consoleService != null) {
|
||||||
|
consoleService.log(DebuggerResources.ICON_MODULES, "<html>Program <b>" +
|
||||||
|
HTMLUtilities.escapeHTML(df.getPathname()) +
|
||||||
|
"</b> has recovery data. It must be opened manually.</html>", ctx);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
new TaskLauncher(new Task("Open " + df, true, false, false) {
|
||||||
|
@Override
|
||||||
|
public void run(TaskMonitor monitor) throws CancelledException {
|
||||||
|
Program program = null;
|
||||||
|
try {
|
||||||
|
program = (Program) df.getDomainObject(this, false, false, monitor);
|
||||||
|
programManager.openProgram(program, state);
|
||||||
|
}
|
||||||
|
catch (VersionException e) {
|
||||||
|
if (consoleService != null) {
|
||||||
|
consoleService.log(DebuggerResources.ICON_MODULES, "<html>Program <b>" +
|
||||||
|
HTMLUtilities.escapeHTML(df.getPathname()) +
|
||||||
|
"</b> was created with a different version of Ghidra." +
|
||||||
|
" It must be opened manually.</html>", ctx);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
if (consoleService != null) {
|
||||||
|
consoleService.log(DebuggerResources.ICON_LOG_ERROR, "<html>Program <b>" +
|
||||||
|
HTMLUtilities.escapeHTML(df.getPathname()) +
|
||||||
|
"</b> could not be opened: " + e + ". Try opening it manually.</html>",
|
||||||
|
ctx);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if (program != null) {
|
||||||
|
program.release(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, tool.getToolFrame());
|
||||||
|
}
|
||||||
|
|
||||||
protected void doCheckCurrentModuleMissing() {
|
protected void doCheckCurrentModuleMissing() {
|
||||||
if (importerService == null || consoleService == null) {
|
// Is there any reason to try to open the module if we're not syncing listings?
|
||||||
|
// I don't think so.
|
||||||
|
if (!isSyncToStaticListing()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Trace trace = current.getTrace();
|
Trace trace = current.getTrace();
|
||||||
@@ -968,9 +1051,7 @@ public class DebuggerListingProvider extends CodeViewerProvider implements Listi
|
|||||||
DomainFile df = ProgramURLUtils.getFileForHackedUpGhidraURL(tool.getProject(),
|
DomainFile df = ProgramURLUtils.getFileForHackedUpGhidraURL(tool.getProject(),
|
||||||
mapping.getStaticProgramURL());
|
mapping.getStaticProgramURL());
|
||||||
if (df != null) {
|
if (df != null) {
|
||||||
// We're almost certainly preparing to goTo, so make it current
|
doTryOpenProgram(df, DomainFile.DEFAULT_VERSION, ProgramManager.OPEN_CURRENT);
|
||||||
programManager.openProgram(df, DomainFile.DEFAULT_VERSION,
|
|
||||||
ProgramManager.OPEN_CURRENT);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -996,14 +1077,19 @@ public class DebuggerListingProvider extends CodeViewerProvider implements Listi
|
|||||||
if (programManager != null && !toOpen.isEmpty()) {
|
if (programManager != null && !toOpen.isEmpty()) {
|
||||||
for (DomainFile df : toOpen) {
|
for (DomainFile df : toOpen) {
|
||||||
// Do not presume a goTo is about to happen. There are no mappings, yet.
|
// Do not presume a goTo is about to happen. There are no mappings, yet.
|
||||||
programManager.openProgram(df, DomainFile.DEFAULT_VERSION,
|
doTryOpenProgram(df, DomainFile.DEFAULT_VERSION,
|
||||||
ProgramManager.OPEN_VISIBLE);
|
ProgramManager.OPEN_VISIBLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (importerService == null || consoleService == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (TraceModule mod : missing) {
|
for (TraceModule mod : missing) {
|
||||||
consoleService.log(DebuggerResources.ICON_LOG_ERROR,
|
consoleService.log(DebuggerResources.ICON_LOG_ERROR,
|
||||||
"<html>The module <b><tt>" + HTMLUtilities.escapeHTML(mod.getName()) +
|
"<html>The module <b><tt>" + HTMLUtilities.escapeHTML(mod.getName()) +
|
||||||
"</tt></b> was not found in the project",
|
"</tt></b> was not found in the project</html>",
|
||||||
new DebuggerMissingModuleActionContext(mod));
|
new DebuggerMissingModuleActionContext(mod));
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -1145,6 +1231,11 @@ public class DebuggerListingProvider extends CodeViewerProvider implements Listi
|
|||||||
public void dispose() {
|
public void dispose() {
|
||||||
super.dispose();
|
super.dispose();
|
||||||
removeOldListeners();
|
removeOldListeners();
|
||||||
|
if (consoleService != null) {
|
||||||
|
if (actionOpenProgram != null) {
|
||||||
|
consoleService.removeResolutionAction(actionOpenProgram);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+55
@@ -0,0 +1,55 @@
|
|||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.app.plugin.core.debug.gui.listing;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import docking.ActionContext;
|
||||||
|
import ghidra.framework.model.DomainFile;
|
||||||
|
|
||||||
|
public class DebuggerOpenProgramActionContext extends ActionContext {
|
||||||
|
private final DomainFile df;
|
||||||
|
private final int hashCode;
|
||||||
|
|
||||||
|
public DebuggerOpenProgramActionContext(DomainFile df) {
|
||||||
|
this.df = df;
|
||||||
|
this.hashCode = Objects.hash(getClass(), df);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DomainFile getDomainFile() {
|
||||||
|
return df;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return hashCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!(obj instanceof DebuggerOpenProgramActionContext)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
DebuggerOpenProgramActionContext that = (DebuggerOpenProgramActionContext) obj;
|
||||||
|
if (!this.df.equals(that.df)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
+29
-6
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.core.debug.gui.modules;
|
package ghidra.app.plugin.core.debug.gui.modules;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
@@ -34,18 +35,17 @@ import ghidra.util.Swing;
|
|||||||
public class DebuggerModuleMapProposalDialog
|
public class DebuggerModuleMapProposalDialog
|
||||||
extends AbstractDebuggerMapProposalDialog<ModuleMapEntry> {
|
extends AbstractDebuggerMapProposalDialog<ModuleMapEntry> {
|
||||||
|
|
||||||
static final String BLANK = "";
|
|
||||||
static final int BUTTON_SIZE = 32;
|
static final int BUTTON_SIZE = 32;
|
||||||
|
|
||||||
protected enum ModuleMapTableColumns
|
protected enum ModuleMapTableColumns
|
||||||
implements EnumeratedTableColumn<ModuleMapTableColumns, ModuleMapEntry> {
|
implements EnumeratedTableColumn<ModuleMapTableColumns, ModuleMapEntry> {
|
||||||
REMOVE("Remove", String.class, e -> BLANK, (e, v) -> nop()),
|
REMOVE("Remove", String.class, e -> "Remove Proposed Entry", (e, v) -> nop()),
|
||||||
MODULE_NAME("Module", String.class, e -> e.getModule().getName()),
|
MODULE_NAME("Module", String.class, e -> e.getModule().getName()),
|
||||||
DYNAMIC_BASE("Dynamic Base", Address.class, e -> e.getModule().getBase()),
|
DYNAMIC_BASE("Dynamic Base", Address.class, e -> e.getModule().getBase()),
|
||||||
|
CHOOSE("Choose", String.class, e -> "Choose Program", (e, v) -> nop()),
|
||||||
PROGRAM_NAME("Program", String.class, e -> e.getProgram().getName()),
|
PROGRAM_NAME("Program", String.class, e -> e.getProgram().getName()),
|
||||||
STATIC_BASE("Static Base", Address.class, e -> e.getProgram().getImageBase()),
|
STATIC_BASE("Static Base", Address.class, e -> e.getProgram().getImageBase()),
|
||||||
SIZE("Size", Long.class, e -> e.getModuleRange().getLength()),
|
SIZE("Size", Long.class, e -> e.getModuleRange().getLength());
|
||||||
CHOOSE("Choose", String.class, e -> BLANK, (e, v) -> nop());
|
|
||||||
|
|
||||||
private final String header;
|
private final String header;
|
||||||
private final Class<?> cls;
|
private final Class<?> cls;
|
||||||
@@ -94,6 +94,19 @@ public class DebuggerModuleMapProposalDialog
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static class ModuleMapPropsalTableModel extends
|
||||||
|
DefaultEnumeratedColumnTableModel<ModuleMapTableColumns, ModuleMapEntry> {
|
||||||
|
|
||||||
|
public ModuleMapPropsalTableModel() {
|
||||||
|
super("Module Map", ModuleMapTableColumns.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ModuleMapTableColumns> defaultSortOrder() {
|
||||||
|
return List.of(ModuleMapTableColumns.MODULE_NAME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private final DebuggerModulesProvider provider;
|
private final DebuggerModulesProvider provider;
|
||||||
|
|
||||||
protected DebuggerModuleMapProposalDialog(DebuggerModulesProvider provider) {
|
protected DebuggerModuleMapProposalDialog(DebuggerModulesProvider provider) {
|
||||||
@@ -102,8 +115,8 @@ public class DebuggerModuleMapProposalDialog
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected EnumeratedColumnTableModel<ModuleMapEntry> createTableModel() {
|
protected ModuleMapPropsalTableModel createTableModel() {
|
||||||
return new DefaultEnumeratedColumnTableModel<>("Module Map", ModuleMapTableColumns.class);
|
return new ModuleMapPropsalTableModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -117,9 +130,19 @@ public class DebuggerModuleMapProposalDialog
|
|||||||
CellEditorUtils.installButton(table, filterPanel, removeCol,
|
CellEditorUtils.installButton(table, filterPanel, removeCol,
|
||||||
DebuggerResources.ICON_DELETE, BUTTON_SIZE, this::removeEntry);
|
DebuggerResources.ICON_DELETE, BUTTON_SIZE, this::removeEntry);
|
||||||
|
|
||||||
|
TableColumn dynBaseCol =
|
||||||
|
columnModel.getColumn(ModuleMapTableColumns.DYNAMIC_BASE.ordinal());
|
||||||
|
dynBaseCol.setCellRenderer(CustomToStringCellRenderer.MONO_OBJECT);
|
||||||
|
|
||||||
TableColumn chooseCol = columnModel.getColumn(ModuleMapTableColumns.CHOOSE.ordinal());
|
TableColumn chooseCol = columnModel.getColumn(ModuleMapTableColumns.CHOOSE.ordinal());
|
||||||
CellEditorUtils.installButton(table, filterPanel, chooseCol,
|
CellEditorUtils.installButton(table, filterPanel, chooseCol,
|
||||||
DebuggerResources.ICON_PROGRAM, BUTTON_SIZE, this::chooseAndSetProgram);
|
DebuggerResources.ICON_PROGRAM, BUTTON_SIZE, this::chooseAndSetProgram);
|
||||||
|
|
||||||
|
TableColumn stBaseCol = columnModel.getColumn(ModuleMapTableColumns.STATIC_BASE.ordinal());
|
||||||
|
stBaseCol.setCellRenderer(CustomToStringCellRenderer.MONO_OBJECT);
|
||||||
|
|
||||||
|
TableColumn sizeCol = columnModel.getColumn(ModuleMapTableColumns.SIZE.ordinal());
|
||||||
|
sizeCol.setCellRenderer(CustomToStringCellRenderer.MONO_ULONG_HEX);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void chooseAndSetProgram(ModuleMapEntry entry) {
|
private void chooseAndSetProgram(ModuleMapEntry entry) {
|
||||||
|
|||||||
+20
-6
@@ -867,12 +867,12 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
|||||||
Msg.error(this, "Import service is not present");
|
Msg.error(this, "Import service is not present");
|
||||||
}
|
}
|
||||||
importModuleFromFileSystem(context.getModule());
|
importModuleFromFileSystem(context.getModule());
|
||||||
consoleService.remove(context); // TODO: Should remove when mapping is created
|
consoleService.removeFromLog(context); // TODO: Should remove when mapping is created
|
||||||
}
|
}
|
||||||
|
|
||||||
private void activatedMapMissingModule(DebuggerMissingModuleActionContext context) {
|
private void activatedMapMissingModule(DebuggerMissingModuleActionContext context) {
|
||||||
mapModuleTo(context.getModule());
|
mapModuleTo(context.getModule());
|
||||||
consoleService.remove(context); // TODO: Should remove when mapping is created
|
consoleService.removeFromLog(context); // TODO: Should remove when mapping is created
|
||||||
}
|
}
|
||||||
|
|
||||||
private void toggledFilter(ActionContext ignored) {
|
private void toggledFilter(ActionContext ignored) {
|
||||||
@@ -972,13 +972,20 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void promptModuleProposal(Collection<ModuleMapEntry> proposal) {
|
protected void promptModuleProposal(Collection<ModuleMapEntry> proposal) {
|
||||||
|
if (proposal.isEmpty()) {
|
||||||
|
Msg.showInfo(this, getComponent(), "Map Modules",
|
||||||
|
"Could not formulate a proposal for any selected module." +
|
||||||
|
" You may need to import and/or open the destination images first.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
Collection<ModuleMapEntry> adjusted =
|
Collection<ModuleMapEntry> adjusted =
|
||||||
moduleProposalDialog.adjustCollection(getTool(), proposal);
|
moduleProposalDialog.adjustCollection(getTool(), proposal);
|
||||||
if (adjusted != null && staticMappingService != null) {
|
if (adjusted == null || staticMappingService == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
tool.executeBackgroundCommand(
|
tool.executeBackgroundCommand(
|
||||||
new MapModulesBackgroundCommand(staticMappingService, adjusted), currentTrace);
|
new MapModulesBackgroundCommand(staticMappingService, adjusted), currentTrace);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
protected void mapModules(Set<TraceModule> modules) {
|
protected void mapModules(Set<TraceModule> modules) {
|
||||||
if (staticMappingService == null) {
|
if (staticMappingService == null) {
|
||||||
@@ -1004,13 +1011,20 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void promptSectionProposal(Collection<SectionMapEntry> proposal) {
|
protected void promptSectionProposal(Collection<SectionMapEntry> proposal) {
|
||||||
|
if (proposal.isEmpty()) {
|
||||||
|
Msg.showInfo(this, getComponent(), "Map Sections",
|
||||||
|
"Could not formulate a proposal for any selected section." +
|
||||||
|
" You may need to import and/or open the destination images first.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
Collection<SectionMapEntry> adjusted =
|
Collection<SectionMapEntry> adjusted =
|
||||||
sectionProposalDialog.adjustCollection(getTool(), proposal);
|
sectionProposalDialog.adjustCollection(getTool(), proposal);
|
||||||
if (adjusted != null && staticMappingService != null) {
|
if (adjusted == null || staticMappingService == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
tool.executeBackgroundCommand(
|
tool.executeBackgroundCommand(
|
||||||
new MapSectionsBackgroundCommand(staticMappingService, adjusted), currentTrace);
|
new MapSectionsBackgroundCommand(staticMappingService, adjusted), currentTrace);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
protected void mapSections(Set<TraceSection> sections) {
|
protected void mapSections(Set<TraceSection> sections) {
|
||||||
if (staticMappingService == null) {
|
if (staticMappingService == null) {
|
||||||
|
|||||||
+29
-6
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.core.debug.gui.modules;
|
package ghidra.app.plugin.core.debug.gui.modules;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
@@ -35,20 +36,19 @@ import ghidra.util.Swing;
|
|||||||
public class DebuggerSectionMapProposalDialog
|
public class DebuggerSectionMapProposalDialog
|
||||||
extends AbstractDebuggerMapProposalDialog<SectionMapEntry> {
|
extends AbstractDebuggerMapProposalDialog<SectionMapEntry> {
|
||||||
|
|
||||||
static final String BLANK = "";
|
|
||||||
static final int BUTTON_SIZE = 32;
|
static final int BUTTON_SIZE = 32;
|
||||||
|
|
||||||
protected enum SectionMapTableColumns
|
protected enum SectionMapTableColumns
|
||||||
implements EnumeratedTableColumn<SectionMapTableColumns, SectionMapEntry> {
|
implements EnumeratedTableColumn<SectionMapTableColumns, SectionMapEntry> {
|
||||||
REMOVE("Remove", String.class, e -> BLANK, (e, v) -> nop()),
|
REMOVE("Remove", String.class, e -> "Remove Proposed Entry", (e, v) -> nop()),
|
||||||
MODULE_NAME("Module", String.class, e -> e.getModule().getName()),
|
MODULE_NAME("Module", String.class, e -> e.getModule().getName()),
|
||||||
SECTION_NAME("Section", String.class, e -> e.getSection().getName()),
|
SECTION_NAME("Section", String.class, e -> e.getSection().getName()),
|
||||||
DYNAMIC_BASE("Dynamic Base", Address.class, e -> e.getSection().getStart()),
|
DYNAMIC_BASE("Dynamic Base", Address.class, e -> e.getSection().getStart()),
|
||||||
|
CHOOSE("Choose", String.class, e -> "Choose Block", (e, s) -> nop()),
|
||||||
PROGRAM_NAME("Program", String.class, e -> e.getProgram().getName()),
|
PROGRAM_NAME("Program", String.class, e -> e.getProgram().getName()),
|
||||||
BLOCK_NAME("Block", String.class, e -> e.getBlock().getName()),
|
BLOCK_NAME("Block", String.class, e -> e.getBlock().getName()),
|
||||||
STATIC_BASE("Static Base", Address.class, e -> e.getBlock().getStart()),
|
STATIC_BASE("Static Base", Address.class, e -> e.getBlock().getStart()),
|
||||||
SIZE("Size", Long.class, e -> e.getLength()),
|
SIZE("Size", Long.class, e -> e.getLength());
|
||||||
CHOOSE("Choose", String.class, e -> BLANK, (e, s) -> nop());
|
|
||||||
|
|
||||||
private final String header;
|
private final String header;
|
||||||
private final Class<?> cls;
|
private final Class<?> cls;
|
||||||
@@ -98,6 +98,19 @@ public class DebuggerSectionMapProposalDialog
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static class SectionMapPropsalTableModel extends
|
||||||
|
DefaultEnumeratedColumnTableModel<SectionMapTableColumns, SectionMapEntry> {
|
||||||
|
|
||||||
|
public SectionMapPropsalTableModel() {
|
||||||
|
super("Section Map", SectionMapTableColumns.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<SectionMapTableColumns> defaultSortOrder() {
|
||||||
|
return List.of(SectionMapTableColumns.MODULE_NAME, SectionMapTableColumns.SECTION_NAME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private final DebuggerModulesProvider provider;
|
private final DebuggerModulesProvider provider;
|
||||||
|
|
||||||
public DebuggerSectionMapProposalDialog(DebuggerModulesProvider provider) {
|
public DebuggerSectionMapProposalDialog(DebuggerModulesProvider provider) {
|
||||||
@@ -106,8 +119,8 @@ public class DebuggerSectionMapProposalDialog
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected EnumeratedColumnTableModel<SectionMapEntry> createTableModel() {
|
protected SectionMapPropsalTableModel createTableModel() {
|
||||||
return new DefaultEnumeratedColumnTableModel<>("Section Map", SectionMapTableColumns.class);
|
return new SectionMapPropsalTableModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -121,9 +134,19 @@ public class DebuggerSectionMapProposalDialog
|
|||||||
CellEditorUtils.installButton(table, filterPanel, removeCol,
|
CellEditorUtils.installButton(table, filterPanel, removeCol,
|
||||||
DebuggerResources.ICON_DELETE, BUTTON_SIZE, this::removeEntry);
|
DebuggerResources.ICON_DELETE, BUTTON_SIZE, this::removeEntry);
|
||||||
|
|
||||||
|
TableColumn dynBaseCol =
|
||||||
|
columnModel.getColumn(SectionMapTableColumns.DYNAMIC_BASE.ordinal());
|
||||||
|
dynBaseCol.setCellRenderer(CustomToStringCellRenderer.MONO_OBJECT);
|
||||||
|
|
||||||
TableColumn chooseCol = columnModel.getColumn(SectionMapTableColumns.CHOOSE.ordinal());
|
TableColumn chooseCol = columnModel.getColumn(SectionMapTableColumns.CHOOSE.ordinal());
|
||||||
CellEditorUtils.installButton(table, filterPanel, chooseCol, DebuggerResources.ICON_PROGRAM,
|
CellEditorUtils.installButton(table, filterPanel, chooseCol, DebuggerResources.ICON_PROGRAM,
|
||||||
BUTTON_SIZE, this::chooseAndSetBlock);
|
BUTTON_SIZE, this::chooseAndSetBlock);
|
||||||
|
|
||||||
|
TableColumn stBaseCol = columnModel.getColumn(SectionMapTableColumns.STATIC_BASE.ordinal());
|
||||||
|
stBaseCol.setCellRenderer(CustomToStringCellRenderer.MONO_OBJECT);
|
||||||
|
|
||||||
|
TableColumn sizeCol = columnModel.getColumn(SectionMapTableColumns.SIZE.ordinal());
|
||||||
|
sizeCol.setCellRenderer(CustomToStringCellRenderer.MONO_ULONG_HEX);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void chooseAndSetBlock(SectionMapEntry entry) {
|
private void chooseAndSetBlock(SectionMapEntry entry) {
|
||||||
|
|||||||
+1
-1
@@ -1118,7 +1118,7 @@ public class DebuggerStaticMappingServicePlugin extends Plugin
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProgramLocation getStaticLocationFromDynamic(ProgramLocation loc) {
|
public ProgramLocation getStaticLocationFromDynamic(ProgramLocation loc) {
|
||||||
loc = traceManager.fixLocation(loc, true);
|
loc = ProgramLocationUtils.fixLocation(loc, true);
|
||||||
TraceProgramView view = (TraceProgramView) loc.getProgram();
|
TraceProgramView view = (TraceProgramView) loc.getProgram();
|
||||||
Trace trace = view.getTrace();
|
Trace trace = view.getTrace();
|
||||||
TraceLocation tloc = new DefaultTraceLocation(trace, null,
|
TraceLocation tloc = new DefaultTraceLocation(trace, null,
|
||||||
|
|||||||
-20
@@ -31,7 +31,6 @@ import ghidra.app.plugin.core.debug.DebuggerCoordinates;
|
|||||||
import ghidra.app.plugin.core.debug.DebuggerPluginPackage;
|
import ghidra.app.plugin.core.debug.DebuggerPluginPackage;
|
||||||
import ghidra.app.plugin.core.debug.event.*;
|
import ghidra.app.plugin.core.debug.event.*;
|
||||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.*;
|
import ghidra.app.plugin.core.debug.gui.DebuggerResources.*;
|
||||||
import ghidra.app.plugin.core.debug.utils.ProgramLocationUtils;
|
|
||||||
import ghidra.app.services.*;
|
import ghidra.app.services.*;
|
||||||
import ghidra.async.AsyncConfigFieldCodec.BooleanAsyncConfigFieldCodec;
|
import ghidra.async.AsyncConfigFieldCodec.BooleanAsyncConfigFieldCodec;
|
||||||
import ghidra.async.AsyncReference;
|
import ghidra.async.AsyncReference;
|
||||||
@@ -47,8 +46,6 @@ import ghidra.framework.plugintool.annotation.AutoConfigStateField;
|
|||||||
import ghidra.framework.plugintool.annotation.AutoServiceConsumed;
|
import ghidra.framework.plugintool.annotation.AutoServiceConsumed;
|
||||||
import ghidra.framework.plugintool.util.PluginStatus;
|
import ghidra.framework.plugintool.util.PluginStatus;
|
||||||
import ghidra.lifecycle.Internal;
|
import ghidra.lifecycle.Internal;
|
||||||
import ghidra.program.model.listing.Program;
|
|
||||||
import ghidra.program.util.ProgramLocation;
|
|
||||||
import ghidra.trace.model.Trace;
|
import ghidra.trace.model.Trace;
|
||||||
import ghidra.trace.model.Trace.TraceThreadChangeType;
|
import ghidra.trace.model.Trace.TraceThreadChangeType;
|
||||||
import ghidra.trace.model.TraceDomainObjectListener;
|
import ghidra.trace.model.TraceDomainObjectListener;
|
||||||
@@ -1147,23 +1144,6 @@ public class DebuggerTraceManagerServicePlugin extends Plugin
|
|||||||
autoCloseOnTerminate.removeChangeListener(listener);
|
autoCloseOnTerminate.removeChangeListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
// TODO: Move this into some static util, now that canonical view is a trace concept
|
|
||||||
public ProgramLocation fixLocation(ProgramLocation location, boolean matchSnap) {
|
|
||||||
Program program = location.getProgram();
|
|
||||||
if (!(program instanceof TraceProgramView)) {
|
|
||||||
return location;
|
|
||||||
}
|
|
||||||
TraceProgramView itsView = (TraceProgramView) program;
|
|
||||||
Trace trace = itsView.getTrace();
|
|
||||||
TraceProgramView canonicalView = trace.getProgramView();
|
|
||||||
if (canonicalView == itsView ||
|
|
||||||
(matchSnap && canonicalView.getSnap() != itsView.getSnap())) {
|
|
||||||
return location;
|
|
||||||
}
|
|
||||||
return ProgramLocationUtils.replaceProgram(location, canonicalView);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canClose() {
|
public boolean canClose() {
|
||||||
if (isSaveTracesByDefault()) {
|
if (isSaveTracesByDefault()) {
|
||||||
|
|||||||
+35
-7
@@ -18,20 +18,48 @@ package ghidra.app.plugin.core.debug.utils;
|
|||||||
import ghidra.framework.options.SaveState;
|
import ghidra.framework.options.SaveState;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.program.util.BytesFieldLocation;
|
||||||
import ghidra.program.util.ProgramLocation;
|
import ghidra.program.util.ProgramLocation;
|
||||||
|
import ghidra.trace.model.Trace;
|
||||||
|
import ghidra.trace.model.program.TraceProgramView;
|
||||||
|
|
||||||
public enum ProgramLocationUtils {
|
public enum ProgramLocationUtils {
|
||||||
;
|
;
|
||||||
|
|
||||||
public static ProgramLocation replaceAddress(ProgramLocation loc, Program program,
|
public static ProgramLocation replaceAddress(ProgramLocation loc, Program program,
|
||||||
Address address) {
|
Address address) {
|
||||||
// HACK: ... and a half
|
// Outside of byte fields, I really don't care
|
||||||
SaveState state = new SaveState("LOC");
|
if (loc instanceof BytesFieldLocation) {
|
||||||
loc.saveState(state);
|
return new BytesFieldLocation(program, address);
|
||||||
state.putString("_ADDRESS", address.toString());
|
}
|
||||||
state.putString("_BYTE_ADDR",
|
return new ProgramLocation(program, address);
|
||||||
address.add(loc.getByteAddress().subtract(loc.getAddress())).toString());
|
}
|
||||||
return ProgramLocation.getLocation(program, state);
|
|
||||||
|
/**
|
||||||
|
* Swap out the trace view of a {@link ProgramLocation} if it is not the canonical view
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* If the program location is not associated with a trace, the same location is returned.
|
||||||
|
* Otherwise, this ensures that the given view is the canonical one for the same trace. If
|
||||||
|
* matchSnap is true, the view is only replaced when the replacement shares the same snap.
|
||||||
|
*
|
||||||
|
* @param location a location possibly in a trace view
|
||||||
|
* @param matchSnap true to only replace is snap matches, false to always replace
|
||||||
|
* @return the adjusted location
|
||||||
|
*/
|
||||||
|
public static ProgramLocation fixLocation(ProgramLocation loc, boolean matchSnap) {
|
||||||
|
Program program = loc.getProgram();
|
||||||
|
if (!(program instanceof TraceProgramView)) {
|
||||||
|
return loc;
|
||||||
|
}
|
||||||
|
TraceProgramView itsView = (TraceProgramView) program;
|
||||||
|
Trace trace = itsView.getTrace();
|
||||||
|
TraceProgramView canonicalView = trace.getProgramView();
|
||||||
|
if (canonicalView == itsView ||
|
||||||
|
(matchSnap && canonicalView.getSnap() != itsView.getSnap())) {
|
||||||
|
return loc;
|
||||||
|
}
|
||||||
|
return replaceProgram(loc, canonicalView);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ProgramLocation replaceProgram(ProgramLocation loc, Program program) {
|
public static ProgramLocation replaceProgram(ProgramLocation loc, Program program) {
|
||||||
|
|||||||
+20
-1
@@ -27,6 +27,17 @@ import ghidra.util.HTMLUtilities;
|
|||||||
@ServiceInfo(defaultProvider = DebuggerConsolePlugin.class)
|
@ServiceInfo(defaultProvider = DebuggerConsolePlugin.class)
|
||||||
public interface DebuggerConsoleService extends DebuggerConsoleLogger {
|
public interface DebuggerConsoleService extends DebuggerConsoleLogger {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log a message to the console
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* <b>WARNING:</b> See {@link #log(Icon, String, ActionContext)} regarding HTML.
|
||||||
|
*
|
||||||
|
* @param icon an icon for the message
|
||||||
|
* @param message the HTML-formatted message
|
||||||
|
*/
|
||||||
|
void log(Icon icon, String message);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Log an actionable message to the console
|
* Log an actionable message to the console
|
||||||
*
|
*
|
||||||
@@ -51,7 +62,15 @@ public interface DebuggerConsoleService extends DebuggerConsoleLogger {
|
|||||||
*
|
*
|
||||||
* @param context the context of the entry to remove
|
* @param context the context of the entry to remove
|
||||||
*/
|
*/
|
||||||
void remove(ActionContext context);
|
void removeFromLog(ActionContext context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the console contains an actionable message for the given context
|
||||||
|
*
|
||||||
|
* @param context the context to check for
|
||||||
|
* @return true if present, false if absent
|
||||||
|
*/
|
||||||
|
boolean logContains(ActionContext context);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add an action which might be applied to an actionable log message
|
* Add an action which might be applied to an actionable log message
|
||||||
|
|||||||
-16
@@ -22,7 +22,6 @@ import ghidra.app.plugin.core.debug.DebuggerCoordinates;
|
|||||||
import ghidra.app.plugin.core.debug.service.tracemgr.DebuggerTraceManagerServicePlugin;
|
import ghidra.app.plugin.core.debug.service.tracemgr.DebuggerTraceManagerServicePlugin;
|
||||||
import ghidra.framework.model.DomainFile;
|
import ghidra.framework.model.DomainFile;
|
||||||
import ghidra.framework.plugintool.ServiceInfo;
|
import ghidra.framework.plugintool.ServiceInfo;
|
||||||
import ghidra.program.util.ProgramLocation;
|
|
||||||
import ghidra.trace.model.Trace;
|
import ghidra.trace.model.Trace;
|
||||||
import ghidra.trace.model.program.TraceProgramView;
|
import ghidra.trace.model.program.TraceProgramView;
|
||||||
import ghidra.trace.model.thread.TraceThread;
|
import ghidra.trace.model.thread.TraceThread;
|
||||||
@@ -195,21 +194,6 @@ public interface DebuggerTraceManagerService {
|
|||||||
|
|
||||||
void removeAutoCloseOnTerminateChangeListener(BooleanChangeAdapter listener);
|
void removeAutoCloseOnTerminateChangeListener(BooleanChangeAdapter listener);
|
||||||
|
|
||||||
/**
|
|
||||||
* Swap out the trace view of a {@link ProgramLocation} if it is not the debugger's view
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* If the program location is not associated with a trace, the same location is returned.
|
|
||||||
* Otherwise, this ensures that the given view is the one found in the debugger plugin for the
|
|
||||||
* same trace. If matchSnap is true, the view is only replaced when the replacement shares the
|
|
||||||
* same snap.
|
|
||||||
*
|
|
||||||
* @param location a location possibly in a trace view
|
|
||||||
* @param matchSnap true to only replace is snap matches, false to always replace
|
|
||||||
* @return the adjusted location
|
|
||||||
*/
|
|
||||||
ProgramLocation fixLocation(ProgramLocation location, boolean matchSnap);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fill in an incomplete coordinate specification, using the manager's "best judgement"
|
* Fill in an incomplete coordinate specification, using the manager's "best judgement"
|
||||||
*
|
*
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 381 B |
@@ -0,0 +1,64 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="16px"
|
||||||
|
height="16px"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
version="1.1"
|
||||||
|
id="SVGRoot"
|
||||||
|
sodipodi:docname="breakpoints-make-effective.svg"
|
||||||
|
inkscape:version="0.92.2 (5c3e80d, 2017-08-06)">
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="757"
|
||||||
|
inkscape:window-height="480"
|
||||||
|
id="namedview8"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="14.75"
|
||||||
|
inkscape:cx="8"
|
||||||
|
inkscape:cy="8"
|
||||||
|
inkscape:window-x="1405"
|
||||||
|
inkscape:window-y="650"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="layer1" />
|
||||||
|
<defs
|
||||||
|
id="defs5287" />
|
||||||
|
<metadata
|
||||||
|
id="metadata5290">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
id="layer1">
|
||||||
|
<circle
|
||||||
|
style="opacity:1;fill:#aa0000;fill-opacity:1;stroke:none;stroke-width:1.14285719;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="path821"
|
||||||
|
cx="11"
|
||||||
|
cy="11.000002"
|
||||||
|
r="4" />
|
||||||
|
<path
|
||||||
|
style="opacity:1;fill:#7f7f7f;fill-opacity:1;stroke:none;stroke-width:1.14285719;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 5,1 C 2.790861,1 1,2.790861 1,5 1,7.209139 2.790861,9 5,9 7.209139,9 9,7.209139 9,5 9,2.790861 7.209139,1 5,1 Z"
|
||||||
|
id="path821-7" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.0 KiB |
+77
-39
@@ -31,6 +31,7 @@ import generic.Unique;
|
|||||||
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest;
|
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest;
|
||||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.*;
|
import ghidra.app.plugin.core.debug.gui.DebuggerResources.*;
|
||||||
import ghidra.app.plugin.core.debug.gui.breakpoint.DebuggerBreakpointsProvider.LogicalBreakpointTableModel;
|
import ghidra.app.plugin.core.debug.gui.breakpoint.DebuggerBreakpointsProvider.LogicalBreakpointTableModel;
|
||||||
|
import ghidra.app.plugin.core.debug.gui.console.DebuggerConsolePlugin;
|
||||||
import ghidra.app.services.*;
|
import ghidra.app.services.*;
|
||||||
import ghidra.app.services.LogicalBreakpoint.Enablement;
|
import ghidra.app.services.LogicalBreakpoint.Enablement;
|
||||||
import ghidra.async.AsyncTestUtils;
|
import ghidra.async.AsyncTestUtils;
|
||||||
@@ -260,12 +261,12 @@ public class DebuggerBreakpointsProviderTest extends AbstractGhidraHeadedDebugge
|
|||||||
programManager.openProgram(program);
|
programManager.openProgram(program);
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
|
||||||
assertFalse(breakpointsProvider.actionEnableSelectedBreakpointsAction.isEnabled());
|
assertFalse(breakpointsProvider.actionEnableSelectedBreakpoints.isEnabled());
|
||||||
|
|
||||||
addStaticMemoryAndBreakpoint();
|
addStaticMemoryAndBreakpoint();
|
||||||
waitForDomainObject(program);
|
waitForDomainObject(program);
|
||||||
|
|
||||||
assertFalse(breakpointsProvider.actionEnableSelectedBreakpointsAction.isEnabled());
|
assertFalse(breakpointsProvider.actionEnableSelectedBreakpoints.isEnabled());
|
||||||
|
|
||||||
LogicalBreakpointRow row =
|
LogicalBreakpointRow row =
|
||||||
Unique.assertOne(breakpointsProvider.breakpointTableModel.getModelData());
|
Unique.assertOne(breakpointsProvider.breakpointTableModel.getModelData());
|
||||||
@@ -274,28 +275,28 @@ public class DebuggerBreakpointsProviderTest extends AbstractGhidraHeadedDebugge
|
|||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
|
||||||
assertEquals(Enablement.INEFFECTIVE_DISABLED, row.getEnablement());
|
assertEquals(Enablement.INEFFECTIVE_DISABLED, row.getEnablement());
|
||||||
assertTrue(breakpointsProvider.actionEnableSelectedBreakpointsAction.isEnabled());
|
assertTrue(breakpointsProvider.actionEnableSelectedBreakpoints.isEnabled());
|
||||||
|
|
||||||
performAction(breakpointsProvider.actionEnableSelectedBreakpointsAction);
|
performAction(breakpointsProvider.actionEnableSelectedBreakpoints);
|
||||||
|
|
||||||
assertEquals(Enablement.INEFFECTIVE_ENABLED, row.getEnablement());
|
assertEquals(Enablement.INEFFECTIVE_ENABLED, row.getEnablement());
|
||||||
assertTrue(breakpointsProvider.actionEnableSelectedBreakpointsAction.isEnabled());
|
assertTrue(breakpointsProvider.actionEnableSelectedBreakpoints.isEnabled());
|
||||||
|
|
||||||
breakpointsProvider.breakpointTable.clearSelection();
|
breakpointsProvider.breakpointTable.clearSelection();
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
|
||||||
assertFalse(breakpointsProvider.actionEnableSelectedBreakpointsAction.isEnabled());
|
assertFalse(breakpointsProvider.actionEnableSelectedBreakpoints.isEnabled());
|
||||||
|
|
||||||
breakpointsProvider.breakpointFilterPanel.setSelectedItem(row);
|
breakpointsProvider.breakpointFilterPanel.setSelectedItem(row);
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
|
||||||
assertTrue(breakpointsProvider.actionEnableSelectedBreakpointsAction.isEnabled());
|
assertTrue(breakpointsProvider.actionEnableSelectedBreakpoints.isEnabled());
|
||||||
|
|
||||||
// Bookmark part should actually be synchronous.
|
// Bookmark part should actually be synchronous.
|
||||||
waitOn(row.getLogicalBreakpoint().delete());
|
waitOn(row.getLogicalBreakpoint().delete());
|
||||||
waitForDomainObject(program);
|
waitForDomainObject(program);
|
||||||
|
|
||||||
assertFalse(breakpointsProvider.actionEnableSelectedBreakpointsAction.isEnabled());
|
assertFalse(breakpointsProvider.actionEnableSelectedBreakpoints.isEnabled());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -304,12 +305,12 @@ public class DebuggerBreakpointsProviderTest extends AbstractGhidraHeadedDebugge
|
|||||||
programManager.openProgram(program);
|
programManager.openProgram(program);
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
|
||||||
assertFalse(breakpointsProvider.actionEnableAllBreakpointsAction.isEnabled());
|
assertFalse(breakpointsProvider.actionEnableAllBreakpoints.isEnabled());
|
||||||
|
|
||||||
addStaticMemoryAndBreakpoint();
|
addStaticMemoryAndBreakpoint();
|
||||||
waitForDomainObject(program);
|
waitForDomainObject(program);
|
||||||
|
|
||||||
assertTrue(breakpointsProvider.actionEnableAllBreakpointsAction.isEnabled());
|
assertTrue(breakpointsProvider.actionEnableAllBreakpoints.isEnabled());
|
||||||
|
|
||||||
LogicalBreakpointRow row =
|
LogicalBreakpointRow row =
|
||||||
Unique.assertOne(breakpointsProvider.breakpointTableModel.getModelData());
|
Unique.assertOne(breakpointsProvider.breakpointTableModel.getModelData());
|
||||||
@@ -317,18 +318,18 @@ public class DebuggerBreakpointsProviderTest extends AbstractGhidraHeadedDebugge
|
|||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
|
||||||
assertEquals(Enablement.INEFFECTIVE_DISABLED, row.getEnablement());
|
assertEquals(Enablement.INEFFECTIVE_DISABLED, row.getEnablement());
|
||||||
assertTrue(breakpointsProvider.actionEnableAllBreakpointsAction.isEnabled());
|
assertTrue(breakpointsProvider.actionEnableAllBreakpoints.isEnabled());
|
||||||
|
|
||||||
performAction(breakpointsProvider.actionEnableAllBreakpointsAction);
|
performAction(breakpointsProvider.actionEnableAllBreakpoints);
|
||||||
|
|
||||||
assertEquals(Enablement.INEFFECTIVE_ENABLED, row.getEnablement());
|
assertEquals(Enablement.INEFFECTIVE_ENABLED, row.getEnablement());
|
||||||
assertTrue(breakpointsProvider.actionEnableAllBreakpointsAction.isEnabled());
|
assertTrue(breakpointsProvider.actionEnableAllBreakpoints.isEnabled());
|
||||||
|
|
||||||
// Bookmark part should actually be synchronous.
|
// Bookmark part should actually be synchronous.
|
||||||
row.getLogicalBreakpoint().delete().get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
|
row.getLogicalBreakpoint().delete().get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
|
||||||
waitForDomainObject(program);
|
waitForDomainObject(program);
|
||||||
|
|
||||||
assertFalse(breakpointsProvider.actionEnableAllBreakpointsAction.isEnabled());
|
assertFalse(breakpointsProvider.actionEnableAllBreakpoints.isEnabled());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -337,12 +338,12 @@ public class DebuggerBreakpointsProviderTest extends AbstractGhidraHeadedDebugge
|
|||||||
programManager.openProgram(program);
|
programManager.openProgram(program);
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
|
||||||
assertFalse(breakpointsProvider.actionDisableSelectedBreakpointsAction.isEnabled());
|
assertFalse(breakpointsProvider.actionDisableSelectedBreakpoints.isEnabled());
|
||||||
|
|
||||||
addStaticMemoryAndBreakpoint();
|
addStaticMemoryAndBreakpoint();
|
||||||
waitForDomainObject(program);
|
waitForDomainObject(program);
|
||||||
|
|
||||||
assertFalse(breakpointsProvider.actionDisableSelectedBreakpointsAction.isEnabled());
|
assertFalse(breakpointsProvider.actionDisableSelectedBreakpoints.isEnabled());
|
||||||
|
|
||||||
LogicalBreakpointRow row =
|
LogicalBreakpointRow row =
|
||||||
Unique.assertOne(breakpointsProvider.breakpointTableModel.getModelData());
|
Unique.assertOne(breakpointsProvider.breakpointTableModel.getModelData());
|
||||||
@@ -350,28 +351,28 @@ public class DebuggerBreakpointsProviderTest extends AbstractGhidraHeadedDebugge
|
|||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
|
||||||
assertEquals(Enablement.INEFFECTIVE_ENABLED, row.getEnablement());
|
assertEquals(Enablement.INEFFECTIVE_ENABLED, row.getEnablement());
|
||||||
assertTrue(breakpointsProvider.actionDisableSelectedBreakpointsAction.isEnabled());
|
assertTrue(breakpointsProvider.actionDisableSelectedBreakpoints.isEnabled());
|
||||||
|
|
||||||
performAction(breakpointsProvider.actionDisableSelectedBreakpointsAction);
|
performAction(breakpointsProvider.actionDisableSelectedBreakpoints);
|
||||||
|
|
||||||
assertEquals(Enablement.INEFFECTIVE_DISABLED, row.getEnablement());
|
assertEquals(Enablement.INEFFECTIVE_DISABLED, row.getEnablement());
|
||||||
assertTrue(breakpointsProvider.actionDisableSelectedBreakpointsAction.isEnabled());
|
assertTrue(breakpointsProvider.actionDisableSelectedBreakpoints.isEnabled());
|
||||||
|
|
||||||
breakpointsProvider.breakpointTable.clearSelection();
|
breakpointsProvider.breakpointTable.clearSelection();
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
|
||||||
assertFalse(breakpointsProvider.actionDisableSelectedBreakpointsAction.isEnabled());
|
assertFalse(breakpointsProvider.actionDisableSelectedBreakpoints.isEnabled());
|
||||||
|
|
||||||
breakpointsProvider.breakpointFilterPanel.setSelectedItem(row);
|
breakpointsProvider.breakpointFilterPanel.setSelectedItem(row);
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
|
||||||
assertTrue(breakpointsProvider.actionDisableSelectedBreakpointsAction.isEnabled());
|
assertTrue(breakpointsProvider.actionDisableSelectedBreakpoints.isEnabled());
|
||||||
|
|
||||||
// Bookmark part should actually be synchronous.
|
// Bookmark part should actually be synchronous.
|
||||||
waitOn(row.getLogicalBreakpoint().delete());
|
waitOn(row.getLogicalBreakpoint().delete());
|
||||||
waitForDomainObject(program);
|
waitForDomainObject(program);
|
||||||
|
|
||||||
assertFalse(breakpointsProvider.actionDisableSelectedBreakpointsAction.isEnabled());
|
assertFalse(breakpointsProvider.actionDisableSelectedBreakpoints.isEnabled());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -380,27 +381,27 @@ public class DebuggerBreakpointsProviderTest extends AbstractGhidraHeadedDebugge
|
|||||||
programManager.openProgram(program);
|
programManager.openProgram(program);
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
|
||||||
assertFalse(breakpointsProvider.actionDisableAllBreakpointsAction.isEnabled());
|
assertFalse(breakpointsProvider.actionDisableAllBreakpoints.isEnabled());
|
||||||
|
|
||||||
addStaticMemoryAndBreakpoint();
|
addStaticMemoryAndBreakpoint();
|
||||||
waitForDomainObject(program);
|
waitForDomainObject(program);
|
||||||
|
|
||||||
assertTrue(breakpointsProvider.actionDisableAllBreakpointsAction.isEnabled());
|
assertTrue(breakpointsProvider.actionDisableAllBreakpoints.isEnabled());
|
||||||
LogicalBreakpointRow row =
|
LogicalBreakpointRow row =
|
||||||
Unique.assertOne(breakpointsProvider.breakpointTableModel.getModelData());
|
Unique.assertOne(breakpointsProvider.breakpointTableModel.getModelData());
|
||||||
assertEquals(Enablement.INEFFECTIVE_ENABLED, row.getEnablement());
|
assertEquals(Enablement.INEFFECTIVE_ENABLED, row.getEnablement());
|
||||||
assertTrue(breakpointsProvider.actionDisableAllBreakpointsAction.isEnabled());
|
assertTrue(breakpointsProvider.actionDisableAllBreakpoints.isEnabled());
|
||||||
|
|
||||||
performAction(breakpointsProvider.actionDisableAllBreakpointsAction);
|
performAction(breakpointsProvider.actionDisableAllBreakpoints);
|
||||||
|
|
||||||
assertEquals(Enablement.INEFFECTIVE_DISABLED, row.getEnablement());
|
assertEquals(Enablement.INEFFECTIVE_DISABLED, row.getEnablement());
|
||||||
assertTrue(breakpointsProvider.actionDisableAllBreakpointsAction.isEnabled());
|
assertTrue(breakpointsProvider.actionDisableAllBreakpoints.isEnabled());
|
||||||
|
|
||||||
// Bookmark part should actually be synchronous.
|
// Bookmark part should actually be synchronous.
|
||||||
row.getLogicalBreakpoint().delete().get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
|
row.getLogicalBreakpoint().delete().get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
|
||||||
waitForDomainObject(program);
|
waitForDomainObject(program);
|
||||||
|
|
||||||
assertFalse(breakpointsProvider.actionDisableAllBreakpointsAction.isEnabled());
|
assertFalse(breakpointsProvider.actionDisableAllBreakpoints.isEnabled());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -409,34 +410,34 @@ public class DebuggerBreakpointsProviderTest extends AbstractGhidraHeadedDebugge
|
|||||||
programManager.openProgram(program);
|
programManager.openProgram(program);
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
|
||||||
assertFalse(breakpointsProvider.actionClearSelectedBreakpointsAction.isEnabled());
|
assertFalse(breakpointsProvider.actionClearSelectedBreakpoints.isEnabled());
|
||||||
|
|
||||||
addStaticMemoryAndBreakpoint();
|
addStaticMemoryAndBreakpoint();
|
||||||
waitForDomainObject(program);
|
waitForDomainObject(program);
|
||||||
|
|
||||||
assertFalse(breakpointsProvider.actionClearSelectedBreakpointsAction.isEnabled());
|
assertFalse(breakpointsProvider.actionClearSelectedBreakpoints.isEnabled());
|
||||||
|
|
||||||
LogicalBreakpointRow row =
|
LogicalBreakpointRow row =
|
||||||
Unique.assertOne(breakpointsProvider.breakpointTableModel.getModelData());
|
Unique.assertOne(breakpointsProvider.breakpointTableModel.getModelData());
|
||||||
breakpointsProvider.breakpointFilterPanel.setSelectedItem(row);
|
breakpointsProvider.breakpointFilterPanel.setSelectedItem(row);
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
|
||||||
assertTrue(breakpointsProvider.actionClearSelectedBreakpointsAction.isEnabled());
|
assertTrue(breakpointsProvider.actionClearSelectedBreakpoints.isEnabled());
|
||||||
|
|
||||||
breakpointsProvider.breakpointTable.clearSelection();
|
breakpointsProvider.breakpointTable.clearSelection();
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
|
||||||
assertFalse(breakpointsProvider.actionClearSelectedBreakpointsAction.isEnabled());
|
assertFalse(breakpointsProvider.actionClearSelectedBreakpoints.isEnabled());
|
||||||
|
|
||||||
breakpointsProvider.breakpointFilterPanel.setSelectedItem(row);
|
breakpointsProvider.breakpointFilterPanel.setSelectedItem(row);
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
|
||||||
assertTrue(breakpointsProvider.actionClearSelectedBreakpointsAction.isEnabled());
|
assertTrue(breakpointsProvider.actionClearSelectedBreakpoints.isEnabled());
|
||||||
|
|
||||||
performAction(breakpointsProvider.actionClearSelectedBreakpointsAction);
|
performAction(breakpointsProvider.actionClearSelectedBreakpoints);
|
||||||
|
|
||||||
assertProviderEmpty();
|
assertProviderEmpty();
|
||||||
assertFalse(breakpointsProvider.actionClearSelectedBreakpointsAction.isEnabled());
|
assertFalse(breakpointsProvider.actionClearSelectedBreakpoints.isEnabled());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -445,17 +446,54 @@ public class DebuggerBreakpointsProviderTest extends AbstractGhidraHeadedDebugge
|
|||||||
programManager.openProgram(program);
|
programManager.openProgram(program);
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
|
||||||
assertFalse(breakpointsProvider.actionClearAllBreakpointsAction.isEnabled());
|
assertFalse(breakpointsProvider.actionClearAllBreakpoints.isEnabled());
|
||||||
|
|
||||||
addStaticMemoryAndBreakpoint();
|
addStaticMemoryAndBreakpoint();
|
||||||
waitForDomainObject(program);
|
waitForDomainObject(program);
|
||||||
|
|
||||||
assertTrue(breakpointsProvider.actionClearAllBreakpointsAction.isEnabled());
|
assertTrue(breakpointsProvider.actionClearAllBreakpoints.isEnabled());
|
||||||
|
|
||||||
performAction(breakpointsProvider.actionClearAllBreakpointsAction);
|
performAction(breakpointsProvider.actionClearAllBreakpoints);
|
||||||
|
|
||||||
assertProviderEmpty();
|
assertProviderEmpty();
|
||||||
assertFalse(breakpointsProvider.actionClearAllBreakpointsAction.isEnabled());
|
assertFalse(breakpointsProvider.actionClearAllBreakpoints.isEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testActionMakeBreakpointsEffective() throws Exception {
|
||||||
|
DebuggerConsolePlugin consolePlugin = addPlugin(tool, DebuggerConsolePlugin.class);
|
||||||
|
|
||||||
|
createTestModel();
|
||||||
|
mb.createTestProcessesAndThreads();
|
||||||
|
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
|
||||||
|
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||||
|
Trace trace = recorder.getTrace();
|
||||||
|
createProgramFromTrace(trace);
|
||||||
|
intoProject(trace);
|
||||||
|
intoProject(program);
|
||||||
|
|
||||||
|
assertFalse(breakpointsProvider.actionMakeBreakpointsEffective.isEnabled());
|
||||||
|
programManager.openProgram(program);
|
||||||
|
assertFalse(breakpointsProvider.actionMakeBreakpointsEffective.isEnabled());
|
||||||
|
traceManager.openTrace(trace);
|
||||||
|
assertFalse(breakpointsProvider.actionMakeBreakpointsEffective.isEnabled());
|
||||||
|
addStaticMemoryAndBreakpoint();
|
||||||
|
assertFalse(breakpointsProvider.actionMakeBreakpointsEffective.isEnabled());
|
||||||
|
|
||||||
|
addMapping(trace, program);
|
||||||
|
waitForPass(() -> {
|
||||||
|
assertTrue(breakpointsProvider.actionMakeBreakpointsEffective.isEnabled());
|
||||||
|
assertEquals(1,
|
||||||
|
consolePlugin.getRowCount(DebuggerMakeBreakpointsEffectiveActionContext.class));
|
||||||
|
});
|
||||||
|
|
||||||
|
performAction(breakpointsProvider.actionMakeBreakpointsEffective);
|
||||||
|
|
||||||
|
waitForPass(() -> {
|
||||||
|
assertFalse(breakpointsProvider.actionMakeBreakpointsEffective.isEnabled());
|
||||||
|
assertEquals(0,
|
||||||
|
consolePlugin.getRowCount(DebuggerMakeBreakpointsEffectiveActionContext.class));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
+130
@@ -19,6 +19,7 @@ import static ghidra.lifecycle.Unfinished.TODO;
|
|||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
import java.io.IOException;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@@ -37,10 +38,13 @@ import ghidra.app.plugin.core.debug.gui.DebuggerResources;
|
|||||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractFollowsCurrentThreadAction;
|
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractFollowsCurrentThreadAction;
|
||||||
import ghidra.app.plugin.core.debug.gui.action.*;
|
import ghidra.app.plugin.core.debug.gui.action.*;
|
||||||
import ghidra.app.plugin.core.debug.gui.console.DebuggerConsolePlugin;
|
import ghidra.app.plugin.core.debug.gui.console.DebuggerConsolePlugin;
|
||||||
|
import ghidra.app.plugin.core.debug.gui.console.DebuggerConsoleProvider.BoundAction;
|
||||||
|
import ghidra.app.plugin.core.debug.gui.console.DebuggerConsoleProvider.LogRow;
|
||||||
import ghidra.app.plugin.core.debug.gui.modules.DebuggerMissingModuleActionContext;
|
import ghidra.app.plugin.core.debug.gui.modules.DebuggerMissingModuleActionContext;
|
||||||
import ghidra.app.services.*;
|
import ghidra.app.services.*;
|
||||||
import ghidra.app.util.viewer.listingpanel.ListingPanel;
|
import ghidra.app.util.viewer.listingpanel.ListingPanel;
|
||||||
import ghidra.async.SwingExecutorService;
|
import ghidra.async.SwingExecutorService;
|
||||||
|
import ghidra.framework.model.*;
|
||||||
import ghidra.plugin.importer.ImporterPlugin;
|
import ghidra.plugin.importer.ImporterPlugin;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.lang.Register;
|
import ghidra.program.model.lang.Register;
|
||||||
@@ -57,6 +61,9 @@ import ghidra.trace.model.modules.TraceModule;
|
|||||||
import ghidra.trace.model.thread.TraceThread;
|
import ghidra.trace.model.thread.TraceThread;
|
||||||
import ghidra.trace.model.time.TraceSnapshot;
|
import ghidra.trace.model.time.TraceSnapshot;
|
||||||
import ghidra.util.database.UndoableTransaction;
|
import ghidra.util.database.UndoableTransaction;
|
||||||
|
import ghidra.util.exception.CancelledException;
|
||||||
|
import ghidra.util.exception.VersionException;
|
||||||
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUITest {
|
public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUITest {
|
||||||
static LocationTrackingSpec getLocationTrackingSpec(String name) {
|
static LocationTrackingSpec getLocationTrackingSpec(String name) {
|
||||||
@@ -1351,4 +1358,127 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
|||||||
|
|
||||||
assertEquals(tb.addr(0x00404321), listingProvider.getLocation().getAddress());
|
assertEquals(tb.addr(0x00404321), listingProvider.getLocation().getAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSyncToStaticListingOpensModule() throws Exception {
|
||||||
|
DebuggerConsolePlugin consolePlugin = addPlugin(tool, DebuggerConsolePlugin.class);
|
||||||
|
|
||||||
|
createAndOpenTrace();
|
||||||
|
createAndOpenProgramFromTrace();
|
||||||
|
intoProject(tb.trace);
|
||||||
|
intoProject(program);
|
||||||
|
|
||||||
|
AddressSpace ss = program.getAddressFactory().getDefaultAddressSpace();
|
||||||
|
try (UndoableTransaction tid = UndoableTransaction.start(program, "Add block", true)) {
|
||||||
|
program.getMemory()
|
||||||
|
.createInitializedBlock(".text", ss.getAddress(0x00600000), 0x10000, (byte) 0,
|
||||||
|
monitor, false);
|
||||||
|
}
|
||||||
|
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||||
|
DBTraceMemoryManager memory = tb.trace.getMemoryManager();
|
||||||
|
memory.addRegion("exe:.text", Range.atLeast(0L), tb.range(0x00400000, 0x0040ffff),
|
||||||
|
TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
|
||||||
|
TraceLocation from =
|
||||||
|
new DefaultTraceLocation(tb.trace, null, Range.atLeast(0L), tb.addr(0x00400000));
|
||||||
|
ProgramLocation to = new ProgramLocation(program, ss.getAddress(0x00600000));
|
||||||
|
mappingService.addMapping(from, to, 0x8000, false);
|
||||||
|
}
|
||||||
|
waitForProgram(program);
|
||||||
|
waitForDomainObject(tb.trace);
|
||||||
|
|
||||||
|
programManager.closeAllPrograms(true);
|
||||||
|
waitForPass(() -> assertEquals(0, programManager.getAllOpenPrograms().length));
|
||||||
|
|
||||||
|
traceManager.activateTrace(tb.trace);
|
||||||
|
waitForSwing();
|
||||||
|
|
||||||
|
listingProvider.getListingPanel()
|
||||||
|
.setCursorPosition(
|
||||||
|
new ProgramLocation(tb.trace.getProgramView(), tb.addr(0x00401234)),
|
||||||
|
EventTrigger.GUI_ACTION);
|
||||||
|
waitForSwing();
|
||||||
|
|
||||||
|
waitForPass(() -> assertEquals(1, programManager.getAllOpenPrograms().length));
|
||||||
|
assertTrue(java.util.List.of(programManager.getAllOpenPrograms()).contains(program));
|
||||||
|
|
||||||
|
assertFalse(consolePlugin
|
||||||
|
.logContains(new DebuggerOpenProgramActionContext(program.getDomainFile())));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSyncToStaticLogsRecoverableProgram() throws Exception {
|
||||||
|
DebuggerConsolePlugin consolePlugin = addPlugin(tool, DebuggerConsolePlugin.class);
|
||||||
|
|
||||||
|
TestDummyDomainFolder root = new TestDummyDomainFolder(null, "root");
|
||||||
|
DomainFile df = new TestDummyDomainFile(root, "dummyFile") {
|
||||||
|
@Override
|
||||||
|
public boolean canRecover() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
listingProvider.doTryOpenProgram(df, DomainFile.DEFAULT_VERSION,
|
||||||
|
ProgramManager.OPEN_CURRENT);
|
||||||
|
waitForSwing();
|
||||||
|
|
||||||
|
DebuggerOpenProgramActionContext ctx = new DebuggerOpenProgramActionContext(df);
|
||||||
|
waitForPass(() -> assertTrue(consolePlugin.logContains(ctx)));
|
||||||
|
assertTrue(consolePlugin.getLogRow(ctx).getMessage().contains("recovery"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSyncToStaticLogsUpgradeableProgram() throws Exception {
|
||||||
|
DebuggerConsolePlugin consolePlugin = addPlugin(tool, DebuggerConsolePlugin.class);
|
||||||
|
|
||||||
|
TestDummyDomainFolder root = new TestDummyDomainFolder(null, "root");
|
||||||
|
DomainFile df = new TestDummyDomainFile(root, "dummyFile") {
|
||||||
|
@Override
|
||||||
|
public boolean canRecover() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DomainObject getDomainObject(Object consumer, boolean okToUpgrade,
|
||||||
|
boolean okToRecover, TaskMonitor monitor)
|
||||||
|
throws VersionException, IOException, CancelledException {
|
||||||
|
throw new VersionException();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
listingProvider.doTryOpenProgram(df, DomainFile.DEFAULT_VERSION,
|
||||||
|
ProgramManager.OPEN_CURRENT);
|
||||||
|
waitForSwing();
|
||||||
|
|
||||||
|
DebuggerOpenProgramActionContext ctx = new DebuggerOpenProgramActionContext(df);
|
||||||
|
waitForPass(() -> assertTrue(consolePlugin.logContains(ctx)));
|
||||||
|
assertTrue(consolePlugin.getLogRow(ctx).getMessage().contains("version"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testActionOpenProgram() throws Exception {
|
||||||
|
DebuggerConsolePlugin consolePlugin = addPlugin(tool, DebuggerConsolePlugin.class);
|
||||||
|
|
||||||
|
createProgram();
|
||||||
|
intoProject(program);
|
||||||
|
|
||||||
|
assertEquals(0, programManager.getAllOpenPrograms().length);
|
||||||
|
|
||||||
|
DebuggerOpenProgramActionContext ctx =
|
||||||
|
new DebuggerOpenProgramActionContext(program.getDomainFile());
|
||||||
|
consolePlugin.log(DebuggerResources.ICON_MODULES, "Test resolution", ctx);
|
||||||
|
waitForSwing();
|
||||||
|
|
||||||
|
LogRow row = consolePlugin.getLogRow(ctx);
|
||||||
|
assertEquals(1, row.getActions().size());
|
||||||
|
BoundAction boundAction = row.getActions().get(0);
|
||||||
|
assertEquals(listingProvider.actionOpenProgram, boundAction.action);
|
||||||
|
|
||||||
|
boundAction.perform();
|
||||||
|
waitForSwing();
|
||||||
|
|
||||||
|
waitForPass(() -> assertEquals(1, programManager.getAllOpenPrograms().length));
|
||||||
|
assertTrue(java.util.List.of(programManager.getAllOpenPrograms()).contains(program));
|
||||||
|
// TODO: Test this independent of this particular action?
|
||||||
|
assertNull(consolePlugin.getLogRow(ctx));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -51,6 +51,7 @@ public class IconButtonTableCellEditor<R> extends AbstractCellEditor
|
|||||||
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected,
|
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected,
|
||||||
int row, int column) {
|
int row, int column) {
|
||||||
this.row = filterPanel.getRowObject(row);
|
this.row = filterPanel.getRowObject(row);
|
||||||
|
button.setToolTipText(value.toString());
|
||||||
return button;
|
return button;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+9
-5
@@ -15,27 +15,31 @@
|
|||||||
*/
|
*/
|
||||||
package docking.widgets.table;
|
package docking.widgets.table;
|
||||||
|
|
||||||
import java.awt.Component;
|
import java.awt.*;
|
||||||
import java.awt.Dimension;
|
|
||||||
|
|
||||||
import javax.swing.Icon;
|
import javax.swing.*;
|
||||||
import javax.swing.JButton;
|
|
||||||
|
|
||||||
import ghidra.docking.settings.Settings;
|
import ghidra.docking.settings.Settings;
|
||||||
import ghidra.util.table.column.AbstractGhidraColumnRenderer;
|
import ghidra.util.table.column.AbstractGhidraColumnRenderer;
|
||||||
|
|
||||||
public class IconButtonTableCellRenderer
|
public class IconButtonTableCellRenderer
|
||||||
extends AbstractGhidraColumnRenderer<String> {
|
extends AbstractGhidraColumnRenderer<String> {
|
||||||
|
protected final JPanel panel = new JPanel();
|
||||||
protected final JButton button = new JButton("");
|
protected final JButton button = new JButton("");
|
||||||
|
|
||||||
public IconButtonTableCellRenderer(Icon icon, int buttonSize) {
|
public IconButtonTableCellRenderer(Icon icon, int buttonSize) {
|
||||||
button.setIcon(icon);
|
button.setIcon(icon);
|
||||||
button.setMinimumSize(new Dimension(buttonSize, buttonSize));
|
button.setMinimumSize(new Dimension(buttonSize, buttonSize));
|
||||||
|
panel.setMinimumSize(new Dimension(buttonSize, buttonSize));
|
||||||
|
panel.setLayout(new BorderLayout());
|
||||||
|
panel.add(button);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Component getTableCellRendererComponent(GTableCellRenderingData data) {
|
public Component getTableCellRendererComponent(GTableCellRenderingData data) {
|
||||||
return button;
|
super.getTableCellRendererComponent(data); // Waste, but sets background
|
||||||
|
panel.setBackground(getBackground());
|
||||||
|
return panel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -0,0 +1,94 @@
|
|||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.util;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some utilities for manipulating a {@link ByteBuffer}
|
||||||
|
*/
|
||||||
|
public interface ByteBufferUtils {
|
||||||
|
/**
|
||||||
|
* Resize a write-mode buffer
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This preserves the buffer contents
|
||||||
|
*
|
||||||
|
* @param buf the buffer
|
||||||
|
* @param capacity the new capacity, greater or equal to the buffer's limit
|
||||||
|
* @return the new buffer
|
||||||
|
*/
|
||||||
|
public static ByteBuffer resize(ByteBuffer buf, int capacity) {
|
||||||
|
if (capacity < buf.limit()) {
|
||||||
|
throw new IllegalArgumentException("New capacity must fit current contents");
|
||||||
|
}
|
||||||
|
buf.flip();
|
||||||
|
ByteBuffer resized = ByteBuffer.allocate(capacity);
|
||||||
|
resized.put(buf);
|
||||||
|
return resized;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resize a write-mode buffer to twice its current capacity
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This preserves the buffer contents
|
||||||
|
*
|
||||||
|
* @param buf the buffer
|
||||||
|
* @return the new buffer
|
||||||
|
*/
|
||||||
|
public static ByteBuffer upsize(ByteBuffer buf) {
|
||||||
|
return resize(buf, buf.capacity() * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks for equality, with a mask applied
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This considers the entire contents of both buffers without regard for position or limit. Both
|
||||||
|
* buffers must have equal capacities to be considered equal. The mask, if given, must have
|
||||||
|
* capacity equal to that of the first buffer {@code a} or an exception is thrown.
|
||||||
|
*
|
||||||
|
* @param mask a buffer containing the mask, or null to match all bytes exactly
|
||||||
|
* @param a the first buffer
|
||||||
|
* @param b the second buffer
|
||||||
|
* @return true if matches, false otherwise
|
||||||
|
* @throws IllegalArgumentException if {@code mask} and {@code a} have unequal capacities
|
||||||
|
*/
|
||||||
|
public static boolean maskedEquals(ByteBuffer mask, ByteBuffer a, ByteBuffer b) {
|
||||||
|
int len = a.capacity();
|
||||||
|
if (mask != null && mask.capacity() != len) {
|
||||||
|
throw new IllegalArgumentException("mask and a must have equal capacities");
|
||||||
|
}
|
||||||
|
if (len != a.capacity()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (mask != null) {
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
if ((a.get(i) & mask.get(i)) != (b.get(i) & mask.get(i))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
if (a.get(i) != b.get(i)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user