mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
Merge remote-tracking branch 'origin/GP-1256_Dan_bitRegisters--SQUASHED' into patch
This commit is contained in:
commit
e61571669f
10 changed files with 661 additions and 473 deletions
|
@ -26,7 +26,8 @@ public interface TraceDefinedDataRegisterView
|
||||||
extends TraceDefinedDataView, TraceBaseDefinedRegisterView<TraceData> {
|
extends TraceDefinedDataView, TraceBaseDefinedRegisterView<TraceData> {
|
||||||
default TraceData create(Range<Long> lifespan, Register register, DataType dataType)
|
default TraceData create(Range<Long> lifespan, Register register, DataType dataType)
|
||||||
throws CodeUnitInsertionException {
|
throws CodeUnitInsertionException {
|
||||||
|
TraceRegisterUtils.requireByteBound(register);
|
||||||
return create(lifespan, register.getAddress(), dataType,
|
return create(lifespan, register.getAddress(), dataType,
|
||||||
TraceRegisterUtils.byteLengthOf(register));
|
register.getNumBytes());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,13 +54,50 @@ public interface TraceMemoryRegisterSpace extends TraceMemorySpace {
|
||||||
return getStates(snap, TraceRegisterUtils.rangeForRegister(register));
|
return getStates(snap, TraceRegisterUtils.rangeForRegister(register));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the value of a register at the given snap
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* <b>IMPORTANT:</b> The trace database cannot track the state ({@link TraceMemoryState#KNOWN},
|
||||||
|
* etc.) with per-bit accuracy. It only has byte precision. If the given value specifies, e.g.,
|
||||||
|
* only a single bit, then the entire byte will become marked {@link TraceMemoryState#KNOWN},
|
||||||
|
* even though the remaining 7 bits could technically be unknown.
|
||||||
|
*
|
||||||
|
* @param snap the snap
|
||||||
|
* @param value the register value
|
||||||
|
* @return the number of bytes written
|
||||||
|
*/
|
||||||
default int setValue(long snap, RegisterValue value) {
|
default int setValue(long snap, RegisterValue value) {
|
||||||
ByteBuffer buf = TraceRegisterUtils.bufferForValue(value);
|
if (!value.hasAnyValue()) {
|
||||||
return putBytes(snap, value.getRegister().getAddress(), buf);
|
return 0;
|
||||||
|
}
|
||||||
|
Register reg = value.getRegister();
|
||||||
|
if (!value.hasValue() || !TraceRegisterUtils.isByteBound(reg)) {
|
||||||
|
RegisterValue old = getValue(snap, reg.getBaseRegister());
|
||||||
|
// Do not use .getRegisterValue, as that will zero unmasked bits
|
||||||
|
// Instead, we'll pass the original register to bufferForValue
|
||||||
|
value = old.combineValues(value);
|
||||||
|
}
|
||||||
|
ByteBuffer buf = TraceRegisterUtils.bufferForValue(reg, value);
|
||||||
|
return putBytes(snap, reg.getAddress(), buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write bytes at the given snap and register address
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Note that bit-masked registers are not properly heeded. If the caller wishes to preserve
|
||||||
|
* non-masked bits, it must first retrieve the current value and combine it with the desired
|
||||||
|
* value. The caller must also account for any bit shift in the passed buffer. Alternatively,
|
||||||
|
* consider {@link #setValue(long, RegisterValue)}.
|
||||||
|
*
|
||||||
|
* @param snap the snap
|
||||||
|
* @param register the register to modify
|
||||||
|
* @param buf the buffer of bytes to write
|
||||||
|
* @return the number of bytes written
|
||||||
|
*/
|
||||||
default int putBytes(long snap, Register register, ByteBuffer buf) {
|
default int putBytes(long snap, Register register, ByteBuffer buf) {
|
||||||
int byteLength = TraceRegisterUtils.byteLengthOf(register);
|
int byteLength = register.getNumBytes();
|
||||||
int limit = buf.limit();
|
int limit = buf.limit();
|
||||||
buf.limit(Math.min(limit, buf.position() + byteLength));
|
buf.limit(Math.min(limit, buf.position() + byteLength));
|
||||||
int result = putBytes(snap, register.getAddress(), buf);
|
int result = putBytes(snap, register.getAddress(), buf);
|
||||||
|
@ -79,7 +116,7 @@ public interface TraceMemoryRegisterSpace extends TraceMemorySpace {
|
||||||
}
|
}
|
||||||
|
|
||||||
default int getBytes(long snap, Register register, ByteBuffer buf) {
|
default int getBytes(long snap, Register register, ByteBuffer buf) {
|
||||||
int byteLength = TraceRegisterUtils.byteLengthOf(register);
|
int byteLength = register.getNumBytes();
|
||||||
int limit = buf.limit();
|
int limit = buf.limit();
|
||||||
buf.limit(Math.min(limit, buf.position() + byteLength));
|
buf.limit(Math.min(limit, buf.position() + byteLength));
|
||||||
int result = getBytes(snap, register.getAddress(), buf);
|
int result = getBytes(snap, register.getAddress(), buf);
|
||||||
|
@ -87,8 +124,21 @@ public interface TraceMemoryRegisterSpace extends TraceMemorySpace {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a value from the given time and register
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* <b>IMPORANT:</b> The trace database cannot track the state ({@link TraceMemoryState#KNOWN},
|
||||||
|
* etc.) with per-bit accuracy. It only has byte precision. If the given register specifies,
|
||||||
|
* e.g., only a single bit, then the entire byte will become marked
|
||||||
|
* {@link TraceMemoryState#UNKNOWN}, even though the remaining 7 bits could technically be
|
||||||
|
* known.
|
||||||
|
*
|
||||||
|
* @param snap the snap
|
||||||
|
* @param register the register
|
||||||
|
*/
|
||||||
default void removeValue(long snap, Register register) {
|
default void removeValue(long snap, Register register) {
|
||||||
int byteLength = TraceRegisterUtils.byteLengthOf(register);
|
int byteLength = register.getNumBytes();
|
||||||
removeBytes(snap, register.getAddress(), byteLength);
|
removeBytes(snap, register.getAddress(), byteLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,16 +34,7 @@ public enum TraceRegisterUtils {
|
||||||
|
|
||||||
public static AddressRange rangeForRegister(Register register) {
|
public static AddressRange rangeForRegister(Register register) {
|
||||||
Address address = register.getAddress();
|
Address address = register.getAddress();
|
||||||
return new AddressRangeImpl(address, address.add(register.getMinimumByteSize() - 1));
|
return new AddressRangeImpl(address, address.add(register.getNumBytes() - 1));
|
||||||
}
|
|
||||||
|
|
||||||
public static int byteLengthOf(Register register) {
|
|
||||||
int bitLength = register.getBitLength();
|
|
||||||
if ((bitLength & 7) != 0) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Cannot work with sub-byte boundaries. Consider using the base register.");
|
|
||||||
}
|
|
||||||
return bitLength >> 3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] padOrTruncate(byte[] arr, int length) {
|
public static byte[] padOrTruncate(byte[] arr, int length) {
|
||||||
|
@ -58,33 +49,22 @@ public enum TraceRegisterUtils {
|
||||||
return Arrays.copyOfRange(arr, arr.length - length, arr.length);
|
return Arrays.copyOfRange(arr, arr.length - length, arr.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ByteBuffer bufferForValue(RegisterValue value) {
|
public static ByteBuffer bufferForValue(Register reg, RegisterValue value) {
|
||||||
byte[] arr = value.getSignedValue().toByteArray();
|
byte[] bytes = value.toBytes().clone();
|
||||||
int byteLength = byteLengthOf(value.getRegister());
|
int start = bytes.length / 2;
|
||||||
arr = padOrTruncate(arr, byteLength);
|
// NB: I guess contextreg is always big?
|
||||||
if (!value.getRegister().isBigEndian()) {
|
if (!reg.isBigEndian() && !reg.isProcessorContext()) {
|
||||||
ArrayUtils.reverse(arr);
|
ArrayUtils.reverse(bytes, start, bytes.length);
|
||||||
}
|
}
|
||||||
return ByteBuffer.wrap(arr);
|
int offset = TraceRegisterUtils.computeMaskOffset(reg);
|
||||||
}
|
return ByteBuffer.wrap(bytes, start + offset, reg.getNumBytes());
|
||||||
|
|
||||||
public static int computeMaskOffset(byte[] arr) {
|
|
||||||
for (int i = 0; i < arr.length; i++) {
|
|
||||||
switch (arr[i]) {
|
|
||||||
case -1:
|
|
||||||
return i;
|
|
||||||
case 0:
|
|
||||||
continue;
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Can only handle sub-registers on byte boundaries");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new IllegalArgumentException("No value");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int computeMaskOffset(Register reg) {
|
public static int computeMaskOffset(Register reg) {
|
||||||
return computeMaskOffset(reg.getBaseMask());
|
if (reg.isBaseRegister()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return reg.getOffset() - reg.getBaseRegister().getOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int computeMaskOffset(RegisterValue value) {
|
public static int computeMaskOffset(RegisterValue value) {
|
||||||
|
@ -162,21 +142,38 @@ public enum TraceRegisterUtils {
|
||||||
return regs.getValue(snap, reg.getBaseRegister()).combineValues(rv);
|
return regs.getValue(snap, reg.getBaseRegister()).combineValues(rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RegisterValue getRegisterValue(Register register,
|
public static RegisterValue getRegisterValue(Register reg,
|
||||||
BiConsumer<Address, ByteBuffer> readAction) {
|
BiConsumer<Address, ByteBuffer> readAction) {
|
||||||
int byteLength = TraceRegisterUtils.byteLengthOf(register);
|
/*
|
||||||
byte[] mask = register.getBaseMask();
|
* The byte array for reg values spans the whole base register, but we'd like to avoid
|
||||||
|
* over-reading, so we'll zero in on the bytes actually included in the mask. We'll then
|
||||||
|
* have to handle endianness and such. The regval instance should then apply the actual mask
|
||||||
|
* for the sub-register, if applicable.
|
||||||
|
*/
|
||||||
|
int byteLength = reg.getNumBytes();
|
||||||
|
byte[] mask = reg.getBaseMask();
|
||||||
ByteBuffer buf = ByteBuffer.allocate(mask.length * 2);
|
ByteBuffer buf = ByteBuffer.allocate(mask.length * 2);
|
||||||
buf.put(mask);
|
buf.put(mask);
|
||||||
int maskOffset = TraceRegisterUtils.computeMaskOffset(mask);
|
int maskOffset = TraceRegisterUtils.computeMaskOffset(reg);
|
||||||
int startVal = buf.position() + maskOffset;
|
int startVal = buf.position() + maskOffset;
|
||||||
buf.position(startVal);
|
buf.position(startVal);
|
||||||
buf.limit(buf.position() + byteLength);
|
buf.limit(buf.position() + byteLength);
|
||||||
readAction.accept(register.getAddress(), buf);
|
readAction.accept(reg.getAddress(), buf);
|
||||||
byte[] arr = buf.array();
|
byte[] arr = buf.array();
|
||||||
if (!register.isBigEndian()) {
|
if (!reg.isBigEndian() && !reg.isProcessorContext()) {
|
||||||
ArrayUtils.reverse(arr, startVal, startVal + byteLength);
|
ArrayUtils.reverse(arr, mask.length, buf.capacity());
|
||||||
|
}
|
||||||
|
return new RegisterValue(reg, arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isByteBound(Register register) {
|
||||||
|
return register.getLeastSignificantBit() % 8 == 0 && register.getBitLength() % 8 == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void requireByteBound(Register register) {
|
||||||
|
if (!isByteBound(register)) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Cannot work with sub-byte registers. Consider a parent, instead.");
|
||||||
}
|
}
|
||||||
return new RegisterValue(register, arr);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,8 @@ import ghidra.trace.database.memory.DBTraceMemoryManager;
|
||||||
import ghidra.trace.database.symbol.DBTraceReference;
|
import ghidra.trace.database.symbol.DBTraceReference;
|
||||||
import ghidra.trace.database.thread.DBTraceThread;
|
import ghidra.trace.database.thread.DBTraceThread;
|
||||||
import ghidra.trace.database.thread.DBTraceThreadManager;
|
import ghidra.trace.database.thread.DBTraceThreadManager;
|
||||||
|
import ghidra.trace.model.ImmutableTraceAddressSnapRange;
|
||||||
|
import ghidra.trace.model.TraceAddressSnapRange;
|
||||||
import ghidra.trace.model.language.TraceGuestLanguage;
|
import ghidra.trace.model.language.TraceGuestLanguage;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.database.DBOpenMode;
|
import ghidra.util.database.DBOpenMode;
|
||||||
|
@ -94,6 +96,10 @@ public class ToyDBTraceBuilder implements AutoCloseable {
|
||||||
return new AddressRangeImpl(addr(start), addr(end));
|
return new AddressRangeImpl(addr(start), addr(end));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TraceAddressSnapRange srange(long snap, long start, long end) {
|
||||||
|
return new ImmutableTraceAddressSnapRange(addr(start), addr(end), snap, snap);
|
||||||
|
}
|
||||||
|
|
||||||
public AddressRange drng(long start, long end) {
|
public AddressRange drng(long start, long end) {
|
||||||
return new AddressRangeImpl(data(start), data(end));
|
return new AddressRangeImpl(data(start), data(end));
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -15,11 +15,20 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.trace.database.memory;
|
package ghidra.trace.database.memory;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
import ghidra.program.model.lang.LanguageID;
|
import ghidra.program.model.lang.LanguageID;
|
||||||
|
import ghidra.trace.util.LanguageTestWatcher.TestLanguage;
|
||||||
|
|
||||||
public class DBTraceMemoryManagerBETest extends AbstractDBTraceMemoryManagerTest {
|
public class DBTraceMemoryManagerBETest extends AbstractDBTraceMemoryManagerTest {
|
||||||
@Override
|
@Override
|
||||||
protected LanguageID getLanguageID() {
|
protected LanguageID getLanguageID() {
|
||||||
return new LanguageID("Toy:BE:64:default");
|
return new LanguageID("Toy:BE:64:default");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestLanguage("Toy:BE:32:builder")
|
||||||
|
@Test
|
||||||
|
public void testRegisterBits() throws Exception {
|
||||||
|
runTestRegisterBits();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,11 +15,20 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.trace.database.memory;
|
package ghidra.trace.database.memory;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
import ghidra.program.model.lang.LanguageID;
|
import ghidra.program.model.lang.LanguageID;
|
||||||
|
import ghidra.trace.util.LanguageTestWatcher.TestLanguage;
|
||||||
|
|
||||||
public class DBTraceMemoryManagerLETest extends AbstractDBTraceMemoryManagerTest {
|
public class DBTraceMemoryManagerLETest extends AbstractDBTraceMemoryManagerTest {
|
||||||
@Override
|
@Override
|
||||||
protected LanguageID getLanguageID() {
|
protected LanguageID getLanguageID() {
|
||||||
return new LanguageID("Toy:LE:64:default");
|
return new LanguageID("Toy:LE:64:default");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestLanguage("Toy:LE:32:builder")
|
||||||
|
@Test
|
||||||
|
public void testRegisterBits() throws Exception {
|
||||||
|
runTestRegisterBits();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,12 +19,9 @@ import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.annotation.*;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.junit.*;
|
import org.junit.*;
|
||||||
import org.junit.rules.TestWatcher;
|
|
||||||
import org.junit.runner.Description;
|
|
||||||
|
|
||||||
import com.google.common.collect.Range;
|
import com.google.common.collect.Range;
|
||||||
|
|
||||||
|
@ -45,6 +42,8 @@ import ghidra.trace.database.memory.DBTraceMemoryManager;
|
||||||
import ghidra.trace.database.memory.DBTraceMemorySpace;
|
import ghidra.trace.database.memory.DBTraceMemorySpace;
|
||||||
import ghidra.trace.model.memory.TraceMemoryFlag;
|
import ghidra.trace.model.memory.TraceMemoryFlag;
|
||||||
import ghidra.trace.model.memory.TraceOverlappedRegionException;
|
import ghidra.trace.model.memory.TraceOverlappedRegionException;
|
||||||
|
import ghidra.trace.util.LanguageTestWatcher;
|
||||||
|
import ghidra.trace.util.LanguageTestWatcher.TestLanguage;
|
||||||
import ghidra.util.database.UndoableTransaction;
|
import ghidra.util.database.UndoableTransaction;
|
||||||
import ghidra.util.exception.*;
|
import ghidra.util.exception.*;
|
||||||
import ghidra.util.task.ConsoleTaskMonitor;
|
import ghidra.util.task.ConsoleTaskMonitor;
|
||||||
|
@ -54,35 +53,8 @@ public class DBTraceDisassemblerIntegrationTest extends AbstractGhidraHeadlessIn
|
||||||
protected ToyDBTraceBuilder b;
|
protected ToyDBTraceBuilder b;
|
||||||
protected DBTraceVariableSnapProgramView view;
|
protected DBTraceVariableSnapProgramView view;
|
||||||
|
|
||||||
@Target(ElementType.METHOD)
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
public @interface TestLanguage {
|
|
||||||
String value();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class LanguageWatcher extends TestWatcher {
|
|
||||||
String language = ProgramBuilder._TOY64_BE;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void starting(Description description) {
|
|
||||||
language = computeLanguage(description);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String computeLanguage(Description description) {
|
|
||||||
TestLanguage annot = description.getAnnotation(TestLanguage.class);
|
|
||||||
if (annot == null) {
|
|
||||||
return ProgramBuilder._TOY64_BE;
|
|
||||||
}
|
|
||||||
return annot.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLanguage() {
|
|
||||||
return language;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public LanguageWatcher testLanguage = new LanguageWatcher();
|
public LanguageTestWatcher testLanguage = new LanguageTestWatcher();
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws IOException {
|
public void setUp() throws IOException {
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
/* ###
|
||||||
|
* 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.util;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
import org.junit.rules.TestWatcher;
|
||||||
|
import org.junit.runner.Description;
|
||||||
|
|
||||||
|
import ghidra.program.database.ProgramBuilder;
|
||||||
|
|
||||||
|
public class LanguageTestWatcher extends TestWatcher {
|
||||||
|
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface TestLanguage {
|
||||||
|
String value();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String language;
|
||||||
|
|
||||||
|
public LanguageTestWatcher() {
|
||||||
|
this(ProgramBuilder._TOY64_BE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LanguageTestWatcher(String defaultLanguage) {
|
||||||
|
this.language = defaultLanguage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void starting(Description description) {
|
||||||
|
TestLanguage annot = description.getAnnotation(TestLanguage.class);
|
||||||
|
if (annot == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
language = annot.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLanguage() {
|
||||||
|
return language;
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,11 +21,10 @@ import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.address.AddressSpace;
|
import ghidra.program.model.address.AddressSpace;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to represent a processor register. To sort of handle bit registers, a
|
* Class to represent a processor register. To sort of handle bit registers, a special addressing
|
||||||
* special addressing convention is used. First the upper bit is set. Second, the
|
* convention is used. First the upper bit is set. Second, the next 3 bits are used to specify what
|
||||||
* next 3 bits are used to specify what bit position within a byte that this register
|
* bit position within a byte that this register bit exists at. Finally, the rest of the address is
|
||||||
* bit exists at. Finally, the rest of the address is the address of the byte where
|
* the address of the byte where the register bit lives.
|
||||||
* the register bit lives.
|
|
||||||
*/
|
*/
|
||||||
public class Register implements java.io.Serializable, Comparable<Register> {
|
public class Register implements java.io.Serializable, Comparable<Register> {
|
||||||
|
|
||||||
|
@ -61,7 +60,7 @@ public class Register implements java.io.Serializable, Comparable<Register> {
|
||||||
private Register baseRegister;
|
private Register baseRegister;
|
||||||
private String group;
|
private String group;
|
||||||
|
|
||||||
/**Set of valid lane sizes**/
|
/** Set of valid lane sizes **/
|
||||||
private TreeSet<Integer> laneSizes;
|
private TreeSet<Integer> laneSizes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -72,10 +71,10 @@ public class Register implements java.io.Serializable, Comparable<Register> {
|
||||||
* @param address the address in register space of this register
|
* @param address the address in register space of this register
|
||||||
* @param numBytes the size (in bytes) of this register
|
* @param numBytes the size (in bytes) of this register
|
||||||
* @param bigEndian true if the most significant bytes are associated with the lowest register
|
* @param bigEndian true if the most significant bytes are associated with the lowest register
|
||||||
* addresses, and false if the least significant bytes are associated with the lowest register
|
* addresses, and false if the least significant bytes are associated with the lowest
|
||||||
* addresses.
|
* register addresses.
|
||||||
* @param typeFlags the type(s) of this Register (TYPE_NONE, TYPE_FP, TYPE_SP,
|
* @param typeFlags the type(s) of this Register (TYPE_NONE, TYPE_FP, TYPE_SP, TYPE_PC,
|
||||||
* TYPE_PC, TYPE_CONTEXT, TYPE_ZERO);)
|
* TYPE_CONTEXT, TYPE_ZERO);)
|
||||||
*/
|
*/
|
||||||
public Register(String name, String description, Address address, int numBytes,
|
public Register(String name, String description, Address address, int numBytes,
|
||||||
boolean bigEndian, int typeFlags) {
|
boolean bigEndian, int typeFlags) {
|
||||||
|
@ -128,6 +127,7 @@ public class Register implements java.io.Serializable, Comparable<Register> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add register alias
|
* Add register alias
|
||||||
|
*
|
||||||
* @param aliasReg
|
* @param aliasReg
|
||||||
*/
|
*/
|
||||||
void addAlias(String alias) {
|
void addAlias(String alias) {
|
||||||
|
@ -142,6 +142,7 @@ public class Register implements java.io.Serializable, Comparable<Register> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove register alias
|
* Remove register alias
|
||||||
|
*
|
||||||
* @param alias
|
* @param alias
|
||||||
*/
|
*/
|
||||||
void removeAlias(String alias) {
|
void removeAlias(String alias) {
|
||||||
|
@ -151,9 +152,8 @@ public class Register implements java.io.Serializable, Comparable<Register> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return register aliases.
|
* Return register aliases. NOTE: This is generally only supported for context register fields.
|
||||||
* NOTE: This is generally only supported for
|
*
|
||||||
* context register fields.
|
|
||||||
* @return register aliases or null
|
* @return register aliases or null
|
||||||
*/
|
*/
|
||||||
public Iterable<String> getAliases() {
|
public Iterable<String> getAliases() {
|
||||||
|
@ -201,6 +201,19 @@ public class Register implements java.io.Serializable, Comparable<Register> {
|
||||||
return (bitLength + 7) / 8;
|
return (bitLength + 7) / 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of bytes spanned by this Register.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Compare to {{@link #getMinimumByteSize()}: Suppose a 5-bit register spans 2 bytes: 1 bit in
|
||||||
|
* the first byte, and the remaining 4 in the following byte. Its value can still be stored in 1
|
||||||
|
* byte, which is what {@link #getMinimumByteSize()} returns; however, its storage still spans 2
|
||||||
|
* bytes of the base register, which is what this method returns.
|
||||||
|
*/
|
||||||
|
public int getNumBytes() {
|
||||||
|
return numBytes;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the offset into the register space for this register
|
* Returns the offset into the register space for this register
|
||||||
*/
|
*/
|
||||||
|
@ -210,6 +223,7 @@ public class Register implements java.io.Serializable, Comparable<Register> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the bit offset from the register address for this register.
|
* Returns the bit offset from the register address for this register.
|
||||||
|
*
|
||||||
* @return the bit offset from the register address for this register.
|
* @return the bit offset from the register address for this register.
|
||||||
*/
|
*/
|
||||||
public int getLeastSignificantBit() {
|
public int getLeastSignificantBit() {
|
||||||
|
@ -224,8 +238,7 @@ public class Register implements java.io.Serializable, Comparable<Register> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true for a register whose context value should
|
* Returns true for a register whose context value should follow the disassembly flow.
|
||||||
* follow the disassembly flow.
|
|
||||||
*/
|
*/
|
||||||
public boolean followsFlow() {
|
public boolean followsFlow() {
|
||||||
return (typeFlags & TYPE_DOES_NOT_FOLLOW_FLOW) == 0;
|
return (typeFlags & TYPE_DOES_NOT_FOLLOW_FLOW) == 0;
|
||||||
|
@ -335,8 +348,8 @@ public class Register implements java.io.Serializable, Comparable<Register> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns list of children registers sorted by
|
* Returns list of children registers sorted by lest-significant bit-offset within this
|
||||||
* lest-significant bit-offset within this register.
|
* register.
|
||||||
*/
|
*/
|
||||||
public List<Register> getChildRegisters() {
|
public List<Register> getChildRegisters() {
|
||||||
return new ArrayList<>(childRegisters);
|
return new ArrayList<>(childRegisters);
|
||||||
|
@ -400,6 +413,7 @@ public class Register implements java.io.Serializable, Comparable<Register> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the mask that indicates which bits in the base register apply to this register.
|
* Returns the mask that indicates which bits in the base register apply to this register.
|
||||||
|
*
|
||||||
* @return the mask that indicates which bits in the base register apply to this register
|
* @return the mask that indicates which bits in the base register apply to this register
|
||||||
*/
|
*/
|
||||||
public byte[] getBaseMask() {
|
public byte[] getBaseMask() {
|
||||||
|
@ -445,11 +459,11 @@ public class Register implements java.io.Serializable, Comparable<Register> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if reg is contained within this register.
|
* Determines if reg is contained within this register. Method does not work for bit registers
|
||||||
* Method does not work for bit registers (e.g., context-bits)
|
* (e.g., context-bits)
|
||||||
|
*
|
||||||
* @param reg another register
|
* @param reg another register
|
||||||
* @return true if reg equals this register or is contained
|
* @return true if reg equals this register or is contained within it.
|
||||||
* within it.
|
|
||||||
*/
|
*/
|
||||||
public boolean contains(Register reg) {
|
public boolean contains(Register reg) {
|
||||||
if (equals(reg)) {
|
if (equals(reg)) {
|
||||||
|
@ -472,8 +486,9 @@ public class Register implements java.io.Serializable, Comparable<Register> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if this is a vector register
|
* Returns true if this is a vector register
|
||||||
* @return true precisely when {@code this} is a full vector register (i.e., a register that can be
|
*
|
||||||
* used as input or output for a SIMD operation).
|
* @return true precisely when {@code this} is a full vector register (i.e., a register that can
|
||||||
|
* be used as input or output for a SIMD operation).
|
||||||
*/
|
*/
|
||||||
public boolean isVectorRegister() {
|
public boolean isVectorRegister() {
|
||||||
return (typeFlags & TYPE_VECTOR) != 0;
|
return (typeFlags & TYPE_VECTOR) != 0;
|
||||||
|
@ -481,8 +496,10 @@ public class Register implements java.io.Serializable, Comparable<Register> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines whether {@code laneSizeInBytes} is a valid lane size for this register.
|
* Determines whether {@code laneSizeInBytes} is a valid lane size for this register.
|
||||||
|
*
|
||||||
* @param laneSizeInBytes lane size to check, measured in bytes
|
* @param laneSizeInBytes lane size to check, measured in bytes
|
||||||
* @return true precisely when {@code this} is a vector register and {@code laneSizeInBytes} is a valid lane size.
|
* @return true precisely when {@code this} is a vector register and {@code laneSizeInBytes} is
|
||||||
|
* a valid lane size.
|
||||||
*/
|
*/
|
||||||
public boolean isValidLaneSize(int laneSizeInBytes) {
|
public boolean isValidLaneSize(int laneSizeInBytes) {
|
||||||
if (!isVectorRegister()) {
|
if (!isVectorRegister()) {
|
||||||
|
@ -496,7 +513,9 @@ public class Register implements java.io.Serializable, Comparable<Register> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the sorted array of lane sizes for this register, measured in bytes.
|
* Returns the sorted array of lane sizes for this register, measured in bytes.
|
||||||
* @return array of lane sizes, or {@code null} if {@code this} is not a vector register or no lane sizes have been set.
|
*
|
||||||
|
* @return array of lane sizes, or {@code null} if {@code this} is not a vector register or no
|
||||||
|
* lane sizes have been set.
|
||||||
*/
|
*/
|
||||||
public int[] getLaneSizes() {
|
public int[] getLaneSizes() {
|
||||||
if (laneSizes == null) {
|
if (laneSizes == null) {
|
||||||
|
@ -512,6 +531,7 @@ public class Register implements java.io.Serializable, Comparable<Register> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a lane size.
|
* Adds a lane size.
|
||||||
|
*
|
||||||
* @param laneSizeInBytes lane size to add
|
* @param laneSizeInBytes lane size to add
|
||||||
* @throws UnsupportedOperationException if register is unable to support the definition of
|
* @throws UnsupportedOperationException if register is unable to support the definition of
|
||||||
* lanes.
|
* lanes.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue