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