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