ClassDefinition.java revision 00fc68adf2e39aeb9fed35293f2576bbe729ec4b
1dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines/* 2dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * [The "BSD licence"] 3dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * Copyright (c) 2010 Ben Gruver (JesusFreke) 4dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * All rights reserved. 5dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * 6dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * Redistribution and use in source and binary forms, with or without 7dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * modification, are permitted provided that the following conditions 8dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * are met: 9dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * 1. Redistributions of source code must retain the above copyright 10dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * notice, this list of conditions and the following disclaimer. 11dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * 2. Redistributions in binary form must reproduce the above copyright 12dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * notice, this list of conditions and the following disclaimer in the 13dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * documentation and/or other materials provided with the distribution. 14dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * 3. The name of the author may not be used to endorse or promote products 15dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * derived from this software without specific prior written permission. 16dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * 17dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines */ 28dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines 29dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hinespackage org.jf.baksmali.Adaptors; 30dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines 31dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hinesimport org.jf.dexlib.Code.Analysis.ValidationException; 32dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hinesimport org.jf.dexlib.EncodedValue.EncodedValue; 33dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hinesimport org.jf.dexlib.*; 34dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hinesimport org.jf.dexlib.Code.Instruction; 35dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hinesimport org.jf.dexlib.Code.Format.Instruction21c; 36dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hinesimport org.jf.dexlib.Util.AccessFlags; 37dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hinesimport org.jf.dexlib.Util.SparseArray; 38dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hinesimport org.antlr.stringtemplate.StringTemplate; 39dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hinesimport org.antlr.stringtemplate.StringTemplateGroup; 40dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines 41dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hinesimport java.util.*; 42dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines 43dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hinespublic class ClassDefinition { 44dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines private StringTemplateGroup stg; 45dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines private ClassDefItem classDefItem; 46dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines private ClassDataItem classDataItem; 47dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines 48dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines private SparseArray<AnnotationSetItem> methodAnnotationsMap; 49dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines private SparseArray<AnnotationSetItem> fieldAnnotationsMap; 50dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines private SparseArray<AnnotationSetRefList> parameterAnnotationsMap; 51dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines 52dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines private SparseArray<FieldIdItem> fieldsSetInStaticConstructor; 53dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines 54dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines protected boolean validationErrors; 55dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines 56dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines public ClassDefinition(StringTemplateGroup stg, ClassDefItem classDefItem) { 57dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines this.stg = stg; 58dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines this.classDefItem = classDefItem; 59dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines this.classDataItem = classDefItem.getClassData(); 60dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines buildAnnotationMaps(); 61dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines findFieldsSetInStaticConstructor(); 62dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines } 63dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines 64dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines public StringTemplate createTemplate() { 65dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines StringTemplate template = stg.getInstanceOf("smaliFile"); 66dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines 67dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines template.setAttribute("AccessFlags", getAccessFlags()); 68dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines template.setAttribute("ClassType", classDefItem.getClassType().getTypeDescriptor()); 69dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines template.setAttribute("SuperType", getSuperType()); 70dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines template.setAttribute("SourceFile", getSourceFile()); 71dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines template.setAttribute("Interfaces", getInterfaces()); 72dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines template.setAttribute("Annotations", getAnnotations()); 73dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines template.setAttribute("StaticFields", getStaticFields()); 74dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines template.setAttribute("InstanceFields", getInstanceFields()); 75 template.setAttribute("DirectMethods", getDirectMethods()); 76 template.setAttribute("VirtualMethods", getVirtualMethods()); 77 78 return template; 79 } 80 81 public boolean hadValidationErrors() { 82 return validationErrors; 83 } 84 85 private void buildAnnotationMaps() { 86 AnnotationDirectoryItem annotationDirectory = classDefItem.getAnnotations(); 87 if (annotationDirectory == null) { 88 methodAnnotationsMap = new SparseArray<AnnotationSetItem>(0); 89 fieldAnnotationsMap = new SparseArray<AnnotationSetItem>(0); 90 parameterAnnotationsMap = new SparseArray<AnnotationSetRefList>(0); 91 return; 92 } 93 94 methodAnnotationsMap = new SparseArray<AnnotationSetItem>(annotationDirectory.getMethodAnnotationCount()); 95 annotationDirectory.iterateMethodAnnotations(new AnnotationDirectoryItem.MethodAnnotationIteratorDelegate() { 96 public void processMethodAnnotations(MethodIdItem method, AnnotationSetItem methodAnnotations) { 97 methodAnnotationsMap.put(method.getIndex(), methodAnnotations); 98 } 99 }); 100 101 fieldAnnotationsMap = new SparseArray<AnnotationSetItem>(annotationDirectory.getFieldAnnotationCount()); 102 annotationDirectory.iterateFieldAnnotations(new AnnotationDirectoryItem.FieldAnnotationIteratorDelegate() { 103 public void processFieldAnnotations(FieldIdItem field, AnnotationSetItem fieldAnnotations) { 104 fieldAnnotationsMap.put(field.getIndex(), fieldAnnotations); 105 } 106 }); 107 108 parameterAnnotationsMap = new SparseArray<AnnotationSetRefList>( 109 annotationDirectory.getParameterAnnotationCount()); 110 annotationDirectory.iterateParameterAnnotations( 111 new AnnotationDirectoryItem.ParameterAnnotationIteratorDelegate() { 112 public void processParameterAnnotations(MethodIdItem method, AnnotationSetRefList parameterAnnotations) { 113 parameterAnnotationsMap.put(method.getIndex(), parameterAnnotations); 114 } 115 }); 116 } 117 118 private void findFieldsSetInStaticConstructor() { 119 fieldsSetInStaticConstructor = new SparseArray<FieldIdItem>(); 120 121 if (classDataItem == null) { 122 return; 123 } 124 125 for (ClassDataItem.EncodedMethod directMethod: classDataItem.getDirectMethods()) { 126 if (directMethod.method.getMethodName().getStringValue().equals("<clinit>")) { 127 128 for (Instruction instruction: directMethod.codeItem.getInstructions()) { 129 switch (instruction.opcode) { 130 case SPUT: 131 case SPUT_BOOLEAN: 132 case SPUT_BYTE: 133 case SPUT_CHAR: 134 case SPUT_OBJECT: 135 case SPUT_SHORT: 136 case SPUT_WIDE: 137 Instruction21c ins = (Instruction21c)instruction; 138 FieldIdItem fieldIdItem = (FieldIdItem)ins.getReferencedItem(); 139 fieldsSetInStaticConstructor.put(fieldIdItem.getIndex(), fieldIdItem); 140 } 141 } 142 } 143 } 144 } 145 146 private List<String> getAccessFlags() { 147 List<String> accessFlags = new ArrayList<String>(); 148 149 for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForClass(classDefItem.getAccessFlags())) { 150 accessFlags.add(accessFlag.toString()); 151 } 152 153 return accessFlags; 154 } 155 156 157 private String getSuperType() { 158 TypeIdItem superClass = classDefItem.getSuperclass(); 159 if (superClass != null) { 160 return superClass.getTypeDescriptor(); 161 } 162 return null; 163 } 164 165 private String getSourceFile() { 166 StringIdItem sourceFile = classDefItem.getSourceFile(); 167 168 if (sourceFile == null) { 169 return null; 170 } 171 return classDefItem.getSourceFile().getStringValue(); 172 } 173 174 private List<String> getInterfaces() { 175 List<String> interfaces = new ArrayList<String>(); 176 177 TypeListItem interfaceList = classDefItem.getInterfaces(); 178 179 if (interfaceList != null) { 180 for (TypeIdItem typeIdItem: interfaceList.getTypes()) { 181 interfaces.add(typeIdItem.getTypeDescriptor()); 182 } 183 } 184 185 return interfaces; 186 } 187 188 private List<StringTemplate> getAnnotations() { 189 AnnotationDirectoryItem annotationDirectory = classDefItem.getAnnotations(); 190 if (annotationDirectory == null) { 191 return null; 192 } 193 194 AnnotationSetItem annotationSet = annotationDirectory.getClassAnnotations(); 195 if (annotationSet == null) { 196 return null; 197 } 198 199 List<StringTemplate> annotations = new ArrayList<StringTemplate>(); 200 201 for (AnnotationItem annotationItem: annotationSet.getAnnotations()) { 202 annotations.add(AnnotationAdaptor.createTemplate(stg, annotationItem)); 203 } 204 return annotations; 205 } 206 207 private List<StringTemplate> getStaticFields() { 208 List<StringTemplate> staticFields = new ArrayList<StringTemplate>(); 209 210 if (classDataItem != null) { 211 //if classDataItem is not null, then classDefItem won't be null either 212 assert(classDefItem != null); 213 EncodedArrayItem encodedStaticInitializers = classDefItem.getStaticFieldInitializers(); 214 215 EncodedValue[] staticInitializers; 216 if (encodedStaticInitializers != null) { 217 staticInitializers = encodedStaticInitializers.getEncodedArray().values; 218 } else { 219 staticInitializers = new EncodedValue[0]; 220 } 221 222 int i=0; 223 for (ClassDataItem.EncodedField field: classDataItem.getStaticFields()) { 224 EncodedValue encodedValue = null; 225 if (i < staticInitializers.length) { 226 encodedValue = staticInitializers[i]; 227 } 228 AnnotationSetItem annotationSet = fieldAnnotationsMap.get(field.field.getIndex()); 229 230 boolean setInStaticConstructor = 231 fieldsSetInStaticConstructor.get(field.field.getIndex()) != null; 232 233 staticFields.add(FieldDefinition.createTemplate(stg, field, encodedValue, annotationSet, 234 setInStaticConstructor)); 235 i++; 236 } 237 } 238 return staticFields; 239 } 240 241 private List<StringTemplate> getInstanceFields() { 242 List<StringTemplate> instanceFields = new ArrayList<StringTemplate>(); 243 244 if (classDataItem != null) { 245 for (ClassDataItem.EncodedField field: classDataItem.getInstanceFields()) { 246 AnnotationSetItem annotationSet = fieldAnnotationsMap.get(field.field.getIndex()); 247 instanceFields.add(FieldDefinition.createTemplate(stg, field, annotationSet)); 248 } 249 } 250 251 return instanceFields; 252 } 253 254 private List<StringTemplate> getDirectMethods() { 255 if (classDataItem == null) { 256 return null; 257 } 258 259 return getTemplatesForMethods(classDataItem.getDirectMethods()); 260 } 261 262 private List<StringTemplate> getVirtualMethods() { 263 if (classDataItem == null) { 264 return null; 265 } 266 267 return getTemplatesForMethods(classDataItem.getVirtualMethods()); 268 } 269 270 private List<StringTemplate> getTemplatesForMethods(ClassDataItem.EncodedMethod[] methods) { 271 List<StringTemplate> methodTemplates = new ArrayList<StringTemplate>(); 272 273 for (ClassDataItem.EncodedMethod method: methods) { 274 AnnotationSetItem annotationSet = methodAnnotationsMap.get(method.method.getIndex()); 275 AnnotationSetRefList parameterAnnotationList = parameterAnnotationsMap.get(method.method.getIndex()); 276 277 MethodDefinition methodDefinition = new MethodDefinition(stg, method); 278 279 methodTemplates.add(methodDefinition.createTemplate(annotationSet, parameterAnnotationList)); 280 281 ValidationException validationException = methodDefinition.getValidationException(); 282 if (validationException != null) { 283 //System.err.println(validationException.toString()); 284 validationException.printStackTrace(System.err); 285 this.validationErrors = true; 286 } 287 } 288 289 return methodTemplates; 290 } 291} 292