blob: a4d97eb7b6a92fa6eb2b760c217a01564da0f68a [file] [log] [blame]
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001/*
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
41static const char* gProgName = "dexdump";
42
43static InstructionWidth* gInstrWidth;
44static InstructionFormat* gInstrFormat;
45
46/* command-line options */
47struct {
48 bool disassemble;
49 bool showFileHeaders;
50 bool showSectionHeaders;
51 const char* tempFileName;
52} gOptions;
53
54/* basic info about a field or method */
55typedef 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 */
64static 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 */
75static 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 */
105static 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 */
121typedef 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 */
132static 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 */
234void 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 */
274void 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 */
315void 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 */
327void 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
368static 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 */
377void 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
390static 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 */
402void 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 */
419bool 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 */
438bool 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 */
457const char* getClassDescriptor(DexFile* pDexFile, u4 classIdx)
458{
459 return dexStringByTypeIdx(pDexFile, classIdx);
460}
461
462/*
463 * Dump a single instruction.
464 */
465void 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 */
786void 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 */
847void 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 */
868void 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 */
908void 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 */
935void 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 */
962void 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 */
1045void 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 */
1067int 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
1091bail:
1092 if (mapped)
1093 sysReleaseShmem(&map);
1094 if (pDexFile != NULL)
1095 dexFileFree(pDexFile);
1096 return result;
1097}
1098
1099
1100/*
1101 * Show usage.
1102 */
1103void 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 */
1119int 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}