GP-1881: Implement editable Repr column for Registers and Watches providers.

This commit is contained in:
Dan 2022-05-06 15:08:09 -04:00
parent 8e8b193ac1
commit dbe670bf85
12 changed files with 314 additions and 28 deletions

View file

@ -325,9 +325,9 @@
<H3><A name="toggle_update_while_running">Update While Running</A></H3> <H3><A name="toggle_update_while_running">Update While Running</A></H3>
<P>By default, events are passed to the Objects Viewer even while the target is running. <P>By default, events are passed to the Objects Viewer even while the target is running. The
The resulting changes in the GUI may be distracting for some. To disable updates to the resulting changes in the GUI may be distracting for some. To disable updates to the Objects
Objects Viewer, toggle "Updates While Running" off.</P> Viewer, toggle "Updates While Running" off.</P>
<H2><A name="color"></A>Color Options</H2> <H2><A name="color"></A>Color Options</H2>

View file

@ -58,7 +58,8 @@
time on."</LI> time on."</LI>
<LI>Representation - the value of the register as interpreted by its data type. If the value <LI>Representation - the value of the register as interpreted by its data type. If the value
is an address, double-clicking this field will navigate to it.</LI> is an address, double-clicking this field will navigate to it. This field is user modifiable
whenever the Value column is modifiable and the selected data type provides an encoder.</LI>
</UL> </UL>
<H2>Actions</H2> <H2>Actions</H2>

View file

@ -78,10 +78,10 @@
trace. Clicking the Apply Data Type action will apply it to the current trace, if trace. Clicking the Apply Data Type action will apply it to the current trace, if
possible.</LI> possible.</LI>
<LI>Representation - the value of the watch as interpreted by the selected data type. This <LI>Representation - the value of the watch as interpreted by the selected data type. If the
field is not yet user modifiable, even if the <B>Enable Edits</B> toggle is on. If the value value is an address, i.e., Type is a pointer, then double-clicking this cell will navigate
is an address, i.e., Type is a pointer, then double-clicking this cell will navigate the the primary dynamic listing, if possible. This field is user-modifiable whenever the Value
primary dynamic listing, if possible.</LI> column is modifiable and the selected data type provides an encoder.</LI>
<LI>Error - if an error occurs during compilation or evaluation of the expression, that error <LI>Error - if an error occurs during compilation or evaluation of the expression, that error
is rendered here. Double-clicking the row will display the stack trace. Note that errors is rendered here. Double-clicking the row will display the stack trace. Note that errors

View file

