org.ow2.asmdex
Class MethodCodeReader

java.lang.Object
  extended by org.ow2.asmdex.MethodCodeReader

public class MethodCodeReader
extends java.lang.Object

Class made to read the code of one method of a Dex file, and make a visitor visits its instructions. Also parses the debug_info structure to get complementary information (line numbers, local variables...).

Should only be used by ApplicationReader.

The NOP instructions are ignored if we reach any Pseudo Instruction such as Packed/Sparse Switch or Fill Array Data, so that NOP don't stack up if we transform an already generated dex file. Meeting any other instruction will stop this behavior.

Author:
Julien Névo

Field Summary
protected  int codeOffset
          Offset of the code of the method inside the Dex file.
protected  int debugAddress
          register of debug state machine : the debug address
protected  int debugCurrentOpcodeOffset
          Offset on opcodes of the debug_info_item.
protected  int debugCurrentOpcodeOffsetAtInitialization
          Copy of the original debugCurrentOpcodeOffset.
protected  int debugEmittedLine
          Last emitted line (DBG_ADVANCE_LINE not counted).
protected  boolean debugEpilogueBegin
          register of debug state machine : the epilogue end
protected  int debugLine
          register of debug state machine : the debug line
protected  int debugLineAtInitialization
          Copy of the original debugLine.
protected  boolean debugPrologueEnd
          register of debug state machine : the prologue end
protected  java.lang.String debugSourceFile
          register of debug state machine : the source file
protected  DexFileReader dexFile
          The reader of the Dex file.
protected  int instructionsEndOffset
          Offset in the Dex file of the byte next to the last opcode/data of the code of the method.
protected  int instructionsStartOffset
          Offset in the Dex file of the first opcode of the code of the current method.
protected  java.util.HashMap<java.lang.Integer,Label> labels
          Map containing the labels located at the given offset (from the beginning of the code of the method).
protected  java.util.HashMap<java.lang.Integer,java.util.ArrayList<TryCatch>> listTryCatchStructures
          Map containing lists of the TryCatch Structures located at the given offset (from the beginning of the code of the method).
protected  java.util.HashMap<java.lang.Integer,java.util.List<LocalVariable>> localVariableLists
          Map containing, for each local variable identified by its number (as described in the debug_info_item), a list of Local Variables.
protected  MethodVisitor methodVisitor
          The Method Visitor.
protected  boolean newDebugLineEmitted
          Indicates if a new Debug Line is emitted.
protected  java.util.HashMap<java.lang.Integer,PackedSwitch> packedSwitchStructures
          Map containing the Packed Switch Structures located at the given offset (from the beginning of the code of the method).
protected  boolean skipDebug
          Indicates if the debug information must be skipped.
protected  java.util.HashMap<java.lang.Integer,SparseSwitch> sparseSwitchStructures
          Map containing the Sparse Switch Structures located at the given offset (from the beginning of the code of the method).
 
Constructor Summary
MethodCodeReader(DexFileReader dexFile, MethodVisitor methodVisitor, int codeOffset, boolean skipDebug)
          Constructor of the MethodCodeReader.
 
Method Summary
protected  void addEndLabelToLocalVariableLabels(int registerNumber, Label endLabel)
          Adds an End Label to a Local Variable labels structure.
protected  void addLabel(int offset)
          Adds a new Label to the Label list, mapped according to its offset from the first byte of the code of the method.
protected  Label addLabel(Label label)
          Convenient method to add an (already resolved) label to the Label list.
protected  void addLabels(Label[] labelList)
          Convenient method to add (already resolved) labels to the Label list.
protected  void addNewLocalVariable(int registerNumber, LocalVariable localVariable)
          Adds the Local Variable at the end of the list designed by the register number.
protected  void addRestartLabelToLocalVariableLabels(int registerNumber, Label restartLabel)
          Adds an Restart Label to a Local Variable labels structure.
protected  void addTryCatchStructure(TryCatch tcs, int relativeOffset)
          Convenient method to add a TryCatchStructure to the listTryCatchStructures.
