OSDN Git Service

Merge change 944 into donut
[android-x86/dalvik.git] / dexdump / DexDump.c
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  * The "dexdump" tool is intended to mimic "objdump".  When possible, use
18  * similar command-line arguments.
19  *
20  * TODO: rework the output format to be more regexp-friendly
21  */
22 #include "libdex/DexFile.h"
23 #include "libdex/DexCatch.h"
24 #include "libdex/DexClass.h"
25 #include "libdex/DexProto.h"
26 #include "libdex/InstrUtils.h"
27 #include "libdex/SysUtil.h"
28 #include "libdex/CmdUtils.h"
29
30 #include "dexdump/OpCodeNames.h"
31
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <fcntl.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <getopt.h>
38 #include <errno.h>
39 #include <assert.h>
40
41 static const char* gProgName = "dexdump";
42
43 static InstructionWidth* gInstrWidth;
44 static InstructionFormat* gInstrFormat;
45
46 /* command-line options */
47 struct {
48     bool disassemble;
49     bool showFileHeaders;
50     bool showSectionHeaders;
51     const char* tempFileName;
52 } gOptions;
53
54 /* basic info about a field or method */
55 typedef struct FieldMethodInfo {
56     const char* classDescriptor;
57     const char* name;
58     const char* signature;
59 } FieldMethodInfo;
60
61 /*
62  * Get 2 little-endian bytes. 
63  */ 
64 static inline u2 get2LE(unsigned char const* pSrc)
65 {
66     return pSrc[0] | (pSrc[1] << 8);
67 }   
68
69 /*
70  * Return a newly-allocated string for the "dot version" of the class
71  * name for the given type descriptor. That is, The initial "L" and
72  * final ";" (if any) have been removed and all occurrences of '/'
73  * have been changed to '.'.
74  */
75 static char* descriptorToDot(const char* str)
76 {
77     size_t at = strlen(str);
78     char* newStr;
79
80     if (str[0] == 'L') {
81         assert(str[at - 1] == ';');
82         at -= 2; /* Two fewer chars to copy. */
83         str++; /* Skip the 'L'. */
84     }
85
86     newStr = malloc(at + 1); /* Add one for the '\0'. */
87     newStr[at] = '\0';
88
89     while (at > 0) {
90         at--;
91         newStr[at] = (str[at] == '/') ? '.' : str[at];
92     }
93
94     return newStr;
95 }
96
97 /*
98  * Count the number of '1' bits in a word.
99  *
100  * Having completed this, I'm ready for an interview at Google.
101  *
102  * TODO? there's a parallel version w/o loops.  Performance not currently
103  * important.
104  */
105 static int countOnes(u4 val)
106 {
107     int count = 0;
108
109     while (val != 0) {
110         val &= val-1;
111         count++;
112     }
113
114     return count;
115 }
116
117
118 /*
119  * Flag for use with createAccessFlagStr().
120  */
121 typedef enum AccessFor {
122     kAccessForClass = 0, kAccessForMethod = 1, kAccessForField = 2,
123     kAccessForMAX
124 } AccessFor;
125
126 /*
127  * Create a new string with human-readable access flags.
128  *
129  * In the base language the access_flags fields are type u2; in Dalvik
130  * they're u4.
131  */
132 static char* createAccessFlagStr(u4 flags, AccessFor forWhat)
133 {
134 #define NUM_FLAGS   18
135     static const char* kAccessStrings[kAccessForMAX][NUM_FLAGS] = {
136         {   
137             /* class, inner class */
138             "PUBLIC",           /* 0x0001 */
139             "PRIVATE",          /* 0x0002 */
140             "PROTECTED",        /* 0x0004 */
141             "STATIC",           /* 0x0008 */
142             "FINAL",            /* 0x0010 */
143             "?",                /* 0x0020 */
144             "?",                /* 0x0040 */
145             "?",                /* 0x0080 */
146             "?",                /* 0x0100 */
147             "INTERFACE",        /* 0x0200 */
148             "ABSTRACT",         /* 0x0400 */
149             "?",                /* 0x0800 */
150             "SYNTHETIC",        /* 0x1000 */
151             "ANNOTATION",       /* 0x2000 */
152             "ENUM",             /* 0x4000 */
153             "?",                /* 0x8000 */
154             "VERIFIED",         /* 0x10000 */
155             "OPTIMIZED",        /* 0x20000 */
156         },
157         {
158             /* method */
159             "PUBLIC",           /* 0x0001 */
160             "PRIVATE",          /* 0x0002 */
161             "PROTECTED",        /* 0x0004 */
162             "STATIC",           /* 0x0008 */
163             "FINAL",            /* 0x0010 */
164             "SYNCHRONIZED",     /* 0x0020 */
165             "BRIDGE",           /* 0x0040 */
166             "VARARGS",          /* 0x0080 */
167             "NATIVE",           /* 0x0100 */
168             "?",                /* 0x0200 */
169             "ABSTRACT",         /* 0x0400 */
170             "STRICT",           /* 0x0800 */
171             "SYNTHETIC",        /* 0x1000 */
172             "?",                /* 0x2000 */
173             "?",                /* 0x4000 */
174             "MIRANDA",          /* 0x8000 */
175             "CONSTRUCTOR",      /* 0x10000 */
176             "DECLARED_SYNCHRONIZED", /* 0x20000 */
177         },
178         {
179             /* field */
180             "PUBLIC",           /* 0x0001 */
181             "PRIVATE",          /* 0x0002 */
182             "PROTECTED",        /* 0x0004 */
183             "STATIC",           /* 0x0008 */
184             "FINAL",            /* 0x0010 */
185             "?",                /* 0x0020 */
186             "VOLATILE",         /* 0x0040 */
187             "TRANSIENT",        /* 0x0080 */
188             "?",                /* 0x0100 */
189             "?",                /* 0x0200 */
190             "?",                /* 0x0400 */
191             "?",                /* 0x0800 */
192             "SYNTHETIC",        /* 0x1000 */
193             "?",                /* 0x2000 */
194             "ENUM",             /* 0x4000 */
195             "?",                /* 0x8000 */
196             "?",                /* 0x10000 */
197             "?",                /* 0x20000 */
198         },
199     };
200     const int kLongest = 21;        /* strlen of longest string above */
201     int i, count;
202     char* str;
203     char* cp;
204
205     /*
206      * Allocate enough storage to hold the expected number of strings,
207      * plus a space between each.  We over-allocate, using the longest
208      * string above as the base metric.
209      */
210     count = countOnes(flags);
211     cp = str = (char*) malloc(count * (kLongest+1) +1);
212
213     for (i = 0; i < NUM_FLAGS; i++) {
214         if (flags & 0x01) {
215             const char* accessStr = kAccessStrings[forWhat][i];
216             int len = strlen(accessStr);
217             if (cp != str)
218                 *cp++ = ' ';
219
220             memcpy(cp, accessStr, len);
221             cp += len;
222         }
223         flags >>= 1;
224     }
225     *cp = '\0';
226
227     return str;
228 }
229
230
231 /*
232  * Dump the file header.
233  */
234 void dumpFileHeader(const DexFile* pDexFile)
235 {
236     const DexHeader* pHeader = pDexFile->pHeader;
237
238     printf("DEX file header:\n");
239     printf("magic               : '%.8s'\n", pHeader->magic);
240     printf("checksum            : %08x\n", pHeader->checksum);
241     printf("signature           : %02x%02x...%02x%02x\n",
242         pHeader->signature[0], pHeader->signature[1],
243         pHeader->signature[kSHA1DigestLen-2],
244         pHeader->signature[kSHA1DigestLen-1]);
245     printf("file_size           : %d\n", pHeader->fileSize);
246     printf("header_size         : %d\n", pHeader->headerSize);
247     printf("link_size           : %d\n", pHeader->linkSize);
248     printf("link_off            : %d (0x%06x)\n",
249         pHeader->linkOff, pHeader->linkOff);
250     printf("string_ids_size     : %d\n", pHeader->stringIdsSize);
251     printf("string_ids_off      : %d (0x%06x)\n",
252         pHeader->stringIdsOff, pHeader->stringIdsOff);
253     printf("type_ids_size       : %d\n", pHeader->typeIdsSize);
254     printf("type_ids_off        : %d (0x%06x)\n",
255         pHeader->typeIdsOff, pHeader->typeIdsOff);
256     printf("field_ids_size      : %d\n", pHeader->fieldIdsSize);
257     printf("field_ids_off       : %d (0x%06x)\n",
258         pHeader->fieldIdsOff, pHeader->fieldIdsOff);
259     printf("method_ids_size     : %d\n", pHeader->methodIdsSize);
260     printf("method_ids_off      : %d (0x%06x)\n",
261         pHeader->methodIdsOff, pHeader->methodIdsOff);
262     printf("class_defs_size     : %d\n", pHeader->classDefsSize);
263     printf("class_defs_off      : %d (0x%06x)\n",
264         pHeader->classDefsOff, pHeader->classDefsOff);
265     printf("data_size           : %d\n", pHeader->dataSize);
266     printf("data_off            : %d (0x%06x)\n",
267         pHeader->dataOff, pHeader->dataOff);
268     printf("\n");
269 }
270
271 /*
272  * Dump a class_def_item.
273  */
274 void dumpClassDef(DexFile* pDexFile, int idx)
275 {
276     const DexClassDef* pClassDef;
277     const u1* pEncodedData;
278     DexClassData* pClassData;
279
280     pClassDef = dexGetClassDef(pDexFile, idx);
281     pEncodedData = dexGetClassData(pDexFile, pClassDef);
282     pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL);
283
284     if (pClassData == NULL) {
285         fprintf(stderr, "Trouble reading class data\n");
286         return;
287     }
288
289     printf("Class #%d header:\n", idx);
290     printf("class_idx           : %d\n", pClassDef->classIdx);
291     printf("access_flags        : %d (0x%04x)\n",
292         pClassDef->accessFlags, pClassDef->accessFlags);
293     printf("superclass_idx      : %d\n", pClassDef->superclassIdx);
294     printf("interfaces_off      : %d (0x%06x)\n",
295         pClassDef->interfacesOff, pClassDef->interfacesOff);
296     printf("source_file_idx     : %d\n", pClassDef->sourceFileIdx);
297     printf("annotations_off     : %d (0x%06x)\n",
298         pClassDef->annotationsOff, pClassDef->annotationsOff);
299     printf("class_data_off      : %d (0x%06x)\n",
300         pClassDef->classDataOff, pClassDef->classDataOff);
301     printf("static_fields_size  : %d\n", pClassData->header.staticFieldsSize);
302     printf("instance_fields_size: %d\n",
303             pClassData->header.instanceFieldsSize);
304     printf("direct_methods_size : %d\n", pClassData->header.directMethodsSize);
305     printf("virtual_methods_size: %d\n",
306             pClassData->header.virtualMethodsSize);
307     printf("\n");
308
309     free(pClassData);
310 }
311
312 /*
313  * Dump an interface.
314  */
315 void dumpInterface(const DexFile* pDexFile, const DexTypeItem* pTypeItem,
316     int i)
317 {
318     const char* interfaceName =
319         dexStringByTypeIdx(pDexFile, pTypeItem->typeIdx);
320
321     printf("    #%d              : '%s'\n", i, interfaceName);
322 }
323
324 /*
325  * Dump the catches table associated with the code.
326  */
327 void dumpCatches(DexFile* pDexFile, const DexCode* pCode)
328 {
329     u4 triesSize = pCode->triesSize;
330
331     if (triesSize == 0) {
332         printf("      catches       : (none)\n");
333         return;
334     } 
335
336     printf("      catches       : %d\n", triesSize);
337
338     const DexTry* pTries = dexGetTries(pCode);
339     u4 i;
340
341     for (i = 0; i < triesSize; i++) {
342         const DexTry* pTry = &pTries[i];
343         u4 start = pTry->startAddr;
344         u4 end = start + pTry->insnCount;
345         DexCatchIterator iterator;
346         
347         printf("        0x%04x - 0x%04x\n", start, end);
348
349         dexCatchIteratorInit(&iterator, pCode, pTry->handlerOff);
350
351         for (;;) {
352             DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
353             const char* descriptor;
354             
355             if (handler == NULL) {
356                 break;
357             }
358             
359             descriptor = (handler->typeIdx == kDexNoIndex) ? "<any>" : 
360                 dexStringByTypeIdx(pDexFile, handler->typeIdx);
361             
362             printf("          %s -> 0x%04x\n", descriptor,
363                     handler->address);
364         }
365     }
366 }
367
368 static int dumpPositionsCb(void *cnxt, u4 address, u4 lineNum)
369 {
370     printf("        0x%04x line=%d\n", address, lineNum);
371     return 0;
372 }
373
374 /*
375  * Dump the positions list.
376  */
377 void dumpPositions(DexFile* pDexFile, const DexCode* pCode, 
378         const DexMethod *pDexMethod)
379 {
380     printf("      positions     : \n");
381     const DexMethodId *pMethodId 
382             = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
383     const char *classDescriptor
384             = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
385
386     dexDecodeDebugInfo(pDexFile, pCode, classDescriptor, pMethodId->protoIdx,
387             pDexMethod->accessFlags, dumpPositionsCb, NULL, NULL);
388 }
389
390 static void dumpLocalsCb(void *cnxt, u2 reg, u4 startAddress,
391         u4 endAddress, const char *name, const char *descriptor,
392         const char *signature)
393 {
394     printf("        0x%04x - 0x%04x reg=%d %s %s %s\n",
395             startAddress, endAddress, reg, name, descriptor, 
396             signature);
397 }
398
399 /*
400  * Dump the locals list.
401  */
402 void dumpLocals(DexFile* pDexFile, const DexCode* pCode,
403         const DexMethod *pDexMethod)
404 {
405     printf("      locals        : \n");
406
407     const DexMethodId *pMethodId 
408             = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
409     const char *classDescriptor 
410             = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
411
412     dexDecodeDebugInfo(pDexFile, pCode, classDescriptor, pMethodId->protoIdx,
413             pDexMethod->accessFlags, NULL, dumpLocalsCb, NULL);
414 }
415
416 /*
417  * Get information about a method.
418  */
419 bool getMethodInfo(DexFile* pDexFile, u4 methodIdx, FieldMethodInfo* pMethInfo)
420 {
421     const DexMethodId* pMethodId;
422
423     if (methodIdx >= pDexFile->pHeader->methodIdsSize)
424         return false;
425
426     pMethodId = dexGetMethodId(pDexFile, methodIdx);
427     pMethInfo->name = dexStringById(pDexFile, pMethodId->nameIdx);
428     pMethInfo->signature = dexCopyDescriptorFromMethodId(pDexFile, pMethodId);
429
430     pMethInfo->classDescriptor = 
431             dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
432     return true;
433 }
434
435 /*
436  * Get information about a field.
437  */
438 bool getFieldInfo(DexFile* pDexFile, u4 fieldIdx, FieldMethodInfo* pFieldInfo)
439 {
440     const DexFieldId* pFieldId;
441
442     if (fieldIdx >= pDexFile->pHeader->fieldIdsSize)
443         return false;
444
445     pFieldId = dexGetFieldId(pDexFile, fieldIdx);
446     pFieldInfo->name = dexStringById(pDexFile, pFieldId->nameIdx);
447     pFieldInfo->signature = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx);
448     pFieldInfo->classDescriptor =
449         dexStringByTypeIdx(pDexFile, pFieldId->classIdx);
450     return true;
451 }
452
453
454 /*
455  * Look up a class' descriptor.
456  */
457 const char* getClassDescriptor(DexFile* pDexFile, u4 classIdx)
458 {
459     return dexStringByTypeIdx(pDexFile, classIdx);
460 }
461
462 /*
463  * Dump a single instruction.
464  */
465 void dumpInstruction(DexFile* pDexFile, const DexCode* pCode, int insnIdx,
466     int insnWidth, const DecodedInstruction* pDecInsn)
467 {
468     static const float gSpecialTab[16] = {
469         -2.0f, -1.0f, -0.5f, -0.25f, -0.1f, 0.1f, 0.25f, 0.5f,
470         1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 10.0f, 100.0f, 1000.0f
471     };
472     const u2* insns = pCode->insns;
473     int i;
474
475     printf("%06x:", ((u1*)insns - pDexFile->baseAddr) + insnIdx*2);
476     for (i = 0; i < 8; i++) {
477         if (i < insnWidth) {
478             if (i == 7) {
479                 printf(" ... ");
480             } else {
481                 /* print 16-bit value in little-endian order */
482                 const u1* bytePtr = (const u1*) &insns[insnIdx+i];
483                 printf(" %02x%02x", bytePtr[0], bytePtr[1]);
484             }
485         } else {
486             fputs("     ", stdout);
487         }
488     }
489
490     if (pDecInsn->opCode == OP_NOP) {
491         u2 instr = get2LE((const u1*) &insns[insnIdx]);
492         if (instr == kPackedSwitchSignature) {
493             printf("|%04x: packed-switch-data (%d units)",
494                 insnIdx, insnWidth);
495         } else if (instr == kSparseSwitchSignature) {
496             printf("|%04x: sparse-switch-data (%d units)",
497                 insnIdx, insnWidth);
498         } else if (instr == kArrayDataSignature) {
499             printf("|%04x: array-data (%d units)",
500                 insnIdx, insnWidth);
501         } else {
502             printf("|%04x: nop // spacer", insnIdx);
503         }
504     } else {
505         printf("|%04x: %s", insnIdx, getOpcodeName(pDecInsn->opCode));
506     }
507
508     switch (dexGetInstrFormat(gInstrFormat, pDecInsn->opCode)) {
509     case kFmt10x:        // op
510         break;
511     case kFmt12x:        // op vA, vB
512         printf(" v%d, v%d", pDecInsn->vA, pDecInsn->vB);
513         break;
514     case kFmt11n:        // op vA, #+B
515         printf(" v%d, #int %d // #%x",
516             pDecInsn->vA, (s4)pDecInsn->vB, (u1)pDecInsn->vB);
517         break;
518     case kFmt11x:        // op vAA
519         printf(" v%d", pDecInsn->vA);
520         break;
521     case kFmt10t:        // op +AA
522     case kFmt20t:        // op +AAAA
523         {
524             s4 targ = (s4) pDecInsn->vA;
525             printf(" %04x // %c%04x",
526                 insnIdx + targ,
527                 (targ < 0) ? '-' : '+',
528                 (targ < 0) ? -targ : targ);
529         }
530         break;
531     case kFmt22x:        // op vAA, vBBBB
532         printf(" v%d, v%d", pDecInsn->vA, pDecInsn->vB);
533         break;
534     case kFmt21t:        // op vAA, +BBBB
535         {
536             s4 targ = (s4) pDecInsn->vB;
537             printf(" v%d, %04x // %c%04x", pDecInsn->vA,
538                 insnIdx + targ,
539                 (targ < 0) ? '-' : '+',
540                 (targ < 0) ? -targ : targ);
541         }
542         break;
543     case kFmt21s:        // op vAA, #+BBBB
544         printf(" v%d, #int %d // #%x",
545             pDecInsn->vA, (s4)pDecInsn->vB, (u2)pDecInsn->vB);
546         break;
547     case kFmt21h:        // op vAA, #+BBBB0000[00000000]
548         // The printed format varies a bit based on the actual opcode.
549         if (pDecInsn->opCode == OP_CONST_HIGH16) {
550             s4 value = pDecInsn->vB << 16;
551             printf(" v%d, #int %d // #%x",
552                 pDecInsn->vA, value, (u2)pDecInsn->vB);
553         } else {
554             s8 value = ((s8) pDecInsn->vB) << 48;
555             printf(" v%d, #long %lld // #%x",
556                 pDecInsn->vA, value, (u2)pDecInsn->vB);
557         }
558         break;
559     case kFmt21c:        // op vAA, thing@BBBB
560         if (pDecInsn->opCode == OP_CONST_STRING) {
561             printf(" v%d, \"%s\" // string@%04x", pDecInsn->vA,
562                 dexStringById(pDexFile, pDecInsn->vB), pDecInsn->vB);
563         } else if (pDecInsn->opCode == OP_CHECK_CAST ||
564                    pDecInsn->opCode == OP_NEW_INSTANCE ||
565                    pDecInsn->opCode == OP_CONST_CLASS)
566         {
567             printf(" v%d, %s // class@%04x", pDecInsn->vA,
568                 getClassDescriptor(pDexFile, pDecInsn->vB), pDecInsn->vB);
569         } else /* OP_SGET* */ {
570             FieldMethodInfo fieldInfo;
571             if (getFieldInfo(pDexFile, pDecInsn->vB, &fieldInfo)) {
572                 printf(" v%d, %s.%s:%s // field@%04x", pDecInsn->vA,
573                     fieldInfo.classDescriptor, fieldInfo.name,
574                     fieldInfo.signature, pDecInsn->vB);
575             } else {
576                 printf(" v%d, ??? // field@%04x", pDecInsn->vA, pDecInsn->vB);
577             }
578         }
579         break;
580     case kFmt23x:        // op vAA, vBB, vCC
581         printf(" v%d, v%d, v%d", pDecInsn->vA, pDecInsn->vB, pDecInsn->vC);
582         break;
583     case kFmt22b:        // op vAA, vBB, #+CC
584         printf(" v%d, v%d, #int %d // #%02x",
585             pDecInsn->vA, pDecInsn->vB, (s4)pDecInsn->vC, (u1)pDecInsn->vC);
586         break;
587     case kFmt22t:        // op vA, vB, +CCCC
588         {
589             s4 targ = (s4) pDecInsn->vC;
590             printf(" v%d, v%d, %04x // %c%04x", pDecInsn->vA, pDecInsn->vB,
591                 insnIdx + targ,
592                 (targ < 0) ? '-' : '+',
593                 (targ < 0) ? -targ : targ);
594         }
595         break;
596     case kFmt22s:        // op vA, vB, #+CCCC
597         printf(" v%d, v%d, #int %d // #%04x",
598             pDecInsn->vA, pDecInsn->vB, (s4)pDecInsn->vC, (u2)pDecInsn->vC);
599         break;
600     case kFmt22c:        // op vA, vB, thing@CCCC
601         if (pDecInsn->opCode >= OP_IGET && pDecInsn->opCode <= OP_IPUT_SHORT) {
602             FieldMethodInfo fieldInfo;
603             if (getFieldInfo(pDexFile, pDecInsn->vC, &fieldInfo)) {
604                 printf(" v%d, v%d, %s.%s:%s // field@%04x", pDecInsn->vA,
605                     pDecInsn->vB, fieldInfo.classDescriptor, fieldInfo.name,
606                     fieldInfo.signature, pDecInsn->vC);
607             } else {
608                 printf(" v%d, v%d, ??? // field@%04x", pDecInsn->vA,
609                     pDecInsn->vB, pDecInsn->vC);
610             }
611         } else {
612             printf(" v%d, v%d, %s // class@%04x",
613                 pDecInsn->vA, pDecInsn->vB,
614                 getClassDescriptor(pDexFile, pDecInsn->vC), pDecInsn->vC);
615         }
616         break;
617     case kFmt22cs:       // [opt] op vA, vB, field offset CCCC
618         printf(" v%d, v%d, [obj+%04x]",
619             pDecInsn->vA, pDecInsn->vB, pDecInsn->vC);
620         break;
621     case kFmt30t:
622         printf(" #%08x", pDecInsn->vA);
623         break;
624     case kFmt31i:        // op vAA, #+BBBBBBBB
625         {
626             /* this is often, but not always, a float */
627             union {
628                 float f;
629                 u4 i;
630             } conv;
631             conv.i = pDecInsn->vB;
632             printf(" v%d, #float %f // #%08x",
633                 pDecInsn->vA, conv.f, pDecInsn->vB);
634         }
635         break;
636     case kFmt31c:        // op vAA, thing@BBBBBBBB
637         printf(" v%d, \"%s\" // string@%08x", pDecInsn->vA,
638             dexStringById(pDexFile, pDecInsn->vB), pDecInsn->vB);
639         break;
640     case kFmt31t:       // op vAA, offset +BBBBBBBB
641         printf(" v%d, %08x // +%08x",
642             pDecInsn->vA, insnIdx + pDecInsn->vB, pDecInsn->vB);
643         break;
644     case kFmt32x:        // op vAAAA, vBBBB
645         printf(" v%d, v%d", pDecInsn->vA, pDecInsn->vB);
646         break;
647     case kFmt35c:        // op vB, {vD, vE, vF, vG, vA}, thing@CCCC
648         {
649             /* NOTE: decoding of 35c doesn't quite match spec */
650             fputs(" {", stdout);
651             for (i = 0; i < (int) pDecInsn->vA; i++) {
652                 if (i == 0)
653                     printf("v%d", pDecInsn->arg[i]);
654                 else
655                     printf(", v%d", pDecInsn->arg[i]);
656             }
657             if (pDecInsn->opCode == OP_FILLED_NEW_ARRAY) {
658                 printf("}, %s // class@%04x",
659                     getClassDescriptor(pDexFile, pDecInsn->vB), pDecInsn->vB);
660             } else {
661                 FieldMethodInfo methInfo;
662                 if (getMethodInfo(pDexFile, pDecInsn->vB, &methInfo)) {
663                     printf("}, %s.%s:%s // method@%04x",
664                         methInfo.classDescriptor, methInfo.name,
665                         methInfo.signature, pDecInsn->vB);
666                 } else {
667                     printf("}, ??? // method@%04x", pDecInsn->vB);
668                 }
669             }
670         }
671         break;
672     case kFmt35ms:       // [opt] invoke-virtual+super
673     case kFmt35fs:       // [opt] invoke-interface
674         {
675             fputs(" {", stdout);
676             for (i = 0; i < (int) pDecInsn->vA; i++) {
677                 if (i == 0)
678                     printf("v%d", pDecInsn->arg[i]);
679                 else
680                     printf(", v%d", pDecInsn->arg[i]);
681             }
682             printf("}, [%04x] // vtable #%04x", pDecInsn->vB, pDecInsn->vB);
683         }
684         break;
685     case kFmt3rc:        // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB
686         {
687             /*
688              * This doesn't match the "dx" output when some of the args are
689              * 64-bit values -- dx only shows the first register.
690              */
691             fputs(" {", stdout);
692             for (i = 0; i < (int) pDecInsn->vA; i++) {
693                 if (i == 0)
694                     printf("v%d", pDecInsn->vC + i);
695                 else
696                     printf(", v%d", pDecInsn->vC + i);
697             }
698             if (pDecInsn->opCode == OP_FILLED_NEW_ARRAY_RANGE) {
699                 printf("}, %s // class@%04x",
700                     getClassDescriptor(pDexFile, pDecInsn->vB), pDecInsn->vB);
701             } else {
702                 FieldMethodInfo methInfo;
703                 if (getMethodInfo(pDexFile, pDecInsn->vB, &methInfo)) {
704                     printf("}, %s.%s:%s // method@%04x",
705                         methInfo.classDescriptor, methInfo.name,
706                         methInfo.signature, pDecInsn->vB);
707                 } else {
708                     printf("}, ??? // method@%04x", pDecInsn->vB);
709                 }
710             }
711         }
712         break;
713     case kFmt3rms:       // [opt] invoke-virtual+super/range
714     case kFmt3rfs:       // [opt] invoke-interface/range
715         {
716             /*
717              * This doesn't match the "dx" output when some of the args are
718              * 64-bit values -- dx only shows the first register.
719              */
720             fputs(" {", stdout);
721             for (i = 0; i < (int) pDecInsn->vA; i++) {
722                 if (i == 0)
723                     printf("v%d", pDecInsn->vC + i);
724                 else
725                     printf(", v%d", pDecInsn->vC + i);
726             }
727             printf("}, [%04x] // vtable #%04x", pDecInsn->vB, pDecInsn->vB);
728         }
729         break;
730     case kFmt3inline:    // [opt] inline invoke
731         {
732 #if 0
733             const InlineOperation* inlineOpsTable = dvmGetInlineOpsTable();
734             u4 tableLen = dvmGetInlineOpsTableLength();
735 #endif
736
737             fputs(" {", stdout);
738             for (i = 0; i < (int) pDecInsn->vA; i++) {
739                 if (i == 0)
740                     printf("v%d", pDecInsn->arg[i]);
741                 else
742                     printf(", v%d", pDecInsn->arg[i]);
743             }
744 #if 0
745             if (pDecInsn->vB < tableLen) {
746                 printf("}, %s.%s:%s // inline #%04x",
747                     inlineOpsTable[pDecInsn->vB].classDescriptor,
748                     inlineOpsTable[pDecInsn->vB].methodName,
749                     inlineOpsTable[pDecInsn->vB].methodSignature,
750                     pDecInsn->vB);
751             } else {
752 #endif
753                 printf("}, [%04x] // inline #%04x", pDecInsn->vB, pDecInsn->vB);
754 #if 0
755             }
756 #endif
757         }
758         break;
759     case kFmt51l:        // op vAA, #+BBBBBBBBBBBBBBBB
760         {
761             /* this is often, but not always, a double */
762             union {
763                 double d;
764                 u8 j;
765             } conv;
766             conv.j = pDecInsn->vB_wide;
767             printf(" v%d, #double %f // #%016llx",
768                 pDecInsn->vA, conv.d, pDecInsn->vB_wide);
769         }
770         break;
771     case kFmtUnknown:
772         break;
773     default:
774         printf(" ???");
775         break;
776     }
777
778
779     putchar('\n');
780
781 }
782
783 /*
784  * Dump a bytecode disassembly.
785  */
786 void dumpBytecodes(DexFile* pDexFile, const DexMethod* pDexMethod)
787 {
788     const DexCode* pCode = dexGetCode(pDexFile, pDexMethod);
789     const u2* insns;
790     int insnIdx;
791     FieldMethodInfo methInfo;
792     int startAddr;
793     char* className = NULL;
794
795     assert(pCode->insnsSize > 0);
796     insns = pCode->insns;
797
798     getMethodInfo(pDexFile, pDexMethod->methodIdx, &methInfo);
799     startAddr = ((u1*)pCode - pDexFile->baseAddr);
800     className = descriptorToDot(methInfo.classDescriptor);
801
802     printf("%06x:                                        |[%06x] %s.%s:%s\n",
803         startAddr, startAddr,
804         className, methInfo.name, methInfo.signature);
805
806     insnIdx = 0;
807     while (insnIdx < (int) pCode->insnsSize) {
808         int insnWidth;
809         OpCode opCode;
810         DecodedInstruction decInsn;
811         u2 instr;
812
813         instr = get2LE((const u1*)insns);
814         if (instr == kPackedSwitchSignature) {
815             insnWidth = 4 + get2LE((const u1*)(insns+1)) * 2;
816         } else if (instr == kSparseSwitchSignature) {
817             insnWidth = 2 + get2LE((const u1*)(insns+1)) * 4;
818         } else if (instr == kArrayDataSignature) {
819             int width = get2LE((const u1*)(insns+1));
820             int size = get2LE((const u1*)(insns+2)) | 
821                        (get2LE((const u1*)(insns+3))<<16);
822             // The plus 1 is to round up for odd size and width 
823             insnWidth = 4 + ((size * width) + 1) / 2;
824         } else {
825             opCode = instr & 0xff;
826             insnWidth = dexGetInstrWidthAbs(gInstrWidth, opCode);
827             if (insnWidth == 0) {
828                 fprintf(stderr,
829                     "GLITCH: zero-width instruction at idx=0x%04x\n", insnIdx);
830                 break;
831             }
832         }
833
834         dexDecodeInstruction(gInstrFormat, insns, &decInsn);
835         dumpInstruction(pDexFile, pCode, insnIdx, insnWidth, &decInsn);
836
837         insns += insnWidth;
838         insnIdx += insnWidth;
839     }
840
841     free(className);
842 }
843
844 /*
845  * Dump a "code" struct.
846  */
847 void dumpCode(DexFile* pDexFile, const DexMethod* pDexMethod)
848 {
849     const DexCode* pCode = dexGetCode(pDexFile, pDexMethod);
850
851     printf("      registers     : %d\n", pCode->registersSize);
852     printf("      ins           : %d\n", pCode->insSize);
853     printf("      outs          : %d\n", pCode->outsSize);
854     printf("      insns size    : %d 16-bit code units\n", pCode->insnsSize);
855
856     if (gOptions.disassemble)
857         dumpBytecodes(pDexFile, pDexMethod);
858
859     dumpCatches(pDexFile, pCode);
860     /* both of these are encoded in debug info */
861     dumpPositions(pDexFile, pCode, pDexMethod);
862     dumpLocals(pDexFile, pCode, pDexMethod);
863 }
864
865 /*
866  * Dump a method.
867  */
868 void dumpMethod(DexFile* pDexFile, const DexMethod* pDexMethod, int i)
869 {
870     const DexMethodId* pMethodId;
871     const char* backDescriptor;
872     const char* name;
873     char* typeDescriptor;
874     char* accessStr;
875
876     pMethodId = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
877     name = dexStringById(pDexFile, pMethodId->nameIdx);
878     typeDescriptor = dexCopyDescriptorFromMethodId(pDexFile, pMethodId);
879
880     backDescriptor = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
881
882     accessStr = createAccessFlagStr(pDexMethod->accessFlags,
883                     kAccessForMethod);
884
885     printf("    #%d              : (in %s)\n", i, backDescriptor);
886     printf("      name          : '%s'\n", name);
887     printf("      type          : '%s'\n", typeDescriptor);
888     printf("      access        : 0x%04x (%s)\n",
889         pDexMethod->accessFlags, accessStr);
890
891     if (pDexMethod->codeOff == 0) {
892         printf("      code          : (none)\n");
893     } else {
894         printf("      code          -\n");
895         dumpCode(pDexFile, pDexMethod);
896     }
897
898     if (gOptions.disassemble)
899         putchar('\n');
900
901     free(typeDescriptor);
902     free(accessStr);
903 }
904
905 /*
906  * Dump a static (class) field.
907  */
908 void dumpSField(const DexFile* pDexFile, const DexField* pSField, int i)
909 {
910     const DexFieldId* pFieldId;
911     const char* backDescriptor;
912     const char* name;
913     const char* typeDescriptor;
914     char* accessStr;
915
916     pFieldId = dexGetFieldId(pDexFile, pSField->fieldIdx);
917     name = dexStringById(pDexFile, pFieldId->nameIdx);
918     typeDescriptor = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx);
919     backDescriptor = dexStringByTypeIdx(pDexFile, pFieldId->classIdx);
920
921     accessStr = createAccessFlagStr(pSField->accessFlags, kAccessForField);
922
923     printf("    #%d              : (in %s)\n", i, backDescriptor);
924     printf("      name          : '%s'\n", name);
925     printf("      type          : '%s'\n", typeDescriptor);
926     printf("      access        : 0x%04x (%s)\n",
927         pSField->accessFlags, accessStr);
928
929     free(accessStr);
930 }
931
932 /*
933  * Dump an instance field.
934  */
935 void dumpIField(const DexFile* pDexFile, const DexField* pIField, int i)
936 {
937     const DexFieldId* pFieldId;
938     const char* backDescriptor;
939     const char* name;
940     const char* typeDescriptor;
941     char* accessStr;
942
943     pFieldId = dexGetFieldId(pDexFile, pIField->fieldIdx);
944     name = dexStringById(pDexFile, pFieldId->nameIdx);
945     typeDescriptor = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx);
946     backDescriptor = dexStringByTypeIdx(pDexFile, pFieldId->classIdx);
947
948     accessStr = createAccessFlagStr(pIField->accessFlags, kAccessForField);
949
950     printf("    #%d              : (in %s)\n", i, backDescriptor);
951     printf("      name          : '%s'\n", name);
952     printf("      type          : '%s'\n", typeDescriptor);
953     printf("      access        : 0x%04x (%s)\n",
954         pIField->accessFlags, accessStr);
955
956     free(accessStr);
957 }
958
959 /*
960  * Dump the class.
961  */
962 void dumpClass(DexFile* pDexFile, int idx)
963 {
964     const DexTypeList* pInterfaces;
965     const DexClassDef* pClassDef;
966     DexClassData* pClassData;
967     const u1* pEncodedData;
968     const char* fileName;
969     const char* classDescriptor;
970     const char* superclassDescriptor;
971     char* accessStr;
972     int i;
973
974     pClassDef = dexGetClassDef(pDexFile, idx);
975     printf("Class #%d            -\n", idx);
976
977     pEncodedData = dexGetClassData(pDexFile, pClassDef);
978     pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL);
979
980     if (pClassData == NULL) {
981         printf("Trouble reading class data\n");
982         return;
983     }
984     
985     classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
986     printf("  Class descriptor  : '%s'\n", classDescriptor);
987
988     accessStr = createAccessFlagStr(pClassDef->accessFlags, kAccessForClass);
989     printf("  Access flags      : 0x%04x (%s)\n",
990         pClassDef->accessFlags, accessStr);
991
992     if (pClassDef->superclassIdx == kDexNoIndex)
993         superclassDescriptor = "(none)";
994     else {
995         superclassDescriptor =
996             dexStringByTypeIdx(pDexFile, pClassDef->superclassIdx);
997         printf("  Superclass        : '%s'\n", superclassDescriptor);
998     }
999
1000     printf("  Interfaces        -\n");
1001     pInterfaces = dexGetInterfacesList(pDexFile, pClassDef);
1002     if (pInterfaces != NULL) {
1003         for (i = 0; i < (int) pInterfaces->size; i++)
1004             dumpInterface(pDexFile, dexGetTypeItem(pInterfaces, i), i);
1005     }
1006
1007     printf("  Static fields     -\n");
1008     for (i = 0; i < (int) pClassData->header.staticFieldsSize; i++) {
1009         dumpSField(pDexFile, &pClassData->staticFields[i], i);
1010     }
1011
1012     printf("  Instance fields   -\n");
1013     for (i = 0; i < (int) pClassData->header.instanceFieldsSize; i++) {
1014         dumpIField(pDexFile, &pClassData->instanceFields[i], i);
1015     }
1016
1017     printf("  Direct methods    -\n");
1018     for (i = 0; i < (int) pClassData->header.directMethodsSize; i++) {
1019         dumpMethod(pDexFile, &pClassData->directMethods[i], i);
1020     }
1021
1022     printf("  Virtual methods   -\n");
1023     for (i = 0; i < (int) pClassData->header.virtualMethodsSize; i++) {
1024         dumpMethod(pDexFile, &pClassData->virtualMethods[i], i);
1025     }
1026
1027     // TODO: Annotations.
1028
1029     if (pClassDef->sourceFileIdx != kDexNoIndex)
1030         fileName = dexStringById(pDexFile, pClassDef->sourceFileIdx);
1031     else
1032         fileName = "unknown";
1033     printf("  source_file_idx   : %d (%s)\n",
1034         pClassDef->sourceFileIdx, fileName);
1035
1036     printf("\n");
1037
1038     free(pClassData);
1039     free(accessStr);
1040 }
1041
1042 /*
1043  * Dump the requested sections of the file.
1044  */
1045 void processDexFile(const char* fileName, DexFile* pDexFile)
1046 {
1047     int i;
1048
1049     printf("Opened '%s', DEX version '%.3s'\n", fileName,
1050         pDexFile->pHeader->magic +4);
1051
1052     if (gOptions.showFileHeaders)
1053         dumpFileHeader(pDexFile);
1054
1055     for (i = 0; i < (int) pDexFile->pHeader->classDefsSize; i++) {
1056         if (gOptions.showSectionHeaders)
1057             dumpClassDef(pDexFile, i);
1058
1059         dumpClass(pDexFile, i);
1060     }
1061 }
1062
1063
1064 /*
1065  * Process one file.
1066  */
1067 int process(const char* fileName)
1068 {
1069     DexFile* pDexFile = NULL;
1070     MemMapping map;
1071     bool mapped = false;
1072     int result = -1;
1073
1074     printf("Processing '%s'...\n", fileName);
1075
1076     if (dexOpenAndMap(fileName, gOptions.tempFileName, &map, false) != 0)
1077         goto bail;
1078     mapped = true;
1079
1080     pDexFile = dexFileParse(map.addr, map.length,
1081         kDexParseVerifyChecksum | kDexParseContinueOnError);
1082     if (pDexFile == NULL) {
1083         fprintf(stderr, "ERROR: DEX parse failed\n");
1084         goto bail;
1085     }
1086
1087     processDexFile(fileName, pDexFile);
1088
1089     result = 0;
1090
1091 bail:
1092     if (mapped)
1093         sysReleaseShmem(&map);
1094     if (pDexFile != NULL)
1095         dexFileFree(pDexFile);
1096     return result;
1097 }
1098
1099
1100 /*
1101  * Show usage.
1102  */
1103 void usage(void)
1104 {
1105     fprintf(stderr, "Copyright (C) 2007 The Android Open Source Project\n\n");
1106     fprintf(stderr, "%s: [-d] [-f] [-h] [-t tempfile] dexfile...\n", gProgName);
1107     fprintf(stderr, "\n");
1108     fprintf(stderr, " -d : disassemble code sections\n");
1109     fprintf(stderr, " -f : display summary information from file header\n");
1110     fprintf(stderr, " -h : display file header details\n");
1111     fprintf(stderr, " -t : temp file name (defaults to /sdcard/dex-temp-*)\n");
1112 }
1113
1114 /*
1115  * Parse args.
1116  *
1117  * I'm not using getopt_long() because we may not have it in libc.
1118  */
1119 int main(int argc, char* const argv[])
1120 {
1121     bool wantUsage = false;
1122     int ic;
1123
1124     memset(&gOptions, 0, sizeof(gOptions));
1125
1126     while (1) {
1127         ic = getopt(argc, argv, "dfht:");
1128         if (ic < 0)
1129             break;
1130
1131         switch (ic) {
1132         case 'd':       // disassemble Dalvik instructions
1133             gOptions.disassemble = true;
1134             break;
1135         case 'f':       // dump outer file header
1136             gOptions.showFileHeaders = true;
1137             break;
1138         case 'h':       // dump section headers, i.e. all meta-data
1139             gOptions.showSectionHeaders = true;
1140             break;
1141         case 't':       // temp file, used when opening compressed Jar
1142             gOptions.tempFileName = argv[optind];
1143             break;
1144         default:
1145             wantUsage = true;
1146             break;
1147         }
1148     }
1149
1150     if (optind == argc) {
1151         fprintf(stderr, "%s: no file specified\n", gProgName);
1152         wantUsage = true;
1153     }
1154
1155     /* initialize some VM tables */
1156     gInstrWidth = dexCreateInstrWidthTable();
1157     gInstrFormat = dexCreateInstrFormatTable();
1158
1159     if (wantUsage) {
1160         usage();
1161         return 2;
1162     }
1163
1164     while (optind < argc)
1165         process(argv[optind++]);
1166
1167     free(gInstrWidth);
1168     free(gInstrFormat);
1169
1170     return 0;
1171 }