1// Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file 2// for details. All rights reserved. Use of this source code is governed by a 3// BSD-style license that can be found in the LICENSE file. 4package com.android.tools.r8.dex; 5 6import static com.android.tools.r8.utils.EncodedValueUtils.parseDouble; 7import static com.android.tools.r8.utils.EncodedValueUtils.parseFloat; 8import static com.android.tools.r8.utils.EncodedValueUtils.parseSigned; 9import static com.android.tools.r8.utils.EncodedValueUtils.parseUnsigned; 10 11import com.android.tools.r8.Resource; 12import com.android.tools.r8.code.Instruction; 13import com.android.tools.r8.code.InstructionFactory; 14import com.android.tools.r8.graph.ClassKind; 15import com.android.tools.r8.graph.Descriptor; 16import com.android.tools.r8.graph.DexAccessFlags; 17import com.android.tools.r8.graph.DexAnnotation; 18import com.android.tools.r8.graph.DexAnnotationElement; 19import com.android.tools.r8.graph.DexAnnotationSet; 20import com.android.tools.r8.graph.DexAnnotationSetRefList; 21import com.android.tools.r8.graph.DexCallSite; 22import com.android.tools.r8.graph.DexClass; 23import com.android.tools.r8.graph.DexCode; 24import com.android.tools.r8.graph.DexCode.Try; 25import com.android.tools.r8.graph.DexCode.TryHandler; 26import com.android.tools.r8.graph.DexCode.TryHandler.TypeAddrPair; 27import com.android.tools.r8.graph.DexDebugEvent; 28import com.android.tools.r8.graph.DexDebugInfo; 29import com.android.tools.r8.graph.DexEncodedAnnotation; 30import com.android.tools.r8.graph.DexEncodedArray; 31import com.android.tools.r8.graph.DexEncodedField; 32import com.android.tools.r8.graph.DexEncodedMethod; 33import com.android.tools.r8.graph.DexField; 34import com.android.tools.r8.graph.DexItem; 35import com.android.tools.r8.graph.DexItemFactory; 36import com.android.tools.r8.graph.DexMemberAnnotation; 37import com.android.tools.r8.graph.DexMemberAnnotation.DexFieldAnnotation; 38import com.android.tools.r8.graph.DexMemberAnnotation.DexMethodAnnotation; 39import com.android.tools.r8.graph.DexMemberAnnotation.DexParameterAnnotation; 40import com.android.tools.r8.graph.DexMethod; 41import com.android.tools.r8.graph.DexMethodHandle; 42import com.android.tools.r8.graph.DexMethodHandle.MethodHandleType; 43import com.android.tools.r8.graph.DexProto; 44import com.android.tools.r8.graph.DexString; 45import com.android.tools.r8.graph.DexType; 46import com.android.tools.r8.graph.DexTypeList; 47import com.android.tools.r8.graph.DexValue; 48import com.android.tools.r8.graph.DexValue.DexValueMethodHandle; 49import com.android.tools.r8.graph.DexValue.DexValueMethodType; 50import com.android.tools.r8.graph.DexValue.DexValueNull; 51import com.android.tools.r8.graph.DexValue.DexValueString; 52import com.android.tools.r8.graph.OffsetToObjectMapping; 53import com.android.tools.r8.logging.Log; 54import it.unimi.dsi.fastutil.ints.Int2ObjectMap; 55import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; 56import java.io.ByteArrayOutputStream; 57import java.io.IOException; 58import java.io.InputStream; 59import java.nio.ShortBuffer; 60import java.nio.file.Path; 61import java.util.ArrayList; 62import java.util.Arrays; 63import java.util.Hashtable; 64import java.util.List; 65import java.util.function.Consumer; 66import java.util.function.Supplier; 67 68public class DexFileReader { 69 70 final int NO_INDEX = -1; 71 private DexFile file; 72 private final Segment[] segments; 73 private int[] stringIDs; 74 private final ClassKind classKind; 75 76 public static Segment[] parseMapFrom(Path file) throws IOException { 77 return parseMapFrom(new DexFile(file.toString())); 78 } 79 80 public static Segment[] parseMapFrom(InputStream stream) throws IOException { 81 return parseMapFrom(new DexFile(stream)); 82 } 83 84 private static Segment[] parseMapFrom(DexFile dex) throws IOException { 85 DexFileReader reader = new DexFileReader(dex, ClassKind.PROGRAM, new DexItemFactory()); 86 return reader.segments; 87 } 88 89 public void close() { 90 // This close behavior is needed to reduce peak memory usage of D8/R8. 91 indexedItems = null; 92 codes = null; 93 offsetMap = null; 94 file = null; 95 stringIDs = null; 96 } 97 98 // Mapping from indexes to indexable dex items. 99 private OffsetToObjectMapping indexedItems = new OffsetToObjectMapping(); 100 101 // Mapping from offset to code item; 102 private Int2ObjectMap<DexCode> codes = new Int2ObjectOpenHashMap<>(); 103 104 // Mapping from offset to dex item; 105 private Int2ObjectMap<Object> offsetMap = new Int2ObjectOpenHashMap<>(); 106 107 // Factory to canonicalize certain dexitems. 108 private final DexItemFactory dexItemFactory; 109 110 public DexFileReader(DexFile file, ClassKind classKind, DexItemFactory dexItemFactory) { 111 this.file = file; 112 this.dexItemFactory = dexItemFactory; 113 file.setByteOrder(); 114 segments = parseMap(); 115 parseStringIDs(); 116 this.classKind = classKind; 117 } 118 119 public OffsetToObjectMapping getIndexedItemsMap() { 120 return indexedItems; 121 } 122 123 void addCodeItemsTo() { 124 if (classKind == ClassKind.LIBRARY) { 125 // Ignore contents of library files. 126 return; 127 } 128 Segment segment = lookupSegment(Constants.TYPE_CODE_ITEM); 129 if (segment.length == 0) { 130 return; 131 } 132 file.position(segment.offset); 133 for (int i = 0; i < segment.length; i++) { 134 file.align(4); // code items are 4 byte aligned. 135 int offset = file.position(); 136 DexCode code = parseCodeItem(); 137 codes.put(offset, code); // Update the file local offset to code mapping. 138 } 139 } 140 141 private DexTypeList parseTypeList() { 142 DexType[] result = new DexType[file.getUint()]; 143 for (int j = 0; j < result.length; j++) { 144 result[j] = indexedItems.getType(file.getUshort()); 145 } 146 return new DexTypeList(result); 147 } 148 149 private DexTypeList typeListAt(int offset) { 150 if (offset == 0) { 151 return DexTypeList.empty(); 152 } 153 return (DexTypeList) cacheAt(offset, this::parseTypeList); 154 } 155 156 public DexValue parseEncodedValue() { 157 int header = file.get() & 0xff; 158 int valueArg = header >> 5; 159 int valueType = header & 0x1f; 160 switch (valueType) { 161 case DexValue.VALUE_BYTE: { 162 assert valueArg == 0; 163 byte value = (byte) parseSigned(file, 1); 164 return DexValue.DexValueByte.create(value); 165 } 166 case DexValue.VALUE_SHORT: { 167 int size = valueArg + 1; 168 short value = (short) parseSigned(file, size); 169 return DexValue.DexValueShort.create(value); 170 } 171 case DexValue.VALUE_CHAR: { 172 int size = valueArg + 1; 173 char value = (char) parseUnsigned(file, size); 174 return DexValue.DexValueChar.create(value); 175 } 176 case DexValue.VALUE_INT: { 177 int size = valueArg + 1; 178 int value = (int) parseSigned(file, size); 179 return DexValue.DexValueInt.create(value); 180 } 181 case DexValue.VALUE_LONG: { 182 int size = valueArg + 1; 183 long value = parseSigned(file, size); 184 return DexValue.DexValueLong.create(value); 185 } 186 case DexValue.VALUE_FLOAT: { 187 int size = valueArg + 1; 188 return DexValue.DexValueFloat.create(parseFloat(file, size)); 189 } 190 case DexValue.VALUE_DOUBLE: { 191 int size = valueArg + 1; 192 return DexValue.DexValueDouble.create(parseDouble(file, size)); 193 } 194 case DexValue.VALUE_STRING: { 195 int size = valueArg + 1; 196 int index = (int) parseUnsigned(file, size); 197 DexString value = indexedItems.getString(index); 198 return new DexValue.DexValueString(value); 199 } 200 case DexValue.VALUE_TYPE: { 201 int size = valueArg + 1; 202 DexType value = indexedItems.getType((int) parseUnsigned(file, size)); 203 return new DexValue.DexValueType(value); 204 } 205 case DexValue.VALUE_FIELD: { 206 int size = valueArg + 1; 207 DexField value = indexedItems.getField((int) parseUnsigned(file, size)); 208 return new DexValue.DexValueField(value); 209 } 210 case DexValue.VALUE_METHOD: { 211 int size = valueArg + 1; 212 DexMethod value = indexedItems.getMethod((int) parseUnsigned(file, size)); 213 return new DexValue.DexValueMethod(value); 214 } 215 case DexValue.VALUE_ENUM: { 216 int size = valueArg + 1; 217 DexField value = indexedItems.getField((int) parseUnsigned(file, size)); 218 return new DexValue.DexValueEnum(value); 219 } 220 case DexValue.VALUE_ARRAY: { 221 assert valueArg == 0; 222 return new DexValue.DexValueArray(parseEncodedArrayValues()); 223 } 224 case DexValue.VALUE_ANNOTATION: { 225 assert valueArg == 0; 226 return new DexValue.DexValueAnnotation(parseEncodedAnnotation()); 227 } 228 case DexValue.VALUE_NULL: { 229 assert valueArg == 0; 230 return DexValueNull.NULL; 231 } 232 case DexValue.VALUE_BOOLEAN: { 233 // 0 is false, and 1 is true. 234 return DexValue.DexValueBoolean.create(valueArg != 0); 235 } 236 case DexValue.VALUE_METHOD_TYPE: { 237 int size = valueArg + 1; 238 DexProto value = indexedItems.getProto((int) parseUnsigned(file, size)); 239 return new DexValue.DexValueMethodType(value); 240 } 241 case DexValue.VALUE_METHOD_HANDLE: { 242 int size = valueArg + 1; 243 DexMethodHandle value = indexedItems.getMethodHandle((int) parseUnsigned(file, size)); 244 return new DexValue.DexValueMethodHandle(value); 245 } 246 default: 247 throw new IndexOutOfBoundsException(); 248 } 249 } 250 251 private DexEncodedAnnotation parseEncodedAnnotation() { 252 int typeIdx = file.getUleb128(); 253 int size = file.getUleb128(); 254 DexAnnotationElement[] elements = new DexAnnotationElement[size]; 255 for (int i = 0; i < size; i++) { 256 int nameIdx = file.getUleb128(); 257 DexValue value = parseEncodedValue(); 258 elements[i] = new DexAnnotationElement(indexedItems.getString(nameIdx), value); 259 } 260 return new DexEncodedAnnotation(indexedItems.getType(typeIdx), elements); 261 } 262 263 private DexValue[] parseEncodedArrayValues() { 264 int size = file.getUleb128(); 265 DexValue[] values = new DexValue[size]; 266 for (int i = 0; i < size; i++) { 267 values[i] = parseEncodedValue(); 268 } 269 return values; 270 } 271 272 273 private DexEncodedArray parseEncodedArray() { 274 return new DexEncodedArray(parseEncodedArrayValues()); 275 } 276 277 private DexEncodedArray encodedArrayAt(int offset) { 278 return (DexEncodedArray) cacheAt(offset, this::parseEncodedArray); 279 } 280 281 private DexFieldAnnotation[] parseFieldAnnotations(int size) { 282 if (size == 0) { 283 return null; 284 } 285 int[] fieldIndices = new int[size]; 286 int[] annotationOffsets = new int[size]; 287 for (int i = 0; i < size; i++) { 288 fieldIndices[i] = file.getUint(); 289 annotationOffsets[i] = file.getUint(); 290 } 291 int saved = file.position(); 292 DexFieldAnnotation[] result = new DexFieldAnnotation[size]; 293 for (int i = 0; i < size; i++) { 294 DexField field = indexedItems.getField(fieldIndices[i]); 295 DexAnnotationSet annotation = annotationSetAt(annotationOffsets[i]); 296 result[i] = new DexFieldAnnotation(field, annotation); 297 } 298 file.position(saved); 299 return result; 300 } 301 302 private DexMethodAnnotation[] parseMethodAnnotations(int size) { 303 if (size == 0) { 304 return null; 305 } 306 int[] methodIndices = new int[size]; 307 int[] annotationOffsets = new int[size]; 308 for (int i = 0; i < size; i++) { 309 methodIndices[i] = file.getUint(); 310 annotationOffsets[i] = file.getUint(); 311 } 312 int saved = file.position(); 313 DexMethodAnnotation[] result = new DexMethodAnnotation[size]; 314 for (int i = 0; i < size; i++) { 315 DexMethod method = indexedItems.getMethod(methodIndices[i]); 316 DexAnnotationSet annotation = annotationSetAt(annotationOffsets[i]); 317 result[i] = new DexMethodAnnotation(method, annotation); 318 } 319 file.position(saved); 320 return result; 321 } 322 323 private DexAnnotationSetRefList annotationSetRefListAt(int offset) { 324 return (DexAnnotationSetRefList) cacheAt(offset, this::parseAnnotationSetRefList); 325 } 326 327 private DexAnnotationSetRefList parseAnnotationSetRefList() { 328 int size = file.getUint(); 329 int[] annotationOffsets = new int[size]; 330 for (int i = 0; i < size; i++) { 331 annotationOffsets[i] = file.getUint(); 332 } 333 DexAnnotationSet[] values = new DexAnnotationSet[size]; 334 for (int i = 0; i < size; i++) { 335 values[i] = annotationSetAt(annotationOffsets[i]); 336 } 337 return new DexAnnotationSetRefList(values); 338 } 339 340 private DexParameterAnnotation[] parseParameterAnnotations(int size) { 341 if (size == 0) { 342 return null; 343 } 344 int[] methodIndices = new int[size]; 345 int[] annotationOffsets = new int[size]; 346 for (int i = 0; i < size; i++) { 347 methodIndices[i] = file.getUint(); 348 annotationOffsets[i] = file.getUint(); 349 } 350 int saved = file.position(); 351 DexParameterAnnotation[] result = new DexParameterAnnotation[size]; 352 for (int i = 0; i < size; i++) { 353 DexMethod method = indexedItems.getMethod(methodIndices[i]); 354 result[i] = new DexParameterAnnotation( 355 method, 356 annotationSetRefListAt(annotationOffsets[i])); 357 } 358 file.position(saved); 359 return result; 360 } 361 362 private <T> Object cacheAt(int offset, Supplier<T> function, Supplier<T> defaultValue) { 363 if (offset == 0) { 364 return defaultValue.get(); 365 } 366 return cacheAt(offset, function); 367 } 368 369 private <T> Object cacheAt(int offset, Supplier<T> function) { 370 if (offset == 0) { 371 return null; // return null for offset zero. 372 } 373 Object result = offsetMap.get(offset); 374 if (result != null) { 375 return result; // return the cached result. 376 } 377 // Cache is empty so parse the structure. 378 file.position(offset); 379 result = function.get(); 380 // Update the map. 381 offsetMap.put(offset, result); 382 assert offsetMap.get(offset) == result; 383 return result; 384 } 385 386 private DexAnnotation parseAnnotation() { 387 if (Log.ENABLED) { 388 Log.verbose(getClass(), "Reading Annotation @ 0x%08x.", file.position()); 389 } 390 int visibility = file.get(); 391 return new DexAnnotation(visibility, parseEncodedAnnotation()); 392 } 393 394 private DexAnnotation annotationAt(int offset) { 395 return (DexAnnotation) cacheAt(offset, this::parseAnnotation); 396 } 397 398 private DexAnnotationSet parseAnnotationSet() { 399 if (Log.ENABLED) { 400 Log.verbose(getClass(), "Reading AnnotationSet @ 0x%08x.", file.position()); 401 } 402 int size = file.getUint(); 403 int[] annotationOffsets = new int[size]; 404 for (int i = 0; i < size; i++) { 405 annotationOffsets[i] = file.getUint(); 406 } 407 DexAnnotation[] result = new DexAnnotation[size]; 408 for (int i = 0; i < size; i++) { 409 result[i] = annotationAt(annotationOffsets[i]); 410 } 411 return new DexAnnotationSet(result); 412 } 413 414 private DexAnnotationSet annotationSetAt(int offset) { 415 return (DexAnnotationSet) cacheAt(offset, this::parseAnnotationSet, DexAnnotationSet::empty); 416 } 417 418 private AnnotationsDirectory annotationsDirectoryAt(int offset) { 419 return (AnnotationsDirectory) cacheAt(offset, this::parseAnnotationsDirectory, 420 AnnotationsDirectory::empty); 421 } 422 423 private AnnotationsDirectory parseAnnotationsDirectory() { 424 int classAnnotationsOff = file.getUint(); 425 int fieldsSize = file.getUint(); 426 int methodsSize = file.getUint(); 427 int parametersSize = file.getUint(); 428 final DexFieldAnnotation[] fields = parseFieldAnnotations(fieldsSize); 429 final DexMethodAnnotation[] methods = parseMethodAnnotations(methodsSize); 430 final DexParameterAnnotation[] parameters = parseParameterAnnotations(parametersSize); 431 return new AnnotationsDirectory( 432 annotationSetAt(classAnnotationsOff), 433 fields, 434 methods, 435 parameters); 436 } 437 438 private DexDebugInfo debugInfoAt(int offset) { 439 return (DexDebugInfo) cacheAt(offset, this::parseDebugInfo); 440 } 441 442 private DexDebugInfo parseDebugInfo() { 443 int start = file.getUleb128(); 444 int parametersSize = file.getUleb128(); 445 DexString[] parameters = new DexString[parametersSize]; 446 for (int i = 0; i < parametersSize; i++) { 447 int index = file.getUleb128p1(); 448 if (index != NO_INDEX) { 449 parameters[i] = indexedItems.getString(index); 450 } 451 } 452 List<DexDebugEvent> events = new ArrayList<>(); 453 for (int head = file.getUbyte(); head != Constants.DBG_END_SEQUENCE; head = file.getUbyte()) { 454 switch (head) { 455 case Constants.DBG_ADVANCE_PC: 456 events.add(dexItemFactory.createAdvancePC(file.getUleb128())); 457 break; 458 case Constants.DBG_ADVANCE_LINE: 459 events.add(dexItemFactory.createAdvanceLine(file.getSleb128())); 460 break; 461 case Constants.DBG_START_LOCAL: { 462 int registerNum = file.getUleb128(); 463 int nameIdx = file.getUleb128p1(); 464 int typeIdx = file.getUleb128p1(); 465 events.add(new DexDebugEvent.StartLocal( 466 registerNum, 467 nameIdx == NO_INDEX ? null : indexedItems.getString(nameIdx), 468 typeIdx == NO_INDEX ? null : indexedItems.getType(typeIdx), 469 null)); 470 break; 471 } 472 case Constants.DBG_START_LOCAL_EXTENDED: { 473 int registerNum = file.getUleb128(); 474 int nameIdx = file.getUleb128p1(); 475 int typeIdx = file.getUleb128p1(); 476 int sigIdx = file.getUleb128p1(); 477 events.add(new DexDebugEvent.StartLocal( 478 registerNum, 479 nameIdx == NO_INDEX ? null : indexedItems.getString(nameIdx), 480 typeIdx == NO_INDEX ? null : indexedItems.getType(typeIdx), 481 sigIdx == NO_INDEX ? null : indexedItems.getString(sigIdx))); 482 break; 483 } 484 case Constants.DBG_END_LOCAL: { 485 events.add(dexItemFactory.createEndLocal(file.getUleb128())); 486 break; 487 } 488 case Constants.DBG_RESTART_LOCAL: { 489 events.add(dexItemFactory.createRestartLocal(file.getUleb128())); 490 break; 491 } 492 case Constants.DBG_SET_PROLOGUE_END: { 493 events.add(dexItemFactory.createSetPrologueEnd()); 494 break; 495 } 496 case Constants.DBG_SET_EPILOGUE_BEGIN: { 497 events.add(dexItemFactory.createSetEpilogueBegin()); 498 break; 499 } 500 case Constants.DBG_SET_FILE: { 501 int nameIdx = file.getUleb128p1(); 502 DexString sourceFile = nameIdx == NO_INDEX ? null : indexedItems.getString(nameIdx); 503 events.add(dexItemFactory.createSetFile(sourceFile)); 504 break; 505 } 506 default: { 507 assert head >= 0x0a && head <= 0xff; 508 events.add(dexItemFactory.createDefault(head)); 509 } 510 } 511 } 512 return new DexDebugInfo(start, parameters, events.toArray(new DexDebugEvent[events.size()])); 513 } 514 515 private static class MemberAnnotationIterator<S extends Descriptor<?, S>, T extends DexItem> { 516 517 private int index = 0; 518 private final DexMemberAnnotation<S, T>[] annotations; 519 private final Supplier<T> emptyValue; 520 521 private MemberAnnotationIterator(DexMemberAnnotation<S, T>[] annotations, 522 Supplier<T> emptyValue) { 523 this.annotations = annotations; 524 this.emptyValue = emptyValue; 525 } 526 527 // Get the annotation set for an item. This method assumes that it is always called with 528 // an item that is higher in the sorting order than the last item. 529 T getNextFor(S item) { 530 // TODO(ager): We could use the indices from the file to make this search faster using 531 // compareTo instead of slowCompareTo. That would require us to assign indices during 532 // reading. Those indices should be cleared after reading to make sure that we resort 533 // everything correctly at the end. 534 while (index < annotations.length && annotations[index].item.slowCompareTo(item) < 0) { 535 index++; 536 } 537 if (index >= annotations.length || !annotations[index].item.equals(item)) { 538 return emptyValue.get(); 539 } 540 return annotations[index].annotations; 541 } 542 } 543 544 private DexEncodedField[] readFields(int size, DexFieldAnnotation[] annotations, 545 DexValue[] staticValues) { 546 DexEncodedField[] fields = new DexEncodedField[size]; 547 int fieldIndex = 0; 548 MemberAnnotationIterator<DexField, DexAnnotationSet> annotationIterator = 549 new MemberAnnotationIterator<>(annotations, DexAnnotationSet::empty); 550 for (int i = 0; i < size; i++) { 551 fieldIndex += file.getUleb128(); 552 DexField field = indexedItems.getField(fieldIndex); 553 DexAccessFlags accessFlags = new DexAccessFlags(file.getUleb128()); 554 DexAnnotationSet fieldAnnotations = annotationIterator.getNextFor(field); 555 DexValue staticValue = null; 556 if (accessFlags.isStatic()) { 557 if (staticValues != null && i < staticValues.length) { 558 staticValue = staticValues[i]; 559 } else { 560 staticValue = DexValue.defaultForType(field.type, dexItemFactory); 561 } 562 } 563 fields[i] = new DexEncodedField(field, accessFlags, fieldAnnotations, staticValue); 564 } 565 return fields; 566 } 567 568 private DexEncodedMethod[] readMethods(int size, DexMethodAnnotation[] annotations, 569 DexParameterAnnotation[] parameters, boolean skipCodes) { 570 DexEncodedMethod[] methods = new DexEncodedMethod[size]; 571 int methodIndex = 0; 572 MemberAnnotationIterator<DexMethod, DexAnnotationSet> annotationIterator = 573 new MemberAnnotationIterator<>(annotations, DexAnnotationSet::empty); 574 MemberAnnotationIterator<DexMethod, DexAnnotationSetRefList> parameterAnnotationsIterator = 575 new MemberAnnotationIterator<>(parameters, DexAnnotationSetRefList::empty); 576 for (int i = 0; i < size; i++) { 577 methodIndex += file.getUleb128(); 578 DexAccessFlags accessFlags = new DexAccessFlags(file.getUleb128()); 579 int codeOff = file.getUleb128(); 580 DexCode code = null; 581 if (!skipCodes) { 582 assert codeOff == 0 || codes.get(codeOff) != null; 583 code = codes.get(codeOff); 584 } 585 DexMethod method = indexedItems.getMethod(methodIndex); 586 methods[i] = new DexEncodedMethod(method, accessFlags, annotationIterator.getNextFor(method), 587 parameterAnnotationsIterator.getNextFor(method), code); 588 } 589 return methods; 590 } 591 592 void addClassDefsTo(Consumer<DexClass> classCollection) { 593 final Segment segment = lookupSegment(Constants.TYPE_CLASS_DEF_ITEM); 594 final int length = segment.length; 595 indexedItems.initializeClasses(length); 596 if (length == 0) { 597 return; 598 } 599 file.position(segment.offset); 600 601 int[] classIndices = new int[length]; 602 int[] accessFlags = new int[length]; 603 int[] superclassIndices = new int[length]; 604 int[] interfacesOffsets = new int[length]; 605 int[] sourceFileIndices = new int[length]; 606 int[] annotationsOffsets = new int[length]; 607 int[] classDataOffsets = new int[length]; 608 int[] staticValuesOffsets = new int[length]; 609 610 for (int i = 0; i < length; i++) { 611 if (Log.ENABLED) { 612 Log.verbose(getClass(), "Reading ClassDef @ 0x%08x.", file.position()); 613 } 614 classIndices[i] = file.getUint(); 615 accessFlags[i] = file.getUint(); 616 superclassIndices[i] = file.getInt(); 617 interfacesOffsets[i] = file.getUint(); 618 sourceFileIndices[i] = file.getInt(); 619 annotationsOffsets[i] = file.getUint(); 620 classDataOffsets[i] = file.getUint(); 621 staticValuesOffsets[i] = file.getUint(); 622 } 623 624 for (int i = 0; i < length; i++) { 625 int superclassIdx = superclassIndices[i]; 626 DexType superclass = superclassIdx == NO_INDEX ? null : indexedItems.getType(superclassIdx); 627 int srcIdx = sourceFileIndices[i]; 628 DexString source = srcIdx == NO_INDEX ? null : indexedItems.getString(srcIdx); 629 // fix annotations. 630 DexType type = indexedItems.getType(classIndices[i]); 631 DexAccessFlags flags = new DexAccessFlags(accessFlags[i]); 632 DexClass clazz; 633 DexEncodedField[] staticFields = DexEncodedField.EMPTY_ARRAY; 634 DexEncodedField[] instanceFields = DexEncodedField.EMPTY_ARRAY; 635 DexEncodedMethod[] directMethods = DexEncodedMethod.EMPTY_ARRAY; 636 DexEncodedMethod[] virtualMethods = DexEncodedMethod.EMPTY_ARRAY; 637 AnnotationsDirectory annotationsDirectory = annotationsDirectoryAt(annotationsOffsets[i]); 638 if (classDataOffsets[i] != 0) { 639 DexEncodedArray staticValues = encodedArrayAt(staticValuesOffsets[i]); 640 641 file.position(classDataOffsets[i]); 642 int staticFieldsSize = file.getUleb128(); 643 int instanceFieldsSize = file.getUleb128(); 644 int directMethodsSize = file.getUleb128(); 645 int virtualMethodsSize = file.getUleb128(); 646 647 staticFields = readFields(staticFieldsSize, annotationsDirectory.fields, 648 staticValues != null ? staticValues.values : null); 649 instanceFields = readFields(instanceFieldsSize, annotationsDirectory.fields, null); 650 directMethods = 651 readMethods( 652 directMethodsSize, 653 annotationsDirectory.methods, 654 annotationsDirectory.parameters, 655 classKind != ClassKind.PROGRAM); 656 virtualMethods = 657 readMethods( 658 virtualMethodsSize, 659 annotationsDirectory.methods, 660 annotationsDirectory.parameters, 661 classKind != ClassKind.PROGRAM); 662 } 663 clazz = classKind.create( 664 type, 665 Resource.Kind.DEX, 666 flags, 667 superclass, 668 typeListAt(interfacesOffsets[i]), 669 source, 670 annotationsDirectory.clazz, 671 staticFields, 672 instanceFields, 673 directMethods, 674 virtualMethods); 675 classCollection.accept(clazz); // Update the application object. 676 } 677 } 678 679 private void parseStringIDs() { 680 Segment segment = lookupSegment(Constants.TYPE_STRING_ID_ITEM); 681 stringIDs = new int[segment.length]; 682 if (segment.length == 0) { 683 return; 684 } 685 file.position(segment.offset); 686 for (int i = 0; i < segment.length; i++) { 687 stringIDs[i] = file.getUint(); 688 } 689 } 690 691 private Segment lookupSegment(int type) { 692 for (Segment s : segments) { 693 if (s.type == type) { 694 return s; 695 } 696 } 697 // If the segment doesn't exist, return an empty segment of this type. 698 return new Segment(type, 0, 0, 0); 699 } 700 701 private Segment[] parseMap() { 702 // Read the segments information from the MAP. 703 int mapOffset = file.getUint(Constants.MAP_OFF_OFFSET); 704 file.position(mapOffset); 705 int mapSize = file.getUint(); 706 final Segment[] result = new Segment[mapSize]; 707 for (int i = 0; i < mapSize; i++) { 708 int type = file.getUshort(); 709 int unused = file.getUshort(); 710 int size = file.getUint(); 711 int offset = file.getUint(); 712 result[i] = new Segment(type, unused, size, offset); 713 } 714 if (Log.ENABLED) { 715 for (int i = 0; i < result.length; i++) { 716 Segment segment = result[i]; 717 int nextOffset = i < result.length - 1 ? result[i + 1].offset : segment.offset; 718 Log.debug(this.getClass(), "Read segment 0x%04x @ 0x%08x #items %08d size 0x%08x.", 719 segment.type, segment.offset, segment.length, nextOffset - segment.offset); 720 } 721 } 722 for (int i = 0; i < mapSize - 1; i++) { 723 result[i].setEnd(result[i + 1].offset); 724 } 725 result[mapSize - 1].setEnd(file.end()); 726 return result; 727 } 728 729 private DexCode parseCodeItem() { 730 int registerSize = file.getUshort(); 731 int insSize = file.getUshort(); 732 int outsSize = file.getUshort(); 733 int triesSize = file.getUshort(); 734 int debugInfoOff = file.getUint(); 735 int insnsSize = file.getUint(); 736 short[] code = new short[insnsSize]; 737 Try[] tries = new Try[triesSize]; 738 DexCode.TryHandler[] handlers = null; 739 740 if (insnsSize != 0) { 741 for (int i = 0; i < insnsSize; i++) { 742 code[i] = file.getShort(); 743 } 744 if (insnsSize % 2 != 0) { 745 file.getUshort(); // Skip padding ushort 746 } 747 if (triesSize > 0) { 748 Hashtable<Integer, Integer> handlerMap = new Hashtable<>(); 749 // tries: try_item[tries_size]. 750 for (int i = 0; i < triesSize; i++) { 751 int startAddr = file.getUint(); 752 int insnCount = file.getUshort(); 753 int handlerOff = file.getUshort(); 754 tries[i] = new Try(startAddr, insnCount, handlerOff); 755 } 756 // handlers: encoded_catch_handler_list 757 int encodedCatchHandlerListPosition = file.position(); 758 // - size: uleb128 759 int size = file.getUleb128(); 760 handlers = new TryHandler[size]; 761 // - list: encoded_catch_handler[handlers_size] 762 for (int i = 0; i < size; i++) { 763 // encoded_catch_handler 764 int encodedCatchHandlerOffset = file.position() - encodedCatchHandlerListPosition; 765 handlerMap.put(encodedCatchHandlerOffset, i); 766 // - size: sleb128 767 int hsize = file.getSleb128(); 768 int realHsize = Math.abs(hsize); 769 // - handlers encoded_type_addr_pair[abs(size)] 770 TryHandler.TypeAddrPair pairs[] = new TryHandler.TypeAddrPair[realHsize]; 771 for (int j = 0; j < realHsize; j++) { 772 int typeIdx = file.getUleb128(); 773 int addr = file.getUleb128(); 774 pairs[j] = new TypeAddrPair(indexedItems.getType(typeIdx), addr, 775 encodedCatchHandlerOffset); 776 } 777 int catchAllAddr = -1; 778 if (hsize <= 0) { 779 catchAllAddr = file.getUleb128(); 780 } 781 handlers[i] = new TryHandler(pairs, catchAllAddr); 782 } 783 // Convert the handler offsets inside the Try objects to indexes. 784 for (Try t : tries) { 785 t.setHandlerIndex(handlerMap); 786 } 787 } 788 } 789 // Store and restore offset information around reading debug info. 790 int saved = file.position(); 791 DexDebugInfo debugInfo = debugInfoAt(debugInfoOff); 792 file.position(saved); 793 InstructionFactory factory = new InstructionFactory(); 794 Instruction[] instructions = 795 factory.readSequenceFrom(ShortBuffer.wrap(code), 0, code.length, indexedItems); 796 return new DexCode( 797 registerSize, 798 insSize, 799 outsSize, 800 instructions, 801 tries, 802 handlers, 803 debugInfo, 804 factory.getHighestSortingString()); 805 } 806 807 static void populateIndexTables(DexFileReader fileReader) { 808 // Populate structures that are already sorted upon read. 809 DexFileReader.populateStrings(fileReader); // Depends on nothing. 810 DexFileReader.populateTypes(fileReader); // Depends on Strings. 811 DexFileReader.populateFields(fileReader); // Depends on Types, and Strings. 812 DexFileReader.populateProtos(fileReader); // Depends on Types and Strings. 813 DexFileReader.populateMethods(fileReader); // Depends on Protos, Types, and Strings. 814 DexFileReader.populateMethodHandles(fileReader); // Depends on Methods and Fields 815 DexFileReader.populateCallSites(fileReader); // Depends on MethodHandles 816 } 817 818 private static void populateStrings(DexFileReader reader) { 819 reader.indexedItems.initializeStrings(reader.stringIDs.length); 820 for (int i = 0; i < reader.stringIDs.length; i++) { 821 reader.indexedItems.setString(i, reader.stringAt(i)); 822 } 823 } 824 825 private static void populateMethodHandles(DexFileReader reader) { 826 Segment segment = reader.lookupSegment(Constants.TYPE_METHOD_HANDLE_ITEM); 827 reader.indexedItems.initializeMethodHandles(segment.length); 828 for (int i = 0; i < segment.length; i++) { 829 reader.indexedItems.setMethodHandle(i, reader.methodHandleAt(i)); 830 } 831 } 832 833 private static void populateCallSites(DexFileReader reader) { 834 Segment segment = reader.lookupSegment(Constants.TYPE_CALL_SITE_ID_ITEM); 835 reader.indexedItems.initializeCallSites(segment.length); 836 for (int i = 0; i < segment.length; i++) { 837 reader.indexedItems.setCallSites(i, reader.callSiteAt(i)); 838 } 839 } 840 841 private static void populateTypes(DexFileReader reader) { 842 Segment segment = reader.lookupSegment(Constants.TYPE_TYPE_ID_ITEM); 843 reader.indexedItems.initializeTypes(segment.length); 844 for (int i = 0; i < segment.length; i++) { 845 reader.indexedItems.setType(i, reader.typeAt(i)); 846 } 847 } 848 849 private static void populateFields(DexFileReader reader) { 850 Segment segment = reader.lookupSegment(Constants.TYPE_FIELD_ID_ITEM); 851 reader.indexedItems.initializeFields(segment.length); 852 for (int i = 0; i < segment.length; i++) { 853 reader.indexedItems.setField(i, reader.fieldAt(i)); 854 } 855 } 856 857 private static void populateProtos(DexFileReader reader) { 858 Segment segment = reader.lookupSegment(Constants.TYPE_PROTO_ID_ITEM); 859 reader.indexedItems.initializeProtos(segment.length); 860 for (int i = 0; i < segment.length; i++) { 861 reader.indexedItems.setProto(i, reader.protoAt(i)); 862 } 863 } 864 865 private static void populateMethods(DexFileReader reader) { 866 Segment segment = reader.lookupSegment(Constants.TYPE_METHOD_ID_ITEM); 867 reader.indexedItems.initializeMethods(segment.length); 868 for (int i = 0; i < segment.length; i++) { 869 reader.indexedItems.setMethod(i, reader.methodAt(i)); 870 } 871 } 872 873 private DexString stringAt(int index) { 874 final int offset = stringIDs[index]; 875 file.position(offset); 876 int size = file.getUleb128(); 877 ByteArrayOutputStream os = new ByteArrayOutputStream(); 878 byte read; 879 do { 880 read = file.get(); 881 os.write(read); 882 } while (read != 0); 883 return dexItemFactory.createString(size, os.toByteArray()); 884 } 885 886 private DexType typeAt(int index) { 887 Segment segment = lookupSegment(Constants.TYPE_TYPE_ID_ITEM); 888 if (index >= segment.length) { 889 return null; 890 } 891 int offset = segment.offset + (Constants.TYPE_TYPE_ID_ITEM_SIZE * index); 892 int stringIndex = file.getUint(offset); 893 return dexItemFactory.createType(indexedItems.getString(stringIndex)); 894 } 895 896 private DexField fieldAt(int index) { 897 Segment segment = lookupSegment(Constants.TYPE_FIELD_ID_ITEM); 898 if (index >= segment.length) { 899 return null; 900 } 901 int offset = segment.offset + (Constants.TYPE_FIELD_ID_ITEM_SIZE * index); 902 file.position(offset); 903 int classIndex = file.getUshort(); 904 int typeIndex = file.getUshort(); 905 int nameIndex = file.getUint(); 906 DexType clazz = indexedItems.getType(classIndex); 907 DexType type = indexedItems.getType(typeIndex); 908 DexString name = indexedItems.getString(nameIndex); 909 return dexItemFactory.createField(clazz, type, name); 910 } 911 912 private DexMethodHandle methodHandleAt(int index) { 913 Segment segment = lookupSegment(Constants.TYPE_METHOD_HANDLE_ITEM); 914 if (index >= segment.length) { 915 return null; 916 } 917 int offset = segment.offset + (Constants.TYPE_METHOD_HANDLE_ITEM_SIZE * index); 918 file.position(offset); 919 MethodHandleType type = MethodHandleType.getKind(file.getUshort()); 920 file.getUshort(); // unused 921 int indexFieldOrMethod = file.getUshort(); 922 Descriptor<? extends DexItem, ? extends Descriptor> fieldOrMethod; 923 switch (type) { 924 case INSTANCE_GET: 925 case INSTANCE_PUT: 926 case STATIC_GET: 927 case STATIC_PUT: { 928 fieldOrMethod = indexedItems.getField(indexFieldOrMethod); 929 break; 930 } 931 case INVOKE_INSTANCE: 932 case INVOKE_STATIC: { 933 fieldOrMethod = indexedItems.getMethod(indexFieldOrMethod); 934 break; 935 } 936 default: 937 throw new AssertionError("Method handle type unsupported in a dex file."); 938 } 939 file.getUshort(); // unused 940 941 return dexItemFactory.createMethodHandle(type, fieldOrMethod); 942 } 943 944 private DexCallSite callSiteAt(int index) { 945 Segment segment = lookupSegment(Constants.TYPE_CALL_SITE_ID_ITEM); 946 if (index >= segment.length) { 947 return null; 948 } 949 int callSiteOffset = 950 file.getUint(segment.offset + (Constants.TYPE_CALL_SITE_ID_ITEM_SIZE * index)); 951 DexEncodedArray callSiteEncodedArray = encodedArrayAt(callSiteOffset); 952 DexValue[] values = callSiteEncodedArray.values; 953 assert values[0] instanceof DexValueMethodHandle; 954 assert values[1] instanceof DexValueString; 955 assert values[2] instanceof DexValueMethodType; 956 957 return dexItemFactory.createCallSite( 958 ((DexValueString) values[1]).value, 959 ((DexValueMethodType) values[2]).value, 960 ((DexValueMethodHandle) values[0]).value, 961 // 3 means first extra args 962 Arrays.asList(Arrays.copyOfRange(values, 3, values.length))); 963 } 964 965 private DexProto protoAt(int index) { 966 Segment segment = lookupSegment(Constants.TYPE_PROTO_ID_ITEM); 967 if (index >= segment.length) { 968 return null; 969 } 970 int offset = segment.offset + (Constants.TYPE_PROTO_ID_ITEM_SIZE * index); 971 file.position(offset); 972 int shortyIndex = file.getUint(); 973 int returnTypeIndex = file.getUint(); 974 int parametersOffsetIndex = file.getUint(); 975 DexString shorty = indexedItems.getString(shortyIndex); 976 DexType returnType = indexedItems.getType(returnTypeIndex); 977 DexTypeList parameters = typeListAt(parametersOffsetIndex); 978 return dexItemFactory.createProto(shorty, returnType, parameters); 979 } 980 981 private DexMethod methodAt(int index) { 982 Segment segment = lookupSegment(Constants.TYPE_METHOD_ID_ITEM); 983 if (index >= segment.length) { 984 return null; 985 } 986 int offset = segment.offset + (Constants.TYPE_METHOD_ID_ITEM_SIZE * index); 987 file.position(offset); 988 int classIndex = file.getUshort(); 989 int protoIndex = file.getUshort(); 990 int nameIndex = file.getUint(); 991 return dexItemFactory.createMethod( 992 indexedItems.getType(classIndex), 993 indexedItems.getProto(protoIndex), 994 indexedItems.getString(nameIndex)); 995 } 996 997 private static class AnnotationsDirectory { 998 999 private static final DexParameterAnnotation[] NO_PARAMETER_ANNOTATIONS = 1000 new DexParameterAnnotation[0]; 1001 1002 private static final DexFieldAnnotation[] NO_FIELD_ANNOTATIONS = 1003 new DexFieldAnnotation[0]; 1004 1005 private static final DexMethodAnnotation[] NO_METHOD_ANNOTATIONS = 1006 new DexMethodAnnotation[0]; 1007 1008 private static final AnnotationsDirectory THE_EMPTY_ANNOTATIONS_DIRECTORY = 1009 new AnnotationsDirectory(DexAnnotationSet.empty(), 1010 NO_FIELD_ANNOTATIONS, new DexMethodAnnotation[0], 1011 NO_PARAMETER_ANNOTATIONS); 1012 1013 public final DexAnnotationSet clazz; 1014 public final DexFieldAnnotation[] fields; 1015 public final DexMethodAnnotation[] methods; 1016 public final DexParameterAnnotation[] parameters; 1017 1018 AnnotationsDirectory(DexAnnotationSet clazz, 1019 DexFieldAnnotation[] fields, 1020 DexMethodAnnotation[] methods, 1021 DexParameterAnnotation[] parameters) { 1022 this.clazz = clazz == null ? DexAnnotationSet.empty() : clazz; 1023 this.fields = fields == null ? NO_FIELD_ANNOTATIONS : fields; 1024 this.methods = methods == null ? NO_METHOD_ANNOTATIONS : methods; 1025 this.parameters = parameters == null ? NO_PARAMETER_ANNOTATIONS : parameters; 1026 } 1027 1028 public static AnnotationsDirectory empty() { 1029 return THE_EMPTY_ANNOTATIONS_DIRECTORY; 1030 } 1031 } 1032} 1033