mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-23 12:49:45 +00:00
GP-4713: Launch mapping uses AutoMapSpec. Fix StaticMappingService.
This commit is contained in:
parent
ebb4027d8b
commit
d95200b166
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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.");
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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 -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user