Merge remote-tracking branch 'origin/GP-4868_Dan_fixMappingAndBrkServices--SQUASHED'

This commit is contained in:
Ryan Kurtz 2024-08-26 14:41:32 -04:00
commit b8548b12dc
15 changed files with 1273 additions and 1081 deletions

View File

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -65,7 +65,9 @@ class TraceBreakpointSet {
@Override
public String toString() {
return String.format("<at %s in %s: %s>", address, trace.getName(), breakpoints);
synchronized (breakpoints) {
return String.format("<at %s in %s: %s>", address, trace.getName(), breakpoints);
}
}
/**
@ -126,22 +128,24 @@ class TraceBreakpointSet {
*/
public TraceMode computeMode() {
TraceMode mode = TraceMode.NONE;
if (getControlMode().useEmulatedBreakpoints()) {
synchronized (breakpoints) {
if (getControlMode().useEmulatedBreakpoints()) {
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
mode = mode.combine(computeEmuMode(bpt.obj));
if (mode == TraceMode.MISSING) {
return mode;
}
}
return mode;
}
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
mode = mode.combine(computeEmuMode(bpt.obj));
mode = mode.combine(computeTargetMode(bpt.obj));
if (mode == TraceMode.MISSING) {
return mode;
}
}
return mode;
}
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
mode = mode.combine(computeTargetMode(bpt.obj));
if (mode == TraceMode.MISSING) {
return mode;
}
}
return mode;
}
/**
@ -188,14 +192,16 @@ class TraceBreakpointSet {
*/
public String computeSleigh() {
String sleigh = null;
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
String s = bpt.obj.getEmuSleigh();
if (sleigh != null && !sleigh.equals(s)) {
return null;
synchronized (breakpoints) {
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
String s = bpt.obj.getEmuSleigh();
if (sleigh != null && !sleigh.equals(s)) {
return null;
}
sleigh = s;
}
sleigh = s;
return sleigh;
}
return sleigh;
}
/**
@ -206,8 +212,10 @@ class TraceBreakpointSet {
public void setEmuSleigh(String emuSleigh) {
this.emuSleigh = emuSleigh;
try (Transaction tx = trace.openTransaction("Set breakpoint Sleigh")) {
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
bpt.obj.setEmuSleigh(emuSleigh);
synchronized (breakpoints) {
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
bpt.obj.setEmuSleigh(emuSleigh);
}
}
}
}
@ -218,7 +226,9 @@ class TraceBreakpointSet {
* @return true if empty, false otherwise
*/
public boolean isEmpty() {
return breakpoints.isEmpty();
synchronized (breakpoints) {
return breakpoints.isEmpty();
}
}
/**
@ -227,7 +237,9 @@ class TraceBreakpointSet {
* @return the breakpoints
*/
public Set<TraceBreakpoint> getBreakpoints() {
return breakpoints.stream().map(e -> e.obj).collect(Collectors.toUnmodifiableSet());
synchronized (breakpoints) {
return breakpoints.stream().map(e -> e.obj).collect(Collectors.toUnmodifiableSet());
}
}
/**
@ -246,7 +258,9 @@ class TraceBreakpointSet {
bpt.setEmuSleigh(emuSleigh);
}
}
return breakpoints.add(new IDHashed<>(bpt));
synchronized (breakpoints) {
return breakpoints.add(new IDHashed<>(bpt));
}
}
/**
@ -275,7 +289,9 @@ class TraceBreakpointSet {
* @return true if the set actually changes as a result
*/
public boolean remove(TraceBreakpoint bpt) {
return breakpoints.remove(new IDHashed<>(bpt));
synchronized (breakpoints) {
return breakpoints.remove(new IDHashed<>(bpt));
}
}
/**
@ -303,7 +319,7 @@ class TraceBreakpointSet {
public void planEnable(BreakpointActionSet actions, long length,
Collection<TraceBreakpointKind> kinds) {
long snap = getSnap();
if (breakpoints.isEmpty()) {
if (isEmpty()) {
if (target == null || getControlMode().useEmulatedBreakpoints()) {
planPlaceEmu(actions, snap, length, kinds);
}
@ -339,14 +355,18 @@ class TraceBreakpointSet {
}
private void planEnableTarget(BreakpointActionSet actions) {
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
actions.planEnableTarget(target, bpt.obj);
synchronized (breakpoints) {
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
actions.planEnableTarget(target, bpt.obj);
}
}
}
private void planEnableEmu(BreakpointActionSet actions) {
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
actions.planEnableEmu(bpt.obj);
synchronized (breakpoints) {
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
actions.planEnableEmu(bpt.obj);
}
}
}
@ -369,14 +389,18 @@ class TraceBreakpointSet {
private void planDisableTarget(BreakpointActionSet actions, long length,
Collection<TraceBreakpointKind> kinds) {
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
actions.planDisableTarget(target, bpt.obj);
synchronized (breakpoints) {
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
actions.planDisableTarget(target, bpt.obj);
}
}
}
private void planDisableEmu(BreakpointActionSet actions) {
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
actions.planDisableEmu(bpt.obj);
synchronized (breakpoints) {
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
actions.planDisableEmu(bpt.obj);
}
}
}
@ -399,14 +423,18 @@ class TraceBreakpointSet {
private void planDeleteTarget(BreakpointActionSet actions, long length,
Set<TraceBreakpointKind> kinds) {
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
actions.planDeleteTarget(target, bpt.obj);
synchronized (breakpoints) {
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
actions.planDeleteTarget(target, bpt.obj);
}
}
}
private void planDeleteEmu(BreakpointActionSet actions) {
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
actions.planDeleteEmu(bpt.obj);
synchronized (breakpoints) {
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
actions.planDeleteEmu(bpt.obj);
}
}
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -15,7 +15,7 @@
*/
package ghidra.app.plugin.core.debug.service.tracemgr;
import static ghidra.framework.main.DataTreeDialogType.*;
import static ghidra.framework.main.DataTreeDialogType.OPEN;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
@ -656,7 +656,9 @@ public class DebuggerTraceManagerServicePlugin extends Plugin
@Override
public synchronized Collection<Trace> getOpenTraces() {
return Set.copyOf(tracesView);
synchronized (listenersByTrace) {
return Set.copyOf(tracesView);
}
}
@Override
@ -998,8 +1000,8 @@ public class DebuggerTraceManagerServicePlugin extends Plugin
protected void doCloseTraces(Collection<Trace> traces, Collection<Target> targets) {
for (Trace t : traces) {
if (t.getConsumerList().contains(this)) {
firePluginEvent(new TraceClosedPluginEvent(getName(), t));
doTraceClosed(t);
firePluginEvent(new TraceClosedPluginEvent(getName(), t));
}
}
TargetActionTask.executeTask(tool, new DisconnectTask(tool, targets));

View File

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -614,8 +614,7 @@ public abstract class AbstractGhidraHeadedDebuggerTest
@BeforeClass
public static void beforeClass() {
// Note: we may decided to move this up to a framework-level base test class
// Note: we decided to move this up to a framework-level base test class
TestDataStructureErrorHandlerInstaller.installConcurrentExceptionErrorHandler();
}

View File

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -95,6 +95,7 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
try (ToyDBTraceBuilder r = new ToyDBTraceBuilder(saved)) {
assertNotSame(tb.trace, r.trace);
traceManager.openTrace(r.trace);
waitForDomainObject(r.trace);
return r.trace;
}
}
@ -240,10 +241,11 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
}
@Test
public void testAddMappingThenCopyAndTranslateStaticToTraceMissWayBefore() throws Exception {
public void testAddMappingThenCopyAndTranslateStaticToTraceMissWayBefore() throws Throwable {
addMapping();
copyTrace();
add2ndMapping();
waitOn(mappingService.changesSettled());
Set<TraceLocation> locations = mappingService.getOpenMappedLocations(
new ProgramLocation(program, stSpace.getAddress(0x00000bad)));
@ -251,10 +253,11 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
}
@Test
public void testAddMappingThenCopyAndTranslateStaticToTraceMissJustBefore() throws Exception {
public void testAddMappingThenCopyAndTranslateStaticToTraceMissJustBefore() throws Throwable {
addMapping();
copyTrace();
add2ndMapping();
waitOn(mappingService.changesSettled());
Set<TraceLocation> locations = mappingService.getOpenMappedLocations(
new ProgramLocation(program, stSpace.getAddress(0x001fffff)));
@ -262,10 +265,11 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
}
@Test
public void testAddMappingThenCopyAndTranslateStaticToTraceHitAtStart() throws Exception {
public void testAddMappingThenCopyAndTranslateStaticToTraceHitAtStart() throws Throwable {
addMapping();
Trace copy = copyTrace();
add2ndMapping();
waitOn(mappingService.changesSettled());
Set<TraceLocation> locations = mappingService.getOpenMappedLocations(
new ProgramLocation(program, stSpace.getAddress(0x00200000)));
@ -281,10 +285,11 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
}
@Test
public void testAddMappingThenCopyAndTranslateStaticToTraceHitInMiddle() throws Exception {
public void testAddMappingThenCopyAndTranslateStaticToTraceHitInMiddle() throws Throwable {
addMapping();
Trace copy = copyTrace();
add2ndMapping();
waitOn(mappingService.changesSettled());
Set<TraceLocation> locations = mappingService.getOpenMappedLocations(
new ProgramLocation(program, stSpace.getAddress(0x00200833)));
@ -298,10 +303,11 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
}
@Test
public void testAddMappingThenCopyAndTranslateStaticToTraceHitAtEnd() throws Exception {
public void testAddMappingThenCopyAndTranslateStaticToTraceHitAtEnd() throws Throwable {
addMapping();
Trace copy = copyTrace();
add2ndMapping();
waitOn(mappingService.changesSettled());
Set<TraceLocation> locations = mappingService.getOpenMappedLocations(
new ProgramLocation(program, stSpace.getAddress(0x00200fff)));
@ -315,10 +321,11 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
}
@Test
public void testAddMappingThenCopyAndTranslateStaticToTraceMissJustAfter() throws Exception {
public void testAddMappingThenCopyAndTranslateStaticToTraceMissJustAfter() throws Throwable {
addMapping();
copyTrace();
add2ndMapping();
waitOn(mappingService.changesSettled());
Set<TraceLocation> locations = mappingService.getOpenMappedLocations(
new ProgramLocation(program, stSpace.getAddress(0x00201000)));
@ -326,10 +333,11 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
}
@Test
public void testAddMappingThenCopyAndTranslateStaticToTraceMissWayAfter() throws Exception {
public void testAddMappingThenCopyAndTranslateStaticToTraceMissWayAfter() throws Throwable {
addMapping();
copyTrace();
add2ndMapping();
waitOn(mappingService.changesSettled());
Set<TraceLocation> locations = mappingService.getOpenMappedLocations(
new ProgramLocation(program, stSpace.getAddress(0xbadbadbadL)));
@ -377,10 +385,11 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
}
@Test
public void testAddMappingThenTranslateStaticViewToTraceEmpty() throws Exception {
public void testAddMappingThenTranslateStaticViewToTraceEmpty() throws Throwable {
addMapping();
copyTrace();
add2ndMapping();
waitOn(mappingService.changesSettled());
Map<TraceSpan, Collection<MappedAddressRange>> views =
mappingService.getOpenMappedViews(program, new AddressSet());
@ -388,10 +397,11 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
}
@Test
public void testAddMappingThenTranslateStaticViewToTraceReplete() throws Exception {
public void testAddMappingThenTranslateStaticViewToTraceReplete() throws Throwable {
addMapping();
Trace copy = copyTrace();
add2ndMapping();
waitOn(mappingService.changesSettled());
AddressSet set = new AddressSet();
// Before
@ -438,10 +448,12 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
}
@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
addMapping();
programManager.closeProgram(program, true);
waitForSwing();
waitOn(mappingService.changesSettled());
AddressSet addrSet = new AddressSet(dynSpace.getAddress(0x00000bad));
Set<Program> programSet =
@ -451,9 +463,11 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
}
@Test
public void testAddMappingThenCloseStaticAndOpenMappedHitInMiddle() throws Exception {
public void testAddMappingThenCloseStaticAndOpenMappedHitInMiddle() throws Throwable {
addMapping();
programManager.closeProgram(program, true);
waitForSwing();
waitOn(mappingService.changesSettled());
AddressSet addrSet = new AddressSet(dynSpace.getAddress(0x00100c0d));
Set<Program> programSet =
@ -465,9 +479,11 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
}
@Test
public void testAddMappingThenCloseStaticAndOpenMappedMissWayAfter() throws Exception {
public void testAddMappingThenCloseStaticAndOpenMappedMissWayAfter() throws Throwable {
addMapping();
programManager.closeProgram(program, true);
waitForSwing();
waitOn(mappingService.changesSettled());
AddressSet addrSet = new AddressSet(dynSpace.getAddress(0xbadbadbadL));
Set<Program> programSet =
@ -478,14 +494,17 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
@Test
public void testAddMappingThenCloseStaticAndTranslateTraceToStaticHitInMiddle()
throws Exception {
throws Throwable {
addMapping();
waitOn(mappingService.changesSettled());
// pre-check
assertNotNull(mappingService.getOpenMappedLocation(
new DefaultTraceLocation(tb.trace, null, Lifespan.nowOn(0),
dynSpace.getAddress(0x00100c0d))));
programManager.closeProgram(program, true);
waitForSwing();
waitOn(mappingService.changesSettled());
assertNull(mappingService.getOpenMappedLocation(
new DefaultTraceLocation(tb.trace, null, Lifespan.nowOn(0),
@ -494,14 +513,16 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
@Test
public void testAddMappingThenCloseTraceAndTranslateStaticToTraceHitInMiddle()
throws Exception {
throws Throwable {
addMapping();
waitOn(mappingService.changesSettled());
// pre-check
assertEquals(1, mappingService.getOpenMappedLocations(
new ProgramLocation(program, stSpace.getAddress(0x00200c0d))).size());
traceManager.closeTrace(tb.trace);
waitForSwing();
waitOn(mappingService.changesSettled());
assertTrue(mappingService.getOpenMappedLocations(
new ProgramLocation(program, stSpace.getAddress(0x00200c0d))).isEmpty());
@ -509,9 +530,11 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
@Test
public void testAddMappingThenCloseAndReopenStaticAndTranslateTraceToStaticHitInMiddle()
throws Exception {
throws Throwable {
addMapping();
programManager.closeProgram(program, true);
waitForSwing();
waitOn(mappingService.changesSettled());
// pre-check
assertNull(mappingService.getOpenMappedLocation(
new DefaultTraceLocation(tb.trace, null, Lifespan.nowOn(0),
@ -519,6 +542,7 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
programManager.openProgram(program);
waitForProgram(program);
waitOn(mappingService.changesSettled());
assertNotNull(mappingService.getOpenMappedLocation(
new DefaultTraceLocation(tb.trace, null, Lifespan.nowOn(0),
@ -527,17 +551,19 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
@Test
public void testAddMappingThenCloseAndReopenTraceAndTranslateStaticToTraceHitInMiddle()
throws Exception {
throws Throwable {
addMapping();
traceManager.closeTrace(tb.trace);
waitForSwing();
waitOn(mappingService.changesSettled());
// pre-check
assertTrue(mappingService.getOpenMappedLocations(
new ProgramLocation(program, stSpace.getAddress(0x00200c0d))).isEmpty());
traceManager.openTrace(tb.trace);
waitForSwing();
waitForDomainObject(tb.trace);
waitOn(mappingService.changesSettled());
assertEquals(1, mappingService.getOpenMappedLocations(
new ProgramLocation(program, stSpace.getAddress(0x00200c0d))).size());
@ -545,7 +571,7 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
@Test
public void testAddMappingThenRemoveButAbortThenTranslateTraceToStaticHitInMiddle()
throws Exception {
throws Throwable {
addMapping();
TraceLocation goodLoc =
new DefaultTraceLocation(tb.trace, null, Lifespan.nowOn(0),
@ -553,19 +579,23 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
try (Transaction tx = tb.startTransaction()) {
mappingManager.findContaining(dynSpace.getAddress(0x00100000), 0).delete();
waitForDomainObject(tb.trace);
waitOn(mappingService.changesSettled());
// pre-check
assertNull(mappingService.getOpenMappedLocation(goodLoc));
tx.abort();
}
waitForDomainObject(tb.trace);
waitOn(mappingService.changesSettled());
assertNotNull(mappingService.getOpenMappedLocation(goodLoc));
}
@Test
public void testAddCorrelationRemoveButUndoThenRequestMappingDynamicToStaticWithin()
throws Exception {
throws Throwable {
addMapping();
waitOn(mappingService.changesSettled());
TraceLocation goodLoc =
new DefaultTraceLocation(tb.trace, null, Lifespan.nowOn(0),
dynSpace.getAddress(0x00100c0d));
@ -577,11 +607,13 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
mappingManager.findContaining(dynSpace.getAddress(0x00100000), 0).delete();
}
waitForDomainObject(tb.trace);
waitOn(mappingService.changesSettled());
// pre-check
assertNull(mappingService.getOpenMappedLocation(goodLoc));
undo(tb.trace, true);
waitOn(mappingService.changesSettled());
assertNotNull(mappingService.getOpenMappedLocation(goodLoc));
}
@ -619,7 +651,7 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
}
@Test
public void testMapFullSpace() throws Exception {
public void testMapFullSpace() throws Throwable {
try (Transaction tx = tb.startTransaction()) {
TraceLocation traceLoc =
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
mappingService.addMapping(traceLoc, progLoc, 0, true);
}
waitForPass(() -> assertMapsTwoWay(0L, 0L));
waitForSwing();
waitOn(mappingService.changesSettled());
assertMapsTwoWay(0L, 0L);
assertMapsTwoWay(-1L, -1L);
assertMapsTwoWay(Long.MAX_VALUE, Long.MAX_VALUE);
assertMapsTwoWay(Long.MIN_VALUE, Long.MIN_VALUE);

View File

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -33,7 +33,7 @@ import ghidra.util.database.*;
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>
* Version history:

View File

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -26,7 +26,30 @@ import ghidra.program.model.listing.CodeUnit;
import ghidra.trace.model.TraceAddressSnapRange;
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>> {
/**
* A means of obtaining the range attribute from each object
*
* @param <T> the type of objects returned by an iterator
*/
public interface Ranger<T> {
Address getMinAddress(T t);

View File

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -483,7 +483,7 @@ public abstract class AbstractDebuggerBreakpointMarkerPluginTest<T>
addMappedBreakpointOpenAndWait(); // wasteful, but whatever
for (LogicalBreakpoint lb : List.copyOf(breakpointService.getAllBreakpoints())) {
TraceBreakpoint brk = Unique.assertOne(lb.getTraceBreakpoints(tb.trace));
lb.delete();
waitOn(lb.delete());
handleDeleteBreakpointInvocation(brk);
}
waitForPass(() -> assertEquals(0, breakpointService.getAllBreakpoints().size()));
@ -515,7 +515,7 @@ public abstract class AbstractDebuggerBreakpointMarkerPluginTest<T>
addMappedBreakpointOpenAndWait(); // wasteful, but whatever
for (LogicalBreakpoint lb : List.copyOf(breakpointService.getAllBreakpoints())) {
TraceBreakpoint brk = Unique.assertOne(lb.getTraceBreakpoints(tb.trace));
lb.delete();
waitOn(lb.delete());
handleDeleteBreakpointInvocation(brk);
}
waitForPass(() -> assertEquals(0, breakpointService.getAllBreakpoints().size()));

View File

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -17,6 +17,8 @@ package ghidra.app.plugin.core.debug.service.breakpoint;
import java.io.IOException;
import org.junit.Ignore;
import db.Transaction;
import ghidra.dbg.target.schema.SchemaContext;
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.target.TraceObjectKeyPath;
@Ignore("Deprecated")
public class DebuggerObjectRecorderLogicalBreakpointServiceTest
extends DebuggerRecorderLogicalBreakpointServiceTest {

View File

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -19,9 +19,9 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.junit.Before;
import org.junit.Ignore;
import db.Transaction;
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.modules.TraceStaticMapping;
@Ignore("Deprecated")
public class DebuggerRecorderLogicalBreakpointServiceTest extends
AbstractDebuggerLogicalBreakpointServiceTest<TraceRecorder, TestTargetMemoryRegion> {
@ -130,6 +131,7 @@ public class DebuggerRecorderLogicalBreakpointServiceTest extends
new ProgramLocation(p, addr(p, 0x00400000)), 0x1000,
false);
}
waitForDomainObject(t);
}
@Override
@ -140,6 +142,7 @@ public class DebuggerRecorderLogicalBreakpointServiceTest extends
t.getStaticMappingManager().findContaining(addr(t, 0x55550000), r.getSnap());
mapping.delete();
}
waitForDomainObject(t);
}
@Override
@ -168,7 +171,7 @@ public class DebuggerRecorderLogicalBreakpointServiceTest extends
@Override
protected void removeTargetSoftwareBreakpoint(TraceRecorder r) throws Throwable {
TargetBreakpointSpecContainer cont = getBreakpointContainer(r);
cont.fetchElements().thenAccept(elements -> {
waitOn(cont.fetchElements().thenCompose(elements -> {
for (TargetObject obj : elements.values()) {
if (!(obj instanceof TargetBreakpointSpec) ||
!(obj instanceof TargetDeletable)) {
@ -179,11 +182,12 @@ public class DebuggerRecorderLogicalBreakpointServiceTest extends
continue;
}
TargetDeletable del = (TargetDeletable) obj;
del.delete();
return;
return del.delete();
}
fail("No deletable software breakpoint spec found");
}).get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
throw new AssertionError();
}));
waitRecorder(r);
}
@Override
@ -200,14 +204,16 @@ public class DebuggerRecorderLogicalBreakpointServiceTest extends
}
@Override
protected void handleToggleBreakpointInvocation(TraceBreakpoint expectedBreakpoint,
boolean expectedEnabled) throws Throwable {
protected void handleToggleBreakpointInvocation(TraceRecorder target,
TraceBreakpoint expectedBreakpoint, boolean expectedEnabled) throws Throwable {
// Logic is in the Test model
waitRecorder(target);
}
@Override
protected void handleDeleteBreakpointInvocation(TraceBreakpoint expectedBreakpoint)
throws Throwable {
protected void handleDeleteBreakpointInvocation(TraceRecorder target,
TraceBreakpoint expectedBreakpoint) throws Throwable {
// Logic is in the Test model
waitRecorder(target);
}
}

View File

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -53,6 +53,7 @@ public class DebuggerRmiLogicalBreakpointServiceTest extends
tb.trace.getObjectManager().createRootObject(SCHEMA_SESSION);
tb.createObjectsProcessAndThreads();
}
waitForDomainObject(tb.trace);
target1 = rmiCx.publishTarget(tool, tb.trace);
}
@ -64,6 +65,7 @@ public class DebuggerRmiLogicalBreakpointServiceTest extends
tb3.trace.getObjectManager().createRootObject(SCHEMA_SESSION);
tb3.createObjectsProcessAndThreads();
}
waitForDomainObject(tb3.trace);
target3 = rmiCx.publishTarget(tool, tb3.trace);
}
@ -79,6 +81,7 @@ public class DebuggerRmiLogicalBreakpointServiceTest extends
try (Transaction tx = trace.openTransaction("Simulate step")) {
snapshot = trace.getTimeManager().createSnapshot("Simulated step");
}
waitForDomainObject(trace);
rmiCx.setLastSnapshot(trace, snapshot.getKey());
}
@ -96,12 +99,15 @@ public class DebuggerRmiLogicalBreakpointServiceTest extends
protected TraceObjectMemoryRegion addTargetTextRegion(TraceRmiTarget target, long offset)
throws Throwable {
Trace trace = target.getTrace();
TraceObjectMemoryRegion result;
try (Transaction tx = trace.openTransaction("Add .text")) {
return Objects.requireNonNull(
result = Objects.requireNonNull(
addMemoryRegion(trace.getObjectManager(), Lifespan.nowOn(target.getSnap()),
tb.range(offset, offset + 0x0fff), "bin:.text", "rx")
.queryInterface(TraceObjectMemoryRegion.class));
}
waitForDomainObject(trace);
return result;
}
@Override
@ -113,12 +119,15 @@ public class DebuggerRmiLogicalBreakpointServiceTest extends
protected TraceObjectMemoryRegion addTargetDataRegion(TraceRmiTarget target) throws Throwable {
Trace trace = target.getTrace();
long offset = 0x56550000;
TraceObjectMemoryRegion result;
try (Transaction tx = trace.openTransaction("Add .data")) {
return Objects.requireNonNull(
result = Objects.requireNonNull(
addMemoryRegion(trace.getObjectManager(), Lifespan.nowOn(target.getSnap()),
tb.range(offset, offset + 0x0fff), "bin:.data", "rw")
.queryInterface(TraceObjectMemoryRegion.class));
}
waitForDomainObject(trace);
return result;
}
@Override
@ -131,6 +140,7 @@ public class DebuggerRmiLogicalBreakpointServiceTest extends
new ProgramLocation(program, addr(program, 0x00400000)), 0x1000,
false);
}
waitForDomainObject(trace);
}
@Override
@ -141,6 +151,7 @@ public class DebuggerRmiLogicalBreakpointServiceTest extends
t.getStaticMappingManager().findContaining(addr(t, 0x55550000), target.getSnap());
mapping.delete();
}
waitForDomainObject(t);
}
@Override
@ -188,6 +199,7 @@ public class DebuggerRmiLogicalBreakpointServiceTest extends
spec.getObject().remove(nowOn);
}
}
waitForDomainObject(trace);
}
@Override
@ -204,8 +216,8 @@ public class DebuggerRmiLogicalBreakpointServiceTest extends
}
@Override
protected void handleToggleBreakpointInvocation(TraceBreakpoint expectedBreakpoint,
boolean expectedEn) throws Throwable {
protected void handleToggleBreakpointInvocation(TraceRmiTarget target,
TraceBreakpoint expectedBreakpoint, boolean expectedEn) throws Throwable {
if (!(expectedBreakpoint instanceof TraceObjectBreakpointLocation loc)) {
throw new AssertionError("Unexpected trace breakpoint type: " + expectedBreakpoint);
}
@ -213,6 +225,7 @@ public class DebuggerRmiLogicalBreakpointServiceTest extends
try (Transaction tx = tb.startTransaction()) {
loc.setEnabled(Lifespan.nowOn(0), expectedEn);
}
waitForDomainObject(tb.trace);
rmiMethodToggleBreak.result(null);
assertEquals(Map.ofEntries(
Map.entry("breakpoint", loc.getSpecification().getObject()),
@ -220,8 +233,8 @@ public class DebuggerRmiLogicalBreakpointServiceTest extends
}
@Override
protected void handleDeleteBreakpointInvocation(TraceBreakpoint expectedBreakpoint)
throws Throwable {
protected void handleDeleteBreakpointInvocation(TraceRmiTarget target,
TraceBreakpoint expectedBreakpoint) throws Throwable {
if (!(expectedBreakpoint instanceof TraceObjectBreakpointLocation loc)) {
throw new AssertionError("Unexpected trace breakpoint type: " + expectedBreakpoint);
}
@ -229,6 +242,7 @@ public class DebuggerRmiLogicalBreakpointServiceTest extends
try (Transaction tx = tb.startTransaction()) {
loc.getObject().remove(Lifespan.nowOn(0));
}
waitForDomainObject(tb.trace);
rmiMethodDeleteBreak.result(null);
assertEquals(Map.ofEntries(
Map.entry("breakpoint", loc.getSpecification().getObject())), args);