Interface IDInstruction

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

@Ser 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.
      Parameters:
      replacedInsn - instruction being replaced
      Returns:
      duplicated instruction
    • duplicateWithOffsetAndSize

      IDInstruction duplicateWithOffsetAndSize(long offset, int size)
      Duplicate this instruction with an explicit offset and size.
      Parameters:
      offset - new offset
      size - new size
      Returns:
      duplicated instruction
    • 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 - source instruction
    • 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:
      method context
    • 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 - new 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:
      instruction opcode
    • setOpcode

      void setOpcode(DOpcodeType opcode)
      Change the instruction opcode. This method is dangerous. Instruction operands may require an update as well.
      Parameters:
      opcode - new 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:
      first operand, or null
    • 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 - new first operand
    • getOperand2

      IDElement getOperand2()
      Get the second operand. May be null if the opcode does not specify one. Refer to getOpcode() and DOpcodeType.
      Returns:
      second operand, or null
    • 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 - new second operand
    • 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 - true to consider operations that may throw as side effects
      Returns:
      true if used components may have side effects
    • isNop

      boolean isNop()
      Determine whether this instruction is a no-op.
      Returns:
      true if this instruction is a nop
    • isAssign

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

      IDExpression getAssignDestination()
      Get the assignment destination.
      Returns:
      assignment destination
    • setAssignDestination

      IDExpression setAssignDestination(IDExpression dst)
      Set the assignment destination.
      Parameters:
      dst - new destination
      Returns:
      previous destination
    • getAssignSource

      IDExpression getAssignSource()
      Get the assignment source.
      Returns:
      assignment source
    • setAssignSource

      IDExpression setAssignSource(IDExpression src)
      Set the assignment source.
      Parameters:
      src - new source
      Returns:
      previous source
    • isAssignToVar

      default boolean isAssignToVar()
      Determine whether this instruction assigns to a variable.
      Returns:
      true if this instruction assigns to a variable
    • isAssignToVar

      default boolean isAssignToVar(int wantedVarId)
      Determine whether this instruction assigns to a specific variable.
      Parameters:
      wantedVarId - target variable id
      Returns:
      true if this instruction assigns to the variable
    • isAssignFromVar

      default boolean isAssignFromVar()
      Determine whether this instruction assigns from a variable.
      Returns:
      true if this instruction assigns from a variable
    • isAssignFromVar

      default boolean isAssignFromVar(int wantedVarId)
      Determine whether this instruction assigns from a specific variable.
      Parameters:
      wantedVarId - source variable id
      Returns:
      true if this instruction assigns from the variable
    • isAssignFromVarToVar

      default boolean isAssignFromVarToVar()
      Determine whether this instruction assigns from a variable to another variable.
      Returns:
      true if this instruction is a variable-to-variable assignment
    • isAssignFromVarToVar

      default boolean isAssignFromVarToVar(int wantedSrcVarId, int wantedDstVarId)
      Determine whether this instruction assigns from a specific variable to another.
      Parameters:
      wantedSrcVarId - source variable id
      wantedDstVarId - destination variable id
      Returns:
      true if this instruction is the requested variable-to-variable assignment
    • isInvoke

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

      IDInvokeInfo getInvokeData()
      Retrieve invocation information.
      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()
      Get the target offset for unconditional and conditional jumps.
      Returns:
      branch target offset
    • isJump

      boolean isJump()
      Determine whether this instruction is an unconditional jump.
      Returns:
      true if this instruction is a jump (goto)
    • isJumpTo

      boolean isJumpTo(int wantedTarget)
      Determine whether this instruction is a jump to a specific target.
      Parameters:
      wantedTarget - target offset
      Returns:
      true if this instruction is a jump to the target
    • isJcond

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

      boolean isJcondTo(int wantedTarget)
      Determine whether this instruction is a conditional jump to a specific target.
      Parameters:
      wantedTarget - target offset
      Returns:
      true if this instruction is a conditional jump to the target
    • isJumpOrJcond

      boolean isJumpOrJcond()
      Determine whether this instruction is an unconditional or conditional jump.
      Returns:
      true if this instruction is a jump or conditional jump
    • isJumpOrJcondTo

      boolean isJumpOrJcondTo(int wantedTarget)
      Determine whether this instruction is an unconditional or conditional jump to a target.
      Parameters:
      wantedTarget - target offset
      Returns:
      true if this instruction is a jump or conditional jump to the target
    • isJcondOrSwitch

      boolean isJcondOrSwitch()
      Determine whether this instruction is a conditional jump or switch.
      Returns:
      true if this instruction is a conditional jump or switch
    • getJcondCondition

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

      IDExpression setJcondCondition(IDExpression cond)
      Set the condition predicate for a conditional jump.
      Parameters:
      cond - new predicate
      Returns:
      previous predicate
    • reverseJcondCondition

      void reverseJcondCondition()
      Reverse the conditional jump predicate.
    • isSwitch

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

      boolean isSwitchOnInt()
      Determine whether this instruction is a switch on integers.
      Returns:
      true if this instruction is an integer switch
    • isSwitchOnString

      boolean isSwitchOnString()
      Determine whether this instruction is a switch on strings.
      Returns:
      true if this instruction is a string switch
    • getSwitchData

      IDSwitchData getSwitchData()
      Get switch data.
      Returns:
      switch data
    • setSwitchData

      IDSwitchData setSwitchData(IDSwitchData swdata)
      Set switch data.
      Parameters:
      swdata - new switch data
      Returns:
      previous switch data
    • getSwitchExpression

      IDExpression getSwitchExpression()
      Get the switch expression.
      Returns:
      switch expression
    • setSwitchExpression

      IDExpression setSwitchExpression(IDExpression exp)
      Set the switch expression.
      Parameters:
      exp - new switch expression
      Returns:
      previous switch expression
    • isReturn

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

      IDExpression getReturnExpression()
      Get the return expression.
      Returns:
      return expression, or null for void returns
    • setReturnExpression

      IDExpression setReturnExpression(IDExpression exp)
      Set the return expression.
      Parameters:
      exp - new return expression
      Returns:
      previous return expression
    • isThrow

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

      IDExpression getThrowExpression()
      Get the thrown expression.
      Returns:
      thrown expression
    • setThrowExpression

      IDExpression setThrowExpression(IDExpression exp)
      Set the thrown expression.
      Parameters:
      exp - new thrown expression
      Returns:
      previous thrown expression
    • isReturnOrThrow

      boolean isReturnOrThrow()
      Determine whether this instruction is a return or throw.
      Returns:
      true if this instruction is a return or throw
    • isStoreException

      boolean isStoreException()
      Determine whether this instruction stores an exception object.
      Returns:
      true if this instruction is a store-exception (special opcode)
    • getStoredExceptionVariable

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

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

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

      boolean isMonitorExit()
      Determine whether this instruction exits a monitor.
      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:
      variable defined by this instruction, or null
    • 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 - variable to count
      Returns:
      number of uses
    • 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 - on evaluation error