diff --git a/Ghidra/Debug/Debugger-api/src/main/java/ghidra/app/services/DebuggerStaticMappingService.java b/Ghidra/Debug/Debugger-api/src/main/java/ghidra/app/services/DebuggerStaticMappingService.java index 8bfcad5784..a51084c001 100644 --- a/Ghidra/Debug/Debugger-api/src/main/java/ghidra/app/services/DebuggerStaticMappingService.java +++ b/Ghidra/Debug/Debugger-api/src/main/java/ghidra/app/services/DebuggerStaticMappingService.java @@ -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. @@ -241,6 +241,7 @@ public interface DebuggerStaticMappingService { * @param entries the entries to add * @param monitor a monitor to cancel the operation * @param truncateExisting true to delete or truncate the lifespan of overlapping entries + * @throws CancelledException if the user cancels * @see #addMapping(TraceLocation, ProgramLocation, long, boolean) * @throws TraceConflictedMappingException if a conflicting mapping overlaps the source and * {@code truncateExisting} is false. @@ -259,6 +260,7 @@ public interface DebuggerStaticMappingService { * @param entries the entries to add * @param monitor a monitor to cancel the operation * @param truncateExisting true to delete or truncate the lifespan of overlapping entries + * @throws CancelledException if the user cancels * @see #addMapping(TraceLocation, ProgramLocation, long, boolean) */ void addSectionMappings(Collection entries, TaskMonitor monitor, @@ -275,6 +277,7 @@ public interface DebuggerStaticMappingService { * @param entries the entries to add * @param monitor a monitor to cancel the operation * @param truncateExisting true to delete or truncate the lifespan of overlapping entries + * @throws CancelledException if the user cancels * @see #addMapping(TraceLocation, ProgramLocation, long, boolean) */ void addRegionMappings(Collection entries, TaskMonitor monitor, @@ -421,17 +424,18 @@ public interface DebuggerStaticMappingService { * The service maintains an index of likely module names to domain files in the active project. * This will search that index for the module's full file path. Failing that, it will search * just for the module's file name. Among the programs found, it first prefers those whose - * module name list (see {@link ProgramModuleIndexer#setModulePaths(Program, List)}) include the - * sought module. Then, it prefers those whose executable path (see - * {@link Program#setExecutablePath(String)}) matches the sought module. Finally, it prefers - * matches on the program name and the domain file name. Ties in name matching are broken by - * looking for domain files in the same folders as those programs already mapped into the trace - * in the given address space. + * module name list includes the sought module. Then, it prefers those whose executable path + * (see {@link Program#setExecutablePath(String)}) matches the sought module. Finally, it + * prefers matches on the program name and the domain file name. Ties in name matching are + * broken by looking for domain files in the same folders as those programs already mapped into + * the trace in the given address space. * + * @param space the fallback address space if the module is missing its base * @param module the trace module + * @param snap the snapshot to consider * @return the, possibly empty, set of probable matches */ - DomainFile findBestModuleProgram(AddressSpace space, TraceModule module); + DomainFile findBestModuleProgram(AddressSpace space, TraceModule module, long snap); /** * Propose a module map for the given module to the given program @@ -440,14 +444,15 @@ public interface DebuggerStaticMappingService { * Note, no sanity check is performed on the given parameters. This will simply propose the * given module-program pair. It is strongly advised to use * {@link ModuleMapProposal#computeScore()} to assess the proposal. Alternatively, use - * {@link #proposeModuleMap(TraceModule, Collection)} to have the service select the best-scored - * mapping from a collection of proposed programs. + * {@link #proposeModuleMap(TraceModule, long, Collection)} to have the service select the + * best-scored mapping from a collection of proposed programs. * * @param module the module to consider + * @param snap the source snapshot key * @param program the destination program to consider * @return the proposal */ - ModuleMapProposal proposeModuleMap(TraceModule module, Program program); + ModuleMapProposal proposeModuleMap(TraceModule module, long snap, Program program); /** * Compute the best-scored module map for the given module and programs @@ -460,10 +465,12 @@ public interface DebuggerStaticMappingService { * @see ModuleMapProposal#computeScore() * * @param module the module to consider + * @param snap the source snapshot key * @param programs a set of proposed destination programs * @return the best-scored proposal, or {@code null} if no program is proposed */ - ModuleMapProposal proposeModuleMap(TraceModule module, Collection programs); + ModuleMapProposal proposeModuleMap(TraceModule module, long snap, + Collection programs); /** * Compute the "best" map of trace module to program for each given module given a collection of @@ -476,11 +483,13 @@ public interface DebuggerStaticMappingService { * {@code null} values. * * @param modules the modules to map + * @param snap the source snapshot key * @param programs the set of proposed destination programs * @return the proposal */ Map proposeModuleMaps( - Collection modules, Collection programs); + Collection modules, long snap, + Collection programs); /** * Propose a singleton section map from the given section to the given program memory block @@ -489,15 +498,17 @@ public interface DebuggerStaticMappingService { * Note, no sanity check is performed on the given parameters. This will simply give a singleton * map of the given entry. It is strongly advised to use * {@link SectionMapProposal#computeScore()} to assess the proposal. Alternatively, use - * {@link #proposeSectionMap(TraceModule, Collection)} to have the service select the + * {@link #proposeSectionMap(TraceModule, long, Collection)} to have the service select the * best-scored mapping from a collection of proposed programs. * * @param section the section to map + * @param snap the source snapshot key * @param program the destination program * @param block the memory block in the destination program * @return the proposed map */ - SectionMapProposal proposeSectionMap(TraceSection section, Program program, MemoryBlock block); + SectionMapProposal proposeSectionMap(TraceSection section, long snap, Program program, + MemoryBlock block); /** * Propose a section map for the given module to the given program @@ -506,14 +517,15 @@ public interface DebuggerStaticMappingService { * Note, no sanity check is performed on the given parameters. This will do its best to map * sections from the given module to memory blocks in the given program. It is strongly advised * to use {@link SectionMapProposal#computeScore()} to assess the proposal. Alternatively, use - * {@link #proposeSectionMap(TraceModule, Collection)} to have the service select the + * {@link #proposeSectionMap(TraceModule, long, Collection)} to have the service select the * best-scored mapping from a collection of proposed programs. * * @param module the module whose sections to map + * @param snap the source snapshot key * @param program the destination program whose blocks to consider * @return the proposed map */ - SectionMapProposal proposeSectionMap(TraceModule module, Program program); + SectionMapProposal proposeSectionMap(TraceModule module, long snap, Program program); /** * Proposed the best-scored section map for the given module and programs @@ -526,10 +538,11 @@ public interface DebuggerStaticMappingService { * @see SectionMapProposal#computeScore() * * @param module the module whose sections to map + * @param snap the source snapshot key * @param programs a set of proposed destination programs * @return the best-scored map, or {@code null} if no program is proposed */ - SectionMapProposal proposeSectionMap(TraceModule module, + SectionMapProposal proposeSectionMap(TraceModule module, long snap, Collection programs); /** @@ -543,11 +556,13 @@ public interface DebuggerStaticMappingService { * {@code null} values. * * @param modules the modules to map + * @param snap the source snapshot key * @param programs a set of proposed destination programs * @return the composite proposal */ Map proposeSectionMaps( - Collection modules, Collection programs); + Collection modules, long snap, + Collection programs); /** * Propose a singleton region map from the given region to the given program memory block @@ -556,15 +571,16 @@ public interface DebuggerStaticMappingService { * Note, no sanity check is performed on the given parameters. This will simply give a singleton * map of the given entry. It is strongly advised to use * {@link RegionMapProposal#computeScore()} to assess the proposal. Alternatively, use - * {@link #proposeRegionMap(Collection, Collection)} to have the service select the best-scored - * mapping from a collection of proposed programs. + * {@link #proposeRegionMaps(Collection, long, Collection)} to have the service select the + * best-scored mapping from a collection of proposed programs. * * @param region the region to map + * @param snap the source snapshot key * @param program the destination program * @param block the memory block in the destination program * @return the proposed map */ - RegionMapProposal proposeRegionMap(TraceMemoryRegion region, Program program, + RegionMapProposal proposeRegionMap(TraceMemoryRegion region, long snap, Program program, MemoryBlock block); /** @@ -575,14 +591,16 @@ public interface DebuggerStaticMappingService { * regions to memory blocks in the given program. For the best results, regions should all * comprise the same module, and the minimum address among the regions should be the module's * base address. It is strongly advised to use {@link RegionMapProposal#computeScore()} to - * assess the proposal. Alternatively, use {@link #proposeRegionMap(Collection, Collection)} to - * have the service select the best-scored mapping from a collection of proposed programs. + * assess the proposal. Alternatively, use + * {@link #proposeRegionMaps(Collection, long, Collection)} to have the service select the + * best-scored mapping from a collection of proposed programs. * - * @param region the region to map + * @param regions the regions to map + * @param snap the source snapshot key * @param program the destination program whose blocks to consider * @return the proposed map */ - RegionMapProposal proposeRegionMap(Collection regions, + RegionMapProposal proposeRegionMap(Collection regions, long snap, Program program); /** @@ -597,11 +615,12 @@ public interface DebuggerStaticMappingService { * regions into likely modules. For the best results, the minimum address of each module should * be among the regions. * - * @param modules the modules to map + * @param regions the regions to map + * @param snap the source snapshot key * @param programs a set of proposed destination programs * @return the composite proposal */ Map, RegionMapProposal> proposeRegionMaps( - Collection regions, + Collection regions, long snap, Collection programs); } diff --git a/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/action/AutoMapSpec.java b/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/action/AutoMapSpec.java index 663d21669b..48614da42e 100644 --- a/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/action/AutoMapSpec.java +++ b/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/action/AutoMapSpec.java @@ -93,7 +93,7 @@ public interface AutoMapSpec extends ExtensionPoint { boolean objectHasType(TraceObjectValue value); - String getInfoForObjects(Trace trace); + String getInfoForObjects(Trace trace, long snap); default boolean hasTask() { return true; @@ -103,7 +103,7 @@ public interface AutoMapSpec extends ExtensionPoint { return getMenuName(); } - default void runTask(PluginTool tool, Trace trace) { + default void runTask(PluginTool tool, Trace trace, long snap) { DebuggerStaticMappingService mappingService = tool.getService(DebuggerStaticMappingService.class); ProgramManager programManager = tool.getService(ProgramManager.class); @@ -114,7 +114,7 @@ public interface AutoMapSpec extends ExtensionPoint { @Override public boolean applyTo(Trace trace, TaskMonitor monitor) { try { - performMapping(mappingService, trace, programManager, monitor); + performMapping(mappingService, trace, snap, programManager, monitor); return true; } catch (CancelledException e) { @@ -132,12 +132,13 @@ public interface AutoMapSpec extends ExtensionPoint { * * @param mappingService the mapping service * @param trace the trace + * @param snap the snap * @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, + boolean performMapping(DebuggerStaticMappingService mappingService, Trace trace, long snap, List programs, TaskMonitor monitor) throws CancelledException; /** @@ -145,13 +146,15 @@ public interface AutoMapSpec extends ExtensionPoint { * * @param mappingService the mapping service * @param trace the trace + * @param snap the snap * @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); + long snap, ProgramManager programManager, TaskMonitor monitor) + throws CancelledException { + return performMapping(mappingService, trace, snap, programs(programManager), monitor); } } diff --git a/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/model/DebuggerObjectActionContext.java b/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/model/DebuggerObjectActionContext.java index ec6563492d..738d9743ef 100644 --- a/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/model/DebuggerObjectActionContext.java +++ b/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/model/DebuggerObjectActionContext.java @@ -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,14 +25,20 @@ import ghidra.trace.model.target.TraceObjectValue; public class DebuggerObjectActionContext extends DefaultActionContext { private final List objectValues; + private final long snap; public DebuggerObjectActionContext(Collection objectValues, - ComponentProvider provider, Component sourceComponent) { + ComponentProvider provider, Component sourceComponent, long snap) { super(provider, sourceComponent); this.objectValues = List.copyOf(objectValues); + this.snap = snap; } public List getObjectValues() { return objectValues; } + + public long getSnap() { + return snap; + } } diff --git a/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/modules/ModuleMapProposal.java b/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/modules/ModuleMapProposal.java index 3deea88c62..cab6ea99e4 100644 --- a/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/modules/ModuleMapProposal.java +++ b/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/modules/ModuleMapProposal.java @@ -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. @@ -33,6 +33,13 @@ public interface ModuleMapProposal extends MapProposal !r.isWrite()); + AddressSetView readOnly = + memoryManager.getRegionsAddressSetWith(snap, r -> !r.isWrite(snap)); AddressSetView everKnown = memoryManager.getAddressesWithState(Lifespan.since(snap), s -> s == TraceMemoryState.KNOWN); AddressSetView roEverKnown = new IntersectionAddressSetView(readOnly, everKnown); diff --git a/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/service/tracermi/TraceRmiTarget.java b/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/service/tracermi/TraceRmiTarget.java index 327bea8d65..0254bf5b13 100644 --- a/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/service/tracermi/TraceRmiTarget.java +++ b/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/service/tracermi/TraceRmiTarget.java @@ -1334,7 +1334,7 @@ public class TraceRmiTarget extends AbstractTarget { RemoteParameter paramFrame = writeReg.params.get("frame"); if (paramFrame != null) { TraceStack stack = trace.getStackManager().getLatestStack(thread, getSnap()); - TraceStackFrame frame = stack.getFrame(frameLevel, false); + TraceStackFrame frame = stack.getFrame(getSnap(), frameLevel, false); if (!(frame instanceof TraceObjectStackFrame tof)) { Msg.error(this, "Non-object trace with TraceRmi!"); return AsyncUtils.nil(); @@ -1568,10 +1568,11 @@ public class TraceRmiTarget extends AbstractTarget { @Override public boolean isBreakpointValid(TraceBreakpoint breakpoint) { - if (breakpoint.getName().endsWith("emu-" + breakpoint.getMinAddress())) { + long snap = getSnap(); + if (breakpoint.getName(snap).endsWith("emu-" + breakpoint.getMinAddress(snap))) { return false; } - if (!breakpoint.isAlive(getSnap())) { + if (!breakpoint.isValid(snap)) { return false; } return true; diff --git a/Ghidra/Debug/Debugger/ghidra_scripts/PopulateDemoTrace.java b/Ghidra/Debug/Debugger/ghidra_scripts/PopulateDemoTrace.java index aaa0000095..97f410f72c 100644 --- a/Ghidra/Debug/Debugger/ghidra_scripts/PopulateDemoTrace.java +++ b/Ghidra/Debug/Debugger/ghidra_scripts/PopulateDemoTrace.java @@ -288,9 +288,8 @@ public class PopulateDemoTrace extends GhidraScript { int pc2 = 0; /** - * For clarity, I will add each tick to the trace in its own transaction. The - * Transaction class eases the syntax and reduces errors in starting and ending - * transactions. + * For clarity, I will add each tick to the trace in its own transaction. The Transaction + * class eases the syntax and reduces errors in starting and ending transactions. */ try (Transaction tx = trace.openTransaction("Populate First Snapshot")) { /** @@ -699,7 +698,7 @@ public class PopulateDemoTrace extends GhidraScript { long snap = trace.getTimeManager().createSnapshot("Stepped Thread 2: CALL exit").getKey(); - thread2.setDestructionSnap(snap); + thread2.remove(snap); } /** @@ -709,7 +708,7 @@ public class PopulateDemoTrace extends GhidraScript { long snap = trace.getTimeManager().createSnapshot("Stepped Thread 1: CALL exit").getKey(); - thread1.setDestructionSnap(snap); + thread1.remove(snap); } /** diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/disassemble/DebuggerDisassemblerPlugin.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/disassemble/DebuggerDisassemblerPlugin.java index 777e85b6f2..8f487d6f05 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/disassemble/DebuggerDisassemblerPlugin.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/disassemble/DebuggerDisassemblerPlugin.java @@ -117,13 +117,13 @@ public class DebuggerDisassemblerPlugin extends Plugin implements PopupActionPro // It has never been known up to this snap return null; } - TraceMemoryRegion region = - memoryManager.getRegionContaining(mrent.getKey().getY1(), start); - if (region == null || region.isWrite()) { + long ks = mrent.getKey().getY1(); + TraceMemoryRegion region = memoryManager.getRegionContaining(ks, start); + if (region == null || region.isWrite(ks)) { // It could have changed this snap, so unknown return null; } - return mrent.getKey().getY1(); + return ks; } /** @@ -133,8 +133,8 @@ public class DebuggerDisassemblerPlugin extends Plugin implements PopupActionPro * The view contains the addresses in {@code known | (readOnly & everKnown)}, where {@code * known} is the set of addresses in the {@link TraceMemoryState#KNOWN} state, {@code readOnly} * is the set of addresses in a {@link TraceMemoryRegion} having - * {@link TraceMemoryRegion#isWrite()} false, and {@code everKnown} is the set of addresses in - * the {@link TraceMemoryState#KNOWN} state in any previous snapshot. + * {@link TraceMemoryRegion#isWrite(long)} false, and {@code everKnown} is the set of addresses + * in the {@link TraceMemoryState#KNOWN} state in any previous snapshot. * *

* In plainer English, we want addresses that have freshly read bytes right now, or addresses in @@ -158,7 +158,7 @@ public class DebuggerDisassemblerPlugin extends Plugin implements PopupActionPro } TraceMemoryManager memoryManager = trace.getMemoryManager(); AddressSetView readOnly = - memoryManager.getRegionsAddressSetWith(ks, r -> !r.isWrite()); + memoryManager.getRegionsAddressSetWith(ks, r -> !r.isWrite(ks)); AddressSetView everKnown = memoryManager.getAddressesWithState(Lifespan.since(ks), s -> s == TraceMemoryState.KNOWN); AddressSetView roEverKnown = new IntersectionAddressSetView(readOnly, everKnown); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/DebuggerBlockChooserDialog.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/DebuggerBlockChooserDialog.java index f16cce9eac..4034cabe05 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/DebuggerBlockChooserDialog.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/DebuggerBlockChooserDialog.java @@ -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. @@ -81,18 +81,19 @@ public class DebuggerBlockChooserDialog extends ReusableDialogComponentProvider return score; } - public double score(TraceSection section, DebuggerStaticMappingService service) { + public double score(TraceSection section, long snap, DebuggerStaticMappingService service) { if (section == null) { return score = 0; } - return score = service.proposeSectionMap(section, program, block).computeScore(); + return score = service.proposeSectionMap(section, snap, program, block).computeScore(); } - public double score(TraceMemoryRegion region, DebuggerStaticMappingService service) { + public double score(TraceMemoryRegion region, long snap, + DebuggerStaticMappingService service) { if (region == null) { return score = 0; } - return score = service.proposeRegionMap(region, program, block).computeScore(); + return score = service.proposeRegionMap(region, snap, program, block).computeScore(); } public ProgramLocation getProgramLocation() { @@ -201,15 +202,15 @@ public class DebuggerBlockChooserDialog extends ReusableDialogComponentProvider } public Map.Entry chooseBlock(PluginTool tool, TraceSection section, - Collection programs) { + long snap, Collection programs) { DebuggerStaticMappingService service = tool.getService(DebuggerStaticMappingService.class); - return chooseBlock(tool, programs, rec -> rec.score(section, service)); + return chooseBlock(tool, programs, rec -> rec.score(section, snap, service)); } public Map.Entry chooseBlock(PluginTool tool, TraceMemoryRegion region, - Collection programs) { + long snap, Collection programs) { DebuggerStaticMappingService service = tool.getService(DebuggerStaticMappingService.class); - return chooseBlock(tool, programs, rec -> rec.score(region, service)); + return chooseBlock(tool, programs, rec -> rec.score(region, snap, service)); } protected Map.Entry chooseBlock(PluginTool tool, diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/DebuggerLocationLabel.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/DebuggerLocationLabel.java index 0a43d1ffc3..b1fa2dc9c4 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/DebuggerLocationLabel.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/DebuggerLocationLabel.java @@ -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. @@ -142,13 +142,14 @@ public class DebuggerLocationLabel extends JLabel { if (sections.isEmpty()) { return null; } + long snap = current.getSnap(); /** * TODO: DB's R-Tree could probably do this natively. Not sure it's an optimization, though, * since few, if any, overlapping sections are expected. */ sections.sort(ComparatorUtils.chainedComparator(List.of( - Comparator.comparing(s -> s.getRange().getMinAddress()), - Comparator.comparing(s -> -s.getRange().getLength())))); + Comparator.comparing(s -> s.getRange(snap).getMinAddress()), + Comparator.comparing(s -> -s.getRange(snap).getLength())))); return sections.get(sections.size() - 1); } @@ -162,10 +163,11 @@ public class DebuggerLocationLabel extends JLabel { if (modules.isEmpty()) { return null; } + long snap = current.getSnap(); // TODO: DB's R-Tree could probably do this natively modules.sort(ComparatorUtils.chainedComparator(List.of( - Comparator.comparing(m -> m.getRange().getMinAddress()), - Comparator.comparing(m -> -m.getRange().getLength())))); + Comparator.comparing(m -> m.getRange(snap).getMinAddress()), + Comparator.comparing(m -> -m.getRange(snap).getLength())))); return modules.get(modules.size() - 1); } @@ -185,18 +187,19 @@ public class DebuggerLocationLabel extends JLabel { if (address == null) { return "(nowhere)"; } + long snap = current.getSnap(); try { TraceSection section = getNearestSectionContaining(); if (section != null) { - return section.getModule().getName() + ":" + section.getName(); + return section.getModule().getName(snap) + ":" + section.getName(snap); } TraceModule module = getNearestModuleContaining(); if (module != null) { - return module.getName(); + return module.getName(snap); } TraceMemoryRegion region = getRegionContaining(); if (region != null) { - return region.getName(); + return region.getName(snap); } return "(unknown)"; } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/ByModuleAutoMapSpec.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/ByModuleAutoMapSpec.java index ff8a5234a8..0c4243c680 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/ByModuleAutoMapSpec.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/ByModuleAutoMapSpec.java @@ -81,14 +81,14 @@ public class ByModuleAutoMapSpec implements AutoMapSpec { } @Override - public String getInfoForObjects(Trace trace) { + public String getInfoForObjects(Trace trace, long snap) { String modPart = trace.getModuleManager() - .getAllModules() + .getLoadedModules(snap) .stream() - .map(m -> m.getName() + ":" + m.getBase()) + .map(m -> m.getName(snap) + ":" + m.getBase(snap)) .sorted() .collect(Collectors.joining(",")); - String regPart = ByRegionAutoMapSpec.getInfoForRegions(trace); + String regPart = ByRegionAutoMapSpec.getInfoForRegions(trace, snap); return modPart + ";" + regPart; } @@ -99,9 +99,9 @@ public class ByModuleAutoMapSpec implements AutoMapSpec { @Override public boolean performMapping(DebuggerStaticMappingService mappingService, Trace trace, - List programs, TaskMonitor monitor) throws CancelledException { + long snap, List programs, TaskMonitor monitor) throws CancelledException { Map maps = mappingService - .proposeModuleMaps(trace.getModuleManager().getAllModules(), programs); + .proposeModuleMaps(trace.getModuleManager().getLoadedModules(snap), snap, programs); Collection entries = MapProposal.flatten(maps.values()); entries = MapProposal.removeOverlapping(entries); mappingService.addModuleMappings(entries, monitor, false); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/ByRegionAutoMapSpec.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/ByRegionAutoMapSpec.java index 5703a508b3..177b67099f 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/ByRegionAutoMapSpec.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/ByRegionAutoMapSpec.java @@ -64,18 +64,18 @@ public class ByRegionAutoMapSpec implements AutoMapSpec { return value.getParent().queryInterface(TraceObjectMemoryRegion.class) != null; } - static String getInfoForRegions(Trace trace) { + static String getInfoForRegions(Trace trace, long snap) { return trace.getMemoryManager() - .getAllRegions() + .getRegionsAtSnap(snap) .stream() - .map(r -> r.getName() + ":" + r.getMinAddress()) + .map(r -> r.getName(snap) + ":" + r.getMinAddress(snap)) .sorted() .collect(Collectors.joining(",")); } @Override - public String getInfoForObjects(Trace trace) { - return getInfoForRegions(trace); + public String getInfoForObjects(Trace trace, long snap) { + return getInfoForRegions(trace, snap); } @Override @@ -85,9 +85,9 @@ public class ByRegionAutoMapSpec implements AutoMapSpec { @Override public boolean performMapping(DebuggerStaticMappingService mappingService, Trace trace, - List programs, TaskMonitor monitor) throws CancelledException { + long snap, List programs, TaskMonitor monitor) throws CancelledException { Map maps = mappingService - .proposeRegionMaps(trace.getMemoryManager().getAllRegions(), programs); + .proposeRegionMaps(trace.getMemoryManager().getRegionsAtSnap(snap), snap, programs); Collection entries = MapProposal.flatten(maps.values()); entries = MapProposal.removeOverlapping(entries); mappingService.addRegionMappings(entries, monitor, false); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/BySectionAutoMapSpec.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/BySectionAutoMapSpec.java index dfa3f28261..cbb6efba73 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/BySectionAutoMapSpec.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/BySectionAutoMapSpec.java @@ -65,11 +65,12 @@ public class BySectionAutoMapSpec implements AutoMapSpec { } @Override - public String getInfoForObjects(Trace trace) { + public String getInfoForObjects(Trace trace, long snap) { return trace.getModuleManager() .getAllSections() .stream() - .map(s -> s.getName() + ":" + s.getStart()) + .filter(s -> s.isValid(snap)) + .map(s -> s.getName(snap) + ":" + s.getStart(snap)) .sorted() .collect(Collectors.joining(",")); } @@ -81,9 +82,9 @@ public class BySectionAutoMapSpec implements AutoMapSpec { @Override public boolean performMapping(DebuggerStaticMappingService mappingService, Trace trace, - List programs, TaskMonitor monitor) throws CancelledException { - Map maps = mappingService - .proposeSectionMaps(trace.getModuleManager().getAllModules(), programs); + long snap, List programs, TaskMonitor monitor) throws CancelledException { + Map maps = mappingService.proposeSectionMaps( + trace.getModuleManager().getLoadedModules(snap), snap, programs); Collection entries = MapProposal.flatten(maps.values()); entries = MapProposal.removeOverlapping(entries); mappingService.addSectionMappings(entries, monitor, false); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/NoneAutoMapSpec.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/NoneAutoMapSpec.java index dfcebbfeba..60c157514a 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/NoneAutoMapSpec.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/NoneAutoMapSpec.java @@ -61,7 +61,7 @@ public class NoneAutoMapSpec implements AutoMapSpec { } @Override - public String getInfoForObjects(Trace trace) { + public String getInfoForObjects(Trace trace, long snap) { return ""; } @@ -71,7 +71,7 @@ public class NoneAutoMapSpec implements AutoMapSpec { } @Override - public void runTask(PluginTool tool, Trace trace) { + public void runTask(PluginTool tool, Trace trace, long snap) { // Don't bother launching a task that does nothing } @@ -82,7 +82,7 @@ public class NoneAutoMapSpec implements AutoMapSpec { @Override public boolean performMapping(DebuggerStaticMappingService mappingService, Trace trace, - List programs, TaskMonitor monitor) throws CancelledException { + long snap, List programs, TaskMonitor monitor) throws CancelledException { return false; } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/OneToOneAutoMapSpec.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/OneToOneAutoMapSpec.java index cb5be8234d..5003d8db87 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/OneToOneAutoMapSpec.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/OneToOneAutoMapSpec.java @@ -62,7 +62,7 @@ public class OneToOneAutoMapSpec implements AutoMapSpec { } @Override - public String getInfoForObjects(Trace trace) { + public String getInfoForObjects(Trace trace, long snap) { return ""; } @@ -77,12 +77,11 @@ public class OneToOneAutoMapSpec implements AutoMapSpec { @Override public boolean performMapping(DebuggerStaticMappingService mappingService, Trace trace, - List programs, TaskMonitor monitor) throws CancelledException { + long snap, List programs, TaskMonitor monitor) throws CancelledException { boolean result = false; for (Program program : programs) { try { - mappingService.addIdentityMapping(trace, program, - Lifespan.nowOn(trace.getProgramView().getSnap()), false); + mappingService.addIdentityMapping(trace, program, Lifespan.nowOn(snap), false); result = true; } catch (TraceConflictedMappingException e) { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/PCByStackLocationTrackingSpec.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/PCByStackLocationTrackingSpec.java index 8ff385ab6d..52ab1c5ba7 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/PCByStackLocationTrackingSpec.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/PCByStackLocationTrackingSpec.java @@ -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. @@ -85,7 +85,7 @@ public enum PCByStackLocationTrackingSpec implements LocationTrackingSpec, Locat return null; } int level = coordinates.getFrame(); - TraceStackFrame frame = stack.getFrame(level, false); + TraceStackFrame frame = stack.getFrame(snap, level, false); if (frame == null) { return null; } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/RegisterLocationTrackingSpec.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/RegisterLocationTrackingSpec.java index 512f857679..f04cba17f0 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/RegisterLocationTrackingSpec.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/RegisterLocationTrackingSpec.java @@ -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. @@ -22,7 +22,8 @@ import ghidra.program.model.address.*; import ghidra.program.model.lang.Register; import ghidra.program.model.lang.RegisterValue; import ghidra.program.util.ProgramLocation; -import ghidra.trace.model.*; +import ghidra.trace.model.Trace; +import ghidra.trace.model.TraceAddressSnapRange; import ghidra.trace.model.guest.TracePlatform; import ghidra.trace.model.memory.TraceMemorySpace; import ghidra.trace.model.memory.TraceMemoryState; @@ -64,8 +65,7 @@ public interface RegisterLocationTrackingSpec extends LocationTrackingSpec, Loca if (reg == null) { return null; } - Lifespan lifespan = thread.getLifespan(); - if (lifespan == null || !lifespan.contains(snap)) { + if (!thread.isValid(snap)) { return null; } TraceMemorySpace regs = reg.getAddressSpace().isRegisterSpace() diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/VisibleROOnceAutoReadMemorySpec.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/VisibleROOnceAutoReadMemorySpec.java index b2d50b66f2..e4b961d811 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/VisibleROOnceAutoReadMemorySpec.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/VisibleROOnceAutoReadMemorySpec.java @@ -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. @@ -60,7 +60,8 @@ public class VisibleROOnceAutoReadMemorySpec implements AutoReadMemorySpec { } Target target = coordinates.getTarget(); TraceMemoryManager mm = coordinates.getTrace().getMemoryManager(); - AddressSetView alreadyKnown = mm.getAddressesWithState(coordinates.getSnap(), visible, + long snap = coordinates.getSnap(); + AddressSetView alreadyKnown = mm.getAddressesWithState(snap, visible, s -> s == TraceMemoryState.KNOWN || s == TraceMemoryState.ERROR); AddressSet toRead = visible.subtract(alreadyKnown); @@ -70,19 +71,18 @@ public class VisibleROOnceAutoReadMemorySpec implements AutoReadMemorySpec { AddressSet everKnown = new AddressSet(); for (AddressRange range : visible) { - for (Entry ent : mm - .getMostRecentStates(coordinates.getSnap(), range)) { + for (Entry ent : mm.getMostRecentStates(snap, + range)) { everKnown.add(ent.getKey().getRange()); } } AddressSet readOnly = new AddressSet(); for (AddressRange range : visible) { - for (TraceMemoryRegion region : mm - .getRegionsIntersecting(Lifespan.at(coordinates.getSnap()), range)) { - if (region.isWrite()) { + for (TraceMemoryRegion region : mm.getRegionsIntersecting(Lifespan.at(snap), range)) { + if (region.isWrite(snap)) { continue; } - readOnly.add(region.getRange()); + readOnly.add(region.getRange(snap)); } } toRead.delete(everKnown.intersect(readOnly)); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/BreakpointLocationRow.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/BreakpointLocationRow.java index 386874642b..8bc8095635 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/BreakpointLocationRow.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/BreakpointLocationRow.java @@ -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,6 @@ import ghidra.pcode.exec.SleighUtils; import ghidra.program.model.address.Address; import ghidra.program.util.ProgramLocation; import ghidra.trace.model.breakpoint.TraceBreakpoint; -import ghidra.trace.model.thread.TraceThread; public class BreakpointLocationRow { private final DebuggerBreakpointsProvider provider; @@ -36,13 +35,16 @@ public class BreakpointLocationRow { this.loc = loc; } + private long getSnap() { + return provider.traceManager.getCurrentFor(loc.getTrace()).getSnap(); + } + public String getName() { - return loc.getName(); + return loc.getName(getSnap()); } public boolean isEnabled() { - long snap = provider.traceManager.getCurrentFor(loc.getTrace()).getSnap(); - return loc.isEnabled(snap); + return loc.isEnabled(getSnap()); } public State getState() { @@ -75,12 +77,12 @@ public class BreakpointLocationRow { public void setName(String name) { try (Transaction tid = loc.getTrace().openTransaction("Set breakpoint name")) { - loc.setName(name); + loc.setName(getSnap(), name); } } public Address getAddress() { - return loc.getMinAddress(); + return loc.getMinAddress(getSnap()); } public ProgramLocation getProgramLocation() { @@ -92,25 +94,26 @@ public class BreakpointLocationRow { } public String getThreads() { - return loc.getThreads() + long snap = getSnap(); + return loc.getThreads(snap) .stream() - .map(TraceThread::getName) + .map(t -> t.getName(snap)) .collect(Collectors.toSet()) .toString(); } public String getComment() { - return loc.getComment(); + return loc.getComment(getSnap()); } public void setComment(String comment) { try (Transaction tid = loc.getTrace().openTransaction("Set breakpoint comment")) { - loc.setComment(comment); + loc.setComment(getSnap(), comment); } } public boolean hasSleigh() { - return !SleighUtils.UNCONDITIONAL_BREAK.equals(loc.getEmuSleigh()); + return !SleighUtils.UNCONDITIONAL_BREAK.equals(loc.getEmuSleigh(getSnap())); } public TraceBreakpoint getTraceBreakpoint() { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsProvider.java index 8b7a29c28b..c478f6606e 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsProvider.java @@ -699,7 +699,7 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter private boolean isVisible(TraceBreakpoint location) { long snap = traceManager.getCurrentFor(trace).getSnap(); - return location.isAlive(snap); + return location.isValid(snap); } private void locationAdded(TraceBreakpoint location) { @@ -1336,7 +1336,8 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter } else if (ctx instanceof DebuggerBreakpointLocationsActionContext locCtx) { for (TraceBreakpoint tb : locCtx.getLocations()) { - if (!EXECUTE_KINDS.containsAll(tb.getKinds())) { + long snap = traceManager.getCurrentFor(tb.getTrace()).getSnap(); + if (!EXECUTE_KINDS.containsAll(tb.getKinds(snap))) { return false; } } @@ -1368,7 +1369,8 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter } else if (ctx instanceof DebuggerBreakpointLocationsActionContext locCtx) { for (TraceBreakpoint tb : locCtx.getLocations()) { - String s = tb.getEmuSleigh(); + long snap = traceManager.getCurrentFor(tb.getTrace()).getSnap(); + String s = tb.getEmuSleigh(snap); if (sleigh != null && !sleigh.equals(s)) { return null; } @@ -1393,7 +1395,8 @@ public class DebuggerBreakpointsProvider extends ComponentProviderAdapter } else if (ctx instanceof DebuggerBreakpointLocationsActionContext locCtx) { for (TraceBreakpoint tb : locCtx.getLocations()) { - tb.setEmuSleigh(sleigh); + long snap = traceManager.getCurrentFor(tb.getTrace()).getSnap(); + tb.setEmuSleigh(snap, sleigh); } } else { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyIntoProgramDialog.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyIntoProgramDialog.java index 2b5f608ac6..601f993383 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyIntoProgramDialog.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyIntoProgramDialog.java @@ -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. @@ -620,23 +620,26 @@ public class DebuggerCopyIntoProgramDialog extends ReusableDialogComponentProvid protected String computeRegionString(AddressRange rng) { TraceMemoryManager mm = source.getTrace().getMemoryManager(); + long snap = source.getSnap(); Collection regions = - mm.getRegionsIntersecting(Lifespan.at(source.getSnap()), rng); - return regions.isEmpty() ? "UNKNOWN" : regions.iterator().next().getName(); + mm.getRegionsIntersecting(Lifespan.at(snap), rng); + return regions.isEmpty() ? "UNKNOWN" : regions.iterator().next().getName(snap); } protected String computeModulesString(AddressRange rng) { TraceModuleManager mm = source.getTrace().getModuleManager(); + long snap = source.getSnap(); Collection modules = - mm.getModulesIntersecting(Lifespan.at(source.getSnap()), rng); - return modules.stream().map(m -> m.getName()).collect(Collectors.joining(",")); + mm.getModulesIntersecting(Lifespan.at(snap), rng); + return modules.stream().map(m -> m.getName(snap)).collect(Collectors.joining(",")); } protected String computeSectionsString(AddressRange rng) { TraceModuleManager mm = source.getTrace().getModuleManager(); + long snap = source.getSnap(); Collection sections = - mm.getSectionsIntersecting(Lifespan.at(source.getSnap()), rng); - return sections.stream().map(s -> s.getName()).collect(Collectors.joining(",")); + mm.getSectionsIntersecting(Lifespan.at(snap), rng); + return sections.stream().map(s -> s.getName(snap)).collect(Collectors.joining(",")); } protected void createEntry(Collection result, AddressRange srcRange, @@ -692,10 +695,11 @@ public class DebuggerCopyIntoProgramDialog extends ReusableDialogComponentProvid protected List breakRangeByRegions(AddressRange srcRange) { AddressSet remains = new AddressSet(srcRange); List result = new ArrayList<>(); + long snap = source.getSnap(); for (TraceMemoryRegion region : source.getTrace() .getMemoryManager() - .getRegionsIntersecting(Lifespan.at(source.getSnap()), srcRange)) { - AddressRange range = region.getRange().intersect(srcRange); + .getRegionsIntersecting(Lifespan.at(snap), srcRange)) { + AddressRange range = region.getRange(snap).intersect(srcRange); result.add(range); remains.delete(range); } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyPlan.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyPlan.java index c1ba706387..f818f6096a 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyPlan.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyPlan.java @@ -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. @@ -219,21 +219,22 @@ public class DebuggerCopyPlan { @Override public void copy(TraceProgramView from, AddressRange fromRange, Program into, Address intoAddress, TaskMonitor monitor) throws Exception { + long snap = from.getSnap(); for (TraceBreakpoint bpt : from.getTrace() .getBreakpointManager() .getBreakpointsIntersecting(Lifespan.at(from.getSnap()), fromRange)) { monitor.checkCancelled(); - long off = bpt.getMinAddress().subtract(fromRange.getMinAddress()); + long off = bpt.getMinAddress(snap).subtract(fromRange.getMinAddress()); Address dest = intoAddress.add(off); ProgramBreakpoint pb = - new ProgramBreakpoint(into, dest, bpt.getLength(), bpt.getKinds()); + new ProgramBreakpoint(into, dest, bpt.getLength(snap), bpt.getKinds(snap)); if (bpt.isEnabled(from.getSnap())) { pb.enable(); } else { pb.disable(); } - pb.setEmuSleigh(bpt.getEmuSleigh()); + pb.setEmuSleigh(bpt.getEmuSleigh(snap)); } } }, diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProvider.java index 5acb99e7fb..ae7cffee69 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProvider.java @@ -1081,13 +1081,13 @@ public class DebuggerListingProvider extends CodeViewerProvider { Set toOpen = new HashSet<>(); TraceModuleManager modMan = trace.getModuleManager(); Collection modules = Stream.concat( - modMan.getModulesAt(snap, address).stream().filter(m -> m.getSections().isEmpty()), + modMan.getModulesAt(snap, address).stream().filter(m -> m.getSections(snap).isEmpty()), modMan.getSectionsAt(snap, address).stream().map(s -> s.getModule())) .collect(Collectors.toSet()); // Attempt to open probable matches. All others, list to import for (TraceModule mod : modules) { - DomainFile match = mappingService.findBestModuleProgram(space, mod); + DomainFile match = mappingService.findBestModuleProgram(space, mod, snap); if (match == null) { missing.add(mod); } @@ -1108,7 +1108,7 @@ public class DebuggerListingProvider extends CodeViewerProvider { for (TraceModule mod : missing) { consoleService.log(DebuggerResources.ICON_LOG_ERROR, - "The module " + HTMLUtilities.escapeHTML(mod.getName()) + + "The module " + HTMLUtilities.escapeHTML(mod.getName(snap)) + " was not found in the project", new DebuggerMissingModuleActionContext(mod)); } @@ -1139,12 +1139,13 @@ public class DebuggerListingProvider extends CodeViewerProvider { if (!affectedTraces.contains(module.getTrace())) { continue; } - if (isMapped(module.getRange())) { + long snap = traceManager.getCurrentFor(module.getTrace()).getSnap(); + if (isMapped(module.getRange(snap))) { consoleService.removeFromLog(mmCtx); continue; } - for (TraceSection section : module.getSections()) { - if (isMapped(section.getRange())) { + for (TraceSection section : module.getSections(snap)) { + if (isMapped(section.getRange(snap))) { consoleService.removeFromLog(mmCtx); continue nextCtx; } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/listing/MemoryStateListingBackgroundColorModel.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/listing/MemoryStateListingBackgroundColorModel.java index e5070cad8c..38420202ba 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/listing/MemoryStateListingBackgroundColorModel.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/listing/MemoryStateListingBackgroundColorModel.java @@ -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. @@ -71,13 +71,14 @@ public class MemoryStateListingBackgroundColorModel implements ListingBackground } protected Color getUnknownColor(Address address) { + long snap = view.getSnap(); Entry ent = - memory.getViewMostRecentStateEntry(view.getSnap(), address); + memory.getViewMostRecentStateEntry(snap, address); if (ent == null || ent.getValue() != TraceMemoryState.KNOWN) { return COLOR_BACKGROUND_UNKNOWN; } TraceMemoryRegion region = memory.getRegionContaining(ent.getKey().getY1(), address); - if (region != null && !region.isWrite()) { + if (region != null && !region.isWrite(snap)) { return COLOR_BACKGROUND_UNKNOWN_BLENDED; } return COLOR_BACKGROUND_UNKNOWN; diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerLegacyRegionsPanel.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerLegacyRegionsPanel.java index b29c35a4e9..d6dacad657 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerLegacyRegionsPanel.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerLegacyRegionsPanel.java @@ -40,7 +40,8 @@ import ghidra.framework.plugintool.annotation.AutoServiceConsumed; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressSet; import ghidra.program.util.ProgramSelection; -import ghidra.trace.model.*; +import ghidra.trace.model.Trace; +import ghidra.trace.model.TraceDomainObjectListener; import ghidra.trace.model.memory.TraceMemoryManager; import ghidra.trace.model.memory.TraceMemoryRegion; import ghidra.trace.util.TraceEvents; @@ -53,7 +54,6 @@ public class DebuggerLegacyRegionsPanel extends JPanel { protected enum RegionTableColumns implements EnumeratedTableColumn { NAME("Name", String.class, RegionRow::getName, RegionRow::setName), - LIFESPAN("Lifespan", Lifespan.class, RegionRow::getLifespan), START("Start", Address.class, RegionRow::getMinAddress), END("End", Address.class, RegionRow::getMaxAddress), LENGTH("Length", Long.class, RegionRow::getLength), @@ -159,7 +159,7 @@ public class DebuggerLegacyRegionsPanel extends JPanel { } AddressSet sel = new AddressSet(); for (TraceMemoryRegion s : regions) { - sel.add(s.getRange()); + sel.add(s.getRange(0)); } ProgramSelection ps = new ProgramSelection(sel); listingService.setCurrentSelection(ps); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionMapProposalDialog.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionMapProposalDialog.java index 5368c27eed..d6f54e4883 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionMapProposalDialog.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionMapProposalDialog.java @@ -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. @@ -42,8 +42,8 @@ public class DebuggerRegionMapProposalDialog protected enum RegionMapTableColumns implements EnumeratedTableColumn { REMOVE("Remove", String.class, e -> "Remove Proposed Entry", (e, v) -> nop()), - REGION_NAME("Region", String.class, e -> e.getRegion().getName()), - DYNAMIC_BASE("Dynamic Base", Address.class, e -> e.getRegion().getMinAddress()), + REGION_NAME("Region", String.class, e -> e.getRegionName()), + DYNAMIC_BASE("Dynamic Base", Address.class, e -> e.getRegionMinAddress()), CHOOSE("Choose", String.class, e -> "Choose Block", (e, s) -> nop()), PROGRAM_NAME("Program", String.class, e -> e.getToProgram().getName()), BLOCK_NAME("Block", String.class, e -> e.getBlock().getName()), diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsProvider.java index 763ffac514..2a1f29d7dc 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsProvider.java @@ -193,7 +193,7 @@ public class DebuggerRegionsProvider extends ComponentProviderAdapter { } AddressSet sel = new AddressSet(); for (TraceMemoryRegion s : regions) { - sel.add(s.getRange()); + sel.add(s.getRange(current.getSnap())); } ProgramSelection ps = new ProgramSelection(sel); listingService.setCurrentSelection(ps); @@ -403,7 +403,7 @@ public class DebuggerRegionsProvider extends ComponentProviderAdapter { return; } Map map = staticMappingService.proposeRegionMaps(regions, - List.of(programManager.getAllOpenPrograms())); + current.getSnap(), List.of(programManager.getAllOpenPrograms())); Collection proposal = MapProposal.flatten(map.values()); promptRegionProposal(proposal); } @@ -416,7 +416,8 @@ public class DebuggerRegionsProvider extends ComponentProviderAdapter { if (program == null) { return; } - RegionMapProposal map = staticMappingService.proposeRegionMap(regions, program); + RegionMapProposal map = + staticMappingService.proposeRegionMap(regions, current.getSnap(), program); Collection proposal = map.computeMap().values(); promptRegionProposal(proposal); } @@ -431,7 +432,8 @@ public class DebuggerRegionsProvider extends ComponentProviderAdapter { return; } RegionMapProposal map = - staticMappingService.proposeRegionMap(region, location.getProgram(), block); + staticMappingService.proposeRegionMap(region, current.getSnap(), location.getProgram(), + block); promptRegionProposal(map.computeMap().values()); } @@ -548,7 +550,7 @@ public class DebuggerRegionsProvider extends ComponentProviderAdapter { Msg.warn(this, "No program manager!"); return null; } - return blockChooserDialog.chooseBlock(getTool(), region, + return blockChooserDialog.chooseBlock(getTool(), region, current.getSnap(), List.of(programManager.getAllOpenPrograms())); } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/RegionRow.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/RegionRow.java index 2277cea485..5d1b8b2a11 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/RegionRow.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/RegionRow.java @@ -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,7 +18,6 @@ package ghidra.app.plugin.core.debug.gui.memory; import db.Transaction; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressRange; -import ghidra.trace.model.Lifespan; import ghidra.trace.model.memory.TraceMemoryRegion; public class RegionRow { @@ -34,84 +33,71 @@ public class RegionRow { public void setName(String name) { try (Transaction tx = region.getTrace().openTransaction("Rename region")) { - region.setName(name); + region.setName(0, name); } } public String getName() { - return region.getName(); - } - - public Lifespan getLifespan() { - return region.getLifespan(); - } - - public long getCreatedSnap() { - return region.getCreationSnap(); - } - - public String getDestroyedSnap() { - long snap = region.getDestructionSnap(); - return snap == Long.MAX_VALUE ? "" : Long.toString(snap); + return region.getName(0); } public AddressRange getRange() { - return region.getRange(); + return region.getRange(0); } public Address getMaxAddress() { - return region.getMaxAddress(); + return region.getMaxAddress(0); } public Address getMinAddress() { - return region.getMinAddress(); + return region.getMinAddress(0); } public long getLength() { - return region.getLength(); + return region.getLength(0); } public void setRead(boolean read) { try (Transaction tx = region.getTrace().openTransaction("Toggle region read flag")) { - region.setRead(read); + region.setRead(0, read); } } public boolean isRead() { - return region.isRead(); + return region.isRead(0); } public void setWrite(boolean write) { try (Transaction tx = region.getTrace().openTransaction("Toggle region write flag")) { - region.setWrite(write); + region.setWrite(0, write); } } public boolean isWrite() { - return region.isWrite(); + return region.isWrite(0); } public void setExecute(boolean execute) { try (Transaction tx = region.getTrace().openTransaction("Toggle region execute flag")) { - region.setExecute(execute); + region.setExecute(0, execute); } } public boolean isExecute() { - return region.isExecute(); + return region.isExecute(0); } public void setVolatile(boolean vol) { try (Transaction tx = region.getTrace().openTransaction("Toggle region volatile flag")) { - region.setVolatile(vol); + region.setVolatile(0, vol); } } public boolean isVolatile() { - return region.isVolatile(); + return region.isVolatile(0); } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/DebuggerMemviewTraceListener.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/DebuggerMemviewTraceListener.java index 081185a210..4ac1030906 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/DebuggerMemviewTraceListener.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memview/DebuggerMemviewTraceListener.java @@ -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. @@ -21,14 +21,13 @@ import ghidra.async.AsyncDebouncer; import ghidra.async.AsyncTimer; import ghidra.debug.api.tracemgr.DebuggerCoordinates; import ghidra.program.model.address.*; +import ghidra.trace.database.module.TraceObjectSection; import ghidra.trace.model.*; -import ghidra.trace.model.breakpoint.TraceBreakpoint; -import ghidra.trace.model.breakpoint.TraceBreakpointManager; -import ghidra.trace.model.memory.TraceMemoryManager; -import ghidra.trace.model.memory.TraceMemoryRegion; +import ghidra.trace.model.breakpoint.*; +import ghidra.trace.model.memory.*; import ghidra.trace.model.modules.*; -import ghidra.trace.model.thread.TraceThread; -import ghidra.trace.model.thread.TraceThreadManager; +import ghidra.trace.model.target.TraceObject; +import ghidra.trace.model.thread.*; import ghidra.trace.util.TraceEvents; import ghidra.util.Swing; @@ -91,60 +90,79 @@ public class DebuggerMemviewTraceListener extends TraceDomainObjectListener { } private void threadChanged(TraceThread thread) { - if (!trackThreads || !trackTrace) { + if (!trackThreads || !trackTrace || !(thread instanceof TraceObjectThread objThread)) { return; } AddressFactory factory = thread.getTrace().getBaseAddressFactory(); AddressSpace defaultSpace = factory.getDefaultAddressSpace(); Long threadId = thread.getKey(); + AddressRange rng = rng(defaultSpace, threadId, threadId); - MemoryBox box = new MemoryBox("Thread " + thread.getName(), MemviewBoxType.THREAD, rng, - thread.getLifespan()); - updateList.add(box); + TraceObject obj = objThread.getObject(); + obj.getCanonicalParents(Lifespan.ALL).forEach(p -> { + MemoryBox box = new MemoryBox("Thread " + thread.getName(p.getMinSnap()), + MemviewBoxType.THREAD, rng, p.getLifespan()); + updateList.add(box); + }); updateLabelDebouncer.contact(null); } private void regionChanged(TraceMemoryRegion region) { - if (!trackRegions || !trackTrace) { + if (!trackRegions || !trackTrace || + !(region instanceof TraceObjectMemoryRegion objRegion)) { return; } - MemoryBox box = new MemoryBox("Region " + region.getName(), MemviewBoxType.VIRTUAL_ALLOC, - region.getRange(), region.getLifespan()); - updateList.add(box); + + TraceObject obj = objRegion.getObject(); + obj.getOrderedValues(Lifespan.ALL, TraceObjectMemoryRegion.KEY_RANGE, true).forEach(v -> { + MemoryBox box = new MemoryBox("Region " + region.getName(v.getMinSnap()), + MemviewBoxType.VIRTUAL_ALLOC, v.castValue(), v.getLifespan()); + updateList.add(box); + }); updateLabelDebouncer.contact(null); } private void moduleChanged(TraceModule module) { - if (!trackModules || !trackTrace) { + if (!trackModules || !trackTrace || !(module instanceof TraceObjectModule objModule)) { return; } - AddressRange range = module.getRange(); - if (range == null) { - return; - } - MemoryBox box = new MemoryBox("Module " + module.getName(), MemviewBoxType.MODULE, range, - module.getLifespan()); - updateList.add(box); + + TraceObject obj = objModule.getObject(); + obj.getOrderedValues(Lifespan.ALL, TraceObjectModule.KEY_RANGE, true).forEach(v -> { + MemoryBox box = new MemoryBox("Module " + module.getName(v.getMinSnap()), + MemviewBoxType.MODULE, v.castValue(), v.getLifespan()); + updateList.add(box); + }); updateLabelDebouncer.contact(null); } private void sectionChanged(TraceSection section) { - if (!trackSections || !trackTrace) { + if (!trackSections || !trackTrace || !(section instanceof TraceObjectSection objSection)) { return; } - MemoryBox box = new MemoryBox("Section " + section.getName(), MemviewBoxType.IMAGE, - section.getRange(), section.getModule().getLifespan()); - updateList.add(box); + + TraceObject obj = objSection.getObject(); + obj.getOrderedValues(Lifespan.ALL, TraceObjectSection.KEY_RANGE, true).forEach(v -> { + MemoryBox box = new MemoryBox("Module " + section.getName(v.getMinSnap()), + MemviewBoxType.IMAGE, v.castValue(), v.getLifespan()); + updateList.add(box); + }); updateLabelDebouncer.contact(null); } private void breakpointChanged(TraceBreakpoint bpt) { - if (!trackBreakpoints || !trackTrace) { + if (!trackBreakpoints || !trackTrace || + !(bpt instanceof TraceObjectBreakpointLocation objBpt)) { return; } - MemoryBox box = new MemoryBox("Breakpoint " + bpt.getName(), MemviewBoxType.BREAKPOINT, - bpt.getRange(), bpt.getLifespan()); - updateList.add(box); + + TraceObject obj = objBpt.getObject(); + obj.getOrderedValues(Lifespan.ALL, TraceObjectBreakpointLocation.KEY_RANGE, true) + .forEach(v -> { + MemoryBox box = new MemoryBox("Module " + bpt.getName(v.getMinSnap()), + MemviewBoxType.BREAKPOINT, v.castValue(), v.getLifespan()); + updateList.add(box); + }); updateLabelDebouncer.contact(null); } @@ -238,7 +256,7 @@ public class DebuggerMemviewTraceListener extends TraceDomainObjectListener { TraceModuleManager moduleManager = trace.getModuleManager(); for (TraceModule module : moduleManager.getAllModules()) { moduleChanged(module); - Collection sections = module.getSections(); + Collection sections = module.getAllSections(); for (TraceSection section : sections) { sectionChanged(section); } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/model/AbstractObjectsTableBasedPanel.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/model/AbstractObjectsTableBasedPanel.java index 8dc9f7d95d..907a77e71b 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/model/AbstractObjectsTableBasedPanel.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/model/AbstractObjectsTableBasedPanel.java @@ -34,7 +34,7 @@ import ghidra.debug.api.tracemgr.DebuggerCoordinates; import ghidra.framework.plugintool.*; import ghidra.framework.plugintool.annotation.AutoServiceConsumed; import ghidra.trace.model.Trace; -import ghidra.trace.model.target.*; +import ghidra.trace.model.target.TraceObject; import ghidra.trace.model.target.iface.TraceObjectInterface; import ghidra.trace.model.target.path.KeyPath; @@ -115,7 +115,8 @@ public abstract class AbstractObjectsTableBasedPanel sel = getSelectedItems(); if (!sel.isEmpty()) { myActionContext = new DebuggerObjectActionContext( - sel.stream().map(r -> r.getValue()).collect(Collectors.toList()), provider, table); + sel.stream().map(r -> r.getValue()).collect(Collectors.toList()), provider, table, + current.getSnap()); } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/model/DebuggerModelProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/model/DebuggerModelProvider.java index ce85513c92..1882b11d66 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/model/DebuggerModelProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/model/DebuggerModelProvider.java @@ -541,7 +541,7 @@ public class DebuggerModelProvider extends ComponentProvider implements Saveable .map(n -> n.getValue()) .filter(o -> o != null) // Root for no trace would return null .collect(Collectors.toList()), - DebuggerModelProvider.this, objectsTreePanel); + DebuggerModelProvider.this, objectsTreePanel, current.getSnap()); } } @@ -610,7 +610,7 @@ public class DebuggerModelProvider extends ComponentProvider implements Saveable return new DebuggerObjectActionContext(sel.stream() .map(r -> r.getValue()) .collect(Collectors.toList()), - DebuggerModelProvider.this, elementsTablePanel); + DebuggerModelProvider.this, elementsTablePanel, current.getSnap()); } } @@ -664,7 +664,7 @@ public class DebuggerModelProvider extends ComponentProvider implements Saveable return new DebuggerObjectActionContext(sel.stream() .map(r -> Objects.requireNonNull(r.getPath().getLastEntry())) .collect(Collectors.toList()), - DebuggerModelProvider.this, attributesTablePanel); + DebuggerModelProvider.this, attributesTablePanel, current.getSnap()); } } @@ -768,7 +768,8 @@ public class DebuggerModelProvider extends ComponentProvider implements Saveable return; } Map actions = target.collectActions(ActionName.REFRESH, - new DebuggerObjectActionContext(List.of(value), this, objectsTreePanel)); + new DebuggerObjectActionContext(List.of(value), this, objectsTreePanel, + current.getSnap())); for (ActionEntry ent : actions.values()) { if (ent.requiresPrompt()) { continue; diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerLegacyModulesPanel.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerLegacyModulesPanel.java index c5b9852fdd..68ab5cb283 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerLegacyModulesPanel.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerLegacyModulesPanel.java @@ -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. @@ -53,7 +53,8 @@ public class DebuggerLegacyModulesPanel extends JPanel { DebuggerModuleActionContext context) { return context.getSelectedModules() .stream() - .flatMap(m -> m.getSections().stream()) + // snap does not matter for legacy module + .flatMap(m -> m.getSections(0).stream()) .collect(Collectors.toSet()); } @@ -61,7 +62,8 @@ public class DebuggerLegacyModulesPanel extends JPanel { DebuggerModuleActionContext context) { AddressSet sel = new AddressSet(); for (TraceModule module : getSelectedModulesFromContext(context)) { - sel.add(module.getRange()); + // snap does not matter for legacy module + sel.add(module.getRange(0)); } return sel; } @@ -73,7 +75,6 @@ public class DebuggerLegacyModulesPanel extends JPanel { SHORT_NAME("Name", String.class, ModuleRow::getShortName), NAME("Module Name", String.class, ModuleRow::getName, ModuleRow::setName), MAPPING("Mapping", String.class, ModuleRow::getMapping), - LIFESPAN("Lifespan", Lifespan.class, ModuleRow::getLifespan), LENGTH("Length", Long.class, ModuleRow::getLength); private final String header; @@ -251,7 +252,7 @@ public class DebuggerLegacyModulesPanel extends JPanel { moduleTableModel.addAllItems(moduleManager.getAllModules()); } - public void setTrace(Trace trace) { + private void setTrace(Trace trace) { if (currentTrace == trace) { return; } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerLegacySectionsPanel.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerLegacySectionsPanel.java index 20b8928162..602ed8da6a 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerLegacySectionsPanel.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerLegacySectionsPanel.java @@ -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. @@ -48,7 +48,7 @@ public class DebuggerLegacySectionsPanel extends JPanel { protected static Set getSelectedModulesFromContext( DebuggerSectionActionContext context) { - return context.getSelectedSections(false) + return context.getSelectedSections(false, 0) .stream() .map(r -> r.getModule()) .collect(Collectors.toSet()); @@ -56,14 +56,14 @@ public class DebuggerLegacySectionsPanel extends JPanel { protected static Set getSelectedSectionsFromContext( DebuggerSectionActionContext context, boolean allowExpansion) { - return context.getSelectedSections(allowExpansion); + return context.getSelectedSections(allowExpansion, 0); } protected static AddressSetView getSelectedAddressesFromContext( DebuggerSectionActionContext context) { AddressSet sel = new AddressSet(); for (TraceSection section : getSelectedSectionsFromContext(context, false)) { - sel.add(section.getRange()); + sel.add(section.getRange(0)); } return sel; } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModuleMapProposalDialog.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModuleMapProposalDialog.java index d39e427883..ab49a239a0 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModuleMapProposalDialog.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModuleMapProposalDialog.java @@ -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. @@ -41,7 +41,7 @@ public class DebuggerModuleMapProposalDialog protected enum ModuleMapTableColumns implements EnumeratedTableColumn { REMOVE("Remove", String.class, e -> "Remove Proposed Entry", (e, v) -> nop()), - MODULE_NAME("Module", String.class, e -> e.getModule().getName()), + MODULE_NAME("Module", String.class, e -> e.getModuleName()), DYNAMIC_BASE("Dynamic Base", Address.class, e -> e.getFromRange().getMinAddress()), CHOOSE("Choose", String.class, e -> "Choose Program", (e, v) -> nop()), PROGRAM_NAME("Program", String.class, e -> (e.getToProgram().getDomainFile() == null diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesPanel.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesPanel.java index cc23ba2586..b4a26fe64c 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesPanel.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesPanel.java @@ -190,7 +190,7 @@ public class DebuggerModulesPanel extends AbstractObjectsTableBasedPanel autoMapStateByTrace = new WeakHashMap<>(); - private AutoMapState forMappingListener; DockingAction actionImportMissingModule; DockingAction actionMapMissingModule; @@ -634,7 +640,7 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter private void importModuleFromFileSystem(TraceModule module) { GhidraFileChooser chooser = new GhidraFileChooser(getComponent()); - chooser.setSelectedFile(new File(module.getName())); + chooser.setSelectedFile(new File(module.getName(current.getSnap()))); File file = chooser.getSelectedFile(); chooser.dispose(); if (file == null) { // Perhaps cancelled @@ -837,7 +843,7 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter return !ctx.getSelectedModules().isEmpty(); } if (context instanceof DebuggerSectionActionContext ctx) { - return !ctx.getSelectedSections(false).isEmpty(); + return !ctx.getSelectedSections(false, current.getSnap()).isEmpty(); } if (context instanceof DebuggerObjectActionContext ctx) { return !ctx.getObjectValues().isEmpty(); @@ -978,10 +984,13 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter if (staticMappingService == null) { return; } + Program program = context.getProgram(); Trace trace = context.getTrace(); + long snap = traceManager.getCurrentFor(trace).getSnap(); + Map map = staticMappingService.proposeModuleMaps( - trace.getModuleManager().getAllModules(), List.of(program)); + trace.getModuleManager().getAllModules(), snap, List.of(program)); Collection proposal = MapProposal.flatten(map.values()); promptModuleProposal(proposal, FMT_NO_MODULES_PROPOSAL_RETRY.formatted( trace.getDomainFile().getName(), program.getDomainFile().getName())); @@ -1022,10 +1031,10 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter Program program = context.getProgram(); ModuleMapProposal proposal = - staticMappingService.proposeModuleMap(module, program); + staticMappingService.proposeModuleMap(module, snap, program); Map map = proposal.computeMap(); promptModuleProposal(map.values(), FMT_NO_MODULES_PROPOSAL_CURRENT.formatted( - module.getName(), program.getDomainFile().getName())); + module.getName(snap), program.getDomainFile().getName())); } private void activatedMapMissingProgramIdentically( @@ -1089,16 +1098,16 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter return; } + long snap = current.getSnap(); ProgramSelection progSel = listingService.getCurrentSelection(); TraceModuleManager moduleManager = current.getTrace().getModuleManager(); if (progSel != null && !progSel.isEmpty()) { - long snap = traceManager.getCurrentSnap(); Set modSel = new HashSet<>(); Set sectionSel = new HashSet<>(); for (AddressRange range : progSel) { for (TraceModule module : moduleManager .getModulesIntersecting(Lifespan.at(snap), range)) { - if (module.getSections().isEmpty()) { + if (module.getSections(snap).isEmpty()) { modSel.add(module); } } @@ -1127,7 +1136,7 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter TraceModule bestModule = null; for (TraceModule module : moduleManager .getLoadedModules(traceManager.getCurrentSnap())) { - Address base = module.getBase(); + Address base = module.getBase(snap); if (base == null || base.getAddressSpace() != address.getAddressSpace()) { continue; } @@ -1138,12 +1147,12 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter if (base.compareTo(address) > 0) { continue; } - if (base.compareTo(bestModule.getBase()) <= 0) { + if (base.compareTo(bestModule.getBase(snap)) <= 0) { continue; } bestModule = module; } - if (bestModule.getSections().isEmpty()) { + if (bestModule.getSections(snap).isEmpty()) { setSelectedModules(Set.of(bestModule)); return; } @@ -1168,8 +1177,9 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter if (staticMappingService == null) { return; } - Map map = staticMappingService.proposeModuleMaps(modules, - List.of(programManager.getAllOpenPrograms())); + Map map = + staticMappingService.proposeModuleMaps(modules, current.getSnap(), + List.of(programManager.getAllOpenPrograms())); Collection proposal = MapProposal.flatten(map.values()); promptModuleProposal(proposal, NO_MODULES_PROPOSAL_SEL); } @@ -1182,7 +1192,8 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter if (program == null) { return; } - ModuleMapProposal proposal = staticMappingService.proposeModuleMap(module, program); + ModuleMapProposal proposal = + staticMappingService.proposeModuleMap(module, current.getSnap(), program); Map map = proposal.computeMap(); promptModuleProposal(map.values(), NO_MODULES_PROPOSAL_SEL); } @@ -1209,8 +1220,9 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter } Set modules = sections.stream().map(TraceSection::getModule).collect(Collectors.toSet()); - Map map = staticMappingService.proposeSectionMaps(modules, - List.of(programManager.getAllOpenPrograms())); + Map map = + staticMappingService.proposeSectionMaps(modules, current.getSnap(), + List.of(programManager.getAllOpenPrograms())); Collection proposal = MapProposal.flatten(map.values()); Collection filtered = proposal.stream() .filter(e -> sections.contains(e.getSection())) @@ -1232,7 +1244,8 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter return; } TraceModule module = modules.iterator().next(); - SectionMapProposal map = staticMappingService.proposeSectionMap(module, program); + SectionMapProposal map = + staticMappingService.proposeSectionMap(module, current.getSnap(), program); Collection proposal = map.computeMap().values(); Collection filtered = proposal.stream() .filter(e -> sections.contains(e.getSection())) @@ -1249,8 +1262,8 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter if (block == null) { return; } - SectionMapProposal map = - staticMappingService.proposeSectionMap(section, location.getProgram(), block); + SectionMapProposal map = staticMappingService.proposeSectionMap(section, current.getSnap(), + location.getProgram(), block); promptSectionProposal(map.computeMap().values()); } @@ -1444,7 +1457,7 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter Msg.warn(this, "No program manager!"); return null; } - return blockChooserDialog.chooseBlock(getTool(), section, + return blockChooserDialog.chooseBlock(getTool(), section, current.getSnap(), List.of(programManager.getAllOpenPrograms())); } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerSectionActionContext.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerSectionActionContext.java index 12cd5bd80d..bf33e5296b 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerSectionActionContext.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerSectionActionContext.java @@ -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. @@ -45,10 +45,10 @@ public class DebuggerSectionActionContext extends DefaultActionContext { this.forcedSingle = forcedSingle; } - public Set getSelectedSections(boolean allowExpansion) { + public Set getSelectedSections(boolean allowExpansion, long snap) { if (forcedSingle && allowExpansion) { return selectedSections.stream() - .flatMap(s -> s.getModule().getSections().stream()) + .flatMap(s -> s.getModule().getSections(snap).stream()) .collect(Collectors.toUnmodifiableSet()); } return selectedSections; diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerSectionMapProposalDialog.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerSectionMapProposalDialog.java index 40e7dc6b53..f5c4b38006 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerSectionMapProposalDialog.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerSectionMapProposalDialog.java @@ -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. @@ -42,9 +42,9 @@ public class DebuggerSectionMapProposalDialog protected enum SectionMapTableColumns implements EnumeratedTableColumn { REMOVE("Remove", String.class, e -> "Remove Proposed Entry", (e, v) -> nop()), - MODULE_NAME("Module", String.class, e -> e.getModule().getName()), - SECTION_NAME("Section", String.class, e -> e.getSection().getName()), - DYNAMIC_BASE("Dynamic Base", Address.class, e -> e.getSection().getStart()), + MODULE_NAME("Module", String.class, e -> e.getModuleName()), + SECTION_NAME("Section", String.class, e -> e.getSectionName()), + DYNAMIC_BASE("Dynamic Base", Address.class, e -> e.getSectionStart()), CHOOSE("Choose", String.class, e -> "Choose Block", (e, s) -> nop()), PROGRAM_NAME("Program", String.class, e -> e.getToProgram().getName()), BLOCK_NAME("Block", String.class, e -> e.getBlock().getName()), diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/ModuleRow.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/ModuleRow.java index 255225af54..e85c47af6c 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/ModuleRow.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/ModuleRow.java @@ -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,7 +18,6 @@ package ghidra.app.plugin.core.debug.gui.modules; import db.Transaction; import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingUtils; import ghidra.program.model.address.Address; -import ghidra.trace.model.Lifespan; import ghidra.trace.model.modules.TraceModule; public class ModuleRow { @@ -36,16 +35,16 @@ public class ModuleRow { public void setName(String name) { try (Transaction tx = module.getTrace().openTransaction("Renamed module")) { - module.setName(name); + module.setName(0, name); } } public String getShortName() { - return DebuggerStaticMappingUtils.computeModuleShortName(module.getName()); + return DebuggerStaticMappingUtils.computeModuleShortName(module.getName(0)); } public String getName() { - return module.getName(); + return module.getName(0); } public String getMapping() { @@ -54,31 +53,18 @@ public class ModuleRow { // 2. Range/Life changes to this module // 3. Snapshot navigation return DebuggerStaticMappingUtils.computeMappedFiles(module.getTrace(), - provider.current.getSnap(), module.getRange()); + provider.current.getSnap(), module.getRange(0)); } public Address getBase() { - return module.getBase(); + return module.getBase(0); } public Address getMaxAddress() { - return module.getMaxAddress(); - } - - public long getLoadedSnap() { - return module.getLoadedSnap(); - } - - public Long getUnloadedSnap() { - long snap = module.getUnloadedSnap(); - return snap == Long.MAX_VALUE ? null : snap; - } - - public Lifespan getLifespan() { - return module.getLifespan(); + return module.getMaxAddress(0); } public long getLength() { - return module.getLength(); + return module.getLength(0); } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/SectionRow.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/SectionRow.java index ac1da236c7..5f77d51845 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/SectionRow.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/SectionRow.java @@ -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,8 +18,6 @@ package ghidra.app.plugin.core.debug.gui.modules; import db.Transaction; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressRange; -import ghidra.trace.model.DefaultTraceLocation; -import ghidra.trace.model.TraceLocation; import ghidra.trace.model.modules.TraceModule; import ghidra.trace.model.modules.TraceSection; import ghidra.util.Msg; @@ -42,7 +40,7 @@ public class SectionRow { public void setName(String name) { try (Transaction tx = section.getTrace().openTransaction("Rename section")) { - section.setName(name); + section.setName(0, name); } catch (DuplicateNameException e) { Msg.showError(this, null, "Rename Section", @@ -51,31 +49,26 @@ public class SectionRow { } public String getName() { - return section.getName(); + return section.getName(0); } public String getModuleName() { - return section.getModule().getName(); + return section.getModule().getName(0); } public AddressRange getRange() { - return section.getRange(); + return section.getRange(0); } public Address getStart() { - return section.getStart(); + return section.getStart(0); } public Address getEnd() { - return section.getEnd(); + return section.getEnd(0); } public long getLength() { - return section.getRange().getLength(); - } - - public TraceLocation getTraceLocation() { - return new DefaultTraceLocation(section.getModule().getTrace(), null, - section.getModule().getLifespan(), section.getStart()); + return section.getRange(0).getLength(); } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/register/DebuggerRegistersProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/register/DebuggerRegistersProvider.java index a27a48de5e..f9fb1f73cd 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/register/DebuggerRegistersProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/register/DebuggerRegistersProvider.java @@ -783,7 +783,7 @@ public class DebuggerRegistersProvider extends ComponentProviderAdapter protected String computeSubTitle() { TraceThread curThread = current.getThread(); - return curThread == null ? "" : curThread.getName(); + return curThread == null ? "" : curThread.getName(current.getSnap()); } protected void updateSubTitle() { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/stack/DebuggerLegacyStackPanel.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/stack/DebuggerLegacyStackPanel.java index 904868a45c..e87686eebf 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/stack/DebuggerLegacyStackPanel.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/stack/DebuggerLegacyStackPanel.java @@ -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. @@ -129,9 +129,6 @@ public class DebuggerLegacyStackPanel extends JPanel { } private void stackAdded(TraceStack stack) { - if (stack.getSnap() != current.getViewSnap()) { - return; - } TraceThread curThread = current.getThread(); if (curThread != stack.getThread()) { return; diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/stack/DebuggerStackProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/stack/DebuggerStackProvider.java index 752886e420..da08076bf9 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/stack/DebuggerStackProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/stack/DebuggerStackProvider.java @@ -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. @@ -145,7 +145,7 @@ public class DebuggerStackProvider extends ComponentProviderAdapter { protected String computeSubTitle() { TraceThread curThread = current.getThread(); - return curThread == null ? "" : curThread.getName(); + return curThread == null ? "" : curThread.getName(current.getSnap()); } protected void updateSubTitle() { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/stack/vars/VariableValueUtils.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/stack/vars/VariableValueUtils.java index d4f2f2f7c7..0c102676b1 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/stack/vars/VariableValueUtils.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/stack/vars/VariableValueUtils.java @@ -269,9 +269,10 @@ public enum VariableValueUtils { RegisterValue spRV = regs.getValue(platform, viewSnap, sp); Address spVal = cSpec.getStackBaseSpace().getAddress(spRV.getUnsignedValue().longValue()); Address max; - TraceMemoryRegion stackRegion = mem.getRegionContaining(coordinates.getSnap(), spVal); + long snap = coordinates.getSnap(); + TraceMemoryRegion stackRegion = mem.getRegionContaining(snap, spVal); if (stackRegion != null) { - max = stackRegion.getMaxAddress(); + max = stackRegion.getMaxAddress(snap); } else { long toMax = spVal.getAddressSpace().getMaxAddress().subtract(spVal); @@ -408,7 +409,7 @@ public enum VariableValueUtils { if (stack == null) { return null; } - TraceStackFrame frame = stack.getFrame(0, false); + TraceStackFrame frame = stack.getFrame(snap, 0, false); if (frame == null) { return null; } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/thread/DebuggerLegacyThreadsPanel.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/thread/DebuggerLegacyThreadsPanel.java index 664c6969f7..87e3e18452 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/thread/DebuggerLegacyThreadsPanel.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/thread/DebuggerLegacyThreadsPanel.java @@ -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,10 +38,10 @@ import ghidra.framework.model.DomainObjectEvent; import ghidra.framework.plugintool.AutoService; import ghidra.framework.plugintool.annotation.AutoServiceConsumed; import ghidra.program.model.address.Address; -import ghidra.trace.model.*; +import ghidra.trace.model.Trace; +import ghidra.trace.model.TraceDomainObjectListener; import ghidra.trace.model.thread.TraceThread; import ghidra.trace.model.thread.TraceThreadManager; -import ghidra.trace.model.time.TraceSnapshot; import ghidra.trace.util.TraceEvents; import ghidra.util.database.ObjectKey; import ghidra.util.table.GhidraTable; @@ -62,12 +62,9 @@ public class DebuggerLegacyThreadsPanel extends JPanel { true, true), MODULE("Module", String.class, ThreadRow::getModule, true, false), SP("SP", Address.class, ThreadRow::getStackPointer, true, false), - CREATED("Created", Long.class, ThreadRow::getCreationSnap, true, false), - DESTROYED("Destroyed", String.class, ThreadRow::getDestructionSnap, true, false), STATE("State", ThreadState.class, ThreadRow::getState, true, true), - COMMENT("Comment", String.class, ThreadRow::getComment, ThreadRow::setComment, true, false), - PLOT("Plot", Lifespan.class, ThreadRow::getLifespan, false, true); + COMMENT("Comment", String.class, ThreadRow::getComment, ThreadRow::setComment, true, false); private final String header; private final Function getter; @@ -145,9 +142,6 @@ public class DebuggerLegacyThreadsPanel extends JPanel { listenFor(TraceEvents.THREAD_CHANGED, this::threadChanged); listenFor(TraceEvents.THREAD_LIFESPAN_CHANGED, this::threadChanged); listenFor(TraceEvents.THREAD_DELETED, this::threadDeleted); - - listenFor(TraceEvents.SNAPSHOT_ADDED, this::snapAdded); - listenFor(TraceEvents.SNAPSHOT_DELETED, this::snapDeleted); } private void objectRestored(DomainObjectChangeRecord rec) { @@ -165,14 +159,6 @@ public class DebuggerLegacyThreadsPanel extends JPanel { private void threadDeleted(TraceThread thread) { threadTableModel.deleteItem(thread); } - - private void snapAdded(TraceSnapshot snapshot) { - updateTimelineMax(); - } - - private void snapDeleted() { - updateTimelineMax(); - } } private final DebuggerThreadsProvider provider; @@ -187,10 +173,6 @@ public class DebuggerLegacyThreadsPanel extends JPanel { private final ForThreadsListener forThreadsListener = new ForThreadsListener(); - /* package access for testing */ - final SpanTableCellRenderer spanRenderer = new SpanTableCellRenderer<>(); - final RangeCursorTableHeaderRenderer headerRenderer; - final TableCellRenderer boldCurrentRenderer = new AbstractGColumnRenderer() { @Override public String getFilterString(Object t, Settings settings) { @@ -225,8 +207,6 @@ public class DebuggerLegacyThreadsPanel extends JPanel { this.autoServiceWiring = AutoService.wireServicesConsumed(plugin, this); threadTableModel = new ThreadTableModel(provider); - headerRenderer = new RangeCursorTableHeaderRenderer<>(0L, - threadTableModel.getColumn(ThreadTableColumns.PLOT.ordinal())); threadTable = new GhidraTable(threadTableModel); threadTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); add(new JScrollPane(threadTable)); @@ -269,32 +249,10 @@ public class DebuggerLegacyThreadsPanel extends JPanel { TableColumnModel columnModel = threadTable.getColumnModel(); TableColumn colName = columnModel.getColumn(ThreadTableColumns.NAME.ordinal()); colName.setCellRenderer(boldCurrentRenderer); - TableColumn colCreated = columnModel.getColumn(ThreadTableColumns.CREATED.ordinal()); - colCreated.setCellRenderer(boldCurrentRenderer); - TableColumn colDestroyed = columnModel.getColumn(ThreadTableColumns.DESTROYED.ordinal()); - colDestroyed.setCellRenderer(boldCurrentRenderer); TableColumn colState = columnModel.getColumn(ThreadTableColumns.STATE.ordinal()); colState.setCellRenderer(boldCurrentRenderer); TableColumn colComment = columnModel.getColumn(ThreadTableColumns.COMMENT.ordinal()); colComment.setCellRenderer(boldCurrentRenderer); - TableColumn colPlot = columnModel.getColumn(ThreadTableColumns.PLOT.ordinal()); - colPlot.setCellRenderer(spanRenderer); - colPlot.setHeaderRenderer(headerRenderer); - - headerRenderer.addSeekListener(seekListener = pos -> { - long snap = Math.round(pos); - if (snap < 0) { - snap = 0; - } - long max = - current.getTrace() == null ? 0 : current.getTrace().getTimeManager().getMaxSnap(); - if (snap > max) { - snap = max; - } - traceManager.activateSnap(snap); - myActionContext = new DebuggerSnapActionContext(current.getTrace(), snap); - provider.legacyThreadsPanelContextChanged(); - }); } private void removeOldListeners() { @@ -326,7 +284,6 @@ public class DebuggerLegacyThreadsPanel extends JPanel { current = coordinates; doSetTrace(coordinates.getTrace()); doSetThread(coordinates.getThread()); - doSetSnap(coordinates.getSnap()); } private void doSetThread(TraceThread thread) { @@ -339,11 +296,6 @@ public class DebuggerLegacyThreadsPanel extends JPanel { threadTableModel.fireTableDataChanged(); } - private void doSetSnap(long snap) { - headerRenderer.setCursorPosition(snap); - threadTable.getTableHeader().repaint(); - } - protected void loadThreads() { threadTableModel.clear(); Trace curTrace = current.getTrace(); @@ -352,16 +304,6 @@ public class DebuggerLegacyThreadsPanel extends JPanel { } TraceThreadManager manager = curTrace.getThreadManager(); threadTableModel.addAllItems(manager.getAllThreads()); - updateTimelineMax(); - } - - protected void updateTimelineMax() { - Trace trace = current.getTrace(); - long max = orZero(trace == null ? null : trace.getTimeManager().getMaxSnap()); - Lifespan fullRange = Lifespan.span(0, max + 1); - spanRenderer.setFullRange(fullRange); - headerRenderer.setFullRange(fullRange); - threadTable.getTableHeader().repaint(); } private void threadRowSelected(ListSelectionEvent e) { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/thread/ThreadRow.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/thread/ThreadRow.java index 03eeb177af..217e022da1 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/thread/ThreadRow.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/thread/ThreadRow.java @@ -23,7 +23,8 @@ import ghidra.debug.api.target.Target; import ghidra.debug.api.tracemgr.DebuggerCoordinates; import ghidra.program.model.address.Address; import ghidra.program.model.listing.Function; -import ghidra.trace.model.*; +import ghidra.trace.model.Trace; +import ghidra.trace.model.TraceExecutionState; import ghidra.trace.model.thread.TraceThread; import ghidra.util.Msg; @@ -46,12 +47,12 @@ public class ThreadRow { public void setName(String name) { try (Transaction tx = thread.getTrace().openTransaction("Rename thread")) { - thread.setName(name); + thread.setName(0, name); } } public String getName() { - return thread.getName(); + return thread.getName(0); } private Address computeProgramCounter(DebuggerCoordinates coords) { @@ -82,33 +83,19 @@ public class ThreadRow { return SPLocationTrackingSpec.INSTANCE.computeTraceAddress(provider.getTool(), coords); } - public long getCreationSnap() { - return thread.getCreationSnap(); - } - - // TODO: Use a renderer to make this transformation instead, otherwise sorting is off. - public String getDestructionSnap() { - long snap = thread.getDestructionSnap(); - return snap == Long.MAX_VALUE ? "" : Long.toString(snap); - } - - public Lifespan getLifespan() { - return thread.getLifespan(); - } - public void setComment(String comment) { try (Transaction tx = thread.getTrace().openTransaction("Set thread comment")) { - thread.setComment(comment); + thread.setComment(0, comment); } } public String getComment() { - return thread.getComment(); + return thread.getComment(0); } public ThreadState getState() { // TODO: Once transition to TraceRmi is complete, this is all in TraceObjectManager - if (!thread.isAlive()) { + if (!thread.isValid(Long.MAX_VALUE)) { return ThreadState.TERMINATED; } if (provider.targetService == null) { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/time/SnapshotRow.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/time/SnapshotRow.java index 9585c83262..7fc00572dc 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/time/SnapshotRow.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/time/SnapshotRow.java @@ -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. @@ -48,7 +48,7 @@ public class SnapshotRow { public String getEventThreadName() { TraceThread thread = snapshot.getEventThread(); - return thread == null ? "" : thread.getName(); + return thread == null ? "" : thread.getName(snapshot.getKey()); } public String getSchedule() { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/dbgeng/DbgengX64DisassemblyInject.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/dbgeng/DbgengX64DisassemblyInject.java index 6e9d4d774f..2c25fe9dad 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/dbgeng/DbgengX64DisassemblyInject.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/platform/dbgeng/DbgengX64DisassemblyInject.java @@ -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. @@ -66,7 +66,7 @@ public class DbgengX64DisassemblyInject implements DisassemblyInject { Collection modules = trace.getModuleManager().getModulesAt(snap, first.getMinAddress()); Msg.debug(this, "Disassembling in modules: " + - modules.stream().map(TraceModule::getName).collect(Collectors.joining(","))); + modules.stream().map(m -> m.getName(snap)).collect(Collectors.joining(","))); Set modes = modules.stream() .map(m -> modeForModule(target, trace, snap, m)) .filter(m -> m != Mode.UNK) @@ -101,7 +101,7 @@ public class DbgengX64DisassemblyInject implements DisassemblyInject { TraceModule module) { if (target != null && target.getSnap() == snap) { AddressSet set = new AddressSet(); - set.add(module.getBase(), module.getBase()); // Recorder should read page + set.add(module.getBase(snap), module.getBase(snap)); // Recorder should read page try { target.readMemory(set, TaskMonitor.DUMMY); trace.flushEvents(); @@ -110,7 +110,7 @@ public class DbgengX64DisassemblyInject implements DisassemblyInject { throw new AssertionError(e); } } - MemBuffer bufferAt = trace.getMemoryManager().getBufferAt(snap, module.getBase()); + MemBuffer bufferAt = trace.getMemoryManager().getBufferAt(snap, module.getBase(snap)); try (ByteProvider bp = new MemBufferByteProvider(bufferAt)) { PortableExecutable pe = new PortableExecutable(bp, SectionLayout.MEMORY, false, false); NTHeader ntHeader = pe.getNTHeader(); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/BreakpointActionSet.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/BreakpointActionSet.java index 75d8bc41e2..dd40e734da 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/BreakpointActionSet.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/BreakpointActionSet.java @@ -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. @@ -36,7 +36,8 @@ public class BreakpointActionSet extends LinkedHashSet { /** * Add an item to enable a target breakpoint * - * @param loc the target breakpoint + * @param target the target + * @param bpt the target breakpoint * @return the added item */ public EnableTargetBreakpointActionItem planEnableTarget(Target target, TraceBreakpoint bpt) { @@ -49,10 +50,11 @@ public class BreakpointActionSet extends LinkedHashSet { * Add an item to enable an emulated breakpoint * * @param bpt the trace breakpoint + * @param snap the snap * @return the added item */ - public EnableEmuBreakpointActionItem planEnableEmu(TraceBreakpoint bpt) { - EnableEmuBreakpointActionItem action = new EnableEmuBreakpointActionItem(bpt); + public EnableEmuBreakpointActionItem planEnableEmu(TraceBreakpoint bpt, long snap) { + EnableEmuBreakpointActionItem action = new EnableEmuBreakpointActionItem(bpt, snap); add(action); return action; } @@ -60,7 +62,8 @@ public class BreakpointActionSet extends LinkedHashSet { /** * Add an item to disable a target breakpoint * - * @param loc the target breakpoint + * @param target the target + * @param bpt the target breakpoint * @return the added item */ public DisableTargetBreakpointActionItem planDisableTarget(Target target, TraceBreakpoint bpt) { @@ -74,10 +77,11 @@ public class BreakpointActionSet extends LinkedHashSet { * Add an item to disable an emulated breakpoint * * @param bpt the trace breakpoint + * @param snap the snap * @return the added item */ - public DisableEmuBreakpointActionItem planDisableEmu(TraceBreakpoint bpt) { - DisableEmuBreakpointActionItem action = new DisableEmuBreakpointActionItem(bpt); + public DisableEmuBreakpointActionItem planDisableEmu(TraceBreakpoint bpt, long snap) { + DisableEmuBreakpointActionItem action = new DisableEmuBreakpointActionItem(bpt, snap); add(action); return action; } @@ -85,7 +89,8 @@ public class BreakpointActionSet extends LinkedHashSet { /** * Add an item to delete a target breakpoint * - * @param loc the target breakpoint + * @param target the target + * @param bpt the target breakpoint * @return the added item */ public DeleteTargetBreakpointActionItem planDeleteTarget(Target target, TraceBreakpoint bpt) { @@ -98,10 +103,11 @@ public class BreakpointActionSet extends LinkedHashSet { * Add an item to delete an emulated breakpoint * * @param bpt the trace breakpoint + * @param snap the snap * @return the added item */ - public DeleteEmuBreakpointActionItem planDeleteEmu(TraceBreakpoint bpt) { - DeleteEmuBreakpointActionItem action = new DeleteEmuBreakpointActionItem(bpt); + public DeleteEmuBreakpointActionItem planDeleteEmu(TraceBreakpoint bpt, long snap) { + DeleteEmuBreakpointActionItem action = new DeleteEmuBreakpointActionItem(bpt, snap); add(action); return action; } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/DebuggerLogicalBreakpointServicePlugin.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/DebuggerLogicalBreakpointServicePlugin.java index 854bb2c388..edd7302648 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/DebuggerLogicalBreakpointServicePlugin.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/DebuggerLogicalBreakpointServicePlugin.java @@ -16,6 +16,7 @@ package ghidra.app.plugin.core.debug.service.breakpoint; import java.util.*; +import java.util.Map.Entry; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.function.*; @@ -219,7 +220,7 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin } private void breakpointAdded(TraceBreakpoint tb) { - if (!tb.isAlive(info.snap)) { + if (!tb.isValid(info.snap)) { return; } try { @@ -232,7 +233,7 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin } private void breakpointChanged(TraceBreakpoint tb) { - if (!tb.isAlive(info.snap)) { + if (!tb.isValid(info.snap)) { return; } try { @@ -338,7 +339,7 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin } protected abstract class AbstractInfo { - final NavigableMap> breakpointsByAddress = + final NavigableMap> logicalByAddress = new TreeMap<>(); public AbstractInfo() { @@ -350,47 +351,30 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin long length, Collection kinds); protected LogicalBreakpointInternal getOrCreateLogicalBreakpointFor(AddCollector a, - Address address, TraceBreakpoint tb) throws TrackedTooSoonException { + Address address, TraceBreakpoint tb, long snap) throws TrackedTooSoonException { Set set = - breakpointsByAddress.computeIfAbsent(address, __ -> new HashSet<>()); + logicalByAddress.computeIfAbsent(address, __ -> new HashSet<>()); for (LogicalBreakpointInternal lb : set) { - if (lb.canMerge(tb)) { + if (lb.canMerge(tb, snap)) { return lb; } } LogicalBreakpointInternal lb = - createLogicalBreakpoint(address, tb.getLength(), tb.getKinds()); + createLogicalBreakpoint(address, tb.getLength(snap), tb.getKinds(snap)); set.add(lb); a.added(lb); return lb; } - protected LogicalBreakpointInternal removeFromLogicalBreakpoint(RemoveCollector r, - Address address, TraceBreakpoint tb) { - Set set = breakpointsByAddress.get(address); - if (set == null) { - return null; - } - for (LogicalBreakpointInternal lb : Set.copyOf(set)) { - if (lb.untrackBreakpoint(tb)) { - if (lb.isEmpty()) { - // If being disposed, this info is no longer in the map - removeLogicalBreakpoint(address, lb); - removeLogicalBreakpointGlobally(lb); - r.removed(lb); - } - else { - r.updated(lb); - } - return lb; + protected boolean removeLogicalBreakpoint(Address address, LogicalBreakpoint lb) { + for (TraceBreakpoint tb : lb.getTraceBreakpoints()) { + InfoPerTrace info = traceInfos.get(tb.getTrace()); + if (info != null) { + info.logicalByBreakpoint.remove(tb); } } - return null; - } - - protected boolean removeLogicalBreakpoint(Address address, LogicalBreakpoint lb) { - Set set = breakpointsByAddress.get(address); + Set set = logicalByAddress.get(address); if (set == null) { return false; } @@ -398,7 +382,7 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin return false; } if (set.isEmpty()) { - breakpointsByAddress.remove(address); + logicalByAddress.remove(address); } return true; } @@ -429,7 +413,7 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin protected void forgetMismappedBreakpoints(RemoveCollector r, Set additionalTraces, Set additionalPrograms) { - for (Set set : List.copyOf(breakpointsByAddress.values())) { + for (Set set : List.copyOf(logicalByAddress.values())) { for (LogicalBreakpointInternal lb : Set.copyOf(set)) { if (isMismapped(lb)) { removeLogicalBreakpointGlobally(lb); @@ -442,6 +426,8 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin } protected class InfoPerTrace extends AbstractInfo { + final Map logicalByBreakpoint = new HashMap<>(); + final Trace trace; final TraceBreakpointsListener breakpointListener; @@ -508,30 +494,30 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin * has changed or become invalid, or because it has no live breakpoint in target mode. */ ControlMode mode = getMode(trace); - for (Set set : List.copyOf(breakpointsByAddress.values())) { - for (LogicalBreakpointInternal lb : Set.copyOf(set)) { - for (TraceBreakpoint tb : Set.copyOf(lb.getTraceBreakpoints(trace))) { - if (!mode.useEmulatedBreakpoints() && - (target == null || !target.isBreakpointValid(tb))) { - forgetTraceBreakpoint(r, tb); - continue; - } - if (!trace.getBreakpointManager().getAllBreakpoints().contains(tb)) { - forgetTraceBreakpoint(r, tb); - continue; - } - if (!tb.isAlive(snap)) { - forgetTraceBreakpoint(r, tb); - continue; - } - ProgramLocation progLoc = computeStaticLocation(tb); - if (!Objects.equals(lb.getProgramLocation(), progLoc)) { - // NOTE: This can happen to Lone breakpoints. - // (mis)Mapped ones should already be forgotten. - forgetTraceBreakpoint(r, tb); - continue; - } - } + + for (Entry ent : Set + .copyOf(logicalByBreakpoint.entrySet())) { + TraceBreakpoint tb = ent.getKey(); + LogicalBreakpoint lb = ent.getValue(); + if (!mode.useEmulatedBreakpoints() && + (target == null || !target.isBreakpointValid(tb))) { + forgetTraceBreakpoint(r, tb); + continue; + } + if (!trace.getBreakpointManager().getAllBreakpoints().contains(tb)) { + forgetTraceBreakpoint(r, tb); + continue; + } + if (!tb.isValid(snap)) { + forgetTraceBreakpoint(r, tb); + continue; + } + ProgramLocation progLoc = computeStaticLocation(tb); + if (!Objects.equals(lb.getProgramLocation(), progLoc)) { + // NOTE: This can happen to Lone breakpoints. + // (mis)Mapped ones should already be forgotten. + forgetTraceBreakpoint(r, tb); + continue; } } } @@ -571,7 +557,7 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin */ return null; } - Address minAddress = tb.getMinAddress(); + Address minAddress = tb.getMinAddress(snap); if (minAddress == null) { return null; } @@ -585,7 +571,7 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin (target == null || !target.isBreakpointValid(tb))) { return; } - Address traceAddr = tb.getMinAddress(); + Address traceAddr = tb.getMinAddress(snap); if (traceAddr == null) { return; // Will update via breakpointChanged when address is set } @@ -593,24 +579,44 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin LogicalBreakpointInternal lb; if (progLoc != null) { InfoPerProgram progInfo = programInfos.get(progLoc.getProgram()); - lb = progInfo.getOrCreateLogicalBreakpointFor(a, progLoc.getByteAddress(), tb); + lb = progInfo.getOrCreateLogicalBreakpointFor(a, progLoc.getByteAddress(), tb, + snap); } else { - lb = getOrCreateLogicalBreakpointFor(a, traceAddr, tb); + lb = getOrCreateLogicalBreakpointFor(a, traceAddr, tb, snap); } - assert breakpointsByAddress.get(traceAddr).contains(lb); + assert logicalByAddress.get(traceAddr).contains(lb); + logicalByBreakpoint.put(tb, lb); if (lb.trackBreakpoint(tb) || forceUpdate) { a.updated(lb); } } + protected LogicalBreakpointInternal removeFromLogicalBreakpoint(RemoveCollector r, + TraceBreakpoint tb) { + LogicalBreakpointInternal lb = logicalByBreakpoint.remove(tb); + if (lb == null || !lb.untrackBreakpoint(tb)) { + return null; + } + if (lb.isEmpty()) { + // If being disposed, this info is no longer in the map + removeLogicalBreakpoint(lb.getTraceAddress(trace), lb); + removeLogicalBreakpointGlobally(lb); + r.removed(lb); + } + else { + r.updated(lb); + } + return lb; + } + protected void forgetTraceBreakpoint(RemoveCollector r, TraceBreakpoint tb) { - LogicalBreakpointInternal lb = removeFromLogicalBreakpoint(r, tb.getMinAddress(), tb); + LogicalBreakpointInternal lb = removeFromLogicalBreakpoint(r, tb); if (lb == null) { return; // Warnings already logged } - assert lb.isEmpty() == (breakpointsByAddress.get(tb.getMinAddress()) == null || - !breakpointsByAddress.get(tb.getMinAddress()).contains(lb)); + assert lb.isEmpty() == (logicalByAddress.get(lb.getTraceAddress(trace)) == null || + !logicalByAddress.get(tb.getMinAddress(snap)).contains(lb)); } public TraceLocation toDynamicLocation(ProgramLocation loc) { @@ -641,7 +647,7 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin } lb.setTraceAddress(ti.trace, loc.getAddress()); lb.setTarget(ti.trace, ti.target); - ti.breakpointsByAddress.computeIfAbsent(loc.getAddress(), __ -> new HashSet<>()) + ti.logicalByAddress.computeIfAbsent(loc.getAddress(), __ -> new HashSet<>()) .add(lb); } } @@ -659,7 +665,7 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin Bookmark pb) { Address address = pb.getAddress(); Set set = - breakpointsByAddress.computeIfAbsent(address, __ -> new HashSet<>()); + logicalByAddress.computeIfAbsent(address, __ -> new HashSet<>()); for (LogicalBreakpointInternal lb : set) { if (lb.canMerge(program, pb)) { return lb; @@ -676,7 +682,7 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin protected LogicalBreakpointInternal removeFromLogicalBreakpoint(RemoveCollector r, Bookmark pb, boolean forChange) { Address address = pb.getAddress(); - Set set = breakpointsByAddress.get(address); + Set set = logicalByAddress.get(address); if (set == null) { Msg.error(this, "Breakpoint " + pb + " was not tracked before removal!"); return null; @@ -731,7 +737,7 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin * NOTE: A change in the program (other than bookmark address), should not affect the * mapped trace addresses. That would require a change in the trace. */ - for (Set set : List.copyOf(breakpointsByAddress.values())) { + for (Set set : List.copyOf(logicalByAddress.values())) { for (LogicalBreakpointInternal lb : Set.copyOf(set)) { Bookmark pb = lb.getProgramBookmark(); if (pb == null) { @@ -765,7 +771,7 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin protected void trackProgramBreakpoint(AddCollector a, Bookmark pb) { LogicalBreakpointInternal lb = getOrCreateLogicalBreakpointFor(a, pb); - assert breakpointsByAddress.get(pb.getAddress()).contains(lb); + assert logicalByAddress.get(pb.getAddress()).contains(lb); if (lb.trackBreakpoint(pb)) { a.updated(lb); } @@ -781,7 +787,7 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin private boolean isConsistentAfterRemoval(Bookmark pb, LogicalBreakpointInternal lb, boolean forChange) { - Set present = breakpointsByAddress.get(pb.getAddress()); + Set present = logicalByAddress.get(pb.getAddress()); boolean shouldBeAbsent = lb.isEmpty() && !forChange; boolean isAbsent = present == null || !present.contains(lb); return shouldBeAbsent == isAbsent; @@ -967,7 +973,7 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin } tInfo.dispose(c.r); for (InfoPerProgram pInfo : programInfos.values()) { - for (Set set : pInfo.breakpointsByAddress.values()) { + for (Set set : pInfo.logicalByAddress.values()) { for (LogicalBreakpointInternal lb : set) { lb.removeTrace(trace); c.a.updated(lb); @@ -1021,7 +1027,7 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin synchronized (lock) { Set records = new HashSet<>(); for (AbstractInfo info : allInfos) { - for (Set recsAtAddress : info.breakpointsByAddress + for (Set recsAtAddress : info.logicalByAddress .values()) { records.addAll(recsAtAddress); } @@ -1046,7 +1052,7 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin if (info == null) { return Collections.emptyNavigableMap(); } - return copyOf(info.breakpointsByAddress); + return copyOf(info.logicalByAddress); } } @@ -1057,12 +1063,12 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin if (info == null) { return Collections.emptyNavigableMap(); } - return copyOf(info.breakpointsByAddress); + return copyOf(info.logicalByAddress); } } protected Set doGetBreakpointsAt(AbstractInfo info, Address address) { - Set set = info.breakpointsByAddress.get(address); + Set set = info.logicalByAddress.get(address); if (set == null) { return Set.of(); } @@ -1097,7 +1103,11 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin public LogicalBreakpoint getBreakpoint(TraceBreakpoint bpt) { Trace trace = bpt.getTrace(); synchronized (lock) { - Address address = bpt.getMinAddress(); + InfoPerTrace info = traceInfos.get(trace); + if (info == null) { + return null; + } + Address address = bpt.getMinAddress(info.snap); if (address == null) { return null; } @@ -1250,9 +1260,16 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin void accept(BreakpointActionSet actions, Target target, TraceBreakpoint tb); } + interface EmuBreakpointConsumer { + void accept(BreakpointActionSet actions, TraceBreakpoint tb, long snap); + } + + interface ProgramBreakpointConsumer { + void accept(LogicalBreakpoint lb); + } + private void planActOnLoc(BreakpointActionSet actions, TraceBreakpoint tb, - TargetBreakpointConsumer targetBptConsumer, - BiConsumer emuLocConsumer) { + TargetBreakpointConsumer targetBptConsumer, EmuBreakpointConsumer emuLocConsumer) { ControlMode mode = getMode(tb.getTrace()); if (mode.useEmulatedBreakpoints()) { planActOnLocEmu(actions, tb, emuLocConsumer); @@ -1272,14 +1289,19 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin } private void planActOnLocEmu(BreakpointActionSet actions, TraceBreakpoint tb, - BiConsumer emuLocConsumer) { - emuLocConsumer.accept(actions, tb); + EmuBreakpointConsumer emuLocConsumer) { + InfoPerTrace info = traceInfos.get(tb.getTrace()); + if (info == null) { + Msg.error(this, "No longer tracking " + tb); + return; + } + emuLocConsumer.accept(actions, tb, info.snap); } protected CompletableFuture actOnLocs(Collection col, TargetBreakpointConsumer targetBptConsumer, - BiConsumer emuLocConsumer, - Consumer progConsumer) { + EmuBreakpointConsumer emuLocConsumer, + ProgramBreakpointConsumer progConsumer) { BreakpointActionSet actions = new BreakpointActionSet(); for (TraceBreakpoint tb : col) { LogicalBreakpoint lb = getBreakpoint(tb); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/DeleteEmuBreakpointActionItem.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/DeleteEmuBreakpointActionItem.java index 7df3edb371..f4132a638c 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/DeleteEmuBreakpointActionItem.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/DeleteEmuBreakpointActionItem.java @@ -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. @@ -21,17 +21,18 @@ import db.Transaction; import ghidra.async.AsyncUtils; import ghidra.trace.model.breakpoint.TraceBreakpoint; -public record DeleteEmuBreakpointActionItem(TraceBreakpoint bpt) implements BreakpointActionItem { +public record DeleteEmuBreakpointActionItem(TraceBreakpoint bpt, long snap) + implements BreakpointActionItem { @Override public CompletableFuture execute() { try (Transaction tx = bpt.getTrace().openTransaction("Delete Emulated Breakpoint")) { - String emuName = PlaceEmuBreakpointActionItem.createName(bpt.getMinAddress()); + String emuName = PlaceEmuBreakpointActionItem.createName(bpt.getMinAddress(snap)); if (bpt.getPath().contains(emuName)) { bpt.delete(); } else { - bpt.setEmuEnabled(false); + bpt.setEmuEnabled(snap, false); } } return AsyncUtils.nil(); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/DisableEmuBreakpointActionItem.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/DisableEmuBreakpointActionItem.java index 88313b55c4..742b084f27 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/DisableEmuBreakpointActionItem.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/DisableEmuBreakpointActionItem.java @@ -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. @@ -21,13 +21,13 @@ import db.Transaction; import ghidra.async.AsyncUtils; import ghidra.trace.model.breakpoint.TraceBreakpoint; -public record DisableEmuBreakpointActionItem(TraceBreakpoint bpt) +public record DisableEmuBreakpointActionItem(TraceBreakpoint bpt, long snap) implements BreakpointActionItem { @Override public CompletableFuture execute() { try (Transaction tx = bpt.getTrace().openTransaction("Disable Emulated Breakpoint")) { - bpt.setEmuEnabled(false); + bpt.setEmuEnabled(snap, false); } return AsyncUtils.nil(); } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/EnableEmuBreakpointActionItem.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/EnableEmuBreakpointActionItem.java index 8a90a5271c..24a59242cf 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/EnableEmuBreakpointActionItem.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/EnableEmuBreakpointActionItem.java @@ -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. @@ -21,12 +21,13 @@ import db.Transaction; import ghidra.async.AsyncUtils; import ghidra.trace.model.breakpoint.TraceBreakpoint; -public record EnableEmuBreakpointActionItem(TraceBreakpoint bpt) implements BreakpointActionItem { +public record EnableEmuBreakpointActionItem(TraceBreakpoint bpt, long snap) + implements BreakpointActionItem { @Override public CompletableFuture execute() { try (Transaction tx = bpt.getTrace().openTransaction("Enable Emulated Breakpoint")) { - bpt.setEmuEnabled(true); + bpt.setEmuEnabled(snap, true); } return AsyncUtils.nil(); } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/LogicalBreakpointInternal.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/LogicalBreakpointInternal.java index 87e0ae2f2f..1c5ce972aa 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/LogicalBreakpointInternal.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/LogicalBreakpointInternal.java @@ -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. @@ -56,10 +56,11 @@ public interface LogicalBreakpointInternal extends LogicalBreakpoint { * breakpoint history provider handles displaying records from the past, including dead traces. * * @param breakpoint the trace breakpoint to check + * @param snap the snap * @return true if it can be aggregated. * @throws TrackedTooSoonException if the containing trace is still being added to the manager */ - boolean canMerge(TraceBreakpoint breakpoint) throws TrackedTooSoonException; + boolean canMerge(TraceBreakpoint breakpoint, long snap) throws TrackedTooSoonException; boolean trackBreakpoint(Bookmark bookmark); @@ -74,7 +75,6 @@ public interface LogicalBreakpointInternal extends LogicalBreakpoint { * * @param actions the destination action set (plan) * @param trace a trace, if actions should be limited to the given trace - * @return a future which completes when the actions are populated */ void planEnable(BreakpointActionSet actions, Trace trace); @@ -83,7 +83,6 @@ public interface LogicalBreakpointInternal extends LogicalBreakpoint { * * @param actions the destination action set (plan) * @param trace a trace, if actions should be limited to the given trace - * @return a future which completes when the actions are populated */ void planDisable(BreakpointActionSet actions, Trace trace); @@ -92,7 +91,6 @@ public interface LogicalBreakpointInternal extends LogicalBreakpoint { * * @param actions the destination action set (plan) * @param trace a trace, if actions should be limited to the given trace - * @return a future which completes when the actions are populated */ void planDelete(BreakpointActionSet actions, Trace trace); } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/LoneLogicalBreakpoint.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/LoneLogicalBreakpoint.java index 89303e50db..010d12b588 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/LoneLogicalBreakpoint.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/LoneLogicalBreakpoint.java @@ -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. @@ -278,8 +278,8 @@ public class LoneLogicalBreakpoint implements LogicalBreakpointInternal { } @Override - public boolean canMerge(TraceBreakpoint breakpoint) { - if (!Objects.equals(kinds, breakpoint.getKinds())) { + public boolean canMerge(TraceBreakpoint breakpoint, long snap) { + if (!Objects.equals(kinds, breakpoint.getKinds(snap))) { return false; } return breaks.canMerge(breakpoint); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/MappedLogicalBreakpoint.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/MappedLogicalBreakpoint.java index 439dd6a853..8f533b2358 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/MappedLogicalBreakpoint.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/MappedLogicalBreakpoint.java @@ -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. @@ -478,7 +478,7 @@ public class MappedLogicalBreakpoint implements LogicalBreakpointInternal { } @Override - public boolean canMerge(TraceBreakpoint breakpoint) throws TrackedTooSoonException { + public boolean canMerge(TraceBreakpoint breakpoint, long snap) throws TrackedTooSoonException { TraceBreakpointSet breaks; synchronized (traceBreaks) { breaks = traceBreaks.get(breakpoint.getTrace()); @@ -494,10 +494,10 @@ public class MappedLogicalBreakpoint implements LogicalBreakpointInternal { */ throw new TrackedTooSoonException(); } - if (length != breakpoint.getLength()) { + if (length != breakpoint.getLength(snap)) { return false; } - if (!Objects.equals(kinds, breakpoint.getKinds())) { + if (!Objects.equals(kinds, breakpoint.getKinds(snap))) { return false; } return breaks.canMerge(breakpoint); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/PlaceEmuBreakpointActionItem.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/PlaceEmuBreakpointActionItem.java index 773577f5cd..c8e3007c80 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/PlaceEmuBreakpointActionItem.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/PlaceEmuBreakpointActionItem.java @@ -112,8 +112,8 @@ public record PlaceEmuBreakpointActionItem(Trace trace, long snap, Address addre TraceBreakpoint bpt = trace.getBreakpointManager() .addBreakpoint(computePath(), Lifespan.at(snap), BreakpointActionItem.range(address, length), Set.of(), kinds, false, null); - bpt.setName(createName(address)); - bpt.setEmuSleigh(emuSleigh); + bpt.setName(snap, createName(address)); + bpt.setEmuSleigh(snap, emuSleigh); return AsyncUtils.nil(); } catch (DuplicateNameException e) { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/TraceBreakpointSet.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/TraceBreakpointSet.java index 31c2100629..c91b59bb36 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/TraceBreakpointSet.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/TraceBreakpointSet.java @@ -192,9 +192,10 @@ class TraceBreakpointSet { */ public String computeSleigh() { String sleigh = null; + long snap = getSnap(); synchronized (breakpoints) { for (IDHashed bpt : breakpoints) { - String s = bpt.obj.getEmuSleigh(); + String s = bpt.obj.getEmuSleigh(snap); if (sleigh != null && !sleigh.equals(s)) { return null; } @@ -211,10 +212,11 @@ class TraceBreakpointSet { */ public void setEmuSleigh(String emuSleigh) { this.emuSleigh = emuSleigh; + long snap = getSnap(); try (Transaction tx = trace.openTransaction("Set breakpoint Sleigh")) { synchronized (breakpoints) { for (IDHashed bpt : breakpoints) { - bpt.obj.setEmuSleigh(emuSleigh); + bpt.obj.setEmuSleigh(snap, emuSleigh); } } } @@ -253,9 +255,10 @@ class TraceBreakpointSet { * @return true if the set actually changed as a result */ public boolean add(TraceBreakpoint bpt) { - if (SleighUtils.UNCONDITIONAL_BREAK.equals(bpt.getEmuSleigh()) && emuSleigh != null) { + long snap = getSnap(); + if (SleighUtils.UNCONDITIONAL_BREAK.equals(bpt.getEmuSleigh(snap)) && emuSleigh != null) { try (Transaction tx = trace.openTransaction("Set breakpoint Sleigh")) { - bpt.setEmuSleigh(emuSleigh); + bpt.setEmuSleigh(snap, emuSleigh); } } synchronized (breakpoints) { @@ -276,7 +279,7 @@ class TraceBreakpointSet { if (trace != bpt.getTrace()) { return false; } - if (!address.equals(bpt.getMinAddress())) { + if (!address.equals(bpt.getMinAddress(getSnap()))) { return false; } return true; @@ -365,7 +368,7 @@ class TraceBreakpointSet { private void planEnableEmu(BreakpointActionSet actions) { synchronized (breakpoints) { for (IDHashed bpt : breakpoints) { - actions.planEnableEmu(bpt.obj); + actions.planEnableEmu(bpt.obj, getSnap()); } } } @@ -399,7 +402,7 @@ class TraceBreakpointSet { private void planDisableEmu(BreakpointActionSet actions) { synchronized (breakpoints) { for (IDHashed bpt : breakpoints) { - actions.planDisableEmu(bpt.obj); + actions.planDisableEmu(bpt.obj, getSnap()); } } } @@ -433,7 +436,7 @@ class TraceBreakpointSet { private void planDeleteEmu(BreakpointActionSet actions) { synchronized (breakpoints) { for (IDHashed bpt : breakpoints) { - actions.planDeleteEmu(bpt.obj); + actions.planDeleteEmu(bpt.obj, getSnap()); } } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/DebuggerEmulationServicePlugin.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/DebuggerEmulationServicePlugin.java index e23e8a20be..8338b33494 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/DebuggerEmulationServicePlugin.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/DebuggerEmulationServicePlugin.java @@ -664,30 +664,30 @@ public class DebuggerEmulationServicePlugin extends Plugin implements DebuggerEm if (!bpt.isEmuEnabled(snap)) { continue; } - Set kinds = bpt.getKinds(); + Set kinds = bpt.getKinds(snap); boolean isExecute = kinds.contains(TraceBreakpointKind.HW_EXECUTE) || kinds.contains(TraceBreakpointKind.SW_EXECUTE); boolean isRead = kinds.contains(TraceBreakpointKind.READ); boolean isWrite = kinds.contains(TraceBreakpointKind.WRITE); if (isExecute) { + Address minAddress = bpt.getMinAddress(snap); try { - emu.inject(bpt.getMinAddress(), bpt.getEmuSleigh()); + emu.inject(minAddress, bpt.getEmuSleigh(snap)); } catch (Exception e) { // This is a bit broad... - Msg.error(this, - "Error compiling breakpoint Sleigh at " + bpt.getMinAddress(), e); - emu.inject(bpt.getMinAddress(), "emu_injection_err();"); + Msg.error(this, "Error compiling breakpoint Sleigh at " + minAddress, e); + emu.inject(minAddress, "emu_injection_err();"); } } if (isRead && isWrite) { - emu.addAccessBreakpoint(bpt.getRange(), AccessKind.RW); + emu.addAccessBreakpoint(bpt.getRange(snap), AccessKind.RW); } else if (isRead) { - emu.addAccessBreakpoint(bpt.getRange(), AccessKind.R); + emu.addAccessBreakpoint(bpt.getRange(snap), AccessKind.R); } else if (isWrite) { - emu.addAccessBreakpoint(bpt.getRange(), AccessKind.W); + emu.addAccessBreakpoint(bpt.getRange(snap), AccessKind.W); } } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/ProgramEmulationUtils.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/ProgramEmulationUtils.java index 97e52533e1..f48a697046 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/ProgramEmulationUtils.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/ProgramEmulationUtils.java @@ -447,14 +447,14 @@ public class ProgramEmulationUtils { } PathPattern patRegion = computePatternRegion(trace); - String threadName = KeyPath.parseIfIndex(thread.getName()); + String threadName = KeyPath.parseIfIndex(thread.getName(snap)); String path = patRegion.applyKeys(alloc.getMinAddress() + "-stack " + threadName) .getSingletonPath() .toString(); TraceMemoryManager mm = trace.getMemoryManager(); try { return mm.createRegion(path, snap, alloc, - TraceMemoryFlag.READ, TraceMemoryFlag.WRITE).getRange(); + TraceMemoryFlag.READ, TraceMemoryFlag.WRITE).getRange(snap); } catch (TraceOverlappedRegionException e) { Msg.showError(ProgramEmulationUtils.class, null, "Stack conflict", @@ -515,7 +515,7 @@ public class ProgramEmulationUtils { TraceMemoryManager mm = trace.getMemoryManager(); try { return mm.createRegion(path, snap, alloc, - TraceMemoryFlag.READ, TraceMemoryFlag.WRITE).getRange(); + TraceMemoryFlag.READ, TraceMemoryFlag.WRITE).getRange(snap); } catch (TraceOverlappedRegionException e) { Msg.showError(ProgramEmulationUtils.class, null, "Stack conflict", @@ -581,13 +581,13 @@ public class ProgramEmulationUtils { for (AddressRange candidate : left) { if (Long.compareUnsigned(candidate.getLength(), size) >= 0) { AddressRange alloc = new AddressRangeImpl(candidate.getMinAddress(), size); - String threadName = KeyPath.parseIfIndex(thread.getName()); + String threadName = KeyPath.parseIfIndex(thread.getName(snap)); String path = patRegion .applyKeys(alloc.getMinAddress() + "-stack " + threadName) .getSingletonPath() .toString(); return mm.createRegion(path, snap, alloc, - TraceMemoryFlag.READ, TraceMemoryFlag.WRITE).getRange(); + TraceMemoryFlag.READ, TraceMemoryFlag.WRITE).getRange(snap); } } } @@ -682,6 +682,13 @@ public class ProgramEmulationUtils { /** * Same as {@link #doLaunchEmulationThread(Trace, long, Program, Address, Address)}, but within * a transaction + * + * @param trace the trace to contain the new thread + * @param snap the creation snap for the new thread + * @param program the program whose context to use for initial register values + * @param tracePc the program counter in the trace's memory map + * @param programPc the program counter in the program's memory map + * @return the new thread */ public static TraceThread launchEmulationThread(Trace trace, long snap, Program program, Address tracePc, Address programPc) { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/AbstractMapEntry.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/AbstractMapEntry.java index 03f4ebde67..caba26c5bd 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/AbstractMapEntry.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/AbstractMapEntry.java @@ -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,12 +25,15 @@ import ghidra.trace.model.*; public abstract class AbstractMapEntry implements MapEntry { protected final Trace fromTrace; protected final T fromObject; + protected final long snap; protected Program toProgram; protected P toObject; - public AbstractMapEntry(Trace fromTrace, T fromObject, Program toProgram, P toObject) { + public AbstractMapEntry(Trace fromTrace, T fromObject, long snap, Program toProgram, + P toObject) { this.fromTrace = fromTrace; this.fromObject = fromObject; + this.snap = snap; this.toProgram = toProgram; this.toObject = toObject; } @@ -60,6 +63,11 @@ public abstract class AbstractMapEntry implements MapEntry { return fromObject; } + @Override + public Lifespan getFromLifespan() { + return Lifespan.nowOn(snap); + } + @Override public TraceLocation getFromTraceLocation() { return new DefaultTraceLocation(fromTrace, null, getFromLifespan(), diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/AbstractMapProposal.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/AbstractMapProposal.java index 2ffe80c51c..40d0860eb2 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/AbstractMapProposal.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/AbstractMapProposal.java @@ -30,14 +30,18 @@ public abstract class AbstractMapProposal> protected abstract static class Matcher { protected final T fromObject; + protected final long snap; protected final P toObject; + protected final AddressRange fromRange; protected final AddressRange toRange; protected final double score; - protected Matcher(T fromObject, P toObject) { + protected Matcher(T fromObject, long snap, P toObject) { this.fromObject = fromObject; + this.snap = snap; this.toObject = toObject; + this.fromRange = fromObject == null ? null : getFromRange(); this.toRange = toObject == null ? null : getToRange(); this.score = fromObject == null || toObject == null ? 0 : computeScore(); @@ -80,9 +84,15 @@ public abstract class AbstractMapProposal> } protected static abstract class MatcherMap> { + protected final long snap; + protected Map> fromsByJoin = new LinkedHashMap<>(); protected Map map = new LinkedHashMap<>(); + public MatcherMap(long snap) { + this.snap = snap; + } + protected abstract M newMatcher(T fromObject, P toObject); protected abstract K getFromJoinKey(T fromObject); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingProposals.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingProposals.java index 378ea85834..71cac8ea36 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingProposals.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingProposals.java @@ -72,15 +72,22 @@ public enum DebuggerStaticMappingProposals { } protected interface ProposalGenerator> { - MP proposeMap(F from, T to); + MP proposeMap(F from, long snap, T to); - MP proposeBestMap(F from, Collection tos); + MP proposeBestMap(F from, long snap, Collection tos); - Map proposeBestMaps(Collection froms, Collection tos); + Map proposeBestMaps(Collection froms, long snap, + Collection tos); } protected abstract static class AbstractProposalGenerator // > { + protected final long snap; + + public AbstractProposalGenerator(long snap) { + this.snap = snap; + } + protected abstract MP proposeMap(F from, T to); protected abstract J computeFromJoinKey(F from); @@ -133,29 +140,31 @@ public enum DebuggerStaticMappingProposals { } @Override - public ModuleMapProposal proposeMap(TraceModule from, Program to) { - return new DefaultModuleMapProposal(from, to); + public ModuleMapProposal proposeMap(TraceModule from, long snap, Program to) { + return new DefaultModuleMapProposal(from, snap, to); } @Override - public ModuleMapProposal proposeBestMap(TraceModule from, + public ModuleMapProposal proposeBestMap(TraceModule from, long snap, Collection tos) { - Collection entries = indexer.filter(indexer.getBestEntries(from), tos); - DomainFile df = indexer.getBestMatch(from, null, entries); + Collection entries = + indexer.filter(indexer.getBestEntries(from, snap), tos); + DomainFile df = indexer.getBestMatch(from, snap, null, entries); if (df == null) { return null; } try (PeekOpenedDomainObject peek = new PeekOpenedDomainObject(df)) { - return proposeMap(from, (Program) peek.object); + return proposeMap(from, snap, (Program) peek.object); } } @Override public Map proposeBestMaps( - Collection froms, Collection tos) { + Collection froms, long snap, + Collection tos) { Map result = new LinkedHashMap<>(); for (TraceModule f : froms) { - ModuleMapProposal map = proposeBestMap(f, tos); + ModuleMapProposal map = proposeBestMap(f, snap, tos); if (map != null) { result.put(f, map); } @@ -164,16 +173,20 @@ public enum DebuggerStaticMappingProposals { } } - protected static class SectionMapProposalGenerator + public static class SectionMapProposalGenerator extends AbstractProposalGenerator { + public SectionMapProposalGenerator(long snap) { + super(snap); + } + @Override protected SectionMapProposal proposeMap(TraceModule from, Program to) { - return new DefaultSectionMapProposal(from, to); + return new DefaultSectionMapProposal(from, snap, to); } @Override protected String computeFromJoinKey(TraceModule from) { - return getLastLower(from.getName()); + return getLastLower(from.getName(snap)); } @Override @@ -182,14 +195,18 @@ public enum DebuggerStaticMappingProposals { } } - protected static class RegionMapProposalGenerator extends + public static class RegionMapProposalGenerator extends AbstractProposalGenerator, Program, Set, // RegionMapProposal> { + public RegionMapProposalGenerator(long snap) { + super(snap); + } + @Override protected RegionMapProposal proposeMap(Collection from, Program to) { - return new DefaultRegionMapProposal(from, to); + return new DefaultRegionMapProposal(from, snap, to); } @Override @@ -206,14 +223,11 @@ public enum DebuggerStaticMappingProposals { } } - // TODO: Should these also take advantage of the program-module index? - protected static final SectionMapProposalGenerator SECTIONS = new SectionMapProposalGenerator(); - protected static final RegionMapProposalGenerator REGIONS = new RegionMapProposalGenerator(); - public static RegionMapProposal proposeRegionMap( - Collection regions, + Collection regions, long snap, Collection programs) { - return REGIONS.proposeBestMap(Collections.unmodifiableCollection(regions), programs); + return new RegionMapProposalGenerator(snap) + .proposeBestMap(Collections.unmodifiableCollection(regions), programs); } public static Set> groupByComponents(Collection vertices, @@ -248,8 +262,9 @@ public enum DebuggerStaticMappingProposals { } catch (IllegalArgumentException e) { // Parse error Msg.error(DebuggerStaticMappingProposals.class, - "Encountered unparsable path: " + region.getName()); - key = region.getName(); // Not a great fallback, but it'll have to do + "Encountered unparsable path: " + region.getPath()); + // Path should always parse in object mode. In legacy mode, snap doesn't matter + key = region.getName(0); // Not a great fallback, but it'll have to do } return Stream.of(key.split("\\s+")) .filter(n -> n.replaceAll("[0-9A-Fa-f]+", "").length() >= 5) diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingServicePlugin.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingServicePlugin.java index e967b5eb12..758fee32b0 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingServicePlugin.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingServicePlugin.java @@ -29,7 +29,7 @@ import ghidra.app.plugin.PluginCategoryNames; import ghidra.app.plugin.core.debug.DebuggerPluginPackage; import ghidra.app.plugin.core.debug.event.TraceClosedPluginEvent; import ghidra.app.plugin.core.debug.event.TraceOpenedPluginEvent; -import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingProposals.ModuleMapProposalGenerator; +import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingProposals.*; import ghidra.app.plugin.core.debug.utils.ProgramLocationUtils; import ghidra.app.plugin.core.debug.utils.ProgramURLUtils; import ghidra.app.services.*; @@ -362,7 +362,7 @@ public class DebuggerStaticMappingServicePlugin extends Plugin try (Transaction tx = ent.getKey().openTransaction("Memorize module mapping")) { for (ModuleMapEntry entry : ent.getValue()) { ProgramModuleIndexer.addModulePaths(entry.getToProgram(), - List.of(entry.getModule().getName())); + List.of(entry.getModuleName())); } } } @@ -561,71 +561,75 @@ public class DebuggerStaticMappingServicePlugin extends Plugin } @Override - public DomainFile findBestModuleProgram(AddressSpace space, TraceModule module) { - return programModuleIndexer.getBestMatch(space, module, programManager.getCurrentProgram()); + public DomainFile findBestModuleProgram(AddressSpace space, TraceModule module, long snap) { + return programModuleIndexer.getBestMatch(space, module, snap, + programManager.getCurrentProgram()); } @Override - public ModuleMapProposal proposeModuleMap(TraceModule module, Program program) { - return moduleMapProposalGenerator.proposeMap(module, program); + public ModuleMapProposal proposeModuleMap(TraceModule module, long snap, Program program) { + return moduleMapProposalGenerator.proposeMap(module, snap, program); } @Override - public ModuleMapProposal proposeModuleMap(TraceModule module, + public ModuleMapProposal proposeModuleMap(TraceModule module, long snap, Collection programs) { - return moduleMapProposalGenerator.proposeBestMap(module, orderCurrentFirst(programs)); + return moduleMapProposalGenerator.proposeBestMap(module, snap, orderCurrentFirst(programs)); } @Override public Map proposeModuleMaps( - Collection modules, Collection programs) { - return moduleMapProposalGenerator.proposeBestMaps(modules, orderCurrentFirst(programs)); - } - - @Override - public SectionMapProposal proposeSectionMap(TraceSection section, Program program, - MemoryBlock block) { - return new DefaultSectionMapProposal(section, program, block); - } - - @Override - public SectionMapProposal proposeSectionMap(TraceModule module, Program program) { - return DebuggerStaticMappingProposals.SECTIONS.proposeMap(module, program); - } - - @Override - public SectionMapProposal proposeSectionMap(TraceModule module, + Collection modules, long snap, Collection programs) { - return DebuggerStaticMappingProposals.SECTIONS.proposeBestMap(module, + return moduleMapProposalGenerator.proposeBestMaps(modules, snap, + orderCurrentFirst(programs)); + } + + @Override + public SectionMapProposal proposeSectionMap(TraceSection section, long snap, Program program, + MemoryBlock block) { + return new DefaultSectionMapProposal(section, snap, program, block); + } + + @Override + public SectionMapProposal proposeSectionMap(TraceModule module, long snap, Program program) { + return new SectionMapProposalGenerator(snap).proposeMap(module, program); + } + + @Override + public SectionMapProposal proposeSectionMap(TraceModule module, long snap, + Collection programs) { + return new SectionMapProposalGenerator(snap).proposeBestMap(module, orderCurrentFirst(programs)); } @Override public Map proposeSectionMaps( - Collection modules, Collection programs) { - return DebuggerStaticMappingProposals.SECTIONS.proposeBestMaps(modules, + Collection modules, long snap, + Collection programs) { + return new SectionMapProposalGenerator(snap).proposeBestMaps(modules, orderCurrentFirst(programs)); } @Override - public RegionMapProposal proposeRegionMap(TraceMemoryRegion region, Program program, + public RegionMapProposal proposeRegionMap(TraceMemoryRegion region, long snap, Program program, MemoryBlock block) { - return new DefaultRegionMapProposal(region, program, block); + return new DefaultRegionMapProposal(region, snap, program, block); } @Override public RegionMapProposal proposeRegionMap(Collection regions, - Program program) { - return DebuggerStaticMappingProposals.REGIONS + long snap, Program program) { + return new RegionMapProposalGenerator(snap) .proposeMap(Collections.unmodifiableCollection(regions), program); } @Override public Map, RegionMapProposal> proposeRegionMaps( - Collection regions, + Collection regions, long snap, Collection programs) { Set> groups = DebuggerStaticMappingProposals.groupRegionsByLikelyModule(regions); - return DebuggerStaticMappingProposals.REGIONS.proposeBestMaps(groups, programs); + return new RegionMapProposalGenerator(snap).proposeBestMaps(groups, programs); } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingUtils.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingUtils.java index 3d1ba7b7dd..8cbf630e09 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingUtils.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingUtils.java @@ -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. @@ -353,10 +353,10 @@ public enum DebuggerStaticMappingUtils { if (trace == null) { return null; } - for (TraceModule module : trace.getModuleManager() - .getModulesAt(coordinates.getSnap(), pc)) { + long snap = coordinates.getSnap(); + for (TraceModule module : trace.getModuleManager().getModulesAt(snap, pc)) { // Just take the first - return computeModuleShortName(module.getName()); + return computeModuleShortName(module.getName(snap)); } return null; } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DefaultModuleMapProposal.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DefaultModuleMapProposal.java index 768849246f..0f17a1da83 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DefaultModuleMapProposal.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DefaultModuleMapProposal.java @@ -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. @@ -26,7 +26,6 @@ import ghidra.program.model.listing.Program; import ghidra.program.model.mem.MemoryBlock; import ghidra.trace.model.Lifespan; import ghidra.trace.model.memory.TraceMemoryRegion; -import ghidra.trace.model.memory.TraceObjectMemoryRegion; import ghidra.trace.model.modules.TraceModule; import ghidra.util.MathUtilities; @@ -112,12 +111,13 @@ public class DefaultModuleMapProposal * to obtain these. * * @param module the module + * @param snap the first snap * @param program the matched program * @param moduleRange a range from the module base the size of the program's image */ - protected DefaultModuleMapEntry(TraceModule module, Program program, + protected DefaultModuleMapEntry(TraceModule module, long snap, Program program, AddressRange moduleRange) { - super(module.getTrace(), module, program, program); + super(module.getTrace(), module, snap, program, program); this.moduleRange = moduleRange; this.imageRange = quantize(computeImageRange(program)); } @@ -128,8 +128,8 @@ public class DefaultModuleMapProposal } @Override - public Lifespan getFromLifespan() { - return getModule().getLifespan(); + public String getModuleName() { + return getModule().getName(snap); } private long getLength() { @@ -179,15 +179,17 @@ public class DefaultModuleMapProposal } protected final TraceModule module; + protected final long snap; // indexed by region's offset from module base protected final NavigableMap matchers = new TreeMap<>(); protected AddressRange imageRange; protected AddressRange moduleRange; - protected DefaultModuleMapProposal(TraceModule module, Program program) { + protected DefaultModuleMapProposal(TraceModule module, long snap, Program program) { super(module.getTrace(), program); this.module = module; + this.snap = snap; processProgram(); processModule(); } @@ -198,7 +200,7 @@ public class DefaultModuleMapProposal } private ModuleRegionMatcher getMatcher(long baseOffset) { - return matchers.computeIfAbsent(baseOffset, ModuleRegionMatcher::new); + return matchers.computeIfAbsent(baseOffset, b -> new ModuleRegionMatcher(snap)); } private void processProgram() { @@ -217,15 +219,12 @@ public class DefaultModuleMapProposal * Must be called after processProgram, so that image size is known */ private void processModule() { - moduleRange = quantize(module.getRange()); + moduleRange = quantize(module.getRange(snap)); Address moduleBase = moduleRange.getMinAddress(); - Lifespan lifespan = module.getLifespan(); for (TraceMemoryRegion region : module.getTrace() .getMemoryManager() - .getRegionsIntersecting(lifespan, moduleRange)) { - Address min = region instanceof TraceObjectMemoryRegion objReg - ? objReg.getMinAddress(lifespan.lmin()) - : region.getMinAddress(); + .getRegionsIntersecting(Lifespan.at(snap), moduleRange)) { + Address min = region.getMinAddress(snap); getMatcher(min.subtract(moduleBase)).region = region; } } @@ -246,7 +245,7 @@ public class DefaultModuleMapProposal @Override public Map computeMap() { - return Map.of(module, new DefaultModuleMapEntry(module, program, moduleRange)); + return Map.of(module, new DefaultModuleMapEntry(module, snap, program, moduleRange)); } @Override diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DefaultRegionMapProposal.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DefaultRegionMapProposal.java index fc11c251af..09cc6709aa 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DefaultRegionMapProposal.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DefaultRegionMapProposal.java @@ -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. @@ -23,7 +23,6 @@ import ghidra.debug.api.modules.RegionMapProposal.RegionMapEntry; import ghidra.program.model.address.*; import ghidra.program.model.listing.Program; import ghidra.program.model.mem.MemoryBlock; -import ghidra.trace.model.Lifespan; import ghidra.trace.model.Trace; import ghidra.trace.model.memory.TraceMemoryRegion; @@ -35,9 +34,9 @@ public class DefaultRegionMapProposal extends AbstractMapEntry implements RegionMapEntry { - public DefaultRegionMapEntry(TraceMemoryRegion region, + public DefaultRegionMapEntry(TraceMemoryRegion region, long snap, Program program, MemoryBlock block) { - super(region.getTrace(), region, program, block); + super(region.getTrace(), region, snap, program, block); } @Override @@ -46,13 +45,18 @@ public class DefaultRegionMapProposal } @Override - public AddressRange getFromRange() { - return getRegion().getRange(); + public String getRegionName() { + return getRegion().getName(snap); } @Override - public Lifespan getFromLifespan() { - return getRegion().getLifespan(); + public Address getRegionMinAddress() { + return getRegion().getMinAddress(snap); + } + + @Override + public AddressRange getFromRange() { + return getRegion().getRange(snap); } @Override @@ -72,13 +76,13 @@ public class DefaultRegionMapProposal } protected class RegionMatcher extends Matcher { - public RegionMatcher(TraceMemoryRegion region, MemoryBlock block) { - super(region, block); + public RegionMatcher(TraceMemoryRegion region, long snap, MemoryBlock block) { + super(region, snap, block); } @Override protected AddressRange getFromRange() { - return fromObject == null ? null : fromObject.getRange(); + return fromObject == null ? null : fromObject.getRange(snap); } @Override @@ -99,7 +103,8 @@ public class DefaultRegionMapProposal if (fOff == tOff) { return 10; } - } catch (IllegalArgumentException e) { + } + catch (IllegalArgumentException e) { // fell-through } return 0; @@ -108,9 +113,14 @@ public class DefaultRegionMapProposal protected class RegionMatcherMap extends MatcherMap { + + public RegionMatcherMap(long snap) { + super(snap); + } + @Override protected RegionMatcher newMatcher(TraceMemoryRegion region, MemoryBlock block) { - return new RegionMatcher(region, block); + return new RegionMatcher(region, snap, block); } @Override @@ -132,28 +142,36 @@ public class DefaultRegionMapProposal } protected final List regions; + protected final long snap; + protected final Address fromBase; protected final Address toBase; - protected final RegionMatcherMap matchers = new RegionMatcherMap(); + protected final RegionMatcherMap matchers; - protected DefaultRegionMapProposal(Collection regions, + protected DefaultRegionMapProposal(Collection regions, long snap, Program program) { super(getTrace(regions), program); + this.snap = snap; this.regions = Collections.unmodifiableList(regions.stream() - .sorted(Comparator.comparing(r -> r.getMinAddress())) + .sorted(Comparator.comparing(r -> r.getMinAddress(snap))) .collect(Collectors.toList())); + this.fromBase = computeFromBase(); this.toBase = program.getImageBase(); + this.matchers = new RegionMatcherMap(snap); processRegions(); processProgram(); } - protected DefaultRegionMapProposal(TraceMemoryRegion region, Program program, + protected DefaultRegionMapProposal(TraceMemoryRegion region, long snap, Program program, MemoryBlock block) { super(region.getTrace(), program); this.regions = List.of(region); - this.fromBase = region.getMinAddress(); + this.snap = snap; + + this.fromBase = region.getMinAddress(snap); this.toBase = program.getImageBase(); + this.matchers = new RegionMatcherMap(snap); processRegions(); matchers.processToObject(block); } @@ -162,7 +180,7 @@ public class DefaultRegionMapProposal if (regions.isEmpty()) { return null; } - return regions.get(0).getMinAddress(); + return regions.get(0).getMinAddress(snap); } private void processRegions() { @@ -184,8 +202,8 @@ public class DefaultRegionMapProposal @Override public Map computeMap() { - return matchers - .computeMap(m -> new DefaultRegionMapEntry(m.fromObject, program, m.toObject)); + return matchers.computeMap( + m -> new DefaultRegionMapEntry(m.fromObject, snap, program, m.toObject)); } @Override diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DefaultSectionMapProposal.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DefaultSectionMapProposal.java index fb02aa776f..28cbe531ab 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DefaultSectionMapProposal.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DefaultSectionMapProposal.java @@ -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. @@ -20,11 +20,9 @@ import java.util.Map; import ghidra.app.services.DebuggerStaticMappingService; import ghidra.debug.api.modules.SectionMapProposal; import ghidra.debug.api.modules.SectionMapProposal.SectionMapEntry; -import ghidra.program.model.address.AddressRange; -import ghidra.program.model.address.AddressRangeImpl; +import ghidra.program.model.address.*; import ghidra.program.model.listing.Program; import ghidra.program.model.mem.MemoryBlock; -import ghidra.trace.model.Lifespan; import ghidra.trace.model.modules.TraceModule; import ghidra.trace.model.modules.TraceSection; @@ -50,8 +48,9 @@ public class DefaultSectionMapProposal * @param program the program containing the matched block * @param block the matched memory block */ - protected DefaultSectionMapEntry(TraceSection section, Program program, MemoryBlock block) { - super(section.getTrace(), section, program, block); + protected DefaultSectionMapEntry(TraceSection section, long snap, Program program, + MemoryBlock block) { + super(section.getTrace(), section, snap, program, block); } @Override @@ -59,19 +58,29 @@ public class DefaultSectionMapProposal return getFromObject().getModule(); } + @Override + public String getModuleName() { + return getModule().getName(snap); + } + @Override public TraceSection getSection() { return getFromObject(); } @Override - public Lifespan getFromLifespan() { - return getModule().getLifespan(); + public String getSectionName() { + return getSection().getName(snap); + } + + @Override + public Address getSectionStart() { + return getSection().getStart(snap); } @Override public AddressRange getFromRange() { - return getSection().getRange(); + return getSection().getRange(snap); } @Override @@ -91,13 +100,13 @@ public class DefaultSectionMapProposal } protected static class SectionMatcher extends Matcher { - public SectionMatcher(TraceSection section, MemoryBlock block) { - super(section, block); + public SectionMatcher(TraceSection section, long snap, MemoryBlock block) { + super(section, snap, block); } @Override protected AddressRange getFromRange() { - return fromObject == null ? null : fromObject.getRange(); + return fromObject == null ? null : fromObject.getRange(snap); } @Override @@ -109,14 +118,19 @@ public class DefaultSectionMapProposal protected static class SectionMatcherMap extends MatcherMap { + + public SectionMatcherMap(long snap) { + super(snap); + } + @Override protected SectionMatcher newMatcher(TraceSection section, MemoryBlock block) { - return new SectionMatcher(section, block); + return new SectionMatcher(section, snap, block); } @Override protected String getFromJoinKey(TraceSection section) { - return section.getName(); + return section.getName(snap); } @Override @@ -126,18 +140,27 @@ public class DefaultSectionMapProposal } protected final TraceModule module; - protected final SectionMatcherMap matchers = new SectionMatcherMap(); + protected final long snap; - protected DefaultSectionMapProposal(TraceModule module, Program program) { + protected final SectionMatcherMap matchers; + + protected DefaultSectionMapProposal(TraceModule module, long snap, Program program) { super(module.getTrace(), program); this.module = module; + this.snap = snap; + + this.matchers = new SectionMatcherMap(snap); processModule(); processProgram(); } - protected DefaultSectionMapProposal(TraceSection section, Program program, MemoryBlock block) { + protected DefaultSectionMapProposal(TraceSection section, long snap, Program program, + MemoryBlock block) { super(section.getTrace(), program); this.module = section.getModule(); + this.snap = snap; + + this.matchers = new SectionMatcherMap(snap); matchers.processFromObject(section); matchers.processToObject(block); } @@ -148,7 +171,7 @@ public class DefaultSectionMapProposal } private void processModule() { - for (TraceSection section : module.getSections()) { + for (TraceSection section : module.getSections(snap)) { matchers.processFromObject(section); } } @@ -166,8 +189,8 @@ public class DefaultSectionMapProposal @Override public Map computeMap() { - return matchers - .computeMap(m -> new DefaultSectionMapEntry(m.fromObject, program, m.toObject)); + return matchers.computeMap( + m -> new DefaultSectionMapEntry(m.fromObject, snap, program, m.toObject)); } @Override diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/ModuleRegionMatcher.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/ModuleRegionMatcher.java index 61161d2ee8..fc6f6f592b 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/ModuleRegionMatcher.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/ModuleRegionMatcher.java @@ -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,10 +19,12 @@ import ghidra.program.model.mem.MemoryBlock; import ghidra.trace.model.memory.TraceMemoryRegion; class ModuleRegionMatcher { + final long snap; MemoryBlock block; TraceMemoryRegion region; - public ModuleRegionMatcher(long baseOffset) { + public ModuleRegionMatcher(long snap) { + this.snap = snap; } int score() { @@ -30,7 +32,7 @@ class ModuleRegionMatcher { return 0; // Unmatched } int score = 3; // For the matching offset - if (block.getSize() == region.getLength()) { + if (block.getSize() == region.getLength(snap)) { score += 10; } return score; diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/ProgramModuleIndexer.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/ProgramModuleIndexer.java index 9ef125e0c8..412792ba7a 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/ProgramModuleIndexer.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/ProgramModuleIndexer.java @@ -28,6 +28,7 @@ import ghidra.framework.options.Options; import ghidra.framework.plugintool.PluginTool; import ghidra.program.model.address.*; import ghidra.program.model.listing.Program; +import ghidra.trace.model.Lifespan; import ghidra.trace.model.modules.TraceModule; // TODO: Consider making this a front-end plugin? @@ -351,8 +352,8 @@ public class ProgramModuleIndexer implements DomainFolderChangeListener { return projectData.getFileByID(entries.stream().max(comparator).get().dfID); } - public DomainFile getBestMatch(AddressSpace space, TraceModule module, Program currentProgram, - Collection entries) { + public DomainFile getBestMatch(AddressSpace space, TraceModule module, long snap, + Program currentProgram, Collection entries) { if (entries.isEmpty()) { return null; } @@ -361,7 +362,7 @@ public class ProgramModuleIndexer implements DomainFolderChangeListener { .getStaticMappingManager() .findAllOverlapping( new AddressRangeImpl(space.getMinAddress(), space.getMaxAddress()), - module.getLifespan()) + Lifespan.at(snap)) .stream() .map(m -> ProgramURLUtils.getDomainFileFromOpenProject(project, m.getStaticProgramURL())) @@ -379,17 +380,17 @@ public class ProgramModuleIndexer implements DomainFolderChangeListener { return selectBest(entries, libraries, folderUses, currentProgram); } - public DomainFile getBestMatch(TraceModule module, Program currentProgram, + public DomainFile getBestMatch(TraceModule module, long snap, Program currentProgram, Collection entries) { - Address base = module.getBase(); + Address base = module.getBase(snap); AddressSpace space = base == null ? module.getTrace().getBaseAddressFactory().getDefaultAddressSpace() : base.getAddressSpace(); - return getBestMatch(space, module, currentProgram, entries); + return getBestMatch(space, module, snap, currentProgram, entries); } - public List getBestEntries(TraceModule module) { - String modulePathName = module.getName().toLowerCase(); + public List getBestEntries(TraceModule module, long snap) { + String modulePathName = module.getName(snap).toLowerCase(); List entries = new ArrayList<>(index.getByName(modulePathName)); if (!entries.isEmpty()) { return entries; @@ -399,8 +400,9 @@ public class ProgramModuleIndexer implements DomainFolderChangeListener { return entries; } - public DomainFile getBestMatch(AddressSpace space, TraceModule module, Program currentProgram) { - return getBestMatch(space, module, currentProgram, getBestEntries(module)); + public DomainFile getBestMatch(AddressSpace space, TraceModule module, long snap, + Program currentProgram) { + return getBestMatch(space, module, snap, currentProgram, getBestEntries(module, snap)); } public Collection filter(Collection entries, diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/stack/StackUnwinder.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/stack/StackUnwinder.java index b5065a5f3a..486359a7e8 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/stack/StackUnwinder.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/stack/StackUnwinder.java @@ -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. @@ -181,7 +181,7 @@ public class StackUnwinder { try { TraceStack stack = trace.getStackManager().getLatestStack(thread, viewSnap); if (stack != null) { - TraceStackFrame frame = stack.getFrame(level, false); + TraceStackFrame frame = stack.getFrame(viewSnap, level, false); if (frame != null) { pcVal = frame.getProgramCounter(viewSnap); } @@ -209,8 +209,7 @@ public class StackUnwinder { return unwind(coordinates, level, pcVal, spVal, state, new SavedRegisterMap(), monitor); } - record StaticAndUnwind(Address staticPc, UnwindInfo info) { - } + record StaticAndUnwind(Address staticPc, UnwindInfo info) {} /** * Compute the unwind information for the given program counter and context diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/taint/AngrTaintState.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/taint/AngrTaintState.java index b45ba7c534..b22a1426ae 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/taint/AngrTaintState.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/taint/AngrTaintState.java @@ -39,8 +39,8 @@ import ghidra.util.Msg; import ghidra.util.NumericUtilities; /** - * Container for all the decompiler elements the users "selects" via the menu. - * This data is used to build queries. + * Container for all the decompiler elements the users "selects" via the menu. This data is used to + * build queries. */ public class AngrTaintState extends AbstractTaintState { @@ -158,7 +158,7 @@ public class AngrTaintState extends AbstractTaintState { Collection allRegions = memoryManager.getRegionsAtSnap(current.getSnap()); for (TraceMemoryRegion region : allRegions) { - AddressRange range = region.getRange(); + AddressRange range = region.getRange(current.getSnap()); Address min = range.getMinAddress(); int len = (int) range.getLength(); byte[] bytes = new byte[len]; diff --git a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyActionsPluginScreenShots.java b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyActionsPluginScreenShots.java index aaf0be6733..c9fcb061a4 100644 --- a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyActionsPluginScreenShots.java +++ b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyActionsPluginScreenShots.java @@ -98,9 +98,9 @@ public class DebuggerCopyActionsPluginScreenShots extends GhidraScreenShotGenera DBTraceModuleManager mods = tb.trace.getModuleManager(); TraceModule modEcho = mods.addLoadedModule("Modules[/bin/echo]", "/bin/echo", tb.range(0x55550000, 0x5556ffff), snap); - modEcho.addSection("Modules[/bin/echo].Sections[.text]", ".text", + modEcho.addSection(snap, "Modules[/bin/echo].Sections[.text]", ".text", tb.range(0x55550000, 0x5555ffff)); - modEcho.addSection("Modules[/bin/echo].Sections[.data]", ".data", + modEcho.addSection(snap, "Modules[/bin/echo].Sections[.data]", ".data", tb.range(0x55560000, 0x5556ffff)); } diff --git a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesPluginScreenShots.java b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesPluginScreenShots.java index ee11ce117e..ce4b48597f 100644 --- a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesPluginScreenShots.java +++ b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesPluginScreenShots.java @@ -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. @@ -78,17 +78,17 @@ public class DebuggerModulesPluginScreenShots extends GhidraScreenShotGenerator TraceModule bin = tb.trace.getModuleManager() .addLoadedModule("Modules[/bin/bash]", "/bin/bash", tb.range(0x00400000, 0x0060ffff), snap); - bin.addSection("Modules[/bin/bash].Sections[.text]", ".text", + bin.addSection(snap, "Modules[/bin/bash].Sections[.text]", ".text", tb.range(0x00400000, 0x0040ffff)); - bin.addSection("Modules[/bin/bash].Sections[.data]", ".data", + bin.addSection(snap, "Modules[/bin/bash].Sections[.data]", ".data", tb.range(0x00600000, 0x0060ffff)); TraceModule lib = tb.trace.getModuleManager() .addLoadedModule("Modules[/lib/libc.so.6]", "/lib/libc.so.6", tb.range(0x7fac0000, 0x7faeffff), snap); - lib.addSection("Modules[/lib/libc.so.6].Sections[.text]", ".text", + lib.addSection(snap, "Modules[/lib/libc.so.6].Sections[.text]", ".text", tb.range(0x7fac0000, 0x7facffff)); - lib.addSection("Modules[/lib/libc.so.6].Sections[.data]", ".data", + lib.addSection(snap, "Modules[/lib/libc.so.6].Sections[.data]", ".data", tb.range(0x7fae0000, 0x7faeffff)); traceManager.openTrace(tb.trace); @@ -111,19 +111,18 @@ public class DebuggerModulesPluginScreenShots extends GhidraScreenShotGenerator TraceModule bin = tb.trace.getModuleManager() .addLoadedModule("Modules[/bin/bash]", "/bin/bash", tb.range(0x00400000, 0x0060ffff), snap); - bin.addSection("Modules[/bin/bash].Sections[.text]", ".text", + bin.addSection(snap, "Modules[/bin/bash].Sections[.text]", ".text", tb.range(0x00400000, 0x0040ffff)); - bin.addSection("Modules[/bin/bash].Sections[.data]", ".data", + bin.addSection(snap, "Modules[/bin/bash].Sections[.data]", ".data", tb.range(0x00600000, 0x0060ffff)); TraceModule lib = tb.trace.getModuleManager() .addLoadedModule("Modules[/lib/libc.so.6]", "/lib/libc.so.6", tb.range(0x7fac0000, 0x7faeffff), snap); - lib.addSection("Modules[/lib/libc.so.6].Sections[.text]", ".text", + lib.addSection(snap, "Modules[/lib/libc.so.6].Sections[.text]", ".text", tb.range(0x7fac0000, 0x7facffff)); - lib.addSection("Modules[/lib/libc.so.6].Sections[.data]", ".data", + lib.addSection(snap, "Modules[/lib/libc.so.6].Sections[.data]", ".data", tb.range(0x7fae0000, 0x7faeffff)); - } progBash = createDefaultProgram("bash", ProgramBuilder._X64, this); diff --git a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerStaticMappingPluginScreenShots.java b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerStaticMappingPluginScreenShots.java index 169be425b5..9e51db23e3 100644 --- a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerStaticMappingPluginScreenShots.java +++ b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerStaticMappingPluginScreenShots.java @@ -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,8 @@ import ghidra.app.plugin.core.debug.service.emulation.ProgramEmulationUtils; import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingServicePlugin; import ghidra.app.plugin.core.debug.service.tracemgr.DebuggerTraceManagerServicePlugin; import ghidra.app.plugin.core.progmgr.ProgramManagerPlugin; -import ghidra.app.services.*; +import ghidra.app.services.DebuggerTraceManagerService; +import ghidra.app.services.ProgramManager; import ghidra.debug.api.modules.MapProposal; import ghidra.debug.api.modules.ModuleMapProposal; import ghidra.debug.api.modules.ModuleMapProposal.ModuleMapEntry; @@ -80,24 +81,25 @@ public class DebuggerStaticMappingPluginScreenShots extends GhidraScreenShotGene @Test public void testCaptureDebuggerStaticMappingPlugin() throws Throwable { DomainFolder root = tool.getProject().getProjectData().getRootFolder(); + final long snap; try (Transaction tx = tb.startTransaction()) { tb.trace.getObjectManager().createRootObject(ProgramEmulationUtils.EMU_SESSION_SCHEMA); - long snap = tb.trace.getTimeManager().createSnapshot("First").getKey(); + snap = tb.trace.getTimeManager().createSnapshot("First").getKey(); TraceModule bin = tb.trace.getModuleManager() .addLoadedModule("Modules[/bin/echo]", "/bin/echo", tb.range(0x00400000, 0x0060ffff), snap); - bin.addSection("Modules[/bin/echo].Sections[.text]", ".text", + bin.addSection(snap, "Modules[/bin/echo].Sections[.text]", ".text", tb.range(0x00400000, 0x0040ffff)); - bin.addSection("Modules[/bin/echo].Sections[.data]", ".data", + bin.addSection(snap, "Modules[/bin/echo].Sections[.data]", ".data", tb.range(0x00600000, 0x0060ffff)); TraceModule lib = tb.trace.getModuleManager() .addLoadedModule("Modules[/lib/libc.so.6]", "/lib/libc.so.6", tb.range(0x7fac0000, 0x7faeffff), snap); - lib.addSection("Modules[/lib/libc.so.6].Sections[.text]", ".text", + lib.addSection(snap, "Modules[/lib/libc.so.6].Sections[.text]", ".text", tb.range(0x7fac0000, 0x7facffff)); - lib.addSection("Modules[/lib/libc.so.6].Sections[.data]", ".data", + lib.addSection(snap, "Modules[/lib/libc.so.6].Sections[.data]", ".data", tb.range(0x7fae0000, 0x7faeffff)); } @@ -137,7 +139,7 @@ public class DebuggerStaticMappingPluginScreenShots extends GhidraScreenShotGene try (Transaction tx = tb.startTransaction()) { Map proposal = mappingService.proposeModuleMaps(tb.trace.getModuleManager().getAllModules(), - List.of(programManager.getAllOpenPrograms())); + snap, List.of(programManager.getAllOpenPrograms())); Collection entries = MapProposal.flatten(proposal.values()); mappingService.addModuleMappings(entries, TaskMonitor.DUMMY, false); } diff --git a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/stack/DebuggerStackPluginScreenShots.java b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/stack/DebuggerStackPluginScreenShots.java index 21e2ae0f0d..f13d5a48f1 100644 --- a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/stack/DebuggerStackPluginScreenShots.java +++ b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/stack/DebuggerStackPluginScreenShots.java @@ -64,8 +64,8 @@ import ghidra.trace.model.breakpoint.TraceBreakpointKind; import ghidra.trace.model.stack.TraceStack; import ghidra.trace.model.stack.TraceStackFrame; import ghidra.trace.model.target.schema.SchemaContext; -import ghidra.trace.model.target.schema.XmlSchemaContext; import ghidra.trace.model.target.schema.TraceObjectSchema.SchemaName; +import ghidra.trace.model.target.schema.XmlSchemaContext; import ghidra.trace.model.thread.TraceThread; import ghidra.trace.model.time.schedule.Scheduler; import ghidra.util.InvalidNameException; @@ -144,14 +144,14 @@ public class DebuggerStackPluginScreenShots extends GhidraScreenShotGenerator thread = tb.getOrAddThread("Processes[1].Threads[1]", snap); TraceStack stack = tb.trace.getStackManager().getStack(thread, snap, true); - stack.setDepth(3, true); + stack.setDepth(snap, 3, true); TraceStackFrame frame; - frame = stack.getFrame(0, false); + frame = stack.getFrame(snap, 0, false); frame.setProgramCounter(Lifespan.ALL, tb.addr(0x00404321)); - frame = stack.getFrame(1, false); + frame = stack.getFrame(snap, 1, false); frame.setProgramCounter(Lifespan.ALL, tb.addr(0x00401234)); - frame = stack.getFrame(2, false); + frame = stack.getFrame(snap, 2, false); frame.setProgramCounter(Lifespan.ALL, tb.addr(0x00401001)); } root.createFile("trace", tb.trace, TaskMonitor.DUMMY); diff --git a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/thread/DebuggerThreadsPluginScreenShots.java b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/thread/DebuggerThreadsPluginScreenShots.java index 1a0cb9e6e3..ef7c3fbd3a 100644 --- a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/thread/DebuggerThreadsPluginScreenShots.java +++ b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/thread/DebuggerThreadsPluginScreenShots.java @@ -46,7 +46,6 @@ import ghidra.trace.model.Lifespan; import ghidra.trace.model.target.TraceObject.ConflictResolution; import ghidra.trace.model.target.path.KeyPath; import ghidra.trace.model.thread.TraceObjectThread; -import ghidra.trace.model.thread.TraceThread; import ghidra.util.task.TaskMonitor; import help.screenshot.GhidraScreenShotGenerator; @@ -94,10 +93,6 @@ public class DebuggerThreadsPluginScreenShots extends GhidraScreenShotGenerator return set; } - protected boolean nullOrDead(TraceThread thread) { - return thread == null || !thread.isAlive(); - } - private void populateTrace() throws Exception { try (Transaction tx = tb.startTransaction()) { DBTraceObjectManager om = tb.trace.getObjectManager(); diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/disassemble/DebuggerDisassemblyTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/disassemble/DebuggerDisassemblyTest.java index 484b5ea728..11630e17f8 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/disassemble/DebuggerDisassemblyTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/disassemble/DebuggerDisassemblyTest.java @@ -65,8 +65,8 @@ import ghidra.trace.model.target.TraceObject.ConflictResolution; import ghidra.trace.model.target.iface.TraceObjectEnvironment; import ghidra.trace.model.target.path.KeyPath; import ghidra.trace.model.target.schema.SchemaContext; -import ghidra.trace.model.target.schema.XmlSchemaContext; import ghidra.trace.model.target.schema.TraceObjectSchema.SchemaName; +import ghidra.trace.model.target.schema.XmlSchemaContext; import ghidra.trace.model.thread.TraceObjectThread; import ghidra.trace.model.thread.TraceThread; import ghidra.trace.model.time.schedule.TraceSchedule; @@ -228,7 +228,7 @@ public class DebuggerDisassemblyTest extends AbstractGhidraHeadedDebuggerTest { try (Transaction tx = tb.startTransaction()) { DBTraceStackManager manager = tb.trace.getStackManager(); TraceStack stack = manager.getStack(thread, snap, true); - TraceStackFrame frame = stack.getFrame(0, true); + TraceStackFrame frame = stack.getFrame(snap, 0, true); frame.setProgramCounter(Lifespan.nowOn(snap), tb.addr(offset)); } } diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsProviderTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsProviderTest.java index be51446186..cf227494b7 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsProviderTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsProviderTest.java @@ -47,12 +47,13 @@ import ghidra.trace.model.Trace; import ghidra.trace.model.memory.TraceMemoryRegion; import ghidra.trace.model.memory.TraceObjectMemoryRegion; import ghidra.trace.model.modules.TraceStaticMapping; -import ghidra.trace.model.target.*; +import ghidra.trace.model.target.TraceObject; import ghidra.trace.model.target.TraceObject.ConflictResolution; +import ghidra.trace.model.target.TraceObjectManager; import ghidra.trace.model.target.path.KeyPath; import ghidra.trace.model.target.schema.SchemaContext; -import ghidra.trace.model.target.schema.XmlSchemaContext; import ghidra.trace.model.target.schema.TraceObjectSchema.SchemaName; +import ghidra.trace.model.target.schema.XmlSchemaContext; import ghidra.util.table.GhidraTable; @Category(NightlyCategory.class) @@ -503,7 +504,7 @@ public class DebuggerRegionsProviderTest extends AbstractGhidraHeadedDebuggerTes waitForSwing(); TraceMemoryRegion region = Unique.assertOne(tb.trace.getMemoryManager().getAllRegions()); - assertEquals(tb.range(0, 0xfff), region.getRange()); + assertEquals(tb.range(0, 0xfff), region.getRange(0)); } @Test diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesProviderTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesProviderTest.java index 6ead51911c..e19188f5c1 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesProviderTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesProviderTest.java @@ -60,7 +60,8 @@ import ghidra.trace.model.modules.TraceStaticMapping; import ghidra.trace.model.target.TraceObject; import ghidra.trace.model.target.TraceObject.ConflictResolution; import ghidra.trace.model.target.TraceObjectManager; -import ghidra.trace.model.target.path.*; +import ghidra.trace.model.target.path.PathFilter; +import ghidra.trace.model.target.path.PathPattern; import ghidra.trace.model.target.schema.SchemaContext; import ghidra.trace.model.target.schema.TraceObjectSchema.SchemaName; import ghidra.trace.model.target.schema.XmlSchemaContext; @@ -364,7 +365,7 @@ public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerTes MemoryBlock block = addBlock(); try (Transaction tx = program.openTransaction("Change name")) { - program.setName(modExe.getName()); + program.setName(modExe.getName(0)); } waitForDomainObject(program); waitForPass(() -> assertSectionTableSize(4)); @@ -524,7 +525,7 @@ public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerTes try (Transaction tx = program.openTransaction("Change name")) { program.setImageBase(addr(program, 0x00400000), true); - program.setName(modExe.getName()); + program.setName(modExe.getName(0)); addBlock(); // So the program has a size } @@ -591,7 +592,7 @@ public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerTes MemoryBlock block = addBlock(); try (Transaction tx = program.openTransaction("Change name")) { - program.setName(modExe.getName()); + program.setName(modExe.getName(0)); } waitForDomainObject(program); waitForTasks(); @@ -680,7 +681,7 @@ public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerTes waitForTasks(); try (Transaction tx = tb.startTransaction()) { - modExe.setName("/bin/echo"); // File has to exist + modExe.setName(0, "/bin/echo"); // File has to exist } waitForPass(() -> assertModuleTableSize(2)); diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/emulation/DebuggerEmulationServiceTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/emulation/DebuggerEmulationServiceTest.java index dd45893063..abb10174b0 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/emulation/DebuggerEmulationServiceTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/emulation/DebuggerEmulationServiceTest.java @@ -493,7 +493,7 @@ public class DebuggerEmulationServiceTest extends AbstractGhidraHeadedDebuggerTe .addBreakpoint("Breakpoints[1]", Lifespan.nowOn(0), addrI1, Set.of(thread), Set.of(TraceBreakpointKind.SW_EXECUTE), true, "test"); // Force "partial instruction" - tb.setEmuSleigh(""" + tb.setEmuSleigh(0, """ r1 = 0xbeef; emu_swi(); emu_exec_decoded(); @@ -567,7 +567,7 @@ public class DebuggerEmulationServiceTest extends AbstractGhidraHeadedDebuggerTe .addBreakpoint("Breakpoints[1]", Lifespan.nowOn(0), addrI1, Set.of(thread), Set.of(TraceBreakpointKind.SW_EXECUTE), true, "test"); // Force "partial instruction" - tb.setEmuSleigh(""" + tb.setEmuSleigh(0, """ r1 = 0xbeef; emu_swi(); emu_exec_decoded(); @@ -633,7 +633,7 @@ public class DebuggerEmulationServiceTest extends AbstractGhidraHeadedDebuggerTe .addBreakpoint("Breakpoints[1]", Lifespan.nowOn(0), addrI1, Set.of(thread), Set.of(TraceBreakpointKind.SW_EXECUTE), true, "test"); // Force "partial instruction" - tb.setEmuSleigh(""" + tb.setEmuSleigh(0, """ r1 = 0xbeef; pcodeop_one(r1); emu_exec_decoded(); @@ -707,7 +707,7 @@ public class DebuggerEmulationServiceTest extends AbstractGhidraHeadedDebuggerTe TraceBreakpoint tb = trace.getBreakpointManager() .addBreakpoint("Breakpoints[0]", Lifespan.nowOn(0), addrI2, Set.of(thread), Set.of(TraceBreakpointKind.SW_EXECUTE), true, "test"); - tb.setEmuSleigh(""" + tb.setEmuSleigh(0, """ r1 = 0x5678; emu_swi(); emu_exec_decoded(); @@ -852,7 +852,7 @@ public class DebuggerEmulationServiceTest extends AbstractGhidraHeadedDebuggerTe TraceBreakpoint tb = trace.getBreakpointManager() .addBreakpoint("Breakpoints[0]", Lifespan.nowOn(0), addrI2, Set.of(thread), Set.of(TraceBreakpointKind.SW_EXECUTE), true, "test"); - tb.setEmuSleigh(""" + tb.setEmuSleigh(0, """ r1 = 0x5678; emu_exec_decoded(); """); @@ -970,7 +970,7 @@ public class DebuggerEmulationServiceTest extends AbstractGhidraHeadedDebuggerTe TraceThread newTraceThread = ProgramEmulationUtils.doLaunchEmulationThread(tb.trace, newSnap, program, tb.addr(0x00400000), addr(program, 0x00400000)); - newTraceThread.setName("MyThread"); + newTraceThread.setName(newSnap, "MyThread"); @SuppressWarnings("unused") PcodeThread newEmuThread = emulator.newThread(newTraceThread.getPath()); diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingServiceTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingServiceTest.java index baddac95ac..1d077bca86 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingServiceTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingServiceTest.java @@ -43,8 +43,8 @@ import ghidra.trace.model.modules.*; import ghidra.trace.model.target.TraceObject.ConflictResolution; import ghidra.trace.model.target.path.KeyPath; import ghidra.trace.model.target.schema.SchemaContext; -import ghidra.trace.model.target.schema.XmlSchemaContext; import ghidra.trace.model.target.schema.TraceObjectSchema.SchemaName; +import ghidra.trace.model.target.schema.XmlSchemaContext; import ghidra.util.Msg; // Not technically a GUI test, but must be carried out in the context of a plugin tool @@ -690,6 +690,6 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg TraceModule modBash = objModBash.queryInterface(TraceObjectModule.class); assertEquals(Map.of(), - mappingService.proposeModuleMaps(List.of(modBash), List.of(program))); + mappingService.proposeModuleMaps(List.of(modBash), 0, List.of(program))); } } diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/stack/StackUnwinderTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/stack/StackUnwinderTest.java index a89b904ef1..0e87881278 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/stack/StackUnwinderTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/stack/StackUnwinderTest.java @@ -980,7 +980,7 @@ public class StackUnwinderTest extends AbstractGhidraHeadedDebuggerTest { bptUnwind = tb.trace.getBreakpointManager() .addBreakpoint("Breakpoints[0]", Lifespan.nowOn(0), entry, Set.of(), Set.of(TraceBreakpointKind.SW_EXECUTE), true, "unwind stack"); - bptUnwind.setEmuSleigh(""" + bptUnwind.setEmuSleigh(0, """ if (%s >= 0x%x) goto ; emu_swi(); diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/DBTraceTimeViewport.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/DBTraceTimeViewport.java index 03270ab921..d38c1f784e 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/DBTraceTimeViewport.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/DBTraceTimeViewport.java @@ -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. @@ -299,6 +299,20 @@ public class DBTraceTimeViewport implements TraceTimeViewport { } } + @Override + public List getReversedSpans() { + ArrayList result = new ArrayList<>(); + try (LockHold hold = trace.lockRead()) { + synchronized (ordered) { + ListIterator it = ordered.listIterator(ordered.size()); + while (it.hasPrevious()) { + result.add(it.previous()); + } + } + } + return result; + } + public List getOrderedSpans(long snap) { try (LockHold hold = trace.lockRead()) { setSnap(snap); diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/breakpoint/DBTraceBreakpoint.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/breakpoint/DBTraceBreakpoint.java index b516dd0831..5144ced862 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/breakpoint/DBTraceBreakpoint.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/breakpoint/DBTraceBreakpoint.java @@ -188,7 +188,7 @@ public class DBTraceBreakpoint } @Override - public void setName(String name) { + public void setName(long snap, String name) { try (LockHold hold = LockHold.lock(space.lock.writeLock())) { this.name = name; update(NAME_COLUMN); @@ -199,14 +199,14 @@ public class DBTraceBreakpoint } @Override - public String getName() { + public String getName(long snap) { try (LockHold hold = LockHold.lock(space.lock.readLock())) { return name; } } @Override - public Set getThreads() { + public Set getThreads(long snap) { try (LockHold hold = LockHold.lock(space.lock.readLock())) { if (threadKeys.length == 0) { return Set.of(); @@ -227,28 +227,28 @@ public class DBTraceBreakpoint } @Override - public AddressRange getRange() { + public AddressRange getRange(long snap) { try (LockHold hold = LockHold.lock(space.lock.readLock())) { return range; } } @Override - public Address getMinAddress() { + public Address getMinAddress(long snap) { try (LockHold hold = LockHold.lock(space.lock.readLock())) { return range.getMinAddress(); } } @Override - public Address getMaxAddress() { + public Address getMaxAddress(long snap) { try (LockHold hold = LockHold.lock(space.lock.readLock())) { return range.getMaxAddress(); } } @Override - public long getLength() { + public long getLength(long snap) { try (LockHold hold = LockHold.lock(space.lock.readLock())) { return range.getLength(); } @@ -272,79 +272,12 @@ public class DBTraceBreakpoint } } - @Override - public boolean isAlive(long snap) { - try (LockHold hold = LockHold.lock(space.lock.readLock())) { - return lifespan.contains(snap); - } - } - - @Override - public long getPlacedSnap() { - try (LockHold hold = LockHold.lock(space.lock.readLock())) { - return lifespan.lmin(); - } - } - - @Override - public void setClearedSnap(long clearedSnap) throws DuplicateNameException { - setLifespan(Lifespan.span(getPlacedSnap(), clearedSnap)); - } - - @Override - public long getClearedSnap() { - try (LockHold hold = LockHold.lock(space.lock.readLock())) { - return lifespan.lmax(); - } - } - protected DBTraceBreakpoint doCopy() { DBTraceBreakpoint breakpoint = space.breakpointMapSpace.put(this, null); breakpoint.set(path, name, threadKeys, flagsByte, comment); return breakpoint; } - @Override - public DBTraceBreakpoint splitAndSet(long snap, boolean en, - Collection kinds) { - DBTraceBreakpoint that; - Lifespan oldLifespan = null; - Lifespan newLifespan = null; - try (LockHold hold = LockHold.lock(space.lock.writeLock())) { - if (!lifespan.contains(snap)) { - throw new IllegalArgumentException("snap = " + snap); - } - if (flagsByte == computeFlagsByte(en, kinds)) { - return this; - } - if (snap == getPlacedSnap()) { - this.doSetFlags(en, kinds); - that = this; - } - else { - that = doCopy(); - that.doSetLifespan(Lifespan.span(snap, getClearedSnap())); - that.doSetFlags(en, kinds); - oldLifespan = lifespan; - newLifespan = Lifespan.span(getPlacedSnap(), snap - 1); - this.doSetLifespan(newLifespan); - } - } - if (that == this) { - space.trace.setChanged( - new TraceChangeRecord<>(TraceEvents.BREAKPOINT_CHANGED, space, this)); - } - else { - // Yes, issue ADDED, before LIFESPAN_CHANGED, as noted in docs - space.trace - .setChanged(new TraceChangeRecord<>(TraceEvents.BREAKPOINT_ADDED, space, that)); - space.trace.setChanged( - new TraceChangeRecord<>(TraceEvents.BREAKPOINT_LIFESPAN_CHANGED, space, this, - Objects.requireNonNull(oldLifespan), Objects.requireNonNull(newLifespan))); - } - return that; - } - protected static byte computeFlagsByte(boolean enabled, Collection kinds) { byte flags = 0; for (TraceBreakpointKind k : kinds) { @@ -405,7 +338,7 @@ public class DBTraceBreakpoint } @Override - public void setEnabled(boolean enabled) { + public void setEnabled(long snap, boolean enabled) { try (LockHold hold = LockHold.lock(space.lock.writeLock())) { doSetEnabled(enabled); } @@ -422,7 +355,7 @@ public class DBTraceBreakpoint } @Override - public void setEmuEnabled(boolean enabled) { + public void setEmuEnabled(long snap, boolean enabled) { try (LockHold hold = LockHold.lock(space.lock.writeLock())) { doSetEmuEnabled(enabled); } @@ -439,7 +372,7 @@ public class DBTraceBreakpoint } @Override - public void setKinds(Collection kinds) { + public void setKinds(long snap, Collection kinds) { try (LockHold hold = LockHold.lock(space.lock.writeLock())) { doSetKinds(kinds); } @@ -448,14 +381,14 @@ public class DBTraceBreakpoint } @Override - public Set getKinds() { + public Set getKinds(long snap) { try (LockHold hold = LockHold.lock(space.lock.readLock())) { return kindsView; } } @Override - public void setComment(String comment) { + public void setComment(long snap, String comment) { try (LockHold hold = LockHold.lock(space.lock.writeLock())) { this.comment = comment; update(COMMENT_COLUMN); @@ -465,14 +398,14 @@ public class DBTraceBreakpoint } @Override - public String getComment() { + public String getComment(long snap) { try (LockHold hold = LockHold.lock(space.lock.readLock())) { return comment; } } @Override - public void setEmuSleigh(String emuSleigh) { + public void setEmuSleigh(long snap, String emuSleigh) { try (LockHold hold = LockHold.lock(space.lock.writeLock())) { if (emuSleigh == null || SleighUtils.UNCONDITIONAL_BREAK.equals(emuSleigh)) { this.emuSleigh = null; @@ -487,7 +420,7 @@ public class DBTraceBreakpoint } @Override - public String getEmuSleigh() { + public String getEmuSleigh(long snap) { try (LockHold hold = LockHold.lock(space.lock.readLock())) { return emuSleigh == null || emuSleigh.isBlank() ? SleighUtils.UNCONDITIONAL_BREAK : emuSleigh; @@ -499,10 +432,29 @@ public class DBTraceBreakpoint space.deleteBreakpoint(this); } + @Override + public void remove(long snap) { + try (LockHold hold = LockHold.lock(space.lock.writeLock())) { + if (snap <= lifespan.lmin()) { + space.deleteBreakpoint(this); + } + else if (snap <= lifespan.lmax()) { + doSetLifespan(lifespan.withMax(snap - 1)); + } + } + } + @Override public boolean isValid(long snap) { try (LockHold hold = LockHold.lock(space.lock.readLock())) { return lifespan.contains(snap); } } + + @Override + public boolean isAlive(Lifespan span) { + try (LockHold hold = LockHold.lock(space.lock.readLock())) { + return lifespan.intersects(span); + } + } } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/breakpoint/DBTraceBreakpointManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/breakpoint/DBTraceBreakpointManager.java index a1ad11989e..e8e80ec1c8 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/breakpoint/DBTraceBreakpointManager.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/breakpoint/DBTraceBreakpointManager.java @@ -83,7 +83,7 @@ public class DBTraceBreakpointManager if (pc == ignore) { continue; } - if (!lifespan.intersects(pc.getLifespan())) { + if (!pc.isAlive(lifespan)) { continue; } throw new DuplicateNameException("A breakpoint having path '" + path + @@ -129,7 +129,7 @@ public class DBTraceBreakpointManager } try (LockHold hold = LockHold.lock(lock.readLock())) { return getBreakpointsByPath(path).stream() - .filter(b -> b.getLifespan().contains(snap)) + .filter(b -> b.isValid(snap)) .findAny() .orElse(null); } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/breakpoint/DBTraceObjectBreakpointLocation.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/breakpoint/DBTraceObjectBreakpointLocation.java index 02ac3d9cf8..9b55e7a037 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/breakpoint/DBTraceObjectBreakpointLocation.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/breakpoint/DBTraceObjectBreakpointLocation.java @@ -33,7 +33,6 @@ import ghidra.trace.model.target.schema.TraceObjectSchema; import ghidra.trace.model.thread.*; import ghidra.trace.util.*; import ghidra.util.LockHold; -import ghidra.util.exception.DuplicateNameException; public class DBTraceObjectBreakpointLocation implements TraceObjectBreakpointLocation, DBTraceObjectInterface { @@ -85,10 +84,6 @@ public class DBTraceObjectBreakpointLocation private final DBTraceObject object; private final BreakpointChangeTranslator translator; - // Keep copies here for when the object gets invalidated - private AddressRange range; - private Lifespan lifespan; - public DBTraceObjectBreakpointLocation(DBTraceObject object) { this.object = object; @@ -111,17 +106,17 @@ public class DBTraceObjectBreakpointLocation } @Override - public void setName(String name) { + public void setName(long snap, String name) { try (LockHold hold = object.getTrace().lockWrite()) { - setName(getLifespan(), name); + setName(Lifespan.nowOn(snap), name); } } @Override - public String getName() { + public String getName(long snap) { try (LockHold hold = object.getTrace().lockRead()) { - String display = TraceObjectInterfaceUtils.getValue(object, getPlacedSnap(), - KEY_DISPLAY, String.class, null); + String display = + TraceObjectInterfaceUtils.getValue(object, snap, KEY_DISPLAY, String.class, null); if (display != null) { return display; } @@ -143,118 +138,44 @@ public class DBTraceObjectBreakpointLocation public void setRange(Lifespan lifespan, AddressRange range) { try (LockHold hold = object.getTrace().lockWrite()) { object.setValue(lifespan, KEY_RANGE, range); - this.range = range; } } @Override - public AddressRange getRange() { + public AddressRange getRange(long snap) { try (LockHold hold = object.getTrace().lockRead()) { - if (object.getLife().isEmpty()) { - return range; - } - return range = TraceObjectInterfaceUtils.getValue(object, getPlacedSnap(), - KEY_RANGE, AddressRange.class, range); + return TraceObjectInterfaceUtils.getValue(object, snap, KEY_RANGE, AddressRange.class, + null); } } @Override - public Address getMinAddress() { - AddressRange range = getRange(); + public Address getMinAddress(long snap) { + AddressRange range = getRange(snap); return range == null ? null : range.getMinAddress(); } @Override - public Address getMaxAddress() { - AddressRange range = getRange(); + public Address getMaxAddress(long snap) { + AddressRange range = getRange(snap); return range == null ? null : range.getMaxAddress(); } @Override - public long getLength() { - AddressRange range = getRange(); + public long getLength(long snap) { + AddressRange range = getRange(snap); return range == null ? 0 : range.getLength(); } - @Override - public void setLifespan(Lifespan lifespan) throws DuplicateNameException { - try (LockHold hold = object.getTrace().lockWrite()) { - TraceObjectInterfaceUtils.setLifespan(TraceObjectBreakpointLocation.class, object, - lifespan); - this.lifespan = lifespan; - } - } - - @Override - public Lifespan getLifespan() { - try (LockHold hold = object.getTrace().lockRead()) { - Lifespan computed = computeSpan(); - if (computed != null) { - lifespan = computed; - } - return lifespan; - } - } - - @Override - public boolean isAlive(long snap) { - try (LockHold hold = object.getTrace().lockRead()) { - return object.isAlive(snap); - } - } - - @Override - public Lifespan computeSpan() { - Lifespan span = TraceObjectBreakpointLocation.super.computeSpan(); - if (span != null) { - return span; - } - return getSpecification().computeSpan(); - } - - @Override - public long getPlacedSnap() { - return getLifespan().lmin(); - } - - @Override - public void setClearedSnap(long clearedSnap) throws DuplicateNameException { - try (LockHold hold = object.getTrace().lockWrite()) { - setLifespan(Lifespan.span(getPlacedSnap(), clearedSnap)); - } - } - - @Override - public long getClearedSnap() { - return getLifespan().lmax(); - } - - @Override - public TraceBreakpoint splitAndSet(long snap, boolean enabled, - Collection kinds) { - try (LockHold hold = object.getTrace().lockWrite()) { - if (enabled != isEnabled(snap)) { - object.setValue(Lifespan.span(snap, getClearedSnap()), - TraceObjectTogglable.KEY_ENABLED, enabled); - } - Set asSet = - kinds instanceof Set yes ? yes : Set.copyOf(kinds); - if (!Objects.equals(asSet, getKinds())) { - this.setKinds(Lifespan.span(snap, getClearedSnap()), asSet); - } - return this; - } - } - @Override public void setEnabled(Lifespan lifespan, boolean enabled) { object.setValue(lifespan, TraceObjectTogglable.KEY_ENABLED, enabled); } @Override - public void setEnabled(boolean enabled) { + public void setEnabled(long snap, boolean enabled) { try (LockHold hold = object.getTrace().lockWrite()) { - setEnabled(getLifespan(), enabled); + setEnabled(Lifespan.nowOn(snap), enabled); } } @@ -282,37 +203,37 @@ public class DBTraceObjectBreakpointLocation } @Override - public void setKinds(Collection kinds) { + public void setKinds(long snap, Collection kinds) { try (LockHold hold = object.getTrace().lockWrite()) { - setKinds(getLifespan(), kinds); + setKinds(Lifespan.nowOn(snap), kinds); } } @Override - public Set getKinds() { + public Set getKinds(long snap) { try (LockHold hold = object.getTrace().lockRead()) { - return getSpecification().getKinds(); + return getSpecification().getKinds(snap); } } @Override - public Set getThreads() { + public Set getThreads(long snap) { // TODO: Delete this? It's sort of deprecated out the gate anyway.... DBTraceObjectManager manager = object.getManager(); TraceObjectSchema schema = manager.getRootSchema(); try (LockHold hold = object.getTrace().lockRead()) { Set threads = - object.queryAncestorsInterface(getLifespan(), TraceObjectThread.class) + object.queryAncestorsInterface(Lifespan.at(snap), TraceObjectThread.class) .collect(Collectors.toSet()); if (!threads.isEmpty()) { return threads; } PathFilter procFilter = schema.searchFor(TraceObjectProcess.class, false); - return object.getAncestorsRoot(getLifespan(), procFilter) + Lifespan lifespan = Lifespan.at(snap); + return object.getAncestorsRoot(lifespan, procFilter) .flatMap(proc -> proc.getSource(object) - .querySuccessorsInterface(getLifespan(), - TraceObjectThread.class, true)) + .querySuccessorsInterface(lifespan, TraceObjectThread.class, true)) .collect(Collectors.toSet()); } } @@ -323,17 +244,17 @@ public class DBTraceObjectBreakpointLocation } @Override - public void setComment(String comment) { + public void setComment(long snap, String comment) { try (LockHold hold = object.getTrace().lockWrite()) { - setComment(getLifespan(), comment); + setComment(Lifespan.nowOn(snap), comment); } } @Override - public String getComment() { + public String getComment(long snap) { try (LockHold hold = object.getTrace().lockRead()) { - String comment = TraceObjectInterfaceUtils.getValue(object, getPlacedSnap(), - KEY_COMMENT, String.class, ""); + String comment = + TraceObjectInterfaceUtils.getValue(object, snap, KEY_COMMENT, String.class, ""); if (!comment.isBlank()) { return comment; } @@ -341,7 +262,7 @@ public class DBTraceObjectBreakpointLocation if (spec == null) { return ""; } - return spec.getExpression(); + return spec.getExpression(snap); } } @@ -351,17 +272,17 @@ public class DBTraceObjectBreakpointLocation } @Override - public void setEmuEnabled(boolean emuEnabled) { + public void setEmuEnabled(long snap, boolean emuEnabled) { try (LockHold hold = object.getTrace().lockWrite()) { - setEmuEnabled(getLifespan(), emuEnabled); + setEmuEnabled(Lifespan.nowOn(snap), emuEnabled); } } @Override public boolean isEmuEnabled(long snap) { try (LockHold hold = object.getTrace().lockRead()) { - return TraceObjectInterfaceUtils.getValue(object, getPlacedSnap(), KEY_EMU_ENABLED, - Boolean.class, true); + return TraceObjectInterfaceUtils.getValue(object, snap, KEY_EMU_ENABLED, Boolean.class, + true); } } @@ -376,30 +297,42 @@ public class DBTraceObjectBreakpointLocation } @Override - public void setEmuSleigh(String sleigh) { + public void setEmuSleigh(long snap, String sleigh) { try (LockHold hold = object.getTrace().lockWrite()) { - setEmuSleigh(getLifespan(), sleigh); + setEmuSleigh(Lifespan.nowOn(snap), sleigh); } } @Override - public String getEmuSleigh() { + public String getEmuSleigh(long snap) { try (LockHold hold = object.getTrace().lockRead()) { - return TraceObjectInterfaceUtils.getValue(object, getPlacedSnap(), KEY_EMU_SLEIGH, - String.class, SleighUtils.UNCONDITIONAL_BREAK); + return TraceObjectInterfaceUtils.getValue(object, snap, KEY_EMU_SLEIGH, String.class, + SleighUtils.UNCONDITIONAL_BREAK); } } @Override public void delete() { try (LockHold hold = object.getTrace().lockWrite()) { - object.removeTree(computeSpan()); + object.removeTree(Lifespan.ALL); + } + } + + @Override + public void remove(long snap) { + try (LockHold hold = object.getTrace().lockWrite()) { + object.removeTree(Lifespan.nowOn(snap)); } } @Override public boolean isValid(long snap) { - return object.getCanonicalParent(snap) != null; + return object.isAlive(snap); + } + + @Override + public boolean isAlive(Lifespan span) { + return object.isAlive(span); } @Override @@ -420,8 +353,8 @@ public class DBTraceObjectBreakpointLocation } } - public TraceAddressSpace getTraceAddressSpace() { - return spaceForValue(computeMinSnap(), KEY_RANGE); + public TraceAddressSpace getTraceAddressSpace(long snap) { + return spaceForValue(snap, KEY_RANGE); } @Override diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/breakpoint/DBTraceObjectBreakpointSpec.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/breakpoint/DBTraceObjectBreakpointSpec.java index 37395aaa40..b07424a0c9 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/breakpoint/DBTraceObjectBreakpointSpec.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/breakpoint/DBTraceObjectBreakpointSpec.java @@ -32,12 +32,10 @@ import ghidra.trace.model.target.iface.TraceObjectInterface; import ghidra.trace.model.target.iface.TraceObjectTogglable; import ghidra.trace.model.target.info.TraceObjectInterfaceUtils; import ghidra.trace.model.target.schema.TraceObjectSchema; -import ghidra.trace.model.thread.TraceObjectThread; import ghidra.trace.model.thread.TraceThread; import ghidra.trace.util.*; import ghidra.util.LockHold; import ghidra.util.Msg; -import ghidra.util.exception.DuplicateNameException; public class DBTraceObjectBreakpointSpec implements TraceObjectBreakpointSpec, DBTraceObjectInterface { @@ -69,82 +67,42 @@ public class DBTraceObjectBreakpointSpec } @Override - public void setName(String name) { + public void setName(long snap, String name) { try (LockHold hold = object.getTrace().lockWrite()) { - object.setValue(getLifespan(), TraceObjectInterface.KEY_DISPLAY, name); + object.setValue(Lifespan.nowOn(snap), TraceObjectInterface.KEY_DISPLAY, name); } } @Override - public String getName() { - return TraceObjectInterfaceUtils.getValue(object, getPlacedSnap(), - TraceObjectInterface.KEY_DISPLAY, String.class, ""); + public String getName(long snap) { + return TraceObjectInterfaceUtils.getValue(object, snap, TraceObjectInterface.KEY_DISPLAY, + String.class, ""); } @Override - public AddressRange getRange() { + public AddressRange getRange(long snap) { throw new UnsupportedOperationException("Ask a location instead"); } @Override - public Address getMinAddress() { + public Address getMinAddress(long snap) { throw new UnsupportedOperationException("Ask a location instead"); } @Override - public Address getMaxAddress() { + public Address getMaxAddress(long snap) { throw new UnsupportedOperationException("Ask a location instead"); } @Override - public long getLength() { + public long getLength(long snap) { throw new UnsupportedOperationException("Ask a location instead"); } @Override - public Lifespan getLifespan() { - return computeSpan(); - } - - @Override - public boolean isAlive(long snap) { - try (LockHold hold = object.getTrace().lockRead()) { - return object.isAlive(snap); - } - } - - @Override - public long getPlacedSnap() { - return computeMinSnap(); - } - - @Override - public void setClearedSnap(long clearedSnap) throws DuplicateNameException { + public void setEnabled(long snap, boolean enabled) { try (LockHold hold = object.getTrace().lockWrite()) { - setLifespan(Lifespan.span(getPlacedSnap(), clearedSnap)); - } - } - - @Override - public long getClearedSnap() { - return computeMaxSnap(); - } - - @Override - public void setLifespan(Lifespan lifespan) throws DuplicateNameException { - TraceObjectInterfaceUtils.setLifespan(TraceObjectThread.class, object, lifespan); - } - - @Override - public TraceBreakpoint splitAndSet(long snap, boolean enabled, - Collection kinds) { - throw new UnsupportedOperationException("Only used by default trace recorder"); - } - - @Override - public void setEnabled(boolean enabled) { - try (LockHold hold = object.getTrace().lockWrite()) { - object.setValue(getLifespan(), TraceObjectTogglable.KEY_ENABLED, + object.setValue(Lifespan.nowOn(snap), TraceObjectTogglable.KEY_ENABLED, enabled ? true : null); } } @@ -167,15 +125,15 @@ public class DBTraceObjectBreakpointSpec } @Override - public void setKinds(Collection kinds) { + public void setKinds(long snap, Collection kinds) { try (LockHold hold = object.getTrace().lockWrite()) { - setKinds(getLifespan(), kinds); + setKinds(Lifespan.nowOn(snap), kinds); } } @Override - public Set getKinds() { - String kindsStr = TraceObjectInterfaceUtils.getValue(object, getPlacedSnap(), + public Set getKinds(long snap) { + String kindsStr = TraceObjectInterfaceUtils.getValue(object, snap, TraceObjectBreakpointSpec.KEY_KINDS, String.class, null); if (kindsStr == null) { return kinds; @@ -190,28 +148,28 @@ public class DBTraceObjectBreakpointSpec } @Override - public String getExpression() { - return TraceObjectInterfaceUtils.getValue(object, getPlacedSnap(), + public String getExpression(long snap) { + return TraceObjectInterfaceUtils.getValue(object, snap, TraceObjectBreakpointSpec.KEY_EXPRESSION, String.class, null); } @Override - public Set getThreads() { + public Set getThreads(long snap) { throw new UnsupportedOperationException("Ask a location instead"); } @Override - public void setComment(String comment) { + public void setComment(long snap, String comment) { throw new UnsupportedOperationException("Set on a location instead"); } @Override - public String getComment() { + public String getComment(long snap) { throw new UnsupportedOperationException("Ask a location instead"); } @Override - public void setEmuEnabled(boolean enabled) { + public void setEmuEnabled(long snap, boolean enabled) { throw new UnsupportedOperationException("Set on a location instead"); } @@ -221,25 +179,37 @@ public class DBTraceObjectBreakpointSpec } @Override - public void setEmuSleigh(String sleigh) { + public void setEmuSleigh(long snap, String sleigh) { throw new UnsupportedOperationException("Set on a location instead"); } @Override - public String getEmuSleigh() { + public String getEmuSleigh(long snap) { throw new UnsupportedOperationException("Ask a location instead"); } @Override public void delete() { try (LockHold hold = object.getTrace().lockWrite()) { - object.removeTree(computeSpan()); + object.removeTree(Lifespan.ALL); + } + } + + @Override + public void remove(long snap) { + try (LockHold hold = object.getTrace().lockWrite()) { + object.removeTree(Lifespan.nowOn(snap)); } } @Override public boolean isValid(long snap) { - return object.getCanonicalParent(snap) != null; + return object.isAlive(snap); + } + + @Override + public boolean isAlive(Lifespan span) { + return object.isAlive(span); } @Override @@ -247,16 +217,18 @@ public class DBTraceObjectBreakpointSpec return object; } - @Override - public Collection getLocations() { + protected Collection getLocations(Lifespan span) { try (LockHold hold = object.getTrace().lockRead()) { - return object - .querySuccessorsInterface(getLifespan(), TraceObjectBreakpointLocation.class, - true) + return object.querySuccessorsInterface(span, TraceObjectBreakpointLocation.class, true) .collect(Collectors.toSet()); } } + @Override + public Collection getLocations(long snap) { + return getLocations(Lifespan.at(snap)); + } + @Override public TraceChangeRecord translateEvent(TraceChangeRecord rec) { if (rec.getEventType() == TraceEvents.VALUE_CREATED) { @@ -271,9 +243,9 @@ public class DBTraceObjectBreakpointSpec if (object.getCanonicalParent(affected.getMaxSnap()) == null) { return null; // Incomplete object } - for (TraceObjectBreakpointLocation loc : getLocations()) { + for (TraceObjectBreakpointLocation loc : getLocations(affected.getLifespan())) { DBTraceObjectBreakpointLocation dbLoc = (DBTraceObjectBreakpointLocation) loc; - TraceAddressSpace space = dbLoc.getTraceAddressSpace(); + TraceAddressSpace space = dbLoc.getTraceAddressSpace(affected.getMinSnap()); TraceChangeRecord evt = new TraceChangeRecord<>(TraceEvents.BREAKPOINT_CHANGED, space, loc, null, null); object.getTrace().setChanged(evt); diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceCodeUnitAdapter.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceCodeUnitAdapter.java index d96aae386c..0a7da73bed 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceCodeUnitAdapter.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceCodeUnitAdapter.java @@ -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.trace.database.listing; -import static ghidra.lifecycle.Unfinished.*; +import static ghidra.lifecycle.Unfinished.TODO; import java.nio.ByteBuffer; import java.util.*; @@ -83,7 +83,7 @@ public interface DBTraceCodeUnitAdapter extends TraceCodeUnit, MemBufferMixin { if (region == null) { return address.toString(showBlockName, pad); } - return region.getName() + ":" + address.toString(false, pad); + return region.getName(getStartSnap()) + ":" + address.toString(false, pad); } } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/memory/DBTraceMemoryRegion.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/memory/DBTraceMemoryRegion.java index 4927dc49c9..c6e54fe29b 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/memory/DBTraceMemoryRegion.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/memory/DBTraceMemoryRegion.java @@ -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. @@ -145,7 +145,7 @@ public class DBTraceMemoryRegion } @Override - public void setName(String name) { + public void setName(long snap, String name) { try (LockHold hold = LockHold.lock(space.lock.writeLock())) { this.name = name; update(NAME_COLUMN); @@ -155,54 +155,14 @@ public class DBTraceMemoryRegion } @Override - public String getName() { + public String getName(long snap) { try (LockHold hold = LockHold.lock(space.lock.readLock())) { return name; } } @Override - public void setLifespan(Lifespan newLifespan) - throws TraceOverlappedRegionException, DuplicateNameException { - try (LockHold hold = LockHold.lock(space.lock.writeLock())) { - checkOverlapConflicts(newLifespan, range); - checkPathConflicts(newLifespan, path); - Lifespan oldLifespan = getLifespan(); - doSetLifespan(newLifespan); - space.trace.updateViewsChangeRegionBlockLifespan(this, oldLifespan, newLifespan); - space.trace.setChanged(new TraceChangeRecord<>(TraceEvents.REGION_LIFESPAN_CHANGED, - space, this, oldLifespan, newLifespan)); - } - } - - @Override - public void setCreationSnap(long creationSnap) - throws DuplicateNameException, TraceOverlappedRegionException { - setLifespan(Lifespan.span(creationSnap, getDestructionSnap())); - } - - @Override - public long getCreationSnap() { - try (LockHold hold = LockHold.lock(space.lock.readLock())) { - return lifespan.lmin(); - } - } - - @Override - public void setDestructionSnap(long destructionSnap) - throws DuplicateNameException, TraceOverlappedRegionException { - setLifespan(Lifespan.span(getCreationSnap(), destructionSnap)); - } - - @Override - public long getDestructionSnap() { - try (LockHold hold = LockHold.lock(space.lock.readLock())) { - return lifespan.lmax(); - } - } - - @Override - public void setRange(AddressRange newRange) throws TraceOverlappedRegionException { + public void setRange(long snap, AddressRange newRange) throws TraceOverlappedRegionException { AddressRange oldRange; try (LockHold hold = LockHold.lock(space.lock.writeLock())) { if (range.equals(newRange)) { @@ -217,51 +177,58 @@ public class DBTraceMemoryRegion } @Override - public void setMinAddress(Address min) throws TraceOverlappedRegionException { - try (LockHold hold = LockHold.lock(space.lock.writeLock())) { - setRange(DBTraceUtils.toRange(min, range.getMaxAddress())); + public AddressRange getRange(long snap) { + try (LockHold hold = LockHold.lock(space.lock.readLock())) { + return range; } } @Override - public Address getMinAddress() { + public void setMinAddress(long snap, Address min) throws TraceOverlappedRegionException { + try (LockHold hold = LockHold.lock(space.lock.writeLock())) { + setRange(snap, DBTraceUtils.toRange(min, range.getMaxAddress())); + } + } + + @Override + public Address getMinAddress(long snap) { try (LockHold hold = LockHold.lock(space.lock.readLock())) { return range.getMinAddress(); } } @Override - public void setMaxAddress(Address max) throws TraceOverlappedRegionException { + public void setMaxAddress(long snap, Address max) throws TraceOverlappedRegionException { try (LockHold hold = LockHold.lock(space.lock.writeLock())) { - setRange(DBTraceUtils.toRange(range.getMinAddress(), max)); + setRange(snap, DBTraceUtils.toRange(range.getMinAddress(), max)); } } @Override - public Address getMaxAddress() { + public Address getMaxAddress(long snap) { try (LockHold hold = LockHold.lock(space.lock.readLock())) { return range.getMaxAddress(); } } @Override - public void setLength(long length) + public void setLength(long snap, long length) throws AddressOverflowException, TraceOverlappedRegionException { try (LockHold hold = LockHold.lock(space.lock.writeLock())) { Address minAddress = range.getMinAddress(); - setRange(DBTraceUtils.toRange(minAddress, minAddress.addNoWrap(length - 1))); + setRange(snap, DBTraceUtils.toRange(minAddress, minAddress.addNoWrap(length - 1))); } } @Override - public long getLength() { + public long getLength(long snap) { try (LockHold hold = LockHold.lock(space.lock.readLock())) { return range.getLength(); } } @Override - public void setFlags(Collection flags) { + public void setFlags(long snap, Collection flags) { try (LockHold hold = LockHold.lock(space.lock.writeLock())) { this.flagsByte = TraceMemoryFlag.toBits(flags); this.flags.clear(); @@ -274,7 +241,7 @@ public class DBTraceMemoryRegion @SuppressWarnings("hiding") @Override - public void addFlags(Collection flags) { + public void addFlags(long snap, Collection flags) { try (LockHold hold = LockHold.lock(space.lock.writeLock())) { this.flagsByte |= TraceMemoryFlag.toBits(flags); this.flags.addAll(flags); @@ -286,7 +253,7 @@ public class DBTraceMemoryRegion @SuppressWarnings("hiding") @Override - public void clearFlags(Collection flags) { + public void clearFlags(long snap, Collection flags) { try (LockHold hold = LockHold.lock(space.lock.writeLock())) { this.flagsByte &= ~TraceMemoryFlag.toBits(flags); this.flags.removeAll(flags); @@ -297,7 +264,7 @@ public class DBTraceMemoryRegion } @Override - public Set getFlags() { + public Set getFlags(long snap) { try (LockHold hold = LockHold.lock(space.lock.readLock())) { return Set.copyOf(flags); } @@ -308,6 +275,18 @@ public class DBTraceMemoryRegion space.deleteRegion(this); } + @Override + public void remove(long snap) { + try (LockHold hold = LockHold.lock(space.lock.writeLock())) { + if (snap <= lifespan.lmin()) { + space.deleteRegion(this); + } + else if (snap <= lifespan.lmax()) { + doSetLifespan(lifespan.withMax(snap - 1)); + } + } + } + @Override public boolean isValid(long snap) { try (LockHold hold = LockHold.lock(space.lock.readLock())) { diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/memory/DBTraceObjectMemoryRegion.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/memory/DBTraceObjectMemoryRegion.java index b258a9dbdd..eb3b07bd43 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/memory/DBTraceObjectMemoryRegion.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/memory/DBTraceObjectMemoryRegion.java @@ -32,7 +32,6 @@ import ghidra.trace.model.target.info.TraceObjectInterfaceUtils; import ghidra.trace.model.target.schema.TraceObjectSchema; import ghidra.trace.util.*; import ghidra.util.LockHold; -import ghidra.util.exception.DuplicateNameException; public class DBTraceObjectMemoryRegion implements TraceObjectMemoryRegion, DBTraceObjectInterface { @@ -128,10 +127,6 @@ public class DBTraceObjectMemoryRegion implements TraceObjectMemoryRegion, DBTra private final DBTraceObject object; private final RegionChangeTranslator translator; - // Keep copies here for when the object gets invalidated - private AddressRange range; - private Lifespan lifespan; - public DBTraceObjectMemoryRegion(DBTraceObject object) { this.object = object; @@ -154,101 +149,44 @@ public class DBTraceObjectMemoryRegion implements TraceObjectMemoryRegion, DBTra } @Override - public void setName(String name) { + public void setName(long snap, String name) { try (LockHold hold = object.getTrace().lockWrite()) { - setName(computeSpan(), name); + setName(Lifespan.nowOn(snap), name); } } @Override - public String getName() { - TraceObjectValue value = - object.getValue(getCreationSnap(), TraceObjectInterface.KEY_DISPLAY); + public String getName(long snap) { + TraceObjectValue value = object.getValue(snap, TraceObjectInterface.KEY_DISPLAY); return value == null ? "" : (String) value.getValue(); } - @Override - public void setLifespan(Lifespan newLifespan) throws DuplicateNameException { - try (LockHold hold = object.getTrace().lockWrite()) { - TraceObjectInterfaceUtils.setLifespan(TraceObjectMemoryRegion.class, object, - newLifespan); - this.lifespan = newLifespan; - } - } - - @Override - public Lifespan getLifespan() { - try (LockHold hold = object.getTrace().lockRead()) { - Lifespan computed = computeSpan(); - if (computed != null) { - lifespan = computed; - } - return lifespan; - } - } - - @Override - public void setCreationSnap(long creationSnap) throws DuplicateNameException { - try (LockHold hold = object.getTrace().lockWrite()) { - setLifespan(Lifespan.span(creationSnap, getDestructionSnap())); - } - } - - @Override - public long getCreationSnap() { - return computeMinSnap(); - } - - @Override - public void setDestructionSnap(long destructionSnap) throws DuplicateNameException { - try (LockHold hold = object.getTrace().lockWrite()) { - setLifespan(Lifespan.span(getCreationSnap(), destructionSnap)); - } - } - - @Override - public long getDestructionSnap() { - return computeMaxSnap(); - } - @Override public void setRange(Lifespan lifespan, AddressRange newRange) { try (LockHold hold = object.getTrace().lockWrite()) { object.setValue(lifespan, TraceObjectMemoryRegion.KEY_RANGE, newRange); - this.range = newRange; } } @Override - public void setRange(AddressRange newRange) { + public void setRange(long snap, AddressRange newRange) { try (LockHold hold = object.getTrace().lockWrite()) { - setRange(computeSpan(), newRange); + setRange(Lifespan.nowOn(snap), newRange); } } @Override public AddressRange getRange(long snap) { try (LockHold hold = object.getTrace().lockRead()) { - // TODO: Caching without regard to snap seems bad - return range = TraceObjectInterfaceUtils.getValue(object, snap, - TraceObjectMemoryRegion.KEY_RANGE, AddressRange.class, range); + return TraceObjectInterfaceUtils.getValue(object, snap, + TraceObjectMemoryRegion.KEY_RANGE, AddressRange.class, null); } } @Override - public AddressRange getRange() { - try (LockHold hold = object.getTrace().lockRead()) { - if (object.getLife().isEmpty()) { - return range; - } - return getRange(getCreationSnap()); - } - } - - @Override - public void setMinAddress(Address min) { + public void setMinAddress(long snap, Address min) { try (LockHold hold = object.getTrace().lockWrite()) { - setRange(DBTraceUtils.toRange(min, getMaxAddress())); + setRange(Lifespan.nowOn(snap), DBTraceUtils.toRange(min, getMaxAddress(snap))); } } @@ -259,15 +197,9 @@ public class DBTraceObjectMemoryRegion implements TraceObjectMemoryRegion, DBTra } @Override - public Address getMinAddress() { - AddressRange range = getRange(); - return range == null ? null : range.getMinAddress(); - } - - @Override - public void setMaxAddress(Address max) { + public void setMaxAddress(long snap, Address max) { try (LockHold hold = object.getTrace().lockWrite()) { - setRange(DBTraceUtils.toRange(getMinAddress(), max)); + setRange(Lifespan.nowOn(snap), DBTraceUtils.toRange(getMinAddress(snap), max)); } } @@ -278,21 +210,16 @@ public class DBTraceObjectMemoryRegion implements TraceObjectMemoryRegion, DBTra } @Override - public Address getMaxAddress() { - AddressRange range = getRange(); - return range == null ? null : range.getMaxAddress(); - } - - @Override - public void setLength(long length) throws AddressOverflowException { + public void setLength(long snap, long length) throws AddressOverflowException { try (LockHold hold = object.getTrace().lockWrite()) { - setRange(new AddressRangeImpl(getMinAddress(), length)); + setRange(Lifespan.nowOn(snap), new AddressRangeImpl(getMinAddress(snap), length)); } } @Override - public long getLength() { - return getRange().getLength(); + public long getLength(long snap) { + AddressRange range = getRange(snap); + return range == null ? 0 : range.getLength(); } protected static String keyForFlag(TraceMemoryFlag flag) { @@ -333,23 +260,23 @@ public class DBTraceObjectMemoryRegion implements TraceObjectMemoryRegion, DBTra } @Override - public void setFlags(Collection flags) { + public void setFlags(long snap, Collection flags) { try (LockHold hold = object.getTrace().lockWrite()) { - setFlags(getLifespan(), flags); + setFlags(Lifespan.nowOn(snap), flags); } } @Override - public void addFlags(Collection flags) { + public void addFlags(long snap, Collection flags) { try (LockHold hold = object.getTrace().lockWrite()) { - addFlags(getLifespan(), flags); + addFlags(Lifespan.nowOn(snap), flags); } } @Override - public void clearFlags(Collection flags) { + public void clearFlags(long snap, Collection flags) { try (LockHold hold = object.getTrace().lockWrite()) { - clearFlags(getLifespan(), flags); + clearFlags(Lifespan.nowOn(snap), flags); } } @@ -366,22 +293,22 @@ public class DBTraceObjectMemoryRegion implements TraceObjectMemoryRegion, DBTra } @Override - public Set getFlags() { - try (LockHold hold = object.getTrace().lockRead()) { - return getFlags(getCreationSnap()); + public void delete() { + try (LockHold hold = object.getTrace().lockWrite()) { + object.removeTree(Lifespan.ALL); } } @Override - public void delete() { + public void remove(long snap) { try (LockHold hold = object.getTrace().lockWrite()) { - object.removeTree(computeSpan()); + object.removeTree(Lifespan.nowOn(snap)); } } @Override public boolean isValid(long snap) { - return object.getCanonicalParent(snap) != null; + return object.isAlive(snap); } @Override diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/memory/DBTraceObjectRegister.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/memory/DBTraceObjectRegister.java index f16d05dcef..9690888de4 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/memory/DBTraceObjectRegister.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/memory/DBTraceObjectRegister.java @@ -56,14 +56,14 @@ public class DBTraceObjectRegister implements TraceObjectRegister, DBTraceObject } @Override - public int getBitLength() { - return TraceObjectInterfaceUtils.getValue(object, computeMinSnap(), - TraceObjectRegister.KEY_BITLENGTH, Integer.class, 0); + public int getBitLength(long snap) { + return TraceObjectInterfaceUtils.getValue(object, snap, TraceObjectRegister.KEY_BITLENGTH, + Integer.class, 0); } @Override public void setValue(Lifespan lifespan, byte[] value) { - int length = getByteLength(); + int length = getByteLength(lifespan.lmin()); if (length != 0 && value.length != length) { throw new IllegalArgumentException("Length must match the register"); } @@ -77,14 +77,14 @@ public class DBTraceObjectRegister implements TraceObjectRegister, DBTraceObject return null; } Object val = ov.getValue(); - if (val instanceof byte[]) { + if (val instanceof byte[] arr) { // TODO: Should I correct mismatched size? - return (byte[]) val; + return arr; } - if (val instanceof String) { + if (val instanceof String str) { // Always base 16. Model API says byte array for register value is big endian. - BigInteger bigVal = new BigInteger((String) val, 16); - return Utils.bigIntegerToBytes(bigVal, getByteLength(), true); + BigInteger bigVal = new BigInteger(str, 16); + return Utils.bigIntegerToBytes(bigVal, getByteLength(snap), true); } throw new ClassCastException("Cannot convert " + val + " to byte array for register value"); } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceModule.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceModule.java index 2665eef9a9..7c554a2175 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceModule.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceModule.java @@ -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,8 @@ */ package ghidra.trace.database.module; -import java.util.*; +import java.util.Collection; +import java.util.Objects; import db.DBRecord; import ghidra.program.model.address.*; @@ -87,8 +88,8 @@ public class DBTraceModule extends AbstractDBTraceAddressSnapRangePropertyMapDat } @Override - public DBTraceSection addSection(String sectionPath, String sectionName, AddressRange range) - throws DuplicateNameException { + public DBTraceSection addSection(long snap, String sectionPath, String sectionName, + AddressRange range) throws DuplicateNameException { try (LockHold hold = LockHold.lock(space.manager.writeLock())) { return space.manager.doAddSection(this, sectionPath, sectionName, range); } @@ -102,7 +103,7 @@ public class DBTraceModule extends AbstractDBTraceAddressSnapRangePropertyMapDat } @Override - public void setName(String name) { + public void setName(long snap, String name) { try (LockHold hold = LockHold.lock(space.manager.writeLock())) { if (Objects.equals(this.name, name)) { return; @@ -114,14 +115,14 @@ public class DBTraceModule extends AbstractDBTraceAddressSnapRangePropertyMapDat } @Override - public String getName() { + public String getName(long snap) { try (LockHold hold = LockHold.lock(space.manager.readLock())) { return name; } } @Override - public void setRange(AddressRange range) { + public void setRange(long snap, AddressRange range) { try (LockHold hold = LockHold.lock(space.manager.writeLock())) { if (this.range.equals(range)) { return; @@ -132,106 +133,67 @@ public class DBTraceModule extends AbstractDBTraceAddressSnapRangePropertyMapDat } @Override - public void setBase(Address base) { - try (LockHold hold = LockHold.lock(space.manager.writeLock())) { - setRange(DBTraceUtils.toRange(base, range.getMaxAddress())); + public AddressRange getRange(long snap) { + try (LockHold hold = LockHold.lock(space.lock.readLock())) { + return range; } } @Override - public Address getBase() { + public void setBase(long snap, Address base) { + try (LockHold hold = LockHold.lock(space.manager.writeLock())) { + setRange(snap, DBTraceUtils.toRange(base, range.getMaxAddress())); + } + } + + @Override + public Address getBase(long snap) { try (LockHold hold = LockHold.lock(space.manager.readLock())) { return range.getMinAddress(); } } @Override - public void setMaxAddress(Address max) { + public void setMaxAddress(long snap, Address max) { try (LockHold hold = LockHold.lock(space.manager.writeLock())) { - setRange(DBTraceUtils.toRange(range.getMinAddress(), max)); + setRange(snap, DBTraceUtils.toRange(range.getMinAddress(), max)); } } @Override - public Address getMaxAddress() { + public Address getMaxAddress(long snap) { try (LockHold hold = LockHold.lock(space.lock.readLock())) { return range.getMaxAddress(); } } @Override - public void setLength(long length) throws AddressOverflowException { + public void setLength(long snap, long length) throws AddressOverflowException { try (LockHold hold = LockHold.lock(space.lock.writeLock())) { Address base = range.getMinAddress(); - setRange(DBTraceUtils.toRange(base, base.addNoWrap(length - 1))); + setRange(snap, DBTraceUtils.toRange(base, base.addNoWrap(length - 1))); } } @Override - public long getLength() { + public long getLength(long snap) { try (LockHold hold = LockHold.lock(space.lock.readLock())) { return range.getLength(); } } @Override - public void setLifespan(Lifespan newLifespan) throws DuplicateNameException { - Lifespan oldLifespan; - try (LockHold hold = LockHold.lock(space.manager.writeLock())) { - space.manager.checkModulePathConflicts(this, path, newLifespan); - ArrayList sections = new ArrayList<>(getSections()); - for (DBTraceSection traceSection : sections) { - space.manager.checkSectionPathConflicts(traceSection, traceSection.getPath(), - newLifespan); - } - oldLifespan = this.lifespan; - doSetLifespan(newLifespan); - for (DBTraceSection traceSection : sections) { - traceSection.doSetLifespan(newLifespan); - } - } - space.trace.setChanged(new TraceChangeRecord<>(TraceEvents.MODULE_LIFESPAN_CHANGED, - null, this, oldLifespan, newLifespan)); + public Collection getSections(long snap) { + return getAllSections(); } @Override - public Lifespan getLifespan() { - try (LockHold hold = LockHold.lock(space.manager.readLock())) { - return lifespan; - } - } - - @Override - public void setLoadedSnap(long loadedSnap) throws DuplicateNameException { - setLifespan(Lifespan.span(loadedSnap, getUnloadedSnap())); - } - - @Override - public long getLoadedSnap() { - try (LockHold hold = LockHold.lock(space.manager.readLock())) { - return lifespan.lmin(); - } - } - - @Override - public void setUnloadedSnap(long unloadedSnap) throws DuplicateNameException { - setLifespan(Lifespan.span(getLoadedSnap(), unloadedSnap)); - } - - @Override - public long getUnloadedSnap() { - try (LockHold hold = LockHold.lock(space.manager.readLock())) { - return lifespan.lmax(); - } - } - - @Override - public Collection getSections() { + public Collection getAllSections() { return space.manager.doGetSectionsByModuleId(getKey()); } @Override - public TraceSection getSectionByName(String sectionName) { + public TraceSection getSectionByName(long snap, String sectionName) { return space.manager.doGetSectionByName(getKey(), sectionName); } @@ -239,4 +201,30 @@ public class DBTraceModule extends AbstractDBTraceAddressSnapRangePropertyMapDat public void delete() { space.manager.doDeleteModule(this); } + + @Override + public void remove(long snap) { + try (LockHold hold = LockHold.lock(space.lock.writeLock())) { + if (snap <= lifespan.lmin()) { + space.manager.doDeleteModule(this); + } + else if (snap <= lifespan.lmax()) { + doSetLifespan(lifespan.withMax(snap - 1)); + } + } + } + + @Override + public boolean isValid(long snap) { + try (LockHold hold = LockHold.lock(space.lock.readLock())) { + return lifespan.contains(snap); + } + } + + @Override + public boolean isAlive(Lifespan span) { + try (LockHold hold = LockHold.lock(space.lock.readLock())) { + return lifespan.intersects(span); + } + } } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceModuleManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceModuleManager.java index 4e23e801f8..ca56e2fc1f 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceModuleManager.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceModuleManager.java @@ -65,7 +65,7 @@ public class DBTraceModuleManager extends AbstractDBTraceSpaceBasedManager m.getLifespan().contains(snap)) + .filter(m -> m.isValid(snap)) .findAny() .orElse(null); } @@ -272,7 +272,7 @@ public class DBTraceModuleManager extends AbstractDBTraceSpaceBasedManager s.getModule().getLifespan().contains(snap)) + .filter(s -> s.getModule().isValid(snap)) .findAny() .orElse(null); } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceModuleSpace.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceModuleSpace.java index bee09e679e..c2140ca255 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceModuleSpace.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceModuleSpace.java @@ -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. @@ -164,7 +164,8 @@ public class DBTraceModuleSpace implements TraceModuleSpace, DBTraceSpaceBased { public DBTraceSection doGetSectionByName(long moduleKey, String sectionName) { for (DBTraceSection section : sectionsByModuleKey.get(moduleKey)) { - if (!Objects.equals(section.getName(), sectionName)) { + // Legacy manager does not consider snap in name + if (!Objects.equals(section.getName(0), sectionName)) { continue; } return section; diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceObjectModule.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceObjectModule.java index 0c433728af..acade328d6 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceObjectModule.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceObjectModule.java @@ -82,10 +82,6 @@ public class DBTraceObjectModule implements TraceObjectModule, DBTraceObjectInte private final DBTraceObject object; private final ModuleChangeTranslator translator; - // Keep copies here for when the object gets invalidated - private AddressRange range; - private Lifespan lifespan; - public DBTraceObjectModule(DBTraceObject object) { this.object = object; @@ -98,8 +94,8 @@ public class DBTraceObjectModule implements TraceObjectModule, DBTraceObjectInte } @Override - public TraceSection addSection(String sectionPath, String sectionName, AddressRange range) - throws DuplicateNameException { + public TraceSection addSection(long snap, String sectionPath, String sectionName, + AddressRange range) throws DuplicateNameException { try (LockHold hold = object.getTrace().lockWrite()) { DBTraceObjectManager manager = object.getManager(); KeyPath sectionKeyList = KeyPath.parse(sectionPath); @@ -107,7 +103,7 @@ public class DBTraceObjectModule implements TraceObjectModule, DBTraceObjectInte throw new IllegalArgumentException( "Section path must be a successor of this module's path"); } - return manager.addSection(sectionPath, sectionName, getLifespan(), range); + return manager.addSection(sectionPath, sectionName, Lifespan.nowOn(snap), range); } } @@ -122,142 +118,102 @@ public class DBTraceObjectModule implements TraceObjectModule, DBTraceObjectInte } @Override - public void setName(String name) { + public void setName(long snap, String name) { try (LockHold hold = object.getTrace().lockWrite()) { - setName(computeSpan(), name); + setName(Lifespan.nowOn(snap), name); } } @Override - public String getName() { - return TraceObjectInterfaceUtils.getValue(object, getLoadedSnap(), - TraceObjectModule.KEY_MODULE_NAME, String.class, ""); + public String getName(long snap) { + return TraceObjectInterfaceUtils.getValue(object, snap, TraceObjectModule.KEY_MODULE_NAME, + String.class, ""); } @Override public void setRange(Lifespan lifespan, AddressRange range) { try (LockHold hold = object.getTrace().lockWrite()) { object.setValue(lifespan, TraceObjectModule.KEY_RANGE, range); - this.range = range; } } @Override - public void setRange(AddressRange range) { + public void setRange(long snap, AddressRange range) { try (LockHold hold = object.getTrace().lockWrite()) { - setRange(computeSpan(), range); + setRange(Lifespan.nowOn(snap), range); } } @Override - public AddressRange getRange() { + public AddressRange getRange(long snap) { try (LockHold hold = object.getTrace().lockRead()) { - if (object.getLife().isEmpty()) { - return range; - } - return range = TraceObjectInterfaceUtils.getValue(object, getLoadedSnap(), - TraceObjectModule.KEY_RANGE, AddressRange.class, range); + return TraceObjectInterfaceUtils.getValue(object, snap, TraceObjectModule.KEY_RANGE, + AddressRange.class, null); } } @Override - public void setBase(Address base) { + public void setBase(long snap, Address base) { try (LockHold hold = object.getTrace().lockWrite()) { - setRange(DBTraceUtils.toRange(base, getMaxAddress())); + setRange(snap, DBTraceUtils.toRange(base, getMaxAddress(snap))); } } @Override - public Address getBase() { - AddressRange range = getRange(); + public Address getBase(long snap) { + AddressRange range = getRange(snap); return range == null ? null : range.getMinAddress(); } @Override - public void setMaxAddress(Address max) { + public void setMaxAddress(long snap, Address max) { try (LockHold hold = object.getTrace().lockWrite()) { - setRange(DBTraceUtils.toRange(getBase(), max)); + setRange(snap, DBTraceUtils.toRange(getBase(snap), max)); } } @Override - public Address getMaxAddress() { - AddressRange range = getRange(); + public Address getMaxAddress(long snap) { + AddressRange range = getRange(snap); return range == null ? null : range.getMaxAddress(); } @Override - public void setLength(long length) throws AddressOverflowException { + public void setLength(long snap, long length) throws AddressOverflowException { try (LockHold hold = object.getTrace().lockWrite()) { - setRange(new AddressRangeImpl(getBase(), length)); + setRange(snap, new AddressRangeImpl(getBase(snap), length)); } } @Override - public long getLength() { - return getRange().getLength(); + public long getLength(long snap) { + AddressRange range = getRange(snap); + return range == null ? 0 : range.getLength(); } @Override - public void setLifespan(Lifespan lifespan) throws DuplicateNameException { - try (LockHold hold = object.getTrace().lockWrite()) { - TraceObjectInterfaceUtils.setLifespan(TraceObjectModule.class, object, lifespan); - this.lifespan = lifespan; - for (TraceObjectSection section : getSections()) { - TraceObjectInterfaceUtils.setLifespan(TraceObjectSection.class, section.getObject(), - lifespan); - } - } - } - - @Override - public Lifespan getLifespan() { + public Collection getSections(long snap) { try (LockHold hold = object.getTrace().lockRead()) { - Lifespan computed = computeSpan(); - if (computed != null) { - lifespan = computed; - } - return lifespan; - } - } - - @Override - public void setLoadedSnap(long loadedSnap) throws DuplicateNameException { - try (LockHold hold = object.getTrace().lockWrite()) { - setLifespan(Lifespan.span(loadedSnap, getUnloadedSnap())); - } - } - - @Override - public long getLoadedSnap() { - return computeMinSnap(); - } - - @Override - public void setUnloadedSnap(long unloadedSnap) throws DuplicateNameException { - try (LockHold hold = object.getTrace().lockWrite()) { - setLifespan(Lifespan.span(getLoadedSnap(), unloadedSnap)); - } - } - - @Override - public long getUnloadedSnap() { - return computeMaxSnap(); - } - - @Override - public Collection getSections() { - try (LockHold hold = object.getTrace().lockRead()) { - return object.querySuccessorsInterface(getLifespan(), TraceObjectSection.class, true) + return object + .querySuccessorsInterface(Lifespan.at(snap), TraceObjectSection.class, true) .collect(Collectors.toSet()); } } @Override - public TraceObjectSection getSectionByName(String sectionName) { + public Collection getAllSections() { + try (LockHold hold = object.getTrace().lockRead()) { + return object + .querySuccessorsInterface(Lifespan.ALL, TraceObjectSection.class, true) + .collect(Collectors.toSet()); + } + } + + @Override + public TraceObjectSection getSectionByName(long snap, String sectionName) { PathFilter filter = object.getSchema().searchFor(TraceObjectSection.class, true); PathFilter applied = filter.applyKeys(Align.LEFT, List.of(sectionName)); - return object.getSuccessors(getLifespan(), applied) + return object.getSuccessors(Lifespan.at(snap), applied) .map(p -> p.getDestination(object).queryInterface(TraceObjectSection.class)) .findAny() .orElse(null); @@ -266,10 +222,27 @@ public class DBTraceObjectModule implements TraceObjectModule, DBTraceObjectInte @Override public void delete() { try (LockHold hold = object.getTrace().lockWrite()) { - object.removeTree(computeSpan()); + object.removeTree(Lifespan.ALL); } } + @Override + public void remove(long snap) { + try (LockHold hold = object.getTrace().lockWrite()) { + object.removeTree(Lifespan.nowOn(snap)); + } + } + + @Override + public boolean isValid(long snap) { + return object.isAlive(snap); + } + + @Override + public boolean isAlive(Lifespan span) { + return object.isAlive(span); + } + @Override public TraceObject getObject() { return object; diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceObjectSection.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceObjectSection.java index 45bf72a944..1a16034331 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceObjectSection.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceObjectSection.java @@ -79,9 +79,6 @@ public class DBTraceObjectSection implements TraceObjectSection, DBTraceObjectIn private final DBTraceObject object; private final SectionTranslator translator; - // Keep copies here for when the object gets invalidated - private AddressRange range; - public DBTraceObjectSection(DBTraceObject object) { this.object = object; @@ -113,55 +110,54 @@ public class DBTraceObjectSection implements TraceObjectSection, DBTraceObjectIn } @Override - public void setName(String name) { + public void setName(long snap, String name) { try (LockHold hold = object.getTrace().lockWrite()) { - setName(computeSpan(), name); + setName(Lifespan.nowOn(snap), name); } } @Override - public String getName() { + public String getName(long snap) { String key = object.getCanonicalPath().key(); String index = KeyPath.parseIfIndex(key); - return TraceObjectInterfaceUtils.getValue(object, computeMinSnap(), - TraceObjectInterface.KEY_DISPLAY, String.class, index); + return TraceObjectInterfaceUtils.getValue(object, snap, TraceObjectInterface.KEY_DISPLAY, + String.class, index); } @Override public void setRange(Lifespan lifespan, AddressRange range) { try (LockHold hold = object.getTrace().lockWrite()) { object.setValue(lifespan, TraceObjectModule.KEY_RANGE, range); - this.range = range; } } @Override - public AddressRange getRange() { + public AddressRange getRange(long snap) { try (LockHold hold = object.getTrace().lockRead()) { - if (object.getLife().isEmpty()) { - return range; - } - return range = TraceObjectInterfaceUtils.getValue(object, computeMinSnap(), - TraceObjectModule.KEY_RANGE, AddressRange.class, range); + return TraceObjectInterfaceUtils.getValue(object, snap, TraceObjectModule.KEY_RANGE, + AddressRange.class, null); } } - @Override - public Lifespan computeSpan() { - Lifespan span = DBTraceObjectInterface.super.computeSpan(); - if (span != null) { - return span; - } - return getModule().computeSpan(); - } - @Override public void delete() { try (LockHold hold = object.getTrace().lockWrite()) { - object.removeTree(computeSpan()); + object.removeTree(Lifespan.ALL); } } + @Override + public void remove(long snap) { + try (LockHold hold = object.getTrace().lockWrite()) { + object.removeTree(Lifespan.nowOn(snap)); + } + } + + @Override + public boolean isValid(long snap) { + return object.isAlive(snap); + } + @Override public TraceObject getObject() { return object; diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceSection.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceSection.java index d9b7461c6b..6cab28118a 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceSection.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceSection.java @@ -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,6 +19,7 @@ import java.io.IOException; import java.util.Objects; import db.DBRecord; +import ghidra.program.model.address.AddressRange; import ghidra.program.model.address.AddressSpace; import ghidra.trace.database.DBTraceUtils; import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree; @@ -129,7 +130,7 @@ public class DBTraceSection extends AbstractDBTraceAddressSnapRangePropertyMapDa } @Override - public void setName(String name) throws DuplicateNameException { + public void setName(long snap, String name) throws DuplicateNameException { try (LockHold hold = LockHold.lock(space.lock.writeLock())) { if (Objects.equals(this.name, name)) { return; @@ -146,15 +147,41 @@ public class DBTraceSection extends AbstractDBTraceAddressSnapRangePropertyMapDa } @Override - public String getName() { + public String getName(long snap) { try (LockHold hold = LockHold.lock(space.lock.readLock())) { return name; } } + @Override + public AddressRange getRange(long snap) { + try (LockHold hold = LockHold.lock(space.lock.readLock())) { + return range; + } + } + @Override public void delete() { space.sectionMapSpace.deleteData(this); space.trace.setChanged(new TraceChangeRecord<>(TraceEvents.SECTION_DELETED, null, this)); } + + @Override + public void remove(long snap) { + try (LockHold hold = LockHold.lock(space.lock.writeLock())) { + if (snap <= lifespan.lmin()) { + delete(); + } + else if (snap <= lifespan.lmax()) { + doSetLifespan(lifespan.withMax(snap - 1)); + } + } + } + + @Override + public boolean isValid(long snap) { + try (LockHold hold = LockHold.lock(space.lock.readLock())) { + return lifespan.contains(snap); + } + } } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewListing.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewListing.java index 8ffa102571..5953832dda 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewListing.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewListing.java @@ -38,6 +38,7 @@ import ghidra.trace.database.DBTrace; import ghidra.trace.database.guest.InternalTracePlatform; import ghidra.trace.database.listing.UndefinedDBTraceData; import ghidra.trace.database.memory.DBTraceMemorySpace; +import ghidra.trace.database.program.DBTraceProgramViewMemory.RegionEntry; import ghidra.trace.database.thread.DBTraceThread; import ghidra.trace.model.*; import ghidra.trace.model.listing.*; @@ -783,13 +784,12 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV @Override public ProgramFragment getFragment(String treeName, Address addr) { - TraceMemoryRegion region = program.memory.getTopRegion( - s -> program.trace.getMemoryManager().getRegionContaining(s, addr)); - if (region == null) { + RegionEntry entry = program.memory.getRegionsByAddress().get(addr); + if (entry == null || !entry.range.contains(addr)) { return null; } - return fragmentsByRegion.computeIfAbsent(region, - r -> new DBTraceProgramViewFragment(this, r)); + return fragmentsByRegion.computeIfAbsent(entry.region, + r -> new DBTraceProgramViewFragment(this, r, entry.snap)); } @Override @@ -802,13 +802,12 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV @Override public ProgramFragment getFragment(String treeName, String name) { - TraceMemoryRegion region = program.memory.getTopRegion( - s -> program.trace.getMemoryManager().getLiveRegionByPath(s, name)); - if (region == null) { + RegionEntry entry = program.memory.getRegionsByName().get(name); + if (entry == null) { return null; } - return fragmentsByRegion.computeIfAbsent(region, - r -> new DBTraceProgramViewFragment(this, r)); + return fragmentsByRegion.computeIfAbsent(entry.region, + r -> new DBTraceProgramViewFragment(this, r, entry.snap)); } @Override diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewMemory.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewMemory.java index 0a1b27360b..762fc1e884 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewMemory.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewMemory.java @@ -19,7 +19,6 @@ import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; import java.util.*; -import java.util.function.Consumer; import ghidra.framework.store.LockException; import ghidra.program.database.mem.*; @@ -28,7 +27,6 @@ import ghidra.program.model.mem.*; import ghidra.trace.database.memory.DBTraceMemoryManager; import ghidra.trace.database.memory.DBTraceMemorySpace; import ghidra.trace.model.Trace; -import ghidra.trace.model.memory.TraceMemoryRegion; import ghidra.trace.model.program.TraceProgramView; import ghidra.trace.model.program.TraceProgramViewMemory; import ghidra.trace.util.MemoryAdapter; @@ -43,9 +41,10 @@ public abstract class AbstractDBTraceProgramViewMemory protected final DBTraceProgramView program; protected final DBTraceMemoryManager memoryManager; - protected volatile AddressSetView addressSet; - protected boolean forceFullView = false; - protected long snap; + private volatile AddressSetView addressSet; + private volatile boolean addressSetValid; + private boolean forceFullView = false; + private long snap; private static final int CACHE_PAGE_COUNT = 3; protected final ByteCache cache = new ByteCache(CACHE_PAGE_COUNT) { @@ -68,37 +67,25 @@ public abstract class AbstractDBTraceProgramViewMemory setSnap(program.snap); } - protected abstract void recomputeAddressSet(); + protected abstract AddressSetView computeAddressSet(); - protected void forPhysicalSpaces(Consumer consumer) { - for (AddressSpace space : program.getAddressFactory().getAddressSpaces()) { - // NB. Overlay's isMemory depends on its base space - // TODO: Allow other? - // For some reason "other" is omitted from factory.getAddressSet - if (space.isMemorySpace() && space.getType() != AddressSpace.TYPE_OTHER) { - consumer.accept(space); - } - } + protected void invalidateAddressSet() { + addressSetValid = false; + program.fireObjectRestored(); } - protected void computeFullAdddressSet() { - AddressSet temp = new AddressSet(); - try (LockHold hold = program.trace.lockRead()) { - forPhysicalSpaces(space -> temp.add(space.getMinAddress(), space.getMaxAddress())); + protected AddressSetView getOrComputeAddressSet() { + if (!addressSetValid) { + addressSet = computeAddressSet(); + addressSetValid = true; } - addressSet = temp; + return addressSet; } @Override public void setForceFullView(boolean forceFullView) { this.forceFullView = forceFullView; - if (forceFullView) { - computeFullAdddressSet(); - } - else { - recomputeAddressSet(); - } - program.fireObjectRestored(); + invalidateAddressSet(); } @Override @@ -109,7 +96,7 @@ public abstract class AbstractDBTraceProgramViewMemory void setSnap(long snap) { this.snap = snap; if (!forceFullView) { - recomputeAddressSet(); + invalidateAddressSet(); } } @@ -130,29 +117,17 @@ public abstract class AbstractDBTraceProgramViewMemory @Override public AddressSetView getLoadedAndInitializedAddressSet() { - return addressSet; + return getOrComputeAddressSet(); } @Override public AddressSetView getAllInitializedAddressSet() { - return addressSet; + return getOrComputeAddressSet(); } @Override public AddressSetView getInitializedAddressSet() { - return addressSet; - } - - @Override - public AddressSetView getExecuteSet() { - AddressSet result = new AddressSet(); - for (TraceMemoryRegion region : memoryManager.getAllRegions()) { - if (!region.isExecute() || !program.isRegionVisible(region, region.getLifespan())) { - continue; - } - result.add(region.getRange()); - } - return result; + return getOrComputeAddressSet(); } @Override @@ -225,7 +200,7 @@ public abstract class AbstractDBTraceProgramViewMemory @Override public long getSize() { - return addressSet.getNumAddresses(); + return getOrComputeAddressSet().getNumAddresses(); } @Override @@ -366,166 +341,141 @@ public abstract class AbstractDBTraceProgramViewMemory @Override public boolean contains(Address addr) { - return addressSet.contains(addr); + return getOrComputeAddressSet().contains(addr); } @Override public boolean contains(Address start, Address end) { - return addressSet.contains(start, end); + return getOrComputeAddressSet().contains(start, end); } @Override public boolean contains(AddressSetView set) { - return addressSet.contains(set); + return getOrComputeAddressSet().contains(set); } @Override public boolean isEmpty() { - return addressSet.isEmpty(); + return getOrComputeAddressSet().isEmpty(); } @Override public Address getMinAddress() { - return addressSet.getMinAddress(); + return getOrComputeAddressSet().getMinAddress(); } @Override public Address getMaxAddress() { - return addressSet.getMaxAddress(); + return getOrComputeAddressSet().getMaxAddress(); } @Override public int getNumAddressRanges() { - return addressSet.getNumAddressRanges(); + return getOrComputeAddressSet().getNumAddressRanges(); } @Override public AddressRangeIterator getAddressRanges() { - return addressSet.getAddressRanges(); + return getOrComputeAddressSet().getAddressRanges(); } @Override public AddressRangeIterator getAddressRanges(boolean forward) { - return addressSet.getAddressRanges(forward); + return getOrComputeAddressSet().getAddressRanges(forward); } @Override public AddressRangeIterator getAddressRanges(Address start, boolean forward) { - return addressSet.getAddressRanges(start, forward); + return getOrComputeAddressSet().getAddressRanges(start, forward); } @Override public Iterator iterator() { - return addressSet.iterator(); + return getOrComputeAddressSet().iterator(); } @Override public Iterator iterator(boolean forward) { - return addressSet.iterator(forward); + return getOrComputeAddressSet().iterator(forward); } @Override public Iterator iterator(Address start, boolean forward) { - return addressSet.iterator(start, forward); + return getOrComputeAddressSet().iterator(start, forward); } @Override public long getNumAddresses() { - return addressSet.getNumAddresses(); + return getOrComputeAddressSet().getNumAddresses(); } @Override public AddressIterator getAddresses(boolean forward) { - return addressSet.getAddresses(forward); + return getOrComputeAddressSet().getAddresses(forward); } @Override public AddressIterator getAddresses(Address start, boolean forward) { - return addressSet.getAddresses(start, forward); + return getOrComputeAddressSet().getAddresses(start, forward); } @Override public boolean intersects(AddressSetView addrSet) { - return addressSet.intersects(addrSet); + return getOrComputeAddressSet().intersects(addrSet); } @Override public boolean intersects(Address start, Address end) { - return addressSet.intersects(start, end); + return getOrComputeAddressSet().intersects(start, end); } @Override public AddressSet intersect(AddressSetView view) { - return addressSet.intersect(view); + return getOrComputeAddressSet().intersect(view); } @Override public AddressSet intersectRange(Address start, Address end) { - return addressSet.intersectRange(start, end); + return getOrComputeAddressSet().intersectRange(start, end); } @Override public AddressSet union(AddressSetView addrSet) { - return addressSet.union(addrSet); + return getOrComputeAddressSet().union(addrSet); } @Override public AddressSet subtract(AddressSetView addrSet) { - return addressSet.subtract(addrSet); + return getOrComputeAddressSet().subtract(addrSet); } @Override public AddressSet xor(AddressSetView addrSet) { - return addressSet.xor(addrSet); + return getOrComputeAddressSet().xor(addrSet); } @Override public boolean hasSameAddresses(AddressSetView view) { - return addressSet.hasSameAddresses(view); + return getOrComputeAddressSet().hasSameAddresses(view); } @Override public AddressRange getFirstRange() { - return addressSet.getFirstRange(); + return getOrComputeAddressSet().getFirstRange(); } @Override public AddressRange getLastRange() { - return addressSet.getLastRange(); + return getOrComputeAddressSet().getLastRange(); } @Override public AddressRange getRangeContaining(Address address) { - return addressSet.getRangeContaining(address); + return getOrComputeAddressSet().getRangeContaining(address); } @Override public Address findFirstAddressInCommon(AddressSetView set) { - return addressSet.findFirstAddressInCommon(set); - } - - protected synchronized void addRange(AddressRange range) { - if (!forceFullView) { - addressSet = addressSet.union(new AddressSet(range)); - } - } - - protected synchronized void removeRange(AddressRange range) { - if (!forceFullView) { - addressSet = addressSet.subtract(new AddressSet(range)); - } - } - - protected synchronized void changeRange(AddressRange remove, AddressRange add) { - if (!forceFullView) { - AddressSet temp = new AddressSet(addressSet); - if (remove != null) { - temp.delete(remove); - } - if (add != null) { - temp.add(add); - } - addressSet = temp; - } + return getOrComputeAddressSet().findFirstAddressInCommon(set); } } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramView.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramView.java index 66db8ab1c5..466e4fd00e 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramView.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramView.java @@ -488,56 +488,26 @@ public class DBTraceProgramView implements TraceProgramView { } private void memoryRegionAdded(TraceAddressSpace space, TraceMemoryRegion region) { - if (!isRegionVisible(region)) { - return; - } - // NOTE: Register view regions are fixed - eventQueues.fireEvent(new ProgramChangeRecord(ProgramEvent.MEMORY_BLOCK_ADDED, - region.getMinAddress(), region.getMaxAddress(), null, null, null)); - // NOTE: MemoryMapDB does this, too. Otherwise, CodeBrowserPlugin does not hear. - eventQueues.fireEvent(new DomainObjectChangeRecord(DomainObjectEvent.RESTORED)); + // This is handled via another path } private void memoryRegionChanged(TraceAddressSpace space, TraceMemoryRegion region) { - if (!isRegionVisible(region)) { - return; - } - eventQueues.fireEvent(new ProgramChangeRecord(ProgramEvent.MEMORY_BLOCK_CHANGED, - region.getMinAddress(), region.getMaxAddress(), null, null, null)); - // TODO: Perhaps a bit heavy-handed here. MemoryMapDB does not do this, too. - // TODO: Probably want a separate RANGE_CHANGED or MOVED event + // Could be a name change, which must get communicated to program. + // RESTORED may be duplicative, but should get de-duped by event manager. eventQueues.fireEvent(new DomainObjectChangeRecord(DomainObjectEvent.RESTORED)); } private void memoryRegionLifespanChanged(TraceAddressSpace space, TraceMemoryRegion region, Lifespan oldSpan, Lifespan newSpan) { - boolean inOld = isRegionVisible(region, oldSpan); - boolean inNew = isRegionVisible(region, newSpan); - if (inOld && !inNew) { - eventQueues.fireEvent(new ProgramChangeRecord(ProgramEvent.MEMORY_BLOCK_REMOVED, - region.getMinAddress(), region.getMaxAddress(), null, null, null)); - // NOTE: MemoryMapDB does this, too. Otherwise, CodeBrowserPlugin does not hear. - eventQueues.fireEvent(new DomainObjectChangeRecord(DomainObjectEvent.RESTORED)); - } - if (!inOld && inNew) { - eventQueues.fireEvent(new ProgramChangeRecord(ProgramEvent.MEMORY_BLOCK_ADDED, - region.getMinAddress(), region.getMaxAddress(), null, null, null)); - // NOTE: MemoryMapDB does this, too. Otherwise, CodeBrowserPlugin does not hear. - eventQueues.fireEvent(new DomainObjectChangeRecord(DomainObjectEvent.RESTORED)); - } + // This is handled via another path } private void memoryRegionDeleted(TraceAddressSpace space, TraceMemoryRegion region) { // HACK listing.fragmentsByRegion.remove(region); // END HACK - if (!isRegionVisible(region)) { - return; - } - eventQueues.fireEvent(new ProgramChangeRecord(ProgramEvent.MEMORY_BLOCK_REMOVED, - region.getMinAddress(), region.getMaxAddress(), null, null, null)); - // NOTE: MemoryMapDB does this, too. Otherwise, CodeBrowserPlugin does not hear. - eventQueues.fireEvent(new DomainObjectChangeRecord(DomainObjectEvent.RESTORED)); + + // Memory stuff handled via another path } private void sourceArchiveAdded(UniversalID id) { @@ -1466,51 +1436,29 @@ public class DBTraceProgramView implements TraceProgramView { } public void updateMemoryAddRegionBlock(TraceMemoryRegion region) { - if (!isRegionVisible(region)) { - return; - } - memory.updateAddRegionBlock(region); + memory.invalidateRegions(); } public void updateMemoryChangeRegionBlockName(TraceMemoryRegion region) { - if (!isRegionVisible(region)) { - return; - } - memory.updateChangeRegionBlockName(region); + // Doesn't affect any cache } public void updateMemoryChangeRegionBlockFlags(TraceMemoryRegion region, Lifespan lifespan) { - if (!isRegionVisible(region, lifespan)) { - return; - } - memory.updateChangeRegionBlockFlags(region); + // Doesn't affect any cache } public void updateMemoryChangeRegionBlockRange(TraceMemoryRegion region, AddressRange oldRange, AddressRange newRange) { - if (!isRegionVisible(region)) { - return; - } - memory.updateChangeRegionBlockRange(region, oldRange, newRange); + memory.invalidateRegions(); } public void updateMemoryChangeRegionBlockLifespan(TraceMemoryRegion region, Lifespan oldLifespan, Lifespan newLifespan) { - boolean inOld = isRegionVisible(region, oldLifespan); - boolean inNew = isRegionVisible(region, newLifespan); - if (inOld && !inNew) { - memory.updateDeleteRegionBlock(region); - } - if (!inOld && inNew) { - memory.updateAddRegionBlock(region); - } + memory.invalidateRegions(); } public void updateMemoryDeleteRegionBlock(TraceMemoryRegion region) { - if (!isRegionVisible(region)) { - return; - } - memory.updateAddRegionBlock(region); + memory.invalidateRegions(); } public void updateMemoryAddSpaceBlock(AddressSpace space) { @@ -1612,7 +1560,7 @@ public class DBTraceProgramView implements TraceProgramView { } @Override - public AddressRange range(TraceCodeUnit cu) { + public AddressRange range(TraceCodeUnit cu, long snap) { return cu.getRange(); } }; @@ -1695,24 +1643,4 @@ public class DBTraceProgramView implements TraceProgramView { } return queues; } - - protected Occlusion regionOcclusion = new RangeQueryOcclusion<>() { - @Override - public Iterable query(AddressRange range, Lifespan span) { - return trace.getMemoryManager().getRegionsIntersecting(Lifespan.at(span.lmax()), range); - } - - @Override - public AddressRange range(TraceMemoryRegion r) { - return r.getRange(); - } - }; - - protected boolean isRegionVisible(TraceMemoryRegion reg) { - return isRegionVisible(reg, reg.getLifespan()); - } - - protected boolean isRegionVisible(TraceMemoryRegion reg, Lifespan lifespan) { - return viewport.isCompletelyVisible(reg.getRange(), lifespan, reg, regionOcclusion); - } } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewFragment.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewFragment.java index 6f5a197dc5..ad46e6f9b2 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewFragment.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewFragment.java @@ -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. @@ -27,11 +27,13 @@ import ghidra.util.exception.NotFoundException; public class DBTraceProgramViewFragment implements ProgramFragment { protected final AbstractDBTraceProgramViewListing listing; protected final TraceMemoryRegion region; + protected final long snap; // From viewport, not necessarily current public DBTraceProgramViewFragment(AbstractDBTraceProgramViewListing listing, - TraceMemoryRegion region) { + TraceMemoryRegion region, long snap) { this.listing = listing; this.region = region; + this.snap = snap; } @Override @@ -46,7 +48,7 @@ public class DBTraceProgramViewFragment implements ProgramFragment { @Override public String getName() { - return region.getName(); + return region.getName(snap); } @Override @@ -76,25 +78,20 @@ public class DBTraceProgramViewFragment implements ProgramFragment { @Override public boolean contains(Address addr) { - return region.getRange().contains(addr) && - region.getLifespan().contains(listing.program.snap); + return region.getRange(snap).contains(addr); } @Override public boolean contains(Address start, Address end) { // Regions are contiguous - AddressRange range = region.getRange(); - return range.contains(start) && range.contains(end) && - region.getLifespan().contains(listing.program.snap); + AddressRange range = region.getRange(snap); + return range.contains(start) && range.contains(end); } @Override public boolean contains(AddressSetView rangeSet) { - if (!region.getLifespan().contains(listing.program.snap)) { - return false; - } for (AddressRange range : rangeSet) { - AddressRange regionRange = region.getRange(); + AddressRange regionRange = region.getRange(snap); if (!regionRange.contains(range.getMinAddress()) || !regionRange.contains(range.getMaxAddress())) { return false; @@ -104,7 +101,7 @@ public class DBTraceProgramViewFragment implements ProgramFragment { } protected AddressSet toAddressSet() { - return new AddressSet(region.getMinAddress(), region.getMaxAddress()); + return new AddressSet(region.getMinAddress(snap), region.getMaxAddress(snap)); } @Override @@ -114,12 +111,12 @@ public class DBTraceProgramViewFragment implements ProgramFragment { @Override public Address getMinAddress() { - return region.getMinAddress(); + return region.getMinAddress(snap); } @Override public Address getMaxAddress() { - return region.getMaxAddress(); + return region.getMaxAddress(snap); } @Override @@ -214,12 +211,12 @@ public class DBTraceProgramViewFragment implements ProgramFragment { @Override public AddressRange getFirstRange() { - return new AddressRangeImpl(region.getMinAddress(), region.getMaxAddress()); + return new AddressRangeImpl(region.getMinAddress(snap), region.getMaxAddress(snap)); } @Override public AddressRange getLastRange() { - return new AddressRangeImpl(region.getMinAddress(), region.getMaxAddress()); + return new AddressRangeImpl(region.getMinAddress(snap), region.getMaxAddress(snap)); } @Override diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewMemory.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewMemory.java index a46a159ee6..20dacbaa9e 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewMemory.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewMemory.java @@ -16,63 +16,158 @@ package ghidra.trace.database.program; import java.util.*; +import java.util.Map.Entry; import java.util.function.Consumer; -import java.util.function.Function; import ghidra.program.model.address.*; import ghidra.program.model.mem.MemoryBlock; +import ghidra.trace.model.Lifespan; import ghidra.trace.model.memory.TraceMemoryRegion; import ghidra.util.LockHold; import ghidra.util.datastruct.WeakValueHashMap; public class DBTraceProgramViewMemory extends AbstractDBTraceProgramViewMemory { - // I think size should be about how many instructions may appear on screen at once. - // Double for good measure (in case windows are cloned, maximized, etc.) - private static final int REGION_CACHE_BY_ADDRESS_SIZE = 300; - - // Size should be about how many distinct regions are involved in displayed instructions - // Probably only about 5, but cost of 30 is still small. - private static final int REGION_CACHE_BY_NAME_SIZE = 30; // NB. Keep both per-region and force-full (per-space) block sets ready private final Map regionBlocks = new WeakValueHashMap<>(); private final Map spaceBlocks = new WeakValueHashMap<>(); - private final Map regionCacheByAddress = new LinkedHashMap<>() { - protected boolean removeEldestEntry(Map.Entry eldest) { - return this.size() > REGION_CACHE_BY_ADDRESS_SIZE; - } - }; - private final Map regionCacheByName = new LinkedHashMap<>() { - protected boolean removeEldestEntry(Map.Entry eldest) { - return this.size() > REGION_CACHE_BY_NAME_SIZE; - } - }; + + private NavigableMap regionsByAddress; + private Map regionsByName; + private volatile boolean regionsValid; public DBTraceProgramViewMemory(DBTraceProgramView program) { super(program); } - protected TraceMemoryRegion getTopRegion(Function regFunc) { - return program.viewport.getTop(s -> { - // TODO: There is probably an early-bail condition I can check for. - TraceMemoryRegion reg = regFunc.apply(s); - if (reg != null && program.isRegionVisible(reg)) { - return reg; + protected void forPhysicalSpaces(Consumer consumer) { + for (AddressSpace space : program.getAddressFactory().getAddressSpaces()) { + // NB. Overlay's isMemory depends on its base space + // TODO: Allow other? + // For some reason "other" is omitted from factory.getAddressSet + if (space.isMemorySpace() && space.getType() != AddressSpace.TYPE_OTHER) { + consumer.accept(space); } - return null; - }); + } } - protected void forVisibleRegions(Consumer action) { - for (long s : program.viewport.getOrderedSnaps()) { - // NOTE: This is slightly faster than new AddressSet(mm.getRegionsAddressSet(snap)) - for (TraceMemoryRegion reg : memoryManager.getRegionsAtSnap(s)) { - if (program.isRegionVisible(reg)) { - action.accept(reg); + static class RegionEntry { + final TraceMemoryRegion region; + final AddressRange range; + + long snap; + + public RegionEntry(TraceMemoryRegion region, long snap) { + this.region = region; + this.range = region.getRange(snap); + + this.snap = snap; + } + + public boolean isSameAtDifferentSnap(RegionEntry that) { + if (that == null) { + return false; + } + // Yes, region by identity + return this.region == that.region && this.range.equals(that.range); + } + } + + class RegionsByAddressComputer { + TreeMap map = new TreeMap<>(); + Map addressByRegion = new HashMap<>(); + + protected void putDeletingOverlaps(RegionEntry newEntry) { + // Check if removal is necessary. + Address newKey = newEntry.range.getMinAddress(); + RegionEntry curEntry = map.get(newKey); + if (newEntry.isSameAtDifferentSnap(curEntry)) { + curEntry.snap = newEntry.snap; + return; + } + + // Remove all overlapping entries + Entry floorEntry = map.floorEntry(newKey); + final Address min; + if (floorEntry != null && floorEntry.getValue().range.contains(newKey)) { + min = floorEntry.getKey(); + } + else { + min = newKey; + } + map.subMap(min, true, newEntry.range.getMaxAddress(), true).clear(); + + // Remove old entry for the same region, if present + Address oldKey = addressByRegion.remove(newEntry.region); + if (oldKey != null) { + map.remove(oldKey); + } + + // Put new entry + map.put(newKey, newEntry); + addressByRegion.put(newEntry.region, newKey); + } + + public NavigableMap compute() { + /** + * We're banking on the viewport being relatively shallow, and for this to be invoked + * relatively infrequently. We build the view from oldest to newest, clobbering old + * overlaps as we add the new. Additionally, if a region moves, we must not show its old + * position. (NOTE: Philosophically, a region cannot "move", but it's key could be + * reused, depending on the connector.) + */ + for (long snap : program.viewport.getReversedSnaps()) { + for (AddressSpace space : getTrace().getBaseAddressFactory().getPhysicalSpaces()) { + AddressRange range = + new AddressRangeImpl(space.getMinAddress(), space.getMaxAddress()); + for (TraceMemoryRegion region : memoryManager + .getRegionsIntersecting(Lifespan.at(snap), range)) { + RegionEntry entry = new RegionEntry(region, snap); + putDeletingOverlaps(entry); + } } } + return map; + } + } + + protected NavigableMap computeRegionsByAddress() { + return new RegionsByAddressComputer().compute(); + } + + protected Map computeRegionsByName(Collection regions) { + Map result = new HashMap<>(); + for (RegionEntry entry : regions) { + result.put(entry.region.getName(entry.snap), entry); + } + return result; + } + + protected NavigableMap getRegionsByAddress() { + if (!regionsValid) { + NavigableMap byAddr = computeRegionsByAddress(); + regionsByAddress = byAddr; + regionsByName = computeRegionsByName(byAddr.values()); + regionsValid = true; + } + return regionsByAddress; + } + + protected Map getRegionsByName() { + if (!regionsValid) { + NavigableMap byAddr = computeRegionsByAddress(); + regionsByAddress = byAddr; + regionsByName = computeRegionsByName(byAddr.values()); + regionsValid = true; + } + return regionsByName; + } + + protected void forVisibleRegions(Consumer action) { + for (RegionEntry entry : getRegionsByAddress().values()) { + action.accept(entry); } } @@ -80,21 +175,35 @@ public class DBTraceProgramViewMemory extends AbstractDBTraceProgramViewMemory { void setSnap(long snap) { super.setSnap(snap); updateBytesChanged(null); + invalidateRegions(); + } + + protected AddressSet computeRegionsAddressSet() { + AddressSet result = new AddressSet(); + try (LockHold hold = program.trace.lockRead()) { + forVisibleRegions(e -> result.add(e.range)); + } + return result; + } + + protected AddressSet computeSpacesAddressSet() { + AddressSet result = new AddressSet(); + try (LockHold hold = program.trace.lockRead()) { + forPhysicalSpaces(space -> result.add(space.getMinAddress(), space.getMaxAddress())); + } + return result; } @Override - protected void recomputeAddressSet() { - AddressSet temp = new AddressSet(); - try (LockHold hold = program.trace.lockRead()) { - // TODO: Performance test this - forVisibleRegions(reg -> temp.add(reg.getRange())); - } - addressSet = temp; + protected AddressSetView computeAddressSet() { + return isForceFullView() + ? computeSpacesAddressSet() + : computeRegionsAddressSet(); } - protected MemoryBlock getRegionBlock(TraceMemoryRegion region) { - return regionBlocks.computeIfAbsent(region, - r -> new DBTraceProgramViewMemoryRegionBlock(program, region)); + protected MemoryBlock getRegionBlock(RegionEntry entry) { + return regionBlocks.computeIfAbsent(entry.region, + r -> new DBTraceProgramViewMemoryRegionBlock(program, entry.region, entry.snap)); } protected MemoryBlock getSpaceBlock(AddressSpace space) { @@ -104,54 +213,35 @@ public class DBTraceProgramViewMemory extends AbstractDBTraceProgramViewMemory { @Override public MemoryBlock getBlock(Address addr) { - if (forceFullView) { + if (isForceFullView()) { return getSpaceBlock(addr.getAddressSpace()); } - TraceMemoryRegion region = regionCacheByAddress.get(addr); - if (region != null && !region.isDeleted()) { - /** - * TODO: This is assuming: 1) We never fork in non-scratch space. 2) Regions are not - * created in scratch space. These are convention, but weren't originally intended to be - * rules. This makes them rules. - */ - long s = program.viewport.getReversedSnaps().get(0); - if (region.getLifespan().contains(s)) { - return getRegionBlock(region); - } + + Entry entry = getRegionsByAddress().floorEntry(addr); + if (entry == null || !entry.getValue().range.contains(addr)) { + return null; } - region = getTopRegion(s -> memoryManager.getRegionContaining(s, addr)); - if (region != null) { - regionCacheByAddress.put(addr, region); - return getRegionBlock(region); - } - return null; + return getRegionBlock(entry.getValue()); } @Override public MemoryBlock getBlock(String blockName) { - if (forceFullView) { + if (isForceFullView()) { AddressSpace space = program.getAddressFactory().getAddressSpace(blockName); return space == null ? null : getSpaceBlock(space); } - TraceMemoryRegion region = regionCacheByName.get(blockName); - if (region != null && !region.isDeleted()) { - long s = program.viewport.getReversedSnaps().get(0); - if (region.getLifespan().contains(s)) { - return getRegionBlock(region); - } + + RegionEntry entry = getRegionsByName().get(blockName); + if (entry == null) { + return null; } - region = getTopRegion(s -> memoryManager.getLiveRegionByPath(s, blockName)); - if (region != null) { - regionCacheByName.put(blockName, region); - return getRegionBlock(region); - } - return null; + return getRegionBlock(entry); } @Override public MemoryBlock[] getBlocks() { List result = new ArrayList<>(); - if (forceFullView) { + if (isForceFullView()) { forPhysicalSpaces(space -> result.add(getSpaceBlock(space))); } else { @@ -161,27 +251,25 @@ public class DBTraceProgramViewMemory extends AbstractDBTraceProgramViewMemory { return result.toArray(new MemoryBlock[result.size()]); } - public void updateAddRegionBlock(TraceMemoryRegion region) { - // TODO: add block to cache? - addRange(region.getRange()); + @Override + public AddressSetView getExecuteSet() { + AddressSet result = new AddressSet(); + forVisibleRegions(e -> { + if (e.region.isExecute(e.snap)) { + result.add(e.range); + } + }); + return result; } - public void updateChangeRegionBlockName(TraceMemoryRegion region) { - // Nothing. Block name is taken from region, uncached - } - - public void updateChangeRegionBlockFlags(TraceMemoryRegion region) { - // Nothing. Block flags are taken from region, uncached - } - - public void updateChangeRegionBlockRange(TraceMemoryRegion region, AddressRange oldRange, - AddressRange newRange) { - changeRange(oldRange, newRange); - } - - public void updateDeleteRegionBlock(TraceMemoryRegion region) { - regionBlocks.remove(region); - removeRange(region.getRange()); + protected void invalidateRegions() { + regionsValid = false; + if (regionBlocks != null) { // order + regionBlocks.clear(); + } + if (!isForceFullView()) { + invalidateAddressSet(); + } } public void updateAddSpaceBlock(AddressSpace space) { @@ -193,9 +281,8 @@ public class DBTraceProgramViewMemory extends AbstractDBTraceProgramViewMemory { } public void updateRefreshBlocks() { - regionBlocks.clear(); + invalidateRegions(); spaceBlocks.clear(); - recomputeAddressSet(); } public void updateBytesChanged(AddressRange range) { diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewMemoryRegionBlock.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewMemoryRegionBlock.java index 69486012e9..516ed4d6f1 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewMemoryRegionBlock.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewMemoryRegionBlock.java @@ -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. @@ -29,11 +29,13 @@ import ghidra.trace.model.memory.*; public class DBTraceProgramViewMemoryRegionBlock extends AbstractDBTraceProgramViewMemoryBlock { private final TraceMemoryRegion region; + private final long snap; // Snap may be in viewport, not current public DBTraceProgramViewMemoryRegionBlock(DBTraceProgramView program, - TraceMemoryRegion region) { + TraceMemoryRegion region, long snap) { super(program); this.region = region; + this.snap = snap; } @Override @@ -43,25 +45,37 @@ public class DBTraceProgramViewMemoryRegionBlock extends AbstractDBTraceProgramV @Override protected AddressSpace getAddressSpace() { - return region.getRange().getAddressSpace(); + return region.getRange(snap).getAddressSpace(); } @Override public AddressRange getAddressRange() { - return region.getRange(); + return region.getRange(snap); + } + + protected void checkSnapOnSet() { + long snap = program.getSnap(); + if (snap != this.snap) { + /** + * TODO: Copy the region to here? It would immediately invalidate this block, but I + * suppose that's okay, as long as the UI updates appropriately. + */ + throw new UnsupportedOperationException("Region is from a forked snapshot"); + } } @Override public void setPermissions(boolean read, boolean write, boolean execute) { - region.setRead(read); - region.setWrite(write); - region.setExecute(execute); + checkSnapOnSet(); + region.setRead(snap, read); + region.setWrite(snap, write); + region.setExecute(snap, execute); } @Override public int getFlags() { int bits = 0; - for (TraceMemoryFlag flag : region.getFlags()) { + for (TraceMemoryFlag flag : region.getFlags(snap)) { bits |= flag.getBits(); } return bits; @@ -69,7 +83,7 @@ public class DBTraceProgramViewMemoryRegionBlock extends AbstractDBTraceProgramV @Override public InputStream getData() { - AddressRange range = region.getRange(); + AddressRange range = region.getRange(snap); DBTraceMemorySpace space = program.trace.getMemoryManager().getMemorySpace(range.getAddressSpace(), false); if (space == null) { @@ -80,72 +94,77 @@ public class DBTraceProgramViewMemoryRegionBlock extends AbstractDBTraceProgramV @Override public Address getStart() { - return region.getRange().getMinAddress(); + return region.getRange(snap).getMinAddress(); } @Override public Address getEnd() { - return region.getRange().getMaxAddress(); + return region.getRange(snap).getMaxAddress(); } @Override public long getSize() { - return region.getRange().getLength(); + return region.getRange(snap).getLength(); } @Override public BigInteger getSizeAsBigInteger() { - return region.getRange().getBigLength(); + return region.getRange(snap).getBigLength(); } @Override public String getName() { - return region.getName(); + return region.getName(snap); } @Override public void setName(String name) throws LockException { - region.setName(name); + checkSnapOnSet(); + region.setName(snap, name); } @Override public boolean isRead() { - return region.isRead(); + return region.isRead(snap); } @Override public void setRead(boolean r) { - region.setRead(r); + checkSnapOnSet(); + region.setRead(snap, r); } @Override public boolean isWrite() { - return region.isWrite(); + return region.isWrite(snap); } @Override public void setWrite(boolean w) { - region.setWrite(w); + checkSnapOnSet(); + region.setWrite(snap, w); } @Override public boolean isExecute() { - return region.isExecute(); + return region.isExecute(snap); } @Override public void setExecute(boolean e) { - region.setExecute(e); + checkSnapOnSet(); + region.setExecute(snap, e); } @Override public boolean isVolatile() { - return region.isVolatile(); + return region.isVolatile(snap); } @Override public void setVolatile(boolean v) { - region.setVolatile(v); + checkSnapOnSet(); + region.setVolatile(snap, v); } @Override diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewRegisterMemory.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewRegisterMemory.java index aa1b013ecb..ff93235287 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewRegisterMemory.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewRegisterMemory.java @@ -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. @@ -28,9 +28,6 @@ public class DBTraceProgramViewRegisterMemory extends AbstractDBTraceProgramView super(program); this.space = space; this.block = new DBTraceProgramViewRegisterMemoryBlock(program, space); - this.addressSet = - new AddressSet(new AddressRangeImpl(space.getAddressSpace().getMinAddress(), - space.getAddressSpace().getMaxAddress())); } @Override @@ -39,8 +36,10 @@ public class DBTraceProgramViewRegisterMemory extends AbstractDBTraceProgramView } @Override - protected void recomputeAddressSet() { + protected AddressSetView computeAddressSet() { // AddressSet is always full space + return new AddressSet(new AddressRangeImpl(space.getAddressSpace().getMinAddress(), + space.getAddressSpace().getMaxAddress())); } @Override @@ -64,4 +63,9 @@ public class DBTraceProgramViewRegisterMemory extends AbstractDBTraceProgramView // NOTE: Don't cache, to avoid external mutation. return new MemoryBlock[] { block }; } + + @Override + public AddressSetView getExecuteSet() { + return new AddressSet(); + } } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewRegisterMemoryBlock.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewRegisterMemoryBlock.java index 975509feef..58fd5c318e 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewRegisterMemoryBlock.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewRegisterMemoryBlock.java @@ -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. @@ -51,7 +51,7 @@ public class DBTraceProgramViewRegisterMemoryBlock implements MemoryBlock { @Override public String getDescription() { - return "Trace registers: " + space.getThread().getName(); + return "Trace registers: " + space.getThread().getName(program.getSnap()); } @Override diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewRootModule.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewRootModule.java index e77b345bca..4b33dd95dc 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewRootModule.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewRootModule.java @@ -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,17 +15,16 @@ */ package ghidra.trace.database.program; -import java.util.ArrayList; -import java.util.List; +import java.util.*; import java.util.function.BiFunction; import java.util.function.Consumer; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressSetView; import ghidra.program.model.listing.*; +import ghidra.trace.database.program.DBTraceProgramViewMemory.RegionEntry; import ghidra.trace.model.memory.TraceMemoryRegion; import ghidra.util.LockHold; -import ghidra.util.MathUtilities; import ghidra.util.exception.*; public class DBTraceProgramViewRootModule implements ProgramModule { @@ -105,9 +104,9 @@ public class DBTraceProgramViewRootModule implements ProgramModule { // NOTE: Would flush on snap change try (LockHold hold = LockHold.lock(program.trace.getReadWriteLock().readLock())) { List frags = new ArrayList<>(); - program.memory.forVisibleRegions(region -> { - frags.add(listing.fragmentsByRegion.computeIfAbsent(region, - r -> new DBTraceProgramViewFragment(listing, r))); + program.memory.forVisibleRegions(e -> { + frags.add(listing.fragmentsByRegion.computeIfAbsent(e.region, + r -> new DBTraceProgramViewFragment(listing, r, e.snap))); }); return frags.toArray(new DBTraceProgramViewFragment[frags.size()]); } @@ -118,7 +117,7 @@ public class DBTraceProgramViewRootModule implements ProgramModule { // TODO: This isn't pretty at all. Really should database these. List names = new ArrayList<>(); try (LockHold hold = LockHold.lock(program.trace.getReadWriteLock().readLock())) { - program.memory.forVisibleRegions(region -> names.add(region.getName())); + program.memory.forVisibleRegions(e -> names.add(e.region.getName(e.snap))); } return names.indexOf(name); } @@ -189,24 +188,20 @@ public class DBTraceProgramViewRootModule implements ProgramModule { @Override public Address getMinAddress() { - if (!program.viewport.isForked()) { - return program.trace.getMemoryManager() - .getRegionsAddressSet(program.snap) - .getMinAddress(); + NavigableMap regionsByAddress = program.memory.getRegionsByAddress(); + if (regionsByAddress.isEmpty()) { + return null; } - // TODO: There has got to be a better way - return reduceRegions(TraceMemoryRegion::getMinAddress, MathUtilities::cmin); + return regionsByAddress.firstKey(); } @Override public Address getMaxAddress() { - if (!program.viewport.isForked()) { - return program.trace.getMemoryManager() - .getRegionsAddressSet(program.snap) - .getMaxAddress(); + NavigableMap regionsByAddress = program.memory.getRegionsByAddress(); + if (regionsByAddress.isEmpty()) { + return null; } - // TODO: There has got to be a better way - return reduceRegions(TraceMemoryRegion::getMaxAddress, MathUtilities::cmax); + return regionsByAddress.lastEntry().getValue().range.getMaxAddress(); } @Override diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/stack/DBTraceObjectStack.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/stack/DBTraceObjectStack.java index 57934672fc..95845d9394 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/stack/DBTraceObjectStack.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/stack/DBTraceObjectStack.java @@ -77,21 +77,17 @@ public class DBTraceObjectStack implements TraceObjectStack, DBTraceObjectInterf @Override public TraceThread getThread() { try (LockHold hold = object.getTrace().lockRead()) { - return object.queryAncestorsInterface(computeSpan(), TraceObjectThread.class) + return object.queryCanonicalAncestorsInterface(TraceObjectThread.class) .findAny() .orElseThrow(); } } @Override - public long getSnap() { - return computeMinSnap(); - } - - @Override - public int getDepth() { + public int getDepth(long snap) { try (LockHold hold = object.getTrace().lockRead()) { - return object.querySuccessorsInterface(computeSpan(), TraceObjectStackFrame.class, true) + return object + .querySuccessorsInterface(Lifespan.at(snap), TraceObjectStackFrame.class, true) .map(f -> f.getLevel()) .reduce(Integer::max) .map(m -> m + 1) @@ -99,7 +95,7 @@ public class DBTraceObjectStack implements TraceObjectStack, DBTraceObjectInterf } } - protected TraceObjectStackFrame doAddStackFrame(int level) { + protected TraceObjectStackFrame doAddStackFrame(long snap, int level) { try (LockHold hold = object.getTrace().lockWrite()) { PathFilter filter = object.getSchema().searchFor(TraceObjectStackFrame.class, true); @@ -108,45 +104,47 @@ public class DBTraceObjectStack implements TraceObjectStack, DBTraceObjectInterf throw new IllegalStateException("Could not determine where to create new frame"); } KeyPath path = object.getCanonicalPath().extend(relPath); - return object.getManager().addStackFrame(path, getSnap()); + return object.getManager().addStackFrame(path, snap); } } - protected void copyFrameAttributes(TraceObjectStackFrame from, TraceObjectStackFrame to) { - // TODO: All attributes within a given span, intersected to that span? - to.setProgramCounter(computeSpan(), from.getProgramCounter(computeMaxSnap())); + protected void copyFrameAttributes(long snap, TraceObjectStackFrame from, + TraceObjectStackFrame to) { + // Program Counter is the only attribute? + to.setProgramCounter(Lifespan.nowOn(snap), from.getProgramCounter(snap)); } - protected void shiftFrameAttributes(int from, int to, int count, + protected void shiftFrameAttributes(long snap, int from, int to, int count, List frames) { if (from == to) { return; } if (from < to) { for (int i = count - 1; i >= 0; i--) { - copyFrameAttributes(frames.get(from + i), frames.get(to + i)); + copyFrameAttributes(snap, frames.get(from + i), frames.get(to + i)); } } else { for (int i = 0; i < count; i++) { - copyFrameAttributes(frames.get(from + i), frames.get(to + i)); + copyFrameAttributes(snap, frames.get(from + i), frames.get(to + i)); } } } - protected void clearFrameAttributes(int start, int end, List frames) { + protected void clearFrameAttributes(long snap, int start, int end, + List frames) { for (int i = start; i < end; i++) { TraceObjectStackFrame frame = frames.get(i); - frame.setProgramCounter(frame.computeSpan(), null); + frame.setProgramCounter(Lifespan.nowOn(snap), null); } } @Override - public void setDepth(int depth, boolean atInner) { - // TODO: Need a span parameter + public void setDepth(long snap, int depth, boolean atInner) { try (LockHold hold = object.getTrace().lockWrite()) { - List frames = // Want mutable list - doGetFrames(computeMinSnap()).collect(Collectors.toCollection(ArrayList::new)); + List frames = doGetFrames(snap) + // Want mutable list + .collect(Collectors.toCollection(ArrayList::new)); int curDepth = frames.size(); if (curDepth == depth) { return; @@ -154,35 +152,35 @@ public class DBTraceObjectStack implements TraceObjectStack, DBTraceObjectInterf if (depth < curDepth) { if (atInner) { int diff = curDepth - depth; - shiftFrameAttributes(diff, 0, depth, frames); + shiftFrameAttributes(snap, diff, 0, depth, frames); } for (int i = depth; i < curDepth; i++) { - frames.get(i).getObject().removeTree(computeSpan()); + frames.get(i).getObject().removeTree(Lifespan.nowOn(snap)); } } else { for (int i = curDepth; i < depth; i++) { - frames.add(doAddStackFrame(i)); + frames.add(doAddStackFrame(snap, i)); } if (atInner) { int diff = depth - curDepth; - shiftFrameAttributes(0, diff, curDepth, frames); - clearFrameAttributes(0, diff, frames); + shiftFrameAttributes(snap, 0, diff, curDepth, frames); + clearFrameAttributes(snap, 0, diff, frames); } } } } - protected TraceStackFrame doGetFrame(int level) { + protected TraceStackFrame doGetFrame(long snap, int level) { TraceObjectSchema schema = object.getSchema(); PathFilter filter = schema.searchFor(TraceObjectStackFrame.class, true); PathFilter decFilter = filter.applyKeys(KeyPath.makeIndex(level)); PathFilter hexFilter = filter.applyKeys("0x" + Integer.toHexString(level)); - Lifespan span = computeSpan(); - return object.getSuccessors(span, decFilter) + Lifespan lifespan = Lifespan.at(snap); + return object.getSuccessors(lifespan, decFilter) .findAny() .map(p -> p.getDestination(object).queryInterface(TraceObjectStackFrame.class)) - .or(() -> object.getSuccessors(span, hexFilter) + .or(() -> object.getSuccessors(lifespan, hexFilter) .findAny() .map(p -> p.getDestination(object) .queryInterface(TraceObjectStackFrame.class))) @@ -191,17 +189,17 @@ public class DBTraceObjectStack implements TraceObjectStack, DBTraceObjectInterf @Override // This assumes the frame indices are contiguous and include 0 - public TraceStackFrame getFrame(int level, boolean ensureDepth) { + public TraceStackFrame getFrame(long snap, int level, boolean ensureDepth) { if (ensureDepth) { try (LockHold hold = object.getTrace().lockWrite()) { - if (level >= getDepth()) { - setDepth(level + 1, false); + if (level >= getDepth(snap)) { + setDepth(snap, level + 1, false); } - return doGetFrame(level); + return doGetFrame(snap, level); } } try (LockHold hold = object.getTrace().lockRead()) { - return doGetFrame(level); + return doGetFrame(snap, level); } } @@ -220,10 +218,22 @@ public class DBTraceObjectStack implements TraceObjectStack, DBTraceObjectInterf @Override public void delete() { try (LockHold hold = object.getTrace().lockWrite()) { - object.removeTree(computeSpan()); + object.removeTree(Lifespan.ALL); } } + @Override + public void remove(long snap) { + try (LockHold hold = object.getTrace().lockWrite()) { + object.removeTree(Lifespan.nowOn(snap)); + } + } + + @Override + public boolean isValid(long snap) { + return object.isAlive(snap); + } + @Override public TraceObject getObject() { return object; diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/stack/DBTraceObjectStackFrame.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/stack/DBTraceObjectStackFrame.java index 614ad8ecef..7aa32aee7f 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/stack/DBTraceObjectStackFrame.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/stack/DBTraceObjectStackFrame.java @@ -153,22 +153,6 @@ public class DBTraceObjectStackFrame implements TraceObjectStackFrame, DBTraceOb return true; } - @Override - public Lifespan computeSpan() { - Lifespan span = DBTraceObjectInterface.super.computeSpan(); - if (span != null) { - return span; - } - return getStack().computeSpan(); - } - - protected long snapFor(TraceChangeRecord rec) { - if (rec.getEventType() == TraceEvents.VALUE_CREATED) { - return TraceEvents.VALUE_CREATED.cast(rec).getAffectedObject().getMinSnap(); - } - return computeMinSnap(); - } - protected TraceChangeRecord createChangeRecord() { return new TraceChangeRecord<>(TraceEvents.STACK_CHANGED, null, getStack(), 0L, life.bound().lmin()); diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/stack/DBTraceStack.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/stack/DBTraceStack.java index 4b506230e2..358de95b7e 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/stack/DBTraceStack.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/stack/DBTraceStack.java @@ -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. @@ -146,13 +146,12 @@ public class DBTraceStack extends DBAnnotatedObject implements TraceStack { return thread; } - @Override - public long getSnap() { + long getSnap() { return threadSnap.snap; } @Override - public int getDepth() { + public int getDepth(long snap) { if (frameKeys == null) { return 0; } @@ -175,7 +174,7 @@ public class DBTraceStack extends DBAnnotatedObject implements TraceStack { } @Override - public void setDepth(int depth, boolean atInner) { + public void setDepth(long snap, int depth, boolean atInner) { try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { //System.err.println("setDepth(threadKey=" + thread.getKey() + "snap=" + getSnap() + // ",depth=" + depth + ",inner=" + atInner + ");"); @@ -213,15 +212,15 @@ public class DBTraceStack extends DBAnnotatedObject implements TraceStack { doUpdateFrameKeys(); } manager.trace.setChanged( - new TraceChangeRecord<>(TraceEvents.STACK_CHANGED, null, this, 0L, getSnap())); + new TraceChangeRecord<>(TraceEvents.STACK_CHANGED, null, this, 0L, snap)); } @Override - public DBTraceStackFrame getFrame(int level, boolean ensureDepth) { + public DBTraceStackFrame getFrame(long snap, int level, boolean ensureDepth) { if (ensureDepth) { try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { if (level >= frames.size()) { - setDepth(level + 1, false); + setDepth(snap, level + 1, false); } return frames.get(level); } @@ -254,6 +253,16 @@ public class DBTraceStack extends DBAnnotatedObject implements TraceStack { manager.trace.setChanged(new TraceChangeRecord<>(TraceEvents.STACK_DELETED, null, this)); } + @Override + public void remove(long snap) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isValid(long snap) { + return this == manager.getLatestStack(thread, snap); + } + @Override public boolean hasFixedFrames() { return true; diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/stack/DBTraceStackFrame.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/stack/DBTraceStackFrame.java index 34a0ac6029..3fc45074df 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/stack/DBTraceStackFrame.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/stack/DBTraceStackFrame.java @@ -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. @@ -130,7 +130,7 @@ public class DBTraceStackFrame extends DBAnnotatedObject update(PC_COLUMN); } manager.trace.setChanged( - new TraceChangeRecord<>(TraceEvents.STACK_CHANGED, null, stack, 0L, stack.getSnap())); + new TraceChangeRecord<>(TraceEvents.STACK_CHANGED, null, stack, 0L, span.lmin())); } @Override @@ -145,7 +145,7 @@ public class DBTraceStackFrame extends DBAnnotatedObject update(COMMENT_COLUMN); } manager.trace.setChanged( - new TraceChangeRecord<>(TraceEvents.STACK_CHANGED, null, stack, 0L, stack.getSnap())); + new TraceChangeRecord<>(TraceEvents.STACK_CHANGED, null, stack, 0L, snap)); } @Internal diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceSpace.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceSpace.java index 5d268091b3..1d30e144eb 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceSpace.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceSpace.java @@ -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. @@ -486,7 +486,8 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS // TODO: Verify that this works for emulation TraceMemoryRegion region = trace.getMemoryManager().getRegionContaining(lifespan.lmin(), addr); - return region != null && MemoryBlock.EXTERNAL_BLOCK_NAME.equals(region.getName()); + return region != null && + MemoryBlock.EXTERNAL_BLOCK_NAME.equals(region.getName(lifespan.lmin())); } @Override diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/target/DBTraceObject.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/target/DBTraceObject.java index 3a8d783531..ee33e5c267 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/target/DBTraceObject.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/target/DBTraceObject.java @@ -193,6 +193,16 @@ public class DBTraceObject extends DBAnnotatedObject implements TraceObject { } } + @Override + public boolean isAlive(Lifespan span) { + try (LockHold hold = manager.trace.lockRead()) { + LifeSet result = ensureCachedLife(); + synchronized (result) { + return result.intersects(span); + } + } + } + protected DBTraceObject doCreateCanonicalParentObject() { return manager.doCreateObject(path.parent()); } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/thread/DBTraceObjectThread.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/thread/DBTraceObjectThread.java index 6413d346ed..7bde0a0c08 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/thread/DBTraceObjectThread.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/thread/DBTraceObjectThread.java @@ -27,7 +27,6 @@ import ghidra.trace.model.thread.TraceObjectThread; import ghidra.trace.model.thread.TraceThread; import ghidra.trace.util.*; import ghidra.util.LockHold; -import ghidra.util.exception.DuplicateNameException; public class DBTraceObjectThread implements TraceObjectThread, DBTraceObjectInterface { @@ -103,9 +102,8 @@ public class DBTraceObjectThread implements TraceObjectThread, DBTraceObjectInte } @Override - public String getName() { - return TraceObjectInterfaceUtils.getValue(object, getCreationSnap(), KEY_DISPLAY, - String.class, ""); + public String getName(long snap) { + return TraceObjectInterfaceUtils.getValue(object, snap, KEY_DISPLAY, String.class, ""); } @Override @@ -114,69 +112,46 @@ public class DBTraceObjectThread implements TraceObjectThread, DBTraceObjectInte } @Override - public void setName(String name) { + public void setName(long snap, String name) { try (LockHold hold = object.getTrace().lockWrite()) { - setName(computeSpan(), name); + setName(Lifespan.nowOn(snap), name); } } @Override - public void setCreationSnap(long creationSnap) throws DuplicateNameException { + public void setComment(long snap, String comment) { try (LockHold hold = object.getTrace().lockWrite()) { - setLifespan(Lifespan.span(creationSnap, getDestructionSnap())); + object.setValue(Lifespan.nowOn(snap), KEY_COMMENT, comment); } } @Override - public long getCreationSnap() { - return computeMinSnap(); - } - - @Override - public void setDestructionSnap(long destructionSnap) throws DuplicateNameException { - try (LockHold hold = object.getTrace().lockWrite()) { - setLifespan(Lifespan.span(getCreationSnap(), destructionSnap)); - } - } - - @Override - public long getDestructionSnap() { - return computeMaxSnap(); - } - - @Override - public void setLifespan(Lifespan lifespan) throws DuplicateNameException { - TraceObjectInterfaceUtils.setLifespan(TraceObjectThread.class, object, lifespan); - } - - @Override - public Lifespan getLifespan() { - return computeSpan(); - } - - @Override - public void setComment(String comment) { - try (LockHold hold = object.getTrace().lockWrite()) { - object.setValue(getLifespan(), KEY_COMMENT, comment); - } - } - - @Override - public String getComment() { - return TraceObjectInterfaceUtils.getValue(object, getCreationSnap(), KEY_COMMENT, - String.class, ""); + public String getComment(long snap) { + return TraceObjectInterfaceUtils.getValue(object, snap, KEY_COMMENT, String.class, ""); } @Override public void delete() { try (LockHold hold = object.getTrace().lockWrite()) { - object.removeTree(computeSpan()); + object.removeTree(Lifespan.ALL); + } + } + + @Override + public void remove(long snap) { + try (LockHold hold = object.getTrace().lockWrite()) { + object.removeTree(Lifespan.nowOn(snap)); } } @Override public boolean isValid(long snap) { - return object.getCanonicalParent(snap) != null; + return object.isAlive(snap); + } + + @Override + public boolean isAlive(Lifespan span) { + return object.isAlive(span); } @Override diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/thread/DBTraceThread.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/thread/DBTraceThread.java index 24fb33238a..2e715beded 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/thread/DBTraceThread.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/thread/DBTraceThread.java @@ -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. @@ -26,7 +26,6 @@ import ghidra.trace.util.TraceEvents; import ghidra.util.LockHold; import ghidra.util.database.*; import ghidra.util.database.annot.*; -import ghidra.util.exception.DuplicateNameException; @DBAnnotatedObjectInfo(version = 0) public class DBTraceThread extends DBAnnotatedObject implements TraceThread { @@ -90,7 +89,15 @@ public class DBTraceThread extends DBAnnotatedObject implements TraceThread { @Override public String toString() { - return "TraceThread: " + getName(); + return "TraceThread: " + getName(0); + } + + protected void doSetLifespan(Lifespan lifespan) { + this.creationSnap = lifespan.lmin(); + this.destructionSnap = lifespan.lmax(); + update(CREATION_SNAP_COLUMN, DESTRUCTION_SNAP_COLUMN); + + this.lifespan = lifespan; } @Override @@ -106,14 +113,14 @@ public class DBTraceThread extends DBAnnotatedObject implements TraceThread { } @Override - public String getName() { + public String getName(long snap) { try (LockHold hold = LockHold.lock(manager.lock.readLock())) { return name; } } @Override - public void setName(String name) { + public void setName(long snap, String name) { try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { this.name = name; update(NAME_COLUMN); @@ -123,50 +130,7 @@ public class DBTraceThread extends DBAnnotatedObject implements TraceThread { } @Override - public void setCreationSnap(long creationSnap) throws DuplicateNameException { - setLifespan(Lifespan.span(creationSnap, destructionSnap)); - } - - @Override - public long getCreationSnap() { - try (LockHold hold = LockHold.lock(manager.lock.readLock())) { - return creationSnap; - } - } - - @Override - public void setDestructionSnap(long destructionSnap) throws DuplicateNameException { - setLifespan(Lifespan.span(creationSnap, destructionSnap)); - } - - @Override - public long getDestructionSnap() { - return destructionSnap; - } - - @Override - public void setLifespan(Lifespan newLifespan) throws DuplicateNameException { - try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { - manager.checkConflictingPath(this, path, newLifespan); - Lifespan oldLifespan = this.lifespan; - this.creationSnap = newLifespan.lmin(); - this.destructionSnap = newLifespan.lmax(); - update(CREATION_SNAP_COLUMN, DESTRUCTION_SNAP_COLUMN); - - this.lifespan = newLifespan; - - manager.trace.setChanged(new TraceChangeRecord<>(TraceEvents.THREAD_LIFESPAN_CHANGED, - null, this, oldLifespan, newLifespan)); - } - } - - @Override - public Lifespan getLifespan() { - return lifespan; - } - - @Override - public void setComment(String comment) { + public void setComment(long snap, String comment) { try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { this.comment = comment; update(COMMENT_COLUMN); @@ -176,7 +140,7 @@ public class DBTraceThread extends DBAnnotatedObject implements TraceThread { } @Override - public String getComment() { + public String getComment(long snap) { return comment; } @@ -185,10 +149,29 @@ public class DBTraceThread extends DBAnnotatedObject implements TraceThread { manager.deleteThread(this); } + @Override + public void remove(long snap) { + try (LockHold hold = LockHold.lock(manager.lock.writeLock())) { + if (snap <= lifespan.lmin()) { + manager.deleteThread(this); + } + else if (snap <= lifespan.lmax()) { + doSetLifespan(lifespan.withMax(snap - 1)); + } + } + } + @Override public boolean isValid(long snap) { try (LockHold hold = LockHold.lock(manager.lock.readLock())) { return lifespan.contains(snap); } } + + @Override + public boolean isAlive(Lifespan span) { + try (LockHold hold = LockHold.lock(manager.lock.readLock())) { + return lifespan.intersects(span); + } + } } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/thread/DBTraceThreadManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/thread/DBTraceThreadManager.java index 588a755f71..0ba940b0cd 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/thread/DBTraceThreadManager.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/thread/DBTraceThreadManager.java @@ -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. @@ -96,7 +96,7 @@ public class DBTraceThreadManager implements TraceThreadManager, DBTraceManager if (pc == ignore) { continue; } - if (!pc.getLifespan().intersects(lifespan)) { + if (!pc.isAlive(lifespan)) { continue; } throw new DuplicateNameException( @@ -149,7 +149,7 @@ public class DBTraceThreadManager implements TraceThreadManager, DBTraceManager try (LockHold hold = LockHold.lock(lock.readLock())) { return threadsByPath.get(path) .stream() - .filter(t -> t.getLifespan().contains(snap)) + .filter(t -> t.isValid(snap)) .findAny() .orElse(null); } @@ -169,9 +169,6 @@ public class DBTraceThreadManager implements TraceThreadManager, DBTraceManager if (objectManager.hasSchema()) { try (LockHold hold = LockHold.lock(lock.readLock())) { return objectManager.queryAllInterface(Lifespan.at(snap), TraceObjectThread.class) - // Exclude the destruction - .filter(thread -> thread.getCreationSnap() <= snap && - snap < thread.getDestructionSnap()) .collect(Collectors.toSet()); } } @@ -180,7 +177,7 @@ public class DBTraceThreadManager implements TraceThreadManager, DBTraceManager Collection result = new LinkedHashSet<>(); for (DBTraceThread thread : threadStore.asMap().values()) { // Don't use .getLifespan().contains(snap). Exclude the destruction. - if (thread.getCreationSnap() <= snap && snap < thread.getDestructionSnap()) { + if (thread.isValid(snap)) { result.add(thread); } } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/DefaultTraceLocation.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/DefaultTraceLocation.java index 7b2a9541e7..a39275c0c2 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/DefaultTraceLocation.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/DefaultTraceLocation.java @@ -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. @@ -98,7 +98,8 @@ public class DefaultTraceLocation implements TraceLocation { if (result != 0) { return result; } - result = this.thread.getName().compareTo(that.getThread().getName()); + result = this.thread.getName(lifespan.lmin()) + .compareTo(that.getThread().getName(lifespan.lmin())); if (result != 0) { return result; } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/TraceTimeViewport.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/TraceTimeViewport.java index b93a249aa4..5c1796d5c1 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/TraceTimeViewport.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/TraceTimeViewport.java @@ -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,7 +38,7 @@ public interface TraceTimeViewport { if (found == object) { continue; } - if (itemOccludes(range, found)) { + if (itemOccludes(range, found, span.lmax())) { return true; } } @@ -53,7 +53,7 @@ public interface TraceTimeViewport { if (found == object) { continue; } - removeItem(remains, found); + removeItem(remains, found, span.lmax()); if (remains.isEmpty()) { return; } @@ -62,34 +62,34 @@ public interface TraceTimeViewport { Iterable query(AddressRange range, Lifespan span); - boolean itemOccludes(AddressRange range, T t); + boolean itemOccludes(AddressRange range, T t, long snap); - void removeItem(AddressSet remains, T t); + void removeItem(AddressSet remains, T t, long snap); } public interface RangeQueryOcclusion extends QueryOcclusion { @Override - default boolean itemOccludes(AddressRange range, T t) { - return range(t).intersects(range); + default boolean itemOccludes(AddressRange range, T t, long snap) { + return range(t, snap).intersects(range); } @Override - default void removeItem(AddressSet remains, T t) { - remains.delete(range(t)); + default void removeItem(AddressSet remains, T t, long snap) { + remains.delete(range(t, snap)); } - AddressRange range(T t); + AddressRange range(T t, long snap); } public interface SetQueryOcclusion extends QueryOcclusion { @Override - default boolean itemOccludes(AddressRange range, T t) { - return set(t).intersects(range.getMinAddress(), range.getMaxAddress()); + default boolean itemOccludes(AddressRange range, T t, long snap) { + return set(t, snap).intersects(range.getMinAddress(), range.getMaxAddress()); } @Override - default void removeItem(AddressSet remains, T t) { - for (AddressRange range : set(t)) { + default void removeItem(AddressSet remains, T t, long snap) { + for (AddressRange range : set(t, snap)) { remains.delete(range); if (remains.isEmpty()) { return; @@ -97,7 +97,7 @@ public interface TraceTimeViewport { } } - AddressSetView set(T t); + AddressSetView set(T t, long snap); } /** @@ -171,9 +171,20 @@ public interface TraceTimeViewport { AddressSet computeVisibleParts(AddressSetView set, Lifespan lifespan, T object, Occlusion occlusion); - + /** + * Get the spans involved in the view in most-recent-first order + * + * @return the list of spans + */ List getOrderedSpans(); - + + /** + * Get the spans involved in the view in least-recent-first order + * + * @return the list of spans + */ + List getReversedSpans(); + /** * Get the snaps involved in the view in most-recent-first order * diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/breakpoint/TraceBreakpoint.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/breakpoint/TraceBreakpoint.java index 9ce422145b..90cb2d3a26 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/breakpoint/TraceBreakpoint.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/breakpoint/TraceBreakpoint.java @@ -23,9 +23,7 @@ import ghidra.pcode.exec.SleighUtils; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressRange; import ghidra.trace.model.*; -import ghidra.trace.model.target.TraceObjectValue; import ghidra.trace.model.thread.TraceThread; -import ghidra.util.exception.DuplicateNameException; /** * A breakpoint in a trace @@ -55,19 +53,21 @@ public interface TraceBreakpoint extends TraceUniqueObject { *

* This should be a name suitable for display on the screen * + * @param snap the first effective snap * @param name the new name */ - void setName(String name); + void setName(long snap, String name); /** * Get the "short name" of this breakpoint * *

- * This defaults to the "full name," but can be modified via {@link #setName(String)} + * This defaults to the "full name," but can be modified via {@link #setName(long, String)} * + * @param snap the snap * @return the name */ - String getName(); + String getName(long snap); /** * Get the range covered by this breakpoint @@ -75,111 +75,44 @@ public interface TraceBreakpoint extends TraceUniqueObject { *

* Most often, esp. for execution breakpoints, this is a single address. * + * @param snap the snap * @return the range */ - AddressRange getRange(); + AddressRange getRange(long snap); /** * Get the minimum address in this breakpoint's range * - * @see #getRange() + * @see #getRange(long) + * @param snap the snap * @return the minimum address */ - Address getMinAddress(); + Address getMinAddress(long snap); /** * Get the maximum address in this breakpoint's range * - * @see #getRange() + * @see #getRange(long) + * @param snap the snap * @return the maximum address */ - Address getMaxAddress(); + Address getMaxAddress(long snap); /** * Get the length of this breakpoint, usually 1 * + * @param snap the snap * @return the length */ - long getLength(); - - /** - * Get the lifespan of this breakpoint - * - * @return the lifespan - * @deprecated Either this method no longer makes sense, or we need to wrap a - * {@link TraceObjectValue} instead. Even then, the attribute values can vary over - * the lifespan. - */ - @Deprecated(since = "11.3", forRemoval = true) - Lifespan getLifespan(); - - /** - * Check if the breakpoint is present at the given snap - * - * @param snap the snap - * @return true if alive, false if not - */ - boolean isAlive(long snap); - - /** - * Get the placed snap of this breakpoint - * - * @return the placed snap, or {@link Long#MIN_VALUE} for "since the beginning of time" - */ - long getPlacedSnap(); - - /** - * Set the cleared snap of this breakpoint - * - * @param clearedSnap the cleared snap, or {@link Long#MAX_VALUE} for "to the end of time" - * @throws DuplicateNameException if extending the lifespan would cause a naming collision - */ - void setClearedSnap(long clearedSnap) throws DuplicateNameException; - - /** - * Get the cleared snap of this breakpoint - * - * @return the cleared snap, or {@link Long#MAX_VALUE} for "to the end of time" - */ - long getClearedSnap(); - - /** - * Split this breakpoint at the given snap, and set the later's fields. - * - *

- * This breakpoint's lifespan must contain the given snap. This method first creates a copy of - * this breakpoint, replacing the copy's placed snap and additional fields. Then, it sets this - * breakpoint's cleared snap to one less than the given snap, so that the two breakpoints do not - * overlap. - * - *

- * Note the following special cases: 1) If the given snap is equal to the placed snap, this - * method simply sets the fields on this breakpoint and returns this. 2) If the field values - * indicate no change, this method does nothing and returns this breakpoint. - * - * @implNote Listeners on breakpoint changes will see the added record before the lifespan - * change of the old record, despite those two records having the same path and - * overlapping in time. This makes it easier for such listeners to distinguish such - * splits from a breakpoint being cleared. - * - * @param snap the placed snap for the later breakpoint - * @param enabled true if the later breakpoint is enabled, false if disabled - * @param kinds the kinds of the later breakpoint - * @return the new breakpoint, or this breakpoint (see special case) - */ - TraceBreakpoint splitAndSet(long snap, boolean enabled, Collection kinds); + long getLength(long snap); /** * Set whether this breakpoint was enabled or disabled * - *

- * This change applies to the entire lifespan of this record. If a breakpoint is enabled for - * some duration and then later disabled, this breakpoint should be split instead. See - * {@link #splitAndSet(long,boolean, Collection)}. - * + * @param snap the first effective snap * @param enabled true if enabled, false if disabled */ - void setEnabled(boolean enabled); + void setEnabled(long snap, boolean enabled); /** * Check whether this breakpoint is enabled or disabled at the given snap @@ -192,13 +125,10 @@ public interface TraceBreakpoint extends TraceUniqueObject { /** * Set whether this breakpoint is enabled or disabled for emulation * - *

- * This change applies to the entire lifespan of the record. It's not intended to record a - * history, but to toggle the breakpoint in the integrated emulator. - * + * @param snap the snap * @param enabled true if enabled, false if disabled */ - void setEmuEnabled(boolean enabled); + void setEmuEnabled(long snap, boolean enabled); /** * Check whether this breakpoint is enabled or disabled for emulation at the given snap @@ -212,14 +142,14 @@ public interface TraceBreakpoint extends TraceUniqueObject { * Set the kinds included in this breakpoint * *

- * See {@link #getKinds()}. Note that it is unusual for a breakpoint to change kinds during its - * life. Nevertheless, in the course of recording a trace, it may happen, or at least appear to - * happen. Rather than require the client to delete and re-create the breakpoint, this allows - * the record to be updated. See also {@link #splitAndSet(long, boolean, Collection)}. + * See {@link #getKinds(long)}. Note that it is unusual for a breakpoint to change kinds during + * its life. Nevertheless, in the course of recording a trace, it may happen, or at least appear + * to happen. * + * @param snap the snap * @param kinds the set of kinds */ - void setKinds(Collection kinds); + void setKinds(long snap, Collection kinds); /** * Get the kinds included in this breakpoint @@ -228,9 +158,10 @@ public interface TraceBreakpoint extends TraceUniqueObject { * For example, an "access breakpoint" or "access watchpoint," depending on terminology, would * include both {@link TraceBreakpointKind#READ} and {@link TraceBreakpointKind#WRITE}. * + * @param snap the snap * @return the set of kinds */ - Set getKinds(); + Set getKinds(long snap); /** * Get the set of threads to which this breakpoint's application is limited @@ -238,23 +169,26 @@ public interface TraceBreakpoint extends TraceUniqueObject { *

* Note, an empty set here implies all contemporary live threads, i.e., the process. * + * @param snap the snap * @return the (possibly empty) set of affected threads */ - Set getThreads(); + Set getThreads(long snap); /** * Set a comment on this breakpoint * + * @param snap the snap * @param comment the comment, possibly {@code null} */ - void setComment(String comment); + void setComment(long snap, String comment); /** * Get the comment on this breakpoint * + * @param snap the snap * @return the comment, possibly {@code null} */ - String getComment(); + String getComment(long snap); /** * Set Sleigh source to replace the breakpointed instruction in emulation @@ -281,16 +215,25 @@ public interface TraceBreakpoint extends TraceUniqueObject { * {@link PcodeEmulationLibrary#emu_swi()} * * @see SleighUtils#UNCONDITIONAL_BREAK + * @param snap the snap * @param sleigh the Sleigh source */ - void setEmuSleigh(String sleigh); + void setEmuSleigh(long snap, String sleigh); /** * Get the Sleigh source that replaces the breakpointed instruction in emulation * + * @param snap the snap * @return the Sleigh source */ - String getEmuSleigh(); + String getEmuSleigh(long snap); + + /** + * Remove this breakpoint from the given snap on + * + * @param snap the snap + */ + void remove(long snap); /** * Delete this breakpoint from the trace @@ -298,7 +241,7 @@ public interface TraceBreakpoint extends TraceUniqueObject { void delete(); /** - * Check if the breakpoint is valid at the given snapshot + * Check if the breakpoint is present at the given snapshot * *

* In object mode, a breakpoint's life may be disjoint, so checking if the snap occurs between @@ -310,4 +253,12 @@ public interface TraceBreakpoint extends TraceUniqueObject { * @return true if valid, false if not */ boolean isValid(long snap); + + /** + * Check if the breakpoint is present for any of the given span + * + * @param span the span + * @return true if its life intersects the span + */ + boolean isAlive(Lifespan span); } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/breakpoint/TraceObjectBreakpointLocation.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/breakpoint/TraceObjectBreakpointLocation.java index b4656cf1e8..ba0324b666 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/breakpoint/TraceObjectBreakpointLocation.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/breakpoint/TraceObjectBreakpointLocation.java @@ -21,7 +21,6 @@ import ghidra.program.model.address.AddressRange; import ghidra.trace.model.Lifespan; import ghidra.trace.model.target.iface.TraceObjectInterface; import ghidra.trace.model.target.info.TraceObjectInfo; -import ghidra.util.exception.DuplicateNameException; @TraceObjectInfo( schemaName = "BreakpointLocation", @@ -41,8 +40,6 @@ public interface TraceObjectBreakpointLocation extends TraceBreakpoint, TraceObj TraceObjectBreakpointSpec getSpecification(); - void setLifespan(Lifespan lifespan) throws DuplicateNameException; - void setRange(Lifespan lifespan, AddressRange range); void setName(Lifespan lifespan, String name); diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/breakpoint/TraceObjectBreakpointSpec.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/breakpoint/TraceObjectBreakpointSpec.java index c1da2b60b5..e2d40cf47f 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/breakpoint/TraceObjectBreakpointSpec.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/breakpoint/TraceObjectBreakpointSpec.java @@ -20,7 +20,6 @@ import java.util.Collection; import ghidra.trace.model.Lifespan; import ghidra.trace.model.target.iface.TraceObjectInterface; import ghidra.trace.model.target.info.TraceObjectInfo; -import ghidra.util.exception.DuplicateNameException; /** * The specification of a breakpoint applied to a target object @@ -65,11 +64,9 @@ public interface TraceObjectBreakpointSpec extends TraceBreakpoint, TraceObjectI // TODO: Make command list part of the common interface? // TODO: Make condition part of the common interface? - void setLifespan(Lifespan lifespan) throws DuplicateNameException; + Collection getLocations(long snap); - Collection getLocations(); - - String getExpression(); + String getExpression(long snap); void setKinds(Lifespan lifespan, Collection kinds); } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/memory/TraceMemoryRegion.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/memory/TraceMemoryRegion.java index 4079445e72..bce6baa355 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/memory/TraceMemoryRegion.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/memory/TraceMemoryRegion.java @@ -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,8 +18,8 @@ package ghidra.trace.model.memory; import java.util.*; import ghidra.program.model.address.*; -import ghidra.trace.model.*; -import ghidra.util.exception.DuplicateNameException; +import ghidra.trace.model.Trace; +import ghidra.trace.model.TraceUniqueObject; /** * A region of mapped target memory in a trace @@ -50,77 +50,21 @@ public interface TraceMemoryRegion extends TraceUniqueObject { *

* The given name should be suitable for display on the screen. * + * @param snap the snap * @param name the name */ - void setName(String name); + void setName(long snap, String name); /** * Get the "short name" of this region * *

- * This defaults to the "full name," but can be modified via {@link #setName(String)} + * This defaults to the "full name," but can be modified via {@link #setName(long, String)} * + * @param snap the snap * @return the name */ - String getName(); - - /** - * Change the lifespan of this region - * - * @param lifespan the new lifespan - * @throws TraceOverlappedRegionException if the specified lifespan would cause this region to - * overlap another - * @throws DuplicateNameException if the specified lifespan would cause the full name of this - * region to conflict with that of another whose lifespan would intersects this - * region's - */ - void setLifespan(Lifespan lifespan) - throws TraceOverlappedRegionException, DuplicateNameException; - - /** - * Get the lifespan of this region - * - * @return the lifespan - */ - Lifespan getLifespan(); - - /** - * @see #setLifespan(Lifespan) - * - * @param creationSnap the creation snap, or {@link Long#MIN_VALUE} for "since the beginning of - * time" - * @throws DuplicateNameException if extending the region would cause a naming conflict - * @throws TraceOverlappedRegionException if extending the region would cause it to overlap - * another - */ - void setCreationSnap(long creationSnap) - throws DuplicateNameException, TraceOverlappedRegionException; - - /** - * Get the creation snap of this region - * - * @return the creation snap, or {@link Long#MIN_VALUE} for "since the beginning of time" - */ - long getCreationSnap(); - - /** - * @see #setLifespan(Lifespan) - * - * @param destructionSnap the destruction snap, or {@link Long#MAX_VALUE} for "to the end of - * time" - * @throws DuplicateNameException if extending the region would cause a naming conflict - * @throws TraceOverlappedRegionException if extending the region would cause it to overlap - * another - */ - void setDestructionSnap(long destructionSnap) - throws DuplicateNameException, TraceOverlappedRegionException; - - /** - * @see #getLifespan() - * - * @return the destruction snap, or {@link Long#MAX_VALUE} for "to the end of time" - */ - long getDestructionSnap(); + String getName(long snap); /** * Set the virtual memory address range of this region @@ -130,222 +74,256 @@ public interface TraceMemoryRegion extends TraceUniqueObject { * i.e., the virtual memory address if an MMU is involved, or the physical address if no MMU is * involved. * + * @param snap the snap * @param range the address range * @throws TraceOverlappedRegionException if the specified range would cause this region to * overlap another */ - void setRange(AddressRange range) throws TraceOverlappedRegionException; + void setRange(long snap, AddressRange range) throws TraceOverlappedRegionException; /** * Get the virtual memory address range of this region * + * @param snap the snap * @return the address range */ - AddressRange getRange(); + AddressRange getRange(long snap); /** * Set the minimum address of the range * - * @see #setRange(AddressRange) + *

+ * Note that this sets the range from the given snap on to the same range, no matter what + * changes may have occurred since. + * + * @see #setRange(long, AddressRange) + * @param snap the snap * @param min the new minimum * @throws TraceOverlappedRegionException if extending the region would cause it to overlap * another */ - void setMinAddress(Address min) throws TraceOverlappedRegionException; + void setMinAddress(long snap, Address min) throws TraceOverlappedRegionException; /** * Get the minimum address of the range * - * @see #getRange() + * @see #getRange(long) + * @param snap the snap * @return the minimum address */ - Address getMinAddress(); + Address getMinAddress(long snap); /** * Set the maximum address of the range * - * @see #setRange(AddressRange) + *

+ * Note that this sets the range from the given snap on to the same range, no matter what + * changes may have occurred since. + * + * @see #setRange(long, AddressRange) + * @param snap the snap * @param max the new minimum * @throws TraceOverlappedRegionException if extending the region would cause it to overlap * another */ - void setMaxAddress(Address max) throws TraceOverlappedRegionException; + void setMaxAddress(long snap, Address max) throws TraceOverlappedRegionException; /** * Get the maximum address of the range * - * @see #getRange() + * @see #getRange(long) + * @param snap the snap * @return the maximum address */ - Address getMaxAddress(); + Address getMaxAddress(long snap); /** * Set the length, in bytes, of this region's address range * *

- * This adjusts the max address of the range so that its length becomes that given + * This adjusts the max address of the range so that its length becomes that given. Note that + * this sets the range from the given snap on to the same range, no matter what changes may have + * occurred since. * - * @see #setRange(AddressRange) + * @see #setRange(long, AddressRange) + * @param snap the snap * @param length the desired length of the range * @throws AddressOverflowException if extending the range would cause the max address to * overflow * @throws TraceOverlappedRegionException if extending the region would cause it to overlap * another */ - void setLength(long length) throws AddressOverflowException, TraceOverlappedRegionException; + void setLength(long snap, long length) + throws AddressOverflowException, TraceOverlappedRegionException; /** * Measure the length, in bytes, of this region's address range * + * @param snap the snap * @return the length */ - long getLength(); + long getLength(long snap); /** * Set the flags, e.g., permissions, of this region * + * @param snap the snap * @param flags the flags */ - void setFlags(Collection flags); + void setFlags(long snap, Collection flags); /** * Set the flags, e.g., permissions, of this region * + * @param snap the snap * @param flags the flags */ - default void setFlags(TraceMemoryFlag... flags) { - setFlags(Arrays.asList(flags)); + default void setFlags(long snap, TraceMemoryFlag... flags) { + setFlags(snap, Arrays.asList(flags)); } /** * Add the given flags, e.g., permissions, to this region * + * @param snap the snap * @param flags the flags */ - void addFlags(Collection flags); + void addFlags(long snap, Collection flags); /** * Add the given flags, e.g., permissions, to this region * + * @param snap the snap * @param flags the flags */ - default void addFlags(TraceMemoryFlag... flags) { - addFlags(Arrays.asList(flags)); + default void addFlags(long snap, TraceMemoryFlag... flags) { + addFlags(snap, Arrays.asList(flags)); } /** * Remove the given flags, e.g., permissions, from this region * + * @param snap the snap * @param flags the flags */ - void clearFlags(Collection flags); + void clearFlags(long snap, Collection flags); /** * Remove the given flags, e.g., permissions, from this region * + * @param snap the snap * @param flags the flags */ - default void clearFlags(TraceMemoryFlag... flags) { - clearFlags(Arrays.asList(flags)); + default void clearFlags(long snap, TraceMemoryFlag... flags) { + clearFlags(snap, Arrays.asList(flags)); } /** * Get the flags, e.g., permissions, of this region * + * @param snap the snap * @return the flags */ - Set getFlags(); + Set getFlags(long snap); /** * Add or clear the {@link TraceMemoryFlag#READ} flag * + * @param snap the snap * @param read true to add, false to clear */ - default void setRead(boolean read) { + default void setRead(long snap, boolean read) { if (read) { - addFlags(TraceMemoryFlag.READ); + addFlags(snap, TraceMemoryFlag.READ); } else { - clearFlags(TraceMemoryFlag.READ); + clearFlags(snap, TraceMemoryFlag.READ); } } /** * Check if the {@link TraceMemoryFlag#READ} flag is present * + * @param snap the snap * @return true if present, false if absent */ - default boolean isRead() { - return getFlags().contains(TraceMemoryFlag.READ); + default boolean isRead(long snap) { + return getFlags(snap).contains(TraceMemoryFlag.READ); } /** * Add or clear the {@link TraceMemoryFlag#WRITE} flag * + * @param snap the snap * @param write true to add, false to clear */ - default void setWrite(boolean write) { + default void setWrite(long snap, boolean write) { if (write) { - addFlags(TraceMemoryFlag.WRITE); + addFlags(snap, TraceMemoryFlag.WRITE); } else { - clearFlags(TraceMemoryFlag.WRITE); + clearFlags(snap, TraceMemoryFlag.WRITE); } } /** * Check if the {@link TraceMemoryFlag#WRITE} flag is present * + * @param snap the snap * @return true if present, false if absent */ - default boolean isWrite() { - return getFlags().contains(TraceMemoryFlag.WRITE); + default boolean isWrite(long snap) { + return getFlags(snap).contains(TraceMemoryFlag.WRITE); } /** * Add or clear the {@link TraceMemoryFlag#EXECUTE} flag * + * @param snap the snap * @param execute true to add, false to clear */ - default void setExecute(boolean execute) { + default void setExecute(long snap, boolean execute) { if (execute) { - addFlags(TraceMemoryFlag.EXECUTE); + addFlags(snap, TraceMemoryFlag.EXECUTE); } else { - clearFlags(TraceMemoryFlag.EXECUTE); + clearFlags(snap, TraceMemoryFlag.EXECUTE); } } /** * Check if the {@link TraceMemoryFlag#EXECUTE} flag is present * + * @param snap the snap * @return true if present, false if absent */ - default boolean isExecute() { - return getFlags().contains(TraceMemoryFlag.EXECUTE); + default boolean isExecute(long snap) { + return getFlags(snap).contains(TraceMemoryFlag.EXECUTE); } /** * Add or clear the {@link TraceMemoryFlag#VOLATILE} flag * + * @param snap the snap * @param vol true to add, false to clear */ - default void setVolatile(boolean vol) { + default void setVolatile(long snap, boolean vol) { if (vol) { - addFlags(TraceMemoryFlag.VOLATILE); + addFlags(snap, TraceMemoryFlag.VOLATILE); } else { - clearFlags(TraceMemoryFlag.VOLATILE); + clearFlags(snap, TraceMemoryFlag.VOLATILE); } } /** * Check if the {@link TraceMemoryFlag#VOLATILE} flag is present * + * @param snap the snap * @return true if present, false if absent */ - default boolean isVolatile() { - return getFlags().contains(TraceMemoryFlag.VOLATILE); + default boolean isVolatile(long snap) { + return getFlags(snap).contains(TraceMemoryFlag.VOLATILE); } /** @@ -353,6 +331,13 @@ public interface TraceMemoryRegion extends TraceUniqueObject { */ void delete(); + /** + * Remove this region from the given snap on + * + * @param snap + */ + void remove(long snap); + /** * Check if the region is valid at the given snapshot * diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/memory/TraceObjectRegister.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/memory/TraceObjectRegister.java index cfef708384..c1a71d63f7 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/memory/TraceObjectRegister.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/memory/TraceObjectRegister.java @@ -73,10 +73,10 @@ public interface TraceObjectRegister extends TraceObjectInterface { String getName(); - int getBitLength(); + int getBitLength(long snap); - default int getByteLength() { - return (getBitLength() + 7) / 8; + default int getByteLength(long snap) { + return (getBitLength(snap) + 7) / 8; } void setValue(Lifespan lifespan, byte[] value); diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/modules/TraceModule.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/modules/TraceModule.java index 8451e42101..9583441b9e 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/modules/TraceModule.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/modules/TraceModule.java @@ -47,27 +47,29 @@ public interface TraceModule extends TraceUniqueObject { * Furthermore, any overlapped mappings to static modules, which are usually derived from * sections stored here, must agree on the address adjustment. * + * @param snap the "load" snap of the module * @param sectionPath the "full name" of the section * @param sectionName the "short name" of the section * @param range the range of memory into which the section is loaded * @return the new section * @throws DuplicateNameException if a section with the given name already exists in this module */ - TraceSection addSection(String sectionPath, String sectionName, AddressRange range) + TraceSection addSection(long snap, String sectionPath, String sectionName, AddressRange range) throws DuplicateNameException; /** * Add a section having the same full and short names * - * @see #addSection(String, String, AddressRange) + * @see #addSection(long, String, String, AddressRange) + * @param snap the "load" snap of the module * @param sectionPath the "full name" of the section * @param range the range of memory into which the section is loaded * @return the new section * @throws DuplicateNameException if a section with the given name already exists in this module */ - default TraceSection addSection(String sectionPath, AddressRange range) + default TraceSection addSection(long snap, String sectionPath, AddressRange range) throws DuplicateNameException { - return addSection(sectionPath, sectionPath, range); + return addSection(snap, sectionPath, sectionPath, range); } /** @@ -89,19 +91,21 @@ public interface TraceModule extends TraceUniqueObject { * The given name is typically the file system path of the module's image, which is considered * suitable for display on the screen. * + * @param snap the snap * @param name the name */ - void setName(String name); + void setName(long snap, String name); /** * Get the "short name" of this module * *

- * This defaults to the "full name," but can be modified via {@link #setName(String)} + * This defaults to the "full name," but can be modified via {@link #setName(long, String)} * + * @param snap the snap * @return the name */ - String getName(); + String getName(long snap); /** * Set the address range of the module @@ -110,17 +114,19 @@ public interface TraceModule extends TraceUniqueObject { * Typically, the minimum address in this range is the module's base address. If sections are * given, this range should enclose all sections mapped into memory. * + * @param snap the snap * @param range the address range. */ - void setRange(AddressRange range); + void setRange(long snap, AddressRange range); /** * Get the address range of the module * - * @see #setRange(AddressRange) + * @see #setRange(long, AddressRange) + * @param snap the snap * @return the address range */ - AddressRange getRange(); + AddressRange getRange(long snap); /** * Set the base (usually minimum) address of the module @@ -130,117 +136,118 @@ public interface TraceModule extends TraceUniqueObject { * it from whatever information is provided. In general, this should be the virtual memory * address mapped to file offset 0 of the module's image. * + *

+ * Note that this sets the range from the given snap on to the same range, no matter what + * changes may have occurred since. + * + * @param snap the snap * @param base the base address */ - void setBase(Address base); + void setBase(long snap, Address base); /** * Get the base address of the module * + * @param snap the snap * @return the base address */ - Address getBase(); + Address getBase(long snap); /** * Set the maximum address of the module * - * @see #setRange(AddressRange) + *

+ * Note that this sets the range from the given snap on to the same range, no matter what + * changes may have occurred since. + * + * @see #setRange(long, AddressRange) + * @param snap the snap * @param max the maximum address */ - void setMaxAddress(Address max); + void setMaxAddress(long snap, Address max); /** * Get the maximum address of the module * - * @see #setRange(AddressRange) + * @see #setRange(long, AddressRange) + * @param snap the snap * @return the maximum address */ - Address getMaxAddress(); + Address getMaxAddress(long snap); /** * Set the length of the range of the module * - * @see #setRange(AddressRange) + *

+ * This adjusts the max address of the range so that its length becomes that given. Note that + * this sets the range from the given snap on to the same range, no matter what changes may have + * occurred since. + * + * @see #setRange(long, AddressRange) + * @param snap the snap * @param length the length * @throws AddressOverflowException if the length would cause the max address to overflow */ - void setLength(long length) throws AddressOverflowException; + void setLength(long snap, long length) throws AddressOverflowException; /** * Get the length of the range of the module * - * @see #setRange(AddressRange) + * @see #setRange(long, AddressRange) + * @param snap the snap * @return the length */ - long getLength(); + long getLength(long snap); /** - * Set the lifespan of this module + * Collect all sections contained within this module at the given snap * - * @param lifespan the lifespan - * @throws DuplicateNameException if the specified lifespan would cause the full name of this - * module or one of its sections to conflict with that of another whose lifespan - * would intersect this module's + * @param snap the snap + * @return the collection of sections */ - void setLifespan(Lifespan lifespan) throws DuplicateNameException; + Collection getSections(long snap); /** - * Get the lifespan of this module - * - * @return the lifespan - */ - Lifespan getLifespan(); - - /** - * @see #setLifespan(Lifespan) - * - * @param loadedSnap the loaded snap, or {@link Long#MIN_VALUE} for "since the beginning of - * time" - * @throws DuplicateNameException if the lifespan adjustment would cause it to collide with - * another module with the same name - */ - void setLoadedSnap(long loadedSnap) throws DuplicateNameException; - - /** - * Get the loaded snap of this module - * - * @return the loaded snap, or {@link Long#MIN_VALUE} for "since the beginning of time" - */ - long getLoadedSnap(); - - /** - * @see #setLifespan(Lifespan) - * - * @param unloadedSnap the unloaded snap, or {@link Long#MAX_VALUE} for "to the end of time" - * @throws DuplicateNameException if the lifespan adjustment would cause it to collide with - * another module with the same name - */ - void setUnloadedSnap(long unloadedSnap) throws DuplicateNameException; - - /** - * Get the unloaded snap of this module - * - * @return the unloaded snap, or {@link Long#MAX_VALUE} for "to the end of time" - */ - long getUnloadedSnap(); - - /** - * Collect all sections contained within this module + * Collect all sections contained within this module at any time * * @return the collection of sections */ - Collection getSections(); + Collection getAllSections(); /** * Get the section in this module having the given short name * + * @param snap the snap * @param sectionName the name * @return the section, or {@code null} if no section has the given name */ - TraceSection getSectionByName(String sectionName); + TraceSection getSectionByName(long snap, String sectionName); /** * Delete this module and its sections from the trace */ void delete(); + + /** + * Remove this module from the given snap on + * + * @param snap the snap + */ + void remove(long snap); + + /** + * Check if the module is valid at the given snapshot + * + * @param snap the snapshot key + * @return true if valid, false if not + */ + boolean isValid(long snap); + + /** + * Check if the module is alive for any of the given span + * + * @param span the span + * @return true if its life intersects the span + */ + boolean isAlive(Lifespan span); } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/modules/TraceObjectModule.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/modules/TraceObjectModule.java index c291d4a358..cc4f171359 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/modules/TraceObjectModule.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/modules/TraceObjectModule.java @@ -50,8 +50,8 @@ public interface TraceObjectModule extends TraceModule, TraceObjectInterface { void setRange(Lifespan lifespan, AddressRange range); @Override - Collection getSections(); + Collection getSections(long snap); @Override - TraceObjectSection getSectionByName(String sectionName); + TraceObjectSection getSectionByName(long snap, String sectionName); } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/modules/TraceSection.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/modules/TraceSection.java index 7ca7b4d4ac..492cf3bf7f 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/modules/TraceSection.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/modules/TraceSection.java @@ -58,44 +58,49 @@ public interface TraceSection extends TraceUniqueObject { * The given name should be the section's name from its module's image, which is considered * suitable for display on the screen. * + * @param snap the snap * @param name the name * @throws DuplicateNameException if the specified name would conflict with another section's in * this module */ - void setName(String name) throws DuplicateNameException; + void setName(long snap, String name) throws DuplicateNameException; /** * Get the "short name" of this section * *

- * This defaults to the "full name," but can be modified via {@link #setName(String)} + * This defaults to the "full name," but can be modified via {@link #setName(long, String)} * + * @param snap the snap * @return the name */ - String getName(); + String getName(long snap); /** * Get the virtual memory address range of this section * + * @param snap the snap * @return the address range */ - AddressRange getRange(); + AddressRange getRange(long snap); /** - * @see #getRange() + * @see #getRange(long) + * @param snap the snap * @return the min address in the range */ - default Address getStart() { - AddressRange range = getRange(); + default Address getStart(long snap) { + AddressRange range = getRange(snap); return range == null ? null : range.getMinAddress(); } /** - * @see #getRange() + * @see #getRange(long) + * @param snap the snap * @return the max address in the range */ - default Address getEnd() { - AddressRange range = getRange(); + default Address getEnd(long snap) { + AddressRange range = getRange(snap); return range == null ? null : range.getMaxAddress(); } @@ -103,4 +108,19 @@ public interface TraceSection extends TraceUniqueObject { * Delete this section from the trace */ void delete(); + + /** + * Remove this section from the given snap on + * + * @param snap the snap + */ + void remove(long snap); + + /** + * Check if the section is valid at the given snapshot + * + * @param snap the snapshot key + * @return true if valid, false if not + */ + boolean isValid(long snap); } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/stack/TraceStack.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/stack/TraceStack.java index 4fcc7c9b5a..d342a8b11f 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/stack/TraceStack.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/stack/TraceStack.java @@ -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. @@ -17,7 +17,6 @@ package ghidra.trace.model.stack; import java.util.List; -import ghidra.lifecycle.Experimental; import ghidra.lifecycle.Transitional; import ghidra.trace.model.TraceUniqueObject; import ghidra.trace.model.memory.TraceMemoryManager; @@ -42,19 +41,13 @@ public interface TraceStack extends TraceUniqueObject { */ TraceThread getThread(); - /** - * Get the snap where this stack is certain - * - * @return the snap - */ - long getSnap(); - /** * Get the depth (as recorded) of this stack * + * @param snap the snap * @return the depth */ - int getDepth(); + int getDepth(long snap); /** * Set the depth of the stack by adding or deleting frames to or from the specified end @@ -67,20 +60,22 @@ public interface TraceStack extends TraceUniqueObject { *

* If the experimental object mode is successful, this method should be deleted. * + * @param snap the snap * @param depth the desired depth * @param atInner true if frames should be "pushed" */ - void setDepth(int depth, boolean atInner); + void setDepth(long snap, int depth, boolean atInner); /** * Get the frame at the given level * + * @param snap the snap * @param level the level, where 0 indicates the inner-most frame. * @param ensureDepth true to expand the depth to accomodate the requested frame * @return the frame, or {@code null} if level exceeds the depth without ensureDepth set * @throws IndexOutOfBoundsException if the level is negative */ - TraceStackFrame getFrame(int level, boolean ensureDepth); + TraceStackFrame getFrame(long snap, int level, boolean ensureDepth); /** * Get all (known) frames in this stack @@ -89,13 +84,28 @@ public interface TraceStack extends TraceUniqueObject { * are fixed over the stack's lifetime) * @return the list of frames */ - List getFrames(@Experimental long snap); + List getFrames(long snap); /** * Delete this stack and its frames */ void delete(); + /** + * Remove this stack and its frame rom the given snapshot on + * + * @param snap the snapshot key + */ + void remove(long snap); + + /** + * Check if this stack is valid at the given snap + * + * @param snap the snap + * @return true if valid + */ + boolean isValid(long snap); + /** * Check if this stack'sframes are fixed for its lifetime * diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/target/TraceObject.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/target/TraceObject.java index 0c728b84ed..6bde8092b4 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/target/TraceObject.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/target/TraceObject.java @@ -191,6 +191,14 @@ public interface TraceObject extends TraceUniqueObject { */ boolean isAlive(long snap); + /** + * Check if the object is alive at all in the given span + * + * @param span the span + * @return true if alive, false if not + */ + boolean isAlive(Lifespan span); + /** * Inserts this object at its canonical path for the given lifespan * diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/target/iface/TraceObjectInterface.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/target/iface/TraceObjectInterface.java index 9aaf7c5d8e..b173320f66 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/target/iface/TraceObjectInterface.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/target/iface/TraceObjectInterface.java @@ -15,9 +15,6 @@ */ package ghidra.trace.model.target.iface; -import ghidra.lifecycle.Transitional; -import ghidra.trace.model.Lifespan; -import ghidra.trace.model.Lifespan.LifeSet; import ghidra.trace.model.target.TraceObject; import ghidra.trace.model.target.info.TraceObjectInfo; import ghidra.trace.model.thread.TraceObjectThread; @@ -52,36 +49,4 @@ public interface TraceObjectInterface { * @return the object */ TraceObject getObject(); - - /** - * Compute the lifespan of this object - * - * @return the span of all lifespans - */ - @Transitional - default Lifespan computeSpan() { - LifeSet life = getObject().getLife(); - if (life.isEmpty()) { - return null; - } - return life.bound(); - } - - @Transitional - default long computeMinSnap() { - Lifespan span = computeSpan(); - if (span == null) { - return 0; - } - return span.lmin(); - } - - @Transitional - default long computeMaxSnap() { - Lifespan span = computeSpan(); - if (span == null) { - return 0; - } - return span.lmax(); - } } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/target/info/TraceObjectInterfaceUtils.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/target/info/TraceObjectInterfaceUtils.java index dc260c4079..c0d1cf4974 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/target/info/TraceObjectInterfaceUtils.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/target/info/TraceObjectInterfaceUtils.java @@ -22,16 +22,13 @@ import java.util.stream.Stream; import javax.swing.event.ChangeEvent; -import ghidra.trace.model.Lifespan; -import ghidra.trace.model.target.*; -import ghidra.trace.model.target.TraceObject.ConflictResolution; +import ghidra.trace.model.target.TraceObject; +import ghidra.trace.model.target.TraceObjectValue; import ghidra.trace.model.target.iface.TraceObjectInterface; import ghidra.trace.model.target.info.TraceObjectInterfaceFactory.Constructor; import ghidra.trace.model.target.schema.TraceObjectSchema; -import ghidra.util.LockHold; import ghidra.util.Msg; import ghidra.util.classfinder.ClassSearcher; -import ghidra.util.exception.DuplicateNameException; public enum TraceObjectInterfaceUtils { ; @@ -122,29 +119,6 @@ public enum TraceObjectInterfaceUtils { return List.of(requireAnnotation(traceIf).fixedKeys()); } - public static void setLifespan(Class traceIf, - TraceObject object, Lifespan lifespan) throws DuplicateNameException { - try (LockHold hold = object.getTrace().lockWrite()) { - for (TraceObjectValue val : object.getParents(Lifespan.ALL)) { - if (val.isCanonical() && !val.isDeleted()) { - val.setLifespan(lifespan, ConflictResolution.DENY); - } - } - } - catch (DuplicateKeyException e) { - throw new DuplicateNameException( - "Duplicate " + getShortName(traceIf) + ": " + e.getMessage()); - } - object.insert(lifespan, ConflictResolution.TRUNCATE); - long lower = lifespan.lmin(); - for (String key : getFixedKeys(traceIf)) { - TraceObjectValue val = object.getValue(lower, key); - if (val != null) { - val.setLifespan(lifespan, ConflictResolution.TRUNCATE); - } - } - } - public static T getValue(TraceObject object, long snap, String key, Class cls, T def) { TraceObjectValue value = object.getValue(snap, key); if (value == null) { diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/thread/TraceThread.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/thread/TraceThread.java index e95c31574a..09538bdd69 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/thread/TraceThread.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/thread/TraceThread.java @@ -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,7 +19,6 @@ import java.util.List; import ghidra.program.model.lang.Register; import ghidra.trace.model.*; -import ghidra.util.exception.DuplicateNameException; /** * A thread in a trace @@ -50,88 +49,34 @@ public interface TraceThread extends TraceUniqueObject { /** * Get the "short name" of this thread * + * @param snap the snap * @return the name */ - String getName(); + String getName(long snap); /** * Set the "short name" of this thread * + * @param snap the snap * @param name the name */ - void setName(String name); - - /** - * @see #setLifespan(Lifespan) - * - * @param creationSnap the creation snap, or {@link Long#MIN_VALUE} for "since the beginning of - * time" - * @throws DuplicateNameException if extending the thread's life would cause a naming conflict - */ - void setCreationSnap(long creationSnap) throws DuplicateNameException; - - /** - * Get the creation snap of this thread - * - * @return the creation snap, or {@link Long#MIN_VALUE} for "since the beginning of time" - */ - long getCreationSnap(); - - /** - * @see #setLifespan(Lifespan) - * - * @param destructionSnap the destruction snap, or {@link Long#MAX_VALUE} for "to the end of - * time" - * @throws DuplicateNameException if extending the thread's life would cause a naming conflict - */ - void setDestructionSnap(long destructionSnap) throws DuplicateNameException; - - /** - * Get the destruction snap of this thread - * - * @return the destruction snap, or {@link Long#MAX_VALUE} for "to the end of time" - */ - long getDestructionSnap(); - - /** - * Set the lifespan of this thread - * - * @param lifespan the lifespan - * @throws DuplicateNameException if the specified lifespan would cause the full name of this - * thread to conflict with that of another whose lifespan would intersect this - * thread's - */ - void setLifespan(Lifespan lifespan) throws DuplicateNameException; - - /** - * Get the lifespan of this thread - * - * @return the lifespan - */ - Lifespan getLifespan(); + void setName(long snap, String name); /** * Set a comment on this thread * + * @param snap the snap * @param comment the comment, possibly {@code null} */ - void setComment(String comment); + void setComment(long snap, String comment); /*** * Get the comment on this thread * + * @param snap the snap * @return the comment, possibly {@code null} */ - String getComment(); - - /** - * Check if the thread has a recorded destruction snap - * - * @return false if destroyed, true otherwise - */ - default boolean isAlive() { - return !getLifespan().maxIsFinite(); - } + String getComment(long snap); /** * A convenience to obtain the registers from the containing trace's base language @@ -147,6 +92,13 @@ public interface TraceThread extends TraceUniqueObject { */ void delete(); + /** + * Remove this thread from the given snapshot on + * + * @param snap the snapshot key + */ + void remove(long snap); + /** * Check if the thread is valid at the given snapshot * @@ -160,4 +112,12 @@ public interface TraceThread extends TraceUniqueObject { * @return true if valid, false if not */ boolean isValid(long snap); + + /** + * Check if the module is alive for any of the given span + * + * @param span the span + * @return true if its life intersects the span + */ + boolean isAlive(Lifespan span); } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/breakpoint/DBTraceBreakpointManagerObjectTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/breakpoint/DBTraceBreakpointManagerObjectTest.java index 215751cae2..756783fa23 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/breakpoint/DBTraceBreakpointManagerObjectTest.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/breakpoint/DBTraceBreakpointManagerObjectTest.java @@ -19,8 +19,8 @@ import org.junit.Before; import db.Transaction; import ghidra.trace.model.target.schema.SchemaContext; -import ghidra.trace.model.target.schema.XmlSchemaContext; import ghidra.trace.model.target.schema.TraceObjectSchema.SchemaName; +import ghidra.trace.model.target.schema.XmlSchemaContext; public class DBTraceBreakpointManagerObjectTest extends DBTraceBreakpointManagerTest { @@ -56,9 +56,4 @@ public class DBTraceBreakpointManagerObjectTest extends DBTraceBreakpointManager b.trace.getObjectManager().createRootObject(ctx.getSchema(new SchemaName("Session"))); } } - - @Override - public void testSplitAndSet() throws Exception { - // This method is not supported in objects mode. - } } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/breakpoint/DBTraceBreakpointManagerTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/breakpoint/DBTraceBreakpointManagerTest.java index 95b3e1dcc4..c039275a49 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/breakpoint/DBTraceBreakpointManagerTest.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/breakpoint/DBTraceBreakpointManagerTest.java @@ -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. @@ -152,73 +152,29 @@ public class DBTraceBreakpointManagerTest extends AbstractGhidraHeadlessIntegrat @Test public void testSetGetName() throws Exception { addBreakpoints(); - assertEquals("Breakpoints[0]", breakMain.getName()); + assertEquals("Breakpoints[0]", breakMain.getName(0)); try (Transaction tx = b.startTransaction()) { - breakMain.setName("bpt 0"); - assertEquals("bpt 0", breakMain.getName()); + breakMain.setName(0, "bpt 0"); + assertEquals("bpt 0", breakMain.getName(0)); } - assertEquals("bpt 0", breakMain.getName()); + assertEquals("bpt 0", breakMain.getName(0)); } @Test public void testGetThreads() throws Exception { addBreakpoints(); - assertEquals(Set.of(thread), Set.copyOf(breakMain.getThreads())); - assertEquals(Set.of(thread), Set.copyOf(breakVarA.getThreads())); - assertEquals(Set.of(thread), Set.copyOf(breakVarB.getThreads())); + assertEquals(Set.of(thread), Set.copyOf(breakMain.getThreads(0))); + assertEquals(Set.of(thread), Set.copyOf(breakVarA.getThreads(0))); + assertEquals(Set.of(thread), Set.copyOf(breakVarB.getThreads(0))); } @Test public void testGetRange() throws Exception { addBreakpoints(); - assertEquals(b.addr(0x00400000), breakMain.getMinAddress()); - assertEquals(b.addr(0x00400000), breakMain.getMaxAddress()); - assertEquals(b.range(0x00400000, 0x00400000), breakMain.getRange()); - assertEquals(1, breakMain.getLength()); - } - - @Test - public void testGetLifespan() throws Exception { - addBreakpoints(); - assertEquals(0, breakMain.getPlacedSnap()); - assertEquals(10, breakMain.getClearedSnap()); - assertEquals(Lifespan.span(0, 10), breakMain.getLifespan()); - } - - @Test - public void testSetCleared() throws Exception { - addBreakpoints(); - try (Transaction tx = b.startTransaction()) { - breakMain.setClearedSnap(5); - assertEquals(5, breakMain.getClearedSnap()); - } - assertEquals(0, breakMain.getPlacedSnap()); - assertEquals(5, breakMain.getClearedSnap()); - assertEquals(Lifespan.span(0, 5), breakMain.getLifespan()); - } - - @Test - public void testSplitAndSet() throws Exception { - addBreakpoints(); - - TraceBreakpoint disMain; - try (Transaction tx = b.startTransaction()) { - TraceBreakpoint oopsMain = - breakMain.splitAndSet(0, true, Set.of(TraceBreakpointKind.HW_EXECUTE)); - assertSame(breakMain, oopsMain); - disMain = - breakMain.splitAndSet(6, false, Set.of(TraceBreakpointKind.HW_EXECUTE)); - assertNotSame(breakMain, disMain); - TraceBreakpoint sameDis = - disMain.splitAndSet(8, false, Set.of(TraceBreakpointKind.HW_EXECUTE)); - assertSame(disMain, sameDis); - } - - assertTrue(breakMain.isEnabled(0)); - assertEquals(Set.of(TraceBreakpointKind.HW_EXECUTE), Set.copyOf(breakMain.getKinds())); - - assertFalse(disMain.isEnabled(6)); - assertEquals(Set.of(TraceBreakpointKind.HW_EXECUTE), Set.copyOf(disMain.getKinds())); + assertEquals(b.addr(0x00400000), breakMain.getMinAddress(0)); + assertEquals(b.addr(0x00400000), breakMain.getMaxAddress(0)); + assertEquals(b.range(0x00400000, 0x00400000), breakMain.getRange(0)); + assertEquals(1, breakMain.getLength(0)); } @Test @@ -226,12 +182,12 @@ public class DBTraceBreakpointManagerTest extends AbstractGhidraHeadlessIntegrat addBreakpoints(); assertTrue(breakMain.isEnabled(0)); try (Transaction tx = b.startTransaction()) { - breakMain.setEnabled(false); + breakMain.setEnabled(0, false); assertFalse(breakMain.isEnabled(0)); } assertFalse(breakMain.isEnabled(0)); try (Transaction tx = b.startTransaction()) { - breakMain.setEnabled(true); + breakMain.setEnabled(0, true); assertTrue(breakMain.isEnabled(0)); } assertTrue(breakMain.isEnabled(0)); @@ -240,23 +196,23 @@ public class DBTraceBreakpointManagerTest extends AbstractGhidraHeadlessIntegrat @Test public void testSetGetKinds() throws Exception { addBreakpoints(); - assertEquals(Set.of(TraceBreakpointKind.SW_EXECUTE), Set.copyOf(breakMain.getKinds())); + assertEquals(Set.of(TraceBreakpointKind.SW_EXECUTE), Set.copyOf(breakMain.getKinds(0))); try (Transaction tx = b.startTransaction()) { - breakMain.setKinds(Set.of(TraceBreakpointKind.HW_EXECUTE)); - assertEquals(Set.of(TraceBreakpointKind.HW_EXECUTE), Set.copyOf(breakMain.getKinds())); + breakMain.setKinds(0, Set.of(TraceBreakpointKind.HW_EXECUTE)); + assertEquals(Set.of(TraceBreakpointKind.HW_EXECUTE), Set.copyOf(breakMain.getKinds(0))); } - assertEquals(Set.of(TraceBreakpointKind.HW_EXECUTE), Set.copyOf(breakMain.getKinds())); + assertEquals(Set.of(TraceBreakpointKind.HW_EXECUTE), Set.copyOf(breakMain.getKinds(0))); } @Test public void testSetGetComment() throws Exception { addBreakpoints(); - assertEquals("main", breakMain.getComment()); + assertEquals("main", breakMain.getComment(0)); try (Transaction tx = b.startTransaction()) { - breakMain.setComment("WinMain"); - assertEquals("WinMain", breakMain.getComment()); + breakMain.setComment(0, "WinMain"); + assertEquals("WinMain", breakMain.getComment(0)); } - assertEquals("WinMain", breakMain.getComment()); + assertEquals("WinMain", breakMain.getComment(0)); } protected static class InvalidBreakpointMatcher extends BaseMatcher { diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/listing/DBTraceCodeManagerTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/listing/DBTraceCodeManagerTest.java index 632f6d0382..676127b4c6 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/listing/DBTraceCodeManagerTest.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/listing/DBTraceCodeManagerTest.java @@ -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. @@ -1415,9 +1415,9 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes try (Transaction tx = b.startTransaction()) { TraceStack stack = b.trace.getStackManager().getStack(thread, 0, true); - stack.setDepth(2, true); - assertEquals(regCode, manager.getCodeRegisterSpace(stack.getFrame(0, false), false)); - frameCode = manager.getCodeRegisterSpace(stack.getFrame(1, false), true); + stack.setDepth(0, 2, true); + assertEquals(regCode, manager.getCodeRegisterSpace(stack.getFrame(0, 0, false), false)); + frameCode = manager.getCodeRegisterSpace(stack.getFrame(0, 1, false), true); assertNotEquals(regCode, frameCode); dR5 = frameCode.definedData() .create(Lifespan.nowOn(0), b.language.getRegister("r5"), LongDataType.dataType); diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/memory/AbstractDBTraceMemoryManagerRegistersTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/memory/AbstractDBTraceMemoryManagerRegistersTest.java index ecfa24ba62..c14c8587cc 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/memory/AbstractDBTraceMemoryManagerRegistersTest.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/memory/AbstractDBTraceMemoryManagerRegistersTest.java @@ -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. @@ -66,10 +66,10 @@ public abstract class AbstractDBTraceMemoryManagerRegistersTest assertEquals(new BigInteger("FEDCBA98", 16), regs.getValue(0, r0l).getUnsignedValue()); TraceStack stack = b.trace.getStackManager().getStack(thread, 0, true); - stack.setDepth(2, true); - assertSame(regs, memory.getMemoryRegisterSpace(stack.getFrame(0, false), false)); + stack.setDepth(0, 2, true); + assertSame(regs, memory.getMemoryRegisterSpace(stack.getFrame(0, 0, false), false)); DBTraceMemorySpace frame = - memory.getMemoryRegisterSpace(stack.getFrame(1, false), true); + memory.getMemoryRegisterSpace(stack.getFrame(0, 1, false), true); if (isRegistersPerFrame()) { assertNotSame(regs, frame); } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/module/DBTraceModuleManagerTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/module/DBTraceModuleManagerTest.java index db15f816aa..18e7ac0d41 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/module/DBTraceModuleManagerTest.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/module/DBTraceModuleManagerTest.java @@ -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. @@ -60,8 +60,8 @@ public class DBTraceModuleManagerTest extends AbstractGhidraHeadlessIntegrationT try (Transaction tx = b.startTransaction()) { TraceModule mod1 = moduleManager.addModule("Modules[first]", "first", b.range(0x00400000, 0x0060002f), Lifespan.span(0, 10)); - mod1.addSection("Modules[first].Sections[.text]", b.range(0x00401000, 0x00401f9f)); - mod1.addSection("Modules[first].Sections[.data]", b.range(0x00600000, 0x0060002f)); + mod1.addSection(0, "Modules[first].Sections[.text]", b.range(0x00401000, 0x00401f9f)); + mod1.addSection(0, "Modules[first].Sections[.data]", b.range(0x00600000, 0x0060002f)); moduleManager.addModule("Modules[second]", "second", b.range(0x7f400000, 0x7f60002f), Lifespan.span(0, 10)); @@ -77,8 +77,8 @@ public class DBTraceModuleManagerTest extends AbstractGhidraHeadlessIntegrationT try (Transaction tx = b.startTransaction()) { mod1 = moduleManager.addModule("Modules[first]", "first", b.range(0x00400000, 0x0060002f), Lifespan.span(0, 10)); - mod1.addSection("Modules[first].Sections[.text]", b.range(0x00401000, 0x00401f9f)); - mod1.addSection("Modules[first].Sections[.data]", b.range(0x00600000, 0x0060002f)); + mod1.addSection(0, "Modules[first].Sections[.text]", b.range(0x00401000, 0x00401f9f)); + mod1.addSection(0, "Modules[first].Sections[.data]", b.range(0x00600000, 0x0060002f)); mod2 = moduleManager.addModule("Modules[second]", "second", b.range(0x7f400000, 0x7f60002f), Lifespan.span(0, 10)); @@ -96,8 +96,8 @@ public class DBTraceModuleManagerTest extends AbstractGhidraHeadlessIntegrationT try (Transaction tx = b.startTransaction()) { mod1 = moduleManager.addModule("Modules[first]", "first", b.range(0x00400000, 0x0060002f), Lifespan.span(0, 10)); - mod1.addSection("Modules[first].Sections[.text]", b.range(0x00401000, 0x00401f9f)); - mod1.addSection("Modules[first].Sections[.data]", b.range(0x00600000, 0x0060002f)); + mod1.addSection(0, "Modules[first].Sections[.text]", b.range(0x00401000, 0x00401f9f)); + mod1.addSection(0, "Modules[first].Sections[.data]", b.range(0x00600000, 0x0060002f)); mod2 = moduleManager.addModule("Modules[second]", "second", b.range(0x7e400000, 0x7e60002f), Lifespan.span(0, 10)); @@ -125,10 +125,10 @@ public class DBTraceModuleManagerTest extends AbstractGhidraHeadlessIntegrationT try (Transaction tx = b.startTransaction()) { mod1 = moduleManager.addModule("Modules[first]", "first", b.range(0x00400000, 0x0060002f), Lifespan.span(0, 10)); - assertEquals("first", mod1.getName()); + assertEquals("first", mod1.getName(0)); - mod1.setName("FIRST"); - assertEquals("FIRST", mod1.getName()); + mod1.setName(0, "FIRST"); + assertEquals("FIRST", mod1.getName(0)); } } @@ -139,32 +139,10 @@ public class DBTraceModuleManagerTest extends AbstractGhidraHeadlessIntegrationT try (Transaction tx = b.startTransaction()) { mod1 = moduleManager.addModule("Modules[first]", "first", b.range(0x00400000, 0x0060002f), Lifespan.span(0, 10)); - assertEquals(b.addr(0x00400000), mod1.getBase()); + assertEquals(b.addr(0x00400000), mod1.getBase(0)); - mod1.setBase(b.addr(0x00400100)); // Cannot exceed current max - assertEquals(b.addr(0x00400100), mod1.getBase()); - } - } - - @Test - public void testModuleSetGetLifespan() throws Exception { - TraceModule mod1; - try (Transaction tx = b.startTransaction()) { - mod1 = moduleManager.addModule("Modules[first]", "first", - b.range(0x00400000, 0x0060002f), Lifespan.span(0, 10)); - assertEquals(Lifespan.span(0, 10), mod1.getLifespan()); - assertEquals(0, mod1.getLoadedSnap()); - assertEquals(10, mod1.getUnloadedSnap()); - - mod1.setLifespan(Lifespan.span(1, 11)); - assertEquals(Lifespan.span(1, 11), mod1.getLifespan()); - assertEquals(1, mod1.getLoadedSnap()); - assertEquals(11, mod1.getUnloadedSnap()); - - mod1.setLoadedSnap(2); - assertEquals(Lifespan.span(2, 11), mod1.getLifespan()); - mod1.setUnloadedSnap(4); - assertEquals(Lifespan.span(2, 4), mod1.getLifespan()); + mod1.setBase(0, b.addr(0x00400100)); // Cannot exceed current max + assertEquals(b.addr(0x00400100), mod1.getBase(0)); } } @@ -179,20 +157,20 @@ public class DBTraceModuleManagerTest extends AbstractGhidraHeadlessIntegrationT try (Transaction tx = b.startTransaction()) { mod1 = moduleManager.addModule("Modules[first]", "first", b.range(0x00400000, 0x0060002f), Lifespan.span(0, 10)); - s1text = - mod1.addSection("Modules[first].Sections[.text]", b.range(0x00401000, 0x00401f9f)); - s1data = - mod1.addSection("Modules[first].Sections[.data]", b.range(0x00600000, 0x0060002f)); + s1text = mod1.addSection(0, "Modules[first].Sections[.text]", + b.range(0x00401000, 0x00401f9f)); + s1data = mod1.addSection(0, "Modules[first].Sections[.data]", + b.range(0x00600000, 0x0060002f)); mod2 = moduleManager.addModule("Modules[second]", "second", b.range(0x7e400000, 0x7e60002f), Lifespan.span(0, 10)); - s2text = - mod2.addSection("Modules[second].Sections[.text]", b.range(0x7f401000, 0x7f401fa0)); - s2data = - mod2.addSection("Modules[second].Sections[.data]", b.range(0x7f600000, 0x7f60002f)); + s2text = mod2.addSection(0, "Modules[second].Sections[.text]", + b.range(0x7f401000, 0x7f401fa0)); + s2data = mod2.addSection(0, "Modules[second].Sections[.data]", + b.range(0x7f600000, 0x7f60002f)); } - assertEquals(Set.of(s1text, s1data), new HashSet<>(mod1.getSections())); - assertEquals(Set.of(s2text, s2data), new HashSet<>(mod2.getSections())); + assertEquals(Set.of(s1text, s1data), new HashSet<>(mod1.getSections(0))); + assertEquals(Set.of(s2text, s2data), new HashSet<>(mod2.getSections(0))); } @Test @@ -206,22 +184,22 @@ public class DBTraceModuleManagerTest extends AbstractGhidraHeadlessIntegrationT try (Transaction tx = b.startTransaction()) { mod1 = moduleManager.addModule("Modules[first]", "first", b.range(0x00400000, 0x0060002f), Lifespan.span(0, 10)); - s1text = mod1.addSection("Modules[first].Sections[.text]", ".text", + s1text = mod1.addSection(0, "Modules[first].Sections[.text]", ".text", b.range(0x00401000, 0x00401f9f)); - s1data = mod1.addSection("Modules[first].Sections[.data]", ".data", + s1data = mod1.addSection(0, "Modules[first].Sections[.data]", ".data", b.range(0x00600000, 0x0060002f)); mod2 = moduleManager.addModule("Modules[second]", "second", b.range(0x7f400000, 0x7f60002f), Lifespan.span(0, 10)); - s2text = mod2.addSection("Modules[second].Sections[.text]", ".text", + s2text = mod2.addSection(0, "Modules[second].Sections[.text]", ".text", b.range(0x7f401000, 0x7f401f9f)); - s2data = mod2.addSection("Modules[second].Sections[.data]", ".data", + s2data = mod2.addSection(0, "Modules[second].Sections[.data]", ".data", b.range(0x7f600000, 0x7f60002f)); } - assertEquals(s1text, mod1.getSectionByName(".text")); - assertEquals(s1data, mod1.getSectionByName(".data")); - assertEquals(s2text, mod2.getSectionByName(".text")); - assertEquals(s2data, mod2.getSectionByName(".data")); + assertEquals(s1text, mod1.getSectionByName(0, ".text")); + assertEquals(s1data, mod1.getSectionByName(0, ".data")); + assertEquals(s2text, mod2.getSectionByName(0, ".text")); + assertEquals(s2data, mod2.getSectionByName(0, ".data")); } @Test @@ -231,8 +209,8 @@ public class DBTraceModuleManagerTest extends AbstractGhidraHeadlessIntegrationT try (Transaction tx = b.startTransaction()) { mod1 = moduleManager.addModule("Modules[first]", "first", b.range(0x00400000, 0x0060002f), Lifespan.span(0, 10)); - mod1.addSection("Modules[first].Sections[.text]", b.range(0x00401000, 0x00401f9f)); - mod1.addSection("Modules[first].Sections[.data]", b.range(0x00600000, 0x0060002f)); + mod1.addSection(0, "Modules[first].Sections[.text]", b.range(0x00401000, 0x00401f9f)); + mod1.addSection(0, "Modules[first].Sections[.data]", b.range(0x00600000, 0x0060002f)); mod2 = moduleManager.addModule("Modules[second]", "second", b.range(0x7f400000, 0x7f60002f), Lifespan.span(0, 10)); @@ -253,7 +231,8 @@ public class DBTraceModuleManagerTest extends AbstractGhidraHeadlessIntegrationT mod1 = moduleManager.addModule("Modules[first]", "first", b.range(0x00400000, 0x0060002f), Lifespan.span(0, 10)); s1text = - mod1.addSection("Modules[first].Sections[.text]", b.range(0x00401000, 0x00401f9f)); + mod1.addSection(0, "Modules[first].Sections[.text]", + b.range(0x00401000, 0x00401f9f)); } assertEquals(mod1, s1text.getModule()); @@ -266,12 +245,12 @@ public class DBTraceModuleManagerTest extends AbstractGhidraHeadlessIntegrationT try (Transaction tx = b.startTransaction()) { mod1 = moduleManager.addModule("Modules[first]", "first", b.range(0x00400000, 0x0060002f), Lifespan.span(0, 10)); - s1text = mod1.addSection("Modules[first].Sections[.text]", ".text", + s1text = mod1.addSection(0, "Modules[first].Sections[.text]", ".text", b.range(0x00401000, 0x00401f9f)); - assertEquals(".text", s1text.getName()); - s1text.setName("_TEXT"); - assertEquals("_TEXT", s1text.getName()); + assertEquals(".text", s1text.getName(0)); + s1text.setName(0, "_TEXT"); + assertEquals("_TEXT", s1text.getName(0)); } } @@ -282,13 +261,13 @@ public class DBTraceModuleManagerTest extends AbstractGhidraHeadlessIntegrationT try (Transaction tx = b.startTransaction()) { mod1 = moduleManager.addModule("Modules[first]", "first", b.range(0x00400000, 0x0060002f), Lifespan.span(0, 10)); - s1text = mod1.addSection("Modules[first].Sections[.text]", ".text", + s1text = mod1.addSection(0, "Modules[first].Sections[.text]", ".text", b.range(0x00401000, 0x00401f9f)); } - assertEquals(b.range(0x00401000, 0x00401f9f), s1text.getRange()); - assertEquals(b.addr(0x00401000), s1text.getStart()); - assertEquals(b.addr(0x00401f9f), s1text.getEnd()); + assertEquals(b.range(0x00401000, 0x00401f9f), s1text.getRange(0)); + assertEquals(b.addr(0x00401000), s1text.getStart(0)); + assertEquals(b.addr(0x00401f9f), s1text.getEnd(0)); } protected T assertOne(Collection col) { @@ -304,9 +283,9 @@ public class DBTraceModuleManagerTest extends AbstractGhidraHeadlessIntegrationT try (Transaction tx = b.startTransaction()) { mod1 = moduleManager.addModule("Modules[first]", "first", b.range(0x00400000, 0x0060002f), Lifespan.span(0, 10)); - mod1.addSection("Modules[first].Sections[.text]", ".text", + mod1.addSection(0, "Modules[first].Sections[.text]", ".text", b.range(0x00401000, 0x00401f9f)); - mod1.addSection("Modules[first].Sections[.data]", ".data", + mod1.addSection(0, "Modules[first].Sections[.data]", ".data", b.range(0x00600000, 0x0060002f)); mod2 = moduleManager.addModule("Modules[second]", "second", @@ -319,15 +298,13 @@ public class DBTraceModuleManagerTest extends AbstractGhidraHeadlessIntegrationT mod1 = assertOne(moduleManager.getModulesByPath("Modules[first]")); mod2 = assertOne(moduleManager.getModulesByPath("Modules[second]")); - TraceSection s1text = mod1.getSectionByName(".text"); - TraceSection s1data = mod1.getSectionByName(".data"); + TraceSection s1text = mod1.getSectionByName(0, ".text"); + TraceSection s1data = mod1.getSectionByName(0, ".data"); - assertEquals(b.addr(0x00400000), mod1.getBase()); - assertEquals(Lifespan.span(0, 10), mod1.getLifespan()); - assertEquals(b.addr(0x7f400000), mod2.getBase()); - assertEquals(Lifespan.span(1, 11), mod2.getLifespan()); - assertEquals(b.range(0x00401000, 0x00401f9f), s1text.getRange()); - assertEquals(b.range(0x00600000, 0x0060002f), s1data.getRange()); + assertEquals(b.addr(0x00400000), mod1.getBase(0)); + assertEquals(b.addr(0x7f400000), mod2.getBase(1)); + assertEquals(b.range(0x00401000, 0x00401f9f), s1text.getRange(0)); + assertEquals(b.range(0x00600000, 0x0060002f), s1data.getRange(0)); } } @@ -337,8 +314,8 @@ public class DBTraceModuleManagerTest extends AbstractGhidraHeadlessIntegrationT try (Transaction tx = b.startTransaction()) { mod1 = moduleManager.addModule("Modules[first]", "first", b.range(0x00400000, 0x0060002f), Lifespan.span(0, 10)); - mod1.addSection("Modules[first].Sections[.text]", b.range(0x00401000, 0x00401f9f)); - mod1.addSection("Modules[first].Sections[.data]", b.range(0x00600000, 0x0060002f)); + mod1.addSection(0, "Modules[first].Sections[.text]", b.range(0x00401000, 0x00401f9f)); + mod1.addSection(0, "Modules[first].Sections[.data]", b.range(0x00600000, 0x0060002f)); } try (Transaction tx = b.startTransaction()) { @@ -359,9 +336,9 @@ public class DBTraceModuleManagerTest extends AbstractGhidraHeadlessIntegrationT try (Transaction tx = b.startTransaction()) { mod1 = moduleManager.addModule("Modules[first]", "first", b.range(0x00400000, 0x0060002f), Lifespan.span(0, 10)); - mod1.addSection("Modules[first].Sections[.text]", ".text", + mod1.addSection(0, "Modules[first].Sections[.text]", ".text", b.range(0x00401000, 0x00401f9f)); - mod1.addSection("Modules[first].Sections[.data]", ".data", + mod1.addSection(0, "Modules[first].Sections[.data]", ".data", b.range(0x00600000, 0x0060002f)); mod2 = moduleManager.addModule("Modules[second]", "second", @@ -376,14 +353,12 @@ public class DBTraceModuleManagerTest extends AbstractGhidraHeadlessIntegrationT // NOTE: Because undo actually removes them, module identity may not be preserved mod1 = assertOne(moduleManager.getModulesByPath("Modules[first]")); mod2 = assertOne(moduleManager.getModulesByPath("Modules[second]")); - TraceSection s1text = mod1.getSectionByName(".text"); - TraceSection s1data = mod1.getSectionByName(".data"); + TraceSection s1text = mod1.getSectionByName(0, ".text"); + TraceSection s1data = mod1.getSectionByName(0, ".data"); - assertEquals(b.addr(0x00400000), mod1.getBase()); - assertEquals(Lifespan.span(0, 10), mod1.getLifespan()); - assertEquals(b.addr(0x7f400000), mod2.getBase()); - assertEquals(Lifespan.span(1, 11), mod2.getLifespan()); - assertEquals(b.range(0x00401000, 0x00401f9f), s1text.getRange()); - assertEquals(b.range(0x00600000, 0x0060002f), s1data.getRange()); + assertEquals(b.addr(0x00400000), mod1.getBase(0)); + assertEquals(b.addr(0x7f400000), mod2.getBase(0)); + assertEquals(b.range(0x00401000, 0x00401f9f), s1text.getRange(0)); + assertEquals(b.range(0x00600000, 0x0060002f), s1data.getRange(0)); } } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceProgramViewMemoryTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceProgramViewMemoryTest.java index 34c21ce57a..7c6923f5da 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceProgramViewMemoryTest.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceProgramViewMemoryTest.java @@ -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. @@ -31,6 +31,7 @@ import ghidra.test.AbstractGhidraHeadlessIntegrationTest; import ghidra.trace.database.ToyDBTraceBuilder; import ghidra.trace.database.memory.DBTraceMemoryManager; import ghidra.trace.database.memory.DBTraceMemoryRegion; +import ghidra.trace.database.program.DBTraceProgramViewMemory.RegionEntry; import ghidra.trace.model.memory.TraceMemoryFlag; public class DBTraceProgramViewMemoryTest extends AbstractGhidraHeadlessIntegrationTest { @@ -78,7 +79,7 @@ public class DBTraceProgramViewMemoryTest extends AbstractGhidraHeadlessIntegrat assertEquals(1, blocks.length); MemoryBlock blk = blocks[0]; - assertSame(blk, vmem.getRegionBlock(io)); + assertSame(blk, vmem.getRegionBlock(new RegionEntry(io, 0))); assertEquals(".io", blk.getName()); assertEquals(tb.addr(os, 0x1000), blk.getStart()); assertEquals(tb.addr(os, 0x1fff), blk.getEnd()); diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/stack/DBTraceStackManagerTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/stack/DBTraceStackManagerTest.java index 3434487d82..8a5d1e666e 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/stack/DBTraceStackManagerTest.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/stack/DBTraceStackManagerTest.java @@ -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. @@ -62,9 +62,9 @@ public class DBTraceStackManagerTest extends AbstractGhidraHeadlessIntegrationTe try (Transaction tx = b.startTransaction()) { TraceThread thread = b.getOrAddThread("Threads[1]", 0); stack = stackManager.getStack(thread, 0, true); - stack.setDepth(1, true); - stack.setDepth(3, false); - stack.setDepth(5, true); + stack.setDepth(0, 1, true); + stack.setDepth(0, 3, false); + stack.setDepth(0, 5, true); } int expectedLevel = 0; for (TraceStackFrame frame : stack.getFrames(0)) { @@ -73,7 +73,7 @@ public class DBTraceStackManagerTest extends AbstractGhidraHeadlessIntegrationTe assertEquals(5, expectedLevel); try (Transaction tx = b.startTransaction()) { - stack.setDepth(3, true); + stack.setDepth(0, 3, true); } expectedLevel = 0; @@ -83,7 +83,7 @@ public class DBTraceStackManagerTest extends AbstractGhidraHeadlessIntegrationTe assertEquals(3, expectedLevel); try (Transaction tx = b.startTransaction()) { - stack.setDepth(1, false); + stack.setDepth(0, 1, false); } expectedLevel = 0; @@ -137,16 +137,16 @@ public class DBTraceStackManagerTest extends AbstractGhidraHeadlessIntegrationTe TraceThread thread = b.getOrAddThread("Threads[1]", 0); TraceStack stack1 = stackManager.getStack(thread, 0, true); - stack1.setDepth(2, true); - frame1a = stack1.getFrame(0, false); - frame1b = stack1.getFrame(1, false); + stack1.setDepth(0, 2, true); + frame1a = stack1.getFrame(0, 0, false); + frame1b = stack1.getFrame(0, 1, false); frame1a.setProgramCounter(Lifespan.nowOn(0), b.addr(0x0040100)); frame1b.setProgramCounter(Lifespan.nowOn(0), b.addr(0x0040300)); TraceStack stack2 = stackManager.getStack(thread, 1, true); - stack2.setDepth(2, true); - frame2a = stack2.getFrame(0, false); - frame2b = stack2.getFrame(1, false); + stack2.setDepth(0, 2, true); + frame2a = stack2.getFrame(0, 0, false); + frame2b = stack2.getFrame(0, 1, false); frame2a.setProgramCounter(Lifespan.nowOn(1), b.addr(0x0040200)); frame2b.setProgramCounter(Lifespan.nowOn(1), b.addr(0x0040400)); } @@ -171,18 +171,6 @@ public class DBTraceStackManagerTest extends AbstractGhidraHeadlessIntegrationTe assertEquals(thread, stack.getThread()); } - @Test - public void testStackGetSnap() throws Exception { - TraceThread thread; - TraceStack stack; - try (Transaction tx = b.startTransaction()) { - thread = b.getOrAddThread("Threads[1]", 0); - stack = stackManager.getStack(thread, 2, true); - } - - assertEquals(2, stack.getSnap()); - } - @Test public void testStackGetDepth() throws Exception { TraceThread thread; @@ -190,10 +178,10 @@ public class DBTraceStackManagerTest extends AbstractGhidraHeadlessIntegrationTe try (Transaction tx = b.startTransaction()) { thread = b.getOrAddThread("Threads[1]", 0); stack = stackManager.getStack(thread, 0, true); - stack.setDepth(2, true); + stack.setDepth(0, 2, true); } - assertEquals(2, stack.getDepth()); + assertEquals(2, stack.getDepth(0)); } @Test @@ -203,13 +191,13 @@ public class DBTraceStackManagerTest extends AbstractGhidraHeadlessIntegrationTe try (Transaction tx = b.startTransaction()) { thread = b.getOrAddThread("Threads[1]", 0); stack = stackManager.getStack(thread, 0, true); - stack.setDepth(2, true); + stack.setDepth(0, 2, true); } List frames = stack.getFrames(0); assertEquals(2, frames.size()); - assertEquals(stack.getFrame(0, false), frames.get(0)); - assertEquals(stack.getFrame(1, false), frames.get(1)); + assertEquals(stack.getFrame(0, 0, false), frames.get(0)); + assertEquals(stack.getFrame(0, 1, false), frames.get(1)); } @Test @@ -219,7 +207,7 @@ public class DBTraceStackManagerTest extends AbstractGhidraHeadlessIntegrationTe try (Transaction tx = b.startTransaction()) { thread = b.getOrAddThread("Threads[1]", 0); stack = stackManager.getStack(thread, 0, true); - stack.setDepth(2, true); + stack.setDepth(0, 2, true); } assertFalse(stack.isDeleted()); @@ -242,7 +230,7 @@ public class DBTraceStackManagerTest extends AbstractGhidraHeadlessIntegrationTe try (Transaction tx = b.startTransaction()) { thread = b.getOrAddThread("Threads[1]", 0); stack = stackManager.getStack(thread, 0, true); - frame = stack.getFrame(0, true); + frame = stack.getFrame(0, 0, true); } assertEquals(stack, frame.getStack()); @@ -257,9 +245,9 @@ public class DBTraceStackManagerTest extends AbstractGhidraHeadlessIntegrationTe try (Transaction tx = b.startTransaction()) { thread = b.getOrAddThread("Threads[1]", 0); stack = stackManager.getStack(thread, 0, true); - stack.setDepth(2, true); - frame0 = stack.getFrame(0, false); - frame1 = stack.getFrame(1, false); + stack.setDepth(0, 2, true); + frame0 = stack.getFrame(0, 0, false); + frame1 = stack.getFrame(0, 1, false); } assertEquals(0, frame0.getLevel()); @@ -274,8 +262,8 @@ public class DBTraceStackManagerTest extends AbstractGhidraHeadlessIntegrationTe try (Transaction tx = b.startTransaction()) { thread = b.getOrAddThread("Threads[1]", 0); stack = stackManager.getStack(thread, 0, true); - stack.setDepth(1, true); - frame = stack.getFrame(0, false); + stack.setDepth(0, 1, true); + frame = stack.getFrame(0, 0, false); assertNull(frame.getProgramCounter(Long.MAX_VALUE)); frame.setProgramCounter(Lifespan.ALL, b.addr(0x00400123)); @@ -292,8 +280,8 @@ public class DBTraceStackManagerTest extends AbstractGhidraHeadlessIntegrationTe try (Transaction tx = b.startTransaction()) { thread = b.getOrAddThread("Threads[1]", 0); stack = stackManager.getStack(thread, 0, true); - stack.setDepth(1, true); - frame = stack.getFrame(0, false); + stack.setDepth(0, 1, true); + frame = stack.getFrame(0, 0, false); // NB. Object-mode sets comment at pc in listing, not on frame itself frame.setProgramCounter(Lifespan.ALL, b.addr(0x00400123)); diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/thread/DBTraceThreadManagerTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/thread/DBTraceThreadManagerTest.java index d0f74c34f0..f13fd83a18 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/thread/DBTraceThreadManagerTest.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/thread/DBTraceThreadManagerTest.java @@ -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. @@ -140,7 +140,8 @@ public class DBTraceThreadManagerTest extends AbstractGhidraHeadlessIntegrationT assertEquals(Set.of(), threadManager.getLiveThreads(-1)); assertEquals(Set.of(thread1, thread2), threadManager.getLiveThreads(0)); assertEquals(Set.of(thread1, thread2), threadManager.getLiveThreads(9)); - // NB. Destruction is excluded - assertEquals(Set.of(thread1), threadManager.getLiveThreads(10)); + // NB. Destruction is included + assertEquals(Set.of(thread1, thread2), threadManager.getLiveThreads(10)); + assertEquals(Set.of(thread1), threadManager.getLiveThreads(11)); } } diff --git a/Ghidra/Test/DebuggerIntegrationTest/src/screen/java/ghidraclass/debugger/screenshot/TutorialDebuggerScreenShots.java b/Ghidra/Test/DebuggerIntegrationTest/src/screen/java/ghidraclass/debugger/screenshot/TutorialDebuggerScreenShots.java index b978acc640..28d89edaab 100644 --- a/Ghidra/Test/DebuggerIntegrationTest/src/screen/java/ghidraclass/debugger/screenshot/TutorialDebuggerScreenShots.java +++ b/Ghidra/Test/DebuggerIntegrationTest/src/screen/java/ghidraclass/debugger/screenshot/TutorialDebuggerScreenShots.java @@ -330,7 +330,7 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator } }) .distinct() - .filter(l -> expression.equals(l.getExpression())) + .filter(l -> expression.equals(l.getExpression(flatDbg.getCurrentSnap()))) .count() == 1); } @@ -359,6 +359,7 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator } protected Address navigateToBreakpoint(String expression) { + long snap = flatDbg.getCurrentSnap(); TraceBreakpoint bp = flatDbg.getAllBreakpoints() .stream() .flatMap(l -> l.getTraceBreakpoints().stream()) @@ -367,10 +368,10 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator down.accept(oloc); } }) - .filter(l -> expression.equals(l.getSpecification().getExpression())) + .filter(l -> expression.equals(l.getSpecification().getExpression(snap))) .findAny() .get(); - Address dynAddr = bp.getMinAddress(); + Address dynAddr = bp.getMinAddress(snap); flatDbg.goToDynamic(dynAddr); return dynAddr; } @@ -388,9 +389,10 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator protected Program importModule(TraceModule module) throws Throwable { Program prog = null; try { + long snap = flatDbg.getCurrentSnap(); MessageLog log = new MessageLog(); LoadResults result = AutoImporter.importByUsingBestGuess( - new File(module.getName()), env.getProject(), "/", this, log, monitor); + new File(module.getName(snap)), env.getProject(), "/", this, log, monitor); result.save(env.getProject(), this, log, monitor); prog = result.getPrimaryDomainObject(); GhidraProgramUtilities.markProgramNotToAskToAnalyze(prog); @@ -435,7 +437,8 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator // This module might be symlinked, so module name and file name may not match. DebuggerStaticMappingService mappings = tool.getService(DebuggerStaticMappingService.class); - ModuleMapProposal proposal = mappings.proposeModuleMap(modLibC, progLibC); + ModuleMapProposal proposal = + mappings.proposeModuleMap(modLibC, flatDbg.getCurrentSnap(), progLibC); try (Transaction tx = modLibC.getTrace().openTransaction("Map")) { mappings.addModuleMappings(proposal.computeMap().values(), monitor, true); } @@ -461,7 +464,8 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator // This module might be symlinked, so module name and file name may not match. DebuggerStaticMappingService mappings = tool.getService(DebuggerStaticMappingService.class); - ModuleMapProposal proposal = mappings.proposeModuleMap(modLibC, progLibC); + ModuleMapProposal proposal = + mappings.proposeModuleMap(modLibC, flatDbg.getCurrentSnap(), progLibC); try (Transaction tx = modLibC.getTrace().openTransaction("Map")) { mappings.addModuleMappings(proposal.computeMap().values(), monitor, true); } @@ -574,7 +578,8 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator // This module might be symlinked, so module name and file name may not match. DebuggerStaticMappingService mappings = tool.getService(DebuggerStaticMappingService.class); - ModuleMapProposal proposal = mappings.proposeModuleMap(modLibC, progLibC); + ModuleMapProposal proposal = + mappings.proposeModuleMap(modLibC, flatDbg.getCurrentSnap(), progLibC); try (Transaction tx = modLibC.getTrace().openTransaction("Map")) { mappings.addModuleMappings(proposal.computeMap().values(), monitor, true); } @@ -596,7 +601,8 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator // This module might be symlinked, so module name and file name may not match. DebuggerStaticMappingService mappings = tool.getService(DebuggerStaticMappingService.class); - ModuleMapProposal proposal = mappings.proposeModuleMap(modLibC, progLibC); + ModuleMapProposal proposal = + mappings.proposeModuleMap(modLibC, flatDbg.getCurrentSnap(), progLibC); try (Transaction tx = modLibC.getTrace().openTransaction("Map")) { mappings.addModuleMappings(proposal.computeMap().values(), monitor, true); } @@ -642,14 +648,14 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator RemoteMethod refreshSections = result.connection().getMethods().get("refresh_sections"); refreshSections.invoke(Map.of("node", modTermmines.getObject())); - TraceSection secTermminesData = modTermmines.getSectionByName(".data"); - flatDbg.readMemory(secTermminesData.getStart(), - (int) secTermminesData.getRange().getLength(), monitor); + TraceSection secTermminesData = modTermmines.getSectionByName(snapA, ".data"); + flatDbg.readMemory(secTermminesData.getStart(snapA), + (int) secTermminesData.getRange(snapA).getLength(), monitor); flatDbg.resume(); // rand.1 Thread.sleep(500); - flatDbg.readMemory(secTermminesData.getStart(), - (int) secTermminesData.getRange().getLength(), monitor); + flatDbg.readMemory(secTermminesData.getStart(snapA), + (int) secTermminesData.getRange(snapA).getLength(), monitor); performAction("Compare", PluginUtils.getPluginNameFromClass(DebuggerTraceViewDiffPlugin.class), false); @@ -678,14 +684,15 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator RemoteMethod refreshSections = result.connection().getMethods().get("refresh_sections"); refreshSections.invoke(Map.of("node", modTermmines.getObject())); - TraceSection secTermminesData = modTermmines.getSectionByName(".data"); - flatDbg.readMemory(secTermminesData.getStart(), - (int) secTermminesData.getRange().getLength(), monitor); + TraceSection secTermminesData = modTermmines.getSectionByName(snapA, ".data"); + flatDbg.readMemory(secTermminesData.getStart(snapA), + (int) secTermminesData.getRange(snapA).getLength(), monitor); flatDbg.resume(); // rand.1 flatDbg.waitForBreak(1000, TimeUnit.MILLISECONDS); - flatDbg.readMemory(secTermminesData.getStart(), - (int) secTermminesData.getRange().getLength(), monitor); + // snapA suffices, since section shouldn't have moved + flatDbg.readMemory(secTermminesData.getStart(snapA), + (int) secTermminesData.getRange(snapA).getLength(), monitor); performAction("Compare", PluginUtils.getPluginNameFromClass(DebuggerTraceViewDiffPlugin.class), false); @@ -705,10 +712,10 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator } }); waitForCondition(() -> actionNextDiff.isEnabled()); - flatDbg.goToDynamic(secTermminesData.getStart()); + flatDbg.goToDynamic(secTermminesData.getStart(snapA)); // Because auto-track is a little broken right now Thread.sleep(500); - flatDbg.goToDynamic(secTermminesData.getStart()); + flatDbg.goToDynamic(secTermminesData.getStart(snapA)); performAction(actionNextDiff); @@ -743,7 +750,8 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator // This module might be symlinked, so module name and file name may not match. DebuggerStaticMappingService mappings = tool.getService(DebuggerStaticMappingService.class); - ModuleMapProposal proposal = mappings.proposeModuleMap(modLibC, progLibC); + ModuleMapProposal proposal = + mappings.proposeModuleMap(modLibC, flatDbg.getCurrentSnap(), progLibC); try (Transaction tx = modLibC.getTrace().openTransaction("Map")) { mappings.addModuleMappings(proposal.computeMap().values(), monitor, true); } @@ -757,16 +765,17 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator @Test public void testMemoryMap_CopyNcursesInto() throws Throwable { launchProgramInGdb(); + long snap = flatDbg.getCurrentSnap(); TraceModule modNcurses = flatDbg.getCurrentTrace() .getModuleManager() .getAllModules() .stream() - .filter(m -> m.getName().contains("ncurses")) + .filter(m -> m.getName(snap).contains("ncurses")) .findAny() .get(); DebuggerListingService listings = tool.getService(DebuggerListingService.class); - runSwing(() -> listings - .setCurrentSelection(new ProgramSelection(new AddressSet(modNcurses.getRange())))); + runSwing(() -> listings.setCurrentSelection( + new ProgramSelection(new AddressSet(modNcurses.getRange(snap))))); DebuggerListingProvider listingProvider = waitForComponentProvider(DebuggerListingProvider.class); performAction("Copy Into New Program", diff --git a/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/dbgeng/rmi/AbstractDbgEngTraceRmiTest.java b/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/dbgeng/rmi/AbstractDbgEngTraceRmiTest.java index 105df7fc74..b599012a2f 100644 --- a/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/dbgeng/rmi/AbstractDbgEngTraceRmiTest.java +++ b/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/dbgeng/rmi/AbstractDbgEngTraceRmiTest.java @@ -64,6 +64,9 @@ public abstract class AbstractDbgEngTraceRmiTest extends AbstractGhidraHeadedDeb protected static final int TIMEOUT_SECONDS = 300; protected static final int QUIT_TIMEOUT_MS = 1000; + /** Some snapshot likely to exceed the latest */ + protected static final long SNAP = 100; + protected static boolean didSetupPython = false; public static final String INSTRUMENT_STATE = """ @@ -189,8 +192,7 @@ public abstract class AbstractDbgEngTraceRmiTest extends AbstractGhidraHeadedDeb } } - protected record ExecInPython(Process python, CompletableFuture future) { - } + protected record ExecInPython(Process python, CompletableFuture future) {} @SuppressWarnings("resource") // Do not close stdin protected ExecInPython execInPython(String script) throws IOException { @@ -349,8 +351,7 @@ public abstract class AbstractDbgEngTraceRmiTest extends AbstractGhidraHeadedDeb return xout.split(head)[1].split("---")[0].replace("(python)", "").trim(); } - record MemDump(long address, byte[] data) { - } + record MemDump(long address, byte[] data) {} protected MemDump parseHexDump(String dump) throws IOException { // First, get the address. Assume contiguous, so only need top line. @@ -374,8 +375,7 @@ public abstract class AbstractDbgEngTraceRmiTest extends AbstractGhidraHeadedDeb return new MemDump(address, buf.toByteArray()); } - record RegDump() { - } + record RegDump() {} protected RegDump parseRegDump(String dump) { return new RegDump(); diff --git a/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/dbgeng/rmi/DbgEngCommandsTest.java b/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/dbgeng/rmi/DbgEngCommandsTest.java index b3cfbf380c..53705a1449 100644 --- a/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/dbgeng/rmi/DbgEngCommandsTest.java +++ b/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/dbgeng/rmi/DbgEngCommandsTest.java @@ -46,7 +46,8 @@ import ghidra.trace.model.listing.TraceCodeSpace; import ghidra.trace.model.listing.TraceData; import ghidra.trace.model.memory.*; import ghidra.trace.model.modules.TraceModule; -import ghidra.trace.model.target.*; +import ghidra.trace.model.target.TraceObject; +import ghidra.trace.model.target.TraceObjectValue; import ghidra.trace.model.target.path.KeyPath; import ghidra.trace.model.target.path.PathFilter; import ghidra.trace.model.thread.TraceThread; @@ -1099,8 +1100,8 @@ public class DbgEngCommandsTest extends AbstractDbgEngTraceRmiTest { // Would be nice to control / validate the specifics Collection all = tb.trace.getModuleManager().getAllModules(); TraceModule modBash = - Unique.assertOne(all.stream().filter(m -> m.getName().contains("notepad"))); - assertNotEquals(tb.addr(0), Objects.requireNonNull(modBash.getBase())); + Unique.assertOne(all.stream().filter(m -> m.getName(SNAP).contains("notepad"))); + assertNotEquals(tb.addr(0), Objects.requireNonNull(modBash.getBase(SNAP))); } } diff --git a/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/dbgeng/rmi/DbgEngMethodsTest.java b/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/dbgeng/rmi/DbgEngMethodsTest.java index f338c63664..0d186b8258 100644 --- a/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/dbgeng/rmi/DbgEngMethodsTest.java +++ b/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/dbgeng/rmi/DbgEngMethodsTest.java @@ -343,9 +343,9 @@ public class DbgEngMethodsTest extends AbstractDbgEngTraceRmiTest { // Would be nice to control / validate the specifics Collection all = tb.trace.getModuleManager().getAllModules(); - TraceModule modBash = - Unique.assertOne(all.stream().filter(m -> m.getName().contains("notepad.exe"))); - assertNotEquals(tb.addr(0), Objects.requireNonNull(modBash.getBase())); + TraceModule modBash = Unique.assertOne( + all.stream().filter(m -> m.getName(SNAP).contains("notepad.exe"))); + assertNotEquals(tb.addr(0), Objects.requireNonNull(modBash.getBase(SNAP))); } } } diff --git a/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/drgn/rmi/AbstractDrgnTraceRmiTest.java b/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/drgn/rmi/AbstractDrgnTraceRmiTest.java index fbc6920108..a53f051966 100644 --- a/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/drgn/rmi/AbstractDrgnTraceRmiTest.java +++ b/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/drgn/rmi/AbstractDrgnTraceRmiTest.java @@ -15,8 +15,9 @@ */ package agent.drgn.rmi; -import static org.junit.Assert.*; -import static org.junit.Assume.*; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; import java.io.FileWriter; import java.io.IOException; @@ -59,12 +60,15 @@ public abstract class AbstractDrgnTraceRmiTest extends AbstractGhidraHeadedDebug os.environ['OPT_TARGET_IMG'] = '$CORE' from ghidradrgn.commands import * """; - + // Connecting should be the first thing the script does, so use a tight timeout. protected static final int CONNECT_TIMEOUT_MS = 3000; protected static final int TIMEOUT_SECONDS = 30000; protected static final int QUIT_TIMEOUT_MS = 1000; + /** Some snapshot likely to exceed the latest */ + protected static final long SNAP = 100; + protected static boolean didSetupPython = false; protected TraceRmiService traceRmi; @@ -147,7 +151,8 @@ public abstract class AbstractDrgnTraceRmiTest extends AbstractGhidraHeadedDebug protected record PythonResult(boolean timedOut, int exitCode, String stdout, String stderr) { protected String handle() { - if (stderr.contains("RuntimeError") || stderr.contains(" Error") || (0 != exitCode && 1 != exitCode && 143 != exitCode)) { + if (stderr.contains("RuntimeError") || stderr.contains(" Error") || + (0 != exitCode && 1 != exitCode && 143 != exitCode)) { throw new PythonError(exitCode, stdout, stderr); } System.out.println("--stdout--"); @@ -158,8 +163,7 @@ public abstract class AbstractDrgnTraceRmiTest extends AbstractGhidraHeadedDebug } } - protected record ExecInDrgn(Process python, CompletableFuture future) { - } + protected record ExecInDrgn(Process python, CompletableFuture future) {} @SuppressWarnings("resource") // Do not close stdin protected ExecInDrgn execInDrgn(String script) throws IOException { @@ -169,7 +173,7 @@ public abstract class AbstractDrgnTraceRmiTest extends AbstractGhidraHeadedDebug FileWriter fw = new FileWriter(fp.toFile()); fw.write(script); fw.close(); - ProcessBuilder pb = new ProcessBuilder(pythonPath.toString(), "-c", + ProcessBuilder pb = new ProcessBuilder(pythonPath.toString(), "-c", rf.getAbsolutePath(), fp.toFile().getAbsolutePath()); setPythonPath(pb); @@ -375,5 +379,4 @@ public abstract class AbstractDrgnTraceRmiTest extends AbstractGhidraHeadedDebug throw new AssertionFailedError(failureMessage); } - } diff --git a/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/drgn/rmi/DrgnCommandsTest.java b/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/drgn/rmi/DrgnCommandsTest.java index 0be0c6a0ad..20afff27c8 100644 --- a/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/drgn/rmi/DrgnCommandsTest.java +++ b/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/drgn/rmi/DrgnCommandsTest.java @@ -17,7 +17,7 @@ package agent.drgn.rmi; import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; -import static org.junit.Assume.*; +import static org.junit.Assume.assumeFalse; import java.util.*; import java.util.concurrent.atomic.AtomicReference; @@ -54,7 +54,7 @@ import ghidra.trace.model.time.TraceSnapshot; import ghidra.util.Msg; public class DrgnCommandsTest extends AbstractDrgnTraceRmiTest { - + //@Test public void testManual() throws Exception { TraceRmiAcceptor acceptor = traceRmi.acceptOne(null); @@ -156,7 +156,7 @@ public class DrgnCommandsTest extends AbstractDrgnTraceRmiTest { } } - @Test + @Test public void testStopTrace() throws Exception { runThrowError(addr -> """ %s @@ -220,26 +220,25 @@ public class DrgnCommandsTest extends AbstractDrgnTraceRmiTest { extractOutSection(out, "---Disconnect---")); } - @Test + @Test public void testLcsp() throws Exception { - String out = runThrowError(addr -> - """ - %s - ghidra_trace_connect('%s') - print('---Import---') - ghidra_trace_info_lcsp() - print('---Create---') - ghidra_trace_create() - print('---File---') - ghidra_trace_info_lcsp() - util.set_convenience_variable('ghidra-language','DATA:BE:64:default') - print('---Language---') - ghidra_trace_info_lcsp() - util.set_convenience_variable('ghidra-compiler','posStack') - print('---Compiler---') - ghidra_trace_info_lcsp() - quit() - """.formatted(PREAMBLE, addr)); + String out = runThrowError(addr -> """ + %s + ghidra_trace_connect('%s') + print('---Import---') + ghidra_trace_info_lcsp() + print('---Create---') + ghidra_trace_create() + print('---File---') + ghidra_trace_info_lcsp() + util.set_convenience_variable('ghidra-language','DATA:BE:64:default') + print('---Language---') + ghidra_trace_info_lcsp() + util.set_convenience_variable('ghidra-compiler','posStack') + print('---Compiler---') + ghidra_trace_info_lcsp() + quit() + """.formatted(PREAMBLE, addr)); assertEquals(""" Selected Ghidra language: x86:LE:64:default @@ -858,8 +857,8 @@ public class DrgnCommandsTest extends AbstractDrgnTraceRmiTest { // Would be nice to control / validate the specifics Collection all = tb.trace.getModuleManager().getAllModules(); TraceModule modBash = - Unique.assertOne(all.stream().filter(m -> m.getName().contains("helloWorld"))); - assertNotEquals(tb.addr(0), Objects.requireNonNull(modBash.getBase())); + Unique.assertOne(all.stream().filter(m -> m.getName(SNAP).contains("helloWorld"))); + assertNotEquals(tb.addr(0), Objects.requireNonNull(modBash.getBase(SNAP))); } } diff --git a/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/drgn/rmi/DrgnMethodsTest.java b/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/drgn/rmi/DrgnMethodsTest.java index c1bcadb221..20e807bb81 100644 --- a/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/drgn/rmi/DrgnMethodsTest.java +++ b/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/drgn/rmi/DrgnMethodsTest.java @@ -15,9 +15,9 @@ */ package agent.drgn.rmi; -import static org.hamcrest.Matchers.*; +import static org.hamcrest.Matchers.greaterThan; import static org.junit.Assert.*; -import static org.junit.Assume.*; +import static org.junit.Assume.assumeFalse; import java.util.*; @@ -49,7 +49,7 @@ public class DrgnMethodsTest extends AbstractDrgnTraceRmiTest { assertEquals(false, execute.parameters().get("to_string").getDefaultValue()); assertEquals("11\n", execute.invoke(Map.of( - "cmd", "print(3+4*2)", + "cmd", "print(3+4*2)", "to_string", true))); } } @@ -83,17 +83,17 @@ public class DrgnMethodsTest extends AbstractDrgnTraceRmiTest { .map(p -> p.getDestination(null)) .toList(); assertEquals(1, list.size()); - + ResourceFile rf = Application.getModuleDataFile("TestResources", CORE); attachCore.invoke(Map.of("processes", processes, "core", rf.getAbsolutePath())); refreshProcesses.invoke(Map.of("node", processes)); - + list = tb.trace.getObjectManager() .getValuePaths(Lifespan.at(getMaxSnap()), PathFilter.parse("Processes[]")) .map(p -> p.getDestination(null)) .toList(); assertEquals(2, list.size()); - + } } } @@ -237,9 +237,9 @@ public class DrgnMethodsTest extends AbstractDrgnTraceRmiTest { // Would be nice to control / validate the specifics Collection all = tb.trace.getModuleManager().getAllModules(); - TraceModule mod = - Unique.assertOne(all.stream().filter(m -> m.getName().contains("helloWorld"))); - assertNotEquals(tb.addr(0), Objects.requireNonNull(mod.getBase())); + TraceModule mod = Unique.assertOne( + all.stream().filter(m -> m.getName(SNAP).contains("helloWorld"))); + assertNotEquals(tb.addr(0), Objects.requireNonNull(mod.getBase(SNAP))); } } } diff --git a/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/gdb/rmi/AbstractGdbTraceRmiTest.java b/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/gdb/rmi/AbstractGdbTraceRmiTest.java index 3e62dc151c..0b091d8de7 100644 --- a/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/gdb/rmi/AbstractGdbTraceRmiTest.java +++ b/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/gdb/rmi/AbstractGdbTraceRmiTest.java @@ -49,7 +49,8 @@ import ghidra.pty.testutil.DummyProc; import ghidra.trace.model.TraceExecutionState; import ghidra.trace.model.breakpoint.TraceBreakpointKind; import ghidra.trace.model.breakpoint.TraceBreakpointKind.TraceBreakpointKindSet; -import ghidra.trace.model.target.*; +import ghidra.trace.model.target.TraceObject; +import ghidra.trace.model.target.TraceObjectValue; import ghidra.trace.model.target.path.KeyPath; import ghidra.util.Msg; import ghidra.util.NumericUtilities; @@ -91,6 +92,9 @@ public abstract class AbstractGdbTraceRmiTest extends AbstractGhidraHeadedDebugg end python gdb.events.cont.connect(lambda e: gdb.execute("set-running"))"""; + /** Some snapshot likely to exceed the latest */ + protected static final long SNAP = 100; + protected TraceRmiService traceRmi; private Path gdbPath; private Path outFile; diff --git a/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/gdb/rmi/GdbCommandsTest.java b/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/gdb/rmi/GdbCommandsTest.java index cc4ad2fa7a..2561b5ee6b 100644 --- a/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/gdb/rmi/GdbCommandsTest.java +++ b/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/gdb/rmi/GdbCommandsTest.java @@ -48,7 +48,8 @@ import ghidra.trace.model.listing.TraceCodeSpace; import ghidra.trace.model.listing.TraceData; import ghidra.trace.model.memory.*; import ghidra.trace.model.modules.TraceModule; -import ghidra.trace.model.target.*; +import ghidra.trace.model.target.TraceObject; +import ghidra.trace.model.target.TraceObjectValue; import ghidra.trace.model.target.path.KeyPath; import ghidra.trace.model.target.path.PathFilter; import ghidra.trace.model.time.TraceSnapshot; @@ -1131,8 +1132,8 @@ public class GdbCommandsTest extends AbstractGdbTraceRmiTest { // Would be nice to control / validate the specifics Collection all = tb.trace.getModuleManager().getAllModules(); TraceModule modBash = - Unique.assertOne(all.stream().filter(m -> m.getName().contains("bash"))); - assertNotEquals(tb.addr(0), Objects.requireNonNull(modBash.getBase())); + Unique.assertOne(all.stream().filter(m -> m.getName(SNAP).contains("bash"))); + assertNotEquals(tb.addr(0), Objects.requireNonNull(modBash.getBase(SNAP))); } } diff --git a/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/gdb/rmi/GdbMethodsTest.java b/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/gdb/rmi/GdbMethodsTest.java index 2f1e851ecf..776ce01f2d 100644 --- a/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/gdb/rmi/GdbMethodsTest.java +++ b/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/gdb/rmi/GdbMethodsTest.java @@ -405,8 +405,8 @@ public class GdbMethodsTest extends AbstractGdbTraceRmiTest { // Would be nice to control / validate the specifics Collection all = tb.trace.getModuleManager().getAllModules(); TraceModule modBash = - Unique.assertOne(all.stream().filter(m -> m.getName().contains("bash"))); - assertNotEquals(tb.addr(0), Objects.requireNonNull(modBash.getBase())); + Unique.assertOne(all.stream().filter(m -> m.getName(SNAP).contains("bash"))); + assertNotEquals(tb.addr(0), Objects.requireNonNull(modBash.getBase(SNAP))); } } } diff --git a/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/java/rmi/AbstractJavaTraceRmiTest.java b/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/java/rmi/AbstractJavaTraceRmiTest.java index b40e33c755..af16da241e 100644 --- a/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/java/rmi/AbstractJavaTraceRmiTest.java +++ b/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/java/rmi/AbstractJavaTraceRmiTest.java @@ -90,6 +90,9 @@ public abstract class AbstractJavaTraceRmiTest extends AbstractGhidraHeadedDebug protected static final long EXT_TIMEOUT_MS = 5000; protected static final long EXT_RETRY_MS = 500; + /** Some snapshot likely to exceed the latest */ + protected static final long SNAP = 100; + protected TraceRmiService traceRmi; private Path jshellPath; private Path outFile; diff --git a/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/java/rmi/JavaCommandsTest.java b/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/java/rmi/JavaCommandsTest.java index f3b04cee17..13a401783c 100644 --- a/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/java/rmi/JavaCommandsTest.java +++ b/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/java/rmi/JavaCommandsTest.java @@ -41,7 +41,8 @@ import ghidra.trace.database.ToyDBTraceBuilder; import ghidra.trace.model.*; import ghidra.trace.model.memory.*; import ghidra.trace.model.modules.TraceModule; -import ghidra.trace.model.target.*; +import ghidra.trace.model.target.TraceObject; +import ghidra.trace.model.target.TraceObjectValue; import ghidra.trace.model.target.path.KeyPath; import ghidra.trace.model.target.path.PathFilter; import ghidra.trace.model.thread.TraceThread; @@ -894,9 +895,9 @@ public class JavaCommandsTest extends AbstractJavaTraceRmiTest { try (ManagedDomainObject mdo = openDomainObject("/New Traces/HelloWorld.class")) { tb = new ToyDBTraceBuilder((Trace) mdo.get()); Collection all = tb.trace.getModuleManager().getAllModules(); - TraceModule mod = - Unique.assertOne(all.stream().filter(m -> m.getName().contains("Thread.class"))); - assertEquals(tb.addr(0x1000), Objects.requireNonNull(mod.getBase())); + TraceModule mod = Unique.assertOne( + all.stream().filter(m -> m.getName(SNAP).contains("Thread.class"))); + assertEquals(tb.addr(0x1000), Objects.requireNonNull(mod.getBase(SNAP))); } } diff --git a/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/lldb/rmi/AbstractLldbTraceRmiTest.java b/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/lldb/rmi/AbstractLldbTraceRmiTest.java index a6544e6ed1..c206d35732 100644 --- a/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/lldb/rmi/AbstractLldbTraceRmiTest.java +++ b/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/lldb/rmi/AbstractLldbTraceRmiTest.java @@ -106,6 +106,9 @@ public abstract class AbstractLldbTraceRmiTest extends AbstractGhidraHeadedDebug protected static final int TIMEOUT_SECONDS = 300; protected static final int QUIT_TIMEOUT_MS = 1000; + /** Some snapshot likely to exceed the latest */ + protected static final long SNAP = 100; + protected TraceRmiService traceRmi; private Path lldbPath; diff --git a/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/lldb/rmi/LldbCommandsTest.java b/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/lldb/rmi/LldbCommandsTest.java index 6e6f2fc918..27b5368af4 100644 --- a/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/lldb/rmi/LldbCommandsTest.java +++ b/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/lldb/rmi/LldbCommandsTest.java @@ -1172,8 +1172,8 @@ public class LldbCommandsTest extends AbstractLldbTraceRmiTest { // Would be nice to control / validate the specifics Collection all = tb.trace.getModuleManager().getAllModules(); TraceModule modExpPrint = - Unique.assertOne(all.stream().filter(m -> m.getName().contains("expPrint"))); - assertNotEquals(tb.addr(0), Objects.requireNonNull(modExpPrint.getBase())); + Unique.assertOne(all.stream().filter(m -> m.getName(SNAP).contains("expPrint"))); + assertNotEquals(tb.addr(0), Objects.requireNonNull(modExpPrint.getBase(SNAP))); } } diff --git a/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/lldb/rmi/LldbMethodsTest.java b/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/lldb/rmi/LldbMethodsTest.java index 934f6d7b0c..900544e337 100644 --- a/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/lldb/rmi/LldbMethodsTest.java +++ b/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/lldb/rmi/LldbMethodsTest.java @@ -345,8 +345,8 @@ public class LldbMethodsTest extends AbstractLldbTraceRmiTest { // Would be nice to control / validate the specifics Collection all = tb.trace.getModuleManager().getAllModules(); TraceModule modExpPrint = Unique.assertOne( - all.stream().filter(m -> m.getName().contains("expPrint"))); - assertNotEquals(tb.addr(0), Objects.requireNonNull(modExpPrint.getBase())); + all.stream().filter(m -> m.getName(SNAP).contains("expPrint"))); + assertNotEquals(tb.addr(0), Objects.requireNonNull(modExpPrint.getBase(SNAP))); } } } diff --git a/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/app/plugin/core/debug/gui/AbstractGhidraHeadedDebuggerIntegrationTest.java b/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/app/plugin/core/debug/gui/AbstractGhidraHeadedDebuggerIntegrationTest.java index a78da09128..9a84b619f9 100644 --- a/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/app/plugin/core/debug/gui/AbstractGhidraHeadedDebuggerIntegrationTest.java +++ b/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/app/plugin/core/debug/gui/AbstractGhidraHeadedDebuggerIntegrationTest.java @@ -42,8 +42,9 @@ import ghidra.trace.model.breakpoint.TraceBreakpointKind; import ghidra.trace.model.breakpoint.TraceBreakpointKind.TraceBreakpointKindSet; import ghidra.trace.model.memory.TraceMemoryState; import ghidra.trace.model.stack.TraceObjectStackFrame; -import ghidra.trace.model.target.*; +import ghidra.trace.model.target.TraceObject; import ghidra.trace.model.target.TraceObject.ConflictResolution; +import ghidra.trace.model.target.TraceObjectManager; import ghidra.trace.model.target.path.KeyPath; import ghidra.trace.model.target.schema.*; import ghidra.trace.model.target.schema.TraceObjectSchema.SchemaName; @@ -486,8 +487,16 @@ public class AbstractGhidraHeadedDebuggerIntegrationTest } } - protected TraceObject findAndCreateFreeBreakpointSpec(TraceObjectManager objs) { + protected TraceObject findAndCreateFreeBreakpointSpec(TraceObjectManager objs, Integer id) { KeyPath brkConPath = KeyPath.parse("Processes[1].Breakpoints"); + if (id != null) { + KeyPath path = brkConPath.index(id); + TraceObject exists = objs.getObjectByCanonicalPath(path); + if (exists != null) { + return exists; + } + return objs.createObject(path); + } for (int i = 1; i < 10; i++) { KeyPath path = brkConPath.index(i); TraceObject exists = objs.getObjectByCanonicalPath(path); @@ -499,9 +508,9 @@ public class AbstractGhidraHeadedDebuggerIntegrationTest } protected TraceObject addBreakpointAndLoc(TraceObjectManager objs, Lifespan lifespan, - AddressRange range, Set kinds) { + AddressRange range, Set kinds, Integer id) { try (Transaction tx = objs.getTrace().openTransaction("Add breakpoint")) { - TraceObject spec = findAndCreateFreeBreakpointSpec(objs); + TraceObject spec = findAndCreateFreeBreakpointSpec(objs, id); spec.setAttribute(lifespan, "_kinds", TraceBreakpointKindSet.encode(kinds)); spec.setAttribute(lifespan, "_expr", "*0x" + range.getMinAddress()); @@ -516,4 +525,9 @@ public class AbstractGhidraHeadedDebuggerIntegrationTest return spec; } } + + protected TraceObject addBreakpointAndLoc(TraceObjectManager objs, Lifespan lifespan, + AddressRange range, Set kinds) { + return addBreakpointAndLoc(objs, lifespan, range, kinds, null); + } } diff --git a/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyActionsPluginTest.java b/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyActionsPluginTest.java index 341ba69194..14cbba96bf 100644 --- a/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyActionsPluginTest.java +++ b/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyActionsPluginTest.java @@ -437,7 +437,7 @@ public class DebuggerCopyActionsPluginTest extends AbstractGhidraHeadedDebuggerI .addRegion("Processes[1].Memory[.text]", Lifespan.nowOn(0), tb.range(0x55550000, 0x5555ffff), Set.of(TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE)) - .setName("[.text]"); + .setName(0, "[.text]"); } TraceObject process = tb.obj("Processes[1]"); rmiCx.publishTarget(tool, tb.trace); diff --git a/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProviderTest.java b/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProviderTest.java index c3dd9d99d6..71092e1673 100644 --- a/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProviderTest.java +++ b/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProviderTest.java @@ -1192,7 +1192,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerInt TraceModule bin = tb.trace.getModuleManager() .addLoadedModule("/bin/bash", "/bin/bash", tb.range(0x00400000, 0x0041ffff), 0); - bin.addSection("bash[.text]", tb.range(0x00400000, 0x0040ffff)); + bin.addSection(0, "bash[.text]", tb.range(0x00400000, 0x0040ffff)); } waitForDomainObject(tb.trace); traceManager.activateTrace(tb.trace); @@ -1265,7 +1265,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerInt waitForPass(() -> assertEquals("modExe", listingProvider.locationLabel.getText())); try (Transaction tx = tb.startTransaction()) { - modExe.addSection(".text", tb.range(0x55550000, 0x555500ff)); + modExe.addSection(0, ".text", tb.range(0x55550000, 0x555500ff)); } waitForDomainObject(tb.trace); waitForPass(() -> assertEquals("modExe:.text", listingProvider.locationLabel.getText())); @@ -1389,8 +1389,8 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerInt thread = tb.getOrAddThread("Thread 1", 0); DBTraceStackManager sm = tb.trace.getStackManager(); TraceStack stack = sm.getStack(thread, 0, true); - stack.getFrame(0, true).setProgramCounter(Lifespan.ALL, tb.addr(0x00401234)); - stack.getFrame(1, true).setProgramCounter(Lifespan.ALL, tb.addr(0x00404321)); + stack.getFrame(0, 0, true).setProgramCounter(Lifespan.ALL, tb.addr(0x00401234)); + stack.getFrame(0, 1, true).setProgramCounter(Lifespan.ALL, tb.addr(0x00404321)); } waitForDomainObject(tb.trace); traceManager.activateThread(thread); @@ -1455,7 +1455,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerInt DBTraceStackManager sm = tb.trace.getStackManager(); TraceStack stack = sm.getStack(thread, 0, true); - stack.getFrame(0, true); + stack.getFrame(0, 0, true); } waitForDomainObject(tb.trace); traceManager.activate(DebuggerCoordinates.NOWHERE.thread(thread).snap(0)); @@ -1486,7 +1486,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerInt TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE); thread = tb.getOrAddThread("Thread 1", 0); TraceStack stack = sm.getStack(thread, 0, true); - stack.getFrame(0, true).setProgramCounter(Lifespan.ALL, tb.addr(0x00401234)); + stack.getFrame(0, 0, true).setProgramCounter(Lifespan.ALL, tb.addr(0x00401234)); } waitForDomainObject(tb.trace); traceManager.activateThread(thread); @@ -1496,7 +1496,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerInt try (Transaction tx = tb.startTransaction()) { TraceStack stack = sm.getStack(thread, 0, true); - stack.getFrame(0, true).setProgramCounter(Lifespan.ALL, tb.addr(0x00404321)); + stack.getFrame(0, 0, true).setProgramCounter(Lifespan.ALL, tb.addr(0x00404321)); } waitForDomainObject(tb.trace); diff --git a/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerMemoryBytesProviderTest.java b/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerMemoryBytesProviderTest.java index e2c1ffa879..6aa751402f 100644 --- a/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerMemoryBytesProviderTest.java +++ b/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerMemoryBytesProviderTest.java @@ -836,7 +836,7 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge waitForPass(() -> assertEquals("modExe", memBytesProvider.locationLabel.getText())); try (Transaction tx = tb.startTransaction()) { - modExe.addSection(".text", tb.range(0x55550000, 0x555500ff)); + modExe.addSection(0, ".text", tb.range(0x55550000, 0x555500ff)); } waitForDomainObject(tb.trace); waitForPass(() -> assertEquals("modExe:.text", memBytesProvider.locationLabel.getText())); @@ -917,8 +917,8 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge thread = tb.getOrAddThread("Thread 1", 0); DBTraceStackManager sm = tb.trace.getStackManager(); TraceStack stack = sm.getStack(thread, 0, true); - stack.getFrame(0, true).setProgramCounter(Lifespan.ALL, tb.addr(0x00401234)); - stack.getFrame(1, true).setProgramCounter(Lifespan.ALL, tb.addr(0x00404321)); + stack.getFrame(0, 0, true).setProgramCounter(Lifespan.ALL, tb.addr(0x00401234)); + stack.getFrame(0, 1, true).setProgramCounter(Lifespan.ALL, tb.addr(0x00404321)); } waitForDomainObject(tb.trace); traceManager.activateThread(thread); @@ -981,7 +981,7 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge DBTraceStackManager sm = tb.trace.getStackManager(); TraceStack stack = sm.getStack(thread, 0, true); - stack.getFrame(0, true); + stack.getFrame(0, 0, true); } waitForDomainObject(tb.trace); traceManager.activate(DebuggerCoordinates.NOWHERE.thread(thread).snap(0)); @@ -1012,7 +1012,7 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE); thread = tb.getOrAddThread("Thread 1", 0); TraceStack stack = sm.getStack(thread, 0, true); - stack.getFrame(0, true).setProgramCounter(Lifespan.ALL, tb.addr(0x00401234)); + stack.getFrame(0, 0, true).setProgramCounter(Lifespan.ALL, tb.addr(0x00401234)); } waitForDomainObject(tb.trace); traceManager.activateThread(thread); @@ -1022,7 +1022,7 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge try (Transaction tx = tb.startTransaction()) { TraceStack stack = sm.getStack(thread, 0, true); - stack.getFrame(0, true).setProgramCounter(Lifespan.ALL, tb.addr(0x00404321)); + stack.getFrame(0, 0, true).setProgramCounter(Lifespan.ALL, tb.addr(0x00404321)); } waitForDomainObject(tb.trace); diff --git a/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/app/plugin/core/debug/service/breakpoint/AbstractDebuggerLogicalBreakpointServiceTest.java b/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/app/plugin/core/debug/service/breakpoint/AbstractDebuggerLogicalBreakpointServiceTest.java index c980c80a7c..2b7a089529 100644 --- a/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/app/plugin/core/debug/service/breakpoint/AbstractDebuggerLogicalBreakpointServiceTest.java +++ b/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/app/plugin/core/debug/service/breakpoint/AbstractDebuggerLogicalBreakpointServiceTest.java @@ -139,7 +139,12 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest protected abstract void removeTextMapping(T t, Program program) throws Throwable; - protected abstract void addTargetSoftwareBreakpoint(T t, MR region) throws Throwable; + protected abstract void addTargetSoftwareBreakpoint(T t, MR region, int offset, Integer id) + throws Throwable; + + protected void addTargetSoftwareBreakpoint(T t, MR region) throws Throwable { + addTargetSoftwareBreakpoint(t, region, 0x123, null); + } protected abstract void removeTargetSoftwareBreakpoint(T t) throws Throwable; @@ -147,7 +152,7 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest protected abstract void terminateTarget(T t); - protected abstract TraceBreakpoint findLoc(Set locs, int index); + protected abstract TraceBreakpoint findLoc(long snap, Set locs, int index); protected abstract void handleToggleBreakpointInvocation(T target, TraceBreakpoint expectedBreakpoint, @@ -1320,6 +1325,44 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest assertEquals(0, breakpointService.getAllBreakpoints().size()); } + @Test + public void testReuseBreakpointKeyTraceOnly() throws Throwable { + createTarget1(); + Trace trace = getTrace(target1); + traceManager.openTrace(trace); + + MR text = addTargetTextRegion(target1); + addTargetSoftwareBreakpoint(target1, text); + waitOn(breakpointService.changesSettled()); + + assertLogicalBreakpointForLoneSoftwareBreakpoint(trace, 1); + + LogicalBreakpoint lb = Unique.assertOne(breakpointService.getAllBreakpoints()); + + int id = Integer.parseInt( + ((TraceObjectBreakpointLocation) Unique.assertOne(lb.getTraceBreakpoints(trace))) + .getSpecification() + .getObject() + .getCanonicalPath() + .index()); + + // Simulate a step, which should also cause snap advance in target + simulateTargetStep(target1); + + CompletableFuture delete = lb.delete(); + handleDeleteBreakpointInvocation(target1, Unique.assertOne(lb.getTraceBreakpoints(trace))); + waitOn(delete); + waitForDomainObject(trace); + waitOn(breakpointService.changesSettled()); + + assertEquals(0, breakpointService.getAllBreakpoints().size()); + + addTargetSoftwareBreakpoint(target1, text, 0x128, id); + waitOn(breakpointService.changesSettled()); + + assertLogicalBreakpointForLoneSoftwareBreakpoint(trace, 0x55550128, 1); + } + @Test public void testRecordThenCloseTraceOnly() throws Throwable { createTarget1(); @@ -1373,8 +1416,9 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest Set locs = lb.getTraceBreakpoints(); - TraceBreakpoint bpt0 = findLoc(locs, 0); - TraceBreakpoint bpt1 = findLoc(locs, 1); + long snap = getSnap(target1); + TraceBreakpoint bpt0 = findLoc(snap, locs, 0); + TraceBreakpoint bpt1 = findLoc(snap, locs, 1); CompletableFuture disable = breakpointService.disableLocs(Set.of(bpt0)); handleToggleBreakpointInvocation(target1, bpt0, false); waitOn(disable); @@ -1440,7 +1484,7 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest assertEquals(State.MIXED, lbEx.computeState().sameAdddress(lbRw.computeState())); } - protected void addTextMappingDead(Program p, ToyDBTraceBuilder tb) throws Throwable { + protected void addTextMappingDead(long snap, Program p, ToyDBTraceBuilder tb) throws Throwable { addProgramTextBlock(p); try (Transaction tid = tb.startTransaction()) { TraceMemoryRegion textRegion = tb.trace.getMemoryManager() @@ -1448,8 +1492,8 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest tb.range(0x55550000, 0x55550fff), Set.of(TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE)); DebuggerStaticMappingUtils.addMapping( - new DefaultTraceLocation(tb.trace, null, textRegion.getLifespan(), - textRegion.getMinAddress()), + new DefaultTraceLocation(tb.trace, null, Lifespan.nowOn(snap), + textRegion.getMinAddress(snap)), new ProgramLocation(p, addr(p, 0x00400000)), 0x1000, false); } waitForDomainObject(tb.trace); @@ -1473,7 +1517,7 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest intoProject(program); programManager.openProgram(program); - addTextMappingDead(program, tb); + addTextMappingDead(0, program, tb); addEnabledProgramBreakpointWithSleigh(program); waitOn(mappingService.changesSettled()); @@ -1489,7 +1533,7 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest TraceBreakpoint bpt = Unique.assertOne( tb.trace.getBreakpointManager().getBreakpointsAt(0, tb.addr(0x55550123))); - assertEquals("r0=0xbeef;", bpt.getEmuSleigh()); + assertEquals("r0=0xbeef;", bpt.getEmuSleigh(0)); } @Test @@ -1508,7 +1552,7 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest assertEquals("r0=0xbeef;", lb.getEmuSleigh()); - addTextMappingDead(program, tb); + addTextMappingDead(0, program, tb); waitOn(mappingService.changesSettled()); waitOn(breakpointService.changesSettled()); lb = Unique.assertOne( @@ -1521,7 +1565,7 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest TraceBreakpoint bpt = Unique.assertOne( tb.trace.getBreakpointManager().getBreakpointsAt(0, tb.addr(0x55550123))); - assertEquals("r0=0xbeef;", bpt.getEmuSleigh()); + assertEquals("r0=0xbeef;", bpt.getEmuSleigh(0)); } @Test @@ -1545,7 +1589,7 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest .addBreakpoint("Processes[1].Breakpoints[0]", Lifespan.nowOn(0), tb.addr(0x55550123), Set.of(), Set.of(TraceBreakpointKind.SW_EXECUTE), false /* emuEnabled defaults to true */, ""); - bpt.setEmuSleigh("r0=0xbeef;"); + bpt.setEmuSleigh(0, "r0=0xbeef;"); } waitForDomainObject(tb.trace); waitOn(mappingService.changesSettled()); @@ -1555,7 +1599,7 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest assertEquals("r0=0xbeef;", lb.getEmuSleigh()); - addTextMappingDead(program, tb); + addTextMappingDead(0, program, tb); waitOn(mappingService.changesSettled()); waitOn(breakpointService.changesSettled()); @@ -1600,7 +1644,7 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest tb.addr(0x55550123), Set.of(), Set.of(TraceBreakpointKind.SW_EXECUTE), false /* emuEnabled defaults to true */, ""); - bpt.setEmuSleigh("r0=0xbeef;"); + bpt.setEmuSleigh(0, "r0=0xbeef;"); waitForValue(() -> Unique.assertAtMostOne( breakpointService.getBreakpointsAt(tb.trace, tb.addr(0x55550123)))); diff --git a/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/app/plugin/core/debug/service/breakpoint/DebuggerRmiLogicalBreakpointServiceTest.java b/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/app/plugin/core/debug/service/breakpoint/DebuggerRmiLogicalBreakpointServiceTest.java index 56ec694d37..ec61930e2c 100644 --- a/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/app/plugin/core/debug/service/breakpoint/DebuggerRmiLogicalBreakpointServiceTest.java +++ b/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/app/plugin/core/debug/service/breakpoint/DebuggerRmiLogicalBreakpointServiceTest.java @@ -33,6 +33,8 @@ import ghidra.trace.model.breakpoint.*; import ghidra.trace.model.breakpoint.TraceBreakpointKind.TraceBreakpointKindSet; import ghidra.trace.model.memory.TraceObjectMemoryRegion; import ghidra.trace.model.modules.TraceStaticMapping; +import ghidra.trace.model.target.TraceObject; +import ghidra.trace.model.target.path.KeyPath; import ghidra.trace.model.time.TraceSnapshot; public class DebuggerRmiLogicalBreakpointServiceTest extends @@ -83,6 +85,9 @@ public class DebuggerRmiLogicalBreakpointServiceTest extends } waitForDomainObject(trace); rmiCx.setLastSnapshot(trace, snapshot.getKey()); + TraceObject thread1 = Objects.requireNonNull(trace.getObjectManager() + .getObjectByCanonicalPath(KeyPath.parse("Processes[1].Threads[1]"))); + rmiCx.synthActivate(thread1); } @Override @@ -134,9 +139,11 @@ public class DebuggerRmiLogicalBreakpointServiceTest extends protected void addTextMapping(TraceRmiTarget target, TraceObjectMemoryRegion text, Program program) throws Throwable { Trace trace = target.getTrace(); + long snap = getSnap(target); try (Transaction tx = trace.openTransaction("Add .text mapping")) { DebuggerStaticMappingUtils.addMapping( - new DefaultTraceLocation(trace, null, text.getLifespan(), text.getMinAddress()), + new DefaultTraceLocation(trace, null, Lifespan.nowOn(snap), + text.getMinAddress(snap)), new ProgramLocation(program, addr(program, 0x00400000)), 0x1000, false); } @@ -157,7 +164,7 @@ public class DebuggerRmiLogicalBreakpointServiceTest extends @Override protected void addTargetAccessBreakpoint(TraceRmiTarget target, TraceObjectMemoryRegion region) throws Throwable { - Address min = region.getMinAddress().add(0x0123); + Address min = region.getMinAddress(getSnap(target)).add(0x0123); Trace trace = target.getTrace(); try (Transaction tx = trace.openTransaction("Add access breakpoint")) { addBreakpointAndLoc(trace.getObjectManager(), Lifespan.nowOn(target.getSnap()), @@ -168,12 +175,12 @@ public class DebuggerRmiLogicalBreakpointServiceTest extends @Override protected void addTargetSoftwareBreakpoint(TraceRmiTarget target, - TraceObjectMemoryRegion region) throws Throwable { - Address min = region.getMinAddress().add(0x0123); + TraceObjectMemoryRegion region, int offset, Integer id) throws Throwable { + Address min = region.getMinAddress(getSnap(target)).add(offset); Trace trace = target.getTrace(); try (Transaction tx = trace.openTransaction("Add software breakpoint")) { addBreakpointAndLoc(trace.getObjectManager(), Lifespan.nowOn(target.getSnap()), - tb.range(min, min), TraceBreakpointKindSet.SW_EXECUTE); + tb.range(min, min), TraceBreakpointKindSet.SW_EXECUTE, id); } waitForDomainObject(trace); } @@ -181,11 +188,12 @@ public class DebuggerRmiLogicalBreakpointServiceTest extends @Override protected void removeTargetSoftwareBreakpoint(TraceRmiTarget target) throws Throwable { Trace trace = target.getTrace(); - Lifespan nowOn = Lifespan.nowOn(target.getSnap()); + long snap = target.getSnap(); + Lifespan nowOn = Lifespan.nowOn(snap); List locsToDel = trace.getBreakpointManager() .getAllBreakpoints() .stream() - .filter(bp -> bp.getKinds().equals(TraceBreakpointKindSet.SW_EXECUTE)) + .filter(bp -> bp.getKinds(snap).equals(TraceBreakpointKindSet.SW_EXECUTE)) .filter(bp -> bp instanceof TraceObjectBreakpointLocation) .map(bp -> (TraceObjectBreakpointLocation) bp) .toList(); @@ -208,9 +216,9 @@ public class DebuggerRmiLogicalBreakpointServiceTest extends } @Override - protected TraceBreakpoint findLoc(Set locs, int index) { + protected TraceBreakpoint findLoc(long snap, Set locs, int index) { return locs.stream() - .filter(b -> b.getName().equals(Integer.toString(index + 1))) + .filter(b -> b.getName(snap).equals(Integer.toString(index + 1))) .findAny() .orElseThrow(); } @@ -223,7 +231,7 @@ public class DebuggerRmiLogicalBreakpointServiceTest extends } Map args = rmiMethodToggleBreak.expect(); try (Transaction tx = tb.startTransaction()) { - loc.setEnabled(Lifespan.nowOn(0), expectedEn); + loc.setEnabled(Lifespan.nowOn(target.getSnap()), expectedEn); } waitForDomainObject(tb.trace); rmiMethodToggleBreak.result(null); @@ -240,7 +248,7 @@ public class DebuggerRmiLogicalBreakpointServiceTest extends } Map args = rmiMethodDeleteBreak.expect(); try (Transaction tx = tb.startTransaction()) { - loc.getObject().remove(Lifespan.nowOn(0)); + loc.getObject().removeTree(Lifespan.nowOn(target.getSnap())); } waitForDomainObject(tb.trace); rmiMethodDeleteBreak.result(null); diff --git a/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/debug/flatapi/AbstractFlatDebuggerAPITest.java b/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/debug/flatapi/AbstractFlatDebuggerAPITest.java index d4fd8f0142..84daa0fb15 100644 --- a/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/debug/flatapi/AbstractFlatDebuggerAPITest.java +++ b/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/debug/flatapi/AbstractFlatDebuggerAPITest.java @@ -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. @@ -90,7 +90,7 @@ public abstract class AbstractFlatDebuggerAPITest try (Transaction tx = tb.startTransaction()) { thread = tb.getOrAddThread("Threads[0]", 0); TraceStack stack = tb.trace.getStackManager().getStack(thread, 0, true); - stack.setDepth(3, true); + stack.setDepth(0, 3, true); } waitForSwing(); return thread; diff --git a/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/debug/flatapi/DeadFlatDebuggerAPITest.java b/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/debug/flatapi/DeadFlatDebuggerAPITest.java index e0a2a4b2e6..a0397e6754 100644 --- a/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/debug/flatapi/DeadFlatDebuggerAPITest.java +++ b/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/debug/flatapi/DeadFlatDebuggerAPITest.java @@ -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. @@ -132,7 +132,7 @@ public class DeadFlatDebuggerAPITest extends AbstractFlatDebuggerAPITest