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("field_ids_size      : %d\n", pHeader->fieldIdsSize);
    439     printf("field_ids_off       : %d (0x%06x)\n",
    440         pHeader->fieldIdsOff, pHeader->fieldIdsOff);
    441     printf("method_ids_size     : %d\n", pHeader->methodIdsSize);
    442     printf("method_ids_off      : %d (0x%06x)\n",
    443         pHeader->methodIdsOff, pHeader->methodIdsOff);
    444     printf("class_defs_size     : %d\n", pHeader->classDefsSize);
    445     printf("class_defs_off      : %d (0x%06x)\n",
    446         pHeader->classDefsOff, pHeader->classDefsOff);
    447     printf("data_size           : %d\n", pHeader->dataSize);
    448     printf("data_off            : %d (0x%06x)\n",
    449         pHeader->dataOff, pHeader->dataOff);
    450     printf("\n");
    451 }
    452 
    453 /*
    454  * Dump the "table of contents" for the opt area.
    455  */
    456 void dumpOptDirectory(const DexFile* pDexFile)
    457 {
    458     const DexOptHeader* pOptHeader = pDexFile->pOptHeader;
    459     if (pOptHeader == NULL)
    460         return;
    461 
    462     printf("OPT section contents:\n");
    463 
    464     const u4* pOpt = (const u4*) ((u1*) pOptHeader + pOptHeader->optOffset);
    465 
    466     if (*pOpt == 0) {
    467         printf("(1.0 format, only class lookup table is present)\n\n");
    468         return;
    469     }
    470 
    471     /*
    472      * The "opt" section is in "chunk" format: a 32-bit identifier, a 32-bit
    473      * length, then the data.  Chunks start on 64-bit boundaries.
    474      */
    475     while (*pOpt != kDexChunkEnd) {
    476         const char* verboseStr;
    477 
    478         u4 size = *(pOpt+1);
    479 
    480         switch (*pOpt) {
    481         case kDexChunkClassLookup:
    482             verboseStr = "class lookup hash table";
    483             break;
    484         case kDexChunkRegisterMaps:
    485             verboseStr = "register maps";
    486             break;
    487         default:
    488             verboseStr = "(unknown chunk type)";
    489             break;
    490         }
    491 
    492         printf("Chunk %08x (%c%c%c%c) - %s (%d bytes)\n", *pOpt,
    493             *pOpt >> 24, (char)(*pOpt >> 16), (char)(*pOpt >> 8), (char)*pOpt,
    494             verboseStr, size);
    495 
    496         size = (size + 8 + 7) & ~7;
    497         pOpt += size / sizeof(u4);
    498     }
    499     printf("\n");
    500 }
    501 
    502 /*
    503  * Dump a class_def_item.
    504  */
    505 void dumpClassDef(DexFile* pDexFile, int idx)
    506 {
    507     const DexClassDef* pClassDef;
    508     const u1* pEncodedData;
    509     DexClassData* pClassData;
    510 
    511     pClassDef = dexGetClassDef(pDexFile, idx);
    512     pEncodedData = dexGetClassData(pDexFile, pClassDef);
    513     pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL);
    514 
    515     if (pClassData == NULL) {
    516         fprintf(stderr, "Trouble reading class data\n");
    517         return;
    518     }
    519 
    520     printf("Class #%d header:\n", idx);
    521     printf("class_idx           : %d\n", pClassDef->classIdx);
    522     printf("access_flags        : %d (0x%04x)\n",
    523         pClassDef->accessFlags, pClassDef->accessFlags);
    524     printf("superclass_idx      : %d\n", pClassDef->superclassIdx);
    525     printf("interfaces_off      : %d (0x%06x)\n",
    526         pClassDef->interfacesOff, pClassDef->interfacesOff);
    527     printf("source_file_idx     : %d\n", pClassDef->sourceFileIdx);
    528     printf("annotations_off     : %d (0x%06x)\n",
    529         pClassDef->annotationsOff, pClassDef->annotationsOff);
    530     printf("class_data_off      : %d (0x%06x)\n",
    531         pClassDef->classDataOff, pClassDef->classDataOff);
    532     printf("static_fields_size  : %d\n", pClassData->header.staticFieldsSize);
    533     printf("instance_fields_size: %d\n",
    534             pClassData->header.instanceFieldsSize);
    535     printf("direct_methods_size : %d\n", pClassData->header.directMethodsSize);
    536     printf("virtual_methods_size: %d\n",
    537             pClassData->header.virtualMethodsSize);
    538     printf("\n");
    539 
    540     free(pClassData);
    541 }
    542 
    543 /*
    544  * Dump an interface that a class declares to implement.
    545  */
    546 void dumpInterface(const DexFile* pDexFile, const DexTypeItem* pTypeItem,
    547     int i)
    548 {
    549     const char* interfaceName =
    550         dexStringByTypeIdx(pDexFile, pTypeItem->typeIdx);
    551 
    552     if (gOptions.outputFormat == OUTPUT_PLAIN) {
    553         printf("    #%d              : '%s'\n", i, interfaceName);
    554     } else {
    555         char* dotted = descriptorToDot(interfaceName);
    556         printf("<implements name=\"%s\">\n</implements>\n", dotted);
    557         free(dotted);
    558     }
    559 }
    560 
    561 /*
    562  * Dump the catches table associated with the code.
    563  */
    564 void dumpCatches(DexFile* pDexFile, const DexCode* pCode)
    565 {
    566     u4 triesSize = pCode->triesSize;
    567 
    568     if (triesSize == 0) {
    569         printf("      catches       : (none)\n");
    570         return;
    571     }
    572 
    573     printf("      catches       : %d\n", triesSize);
    574 
    575     const DexTry* pTries = dexGetTries(pCode);
    576     u4 i;
    577 
    578     for (i = 0; i < triesSize; i++) {
    579         const DexTry* pTry = &pTries[i];
    580         u4 start = pTry->startAddr;
    581         u4 end = start + pTry->insnCount;
    582         DexCatchIterator iterator;
    583 
    584         printf("        0x%04x - 0x%04x\n", start, end);
    585 
    586         dexCatchIteratorInit(&iterator, pCode, pTry->handlerOff);
    587 
    588         for (;;) {
    589             DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
    590             const char* descriptor;
    591 
    592             if (handler == NULL) {
    593                 break;
    594             }
    595 
    596             descriptor = (handler->typeIdx == kDexNoIndex) ? "<any>" :
    597                 dexStringByTypeIdx(pDexFile, handler->typeIdx);
    598 
    599             printf("          %s -> 0x%04x\n", descriptor,
    600                     handler->address);
    601         }
    602     }
    603 }
    604 
    605 static int dumpPositionsCb(void *cnxt, u4 address, u4 lineNum)
    606 {
    607     printf("        0x%04x line=%d\n", address, lineNum);
    608     return 0;
    609 }
    610 
    611 /*
    612  * Dump the positions list.
    613  */
    614 void dumpPositions(DexFile* pDexFile, const DexCode* pCode,
    615         const DexMethod *pDexMethod)
    616 {
    617     printf("      positions     : \n");
    618     const DexMethodId *pMethodId
    619             = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
    620     const char *classDescriptor
    621             = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
    622 
    623     dexDecodeDebugInfo(pDexFile, pCode, classDescriptor, pMethodId->protoIdx,
    624             pDexMethod->accessFlags, dumpPositionsCb, NULL, NULL);
    625 }
    626 
    627 static void dumpLocalsCb(void *cnxt, u2 reg, u4 startAddress,
    628         u4 endAddress, const char *name, const char *descriptor,
    629         const char *signature)
    630 {
    631     printf("        0x%04x - 0x%04x reg=%d %s %s %s\n",
    632             startAddress, endAddress, reg, name, descriptor,
    633             signature);
    634 }
    635 
    636 /*
    637  * Dump the locals list.
    638  */
    639 void dumpLocals(DexFile* pDexFile, const DexCode* pCode,
    640         const DexMethod *pDexMethod)
    641 {
    642     printf("      locals        : \n");
    643 
    644     const DexMethodId *pMethodId
    645             = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
    646     const char *classDescriptor
    647             = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
    648 
    649     dexDecodeDebugInfo(pDexFile, pCode, classDescriptor, pMethodId->protoIdx,
    650             pDexMethod->accessFlags, NULL, dumpLocalsCb, NULL);
    651 }
    652 
    653 /*
    654  * Get information about a method.
    655  */
    656 bool getMethodInfo(DexFile* pDexFile, u4 methodIdx, FieldMethodInfo* pMethInfo)
    657 {
    658     const DexMethodId* pMethodId;
    659 
    660     if (methodIdx >= pDexFile->pHeader->methodIdsSize)
    661         return false;
    662 
    663     pMethodId = dexGetMethodId(pDexFile, methodIdx);
    664     pMethInfo->name = dexStringById(pDexFile, pMethodId->nameIdx);
    665     pMethInfo->signature = dexCopyDescriptorFromMethodId(pDexFile, pMethodId);
    666 
    667     pMethInfo->classDescriptor =
    668             dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
    669     return true;
    670 }
    671 
    672 /*
    673  * Get information about a field.
    674  */
    675 bool getFieldInfo(DexFile* pDexFile, u4 fieldIdx, FieldMethodInfo* pFieldInfo)
    676 {
    677     const DexFieldId* pFieldId;
    678 
    679     if (fieldIdx >= pDexFile->pHeader->fieldIdsSize)
    680         return false;
    681 
    682     pFieldId = dexGetFieldId(pDexFile, fieldIdx);
    683     pFieldInfo->name = dexStringById(pDexFile, pFieldId->nameIdx);
    684     pFieldInfo->signature = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx);
    685     pFieldInfo->classDescriptor =
    686         dexStringByTypeIdx(pDexFile, pFieldId->classIdx);
    687     return true;
    688 }
    689 
    690 
    691 /*
    692  * Look up a class' descriptor.
    693  */
    694 const char* getClassDescriptor(DexFile* pDexFile, u4 classIdx)
    695 {
    696     return dexStringByTypeIdx(pDexFile, classIdx);
    697 }
    698 
    699 /*
    700  * Helper for dumpInstruction(), which builds the string
    701  * representation for the index in the given instruction. This will
    702  * first try to use the given buffer, but if the result won't fit,
    703  * then this will allocate a new buffer to hold the result. A pointer
    704  * to the buffer which holds the full result is always returned, and
    705  * this can be compared with the one passed in, to see if the result
    706  * needs to be free()d.
    707  */
    708 static char* indexString(DexFile* pDexFile,
    709     const DecodedInstruction* pDecInsn, char* buf, size_t bufSize)
    710 {
    711     int outSize;
    712     u4 index;
    713     u4 width;
    714 
    715     /* TODO: Make the index *always* be in field B, to simplify this code. */
    716     switch (dexGetFormatFromOpcode(pDecInsn->opcode)) {
    717     case kFmt20bc:
    718     case kFmt21c:
    719     case kFmt35c:
    720     case kFmt35ms:
    721     case kFmt3rc:
    722     case kFmt3rms:
    723     case kFmt35mi:
    724     case kFmt3rmi:
    725         index = pDecInsn->vB;
    726         width = 4;
    727         break;
    728     case kFmt31c:
    729     case kFmt40sc:
    730     case kFmt41c:
    731     case kFmt5rc:
    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     case kFmt52c:
    741         index = pDecInsn->vC;
    742         width = 8;
    743         break;
    744     default:
    745         index = 0;
    746         width = 4;
    747         break;
    748     }
    749 
    750     switch (pDecInsn->indexType) {
    751     case kIndexUnknown:
    752         /*
    753          * This function shouldn't ever get called for this type, but do
    754          * something sensible here, just to help with debugging.
    755          */
    756         outSize = snprintf(buf, bufSize, "<unknown-index>");
    757         break;
    758     case kIndexNone:
    759         /*
    760          * This function shouldn't ever get called for this type, but do
    761          * something sensible here, just to help with debugging.
    762          */
    763         outSize = snprintf(buf, bufSize, "<no-index>");
    764         break;
    765     case kIndexVaries:
    766         /*
    767          * This one should never show up in a dexdump, so no need to try
    768          * to get fancy here.
    769          */
    770         outSize = snprintf(buf, bufSize, "<index-varies> // thing@%0*x",
    771                 width, index);
    772         break;
    773     case kIndexTypeRef:
    774         outSize = snprintf(buf, bufSize, "%s // type@%0*x",
    775                 getClassDescriptor(pDexFile, index), width, index);
    776         break;
    777     case kIndexStringRef:
    778         outSize = snprintf(buf, bufSize, "\"%s\" // string@%0*x",
    779                 dexStringById(pDexFile, index), width, index);
    780         break;
    781     case kIndexMethodRef:
    782         {
    783             FieldMethodInfo methInfo;
    784             if (getMethodInfo(pDexFile, index, &methInfo)) {
    785                 outSize = snprintf(buf, bufSize, "%s.%s:%s // method@%0*x",
    786                         methInfo.classDescriptor, methInfo.name,
    787                         methInfo.signature, width, index);
    788             } else {
    789                 outSize = snprintf(buf, bufSize, "<method?> // method@%0*x",
    790                         width, index);
    791             }
    792         }
    793         break;
    794     case kIndexFieldRef:
    795         {
    796             FieldMethodInfo fieldInfo;
    797             if (getFieldInfo(pDexFile, index, &fieldInfo)) {
    798                 outSize = snprintf(buf, bufSize, "%s.%s:%s // field@%0*x",
    799                         fieldInfo.classDescriptor, fieldInfo.name,
    800                         fieldInfo.signature, width, index);
    801             } else {
    802                 outSize = snprintf(buf, bufSize, "<field?> // field@%0*x",
    803                         width, index);
    804             }
    805         }
    806         break;
    807     case kIndexInlineMethod:
    808         outSize = snprintf(buf, bufSize, "[%0*x] // inline #%0*x",
    809                 width, index, width, index);
    810         break;
    811     case kIndexVtableOffset:
    812         outSize = snprintf(buf, bufSize, "[%0*x] // vtable #%0*x",
    813                 width, index, width, index);
    814         break;
    815     case kIndexFieldOffset:
    816         outSize = snprintf(buf, bufSize, "[obj+%0*x]", width, index);
    817         break;
    818     default:
    819         outSize = snprintf(buf, bufSize, "<?>");
    820         break;
    821     }
    822 
    823     if (outSize >= (int) bufSize) {
    824         /*
    825          * The buffer wasn't big enough; allocate and retry. Note:
    826          * snprintf() doesn't count the '\0' as part of its returned
    827          * size, so we add explicit space for it here.
    828          */
    829         outSize++;
    830         buf = (char*)malloc(outSize);
    831         if (buf == NULL) {
    832             return NULL;
    833         }
    834         return indexString(pDexFile, pDecInsn, buf, outSize);
    835     } else {
    836         return buf;
    837     }
    838 }
    839 
    840 /*
    841  * Dump a single instruction.
    842  */
    843 void dumpInstruction(DexFile* pDexFile, const DexCode* pCode, int insnIdx,
    844     int insnWidth, const DecodedInstruction* pDecInsn)
    845 {
    846     char indexBufChars[200];
    847     char *indexBuf = indexBufChars;
    848     const u2* insns = pCode->insns;
    849     int i;
    850 
    851     printf("%06x:", ((u1*)insns - pDexFile->baseAddr) + insnIdx*2);
    852     for (i = 0; i < 8; i++) {
    853         if (i < insnWidth) {
    854             if (i == 7) {
    855                 printf(" ... ");
    856             } else {
    857                 /* print 16-bit value in little-endian order */
    858                 const u1* bytePtr = (const u1*) &insns[insnIdx+i];
    859                 printf(" %02x%02x", bytePtr[0], bytePtr[1]);
    860             }
    861         } else {
    862             fputs("     ", stdout);
    863         }
    864     }
    865 
    866     if (pDecInsn->opcode == OP_NOP) {
    867         u2 instr = get2LE((const u1*) &insns[insnIdx]);
    868         if (instr == kPackedSwitchSignature) {
    869             printf("|%04x: packed-switch-data (%d units)",
    870                 insnIdx, insnWidth);
    871         } else if (instr == kSparseSwitchSignature) {
    872             printf("|%04x: sparse-switch-data (%d units)",
    873                 insnIdx, insnWidth);
    874         } else if (instr == kArrayDataSignature) {
    875             printf("|%04x: array-data (%d units)",
    876                 insnIdx, insnWidth);
    877         } else {
    878             printf("|%04x: nop // spacer", insnIdx);
    879         }
    880     } else {
    881         printf("|%04x: %s", insnIdx, dexGetOpcodeName(pDecInsn->opcode));
    882     }
    883 
    884     if (pDecInsn->indexType != kIndexNone) {
    885         indexBuf = indexString(pDexFile, pDecInsn,
    886                 indexBufChars, sizeof(indexBufChars));
    887     }
    888 
    889     switch (dexGetFormatFromOpcode(pDecInsn->opcode)) {
    890     case kFmt10x:        // op
    891         break;
    892     case kFmt12x:        // op vA, vB
    893         printf(" v%d, v%d", pDecInsn->vA, pDecInsn->vB);
    894         break;
    895     case kFmt11n:        // op vA, #+B
    896         printf(" v%d, #int %d // #%x",
    897             pDecInsn->vA, (s4)pDecInsn->vB, (u1)pDecInsn->vB);
    898         break;
    899     case kFmt11x:        // op vAA
    900         printf(" v%d", pDecInsn->vA);
    901         break;
    902     case kFmt10t:        // op +AA
    903     case kFmt20t:        // op +AAAA
    904         {
    905             s4 targ = (s4) pDecInsn->vA;
    906             printf(" %04x // %c%04x",
    907                 insnIdx + targ,
    908                 (targ < 0) ? '-' : '+',
    909                 (targ < 0) ? -targ : targ);
    910         }
    911         break;
    912     case kFmt22x:        // op vAA, vBBBB
    913         printf(" v%d, v%d", pDecInsn->vA, pDecInsn->vB);
    914         break;
    915     case kFmt21t:        // op vAA, +BBBB
    916         {
    917             s4 targ = (s4) pDecInsn->vB;
    918             printf(" v%d, %04x // %c%04x", pDecInsn->vA,
    919                 insnIdx + targ,
    920                 (targ < 0) ? '-' : '+',
    921                 (targ < 0) ? -targ : targ);
    922         }
    923         break;
    924     case kFmt21s:        // op vAA, #+BBBB
    925         printf(" v%d, #int %d // #%x",
    926             pDecInsn->vA, (s4)pDecInsn->vB, (u2)pDecInsn->vB);
    927         break;
    928     case kFmt21h:        // op vAA, #+BBBB0000[00000000]
    929         // The printed format varies a bit based on the actual opcode.
    930         if (pDecInsn->opcode == OP_CONST_HIGH16) {
    931             s4 value = pDecInsn->vB << 16;
    932             printf(" v%d, #int %d // #%x",
    933                 pDecInsn->vA, value, (u2)pDecInsn->vB);
    934         } else {
    935             s8 value = ((s8) pDecInsn->vB) << 48;
    936             printf(" v%d, #long %lld // #%x",
    937                 pDecInsn->vA, value, (u2)pDecInsn->vB);
    938         }
    939         break;
    940     case kFmt21c:        // op vAA, thing@BBBB
    941     case kFmt31c:        // op vAA, thing@BBBBBBBB
    942     case kFmt41c:        // exop vAAAA, thing@BBBBBBBB
    943         printf(" v%d, %s", pDecInsn->vA, indexBuf);
    944         break;
    945     case kFmt23x:        // op vAA, vBB, vCC
    946     case kFmt33x:        // exop vAA, vBB, vCCCC
    947         printf(" v%d, v%d, v%d", pDecInsn->vA, pDecInsn->vB, pDecInsn->vC);
    948         break;
    949     case kFmt22b:        // op vAA, vBB, #+CC
    950         printf(" v%d, v%d, #int %d // #%02x",
    951             pDecInsn->vA, pDecInsn->vB, (s4)pDecInsn->vC, (u1)pDecInsn->vC);
    952         break;
    953     case kFmt22t:        // op vA, vB, +CCCC
    954         {
    955             s4 targ = (s4) pDecInsn->vC;
    956             printf(" v%d, v%d, %04x // %c%04x", pDecInsn->vA, pDecInsn->vB,
    957                 insnIdx + targ,
    958                 (targ < 0) ? '-' : '+',
    959                 (targ < 0) ? -targ : targ);
    960         }
    961         break;
    962     case kFmt22s:        // op vA, vB, #+CCCC
    963     case kFmt32s:        // exop vAA, vBB, #+CCCC
    964         printf(" v%d, v%d, #int %d // #%04x",
    965             pDecInsn->vA, pDecInsn->vB, (s4)pDecInsn->vC, (u2)pDecInsn->vC);
    966         break;
    967     case kFmt22c:        // op vA, vB, thing@CCCC
    968     case kFmt22cs:       // [opt] op vA, vB, field offset CCCC
    969     case kFmt52c:        // exop vAAAA, vBBBB, thing@CCCCCCCC
    970         printf(" v%d, v%d, %s", pDecInsn->vA, pDecInsn->vB, indexBuf);
    971         break;
    972     case kFmt30t:
    973         printf(" #%08x", pDecInsn->vA);
    974         break;
    975     case kFmt31i:        // op vAA, #+BBBBBBBB
    976         {
    977             /* this is often, but not always, a float */
    978             union {
    979                 float f;
    980                 u4 i;
    981             } conv;
    982             conv.i = pDecInsn->vB;
    983             printf(" v%d, #float %f // #%08x",
    984                 pDecInsn->vA, conv.f, pDecInsn->vB);
    985         }
    986         break;
    987     case kFmt31t:       // op vAA, offset +BBBBBBBB
    988         printf(" v%d, %08x // +%08x",
    989             pDecInsn->vA, insnIdx + pDecInsn->vB, pDecInsn->vB);
    990         break;
    991     case kFmt32x:        // op vAAAA, vBBBB
    992         printf(" v%d, v%d", pDecInsn->vA, pDecInsn->vB);
    993         break;
    994     case kFmt35c:        // op {vC, vD, vE, vF, vG}, thing@BBBB
    995     case kFmt35ms:       // [opt] invoke-virtual+super
    996     case kFmt35mi:       // [opt] inline invoke
    997         {
    998             fputs(" {", stdout);
    999             for (i = 0; i < (int) pDecInsn->vA; i++) {
   1000                 if (i == 0)
   1001                     printf("v%d", pDecInsn->arg[i]);
   1002                 else
   1003                     printf(", v%d", pDecInsn->arg[i]);
   1004             }
   1005             printf("}, %s", indexBuf);
   1006         }
   1007         break;
   1008     case kFmt3rc:        // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB
   1009     case kFmt3rms:       // [opt] invoke-virtual+super/range
   1010     case kFmt3rmi:       // [opt] execute-inline/range
   1011     case kFmt5rc:        // exop {vCCCC .. v(CCCC+AAAA-1)}, meth@BBBBBBBB
   1012         {
   1013             /*
   1014              * This doesn't match the "dx" output when some of the args are
   1015              * 64-bit values -- dx only shows the first register.
   1016              */
   1017             fputs(" {", stdout);
   1018             for (i = 0; i < (int) pDecInsn->vA; i++) {
   1019                 if (i == 0)
   1020                     printf("v%d", pDecInsn->vC + i);
   1021                 else
   1022                     printf(", v%d", pDecInsn->vC + i);
   1023             }
   1024             printf("}, %s", indexBuf);
   1025         }
   1026         break;
   1027     case kFmt51l:        // op vAA, #+BBBBBBBBBBBBBBBB
   1028         {
   1029             /* this is often, but not always, a double */
   1030             union {
   1031                 double d;
   1032                 u8 j;
   1033             } conv;
   1034             conv.j = pDecInsn->vB_wide;
   1035             printf(" v%d, #double %f // #%016llx",
   1036                 pDecInsn->vA, conv.d, pDecInsn->vB_wide);
   1037         }
   1038         break;
   1039     case kFmt00x:        // unknown op or breakpoint
   1040         break;
   1041     default:
   1042         printf(" ???");
   1043         break;
   1044     }
   1045 
   1046     putchar('\n');
   1047 
   1048     if (indexBuf != indexBufChars) {
   1049         free(indexBuf);
   1050     }
   1051 }
   1052 
   1053 /*
   1054  * Dump a bytecode disassembly.
   1055  */
   1056 void dumpBytecodes(DexFile* pDexFile, const DexMethod* pDexMethod)
   1057 {
   1058     const DexCode* pCode = dexGetCode(pDexFile, pDexMethod);
   1059     const u2* insns;
   1060     int insnIdx;
   1061     FieldMethodInfo methInfo;
   1062     int startAddr;
   1063     char* className = NULL;
   1064 
   1065     assert(pCode->insnsSize > 0);
   1066     insns = pCode->insns;
   1067 
   1068     getMethodInfo(pDexFile, pDexMethod->methodIdx, &methInfo);
   1069     startAddr = ((u1*)pCode - pDexFile->baseAddr);
   1070     className = descriptorToDot(methInfo.classDescriptor);
   1071 
   1072     printf("%06x:                                        |[%06x] %s.%s:%s\n",
   1073         startAddr, startAddr,
   1074         className, methInfo.name, methInfo.signature);
   1075 
   1076     insnIdx = 0;
   1077     while (insnIdx < (int) pCode->insnsSize) {
   1078         int insnWidth;
   1079         DecodedInstruction decInsn;
   1080         u2 instr;
   1081 
   1082         /*
   1083          * Note: This code parallels the function
   1084          * dexGetWidthFromInstruction() in InstrUtils.c, but this version
   1085          * can deal with data in either endianness.
   1086          *
   1087          * TODO: Figure out if this really matters, and possibly change
   1088          * this to just use dexGetWidthFromInstruction().
   1089          */
   1090         instr = get2LE((const u1*)insns);
   1091         if (instr == kPackedSwitchSignature) {
   1092             insnWidth = 4 + get2LE((const u1*)(insns+1)) * 2;
   1093         } else if (instr == kSparseSwitchSignature) {
   1094             insnWidth = 2 + get2LE((const u1*)(insns+1)) * 4;
   1095         } else if (instr == kArrayDataSignature) {
   1096             int width = get2LE((const u1*)(insns+1));
   1097             int size = get2LE((const u1*)(insns+2)) |
   1098                        (get2LE((const u1*)(insns+3))<<16);
   1099             // The plus 1 is to round up for odd size and width.
   1100             insnWidth = 4 + ((size * width) + 1) / 2;
   1101         } else {
   1102             Opcode opcode = dexOpcodeFromCodeUnit(instr);
   1103             insnWidth = dexGetWidthFromOpcode(opcode);
   1104             if (insnWidth == 0) {
   1105                 fprintf(stderr,
   1106                     "GLITCH: zero-width instruction at idx=0x%04x\n", insnIdx);
   1107                 break;
   1108             }
   1109         }
   1110 
   1111         dexDecodeInstruction(insns, &decInsn);
   1112         dumpInstruction(pDexFile, pCode, insnIdx, insnWidth, &decInsn);
   1113 
   1114         insns += insnWidth;
   1115         insnIdx += insnWidth;
   1116     }
   1117 
   1118     free(className);
   1119 }
   1120 
   1121 /*
   1122  * Dump a "code" struct.
   1123  */
   1124 void dumpCode(DexFile* pDexFile, const DexMethod* pDexMethod)
   1125 {
   1126     const DexCode* pCode = dexGetCode(pDexFile, pDexMethod);
   1127 
   1128     printf("      registers     : %d\n", pCode->registersSize);
   1129     printf("      ins           : %d\n", pCode->insSize);
   1130     printf("      outs          : %d\n", pCode->outsSize);
   1131     printf("      insns size    : %d 16-bit code units\n", pCode->insnsSize);
   1132 
   1133     if (gOptions.disassemble)
   1134         dumpBytecodes(pDexFile, pDexMethod);
   1135 
   1136     dumpCatches(pDexFile, pCode);
   1137     /* both of these are encoded in debug info */
   1138     dumpPositions(pDexFile, pCode, pDexMethod);
   1139     dumpLocals(pDexFile, pCode, pDexMethod);
   1140 }
   1141 
   1142 /*
   1143  * Dump a method.
   1144  */
   1145 void dumpMethod(DexFile* pDexFile, const DexMethod* pDexMethod, int i)
   1146 {
   1147     const DexMethodId* pMethodId;
   1148     const char* backDescriptor;
   1149     const char* name;
   1150     char* typeDescriptor = NULL;
   1151     char* accessStr = NULL;
   1152 
   1153     if (gOptions.exportsOnly &&
   1154         (pDexMethod->accessFlags & (ACC_PUBLIC | ACC_PROTECTED)) == 0)
   1155     {
   1156         return;
   1157     }
   1158 
   1159     pMethodId = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
   1160     name = dexStringById(pDexFile, pMethodId->nameIdx);
   1161     typeDescriptor = dexCopyDescriptorFromMethodId(pDexFile, pMethodId);
   1162 
   1163     backDescriptor = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
   1164 
   1165     accessStr = createAccessFlagStr(pDexMethod->accessFlags,
   1166                     kAccessForMethod);
   1167 
   1168     if (gOptions.outputFormat == OUTPUT_PLAIN) {
   1169         printf("    #%d              : (in %s)\n", i, backDescriptor);
   1170         printf("      name          : '%s'\n", name);
   1171         printf("      type          : '%s'\n", typeDescriptor);
   1172         printf("      access        : 0x%04x (%s)\n",
   1173             pDexMethod->accessFlags, accessStr);
   1174 
   1175         if (pDexMethod->codeOff == 0) {
   1176             printf("      code          : (none)\n");
   1177         } else {
   1178             printf("      code          -\n");
   1179             dumpCode(pDexFile, pDexMethod);
   1180         }
   1181 
   1182         if (gOptions.disassemble)
   1183             putchar('\n');
   1184     } else if (gOptions.outputFormat == OUTPUT_XML) {
   1185         bool constructor = (name[0] == '<');
   1186 
   1187         if (constructor) {
   1188             char* tmp;
   1189 
   1190             tmp = descriptorClassToDot(backDescriptor);
   1191             printf("<constructor name=\"%s\"\n", tmp);
   1192             free(tmp);
   1193 
   1194             tmp = descriptorToDot(backDescriptor);
   1195             printf(" type=\"%s\"\n", tmp);
   1196             free(tmp);
   1197         } else {
   1198             printf("<method name=\"%s\"\n", name);
   1199 
   1200             const char* returnType = strrchr(typeDescriptor, ')');
   1201             if (returnType == NULL) {
   1202                 fprintf(stderr, "bad method type descriptor '%s'\n",
   1203                     typeDescriptor);
   1204                 goto bail;
   1205             }
   1206 
   1207             char* tmp = descriptorToDot(returnType+1);
   1208             printf(" return=\"%s\"\n", tmp);
   1209             free(tmp);
   1210 
   1211             printf(" abstract=%s\n",
   1212                 quotedBool((pDexMethod->accessFlags & ACC_ABSTRACT) != 0));
   1213             printf(" native=%s\n",
   1214                 quotedBool((pDexMethod->accessFlags & ACC_NATIVE) != 0));
   1215 
   1216             bool isSync =
   1217                 (pDexMethod->accessFlags & ACC_SYNCHRONIZED) != 0 ||
   1218                 (pDexMethod->accessFlags & ACC_DECLARED_SYNCHRONIZED) != 0;
   1219             printf(" synchronized=%s\n", quotedBool(isSync));
   1220         }
   1221 
   1222         printf(" static=%s\n",
   1223             quotedBool((pDexMethod->accessFlags & ACC_STATIC) != 0));
   1224         printf(" final=%s\n",
   1225             quotedBool((pDexMethod->accessFlags & ACC_FINAL) != 0));
   1226         // "deprecated=" not knowable w/o parsing annotations
   1227         printf(" visibility=%s\n",
   1228             quotedVisibility(pDexMethod->accessFlags));
   1229 
   1230         printf(">\n");
   1231 
   1232         /*
   1233          * Parameters.
   1234          */
   1235         if (typeDescriptor[0] != '(') {
   1236             fprintf(stderr, "ERROR: bad descriptor '%s'\n", typeDescriptor);
   1237             goto bail;
   1238         }
   1239 
   1240         char tmpBuf[strlen(typeDescriptor)+1];      /* more than big enough */
   1241         int argNum = 0;
   1242 
   1243         const char* base = typeDescriptor+1;
   1244 
   1245         while (*base != ')') {
   1246             char* cp = tmpBuf;
   1247 
   1248             while (*base == '[')
   1249                 *cp++ = *base++;
   1250 
   1251             if (*base == 'L') {
   1252                 /* copy through ';' */
   1253                 do {
   1254                     *cp = *base++;
   1255                 } while (*cp++ != ';');
   1256             } else {
   1257                 /* primitive char, copy it */
   1258                 if (strchr("ZBCSIFJD", *base) == NULL) {
   1259                     fprintf(stderr, "ERROR: bad method signature '%s'\n", base);
   1260                     goto bail;
   1261                 }
   1262                 *cp++ = *base++;
   1263             }
   1264 
   1265             /* null terminate and display */
   1266             *cp++ = '\0';
   1267 
   1268             char* tmp = descriptorToDot(tmpBuf);
   1269             printf("<parameter name=\"arg%d\" type=\"%s\">\n</parameter>\n",
   1270                 argNum++, tmp);
   1271             free(tmp);
   1272         }
   1273 
   1274         if (constructor)
   1275             printf("</constructor>\n");
   1276         else
   1277             printf("</method>\n");
   1278     }
   1279 
   1280 bail:
   1281     free(typeDescriptor);
   1282     free(accessStr);
   1283 }
   1284 
   1285 /*
   1286  * Dump a static (class) field.
   1287  */
   1288 void dumpSField(const DexFile* pDexFile, const DexField* pSField, int i)
   1289 {
   1290     const DexFieldId* pFieldId;
   1291     const char* backDescriptor;
   1292     const char* name;
   1293     const char* typeDescriptor;
   1294     char* accessStr;
   1295 
   1296     if (gOptions.exportsOnly &&
   1297         (pSField->accessFlags & (ACC_PUBLIC | ACC_PROTECTED)) == 0)
   1298     {
   1299         return;
   1300     }
   1301 
   1302     pFieldId = dexGetFieldId(pDexFile, pSField->fieldIdx);
   1303     name = dexStringById(pDexFile, pFieldId->nameIdx);
   1304     typeDescriptor = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx);
   1305     backDescriptor = dexStringByTypeIdx(pDexFile, pFieldId->classIdx);
   1306 
   1307     accessStr = createAccessFlagStr(pSField->accessFlags, kAccessForField);
   1308 
   1309     if (gOptions.outputFormat == OUTPUT_PLAIN) {
   1310         printf("    #%d              : (in %s)\n", i, backDescriptor);
   1311         printf("      name          : '%s'\n", name);
   1312         printf("      type          : '%s'\n", typeDescriptor);
   1313         printf("      access        : 0x%04x (%s)\n",
   1314             pSField->accessFlags, accessStr);
   1315     } else if (gOptions.outputFormat == OUTPUT_XML) {
   1316         char* tmp;
   1317 
   1318         printf("<field name=\"%s\"\n", name);
   1319 
   1320         tmp = descriptorToDot(typeDescriptor);
   1321         printf(" type=\"%s\"\n", tmp);
   1322         free(tmp);
   1323 
   1324         printf(" transient=%s\n",
   1325             quotedBool((pSField->accessFlags & ACC_TRANSIENT) != 0));
   1326         printf(" volatile=%s\n",
   1327             quotedBool((pSField->accessFlags & ACC_VOLATILE) != 0));
   1328         // "value=" not knowable w/o parsing annotations
   1329         printf(" static=%s\n",
   1330             quotedBool((pSField->accessFlags & ACC_STATIC) != 0));
   1331         printf(" final=%s\n",
   1332             quotedBool((pSField->accessFlags & ACC_FINAL) != 0));
   1333         // "deprecated=" not knowable w/o parsing annotations
   1334         printf(" visibility=%s\n",
   1335             quotedVisibility(pSField->accessFlags));
   1336         printf(">\n</field>\n");
   1337     }
   1338 
   1339     free(accessStr);
   1340 }
   1341 
   1342 /*
   1343  * Dump an instance field.
   1344  */
   1345 void dumpIField(const DexFile* pDexFile, const DexField* pIField, int i)
   1346 {
   1347     dumpSField(pDexFile, pIField, i);
   1348 }
   1349 
   1350 /*
   1351  * Dump the class.
   1352  *
   1353  * Note "idx" is a DexClassDef index, not a DexTypeId index.
   1354  *
   1355  * If "*pLastPackage" is NULL or does not match the current class' package,
   1356  * the value will be replaced with a newly-allocated string.
   1357  */
   1358 void dumpClass(DexFile* pDexFile, int idx, char** pLastPackage)
   1359 {
   1360     const DexTypeList* pInterfaces;
   1361     const DexClassDef* pClassDef;
   1362     DexClassData* pClassData = NULL;
   1363     const u1* pEncodedData;
   1364     const char* fileName;
   1365     const char* classDescriptor;
   1366     const char* superclassDescriptor;
   1367     char* accessStr = NULL;
   1368     int i;
   1369 
   1370     pClassDef = dexGetClassDef(pDexFile, idx);
   1371 
   1372     if (gOptions.exportsOnly && (pClassDef->accessFlags & ACC_PUBLIC) == 0) {
   1373         //printf("<!-- omitting non-public class %s -->\n",
   1374         //    classDescriptor);
   1375         goto bail;
   1376     }
   1377 
   1378     pEncodedData = dexGetClassData(pDexFile, pClassDef);
   1379     pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL);
   1380 
   1381     if (pClassData == NULL) {
   1382         printf("Trouble reading class data (#%d)\n", idx);
   1383         goto bail;
   1384     }
   1385 
   1386     classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
   1387 
   1388     /*
   1389      * For the XML output, show the package name.  Ideally we'd gather
   1390      * up the classes, sort them, and dump them alphabetically so the
   1391      * package name wouldn't jump around, but that's not a great plan
   1392      * for something that needs to run on the device.
   1393      */
   1394     if (!(classDescriptor[0] == 'L' &&
   1395           classDescriptor[strlen(classDescriptor)-1] == ';'))
   1396     {
   1397         /* arrays and primitives should not be defined explicitly */
   1398         fprintf(stderr, "Malformed class name '%s'\n", classDescriptor);
   1399         /* keep going? */
   1400     } else if (gOptions.outputFormat == OUTPUT_XML) {
   1401         char* mangle;
   1402         char* lastSlash;
   1403         char* cp;
   1404 
   1405         mangle = strdup(classDescriptor + 1);
   1406         mangle[strlen(mangle)-1] = '\0';
   1407 
   1408         /* reduce to just the package name */
   1409         lastSlash = strrchr(mangle, '/');
   1410         if (lastSlash != NULL) {
   1411             *lastSlash = '\0';
   1412         } else {
   1413             *mangle = '\0';
   1414         }
   1415 
   1416         for (cp = mangle; *cp != '\0'; cp++) {
   1417             if (*cp == '/')
   1418                 *cp = '.';
   1419         }
   1420 
   1421         if (*pLastPackage == NULL || strcmp(mangle, *pLastPackage) != 0) {
   1422             /* start of a new package */
   1423             if (*pLastPackage != NULL)
   1424                 printf("</package>\n");
   1425             printf("<package name=\"%s\"\n>\n", mangle);
   1426             free(*pLastPackage);
   1427             *pLastPackage = mangle;
   1428         } else {
   1429             free(mangle);
   1430         }
   1431     }
   1432 
   1433     accessStr = createAccessFlagStr(pClassDef->accessFlags, kAccessForClass);
   1434 
   1435     if (pClassDef->superclassIdx == kDexNoIndex) {
   1436         superclassDescriptor = NULL;
   1437     } else {
   1438         superclassDescriptor =
   1439             dexStringByTypeIdx(pDexFile, pClassDef->superclassIdx);
   1440     }
   1441 
   1442     if (gOptions.outputFormat == OUTPUT_PLAIN) {
   1443         printf("Class #%d            -\n", idx);
   1444         printf("  Class descriptor  : '%s'\n", classDescriptor);
   1445         printf("  Access flags      : 0x%04x (%s)\n",
   1446             pClassDef->accessFlags, accessStr);
   1447 
   1448         if (superclassDescriptor != NULL)
   1449             printf("  Superclass        : '%s'\n", superclassDescriptor);
   1450 
   1451         printf("  Interfaces        -\n");
   1452     } else {
   1453         char* tmp;
   1454 
   1455         tmp = descriptorClassToDot(classDescriptor);
   1456         printf("<class name=\"%s\"\n", tmp);
   1457         free(tmp);
   1458 
   1459         if (superclassDescriptor != NULL) {
   1460             tmp = descriptorToDot(superclassDescriptor);
   1461             printf(" extends=\"%s\"\n", tmp);
   1462             free(tmp);
   1463         }
   1464         printf(" abstract=%s\n",
   1465             quotedBool((pClassDef->accessFlags & ACC_ABSTRACT) != 0));
   1466         printf(" static=%s\n",
   1467             quotedBool((pClassDef->accessFlags & ACC_STATIC) != 0));
   1468         printf(" final=%s\n",
   1469             quotedBool((pClassDef->accessFlags & ACC_FINAL) != 0));
   1470         // "deprecated=" not knowable w/o parsing annotations
   1471         printf(" visibility=%s\n",
   1472             quotedVisibility(pClassDef->accessFlags));
   1473         printf(">\n");
   1474     }
   1475     pInterfaces = dexGetInterfacesList(pDexFile, pClassDef);
   1476     if (pInterfaces != NULL) {
   1477         for (i = 0; i < (int) pInterfaces->size; i++)
   1478             dumpInterface(pDexFile, dexGetTypeItem(pInterfaces, i), i);
   1479     }
   1480 
   1481     if (gOptions.outputFormat == OUTPUT_PLAIN)
   1482         printf("  Static fields     -\n");
   1483     for (i = 0; i < (int) pClassData->header.staticFieldsSize; i++) {
   1484         dumpSField(pDexFile, &pClassData->staticFields[i], i);
   1485     }
   1486 
   1487     if (gOptions.outputFormat == OUTPUT_PLAIN)
   1488         printf("  Instance fields   -\n");
   1489     for (i = 0; i < (int) pClassData->header.instanceFieldsSize; i++) {
   1490         dumpIField(pDexFile, &pClassData->instanceFields[i], i);
   1491     }
   1492 
   1493     if (gOptions.outputFormat == OUTPUT_PLAIN)
   1494         printf("  Direct methods    -\n");
   1495     for (i = 0; i < (int) pClassData->header.directMethodsSize; i++) {
   1496         dumpMethod(pDexFile, &pClassData->directMethods[i], i);
   1497     }
   1498 
   1499     if (gOptions.outputFormat == OUTPUT_PLAIN)
   1500         printf("  Virtual methods   -\n");
   1501     for (i = 0; i < (int) pClassData->header.virtualMethodsSize; i++) {
   1502         dumpMethod(pDexFile, &pClassData->virtualMethods[i], i);
   1503     }
   1504 
   1505     // TODO: Annotations.
   1506 
   1507     if (pClassDef->sourceFileIdx != kDexNoIndex)
   1508         fileName = dexStringById(pDexFile, pClassDef->sourceFileIdx);
   1509     else
   1510         fileName = "unknown";
   1511 
   1512     if (gOptions.outputFormat == OUTPUT_PLAIN) {
   1513         printf("  source_file_idx   : %d (%s)\n",
   1514             pClassDef->sourceFileIdx, fileName);
   1515         printf("\n");
   1516     }
   1517 
   1518     if (gOptions.outputFormat == OUTPUT_XML) {
   1519         printf("</class>\n");
   1520     }
   1521 
   1522 bail:
   1523     free(pClassData);
   1524     free(accessStr);
   1525 }
   1526 
   1527 
   1528 /*
   1529  * Advance "ptr" to ensure 32-bit alignment.
   1530  */
   1531 static inline const u1* align32(const u1* ptr)
   1532 {
   1533     return (u1*) (((int) ptr + 3) & ~0x03);
   1534 }
   1535 
   1536 
   1537 /*
   1538  * Dump a map in the "differential" format.
   1539  *
   1540  * TODO: show a hex dump of the compressed data.  (We can show the
   1541  * uncompressed data if we move the compression code to libdex; otherwise
   1542  * it's too complex to merit a fast & fragile implementation here.)
   1543  */
   1544 void dumpDifferentialCompressedMap(const u1** pData)
   1545 {
   1546     const u1* data = *pData;
   1547     const u1* dataStart = data -1;      // format byte already removed
   1548     u1 regWidth;
   1549     u2 numEntries;
   1550 
   1551     /* standard header */
   1552     regWidth = *data++;
   1553     numEntries = *data++;
   1554     numEntries |= (*data++) << 8;
   1555 
   1556     /* compressed data begins with the compressed data length */
   1557     int compressedLen = readUnsignedLeb128(&data);
   1558     int addrWidth = 1;
   1559     if ((*data & 0x80) != 0)
   1560         addrWidth++;
   1561 
   1562     int origLen = 4 + (addrWidth + regWidth) * numEntries;
   1563     int compLen = (data - dataStart) + compressedLen;
   1564 
   1565     printf("        (differential compression %d -> %d [%d -> %d])\n",
   1566         origLen, compLen,
   1567         (addrWidth + regWidth) * numEntries, compressedLen);
   1568 
   1569     /* skip past end of entry */
   1570     data += compressedLen;
   1571 
   1572     *pData = data;
   1573 }
   1574 
   1575 /*
   1576  * Dump register map contents of the current method.
   1577  *
   1578  * "*pData" should point to the start of the register map data.  Advances
   1579  * "*pData" to the start of the next map.
   1580  */
   1581 void dumpMethodMap(DexFile* pDexFile, const DexMethod* pDexMethod, int idx,
   1582     const u1** pData)
   1583 {
   1584     const u1* data = *pData;
   1585     const DexMethodId* pMethodId;
   1586     const char* name;
   1587     int offset = data - (u1*) pDexFile->pOptHeader;
   1588 
   1589     pMethodId = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
   1590     name = dexStringById(pDexFile, pMethodId->nameIdx);
   1591     printf("      #%d: 0x%08x %s\n", idx, offset, name);
   1592 
   1593     u1 format;
   1594     int addrWidth;
   1595 
   1596     format = *data++;
   1597     if (format == 1) {              /* kRegMapFormatNone */
   1598         /* no map */
   1599         printf("        (no map)\n");
   1600         addrWidth = 0;
   1601     } else if (format == 2) {       /* kRegMapFormatCompact8 */
   1602         addrWidth = 1;
   1603     } else if (format == 3) {       /* kRegMapFormatCompact16 */
   1604         addrWidth = 2;
   1605     } else if (format == 4) {       /* kRegMapFormatDifferential */
   1606         dumpDifferentialCompressedMap(&data);
   1607         goto bail;
   1608     } else {
   1609         printf("        (unknown format %d!)\n", format);
   1610         /* don't know how to skip data; failure will cascade to end of class */
   1611         goto bail;
   1612     }
   1613 
   1614     if (addrWidth > 0) {
   1615         u1 regWidth;
   1616         u2 numEntries;
   1617         int idx, addr, byte;
   1618 
   1619         regWidth = *data++;
   1620         numEntries = *data++;
   1621         numEntries |= (*data++) << 8;
   1622 
   1623         for (idx = 0; idx < numEntries; idx++) {
   1624             addr = *data++;
   1625             if (addrWidth > 1)
   1626                 addr |= (*data++) << 8;
   1627 
   1628             printf("        %4x:", addr);
   1629             for (byte = 0; byte < regWidth; byte++) {
   1630                 printf(" %02x", *data++);
   1631             }
   1632             printf("\n");
   1633         }
   1634     }
   1635 
   1636 bail:
   1637     //if (addrWidth >= 0)
   1638     //    *pData = align32(data);
   1639     *pData = data;
   1640 }
   1641 
   1642 /*
   1643  * Dump the contents of the register map area.
   1644  *
   1645  * These are only present in optimized DEX files, and the structure is
   1646  * not really exposed to other parts of the VM itself.  We're going to
   1647  * dig through them here, but this is pretty fragile.  DO NOT rely on
   1648  * this or derive other code from it.
   1649  */
   1650 void dumpRegisterMaps(DexFile* pDexFile)
   1651 {
   1652     const u1* pClassPool = (const u1*)pDexFile->pRegisterMapPool;
   1653     const u4* classOffsets;
   1654     const u1* ptr;
   1655     u4 numClasses;
   1656     int baseFileOffset = (u1*) pClassPool - (u1*) pDexFile->pOptHeader;
   1657     int idx;
   1658 
   1659     if (pClassPool == NULL) {
   1660         printf("No register maps found\n");
   1661         return;
   1662     }
   1663 
   1664     ptr = pClassPool;
   1665     numClasses = get4LE(ptr);
   1666     ptr += sizeof(u4);
   1667     classOffsets = (const u4*) ptr;
   1668 
   1669     printf("RMAP begins at offset 0x%07x\n", baseFileOffset);
   1670     printf("Maps for %d classes\n", numClasses);
   1671     for (idx = 0; idx < (int) numClasses; idx++) {
   1672         const DexClassDef* pClassDef;
   1673         const char* classDescriptor;
   1674 
   1675         pClassDef = dexGetClassDef(pDexFile, idx);
   1676         classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
   1677 
   1678         printf("%4d: +%d (0x%08x) %s\n", idx, classOffsets[idx],
   1679             baseFileOffset + classOffsets[idx], classDescriptor);
   1680 
   1681         if (classOffsets[idx] == 0)
   1682             continue;
   1683 
   1684         /*
   1685          * What follows is a series of RegisterMap entries, one for every
   1686          * direct method, then one for every virtual method.
   1687          */
   1688         DexClassData* pClassData;
   1689         const u1* pEncodedData;
   1690         const u1* data = (u1*) pClassPool + classOffsets[idx];
   1691         u2 methodCount;
   1692         int i;
   1693 
   1694         pEncodedData = dexGetClassData(pDexFile, pClassDef);
   1695         pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL);
   1696         if (pClassData == NULL) {
   1697             fprintf(stderr, "Trouble reading class data\n");
   1698             continue;
   1699         }
   1700 
   1701         methodCount = *data++;
   1702         methodCount |= (*data++) << 8;
   1703         data += 2;      /* two pad bytes follow methodCount */
   1704         if (methodCount != pClassData->header.directMethodsSize
   1705                             + pClassData->header.virtualMethodsSize)
   1706         {
   1707             printf("NOTE: method count discrepancy (%d != %d + %d)\n",
   1708                 methodCount, pClassData->header.directMethodsSize,
   1709                 pClassData->header.virtualMethodsSize);
   1710             /* this is bad, but keep going anyway */
   1711         }
   1712 
   1713         printf("    direct methods: %d\n",
   1714             pClassData->header.directMethodsSize);
   1715         for (i = 0; i < (int) pClassData->header.directMethodsSize; i++) {
   1716             dumpMethodMap(pDexFile, &pClassData->directMethods[i], i, &data);
   1717         }
   1718 
   1719         printf("    virtual methods: %d\n",
   1720             pClassData->header.virtualMethodsSize);
   1721         for (i = 0; i < (int) pClassData->header.virtualMethodsSize; i++) {
   1722             dumpMethodMap(pDexFile, &pClassData->virtualMethods[i], i, &data);
   1723         }
   1724 
   1725         free(pClassData);
   1726     }
   1727 }
   1728 
   1729 /*
   1730  * Dump the requested sections of the file.
   1731  */
   1732 void processDexFile(const char* fileName, DexFile* pDexFile)
   1733 {
   1734     char* package = NULL;
   1735     int i;
   1736 
   1737     if (gOptions.verbose) {
   1738         printf("Opened '%s', DEX version '%.3s'\n", fileName,
   1739             pDexFile->pHeader->magic +4);
   1740     }
   1741 
   1742     if (gOptions.dumpRegisterMaps) {
   1743         dumpRegisterMaps(pDexFile);
   1744         return;
   1745     }
   1746 
   1747     if (gOptions.showFileHeaders) {
   1748         dumpFileHeader(pDexFile);
   1749         dumpOptDirectory(pDexFile);
   1750     }
   1751 
   1752     if (gOptions.outputFormat == OUTPUT_XML)
   1753         printf("<api>\n");
   1754 
   1755     for (i = 0; i < (int) pDexFile->pHeader->classDefsSize; i++) {
   1756         if (gOptions.showSectionHeaders)
   1757             dumpClassDef(pDexFile, i);
   1758 
   1759         dumpClass(pDexFile, i, &package);
   1760     }
   1761 
   1762     /* free the last one allocated */
   1763     if (package != NULL) {
   1764         printf("</package>\n");
   1765         free(package);
   1766     }
   1767 
   1768     if (gOptions.outputFormat == OUTPUT_XML)
   1769         printf("</api>\n");
   1770 }
   1771 
   1772 
   1773 /*
   1774  * Process one file.
   1775  */
   1776 int process(const char* fileName)
   1777 {
   1778     DexFile* pDexFile = NULL;
   1779     MemMapping map;
   1780     bool mapped = false;
   1781     int result = -1;
   1782 
   1783     if (gOptions.verbose)
   1784         printf("Processing '%s'...\n", fileName);
   1785 
   1786     if (dexOpenAndMap(fileName, gOptions.tempFileName, &map, false) != 0) {
   1787         return result;
   1788     }
   1789     mapped = true;
   1790 
   1791     int flags = kDexParseVerifyChecksum;
   1792     if (gOptions.ignoreBadChecksum)
   1793         flags |= kDexParseContinueOnError;
   1794 
   1795     pDexFile = dexFileParse((u1*)map.addr, map.length, flags);
   1796     if (pDexFile == NULL) {
   1797         fprintf(stderr, "ERROR: DEX parse failed\n");
   1798         goto bail;
   1799     }
   1800 
   1801     if (gOptions.checksumOnly) {
   1802         printf("Checksum verified\n");
   1803     } else {
   1804         processDexFile(fileName, pDexFile);
   1805     }
   1806 
   1807     result = 0;
   1808 
   1809 bail:
   1810     if (mapped)
   1811         sysReleaseShmem(&map);
   1812     if (pDexFile != NULL)
   1813         dexFileFree(pDexFile);
   1814     return result;
   1815 }
   1816 
   1817 
   1818 /*
   1819  * Show usage.
   1820  */
   1821 void usage(void)
   1822 {
   1823     fprintf(stderr, "Copyright (C) 2007 The Android Open Source Project\n\n");
   1824     fprintf(stderr,
   1825         "%s: [-c] [-d] [-f] [-h] [-i] [-l layout] [-m] [-t tempfile] dexfile...\n",
   1826         gProgName);
   1827     fprintf(stderr, "\n");
   1828     fprintf(stderr, " -c : verify checksum and exit\n");
   1829     fprintf(stderr, " -d : disassemble code sections\n");
   1830     fprintf(stderr, " -f : display summary information from file header\n");
   1831     fprintf(stderr, " -h : display file header details\n");
   1832     fprintf(stderr, " -i : ignore checksum failures\n");
   1833     fprintf(stderr, " -l : output layout, either 'plain' or 'xml'\n");
   1834     fprintf(stderr, " -m : dump register maps (and nothing else)\n");
   1835     fprintf(stderr, " -t : temp file name (defaults to /sdcard/dex-temp-*)\n");
   1836 }
   1837 
   1838 /*
   1839  * Parse args.
   1840  *
   1841  * I'm not using getopt_long() because we may not have it in libc.
   1842  */
   1843 int main(int argc, char* const argv[])
   1844 {
   1845     bool wantUsage = false;
   1846     int ic;
   1847 
   1848     memset(&gOptions, 0, sizeof(gOptions));
   1849     gOptions.verbose = true;
   1850 
   1851     while (1) {
   1852         ic = getopt(argc, argv, "cdfhil:mt:");
   1853         if (ic < 0)
   1854             break;
   1855 
   1856         switch (ic) {
   1857         case 'c':       // verify the checksum then exit
   1858             gOptions.checksumOnly = true;
   1859             break;
   1860         case 'd':       // disassemble Dalvik instructions
   1861             gOptions.disassemble = true;
   1862             break;
   1863         case 'f':       // dump outer file header
   1864             gOptions.showFileHeaders = true;
   1865             break;
   1866         case 'h':       // dump section headers, i.e. all meta-data
   1867             gOptions.showSectionHeaders = true;
   1868             break;
   1869         case 'i':       // continue even if checksum is bad
   1870             gOptions.ignoreBadChecksum = true;
   1871             break;
   1872         case 'l':       // layout
   1873             if (strcmp(optarg, "plain") == 0) {
   1874                 gOptions.outputFormat = OUTPUT_PLAIN;
   1875             } else if (strcmp(optarg, "xml") == 0) {
   1876                 gOptions.outputFormat = OUTPUT_XML;
   1877                 gOptions.verbose = false;
   1878                 gOptions.exportsOnly = true;
   1879             } else {
   1880                 wantUsage = true;
   1881             }
   1882             break;
   1883         case 'm':       // dump register maps only
   1884             gOptions.dumpRegisterMaps = true;
   1885             break;
   1886         case 't':       // temp file, used when opening compressed Jar
   1887             gOptions.tempFileName = optarg;
   1888             break;
   1889         default:
   1890             wantUsage = true;
   1891             break;
   1892         }
   1893     }
   1894 
   1895     if (optind == argc) {
   1896         fprintf(stderr, "%s: no file specified\n", gProgName);
   1897         wantUsage = true;
   1898     }
   1899 
   1900     if (gOptions.checksumOnly && gOptions.ignoreBadChecksum) {
   1901         fprintf(stderr, "Can't specify both -c and -i\n");
   1902         wantUsage = true;
   1903     }
   1904 
   1905     if (wantUsage) {
   1906         usage();
   1907         return 2;
   1908     }
   1909 
   1910     int result = 0;
   1911     while (optind < argc) {
   1912         result |= process(argv[optind++]);
   1913     }
   1914 
   1915     return (result != 0);
   1916 }
   1917