@ -62,8 +62,7 @@ import ghidra.framework.plugintool.AutoService;
import ghidra.framework.plugintool.ComponentProviderAdapter; import ghidra.framework.plugintool.ComponentProviderAdapter;
import ghidra.framework.plugintool.annotation.AutoServiceConsumed; import ghidra.framework.plugintool.annotation.AutoServiceConsumed;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.data.DataType; import ghidra.program.model.data.*;
import ghidra.program.model.data.DataTypeConflictException;
import ghidra.program.model.lang.*; import ghidra.program.model.lang.*;
import ghidra.program.model.util.CodeUnitInsertionException; import ghidra.program.model.util.CodeUnitInsertionException;
import ghidra.trace.model.*; import ghidra.trace.model.*;
@ -89,12 +88,16 @@ public class DebuggerRegistersProvider extends ComponentProviderAdapter
protected enum RegisterTableColumns protected enum RegisterTableColumns
implements EnumeratedTableColumn<RegisterTableColumns, RegisterRow> { implements EnumeratedTableColumn<RegisterTableColumns, RegisterRow> {
FAV("Fav", Boolean.class, RegisterRow::isFavorite, RegisterRow::setFavorite, r -> true, SortDirection.DESCENDING), FAV("Fav", Boolean.class, RegisterRow::isFavorite, RegisterRow::setFavorite, //
r -> true, SortDirection.DESCENDING),
NUMBER("#", Integer.class, RegisterRow::getNumber), NUMBER("#", Integer.class, RegisterRow::getNumber),
NAME("Name", String.class, RegisterRow::getName), NAME("Name", String.class, RegisterRow::getName),
VALUE("Value", BigInteger.class, RegisterRow::getValue, RegisterRow::setValue, RegisterRow::isValueEditable, SortDirection.ASCENDING), VALUE("Value", BigInteger.class, RegisterRow::getValue, RegisterRow::setValue, //
TYPE("Type", DataType.class, RegisterRow::getDataType, RegisterRow::setDataType, r -> true, SortDirection.ASCENDING), RegisterRow::isValueEditable, SortDirection.ASCENDING),
REPR("Repr", String.class, RegisterRow::getRepresentation); TYPE("Type", DataType.class, RegisterRow::getDataType, RegisterRow::setDataType, //
r -> true, SortDirection.ASCENDING),
REPR("Repr", String.class, RegisterRow::getRepresentation, RegisterRow::setRepresentation, //
RegisterRow::isRepresentationEditable, SortDirection.ASCENDING);
private final String header; private final String header;
private final Function<RegisterRow, ?> getter; private final Function<RegisterRow, ?> getter;
@ -859,6 +862,35 @@ public class DebuggerRegistersProvider extends ComponentProviderAdapter
return data.getDataType(); return data.getDataType();
} }
void writeRegisterValueRepresentation(Register register, String representation) {
TraceData data = getRegisterData(register);
if (data == null) {
// isEditable should have been false
tool.setStatusInfo("Register has no data type", true);
return;
}
try {
RegisterValue rv = TraceRegisterUtils.encodeValueRepresentationHackPointer(
register, data, representation);
writeRegisterValue(rv);
}
catch (DataTypeEncodeException e) {
tool.setStatusInfo(e.getMessage(), true);
return;
}
}
boolean canWriteRegisterRepresentation(Register register) {
if (!canWriteRegister(register)) {
return false;
}
TraceData data = getRegisterData(register);
if (data == null) {
return false;
}
return data.getBaseDataType().isEncodable();
}
String getRegisterValueRepresentation(Register register) { String getRegisterValueRepresentation(Register register) {
TraceData data = getRegisterData(register); TraceData data = getRegisterData(register);
if (data == null) { if (data == null) {

View file

@ -91,7 +91,13 @@ public class RegisterRow {
return provider.getRegisterDataType(register); return provider.getRegisterDataType(register);
} }
// TODO: setValueRepresentation. Requires support from data types. public void setRepresentation(String representation) {
provider.writeRegisterValueRepresentation(register, representation);
}
public boolean isRepresentationEditable() {
return provider.canWriteRegisterRepresentation(register);
}
public String getRepresentation() { public String getRepresentation() {
return provider.getRegisterValueRepresentation(register); return provider.getRegisterValueRepresentation(register);

View file

@ -86,9 +86,11 @@ public class DebuggerWatchesProvider extends ComponentProviderAdapter {
protected enum WatchTableColumns implements EnumeratedTableColumn<WatchTableColumns, WatchRow> { protected enum WatchTableColumns implements EnumeratedTableColumn<WatchTableColumns, WatchRow> {
EXPRESSION("Expression", String.class, WatchRow::getExpression, WatchRow::setExpression), EXPRESSION("Expression", String.class, WatchRow::getExpression, WatchRow::setExpression),
ADDRESS("Address", Address.class, WatchRow::getAddress), ADDRESS("Address", Address.class, WatchRow::getAddress),
VALUE("Value", String.class, WatchRow::getRawValueString, WatchRow::setRawValueString, WatchRow::isValueEditable), VALUE("Value", String.class, WatchRow::getRawValueString, WatchRow::setRawValueString, //
WatchRow::isRawValueEditable),
TYPE("Type", DataType.class, WatchRow::getDataType, WatchRow::setDataType), TYPE("Type", DataType.class, WatchRow::getDataType, WatchRow::setDataType),
REPR("Repr", String.class, WatchRow::getValueString), REPR("Repr", String.class, WatchRow::getValueString, WatchRow::setValueString, //
WatchRow::isValueEditable),
ERROR("Error", String.class, WatchRow::getErrorMessage); ERROR("Error", String.class, WatchRow::getErrorMessage);
private final String header; private final String header;

View file

@ -33,6 +33,7 @@ import ghidra.pcode.exec.trace.TraceSleighUtils;
import ghidra.pcode.utils.Utils; import ghidra.pcode.utils.Utils;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.data.DataType; import ghidra.program.model.data.DataType;
import ghidra.program.model.data.DataTypeEncodeException;
import ghidra.program.model.lang.Language; import ghidra.program.model.lang.Language;
import ghidra.program.model.mem.ByteMemBufferImpl; import ghidra.program.model.mem.ByteMemBufferImpl;
import ghidra.program.model.mem.MemBuffer; import ghidra.program.model.mem.MemBuffer;
@ -143,6 +144,8 @@ public class WatchRow {
return dataType.getRepresentation(buffer, SettingsImpl.NO_SETTINGS, value.length); return dataType.getRepresentation(buffer, SettingsImpl.NO_SETTINGS, value.length);
} }
// TODO: DataType settings
protected Object parseAsDataTypeObj() { protected Object parseAsDataTypeObj() {
if (dataType == null || value == null) { if (dataType == null || value == null) {
return null; return null;
@ -373,7 +376,7 @@ public class WatchRow {
return valueObj; return valueObj;
} }
public boolean isValueEditable() { public boolean isRawValueEditable() {
if (!provider.isEditsEnabled()) { if (!provider.isEditsEnabled()) {
return false; return false;
} }
@ -423,8 +426,13 @@ public class WatchRow {
if (address == null) { if (address == null) {
throw new IllegalStateException("Cannot write to watch variable without an address"); throw new IllegalStateException("Cannot write to watch variable without an address");
} }
if (bytes.length != value.length) { if (bytes.length > value.length) {
throw new IllegalArgumentException("Byte array values must match length of variable"); throw new IllegalArgumentException("Byte arrays cannot exceed length of variable");
}
if (bytes.length < value.length) {
byte[] fillOld = Arrays.copyOf(value, value.length);
System.arraycopy(bytes, 0, fillOld, 0, bytes.length);
bytes = fillOld;
} }
DebuggerStateEditingService editingService = provider.editingService; DebuggerStateEditingService editingService = provider.editingService;
if (editingService == null) { if (editingService == null) {
@ -438,6 +446,33 @@ public class WatchRow {
}); });
} }
public void setValueString(String valueString) {
if (dataType == null || value == null) {
// isValueEditable should have been false
provider.getTool().setStatusInfo("Watch no value or no data type", true);
return;
}
try {
byte[] encoded = dataType.encodeRepresentation(valueString,
new ByteMemBufferImpl(address, value, language.isBigEndian()),
SettingsImpl.NO_SETTINGS, value.length);
setRawValueBytes(encoded);
}
catch (DataTypeEncodeException e) {
provider.getTool().setStatusInfo(e.getMessage(), true);
}
}
public boolean isValueEditable() {
if (!isRawValueEditable()) {
return false;
}
if (dataType == null) {
return false;
}
return dataType.isEncodable();
}
public int getValueLength() { public int getValueLength() {
return value == null ? 0 : value.length; return value == null ? 0 : value.length;
} }

View file

@ -19,6 +19,7 @@ import static ghidra.lifecycle.Unfinished.TODO;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import java.math.BigInteger; import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -159,6 +160,11 @@ public class DebuggerRegistersProviderTest extends AbstractGhidraHeadedDebuggerG
row.setValue(new BigInteger(text, 16)); row.setValue(new BigInteger(text, 16));
} }
protected void setRowRepr(RegisterRow row, String repr) {
assertTrue(row.isRepresentationEditable());
row.setRepresentation(repr);
}
protected void assertRowValueEmpty(RegisterRow row) { protected void assertRowValueEmpty(RegisterRow row) {
assertEquals(BigInteger.ZERO, row.getValue()); assertEquals(BigInteger.ZERO, row.getValue());
} }
@ -393,6 +399,48 @@ public class DebuggerRegistersProviderTest extends AbstractGhidraHeadedDebuggerG
}); });
} }
long encodeDouble(double value) {
ByteBuffer buf = ByteBuffer.allocate(Double.BYTES);
buf.putDouble(0, value);
return buf.getLong(0);
}
@Test
public void testModifyRepresentationEmu() throws Exception {
traceManager.openTrace(tb.trace);
TraceThread thread = addThread();
traceManager.activateThread(thread);
waitForSwing();
editingService.setCurrentMode(tb.trace, StateEditingMode.WRITE_EMULATOR);
assertTrue(registersProvider.actionEnableEdits.isEnabled());
performAction(registersProvider.actionEnableEdits);
addRegisterValues(thread);
waitForDomainObject(tb.trace);
TraceMemoryRegisterSpace regVals =
tb.trace.getMemoryManager().getMemoryRegisterSpace(thread, false);
RegisterRow row = findRegisterRow(r0);
assertFalse(row.isRepresentationEditable());
row.setDataType(DoubleDataType.dataType);
waitForDomainObject(tb.trace);
setRowRepr(row, "1234");
waitForSwing();
waitForPass(() -> {
long viewSnap = traceManager.getCurrent().getViewSnap();
assertTrue(DBTraceUtils.isScratch(viewSnap));
assertEquals(BigInteger.valueOf(encodeDouble(1234)),
regVals.getValue(viewSnap, r0).getUnsignedValue());
assertEquals(BigInteger.valueOf(encodeDouble(1234)), row.getValue());
});
}
// NOTE: Value modification only allowed on live target // NOTE: Value modification only allowed on live target
@Test @Test

View file

@ -270,17 +270,17 @@ public class DebuggerWatchesProviderTest extends AbstractGhidraHeadedDebuggerGUI
WatchRow row = Unique.assertOne(watchesProvider.watchTableModel.getModelData()); WatchRow row = Unique.assertOne(watchesProvider.watchTableModel.getModelData());
row.setExpression(expression); row.setExpression(expression);
assertFalse(row.isValueEditable()); assertFalse(row.isRawValueEditable());
traceManager.openTrace(tb.trace); traceManager.openTrace(tb.trace);
traceManager.activateThread(thread); traceManager.activateThread(thread);
editingService.setCurrentMode(tb.trace, StateEditingMode.WRITE_EMULATOR); editingService.setCurrentMode(tb.trace, StateEditingMode.WRITE_EMULATOR);
waitForSwing(); waitForSwing();
assertNoErr(row); assertNoErr(row);
assertFalse(row.isValueEditable()); assertFalse(row.isRawValueEditable());
performAction(watchesProvider.actionEnableEdits); performAction(watchesProvider.actionEnableEdits);
assertEquals(expectWritable, row.isValueEditable()); assertEquals(expectWritable, row.isRawValueEditable());
} }
@Test @Test
@ -314,6 +314,12 @@ public class DebuggerWatchesProviderTest extends AbstractGhidraHeadedDebuggerGUI
return row; return row;
} }
long encodeDouble(double value) {
ByteBuffer buf = ByteBuffer.allocate(Double.BYTES);
buf.putDouble(0, value);
return buf.getLong(0);
}
@Test @Test
public void testEditRegisterEmu() { public void testEditRegisterEmu() {
WatchRow row = prepareTestEditEmu("r0"); WatchRow row = prepareTestEditEmu("r0");
@ -339,9 +345,33 @@ public class DebuggerWatchesProviderTest extends AbstractGhidraHeadedDebuggerGUI
}); });
} }
@Test
public void testEditRegisterRepresentationEmu() {
WatchRow row = prepareTestEditEmu("r0");
assertFalse(row.isValueEditable());
row.setDataType(DoubleDataType.dataType);
waitForSwing();
assertTrue(row.isValueEditable());
TraceMemoryRegisterSpace regVals =
tb.trace.getMemoryManager().getMemoryRegisterSpace(thread, false);
row.setValueString("1234");
waitForPass(() -> {
long viewSnap = traceManager.getCurrent().getViewSnap();
assertTrue(DBTraceUtils.isScratch(viewSnap));
assertEquals(BigInteger.valueOf(encodeDouble(1234)),
regVals.getValue(viewSnap, r0).getUnsignedValue());
assertEquals("0x4093480000000000", row.getRawValueString());
assertEquals("1234.0", row.getValueString());
});
}
@Test @Test
public void testEditMemoryEmu() { public void testEditMemoryEmu() {
WatchRow row = prepareTestEditEmu("*:8 r0"); WatchRow row = prepareTestEditEmu("*:8 r0");
TraceMemoryOperations mem = tb.trace.getMemoryManager(); TraceMemoryOperations mem = tb.trace.getMemoryManager();
ByteBuffer buf = ByteBuffer.allocate(8); ByteBuffer buf = ByteBuffer.allocate(8);
@ -366,6 +396,55 @@ public class DebuggerWatchesProviderTest extends AbstractGhidraHeadedDebuggerGUI
}); });
} }
@Test
public void testEditMemoryRepresentationEmu() {
WatchRow row = prepareTestEditEmu("*:8 r0");
assertFalse(row.isValueEditable());
row.setDataType(DoubleDataType.dataType);
waitForSwing();
assertTrue(row.isValueEditable());
TraceMemoryOperations mem = tb.trace.getMemoryManager();
ByteBuffer buf = ByteBuffer.allocate(8);
row.setValueString("1234");
waitForPass(() -> {
long viewSnap = traceManager.getCurrent().getViewSnap();
assertTrue(DBTraceUtils.isScratch(viewSnap));
buf.clear();
mem.getBytes(viewSnap, tb.addr(0x00400000), buf);
buf.flip();
assertEquals(encodeDouble(1234), buf.getLong());
assertEquals("1234.0", row.getValueString());
});
}
@Test
public void testEditMemoryStringEmu() {
// Variable size must exceed that of desired string's bytes
WatchRow row = prepareTestEditEmu("*:16 r0");
assertFalse(row.isValueEditable());
row.setDataType(TerminatedStringDataType.dataType);
waitForSwing();
assertTrue(row.isValueEditable());
TraceMemoryOperations mem = tb.trace.getMemoryManager();
ByteBuffer buf = ByteBuffer.allocate(14);
row.setValueString("\"Hello, World!\"");
waitForPass(() -> {
long viewSnap = traceManager.getCurrent().getViewSnap();
assertTrue(DBTraceUtils.isScratch(viewSnap));
buf.clear();
mem.getBytes(viewSnap, tb.addr(0x00400000), buf);
buf.flip();
assertArrayEquals("Hello, World!\0".getBytes(), buf.array());
assertEquals("\"Hello, World!\"", row.getValueString());
});
}
protected WatchRow prepareTestEditTarget(String expression) throws Exception { protected WatchRow prepareTestEditTarget(String expression) throws Exception {
createTestModel(); createTestModel();
mb.createTestProcessesAndThreads(); mb.createTestProcessesAndThreads();
@ -422,7 +501,7 @@ public class DebuggerWatchesProviderTest extends AbstractGhidraHeadedDebuggerGUI
// Sanity check // Sanity check
assertFalse(recorder.isRegisterOnTarget(thread, r1)); assertFalse(recorder.isRegisterOnTarget(thread, r1));
assertFalse(row.isValueEditable()); assertFalse(row.isRawValueEditable());
row.setRawValueString("0x1234"); row.setRawValueString("0x1234");
} }

