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