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