ClassDefinition.java revision d863324ffb94f70dbb59f1dab4dabd2ce1b39cfd
1/* 2 * [The "BSD licence"] 3 * Copyright (c) 2010 Ben Gruver (JesusFreke) 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29package org.jf.baksmali.Adaptors; 30 31import org.jf.dexlib.Util.Utf8Utils; 32import org.jf.util.IndentingWriter; 33import org.jf.dexlib.*; 34import org.jf.dexlib.Code.Analysis.ValidationException; 35import org.jf.dexlib.Code.Format.Instruction21c; 36import org.jf.dexlib.Code.Format.Instruction41c; 37import org.jf.dexlib.Code.Instruction; 38import org.jf.dexlib.EncodedValue.EncodedValue; 39import org.jf.dexlib.Util.AccessFlags; 40import org.jf.dexlib.Util.SparseArray; 41 42import java.io.IOException; 43import java.util.List; 44 45public class ClassDefinition { 46 private ClassDefItem classDefItem; 47 private ClassDataItem classDataItem; 48 49 private SparseArray<AnnotationSetItem> methodAnnotationsMap; 50 private SparseArray<AnnotationSetItem> fieldAnnotationsMap; 51 private SparseArray<AnnotationSetRefList> parameterAnnotationsMap; 52 53 private SparseArray<FieldIdItem> fieldsSetInStaticConstructor; 54 55 protected boolean validationErrors; 56 57 public ClassDefinition(ClassDefItem classDefItem) { 58 this.classDefItem = classDefItem; 59 this.classDataItem = classDefItem.getClassData(); 60 buildAnnotationMaps(); 61 findFieldsSetInStaticConstructor(); 62 } 63 64 public boolean hadValidationErrors() { 65 return validationErrors; 66 } 67 68 private void buildAnnotationMaps() { 69 AnnotationDirectoryItem annotationDirectory = classDefItem.getAnnotations(); 70 if (annotationDirectory == null) { 71 methodAnnotationsMap = new SparseArray<AnnotationSetItem>(0); 72 fieldAnnotationsMap = new SparseArray<AnnotationSetItem>(0); 73 parameterAnnotationsMap = new SparseArray<AnnotationSetRefList>(0); 74 return; 75 } 76 77 methodAnnotationsMap = new SparseArray<AnnotationSetItem>(annotationDirectory.getMethodAnnotationCount()); 78 annotationDirectory.iterateMethodAnnotations(new AnnotationDirectoryItem.MethodAnnotationIteratorDelegate() { 79 public void processMethodAnnotations(MethodIdItem method, AnnotationSetItem methodAnnotations) { 80 methodAnnotationsMap.put(method.getIndex(), methodAnnotations); 81 } 82 }); 83 84 fieldAnnotationsMap = new SparseArray<AnnotationSetItem>(annotationDirectory.getFieldAnnotationCount()); 85 annotationDirectory.iterateFieldAnnotations(new AnnotationDirectoryItem.FieldAnnotationIteratorDelegate() { 86 public void processFieldAnnotations(FieldIdItem field, AnnotationSetItem fieldAnnotations) { 87 fieldAnnotationsMap.put(field.getIndex(), fieldAnnotations); 88 } 89 }); 90 91 parameterAnnotationsMap = new SparseArray<AnnotationSetRefList>( 92 annotationDirectory.getParameterAnnotationCount()); 93 annotationDirectory.iterateParameterAnnotations( 94 new AnnotationDirectoryItem.ParameterAnnotationIteratorDelegate() { 95 public void processParameterAnnotations(MethodIdItem method, AnnotationSetRefList parameterAnnotations) { 96 parameterAnnotationsMap.put(method.getIndex(), parameterAnnotations); 97 } 98 }); 99 } 100 101 private void findFieldsSetInStaticConstructor() { 102 fieldsSetInStaticConstructor = new SparseArray<FieldIdItem>(); 103 104 if (classDataItem == null) { 105 return; 106 } 107 108 for (ClassDataItem.EncodedMethod directMethod: classDataItem.getDirectMethods()) { 109 if (directMethod.method.getMethodName().getStringValue().equals("<clinit>") && 110 directMethod.codeItem != null) { 111 for (Instruction instruction: directMethod.codeItem.getInstructions()) { 112 switch (instruction.opcode) { 113 case SPUT: 114 case SPUT_BOOLEAN: 115 case SPUT_BYTE: 116 case SPUT_CHAR: 117 case SPUT_OBJECT: 118 case SPUT_SHORT: 119 case SPUT_WIDE: { 120 Instruction21c ins = (Instruction21c)instruction; 121 FieldIdItem fieldIdItem = (FieldIdItem)ins.getReferencedItem(); 122 fieldsSetInStaticConstructor.put(fieldIdItem.getIndex(), fieldIdItem); 123 break; 124 } 125 case SPUT_JUMBO: 126 case SPUT_BOOLEAN_JUMBO: 127 case SPUT_BYTE_JUMBO: 128 case SPUT_CHAR_JUMBO: 129 case SPUT_OBJECT_JUMBO: 130 case SPUT_SHORT_JUMBO: 131 case SPUT_WIDE_JUMBO: { 132 Instruction41c ins = (Instruction41c)instruction; 133 FieldIdItem fieldIdItem = (FieldIdItem)ins.getReferencedItem(); 134 fieldsSetInStaticConstructor.put(fieldIdItem.getIndex(), fieldIdItem); 135 break; 136 } 137 } 138 } 139 } 140 } 141 } 142 143 public void writeTo(IndentingWriter writer) throws IOException { 144 writeClass(writer); 145 writeSuper(writer); 146 writeSourceFile(writer); 147 writeInterfaces(writer); 148 writeAnnotations(writer); 149 writeStaticFields(writer); 150 writeInstanceFields(writer); 151 writeDirectMethods(writer); 152 writeVirtualMethods(writer); 153 return ; 154 } 155 156 private void writeClass(IndentingWriter writer) throws IOException { 157 writer.write(".class "); 158 writeAccessFlags(writer); 159 writer.write(classDefItem.getClassType().getTypeDescriptor()); 160 writer.write('\n'); 161 } 162 163 private void writeAccessFlags(IndentingWriter writer) throws IOException { 164 for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForClass(classDefItem.getAccessFlags())) { 165 writer.write(accessFlag.toString()); 166 writer.write(' '); 167 } 168 } 169 170 private void writeSuper(IndentingWriter writer) throws IOException { 171 TypeIdItem superClass = classDefItem.getSuperclass(); 172 if (superClass != null) { 173 writer.write(".super "); 174 writer.write(superClass.getTypeDescriptor()); 175 writer.write('\n'); 176 } 177 } 178 179 private void writeSourceFile(IndentingWriter writer) throws IOException { 180 StringIdItem sourceFile = classDefItem.getSourceFile(); 181 if (sourceFile != null) { 182 writer.write(".source \""); 183 Utf8Utils.writeEscapedString(writer, sourceFile.getStringValue()); 184 writer.write("\"\n"); 185 } 186 } 187 188 private void writeInterfaces(IndentingWriter writer) throws IOException { 189 TypeListItem interfaceList = classDefItem.getInterfaces(); 190 if (interfaceList == null) { 191 return; 192 } 193 194 List<TypeIdItem> interfaces = interfaceList.getTypes(); 195 if (interfaces == null || interfaces.size() == 0) { 196 return; 197 } 198 199 writer.write('\n'); 200 writer.write("# interfaces\n"); 201 for (TypeIdItem typeIdItem: interfaceList.getTypes()) { 202 writer.write(".implements "); 203 writer.write(typeIdItem.getTypeDescriptor()); 204 writer.write('\n'); 205 } 206 } 207 208 private void writeAnnotations(IndentingWriter writer) throws IOException { 209 AnnotationDirectoryItem annotationDirectory = classDefItem.getAnnotations(); 210 if (annotationDirectory == null) { 211 return; 212 } 213 214 AnnotationSetItem annotationSet = annotationDirectory.getClassAnnotations(); 215 if (annotationSet == null) { 216 return; 217 } 218 219 writer.write("\n\n"); 220 writer.write("# annotations\n"); 221 AnnotationFormatter.writeTo(writer, annotationSet); 222 } 223 224 private void writeStaticFields(IndentingWriter writer) throws IOException { 225 if (classDataItem == null) { 226 return; 227 } 228 //if classDataItem is not null, then classDefItem won't be null either 229 assert(classDefItem != null); 230 231 EncodedArrayItem encodedStaticInitializers = classDefItem.getStaticFieldInitializers(); 232 233 EncodedValue[] staticInitializers; 234 if (encodedStaticInitializers != null) { 235 staticInitializers = encodedStaticInitializers.getEncodedArray().values; 236 } else { 237 staticInitializers = new EncodedValue[0]; 238 } 239 240 ClassDataItem.EncodedField[] encodedFields = classDataItem.getStaticFields(); 241 if (encodedFields == null || encodedFields.length == 0) { 242 return; 243 } 244 245 writer.write("\n\n"); 246 writer.write("# static fields\n"); 247 248 boolean first = true; 249 for (int i=0; i<encodedFields.length; i++) { 250 if (!first) { 251 writer.write('\n'); 252 } 253 first = false; 254 255 ClassDataItem.EncodedField field = encodedFields[i]; 256 EncodedValue encodedValue = null; 257 if (i < staticInitializers.length) { 258 encodedValue = staticInitializers[i]; 259 } 260 AnnotationSetItem annotationSet = fieldAnnotationsMap.get(field.field.getIndex()); 261 262 boolean setInStaticConstructor = 263 fieldsSetInStaticConstructor.get(field.field.getIndex()) != null; 264 265 FieldDefinition.writeTo(writer, field, encodedValue, annotationSet, setInStaticConstructor); 266 } 267 } 268 269 private void writeInstanceFields(IndentingWriter writer) throws IOException { 270 if (classDataItem == null) { 271 return; 272 } 273 274 ClassDataItem.EncodedField[] encodedFields = classDataItem.getInstanceFields(); 275 if (encodedFields == null || encodedFields.length == 0) { 276 return; 277 } 278 279 writer.write("\n\n"); 280 writer.write("# instance fields\n"); 281 boolean first = true; 282 for (ClassDataItem.EncodedField field: classDataItem.getInstanceFields()) { 283 if (!first) { 284 writer.write('\n'); 285 } 286 first = false; 287 288 AnnotationSetItem annotationSet = fieldAnnotationsMap.get(field.field.getIndex()); 289 290 FieldDefinition.writeTo(writer, field, null, annotationSet, false); 291 } 292 } 293 294 private void writeDirectMethods(IndentingWriter writer) throws IOException { 295 if (classDataItem == null) { 296 return; 297 } 298 299 ClassDataItem.EncodedMethod[] directMethods = classDataItem.getDirectMethods(); 300 301 if (directMethods == null || directMethods.length == 0) { 302 return; 303 } 304 305 writer.write("\n\n"); 306 writer.write("# direct methods\n"); 307 writeMethods(writer, directMethods); 308 } 309 310 private void writeVirtualMethods(IndentingWriter writer) throws IOException { 311 if (classDataItem == null) { 312 return; 313 } 314 315 ClassDataItem.EncodedMethod[] virtualMethods = classDataItem.getVirtualMethods(); 316 317 if (virtualMethods == null || virtualMethods.length == 0) { 318 return; 319 } 320 321 writer.write("\n\n"); 322 writer.write("# virtual methods\n"); 323 writeMethods(writer, virtualMethods); 324 } 325 326 private void writeMethods(IndentingWriter writer, ClassDataItem.EncodedMethod[] methods) throws IOException { 327 boolean first = true; 328 for (ClassDataItem.EncodedMethod method: methods) { 329 if (!first) { 330 writer.write('\n'); 331 } 332 first = false; 333 334 AnnotationSetItem annotationSet = methodAnnotationsMap.get(method.method.getIndex()); 335 AnnotationSetRefList parameterAnnotationList = parameterAnnotationsMap.get(method.method.getIndex()); 336 337 MethodDefinition methodDefinition = new MethodDefinition(method); 338 methodDefinition.writeTo(writer, annotationSet, parameterAnnotationList); 339 340 ValidationException validationException = methodDefinition.getValidationException(); 341 if (validationException != null) { 342 System.err.println(String.format("Error while disassembling method %s. Continuing.", 343 method.method.getMethodString())); 344 validationException.printStackTrace(System.err); 345 this.validationErrors = true; 346 } 347 } 348 } 349} 350