GP-4713: Launch mapping uses AutoMapSpec. Fix StaticMappingService.

This commit is contained in:
Dan 2024-08-14 15:44:42 -04:00
parent ebb4027d8b
commit d95200b166
17 changed files with 623 additions and 193 deletions

View File

@ -0,0 +1,42 @@
/* ###
* 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.services;
import ghidra.debug.api.action.AutoMapSpec;
import ghidra.framework.plugintool.ServiceInfo;
import ghidra.trace.model.Trace;
/**
* The service to query auto-map settings
*/
@ServiceInfo(defaultProviderName = "ghidra.app.plugin.core.debug.gui.modules.DebuggerModulesPlugin")
public interface DebuggerAutoMappingService {
/**
* Get the auto-map setting currently active in the Modules provider
*
* @return the current setting
*/
AutoMapSpec getAutoMapSpec();
/**
* Get the current auto-map setting for the given trace
*
* @param trace the trace
* @return the auto-map setting for the trace, or the setting in the Modules provider, if the
* trace does not have its own setting.
*/
AutoMapSpec getAutoMapSpec(Trace trace);
}

View File

@ -4,16 +4,16 @@
* 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.action;
package ghidra.debug.api.action;
import java.util.*;
@ -21,15 +21,15 @@ import javax.swing.Icon;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
import ghidra.app.plugin.core.debug.utils.MiscellaneousUtils;
import ghidra.app.services.DebuggerStaticMappingService;
import ghidra.app.services.ProgramManager;
import ghidra.framework.cmd.BackgroundCommand;
import ghidra.framework.options.SaveState;
import ghidra.framework.plugintool.AutoConfigState.ConfigFieldCodec;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.listing.Program;
import ghidra.trace.model.Trace;
import ghidra.trace.model.target.TraceObjectValue;
import ghidra.trace.util.TraceEvent;
import ghidra.util.classfinder.ClassSearcher;
import ghidra.util.classfinder.ExtensionPoint;
@ -50,7 +50,7 @@ public interface AutoMapSpec extends ExtensionPoint {
}
private synchronized void classesChanged(ChangeEvent evt) {
MiscellaneousUtils.collectUniqueInstances(AutoMapSpec.class, specsByName,
InstanceUtils.collectUniqueInstances(AutoMapSpec.class, specsByName,
AutoMapSpec::getConfigName);
}
}
@ -87,12 +87,18 @@ public interface AutoMapSpec extends ExtensionPoint {
String getMenuName();
default Icon getMenuIcon() {
return DebuggerResources.ICON_CONFIG;
}
Icon getMenuIcon();
Collection<TraceEvent<?, ?>> getChangeTypes();
boolean objectHasType(TraceObjectValue value);
String getInfoForObjects(Trace trace);
default boolean hasTask() {
return true;
}
default String getTaskTitle() {
return getMenuName();
}
@ -119,6 +125,33 @@ public interface AutoMapSpec extends ExtensionPoint {
tool.executeBackgroundCommand(cmd, trace);
}
void performMapping(DebuggerStaticMappingService mappingService, Trace trace,
ProgramManager programManager, TaskMonitor monitor) throws CancelledException;
List<Program> programs(ProgramManager programManager);
/**
* Perform the actual mapping
*
* @param mappingService the mapping service
* @param trace the trace
* @param programs the programs to consider
* @param monitor a task monitor
* @return true if any mappings were added
* @throws CancelledException if the task monitor cancelled the task
*/
boolean performMapping(DebuggerStaticMappingService mappingService, Trace trace,
List<Program> programs, TaskMonitor monitor) throws CancelledException;
/**
* Perform the actual mapping
*
* @param mappingService the mapping service
* @param trace the trace
* @param programManager the program manager
* @param monitor a task monitor
* @return true if any mappings were added
* @throws CancelledException if the task monitor cancelled the task
*/
default boolean performMapping(DebuggerStaticMappingService mappingService, Trace trace,
ProgramManager programManager, TaskMonitor monitor) throws CancelledException {
return performMapping(mappingService, trace, programs(programManager), monitor);
}
}

View File

