GP-2551: Fix RegistersProvider for new trace conventions

This commit is contained in:
Dan 2022-09-15 11:53:24 -04:00
parent e89b86a66f
commit bc2ba594b4
86 changed files with 1743 additions and 708 deletions

View file

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

View file

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

View file

@ -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) {

View file

@ -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

View file

@ -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()
*/

View file

@ -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
*

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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
*

View file

@ -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

View file

@ -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

View file

@ -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

View file

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

View file

@ -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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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

View file

@ -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

View file

@ -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

View file

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

View file

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

View file

@ -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
*

View file

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

View file

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

View file

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

View file

@ -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) {

View file

@ -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,

View file

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

View file

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