Home | History | Annotate | Download | only in dexdump
      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("&amp;", gOutFile);
    395         break;
    396       case '<':
    397         fputs("&lt;", gOutFile);
    398         break;
    399       case '>':
    400         fputs("&gt;", gOutFile);
    401         break;
    402       case '"':
    403         fputs("&quot;", gOutFile);
    404         break;
    405       case '\t':
    406         fputs("&#x9;", gOutFile);
    407         break;
    408       case '\n':
    409         fputs("&#xA;", gOutFile);
    410         break;
    411       case '\r':
    412         fputs("&#xD;", 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