diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/pcode/exec/trace/BytesTracePcodeEmulatorTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/pcode/exec/trace/BytesTracePcodeEmulatorTest.java index de68c57550..55adbeaf23 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/pcode/exec/trace/BytesTracePcodeEmulatorTest.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/pcode/exec/trace/BytesTracePcodeEmulatorTest.java @@ -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 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 * diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighInstructionPrototype.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighInstructionPrototype.java index 1870351fec..4d1d0a9c6c 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighInstructionPrototype.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighInstructionPrototype.java @@ -62,12 +62,14 @@ public class SleighInstructionPrototype implements InstructionPrototype { static public class FlowSummary { public int delay; public boolean hasCrossBuilds; + public boolean hasNext2; public ArrayList 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> 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 */ diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighParserContext.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighParserContext.java index a125bfc4e4..7368e18b25 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighParserContext.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/processors/sleigh/SleighParserContext.java @@ -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 + *

* 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 diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/util/PseudoInstruction.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/util/PseudoInstruction.java index 92c8dc4868..378739306e 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/util/PseudoInstruction.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/util/PseudoInstruction.java @@ -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() { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/InstructionPrototype.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/InstructionPrototype.java index ef9444bb79..3910e1828d 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/InstructionPrototype.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/InstructionPrototype.java @@ -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} + *

+ * 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} + *

+ * 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} + *

+ * 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} + *

+ * 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} + *

+ * 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} + *

+ * In particular, the separator string for operand 0 are the characters before the + * first operand. The separator string for {@code numOperands} are the characters after + * 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} + *

+ * 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 getOpRepresentationList(int opIndex, InstructionContext context); + public ArrayList 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} + *

+ * 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} + *

+ * 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} + *

+ * 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} + *

+ * 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(); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/InvalidPrototype.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/InvalidPrototype.java index d7a12bfdfb..e5c08e6228 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/InvalidPrototype.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/InvalidPrototype.java @@ -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; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Instruction.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Instruction.java index 7e9c84ab8a..8203d29ff5 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Instruction.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Instruction.java @@ -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. + *

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

* 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! + *

+ * 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 getDefaultOperandRepresentationList(int opIndex); + public List getDefaultOperandRepresentationList(int operandIndex); /** * Get the separator strings between an 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. * - * 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. + *

+ * 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. + *

* 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} + *

+ * This is useful for handling instructions that are found in a delay slot. + *

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

 	 * JMPIF Y, X
 	 *   lab:
@@ -165,187 +174,207 @@ public interface Instruction extends CodeUnit, ProcessorContext {
 	 * JMP Y, X
 	 *     _ADD         getFallFrom() = JMP
 	 * MOV              getFallFrom() = null
-	 *
+ * */ 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. + *

+ * 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. + *

+ * 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. + *

+ * 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. *

* 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. + *

+ * 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()}. + *

* This method is equivalent to the following code for a given instruction: - *
+ * *

 	 * {@link InstructionPrototype} proto = instruction.{@link #getPrototype()};
 	 * int length = proto.{@link InstructionPrototype#getLength() getLength()};
 	 * 
+ * * @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. + *

+ * 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. + *

* This method is equivalent to the following code for a given instruction: - *
+ * *

 	 * {@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()};
 	 * 
+ * * @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. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

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