From fa07a1972e3cff56d5615c18a8797ff58fc9f739 Mon Sep 17 00:00:00 2001 From: "JesusFreke@JesusFreke.com" Date: Thu, 18 Jun 2009 06:52:02 +0000 Subject: [PATCH] Implemented class and method annotations git-svn-id: https://smali.googlecode.com/svn/trunk@166 55b6fa8a-2a1e-11de-a435-ffa8d773f76a --- .../baksmali/Adaptors/AnnotationAdaptor.java | 65 +++++++++++++++++++ .../jf/baksmali/Adaptors/ClassDefinition.java | 53 ++++++++++++--- .../baksmali/Adaptors/MethodDefinition.java | 21 ++++-- .../src/main/resources/templates/baksmali.stg | 35 ++++++++-- .../src/test/smali/baksmali_test_class.smali | 29 +++++++++ .../jf/dexlib/AnnotationDirectoryItem.java | 16 +++++ .../java/org/jf/dexlib/AnnotationItem.java | 8 +++ .../java/org/jf/dexlib/AnnotationSetItem.java | 9 +++ .../main/java/org/jf/dexlib/ClassDefItem.java | 4 ++ 9 files changed, 223 insertions(+), 17 deletions(-) create mode 100644 baksmali/src/main/java/org/jf/baksmali/Adaptors/AnnotationAdaptor.java diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/AnnotationAdaptor.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/AnnotationAdaptor.java new file mode 100644 index 00000000..96e29270 --- /dev/null +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/AnnotationAdaptor.java @@ -0,0 +1,65 @@ +/* + * [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.baksmali.Adaptors; + +import org.jf.dexlib.AnnotationItem; +import org.jf.baksmali.Adaptors.EncodedValue.AnnotationEncodedValueAdaptor; +import org.jf.baksmali.Adaptors.Reference.TypeReference; + +import java.util.List; + +public class AnnotationAdaptor { + private AnnotationItem annotationItem; + private AnnotationEncodedValueAdaptor encodedAnnotationAdaptor; + + public AnnotationAdaptor(AnnotationItem annotationItem) { + this.annotationItem = annotationItem; + this.encodedAnnotationAdaptor = new AnnotationEncodedValueAdaptor(annotationItem.getEncodedAnnotation()); + } + + public String getVisibility() { + switch (annotationItem.getVisibility()) { + case 0: + return "build"; + case 1: + return "runtime"; + case 2: + return "system"; + } + return null; + } + + public TypeReference getAnnotationType() { + return encodedAnnotationAdaptor.getAnnotationType(); + } + + public List getElements() { + return encodedAnnotationAdaptor.getElements(); + } +} diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/ClassDefinition.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/ClassDefinition.java index a194ea3f..b874c088 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/ClassDefinition.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/ClassDefinition.java @@ -28,23 +28,37 @@ package org.jf.baksmali.Adaptors; -import org.jf.dexlib.ClassDataItem; -import org.jf.dexlib.ClassDefItem; -import org.jf.dexlib.EncodedArrayItem; import org.jf.dexlib.EncodedValue.EncodedValue; -import org.jf.dexlib.TypeIdItem; +import org.jf.dexlib.*; import org.jf.dexlib.util.AccessFlags; -import java.util.ArrayList; -import java.util.List; +import java.util.*; public class ClassDefinition { private ClassDefItem classDefItem; private ClassDataItem classDataItem; - + + private HashMap methodAnnotations = new HashMap(); + public ClassDefinition(ClassDefItem classDefItem) { this.classDefItem = classDefItem; this.classDataItem = classDefItem.getClassData(); + buildAnnotationMaps(); + } + + private void buildAnnotationMaps() { + AnnotationDirectoryItem annotationDirectory = classDefItem.getAnnotationDirectory(); + if (annotationDirectory == null) { + return; + } + + List methodAnnotationList = annotationDirectory.getMethodAnnotations(); + + if (methodAnnotations != null) { + for (AnnotationDirectoryItem.MethodAnnotation methodAnnotation: methodAnnotationList) { + methodAnnotations.put(methodAnnotation.getMethod().getIndex(), methodAnnotation.getAnnotationSet()); + } + } } private List accessFlags = null; @@ -142,7 +156,8 @@ public class ClassDefinition { if (classDataItem != null) { for (ClassDataItem.EncodedMethod method: classDataItem.getDirectMethods()) { - directMethods.add(new MethodDefinition(method)); + AnnotationSetItem annotationSet = methodAnnotations.get(method.getMethod().getIndex()); + directMethods.add(new MethodDefinition(method, annotationSet)); } } } @@ -156,10 +171,30 @@ public class ClassDefinition { if (classDataItem != null) { for (ClassDataItem.EncodedMethod method: classDataItem.getVirtualMethods()) { - virtualMethods.add(new MethodDefinition(method)); + AnnotationSetItem annotationSet = methodAnnotations.get(method.getMethod().getIndex()); + virtualMethods.add(new MethodDefinition(method, annotationSet)); } } } return virtualMethods; } + + public List getAnnotations() { + AnnotationDirectoryItem annotationDirectory = classDefItem.getAnnotationDirectory(); + if (annotationDirectory == null) { + return null; + } + + AnnotationSetItem annotationSet = annotationDirectory.getClassAnnotations(); + if (annotationSet == null) { + return null; + } + + List annotationAdaptors = new ArrayList(); + + for (AnnotationItem annotationItem: annotationSet.getAnnotationItems()) { + annotationAdaptors.add(new AnnotationAdaptor(annotationItem)); + } + return annotationAdaptors; + } } diff --git a/baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java b/baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java index 6dee5807..950b374e 100644 --- a/baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java +++ b/baksmali/src/main/java/org/jf/baksmali/Adaptors/MethodDefinition.java @@ -29,9 +29,7 @@ package org.jf.baksmali.Adaptors; import org.jf.baksmali.Adaptors.Format.*; -import org.jf.dexlib.ClassDataItem; -import org.jf.dexlib.CodeItem; -import org.jf.dexlib.MethodIdItem; +import org.jf.dexlib.*; import org.jf.dexlib.code.Format.*; import org.jf.dexlib.code.Instruction; import org.jf.dexlib.code.InstructionField; @@ -44,11 +42,13 @@ public class MethodDefinition { private ClassDataItem.EncodedMethod encodedMethod; private MethodIdItem methodIdItem; private CodeItem codeItem; + private AnnotationSetItem annotationSet; - public MethodDefinition(ClassDataItem.EncodedMethod encodedMethod) { + public MethodDefinition(ClassDataItem.EncodedMethod encodedMethod, AnnotationSetItem annotationSet) { this.encodedMethod = encodedMethod; this.methodIdItem = encodedMethod.getMethod(); this.codeItem = encodedMethod.getCodeItem(); + this.annotationSet = annotationSet; } private String methodName = null; @@ -99,6 +99,19 @@ public class MethodDefinition { return registerCount; } + public List getAnnotations() { + if (annotationSet == null) { + return null; + } + + List annotationAdaptors = new ArrayList(); + + for (AnnotationItem annotationItem: annotationSet.getAnnotationItems()) { + annotationAdaptors.add(new AnnotationAdaptor(annotationItem)); + } + return annotationAdaptors; + } + private List methodItems = null; public List getMethodItems() { diff --git a/baksmali/src/main/resources/templates/baksmali.stg b/baksmali/src/main/resources/templates/baksmali.stg index c254e981..8997f931 100644 --- a/baksmali/src/main/resources/templates/baksmali.stg +++ b/baksmali/src/main/resources/templates/baksmali.stg @@ -9,6 +9,13 @@ smaliFile(classDef) ::= # interfaces + + + + +# annotations + + @@ -49,6 +56,19 @@ implement(interface) ::= >> +annotation(annotationAdaptor) ::= +<< +.annotation + + + + + + + +.end annotation +>> + field(fieldDef) ::= @@ -60,12 +80,19 @@ field(fieldDef) ::= method(methodDef) ::= << .method - + .registers + + + - - + .end method + + +.end method + + >> MethodItem(MethodItem) ::= @@ -291,7 +318,7 @@ EnumEncodedValue(EncodedValue) ::= AnnotationEncodedValue(EncodedValue) ::= << -.subannotation EncodedValue.Type +.subannotation .end subannotation >> diff --git a/baksmali/src/test/smali/baksmali_test_class.smali b/baksmali/src/test/smali/baksmali_test_class.smali index 141c3f88..b8cefc83 100644 --- a/baksmali/src/test/smali/baksmali_test_class.smali +++ b/baksmali/src/test/smali/baksmali_test_class.smali @@ -5,6 +5,19 @@ .implements Lsome/other/interface; +.annotation build Lsome/annotation; + value1 = "test" + value2 = .subannotation Lsome/annotation; + value1 = "test2" + value2 = Lsome/enum; + .end subannotation +.end annotation + +.annotation system Lsome/annotation; +.end annotation + + + .field public static aStaticFieldWithoutAnInitializer:I .field public static longStaticField:J = 0x300000000L @@ -63,6 +76,12 @@ .method public testMethod(ILjava/lang/String;)Ljava/lang/String; .registers 3 + .annotation runtime Lorg/junit/Test; + .end annotation + .annotation system Lyet/another/annotation; + somevalue = 1234 + anothervalue = 3.14159 + .end annotation const-string v0, "testing\n123" @@ -96,3 +115,13 @@ .end method +.method public abstract testMethod2()V + .annotation runtime Lsome/annotation; + subannotation = .subannotation Lsome/other/annotation; + value = "value" + .end subannotation + .end annotation + .annotation runtime Lorg/junit/Test; + .end annotation +.end method + diff --git a/dexlib/src/main/java/org/jf/dexlib/AnnotationDirectoryItem.java b/dexlib/src/main/java/org/jf/dexlib/AnnotationDirectoryItem.java index 0babb61e..47076fc3 100644 --- a/dexlib/src/main/java/org/jf/dexlib/AnnotationDirectoryItem.java +++ b/dexlib/src/main/java/org/jf/dexlib/AnnotationDirectoryItem.java @@ -119,6 +119,14 @@ public class AnnotationDirectoryItem extends OffsettedItem getMethodAnnotations() { + return methodAnnotationList; + } + public static class FieldAnnotation extends CompositeField implements Comparable { private final IndexedItemReference fieldReferenceField; @@ -170,6 +178,14 @@ public class AnnotationDirectoryItem extends OffsettedItem diff --git a/dexlib/src/main/java/org/jf/dexlib/AnnotationItem.java b/dexlib/src/main/java/org/jf/dexlib/AnnotationItem.java index d8930c83..3280aac8 100644 --- a/dexlib/src/main/java/org/jf/dexlib/AnnotationItem.java +++ b/dexlib/src/main/java/org/jf/dexlib/AnnotationItem.java @@ -60,4 +60,12 @@ public class AnnotationItem extends OffsettedItem { public String getConciseIdentity() { return "annotation_item @0x" + Integer.toHexString(getOffset()); } + + public byte getVisibility() { + return (byte)visibilityField.getCachedValue(); + } + + public AnnotationEncodedValueSubField getEncodedAnnotation() { + return annotationField; + } } diff --git a/dexlib/src/main/java/org/jf/dexlib/AnnotationSetItem.java b/dexlib/src/main/java/org/jf/dexlib/AnnotationSetItem.java index 1b28fcce..97db1abf 100644 --- a/dexlib/src/main/java/org/jf/dexlib/AnnotationSetItem.java +++ b/dexlib/src/main/java/org/jf/dexlib/AnnotationSetItem.java @@ -74,4 +74,13 @@ public class AnnotationSetItem extends OffsettedItem { public String getConciseIdentity() { return "annotation_set_item @0x" + Integer.toHexString(getOffset()); } + + public List getAnnotationItems() { + List annotationItems = new ArrayList(); + + for (OffsettedItemReference annotationItemReference: annotationReferences) { + annotationItems.add(annotationItemReference.getReference()); + } + return annotationItems; + } } diff --git a/dexlib/src/main/java/org/jf/dexlib/ClassDefItem.java b/dexlib/src/main/java/org/jf/dexlib/ClassDefItem.java index 5ce76eec..8a072529 100644 --- a/dexlib/src/main/java/org/jf/dexlib/ClassDefItem.java +++ b/dexlib/src/main/java/org/jf/dexlib/ClassDefItem.java @@ -129,6 +129,10 @@ public class ClassDefItem extends IndexedItem { return classDataReferenceField.getReference(); } + public AnnotationDirectoryItem getAnnotationDirectory() { + return classAnnotationsReferenceField.getReference(); + } + public String getConciseIdentity() { return "class_def_item: " + getClassName(); }