View file

@ -44,7 +44,21 @@ public class PatchStep implements Step {
protected String sleigh; protected String sleigh;
protected int hashCode; protected int hashCode;
public static String generateSleigh(Language language, Address address, byte[] data, /**
* Generate a single line of Sleigh
*
* <p>
* Note that when length is greater than 8, this will generate constants which are too large for
* the Java implementation of Sleigh. Use {@link #generateSleigh(Language, Address, byte[])}
* instead to write the variable in chunks.
*
* @param language the target language
* @param address the (start) address of the variable
* @param data the bytes to write to the variable
* @param length the length of the variable
* @return the Sleigh code
*/
public static String generateSleighLine(Language language, Address address, byte[] data,
int length) { int length) {
BigInteger value = Utils.bytesToBigInteger(data, length, language.isBigEndian(), false); BigInteger value = Utils.bytesToBigInteger(data, length, language.isBigEndian(), false);
if (address.isMemoryAddress()) { if (address.isMemoryAddress()) {
@ -67,8 +81,34 @@ public class PatchStep implements Step {
return String.format("%s=0x%s", register, value.toString(16)); return String.format("%s=0x%s", register, value.toString(16));
} }
public static String generateSleigh(Language language, Address address, byte[] data) { /**
return generateSleigh(language, address, data, data.length); * Generate a single line of Sleigh
*
* @see #generateSleighLine(Language, Address, byte[], int)
*/
public static String generateSleighLine(Language language, Address address, byte[] data) {
return generateSleighLine(language, address, data, data.length);
}
/**
* Generate multiple lines of Sleigh, all to set a single variable
*
* @param language the target language
* @param address the (start) address of the variable
* @param data the bytes to write to the variable
* @return the lines of Sleigh code
*/
public static List<String> generateSleigh(Language language, Address address, byte[] data) {
List<String> result = new ArrayList<>();
generateSleigh(result, language, address, data);
return result;
}
protected static void generateSleigh(List<String> result, Language language, Address address,
byte[] data) {
SemisparseByteArray array = new SemisparseByteArray(); // TODO: Seems heavy-handed
array.putData(address.getOffset(), data);
generateSleigh(result, language, address.getAddressSpace(), array);
} }
protected static List<String> generateSleigh(Language language, protected static List<String> generateSleigh(Language language,
@ -102,7 +142,7 @@ public class PatchStep implements Step {
Address min = chunk.getMinAddress(); Address min = chunk.getMinAddress();
int length = (int) chunk.getLength(); int length = (int) chunk.getLength();
array.getData(min.getOffset(), data, 0, length); array.getData(min.getOffset(), data, 0, length);
result.add(generateSleigh(language, min, data, length)); result.add(generateSleighLine(language, min, data, length));
} }
} }
} }

View file

@ -494,6 +494,7 @@ public class TraceSchedule implements Comparable<TraceSchedule> {
/** /**
* Returns the equivalent of executing this schedule then performing a given patch * Returns the equivalent of executing this schedule then performing a given patch
* *
* @param thread the thread context for the patch; cannot be null
* @param sleigh a single line of sleigh, excluding the terminating semicolon. * @param sleigh a single line of sleigh, excluding the terminating semicolon.
* @return the resulting schedule * @return the resulting schedule
*/ */
@ -509,4 +510,27 @@ public class TraceSchedule implements Comparable<TraceSchedule> {
ticks.coalescePatches(thread.getTrace().getBaseLanguage()); ticks.coalescePatches(thread.getTrace().getBaseLanguage());
return new TraceSchedule(snap, ticks, new Sequence()); return new TraceSchedule(snap, ticks, new Sequence());
} }
/**
* Returns the equivalent of executing this schedule then performing the given patches
*
* @param thread the thread context for the patch; cannot be null
* @param sleigh the lines of sleigh, excluding the terminating semicolons.
* @return the resulting schedule
*/
public TraceSchedule patched(TraceThread thread, 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());
return new TraceSchedule(snap, steps.clone(), pTicks);
}
Sequence ticks = this.steps.clone();
for (String line : sleigh) {
ticks.advance(new PatchStep(thread.getKey(), line));
}
return new TraceSchedule(snap, ticks, new Sequence());
}
} }

