Interface IDInstruction

All Superinterfaces:
IDElement, IDExpression, IInstruction, IInstructionOperand, ILocatedInstruction

public interface IDInstruction extends IDExpression, ILocatedInstruction
dexdec IR instruction object. Each intermediate representation instruction has:
- an opcode: refer to DOpcodeType
- zero, one, or two operands, of type IDElement
- an offset (in the IR)
- a size

IR CFGs consist of basic blocks made of IR instructions. An IDMethodContext references it IR CFG. IR instructions can also be created via the createXxx methods of the context object.

When creating IR instructions, the default size is set to 1. The offset is not set (-1), and needs to be set manually. The size of an IR instruction can be set to any strictly positive value. In a CFG, it is important that all instructions be contiguous (i.e. there is no gap): if an instruction has offset O and size S, the next instruction must be at offset O+S.

  • Field Details

    • KEEP_INSTRUCTION

      static final String KEEP_INSTRUCTION
      This boolean attribute can be set by optimizers on jump and jcond instructions. When True, optimizers should do their best to not remove the instruction.
      See Also:
  • Method Details

    • duplicate

      IDInstruction duplicate()
      Deep copy of this instruction.
      Specified by:
      duplicate in interface IDElement
      Specified by:
      duplicate in interface IDExpression
      Returns:
      a deep copy of this element; the type of the duplicated element should be the same as this element's type
    • copy

      Description copied from interface: IDElement
      Copy this element. This operation can be seen as a custom duplication; the resulting element may not be of the same type as this element.
      Specified by:
      copy in interface IDElement
      Specified by:
      copy in interface IDExpression
      Parameters:
      opt - optional; if one is provided, DCopyOptions.onDup(IDExpression) will be tried first to create a copy
      Returns:
      the copied element
    • duplicateForReplacement

      IDInstruction duplicateForReplacement(IDInstruction replacedInsn)
      Duplicate this instruction with the intent to replace the source instruction. The offset and size of the source instruction are copied over to the newly created instruction.
      Returns:
    • duplicateWithOffsetAndSize

      IDInstruction duplicateWithOffsetAndSize(long offset, int size)
      Parameters:
      offset -
      size -
      Returns:
    • copyBaseFields

      void copyBaseFields(IDInstruction sourceInsn)
      Copy all base fields, that is all fields but the opcode and operands of the source instruction to this instruction.
      Parameters:
      sourceInsn -
    • getContext

      IDMethodContext getContext()
      Retrieve the IR method context to which this instruction belongs. The method context holds all information regarding a current method decompilation. It is also a factory to create more IDInstruction objects.
      Returns:
    • setContext

      Update the instruction context. It is important to update the context when transferring the instructions from a CFG (from context A) to another CFG (of contextB).
      Parameters:
      ctx - new context
      Returns:
      the previous context
    • getOffset

      long getOffset()
      IR offsets are 32-bit integers; they can be safely cast to int.
      Specified by:
      getOffset in interface ILocatedInstruction
      Returns:
      the instruction offset/address
    • getOffsetEnd

      long getOffsetEnd()
      Retrieve the end offset (exclusive) of this instruction
      Specified by:
      getOffsetEnd in interface ILocatedInstruction
      Returns:
      getOffset() + IInstruction.getSize()
    • setOffset

      void setOffset(long offset)
      Set this instruction's IR offset. Dangerous method. Make sure to ensure CFG consistency if this instruction is part of a CFG.
      Parameters:
      offset -
    • withOffset

      IDInstruction withOffset(long offset)
      Update the instruction offset.
      Parameters:
      offset - new offset
      Returns:
      this object
    • setSize

      void setSize(int size)
      Set this instruction's IR size. Dangerous method. Make sure to ensure CFG consistency if this instruction is part of a CFG.
      Parameters:
      size - new size
    • withSize

      IDInstruction withSize(int size)
      Update the instruction size.
      Parameters:
      size - new size
      Returns:
      this object
    • adjustSize

      void adjustSize(int delta)
      Adjust this instruction's IR size. Dangerous method. Make sure to ensure CFG consistency if this instruction is part of a CFG.
      Parameters:
      delta - added to the current size
    • getOpcode

      DOpcodeType getOpcode()
      Get this instruction opcode.
      Returns:
    • setOpcode

      void setOpcode(DOpcodeType opcode)
      Change the instruction opcode. This method is dangerous. Instruction operands may require an update as well.
      Parameters:
      opcode -
    • isOpcode

      boolean isOpcode(DOpcodeType... candidateOpcodes)
      Determine if this instruction's opcode is any of the provided candidates.
      Parameters:
      candidateOpcodes - a list of candidate opcodes
      Returns:
      true if this instruction's opcode was one of the candidates
    • getOperand1

      IDElement getOperand1()
      Get the first operand. May be null if the opcode does not specify one. Refer to getOpcode() and DOpcodeType.
      Returns:
    • setOperand1

      void setOperand1(IDElement opnd)
      Change the instruction first operand. This method is dangerous. Other instruction attributes may require an update as well.
      Parameters:
      opnd -
    • getOperand2

      IDElement getOperand2()
      Get the second operand. May be null if the opcode does not specify one. Refer to getOpcode() and DOpcodeType.
      Returns:
    • setOperand2

      void setOperand2(IDElement opnd)
      Change the instruction second operand. This method is dangerous. Other instruction attributes may require an update as well.
      Parameters:
      opnd -
    • hasUseSideEffects

      boolean hasUseSideEffects(boolean includeCanThrow)
      Determine whether the used components of the statement may have side-effects.

      This method is not fail-safe, it works on a best-effort basis. Refer to IDExpression.hasSideEffects(IDMethodContext, boolean) for more information.

      Parameters:
      includeCanThrow -
      Returns:
    • isNop

      boolean isNop()
      Returns:
      true if this instruction is a nop
    • isAssign

      boolean isAssign()
      Returns:
      true if this instruction is an assignment
    • getAssignDestination

      IDExpression getAssignDestination()
    • setAssignDestination

      IDExpression setAssignDestination(IDExpression dst)
    • getAssignSource

      IDExpression getAssignSource()
    • setAssignSource

      IDExpression setAssignSource(IDExpression src)
    • isAssignToVar

      default boolean isAssignToVar()
    • isAssignToVar

      default boolean isAssignToVar(int wantedVarId)
    • isAssignFromVar

      default boolean isAssignFromVar()
    • isAssignFromVar

      default boolean isAssignFromVar(int wantedVarId)
    • isAssignFromVarToVar

      default boolean isAssignFromVarToVar()
    • isAssignFromVarToVar

      default boolean isAssignFromVarToVar(int wantedSrcVarId, int wantedDstVarId)
    • isInvoke

      boolean isInvoke()
      Returns:
      true if this instruction is an invocation (call, new, new-array, alloc-object)
    • getInvokeData

      IDInvokeInfo getInvokeData()
      Returns:
      the invocation information, if the instruction is an invocation
    • setBranchTarget

      int setBranchTarget(int offset)
      Update the branch target for unconditional and conditional jumps only. This function fails for all other opcodes, including switches.
      Parameters:
      offset - the new offset
      Returns:
      previous value
    • getBranchTarget

      int getBranchTarget()
    • isJump

      boolean isJump()
      Returns:
      true if this instruction is a jump (goto)
    • isJumpTo

      boolean isJumpTo(int wantedTarget)
    • isJcond

      boolean isJcond()
      Returns:
      true if this instruction is a conditional jump
    • isJcondTo

      boolean isJcondTo(int wantedTarget)
    • isJumpOrJcond

      boolean isJumpOrJcond()
    • isJumpOrJcondTo

      boolean isJumpOrJcondTo(int wantedTarget)
    • isJcondOrSwitch

      boolean isJcondOrSwitch()
    • getJcondCondition

      IDExpression getJcondCondition()
      Get the condition predicate (if the instruction is a JCOND).
      Returns:
    • setJcondCondition

      IDExpression setJcondCondition(IDExpression cond)
      Parameters:
      cond -
      Returns:
    • reverseJcondCondition

      void reverseJcondCondition()
    • isSwitch

      boolean isSwitch()
      Returns:
      true if this instruction is a switch
    • isSwitchOnInt

      boolean isSwitchOnInt()
    • isSwitchOnString

      boolean isSwitchOnString()
    • getSwitchData

      IDSwitchData getSwitchData()
    • setSwitchData

      IDSwitchData setSwitchData(IDSwitchData swdata)
    • getSwitchExpression

      IDExpression getSwitchExpression()
    • setSwitchExpression

      IDExpression setSwitchExpression(IDExpression exp)
    • isReturn

      boolean isReturn()
      Returns:
      true if this instruction is a return
    • getReturnExpression

      IDExpression getReturnExpression()
    • setReturnExpression

      IDExpression setReturnExpression(IDExpression exp)
    • isThrow

      boolean isThrow()
      Returns:
      true if this instruction is a throw
    • getThrowExpression

      IDExpression getThrowExpression()
    • setThrowExpression

      IDExpression setThrowExpression(IDExpression exp)
    • isReturnOrThrow

      boolean isReturnOrThrow()
    • isStoreException

      boolean isStoreException()
      Returns:
      true if this instruction is a store-exception (special opcode)
    • getStoredExceptionVariable

      IDVar getStoredExceptionVariable()
      Returns:
      the exception variable set up by a store-exception instruction
    • setStoredExceptionVariable

      IDVar setStoredExceptionVariable(IDVar ex)
      Parameters:
      ex - a new exception variable for a store-exception instruction
      Returns:
      the previous variable
    • isMonitorEnter

      boolean isMonitorEnter()
      Returns:
      true if this instruction is a monitor-enter
    • isMonitorExit

      boolean isMonitorExit()
      Returns:
      true if this instruction is a monitor-exit
    • transformToNop

      void transformToNop()
      Transform any instruction to a NOP.
    • transformJcondToJump

      void transformJcondToJump()
      Transform a conditional jump instruction to a jump. It is the caller's responsibility to verify that the instruction is a JCOND.
       IF pred GOTO target ==> GOTO target
       
    • transformToJump

      void transformToJump(int offset)
      Transform any instruction to a jump, and update the jump target.
      Parameters:
      offset - target offset
    • transformToJump

      void transformToJump(IDTarget target)
      Transform any instruction to a jump, and update the jump target.
      Parameters:
      target - a target
    • transformJcondToAssign

      void transformJcondToAssign(IDVar dst)
      Transform a conditional jump instruction to a conditional-predicate assignment. It is the caller's responsibility to verify that the instruction is a JCOND.
       IF pred GOTO target ==> dst = pred
       
      Parameters:
      dst - the destination operand for the predicate
    • transformSwitchToJcond

      boolean transformSwitchToJcond()
      Transform a single-case switch into a conditional jump.
       SWITCH(VAR) {
       CASE X: GOTO target;
       }
       // fall-through
       =>
       IF VAR==X GOTO target;
       // fall-through
       
      Returns:
      success indicators (if the switch has several cases, this method will fail)
    • updateTargets

      int updateTargets(Map<Integer,Integer> oldToNewOffsets)
      Update the targets of a branching instruction. This method has no effect on IR opcodes other than JUMP, JCOND, and SWITCH.
      Parameters:
      oldToNewOffsets - a map of current IR offsets to new IR offsets
      Returns:
      the number of updated targets
    • updateTargets

      int updateTargets(Map<Integer,Integer> oldToNewOffsets, boolean failOnMissedEntry)
      Update the targets of a branching instruction. This method has no effect on IR opcodes other than JUMP, JCOND, and SWITCH.
      Parameters:
      oldToNewOffsets - a map of current IR offsets to new IR offsets
      failOnMissedEntry - if true, the method will raise if a (current) branch target cannot be mapped to a new target (i.e., if there is no entry for a branch target in the map)
      Returns:
      the number of updated targets
    • morph

      void morph(DOpcodeType opcode, IDElement opnd1, IDElement opnd2)
      This dangerous method allows changing an IR instruction into a different one, while keeping metadata (e.g. offset, size, etc.) intact. If possible, use one of the transformXxx instructions instead.
      Parameters:
      opcode - new opcode
      opnd1 - new operand 1 (if any) - refer to DOpcodeType's type for operand type
      opnd2 - new operand 2 (if any) - refer to DOpcodeType's type for operand type
    • verify

      void verify() throws IllegalStateException
      Verify this instruction.

      Currently, this method verifies that the instruction operands match the current opcode specifications (see DOpcodeType).

      Throws:
      IllegalStateException - throw on error
    • replaceUsedVariable

      int replaceUsedVariable(IDVar var, IDExpression repl)
      Deep replace all matching used variables of this instruction. The replacement expression is duplicated to avoid reuse. Defined identifiers (if any) are not replaced.
      Parameters:
      var - target variable to be replaced
      repl - expression that will replace the variable
      Returns:
      the number of replacements
    • replaceDefinedVariable

      int replaceDefinedVariable(IDVar var, IDExpression repl)
      Replace the variable defined by this statement (if there is any).
      Parameters:
      var - target variable to be replaced
      repl - expression that will replace the variable
      Returns:
      the number of replacements (usually 0, potentially 1 for an assigment-like instruction)
    • getUsedVariables

      List<IDVar> getUsedVariables()
      Get the variables used (read) by this instruction.
      Returns:
      the list of all variables used, which may contain duplicates variables if the instruction uses the same variable multiple times (example: z = x + (y * x) would return [y, x, x].
    • getDefinedVariable

      IDVar getDefinedVariable()
      Get the identifier defined (written) by this method, if there is one. Only DOpcodeType.IR_ASSIGN and DOpcodeType.IR_STORE_EXCEPTION may define (write) identifiers.
      Returns:
    • countUsedVariable

      int countUsedVariable(IDVar var)
      Count the number of times the provided variable is used (read) by this instruction.

      Example (ASSIGN opcode): x = y * (y + z) => x is not used; y is used twice; z is used once

      Parameters:
      var -
      Returns:
    • visitInstruction

      boolean visitInstruction(IDVisitor visitor)
      Visit this instruction and its constituents. The visit is made depth-first, pre-order, and parents are recorded. (Refer to IVisitResults for details.)

      Same as visitInstructionPreOrder. Replacements must be reported (refer to IDExpression.visitDepthPre(IDVisitor) for details).

      Parameters:
      visitor - visitor object
      Returns:
      success indicator; true unless a different value was specified in DVisitResults when visiting an element
    • visitInstruction

      boolean visitInstruction(IDVisitor visitor, boolean skipAssignmentDestination)
      Visit this instruction and its constituents. The visit is made depth-first, pre-order, and parents are recorded. (Refer to IVisitResults for details.)

      Same as visitInstructionPreOrder. Replacements must be reported (refer to IDExpression.visitDepthPre(IDVisitor) for details).

      Parameters:
      visitor - visitor object
      skipAssignmentDestination - true to skip visiting the destination of DOpcodeType.IR_ASSIGN or DOpcodeType.IR_STORE_EXCEPTION
      Returns:
      success indicator; true unless a different value was specified in DVisitResults when visiting an element
    • visitInstructionPreOrder

      boolean visitInstructionPreOrder(IDVisitor visitor, boolean skipAssignmentDestination)
      Visit this instruction and its constituents. The visit is made depth-first, pre-order, and parents are recorded. (Refer to IVisitResults for details.)

      Replacements must be reported (refer to IDExpression.visitDepthPre(IDVisitor) for details).

      Parameters:
      visitor - visitor object
      skipAssignmentDestination - true to skip visiting the destination of DOpcodeType.IR_ASSIGN or DOpcodeType.IR_STORE_EXCEPTION
      Returns:
      success indicator; true unless a different value was specified in DVisitResults when visiting an element
    • visitInstructionPostOrder

      boolean visitInstructionPostOrder(IDVisitor visitor, boolean skipAssignmentDestination)
      Visit this instruction and its constituents. The visit is made depth-first, post-order, and parents are recorded. (Refer to IVisitResults for details.)

      Replacements need not be reported.

      Parameters:
      visitor - visitor object
      skipAssignmentDestination - true to skip visiting the destination of DOpcodeType.IR_ASSIGN or DOpcodeType.IR_STORE_EXCEPTION
      Returns:
      success indicator; true unless a different value was specified in DVisitResults when visiting an element
    • evaluate

      Convenience method: evaluate the IR instruction using the provided set a variable values.
      Parameters:
      varmap - a map of variable values to be used when evaluating the expression (this map will not be modified after evaluation of the instruction; for full-control of the emulation, use IDExpression.evaluate(IDState) instead of this method)
      Returns:
      the offset of the next IR instruction to be executed; null if none (e.g. a Return was executed)
      Throws:
      DexDecEvaluationException