mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 19:42:36 +02:00
GP-2551: Fix RegistersProvider for new trace conventions
This commit is contained in:
parent
e89b86a66f
commit
bc2ba594b4
86 changed files with 1743 additions and 708 deletions
|
@ -31,7 +31,7 @@ import ghidra.dbg.util.PathUtils;
|
|||
public interface TargetRegister extends TargetObject {
|
||||
|
||||
String CONTAINER_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "container";
|
||||
String LENGTH_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "length";
|
||||
String BIT_LENGTH_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "length";
|
||||
|
||||
/**
|
||||
* Get the container of this register.
|
||||
|
@ -60,12 +60,25 @@ public interface TargetRegister extends TargetObject {
|
|||
* @return the length of the register
|
||||
*/
|
||||
@TargetAttributeType(
|
||||
name = LENGTH_ATTRIBUTE_NAME,
|
||||
name = BIT_LENGTH_ATTRIBUTE_NAME,
|
||||
required = true,
|
||||
fixed = true,
|
||||
hidden = true)
|
||||
default int getBitLength() {
|
||||
return getTypedAttributeNowByName(LENGTH_ATTRIBUTE_NAME, Integer.class, 0);
|
||||
return getTypedAttributeNowByName(BIT_LENGTH_ATTRIBUTE_NAME, Integer.class, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the length, in bytes, of the register
|
||||
*
|
||||
* <p>
|
||||
* For registers whose bit lengths are not a multiple of 8, this should be the minimum number of
|
||||
* bytes required to bit all the bits, i.e., it should divide by 8 rounding up.
|
||||
*
|
||||
* @return the length of the register
|
||||
*/
|
||||
default int getByteLength() {
|
||||
return (getBitLength() + 7) / 8;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -317,12 +317,8 @@ public interface TargetObjectSchema {
|
|||
* @return the named schema
|
||||
*/
|
||||
default SchemaName getElementSchema(String index) {
|
||||
for (Entry<String, SchemaName> ent : getElementSchemas().entrySet()) {
|
||||
if (ent.getKey().equals(index)) {
|
||||
return ent.getValue();
|
||||
}
|
||||
}
|
||||
return getDefaultElementSchema();
|
||||
SchemaName schemaName = getElementSchemas().get(index);
|
||||
return schemaName == null ? getDefaultElementSchema() : schemaName;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -365,12 +361,8 @@ public interface TargetObjectSchema {
|
|||
* @return the attribute schema
|
||||
*/
|
||||
default AttributeSchema getAttributeSchema(String name) {
|
||||
for (Entry<String, AttributeSchema> ent : getAttributeSchemas().entrySet()) {
|
||||
if (ent.getKey().equals(name)) {
|
||||
return ent.getValue();
|
||||
}
|
||||
}
|
||||
return getDefaultAttributeSchema();
|
||||
AttributeSchema attributeSchema = getAttributeSchemas().get(name);
|
||||
return attributeSchema == null ? getDefaultAttributeSchema() : attributeSchema;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -935,46 +927,46 @@ public interface TargetObjectSchema {
|
|||
* This places some conventional restrictions / expectations on models where registers are given
|
||||
* on a frame-by-frame basis. The schema should present the {@link TargetRegisterContainer} as
|
||||
* the same object or a successor to {@link TargetStackFrame}, which must in turn be a successor
|
||||
* to {@link TargetThread}. The frame level (usually an index) must be in the path from thread
|
||||
* to stack frame. There can be no wild cards between the frame and the register container. For
|
||||
* example, the container for {@code Threads[1]} may be {@code Threads[1].Stack[n].Registers},
|
||||
* where {@code n} is the frame level. {@code Threads[1]} would have the {@link TargetThread}
|
||||
* to {@link TargetStack}. The frame level (an index) must be in the path from stack to frame.
|
||||
* There can be no wild cards between the frame and the register container. For example, the
|
||||
* container for {@code Threads[1]} may be {@code Threads[1].Stack[n].Registers}, where
|
||||
* {@code n} is the frame level. {@code Threads[1].Stack} would have the {@link TargetStack}
|
||||
* interface, {@code Threads[1].Stack[0]} would have the {@link TargetStackFrame} interface, and
|
||||
* {@code Threads[1].Stack[0].Registers} would have the {@link TargetRegisterContainer}
|
||||
* interface. Note it is not sufficient for {@link TargetRegisterContainer} to be a successor of
|
||||
* {@link TargetThread} with a single index between. There <em>must</em> be an intervening
|
||||
* {@link TargetStack} with a single index between. There <em>must</em> be an intervening
|
||||
* {@link TargetStackFrame}, and the frame level (index) must precede it.
|
||||
*
|
||||
* @param frameLevel the frameLevel, must be 0 if not applicable
|
||||
* @param frameLevel the frame level. May be ignored if not applicable
|
||||
* @path the path of the seed object relative to the root
|
||||
* @return the predicates where the register container should be found, possibly empty
|
||||
*/
|
||||
default PathPredicates searchForRegisterContainer(int frameLevel, List<String> path) {
|
||||
List<String> simple = searchForSuitable(TargetRegisterContainer.class, path);
|
||||
if (simple != null) {
|
||||
return frameLevel == 0 ? PathPredicates.pattern(simple) : PathPredicates.EMPTY;
|
||||
return PathPredicates.pattern(simple);
|
||||
}
|
||||
List<String> threadPath = searchForAncestor(TargetThread.class, path);
|
||||
if (threadPath == null) {
|
||||
List<String> stackPath = searchForSuitable(TargetStack.class, path);
|
||||
if (stackPath == null) {
|
||||
return PathPredicates.EMPTY;
|
||||
}
|
||||
PathPattern framePatternRelThread =
|
||||
getSuccessorSchema(threadPath).searchFor(TargetStackFrame.class, false)
|
||||
PathPattern framePatternRelStack =
|
||||
getSuccessorSchema(stackPath).searchFor(TargetStackFrame.class, false)
|
||||
.getSingletonPattern();
|
||||
if (framePatternRelThread == null) {
|
||||
if (framePatternRelStack == null) {
|
||||
return PathPredicates.EMPTY;
|
||||
}
|
||||
|
||||
if (framePatternRelThread.countWildcards() != 1) {
|
||||
if (framePatternRelStack.countWildcards() != 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
PathMatcher result = new PathMatcher();
|
||||
for (String index : List.of(Integer.toString(frameLevel),
|
||||
"0x" + Integer.toHexString(frameLevel))) {
|
||||
List<String> framePathRelThread =
|
||||
framePatternRelThread.applyKeys(index).getSingletonPath();
|
||||
List<String> framePath = PathUtils.extend(threadPath, framePathRelThread);
|
||||
List<String> framePathRelStack =
|
||||
framePatternRelStack.applyKeys(index).getSingletonPath();
|
||||
List<String> framePath = PathUtils.extend(stackPath, framePathRelStack);
|
||||
List<String> regsPath =
|
||||
searchForSuitable(TargetRegisterContainer.class, framePath);
|
||||
if (regsPath != null) {
|
||||
|
@ -983,4 +975,36 @@ public interface TargetObjectSchema {
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the frame level of the object at the given path relative to this schema
|
||||
*
|
||||
* <p>
|
||||
* If there is no {@link TargetStackFrame} in the path, this will return 0 since it is not
|
||||
* applicable to the object. If there is a stack frame in the path, this will examine its
|
||||
* ancestry, up to and excluding the {@link TargetStack} for an index. If there isn't a stack in
|
||||
* the path, it is assumed to be an ancestor of this schema, meaning the examination will
|
||||
* exhaust the ancestry provided in the path. If no index is found, an exception is thrown,
|
||||
* because the frame level is applicable, but couldn't be computed from the path given. In that
|
||||
* case, the client should include more ancestry in the path. Ideally, this is invoked relative
|
||||
* to the root schema.
|
||||
*
|
||||
* @param path the path
|
||||
* @return the frame level, or 0 if not applicable
|
||||
* @throws IllegalArgumentException if frame level is applicable but not given in the path
|
||||
*/
|
||||
default int computeFrameLevel(List<String> path) {
|
||||
List<String> framePath = searchForAncestor(TargetStackFrame.class, path);
|
||||
if (framePath == null) {
|
||||
return 0;
|
||||
}
|
||||
List<String> stackPath = searchForAncestor(TargetStack.class, framePath);
|
||||
for (int i = stackPath == null ? 0 : stackPath.size(); i < framePath.size(); i++) {
|
||||
String key = framePath.get(i);
|
||||
if (PathUtils.isIndex(key)) {
|
||||
return Integer.decode(PathUtils.parseIndex(key));
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("No index between stack and frame");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,27 +15,35 @@
|
|||
*/
|
||||
package ghidra.dbg.model;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import ghidra.dbg.error.DebuggerRegisterAccessException;
|
||||
import ghidra.dbg.target.TargetRegisterBank;
|
||||
import ghidra.dbg.target.TargetRegisterContainer;
|
||||
import ghidra.dbg.util.PathUtils;
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.program.model.address.Address;
|
||||
|
||||
public abstract class AbstractTestTargetRegisterBank<P extends TestTargetObject>
|
||||
extends DefaultTestTargetObject<TestTargetObject, P> implements TargetRegisterBank {
|
||||
extends DefaultTestTargetObject<TestTargetObject, P>
|
||||
implements TargetRegisterBank, TargetRegisterContainer {
|
||||
|
||||
protected final TestTargetRegisterContainer regs;
|
||||
// TODO: Remove the separate descriptors idea
|
||||
protected final TestTargetRegisterContainer descs;
|
||||
public final Map<String, byte[]> regVals = new HashMap<>();
|
||||
|
||||
public AbstractTestTargetRegisterBank(P parent, String name, String typeHint,
|
||||
TestTargetRegisterContainer regs) {
|
||||
super(parent, name, typeHint);
|
||||
this.regs = regs;
|
||||
this.descs = regs;
|
||||
this.descs.addBank(this);
|
||||
changeAttributes(List.of(), Map.of(
|
||||
DESCRIPTIONS_ATTRIBUTE_NAME, regs //
|
||||
), "Initialized");
|
||||
DESCRIPTIONS_ATTRIBUTE_NAME, this),
|
||||
"Initialized");
|
||||
initializeValues();
|
||||
}
|
||||
|
||||
public abstract TestTargetThread getThread();
|
||||
|
@ -43,18 +51,19 @@ public abstract class AbstractTestTargetRegisterBank<P extends TestTargetObject>
|
|||
@Override
|
||||
public CompletableFuture<? extends Map<String, byte[]>> readRegistersNamed(
|
||||
Collection<String> names) {
|
||||
if (!regs.getDescs().keySet().containsAll(names)) {
|
||||
if (!descs.getDescs().keySet().containsAll(names)) {
|
||||
throw new DebuggerRegisterAccessException("No such register");
|
||||
}
|
||||
Map<String, byte[]> result = new LinkedHashMap<>();
|
||||
for (String n : names) {
|
||||
byte[] v = regVals.get(n);
|
||||
if (v == null) {
|
||||
v = regs.getDescs().get(n).defaultValue();
|
||||
v = descs.getDescs().get(n).defaultValue();
|
||||
}
|
||||
result.put(n, v);
|
||||
}
|
||||
return model.gateFuture(regs.getModel().future(result).thenApply(__ -> {
|
||||
populateObjectValues(result, "Read registers");
|
||||
return model.gateFuture(descs.getModel().future(result).thenApply(__ -> {
|
||||
listeners.fire.registersUpdated(this, result);
|
||||
return result;
|
||||
}));
|
||||
|
@ -62,14 +71,14 @@ public abstract class AbstractTestTargetRegisterBank<P extends TestTargetObject>
|
|||
|
||||
protected CompletableFuture<Void> writeRegs(Map<String, byte[]> values,
|
||||
Consumer<Address> setPC) {
|
||||
if (!regs.getDescs().keySet().containsAll(values.keySet())) {
|
||||
if (!descs.getDescs().keySet().containsAll(values.keySet())) {
|
||||
throw new DebuggerRegisterAccessException("No such register");
|
||||
}
|
||||
Map<String, byte[]> updates = new LinkedHashMap<>();
|
||||
CompletableFuture<Void> future = regs.getModel().future(null);
|
||||
CompletableFuture<Void> future = descs.getModel().future(null);
|
||||
for (Map.Entry<String, byte[]> ent : values.entrySet()) {
|
||||
String n = ent.getKey();
|
||||
TestTargetRegister desc = regs.getDescs().get(n);
|
||||
TestTargetRegister desc = descs.getDescs().get(n);
|
||||
byte[] v = desc.normalizeValue(ent.getValue());
|
||||
regVals.put(n, v);
|
||||
updates.put(n, v);
|
||||
|
@ -79,12 +88,53 @@ public abstract class AbstractTestTargetRegisterBank<P extends TestTargetObject>
|
|||
});
|
||||
}
|
||||
}
|
||||
populateObjectValues(updates, "Write registers");
|
||||
future.thenAccept(__ -> {
|
||||
listeners.fire.registersUpdated(this, updates);
|
||||
});
|
||||
return model.gateFuture(future);
|
||||
}
|
||||
|
||||
protected void addObjectValues(Collection<TestTargetRegister> descs, String reason) {
|
||||
Set<TestTargetRegisterValue> objVals = new HashSet<>();
|
||||
for (TestTargetRegister rd : descs) {
|
||||
if (attributes.containsKey(rd.getName())) {
|
||||
continue;
|
||||
}
|
||||
TestTargetRegisterValue tv = new TestTargetRegisterValue(this, rd, (BigInteger) null);
|
||||
objVals.add(tv);
|
||||
}
|
||||
changeAttributes(List.of(), objVals, Map.of(), reason);
|
||||
}
|
||||
|
||||
protected void removeObjectValues(Collection<TestTargetRegister> descs, String reason) {
|
||||
List<String> toRemove = new ArrayList<>();
|
||||
for (TestTargetRegister rd : descs) {
|
||||
toRemove.add(PathUtils.parseIndex(rd.getName()));
|
||||
}
|
||||
changeAttributes(toRemove, Map.of(), reason);
|
||||
}
|
||||
|
||||
protected void populateObjectValues(Map<String, byte[]> values, String reason) {
|
||||
Set<TestTargetRegisterValue> objVals = new HashSet<>();
|
||||
for (Map.Entry<String, byte[]> ent : values.entrySet()) {
|
||||
TestTargetRegister rd = descs.getDescs().get(ent.getKey());
|
||||
byte[] value = ent.getValue();
|
||||
TestTargetRegisterValue tv = new TestTargetRegisterValue(this, rd,
|
||||
value == null ? null : Utils.bytesToBigInteger(value, rd.byteLength, true, false));
|
||||
objVals.add(tv);
|
||||
}
|
||||
changeAttributes(List.of(), objVals, Map.of(), reason);
|
||||
}
|
||||
|
||||
protected void initializeValues() {
|
||||
Map<String, byte[]> values = new HashMap<>();
|
||||
for (TestTargetRegister desc : descs.getDescs().values()) {
|
||||
values.put(desc.getIndex(), null);
|
||||
}
|
||||
populateObjectValues(values, "Populate");
|
||||
}
|
||||
|
||||
public void setFromBank(AbstractTestTargetRegisterBank<?> bank) {
|
||||
//Map<String, byte[]> updates = new HashMap<>();
|
||||
//updates.putAll(bank.regVals);
|
||||
|
@ -98,4 +148,12 @@ public abstract class AbstractTestTargetRegisterBank<P extends TestTargetObject>
|
|||
kit.remove();
|
||||
}
|
||||
}
|
||||
|
||||
public void addRegisterDescs(Collection<TestTargetRegister> added, String reason) {
|
||||
addObjectValues(added, reason);
|
||||
}
|
||||
|
||||
public void removeRegisterDescs(Collection<TestTargetRegister> removed, String reason) {
|
||||
removeObjectValues(removed, reason);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,8 +44,8 @@ public class TestTargetRegister
|
|||
|
||||
changeAttributes(List.of(), Map.of(
|
||||
CONTAINER_ATTRIBUTE_NAME, parent,
|
||||
LENGTH_ATTRIBUTE_NAME, byteLength //
|
||||
), "Initialized");
|
||||
BIT_LENGTH_ATTRIBUTE_NAME, byteLength * 8),
|
||||
"Initialized");
|
||||
}
|
||||
|
||||
public byte[] normalizeValue(byte[] value) {
|
||||
|
|
|
@ -19,6 +19,7 @@ import java.util.*;
|
|||
import java.util.function.Predicate;
|
||||
|
||||
import ghidra.dbg.target.TargetRegisterContainer;
|
||||
import ghidra.dbg.util.CollectionUtils.Delta;
|
||||
import ghidra.program.model.lang.Language;
|
||||
import ghidra.program.model.lang.Register;
|
||||
|
||||
|
@ -26,6 +27,8 @@ public class TestTargetRegisterContainer
|
|||
extends DefaultTestTargetObject<TestTargetRegister, TestTargetProcess>
|
||||
implements TargetRegisterContainer {
|
||||
|
||||
private final Set<AbstractTestTargetRegisterBank<?>> banks = new HashSet<>();
|
||||
|
||||
public TestTargetRegisterContainer(TestTargetProcess parent) {
|
||||
super(parent, "Registers", "RegisterContainer");
|
||||
}
|
||||
|
@ -43,13 +46,50 @@ public class TestTargetRegisterContainer
|
|||
}
|
||||
add.add(getModel().newTestTargetRegister(this, register));
|
||||
}
|
||||
changeElements(List.of(), add, "Added registers from Ghidra language: " + language);
|
||||
String reason = "Added registers from Ghidra language: " + language;
|
||||
changeElements(List.of(), add, reason);
|
||||
List<AbstractTestTargetRegisterBank<?>> banks;
|
||||
synchronized (this.banks) {
|
||||
banks = List.copyOf(this.banks);
|
||||
}
|
||||
for (AbstractTestTargetRegisterBank<?> bank : banks) {
|
||||
bank.addRegisterDescs(add, reason);
|
||||
}
|
||||
return add;
|
||||
}
|
||||
|
||||
public TestTargetRegister addRegister(Register register) {
|
||||
TestTargetRegister tr = getModel().newTestTargetRegister(this, register);
|
||||
changeElements(List.of(), List.of(tr), "Added " + register + " from Ghidra language");
|
||||
TestTargetRegister tr =
|
||||
getModel().newTestTargetRegister(this, Objects.requireNonNull(register));
|
||||
String reason = "Added " + register + " from Ghidra language";
|
||||
changeElements(List.of(), List.of(tr), reason);
|
||||
List<AbstractTestTargetRegisterBank<?>> banks;
|
||||
synchronized (this.banks) {
|
||||
banks = List.copyOf(this.banks);
|
||||
}
|
||||
for (AbstractTestTargetRegisterBank<?> bank : banks) {
|
||||
bank.addRegisterDescs(List.of(tr), reason);
|
||||
}
|
||||
return tr;
|
||||
}
|
||||
|
||||
public Delta<TestTargetRegister, TestTargetRegister> removeRegister(Register register,
|
||||
String reason) {
|
||||
Delta<TestTargetRegister, TestTargetRegister> result =
|
||||
changeElements(List.of(register.getName()), List.of(), reason);
|
||||
List<AbstractTestTargetRegisterBank<?>> banks;
|
||||
synchronized (this.banks) {
|
||||
banks = List.copyOf(this.banks);
|
||||
}
|
||||
for (AbstractTestTargetRegisterBank<?> bank : banks) {
|
||||
bank.removeRegisterDescs(result.removed.values(), reason);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void addBank(AbstractTestTargetRegisterBank<?> bank) {
|
||||
synchronized (this.banks) {
|
||||
this.banks.add(bank);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,44 +22,42 @@ import java.util.Map;
|
|||
import ghidra.dbg.target.TargetRegister;
|
||||
import ghidra.dbg.util.PathUtils;
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.program.model.lang.RegisterValue;
|
||||
|
||||
public class TestTargetRegisterValue
|
||||
extends DefaultTestTargetObject<TestTargetObject, AbstractTestTargetRegisterBank<?>>
|
||||
implements TargetRegister {
|
||||
|
||||
public static TestTargetRegisterValue fromRegisterValue(
|
||||
AbstractTestTargetRegisterBank<?> parent, RegisterValue rv) {
|
||||
Register register = rv.getRegister();
|
||||
return new TestTargetRegisterValue(parent, PathUtils.makeKey(register.getName()),
|
||||
register.isProgramCounter(), rv.getUnsignedValue(), register.getBitLength() + 7 / 8);
|
||||
public final TestTargetRegister desc;
|
||||
|
||||
public TestTargetRegisterValue(AbstractTestTargetRegisterBank<?> parent,
|
||||
TestTargetRegister desc, BigInteger value) {
|
||||
this(parent, desc,
|
||||
value == null ? null : Utils.bigIntegerToBytes(value, desc.byteLength, true));
|
||||
}
|
||||
|
||||
protected final int byteLength;
|
||||
protected final boolean isPC;
|
||||
public TestTargetRegisterValue(AbstractTestTargetRegisterBank<?> parent,
|
||||
TestTargetRegister desc, byte[] value) {
|
||||
super(parent, PathUtils.parseIndex(desc.getName()), "Register");
|
||||
this.desc = desc;
|
||||
|
||||
public TestTargetRegisterValue(AbstractTestTargetRegisterBank<?> parent, String name,
|
||||
boolean isPC, BigInteger value, int byteLength) {
|
||||
this(parent, name, isPC, Utils.bigIntegerToBytes(value, byteLength, true));
|
||||
}
|
||||
|
||||
public TestTargetRegisterValue(AbstractTestTargetRegisterBank<?> parent, String name,
|
||||
boolean isPC, byte[] value) {
|
||||
super(parent, name, "Register");
|
||||
this.byteLength = value.length;
|
||||
this.isPC = isPC;
|
||||
|
||||
changeAttributes(List.of(), Map.of(
|
||||
CONTAINER_ATTRIBUTE_NAME, parent,
|
||||
LENGTH_ATTRIBUTE_NAME, byteLength,
|
||||
VALUE_ATTRIBUTE_NAME, value //
|
||||
), "Initialized");
|
||||
if (value == null) {
|
||||
changeAttributes(List.of(), Map.of(
|
||||
CONTAINER_ATTRIBUTE_NAME, parent,
|
||||
BIT_LENGTH_ATTRIBUTE_NAME, desc.byteLength * 8),
|
||||
"Populated");
|
||||
}
|
||||
else {
|
||||
changeAttributes(List.of(), Map.of(
|
||||
CONTAINER_ATTRIBUTE_NAME, parent,
|
||||
BIT_LENGTH_ATTRIBUTE_NAME, desc.byteLength * 8,
|
||||
VALUE_ATTRIBUTE_NAME, value),
|
||||
"Initialized");
|
||||
}
|
||||
}
|
||||
|
||||
public void setValue(BigInteger value) {
|
||||
changeAttributes(List.of(), Map.of(
|
||||
VALUE_ATTRIBUTE_NAME, Utils.bigIntegerToBytes(value, byteLength, true) //
|
||||
), "Set value");
|
||||
VALUE_ATTRIBUTE_NAME, Utils.bigIntegerToBytes(value, desc.byteLength, true)),
|
||||
"Set value");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,8 +25,8 @@ import ghidra.dbg.util.PathUtils;
|
|||
|
||||
public class TestTargetThread
|
||||
extends DefaultTestTargetObject<TestTargetObject, TestTargetThreadContainer>
|
||||
implements TargetThread, TargetExecutionStateful, TargetSteppable, TargetResumable,
|
||||
TargetInterruptible, TargetKillable {
|
||||
implements TargetThread, TargetAggregate, TargetExecutionStateful, TargetSteppable,
|
||||
TargetResumable, TargetInterruptible, TargetKillable {
|
||||
|
||||
public static final TargetStepKindSet SUPPORTED_KINDS =
|
||||
TargetStepKindSet.of(TargetStepKind.values());
|
||||
|
|
|
@ -94,7 +94,7 @@
|
|||
<attribute name="Breakpoints" schema="BreakpointContainer" required="yes" fixed="yes" />
|
||||
<attribute name="Memory" schema="Memory" required="yes" fixed="yes" />
|
||||
<attribute name="Modules" schema="ModuleContainer" required="yes" fixed="yes" />
|
||||
<attribute name="Registers" schema="RegisterContainer" required="yes" fixed="yes" />
|
||||
<!-- <attribute name="Registers" schema="RegisterContainer" required="yes" fixed="yes" /> -->
|
||||
<attribute name="Threads" schema="ThreadContainer" required="yes" fixed="yes" />
|
||||
<attribute name="Devices" schema="OBJECT" />
|
||||
<attribute name="Environment" schema="OBJECT" />
|
||||
|
@ -171,6 +171,7 @@
|
|||
</schema>
|
||||
<schema name="Thread" elementResync="NEVER" attributeResync="NEVER">
|
||||
<interface name="Thread" />
|
||||
<interface name="Aggregate" />
|
||||
<interface name="ExecutionStateful" />
|
||||
<interface name="Steppable" />
|
||||
<interface name="Resumable" />
|
||||
|
@ -269,7 +270,7 @@
|
|||
<attribute name="_order" schema="INT" hidden="yes" />
|
||||
<attribute schema="ANY" />
|
||||
</schema>
|
||||
<schema name="RegisterContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
|
||||
<schema name="RegisterContainer" elementResync="NEVER" attributeResync="NEVER">
|
||||
<interface name="RegisterContainer" />
|
||||
<element schema="RegisterDescriptor" />
|
||||
<attribute name="_descriptions" schema="RegisterContainer" />
|
||||
|
@ -280,12 +281,13 @@
|
|||
<attribute name="_value" schema="ANY" hidden="yes" />
|
||||
<attribute name="_type" schema="STRING" hidden="yes" />
|
||||
<attribute name="_order" schema="INT" hidden="yes" />
|
||||
<attribute schema="ANY" />
|
||||
</schema>
|
||||
<schema name="RegisterBank" elementResync="NEVER" attributeResync="NEVER">
|
||||
<schema name="RegisterBank" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
|
||||
<interface name="RegisterBank" />
|
||||
<interface name="RegisterContainer" />
|
||||
<!-- NB: registers are attributes, not elements here -->
|
||||
<element schema="RegisterDescriptor" />
|
||||
<element schema="VOID" />
|
||||
<attribute schema="RegisterValue" />
|
||||
<attribute name="_descriptions" schema="RegisterContainer" />
|
||||
<attribute name="_modified" schema="BOOL" hidden="yes" />
|
||||
<attribute name="_display" schema="STRING" hidden="yes" />
|
||||
|
@ -294,9 +296,9 @@
|
|||
<attribute name="_value" schema="ANY" hidden="yes" />
|
||||
<attribute name="_type" schema="STRING" hidden="yes" />
|
||||
<attribute name="_order" schema="INT" hidden="yes" />
|
||||
<attribute schema="OBJECT" />
|
||||
</schema>
|
||||
<schema name="Stack" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
|
||||
<interface name="Stack" />
|
||||
<element schema="StackFrame" />
|
||||
<attribute name="_modified" schema="BOOL" hidden="yes" />
|
||||
<attribute name="_display" schema="STRING" hidden="yes" />
|
||||
|
@ -394,4 +396,18 @@
|
|||
<attribute name="_order" schema="INT" hidden="yes" />
|
||||
<attribute schema="VOID" />
|
||||
</schema>
|
||||
</context>
|
||||
<schema name="RegisterValue" elementResync="NEVER" attributeResync="NEVER">
|
||||
<interface name="Register" />
|
||||
<element schema="VOID" />
|
||||
<attribute name="_length" schema="INT" fixed="yes" hidden="yes" />
|
||||
<attribute name="_container" schema="RegisterContainer" />
|
||||
<attribute name="_modified" schema="BOOL" hidden="yes" />
|
||||
<attribute name="_display" schema="STRING" hidden="yes" />
|
||||
<attribute name="_kind" schema="STRING" fixed="yes" hidden="yes" />
|
||||
<attribute name="_short_display" schema="STRING" hidden="yes" />
|
||||
<attribute name="_value" schema="ANY" required="yes" hidden="yes" />
|
||||
<attribute name="_type" schema="STRING" hidden="yes" />
|
||||
<attribute name="_order" schema="INT" hidden="yes" />
|
||||
<attribute schema="VOID" />
|
||||
</schema>
|
||||
</context>
|
Loading…
Add table
Add a link
Reference in a new issue