View file

@ -15,12 +15,14 @@
*/ */
package ghidra.trace.util; package ghidra.trace.util;
import java.math.BigInteger;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Arrays; import java.util.Arrays;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.ArrayUtils;
import ghidra.pcode.utils.Utils;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.lang.Register; import ghidra.program.model.lang.Register;
@ -122,6 +124,23 @@ public enum TraceRegisterUtils {
return addr.toString(); return addr.toString();
} }
public static RegisterValue encodeValueRepresentationHackPointer(Register register,
TraceData data, String representation) throws DataTypeEncodeException {
DataType dataType = data.getBaseDataType();
if (data.getValueClass() != Address.class) {
byte[] bytes =
dataType.encodeRepresentation(representation, data, data, data.getLength());
BigInteger value = Utils.bytesToBigInteger(bytes, register.getMinimumByteSize(),
register.isBigEndian(), false);
return new RegisterValue(register, value);
}
Address addr = data.getTrace().getBaseAddressFactory().getAddress(representation);
if (addr == null) {
throw new DataTypeEncodeException("Invalid address", representation, dataType);
}
return new RegisterValue(register, addr.getOffsetAsBigInteger());
}
public static RegisterValue combineWithTraceBaseRegisterValue(RegisterValue rv, long snap, public static RegisterValue combineWithTraceBaseRegisterValue(RegisterValue rv, long snap,
TraceMemoryRegisterSpace regs, boolean requireKnown) { TraceMemoryRegisterSpace regs, boolean requireKnown) {
Register reg = rv.getRegister(); Register reg = rv.getRegister();