protected  Label createAndAddLabel(int offset)
          Creates and adds to the Labels list a new Label which offset (relative to the first byte of the code of the method) is given, but if a Label already exists here, returns this existing label.
protected  Label getLabel(int offset)
          Convenient method to get the Label related to the offset (relative to the first byte of the code of the method).
protected  LocalVariable getLocalVariable(int registerNumber)
          Returns the LAST Local Variable used according to the given register number.
protected  void parseAndVisitSwitchCase(MethodVisitor methodVisitor, int fullOpcode, boolean findLabelsOnly)
          Parses and visits a Switch Case instruction, whether it be a Packed or Sparse switch.
protected  void parseDebugInformationItem(MethodVisitor methodVisitor, int currentBytecodeOffset, boolean findLabelsOnly)
          Parses the debug_info_item information of the given debug opcode.
protected  void parseDebugStartLocalVariable(MethodVisitor methodVisitor, int currentBytecodeOffset, boolean isLocalExtended, boolean findLabelsOnly)
          Parses a DBG_START_LOCAL or DBG_START_LOCAL_EXTENDED instruction, and visits the local variables.
protected  PackedSwitch parsePackedSwitchFormat(int relativeSwitchOffset, int packedSwitchOffset)
          Reads a packed-switch structure, from the switch offset and the packed switch offset and returns a structure containing all the information read.
protected  SparseSwitch parseSparseSwitchFormat(int relativeSwitchOffset, int sparseSwitchOffset)
          Reads a sparse-switch structure, from the switch offset and the packed switch offset and returns a structure containing all the information read.
protected  void parseTryItemsFormat(int tryItemOffset, int triesSize)
          Parses the "tries" structure.
protected  void visitFieldInsn(MethodVisitor methodVisitor, int opcode, int registerA, int registerB, int index)
          Visits a given Field Instruction, and parses it.
protected  void visitFillArrayData(MethodVisitor methodVisitor, int register, int offset)
          Visits a FillArrayData instruction.
protected  void visitJumpInsn(int opcode, int offset, int firstRegister, int secondRegister, MethodVisitor methodVisitor, boolean findLabelsOnly)
          Parses and visits a Jump Instruction (format 10X, 20X, 30X).
 void visitMethodCode()
          Visits the code of a method.
protected  void visitMethodInstruction(MethodVisitor methodVisitor, int opcodeByte, int methodIndex, int[] registers)
          Method used by the methods that decodes the invoke-kind, in order to get the invoked method information and call the visitor.
protected  void visitMultiANewArrayInsn(MethodVisitor methodVisitor, int index, int[] registers)
          Visits a MultiANewArrayInsn Instruction.
protected  void visitVarInsn(int opcodeByte, MethodVisitor methodVisitor, int destinationRegister, int var)
          Visits a Var Instruction.
protected  void visitVarInsn(int opcodeByte, MethodVisitor methodVisitor, int destinationRegister, long var)
          Visits a Var Instruction.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

methodVisitor

protected MethodVisitor methodVisitor
The Method Visitor.


dexFile

protected DexFileReader dexFile
The reader of the Dex file.


codeOffset

protected int codeOffset
Offset of the code of the method inside the Dex file. May be 0 if the method is abstract or native.


skipDebug

protected boolean skipDebug
Indicates if the debug information must be skipped.


instructionsStartOffset

protected int instructionsStartOffset
Offset in the Dex file of the first opcode of the code of the current method.


instructionsEndOffset

protected int instructionsEndOffset
Offset in the Dex file of the byte next to the last opcode/data of the code of the method.


labels

protected java.util.HashMap<java.lang.Integer,Label> labels
Map containing the labels located at the given offset (from the beginning of the code of the method).


packedSwitchStructures

protected java.util.HashMap<java.lang.Integer,PackedSwitch> packedSwitchStructures
Map containing the Packed Switch Structures located at the given offset (from the beginning of the code of the method). The offset points to the packed-switch opcode, NOT the packed-switch format itself.


sparseSwitchStructures

