mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-02-05 19:15:12 +08:00
Merge remote-tracking branch
'origin/GP-6134_Dan_fixEmuInstNext2-take2--SQUASHED' into patch (Closes #8646)
This commit is contained in:
@@ -313,6 +313,39 @@ public class BytesTracePcodeEmulatorTest extends AbstractTracePcodeEmulatorTest
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This tests the inst_next2 symbol
|
||||
*/
|
||||
@Test
|
||||
public void testSK() throws Throwable {
|
||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "Toy:BE:64:default")) {
|
||||
TraceThread thread = initTrace(tb, """
|
||||
pc = 0x00400000;
|
||||
sp = 0x00110000;
|
||||
""",
|
||||
List.of(
|
||||
"imm r0, #123", // decimal
|
||||
"sk",
|
||||
"imm r0, #911" // decimal
|
||||
));
|
||||
|
||||
Writer writer = createWriter(tb.host, 0);
|
||||
PcodeEmulator emu = createEmulator(tb.host, writer);
|
||||
PcodeThread<byte[]> emuThread = emu.newThread(thread.getPath());
|
||||
emuThread.stepInstruction(); // imm 123
|
||||
emuThread.stepInstruction(); // sk
|
||||
|
||||
try (Transaction tx = tb.startTransaction()) {
|
||||
writer.writeDown(1);
|
||||
}
|
||||
|
||||
assertEquals(BigInteger.valueOf(0x00400006),
|
||||
TraceSleighUtils.evaluate("pc", tb.trace, 1, thread, 0));
|
||||
assertEquals(BigInteger.valueOf(123),
|
||||
TraceSleighUtils.evaluate("r0", tb.trace, 1, thread, 0));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the instruction decoder considers the cached state
|
||||
*
|
||||
|
||||
@@ -62,12 +62,14 @@ public class SleighInstructionPrototype implements InstructionPrototype {
|
||||
static public class FlowSummary {
|
||||
public int delay;
|
||||
public boolean hasCrossBuilds;
|
||||
public boolean hasNext2;
|
||||
public ArrayList<FlowRecord> flowState;
|
||||
public OpTpl lastop;
|
||||
|
||||
public FlowSummary() {
|
||||
delay = 0;
|
||||
hasCrossBuilds = false;
|
||||
hasNext2 = false;
|
||||
flowState = null;
|
||||
lastop = null;
|
||||
}
|
||||
@@ -82,6 +84,7 @@ public class SleighInstructionPrototype implements InstructionPrototype {
|
||||
private int delaySlotByteCnt;
|
||||
|
||||
private boolean hasCrossBuilds;
|
||||
private boolean hasNext2;
|
||||
private ArrayList<ArrayList<FlowRecord>> flowStateListNamed;
|
||||
|
||||
private final static PcodeOp[] emptyPCode = new PcodeOp[0];
|
||||
@@ -153,6 +156,11 @@ public class SleighInstructionPrototype implements InstructionPrototype {
|
||||
return hasCrossBuilds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext2Dependency() {
|
||||
return hasNext2;
|
||||
}
|
||||
|
||||
private static void addExplicitFlow(ConstructState state, OpTpl op, int flags,
|
||||
FlowSummary summary) {
|
||||
if (summary.flowState == null) {
|
||||
@@ -207,14 +215,14 @@ public class SleighInstructionPrototype implements InstructionPrototype {
|
||||
}
|
||||
res.lastop = (OpTpl) state;
|
||||
switch (res.lastop.getOpcode()) {
|
||||
case PcodeOp.PTRSUB: // encoded crossbuild directive
|
||||
case PcodeOp.PTRSUB -> { // encoded crossbuild directive
|
||||
res.hasCrossBuilds = true;
|
||||
addExplicitFlow(walker.getState(), res.lastop, CROSSBUILD, res);
|
||||
break;
|
||||
case PcodeOp.BRANCHIND:
|
||||
}
|
||||
case PcodeOp.BRANCHIND -> {
|
||||
addExplicitFlow(null, res.lastop, BRANCH_INDIRECT | NO_FALLTHRU, res);
|
||||
break;
|
||||
case PcodeOp.BRANCH:
|
||||
}
|
||||
case PcodeOp.BRANCH -> {
|
||||
destType = res.lastop.getInput()[0].getOffset().getType();
|
||||
if (destType == ConstTpl.J_NEXT) {
|
||||
flags = BRANCH_TO_END;
|
||||
@@ -229,8 +237,8 @@ public class SleighInstructionPrototype implements InstructionPrototype {
|
||||
flags = JUMPOUT | NO_FALLTHRU;
|
||||
}
|
||||
addExplicitFlow(walker.getState(), res.lastop, flags, res);
|
||||
break;
|
||||
case PcodeOp.CBRANCH:
|
||||
}
|
||||
case PcodeOp.CBRANCH -> {
|
||||
destType = res.lastop.getInput()[0].getOffset().getType();
|
||||
if (destType == ConstTpl.J_NEXT) {
|
||||
flags = BRANCH_TO_END;
|
||||
@@ -245,27 +253,32 @@ public class SleighInstructionPrototype implements InstructionPrototype {
|
||||
flags = 0;
|
||||
}
|
||||
addExplicitFlow(walker.getState(), res.lastop, flags, res);
|
||||
break;
|
||||
case PcodeOp.CALL:
|
||||
}
|
||||
case PcodeOp.CALL -> {
|
||||
addExplicitFlow(walker.getState(), res.lastop, CALL, res);
|
||||
break;
|
||||
case PcodeOp.CALLIND:
|
||||
}
|
||||
case PcodeOp.CALLIND -> {
|
||||
addExplicitFlow(null, res.lastop, CALL_INDIRECT, res);
|
||||
break;
|
||||
case PcodeOp.RETURN:
|
||||
}
|
||||
case PcodeOp.RETURN -> {
|
||||
addExplicitFlow(null, res.lastop, RETURN | NO_FALLTHRU, res);
|
||||
break;
|
||||
case PcodeOp.PTRADD: // Encoded label build directive
|
||||
}
|
||||
case PcodeOp.PTRADD -> { // Encoded label build directive
|
||||
addExplicitFlow(null, res.lastop, LABEL, res);
|
||||
break;
|
||||
case PcodeOp.INDIRECT: // Encode delayslot
|
||||
}
|
||||
case PcodeOp.INDIRECT -> { // Encode delayslot
|
||||
destType = (int) res.lastop.getInput()[0].getOffset().getReal();
|
||||
if (destType > res.delay) {
|
||||
res.delay = destType;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
default -> {
|
||||
}
|
||||
}
|
||||
for (VarnodeTpl input : res.lastop.getInput()) {
|
||||
if (input.getOffset().getType() == ConstTpl.J_NEXT2) {
|
||||
res.hasNext2 = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
@@ -293,6 +306,7 @@ public class SleighInstructionPrototype implements InstructionPrototype {
|
||||
|
||||
delaySlotByteCnt = summary.delay;
|
||||
hasCrossBuilds = summary.hasCrossBuilds;
|
||||
hasNext2 = summary.hasNext2;
|
||||
if (summary.flowState != null) {
|
||||
flowStateList = summary.flowState;
|
||||
flowType = flowListToFlowType(summary.flowState);
|
||||
@@ -1461,11 +1475,11 @@ public class SleighInstructionPrototype implements InstructionPrototype {
|
||||
}
|
||||
|
||||
/**
|
||||
* Reconstruct the ParserContext's internal packed context array and its list of global
|
||||
* Reconstruct the ParserContext's internal packed context array and its list of global
|
||||
* ContextSet directives by walking a previously resolved ConstructState tree
|
||||
*
|
||||
* @param protoContext is the SleighParserContext containing the tree and holding the context
|
||||
* results
|
||||
* results
|
||||
* @param debug (optional) logger for collecting information about the recovered context
|
||||
* @throws MemoryAccessException if memory errors occur trying to recover context
|
||||
*/
|
||||
|
||||
@@ -19,14 +19,15 @@ import java.util.*;
|
||||
|
||||
import ghidra.app.plugin.processors.sleigh.symbol.OperandSymbol;
|
||||
import ghidra.app.plugin.processors.sleigh.symbol.TripleSymbol;
|
||||
import ghidra.app.util.PseudoInstruction;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.lang.*;
|
||||
import ghidra.program.model.mem.*;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* All the recovered context for a single instruction
|
||||
* <p>
|
||||
* The main data structure is the tree of constructors and operands
|
||||
*/
|
||||
|
||||
@@ -71,12 +72,13 @@ public class SleighParserContext implements ParserContext {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for building precompiled templates.
|
||||
* NOTE: This form does not support use of {@code inst_next2}.
|
||||
* @param aAddr = address to which 'inst_start' resolves
|
||||
* @param nAddr = address to which 'inst_next' resolves
|
||||
* @param rAddr = special address associated with original call
|
||||
* @param dAddr = destination address of original call being replaced
|
||||
* Constructor for building precompiled templates. NOTE: This form does not support use of
|
||||
* {@code inst_next2}.
|
||||
*
|
||||
* @param aAddr = address to which 'inst_start' resolves
|
||||
* @param nAddr = address to which 'inst_next' resolves
|
||||
* @param rAddr = special address associated with original call
|
||||
* @param dAddr = destination address of original call being replaced
|
||||
*/
|
||||
public SleighParserContext(Address aAddr, Address nAddr, Address rAddr, Address dAddr) {
|
||||
memBuffer = null;
|
||||
@@ -91,10 +93,11 @@ public class SleighParserContext implements ParserContext {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate context specifically for an instruction that has a delayslot.
|
||||
* When generating p-code SLEIGH has an alternate interpretation of the "inst_next"
|
||||
* symbol that takes into account the instruction in the delay slot. This context is
|
||||
* generated at the point when specific instruction(s) in the delay slot are known.
|
||||
* Generate context specifically for an instruction that has a delayslot. When generating p-code
|
||||
* SLEIGH has an alternate interpretation of the "inst_next" symbol that takes into account the
|
||||
* instruction in the delay slot. This context is generated at the point when specific
|
||||
* instruction(s) in the delay slot are known.
|
||||
*
|
||||
* @param origContext is the original context (for the instruction in isolation)
|
||||
* @param delayByteCount is the number of bytes in instruction stream occupied by the delay slot
|
||||
*/
|
||||
@@ -175,6 +178,7 @@ public class SleighParserContext implements ParserContext {
|
||||
|
||||
/**
|
||||
* get address of current instruction
|
||||
*
|
||||
* @return address of current instruction
|
||||
*/
|
||||
public Address getAddr() {
|
||||
@@ -182,9 +186,10 @@ public class SleighParserContext implements ParserContext {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get address of instruction after current instruction. This may return null if this context
|
||||
* Get address of instruction after current instruction. This may return null if this context
|
||||
* instance does not support use of {@code inst_next} or next address falls beyond end of
|
||||
* address space.
|
||||
*
|
||||
* @return address of next instruction or null
|
||||
*/
|
||||
public Address getNaddr() {
|
||||
@@ -192,33 +197,31 @@ public class SleighParserContext implements ParserContext {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get address of instruction after the next instruction. This may return {@link #getNaddr()}
|
||||
* if this context instance does not support use of {@code inst_next2} or parse of next
|
||||
* instruction fails.
|
||||
* @return address of instruction after the next instruction or null
|
||||
* {@return the address of the instruction after the next instruction or
|
||||
* {@link Address#NO_ADDRESS}, if the next instruction cannot be parsed or if {@code inst_next2}
|
||||
* is not supported in this context.}
|
||||
*
|
||||
* @implNote If this is returning {@link Address#NO_ADDRESS} unexpectedly in emulation, refer to
|
||||
* {@link PseudoInstruction} and its logic for choosing how many bytes to cache.
|
||||
*/
|
||||
public Address getN2addr() {
|
||||
if (next2InstAddr != null) {
|
||||
return next2InstAddr;
|
||||
}
|
||||
next2InstAddr = computeNext2Address();
|
||||
if (next2InstAddr == null) {
|
||||
// unsupported use of inst_next2 or parse failure on next instruction
|
||||
// returns same as inst_next
|
||||
next2InstAddr = nextInstrAddr;
|
||||
}
|
||||
return next2InstAddr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the address after the next instruction (inst_next2). The length of next instruction
|
||||
* based on attempted parse of next instruction and does not consider any delayslot use.
|
||||
* The current instructions context is used during the parse.
|
||||
* Return the address after the next instruction (inst_next2). The length of next instruction
|
||||
* based on attempted parse of next instruction and does not consider any delayslot use. The
|
||||
* current instructions context is used during the parse.
|
||||
*
|
||||
* @return address after the next instruction or null if unable/failed to determine
|
||||
*/
|
||||
private Address computeNext2Address() {
|
||||
if (memBuffer == null || nextInstrAddr == null) {
|
||||
return null; // not supported without memBuffer for parse
|
||||
return Address.NO_ADDRESS; // not supported without memBuffer for parse
|
||||
}
|
||||
try {
|
||||
Address nextAddr = nextInstrAddr;
|
||||
@@ -240,13 +243,27 @@ public class SleighParserContext implements ParserContext {
|
||||
return nextAddr.addNoWrap(proto.getLength());
|
||||
}
|
||||
catch (Exception e) {
|
||||
// ignore
|
||||
Msg.error(this, "Could not compute inst_next2: " + e);
|
||||
/**
|
||||
* Unsupported use of inst_next2 or parse failure on next instruction. IMPORTANT!: This
|
||||
* CANNOT fall back to inst_next. While it may be tempting, it's likely that a jump to
|
||||
* inst_next2 intends to *skip* that instruction. Falling back to inst_next will
|
||||
* definitely *execute* that instruction leading to VERY unexpected behavior, especially
|
||||
* in the emulator.
|
||||
*
|
||||
* We'll return Address.NO_ADDRESS, even though that doesn't actually make it into the
|
||||
* p-code. PcodeEmit#generateLocation and ConstTpl#fix work on offsets, so they re-write
|
||||
* it to "ram:00000000". Still, at least that is more likely to cause a crash (the
|
||||
* desired behavior) vs. stumbling along and executing an instruction that was likely
|
||||
* meant to be skipped.
|
||||
*/
|
||||
return Address.NO_ADDRESS;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get address space containing current instruction
|
||||
*
|
||||
* @return address space containing current instruction
|
||||
*/
|
||||
public AddressSpace getCurSpace() {
|
||||
@@ -255,6 +272,7 @@ public class SleighParserContext implements ParserContext {
|
||||
|
||||
/**
|
||||
* Get constant address space
|
||||
*
|
||||
* @return constant address space
|
||||
*/
|
||||
public AddressSpace getConstSpace() {
|
||||
@@ -262,8 +280,9 @@ public class SleighParserContext implements ParserContext {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get memory buffer for current instruction which may also be used to parse next instruction
|
||||
* or delay slot instructions.
|
||||
* Get memory buffer for current instruction which may also be used to parse next instruction or
|
||||
* delay slot instructions.
|
||||
*
|
||||
* @return memory buffer for current instruction
|
||||
*/
|
||||
public MemBuffer getMemBuffer() {
|
||||
@@ -271,14 +290,15 @@ public class SleighParserContext implements ParserContext {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get bytes from the instruction stream into an int
|
||||
* (packed in big endian format). Uninitialized or
|
||||
* undefined memory will return zero byte values.
|
||||
* Get bytes from the instruction stream into an int (packed in big endian format).
|
||||
* Uninitialized or undefined memory will return zero byte values.
|
||||
*
|
||||
* @param offset offset relative start of this context
|
||||
* @param bytestart pattern byte offset relative to specified context offset
|
||||
* @param bytestart pattern byte offset relative to specified context offset
|
||||
* @param size is the number of bytes to fetch
|
||||
* @return requested byte-range value
|
||||
* @throws MemoryAccessException if no bytes are available at first byte when (offset+bytestart==0).
|
||||
* @throws MemoryAccessException if no bytes are available at first byte when
|
||||
* (offset+bytestart==0).
|
||||
*/
|
||||
public int getInstructionBytes(int offset, int bytestart, int size)
|
||||
throws MemoryAccessException {
|
||||
@@ -297,14 +317,15 @@ public class SleighParserContext implements ParserContext {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get bits from the instruction stream into an int
|
||||
* (packed in big endian format). Uninitialized or
|
||||
* undefined memory will return zero bit values.
|
||||
* Get bits from the instruction stream into an int (packed in big endian format). Uninitialized
|
||||
* or undefined memory will return zero bit values.
|
||||
*
|
||||
* @param offset offset relative start of this context
|
||||
* @param startbit is the index of the first bit to fetch
|
||||
* @param size is the number of bits to fetch
|
||||
* @return requested bit-range value
|
||||
* @throws MemoryAccessException if no bytes are available at first byte when (offset+bytestart/8==0).
|
||||
* @throws MemoryAccessException if no bytes are available at first byte when
|
||||
* (offset+bytestart/8==0).
|
||||
*/
|
||||
public int getInstructionBits(int offset, int startbit, int size) throws MemoryAccessException {
|
||||
|
||||
@@ -331,6 +352,7 @@ public class SleighParserContext implements ParserContext {
|
||||
|
||||
/**
|
||||
* Get the processor context value as a RegisterValue
|
||||
*
|
||||
* @return processor context value
|
||||
*/
|
||||
public RegisterValue getContextRegisterValue() {
|
||||
@@ -369,6 +391,7 @@ public class SleighParserContext implements ParserContext {
|
||||
|
||||
/**
|
||||
* Get bytes from context into an int
|
||||
*
|
||||
* @param bytestart is the index of the first byte to fetch
|
||||
* @param bytesize number of bytes (range: 1 - 4)
|
||||
* @return the packed bytes from context
|
||||
@@ -391,8 +414,9 @@ public class SleighParserContext implements ParserContext {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get full set of context bytes. Sleigh only supports context
|
||||
* which is a multiple of 4-bytes (i.e., size of int)
|
||||
* Get full set of context bytes. Sleigh only supports context which is a multiple of 4-bytes
|
||||
* (i.e., size of int)
|
||||
*
|
||||
* @return the array of context data
|
||||
*/
|
||||
public int[] getContextBytes() {
|
||||
@@ -401,6 +425,7 @@ public class SleighParserContext implements ParserContext {
|
||||
|
||||
/**
|
||||
* Get bits from context into an int
|
||||
*
|
||||
* @param startbit is the index of the first bit to fetch
|
||||
* @param bitsize number of bits (range: 1 - 32)
|
||||
* @return the packed bits
|
||||
|
||||
@@ -35,11 +35,11 @@ import ghidra.util.SystemUtilities;
|
||||
import ghidra.util.exception.AssertException;
|
||||
|
||||
/**
|
||||
* Pseudo (i.e., fake) instruction that is generated by the Disassembler. This form of
|
||||
* has some limitation over an instruction which is obtained from a program listing.
|
||||
* The instruction will completely cache all bytes corresponding to the prototype length
|
||||
* at the specified address. Additional bytes will be cached for delay-slotted instructions
|
||||
* to facilitate pcode generation and obtaining general pcode related attributes.
|
||||
* Pseudo (i.e., fake) instruction that is generated by the Disassembler. This form of has some
|
||||
* limitation over an instruction which is obtained from a program listing. The instruction will
|
||||
* completely cache all bytes corresponding to the prototype length at the specified address.
|
||||
* Additional bytes will be cached for delay-slotted instructions to facilitate pcode generation and
|
||||
* obtaining general pcode related attributes.
|
||||
*/
|
||||
public class PseudoInstruction extends PseudoCodeUnit implements Instruction, InstructionContext {
|
||||
|
||||
@@ -54,8 +54,9 @@ public class PseudoInstruction extends PseudoCodeUnit implements Instruction, In
|
||||
private Address fallThroughOverride = null; // NO_ADDRESS indicate fall-through removed
|
||||
private FlowOverride flowOverride = FlowOverride.NONE;
|
||||
|
||||
/**
|
||||
/**
|
||||
* Construct a new PseudoInstruction within a program.
|
||||
*
|
||||
* @param program is the given Program
|
||||
* @param addr address of the instruction
|
||||
* @param prototype prototype of the instruction
|
||||
@@ -73,8 +74,9 @@ public class PseudoInstruction extends PseudoCodeUnit implements Instruction, In
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Construct a new PseudoInstruction within a program.
|
||||
*
|
||||
* @param addrFactory program/language address factory
|
||||
* @param addr address of the instruction
|
||||
* @param prototype prototype of the instruction
|
||||
@@ -91,8 +93,9 @@ public class PseudoInstruction extends PseudoCodeUnit implements Instruction, In
|
||||
this.addrFactory = addrFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Construct a new PseudoInstruction without a program (flow override not supported).
|
||||
*
|
||||
* @param addr address of the instruction
|
||||
* @param prototype prototype of the instruction
|
||||
* @param memBuffer buffer containing the bytes for the instruction
|
||||
@@ -110,8 +113,18 @@ public class PseudoInstruction extends PseudoCodeUnit implements Instruction, In
|
||||
// NOTE: in certain cases this may not cache enough if slot size was
|
||||
// specified as a minimum and not actual
|
||||
int length = prototype.getLength();
|
||||
int delaySlotByteCount = prototype.getDelaySlotByteCount();
|
||||
if (delaySlotByteCount == 1) {
|
||||
int extraByteCount = prototype.getDelaySlotByteCount();
|
||||
if (prototype.hasNext2Dependency()) {
|
||||
/**
|
||||
* NOTE: The notes about problems below apply here, too. We're assuming that the next
|
||||
* instruction is at most 3 bytes longer than this instruction. Maybe that suffices, but
|
||||
* be prepared to 1) Add more slack bytes, or 2) Actually parse the next instruction(s).
|
||||
* The difficulty with option 2 (and why I don't just do it now) is that I need the
|
||||
* initial context register value for that next instruction.
|
||||
*/
|
||||
extraByteCount = Math.max(length, extraByteCount);
|
||||
}
|
||||
if (extraByteCount == 1) {
|
||||
// Assume this is a minimum size and cache enough for one
|
||||
// more instruction of the same size.
|
||||
length += length;
|
||||
@@ -119,7 +132,7 @@ public class PseudoInstruction extends PseudoCodeUnit implements Instruction, In
|
||||
else {
|
||||
// NOTE: This may have a problem if delaySlotByteCount is a
|
||||
// minimum byte count and more bytes are needed for delay slots.
|
||||
length += delaySlotByteCount;
|
||||
length += extraByteCount;
|
||||
}
|
||||
// Sleigh utilizes 4-byte (int) chunks when evaluating patterns
|
||||
// make sure we have enough bytes to give out for any valid offset
|
||||
@@ -128,8 +141,9 @@ public class PseudoInstruction extends PseudoCodeUnit implements Instruction, In
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the byte value repeated for all bytes within this instruction or null
|
||||
* if byte values vary.
|
||||
* Return the byte value repeated for all bytes within this instruction or null if byte values
|
||||
* vary.
|
||||
*
|
||||
* @return repeated byte value or null if bytes vary
|
||||
*/
|
||||
public synchronized Byte getRepeatedByte() {
|
||||
|
||||
@@ -19,6 +19,7 @@ import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.VariableOffset;
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.pcode.*;
|
||||
@@ -27,295 +28,291 @@ import ghidra.program.model.symbol.FlowType;
|
||||
import ghidra.program.model.symbol.RefType;
|
||||
|
||||
/**
|
||||
* InstructionPrototype is designed to describe one machine level instruction.
|
||||
* A language parser can return the same InstructionProtoype object for the
|
||||
* same type node. Prototypes for instructions will normally be fixed for a node.
|
||||
* InstructionPrototype is designed to describe one machine level instruction. A language parser can
|
||||
* return the same InstructionProtoype object for the same type node. Prototypes for instructions
|
||||
* will normally be fixed for a node.
|
||||
*/
|
||||
public interface InstructionPrototype {
|
||||
public static final int INVALID_DEPTH_CHANGE = 16777216; // 2^24
|
||||
/** Sentinel value to indicate an invalid depth change */
|
||||
public static final int INVALID_DEPTH_CHANGE = 1 << 24;
|
||||
|
||||
/**
|
||||
* Get a new instance of a ParserContext.
|
||||
* @param buf
|
||||
* @param processorContext
|
||||
* @return instruction ParserContext
|
||||
* @throws MemoryAccessException
|
||||
* {@return a new instance of an instruction {@link ParserContext}}
|
||||
*
|
||||
* @param buf the memory from which this prototype was parsed, or an equivalent cache
|
||||
* @param processorContext the (incoming) processor context during parse
|
||||
* @throws MemoryAccessException if the memory buffer cannot be accessed
|
||||
*/
|
||||
public ParserContext getParserContext(MemBuffer buf, ProcessorContextView processorContext)
|
||||
throws MemoryAccessException;
|
||||
|
||||
/**
|
||||
* Get a ParserContext by parsing bytes outside of the normal disassembly process
|
||||
* @param addr where the ParserContext is needed
|
||||
* {@return a ParserContext by parsing bytes outside of the normal disassembly process}
|
||||
*
|
||||
* @param address where the ParserContext is needed, i.e., the first address of an instruction
|
||||
* to be parsed
|
||||
* @param buffer of actual bytes
|
||||
* @param processorContext
|
||||
* @return
|
||||
* @throws InsufficientBytesException
|
||||
* @throws UnknownInstructionException
|
||||
* @throws UnknownContextException
|
||||
* @throws MemoryAccessException
|
||||
* @param processorContext the (incoming) processor context
|
||||
* @throws InsufficientBytesException if not enough bytes are in the buffer
|
||||
* @throws UnknownInstructionException if the bytes do not constitute a valid instruction
|
||||
* @throws UnknownContextException if contextual dependencies, e.g. {@code crossbuild}
|
||||
* instructions, are not available
|
||||
* @throws MemoryAccessException if the memory buffer cannot be accessed
|
||||
*/
|
||||
public ParserContext getPseudoParserContext(Address addr, MemBuffer buffer,
|
||||
public ParserContext getPseudoParserContext(Address address, MemBuffer buffer,
|
||||
ProcessorContextView processorContext) throws InsufficientBytesException,
|
||||
UnknownInstructionException, UnknownContextException, MemoryAccessException;
|
||||
|
||||
/**
|
||||
* @return true if instruction prototype expects one or more delay slotted
|
||||
* instructions to exist.
|
||||
* {@return true if instruction prototype expects one or more delay slotted instructions to
|
||||
* exist}
|
||||
*/
|
||||
public boolean hasDelaySlots();
|
||||
|
||||
/**
|
||||
* @return true if instruction semantics have a CrossBuild instruction
|
||||
* dependency which may require a robust InstructionContext with access
|
||||
* to preceding instructions
|
||||
* {@return true if instruction semantics have a {@code crossbuild} instruction dependency which
|
||||
* may require a robust {@link InstructionContext} with access to preceding instructions}
|
||||
*/
|
||||
public boolean hasCrossBuildDependency();
|
||||
|
||||
/**
|
||||
* Get the mnemonic for this CodeProtype. Examples: "MOV" and
|
||||
* "CALL" for instructions and "DB" and "DA" for data.
|
||||
* {@return true if instruction semantics contain a reference to {@code inst_next2}}.
|
||||
*/
|
||||
public boolean hasNext2Dependency();
|
||||
|
||||
/**
|
||||
* {@return the mnemonic for this prototype}
|
||||
* <p>
|
||||
* Examples: "{@code MOV}" and "{@code CALL}"
|
||||
*
|
||||
* @param context the instruction context
|
||||
* @return the mnemonic for this CodePrototype.
|
||||
*/
|
||||
public String getMnemonic(InstructionContext context);
|
||||
|
||||
/**
|
||||
* Get the length of this CodeProtoype.
|
||||
*
|
||||
* @return the length of this CodeProtoype.
|
||||
* {@return the length in bytes of this prototype}
|
||||
*/
|
||||
public int getLength();
|
||||
|
||||
/**
|
||||
* Get a Mask that describe which bits of this instruction determine
|
||||
* the opcode.
|
||||
*
|
||||
* @return a Mask for the opcode bits or null if unknown.
|
||||
* {@return the {@link Mask} that describe which bits of this instruction determine the opcode,
|
||||
* or null if unknown}
|
||||
*/
|
||||
public Mask getInstructionMask();
|
||||
|
||||
/**
|
||||
* Get a Mask that describe which bits of this instruction determine
|
||||
* the operand value.
|
||||
*
|
||||
* @return a Mask for the operand bits or null if unknown.
|
||||
* {@return the {@link Mask} that describe which bits of this instruction determine a specific
|
||||
* operand's value, or null if unknown}
|
||||
*
|
||||
* @param operandIndex the 0-up index of the operand
|
||||
*/
|
||||
public Mask getOperandValueMask(int operandIndex);
|
||||
|
||||
/**
|
||||
* Get the flow type of this instruction. Used
|
||||
* for analysis purposes. i.e., how this
|
||||
* instruction flows to the next instruction.
|
||||
* {@return the flow type of this instruction}
|
||||
* <p>
|
||||
* This is used for analysis purposes. i.e., how this instruction flows to the next instruction.
|
||||
*
|
||||
* @param context the instruction context
|
||||
* @return flow type.
|
||||
*/
|
||||
public FlowType getFlowType(InstructionContext context);
|
||||
|
||||
/**
|
||||
* Get the number of delay slot instructions for this
|
||||
* argument. This should be 0 for instructions which don't have a
|
||||
* delay slot. This is used to support the delay slots found on
|
||||
* some RISC processors such as SPARC and the PA-RISC. This
|
||||
* returns an integer instead of a boolean in case some other
|
||||
* processor executes more than one instruction from a delay slot.
|
||||
* {@return the number of delay slot instructions following this instruction}
|
||||
* <p>
|
||||
* This should be 0 for instructions which don't have a delay slot. This is used to support the
|
||||
* delay slots found on some RISC processors such as SPARC and the PA-RISC. This returns an
|
||||
* integer instead of a boolean in case some other processor executes more than one instruction
|
||||
* from a delay slot.
|
||||
*
|
||||
* @param context the instruction context
|
||||
*
|
||||
* @return the number of delay slot instructions for this instruction.
|
||||
*/
|
||||
public int getDelaySlotDepth(InstructionContext context);
|
||||
|
||||
/**
|
||||
* @return the number of delay-slot instruction bytes which correspond
|
||||
* to this prototype.
|
||||
* {@return the number of delay-slot instruction bytes which correspond to this prototype}
|
||||
*/
|
||||
public int getDelaySlotByteCount();
|
||||
|
||||
/**
|
||||
* Return true if this prototype was disassembled in a delay slot.
|
||||
* {@return true if this prototype was disassembled in a delay slot}
|
||||
*/
|
||||
boolean isInDelaySlot();
|
||||
|
||||
/**
|
||||
* Return the number of operands in this instruction.
|
||||
*
|
||||
* {@return the number of operands in this instruction}
|
||||
*/
|
||||
public int getNumOperands();
|
||||
|
||||
/**
|
||||
* Get the type of a specific operand.
|
||||
* {@return the type of a specific operand}
|
||||
*
|
||||
* @param opIndex the index of the operand. (zero based)
|
||||
* @param operandIndex the 0-up index of the operand
|
||||
* @param context the instruction context.
|
||||
* @return the type of the operand.
|
||||
*/
|
||||
public int getOpType(int opIndex, InstructionContext context);
|
||||
public int getOpType(int operandIndex, InstructionContext context);
|
||||
|
||||
/**
|
||||
* Get the Address for default flow after instruction.
|
||||
* {@return the {@link Address} for fall-through flow after this instruction, or null if flow
|
||||
* cannot fall through this instruction}
|
||||
*
|
||||
* @param context the instruction context
|
||||
*
|
||||
* @return Address of fall through flow or null if flow
|
||||
* does not fall through this instruction.
|
||||
*/
|
||||
public Address getFallThrough(InstructionContext context);
|
||||
|
||||
/**
|
||||
* Get the byte offset to the default flow after instruction.
|
||||
* If this instruction does not have a fall-through due to flow
|
||||
* behavior, this method will still return an offset which accounts for
|
||||
* the instruction length including delay slotted instructions if
|
||||
* applicable.
|
||||
* {@return the byte offset to the fall-through flow after this instruction}
|
||||
* <p>
|
||||
* Ordinarily, this is just the length (in bytes) of this instruction. However, if this
|
||||
* instruction has delay-slotted instruction(s), their lengths are included. Even if flow cannot
|
||||
* fall through this instruction, this method will still return a the fall-through offset.
|
||||
*
|
||||
* @param context the instruction context
|
||||
*
|
||||
* @return int how much to add to the current address to get
|
||||
* the fall through address.
|
||||
*/
|
||||
public int getFallThroughOffset(InstructionContext context);
|
||||
|
||||
/**
|
||||
* Get an array of Address objects for all flows other than
|
||||
* a fall-through, null if no flows.
|
||||
* {@return the {@link Address}es for all flows other than a fall-through, or null if no flows}
|
||||
* <p>
|
||||
* A null return is equivalent to an empty array. Note the result may include
|
||||
* {@link Address#NO_ADDRESS} to indicate flow to an address that could not be evaluated, e.g.,
|
||||
* to {@code inst_next2} when the skipped instruction could not be parsed.
|
||||
*
|
||||
* @param context the instruction context.
|
||||
* @return an array of Address objects for all flows other than
|
||||
* a fall-through, null if no flows.
|
||||
*/
|
||||
public Address[] getFlows(InstructionContext context);
|
||||
|
||||
/**
|
||||
* Get the separator strings between an operand.
|
||||
* {@return the separator string before a specific operand, or null}
|
||||
* <p>
|
||||
* In particular, the separator string for operand 0 are the characters <em>before</em> the
|
||||
* first operand. The separator string for {@code numOperands} are the characters <em>after</em>
|
||||
* the last operand. A null return value is equivalent to an empty string.
|
||||
*
|
||||
* The separator string for 0 are the characters before the first operand.
|
||||
* The separator string for numOperands+1 are the characters after the last operand.
|
||||
*
|
||||
* @param opIndex valid values are 0 thru numOperands+1
|
||||
* @return separator string, or null if there is no string
|
||||
* @param operandIndex valid values are 0 thru {@code numOperands}, inclusive
|
||||
*/
|
||||
public String getSeparator(int opIndex);
|
||||
public String getSeparator(int operandIndex);
|
||||
|
||||
/**
|
||||
* Get a List of Objects that can be used to render an operands representation.
|
||||
* {@return a the objects for rendering an operand's representation}
|
||||
* <p>
|
||||
* Each element is one of {@link Address}, {@link Register}, {@link Scalar},
|
||||
* {@link VariableOffset}, {@link Character}, or null. This method may also return null (as in
|
||||
* no list at all) if the operation is not supported. Nulls should be rendered as empty strings.
|
||||
*
|
||||
* @param opIndex operand to get the Representation List
|
||||
* @param operandIndex the 0-up index of the operand
|
||||
* @param context the instruction context
|
||||
*
|
||||
* @return ArrayList of Register, Address, Scalar, VariableOffset and Character objects
|
||||
* of null if the operation isn't supported
|
||||
*/
|
||||
public ArrayList<Object> getOpRepresentationList(int opIndex, InstructionContext context);
|
||||
public ArrayList<Object> getOpRepresentationList(int operandIndex, InstructionContext context);
|
||||
|
||||
/**
|
||||
* If the indicated operand is an address, this gets the address value for
|
||||
* that operand
|
||||
* @param opIndex index of the operand.
|
||||
* {@return the {@link Address} value of a specific operand, or null if its value is not an
|
||||
* {@link Address}}
|
||||
*
|
||||
* @param operandIndex the 0-up index of the operand
|
||||
* @param context the instruction context.
|
||||
* @return the address indicated by the operand
|
||||
*/
|
||||
public Address getAddress(int opIndex, InstructionContext context);
|
||||
public Address getAddress(int operandIndex, InstructionContext context);
|
||||
|
||||
/**
|
||||
* If the indicated operand is a scalar, this gets the scalar value for
|
||||
* that operand
|
||||
* @param opIndex index of the operand.
|
||||
* {@return the {@link Register} value of a specific operand, or null if its value is not an
|
||||
* {@link Register}}
|
||||
*
|
||||
* @param operandIndex the 0-up index of the operand
|
||||
* @param context the instruction context
|
||||
* @return the scalar for the indicated operand
|
||||
*/
|
||||
public Scalar getScalar(int opIndex, InstructionContext context);
|
||||
public Register getRegister(int operandIndex, InstructionContext context);
|
||||
|
||||
/**
|
||||
* If the indicated operand is a register, this gets the register value
|
||||
* for that operand
|
||||
* @param opIndex index of the operand.
|
||||
* {@return the {@link Scalar} value of a specific operand, or null if its value is not an
|
||||
* {@link Scalar}}
|
||||
*
|
||||
* @param operandIndex the 0-up index of the operand
|
||||
* @param context the instruction context
|
||||
* @return a register description for the indicated operand
|
||||
*/
|
||||
public Register getRegister(int opIndex, InstructionContext context);
|
||||
public Scalar getScalar(int operandIndex, InstructionContext context);
|
||||
|
||||
/**
|
||||
* Get objects used by this operand (Address, Scalar, Register ...)
|
||||
* @param opIndex the index of the operand. (zero based)
|
||||
* {@return the objects used by a specific operand}
|
||||
* <p>
|
||||
* Each element is one of {@link Address}, {@link Register}, {@link Scalar}, or
|
||||
* {@link VariableOffset}.
|
||||
*
|
||||
* @param operandIndex the 0-up index of the operand
|
||||
* @param context the instruction context
|
||||
* @return an array of objects found at this operand.
|
||||
*/
|
||||
public Object[] getOpObjects(int opIndex, InstructionContext context);
|
||||
public Object[] getOpObjects(int operandIndex, InstructionContext context);
|
||||
|
||||
/**
|
||||
* Get the suggested operand reference type.
|
||||
* @param opIndex the index of the operand. (zero based)
|
||||
* {@return the suggested reference type for a specific operand}
|
||||
*
|
||||
* @param operandIndex the 0-up index of the operand
|
||||
* @param context the instruction context
|
||||
* @param override if not null, steers local overrides of pcode generation
|
||||
* @return reference type.
|
||||
* @param override if not null, steers local overrides of p-code generation
|
||||
*/
|
||||
public RefType getOperandRefType(int opIndex, InstructionContext context,
|
||||
public RefType getOperandRefType(int operandIndex, InstructionContext context,
|
||||
PcodeOverride override);
|
||||
|
||||
/**
|
||||
* Return true if the operand at opIndex should have a delimiter following it.
|
||||
* @param opIndex the index of the operand to test for having a delimiter.
|
||||
* {@return true if a specific operand ought to have a delimiter following it}
|
||||
*
|
||||
* @param operandIndex the 0-up index of the operand
|
||||
*/
|
||||
public boolean hasDelimeter(int opIndex);
|
||||
public boolean hasDelimeter(int operandIndex);
|
||||
|
||||
/**
|
||||
* Get the Result objects produced/affected by this instruction
|
||||
* These would probably only be Register or Address
|
||||
* {@return the objects used as input by this instruction}
|
||||
* <p>
|
||||
* Each element should probably only be one of {@link Address} or {@link Register}.
|
||||
*
|
||||
* @param context the instruction context
|
||||
*
|
||||
* @return an array of objects that are used by this instruction
|
||||
*/
|
||||
public Object[] getInputObjects(InstructionContext context);
|
||||
|
||||
/**
|
||||
* Get the Result objects produced/affected by this instruction
|
||||
* These would probably only be Register or Address
|
||||
* {@return the objects affected by this instruction}
|
||||
* <p>
|
||||
* Each element should probably only be one of {@link Address} or {@link Register}.
|
||||
*
|
||||
* @param context the instruction context
|
||||
*
|
||||
* @return an array of objects that are affected by this instruction
|
||||
*/
|
||||
public Object[] getResultObjects(InstructionContext context);
|
||||
|
||||
/**
|
||||
* Get an array of PCode operations (micro code) that this instruction
|
||||
* performs.
|
||||
* {@return the p-code operations (micro code) that this instruction performs}
|
||||
* <p>
|
||||
* This will return an empty array if the language does not support p-code for this instruction.
|
||||
*
|
||||
* @param context the instruction context
|
||||
* @param override if not null, may indicate that different elements of the pcode generation are overridden
|
||||
* @return array of PCODE,
|
||||
* zero length array if language doesn't support PCODE for this instruction
|
||||
* @param override if not null, may indicate that different elements of the pcode generation are
|
||||
* overridden
|
||||
*/
|
||||
public PcodeOp[] getPcode(InstructionContext context, PcodeOverride override);
|
||||
|
||||
/**
|
||||
* Same as getPcode but emits the operations directly to an encoder to optimize transfer to other processes
|
||||
* Does the same as {@link #getPcode(InstructionContext, PcodeOverride)} but emits the
|
||||
* operations directly to an encoder to optimize transfer to other processes}
|
||||
*
|
||||
* @param encoder is the encoder receiving the operations
|
||||
* @param context the instruction context
|
||||
* @param override if not null, may indicate that different elements of the pcode generation are overridden
|
||||
* @param override if not null, may indicate that different elements of the pcode generation are
|
||||
* overridden
|
||||
* @throws IOException for errors writing to any stream underlying the encoder
|
||||
*/
|
||||
public void getPcodePacked(PatchEncoder encoder, InstructionContext context,
|
||||
PcodeOverride override) throws IOException;
|
||||
|
||||
/**
|
||||
* Get an array of PCode operations (micro code) that a particular operand
|
||||
* performs to compute its value.
|
||||
* {@return the p-code operations (micro code) that perform the computation of a particular
|
||||
* operand's value}
|
||||
*
|
||||
* @param context the instruction context
|
||||
* @param opIndex the index of the operand for which to get PCode.
|
||||
*
|
||||
* @return array of PCODE,
|
||||
* zero length array if language doesn't support PCODE for this instruction
|
||||
* @param operandIndex the 0-up index of the operand
|
||||
*/
|
||||
public PcodeOp[] getPcode(InstructionContext context, int opIndex);
|
||||
public PcodeOp[] getPcode(InstructionContext context, int operandIndex);
|
||||
|
||||
/**
|
||||
* Get processor language module associated with this prototype.
|
||||
* @return language module
|
||||
* {@return the processor language module associated with this prototype}
|
||||
*/
|
||||
public Language getLanguage();
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ public class InvalidPrototype implements InstructionPrototype, ParserContext {
|
||||
|
||||
/**
|
||||
* Construct a new invalid instruction prototype.
|
||||
*
|
||||
* @param lang is the Language for which the invalid instruction is discovered
|
||||
*/
|
||||
public InvalidPrototype(Language lang) {
|
||||
@@ -54,6 +55,11 @@ public class InvalidPrototype implements InstructionPrototype, ParserContext {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext2Dependency() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mask getInstructionMask() {
|
||||
return null;
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -35,26 +35,29 @@ public interface Instruction extends CodeUnit, ProcessorContext {
|
||||
public static final int MAX_LENGTH_OVERRIDE = 7;
|
||||
|
||||
/**
|
||||
* @return the prototype for this instruction.
|
||||
* {@return the prototype for this instruction}
|
||||
*/
|
||||
public InstructionPrototype getPrototype();
|
||||
|
||||
/**
|
||||
* If operand is a pure Register, return the register.
|
||||
* @param opIndex index of the operand.
|
||||
* @return A register if the operand represents a register.
|
||||
* If a specific operand is a pure {@link Register}, return it
|
||||
*
|
||||
* @param operandIndex the 0-up index of the operand.
|
||||
* @return the register or null
|
||||
*/
|
||||
public Register getRegister(int opIndex);
|
||||
public Register getRegister(int operandIndex);
|
||||
|
||||
/**
|
||||
* Get objects used by this operand (Address, Scalar, Register ...)
|
||||
* @param opIndex index of the operand.
|
||||
*
|
||||
* @param operandIndex index of the operand.
|
||||
* @return objects used by this operand (Address, Scalar, Register ...)
|
||||
*/
|
||||
public Object[] getOpObjects(int opIndex);
|
||||
public Object[] getOpObjects(int operandIndex);
|
||||
|
||||
/**
|
||||
* Get the Input objects used by this instruction.
|
||||
* <p>
|
||||
* These could be Scalars, Registers, Addresses
|
||||
*
|
||||
* @return an array of objects that are used by this instruction
|
||||
@@ -63,6 +66,7 @@ public interface Instruction extends CodeUnit, ProcessorContext {
|
||||
|
||||
/**
|
||||
* Get the Result objects produced/affected by this instruction
|
||||
* <p>
|
||||
* These would probably only be Register or Address
|
||||
*
|
||||
* @return an array of objects that are affected by this instruction
|
||||
@@ -72,81 +76,86 @@ public interface Instruction extends CodeUnit, ProcessorContext {
|
||||
/**
|
||||
* Get the operand representation for the given operand index without markup.
|
||||
*
|
||||
* @param opIndex operand index
|
||||
*
|
||||
* @param operandIndex operand index
|
||||
* @return operand represented as a string.
|
||||
*/
|
||||
public String getDefaultOperandRepresentation(int opIndex);
|
||||
public String getDefaultOperandRepresentation(int operandIndex);
|
||||
|
||||
/**
|
||||
* Get the operand representation for the given operand index.
|
||||
* A list of Register, Address, Scalar, Character and String objects is returned - without markup!
|
||||
* <p>
|
||||
* A list of Register, Address, Scalar, Character and String objects is returned - without
|
||||
* markup!
|
||||
*
|
||||
* @param opIndex operand index
|
||||
*
|
||||
* @return ArrayList of pieces of the operand representation. Unsupported languages may return null.
|
||||
* @param operandIndex operand index
|
||||
* @return ArrayList of pieces of the operand representation. Unsupported languages may return
|
||||
* null.
|
||||
*/
|
||||
public List<Object> getDefaultOperandRepresentationList(int opIndex);
|
||||
public List<Object> getDefaultOperandRepresentationList(int operandIndex);
|
||||
|
||||
/**
|
||||
* Get the separator strings between an operand.
|
||||
* <p>
|
||||
* The separator string for 0 are the characters before the first operand. The separator string
|
||||
* for numOperands+1 are the characters after the last operand.
|
||||
*
|
||||
* The separator string for 0 are the characters before the first operand.
|
||||
* The separator string for numOperands+1 are the characters after the last operand.
|
||||
*
|
||||
* @param opIndex valid values are 0 thru numOperands+1
|
||||
* @param operandIndex valid values are 0 thru numOperands+1
|
||||
* @return separator string, or null if there is no string
|
||||
*/
|
||||
public String getSeparator(int opIndex);
|
||||
public String getSeparator(int operandIndex);
|
||||
|
||||
/**
|
||||
* Get the type of a specific operand.
|
||||
*
|
||||
* @param opIndex the index of the operand. (zero based)
|
||||
* @param operandIndex the index of the operand. (zero based)
|
||||
* @return the type of the operand.
|
||||
*
|
||||
* @see OperandType
|
||||
*/
|
||||
public int getOperandType(int opIndex);
|
||||
public int getOperandType(int operandIndex);
|
||||
|
||||
/**
|
||||
* Get the operand reference type for the given operand index.
|
||||
* @param index operand index
|
||||
*
|
||||
* @param operandIndex operand index
|
||||
* @return the operand reference type for the given operand index.
|
||||
*/
|
||||
public RefType getOperandRefType(int index);
|
||||
public RefType getOperandRefType(int operandIndex);
|
||||
|
||||
/**
|
||||
* Get default fall-through offset in bytes from start of instruction to the
|
||||
* fallthrough instruction. This accounts for any
|
||||
* instructions contained with delay slots.
|
||||
* @return default fall-through offset or zero (0) if instruction has no fallthrough
|
||||
* Get default fall-through offset in bytes from start of instruction to the fall-through
|
||||
* instruction.
|
||||
* <p>
|
||||
* This accounts for any instructions contained with delay slots.
|
||||
*
|
||||
* @return default fall-through offset or zero (0) if instruction has no fall through
|
||||
*/
|
||||
public int getDefaultFallThroughOffset();
|
||||
|
||||
/**
|
||||
* Get the default fallthrough for this instruction.
|
||||
* Get the default fall through for this instruction.
|
||||
* <p>
|
||||
* This accounts for any instructions contained with delay slots.
|
||||
* @return fall-through address or null if instruction has no default fallthrough
|
||||
*
|
||||
* @return fall-through address or null if instruction has no default fall through
|
||||
*/
|
||||
public Address getDefaultFallThrough();
|
||||
|
||||
/**
|
||||
* Get the fallthrough for this instruction, factoring in
|
||||
* any fallthrough override and delay slotted instructions.
|
||||
* @return fall-through address or null if instruction has no fallthrough
|
||||
* Get the fall through for this instruction, factoring in any fall-through override and delay
|
||||
* slotted instructions.
|
||||
*
|
||||
* @return fall-through address or null if instruction has no fall through
|
||||
*/
|
||||
public Address getFallThrough();
|
||||
|
||||
/**
|
||||
* @return the Address for the instruction that fell through to
|
||||
* this instruction.
|
||||
* This is useful for handling instructions that are found
|
||||
* in a delay slot.
|
||||
* {@return the {@link Address} for the instruction that fell through to this instruction}
|
||||
* <p>
|
||||
* This is useful for handling instructions that are found in a delay slot.
|
||||
* <p>
|
||||
* Note: if an instruction is in a delay slot, then it may have a branch into the delay slot,
|
||||
* which is handled as follows
|
||||
*
|
||||
* Note: if an instruction is in a delayslot, then it may have
|
||||
* a branch into the delayslot, which is handled as follows
|
||||
*
|
||||
* <pre>
|
||||
* JMPIF Y, X
|
||||
* lab:
|
||||
@@ -165,187 +174,207 @@ public interface Instruction extends CodeUnit, ProcessorContext {
|
||||
* JMP Y, X
|
||||
* _ADD getFallFrom() = JMP
|
||||
* MOV getFallFrom() = null
|
||||
*</pre>
|
||||
* </pre>
|
||||
*/
|
||||
public Address getFallFrom();
|
||||
|
||||
/**
|
||||
* Get an array of Address objects for all flows other than
|
||||
* a fall-through. This will include any flow references which
|
||||
* have been added to the instruction.
|
||||
* @return flow addresses or null if there are no flows
|
||||
* Get an array of {@link Address}es for all flows other than a fall-through.
|
||||
* <p>
|
||||
* This will include any flow references which have been added to the instruction. Note the
|
||||
* result may include {@link Address#NO_ADDRESS} to indicate flow to an address that could not
|
||||
* be evaluated, e.g., to {@code inst_next2} when the skipped instruction could not be parsed.
|
||||
*
|
||||
* @return flow addresses or null if there are no flows
|
||||
*/
|
||||
public Address[] getFlows();
|
||||
|
||||
/**
|
||||
* Get an array of Address objects for all default flows established
|
||||
* by the underlying instruction prototype. References are ignored.
|
||||
* @return flow addresses or null if there are no flows
|
||||
* Get an array of {@link Address}es for all default flows established by the underlying
|
||||
* instruction prototype.
|
||||
* <p>
|
||||
* References are ignored. Note the result may include {@link Address#NO_ADDRESS} to indicate
|
||||
* flow to an address that could not be evaluated, e.g., to {@code inst_next2} when the skipped
|
||||
* instruction could not be parsed.
|
||||
*
|
||||
* @return flow addresses or null if there are no flows
|
||||
*/
|
||||
public Address[] getDefaultFlows();
|
||||
|
||||
/**
|
||||
* @return the flow type of this instruction (how this
|
||||
* instruction flows to the next instruction).
|
||||
* {@return the flow type of this instruction (how this instruction flows to the next
|
||||
* instruction)}
|
||||
*/
|
||||
public FlowType getFlowType();
|
||||
|
||||
/**
|
||||
* @return true if this instruction has no execution flow other than fall-through.
|
||||
* {@return true if this instruction has no execution flow other than fall-through}
|
||||
*/
|
||||
public boolean isFallthrough();
|
||||
|
||||
/**
|
||||
* @return true if this instruction has a fall-through flow.
|
||||
* {@return true if this instruction has a fall-through flow}
|
||||
*/
|
||||
public boolean hasFallthrough();
|
||||
|
||||
/**
|
||||
* @return the flow override which may have been set on this instruction.
|
||||
* {@return the flow override which may have been set on this instruction}
|
||||
*/
|
||||
public FlowOverride getFlowOverride();
|
||||
|
||||
/**
|
||||
* Set the flow override for this instruction.
|
||||
*
|
||||
* @param flowOverride flow override setting or {@link FlowOverride#NONE} to clear.
|
||||
*/
|
||||
public void setFlowOverride(FlowOverride flowOverride);
|
||||
|
||||
/**
|
||||
* Set instruction length override. Specified length must be in the range 0..7 where 0 clears
|
||||
* the setting and adopts the default length. The specified length must be less than the actual
|
||||
* number of bytes consumed by the prototype and be a multiple of the language specified
|
||||
* instruction alignment.
|
||||
* Set instruction length override.
|
||||
* <p>
|
||||
* Specified length must be in the range 0..7 where 0 clears the setting and adopts the default
|
||||
* length. The specified length must be less than the actual number of bytes consumed by the
|
||||
* prototype and be a multiple of the language specified instruction alignment.
|
||||
* <p>
|
||||
* NOTE: Use of the feature with a delay slot instruction is discouraged.
|
||||
*
|
||||
* @param length effective instruction code unit length.
|
||||
* @throws CodeUnitInsertionException if expanding instruction length conflicts with another
|
||||
* instruction or length is not a multiple of the language specified instruction alignment.
|
||||
* @throws CodeUnitInsertionException if expanding instruction length conflicts with another
|
||||
* instruction or length is not a multiple of the language specified instruction
|
||||
* alignment.
|
||||
*/
|
||||
public void setLengthOverride(int length) throws CodeUnitInsertionException;
|
||||
|
||||
/**
|
||||
* Determine if an instruction length override has been set.
|
||||
*
|
||||
* @return true if length override has been set else false.
|
||||
*/
|
||||
public boolean isLengthOverridden();
|
||||
|
||||
/**
|
||||
* Get the actual number of bytes parsed when forming this instruction. While this method
|
||||
* will generally return the same value as {@link #getLength()}, its value will differ when
|
||||
* {@link #setLengthOverride(int)} has been used. In addition, it is important to note that
|
||||
* {@link #getMaxAddress()} will always reflect a non-overlapping address which reflects
|
||||
* {@link #getLength()}.
|
||||
* Get the actual number of bytes parsed when forming this instruction.
|
||||
* <p>
|
||||
* While this method will generally return the same value as {@link #getLength()}, its value
|
||||
* will differ when {@link #setLengthOverride(int)} has been used. In addition, it is important
|
||||
* to note that {@link #getMaxAddress()} will always reflect a non-overlapping address which
|
||||
* reflects {@link #getLength()}.
|
||||
* <p>
|
||||
* This method is equivalent to the following code for a given instruction:
|
||||
* <br>
|
||||
*
|
||||
* <pre>
|
||||
* {@link InstructionPrototype} proto = instruction.{@link #getPrototype()};
|
||||
* int length = proto.{@link InstructionPrototype#getLength() getLength()};
|
||||
* </pre>
|
||||
*
|
||||
* @return the actual number of bytes parsed when forming this instruction
|
||||
*/
|
||||
public int getParsedLength();
|
||||
|
||||
/**
|
||||
* Get the actual bytes parsed when forming this instruction. While this method
|
||||
* will generally return the same value as {@link #getBytes()}, it will return more bytes when
|
||||
* {@link #setLengthOverride(int)} has been used. In this override situation, the bytes
|
||||
* returned will generally duplicate some of the parsed bytes associated with the next
|
||||
* Get the actual bytes parsed when forming this instruction.
|
||||
* <p>
|
||||
* While this method will generally return the same value as {@link #getBytes()}, it will return
|
||||
* more bytes when {@link #setLengthOverride(int)} has been used. In this override situation,
|
||||
* the bytes returned will generally duplicate some of the parsed bytes associated with the next
|
||||
* instruction that this instruction overlaps.
|
||||
* <p>
|
||||
* This method is equivalent to the following code for a given instruction:
|
||||
* <br>
|
||||
*
|
||||
* <pre>
|
||||
* {@link InstructionPrototype} proto = instruction.{@link #getPrototype()};
|
||||
* {@link Memory} mem = instruction.{@link #getMemory()};
|
||||
* byte[] bytes = mem.getBytes(instruction.{@link #getAddress()}, proto.getLength());
|
||||
* int length = proto.{@link InstructionPrototype#getLength() getLength()};
|
||||
* </pre>
|
||||
*
|
||||
* @return the actual number of bytes parsed when forming this instruction
|
||||
* @throws MemoryAccessException if the full number of bytes could not be read
|
||||
*/
|
||||
public byte[] getParsedBytes() throws MemoryAccessException;
|
||||
|
||||
/**
|
||||
* Get an array of PCode operations (micro code) that this instruction
|
||||
* performs. Flow overrides are not factored into pcode.
|
||||
* Get an array of p-code operations (micro code) that this instruction performs.
|
||||
* <p>
|
||||
* Flow overrides are not factored into p-code.
|
||||
*
|
||||
* @return an array of Pcode operations,
|
||||
* a zero length array if the language does not support PCode
|
||||
* @return an array of p-code operations, a zero length array if the language does not support
|
||||
* p-code
|
||||
*/
|
||||
public PcodeOp[] getPcode();
|
||||
|
||||
/**
|
||||
* Get an array of PCode operations (micro code) that this instruction
|
||||
* performs. NOTE: If includeOverrides is true, unique temporary varnodes
|
||||
* may be produced which vary in size to those produced for other instructions.
|
||||
* @param includeOverrides if true any flow overrides will be factored
|
||||
* into generated pcode.
|
||||
* @return an array of Pcode operations,
|
||||
* a zero length array if the language does not support PCode
|
||||
* Get an array of p-code operations (micro code) that this instruction performs.
|
||||
* <p>
|
||||
* NOTE: If includeOverrides is true, unique temporary varnodes may be produced which vary in
|
||||
* size to those produced for other instructions.
|
||||
*
|
||||
* @param includeOverrides if true any flow overrides will be factored into generated p-code.
|
||||
* @return an array of p-code operations, a zero length array if the language does not support
|
||||
* p-code
|
||||
*/
|
||||
public PcodeOp[] getPcode(boolean includeOverrides);
|
||||
|
||||
/**
|
||||
* Get an array of PCode operations (micro code) that a particular operand
|
||||
* performs to compute its value.
|
||||
* Get an array of p-code operations (micro code) that a particular operand performs to compute
|
||||
* its value.
|
||||
*
|
||||
* @param opIndex index of the operand to retrieve PCode
|
||||
* @param operandIndex index of the operand to retrieve p-code
|
||||
*
|
||||
* @return an array of PCode operations,
|
||||
* a zero length array if the language does not support PCode
|
||||
* @return an array of p-code operations, a zero length array if the language does not support
|
||||
* p-code
|
||||
*/
|
||||
public PcodeOp[] getPcode(int opIndex);
|
||||
public PcodeOp[] getPcode(int operandIndex);
|
||||
|
||||
/**
|
||||
* Get the number of delay slot instructions for this
|
||||
* argument. This should be 0 for instructions which don't have a
|
||||
* delay slot. This is used to support the delay slots found on
|
||||
* some RISC processors such as SPARC and the PA-RISC. This
|
||||
* returns an integer instead of a boolean in case some other
|
||||
* processor executes more than one instruction from a delay slot.
|
||||
* Get the number of delay slot instructions for this argument.
|
||||
* <p>
|
||||
* This should be 0 for instructions which don't have a delay slot. This is used to support the
|
||||
* delay slots found on some RISC processors such as SPARC and the PA-RISC. This returns an
|
||||
* integer instead of a boolean in case some other processor executes more than one instruction
|
||||
* from a delay slot.
|
||||
*
|
||||
* @return delay slot depth (number of instructions)
|
||||
*/
|
||||
public int getDelaySlotDepth();
|
||||
|
||||
/**
|
||||
* @return true if this instruction was disassembled in a delay slot
|
||||
* {@return true if this instruction was disassembled in a delay slot}
|
||||
*/
|
||||
public boolean isInDelaySlot();
|
||||
|
||||
/**
|
||||
* @return the instruction following this one in address order or null if none found.
|
||||
* {@return the instruction following this one in address order or null if none found}
|
||||
*/
|
||||
public Instruction getNext();
|
||||
|
||||
/**
|
||||
* @return the instruction before this one in address order or null if none found.
|
||||
* {@return the instruction before this one in address order or null if none found}
|
||||
*/
|
||||
public Instruction getPrevious();
|
||||
|
||||
/**
|
||||
* Overrides the instruction's default fallthrough address to the given address.
|
||||
* The given address may be null to indicate that the instruction has no fallthrough.
|
||||
* @param addr the address to be used as this instructions fallthrough address. May be null.
|
||||
* Override the instruction's default fall-through address to the given address.
|
||||
* <p>
|
||||
* The given address may be null to indicate that the instruction has no fall through.
|
||||
*
|
||||
* @param addr the address to be used as this instructions fall-through address. May be null.
|
||||
*/
|
||||
public void setFallThrough(Address addr);
|
||||
|
||||
/**
|
||||
* Restores this instruction's fallthrough address back to the default fallthrough
|
||||
* for this instruction.
|
||||
*
|
||||
* Restores this instruction's fall-through address back to the default fall through for this
|
||||
* instruction.
|
||||
*/
|
||||
public void clearFallThroughOverride();
|
||||
|
||||
/**
|
||||
* @return true if this instructions fallthrough has been overriden.
|
||||
* {@return true if this instruction's fall through has been overridden}
|
||||
*/
|
||||
public boolean isFallThroughOverridden();
|
||||
|
||||
/**
|
||||
* @return the instruction context for this instruction
|
||||
* {@return the instruction context for this instruction}
|
||||
*/
|
||||
public InstructionContext getInstructionContext();
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user