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