protected java.util.HashMap<java.lang.Integer,SparseSwitch> sparseSwitchStructures
Map containing the Sparse Switch Structures located at the given offset (from the beginning of the code of the method). The offset points to the sparse-switch opcode, NOT the sparse-switch format itself.


listTryCatchStructures

protected java.util.HashMap<java.lang.Integer,java.util.ArrayList<TryCatch>> listTryCatchStructures
Map containing lists of the TryCatch Structures located at the given offset (from the beginning of the code of the method). The offset points to the Try.


localVariableLists

protected java.util.HashMap<java.lang.Integer,java.util.List<LocalVariable>> localVariableLists
Map containing, for each local variable identified by its number (as described in the debug_info_item), a list of Local Variables. Why a List ? Because a register number can share one or more variables (though it doesn't happen often). Note that when a Local Variable is started, it is added to the end of the list, and all the Restarts/Ends found will be added to this Variable.


debugAddress

protected int debugAddress
register of debug state machine : the debug address


debugLine

protected int debugLine
register of debug state machine : the debug line


debugSourceFile

protected java.lang.String debugSourceFile
register of debug state machine : the source file


debugPrologueEnd

protected boolean debugPrologueEnd
register of debug state machine : the prologue end


debugEpilogueBegin

protected boolean debugEpilogueBegin
register of debug state machine : the epilogue end


debugLineAtInitialization

protected int debugLineAtInitialization
Copy of the original debugLine. This is useful, because we make two passes, and need to recover the original value for the second.


debugCurrentOpcodeOffsetAtInitialization

protected int debugCurrentOpcodeOffsetAtInitialization
Copy of the original debugCurrentOpcodeOffset. This is useful, because we make two passes, and need to recover the original value for the second.


debugCurrentOpcodeOffset

protected int debugCurrentOpcodeOffset
Offset on opcodes of the debug_info_item.


newDebugLineEmitted

protected boolean newDebugLineEmitted
Indicates if a new Debug Line is emitted.


debugEmittedLine

protected int debugEmittedLine
Last emitted line (DBG_ADVANCE_LINE not counted).

Constructor Detail

MethodCodeReader

public MethodCodeReader(DexFileReader dexFile,
                        MethodVisitor methodVisitor,
                        int codeOffset,
                        boolean skipDebug)
Constructor of the MethodCodeReader.

Parameters:
dexFile - the Dex file.
methodVisitor - visitor to visit the instructions of the code of the method.
codeOffset - offset of the code of the method inside the Dex file. May be 0 if the method is abstract or native.
skipDebug - indicates if the debug information must be skipped.
Method Detail

visitMethodCode

public void visitMethodCode()
Visits the code of a method. Also needs to parse the debug_info structure to get complementary information (line number, local variables...).


parseDebugInformationItem

protected void parseDebugInformationItem(MethodVisitor methodVisitor,
                                         int currentBytecodeOffset,
                                         boolean findLabelsOnly)
Parses the debug_info_item information of the given debug opcode. We stop the reading when the debugAddress doesn't coincide with the bytecode pointer. Updates the debugAddress and debugCurrentOpcodeOffset. However, the visit isn't done here, but by the calling method. The dex file reader position is saved.

Parameters:
methodVisitor - the visitor to visit the debug information item.
currentBytecodeOffset - Offset from the method opcodes currently being parsed.
findLabelsOnly - true if no visitor must be called, because we only want to set up the Labels by parsing this structure.

parseDebugStartLocalVariable

protected void parseDebugStartLocalVariable(MethodVisitor methodVisitor,
                                            int currentBytecodeOffset,
                                            boolean isLocalExtended,
                                            boolean findLabelsOnly)
Parses a DBG_START_LOCAL or DBG_START_LOCAL_EXTENDED instruction, and visits the local variables.

Parameters:
methodVisitor - the visitor to visit the debug information item.
currentBytecodeOffset - Offset from the method opcodes currently being parsed.
isLocalExtended - true if the instruction concerns a LOCAL_EXTENDED variable.
findLabelsOnly - true if no visitor must be called, because we only want to set up the Labels by parsing this structure.

getLocalVariable

protected LocalVariable getLocalVariable(int registerNumber)
Returns the LAST Local Variable used according to the given register number. If it doesn't exist, it creates it.

Parameters:
registerNumber -
Returns:
a Local Variable, new or existing.

addNewLocalVariable

protected void addNewLocalVariable(int registerNumber,
                                   LocalVariable localVariable)
Adds the Local Variable at the end of the list designed by the register number.

Parameters:
registerNumber - the register number of the Local Variable.
localVariable - the Local Variable to add.

parseTryItemsFormat

protected void parseTryItemsFormat(int tryItemOffset,
                                   int triesSize)
Parses the "tries" structure. It may contains several "try_item" items. In order to get all the information needed, it will also parse the encoded_catch_handler_list (only reaching the information needed). The dex file reader position is modified.

Parameters:
tryItemOffset - offset to the "tries" structure (which offset is given in the code_item structure), from the beginning of the file.
triesSize - number of "try" structure.

addLabel

protected void addLabel(int offset)
Adds a new Label to the Label list, mapped according to its offset from the first byte of the code of the method. Doesn't add it if it already exists.

Parameters:
offset - offset from the first byte of the code of the method.

addLabel

protected Label addLabel(Label label)
Convenient method to add an (already resolved) label to the Label list. Returns a reference to the actually labels here. This is useful is a label already exists here.

Parameters:
label - label to add.
Returns:
the label actually put. This is useful not to have two labels at the same location.

addLabels

protected void addLabels(Label[] labelList)
Convenient method to add (already resolved) labels to the Label list.

Parameters:
labelList - list of the Labels to add.

addTryCatchStructure

protected void addTryCatchStructure(TryCatch tcs,
                                    int relativeOffset)
Convenient method to add a TryCatchStructure to the listTryCatchStructures. As it contains lists of TryCatchStructure, we have to make sure that a list already exists before adding the structure, else we have to create one.

Parameters:
tcs - TryCatchStructure to add.
relativeOffset - Offset to where the Try is in the bytecode, relative to the first byte of the code of the method.

getLabel

protected Label getLabel(int offset)
Convenient method to get the Label related to the offset (relative to the first byte of the code of the method).

Parameters:
offset - offset of the Label, relative to the first byte of the code of the method.
Returns:
the Label related to the offset given, or Null if the Label isn't found.

createAndAddLabel

protected Label createAndAddLabel(int offset)
Creates and adds to the Labels list a new Label which offset (relative to the first byte of the code of the method) is given, but if a Label already exists here, returns this existing label.

Parameters:
offset - offset of the Label, relative to the first byte of the code of the method).
Returns:
A new Label, or the Label existing at this offset.

