mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
GP-2551: Fix RegistersProvider for new trace conventions
This commit is contained in:
parent
e89b86a66f
commit
bc2ba594b4
86 changed files with 1743 additions and 708 deletions
|
@ -25,6 +25,7 @@ import ghidra.trace.model.memory.TraceMemoryState;
|
|||
import ghidra.trace.model.property.TracePropertyMap;
|
||||
import ghidra.trace.model.property.TracePropertyMapSpace;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.trace.util.TraceRegisterUtils;
|
||||
import ghidra.trace.util.TraceTimeViewport;
|
||||
|
||||
/**
|
||||
|
@ -128,9 +129,7 @@ public class DefaultPcodeTraceRegistersAccess extends AbstractPcodeTraceDataAcce
|
|||
return null; // client should bail anyway
|
||||
}
|
||||
AddressSpace space = ops.getAddressSpace();
|
||||
return new AddressRangeImpl(
|
||||
space.getOverlayAddress(range.getMinAddress()),
|
||||
space.getOverlayAddress(range.getMaxAddress()));
|
||||
return TraceRegisterUtils.getOverlayRange(space, range);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -140,12 +139,6 @@ public class DefaultPcodeTraceRegistersAccess extends AbstractPcodeTraceDataAcce
|
|||
return null; // client should bail anyway
|
||||
}
|
||||
AddressSpace space = ops.getAddressSpace();
|
||||
AddressSet result = new AddressSet();
|
||||
for (AddressRange rng : set) {
|
||||
result.add(
|
||||
space.getOverlayAddress(rng.getMinAddress()),
|
||||
space.getOverlayAddress(rng.getMaxAddress()));
|
||||
}
|
||||
return result;
|
||||
return TraceRegisterUtils.getOverlaySet(space, set);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -227,6 +227,20 @@ public class DBTraceOverlaySpaceAdapter implements DBTraceManager {
|
|||
}
|
||||
}
|
||||
|
||||
protected AddressSpace doCreateOverlaySpace(String name, AddressSpace base) {
|
||||
TraceAddressFactory factory = trace.getInternalAddressFactory();
|
||||
OverlayAddressSpace space =
|
||||
factory.addOverlayAddressSpace(name, true, base, base.getMinAddress().getOffset(),
|
||||
base.getMaxAddress().getOffset());
|
||||
// Only if it succeeds do we store the record
|
||||
DBTraceOverlaySpaceEntry ent = overlayStore.create();
|
||||
ent.set(space.getName(), base.getName());
|
||||
trace.updateViewsAddSpaceBlock(space);
|
||||
trace.setChanged(new TraceChangeRecord<>(TraceOverlaySpaceChangeType.ADDED, null,
|
||||
trace, null, space));
|
||||
return space;
|
||||
}
|
||||
|
||||
public AddressSpace createOverlayAddressSpace(String name, AddressSpace base)
|
||||
throws DuplicateNameException {
|
||||
// TODO: Exclusive lock?
|
||||
|
@ -235,17 +249,19 @@ public class DBTraceOverlaySpaceAdapter implements DBTraceManager {
|
|||
if (factory.getAddressSpace(name) != null) {
|
||||
throw new DuplicateNameException("Address space " + name + " already exists.");
|
||||
}
|
||||
return doCreateOverlaySpace(name, base);
|
||||
}
|
||||
}
|
||||
|
||||
OverlayAddressSpace space =
|
||||
factory.addOverlayAddressSpace(name, true, base, base.getMinAddress().getOffset(),
|
||||
base.getMaxAddress().getOffset());
|
||||
// Only if it succeeds do we store the record
|
||||
DBTraceOverlaySpaceEntry ent = overlayStore.create();
|
||||
ent.set(space.getName(), base.getName());
|
||||
trace.updateViewsAddSpaceBlock(space);
|
||||
trace.setChanged(new TraceChangeRecord<>(TraceOverlaySpaceChangeType.ADDED, null,
|
||||
trace, null, space));
|
||||
return space;
|
||||
public AddressSpace getOrCreateOverlayAddressSpace(String name, AddressSpace base) {
|
||||
// TODO: Exclusive lock?
|
||||
try (LockHold hold = LockHold.lock(lock.writeLock())) {
|
||||
TraceAddressFactory factory = trace.getInternalAddressFactory();
|
||||
AddressSpace space = factory.getAddressSpace(name);
|
||||
if (space != null) {
|
||||
return space.getPhysicalSpace() == base ? space : null;
|
||||
}
|
||||
return doCreateOverlaySpace(name, base);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ public enum DBTraceObjectRegisterSupport {
|
|||
static class LazyValues {
|
||||
private final TraceObjectValue registerValue;
|
||||
private BigInteger value;
|
||||
private int length = -1;
|
||||
private int bitLength = -1;
|
||||
private byte[] be;
|
||||
private byte[] le;
|
||||
|
||||
|
@ -85,7 +85,11 @@ public enum DBTraceObjectRegisterSupport {
|
|||
"Invalid register value " + s + ". Must be hex digits only.");
|
||||
}
|
||||
}
|
||||
if (val instanceof Byte b) {
|
||||
else if (val instanceof byte[] arr) {
|
||||
// NOTE: Reg object values are always big endian
|
||||
return new BigInteger(1, arr);
|
||||
}
|
||||
else if (val instanceof Byte b) {
|
||||
return BigInteger.valueOf(b);
|
||||
}
|
||||
else if (val instanceof Short s) {
|
||||
|
@ -106,16 +110,16 @@ public enum DBTraceObjectRegisterSupport {
|
|||
"'");
|
||||
}
|
||||
|
||||
int getRegisterValueLength() throws RegisterValueException {
|
||||
Object objLength = registerValue.getParent()
|
||||
.getValue(registerValue.getMinSnap(), TargetRegister.LENGTH_ATTRIBUTE_NAME)
|
||||
int getRegisterValueBitLength() throws RegisterValueException {
|
||||
Object objBitLength = registerValue.getParent()
|
||||
.getValue(registerValue.getMinSnap(), TargetRegister.BIT_LENGTH_ATTRIBUTE_NAME)
|
||||
.getValue();
|
||||
if (!(objLength instanceof Number)) {
|
||||
if (!(objBitLength instanceof Number)) {
|
||||
throw new RegisterValueException(
|
||||
"Register length is not numeric: (" + objLength.getClass() + ") '" + objLength +
|
||||
"'");
|
||||
"Register length is not numeric: (" + objBitLength.getClass() + ") '" +
|
||||
objBitLength + "'");
|
||||
}
|
||||
return ((Number) objLength).intValue();
|
||||
return ((Number) objBitLength).intValue();
|
||||
}
|
||||
|
||||
BigInteger getValue() throws RegisterValueException {
|
||||
|
@ -125,25 +129,29 @@ public enum DBTraceObjectRegisterSupport {
|
|||
return value = convertRegisterValueToBigInteger();
|
||||
}
|
||||
|
||||
int getLength() throws RegisterValueException {
|
||||
if (length != -1) {
|
||||
return length;
|
||||
int getBitLength() throws RegisterValueException {
|
||||
if (bitLength != -1) {
|
||||
return bitLength;
|
||||
}
|
||||
return length = getRegisterValueLength();
|
||||
return bitLength = getRegisterValueBitLength();
|
||||
}
|
||||
|
||||
int getByteLength() throws RegisterValueException {
|
||||
return (getBitLength() + 7) / 8;
|
||||
}
|
||||
|
||||
byte[] getBytesBigEndian() throws RegisterValueException {
|
||||
if (be != null) {
|
||||
return be;
|
||||
}
|
||||
return be = Utils.bigIntegerToBytes(getValue(), getLength(), true);
|
||||
return be = Utils.bigIntegerToBytes(getValue(), getByteLength(), true);
|
||||
}
|
||||
|
||||
byte[] getBytesLittleEndian() throws RegisterValueException {
|
||||
if (le != null) {
|
||||
return le;
|
||||
}
|
||||
return le = Utils.bigIntegerToBytes(getValue(), getLength(), false);
|
||||
return le = Utils.bigIntegerToBytes(getValue(), getByteLength(), false);
|
||||
}
|
||||
|
||||
public byte[] getBytes(boolean isBigEndian) throws RegisterValueException {
|
||||
|
@ -160,14 +168,10 @@ public enum DBTraceObjectRegisterSupport {
|
|||
return null;
|
||||
}
|
||||
String pathStr = container.getCanonicalPath().toString();
|
||||
AddressSpace space = object.getTrace().getBaseAddressFactory().getAddressSpace(pathStr);
|
||||
if (space == null) {
|
||||
return null;
|
||||
}
|
||||
if (!space.isRegisterSpace()) {
|
||||
return null;
|
||||
}
|
||||
return space;
|
||||
Trace trace = object.getTrace();
|
||||
return trace.getMemoryManager()
|
||||
.getOrCreateOverlayAddressSpace(pathStr,
|
||||
trace.getBaseAddressFactory().getRegisterSpace());
|
||||
}
|
||||
|
||||
protected AddressSpace findRegisterOverlay(TraceObjectValue objectValue) {
|
||||
|
|
|
@ -18,6 +18,7 @@ package ghidra.trace.database.guest;
|
|||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.dbg.target.TargetObject;
|
||||
import ghidra.dbg.target.TargetRegister;
|
||||
import ghidra.dbg.target.schema.TargetObjectSchema;
|
||||
import ghidra.dbg.util.PathMatcher;
|
||||
|
@ -30,6 +31,7 @@ import ghidra.program.model.symbol.SourceType;
|
|||
import ghidra.trace.database.guest.DBTraceGuestPlatform.DBTraceGuestLanguage;
|
||||
import ghidra.trace.model.guest.TracePlatform;
|
||||
import ghidra.trace.model.symbol.*;
|
||||
import ghidra.trace.model.target.TraceObject;
|
||||
import ghidra.trace.util.TraceRegisterUtils;
|
||||
import ghidra.util.LockHold;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
@ -78,6 +80,48 @@ public interface InternalTracePlatform extends TracePlatform {
|
|||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
default String getConventionalRegisterObjectName(Register register) {
|
||||
Address pmin = mapGuestToHost(register.getAddress());
|
||||
if (pmin == null) {
|
||||
return register.getName();
|
||||
}
|
||||
TraceSymbolManager symbolManager = getTrace().getSymbolManager();
|
||||
TraceNamespaceSymbol nsRegMap = symbolManager.namespaces().getGlobalNamed(regMap(register));
|
||||
Collection<? extends TraceLabelSymbol> labels = symbolManager.labels()
|
||||
.getAt(0, null, pmin, false)
|
||||
.stream()
|
||||
.filter(s -> s.getParentNamespace() == nsRegMap)
|
||||
.toList();
|
||||
if (labels.isEmpty()) {
|
||||
return register.getName();
|
||||
}
|
||||
// primary is listed first, so take it
|
||||
return labels.iterator().next().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
default PathMatcher getConventionalRegisterPath(TargetObjectSchema schema, List<String> path,
|
||||
Register register) {
|
||||
PathMatcher matcher = schema.searchFor(TargetRegister.class, path, true);
|
||||
if (matcher.isEmpty()) {
|
||||
return matcher;
|
||||
}
|
||||
String name = getConventionalRegisterObjectName(register);
|
||||
return matcher.applyKeys(Align.RIGHT, List.of(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
default PathMatcher getConventionalRegisterPath(TraceObject container, Register register) {
|
||||
return getConventionalRegisterPath(container.getTargetSchema(),
|
||||
container.getCanonicalPath().getKeyList(), register);
|
||||
}
|
||||
|
||||
@Override
|
||||
default PathMatcher getConventionalRegisterPath(TargetObject container, Register register) {
|
||||
return getConventionalRegisterPath(container.getSchema(), container.getPath(), register);
|
||||
}
|
||||
|
||||
@Override
|
||||
default PathMatcher getConventionalRegisterPath(AddressSpace space, Register register) {
|
||||
List<String> path = PathUtils.parse(space.getName());
|
||||
|
@ -87,20 +131,7 @@ public interface InternalTracePlatform extends TracePlatform {
|
|||
}
|
||||
TargetObjectSchema schema = rootSchema
|
||||
.getSuccessorSchema(path);
|
||||
PathMatcher matcher = schema.searchFor(TargetRegister.class, path, true);
|
||||
if (matcher.isEmpty()) {
|
||||
return matcher;
|
||||
}
|
||||
Address pmin = mapGuestToHost(register.getAddress());
|
||||
TraceSymbolManager symbolManager = getTrace().getSymbolManager();
|
||||
TraceNamespaceSymbol nsRegMap = symbolManager.namespaces().getGlobalNamed(regMap(register));
|
||||
Collection<? extends TraceLabelSymbol> labels = symbolManager.labels()
|
||||
.getAt(0, null, pmin, false)
|
||||
.stream()
|
||||
.filter(s -> s.getParentNamespace() == nsRegMap)
|
||||
.toList();
|
||||
String name = labels.isEmpty() ? register.getName() : labels.iterator().next().getName();
|
||||
return matcher.applyKeys(Align.RIGHT, List.of(name));
|
||||
return getConventionalRegisterPath(schema, path, register);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -55,6 +55,10 @@ public abstract class AbstractBaseDBTraceCodeUnitsMemoryView<T extends DBTraceCo
|
|||
Collections2.transform(manager.getActiveMemorySpaces(), this::getView);
|
||||
}
|
||||
|
||||
public AddressSpace getSpace() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see TraceBaseCodeUnitsView#getTrace()
|
||||
*/
|
||||
|
|
|
@ -47,6 +47,10 @@ public abstract class AbstractBaseDBTraceCodeUnitsView<T extends DBTraceCodeUnit
|
|||
this.space = space;
|
||||
}
|
||||
|
||||
public AddressSpace getSpace() {
|
||||
return getAddressSpace();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the address space for this view
|
||||
*
|
||||
|
|
|
@ -16,15 +16,14 @@
|
|||
package ghidra.trace.database.listing;
|
||||
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.trace.model.listing.TraceCodeManager;
|
||||
import ghidra.trace.model.listing.TraceCodeUnitsView;
|
||||
import ghidra.trace.model.listing.*;
|
||||
|
||||
/**
|
||||
* The implementation of {@link TraceCodeManager#codeUnits()}
|
||||
*/
|
||||
public class DBTraceCodeUnitsMemoryView extends
|
||||
AbstractWithUndefinedDBTraceCodeUnitsMemoryView<DBTraceCodeUnitAdapter, DBTraceCodeUnitsView>
|
||||
implements TraceCodeUnitsView {
|
||||
implements TraceCodeUnitsView, InternalBaseCodeUnitsView<TraceCodeUnit> {
|
||||
|
||||
/**
|
||||
* Construct the view
|
||||
|
|
|
@ -20,15 +20,14 @@ import java.util.List;
|
|||
import com.google.common.collect.Range;
|
||||
|
||||
import ghidra.program.model.address.AddressRange;
|
||||
import ghidra.trace.model.listing.TraceCodeSpace;
|
||||
import ghidra.trace.model.listing.TraceCodeUnitsView;
|
||||
import ghidra.trace.model.listing.*;
|
||||
|
||||
/**
|
||||
* The implementation of {@link TraceCodeSpace#codeUnits()}
|
||||
*/
|
||||
public class DBTraceCodeUnitsView extends
|
||||
AbstractComposedDBTraceCodeUnitsView<DBTraceCodeUnitAdapter, AbstractSingleDBTraceCodeUnitsView<? extends DBTraceCodeUnitAdapter>>
|
||||
implements TraceCodeUnitsView {
|
||||
implements TraceCodeUnitsView, InternalBaseCodeUnitsView<TraceCodeUnit> {
|
||||
|
||||
/**
|
||||
* Construct the view
|
||||
|
|
|
@ -15,15 +15,14 @@
|
|||
*/
|
||||
package ghidra.trace.database.listing;
|
||||
|
||||
import ghidra.trace.model.listing.TraceCodeManager;
|
||||
import ghidra.trace.model.listing.TraceDataView;
|
||||
import ghidra.trace.model.listing.*;
|
||||
|
||||
/**
|
||||
* The implementation of {@link TraceCodeManager#data()}
|
||||
*/
|
||||
public class DBTraceDataMemoryView
|
||||
extends AbstractWithUndefinedDBTraceCodeUnitsMemoryView<DBTraceDataAdapter, DBTraceDataView>
|
||||
implements TraceDataView {
|
||||
implements TraceDataView, InternalBaseCodeUnitsView<TraceData> {
|
||||
|
||||
/**
|
||||
* Construct the view
|
||||
|
|
|
@ -20,15 +20,14 @@ import java.util.List;
|
|||
import com.google.common.collect.Range;
|
||||
|
||||
import ghidra.program.model.address.AddressRange;
|
||||
import ghidra.trace.model.listing.TraceCodeSpace;
|
||||
import ghidra.trace.model.listing.TraceDataView;
|
||||
import ghidra.trace.model.listing.*;
|
||||
|
||||
/**
|
||||
* The implementation of {@link TraceCodeSpace#data()}
|
||||
*/
|
||||
public class DBTraceDataView extends
|
||||
AbstractComposedDBTraceCodeUnitsView<DBTraceDataAdapter, AbstractSingleDBTraceCodeUnitsView<? extends DBTraceDataAdapter>>
|
||||
implements TraceDataView {
|
||||
implements TraceDataView, InternalBaseCodeUnitsView<TraceData> {
|
||||
|
||||
/**
|
||||
* Construct the view
|
||||
|
|
|
@ -17,12 +17,10 @@ package ghidra.trace.database.listing;
|
|||
|
||||
import com.google.common.collect.Range;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressRange;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||
import ghidra.trace.model.listing.TraceCodeManager;
|
||||
import ghidra.trace.model.listing.TraceDefinedDataView;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
|
@ -31,7 +29,7 @@ import ghidra.util.task.TaskMonitor;
|
|||
*/
|
||||
public class DBTraceDefinedDataMemoryView
|
||||
extends AbstractBaseDBTraceCodeUnitsMemoryView<DBTraceData, DBTraceDefinedDataView>
|
||||
implements TraceDefinedDataView {
|
||||
implements InternalTraceDefinedDataView {
|
||||
|
||||
/**
|
||||
* Construct the view
|
||||
|
|
|
@ -28,7 +28,6 @@ import ghidra.trace.model.Trace.TraceCodeChangeType;
|
|||
import ghidra.trace.model.Trace.TraceCompositeDataChangeType;
|
||||
import ghidra.trace.model.TraceAddressSnapRange;
|
||||
import ghidra.trace.model.listing.TraceCodeSpace;
|
||||
import ghidra.trace.model.listing.TraceDefinedDataView;
|
||||
import ghidra.trace.util.TraceChangeRecord;
|
||||
import ghidra.util.LockHold;
|
||||
|
||||
|
@ -36,7 +35,7 @@ import ghidra.util.LockHold;
|
|||
* The implementation of {@link TraceCodeSpace#definedData()}
|
||||
*/
|
||||
public class DBTraceDefinedDataView extends AbstractBaseDBTraceDefinedUnitsView<DBTraceData>
|
||||
implements TraceDefinedDataView {
|
||||
implements InternalTraceDefinedDataView {
|
||||
/**
|
||||
* Construct the view
|
||||
*
|
||||
|
|
|
@ -18,8 +18,7 @@ package ghidra.trace.database.listing;
|
|||
import com.google.common.collect.Range;
|
||||
|
||||
import ghidra.program.model.address.AddressRange;
|
||||
import ghidra.trace.model.listing.TraceCodeManager;
|
||||
import ghidra.trace.model.listing.TraceDefinedUnitsView;
|
||||
import ghidra.trace.model.listing.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
|
@ -28,7 +27,7 @@ import ghidra.util.task.TaskMonitor;
|
|||
*/
|
||||
public class DBTraceDefinedUnitsMemoryView extends
|
||||
AbstractBaseDBTraceCodeUnitsMemoryView<AbstractDBTraceCodeUnit<?>, DBTraceDefinedUnitsView>
|
||||
implements TraceDefinedUnitsView {
|
||||
implements TraceDefinedUnitsView, InternalTraceBaseDefinedUnitsView<TraceCodeUnit> {
|
||||
|
||||
/**
|
||||
* Construct the view
|
||||
|
|
|
@ -22,8 +22,7 @@ import com.google.common.collect.Range;
|
|||
import ghidra.program.model.address.AddressRange;
|
||||
import ghidra.trace.model.ImmutableTraceAddressSnapRange;
|
||||
import ghidra.trace.model.TraceAddressSnapRange;
|
||||
import ghidra.trace.model.listing.TraceCodeSpace;
|
||||
import ghidra.trace.model.listing.TraceDefinedUnitsView;
|
||||
import ghidra.trace.model.listing.*;
|
||||
import ghidra.util.LockHold;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
@ -33,7 +32,7 @@ import ghidra.util.task.TaskMonitor;
|
|||
*/
|
||||
public class DBTraceDefinedUnitsView extends
|
||||
AbstractComposedDBTraceCodeUnitsView<AbstractDBTraceCodeUnit<?>, AbstractBaseDBTraceDefinedUnitsView<? extends AbstractDBTraceCodeUnit<?>>>
|
||||
implements TraceDefinedUnitsView {
|
||||
implements TraceDefinedUnitsView, InternalTraceBaseDefinedUnitsView<TraceCodeUnit> {
|
||||
|
||||
/**
|
||||
* Construct the view
|
||||
|
|
|
@ -25,8 +25,7 @@ import ghidra.program.model.address.*;
|
|||
import ghidra.program.model.lang.*;
|
||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||
import ghidra.trace.model.guest.TracePlatform;
|
||||
import ghidra.trace.model.listing.TraceCodeManager;
|
||||
import ghidra.trace.model.listing.TraceInstructionsView;
|
||||
import ghidra.trace.model.listing.*;
|
||||
import ghidra.util.LockHold;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
@ -36,7 +35,7 @@ import ghidra.util.task.TaskMonitor;
|
|||
*/
|
||||
public class DBTraceInstructionsMemoryView
|
||||
extends AbstractBaseDBTraceCodeUnitsMemoryView<DBTraceInstruction, DBTraceInstructionsView>
|
||||
implements TraceInstructionsView {
|
||||
implements TraceInstructionsView, InternalTraceBaseDefinedUnitsView<TraceInstruction> {
|
||||
|
||||
/**
|
||||
* Construct the view
|
||||
|
|
|
@ -46,7 +46,7 @@ import ghidra.util.task.TaskMonitor;
|
|||
* The implementation of {@link TraceCodeSpace#instructions()}
|
||||
*/
|
||||
public class DBTraceInstructionsView extends AbstractBaseDBTraceDefinedUnitsView<DBTraceInstruction>
|
||||
implements TraceInstructionsView {
|
||||
implements TraceInstructionsView, InternalTraceBaseDefinedUnitsView<TraceInstruction> {
|
||||
|
||||
protected static <T> T replaceIfNotNull(T cur, T rep) {
|
||||
return rep != null ? rep : cur;
|
||||
|
|
|
@ -15,15 +15,14 @@
|
|||
*/
|
||||
package ghidra.trace.database.listing;
|
||||
|
||||
import ghidra.trace.model.listing.TraceCodeManager;
|
||||
import ghidra.trace.model.listing.TraceUndefinedDataView;
|
||||
import ghidra.trace.model.listing.*;
|
||||
|
||||
/**
|
||||
* The implementation of {@link TraceCodeManager#undefinedData()}
|
||||
*/
|
||||
public class DBTraceUndefinedDataMemoryView extends
|
||||
AbstractWithUndefinedDBTraceCodeUnitsMemoryView<UndefinedDBTraceData, DBTraceUndefinedDataView>
|
||||
implements TraceUndefinedDataView {
|
||||
implements TraceUndefinedDataView, InternalBaseCodeUnitsView<TraceData> {
|
||||
|
||||
/**
|
||||
* Construct the view
|
||||
|
|
|
@ -26,15 +26,15 @@ import com.google.common.collect.Range;
|
|||
import ghidra.program.model.address.*;
|
||||
import ghidra.trace.database.DBTraceUtils;
|
||||
import ghidra.trace.model.TraceAddressSnapRange;
|
||||
import ghidra.trace.model.listing.TraceCodeSpace;
|
||||
import ghidra.trace.model.listing.TraceUndefinedDataView;
|
||||
import ghidra.trace.model.listing.*;
|
||||
import ghidra.util.*;
|
||||
|
||||
/**
|
||||
* The implementation of {@link TraceCodeSpace#undefinedData()}
|
||||
*/
|
||||
public class DBTraceUndefinedDataView extends
|
||||
AbstractSingleDBTraceCodeUnitsView<UndefinedDBTraceData> implements TraceUndefinedDataView {
|
||||
AbstractSingleDBTraceCodeUnitsView<UndefinedDBTraceData>
|
||||
implements TraceUndefinedDataView, InternalBaseCodeUnitsView<TraceData> {
|
||||
|
||||
protected final static int CACHE_MAX_SNAPS = 5;
|
||||
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/* ###
|
||||
* 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.trace.database.listing;
|
||||
|
||||
import ghidra.program.model.address.AddressRange;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.trace.model.guest.TracePlatform;
|
||||
import ghidra.trace.model.listing.*;
|
||||
import ghidra.trace.util.TraceRegisterUtils;
|
||||
|
||||
public interface InternalBaseCodeUnitsView<T extends TraceCodeUnit>
|
||||
extends TraceBaseCodeUnitsView<T> {
|
||||
AddressSpace getSpace();
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
default T getForRegister(TracePlatform platform, long snap, Register register) {
|
||||
// Find a code unit which contains the register completely
|
||||
AddressRange range = platform.getConventionalRegisterRange(getSpace(), register);
|
||||
T candidate = getContaining(snap, range.getMinAddress());
|
||||
if (candidate == null) {
|
||||
return null;
|
||||
}
|
||||
int cmpMax = range.getMaxAddress().compareTo(candidate.getMaxAddress());
|
||||
if (cmpMax > 0) {
|
||||
return null;
|
||||
}
|
||||
if (cmpMax == 0 && candidate.getMinAddress().equals(range.getMinAddress())) {
|
||||
return candidate;
|
||||
}
|
||||
if (!(candidate instanceof TraceData)) {
|
||||
return null;
|
||||
}
|
||||
TraceData data = (TraceData) candidate;
|
||||
// Cast because if candidate is TraceData, T is, too
|
||||
// NOTE: It may not be a primitive
|
||||
return (T) TraceRegisterUtils.seekComponent(data, range);
|
||||
}
|
||||
|
||||
@Override
|
||||
default T getContaining(TracePlatform platform, long snap, Register register) {
|
||||
AddressRange range = platform.getConventionalRegisterRange(getSpace(), register);
|
||||
T candidate = getContaining(snap, range.getMinAddress());
|
||||
if (candidate == null) {
|
||||
return null;
|
||||
}
|
||||
int cmpMax = range.getMaxAddress().compareTo(candidate.getMaxAddress());
|
||||
if (cmpMax > 0) {
|
||||
return null;
|
||||
}
|
||||
return candidate;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/* ###
|
||||
* 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.trace.database.listing;
|
||||
|
||||
import com.google.common.collect.Range;
|
||||
|
||||
import ghidra.program.model.address.AddressRange;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.trace.model.guest.TracePlatform;
|
||||
import ghidra.trace.model.listing.TraceBaseDefinedUnitsView;
|
||||
import ghidra.trace.model.listing.TraceCodeUnit;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public interface InternalTraceBaseDefinedUnitsView<T extends TraceCodeUnit>
|
||||
extends TraceBaseDefinedUnitsView<T>, InternalBaseCodeUnitsView<T> {
|
||||
|
||||
@Override
|
||||
default void clear(TracePlatform platform, Range<Long> span, Register register,
|
||||
TaskMonitor monitor) throws CancelledException {
|
||||
AddressRange range = platform.getConventionalRegisterRange(getSpace(), register);
|
||||
clear(span, range, true, monitor);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/* ###
|
||||
* 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.trace.database.listing;
|
||||
|
||||
import com.google.common.collect.Range;
|
||||
|
||||
import ghidra.program.model.address.AddressRange;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||
import ghidra.trace.model.guest.TracePlatform;
|
||||
import ghidra.trace.model.listing.TraceData;
|
||||
import ghidra.trace.model.listing.TraceDefinedDataView;
|
||||
import ghidra.trace.util.TraceRegisterUtils;
|
||||
|
||||
public interface InternalTraceDefinedDataView
|
||||
extends TraceDefinedDataView, InternalTraceBaseDefinedUnitsView<TraceData> {
|
||||
|
||||
@Override
|
||||
default TraceData create(TracePlatform platform, Range<Long> lifespan, Register register,
|
||||
DataType dataType) throws CodeUnitInsertionException {
|
||||
TraceRegisterUtils.requireByteBound(register);
|
||||
AddressRange range = platform.getConventionalRegisterRange(getSpace(), register);
|
||||
return create(lifespan, range.getMinAddress(), dataType, (int) range.getLength());
|
||||
}
|
||||
}
|
|
@ -77,6 +77,11 @@ public class DBTraceMemoryManager extends AbstractDBTraceSpaceBasedManager<DBTra
|
|||
return overlayAdapter.createOverlayAddressSpace(name, base);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddressSpace getOrCreateOverlayAddressSpace(String name, AddressSpace base) {
|
||||
return overlayAdapter.getOrCreateOverlayAddressSpace(name, base);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteOverlayAddressSpace(String name) {
|
||||
overlayAdapter.deleteOverlayAddressSpace(name);
|
||||
|
|
|
@ -60,14 +60,14 @@ public class DBTraceObjectRegister implements TraceObjectRegister, DBTraceObject
|
|||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
public int getBitLength() {
|
||||
return TraceObjectInterfaceUtils.getValue(object, computeMinSnap(),
|
||||
TargetRegister.LENGTH_ATTRIBUTE_NAME, Integer.class, 0);
|
||||
TargetRegister.BIT_LENGTH_ATTRIBUTE_NAME, Integer.class, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(Range<Long> lifespan, byte[] value) {
|
||||
int length = getLength();
|
||||
int length = getByteLength();
|
||||
if (length != 0 && value.length != length) {
|
||||
throw new IllegalArgumentException("Length must match the register");
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ public class DBTraceObjectRegister implements TraceObjectRegister, DBTraceObject
|
|||
if (val instanceof String) {
|
||||
// Always base 16. Model API says byte array for register value is big endian.
|
||||
BigInteger bigVal = new BigInteger((String) val, 16);
|
||||
return Utils.bigIntegerToBytes(bigVal, getLength(), true);
|
||||
return Utils.bigIntegerToBytes(bigVal, getByteLength(), true);
|
||||
}
|
||||
throw new ClassCastException("Cannot convert " + val + " to byte array for register value");
|
||||
}
|
||||
|
|
|
@ -26,8 +26,6 @@ import db.DBHandle;
|
|||
import db.DBRecord;
|
||||
import generic.CatenatedCollection;
|
||||
import ghidra.dbg.target.TargetRegisterContainer;
|
||||
import ghidra.dbg.util.PathPattern;
|
||||
import ghidra.dbg.util.PathPredicates;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.lang.Language;
|
||||
import ghidra.trace.database.*;
|
||||
|
@ -35,7 +33,6 @@ import ghidra.trace.database.thread.DBTraceThreadManager;
|
|||
import ghidra.trace.model.stack.TraceObjectStackFrame;
|
||||
import ghidra.trace.model.stack.TraceStackFrame;
|
||||
import ghidra.trace.model.target.TraceObject;
|
||||
import ghidra.trace.model.target.TraceObjectKeyPath;
|
||||
import ghidra.trace.model.thread.TraceObjectThread;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.trace.util.TraceAddressSpace;
|
||||
|
@ -247,22 +244,6 @@ public abstract class AbstractDBTraceSpaceBasedManager<M extends DBTraceSpaceBas
|
|||
return getForRegisterSpace(frame.getStack().getThread(), frame.getLevel(), createIfAbsent);
|
||||
}
|
||||
|
||||
private TraceObject searchForRegisterContainer(TraceObject object, int frameLevel) {
|
||||
PathPredicates regsMatcher = object.getRoot()
|
||||
.getTargetSchema()
|
||||
.searchForRegisterContainer(frameLevel, object.getCanonicalPath().getKeyList());
|
||||
|
||||
for (PathPattern regsPattern : regsMatcher.getPatterns()) {
|
||||
TraceObject regsObj = trace.getObjectManager()
|
||||
.getObjectByCanonicalPath(
|
||||
TraceObjectKeyPath.of(regsPattern.getSingletonPath()));
|
||||
if (regsObj != null) {
|
||||
return regsObj;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private M doGetForRegisterSpaceFoundContainer(TraceObject object, TraceObject objRegs,
|
||||
boolean createIfAbsent) {
|
||||
String name = objRegs.getCanonicalPath().toString();
|
||||
|
@ -284,21 +265,15 @@ public abstract class AbstractDBTraceSpaceBasedManager<M extends DBTraceSpaceBas
|
|||
}
|
||||
}
|
||||
try (LockHold hold = LockHold.lock(lock.writeLock())) {
|
||||
AddressSpace as = trace.getBaseAddressFactory().getAddressSpace(name);
|
||||
if (as == null) {
|
||||
as = trace.getMemoryManager()
|
||||
.createOverlayAddressSpace(name,
|
||||
trace.getBaseAddressFactory().getRegisterSpace());
|
||||
}
|
||||
AddressSpace as = trace.getMemoryManager()
|
||||
.getOrCreateOverlayAddressSpace(name,
|
||||
trace.getBaseAddressFactory().getRegisterSpace());
|
||||
M space = getForSpace(as, createIfAbsent);
|
||||
synchronized (regSpacesByObject) {
|
||||
regSpacesByObject.put(object, space);
|
||||
}
|
||||
return space;
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
throw new AssertionError(e); // I checked for it first, with a lock
|
||||
}
|
||||
}
|
||||
|
||||
protected M getForRegisterSpaceObjectThread(TraceObjectThread thread, int frameLevel,
|
||||
|
@ -319,7 +294,7 @@ public abstract class AbstractDBTraceSpaceBasedManager<M extends DBTraceSpaceBas
|
|||
if (object.getTargetSchema().getInterfaces().contains(TargetRegisterContainer.class)) {
|
||||
return doGetForRegisterSpaceFoundContainer(object, object, createIfAbsent);
|
||||
}
|
||||
TraceObject objRegs = searchForRegisterContainer(object, frameLevel);
|
||||
TraceObject objRegs = object.queryRegisterContainer(frameLevel);
|
||||
if (objRegs != null) {
|
||||
return doGetForRegisterSpaceFoundContainer(object, objRegs, createIfAbsent);
|
||||
}
|
||||
|
|
|
@ -36,10 +36,18 @@ public interface DBTraceSpaceBased extends DBTraceSpaceKey {
|
|||
return false;
|
||||
}
|
||||
|
||||
default String explainLanguages(AddressSpace space) {
|
||||
if (space.getName().equals(getAddressSpace().getName())) {
|
||||
return ". It's likely they come from different languages. Check the platform.";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
default long assertInSpace(Address addr) {
|
||||
if (!isMySpace(addr.getAddressSpace())) {
|
||||
throw new IllegalArgumentException(
|
||||
"Address '" + addr + "' is not in this space: '" + getAddressSpace() + "'");
|
||||
"Address '" + addr + "' is not in this space: '" + getAddressSpace() + "'" +
|
||||
explainLanguages(addr.getAddressSpace()));
|
||||
}
|
||||
return addr.getOffset();
|
||||
}
|
||||
|
@ -47,7 +55,8 @@ public interface DBTraceSpaceBased extends DBTraceSpaceKey {
|
|||
default void assertInSpace(AddressRange range) {
|
||||
if (!isMySpace(range.getAddressSpace())) {
|
||||
throw new IllegalArgumentException(
|
||||
"Address Range '" + range + "' is not in this space: '" + getAddressSpace() + "'");
|
||||
"Address Range '" + range + "' is not in this space: '" + getAddressSpace() + "'" +
|
||||
explainLanguages(range.getAddressSpace()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -859,13 +859,25 @@ public class DBTraceObject extends DBAnnotatedObject implements TraceObject {
|
|||
.map(o -> o.queryInterface(ifClass));
|
||||
}
|
||||
|
||||
// TODO: Post filter until GP-1301
|
||||
private boolean isActuallyInterface(TraceObjectValPath path,
|
||||
Class<? extends TargetObject> targetIf) {
|
||||
TraceObjectValue lastEntry = path.getLastEntry();
|
||||
if (lastEntry == null) {
|
||||
// TODO: This assumes the client will call getDestination(this)
|
||||
return this.getTargetSchema().getInterfaces().contains(targetIf);
|
||||
}
|
||||
if (!lastEntry.isObject()) {
|
||||
return false;
|
||||
}
|
||||
return lastEntry.getChild().getTargetSchema().getInterfaces().contains(targetIf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<? extends TraceObjectValPath> querySuccessorsTargetInterface(Range<Long> span,
|
||||
Class<? extends TargetObject> targetIf) {
|
||||
PathMatcher matcher = getTargetSchema().searchFor(targetIf, true);
|
||||
// TODO: Post filter until GP-1301
|
||||
return getSuccessors(span, matcher).filter(
|
||||
p -> p.getDestination(this).getTargetSchema().getInterfaces().contains(targetIf));
|
||||
return getSuccessors(span, matcher).filter(p -> isActuallyInterface(p, targetIf));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -15,13 +15,18 @@
|
|||
*/
|
||||
package ghidra.trace.model.guest;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.dbg.target.TargetObject;
|
||||
import ghidra.dbg.target.TargetRegister;
|
||||
import ghidra.dbg.target.schema.TargetObjectSchema;
|
||||
import ghidra.dbg.util.PathMatcher;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.lang.*;
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.symbol.TraceLabelSymbol;
|
||||
import ghidra.trace.model.target.TraceObject;
|
||||
|
||||
/**
|
||||
* A platform within a trace
|
||||
|
@ -119,7 +124,7 @@ public interface TracePlatform {
|
|||
* Translate a set from host to guest
|
||||
*
|
||||
* <p>
|
||||
* Only those ranges (or parts of ranges) that map are included.
|
||||
* Only those ranges (or parts of ranges) that mapped are included.
|
||||
*
|
||||
* @param hostSet the host set
|
||||
* @return the guest set
|
||||
|
@ -149,7 +154,7 @@ public interface TracePlatform {
|
|||
* Translate a set from guest to host
|
||||
*
|
||||
* <p>
|
||||
* Only those ranges (or parts of ranges) that map are included.
|
||||
* Only those ranges (or parts of ranges) that mapped are included.
|
||||
*
|
||||
* @param guestSet the guest set
|
||||
* @return the host set
|
||||
|
@ -165,13 +170,57 @@ public interface TracePlatform {
|
|||
*/
|
||||
AddressRange getConventionalRegisterRange(AddressSpace overlay, Register register);
|
||||
|
||||
/**
|
||||
* Get the name or index of the register object for the given platform register
|
||||
*
|
||||
* <p>
|
||||
* This will check for a label in the host physical space, allowing a mapper to specify an
|
||||
* alternative register object name. See {@link #addRegisterMapOverride(Register, String)}.
|
||||
*
|
||||
* @param register the platform register
|
||||
* @return the mapped name
|
||||
*/
|
||||
String getConventionalRegisterObjectName(Register register);
|
||||
|
||||
/**
|
||||
* Get the expected path where an object defining the register value would be
|
||||
*
|
||||
* <p>
|
||||
* This will check for a label in the host physical space, allowing a mapper to specify an
|
||||
* alternative register name.
|
||||
* alternative register object name. See {@link #addRegisterMapOverride(Register, String)}.
|
||||
*
|
||||
* @param schema the schema of the register container
|
||||
* @param path the path to the register container
|
||||
* @param register the platform register
|
||||
* @return the path matcher, possibly empty
|
||||
*/
|
||||
PathMatcher getConventionalRegisterPath(TargetObjectSchema schema, List<String> path,
|
||||
Register register);
|
||||
|
||||
/**
|
||||
* Get the expected path where an object defining the register value would be
|
||||
*
|
||||
* @see #getConventionalRegisterPath(TargetObjectSchema, List, Register)
|
||||
* @param container the register container
|
||||
* @param register the platform register
|
||||
* @return that path matcher, possibly empty, or null if the trace has no root schema
|
||||
*/
|
||||
PathMatcher getConventionalRegisterPath(TraceObject container, Register register);
|
||||
|
||||
/**
|
||||
* Get the expected path where an object defining the register value would be
|
||||
*
|
||||
* @see #getConventionalRegisterPath(TargetObjectSchema, List, Register)
|
||||
* @param container the target register container
|
||||
* @param register the platform register
|
||||
* @return the path matcher, possibly empty
|
||||
*/
|
||||
PathMatcher getConventionalRegisterPath(TargetObject container, Register register);
|
||||
|
||||
/**
|
||||
* Get the expected path where an object defining the register value would be
|
||||
*
|
||||
* @see #getConventionalRegisterPath(TargetObjectSchema, List, Register)
|
||||
* @param overlay the overlay space allocated for a thread or frame
|
||||
* @param register the platform register
|
||||
* @return the path matcher, or null if there is no root schema
|
||||
|
|
|
@ -15,15 +15,13 @@
|
|||
*/
|
||||
package ghidra.trace.model.listing;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.collect.Range;
|
||||
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.TraceAddressSnapRange;
|
||||
import ghidra.trace.model.guest.TracePlatform;
|
||||
import ghidra.trace.util.TraceRegisterUtils;
|
||||
import ghidra.util.IntersectionAddressSetView;
|
||||
import ghidra.util.UnionAddressSetView;
|
||||
|
@ -251,15 +249,6 @@ public interface TraceBaseCodeUnitsView<T extends TraceCodeUnit> {
|
|||
*/
|
||||
boolean intersectsRange(TraceAddressSnapRange range);
|
||||
|
||||
/**
|
||||
* Get the set of registers for the trace's base language
|
||||
*
|
||||
* @return the register set
|
||||
*/
|
||||
default Set<Register> getRegisters() {
|
||||
return new HashSet<>(getTrace().getBaseLanguage().getRegisters());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the unit (or component of a structure) which spans exactly the addresses of the given
|
||||
* register
|
||||
|
@ -267,28 +256,32 @@ public interface TraceBaseCodeUnitsView<T extends TraceCodeUnit> {
|
|||
* @param register the register
|
||||
* @return the unit or {@code null}
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
default T getForRegister(long snap, Register register) {
|
||||
// Find a code unit which contains the register completely
|
||||
T candidate = getContaining(snap, register.getAddress());
|
||||
if (candidate == null) {
|
||||
return null;
|
||||
}
|
||||
AddressRange range = TraceRegisterUtils.rangeForRegister(register);
|
||||
int cmpMax = range.getMaxAddress().compareTo(candidate.getMaxAddress());
|
||||
if (cmpMax > 0) {
|
||||
return null;
|
||||
}
|
||||
if (cmpMax == 0 && candidate.getMinAddress().equals(register.getAddress())) {
|
||||
return candidate;
|
||||
}
|
||||
if (!(candidate instanceof TraceData)) {
|
||||
return null;
|
||||
}
|
||||
TraceData data = (TraceData) candidate;
|
||||
// Cast because if candidate is TraceData, T is, too
|
||||
// NOTE: It may not be a primitive
|
||||
return (T) TraceRegisterUtils.seekComponent(data, range);
|
||||
return getForRegister(getTrace().getPlatformManager().getHostPlatform(), snap, register);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the unit (or component of a structure) which spans exactly the addresses of the given
|
||||
* platform register
|
||||
*
|
||||
* @param platform the platform whose language defines the register
|
||||
* @param register the register
|
||||
* @return the unit or {@code null}
|
||||
*/
|
||||
T getForRegister(TracePlatform platform, long snap, Register register);
|
||||
|
||||
/**
|
||||
* Get the unit which completely contains the given register
|
||||
*
|
||||
* <p>
|
||||
* This does not descend into structures.
|
||||
*
|
||||
* @param snap the snap during which the unit must be alive
|
||||
* @param register the register
|
||||
* @return the unit or {@code unit}
|
||||
*/
|
||||
default T getContaining(long snap, Register register) {
|
||||
return getContaining(getTrace().getPlatformManager().getHostPlatform(), snap, register);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -297,21 +290,12 @@ public interface TraceBaseCodeUnitsView<T extends TraceCodeUnit> {
|
|||
* <p>
|
||||
* This does not descend into structures.
|
||||
*
|
||||
* @platform the platform whose language defines the register
|
||||
* @param snap the snap during which the unit must be alive
|
||||
* @param register the register
|
||||
* @return the unit or {@code unit}
|
||||
*/
|
||||
default T getContaining(long snap, Register register) {
|
||||
T candidate = getContaining(snap, register.getAddress());
|
||||
if (candidate == null) {
|
||||
return null;
|
||||
}
|
||||
AddressRange range = TraceRegisterUtils.rangeForRegister(register);
|
||||
int cmpMax = range.getMaxAddress().compareTo(candidate.getMaxAddress());
|
||||
if (cmpMax > 0) {
|
||||
return null;
|
||||
}
|
||||
return candidate;
|
||||
}
|
||||
T getContaining(TracePlatform platform, long snap, Register register);
|
||||
|
||||
/**
|
||||
* Get the live units whose start addresses are within the given register
|
||||
|
|
|
@ -19,6 +19,7 @@ import com.google.common.collect.Range;
|
|||
|
||||
import ghidra.program.model.address.AddressRange;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.trace.model.guest.TracePlatform;
|
||||
import ghidra.trace.util.TraceRegisterUtils;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
@ -64,4 +65,19 @@ public interface TraceBaseDefinedUnitsView<T extends TraceCodeUnit>
|
|||
throws CancelledException {
|
||||
clear(span, TraceRegisterUtils.rangeForRegister(register), true, monitor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the units contained within the given span and platform register
|
||||
*
|
||||
* <p>
|
||||
* Any units alive before the given span are truncated instead of deleted.
|
||||
*
|
||||
* @param platform the platform whose language defines the register
|
||||
* @param span the span to clear
|
||||
* @param register the register
|
||||
* @param monitor a monitor for progress and cancellation
|
||||
* @throws CancelledException if the clear is cancelled
|
||||
*/
|
||||
void clear(TracePlatform platform, Range<Long> span, Register register, TaskMonitor monitor)
|
||||
throws CancelledException;
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ import ghidra.program.model.address.Address;
|
|||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.guest.TracePlatform;
|
||||
import ghidra.trace.util.TraceRegisterUtils;
|
||||
|
||||
/**
|
||||
|
@ -75,17 +75,24 @@ public interface TraceDefinedDataView extends TraceBaseDefinedUnitsView<TraceDat
|
|||
*/
|
||||
default TraceData create(Range<Long> lifespan, Register register, DataType dataType)
|
||||
throws CodeUnitInsertionException {
|
||||
// TODO: A better way to handle memory-mapped registers?
|
||||
Trace trace = getTrace();
|
||||
if (register.getAddressSpace() != trace
|
||||
.getBaseLanguage()
|
||||
.getAddressFactory()
|
||||
.getRegisterSpace()) {
|
||||
return trace.getCodeManager()
|
||||
.definedData()
|
||||
.create(lifespan, register.getAddress(), dataType, register.getNumBytes());
|
||||
}
|
||||
TraceRegisterUtils.requireByteBound(register);
|
||||
return create(lifespan, register.getAddress(), dataType, register.getNumBytes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a data unit on the given platform register
|
||||
*
|
||||
* <p>
|
||||
* If the register is memory mapped, this will delegate to the appropriate space. In those
|
||||
* cases, the assignment affects all threads.
|
||||
*
|
||||
* @param platform the platform whose language defines the register
|
||||
* @param lifespan the span for which the unit is effective
|
||||
* @param register the register to assign a data type
|
||||
* @param dataType the data type for the register
|
||||
* @return the new data unit
|
||||
* @throws CodeUnitInsertionException if there's a conflict
|
||||
*/
|
||||
TraceData create(TracePlatform platform, Range<Long> lifespan, Register register,
|
||||
DataType dataType) throws CodeUnitInsertionException;
|
||||
}
|
||||
|
|
|
@ -49,6 +49,12 @@ public interface TraceMemoryManager extends TraceMemoryOperations {
|
|||
* space named after the path of each memory being recorded. Of course, the mapping still needs
|
||||
* to occur between the trace and parts of the display and during emulation.
|
||||
*
|
||||
* <p>
|
||||
* NOTE: We are also moving away from (space, thread, frame) triples to uniquely identify
|
||||
* register storage. Instead, that will be encoded into the address space itself. Register
|
||||
* overlays will overlay register space as be named after the register container object, which
|
||||
* subsumes thread and frame when applicable.
|
||||
*
|
||||
* @param name the name of the new address space
|
||||
* @param base the space after which this is modeled
|
||||
* @return the create space
|
||||
|
@ -57,6 +63,21 @@ public interface TraceMemoryManager extends TraceMemoryOperations {
|
|||
AddressSpace createOverlayAddressSpace(String name, AddressSpace base)
|
||||
throws DuplicateNameException;
|
||||
|
||||
/**
|
||||
* Get or create an overlay address space
|
||||
*
|
||||
* <p>
|
||||
* If the space already exists, and it overlays the given base, the existing space is returned.
|
||||
* If it overlays a different space, null is returned. If the space does not exist, it is
|
||||
* created with the given base space.
|
||||
*
|
||||
* @see #createOverlayAddressSpace(String, AddressSpace)
|
||||
* @param name the name of the address space
|
||||
* @param base the expected base space
|
||||
* @return the space, or null
|
||||
*/
|
||||
AddressSpace getOrCreateOverlayAddressSpace(String name, AddressSpace base);
|
||||
|
||||
/**
|
||||
* Delete an overlay address space
|
||||
*
|
||||
|
|
|
@ -27,7 +27,7 @@ import ghidra.trace.model.thread.TraceObjectThread;
|
|||
targetIf = TargetRegister.class,
|
||||
shortName = "register",
|
||||
fixedKeys = {
|
||||
TargetRegister.LENGTH_ATTRIBUTE_NAME
|
||||
TargetRegister.BIT_LENGTH_ATTRIBUTE_NAME
|
||||
})
|
||||
public interface TraceObjectRegister extends TraceObjectInterface {
|
||||
String KEY_STATE = "_state";
|
||||
|
@ -36,7 +36,11 @@ public interface TraceObjectRegister extends TraceObjectInterface {
|
|||
|
||||
String getName();
|
||||
|
||||
int getLength();
|
||||
int getBitLength();
|
||||
|
||||
default int getByteLength() {
|
||||
return (getBitLength() + 7) / 8;
|
||||
}
|
||||
|
||||
void setValue(Range<Long> lifespan, byte[] value);
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ import com.google.common.collect.RangeSet;
|
|||
import ghidra.dbg.target.TargetMethod;
|
||||
import ghidra.dbg.target.TargetObject;
|
||||
import ghidra.dbg.target.schema.TargetObjectSchema;
|
||||
import ghidra.dbg.util.PathPattern;
|
||||
import ghidra.dbg.util.PathPredicates;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.TraceUniqueObject;
|
||||
|
@ -548,4 +549,25 @@ public interface TraceObject extends TraceUniqueObject {
|
|||
}
|
||||
return getTrace().getObjectManager().getObjectByCanonicalPath(TraceObjectKeyPath.of(path));
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for a suitable register container
|
||||
*
|
||||
* @see TargetObjectSchema#searchForRegisterContainer(int, List)
|
||||
* @param frameLevel the frame level. Must be 0 if not applicable
|
||||
* @return the register container, or null
|
||||
*/
|
||||
default TraceObject queryRegisterContainer(int frameLevel) {
|
||||
PathPredicates regsMatcher = getRoot().getTargetSchema()
|
||||
.searchForRegisterContainer(frameLevel, getCanonicalPath().getKeyList());
|
||||
for (PathPattern regsPattern : regsMatcher.getPatterns()) {
|
||||
TraceObject regsObj = getTrace().getObjectManager()
|
||||
.getObjectByCanonicalPath(
|
||||
TraceObjectKeyPath.of(regsPattern.getSingletonPath()));
|
||||
if (regsObj != null) {
|
||||
return regsObj;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package ghidra.trace.model.time.schedule;
|
|||
import java.util.*;
|
||||
|
||||
import ghidra.pcode.emu.PcodeMachine;
|
||||
import ghidra.program.model.lang.Language;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.trace.model.time.TraceSnapshot;
|
||||
|
@ -523,16 +524,16 @@ public class TraceSchedule implements Comparable<TraceSchedule> {
|
|||
* @param sleigh a single line of sleigh, excluding the terminating semicolon.
|
||||
* @return the resulting schedule
|
||||
*/
|
||||
public TraceSchedule patched(TraceThread thread, String sleigh) {
|
||||
public TraceSchedule patched(TraceThread thread, Language language, String sleigh) {
|
||||
if (!this.pSteps.isNop()) {
|
||||
Sequence pTicks = this.pSteps.clone();
|
||||
pTicks.advance(new PatchStep(thread.getKey(), sleigh));
|
||||
pTicks.coalescePatches(thread.getTrace().getBaseLanguage());
|
||||
pTicks.coalescePatches(language);
|
||||
return new TraceSchedule(snap, steps.clone(), pTicks);
|
||||
}
|
||||
Sequence ticks = this.steps.clone();
|
||||
ticks.advance(new PatchStep(keyOf(thread), sleigh));
|
||||
ticks.coalescePatches(thread.getTrace().getBaseLanguage());
|
||||
ticks.coalescePatches(language);
|
||||
return new TraceSchedule(snap, ticks, new Sequence());
|
||||
}
|
||||
|
||||
|
@ -543,20 +544,20 @@ public class TraceSchedule implements Comparable<TraceSchedule> {
|
|||
* @param sleigh the lines of sleigh, excluding the terminating semicolons.
|
||||
* @return the resulting schedule
|
||||
*/
|
||||
public TraceSchedule patched(TraceThread thread, List<String> sleigh) {
|
||||
public TraceSchedule patched(TraceThread thread, Language language, List<String> sleigh) {
|
||||
if (!this.pSteps.isNop()) {
|
||||
Sequence pTicks = this.pSteps.clone();
|
||||
for (String line : sleigh) {
|
||||
pTicks.advance(new PatchStep(thread.getKey(), line));
|
||||
}
|
||||
pTicks.coalescePatches(thread.getTrace().getBaseLanguage());
|
||||
pTicks.coalescePatches(language);
|
||||
return new TraceSchedule(snap, steps.clone(), pTicks);
|
||||
}
|
||||
Sequence ticks = this.steps.clone();
|
||||
for (String line : sleigh) {
|
||||
ticks.advance(new PatchStep(thread.getKey(), line));
|
||||
}
|
||||
ticks.coalescePatches(thread.getTrace().getBaseLanguage());
|
||||
ticks.coalescePatches(language);
|
||||
return new TraceSchedule(snap, ticks, new Sequence());
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ import ghidra.program.model.address.*;
|
|||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.program.model.lang.RegisterValue;
|
||||
import ghidra.trace.model.guest.TracePlatform;
|
||||
import ghidra.trace.model.listing.TraceData;
|
||||
import ghidra.trace.model.memory.TraceMemorySpace;
|
||||
import ghidra.trace.model.memory.TraceMemoryState;
|
||||
|
@ -39,6 +40,27 @@ public enum TraceRegisterUtils {
|
|||
return new AddressRangeImpl(address, address.add(register.getNumBytes() - 1));
|
||||
}
|
||||
|
||||
public static AddressRange getOverlayRange(AddressSpace space, AddressRange range) {
|
||||
AddressSpace physical = space.getPhysicalSpace();
|
||||
if (physical == space || physical != range.getAddressSpace()) {
|
||||
return range;
|
||||
}
|
||||
return new AddressRangeImpl(
|
||||
space.getAddress(range.getMinAddress().getOffset()),
|
||||
space.getAddress(range.getMaxAddress().getOffset()));
|
||||
}
|
||||
|
||||
public static AddressSetView getOverlaySet(AddressSpace space, AddressSetView set) {
|
||||
if (!space.isOverlaySpace()) {
|
||||
return set;
|
||||
}
|
||||
AddressSet result = new AddressSet();
|
||||
for (AddressRange rng : set) {
|
||||
result.add(getOverlayRange(space, rng));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static byte[] padOrTruncate(byte[] arr, int length) {
|
||||
if (arr.length == length) {
|
||||
return arr;
|
||||
|
@ -141,8 +163,8 @@ public enum TraceRegisterUtils {
|
|||
return new RegisterValue(register, addr.getOffsetAsBigInteger());
|
||||
}
|
||||
|
||||
public static RegisterValue combineWithTraceBaseRegisterValue(RegisterValue rv, long snap,
|
||||
TraceMemorySpace regs, boolean requireKnown) {
|
||||
public static RegisterValue combineWithTraceBaseRegisterValue(RegisterValue rv,
|
||||
TracePlatform platform, long snap, TraceMemorySpace regs, boolean requireKnown) {
|
||||
Register reg = rv.getRegister();
|
||||
if (reg.isBaseRegister()) {
|
||||
return rv;
|
||||
|
@ -154,11 +176,11 @@ public enum TraceRegisterUtils {
|
|||
return rv.getBaseRegisterValue();
|
||||
}
|
||||
if (requireKnown) {
|
||||
if (TraceMemoryState.KNOWN != regs.getState(snap, reg.getBaseRegister())) {
|
||||
if (TraceMemoryState.KNOWN != regs.getState(platform, snap, reg.getBaseRegister())) {
|
||||
throw new IllegalStateException("Must fetch base register before setting a child");
|
||||
}
|
||||
}
|
||||
return regs.getValue(snap, reg.getBaseRegister()).combineValues(rv);
|
||||
return regs.getValue(platform, snap, reg.getBaseRegister()).combineValues(rv);
|
||||
}
|
||||
|
||||
public static ByteBuffer prepareBuffer(Register register) {
|
||||
|
|
|
@ -128,11 +128,11 @@ public class ToyDBTraceBuilder implements AutoCloseable {
|
|||
* Manipulate the trace's memory and registers using Sleigh
|
||||
*
|
||||
* @param snap the snap to modify
|
||||
* @param frame the frame to modify
|
||||
* @param thread the thread to modify, can be {@code null} if only memory is used
|
||||
* @param frame the frame to modify
|
||||
* @param sleigh the Sleigh source
|
||||
*/
|
||||
public void exec(long snap, int frame, TraceThread thread, String sleigh) {
|
||||
public void exec(long snap, TraceThread thread, int frame, String sleigh) {
|
||||
PcodeProgram program = SleighProgramCompiler.compileProgram((SleighLanguage) language,
|
||||
"builder", sleigh, PcodeUseropLibrary.nil());
|
||||
TraceSleighUtils.buildByteExecutor(trace, snap, thread, frame)
|
||||
|
@ -144,8 +144,8 @@ public class ToyDBTraceBuilder implements AutoCloseable {
|
|||
*
|
||||
* @param platform the platform whose language to use
|
||||
* @param snap the snap to modify
|
||||
* @param frame the frame to modify
|
||||
* @param thread the thread to modify, can be {@code null} if only memory is used
|
||||
* @param frame the frame to modify
|
||||
* @param sleigh the lines of Sleigh, including semicolons.
|
||||
*/
|
||||
public void exec(TracePlatform platform, long snap, TraceThread thread, int frame,
|
||||
|
|
|
@ -76,7 +76,7 @@ public class DBTraceObjectRegisterSupportTest extends AbstractGhidraHeadlessInte
|
|||
.createOverlayAddressSpace("Targets[0].Threads[0].Registers",
|
||||
b.trace.getBaseAddressFactory().getRegisterSpace());
|
||||
|
||||
regR0.setValue(Range.atLeast(0L), TargetRegister.LENGTH_ATTRIBUTE_NAME, 8);
|
||||
regR0.setValue(Range.atLeast(0L), TargetRegister.BIT_LENGTH_ATTRIBUTE_NAME, 64);
|
||||
regR0.setValue(Range.atLeast(0L), TargetRegister.VALUE_ATTRIBUTE_NAME, 0x1234);
|
||||
}
|
||||
|
||||
|
@ -109,7 +109,7 @@ public class DBTraceObjectRegisterSupportTest extends AbstractGhidraHeadlessInte
|
|||
getSLEIGH_X86_64_LANGUAGE().getCompilerSpecByID(new CompilerSpecID("gcc")));
|
||||
amd64.addMappedRegisterRange();
|
||||
|
||||
regRAX.setValue(Range.atLeast(0L), TargetRegister.LENGTH_ATTRIBUTE_NAME, 8);
|
||||
regRAX.setValue(Range.atLeast(0L), TargetRegister.BIT_LENGTH_ATTRIBUTE_NAME, 64);
|
||||
regRAX.setValue(Range.atLeast(0L), TargetRegister.VALUE_ATTRIBUTE_NAME, 0x1234);
|
||||
}
|
||||
|
||||
|
@ -145,7 +145,7 @@ public class DBTraceObjectRegisterSupportTest extends AbstractGhidraHeadlessInte
|
|||
RAX = amd64.getLanguage().getRegister("RAX");
|
||||
amd64.addRegisterMapOverride(RAX, "orig_rax");
|
||||
|
||||
regOrigRAX.setValue(Range.atLeast(0L), TargetRegister.LENGTH_ATTRIBUTE_NAME, 8);
|
||||
regOrigRAX.setValue(Range.atLeast(0L), TargetRegister.BIT_LENGTH_ATTRIBUTE_NAME, 64);
|
||||
regOrigRAX.setValue(Range.atLeast(0L), TargetRegister.VALUE_ATTRIBUTE_NAME, 0x1234);
|
||||
}
|
||||
|
||||
|
@ -177,7 +177,7 @@ public class DBTraceObjectRegisterSupportTest extends AbstractGhidraHeadlessInte
|
|||
avr8.addMappedRange(b.addr(0),
|
||||
avr8.getLanguage().getDefaultDataSpace().getAddress(0), 0x1000);
|
||||
|
||||
regR0.setValue(Range.atLeast(0L), TargetRegister.LENGTH_ATTRIBUTE_NAME, 1);
|
||||
regR0.setValue(Range.atLeast(0L), TargetRegister.BIT_LENGTH_ATTRIBUTE_NAME, 8);
|
||||
regR0.setValue(Range.atLeast(0L), TargetRegister.VALUE_ATTRIBUTE_NAME, 0x12);
|
||||
}
|
||||
|
||||
|
@ -215,7 +215,7 @@ public class DBTraceObjectRegisterSupportTest extends AbstractGhidraHeadlessInte
|
|||
avr8.addMappedRange(b.addr(overlay, 0),
|
||||
avr8.getLanguage().getDefaultDataSpace().getAddress(0), 0x1000);
|
||||
|
||||
regR0.setValue(Range.atLeast(0L), TargetRegister.LENGTH_ATTRIBUTE_NAME, 1);
|
||||
regR0.setValue(Range.atLeast(0L), TargetRegister.BIT_LENGTH_ATTRIBUTE_NAME, 8);
|
||||
regR0.setValue(Range.atLeast(0L), TargetRegister.VALUE_ATTRIBUTE_NAME, 0x12);
|
||||
}
|
||||
|
||||
|
@ -251,7 +251,7 @@ public class DBTraceObjectRegisterSupportTest extends AbstractGhidraHeadlessInte
|
|||
R0 = avr8.getLanguage().getRegister("R0");
|
||||
avr8.addRegisterMapOverride(R0, "orig_r0");
|
||||
|
||||
regR0.setValue(Range.atLeast(0L), TargetRegister.LENGTH_ATTRIBUTE_NAME, 1);
|
||||
regR0.setValue(Range.atLeast(0L), TargetRegister.BIT_LENGTH_ATTRIBUTE_NAME, 8);
|
||||
regR0.setValue(Range.atLeast(0L), TargetRegister.VALUE_ATTRIBUTE_NAME, 0x12);
|
||||
}
|
||||
|
||||
|
@ -285,7 +285,7 @@ public class DBTraceObjectRegisterSupportTest extends AbstractGhidraHeadlessInte
|
|||
getSLEIGH_X86_64_LANGUAGE().getCompilerSpecByID(new CompilerSpecID("gcc")));
|
||||
amd64.addMappedRegisterRange();
|
||||
|
||||
regOrigRAX.setValue(Range.atLeast(0L), TargetRegister.LENGTH_ATTRIBUTE_NAME, 8);
|
||||
regOrigRAX.setValue(Range.atLeast(0L), TargetRegister.BIT_LENGTH_ATTRIBUTE_NAME, 64);
|
||||
regOrigRAX.setValue(Range.atLeast(0L), TargetRegister.VALUE_ATTRIBUTE_NAME, 0x1234);
|
||||
|
||||
RAX = amd64.getLanguage().getRegister("RAX");
|
||||
|
@ -321,7 +321,7 @@ public class DBTraceObjectRegisterSupportTest extends AbstractGhidraHeadlessInte
|
|||
avr8.addMappedRange(b.addr(0),
|
||||
avr8.getLanguage().getDefaultDataSpace().getAddress(0), 0x1000);
|
||||
|
||||
regR0.setValue(Range.atLeast(0L), TargetRegister.LENGTH_ATTRIBUTE_NAME, 1);
|
||||
regR0.setValue(Range.atLeast(0L), TargetRegister.BIT_LENGTH_ATTRIBUTE_NAME, 8);
|
||||
regR0.setValue(Range.atLeast(0L), TargetRegister.VALUE_ATTRIBUTE_NAME, 0x12);
|
||||
|
||||
R0 = avr8.getLanguage().getRegister("R0");
|
||||
|
@ -352,7 +352,7 @@ public class DBTraceObjectRegisterSupportTest extends AbstractGhidraHeadlessInte
|
|||
.createOverlayAddressSpace("Targets[0].Threads[0].Registers",
|
||||
b.trace.getBaseAddressFactory().getRegisterSpace());
|
||||
|
||||
regRAX.setValue(Range.atLeast(0L), TargetRegister.LENGTH_ATTRIBUTE_NAME, 8);
|
||||
regRAX.setValue(Range.atLeast(0L), TargetRegister.BIT_LENGTH_ATTRIBUTE_NAME, 64);
|
||||
regRAX.setValue(Range.atLeast(0L), TargetRegister.VALUE_ATTRIBUTE_NAME, 0x1234);
|
||||
|
||||
amd64 = b.trace.getPlatformManager()
|
||||
|
@ -382,7 +382,7 @@ public class DBTraceObjectRegisterSupportTest extends AbstractGhidraHeadlessInte
|
|||
TraceObjectKeyPath.parse("Targets[0].Threads[0].Registers.User[RAX]"));
|
||||
regRAX.insert(Range.atLeast(0L), ConflictResolution.DENY);
|
||||
|
||||
regRAX.setValue(Range.atLeast(0L), TargetRegister.LENGTH_ATTRIBUTE_NAME, 8);
|
||||
regRAX.setValue(Range.atLeast(0L), TargetRegister.BIT_LENGTH_ATTRIBUTE_NAME, 64);
|
||||
regRAX.setValue(Range.atLeast(0L), TargetRegister.VALUE_ATTRIBUTE_NAME, 0x1234);
|
||||
|
||||
amd64 = b.trace.getPlatformManager()
|
||||
|
|
|
@ -445,15 +445,16 @@ public class TraceScheduleTest extends AbstractGhidraHeadlessIntegrationTest {
|
|||
thread = tb.trace.getThreadManager().createThread("Threads[0]", 0);
|
||||
}
|
||||
TraceSchedule time = TraceSchedule.parse("0");
|
||||
time = time.patched(thread, "r0l=1");
|
||||
time = time.patched(thread, tb.language, "r0l=1");
|
||||
assertEquals("0:t0-{r0l=0x1}", time.toString());
|
||||
time = time.patched(thread, "r0h=2");
|
||||
time = time.patched(thread, tb.language, "r0h=2");
|
||||
assertEquals("0:t0-{r0=0x200000001}", time.toString());
|
||||
time = time.patched(thread, "r1l=3").patched(thread, "*[ram]:4 0xcafe:8=0xdeadbeef");
|
||||
time = time.patched(thread, tb.language, "r1l=3")
|
||||
.patched(thread, tb.language, "*[ram]:4 0xcafe:8=0xdeadbeef");
|
||||
assertEquals("0:t0-{*:4 0xcafe:8=0xdeadbeef};t0-{r0=0x200000001};t0-{r1l=0x3}",
|
||||
time.toString());
|
||||
|
||||
time = time.patched(thread, "*:8 0xcb00:8 = 0x1122334455667788");
|
||||
time = time.patched(thread, tb.language, "*:8 0xcb00:8 = 0x1122334455667788");
|
||||
assertEquals("0:t0-{*:8 0xcafe:8=0xdead112233445566};t0-{*:2 0xcb06:8=0x7788};" +
|
||||
"t0-{r0=0x200000001};t0-{r1l=0x3}", time.toString());
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue