mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
GP-4868: Re-write StaticMappingService. Fix tests.
This commit is contained in:
parent
db28b29dab
commit
78fb4e7077
15 changed files with 1273 additions and 1081 deletions
|
@ -65,8 +65,10 @@ class TraceBreakpointSet {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
synchronized (breakpoints) {
|
||||||
return String.format("<at %s in %s: %s>", address, trace.getName(), breakpoints);
|
return String.format("<at %s in %s: %s>", address, trace.getName(), breakpoints);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the target when the trace is associated to a live target
|
* Set the target when the trace is associated to a live target
|
||||||
|
@ -126,6 +128,7 @@ class TraceBreakpointSet {
|
||||||
*/
|
*/
|
||||||
public TraceMode computeMode() {
|
public TraceMode computeMode() {
|
||||||
TraceMode mode = TraceMode.NONE;
|
TraceMode mode = TraceMode.NONE;
|
||||||
|
synchronized (breakpoints) {
|
||||||
if (getControlMode().useEmulatedBreakpoints()) {
|
if (getControlMode().useEmulatedBreakpoints()) {
|
||||||
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
|
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
|
||||||
mode = mode.combine(computeEmuMode(bpt.obj));
|
mode = mode.combine(computeEmuMode(bpt.obj));
|
||||||
|
@ -143,6 +146,7 @@ class TraceBreakpointSet {
|
||||||
}
|
}
|
||||||
return mode;
|
return mode;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compute the mode (enablement) of the given breakpoint
|
* Compute the mode (enablement) of the given breakpoint
|
||||||
|
@ -188,6 +192,7 @@ class TraceBreakpointSet {
|
||||||
*/
|
*/
|
||||||
public String computeSleigh() {
|
public String computeSleigh() {
|
||||||
String sleigh = null;
|
String sleigh = null;
|
||||||
|
synchronized (breakpoints) {
|
||||||
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
|
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
|
||||||
String s = bpt.obj.getEmuSleigh();
|
String s = bpt.obj.getEmuSleigh();
|
||||||
if (sleigh != null && !sleigh.equals(s)) {
|
if (sleigh != null && !sleigh.equals(s)) {
|
||||||
|
@ -197,6 +202,7 @@ class TraceBreakpointSet {
|
||||||
}
|
}
|
||||||
return sleigh;
|
return sleigh;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the sleigh injection for all breakpoints in this set
|
* Set the sleigh injection for all breakpoints in this set
|
||||||
|
@ -206,11 +212,13 @@ class TraceBreakpointSet {
|
||||||
public void setEmuSleigh(String emuSleigh) {
|
public void setEmuSleigh(String emuSleigh) {
|
||||||
this.emuSleigh = emuSleigh;
|
this.emuSleigh = emuSleigh;
|
||||||
try (Transaction tx = trace.openTransaction("Set breakpoint Sleigh")) {
|
try (Transaction tx = trace.openTransaction("Set breakpoint Sleigh")) {
|
||||||
|
synchronized (breakpoints) {
|
||||||
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
|
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
|
||||||
bpt.obj.setEmuSleigh(emuSleigh);
|
bpt.obj.setEmuSleigh(emuSleigh);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if this set actually contains any trace breakpoints
|
* Check if this set actually contains any trace breakpoints
|
||||||
|
@ -218,8 +226,10 @@ class TraceBreakpointSet {
|
||||||
* @return true if empty, false otherwise
|
* @return true if empty, false otherwise
|
||||||
*/
|
*/
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
|
synchronized (breakpoints) {
|
||||||
return breakpoints.isEmpty();
|
return breakpoints.isEmpty();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the breakpoints in this set
|
* Get the breakpoints in this set
|
||||||
|
@ -227,8 +237,10 @@ class TraceBreakpointSet {
|
||||||
* @return the breakpoints
|
* @return the breakpoints
|
||||||
*/
|
*/
|
||||||
public Set<TraceBreakpoint> getBreakpoints() {
|
public Set<TraceBreakpoint> getBreakpoints() {
|
||||||
|
synchronized (breakpoints) {
|
||||||
return breakpoints.stream().map(e -> e.obj).collect(Collectors.toUnmodifiableSet());
|
return breakpoints.stream().map(e -> e.obj).collect(Collectors.toUnmodifiableSet());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a breakpoint to this set
|
* Add a breakpoint to this set
|
||||||
|
@ -246,8 +258,10 @@ class TraceBreakpointSet {
|
||||||
bpt.setEmuSleigh(emuSleigh);
|
bpt.setEmuSleigh(emuSleigh);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
synchronized (breakpoints) {
|
||||||
return breakpoints.add(new IDHashed<>(bpt));
|
return breakpoints.add(new IDHashed<>(bpt));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the given trace breakpoint "fits" in this set
|
* Check if the given trace breakpoint "fits" in this set
|
||||||
|
@ -275,8 +289,10 @@ class TraceBreakpointSet {
|
||||||
* @return true if the set actually changes as a result
|
* @return true if the set actually changes as a result
|
||||||
*/
|
*/
|
||||||
public boolean remove(TraceBreakpoint bpt) {
|
public boolean remove(TraceBreakpoint bpt) {
|
||||||
|
synchronized (breakpoints) {
|
||||||
return breakpoints.remove(new IDHashed<>(bpt));
|
return breakpoints.remove(new IDHashed<>(bpt));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Plan to enable the logical breakpoint within this trace
|
* Plan to enable the logical breakpoint within this trace
|
||||||
|
@ -303,7 +319,7 @@ class TraceBreakpointSet {
|
||||||
public void planEnable(BreakpointActionSet actions, long length,
|
public void planEnable(BreakpointActionSet actions, long length,
|
||||||
Collection<TraceBreakpointKind> kinds) {
|
Collection<TraceBreakpointKind> kinds) {
|
||||||
long snap = getSnap();
|
long snap = getSnap();
|
||||||
if (breakpoints.isEmpty()) {
|
if (isEmpty()) {
|
||||||
if (target == null || getControlMode().useEmulatedBreakpoints()) {
|
if (target == null || getControlMode().useEmulatedBreakpoints()) {
|
||||||
planPlaceEmu(actions, snap, length, kinds);
|
planPlaceEmu(actions, snap, length, kinds);
|
||||||
}
|
}
|
||||||
|
@ -339,16 +355,20 @@ class TraceBreakpointSet {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void planEnableTarget(BreakpointActionSet actions) {
|
private void planEnableTarget(BreakpointActionSet actions) {
|
||||||
|
synchronized (breakpoints) {
|
||||||
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
|
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
|
||||||
actions.planEnableTarget(target, bpt.obj);
|
actions.planEnableTarget(target, bpt.obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void planEnableEmu(BreakpointActionSet actions) {
|
private void planEnableEmu(BreakpointActionSet actions) {
|
||||||
|
synchronized (breakpoints) {
|
||||||
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
|
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
|
||||||
actions.planEnableEmu(bpt.obj);
|
actions.planEnableEmu(bpt.obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Plan to disable the logical breakpoint in this trace
|
* Plan to disable the logical breakpoint in this trace
|
||||||
|
@ -369,16 +389,20 @@ class TraceBreakpointSet {
|
||||||
|
|
||||||
private void planDisableTarget(BreakpointActionSet actions, long length,
|
private void planDisableTarget(BreakpointActionSet actions, long length,
|
||||||
Collection<TraceBreakpointKind> kinds) {
|
Collection<TraceBreakpointKind> kinds) {
|
||||||
|
synchronized (breakpoints) {
|
||||||
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
|
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
|
||||||
actions.planDisableTarget(target, bpt.obj);
|
actions.planDisableTarget(target, bpt.obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void planDisableEmu(BreakpointActionSet actions) {
|
private void planDisableEmu(BreakpointActionSet actions) {
|
||||||
|
synchronized (breakpoints) {
|
||||||
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
|
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
|
||||||
actions.planDisableEmu(bpt.obj);
|
actions.planDisableEmu(bpt.obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Plan to delete the logical breakpoint in this trace
|
* Plan to delete the logical breakpoint in this trace
|
||||||
|
@ -399,14 +423,18 @@ class TraceBreakpointSet {
|
||||||
|
|
||||||
private void planDeleteTarget(BreakpointActionSet actions, long length,
|
private void planDeleteTarget(BreakpointActionSet actions, long length,
|
||||||
Set<TraceBreakpointKind> kinds) {
|
Set<TraceBreakpointKind> kinds) {
|
||||||
|
synchronized (breakpoints) {
|
||||||
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
|
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
|
||||||
actions.planDeleteTarget(target, bpt.obj);
|
actions.planDeleteTarget(target, bpt.obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void planDeleteEmu(BreakpointActionSet actions) {
|
private void planDeleteEmu(BreakpointActionSet actions) {
|
||||||
|
synchronized (breakpoints) {
|
||||||
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
|
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
|
||||||
actions.planDeleteEmu(bpt.obj);
|
actions.planDeleteEmu(bpt.obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,180 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.app.plugin.core.debug.service.modules;
|
||||||
|
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingServicePlugin.ChangeCollector;
|
||||||
|
import ghidra.app.plugin.core.debug.utils.ProgramURLUtils;
|
||||||
|
import ghidra.app.services.DebuggerStaticMappingService.MappedAddressRange;
|
||||||
|
import ghidra.framework.model.*;
|
||||||
|
import ghidra.program.model.address.*;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.trace.model.*;
|
||||||
|
import ghidra.util.Msg;
|
||||||
|
|
||||||
|
class InfoPerProgram implements DomainObjectListener {
|
||||||
|
|
||||||
|
static class NavMultiMap<K, V> {
|
||||||
|
private final TreeMap<K, Set<V>> map = new TreeMap<>();
|
||||||
|
|
||||||
|
public boolean put(K k, V v) {
|
||||||
|
return map.computeIfAbsent(k, __ -> new HashSet<>()).add(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean remove(K k, V v) {
|
||||||
|
Set<V> set = map.get(k);
|
||||||
|
if (set == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!set.remove(v)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (set.isEmpty()) {
|
||||||
|
map.remove(k);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final DebuggerStaticMappingServicePlugin plugin;
|
||||||
|
final Program program;
|
||||||
|
final NavMultiMap<Address, MappingEntry> inboundByStaticAddress = new NavMultiMap<>();
|
||||||
|
|
||||||
|
final URL url;
|
||||||
|
|
||||||
|
InfoPerProgram(DebuggerStaticMappingServicePlugin plugin, Program program) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.program = program;
|
||||||
|
this.url = ProgramURLUtils.getUrlFromProgram(program);
|
||||||
|
|
||||||
|
program.addListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void domainObjectChanged(DomainObjectChangedEvent ev) {
|
||||||
|
if (ev.contains(DomainObjectEvent.FILE_CHANGED) || ev.contains(DomainObjectEvent.RENAMED)) {
|
||||||
|
if (!urlMatches()) {
|
||||||
|
CompletableFuture.runAsync(plugin::programsChanged, plugin.executor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean urlMatches() {
|
||||||
|
return Objects.equals(url, ProgramURLUtils.getUrlFromProgram(program));
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearProgram(ChangeCollector cc, MappingEntry me) {
|
||||||
|
assert me.program == program;
|
||||||
|
inboundByStaticAddress.remove(me.getStaticAddress(), me);
|
||||||
|
me.clearProgram(cc, program);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fillProgram(ChangeCollector cc, MappingEntry me) {
|
||||||
|
assert me.getStaticProgramUrl().equals(ProgramURLUtils.getUrlFromProgram(program));
|
||||||
|
me.fillProgram(cc, program);
|
||||||
|
inboundByStaticAddress.put(me.getStaticAddress(), me);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearEntries(ChangeCollector cc) {
|
||||||
|
if (url == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (InfoPerTrace info : plugin.traceInfoByTrace.values()) {
|
||||||
|
info.clearEntriesForProgram(cc, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fillEntries(ChangeCollector cc) {
|
||||||
|
if (url == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (InfoPerTrace info : plugin.traceInfoByTrace.values()) {
|
||||||
|
info.fillEntriesForProgram(cc, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<TraceLocation> getOpenMappedTraceLocations(Address address) {
|
||||||
|
Set<TraceLocation> result = new HashSet<>();
|
||||||
|
for (Set<MappingEntry> set : inboundByStaticAddress.map.headMap(address, true).values()) {
|
||||||
|
for (MappingEntry me : set) {
|
||||||
|
if (me.mapping.isDeleted()) {
|
||||||
|
Msg.warn(this, "Encountered deleted mapping: " + me.mapping);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!me.isInProgramRange(address)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
result.add(me.mapProgramAddressToTraceLocation(address));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
TraceLocation getOpenMappedTraceLocation(Trace trace, Address address, long snap) {
|
||||||
|
// TODO: Map by trace?
|
||||||
|
for (Set<MappingEntry> set : inboundByStaticAddress.map.headMap(address, true).values()) {
|
||||||
|
for (MappingEntry me : set) {
|
||||||
|
if (me.mapping.isDeleted()) {
|
||||||
|
Msg.warn(this, "Encountered deleted mapping: " + me.mapping);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (me.getTrace() != trace) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!me.isInProgramRange(address)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!me.isInTraceLifespan(snap)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return me.mapProgramAddressToTraceLocation(address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void collectOpenMappedViews(Map<TraceSpan, Collection<MappedAddressRange>> result,
|
||||||
|
AddressRange rng) {
|
||||||
|
for (Set<MappingEntry> set : inboundByStaticAddress.map.headMap(rng.getMaxAddress(), true)
|
||||||
|
.values()) {
|
||||||
|
for (MappingEntry me : set) {
|
||||||
|
if (me.mapping.isDeleted()) {
|
||||||
|
Msg.warn(this, "Encountered deleted mapping: " + me.mapping);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// NB. No lifespan to consider
|
||||||
|
if (!me.isInProgramRange(rng)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
AddressRange srcRange = me.getStaticRange().intersect(rng);
|
||||||
|
AddressRange dstRange = me.mapProgramRangeToTrace(rng);
|
||||||
|
result.computeIfAbsent(me.getTraceSpan(), p -> new TreeSet<>())
|
||||||
|
.add(new MappedAddressRange(srcRange, dstRange));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<TraceSpan, Collection<MappedAddressRange>> getOpenMappedViews(AddressSetView set) {
|
||||||
|
Map<TraceSpan, Collection<MappedAddressRange>> result = new HashMap<>();
|
||||||
|
for (AddressRange rng : set) {
|
||||||
|
collectOpenMappedViews(result, rng);
|
||||||
|
}
|
||||||
|
return Collections.unmodifiableMap(result);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,254 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.app.plugin.core.debug.service.modules;
|
||||||
|
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.apache.commons.collections4.MultiValuedMap;
|
||||||
|
import org.apache.commons.collections4.multimap.HashSetValuedHashMap;
|
||||||
|
|
||||||
|
import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingServicePlugin.ChangeCollector;
|
||||||
|
import ghidra.app.services.DebuggerStaticMappingService.MappedAddressRange;
|
||||||
|
import ghidra.framework.model.DomainObjectChangedEvent;
|
||||||
|
import ghidra.framework.model.DomainObjectEvent;
|
||||||
|
import ghidra.program.model.address.*;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.program.util.ProgramLocation;
|
||||||
|
import ghidra.trace.model.*;
|
||||||
|
import ghidra.trace.model.modules.TraceStaticMapping;
|
||||||
|
import ghidra.trace.util.TraceEvents;
|
||||||
|
import ghidra.util.Msg;
|
||||||
|
|
||||||
|
class InfoPerTrace extends TraceDomainObjectListener {
|
||||||
|
private final DebuggerStaticMappingServicePlugin plugin;
|
||||||
|
final Trace trace;
|
||||||
|
|
||||||
|
final Map<TraceStaticMapping, MappingEntry> outboundByEntry = new HashMap<>();
|
||||||
|
final NavigableMap<TraceAddressSnapRange, MappingEntry> outboundByRange =
|
||||||
|
new TreeMap<>(Comparator.comparing(TraceAddressSnapRange::getX1));
|
||||||
|
final MultiValuedMap<URL, MappingEntry> outboundByStaticUrl = new HashSetValuedHashMap<>();
|
||||||
|
|
||||||
|
private volatile boolean needsResync = false;
|
||||||
|
|
||||||
|
InfoPerTrace(DebuggerStaticMappingServicePlugin plugin, Trace trace) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.trace = trace;
|
||||||
|
|
||||||
|
listenForUntyped(DomainObjectEvent.RESTORED, e -> objectRestored());
|
||||||
|
listenFor(TraceEvents.MAPPING_ADDED, this::staticMappingAdded);
|
||||||
|
listenFor(TraceEvents.MAPPING_DELETED, this::staticMappingDeleted);
|
||||||
|
trace.addListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void domainObjectChanged(DomainObjectChangedEvent ev) {
|
||||||
|
super.domainObjectChanged(ev); // Dispatch individual records
|
||||||
|
// Now do the actual processing
|
||||||
|
if (needsResync) {
|
||||||
|
needsResync = false;
|
||||||
|
CompletableFuture.runAsync(this::resyncEntries, plugin.executor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void objectRestored() {
|
||||||
|
this.needsResync = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void staticMappingAdded(TraceStaticMapping mapping) {
|
||||||
|
this.needsResync = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void staticMappingDeleted(TraceStaticMapping mapping) {
|
||||||
|
this.needsResync = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dispose() {
|
||||||
|
trace.removeListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resyncEntries() {
|
||||||
|
try (ChangeCollector cc = new ChangeCollector(plugin)) {
|
||||||
|
// Invoke change callbacks without the lock! (try must surround sync)
|
||||||
|
synchronized (plugin.lock) {
|
||||||
|
resyncEntries(cc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void resyncEntries(ChangeCollector cc) {
|
||||||
|
Set<TraceStaticMapping> oldEntries = outboundByEntry.keySet();
|
||||||
|
Set<TraceStaticMapping> curEntries = trace.getStaticMappingManager()
|
||||||
|
.getAllEntries()
|
||||||
|
.stream()
|
||||||
|
.filter(e -> !e.isDeleted()) // Double-check
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
|
Set<TraceStaticMapping> removed = ChangeCollector.subtract(oldEntries, curEntries);
|
||||||
|
Set<TraceStaticMapping> added = ChangeCollector.subtract(curEntries, oldEntries);
|
||||||
|
|
||||||
|
processRemovedEntries(cc, removed);
|
||||||
|
processAddedEntries(cc, added);
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeEntries(ChangeCollector cc) {
|
||||||
|
processRemovedEntries(cc, Set.copyOf(outboundByEntry.keySet()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processRemovedEntries(ChangeCollector cc, Set<TraceStaticMapping> removed) {
|
||||||
|
for (TraceStaticMapping entry : removed) {
|
||||||
|
processRemovedEntry(cc, entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processRemovedEntry(ChangeCollector cc, TraceStaticMapping entry) {
|
||||||
|
MappingEntry me = outboundByEntry.remove(entry);
|
||||||
|
if (me == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
outboundByRange.remove(me.getTraceAddressSnapRange());
|
||||||
|
outboundByStaticUrl.removeMapping(me.getStaticProgramUrl(), me);
|
||||||
|
plugin.checkAndClearProgram(cc, me);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processAddedEntries(ChangeCollector cc, Set<TraceStaticMapping> added) {
|
||||||
|
for (TraceStaticMapping entry : added) {
|
||||||
|
processAddedEntry(cc, entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processAddedEntry(ChangeCollector cc, TraceStaticMapping entry) {
|
||||||
|
MappingEntry me = new MappingEntry(entry);
|
||||||
|
outboundByEntry.put(entry, me);
|
||||||
|
outboundByRange.put(me.getTraceAddressSnapRange(), me);
|
||||||
|
outboundByStaticUrl.put(me.getStaticProgramUrl(), me);
|
||||||
|
plugin.checkAndFillProgram(cc, me);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearEntriesForProgram(ChangeCollector cc, InfoPerProgram progInfo) {
|
||||||
|
for (MappingEntry me : outboundByStaticUrl.get(progInfo.url)) {
|
||||||
|
progInfo.clearProgram(cc, me);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fillEntriesForProgram(ChangeCollector cc, InfoPerProgram progInfo) {
|
||||||
|
for (MappingEntry me : outboundByStaticUrl.get(progInfo.url)) {
|
||||||
|
progInfo.fillProgram(cc, me);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<Program> getOpenMappedProgramsAtSnap(long snap) {
|
||||||
|
Set<Program> result = new HashSet<>();
|
||||||
|
for (Entry<TraceAddressSnapRange, MappingEntry> out : outboundByRange.entrySet()) {
|
||||||
|
MappingEntry me = out.getValue();
|
||||||
|
if (me.mapping.isDeleted()) {
|
||||||
|
Msg.warn(this, "Encountered deleted mapping: " + me.mapping);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!me.isStaticProgramOpen()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!out.getKey().getLifespan().contains(snap)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
result.add(me.program);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProgramLocation getOpenMappedProgramLocation(Address address, Lifespan span) {
|
||||||
|
TraceAddressSnapRange tasr = new ImmutableTraceAddressSnapRange(address, span);
|
||||||
|
// max is tasr (single address)
|
||||||
|
for (MappingEntry me : outboundByRange.headMap(tasr, true).values()) {
|
||||||
|
if (me.mapping.isDeleted()) {
|
||||||
|
Msg.warn(this, "Encountered deleted mapping: " + me.mapping);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!tasr.intersects(me.getTraceAddressSnapRange())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (me.isStaticProgramOpen()) {
|
||||||
|
return me.mapTraceAddressToProgramLocation(address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void collectOpenMappedViews(Map<Program, Collection<MappedAddressRange>> result,
|
||||||
|
AddressRange rng, Lifespan span) {
|
||||||
|
TraceAddressSnapRange tasr = new ImmutableTraceAddressSnapRange(rng, span);
|
||||||
|
TraceAddressSnapRange max = new ImmutableTraceAddressSnapRange(rng.getMaxAddress(), span);
|
||||||
|
for (MappingEntry me : outboundByRange.headMap(max, true).values()) {
|
||||||
|
if (me.mapping.isDeleted()) {
|
||||||
|
Msg.warn(this, "Encountered deleted mapping: " + me.mapping);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (me.program == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!tasr.intersects(me.getTraceAddressSnapRange())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
AddressRange srcRng = me.getTraceRange().intersect(rng);
|
||||||
|
AddressRange dstRng = me.mapTraceRangeToProgram(rng);
|
||||||
|
result.computeIfAbsent(me.program, p -> new TreeSet<>())
|
||||||
|
.add(new MappedAddressRange(srcRng, dstRng));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<Program, Collection<MappedAddressRange>> getOpenMappedViews(AddressSetView set,
|
||||||
|
Lifespan span) {
|
||||||
|
/**
|
||||||
|
* NB. Cannot use the OverlappingObjectIterator here. Because of the snap dimension, objects
|
||||||
|
* may not be disjoint in the address dimension.
|
||||||
|
*/
|
||||||
|
Map<Program, Collection<MappedAddressRange>> result = new HashMap<>();
|
||||||
|
for (AddressRange rng : set) {
|
||||||
|
collectOpenMappedViews(result, rng, span);
|
||||||
|
}
|
||||||
|
return Collections.unmodifiableMap(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void collectMappedProgramUrlsInView(Set<URL> result, AddressRange rng, Lifespan span) {
|
||||||
|
TraceAddressSnapRange tasr = new ImmutableTraceAddressSnapRange(rng, span);
|
||||||
|
TraceAddressSnapRange max = new ImmutableTraceAddressSnapRange(rng.getMaxAddress(), span);
|
||||||
|
for (MappingEntry me : outboundByRange.headMap(max, true).values()) {
|
||||||
|
if (me.mapping.isDeleted()) {
|
||||||
|
Msg.warn(this, "Encountered deleted mapping: " + me.mapping);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!tasr.intersects(me.getTraceAddressSnapRange())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
result.add(me.getStaticProgramUrl());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<URL> getMappedProgramUrlsInView(AddressSetView set, Lifespan span) {
|
||||||
|
/**
|
||||||
|
* NB. Cannot use the OverlappingObjectIterator here. Because of the snap dimension, objects
|
||||||
|
* may not be disjoint in the address dimension.
|
||||||
|
*/
|
||||||
|
Set<URL> result = new HashSet<>();
|
||||||
|
for (AddressRange rng : set) {
|
||||||
|
collectMappedProgramUrlsInView(result, rng, span);
|
||||||
|
}
|
||||||
|
return Collections.unmodifiableSet(result);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,202 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.app.plugin.core.debug.service.modules;
|
||||||
|
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingServicePlugin.ChangeCollector;
|
||||||
|
import ghidra.program.model.address.*;
|
||||||
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.program.util.ProgramLocation;
|
||||||
|
import ghidra.trace.model.*;
|
||||||
|
import ghidra.trace.model.modules.TraceStaticMapping;
|
||||||
|
import ghidra.util.Msg;
|
||||||
|
|
||||||
|
class MappingEntry {
|
||||||
|
final TraceStaticMapping mapping;
|
||||||
|
final TraceAddressSnapRange tasr;
|
||||||
|
|
||||||
|
Program program;
|
||||||
|
private AddressRange staticRange;
|
||||||
|
|
||||||
|
public MappingEntry(TraceStaticMapping mapping) {
|
||||||
|
this.mapping = mapping;
|
||||||
|
// Yes, mapping range and lifespan are immutable
|
||||||
|
this.tasr = new ImmutableTraceAddressSnapRange(mapping.getTraceAddressRange(),
|
||||||
|
mapping.getLifespan());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (!(o instanceof MappingEntry that)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Yes, use identity, since it should be the same trace db records
|
||||||
|
if (this.mapping != that.mapping) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.program != that.program) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!Objects.equals(this.staticRange, that.staticRange)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Trace getTrace() {
|
||||||
|
return mapping.getTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
Address addrOrMin(Program program, String addr) {
|
||||||
|
AddressFactory factory = program.getAddressFactory();
|
||||||
|
Address result = factory.getAddress(addr);
|
||||||
|
if (result == null) {
|
||||||
|
Msg.warn(this, "Mapping entry has invalid static address: " + addr);
|
||||||
|
result = factory.getDefaultAddressSpace().getMinAddress();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Address addrOrMax(Address start, long length) {
|
||||||
|
Address result = start.addWrapSpace(length);
|
||||||
|
if (result.compareTo(start) < 0) {
|
||||||
|
Msg.warn(this, "Mapping entry caused overflow in static address space");
|
||||||
|
return start.getAddressSpace().getMaxAddress();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearProgram(ChangeCollector cc, Program program) {
|
||||||
|
this.program = null;
|
||||||
|
this.staticRange = null;
|
||||||
|
cc.traceAffected(getTrace());
|
||||||
|
cc.programAffected(program);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fillProgram(ChangeCollector cc, Program program) {
|
||||||
|
this.program = program;
|
||||||
|
Address minAddr = addrOrMin(program, mapping.getStaticAddress());
|
||||||
|
Address maxAddr = addrOrMax(minAddr, mapping.getLength() - 1);
|
||||||
|
this.staticRange = new AddressRangeImpl(minAddr, maxAddr);
|
||||||
|
cc.traceAffected(getTrace());
|
||||||
|
cc.programAffected(program);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AddressRange getTraceRange() {
|
||||||
|
return mapping.getTraceAddressRange();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Address getTraceAddress() {
|
||||||
|
return mapping.getMinTraceAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AddressRange getStaticRange() {
|
||||||
|
return staticRange;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Address getStaticAddress() {
|
||||||
|
if (staticRange == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return staticRange.getMinAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TraceSpan getTraceSpan() {
|
||||||
|
return new DefaultTraceSpan(mapping.getTrace(), mapping.getLifespan());
|
||||||
|
}
|
||||||
|
|
||||||
|
public TraceAddressSnapRange getTraceAddressSnapRange() {
|
||||||
|
return tasr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInTraceRange(Address address, Long snap) {
|
||||||
|
return mapping.getTraceAddressRange().contains(address) &&
|
||||||
|
(snap == null || mapping.getLifespan().contains(snap));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInTraceRange(AddressRange rng, Long snap) {
|
||||||
|
return mapping.getTraceAddressRange().intersects(rng) &&
|
||||||
|
(snap == null || mapping.getLifespan().contains(snap));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInTraceLifespan(long snap) {
|
||||||
|
return mapping.getLifespan().contains(snap);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInProgramRange(Address address) {
|
||||||
|
if (staticRange == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return staticRange.contains(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInProgramRange(AddressRange rng) {
|
||||||
|
if (staticRange == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return staticRange.intersects(rng);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Address mapTraceAddressToProgram(Address address) {
|
||||||
|
assert isInTraceRange(address, null);
|
||||||
|
long offset = address.subtract(mapping.getMinTraceAddress());
|
||||||
|
return staticRange.getMinAddress().addWrapSpace(offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProgramLocation mapTraceAddressToProgramLocation(Address address) {
|
||||||
|
if (program == null) {
|
||||||
|
throw new IllegalStateException("Static program is not opened");
|
||||||
|
}
|
||||||
|
return new ProgramLocation(program, mapTraceAddressToProgram(address));
|
||||||
|
}
|
||||||
|
|
||||||
|
public AddressRange mapTraceRangeToProgram(AddressRange rng) {
|
||||||
|
assert isInTraceRange(rng, null);
|
||||||
|
AddressRange part = rng.intersect(mapping.getTraceAddressRange());
|
||||||
|
Address min = mapTraceAddressToProgram(part.getMinAddress());
|
||||||
|
Address max = mapTraceAddressToProgram(part.getMaxAddress());
|
||||||
|
return new AddressRangeImpl(min, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Address mapProgramAddressToTrace(Address address) {
|
||||||
|
assert isInProgramRange(address);
|
||||||
|
long offset = address.subtract(staticRange.getMinAddress());
|
||||||
|
return mapping.getMinTraceAddress().addWrapSpace(offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected TraceLocation mapProgramAddressToTraceLocation(Address address) {
|
||||||
|
return new DefaultTraceLocation(mapping.getTrace(), null, mapping.getLifespan(),
|
||||||
|
mapProgramAddressToTrace(address));
|
||||||
|
}
|
||||||
|
|
||||||
|
public AddressRange mapProgramRangeToTrace(AddressRange rng) {
|
||||||
|
assert (rng.intersects(staticRange));
|
||||||
|
AddressRange part = rng.intersect(staticRange);
|
||||||
|
Address min = mapProgramAddressToTrace(part.getMinAddress());
|
||||||
|
Address max = mapProgramAddressToTrace(part.getMaxAddress());
|
||||||
|
return new AddressRangeImpl(min, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isStaticProgramOpen() {
|
||||||
|
return program != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public URL getStaticProgramUrl() {
|
||||||
|
return mapping.getStaticProgramURL();
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.core.debug.service.tracemgr;
|
package ghidra.app.plugin.core.debug.service.tracemgr;
|
||||||
|
|
||||||
import static ghidra.framework.main.DataTreeDialogType.*;
|
import static ghidra.framework.main.DataTreeDialogType.OPEN;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
|
@ -656,8 +656,10 @@ public class DebuggerTraceManagerServicePlugin extends Plugin
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized Collection<Trace> getOpenTraces() {
|
public synchronized Collection<Trace> getOpenTraces() {
|
||||||
|
synchronized (listenersByTrace) {
|
||||||
return Set.copyOf(tracesView);
|
return Set.copyOf(tracesView);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DebuggerCoordinates getCurrent() {
|
public DebuggerCoordinates getCurrent() {
|
||||||
|
@ -998,8 +1000,8 @@ public class DebuggerTraceManagerServicePlugin extends Plugin
|
||||||
protected void doCloseTraces(Collection<Trace> traces, Collection<Target> targets) {
|
protected void doCloseTraces(Collection<Trace> traces, Collection<Target> targets) {
|
||||||
for (Trace t : traces) {
|
for (Trace t : traces) {
|
||||||
if (t.getConsumerList().contains(this)) {
|
if (t.getConsumerList().contains(this)) {
|
||||||
firePluginEvent(new TraceClosedPluginEvent(getName(), t));
|
|
||||||
doTraceClosed(t);
|
doTraceClosed(t);
|
||||||
|
firePluginEvent(new TraceClosedPluginEvent(getName(), t));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TargetActionTask.executeTask(tool, new DisconnectTask(tool, targets));
|
TargetActionTask.executeTask(tool, new DisconnectTask(tool, targets));
|
||||||
|
|
|
@ -614,8 +614,7 @@ public abstract class AbstractGhidraHeadedDebuggerTest
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void beforeClass() {
|
public static void beforeClass() {
|
||||||
|
// Note: we decided to move this up to a framework-level base test class
|
||||||
// Note: we may decided to move this up to a framework-level base test class
|
|
||||||
TestDataStructureErrorHandlerInstaller.installConcurrentExceptionErrorHandler();
|
TestDataStructureErrorHandlerInstaller.installConcurrentExceptionErrorHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -95,6 +95,7 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
|
||||||
try (ToyDBTraceBuilder r = new ToyDBTraceBuilder(saved)) {
|
try (ToyDBTraceBuilder r = new ToyDBTraceBuilder(saved)) {
|
||||||
assertNotSame(tb.trace, r.trace);
|
assertNotSame(tb.trace, r.trace);
|
||||||
traceManager.openTrace(r.trace);
|
traceManager.openTrace(r.trace);
|
||||||
|
waitForDomainObject(r.trace);
|
||||||
return r.trace;
|
return r.trace;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -240,10 +241,11 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddMappingThenCopyAndTranslateStaticToTraceMissWayBefore() throws Exception {
|
public void testAddMappingThenCopyAndTranslateStaticToTraceMissWayBefore() throws Throwable {
|
||||||
addMapping();
|
addMapping();
|
||||||
copyTrace();
|
copyTrace();
|
||||||
add2ndMapping();
|
add2ndMapping();
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
|
||||||
Set<TraceLocation> locations = mappingService.getOpenMappedLocations(
|
Set<TraceLocation> locations = mappingService.getOpenMappedLocations(
|
||||||
new ProgramLocation(program, stSpace.getAddress(0x00000bad)));
|
new ProgramLocation(program, stSpace.getAddress(0x00000bad)));
|
||||||
|
@ -251,10 +253,11 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddMappingThenCopyAndTranslateStaticToTraceMissJustBefore() throws Exception {
|
public void testAddMappingThenCopyAndTranslateStaticToTraceMissJustBefore() throws Throwable {
|
||||||
addMapping();
|
addMapping();
|
||||||
copyTrace();
|
copyTrace();
|
||||||
add2ndMapping();
|
add2ndMapping();
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
|
||||||
Set<TraceLocation> locations = mappingService.getOpenMappedLocations(
|
Set<TraceLocation> locations = mappingService.getOpenMappedLocations(
|
||||||
new ProgramLocation(program, stSpace.getAddress(0x001fffff)));
|
new ProgramLocation(program, stSpace.getAddress(0x001fffff)));
|
||||||
|
@ -262,10 +265,11 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddMappingThenCopyAndTranslateStaticToTraceHitAtStart() throws Exception {
|
public void testAddMappingThenCopyAndTranslateStaticToTraceHitAtStart() throws Throwable {
|
||||||
addMapping();
|
addMapping();
|
||||||
Trace copy = copyTrace();
|
Trace copy = copyTrace();
|
||||||
add2ndMapping();
|
add2ndMapping();
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
|
||||||
Set<TraceLocation> locations = mappingService.getOpenMappedLocations(
|
Set<TraceLocation> locations = mappingService.getOpenMappedLocations(
|
||||||
new ProgramLocation(program, stSpace.getAddress(0x00200000)));
|
new ProgramLocation(program, stSpace.getAddress(0x00200000)));
|
||||||
|
@ -281,10 +285,11 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddMappingThenCopyAndTranslateStaticToTraceHitInMiddle() throws Exception {
|
public void testAddMappingThenCopyAndTranslateStaticToTraceHitInMiddle() throws Throwable {
|
||||||
addMapping();
|
addMapping();
|
||||||
Trace copy = copyTrace();
|
Trace copy = copyTrace();
|
||||||
add2ndMapping();
|
add2ndMapping();
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
|
||||||
Set<TraceLocation> locations = mappingService.getOpenMappedLocations(
|
Set<TraceLocation> locations = mappingService.getOpenMappedLocations(
|
||||||
new ProgramLocation(program, stSpace.getAddress(0x00200833)));
|
new ProgramLocation(program, stSpace.getAddress(0x00200833)));
|
||||||
|
@ -298,10 +303,11 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddMappingThenCopyAndTranslateStaticToTraceHitAtEnd() throws Exception {
|
public void testAddMappingThenCopyAndTranslateStaticToTraceHitAtEnd() throws Throwable {
|
||||||
addMapping();
|
addMapping();
|
||||||
Trace copy = copyTrace();
|
Trace copy = copyTrace();
|
||||||
add2ndMapping();
|
add2ndMapping();
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
|
||||||
Set<TraceLocation> locations = mappingService.getOpenMappedLocations(
|
Set<TraceLocation> locations = mappingService.getOpenMappedLocations(
|
||||||
new ProgramLocation(program, stSpace.getAddress(0x00200fff)));
|
new ProgramLocation(program, stSpace.getAddress(0x00200fff)));
|
||||||
|
@ -315,10 +321,11 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddMappingThenCopyAndTranslateStaticToTraceMissJustAfter() throws Exception {
|
public void testAddMappingThenCopyAndTranslateStaticToTraceMissJustAfter() throws Throwable {
|
||||||
addMapping();
|
addMapping();
|
||||||
copyTrace();
|
copyTrace();
|
||||||
add2ndMapping();
|
add2ndMapping();
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
|
||||||
Set<TraceLocation> locations = mappingService.getOpenMappedLocations(
|
Set<TraceLocation> locations = mappingService.getOpenMappedLocations(
|
||||||
new ProgramLocation(program, stSpace.getAddress(0x00201000)));
|
new ProgramLocation(program, stSpace.getAddress(0x00201000)));
|
||||||
|
@ -326,10 +333,11 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddMappingThenCopyAndTranslateStaticToTraceMissWayAfter() throws Exception {
|
public void testAddMappingThenCopyAndTranslateStaticToTraceMissWayAfter() throws Throwable {
|
||||||
addMapping();
|
addMapping();
|
||||||
copyTrace();
|
copyTrace();
|
||||||
add2ndMapping();
|
add2ndMapping();
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
|
||||||
Set<TraceLocation> locations = mappingService.getOpenMappedLocations(
|
Set<TraceLocation> locations = mappingService.getOpenMappedLocations(
|
||||||
new ProgramLocation(program, stSpace.getAddress(0xbadbadbadL)));
|
new ProgramLocation(program, stSpace.getAddress(0xbadbadbadL)));
|
||||||
|
@ -377,10 +385,11 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddMappingThenTranslateStaticViewToTraceEmpty() throws Exception {
|
public void testAddMappingThenTranslateStaticViewToTraceEmpty() throws Throwable {
|
||||||
addMapping();
|
addMapping();
|
||||||
copyTrace();
|
copyTrace();
|
||||||
add2ndMapping();
|
add2ndMapping();
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
|
||||||
Map<TraceSpan, Collection<MappedAddressRange>> views =
|
Map<TraceSpan, Collection<MappedAddressRange>> views =
|
||||||
mappingService.getOpenMappedViews(program, new AddressSet());
|
mappingService.getOpenMappedViews(program, new AddressSet());
|
||||||
|
@ -388,10 +397,11 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddMappingThenTranslateStaticViewToTraceReplete() throws Exception {
|
public void testAddMappingThenTranslateStaticViewToTraceReplete() throws Throwable {
|
||||||
addMapping();
|
addMapping();
|
||||||
Trace copy = copyTrace();
|
Trace copy = copyTrace();
|
||||||
add2ndMapping();
|
add2ndMapping();
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
|
||||||
AddressSet set = new AddressSet();
|
AddressSet set = new AddressSet();
|
||||||
// Before
|
// Before
|
||||||
|
@ -438,10 +448,12 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddMappingThenCloseStaticAndOpenMappedMissWayBefore() throws Exception {
|
public void testAddMappingThenCloseStaticAndOpenMappedMissWayBefore() throws Throwable {
|
||||||
// NOTE: Does not make sense to test program->trace, as program has no mapping records
|
// NOTE: Does not make sense to test program->trace, as program has no mapping records
|
||||||
addMapping();
|
addMapping();
|
||||||
programManager.closeProgram(program, true);
|
programManager.closeProgram(program, true);
|
||||||
|
waitForSwing();
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
|
||||||
AddressSet addrSet = new AddressSet(dynSpace.getAddress(0x00000bad));
|
AddressSet addrSet = new AddressSet(dynSpace.getAddress(0x00000bad));
|
||||||
Set<Program> programSet =
|
Set<Program> programSet =
|
||||||
|
@ -451,9 +463,11 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddMappingThenCloseStaticAndOpenMappedHitInMiddle() throws Exception {
|
public void testAddMappingThenCloseStaticAndOpenMappedHitInMiddle() throws Throwable {
|
||||||
addMapping();
|
addMapping();
|
||||||
programManager.closeProgram(program, true);
|
programManager.closeProgram(program, true);
|
||||||
|
waitForSwing();
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
|
||||||
AddressSet addrSet = new AddressSet(dynSpace.getAddress(0x00100c0d));
|
AddressSet addrSet = new AddressSet(dynSpace.getAddress(0x00100c0d));
|
||||||
Set<Program> programSet =
|
Set<Program> programSet =
|
||||||
|
@ -465,9 +479,11 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddMappingThenCloseStaticAndOpenMappedMissWayAfter() throws Exception {
|
public void testAddMappingThenCloseStaticAndOpenMappedMissWayAfter() throws Throwable {
|
||||||
addMapping();
|
addMapping();
|
||||||
programManager.closeProgram(program, true);
|
programManager.closeProgram(program, true);
|
||||||
|
waitForSwing();
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
|
||||||
AddressSet addrSet = new AddressSet(dynSpace.getAddress(0xbadbadbadL));
|
AddressSet addrSet = new AddressSet(dynSpace.getAddress(0xbadbadbadL));
|
||||||
Set<Program> programSet =
|
Set<Program> programSet =
|
||||||
|
@ -478,14 +494,17 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddMappingThenCloseStaticAndTranslateTraceToStaticHitInMiddle()
|
public void testAddMappingThenCloseStaticAndTranslateTraceToStaticHitInMiddle()
|
||||||
throws Exception {
|
throws Throwable {
|
||||||
addMapping();
|
addMapping();
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
// pre-check
|
// pre-check
|
||||||
assertNotNull(mappingService.getOpenMappedLocation(
|
assertNotNull(mappingService.getOpenMappedLocation(
|
||||||
new DefaultTraceLocation(tb.trace, null, Lifespan.nowOn(0),
|
new DefaultTraceLocation(tb.trace, null, Lifespan.nowOn(0),
|
||||||
dynSpace.getAddress(0x00100c0d))));
|
dynSpace.getAddress(0x00100c0d))));
|
||||||
|
|
||||||
programManager.closeProgram(program, true);
|
programManager.closeProgram(program, true);
|
||||||
|
waitForSwing();
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
|
||||||
assertNull(mappingService.getOpenMappedLocation(
|
assertNull(mappingService.getOpenMappedLocation(
|
||||||
new DefaultTraceLocation(tb.trace, null, Lifespan.nowOn(0),
|
new DefaultTraceLocation(tb.trace, null, Lifespan.nowOn(0),
|
||||||
|
@ -494,14 +513,16 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddMappingThenCloseTraceAndTranslateStaticToTraceHitInMiddle()
|
public void testAddMappingThenCloseTraceAndTranslateStaticToTraceHitInMiddle()
|
||||||
throws Exception {
|
throws Throwable {
|
||||||
addMapping();
|
addMapping();
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
// pre-check
|
// pre-check
|
||||||
assertEquals(1, mappingService.getOpenMappedLocations(
|
assertEquals(1, mappingService.getOpenMappedLocations(
|
||||||
new ProgramLocation(program, stSpace.getAddress(0x00200c0d))).size());
|
new ProgramLocation(program, stSpace.getAddress(0x00200c0d))).size());
|
||||||
|
|
||||||
traceManager.closeTrace(tb.trace);
|
traceManager.closeTrace(tb.trace);
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
|
||||||
assertTrue(mappingService.getOpenMappedLocations(
|
assertTrue(mappingService.getOpenMappedLocations(
|
||||||
new ProgramLocation(program, stSpace.getAddress(0x00200c0d))).isEmpty());
|
new ProgramLocation(program, stSpace.getAddress(0x00200c0d))).isEmpty());
|
||||||
|
@ -509,9 +530,11 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddMappingThenCloseAndReopenStaticAndTranslateTraceToStaticHitInMiddle()
|
public void testAddMappingThenCloseAndReopenStaticAndTranslateTraceToStaticHitInMiddle()
|
||||||
throws Exception {
|
throws Throwable {
|
||||||
addMapping();
|
addMapping();
|
||||||
programManager.closeProgram(program, true);
|
programManager.closeProgram(program, true);
|
||||||
|
waitForSwing();
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
// pre-check
|
// pre-check
|
||||||
assertNull(mappingService.getOpenMappedLocation(
|
assertNull(mappingService.getOpenMappedLocation(
|
||||||
new DefaultTraceLocation(tb.trace, null, Lifespan.nowOn(0),
|
new DefaultTraceLocation(tb.trace, null, Lifespan.nowOn(0),
|
||||||
|
@ -519,6 +542,7 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
|
||||||
|
|
||||||
programManager.openProgram(program);
|
programManager.openProgram(program);
|
||||||
waitForProgram(program);
|
waitForProgram(program);
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
|
||||||
assertNotNull(mappingService.getOpenMappedLocation(
|
assertNotNull(mappingService.getOpenMappedLocation(
|
||||||
new DefaultTraceLocation(tb.trace, null, Lifespan.nowOn(0),
|
new DefaultTraceLocation(tb.trace, null, Lifespan.nowOn(0),
|
||||||
|
@ -527,17 +551,19 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddMappingThenCloseAndReopenTraceAndTranslateStaticToTraceHitInMiddle()
|
public void testAddMappingThenCloseAndReopenTraceAndTranslateStaticToTraceHitInMiddle()
|
||||||
throws Exception {
|
throws Throwable {
|
||||||
addMapping();
|
addMapping();
|
||||||
traceManager.closeTrace(tb.trace);
|
traceManager.closeTrace(tb.trace);
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
|
||||||
// pre-check
|
// pre-check
|
||||||
assertTrue(mappingService.getOpenMappedLocations(
|
assertTrue(mappingService.getOpenMappedLocations(
|
||||||
new ProgramLocation(program, stSpace.getAddress(0x00200c0d))).isEmpty());
|
new ProgramLocation(program, stSpace.getAddress(0x00200c0d))).isEmpty());
|
||||||
|
|
||||||
traceManager.openTrace(tb.trace);
|
traceManager.openTrace(tb.trace);
|
||||||
waitForSwing();
|
waitForDomainObject(tb.trace);
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
|
||||||
assertEquals(1, mappingService.getOpenMappedLocations(
|
assertEquals(1, mappingService.getOpenMappedLocations(
|
||||||
new ProgramLocation(program, stSpace.getAddress(0x00200c0d))).size());
|
new ProgramLocation(program, stSpace.getAddress(0x00200c0d))).size());
|
||||||
|
@ -545,7 +571,7 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddMappingThenRemoveButAbortThenTranslateTraceToStaticHitInMiddle()
|
public void testAddMappingThenRemoveButAbortThenTranslateTraceToStaticHitInMiddle()
|
||||||
throws Exception {
|
throws Throwable {
|
||||||
addMapping();
|
addMapping();
|
||||||
TraceLocation goodLoc =
|
TraceLocation goodLoc =
|
||||||
new DefaultTraceLocation(tb.trace, null, Lifespan.nowOn(0),
|
new DefaultTraceLocation(tb.trace, null, Lifespan.nowOn(0),
|
||||||
|
@ -553,19 +579,23 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
|
||||||
try (Transaction tx = tb.startTransaction()) {
|
try (Transaction tx = tb.startTransaction()) {
|
||||||
mappingManager.findContaining(dynSpace.getAddress(0x00100000), 0).delete();
|
mappingManager.findContaining(dynSpace.getAddress(0x00100000), 0).delete();
|
||||||
waitForDomainObject(tb.trace);
|
waitForDomainObject(tb.trace);
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
// pre-check
|
// pre-check
|
||||||
assertNull(mappingService.getOpenMappedLocation(goodLoc));
|
assertNull(mappingService.getOpenMappedLocation(goodLoc));
|
||||||
tx.abort();
|
tx.abort();
|
||||||
}
|
}
|
||||||
waitForDomainObject(tb.trace);
|
waitForDomainObject(tb.trace);
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
|
||||||
assertNotNull(mappingService.getOpenMappedLocation(goodLoc));
|
assertNotNull(mappingService.getOpenMappedLocation(goodLoc));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddCorrelationRemoveButUndoThenRequestMappingDynamicToStaticWithin()
|
public void testAddCorrelationRemoveButUndoThenRequestMappingDynamicToStaticWithin()
|
||||||
throws Exception {
|
throws Throwable {
|
||||||
addMapping();
|
addMapping();
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
|
||||||
TraceLocation goodLoc =
|
TraceLocation goodLoc =
|
||||||
new DefaultTraceLocation(tb.trace, null, Lifespan.nowOn(0),
|
new DefaultTraceLocation(tb.trace, null, Lifespan.nowOn(0),
|
||||||
dynSpace.getAddress(0x00100c0d));
|
dynSpace.getAddress(0x00100c0d));
|
||||||
|
@ -577,11 +607,13 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
|
||||||
mappingManager.findContaining(dynSpace.getAddress(0x00100000), 0).delete();
|
mappingManager.findContaining(dynSpace.getAddress(0x00100000), 0).delete();
|
||||||
}
|
}
|
||||||
waitForDomainObject(tb.trace);
|
waitForDomainObject(tb.trace);
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
|
||||||
// pre-check
|
// pre-check
|
||||||
assertNull(mappingService.getOpenMappedLocation(goodLoc));
|
assertNull(mappingService.getOpenMappedLocation(goodLoc));
|
||||||
|
|
||||||
undo(tb.trace, true);
|
undo(tb.trace, true);
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
|
||||||
assertNotNull(mappingService.getOpenMappedLocation(goodLoc));
|
assertNotNull(mappingService.getOpenMappedLocation(goodLoc));
|
||||||
}
|
}
|
||||||
|
@ -619,7 +651,7 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMapFullSpace() throws Exception {
|
public void testMapFullSpace() throws Throwable {
|
||||||
try (Transaction tx = tb.startTransaction()) {
|
try (Transaction tx = tb.startTransaction()) {
|
||||||
TraceLocation traceLoc =
|
TraceLocation traceLoc =
|
||||||
new DefaultTraceLocation(tb.trace, null, Lifespan.nowOn(0), tb.addr(0));
|
new DefaultTraceLocation(tb.trace, null, Lifespan.nowOn(0), tb.addr(0));
|
||||||
|
@ -627,7 +659,10 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
|
||||||
// NB. 0 indicates 1 << 64
|
// NB. 0 indicates 1 << 64
|
||||||
mappingService.addMapping(traceLoc, progLoc, 0, true);
|
mappingService.addMapping(traceLoc, progLoc, 0, true);
|
||||||
}
|
}
|
||||||
waitForPass(() -> assertMapsTwoWay(0L, 0L));
|
waitForSwing();
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
|
||||||
|
assertMapsTwoWay(0L, 0L);
|
||||||
assertMapsTwoWay(-1L, -1L);
|
assertMapsTwoWay(-1L, -1L);
|
||||||
assertMapsTwoWay(Long.MAX_VALUE, Long.MAX_VALUE);
|
assertMapsTwoWay(Long.MAX_VALUE, Long.MAX_VALUE);
|
||||||
assertMapsTwoWay(Long.MIN_VALUE, Long.MIN_VALUE);
|
assertMapsTwoWay(Long.MIN_VALUE, Long.MIN_VALUE);
|
||||||
|
|
|
@ -33,7 +33,7 @@ import ghidra.util.database.*;
|
||||||
import ghidra.util.database.annot.*;
|
import ghidra.util.database.annot.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The implementation of a stack mapping, directly via a database object
|
* The implementation of a static mapping, directly via a database object
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* Version history:
|
* Version history:
|
||||||
|
|
|
@ -26,7 +26,30 @@ import ghidra.program.model.listing.CodeUnit;
|
||||||
import ghidra.trace.model.TraceAddressSnapRange;
|
import ghidra.trace.model.TraceAddressSnapRange;
|
||||||
import ghidra.util.AbstractPeekableIterator;
|
import ghidra.util.AbstractPeekableIterator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An iterator of overlapping objects return from two given iterators.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The given iterators, named left and right, must return objects each having a range attribute.
|
||||||
|
* Each iterator must return objects having disjoint ranges, i.e., no two objects from the
|
||||||
|
* <em>same</em> iterator may intersect. Each iterator must also return the objects sorted by min
|
||||||
|
* address. This iterator will then discover every case where an object from the left iterator
|
||||||
|
* overlaps an object from the right iterator, and return a pair for each such instance, in order of
|
||||||
|
* min address.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* <b>WARNING:</b> To avoid heap pollution, this iterator re-uses the same {@link Pair} on each call
|
||||||
|
* to {@link #next()}. If you need to save an overlapping pair, you must copy it.
|
||||||
|
*
|
||||||
|
* @param <L> the type of objects returned by the left iterator
|
||||||
|
* @param <R> the type of objects returned by the right iterator
|
||||||
|
*/
|
||||||
public class OverlappingObjectIterator<L, R> extends AbstractPeekableIterator<Pair<L, R>> {
|
public class OverlappingObjectIterator<L, R> extends AbstractPeekableIterator<Pair<L, R>> {
|
||||||
|
/**
|
||||||
|
* A means of obtaining the range attribute from each object
|
||||||
|
*
|
||||||
|
* @param <T> the type of objects returned by an iterator
|
||||||
|
*/
|
||||||
public interface Ranger<T> {
|
public interface Ranger<T> {
|
||||||
Address getMinAddress(T t);
|
Address getMinAddress(T t);
|
||||||
|
|
||||||
|
|
|
@ -483,7 +483,7 @@ public abstract class AbstractDebuggerBreakpointMarkerPluginTest<T>
|
||||||
addMappedBreakpointOpenAndWait(); // wasteful, but whatever
|
addMappedBreakpointOpenAndWait(); // wasteful, but whatever
|
||||||
for (LogicalBreakpoint lb : List.copyOf(breakpointService.getAllBreakpoints())) {
|
for (LogicalBreakpoint lb : List.copyOf(breakpointService.getAllBreakpoints())) {
|
||||||
TraceBreakpoint brk = Unique.assertOne(lb.getTraceBreakpoints(tb.trace));
|
TraceBreakpoint brk = Unique.assertOne(lb.getTraceBreakpoints(tb.trace));
|
||||||
lb.delete();
|
waitOn(lb.delete());
|
||||||
handleDeleteBreakpointInvocation(brk);
|
handleDeleteBreakpointInvocation(brk);
|
||||||
}
|
}
|
||||||
waitForPass(() -> assertEquals(0, breakpointService.getAllBreakpoints().size()));
|
waitForPass(() -> assertEquals(0, breakpointService.getAllBreakpoints().size()));
|
||||||
|
@ -515,7 +515,7 @@ public abstract class AbstractDebuggerBreakpointMarkerPluginTest<T>
|
||||||
addMappedBreakpointOpenAndWait(); // wasteful, but whatever
|
addMappedBreakpointOpenAndWait(); // wasteful, but whatever
|
||||||
for (LogicalBreakpoint lb : List.copyOf(breakpointService.getAllBreakpoints())) {
|
for (LogicalBreakpoint lb : List.copyOf(breakpointService.getAllBreakpoints())) {
|
||||||
TraceBreakpoint brk = Unique.assertOne(lb.getTraceBreakpoints(tb.trace));
|
TraceBreakpoint brk = Unique.assertOne(lb.getTraceBreakpoints(tb.trace));
|
||||||
lb.delete();
|
waitOn(lb.delete());
|
||||||
handleDeleteBreakpointInvocation(brk);
|
handleDeleteBreakpointInvocation(brk);
|
||||||
}
|
}
|
||||||
waitForPass(() -> assertEquals(0, breakpointService.getAllBreakpoints().size()));
|
waitForPass(() -> assertEquals(0, breakpointService.getAllBreakpoints().size()));
|
||||||
|
|
|
@ -46,8 +46,6 @@ import ghidra.trace.model.memory.TraceMemoryFlag;
|
||||||
import ghidra.trace.model.memory.TraceMemoryRegion;
|
import ghidra.trace.model.memory.TraceMemoryRegion;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.SystemUtilities;
|
import ghidra.util.SystemUtilities;
|
||||||
import utility.function.ExceptionalCallback;
|
|
||||||
import utility.function.ExceptionalSupplier;
|
|
||||||
|
|
||||||
public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
extends AbstractGhidraHeadedDebuggerIntegrationTest {
|
extends AbstractGhidraHeadedDebuggerIntegrationTest {
|
||||||
|
@ -102,22 +100,6 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected <U, E extends Throwable> U expectMappingChange(ExceptionalSupplier<U, E> supplier)
|
|
||||||
throws Throwable {
|
|
||||||
mappingChangeListener.ar.set(false, null);
|
|
||||||
U result = supplier.get();
|
|
||||||
waitOn(mappingChangeListener.ar.waitValue(true));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected <E extends Throwable> void expectMappingChange(ExceptionalCallback<E> runnable)
|
|
||||||
throws Throwable {
|
|
||||||
expectMappingChange(() -> {
|
|
||||||
runnable.call();
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
protected DebuggerStaticMappingService mappingService;
|
protected DebuggerStaticMappingService mappingService;
|
||||||
protected DebuggerLogicalBreakpointService breakpointService;
|
protected DebuggerLogicalBreakpointService breakpointService;
|
||||||
|
|
||||||
|
@ -134,8 +116,6 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
|
|
||||||
protected NoDuplicatesBreakpointsChangeListener changeListener =
|
protected NoDuplicatesBreakpointsChangeListener changeListener =
|
||||||
new NoDuplicatesBreakpointsChangeListener();
|
new NoDuplicatesBreakpointsChangeListener();
|
||||||
protected ForTimingMappingChangeListener mappingChangeListener =
|
|
||||||
new ForTimingMappingChangeListener();
|
|
||||||
|
|
||||||
protected abstract void createTarget1() throws Throwable;
|
protected abstract void createTarget1() throws Throwable;
|
||||||
|
|
||||||
|
@ -169,10 +149,12 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
|
|
||||||
protected abstract TraceBreakpoint findLoc(Set<TraceBreakpoint> locs, int index);
|
protected abstract TraceBreakpoint findLoc(Set<TraceBreakpoint> locs, int index);
|
||||||
|
|
||||||
protected abstract void handleToggleBreakpointInvocation(TraceBreakpoint expectedBreakpoint,
|
protected abstract void handleToggleBreakpointInvocation(T target,
|
||||||
|
TraceBreakpoint expectedBreakpoint,
|
||||||
boolean expectedEnabled) throws Throwable;
|
boolean expectedEnabled) throws Throwable;
|
||||||
|
|
||||||
protected abstract void handleDeleteBreakpointInvocation(TraceBreakpoint expectedBreakpoint)
|
protected abstract void handleDeleteBreakpointInvocation(T target,
|
||||||
|
TraceBreakpoint expectedBreakpoint)
|
||||||
throws Throwable;
|
throws Throwable;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
|
@ -182,7 +164,6 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
mappingService = tool.getService(DebuggerStaticMappingService.class);
|
mappingService = tool.getService(DebuggerStaticMappingService.class);
|
||||||
|
|
||||||
breakpointService.addChangeListener(changeListener);
|
breakpointService.addChangeListener(changeListener);
|
||||||
mappingService.addChangeListener(mappingChangeListener);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
|
@ -269,6 +250,7 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
.createInitializedBlock(".text", addr(p, 0x00400000), 0x1000, (byte) 0, monitor,
|
.createInitializedBlock(".text", addr(p, 0x00400000), 0x1000, (byte) 0, monitor,
|
||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
|
waitForDomainObject(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void addProgramBreakpoints(Program p) throws Throwable {
|
protected void addProgramBreakpoints(Program p) throws Throwable {
|
||||||
|
@ -280,6 +262,7 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
.setBookmark(addr(p, 0x00400321), LogicalBreakpoint.DISABLED_BOOKMARK_TYPE,
|
.setBookmark(addr(p, 0x00400321), LogicalBreakpoint.DISABLED_BOOKMARK_TYPE,
|
||||||
"SW_EXECUTE;1", "");
|
"SW_EXECUTE;1", "");
|
||||||
}
|
}
|
||||||
|
waitForDomainObject(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void refetchProgramBreakpoints(Program p) throws Throwable {
|
protected void refetchProgramBreakpoints(Program p) throws Throwable {
|
||||||
|
@ -297,6 +280,7 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
p.getBookmarkManager().removeBookmark(enBm);
|
p.getBookmarkManager().removeBookmark(enBm);
|
||||||
p.getBookmarkManager().removeBookmark(disBm);
|
p.getBookmarkManager().removeBookmark(disBm);
|
||||||
}
|
}
|
||||||
|
waitForDomainObject(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void assertLogicalBreakpointForLoneAccessBreakpoint(Trace trace) {
|
protected void assertLogicalBreakpointForLoneAccessBreakpoint(Trace trace) {
|
||||||
|
@ -546,8 +530,8 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
|
|
||||||
addProgramTextBlock(program);
|
addProgramTextBlock(program);
|
||||||
MR text = addTargetTextRegion(target1);
|
MR text = addTargetTextRegion(target1);
|
||||||
expectMappingChange(() -> addTextMapping(target1, text, program));
|
addTextMapping(target1, text, program);
|
||||||
waitForSwing();
|
waitOn(mappingService.changesSettled());
|
||||||
|
|
||||||
assertTrue(breakpointService.getAllBreakpoints().isEmpty());
|
assertTrue(breakpointService.getAllBreakpoints().isEmpty());
|
||||||
}
|
}
|
||||||
|
@ -564,9 +548,9 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
|
|
||||||
addProgramTextBlock(program);
|
addProgramTextBlock(program);
|
||||||
MR text = addTargetTextRegion(target1);
|
MR text = addTargetTextRegion(target1);
|
||||||
expectMappingChange(() -> addTextMapping(target1, text, program));
|
addTextMapping(target1, text, program);
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
addProgramBreakpoints(program);
|
addProgramBreakpoints(program);
|
||||||
waitForSwing();
|
|
||||||
|
|
||||||
assertLogicalBreakpointsForMappedBookmarks(trace);
|
assertLogicalBreakpointsForMappedBookmarks(trace);
|
||||||
}
|
}
|
||||||
|
@ -584,12 +568,12 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
addProgramTextBlock(program);
|
addProgramTextBlock(program);
|
||||||
MR text = addTargetTextRegion(target1);
|
MR text = addTargetTextRegion(target1);
|
||||||
addProgramBreakpoints(program);
|
addProgramBreakpoints(program);
|
||||||
waitForSwing();
|
|
||||||
|
|
||||||
changeListener.assertAgreesWithService();
|
changeListener.assertAgreesWithService();
|
||||||
|
|
||||||
expectMappingChange(() -> addTextMapping(target1, text, program));
|
addTextMapping(target1, text, program);
|
||||||
waitForSwing();
|
waitOn(mappingService.changesSettled());
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
assertLogicalBreakpointsForMappedBookmarks(trace);
|
assertLogicalBreakpointsForMappedBookmarks(trace);
|
||||||
}
|
}
|
||||||
|
@ -606,12 +590,12 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
|
|
||||||
addProgramTextBlock(program);
|
addProgramTextBlock(program);
|
||||||
MR text = addTargetTextRegion(target1);
|
MR text = addTargetTextRegion(target1);
|
||||||
expectMappingChange(() -> addTextMapping(target1, text, program));
|
addTextMapping(target1, text, program);
|
||||||
addTargetSoftwareBreakpoint(target1, text);
|
addTargetSoftwareBreakpoint(target1, text);
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
waitForPass(() -> {
|
|
||||||
assertLogicalBreakpointForMappedSoftwareBreakpoint(trace);
|
assertLogicalBreakpointForMappedSoftwareBreakpoint(trace);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -627,14 +611,14 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
addProgramTextBlock(program);
|
addProgramTextBlock(program);
|
||||||
MR text = addTargetTextRegion(target1);
|
MR text = addTargetTextRegion(target1);
|
||||||
addTargetSoftwareBreakpoint(target1, text);
|
addTargetSoftwareBreakpoint(target1, text);
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
waitForPass(() -> {
|
|
||||||
assertLogicalBreakpointForLoneSoftwareBreakpoint(trace, 1);
|
assertLogicalBreakpointForLoneSoftwareBreakpoint(trace, 1);
|
||||||
});
|
|
||||||
changeListener.assertAgreesWithService();
|
changeListener.assertAgreesWithService();
|
||||||
|
|
||||||
expectMappingChange(() -> addTextMapping(target1, text, program));
|
addTextMapping(target1, text, program);
|
||||||
waitForSwing();
|
waitOn(mappingService.changesSettled());
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
assertLogicalBreakpointForMappedSoftwareBreakpoint(trace);
|
assertLogicalBreakpointForMappedSoftwareBreakpoint(trace);
|
||||||
}
|
}
|
||||||
|
@ -660,8 +644,9 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
// NOTE: Extraneous mappings-changed events can cause timing issues here.
|
// NOTE: Extraneous mappings-changed events can cause timing issues here.
|
||||||
// TODO: Better testing for static mapping listener events?
|
// TODO: Better testing for static mapping listener events?
|
||||||
MR text = addTargetTextRegion(target1);
|
MR text = addTargetTextRegion(target1);
|
||||||
expectMappingChange(() -> addTextMapping(target1, text, program));
|
addTextMapping(target1, text, program);
|
||||||
waitForSwing();
|
waitOn(mappingService.changesSettled());
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
assertLogicalBreakpointsForMappedBookmarks(trace);
|
assertLogicalBreakpointsForMappedBookmarks(trace);
|
||||||
}
|
}
|
||||||
|
@ -680,12 +665,15 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
MR text = addTargetTextRegion(target1);
|
MR text = addTargetTextRegion(target1);
|
||||||
addTextMapping(target1, text, program);
|
addTextMapping(target1, text, program);
|
||||||
addProgramBreakpoints(program);
|
addProgramBreakpoints(program);
|
||||||
waitForSwing();
|
waitOn(mappingService.changesSettled());
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
assertTrue(breakpointService.getAllBreakpoints().isEmpty());
|
assertTrue(breakpointService.getAllBreakpoints().isEmpty());
|
||||||
|
|
||||||
expectMappingChange(() -> programManager.openProgram(program));
|
programManager.openProgram(program);
|
||||||
waitForSwing();
|
waitForDomainObject(program);
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
assertLogicalBreakpointsForMappedBookmarks(trace);
|
assertLogicalBreakpointsForMappedBookmarks(trace);
|
||||||
}
|
}
|
||||||
|
@ -704,13 +692,17 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
MR text = addTargetTextRegion(target1);
|
MR text = addTargetTextRegion(target1);
|
||||||
addTextMapping(target1, text, program);
|
addTextMapping(target1, text, program);
|
||||||
addTargetSoftwareBreakpoint(target1, text);
|
addTargetSoftwareBreakpoint(target1, text);
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
waitForPass(() -> assertLogicalBreakpointForLoneSoftwareBreakpoint(trace, 1));
|
assertLogicalBreakpointForLoneSoftwareBreakpoint(trace, 1);
|
||||||
|
|
||||||
expectMappingChange(() -> programManager.openProgram(program));
|
programManager.openProgram(program);
|
||||||
waitForSwing();
|
waitForDomainObject(program);
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
waitForPass(() -> assertLogicalBreakpointForMappedSoftwareBreakpoint(trace));
|
assertLogicalBreakpointForMappedSoftwareBreakpoint(trace);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -722,12 +714,16 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
createProgramFromTrace(trace);
|
createProgramFromTrace(trace);
|
||||||
intoProject(program);
|
intoProject(program);
|
||||||
programManager.openProgram(program);
|
programManager.openProgram(program);
|
||||||
waitForSwing();
|
waitForDomainObject(program);
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
assertTrue(breakpointService.getAllBreakpoints().isEmpty());
|
assertTrue(breakpointService.getAllBreakpoints().isEmpty());
|
||||||
|
|
||||||
programManager.closeProgram(program, true);
|
programManager.closeProgram(program, true);
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
assertTrue(breakpointService.getAllBreakpoints().isEmpty());
|
assertTrue(breakpointService.getAllBreakpoints().isEmpty());
|
||||||
}
|
}
|
||||||
|
@ -741,13 +737,17 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
createProgramFromTrace(trace);
|
createProgramFromTrace(trace);
|
||||||
intoProject(program);
|
intoProject(program);
|
||||||
programManager.openProgram(program);
|
programManager.openProgram(program);
|
||||||
waitForSwing();
|
waitForDomainObject(program);
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
assertTrue(breakpointService.getAllBreakpoints().isEmpty());
|
assertTrue(breakpointService.getAllBreakpoints().isEmpty());
|
||||||
|
|
||||||
traceManager.closeTrace(trace);
|
traceManager.closeTrace(trace);
|
||||||
terminateTarget(target1);
|
terminateTarget(target1);
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
assertTrue(breakpointService.getAllBreakpoints().isEmpty());
|
assertTrue(breakpointService.getAllBreakpoints().isEmpty());
|
||||||
}
|
}
|
||||||
|
@ -766,13 +766,14 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
addProgramTextBlock(program);
|
addProgramTextBlock(program);
|
||||||
addProgramBreakpoints(program);
|
addProgramBreakpoints(program);
|
||||||
MR text = addTargetTextRegion(target1);
|
MR text = addTargetTextRegion(target1);
|
||||||
expectMappingChange(() -> addTextMapping(target1, text, program));
|
addTextMapping(target1, text, program);
|
||||||
waitForSwing();
|
waitOn(mappingService.changesSettled());
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
assertLogicalBreakpointsForMappedBookmarks(trace);
|
assertLogicalBreakpointsForMappedBookmarks(trace);
|
||||||
|
|
||||||
removeProgramBreakpoints(program);
|
removeProgramBreakpoints(program);
|
||||||
waitForSwing();
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
assertTrue(breakpointService.getAllBreakpoints().isEmpty());
|
assertTrue(breakpointService.getAllBreakpoints().isEmpty());
|
||||||
}
|
}
|
||||||
|
@ -791,13 +792,15 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
addProgramTextBlock(program);
|
addProgramTextBlock(program);
|
||||||
addProgramBreakpoints(program);
|
addProgramBreakpoints(program);
|
||||||
MR text = addTargetTextRegion(target1);
|
MR text = addTargetTextRegion(target1);
|
||||||
expectMappingChange(() -> addTextMapping(target1, text, program));
|
addTextMapping(target1, text, program);
|
||||||
waitForSwing();
|
waitOn(mappingService.changesSettled());
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
assertLogicalBreakpointsForMappedBookmarks(trace);
|
assertLogicalBreakpointsForMappedBookmarks(trace);
|
||||||
|
|
||||||
expectMappingChange(() -> removeTextMapping(target1, program));
|
removeTextMapping(target1, program);
|
||||||
waitForSwing();
|
waitOn(mappingService.changesSettled());
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
assertLogicalBreakpointsForUnmappedBookmarks();
|
assertLogicalBreakpointsForUnmappedBookmarks();
|
||||||
assertTrue(breakpointService.getBreakpoints(trace).isEmpty());
|
assertTrue(breakpointService.getBreakpoints(trace).isEmpty());
|
||||||
|
@ -818,19 +821,19 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
programManager.openProgram(program);
|
programManager.openProgram(program);
|
||||||
|
|
||||||
addProgramTextBlock(program);
|
addProgramTextBlock(program);
|
||||||
expectMappingChange(() -> addTextMapping(target1, text, program));
|
addTextMapping(target1, text, program);
|
||||||
waitForSwing();
|
waitOn(mappingService.changesSettled());
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
assertLogicalBreakpointForMappedSoftwareBreakpoint(trace);
|
assertLogicalBreakpointForMappedSoftwareBreakpoint(trace);
|
||||||
assertServiceAgreesWithOpenProgramsAndTraces();
|
assertServiceAgreesWithOpenProgramsAndTraces();
|
||||||
|
|
||||||
removeTargetSoftwareBreakpoint(target1);
|
removeTargetSoftwareBreakpoint(target1);
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
waitForPass(() -> {
|
|
||||||
// NB. The bookmark remains
|
// NB. The bookmark remains
|
||||||
LogicalBreakpoint one = Unique.assertOne(breakpointService.getAllBreakpoints());
|
LogicalBreakpoint one = Unique.assertOne(breakpointService.getAllBreakpoints());
|
||||||
assertTrue(one.getTraceBreakpoints().isEmpty());
|
assertTrue(one.getTraceBreakpoints().isEmpty());
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -848,14 +851,16 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
programManager.openProgram(program);
|
programManager.openProgram(program);
|
||||||
|
|
||||||
addProgramTextBlock(program);
|
addProgramTextBlock(program);
|
||||||
expectMappingChange(() -> addTextMapping(target1, text, program));
|
addTextMapping(target1, text, program);
|
||||||
waitForSwing();
|
waitOn(mappingService.changesSettled());
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
assertLogicalBreakpointForMappedSoftwareBreakpoint(trace);
|
assertLogicalBreakpointForMappedSoftwareBreakpoint(trace);
|
||||||
assertServiceAgreesWithOpenProgramsAndTraces();
|
assertServiceAgreesWithOpenProgramsAndTraces();
|
||||||
|
|
||||||
expectMappingChange(() -> removeTextMapping(target1, program));
|
removeTextMapping(target1, program);
|
||||||
waitForSwing();
|
waitOn(mappingService.changesSettled());
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
// NB. Bookmark remains
|
// NB. Bookmark remains
|
||||||
assertLogicalBreakpointForLoneSoftwareBreakpoint(trace, 2);
|
assertLogicalBreakpointForLoneSoftwareBreakpoint(trace, 2);
|
||||||
|
@ -881,23 +886,19 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
|
|
||||||
addTextMapping(target1, text1, program);
|
addTextMapping(target1, text1, program);
|
||||||
addTextMapping(target3, text3, program);
|
addTextMapping(target3, text3, program);
|
||||||
waitForSwing();
|
waitOn(mappingService.changesSettled());
|
||||||
waitForPass(() -> {
|
waitOn(breakpointService.changesSettled());
|
||||||
assertEquals(2,
|
|
||||||
mappingService
|
assertEquals(2, mappingService
|
||||||
.getOpenMappedLocations(
|
.getOpenMappedLocations(new ProgramLocation(program, addr(program, 0x00400123)))
|
||||||
new ProgramLocation(program, addr(program, 0x00400123)))
|
|
||||||
.size());
|
.size());
|
||||||
});
|
|
||||||
waitForSwing();
|
|
||||||
|
|
||||||
addProgramBreakpoints(program);
|
addProgramBreakpoints(program);
|
||||||
addTargetSoftwareBreakpoint(target1, text1);
|
addTargetSoftwareBreakpoint(target1, text1);
|
||||||
addTargetSoftwareBreakpoint(target3, text3);
|
addTargetSoftwareBreakpoint(target3, text3);
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
waitForPass(() -> {
|
|
||||||
assertLogicalBreakpointForMappedBookmarkAnd2TraceBreakpoints(trace1, trace3);
|
assertLogicalBreakpointForMappedBookmarkAnd2TraceBreakpoints(trace1, trace3);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -920,26 +921,24 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
|
|
||||||
addTextMapping(target1, text1, program);
|
addTextMapping(target1, text1, program);
|
||||||
addTextMapping(target3, text3, program);
|
addTextMapping(target3, text3, program);
|
||||||
waitForSwing();
|
waitOn(mappingService.changesSettled());
|
||||||
waitForPass(() -> {
|
waitOn(breakpointService.changesSettled());
|
||||||
assertEquals(2,
|
|
||||||
mappingService
|
assertEquals(2, mappingService
|
||||||
.getOpenMappedLocations(
|
.getOpenMappedLocations(new ProgramLocation(program, addr(program, 0x00400123)))
|
||||||
new ProgramLocation(program, addr(program, 0x00400123)))
|
|
||||||
.size());
|
.size());
|
||||||
});
|
|
||||||
waitForSwing();
|
|
||||||
|
|
||||||
addProgramBreakpoints(program);
|
addProgramBreakpoints(program);
|
||||||
addTargetSoftwareBreakpoint(target1, text1);
|
addTargetSoftwareBreakpoint(target1, text1);
|
||||||
addTargetSoftwareBreakpoint(target3, text3);
|
addTargetSoftwareBreakpoint(target3, text3);
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
waitForPass(() -> {
|
|
||||||
assertLogicalBreakpointForMappedBookmarkAnd2TraceBreakpoints(trace1, trace3);
|
assertLogicalBreakpointForMappedBookmarkAnd2TraceBreakpoints(trace1, trace3);
|
||||||
});
|
|
||||||
|
|
||||||
expectMappingChange(() -> programManager.closeProgram(program, true));
|
programManager.closeProgram(program, true);
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
assertLogicalBreakpointForLoneSoftwareBreakpoint(trace1, 0x55550123, 2);
|
assertLogicalBreakpointForLoneSoftwareBreakpoint(trace1, 0x55550123, 2);
|
||||||
assertLogicalBreakpointForLoneSoftwareBreakpoint(trace3, 0x55551123, 2);
|
assertLogicalBreakpointForLoneSoftwareBreakpoint(trace3, 0x55551123, 2);
|
||||||
|
@ -965,38 +964,34 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
|
|
||||||
addTextMapping(target1, text1, program);
|
addTextMapping(target1, text1, program);
|
||||||
addTextMapping(target3, text3, program);
|
addTextMapping(target3, text3, program);
|
||||||
waitForSwing();
|
waitOn(mappingService.changesSettled());
|
||||||
waitForPass(() -> {
|
waitOn(breakpointService.changesSettled());
|
||||||
assertEquals(2,
|
|
||||||
mappingService
|
assertEquals(2, mappingService
|
||||||
.getOpenMappedLocations(
|
.getOpenMappedLocations(new ProgramLocation(program, addr(program, 0x00400123)))
|
||||||
new ProgramLocation(program, addr(program, 0x00400123)))
|
|
||||||
.size());
|
.size());
|
||||||
});
|
|
||||||
waitForSwing();
|
|
||||||
|
|
||||||
addProgramBreakpoints(program);
|
addProgramBreakpoints(program);
|
||||||
addTargetSoftwareBreakpoint(target1, text1);
|
addTargetSoftwareBreakpoint(target1, text1);
|
||||||
addTargetSoftwareBreakpoint(target3, text3);
|
addTargetSoftwareBreakpoint(target3, text3);
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
waitForPass(() -> {
|
|
||||||
assertLogicalBreakpointForMappedBookmarkAnd2TraceBreakpoints(trace1, trace3);
|
assertLogicalBreakpointForMappedBookmarkAnd2TraceBreakpoints(trace1, trace3);
|
||||||
});
|
|
||||||
|
|
||||||
expectMappingChange(() -> programManager.closeProgram(program, true));
|
programManager.closeProgram(program, true);
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
waitForPass(() -> {
|
|
||||||
assertLogicalBreakpointForLoneSoftwareBreakpoint(trace1, 0x55550123, 2);
|
assertLogicalBreakpointForLoneSoftwareBreakpoint(trace1, 0x55550123, 2);
|
||||||
assertLogicalBreakpointForLoneSoftwareBreakpoint(trace3, 0x55551123, 2);
|
assertLogicalBreakpointForLoneSoftwareBreakpoint(trace3, 0x55551123, 2);
|
||||||
});
|
|
||||||
|
|
||||||
expectMappingChange(() -> programManager.openProgram(program));
|
programManager.openProgram(program);
|
||||||
waitForSwing();
|
waitForDomainObject(program);
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
waitForPass(() -> {
|
|
||||||
assertLogicalBreakpointForMappedBookmarkAnd2TraceBreakpoints(trace1, trace3);
|
assertLogicalBreakpointForMappedBookmarkAnd2TraceBreakpoints(trace1, trace3);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -1019,36 +1014,34 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
|
|
||||||
addTextMapping(target1, text1, program);
|
addTextMapping(target1, text1, program);
|
||||||
addTextMapping(target3, text3, program);
|
addTextMapping(target3, text3, program);
|
||||||
waitForSwing();
|
waitOn(mappingService.changesSettled());
|
||||||
waitForPass(() -> {
|
waitOn(breakpointService.changesSettled());
|
||||||
assertEquals(2,
|
|
||||||
mappingService
|
assertEquals(2, mappingService
|
||||||
.getOpenMappedLocations(
|
.getOpenMappedLocations(new ProgramLocation(program, addr(program, 0x00400123)))
|
||||||
new ProgramLocation(program, addr(program, 0x00400123)))
|
|
||||||
.size());
|
.size());
|
||||||
});
|
|
||||||
waitForSwing();
|
|
||||||
|
|
||||||
addProgramBreakpoints(program);
|
addProgramBreakpoints(program);
|
||||||
addTargetSoftwareBreakpoint(target1, text1);
|
addTargetSoftwareBreakpoint(target1, text1);
|
||||||
addTargetSoftwareBreakpoint(target3, text3);
|
addTargetSoftwareBreakpoint(target3, text3);
|
||||||
waitForSwing();
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
waitForPass(() -> {
|
|
||||||
assertLogicalBreakpointForMappedBookmarkAnd2TraceBreakpoints(trace1, trace3);
|
assertLogicalBreakpointForMappedBookmarkAnd2TraceBreakpoints(trace1, trace3);
|
||||||
});
|
|
||||||
|
|
||||||
waitForLock(getTrace(target3));
|
waitForLock(getTrace(target3));
|
||||||
expectMappingChange(() -> {
|
/**
|
||||||
// If I don't close the trace here, the test will fail.
|
* NB. Relying on terminate to auto-close is causing some timing issue I don't yet
|
||||||
|
* understand. So, I close it in the test code.
|
||||||
|
*/
|
||||||
terminateTarget(target3);
|
terminateTarget(target3);
|
||||||
// NB. Auto-close on stop is the default
|
traceManager.closeTrace(trace3);
|
||||||
//traceManager.closeTrace(trace3);
|
waitForPass(() -> !traceManager.getOpenTraces().contains(trace3));
|
||||||
});
|
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
// NB. Auto-close is possibly delayed because of auto-save
|
// NB. Auto-close is possibly delayed because of auto-save
|
||||||
waitForPass(() -> assertLogicalBreakpointForMappedBookmarkAnd1TraceBreakpoint(trace1));
|
assertLogicalBreakpointForMappedBookmarkAnd1TraceBreakpoint(trace1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // Mappings are not write-behind cached
|
@Test // Mappings are not write-behind cached
|
||||||
|
@ -1064,10 +1057,10 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
addProgramTextBlock(program);
|
addProgramTextBlock(program);
|
||||||
MR text = addTargetTextRegion(target1);
|
MR text = addTargetTextRegion(target1);
|
||||||
addTargetSoftwareBreakpoint(target1, text);
|
addTargetSoftwareBreakpoint(target1, text);
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
waitForPass(() -> {
|
|
||||||
assertLogicalBreakpointForLoneSoftwareBreakpoint(trace, 1);
|
assertLogicalBreakpointForLoneSoftwareBreakpoint(trace, 1);
|
||||||
});
|
|
||||||
/**
|
/**
|
||||||
* NB. The target could still be mid transaction. If we open this transaction too soon, then
|
* NB. The target could still be mid transaction. If we open this transaction too soon, then
|
||||||
* the breakpoint gets aborted as well.
|
* the breakpoint gets aborted as well.
|
||||||
|
@ -1077,19 +1070,21 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
changeListener.assertAgreesWithService();
|
changeListener.assertAgreesWithService();
|
||||||
|
|
||||||
try (Transaction tx = trace.openTransaction("Will abort")) {
|
try (Transaction tx = trace.openTransaction("Will abort")) {
|
||||||
expectMappingChange(() -> addTextMapping(target1, text, program));
|
addTextMapping(target1, text, program);
|
||||||
waitForSwing();
|
waitOn(mappingService.changesSettled());
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
// Sanity
|
// Sanity
|
||||||
assertLogicalBreakpointForMappedSoftwareBreakpoint(trace);
|
assertLogicalBreakpointForMappedSoftwareBreakpoint(trace);
|
||||||
|
|
||||||
expectMappingChange(() -> tx.abort());
|
tx.abort();
|
||||||
}
|
}
|
||||||
|
waitForDomainObject(trace);
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
waitForPass(() -> {
|
|
||||||
// NB. The bookmark is left over, so total increases
|
// NB. The bookmark is left over, so total increases
|
||||||
assertLogicalBreakpointForLoneSoftwareBreakpoint(trace, 2);
|
assertLogicalBreakpointForLoneSoftwareBreakpoint(trace, 2);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Test // Not gonna with write-behind cache
|
// @Test // Not gonna with write-behind cache
|
||||||
|
@ -1108,15 +1103,18 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
try (Transaction tx = trace.openTransaction("Will abort")) {
|
try (Transaction tx = trace.openTransaction("Will abort")) {
|
||||||
addTargetSoftwareBreakpoint(target1, text);
|
addTargetSoftwareBreakpoint(target1, text);
|
||||||
|
|
||||||
expectMappingChange(() -> addTextMapping(target1, text, program));
|
addTextMapping(target1, text, program);
|
||||||
waitForSwing();
|
waitOn(mappingService.changesSettled());
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
// Sanity
|
// Sanity
|
||||||
assertLogicalBreakpointForMappedSoftwareBreakpoint(trace);
|
assertLogicalBreakpointForMappedSoftwareBreakpoint(trace);
|
||||||
|
|
||||||
expectMappingChange(() -> tx.abort());
|
tx.abort();
|
||||||
}
|
}
|
||||||
waitForDomainObject(trace); // Duplicative, but for form's sake....
|
waitForDomainObject(trace);
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
// Left over, because it was bookmarked automatically in program
|
// Left over, because it was bookmarked automatically in program
|
||||||
// Still, there should be no trace breakpoint in it
|
// Still, there should be no trace breakpoint in it
|
||||||
|
@ -1136,18 +1134,19 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
|
|
||||||
addProgramTextBlock(program);
|
addProgramTextBlock(program);
|
||||||
MR text = addTargetTextRegion(target1);
|
MR text = addTargetTextRegion(target1);
|
||||||
expectMappingChange(() -> addTextMapping(target1, text, program));
|
addTextMapping(target1, text, program);
|
||||||
waitForSwing();
|
waitOn(mappingService.changesSettled());
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
try (Transaction tx = program.openTransaction("Will abort")) {
|
try (Transaction tx = program.openTransaction("Will abort")) {
|
||||||
addProgramBreakpoints(program);
|
addProgramBreakpoints(program);
|
||||||
waitForDomainObject(program);
|
|
||||||
|
|
||||||
// Sanity
|
// Sanity
|
||||||
assertLogicalBreakpointsForMappedBookmarks(trace);
|
assertLogicalBreakpointsForMappedBookmarks(trace);
|
||||||
tx.abort();
|
tx.abort();
|
||||||
}
|
}
|
||||||
waitForDomainObject(program);
|
waitForDomainObject(program);
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
assertTrue(breakpointService.getAllBreakpoints().isEmpty());
|
assertTrue(breakpointService.getAllBreakpoints().isEmpty());
|
||||||
}
|
}
|
||||||
|
@ -1167,18 +1166,16 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
|
|
||||||
try (Transaction tx = trace.openTransaction("Will undo")) {
|
try (Transaction tx = trace.openTransaction("Will undo")) {
|
||||||
addTargetSoftwareBreakpoint(target1, text);
|
addTargetSoftwareBreakpoint(target1, text);
|
||||||
expectMappingChange(() -> addTextMapping(target1, text, program));
|
addTextMapping(target1, text, program);
|
||||||
}
|
}
|
||||||
waitForDomainObject(trace);
|
waitForDomainObject(program);
|
||||||
|
|
||||||
waitOn(mappingService.changesSettled());
|
waitOn(mappingService.changesSettled());
|
||||||
waitOn(breakpointService.changesSettled());
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
// Sanity
|
// Sanity
|
||||||
assertLogicalBreakpointForMappedSoftwareBreakpoint(trace);
|
assertLogicalBreakpointForMappedSoftwareBreakpoint(trace);
|
||||||
|
|
||||||
expectMappingChange(() -> undo(trace));
|
undo(trace);
|
||||||
|
|
||||||
waitOn(mappingService.changesSettled());
|
waitOn(mappingService.changesSettled());
|
||||||
waitOn(breakpointService.changesSettled());
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
|
@ -1186,10 +1183,12 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
LogicalBreakpoint one = Unique.assertOne(breakpointService.getAllBreakpoints());
|
LogicalBreakpoint one = Unique.assertOne(breakpointService.getAllBreakpoints());
|
||||||
assertTrue(one.getTraceBreakpoints().isEmpty());
|
assertTrue(one.getTraceBreakpoints().isEmpty());
|
||||||
|
|
||||||
expectMappingChange(() -> redo(trace));
|
redo(trace);
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
// Mapping, breakpoint may be processed in whatever order
|
// Mapping, breakpoint may be processed in whatever order
|
||||||
waitForPass(() -> assertLogicalBreakpointForMappedSoftwareBreakpoint(trace));
|
assertLogicalBreakpointForMappedSoftwareBreakpoint(trace);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -1204,22 +1203,27 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
|
|
||||||
addProgramTextBlock(program);
|
addProgramTextBlock(program);
|
||||||
MR text = addTargetTextRegion(target1);
|
MR text = addTargetTextRegion(target1);
|
||||||
expectMappingChange(() -> addTextMapping(target1, text, program));
|
addTextMapping(target1, text, program);
|
||||||
waitForSwing();
|
waitOn(mappingService.changesSettled());
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
try (Transaction tx = program.openTransaction("Will undo")) {
|
try (Transaction tx = program.openTransaction("Will undo")) {
|
||||||
addProgramBreakpoints(program);
|
addProgramBreakpoints(program);
|
||||||
}
|
}
|
||||||
waitForDomainObject(program);
|
waitForDomainObject(program);
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
// Sanity
|
// Sanity
|
||||||
assertLogicalBreakpointsForMappedBookmarks(trace);
|
assertLogicalBreakpointsForMappedBookmarks(trace);
|
||||||
|
|
||||||
undo(program);
|
undo(program);
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
assertTrue(breakpointService.getAllBreakpoints().isEmpty());
|
assertTrue(breakpointService.getAllBreakpoints().isEmpty());
|
||||||
|
|
||||||
redo(program);
|
redo(program);
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
refetchProgramBreakpoints(program);
|
refetchProgramBreakpoints(program);
|
||||||
assertLogicalBreakpointsForMappedBookmarks(trace);
|
assertLogicalBreakpointsForMappedBookmarks(trace);
|
||||||
|
@ -1234,18 +1238,20 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
MR text = addTargetTextRegion(target1);
|
MR text = addTargetTextRegion(target1);
|
||||||
|
|
||||||
addTargetSoftwareBreakpoint(target1, text);
|
addTargetSoftwareBreakpoint(target1, text);
|
||||||
waitForPass(() -> {
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
assertLogicalBreakpointForLoneSoftwareBreakpoint(trace, 1);
|
assertLogicalBreakpointForLoneSoftwareBreakpoint(trace, 1);
|
||||||
});
|
|
||||||
|
|
||||||
LogicalBreakpoint lb = Unique.assertOne(breakpointService.getAllBreakpoints());
|
LogicalBreakpoint lb = Unique.assertOne(breakpointService.getAllBreakpoints());
|
||||||
|
|
||||||
CompletableFuture<Void> disable = lb.disable();
|
CompletableFuture<Void> disable = lb.disable();
|
||||||
handleToggleBreakpointInvocation(Unique.assertOne(lb.getTraceBreakpoints(trace)), false);
|
handleToggleBreakpointInvocation(target1, Unique.assertOne(lb.getTraceBreakpoints(trace)),
|
||||||
|
false);
|
||||||
waitOn(disable);
|
waitOn(disable);
|
||||||
waitForPass(() -> {
|
waitForDomainObject(trace);
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
assertEquals(State.INCONSISTENT_DISABLED, lb.computeState());
|
assertEquals(State.INCONSISTENT_DISABLED, lb.computeState());
|
||||||
});
|
|
||||||
|
|
||||||
// Simulate a step, which should also cause snap advance in target
|
// Simulate a step, which should also cause snap advance in target
|
||||||
long oldSnap = getSnap(target1);
|
long oldSnap = getSnap(target1);
|
||||||
|
@ -1256,11 +1262,13 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
});
|
});
|
||||||
|
|
||||||
CompletableFuture<Void> enable = lb.enable();
|
CompletableFuture<Void> enable = lb.enable();
|
||||||
handleToggleBreakpointInvocation(Unique.assertOne(lb.getTraceBreakpoints(trace)), true);
|
handleToggleBreakpointInvocation(target1, Unique.assertOne(lb.getTraceBreakpoints(trace)),
|
||||||
|
true);
|
||||||
waitOn(enable);
|
waitOn(enable);
|
||||||
waitForPass(() -> {
|
waitForDomainObject(trace);
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
assertEquals(State.INCONSISTENT_ENABLED, lb.computeState());
|
assertEquals(State.INCONSISTENT_ENABLED, lb.computeState());
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -1270,22 +1278,20 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
traceManager.openTrace(trace);
|
traceManager.openTrace(trace);
|
||||||
|
|
||||||
MR text = addTargetTextRegion(target1);
|
MR text = addTargetTextRegion(target1);
|
||||||
|
|
||||||
addTargetSoftwareBreakpoint(target1, text);
|
addTargetSoftwareBreakpoint(target1, text);
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
waitForPass(() -> {
|
|
||||||
assertLogicalBreakpointForLoneSoftwareBreakpoint(trace, 1);
|
assertLogicalBreakpointForLoneSoftwareBreakpoint(trace, 1);
|
||||||
});
|
|
||||||
|
|
||||||
LogicalBreakpoint lb = Unique.assertOne(breakpointService.getAllBreakpoints());
|
LogicalBreakpoint lb = Unique.assertOne(breakpointService.getAllBreakpoints());
|
||||||
|
|
||||||
CompletableFuture<Void> delete = lb.delete();
|
CompletableFuture<Void> delete = lb.delete();
|
||||||
handleDeleteBreakpointInvocation(Unique.assertOne(lb.getTraceBreakpoints(trace)));
|
handleDeleteBreakpointInvocation(target1, Unique.assertOne(lb.getTraceBreakpoints(trace)));
|
||||||
waitOn(delete);
|
waitOn(delete);
|
||||||
|
waitForDomainObject(trace);
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
waitForPass(() -> {
|
|
||||||
assertTrue(breakpointService.getAllBreakpoints().isEmpty());
|
assertTrue(breakpointService.getAllBreakpoints().isEmpty());
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -1295,11 +1301,10 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
traceManager.openTrace(trace);
|
traceManager.openTrace(trace);
|
||||||
|
|
||||||
MR text = addTargetTextRegion(target1);
|
MR text = addTargetTextRegion(target1);
|
||||||
|
|
||||||
addTargetSoftwareBreakpoint(target1, text);
|
addTargetSoftwareBreakpoint(target1, text);
|
||||||
waitForDomainObject(trace);
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
waitForPass(() -> assertLogicalBreakpointForLoneSoftwareBreakpoint(trace, 1));
|
assertLogicalBreakpointForLoneSoftwareBreakpoint(trace, 1);
|
||||||
|
|
||||||
LogicalBreakpoint lb = Unique.assertOne(breakpointService.getAllBreakpoints());
|
LogicalBreakpoint lb = Unique.assertOne(breakpointService.getAllBreakpoints());
|
||||||
|
|
||||||
|
@ -1307,12 +1312,12 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
simulateTargetStep(target1);
|
simulateTargetStep(target1);
|
||||||
|
|
||||||
CompletableFuture<Void> delete = lb.delete();
|
CompletableFuture<Void> delete = lb.delete();
|
||||||
handleDeleteBreakpointInvocation(Unique.assertOne(lb.getTraceBreakpoints(trace)));
|
handleDeleteBreakpointInvocation(target1, Unique.assertOne(lb.getTraceBreakpoints(trace)));
|
||||||
waitOn(delete);
|
waitOn(delete);
|
||||||
|
waitForDomainObject(trace);
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
waitForPass(() -> {
|
|
||||||
assertEquals(0, breakpointService.getAllBreakpoints().size());
|
assertEquals(0, breakpointService.getAllBreakpoints().size());
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -1324,14 +1329,14 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
MR text = addTargetTextRegion(target1);
|
MR text = addTargetTextRegion(target1);
|
||||||
|
|
||||||
addTargetSoftwareBreakpoint(target1, text);
|
addTargetSoftwareBreakpoint(target1, text);
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
waitForPass(() -> {
|
|
||||||
assertLogicalBreakpointForLoneSoftwareBreakpoint(trace, 1);
|
assertLogicalBreakpointForLoneSoftwareBreakpoint(trace, 1);
|
||||||
});
|
|
||||||
|
|
||||||
// NOTE: Still recording in the background
|
// NOTE: Still recording in the background
|
||||||
traceManager.closeTraceNoConfirm(trace);
|
traceManager.closeTraceNoConfirm(trace);
|
||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
assertEquals(0, breakpointService.getAllBreakpoints().size());
|
assertEquals(0, breakpointService.getAllBreakpoints().size());
|
||||||
}
|
}
|
||||||
|
@ -1350,13 +1355,13 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
MR text = addTargetTextRegion(target1);
|
MR text = addTargetTextRegion(target1);
|
||||||
|
|
||||||
addTextMapping(target1, text, program);
|
addTextMapping(target1, text, program);
|
||||||
waitForSwing();
|
|
||||||
|
|
||||||
addProgramBreakpoints(program);
|
addProgramBreakpoints(program);
|
||||||
addTargetSoftwareBreakpoint(target1, text);
|
addTargetSoftwareBreakpoint(target1, text);
|
||||||
addTargetSoftwareBreakpoint(target1, text);
|
addTargetSoftwareBreakpoint(target1, text);
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
waitForPass(() -> {
|
|
||||||
assertEquals(2, breakpointService.getAllBreakpoints().size());
|
assertEquals(2, breakpointService.getAllBreakpoints().size());
|
||||||
|
|
||||||
LogicalBreakpoint lb = Unique.assertOne(
|
LogicalBreakpoint lb = Unique.assertOne(
|
||||||
|
@ -1365,24 +1370,21 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
assertEquals(Set.of(trace), lb.getMappedTraces());
|
assertEquals(Set.of(trace), lb.getMappedTraces());
|
||||||
|
|
||||||
assertEquals(2, lb.getTraceBreakpoints().size());
|
assertEquals(2, lb.getTraceBreakpoints().size());
|
||||||
});
|
|
||||||
|
|
||||||
LogicalBreakpoint lb = Unique
|
|
||||||
.assertOne(breakpointService.getBreakpointsAt(program, addr(program, 0x00400123)));
|
|
||||||
Set<TraceBreakpoint> locs = lb.getTraceBreakpoints();
|
Set<TraceBreakpoint> locs = lb.getTraceBreakpoints();
|
||||||
|
|
||||||
TraceBreakpoint bpt0 = findLoc(locs, 0);
|
TraceBreakpoint bpt0 = findLoc(locs, 0);
|
||||||
TraceBreakpoint bpt1 = findLoc(locs, 1);
|
TraceBreakpoint bpt1 = findLoc(locs, 1);
|
||||||
CompletableFuture<Void> disable = breakpointService.disableLocs(Set.of(bpt0));
|
CompletableFuture<Void> disable = breakpointService.disableLocs(Set.of(bpt0));
|
||||||
handleToggleBreakpointInvocation(bpt0, false);
|
handleToggleBreakpointInvocation(target1, bpt0, false);
|
||||||
waitOn(disable);
|
waitOn(disable);
|
||||||
|
waitForDomainObject(trace);
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
waitForPass(() -> {
|
|
||||||
assertEquals(State.INCONSISTENT_ENABLED, lb.computeState());
|
assertEquals(State.INCONSISTENT_ENABLED, lb.computeState());
|
||||||
assertEquals(State.INCONSISTENT_MIXED, lb.computeStateForTrace(trace));
|
assertEquals(State.INCONSISTENT_MIXED, lb.computeStateForTrace(trace));
|
||||||
assertEquals(State.INCONSISTENT_DISABLED, lb.computeStateForLocation(bpt0));
|
assertEquals(State.INCONSISTENT_DISABLED, lb.computeStateForLocation(bpt0));
|
||||||
assertEquals(State.ENABLED, lb.computeStateForLocation(bpt1));
|
assertEquals(State.ENABLED, lb.computeStateForLocation(bpt1));
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -1399,13 +1401,13 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
MR text = addTargetTextRegion(target1);
|
MR text = addTargetTextRegion(target1);
|
||||||
|
|
||||||
addTextMapping(target1, text, program);
|
addTextMapping(target1, text, program);
|
||||||
waitForSwing();
|
|
||||||
|
|
||||||
addProgramBreakpoints(program);
|
addProgramBreakpoints(program);
|
||||||
addTargetSoftwareBreakpoint(target1, text);
|
addTargetSoftwareBreakpoint(target1, text);
|
||||||
addTargetAccessBreakpoint(target1, text);
|
addTargetAccessBreakpoint(target1, text);
|
||||||
|
waitOn(mappingService.changesSettled());
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
waitForPass(() -> {
|
|
||||||
assertEquals(3, breakpointService.getAllBreakpoints().size());
|
assertEquals(3, breakpointService.getAllBreakpoints().size());
|
||||||
|
|
||||||
Set<LogicalBreakpoint> lbs =
|
Set<LogicalBreakpoint> lbs =
|
||||||
|
@ -1419,9 +1421,6 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
.filter(l -> l.getKinds().contains(TraceBreakpointKind.READ))
|
.filter(l -> l.getKinds().contains(TraceBreakpointKind.READ))
|
||||||
.findAny()
|
.findAny()
|
||||||
.orElseThrow();
|
.orElseThrow();
|
||||||
});
|
|
||||||
Set<LogicalBreakpoint> lbs =
|
|
||||||
breakpointService.getBreakpointsAt(program, addr(program, 0x00400123));
|
|
||||||
LogicalBreakpoint lbEx = lbs.stream()
|
LogicalBreakpoint lbEx = lbs.stream()
|
||||||
.filter(l -> l.getKinds().contains(TraceBreakpointKind.SW_EXECUTE))
|
.filter(l -> l.getKinds().contains(TraceBreakpointKind.SW_EXECUTE))
|
||||||
.findAny()
|
.findAny()
|
||||||
|
@ -1431,12 +1430,14 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
.findAny()
|
.findAny()
|
||||||
.orElseThrow();
|
.orElseThrow();
|
||||||
CompletableFuture<Void> disable = lbEx.disable();
|
CompletableFuture<Void> disable = lbEx.disable();
|
||||||
handleToggleBreakpointInvocation(Unique.assertOne(lbEx.getTraceBreakpoints(trace)), false);
|
handleToggleBreakpointInvocation(target1, Unique.assertOne(lbEx.getTraceBreakpoints(trace)),
|
||||||
|
false);
|
||||||
waitOn(disable);
|
waitOn(disable);
|
||||||
|
waitForDomainObject(trace);
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
// TODO: This is more a test for the marker plugin, no?
|
// TODO: This is more a test for the marker plugin, no?
|
||||||
waitForPass(
|
assertEquals(State.MIXED, lbEx.computeState().sameAdddress(lbRw.computeState()));
|
||||||
() -> assertEquals(State.MIXED, lbEx.computeState().sameAdddress(lbRw.computeState())));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void addTextMappingDead(Program p, ToyDBTraceBuilder tb) throws Throwable {
|
protected void addTextMappingDead(Program p, ToyDBTraceBuilder tb) throws Throwable {
|
||||||
|
@ -1451,6 +1452,7 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
textRegion.getMinAddress()),
|
textRegion.getMinAddress()),
|
||||||
new ProgramLocation(p, addr(p, 0x00400000)), 0x1000, false);
|
new ProgramLocation(p, addr(p, 0x00400000)), 0x1000, false);
|
||||||
}
|
}
|
||||||
|
waitForDomainObject(tb.trace);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void addEnabledProgramBreakpointWithSleigh(Program p) {
|
protected void addEnabledProgramBreakpointWithSleigh(Program p) {
|
||||||
|
@ -1459,6 +1461,7 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
.setBookmark(addr(p, 0x00400123), LogicalBreakpoint.ENABLED_BOOKMARK_TYPE,
|
.setBookmark(addr(p, 0x00400123), LogicalBreakpoint.ENABLED_BOOKMARK_TYPE,
|
||||||
"SW_EXECUTE;1", "{sleigh: 'r0=0xbeef;'}");
|
"SW_EXECUTE;1", "{sleigh: 'r0=0xbeef;'}");
|
||||||
}
|
}
|
||||||
|
waitForDomainObject(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -1471,16 +1474,18 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
programManager.openProgram(program);
|
programManager.openProgram(program);
|
||||||
|
|
||||||
addTextMappingDead(program, tb);
|
addTextMappingDead(program, tb);
|
||||||
waitForSwing();
|
|
||||||
|
|
||||||
addEnabledProgramBreakpointWithSleigh(program);
|
addEnabledProgramBreakpointWithSleigh(program);
|
||||||
LogicalBreakpoint lb = waitForValue(() -> Unique.assertAtMostOne(
|
waitOn(mappingService.changesSettled());
|
||||||
breakpointService.getBreakpointsAt(program, addr(program, 0x00400123))));
|
waitOn(breakpointService.changesSettled());
|
||||||
|
LogicalBreakpoint lb = Unique.assertAtMostOne(
|
||||||
|
breakpointService.getBreakpointsAt(program, addr(program, 0x00400123)));
|
||||||
|
|
||||||
assertEquals("r0=0xbeef;", lb.getEmuSleigh());
|
assertEquals("r0=0xbeef;", lb.getEmuSleigh());
|
||||||
|
|
||||||
waitOn(lb.enable());
|
waitOn(lb.enable());
|
||||||
waitForSwing();
|
waitForDomainObject(program);
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
TraceBreakpoint bpt = Unique.assertOne(
|
TraceBreakpoint bpt = Unique.assertOne(
|
||||||
tb.trace.getBreakpointManager().getBreakpointsAt(0, tb.addr(0x55550123)));
|
tb.trace.getBreakpointManager().getBreakpointsAt(0, tb.addr(0x55550123)));
|
||||||
|
@ -1497,21 +1502,22 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
programManager.openProgram(program);
|
programManager.openProgram(program);
|
||||||
|
|
||||||
addEnabledProgramBreakpointWithSleigh(program);
|
addEnabledProgramBreakpointWithSleigh(program);
|
||||||
LogicalBreakpoint lb = waitForValue(() -> Unique.assertAtMostOne(
|
waitOn(breakpointService.changesSettled());
|
||||||
breakpointService.getBreakpointsAt(program, addr(program, 0x00400123))));
|
LogicalBreakpoint lb = Unique.assertAtMostOne(
|
||||||
|
breakpointService.getBreakpointsAt(program, addr(program, 0x00400123)));
|
||||||
|
|
||||||
assertEquals("r0=0xbeef;", lb.getEmuSleigh());
|
assertEquals("r0=0xbeef;", lb.getEmuSleigh());
|
||||||
|
|
||||||
addTextMappingDead(program, tb);
|
addTextMappingDead(program, tb);
|
||||||
lb = waitForPass(() -> {
|
waitOn(mappingService.changesSettled());
|
||||||
LogicalBreakpoint newLb = Unique.assertOne(
|
waitOn(breakpointService.changesSettled());
|
||||||
|
lb = Unique.assertOne(
|
||||||
breakpointService.getBreakpointsAt(program, addr(program, 0x00400123)));
|
breakpointService.getBreakpointsAt(program, addr(program, 0x00400123)));
|
||||||
assertTrue(newLb.getMappedTraces().contains(tb.trace));
|
assertTrue(lb.getMappedTraces().contains(tb.trace));
|
||||||
return newLb;
|
|
||||||
});
|
|
||||||
|
|
||||||
waitOn(lb.enable());
|
waitOn(lb.enable());
|
||||||
waitForSwing();
|
waitForDomainObject(program);
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
TraceBreakpoint bpt = Unique.assertOne(
|
TraceBreakpoint bpt = Unique.assertOne(
|
||||||
tb.trace.getBreakpointManager().getBreakpointsAt(0, tb.addr(0x55550123)));
|
tb.trace.getBreakpointManager().getBreakpointsAt(0, tb.addr(0x55550123)));
|
||||||
|
@ -1541,21 +1547,25 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
false /* emuEnabled defaults to true */, "");
|
false /* emuEnabled defaults to true */, "");
|
||||||
bpt.setEmuSleigh("r0=0xbeef;");
|
bpt.setEmuSleigh("r0=0xbeef;");
|
||||||
}
|
}
|
||||||
LogicalBreakpoint lb = waitForValue(() -> Unique.assertAtMostOne(
|
waitForDomainObject(tb.trace);
|
||||||
breakpointService.getBreakpointsAt(tb.trace, tb.addr(0x55550123))));
|
waitOn(mappingService.changesSettled());
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
LogicalBreakpoint lb = Unique.assertAtMostOne(
|
||||||
|
breakpointService.getBreakpointsAt(tb.trace, tb.addr(0x55550123)));
|
||||||
|
|
||||||
assertEquals("r0=0xbeef;", lb.getEmuSleigh());
|
assertEquals("r0=0xbeef;", lb.getEmuSleigh());
|
||||||
|
|
||||||
addTextMappingDead(program, tb);
|
addTextMappingDead(program, tb);
|
||||||
lb = waitForPass(() -> {
|
waitOn(mappingService.changesSettled());
|
||||||
LogicalBreakpoint newLb = Unique.assertOne(
|
waitOn(breakpointService.changesSettled());
|
||||||
breakpointService.getBreakpointsAt(program, addr(program, 0x00400123)));
|
|
||||||
assertTrue(newLb.getMappedTraces().contains(tb.trace));
|
lb = Unique
|
||||||
return newLb;
|
.assertOne(breakpointService.getBreakpointsAt(program, addr(program, 0x00400123)));
|
||||||
});
|
assertTrue(lb.getMappedTraces().contains(tb.trace));
|
||||||
|
|
||||||
lb.enableForProgram();
|
lb.enableForProgram();
|
||||||
waitForSwing();
|
waitForDomainObject(tb.trace);
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
assertEquals("{\"sleigh\":\"r0\\u003d0xbeef;\"}", lb.getProgramBookmark().getComment());
|
assertEquals("{\"sleigh\":\"r0\\u003d0xbeef;\"}", lb.getProgramBookmark().getComment());
|
||||||
}
|
}
|
||||||
|
@ -1566,6 +1576,8 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* With the addition of the write-behind cache, this test is no longer sane.
|
* With the addition of the write-behind cache, this test is no longer sane.
|
||||||
|
*
|
||||||
|
* @throws Throwable who doesn't?
|
||||||
*/
|
*/
|
||||||
// @Test
|
// @Test
|
||||||
public void testAbortAddBreakpointSetSleigh() throws Throwable {
|
public void testAbortAddBreakpointSetSleigh() throws Throwable {
|
||||||
|
@ -1595,6 +1607,7 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest<T, MR>
|
||||||
tid.abort();
|
tid.abort();
|
||||||
}
|
}
|
||||||
waitForDomainObject(tb.trace);
|
waitForDomainObject(tb.trace);
|
||||||
|
waitOn(breakpointService.changesSettled());
|
||||||
|
|
||||||
assertTrue(breakpointService.getAllBreakpoints().isEmpty());
|
assertTrue(breakpointService.getAllBreakpoints().isEmpty());
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,8 @@ package ghidra.app.plugin.core.debug.service.breakpoint;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.junit.Ignore;
|
||||||
|
|
||||||
import db.Transaction;
|
import db.Transaction;
|
||||||
import ghidra.dbg.target.schema.SchemaContext;
|
import ghidra.dbg.target.schema.SchemaContext;
|
||||||
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
|
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
|
||||||
|
@ -24,6 +26,7 @@ import ghidra.dbg.target.schema.XmlSchemaContext;
|
||||||
import ghidra.trace.model.Trace;
|
import ghidra.trace.model.Trace;
|
||||||
import ghidra.trace.model.target.TraceObjectKeyPath;
|
import ghidra.trace.model.target.TraceObjectKeyPath;
|
||||||
|
|
||||||
|
@Ignore("Deprecated")
|
||||||
public class DebuggerObjectRecorderLogicalBreakpointServiceTest
|
public class DebuggerObjectRecorderLogicalBreakpointServiceTest
|
||||||
extends DebuggerRecorderLogicalBreakpointServiceTest {
|
extends DebuggerRecorderLogicalBreakpointServiceTest {
|
||||||
|
|
||||||
|
|
|
@ -19,9 +19,9 @@ import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
import org.junit.Ignore;
|
||||||
|
|
||||||
import db.Transaction;
|
import db.Transaction;
|
||||||
import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingUtils;
|
import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingUtils;
|
||||||
|
@ -39,6 +39,7 @@ import ghidra.trace.model.breakpoint.TraceBreakpoint;
|
||||||
import ghidra.trace.model.memory.TraceMemoryRegion;
|
import ghidra.trace.model.memory.TraceMemoryRegion;
|
||||||
import ghidra.trace.model.modules.TraceStaticMapping;
|
import ghidra.trace.model.modules.TraceStaticMapping;
|
||||||
|
|
||||||
|
@Ignore("Deprecated")
|
||||||
public class DebuggerRecorderLogicalBreakpointServiceTest extends
|
public class DebuggerRecorderLogicalBreakpointServiceTest extends
|
||||||
AbstractDebuggerLogicalBreakpointServiceTest<TraceRecorder, TestTargetMemoryRegion> {
|
AbstractDebuggerLogicalBreakpointServiceTest<TraceRecorder, TestTargetMemoryRegion> {
|
||||||
|
|
||||||
|
@ -130,6 +131,7 @@ public class DebuggerRecorderLogicalBreakpointServiceTest extends
|
||||||
new ProgramLocation(p, addr(p, 0x00400000)), 0x1000,
|
new ProgramLocation(p, addr(p, 0x00400000)), 0x1000,
|
||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
|
waitForDomainObject(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -140,6 +142,7 @@ public class DebuggerRecorderLogicalBreakpointServiceTest extends
|
||||||
t.getStaticMappingManager().findContaining(addr(t, 0x55550000), r.getSnap());
|
t.getStaticMappingManager().findContaining(addr(t, 0x55550000), r.getSnap());
|
||||||
mapping.delete();
|
mapping.delete();
|
||||||
}
|
}
|
||||||
|
waitForDomainObject(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -168,7 +171,7 @@ public class DebuggerRecorderLogicalBreakpointServiceTest extends
|
||||||
@Override
|
@Override
|
||||||
protected void removeTargetSoftwareBreakpoint(TraceRecorder r) throws Throwable {
|
protected void removeTargetSoftwareBreakpoint(TraceRecorder r) throws Throwable {
|
||||||
TargetBreakpointSpecContainer cont = getBreakpointContainer(r);
|
TargetBreakpointSpecContainer cont = getBreakpointContainer(r);
|
||||||
cont.fetchElements().thenAccept(elements -> {
|
waitOn(cont.fetchElements().thenCompose(elements -> {
|
||||||
for (TargetObject obj : elements.values()) {
|
for (TargetObject obj : elements.values()) {
|
||||||
if (!(obj instanceof TargetBreakpointSpec) ||
|
if (!(obj instanceof TargetBreakpointSpec) ||
|
||||||
!(obj instanceof TargetDeletable)) {
|
!(obj instanceof TargetDeletable)) {
|
||||||
|
@ -179,11 +182,12 @@ public class DebuggerRecorderLogicalBreakpointServiceTest extends
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
TargetDeletable del = (TargetDeletable) obj;
|
TargetDeletable del = (TargetDeletable) obj;
|
||||||
del.delete();
|
return del.delete();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
fail("No deletable software breakpoint spec found");
|
fail("No deletable software breakpoint spec found");
|
||||||
}).get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
|
throw new AssertionError();
|
||||||
|
}));
|
||||||
|
waitRecorder(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -200,14 +204,16 @@ public class DebuggerRecorderLogicalBreakpointServiceTest extends
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void handleToggleBreakpointInvocation(TraceBreakpoint expectedBreakpoint,
|
protected void handleToggleBreakpointInvocation(TraceRecorder target,
|
||||||
boolean expectedEnabled) throws Throwable {
|
TraceBreakpoint expectedBreakpoint, boolean expectedEnabled) throws Throwable {
|
||||||
// Logic is in the Test model
|
// Logic is in the Test model
|
||||||
|
waitRecorder(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void handleDeleteBreakpointInvocation(TraceBreakpoint expectedBreakpoint)
|
protected void handleDeleteBreakpointInvocation(TraceRecorder target,
|
||||||
throws Throwable {
|
TraceBreakpoint expectedBreakpoint) throws Throwable {
|
||||||
// Logic is in the Test model
|
// Logic is in the Test model
|
||||||
|
waitRecorder(target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@ public class DebuggerRmiLogicalBreakpointServiceTest extends
|
||||||
tb.trace.getObjectManager().createRootObject(SCHEMA_SESSION);
|
tb.trace.getObjectManager().createRootObject(SCHEMA_SESSION);
|
||||||
tb.createObjectsProcessAndThreads();
|
tb.createObjectsProcessAndThreads();
|
||||||
}
|
}
|
||||||
|
waitForDomainObject(tb.trace);
|
||||||
target1 = rmiCx.publishTarget(tool, tb.trace);
|
target1 = rmiCx.publishTarget(tool, tb.trace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,6 +65,7 @@ public class DebuggerRmiLogicalBreakpointServiceTest extends
|
||||||
tb3.trace.getObjectManager().createRootObject(SCHEMA_SESSION);
|
tb3.trace.getObjectManager().createRootObject(SCHEMA_SESSION);
|
||||||
tb3.createObjectsProcessAndThreads();
|
tb3.createObjectsProcessAndThreads();
|
||||||
}
|
}
|
||||||
|
waitForDomainObject(tb3.trace);
|
||||||
target3 = rmiCx.publishTarget(tool, tb3.trace);
|
target3 = rmiCx.publishTarget(tool, tb3.trace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,6 +81,7 @@ public class DebuggerRmiLogicalBreakpointServiceTest extends
|
||||||
try (Transaction tx = trace.openTransaction("Simulate step")) {
|
try (Transaction tx = trace.openTransaction("Simulate step")) {
|
||||||
snapshot = trace.getTimeManager().createSnapshot("Simulated step");
|
snapshot = trace.getTimeManager().createSnapshot("Simulated step");
|
||||||
}
|
}
|
||||||
|
waitForDomainObject(trace);
|
||||||
rmiCx.setLastSnapshot(trace, snapshot.getKey());
|
rmiCx.setLastSnapshot(trace, snapshot.getKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,12 +99,15 @@ public class DebuggerRmiLogicalBreakpointServiceTest extends
|
||||||
protected TraceObjectMemoryRegion addTargetTextRegion(TraceRmiTarget target, long offset)
|
protected TraceObjectMemoryRegion addTargetTextRegion(TraceRmiTarget target, long offset)
|
||||||
throws Throwable {
|
throws Throwable {
|
||||||
Trace trace = target.getTrace();
|
Trace trace = target.getTrace();
|
||||||
|
TraceObjectMemoryRegion result;
|
||||||
try (Transaction tx = trace.openTransaction("Add .text")) {
|
try (Transaction tx = trace.openTransaction("Add .text")) {
|
||||||
return Objects.requireNonNull(
|
result = Objects.requireNonNull(
|
||||||
addMemoryRegion(trace.getObjectManager(), Lifespan.nowOn(target.getSnap()),
|
addMemoryRegion(trace.getObjectManager(), Lifespan.nowOn(target.getSnap()),
|
||||||
tb.range(offset, offset + 0x0fff), "bin:.text", "rx")
|
tb.range(offset, offset + 0x0fff), "bin:.text", "rx")
|
||||||
.queryInterface(TraceObjectMemoryRegion.class));
|
.queryInterface(TraceObjectMemoryRegion.class));
|
||||||
}
|
}
|
||||||
|
waitForDomainObject(trace);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -113,12 +119,15 @@ public class DebuggerRmiLogicalBreakpointServiceTest extends
|
||||||
protected TraceObjectMemoryRegion addTargetDataRegion(TraceRmiTarget target) throws Throwable {
|
protected TraceObjectMemoryRegion addTargetDataRegion(TraceRmiTarget target) throws Throwable {
|
||||||
Trace trace = target.getTrace();
|
Trace trace = target.getTrace();
|
||||||
long offset = 0x56550000;
|
long offset = 0x56550000;
|
||||||
|
TraceObjectMemoryRegion result;
|
||||||
try (Transaction tx = trace.openTransaction("Add .data")) {
|
try (Transaction tx = trace.openTransaction("Add .data")) {
|
||||||
return Objects.requireNonNull(
|
result = Objects.requireNonNull(
|
||||||
addMemoryRegion(trace.getObjectManager(), Lifespan.nowOn(target.getSnap()),
|
addMemoryRegion(trace.getObjectManager(), Lifespan.nowOn(target.getSnap()),
|
||||||
tb.range(offset, offset + 0x0fff), "bin:.data", "rw")
|
tb.range(offset, offset + 0x0fff), "bin:.data", "rw")
|
||||||
.queryInterface(TraceObjectMemoryRegion.class));
|
.queryInterface(TraceObjectMemoryRegion.class));
|
||||||
}
|
}
|
||||||
|
waitForDomainObject(trace);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -131,6 +140,7 @@ public class DebuggerRmiLogicalBreakpointServiceTest extends
|
||||||
new ProgramLocation(program, addr(program, 0x00400000)), 0x1000,
|
new ProgramLocation(program, addr(program, 0x00400000)), 0x1000,
|
||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
|
waitForDomainObject(trace);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -141,6 +151,7 @@ public class DebuggerRmiLogicalBreakpointServiceTest extends
|
||||||
t.getStaticMappingManager().findContaining(addr(t, 0x55550000), target.getSnap());
|
t.getStaticMappingManager().findContaining(addr(t, 0x55550000), target.getSnap());
|
||||||
mapping.delete();
|
mapping.delete();
|
||||||
}
|
}
|
||||||
|
waitForDomainObject(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -188,6 +199,7 @@ public class DebuggerRmiLogicalBreakpointServiceTest extends
|
||||||
spec.getObject().remove(nowOn);
|
spec.getObject().remove(nowOn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
waitForDomainObject(trace);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -204,8 +216,8 @@ public class DebuggerRmiLogicalBreakpointServiceTest extends
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void handleToggleBreakpointInvocation(TraceBreakpoint expectedBreakpoint,
|
protected void handleToggleBreakpointInvocation(TraceRmiTarget target,
|
||||||
boolean expectedEn) throws Throwable {
|
TraceBreakpoint expectedBreakpoint, boolean expectedEn) throws Throwable {
|
||||||
if (!(expectedBreakpoint instanceof TraceObjectBreakpointLocation loc)) {
|
if (!(expectedBreakpoint instanceof TraceObjectBreakpointLocation loc)) {
|
||||||
throw new AssertionError("Unexpected trace breakpoint type: " + expectedBreakpoint);
|
throw new AssertionError("Unexpected trace breakpoint type: " + expectedBreakpoint);
|
||||||
}
|
}
|
||||||
|
@ -213,6 +225,7 @@ public class DebuggerRmiLogicalBreakpointServiceTest extends
|
||||||
try (Transaction tx = tb.startTransaction()) {
|
try (Transaction tx = tb.startTransaction()) {
|
||||||
loc.setEnabled(Lifespan.nowOn(0), expectedEn);
|
loc.setEnabled(Lifespan.nowOn(0), expectedEn);
|
||||||
}
|
}
|
||||||
|
waitForDomainObject(tb.trace);
|
||||||
rmiMethodToggleBreak.result(null);
|
rmiMethodToggleBreak.result(null);
|
||||||
assertEquals(Map.ofEntries(
|
assertEquals(Map.ofEntries(
|
||||||
Map.entry("breakpoint", loc.getSpecification().getObject()),
|
Map.entry("breakpoint", loc.getSpecification().getObject()),
|
||||||
|
@ -220,8 +233,8 @@ public class DebuggerRmiLogicalBreakpointServiceTest extends
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void handleDeleteBreakpointInvocation(TraceBreakpoint expectedBreakpoint)
|
protected void handleDeleteBreakpointInvocation(TraceRmiTarget target,
|
||||||
throws Throwable {
|
TraceBreakpoint expectedBreakpoint) throws Throwable {
|
||||||
if (!(expectedBreakpoint instanceof TraceObjectBreakpointLocation loc)) {
|
if (!(expectedBreakpoint instanceof TraceObjectBreakpointLocation loc)) {
|
||||||
throw new AssertionError("Unexpected trace breakpoint type: " + expectedBreakpoint);
|
throw new AssertionError("Unexpected trace breakpoint type: " + expectedBreakpoint);
|
||||||
}
|
}
|
||||||
|
@ -229,6 +242,7 @@ public class DebuggerRmiLogicalBreakpointServiceTest extends
|
||||||
try (Transaction tx = tb.startTransaction()) {
|
try (Transaction tx = tb.startTransaction()) {
|
||||||
loc.getObject().remove(Lifespan.nowOn(0));
|
loc.getObject().remove(Lifespan.nowOn(0));
|
||||||
}
|
}
|
||||||
|
waitForDomainObject(tb.trace);
|
||||||
rmiMethodDeleteBreak.result(null);
|
rmiMethodDeleteBreak.result(null);
|
||||||
assertEquals(Map.ofEntries(
|
assertEquals(Map.ofEntries(
|
||||||
Map.entry("breakpoint", loc.getSpecification().getObject())), args);
|
Map.entry("breakpoint", loc.getSpecification().getObject())), args);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue