mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
GP-4636: Use Debug Console for initial mapping failure.
This commit is contained in:
parent
35434613b8
commit
1db04f8c71
8 changed files with 435 additions and 58 deletions
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.plugin.core.debug.gui.modules;
|
||||
package ghidra.debug.api.modules;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
|
@ -43,10 +43,9 @@ public class DebuggerMissingModuleActionContext extends DefaultActionContext {
|
|||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof DebuggerMissingModuleActionContext)) {
|
||||
if (!(obj instanceof DebuggerMissingModuleActionContext that)) {
|
||||
return false;
|
||||
}
|
||||
DebuggerMissingModuleActionContext that = (DebuggerMissingModuleActionContext) obj;
|
||||
if (!this.module.equals(that.module)) {
|
||||
return false;
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
/* ###
|
||||
* 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.debug.api.modules;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import docking.DefaultActionContext;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.InstructionIterator;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.trace.model.Trace;
|
||||
|
||||
public class DebuggerMissingProgramActionContext extends DefaultActionContext {
|
||||
|
||||
public static Address getMappingProbeAddress(Program program) {
|
||||
if (program == null) {
|
||||
return null;
|
||||
}
|
||||
AddressIterator eepi = program.getSymbolTable().getExternalEntryPointIterator();
|
||||
if (eepi.hasNext()) {
|
||||
return eepi.next();
|
||||
}
|
||||
InstructionIterator ii = program.getListing().getInstructions(true);
|
||||
if (ii.hasNext()) {
|
||||
return ii.next().getAddress();
|
||||
}
|
||||
AddressSetView es = program.getMemory().getExecuteSet();
|
||||
if (!es.isEmpty()) {
|
||||
return es.getMinAddress();
|
||||
}
|
||||
if (!program.getMemory().isEmpty()) {
|
||||
return program.getMinAddress();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private final Trace trace;
|
||||
private final Program program;
|
||||
private final int hashCode;
|
||||
|
||||
private Address probe;
|
||||
|
||||
public DebuggerMissingProgramActionContext(Trace trace, Program program) {
|
||||
this.trace = Objects.requireNonNull(trace);
|
||||
this.program = Objects.requireNonNull(program);
|
||||
this.hashCode = Objects.hash(getClass(), trace, program);
|
||||
}
|
||||
|
||||
public Trace getTrace() {
|
||||
return trace;
|
||||
}
|
||||
|
||||
public Program getProgram() {
|
||||
return program;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof DebuggerMissingProgramActionContext that)) {
|
||||
return false;
|
||||
}
|
||||
if (!this.trace.equals(that.trace)) {
|
||||
return false;
|
||||
}
|
||||
if (!this.program.equals(that.program)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public Address getMappingProbeAddress() {
|
||||
if (probe == null) {
|
||||
probe = getMappingProbeAddress(program);
|
||||
}
|
||||
return probe;
|
||||
}
|
||||
}
|
|
@ -43,16 +43,14 @@ import ghidra.debug.api.tracermi.*;
|
|||
import ghidra.framework.options.SaveState;
|
||||
import ghidra.framework.plugintool.AutoConfigState.ConfigStateField;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.InstructionIterator;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.util.ProgramLocation;
|
||||
import ghidra.pty.*;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.TraceLocation;
|
||||
import ghidra.trace.model.modules.TraceModule;
|
||||
import ghidra.util.MessageType;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.Task;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
@ -169,25 +167,8 @@ public abstract class AbstractTraceRmiLaunchOffer implements TraceRmiLaunchOffer
|
|||
}
|
||||
|
||||
protected Address getMappingProbeAddress() {
|
||||
if (program == null) {
|
||||
return null;
|
||||
}
|
||||
AddressIterator eepi = program.getSymbolTable().getExternalEntryPointIterator();
|
||||
if (eepi.hasNext()) {
|
||||
return eepi.next();
|
||||
}
|
||||
InstructionIterator ii = program.getListing().getInstructions(true);
|
||||
if (ii.hasNext()) {
|
||||
return ii.next().getAddress();
|
||||
}
|
||||
AddressSetView es = program.getMemory().getExecuteSet();
|
||||
if (!es.isEmpty()) {
|
||||
return es.getMinAddress();
|
||||
}
|
||||
if (!program.getMemory().isEmpty()) {
|
||||
return program.getMinAddress();
|
||||
}
|
||||
return null; // I guess we won't wait for a mapping, then
|
||||
// May be null, in which case, we won't wait for a mapping
|
||||
return DebuggerMissingProgramActionContext.getMappingProbeAddress(program);
|
||||
}
|
||||
|
||||
protected CompletableFuture<Void> listenForMapping(DebuggerStaticMappingService mappingService,
|
||||
|
@ -641,6 +622,22 @@ public abstract class AbstractTraceRmiLaunchOffer implements TraceRmiLaunchOffer
|
|||
}
|
||||
return new LaunchResult(program, Map.of(), null, null, null, lastExc);
|
||||
}
|
||||
catch (NoStaticMappingException e) {
|
||||
DebuggerConsoleService consoleService =
|
||||
tool.getService(DebuggerConsoleService.class);
|
||||
if (consoleService == null) {
|
||||
Msg.error(this, e.getMessage());
|
||||
}
|
||||
else {
|
||||
consoleService.log(DebuggerResources.ICON_MODULES,
|
||||
"<html>The trace <b>%s</b> has no mapping to its program <b>%s</b></html>"
|
||||
.formatted(
|
||||
HTMLUtilities.escapeHTML(trace.getDomainFile().getName()),
|
||||
HTMLUtilities.escapeHTML(program.getDomainFile().getName())),
|
||||
new DebuggerMissingProgramActionContext(trace, program));
|
||||
}
|
||||
return new LaunchResult(program, sessions, acceptor, connection, trace, e);
|
||||
}
|
||||
catch (Exception e) {
|
||||
DebuggerConsoleService consoleService =
|
||||
tool.getService(DebuggerConsoleService.class);
|
||||
|
|
|
@ -152,14 +152,51 @@
|
|||
<H3><A name="import_missing_module"></A><IMG alt="" src="icon.debugger.import"> Import Missing
|
||||
Module</H3>
|
||||
|
||||
<P>This action is offered to resolve a "missing module" console message. It is equivalent to <A
|
||||
href="#import_from_fs">Import From File System</A> on the missing module.</P>
|
||||
<P>This action is offered to resolve a "missing module" console message. Such a message is
|
||||
reported in the <A href="help/topics/DebuggerConsolePlugin/DebuggerConsolePlugin.html">Debug
|
||||
Console</A> when the cursor in the <A href=
|
||||
"help/topics/DebuggerListingPlugin/DebuggerListingPlugin.html">Dynamic Listing</A> cannot be
|
||||
synchronized to the static listing for lack of a module mapping. This action is equivalent to
|
||||
<A href="#import_from_fs">Import From File System</A> on the missing module.</P>
|
||||
|
||||
<H3><A name="map_missing_module"></A><IMG alt="" src="icon.debugger.map.modules"> Map Missing
|
||||
Module</H3>
|
||||
|
||||
<P>This action is offered to resolve a "missing module" console message. It is equivalent to <A
|
||||
href="#map_module_to">Map Module To</A> on the missing module.</P>
|
||||
<P>This action is offered to resolve a "missing module" console message. Such a message is
|
||||
reported in the <A href="help/topics/DebuggerConsolePlugin/DebuggerConsolePlugin.html">Debug
|
||||
Console</A> when the cursor in the <A href=
|
||||
"help/topics/DebuggerListingPlugin/DebuggerListingPlugin.html">Dynamic Listing</A> cannot be
|
||||
synchronized to the static listing for lack of a module mapping. This action is equivalent to
|
||||
<A href="#map_module_to">Map Module To</A> on the missing module.</P>
|
||||
|
||||
<H3><A name="map_missing_program_retry"></A><IMG alt="" src="icon.debugger.map.auto"> Retry Map
|
||||
Missing Program</H3>
|
||||
|
||||
<P>This action is offered to resolve a "missing program" console message. Such a message is
|
||||
reported in the <A href="help/topics/DebuggerConsolePlugin/DebuggerConsolePlugin.html">Debug
|
||||
Console</A> when the launcher fails to map the current program database to the launched trace.
|
||||
This action is equivalent to <A href="#map_modules">Map Modules</A>, but considering only the
|
||||
missing program and launched trace.</P>
|
||||
|
||||
<H3><A name="map_missing_program_current"></A><IMG alt="" src="icon.debugger.map.modules"> Map
|
||||
Missing Program to Current Module</H3>
|
||||
|
||||
<P>This action is offered to resolve a "missing program" console message. Such a message is
|
||||
reported in the <A href="help/topics/DebuggerConsolePlugin/DebuggerConsolePlugin.html">Debug
|
||||
Console</A> when the launcher fails to map the current program database to the launched trace.
|
||||
This action is only available when the current trace is the launched trace. It finds the module
|
||||
containing the cursor in the <A href=
|
||||
"help/topics/DebuggerListingPlugin/DebuggerListingPlugin.html">Dynamic Listing</A> and proposes
|
||||
to map it to the missing program.</P>
|
||||
|
||||
<H3><A name="map_missing_program_identically"></A><IMG alt="" src=
|
||||
"icon.debugger.map.identically"> Map Missing Program Identically</H3>
|
||||
|
||||
<P>This action is offered to resolve a "missing program" console message. Such a message is
|
||||
reported in the <A href="help/topics/DebuggerConsolePlugin/DebuggerConsolePlugin.html">Debug
|
||||
Console</A> when the launcher fails to map the current program database to the launched trace.
|
||||
This action is equivalent to <A href="#map_identically">Map Identically</A>, but for the
|
||||
missing program and launched trace.</P>
|
||||
|
||||
<H3><A name="show_sections_table"></A><IMG alt="" src="icon.debugger.modules.table.sections">
|
||||
Show Sections Table</H3>
|
||||
|
@ -179,12 +216,15 @@
|
|||
Addresses</H3>
|
||||
|
||||
<P>This action is available when at least one module or section is selected. It selects all
|
||||
addresses in the dynamic listing contained by the selected modules or sections.</P>
|
||||
addresses in the <A href="help/topics/DebuggerListingPlugin/DebuggerListingPlugin.html">Dynamic
|
||||
Listing</A> contained by the selected modules or sections.</P>
|
||||
|
||||
<H3><A name="select_rows"></A><IMG alt="" src="icon.debugger.select.rows"> Select Rows</H3>
|
||||
|
||||
<P>This action is available when the dynamic listing's cursor is at a valid location. It
|
||||
selects the module and section, if applicable, containing that cursor. If the dynamic listing
|
||||
has a selection, it selects all modules and sections intersecting that selection.</P>
|
||||
<P>This action is available when the <A href=
|
||||
"help/topics/DebuggerListingPlugin/DebuggerListingPlugin.html">Dynamic Listing</A>'s cursor is
|
||||
at a valid location. It selects the module and section, if applicable, containing that cursor.
|
||||
If the dynamic listing has a selection, it selects all modules and sections intersecting that
|
||||
selection.</P>
|
||||
</BODY>
|
||||
</HTML>
|
||||
|
|
|
@ -56,7 +56,6 @@ import ghidra.app.plugin.core.debug.gui.DebuggerResources;
|
|||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.FollowsCurrentThreadAction;
|
||||
import ghidra.app.plugin.core.debug.gui.DebuggerResources.OpenProgramAction;
|
||||
import ghidra.app.plugin.core.debug.gui.action.*;
|
||||
import ghidra.app.plugin.core.debug.gui.modules.DebuggerMissingModuleActionContext;
|
||||
import ghidra.app.plugin.core.debug.gui.thread.DebuggerTraceFileActionContext;
|
||||
import ghidra.app.plugin.core.debug.gui.trace.DebuggerTraceTabPanel;
|
||||
import ghidra.app.plugin.core.debug.utils.ProgramLocationUtils;
|
||||
|
@ -74,6 +73,7 @@ import ghidra.debug.api.action.GoToInput;
|
|||
import ghidra.debug.api.action.LocationTrackingSpec;
|
||||
import ghidra.debug.api.control.ControlMode;
|
||||
import ghidra.debug.api.listing.MultiBlendedListingBackgroundColorModel;
|
||||
import ghidra.debug.api.modules.DebuggerMissingModuleActionContext;
|
||||
import ghidra.debug.api.modules.DebuggerStaticMappingChangeListener;
|
||||
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
|
||||
import ghidra.framework.model.DomainFile;
|
||||
|
|
|
@ -20,6 +20,7 @@ import ghidra.app.plugin.PluginCategoryNames;
|
|||
import ghidra.app.plugin.core.debug.AbstractDebuggerPlugin;
|
||||
import ghidra.app.plugin.core.debug.DebuggerPluginPackage;
|
||||
import ghidra.app.plugin.core.debug.event.TraceActivatedPluginEvent;
|
||||
import ghidra.app.plugin.core.debug.event.TraceClosedPluginEvent;
|
||||
import ghidra.app.services.*;
|
||||
import ghidra.framework.options.SaveState;
|
||||
import ghidra.framework.plugintool.*;
|
||||
|
@ -37,6 +38,7 @@ import ghidra.framework.plugintool.util.PluginStatus;
|
|||
ProgramLocationPluginEvent.class,
|
||||
ProgramClosedPluginEvent.class,
|
||||
TraceActivatedPluginEvent.class,
|
||||
TraceClosedPluginEvent.class,
|
||||
},
|
||||
servicesRequired = {
|
||||
DebuggerStaticMappingService.class,
|
||||
|
@ -81,6 +83,9 @@ public class DebuggerModulesPlugin extends AbstractDebuggerPlugin {
|
|||
else if (event instanceof TraceActivatedPluginEvent ev) {
|
||||
provider.coordinatesActivated(ev.getActiveCoordinates());
|
||||
}
|
||||
else if (event instanceof TraceClosedPluginEvent ev) {
|
||||
provider.traceClosed(ev.getTrace());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
package ghidra.app.plugin.core.debug.gui.modules;
|
||||
|
||||
import static ghidra.framework.main.DataTreeDialogType.*;
|
||||
import static ghidra.framework.main.DataTreeDialogType.OPEN;
|
||||
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.io.File;
|
||||
|
@ -67,15 +67,29 @@ import ghidra.program.util.ProgramLocation;
|
|||
import ghidra.program.util.ProgramSelection;
|
||||
import ghidra.trace.model.*;
|
||||
import ghidra.trace.model.modules.*;
|
||||
import ghidra.trace.model.program.TraceProgramView;
|
||||
import ghidra.trace.util.TraceEvent;
|
||||
import ghidra.trace.util.TraceEvents;
|
||||
import ghidra.util.HelpLocation;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.*;
|
||||
|
||||
public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
||||
protected static final AutoConfigState.ClassHandler<DebuggerModulesProvider> CONFIG_STATE_HANDLER =
|
||||
AutoConfigState.wireHandler(DebuggerModulesProvider.class, MethodHandles.lookup());
|
||||
|
||||
protected static final String NO_MODULES_PROPOSAL_SEL = """
|
||||
Could not formulate a proposal for any selected module. \
|
||||
You may need to import and/or open the destination images first.\
|
||||
""";
|
||||
|
||||
protected static final String FMT_NO_MODULES_PROPOSAL_RETRY = """
|
||||
Could not formulate a proposal for program '%s' to trace '%s'. \
|
||||
The module may not be loaded yet, or the chosen image could be wrong.\
|
||||
""";
|
||||
|
||||
protected static final String FMT_NO_MODULES_PROPOSAL_CURRENT = """
|
||||
Could not formulate a proposal from module '%s' to program '%s'.\
|
||||
""";
|
||||
|
||||
protected static boolean sameCoordinates(DebuggerCoordinates a, DebuggerCoordinates b) {
|
||||
if (!Objects.equals(a.getTrace(), b.getTrace())) {
|
||||
return false;
|
||||
|
@ -253,6 +267,57 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
|||
}
|
||||
}
|
||||
|
||||
interface MapMissingProgramRetryAction {
|
||||
String NAME = "Retry Map Missing Program";
|
||||
String DESCRIPTION = "Retry mapping the missing program by finding its module";
|
||||
Icon ICON = DebuggerResources.ICON_MAP_AUTO;
|
||||
String HELP_ANCHOR = "map_missing_program_retry";
|
||||
|
||||
static ActionBuilder builder(Plugin owner) {
|
||||
String ownerName = owner.getName();
|
||||
return new ActionBuilder(NAME, ownerName)
|
||||
.description(DESCRIPTION)
|
||||
.toolBarIcon(ICON)
|
||||
.popupMenuIcon(ICON)
|
||||
.popupMenuPath(NAME)
|
||||
.helpLocation(new HelpLocation(ownerName, HELP_ANCHOR));
|
||||
}
|
||||
}
|
||||
|
||||
interface MapMissingProgramToCurrentAction {
|
||||
String NAME = "Map Missing Program to Current Module";
|
||||
String DESCRIPTION = "Map the missing program to the current module";
|
||||
Icon ICON = DebuggerResources.ICON_MAP_MODULES;
|
||||
String HELP_ANCHOR = "map_missing_program_current";
|
||||
|
||||
static ActionBuilder builder(Plugin owner) {
|
||||
String ownerName = owner.getName();
|
||||
return new ActionBuilder(NAME, ownerName)
|
||||
.description(DESCRIPTION)
|
||||
.toolBarIcon(ICON)
|
||||
.popupMenuIcon(ICON)
|
||||
.popupMenuPath(NAME)
|
||||
.helpLocation(new HelpLocation(ownerName, HELP_ANCHOR));
|
||||
}
|
||||
}
|
||||
|
||||
interface MapMissingProgramIdenticallyAction {
|
||||
String NAME = "Map Missing Program Identically";
|
||||
String DESCRIPTION = "Map the missing program to its trace identically";
|
||||
Icon ICON = DebuggerResources.ICON_MAP_IDENTICALLY;
|
||||
String HELP_ANCHOR = "map_missing_program_identically";
|
||||
|
||||
static ActionBuilder builder(Plugin owner) {
|
||||
String ownerName = owner.getName();
|
||||
return new ActionBuilder(NAME, ownerName)
|
||||
.description(DESCRIPTION)
|
||||
.toolBarIcon(ICON)
|
||||
.popupMenuIcon(ICON)
|
||||
.popupMenuPath(NAME)
|
||||
.helpLocation(new HelpLocation(ownerName, HELP_ANCHOR));
|
||||
}
|
||||
}
|
||||
|
||||
interface ShowSectionsTableAction {
|
||||
String NAME = "Show Sections Table";
|
||||
Icon ICON = new GIcon("icon.debugger.modules.table.sections");
|
||||
|
@ -404,9 +469,17 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
|||
}
|
||||
}
|
||||
|
||||
protected class ForCleanupMappingChangeListener
|
||||
implements DebuggerStaticMappingChangeListener {
|
||||
@Override
|
||||
public void mappingsChanged(Set<Trace> affectedTraces, Set<Program> affectedPrograms) {
|
||||
Swing.runIfSwingOrRunLater(() -> cleanMissingProgramMessages(null, null));
|
||||
}
|
||||
}
|
||||
|
||||
final DebuggerModulesPlugin plugin;
|
||||
|
||||
@AutoServiceConsumed
|
||||
//@AutoServiceConsumed via method
|
||||
private DebuggerStaticMappingService staticMappingService;
|
||||
@AutoServiceConsumed
|
||||
private DebuggerTraceManagerService traceManager;
|
||||
|
@ -467,6 +540,13 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
|||
DockingAction actionImportMissingModule;
|
||||
DockingAction actionMapMissingModule;
|
||||
|
||||
DockingAction actionMapMissingProgramRetry;
|
||||
DockingAction actionMapMissingProgramToCurrent;
|
||||
DockingAction actionMapMissingProgramIdentically;
|
||||
|
||||
protected final ForCleanupMappingChangeListener mappingChangeListener =
|
||||
new ForCleanupMappingChangeListener();
|
||||
|
||||
SelectAddressesAction actionSelectAddresses;
|
||||
ImportFromFileSystemAction actionImportFromFileSystem;
|
||||
ToggleDockingAction actionShowSectionsTable;
|
||||
|
@ -507,26 +587,37 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
|||
importerService.importFile(root, file);
|
||||
}
|
||||
|
||||
void addResolutionActionMaybe(DebuggerConsoleService consoleService, DockingActionIf action) {
|
||||
if (action != null) {
|
||||
consoleService.addResolutionAction(action);
|
||||
}
|
||||
}
|
||||
|
||||
void removeResolutionActionMaybe(DebuggerConsoleService consoleService,
|
||||
DockingActionIf action) {
|
||||
if (action != null) {
|
||||
consoleService.removeResolutionAction(action);
|
||||
}
|
||||
}
|
||||
|
||||
@AutoServiceConsumed
|
||||
private void setConsoleService(DebuggerConsoleService consoleService) {
|
||||
if (consoleService != null) {
|
||||
if (actionImportMissingModule != null) {
|
||||
consoleService.addResolutionAction(actionImportMissingModule);
|
||||
}
|
||||
if (actionMapMissingModule != null) {
|
||||
consoleService.addResolutionAction(actionMapMissingModule);
|
||||
}
|
||||
addResolutionActionMaybe(consoleService, actionImportMissingModule);
|
||||
addResolutionActionMaybe(consoleService, actionMapMissingModule);
|
||||
addResolutionActionMaybe(consoleService, actionMapMissingProgramRetry);
|
||||
addResolutionActionMaybe(consoleService, actionMapMissingProgramToCurrent);
|
||||
addResolutionActionMaybe(consoleService, actionMapMissingProgramIdentically);
|
||||
}
|
||||
}
|
||||
|
||||
protected void dispose() {
|
||||
if (consoleService != null) {
|
||||
if (actionImportMissingModule != null) {
|
||||
consoleService.removeResolutionAction(actionImportMissingModule);
|
||||
}
|
||||
if (actionMapMissingModule != null) {
|
||||
consoleService.removeResolutionAction(actionMapMissingModule);
|
||||
}
|
||||
removeResolutionActionMaybe(consoleService, actionImportMissingModule);
|
||||
removeResolutionActionMaybe(consoleService, actionMapMissingModule);
|
||||
removeResolutionActionMaybe(consoleService, actionMapMissingProgramRetry);
|
||||
removeResolutionActionMaybe(consoleService, actionMapMissingProgramToCurrent);
|
||||
removeResolutionActionMaybe(consoleService, actionMapMissingProgramIdentically);
|
||||
}
|
||||
|
||||
blockChooserDialog.dispose();
|
||||
|
@ -637,6 +728,20 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
|||
.onAction(this::activatedMapMissingModule)
|
||||
.build();
|
||||
|
||||
actionMapMissingProgramRetry = MapMissingProgramRetryAction.builder(plugin)
|
||||
.withContext(DebuggerMissingProgramActionContext.class)
|
||||
.onAction(this::activatedMapMissingProgramRetry)
|
||||
.build();
|
||||
actionMapMissingProgramToCurrent = MapMissingProgramToCurrentAction.builder(plugin)
|
||||
.withContext(DebuggerMissingProgramActionContext.class)
|
||||
.enabledWhen(this::isEnabledMapMissingProgramToCurrent)
|
||||
.onAction(this::activatedMapMissingProgramToCurrent)
|
||||
.build();
|
||||
actionMapMissingProgramIdentically = MapMissingProgramIdenticallyAction.builder(plugin)
|
||||
.withContext(DebuggerMissingProgramActionContext.class)
|
||||
.onAction(this::activatedMapMissingProgramIdentically)
|
||||
.build();
|
||||
|
||||
actionSelectAddresses = new SelectAddressesAction();
|
||||
actionImportFromFileSystem = new ImportFromFileSystemAction();
|
||||
actionShowSectionsTable = ShowSectionsTableAction.builder(plugin)
|
||||
|
@ -799,6 +904,78 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
|||
mapModuleTo(context.getModule());
|
||||
}
|
||||
|
||||
private void activatedMapMissingProgramRetry(DebuggerMissingProgramActionContext context) {
|
||||
if (staticMappingService == null) {
|
||||
return;
|
||||
}
|
||||
Program program = context.getProgram();
|
||||
Trace trace = context.getTrace();
|
||||
Map<TraceModule, ModuleMapProposal> map = staticMappingService.proposeModuleMaps(
|
||||
trace.getModuleManager().getAllModules(), List.of(program));
|
||||
Collection<ModuleMapEntry> proposal = MapProposal.flatten(map.values());
|
||||
promptModuleProposal(proposal, FMT_NO_MODULES_PROPOSAL_RETRY.formatted(
|
||||
trace.getDomainFile().getName(), program.getDomainFile().getName()));
|
||||
}
|
||||
|
||||
private boolean isEnabledMapMissingProgramToCurrent(
|
||||
DebuggerMissingProgramActionContext context) {
|
||||
if (staticMappingService == null || traceManager == null || listingService == null) {
|
||||
return false;
|
||||
}
|
||||
ProgramLocation loc = listingService.getCurrentLocation();
|
||||
if (loc == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(loc.getProgram() instanceof TraceProgramView view)) {
|
||||
return false;
|
||||
}
|
||||
Trace trace = context.getTrace();
|
||||
if (view.getTrace() != trace) {
|
||||
return false;
|
||||
}
|
||||
|
||||
long snap = traceManager.getCurrentFor(trace).getSnap();
|
||||
Address address = loc.getAddress();
|
||||
return !trace.getModuleManager().getModulesAt(snap, address).isEmpty();
|
||||
}
|
||||
|
||||
private void activatedMapMissingProgramToCurrent(DebuggerMissingProgramActionContext context) {
|
||||
if (staticMappingService == null || traceManager == null || listingService == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Trace trace = context.getTrace();
|
||||
long snap = traceManager.getCurrentFor(trace).getSnap();
|
||||
Address address = listingService.getCurrentLocation().getAddress();
|
||||
|
||||
TraceModule module = trace.getModuleManager().getModulesAt(snap, address).iterator().next();
|
||||
|
||||
Program program = context.getProgram();
|
||||
ModuleMapProposal proposal =
|
||||
staticMappingService.proposeModuleMap(module, program);
|
||||
Map<TraceModule, ModuleMapEntry> map = proposal.computeMap();
|
||||
promptModuleProposal(map.values(), FMT_NO_MODULES_PROPOSAL_CURRENT.formatted(
|
||||
module.getName(), program.getDomainFile().getName()));
|
||||
}
|
||||
|
||||
private void activatedMapMissingProgramIdentically(
|
||||
DebuggerMissingProgramActionContext context) {
|
||||
if (staticMappingService == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Trace trace = context.getTrace();
|
||||
long snap = traceManager == null ? 0 : traceManager.getCurrentFor(trace).getSnap();
|
||||
|
||||
try {
|
||||
staticMappingService.addIdentityMapping(trace, context.getProgram(),
|
||||
Lifespan.nowOn(snap), true);
|
||||
}
|
||||
catch (TraceConflictedMappingException e) {
|
||||
Msg.showError(this, null, "Map Identically", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void toggledShowSectionsTable(ActionContext ignored) {
|
||||
setShowSectionsTable(actionShowSectionsTable.isSelected());
|
||||
}
|
||||
|
@ -903,11 +1080,9 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
|||
}
|
||||
}
|
||||
|
||||
protected void promptModuleProposal(Collection<ModuleMapEntry> proposal) {
|
||||
protected void promptModuleProposal(Collection<ModuleMapEntry> proposal, String emptyMsg) {
|
||||
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.");
|
||||
Msg.showInfo(this, getComponent(), "Map Modules", emptyMsg);
|
||||
return;
|
||||
}
|
||||
Collection<ModuleMapEntry> adjusted =
|
||||
|
@ -926,7 +1101,7 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
|||
Map<TraceModule, ModuleMapProposal> map = staticMappingService.proposeModuleMaps(modules,
|
||||
List.of(programManager.getAllOpenPrograms()));
|
||||
Collection<ModuleMapEntry> proposal = MapProposal.flatten(map.values());
|
||||
promptModuleProposal(proposal);
|
||||
promptModuleProposal(proposal, NO_MODULES_PROPOSAL_SEL);
|
||||
}
|
||||
|
||||
protected void mapModuleTo(TraceModule module) {
|
||||
|
@ -939,7 +1114,7 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
|||
}
|
||||
ModuleMapProposal proposal = staticMappingService.proposeModuleMap(module, program);
|
||||
Map<TraceModule, ModuleMapEntry> map = proposal.computeMap();
|
||||
promptModuleProposal(map.values());
|
||||
promptModuleProposal(map.values(), NO_MODULES_PROPOSAL_SEL);
|
||||
}
|
||||
|
||||
protected void promptSectionProposal(Collection<SectionMapEntry> proposal) {
|
||||
|
@ -1090,6 +1265,11 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
|||
if (currentProgram == program) {
|
||||
currentProgram = null;
|
||||
}
|
||||
cleanMissingProgramMessages(null, program);
|
||||
}
|
||||
|
||||
public void traceClosed(Trace trace) {
|
||||
cleanMissingProgramMessages(trace, null);
|
||||
}
|
||||
|
||||
protected void addNewTraceListener() {
|
||||
|
@ -1232,4 +1412,62 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
|||
doSetFilterSectionsByModules(filterSectionsByModules);
|
||||
doSetShowSectionsTable(showSectionsTable);
|
||||
}
|
||||
|
||||
protected boolean shouldKeepMessage(DebuggerMissingProgramActionContext ctx, Trace closedTrace,
|
||||
Program closedProgram) {
|
||||
Trace trace = ctx.getTrace();
|
||||
if (trace == closedTrace) {
|
||||
return false;
|
||||
}
|
||||
if (!traceManager.getOpenTraces().contains(trace)) {
|
||||
return false;
|
||||
}
|
||||
Program program = ctx.getProgram();
|
||||
if (program == closedProgram) {
|
||||
return false;
|
||||
}
|
||||
if (programManager != null &&
|
||||
!Arrays.asList(programManager.getAllOpenPrograms()).contains(program)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only do mapping probe on mapping changed events
|
||||
if (closedTrace != null || closedProgram != null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
TraceProgramView view = traceManager.getCurrentFor(trace).getView();
|
||||
Address probe = ctx.getMappingProbeAddress();
|
||||
ProgramLocation dyn = staticMappingService.getDynamicLocationFromStatic(view,
|
||||
new ProgramLocation(program, probe));
|
||||
if (dyn != null) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void cleanMissingProgramMessages(Trace closedTrace, Program closedProgram) {
|
||||
if (traceManager == null) {
|
||||
return;
|
||||
}
|
||||
for (ActionContext ctx : consoleService.getActionContexts()) {
|
||||
if (!(ctx instanceof DebuggerMissingProgramActionContext mpCtx)) {
|
||||
continue;
|
||||
}
|
||||
if (!shouldKeepMessage(mpCtx, closedTrace, closedProgram)) {
|
||||
consoleService.removeFromLog(mpCtx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AutoServiceConsumed
|
||||
private void setStaticMappingService(DebuggerStaticMappingService staticMappingService) {
|
||||
if (this.staticMappingService != null) {
|
||||
this.staticMappingService.removeChangeListener(mappingChangeListener);
|
||||
}
|
||||
this.staticMappingService = staticMappingService;
|
||||
if (this.staticMappingService != null) {
|
||||
this.staticMappingService.addChangeListener(mappingChangeListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,13 +47,13 @@ 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.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.service.modules.DebuggerStaticMappingUtils;
|
||||
import ghidra.app.services.DebuggerStaticMappingService;
|
||||
import ghidra.app.services.ProgramManager;
|
||||
import ghidra.app.util.viewer.listingpanel.ListingPanel;
|
||||
import ghidra.async.SwingExecutorService;
|
||||
import ghidra.debug.api.model.TraceRecorder;
|
||||
import ghidra.debug.api.modules.DebuggerMissingModuleActionContext;
|
||||
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
|
||||
import ghidra.framework.model.*;
|
||||
import ghidra.plugin.importer.ImporterPlugin;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue