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