mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 09:49:23 +02:00
GP-5379: Require snap parameter in object getters/setters. Lots of fallout.
This commit is contained in:
parent
22a4de14ea
commit
789a9fa4b7
167 changed files with 2527 additions and 2788 deletions
|
@ -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<SectionMapEntry> 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<RegionMapEntry> 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<? extends Program> programs);
|
||||
ModuleMapProposal proposeModuleMap(TraceModule module, long snap,
|
||||
Collection<? extends Program> 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<TraceModule, ModuleMapProposal> proposeModuleMaps(
|
||||
Collection<? extends TraceModule> modules, Collection<? extends Program> programs);
|
||||
Collection<? extends TraceModule> modules, long snap,
|
||||
Collection<? extends Program> 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<? extends Program> 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<TraceModule, SectionMapProposal> proposeSectionMaps(
|
||||
Collection<? extends TraceModule> modules, Collection<? extends Program> programs);
|
||||
Collection<? extends TraceModule> modules, long snap,
|
||||
Collection<? extends Program> 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<? extends TraceMemoryRegion> regions,
|
||||
RegionMapProposal proposeRegionMap(Collection<? extends TraceMemoryRegion> 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<Collection<TraceMemoryRegion>, RegionMapProposal> proposeRegionMaps(
|
||||
Collection<? extends TraceMemoryRegion> regions,
|
||||
Collection<? extends TraceMemoryRegion> regions, long snap,
|
||||
Collection<? extends Program> programs);
|
||||
}
|
||||
|
|
|
@ -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<Program> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<TraceObjectValue> objectValues;
|
||||
private final long snap;
|
||||
|
||||
public DebuggerObjectActionContext(Collection<TraceObjectValue> objectValues,
|
||||
ComponentProvider provider, Component sourceComponent) {
|
||||
ComponentProvider provider, Component sourceComponent, long snap) {
|
||||
super(provider, sourceComponent);
|
||||
this.objectValues = List.copyOf(objectValues);
|
||||
this.snap = snap;
|
||||
}
|
||||
|
||||
public List<TraceObjectValue> getObjectValues() {
|
||||
return objectValues;
|
||||
}
|
||||
|
||||
public long getSnap() {
|
||||
return snap;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<TraceModule, Program, Mod
|
|||
*/
|
||||
TraceModule getModule();
|
||||
|
||||
/**
|
||||
* Get the module name for this entry (may depend on the snap)
|
||||
*
|
||||
* @return the name
|
||||
*/
|
||||
String getModuleName();
|
||||
|
||||
/**
|
||||
* Get the address range of the module in the trace, as computed from the matched program's
|
||||
* image size
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
@ -16,6 +16,7 @@
|
|||
package ghidra.debug.api.modules;
|
||||
|
||||
import ghidra.debug.api.modules.RegionMapProposal.RegionMapEntry;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.MemoryBlock;
|
||||
import ghidra.trace.model.memory.TraceMemoryRegion;
|
||||
|
@ -34,6 +35,20 @@ public interface RegionMapProposal
|
|||
*/
|
||||
TraceMemoryRegion getRegion();
|
||||
|
||||
/**
|
||||
* Get the region's name (may depend on snap)
|
||||
*
|
||||
* @return the name
|
||||
*/
|
||||
String getRegionName();
|
||||
|
||||
/**
|
||||
* Get the region's minimum address (may depend on snap)
|
||||
*
|
||||
* @return the address
|
||||
*/
|
||||
Address getRegionMinAddress();
|
||||
|
||||
/**
|
||||
* Get the matched memory block
|
||||
*
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
@ -16,6 +16,7 @@
|
|||
package ghidra.debug.api.modules;
|
||||
|
||||
import ghidra.debug.api.modules.SectionMapProposal.SectionMapEntry;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.MemoryBlock;
|
||||
import ghidra.trace.model.modules.TraceModule;
|
||||
|
@ -36,6 +37,20 @@ public interface SectionMapProposal
|
|||
*/
|
||||
TraceSection getSection();
|
||||
|
||||
/**
|
||||
* Get the section name (may depend on the snap)
|
||||
*
|
||||
* @return the name
|
||||
*/
|
||||
String getSectionName();
|
||||
|
||||
/**
|
||||
* Get the start address of the section (may depend on the snap)
|
||||
*
|
||||
* @return the start address
|
||||
*/
|
||||
Address getSectionStart();
|
||||
|
||||
/**
|
||||
* Get the module containing the section
|
||||
*
|
||||
|
@ -43,6 +58,13 @@ public interface SectionMapProposal
|
|||
*/
|
||||
TraceModule getModule();
|
||||
|
||||
/**
|
||||
* Get the name of the module containing the section (may depend on snap)
|
||||
*
|
||||
* @return the name
|
||||
*/
|
||||
String getModuleName();
|
||||
|
||||
/**
|
||||
* Get the matched memory block
|
||||
*
|
||||
|
@ -71,5 +93,6 @@ public interface SectionMapProposal
|
|||
*
|
||||
* @return the program
|
||||
*/
|
||||
@Override
|
||||
Program getProgram();
|
||||
}
|
||||
|
|
|
@ -320,8 +320,9 @@ public class DebuggerCoordinates {
|
|||
return objThread.getCanonicalPath();
|
||||
}
|
||||
TraceStack stack;
|
||||
long snap = time.getSnap();
|
||||
try {
|
||||
stack = thread.getTrace().getStackManager().getStack(thread, time.getSnap(), false);
|
||||
stack = thread.getTrace().getStackManager().getStack(thread, snap, false);
|
||||
}
|
||||
catch (IllegalStateException e) {
|
||||
// Schema does not specify a stack
|
||||
|
@ -330,7 +331,7 @@ public class DebuggerCoordinates {
|
|||
if (stack == null) {
|
||||
return objThread.getCanonicalPath();
|
||||
}
|
||||
TraceStackFrame frame = stack.getFrame(frameLevel, false);
|
||||
TraceStackFrame frame = stack.getFrame(snap, frameLevel, false);
|
||||
if (frame == null) {
|
||||
return objThread.getCanonicalPath();
|
||||
}
|
||||
|
@ -406,9 +407,8 @@ public class DebuggerCoordinates {
|
|||
return NOWHERE;
|
||||
}
|
||||
long snap = newTime.getSnap();
|
||||
Lifespan threadLifespan = thread == null ? null : thread.getLifespan();
|
||||
TraceThread newThread = threadLifespan != null && threadLifespan.contains(snap) ? thread
|
||||
: resolveThread(trace, target, newTime);
|
||||
boolean isThreadValid = thread == null ? false : thread.isValid(snap);
|
||||
TraceThread newThread = isThreadValid ? thread : resolveThread(trace, target, newTime);
|
||||
// This will cause the frame to reset to 0 on every snap change. That's fair....
|
||||
Integer newFrame = resolveFrame(newThread, newTime);
|
||||
KeyPath threadOrFramePath = resolvePath(newThread, newFrame, newTime);
|
||||
|
|
|
@ -1444,8 +1444,10 @@ public interface FlatDebuggerAPI {
|
|||
}
|
||||
|
||||
default ActionContext createContext(TraceObject object) {
|
||||
Trace trace = object.getTrace();
|
||||
DebuggerCoordinates coords = getTraceManager().getCurrentFor(trace);
|
||||
TraceObjectValue value = object.getCanonicalParents(Lifespan.ALL).findAny().orElseThrow();
|
||||
return new DebuggerObjectActionContext(List.of(value), null, null);
|
||||
return new DebuggerObjectActionContext(List.of(value), null, null, coords.getSnap());
|
||||
}
|
||||
|
||||
default ActionContext createContext(TraceThread thread) {
|
||||
|
@ -1720,8 +1722,7 @@ public interface FlatDebuggerAPI {
|
|||
* This does not consider the current snap. It only considers a live target thread in the
|
||||
* present. In other words, if the user rewinds trace history to a point where the thread was
|
||||
* alive, this method still considers that thread terminated. To compute state with respect to
|
||||
* trace history, use {@link TraceThread#getLifespan()} and check if it contains the current
|
||||
* snap.
|
||||
* trace history, use {@link TraceThread#isValid(long)}.
|
||||
*
|
||||
* @param thread
|
||||
* @return the thread's execution state
|
||||
|
|
|
@ -190,7 +190,8 @@ public abstract class AbstractTraceRmiLaunchOffer implements TraceRmiLaunchOffer
|
|||
return false;
|
||||
}
|
||||
|
||||
if (spec.performMapping(mappingService, trace, List.of(program), monitor)) {
|
||||
long snap = connection.getLastSnapshot(trace);
|
||||
if (spec.performMapping(mappingService, trace, snap, List.of(program), monitor)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -206,7 +207,7 @@ public abstract class AbstractTraceRmiLaunchOffer implements TraceRmiLaunchOffer
|
|||
return true; // Probably shouldn't happen, but if it does, say "success"
|
||||
}
|
||||
ProgramLocation probe = new ProgramLocation(program, probeAddress);
|
||||
long snap = connection.getLastSnapshot(trace);
|
||||
|
||||
return mappingService.getOpenMappedLocation(trace, probe, snap) != null;
|
||||
}
|
||||
|
||||
|
|
|
@ -938,7 +938,8 @@ public class TraceRmiHandler extends AbstractTraceRmiConnection {
|
|||
|
||||
// Want addresses satisfying {@code known | (readOnly & everKnown)}
|
||||
TraceMemoryManager memoryManager = open.trace.getMemoryManager();
|
||||
AddressSetView readOnly = memoryManager.getRegionsAddressSetWith(snap, r -> !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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
* <p>
|
||||
* 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);
|
||||
|
|
|
@ -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<Program, MemoryBlock> chooseBlock(PluginTool tool, TraceSection section,
|
||||
Collection<Program> programs) {
|
||||
long snap, Collection<Program> 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<Program, MemoryBlock> chooseBlock(PluginTool tool, TraceMemoryRegion region,
|
||||
Collection<Program> programs) {
|
||||
long snap, Collection<Program> 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<Program, MemoryBlock> chooseBlock(PluginTool tool,
|
||||
|
|
|
@ -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)";
|
||||
}
|
||||
|
|
|
@ -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<Program> programs, TaskMonitor monitor) throws CancelledException {
|
||||
long snap, List<Program> programs, TaskMonitor monitor) throws CancelledException {
|
||||
Map<?, ModuleMapProposal> maps = mappingService
|
||||
.proposeModuleMaps(trace.getModuleManager().getAllModules(), programs);
|
||||
.proposeModuleMaps(trace.getModuleManager().getLoadedModules(snap), snap, programs);
|
||||
Collection<ModuleMapEntry> entries = MapProposal.flatten(maps.values());
|
||||
entries = MapProposal.removeOverlapping(entries);
|
||||
mappingService.addModuleMappings(entries, monitor, false);
|
||||
|
|
|
@ -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<Program> programs, TaskMonitor monitor) throws CancelledException {
|
||||
long snap, List<Program> programs, TaskMonitor monitor) throws CancelledException {
|
||||
Map<?, RegionMapProposal> maps = mappingService
|
||||
.proposeRegionMaps(trace.getMemoryManager().getAllRegions(), programs);
|
||||
.proposeRegionMaps(trace.getMemoryManager().getRegionsAtSnap(snap), snap, programs);
|
||||
Collection<RegionMapEntry> entries = MapProposal.flatten(maps.values());
|
||||
entries = MapProposal.removeOverlapping(entries);
|
||||
mappingService.addRegionMappings(entries, monitor, false);
|
||||
|
|
|
@ -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<Program> programs, TaskMonitor monitor) throws CancelledException {
|
||||
Map<?, SectionMapProposal> maps = mappingService
|
||||
.proposeSectionMaps(trace.getModuleManager().getAllModules(), programs);
|
||||
long snap, List<Program> programs, TaskMonitor monitor) throws CancelledException {
|
||||
Map<?, SectionMapProposal> maps = mappingService.proposeSectionMaps(
|
||||
trace.getModuleManager().getLoadedModules(snap), snap, programs);
|
||||
Collection<SectionMapEntry> entries = MapProposal.flatten(maps.values());
|
||||
entries = MapProposal.removeOverlapping(entries);
|
||||
mappingService.addSectionMappings(entries, monitor, false);
|
||||
|
|
|
@ -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<Program> programs, TaskMonitor monitor) throws CancelledException {
|
||||
long snap, List<Program> programs, TaskMonitor monitor) throws CancelledException {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Program> programs, TaskMonitor monitor) throws CancelledException {
|
||||
long snap, List<Program> programs, TaskMonitor monitor) throws CancelledException {
|
||||
boolean result = false;
|
||||
for (Program program : programs) {
|
||||
try {
|
||||
mappingService.addIdentityMapping(trace, program,
|
||||
Lifespan.nowOn(trace.getProgramView().getSnap()), false);
|
||||
mappingService.addIdentityMapping(trace, program, Lifespan.nowOn(snap), false);
|
||||
result = true;
|
||||
}
|
||||
catch (TraceConflictedMappingException e) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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<TraceAddressSnapRange, TraceMemoryState> ent : mm
|
||||
.getMostRecentStates(coordinates.getSnap(), range)) {
|
||||
for (Entry<TraceAddressSnapRange, TraceMemoryState> 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));
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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<? extends TraceMemoryRegion> 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<? extends TraceModule> 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<? extends TraceSection> 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<RangeEntry> result, AddressRange srcRange,
|
||||
|
@ -692,10 +695,11 @@ public class DebuggerCopyIntoProgramDialog extends ReusableDialogComponentProvid
|
|||
protected List<AddressRange> breakRangeByRegions(AddressRange srcRange) {
|
||||
AddressSet remains = new AddressSet(srcRange);
|
||||
List<AddressRange> 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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -1081,13 +1081,13 @@ public class DebuggerListingProvider extends CodeViewerProvider {
|
|||
Set<DomainFile> toOpen = new HashSet<>();
|
||||
TraceModuleManager modMan = trace.getModuleManager();
|
||||
Collection<TraceModule> 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,
|
||||
"<html>The module <b><tt>" + HTMLUtilities.escapeHTML(mod.getName()) +
|
||||
"<html>The module <b><tt>" + HTMLUtilities.escapeHTML(mod.getName(snap)) +
|
||||
"</tt></b> was not found in the project</html>",
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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<TraceAddressSnapRange, TraceMemoryState> 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;
|
||||
|
|
|
@ -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<RegionTableColumns, RegionRow> {
|
||||
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);
|
||||
|
|
|
@ -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<RegionMapTableColumns, RegionMapEntry> {
|
||||
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()),
|
||||
|
|
|
@ -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<?, RegionMapProposal> map = staticMappingService.proposeRegionMaps(regions,
|
||||
List.of(programManager.getAllOpenPrograms()));
|
||||
current.getSnap(), List.of(programManager.getAllOpenPrograms()));
|
||||
Collection<RegionMapEntry> 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<RegionMapEntry> 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()));
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<? extends TraceSection> sections = module.getSections();
|
||||
Collection<? extends TraceSection> sections = module.getAllSections();
|
||||
for (TraceSection section : sections) {
|
||||
sectionChanged(section);
|
||||
}
|
||||
|
|
|
@ -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<U extends TraceObjectInterf
|
|||
List<ValueRow> 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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<String, ActionEntry> 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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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<TraceModule> 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<TraceSection> 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;
|
||||
}
|
||||
|
|
|
@ -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<ModuleMapTableColumns, ModuleMapEntry> {
|
||||
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
|
||||
|
|
|
@ -190,7 +190,7 @@ public class DebuggerModulesPanel extends AbstractObjectsTableBasedPanel<TraceOb
|
|||
TraceObject child = value.getChild();
|
||||
TraceObjectModule module = child.queryInterface(TraceObjectModule.class);
|
||||
if (module != null) {
|
||||
result.addAll(module.getSections());
|
||||
result.addAll(module.getSections(ctx.getSnap()));
|
||||
continue;
|
||||
}
|
||||
TraceObjectSection section = child.queryInterface(TraceObjectSection.class);
|
||||
|
@ -208,12 +208,12 @@ public class DebuggerModulesPanel extends AbstractObjectsTableBasedPanel<TraceOb
|
|||
TraceObject child = value.getChild();
|
||||
TraceObjectModule module = child.queryInterface(TraceObjectModule.class);
|
||||
if (module != null) {
|
||||
result.add(module.getRange());
|
||||
result.add(module.getRange(ctx.getSnap()));
|
||||
continue;
|
||||
}
|
||||
TraceObjectSection section = child.queryInterface(TraceObjectSection.class);
|
||||
if (section != null) {
|
||||
result.add(section.getRange());
|
||||
result.add(section.getRange(ctx.getSnap()));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -402,13 +402,20 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter
|
|||
return;
|
||||
}
|
||||
couldHaveChanged = false;
|
||||
String infosThisTime = spec.getInfoForObjects(trace);
|
||||
DebuggerTraceManagerService traceManager =
|
||||
tool.getService(DebuggerTraceManagerService.class);
|
||||
if (traceManager == null) {
|
||||
return;
|
||||
}
|
||||
DebuggerCoordinates current = traceManager.getCurrentFor(trace);
|
||||
long snap = current.getSnap();
|
||||
String infosThisTime = spec.getInfoForObjects(trace, snap);
|
||||
if (Objects.equals(infosThisTime, infosLastTime)) {
|
||||
return;
|
||||
}
|
||||
infosLastTime = infosThisTime;
|
||||
|
||||
spec.runTask(tool, trace);
|
||||
spec.runTask(tool, trace, snap);
|
||||
}
|
||||
|
||||
public void forceMap() {
|
||||
|
@ -593,7 +600,6 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter
|
|||
boolean filterSectionsByModules = false;
|
||||
|
||||
private final Map<Trace, AutoMapState> 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<TraceModule, ModuleMapProposal> map = staticMappingService.proposeModuleMaps(
|
||||
trace.getModuleManager().getAllModules(), List.of(program));
|
||||
trace.getModuleManager().getAllModules(), snap, List.of(program));
|
||||
Collection<ModuleMapEntry> 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<TraceModule, ModuleMapEntry> 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<TraceModule> modSel = new HashSet<>();
|
||||
Set<TraceSection> 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<TraceModule, ModuleMapProposal> map = staticMappingService.proposeModuleMaps(modules,
|
||||
List.of(programManager.getAllOpenPrograms()));
|
||||
Map<TraceModule, ModuleMapProposal> map =
|
||||
staticMappingService.proposeModuleMaps(modules, current.getSnap(),
|
||||
List.of(programManager.getAllOpenPrograms()));
|
||||
Collection<ModuleMapEntry> 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<TraceModule, ModuleMapEntry> map = proposal.computeMap();
|
||||
promptModuleProposal(map.values(), NO_MODULES_PROPOSAL_SEL);
|
||||
}
|
||||
|
@ -1209,8 +1220,9 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter
|
|||
}
|
||||
Set<TraceModule> modules =
|
||||
sections.stream().map(TraceSection::getModule).collect(Collectors.toSet());
|
||||
Map<?, SectionMapProposal> map = staticMappingService.proposeSectionMaps(modules,
|
||||
List.of(programManager.getAllOpenPrograms()));
|
||||
Map<?, SectionMapProposal> map =
|
||||
staticMappingService.proposeSectionMaps(modules, current.getSnap(),
|
||||
List.of(programManager.getAllOpenPrograms()));
|
||||
Collection<SectionMapEntry> proposal = MapProposal.flatten(map.values());
|
||||
Collection<SectionMapEntry> 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<SectionMapEntry> proposal = map.computeMap().values();
|
||||
Collection<SectionMapEntry> 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()));
|
||||
}
|
||||
|
||||
|
|
|
@ -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<TraceSection> getSelectedSections(boolean allowExpansion) {
|
||||
public Set<TraceSection> 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;
|
||||
|
|
|
@ -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<SectionMapTableColumns, SectionMapEntry> {
|
||||
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()),
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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<ThreadRow, ?> 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<Long> spanRenderer = new SpanTableCellRenderer<>();
|
||||
final RangeCursorTableHeaderRenderer<Long> headerRenderer;
|
||||
|
||||
final TableCellRenderer boldCurrentRenderer = new AbstractGColumnRenderer<Object>() {
|
||||
@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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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<? extends TraceModule> 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<Mode> 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();
|
||||
|
|
|
@ -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<BreakpointActionItem> {
|
|||
/**
|
||||
* 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<BreakpointActionItem> {
|
|||
* 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<BreakpointActionItem> {
|
|||
/**
|
||||
* 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<BreakpointActionItem> {
|
|||
* 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<BreakpointActionItem> {
|
|||
/**
|
||||
* 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<BreakpointActionItem> {
|
|||
* 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;
|
||||
}
|
||||
|
|
|
@ -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<Address, Set<LogicalBreakpointInternal>> breakpointsByAddress =
|
||||
final NavigableMap<Address, Set<LogicalBreakpointInternal>> logicalByAddress =
|
||||
new TreeMap<>();
|
||||
|
||||
public AbstractInfo() {
|
||||
|
@ -350,47 +351,30 @@ public class DebuggerLogicalBreakpointServicePlugin extends Plugin
|
|||
long length, Collection<TraceBreakpointKind> kinds);
|
||||
|
||||
protected LogicalBreakpointInternal getOrCreateLogicalBreakpointFor(AddCollector a,
|
||||
Address address, TraceBreakpoint tb) throws TrackedTooSoonException {
|
||||
Address address, TraceBreakpoint tb, long snap) throws TrackedTooSoonException {
|
||||
Set<LogicalBreakpointInternal> 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<LogicalBreakpointInternal> 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<LogicalBreakpointInternal> set = breakpointsByAddress.get(address);
|
||||
Set<LogicalBreakpointInternal> 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<Trace> additionalTraces,
|
||||
Set<Program> additionalPrograms) {
|
||||
for (Set<LogicalBreakpointInternal> set : List.copyOf(breakpointsByAddress.values())) {
|
||||
for (Set<LogicalBreakpointInternal> 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<TraceBreakpoint, LogicalBreakpointInternal> 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<LogicalBreakpointInternal> 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<TraceBreakpoint, LogicalBreakpointInternal> 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<LogicalBreakpointInternal> 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<LogicalBreakpointInternal> set = breakpointsByAddress.get(address);
|
||||
Set<LogicalBreakpointInternal> 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<LogicalBreakpointInternal> set : List.copyOf(breakpointsByAddress.values())) {
|
||||
for (Set<LogicalBreakpointInternal> 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<LogicalBreakpointInternal> present = breakpointsByAddress.get(pb.getAddress());
|
||||
Set<LogicalBreakpointInternal> 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<LogicalBreakpointInternal> set : pInfo.breakpointsByAddress.values()) {
|
||||
for (Set<LogicalBreakpointInternal> 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<LogicalBreakpoint> records = new HashSet<>();
|
||||
for (AbstractInfo info : allInfos) {
|
||||
for (Set<LogicalBreakpointInternal> recsAtAddress : info.breakpointsByAddress
|
||||
for (Set<LogicalBreakpointInternal> 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<LogicalBreakpoint> doGetBreakpointsAt(AbstractInfo info, Address address) {
|
||||
Set<LogicalBreakpointInternal> set = info.breakpointsByAddress.get(address);
|
||||
Set<LogicalBreakpointInternal> 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<BreakpointActionSet, TraceBreakpoint> 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<BreakpointActionSet, TraceBreakpoint> 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<Void> actOnLocs(Collection<TraceBreakpoint> col,
|
||||
TargetBreakpointConsumer targetBptConsumer,
|
||||
BiConsumer<BreakpointActionSet, TraceBreakpoint> emuLocConsumer,
|
||||
Consumer<LogicalBreakpoint> progConsumer) {
|
||||
EmuBreakpointConsumer emuLocConsumer,
|
||||
ProgramBreakpointConsumer progConsumer) {
|
||||
BreakpointActionSet actions = new BreakpointActionSet();
|
||||
for (TraceBreakpoint tb : col) {
|
||||
LogicalBreakpoint lb = getBreakpoint(tb);
|
||||
|
|
|
@ -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<Void> 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();
|
||||
|
|
|
@ -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<Void> execute() {
|
||||
try (Transaction tx =
|
||||
bpt.getTrace().openTransaction("Disable Emulated Breakpoint")) {
|
||||
bpt.setEmuEnabled(false);
|
||||
bpt.setEmuEnabled(snap, false);
|
||||
}
|
||||
return AsyncUtils.nil();
|
||||
}
|
||||
|
|
|
@ -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<Void> execute() {
|
||||
try (Transaction tx =
|
||||
bpt.getTrace().openTransaction("Enable Emulated Breakpoint")) {
|
||||
bpt.setEmuEnabled(true);
|
||||
bpt.setEmuEnabled(snap, true);
|
||||
}
|
||||
return AsyncUtils.nil();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -192,9 +192,10 @@ class TraceBreakpointSet {
|
|||
*/
|
||||
public String computeSleigh() {
|
||||
String sleigh = null;
|
||||
long snap = getSnap();
|
||||
synchronized (breakpoints) {
|
||||
for (IDHashed<TraceBreakpoint> 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<TraceBreakpoint> 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<TraceBreakpoint> 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<TraceBreakpoint> 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<TraceBreakpoint> bpt : breakpoints) {
|
||||
actions.planDeleteEmu(bpt.obj);
|
||||
actions.planDeleteEmu(bpt.obj, getSnap());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -664,30 +664,30 @@ public class DebuggerEmulationServicePlugin extends Plugin implements DebuggerEm
|
|||
if (!bpt.isEmuEnabled(snap)) {
|
||||
continue;
|
||||
}
|
||||
Set<TraceBreakpointKind> kinds = bpt.getKinds();
|
||||
Set<TraceBreakpointKind> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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<T, P> implements MapEntry<T, P> {
|
||||
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<T, P> implements MapEntry<T, P> {
|
|||
return fromObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Lifespan getFromLifespan() {
|
||||
return Lifespan.nowOn(snap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceLocation getFromTraceLocation() {
|
||||
return new DefaultTraceLocation(fromTrace, null, getFromLifespan(),
|
||||
|
|
|
@ -30,14 +30,18 @@ public abstract class AbstractMapProposal<T, P, E extends MapEntry<T, P>>
|
|||
|
||||
protected abstract static class Matcher<T, P> {
|
||||
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<T, P, E extends MapEntry<T, P>>
|
|||
}
|
||||
|
||||
protected static abstract class MatcherMap<K, T, P, M extends Matcher<T, P>> {
|
||||
protected final long snap;
|
||||
|
||||
protected Map<K, Set<T>> fromsByJoin = new LinkedHashMap<>();
|
||||
protected Map<T, M> map = new LinkedHashMap<>();
|
||||
|
||||
public MatcherMap(long snap) {
|
||||
this.snap = snap;
|
||||
}
|
||||
|
||||
protected abstract M newMatcher(T fromObject, P toObject);
|
||||
|
||||
protected abstract K getFromJoinKey(T fromObject);
|
||||
|
|
|
@ -72,15 +72,22 @@ public enum DebuggerStaticMappingProposals {
|
|||
}
|
||||
|
||||
protected interface ProposalGenerator<F, T, MP extends MapProposal<?, ?, ?>> {
|
||||
MP proposeMap(F from, T to);
|
||||
MP proposeMap(F from, long snap, T to);
|
||||
|
||||
MP proposeBestMap(F from, Collection<? extends T> tos);
|
||||
MP proposeBestMap(F from, long snap, Collection<? extends T> tos);
|
||||
|
||||
Map<F, MP> proposeBestMaps(Collection<? extends F> froms, Collection<? extends T> tos);
|
||||
Map<F, MP> proposeBestMaps(Collection<? extends F> froms, long snap,
|
||||
Collection<? extends T> tos);
|
||||
}
|
||||
|
||||
protected abstract static class AbstractProposalGenerator //
|
||||
<F, T, J, MP extends MapProposal<?, ?, ?>> {
|
||||
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<? extends Program> tos) {
|
||||
Collection<IndexEntry> entries = indexer.filter(indexer.getBestEntries(from), tos);
|
||||
DomainFile df = indexer.getBestMatch(from, null, entries);
|
||||
Collection<IndexEntry> 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<TraceModule, ModuleMapProposal> proposeBestMaps(
|
||||
Collection<? extends TraceModule> froms, Collection<? extends Program> tos) {
|
||||
Collection<? extends TraceModule> froms, long snap,
|
||||
Collection<? extends Program> tos) {
|
||||
Map<TraceModule, ModuleMapProposal> 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<TraceModule, Program, String, SectionMapProposal> {
|
||||
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<Collection<TraceMemoryRegion>, Program, Set<String>, //
|
||||
RegionMapProposal> {
|
||||
|
||||
public RegionMapProposalGenerator(long snap) {
|
||||
super(snap);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RegionMapProposal proposeMap(Collection<TraceMemoryRegion> 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<? extends TraceMemoryRegion> regions,
|
||||
Collection<? extends TraceMemoryRegion> regions, long snap,
|
||||
Collection<? extends Program> programs) {
|
||||
return REGIONS.proposeBestMap(Collections.unmodifiableCollection(regions), programs);
|
||||
return new RegionMapProposalGenerator(snap)
|
||||
.proposeBestMap(Collections.unmodifiableCollection(regions), programs);
|
||||
}
|
||||
|
||||
public static <V, J> Set<Set<V>> groupByComponents(Collection<? extends V> 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)
|
||||
|
|
|
@ -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<? extends Program> programs) {
|
||||
return moduleMapProposalGenerator.proposeBestMap(module, orderCurrentFirst(programs));
|
||||
return moduleMapProposalGenerator.proposeBestMap(module, snap, orderCurrentFirst(programs));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<TraceModule, ModuleMapProposal> proposeModuleMaps(
|
||||
Collection<? extends TraceModule> modules, Collection<? extends Program> 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<? extends TraceModule> modules, long snap,
|
||||
Collection<? extends Program> 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<? extends Program> programs) {
|
||||
return new SectionMapProposalGenerator(snap).proposeBestMap(module,
|
||||
orderCurrentFirst(programs));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<TraceModule, SectionMapProposal> proposeSectionMaps(
|
||||
Collection<? extends TraceModule> modules, Collection<? extends Program> programs) {
|
||||
return DebuggerStaticMappingProposals.SECTIONS.proposeBestMaps(modules,
|
||||
Collection<? extends TraceModule> modules, long snap,
|
||||
Collection<? extends Program> 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<? extends TraceMemoryRegion> regions,
|
||||
Program program) {
|
||||
return DebuggerStaticMappingProposals.REGIONS
|
||||
long snap, Program program) {
|
||||
return new RegionMapProposalGenerator(snap)
|
||||
.proposeMap(Collections.unmodifiableCollection(regions), program);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Collection<TraceMemoryRegion>, RegionMapProposal> proposeRegionMaps(
|
||||
Collection<? extends TraceMemoryRegion> regions,
|
||||
Collection<? extends TraceMemoryRegion> regions, long snap,
|
||||
Collection<? extends Program> programs) {
|
||||
Set<Set<TraceMemoryRegion>> groups =
|
||||
DebuggerStaticMappingProposals.groupRegionsByLikelyModule(regions);
|
||||
return DebuggerStaticMappingProposals.REGIONS.proposeBestMaps(groups, programs);
|
||||
return new RegionMapProposalGenerator(snap).proposeBestMaps(groups, programs);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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<Long, ModuleRegionMatcher> 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<TraceModule, ModuleMapEntry> computeMap() {
|
||||
return Map.of(module, new DefaultModuleMapEntry(module, program, moduleRange));
|
||||
return Map.of(module, new DefaultModuleMapEntry(module, snap, program, moduleRange));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -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<TraceMemoryRegion, MemoryBlock>
|
||||
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<TraceMemoryRegion, MemoryBlock> {
|
||||
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<Void, TraceMemoryRegion, MemoryBlock, RegionMatcher> {
|
||||
|
||||
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<TraceMemoryRegion> 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<? extends TraceMemoryRegion> regions,
|
||||
protected DefaultRegionMapProposal(Collection<? extends TraceMemoryRegion> 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<TraceMemoryRegion, RegionMapEntry> 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
|
||||
|
|
|
@ -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<TraceSection, MemoryBlock> {
|
||||
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<String, TraceSection, MemoryBlock, SectionMatcher> {
|
||||
|
||||
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<TraceSection, SectionMapEntry> 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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<IndexEntry> entries) {
|
||||
public DomainFile getBestMatch(AddressSpace space, TraceModule module, long snap,
|
||||
Program currentProgram, Collection<IndexEntry> 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<IndexEntry> 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<IndexEntry> getBestEntries(TraceModule module) {
|
||||
String modulePathName = module.getName().toLowerCase();
|
||||
public List<IndexEntry> getBestEntries(TraceModule module, long snap) {
|
||||
String modulePathName = module.getName(snap).toLowerCase();
|
||||
List<IndexEntry> 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<IndexEntry> filter(Collection<IndexEntry> entries,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<? extends TraceMemoryRegion> 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];
|
||||
|
|
|
@ -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));
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<TraceModule, ModuleMapProposal> proposal =
|
||||
mappingService.proposeModuleMaps(tb.trace.getModuleManager().getAllModules(),
|
||||
List.of(programManager.getAllOpenPrograms()));
|
||||
snap, List.of(programManager.getAllOpenPrograms()));
|
||||
Collection<ModuleMapEntry> entries = MapProposal.flatten(proposal.values());
|
||||
mappingService.addModuleMappings(entries, TaskMonitor.DUMMY, false);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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<byte[]> newEmuThread = emulator.newThread(newTraceThread.getPath());
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 <skip>;
|
||||
emu_swi();
|
||||
<skip>
|
||||
|
|
|
@ -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<Lifespan> getReversedSpans() {
|
||||
ArrayList<Lifespan> result = new ArrayList<>();
|
||||
try (LockHold hold = trace.lockRead()) {
|
||||
synchronized (ordered) {
|
||||
ListIterator<Lifespan> it = ordered.listIterator(ordered.size());
|
||||
while (it.hasPrevious()) {
|
||||
result.add(it.previous());
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public List<Lifespan> getOrderedSpans(long snap) {
|
||||
try (LockHold hold = trace.lockRead()) {
|
||||
setSnap(snap);
|
||||
|
|
|
@ -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<TraceThread> getThreads() {
|
||||
public Set<TraceThread> 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<TraceBreakpointKind> 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<TraceBreakpointKind> 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<TraceBreakpointKind> kinds) {
|
||||
public void setKinds(long snap, Collection<TraceBreakpointKind> kinds) {
|
||||
try (LockHold hold = LockHold.lock(space.lock.writeLock())) {
|
||||
doSetKinds(kinds);
|
||||
}
|
||||
|
@ -448,14 +381,14 @@ public class DBTraceBreakpoint
|
|||
}
|
||||
|
||||
@Override
|
||||
public Set<TraceBreakpointKind> getKinds() {
|
||||
public Set<TraceBreakpointKind> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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<TraceBreakpointKind> kinds) {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
if (enabled != isEnabled(snap)) {
|
||||
object.setValue(Lifespan.span(snap, getClearedSnap()),
|
||||
TraceObjectTogglable.KEY_ENABLED, enabled);
|
||||
}
|
||||
Set<TraceBreakpointKind> asSet =
|
||||
kinds instanceof Set<TraceBreakpointKind> 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<TraceBreakpointKind> kinds) {
|
||||
public void setKinds(long snap, Collection<TraceBreakpointKind> kinds) {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
setKinds(getLifespan(), kinds);
|
||||
setKinds(Lifespan.nowOn(snap), kinds);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<TraceBreakpointKind> getKinds() {
|
||||
public Set<TraceBreakpointKind> getKinds(long snap) {
|
||||
try (LockHold hold = object.getTrace().lockRead()) {
|
||||
return getSpecification().getKinds();
|
||||
return getSpecification().getKinds(snap);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<TraceThread> getThreads() {
|
||||
public Set<TraceThread> 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<TraceThread> 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
|
||||
|
|
|
@ -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<TraceBreakpointKind> 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<TraceBreakpointKind> kinds) {
|
||||
public void setKinds(long snap, Collection<TraceBreakpointKind> kinds) {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
setKinds(getLifespan(), kinds);
|
||||
setKinds(Lifespan.nowOn(snap), kinds);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<TraceBreakpointKind> getKinds() {
|
||||
String kindsStr = TraceObjectInterfaceUtils.getValue(object, getPlacedSnap(),
|
||||
public Set<TraceBreakpointKind> 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<TraceThread> getThreads() {
|
||||
public Set<TraceThread> 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<? extends TraceObjectBreakpointLocation> getLocations() {
|
||||
protected Collection<? extends TraceObjectBreakpointLocation> 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<? extends TraceObjectBreakpointLocation> 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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<TraceMemoryFlag> flags) {
|
||||
public void setFlags(long snap, Collection<TraceMemoryFlag> 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<TraceMemoryFlag> flags) {
|
||||
public void addFlags(long snap, Collection<TraceMemoryFlag> 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<TraceMemoryFlag> flags) {
|
||||
public void clearFlags(long snap, Collection<TraceMemoryFlag> 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<TraceMemoryFlag> getFlags() {
|
||||
public Set<TraceMemoryFlag> 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())) {
|
||||
|
|
|
@ -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<TraceMemoryFlag> flags) {
|
||||
public void setFlags(long snap, Collection<TraceMemoryFlag> flags) {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
setFlags(getLifespan(), flags);
|
||||
setFlags(Lifespan.nowOn(snap), flags);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addFlags(Collection<TraceMemoryFlag> flags) {
|
||||
public void addFlags(long snap, Collection<TraceMemoryFlag> flags) {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
addFlags(getLifespan(), flags);
|
||||
addFlags(Lifespan.nowOn(snap), flags);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearFlags(Collection<TraceMemoryFlag> flags) {
|
||||
public void clearFlags(long snap, Collection<TraceMemoryFlag> 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<TraceMemoryFlag> 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
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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<? extends DBTraceSection> 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<? extends DBTraceSection> 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<? extends DBTraceSection> getSections() {
|
||||
public Collection<? extends DBTraceSection> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ public class DBTraceModuleManager extends AbstractDBTraceSpaceBasedManager<DBTra
|
|||
if (pc == ignore) {
|
||||
continue;
|
||||
}
|
||||
if (!pc.getLifespan().intersects(moduleLifespan)) {
|
||||
if (!pc.isAlive(moduleLifespan)) {
|
||||
continue;
|
||||
}
|
||||
throw new DuplicateNameException(
|
||||
|
@ -85,7 +85,7 @@ public class DBTraceModuleManager extends AbstractDBTraceSpaceBasedManager<DBTra
|
|||
* so have the same lifespan, no? I suppose this logic is only true in objects mode...,
|
||||
* and there, the logic is performed by the value key duplicate check.
|
||||
*/
|
||||
if (!pc.getModule().getLifespan().intersects(moduleLifespan)) {
|
||||
if (!pc.getModule().isAlive(moduleLifespan)) {
|
||||
continue;
|
||||
}
|
||||
throw new DuplicateNameException("Section with path '" + sectionPath +
|
||||
|
@ -131,7 +131,7 @@ public class DBTraceModuleManager extends AbstractDBTraceSpaceBasedManager<DBTra
|
|||
}
|
||||
try (LockHold hold = LockHold.lock(lock.readLock())) {
|
||||
return doGetModulesByPath(modulePath).stream()
|
||||
.filter(m -> m.getLifespan().contains(snap))
|
||||
.filter(m -> m.isValid(snap))
|
||||
.findAny()
|
||||
.orElse(null);
|
||||
}
|
||||
|
@ -272,7 +272,7 @@ public class DBTraceModuleManager extends AbstractDBTraceSpaceBasedManager<DBTra
|
|||
}
|
||||
try (LockHold hold = LockHold.lock(lock.readLock())) {
|
||||
return doGetSectionsByPath(sectionPath).stream()
|
||||
.filter(s -> s.getModule().getLifespan().contains(snap))
|
||||
.filter(s -> s.getModule().isValid(snap))
|
||||
.findAny()
|
||||
.orElse(null);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue