Home | History | Annotate | Download | only in dexdump
      1 /*
      2  * Copyright (C) 2008 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 
     17 /*
     18  * The "dexdump" tool is intended to mimic "objdump".  When possible, use
     19  * similar command-line arguments.
     20  *
     21  * TODO: rework the "plain" output format to be more regexp-friendly
     22  *
     23  * Differences between XML output and the "current.xml" file:
     24  * - classes in same package are not all grouped together; generally speaking
     25  *   nothing is sorted
     26  * - no "deprecated" on fields and methods
     27  * - no "value" on fields
     28  * - no parameter names
     29  * - no generic signatures on parameters, e.g. type="java.lang.Class<?>"
     30  * - class shows declared fields and methods; does not show inherited fields
     31  */
     32 
     33 #include "libdex/DexFile.h"
     34 
     35 #include "libdex/CmdUtils.h"
     36 #include "libdex/DexCatch.h"
     37 #include "libdex/DexClass.h"
     38 #include "libdex/DexDebugInfo.h"
     39 #include "libdex/DexOpcodes.h"
     40 #include "libdex/DexProto.h"
     41 #include "libdex/InstrUtils.h"
     42 #include "libdex/SysUtil.h"
     43 
     44 #include <stdlib.h>
     45 #include <stdio.h>
     46 #include <fcntl.h>
     47 #include <string.h>
     48 #include <unistd.h>
     49 #include <getopt.h>
     50 #include <errno.h>
     51 #include <assert.h>
     52 #include <inttypes.h>
     53 
     54 static const char* gProgName = "dexdump";
     55 
     56 enum OutputFormat {
     57     OUTPUT_PLAIN = 0,               /* default */
     58     OUTPUT_XML,                     /* fancy */
     59 };
     60 
     61 /* command-line options */
     62 struct Options {
     63     bool checksumOnly;
     64     bool disassemble;
     65     bool showFileHeaders;
     66     bool showSectionHeaders;
     67     bool ignoreBadChecksum;
     68     bool dumpRegisterMaps;
     69     OutputFormat outputFormat;
     70     const char* tempFileName;
     71     bool exportsOnly;
     72     bool verbose;
     73 };
     74 
     75 struct Options gOptions;
     76 
     77 /* basic info about a field or method */
     78 struct FieldMethodInfo {
     79     const char* classDescriptor;
     80     const char* name;
     81     const char* signature;
     82 };
     83 
     84 /*
     85  * Get 2 little-endian bytes.
     86  */
     87 static inline u2 get2LE(unsigned char const* pSrc)
     88 {
     89     return pSrc[0] | (pSrc[1] << 8);
     90 }
     91 
     92 /*
     93  * Get 4 little-endian bytes.
     94  */
     95 static inline u4 get4LE(unsigned char const* pSrc)
     96 {
     97     return pSrc[0] | (pSrc[1] << 8) | (pSrc[2] << 16) | (pSrc[3] << 24);
     98 }
     99 
    100 /*
    101  * Converts a single-character primitive type into its human-readable
    102  * equivalent.
    103  */
    104 static const char* primitiveTypeLabel(char typeChar)
    105 {
    106     switch (typeChar) {
    107     case 'B':   return "byte";
    108     case 'C':   return "char";
    109     case 'D':   return "double";
    110     case 'F':   return "float";
    111     case 'I':   return "int";
    112     case 'J':   return "long";
    113     case 'S':   return "short";
    114     case 'V':   return "void";
    115     case 'Z':   return "boolean";
    116     default:
    117                 return "UNKNOWN";
    118     }
    119 }
    120 
    121 /*
    122  * Converts a type descriptor to human-readable "dotted" form.  For
    123  * example, "Ljava/lang/String;" becomes "java.lang.String", and
    124  * "[I" becomes "int[]".  Also converts '$' to '.', which means this
    125  * form can't be converted back to a descriptor.
    126  */
    127 static char* descriptorToDot(const char* str)
    128 {
    129     int targetLen = strlen(str);
    130     int offset = 0;
    131     int arrayDepth = 0;
    132     char* newStr;
    133 
    134     /* strip leading [s; will be added to end */
    135     while (targetLen > 1 && str[offset] == '[') {
    136         offset++;
    137         targetLen--;
    138     }
    139     arrayDepth = offset;
    140 
    141     if (targetLen == 1) {
    142         /* primitive type */
    143         str = primitiveTypeLabel(str[offset]);
    144         offset = 0;
    145         targetLen = strlen(str);
    146     } else {
    147         /* account for leading 'L' and trailing ';' */
    148         if (targetLen >= 2 && str[offset] == 'L' &&
    149             str[offset+targetLen-1] == ';')
    150         {
    151             targetLen -= 2;
    152             offset++;
    153         }
    154     }
    155 
    156     newStr = (char*)malloc(targetLen + arrayDepth * 2 +1);
    157 
    158     /* copy class name over */
    159     int i;
    160     for (i = 0; i < targetLen; i++) {
    161         char ch = str[offset + i];
    162         newStr[i] = (ch == '/' || ch == '$') ? '.' : ch;
    163     }
    164 
    165     /* add the appropriate number of brackets for arrays */
    166     while (arrayDepth-- > 0) {
    167         newStr[i++] = '[';
    168         newStr[i++] = ']';
    169     }
    170     newStr[i] = '\0';
    171     assert(i == targetLen + arrayDepth * 2);
    172 
    173     return newStr;
    174 }
    175 
    176 /*
    177  * Converts the class name portion of a type descriptor to human-readable
    178  * "dotted" form.
    179  *
    180  * Returns a newly-allocated string.
    181  */
    182 static char* descriptorClassToDot(const char* str)
    183 {
    184     const char* lastSlash;
    185     char* newStr;
    186     char* cp;
    187 
    188     /* reduce to just the class name, trimming trailing ';' */
    189     lastSlash = strrchr(str, '/');
    190     if (lastSlash == NULL)
    191         lastSlash = str + 1;        /* start past 'L' */
    192     else
    193         lastSlash++;                /* start past '/' */
    194 
    195     newStr = strdup(lastSlash);
    196     newStr[strlen(lastSlash)-1] = '\0';
    197     for (cp = newStr; *cp != '\0'; cp++) {
    198         if (*cp == '$')
    199             *cp = '.';
    200     }
    201 
    202     return newStr;
    203 }
    204 
    205 /*
    206  * Returns a quoted string representing the boolean value.
    207  */
    208 static const char* quotedBool(bool val)
    209 {
    210     if (val)
    211         return "\"true\"";
    212     else
    213         return "\"false\"";
    214 }
    215 
    216 static const char* quotedVisibility(u4 accessFlags)
    217 {
    218     if ((accessFlags & ACC_PUBLIC) != 0)
    219         return "\"public\"";
    220     else if ((accessFlags & ACC_PROTECTED) != 0)
    221         return "\"protected\"";
    222     else if ((accessFlags & ACC_PRIVATE) != 0)
    223         return "\"private\"";
    224     else
    225         return "\"package\"";
    226 }
    227 
    228 /*
    229  * Count the number of '1' bits in a word.
    230  */
    231 static int countOnes(u4 val)
    232 {
    233     int count = 0;
    234 
    235     val = val - ((val >> 1) & 0x55555555);
    236     val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
    237     count = (((val + (val >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
    238 
    239     return count;
    240 }
    241 
    242 /*
    243  * Flag for use with createAccessFlagStr().
    244  */
    245 enum AccessFor {
    246     kAccessForClass = 0, kAccessForMethod = 1, kAccessForField = 2,
    247     kAccessForMAX
    248 };
    249 
    250 /*
    251  * Create a new string with human-readable access flags.
    252  *
    253  * In the base language the access_flags fields are type u2; in Dalvik
    254  * they're u4.
    255  */
    256 static char* createAccessFlagStr(u4 flags, AccessFor forWhat)
    257 {
    258 #define NUM_FLAGS   18
    259     static const char* kAccessStrings[kAccessForMAX][NUM_FLAGS] = {
    260         {
    261             /* class, inner class */
    262             "PUBLIC",           /* 0x0001 */
    263             "PRIVATE",          /* 0x0002 */
    264             "PROTECTED",        /* 0x0004 */
    265             "STATIC",           /* 0x0008 */
    266             "FINAL",            /* 0x0010 */
    267             "?",                /* 0x0020 */
    268             "?",                /* 0x0040 */
    269             "?",                /* 0x0080 */
    270             "?",                /* 0x0100 */
    271             "INTERFACE",        /* 0x0200 */
    272             "ABSTRACT",         /* 0x0400 */
    273             "?",                /* 0x0800 */
    274             "SYNTHETIC",        /* 0x1000 */
    275             "ANNOTATION",       /* 0x2000 */
    276             "ENUM",             /* 0x4000 */
    277             "?",                /* 0x8000 */
    278             "VERIFIED",         /* 0x10000 */
    279             "OPTIMIZED",        /* 0x20000 */
    280         },
    281         {
    282             /* method */
    283             "PUBLIC",           /* 0x0001 */
    284             "PRIVATE",          /* 0x0002 */
    285             "PROTECTED",        /* 0x0004 */
    286             "STATIC",           /* 0x0008 */
    287             "FINAL",            /* 0x0010 */
    288             "SYNCHRONIZED",     /* 0x0020 */
    289             "BRIDGE",           /* 0x0040 */
    290             "VARARGS",          /* 0x0080 */
    291             "NATIVE",           /* 0x0100 */
    292             "?",                /* 0x0200 */
    293             "ABSTRACT",         /* 0x0400 */
    294             "STRICT",           /* 0x0800 */
    295             "SYNTHETIC",        /* 0x1000 */
    296             "?",                /* 0x2000 */
    297             "?",                /* 0x4000 */
    298             "MIRANDA",          /* 0x8000 */
    299             "CONSTRUCTOR",      /* 0x10000 */
    300             "DECLARED_SYNCHRONIZED", /* 0x20000 */
    301         },
    302         {
    303             /* field */
    304             "PUBLIC",           /* 0x0001 */
    305             "PRIVATE",          /* 0x0002 */
    306             "PROTECTED",        /* 0x0004 */
    307             "STATIC",           /* 0x0008 */
    308             "FINAL",            /* 0x0010 */
    309             "?",                /* 0x0020 */
    310             "VOLATILE",         /* 0x0040 */
    311             "TRANSIENT",        /* 0x0080 */
    312             "?",                /* 0x0100 */
    313             "?",                /* 0x0200 */
    314             "?",                /* 0x0400 */
    315             "?",                /* 0x0800 */
    316             "SYNTHETIC",        /* 0x1000 */
    317             "?",                /* 0x2000 */
    318             "ENUM",             /* 0x4000 */
    319             "?",                /* 0x8000 */
    320             "?",                /* 0x10000 */
    321             "?",                /* 0x20000 */
    322         },
    323     };
    324     const int kLongest = 21;        /* strlen of longest string above */
    325     int i, count;
    326     char* str;
    327     char* cp;
    328 
    329     /*
    330      * Allocate enough storage to hold the expected number of strings,
    331      * plus a space between each.  We over-allocate, using the longest
    332      * string above as the base metric.
    333      */
    334     count = countOnes(flags);
    335     cp = str = (char*) malloc(count * (kLongest+1) +1);
    336 
    337     for (i = 0; i < NUM_FLAGS; i++) {
    338         if (flags & 0x01) {
    339             const char* accessStr = kAccessStrings[forWhat][i];
    340             int len = strlen(accessStr);
    341             if (cp != str)
    342                 *cp++ = ' ';
    343 
    344             memcpy(cp, accessStr, len);
    345             cp += len;
    346         }
    347         flags >>= 1;
    348     }
    349     *cp = '\0';
    350 
    351     return str;
    352 }
    353 
    354 
    355 /*
    356  * Copy character data from "data" to "out", converting non-ASCII values
    357  * to printf format chars or an ASCII filler ('.' or '?').
    358  *
    359  * The output buffer must be able to hold (2*len)+1 bytes.  The result is
    360  * NUL-terminated.
    361  */
    362 static void asciify(char* out, const unsigned char* data, size_t len)
    363 {
    364     while (len--) {
    365         if (*data < 0x20) {
    366             /* could do more here, but we don't need them yet */
    367             switch (*data) {
    368             case '\0':
    369                 *out++ = '\\';
    370                 *out++ = '0';
    371                 break;
    372             case '\n':
    373                 *out++ = '\\';
    374                 *out++ = 'n';
    375                 break;
    376             default:
    377                 *out++ = '.';
    378                 break;
    379             }
    380         } else if (*data >= 0x80) {
    381             *out++ = '?';
    382         } else {
    383             *out++ = *data;
    384         }
    385         data++;
    386     }
    387     *out = '\0';
    388 }
    389 
    390 /*
    391  * Dump the file header.
    392  */
    393 void dumpFileHeader(const DexFile* pDexFile)
    394 {
    395     const DexOptHeader* pOptHeader = pDexFile->pOptHeader;
    396     const DexHeader* pHeader = pDexFile->pHeader;
    397     char sanitized[sizeof(pHeader->magic)*2 +1];
    398 
    399     assert(sizeof(pHeader->magic) == sizeof(pOptHeader->magic));
    400 
    401     if (pOptHeader != NULL) {
    402         printf("Optimized DEX file header:\n");
    403 
    404         asciify(sanitized, pOptHeader->magic, sizeof(pOptHeader->magic));
    405         printf("magic               : '%s'\n", sanitized);
    406         printf("dex_offset          : %d (0x%06x)\n",
    407             pOptHeader->dexOffset, pOptHeader->dexOffset);
    408         printf("dex_length          : %d\n", pOptHeader->dexLength);
    409         printf("deps_offset         : %d (0x%06x)\n",
    410             pOptHeader->depsOffset, pOptHeader->depsOffset);
    411         printf("deps_length         : %d\n", pOptHeader->depsLength);
    412         printf("opt_offset          : %d (0x%06x)\n",
    413             pOptHeader->optOffset, pOptHeader->optOffset);
    414         printf("opt_length          : %d\n", pOptHeader->optLength);
    415         printf("flags               : %08x\n", pOptHeader->flags);
    416         printf("checksum            : %08x\n", pOptHeader->checksum);
    417         printf("\n");
    418     }
    419 
    420     printf("DEX file header:\n");
    421     asciify(sanitized, pHeader->magic, sizeof(pHeader->magic));
    422     printf("magic               : '%s'\n", sanitized);
    423     printf("checksum            : %08x\n", pHeader->checksum);
    424     printf("signature           : %02x%02x...%02x%02x\n",
    425         pHeader->signature[0], pHeader->signature[1],
    426         pHeader->signature[kSHA1DigestLen-2],
    427         pHeader->signature[kSHA1DigestLen-1]);
    428     printf("file_size           : %d\n", pHeader->fileSize);
    429     printf("header_size         : %d\n", pHeader->headerSize);
    430     printf("link_size           : %d\n", pHeader->linkSize);
    431     printf("link_off            : %d (0x%06x)\n",
    432         pHeader->linkOff, pHeader->linkOff);
    433     printf("string_ids_size     : %d\n", pHeader->stringIdsSize);
    434     printf("string_ids_off      : %d (0x%06x)\n",
    435         pHeader->stringIdsOff, pHeader->stringIdsOff);
    436     printf("type_ids_size       : %d\n", pHeader->typeIdsSize);
    437     printf("type_ids_off        : %d (0x%06x)\n",
    438         pHeader->typeIdsOff, pHeader->typeIdsOff);
    439     printf("proto_ids_size       : %d\n", pHeader->protoIdsSize);
    440     printf("proto_ids_off        : %d (0x%06x)\n",
    441         pHeader->protoIdsOff, pHeader->protoIdsOff);
    442     printf("field_ids_size      : %d\n", pHeader->fieldIdsSize);
    443     printf("field_ids_off       : %d (0x%06x)\n",
    444         pHeader->fieldIdsOff, pHeader->fieldIdsOff);
    445     printf("method_ids_size     : %d\n", pHeader->methodIdsSize);
    446     printf("method_ids_off      : %d (0x%06x)\n",
    447         pHeader->methodIdsOff, pHeader->methodIdsOff);
    448     printf("class_defs_size     : %d\n", pHeader->classDefsSize);
    449     printf("class_defs_off      : %d (0x%06x)\n",
    450         pHeader->classDefsOff, pHeader->classDefsOff);
    451     printf("data_size           : %d\n", pHeader->dataSize);
    452     printf("data_off            : %d (0x%06x)\n",
    453         pHeader->dataOff, pHeader->dataOff);
    454     printf("\n");
    455 }
    456 
    457 /*
    458  * Dump the "table of contents" for the opt area.
    459  */
    460 void dumpOptDirectory(const DexFile* pDexFile)
    461 {
    462     const DexOptHeader* pOptHeader = pDexFile->pOptHeader;
    463     if (pOptHeader == NULL)
    464         return;
    465 
    466     printf("OPT section contents:\n");
    467 
    468     const u4* pOpt = (const u4*) ((u1*) pOptHeader + pOptHeader->optOffset);
    469 
    470     if (*pOpt == 0) {
    471         printf("(1.0 format, only class lookup table is present)\n\n");
    472         return;
    473     }
    474 
    475     /*
    476      * The "opt" section is in "chunk" format: a 32-bit identifier, a 32-bit
    477      * length, then the data.  Chunks start on 64-bit boundaries.
    478      */
    479     while (*pOpt != kDexChunkEnd) {
    480         const char* verboseStr;
    481 
    482         u4 size = *(pOpt+1);
    483 
    484         switch (*pOpt) {
    485         case kDexChunkClassLookup:
    486             verboseStr = "class lookup hash table";
    487             break;
    488         case kDexChunkRegisterMaps:
    489             verboseStr = "register maps";
    490             break;
    491         default:
    492             verboseStr = "(unknown chunk type)";
    493             break;
    494         }
    495 
    496         printf("Chunk %08x (%c%c%c%c) - %s (%d bytes)\n", *pOpt,
    497             *pOpt >> 24, (char)(*pOpt >> 16), (char)(*pOpt >> 8), (char)*pOpt,
    498             verboseStr, size);
    499 
    500         size = (size + 8 + 7) & ~7;
    501         pOpt += size / sizeof(u4);
    502     }
    503     printf("\n");
    504 }
    505 
    506 /*
    507  * Dump a class_def_item.
    508  */
    509 void dumpClassDef(DexFile* pDexFile, int idx)
    510 {
    511     const DexClassDef* pClassDef;
    512     const u1* pEncodedData;
    513     DexClassData* pClassData;
    514 
    515     pClassDef = dexGetClassDef(pDexFile, idx);
    516     pEncodedData = dexGetClassData(pDexFile, pClassDef);
    517     pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL);
    518 
    519     if (pClassData == NULL) {
    520         fprintf(stderr, "Trouble reading class data\n");
    521         return;
    522     }
    523 
    524     printf("Class #%d header:\n", idx);
    525     printf("class_idx           : %d\n", pClassDef->classIdx);
    526     printf("access_flags        : %d (0x%04x)\n",
    527         pClassDef->accessFlags, pClassDef->accessFlags);
    528     printf("superclass_idx      : %d\n", pClassDef->superclassIdx);
    529     printf("interfaces_off      : %d (0x%06x)\n",
    530         pClassDef->interfacesOff, pClassDef->interfacesOff);
    531     printf("source_file_idx     : %d\n", pClassDef->sourceFileIdx);
    532     printf("annotations_off     : %d (0x%06x)\n",
    533         pClassDef->annotationsOff, pClassDef->annotationsOff);
    534     printf("class_data_off      : %d (0x%06x)\n",
    535         pClassDef->classDataOff, pClassDef->classDataOff);
    536     printf("static_fields_size  : %d\n", pClassData->header.staticFieldsSize);
    537     printf("instance_fields_size: %d\n",
    538             pClassData->header.instanceFieldsSize);
    539     printf("direct_methods_size : %d\n", pClassData->header.directMethodsSize);
    540     printf("virtual_methods_size: %d\n",
    541             pClassData->header.virtualMethodsSize);
    542     printf("\n");
    543 
    544     free(pClassData);
    545 }
    546 
    547 /*
    548  * Dump an interface that a class declares to implement.
    549  */
    550 void dumpInterface(const DexFile* pDexFile, const DexTypeItem* pTypeItem,
    551     int i)
    552 {
    553     const char* interfaceName =
    554         dexStringByTypeIdx(pDexFile, pTypeItem->typeIdx);
    555 
    556     if (gOptions.outputFormat == OUTPUT_PLAIN) {
    557         printf("    #%d              : '%s'\n", i, interfaceName);
    558     } else {
    559         char* dotted = descriptorToDot(interfaceName);
    560         printf("<implements name=\"%s\">\n</implements>\n", dotted);
    561         free(dotted);
    562     }
    563 }
    564 
    565 /*
    566  * Dump the catches table associated with the code.
    567  */
    568 void dumpCatches(DexFile* pDexFile, const DexCode* pCode)
    569 {
    570     u4 triesSize = pCode->triesSize;
    571 
    572     if (triesSize == 0) {
    573         printf("      catches       : (none)\n");
    574         return;
    575     }
    576 
    577     printf("      catches       : %d\n", triesSize);
    578 
    579     const DexTry* pTries = dexGetTries(pCode);
    580     u4 i;
    581 
    582     for (i = 0; i < triesSize; i++) {
    583         const DexTry* pTry = &pTries[i];
    584         u4 start = pTry->startAddr;
    585         u4 end = start + pTry->insnCount;
    586         DexCatchIterator iterator;
    587 
    588         printf("        0x%04x - 0x%04x\n", start, end);
    589 
    590         dexCatchIteratorInit(&iterator, pCode, pTry->handlerOff);
    591 
    592         for (;;) {
    593             DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
    594             const char* descriptor;
    595 
    596             if (handler == NULL) {
    597                 break;
    598             }
    599 
    600             descriptor = (handler->typeIdx == kDexNoIndex) ? "<any>" :
    601                 dexStringByTypeIdx(pDexFile, handler->typeIdx);
    602 
    603             printf("          %s -> 0x%04x\n", descriptor,
    604                     handler->address);
    605         }
    606     }
    607 }
    608 
    609 static int dumpPositionsCb(void * /* cnxt */, u4 address, u4 lineNum)
    610 {
    611     printf("        0x%04x line=%d\n", address, lineNum);
    612     return 0;
    613 }
    614 
    615 /*
    616  * Dump the positions list.
    617  */
    618 void dumpPositions(DexFile* pDexFile, const DexCode* pCode,
    619         const DexMethod *pDexMethod)
    620 {
    621     printf("      positions     : \n");
    622     const DexMethodId *pMethodId
    623             = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
    624     const char *classDescriptor
    625             = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
    626 
    627     dexDecodeDebugInfo(pDexFile, pCode, classDescriptor, pMethodId->protoIdx,
    628             pDexMethod->accessFlags, dumpPositionsCb, NULL, NULL);
    629 }
    630 
    631 static void dumpLocalsCb(void * /* cnxt */, u2 reg, u4 startAddress,
    632         u4 endAddress, const char *name, const char *descriptor,
    633         const char *signature)
    634 {
    635     printf("        0x%04x - 0x%04x reg=%d %s %s %s\n",
    636             startAddress, endAddress, reg, name, descriptor,
    637             signature);
    638 }
    639 
    640 /*
    641  * Dump the locals list.
    642  */
    643 void dumpLocals(DexFile* pDexFile, const DexCode* pCode,
    644         const DexMethod *pDexMethod)
    645 {
    646     printf("      locals        : \n");
    647 
    648     const DexMethodId *pMethodId
    649             = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
    650     const char *classDescriptor
    651             = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
    652 
    653     dexDecodeDebugInfo(pDexFile, pCode, classDescriptor, pMethodId->protoIdx,
    654             pDexMethod->accessFlags, NULL, dumpLocalsCb, NULL);
    655 }
    656 
    657 /*
    658  * Get information about a method.
    659  */
    660 bool getMethodInfo(DexFile* pDexFile, u4 methodIdx, FieldMethodInfo* pMethInfo)
    661 {
    662     const DexMethodId* pMethodId;
    663 
    664     if (methodIdx >= pDexFile->pHeader->methodIdsSize)
    665         return false;
    666 
    667     pMethodId = dexGetMethodId(pDexFile, methodIdx);
    668     pMethInfo->name = dexStringById(pDexFile, pMethodId->nameIdx);
    669     pMethInfo->signature = dexCopyDescriptorFromMethodId(pDexFile, pMethodId);
    670 
    671     pMethInfo->classDescriptor =
    672             dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
    673     return true;
    674 }
    675 
    676 /*
    677  * Get information about a field.
    678  */
    679 bool getFieldInfo(DexFile* pDexFile, u4 fieldIdx, FieldMethodInfo* pFieldInfo)
    680 {
    681     const DexFieldId* pFieldId;
    682 
    683     if (fieldIdx >= pDexFile->pHeader->fieldIdsSize)
    684         return false;
    685 
    686     pFieldId = dexGetFieldId(pDexFile, fieldIdx);
    687     pFieldInfo->name = dexStringById(pDexFile, pFieldId->nameIdx);
    688     pFieldInfo->signature = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx);
    689     pFieldInfo->classDescriptor =
    690         dexStringByTypeIdx(pDexFile, pFieldId->classIdx);
    691     return true;
    692 }
    693 
    694 
    695 /*
    696  * Look up a class' descriptor.
    697  */
    698 const char* getClassDescriptor(DexFile* pDexFile, u4 classIdx)
    699 {
    700     return dexStringByTypeIdx(pDexFile, classIdx);
    701 }
    702 
    703 /*
    704  * Helper for dumpInstruction(), which builds the string
    705  * representation for the index in the given instruction. This will
    706  * first try to use the given buffer, but if the result won't fit,
    707  * then this will allocate a new buffer to hold the result. A pointer
    708  * to the buffer which holds the full result is always returned, and
    709  * this can be compared with the one passed in, to see if the result
    710  * needs to be free()d.
    711  */
    712 static char* indexString(DexFile* pDexFile,
    713     const DecodedInstruction* pDecInsn, char* buf, size_t bufSize)
    714 {
    715     int outSize;
    716     u4 index;
    717     u4 width;
    718 
    719     /* TODO: Make the index *always* be in field B, to simplify this code. */
    720     switch (dexGetFormatFromOpcode(pDecInsn->opcode)) {
    721     case kFmt20bc:
    722     case kFmt21c:
    723     case kFmt35c:
    724     case kFmt35ms:
    725     case kFmt3rc:
    726     case kFmt3rms:
    727     case kFmt35mi:
    728     case kFmt3rmi:
    729         index = pDecInsn->vB;
    730         width = 4;
    731         break;
    732     case kFmt31c:
    733         index = pDecInsn->vB;
    734         width = 8;
    735         break;
    736     case kFmt22c:
    737     case kFmt22cs:
    738         index = pDecInsn->vC;
    739         width = 4;
    740         break;
    741     default:
    742         index = 0;
    743         width = 4;
    744         break;
    745     }
    746 
    747     switch (pDecInsn->indexType) {
    748     case kIndexUnknown:
    749         /*
    750          * This function shouldn't ever get called for this type, but do
    751          * something sensible here, just to help with debugging.
    752          */
    753         outSize = snprintf(buf, bufSize, "<unknown-index>");
    754         break;
    755     case kIndexNone:
    756         /*
    757          * This function shouldn't ever get called for this type, but do
    758          * something sensible here, just to help with debugging.
    759          */
    760         outSize = snprintf(buf, bufSize, "<no-index>");
    761         break;
    762     case kIndexVaries:
    763         /*
    764          * This one should never show up in a dexdump, so no need to try
    765          * to get fancy here.
    766          */
    767         outSize = snprintf(buf, bufSize, "<index-varies> // thing@%0*x",
    768                 width, index);
    769         break;
    770     case kIndexTypeRef:
    771         if (index < pDexFile->pHeader->typeIdsSize) {
    772             outSize = snprintf(buf, bufSize, "%s // type@%0*x",
    773                                getClassDescriptor(pDexFile, index), width, index);
    774         } else {
    775             outSize = snprintf(buf, bufSize, "<type?> // type@%0*x", width, index);
    776         }
    777         break;
    778     case kIndexStringRef:
    779         if (index < pDexFile->pHeader->stringIdsSize) {
    780             outSize = snprintf(buf, bufSize, "\"%s\" // string@%0*x",
    781                                dexStringById(pDexFile, index), width, index);
    782         } else {
    783             outSize = snprintf(buf, bufSize, "<string?> // string@%0*x",
    784                                width, index);
    785         }
    786         break;
    787     case kIndexMethodRef:
    788         {
    789             FieldMethodInfo methInfo;
    790             if (getMethodInfo(pDexFile, index, &methInfo)) {
    791                 outSize = snprintf(buf, bufSize, "%s.%s:%s // method@%0*x",
    792                         methInfo.classDescriptor, methInfo.name,
    793                         methInfo.signature, width, index);
    794                 free((void *) methInfo.signature);
    795             } else {
    796                 outSize = snprintf(buf, bufSize, "<method?> // method@%0*x",
    797                         width, index);
    798             }
    799         }
    800         break;
    801     case kIndexFieldRef:
    802         {
    803             FieldMethodInfo fieldInfo;
    804             if (getFieldInfo(pDexFile, index, &fieldInfo)) {
    805                 outSize = snprintf(buf, bufSize, "%s.%s:%s // field@%0*x",
    806                         fieldInfo.classDescriptor, fieldInfo.name,
    807                         fieldInfo.signature, width, index);
    808             } else {
    809                 outSize = snprintf(buf, bufSize, "<field?> // field@%0*x",
    810                         width, index);
    811             }
    812         }
    813         break;
    814     case kIndexInlineMethod:
    815         outSize = snprintf(buf, bufSize, "[%0*x] // inline #%0*x",
    816                 width, index, width, index);
    817         break;
    818     case kIndexVtableOffset:
    819         outSize = snprintf(buf, bufSize, "[%0*x] // vtable #%0*x",
    820                 width, index, width, index);
    821         break;
    822     case kIndexFieldOffset:
    823         outSize = snprintf(buf, bufSize, "[obj+%0*x]", width, index);
    824         break;
    825     default:
    826         outSize = snprintf(buf, bufSize, "<?>");
    827         break;
    828     }
    829 
    830     if (outSize >= (int) bufSize) {
    831         /*
    832          * The buffer wasn't big enough; allocate and retry. Note:
    833          * snprintf() doesn't count the '\0' as part of its returned
    834          * size, so we add explicit space for it here.
    835          */
    836         outSize++;
    837         buf = (char*)malloc(outSize);
    838         if (buf == NULL) {
    839             return NULL;
    840         }
    841         return indexString(pDexFile, pDecInsn, buf, outSize);
    842     } else {
    843         return buf;
    844     }
    845 }
    846 
    847 /*
    848  * Dump a single instruction.
    849  */
    850 void dumpInstruction(DexFile* pDexFile, const DexCode* pCode, int insnIdx,
    851     int insnWidth, const DecodedInstruction* pDecInsn)
    852 {
    853     char indexBufChars[200];
    854     char *indexBuf = indexBufChars;
    855     const u2* insns = pCode->insns;
    856     int i;
    857 
    858     // Address of instruction (expressed as byte offset).
    859     printf("%06zx:", ((u1*)insns - pDexFile->baseAddr) + insnIdx*2);
    860 
    861     for (i = 0; i < 8; i++) {
    862         if (i < insnWidth) {
    863             if (i == 7) {
    864                 printf(" ... ");
    865             } else {
    866                 /* print 16-bit value in little-endian order */
    867                 const u1* bytePtr = (const u1*) &insns[insnIdx+i];
    868                 printf(" %02x%02x", bytePtr[0], bytePtr[1]);
    869             }
    870         } else {
    871             fputs("     ", stdout);
    872         }
    873     }
    874 
    875     if (pDecInsn->opcode == OP_NOP) {
    876         u2 instr = get2LE((const u1*) &insns[insnIdx]);
    877         if (instr == kPackedSwitchSignature) {
    878             printf("|%04x: packed-switch-data (%d units)",
    879                 insnIdx, insnWidth);
    880         } else if (instr == kSparseSwitchSignature) {
    881             printf("|%04x: sparse-switch-data (%d units)",
    882                 insnIdx, insnWidth);
    883         } else if (instr == kArrayDataSignature) {
    884             printf("|%04x: array-data (%d units)",
    885                 insnIdx, insnWidth);
    886         } else {
    887             printf("|%04x: nop // spacer", insnIdx);
    888         }
    889     } else {
    890         printf("|%04x: %s", insnIdx, dexGetOpcodeName(pDecInsn->opcode));
    891     }
    892 
    893     if (pDecInsn->indexType != kIndexNone) {
    894         indexBuf = indexString(pDexFile, pDecInsn,
    895                 indexBufChars, sizeof(indexBufChars));
    896     }
    897 
    898     switch (dexGetFormatFromOpcode(pDecInsn->opcode)) {
    899     case kFmt10x:        // op
    900         break;
    901     case kFmt12x:        // op vA, vB
    902         printf(" v%d, v%d", pDecInsn->vA, pDecInsn->vB);
    903         break;
    904     case kFmt11n:        // op vA, #+B
    905         printf(" v%d, #int %d // #%x",
    906             pDecInsn->vA, (s4)pDecInsn->vB, (u1)pDecInsn->vB);
    907         break;
    908     case kFmt11x:        // op vAA
    909         printf(" v%d", pDecInsn->vA);
    910         break;
    911     case kFmt10t:        // op +AA
    912     case kFmt20t:        // op +AAAA
    913         {
    914             s4 targ = (s4) pDecInsn->vA;
    915             printf(" %04x // %c%04x",
    916                 insnIdx + targ,
    917                 (targ < 0) ? '-' : '+',
    918                 (targ < 0) ? -targ : targ);
    919         }
    920         break;
    921     case kFmt22x:        // op vAA, vBBBB
    922         printf(" v%d, v%d", pDecInsn->vA, pDecInsn->vB);
    923         break;
    924     case kFmt21t:        // op vAA, +BBBB
    925         {
    926             s4 targ = (s4) pDecInsn->vB;
    927             printf(" v%d, %04x // %c%04x", pDecInsn->vA,
    928                 insnIdx + targ,
    929                 (targ < 0) ? '-' : '+',
    930                 (targ < 0) ? -targ : targ);
    931         }
    932         break;
    933     case kFmt21s:        // op vAA, #+BBBB
    934         printf(" v%d, #int %d // #%x",
    935             pDecInsn->vA, (s4)pDecInsn->vB, (u2)pDecInsn->vB);
    936         break;
    937     case kFmt21h:        // op vAA, #+BBBB0000[00000000]
    938         // The printed format varies a bit based on the actual opcode.
    939         if (pDecInsn->opcode == OP_CONST_HIGH16) {
    940             s4 value = pDecInsn->vB << 16;
    941             printf(" v%d, #int %d // #%x",
    942                 pDecInsn->vA, value, (u2)pDecInsn->vB);
    943         } else {
    944             s8 value = ((s8) pDecInsn->vB) << 48;
    945             printf(" v%d, #long %" PRId64 " // #%x",
    946                 pDecInsn->vA, value, (u2)pDecInsn->vB);
    947         }
    948         break;
    949     case kFmt21c:        // op vAA, thing@BBBB
    950     case kFmt31c:        // op vAA, thing@BBBBBBBB
    951         printf(" v%d, %s", pDecInsn->vA, indexBuf);
    952         break;
    953     case kFmt23x:        // op vAA, vBB, vCC
    954         printf(" v%d, v%d, v%d", pDecInsn->vA, pDecInsn->vB, pDecInsn->vC);
    955         break;
    956     case kFmt22b:        // op vAA, vBB, #+CC
    957         printf(" v%d, v%d, #int %d // #%02x",
    958             pDecInsn->vA, pDecInsn->vB, (s4)pDecInsn->vC, (u1)pDecInsn->vC);
    959         break;
    960     case kFmt22t:        // op vA, vB, +CCCC
    961         {
    962             s4 targ = (s4) pDecInsn->vC;
    963             printf(" v%d, v%d, %04x // %c%04x", pDecInsn->vA, pDecInsn->vB,
    964                 insnIdx + targ,
    965                 (targ < 0) ? '-' : '+',
    966                 (targ < 0) ? -targ : targ);
    967         }
    968         break;
    969     case kFmt22s:        // op vA, vB, #+CCCC
    970         printf(" v%d, v%d, #int %d // #%04x",
    971             pDecInsn->vA, pDecInsn->vB, (s4)pDecInsn->vC, (u2)pDecInsn->vC);
    972         break;
    973     case kFmt22c:        // op vA, vB, thing@CCCC
    974     case kFmt22cs:       // [opt] op vA, vB, field offset CCCC
    975         printf(" v%d, v%d, %s", pDecInsn->vA, pDecInsn->vB, indexBuf);
    976         break;
    977     case kFmt30t:
    978         printf(" #%08x", pDecInsn->vA);
    979         break;
    980     case kFmt31i:        // op vAA, #+BBBBBBBB
    981         {
    982             /* this is often, but not always, a float */
    983             union {
    984                 float f;
    985                 u4 i;
    986             } conv;
    987             conv.i = pDecInsn->vB;
    988             printf(" v%d, #float %f // #%08x",
    989                 pDecInsn->vA, conv.f, pDecInsn->vB);
    990         }
    991         break;
    992     case kFmt31t:       // op vAA, offset +BBBBBBBB
    993         printf(" v%d, %08x // +%08x",
    994             pDecInsn->vA, insnIdx + pDecInsn->vB, pDecInsn->vB);
    995         break;
    996     case kFmt32x:        // op vAAAA, vBBBB
    997         printf(" v%d, v%d", pDecInsn->vA, pDecInsn->vB);
    998         break;
    999     case kFmt35c:        // op {vC, vD, vE, vF, vG}, thing@BBBB
   1000     case kFmt35ms:       // [opt] invoke-virtual+super
   1001     case kFmt35mi:       // [opt] inline invoke
   1002         {
   1003             fputs(" {", stdout);
   1004             for (i = 0; i < (int) pDecInsn->vA; i++) {
   1005                 if (i == 0)
   1006                     printf("v%d", pDecInsn->arg[i]);
   1007                 else
   1008                     printf(", v%d", pDecInsn->arg[i]);
   1009             }
   1010             printf("}, %s", indexBuf);
   1011         }
   1012         break;
   1013     case kFmt3rc:        // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB
   1014     case kFmt3rms:       // [opt] invoke-virtual+super/range
   1015     case kFmt3rmi:       // [opt] execute-inline/range
   1016         {
   1017             /*
   1018              * This doesn't match the "dx" output when some of the args are
   1019              * 64-bit values -- dx only shows the first register.
   1020              */
   1021             fputs(" {", stdout);
   1022             for (i = 0; i < (int) pDecInsn->vA; i++) {
   1023                 if (i == 0)
   1024                     printf("v%d", pDecInsn->vC + i);
   1025                 else
   1026                     printf(", v%d", pDecInsn->vC + i);
   1027             }
   1028             printf("}, %s", indexBuf);
   1029         }
   1030         break;
   1031     case kFmt51l:        // op vAA, #+BBBBBBBBBBBBBBBB
   1032         {
   1033             /* this is often, but not always, a double */
   1034             union {
   1035                 double d;
   1036                 u8 j;
   1037             } conv;
   1038             conv.j = pDecInsn->vB_wide;
   1039             printf(" v%d, #double %f // #%016" PRIx64,
   1040                 pDecInsn->vA, conv.d, pDecInsn->vB_wide);
   1041         }
   1042         break;
   1043     case kFmt00x:        // unknown op or breakpoint
   1044         break;
   1045     default:
   1046         printf(" ???");
   1047         break;
   1048     }
   1049 
   1050     putchar('\n');
   1051 
   1052     if (indexBuf != indexBufChars) {
   1053         free(indexBuf);
   1054     }
   1055 }
   1056 
   1057 /*
   1058  * Dump a bytecode disassembly.
   1059  */
   1060 void dumpBytecodes(DexFile* pDexFile, const DexMethod* pDexMethod)
   1061 {
   1062     const DexCode* pCode = dexGetCode(pDexFile, pDexMethod);
   1063     const u2* insns;
   1064     int insnIdx;
   1065     FieldMethodInfo methInfo;
   1066     int startAddr;
   1067     char* className = NULL;
   1068 
   1069     assert(pCode->insnsSize > 0);
   1070     insns = pCode->insns;
   1071 
   1072     methInfo.classDescriptor =
   1073     methInfo.name =
   1074     methInfo.signature = NULL;
   1075 
   1076     getMethodInfo(pDexFile, pDexMethod->methodIdx, &methInfo);
   1077     startAddr = ((u1*)pCode - pDexFile->baseAddr);
   1078     className = descriptorToDot(methInfo.classDescriptor);
   1079 
   1080     printf("%06x:                                        |[%06x] %s.%s:%s\n",
   1081         startAddr, startAddr,
   1082         className, methInfo.name, methInfo.signature);
   1083     free((void *) methInfo.signature);
   1084 
   1085     insnIdx = 0;
   1086     while (insnIdx < (int) pCode->insnsSize) {
   1087         int insnWidth;
   1088         DecodedInstruction decInsn;
   1089         u2 instr;
   1090 
   1091         /*
   1092          * Note: This code parallels the function
   1093          * dexGetWidthFromInstruction() in InstrUtils.c, but this version
   1094          * can deal with data in either endianness.
   1095          *
   1096          * TODO: Figure out if this really matters, and possibly change
   1097          * this to just use dexGetWidthFromInstruction().
   1098          */
   1099         instr = get2LE((const u1*)insns);
   1100         if (instr == kPackedSwitchSignature) {
   1101             insnWidth = 4 + get2LE((const u1*)(insns+1)) * 2;
   1102         } else if (instr == kSparseSwitchSignature) {
   1103             insnWidth = 2 + get2LE((const u1*)(insns+1)) * 4;
   1104         } else if (instr == kArrayDataSignature) {
   1105             int width = get2LE((const u1*)(insns+1));
   1106             int size = get2LE((const u1*)(insns+2)) |
   1107                        (get2LE((const u1*)(insns+3))<<16);
   1108             // The plus 1 is to round up for odd size and width.
   1109             insnWidth = 4 + ((size * width) + 1) / 2;
   1110         } else {
   1111             Opcode opcode = dexOpcodeFromCodeUnit(instr);
   1112             insnWidth = dexGetWidthFromOpcode(opcode);
   1113             if (insnWidth == 0) {
   1114                 fprintf(stderr,
   1115                     "GLITCH: zero-width instruction at idx=0x%04x\n", insnIdx);
   1116                 break;
   1117             }
   1118         }
   1119 
   1120         dexDecodeInstruction(insns, &decInsn);
   1121         dumpInstruction(pDexFile, pCode, insnIdx, insnWidth, &decInsn);
   1122 
   1123         insns += insnWidth;
   1124         insnIdx += insnWidth;
   1125     }
   1126 
   1127     free(className);
   1128 }
   1129 
   1130 /*
   1131  * Dump a "code" struct.
   1132  */
   1133 void dumpCode(DexFile* pDexFile, const DexMethod* pDexMethod)
   1134 {
   1135     const DexCode* pCode = dexGetCode(pDexFile, pDexMethod);
   1136 
   1137     printf("      registers     : %d\n", pCode->registersSize);
   1138     printf("      ins           : %d\n", pCode->insSize);
   1139     printf("      outs          : %d\n", pCode->outsSize);
   1140     printf("      insns size    : %d 16-bit code units\n", pCode->insnsSize);
   1141 
   1142     if (gOptions.disassemble)
   1143         dumpBytecodes(pDexFile, pDexMethod);
   1144 
   1145     dumpCatches(pDexFile, pCode);
   1146     /* both of these are encoded in debug info */
   1147     dumpPositions(pDexFile, pCode, pDexMethod);
   1148     dumpLocals(pDexFile, pCode, pDexMethod);
   1149 }
   1150 
   1151 /*
   1152  * Dump a method.
   1153  */
   1154 void dumpMethod(DexFile* pDexFile, const DexMethod* pDexMethod, int i)
   1155 {
   1156     const DexMethodId* pMethodId;
   1157     const char* backDescriptor;
   1158     const char* name;
   1159     char* typeDescriptor = NULL;
   1160     char* accessStr = NULL;
   1161 
   1162     if (gOptions.exportsOnly &&
   1163         (pDexMethod->accessFlags & (ACC_PUBLIC | ACC_PROTECTED)) == 0)
   1164     {
   1165         return;
   1166     }
   1167 
   1168     pMethodId = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
   1169     name = dexStringById(pDexFile, pMethodId->nameIdx);
   1170     typeDescriptor = dexCopyDescriptorFromMethodId(pDexFile, pMethodId);
   1171 
   1172     backDescriptor = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
   1173 
   1174     accessStr = createAccessFlagStr(pDexMethod->accessFlags,
   1175                     kAccessForMethod);
   1176 
   1177     if (gOptions.outputFormat == OUTPUT_PLAIN) {
   1178         printf("    #%d              : (in %s)\n", i, backDescriptor);
   1179         printf("      name          : '%s'\n", name);
   1180         printf("      type          : '%s'\n", typeDescriptor);
   1181         printf("      access        : 0x%04x (%s)\n",
   1182             pDexMethod->accessFlags, accessStr);
   1183 
   1184         if (pDexMethod->codeOff == 0) {
   1185             printf("      code          : (none)\n");
   1186         } else {
   1187             printf("      code          -\n");
   1188             dumpCode(pDexFile, pDexMethod);
   1189         }
   1190 
   1191         if (gOptions.disassemble)
   1192             putchar('\n');
   1193     } else if (gOptions.outputFormat == OUTPUT_XML) {
   1194         bool constructor = (name[0] == '<');
   1195 
   1196         if (constructor) {
   1197             char* tmp;
   1198 
   1199             tmp = descriptorClassToDot(backDescriptor);
   1200             printf("<constructor name=\"%s\"\n", tmp);
   1201             free(tmp);
   1202 
   1203             tmp = descriptorToDot(backDescriptor);
   1204             printf(" type=\"%s\"\n", tmp);
   1205             free(tmp);
   1206         } else {
   1207             printf("<method name=\"%s\"\n", name);
   1208 
   1209             const char* returnType = strrchr(typeDescriptor, ')');
   1210             if (returnType == NULL) {
   1211                 fprintf(stderr, "bad method type descriptor '%s'\n",
   1212                     typeDescriptor);
   1213                 goto bail;
   1214             }
   1215 
   1216             char* tmp = descriptorToDot(returnType+1);
   1217             printf(" return=\"%s\"\n", tmp);
   1218             free(tmp);
   1219 
   1220             printf(" abstract=%s\n",
   1221                 quotedBool((pDexMethod->accessFlags & ACC_ABSTRACT) != 0));
   1222             printf(" native=%s\n",
   1223                 quotedBool((pDexMethod->accessFlags & ACC_NATIVE) != 0));
   1224 
   1225             bool isSync =
   1226                 (pDexMethod->accessFlags & ACC_SYNCHRONIZED) != 0 ||
   1227                 (pDexMethod->accessFlags & ACC_DECLARED_SYNCHRONIZED) != 0;
   1228             printf(" synchronized=%s\n", quotedBool(isSync));
   1229         }
   1230 
   1231         printf(" static=%s\n",
   1232             quotedBool((pDexMethod->accessFlags & ACC_STATIC) != 0));
   1233         printf(" final=%s\n",
   1234             quotedBool((pDexMethod->accessFlags & ACC_FINAL) != 0));
   1235         // "deprecated=" not knowable w/o parsing annotations
   1236         printf(" visibility=%s\n",
   1237             quotedVisibility(pDexMethod->accessFlags));
   1238 
   1239         printf(">\n");
   1240 
   1241         /*
   1242          * Parameters.
   1243          */
   1244         if (typeDescriptor[0] != '(') {
   1245             fprintf(stderr, "ERROR: bad descriptor '%s'\n", typeDescriptor);
   1246             goto bail;
   1247         }
   1248 
   1249         char tmpBuf[strlen(typeDescriptor)+1];      /* more than big enough */
   1250         int argNum = 0;
   1251 
   1252         const char* base = typeDescriptor+1;
   1253 
   1254         while (*base != ')') {
   1255             char* cp = tmpBuf;
   1256 
   1257             while (*base == '[')
   1258                 *cp++ = *base++;
   1259 
   1260             if (*base == 'L') {
   1261                 /* copy through ';' */
   1262                 do {
   1263                     *cp = *base++;
   1264                 } while (*cp++ != ';');
   1265             } else {
   1266                 /* primitive char, copy it */
   1267                 if (strchr("ZBCSIFJD", *base) == NULL) {
   1268                     fprintf(stderr, "ERROR: bad method signature '%s'\n", base);
   1269                     goto bail;
   1270                 }
   1271                 *cp++ = *base++;
   1272             }
   1273 
   1274             /* null terminate and display */
   1275             *cp++ = '\0';
   1276 
   1277             char* tmp = descriptorToDot(tmpBuf);
   1278             printf("<parameter name=\"arg%d\" type=\"%s\">\n</parameter>\n",
   1279                 argNum++, tmp);
   1280             free(tmp);
   1281         }
   1282 
   1283         if (constructor)
   1284             printf("</constructor>\n");
   1285         else
   1286             printf("</method>\n");
   1287     }
   1288 
   1289 bail:
   1290     free(typeDescriptor);
   1291     free(accessStr);
   1292 }
   1293 
   1294 /*
   1295  * Dump a static (class) field.
   1296  */
   1297 void dumpSField(const DexFile* pDexFile, const DexField* pSField, int i)
   1298 {
   1299     const DexFieldId* pFieldId;
   1300     const char* backDescriptor;
   1301     const char* name;
   1302     const char* typeDescriptor;
   1303     char* accessStr;
   1304 
   1305     if (gOptions.exportsOnly &&
   1306         (pSField->accessFlags & (ACC_PUBLIC | ACC_PROTECTED)) == 0)
   1307     {
   1308         return;
   1309     }
   1310 
   1311     pFieldId = dexGetFieldId(pDexFile, pSField->fieldIdx);
   1312     name = dexStringById(pDexFile, pFieldId->nameIdx);
   1313     typeDescriptor = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx);
   1314     backDescriptor = dexStringByTypeIdx(pDexFile, pFieldId->classIdx);
   1315 
   1316     accessStr = createAccessFlagStr(pSField->accessFlags, kAccessForField);
   1317 
   1318     if (gOptions.outputFormat == OUTPUT_PLAIN) {
   1319         printf("    #%d              : (in %s)\n", i, backDescriptor);
   1320         printf("      name          : '%s'\n", name);
   1321         printf("      type          : '%s'\n", typeDescriptor);
   1322         printf("      access        : 0x%04x (%s)\n",
   1323             pSField->accessFlags, accessStr);
   1324     } else if (gOptions.outputFormat == OUTPUT_XML) {
   1325         char* tmp;
   1326 
   1327         printf("<field name=\"%s\"\n", name);
   1328 
   1329         tmp = descriptorToDot(typeDescriptor);
   1330         printf(" type=\"%s\"\n", tmp);
   1331         free(tmp);
   1332 
   1333         printf(" transient=%s\n",
   1334             quotedBool((pSField->accessFlags & ACC_TRANSIENT) != 0));
   1335         printf(" volatile=%s\n",
   1336             quotedBool((pSField->accessFlags & ACC_VOLATILE) != 0));
   1337         // "value=" not knowable w/o parsing annotations
   1338         printf(" static=%s\n",
   1339             quotedBool((pSField->accessFlags & ACC_STATIC) != 0));
   1340         printf(" final=%s\n",
   1341             quotedBool((pSField->accessFlags & ACC_FINAL) != 0));
   1342         // "deprecated=" not knowable w/o parsing annotations
   1343         printf(" visibility=%s\n",
   1344             quotedVisibility(pSField->accessFlags));
   1345         printf(">\n</field>\n");
   1346     }
   1347 
   1348     free(accessStr);
   1349 }
   1350 
   1351 /*
   1352  * Dump an instance field.
   1353  */
   1354 void dumpIField(const DexFile* pDexFile, const DexField* pIField, int i)
   1355 {
   1356     dumpSField(pDexFile, pIField, i);
   1357 }
   1358 
   1359 /*
   1360  * Dump the class.
   1361  *
   1362  * Note "idx" is a DexClassDef index, not a DexTypeId index.
   1363  *
   1364  * If "*pLastPackage" is NULL or does not match the current class' package,
   1365  * the value will be replaced with a newly-allocated string.
   1366  */
   1367 void dumpClass(DexFile* pDexFile, int idx, char** pLastPackage)
   1368 {
   1369     const DexTypeList* pInterfaces;
   1370     const DexClassDef* pClassDef;
   1371     DexClassData* pClassData = NULL;
   1372     const u1* pEncodedData;
   1373     const char* fileName;
   1374     const char* classDescriptor;
   1375     const char* superclassDescriptor;
   1376     char* accessStr = NULL;
   1377     int i;
   1378 
   1379     pClassDef = dexGetClassDef(pDexFile, idx);
   1380 
   1381     if (gOptions.exportsOnly && (pClassDef->accessFlags & ACC_PUBLIC) == 0) {
   1382         //printf("<!-- omitting non-public class %s -->\n",
   1383         //    classDescriptor);
   1384         goto bail;
   1385     }
   1386 
   1387     pEncodedData = dexGetClassData(pDexFile, pClassDef);
   1388     pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL);
   1389 
   1390     if (pClassData == NULL) {
   1391         printf("Trouble reading class data (#%d)\n", idx);
   1392         goto bail;
   1393     }
   1394 
   1395     classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
   1396 
   1397     /*
   1398      * For the XML output, show the package name.  Ideally we'd gather
   1399      * up the classes, sort them, and dump them alphabetically so the
   1400      * package name wouldn't jump around, but that's not a great plan
   1401      * for something that needs to run on the device.
   1402      */
   1403     if (!(classDescriptor[0] == 'L' &&
   1404           classDescriptor[strlen(classDescriptor)-1] == ';'))
   1405     {
   1406         /* arrays and primitives should not be defined explicitly */
   1407         fprintf(stderr, "Malformed class name '%s'\n", classDescriptor);
   1408         /* keep going? */
   1409     } else if (gOptions.outputFormat == OUTPUT_XML) {
   1410         char* mangle;
   1411         char* lastSlash;
   1412         char* cp;
   1413 
   1414         mangle = strdup(classDescriptor + 1);
   1415         mangle[strlen(mangle)-1] = '\0';
   1416 
   1417         /* reduce to just the package name */
   1418         lastSlash = strrchr(mangle, '/');
   1419         if (lastSlash != NULL) {
   1420             *lastSlash = '\0';
   1421         } else {
   1422             *mangle = '\0';
   1423         }
   1424 
   1425         for (cp = mangle; *cp != '\0'; cp++) {
   1426             if (*cp == '/')
   1427                 *cp = '.';
   1428         }
   1429 
   1430         if (*pLastPackage == NULL || strcmp(mangle, *pLastPackage) != 0) {
   1431             /* start of a new package */
   1432             if (*pLastPackage != NULL)
   1433                 printf("</package>\n");
   1434             printf("<package name=\"%s\"\n>\n", mangle);
   1435             free(*pLastPackage);
   1436             *pLastPackage = mangle;
   1437         } else {
   1438             free(mangle);
   1439         }
   1440     }
   1441 
   1442     accessStr = createAccessFlagStr(pClassDef->accessFlags, kAccessForClass);
   1443 
   1444     if (pClassDef->superclassIdx == kDexNoIndex) {
   1445         superclassDescriptor = NULL;
   1446     } else {
   1447         superclassDescriptor =
   1448             dexStringByTypeIdx(pDexFile, pClassDef->superclassIdx);
   1449     }
   1450 
   1451     if (gOptions.outputFormat == OUTPUT_PLAIN) {
   1452         printf("Class #%d            -\n", idx);
   1453         printf("  Class descriptor  : '%s'\n", classDescriptor);
   1454         printf("  Access flags      : 0x%04x (%s)\n",
   1455             pClassDef->accessFlags, accessStr);
   1456 
   1457         if (superclassDescriptor != NULL)
   1458             printf("  Superclass        : '%s'\n", superclassDescriptor);
   1459 
   1460         printf("  Interfaces        -\n");
   1461     } else {
   1462         char* tmp;
   1463 
   1464         tmp = descriptorClassToDot(classDescriptor);
   1465         printf("<class name=\"%s\"\n", tmp);
   1466         free(tmp);
   1467 
   1468         if (superclassDescriptor != NULL) {
   1469             tmp = descriptorToDot(superclassDescriptor);
   1470             printf(" extends=\"%s\"\n", tmp);
   1471             free(tmp);
   1472         }
   1473         printf(" abstract=%s\n",
   1474             quotedBool((pClassDef->accessFlags & ACC_ABSTRACT) != 0));
   1475         printf(" static=%s\n",
   1476             quotedBool((pClassDef->accessFlags & ACC_STATIC) != 0));
   1477         printf(" final=%s\n",
   1478             quotedBool((pClassDef->accessFlags & ACC_FINAL) != 0));
   1479         // "deprecated=" not knowable w/o parsing annotations
   1480         printf(" visibility=%s\n",
   1481             quotedVisibility(pClassDef->accessFlags));
   1482         printf(">\n");
   1483     }
   1484     pInterfaces = dexGetInterfacesList(pDexFile, pClassDef);
   1485     if (pInterfaces != NULL) {
   1486         for (i = 0; i < (int) pInterfaces->size; i++)
   1487             dumpInterface(pDexFile, dexGetTypeItem(pInterfaces, i), i);
   1488     }
   1489 
   1490     if (gOptions.outputFormat == OUTPUT_PLAIN)
   1491         printf("  Static fields     -\n");
   1492     for (i = 0; i < (int) pClassData->header.staticFieldsSize; i++) {
   1493         dumpSField(pDexFile, &pClassData->staticFields[i], i);
   1494     }
   1495 
   1496     if (gOptions.outputFormat == OUTPUT_PLAIN)
   1497         printf("  Instance fields   -\n");
   1498     for (i = 0; i < (int) pClassData->header.instanceFieldsSize; i++) {
   1499         dumpIField(pDexFile, &pClassData->instanceFields[i], i);
   1500     }
   1501 
   1502     if (gOptions.outputFormat == OUTPUT_PLAIN)
   1503         printf("  Direct methods    -\n");
   1504     for (i = 0; i < (int) pClassData->header.directMethodsSize; i++) {
   1505         dumpMethod(pDexFile, &pClassData->directMethods[i], i);
   1506     }
   1507 
   1508     if (gOptions.outputFormat == OUTPUT_PLAIN)
   1509         printf("  Virtual methods   -\n");
   1510     for (i = 0; i < (int) pClassData->header.virtualMethodsSize; i++) {
   1511         dumpMethod(pDexFile, &pClassData->virtualMethods[i], i);
   1512     }
   1513 
   1514     // TODO: Annotations.
   1515 
   1516     if (pClassDef->sourceFileIdx != kDexNoIndex)
   1517         fileName = dexStringById(pDexFile, pClassDef->sourceFileIdx);
   1518     else
   1519         fileName = "unknown";
   1520 
   1521     if (gOptions.outputFormat == OUTPUT_PLAIN) {
   1522         printf("  source_file_idx   : %d (%s)\n",
   1523             pClassDef->sourceFileIdx, fileName);
   1524         printf("\n");
   1525     }
   1526 
   1527     if (gOptions.outputFormat == OUTPUT_XML) {
   1528         printf("</class>\n");
   1529     }
   1530 
   1531 bail:
   1532     free(pClassData);
   1533     free(accessStr);
   1534 }
   1535 
   1536 
   1537 /*
   1538  * Advance "ptr" to ensure 32-bit alignment.
   1539  */
   1540 static inline const u1* align32(const u1* ptr)
   1541 {
   1542     return (u1*) (((uintptr_t) ptr + 3) & ~0x03);
   1543 }
   1544 
   1545 
   1546 /*
   1547  * Dump a map in the "differential" format.
   1548  *
   1549  * TODO: show a hex dump of the compressed data.  (We can show the
   1550  * uncompressed data if we move the compression code to libdex; otherwise
   1551  * it's too complex to merit a fast & fragile implementation here.)
   1552  */
   1553 void dumpDifferentialCompressedMap(const u1** pData)
   1554 {
   1555     const u1* data = *pData;
   1556     const u1* dataStart = data -1;      // format byte already removed
   1557     u1 regWidth;
   1558     u2 numEntries;
   1559 
   1560     /* standard header */
   1561     regWidth = *data++;
   1562     numEntries = *data++;
   1563     numEntries |= (*data++) << 8;
   1564 
   1565     /* compressed data begins with the compressed data length */
   1566     int compressedLen = readUnsignedLeb128(&data);
   1567     int addrWidth = 1;
   1568     if ((*data & 0x80) != 0)
   1569         addrWidth++;
   1570 
   1571     int origLen = 4 + (addrWidth + regWidth) * numEntries;
   1572     int compLen = (data - dataStart) + compressedLen;
   1573 
   1574     printf("        (differential compression %d -> %d [%d -> %d])\n",
   1575         origLen, compLen,
   1576         (addrWidth + regWidth) * numEntries, compressedLen);
   1577 
   1578     /* skip past end of entry */
   1579     data += compressedLen;
   1580 
   1581     *pData = data;
   1582 }
   1583 
   1584 /*
   1585  * Dump register map contents of the current method.
   1586  *
   1587  * "*pData" should point to the start of the register map data.  Advances
   1588  * "*pData" to the start of the next map.
   1589  */
   1590 void dumpMethodMap(DexFile* pDexFile, const DexMethod* pDexMethod, int idx,
   1591     const u1** pData)
   1592 {
   1593     const u1* data = *pData;
   1594     const DexMethodId* pMethodId;
   1595     const char* name;
   1596     int offset = data - (u1*) pDexFile->pOptHeader;
   1597 
   1598     pMethodId = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
   1599     name = dexStringById(pDexFile, pMethodId->nameIdx);
   1600     printf("      #%d: 0x%08x %s\n", idx, offset, name);
   1601 
   1602     u1 format;
   1603     int addrWidth;
   1604 
   1605     format = *data++;
   1606     if (format == 1) {              /* kRegMapFormatNone */
   1607         /* no map */
   1608         printf("        (no map)\n");
   1609         addrWidth = 0;
   1610     } else if (format == 2) {       /* kRegMapFormatCompact8 */
   1611         addrWidth = 1;
   1612     } else if (format == 3) {       /* kRegMapFormatCompact16 */
   1613         addrWidth = 2;
   1614     } else if (format == 4) {       /* kRegMapFormatDifferential */
   1615         dumpDifferentialCompressedMap(&data);
   1616         goto bail;
   1617     } else {
   1618         printf("        (unknown format %d!)\n", format);
   1619         /* don't know how to skip data; failure will cascade to end of class */
   1620         goto bail;
   1621     }
   1622 
   1623     if (addrWidth > 0) {
   1624         u1 regWidth;
   1625         u2 numEntries;
   1626         int idx, addr, byte;
   1627 
   1628         regWidth = *data++;
   1629         numEntries = *data++;
   1630         numEntries |= (*data++) << 8;
   1631 
   1632         for (idx = 0; idx < numEntries; idx++) {
   1633             addr = *data++;
   1634             if (addrWidth > 1)
   1635                 addr |= (*data++) << 8;
   1636 
   1637             printf("        %4x:", addr);
   1638             for (byte = 0; byte < regWidth; byte++) {
   1639                 printf(" %02x", *data++);
   1640             }
   1641             printf("\n");
   1642         }
   1643     }
   1644 
   1645 bail:
   1646     //if (addrWidth >= 0)
   1647     //    *pData = align32(data);
   1648     *pData = data;
   1649 }
   1650 
   1651 /*
   1652  * Dump the contents of the register map area.
   1653  *
   1654  * These are only present in optimized DEX files, and the structure is
   1655  * not really exposed to other parts of the VM itself.  We're going to
   1656  * dig through them here, but this is pretty fragile.  DO NOT rely on
   1657  * this or derive other code from it.
   1658  */
   1659 void dumpRegisterMaps(DexFile* pDexFile)
   1660 {
   1661     const u1* pClassPool = (const u1*)pDexFile->pRegisterMapPool;
   1662     const u4* classOffsets;
   1663     const u1* ptr;
   1664     u4 numClasses;
   1665     int baseFileOffset = (u1*) pClassPool - (u1*) pDexFile->pOptHeader;
   1666     int idx;
   1667 
   1668     if (pClassPool == NULL) {
   1669         printf("No register maps found\n");
   1670         return;
   1671     }
   1672 
   1673     ptr = pClassPool;
   1674     numClasses = get4LE(ptr);
   1675     ptr += sizeof(u4);
   1676     classOffsets = (const u4*) ptr;
   1677 
   1678     printf("RMAP begins at offset 0x%07x\n", baseFileOffset);
   1679     printf("Maps for %d classes\n", numClasses);
   1680     for (idx = 0; idx < (int) numClasses; idx++) {
   1681         const DexClassDef* pClassDef;
   1682         const char* classDescriptor;
   1683 
   1684         pClassDef = dexGetClassDef(pDexFile, idx);
   1685         classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
   1686 
   1687         printf("%4d: +%d (0x%08x) %s\n", idx, classOffsets[idx],
   1688             baseFileOffset + classOffsets[idx], classDescriptor);
   1689 
   1690         if (classOffsets[idx] == 0)
   1691             continue;
   1692 
   1693         /*
   1694          * What follows is a series of RegisterMap entries, one for every
   1695          * direct method, then one for every virtual method.
   1696          */
   1697         DexClassData* pClassData;
   1698         const u1* pEncodedData;
   1699         const u1* data = (u1*) pClassPool + classOffsets[idx];
   1700         u2 methodCount;
   1701         int i;
   1702 
   1703         pEncodedData = dexGetClassData(pDexFile, pClassDef);
   1704         pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL);
   1705         if (pClassData == NULL) {
   1706             fprintf(stderr, "Trouble reading class data\n");
   1707             continue;
   1708         }
   1709 
   1710         methodCount = *data++;
   1711         methodCount |= (*data++) << 8;
   1712         data += 2;      /* two pad bytes follow methodCount */
   1713         if (methodCount != pClassData->header.directMethodsSize
   1714                             + pClassData->header.virtualMethodsSize)
   1715         {
   1716             printf("NOTE: method count discrepancy (%d != %d + %d)\n",
   1717                 methodCount, pClassData->header.directMethodsSize,
   1718                 pClassData->header.virtualMethodsSize);
   1719             /* this is bad, but keep going anyway */
   1720         }
   1721 
   1722         printf("    direct methods: %d\n",
   1723             pClassData->header.directMethodsSize);
   1724         for (i = 0; i < (int) pClassData->header.directMethodsSize; i++) {
   1725             dumpMethodMap(pDexFile, &pClassData->directMethods[i], i, &data);
   1726         }
   1727 
   1728         printf("    virtual methods: %d\n",
   1729             pClassData->header.virtualMethodsSize);
   1730         for (i = 0; i < (int) pClassData->header.virtualMethodsSize; i++) {
   1731             dumpMethodMap(pDexFile, &pClassData->virtualMethods[i], i, &data);
   1732         }
   1733 
   1734         free(pClassData);
   1735     }
   1736 }
   1737 
   1738 /*
   1739  * Dump the requested sections of the file.
   1740  */
   1741 void processDexFile(const char* fileName, DexFile* pDexFile)
   1742 {
   1743     char* package = NULL;
   1744     int i;
   1745 
   1746     if (gOptions.verbose) {
   1747         printf("Opened '%s', DEX version '%.3s'\n", fileName,
   1748             pDexFile->pHeader->magic +4);
   1749     }
   1750 
   1751     if (gOptions.dumpRegisterMaps) {
   1752         dumpRegisterMaps(pDexFile);
   1753         return;
   1754     }
   1755 
   1756     if (gOptions.showFileHeaders) {
   1757         dumpFileHeader(pDexFile);
   1758         dumpOptDirectory(pDexFile);
   1759     }
   1760 
   1761     if (gOptions.outputFormat == OUTPUT_XML)
   1762         printf("<api>\n");
   1763 
   1764     for (i = 0; i < (int) pDexFile->pHeader->classDefsSize; i++) {
   1765         if (gOptions.showSectionHeaders)
   1766             dumpClassDef(pDexFile, i);
   1767 
   1768         dumpClass(pDexFile, i, &package);
   1769     }
   1770 
   1771     /* free the last one allocated */
   1772     if (package != NULL) {
   1773         printf("</package>\n");
   1774         free(package);
   1775     }
   1776 
   1777     if (gOptions.outputFormat == OUTPUT_XML)
   1778         printf("</api>\n");
   1779 }
   1780 
   1781 
   1782 /*
   1783  * Process one file.
   1784  */
   1785 int process(const char* fileName)
   1786 {
   1787     DexFile* pDexFile = NULL;
   1788     MemMapping map;
   1789     bool mapped = false;
   1790     int result = -1;
   1791 
   1792     if (gOptions.verbose)
   1793         printf("Processing '%s'...\n", fileName);
   1794 
   1795     if (dexOpenAndMap(fileName, gOptions.tempFileName, &map, false) != 0) {
   1796         return result;
   1797     }
   1798     mapped = true;
   1799 
   1800     int flags = kDexParseVerifyChecksum;
   1801     if (gOptions.ignoreBadChecksum)
   1802         flags |= kDexParseContinueOnError;
   1803 
   1804     pDexFile = dexFileParse((u1*)map.addr, map.length, flags);
   1805     if (pDexFile == NULL) {
   1806         fprintf(stderr, "ERROR: DEX parse failed\n");
   1807         goto bail;
   1808     }
   1809 
   1810     if (gOptions.checksumOnly) {
   1811         printf("Checksum verified\n");
   1812     } else {
   1813         processDexFile(fileName, pDexFile);
   1814     }
   1815 
   1816     result = 0;
   1817 
   1818 bail:
   1819     if (mapped)
   1820         sysReleaseShmem(&map);
   1821     if (pDexFile != NULL)
   1822         dexFileFree(pDexFile);
   1823     return result;
   1824 }
   1825 
   1826 
   1827 /*
   1828  * Show usage.
   1829  */
   1830 void usage(void)
   1831 {
   1832     fprintf(stderr, "Copyright (C) 2007 The Android Open Source Project\n\n");
   1833     fprintf(stderr,
   1834         "%s: [-c] [-d] [-f] [-h] [-i] [-l layout] [-m] [-t tempfile] dexfile...\n",
   1835         gProgName);
   1836     fprintf(stderr, "\n");
   1837     fprintf(stderr, " -c : verify checksum and exit\n");
   1838     fprintf(stderr, " -d : disassemble code sections\n");
   1839     fprintf(stderr, " -f : display summary information from file header\n");
   1840     fprintf(stderr, " -h : display file header details\n");
   1841     fprintf(stderr, " -i : ignore checksum failures\n");
   1842     fprintf(stderr, " -l : output layout, either 'plain' or 'xml'\n");
   1843     fprintf(stderr, " -m : dump register maps (and nothing else)\n");
   1844     fprintf(stderr, " -t : temp file name (defaults to /sdcard/dex-temp-*)\n");
   1845 }
   1846 
   1847 /*
   1848  * Parse args.
   1849  *
   1850  * I'm not using getopt_long() because we may not have it in libc.
   1851  */
   1852 int main(int argc, char* const argv[])
   1853 {
   1854     bool wantUsage = false;
   1855     int ic;
   1856 
   1857     memset(&gOptions, 0, sizeof(gOptions));
   1858     gOptions.verbose = true;
   1859 
   1860     while (1) {
   1861         ic = getopt(argc, argv, "cdfhil:mt:");
   1862         if (ic < 0)
   1863             break;
   1864 
   1865         switch (ic) {
   1866         case 'c':       // verify the checksum then exit
   1867             gOptions.checksumOnly = true;
   1868             break;
   1869         case 'd':       // disassemble Dalvik instructions
   1870             gOptions.disassemble = true;
   1871             break;
   1872         case 'f':       // dump outer file header
   1873             gOptions.showFileHeaders = true;
   1874             break;
   1875         case 'h':       // dump section headers, i.e. all meta-data
   1876             gOptions.showSectionHeaders = true;
   1877             break;
   1878         case 'i':       // continue even if checksum is bad
   1879             gOptions.ignoreBadChecksum = true;
   1880             break;
   1881         case 'l':       // layout
   1882             if (strcmp(optarg, "plain") == 0) {
   1883                 gOptions.outputFormat = OUTPUT_PLAIN;
   1884             } else if (strcmp(optarg, "xml") == 0) {
   1885                 gOptions.outputFormat = OUTPUT_XML;
   1886                 gOptions.verbose = false;
   1887                 gOptions.exportsOnly = true;
   1888             } else {
   1889                 wantUsage = true;
   1890             }
   1891             break;
   1892         case 'm':       // dump register maps only
   1893             gOptions.dumpRegisterMaps = true;
   1894             break;
   1895         case 't':       // temp file, used when opening compressed Jar
   1896             gOptions.tempFileName = optarg;
   1897             break;
   1898         default:
   1899             wantUsage = true;
   1900             break;
   1901         }
   1902     }
   1903 
   1904     if (optind == argc) {
   1905         fprintf(stderr, "%s: no file specified\n", gProgName);
   1906         wantUsage = true;
   1907     }
   1908 
   1909     if (gOptions.checksumOnly && gOptions.ignoreBadChecksum) {
   1910         fprintf(stderr, "Can't specify both -c and -i\n");
   1911         wantUsage = true;
   1912     }
   1913 
   1914     if (wantUsage) {
   1915         usage();
   1916         return 2;
   1917     }
   1918 
   1919     int result = 0;
   1920     while (optind < argc) {
   1921         result |= process(argv[optind++]);
   1922     }
   1923 
   1924     return (result != 0);
   1925 }
   1926