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
50static const char* gProgName = "dexdump";
51
52static InstructionWidth* gInstrWidth;
53static InstructionFormat* gInstrFormat;
54
55typedef enum OutputFormat {
56    OUTPUT_PLAIN = 0,               /* default */
57    OUTPUT_XML,                     /* fancy */
58} OutputFormat;
59
60/* command-line options */
61struct {
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 */
75typedef 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 */
84static 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 */
92static 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 */
101static 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 */
124static 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 */
179static 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 */
205static const char* quotedBool(bool val)
206{
207    if (val)
208        return "\"true\"";
209    else
210        return "\"false\"";
211}
212
213static 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 */
228static 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 */
242typedef 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 */
253static 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 */
359static 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 */
390void 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 */
454void 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 */
503void 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 */
544void 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 */
562void 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
603static 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 */
612void 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
625static 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 */
637void 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 */
654bool 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 */
673bool 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 */
692const char* getClassDescriptor(DexFile* pDexFile, u4 classIdx)
693{
694    return dexStringByTypeIdx(pDexFile, classIdx);
695}
696
697/*
698 * Dump a single instruction.
699 */
700void 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 */
1032void 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 */
1093void 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 */
1114void 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
1249bail:
1250    free(typeDescriptor);
1251    free(accessStr);
1252}
1253
1254/*
1255 * Dump a static (class) field.
1256 */
1257void 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 */
1314void 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 */
1327void 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
1491bail:
1492    free(pClassData);
1493    free(accessStr);
1494}
1495
1496
1497/*
1498 * Advance "ptr" to ensure 32-bit alignment.
1499 */
1500static 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 */
1513void 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 */
1550void 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
1605bail:
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 */
1619void 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 */
1701void 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 */
1745int 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
1777bail:
1778    if (mapped)
1779        sysReleaseShmem(&map);
1780    if (pDexFile != NULL)
1781        dexFileFree(pDexFile);
1782    return result;
1783}
1784
1785
1786/*
1787 * Show usage.
1788 */
1789void 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 */
1811int 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