visitVarInsn

protected void visitVarInsn(int opcodeByte,
                            MethodVisitor methodVisitor,
                            int destinationRegister,
                            int var)
Visits a Var Instruction.

Parameters:
opcodeByte - 8-bit opcode of the instruction.
methodVisitor - visitor to call.
destinationRegister - the destination register.
var - the operand of the instruction to be visited. This operand is either a value or a source Register.

visitVarInsn

protected void visitVarInsn(int opcodeByte,
                            MethodVisitor methodVisitor,
                            int destinationRegister,
                            long var)
Visits a Var Instruction.

Parameters:
opcodeByte - 8-bit opcode of the instruction.
methodVisitor - visitor to call.
destinationRegister - the destination register.
var - the operand of the instruction to be visited. This operand is either a value or a source Register.

visitMethodInstruction

protected void visitMethodInstruction(MethodVisitor methodVisitor,
                                      int opcodeByte,
                                      int methodIndex,
                                      int[] registers)
Method used by the methods that decodes the invoke-kind, in order to get the invoked method information and call the visitor. The dex file reader position is saved.

Parameters:
methodVisitor - visitor to call.
opcodeByte - 8-bit opcode of the instruction.
methodIndex - method index of the invoked method.
registers - list of the registers encoded to pass to the invoked method.

visitJumpInsn

