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[]".  Also converts '$' to '.', which means this
132  * form can't be converted back to a descriptor.
133  */
descriptorToDot(const char * str)134 static 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  */
descriptorClassToDot(const char * str)189 static 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  */
quotedBool(bool val)215 static const char* quotedBool(bool val)
216 {
217     if (val)
218         return "\"true\"";
219     else
220         return "\"false\"";
221 }
222 
quotedVisibility(u4 accessFlags)223 static 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  */
countOnes(u4 val)238 static 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  */
252 enum 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  */
createAccessFlagStr(u4 flags,AccessFor forWhat)263 static 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  */
asciify(char * out,const unsigned char * data,size_t len)369 static 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  */
dumpFileHeader(const DexFile * pDexFile)400 void 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  */
dumpOptDirectory(const DexFile * pDexFile)467 void 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  */
dumpClassDef(DexFile * pDexFile,int idx)516 void 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  */
dumpInterface(const DexFile * pDexFile,const DexTypeItem * pTypeItem,int i)557 void 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  */
dumpCatches(DexFile * pDexFile,const DexCode * pCode)575 void 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 
dumpPositionsCb(void *,u4 address,u4 lineNum)616 static 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  */
dumpPositions(DexFile * pDexFile,const DexCode * pCode,const DexMethod * pDexMethod)625 void 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 
dumpLocalsCb(void *,u2 reg,u4 startAddress,u4 endAddress,const char * name,const char * descriptor,const char * signature)638 static 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  */
dumpLocals(DexFile * pDexFile,const DexCode * pCode,const DexMethod * pDexMethod)650 void 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  */
getMethodInfo(DexFile * pDexFile,u4 methodIdx,FieldMethodInfo * pMethInfo)667 bool 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  */
getFieldInfo(DexFile * pDexFile,u4 fieldIdx,FieldMethodInfo * pFieldInfo)686 bool 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  */
getProtoInfo(DexFile * pDexFile,u4 protoIdx,ProtoInfo * pProtoInfo)704 bool 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  */
getClassDescriptor(DexFile * pDexFile,u4 classIdx)762 const 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  */
indexString(DexFile * pDexFile,const DecodedInstruction * pDecInsn,size_t bufSize)776 static 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  */
dumpInstruction(DexFile * pDexFile,const DexCode * pCode,int insnIdx,int insnWidth,const DecodedInstruction * pDecInsn)942 void 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  */
dumpBytecodes(DexFile * pDexFile,const DexMethod * pDexMethod)1170 void 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  */
dumpCode(DexFile * pDexFile,const DexMethod * pDexMethod)1243 void 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  */
dumpMethod(DexFile * pDexFile,const DexMethod * pDexMethod,int i)1264 void 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 
1399 bail:
1400     free(typeDescriptor);
1401     free(accessStr);
1402 }
1403 
1404 /*
1405  * Dump a static (class) field.
1406  */
dumpSField(const DexFile * pDexFile,const DexField * pSField,int i)1407 void 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  */
dumpIField(const DexFile * pDexFile,const DexField * pIField,int i)1464 void 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  */
dumpClass(DexFile * pDexFile,int idx,char ** pLastPackage)1477 void 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 
1641 bail:
1642     free(pClassData);
1643     free(accessStr);
1644 }
1645 
1646 
1647 /*
1648  * Advance "ptr" to ensure 32-bit alignment.
1649  */
align32(const u1 * ptr)1650 static 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  */
dumpDifferentialCompressedMap(const u1 ** pData)1663 void 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  */
dumpMethodMap(DexFile * pDexFile,const DexMethod * pDexMethod,int idx,const u1 ** pData)1700 void 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 
1755 bail:
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  */
dumpRegisterMaps(DexFile * pDexFile)1769 void 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 
findMapItem(const DexFile * pDexFile,u4 type)1848 static 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 
dumpMethodHandles(DexFile * pDexFile)1860 static 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         bool is_invoke = false;
1869         const char* type;
1870         switch (mh.methodHandleType) {
1871             case 0:
1872                 type = "put-static";
1873                 break;
1874             case 1:
1875                 type = "get-static";
1876                 break;
1877             case 2:
1878                 type = "put-instance";
1879                 break;
1880             case 3:
1881                 type = "get-instance";
1882                 break;
1883             case 4:
1884                 type = "invoke-static";
1885                 is_invoke = true;
1886                 break;
1887             case 5:
1888                 type = "invoke-instance";
1889                 is_invoke = true;
1890                 break;
1891             case 6:
1892                 type = "invoke-constructor";
1893                 is_invoke = true;
1894                 break;
1895         }
1896 
1897         FieldMethodInfo info;
1898         memset(&info, 0, sizeof(info));
1899         if (is_invoke) {
1900             getMethodInfo(pDexFile, mh.fieldOrMethodIdx, &info);
1901         } else {
1902             getFieldInfo(pDexFile, mh.fieldOrMethodIdx, &info);
1903         }
1904 
1905         if (gOptions.outputFormat == OUTPUT_XML) {
1906             printf("<method_handle index index=\"%u\"\n", i);
1907             printf(" type=\"%s\"\n", type);
1908             printf(" target_class=\"%s\"\n", info.classDescriptor);
1909             printf(" target_member=\"%s\"\n", info.name);
1910             printf(" target_member_type=\"%s\"\n", info.signature);
1911             printf("</method_handle>\n");
1912         } else {
1913             printf("Method Handle #%u:\n", i);
1914             printf("  type        : %s\n", type);
1915             printf("  target      : %s %s\n", info.classDescriptor, info.name);
1916             printf("  target_type : %s\n", info.signature);
1917         }
1918     }
1919 }
1920 
1921 /* Helper for dumpCallSites(), which reads a 1- to 8- byte signed
1922  * little endian value. */
readSignedLittleEndian(const u1 ** pData,u4 size)1923 static u8 readSignedLittleEndian(const u1** pData, u4 size) {
1924     const u1* data = *pData;
1925     u8 result = 0;
1926     u4 i;
1927 
1928     for (i = 0; i < size; i++) {
1929         result = (result >> 8) | (((int64_t)*data++) << 56);
1930     }
1931 
1932     result >>= (8 - size) * 8;
1933     *pData = data;
1934     return result;
1935 }
1936 
1937 /* Helper for dumpCallSites(), which reads a 1- to 8- byte unsigned
1938  * little endian value. */
readUnsignedLittleEndian(const u1 ** pData,u4 size,bool fillOnRight=false)1939 static u8 readUnsignedLittleEndian(const u1** pData, u4 size, bool fillOnRight = false) {
1940     const u1* data = *pData;
1941     u8 result = 0;
1942     u4 i;
1943 
1944     for (i = 0; i < size; i++) {
1945         result = (result >> 8) | (((u8)*data++) << 56);
1946     }
1947 
1948     u8 oldResult = result;
1949     if (!fillOnRight) {
1950         result >>= (8u - size) * 8;
1951     }
1952 
1953     *pData = data;
1954     return result;
1955 }
1956 
dumpCallSites(DexFile * pDexFile)1957 static void dumpCallSites(DexFile* pDexFile)
1958 {
1959     const DexMapItem* item = findMapItem(pDexFile, kDexTypeCallSiteIdItem);
1960     if (item == nullptr) return;
1961     const DexCallSiteId* ids = (const DexCallSiteId*)(pDexFile->baseAddr + item->offset);
1962     for (u4 index = 0; index < item->size; ++index) {
1963         bool doXml = (gOptions.outputFormat == OUTPUT_XML);
1964         printf(doXml ? "<call_site index=\"%u\">\n" : "Call Site #%u\n", index);
1965         const u1* data = pDexFile->baseAddr + ids[index].callSiteOff;
1966         u4 count = readUnsignedLeb128(&data);
1967         for (u4 i = 0; i < count; ++i) {
1968             printf(doXml ? "<link_argument index=\"%u\" " : "  link_argument[%u] : ", i);
1969             u1 headerByte = *data++;
1970             u4 valueType = headerByte & kDexAnnotationValueTypeMask;
1971             u4 valueArg = headerByte >> kDexAnnotationValueArgShift;
1972             switch (valueType) {
1973                 case kDexAnnotationByte: {
1974                     printf(doXml ? "type=\"byte\" value=\"%d\"/>" : "%d (byte)", (int)*data++);
1975                     break;
1976                 }
1977                 case kDexAnnotationShort: {
1978                     printf(doXml ? "type=\"short\" value=\"%d\"/>" : "%d (short)",
1979                            (int) readSignedLittleEndian(&data, valueArg + 1));
1980                     break;
1981                 }
1982                 case kDexAnnotationChar: {
1983                     printf(doXml ? "type=\"short\" value=\"%u\"/>" : "%u (char)",
1984                            (u2) readUnsignedLittleEndian(&data, valueArg + 1));
1985                     break;
1986                 }
1987                 case kDexAnnotationInt: {
1988                     printf(doXml ? "type=\"int\" value=\"%d\"/>" : "%d (int)",
1989                            (int) readSignedLittleEndian(&data, valueArg + 1));
1990                     break;
1991                 }
1992                 case kDexAnnotationLong: {
1993                     printf(doXml ? "type=\"long\" value=\"%" PRId64 "\"/>" : "%" PRId64 " (long)",
1994                            (int64_t) readSignedLittleEndian(&data, valueArg + 1));
1995                     break;
1996                 }
1997                 case kDexAnnotationFloat: {
1998                     u4 rawValue = (u4) (readUnsignedLittleEndian(&data, valueArg + 1, true) >> 32);
1999                     printf(doXml ? "type=\"float\" value=\"%g\"/>" : "%g (float)",
2000                            *((float*) &rawValue));
2001                     break;
2002                 }
2003                 case kDexAnnotationDouble: {
2004                     u8 rawValue = readUnsignedLittleEndian(&data, valueArg + 1, true);
2005                     printf(doXml ? "type=\"double\" value=\"%g\"/>" : "%g (double)",
2006                            *((double*) &rawValue));
2007                     break;
2008                 }
2009                 case kDexAnnotationMethodType: {
2010                     u4 idx = (u4) readUnsignedLittleEndian(&data, valueArg + 1);
2011                     ProtoInfo protoInfo;
2012                     memset(&protoInfo, 0, sizeof(protoInfo));
2013                     getProtoInfo(pDexFile, idx, &protoInfo);
2014                     printf(doXml ? "type=\"MethodType\" value=\"(%s)%s\"/>" : "(%s)%s (MethodType)",
2015                            protoInfo.parameterTypes, protoInfo.returnType);
2016                     free(protoInfo.parameterTypes);
2017                     break;
2018                 }
2019                 case kDexAnnotationMethodHandle: {
2020                     u4 idx = (u4) readUnsignedLittleEndian(&data, valueArg + 1);
2021                     printf(doXml ? "type=\"MethodHandle\" value=\"%u\"/>" : "%u (MethodHandle)",
2022                            idx);
2023                     break;
2024                 }
2025                 case kDexAnnotationString: {
2026                     u4 idx = (u4) readUnsignedLittleEndian(&data, valueArg + 1);
2027                     printf(doXml ? "type=\"String\" value=\"%s\"/>" : "%s (String)",
2028                            dexStringById(pDexFile, idx));
2029                     break;
2030                 }
2031                 case kDexAnnotationType: {
2032                     u4 idx = (u4) readUnsignedLittleEndian(&data, valueArg + 1);
2033                     printf(doXml ? "type=\"Class\" value=\"%s\"/>" : "%s (Class)",
2034                            dexStringByTypeIdx(pDexFile, idx));
2035                     break;
2036                 }
2037                 case kDexAnnotationNull: {
2038                     printf(doXml ? "type=\"null\" value=\"null\"/>" : "null (null)");
2039                     break;
2040                 }
2041                 case kDexAnnotationBoolean: {
2042                     printf(doXml ? "type=\"boolean\" value=\"%s\"/>" : "%s (boolean)",
2043                            (valueArg & 1) == 0 ? "false" : "true");
2044                     break;
2045                 }
2046                 default:
2047                     // Other types are not anticipated being reached here.
2048                     printf("Unexpected type found, bailing on call site info.\n");
2049                     i = count;
2050                     break;
2051             }
2052             printf("\n");
2053         }
2054 
2055         if (doXml) {
2056             printf("</callsite>\n");
2057         }
2058     }
2059 }
2060 
2061 /*
2062  * Dump the requested sections of the file.
2063  */
processDexFile(const char * fileName,DexFile * pDexFile)2064 void processDexFile(const char* fileName, DexFile* pDexFile)
2065 {
2066     char* package = NULL;
2067     int i;
2068 
2069     if (gOptions.verbose) {
2070         printf("Opened '%s', DEX version '%.3s'\n", fileName,
2071             pDexFile->pHeader->magic +4);
2072     }
2073 
2074     if (gOptions.dumpRegisterMaps) {
2075         dumpRegisterMaps(pDexFile);
2076         return;
2077     }
2078 
2079     if (gOptions.showFileHeaders) {
2080         dumpFileHeader(pDexFile);
2081         dumpOptDirectory(pDexFile);
2082     }
2083 
2084     if (gOptions.outputFormat == OUTPUT_XML)
2085         printf("<api>\n");
2086 
2087     for (i = 0; i < (int) pDexFile->pHeader->classDefsSize; i++) {
2088         if (gOptions.showSectionHeaders)
2089             dumpClassDef(pDexFile, i);
2090 
2091         dumpClass(pDexFile, i, &package);
2092     }
2093 
2094     dumpMethodHandles(pDexFile);
2095     dumpCallSites(pDexFile);
2096 
2097     /* free the last one allocated */
2098     if (package != NULL) {
2099         printf("</package>\n");
2100         free(package);
2101     }
2102 
2103     if (gOptions.outputFormat == OUTPUT_XML)
2104         printf("</api>\n");
2105 }
2106 
2107 
2108 /*
2109  * Process one file.
2110  */
process(const char * fileName)2111 int process(const char* fileName)
2112 {
2113     DexFile* pDexFile = NULL;
2114     MemMapping map;
2115     bool mapped = false;
2116     int result = -1;
2117 
2118     if (gOptions.verbose)
2119         printf("Processing '%s'...\n", fileName);
2120 
2121     if (dexOpenAndMap(fileName, gOptions.tempFileName, &map, false) != 0) {
2122         return result;
2123     }
2124     mapped = true;
2125 
2126     int flags = kDexParseVerifyChecksum;
2127     if (gOptions.ignoreBadChecksum)
2128         flags |= kDexParseContinueOnError;
2129 
2130     pDexFile = dexFileParse((u1*)map.addr, map.length, flags);
2131     if (pDexFile == NULL) {
2132         fprintf(stderr, "ERROR: DEX parse failed\n");
2133         goto bail;
2134     }
2135 
2136     if (gOptions.checksumOnly) {
2137         printf("Checksum verified\n");
2138     } else {
2139         processDexFile(fileName, pDexFile);
2140     }
2141 
2142     result = 0;
2143 
2144 bail:
2145     if (mapped)
2146         sysReleaseShmem(&map);
2147     if (pDexFile != NULL)
2148         dexFileFree(pDexFile);
2149     return result;
2150 }
2151 
2152 
2153 /*
2154  * Show usage.
2155  */
usage(void)2156 void usage(void)
2157 {
2158     fprintf(stderr, "Copyright (C) 2007 The Android Open Source Project\n\n");
2159     fprintf(stderr,
2160         "%s: [-c] [-d] [-f] [-h] [-i] [-l layout] [-m] [-t tempfile] dexfile...\n",
2161         gProgName);
2162     fprintf(stderr, "\n");
2163     fprintf(stderr, " -c : verify checksum and exit\n");
2164     fprintf(stderr, " -d : disassemble code sections\n");
2165     fprintf(stderr, " -f : display summary information from file header\n");
2166     fprintf(stderr, " -h : display file header details\n");
2167     fprintf(stderr, " -i : ignore checksum failures\n");
2168     fprintf(stderr, " -l : output layout, either 'plain' or 'xml'\n");
2169     fprintf(stderr, " -m : dump register maps (and nothing else)\n");
2170     fprintf(stderr, " -t : temp file name (defaults to /sdcard/dex-temp-*)\n");
2171 }
2172 
2173 /*
2174  * Parse args.
2175  *
2176  * I'm not using getopt_long() because we may not have it in libc.
2177  */
main(int argc,char * const argv[])2178 int main(int argc, char* const argv[])
2179 {
2180     bool wantUsage = false;
2181     int ic;
2182 
2183     memset(&gOptions, 0, sizeof(gOptions));
2184     gOptions.verbose = true;
2185 
2186     while (1) {
2187         ic = getopt(argc, argv, "cdfhil:mt:");
2188         if (ic < 0)
2189             break;
2190 
2191         switch (ic) {
2192         case 'c':       // verify the checksum then exit
2193             gOptions.checksumOnly = true;
2194             break;
2195         case 'd':       // disassemble Dalvik instructions
2196             gOptions.disassemble = true;
2197             break;
2198         case 'f':       // dump outer file header
2199             gOptions.showFileHeaders = true;
2200             break;
2201         case 'h':       // dump section headers, i.e. all meta-data
2202             gOptions.showSectionHeaders = true;
2203             break;
2204         case 'i':       // continue even if checksum is bad
2205             gOptions.ignoreBadChecksum = true;
2206             break;
2207         case 'l':       // layout
2208             if (strcmp(optarg, "plain") == 0) {
2209                 gOptions.outputFormat = OUTPUT_PLAIN;
2210             } else if (strcmp(optarg, "xml") == 0) {
2211                 gOptions.outputFormat = OUTPUT_XML;
2212                 gOptions.verbose = false;
2213                 gOptions.exportsOnly = true;
2214             } else {
2215                 wantUsage = true;
2216             }
2217             break;
2218         case 'm':       // dump register maps only
2219             gOptions.dumpRegisterMaps = true;
2220             break;
2221         case 't':       // temp file, used when opening compressed Jar
2222             gOptions.tempFileName = optarg;
2223             break;
2224         default:
2225             wantUsage = true;
2226             break;
2227         }
2228     }
2229 
2230     if (optind == argc) {
2231         fprintf(stderr, "%s: no file specified\n", gProgName);
2232         wantUsage = true;
2233     }
2234 
2235     if (gOptions.checksumOnly && gOptions.ignoreBadChecksum) {
2236         fprintf(stderr, "Can't specify both -c and -i\n");
2237         wantUsage = true;
2238     }
2239 
2240     if (wantUsage) {
2241         usage();
2242         return 2;
2243     }
2244 
2245     int result = 0;
2246     while (optind < argc) {
2247         result |= process(argv[optind++]);
2248     }
2249 
2250     return (result != 0);
2251 }
2252