@ -0,0 +1,41 @@
/* ###
* 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.action;
import java.util.Map;
import java.util.function.Function;
import ghidra.util.Msg;
import ghidra.util.classfinder.ClassSearcher;
public class InstanceUtils {
public static <T> void collectUniqueInstances(Class<T> cls, Map<String, T> map,
Function<T, String> keyFunc) {
// This is wasteful. Existing instances will be re-instantiated and thrown away
for (T t : ClassSearcher.getInstances(cls)) {
String key = keyFunc.apply(t);
T exists = map.get(key);
if (exists != null) {
if (exists.getClass().equals(t.getClass())) {
continue;
}
Msg.error(LocationTrackingSpec.class,
cls.getSimpleName() + " conflict over key: " + key);
}
map.put(key, t);
}
}
}

View File

@ -4,9 +4,9 @@
* 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.
@ -38,8 +38,9 @@ import ghidra.app.services.DebuggerTraceManagerService.ActivationCause;
import ghidra.async.AsyncUtils;
import ghidra.dbg.target.TargetMethod.ParameterDescription;
import ghidra.dbg.util.ShellUtils;
import ghidra.debug.api.modules.*;
import ghidra.debug.api.modules.ModuleMapProposal.ModuleMapEntry;
import ghidra.debug.api.action.AutoMapSpec;
import ghidra.debug.api.modules.DebuggerMissingProgramActionContext;
import ghidra.debug.api.modules.DebuggerStaticMappingChangeListener;
import ghidra.debug.api.tracermi.*;
import ghidra.framework.options.SaveState;
import ghidra.framework.plugintool.AutoConfigState.*;
@ -50,7 +51,6 @@ 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.*;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.Task;
@ -185,16 +185,31 @@ public abstract class AbstractTraceRmiLaunchOffer implements TraceRmiLaunchOffer
return result;
}
protected Collection<ModuleMapEntry> invokeMapper(TaskMonitor monitor,
DebuggerStaticMappingService mappingService, Trace trace) throws CancelledException {
protected boolean invokeMapper(TaskMonitor monitor, DebuggerStaticMappingService mappingService,
TraceRmiConnection connection, Trace trace, AutoMapSpec spec)
throws CancelledException {
if (program == null) {
return List.of();
return false;
}
Map<TraceModule, ModuleMapProposal> map = mappingService
.proposeModuleMaps(trace.getModuleManager().getAllModules(), List.of(program));
Collection<ModuleMapEntry> proposal = MapProposal.flatten(map.values());
mappingService.addModuleMappings(proposal, monitor, true);
return proposal;
if (spec.performMapping(mappingService, trace, List.of(program), monitor)) {
return true;
}
try {
mappingService.changesSettled().get(1, TimeUnit.SECONDS);
}
catch (InterruptedException | ExecutionException | TimeoutException e) {
// Whatever, just check for the mapping
}
Address probeAddress = getMappingProbeAddress();
if (probeAddress == null) {
return true; // Probably shouldn't happen, but if it does, say "success"
}
ProgramLocation probe = new ProgramLocation(program, probeAddress);
long snap = connection.getLastSnapshot(trace);
return mappingService.getOpenMappedLocation(trace, probe, snap) != null;
}
protected SaveState saveLauncherArgsToState(Map<String, ?> args,
@ -543,7 +558,9 @@ public abstract class AbstractTraceRmiLaunchOffer implements TraceRmiLaunchOffer
}
protected void initializeMonitor(TaskMonitor monitor) {
if (requiresImage()) {
DebuggerAutoMappingService auto = tool.getService(DebuggerAutoMappingService.class);
AutoMapSpec spec = auto.getAutoMapSpec();
if (requiresImage() && spec.hasTask()) {
monitor.setMaximum(6);
}
else {
@ -557,6 +574,11 @@ public abstract class AbstractTraceRmiLaunchOffer implements TraceRmiLaunchOffer
if (!requiresImage()) {
return;
}
DebuggerAutoMappingService auto = tool.getService(DebuggerAutoMappingService.class);
AutoMapSpec spec = auto.getAutoMapSpec(trace);
if (!spec.hasTask()) {
return;
}
DebuggerStaticMappingService mappingService =
tool.getService(DebuggerStaticMappingService.class);
monitor.setMessage("Waiting for module mapping");
@ -567,14 +589,14 @@ public abstract class AbstractTraceRmiLaunchOffer implements TraceRmiLaunchOffer
catch (TimeoutException e) {
monitor.setMessage(
"Timed out waiting for module mapping. Invoking the mapper.");
Collection<ModuleMapEntry> mapped;
boolean mapped;
try {
mapped = invokeMapper(monitor, mappingService, trace);
mapped = invokeMapper(monitor, mappingService, connection, trace, spec);
}
catch (CancelledException ce) {
throw new CancellationException(e.getMessage());
}
if (mapped.isEmpty()) {
if (!mapped) {
throw new NoStaticMappingException(
"The resulting target process has no mapping to the static image.");
}

View File

@ -4,9 +4,9 @@
* 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.
@ -25,7 +25,7 @@ import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import ghidra.app.plugin.core.debug.gui.control.TargetActionTask;
import ghidra.app.plugin.core.debug.utils.MiscellaneousUtils;
import ghidra.debug.api.action.InstanceUtils;
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
import ghidra.framework.options.SaveState;
import ghidra.framework.plugintool.AutoConfigState.ConfigFieldCodec;
@ -49,7 +49,7 @@ public interface AutoReadMemorySpec extends ExtensionPoint {
}
private synchronized void classesChanged(ChangeEvent evt) {
MiscellaneousUtils.collectUniqueInstances(AutoReadMemorySpec.class, specsByName,
InstanceUtils.collectUniqueInstances(AutoReadMemorySpec.class, specsByName,
AutoReadMemorySpec::getConfigName);
}
}

View File

@ -4,9 +4,9 @@
* 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.
@ -16,14 +16,22 @@
package ghidra.app.plugin.core.debug.gui.action;
import java.util.*;
import java.util.stream.Collectors;
import javax.swing.Icon;
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
import ghidra.app.services.DebuggerStaticMappingService;
import ghidra.app.services.ProgramManager;
import ghidra.debug.api.action.AutoMapSpec;
import ghidra.debug.api.modules.MapProposal;
import ghidra.debug.api.modules.ModuleMapProposal;
import ghidra.debug.api.modules.ModuleMapProposal.ModuleMapEntry;
import ghidra.program.model.listing.Program;
import ghidra.trace.model.Trace;
import ghidra.trace.model.memory.TraceObjectMemoryRegion;
import ghidra.trace.model.modules.TraceObjectModule;
import ghidra.trace.model.target.TraceObjectValue;
import ghidra.trace.util.TraceEvent;
import ghidra.trace.util.TraceEvents;
import ghidra.util.exception.CancelledException;
@ -42,6 +50,11 @@ public class ByModuleAutoMapSpec implements AutoMapSpec {
return "Auto-Map by Module";
}
@Override
public Icon getMenuIcon() {
return DebuggerResources.ICON_CONFIG;
}
@Override
public Collection<TraceEvent<?, ?>> getChangeTypes() {
return List.of(
@ -50,13 +63,36 @@ public class ByModuleAutoMapSpec implements AutoMapSpec {
}
@Override
public void performMapping(DebuggerStaticMappingService mappingService, Trace trace,
ProgramManager programManager, TaskMonitor monitor) throws CancelledException {
List<Program> programs = Arrays.asList(programManager.getAllOpenPrograms());
public boolean objectHasType(TraceObjectValue value) {
return value.getParent().queryInterface(TraceObjectModule.class) != null ||
value.getParent().queryInterface(TraceObjectMemoryRegion.class) != null;
}
@Override
public String getInfoForObjects(Trace trace) {
String modPart = trace.getModuleManager()
.getAllModules()
.stream()
.map(m -> m.getName() + ":" + m.getBase())
.sorted()
.collect(Collectors.joining(","));
String regPart = ByRegionAutoMapSpec.getInfoForRegions(trace);
return modPart + ";" + regPart;
}
@Override
public List<Program> programs(ProgramManager programManager) {
return Arrays.asList(programManager.getAllOpenPrograms());
}
@Override
public boolean performMapping(DebuggerStaticMappingService mappingService, Trace trace,
List<Program> programs, TaskMonitor monitor) throws CancelledException {
Map<?, ModuleMapProposal> maps = mappingService
.proposeModuleMaps(trace.getModuleManager().getAllModules(), programs);
Collection<ModuleMapEntry> entries = MapProposal.flatten(maps.values());
entries = MapProposal.removeOverlapping(entries);
mappingService.addModuleMappings(entries, monitor, false);
return !entries.isEmpty();
}
}

View File

@ -4,9 +4,9 @@
* 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.
@ -16,14 +16,21 @@
package ghidra.app.plugin.core.debug.gui.action;
import java.util.*;
import java.util.stream.Collectors;
import javax.swing.Icon;
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
import ghidra.app.services.DebuggerStaticMappingService;
import ghidra.app.services.ProgramManager;
import ghidra.debug.api.action.AutoMapSpec;
import ghidra.debug.api.modules.MapProposal;
import ghidra.debug.api.modules.RegionMapProposal;
import ghidra.debug.api.modules.RegionMapProposal.RegionMapEntry;
import ghidra.program.model.listing.Program;
import ghidra.trace.model.Trace;
import ghidra.trace.model.memory.TraceObjectMemoryRegion;
import ghidra.trace.model.target.TraceObjectValue;
import ghidra.trace.util.TraceEvent;
import ghidra.trace.util.TraceEvents;
import ghidra.util.exception.CancelledException;
@ -42,19 +49,48 @@ public class ByRegionAutoMapSpec implements AutoMapSpec {
return "Auto-Map by Region";
}
@Override
public Icon getMenuIcon() {
return DebuggerResources.ICON_CONFIG;
}
@Override
public Collection<TraceEvent<?, ?>> getChangeTypes() {
return List.of(TraceEvents.REGION_ADDED);
}
@Override
public void performMapping(DebuggerStaticMappingService mappingService, Trace trace,
ProgramManager programManager, TaskMonitor monitor) throws CancelledException {
List<Program> programs = Arrays.asList(programManager.getAllOpenPrograms());
public boolean objectHasType(TraceObjectValue value) {
return value.getParent().queryInterface(TraceObjectMemoryRegion.class) != null;
}
static String getInfoForRegions(Trace trace) {
return trace.getMemoryManager()
.getAllRegions()
.stream()
.map(r -> r.getName() + ":" + r.getMinAddress())
.sorted()
.collect(Collectors.joining(","));
}
@Override
public String getInfoForObjects(Trace trace) {
return getInfoForRegions(trace);
}
@Override
public List<Program> programs(ProgramManager programManager) {
return Arrays.asList(programManager.getAllOpenPrograms());
}
@Override
public boolean performMapping(DebuggerStaticMappingService mappingService, Trace trace,
List<Program> programs, TaskMonitor monitor) throws CancelledException {
Map<?, RegionMapProposal> maps = mappingService
.proposeRegionMaps(trace.getMemoryManager().getAllRegions(), programs);
Collection<RegionMapEntry> entries = MapProposal.flatten(maps.values());
entries = MapProposal.removeOverlapping(entries);
mappingService.addRegionMappings(entries, monitor, false);
return !entries.isEmpty();
}
}

View File

@ -4,9 +4,9 @@
* 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.
@ -16,14 +16,21 @@
package ghidra.app.plugin.core.debug.gui.action;
import java.util.*;
import java.util.stream.Collectors;
import javax.swing.Icon;
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
import ghidra.app.services.DebuggerStaticMappingService;
import ghidra.app.services.ProgramManager;
import ghidra.debug.api.action.AutoMapSpec;
import ghidra.debug.api.modules.MapProposal;
import ghidra.debug.api.modules.SectionMapProposal;
import ghidra.debug.api.modules.SectionMapProposal.SectionMapEntry;
import ghidra.program.model.listing.Program;
import ghidra.trace.database.module.TraceObjectSection;
import ghidra.trace.model.Trace;
import ghidra.trace.model.target.TraceObjectValue;
import ghidra.trace.util.TraceEvent;
import ghidra.trace.util.TraceEvents;
import ghidra.util.exception.CancelledException;
@ -42,19 +49,44 @@ public class BySectionAutoMapSpec implements AutoMapSpec {
return "Auto-Map by Section";
}
@Override
public Icon getMenuIcon() {
return DebuggerResources.ICON_CONFIG;
}
@Override
public Collection<TraceEvent<?, ?>> getChangeTypes() {
return List.of(TraceEvents.SECTION_ADDED);
}
@Override
public void performMapping(DebuggerStaticMappingService mappingService, Trace trace,
ProgramManager programManager, TaskMonitor monitor) throws CancelledException {
List<Program> programs = Arrays.asList(programManager.getAllOpenPrograms());
public boolean objectHasType(TraceObjectValue value) {
return value.getParent().queryInterface(TraceObjectSection.class) != null;
}
@Override
public String getInfoForObjects(Trace trace) {
return trace.getModuleManager()
.getAllSections()
.stream()
.map(s -> s.getName() + ":" + s.getStart())
.sorted()
.collect(Collectors.joining(","));
}
@Override
public List<Program> programs(ProgramManager programManager) {
return Arrays.asList(programManager.getAllOpenPrograms());
}
@Override
public boolean performMapping(DebuggerStaticMappingService mappingService, Trace trace,
List<Program> programs, TaskMonitor monitor) throws CancelledException {
Map<?, SectionMapProposal> maps = mappingService
.proposeSectionMaps(trace.getModuleManager().getAllModules(), programs);
Collection<SectionMapEntry> entries = MapProposal.flatten(maps.values());
entries = MapProposal.removeOverlapping(entries);
mappingService.addSectionMappings(entries, monitor, false);
return !entries.isEmpty();
}
}

View File

@ -4,9 +4,9 @@
* 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.
@ -18,10 +18,16 @@ package ghidra.app.plugin.core.debug.gui.action;
import java.util.Collection;
import java.util.List;
import javax.swing.Icon;
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
import ghidra.app.services.DebuggerStaticMappingService;
import ghidra.app.services.ProgramManager;
import ghidra.debug.api.action.AutoMapSpec;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.listing.Program;
import ghidra.trace.model.Trace;
import ghidra.trace.model.target.TraceObjectValue;
import ghidra.trace.util.TraceEvent;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
@ -39,18 +45,44 @@ public class NoneAutoMapSpec implements AutoMapSpec {
return "Do Not Auto-Map";
}
@Override
public Icon getMenuIcon() {
return DebuggerResources.ICON_CONFIG;
}
@Override
public Collection<TraceEvent<?, ?>> getChangeTypes() {
return List.of();
}
@Override
public boolean objectHasType(TraceObjectValue value) {
return false;
}
@Override
public String getInfoForObjects(Trace trace) {
return "";
}
@Override
public boolean hasTask() {
return false;
}
@Override
public void runTask(PluginTool tool, Trace trace) {
// Don't bother launching a task that does nothing
}
@Override
public void performMapping(DebuggerStaticMappingService mappingService, Trace trace,
ProgramManager programManager, TaskMonitor monitor) throws CancelledException {
public List<Program> programs(ProgramManager programManager) {
return List.of();
}
@Override
public boolean performMapping(DebuggerStaticMappingService mappingService, Trace trace,
List<Program> programs, TaskMonitor monitor) throws CancelledException {
return false;
}
}

View File

@ -4,9 +4,9 @@
* 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.
@ -18,12 +18,17 @@ package ghidra.app.plugin.core.debug.gui.action;
import java.util.Collection;
import java.util.List;
import javax.swing.Icon;
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
import ghidra.app.services.DebuggerStaticMappingService;
import ghidra.app.services.ProgramManager;
import ghidra.debug.api.action.AutoMapSpec;
import ghidra.program.model.listing.Program;
import ghidra.trace.model.Lifespan;
import ghidra.trace.model.Trace;
import ghidra.trace.model.modules.TraceConflictedMappingException;
import ghidra.trace.model.target.TraceObjectValue;
import ghidra.trace.util.TraceEvent;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
@ -41,24 +46,49 @@ public class OneToOneAutoMapSpec implements AutoMapSpec {
return "Auto-Map Identically (1-to-1)";
}
@Override
public Icon getMenuIcon() {
return DebuggerResources.ICON_CONFIG;
}
@Override
public Collection<TraceEvent<?, ?>> getChangeTypes() {
return List.of();
}
@Override
public void performMapping(DebuggerStaticMappingService mappingService, Trace trace,
ProgramManager programManager, TaskMonitor monitor) throws CancelledException {
public boolean objectHasType(TraceObjectValue value) {
return false;
}
@Override
public String getInfoForObjects(Trace trace) {
return "";
}
@Override
public List<Program> programs(ProgramManager programManager) {
Program program = programManager.getCurrentProgram();
if (program == null) {
return;
return List.of();
}
try {
mappingService.addIdentityMapping(trace, program,
Lifespan.nowOn(trace.getProgramView().getSnap()), false);
}
catch (TraceConflictedMappingException e) {
// aww well
return List.of(program);
}
@Override
public boolean performMapping(DebuggerStaticMappingService mappingService, Trace trace,
List<Program> programs, TaskMonitor monitor) throws CancelledException {
boolean result = false;
for (Program program : programs) {
try {
mappingService.addIdentityMapping(trace, program,
Lifespan.nowOn(trace.getProgramView().getSnap()), false);
result = true;
}
catch (TraceConflictedMappingException e) {
// aww well
}
}
return result;
}
}

View File

@ -4,9 +4,9 @@
* 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.
@ -19,11 +19,11 @@ import ghidra.app.events.*;
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.plugin.core.debug.event.*;
import ghidra.app.services.*;
import ghidra.framework.options.SaveState;
import ghidra.framework.plugintool.*;
import ghidra.framework.plugintool.annotation.AutoServiceProvided;
import ghidra.framework.plugintool.util.PluginStatus;
@PluginInfo(
@ -37,6 +37,7 @@ import ghidra.framework.plugintool.util.PluginStatus;
ProgramActivatedPluginEvent.class,
ProgramLocationPluginEvent.class,
ProgramClosedPluginEvent.class,
TraceOpenedPluginEvent.class,
TraceActivatedPluginEvent.class,
TraceClosedPluginEvent.class,
},
@ -44,8 +45,13 @@ import ghidra.framework.plugintool.util.PluginStatus;
DebuggerStaticMappingService.class,
DebuggerTraceManagerService.class,
ProgramManager.class,
},
servicesProvided = {
DebuggerAutoMappingService.class,
})
public class DebuggerModulesPlugin extends AbstractDebuggerPlugin {
@AutoServiceProvided(iface = DebuggerAutoMappingService.class)
protected DebuggerModulesProvider provider;
public DebuggerModulesPlugin(PluginTool tool) {
@ -68,23 +74,17 @@ public class DebuggerModulesPlugin extends AbstractDebuggerPlugin {
@Override
public void processEvent(PluginEvent event) {
super.processEvent(event);
if (event instanceof ProgramOpenedPluginEvent ev) {
provider.programOpened(ev.getProgram());
}
else if (event instanceof ProgramActivatedPluginEvent ev) {
provider.setProgram(ev.getActiveProgram());
}
else if (event instanceof ProgramLocationPluginEvent ev) {
provider.setLocation(ev.getLocation());
}
else if (event instanceof ProgramClosedPluginEvent ev) {
provider.programClosed(ev.getProgram());
}
else if (event instanceof TraceActivatedPluginEvent ev) {
provider.coordinatesActivated(ev.getActiveCoordinates());
}
else if (event instanceof TraceClosedPluginEvent ev) {
provider.traceClosed(ev.getTrace());
switch (event) {
case ProgramOpenedPluginEvent ev -> provider.programOpened(ev.getProgram());
case ProgramActivatedPluginEvent ev -> provider.setProgram(ev.getActiveProgram());
case ProgramLocationPluginEvent ev -> provider.setLocation(ev.getLocation());
case ProgramClosedPluginEvent ev -> provider.programClosed(ev.getProgram());
case TraceOpenedPluginEvent ev -> provider.traceOpened(ev.getTrace());
case TraceActivatedPluginEvent ev -> provider
.coordinatesActivated(ev.getActiveCoordinates());
case TraceClosedPluginEvent ev -> provider.traceClosed(ev.getTrace());
default -> {
}
}
}

View File

@ -4,9 +4,9 @@
* 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.
@ -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;
@ -40,18 +40,18 @@ import ghidra.app.plugin.core.debug.DebuggerPluginPackage;
import ghidra.app.plugin.core.debug.gui.DebuggerBlockChooserDialog;
import ghidra.app.plugin.core.debug.gui.DebuggerResources;
import ghidra.app.plugin.core.debug.gui.DebuggerResources.*;
import ghidra.app.plugin.core.debug.gui.action.AutoMapSpec;
import ghidra.app.plugin.core.debug.gui.action.AutoMapSpec.AutoMapSpecConfigFieldCodec;
import ghidra.app.plugin.core.debug.gui.action.ByModuleAutoMapSpec;
import ghidra.app.plugin.core.debug.service.model.TraceRecorderTarget;
import ghidra.app.plugin.core.debug.service.modules.MapModulesBackgroundCommand;
import ghidra.app.plugin.core.debug.service.modules.MapSectionsBackgroundCommand;
import ghidra.app.services.*;
import ghidra.debug.api.action.AutoMapSpec;
import ghidra.debug.api.action.AutoMapSpec.AutoMapSpecConfigFieldCodec;
import ghidra.debug.api.model.DebuggerObjectActionContext;
import ghidra.debug.api.modules.*;
import ghidra.debug.api.modules.ModuleMapProposal.ModuleMapEntry;
import ghidra.debug.api.modules.SectionMapProposal.SectionMapEntry;
import ghidra.debug.api.tracemgr.DebuggerCoordinates;
import ghidra.framework.data.DomainObjectAdapterDB;
import ghidra.framework.main.AppInfo;
import ghidra.framework.main.DataTreeDialog;
import ghidra.framework.model.*;
@ -68,11 +68,14 @@ import ghidra.program.util.ProgramSelection;
import ghidra.trace.model.*;
import ghidra.trace.model.modules.*;
import ghidra.trace.model.program.TraceProgramView;
import ghidra.trace.model.target.TraceObjectValue;
import ghidra.trace.util.TraceEvent;
import ghidra.trace.util.TraceEvents;
import ghidra.util.*;
public class DebuggerModulesProvider extends ComponentProviderAdapter {
public class DebuggerModulesProvider extends ComponentProviderAdapter
implements DebuggerAutoMappingService {
protected static final AutoConfigState.ClassHandler<DebuggerModulesProvider> CONFIG_STATE_HANDLER =
AutoConfigState.wireHandler(DebuggerModulesProvider.class, MethodHandles.lookup());
@ -336,27 +339,82 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
}
}
protected class ForMappingTraceListener extends TraceDomainObjectListener {
public ForMappingTraceListener(AutoMapSpec spec) {
protected static class AutoMapState extends TraceDomainObjectListener
implements TransactionListener {
private final PluginTool tool;
private final Trace trace;
private final AutoMapSpec spec;
private volatile boolean couldHaveChanged = true;
private volatile String infosLastTime = "";
public AutoMapState(PluginTool tool, Trace trace, AutoMapSpec spec) {
this.tool = tool;
this.trace = trace;
this.spec = spec;
for (TraceEvent<?, ?> type : spec.getChangeTypes()) {
listenFor(type, this::changed);
}
// Delete this if/when TraceRecorderTarget is removed
listenFor(TraceEvents.BYTES_CHANGED, this::memoryChanged);
listenFor(TraceEvents.VALUE_CREATED, this::valueCreated);
listenForUntyped(DomainObjectEvent.RESTORED, this::objectRestored);
trace.addListener(this);
trace.addTransactionListener(this);
}
public void dispose() {
trace.removeListener(this);
trace.removeTransactionListener(this);
}
private void changed() {
cueAutoMap = true;
couldHaveChanged = true;
}
private void memoryChanged(TraceAddressSnapRange range) {
if (range.getRange().getAddressSpace().isRegisterSpace()) {
private void valueCreated(TraceObjectValue value) {
couldHaveChanged = true;
}
private void objectRestored(DomainObjectChangeRecord rec) {
couldHaveChanged = true;
}
@Override
public void transactionStarted(DomainObjectAdapterDB domainObj, TransactionInfo tx) {
}
@Override
public void transactionEnded(DomainObjectAdapterDB domainObj) {
checkAutoMap();
}
@Override
public void undoStackChanged(DomainObjectAdapterDB domainObj) {
}
@Override
public void undoRedoOccurred(DomainObjectAdapterDB domainObj) {
}
private void checkAutoMap() {
if (!couldHaveChanged) {
return;
}
if (current.getTarget() instanceof TraceRecorderTarget) {
doCuedAutoMap();
couldHaveChanged = false;
String infosThisTime = spec.getInfoForObjects(trace);
if (Objects.equals(infosThisTime, infosLastTime)) {
return;
}
infosLastTime = infosThisTime;
spec.runTask(tool, trace);
}
public void forceMap() {
couldHaveChanged = true;
infosLastTime = "";
checkAutoMap();
}
}
@ -534,8 +592,8 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
@AutoConfigStateField
boolean filterSectionsByModules = false;
boolean cueAutoMap;
private ForMappingTraceListener forMappingListener;
private final Map<Trace, AutoMapState> autoMapStateByTrace = new WeakHashMap<>();
private AutoMapState forMappingListener;
DockingAction actionImportMissingModule;
DockingAction actionMapMissingModule;
@ -612,6 +670,10 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
}
protected void dispose() {
for (AutoMapState state : autoMapStateByTrace.values()) {
state.dispose();
}
if (consoleService != null) {
removeResolutionActionMaybe(consoleService, actionImportMissingModule);
removeResolutionActionMaybe(consoleService, actionMapMissingModule);
@ -885,12 +947,20 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
}
private void doSetAutoMapSpec(AutoMapSpec autoMapSpec) {
if (this.autoMapSpec == autoMapSpec) {
this.autoMapSpec = autoMapSpec;
Trace trace = current.getTrace();
if (trace == null) {
return;
}
removeOldTraceListener();
this.autoMapSpec = autoMapSpec;
addNewTraceListener();
AutoMapState state = autoMapStateByTrace.remove(trace);
if (state != null && state.spec.equals(autoMapSpec)) {
autoMapStateByTrace.put(trace, state);
}
else {
state.dispose();
autoMapStateByTrace.put(trace, new AutoMapState(tool, trace, autoMapSpec));
}
}
private void activatedImportMissingModule(DebuggerMissingModuleActionContext context) {
@ -1256,9 +1326,14 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
}
public void programOpened(Program program) {
AutoMapState mapState = autoMapStateByTrace.get(current.getTrace());
// TODO: All open traces, or just the current one?
if (mapState == null) {
// Could be, e.g., current is NOWHERE
return;
}
// TODO: Debounce this?
cueAutoMap = true;
doCuedAutoMap();
mapState.forceMap();
}
public void programClosed(Program program) {
@ -1268,43 +1343,38 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
cleanMissingProgramMessages(null, program);
}
public void traceOpened(Trace trace) {
autoMapStateByTrace.computeIfAbsent(trace, t -> new AutoMapState(tool, trace, autoMapSpec));
}
public void traceClosed(Trace trace) {
AutoMapState state = autoMapStateByTrace.remove(trace);
if (state != null) {
state.dispose();
}
cleanMissingProgramMessages(trace, null);
}
protected void addNewTraceListener() {
if (current.getTrace() != null && autoMapSpec != null) {
forMappingListener = new ForMappingTraceListener(autoMapSpec);
current.getTrace().addListener(forMappingListener);
}
}
protected void removeOldTraceListener() {
if (forMappingListener != null) {
if (current.getTrace() != null) {
current.getTrace().removeListener(forMappingListener);
}
forMappingListener = null;
}
}
public void coordinatesActivated(DebuggerCoordinates coordinates) {
if (sameCoordinates(current, coordinates)) {
current = coordinates;
return;
}
boolean changeTrace = current.getTrace() != coordinates.getTrace();
Trace newTrace = coordinates.getTrace();
boolean changeTrace = current.getTrace() != newTrace;
if (changeTrace) {
myActionContext = null;
removeOldTraceListener();
}
current = coordinates;
if (changeTrace) {
addNewTraceListener();
AutoMapState amState = autoMapStateByTrace.get(newTrace);
if (amState != null) {
// Can't just set field directly. Want GUI update.
setAutoMapSpec(amState.spec);
}
if (Trace.isLegacy(coordinates.getTrace())) {
if (Trace.isLegacy(newTrace)) {
modulesPanel.coordinatesActivated(DebuggerCoordinates.NOWHERE);
sectionsPanel.coordinatesActivated(DebuggerCoordinates.NOWHERE);
legacyModulesPanel.coordinatesActivated(coordinates);
@ -1332,22 +1402,6 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
}
contextChanged();
if (coordinates.getTarget() instanceof TraceRecorderTarget) {
// HACK while TraceRecorderTarget is still around
cueAutoMap = true;
}
doCuedAutoMap();
}
private void doCuedAutoMap() {
if (cueAutoMap) {
cueAutoMap = false;
Trace trace = current.getTrace();
if (autoMapSpec != null && trace != null) {
autoMapSpec.runTask(tool, trace);
}
}
}
public void setSelectedModules(Set<TraceModule> sel) {
@ -1398,10 +1452,17 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
actionAutoMap.setCurrentActionStateByUserData(spec);
}
@Override
public AutoMapSpec getAutoMapSpec() {
return autoMapSpec;
}
@Override
public AutoMapSpec getAutoMapSpec(Trace trace) {
AutoMapState state = autoMapStateByTrace.get(trace);
return state == null ? autoMapSpec : state.spec;
}
public void writeConfigState(SaveState saveState) {
CONFIG_STATE_HANDLER.writeConfigState(this, saveState);
}

View File

@ -4,9 +4,9 @@
* 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.
@ -253,12 +253,15 @@ public class DebuggerStaticMappingServicePlugin extends Plugin
private void objectRestored() {
synchronized (lock) {
Set<Program> fromClosure = collectAffectedByTrace(trace);
var old = Map.copyOf(outbound);
outbound.clear();
loadOutboundEntries(); // Also places/updates corresponding inbound entries
clearOutboundEntries();
loadOutboundEntries(); // Also places corresponding inbound entries
if (!old.equals(outbound)) {
// TODO: What about removed corresponding inbound entries?
doAffectedByTraceClosed(trace);
if (!fromClosure.isEmpty()) {
traceAffected(trace);
}
programsAffected(fromClosure);
doAffectedByTraceOpened(trace);
}
}
@ -309,9 +312,7 @@ public class DebuggerStaticMappingServicePlugin extends Plugin
destInfo.inbound.put(me, me.getStaticAddress());
}
protected void removeOutboundAndInboundEntries(MappingEntry me) {
outbound.remove(me.getTraceAddressSnapRange());
protected void removeInboundEntryFor(MappingEntry me) {
InfoPerProgram destInfo = trackedProgramInfo.get(me.getStaticProgramURL());
if (destInfo == null) {
return; // Not opened
@ -319,6 +320,11 @@ public class DebuggerStaticMappingServicePlugin extends Plugin
destInfo.inbound.remove(me);
}
protected void removeOutboundAndInboundEntries(MappingEntry me) {
outbound.remove(me.getTraceAddressSnapRange());
removeInboundEntryFor(me);
}
protected void loadOutboundEntries() {
TraceStaticMappingManager manager = trace.getStaticMappingManager();
for (TraceStaticMapping mapping : manager.getAllEntries()) {
@ -326,6 +332,13 @@ public class DebuggerStaticMappingServicePlugin extends Plugin
}
}
protected void clearOutboundEntries() {
for (MappingEntry me : outbound.values()) {
removeInboundEntryFor(me);
}
outbound.clear();
}
public boolean programOpened(Program other, InfoPerProgram otherInfo) {
boolean result = false;
for (MappingEntry me : outbound.values()) {
@ -347,8 +360,14 @@ public class DebuggerStaticMappingServicePlugin extends Plugin
public Set<Program> getOpenMappedProgramsAtSnap(long snap) {
Set<Program> result = new HashSet<>();
Set<MappingEntry> toClean = new HashSet<>();
for (Entry<TraceAddressSnapRange, MappingEntry> out : outbound.entrySet()) {
MappingEntry me = out.getValue();
if (me.mapping.isDeleted()) {
Msg.warn(this, "Encountered deleted mapping: " + me.mapping);
toClean.add(me);
continue;
}
if (!me.isStaticProgramOpen()) {
continue;
}
@ -357,27 +376,42 @@ public class DebuggerStaticMappingServicePlugin extends Plugin
}
result.add(me.program);
}
outbound.values().removeAll(toClean);
return result;
}
public ProgramLocation getOpenMappedLocations(Address address, Lifespan span) {
TraceAddressSnapRange at = new ImmutableTraceAddressSnapRange(address, span);
Set<MappingEntry> toClean = new HashSet<>();
for (Entry<TraceAddressSnapRange, MappingEntry> out : outbound.entrySet()) {
if (out.getKey().intersects(at)) {
MappingEntry me = out.getValue();
if (me.mapping.isDeleted()) {
Msg.warn(this, "Encountered deleted mapping: " + me.mapping);
toClean.add(me);
continue;
}
if (me.isStaticProgramOpen()) {
outbound.values().removeAll(toClean);
return me.mapTraceAddressToProgramLocation(address);
}
}
}
outbound.values().removeAll(toClean);
return null;
}
protected void collectOpenMappedPrograms(AddressRange rng, Lifespan span,
Map<Program, Collection<MappedAddressRange>> result) {
TraceAddressSnapRange tatr = new ImmutableTraceAddressSnapRange(rng, span);
Set<MappingEntry> toClean = new HashSet<>();
for (Entry<TraceAddressSnapRange, MappingEntry> out : outbound.entrySet()) {
MappingEntry me = out.getValue();
if (me.mapping.isDeleted()) {
Msg.warn(this, "Encountered deleted mapping: " + me.mapping);
toClean.add(me);
continue;
}
if (me.program == null) {
continue;
}
@ -389,6 +423,7 @@ public class DebuggerStaticMappingServicePlugin extends Plugin
result.computeIfAbsent(me.program, p -> new TreeSet<>())
.add(new MappedAddressRange(srcRng, dstRng));
}
outbound.values().removeAll(toClean);
}
public Map<Program, Collection<MappedAddressRange>> getOpenMappedViews(AddressSetView set,
@ -402,14 +437,21 @@ public class DebuggerStaticMappingServicePlugin extends Plugin
protected void collectMappedProgramURLsInView(AddressRange rng, Lifespan span,
Set<URL> result) {
Set<MappingEntry> toClean = new HashSet<>();
TraceAddressSnapRange tatr = new ImmutableTraceAddressSnapRange(rng, span);
for (Entry<TraceAddressSnapRange, MappingEntry> out : outbound.entrySet()) {
MappingEntry me = out.getValue();
if (me.mapping.isDeleted()) {
Msg.warn(this, "Encountered deleted mapping: " + me.mapping);
toClean.add(me);
continue;
}
if (!out.getKey().intersects(tatr)) {
continue;
}
MappingEntry me = out.getValue();
result.add(me.getStaticProgramURL());
}
outbound.values().removeAll(toClean);
}
public Set<URL> getMappedProgramURLsInView(AddressSetView set, Lifespan span) {
@ -455,11 +497,19 @@ public class DebuggerStaticMappingServicePlugin extends Plugin
}
public boolean isMappedInTrace(Trace trace) {
Set<MappingEntry> toClean = new HashSet<>();
for (MappingEntry me : inbound.keySet()) {
if (me.mapping.isDeleted()) {
Msg.warn(this, "Encountered deleted mapping: " + me.mapping);
toClean.add(me);
continue;
}
if (Objects.equals(trace, me.getTrace())) {
inbound.keySet().removeAll(toClean);
return true;
}
}
inbound.keySet().removeAll(toClean);
return false;
}
@ -476,30 +526,43 @@ public class DebuggerStaticMappingServicePlugin extends Plugin
public Set<TraceLocation> getOpenMappedTraceLocations(Address address) {
Set<TraceLocation> result = new HashSet<>();
Set<MappingEntry> toClean = new HashSet<>();
for (Entry<MappingEntry, Address> inPreceding : inbound.headMapByValue(address, true)
.entrySet()) {
MappingEntry me = inPreceding.getKey();
if (me.mapping.isDeleted()) {
Msg.warn(this, "Encountered deleted mapping: " + me.mapping);
toClean.add(me);
continue;
}
Address start = inPreceding.getValue();
if (start == null) {
continue;
}
MappingEntry me = inPreceding.getKey();
if (!me.isInProgramRange(address)) {
continue;
}
result.add(me.mapProgramAddressToTraceLocation(address));
}
inbound.keySet().removeAll(toClean);
return result;
}
public TraceLocation getOpenMappedTraceLocation(Trace trace, Address address, long snap) {
// TODO: Map by trace?
Set<MappingEntry> toClean = new HashSet<>();
for (Entry<MappingEntry, Address> inPreceding : inbound.headMapByValue(address, true)
.entrySet()) {
MappingEntry me = inPreceding.getKey();
if (me.mapping.isDeleted()) {
Msg.warn(this, "Encountered deleted mapping: " + me.mapping);
toClean.add(me);
continue;
}
Address start = inPreceding.getValue();
if (start == null) {
continue;
}
MappingEntry me = inPreceding.getKey();
if (me.getTrace() != trace) {
continue;
}
@ -509,21 +572,29 @@ public class DebuggerStaticMappingServicePlugin extends Plugin
if (!me.isInTraceLifespan(snap)) {
continue;
}
inbound.keySet().removeAll(toClean);
return me.mapProgramAddressToTraceLocation(address);
}
inbound.keySet().removeAll(toClean);
return null;
}
protected void collectOpenMappedViews(AddressRange rng,
Map<TraceSpan, Collection<MappedAddressRange>> result) {
Set<MappingEntry> toClean = new HashSet<>();
for (Entry<MappingEntry, Address> inPreceeding : inbound
.headMapByValue(rng.getMaxAddress(), true)
.entrySet()) {
MappingEntry me = inPreceeding.getKey();
if (me.mapping.isDeleted()) {
Msg.warn(this, "Encountered deleted mapping: " + me.mapping);
toClean.add(me);
continue;
}
Address start = inPreceeding.getValue();
if (start == null) {
continue;
}
MappingEntry me = inPreceeding.getKey();
if (!me.isInProgramRange(rng)) {
continue;
}
@ -533,6 +604,7 @@ public class DebuggerStaticMappingServicePlugin extends Plugin
result.computeIfAbsent(me.getTraceSpan(), p -> new TreeSet<>())
.add(new MappedAddressRange(srcRange, dstRange));
}
inbound.keySet().removeAll(toClean);
}
public Map<TraceSpan, Collection<MappedAddressRange>> getOpenMappedViews(
@ -609,6 +681,13 @@ public class DebuggerStaticMappingServicePlugin extends Plugin
}
}
private void programsAffected(Collection<Program> programs) {
synchronized (affectedTraces) {
affectedPrograms.addAll(programs);
changeDebouncer.contact(null);
}
}
@Override
public void addChangeListener(DebuggerStaticMappingChangeListener l) {
changeListeners.add(l);
@ -706,13 +785,22 @@ public class DebuggerStaticMappingServicePlugin extends Plugin
}
}
private void doAffectedByTraceOpened(Trace trace) {
private Set<Program> collectAffectedByTrace(Trace trace) {
Set<Program> set = new HashSet<>();
for (InfoPerProgram info : trackedProgramInfo.values()) {
if (info.isMappedInTrace(trace)) {
traceAffected(trace);
programAffected(info.program);
set.add(info.program);
}
}
return set;
}
private void doAffectedByTraceOpened(Trace trace) {
Set<Program> set = collectAffectedByTrace(trace);
if (!set.isEmpty()) {
traceAffected(trace);
programsAffected(set);
}
}
private void traceOpened(Trace trace) {

View File

@ -4,9 +4,9 @@
* 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.
@ -19,15 +19,10 @@ import java.awt.Component;
import java.awt.event.*;
import java.beans.PropertyEditor;
import java.math.BigInteger;
import java.util.Map;
import java.util.function.Function;
import ghidra.debug.api.action.LocationTrackingSpec;
import ghidra.framework.options.*;
import ghidra.program.model.address.AddressRange;
import ghidra.util.MathUtilities;
import ghidra.util.Msg;
import ghidra.util.classfinder.ClassSearcher;
public enum MiscellaneousUtils {
;
@ -87,23 +82,6 @@ public enum MiscellaneousUtils {
});
}
public static <T> void collectUniqueInstances(Class<T> cls, Map<String, T> map,
Function<T, String> keyFunc) {
// This is wasteful. Existing instances will be re-instantiated and thrown away
for (T t : ClassSearcher.getInstances(cls)) {
String key = keyFunc.apply(t);
T exists = map.get(key);
if (exists != null) {
if (exists.getClass().equals(t.getClass())) {
continue;
}
Msg.error(LocationTrackingSpec.class,
cls.getSimpleName() + " conflict over key: " + key);
}
map.put(key, t);
}
}
public static long lengthMin(long a, long b) {
if (a == 0) {
return b;

View File

@ -4,9 +4,9 @@
* 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.
@ -32,7 +32,6 @@ import ghidra.app.plugin.core.debug.gui.*;
import ghidra.app.plugin.core.debug.gui.DebuggerBlockChooserDialog.MemoryBlockRow;
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractImportFromFileSystemAction;
import ghidra.app.plugin.core.debug.gui.DebuggerResources.AbstractSelectAddressesAction;
import ghidra.app.plugin.core.debug.gui.action.AutoMapSpec;
import ghidra.app.plugin.core.debug.gui.action.NoneAutoMapSpec;
import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingPlugin;
import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingProvider;
@ -42,6 +41,7 @@ import ghidra.app.plugin.core.debug.gui.modules.DebuggerModulesProvider.MapSecti
import ghidra.app.plugin.core.debug.gui.modules.DebuggerSectionMapProposalDialog.SectionMapTableColumns;
import ghidra.app.plugin.core.debug.service.tracemgr.DebuggerTraceManagerServiceTestAccess;
import ghidra.app.services.DebuggerListingService;
import ghidra.debug.api.action.AutoMapSpec;
import ghidra.debug.api.modules.ModuleMapProposal.ModuleMapEntry;
import ghidra.debug.api.modules.SectionMapProposal.SectionMapEntry;
import ghidra.framework.main.DataTreeDialog;

View File

@ -4,9 +4,9 @@
* 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.

View File

@ -4,9 +4,9 @@
* 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.
@ -148,8 +148,7 @@ public class DBTraceObjectManager implements TraceObjectManager, DBTraceManager
}
record ObjectsContainingKey(long snap, Address address, String key,
Class<? extends TraceObjectInterface> iface) {
}
Class<? extends TraceObjectInterface> iface) {}
protected final ReadWriteLock lock;
protected final DBTrace trace;