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