diff --git a/src/main/antlr3/org/jf/smali/smaliParser.g b/src/main/antlr3/org/jf/smali/smaliParser.g index 565c3c12..e18ae4ba 100644 --- a/src/main/antlr3/org/jf/smali/smaliParser.g +++ b/src/main/antlr3/org/jf/smali/smaliParser.g @@ -323,92 +323,92 @@ instruction returns [int size] @init {boolean needsNop = false; int targetCount = 0;} : //e.g. goto endloop: //e.g. goto +3 - INSTRUCTION_FORMAT10t (LABEL | OFFSET) {$size = Format10t.Format.getByteCount();} + INSTRUCTION_FORMAT10t (LABEL | OFFSET) {$size = Format.Format10t.size;} -> ^(I_STATEMENT_FORMAT10t[$start, "I_STATEMENT_FORMAT10t"] INSTRUCTION_FORMAT10t LABEL? OFFSET?) | //e.g. return - INSTRUCTION_FORMAT10x {$size = Format10x.Format.getByteCount();} + INSTRUCTION_FORMAT10x {$size = Format.Format10x.size;} -> ^(I_STATEMENT_FORMAT10x[$start, "I_STATEMENT_FORMAT10x"] INSTRUCTION_FORMAT10x) | //e.g. const/4 v0, 5 - INSTRUCTION_FORMAT11n REGISTER integral_literal {$size = Format11n.Format.getByteCount();} + INSTRUCTION_FORMAT11n REGISTER integral_literal {$size = Format.Format11n.size;} -> ^(I_STATEMENT_FORMAT11n[$start, "I_STARTMENT_FORMAT11n"] INSTRUCTION_FORMAT11n REGISTER integral_literal) | //e.g. move-result-object v1 - INSTRUCTION_FORMAT11x REGISTER {$size = Format11x.Format.getByteCount();} + INSTRUCTION_FORMAT11x REGISTER {$size = Format.Format11x.size;} -> ^(I_STATEMENT_FORMAT11x[$start, "I_STATEMENT_FORMAT11x"] INSTRUCTION_FORMAT11x REGISTER) | //e.g. move v1 v2 - INSTRUCTION_FORMAT12x REGISTER REGISTER {$size = Format12x.Format.getByteCount();} + INSTRUCTION_FORMAT12x REGISTER REGISTER {$size = Format.Format12x.size;} -> ^(I_STATEMENT_FORMAT12x[$start, "I_STATEMENT_FORMAT12x"] INSTRUCTION_FORMAT12x REGISTER REGISTER) | //e.g. goto/16 endloop: - INSTRUCTION_FORMAT20t (LABEL | OFFSET) {$size = Format20t.Format.getByteCount();} + INSTRUCTION_FORMAT20t (LABEL | OFFSET) {$size = Format.Format20t.size;} -> ^(I_STATEMENT_FORMAT20t[$start, "I_STATEMENT_FORMAT20t"] INSTRUCTION_FORMAT20t LABEL? OFFSET?) | //e.g. sget_object v0 java/lang/System/out LJava/io/PrintStream; - INSTRUCTION_FORMAT21c_FIELD REGISTER fully_qualified_field {$size = Format21c.Format.getByteCount();} + INSTRUCTION_FORMAT21c_FIELD REGISTER fully_qualified_field {$size = Format.Format21c.size;} -> ^(I_STATEMENT_FORMAT21c_FIELD[$start, "I_STATEMENT_FORMAT21c_FIELD"] INSTRUCTION_FORMAT21c_FIELD REGISTER fully_qualified_field) | //e.g. const-string v1 "Hello World!" - INSTRUCTION_FORMAT21c_STRING REGISTER STRING_LITERAL {$size = Format21c.Format.getByteCount();} + INSTRUCTION_FORMAT21c_STRING REGISTER STRING_LITERAL {$size = Format.Format21c.size;} -> ^(I_STATEMENT_FORMAT21c_STRING[$start, "I_STATEMENT_FORMAT21c_STRING"] INSTRUCTION_FORMAT21c_STRING REGISTER STRING_LITERAL) | //e.g. const-class v2 org/jf/HelloWorld2/HelloWorld2 - INSTRUCTION_FORMAT21c_TYPE REGISTER reference_type_descriptor {$size = Format21c.Format.getByteCount();} + INSTRUCTION_FORMAT21c_TYPE REGISTER reference_type_descriptor {$size = Format.Format21c.size;} -> ^(I_STATEMENT_FORMAT21c_TYPE[$start, "I_STATEMENT_FORMAT21c"] INSTRUCTION_FORMAT21c_TYPE REGISTER reference_type_descriptor) | //e.g. const/high16 v1, 1234 - INSTRUCTION_FORMAT21h REGISTER integral_literal {$size = Format21h.Format.getByteCount();} + INSTRUCTION_FORMAT21h REGISTER integral_literal {$size = Format.Format21h.size;} -> ^(I_STATEMENT_FORMAT21h[$start, "I_STATEMENT_FORMAT21h"] INSTRUCTION_FORMAT21h REGISTER integral_literal) | //e.g. const/16 v1, 1234 - INSTRUCTION_FORMAT21s REGISTER integral_literal {$size = Format21s.Format.getByteCount();} + INSTRUCTION_FORMAT21s REGISTER integral_literal {$size = Format.Format21s.size;} -> ^(I_STATEMENT_FORMAT21s[$start, "I_STATEMENT_FORMAT21s"] INSTRUCTION_FORMAT21s REGISTER integral_literal) | //e.g. if-eqz v0, endloop: - INSTRUCTION_FORMAT21t REGISTER (LABEL | OFFSET) {$size = Format21t.Format.getByteCount();} + INSTRUCTION_FORMAT21t REGISTER (LABEL | OFFSET) {$size = Format.Format21t.size;} -> ^(I_STATEMENT_FORMAT21t[$start, "I_STATEMENT_FORMAT21t"] INSTRUCTION_FORMAT21t REGISTER LABEL? OFFSET?) | //e.g. add-int v0, v1, 123 - INSTRUCTION_FORMAT22b REGISTER REGISTER integral_literal {$size = Format22b.Format.getByteCount();} + INSTRUCTION_FORMAT22b REGISTER REGISTER integral_literal {$size = Format.Format22b.size;} -> ^(I_STATEMENT_FORMAT22b[$start, "I_STATEMENT_FORMAT22b"] INSTRUCTION_FORMAT22b REGISTER REGISTER integral_literal) | //e.g. iput-object v1, v0 org/jf/HelloWorld2/HelloWorld2.helloWorld Ljava/lang/String; - INSTRUCTION_FORMAT22c_FIELD REGISTER REGISTER fully_qualified_field {$size = Format22c.Format.getByteCount();} + INSTRUCTION_FORMAT22c_FIELD REGISTER REGISTER fully_qualified_field {$size = Format.Format22c.size;} -> ^(I_STATEMENT_FORMAT22c_FIELD[$start, "I_STATEMENT_FORMAT22c_FIELD"] INSTRUCTION_FORMAT22c_FIELD REGISTER REGISTER fully_qualified_field) | //e.g. instance-of v0, v1, Ljava/lang/String; - INSTRUCTION_FORMAT22c_TYPE REGISTER REGISTER nonvoid_type_descriptor {$size = Format22c.Format.getByteCount();} + INSTRUCTION_FORMAT22c_TYPE REGISTER REGISTER nonvoid_type_descriptor {$size = Format.Format22c.size;} -> ^(I_STATEMENT_FORMAT22c_TYPE[$start, "I_STATEMENT_FORMAT22c_TYPE"] INSTRUCTION_FORMAT22c_TYPE REGISTER REGISTER nonvoid_type_descriptor) | //e.g. add-int/lit16 v0, v1, 12345 - INSTRUCTION_FORMAT22s REGISTER REGISTER integral_literal {$size = Format22s.Format.getByteCount();} + INSTRUCTION_FORMAT22s REGISTER REGISTER integral_literal {$size = Format.Format22s.size;} -> ^(I_STATEMENT_FORMAT22s[$start, "I_STATEMENT_FORMAT22s"] INSTRUCTION_FORMAT22s REGISTER REGISTER integral_literal) | //e.g. if-eq v0, v1, endloop: - INSTRUCTION_FORMAT22t REGISTER REGISTER (LABEL | OFFSET) {$size = Format22t.Format.getByteCount();} + INSTRUCTION_FORMAT22t REGISTER REGISTER (LABEL | OFFSET) {$size = Format.Format22t.size;} -> ^(I_STATEMENT_FORMAT22t[$start, "I_STATEMENT_FFORMAT22t"] INSTRUCTION_FORMAT22t REGISTER REGISTER LABEL? OFFSET?) | //e.g. move/from16 v1, v1234 - INSTRUCTION_FORMAT22x REGISTER REGISTER {$size = Format22x.Format.getByteCount();} + INSTRUCTION_FORMAT22x REGISTER REGISTER {$size = Format.Format22x.size;} -> ^(I_STATEMENT_FORMAT22x[$start, "I_STATEMENT_FORMAT22x"] INSTRUCTION_FORMAT22x REGISTER REGISTER) | //e.g. add-int v1, v2, v3 - INSTRUCTION_FORMAT23x REGISTER REGISTER REGISTER {$size = Format23x.Format.getByteCount();} + INSTRUCTION_FORMAT23x REGISTER REGISTER REGISTER {$size = Format.Format23x.size;} -> ^(I_STATEMENT_FORMAT23x[$start, "I_STATEMENT_FORMAT23x"] INSTRUCTION_FORMAT23x REGISTER REGISTER REGISTER) | //e.g. goto/32 endloop: - INSTRUCTION_FORMAT30t (LABEL | OFFSET) {$size = Format30t.Format.getByteCount();} + INSTRUCTION_FORMAT30t (LABEL | OFFSET) {$size = Format.Format30t.size;} -> ^(I_STATEMENT_FORMAT30t[$start, "I_STATEMENT_FORMAT30t"] INSTRUCTION_FORMAT30t LABEL? OFFSET?) | //e.g. const-string/jumbo v1 "Hello World!" - INSTRUCTION_FORMAT31c REGISTER STRING_LITERAL {$size = Format31c.Format.getByteCount();} + INSTRUCTION_FORMAT31c REGISTER STRING_LITERAL {$size = Format.Format31c.size;} ->^(I_STATEMENT_FORMAT31c[$start, "I_STATEMENT_FORMAT31c"] INSTRUCTION_FORMAT31c REGISTER STRING_LITERAL) | //e.g. const v0, 123456 - INSTRUCTION_FORMAT31i REGISTER fixed_32bit_literal {$size = Format31i.Format.getByteCount();} + INSTRUCTION_FORMAT31i REGISTER fixed_32bit_literal {$size = Format.Format31i.size;} -> ^(I_STATEMENT_FORMAT31i[$start, "I_STATEMENT_FORMAT31i"] INSTRUCTION_FORMAT31i REGISTER fixed_32bit_literal) | //e.g. fill-array-data v0, ArrayData: - INSTRUCTION_FORMAT31t REGISTER (LABEL | OFFSET) {$size = Format31t.Format.getByteCount();} + INSTRUCTION_FORMAT31t REGISTER (LABEL | OFFSET) {$size = Format.Format31t.size;} -> ^(I_STATEMENT_FORMAT31t[$start, "I_STATEMENT_FORMAT31t"] INSTRUCTION_FORMAT31t REGISTER LABEL? OFFSET?) | //e.g. move/16 v4567, v1234 - INSTRUCTION_FORMAT32x REGISTER REGISTER {$size = Format32x.Format.getByteCount();} + INSTRUCTION_FORMAT32x REGISTER REGISTER {$size = Format.Format32x.size;} -> ^(I_STATEMENT_FORMAT32x[$start, "I_STATEMENT_FORMAT32x"] INSTRUCTION_FORMAT32x REGISTER REGISTER) | //e.g. invoke-virtual {v0,v1} java/io/PrintStream/print(Ljava/lang/Stream;)V - INSTRUCTION_FORMAT35c_METHOD OPEN_BRACKET register_list CLOSE_BRACKET fully_qualified_method {$size = Format35c.Format.getByteCount();} + INSTRUCTION_FORMAT35c_METHOD OPEN_BRACKET register_list CLOSE_BRACKET fully_qualified_method {$size = Format.Format35c.size;} -> ^(I_STATEMENT_FORMAT35c_METHOD[$start, "I_STATEMENT_FORMAT35c_METHOD"] INSTRUCTION_FORMAT35c_METHOD register_list fully_qualified_method) | //e.g. filled-new-array {v0,v1}, I - INSTRUCTION_FORMAT35c_TYPE OPEN_BRACKET register_list CLOSE_BRACKET nonvoid_type_descriptor {$size = Format35c.Format.getByteCount();} + INSTRUCTION_FORMAT35c_TYPE OPEN_BRACKET register_list CLOSE_BRACKET nonvoid_type_descriptor {$size = Format.Format35c.size;} -> ^(I_STATEMENT_FORMAT35c_TYPE[$start, "I_STATEMENT_FORMAT35c_TYPE"] INSTRUCTION_FORMAT35c_TYPE register_list nonvoid_type_descriptor) | //e.g. invoke-virtual/range {v25..v26} java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder; - INSTRUCTION_FORMAT3rc_METHOD OPEN_BRACKET register_range CLOSE_BRACKET fully_qualified_method {$size = Format3rc.Format.getByteCount();} + INSTRUCTION_FORMAT3rc_METHOD OPEN_BRACKET register_range CLOSE_BRACKET fully_qualified_method {$size = Format.Format3rc.size;} -> ^(I_STATEMENT_FORMAT3rc_METHOD[$start, "I_STATEMENT_FORMAT3rc_METHOD"] INSTRUCTION_FORMAT3rc_METHOD register_range fully_qualified_method) | //e.g. filled-new-array/range {v0..v6} I - INSTRUCTION_FORMAT3rc_TYPE OPEN_BRACKET register_range CLOSE_BRACKET nonvoid_type_descriptor {$size = Format3rc.Format.getByteCount();} + INSTRUCTION_FORMAT3rc_TYPE OPEN_BRACKET register_range CLOSE_BRACKET nonvoid_type_descriptor {$size = Format.Format3rc.size;} -> ^(I_STATEMENT_FORMAT3rc_TYPE[$start, "I_STATEMENT_FORMAT3rc_TYPE"] INSTRUCTION_FORMAT3rc_TYPE register_range nonvoid_type_descriptor) | //e.g. const-wide v0, 5000000000L - INSTRUCTION_FORMAT51l REGISTER fixed_literal {$size = Format51l.Format.getByteCount();} - -> ^(I_STATEMENT_FORMAT51l[$start, "I_STATEMENT_FORMAT51l"] INSTRUCTION_FORMAT51l REGISTER fixed_literal) + INSTRUCTION_FORMAT51l REGISTER fixed_literal {$size = Format.Format51l.size;} + -> ^(I_STATEMENT_FORMAT51l[$start, "I_STATEMENT_FORMAT51l"] INSTRUCTION_FORMAT51l REGISTER fixed_literal) | ARRAY_DATA_DIRECTIVE { diff --git a/src/main/antlr3/org/jf/smali/smaliTreeWalker.g b/src/main/antlr3/org/jf/smali/smaliTreeWalker.g index 9e4c8391..deb7cce7 100644 --- a/src/main/antlr3/org/jf/smali/smaliTreeWalker.g +++ b/src/main/antlr3/org/jf/smali/smaliTreeWalker.g @@ -401,7 +401,7 @@ method returns[ ClassDataItem.EncodedMethod encodedMethod, annotations ) { - ArrayList instructions = $statements.instructions; + ArrayList instructions = $statements.instructions; Pair, List> temp = $method::tryList.encodeTries(dexFile); List tries = temp.first; @@ -640,16 +640,16 @@ source $method::debugInfo.addSetFile($address.address, $string_literal.value); }; -statements[int totalMethodRegisters, int methodParameterRegisters] returns[ArrayList instructions] +statements[int totalMethodRegisters, int methodParameterRegisters] returns[ArrayList instructions] @init { - $instructions = new ArrayList(); + $instructions = new ArrayList(); } : ^(I_STATEMENTS (instruction[$totalMethodRegisters, $methodParameterRegisters] { if ($instruction.instruction != null) { $instructions.add($instruction.instruction); - $method::currentAddress += $instruction.instruction.getBytes().length/2; + $method::currentAddress += $instruction.instruction.getSize($method::currentAddress) / 2; } })*); @@ -690,7 +690,7 @@ offset_or_label returns[int offsetValue] : offset {$offsetValue = $offset.offsetValue;} | label_ref {$offsetValue = $label_ref.labelAddress-$method::currentAddress;}; -instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Instruction instruction] +instruction[int totalMethodRegisters, int methodParameterRegisters] returns[InstructionField instruction] : //e.g. goto endloop: ^(I_STATEMENT_FORMAT10t INSTRUCTION_FORMAT10t offset_or_label) { @@ -702,13 +702,13 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins throw new SemanticException(input, "The offset/label is out of range. The offset is " + Integer.toString(addressOffset) + " and the range for this opcode is [-128, 127]."); } - $instruction = Format10t.Format.make(dexFile, opcode.value, (byte)addressOffset); + $instruction = new InstructionField(dexFile, new Instruction10t(dexFile, opcode, (byte)addressOffset)); } | //e.g. return ^(I_STATEMENT_FORMAT10x INSTRUCTION_FORMAT10x) { Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT10x.text); - $instruction = Format10x.Format.make(dexFile, opcode.value); + $instruction = new InstructionField(dexFile, new Instruction10x(dexFile, opcode)); } | //e.g. const/4 v0, 5 ^(I_STATEMENT_FORMAT11n INSTRUCTION_FORMAT11n REGISTER short_integral_literal) @@ -719,7 +719,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins short litB = $short_integral_literal.value; literalTools.checkNibble(litB); - $instruction = Format11n.Format.make(dexFile, opcode.value, regA, (byte)litB); + $instruction = new InstructionField(dexFile, new Instruction11n(dexFile, opcode, regA, (byte)litB)); } | //e.g. move-result-object v1 ^(I_STATEMENT_FORMAT11x INSTRUCTION_FORMAT11x REGISTER) @@ -727,7 +727,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT11x.text); short regA = parseRegister_byte($REGISTER.text, $totalMethodRegisters, $methodParameterRegisters); - $instruction = Format11x.Format.make(dexFile, opcode.value, regA); + $instruction = new InstructionField(dexFile, new Instruction11x(dexFile, opcode, regA)); } | //e.g. move v1 v2 ^(I_STATEMENT_FORMAT12x INSTRUCTION_FORMAT12x registerA=REGISTER registerB=REGISTER) @@ -736,7 +736,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins byte regA = parseRegister_nibble($registerA.text, $totalMethodRegisters, $methodParameterRegisters); byte regB = parseRegister_nibble($registerB.text, $totalMethodRegisters, $methodParameterRegisters); - $instruction = Format12x.Format.make(dexFile, opcode.value, regA, regB); + $instruction = new InstructionField(dexFile, new Instruction12x(dexFile, opcode, regA, regB)); } | //e.g. goto/16 endloop: ^(I_STATEMENT_FORMAT20t INSTRUCTION_FORMAT20t offset_or_label) @@ -749,7 +749,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins throw new SemanticException(input, "The offset/label is out of range. The offset is " + Integer.toString(addressOffset) + " and the range for this opcode is [-32768, 32767]."); } - $instruction = Format20t.Format.make(dexFile, opcode.value, (short)addressOffset); + $instruction = new InstructionField(dexFile, new Instruction20t(dexFile, opcode, (short)addressOffset)); } | //e.g. sget_object v0 java/lang/System/out LJava/io/PrintStream; ^(I_STATEMENT_FORMAT21c_FIELD INSTRUCTION_FORMAT21c_FIELD REGISTER fully_qualified_field) @@ -759,7 +759,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins FieldIdItem fieldIdItem = $fully_qualified_field.fieldIdItem; - $instruction = Format21c.Format.make(dexFile, opcode.value, regA, fieldIdItem); + $instruction = new InstructionField(dexFile, new Instruction21c(dexFile, opcode, regA, fieldIdItem)); } | //e.g. const-string v1 "Hello World!" ^(I_STATEMENT_FORMAT21c_STRING INSTRUCTION_FORMAT21c_STRING REGISTER string_literal) @@ -769,7 +769,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins StringIdItem stringIdItem = new StringIdItem(dexFile, $string_literal.value); - $instruction = Format21c.Format.make(dexFile, opcode.value, regA, stringIdItem); + $instruction = new InstructionField(dexFile, new Instruction21c(dexFile, opcode, regA, stringIdItem)); } | //e.g. const-class v2 org/jf/HelloWorld2/HelloWorld2 ^(I_STATEMENT_FORMAT21c_TYPE INSTRUCTION_FORMAT21c_TYPE REGISTER reference_type_descriptor) @@ -779,7 +779,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins TypeIdItem typeIdItem = $reference_type_descriptor.type; - $instruction = Format21c.Format.make(dexFile, opcode.value, regA, typeIdItem); + $instruction = new InstructionField(dexFile, new Instruction21c(dexFile, opcode, regA, typeIdItem)); } | //e.g. const/high16 v1, 1234 ^(I_STATEMENT_FORMAT21h INSTRUCTION_FORMAT21h REGISTER short_integral_literal) @@ -789,7 +789,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins short litB = $short_integral_literal.value; - $instruction = Format21h.Format.make(dexFile, opcode.value, regA, litB); + $instruction = new InstructionField(dexFile, new Instruction21h(dexFile, opcode, regA, litB)); } | //e.g. const/16 v1, 1234 ^(I_STATEMENT_FORMAT21s INSTRUCTION_FORMAT21s REGISTER short_integral_literal) @@ -799,7 +799,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins short litB = $short_integral_literal.value; - $instruction = Format21s.Format.make(dexFile, opcode.value, regA, litB); + $instruction = new InstructionField(dexFile, new Instruction21s(dexFile, opcode, regA, litB)); } | //e.g. if-eqz v0, endloop: ^(I_STATEMENT_FORMAT21t INSTRUCTION_FORMAT21t REGISTER offset_or_label) @@ -813,7 +813,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins throw new SemanticException(input, "The offset/label is out of range. The offset is " + Integer.toString(addressOffset) + " and the range for this opcode is [-32768, 32767]."); } - $instruction = Format21t.Format.make(dexFile, opcode.value, regA, (short)addressOffset); + $instruction = new InstructionField(dexFile, new Instruction21t(dexFile, opcode, regA, (short)addressOffset)); } | //e.g. add-int v0, v1, 123 ^(I_STATEMENT_FORMAT22b INSTRUCTION_FORMAT22b registerA=REGISTER registerB=REGISTER short_integral_literal) @@ -825,7 +825,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins short litC = $short_integral_literal.value; literalTools.checkByte(litC); - $instruction = Format22b.Format.make(dexFile, opcode.value, regA, regB, (byte)litC); + $instruction = new InstructionField(dexFile, new Instruction22b(dexFile, opcode, regA, regB, (byte)litC)); } | //e.g. iput-object v1 v0 org/jf/HelloWorld2/HelloWorld2.helloWorld Ljava/lang/String; ^(I_STATEMENT_FORMAT22c_FIELD INSTRUCTION_FORMAT22c_FIELD registerA=REGISTER registerB=REGISTER fully_qualified_field) @@ -836,7 +836,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins FieldIdItem fieldIdItem = $fully_qualified_field.fieldIdItem; - $instruction = Format22c.Format.make(dexFile, opcode.value, regA, regB, fieldIdItem); + $instruction = new InstructionField(dexFile, new Instruction22c(dexFile, opcode, regA, regB, fieldIdItem)); } | //e.g. instance-of v0, v1, Ljava/lang/String; ^(I_STATEMENT_FORMAT22c_TYPE INSTRUCTION_FORMAT22c_TYPE registerA=REGISTER registerB=REGISTER nonvoid_type_descriptor) @@ -847,7 +847,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins TypeIdItem typeIdItem = $nonvoid_type_descriptor.type; - $instruction = Format22c.Format.make(dexFile, opcode.value, regA, regB, typeIdItem); + $instruction = new InstructionField(dexFile, new Instruction22c(dexFile, opcode, regA, regB, typeIdItem)); } | //e.g. add-int/lit16 v0, v1, 12345 ^(I_STATEMENT_FORMAT22s INSTRUCTION_FORMAT22s registerA=REGISTER registerB=REGISTER short_integral_literal) @@ -858,7 +858,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins short litC = $short_integral_literal.value; - $instruction = Format22s.Format.make(dexFile, opcode.value, regA, regB, litC); + $instruction = new InstructionField(dexFile, new Instruction22s(dexFile, opcode, regA, regB, litC)); } | //e.g. if-eq v0, v1, endloop: ^(I_STATEMENT_FORMAT22t INSTRUCTION_FORMAT22t registerA=REGISTER registerB=REGISTER offset_or_label) @@ -873,7 +873,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins throw new SemanticException(input, "The offset/label is out of range. The offset is " + Integer.toString(addressOffset) + " and the range for this opcode is [-32768, 32767]."); } - $instruction = Format22t.Format.make(dexFile, opcode.value, regA, regB, (short)addressOffset); + $instruction = new InstructionField(dexFile, new Instruction22t(dexFile, opcode, regA, regB, (short)addressOffset)); } | //e.g. move/from16 v1, v1234 ^(I_STATEMENT_FORMAT22x INSTRUCTION_FORMAT22x registerA=REGISTER registerB=REGISTER) @@ -882,7 +882,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins short regA = parseRegister_byte($registerA.text, $totalMethodRegisters, $methodParameterRegisters); int regB = parseRegister_short($registerB.text, $totalMethodRegisters, $methodParameterRegisters); - $instruction = Format22x.Format.make(dexFile, opcode.value, regA, regB); + $instruction = new InstructionField(dexFile, new Instruction22x(dexFile, opcode, regA, regB)); } | //e.g. add-int v1, v2, v3 ^(I_STATEMENT_FORMAT23x INSTRUCTION_FORMAT23x registerA=REGISTER registerB=REGISTER registerC=REGISTER) @@ -892,7 +892,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins short regB = parseRegister_byte($registerB.text, $totalMethodRegisters, $methodParameterRegisters); short regC = parseRegister_byte($registerC.text, $totalMethodRegisters, $methodParameterRegisters); - $instruction = Format23x.Format.make(dexFile, opcode.value, regA, regB, regC); + $instruction = new InstructionField(dexFile, new Instruction23x(dexFile, opcode, regA, regB, regC)); } | //e.g. goto/32 endloop: ^(I_STATEMENT_FORMAT30t INSTRUCTION_FORMAT30t offset_or_label) @@ -901,7 +901,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins int addressOffset = $offset_or_label.offsetValue; - $instruction = Format30t.Format.make(dexFile, opcode.value, addressOffset); + $instruction = new InstructionField(dexFile, new Instruction30t(dexFile, opcode, addressOffset)); } | //e.g. const-string/jumbo v1 "Hello World!" ^(I_STATEMENT_FORMAT31c INSTRUCTION_FORMAT31c REGISTER string_literal) @@ -911,7 +911,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins StringIdItem stringIdItem = new StringIdItem(dexFile, $string_literal.value); - $instruction = Format31c.Format.make(dexFile, opcode.value, regA, stringIdItem); + $instruction = new InstructionField(dexFile, new Instruction31c(dexFile, opcode, regA, stringIdItem)); } | //e.g. const v0, 123456 ^(I_STATEMENT_FORMAT31i INSTRUCTION_FORMAT31i REGISTER fixed_32bit_literal) @@ -921,7 +921,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins int litB = $fixed_32bit_literal.value; - $instruction = Format31i.Format.make(dexFile, opcode.value, regA, litB); + $instruction = new InstructionField(dexFile, new Instruction31i(dexFile, opcode, regA, litB)); } | //e.g. fill-array-data v0, ArrayData: ^(I_STATEMENT_FORMAT31t INSTRUCTION_FORMAT31t REGISTER offset_or_label) @@ -935,7 +935,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins addressOffset++; } - $instruction = Format31t.Format.make(dexFile, opcode.value, regA, addressOffset); + $instruction = new InstructionField(dexFile, new Instruction31t(dexFile, opcode, regA, addressOffset)); } | //e.g. move/16 v5678, v1234 ^(I_STATEMENT_FORMAT32x INSTRUCTION_FORMAT32x registerA=REGISTER registerB=REGISTER) @@ -944,7 +944,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins int regA = parseRegister_short($registerA.text, $totalMethodRegisters, $methodParameterRegisters); int regB = parseRegister_short($registerB.text, $totalMethodRegisters, $methodParameterRegisters); - $instruction = Format32x.Format.make(dexFile, opcode.value, regA, regB); + $instruction = new InstructionField(dexFile, new Instruction32x(dexFile, opcode, regA, regB)); } | //e.g. invoke-virtual {v0,v1} java/io/PrintStream/print(Ljava/lang/Stream;)V ^(I_STATEMENT_FORMAT35c_METHOD INSTRUCTION_FORMAT35c_METHOD register_list[$totalMethodRegisters, $methodParameterRegisters] fully_qualified_method) @@ -957,7 +957,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins MethodIdItem methodIdItem = $fully_qualified_method.methodIdItem; - $instruction = Format35c.Format.make(dexFile, opcode.value, registerCount, registers[0], registers[1], registers[2], registers[3], registers[4], methodIdItem); + $instruction = new InstructionField(dexFile, new Instruction35c(dexFile, opcode, registerCount, registers[0], registers[1], registers[2], registers[3], registers[4], methodIdItem)); } | //e.g. filled-new-array {v0,v1}, I ^(I_STATEMENT_FORMAT35c_TYPE INSTRUCTION_FORMAT35c_TYPE register_list[$totalMethodRegisters, $methodParameterRegisters] nonvoid_type_descriptor) @@ -970,7 +970,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins TypeIdItem typeIdItem = $nonvoid_type_descriptor.type; - $instruction = Format35c.Format.make(dexFile, opcode.value, registerCount, registers[0], registers[1], registers[2], registers[3], registers[4], typeIdItem); + $instruction = new InstructionField(dexFile, new Instruction35c(dexFile, opcode, registerCount, registers[0], registers[1], registers[2], registers[3], registers[4], typeIdItem)); } | //e.g. invoke-virtual/range {v25..v26} java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder; ^(I_STATEMENT_FORMAT3rc_METHOD INSTRUCTION_FORMAT3rc_METHOD register_range[$totalMethodRegisters, $methodParameterRegisters] fully_qualified_method) @@ -990,7 +990,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins MethodIdItem methodIdItem = $fully_qualified_method.methodIdItem; //not supported yet - $instruction = Format3rc.Format.make(dexFile, opcode.value, (short)registerCount, startRegister, methodIdItem); + $instruction = new InstructionField(dexFile, new Instruction3rc(dexFile, opcode, (short)registerCount, startRegister, methodIdItem)); } | //e.g. filled-new-array/range {v0..v6} I ^(I_STATEMENT_FORMAT3rc_TYPE INSTRUCTION_FORMAT3rc_TYPE register_range[$totalMethodRegisters, $methodParameterRegisters] nonvoid_type_descriptor) @@ -1010,7 +1010,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins TypeIdItem typeIdItem = $nonvoid_type_descriptor.type; //not supported yet - $instruction = Format3rc.Format.make(dexFile, opcode.value, (short)registerCount, startRegister, typeIdItem); + $instruction = new InstructionField(dexFile, new Instruction3rc(dexFile, opcode, (short)registerCount, startRegister, typeIdItem)); } | //e.g. const-wide v0, 5000000000L ^(I_STATEMENT_FORMAT51l INSTRUCTION_FORMAT51l REGISTER fixed_64bit_literal) @@ -1020,7 +1020,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins long litB = $fixed_64bit_literal.value; - $instruction = Format51l.Format.make(dexFile, opcode.value, regA, litB); + $instruction = new InstructionField(dexFile, new Instruction51l(dexFile, opcode, regA, litB)); } | //e.g. .array-data 4 1000000 .end array-data ^(I_STATEMENT_ARRAY_DATA ^(I_ARRAY_ELEMENT_SIZE short_integral_literal) array_elements) @@ -1028,7 +1028,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins int elementWidth = $short_integral_literal.value; List byteValues = $array_elements.values; - $instruction = ArrayData.make(dexFile, elementWidth, byteValues); + $instruction = new InstructionField(dexFile, new ArrayDataPseudoInstruction(dexFile, elementWidth, byteValues)); } | @@ -1037,7 +1037,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins int startKey = $fixed_32bit_literal.value; int[] targets = $packed_switch_targets.targets; - $instruction = PackedSwitchData.make(dexFile, startKey, targets); + $instruction = new InstructionField(dexFile, new PackedSwitchDataPseudoInstruction(dexFile, startKey, targets)); } | ^(I_STATEMENT_SPARSE_SWITCH ^(I_SPARSE_SWITCH_BASE_OFFSET base_offset=offset_or_label) sparse_switch_target_count sparse_switch_keys[$sparse_switch_target_count.targetCount] sparse_switch_targets[$base_offset.offsetValue, $sparse_switch_target_count.targetCount]) @@ -1045,7 +1045,7 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins int[] keys = $sparse_switch_keys.keys; int[] targets = $sparse_switch_targets.targets; - $instruction = SparseSwitchData.make(dexFile, keys, targets); + $instruction = new InstructionField(dexFile, new SparseSwitchDataPseudoInstruction(dexFile, keys, targets)); }; catch [Exception ex] { reportError(new SemanticException(input, ex)); diff --git a/src/main/java/org/jf/dexlib/CodeItem.java b/src/main/java/org/jf/dexlib/CodeItem.java index 054f8c7c..46fa6437 100644 --- a/src/main/java/org/jf/dexlib/CodeItem.java +++ b/src/main/java/org/jf/dexlib/CodeItem.java @@ -30,6 +30,7 @@ package org.jf.dexlib; import org.jf.dexlib.code.Instruction; import org.jf.dexlib.code.Opcode; +import org.jf.dexlib.code.InstructionField; import org.jf.dexlib.ItemType; import org.jf.dexlib.util.Input; import org.jf.dexlib.util.AnnotatedOutput; @@ -39,7 +40,7 @@ import java.util.List; import java.util.HashMap; public class CodeItem extends OffsettedItem { - private final ArrayList instructionList; + private final ArrayList instructionList; private final ArrayList tryItems = new ArrayList(); private final ArrayList catchHandlerList = new ArrayList(); @@ -57,7 +58,7 @@ public class CodeItem extends OffsettedItem { public CodeItem(final DexFile dexFile, int offset) { super(offset); - instructionList = new ArrayList(); + instructionList = new ArrayList(); fields = new Field[] { registersCountField = new ShortIntegerField("registers_size"), @@ -82,7 +83,7 @@ public class CodeItem extends OffsettedItem { public CodeItem(final DexFile dexFile, int registersCount, int inArguments, - List instructions, + List instructions, DebugInfoItem debugInfo, List tries, List handlers) { @@ -447,7 +448,7 @@ public class CodeItem extends OffsettedItem { public void writeTo(AnnotatedOutput out) { int startPosition = out.getCursor(); - for (Instruction instruction: instructionList) { + for (InstructionField instruction: instructionList) { instruction.writeTo(out); } if ((out.getCursor() - startPosition) != (instructionsSizeField.getCachedValue() * 2)) { @@ -460,7 +461,7 @@ public class CodeItem extends OffsettedItem { int startPosition = in.getCursor(); do { - Instruction instruction = new Instruction(dexFile); + InstructionField instruction = new InstructionField(dexFile); instruction.readFrom(in); instructionList.add(instruction); } while (in.getCursor() - startPosition < numBytes); @@ -475,23 +476,23 @@ public class CodeItem extends OffsettedItem { } public void copyTo(DexFile dexFile, InstructionListField copy) { - ArrayList copyInstructionList = copy.getInstructionList(); + ArrayList copyInstructionList = copy.getInstructionList(); copyInstructionList.clear(); - for (Instruction instruction: instructionList) { - Instruction instructionCopy = new Instruction(dexFile); + for (InstructionField instruction: instructionList) { + InstructionField instructionCopy = new InstructionField(dexFile); instruction.copyTo(dexFile, instructionCopy); copyInstructionList.add(instructionCopy); } } - private ArrayList getInstructionList() { + private ArrayList getInstructionList() { return instructionList; } //return the word size of the instruction list public int getInstructionWordCount() { int bytes = 0; - for (Instruction instruction: instructionList) { + for (InstructionField instruction: instructionList) { bytes += instruction.getSize(bytes); } return bytes/2; @@ -500,11 +501,11 @@ public class CodeItem extends OffsettedItem { //return the highest parameter word count of any method invokation public int getOutArguments() { int maxParamWordCount = 0; - for (Instruction instruction: instructionList) { - IndexedItem item = instruction.getReference(); + for (InstructionField instruction: instructionList) { + IndexedItem item = instruction.getInstruction().getReferencedItem(); if (item instanceof MethodIdItem) { MethodIdItem methodIdItem = (MethodIdItem)item; - Opcode opcode = instruction.getOpcode(); + Opcode opcode = instruction.getInstruction().getOpcode(); boolean isStatic = false; if (opcode == Opcode.INVOKE_STATIC || opcode == Opcode.INVOKE_STATIC_RANGE) { diff --git a/src/main/java/org/jf/dexlib/code/Format/ArrayData.java b/src/main/java/org/jf/dexlib/code/Format/ArrayData.java deleted file mode 100644 index 32abbc66..00000000 --- a/src/main/java/org/jf/dexlib/code/Format/ArrayData.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.jf.dexlib.code.Format; - -import org.jf.dexlib.code.Instruction; -import org.jf.dexlib.DexFile; - -import java.util.List; - -public class ArrayData -{ - public static Instruction make(DexFile dexFile, int elementWidth, List values) { - byte[] bytes; - - int byteCount = 0; - - for (byte[] value: values) { - byteCount += value.length; - } - - if (byteCount % elementWidth != 0) { - throw new RuntimeException("There are not a whole number of " + ((Integer)elementWidth).toString() + " byte elements"); - } - - bytes = new byte[byteCount+8]; - int position = 8; - - for (byte[] value: values) { - for (byte byteValue: value) { - bytes[position++] = byteValue; - } - } - - //fill-array-data psuedo-opcode - bytes[0] = 0x00; - bytes[1] = 0x03; - - bytes[2] = (byte)elementWidth; - bytes[3] = (byte)(elementWidth >> 8); - - int elementCount = byteCount / elementWidth; - - bytes[4] = (byte)elementCount; - bytes[5] = (byte)(elementCount >> 8); - bytes[6] = (byte)(elementCount >> 16); - bytes[7] = (byte)(elementCount >> 24); - - return new Instruction(dexFile, bytes, null); - } -} diff --git a/src/main/java/org/jf/dexlib/code/Format/ArrayDataPseudoInstruction.java b/src/main/java/org/jf/dexlib/code/Format/ArrayDataPseudoInstruction.java new file mode 100644 index 00000000..55f965b7 --- /dev/null +++ b/src/main/java/org/jf/dexlib/code/Format/ArrayDataPseudoInstruction.java @@ -0,0 +1,114 @@ +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib.code.Format; + +import org.jf.dexlib.code.Instruction; +import org.jf.dexlib.code.Opcode; +import org.jf.dexlib.DexFile; +import org.jf.dexlib.IndexedItem; +import org.jf.dexlib.util.Input; + +import java.util.List; +import java.util.ArrayList; + +public class ArrayDataPseudoInstruction extends Instruction +{ + public ArrayDataPseudoInstruction(DexFile dexFile, int elementWidth, List values) { + super(dexFile, Opcode.NOP, (IndexedItem)null); + + int byteCount = 0; + + for (byte[] value: values) { + byteCount += value.length; + } + + if (byteCount % elementWidth != 0) { + throw new RuntimeException("There are not a whole number of " + ((Integer)elementWidth).toString() + " byte elements"); + } + + int elementCount = byteCount / elementWidth; + + encodedInstruction = new byte[byteCount+8]; + encodedInstruction[0] = 0x00; + encodedInstruction[1] = 0x03; //fill-array-data psuedo-opcode + + encodedInstruction[2] = (byte)elementWidth; + encodedInstruction[3] = (byte)(elementWidth >> 8); + + encodedInstruction[4] = (byte)elementCount; + encodedInstruction[5] = (byte)(elementCount >> 8); + encodedInstruction[6] = (byte)(elementCount >> 16); + encodedInstruction[7] = (byte)(elementCount >> 24); + + int position = 8; + + for (byte[] value: values) { + for (byte byteValue: value) { + encodedInstruction[position++] = byteValue; + } + } + } + + private ArrayDataPseudoInstruction() { + } + + protected void checkFormat(Format format) { + //no need to check the format + } + + public static ArrayDataPseudoInstruction make(DexFile dexFile, Input input) { + byte opcodeByte = input.readByte(); + if (opcodeByte != 0x00) { + throw new RuntimeException("Invalid opcode byte for an ArrayData pseudo-instruction"); + } + byte subopcodeByte = input.readByte(); + if (subopcodeByte != 0x02) { + throw new RuntimeException("Invalid sub-opcode byte for an ArrayData pseudo-instruction"); + } + + int elementWidth = input.readShort(); + int size = input.readInt(); + + List elementsList = new ArrayList(); + + for (int i=0; i> 8); - bytes[4] = (byte)(offA >> 16); - bytes[5] = (byte)(offA >> 24); - - return new Instruction(dexFile, bytes, null); - } - - public int getByteCount() - { - return 6; - } - - public String getFormatName() - { - return "30t"; - } -} diff --git a/src/main/java/org/jf/dexlib/code/Format/Format31t.java b/src/main/java/org/jf/dexlib/code/Format/Format31t.java deleted file mode 100644 index 0686effe..00000000 --- a/src/main/java/org/jf/dexlib/code/Format/Format31t.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.jf.dexlib.code.Format; - -import org.jf.dexlib.code.Instruction; -import org.jf.dexlib.code.Opcode; -import org.jf.dexlib.DexFile; - -public class Format31t extends Format -{ - public static final Format31t Format = new Format31t(); - - private Format31t() { - } - - public Instruction make(DexFile dexFile, byte opcode, short regA, int offB) { - byte[] bytes = new byte[6]; - - Opcode op = Opcode.getOpcodeByValue(opcode); - - checkOpcodeFormat(op); - - if (regA >= 1<<8) { - throw new RuntimeException("The register number must be less than v256"); - } - - bytes[0] = opcode; - bytes[1] = (byte)regA; - - bytes[2] = (byte)offB; - bytes[3] = (byte)(offB >> 8); - - bytes[4] = (byte)(offB >> 16); - bytes[5] = (byte)(offB >> 24); - - return new Instruction(dexFile, bytes, null); - } - - public int getByteCount() { - return 6; - } - - public String getFormatName() { - return "31t"; - } -} diff --git a/src/main/java/org/jf/dexlib/code/Format/Format10t.java b/src/main/java/org/jf/dexlib/code/Format/Instruction10t.java similarity index 59% rename from src/main/java/org/jf/dexlib/code/Format/Format10t.java rename to src/main/java/org/jf/dexlib/code/Format/Instruction10t.java index c2b3c5d8..55fd3c5a 100644 --- a/src/main/java/org/jf/dexlib/code/Format/Format10t.java +++ b/src/main/java/org/jf/dexlib/code/Format/Instruction10t.java @@ -31,33 +31,51 @@ package org.jf.dexlib.code.Format; import org.jf.dexlib.code.Instruction; import org.jf.dexlib.code.Opcode; import org.jf.dexlib.DexFile; +import org.jf.dexlib.IndexedItem; -public class Format10t extends Format +public class Instruction10t extends Instruction { - public static final Format10t Format = new Format10t(); + public static final InstructionFactory Factory = new Factory(); - private Format10t() { - } + public Instruction10t(DexFile dexFile, Opcode opcode, byte offA) { + super(dexFile, opcode, (IndexedItem)null); - public Instruction make(DexFile dexFile, byte opcode, byte offA) { - Opcode op = Opcode.getOpcodeByValue(opcode); - - checkOpcodeFormat(op); - if (offA == 0) { throw new RuntimeException("The offset cannot be 0. Use goto/32 instead."); } - return new Instruction(dexFile, new byte[]{opcode,offA}, null); + encodedInstruction = new byte[2]; + encodedInstruction[0] = opcode.value; + encodedInstruction[1] = offA; } - public int getByteCount() - { - return 2; + private Instruction10t(DexFile dexFile, Opcode opcode, byte[] rest) { + super(dexFile, opcode, rest); + + if (getOffset() == 0) { + throw new RuntimeException("The offset cannot be 0. Use goto/32 instead."); + } } - public String getFormatName() - { - return "10t"; + private Instruction10t() { + } + + public Format getFormat() { + return Format.Format10t; + } + + protected Instruction makeClone() { + return new Instruction10t(); + } + + private static class Factory implements InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] rest) { + return new Instruction10t(dexFile, opcode, rest); + } + } + + + public byte getOffset() { + return encodedInstruction[1]; } } diff --git a/src/main/java/org/jf/dexlib/code/Format/Format21c.java b/src/main/java/org/jf/dexlib/code/Format/Instruction10x.java similarity index 62% rename from src/main/java/org/jf/dexlib/code/Format/Format21c.java rename to src/main/java/org/jf/dexlib/code/Format/Instruction10x.java index fd821632..bb59f792 100644 --- a/src/main/java/org/jf/dexlib/code/Format/Format21c.java +++ b/src/main/java/org/jf/dexlib/code/Format/Instruction10x.java @@ -32,41 +32,40 @@ import org.jf.dexlib.code.Instruction; import org.jf.dexlib.code.Opcode; import org.jf.dexlib.DexFile; import org.jf.dexlib.IndexedItem; -import org.jf.dexlib.TypeIdItem; -public class Format21c extends Format +public class Instruction10x extends Instruction { - public static final Format21c Format = new Format21c(); + public static final InstructionFactory Factory = new Factory(); + + public Instruction10x(DexFile dexFile, Opcode opcode) { + super(dexFile, opcode, (IndexedItem)null); + + encodedInstruction = new byte[2]; + encodedInstruction[0] = opcode.value; + } + + public Instruction10x(DexFile dexFile, Opcode opcode, byte[] rest) { + super(dexFile, opcode, rest); + + if (rest[0] != 0x00) { + throw new RuntimeException("The second byte of the instruction must be 0"); + } + } + + private Instruction10x() { + } + + public Format getFormat() { + return Format.Format10x; + } + + protected Instruction makeClone() { + return new Instruction10x(); + } - private Format21c() { - } - - public Instruction make(DexFile dexFile, byte opcode, short regA, IndexedItem item) { - byte[] bytes = new byte[4]; - - Opcode op = Opcode.getOpcodeByValue(opcode); - - checkOpcodeFormat(op); - - if (regA >= 1<<8) { - throw new RuntimeException("The register number must be less than v256"); + private static class Factory implements InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] rest) { + return new Instruction10x(dexFile, opcode, rest); } - - if (opcode == Opcode.NEW_INSTANCE.value && ((TypeIdItem)item).getTypeDescriptor().charAt(0) != 'L') { - throw new RuntimeException("Only class references can be used with the new-instance opcode"); - } - - bytes[0] = opcode; - bytes[1] = (byte)regA; - - return new Instruction(dexFile, bytes, item); } - - public int getByteCount() { - return 4; - } - - public String getFormatName() { - return "21c"; - } -} +} \ No newline at end of file diff --git a/src/main/java/org/jf/dexlib/code/Format/Format11n.java b/src/main/java/org/jf/dexlib/code/Format/Instruction11n.java similarity index 60% rename from src/main/java/org/jf/dexlib/code/Format/Format11n.java rename to src/main/java/org/jf/dexlib/code/Format/Instruction11n.java index eb85ac2b..2f072705 100644 --- a/src/main/java/org/jf/dexlib/code/Format/Format11n.java +++ b/src/main/java/org/jf/dexlib/code/Format/Instruction11n.java @@ -31,21 +31,15 @@ package org.jf.dexlib.code.Format; import org.jf.dexlib.code.Instruction; import org.jf.dexlib.code.Opcode; import org.jf.dexlib.DexFile; +import org.jf.dexlib.IndexedItem; +import org.jf.dexlib.util.NumberUtils; -public class Format11n extends Format +public class Instruction11n extends Instruction { - public static final Format11n Format = new Format11n(); - - private Format11n() { - } - - public Instruction make(DexFile dexFile, byte opcode, byte regA, byte litB) { - byte[] bytes = new byte[2]; - - Opcode op = Opcode.getOpcodeByValue(opcode); - - checkOpcodeFormat(op); + public static final InstructionFactory Factory = new Factory(); + public Instruction11n(DexFile dexFile, Opcode opcode, byte regA, byte litB) { + super(dexFile, opcode, (IndexedItem)null); if (regA >= 1<<4) { throw new RuntimeException("The register number must be less than v16"); @@ -55,21 +49,39 @@ public class Format11n extends Format litB >= 1<<3) { throw new RuntimeException("The literal value must be between -8 and 7 inclusive"); } - - bytes[0] = opcode; - bytes[1] = (byte)((litB << 4) | regA); - - - return new Instruction(dexFile, bytes, null); + + encodedInstruction = new byte[2]; + encodedInstruction[0] = opcode.value; + encodedInstruction[1] = (byte)((litB << 4) | regA); } - public int getByteCount() - { - return 2; + private Instruction11n(DexFile dexFile, Opcode opcode, byte[] rest) { + super(dexFile, opcode, rest); } - public String getFormatName() - { - return "11n"; + private Instruction11n() { } -} + + public Format getFormat() { + return Format.Format11n; + } + + protected Instruction makeClone() { + return new Instruction11n(); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] rest) { + return new Instruction11n(dexFile, opcode, rest); + } + } + + + public byte getRegister() { + return NumberUtils.decodeLowUnsignedNibble(encodedInstruction[1]); + } + + public byte getLiteral() { + return NumberUtils.decodeHighSignedNibble(encodedInstruction[1]); + } +} \ No newline at end of file diff --git a/src/main/java/org/jf/dexlib/code/Format/Format31c.java b/src/main/java/org/jf/dexlib/code/Format/Instruction11x.java similarity index 61% rename from src/main/java/org/jf/dexlib/code/Format/Format31c.java rename to src/main/java/org/jf/dexlib/code/Format/Instruction11x.java index 7bde2a12..25a216f0 100644 --- a/src/main/java/org/jf/dexlib/code/Format/Format31c.java +++ b/src/main/java/org/jf/dexlib/code/Format/Instruction11x.java @@ -32,36 +32,47 @@ import org.jf.dexlib.code.Instruction; import org.jf.dexlib.code.Opcode; import org.jf.dexlib.DexFile; import org.jf.dexlib.IndexedItem; +import org.jf.dexlib.util.NumberUtils; -public class Format31c extends Format +public class Instruction11x extends Instruction { - public static final Format31c Format = new Format31c(); + public static final Instruction.InstructionFactory Factory = new Factory(); - private Format31c() { - } - - public Instruction make(DexFile dexFile, byte opcode, short regA, IndexedItem item) { - byte[] bytes = new byte[6]; - - Opcode op = Opcode.getOpcodeByValue(opcode); - - checkOpcodeFormat(op); + public Instruction11x(DexFile dexFile, Opcode opcode, short regA) { + super(dexFile, opcode, (IndexedItem)null); if (regA >= 1<<8) { throw new RuntimeException("The register number must be less than v256"); } - bytes[0] = opcode; - bytes[1] = (byte)regA; - - return new Instruction(dexFile, bytes, item); + encodedInstruction = new byte[2]; + encodedInstruction[0] = opcode.value; + encodedInstruction[1] = (byte)regA; } - public int getByteCount() { - return 6; + private Instruction11x(DexFile dexFile, Opcode opcode, byte[] rest) { + super(dexFile, opcode, rest); } - public String getFormatName() { - return "31c"; + private Instruction11x() { + } + + public Format getFormat() { + return Format.Format11x; + } + + protected Instruction makeClone() { + return new Instruction11x(); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] rest) { + return new Instruction11x(dexFile, opcode, rest); + } + } + + + public short getRegister() { + return NumberUtils.decodeUnsignedByte(encodedInstruction[1]); } } diff --git a/src/main/java/org/jf/dexlib/code/Format/Format22c.java b/src/main/java/org/jf/dexlib/code/Format/Instruction12x.java similarity index 58% rename from src/main/java/org/jf/dexlib/code/Format/Format22c.java rename to src/main/java/org/jf/dexlib/code/Format/Instruction12x.java index 08fd95b8..b915156b 100644 --- a/src/main/java/org/jf/dexlib/code/Format/Format22c.java +++ b/src/main/java/org/jf/dexlib/code/Format/Instruction12x.java @@ -32,38 +32,52 @@ import org.jf.dexlib.code.Instruction; import org.jf.dexlib.code.Opcode; import org.jf.dexlib.DexFile; import org.jf.dexlib.IndexedItem; +import org.jf.dexlib.util.NumberUtils; -public class Format22c extends Format +public class Instruction12x extends Instruction { - public static final Format22c Format = new Format22c(); + public static final Instruction.InstructionFactory Factory = new Factory(); - private Format22c() { - } - - public Instruction make(DexFile dexFile, byte opcode, byte regA, byte regB, IndexedItem item) { - byte[] bytes = new byte[4]; - - Opcode op = Opcode.getOpcodeByValue(opcode); - - checkOpcodeFormat(op); + public Instruction12x(DexFile dexFile, Opcode opcode, byte regA, byte regB) { + super(dexFile, opcode, (IndexedItem)null); if (regA >= 1<<4 || regB >= 1<<4) { throw new RuntimeException("The register number must be less than v16"); } - - bytes[0] = opcode; - bytes[1] = (byte)((regB << 4) | regA); - - return new Instruction(dexFile, bytes, item); + encodedInstruction = new byte[2]; + encodedInstruction[0] = opcode.value; + encodedInstruction[1] = (byte)((regB << 4) | regA); } - public int getByteCount() { - return 4; + private Instruction12x(DexFile dexFile, Opcode opcode, byte[] rest) { + super(dexFile, opcode, rest); } - public String getFormatName() { - return "22c"; + private Instruction12x() { + } + + public Format getFormat() { + return Format.Format12x; + } + + protected Instruction makeClone() { + return new Instruction12x(); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] rest) { + return new Instruction12x(dexFile, opcode, rest); + } + } + + + public byte getRegisterA() { + return NumberUtils.decodeLowUnsignedNibble(encodedInstruction[1]); + } + + public byte getRegisterB() { + return NumberUtils.decodeHighUnsignedNibble(encodedInstruction[1]); } } diff --git a/src/main/java/org/jf/dexlib/code/Format/Format20t.java b/src/main/java/org/jf/dexlib/code/Format/Instruction20t.java similarity index 56% rename from src/main/java/org/jf/dexlib/code/Format/Format20t.java rename to src/main/java/org/jf/dexlib/code/Format/Instruction20t.java index 3355d4c7..a8c7fc7e 100644 --- a/src/main/java/org/jf/dexlib/code/Format/Format20t.java +++ b/src/main/java/org/jf/dexlib/code/Format/Instruction20t.java @@ -31,39 +31,53 @@ package org.jf.dexlib.code.Format; import org.jf.dexlib.code.Instruction; import org.jf.dexlib.code.Opcode; import org.jf.dexlib.DexFile; +import org.jf.dexlib.IndexedItem; +import org.jf.dexlib.util.NumberUtils; -public class Format20t extends Format +public class Instruction20t extends Instruction { - public static final Format20t Format = new Format20t(); + public static final Instruction.InstructionFactory Factory = new Factory(); - private Format20t() { - } - - public Instruction make(DexFile dexFile, byte opcode, short offA) { - byte[] bytes = new byte[4]; - - Opcode op = Opcode.getOpcodeByValue(opcode); - - checkOpcodeFormat(op); + public Instruction20t(DexFile dexFile, Opcode opcode, short offA) { + super(dexFile, opcode, (IndexedItem)null); if (offA == 0) { throw new RuntimeException("The offset cannot be 0. Use goto/32 instead."); } - bytes[0] = opcode; - bytes[2] = (byte)offA; - bytes[3] = (byte)(offA >> 8); - - return new Instruction(dexFile, bytes, null); + encodedInstruction = new byte[4]; + encodedInstruction[0] = opcode.value; + encodedInstruction[2] = (byte)offA; + encodedInstruction[3] = (byte)(offA>>8); } - public int getByteCount() - { - return 4; + private Instruction20t(DexFile dexFile, Opcode opcode, byte[] rest) { + super(dexFile, opcode, rest); + + if (getOffset() == 0) { + throw new RuntimeException("The offset cannot be 0. Use goto/32 instead."); + } } - public String getFormatName() - { - return "20t"; + private Instruction20t() { + } + + public Format getFormat() { + return Format.Format20t; + } + + protected Instruction makeClone() { + return new Instruction20t(); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] rest) { + return new Instruction20t(dexFile, opcode, rest); + } + } + + + public short getOffset() { + return NumberUtils.decodeShort(encodedInstruction[2], encodedInstruction[3]); } } diff --git a/src/main/java/org/jf/dexlib/code/Format/Instruction21c.java b/src/main/java/org/jf/dexlib/code/Format/Instruction21c.java new file mode 100644 index 00000000..05342a42 --- /dev/null +++ b/src/main/java/org/jf/dexlib/code/Format/Instruction21c.java @@ -0,0 +1,88 @@ +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib.code.Format; + +import org.jf.dexlib.code.Instruction; +import org.jf.dexlib.code.Opcode; +import org.jf.dexlib.DexFile; +import org.jf.dexlib.IndexedItem; +import org.jf.dexlib.TypeIdItem; +import org.jf.dexlib.util.NumberUtils; + +public class Instruction21c extends Instruction +{ + public static final Instruction.InstructionFactory Factory = new Factory(); + + public Instruction21c(DexFile dexFile, Opcode opcode, short regA, IndexedItem item) { + super(dexFile, opcode, item); + + if (regA >= 1<<8) { + throw new RuntimeException("The register number must be less than v256"); + } + + if (opcode == Opcode.NEW_INSTANCE && ((TypeIdItem)item).getTypeDescriptor().charAt(0) != 'L') { + throw new RuntimeException("Only class references can be used with the new-instance opcode"); + } + + encodedInstruction = new byte[4]; + encodedInstruction[0] = opcode.value; + encodedInstruction[1] = (byte)regA; + //the item index will be set later, during placement/writing + } + + private Instruction21c(DexFile dexFile, Opcode opcode, byte[] rest) { + super(dexFile, opcode, rest); + + if (opcode == Opcode.NEW_INSTANCE && ((TypeIdItem)this.getReferencedItem()).getTypeDescriptor().charAt(0) != 'L') { + throw new RuntimeException("Only class references can be used with the new-instance opcode"); + } + } + + private Instruction21c() { + } + + public Format getFormat() { + return Format.Format21c; + } + + protected Instruction makeClone() { + return new Instruction21c(); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] rest) { + return new Instruction21c(dexFile, opcode, rest); + } + } + + + public short getRegister() { + return NumberUtils.decodeUnsignedByte(encodedInstruction[1]); + } +} diff --git a/src/main/java/org/jf/dexlib/code/Format/Format21h.java b/src/main/java/org/jf/dexlib/code/Format/Instruction21h.java similarity index 56% rename from src/main/java/org/jf/dexlib/code/Format/Format21h.java rename to src/main/java/org/jf/dexlib/code/Format/Instruction21h.java index b0e032bd..81ff3896 100644 --- a/src/main/java/org/jf/dexlib/code/Format/Format21h.java +++ b/src/main/java/org/jf/dexlib/code/Format/Instruction21h.java @@ -31,40 +31,54 @@ package org.jf.dexlib.code.Format; import org.jf.dexlib.code.Instruction; import org.jf.dexlib.code.Opcode; import org.jf.dexlib.DexFile; +import org.jf.dexlib.IndexedItem; +import org.jf.dexlib.util.NumberUtils; -public class Format21h extends Format +public class Instruction21h extends Instruction { - public static final Format21h Format = new Format21h(); + public static final Instruction.InstructionFactory Factory = new Factory(); - private Format21h() { - } - - public Instruction make(DexFile dexFile, byte opcode, short regA, short litB) { - byte[] bytes = new byte[4]; - - Opcode op = Opcode.getOpcodeByValue(opcode); - - checkOpcodeFormat(op); + public Instruction21h(DexFile dexFile, Opcode opcode, short regA, short litB) { + super(dexFile, opcode, (IndexedItem)null); if (regA >= 1<<8) { throw new RuntimeException("The register number must be less than v256"); } - bytes[0] = opcode; - bytes[1] = (byte)regA; - bytes[2] = (byte)litB; - bytes[3] = (byte)(litB >> 8); - - return new Instruction(dexFile, bytes, null); + encodedInstruction = new byte[4]; + encodedInstruction[0] = opcode.value; + encodedInstruction[1] = (byte)regA; + encodedInstruction[2] = (byte)litB; + encodedInstruction[3] = (byte)(litB >> 8); } - public int getByteCount() - { - return 4; + private Instruction21h(DexFile dexFile, Opcode opcode, byte[] rest) { + super(dexFile, opcode, rest); } - public String getFormatName() - { - return "21h"; + private Instruction21h() { + } + + public Format getFormat() { + return Format.Format21h; + } + + protected Instruction makeClone() { + return new Instruction21h(); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] rest) { + return new Instruction21h(dexFile, opcode, rest); + } + } + + + public short getRegister() { + return NumberUtils.decodeUnsignedByte(encodedInstruction[1]); + } + + public short getLiteral() { + return NumberUtils.decodeShort(encodedInstruction[2], encodedInstruction[3]); } } diff --git a/src/main/java/org/jf/dexlib/code/Format/Format21s.java b/src/main/java/org/jf/dexlib/code/Format/Instruction21s.java similarity index 56% rename from src/main/java/org/jf/dexlib/code/Format/Format21s.java rename to src/main/java/org/jf/dexlib/code/Format/Instruction21s.java index 1c8d780e..032bf4a3 100644 --- a/src/main/java/org/jf/dexlib/code/Format/Format21s.java +++ b/src/main/java/org/jf/dexlib/code/Format/Instruction21s.java @@ -31,40 +31,54 @@ package org.jf.dexlib.code.Format; import org.jf.dexlib.code.Instruction; import org.jf.dexlib.code.Opcode; import org.jf.dexlib.DexFile; +import org.jf.dexlib.IndexedItem; +import org.jf.dexlib.util.NumberUtils; -public class Format21s extends Format +public class Instruction21s extends Instruction { - public static final Format21s Format = new Format21s(); + public static final Instruction.InstructionFactory Factory = new Factory(); - private Format21s() { - } - - public Instruction make(DexFile dexFile, byte opcode, short regA, short litB) { - byte[] bytes = new byte[4]; - - Opcode op = Opcode.getOpcodeByValue(opcode); - - checkOpcodeFormat(op); + public Instruction21s(DexFile dexFile, Opcode opcode, short regA, short litB) { + super(dexFile, opcode, (IndexedItem)null); if (regA >= 1<<8) { throw new RuntimeException("The register number must be less than v256"); } - bytes[0] = opcode; - bytes[1] = (byte)regA; - bytes[2] = (byte)litB; - bytes[3] = (byte)(litB >> 8); - - return new Instruction(dexFile, bytes, null); + encodedInstruction = new byte[4]; + encodedInstruction[0] = opcode.value; + encodedInstruction[1] = (byte)regA; + encodedInstruction[2] = (byte)litB; + encodedInstruction[3] = (byte)(litB >> 8); } - public int getByteCount() - { - return 4; + private Instruction21s(DexFile dexFile, Opcode opcode, byte[] rest) { + super(dexFile, opcode, rest); } - public String getFormatName() - { - return "21s"; + private Instruction21s() { + } + + public Format getFormat() { + return Format.Format21s; + } + + protected Instruction makeClone() { + return new Instruction21s(); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] rest) { + return new Instruction21s(dexFile, opcode, rest); + } + } + + + public short getRegister() { + return NumberUtils.decodeUnsignedByte(encodedInstruction[1]); + } + + public short getLiteral() { + return NumberUtils.decodeShort(encodedInstruction[2], encodedInstruction[3]); } } diff --git a/src/main/java/org/jf/dexlib/code/Format/Format21t.java b/src/main/java/org/jf/dexlib/code/Format/Instruction21t.java similarity index 55% rename from src/main/java/org/jf/dexlib/code/Format/Format21t.java rename to src/main/java/org/jf/dexlib/code/Format/Instruction21t.java index 4fe6cef1..b59342c8 100644 --- a/src/main/java/org/jf/dexlib/code/Format/Format21t.java +++ b/src/main/java/org/jf/dexlib/code/Format/Instruction21t.java @@ -31,44 +31,62 @@ package org.jf.dexlib.code.Format; import org.jf.dexlib.code.Instruction; import org.jf.dexlib.code.Opcode; import org.jf.dexlib.DexFile; +import org.jf.dexlib.IndexedItem; +import org.jf.dexlib.util.NumberUtils; -public class Format21t extends Format +public class Instruction21t extends Instruction { - public static final Format21t Format = new Format21t(); + public static final Instruction.InstructionFactory Factory = new Factory(); - private Format21t() { - } - - public Instruction make(DexFile dexFile, byte opcode, short regA, short offB) { - byte[] bytes = new byte[4]; - - Opcode op = Opcode.getOpcodeByValue(opcode); - - checkOpcodeFormat(op); + public Instruction21t(DexFile dexFile, Opcode opcode, short regA, short offB) { + super(dexFile, opcode, (IndexedItem)null); if (regA >= 1<<8) { throw new RuntimeException("The register number must be less than v256"); } - if (offB == 0) { + if (offB == 0) { throw new RuntimeException("The offset cannot be 0."); } - bytes[0] = opcode; - bytes[1] = (byte)regA; - bytes[2] = (byte)offB; - bytes[3] = (byte)(offB >> 8); - - return new Instruction(dexFile, bytes, null); + encodedInstruction = new byte[4]; + encodedInstruction[0] = opcode.value; + encodedInstruction[1] = (byte)regA; + encodedInstruction[2] = (byte)offB; + encodedInstruction[3] = (byte)(offB >> 8); } - public int getByteCount() - { - return 4; + private Instruction21t(DexFile dexFile, Opcode opcode, byte[] rest) { + super(dexFile, opcode, rest); + + if (getOffset() == 0) { + throw new RuntimeException("The offset cannot be 0."); + } } - public String getFormatName() - { - return "21t"; + private Instruction21t() { + } + + public Format getFormat() { + return Format.Format21t; + } + + protected Instruction makeClone() { + return new Instruction21t(); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] rest) { + return new Instruction21t(dexFile, opcode, rest); + } + } + + + public short getRegister() { + return NumberUtils.decodeUnsignedByte(encodedInstruction[1]); + } + + public short getOffset() { + return NumberUtils.decodeShort(encodedInstruction[2], encodedInstruction[3]); } } diff --git a/src/main/java/org/jf/dexlib/code/Format/Instruction22b.java b/src/main/java/org/jf/dexlib/code/Format/Instruction22b.java new file mode 100644 index 00000000..e3131666 --- /dev/null +++ b/src/main/java/org/jf/dexlib/code/Format/Instruction22b.java @@ -0,0 +1,89 @@ +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib.code.Format; + +import org.jf.dexlib.code.Instruction; +import org.jf.dexlib.code.Opcode; +import org.jf.dexlib.DexFile; +import org.jf.dexlib.IndexedItem; +import org.jf.dexlib.util.NumberUtils; + +public class Instruction22b extends Instruction +{ + public static final Instruction.InstructionFactory Factory = new Factory(); + + public Instruction22b(DexFile dexFile, Opcode opcode, short regA, short regB, byte litC) { + super(dexFile, opcode, (IndexedItem)null); + + if (regA >= 1<<8 || + regB >= 1<<8) { + throw new RuntimeException("The register number must be less than v256"); + } + + encodedInstruction = new byte[4]; + encodedInstruction[0] = opcode.value; + encodedInstruction[1] = (byte)regA; + encodedInstruction[2] = (byte)regB; + encodedInstruction[3] = litC; + } + + private Instruction22b(DexFile dexFile, Opcode opcode, byte[] rest) { + super(dexFile, opcode, rest); + } + + private Instruction22b() { + } + + public Format getFormat() { + return Format.Format22b; + } + + protected Instruction makeClone() { + return new Instruction22b(); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] rest) { + return new Instruction22b(dexFile, opcode, rest); + } + } + + + public short getRegisterA() { + return NumberUtils.decodeUnsignedByte(encodedInstruction[1]); + } + + public short getRegisterB() { + return NumberUtils.decodeUnsignedByte(encodedInstruction[2]); + } + + public byte getLiteral() { + return encodedInstruction[3]; + } +} diff --git a/src/main/java/org/jf/dexlib/code/Format/Format12x.java b/src/main/java/org/jf/dexlib/code/Format/Instruction22c.java similarity index 56% rename from src/main/java/org/jf/dexlib/code/Format/Format12x.java rename to src/main/java/org/jf/dexlib/code/Format/Instruction22c.java index dcdaaf73..aecee5e3 100644 --- a/src/main/java/org/jf/dexlib/code/Format/Format12x.java +++ b/src/main/java/org/jf/dexlib/code/Format/Instruction22c.java @@ -31,39 +31,54 @@ package org.jf.dexlib.code.Format; import org.jf.dexlib.code.Instruction; import org.jf.dexlib.code.Opcode; import org.jf.dexlib.DexFile; +import org.jf.dexlib.IndexedItem; +import org.jf.dexlib.util.NumberUtils; -public class Format12x extends Format +public class Instruction22c extends Instruction { - public static final Format12x Format = new Format12x(); + public static final Instruction.InstructionFactory Factory = new Factory(); - private Format12x() { - } - - public Instruction make(DexFile dexFile, byte opcode, byte regA, byte regB) { - byte[] bytes = new byte[2]; - - Opcode op = Opcode.getOpcodeByValue(opcode); - - checkOpcodeFormat(op); + public Instruction22c(DexFile dexFile, Opcode opcode, byte regA, byte regB, IndexedItem item) { + super(dexFile, opcode, item); if (regA >= 1<<4 || regB >= 1<<4) { throw new RuntimeException("The register number must be less than v16"); } - bytes[0] = opcode; - bytes[1] = (byte)((regB << 4) | regA); - - return new Instruction(dexFile, bytes, null); + encodedInstruction = new byte[4]; + encodedInstruction[0] = opcode.value; + encodedInstruction[1] = (byte)((regB << 4) | regA); + //the item index will be set later, during placement/writing } - public int getByteCount() - { - return 2; + private Instruction22c(DexFile dexFile, Opcode opcode, byte[] rest) { + super(dexFile, opcode, rest); } - public String getFormatName() - { - return "12x"; + private Instruction22c() { + } + + public Format getFormat() { + return Format.Format22c; + } + + protected Instruction makeClone() { + return new Instruction22c(); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] rest) { + return new Instruction22c(dexFile, opcode, rest); + } + } + + + public byte getRegisterA() { + return NumberUtils.decodeLowUnsignedNibble(encodedInstruction[1]); + } + + public byte getRegisterB() { + return NumberUtils.decodeHighUnsignedNibble(encodedInstruction[1]); } } diff --git a/src/main/java/org/jf/dexlib/code/Format/Format22s.java b/src/main/java/org/jf/dexlib/code/Format/Instruction22s.java similarity index 53% rename from src/main/java/org/jf/dexlib/code/Format/Format22s.java rename to src/main/java/org/jf/dexlib/code/Format/Instruction22s.java index 24f7b9f3..004e2ba9 100644 --- a/src/main/java/org/jf/dexlib/code/Format/Format22s.java +++ b/src/main/java/org/jf/dexlib/code/Format/Instruction22s.java @@ -31,44 +31,59 @@ package org.jf.dexlib.code.Format; import org.jf.dexlib.code.Instruction; import org.jf.dexlib.code.Opcode; import org.jf.dexlib.DexFile; +import org.jf.dexlib.IndexedItem; +import org.jf.dexlib.util.NumberUtils; -public class Format22s extends Format +public class Instruction22s extends Instruction { - public static final Format22s Format = new Format22s(); + public static final Instruction.InstructionFactory Factory = new Factory(); - private Format22s() { - } + public Instruction22s(DexFile dexFile, Opcode opcode, byte regA, byte regB, short litC) { + super(dexFile, opcode, (IndexedItem)null); - public Instruction make(DexFile dexFile, byte opcode, byte regA, byte regB, short litC) { - byte[] bytes = new byte[4]; - - Opcode op = Opcode.getOpcodeByValue(opcode); - - checkOpcodeFormat(op); - - if (regA >= 1<<4) { + if (regA >= 1<<4 || + regB >= 1<<4) { throw new RuntimeException("The register number must be less than v16"); } - if (regB >= 1<<4) { - throw new RuntimeException("The register number must be less than v16"); + encodedInstruction = new byte[4]; + encodedInstruction[0] = opcode.value; + encodedInstruction[1] = (byte)((regB << 4) | regA); + encodedInstruction[2] = (byte)litC; + encodedInstruction[3] = (byte)(litC >> 8); + } + + private Instruction22s(DexFile dexFile, Opcode opcode, byte[] rest) { + super(dexFile, opcode, rest); + } + + private Instruction22s() { + } + + public Format getFormat() { + return Format.Format22s; + } + + protected Instruction makeClone() { + return new Instruction22s(); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] rest) { + return new Instruction22s(dexFile, opcode, rest); } - - bytes[0] = opcode; - bytes[1] = (byte)((regB << 4) | regA); - bytes[2] = (byte)litC; - bytes[3] = (byte)(litC >> 8); - - return new Instruction(dexFile, bytes, null); } - public int getByteCount() - { - return 4; + + public byte getRegisterA() { + return NumberUtils.decodeLowUnsignedNibble(encodedInstruction[1]); } - public String getFormatName() - { - return "22s"; + public byte getRegisterB() { + return NumberUtils.decodeHighUnsignedNibble(encodedInstruction[1]); + } + + public short getLiteral() { + return NumberUtils.decodeShort(encodedInstruction[2], encodedInstruction[3]); } } diff --git a/src/main/java/org/jf/dexlib/code/Format/Format22t.java b/src/main/java/org/jf/dexlib/code/Format/Instruction22t.java similarity index 52% rename from src/main/java/org/jf/dexlib/code/Format/Format22t.java rename to src/main/java/org/jf/dexlib/code/Format/Instruction22t.java index ea785d61..6ebe57d7 100644 --- a/src/main/java/org/jf/dexlib/code/Format/Format22t.java +++ b/src/main/java/org/jf/dexlib/code/Format/Instruction22t.java @@ -31,26 +31,18 @@ package org.jf.dexlib.code.Format; import org.jf.dexlib.code.Instruction; import org.jf.dexlib.code.Opcode; import org.jf.dexlib.DexFile; +import org.jf.dexlib.IndexedItem; +import org.jf.dexlib.util.NumberUtils; -public class Format22t extends Format +public class Instruction22t extends Instruction { - public static final Format22t Format = new Format22t(); + public static final Instruction.InstructionFactory Factory = new Factory(); - private Format22t() { - } + public Instruction22t(DexFile dexFile, Opcode opcode, byte regA, byte regB, short offC) { + super(dexFile, opcode, (IndexedItem)null); - public Instruction make(DexFile dexFile, byte opcode, byte regA, byte regB, short offC) { - byte[] bytes = new byte[4]; - - Opcode op = Opcode.getOpcodeByValue(opcode); - - checkOpcodeFormat(op); - - if (regA >= 1<<4) { - throw new RuntimeException("The register number must be less than v16"); - } - - if (regB >= 1<<4) { + if (regA >= 1<<4 || + regB >= 1<<4) { throw new RuntimeException("The register number must be less than v16"); } @@ -58,19 +50,48 @@ public class Format22t extends Format throw new RuntimeException("The offset cannot be 0."); } - bytes[0] = opcode; - bytes[1] = (byte)((regB << 4) | regA); - bytes[2] = (byte)offC; - bytes[3] = (byte)(offC >> 8); - - return new Instruction(dexFile, bytes, null); + encodedInstruction = new byte[4]; + encodedInstruction[0] = opcode.value; + encodedInstruction[1] = (byte)((regB << 4) | regA); + encodedInstruction[2] = (byte)offC; + encodedInstruction[3] = (byte)(offC >> 8); } - public int getByteCount() { - return 4; + private Instruction22t(DexFile dexFile, Opcode opcode, byte[] rest) { + super(dexFile, opcode, rest); + + if (getOffset() == 0) { + throw new RuntimeException("The offset cannot be 0."); + } } - public String getFormatName() { - return "22t"; + private Instruction22t() { + } + + public Format getFormat() { + return Format.Format22t; + } + + protected Instruction makeClone() { + return new Instruction22t(); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] rest) { + return new Instruction22t(dexFile, opcode, rest); + } + } + + + public byte getRegisterA() { + return NumberUtils.decodeLowUnsignedNibble(encodedInstruction[1]); + } + + public byte getRegisterB() { + return NumberUtils.decodeHighUnsignedNibble(encodedInstruction[1]); + } + + public short getOffset() { + return NumberUtils.decodeShort(encodedInstruction[2], encodedInstruction[3]); } } diff --git a/src/main/java/org/jf/dexlib/code/Format/Format22x.java b/src/main/java/org/jf/dexlib/code/Format/Instruction22x.java similarity index 57% rename from src/main/java/org/jf/dexlib/code/Format/Format22x.java rename to src/main/java/org/jf/dexlib/code/Format/Instruction22x.java index c63bfe1d..94412858 100644 --- a/src/main/java/org/jf/dexlib/code/Format/Format22x.java +++ b/src/main/java/org/jf/dexlib/code/Format/Instruction22x.java @@ -31,42 +31,58 @@ package org.jf.dexlib.code.Format; import org.jf.dexlib.code.Instruction; import org.jf.dexlib.code.Opcode; import org.jf.dexlib.DexFile; +import org.jf.dexlib.IndexedItem; +import org.jf.dexlib.util.NumberUtils; -public class Format22x extends Format +public class Instruction22x extends Instruction { - public static final Format22x Format = new Format22x(); + public static final Instruction.InstructionFactory Factory = new Factory(); - private Format22x() { - } - - public Instruction make(DexFile dexFile, byte opcode, short regA, int regB) { - byte[] bytes = new byte[4]; - - Opcode op = Opcode.getOpcodeByValue(opcode); - - checkOpcodeFormat(op); + public Instruction22x(DexFile dexFile, Opcode opcode, short regA, int regB) { + super(dexFile, opcode, (IndexedItem)null); if (regA >= 1<<8) { - throw new RuntimeException("The register number must be less than v256"); + throw new RuntimeException("The register number must be less than v16"); } if (regB >= 1<<16) { throw new RuntimeException("The register number must be less than v65536"); } - bytes[0] = opcode; - bytes[1] = (byte)regA; - bytes[2] = (byte)regB; - bytes[3] = (byte)(regB >> 8); - - return new Instruction(dexFile, bytes, null); + encodedInstruction = new byte[4]; + encodedInstruction[0] = opcode.value; + encodedInstruction[1] = (byte)regA; + encodedInstruction[2] = (byte)regB; + encodedInstruction[3] = (byte)(regB >> 8); } - public int getByteCount() { - return 4; + private Instruction22x(DexFile dexFile, Opcode opcode, byte[] rest) { + super(dexFile, opcode, rest); } - public String getFormatName() { - return "22x"; + private Instruction22x() { + } + + public Format getFormat() { + return Format.Format22x; + } + + protected Instruction makeClone() { + return new Instruction22x(); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] rest) { + return new Instruction22x(dexFile, opcode, rest); + } + } + + + public short getRegisterA() { + return NumberUtils.decodeUnsignedByte(encodedInstruction[1]); + } + + public int getRegisterB() { + return NumberUtils.decodeUnsignedShort(encodedInstruction[2], encodedInstruction[3]); } } diff --git a/src/main/java/org/jf/dexlib/code/Format/Format23x.java b/src/main/java/org/jf/dexlib/code/Format/Instruction23x.java similarity index 53% rename from src/main/java/org/jf/dexlib/code/Format/Format23x.java rename to src/main/java/org/jf/dexlib/code/Format/Instruction23x.java index 0c4bb9c8..0e99c4a9 100644 --- a/src/main/java/org/jf/dexlib/code/Format/Format23x.java +++ b/src/main/java/org/jf/dexlib/code/Format/Instruction23x.java @@ -31,46 +31,60 @@ package org.jf.dexlib.code.Format; import org.jf.dexlib.code.Instruction; import org.jf.dexlib.code.Opcode; import org.jf.dexlib.DexFile; +import org.jf.dexlib.IndexedItem; +import org.jf.dexlib.util.NumberUtils; -public class Format23x extends Format +public class Instruction23x extends Instruction { - public static final Format23x Format = new Format23x(); + public static final Instruction.InstructionFactory Factory = new Factory(); - private Format23x() { - } + public Instruction23x(DexFile dexFile, Opcode opcode, short regA, short regB, short regC) { + super(dexFile, opcode, (IndexedItem)null); - public Instruction make(DexFile dexFile, byte opcode, short regA, short regB, short regC) { - byte[] bytes = new byte[4]; - - Opcode op = Opcode.getOpcodeByValue(opcode); - - checkOpcodeFormat(op); - - if (regA >= 1<<8) { + if (regA >= 1<<8 || + regB >= 1<<8 || + regC >= 1<<8) { throw new RuntimeException("The register number must be less than v256"); } - if (regB >= 1<<8) { - throw new RuntimeException("The register number must be less than v256"); - } - - if (regC >= 1<<8) { - throw new RuntimeException("The register number must be less than v256"); - } - - bytes[0] = opcode; - bytes[1] = (byte)regA; - bytes[2] = (byte)regB; - bytes[3] = (byte)regC; - - return new Instruction(dexFile, bytes, null); + encodedInstruction = new byte[4]; + encodedInstruction[0] = opcode.value; + encodedInstruction[1] = (byte)regA; + encodedInstruction[2] = (byte)regB; + encodedInstruction[3] = (byte)regC; } - public int getByteCount() { - return 4; + private Instruction23x(DexFile dexFile, Opcode opcode, byte[] rest) { + super(dexFile, opcode, rest); } - public String getFormatName() { - return "23x"; + private Instruction23x() { + } + + public Format getFormat() { + return Format.Format23x; + } + + protected Instruction makeClone() { + return new Instruction23x(); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] rest) { + return new Instruction23x(dexFile, opcode, rest); + } + } + + + public short getRegisterA() { + return NumberUtils.decodeUnsignedByte(encodedInstruction[1]); + } + + public short getRegisterB() { + return NumberUtils.decodeUnsignedByte(encodedInstruction[2]); + } + + public short getRegisterC() { + return NumberUtils.decodeUnsignedByte(encodedInstruction[3]); } } diff --git a/src/main/java/org/jf/dexlib/code/Format/Instruction30t.java b/src/main/java/org/jf/dexlib/code/Format/Instruction30t.java new file mode 100644 index 00000000..16d7e0b2 --- /dev/null +++ b/src/main/java/org/jf/dexlib/code/Format/Instruction30t.java @@ -0,0 +1,78 @@ +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib.code.Format; + +import org.jf.dexlib.code.Instruction; +import org.jf.dexlib.code.Opcode; +import org.jf.dexlib.DexFile; +import org.jf.dexlib.IndexedItem; +import org.jf.dexlib.util.NumberUtils; + +public class Instruction30t extends Instruction +{ + public static final Instruction.InstructionFactory Factory = new Factory(); + + public Instruction30t(DexFile dexFile, Opcode opcode, int offA) { + super(dexFile, opcode, (IndexedItem)null); + + encodedInstruction = new byte[6]; + encodedInstruction[0] = opcode.value; + encodedInstruction[2] = (byte)offA; + encodedInstruction[3] = (byte)(offA >> 8); + encodedInstruction[4] = (byte)(offA >> 16); + encodedInstruction[5] = (byte)(offA >> 24); + } + + private Instruction30t(DexFile dexFile, Opcode opcode, byte[] rest) { + super(dexFile, opcode, rest); + } + + private Instruction30t() { + } + + public Format getFormat() { + return Format.Format30t; + } + + protected Instruction makeClone() { + return new Instruction30t(); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] rest) { + return new Instruction30t(dexFile, opcode, rest); + } + } + + + public int getOffset() { + return NumberUtils.decodeInt(encodedInstruction[2], encodedInstruction[3], encodedInstruction[4], + encodedInstruction[5]); + } +} diff --git a/src/main/java/org/jf/dexlib/code/Format/Format22b.java b/src/main/java/org/jf/dexlib/code/Format/Instruction31c.java similarity index 59% rename from src/main/java/org/jf/dexlib/code/Format/Format22b.java rename to src/main/java/org/jf/dexlib/code/Format/Instruction31c.java index 79876366..418e6ac3 100644 --- a/src/main/java/org/jf/dexlib/code/Format/Format22b.java +++ b/src/main/java/org/jf/dexlib/code/Format/Instruction31c.java @@ -31,42 +31,49 @@ package org.jf.dexlib.code.Format; import org.jf.dexlib.code.Instruction; import org.jf.dexlib.code.Opcode; import org.jf.dexlib.DexFile; +import org.jf.dexlib.IndexedItem; +import org.jf.dexlib.util.NumberUtils; -public class Format22b extends Format +public class Instruction31c extends Instruction { - public static final Format22b Format = new Format22b(); + public static final Instruction.InstructionFactory Factory = new Factory(); - private Format22b() { - } - - public Instruction make(DexFile dexFile, byte opcode, short regA, short regB, byte litC) { - byte[] bytes = new byte[4]; - - Opcode op = Opcode.getOpcodeByValue(opcode); - - checkOpcodeFormat(op); + public Instruction31c(DexFile dexFile, Opcode opcode, short regA, IndexedItem item) { + super(dexFile, opcode, item); if (regA >= 1<<8) { throw new RuntimeException("The register number must be less than v256"); } - if (regB >= 1<<8) { - throw new RuntimeException("The register number must be less than v256"); + encodedInstruction = new byte[6]; + encodedInstruction[0] = opcode.value; + encodedInstruction[1] = (byte)regA; + //the item index will be set later, during placement/writing + } + + private Instruction31c(DexFile dexFile, Opcode opcode, byte[] rest) { + super(dexFile, opcode, rest); + } + + private Instruction31c() { + } + + public Format getFormat() { + return Format.Format31c; + } + + protected Instruction makeClone() { + return new Instruction31c(); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] rest) { + return new Instruction31c(dexFile, opcode, rest); } - - bytes[0] = opcode; - bytes[1] = (byte)regA; - bytes[2] = (byte)regB; - bytes[3] = litC; - - return new Instruction(dexFile, bytes, null); } - public int getByteCount() { - return 4; - } - public String getFormatName() { - return "22b"; + public short getRegister() { + return NumberUtils.decodeUnsignedByte(encodedInstruction[1]); } } diff --git a/src/main/java/org/jf/dexlib/code/Format/Format31i.java b/src/main/java/org/jf/dexlib/code/Format/Instruction31i.java similarity index 53% rename from src/main/java/org/jf/dexlib/code/Format/Format31i.java rename to src/main/java/org/jf/dexlib/code/Format/Instruction31i.java index c5ccaa1e..3668c4a0 100644 --- a/src/main/java/org/jf/dexlib/code/Format/Format31i.java +++ b/src/main/java/org/jf/dexlib/code/Format/Instruction31i.java @@ -31,42 +31,57 @@ package org.jf.dexlib.code.Format; import org.jf.dexlib.code.Instruction; import org.jf.dexlib.code.Opcode; import org.jf.dexlib.DexFile; +import org.jf.dexlib.IndexedItem; +import org.jf.dexlib.util.NumberUtils; -public class Format31i extends Format +public class Instruction31i extends Instruction { - public static final Format31i Format = new Format31i(); + public static final Instruction.InstructionFactory Factory = new Factory(); - private Format31i() { - } - - public Instruction make(DexFile dexFile, byte opcode, short regA, int litB) { - byte[] bytes = new byte[6]; - - Opcode op = Opcode.getOpcodeByValue(opcode); - - checkOpcodeFormat(op); + public Instruction31i(DexFile dexFile, Opcode opcode, short regA, int litB) { + super(dexFile, opcode, (IndexedItem)null); if (regA >= 1<<8) { throw new RuntimeException("The register number must be less than v256"); } - bytes[0] = opcode; - bytes[1] = (byte)regA; - - bytes[2] = (byte)litB; - bytes[3] = (byte)(litB >> 8); - - bytes[4] = (byte)(litB >> 16); - bytes[5] = (byte)(litB >> 24); - - return new Instruction(dexFile, bytes, null); + encodedInstruction = new byte[6]; + encodedInstruction[0] = opcode.value; + encodedInstruction[1] = (byte)regA; + encodedInstruction[2] = (byte)litB; + encodedInstruction[3] = (byte)(litB >> 8); + encodedInstruction[4] = (byte)(litB >> 16); + encodedInstruction[5] = (byte)(litB >> 24); } - public int getByteCount() { - return 6; + private Instruction31i(DexFile dexFile, Opcode opcode, byte[] rest) { + super(dexFile, opcode, rest); } - public String getFormatName() { - return "31i"; + private Instruction31i() { + } + + public Format getFormat() { + return Format.Format31i; + } + + protected Instruction makeClone() { + return new Instruction31i(); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] rest) { + return new Instruction31i(dexFile, opcode, rest); + } + } + + + public short getRegister() { + return NumberUtils.decodeUnsignedByte(encodedInstruction[1]); + } + + public int getLiteral() { + return NumberUtils.decodeInt(encodedInstruction[2], encodedInstruction[3], encodedInstruction[4], + encodedInstruction[5]); } } diff --git a/src/main/java/org/jf/dexlib/code/Format/Format11x.java b/src/main/java/org/jf/dexlib/code/Format/Instruction31t.java similarity index 54% rename from src/main/java/org/jf/dexlib/code/Format/Format11x.java rename to src/main/java/org/jf/dexlib/code/Format/Instruction31t.java index 04f9f6c9..155b292c 100644 --- a/src/main/java/org/jf/dexlib/code/Format/Format11x.java +++ b/src/main/java/org/jf/dexlib/code/Format/Instruction31t.java @@ -31,33 +31,57 @@ package org.jf.dexlib.code.Format; import org.jf.dexlib.code.Instruction; import org.jf.dexlib.code.Opcode; import org.jf.dexlib.DexFile; +import org.jf.dexlib.IndexedItem; +import org.jf.dexlib.util.NumberUtils; -public class Format11x extends Format +public class Instruction31t extends Instruction { - public static final Format11x Format = new Format11x(); + public static final Instruction.InstructionFactory Factory = new Factory(); - private Format11x() { - } - - public Instruction make(DexFile dexFile, byte opcode, short regA) { - Opcode op = Opcode.getOpcodeByValue(opcode); - - checkOpcodeFormat(op); + public Instruction31t(DexFile dexFile, Opcode opcode, short regA, int offB) { + super(dexFile, opcode, (IndexedItem)null); if (regA >= 1<<8) { throw new RuntimeException("The register number must be less than v256"); } - return new Instruction(dexFile, new byte[]{opcode,(byte)regA}, null); + encodedInstruction = new byte[6]; + encodedInstruction[0] = opcode.value; + encodedInstruction[1] = (byte)regA; + encodedInstruction[2] = (byte)offB; + encodedInstruction[3] = (byte)(offB >> 8); + encodedInstruction[4] = (byte)(offB >> 16); + encodedInstruction[5] = (byte)(offB >> 24); } - public int getByteCount() - { - return 2; + private Instruction31t(DexFile dexFile, Opcode opcode, byte[] rest) { + super(dexFile, opcode, rest); } - public String getFormatName() - { - return "11x"; + private Instruction31t() { + } + + public Format getFormat() { + return Format.Format31t; + } + + protected Instruction makeClone() { + return new Instruction31t(); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] rest) { + return new Instruction31t(dexFile, opcode, rest); + } + } + + + public short getRegister() { + return NumberUtils.decodeUnsignedByte(encodedInstruction[1]); + } + + public int getOffset() { + return NumberUtils.decodeInt(encodedInstruction[2], encodedInstruction[3], encodedInstruction[4], + encodedInstruction[5]); } } diff --git a/src/main/java/org/jf/dexlib/code/Format/Format32x.java b/src/main/java/org/jf/dexlib/code/Format/Instruction32x.java similarity index 53% rename from src/main/java/org/jf/dexlib/code/Format/Format32x.java rename to src/main/java/org/jf/dexlib/code/Format/Instruction32x.java index 86ffbc33..a6038491 100644 --- a/src/main/java/org/jf/dexlib/code/Format/Format32x.java +++ b/src/main/java/org/jf/dexlib/code/Format/Instruction32x.java @@ -31,45 +31,56 @@ package org.jf.dexlib.code.Format; import org.jf.dexlib.code.Instruction; import org.jf.dexlib.code.Opcode; import org.jf.dexlib.DexFile; +import org.jf.dexlib.IndexedItem; +import org.jf.dexlib.util.NumberUtils; -public class Format32x extends Format +public class Instruction32x extends Instruction { - public static final Format32x Format = new Format32x(); + public static final Instruction.InstructionFactory Factory = new Factory(); - private Format32x() { - } + public Instruction32x(DexFile dexFile, Opcode opcode, int regA, int regB) { + super(dexFile, opcode, (IndexedItem)null); - public Instruction make(DexFile dexFile, byte opcode, int regA, int regB) { - byte[] bytes = new byte[6]; - - Opcode op = Opcode.getOpcodeByValue(opcode); - - checkOpcodeFormat(op); - - if (regA >= 1<<16) { + if (regA >= 1<<16 || + regB >= 1<<16) { throw new RuntimeException("The register number must be less than v65536"); } - if (regB >= 1<<16) { - throw new RuntimeException("The register number must be less than v65536"); + encodedInstruction = new byte[6]; + encodedInstruction[0] = opcode.value; + encodedInstruction[2] = (byte)regA; + encodedInstruction[3] = (byte)(regA >> 8); + encodedInstruction[4] = (byte)regB; + encodedInstruction[5] = (byte)(regB >> 8); + } + + private Instruction32x(DexFile dexFile, Opcode opcode, byte[] rest) { + super(dexFile, opcode, rest); + } + + private Instruction32x() { + } + + public Format getFormat() { + return Format.Format32x; + } + + protected Instruction makeClone() { + return new Instruction32x(); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] rest) { + return new Instruction32x(dexFile, opcode, rest); } - - bytes[0] = opcode; - - bytes[2] = (byte)regA; - bytes[3] = (byte)(regA >> 8); - - bytes[4] = (byte)regB; - bytes[5] = (byte)(regB >> 8); - - return new Instruction(dexFile, bytes, null); } - public int getByteCount() { - return 6; + + public int getRegisterA() { + return NumberUtils.decodeUnsignedShort(encodedInstruction[2], encodedInstruction[3]); } - public String getFormatName() { - return "32x"; + public int getRegisterB() { + return NumberUtils.decodeUnsignedShort(encodedInstruction[4], encodedInstruction[5]); } } diff --git a/src/main/java/org/jf/dexlib/code/Format/Format35c.java b/src/main/java/org/jf/dexlib/code/Format/Instruction35c.java similarity index 52% rename from src/main/java/org/jf/dexlib/code/Format/Format35c.java rename to src/main/java/org/jf/dexlib/code/Format/Instruction35c.java index 4c8946e2..3250121d 100644 --- a/src/main/java/org/jf/dexlib/code/Format/Format35c.java +++ b/src/main/java/org/jf/dexlib/code/Format/Instruction35c.java @@ -29,27 +29,23 @@ package org.jf.dexlib.code.Format; import org.jf.dexlib.*; +import org.jf.dexlib.util.NumberUtils; import org.jf.dexlib.code.Instruction; import org.jf.dexlib.code.Opcode; import static org.jf.dexlib.code.Opcode.*; -public class Format35c extends Format +public class Instruction35c extends Instruction { - public static final Format35c Format = new Format35c(); + public static final Instruction.InstructionFactory Factory = new Factory(); - private Format35c() { - } - - public Instruction make(DexFile dexFile, byte opcode, byte regCount, byte regD, byte regE, byte regF, byte regG, byte regA, IndexedItem item) { - byte[] bytes = new byte[6]; - - Opcode op = Opcode.getOpcodeByValue(opcode); - - checkOpcodeFormat(op); + public Instruction35c(DexFile dexFile, Opcode opcode, int regCount, byte regD, byte regE, byte regF, byte regG, + byte regA, IndexedItem item) { + super(dexFile, opcode, item); if (regCount > 5) { throw new RuntimeException("regCount cannot be greater than 5"); } + if (regD >= 1<<4 || regE >= 1<<4 || regF >= 1<<4 || @@ -58,16 +54,73 @@ public class Format35c extends Format throw new RuntimeException("All register args must fit in 4 bits"); } - bytes[0] = opcode; - bytes[1] = (byte)((regCount << 4) | regA); - bytes[4] = (byte)((regE << 4) | regD); - bytes[5] = (byte)((regG << 4) | regF); + encodedInstruction = new byte[6]; + encodedInstruction[0] = opcode.value; + encodedInstruction[1] = (byte)((regCount << 4) | regA); + //the item index will be set later, during placement/writing + encodedInstruction[4] = (byte)((regE << 4) | regD); + encodedInstruction[5] = (byte)((regG << 4) | regF); - //go ahead and make the instruction, to verify that item is the correct type. If it isn't, - //the construction will throw an exception - Instruction instruction = new Instruction(dexFile, bytes, item); + checkItem(); + } - if (opcode == FILLED_NEW_ARRAY.value) { + private Instruction35c(DexFile dexFile, Opcode opcode, byte[] rest) { + super(dexFile, opcode, rest); + + if (getRegCount() > 5) { + throw new RuntimeException("regCount cannot be greater than 5"); + } + + checkItem(); + } + + private Instruction35c() { + } + + public Format getFormat() { + return Format.Format35c; + } + + protected Instruction makeClone() { + return new Instruction35c(); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] rest) { + return new Instruction35c(dexFile, opcode, rest); + } + } + + + public byte getRegisterA() { + return NumberUtils.decodeLowUnsignedNibble(encodedInstruction[1]); + } + + public byte getRegCount() { + return NumberUtils.decodeHighUnsignedNibble(encodedInstruction[1]); + } + + public byte getRegisterD() { + return NumberUtils.decodeLowUnsignedNibble(encodedInstruction[4]); + } + + public byte getRegisterE() { + return NumberUtils.decodeHighUnsignedNibble(encodedInstruction[4]); + } + + public byte getRegisterF() { + return NumberUtils.decodeLowUnsignedNibble(encodedInstruction[5]); + } + + public byte getRegisterG() { + return NumberUtils.decodeLowUnsignedNibble(encodedInstruction[5]); + } + + private void checkItem() { + Opcode opcode = getOpcode(); + IndexedItem item = getReferencedItem(); + + if (opcode == FILLED_NEW_ARRAY) { //check data for filled-new-array opcode String type = ((TypeIdItem)item).getTypeDescriptor(); if (type.charAt(0) != '[') { @@ -76,39 +129,13 @@ public class Format35c extends Format if (type.charAt(1) == 'J' || type.charAt(1) == 'D') { throw new RuntimeException("The type cannot be an array of longs or doubles"); } - } else if (opcode >= INVOKE_VIRTUAL.value && opcode <= INVOKE_INTERFACE.value) { + } else if (opcode.value >= INVOKE_VIRTUAL.value && opcode.value <= INVOKE_INTERFACE.value) { //check data for invoke-* opcodes MethodIdItem methodIdItem = (MethodIdItem)item; - if (methodIdItem.getParameterRegisterCount(opcode == INVOKE_STATIC.value) != regCount) { + if (methodIdItem.getParameterRegisterCount(opcode == INVOKE_STATIC) != getRegCount()) { throw new RuntimeException("regCount does not match the number of arguments of the method"); } - } else { - throw new RuntimeException("Opcode " + Integer.toHexString(opcode) + " does not use the 35c format"); } - - return instruction; } - public int getByteCount() { - return 6; - } - - public String getFormatName() { - return "35c"; - } - - /*@Test - public void testInvoke() { - DexFile dexFile = new DexFile(); - ArrayList types = new ArrayList(); - types.add(new TypeIdItem(dexFile, "I")); - types.add(new TypeIdItem(dexFile, "I")); - types.add(new TypeIdItem(dexFile, "I")); - types.add(new TypeIdItem(dexFile, "I")); - types.add(new TypeIdItem(dexFile, "I")); - MethodIdItem method = new MethodIdItem(dexFile, new TypeIdItem(dexFile, "test"), "test", new ProtoIdItem(dexFile, new TypeIdItem(dexFile, "V"), types)); - - Instruction ins = make(dexFile, (byte)INVOKE_VIRTUAL.value, (byte)5, (byte)0, (byte)1, (byte)2, (byte)3, (byte)4, method); - assertTrue("Is everything put in the right place?", java.util.Arrays.equals(ins.getBytes(), new byte[] {0x6e, 0x54, 0x00, 0x00, 0x10, 0x32})); - }*/ } diff --git a/src/main/java/org/jf/dexlib/code/Format/Format3rc.java b/src/main/java/org/jf/dexlib/code/Format/Instruction3rc.java similarity index 58% rename from src/main/java/org/jf/dexlib/code/Format/Format3rc.java rename to src/main/java/org/jf/dexlib/code/Format/Instruction3rc.java index 41f72b7a..47c98d7e 100644 --- a/src/main/java/org/jf/dexlib/code/Format/Format3rc.java +++ b/src/main/java/org/jf/dexlib/code/Format/Instruction3rc.java @@ -29,23 +29,17 @@ package org.jf.dexlib.code.Format; import org.jf.dexlib.*; +import org.jf.dexlib.util.NumberUtils; import org.jf.dexlib.code.Instruction; import org.jf.dexlib.code.Opcode; import static org.jf.dexlib.code.Opcode.*; -public class Format3rc extends Format +public class Instruction3rc extends Instruction { - public static final Format3rc Format = new Format3rc(); + public static final Instruction.InstructionFactory Factory = new Factory(); - public Format3rc() { - } - - public Instruction make(DexFile dexFile, byte opcode, short regCount, int startReg, IndexedItem item) { - byte[] bytes = new byte[6]; - - Opcode op = Opcode.getOpcodeByValue(opcode); - - checkOpcodeFormat(op); + public Instruction3rc(DexFile dexFile, Opcode opcode, short regCount, int startReg, IndexedItem item) { + super(dexFile, opcode, item); if (regCount >= 1<<8) { throw new RuntimeException("regCount must be less than 256"); @@ -61,16 +55,53 @@ public class Format3rc extends Format throw new RuntimeException("The beginning register of the range cannot be negative"); } - bytes[0] = opcode; - bytes[1] = (byte)regCount; - bytes[4] = (byte)startReg; - bytes[5] = (byte)(startReg >> 8); + encodedInstruction = new byte[6]; + encodedInstruction[0] = opcode.value; + encodedInstruction[1] = (byte)regCount; + //the item index will be set later, during placement/writing + encodedInstruction[4] = (byte)startReg; + encodedInstruction[5] = (byte)(startReg >> 8); - //go ahead and make the instruction now, which will verify that item is the correct type. If it isn't, - //the construction will throw an exception - Instruction instruction = new Instruction(dexFile, bytes, item); + checkItem(); + } - if (opcode == FILLED_NEW_ARRAY_RANGE.value) { + private Instruction3rc(DexFile dexFile, Opcode opcode, byte[] rest) { + super(dexFile, opcode, rest); + + checkItem(); + } + + private Instruction3rc() { + } + + public Format getFormat() { + return Format.Format3rc; + } + + protected Instruction makeClone() { + return new Instruction3rc(); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] rest) { + return new Instruction3rc(dexFile, opcode, rest); + } + } + + + public short getRegCount() { + return NumberUtils.decodeUnsignedByte(encodedInstruction[1]); + } + + public int getStartRegister() { + return NumberUtils.decodeUnsignedShort(encodedInstruction[4], encodedInstruction[5]); + } + + private void checkItem() { + Opcode opcode = getOpcode(); + IndexedItem item = getReferencedItem(); + + if (opcode == FILLED_NEW_ARRAY_RANGE) { //check data for filled-new-array/range opcode String type = ((TypeIdItem)item).getTypeDescriptor(); if (type.charAt(0) != '[') { @@ -79,40 +110,12 @@ public class Format3rc extends Format if (type.charAt(1) == 'J' || type.charAt(1) == 'D') { throw new RuntimeException("The type cannot be an array of longs or doubles"); } - } else if (opcode >= INVOKE_VIRTUAL_RANGE.value && opcode <= INVOKE_INTERFACE_RANGE.value) { + } else if (opcode.value >= INVOKE_VIRTUAL_RANGE.value && opcode.value <= INVOKE_INTERFACE_RANGE.value) { //check data for invoke-*/range opcodes MethodIdItem methodIdItem = (MethodIdItem)item; - if (methodIdItem.getParameterRegisterCount(opcode == INVOKE_STATIC_RANGE.value) != regCount) { + if (methodIdItem.getParameterRegisterCount(opcode == INVOKE_STATIC_RANGE) != getRegCount()) { throw new RuntimeException("regCount does not match the number of arguments of the method"); } - } else { - throw new RuntimeException("Opcode " + Integer.toHexString(opcode) + " does not use the 35c format"); } - - return instruction; } - - public int getByteCount() { - return 6; - } - - public String getFormatName() { - return "3rc"; - } - - /*@Test - public void testInvoke() { - DexFile dexFile = DexFile.makeBlankDexFile(); - ArrayList types = new ArrayList(); - types.add(new TypeIdItem(dexFile, "I")); - types.add(new TypeIdItem(dexFile, "I")); - types.add(new TypeIdItem(dexFile, "I")); - types.add(new TypeIdItem(dexFile, "I")); - types.add(new TypeIdItem(dexFile, "I")); - MethodIdItem method = new MethodIdItem(dexFile, new TypeIdItem(dexFile, "test"), "test", new ProtoIdItem(dexFile, new TypeIdItem(dexFile, "V"), types)); - - Instruction ins = Format.make(dexFile, (byte)INVOKE_VIRTUAL_RANGE.value, (short)6, 65500, method); - byte[] bytes = new byte[] {0x74, 0x06, 0x00, 0x00, (byte)0xDC, (byte)0xFF}; - assertTrue("Is everything put in the right place?", java.util.Arrays.equals(ins.getBytes(), bytes)); - }*/ } diff --git a/src/main/java/org/jf/dexlib/code/Format/Format51l.java b/src/main/java/org/jf/dexlib/code/Format/Instruction51l.java similarity index 51% rename from src/main/java/org/jf/dexlib/code/Format/Format51l.java rename to src/main/java/org/jf/dexlib/code/Format/Instruction51l.java index 73d3a1ee..a04b9fb2 100644 --- a/src/main/java/org/jf/dexlib/code/Format/Format51l.java +++ b/src/main/java/org/jf/dexlib/code/Format/Instruction51l.java @@ -31,48 +31,60 @@ package org.jf.dexlib.code.Format; import org.jf.dexlib.code.Instruction; import org.jf.dexlib.code.Opcode; import org.jf.dexlib.DexFile; +import org.jf.dexlib.IndexedItem; +import org.jf.dexlib.util.NumberUtils; -public class Format51l extends Format +public class Instruction51l extends Instruction { - public static final Format51l Format = new Format51l(); + public static final Instruction.InstructionFactory Factory = new Factory(); - private Format51l() { - } - - public Instruction make(DexFile dexFile, byte opcode, short regA, long litB) { - byte[] bytes = new byte[10]; - - Opcode op = Opcode.getOpcodeByValue(opcode); - - checkOpcodeFormat(op); + public Instruction51l(DexFile dexFile, Opcode opcode, short regA, long litB) { + super(dexFile, opcode, (IndexedItem)null); if (regA >= 1<<8) { throw new RuntimeException("The register number must be less than v256"); } - bytes[0] = opcode; - bytes[1] = (byte)regA; - - bytes[2] = (byte)litB; - bytes[3] = (byte)(litB >> 8); - - bytes[4] = (byte)(litB >> 16); - bytes[5] = (byte)(litB >> 24); - - bytes[6] = (byte)(litB >> 32); - bytes[7] = (byte)(litB >> 40); - - bytes[8] = (byte)(litB >> 48); - bytes[9] = (byte)(litB >> 56); - - return new Instruction(dexFile, bytes, null); + encodedInstruction = new byte[10]; + encodedInstruction[0] = opcode.value; + encodedInstruction[1] = (byte)regA; + encodedInstruction[2] = (byte)litB; + encodedInstruction[3] = (byte)(litB >> 8); + encodedInstruction[4] = (byte)(litB >> 16); + encodedInstruction[5] = (byte)(litB >> 24); + encodedInstruction[6] = (byte)(litB >> 32); + encodedInstruction[7] = (byte)(litB >> 40); + encodedInstruction[8] = (byte)(litB >> 48); + encodedInstruction[9] = (byte)(litB >> 56); } - public int getByteCount() { - return 10; + private Instruction51l(DexFile dexFile, Opcode opcode, byte[] rest) { + super(dexFile, opcode, rest); } - public String getFormatName() { - return "51l"; + private Instruction51l() { + } + + public Format getFormat() { + return Format.Format51l; + } + + protected Instruction makeClone() { + return new Instruction51l(); + } + + private static class Factory implements Instruction.InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] rest) { + return new Instruction51l(dexFile, opcode, rest); + } + } + + + public short getRegister() { + return NumberUtils.decodeUnsignedByte(encodedInstruction[1]); + } + + public long getLiteral() { + return NumberUtils.decodeLong(encodedInstruction, 2); } } diff --git a/src/main/java/org/jf/dexlib/code/Format/PackedSwitchData.java b/src/main/java/org/jf/dexlib/code/Format/PackedSwitchData.java deleted file mode 100644 index d78a2f34..00000000 --- a/src/main/java/org/jf/dexlib/code/Format/PackedSwitchData.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * [The "BSD licence"] - * Copyright (c) 2009 Ben Gruver - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.jf.dexlib.code.Format; - -import org.jf.dexlib.code.Instruction; -import org.jf.dexlib.DexFile; - -public class PackedSwitchData -{ - public static Instruction make(DexFile dexFile, int firstKey, int[] targets) { - byte[] bytes; - - if (targets.length > 0xFFFF) { - throw new RuntimeException("The packed-switch data contains too many elements. " + - "The maximum number of switch elements is 65535"); - } - - bytes = new byte[targets.length * 4 + 8]; - int position = 8; - - for (int target: targets) { - bytes[position++] = (byte)target; - bytes[position++] = (byte)(target >> 8); - bytes[position++] = (byte)(target >> 16); - bytes[position++] = (byte)(target >> 24); - } - - //packed-switch psuedo-opcode - bytes[0] = 0x00; - bytes[1] = 0x01; - - bytes[2] = (byte)targets.length; - bytes[3] = (byte)(targets.length >> 8); - - bytes[4] = (byte)firstKey; - bytes[5] = (byte)(firstKey >> 8); - bytes[6] = (byte)(firstKey >> 16); - bytes[7] = (byte)(firstKey >> 24); - - return new Instruction(dexFile, bytes, null); - } -} diff --git a/src/main/java/org/jf/dexlib/code/Format/PackedSwitchDataPseudoInstruction.java b/src/main/java/org/jf/dexlib/code/Format/PackedSwitchDataPseudoInstruction.java new file mode 100644 index 00000000..8dfea3b6 --- /dev/null +++ b/src/main/java/org/jf/dexlib/code/Format/PackedSwitchDataPseudoInstruction.java @@ -0,0 +1,105 @@ +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib.code.Format; + +import org.jf.dexlib.code.Instruction; +import org.jf.dexlib.code.Opcode; +import org.jf.dexlib.DexFile; +import org.jf.dexlib.IndexedItem; +import org.jf.dexlib.util.Input; + +public class PackedSwitchDataPseudoInstruction extends Instruction +{ + public PackedSwitchDataPseudoInstruction(DexFile dexFile, int firstKey, int[] targets) { + super(dexFile, Opcode.NOP, (IndexedItem)null); + + if (targets.length > 0xFFFF) { + throw new RuntimeException("The packed-switch data contains too many elements. " + + "The maximum number of switch elements is 65535"); + } + + encodedInstruction = new byte[targets.length * 4 + 8]; + encodedInstruction[0] = 0x00; + encodedInstruction[1] = 0x01; //packed-switch pseudo-opcode + + encodedInstruction[2] = (byte)targets.length; + encodedInstruction[3] = (byte)(targets.length >> 8); + + encodedInstruction[4] = (byte)firstKey; + encodedInstruction[5] = (byte)(firstKey >> 8); + encodedInstruction[6] = (byte)(firstKey >> 16); + encodedInstruction[7] = (byte)(firstKey >> 24); + + int position= 8; + for (int target: targets) { + encodedInstruction[position++] = (byte)target; + encodedInstruction[position++] = (byte)(target >> 8); + encodedInstruction[position++] = (byte)(target >> 16); + encodedInstruction[position++] = (byte)(target >> 24); + } + } + + protected void checkFormat(Format format) { + //no need to check the format + } + + private PackedSwitchDataPseudoInstruction() { + } + + protected Instruction makeClone() { + return new PackedSwitchDataPseudoInstruction(); + } + + + public static PackedSwitchDataPseudoInstruction make(DexFile dexFile, Input input) { + byte opcodeByte = input.readByte(); + if (opcodeByte != 0x00) { + throw new RuntimeException("Invalid opcode byte for a PackedSwitchData pseudo-instruction"); + } + byte subopcodeByte = input.readByte(); + if (subopcodeByte != 0x01) { + throw new RuntimeException("Invalid sub-opcode byte for a PackedSwitchData pseudo-instruction"); + } + + int targetCount = input.readShort(); + + int firstKey = input.readInt(); + int[] targets = new int[targetCount]; + + for (int i=0; i 0xFFFF) { - throw new RuntimeException("The sparse-switch data contains too many elements. " + - "The maximum number of switch elements is 65535"); - } - - bytes = new byte[targets.length * 8 + 4]; - int position = 8; - - if (targets.length > 0) { - int key = keys[0]; - bytes[4] = (byte)key; - bytes[5] = (byte)(key >> 8); - bytes[6] = (byte)(key >> 16); - bytes[7] = (byte)(key >> 24); - - for (int i=1; i> 8); - bytes[position++] = (byte)(key >> 16); - bytes[position++] = (byte)(key >> 24); - } - - for (int target: targets) { - bytes[position++] = (byte)target; - bytes[position++] = (byte)(target >> 8); - bytes[position++] = (byte)(target >> 16); - bytes[position++] = (byte)(target >> 24); - } - } - - //sparse-switch psuedo-opcode - bytes[0] = 0x00; - bytes[1] = 0x02; - - bytes[2] = (byte)targets.length; - bytes[3] = (byte)(targets.length >> 8); - - return new Instruction(dexFile, bytes, null); - } -} diff --git a/src/main/java/org/jf/dexlib/code/Format/SparseSwitchDataPseudoInstruction.java b/src/main/java/org/jf/dexlib/code/Format/SparseSwitchDataPseudoInstruction.java new file mode 100644 index 00000000..0fd6beba --- /dev/null +++ b/src/main/java/org/jf/dexlib/code/Format/SparseSwitchDataPseudoInstruction.java @@ -0,0 +1,133 @@ +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib.code.Format; + +import org.jf.dexlib.code.Instruction; +import org.jf.dexlib.code.Opcode; +import org.jf.dexlib.DexFile; +import org.jf.dexlib.IndexedItem; +import org.jf.dexlib.util.Input; + +public class SparseSwitchDataPseudoInstruction extends Instruction +{ + public SparseSwitchDataPseudoInstruction(DexFile dexFile, int[] keys, int[] targets) { + super(dexFile, Opcode.NOP, (IndexedItem)null); + + if (keys.length != targets.length) { + throw new RuntimeException("The number of keys and offsets don't match"); + } + + if (targets.length == 0) { + throw new RuntimeException("The sparse-switch data must contain at least 1 key/target"); + } + + if (targets.length > 0xFFFF) { + throw new RuntimeException("The sparse-switch data contains too many elements. " + + "The maximum number of switch elements is 65535"); + } + + encodedInstruction = new byte[targets.length * 8 + 4]; + encodedInstruction[0] = 0x00; + encodedInstruction[1] = 0x02; //sparse-switch psuedo-opcode + + encodedInstruction[2] = (byte)targets.length; + encodedInstruction[3] = (byte)(targets.length >> 8); + + int position = 8; + + if (targets.length > 0) { + int key = keys[0]; + encodedInstruction[4] = (byte)key; + encodedInstruction[5] = (byte)(key >> 8); + encodedInstruction[6] = (byte)(key >> 16); + encodedInstruction[7] = (byte)(key >> 24); + + for (int i=1; i> 8); + encodedInstruction[position++] = (byte)(key >> 16); + encodedInstruction[position++] = (byte)(key >> 24); + } + + for (int target: targets) { + encodedInstruction[position++] = (byte)target; + encodedInstruction[position++] = (byte)(target >> 8); + encodedInstruction[position++] = (byte)(target >> 16); + encodedInstruction[position++] = (byte)(target >> 24); + } + } + } + + protected void checkFormat(Format format) { + //no need to check the format + } + + private SparseSwitchDataPseudoInstruction() { + } + + protected Instruction makeClone() { + return new SparseSwitchDataPseudoInstruction(); + } + + public static SparseSwitchDataPseudoInstruction make(DexFile dexFile, Input input) { + byte opcodeByte = input.readByte(); + if (opcodeByte != 0x00) { + throw new RuntimeException("Invalid opcode byte for a SparseSwitchData pseudo-instruction"); + } + byte subopcodeByte = input.readByte(); + if (subopcodeByte != 0x02) { + throw new RuntimeException("Invalid sub-opcode byte for a SparseSwitchData pseudo-instruction"); + } + + int targetCount = input.readShort(); + + int[] keys = new int[targetCount]; + int[] targets = new int[targetCount]; + + for (int i=0; i { +import java.util.Collections; +import java.lang.reflect.Array; + +public abstract class Instruction { private DexFile dexFile; - private byte[] bytes; private Opcode opcode; + private IndexedItem referencedItem; + protected byte[] encodedInstruction; - private IndexedItem reference; - - public byte[] getBytes() { - return bytes; + public int getSize() { + return encodedInstruction.length; } public Opcode getOpcode() { return opcode; } - public IndexedItem getReference() { - return reference; + public IndexedItem getReferencedItem() { + return referencedItem; } - public Instruction(DexFile dexFile) { - this.dexFile = dexFile; + protected void setReferencedItem(IndexedItem referencedItem) { + checkReferenceType(referencedItem, this.opcode); + this.referencedItem = referencedItem; } - public Instruction(DexFile dexFile, byte[] bytes, IndexedItem item) { + protected Instruction(DexFile dexFile, Opcode opcode, IndexedItem referencedItem) { this.dexFile = dexFile; - this.bytes = bytes; - this.reference = item; - this.opcode = Opcode.getOpcodeByValue(bytes[0]); - if (!this.opcode.referenceType.checkItem(item)) { - throw new RuntimeException("item is not the correct type for this opcode (got " + item.getClass().toString() + ", expecting " + opcode.referenceType.toString() + ")"); + this.opcode = opcode; + this.referencedItem = referencedItem; + + checkFormat(opcode.format); + checkReferenceType(referencedItem, this.opcode); + } + + protected void checkFormat(Format format) { + if (format != getFormat()) { + throw new RuntimeException(opcode.name + " does not use " + getFormat().toString()); } } - public void readFrom(Input in) { - int startPos = in.getCursor(); - - byte opByte = in.readByte(); + protected Instruction(DexFile dexFile, Opcode opcode, byte[] rest) { + this.dexFile = dexFile; + this.opcode = opcode; - if (opByte == 0x00) { - reference = null; - byte secondByte = in.readByte(); - - int count; - - - switch (secondByte) { - case 0x00: - /** nop */ - bytes = new byte[] { 0x00, 0x00 }; - return; - case 0x01: - /** packed switch */ - count = in.readShort(); - in.setCursor(startPos); - bytes = in.readBytes((count * 4) + 8); - return; - case 0x02: - /** sparse switch */ - count = in.readShort(); - in.setCursor(startPos); - bytes = in.readBytes((count * 8) + 4); - return; - case 0x03: - /** fill array data */ - int elementWidth = in.readShort(); - count = in.readInt(); - in.setCursor(startPos); - bytes = in.readBytes(((elementWidth * count + 1)/2 + 4) * 2); - return; - default: - throw new RuntimeException("Invalid 2nd byte for opcode 0x00"); - } + if ((rest.length + 1) != opcode.format.size) { + throw new RuntimeException("Invalid instruction size. This opcode is " + + Integer.toString(rest.length + 1) + " bytes, but the opcode should be " + + Integer.toString(opcode.format.size) + " bytes."); } - this.opcode = Opcode.getOpcodeByValue(opByte); + this.encodedInstruction = new byte[rest.length + 1]; + encodedInstruction[0] = opcode.value; + System.arraycopy(rest, 0, encodedInstruction, 1, rest.length); if (opcode.referenceType != ReferenceType.none) { - in.skipBytes(1); - int referenceIndex = in.readShort(); - - //handle const-string/jumbo as a special case - if (opByte == 0x1b) { - int hiWord = in.readShort(); - if (hiWord != 0) { - referenceIndex += (hiWord<<16); - } - } - - switch (opcode.referenceType) { - case string: - reference = dexFile.StringIdsSection.getByIndex(referenceIndex); - break; - case type: - reference = dexFile.TypeIdsSection.getByIndex(referenceIndex); - break; - case field: - reference = dexFile.FieldIdsSection.getByIndex(referenceIndex); - break; - case method: - reference = dexFile.MethodIdsSection.getByIndex(referenceIndex); - break; - } - } else { - reference = null; - } - - in.setCursor(startPos); - bytes = in.readBytes(opcode.numBytes); - } - - public void writeTo(AnnotatedOutput out) { - out.annotate(bytes.length, "instruction"); - if (needsAlign()) { - //the "special instructions" must be 4 byte aligned - out.alignTo(4); - out.write(bytes); - } else if (reference == null) { - out.write(bytes); - } else { - out.write(bytes,0,2); - //handle const-string/jumbo as a special case - if (bytes[0] == 0x1b) { - out.writeInt(reference.getIndex()); - } else { - int index = reference.getIndex(); - if (index > 0xFFFF) { - throw new RuntimeException("String index doesn't fit."); - } - out.writeShort(reference.getIndex()); - out.write(bytes, 4, bytes.length - 4); - } + int itemIndex = (encodedInstruction[3] << 8) | encodedInstruction[2]; + getReferencedItem(dexFile, opcode, itemIndex); } } - public void copyTo(DexFile dexFile, Instruction copy) { - copy.bytes = bytes; - copy.opcode = opcode; + protected Instruction() { + //this should only be used to make a blank clone within cloneTo() + } + private void checkReferenceType(IndexedItem referencedItem, Opcode opcode) { + switch (opcode.referenceType) { + case field: + if (!(referencedItem instanceof FieldIdItem)) { + throw new RuntimeException(referencedItem.getClass().getSimpleName() + + " is the wrong item type for opcode " + opcode.name + ". Expecting FieldIdItem."); + } + return; + case method: + if (!(referencedItem instanceof MethodIdItem)) { + throw new RuntimeException(referencedItem.getClass().getSimpleName() + + " is the wrong item type for opcode " + opcode.name + ". Expecting MethodIdItem."); + } + return; + case type: + if (!(referencedItem instanceof TypeIdItem)) { + throw new RuntimeException(referencedItem.getClass().getSimpleName() + + " is the wrong item type for opcode " + opcode.name + ". Expecting TypeIdItem."); + } + return; + case string: + if (!(referencedItem instanceof StringIdItem)) { + throw new RuntimeException(referencedItem.getClass().getSimpleName() + + " is the wrong item type for opcode " + opcode.name + ". Expecting StringIdItem."); + } + return; + default: + if (referencedItem != null) { + throw new RuntimeException(referencedItem.getClass().getSimpleName() + + " is invalid for opcode " + opcode.name + ". This opcode does not reference an item"); + } + return; + } + } + + private void getReferencedItem(DexFile dexFile, Opcode opcode, int itemIndex) { + switch (opcode.referenceType) { + case field: + referencedItem = dexFile.FieldIdsSection.getByIndex(itemIndex); + return; + case method: + referencedItem = dexFile.MethodIdsSection.getByIndex(itemIndex); + return; + case type: + referencedItem = dexFile.TypeIdsSection.getByIndex(itemIndex); + return; + case string: + referencedItem = dexFile.StringIdsSection.getByIndex(itemIndex); + return; + } + return; + } + + public abstract Format getFormat(); + + public static interface InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] rest); + } + + public Instruction cloneTo(DexFile dexFile) { + Instruction clone = makeClone(); + clone.encodedInstruction = encodedInstruction.clone(); + clone.dexFile = dexFile; + clone.opcode = opcode; + if (referencedItem != null) { switch (opcode.referenceType) { case string: - copy.reference = dexFile.StringIdsSection.intern(dexFile, (StringIdItem)reference); + clone.referencedItem = dexFile.StringIdsSection.intern(dexFile, (StringIdItem)referencedItem); break; case type: - copy.reference = dexFile.TypeIdsSection.intern(dexFile, (TypeIdItem)reference); + clone.referencedItem = dexFile.TypeIdsSection.intern(dexFile, (TypeIdItem)referencedItem); break; case field: - copy.reference = dexFile.FieldIdsSection.intern(dexFile, (FieldIdItem)reference); + clone.referencedItem = dexFile.FieldIdsSection.intern(dexFile, (FieldIdItem)referencedItem); break; case method: - copy.reference = dexFile.MethodIdsSection.intern(dexFile, (MethodIdItem)reference); + clone.referencedItem = dexFile.MethodIdsSection.intern(dexFile, (MethodIdItem)referencedItem); break; case none: break; } - } - - public int place(int offset) { - return offset + getSize(offset); - } - - public int getSize(int offset) { - if (this.needsAlign() && (offset % 4) != 0) { - return bytes.length + 2; - } else { - return bytes.length; } + + return clone; } - private boolean needsAlign() { - //true if the opcode is one of the "special format" opcodes - return bytes[0] == 0 && bytes[1] > 0; - } + protected abstract Instruction makeClone(); + +// public void readFrom(Input in) { +// int startPos = in.getCursor(); +// +// byte opByte = in.readByte(); +// +// if (opByte == 0x00) { +// reference = null; +// byte secondByte = in.readByte(); +// +// int count; +// +// +// switch (secondByte) { +// case 0x00: +// /** nop */ +// bytes = new byte[] { 0x00, 0x00 }; +// return; +// case 0x01: +// /** packed switch */ +// count = in.readShort(); +// in.setCursor(startPos); +// bytes = in.readBytes((count * 4) + 8); +// return; +// case 0x02: +// /** sparse switch */ +// count = in.readShort(); +// in.setCursor(startPos); +// bytes = in.readBytes((count * 8) + 4); +// return; +// case 0x03: +// /** fill array data */ +// int elementWidth = in.readShort(); +// count = in.readInt(); +// in.setCursor(startPos); +// bytes = in.readBytes(((elementWidth * count + 1)/2 + 4) * 2); +// return; +// default: +// throw new RuntimeException("Invalid 2nd byte for opcode 0x00"); +// } +// } +// +// this.opcode = Opcode.getOpcodeByValue(opByte); +// +// if (opcode.referenceType != ReferenceType.none) { +// in.skipBytes(1); +// int referenceIndex = in.readShort(); +// +// //handle const-string/jumbo as a special case +// if (opByte == 0x1b) { +// int hiWord = in.readShort(); +// if (hiWord != 0) { +// referenceIndex += (hiWord<<16); +// } +// } +// +// switch (opcode.referenceType) { +// case string: +// reference = dexFile.StringIdsSection.getByIndex(referenceIndex); +// break; +// case type: +// reference = dexFile.TypeIdsSection.getByIndex(referenceIndex); +// break; +// case field: +// reference = dexFile.FieldIdsSection.getByIndex(referenceIndex); +// break; +// case method: +// reference = dexFile.MethodIdsSection.getByIndex(referenceIndex); +// break; +// } +// } else { +// reference = null; +// } +// +// in.setCursor(startPos); +// bytes = in.readBytes(opcode.numBytes); +// } +// +// public void writeTo(AnnotatedOutput out) { +// out.annotate(bytes.length, "instruction"); +// if (needsAlign()) { +// //the "special instructions" must be 4 byte aligned +// out.alignTo(4); +// out.write(bytes); +// } else if (reference == null) { +// out.write(bytes); +// } else { +// out.write(bytes,0,2); +// //handle const-string/jumbo as a special case +// if (bytes[0] == 0x1b) { +// out.writeInt(reference.getIndex()); +// } else { +// int index = reference.getIndex(); +// if (index > 0xFFFF) { +// throw new RuntimeException("String index doesn't fit."); +// } +// out.writeShort(reference.getIndex()); +// out.write(bytes, 4, bytes.length - 4); +// } +// } +// } +// +// public void copyTo(DexFile dexFile, Instruction copy) { +// copy.bytes = bytes; +// copy.opcode = opcode; +// +// switch (opcode.referenceType) { +// case string: +// copy.reference = dexFile.StringIdsSection.intern(dexFile, (StringIdItem)reference); +// break; +// case type: +// copy.reference = dexFile.TypeIdsSection.intern(dexFile, (TypeIdItem)reference); +// break; +// case field: +// copy.reference = dexFile.FieldIdsSection.intern(dexFile, (FieldIdItem)reference); +// break; +// case method: +// copy.reference = dexFile.MethodIdsSection.intern(dexFile, (MethodIdItem)reference); +// break; +// case none: +// break; +// } +// } +// +// public int place(int offset) { +// return offset + getSize(offset); +// } +// +// public int getSize(int offset) { +// if (this.needsAlign() && (offset % 4) != 0) { +// return bytes.length + 2; +// } else { +// return bytes.length; +// } +// } +// +// private boolean needsAlign() { +// //true if the opcode is one of the "special format" opcodes +// return bytes[0] == 0 && bytes[1] > 0; +// } } diff --git a/src/main/java/org/jf/dexlib/code/InstructionField.java b/src/main/java/org/jf/dexlib/code/InstructionField.java new file mode 100644 index 00000000..7ce1c1f3 --- /dev/null +++ b/src/main/java/org/jf/dexlib/code/InstructionField.java @@ -0,0 +1,141 @@ +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib.code; + +import org.jf.dexlib.Field; +import org.jf.dexlib.DexFile; +import org.jf.dexlib.IndexedItem; +import org.jf.dexlib.code.Format.PackedSwitchDataPseudoInstruction; +import org.jf.dexlib.code.Format.SparseSwitchDataPseudoInstruction; +import org.jf.dexlib.code.Format.ArrayDataPseudoInstruction; +import org.jf.dexlib.util.AnnotatedOutput; +import org.jf.dexlib.util.Input; + +public class InstructionField implements Field { + private Instruction instruction; + private DexFile dexFile; + + public InstructionField(DexFile dexFile) { + this.dexFile = dexFile; + } + + public InstructionField(DexFile dexFile, Instruction instruction) { + this.dexFile = dexFile; + this.instruction = instruction; + } + + public void writeTo(AnnotatedOutput out) { + byte[] bytes = instruction.encodedInstruction; + IndexedItem reference = instruction.getReferencedItem(); + + out.annotate(bytes.length, "instruction"); + if (needsAlign()) { + //the "special instructions" must be 4 byte aligned + out.alignTo(4); + out.write(bytes); + } else if (reference == null) { + out.write(bytes); + } else { + out.write(bytes,0,2); + //handle const-string/jumbo as a special case + if (bytes[0] == 0x1b) { + out.writeInt(reference.getIndex()); + } else { + int index = reference.getIndex(); + if (index > 0xFFFF) { + throw new RuntimeException("String index doesn't fit."); + } + out.writeShort(reference.getIndex()); + out.write(bytes, 4, bytes.length - 4); + } + } + } + + public void readFrom(Input in) { + int startPos = in.getCursor(); + + byte opByte = in.readByte(); + + if (opByte == 0x00) { + byte secondByte = in.readByte(); + + switch (secondByte) { + case 0x00: + //nop + instruction = Opcode.NOP.format.Factory.makeInstruction(dexFile, Opcode.NOP, new byte[]{0x00, 0x00}); + return; + case 0x01: + //packed switch + in.setCursor(startPos); + instruction = PackedSwitchDataPseudoInstruction.make(dexFile, in); + return; + case 0x02: + //sparse switch + in.setCursor(startPos); + instruction = SparseSwitchDataPseudoInstruction.make(dexFile, in); + return; + case 0x03: + //array data + in.setCursor(startPos); + instruction = ArrayDataPseudoInstruction.make(dexFile, in); + return; + default: + throw new RuntimeException("Invalid 2nd byte for opcode 0x00"); + } + } + + Opcode opcode = Opcode.getOpcodeByValue(opByte); + instruction = opcode.format.Factory.makeInstruction(dexFile, opcode, in.readBytes(opcode.format.size - 1)); + } + + public int place(int offset) { + return offset + getSize(offset); + } + + public void copyTo(DexFile dexFile, InstructionField copy) { + copy.instruction = instruction.cloneTo(dexFile); + } + + public int getSize(int offset) { + if (this.needsAlign() && (offset % 4) != 0) { + return instruction.encodedInstruction.length + 2; + } else { + return instruction.encodedInstruction.length; + } + } + + private boolean needsAlign() { + //true if the opcode is one of the "special format" opcodes + return instruction.encodedInstruction[0] == 0 && instruction.encodedInstruction[1] > 0; + } + + public Instruction getInstruction() { + return instruction; + } +} diff --git a/src/main/java/org/jf/dexlib/code/Opcode.java b/src/main/java/org/jf/dexlib/code/Opcode.java index b27f90f0..ae908f25 100644 --- a/src/main/java/org/jf/dexlib/code/Opcode.java +++ b/src/main/java/org/jf/dexlib/code/Opcode.java @@ -28,229 +28,231 @@ package org.jf.dexlib.code; +import org.jf.dexlib.code.Format.*; + import java.util.ArrayList; import java.util.HashMap; public enum Opcode { - NOP((byte)0x00, "NOP", (byte)2, ReferenceType.none, "10x"), - MOVE((byte)0x01, "MOVE", (byte)2, ReferenceType.none, "12x"), - MOVE_FROM16((byte)0x02, "MOVE/FROM16", (byte)4, ReferenceType.none, "22x"), - MOVE_16((byte)0x03, "MOVE/16", (byte)6, ReferenceType.none, "32x"), - MOVE_WIDE((byte)0x04, "MOVE-WIDE", (byte)2, ReferenceType.none, "12x"), - MOVE_WIDE_FROM16((byte)0x05, "MOVE-WIDE/FROM16", (byte)4, ReferenceType.none, "22x"), - MOVE_WIDE_16((byte)0x06, "MOVE-WIDE/16", (byte)6, ReferenceType.none, "32x"), - MOVE_OBJECT((byte)0x07, "MOVE-OBJECT", (byte)2, ReferenceType.none, "12x"), - MOVE_OBJECT_FROM16((byte)0x08, "MOVE-OBJECT/FROM16", (byte)4, ReferenceType.none, "22x"), - MOVE_OBJECT_16((byte)0x09, "MOVE-OBJECT/16", (byte)6, ReferenceType.none, "32x"), - MOVE_RESULT((byte)0x0a, "MOVE-RESULT", (byte)2, ReferenceType.none, "11x"), - MOVE_RESULT_WIDE((byte)0x0b, "MOVE-RESULT-WIDE", (byte)2, ReferenceType.none, "11x"), - MOVE_RESULT_OBJECT((byte)0x0c, "MOVE-RESULT-OBJECT", (byte)2, ReferenceType.none, "11x"), - MOVE_EXCEPTION((byte)0x0d, "MOVE-EXCEPTION", (byte)2, ReferenceType.none, "11x"), - RETURN_VOID((byte)0x0e, "RETURN-VOID", (byte)2, ReferenceType.none, "10x"), - RETURN((byte)0x0f, "RETURN", (byte)2, ReferenceType.none, "11x"), - RETURN_WIDE((byte)0x10, "RETURN-WIDE", (byte)2, ReferenceType.none, "11x"), - RETURN_OBJECT((byte)0x11, "RETURN-OBJECT", (byte)2, ReferenceType.none, "11x"), - CONST_4((byte)0x12, "CONST/4", (byte)2, ReferenceType.none, "11n"), - CONST_16((byte)0x13, "CONST/16", (byte)4, ReferenceType.none, "21s"), - CONST((byte)0x14, "CONST", (byte)6, ReferenceType.none, "31i"), - CONST_HIGH16((byte)0x15, "CONST/HIGH16", (byte)4, ReferenceType.none, "21h"), - CONST_WIDE_16((byte)0x16, "CONST-WIDE/16", (byte)4, ReferenceType.none, "21s"), - CONST_WIDE_32((byte)0x17, "CONST-WIDE/32", (byte)6, ReferenceType.none, "31i"), - CONST_WIDE((byte)0x18, "CONST-WIDE", (byte)10, ReferenceType.none, "51l"), - CONST_WIDE_HIGH16((byte)0x19, "CONST-WIDE/HIGH16", (byte)4, ReferenceType.none, "21h"), - CONST_STRING((byte)0x1a, "CONST-STRING", (byte)4, ReferenceType.string, "21c"), - CONST_STRING_JUMBO((byte)0x1b, "CONST-STRING/JUMBO", (byte)6, ReferenceType.string, "31c"), - CONST_CLASS((byte)0x1c, "CONST-CLASS", (byte)4, ReferenceType.type, "21c"), - MONITOR_ENTER((byte)0x1d, "MONITOR-ENTER", (byte)2, ReferenceType.none, "11x"), - MONITOR_EXIT((byte)0x1e, "MONITOR-EXIT", (byte)2, ReferenceType.none, "11x"), - CHECK_CAST((byte)0x1f, "CHECK-CAST", (byte)4, ReferenceType.type, "21c"), - INSTANCE_OF((byte)0x20, "INSTANCE-OF", (byte)4, ReferenceType.type, "22c"), - ARRAY_LENGTH((byte)0x21, "ARRAY-LENGTH", (byte)2, ReferenceType.none, "12x"), - NEW_INSTANCE((byte)0x22, "NEW-INSTANCE", (byte)4, ReferenceType.type, "21c"), - NEW_ARRAY((byte)0x23, "NEW-ARRAY", (byte)4, ReferenceType.type, "22c"), - FILLED_NEW_ARRAY((byte)0x24, "FILLED-NEW-ARRAY", (byte)6, ReferenceType.type, "35c"), - FILLED_NEW_ARRAY_RANGE((byte)0x25, "FILLED-NEW-ARRAY/RANGE", (byte)6, ReferenceType.type, "3rc"), - FILL_ARRAY_DATA((byte)0x26, "FILL-ARRAY-DATA", (byte)6, ReferenceType.none, "31t"), - THROW((byte)0x27, "THROW", (byte)2, ReferenceType.none, "11x"), - GOTO((byte)0x28, "GOTO", (byte)2, ReferenceType.none, "10t"), - GOTO_16((byte)0x29, "GOTO/16", (byte)4, ReferenceType.none, "20t"), - GOTO_32((byte)0x2a, "GOTO/32", (byte)6, ReferenceType.none, "30t"), - PACKED_SWITCH((byte)0x2b, "PACKED-SWITCH", (byte)6, ReferenceType.none, "31t"), - SPARSE_SWITCH((byte)0x2c, "SPARSE-SWITCH", (byte)6, ReferenceType.none, "31t"), - CMPL_FLOAT((byte)0x2d, "CMPL-FLOAT", (byte)4, ReferenceType.none, "23x"), - CMPG_FLOAT((byte)0x2e, "CMPG-FLOAT", (byte)4, ReferenceType.none, "23x"), - CMPL_DOUBLE((byte)0x2f, "CMPL-DOUBLE", (byte)4, ReferenceType.none, "23x"), - CMPG_DOUBLE((byte)0x30, "CMPG-DOUBLE", (byte)4, ReferenceType.none, "23x"), - CMP_LONG((byte)0x31, "CMP-LONG", (byte)4, ReferenceType.none, "23x"), - IF_EQ((byte)0x32, "IF-EQ", (byte)4, ReferenceType.none, "22t"), - IF_NE((byte)0x33, "IF-NE", (byte)4, ReferenceType.none, "22t"), - IF_LT((byte)0x34, "IF-LT", (byte)4, ReferenceType.none, "22t"), - IF_GE((byte)0x35, "IF-GE", (byte)4, ReferenceType.none, "22t"), - IF_GT((byte)0x36, "IF-GT", (byte)4, ReferenceType.none, "22t"), - IF_LE((byte)0x37, "IF-LE", (byte)4, ReferenceType.none, "22t"), - IF_EQZ((byte)0x38, "IF-EQZ", (byte)4, ReferenceType.none, "21t"), - IF_NEZ((byte)0x39, "IF-NEZ", (byte)4, ReferenceType.none, "21t"), - IF_LTZ((byte)0x3a, "IF-LTZ", (byte)4, ReferenceType.none, "21t"), - IF_GEZ((byte)0x3b, "IF-GEZ", (byte)4, ReferenceType.none, "21t"), - IF_GTZ((byte)0x3c, "IF-GTZ", (byte)4, ReferenceType.none, "21t"), - IF_LEZ((byte)0x3d, "IF-LEZ", (byte)4, ReferenceType.none, "21t"), - AGET((byte)0x44, "AGET", (byte)4, ReferenceType.none, "23x"), - AGET_WIDE((byte)0x45, "AGET-WIDE", (byte)4, ReferenceType.none, "23x"), - AGET_OBJECT((byte)0x46, "AGET-OBJECT", (byte)4, ReferenceType.none, "23x"), - AGET_BOOLEAN((byte)0x47, "AGET-BOOLEAN", (byte)4, ReferenceType.none, "23x"), - AGET_BYTE((byte)0x48, "AGET-BYTE", (byte)4, ReferenceType.none, "23x"), - AGET_CHAR((byte)0x49, "AGET-CHAR", (byte)4, ReferenceType.none, "23x"), - AGET_SHORT((byte)0x4a, "AGET-SHORT", (byte)4, ReferenceType.none, "23x"), - APUT((byte)0x4b, "APUT", (byte)4, ReferenceType.none, "23x"), - APUT_WIDE((byte)0x4c, "APUT-WIDE", (byte)4, ReferenceType.none, "23x"), - APUT_OBJECT((byte)0x4d, "APUT-OBJECT", (byte)4, ReferenceType.none, "23x"), - APUT_BOOLEAN((byte)0x4e, "APUT-BOOLEAN", (byte)4, ReferenceType.none, "23x"), - APUT_BYTE((byte)0x4f, "APUT-BYTE", (byte)4, ReferenceType.none, "23x"), - APUT_CHAR((byte)0x50, "APUT-CHAR", (byte)4, ReferenceType.none, "23x"), - APUT_SHORT((byte)0x51, "APUT-SHORT", (byte)4, ReferenceType.none, "23x"), - IGET((byte)0x52, "IGET", (byte)4, ReferenceType.field, "22c"), - IGET_WIDE((byte)0x53, "IGET-WIDE", (byte)4, ReferenceType.field, "22c"), - IGET_OBJECT((byte)0x54, "IGET-OBJECT", (byte)4, ReferenceType.field, "22c"), - IGET_BOOLEAN((byte)0x55, "IGET-BOOLEAN", (byte)4, ReferenceType.field, "22c"), - IGET_BYTE((byte)0x56, "IGET-BYTE", (byte)4, ReferenceType.field, "22c"), - IGET_CHAR((byte)0x57, "IGET-CHAR", (byte)4, ReferenceType.field, "22c"), - IGET_SHORT((byte)0x58, "IGET-SHORT", (byte)4, ReferenceType.field, "22c"), - IPUT((byte)0x59, "IPUT", (byte)4, ReferenceType.field, "22c"), - IPUT_WIDE((byte)0x5a, "IPUT-WIDE", (byte)4, ReferenceType.field, "22c"), - IPUT_OBJECT((byte)0x5b, "IPUT-OBJECT", (byte)4, ReferenceType.field, "22c"), - IPUT_BOOLEAN((byte)0x5c, "IPUT-BOOLEAN", (byte)4, ReferenceType.field, "22c"), - IPUT_BYTE((byte)0x5d, "IPUT-BYTE", (byte)4, ReferenceType.field, "22c"), - IPUT_CHAR((byte)0x5e, "IPUT-CHAR", (byte)4, ReferenceType.field, "22c"), - IPUT_SHORT((byte)0x5f, "IPUT-SHORT", (byte)4, ReferenceType.field, "22c"), - SGET((byte)0x60, "SGET", (byte)4, ReferenceType.field, "21c"), - SGET_WIDE((byte)0x61, "SGET-WIDE", (byte)4, ReferenceType.field, "21c"), - SGET_OBJECT((byte)0x62, "SGET-OBJECT", (byte)4, ReferenceType.field, "21c"), - SGET_BOOLEAN((byte)0x63, "SGET-BOOLEAN", (byte)4, ReferenceType.field, "21c"), - SGET_BYTE((byte)0x64, "SGET-BYTE", (byte)4, ReferenceType.field, "21c"), - SGET_CHAR((byte)0x65, "SGET-CHAR", (byte)4, ReferenceType.field, "21c"), - SGET_SHORT((byte)0x66, "SGET-SHORT", (byte)4, ReferenceType.field, "21c"), - SPUT((byte)0x67, "SPUT", (byte)4, ReferenceType.field, "21c"), - SPUT_WIDE((byte)0x68, "SPUT-WIDE", (byte)4, ReferenceType.field, "21c"), - SPUT_OBJECT((byte)0x69, "SPUT-OBJECT", (byte)4, ReferenceType.field, "21c"), - SPUT_BOOLEAN((byte)0x6a, "SPUT-BOOLEAN", (byte)4, ReferenceType.field, "21c"), - SPUT_BYTE((byte)0x6b, "SPUT-BYTE", (byte)4, ReferenceType.field, "21c"), - SPUT_CHAR((byte)0x6c, "SPUT-CHAR", (byte)4, ReferenceType.field, "21c"), - SPUT_SHORT((byte)0x6d, "SPUT-SHORT", (byte)4, ReferenceType.field, "21c"), - INVOKE_VIRTUAL((byte)0x6e, "INVOKE-VIRTUAL", (byte)6, ReferenceType.method, "35c"), - INVOKE_SUPER((byte)0x6f, "INVOKE-SUPER", (byte)6, ReferenceType.method, "35c"), - INVOKE_DIRECT((byte)0x70, "INVOKE-DIRECT", (byte)6, ReferenceType.method, "35c"), - INVOKE_STATIC((byte)0x71, "INVOKE-STATIC", (byte)6, ReferenceType.method, "35c"), - INVOKE_INTERFACE((byte)0x72, "INVOKE-INTERFACE", (byte)6, ReferenceType.method, "35c"), - INVOKE_VIRTUAL_RANGE((byte)0x74, "INVOKE-VIRTUAL/RANGE", (byte)6, ReferenceType.method, "3rc"), - INVOKE_SUPER_RANGE((byte)0x75, "INVOKE-SUPER/RANGE", (byte)6, ReferenceType.method, "3rc"), - INVOKE_DIRECT_RANGE((byte)0x76, "INVOKE-DIRECT/RANGE", (byte)6, ReferenceType.method, "3rc"), - INVOKE_STATIC_RANGE((byte)0x77, "INVOKE-STATIC/RANGE", (byte)6, ReferenceType.method, "3rc"), - INVOKE_INTERFACE_RANGE((byte)0x78, "INVOKE-INTERFACE/RANGE", (byte)6, ReferenceType.method, "3rc"), - NEG_INT((byte)0x7b, "NEG-INT", (byte)2, ReferenceType.none, "12x"), - NOT_INT((byte)0x7c, "NOT-INT", (byte)2, ReferenceType.none, "12x"), - NEG_LONG((byte)0x7d, "NEG-LONG", (byte)2, ReferenceType.none, "12x"), - NOT_LONG((byte)0x7e, "NOT-LONG", (byte)2, ReferenceType.none, "12x"), - NEG_FLOAT((byte)0x7f, "NEG-FLOAT", (byte)2, ReferenceType.none, "12x"), - NEG_DOUBLE((byte)0x80, "NEG-DOUBLE", (byte)2, ReferenceType.none, "12x"), - INT_TO_LONG((byte)0x81, "INT-TO-LONG", (byte)2, ReferenceType.none, "12x"), - INT_TO_FLOAT((byte)0x82, "INT-TO-FLOAT", (byte)2, ReferenceType.none, "12x"), - INT_TO_DOUBLE((byte)0x83, "INT-TO-DOUBLE", (byte)2, ReferenceType.none, "12x"), - LONG_TO_INT((byte)0x84, "LONG-TO-INT", (byte)2, ReferenceType.none, "12x"), - LONG_TO_FLOAT((byte)0x85, "LONG-TO-FLOAT", (byte)2, ReferenceType.none, "12x"), - LONG_TO_DOUBLE((byte)0x86, "LONG-TO-DOUBLE", (byte)2, ReferenceType.none, "12x"), - FLOAT_TO_INT((byte)0x87, "FLOAT-TO-INT", (byte)2, ReferenceType.none, "12x"), - FLOAT_TO_LONG((byte)0x88, "FLOAT-TO-LONG", (byte)2, ReferenceType.none, "12x"), - FLOAT_TO_DOUBLE((byte)0x89, "FLOAT-TO-DOUBLE", (byte)2, ReferenceType.none, "12x"), - DOUBLE_TO_INT((byte)0x8a, "DOUBLE-TO-INT", (byte)2, ReferenceType.none, "12x"), - DOUBLE_TO_LONG((byte)0x8b, "DOUBLE-TO-LONG", (byte)2, ReferenceType.none, "12x"), - DOUBLE_TO_FLOAT((byte)0x8c, "DOUBLE-TO-FLOAT", (byte)2, ReferenceType.none, "12x"), - INT_TO_BYTE((byte)0x8d, "INT-TO-BYTE", (byte)2, ReferenceType.none, "12x"), - INT_TO_CHAR((byte)0x8e, "INT-TO-CHAR", (byte)2, ReferenceType.none, "12x"), - INT_TO_SHORT((byte)0x8f, "INT-TO-SHORT", (byte)2, ReferenceType.none, "12x"), - ADD_INT((byte)0x90, "ADD-INT", (byte)4, ReferenceType.none, "23x"), - SUB_INT((byte)0x91, "SUB-INT", (byte)4, ReferenceType.none, "23x"), - MUL_INT((byte)0x92, "MUL-INT", (byte)4, ReferenceType.none, "23x"), - DIV_INT((byte)0x93, "DIV-INT", (byte)4, ReferenceType.none, "23x"), - REM_INT((byte)0x94, "REM-INT", (byte)4, ReferenceType.none, "23x"), - AND_INT((byte)0x95, "AND-INT", (byte)4, ReferenceType.none, "23x"), - OR_INT((byte)0x96, "OR-INT", (byte)4, ReferenceType.none, "23x"), - XOR_INT((byte)0x97, "XOR-INT", (byte)4, ReferenceType.none, "23x"), - SHL_INT((byte)0x98, "SHL-INT", (byte)4, ReferenceType.none, "23x"), - SHR_INT((byte)0x99, "SHR-INT", (byte)4, ReferenceType.none, "23x"), - USHR_INT((byte)0x9a, "USHR-INT", (byte)4, ReferenceType.none, "23x"), - ADD_LONG((byte)0x9b, "ADD-LONG", (byte)4, ReferenceType.none, "23x"), - SUB_LONG((byte)0x9c, "SUB-LONG", (byte)4, ReferenceType.none, "23x"), - MUL_LONG((byte)0x9d, "MUL-LONG", (byte)4, ReferenceType.none, "23x"), - DIV_LONG((byte)0x9e, "DIV-LONG", (byte)4, ReferenceType.none, "23x"), - REM_LONG((byte)0x9f, "REM-LONG", (byte)4, ReferenceType.none, "23x"), - AND_LONG((byte)0xa0, "AND-LONG", (byte)4, ReferenceType.none, "23x"), - OR_LONG((byte)0xa1, "OR-LONG", (byte)4, ReferenceType.none, "23x"), - XOR_LONG((byte)0xa2, "XOR-LONG", (byte)4, ReferenceType.none, "23x"), - SHL_LONG((byte)0xa3, "SHL-LONG", (byte)4, ReferenceType.none, "23x"), - SHR_LONG((byte)0xa4, "SHR-LONG", (byte)4, ReferenceType.none, "23x"), - USHR_LONG((byte)0xa5, "USHR-LONG", (byte)4, ReferenceType.none, "23x"), - ADD_FLOAT((byte)0xa6, "ADD-FLOAT", (byte)4, ReferenceType.none, "23x"), - SUB_FLOAT((byte)0xa7, "SUB-FLOAT", (byte)4, ReferenceType.none, "23x"), - MUL_FLOAT((byte)0xa8, "MUL-FLOAT", (byte)4, ReferenceType.none, "23x"), - DIV_FLOAT((byte)0xa9, "DIV-FLOAT", (byte)4, ReferenceType.none, "23x"), - REM_FLOAT((byte)0xaa, "REM-FLOAT", (byte)4, ReferenceType.none, "23x"), - ADD_DOUBLE((byte)0xab, "ADD-DOUBLE", (byte)4, ReferenceType.none, "23x"), - SUB_DOUBLE((byte)0xac, "SUB-DOUBLE", (byte)4, ReferenceType.none, "23x"), - MUL_DOUBLE((byte)0xad, "MUL-DOUBLE", (byte)4, ReferenceType.none, "23x"), - DIV_DOUBLE((byte)0xae, "DIV-DOUBLE", (byte)4, ReferenceType.none, "23x"), - REM_DOUBLE((byte)0xaf, "REM-DOUBLE", (byte)4, ReferenceType.none, "23x"), - ADD_INT_2ADDR((byte)0xb0, "ADD-INT/2ADDR", (byte)2, ReferenceType.none, "12x"), - SUB_INT_2ADDR((byte)0xb1, "SUB-INT/2ADDR", (byte)2, ReferenceType.none, "12x"), - MUL_INT_2ADDR((byte)0xb2, "MUL-INT/2ADDR", (byte)2, ReferenceType.none, "12x"), - DIV_INT_2ADDR((byte)0xb3, "DIV-INT/2ADDR", (byte)2, ReferenceType.none, "12x"), - REM_INT_2ADDR((byte)0xb4, "REM-INT/2ADDR", (byte)2, ReferenceType.none, "12x"), - AND_INT_2ADDR((byte)0xb5, "AND-INT/2ADDR", (byte)2, ReferenceType.none, "12x"), - OR_INT_2ADDR((byte)0xb6, "OR-INT/2ADDR", (byte)2, ReferenceType.none, "12x"), - XOR_INT_2ADDR((byte)0xb7, "XOR-INT/2ADDR", (byte)2, ReferenceType.none, "12x"), - SHL_INT_2ADDR((byte)0xb8, "SHL-INT/2ADDR", (byte)2, ReferenceType.none, "12x"), - SHR_INT_2ADDR((byte)0xb9, "SHR-INT/2ADDR", (byte)2, ReferenceType.none, "12x"), - USHR_INT_2ADDR((byte)0xba, "USHR-INT/2ADDR", (byte)2, ReferenceType.none, "12x"), - ADD_LONG_2ADDR((byte)0xbb, "ADD-LONG/2ADDR", (byte)2, ReferenceType.none, "12x"), - SUB_LONG_2ADDR((byte)0xbc, "SUB-LONG/2ADDR", (byte)2, ReferenceType.none, "12x"), - MUL_LONG_2ADDR((byte)0xbd, "MUL-LONG/2ADDR", (byte)2, ReferenceType.none, "12x"), - DIV_LONG_2ADDR((byte)0xbe, "DIV-LONG/2ADDR", (byte)2, ReferenceType.none, "12x"), - REM_LONG_2ADDR((byte)0xbf, "REM-LONG/2ADDR", (byte)2, ReferenceType.none, "12x"), - AND_LONG_2ADDR((byte)0xc0, "AND-LONG/2ADDR", (byte)2, ReferenceType.none, "12x"), - OR_LONG_2ADDR((byte)0xc1, "OR-LONG/2ADDR", (byte)2, ReferenceType.none, "12x"), - XOR_LONG_2ADDR((byte)0xc2, "XOR-LONG/2ADDR", (byte)2, ReferenceType.none, "12x"), - SHL_LONG_2ADDR((byte)0xc3, "SHL-LONG/2ADDR", (byte)2, ReferenceType.none, "12x"), - SHR_LONG_2ADDR((byte)0xc4, "SHR-LONG/2ADDR", (byte)2, ReferenceType.none, "12x"), - USHR_LONG_2ADDR((byte)0xc5, "USHR-LONG/2ADDR", (byte)2, ReferenceType.none, "12x"), - ADD_FLOAT_2ADDR((byte)0xc6, "ADD-FLOAT/2ADDR", (byte)2, ReferenceType.none, "12x"), - SUB_FLOAT_2ADDR((byte)0xc7, "SUB-FLOAT/2ADDR", (byte)2, ReferenceType.none, "12x"), - MUL_FLOAT_2ADDR((byte)0xc8, "MUL-FLOAT/2ADDR", (byte)2, ReferenceType.none, "12x"), - DIV_FLOAT_2ADDR((byte)0xc9, "DIV-FLOAT/2ADDR", (byte)2, ReferenceType.none, "12x"), - REM_FLOAT_2ADDR((byte)0xca, "REM-FLOAT/2ADDR", (byte)2, ReferenceType.none, "12x"), - ADD_DOUBLE_2ADDR((byte)0xcb, "ADD-DOUBLE/2ADDR", (byte)2, ReferenceType.none, "12x"), - SUB_DOUBLE_2ADDR((byte)0xcc, "SUB-DOUBLE/2ADDR", (byte)2, ReferenceType.none, "12x"), - MUL_DOUBLE_2ADDR((byte)0xcd, "MUL-DOUBLE/2ADDR", (byte)2, ReferenceType.none, "12x"), - DIV_DOUBLE_2ADDR((byte)0xce, "DIV-DOUBLE/2ADDR", (byte)2, ReferenceType.none, "12x"), - REM_DOUBLE_2ADDR((byte)0xcf, "REM-DOUBLE/2ADDR", (byte)2, ReferenceType.none, "12x"), - ADD_INT_LIT16((byte)0xd0, "ADD-INT/LIT16", (byte)4, ReferenceType.none, "22s"), - RSUB_INT((byte)0xd1, "RSUB-INT", (byte)4, ReferenceType.none, "22s"), - MUL_INT_LIT16((byte)0xd2, "MUL-INT/LIT16", (byte)4, ReferenceType.none, "22s"), - DIV_INT_LIT16((byte)0xd3, "DIV-INT/LIT16", (byte)4, ReferenceType.none, "22s"), - REM_INT_LIT16((byte)0xd4, "REM-INT/LIT16", (byte)4, ReferenceType.none, "22s"), - AND_INT_LIT16((byte)0xd5, "AND-INT/LIT16", (byte)4, ReferenceType.none, "22s"), - OR_INT_LIT16((byte)0xd6, "OR-INT/LIT16", (byte)4, ReferenceType.none, "22s"), - XOR_INT_LIT16((byte)0xd7, "XOR-INT/LIT16", (byte)4, ReferenceType.none, "22s"), - ADD_INT_LIT8((byte)0xd8, "ADD-INT/LIT8", (byte)4, ReferenceType.none, "22b"), - RSUB_INT_LIT8((byte)0xd9, "RSUB-INT/LIT8", (byte)4, ReferenceType.none, "22b"), - MUL_INT_LIT8((byte)0xda, "MUL-INT/LIT8", (byte)4, ReferenceType.none, "22b"), - DIV_INT_LIT8((byte)0xdb, "DIV-INT/LIT8", (byte)4, ReferenceType.none, "22b"), - REM_INT_LIT8((byte)0xdc, "REM-INT/LIT8", (byte)4, ReferenceType.none, "22b"), - AND_INT_LIT8((byte)0xdd, "AND-INT/LIT8", (byte)4, ReferenceType.none, "22b"), - OR_INT_LIT8((byte)0xde, "OR-INT/LIT8", (byte)4, ReferenceType.none, "22b"), - XOR_INT_LIT8((byte)0xdf, "XOR-INT/LIT8", (byte)4, ReferenceType.none, "22b"), - SHL_INT_LIT8((byte)0xe0, "SHL-INT/LIT8", (byte)4, ReferenceType.none, "22b"), - SHR_INT_LIT8((byte)0xe1, "SHR-INT/LIT8", (byte)4, ReferenceType.none, "22b"), - USHR_INT_LIT8((byte)0xe2, "USHR-INT/LIT8", (byte)4, ReferenceType.none, "22b"); + NOP((byte)0x00, "nop", ReferenceType.none, Format.Format10x), + MOVE((byte)0x01, "move", ReferenceType.none, Format.Format12x), + MOVE_FROM16((byte)0x02, "move/from16", ReferenceType.none, Format.Format22x), + MOVE_16((byte)0x03, "move/16", ReferenceType.none, Format.Format32x), + MOVE_WIDE((byte)0x04, "move-wide", ReferenceType.none, Format.Format12x), + MOVE_WIDE_FROM16((byte)0x05, "move-wide/from16", ReferenceType.none, Format.Format22x), + MOVE_WIDE_16((byte)0x06, "move-wide/16", ReferenceType.none, Format.Format32x), + MOVE_OBJECT((byte)0x07, "move-object", ReferenceType.none, Format.Format12x), + MOVE_OBJECT_FROM16((byte)0x08, "move-object/from16", ReferenceType.none, Format.Format22x), + MOVE_OBJECT_16((byte)0x09, "move-object/16", ReferenceType.none, Format.Format32x), + MOVE_RESULT((byte)0x0a, "move-result", ReferenceType.none, Format.Format11x), + MOVE_RESULT_WIDE((byte)0x0b, "move-result-wide", ReferenceType.none, Format.Format11x), + MOVE_RESULT_OBJECT((byte)0x0c, "move-result-object", ReferenceType.none, Format.Format11x), + MOVE_EXCEPTION((byte)0x0d, "move-exception", ReferenceType.none, Format.Format11x), + RETURN_VOID((byte)0x0e, "return-void", ReferenceType.none, Format.Format10x), + RETURN((byte)0x0f, "return", ReferenceType.none, Format.Format11x), + RETURN_WIDE((byte)0x10, "return-wide", ReferenceType.none, Format.Format11x), + RETURN_OBJECT((byte)0x11, "return-object", ReferenceType.none, Format.Format11x), + CONST_4((byte)0x12, "const/4", ReferenceType.none, Format.Format11n), + CONST_16((byte)0x13, "const/16", ReferenceType.none, Format.Format21s), + CONST((byte)0x14, "const", ReferenceType.none, Format.Format31i), + CONST_HIGH16((byte)0x15, "const/high16", ReferenceType.none, Format.Format21h), + CONST_WIDE_16((byte)0x16, "const-wide/16", ReferenceType.none, Format.Format21s), + CONST_WIDE_32((byte)0x17, "const-wide/32", ReferenceType.none, Format.Format31i), + CONST_WIDE((byte)0x18, "const-wide", ReferenceType.none, Format.Format51l), + CONST_WIDE_HIGH16((byte)0x19, "const-wide/high16", ReferenceType.none, Format.Format21h), + CONST_STRING((byte)0x1a, "const-string", ReferenceType.string, Format.Format21c), + CONST_STRING_JUMBO((byte)0x1b, "const-string/jumbo", ReferenceType.string, Format.Format31c), + CONST_CLASS((byte)0x1c, "const-class", ReferenceType.type, Format.Format21c), + MONITOR_ENTER((byte)0x1d, "monitor-enter", ReferenceType.none, Format.Format11x), + MONITOR_EXIT((byte)0x1e, "monitor-exit", ReferenceType.none, Format.Format11x), + CHECK_CAST((byte)0x1f, "check-cast", ReferenceType.type, Format.Format21c), + INSTANCE_OF((byte)0x20, "instance-of", ReferenceType.type, Format.Format22c), + ARRAY_LENGTH((byte)0x21, "array-length", ReferenceType.none, Format.Format12x), + NEW_INSTANCE((byte)0x22, "new-instance", ReferenceType.type, Format.Format21c), + NEW_ARRAY((byte)0x23, "new-array", ReferenceType.type, Format.Format22c), + FILLED_NEW_ARRAY((byte)0x24, "filled-new-array", ReferenceType.type, Format.Format35c), + FILLED_NEW_ARRAY_RANGE((byte)0x25, "filled-new-array/range", ReferenceType.type, Format.Format3rc), + FILL_ARRAY_DATA((byte)0x26, "fill-array-data", ReferenceType.none, Format.Format31t), + THROW((byte)0x27, "throw", ReferenceType.none, Format.Format11x), + GOTO((byte)0x28, "goto", ReferenceType.none, Format.Format10t), + GOTO_16((byte)0x29, "goto/16", ReferenceType.none, Format.Format20t), + GOTO_32((byte)0x2a, "goto/32", ReferenceType.none, Format.Format30t), + PACKED_SWITCH((byte)0x2b, "packed-switch", ReferenceType.none, Format.Format31t), + SPARSE_SWITCH((byte)0x2c, "sparse-switch", ReferenceType.none, Format.Format31t), + CMPL_FLOAT((byte)0x2d, "cmpl-float", ReferenceType.none, Format.Format23x), + CMPG_FLOAT((byte)0x2e, "cmpg-float", ReferenceType.none, Format.Format23x), + CMPL_DOUBLE((byte)0x2f, "cmpl-double", ReferenceType.none, Format.Format23x), + CMPG_DOUBLE((byte)0x30, "cmpg-double", ReferenceType.none, Format.Format23x), + CMP_LONG((byte)0x31, "cmp-long", ReferenceType.none, Format.Format23x), + IF_EQ((byte)0x32, "if-eq", ReferenceType.none, Format.Format22t), + IF_NE((byte)0x33, "if-ne", ReferenceType.none, Format.Format22t), + IF_LT((byte)0x34, "if-lt", ReferenceType.none, Format.Format22t), + IF_GE((byte)0x35, "if-ge", ReferenceType.none, Format.Format22t), + IF_GT((byte)0x36, "if-gt", ReferenceType.none, Format.Format22t), + IF_LE((byte)0x37, "if-le", ReferenceType.none, Format.Format22t), + IF_EQZ((byte)0x38, "if-eqz", ReferenceType.none, Format.Format21t), + IF_NEZ((byte)0x39, "if-nez", ReferenceType.none, Format.Format21t), + IF_LTZ((byte)0x3a, "if-ltz", ReferenceType.none, Format.Format21t), + IF_GEZ((byte)0x3b, "if-gez", ReferenceType.none, Format.Format21t), + IF_GTZ((byte)0x3c, "if-gtz", ReferenceType.none, Format.Format21t), + IF_LEZ((byte)0x3d, "if-lez", ReferenceType.none, Format.Format21t), + AGET((byte)0x44, "aget", ReferenceType.none, Format.Format23x), + AGET_WIDE((byte)0x45, "aget-wide", ReferenceType.none, Format.Format23x), + AGET_OBJECT((byte)0x46, "aget-object", ReferenceType.none, Format.Format23x), + AGET_BOOLEAN((byte)0x47, "aget-boolean", ReferenceType.none, Format.Format23x), + AGET_BYTE((byte)0x48, "aget-byte", ReferenceType.none, Format.Format23x), + AGET_CHAR((byte)0x49, "aget-char", ReferenceType.none, Format.Format23x), + AGET_SHORT((byte)0x4a, "aget-short", ReferenceType.none, Format.Format23x), + APUT((byte)0x4b, "aput", ReferenceType.none, Format.Format23x), + APUT_WIDE((byte)0x4c, "aput-wide", ReferenceType.none, Format.Format23x), + APUT_OBJECT((byte)0x4d, "aput-object", ReferenceType.none, Format.Format23x), + APUT_BOOLEAN((byte)0x4e, "aput-boolean", ReferenceType.none, Format.Format23x), + APUT_BYTE((byte)0x4f, "aput-byte", ReferenceType.none, Format.Format23x), + APUT_CHAR((byte)0x50, "aput-char", ReferenceType.none, Format.Format23x), + APUT_SHORT((byte)0x51, "aput-short", ReferenceType.none, Format.Format23x), + IGET((byte)0x52, "iget", ReferenceType.field, Format.Format22c), + IGET_WIDE((byte)0x53, "iget-wide", ReferenceType.field, Format.Format22c), + IGET_OBJECT((byte)0x54, "iget-object", ReferenceType.field, Format.Format22c), + IGET_BOOLEAN((byte)0x55, "iget-boolean", ReferenceType.field, Format.Format22c), + IGET_BYTE((byte)0x56, "iget-byte", ReferenceType.field, Format.Format22c), + IGET_CHAR((byte)0x57, "iget-char", ReferenceType.field, Format.Format22c), + IGET_SHORT((byte)0x58, "iget-short", ReferenceType.field, Format.Format22c), + IPUT((byte)0x59, "iput", ReferenceType.field, Format.Format22c), + IPUT_WIDE((byte)0x5a, "iput-wide", ReferenceType.field, Format.Format22c), + IPUT_OBJECT((byte)0x5b, "iput-object", ReferenceType.field, Format.Format22c), + IPUT_BOOLEAN((byte)0x5c, "iput-boolean", ReferenceType.field, Format.Format22c), + IPUT_BYTE((byte)0x5d, "iput-byte", ReferenceType.field, Format.Format22c), + IPUT_CHAR((byte)0x5e, "iput-char", ReferenceType.field, Format.Format22c), + IPUT_SHORT((byte)0x5f, "iput-short", ReferenceType.field, Format.Format22c), + SGET((byte)0x60, "sget", ReferenceType.field, Format.Format21c), + SGET_WIDE((byte)0x61, "sget-wide", ReferenceType.field, Format.Format21c), + SGET_OBJECT((byte)0x62, "sget-object", ReferenceType.field, Format.Format21c), + SGET_BOOLEAN((byte)0x63, "sget-boolean", ReferenceType.field, Format.Format21c), + SGET_BYTE((byte)0x64, "sget-byte", ReferenceType.field, Format.Format21c), + SGET_CHAR((byte)0x65, "sget-char", ReferenceType.field, Format.Format21c), + SGET_SHORT((byte)0x66, "sget-short", ReferenceType.field, Format.Format21c), + SPUT((byte)0x67, "sput", ReferenceType.field, Format.Format21c), + SPUT_WIDE((byte)0x68, "sput-wide", ReferenceType.field, Format.Format21c), + SPUT_OBJECT((byte)0x69, "sput-object", ReferenceType.field, Format.Format21c), + SPUT_BOOLEAN((byte)0x6a, "sput-boolean", ReferenceType.field, Format.Format21c), + SPUT_BYTE((byte)0x6b, "sput-byte", ReferenceType.field, Format.Format21c), + SPUT_CHAR((byte)0x6c, "sput-char", ReferenceType.field, Format.Format21c), + SPUT_SHORT((byte)0x6d, "sput-short", ReferenceType.field, Format.Format21c), + INVOKE_VIRTUAL((byte)0x6e, "invoke-virtual", ReferenceType.method, Format.Format35c), + INVOKE_SUPER((byte)0x6f, "invoke-super", ReferenceType.method, Format.Format35c), + INVOKE_DIRECT((byte)0x70, "invoke-direct", ReferenceType.method, Format.Format35c), + INVOKE_STATIC((byte)0x71, "invoke-static", ReferenceType.method, Format.Format35c), + INVOKE_INTERFACE((byte)0x72, "invoke-interface", ReferenceType.method, Format.Format35c), + INVOKE_VIRTUAL_RANGE((byte)0x74, "invoke-virtual/range", ReferenceType.method, Format.Format3rc), + INVOKE_SUPER_RANGE((byte)0x75, "invoke-super/range", ReferenceType.method, Format.Format3rc), + INVOKE_DIRECT_RANGE((byte)0x76, "invoke-direct/range", ReferenceType.method, Format.Format3rc), + INVOKE_STATIC_RANGE((byte)0x77, "invoke-static/range", ReferenceType.method, Format.Format3rc), + INVOKE_INTERFACE_RANGE((byte)0x78, "invoke-interface/range", ReferenceType.method, Format.Format3rc), + NEG_INT((byte)0x7b, "neg-int", ReferenceType.none, Format.Format12x), + NOT_INT((byte)0x7c, "not-int", ReferenceType.none, Format.Format12x), + NEG_LONG((byte)0x7d, "neg-long", ReferenceType.none, Format.Format12x), + NOT_LONG((byte)0x7e, "not-long", ReferenceType.none, Format.Format12x), + NEG_FLOAT((byte)0x7f, "neg-float", ReferenceType.none, Format.Format12x), + NEG_DOUBLE((byte)0x80, "neg-double", ReferenceType.none, Format.Format12x), + INT_TO_LONG((byte)0x81, "int-to-long", ReferenceType.none, Format.Format12x), + INT_TO_FLOAT((byte)0x82, "int-to-float", ReferenceType.none, Format.Format12x), + INT_TO_DOUBLE((byte)0x83, "int-to-double", ReferenceType.none, Format.Format12x), + LONG_TO_INT((byte)0x84, "long-to-int", ReferenceType.none, Format.Format12x), + LONG_TO_FLOAT((byte)0x85, "long-to-float", ReferenceType.none, Format.Format12x), + LONG_TO_DOUBLE((byte)0x86, "long-to-double", ReferenceType.none, Format.Format12x), + FLOAT_TO_INT((byte)0x87, "float-to-int", ReferenceType.none, Format.Format12x), + FLOAT_TO_LONG((byte)0x88, "float-to-long", ReferenceType.none, Format.Format12x), + FLOAT_TO_DOUBLE((byte)0x89, "float-to-double", ReferenceType.none, Format.Format12x), + DOUBLE_TO_INT((byte)0x8a, "double-to-int", ReferenceType.none, Format.Format12x), + DOUBLE_TO_LONG((byte)0x8b, "double-to-long", ReferenceType.none, Format.Format12x), + DOUBLE_TO_FLOAT((byte)0x8c, "double-to-float", ReferenceType.none, Format.Format12x), + INT_TO_BYTE((byte)0x8d, "int-to-byte", ReferenceType.none, Format.Format12x), + INT_TO_CHAR((byte)0x8e, "int-to-char", ReferenceType.none, Format.Format12x), + INT_TO_SHORT((byte)0x8f, "int-to-short", ReferenceType.none, Format.Format12x), + ADD_INT((byte)0x90, "add-int", ReferenceType.none, Format.Format23x), + SUB_INT((byte)0x91, "sub-int", ReferenceType.none, Format.Format23x), + MUL_INT((byte)0x92, "mul-int", ReferenceType.none, Format.Format23x), + DIV_INT((byte)0x93, "div-int", ReferenceType.none, Format.Format23x), + REM_INT((byte)0x94, "rem-int", ReferenceType.none, Format.Format23x), + AND_INT((byte)0x95, "and-int", ReferenceType.none, Format.Format23x), + OR_INT((byte)0x96, "or-int", ReferenceType.none, Format.Format23x), + XOR_INT((byte)0x97, "xor-int", ReferenceType.none, Format.Format23x), + SHL_INT((byte)0x98, "shl-int", ReferenceType.none, Format.Format23x), + SHR_INT((byte)0x99, "shr-int", ReferenceType.none, Format.Format23x), + USHR_INT((byte)0x9a, "ushr-int", ReferenceType.none, Format.Format23x), + ADD_LONG((byte)0x9b, "add-long", ReferenceType.none, Format.Format23x), + SUB_LONG((byte)0x9c, "sub-long", ReferenceType.none, Format.Format23x), + MUL_LONG((byte)0x9d, "mul-long", ReferenceType.none, Format.Format23x), + DIV_LONG((byte)0x9e, "div-long", ReferenceType.none, Format.Format23x), + REM_LONG((byte)0x9f, "rem-long", ReferenceType.none, Format.Format23x), + AND_LONG((byte)0xa0, "and-long", ReferenceType.none, Format.Format23x), + OR_LONG((byte)0xa1, "or-long", ReferenceType.none, Format.Format23x), + XOR_LONG((byte)0xa2, "xor-long", ReferenceType.none, Format.Format23x), + SHL_LONG((byte)0xa3, "shl-long", ReferenceType.none, Format.Format23x), + SHR_LONG((byte)0xa4, "shr-long", ReferenceType.none, Format.Format23x), + USHR_LONG((byte)0xa5, "ushr-long", ReferenceType.none, Format.Format23x), + ADD_FLOAT((byte)0xa6, "add-float", ReferenceType.none, Format.Format23x), + SUB_FLOAT((byte)0xa7, "sub-float", ReferenceType.none, Format.Format23x), + MUL_FLOAT((byte)0xa8, "mul-float", ReferenceType.none, Format.Format23x), + DIV_FLOAT((byte)0xa9, "div-float", ReferenceType.none, Format.Format23x), + REM_FLOAT((byte)0xaa, "rem-float", ReferenceType.none, Format.Format23x), + ADD_DOUBLE((byte)0xab, "add-double", ReferenceType.none, Format.Format23x), + SUB_DOUBLE((byte)0xac, "sub-double", ReferenceType.none, Format.Format23x), + MUL_DOUBLE((byte)0xad, "mul-double", ReferenceType.none, Format.Format23x), + DIV_DOUBLE((byte)0xae, "div-double", ReferenceType.none, Format.Format23x), + REM_DOUBLE((byte)0xaf, "rem-double", ReferenceType.none, Format.Format23x), + ADD_INT_2ADDR((byte)0xb0, "add-int/2addr", ReferenceType.none, Format.Format12x), + SUB_INT_2ADDR((byte)0xb1, "sub-int/2addr", ReferenceType.none, Format.Format12x), + MUL_INT_2ADDR((byte)0xb2, "mul-int/2addr", ReferenceType.none, Format.Format12x), + DIV_INT_2ADDR((byte)0xb3, "div-int/2addr", ReferenceType.none, Format.Format12x), + REM_INT_2ADDR((byte)0xb4, "rem-int/2addr", ReferenceType.none, Format.Format12x), + AND_INT_2ADDR((byte)0xb5, "and-int/2addr", ReferenceType.none, Format.Format12x), + OR_INT_2ADDR((byte)0xb6, "or-int/2addr", ReferenceType.none, Format.Format12x), + XOR_INT_2ADDR((byte)0xb7, "xor-int/2addr", ReferenceType.none, Format.Format12x), + SHL_INT_2ADDR((byte)0xb8, "shl-int/2addr", ReferenceType.none, Format.Format12x), + SHR_INT_2ADDR((byte)0xb9, "shr-int/2addr", ReferenceType.none, Format.Format12x), + USHR_INT_2ADDR((byte)0xba, "ushr-int/2addr", ReferenceType.none, Format.Format12x), + ADD_LONG_2ADDR((byte)0xbb, "add-long/2addr", ReferenceType.none, Format.Format12x), + SUB_LONG_2ADDR((byte)0xbc, "sub-long/2addr", ReferenceType.none, Format.Format12x), + MUL_LONG_2ADDR((byte)0xbd, "mul-long/2addr", ReferenceType.none, Format.Format12x), + DIV_LONG_2ADDR((byte)0xbe, "div-long/2addr", ReferenceType.none, Format.Format12x), + REM_LONG_2ADDR((byte)0xbf, "rem-long/2addr", ReferenceType.none, Format.Format12x), + AND_LONG_2ADDR((byte)0xc0, "and-long/2addr", ReferenceType.none, Format.Format12x), + OR_LONG_2ADDR((byte)0xc1, "or-long/2addr", ReferenceType.none, Format.Format12x), + XOR_LONG_2ADDR((byte)0xc2, "xor-long/2addr", ReferenceType.none, Format.Format12x), + SHL_LONG_2ADDR((byte)0xc3, "shl-long/2addr", ReferenceType.none, Format.Format12x), + SHR_LONG_2ADDR((byte)0xc4, "shr-long/2addr", ReferenceType.none, Format.Format12x), + USHR_LONG_2ADDR((byte)0xc5, "ushr-long/2addr", ReferenceType.none, Format.Format12x), + ADD_FLOAT_2ADDR((byte)0xc6, "add-float/2addr", ReferenceType.none, Format.Format12x), + SUB_FLOAT_2ADDR((byte)0xc7, "sub-float/2addr", ReferenceType.none, Format.Format12x), + MUL_FLOAT_2ADDR((byte)0xc8, "mul-float/2addr", ReferenceType.none, Format.Format12x), + DIV_FLOAT_2ADDR((byte)0xc9, "div-float/2addr", ReferenceType.none, Format.Format12x), + REM_FLOAT_2ADDR((byte)0xca, "rem-float/2addr", ReferenceType.none, Format.Format12x), + ADD_DOUBLE_2ADDR((byte)0xcb, "add-double/2addr", ReferenceType.none, Format.Format12x), + SUB_DOUBLE_2ADDR((byte)0xcc, "sub-double/2addr", ReferenceType.none, Format.Format12x), + MUL_DOUBLE_2ADDR((byte)0xcd, "mul-double/2addr", ReferenceType.none, Format.Format12x), + DIV_DOUBLE_2ADDR((byte)0xce, "div-double/2addr", ReferenceType.none, Format.Format12x), + REM_DOUBLE_2ADDR((byte)0xcf, "rem-double/2addr", ReferenceType.none, Format.Format12x), + ADD_INT_LIT16((byte)0xd0, "add-int/lit16", ReferenceType.none, Format.Format22s), + RSUB_INT((byte)0xd1, "rsub-int", ReferenceType.none, Format.Format22s), + MUL_INT_LIT16((byte)0xd2, "mul-int/lit16", ReferenceType.none, Format.Format22s), + DIV_INT_LIT16((byte)0xd3, "div-int/lit16", ReferenceType.none, Format.Format22s), + REM_INT_LIT16((byte)0xd4, "rem-int/lit16", ReferenceType.none, Format.Format22s), + AND_INT_LIT16((byte)0xd5, "and-int/lit16", ReferenceType.none, Format.Format22s), + OR_INT_LIT16((byte)0xd6, "or-int/lit16", ReferenceType.none, Format.Format22s), + XOR_INT_LIT16((byte)0xd7, "xor-int/lit16", ReferenceType.none, Format.Format22s), + ADD_INT_LIT8((byte)0xd8, "add-int/lit8", ReferenceType.none, Format.Format22b), + RSUB_INT_LIT8((byte)0xd9, "rsub-int/lit8", ReferenceType.none, Format.Format22b), + MUL_INT_LIT8((byte)0xda, "mul-int/lit8", ReferenceType.none, Format.Format22b), + DIV_INT_LIT8((byte)0xdb, "div-int/lit8", ReferenceType.none, Format.Format22b), + REM_INT_LIT8((byte)0xdc, "rem-int/lit8", ReferenceType.none, Format.Format22b), + AND_INT_LIT8((byte)0xdd, "and-int/lit8", ReferenceType.none, Format.Format22b), + OR_INT_LIT8((byte)0xde, "or-int/lit8", ReferenceType.none, Format.Format22b), + XOR_INT_LIT8((byte)0xdf, "xor-int/lit8", ReferenceType.none, Format.Format22b), + SHL_INT_LIT8((byte)0xe0, "shl-int/lit8", ReferenceType.none, Format.Format22b), + SHR_INT_LIT8((byte)0xe1, "shr-int/lit8", ReferenceType.none, Format.Format22b), + USHR_INT_LIT8((byte)0xe2, "ushr-int/lit8", ReferenceType.none, Format.Format22b); @@ -269,7 +271,7 @@ public enum Opcode for (Opcode opcode: Opcode.values()) { opcodesByValue.set((opcode.value & 0xFF), opcode); - opcodesByName.put(opcode.name.toLowerCase().hashCode(), opcode); + opcodesByName.put(opcode.name.hashCode(), opcode); } }catch (Exception ex) { System.out.println(ex.toString()); @@ -286,14 +288,12 @@ public enum Opcode public final byte value; public final String name; - public final byte numBytes; public final ReferenceType referenceType; - public final String format; + public final Format format; - Opcode(byte opcodeValue, String opcodeName, byte numBytes, ReferenceType referenceType, String format) { + Opcode(byte opcodeValue, String opcodeName, ReferenceType referenceType, Format format) { this.value = opcodeValue; this.name = opcodeName; - this.numBytes = numBytes; this.referenceType = referenceType; this.format = format; } diff --git a/src/main/java/org/jf/dexlib/util/NumberUtils.java b/src/main/java/org/jf/dexlib/util/NumberUtils.java new file mode 100644 index 00000000..e7668185 --- /dev/null +++ b/src/main/java/org/jf/dexlib/util/NumberUtils.java @@ -0,0 +1,78 @@ +/* + * [The "BSD licence"] + * Copyright (c) 2009 Ben Gruver + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib.util; + +public class NumberUtils { + + public static byte decodeHighSignedNibble(byte b) { + return (byte)(b >> 4); + } + + public static byte decodeHighUnsignedNibble(byte b) { + return (byte)((b & 0xFF) >>> 4); + } + + public static byte decodeLowUnsignedNibble(byte b) { + return (byte)(b & 0x0F); + } + + public static short decodeUnsignedByte(byte b) { + return (short)(b & 0xFF); + } + + public static short decodeShort(byte lsb, byte msb) { + return (short) + ( lsb | + (msb << 8) + ); + } + + public static int decodeUnsignedShort(byte lsb, byte msb) { + return ((msb & 0xFF) << 8) | + (lsb & 0xFF); + } + + public static int decodeInt(byte lsb, byte mlsb, byte mmsb, byte msb) { + return lsb | + (mlsb << 8) | + (mmsb << 16) | + (msb << 24); + } + + public static long decodeLong(byte[] array, int startIndex) { + return array[startIndex++] | + (array[startIndex++] >> 8) | + (array[startIndex++] >> 16) | + (array[startIndex++] >> 24) | + ((long)array[startIndex++] >> 32) | + ((long)array[startIndex++] >> 40) | + ((long)array[startIndex++] >> 48) | + ((long)array[startIndex++] >> 56); + } +}