mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-02-16 15:40:14 +00:00
Merge remote-tracking branch 'origin/GP-4868_Dan_fixMappingAndBrkServices--SQUASHED'
This commit is contained in:
commit
b8548b12dc
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
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();
|
||||
}
|
||||
}
|
@ -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));
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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()));
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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 {
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user