From 1efc2c038842f85728b0ae4311a0e550b826390b Mon Sep 17 00:00:00 2001 From: Ben Gruver Date: Thu, 17 Nov 2011 17:45:16 -0800 Subject: [PATCH] Add support for Format52c (type references) --- .../Format/InstructionMethodItem.java | 1 + .../org/jf/dexlib/Code/Format/Format.java | 1 + .../jf/dexlib/Code/Format/Instruction22c.java | 4 + .../jf/dexlib/Code/Format/Instruction52c.java | 94 ++++++++++++++++++ .../main/java/org/jf/dexlib/Code/Opcode.java | 2 + .../test/smali/jumbo-type-tests/Assert.smali | 41 ++++++++ .../smali/jumbo-type-tests/Format52c.smali | 98 +++++++++++++++++++ .../smali/jumbo-type-tests/TestSuite.smali | 4 +- .../src/main/antlr3/org/jf/smali/smaliLexer.g | 4 + .../main/antlr3/org/jf/smali/smaliParser.g | 4 + .../antlr3/org/jf/smali/smaliTreeWalker.g | 11 +++ smali/src/main/jflex/smaliLexer.flex | 4 + .../resources/LexerTest/InstructionTest.smali | 4 +- .../LexerTest/InstructionTest.tokens | 4 +- 14 files changed, 273 insertions(+), 3 deletions(-) create mode 100644 dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction52c.java create mode 100644 smali-integration-tests/src/test/smali/jumbo-type-tests/Assert.smali create mode 100644 smali-integration-tests/src/test/smali/jumbo-type-tests/Format52c.smali diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java index a39ded32..a3528824 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/Format/InstructionMethodItem.java @@ -136,6 +136,7 @@ public class InstructionMethodItem extends MethodItem { writeLiteral(writer); return true; case Format22c: + case Format52c: writeOpcode(writer); writer.write(' '); writeFirstRegister(writer); diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Format.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Format.java index 198dc263..60a88eb7 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Format.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Format.java @@ -63,6 +63,7 @@ public enum Format { Format3rms(Instruction3rms.Factory, 6), Format41c(Instruction41c.Factory, 8), Format51l(Instruction51l.Factory, 10), + Format52c(Instruction52c.Factory, 10), ArrayData(null, -1, true), PackedSwitchData(null, -1, true), SparseSwitchData(null, -1, true), diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22c.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22c.java index 46b2c5a3..3ffb71c8 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22c.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction22c.java @@ -62,6 +62,10 @@ public class Instruction22c extends InstructionWithReference implements TwoRegis } protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) { + if(getReferencedItem().getIndex() > 0xFFFF) { + throw new RuntimeException(String.format("%s index is too large. Use the %s/jumbo instruction instead.", opcode.referenceType.name(), opcode.name)); + } + out.writeByte(opcode.value); out.writeByte((regB << 4) | regA); out.writeShort(getReferencedItem().getIndex()); diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction52c.java b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction52c.java new file mode 100644 index 00000000..0d7f3f55 --- /dev/null +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Format/Instruction52c.java @@ -0,0 +1,94 @@ +/* + * Copyright 2011, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 COPYRIGHT + * OWNER OR CONTRIBUTORS 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.Code.TwoRegisterInstruction; +import org.jf.dexlib.DexFile; +import org.jf.dexlib.Item; +import org.jf.dexlib.Util.AnnotatedOutput; +import org.jf.dexlib.Util.NumberUtils; + +public class Instruction52c extends InstructionWithJumboReference implements TwoRegisterInstruction { + public static final InstructionFactory Factory = new Factory(); + private short regA; + private short regB; + + public Instruction52c(Opcode opcode, int regA, int regB, Item referencedItem) { + super(opcode, referencedItem); + + if (regA >= 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"); + } + + this.regA = (short)regA; + this.regB = (short)regB; + } + + private Instruction52c(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { + super(dexFile, opcode, buffer, bufferIndex); + + this.regA = (short)NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 6); + this.regB = (short)NumberUtils.decodeUnsignedShort(buffer, bufferIndex + 8); + } + + protected void writeInstruction(AnnotatedOutput out, int currentCodeAddress) { + out.writeByte(0xFF); + out.writeByte(opcode.value); + out.writeInt(getReferencedItem().getIndex()); + out.writeShort(getRegisterA()); + out.writeShort(getRegisterB()); + } + + public Format getFormat() { + return Format.Format52c; + } + + public int getRegisterA() { + return regA & 0xFFFF; + } + + public int getRegisterB() { + return regB & 0xFFFF; + } + + private static class Factory implements InstructionFactory { + public Instruction makeInstruction(DexFile dexFile, Opcode opcode, byte[] buffer, int bufferIndex) { + return new Instruction52c(dexFile, opcode, buffer, bufferIndex); + } + } +} diff --git a/dexlib/src/main/java/org/jf/dexlib/Code/Opcode.java b/dexlib/src/main/java/org/jf/dexlib/Code/Opcode.java index 1a884a1a..5679feb6 100644 --- a/dexlib/src/main/java/org/jf/dexlib/Code/Opcode.java +++ b/dexlib/src/main/java/org/jf/dexlib/Code/Opcode.java @@ -284,7 +284,9 @@ public enum Opcode CONST_CLASS_JUMBO((short)0xff00, "const-class/jumbo", ReferenceType.type, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), CHECK_CAST_JUMBO((short)0xff01, "check-cast/jumbo", ReferenceType.type, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), + INSTANCE_OF_JUMBO((short)0xff02, "instance-of/jumbo", ReferenceType.type, Format.Format52c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), NEW_INSTANCE_JUMBO((short)0xff03, "new-instance/jumbo", ReferenceType.type, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), + NEW_ARRAY_JUMBO((short)0xff04, "new-array/jumbo", ReferenceType.type, Format.Format52c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), SGET_JUMBO((short)0xff14, "sget/jumbo", ReferenceType.field, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER), SGET_WIDE_JUMBO((short)0xff15, "sget-wide/jumbo", ReferenceType.field, Format.Format41c, Opcode.CAN_THROW | Opcode.CAN_CONTINUE | Opcode.SETS_REGISTER | Opcode.SETS_WIDE_REGISTER), diff --git a/smali-integration-tests/src/test/smali/jumbo-type-tests/Assert.smali b/smali-integration-tests/src/test/smali/jumbo-type-tests/Assert.smali new file mode 100644 index 00000000..9d2ae5e0 --- /dev/null +++ b/smali-integration-tests/src/test/smali/jumbo-type-tests/Assert.smali @@ -0,0 +1,41 @@ +.class public LAssert; +.super Ljava/lang/Object; +.source "Assert.smali" + +#junit's Assert doesn't have an AssertEquals method for ints, only longs +.method public static assertEquals(II)V + .registers 4 + + int-to-long v0, p1 + int-to-long p0, p0 + + invoke-static {v0, v1, p0, p1}, Lorg/junit/Assert;->assertEquals(JJ)V + return-void +.end method + +#junit's Assert doesn't have an AssertEquals method for floats, only doubles +.method public static assertEquals(FF)V + .registers 6 + + float-to-double v0, p0 + float-to-double v2, p1 + + const-wide v4, .00001 + + invoke-static/range {v0..v5}, Lorg/junit/Assert;->assertEquals(DDD)V + return-void +.end method + +#convenience method that supplies a default "Delta" argument +.method public static assertEquals(DD)V + .registers 6 + + move-wide v0, p0 + move-wide v2, p2 + + const-wide v4, .00001 + + invoke-static/range {v0..v5}, Lorg/junit/Assert;->assertEquals(DDD)V + + return-void +.end method \ No newline at end of file diff --git a/smali-integration-tests/src/test/smali/jumbo-type-tests/Format52c.smali b/smali-integration-tests/src/test/smali/jumbo-type-tests/Format52c.smali new file mode 100644 index 00000000..b407cd3f --- /dev/null +++ b/smali-integration-tests/src/test/smali/jumbo-type-tests/Format52c.smali @@ -0,0 +1,98 @@ +#Copyright 2011, Google Inc. +#All rights reserved. +# +#Redistribution and use in source and binary forms, with or without +#modification, are permitted provided that the following conditions are +#met: +# +# * Redistributions of source code must retain the above copyright +#notice, this list of conditions and the following disclaimer. +# * 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. +# * Neither the name of Google Inc. nor the names of its +#contributors may be used to endorse or promote products derived from +#this software without specific prior written permission. +# +#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +#"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 COPYRIGHT +#OWNER OR CONTRIBUTORS 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 + +.class public LFormat52c; +.super Ljava/lang/Object; +.source "Format52c.smali" + +.method public constructor ()V + .registers 1 + invoke-direct {p0}, Ljava/lang/Object;->()V + return-void +.end method + +.method public test-instance-of-jumbo-success()V + .registers 258 + .annotation runtime Lorg/junit/Test; + .end annotation + + const-string v0, "test" + + new-instance v1, LStringWrapper; + invoke-direct {v1, v0}, LStringWrapper;->(Ljava/lang/String;)V + + move-object/16 v256, v1 + + instance-of/jumbo v257, v256, Ljava/lang/Object; + + const v0, 1 + move/16 v256, v0 + + invoke-static/range {v256 .. v257}, LAssert;->assertEquals(II)V + return-void +.end method + +.method public test-instance-of-jumbo-failure()V + .registers 258 + .annotation runtime Lorg/junit/Test; + .end annotation + + const-string v0, "test" + + new-instance v1, LStringWrapper; + invoke-direct {v1, v0}, LStringWrapper;->(Ljava/lang/String;)V + + move-object/16 v256, v1 + + instance-of/jumbo v257, v256, Lzzz99999; + + const v0, 0 + move/16 v256, v0 + + invoke-static/range {v256 .. v257}, LAssert;->assertEquals(II)V + return-void +.end method + +.method public test-new-array-jumbo()V + .registers 258 + .annotation runtime Lorg/junit/Test; + .end annotation + + const v0, 1 + move/16 v256, v0 + + new-array/jumbo v257, v256, [Lzzz99999; + + move-object/16 v1, v257 + + array-length v2, v1 + + invoke-static {v0, v2}, LAssert;->assertEquals(II)V + return-void +.end method \ No newline at end of file diff --git a/smali-integration-tests/src/test/smali/jumbo-type-tests/TestSuite.smali b/smali-integration-tests/src/test/smali/jumbo-type-tests/TestSuite.smali index c6e53500..001e18f6 100644 --- a/smali-integration-tests/src/test/smali/jumbo-type-tests/TestSuite.smali +++ b/smali-integration-tests/src/test/smali/jumbo-type-tests/TestSuite.smali @@ -35,5 +35,7 @@ .end annotation .annotation runtime Lorg/junit/runners/Suite$SuiteClasses; - value = { LFormat41c; } + value = { LFormat41c;, + LFormat52c; + } .end annotation \ No newline at end of file diff --git a/smali/src/main/antlr3/org/jf/smali/smaliLexer.g b/smali/src/main/antlr3/org/jf/smali/smaliLexer.g index d4484621..ce1a6237 100644 --- a/smali/src/main/antlr3/org/jf/smali/smaliLexer.g +++ b/smali/src/main/antlr3/org/jf/smali/smaliLexer.g @@ -714,6 +714,10 @@ INSTRUCTION_FORMAT41c_FIELD INSTRUCTION_FORMAT51l : 'const-wide'; +INSTRUCTION_FORMAT52c_TYPE + : 'instance-of/jumbo' + | 'new-array/jumbo'; + /********************************************************** * Types diff --git a/smali/src/main/antlr3/org/jf/smali/smaliParser.g b/smali/src/main/antlr3/org/jf/smali/smaliParser.g index 318ac14f..8b22556f 100644 --- a/smali/src/main/antlr3/org/jf/smali/smaliParser.g +++ b/smali/src/main/antlr3/org/jf/smali/smaliParser.g @@ -120,6 +120,7 @@ tokens { I_STATEMENT_FORMAT41c_TYPE; I_STATEMENT_FORMAT41c_FIELD; I_STATEMENT_FORMAT51l; + I_STATEMENT_FORMAT52c_TYPE; I_STATEMENT_ARRAY_DATA; I_STATEMENT_PACKED_SWITCH; I_STATEMENT_SPARSE_SWITCH; @@ -845,6 +846,9 @@ instruction returns [int size] | //e.g. const-wide v0, 5000000000L INSTRUCTION_FORMAT51l REGISTER COMMA fixed_literal {$size = Format.Format51l.size;} -> ^(I_STATEMENT_FORMAT51l[$start, "I_STATEMENT_FORMAT51l"] INSTRUCTION_FORMAT51l REGISTER fixed_literal) + | //e.g. instance-of/jumbo v0, v1, Ljava/lang/String; + INSTRUCTION_FORMAT52c_TYPE REGISTER COMMA REGISTER COMMA nonvoid_type_descriptor {$size = Format.Format52c.size;} + -> ^(I_STATEMENT_FORMAT52c_TYPE[$start, "I_STATEMENT_FORMAT52c_TYPE"] INSTRUCTION_FORMAT52c_TYPE REGISTER REGISTER nonvoid_type_descriptor) | ARRAY_DATA_DIRECTIVE { diff --git a/smali/src/main/antlr3/org/jf/smali/smaliTreeWalker.g b/smali/src/main/antlr3/org/jf/smali/smaliTreeWalker.g index 8055c499..f4ffefa0 100644 --- a/smali/src/main/antlr3/org/jf/smali/smaliTreeWalker.g +++ b/smali/src/main/antlr3/org/jf/smali/smaliTreeWalker.g @@ -1279,6 +1279,17 @@ instruction[int totalMethodRegisters, int methodParameterRegisters, List