GP-4636: Use Debug Console for initial mapping failure.

This commit is contained in:
Dan 2024-05-30 14:52:16 -04:00
parent 35434613b8
commit 1db04f8c71
8 changed files with 435 additions and 58 deletions

View file

@ -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;
}

View file

@ -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;
}
}

View file

@ -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);

View file

@ -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>

View file

@ -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;

View file

@ -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

View file

@ -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);
}
}
}

View file

@ -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;