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