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