blob: 594930376a996ad95dc295a58193e4d60258b81c [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 *
Andy McFaddena2ee53b2009-05-05 16:52:10 -070021 * TODO: rework the "plain" output format to be more regexp-friendly
22 *
23 * Differences between XML output and the "current.xml" file:
24 * - classes in same package are not all grouped together; generally speaking
25 * nothing is sorted
26 * - no "deprecated" on fields and methods
27 * - no "value" on fields
28 * - no parameter names
29 * - no generic signatures on parameters, e.g. type="java.lang.Class<?>"
30 * - class shows declared fields and methods; does not show inherited fields
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080031 */
32#include "libdex/DexFile.h"
33#include "libdex/DexCatch.h"
34#include "libdex/DexClass.h"
35#include "libdex/DexProto.h"
36#include "libdex/InstrUtils.h"
Andy McFaddenc6b25c72010-06-22 11:01:20 -070037#include "libdex/OpCodeNames.h"
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080038#include "libdex/SysUtil.h"
39#include "libdex/CmdUtils.h"
40
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080041#include <stdlib.h>
42#include <stdio.h>
43#include <fcntl.h>
44#include <string.h>
45#include <unistd.h>
46#include <getopt.h>
47#include <errno.h>
48#include <assert.h>
49
50static const char* gProgName = "dexdump";
51
Dan Bornstein44a38f42010-11-10 17:34:32 -080052static InstructionInfoTables gInstrInfo;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080053
Andy McFaddena2ee53b2009-05-05 16:52:10 -070054typedef enum OutputFormat {
55 OUTPUT_PLAIN = 0, /* default */
56 OUTPUT_XML, /* fancy */
57} OutputFormat;
58
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080059/* command-line options */
60struct {
Andy McFadden0198b142009-04-02 14:48:56 -070061 bool checksumOnly;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080062 bool disassemble;
63 bool showFileHeaders;
64 bool showSectionHeaders;
Andy McFadden2124cb82009-03-25 15:37:39 -070065 bool ignoreBadChecksum;
The Android Open Source Project99409882009-03-18 22:20:24 -070066 bool dumpRegisterMaps;
Andy McFaddena2ee53b2009-05-05 16:52:10 -070067 OutputFormat outputFormat;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080068 const char* tempFileName;
Andy McFaddena2ee53b2009-05-05 16:52:10 -070069 bool exportsOnly;
70 bool verbose;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080071} gOptions;
72
73/* basic info about a field or method */
74typedef struct FieldMethodInfo {
75 const char* classDescriptor;
76 const char* name;
77 const char* signature;
78} FieldMethodInfo;
79
80/*
Carl Shapirode750892010-06-08 16:37:12 -070081 * Get 2 little-endian bytes.
82 */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080083static inline u2 get2LE(unsigned char const* pSrc)
84{
85 return pSrc[0] | (pSrc[1] << 8);
Carl Shapirode750892010-06-08 16:37:12 -070086}
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080087
88/*
Carl Shapirode750892010-06-08 16:37:12 -070089 * Get 4 little-endian bytes.
90 */
The Android Open Source Project99409882009-03-18 22:20:24 -070091static inline u4 get4LE(unsigned char const* pSrc)
92{
93 return pSrc[0] | (pSrc[1] << 8) | (pSrc[2] << 16) | (pSrc[3] << 24);
Carl Shapirode750892010-06-08 16:37:12 -070094}
The Android Open Source Project99409882009-03-18 22:20:24 -070095
96/*
Andy McFaddena2ee53b2009-05-05 16:52:10 -070097 * Converts a single-character primitive type into its human-readable
98 * equivalent.
99 */
100static const char* primitiveTypeLabel(char typeChar)
101{
102 switch (typeChar) {
103 case 'B': return "byte";
104 case 'C': return "char";
105 case 'D': return "double";
106 case 'F': return "float";
107 case 'I': return "int";
108 case 'J': return "long";
109 case 'S': return "short";
110 case 'V': return "void";
111 case 'Z': return "boolean";
112 default:
113 return "UNKNOWN";
114 }
115}
116
117/*
118 * Converts a type descriptor to human-readable "dotted" form. For
119 * example, "Ljava/lang/String;" becomes "java.lang.String", and
120 * "[I" becomes "int[]". Also converts '$' to '.', which means this
121 * form can't be converted back to a descriptor.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800122 */
123static char* descriptorToDot(const char* str)
124{
Andy McFaddena2ee53b2009-05-05 16:52:10 -0700125 int targetLen = strlen(str);
126 int offset = 0;
127 int arrayDepth = 0;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800128 char* newStr;
129
Andy McFaddena2ee53b2009-05-05 16:52:10 -0700130 /* strip leading [s; will be added to end */
131 while (targetLen > 1 && str[offset] == '[') {
132 offset++;
133 targetLen--;
134 }
135 arrayDepth = offset;
136
137 if (targetLen == 1) {
138 /* primitive type */
139 str = primitiveTypeLabel(str[offset]);
140 offset = 0;
141 targetLen = strlen(str);
142 } else {
143 /* account for leading 'L' and trailing ';' */
144 if (targetLen >= 2 && str[offset] == 'L' &&
145 str[offset+targetLen-1] == ';')
146 {
147 targetLen -= 2;
148 offset++;
149 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800150 }
151
Andy McFaddena2ee53b2009-05-05 16:52:10 -0700152 newStr = malloc(targetLen + arrayDepth * 2 +1);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800153
Andy McFaddena2ee53b2009-05-05 16:52:10 -0700154 /* copy class name over */
155 int i;
156 for (i = 0; i < targetLen; i++) {
157 char ch = str[offset + i];
158 newStr[i] = (ch == '/' || ch == '$') ? '.' : ch;
159 }
160
161 /* add the appropriate number of brackets for arrays */
162 while (arrayDepth-- > 0) {
163 newStr[i++] = '[';
164 newStr[i++] = ']';
165 }
166 newStr[i] = '\0';
167 assert(i == targetLen + arrayDepth * 2);
168
169 return newStr;
170}
171
172/*
173 * Converts the class name portion of a type descriptor to human-readable
174 * "dotted" form.
175 *
176 * Returns a newly-allocated string.
177 */
178static char* descriptorClassToDot(const char* str)
179{
180 const char* lastSlash;
181 char* newStr;
182 char* cp;
183
184 /* reduce to just the class name, trimming trailing ';' */
185 lastSlash = strrchr(str, '/');
186 if (lastSlash == NULL)
187 lastSlash = str + 1; /* start past 'L' */
188 else
189 lastSlash++; /* start past '/' */
190
191 newStr = strdup(lastSlash);
192 newStr[strlen(lastSlash)-1] = '\0';
193 for (cp = newStr; *cp != '\0'; cp++) {
194 if (*cp == '$')
195 *cp = '.';
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800196 }
197
198 return newStr;
199}
200
201/*
Andy McFaddena2ee53b2009-05-05 16:52:10 -0700202 * Returns a quoted string representing the boolean value.
203 */
204static const char* quotedBool(bool val)
205{
206 if (val)
207 return "\"true\"";
208 else
209 return "\"false\"";
210}
211
212static const char* quotedVisibility(u4 accessFlags)
213{
214 if ((accessFlags & ACC_PUBLIC) != 0)
215 return "\"public\"";
216 else if ((accessFlags & ACC_PROTECTED) != 0)
217 return "\"protected\"";
218 else if ((accessFlags & ACC_PRIVATE) != 0)
219 return "\"private\"";
220 else
221 return "\"package\"";
222}
223
224/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800225 * Count the number of '1' bits in a word.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800226 */
227static int countOnes(u4 val)
228{
229 int count = 0;
230
Cosmin Cojocare3393432010-04-18 18:25:06 +0200231 val = val - ((val >> 1) & 0x55555555);
232 val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
233 count = (((val + (val >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800234
235 return count;
236}
237
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800238/*
239 * Flag for use with createAccessFlagStr().
240 */
241typedef enum AccessFor {
242 kAccessForClass = 0, kAccessForMethod = 1, kAccessForField = 2,
243 kAccessForMAX
244} AccessFor;
245
246/*
247 * Create a new string with human-readable access flags.
248 *
249 * In the base language the access_flags fields are type u2; in Dalvik
250 * they're u4.
251 */
252static char* createAccessFlagStr(u4 flags, AccessFor forWhat)
253{
254#define NUM_FLAGS 18
255 static const char* kAccessStrings[kAccessForMAX][NUM_FLAGS] = {
Carl Shapirode750892010-06-08 16:37:12 -0700256 {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800257 /* class, inner class */
258 "PUBLIC", /* 0x0001 */
259 "PRIVATE", /* 0x0002 */
260 "PROTECTED", /* 0x0004 */
261 "STATIC", /* 0x0008 */
262 "FINAL", /* 0x0010 */
263 "?", /* 0x0020 */
264 "?", /* 0x0040 */
265 "?", /* 0x0080 */
266 "?", /* 0x0100 */
267 "INTERFACE", /* 0x0200 */
268 "ABSTRACT", /* 0x0400 */
269 "?", /* 0x0800 */
270 "SYNTHETIC", /* 0x1000 */
271 "ANNOTATION", /* 0x2000 */
272 "ENUM", /* 0x4000 */
273 "?", /* 0x8000 */
274 "VERIFIED", /* 0x10000 */
275 "OPTIMIZED", /* 0x20000 */
276 },
277 {
278 /* method */
279 "PUBLIC", /* 0x0001 */
280 "PRIVATE", /* 0x0002 */
281 "PROTECTED", /* 0x0004 */
282 "STATIC", /* 0x0008 */
283 "FINAL", /* 0x0010 */
284 "SYNCHRONIZED", /* 0x0020 */
285 "BRIDGE", /* 0x0040 */
286 "VARARGS", /* 0x0080 */
287 "NATIVE", /* 0x0100 */
288 "?", /* 0x0200 */
289 "ABSTRACT", /* 0x0400 */
290 "STRICT", /* 0x0800 */
291 "SYNTHETIC", /* 0x1000 */
292 "?", /* 0x2000 */
293 "?", /* 0x4000 */
294 "MIRANDA", /* 0x8000 */
295 "CONSTRUCTOR", /* 0x10000 */
296 "DECLARED_SYNCHRONIZED", /* 0x20000 */
297 },
298 {
299 /* field */
300 "PUBLIC", /* 0x0001 */
301 "PRIVATE", /* 0x0002 */
302 "PROTECTED", /* 0x0004 */
303 "STATIC", /* 0x0008 */
304 "FINAL", /* 0x0010 */
305 "?", /* 0x0020 */
306 "VOLATILE", /* 0x0040 */
307 "TRANSIENT", /* 0x0080 */
308 "?", /* 0x0100 */
309 "?", /* 0x0200 */
310 "?", /* 0x0400 */
311 "?", /* 0x0800 */
312 "SYNTHETIC", /* 0x1000 */
313 "?", /* 0x2000 */
314 "ENUM", /* 0x4000 */
315 "?", /* 0x8000 */
316 "?", /* 0x10000 */
317 "?", /* 0x20000 */
318 },
319 };
320 const int kLongest = 21; /* strlen of longest string above */
321 int i, count;
322 char* str;
323 char* cp;
324
325 /*
326 * Allocate enough storage to hold the expected number of strings,
327 * plus a space between each. We over-allocate, using the longest
328 * string above as the base metric.
329 */
330 count = countOnes(flags);
331 cp = str = (char*) malloc(count * (kLongest+1) +1);
332
333 for (i = 0; i < NUM_FLAGS; i++) {
334 if (flags & 0x01) {
335 const char* accessStr = kAccessStrings[forWhat][i];
336 int len = strlen(accessStr);
337 if (cp != str)
338 *cp++ = ' ';
339
340 memcpy(cp, accessStr, len);
341 cp += len;
342 }
343 flags >>= 1;
344 }
345 *cp = '\0';
346
347 return str;
348}
349
350
351/*
Andy McFadden0ea77b92010-04-20 14:18:59 -0700352 * Copy character data from "data" to "out", converting non-ASCII values
353 * to printf format chars or an ASCII filler ('.' or '?').
354 *
355 * The output buffer must be able to hold (2*len)+1 bytes. The result is
356 * NUL-terminated.
357 */
358static void asciify(char* out, const unsigned char* data, size_t len)
359{
360 while (len--) {
361 if (*data < 0x20) {
362 /* could do more here, but we don't need them yet */
363 switch (*data) {
364 case '\0':
365 *out++ = '\\';
366 *out++ = '0';
367 break;
368 case '\n':
369 *out++ = '\\';
370 *out++ = 'n';
371 break;
372 default:
373 *out++ = '.';
374 break;
375 }
376 } else if (*data >= 0x80) {
377 *out++ = '?';
378 } else {
379 *out++ = *data;
380 }
381 data++;
382 }
383 *out = '\0';
384}
385
386/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800387 * Dump the file header.
388 */
389void dumpFileHeader(const DexFile* pDexFile)
390{
Andy McFadden0ea77b92010-04-20 14:18:59 -0700391 const DexOptHeader* pOptHeader = pDexFile->pOptHeader;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800392 const DexHeader* pHeader = pDexFile->pHeader;
Andy McFadden0ea77b92010-04-20 14:18:59 -0700393 char sanitized[sizeof(pHeader->magic)*2 +1];
394
395 assert(sizeof(pHeader->magic) == sizeof(pOptHeader->magic));
396
397 if (pOptHeader != NULL) {
398 printf("Optimized DEX file header:\n");
399
400 asciify(sanitized, pOptHeader->magic, sizeof(pOptHeader->magic));
401 printf("magic : '%s'\n", sanitized);
402 printf("dex_offset : %d (0x%06x)\n",
403 pOptHeader->dexOffset, pOptHeader->dexOffset);
404 printf("dex_length : %d\n", pOptHeader->dexLength);
405 printf("deps_offset : %d (0x%06x)\n",
406 pOptHeader->depsOffset, pOptHeader->depsOffset);
407 printf("deps_length : %d\n", pOptHeader->depsLength);
Dan Bornsteine377ef62010-08-31 16:50:00 -0700408 printf("opt_offset : %d (0x%06x)\n",
409 pOptHeader->optOffset, pOptHeader->optOffset);
410 printf("opt_length : %d\n", pOptHeader->optLength);
Andy McFadden0ea77b92010-04-20 14:18:59 -0700411 printf("flags : %08x\n", pOptHeader->flags);
412 printf("checksum : %08x\n", pOptHeader->checksum);
413 printf("\n");
414 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800415
416 printf("DEX file header:\n");
Andy McFadden0ea77b92010-04-20 14:18:59 -0700417 asciify(sanitized, pHeader->magic, sizeof(pHeader->magic));
418 printf("magic : '%s'\n", sanitized);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800419 printf("checksum : %08x\n", pHeader->checksum);
420 printf("signature : %02x%02x...%02x%02x\n",
421 pHeader->signature[0], pHeader->signature[1],
422 pHeader->signature[kSHA1DigestLen-2],
423 pHeader->signature[kSHA1DigestLen-1]);
424 printf("file_size : %d\n", pHeader->fileSize);
425 printf("header_size : %d\n", pHeader->headerSize);
426 printf("link_size : %d\n", pHeader->linkSize);
427 printf("link_off : %d (0x%06x)\n",
428 pHeader->linkOff, pHeader->linkOff);
429 printf("string_ids_size : %d\n", pHeader->stringIdsSize);
430 printf("string_ids_off : %d (0x%06x)\n",
431 pHeader->stringIdsOff, pHeader->stringIdsOff);
432 printf("type_ids_size : %d\n", pHeader->typeIdsSize);
433 printf("type_ids_off : %d (0x%06x)\n",
434 pHeader->typeIdsOff, pHeader->typeIdsOff);
435 printf("field_ids_size : %d\n", pHeader->fieldIdsSize);
436 printf("field_ids_off : %d (0x%06x)\n",
437 pHeader->fieldIdsOff, pHeader->fieldIdsOff);
438 printf("method_ids_size : %d\n", pHeader->methodIdsSize);
439 printf("method_ids_off : %d (0x%06x)\n",
440 pHeader->methodIdsOff, pHeader->methodIdsOff);
441 printf("class_defs_size : %d\n", pHeader->classDefsSize);
442 printf("class_defs_off : %d (0x%06x)\n",
443 pHeader->classDefsOff, pHeader->classDefsOff);
444 printf("data_size : %d\n", pHeader->dataSize);
445 printf("data_off : %d (0x%06x)\n",
446 pHeader->dataOff, pHeader->dataOff);
447 printf("\n");
448}
449
450/*
Dan Bornsteine377ef62010-08-31 16:50:00 -0700451 * Dump the "table of contents" for the opt area.
Andy McFadden0ea77b92010-04-20 14:18:59 -0700452 */
Dan Bornsteine377ef62010-08-31 16:50:00 -0700453void dumpOptDirectory(const DexFile* pDexFile)
Andy McFadden0ea77b92010-04-20 14:18:59 -0700454{
455 const DexOptHeader* pOptHeader = pDexFile->pOptHeader;
456 if (pOptHeader == NULL)
457 return;
458
Dan Bornsteine377ef62010-08-31 16:50:00 -0700459 printf("OPT section contents:\n");
Andy McFadden0ea77b92010-04-20 14:18:59 -0700460
Dan Bornsteine377ef62010-08-31 16:50:00 -0700461 const u4* pOpt = (const u4*) ((u1*) pOptHeader + pOptHeader->optOffset);
Andy McFadden0ea77b92010-04-20 14:18:59 -0700462
Dan Bornsteine377ef62010-08-31 16:50:00 -0700463 if (*pOpt == 0) {
Andy McFadden0ea77b92010-04-20 14:18:59 -0700464 printf("(1.0 format, only class lookup table is present)\n\n");
465 return;
466 }
467
468 /*
Dan Bornsteine377ef62010-08-31 16:50:00 -0700469 * The "opt" section is in "chunk" format: a 32-bit identifier, a 32-bit
Andy McFadden0ea77b92010-04-20 14:18:59 -0700470 * length, then the data. Chunks start on 64-bit boundaries.
471 */
Dan Bornsteine377ef62010-08-31 16:50:00 -0700472 while (*pOpt != kDexChunkEnd) {
Andy McFadden0ea77b92010-04-20 14:18:59 -0700473 const char* verboseStr;
474
Dan Bornsteine377ef62010-08-31 16:50:00 -0700475 u4 size = *(pOpt+1);
Andy McFadden0ea77b92010-04-20 14:18:59 -0700476
Dan Bornsteine377ef62010-08-31 16:50:00 -0700477 switch (*pOpt) {
Andy McFadden0ea77b92010-04-20 14:18:59 -0700478 case kDexChunkClassLookup:
479 verboseStr = "class lookup hash table";
480 break;
481 case kDexChunkRegisterMaps:
482 verboseStr = "register maps";
483 break;
Andy McFadden0ea77b92010-04-20 14:18:59 -0700484 default:
485 verboseStr = "(unknown chunk type)";
486 break;
487 }
488
Dan Bornsteine377ef62010-08-31 16:50:00 -0700489 printf("Chunk %08x (%c%c%c%c) - %s (%d bytes)\n", *pOpt,
490 *pOpt >> 24, (char)(*pOpt >> 16), (char)(*pOpt >> 8), (char)*pOpt,
Andy McFadden0ea77b92010-04-20 14:18:59 -0700491 verboseStr, size);
492
493 size = (size + 8 + 7) & ~7;
Dan Bornsteine377ef62010-08-31 16:50:00 -0700494 pOpt += size / sizeof(u4);
Andy McFadden0ea77b92010-04-20 14:18:59 -0700495 }
496 printf("\n");
497}
498
499/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800500 * Dump a class_def_item.
501 */
502void dumpClassDef(DexFile* pDexFile, int idx)
503{
504 const DexClassDef* pClassDef;
505 const u1* pEncodedData;
506 DexClassData* pClassData;
507
508 pClassDef = dexGetClassDef(pDexFile, idx);
509 pEncodedData = dexGetClassData(pDexFile, pClassDef);
510 pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL);
511
512 if (pClassData == NULL) {
513 fprintf(stderr, "Trouble reading class data\n");
514 return;
515 }
516
517 printf("Class #%d header:\n", idx);
518 printf("class_idx : %d\n", pClassDef->classIdx);
519 printf("access_flags : %d (0x%04x)\n",
520 pClassDef->accessFlags, pClassDef->accessFlags);
521 printf("superclass_idx : %d\n", pClassDef->superclassIdx);
522 printf("interfaces_off : %d (0x%06x)\n",
523 pClassDef->interfacesOff, pClassDef->interfacesOff);
524 printf("source_file_idx : %d\n", pClassDef->sourceFileIdx);
525 printf("annotations_off : %d (0x%06x)\n",
526 pClassDef->annotationsOff, pClassDef->annotationsOff);
527 printf("class_data_off : %d (0x%06x)\n",
528 pClassDef->classDataOff, pClassDef->classDataOff);
529 printf("static_fields_size : %d\n", pClassData->header.staticFieldsSize);
530 printf("instance_fields_size: %d\n",
531 pClassData->header.instanceFieldsSize);
532 printf("direct_methods_size : %d\n", pClassData->header.directMethodsSize);
533 printf("virtual_methods_size: %d\n",
534 pClassData->header.virtualMethodsSize);
535 printf("\n");
536
537 free(pClassData);
538}
539
540/*
Andy McFaddena2ee53b2009-05-05 16:52:10 -0700541 * Dump an interface that a class declares to implement.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800542 */
543void dumpInterface(const DexFile* pDexFile, const DexTypeItem* pTypeItem,
544 int i)
545{
546 const char* interfaceName =
547 dexStringByTypeIdx(pDexFile, pTypeItem->typeIdx);
548
Andy McFaddena2ee53b2009-05-05 16:52:10 -0700549 if (gOptions.outputFormat == OUTPUT_PLAIN) {
550 printf(" #%d : '%s'\n", i, interfaceName);
551 } else {
552 char* dotted = descriptorToDot(interfaceName);
553 printf("<implements name=\"%s\">\n</implements>\n", dotted);
554 free(dotted);
555 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800556}
557
558/*
559 * Dump the catches table associated with the code.
560 */
561void dumpCatches(DexFile* pDexFile, const DexCode* pCode)
562{
563 u4 triesSize = pCode->triesSize;
564
565 if (triesSize == 0) {
566 printf(" catches : (none)\n");
567 return;
Carl Shapirode750892010-06-08 16:37:12 -0700568 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800569
570 printf(" catches : %d\n", triesSize);
571
572 const DexTry* pTries = dexGetTries(pCode);
573 u4 i;
574
575 for (i = 0; i < triesSize; i++) {
576 const DexTry* pTry = &pTries[i];
577 u4 start = pTry->startAddr;
578 u4 end = start + pTry->insnCount;
579 DexCatchIterator iterator;
Carl Shapirode750892010-06-08 16:37:12 -0700580
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800581 printf(" 0x%04x - 0x%04x\n", start, end);
582
583 dexCatchIteratorInit(&iterator, pCode, pTry->handlerOff);
584
585 for (;;) {
586 DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
587 const char* descriptor;
Carl Shapirode750892010-06-08 16:37:12 -0700588
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800589 if (handler == NULL) {
590 break;
591 }
Carl Shapirode750892010-06-08 16:37:12 -0700592
593 descriptor = (handler->typeIdx == kDexNoIndex) ? "<any>" :
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800594 dexStringByTypeIdx(pDexFile, handler->typeIdx);
Carl Shapirode750892010-06-08 16:37:12 -0700595
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800596 printf(" %s -> 0x%04x\n", descriptor,
597 handler->address);
598 }
599 }
600}
601
602static int dumpPositionsCb(void *cnxt, u4 address, u4 lineNum)
603{
604 printf(" 0x%04x line=%d\n", address, lineNum);
605 return 0;
606}
607
608/*
609 * Dump the positions list.
610 */
Carl Shapirode750892010-06-08 16:37:12 -0700611void dumpPositions(DexFile* pDexFile, const DexCode* pCode,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800612 const DexMethod *pDexMethod)
613{
614 printf(" positions : \n");
Carl Shapirode750892010-06-08 16:37:12 -0700615 const DexMethodId *pMethodId
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800616 = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
617 const char *classDescriptor
618 = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
619
620 dexDecodeDebugInfo(pDexFile, pCode, classDescriptor, pMethodId->protoIdx,
621 pDexMethod->accessFlags, dumpPositionsCb, NULL, NULL);
622}
623
624static void dumpLocalsCb(void *cnxt, u2 reg, u4 startAddress,
625 u4 endAddress, const char *name, const char *descriptor,
626 const char *signature)
627{
628 printf(" 0x%04x - 0x%04x reg=%d %s %s %s\n",
Carl Shapirode750892010-06-08 16:37:12 -0700629 startAddress, endAddress, reg, name, descriptor,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800630 signature);
631}
632
633/*
634 * Dump the locals list.
635 */
636void dumpLocals(DexFile* pDexFile, const DexCode* pCode,
637 const DexMethod *pDexMethod)
638{
639 printf(" locals : \n");
640
Carl Shapirode750892010-06-08 16:37:12 -0700641 const DexMethodId *pMethodId
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800642 = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
Carl Shapirode750892010-06-08 16:37:12 -0700643 const char *classDescriptor
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800644 = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
645
646 dexDecodeDebugInfo(pDexFile, pCode, classDescriptor, pMethodId->protoIdx,
647 pDexMethod->accessFlags, NULL, dumpLocalsCb, NULL);
648}
649
650/*
651 * Get information about a method.
652 */
653bool getMethodInfo(DexFile* pDexFile, u4 methodIdx, FieldMethodInfo* pMethInfo)
654{
655 const DexMethodId* pMethodId;
656
657 if (methodIdx >= pDexFile->pHeader->methodIdsSize)
658 return false;
659
660 pMethodId = dexGetMethodId(pDexFile, methodIdx);
661 pMethInfo->name = dexStringById(pDexFile, pMethodId->nameIdx);
662 pMethInfo->signature = dexCopyDescriptorFromMethodId(pDexFile, pMethodId);
663
Carl Shapirode750892010-06-08 16:37:12 -0700664 pMethInfo->classDescriptor =
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800665 dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
666 return true;
667}
668
669/*
670 * Get information about a field.
671 */
672bool getFieldInfo(DexFile* pDexFile, u4 fieldIdx, FieldMethodInfo* pFieldInfo)
673{
674 const DexFieldId* pFieldId;
675
676 if (fieldIdx >= pDexFile->pHeader->fieldIdsSize)
677 return false;
678
679 pFieldId = dexGetFieldId(pDexFile, fieldIdx);
680 pFieldInfo->name = dexStringById(pDexFile, pFieldId->nameIdx);
681 pFieldInfo->signature = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx);
682 pFieldInfo->classDescriptor =
683 dexStringByTypeIdx(pDexFile, pFieldId->classIdx);
684 return true;
685}
686
687
688/*
689 * Look up a class' descriptor.
690 */
691const char* getClassDescriptor(DexFile* pDexFile, u4 classIdx)
692{
693 return dexStringByTypeIdx(pDexFile, classIdx);
694}
695
696/*
Dan Bornstein4a6b4822010-11-11 12:26:58 -0800697 * Helper for dumpInstruction(), which builds the string
698 * representation for the index in the given instruction. This will
699 * first try to use the given buffer, but if the result won't fit,
700 * then this will allocate a new buffer to hold the result. A pointer
701 * to the buffer which holds the full result is always returned, and
702 * this can be compared with the one passed in, to see if the result
703 * needs to be free()d.
704 */
705static char* indexString(DexFile* pDexFile,
706 const DecodedInstruction* pDecInsn, char* buf, size_t bufSize)
707{
708 int outSize;
709 u4 index;
710 u4 width;
711
712 /* TODO: Make the index *always* be in field B, to simplify this code. */
713 switch (dexGetInstrFormat(gInstrInfo.formats, pDecInsn->opCode)) {
714 case kFmt20bc:
715 case kFmt21c:
716 case kFmt35c:
717 case kFmt35ms:
718 case kFmt3rc:
719 case kFmt3rms:
720 case kFmt35mi:
721 case kFmt3rmi:
722 index = pDecInsn->vB;
723 width = 4;
724 break;
725 case kFmt31c:
726 case kFmt41c:
727 case kFmt5rc:
728 index = pDecInsn->vB;
729 width = 8;
730 break;
731 case kFmt22c:
732 case kFmt22cs:
733 index = pDecInsn->vC;
734 width = 4;
735 break;
736 case kFmt52c:
737 index = pDecInsn->vC;
738 width = 8;
739 break;
740 default:
741 index = 0;
742 width = 4;
743 break;
744 }
745
746 switch (pDecInsn->indexType) {
747 case kIndexUnknown:
748 /*
749 * This function shouldn't ever get called for this type, but do
750 * something sensible here, just to help with debugging.
751 */
752 outSize = snprintf(buf, bufSize, "<unknown-index>");
753 break;
754 case kIndexNone:
755 /*
756 * This function shouldn't ever get called for this type, but do
757 * something sensible here, just to help with debugging.
758 */
759 outSize = snprintf(buf, bufSize, "<no-index>");
760 break;
761 case kIndexVaries:
762 /*
763 * This one should never show up in a dexdump, so no need to try
764 * to get fancy here.
765 */
766 outSize = snprintf(buf, bufSize, "<index-varies> // thing@%0*x",
767 width, index);
768 break;
Dan Bornstein1530c3e2010-11-12 12:51:35 -0800769 case kIndexTypeRef:
770 outSize = snprintf(buf, bufSize, "%s // type@%0*x",
Dan Bornstein4a6b4822010-11-11 12:26:58 -0800771 getClassDescriptor(pDexFile, index), width, index);
772 break;
773 case kIndexStringRef:
774 outSize = snprintf(buf, bufSize, "\"%s\" // string@%0*x",
775 dexStringById(pDexFile, index), width, index);
776 break;
777 case kIndexMethodRef:
778 {
779 FieldMethodInfo methInfo;
780 if (getMethodInfo(pDexFile, index, &methInfo)) {
781 outSize = snprintf(buf, bufSize, "%s.%s:%s // method@%0*x",
782 methInfo.classDescriptor, methInfo.name,
783 methInfo.signature, width, index);
784 } else {
785 outSize = snprintf(buf, bufSize, "<method?> // method@%0*x",
786 width, index);
787 }
788 }
789 break;
790 case kIndexFieldRef:
791 {
792 FieldMethodInfo fieldInfo;
793 if (getFieldInfo(pDexFile, index, &fieldInfo)) {
794 outSize = snprintf(buf, bufSize, "%s.%s:%s // field@%0*x",
795 fieldInfo.classDescriptor, fieldInfo.name,
796 fieldInfo.signature, width, index);
797 } else {
798 outSize = snprintf(buf, bufSize, "<field?> // field@%0*x",
799 width, index);
800 }
801 }
802 break;
803 case kIndexInlineMethod:
804 outSize = snprintf(buf, bufSize, "[%0*x] // inline #%0*x",
805 width, index, width, index);
806 break;
807 case kIndexVtableOffset:
808 outSize = snprintf(buf, bufSize, "[%0*x] // vtable #%0*x",
809 width, index, width, index);
810 break;
811 case kIndexFieldOffset:
812 outSize = snprintf(buf, bufSize, "[obj+%0*x]", width, index);
813 break;
814 default:
815 outSize = snprintf(buf, bufSize, "<?>");
816 break;
817 }
818
819 if (outSize >= (int) bufSize) {
820 /*
821 * The buffer wasn't big enough; allocate and retry. Note:
822 * snprintf() doesn't count the '\0' as part of its returned
823 * size, so we add explicit space for it here.
824 */
825 outSize++;
826 buf = malloc(outSize);
827 if (buf == NULL) {
828 return NULL;
829 }
830 return indexString(pDexFile, pDecInsn, buf, outSize);
831 } else {
832 return buf;
833 }
834}
835
836/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800837 * Dump a single instruction.
838 */
839void dumpInstruction(DexFile* pDexFile, const DexCode* pCode, int insnIdx,
840 int insnWidth, const DecodedInstruction* pDecInsn)
841{
Dan Bornstein4a6b4822010-11-11 12:26:58 -0800842 char indexBufChars[200];
843 char *indexBuf = indexBufChars;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800844 const u2* insns = pCode->insns;
845 int i;
846
847 printf("%06x:", ((u1*)insns - pDexFile->baseAddr) + insnIdx*2);
848 for (i = 0; i < 8; i++) {
849 if (i < insnWidth) {
850 if (i == 7) {
851 printf(" ... ");
852 } else {
853 /* print 16-bit value in little-endian order */
854 const u1* bytePtr = (const u1*) &insns[insnIdx+i];
855 printf(" %02x%02x", bytePtr[0], bytePtr[1]);
856 }
857 } else {
858 fputs(" ", stdout);
859 }
860 }
861
862 if (pDecInsn->opCode == OP_NOP) {
863 u2 instr = get2LE((const u1*) &insns[insnIdx]);
864 if (instr == kPackedSwitchSignature) {
865 printf("|%04x: packed-switch-data (%d units)",
866 insnIdx, insnWidth);
867 } else if (instr == kSparseSwitchSignature) {
868 printf("|%04x: sparse-switch-data (%d units)",
869 insnIdx, insnWidth);
870 } else if (instr == kArrayDataSignature) {
871 printf("|%04x: array-data (%d units)",
872 insnIdx, insnWidth);
873 } else {
874 printf("|%04x: nop // spacer", insnIdx);
875 }
876 } else {
Andy McFaddenc6b25c72010-06-22 11:01:20 -0700877 printf("|%04x: %s", insnIdx, dexGetOpcodeName(pDecInsn->opCode));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800878 }
879
Dan Bornstein4a6b4822010-11-11 12:26:58 -0800880 if (pDecInsn->indexType != kIndexNone) {
881 indexBuf = indexString(pDexFile, pDecInsn,
882 indexBufChars, sizeof(indexBufChars));
883 }
884
Dan Bornstein44a38f42010-11-10 17:34:32 -0800885 switch (dexGetInstrFormat(gInstrInfo.formats, pDecInsn->opCode)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800886 case kFmt10x: // op
887 break;
888 case kFmt12x: // op vA, vB
889 printf(" v%d, v%d", pDecInsn->vA, pDecInsn->vB);
890 break;
891 case kFmt11n: // op vA, #+B
892 printf(" v%d, #int %d // #%x",
893 pDecInsn->vA, (s4)pDecInsn->vB, (u1)pDecInsn->vB);
894 break;
895 case kFmt11x: // op vAA
896 printf(" v%d", pDecInsn->vA);
897 break;
898 case kFmt10t: // op +AA
899 case kFmt20t: // op +AAAA
900 {
901 s4 targ = (s4) pDecInsn->vA;
902 printf(" %04x // %c%04x",
903 insnIdx + targ,
904 (targ < 0) ? '-' : '+',
905 (targ < 0) ? -targ : targ);
906 }
907 break;
908 case kFmt22x: // op vAA, vBBBB
909 printf(" v%d, v%d", pDecInsn->vA, pDecInsn->vB);
910 break;
911 case kFmt21t: // op vAA, +BBBB
912 {
913 s4 targ = (s4) pDecInsn->vB;
914 printf(" v%d, %04x // %c%04x", pDecInsn->vA,
915 insnIdx + targ,
916 (targ < 0) ? '-' : '+',
917 (targ < 0) ? -targ : targ);
918 }
919 break;
920 case kFmt21s: // op vAA, #+BBBB
921 printf(" v%d, #int %d // #%x",
922 pDecInsn->vA, (s4)pDecInsn->vB, (u2)pDecInsn->vB);
923 break;
924 case kFmt21h: // op vAA, #+BBBB0000[00000000]
925 // The printed format varies a bit based on the actual opcode.
926 if (pDecInsn->opCode == OP_CONST_HIGH16) {
927 s4 value = pDecInsn->vB << 16;
928 printf(" v%d, #int %d // #%x",
929 pDecInsn->vA, value, (u2)pDecInsn->vB);
930 } else {
931 s8 value = ((s8) pDecInsn->vB) << 48;
932 printf(" v%d, #long %lld // #%x",
933 pDecInsn->vA, value, (u2)pDecInsn->vB);
934 }
935 break;
936 case kFmt21c: // op vAA, thing@BBBB
Dan Bornstein4a6b4822010-11-11 12:26:58 -0800937 case kFmt31c: // op vAA, thing@BBBBBBBB
938 case kFmt41c: // exop vAAAA, thing@BBBBBBBB
939 printf(" v%d, %s", pDecInsn->vA, indexBuf);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800940 break;
941 case kFmt23x: // op vAA, vBB, vCC
Dan Bornstein4a6b4822010-11-11 12:26:58 -0800942 case kFmt33x: // exop vAA, vBB, vCCCC
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800943 printf(" v%d, v%d, v%d", pDecInsn->vA, pDecInsn->vB, pDecInsn->vC);
944 break;
945 case kFmt22b: // op vAA, vBB, #+CC
946 printf(" v%d, v%d, #int %d // #%02x",
947 pDecInsn->vA, pDecInsn->vB, (s4)pDecInsn->vC, (u1)pDecInsn->vC);
948 break;
949 case kFmt22t: // op vA, vB, +CCCC
950 {
951 s4 targ = (s4) pDecInsn->vC;
952 printf(" v%d, v%d, %04x // %c%04x", pDecInsn->vA, pDecInsn->vB,
953 insnIdx + targ,
954 (targ < 0) ? '-' : '+',
955 (targ < 0) ? -targ : targ);
956 }
957 break;
958 case kFmt22s: // op vA, vB, #+CCCC
Dan Bornstein4a6b4822010-11-11 12:26:58 -0800959 case kFmt32s: // exop vAA, vBB, #+CCCC
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800960 printf(" v%d, v%d, #int %d // #%04x",
961 pDecInsn->vA, pDecInsn->vB, (s4)pDecInsn->vC, (u2)pDecInsn->vC);
962 break;
963 case kFmt22c: // op vA, vB, thing@CCCC
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800964 case kFmt22cs: // [opt] op vA, vB, field offset CCCC
Dan Bornstein4a6b4822010-11-11 12:26:58 -0800965 case kFmt52c: // exop vAAAA, vBBBB, thing@CCCCCCCC
966 printf(" v%d, v%d, %s", pDecInsn->vA, pDecInsn->vB, indexBuf);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800967 break;
968 case kFmt30t:
969 printf(" #%08x", pDecInsn->vA);
970 break;
971 case kFmt31i: // op vAA, #+BBBBBBBB
972 {
973 /* this is often, but not always, a float */
974 union {
975 float f;
976 u4 i;
977 } conv;
978 conv.i = pDecInsn->vB;
979 printf(" v%d, #float %f // #%08x",
980 pDecInsn->vA, conv.f, pDecInsn->vB);
981 }
982 break;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800983 case kFmt31t: // op vAA, offset +BBBBBBBB
984 printf(" v%d, %08x // +%08x",
985 pDecInsn->vA, insnIdx + pDecInsn->vB, pDecInsn->vB);
986 break;
987 case kFmt32x: // op vAAAA, vBBBB
988 printf(" v%d, v%d", pDecInsn->vA, pDecInsn->vB);
989 break;
Dan Bornstein7b3e9b02010-11-09 17:15:10 -0800990 case kFmt35c: // op {vC, vD, vE, vF, vG}, thing@BBBB
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800991 case kFmt35ms: // [opt] invoke-virtual+super
Dan Bornstein7b3e9b02010-11-09 17:15:10 -0800992 case kFmt35mi: // [opt] inline invoke
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800993 {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800994 fputs(" {", stdout);
995 for (i = 0; i < (int) pDecInsn->vA; i++) {
996 if (i == 0)
997 printf("v%d", pDecInsn->arg[i]);
998 else
999 printf(", v%d", pDecInsn->arg[i]);
1000 }
Dan Bornstein4a6b4822010-11-11 12:26:58 -08001001 printf("}, %s", indexBuf);
1002 }
1003 break;
1004 case kFmt3rc: // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB
1005 case kFmt3rms: // [opt] invoke-virtual+super/range
1006 case kFmt3rmi: // [opt] execute-inline/range
1007 case kFmt5rc: // exop {vCCCC .. v(CCCC+AAAA-1)}, meth@BBBBBBBB
1008 {
1009 /*
1010 * This doesn't match the "dx" output when some of the args are
1011 * 64-bit values -- dx only shows the first register.
1012 */
1013 fputs(" {", stdout);
1014 for (i = 0; i < (int) pDecInsn->vA; i++) {
1015 if (i == 0)
1016 printf("v%d", pDecInsn->vC + i);
1017 else
1018 printf(", v%d", pDecInsn->vC + i);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001019 }
Dan Bornstein4a6b4822010-11-11 12:26:58 -08001020 printf("}, %s", indexBuf);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001021 }
1022 break;
1023 case kFmt51l: // op vAA, #+BBBBBBBBBBBBBBBB
1024 {
1025 /* this is often, but not always, a double */
1026 union {
1027 double d;
1028 u8 j;
1029 } conv;
1030 conv.j = pDecInsn->vB_wide;
1031 printf(" v%d, #double %f // #%016llx",
1032 pDecInsn->vA, conv.d, pDecInsn->vB_wide);
1033 }
1034 break;
Dan Bornstein84244322010-11-17 12:05:04 -08001035 case kFmt00x: // unknown op or breakpoint
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001036 break;
1037 default:
1038 printf(" ???");
1039 break;
1040 }
1041
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001042 putchar('\n');
1043
Dan Bornstein4a6b4822010-11-11 12:26:58 -08001044 if (indexBuf != indexBufChars) {
1045 free(indexBuf);
1046 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001047}
1048
1049/*
1050 * Dump a bytecode disassembly.
1051 */
1052void dumpBytecodes(DexFile* pDexFile, const DexMethod* pDexMethod)
1053{
1054 const DexCode* pCode = dexGetCode(pDexFile, pDexMethod);
1055 const u2* insns;
1056 int insnIdx;
1057 FieldMethodInfo methInfo;
1058 int startAddr;
1059 char* className = NULL;
1060
1061 assert(pCode->insnsSize > 0);
1062 insns = pCode->insns;
1063
1064 getMethodInfo(pDexFile, pDexMethod->methodIdx, &methInfo);
1065 startAddr = ((u1*)pCode - pDexFile->baseAddr);
1066 className = descriptorToDot(methInfo.classDescriptor);
1067
1068 printf("%06x: |[%06x] %s.%s:%s\n",
1069 startAddr, startAddr,
1070 className, methInfo.name, methInfo.signature);
1071
1072 insnIdx = 0;
1073 while (insnIdx < (int) pCode->insnsSize) {
1074 int insnWidth;
1075 OpCode opCode;
1076 DecodedInstruction decInsn;
1077 u2 instr;
1078
1079 instr = get2LE((const u1*)insns);
1080 if (instr == kPackedSwitchSignature) {
1081 insnWidth = 4 + get2LE((const u1*)(insns+1)) * 2;
1082 } else if (instr == kSparseSwitchSignature) {
1083 insnWidth = 2 + get2LE((const u1*)(insns+1)) * 4;
1084 } else if (instr == kArrayDataSignature) {
1085 int width = get2LE((const u1*)(insns+1));
Carl Shapirode750892010-06-08 16:37:12 -07001086 int size = get2LE((const u1*)(insns+2)) |
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001087 (get2LE((const u1*)(insns+3))<<16);
Carl Shapirode750892010-06-08 16:37:12 -07001088 // The plus 1 is to round up for odd size and width
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001089 insnWidth = 4 + ((size * width) + 1) / 2;
1090 } else {
1091 opCode = instr & 0xff;
Andy McFaddena0929372010-11-11 16:49:22 -08001092 insnWidth = dexGetInstrWidth(gInstrInfo.widths, opCode);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001093 if (insnWidth == 0) {
1094 fprintf(stderr,
1095 "GLITCH: zero-width instruction at idx=0x%04x\n", insnIdx);
1096 break;
1097 }
1098 }
1099
Dan Bornstein44a38f42010-11-10 17:34:32 -08001100 dexDecodeInstruction(&gInstrInfo, insns, &decInsn);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001101 dumpInstruction(pDexFile, pCode, insnIdx, insnWidth, &decInsn);
1102
1103 insns += insnWidth;
1104 insnIdx += insnWidth;
1105 }
1106
1107 free(className);
1108}
1109
1110/*
1111 * Dump a "code" struct.
1112 */
1113void dumpCode(DexFile* pDexFile, const DexMethod* pDexMethod)
1114{
1115 const DexCode* pCode = dexGetCode(pDexFile, pDexMethod);
1116
1117 printf(" registers : %d\n", pCode->registersSize);
1118 printf(" ins : %d\n", pCode->insSize);
1119 printf(" outs : %d\n", pCode->outsSize);
1120 printf(" insns size : %d 16-bit code units\n", pCode->insnsSize);
1121
1122 if (gOptions.disassemble)
1123 dumpBytecodes(pDexFile, pDexMethod);
1124
1125 dumpCatches(pDexFile, pCode);
1126 /* both of these are encoded in debug info */
1127 dumpPositions(pDexFile, pCode, pDexMethod);
1128 dumpLocals(pDexFile, pCode, pDexMethod);
1129}
1130
1131/*
1132 * Dump a method.
1133 */
1134void dumpMethod(DexFile* pDexFile, const DexMethod* pDexMethod, int i)
1135{
1136 const DexMethodId* pMethodId;
1137 const char* backDescriptor;
1138 const char* name;
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001139 char* typeDescriptor = NULL;
1140 char* accessStr = NULL;
1141
1142 if (gOptions.exportsOnly &&
1143 (pDexMethod->accessFlags & (ACC_PUBLIC | ACC_PROTECTED)) == 0)
1144 {
1145 return;
1146 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001147
1148 pMethodId = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
1149 name = dexStringById(pDexFile, pMethodId->nameIdx);
1150 typeDescriptor = dexCopyDescriptorFromMethodId(pDexFile, pMethodId);
1151
1152 backDescriptor = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
1153
1154 accessStr = createAccessFlagStr(pDexMethod->accessFlags,
1155 kAccessForMethod);
1156
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001157 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1158 printf(" #%d : (in %s)\n", i, backDescriptor);
1159 printf(" name : '%s'\n", name);
1160 printf(" type : '%s'\n", typeDescriptor);
1161 printf(" access : 0x%04x (%s)\n",
1162 pDexMethod->accessFlags, accessStr);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001163
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001164 if (pDexMethod->codeOff == 0) {
1165 printf(" code : (none)\n");
1166 } else {
1167 printf(" code -\n");
1168 dumpCode(pDexFile, pDexMethod);
1169 }
1170
1171 if (gOptions.disassemble)
1172 putchar('\n');
1173 } else if (gOptions.outputFormat == OUTPUT_XML) {
1174 bool constructor = (name[0] == '<');
1175
1176 if (constructor) {
1177 char* tmp;
1178
1179 tmp = descriptorClassToDot(backDescriptor);
1180 printf("<constructor name=\"%s\"\n", tmp);
1181 free(tmp);
1182
1183 tmp = descriptorToDot(backDescriptor);
1184 printf(" type=\"%s\"\n", tmp);
1185 free(tmp);
1186 } else {
1187 printf("<method name=\"%s\"\n", name);
1188
1189 const char* returnType = strrchr(typeDescriptor, ')');
1190 if (returnType == NULL) {
1191 fprintf(stderr, "bad method type descriptor '%s'\n",
1192 typeDescriptor);
1193 goto bail;
1194 }
1195
1196 char* tmp = descriptorToDot(returnType+1);
1197 printf(" return=\"%s\"\n", tmp);
1198 free(tmp);
1199
1200 printf(" abstract=%s\n",
1201 quotedBool((pDexMethod->accessFlags & ACC_ABSTRACT) != 0));
1202 printf(" native=%s\n",
1203 quotedBool((pDexMethod->accessFlags & ACC_NATIVE) != 0));
1204
1205 bool isSync =
1206 (pDexMethod->accessFlags & ACC_SYNCHRONIZED) != 0 ||
1207 (pDexMethod->accessFlags & ACC_DECLARED_SYNCHRONIZED) != 0;
1208 printf(" synchronized=%s\n", quotedBool(isSync));
1209 }
1210
1211 printf(" static=%s\n",
1212 quotedBool((pDexMethod->accessFlags & ACC_STATIC) != 0));
1213 printf(" final=%s\n",
1214 quotedBool((pDexMethod->accessFlags & ACC_FINAL) != 0));
1215 // "deprecated=" not knowable w/o parsing annotations
1216 printf(" visibility=%s\n",
1217 quotedVisibility(pDexMethod->accessFlags));
1218
1219 printf(">\n");
1220
1221 /*
1222 * Parameters.
1223 */
1224 if (typeDescriptor[0] != '(') {
1225 fprintf(stderr, "ERROR: bad descriptor '%s'\n", typeDescriptor);
1226 goto bail;
1227 }
1228
1229 char tmpBuf[strlen(typeDescriptor)+1]; /* more than big enough */
1230 int argNum = 0;
1231
1232 const char* base = typeDescriptor+1;
1233
1234 while (*base != ')') {
1235 char* cp = tmpBuf;
1236
1237 while (*base == '[')
1238 *cp++ = *base++;
1239
1240 if (*base == 'L') {
1241 /* copy through ';' */
1242 do {
1243 *cp = *base++;
1244 } while (*cp++ != ';');
1245 } else {
1246 /* primitive char, copy it */
1247 if (strchr("ZBCSIFJD", *base) == NULL) {
1248 fprintf(stderr, "ERROR: bad method signature '%s'\n", base);
1249 goto bail;
1250 }
1251 *cp++ = *base++;
1252 }
1253
1254 /* null terminate and display */
1255 *cp++ = '\0';
1256
1257 char* tmp = descriptorToDot(tmpBuf);
1258 printf("<parameter name=\"arg%d\" type=\"%s\">\n</parameter>\n",
1259 argNum++, tmp);
1260 free(tmp);
1261 }
1262
1263 if (constructor)
1264 printf("</constructor>\n");
1265 else
1266 printf("</method>\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001267 }
1268
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001269bail:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001270 free(typeDescriptor);
1271 free(accessStr);
1272}
1273
1274/*
1275 * Dump a static (class) field.
1276 */
1277void dumpSField(const DexFile* pDexFile, const DexField* pSField, int i)
1278{
1279 const DexFieldId* pFieldId;
1280 const char* backDescriptor;
1281 const char* name;
1282 const char* typeDescriptor;
1283 char* accessStr;
1284
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001285 if (gOptions.exportsOnly &&
1286 (pSField->accessFlags & (ACC_PUBLIC | ACC_PROTECTED)) == 0)
1287 {
1288 return;
1289 }
1290
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001291 pFieldId = dexGetFieldId(pDexFile, pSField->fieldIdx);
1292 name = dexStringById(pDexFile, pFieldId->nameIdx);
1293 typeDescriptor = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx);
1294 backDescriptor = dexStringByTypeIdx(pDexFile, pFieldId->classIdx);
1295
1296 accessStr = createAccessFlagStr(pSField->accessFlags, kAccessForField);
1297
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001298 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1299 printf(" #%d : (in %s)\n", i, backDescriptor);
1300 printf(" name : '%s'\n", name);
1301 printf(" type : '%s'\n", typeDescriptor);
1302 printf(" access : 0x%04x (%s)\n",
1303 pSField->accessFlags, accessStr);
1304 } else if (gOptions.outputFormat == OUTPUT_XML) {
1305 char* tmp;
1306
1307 printf("<field name=\"%s\"\n", name);
1308
1309 tmp = descriptorToDot(typeDescriptor);
1310 printf(" type=\"%s\"\n", tmp);
1311 free(tmp);
1312
1313 printf(" transient=%s\n",
1314 quotedBool((pSField->accessFlags & ACC_TRANSIENT) != 0));
1315 printf(" volatile=%s\n",
1316 quotedBool((pSField->accessFlags & ACC_VOLATILE) != 0));
1317 // "value=" not knowable w/o parsing annotations
1318 printf(" static=%s\n",
1319 quotedBool((pSField->accessFlags & ACC_STATIC) != 0));
1320 printf(" final=%s\n",
1321 quotedBool((pSField->accessFlags & ACC_FINAL) != 0));
1322 // "deprecated=" not knowable w/o parsing annotations
1323 printf(" visibility=%s\n",
1324 quotedVisibility(pSField->accessFlags));
1325 printf(">\n</field>\n");
1326 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001327
1328 free(accessStr);
1329}
1330
1331/*
1332 * Dump an instance field.
1333 */
1334void dumpIField(const DexFile* pDexFile, const DexField* pIField, int i)
1335{
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001336 dumpSField(pDexFile, pIField, i);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001337}
1338
1339/*
1340 * Dump the class.
The Android Open Source Project99409882009-03-18 22:20:24 -07001341 *
1342 * Note "idx" is a DexClassDef index, not a DexTypeId index.
Andy McFaddend18aff32009-05-06 10:19:16 -07001343 *
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001344 * If "*pLastPackage" is NULL or does not match the current class' package,
1345 * the value will be replaced with a newly-allocated string.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001346 */
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001347void dumpClass(DexFile* pDexFile, int idx, char** pLastPackage)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001348{
1349 const DexTypeList* pInterfaces;
1350 const DexClassDef* pClassDef;
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001351 DexClassData* pClassData = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001352 const u1* pEncodedData;
1353 const char* fileName;
1354 const char* classDescriptor;
1355 const char* superclassDescriptor;
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001356 char* accessStr = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001357 int i;
1358
1359 pClassDef = dexGetClassDef(pDexFile, idx);
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001360
1361 if (gOptions.exportsOnly && (pClassDef->accessFlags & ACC_PUBLIC) == 0) {
1362 //printf("<!-- omitting non-public class %s -->\n",
1363 // classDescriptor);
1364 goto bail;
1365 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001366
1367 pEncodedData = dexGetClassData(pDexFile, pClassDef);
1368 pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL);
1369
1370 if (pClassData == NULL) {
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001371 printf("Trouble reading class data (#%d)\n", idx);
1372 goto bail;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001373 }
Carl Shapirode750892010-06-08 16:37:12 -07001374
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001375 classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001376
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001377 /*
1378 * For the XML output, show the package name. Ideally we'd gather
1379 * up the classes, sort them, and dump them alphabetically so the
1380 * package name wouldn't jump around, but that's not a great plan
1381 * for something that needs to run on the device.
1382 */
1383 if (!(classDescriptor[0] == 'L' &&
1384 classDescriptor[strlen(classDescriptor)-1] == ';'))
1385 {
1386 /* arrays and primitives should not be defined explicitly */
1387 fprintf(stderr, "Malformed class name '%s'\n", classDescriptor);
1388 /* keep going? */
1389 } else if (gOptions.outputFormat == OUTPUT_XML) {
1390 char* mangle;
1391 char* lastSlash;
1392 char* cp;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001393
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001394 mangle = strdup(classDescriptor + 1);
1395 mangle[strlen(mangle)-1] = '\0';
1396
1397 /* reduce to just the package name */
1398 lastSlash = strrchr(mangle, '/');
1399 if (lastSlash != NULL) {
1400 *lastSlash = '\0';
1401 } else {
1402 *mangle = '\0';
1403 }
1404
1405 for (cp = mangle; *cp != '\0'; cp++) {
1406 if (*cp == '/')
1407 *cp = '.';
1408 }
1409
1410 if (*pLastPackage == NULL || strcmp(mangle, *pLastPackage) != 0) {
1411 /* start of a new package */
1412 if (*pLastPackage != NULL)
1413 printf("</package>\n");
1414 printf("<package name=\"%s\"\n>\n", mangle);
1415 free(*pLastPackage);
1416 *pLastPackage = mangle;
1417 } else {
1418 free(mangle);
1419 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001420 }
1421
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001422 accessStr = createAccessFlagStr(pClassDef->accessFlags, kAccessForClass);
1423
1424 if (pClassDef->superclassIdx == kDexNoIndex) {
1425 superclassDescriptor = NULL;
1426 } else {
1427 superclassDescriptor =
1428 dexStringByTypeIdx(pDexFile, pClassDef->superclassIdx);
1429 }
1430
1431 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1432 printf("Class #%d -\n", idx);
1433 printf(" Class descriptor : '%s'\n", classDescriptor);
1434 printf(" Access flags : 0x%04x (%s)\n",
1435 pClassDef->accessFlags, accessStr);
1436
1437 if (superclassDescriptor != NULL)
1438 printf(" Superclass : '%s'\n", superclassDescriptor);
1439
1440 printf(" Interfaces -\n");
1441 } else {
1442 char* tmp;
1443
1444 tmp = descriptorClassToDot(classDescriptor);
1445 printf("<class name=\"%s\"\n", tmp);
1446 free(tmp);
1447
1448 if (superclassDescriptor != NULL) {
1449 tmp = descriptorToDot(superclassDescriptor);
1450 printf(" extends=\"%s\"\n", tmp);
1451 free(tmp);
1452 }
1453 printf(" abstract=%s\n",
1454 quotedBool((pClassDef->accessFlags & ACC_ABSTRACT) != 0));
1455 printf(" static=%s\n",
1456 quotedBool((pClassDef->accessFlags & ACC_STATIC) != 0));
1457 printf(" final=%s\n",
1458 quotedBool((pClassDef->accessFlags & ACC_FINAL) != 0));
1459 // "deprecated=" not knowable w/o parsing annotations
1460 printf(" visibility=%s\n",
1461 quotedVisibility(pClassDef->accessFlags));
1462 printf(">\n");
1463 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001464 pInterfaces = dexGetInterfacesList(pDexFile, pClassDef);
1465 if (pInterfaces != NULL) {
1466 for (i = 0; i < (int) pInterfaces->size; i++)
1467 dumpInterface(pDexFile, dexGetTypeItem(pInterfaces, i), i);
1468 }
1469
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001470 if (gOptions.outputFormat == OUTPUT_PLAIN)
1471 printf(" Static fields -\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001472 for (i = 0; i < (int) pClassData->header.staticFieldsSize; i++) {
1473 dumpSField(pDexFile, &pClassData->staticFields[i], i);
1474 }
1475
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001476 if (gOptions.outputFormat == OUTPUT_PLAIN)
1477 printf(" Instance fields -\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001478 for (i = 0; i < (int) pClassData->header.instanceFieldsSize; i++) {
1479 dumpIField(pDexFile, &pClassData->instanceFields[i], i);
1480 }
1481
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001482 if (gOptions.outputFormat == OUTPUT_PLAIN)
1483 printf(" Direct methods -\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001484 for (i = 0; i < (int) pClassData->header.directMethodsSize; i++) {
1485 dumpMethod(pDexFile, &pClassData->directMethods[i], i);
1486 }
1487
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001488 if (gOptions.outputFormat == OUTPUT_PLAIN)
1489 printf(" Virtual methods -\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001490 for (i = 0; i < (int) pClassData->header.virtualMethodsSize; i++) {
1491 dumpMethod(pDexFile, &pClassData->virtualMethods[i], i);
1492 }
1493
1494 // TODO: Annotations.
1495
1496 if (pClassDef->sourceFileIdx != kDexNoIndex)
1497 fileName = dexStringById(pDexFile, pClassDef->sourceFileIdx);
1498 else
1499 fileName = "unknown";
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001500
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001501 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1502 printf(" source_file_idx : %d (%s)\n",
1503 pClassDef->sourceFileIdx, fileName);
1504 printf("\n");
1505 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001506
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001507 if (gOptions.outputFormat == OUTPUT_XML) {
1508 printf("</class>\n");
1509 }
1510
1511bail:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001512 free(pClassData);
1513 free(accessStr);
1514}
1515
The Android Open Source Project99409882009-03-18 22:20:24 -07001516
1517/*
1518 * Advance "ptr" to ensure 32-bit alignment.
1519 */
1520static inline const u1* align32(const u1* ptr)
1521{
1522 return (u1*) (((int) ptr + 3) & ~0x03);
1523}
1524
Andy McFadden10351272009-03-24 21:30:32 -07001525
1526/*
1527 * Dump a map in the "differential" format.
1528 *
1529 * TODO: show a hex dump of the compressed data. (We can show the
1530 * uncompressed data if we move the compression code to libdex; otherwise
1531 * it's too complex to merit a fast & fragile implementation here.)
1532 */
1533void dumpDifferentialCompressedMap(const u1** pData)
1534{
1535 const u1* data = *pData;
1536 const u1* dataStart = data -1; // format byte already removed
1537 u1 regWidth;
1538 u2 numEntries;
1539
1540 /* standard header */
1541 regWidth = *data++;
1542 numEntries = *data++;
1543 numEntries |= (*data++) << 8;
1544
1545 /* compressed data begins with the compressed data length */
1546 int compressedLen = readUnsignedLeb128(&data);
1547 int addrWidth = 1;
1548 if ((*data & 0x80) != 0)
1549 addrWidth++;
1550
1551 int origLen = 4 + (addrWidth + regWidth) * numEntries;
1552 int compLen = (data - dataStart) + compressedLen;
1553
1554 printf(" (differential compression %d -> %d [%d -> %d])\n",
1555 origLen, compLen,
1556 (addrWidth + regWidth) * numEntries, compressedLen);
1557
1558 /* skip past end of entry */
1559 data += compressedLen;
1560
1561 *pData = data;
1562}
1563
The Android Open Source Project99409882009-03-18 22:20:24 -07001564/*
1565 * Dump register map contents of the current method.
1566 *
1567 * "*pData" should point to the start of the register map data. Advances
1568 * "*pData" to the start of the next map.
1569 */
1570void dumpMethodMap(DexFile* pDexFile, const DexMethod* pDexMethod, int idx,
1571 const u1** pData)
1572{
1573 const u1* data = *pData;
1574 const DexMethodId* pMethodId;
1575 const char* name;
1576 int offset = data - (u1*) pDexFile->pOptHeader;
1577
1578 pMethodId = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
1579 name = dexStringById(pDexFile, pMethodId->nameIdx);
1580 printf(" #%d: 0x%08x %s\n", idx, offset, name);
1581
1582 u1 format;
1583 int addrWidth;
1584
1585 format = *data++;
1586 if (format == 1) { /* kRegMapFormatNone */
1587 /* no map */
1588 printf(" (no map)\n");
1589 addrWidth = 0;
1590 } else if (format == 2) { /* kRegMapFormatCompact8 */
1591 addrWidth = 1;
1592 } else if (format == 3) { /* kRegMapFormatCompact16 */
1593 addrWidth = 2;
Andy McFadden10351272009-03-24 21:30:32 -07001594 } else if (format == 4) { /* kRegMapFormatDifferential */
1595 dumpDifferentialCompressedMap(&data);
1596 goto bail;
The Android Open Source Project99409882009-03-18 22:20:24 -07001597 } else {
1598 printf(" (unknown format %d!)\n", format);
Andy McFadden10351272009-03-24 21:30:32 -07001599 /* don't know how to skip data; failure will cascade to end of class */
1600 goto bail;
The Android Open Source Project99409882009-03-18 22:20:24 -07001601 }
1602
1603 if (addrWidth > 0) {
1604 u1 regWidth;
1605 u2 numEntries;
1606 int idx, addr, byte;
1607
1608 regWidth = *data++;
1609 numEntries = *data++;
1610 numEntries |= (*data++) << 8;
1611
1612 for (idx = 0; idx < numEntries; idx++) {
1613 addr = *data++;
1614 if (addrWidth > 1)
1615 addr |= (*data++) << 8;
1616
1617 printf(" %4x:", addr);
1618 for (byte = 0; byte < regWidth; byte++) {
1619 printf(" %02x", *data++);
1620 }
1621 printf("\n");
1622 }
1623 }
1624
Andy McFadden10351272009-03-24 21:30:32 -07001625bail:
The Android Open Source Project99409882009-03-18 22:20:24 -07001626 //if (addrWidth >= 0)
1627 // *pData = align32(data);
1628 *pData = data;
1629}
1630
1631/*
1632 * Dump the contents of the register map area.
1633 *
1634 * These are only present in optimized DEX files, and the structure is
1635 * not really exposed to other parts of the VM itself. We're going to
1636 * dig through them here, but this is pretty fragile. DO NOT rely on
1637 * this or derive other code from it.
1638 */
1639void dumpRegisterMaps(DexFile* pDexFile)
1640{
1641 const u1* pClassPool = pDexFile->pRegisterMapPool;
1642 const u4* classOffsets;
1643 const u1* ptr;
1644 u4 numClasses;
1645 int baseFileOffset = (u1*) pClassPool - (u1*) pDexFile->pOptHeader;
1646 int idx;
1647
1648 if (pClassPool == NULL) {
1649 printf("No register maps found\n");
1650 return;
1651 }
1652
1653 ptr = pClassPool;
1654 numClasses = get4LE(ptr);
1655 ptr += sizeof(u4);
1656 classOffsets = (const u4*) ptr;
1657
1658 printf("RMAP begins at offset 0x%07x\n", baseFileOffset);
1659 printf("Maps for %d classes\n", numClasses);
1660 for (idx = 0; idx < (int) numClasses; idx++) {
1661 const DexClassDef* pClassDef;
1662 const char* classDescriptor;
1663
1664 pClassDef = dexGetClassDef(pDexFile, idx);
1665 classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
1666
1667 printf("%4d: +%d (0x%08x) %s\n", idx, classOffsets[idx],
1668 baseFileOffset + classOffsets[idx], classDescriptor);
1669
1670 if (classOffsets[idx] == 0)
1671 continue;
1672
1673 /*
1674 * What follows is a series of RegisterMap entries, one for every
1675 * direct method, then one for every virtual method.
1676 */
1677 DexClassData* pClassData;
1678 const u1* pEncodedData;
1679 const u1* data = (u1*) pClassPool + classOffsets[idx];
1680 u2 methodCount;
1681 int i;
1682
1683 pEncodedData = dexGetClassData(pDexFile, pClassDef);
1684 pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL);
1685 if (pClassData == NULL) {
1686 fprintf(stderr, "Trouble reading class data\n");
1687 continue;
1688 }
1689
1690 methodCount = *data++;
1691 methodCount |= (*data++) << 8;
1692 data += 2; /* two pad bytes follow methodCount */
1693 if (methodCount != pClassData->header.directMethodsSize
1694 + pClassData->header.virtualMethodsSize)
1695 {
1696 printf("NOTE: method count discrepancy (%d != %d + %d)\n",
1697 methodCount, pClassData->header.directMethodsSize,
1698 pClassData->header.virtualMethodsSize);
1699 /* this is bad, but keep going anyway */
1700 }
1701
1702 printf(" direct methods: %d\n",
1703 pClassData->header.directMethodsSize);
1704 for (i = 0; i < (int) pClassData->header.directMethodsSize; i++) {
1705 dumpMethodMap(pDexFile, &pClassData->directMethods[i], i, &data);
1706 }
1707
1708 printf(" virtual methods: %d\n",
1709 pClassData->header.virtualMethodsSize);
1710 for (i = 0; i < (int) pClassData->header.virtualMethodsSize; i++) {
1711 dumpMethodMap(pDexFile, &pClassData->virtualMethods[i], i, &data);
1712 }
1713
1714 free(pClassData);
1715 }
1716}
1717
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001718/*
1719 * Dump the requested sections of the file.
1720 */
1721void processDexFile(const char* fileName, DexFile* pDexFile)
1722{
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001723 char* package = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001724 int i;
1725
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001726 if (gOptions.verbose) {
1727 printf("Opened '%s', DEX version '%.3s'\n", fileName,
1728 pDexFile->pHeader->magic +4);
1729 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001730
The Android Open Source Project99409882009-03-18 22:20:24 -07001731 if (gOptions.dumpRegisterMaps) {
1732 dumpRegisterMaps(pDexFile);
1733 return;
1734 }
1735
Andy McFadden0ea77b92010-04-20 14:18:59 -07001736 if (gOptions.showFileHeaders) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001737 dumpFileHeader(pDexFile);
Dan Bornsteine377ef62010-08-31 16:50:00 -07001738 dumpOptDirectory(pDexFile);
Andy McFadden0ea77b92010-04-20 14:18:59 -07001739 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001740
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001741 if (gOptions.outputFormat == OUTPUT_XML)
1742 printf("<api>\n");
1743
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001744 for (i = 0; i < (int) pDexFile->pHeader->classDefsSize; i++) {
1745 if (gOptions.showSectionHeaders)
1746 dumpClassDef(pDexFile, i);
1747
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001748 dumpClass(pDexFile, i, &package);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001749 }
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001750
1751 /* free the last one allocated */
1752 if (package != NULL) {
1753 printf("</package>\n");
1754 free(package);
1755 }
1756
1757 if (gOptions.outputFormat == OUTPUT_XML)
1758 printf("</api>\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001759}
1760
1761
1762/*
1763 * Process one file.
1764 */
1765int process(const char* fileName)
1766{
1767 DexFile* pDexFile = NULL;
1768 MemMapping map;
1769 bool mapped = false;
1770 int result = -1;
1771
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001772 if (gOptions.verbose)
1773 printf("Processing '%s'...\n", fileName);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001774
1775 if (dexOpenAndMap(fileName, gOptions.tempFileName, &map, false) != 0)
1776 goto bail;
1777 mapped = true;
1778
Andy McFadden2124cb82009-03-25 15:37:39 -07001779 int flags = kDexParseVerifyChecksum;
1780 if (gOptions.ignoreBadChecksum)
1781 flags |= kDexParseContinueOnError;
1782
1783 pDexFile = dexFileParse(map.addr, map.length, flags);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001784 if (pDexFile == NULL) {
1785 fprintf(stderr, "ERROR: DEX parse failed\n");
1786 goto bail;
1787 }
1788
Andy McFadden0198b142009-04-02 14:48:56 -07001789 if (gOptions.checksumOnly) {
1790 printf("Checksum verified\n");
1791 } else {
1792 processDexFile(fileName, pDexFile);
1793 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001794
1795 result = 0;
1796
1797bail:
1798 if (mapped)
1799 sysReleaseShmem(&map);
1800 if (pDexFile != NULL)
1801 dexFileFree(pDexFile);
1802 return result;
1803}
1804
1805
1806/*
1807 * Show usage.
1808 */
1809void usage(void)
1810{
1811 fprintf(stderr, "Copyright (C) 2007 The Android Open Source Project\n\n");
Andy McFadden0198b142009-04-02 14:48:56 -07001812 fprintf(stderr,
Andy McFaddend18aff32009-05-06 10:19:16 -07001813 "%s: [-c] [-d] [-f] [-h] [-i] [-l layout] [-m] [-t tempfile] dexfile...\n",
The Android Open Source Project99409882009-03-18 22:20:24 -07001814 gProgName);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001815 fprintf(stderr, "\n");
Andy McFadden0198b142009-04-02 14:48:56 -07001816 fprintf(stderr, " -c : verify checksum and exit\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001817 fprintf(stderr, " -d : disassemble code sections\n");
1818 fprintf(stderr, " -f : display summary information from file header\n");
1819 fprintf(stderr, " -h : display file header details\n");
Andy McFadden2124cb82009-03-25 15:37:39 -07001820 fprintf(stderr, " -i : ignore checksum failures\n");
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001821 fprintf(stderr, " -l : output layout, either 'plain' or 'xml'\n");
The Android Open Source Project99409882009-03-18 22:20:24 -07001822 fprintf(stderr, " -m : dump register maps (and nothing else)\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001823 fprintf(stderr, " -t : temp file name (defaults to /sdcard/dex-temp-*)\n");
1824}
1825
1826/*
1827 * Parse args.
1828 *
1829 * I'm not using getopt_long() because we may not have it in libc.
1830 */
1831int main(int argc, char* const argv[])
1832{
1833 bool wantUsage = false;
1834 int ic;
1835
1836 memset(&gOptions, 0, sizeof(gOptions));
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001837 gOptions.verbose = true;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001838
1839 while (1) {
Andy McFaddend18aff32009-05-06 10:19:16 -07001840 ic = getopt(argc, argv, "cdfhil:mt:");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001841 if (ic < 0)
1842 break;
1843
1844 switch (ic) {
Andy McFadden0198b142009-04-02 14:48:56 -07001845 case 'c': // verify the checksum then exit
1846 gOptions.checksumOnly = true;
1847 break;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001848 case 'd': // disassemble Dalvik instructions
1849 gOptions.disassemble = true;
1850 break;
1851 case 'f': // dump outer file header
1852 gOptions.showFileHeaders = true;
1853 break;
1854 case 'h': // dump section headers, i.e. all meta-data
1855 gOptions.showSectionHeaders = true;
1856 break;
Andy McFadden2124cb82009-03-25 15:37:39 -07001857 case 'i': // continue even if checksum is bad
1858 gOptions.ignoreBadChecksum = true;
1859 break;
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001860 case 'l': // layout
1861 if (strcmp(optarg, "plain") == 0) {
1862 gOptions.outputFormat = OUTPUT_PLAIN;
1863 } else if (strcmp(optarg, "xml") == 0) {
1864 gOptions.outputFormat = OUTPUT_XML;
1865 gOptions.verbose = false;
1866 gOptions.exportsOnly = true;
1867 } else {
1868 wantUsage = true;
1869 }
1870 break;
The Android Open Source Project99409882009-03-18 22:20:24 -07001871 case 'm': // dump register maps only
1872 gOptions.dumpRegisterMaps = true;
1873 break;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001874 case 't': // temp file, used when opening compressed Jar
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001875 gOptions.tempFileName = optarg;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001876 break;
1877 default:
1878 wantUsage = true;
1879 break;
1880 }
1881 }
1882
1883 if (optind == argc) {
1884 fprintf(stderr, "%s: no file specified\n", gProgName);
1885 wantUsage = true;
1886 }
1887
Andy McFadden0198b142009-04-02 14:48:56 -07001888 if (gOptions.checksumOnly && gOptions.ignoreBadChecksum) {
1889 fprintf(stderr, "Can't specify both -c and -i\n");
1890 wantUsage = true;
1891 }
1892
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001893 /* initialize some VM tables */
Dan Bornstein44a38f42010-11-10 17:34:32 -08001894 if (dexCreateInstructionInfoTables(&gInstrInfo)) {
1895 fprintf(stderr, "Failed to construct instruction tables\n");
1896 return 1;
1897 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001898
1899 if (wantUsage) {
1900 usage();
1901 return 2;
1902 }
1903
Andy McFadden0198b142009-04-02 14:48:56 -07001904 int result = 0;
1905 while (optind < argc) {
1906 result |= process(argv[optind++]);
1907 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001908
Dan Bornstein44a38f42010-11-10 17:34:32 -08001909 dexFreeInstructionInfoTables(&gInstrInfo);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001910
Andy McFadden0198b142009-04-02 14:48:56 -07001911 return (result != 0);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001912}