protected void visitJumpInsn(int opcode,
                             int offset,
                             int firstRegister,
                             int secondRegister,
                             MethodVisitor methodVisitor,
                             boolean findLabelsOnly)
Parses and visits a Jump Instruction (format 10X, 20X, 30X).

Parameters:
opcode - the 8-bit opcode of the Instruction.
offset - offset relative to the beginning of the Dex file, to go to.
firstRegister - first register to test, if any.
secondRegister - second register to test, if any.
methodVisitor - MethodVisitor to visit the Jump.
findLabelsOnly - indicates if the parsing is only about getting the Label offsets. In this case, no method from the visitor must be called.

visitFieldInsn

protected void visitFieldInsn(MethodVisitor methodVisitor,
                              int opcode,
                              int registerA,
                              int registerB,
                              int index)
Visits a given Field Instruction, and parses it. The dex file reader position is saved.

Parameters:
methodVisitor - MethodVisitor to visit the instruction.
opcode - Opcode of the instruction
registerA - First register
registerB - Second register
index - index of the field definition

visitMultiANewArrayInsn

protected void visitMultiANewArrayInsn(MethodVisitor methodVisitor,
                                       int index,
                                       int[] registers)
Visits a MultiANewArrayInsn Instruction. The dex file reader position is saved.

Parameters:
methodVisitor - MethodVisitor to visit the instruction.
index - the index of the descriptor of the Array.
registers - the registers containing the values of the Array.

visitFillArrayData

protected void visitFillArrayData(MethodVisitor methodVisitor,
                                  int register,
                                  int offset)
Visits a FillArrayData instruction. Just like switch/case instruction, we directly get to the array data (encoded later) in order to parse them for this visitor.

Parameters:
methodVisitor - MethodVisitor to visit the instruction.
register - register holding the array.
offset - offset of the data structure of the Array.

parseAndVisitSwitchCase

protected void parseAndVisitSwitchCase(MethodVisitor methodVisitor,
                                       int fullOpcode,
                                       boolean findLabelsOnly)
Parses and visits a Switch Case instruction, whether it be a Packed or Sparse switch. Its nature is found according to the given opcode. The dex file reader must point after the 16-bit opcode. On return, points after the full instruction.

Parameters:
methodVisitor - MethodVisitor to visit the switch.
fullOpcode - the 16-bit opcode.
findLabelsOnly - indicates if the parsing is only about getting the Label offsets. In this case, no method from the visitor must be called.

parsePackedSwitchFormat

protected PackedSwitch parsePackedSwitchFormat(int relativeSwitchOffset,
                                               int packedSwitchOffset)
Reads a packed-switch structure, from the switch offset and the packed switch offset and returns a structure containing all the information read. The dex file reader position is saved.

Parameters:
relativeSwitchOffset - offset of the first byte of the switch opcode, from the beginning of the code of the method.
packedSwitchOffset - offset of the packed switch structure, from the beginning of the Dex file.
Returns:
a PackedSwitchStructure containing all the information of the packed switch structure.

parseSparseSwitchFormat

protected SparseSwitch parseSparseSwitchFormat(int relativeSwitchOffset,
                                               int sparseSwitchOffset)
Reads a sparse-switch structure, from the switch offset and the packed switch offset and returns a structure containing all the information read. The dex file reader position is saved.

Parameters:
relativeSwitchOffset - offset of the first byte of the switch opcode, from the beginning of the code of the method.
sparseSwitchOffset - offset of the packed switch structure, from the beginning of the Dex file.
Returns:
a SparseSwitchStructure containing all the information of the sparse switch structure.

addEndLabelToLocalVariableLabels

protected void addEndLabelToLocalVariableLabels(int registerNumber,
                                                Label endLabel)
Adds an End Label to a Local Variable labels structure.

Parameters:
registerNumber - register number.
endLabel - the Label to add.

addRestartLabelToLocalVariableLabels

protected void addRestartLabelToLocalVariableLabels(int registerNumber,
                                                    Label restartLabel)
Adds an Restart Label to a Local Variable labels structure.

Parameters:
registerNumber - register number.
restartLabel - the Label to add.