ClassDefinition.java revision 10ebad1205b6c2407233ebf9805e4e2db29c251b
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<FieldIdItem> fieldsSetInStaticConstructor; 50 51 protected boolean validationErrors; 52 53 public ClassDefinition(ClassDefItem classDefItem) { 54 this.classDefItem = classDefItem; 55 this.classDataItem = classDefItem.getClassData(); 56 findFieldsSetInStaticConstructor(); 57 } 58 59 public boolean hadValidationErrors() { 60 return validationErrors; 61 } 62 63 private void findFieldsSetInStaticConstructor() { 64 fieldsSetInStaticConstructor = new SparseArray<FieldIdItem>(); 65 66 if (classDataItem == null) { 67 return; 68 } 69 70 for (ClassDataItem.EncodedMethod directMethod: classDataItem.getDirectMethods()) { 71 if (directMethod.method.getMethodName().getStringValue().equals("<clinit>") && 72 directMethod.codeItem != null) { 73 for (Instruction instruction: directMethod.codeItem.getInstructions()) { 74 switch (instruction.opcode) { 75 case SPUT: 76 case SPUT_BOOLEAN: 77 case SPUT_BYTE: 78 case SPUT_CHAR: 79 case SPUT_OBJECT: 80 case SPUT_SHORT: 81 case SPUT_WIDE: { 82 Instruction21c ins = (Instruction21c)instruction; 83 FieldIdItem fieldIdItem = (FieldIdItem)ins.getReferencedItem(); 84 fieldsSetInStaticConstructor.put(fieldIdItem.getIndex(), fieldIdItem); 85 break; 86 } 87 case SPUT_JUMBO: 88 case SPUT_BOOLEAN_JUMBO: 89 case SPUT_BYTE_JUMBO: 90 case SPUT_CHAR_JUMBO: 91 case SPUT_OBJECT_JUMBO: 92 case SPUT_SHORT_JUMBO: 93 case SPUT_WIDE_JUMBO: { 94 Instruction41c ins = (Instruction41c)instruction; 95 FieldIdItem fieldIdItem = (FieldIdItem)ins.getReferencedItem(); 96 fieldsSetInStaticConstructor.put(fieldIdItem.getIndex(), fieldIdItem); 97 break; 98 } 99 } 100 } 101 } 102 } 103 } 104 105 public void writeTo(IndentingWriter writer) throws IOException { 106 writeClass(writer); 107 writeSuper(writer); 108 writeSourceFile(writer); 109 writeInterfaces(writer); 110 writeAnnotations(writer); 111 writeStaticFields(writer); 112 writeInstanceFields(writer); 113 writeDirectMethods(writer); 114 writeVirtualMethods(writer); 115 } 116 117 private void writeClass(IndentingWriter writer) throws IOException { 118 writer.write(".class "); 119 writeAccessFlags(writer); 120 writer.write(classDefItem.getClassType().getTypeDescriptor()); 121 writer.write('\n'); 122 } 123 124 private void writeAccessFlags(IndentingWriter writer) throws IOException { 125 for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForClass(classDefItem.getAccessFlags())) { 126 writer.write(accessFlag.toString()); 127 writer.write(' '); 128 } 129 } 130 131 private void writeSuper(IndentingWriter writer) throws IOException { 132 TypeIdItem superClass = classDefItem.getSuperclass(); 133 if (superClass != null) { 134 writer.write(".super "); 135 writer.write(superClass.getTypeDescriptor()); 136 writer.write('\n'); 137 } 138 } 139 140 private void writeSourceFile(IndentingWriter writer) throws IOException { 141 StringIdItem sourceFile = classDefItem.getSourceFile(); 142 if (sourceFile != null) { 143 writer.write(".source \""); 144 Utf8Utils.writeEscapedString(writer, sourceFile.getStringValue()); 145 writer.write("\"\n"); 146 } 147 } 148 149 private void writeInterfaces(IndentingWriter writer) throws IOException { 150 TypeListItem interfaceList = classDefItem.getInterfaces(); 151 if (interfaceList == null) { 152 return; 153 } 154 155 List<TypeIdItem> interfaces = interfaceList.getTypes(); 156 if (interfaces == null || interfaces.size() == 0) { 157 return; 158 } 159 160 writer.write('\n'); 161 writer.write("# interfaces\n"); 162 for (TypeIdItem typeIdItem: interfaceList.getTypes()) { 163 writer.write(".implements "); 164 writer.write(typeIdItem.getTypeDescriptor()); 165 writer.write('\n'); 166 } 167 } 168 169 private void writeAnnotations(IndentingWriter writer) throws IOException { 170 AnnotationDirectoryItem annotationDirectory = classDefItem.getAnnotations(); 171 if (annotationDirectory == null) { 172 return; 173 } 174 175 AnnotationSetItem annotationSet = annotationDirectory.getClassAnnotations(); 176 if (annotationSet == null) { 177 return; 178 } 179 180 writer.write("\n\n"); 181 writer.write("# annotations\n"); 182 AnnotationFormatter.writeTo(writer, annotationSet); 183 } 184 185 private void writeStaticFields(IndentingWriter writer) throws IOException { 186 if (classDataItem == null) { 187 return; 188 } 189 //if classDataItem is not null, then classDefItem won't be null either 190 assert(classDefItem != null); 191 192 EncodedArrayItem encodedStaticInitializers = classDefItem.getStaticFieldInitializers(); 193 194 EncodedValue[] staticInitializers; 195 if (encodedStaticInitializers != null) { 196 staticInitializers = encodedStaticInitializers.getEncodedArray().values; 197 } else { 198 staticInitializers = new EncodedValue[0]; 199 } 200 201 List<ClassDataItem.EncodedField> encodedFields = classDataItem.getStaticFields(); 202 if (encodedFields.size() == 0) { 203 return; 204 } 205 206 writer.write("\n\n"); 207 writer.write("# static fields\n"); 208 209 boolean first = true; 210 for (int i=0; i<encodedFields.size(); i++) { 211 if (!first) { 212 writer.write('\n'); 213 } 214 first = false; 215 216 ClassDataItem.EncodedField field = encodedFields.get(i); 217 EncodedValue encodedValue = null; 218 if (i < staticInitializers.length) { 219 encodedValue = staticInitializers[i]; 220 } 221 AnnotationSetItem fieldAnnotations = null; 222 AnnotationDirectoryItem annotations = classDefItem.getAnnotations(); 223 if (annotations != null) { 224 fieldAnnotations = annotations.getFieldAnnotations(field.field); 225 } 226 227 boolean setInStaticConstructor = 228 fieldsSetInStaticConstructor.get(field.field.getIndex()) != null; 229 230 FieldDefinition.writeTo(writer, field, encodedValue, fieldAnnotations, setInStaticConstructor); 231 } 232 } 233 234 private void writeInstanceFields(IndentingWriter writer) throws IOException { 235 if (classDataItem == null) { 236 return; 237 } 238 239 List<ClassDataItem.EncodedField> encodedFields = classDataItem.getInstanceFields(); 240 if (encodedFields.size() == 0) { 241 return; 242 } 243 244 writer.write("\n\n"); 245 writer.write("# instance fields\n"); 246 boolean first = true; 247 for (ClassDataItem.EncodedField field: encodedFields) { 248 if (!first) { 249 writer.write('\n'); 250 } 251 first = false; 252 253 AnnotationSetItem fieldAnnotations = null; 254 AnnotationDirectoryItem annotations = classDefItem.getAnnotations(); 255 if (annotations != null) { 256 fieldAnnotations = annotations.getFieldAnnotations(field.field); 257 } 258 259 FieldDefinition.writeTo(writer, field, null, fieldAnnotations, false); 260 } 261 } 262 263 private void writeDirectMethods(IndentingWriter writer) throws IOException { 264 if (classDataItem == null) { 265 return; 266 } 267 268 List<ClassDataItem.EncodedMethod> directMethods = classDataItem.getDirectMethods(); 269 if (directMethods.size() == 0) { 270 return; 271 } 272 273 writer.write("\n\n"); 274 writer.write("# direct methods\n"); 275 writeMethods(writer, directMethods); 276 } 277 278 private void writeVirtualMethods(IndentingWriter writer) throws IOException { 279 if (classDataItem == null) { 280 return; 281 } 282 283 List<ClassDataItem.EncodedMethod> virtualMethods = classDataItem.getVirtualMethods(); 284 285 if (virtualMethods.size() == 0) { 286 return; 287 } 288 289 writer.write("\n\n"); 290 writer.write("# virtual methods\n"); 291 writeMethods(writer, virtualMethods); 292 } 293 294 private void writeMethods(IndentingWriter writer, List<ClassDataItem.EncodedMethod> methods) throws IOException { 295 boolean first = true; 296 for (ClassDataItem.EncodedMethod method: methods) { 297 if (!first) { 298 writer.write('\n'); 299 } 300 first = false; 301 302 AnnotationSetItem methodAnnotations = null; 303 AnnotationSetRefList parameterAnnotations = null; 304 AnnotationDirectoryItem annotations = classDefItem.getAnnotations(); 305 if (annotations != null) { 306 methodAnnotations = annotations.getMethodAnnotations(method.method); 307 parameterAnnotations = annotations.getParameterAnnotations(method.method); 308 } 309 310 MethodDefinition methodDefinition = new MethodDefinition(method); 311 methodDefinition.writeTo(writer, methodAnnotations, parameterAnnotations); 312 313 ValidationException validationException = methodDefinition.getValidationException(); 314 if (validationException != null) { 315 System.err.println(String.format("Error while disassembling method %s. Continuing.", 316 method.method.getMethodString())); 317 validationException.printStackTrace(System.err); 318 this.validationErrors = true; 319 } 320 } 321 } 322} 323