Merge remote-tracking branch

'origin/GP-2241_TruncateMemoryRangeMapping--SQUASHED' (Closes #4345)
This commit is contained in:
Ryan Kurtz
2022-08-23 00:31:41 -04:00
7 changed files with 106 additions and 42 deletions
@@ -62,41 +62,58 @@ public class GdbModelTargetProcessMemory
this.inferior = inferior.inferior;
}
protected CompletableFuture<Map<BigInteger, GdbMemoryMapping>> defaultUsingAddressSize() {
return inferior.evaluate("sizeof(int*)").thenApply(sizeStr -> {
int size;
try {
size = Integer.parseInt(sizeStr);
}
catch (NumberFormatException e) {
throw new GdbCommandError("Couldn't determine address size: " + e);
}
BigInteger start = BigInteger.ZERO;
BigInteger end = BigInteger.ONE.shiftLeft(size * 8);
if (size >= 0 && size < 8) {
GdbMemoryMapping mapping = new GdbMemoryMapping(start, end,
end.subtract(start), BigInteger.ZERO, "rwx", "default");
return Map.of(start, mapping);
}
if (size == 8) {
// TODO: This split shouldn't be necessary.
BigInteger split = BigInteger.valueOf(Long.MAX_VALUE);
GdbMemoryMapping lowMapping = new GdbMemoryMapping(start, split,
split.subtract(start), BigInteger.ZERO, "rwx", "defaultLow");
GdbMemoryMapping highMapping = new GdbMemoryMapping(split, end,
end.subtract(split), BigInteger.ZERO, "rwx", "defaultHigh");
return Map.of(start, lowMapping, split, highMapping);
}
throw new GdbCommandError("Unexpected address size: " + size);
});
}
protected void updateUsingMappings(Map<BigInteger, GdbMemoryMapping> byStart) {
List<GdbModelTargetMemoryRegion> regions;
synchronized (this) {
regions =
byStart.values().stream().map(this::getTargetRegion).collect(Collectors.toList());
if (regions.isEmpty() && valid) {
Map<BigInteger, GdbMemoryMapping> defaultMap =
new HashMap<BigInteger, GdbMemoryMapping>();
AddressSet addressSet = impl.getAddressFactory().getAddressSet();
BigInteger start = addressSet.getMinAddress().getOffsetAsBigInteger();
BigInteger end = addressSet.getMaxAddress().getOffsetAsBigInteger();
if (end.longValue() < 0) {
BigInteger split = BigInteger.valueOf(Long.MAX_VALUE);
GdbMemoryMapping lmem = new GdbMemoryMapping(start, split,
split.subtract(start), start.subtract(start), "rwx", "defaultLow");
defaultMap.put(start, lmem);
split = split.add(BigInteger.valueOf(1));
GdbMemoryMapping hmem = new GdbMemoryMapping(split, end,
end.subtract(split), split.subtract(split), "rwx", "defaultHigh");
defaultMap.put(split, hmem);
}
else {
GdbMemoryMapping mem = new GdbMemoryMapping(start, end,
end.subtract(start), start.subtract(start), "rwx", "default");
defaultMap.put(start, mem);
}
regions =
defaultMap.values()
.stream()
.map(this::getTargetRegion)
.collect(Collectors.toList());
if (!valid) {
setElements(List.of(), "Refreshed");
}
}
setElements(regions, "Refreshed");
CompletableFuture<Map<BigInteger, GdbMemoryMapping>> maybeDefault =
byStart.isEmpty() ? defaultUsingAddressSize()
: CompletableFuture.completedFuture(byStart);
maybeDefault.thenAccept(mappings -> {
List<GdbModelTargetMemoryRegion> regions;
synchronized (this) {
regions = mappings.values()
.stream()
.map(this::getTargetRegion)
.collect(Collectors.toList());
}
setElements(regions, "Refreshed");
}).exceptionally(ex -> {
Msg.info(this, "Failed to update regions: " + ex);
return null;
});
}
@Override
@@ -55,4 +55,13 @@ public interface DebuggerMemoryMapper {
return new AddressRangeImpl(targetToTrace(targetRange.getMinAddress()),
targetToTrace(targetRange.getMaxAddress()));
}
/**
* Map the given address range from the target process into the trace, truncating it to the
* portion intersecting the trace-side address space
*
* @param targetRange the range in the target's address space
* @return the intersection of the "same range" and the trace's address space
*/
AddressRange targetToTraceTruncated(AddressRange targetRange);
}
@@ -18,6 +18,7 @@ package ghidra.app.plugin.core.debug.mapping;
import ghidra.dbg.DebuggerObjectModel;
import ghidra.program.model.address.*;
import ghidra.program.model.lang.Language;
import ghidra.util.MathUtilities;
public class DefaultDebuggerMemoryMapper implements DebuggerMemoryMapper {
protected final AddressFactory traceAddressFactory;
@@ -50,13 +51,29 @@ public class DefaultDebuggerMemoryMapper implements DebuggerMemoryMapper {
@Override
public Address targetToTrace(Address targetAddr) {
if (targetAddr == SpecialAddress.NO_ADDRESS) {
/**
* TODO: Allow NO_ADDRESS into the database? There will be a bit of fallout as the UI
* will have to accommodate the same possibility, esp., for go-to.
*/
return null;
return SpecialAddress.NO_ADDRESS;
}
assert isInFactory(targetAddr, targetAddressFactory);
return toSameNamedSpace(targetAddr, traceAddressFactory);
}
@Override
public AddressRange targetToTraceTruncated(AddressRange targetRange) {
AddressSpace traceSpace =
traceAddressFactory.getAddressSpace(targetRange.getAddressSpace().getName());
long maxTraceSpaceOffset = traceSpace.getMaxAddress().getOffset();
Address targetMin = targetRange.getMinAddress();
long minTargetOffset = targetMin.getOffset();
if (Long.compareUnsigned(maxTraceSpaceOffset, minTargetOffset) < 0) {
return null;
}
Address traceMin = traceSpace.getAddress(minTargetOffset);
Address targetMax = targetRange.getMaxAddress();
long maxTargetOffset = targetMax.getOffset();
Address traceMax =
traceSpace.getAddress(MathUtilities.unsignedMin(maxTraceSpaceOffset, maxTargetOffset));
return new AddressRangeImpl(traceMin, traceMax);
}
}
@@ -70,6 +70,12 @@ public class ObjectBasedDebuggerMemoryMapper implements DebuggerMemoryMapper {
return traceSpace.getAddress(targetAddr.getOffset());
}
@Override
public AddressRange targetToTraceTruncated(AddressRange targetRange) {
// the DATA space can always accommodate all 64 bits
return targetToTrace(targetRange);
}
protected AddressSpace createSpace(String name) {
try (UndoableTransaction tid =
UndoableTransaction.start(trace, "Create space for mapping")) {
@@ -24,8 +24,7 @@ import ghidra.app.plugin.core.debug.service.model.interfaces.ManagedMemoryRecord
import ghidra.app.plugin.core.debug.service.model.record.RecorderUtils;
import ghidra.dbg.target.TargetMemory;
import ghidra.dbg.target.TargetMemoryRegion;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.address.*;
import ghidra.trace.model.Trace;
import ghidra.trace.model.memory.*;
import ghidra.util.Msg;
@@ -72,8 +71,16 @@ public class DefaultMemoryRecorder implements ManagedMemoryRecorder {
Msg.warn(this, "Region " + path + " already recorded");
return;
}
traceRegion = memoryManager.addRegion(path, Range.atLeast(snap),
recorder.getMemoryMapper().targetToTrace(region.getRange()),
AddressRange traceRange =
recorder.getMemoryMapper().targetToTraceTruncated(region.getRange());
if (traceRange == null) {
Msg.warn(this, "Dropped unmappable region: " + region);
return;
}
if (region.getRange().getLength() != traceRange.getLength()) {
Msg.warn(this, "Truncated region: " + region);
}
traceRegion = memoryManager.addRegion(path, Range.atLeast(snap), traceRange,
getTraceFlags(region));
traceRegion.setName(region.getDisplay());
}
@@ -82,7 +82,11 @@ public class RecorderComposedMemory implements AbstractRecorderMemory {
if (acc == null || !acc.getAllAccessibility()) {
continue;
}
accessible.add(memMapper.targetToTrace(ent.getKey().getRange()));
AddressRange traceRange = memMapper.targetToTraceTruncated(ent.getKey().getRange());
if (traceRange == null) {
continue;
}
accessible.add(traceRange);
}
return accessible;
}
@@ -105,7 +105,11 @@ public class RecorderSimpleMemory implements AbstractRecorderMemory {
AddressSet accessible = new AddressSet();
if (memMapper != null) {
for (Entry<Address, TargetMemoryRegion> ent : byMin.entrySet()) {
accessible.add(memMapper.targetToTrace(ent.getValue().getRange()));
AddressRange traceRange =
memMapper.targetToTraceTruncated(ent.getValue().getRange());
if (traceRange != null) {
accessible.add(traceRange);
}
}
}
return accessible;