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 identical to
     21  * 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 "dex_file-inl.h"
     46 #include "dex_instruction-inl.h"
     47 #include "utils.h"
     48 
     49 namespace art {
     50 
     51 /*
     52  * Options parsed in main driver.
     53  */
     54 struct Options gOptions;
     55 
     56 /*
     57  * Output file. Defaults to stdout.
     58  */
     59 FILE* gOutFile = stdout;
     60 
     61 /*
     62  * Data types that match the definitions in the VM specification.
     63  */
     64 typedef uint8_t  u1;
     65 typedef uint16_t u2;
     66 typedef uint32_t u4;
     67 typedef uint64_t u8;
     68 typedef int32_t  s4;
     69 typedef int64_t  s8;
     70 
     71 /*
     72  * Basic information about a field or a method.
     73  */
     74 struct FieldMethodInfo {
     75   const char* classDescriptor;
     76   const char* name;
     77   const char* signature;
     78 };
     79 
     80 /*
     81  * Flags for use with createAccessFlagStr().
     82  */
     83 enum AccessFor {
     84   kAccessForClass = 0, kAccessForMethod = 1, kAccessForField = 2, kAccessForMAX
     85 };
     86 const int kNumFlags = 18;
     87 
     88 /*
     89  * Gets 2 little-endian bytes.
     90  */
     91 static inline u2 get2LE(unsigned char const* pSrc) {
     92   return pSrc[0] | (pSrc[1] << 8);
     93 }
     94 
     95 /*
     96  * Converts a single-character primitive type into human-readable form.
     97  */
     98 static const char* primitiveTypeLabel(char typeChar) {
     99   switch (typeChar) {
    100     case 'B': return "byte";
    101     case 'C': return "char";
    102     case 'D': return "double";
    103     case 'F': return "float";
    104     case 'I': return "int";
    105     case 'J': return "long";
    106     case 'S': return "short";
    107     case 'V': return "void";
    108     case 'Z': return "boolean";
    109     default:  return "UNKNOWN";
    110   }  // switch
    111 }
    112 
    113 /*
    114  * Converts a type descriptor to human-readable "dotted" form.  For
    115  * example, "Ljava/lang/String;" becomes "java.lang.String", and
    116  * "[I" becomes "int[]".  Also converts '$' to '.', which means this
    117  * form can't be converted back to a descriptor.
    118  */
    119 static char* descriptorToDot(const char* str) {
    120   int targetLen = strlen(str);
    121   int offset = 0;
    122 
    123   // Strip leading [s; will be added to end.
    124   while (targetLen > 1 && str[offset] == '[') {
    125     offset++;
    126     targetLen--;
    127   }  // while
    128 
    129   const int arrayDepth = offset;
    130 
    131   if (targetLen == 1) {
    132     // Primitive type.
    133     str = primitiveTypeLabel(str[offset]);
    134     offset = 0;
    135     targetLen = strlen(str);
    136   } else {
    137     // Account for leading 'L' and trailing ';'.
    138     if (targetLen >= 2 && str[offset] == 'L' &&
    139         str[offset + targetLen - 1] == ';') {
    140       targetLen -= 2;
    141       offset++;
    142     }
    143   }
    144 
    145   // Copy class name over.
    146   char* newStr = reinterpret_cast<char*>(
    147       malloc(targetLen + arrayDepth * 2 + 1));
    148   int i = 0;
    149   for (; i < targetLen; i++) {
    150     const char ch = str[offset + i];
    151     newStr[i] = (ch == '/' || ch == '$') ? '.' : ch;
    152   }  // for
    153 
    154   // Add the appropriate number of brackets for arrays.
    155   for (int j = 0; j < arrayDepth; j++) {
    156     newStr[i++] = '[';
    157     newStr[i++] = ']';
    158   }  // for
    159 
    160   newStr[i] = '\0';
    161   return newStr;
    162 }
    163 
    164 /*
    165  * Converts the class name portion of a type descriptor to human-readable
    166  * "dotted" form.
    167  *
    168  * Returns a newly-allocated string.
    169  */
    170 static char* descriptorClassToDot(const char* str) {
    171   // Reduce to just the class name, trimming trailing ';'.
    172   const char* lastSlash = strrchr(str, '/');
    173   if (lastSlash == nullptr) {
    174     lastSlash = str + 1;  // start past 'L'
    175   } else {
    176     lastSlash++;          // start past '/'
    177   }
    178 
    179   char* newStr = strdup(lastSlash);
    180   newStr[strlen(lastSlash) - 1] = '\0';
    181   for (char* cp = newStr; *cp != '\0'; cp++) {
    182     if (*cp == '$') {
    183       *cp = '.';
    184     }
    185   }  // for
    186   return newStr;
    187 }
    188 
    189 /*
    190  * Returns a quoted string representing the boolean value.
    191  */
    192 static const char* quotedBool(bool val) {
    193   return val ? "\"true\"" : "\"false\"";
    194 }
    195 
    196 /*
    197  * Returns a quoted string representing the access flags.
    198  */
    199 static const char* quotedVisibility(u4 accessFlags) {
    200   if (accessFlags & kAccPublic) {
    201     return "\"public\"";
    202   } else if (accessFlags & kAccProtected) {
    203     return "\"protected\"";
    204   } else if (accessFlags & kAccPrivate) {
    205     return "\"private\"";
    206   } else {
    207     return "\"package\"";
    208   }
    209 }
    210 
    211 /*
    212  * Counts the number of '1' bits in a word.
    213  */
    214 static int countOnes(u4 val) {
    215   val = val - ((val >> 1) & 0x55555555);
    216   val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
    217   return (((val + (val >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
    218 }
    219 
    220 /*
    221  * Creates a new string with human-readable access flags.
    222  *
    223  * In the base language the access_flags fields are type u2; in Dalvik
    224  * they're u4.
    225  */
    226 static char* createAccessFlagStr(u4 flags, AccessFor forWhat) {
    227   static const char* kAccessStrings[kAccessForMAX][kNumFlags] = {
    228     {
    229       "PUBLIC",                /* 0x00001 */
    230       "PRIVATE",               /* 0x00002 */
    231       "PROTECTED",             /* 0x00004 */
    232       "STATIC",                /* 0x00008 */
    233       "FINAL",                 /* 0x00010 */
    234       "?",                     /* 0x00020 */
    235       "?",                     /* 0x00040 */
    236       "?",                     /* 0x00080 */
    237       "?",                     /* 0x00100 */
    238       "INTERFACE",             /* 0x00200 */
    239       "ABSTRACT",              /* 0x00400 */
    240       "?",                     /* 0x00800 */
    241       "SYNTHETIC",             /* 0x01000 */
    242       "ANNOTATION",            /* 0x02000 */
    243       "ENUM",                  /* 0x04000 */
    244       "?",                     /* 0x08000 */
    245       "VERIFIED",              /* 0x10000 */
    246       "OPTIMIZED",             /* 0x20000 */
    247     }, {
    248       "PUBLIC",                /* 0x00001 */
    249       "PRIVATE",               /* 0x00002 */
    250       "PROTECTED",             /* 0x00004 */
    251       "STATIC",                /* 0x00008 */
    252       "FINAL",                 /* 0x00010 */
    253       "SYNCHRONIZED",          /* 0x00020 */
    254       "BRIDGE",                /* 0x00040 */
    255       "VARARGS",               /* 0x00080 */
    256       "NATIVE",                /* 0x00100 */
    257       "?",                     /* 0x00200 */
    258       "ABSTRACT",              /* 0x00400 */
    259       "STRICT",                /* 0x00800 */
    260       "SYNTHETIC",             /* 0x01000 */
    261       "?",                     /* 0x02000 */
    262       "?",                     /* 0x04000 */
    263       "MIRANDA",               /* 0x08000 */
    264       "CONSTRUCTOR",           /* 0x10000 */
    265       "DECLARED_SYNCHRONIZED", /* 0x20000 */
    266     }, {
    267       "PUBLIC",                /* 0x00001 */
    268       "PRIVATE",               /* 0x00002 */
    269       "PROTECTED",             /* 0x00004 */
    270       "STATIC",                /* 0x00008 */
    271       "FINAL",                 /* 0x00010 */
    272       "?",                     /* 0x00020 */
    273       "VOLATILE",              /* 0x00040 */
    274       "TRANSIENT",             /* 0x00080 */
    275       "?",                     /* 0x00100 */
    276       "?",                     /* 0x00200 */
    277       "?",                     /* 0x00400 */
    278       "?",                     /* 0x00800 */
    279       "SYNTHETIC",             /* 0x01000 */
    280       "?",                     /* 0x02000 */
    281       "ENUM",                  /* 0x04000 */
    282       "?",                     /* 0x08000 */
    283       "?",                     /* 0x10000 */
    284       "?",                     /* 0x20000 */
    285     },
    286   };
    287 
    288   // Allocate enough storage to hold the expected number of strings,
    289   // plus a space between each.  We over-allocate, using the longest
    290   // string above as the base metric.
    291   const int kLongest = 21;  // The strlen of longest string above.
    292   const int count = countOnes(flags);
    293   char* str;
    294   char* cp;
    295   cp = str = reinterpret_cast<char*>(malloc(count * (kLongest + 1) + 1));
    296 
    297   for (int i = 0; i < kNumFlags; i++) {
    298     if (flags & 0x01) {
    299       const char* accessStr = kAccessStrings[forWhat][i];
    300       const int len = strlen(accessStr);
    301       if (cp != str) {
    302         *cp++ = ' ';
    303       }
    304       memcpy(cp, accessStr, len);
    305       cp += len;
    306     }
    307     flags >>= 1;
    308   }  // for
    309 
    310   *cp = '\0';
    311   return str;
    312 }
    313 
    314 /*
    315  * Copies character data from "data" to "out", converting non-ASCII values
    316  * to fprintf format chars or an ASCII filler ('.' or '?').
    317  *
    318  * The output buffer must be able to hold (2*len)+1 bytes.  The result is
    319  * NULL-terminated.
    320  */
    321 static void asciify(char* out, const unsigned char* data, size_t len) {
    322   while (len--) {
    323     if (*data < 0x20) {
    324       // Could do more here, but we don't need them yet.
    325       switch (*data) {
    326         case '\0':
    327           *out++ = '\\';
    328           *out++ = '0';
    329           break;
    330         case '\n':
    331           *out++ = '\\';
    332           *out++ = 'n';
    333           break;
    334         default:
    335           *out++ = '.';
    336           break;
    337       }  // switch
    338     } else if (*data >= 0x80) {
    339       *out++ = '?';
    340     } else {
    341       *out++ = *data;
    342     }
    343     data++;
    344   }  // while
    345   *out = '\0';
    346 }
    347 
    348 /*
    349  * Dumps the file header.
    350  *
    351  * Note that some of the : are misaligned on purpose to preserve
    352  * the exact output of the original Dalvik dexdump.
    353  */
    354 static void dumpFileHeader(const DexFile* pDexFile) {
    355   const DexFile::Header& pHeader = pDexFile->GetHeader();
    356   char sanitized[sizeof(pHeader.magic_) * 2 + 1];
    357   fprintf(gOutFile, "DEX file header:\n");
    358   asciify(sanitized, pHeader.magic_, sizeof(pHeader.magic_));
    359   fprintf(gOutFile, "magic               : '%s'\n", sanitized);
    360   fprintf(gOutFile, "checksum            : %08x\n", pHeader.checksum_);
    361   fprintf(gOutFile, "signature           : %02x%02x...%02x%02x\n",
    362           pHeader.signature_[0], pHeader.signature_[1],
    363           pHeader.signature_[DexFile::kSha1DigestSize - 2],
    364           pHeader.signature_[DexFile::kSha1DigestSize - 1]);
    365   fprintf(gOutFile, "file_size           : %d\n", pHeader.file_size_);
    366   fprintf(gOutFile, "header_size         : %d\n", pHeader.header_size_);
    367   fprintf(gOutFile, "link_size           : %d\n", pHeader.link_size_);
    368   fprintf(gOutFile, "link_off            : %d (0x%06x)\n",
    369           pHeader.link_off_, pHeader.link_off_);
    370   fprintf(gOutFile, "string_ids_size     : %d\n", pHeader.string_ids_size_);
    371   fprintf(gOutFile, "string_ids_off      : %d (0x%06x)\n",
    372           pHeader.string_ids_off_, pHeader.string_ids_off_);
    373   fprintf(gOutFile, "type_ids_size       : %d\n", pHeader.type_ids_size_);
    374   fprintf(gOutFile, "type_ids_off        : %d (0x%06x)\n",
    375           pHeader.type_ids_off_, pHeader.type_ids_off_);
    376   fprintf(gOutFile, "proto_ids_size       : %d\n", pHeader.proto_ids_size_);
    377   fprintf(gOutFile, "proto_ids_off        : %d (0x%06x)\n",
    378           pHeader.proto_ids_off_, pHeader.proto_ids_off_);
    379   fprintf(gOutFile, "field_ids_size      : %d\n", pHeader.field_ids_size_);
    380   fprintf(gOutFile, "field_ids_off       : %d (0x%06x)\n",
    381           pHeader.field_ids_off_, pHeader.field_ids_off_);
    382   fprintf(gOutFile, "method_ids_size     : %d\n", pHeader.method_ids_size_);
    383   fprintf(gOutFile, "method_ids_off      : %d (0x%06x)\n",
    384           pHeader.method_ids_off_, pHeader.method_ids_off_);
    385   fprintf(gOutFile, "class_defs_size     : %d\n", pHeader.class_defs_size_);
    386   fprintf(gOutFile, "class_defs_off      : %d (0x%06x)\n",
    387           pHeader.class_defs_off_, pHeader.class_defs_off_);
    388   fprintf(gOutFile, "data_size           : %d\n", pHeader.data_size_);
    389   fprintf(gOutFile, "data_off            : %d (0x%06x)\n\n",
    390           pHeader.data_off_, pHeader.data_off_);
    391 }
    392 
    393 /*
    394  * Dumps a class_def_item.
    395  */
    396 static void dumpClassDef(const DexFile* pDexFile, int idx) {
    397   // General class information.
    398   const DexFile::ClassDef& pClassDef = pDexFile->GetClassDef(idx);
    399   fprintf(gOutFile, "Class #%d header:\n", idx);
    400   fprintf(gOutFile, "class_idx           : %d\n", pClassDef.class_idx_);
    401   fprintf(gOutFile, "access_flags        : %d (0x%04x)\n",
    402           pClassDef.access_flags_, pClassDef.access_flags_);
    403   fprintf(gOutFile, "superclass_idx      : %d\n", pClassDef.superclass_idx_);
    404   fprintf(gOutFile, "interfaces_off      : %d (0x%06x)\n",
    405           pClassDef.interfaces_off_, pClassDef.interfaces_off_);
    406   fprintf(gOutFile, "source_file_idx     : %d\n", pClassDef.source_file_idx_);
    407   fprintf(gOutFile, "annotations_off     : %d (0x%06x)\n",
    408           pClassDef.annotations_off_, pClassDef.annotations_off_);
    409   fprintf(gOutFile, "class_data_off      : %d (0x%06x)\n",
    410           pClassDef.class_data_off_, pClassDef.class_data_off_);
    411 
    412   // Fields and methods.
    413   const u1* pEncodedData = pDexFile->GetClassData(pClassDef);
    414   if (pEncodedData != nullptr) {
    415     ClassDataItemIterator pClassData(*pDexFile, pEncodedData);
    416     fprintf(gOutFile, "static_fields_size  : %d\n", pClassData.NumStaticFields());
    417     fprintf(gOutFile, "instance_fields_size: %d\n", pClassData.NumInstanceFields());
    418     fprintf(gOutFile, "direct_methods_size : %d\n", pClassData.NumDirectMethods());
    419     fprintf(gOutFile, "virtual_methods_size: %d\n", pClassData.NumVirtualMethods());
    420   } else {
    421     fprintf(gOutFile, "static_fields_size  : 0\n");
    422     fprintf(gOutFile, "instance_fields_size: 0\n");
    423     fprintf(gOutFile, "direct_methods_size : 0\n");
    424     fprintf(gOutFile, "virtual_methods_size: 0\n");
    425   }
    426   fprintf(gOutFile, "\n");
    427 }
    428 
    429 /*
    430  * Dumps an interface that a class declares to implement.
    431  */
    432 static void dumpInterface(const DexFile* pDexFile, const DexFile::TypeItem& pTypeItem, int i) {
    433   const char* interfaceName = pDexFile->StringByTypeIdx(pTypeItem.type_idx_);
    434   if (gOptions.outputFormat == OUTPUT_PLAIN) {
    435     fprintf(gOutFile, "    #%d              : '%s'\n", i, interfaceName);
    436   } else {
    437     char* dotted = descriptorToDot(interfaceName);
    438     fprintf(gOutFile, "<implements name=\"%s\">\n</implements>\n", dotted);
    439     free(dotted);
    440   }
    441 }
    442 
    443 /*
    444  * Dumps the catches table associated with the code.
    445  */
    446 static void dumpCatches(const DexFile* pDexFile, const DexFile::CodeItem* pCode) {
    447   const u4 triesSize = pCode->tries_size_;
    448 
    449   // No catch table.
    450   if (triesSize == 0) {
    451     fprintf(gOutFile, "      catches       : (none)\n");
    452     return;
    453   }
    454 
    455   // Dump all table entries.
    456   fprintf(gOutFile, "      catches       : %d\n", triesSize);
    457   for (u4 i = 0; i < triesSize; i++) {
    458     const DexFile::TryItem* pTry = pDexFile->GetTryItems(*pCode, i);
    459     const u4 start = pTry->start_addr_;
    460     const u4 end = start + pTry->insn_count_;
    461     fprintf(gOutFile, "        0x%04x - 0x%04x\n", start, end);
    462     for (CatchHandlerIterator it(*pCode, *pTry); it.HasNext(); it.Next()) {
    463       const u2 tidx = it.GetHandlerTypeIndex();
    464       const char* descriptor =
    465           (tidx == DexFile::kDexNoIndex16) ? "<any>" : pDexFile->StringByTypeIdx(tidx);
    466       fprintf(gOutFile, "          %s -> 0x%04x\n", descriptor, it.GetHandlerAddress());
    467     }  // for
    468   }  // for
    469 }
    470 
    471 /*
    472  * Callback for dumping each positions table entry.
    473  */
    474 static bool dumpPositionsCb(void* /*context*/, const DexFile::PositionInfo& entry) {
    475   fprintf(gOutFile, "        0x%04x line=%d\n", entry.address_, entry.line_);
    476   return false;
    477 }
    478 
    479 /*
    480  * Callback for dumping locals table entry.
    481  */
    482 static void dumpLocalsCb(void* /*context*/, const DexFile::LocalInfo& entry) {
    483   const char* signature = entry.signature_ != nullptr ? entry.signature_ : "";
    484   fprintf(gOutFile, "        0x%04x - 0x%04x reg=%d %s %s %s\n",
    485           entry.start_address_, entry.end_address_, entry.reg_,
    486           entry.name_, entry.descriptor_, signature);
    487 }
    488 
    489 /*
    490  * Helper for dumpInstruction(), which builds the string
    491  * representation for the index in the given instruction. This will
    492  * first try to use the given buffer, but if the result won't fit,
    493  * then this will allocate a new buffer to hold the result. A pointer
    494  * to the buffer which holds the full result is always returned, and
    495  * this can be compared with the one passed in, to see if the result
    496  * needs to be free()d.
    497  */
    498 static char* indexString(const DexFile* pDexFile,
    499                          const Instruction* pDecInsn, char* buf, size_t bufSize) {
    500   // Determine index and width of the string.
    501   u4 index = 0;
    502   u4 width = 4;
    503   switch (Instruction::FormatOf(pDecInsn->Opcode())) {
    504     // SOME NOT SUPPORTED:
    505     // case Instruction::k20bc:
    506     case Instruction::k21c:
    507     case Instruction::k35c:
    508     // case Instruction::k35ms:
    509     case Instruction::k3rc:
    510     // case Instruction::k3rms:
    511     // case Instruction::k35mi:
    512     // case Instruction::k3rmi:
    513       index = pDecInsn->VRegB();
    514       width = 4;
    515       break;
    516     case Instruction::k31c:
    517       index = pDecInsn->VRegB();
    518       width = 8;
    519       break;
    520     case Instruction::k22c:
    521     // case Instruction::k22cs:
    522       index = pDecInsn->VRegC();
    523       width = 4;
    524       break;
    525     default:
    526       break;
    527   }  // switch
    528 
    529   // Determine index type.
    530   size_t outSize = 0;
    531   switch (Instruction::IndexTypeOf(pDecInsn->Opcode())) {
    532     case Instruction::kIndexUnknown:
    533       // This function should never get called for this type, but do
    534       // something sensible here, just to help with debugging.
    535       outSize = snprintf(buf, bufSize, "<unknown-index>");
    536       break;
    537     case Instruction::kIndexNone:
    538       // This function should never get called for this type, but do
    539       // something sensible here, just to help with debugging.
    540       outSize = snprintf(buf, bufSize, "<no-index>");
    541       break;
    542     case Instruction::kIndexTypeRef:
    543       if (index < pDexFile->GetHeader().type_ids_size_) {
    544         const char* tp = pDexFile->StringByTypeIdx(index);
    545         outSize = snprintf(buf, bufSize, "%s // type@%0*x", tp, width, index);
    546       } else {
    547         outSize = snprintf(buf, bufSize, "<type?> // type@%0*x", width, index);
    548       }
    549       break;
    550     case Instruction::kIndexStringRef:
    551       if (index < pDexFile->GetHeader().string_ids_size_) {
    552         const char* st = pDexFile->StringDataByIdx(index);
    553         outSize = snprintf(buf, bufSize, "\"%s\" // string@%0*x", st, width, index);
    554       } else {
    555         outSize = snprintf(buf, bufSize, "<string?> // string@%0*x", width, index);
    556       }
    557       break;
    558     case Instruction::kIndexMethodRef:
    559       if (index < pDexFile->GetHeader().method_ids_size_) {
    560         const DexFile::MethodId& pMethodId = pDexFile->GetMethodId(index);
    561         const char* name = pDexFile->StringDataByIdx(pMethodId.name_idx_);
    562         const Signature signature = pDexFile->GetMethodSignature(pMethodId);
    563         const char* backDescriptor = pDexFile->StringByTypeIdx(pMethodId.class_idx_);
    564         outSize = snprintf(buf, bufSize, "%s.%s:%s // method@%0*x",
    565                            backDescriptor, name, signature.ToString().c_str(), width, index);
    566       } else {
    567         outSize = snprintf(buf, bufSize, "<method?> // method@%0*x", width, index);
    568       }
    569       break;
    570     case Instruction::kIndexFieldRef:
    571       if (index < pDexFile->GetHeader().field_ids_size_) {
    572         const DexFile::FieldId& pFieldId = pDexFile->GetFieldId(index);
    573         const char* name = pDexFile->StringDataByIdx(pFieldId.name_idx_);
    574         const char* typeDescriptor = pDexFile->StringByTypeIdx(pFieldId.type_idx_);
    575         const char* backDescriptor = pDexFile->StringByTypeIdx(pFieldId.class_idx_);
    576         outSize = snprintf(buf, bufSize, "%s.%s:%s // field@%0*x",
    577                            backDescriptor, name, typeDescriptor, width, index);
    578       } else {
    579         outSize = snprintf(buf, bufSize, "<field?> // field@%0*x", width, index);
    580       }
    581       break;
    582     case Instruction::kIndexVtableOffset:
    583       outSize = snprintf(buf, bufSize, "[%0*x] // vtable #%0*x",
    584                          width, index, width, index);
    585       break;
    586     case Instruction::kIndexFieldOffset:
    587       outSize = snprintf(buf, bufSize, "[obj+%0*x]", width, index);
    588       break;
    589     // SOME NOT SUPPORTED:
    590     // case Instruction::kIndexVaries:
    591     // case Instruction::kIndexInlineMethod:
    592     default:
    593       outSize = snprintf(buf, bufSize, "<?>");
    594       break;
    595   }  // switch
    596 
    597   // Determine success of string construction.
    598   if (outSize >= bufSize) {
    599     // The buffer wasn't big enough; allocate and retry. Note:
    600     // snprintf() doesn't count the '\0' as part of its returned
    601     // size, so we add explicit space for it here.
    602     outSize++;
    603     buf = reinterpret_cast<char*>(malloc(outSize));
    604     if (buf == nullptr) {
    605       return nullptr;
    606     }
    607     return indexString(pDexFile, pDecInsn, buf, outSize);
    608   }
    609   return buf;
    610 }
    611 
    612 /*
    613  * Dumps a single instruction.
    614  */
    615 static void dumpInstruction(const DexFile* pDexFile,
    616                             const DexFile::CodeItem* pCode,
    617                             u4 codeOffset, u4 insnIdx, u4 insnWidth,
    618                             const Instruction* pDecInsn) {
    619   // Address of instruction (expressed as byte offset).
    620   fprintf(gOutFile, "%06x:", codeOffset + 0x10 + insnIdx * 2);
    621 
    622   // Dump (part of) raw bytes.
    623   const u2* insns = pCode->insns_;
    624   for (u4 i = 0; i < 8; i++) {
    625     if (i < insnWidth) {
    626       if (i == 7) {
    627         fprintf(gOutFile, " ... ");
    628       } else {
    629         // Print 16-bit value in little-endian order.
    630         const u1* bytePtr = (const u1*) &insns[insnIdx + i];
    631         fprintf(gOutFile, " %02x%02x", bytePtr[0], bytePtr[1]);
    632       }
    633     } else {
    634       fputs("     ", gOutFile);
    635     }
    636   }  // for
    637 
    638   // Dump pseudo-instruction or opcode.
    639   if (pDecInsn->Opcode() == Instruction::NOP) {
    640     const u2 instr = get2LE((const u1*) &insns[insnIdx]);
    641     if (instr == Instruction::kPackedSwitchSignature) {
    642       fprintf(gOutFile, "|%04x: packed-switch-data (%d units)", insnIdx, insnWidth);
    643     } else if (instr == Instruction::kSparseSwitchSignature) {
    644       fprintf(gOutFile, "|%04x: sparse-switch-data (%d units)", insnIdx, insnWidth);
    645     } else if (instr == Instruction::kArrayDataSignature) {
    646       fprintf(gOutFile, "|%04x: array-data (%d units)", insnIdx, insnWidth);
    647     } else {
    648       fprintf(gOutFile, "|%04x: nop // spacer", insnIdx);
    649     }
    650   } else {
    651     fprintf(gOutFile, "|%04x: %s", insnIdx, pDecInsn->Name());
    652   }
    653 
    654   // Set up additional argument.
    655   char indexBufChars[200];
    656   char *indexBuf = indexBufChars;
    657   if (Instruction::IndexTypeOf(pDecInsn->Opcode()) != Instruction::kIndexNone) {
    658     indexBuf = indexString(pDexFile, pDecInsn,
    659                            indexBufChars, sizeof(indexBufChars));
    660   }
    661 
    662   // Dump the instruction.
    663   //
    664   // NOTE: pDecInsn->DumpString(pDexFile) differs too much from original.
    665   //
    666   switch (Instruction::FormatOf(pDecInsn->Opcode())) {
    667     case Instruction::k10x:        // op
    668       break;
    669     case Instruction::k12x:        // op vA, vB
    670       fprintf(gOutFile, " v%d, v%d", pDecInsn->VRegA(), pDecInsn->VRegB());
    671       break;
    672     case Instruction::k11n:        // op vA, #+B
    673       fprintf(gOutFile, " v%d, #int %d // #%x",
    674               pDecInsn->VRegA(), (s4) pDecInsn->VRegB(), (u1)pDecInsn->VRegB());
    675       break;
    676     case Instruction::k11x:        // op vAA
    677       fprintf(gOutFile, " v%d", pDecInsn->VRegA());
    678       break;
    679     case Instruction::k10t:        // op +AA
    680     case Instruction::k20t:        // op +AAAA
    681       {
    682         const s4 targ = (s4) pDecInsn->VRegA();
    683         fprintf(gOutFile, " %04x // %c%04x",
    684                 insnIdx + targ,
    685                 (targ < 0) ? '-' : '+',
    686                 (targ < 0) ? -targ : targ);
    687       }
    688       break;
    689     case Instruction::k22x:        // op vAA, vBBBB
    690       fprintf(gOutFile, " v%d, v%d", pDecInsn->VRegA(), pDecInsn->VRegB());
    691       break;
    692     case Instruction::k21t:        // op vAA, +BBBB
    693       {
    694         const s4 targ = (s4) pDecInsn->VRegB();
    695         fprintf(gOutFile, " v%d, %04x // %c%04x", pDecInsn->VRegA(),
    696                 insnIdx + targ,
    697                 (targ < 0) ? '-' : '+',
    698                 (targ < 0) ? -targ : targ);
    699       }
    700       break;
    701     case Instruction::k21s:        // op vAA, #+BBBB
    702       fprintf(gOutFile, " v%d, #int %d // #%x",
    703               pDecInsn->VRegA(), (s4) pDecInsn->VRegB(), (u2)pDecInsn->VRegB());
    704       break;
    705     case Instruction::k21h:        // op vAA, #+BBBB0000[00000000]
    706       // The printed format varies a bit based on the actual opcode.
    707       if (pDecInsn->Opcode() == Instruction::CONST_HIGH16) {
    708         const s4 value = pDecInsn->VRegB() << 16;
    709         fprintf(gOutFile, " v%d, #int %d // #%x",
    710                 pDecInsn->VRegA(), value, (u2) pDecInsn->VRegB());
    711       } else {
    712         const s8 value = ((s8) pDecInsn->VRegB()) << 48;
    713         fprintf(gOutFile, " v%d, #long %" PRId64 " // #%x",
    714                 pDecInsn->VRegA(), value, (u2) pDecInsn->VRegB());
    715       }
    716       break;
    717     case Instruction::k21c:        // op vAA, thing@BBBB
    718     case Instruction::k31c:        // op vAA, thing@BBBBBBBB
    719       fprintf(gOutFile, " v%d, %s", pDecInsn->VRegA(), indexBuf);
    720       break;
    721     case Instruction::k23x:        // op vAA, vBB, vCC
    722       fprintf(gOutFile, " v%d, v%d, v%d",
    723               pDecInsn->VRegA(), pDecInsn->VRegB(), pDecInsn->VRegC());
    724       break;
    725     case Instruction::k22b:        // op vAA, vBB, #+CC
    726       fprintf(gOutFile, " v%d, v%d, #int %d // #%02x",
    727               pDecInsn->VRegA(), pDecInsn->VRegB(),
    728               (s4) pDecInsn->VRegC(), (u1) pDecInsn->VRegC());
    729       break;
    730     case Instruction::k22t:        // op vA, vB, +CCCC
    731       {
    732         const s4 targ = (s4) pDecInsn->VRegC();
    733         fprintf(gOutFile, " v%d, v%d, %04x // %c%04x",
    734                 pDecInsn->VRegA(), pDecInsn->VRegB(),
    735                 insnIdx + targ,
    736                 (targ < 0) ? '-' : '+',
    737                 (targ < 0) ? -targ : targ);
    738       }
    739       break;
    740     case Instruction::k22s:        // op vA, vB, #+CCCC
    741       fprintf(gOutFile, " v%d, v%d, #int %d // #%04x",
    742               pDecInsn->VRegA(), pDecInsn->VRegB(),
    743               (s4) pDecInsn->VRegC(), (u2) pDecInsn->VRegC());
    744       break;
    745     case Instruction::k22c:        // op vA, vB, thing@CCCC
    746     // NOT SUPPORTED:
    747     // case Instruction::k22cs:    // [opt] op vA, vB, field offset CCCC
    748       fprintf(gOutFile, " v%d, v%d, %s",
    749               pDecInsn->VRegA(), pDecInsn->VRegB(), indexBuf);
    750       break;
    751     case Instruction::k30t:
    752       fprintf(gOutFile, " #%08x", pDecInsn->VRegA());
    753       break;
    754     case Instruction::k31i:        // op vAA, #+BBBBBBBB
    755       {
    756         // This is often, but not always, a float.
    757         union {
    758           float f;
    759           u4 i;
    760         } conv;
    761         conv.i = pDecInsn->VRegB();
    762         fprintf(gOutFile, " v%d, #float %f // #%08x",
    763                 pDecInsn->VRegA(), conv.f, pDecInsn->VRegB());
    764       }
    765       break;
    766     case Instruction::k31t:       // op vAA, offset +BBBBBBBB
    767       fprintf(gOutFile, " v%d, %08x // +%08x",
    768               pDecInsn->VRegA(), insnIdx + pDecInsn->VRegB(), pDecInsn->VRegB());
    769       break;
    770     case Instruction::k32x:        // op vAAAA, vBBBB
    771       fprintf(gOutFile, " v%d, v%d", pDecInsn->VRegA(), pDecInsn->VRegB());
    772       break;
    773     case Instruction::k35c:        // op {vC, vD, vE, vF, vG}, thing@BBBB
    774     // NOT SUPPORTED:
    775     // case Instruction::k35ms:       // [opt] invoke-virtual+super
    776     // case Instruction::k35mi:       // [opt] inline invoke
    777       {
    778         u4 arg[Instruction::kMaxVarArgRegs];
    779         pDecInsn->GetVarArgs(arg);
    780         fputs(" {", gOutFile);
    781         for (int i = 0, n = pDecInsn->VRegA(); i < n; i++) {
    782           if (i == 0) {
    783             fprintf(gOutFile, "v%d", arg[i]);
    784           } else {
    785             fprintf(gOutFile, ", v%d", arg[i]);
    786           }
    787         }  // for
    788         fprintf(gOutFile, "}, %s", indexBuf);
    789       }
    790       break;
    791     case Instruction::k25x:        // op vC, {vD, vE, vF, vG} (B: count)
    792       {
    793         u4 arg[Instruction::kMaxVarArgRegs25x];
    794         pDecInsn->GetAllArgs25x(arg);
    795         fprintf(gOutFile, " v%d, {", arg[0]);
    796         for (int i = 0, n = pDecInsn->VRegB(); i < n; i++) {
    797           if (i == 0) {
    798             fprintf(gOutFile, "v%d", arg[Instruction::kLambdaVirtualRegisterWidth + i]);
    799           } else {
    800             fprintf(gOutFile, ", v%d", arg[Instruction::kLambdaVirtualRegisterWidth + i]);
    801           }
    802         }  // for
    803         fputc('}', gOutFile);
    804       }
    805       break;
    806     case Instruction::k3rc:        // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB
    807     // NOT SUPPORTED:
    808     // case Instruction::k3rms:       // [opt] invoke-virtual+super/range
    809     // case Instruction::k3rmi:       // [opt] execute-inline/range
    810       {
    811         // This doesn't match the "dx" output when some of the args are
    812         // 64-bit values -- dx only shows the first register.
    813         fputs(" {", gOutFile);
    814         for (int i = 0, n = pDecInsn->VRegA(); i < n; i++) {
    815           if (i == 0) {
    816             fprintf(gOutFile, "v%d", pDecInsn->VRegC() + i);
    817           } else {
    818             fprintf(gOutFile, ", v%d", pDecInsn->VRegC() + i);
    819           }
    820         }  // for
    821         fprintf(gOutFile, "}, %s", indexBuf);
    822       }
    823       break;
    824     case Instruction::k51l:        // op vAA, #+BBBBBBBBBBBBBBBB
    825       {
    826         // This is often, but not always, a double.
    827         union {
    828           double d;
    829           u8 j;
    830         } conv;
    831         conv.j = pDecInsn->WideVRegB();
    832         fprintf(gOutFile, " v%d, #double %f // #%016" PRIx64,
    833                 pDecInsn->VRegA(), conv.d, pDecInsn->WideVRegB());
    834       }
    835       break;
    836     // NOT SUPPORTED:
    837     // case Instruction::k00x:        // unknown op or breakpoint
    838     //    break;
    839     default:
    840       fprintf(gOutFile, " ???");
    841       break;
    842   }  // switch
    843 
    844   fputc('\n', gOutFile);
    845 
    846   if (indexBuf != indexBufChars) {
    847     free(indexBuf);
    848   }
    849 }
    850 
    851 /*
    852  * Dumps a bytecode disassembly.
    853  */
    854 static void dumpBytecodes(const DexFile* pDexFile, u4 idx,
    855                           const DexFile::CodeItem* pCode, u4 codeOffset) {
    856   const DexFile::MethodId& pMethodId = pDexFile->GetMethodId(idx);
    857   const char* name = pDexFile->StringDataByIdx(pMethodId.name_idx_);
    858   const Signature signature = pDexFile->GetMethodSignature(pMethodId);
    859   const char* backDescriptor = pDexFile->StringByTypeIdx(pMethodId.class_idx_);
    860 
    861   // Generate header.
    862   char* tmp = descriptorToDot(backDescriptor);
    863   fprintf(gOutFile, "%06x:                                        "
    864           "|[%06x] %s.%s:%s\n",
    865           codeOffset, codeOffset, tmp, name, signature.ToString().c_str());
    866   free(tmp);
    867 
    868   // Iterate over all instructions.
    869   const u2* insns = pCode->insns_;
    870   for (u4 insnIdx = 0; insnIdx < pCode->insns_size_in_code_units_;) {
    871     const Instruction* instruction = Instruction::At(&insns[insnIdx]);
    872     const u4 insnWidth = instruction->SizeInCodeUnits();
    873     if (insnWidth == 0) {
    874       fprintf(stderr, "GLITCH: zero-width instruction at idx=0x%04x\n", insnIdx);
    875       break;
    876     }
    877     dumpInstruction(pDexFile, pCode, codeOffset, insnIdx, insnWidth, instruction);
    878     insnIdx += insnWidth;
    879   }  // for
    880 }
    881 
    882 /*
    883  * Dumps code of a method.
    884  */
    885 static void dumpCode(const DexFile* pDexFile, u4 idx, u4 flags,
    886                      const DexFile::CodeItem* pCode, u4 codeOffset) {
    887   fprintf(gOutFile, "      registers     : %d\n", pCode->registers_size_);
    888   fprintf(gOutFile, "      ins           : %d\n", pCode->ins_size_);
    889   fprintf(gOutFile, "      outs          : %d\n", pCode->outs_size_);
    890   fprintf(gOutFile, "      insns size    : %d 16-bit code units\n",
    891           pCode->insns_size_in_code_units_);
    892 
    893   // Bytecode disassembly, if requested.
    894   if (gOptions.disassemble) {
    895     dumpBytecodes(pDexFile, idx, pCode, codeOffset);
    896   }
    897 
    898   // Try-catch blocks.
    899   dumpCatches(pDexFile, pCode);
    900 
    901   // Positions and locals table in the debug info.
    902   bool is_static = (flags & kAccStatic) != 0;
    903   fprintf(gOutFile, "      positions     : \n");
    904   pDexFile->DecodeDebugPositionInfo(pCode, dumpPositionsCb, nullptr);
    905   fprintf(gOutFile, "      locals        : \n");
    906   pDexFile->DecodeDebugLocalInfo(pCode, is_static, idx, dumpLocalsCb, nullptr);
    907 }
    908 
    909 /*
    910  * Dumps a method.
    911  */
    912 static void dumpMethod(const DexFile* pDexFile, u4 idx, u4 flags,
    913                        const DexFile::CodeItem* pCode, u4 codeOffset, int i) {
    914   // Bail for anything private if export only requested.
    915   if (gOptions.exportsOnly && (flags & (kAccPublic | kAccProtected)) == 0) {
    916     return;
    917   }
    918 
    919   const DexFile::MethodId& pMethodId = pDexFile->GetMethodId(idx);
    920   const char* name = pDexFile->StringDataByIdx(pMethodId.name_idx_);
    921   const Signature signature = pDexFile->GetMethodSignature(pMethodId);
    922   char* typeDescriptor = strdup(signature.ToString().c_str());
    923   const char* backDescriptor = pDexFile->StringByTypeIdx(pMethodId.class_idx_);
    924   char* accessStr = createAccessFlagStr(flags, kAccessForMethod);
    925 
    926   if (gOptions.outputFormat == OUTPUT_PLAIN) {
    927     fprintf(gOutFile, "    #%d              : (in %s)\n", i, backDescriptor);
    928     fprintf(gOutFile, "      name          : '%s'\n", name);
    929     fprintf(gOutFile, "      type          : '%s'\n", typeDescriptor);
    930     fprintf(gOutFile, "      access        : 0x%04x (%s)\n", flags, accessStr);
    931     if (pCode == nullptr) {
    932       fprintf(gOutFile, "      code          : (none)\n");
    933     } else {
    934       fprintf(gOutFile, "      code          -\n");
    935       dumpCode(pDexFile, idx, flags, pCode, codeOffset);
    936     }
    937     if (gOptions.disassemble) {
    938       fputc('\n', gOutFile);
    939     }
    940   } else if (gOptions.outputFormat == OUTPUT_XML) {
    941     const bool constructor = (name[0] == '<');
    942 
    943     // Method name and prototype.
    944     if (constructor) {
    945       char* tmp = descriptorClassToDot(backDescriptor);
    946       fprintf(gOutFile, "<constructor name=\"%s\"\n", tmp);
    947       free(tmp);
    948       tmp = descriptorToDot(backDescriptor);
    949       fprintf(gOutFile, " type=\"%s\"\n", tmp);
    950       free(tmp);
    951     } else {
    952       fprintf(gOutFile, "<method name=\"%s\"\n", name);
    953       const char* returnType = strrchr(typeDescriptor, ')');
    954       if (returnType == nullptr) {
    955         fprintf(stderr, "bad method type descriptor '%s'\n", typeDescriptor);
    956         goto bail;
    957       }
    958       char* tmp = descriptorToDot(returnType+1);
    959       fprintf(gOutFile, " return=\"%s\"\n", tmp);
    960       free(tmp);
    961       fprintf(gOutFile, " abstract=%s\n", quotedBool((flags & kAccAbstract) != 0));
    962       fprintf(gOutFile, " native=%s\n", quotedBool((flags & kAccNative) != 0));
    963       fprintf(gOutFile, " synchronized=%s\n", quotedBool(
    964           (flags & (kAccSynchronized | kAccDeclaredSynchronized)) != 0));
    965     }
    966 
    967     // Additional method flags.
    968     fprintf(gOutFile, " static=%s\n", quotedBool((flags & kAccStatic) != 0));
    969     fprintf(gOutFile, " final=%s\n", quotedBool((flags & kAccFinal) != 0));
    970     // The "deprecated=" not knowable w/o parsing annotations.
    971     fprintf(gOutFile, " visibility=%s\n>\n", quotedVisibility(flags));
    972 
    973     // Parameters.
    974     if (typeDescriptor[0] != '(') {
    975       fprintf(stderr, "ERROR: bad descriptor '%s'\n", typeDescriptor);
    976       goto bail;
    977     }
    978     char* tmpBuf = reinterpret_cast<char*>(malloc(strlen(typeDescriptor) + 1));
    979     const char* base = typeDescriptor + 1;
    980     int argNum = 0;
    981     while (*base != ')') {
    982       char* cp = tmpBuf;
    983       while (*base == '[') {
    984         *cp++ = *base++;
    985       }
    986       if (*base == 'L') {
    987         // Copy through ';'.
    988         do {
    989           *cp = *base++;
    990         } while (*cp++ != ';');
    991       } else {
    992         // Primitive char, copy it.
    993         if (strchr("ZBCSIFJD", *base) == NULL) {
    994           fprintf(stderr, "ERROR: bad method signature '%s'\n", base);
    995           goto bail;
    996         }
    997         *cp++ = *base++;
    998       }
    999       // Null terminate and display.
   1000       *cp++ = '\0';
   1001       char* tmp = descriptorToDot(tmpBuf);
   1002       fprintf(gOutFile, "<parameter name=\"arg%d\" type=\"%s\">\n"
   1003                         "</parameter>\n", argNum++, tmp);
   1004       free(tmp);
   1005     }  // while
   1006     free(tmpBuf);
   1007     if (constructor) {
   1008       fprintf(gOutFile, "</constructor>\n");
   1009     } else {
   1010       fprintf(gOutFile, "</method>\n");
   1011     }
   1012   }
   1013 
   1014  bail:
   1015   free(typeDescriptor);
   1016   free(accessStr);
   1017 }
   1018 
   1019 /*
   1020  * Dumps a string value with some escape characters.
   1021  */
   1022 static void dumpEscapedString(const char* p) {
   1023   for (; *p; p++) {
   1024     switch (*p) {
   1025       case '\\':
   1026         fputs("\\\\", gOutFile);
   1027         break;
   1028       case '\"':
   1029         fputs("\\\"", gOutFile);
   1030         break;
   1031       case '\t':
   1032         fputs("\\t", gOutFile);
   1033         break;
   1034       case '\n':
   1035         fputs("\\n", gOutFile);
   1036         break;
   1037       case '\r':
   1038         fputs("\\r", gOutFile);
   1039         break;
   1040       default:
   1041         putc(*p, gOutFile);
   1042     }
   1043   }
   1044 }
   1045 
   1046 /*
   1047  * Dumps an XML attribute value between double-quotes.
   1048  */
   1049 static void dumpXmlAttribute(const char* p) {
   1050   for (; *p; p++) {
   1051     switch (*p) {
   1052       case '&':
   1053         fputs("&amp;", gOutFile);
   1054         break;
   1055       case '<':
   1056         fputs("&lt;", gOutFile);
   1057         break;
   1058       case '"':
   1059         fputs("&quot;", gOutFile);
   1060         break;
   1061       case '\t':
   1062         fputs("&#x9;", gOutFile);
   1063         break;
   1064       case '\n':
   1065         fputs("&#xA;", gOutFile);
   1066         break;
   1067       case '\r':
   1068         fputs("&#xD;", gOutFile);
   1069         break;
   1070       default:
   1071         putc(*p, gOutFile);
   1072     }
   1073   }
   1074 }
   1075 
   1076 /*
   1077  * Dumps a value of static (class) field.
   1078  */
   1079 static void dumpSFieldValue(const DexFile* pDexFile,
   1080                             EncodedStaticFieldValueIterator::ValueType valueType,
   1081                             const jvalue* pValue) {
   1082   switch (valueType) {
   1083     case EncodedStaticFieldValueIterator::kByte:
   1084       fprintf(gOutFile, "%" PRIu8, pValue->b);
   1085       break;
   1086     case EncodedStaticFieldValueIterator::kShort:
   1087       fprintf(gOutFile, "%" PRId16, pValue->s);
   1088       break;
   1089     case EncodedStaticFieldValueIterator::kChar:
   1090       fprintf(gOutFile, "%" PRIu16, pValue->c);
   1091       break;
   1092     case EncodedStaticFieldValueIterator::kInt:
   1093       fprintf(gOutFile, "%" PRId32, pValue->i);
   1094       break;
   1095     case EncodedStaticFieldValueIterator::kLong:
   1096       fprintf(gOutFile, "%" PRId64, pValue->j);
   1097       break;
   1098     case EncodedStaticFieldValueIterator::kFloat:
   1099       fprintf(gOutFile, "%f", pValue->f);
   1100       break;
   1101     case EncodedStaticFieldValueIterator::kDouble:
   1102       fprintf(gOutFile, "%f", pValue->d);
   1103       break;
   1104     case EncodedStaticFieldValueIterator::kString: {
   1105       const char* str =
   1106           pDexFile->GetStringData(pDexFile->GetStringId(pValue->i));
   1107       if (gOptions.outputFormat == OUTPUT_PLAIN) {
   1108         fputs("\"", gOutFile);
   1109         dumpEscapedString(str);
   1110         fputs("\"", gOutFile);
   1111       } else {
   1112         dumpXmlAttribute(str);
   1113       }
   1114       break;
   1115     }
   1116     case EncodedStaticFieldValueIterator::kNull:
   1117       fputs("null", gOutFile);
   1118       break;
   1119     case EncodedStaticFieldValueIterator::kBoolean:
   1120       fputs(pValue->z ? "true" : "false", gOutFile);
   1121       break;
   1122 
   1123     case EncodedStaticFieldValueIterator::kAnnotation:
   1124     case EncodedStaticFieldValueIterator::kArray:
   1125     case EncodedStaticFieldValueIterator::kEnum:
   1126     case EncodedStaticFieldValueIterator::kField:
   1127     case EncodedStaticFieldValueIterator::kMethod:
   1128     case EncodedStaticFieldValueIterator::kType:
   1129     default:
   1130       fprintf(gOutFile, "Unexpected static field type: %d", valueType);
   1131   }
   1132 }
   1133 
   1134 /*
   1135  * Dumps a static (class) field.
   1136  */
   1137 static void dumpSField(const DexFile* pDexFile, u4 idx, u4 flags, int i,
   1138                        EncodedStaticFieldValueIterator::ValueType valueType,
   1139                        const jvalue* pValue) {
   1140   // Bail for anything private if export only requested.
   1141   if (gOptions.exportsOnly && (flags & (kAccPublic | kAccProtected)) == 0) {
   1142     return;
   1143   }
   1144 
   1145   const DexFile::FieldId& pFieldId = pDexFile->GetFieldId(idx);
   1146   const char* name = pDexFile->StringDataByIdx(pFieldId.name_idx_);
   1147   const char* typeDescriptor = pDexFile->StringByTypeIdx(pFieldId.type_idx_);
   1148   const char* backDescriptor = pDexFile->StringByTypeIdx(pFieldId.class_idx_);
   1149   char* accessStr = createAccessFlagStr(flags, kAccessForField);
   1150 
   1151   if (gOptions.outputFormat == OUTPUT_PLAIN) {
   1152     fprintf(gOutFile, "    #%d              : (in %s)\n", i, backDescriptor);
   1153     fprintf(gOutFile, "      name          : '%s'\n", name);
   1154     fprintf(gOutFile, "      type          : '%s'\n", typeDescriptor);
   1155     fprintf(gOutFile, "      access        : 0x%04x (%s)\n", flags, accessStr);
   1156     if (pValue != nullptr) {
   1157       fputs("      value         : ", gOutFile);
   1158       dumpSFieldValue(pDexFile, valueType, pValue);
   1159       fputs("\n", gOutFile);
   1160     }
   1161   } else if (gOptions.outputFormat == OUTPUT_XML) {
   1162     fprintf(gOutFile, "<field name=\"%s\"\n", name);
   1163     char *tmp = descriptorToDot(typeDescriptor);
   1164     fprintf(gOutFile, " type=\"%s\"\n", tmp);
   1165     free(tmp);
   1166     fprintf(gOutFile, " transient=%s\n", quotedBool((flags & kAccTransient) != 0));
   1167     fprintf(gOutFile, " volatile=%s\n", quotedBool((flags & kAccVolatile) != 0));
   1168     // The "value=" is not knowable w/o parsing annotations.
   1169     fprintf(gOutFile, " static=%s\n", quotedBool((flags & kAccStatic) != 0));
   1170     fprintf(gOutFile, " final=%s\n", quotedBool((flags & kAccFinal) != 0));
   1171     // The "deprecated=" is not knowable w/o parsing annotations.
   1172     fprintf(gOutFile, " visibility=%s\n", quotedVisibility(flags));
   1173     if (pValue != nullptr) {
   1174       fputs(" value=\"", gOutFile);
   1175       dumpSFieldValue(pDexFile, valueType, pValue);
   1176       fputs("\"\n", gOutFile);
   1177     }
   1178     fputs(">\n</field>\n", gOutFile);
   1179   }
   1180 
   1181   free(accessStr);
   1182 }
   1183 
   1184 /*
   1185  * Dumps an instance field.
   1186  */
   1187 static void dumpIField(const DexFile* pDexFile, u4 idx, u4 flags, int i) {
   1188   dumpSField(pDexFile, idx, flags, i,
   1189              EncodedStaticFieldValueIterator::kByte, nullptr);
   1190 }
   1191 
   1192 /*
   1193  * Dumping a CFG. Note that this will do duplicate work. utils.h doesn't expose the code-item
   1194  * version, so the DumpMethodCFG code will have to iterate again to find it. But dexdump is a
   1195  * tool, so this is not performance-critical.
   1196  */
   1197 
   1198 static void dumpCfg(const DexFile* dex_file,
   1199                     uint32_t dex_method_idx,
   1200                     const DexFile::CodeItem* code_item) {
   1201   if (code_item != nullptr) {
   1202     std::ostringstream oss;
   1203     DumpMethodCFG(dex_file, dex_method_idx, oss);
   1204     fprintf(gOutFile, "%s", oss.str().c_str());
   1205   }
   1206 }
   1207 
   1208 static void dumpCfg(const DexFile* dex_file, int idx) {
   1209   const DexFile::ClassDef& class_def = dex_file->GetClassDef(idx);
   1210   const uint8_t* class_data = dex_file->GetClassData(class_def);
   1211   if (class_data == nullptr) {  // empty class such as a marker interface?
   1212     return;
   1213   }
   1214   ClassDataItemIterator it(*dex_file, class_data);
   1215   while (it.HasNextStaticField()) {
   1216     it.Next();
   1217   }
   1218   while (it.HasNextInstanceField()) {
   1219     it.Next();
   1220   }
   1221   while (it.HasNextDirectMethod()) {
   1222     dumpCfg(dex_file,
   1223             it.GetMemberIndex(),
   1224             it.GetMethodCodeItem());
   1225     it.Next();
   1226   }
   1227   while (it.HasNextVirtualMethod()) {
   1228     dumpCfg(dex_file,
   1229                 it.GetMemberIndex(),
   1230                 it.GetMethodCodeItem());
   1231     it.Next();
   1232   }
   1233 }
   1234 
   1235 /*
   1236  * Dumps the class.
   1237  *
   1238  * Note "idx" is a DexClassDef index, not a DexTypeId index.
   1239  *
   1240  * If "*pLastPackage" is nullptr or does not match the current class' package,
   1241  * the value will be replaced with a newly-allocated string.
   1242  */
   1243 static void dumpClass(const DexFile* pDexFile, int idx, char** pLastPackage) {
   1244   const DexFile::ClassDef& pClassDef = pDexFile->GetClassDef(idx);
   1245 
   1246   // Omitting non-public class.
   1247   if (gOptions.exportsOnly && (pClassDef.access_flags_ & kAccPublic) == 0) {
   1248     return;
   1249   }
   1250 
   1251   if (gOptions.cfg) {
   1252     dumpCfg(pDexFile, idx);
   1253     return;
   1254   }
   1255 
   1256   // For the XML output, show the package name.  Ideally we'd gather
   1257   // up the classes, sort them, and dump them alphabetically so the
   1258   // package name wouldn't jump around, but that's not a great plan
   1259   // for something that needs to run on the device.
   1260   const char* classDescriptor = pDexFile->StringByTypeIdx(pClassDef.class_idx_);
   1261   if (!(classDescriptor[0] == 'L' &&
   1262         classDescriptor[strlen(classDescriptor)-1] == ';')) {
   1263     // Arrays and primitives should not be defined explicitly. Keep going?
   1264     fprintf(stderr, "Malformed class name '%s'\n", classDescriptor);
   1265   } else if (gOptions.outputFormat == OUTPUT_XML) {
   1266     char* mangle = strdup(classDescriptor + 1);
   1267     mangle[strlen(mangle)-1] = '\0';
   1268 
   1269     // Reduce to just the package name.
   1270     char* lastSlash = strrchr(mangle, '/');
   1271     if (lastSlash != nullptr) {
   1272       *lastSlash = '\0';
   1273     } else {
   1274       *mangle = '\0';
   1275     }
   1276 
   1277     for (char* cp = mangle; *cp != '\0'; cp++) {
   1278       if (*cp == '/') {
   1279         *cp = '.';
   1280       }
   1281     }  // for
   1282 
   1283     if (*pLastPackage == nullptr || strcmp(mangle, *pLastPackage) != 0) {
   1284       // Start of a new package.
   1285       if (*pLastPackage != nullptr) {
   1286         fprintf(gOutFile, "</package>\n");
   1287       }
   1288       fprintf(gOutFile, "<package name=\"%s\"\n>\n", mangle);
   1289       free(*pLastPackage);
   1290       *pLastPackage = mangle;
   1291     } else {
   1292       free(mangle);
   1293     }
   1294   }
   1295 
   1296   // General class information.
   1297   char* accessStr = createAccessFlagStr(pClassDef.access_flags_, kAccessForClass);
   1298   const char* superclassDescriptor;
   1299   if (pClassDef.superclass_idx_ == DexFile::kDexNoIndex16) {
   1300     superclassDescriptor = nullptr;
   1301   } else {
   1302     superclassDescriptor = pDexFile->StringByTypeIdx(pClassDef.superclass_idx_);
   1303   }
   1304   if (gOptions.outputFormat == OUTPUT_PLAIN) {
   1305     fprintf(gOutFile, "Class #%d            -\n", idx);
   1306     fprintf(gOutFile, "  Class descriptor  : '%s'\n", classDescriptor);
   1307     fprintf(gOutFile, "  Access flags      : 0x%04x (%s)\n", pClassDef.access_flags_, accessStr);
   1308     if (superclassDescriptor != nullptr) {
   1309       fprintf(gOutFile, "  Superclass        : '%s'\n", superclassDescriptor);
   1310     }
   1311     fprintf(gOutFile, "  Interfaces        -\n");
   1312   } else {
   1313     char* tmp = descriptorClassToDot(classDescriptor);
   1314     fprintf(gOutFile, "<class name=\"%s\"\n", tmp);
   1315     free(tmp);
   1316     if (superclassDescriptor != nullptr) {
   1317       tmp = descriptorToDot(superclassDescriptor);
   1318       fprintf(gOutFile, " extends=\"%s\"\n", tmp);
   1319       free(tmp);
   1320     }
   1321     fprintf(gOutFile, " interface=%s\n",
   1322             quotedBool((pClassDef.access_flags_ & kAccInterface) != 0));
   1323     fprintf(gOutFile, " abstract=%s\n", quotedBool((pClassDef.access_flags_ & kAccAbstract) != 0));
   1324     fprintf(gOutFile, " static=%s\n", quotedBool((pClassDef.access_flags_ & kAccStatic) != 0));
   1325     fprintf(gOutFile, " final=%s\n", quotedBool((pClassDef.access_flags_ & kAccFinal) != 0));
   1326     // The "deprecated=" not knowable w/o parsing annotations.
   1327     fprintf(gOutFile, " visibility=%s\n", quotedVisibility(pClassDef.access_flags_));
   1328     fprintf(gOutFile, ">\n");
   1329   }
   1330 
   1331   // Interfaces.
   1332   const DexFile::TypeList* pInterfaces = pDexFile->GetInterfacesList(pClassDef);
   1333   if (pInterfaces != nullptr) {
   1334     for (u4 i = 0; i < pInterfaces->Size(); i++) {
   1335       dumpInterface(pDexFile, pInterfaces->GetTypeItem(i), i);
   1336     }  // for
   1337   }
   1338 
   1339   // Fields and methods.
   1340   const u1* pEncodedData = pDexFile->GetClassData(pClassDef);
   1341   if (pEncodedData == nullptr) {
   1342     if (gOptions.outputFormat == OUTPUT_PLAIN) {
   1343       fprintf(gOutFile, "  Static fields     -\n");
   1344       fprintf(gOutFile, "  Instance fields   -\n");
   1345       fprintf(gOutFile, "  Direct methods    -\n");
   1346       fprintf(gOutFile, "  Virtual methods   -\n");
   1347     }
   1348   } else {
   1349     ClassDataItemIterator pClassData(*pDexFile, pEncodedData);
   1350     if (gOptions.outputFormat == OUTPUT_PLAIN) {
   1351       fprintf(gOutFile, "  Static fields     -\n");
   1352     }
   1353     EncodedStaticFieldValueIterator staticFieldValues(*pDexFile, pClassDef);
   1354     for (int i = 0; pClassData.HasNextStaticField(); i++, pClassData.Next()) {
   1355       EncodedStaticFieldValueIterator::ValueType valueType =
   1356           EncodedStaticFieldValueIterator::kByte;
   1357       const jvalue* pValue = nullptr;
   1358       if (staticFieldValues.HasNext()) {
   1359         valueType = staticFieldValues.GetValueType();
   1360         pValue = &staticFieldValues.GetJavaValue();
   1361       }
   1362       dumpSField(pDexFile, pClassData.GetMemberIndex(),
   1363                            pClassData.GetRawMemberAccessFlags(), i,
   1364                  valueType, pValue);
   1365       if (staticFieldValues.HasNext()) {
   1366         staticFieldValues.Next();
   1367       }
   1368     }  // for
   1369     DCHECK(!staticFieldValues.HasNext());
   1370     if (gOptions.outputFormat == OUTPUT_PLAIN) {
   1371       fprintf(gOutFile, "  Instance fields   -\n");
   1372     }
   1373     for (int i = 0; pClassData.HasNextInstanceField(); i++, pClassData.Next()) {
   1374       dumpIField(pDexFile, pClassData.GetMemberIndex(),
   1375                           pClassData.GetRawMemberAccessFlags(), i);
   1376     }  // for
   1377     if (gOptions.outputFormat == OUTPUT_PLAIN) {
   1378       fprintf(gOutFile, "  Direct methods    -\n");
   1379     }
   1380     for (int i = 0; pClassData.HasNextDirectMethod(); i++, pClassData.Next()) {
   1381       dumpMethod(pDexFile, pClassData.GetMemberIndex(),
   1382                            pClassData.GetRawMemberAccessFlags(),
   1383                            pClassData.GetMethodCodeItem(),
   1384                            pClassData.GetMethodCodeItemOffset(), i);
   1385     }  // for
   1386     if (gOptions.outputFormat == OUTPUT_PLAIN) {
   1387       fprintf(gOutFile, "  Virtual methods   -\n");
   1388     }
   1389     for (int i = 0; pClassData.HasNextVirtualMethod(); i++, pClassData.Next()) {
   1390       dumpMethod(pDexFile, pClassData.GetMemberIndex(),
   1391                            pClassData.GetRawMemberAccessFlags(),
   1392                            pClassData.GetMethodCodeItem(),
   1393                            pClassData.GetMethodCodeItemOffset(), i);
   1394     }  // for
   1395   }
   1396 
   1397   // End of class.
   1398   if (gOptions.outputFormat == OUTPUT_PLAIN) {
   1399     const char* fileName;
   1400     if (pClassDef.source_file_idx_ != DexFile::kDexNoIndex) {
   1401       fileName = pDexFile->StringDataByIdx(pClassDef.source_file_idx_);
   1402     } else {
   1403       fileName = "unknown";
   1404     }
   1405     fprintf(gOutFile, "  source_file_idx   : %d (%s)\n\n",
   1406             pClassDef.source_file_idx_, fileName);
   1407   } else if (gOptions.outputFormat == OUTPUT_XML) {
   1408     fprintf(gOutFile, "</class>\n");
   1409   }
   1410 
   1411   free(accessStr);
   1412 }
   1413 
   1414 /*
   1415  * Dumps the requested sections of the file.
   1416  */
   1417 static void processDexFile(const char* fileName, const DexFile* pDexFile) {
   1418   if (gOptions.verbose) {
   1419     fprintf(gOutFile, "Opened '%s', DEX version '%.3s'\n",
   1420             fileName, pDexFile->GetHeader().magic_ + 4);
   1421   }
   1422 
   1423   // Headers.
   1424   if (gOptions.showFileHeaders) {
   1425     dumpFileHeader(pDexFile);
   1426   }
   1427 
   1428   // Open XML context.
   1429   if (gOptions.outputFormat == OUTPUT_XML) {
   1430     fprintf(gOutFile, "<api>\n");
   1431   }
   1432 
   1433   // Iterate over all classes.
   1434   char* package = nullptr;
   1435   const u4 classDefsSize = pDexFile->GetHeader().class_defs_size_;
   1436   for (u4 i = 0; i < classDefsSize; i++) {
   1437     if (gOptions.showSectionHeaders) {
   1438       dumpClassDef(pDexFile, i);
   1439     }
   1440     dumpClass(pDexFile, i, &package);
   1441   }  // for
   1442 
   1443   // Free the last package allocated.
   1444   if (package != nullptr) {
   1445     fprintf(gOutFile, "</package>\n");
   1446     free(package);
   1447   }
   1448 
   1449   // Close XML context.
   1450   if (gOptions.outputFormat == OUTPUT_XML) {
   1451     fprintf(gOutFile, "</api>\n");
   1452   }
   1453 }
   1454 
   1455 /*
   1456  * Processes a single file (either direct .dex or indirect .zip/.jar/.apk).
   1457  */
   1458 int processFile(const char* fileName) {
   1459   if (gOptions.verbose) {
   1460     fprintf(gOutFile, "Processing '%s'...\n", fileName);
   1461   }
   1462 
   1463   // If the file is not a .dex file, the function tries .zip/.jar/.apk files,
   1464   // all of which are Zip archives with "classes.dex" inside. The compressed
   1465   // data needs to be extracted to a temp file, the location of which varies.
   1466   //
   1467   // TODO(ajcbik): fix following issues
   1468   //
   1469   // (1) gOptions.tempFileName is not accounted for
   1470   // (2) gOptions.ignoreBadChecksum is not accounted for
   1471   //
   1472   std::string error_msg;
   1473   std::vector<std::unique_ptr<const DexFile>> dex_files;
   1474   if (!DexFile::Open(fileName, fileName, &error_msg, &dex_files)) {
   1475     // Display returned error message to user. Note that this error behavior
   1476     // differs from the error messages shown by the original Dalvik dexdump.
   1477     fputs(error_msg.c_str(), stderr);
   1478     fputc('\n', stderr);
   1479     return -1;
   1480   }
   1481 
   1482   // Success. Either report checksum verification or process
   1483   // all dex files found in given file.
   1484   if (gOptions.checksumOnly) {
   1485     fprintf(gOutFile, "Checksum verified\n");
   1486   } else {
   1487     for (size_t i = 0; i < dex_files.size(); i++) {
   1488       processDexFile(fileName, dex_files[i].get());
   1489     }
   1490   }
   1491   return 0;
   1492 }
   1493 
   1494 }  // namespace art
   1495