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