blob: 879288bb8ed4f5c294c2234afdea83f911687881 [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
1063/*
1064 * Dump register map contents of the current method.
1065 *
1066 * "*pData" should point to the start of the register map data. Advances
1067 * "*pData" to the start of the next map.
1068 */
1069void dumpMethodMap(DexFile* pDexFile, const DexMethod* pDexMethod, int idx,
1070 const u1** pData)
1071{
1072 const u1* data = *pData;
1073 const DexMethodId* pMethodId;
1074 const char* name;
1075 int offset = data - (u1*) pDexFile->pOptHeader;
1076
1077 pMethodId = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
1078 name = dexStringById(pDexFile, pMethodId->nameIdx);
1079 printf(" #%d: 0x%08x %s\n", idx, offset, name);
1080
1081 u1 format;
1082 int addrWidth;
1083
1084 format = *data++;
1085 if (format == 1) { /* kRegMapFormatNone */
1086 /* no map */
1087 printf(" (no map)\n");
1088 addrWidth = 0;
1089 } else if (format == 2) { /* kRegMapFormatCompact8 */
1090 addrWidth = 1;
1091 } else if (format == 3) { /* kRegMapFormatCompact16 */
1092 addrWidth = 2;
1093 } else {
1094 printf(" (unknown format %d!)\n", format);
1095 addrWidth = -1;
1096 }
1097
1098 if (addrWidth > 0) {
1099 u1 regWidth;
1100 u2 numEntries;
1101 int idx, addr, byte;
1102
1103 regWidth = *data++;
1104 numEntries = *data++;
1105 numEntries |= (*data++) << 8;
1106
1107 for (idx = 0; idx < numEntries; idx++) {
1108 addr = *data++;
1109 if (addrWidth > 1)
1110 addr |= (*data++) << 8;
1111
1112 printf(" %4x:", addr);
1113 for (byte = 0; byte < regWidth; byte++) {
1114 printf(" %02x", *data++);
1115 }
1116 printf("\n");
1117 }
1118 }
1119
1120 //if (addrWidth >= 0)
1121 // *pData = align32(data);
1122 *pData = data;
1123}
1124
1125/*
1126 * Dump the contents of the register map area.
1127 *
1128 * These are only present in optimized DEX files, and the structure is
1129 * not really exposed to other parts of the VM itself. We're going to
1130 * dig through them here, but this is pretty fragile. DO NOT rely on
1131 * this or derive other code from it.
1132 */
1133void dumpRegisterMaps(DexFile* pDexFile)
1134{
1135 const u1* pClassPool = pDexFile->pRegisterMapPool;
1136 const u4* classOffsets;
1137 const u1* ptr;
1138 u4 numClasses;
1139 int baseFileOffset = (u1*) pClassPool - (u1*) pDexFile->pOptHeader;
1140 int idx;
1141
1142 if (pClassPool == NULL) {
1143 printf("No register maps found\n");
1144 return;
1145 }
1146
1147 ptr = pClassPool;
1148 numClasses = get4LE(ptr);
1149 ptr += sizeof(u4);
1150 classOffsets = (const u4*) ptr;
1151
1152 printf("RMAP begins at offset 0x%07x\n", baseFileOffset);
1153 printf("Maps for %d classes\n", numClasses);
1154 for (idx = 0; idx < (int) numClasses; idx++) {
1155 const DexClassDef* pClassDef;
1156 const char* classDescriptor;
1157
1158 pClassDef = dexGetClassDef(pDexFile, idx);
1159 classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
1160
1161 printf("%4d: +%d (0x%08x) %s\n", idx, classOffsets[idx],
1162 baseFileOffset + classOffsets[idx], classDescriptor);
1163
1164 if (classOffsets[idx] == 0)
1165 continue;
1166
1167 /*
1168 * What follows is a series of RegisterMap entries, one for every
1169 * direct method, then one for every virtual method.
1170 */
1171 DexClassData* pClassData;
1172 const u1* pEncodedData;
1173 const u1* data = (u1*) pClassPool + classOffsets[idx];
1174 u2 methodCount;
1175 int i;
1176
1177 pEncodedData = dexGetClassData(pDexFile, pClassDef);
1178 pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL);
1179 if (pClassData == NULL) {
1180 fprintf(stderr, "Trouble reading class data\n");
1181 continue;
1182 }
1183
1184 methodCount = *data++;
1185 methodCount |= (*data++) << 8;
1186 data += 2; /* two pad bytes follow methodCount */
1187 if (methodCount != pClassData->header.directMethodsSize
1188 + pClassData->header.virtualMethodsSize)
1189 {
1190 printf("NOTE: method count discrepancy (%d != %d + %d)\n",
1191 methodCount, pClassData->header.directMethodsSize,
1192 pClassData->header.virtualMethodsSize);
1193 /* this is bad, but keep going anyway */
1194 }
1195
1196 printf(" direct methods: %d\n",
1197 pClassData->header.directMethodsSize);
1198 for (i = 0; i < (int) pClassData->header.directMethodsSize; i++) {
1199 dumpMethodMap(pDexFile, &pClassData->directMethods[i], i, &data);
1200 }
1201
1202 printf(" virtual methods: %d\n",
1203 pClassData->header.virtualMethodsSize);
1204 for (i = 0; i < (int) pClassData->header.virtualMethodsSize; i++) {
1205 dumpMethodMap(pDexFile, &pClassData->virtualMethods[i], i, &data);
1206 }
1207
1208 free(pClassData);
1209 }
1210}
1211
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001212/*
1213 * Dump the requested sections of the file.
1214 */
1215void processDexFile(const char* fileName, DexFile* pDexFile)
1216{
1217 int i;
1218
1219 printf("Opened '%s', DEX version '%.3s'\n", fileName,
1220 pDexFile->pHeader->magic +4);
1221
The Android Open Source Project99409882009-03-18 22:20:24 -07001222 if (gOptions.dumpRegisterMaps) {
1223 dumpRegisterMaps(pDexFile);
1224 return;
1225 }
1226
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001227 if (gOptions.showFileHeaders)
1228 dumpFileHeader(pDexFile);
1229
1230 for (i = 0; i < (int) pDexFile->pHeader->classDefsSize; i++) {
1231 if (gOptions.showSectionHeaders)
1232 dumpClassDef(pDexFile, i);
1233
1234 dumpClass(pDexFile, i);
1235 }
1236}
1237
1238
1239/*
1240 * Process one file.
1241 */
1242int process(const char* fileName)
1243{
1244 DexFile* pDexFile = NULL;
1245 MemMapping map;
1246 bool mapped = false;
1247 int result = -1;
1248
1249 printf("Processing '%s'...\n", fileName);
1250
1251 if (dexOpenAndMap(fileName, gOptions.tempFileName, &map, false) != 0)
1252 goto bail;
1253 mapped = true;
1254
1255 pDexFile = dexFileParse(map.addr, map.length,
1256 kDexParseVerifyChecksum | kDexParseContinueOnError);
1257 if (pDexFile == NULL) {
1258 fprintf(stderr, "ERROR: DEX parse failed\n");
1259 goto bail;
1260 }
1261
1262 processDexFile(fileName, pDexFile);
1263
1264 result = 0;
1265
1266bail:
1267 if (mapped)
1268 sysReleaseShmem(&map);
1269 if (pDexFile != NULL)
1270 dexFileFree(pDexFile);
1271 return result;
1272}
1273
1274
1275/*
1276 * Show usage.
1277 */
1278void usage(void)
1279{
1280 fprintf(stderr, "Copyright (C) 2007 The Android Open Source Project\n\n");
The Android Open Source Project99409882009-03-18 22:20:24 -07001281 fprintf(stderr, "%s: [-d] [-f] [-h] [-m] [-t tempfile] dexfile...\n",
1282 gProgName);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001283 fprintf(stderr, "\n");
1284 fprintf(stderr, " -d : disassemble code sections\n");
1285 fprintf(stderr, " -f : display summary information from file header\n");
1286 fprintf(stderr, " -h : display file header details\n");
The Android Open Source Project99409882009-03-18 22:20:24 -07001287 fprintf(stderr, " -m : dump register maps (and nothing else)\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001288 fprintf(stderr, " -t : temp file name (defaults to /sdcard/dex-temp-*)\n");
1289}
1290
1291/*
1292 * Parse args.
1293 *
1294 * I'm not using getopt_long() because we may not have it in libc.
1295 */
1296int main(int argc, char* const argv[])
1297{
1298 bool wantUsage = false;
1299 int ic;
1300
1301 memset(&gOptions, 0, sizeof(gOptions));
1302
1303 while (1) {
The Android Open Source Project99409882009-03-18 22:20:24 -07001304 ic = getopt(argc, argv, "dfhmt:");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001305 if (ic < 0)
1306 break;
1307
1308 switch (ic) {
1309 case 'd': // disassemble Dalvik instructions
1310 gOptions.disassemble = true;
1311 break;
1312 case 'f': // dump outer file header
1313 gOptions.showFileHeaders = true;
1314 break;
1315 case 'h': // dump section headers, i.e. all meta-data
1316 gOptions.showSectionHeaders = true;
1317 break;
The Android Open Source Project99409882009-03-18 22:20:24 -07001318 case 'm': // dump register maps only
1319 gOptions.dumpRegisterMaps = true;
1320 break;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001321 case 't': // temp file, used when opening compressed Jar
1322 gOptions.tempFileName = argv[optind];
1323 break;
1324 default:
1325 wantUsage = true;
1326 break;
1327 }
1328 }
1329
1330 if (optind == argc) {
1331 fprintf(stderr, "%s: no file specified\n", gProgName);
1332 wantUsage = true;
1333 }
1334
1335 /* initialize some VM tables */
1336 gInstrWidth = dexCreateInstrWidthTable();
1337 gInstrFormat = dexCreateInstrFormatTable();
1338
1339 if (wantUsage) {
1340 usage();
1341 return 2;
1342 }
1343
1344 while (optind < argc)
1345 process(argv[optind++]);
1346
1347 free(gInstrWidth);
1348 free(gInstrFormat);
1349
1350 return 0;
1351}