1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * Implementation file of the dexdump utility. 17 * 18 * This is a re-implementation of the original dexdump utility that was 19 * based on Dalvik functions in libdex into a new dexdump that is now 20 * based on Art functions in libart instead. The output is very similar to 21 * to the original for correct DEX files. Error messages may differ, however. 22 * Also, ODEX files are no longer supported. 23 * 24 * The dexdump tool is intended to mimic objdump. When possible, use 25 * similar command-line arguments. 26 * 27 * Differences between XML output and the "current.xml" file: 28 * - classes in same package are not all grouped together; nothing is sorted 29 * - no "deprecated" on fields and methods 30 * - no parameter names 31 * - no generic signatures on parameters, e.g. type="java.lang.Class<?>" 32 * - class shows declared fields and methods; does not show inherited fields 33 */ 34 35 #include "dexdump.h" 36 37 #include <inttypes.h> 38 #include <stdio.h> 39 40 #include <memory> 41 #include <sstream> 42 #include <vector> 43 44 #include "android-base/file.h" 45 #include "android-base/logging.h" 46 #include "android-base/stringprintf.h" 47 48 #include "dex/code_item_accessors-inl.h" 49 #include "dex/dex_file-inl.h" 50 #include "dex/dex_file_exception_helpers.h" 51 #include "dex/dex_file_loader.h" 52 #include "dex/dex_file_types.h" 53 #include "dex/dex_instruction-inl.h" 54 #include "dexdump_cfg.h" 55 56 namespace art { 57 58 /* 59 * Options parsed in main driver. 60 */ 61 struct Options gOptions; 62 63 /* 64 * Output file. Defaults to stdout. 65 */ 66 FILE* gOutFile = stdout; 67 68 /* 69 * Data types that match the definitions in the VM specification. 70 */ 71 typedef uint8_t u1; 72 typedef uint16_t u2; 73 typedef uint32_t u4; 74 typedef uint64_t u8; 75 typedef int8_t s1; 76 typedef int16_t s2; 77 typedef int32_t s4; 78 typedef int64_t s8; 79 80 /* 81 * Basic information about a field or a method. 82 */ 83 struct FieldMethodInfo { 84 const char* classDescriptor; 85 const char* name; 86 const char* signature; 87 }; 88 89 /* 90 * Flags for use with createAccessFlagStr(). 91 */ 92 enum AccessFor { 93 kAccessForClass = 0, kAccessForMethod = 1, kAccessForField = 2, kAccessForMAX 94 }; 95 const int kNumFlags = 18; 96 97 /* 98 * Gets 2 little-endian bytes. 99 */ 100 static inline u2 get2LE(unsigned char const* pSrc) { 101 return pSrc[0] | (pSrc[1] << 8); 102 } 103 104 /* 105 * Converts a single-character primitive type into human-readable form. 106 */ 107 static const char* primitiveTypeLabel(char typeChar) { 108 switch (typeChar) { 109 case 'B': return "byte"; 110 case 'C': return "char"; 111 case 'D': return "double"; 112 case 'F': return "float"; 113 case 'I': return "int"; 114 case 'J': return "long"; 115 case 'S': return "short"; 116 case 'V': return "void"; 117 case 'Z': return "boolean"; 118 default: return "UNKNOWN"; 119 } // switch 120 } 121 122 /* 123 * Converts a type descriptor to human-readable "dotted" form. For 124 * example, "Ljava/lang/String;" becomes "java.lang.String", and 125 * "[I" becomes "int[]". Also converts '$' to '.', which means this 126 * form can't be converted back to a descriptor. 127 */ 128 static std::unique_ptr<char[]> descriptorToDot(const char* str) { 129 int targetLen = strlen(str); 130 int offset = 0; 131 132 // Strip leading [s; will be added to end. 133 while (targetLen > 1 && str[offset] == '[') { 134 offset++; 135 targetLen--; 136 } // while 137 138 const int arrayDepth = offset; 139 140 if (targetLen == 1) { 141 // Primitive type. 142 str = primitiveTypeLabel(str[offset]); 143 offset = 0; 144 targetLen = strlen(str); 145 } else { 146 // Account for leading 'L' and trailing ';'. 147 if (targetLen >= 2 && str[offset] == 'L' && 148 str[offset + targetLen - 1] == ';') { 149 targetLen -= 2; 150 offset++; 151 } 152 } 153 154 // Copy class name over. 155 std::unique_ptr<char[]> newStr(new char[targetLen + arrayDepth * 2 + 1]); 156 int i = 0; 157 for (; i < targetLen; i++) { 158 const char ch = str[offset + i]; 159 newStr[i] = (ch == '/' || ch == '$') ? '.' : ch; 160 } // for 161 162 // Add the appropriate number of brackets for arrays. 163 for (int j = 0; j < arrayDepth; j++) { 164 newStr[i++] = '['; 165 newStr[i++] = ']'; 166 } // for 167 168 newStr[i] = '\0'; 169 return newStr; 170 } 171 172 /* 173 * Converts the class name portion of a type descriptor to human-readable 174 * "dotted" form. For example, "Ljava/lang/String;" becomes "String". 175 */ 176 static std::unique_ptr<char[]> descriptorClassToDot(const char* str) { 177 // Reduce to just the class name prefix. 178 const char* lastSlash = strrchr(str, '/'); 179 if (lastSlash == nullptr) { 180 lastSlash = str + 1; // start past 'L' 181 } else { 182 lastSlash++; // start past '/' 183 } 184 185 // Copy class name over, trimming trailing ';'. 186 const int targetLen = strlen(lastSlash); 187 std::unique_ptr<char[]> newStr(new char[targetLen]); 188 for (int i = 0; i < targetLen - 1; i++) { 189 const char ch = lastSlash[i]; 190 newStr[i] = ch == '$' ? '.' : ch; 191 } // for 192 newStr[targetLen - 1] = '\0'; 193 return newStr; 194 } 195 196 /* 197 * Returns string representing the boolean value. 198 */ 199 static const char* strBool(bool val) { 200 return val ? "true" : "false"; 201 } 202 203 /* 204 * Returns a quoted string representing the boolean value. 205 */ 206 static const char* quotedBool(bool val) { 207 return val ? "\"true\"" : "\"false\""; 208 } 209 210 /* 211 * Returns a quoted string representing the access flags. 212 */ 213 static const char* quotedVisibility(u4 accessFlags) { 214 if (accessFlags & kAccPublic) { 215 return "\"public\""; 216 } else if (accessFlags & kAccProtected) { 217 return "\"protected\""; 218 } else if (accessFlags & kAccPrivate) { 219 return "\"private\""; 220 } else { 221 return "\"package\""; 222 } 223 } 224 225 /* 226 * Counts the number of '1' bits in a word. 227 */ 228 static int countOnes(u4 val) { 229 val = val - ((val >> 1) & 0x55555555); 230 val = (val & 0x33333333) + ((val >> 2) & 0x33333333); 231 return (((val + (val >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24; 232 } 233 234 /* 235 * Creates a new string with human-readable access flags. 236 * 237 * In the base language the access_flags fields are type u2; in Dalvik 238 * they're u4. 239 */ 240 static char* createAccessFlagStr(u4 flags, AccessFor forWhat) { 241 static const char* kAccessStrings[kAccessForMAX][kNumFlags] = { 242 { 243 "PUBLIC", /* 0x00001 */ 244 "PRIVATE", /* 0x00002 */ 245 "PROTECTED", /* 0x00004 */ 246 "STATIC", /* 0x00008 */ 247 "FINAL", /* 0x00010 */ 248 "?", /* 0x00020 */ 249 "?", /* 0x00040 */ 250 "?", /* 0x00080 */ 251 "?", /* 0x00100 */ 252 "INTERFACE", /* 0x00200 */ 253 "ABSTRACT", /* 0x00400 */ 254 "?", /* 0x00800 */ 255 "SYNTHETIC", /* 0x01000 */ 256 "ANNOTATION", /* 0x02000 */ 257 "ENUM", /* 0x04000 */ 258 "?", /* 0x08000 */ 259 "VERIFIED", /* 0x10000 */ 260 "OPTIMIZED", /* 0x20000 */ 261 }, { 262 "PUBLIC", /* 0x00001 */ 263 "PRIVATE", /* 0x00002 */ 264 "PROTECTED", /* 0x00004 */ 265 "STATIC", /* 0x00008 */ 266 "FINAL", /* 0x00010 */ 267 "SYNCHRONIZED", /* 0x00020 */ 268 "BRIDGE", /* 0x00040 */ 269 "VARARGS", /* 0x00080 */ 270 "NATIVE", /* 0x00100 */ 271 "?", /* 0x00200 */ 272 "ABSTRACT", /* 0x00400 */ 273 "STRICT", /* 0x00800 */ 274 "SYNTHETIC", /* 0x01000 */ 275 "?", /* 0x02000 */ 276 "?", /* 0x04000 */ 277 "MIRANDA", /* 0x08000 */ 278 "CONSTRUCTOR", /* 0x10000 */ 279 "DECLARED_SYNCHRONIZED", /* 0x20000 */ 280 }, { 281 "PUBLIC", /* 0x00001 */ 282 "PRIVATE", /* 0x00002 */ 283 "PROTECTED", /* 0x00004 */ 284 "STATIC", /* 0x00008 */ 285 "FINAL", /* 0x00010 */ 286 "?", /* 0x00020 */ 287 "VOLATILE", /* 0x00040 */ 288 "TRANSIENT", /* 0x00080 */ 289 "?", /* 0x00100 */ 290 "?", /* 0x00200 */ 291 "?", /* 0x00400 */ 292 "?", /* 0x00800 */ 293 "SYNTHETIC", /* 0x01000 */ 294 "?", /* 0x02000 */ 295 "ENUM", /* 0x04000 */ 296 "?", /* 0x08000 */ 297 "?", /* 0x10000 */ 298 "?", /* 0x20000 */ 299 }, 300 }; 301 302 // Allocate enough storage to hold the expected number of strings, 303 // plus a space between each. We over-allocate, using the longest 304 // string above as the base metric. 305 const int kLongest = 21; // The strlen of longest string above. 306 const int count = countOnes(flags); 307 char* str; 308 char* cp; 309 cp = str = reinterpret_cast<char*>(malloc(count * (kLongest + 1) + 1)); 310 311 for (int i = 0; i < kNumFlags; i++) { 312 if (flags & 0x01) { 313 const char* accessStr = kAccessStrings[forWhat][i]; 314 const int len = strlen(accessStr); 315 if (cp != str) { 316 *cp++ = ' '; 317 } 318 memcpy(cp, accessStr, len); 319 cp += len; 320 } 321 flags >>= 1; 322 } // for 323 324 *cp = '\0'; 325 return str; 326 } 327 328 /* 329 * Copies character data from "data" to "out", converting non-ASCII values 330 * to fprintf format chars or an ASCII filler ('.' or '?'). 331 * 332 * The output buffer must be able to hold (2*len)+1 bytes. The result is 333 * NULL-terminated. 334 */ 335 static void asciify(char* out, const unsigned char* data, size_t len) { 336 while (len--) { 337 if (*data < 0x20) { 338 // Could do more here, but we don't need them yet. 339 switch (*data) { 340 case '\0': 341 *out++ = '\\'; 342 *out++ = '0'; 343 break; 344 case '\n': 345 *out++ = '\\'; 346 *out++ = 'n'; 347 break; 348 default: 349 *out++ = '.'; 350 break; 351 } // switch 352 } else if (*data >= 0x80) { 353 *out++ = '?'; 354 } else { 355 *out++ = *data; 356 } 357 data++; 358 } // while 359 *out = '\0'; 360 } 361 362 /* 363 * Dumps a string value with some escape characters. 364 */ 365 static void dumpEscapedString(const char* p) { 366 fputs("\"", gOutFile); 367 for (; *p; p++) { 368 switch (*p) { 369 case '\\': 370 fputs("\\\\", gOutFile); 371 break; 372 case '\"': 373 fputs("\\\"", gOutFile); 374 break; 375 case '\t': 376 fputs("\\t", gOutFile); 377 break; 378 case '\n': 379 fputs("\\n", gOutFile); 380 break; 381 case '\r': 382 fputs("\\r", gOutFile); 383 break; 384 default: 385 putc(*p, gOutFile); 386 } // switch 387 } // for 388 fputs("\"", gOutFile); 389 } 390 391 /* 392 * Dumps a string as an XML attribute value. 393 */ 394 static void dumpXmlAttribute(const char* p) { 395 for (; *p; p++) { 396 switch (*p) { 397 case '&': 398 fputs("&", gOutFile); 399 break; 400 case '<': 401 fputs("<", gOutFile); 402 break; 403 case '>': 404 fputs(">", gOutFile); 405 break; 406 case '"': 407 fputs(""", gOutFile); 408 break; 409 case '\t': 410 fputs("	", gOutFile); 411 break; 412 case '\n': 413 fputs("
", gOutFile); 414 break; 415 case '\r': 416 fputs("
", gOutFile); 417 break; 418 default: 419 putc(*p, gOutFile); 420 } // switch 421 } // for 422 } 423 424 /* 425 * Reads variable width value, possibly sign extended at the last defined byte. 426 */ 427 static u8 readVarWidth(const u1** data, u1 arg, bool sign_extend) { 428 u8 value = 0; 429 for (u4 i = 0; i <= arg; i++) { 430 value |= static_cast<u8>(*(*data)++) << (i * 8); 431 } 432 if (sign_extend) { 433 int shift = (7 - arg) * 8; 434 return (static_cast<s8>(value) << shift) >> shift; 435 } 436 return value; 437 } 438 439 /* 440 * Dumps encoded value. 441 */ 442 static void dumpEncodedValue(const DexFile* pDexFile, const u1** data); // forward 443 static void dumpEncodedValue(const DexFile* pDexFile, const u1** data, u1 type, u1 arg) { 444 switch (type) { 445 case DexFile::kDexAnnotationByte: 446 fprintf(gOutFile, "%" PRId8, static_cast<s1>(readVarWidth(data, arg, false))); 447 break; 448 case DexFile::kDexAnnotationShort: 449 fprintf(gOutFile, "%" PRId16, static_cast<s2>(readVarWidth(data, arg, true))); 450 break; 451 case DexFile::kDexAnnotationChar: 452 fprintf(gOutFile, "%" PRIu16, static_cast<u2>(readVarWidth(data, arg, false))); 453 break; 454 case DexFile::kDexAnnotationInt: 455 fprintf(gOutFile, "%" PRId32, static_cast<s4>(readVarWidth(data, arg, true))); 456 break; 457 case DexFile::kDexAnnotationLong: 458 fprintf(gOutFile, "%" PRId64, static_cast<s8>(readVarWidth(data, arg, true))); 459 break; 460 case DexFile::kDexAnnotationFloat: { 461 // Fill on right. 462 union { 463 float f; 464 u4 data; 465 } conv; 466 conv.data = static_cast<u4>(readVarWidth(data, arg, false)) << (3 - arg) * 8; 467 fprintf(gOutFile, "%g", conv.f); 468 break; 469 } 470 case DexFile::kDexAnnotationDouble: { 471 // Fill on right. 472 union { 473 double d; 474 u8 data; 475 } conv; 476 conv.data = readVarWidth(data, arg, false) << (7 - arg) * 8; 477 fprintf(gOutFile, "%g", conv.d); 478 break; 479 } 480 case DexFile::kDexAnnotationString: { 481 const u4 idx = static_cast<u4>(readVarWidth(data, arg, false)); 482 if (gOptions.outputFormat == OUTPUT_PLAIN) { 483 dumpEscapedString(pDexFile->StringDataByIdx(dex::StringIndex(idx))); 484 } else { 485 dumpXmlAttribute(pDexFile->StringDataByIdx(dex::StringIndex(idx))); 486 } 487 break; 488 } 489 case DexFile::kDexAnnotationType: { 490 const u4 str_idx = static_cast<u4>(readVarWidth(data, arg, false)); 491 fputs(pDexFile->StringByTypeIdx(dex::TypeIndex(str_idx)), gOutFile); 492 break; 493 } 494 case DexFile::kDexAnnotationField: 495 case DexFile::kDexAnnotationEnum: { 496 const u4 field_idx = static_cast<u4>(readVarWidth(data, arg, false)); 497 const DexFile::FieldId& pFieldId = pDexFile->GetFieldId(field_idx); 498 fputs(pDexFile->StringDataByIdx(pFieldId.name_idx_), gOutFile); 499 break; 500 } 501 case DexFile::kDexAnnotationMethod: { 502 const u4 method_idx = static_cast<u4>(readVarWidth(data, arg, false)); 503 const DexFile::MethodId& pMethodId = pDexFile->GetMethodId(method_idx); 504 fputs(pDexFile->StringDataByIdx(pMethodId.name_idx_), gOutFile); 505 break; 506 } 507 case DexFile::kDexAnnotationArray: { 508 fputc('{', gOutFile); 509 // Decode and display all elements. 510 const u4 size = DecodeUnsignedLeb128(data); 511 for (u4 i = 0; i < size; i++) { 512 fputc(' ', gOutFile); 513 dumpEncodedValue(pDexFile, data); 514 } 515 fputs(" }", gOutFile); 516 break; 517 } 518 case DexFile::kDexAnnotationAnnotation: { 519 const u4 type_idx = DecodeUnsignedLeb128(data); 520 fputs(pDexFile->StringByTypeIdx(dex::TypeIndex(type_idx)), gOutFile); 521 // Decode and display all name=value pairs. 522 const u4 size = DecodeUnsignedLeb128(data); 523 for (u4 i = 0; i < size; i++) { 524 const u4 name_idx = DecodeUnsignedLeb128(data); 525 fputc(' ', gOutFile); 526 fputs(pDexFile->StringDataByIdx(dex::StringIndex(name_idx)), gOutFile); 527 fputc('=', gOutFile); 528 dumpEncodedValue(pDexFile, data); 529 } 530 break; 531 } 532 case DexFile::kDexAnnotationNull: 533 fputs("null", gOutFile); 534 break; 535 case DexFile::kDexAnnotationBoolean: 536 fputs(strBool(arg), gOutFile); 537 break; 538 default: 539 fputs("????", gOutFile); 540 break; 541 } // switch 542 } 543 544 /* 545 * Dumps encoded value with prefix. 546 */ 547 static void dumpEncodedValue(const DexFile* pDexFile, const u1** data) { 548 const u1 enc = *(*data)++; 549 dumpEncodedValue(pDexFile, data, enc & 0x1f, enc >> 5); 550 } 551 552 /* 553 * Dumps the file header. 554 */ 555 static void dumpFileHeader(const DexFile* pDexFile) { 556 const DexFile::Header& pHeader = pDexFile->GetHeader(); 557 char sanitized[sizeof(pHeader.magic_) * 2 + 1]; 558 fprintf(gOutFile, "DEX file header:\n"); 559 asciify(sanitized, pHeader.magic_, sizeof(pHeader.magic_)); 560 fprintf(gOutFile, "magic : '%s'\n", sanitized); 561 fprintf(gOutFile, "checksum : %08x\n", pHeader.checksum_); 562 fprintf(gOutFile, "signature : %02x%02x...%02x%02x\n", 563 pHeader.signature_[0], pHeader.signature_[1], 564 pHeader.signature_[DexFile::kSha1DigestSize - 2], 565 pHeader.signature_[DexFile::kSha1DigestSize - 1]); 566 fprintf(gOutFile, "file_size : %d\n", pHeader.file_size_); 567 fprintf(gOutFile, "header_size : %d\n", pHeader.header_size_); 568 fprintf(gOutFile, "link_size : %d\n", pHeader.link_size_); 569 fprintf(gOutFile, "link_off : %d (0x%06x)\n", 570 pHeader.link_off_, pHeader.link_off_); 571 fprintf(gOutFile, "string_ids_size : %d\n", pHeader.string_ids_size_); 572 fprintf(gOutFile, "string_ids_off : %d (0x%06x)\n", 573 pHeader.string_ids_off_, pHeader.string_ids_off_); 574 fprintf(gOutFile, "type_ids_size : %d\n", pHeader.type_ids_size_); 575 fprintf(gOutFile, "type_ids_off : %d (0x%06x)\n", 576 pHeader.type_ids_off_, pHeader.type_ids_off_); 577 fprintf(gOutFile, "proto_ids_size : %d\n", pHeader.proto_ids_size_); 578 fprintf(gOutFile, "proto_ids_off : %d (0x%06x)\n", 579 pHeader.proto_ids_off_, pHeader.proto_ids_off_); 580 fprintf(gOutFile, "field_ids_size : %d\n", pHeader.field_ids_size_); 581 fprintf(gOutFile, "field_ids_off : %d (0x%06x)\n", 582 pHeader.field_ids_off_, pHeader.field_ids_off_); 583 fprintf(gOutFile, "method_ids_size : %d\n", pHeader.method_ids_size_); 584 fprintf(gOutFile, "method_ids_off : %d (0x%06x)\n", 585 pHeader.method_ids_off_, pHeader.method_ids_off_); 586 fprintf(gOutFile, "class_defs_size : %d\n", pHeader.class_defs_size_); 587 fprintf(gOutFile, "class_defs_off : %d (0x%06x)\n", 588 pHeader.class_defs_off_, pHeader.class_defs_off_); 589 fprintf(gOutFile, "data_size : %d\n", pHeader.data_size_); 590 fprintf(gOutFile, "data_off : %d (0x%06x)\n\n", 591 pHeader.data_off_, pHeader.data_off_); 592 } 593 594 /* 595 * Dumps a class_def_item. 596 */ 597 static void dumpClassDef(const DexFile* pDexFile, int idx) { 598 // General class information. 599 const DexFile::ClassDef& pClassDef = pDexFile->GetClassDef(idx); 600 fprintf(gOutFile, "Class #%d header:\n", idx); 601 fprintf(gOutFile, "class_idx : %d\n", pClassDef.class_idx_.index_); 602 fprintf(gOutFile, "access_flags : %d (0x%04x)\n", 603 pClassDef.access_flags_, pClassDef.access_flags_); 604 fprintf(gOutFile, "superclass_idx : %d\n", pClassDef.superclass_idx_.index_); 605 fprintf(gOutFile, "interfaces_off : %d (0x%06x)\n", 606 pClassDef.interfaces_off_, pClassDef.interfaces_off_); 607 fprintf(gOutFile, "source_file_idx : %d\n", pClassDef.source_file_idx_.index_); 608 fprintf(gOutFile, "annotations_off : %d (0x%06x)\n", 609 pClassDef.annotations_off_, pClassDef.annotations_off_); 610 fprintf(gOutFile, "class_data_off : %d (0x%06x)\n", 611 pClassDef.class_data_off_, pClassDef.class_data_off_); 612 613 // Fields and methods. 614 const u1* pEncodedData = pDexFile->GetClassData(pClassDef); 615 if (pEncodedData != nullptr) { 616 ClassDataItemIterator pClassData(*pDexFile, pEncodedData); 617 fprintf(gOutFile, "static_fields_size : %d\n", pClassData.NumStaticFields()); 618 fprintf(gOutFile, "instance_fields_size: %d\n", pClassData.NumInstanceFields()); 619 fprintf(gOutFile, "direct_methods_size : %d\n", pClassData.NumDirectMethods()); 620 fprintf(gOutFile, "virtual_methods_size: %d\n", pClassData.NumVirtualMethods()); 621 } else { 622 fprintf(gOutFile, "static_fields_size : 0\n"); 623 fprintf(gOutFile, "instance_fields_size: 0\n"); 624 fprintf(gOutFile, "direct_methods_size : 0\n"); 625 fprintf(gOutFile, "virtual_methods_size: 0\n"); 626 } 627 fprintf(gOutFile, "\n"); 628 } 629 630 /** 631 * Dumps an annotation set item. 632 */ 633 static void dumpAnnotationSetItem(const DexFile* pDexFile, const DexFile::AnnotationSetItem* set_item) { 634 if (set_item == nullptr || set_item->size_ == 0) { 635 fputs(" empty-annotation-set\n", gOutFile); 636 return; 637 } 638 for (u4 i = 0; i < set_item->size_; i++) { 639 const DexFile::AnnotationItem* annotation = pDexFile->GetAnnotationItem(set_item, i); 640 if (annotation == nullptr) { 641 continue; 642 } 643 fputs(" ", gOutFile); 644 switch (annotation->visibility_) { 645 case DexFile::kDexVisibilityBuild: fputs("VISIBILITY_BUILD ", gOutFile); break; 646 case DexFile::kDexVisibilityRuntime: fputs("VISIBILITY_RUNTIME ", gOutFile); break; 647 case DexFile::kDexVisibilitySystem: fputs("VISIBILITY_SYSTEM ", gOutFile); break; 648 default: fputs("VISIBILITY_UNKNOWN ", gOutFile); break; 649 } // switch 650 // Decode raw bytes in annotation. 651 const u1* rData = annotation->annotation_; 652 dumpEncodedValue(pDexFile, &rData, DexFile::kDexAnnotationAnnotation, 0); 653 fputc('\n', gOutFile); 654 } 655 } 656 657 /* 658 * Dumps class annotations. 659 */ 660 static void dumpClassAnnotations(const DexFile* pDexFile, int idx) { 661 const DexFile::ClassDef& pClassDef = pDexFile->GetClassDef(idx); 662 const DexFile::AnnotationsDirectoryItem* dir = pDexFile->GetAnnotationsDirectory(pClassDef); 663 if (dir == nullptr) { 664 return; // none 665 } 666 667 fprintf(gOutFile, "Class #%d annotations:\n", idx); 668 669 const DexFile::AnnotationSetItem* class_set_item = pDexFile->GetClassAnnotationSet(dir); 670 const DexFile::FieldAnnotationsItem* fields = pDexFile->GetFieldAnnotations(dir); 671 const DexFile::MethodAnnotationsItem* methods = pDexFile->GetMethodAnnotations(dir); 672 const DexFile::ParameterAnnotationsItem* pars = pDexFile->GetParameterAnnotations(dir); 673 674 // Annotations on the class itself. 675 if (class_set_item != nullptr) { 676 fprintf(gOutFile, "Annotations on class\n"); 677 dumpAnnotationSetItem(pDexFile, class_set_item); 678 } 679 680 // Annotations on fields. 681 if (fields != nullptr) { 682 for (u4 i = 0; i < dir->fields_size_; i++) { 683 const u4 field_idx = fields[i].field_idx_; 684 const DexFile::FieldId& pFieldId = pDexFile->GetFieldId(field_idx); 685 const char* field_name = pDexFile->StringDataByIdx(pFieldId.name_idx_); 686 fprintf(gOutFile, "Annotations on field #%u '%s'\n", field_idx, field_name); 687 dumpAnnotationSetItem(pDexFile, pDexFile->GetFieldAnnotationSetItem(fields[i])); 688 } 689 } 690 691 // Annotations on methods. 692 if (methods != nullptr) { 693 for (u4 i = 0; i < dir->methods_size_; i++) { 694 const u4 method_idx = methods[i].method_idx_; 695 const DexFile::MethodId& pMethodId = pDexFile->GetMethodId(method_idx); 696 const char* method_name = pDexFile->StringDataByIdx(pMethodId.name_idx_); 697 fprintf(gOutFile, "Annotations on method #%u '%s'\n", method_idx, method_name); 698 dumpAnnotationSetItem(pDexFile, pDexFile->GetMethodAnnotationSetItem(methods[i])); 699 } 700 } 701 702 // Annotations on method parameters. 703 if (pars != nullptr) { 704 for (u4 i = 0; i < dir->parameters_size_; i++) { 705 const u4 method_idx = pars[i].method_idx_; 706 const DexFile::MethodId& pMethodId = pDexFile->GetMethodId(method_idx); 707 const char* method_name = pDexFile->StringDataByIdx(pMethodId.name_idx_); 708 fprintf(gOutFile, "Annotations on method #%u '%s' parameters\n", method_idx, method_name); 709 const DexFile::AnnotationSetRefList* 710 list = pDexFile->GetParameterAnnotationSetRefList(&pars[i]); 711 if (list != nullptr) { 712 for (u4 j = 0; j < list->size_; j++) { 713 fprintf(gOutFile, "#%u\n", j); 714 dumpAnnotationSetItem(pDexFile, pDexFile->GetSetRefItemItem(&list->list_[j])); 715 } 716 } 717 } 718 } 719 720 fputc('\n', gOutFile); 721 } 722 723 /* 724 * Dumps an interface that a class declares to implement. 725 */ 726 static void dumpInterface(const DexFile* pDexFile, const DexFile::TypeItem& pTypeItem, int i) { 727 const char* interfaceName = pDexFile->StringByTypeIdx(pTypeItem.type_idx_); 728 if (gOptions.outputFormat == OUTPUT_PLAIN) { 729 fprintf(gOutFile, " #%d : '%s'\n", i, interfaceName); 730 } else { 731 std::unique_ptr<char[]> dot(descriptorToDot(interfaceName)); 732 fprintf(gOutFile, "<implements name=\"%s\">\n</implements>\n", dot.get()); 733 } 734 } 735 736 /* 737 * Dumps the catches table associated with the code. 738 */ 739 static void dumpCatches(const DexFile* pDexFile, const DexFile::CodeItem* pCode) { 740 CodeItemDataAccessor accessor(*pDexFile, pCode); 741 const u4 triesSize = accessor.TriesSize(); 742 743 // No catch table. 744 if (triesSize == 0) { 745 fprintf(gOutFile, " catches : (none)\n"); 746 return; 747 } 748 749 // Dump all table entries. 750 fprintf(gOutFile, " catches : %d\n", triesSize); 751 for (const DexFile::TryItem& try_item : accessor.TryItems()) { 752 const u4 start = try_item.start_addr_; 753 const u4 end = start + try_item.insn_count_; 754 fprintf(gOutFile, " 0x%04x - 0x%04x\n", start, end); 755 for (CatchHandlerIterator it(accessor, try_item); it.HasNext(); it.Next()) { 756 const dex::TypeIndex tidx = it.GetHandlerTypeIndex(); 757 const char* descriptor = (!tidx.IsValid()) ? "<any>" : pDexFile->StringByTypeIdx(tidx); 758 fprintf(gOutFile, " %s -> 0x%04x\n", descriptor, it.GetHandlerAddress()); 759 } // for 760 } // for 761 } 762 763 /* 764 * Callback for dumping each positions table entry. 765 */ 766 static bool dumpPositionsCb(void* /*context*/, const DexFile::PositionInfo& entry) { 767 fprintf(gOutFile, " 0x%04x line=%d\n", entry.address_, entry.line_); 768 return false; 769 } 770 771 /* 772 * Callback for dumping locals table entry. 773 */ 774 static void dumpLocalsCb(void* /*context*/, const DexFile::LocalInfo& entry) { 775 const char* signature = entry.signature_ != nullptr ? entry.signature_ : ""; 776 fprintf(gOutFile, " 0x%04x - 0x%04x reg=%d %s %s %s\n", 777 entry.start_address_, entry.end_address_, entry.reg_, 778 entry.name_, entry.descriptor_, signature); 779 } 780 781 /* 782 * Helper for dumpInstruction(), which builds the string 783 * representation for the index in the given instruction. 784 * Returns a pointer to a buffer of sufficient size. 785 */ 786 static std::unique_ptr<char[]> indexString(const DexFile* pDexFile, 787 const Instruction* pDecInsn, 788 size_t bufSize) { 789 static const u4 kInvalidIndex = std::numeric_limits<u4>::max(); 790 std::unique_ptr<char[]> buf(new char[bufSize]); 791 // Determine index and width of the string. 792 u4 index = 0; 793 u4 secondary_index = kInvalidIndex; 794 u4 width = 4; 795 switch (Instruction::FormatOf(pDecInsn->Opcode())) { 796 // SOME NOT SUPPORTED: 797 // case Instruction::k20bc: 798 case Instruction::k21c: 799 case Instruction::k35c: 800 // case Instruction::k35ms: 801 case Instruction::k3rc: 802 // case Instruction::k3rms: 803 // case Instruction::k35mi: 804 // case Instruction::k3rmi: 805 index = pDecInsn->VRegB(); 806 width = 4; 807 break; 808 case Instruction::k31c: 809 index = pDecInsn->VRegB(); 810 width = 8; 811 break; 812 case Instruction::k22c: 813 // case Instruction::k22cs: 814 index = pDecInsn->VRegC(); 815 width = 4; 816 break; 817 case Instruction::k45cc: 818 case Instruction::k4rcc: 819 index = pDecInsn->VRegB(); 820 secondary_index = pDecInsn->VRegH(); 821 width = 4; 822 break; 823 default: 824 break; 825 } // switch 826 827 // Determine index type. 828 size_t outSize = 0; 829 switch (Instruction::IndexTypeOf(pDecInsn->Opcode())) { 830 case Instruction::kIndexUnknown: 831 // This function should never get called for this type, but do 832 // something sensible here, just to help with debugging. 833 outSize = snprintf(buf.get(), bufSize, "<unknown-index>"); 834 break; 835 case Instruction::kIndexNone: 836 // This function should never get called for this type, but do 837 // something sensible here, just to help with debugging. 838 outSize = snprintf(buf.get(), bufSize, "<no-index>"); 839 break; 840 case Instruction::kIndexTypeRef: 841 if (index < pDexFile->GetHeader().type_ids_size_) { 842 const char* tp = pDexFile->StringByTypeIdx(dex::TypeIndex(index)); 843 outSize = snprintf(buf.get(), bufSize, "%s // type@%0*x", tp, width, index); 844 } else { 845 outSize = snprintf(buf.get(), bufSize, "<type?> // type@%0*x", width, index); 846 } 847 break; 848 case Instruction::kIndexStringRef: 849 if (index < pDexFile->GetHeader().string_ids_size_) { 850 const char* st = pDexFile->StringDataByIdx(dex::StringIndex(index)); 851 outSize = snprintf(buf.get(), bufSize, "\"%s\" // string@%0*x", st, width, index); 852 } else { 853 outSize = snprintf(buf.get(), bufSize, "<string?> // string@%0*x", width, index); 854 } 855 break; 856 case Instruction::kIndexMethodRef: 857 if (index < pDexFile->GetHeader().method_ids_size_) { 858 const DexFile::MethodId& pMethodId = pDexFile->GetMethodId(index); 859 const char* name = pDexFile->StringDataByIdx(pMethodId.name_idx_); 860 const Signature signature = pDexFile->GetMethodSignature(pMethodId); 861 const char* backDescriptor = pDexFile->StringByTypeIdx(pMethodId.class_idx_); 862 outSize = snprintf(buf.get(), bufSize, "%s.%s:%s // method@%0*x", 863 backDescriptor, name, signature.ToString().c_str(), width, index); 864 } else { 865 outSize = snprintf(buf.get(), bufSize, "<method?> // method@%0*x", width, index); 866 } 867 break; 868 case Instruction::kIndexFieldRef: 869 if (index < pDexFile->GetHeader().field_ids_size_) { 870 const DexFile::FieldId& pFieldId = pDexFile->GetFieldId(index); 871 const char* name = pDexFile->StringDataByIdx(pFieldId.name_idx_); 872 const char* typeDescriptor = pDexFile->StringByTypeIdx(pFieldId.type_idx_); 873 const char* backDescriptor = pDexFile->StringByTypeIdx(pFieldId.class_idx_); 874 outSize = snprintf(buf.get(), bufSize, "%s.%s:%s // field@%0*x", 875 backDescriptor, name, typeDescriptor, width, index); 876 } else { 877 outSize = snprintf(buf.get(), bufSize, "<field?> // field@%0*x", width, index); 878 } 879 break; 880 case Instruction::kIndexVtableOffset: 881 outSize = snprintf(buf.get(), bufSize, "[%0*x] // vtable #%0*x", 882 width, index, width, index); 883 break; 884 case Instruction::kIndexFieldOffset: 885 outSize = snprintf(buf.get(), bufSize, "[obj+%0*x]", width, index); 886 break; 887 case Instruction::kIndexMethodAndProtoRef: { 888 std::string method("<method?>"); 889 std::string proto("<proto?>"); 890 if (index < pDexFile->GetHeader().method_ids_size_) { 891 const DexFile::MethodId& pMethodId = pDexFile->GetMethodId(index); 892 const char* name = pDexFile->StringDataByIdx(pMethodId.name_idx_); 893 const Signature signature = pDexFile->GetMethodSignature(pMethodId); 894 const char* backDescriptor = pDexFile->StringByTypeIdx(pMethodId.class_idx_); 895 method = android::base::StringPrintf("%s.%s:%s", 896 backDescriptor, 897 name, 898 signature.ToString().c_str()); 899 } 900 if (secondary_index < pDexFile->GetHeader().proto_ids_size_) { 901 const DexFile::ProtoId& protoId = pDexFile->GetProtoId(secondary_index); 902 const Signature signature = pDexFile->GetProtoSignature(protoId); 903 proto = signature.ToString(); 904 } 905 outSize = snprintf(buf.get(), bufSize, "%s, %s // method@%0*x, proto@%0*x", 906 method.c_str(), proto.c_str(), width, index, width, secondary_index); 907 break; 908 } 909 case Instruction::kIndexCallSiteRef: 910 // Call site information is too large to detail in disassembly so just output the index. 911 outSize = snprintf(buf.get(), bufSize, "call_site@%0*x", width, index); 912 break; 913 case Instruction::kIndexMethodHandleRef: 914 // Method handle information is too large to detail in disassembly so just output the index. 915 outSize = snprintf(buf.get(), bufSize, "method_handle@%0*x", width, index); 916 break; 917 case Instruction::kIndexProtoRef: 918 if (index < pDexFile->GetHeader().proto_ids_size_) { 919 const DexFile::ProtoId& protoId = pDexFile->GetProtoId(index); 920 const Signature signature = pDexFile->GetProtoSignature(protoId); 921 const std::string& proto = signature.ToString(); 922 outSize = snprintf(buf.get(), bufSize, "%s // proto@%0*x", proto.c_str(), width, index); 923 } else { 924 outSize = snprintf(buf.get(), bufSize, "<?> // proto@%0*x", width, index); 925 } 926 break; 927 } // switch 928 929 if (outSize == 0) { 930 // The index type has not been handled in the switch above. 931 outSize = snprintf(buf.get(), bufSize, "<?>"); 932 } 933 934 // Determine success of string construction. 935 if (outSize >= bufSize) { 936 // The buffer wasn't big enough; retry with computed size. Note: snprintf() 937 // doesn't count/ the '\0' as part of its returned size, so we add explicit 938 // space for it here. 939 return indexString(pDexFile, pDecInsn, outSize + 1); 940 } 941 return buf; 942 } 943 944 /* 945 * Dumps a single instruction. 946 */ 947 static void dumpInstruction(const DexFile* pDexFile, 948 const DexFile::CodeItem* pCode, 949 u4 codeOffset, u4 insnIdx, u4 insnWidth, 950 const Instruction* pDecInsn) { 951 // Address of instruction (expressed as byte offset). 952 fprintf(gOutFile, "%06x:", codeOffset + 0x10 + insnIdx * 2); 953 954 // Dump (part of) raw bytes. 955 CodeItemInstructionAccessor accessor(*pDexFile, pCode); 956 for (u4 i = 0; i < 8; i++) { 957 if (i < insnWidth) { 958 if (i == 7) { 959 fprintf(gOutFile, " ... "); 960 } else { 961 // Print 16-bit value in little-endian order. 962 const u1* bytePtr = (const u1*) &accessor.Insns()[insnIdx + i]; 963 fprintf(gOutFile, " %02x%02x", bytePtr[0], bytePtr[1]); 964 } 965 } else { 966 fputs(" ", gOutFile); 967 } 968 } // for 969 970 // Dump pseudo-instruction or opcode. 971 if (pDecInsn->Opcode() == Instruction::NOP) { 972 const u2 instr = get2LE((const u1*) &accessor.Insns()[insnIdx]); 973 if (instr == Instruction::kPackedSwitchSignature) { 974 fprintf(gOutFile, "|%04x: packed-switch-data (%d units)", insnIdx, insnWidth); 975 } else if (instr == Instruction::kSparseSwitchSignature) { 976 fprintf(gOutFile, "|%04x: sparse-switch-data (%d units)", insnIdx, insnWidth); 977 } else if (instr == Instruction::kArrayDataSignature) { 978 fprintf(gOutFile, "|%04x: array-data (%d units)", insnIdx, insnWidth); 979 } else { 980 fprintf(gOutFile, "|%04x: nop // spacer", insnIdx); 981 } 982 } else { 983 fprintf(gOutFile, "|%04x: %s", insnIdx, pDecInsn->Name()); 984 } 985 986 // Set up additional argument. 987 std::unique_ptr<char[]> indexBuf; 988 if (Instruction::IndexTypeOf(pDecInsn->Opcode()) != Instruction::kIndexNone) { 989 indexBuf = indexString(pDexFile, pDecInsn, 200); 990 } 991 992 // Dump the instruction. 993 // 994 // NOTE: pDecInsn->DumpString(pDexFile) differs too much from original. 995 // 996 switch (Instruction::FormatOf(pDecInsn->Opcode())) { 997 case Instruction::k10x: // op 998 break; 999 case Instruction::k12x: // op vA, vB 1000 fprintf(gOutFile, " v%d, v%d", pDecInsn->VRegA(), pDecInsn->VRegB()); 1001 break; 1002 case Instruction::k11n: // op vA, #+B 1003 fprintf(gOutFile, " v%d, #int %d // #%x", 1004 pDecInsn->VRegA(), (s4) pDecInsn->VRegB(), (u1)pDecInsn->VRegB()); 1005 break; 1006 case Instruction::k11x: // op vAA 1007 fprintf(gOutFile, " v%d", pDecInsn->VRegA()); 1008 break; 1009 case Instruction::k10t: // op +AA 1010 case Instruction::k20t: { // op +AAAA 1011 const s4 targ = (s4) pDecInsn->VRegA(); 1012 fprintf(gOutFile, " %04x // %c%04x", 1013 insnIdx + targ, 1014 (targ < 0) ? '-' : '+', 1015 (targ < 0) ? -targ : targ); 1016 break; 1017 } 1018 case Instruction::k22x: // op vAA, vBBBB 1019 fprintf(gOutFile, " v%d, v%d", pDecInsn->VRegA(), pDecInsn->VRegB()); 1020 break; 1021 case Instruction::k21t: { // op vAA, +BBBB 1022 const s4 targ = (s4) pDecInsn->VRegB(); 1023 fprintf(gOutFile, " v%d, %04x // %c%04x", pDecInsn->VRegA(), 1024 insnIdx + targ, 1025 (targ < 0) ? '-' : '+', 1026 (targ < 0) ? -targ : targ); 1027 break; 1028 } 1029 case Instruction::k21s: // op vAA, #+BBBB 1030 fprintf(gOutFile, " v%d, #int %d // #%x", 1031 pDecInsn->VRegA(), (s4) pDecInsn->VRegB(), (u2)pDecInsn->VRegB()); 1032 break; 1033 case Instruction::k21h: // op vAA, #+BBBB0000[00000000] 1034 // The printed format varies a bit based on the actual opcode. 1035 if (pDecInsn->Opcode() == Instruction::CONST_HIGH16) { 1036 const s4 value = pDecInsn->VRegB() << 16; 1037 fprintf(gOutFile, " v%d, #int %d // #%x", 1038 pDecInsn->VRegA(), value, (u2) pDecInsn->VRegB()); 1039 } else { 1040 const s8 value = ((s8) pDecInsn->VRegB()) << 48; 1041 fprintf(gOutFile, " v%d, #long %" PRId64 " // #%x", 1042 pDecInsn->VRegA(), value, (u2) pDecInsn->VRegB()); 1043 } 1044 break; 1045 case Instruction::k21c: // op vAA, thing@BBBB 1046 case Instruction::k31c: // op vAA, thing@BBBBBBBB 1047 fprintf(gOutFile, " v%d, %s", pDecInsn->VRegA(), indexBuf.get()); 1048 break; 1049 case Instruction::k23x: // op vAA, vBB, vCC 1050 fprintf(gOutFile, " v%d, v%d, v%d", 1051 pDecInsn->VRegA(), pDecInsn->VRegB(), pDecInsn->VRegC()); 1052 break; 1053 case Instruction::k22b: // op vAA, vBB, #+CC 1054 fprintf(gOutFile, " v%d, v%d, #int %d // #%02x", 1055 pDecInsn->VRegA(), pDecInsn->VRegB(), 1056 (s4) pDecInsn->VRegC(), (u1) pDecInsn->VRegC()); 1057 break; 1058 case Instruction::k22t: { // op vA, vB, +CCCC 1059 const s4 targ = (s4) pDecInsn->VRegC(); 1060 fprintf(gOutFile, " v%d, v%d, %04x // %c%04x", 1061 pDecInsn->VRegA(), pDecInsn->VRegB(), 1062 insnIdx + targ, 1063 (targ < 0) ? '-' : '+', 1064 (targ < 0) ? -targ : targ); 1065 break; 1066 } 1067 case Instruction::k22s: // op vA, vB, #+CCCC 1068 fprintf(gOutFile, " v%d, v%d, #int %d // #%04x", 1069 pDecInsn->VRegA(), pDecInsn->VRegB(), 1070 (s4) pDecInsn->VRegC(), (u2) pDecInsn->VRegC()); 1071 break; 1072 case Instruction::k22c: // op vA, vB, thing@CCCC 1073 // NOT SUPPORTED: 1074 // case Instruction::k22cs: // [opt] op vA, vB, field offset CCCC 1075 fprintf(gOutFile, " v%d, v%d, %s", 1076 pDecInsn->VRegA(), pDecInsn->VRegB(), indexBuf.get()); 1077 break; 1078 case Instruction::k30t: 1079 fprintf(gOutFile, " #%08x", pDecInsn->VRegA()); 1080 break; 1081 case Instruction::k31i: { // op vAA, #+BBBBBBBB 1082 // This is often, but not always, a float. 1083 union { 1084 float f; 1085 u4 i; 1086 } conv; 1087 conv.i = pDecInsn->VRegB(); 1088 fprintf(gOutFile, " v%d, #float %g // #%08x", 1089 pDecInsn->VRegA(), conv.f, pDecInsn->VRegB()); 1090 break; 1091 } 1092 case Instruction::k31t: // op vAA, offset +BBBBBBBB 1093 fprintf(gOutFile, " v%d, %08x // +%08x", 1094 pDecInsn->VRegA(), insnIdx + pDecInsn->VRegB(), pDecInsn->VRegB()); 1095 break; 1096 case Instruction::k32x: // op vAAAA, vBBBB 1097 fprintf(gOutFile, " v%d, v%d", pDecInsn->VRegA(), pDecInsn->VRegB()); 1098 break; 1099 case Instruction::k35c: // op {vC, vD, vE, vF, vG}, thing@BBBB 1100 case Instruction::k45cc: { // op {vC, vD, vE, vF, vG}, method@BBBB, proto@HHHH 1101 // NOT SUPPORTED: 1102 // case Instruction::k35ms: // [opt] invoke-virtual+super 1103 // case Instruction::k35mi: // [opt] inline invoke 1104 u4 arg[Instruction::kMaxVarArgRegs]; 1105 pDecInsn->GetVarArgs(arg); 1106 fputs(" {", gOutFile); 1107 for (int i = 0, n = pDecInsn->VRegA(); i < n; i++) { 1108 if (i == 0) { 1109 fprintf(gOutFile, "v%d", arg[i]); 1110 } else { 1111 fprintf(gOutFile, ", v%d", arg[i]); 1112 } 1113 } // for 1114 fprintf(gOutFile, "}, %s", indexBuf.get()); 1115 break; 1116 } 1117 case Instruction::k3rc: // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB 1118 case Instruction::k4rcc: { // op {vCCCC .. v(CCCC+AA-1)}, method@BBBB, proto@HHHH 1119 // NOT SUPPORTED: 1120 // case Instruction::k3rms: // [opt] invoke-virtual+super/range 1121 // case Instruction::k3rmi: // [opt] execute-inline/range 1122 // This doesn't match the "dx" output when some of the args are 1123 // 64-bit values -- dx only shows the first register. 1124 fputs(" {", gOutFile); 1125 for (int i = 0, n = pDecInsn->VRegA(); i < n; i++) { 1126 if (i == 0) { 1127 fprintf(gOutFile, "v%d", pDecInsn->VRegC() + i); 1128 } else { 1129 fprintf(gOutFile, ", v%d", pDecInsn->VRegC() + i); 1130 } 1131 } // for 1132 fprintf(gOutFile, "}, %s", indexBuf.get()); 1133 } 1134 break; 1135 case Instruction::k51l: { // op vAA, #+BBBBBBBBBBBBBBBB 1136 // This is often, but not always, a double. 1137 union { 1138 double d; 1139 u8 j; 1140 } conv; 1141 conv.j = pDecInsn->WideVRegB(); 1142 fprintf(gOutFile, " v%d, #double %g // #%016" PRIx64, 1143 pDecInsn->VRegA(), conv.d, pDecInsn->WideVRegB()); 1144 break; 1145 } 1146 // NOT SUPPORTED: 1147 // case Instruction::k00x: // unknown op or breakpoint 1148 // break; 1149 default: 1150 fprintf(gOutFile, " ???"); 1151 break; 1152 } // switch 1153 1154 fputc('\n', gOutFile); 1155 } 1156 1157 /* 1158 * Dumps a bytecode disassembly. 1159 */ 1160 static void dumpBytecodes(const DexFile* pDexFile, u4 idx, 1161 const DexFile::CodeItem* pCode, u4 codeOffset) { 1162 const DexFile::MethodId& pMethodId = pDexFile->GetMethodId(idx); 1163 const char* name = pDexFile->StringDataByIdx(pMethodId.name_idx_); 1164 const Signature signature = pDexFile->GetMethodSignature(pMethodId); 1165 const char* backDescriptor = pDexFile->StringByTypeIdx(pMethodId.class_idx_); 1166 1167 // Generate header. 1168 std::unique_ptr<char[]> dot(descriptorToDot(backDescriptor)); 1169 fprintf(gOutFile, "%06x: |[%06x] %s.%s:%s\n", 1170 codeOffset, codeOffset, dot.get(), name, signature.ToString().c_str()); 1171 1172 // Iterate over all instructions. 1173 CodeItemDataAccessor accessor(*pDexFile, pCode); 1174 const u4 maxPc = accessor.InsnsSizeInCodeUnits(); 1175 for (const DexInstructionPcPair& pair : accessor) { 1176 const u4 dexPc = pair.DexPc(); 1177 if (dexPc >= maxPc) { 1178 LOG(WARNING) << "GLITCH: run-away instruction at idx=0x" << std::hex << dexPc; 1179 break; 1180 } 1181 const Instruction* instruction = &pair.Inst(); 1182 const u4 insnWidth = instruction->SizeInCodeUnits(); 1183 if (insnWidth == 0) { 1184 LOG(WARNING) << "GLITCH: zero-width instruction at idx=0x" << std::hex << dexPc; 1185 break; 1186 } 1187 dumpInstruction(pDexFile, pCode, codeOffset, dexPc, insnWidth, instruction); 1188 } // for 1189 } 1190 1191 /* 1192 * Dumps code of a method. 1193 */ 1194 static void dumpCode(const DexFile* pDexFile, u4 idx, u4 flags, 1195 const DexFile::CodeItem* pCode, u4 codeOffset) { 1196 CodeItemDebugInfoAccessor accessor(*pDexFile, pCode, idx); 1197 1198 fprintf(gOutFile, " registers : %d\n", accessor.RegistersSize()); 1199 fprintf(gOutFile, " ins : %d\n", accessor.InsSize()); 1200 fprintf(gOutFile, " outs : %d\n", accessor.OutsSize()); 1201 fprintf(gOutFile, " insns size : %d 16-bit code units\n", 1202 accessor.InsnsSizeInCodeUnits()); 1203 1204 // Bytecode disassembly, if requested. 1205 if (gOptions.disassemble) { 1206 dumpBytecodes(pDexFile, idx, pCode, codeOffset); 1207 } 1208 1209 // Try-catch blocks. 1210 dumpCatches(pDexFile, pCode); 1211 1212 // Positions and locals table in the debug info. 1213 bool is_static = (flags & kAccStatic) != 0; 1214 fprintf(gOutFile, " positions : \n"); 1215 pDexFile->DecodeDebugPositionInfo(accessor.DebugInfoOffset(), dumpPositionsCb, nullptr); 1216 fprintf(gOutFile, " locals : \n"); 1217 accessor.DecodeDebugLocalInfo(is_static, idx, dumpLocalsCb, nullptr); 1218 } 1219 1220 /* 1221 * Dumps a method. 1222 */ 1223 static void dumpMethod(const DexFile* pDexFile, u4 idx, u4 flags, 1224 const DexFile::CodeItem* pCode, u4 codeOffset, int i) { 1225 // Bail for anything private if export only requested. 1226 if (gOptions.exportsOnly && (flags & (kAccPublic | kAccProtected)) == 0) { 1227 return; 1228 } 1229 1230 const DexFile::MethodId& pMethodId = pDexFile->GetMethodId(idx); 1231 const char* name = pDexFile->StringDataByIdx(pMethodId.name_idx_); 1232 const Signature signature = pDexFile->GetMethodSignature(pMethodId); 1233 char* typeDescriptor = strdup(signature.ToString().c_str()); 1234 const char* backDescriptor = pDexFile->StringByTypeIdx(pMethodId.class_idx_); 1235 char* accessStr = createAccessFlagStr(flags, kAccessForMethod); 1236 1237 if (gOptions.outputFormat == OUTPUT_PLAIN) { 1238 fprintf(gOutFile, " #%d : (in %s)\n", i, backDescriptor); 1239 fprintf(gOutFile, " name : '%s'\n", name); 1240 fprintf(gOutFile, " type : '%s'\n", typeDescriptor); 1241 fprintf(gOutFile, " access : 0x%04x (%s)\n", flags, accessStr); 1242 if (pCode == nullptr) { 1243 fprintf(gOutFile, " code : (none)\n"); 1244 } else { 1245 fprintf(gOutFile, " code -\n"); 1246 dumpCode(pDexFile, idx, flags, pCode, codeOffset); 1247 } 1248 if (gOptions.disassemble) { 1249 fputc('\n', gOutFile); 1250 } 1251 } else if (gOptions.outputFormat == OUTPUT_XML) { 1252 const bool constructor = (name[0] == '<'); 1253 1254 // Method name and prototype. 1255 if (constructor) { 1256 std::unique_ptr<char[]> dot(descriptorClassToDot(backDescriptor)); 1257 fprintf(gOutFile, "<constructor name=\"%s\"\n", dot.get()); 1258 dot = descriptorToDot(backDescriptor); 1259 fprintf(gOutFile, " type=\"%s\"\n", dot.get()); 1260 } else { 1261 fprintf(gOutFile, "<method name=\"%s\"\n", name); 1262 const char* returnType = strrchr(typeDescriptor, ')'); 1263 if (returnType == nullptr) { 1264 LOG(ERROR) << "bad method type descriptor '" << typeDescriptor << "'"; 1265 goto bail; 1266 } 1267 std::unique_ptr<char[]> dot(descriptorToDot(returnType + 1)); 1268 fprintf(gOutFile, " return=\"%s\"\n", dot.get()); 1269 fprintf(gOutFile, " abstract=%s\n", quotedBool((flags & kAccAbstract) != 0)); 1270 fprintf(gOutFile, " native=%s\n", quotedBool((flags & kAccNative) != 0)); 1271 fprintf(gOutFile, " synchronized=%s\n", quotedBool( 1272 (flags & (kAccSynchronized | kAccDeclaredSynchronized)) != 0)); 1273 } 1274 1275 // Additional method flags. 1276 fprintf(gOutFile, " static=%s\n", quotedBool((flags & kAccStatic) != 0)); 1277 fprintf(gOutFile, " final=%s\n", quotedBool((flags & kAccFinal) != 0)); 1278 // The "deprecated=" not knowable w/o parsing annotations. 1279 fprintf(gOutFile, " visibility=%s\n>\n", quotedVisibility(flags)); 1280 1281 // Parameters. 1282 if (typeDescriptor[0] != '(') { 1283 LOG(ERROR) << "ERROR: bad descriptor '" << typeDescriptor << "'"; 1284 goto bail; 1285 } 1286 char* tmpBuf = reinterpret_cast<char*>(malloc(strlen(typeDescriptor) + 1)); 1287 const char* base = typeDescriptor + 1; 1288 int argNum = 0; 1289 while (*base != ')') { 1290 char* cp = tmpBuf; 1291 while (*base == '[') { 1292 *cp++ = *base++; 1293 } 1294 if (*base == 'L') { 1295 // Copy through ';'. 1296 do { 1297 *cp = *base++; 1298 } while (*cp++ != ';'); 1299 } else { 1300 // Primitive char, copy it. 1301 if (strchr("ZBCSIFJD", *base) == nullptr) { 1302 LOG(ERROR) << "ERROR: bad method signature '" << base << "'"; 1303 break; // while 1304 } 1305 *cp++ = *base++; 1306 } 1307 // Null terminate and display. 1308 *cp++ = '\0'; 1309 std::unique_ptr<char[]> dot(descriptorToDot(tmpBuf)); 1310 fprintf(gOutFile, "<parameter name=\"arg%d\" type=\"%s\">\n" 1311 "</parameter>\n", argNum++, dot.get()); 1312 } // while 1313 free(tmpBuf); 1314 if (constructor) { 1315 fprintf(gOutFile, "</constructor>\n"); 1316 } else { 1317 fprintf(gOutFile, "</method>\n"); 1318 } 1319 } 1320 1321 bail: 1322 free(typeDescriptor); 1323 free(accessStr); 1324 } 1325 1326 /* 1327 * Dumps a static (class) field. 1328 */ 1329 static void dumpSField(const DexFile* pDexFile, u4 idx, u4 flags, int i, const u1** data) { 1330 // Bail for anything private if export only requested. 1331 if (gOptions.exportsOnly && (flags & (kAccPublic | kAccProtected)) == 0) { 1332 return; 1333 } 1334 1335 const DexFile::FieldId& pFieldId = pDexFile->GetFieldId(idx); 1336 const char* name = pDexFile->StringDataByIdx(pFieldId.name_idx_); 1337 const char* typeDescriptor = pDexFile->StringByTypeIdx(pFieldId.type_idx_); 1338 const char* backDescriptor = pDexFile->StringByTypeIdx(pFieldId.class_idx_); 1339 char* accessStr = createAccessFlagStr(flags, kAccessForField); 1340 1341 if (gOptions.outputFormat == OUTPUT_PLAIN) { 1342 fprintf(gOutFile, " #%d : (in %s)\n", i, backDescriptor); 1343 fprintf(gOutFile, " name : '%s'\n", name); 1344 fprintf(gOutFile, " type : '%s'\n", typeDescriptor); 1345 fprintf(gOutFile, " access : 0x%04x (%s)\n", flags, accessStr); 1346 if (data != nullptr) { 1347 fputs(" value : ", gOutFile); 1348 dumpEncodedValue(pDexFile, data); 1349 fputs("\n", gOutFile); 1350 } 1351 } else if (gOptions.outputFormat == OUTPUT_XML) { 1352 fprintf(gOutFile, "<field name=\"%s\"\n", name); 1353 std::unique_ptr<char[]> dot(descriptorToDot(typeDescriptor)); 1354 fprintf(gOutFile, " type=\"%s\"\n", dot.get()); 1355 fprintf(gOutFile, " transient=%s\n", quotedBool((flags & kAccTransient) != 0)); 1356 fprintf(gOutFile, " volatile=%s\n", quotedBool((flags & kAccVolatile) != 0)); 1357 // The "value=" is not knowable w/o parsing annotations. 1358 fprintf(gOutFile, " static=%s\n", quotedBool((flags & kAccStatic) != 0)); 1359 fprintf(gOutFile, " final=%s\n", quotedBool((flags & kAccFinal) != 0)); 1360 // The "deprecated=" is not knowable w/o parsing annotations. 1361 fprintf(gOutFile, " visibility=%s\n", quotedVisibility(flags)); 1362 if (data != nullptr) { 1363 fputs(" value=\"", gOutFile); 1364 dumpEncodedValue(pDexFile, data); 1365 fputs("\"\n", gOutFile); 1366 } 1367 fputs(">\n</field>\n", gOutFile); 1368 } 1369 1370 free(accessStr); 1371 } 1372 1373 /* 1374 * Dumps an instance field. 1375 */ 1376 static void dumpIField(const DexFile* pDexFile, u4 idx, u4 flags, int i) { 1377 dumpSField(pDexFile, idx, flags, i, nullptr); 1378 } 1379 1380 /* 1381 * Dumping a CFG. Note that this will do duplicate work. utils.h doesn't expose the code-item 1382 * version, so the DumpMethodCFG code will have to iterate again to find it. But dexdump is a 1383 * tool, so this is not performance-critical. 1384 */ 1385 1386 static void dumpCfg(const DexFile* dex_file, 1387 u4 dex_method_idx, 1388 const DexFile::CodeItem* code_item) { 1389 if (code_item != nullptr) { 1390 std::ostringstream oss; 1391 DumpMethodCFG(dex_file, dex_method_idx, oss); 1392 fputs(oss.str().c_str(), gOutFile); 1393 } 1394 } 1395 1396 static void dumpCfg(const DexFile* dex_file, int idx) { 1397 const DexFile::ClassDef& class_def = dex_file->GetClassDef(idx); 1398 const u1* class_data = dex_file->GetClassData(class_def); 1399 if (class_data == nullptr) { // empty class such as a marker interface? 1400 return; 1401 } 1402 ClassDataItemIterator it(*dex_file, class_data); 1403 it.SkipAllFields(); 1404 while (it.HasNextMethod()) { 1405 dumpCfg(dex_file, 1406 it.GetMemberIndex(), 1407 it.GetMethodCodeItem()); 1408 it.Next(); 1409 } 1410 } 1411 1412 /* 1413 * Dumps the class. 1414 * 1415 * Note "idx" is a DexClassDef index, not a DexTypeId index. 1416 * 1417 * If "*pLastPackage" is nullptr or does not match the current class' package, 1418 * the value will be replaced with a newly-allocated string. 1419 */ 1420 static void dumpClass(const DexFile* pDexFile, int idx, char** pLastPackage) { 1421 const DexFile::ClassDef& pClassDef = pDexFile->GetClassDef(idx); 1422 1423 // Omitting non-public class. 1424 if (gOptions.exportsOnly && (pClassDef.access_flags_ & kAccPublic) == 0) { 1425 return; 1426 } 1427 1428 if (gOptions.showSectionHeaders) { 1429 dumpClassDef(pDexFile, idx); 1430 } 1431 1432 if (gOptions.showAnnotations) { 1433 dumpClassAnnotations(pDexFile, idx); 1434 } 1435 1436 if (gOptions.showCfg) { 1437 dumpCfg(pDexFile, idx); 1438 return; 1439 } 1440 1441 // For the XML output, show the package name. Ideally we'd gather 1442 // up the classes, sort them, and dump them alphabetically so the 1443 // package name wouldn't jump around, but that's not a great plan 1444 // for something that needs to run on the device. 1445 const char* classDescriptor = pDexFile->StringByTypeIdx(pClassDef.class_idx_); 1446 if (!(classDescriptor[0] == 'L' && 1447 classDescriptor[strlen(classDescriptor)-1] == ';')) { 1448 // Arrays and primitives should not be defined explicitly. Keep going? 1449 LOG(WARNING) << "Malformed class name '" << classDescriptor << "'"; 1450 } else if (gOptions.outputFormat == OUTPUT_XML) { 1451 char* mangle = strdup(classDescriptor + 1); 1452 mangle[strlen(mangle)-1] = '\0'; 1453 1454 // Reduce to just the package name. 1455 char* lastSlash = strrchr(mangle, '/'); 1456 if (lastSlash != nullptr) { 1457 *lastSlash = '\0'; 1458 } else { 1459 *mangle = '\0'; 1460 } 1461 1462 for (char* cp = mangle; *cp != '\0'; cp++) { 1463 if (*cp == '/') { 1464 *cp = '.'; 1465 } 1466 } // for 1467 1468 if (*pLastPackage == nullptr || strcmp(mangle, *pLastPackage) != 0) { 1469 // Start of a new package. 1470 if (*pLastPackage != nullptr) { 1471 fprintf(gOutFile, "</package>\n"); 1472 } 1473 fprintf(gOutFile, "<package name=\"%s\"\n>\n", mangle); 1474 free(*pLastPackage); 1475 *pLastPackage = mangle; 1476 } else { 1477 free(mangle); 1478 } 1479 } 1480 1481 // General class information. 1482 char* accessStr = createAccessFlagStr(pClassDef.access_flags_, kAccessForClass); 1483 const char* superclassDescriptor; 1484 if (!pClassDef.superclass_idx_.IsValid()) { 1485 superclassDescriptor = nullptr; 1486 } else { 1487 superclassDescriptor = pDexFile->StringByTypeIdx(pClassDef.superclass_idx_); 1488 } 1489 if (gOptions.outputFormat == OUTPUT_PLAIN) { 1490 fprintf(gOutFile, "Class #%d -\n", idx); 1491 fprintf(gOutFile, " Class descriptor : '%s'\n", classDescriptor); 1492 fprintf(gOutFile, " Access flags : 0x%04x (%s)\n", pClassDef.access_flags_, accessStr); 1493 if (superclassDescriptor != nullptr) { 1494 fprintf(gOutFile, " Superclass : '%s'\n", superclassDescriptor); 1495 } 1496 fprintf(gOutFile, " Interfaces -\n"); 1497 } else { 1498 std::unique_ptr<char[]> dot(descriptorClassToDot(classDescriptor)); 1499 fprintf(gOutFile, "<class name=\"%s\"\n", dot.get()); 1500 if (superclassDescriptor != nullptr) { 1501 dot = descriptorToDot(superclassDescriptor); 1502 fprintf(gOutFile, " extends=\"%s\"\n", dot.get()); 1503 } 1504 fprintf(gOutFile, " interface=%s\n", 1505 quotedBool((pClassDef.access_flags_ & kAccInterface) != 0)); 1506 fprintf(gOutFile, " abstract=%s\n", quotedBool((pClassDef.access_flags_ & kAccAbstract) != 0)); 1507 fprintf(gOutFile, " static=%s\n", quotedBool((pClassDef.access_flags_ & kAccStatic) != 0)); 1508 fprintf(gOutFile, " final=%s\n", quotedBool((pClassDef.access_flags_ & kAccFinal) != 0)); 1509 // The "deprecated=" not knowable w/o parsing annotations. 1510 fprintf(gOutFile, " visibility=%s\n", quotedVisibility(pClassDef.access_flags_)); 1511 fprintf(gOutFile, ">\n"); 1512 } 1513 1514 // Interfaces. 1515 const DexFile::TypeList* pInterfaces = pDexFile->GetInterfacesList(pClassDef); 1516 if (pInterfaces != nullptr) { 1517 for (u4 i = 0; i < pInterfaces->Size(); i++) { 1518 dumpInterface(pDexFile, pInterfaces->GetTypeItem(i), i); 1519 } // for 1520 } 1521 1522 // Fields and methods. 1523 const u1* pEncodedData = pDexFile->GetClassData(pClassDef); 1524 if (pEncodedData == nullptr) { 1525 if (gOptions.outputFormat == OUTPUT_PLAIN) { 1526 fprintf(gOutFile, " Static fields -\n"); 1527 fprintf(gOutFile, " Instance fields -\n"); 1528 fprintf(gOutFile, " Direct methods -\n"); 1529 fprintf(gOutFile, " Virtual methods -\n"); 1530 } 1531 } else { 1532 ClassDataItemIterator pClassData(*pDexFile, pEncodedData); 1533 1534 // Prepare data for static fields. 1535 const u1* sData = pDexFile->GetEncodedStaticFieldValuesArray(pClassDef); 1536 const u4 sSize = sData != nullptr ? DecodeUnsignedLeb128(&sData) : 0; 1537 1538 // Static fields. 1539 if (gOptions.outputFormat == OUTPUT_PLAIN) { 1540 fprintf(gOutFile, " Static fields -\n"); 1541 } 1542 for (u4 i = 0; pClassData.HasNextStaticField(); i++, pClassData.Next()) { 1543 dumpSField(pDexFile, 1544 pClassData.GetMemberIndex(), 1545 pClassData.GetRawMemberAccessFlags(), 1546 i, 1547 i < sSize ? &sData : nullptr); 1548 } // for 1549 1550 // Instance fields. 1551 if (gOptions.outputFormat == OUTPUT_PLAIN) { 1552 fprintf(gOutFile, " Instance fields -\n"); 1553 } 1554 for (u4 i = 0; pClassData.HasNextInstanceField(); i++, pClassData.Next()) { 1555 dumpIField(pDexFile, 1556 pClassData.GetMemberIndex(), 1557 pClassData.GetRawMemberAccessFlags(), 1558 i); 1559 } // for 1560 1561 // Direct methods. 1562 if (gOptions.outputFormat == OUTPUT_PLAIN) { 1563 fprintf(gOutFile, " Direct methods -\n"); 1564 } 1565 for (int i = 0; pClassData.HasNextDirectMethod(); i++, pClassData.Next()) { 1566 dumpMethod(pDexFile, pClassData.GetMemberIndex(), 1567 pClassData.GetRawMemberAccessFlags(), 1568 pClassData.GetMethodCodeItem(), 1569 pClassData.GetMethodCodeItemOffset(), i); 1570 } // for 1571 1572 // Virtual methods. 1573 if (gOptions.outputFormat == OUTPUT_PLAIN) { 1574 fprintf(gOutFile, " Virtual methods -\n"); 1575 } 1576 for (int i = 0; pClassData.HasNextVirtualMethod(); i++, pClassData.Next()) { 1577 dumpMethod(pDexFile, pClassData.GetMemberIndex(), 1578 pClassData.GetRawMemberAccessFlags(), 1579 pClassData.GetMethodCodeItem(), 1580 pClassData.GetMethodCodeItemOffset(), i); 1581 } // for 1582 } 1583 1584 // End of class. 1585 if (gOptions.outputFormat == OUTPUT_PLAIN) { 1586 const char* fileName; 1587 if (pClassDef.source_file_idx_.IsValid()) { 1588 fileName = pDexFile->StringDataByIdx(pClassDef.source_file_idx_); 1589 } else { 1590 fileName = "unknown"; 1591 } 1592 fprintf(gOutFile, " source_file_idx : %d (%s)\n\n", 1593 pClassDef.source_file_idx_.index_, fileName); 1594 } else if (gOptions.outputFormat == OUTPUT_XML) { 1595 fprintf(gOutFile, "</class>\n"); 1596 } 1597 1598 free(accessStr); 1599 } 1600 1601 static void dumpMethodHandle(const DexFile* pDexFile, u4 idx) { 1602 const DexFile::MethodHandleItem& mh = pDexFile->GetMethodHandle(idx); 1603 const char* type = nullptr; 1604 bool is_instance = false; 1605 bool is_invoke = false; 1606 switch (static_cast<DexFile::MethodHandleType>(mh.method_handle_type_)) { 1607 case DexFile::MethodHandleType::kStaticPut: 1608 type = "put-static"; 1609 is_instance = false; 1610 is_invoke = false; 1611 break; 1612 case DexFile::MethodHandleType::kStaticGet: 1613 type = "get-static"; 1614 is_instance = false; 1615 is_invoke = false; 1616 break; 1617 case DexFile::MethodHandleType::kInstancePut: 1618 type = "put-instance"; 1619 is_instance = true; 1620 is_invoke = false; 1621 break; 1622 case DexFile::MethodHandleType::kInstanceGet: 1623 type = "get-instance"; 1624 is_instance = true; 1625 is_invoke = false; 1626 break; 1627 case DexFile::MethodHandleType::kInvokeStatic: 1628 type = "invoke-static"; 1629 is_instance = false; 1630 is_invoke = true; 1631 break; 1632 case DexFile::MethodHandleType::kInvokeInstance: 1633 type = "invoke-instance"; 1634 is_instance = true; 1635 is_invoke = true; 1636 break; 1637 case DexFile::MethodHandleType::kInvokeConstructor: 1638 type = "invoke-constructor"; 1639 is_instance = true; 1640 is_invoke = true; 1641 break; 1642 case DexFile::MethodHandleType::kInvokeDirect: 1643 type = "invoke-direct"; 1644 is_instance = true; 1645 is_invoke = true; 1646 break; 1647 case DexFile::MethodHandleType::kInvokeInterface: 1648 type = "invoke-interface"; 1649 is_instance = true; 1650 is_invoke = true; 1651 break; 1652 } 1653 1654 const char* declaring_class; 1655 const char* member; 1656 std::string member_type; 1657 if (type != nullptr) { 1658 if (is_invoke) { 1659 const DexFile::MethodId& method_id = pDexFile->GetMethodId(mh.field_or_method_idx_); 1660 declaring_class = pDexFile->GetMethodDeclaringClassDescriptor(method_id); 1661 member = pDexFile->GetMethodName(method_id); 1662 member_type = pDexFile->GetMethodSignature(method_id).ToString(); 1663 } else { 1664 const DexFile::FieldId& field_id = pDexFile->GetFieldId(mh.field_or_method_idx_); 1665 declaring_class = pDexFile->GetFieldDeclaringClassDescriptor(field_id); 1666 member = pDexFile->GetFieldName(field_id); 1667 member_type = pDexFile->GetFieldTypeDescriptor(field_id); 1668 } 1669 if (is_instance) { 1670 member_type = android::base::StringPrintf("(%s%s", declaring_class, member_type.c_str() + 1); 1671 } 1672 } else { 1673 type = "?"; 1674 declaring_class = "?"; 1675 member = "?"; 1676 member_type = "?"; 1677 } 1678 1679 if (gOptions.outputFormat == OUTPUT_PLAIN) { 1680 fprintf(gOutFile, "Method handle #%u:\n", idx); 1681 fprintf(gOutFile, " type : %s\n", type); 1682 fprintf(gOutFile, " target : %s %s\n", declaring_class, member); 1683 fprintf(gOutFile, " target_type : %s\n", member_type.c_str()); 1684 } else { 1685 fprintf(gOutFile, "<method_handle index=\"%u\"\n", idx); 1686 fprintf(gOutFile, " type=\"%s\"\n", type); 1687 fprintf(gOutFile, " target_class=\"%s\"\n", declaring_class); 1688 fprintf(gOutFile, " target_member=\"%s\"\n", member); 1689 fprintf(gOutFile, " target_member_type="); 1690 dumpEscapedString(member_type.c_str()); 1691 fprintf(gOutFile, "\n>\n</method_handle>\n"); 1692 } 1693 } 1694 1695 static void dumpCallSite(const DexFile* pDexFile, u4 idx) { 1696 const DexFile::CallSiteIdItem& call_site_id = pDexFile->GetCallSiteId(idx); 1697 CallSiteArrayValueIterator it(*pDexFile, call_site_id); 1698 if (it.Size() < 3) { 1699 LOG(ERROR) << "ERROR: Call site " << idx << " has too few values."; 1700 return; 1701 } 1702 1703 uint32_t method_handle_idx = static_cast<uint32_t>(it.GetJavaValue().i); 1704 it.Next(); 1705 dex::StringIndex method_name_idx = static_cast<dex::StringIndex>(it.GetJavaValue().i); 1706 const char* method_name = pDexFile->StringDataByIdx(method_name_idx); 1707 it.Next(); 1708 uint32_t method_type_idx = static_cast<uint32_t>(it.GetJavaValue().i); 1709 const DexFile::ProtoId& method_type_id = pDexFile->GetProtoId(method_type_idx); 1710 std::string method_type = pDexFile->GetProtoSignature(method_type_id).ToString(); 1711 it.Next(); 1712 1713 if (gOptions.outputFormat == OUTPUT_PLAIN) { 1714 fprintf(gOutFile, "Call site #%u: // offset %u\n", idx, call_site_id.data_off_); 1715 fprintf(gOutFile, " link_argument[0] : %u (MethodHandle)\n", method_handle_idx); 1716 fprintf(gOutFile, " link_argument[1] : %s (String)\n", method_name); 1717 fprintf(gOutFile, " link_argument[2] : %s (MethodType)\n", method_type.c_str()); 1718 } else { 1719 fprintf(gOutFile, "<call_site index=\"%u\" offset=\"%u\">\n", idx, call_site_id.data_off_); 1720 fprintf(gOutFile, 1721 "<link_argument index=\"0\" type=\"MethodHandle\" value=\"%u\"/>\n", 1722 method_handle_idx); 1723 fprintf(gOutFile, 1724 "<link_argument index=\"1\" type=\"String\" values=\"%s\"/>\n", 1725 method_name); 1726 fprintf(gOutFile, 1727 "<link_argument index=\"2\" type=\"MethodType\" value=\"%s\"/>\n", 1728 method_type.c_str()); 1729 } 1730 1731 size_t argument = 3; 1732 while (it.HasNext()) { 1733 const char* type; 1734 std::string value; 1735 switch (it.GetValueType()) { 1736 case EncodedArrayValueIterator::ValueType::kByte: 1737 type = "byte"; 1738 value = android::base::StringPrintf("%u", it.GetJavaValue().b); 1739 break; 1740 case EncodedArrayValueIterator::ValueType::kShort: 1741 type = "short"; 1742 value = android::base::StringPrintf("%d", it.GetJavaValue().s); 1743 break; 1744 case EncodedArrayValueIterator::ValueType::kChar: 1745 type = "char"; 1746 value = android::base::StringPrintf("%u", it.GetJavaValue().c); 1747 break; 1748 case EncodedArrayValueIterator::ValueType::kInt: 1749 type = "int"; 1750 value = android::base::StringPrintf("%d", it.GetJavaValue().i); 1751 break; 1752 case EncodedArrayValueIterator::ValueType::kLong: 1753 type = "long"; 1754 value = android::base::StringPrintf("%" PRId64, it.GetJavaValue().j); 1755 break; 1756 case EncodedArrayValueIterator::ValueType::kFloat: 1757 type = "float"; 1758 value = android::base::StringPrintf("%g", it.GetJavaValue().f); 1759 break; 1760 case EncodedArrayValueIterator::ValueType::kDouble: 1761 type = "double"; 1762 value = android::base::StringPrintf("%g", it.GetJavaValue().d); 1763 break; 1764 case EncodedArrayValueIterator::ValueType::kMethodType: { 1765 type = "MethodType"; 1766 uint32_t proto_idx = static_cast<uint32_t>(it.GetJavaValue().i); 1767 const DexFile::ProtoId& proto_id = pDexFile->GetProtoId(proto_idx); 1768 value = pDexFile->GetProtoSignature(proto_id).ToString(); 1769 break; 1770 } 1771 case EncodedArrayValueIterator::ValueType::kMethodHandle: 1772 type = "MethodHandle"; 1773 value = android::base::StringPrintf("%d", it.GetJavaValue().i); 1774 break; 1775 case EncodedArrayValueIterator::ValueType::kString: { 1776 type = "String"; 1777 dex::StringIndex string_idx = static_cast<dex::StringIndex>(it.GetJavaValue().i); 1778 value = pDexFile->StringDataByIdx(string_idx); 1779 break; 1780 } 1781 case EncodedArrayValueIterator::ValueType::kType: { 1782 type = "Class"; 1783 dex::TypeIndex type_idx = static_cast<dex::TypeIndex>(it.GetJavaValue().i); 1784 const DexFile::ClassDef* class_def = pDexFile->FindClassDef(type_idx); 1785 value = pDexFile->GetClassDescriptor(*class_def); 1786 value = descriptorClassToDot(value.c_str()).get(); 1787 break; 1788 } 1789 case EncodedArrayValueIterator::ValueType::kField: 1790 case EncodedArrayValueIterator::ValueType::kMethod: 1791 case EncodedArrayValueIterator::ValueType::kEnum: 1792 case EncodedArrayValueIterator::ValueType::kArray: 1793 case EncodedArrayValueIterator::ValueType::kAnnotation: 1794 // Unreachable based on current EncodedArrayValueIterator::Next(). 1795 UNIMPLEMENTED(FATAL) << " type " << it.GetValueType(); 1796 UNREACHABLE(); 1797 case EncodedArrayValueIterator::ValueType::kNull: 1798 type = "Null"; 1799 value = "null"; 1800 break; 1801 case EncodedArrayValueIterator::ValueType::kBoolean: 1802 type = "boolean"; 1803 value = it.GetJavaValue().z ? "true" : "false"; 1804 break; 1805 } 1806 1807 if (gOptions.outputFormat == OUTPUT_PLAIN) { 1808 fprintf(gOutFile, " link_argument[%zu] : %s (%s)\n", argument, value.c_str(), type); 1809 } else { 1810 fprintf(gOutFile, "<link_argument index=\"%zu\" type=\"%s\" value=", argument, type); 1811 dumpEscapedString(value.c_str()); 1812 fprintf(gOutFile, "/>\n"); 1813 } 1814 1815 it.Next(); 1816 argument++; 1817 } 1818 1819 if (gOptions.outputFormat == OUTPUT_XML) { 1820 fprintf(gOutFile, "</call_site>\n"); 1821 } 1822 } 1823 1824 /* 1825 * Dumps the requested sections of the file. 1826 */ 1827 static void processDexFile(const char* fileName, 1828 const DexFile* pDexFile, size_t i, size_t n) { 1829 if (gOptions.verbose) { 1830 fputs("Opened '", gOutFile); 1831 fputs(fileName, gOutFile); 1832 if (n > 1) { 1833 fprintf(gOutFile, ":%s", DexFileLoader::GetMultiDexClassesDexName(i).c_str()); 1834 } 1835 fprintf(gOutFile, "', DEX version '%.3s'\n", pDexFile->GetHeader().magic_ + 4); 1836 } 1837 1838 // Headers. 1839 if (gOptions.showFileHeaders) { 1840 dumpFileHeader(pDexFile); 1841 } 1842 1843 // Open XML context. 1844 if (gOptions.outputFormat == OUTPUT_XML) { 1845 fprintf(gOutFile, "<api>\n"); 1846 } 1847 1848 // Iterate over all classes. 1849 char* package = nullptr; 1850 const u4 classDefsSize = pDexFile->GetHeader().class_defs_size_; 1851 for (u4 i = 0; i < classDefsSize; i++) { 1852 dumpClass(pDexFile, i, &package); 1853 } // for 1854 1855 // Iterate over all method handles. 1856 for (u4 i = 0; i < pDexFile->NumMethodHandles(); ++i) { 1857 dumpMethodHandle(pDexFile, i); 1858 } // for 1859 1860 // Iterate over all call site ids. 1861 for (u4 i = 0; i < pDexFile->NumCallSiteIds(); ++i) { 1862 dumpCallSite(pDexFile, i); 1863 } // for 1864 1865 // Free the last package allocated. 1866 if (package != nullptr) { 1867 fprintf(gOutFile, "</package>\n"); 1868 free(package); 1869 } 1870 1871 // Close XML context. 1872 if (gOptions.outputFormat == OUTPUT_XML) { 1873 fprintf(gOutFile, "</api>\n"); 1874 } 1875 } 1876 1877 /* 1878 * Processes a single file (either direct .dex or indirect .zip/.jar/.apk). 1879 */ 1880 int processFile(const char* fileName) { 1881 if (gOptions.verbose) { 1882 fprintf(gOutFile, "Processing '%s'...\n", fileName); 1883 } 1884 1885 const bool kVerifyChecksum = !gOptions.ignoreBadChecksum; 1886 const bool kVerify = !gOptions.disableVerifier; 1887 std::string content; 1888 // If the file is not a .dex file, the function tries .zip/.jar/.apk files, 1889 // all of which are Zip archives with "classes.dex" inside. 1890 // TODO: add an api to android::base to read a std::vector<uint8_t>. 1891 if (!android::base::ReadFileToString(fileName, &content)) { 1892 LOG(ERROR) << "ReadFileToString failed"; 1893 return -1; 1894 } 1895 const DexFileLoader dex_file_loader; 1896 std::string error_msg; 1897 std::vector<std::unique_ptr<const DexFile>> dex_files; 1898 if (!dex_file_loader.OpenAll(reinterpret_cast<const uint8_t*>(content.data()), 1899 content.size(), 1900 fileName, 1901 kVerify, 1902 kVerifyChecksum, 1903 &error_msg, 1904 &dex_files)) { 1905 // Display returned error message to user. Note that this error behavior 1906 // differs from the error messages shown by the original Dalvik dexdump. 1907 LOG(ERROR) << error_msg; 1908 return -1; 1909 } 1910 1911 // Success. Either report checksum verification or process 1912 // all dex files found in given file. 1913 if (gOptions.checksumOnly) { 1914 fprintf(gOutFile, "Checksum verified\n"); 1915 } else { 1916 for (size_t i = 0, n = dex_files.size(); i < n; i++) { 1917 processDexFile(fileName, dex_files[i].get(), i, n); 1918 } 1919 } 1920 return 0; 1921 } 1922 1923 } // namespace art 1924