blob: 93534714f096f546a6934687e0868587cda53a27 [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 */
Dan Bornstein9ea32b02011-03-09 17:40:41 -080032
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080033#include "libdex/DexFile.h"
Dan Bornstein9ea32b02011-03-09 17:40:41 -080034
35#include "libdex/CmdUtils.h"
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080036#include "libdex/DexCatch.h"
37#include "libdex/DexClass.h"
Dan Bornstein9ea32b02011-03-09 17:40:41 -080038#include "libdex/DexDebugInfo.h"
Dan Bornsteindf4daaf2010-12-01 14:23:44 -080039#include "libdex/DexOpcodes.h"
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080040#include "libdex/DexProto.h"
41#include "libdex/InstrUtils.h"
42#include "libdex/SysUtil.h"
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080043
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080044#include <stdlib.h>
45#include <stdio.h>
46#include <fcntl.h>
47#include <string.h>
48#include <unistd.h>
49#include <getopt.h>
50#include <errno.h>
51#include <assert.h>
52
53static const char* gProgName = "dexdump";
54
Andy McFaddena2ee53b2009-05-05 16:52:10 -070055typedef enum OutputFormat {
56 OUTPUT_PLAIN = 0, /* default */
57 OUTPUT_XML, /* fancy */
58} OutputFormat;
59
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080060/* command-line options */
61struct {
Andy McFadden0198b142009-04-02 14:48:56 -070062 bool checksumOnly;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080063 bool disassemble;
64 bool showFileHeaders;
65 bool showSectionHeaders;
Andy McFadden2124cb82009-03-25 15:37:39 -070066 bool ignoreBadChecksum;
The Android Open Source Project99409882009-03-18 22:20:24 -070067 bool dumpRegisterMaps;
Andy McFaddena2ee53b2009-05-05 16:52:10 -070068 OutputFormat outputFormat;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080069 const char* tempFileName;
Andy McFaddena2ee53b2009-05-05 16:52:10 -070070 bool exportsOnly;
71 bool verbose;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080072} gOptions;
73
74/* basic info about a field or method */
75typedef struct FieldMethodInfo {
76 const char* classDescriptor;
77 const char* name;
78 const char* signature;
79} FieldMethodInfo;
80
81/*
Carl Shapirode750892010-06-08 16:37:12 -070082 * Get 2 little-endian bytes.
83 */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080084static inline u2 get2LE(unsigned char const* pSrc)
85{
86 return pSrc[0] | (pSrc[1] << 8);
Carl Shapirode750892010-06-08 16:37:12 -070087}
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080088
89/*
Carl Shapirode750892010-06-08 16:37:12 -070090 * Get 4 little-endian bytes.
91 */
The Android Open Source Project99409882009-03-18 22:20:24 -070092static inline u4 get4LE(unsigned char const* pSrc)
93{
94 return pSrc[0] | (pSrc[1] << 8) | (pSrc[2] << 16) | (pSrc[3] << 24);
Carl Shapirode750892010-06-08 16:37:12 -070095}
The Android Open Source Project99409882009-03-18 22:20:24 -070096
97/*
Andy McFaddena2ee53b2009-05-05 16:52:10 -070098 * Converts a single-character primitive type into its human-readable
99 * equivalent.
100 */
101static const char* primitiveTypeLabel(char typeChar)
102{
103 switch (typeChar) {
104 case 'B': return "byte";
105 case 'C': return "char";
106 case 'D': return "double";
107 case 'F': return "float";
108 case 'I': return "int";
109 case 'J': return "long";
110 case 'S': return "short";
111 case 'V': return "void";
112 case 'Z': return "boolean";
113 default:
114 return "UNKNOWN";
115 }
116}
117
118/*
119 * Converts a type descriptor to human-readable "dotted" form. For
120 * example, "Ljava/lang/String;" becomes "java.lang.String", and
121 * "[I" becomes "int[]". Also converts '$' to '.', which means this
122 * form can't be converted back to a descriptor.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800123 */
124static char* descriptorToDot(const char* str)
125{
Andy McFaddena2ee53b2009-05-05 16:52:10 -0700126 int targetLen = strlen(str);
127 int offset = 0;
128 int arrayDepth = 0;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800129 char* newStr;
130
Andy McFaddena2ee53b2009-05-05 16:52:10 -0700131 /* strip leading [s; will be added to end */
132 while (targetLen > 1 && str[offset] == '[') {
133 offset++;
134 targetLen--;
135 }
136 arrayDepth = offset;
137
138 if (targetLen == 1) {
139 /* primitive type */
140 str = primitiveTypeLabel(str[offset]);
141 offset = 0;
142 targetLen = strlen(str);
143 } else {
144 /* account for leading 'L' and trailing ';' */
145 if (targetLen >= 2 && str[offset] == 'L' &&
146 str[offset+targetLen-1] == ';')
147 {
148 targetLen -= 2;
149 offset++;
150 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800151 }
152
Andy McFaddena2ee53b2009-05-05 16:52:10 -0700153 newStr = malloc(targetLen + arrayDepth * 2 +1);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800154
Andy McFaddena2ee53b2009-05-05 16:52:10 -0700155 /* copy class name over */
156 int i;
157 for (i = 0; i < targetLen; i++) {
158 char ch = str[offset + i];
159 newStr[i] = (ch == '/' || ch == '$') ? '.' : ch;
160 }
161
162 /* add the appropriate number of brackets for arrays */
163 while (arrayDepth-- > 0) {
164 newStr[i++] = '[';
165 newStr[i++] = ']';
166 }
167 newStr[i] = '\0';
168 assert(i == targetLen + arrayDepth * 2);
169
170 return newStr;
171}
172
173/*
174 * Converts the class name portion of a type descriptor to human-readable
175 * "dotted" form.
176 *
177 * Returns a newly-allocated string.
178 */
179static char* descriptorClassToDot(const char* str)
180{
181 const char* lastSlash;
182 char* newStr;
183 char* cp;
184
185 /* reduce to just the class name, trimming trailing ';' */
186 lastSlash = strrchr(str, '/');
187 if (lastSlash == NULL)
188 lastSlash = str + 1; /* start past 'L' */
189 else
190 lastSlash++; /* start past '/' */
191
192 newStr = strdup(lastSlash);
193 newStr[strlen(lastSlash)-1] = '\0';
194 for (cp = newStr; *cp != '\0'; cp++) {
195 if (*cp == '$')
196 *cp = '.';
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800197 }
198
199 return newStr;
200}
201
202/*
Andy McFaddena2ee53b2009-05-05 16:52:10 -0700203 * Returns a quoted string representing the boolean value.
204 */
205static const char* quotedBool(bool val)
206{
207 if (val)
208 return "\"true\"";
209 else
210 return "\"false\"";
211}
212
213static const char* quotedVisibility(u4 accessFlags)
214{
215 if ((accessFlags & ACC_PUBLIC) != 0)
216 return "\"public\"";
217 else if ((accessFlags & ACC_PROTECTED) != 0)
218 return "\"protected\"";
219 else if ((accessFlags & ACC_PRIVATE) != 0)
220 return "\"private\"";
221 else
222 return "\"package\"";
223}
224
225/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800226 * Count the number of '1' bits in a word.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800227 */
228static int countOnes(u4 val)
229{
230 int count = 0;
231
Cosmin Cojocare3393432010-04-18 18:25:06 +0200232 val = val - ((val >> 1) & 0x55555555);
233 val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
234 count = (((val + (val >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800235
236 return count;
237}
238
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800239/*
240 * Flag for use with createAccessFlagStr().
241 */
242typedef enum AccessFor {
243 kAccessForClass = 0, kAccessForMethod = 1, kAccessForField = 2,
244 kAccessForMAX
245} AccessFor;
246
247/*
248 * Create a new string with human-readable access flags.
249 *
250 * In the base language the access_flags fields are type u2; in Dalvik
251 * they're u4.
252 */
253static char* createAccessFlagStr(u4 flags, AccessFor forWhat)
254{
255#define NUM_FLAGS 18
256 static const char* kAccessStrings[kAccessForMAX][NUM_FLAGS] = {
Carl Shapirode750892010-06-08 16:37:12 -0700257 {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800258 /* class, inner class */
259 "PUBLIC", /* 0x0001 */
260 "PRIVATE", /* 0x0002 */
261 "PROTECTED", /* 0x0004 */
262 "STATIC", /* 0x0008 */
263 "FINAL", /* 0x0010 */
264 "?", /* 0x0020 */
265 "?", /* 0x0040 */
266 "?", /* 0x0080 */
267 "?", /* 0x0100 */
268 "INTERFACE", /* 0x0200 */
269 "ABSTRACT", /* 0x0400 */
270 "?", /* 0x0800 */
271 "SYNTHETIC", /* 0x1000 */
272 "ANNOTATION", /* 0x2000 */
273 "ENUM", /* 0x4000 */
274 "?", /* 0x8000 */
275 "VERIFIED", /* 0x10000 */
276 "OPTIMIZED", /* 0x20000 */
277 },
278 {
279 /* method */
280 "PUBLIC", /* 0x0001 */
281 "PRIVATE", /* 0x0002 */
282 "PROTECTED", /* 0x0004 */
283 "STATIC", /* 0x0008 */
284 "FINAL", /* 0x0010 */
285 "SYNCHRONIZED", /* 0x0020 */
286 "BRIDGE", /* 0x0040 */
287 "VARARGS", /* 0x0080 */
288 "NATIVE", /* 0x0100 */
289 "?", /* 0x0200 */
290 "ABSTRACT", /* 0x0400 */
291 "STRICT", /* 0x0800 */
292 "SYNTHETIC", /* 0x1000 */
293 "?", /* 0x2000 */
294 "?", /* 0x4000 */
295 "MIRANDA", /* 0x8000 */
296 "CONSTRUCTOR", /* 0x10000 */
297 "DECLARED_SYNCHRONIZED", /* 0x20000 */
298 },
299 {
300 /* field */
301 "PUBLIC", /* 0x0001 */
302 "PRIVATE", /* 0x0002 */
303 "PROTECTED", /* 0x0004 */
304 "STATIC", /* 0x0008 */
305 "FINAL", /* 0x0010 */
306 "?", /* 0x0020 */
307 "VOLATILE", /* 0x0040 */
308 "TRANSIENT", /* 0x0080 */
309 "?", /* 0x0100 */
310 "?", /* 0x0200 */
311 "?", /* 0x0400 */
312 "?", /* 0x0800 */
313 "SYNTHETIC", /* 0x1000 */
314 "?", /* 0x2000 */
315 "ENUM", /* 0x4000 */
316 "?", /* 0x8000 */
317 "?", /* 0x10000 */
318 "?", /* 0x20000 */
319 },
320 };
321 const int kLongest = 21; /* strlen of longest string above */
322 int i, count;
323 char* str;
324 char* cp;
325
326 /*
327 * Allocate enough storage to hold the expected number of strings,
328 * plus a space between each. We over-allocate, using the longest
329 * string above as the base metric.
330 */
331 count = countOnes(flags);
332 cp = str = (char*) malloc(count * (kLongest+1) +1);
333
334 for (i = 0; i < NUM_FLAGS; i++) {
335 if (flags & 0x01) {
336 const char* accessStr = kAccessStrings[forWhat][i];
337 int len = strlen(accessStr);
338 if (cp != str)
339 *cp++ = ' ';
340
341 memcpy(cp, accessStr, len);
342 cp += len;
343 }
344 flags >>= 1;
345 }
346 *cp = '\0';
347
348 return str;
349}
350
351
352/*
Andy McFadden0ea77b92010-04-20 14:18:59 -0700353 * Copy character data from "data" to "out", converting non-ASCII values
354 * to printf format chars or an ASCII filler ('.' or '?').
355 *
356 * The output buffer must be able to hold (2*len)+1 bytes. The result is
357 * NUL-terminated.
358 */
359static void asciify(char* out, const unsigned char* data, size_t len)
360{
361 while (len--) {
362 if (*data < 0x20) {
363 /* could do more here, but we don't need them yet */
364 switch (*data) {
365 case '\0':
366 *out++ = '\\';
367 *out++ = '0';
368 break;
369 case '\n':
370 *out++ = '\\';
371 *out++ = 'n';
372 break;
373 default:
374 *out++ = '.';
375 break;
376 }
377 } else if (*data >= 0x80) {
378 *out++ = '?';
379 } else {
380 *out++ = *data;
381 }
382 data++;
383 }
384 *out = '\0';
385}
386
387/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800388 * Dump the file header.
389 */
390void dumpFileHeader(const DexFile* pDexFile)
391{
Andy McFadden0ea77b92010-04-20 14:18:59 -0700392 const DexOptHeader* pOptHeader = pDexFile->pOptHeader;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800393 const DexHeader* pHeader = pDexFile->pHeader;
Andy McFadden0ea77b92010-04-20 14:18:59 -0700394 char sanitized[sizeof(pHeader->magic)*2 +1];
395
396 assert(sizeof(pHeader->magic) == sizeof(pOptHeader->magic));
397
398 if (pOptHeader != NULL) {
399 printf("Optimized DEX file header:\n");
400
401 asciify(sanitized, pOptHeader->magic, sizeof(pOptHeader->magic));
402 printf("magic : '%s'\n", sanitized);
403 printf("dex_offset : %d (0x%06x)\n",
404 pOptHeader->dexOffset, pOptHeader->dexOffset);
405 printf("dex_length : %d\n", pOptHeader->dexLength);
406 printf("deps_offset : %d (0x%06x)\n",
407 pOptHeader->depsOffset, pOptHeader->depsOffset);
408 printf("deps_length : %d\n", pOptHeader->depsLength);
Dan Bornsteine377ef62010-08-31 16:50:00 -0700409 printf("opt_offset : %d (0x%06x)\n",
410 pOptHeader->optOffset, pOptHeader->optOffset);
411 printf("opt_length : %d\n", pOptHeader->optLength);
Andy McFadden0ea77b92010-04-20 14:18:59 -0700412 printf("flags : %08x\n", pOptHeader->flags);
413 printf("checksum : %08x\n", pOptHeader->checksum);
414 printf("\n");
415 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800416
417 printf("DEX file header:\n");
Andy McFadden0ea77b92010-04-20 14:18:59 -0700418 asciify(sanitized, pHeader->magic, sizeof(pHeader->magic));
419 printf("magic : '%s'\n", sanitized);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800420 printf("checksum : %08x\n", pHeader->checksum);
421 printf("signature : %02x%02x...%02x%02x\n",
422 pHeader->signature[0], pHeader->signature[1],
423 pHeader->signature[kSHA1DigestLen-2],
424 pHeader->signature[kSHA1DigestLen-1]);
425 printf("file_size : %d\n", pHeader->fileSize);
426 printf("header_size : %d\n", pHeader->headerSize);
427 printf("link_size : %d\n", pHeader->linkSize);
428 printf("link_off : %d (0x%06x)\n",
429 pHeader->linkOff, pHeader->linkOff);
430 printf("string_ids_size : %d\n", pHeader->stringIdsSize);
431 printf("string_ids_off : %d (0x%06x)\n",
432 pHeader->stringIdsOff, pHeader->stringIdsOff);
433 printf("type_ids_size : %d\n", pHeader->typeIdsSize);
434 printf("type_ids_off : %d (0x%06x)\n",
435 pHeader->typeIdsOff, pHeader->typeIdsOff);
436 printf("field_ids_size : %d\n", pHeader->fieldIdsSize);
437 printf("field_ids_off : %d (0x%06x)\n",
438 pHeader->fieldIdsOff, pHeader->fieldIdsOff);
439 printf("method_ids_size : %d\n", pHeader->methodIdsSize);
440 printf("method_ids_off : %d (0x%06x)\n",
441 pHeader->methodIdsOff, pHeader->methodIdsOff);
442 printf("class_defs_size : %d\n", pHeader->classDefsSize);
443 printf("class_defs_off : %d (0x%06x)\n",
444 pHeader->classDefsOff, pHeader->classDefsOff);
445 printf("data_size : %d\n", pHeader->dataSize);
446 printf("data_off : %d (0x%06x)\n",
447 pHeader->dataOff, pHeader->dataOff);
448 printf("\n");
449}
450
451/*
Dan Bornsteine377ef62010-08-31 16:50:00 -0700452 * Dump the "table of contents" for the opt area.
Andy McFadden0ea77b92010-04-20 14:18:59 -0700453 */
Dan Bornsteine377ef62010-08-31 16:50:00 -0700454void dumpOptDirectory(const DexFile* pDexFile)
Andy McFadden0ea77b92010-04-20 14:18:59 -0700455{
456 const DexOptHeader* pOptHeader = pDexFile->pOptHeader;
457 if (pOptHeader == NULL)
458 return;
459
Dan Bornsteine377ef62010-08-31 16:50:00 -0700460 printf("OPT section contents:\n");
Andy McFadden0ea77b92010-04-20 14:18:59 -0700461
Dan Bornsteine377ef62010-08-31 16:50:00 -0700462 const u4* pOpt = (const u4*) ((u1*) pOptHeader + pOptHeader->optOffset);
Andy McFadden0ea77b92010-04-20 14:18:59 -0700463
Dan Bornsteine377ef62010-08-31 16:50:00 -0700464 if (*pOpt == 0) {
Andy McFadden0ea77b92010-04-20 14:18:59 -0700465 printf("(1.0 format, only class lookup table is present)\n\n");
466 return;
467 }
468
469 /*
Dan Bornsteine377ef62010-08-31 16:50:00 -0700470 * The "opt" section is in "chunk" format: a 32-bit identifier, a 32-bit
Andy McFadden0ea77b92010-04-20 14:18:59 -0700471 * length, then the data. Chunks start on 64-bit boundaries.
472 */
Dan Bornsteine377ef62010-08-31 16:50:00 -0700473 while (*pOpt != kDexChunkEnd) {
Andy McFadden0ea77b92010-04-20 14:18:59 -0700474 const char* verboseStr;
475
Dan Bornsteine377ef62010-08-31 16:50:00 -0700476 u4 size = *(pOpt+1);
Andy McFadden0ea77b92010-04-20 14:18:59 -0700477
Dan Bornsteine377ef62010-08-31 16:50:00 -0700478 switch (*pOpt) {
Andy McFadden0ea77b92010-04-20 14:18:59 -0700479 case kDexChunkClassLookup:
480 verboseStr = "class lookup hash table";
481 break;
482 case kDexChunkRegisterMaps:
483 verboseStr = "register maps";
484 break;
Andy McFadden0ea77b92010-04-20 14:18:59 -0700485 default:
486 verboseStr = "(unknown chunk type)";
487 break;
488 }
489
Dan Bornsteine377ef62010-08-31 16:50:00 -0700490 printf("Chunk %08x (%c%c%c%c) - %s (%d bytes)\n", *pOpt,
491 *pOpt >> 24, (char)(*pOpt >> 16), (char)(*pOpt >> 8), (char)*pOpt,
Andy McFadden0ea77b92010-04-20 14:18:59 -0700492 verboseStr, size);
493
494 size = (size + 8 + 7) & ~7;
Dan Bornsteine377ef62010-08-31 16:50:00 -0700495 pOpt += size / sizeof(u4);
Andy McFadden0ea77b92010-04-20 14:18:59 -0700496 }
497 printf("\n");
498}
499
500/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800501 * Dump a class_def_item.
502 */
503void dumpClassDef(DexFile* pDexFile, int idx)
504{
505 const DexClassDef* pClassDef;
506 const u1* pEncodedData;
507 DexClassData* pClassData;
508
509 pClassDef = dexGetClassDef(pDexFile, idx);
510 pEncodedData = dexGetClassData(pDexFile, pClassDef);
511 pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL);
512
513 if (pClassData == NULL) {
514 fprintf(stderr, "Trouble reading class data\n");
515 return;
516 }
517
518 printf("Class #%d header:\n", idx);
519 printf("class_idx : %d\n", pClassDef->classIdx);
520 printf("access_flags : %d (0x%04x)\n",
521 pClassDef->accessFlags, pClassDef->accessFlags);
522 printf("superclass_idx : %d\n", pClassDef->superclassIdx);
523 printf("interfaces_off : %d (0x%06x)\n",
524 pClassDef->interfacesOff, pClassDef->interfacesOff);
525 printf("source_file_idx : %d\n", pClassDef->sourceFileIdx);
526 printf("annotations_off : %d (0x%06x)\n",
527 pClassDef->annotationsOff, pClassDef->annotationsOff);
528 printf("class_data_off : %d (0x%06x)\n",
529 pClassDef->classDataOff, pClassDef->classDataOff);
530 printf("static_fields_size : %d\n", pClassData->header.staticFieldsSize);
531 printf("instance_fields_size: %d\n",
532 pClassData->header.instanceFieldsSize);
533 printf("direct_methods_size : %d\n", pClassData->header.directMethodsSize);
534 printf("virtual_methods_size: %d\n",
535 pClassData->header.virtualMethodsSize);
536 printf("\n");
537
538 free(pClassData);
539}
540
541/*
Andy McFaddena2ee53b2009-05-05 16:52:10 -0700542 * Dump an interface that a class declares to implement.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800543 */
544void dumpInterface(const DexFile* pDexFile, const DexTypeItem* pTypeItem,
545 int i)
546{
547 const char* interfaceName =
548 dexStringByTypeIdx(pDexFile, pTypeItem->typeIdx);
549
Andy McFaddena2ee53b2009-05-05 16:52:10 -0700550 if (gOptions.outputFormat == OUTPUT_PLAIN) {
551 printf(" #%d : '%s'\n", i, interfaceName);
552 } else {
553 char* dotted = descriptorToDot(interfaceName);
554 printf("<implements name=\"%s\">\n</implements>\n", dotted);
555 free(dotted);
556 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800557}
558
559/*
560 * Dump the catches table associated with the code.
561 */
562void dumpCatches(DexFile* pDexFile, const DexCode* pCode)
563{
564 u4 triesSize = pCode->triesSize;
565
566 if (triesSize == 0) {
567 printf(" catches : (none)\n");
568 return;
Carl Shapirode750892010-06-08 16:37:12 -0700569 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800570
571 printf(" catches : %d\n", triesSize);
572
573 const DexTry* pTries = dexGetTries(pCode);
574 u4 i;
575
576 for (i = 0; i < triesSize; i++) {
577 const DexTry* pTry = &pTries[i];
578 u4 start = pTry->startAddr;
579 u4 end = start + pTry->insnCount;
580 DexCatchIterator iterator;
Carl Shapirode750892010-06-08 16:37:12 -0700581
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800582 printf(" 0x%04x - 0x%04x\n", start, end);
583
584 dexCatchIteratorInit(&iterator, pCode, pTry->handlerOff);
585
586 for (;;) {
587 DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
588 const char* descriptor;
Carl Shapirode750892010-06-08 16:37:12 -0700589
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800590 if (handler == NULL) {
591 break;
592 }
Carl Shapirode750892010-06-08 16:37:12 -0700593
594 descriptor = (handler->typeIdx == kDexNoIndex) ? "<any>" :
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800595 dexStringByTypeIdx(pDexFile, handler->typeIdx);
Carl Shapirode750892010-06-08 16:37:12 -0700596
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800597 printf(" %s -> 0x%04x\n", descriptor,
598 handler->address);
599 }
600 }
601}
602
603static int dumpPositionsCb(void *cnxt, u4 address, u4 lineNum)
604{
605 printf(" 0x%04x line=%d\n", address, lineNum);
606 return 0;
607}
608
609/*
610 * Dump the positions list.
611 */
Carl Shapirode750892010-06-08 16:37:12 -0700612void dumpPositions(DexFile* pDexFile, const DexCode* pCode,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800613 const DexMethod *pDexMethod)
614{
615 printf(" positions : \n");
Carl Shapirode750892010-06-08 16:37:12 -0700616 const DexMethodId *pMethodId
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800617 = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
618 const char *classDescriptor
619 = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
620
621 dexDecodeDebugInfo(pDexFile, pCode, classDescriptor, pMethodId->protoIdx,
622 pDexMethod->accessFlags, dumpPositionsCb, NULL, NULL);
623}
624
625static void dumpLocalsCb(void *cnxt, u2 reg, u4 startAddress,
626 u4 endAddress, const char *name, const char *descriptor,
627 const char *signature)
628{
629 printf(" 0x%04x - 0x%04x reg=%d %s %s %s\n",
Carl Shapirode750892010-06-08 16:37:12 -0700630 startAddress, endAddress, reg, name, descriptor,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800631 signature);
632}
633
634/*
635 * Dump the locals list.
636 */
637void dumpLocals(DexFile* pDexFile, const DexCode* pCode,
638 const DexMethod *pDexMethod)
639{
640 printf(" locals : \n");
641
Carl Shapirode750892010-06-08 16:37:12 -0700642 const DexMethodId *pMethodId
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800643 = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
Carl Shapirode750892010-06-08 16:37:12 -0700644 const char *classDescriptor
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800645 = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
646
647 dexDecodeDebugInfo(pDexFile, pCode, classDescriptor, pMethodId->protoIdx,
648 pDexMethod->accessFlags, NULL, dumpLocalsCb, NULL);
649}
650
651/*
652 * Get information about a method.
653 */
654bool getMethodInfo(DexFile* pDexFile, u4 methodIdx, FieldMethodInfo* pMethInfo)
655{
656 const DexMethodId* pMethodId;
657
658 if (methodIdx >= pDexFile->pHeader->methodIdsSize)
659 return false;
660
661 pMethodId = dexGetMethodId(pDexFile, methodIdx);
662 pMethInfo->name = dexStringById(pDexFile, pMethodId->nameIdx);
663 pMethInfo->signature = dexCopyDescriptorFromMethodId(pDexFile, pMethodId);
664
Carl Shapirode750892010-06-08 16:37:12 -0700665 pMethInfo->classDescriptor =
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800666 dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
667 return true;
668}
669
670/*
671 * Get information about a field.
672 */
673bool getFieldInfo(DexFile* pDexFile, u4 fieldIdx, FieldMethodInfo* pFieldInfo)
674{
675 const DexFieldId* pFieldId;
676
677 if (fieldIdx >= pDexFile->pHeader->fieldIdsSize)
678 return false;
679
680 pFieldId = dexGetFieldId(pDexFile, fieldIdx);
681 pFieldInfo->name = dexStringById(pDexFile, pFieldId->nameIdx);
682 pFieldInfo->signature = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx);
683 pFieldInfo->classDescriptor =
684 dexStringByTypeIdx(pDexFile, pFieldId->classIdx);
685 return true;
686}
687
688
689/*
690 * Look up a class' descriptor.
691 */
692const char* getClassDescriptor(DexFile* pDexFile, u4 classIdx)
693{
694 return dexStringByTypeIdx(pDexFile, classIdx);
695}
696
697/*
Dan Bornstein4a6b4822010-11-11 12:26:58 -0800698 * Helper for dumpInstruction(), which builds the string
699 * representation for the index in the given instruction. This will
700 * first try to use the given buffer, but if the result won't fit,
701 * then this will allocate a new buffer to hold the result. A pointer
702 * to the buffer which holds the full result is always returned, and
703 * this can be compared with the one passed in, to see if the result
704 * needs to be free()d.
705 */
706static char* indexString(DexFile* pDexFile,
707 const DecodedInstruction* pDecInsn, char* buf, size_t bufSize)
708{
709 int outSize;
710 u4 index;
711 u4 width;
712
713 /* TODO: Make the index *always* be in field B, to simplify this code. */
Dan Bornsteine4852762010-12-02 12:45:00 -0800714 switch (dexGetFormatFromOpcode(pDecInsn->opcode)) {
Dan Bornstein4a6b4822010-11-11 12:26:58 -0800715 case kFmt20bc:
716 case kFmt21c:
717 case kFmt35c:
718 case kFmt35ms:
719 case kFmt3rc:
720 case kFmt3rms:
721 case kFmt35mi:
722 case kFmt3rmi:
723 index = pDecInsn->vB;
724 width = 4;
725 break;
726 case kFmt31c:
jeffhao71eee1f2011-01-04 14:18:54 -0800727 case kFmt40sc:
Dan Bornstein4a6b4822010-11-11 12:26:58 -0800728 case kFmt41c:
729 case kFmt5rc:
730 index = pDecInsn->vB;
731 width = 8;
732 break;
733 case kFmt22c:
734 case kFmt22cs:
735 index = pDecInsn->vC;
736 width = 4;
737 break;
738 case kFmt52c:
739 index = pDecInsn->vC;
740 width = 8;
741 break;
742 default:
743 index = 0;
744 width = 4;
745 break;
746 }
747
748 switch (pDecInsn->indexType) {
749 case kIndexUnknown:
750 /*
751 * This function shouldn't ever get called for this type, but do
752 * something sensible here, just to help with debugging.
753 */
754 outSize = snprintf(buf, bufSize, "<unknown-index>");
755 break;
756 case kIndexNone:
757 /*
758 * This function shouldn't ever get called for this type, but do
759 * something sensible here, just to help with debugging.
760 */
761 outSize = snprintf(buf, bufSize, "<no-index>");
762 break;
763 case kIndexVaries:
764 /*
765 * This one should never show up in a dexdump, so no need to try
766 * to get fancy here.
767 */
768 outSize = snprintf(buf, bufSize, "<index-varies> // thing@%0*x",
769 width, index);
770 break;
Dan Bornstein1530c3e2010-11-12 12:51:35 -0800771 case kIndexTypeRef:
772 outSize = snprintf(buf, bufSize, "%s // type@%0*x",
Dan Bornstein4a6b4822010-11-11 12:26:58 -0800773 getClassDescriptor(pDexFile, index), width, index);
774 break;
775 case kIndexStringRef:
776 outSize = snprintf(buf, bufSize, "\"%s\" // string@%0*x",
777 dexStringById(pDexFile, index), width, index);
778 break;
779 case kIndexMethodRef:
780 {
781 FieldMethodInfo methInfo;
782 if (getMethodInfo(pDexFile, index, &methInfo)) {
783 outSize = snprintf(buf, bufSize, "%s.%s:%s // method@%0*x",
784 methInfo.classDescriptor, methInfo.name,
785 methInfo.signature, width, index);
786 } else {
787 outSize = snprintf(buf, bufSize, "<method?> // method@%0*x",
788 width, index);
789 }
790 }
791 break;
792 case kIndexFieldRef:
793 {
794 FieldMethodInfo fieldInfo;
795 if (getFieldInfo(pDexFile, index, &fieldInfo)) {
796 outSize = snprintf(buf, bufSize, "%s.%s:%s // field@%0*x",
797 fieldInfo.classDescriptor, fieldInfo.name,
798 fieldInfo.signature, width, index);
799 } else {
800 outSize = snprintf(buf, bufSize, "<field?> // field@%0*x",
801 width, index);
802 }
803 }
804 break;
805 case kIndexInlineMethod:
806 outSize = snprintf(buf, bufSize, "[%0*x] // inline #%0*x",
807 width, index, width, index);
808 break;
809 case kIndexVtableOffset:
810 outSize = snprintf(buf, bufSize, "[%0*x] // vtable #%0*x",
811 width, index, width, index);
812 break;
813 case kIndexFieldOffset:
814 outSize = snprintf(buf, bufSize, "[obj+%0*x]", width, index);
815 break;
816 default:
817 outSize = snprintf(buf, bufSize, "<?>");
818 break;
819 }
820
821 if (outSize >= (int) bufSize) {
822 /*
823 * The buffer wasn't big enough; allocate and retry. Note:
824 * snprintf() doesn't count the '\0' as part of its returned
825 * size, so we add explicit space for it here.
826 */
827 outSize++;
828 buf = malloc(outSize);
829 if (buf == NULL) {
830 return NULL;
831 }
832 return indexString(pDexFile, pDecInsn, buf, outSize);
833 } else {
834 return buf;
835 }
836}
837
838/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800839 * Dump a single instruction.
840 */
841void dumpInstruction(DexFile* pDexFile, const DexCode* pCode, int insnIdx,
842 int insnWidth, const DecodedInstruction* pDecInsn)
843{
Dan Bornstein4a6b4822010-11-11 12:26:58 -0800844 char indexBufChars[200];
845 char *indexBuf = indexBufChars;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800846 const u2* insns = pCode->insns;
847 int i;
848
849 printf("%06x:", ((u1*)insns - pDexFile->baseAddr) + insnIdx*2);
850 for (i = 0; i < 8; i++) {
851 if (i < insnWidth) {
852 if (i == 7) {
853 printf(" ... ");
854 } else {
855 /* print 16-bit value in little-endian order */
856 const u1* bytePtr = (const u1*) &insns[insnIdx+i];
857 printf(" %02x%02x", bytePtr[0], bytePtr[1]);
858 }
859 } else {
860 fputs(" ", stdout);
861 }
862 }
863
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800864 if (pDecInsn->opcode == OP_NOP) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800865 u2 instr = get2LE((const u1*) &insns[insnIdx]);
866 if (instr == kPackedSwitchSignature) {
867 printf("|%04x: packed-switch-data (%d units)",
868 insnIdx, insnWidth);
869 } else if (instr == kSparseSwitchSignature) {
870 printf("|%04x: sparse-switch-data (%d units)",
871 insnIdx, insnWidth);
872 } else if (instr == kArrayDataSignature) {
873 printf("|%04x: array-data (%d units)",
874 insnIdx, insnWidth);
875 } else {
876 printf("|%04x: nop // spacer", insnIdx);
877 }
878 } else {
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800879 printf("|%04x: %s", insnIdx, dexGetOpcodeName(pDecInsn->opcode));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800880 }
881
Dan Bornstein4a6b4822010-11-11 12:26:58 -0800882 if (pDecInsn->indexType != kIndexNone) {
883 indexBuf = indexString(pDexFile, pDecInsn,
884 indexBufChars, sizeof(indexBufChars));
885 }
886
Dan Bornsteine4852762010-12-02 12:45:00 -0800887 switch (dexGetFormatFromOpcode(pDecInsn->opcode)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800888 case kFmt10x: // op
889 break;
890 case kFmt12x: // op vA, vB
891 printf(" v%d, v%d", pDecInsn->vA, pDecInsn->vB);
892 break;
893 case kFmt11n: // op vA, #+B
894 printf(" v%d, #int %d // #%x",
895 pDecInsn->vA, (s4)pDecInsn->vB, (u1)pDecInsn->vB);
896 break;
897 case kFmt11x: // op vAA
898 printf(" v%d", pDecInsn->vA);
899 break;
900 case kFmt10t: // op +AA
901 case kFmt20t: // op +AAAA
902 {
903 s4 targ = (s4) pDecInsn->vA;
904 printf(" %04x // %c%04x",
905 insnIdx + targ,
906 (targ < 0) ? '-' : '+',
907 (targ < 0) ? -targ : targ);
908 }
909 break;
910 case kFmt22x: // op vAA, vBBBB
911 printf(" v%d, v%d", pDecInsn->vA, pDecInsn->vB);
912 break;
913 case kFmt21t: // op vAA, +BBBB
914 {
915 s4 targ = (s4) pDecInsn->vB;
916 printf(" v%d, %04x // %c%04x", pDecInsn->vA,
917 insnIdx + targ,
918 (targ < 0) ? '-' : '+',
919 (targ < 0) ? -targ : targ);
920 }
921 break;
922 case kFmt21s: // op vAA, #+BBBB
923 printf(" v%d, #int %d // #%x",
924 pDecInsn->vA, (s4)pDecInsn->vB, (u2)pDecInsn->vB);
925 break;
926 case kFmt21h: // op vAA, #+BBBB0000[00000000]
927 // The printed format varies a bit based on the actual opcode.
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800928 if (pDecInsn->opcode == OP_CONST_HIGH16) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800929 s4 value = pDecInsn->vB << 16;
930 printf(" v%d, #int %d // #%x",
931 pDecInsn->vA, value, (u2)pDecInsn->vB);
932 } else {
933 s8 value = ((s8) pDecInsn->vB) << 48;
934 printf(" v%d, #long %lld // #%x",
935 pDecInsn->vA, value, (u2)pDecInsn->vB);
936 }
937 break;
938 case kFmt21c: // op vAA, thing@BBBB
Dan Bornstein4a6b4822010-11-11 12:26:58 -0800939 case kFmt31c: // op vAA, thing@BBBBBBBB
940 case kFmt41c: // exop vAAAA, thing@BBBBBBBB
941 printf(" v%d, %s", pDecInsn->vA, indexBuf);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800942 break;
943 case kFmt23x: // op vAA, vBB, vCC
Dan Bornstein4a6b4822010-11-11 12:26:58 -0800944 case kFmt33x: // exop vAA, vBB, vCCCC
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800945 printf(" v%d, v%d, v%d", pDecInsn->vA, pDecInsn->vB, pDecInsn->vC);
946 break;
947 case kFmt22b: // op vAA, vBB, #+CC
948 printf(" v%d, v%d, #int %d // #%02x",
949 pDecInsn->vA, pDecInsn->vB, (s4)pDecInsn->vC, (u1)pDecInsn->vC);
950 break;
951 case kFmt22t: // op vA, vB, +CCCC
952 {
953 s4 targ = (s4) pDecInsn->vC;
954 printf(" v%d, v%d, %04x // %c%04x", pDecInsn->vA, pDecInsn->vB,
955 insnIdx + targ,
956 (targ < 0) ? '-' : '+',
957 (targ < 0) ? -targ : targ);
958 }
959 break;
960 case kFmt22s: // op vA, vB, #+CCCC
Dan Bornstein4a6b4822010-11-11 12:26:58 -0800961 case kFmt32s: // exop vAA, vBB, #+CCCC
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800962 printf(" v%d, v%d, #int %d // #%04x",
963 pDecInsn->vA, pDecInsn->vB, (s4)pDecInsn->vC, (u2)pDecInsn->vC);
964 break;
965 case kFmt22c: // op vA, vB, thing@CCCC
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800966 case kFmt22cs: // [opt] op vA, vB, field offset CCCC
Dan Bornstein4a6b4822010-11-11 12:26:58 -0800967 case kFmt52c: // exop vAAAA, vBBBB, thing@CCCCCCCC
968 printf(" v%d, v%d, %s", pDecInsn->vA, pDecInsn->vB, indexBuf);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800969 break;
970 case kFmt30t:
971 printf(" #%08x", pDecInsn->vA);
972 break;
973 case kFmt31i: // op vAA, #+BBBBBBBB
974 {
975 /* this is often, but not always, a float */
976 union {
977 float f;
978 u4 i;
979 } conv;
980 conv.i = pDecInsn->vB;
981 printf(" v%d, #float %f // #%08x",
982 pDecInsn->vA, conv.f, pDecInsn->vB);
983 }
984 break;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800985 case kFmt31t: // op vAA, offset +BBBBBBBB
986 printf(" v%d, %08x // +%08x",
987 pDecInsn->vA, insnIdx + pDecInsn->vB, pDecInsn->vB);
988 break;
989 case kFmt32x: // op vAAAA, vBBBB
990 printf(" v%d, v%d", pDecInsn->vA, pDecInsn->vB);
991 break;
Dan Bornstein7b3e9b02010-11-09 17:15:10 -0800992 case kFmt35c: // op {vC, vD, vE, vF, vG}, thing@BBBB
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800993 case kFmt35ms: // [opt] invoke-virtual+super
Dan Bornstein7b3e9b02010-11-09 17:15:10 -0800994 case kFmt35mi: // [opt] inline invoke
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800995 {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800996 fputs(" {", stdout);
997 for (i = 0; i < (int) pDecInsn->vA; i++) {
998 if (i == 0)
999 printf("v%d", pDecInsn->arg[i]);
1000 else
1001 printf(", v%d", pDecInsn->arg[i]);
1002 }
Dan Bornstein4a6b4822010-11-11 12:26:58 -08001003 printf("}, %s", indexBuf);
1004 }
1005 break;
1006 case kFmt3rc: // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB
1007 case kFmt3rms: // [opt] invoke-virtual+super/range
1008 case kFmt3rmi: // [opt] execute-inline/range
1009 case kFmt5rc: // exop {vCCCC .. v(CCCC+AAAA-1)}, meth@BBBBBBBB
1010 {
1011 /*
1012 * This doesn't match the "dx" output when some of the args are
1013 * 64-bit values -- dx only shows the first register.
1014 */
1015 fputs(" {", stdout);
1016 for (i = 0; i < (int) pDecInsn->vA; i++) {
1017 if (i == 0)
1018 printf("v%d", pDecInsn->vC + i);
1019 else
1020 printf(", v%d", pDecInsn->vC + i);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001021 }
Dan Bornstein4a6b4822010-11-11 12:26:58 -08001022 printf("}, %s", indexBuf);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001023 }
1024 break;
1025 case kFmt51l: // op vAA, #+BBBBBBBBBBBBBBBB
1026 {
1027 /* this is often, but not always, a double */
1028 union {
1029 double d;
1030 u8 j;
1031 } conv;
1032 conv.j = pDecInsn->vB_wide;
1033 printf(" v%d, #double %f // #%016llx",
1034 pDecInsn->vA, conv.d, pDecInsn->vB_wide);
1035 }
1036 break;
Dan Bornstein84244322010-11-17 12:05:04 -08001037 case kFmt00x: // unknown op or breakpoint
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001038 break;
1039 default:
1040 printf(" ???");
1041 break;
1042 }
1043
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001044 putchar('\n');
1045
Dan Bornstein4a6b4822010-11-11 12:26:58 -08001046 if (indexBuf != indexBufChars) {
1047 free(indexBuf);
1048 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001049}
1050
1051/*
1052 * Dump a bytecode disassembly.
1053 */
1054void dumpBytecodes(DexFile* pDexFile, const DexMethod* pDexMethod)
1055{
1056 const DexCode* pCode = dexGetCode(pDexFile, pDexMethod);
1057 const u2* insns;
1058 int insnIdx;
1059 FieldMethodInfo methInfo;
1060 int startAddr;
1061 char* className = NULL;
1062
1063 assert(pCode->insnsSize > 0);
1064 insns = pCode->insns;
1065
1066 getMethodInfo(pDexFile, pDexMethod->methodIdx, &methInfo);
1067 startAddr = ((u1*)pCode - pDexFile->baseAddr);
1068 className = descriptorToDot(methInfo.classDescriptor);
1069
1070 printf("%06x: |[%06x] %s.%s:%s\n",
1071 startAddr, startAddr,
1072 className, methInfo.name, methInfo.signature);
1073
1074 insnIdx = 0;
1075 while (insnIdx < (int) pCode->insnsSize) {
1076 int insnWidth;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001077 DecodedInstruction decInsn;
1078 u2 instr;
1079
Dan Bornstein11122162010-12-01 12:30:21 -08001080 /*
1081 * Note: This code parallels the function
Dan Bornsteine4852762010-12-02 12:45:00 -08001082 * dexGetWidthFromInstruction() in InstrUtils.c, but this version
Dan Bornstein11122162010-12-01 12:30:21 -08001083 * can deal with data in either endianness.
1084 *
1085 * TODO: Figure out if this really matters, and possibly change
Dan Bornsteine4852762010-12-02 12:45:00 -08001086 * this to just use dexGetWidthFromInstruction().
Dan Bornstein11122162010-12-01 12:30:21 -08001087 */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001088 instr = get2LE((const u1*)insns);
1089 if (instr == kPackedSwitchSignature) {
1090 insnWidth = 4 + get2LE((const u1*)(insns+1)) * 2;
1091 } else if (instr == kSparseSwitchSignature) {
1092 insnWidth = 2 + get2LE((const u1*)(insns+1)) * 4;
1093 } else if (instr == kArrayDataSignature) {
1094 int width = get2LE((const u1*)(insns+1));
Carl Shapirode750892010-06-08 16:37:12 -07001095 int size = get2LE((const u1*)(insns+2)) |
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001096 (get2LE((const u1*)(insns+3))<<16);
Dan Bornstein11122162010-12-01 12:30:21 -08001097 // The plus 1 is to round up for odd size and width.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001098 insnWidth = 4 + ((size * width) + 1) / 2;
1099 } else {
Dan Bornstein9a1f8162010-12-01 17:02:26 -08001100 Opcode opcode = dexOpcodeFromCodeUnit(instr);
Dan Bornsteine4852762010-12-02 12:45:00 -08001101 insnWidth = dexGetWidthFromOpcode(opcode);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001102 if (insnWidth == 0) {
1103 fprintf(stderr,
1104 "GLITCH: zero-width instruction at idx=0x%04x\n", insnIdx);
1105 break;
1106 }
1107 }
1108
Dan Bornstein54322392010-11-17 14:16:56 -08001109 dexDecodeInstruction(insns, &decInsn);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001110 dumpInstruction(pDexFile, pCode, insnIdx, insnWidth, &decInsn);
1111
1112 insns += insnWidth;
1113 insnIdx += insnWidth;
1114 }
1115
1116 free(className);
1117}
1118
1119/*
1120 * Dump a "code" struct.
1121 */
1122void dumpCode(DexFile* pDexFile, const DexMethod* pDexMethod)
1123{
1124 const DexCode* pCode = dexGetCode(pDexFile, pDexMethod);
1125
1126 printf(" registers : %d\n", pCode->registersSize);
1127 printf(" ins : %d\n", pCode->insSize);
1128 printf(" outs : %d\n", pCode->outsSize);
1129 printf(" insns size : %d 16-bit code units\n", pCode->insnsSize);
1130
1131 if (gOptions.disassemble)
1132 dumpBytecodes(pDexFile, pDexMethod);
1133
1134 dumpCatches(pDexFile, pCode);
1135 /* both of these are encoded in debug info */
1136 dumpPositions(pDexFile, pCode, pDexMethod);
1137 dumpLocals(pDexFile, pCode, pDexMethod);
1138}
1139
1140/*
1141 * Dump a method.
1142 */
1143void dumpMethod(DexFile* pDexFile, const DexMethod* pDexMethod, int i)
1144{
1145 const DexMethodId* pMethodId;
1146 const char* backDescriptor;
1147 const char* name;
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001148 char* typeDescriptor = NULL;
1149 char* accessStr = NULL;
1150
1151 if (gOptions.exportsOnly &&
1152 (pDexMethod->accessFlags & (ACC_PUBLIC | ACC_PROTECTED)) == 0)
1153 {
1154 return;
1155 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001156
1157 pMethodId = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
1158 name = dexStringById(pDexFile, pMethodId->nameIdx);
1159 typeDescriptor = dexCopyDescriptorFromMethodId(pDexFile, pMethodId);
1160
1161 backDescriptor = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
1162
1163 accessStr = createAccessFlagStr(pDexMethod->accessFlags,
1164 kAccessForMethod);
1165
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001166 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1167 printf(" #%d : (in %s)\n", i, backDescriptor);
1168 printf(" name : '%s'\n", name);
1169 printf(" type : '%s'\n", typeDescriptor);
1170 printf(" access : 0x%04x (%s)\n",
1171 pDexMethod->accessFlags, accessStr);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001172
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001173 if (pDexMethod->codeOff == 0) {
1174 printf(" code : (none)\n");
1175 } else {
1176 printf(" code -\n");
1177 dumpCode(pDexFile, pDexMethod);
1178 }
1179
1180 if (gOptions.disassemble)
1181 putchar('\n');
1182 } else if (gOptions.outputFormat == OUTPUT_XML) {
1183 bool constructor = (name[0] == '<');
1184
1185 if (constructor) {
1186 char* tmp;
1187
1188 tmp = descriptorClassToDot(backDescriptor);
1189 printf("<constructor name=\"%s\"\n", tmp);
1190 free(tmp);
1191
1192 tmp = descriptorToDot(backDescriptor);
1193 printf(" type=\"%s\"\n", tmp);
1194 free(tmp);
1195 } else {
1196 printf("<method name=\"%s\"\n", name);
1197
1198 const char* returnType = strrchr(typeDescriptor, ')');
1199 if (returnType == NULL) {
1200 fprintf(stderr, "bad method type descriptor '%s'\n",
1201 typeDescriptor);
1202 goto bail;
1203 }
1204
1205 char* tmp = descriptorToDot(returnType+1);
1206 printf(" return=\"%s\"\n", tmp);
1207 free(tmp);
1208
1209 printf(" abstract=%s\n",
1210 quotedBool((pDexMethod->accessFlags & ACC_ABSTRACT) != 0));
1211 printf(" native=%s\n",
1212 quotedBool((pDexMethod->accessFlags & ACC_NATIVE) != 0));
1213
1214 bool isSync =
1215 (pDexMethod->accessFlags & ACC_SYNCHRONIZED) != 0 ||
1216 (pDexMethod->accessFlags & ACC_DECLARED_SYNCHRONIZED) != 0;
1217 printf(" synchronized=%s\n", quotedBool(isSync));
1218 }
1219
1220 printf(" static=%s\n",
1221 quotedBool((pDexMethod->accessFlags & ACC_STATIC) != 0));
1222 printf(" final=%s\n",
1223 quotedBool((pDexMethod->accessFlags & ACC_FINAL) != 0));
1224 // "deprecated=" not knowable w/o parsing annotations
1225 printf(" visibility=%s\n",
1226 quotedVisibility(pDexMethod->accessFlags));
1227
1228 printf(">\n");
1229
1230 /*
1231 * Parameters.
1232 */
1233 if (typeDescriptor[0] != '(') {
1234 fprintf(stderr, "ERROR: bad descriptor '%s'\n", typeDescriptor);
1235 goto bail;
1236 }
1237
1238 char tmpBuf[strlen(typeDescriptor)+1]; /* more than big enough */
1239 int argNum = 0;
1240
1241 const char* base = typeDescriptor+1;
1242
1243 while (*base != ')') {
1244 char* cp = tmpBuf;
1245
1246 while (*base == '[')
1247 *cp++ = *base++;
1248
1249 if (*base == 'L') {
1250 /* copy through ';' */
1251 do {
1252 *cp = *base++;
1253 } while (*cp++ != ';');
1254 } else {
1255 /* primitive char, copy it */
1256 if (strchr("ZBCSIFJD", *base) == NULL) {
1257 fprintf(stderr, "ERROR: bad method signature '%s'\n", base);
1258 goto bail;
1259 }
1260 *cp++ = *base++;
1261 }
1262
1263 /* null terminate and display */
1264 *cp++ = '\0';
1265
1266 char* tmp = descriptorToDot(tmpBuf);
1267 printf("<parameter name=\"arg%d\" type=\"%s\">\n</parameter>\n",
1268 argNum++, tmp);
1269 free(tmp);
1270 }
1271
1272 if (constructor)
1273 printf("</constructor>\n");
1274 else
1275 printf("</method>\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001276 }
1277
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001278bail:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001279 free(typeDescriptor);
1280 free(accessStr);
1281}
1282
1283/*
1284 * Dump a static (class) field.
1285 */
1286void dumpSField(const DexFile* pDexFile, const DexField* pSField, int i)
1287{
1288 const DexFieldId* pFieldId;
1289 const char* backDescriptor;
1290 const char* name;
1291 const char* typeDescriptor;
1292 char* accessStr;
1293
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001294 if (gOptions.exportsOnly &&
1295 (pSField->accessFlags & (ACC_PUBLIC | ACC_PROTECTED)) == 0)
1296 {
1297 return;
1298 }
1299
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001300 pFieldId = dexGetFieldId(pDexFile, pSField->fieldIdx);
1301 name = dexStringById(pDexFile, pFieldId->nameIdx);
1302 typeDescriptor = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx);
1303 backDescriptor = dexStringByTypeIdx(pDexFile, pFieldId->classIdx);
1304
1305 accessStr = createAccessFlagStr(pSField->accessFlags, kAccessForField);
1306
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001307 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1308 printf(" #%d : (in %s)\n", i, backDescriptor);
1309 printf(" name : '%s'\n", name);
1310 printf(" type : '%s'\n", typeDescriptor);
1311 printf(" access : 0x%04x (%s)\n",
1312 pSField->accessFlags, accessStr);
1313 } else if (gOptions.outputFormat == OUTPUT_XML) {
1314 char* tmp;
1315
1316 printf("<field name=\"%s\"\n", name);
1317
1318 tmp = descriptorToDot(typeDescriptor);
1319 printf(" type=\"%s\"\n", tmp);
1320 free(tmp);
1321
1322 printf(" transient=%s\n",
1323 quotedBool((pSField->accessFlags & ACC_TRANSIENT) != 0));
1324 printf(" volatile=%s\n",
1325 quotedBool((pSField->accessFlags & ACC_VOLATILE) != 0));
1326 // "value=" not knowable w/o parsing annotations
1327 printf(" static=%s\n",
1328 quotedBool((pSField->accessFlags & ACC_STATIC) != 0));
1329 printf(" final=%s\n",
1330 quotedBool((pSField->accessFlags & ACC_FINAL) != 0));
1331 // "deprecated=" not knowable w/o parsing annotations
1332 printf(" visibility=%s\n",
1333 quotedVisibility(pSField->accessFlags));
1334 printf(">\n</field>\n");
1335 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001336
1337 free(accessStr);
1338}
1339
1340/*
1341 * Dump an instance field.
1342 */
1343void dumpIField(const DexFile* pDexFile, const DexField* pIField, int i)
1344{
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001345 dumpSField(pDexFile, pIField, i);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001346}
1347
1348/*
1349 * Dump the class.
The Android Open Source Project99409882009-03-18 22:20:24 -07001350 *
1351 * Note "idx" is a DexClassDef index, not a DexTypeId index.
Andy McFaddend18aff32009-05-06 10:19:16 -07001352 *
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001353 * If "*pLastPackage" is NULL or does not match the current class' package,
1354 * the value will be replaced with a newly-allocated string.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001355 */
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001356void dumpClass(DexFile* pDexFile, int idx, char** pLastPackage)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001357{
1358 const DexTypeList* pInterfaces;
1359 const DexClassDef* pClassDef;
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001360 DexClassData* pClassData = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001361 const u1* pEncodedData;
1362 const char* fileName;
1363 const char* classDescriptor;
1364 const char* superclassDescriptor;
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001365 char* accessStr = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001366 int i;
1367
1368 pClassDef = dexGetClassDef(pDexFile, idx);
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001369
1370 if (gOptions.exportsOnly && (pClassDef->accessFlags & ACC_PUBLIC) == 0) {
1371 //printf("<!-- omitting non-public class %s -->\n",
1372 // classDescriptor);
1373 goto bail;
1374 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001375
1376 pEncodedData = dexGetClassData(pDexFile, pClassDef);
1377 pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL);
1378
1379 if (pClassData == NULL) {
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001380 printf("Trouble reading class data (#%d)\n", idx);
1381 goto bail;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001382 }
Carl Shapirode750892010-06-08 16:37:12 -07001383
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001384 classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001385
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001386 /*
1387 * For the XML output, show the package name. Ideally we'd gather
1388 * up the classes, sort them, and dump them alphabetically so the
1389 * package name wouldn't jump around, but that's not a great plan
1390 * for something that needs to run on the device.
1391 */
1392 if (!(classDescriptor[0] == 'L' &&
1393 classDescriptor[strlen(classDescriptor)-1] == ';'))
1394 {
1395 /* arrays and primitives should not be defined explicitly */
1396 fprintf(stderr, "Malformed class name '%s'\n", classDescriptor);
1397 /* keep going? */
1398 } else if (gOptions.outputFormat == OUTPUT_XML) {
1399 char* mangle;
1400 char* lastSlash;
1401 char* cp;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001402
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001403 mangle = strdup(classDescriptor + 1);
1404 mangle[strlen(mangle)-1] = '\0';
1405
1406 /* reduce to just the package name */
1407 lastSlash = strrchr(mangle, '/');
1408 if (lastSlash != NULL) {
1409 *lastSlash = '\0';
1410 } else {
1411 *mangle = '\0';
1412 }
1413
1414 for (cp = mangle; *cp != '\0'; cp++) {
1415 if (*cp == '/')
1416 *cp = '.';
1417 }
1418
1419 if (*pLastPackage == NULL || strcmp(mangle, *pLastPackage) != 0) {
1420 /* start of a new package */
1421 if (*pLastPackage != NULL)
1422 printf("</package>\n");
1423 printf("<package name=\"%s\"\n>\n", mangle);
1424 free(*pLastPackage);
1425 *pLastPackage = mangle;
1426 } else {
1427 free(mangle);
1428 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001429 }
1430
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001431 accessStr = createAccessFlagStr(pClassDef->accessFlags, kAccessForClass);
1432
1433 if (pClassDef->superclassIdx == kDexNoIndex) {
1434 superclassDescriptor = NULL;
1435 } else {
1436 superclassDescriptor =
1437 dexStringByTypeIdx(pDexFile, pClassDef->superclassIdx);
1438 }
1439
1440 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1441 printf("Class #%d -\n", idx);
1442 printf(" Class descriptor : '%s'\n", classDescriptor);
1443 printf(" Access flags : 0x%04x (%s)\n",
1444 pClassDef->accessFlags, accessStr);
1445
1446 if (superclassDescriptor != NULL)
1447 printf(" Superclass : '%s'\n", superclassDescriptor);
1448
1449 printf(" Interfaces -\n");
1450 } else {
1451 char* tmp;
1452
1453 tmp = descriptorClassToDot(classDescriptor);
1454 printf("<class name=\"%s\"\n", tmp);
1455 free(tmp);
1456
1457 if (superclassDescriptor != NULL) {
1458 tmp = descriptorToDot(superclassDescriptor);
1459 printf(" extends=\"%s\"\n", tmp);
1460 free(tmp);
1461 }
1462 printf(" abstract=%s\n",
1463 quotedBool((pClassDef->accessFlags & ACC_ABSTRACT) != 0));
1464 printf(" static=%s\n",
1465 quotedBool((pClassDef->accessFlags & ACC_STATIC) != 0));
1466 printf(" final=%s\n",
1467 quotedBool((pClassDef->accessFlags & ACC_FINAL) != 0));
1468 // "deprecated=" not knowable w/o parsing annotations
1469 printf(" visibility=%s\n",
1470 quotedVisibility(pClassDef->accessFlags));
1471 printf(">\n");
1472 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001473 pInterfaces = dexGetInterfacesList(pDexFile, pClassDef);
1474 if (pInterfaces != NULL) {
1475 for (i = 0; i < (int) pInterfaces->size; i++)
1476 dumpInterface(pDexFile, dexGetTypeItem(pInterfaces, i), i);
1477 }
1478
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001479 if (gOptions.outputFormat == OUTPUT_PLAIN)
1480 printf(" Static fields -\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001481 for (i = 0; i < (int) pClassData->header.staticFieldsSize; i++) {
1482 dumpSField(pDexFile, &pClassData->staticFields[i], i);
1483 }
1484
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001485 if (gOptions.outputFormat == OUTPUT_PLAIN)
1486 printf(" Instance fields -\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001487 for (i = 0; i < (int) pClassData->header.instanceFieldsSize; i++) {
1488 dumpIField(pDexFile, &pClassData->instanceFields[i], i);
1489 }
1490
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001491 if (gOptions.outputFormat == OUTPUT_PLAIN)
1492 printf(" Direct methods -\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001493 for (i = 0; i < (int) pClassData->header.directMethodsSize; i++) {
1494 dumpMethod(pDexFile, &pClassData->directMethods[i], i);
1495 }
1496
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001497 if (gOptions.outputFormat == OUTPUT_PLAIN)
1498 printf(" Virtual methods -\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001499 for (i = 0; i < (int) pClassData->header.virtualMethodsSize; i++) {
1500 dumpMethod(pDexFile, &pClassData->virtualMethods[i], i);
1501 }
1502
1503 // TODO: Annotations.
1504
1505 if (pClassDef->sourceFileIdx != kDexNoIndex)
1506 fileName = dexStringById(pDexFile, pClassDef->sourceFileIdx);
1507 else
1508 fileName = "unknown";
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001509
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001510 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1511 printf(" source_file_idx : %d (%s)\n",
1512 pClassDef->sourceFileIdx, fileName);
1513 printf("\n");
1514 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001515
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001516 if (gOptions.outputFormat == OUTPUT_XML) {
1517 printf("</class>\n");
1518 }
1519
1520bail:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001521 free(pClassData);
1522 free(accessStr);
1523}
1524
The Android Open Source Project99409882009-03-18 22:20:24 -07001525
1526/*
1527 * Advance "ptr" to ensure 32-bit alignment.
1528 */
1529static inline const u1* align32(const u1* ptr)
1530{
1531 return (u1*) (((int) ptr + 3) & ~0x03);
1532}
1533
Andy McFadden10351272009-03-24 21:30:32 -07001534
1535/*
1536 * Dump a map in the "differential" format.
1537 *
1538 * TODO: show a hex dump of the compressed data. (We can show the
1539 * uncompressed data if we move the compression code to libdex; otherwise
1540 * it's too complex to merit a fast & fragile implementation here.)
1541 */
1542void dumpDifferentialCompressedMap(const u1** pData)
1543{
1544 const u1* data = *pData;
1545 const u1* dataStart = data -1; // format byte already removed
1546 u1 regWidth;
1547 u2 numEntries;
1548
1549 /* standard header */
1550 regWidth = *data++;
1551 numEntries = *data++;
1552 numEntries |= (*data++) << 8;
1553
1554 /* compressed data begins with the compressed data length */
1555 int compressedLen = readUnsignedLeb128(&data);
1556 int addrWidth = 1;
1557 if ((*data & 0x80) != 0)
1558 addrWidth++;
1559
1560 int origLen = 4 + (addrWidth + regWidth) * numEntries;
1561 int compLen = (data - dataStart) + compressedLen;
1562
1563 printf(" (differential compression %d -> %d [%d -> %d])\n",
1564 origLen, compLen,
1565 (addrWidth + regWidth) * numEntries, compressedLen);
1566
1567 /* skip past end of entry */
1568 data += compressedLen;
1569
1570 *pData = data;
1571}
1572
The Android Open Source Project99409882009-03-18 22:20:24 -07001573/*
1574 * Dump register map contents of the current method.
1575 *
1576 * "*pData" should point to the start of the register map data. Advances
1577 * "*pData" to the start of the next map.
1578 */
1579void dumpMethodMap(DexFile* pDexFile, const DexMethod* pDexMethod, int idx,
1580 const u1** pData)
1581{
1582 const u1* data = *pData;
1583 const DexMethodId* pMethodId;
1584 const char* name;
1585 int offset = data - (u1*) pDexFile->pOptHeader;
1586
1587 pMethodId = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
1588 name = dexStringById(pDexFile, pMethodId->nameIdx);
1589 printf(" #%d: 0x%08x %s\n", idx, offset, name);
1590
1591 u1 format;
1592 int addrWidth;
1593
1594 format = *data++;
1595 if (format == 1) { /* kRegMapFormatNone */
1596 /* no map */
1597 printf(" (no map)\n");
1598 addrWidth = 0;
1599 } else if (format == 2) { /* kRegMapFormatCompact8 */
1600 addrWidth = 1;
1601 } else if (format == 3) { /* kRegMapFormatCompact16 */
1602 addrWidth = 2;
Andy McFadden10351272009-03-24 21:30:32 -07001603 } else if (format == 4) { /* kRegMapFormatDifferential */
1604 dumpDifferentialCompressedMap(&data);
1605 goto bail;
The Android Open Source Project99409882009-03-18 22:20:24 -07001606 } else {
1607 printf(" (unknown format %d!)\n", format);
Andy McFadden10351272009-03-24 21:30:32 -07001608 /* don't know how to skip data; failure will cascade to end of class */
1609 goto bail;
The Android Open Source Project99409882009-03-18 22:20:24 -07001610 }
1611
1612 if (addrWidth > 0) {
1613 u1 regWidth;
1614 u2 numEntries;
1615 int idx, addr, byte;
1616
1617 regWidth = *data++;
1618 numEntries = *data++;
1619 numEntries |= (*data++) << 8;
1620
1621 for (idx = 0; idx < numEntries; idx++) {
1622 addr = *data++;
1623 if (addrWidth > 1)
1624 addr |= (*data++) << 8;
1625
1626 printf(" %4x:", addr);
1627 for (byte = 0; byte < regWidth; byte++) {
1628 printf(" %02x", *data++);
1629 }
1630 printf("\n");
1631 }
1632 }
1633
Andy McFadden10351272009-03-24 21:30:32 -07001634bail:
The Android Open Source Project99409882009-03-18 22:20:24 -07001635 //if (addrWidth >= 0)
1636 // *pData = align32(data);
1637 *pData = data;
1638}
1639
1640/*
1641 * Dump the contents of the register map area.
1642 *
1643 * These are only present in optimized DEX files, and the structure is
1644 * not really exposed to other parts of the VM itself. We're going to
1645 * dig through them here, but this is pretty fragile. DO NOT rely on
1646 * this or derive other code from it.
1647 */
1648void dumpRegisterMaps(DexFile* pDexFile)
1649{
1650 const u1* pClassPool = pDexFile->pRegisterMapPool;
1651 const u4* classOffsets;
1652 const u1* ptr;
1653 u4 numClasses;
1654 int baseFileOffset = (u1*) pClassPool - (u1*) pDexFile->pOptHeader;
1655 int idx;
1656
1657 if (pClassPool == NULL) {
1658 printf("No register maps found\n");
1659 return;
1660 }
1661
1662 ptr = pClassPool;
1663 numClasses = get4LE(ptr);
1664 ptr += sizeof(u4);
1665 classOffsets = (const u4*) ptr;
1666
1667 printf("RMAP begins at offset 0x%07x\n", baseFileOffset);
1668 printf("Maps for %d classes\n", numClasses);
1669 for (idx = 0; idx < (int) numClasses; idx++) {
1670 const DexClassDef* pClassDef;
1671 const char* classDescriptor;
1672
1673 pClassDef = dexGetClassDef(pDexFile, idx);
1674 classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
1675
1676 printf("%4d: +%d (0x%08x) %s\n", idx, classOffsets[idx],
1677 baseFileOffset + classOffsets[idx], classDescriptor);
1678
1679 if (classOffsets[idx] == 0)
1680 continue;
1681
1682 /*
1683 * What follows is a series of RegisterMap entries, one for every
1684 * direct method, then one for every virtual method.
1685 */
1686 DexClassData* pClassData;
1687 const u1* pEncodedData;
1688 const u1* data = (u1*) pClassPool + classOffsets[idx];
1689 u2 methodCount;
1690 int i;
1691
1692 pEncodedData = dexGetClassData(pDexFile, pClassDef);
1693 pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL);
1694 if (pClassData == NULL) {
1695 fprintf(stderr, "Trouble reading class data\n");
1696 continue;
1697 }
1698
1699 methodCount = *data++;
1700 methodCount |= (*data++) << 8;
1701 data += 2; /* two pad bytes follow methodCount */
1702 if (methodCount != pClassData->header.directMethodsSize
1703 + pClassData->header.virtualMethodsSize)
1704 {
1705 printf("NOTE: method count discrepancy (%d != %d + %d)\n",
1706 methodCount, pClassData->header.directMethodsSize,
1707 pClassData->header.virtualMethodsSize);
1708 /* this is bad, but keep going anyway */
1709 }
1710
1711 printf(" direct methods: %d\n",
1712 pClassData->header.directMethodsSize);
1713 for (i = 0; i < (int) pClassData->header.directMethodsSize; i++) {
1714 dumpMethodMap(pDexFile, &pClassData->directMethods[i], i, &data);
1715 }
1716
1717 printf(" virtual methods: %d\n",
1718 pClassData->header.virtualMethodsSize);
1719 for (i = 0; i < (int) pClassData->header.virtualMethodsSize; i++) {
1720 dumpMethodMap(pDexFile, &pClassData->virtualMethods[i], i, &data);
1721 }
1722
1723 free(pClassData);
1724 }
1725}
1726
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001727/*
1728 * Dump the requested sections of the file.
1729 */
1730void processDexFile(const char* fileName, DexFile* pDexFile)
1731{
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001732 char* package = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001733 int i;
1734
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001735 if (gOptions.verbose) {
1736 printf("Opened '%s', DEX version '%.3s'\n", fileName,
1737 pDexFile->pHeader->magic +4);
1738 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001739
The Android Open Source Project99409882009-03-18 22:20:24 -07001740 if (gOptions.dumpRegisterMaps) {
1741 dumpRegisterMaps(pDexFile);
1742 return;
1743 }
1744
Andy McFadden0ea77b92010-04-20 14:18:59 -07001745 if (gOptions.showFileHeaders) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001746 dumpFileHeader(pDexFile);
Dan Bornsteine377ef62010-08-31 16:50:00 -07001747 dumpOptDirectory(pDexFile);
Andy McFadden0ea77b92010-04-20 14:18:59 -07001748 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001749
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001750 if (gOptions.outputFormat == OUTPUT_XML)
1751 printf("<api>\n");
1752
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001753 for (i = 0; i < (int) pDexFile->pHeader->classDefsSize; i++) {
1754 if (gOptions.showSectionHeaders)
1755 dumpClassDef(pDexFile, i);
1756
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001757 dumpClass(pDexFile, i, &package);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001758 }
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001759
1760 /* free the last one allocated */
1761 if (package != NULL) {
1762 printf("</package>\n");
1763 free(package);
1764 }
1765
1766 if (gOptions.outputFormat == OUTPUT_XML)
1767 printf("</api>\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001768}
1769
1770
1771/*
1772 * Process one file.
1773 */
1774int process(const char* fileName)
1775{
1776 DexFile* pDexFile = NULL;
1777 MemMapping map;
1778 bool mapped = false;
1779 int result = -1;
1780
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001781 if (gOptions.verbose)
1782 printf("Processing '%s'...\n", fileName);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001783
1784 if (dexOpenAndMap(fileName, gOptions.tempFileName, &map, false) != 0)
1785 goto bail;
1786 mapped = true;
1787
Andy McFadden2124cb82009-03-25 15:37:39 -07001788 int flags = kDexParseVerifyChecksum;
1789 if (gOptions.ignoreBadChecksum)
1790 flags |= kDexParseContinueOnError;
1791
1792 pDexFile = dexFileParse(map.addr, map.length, flags);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001793 if (pDexFile == NULL) {
1794 fprintf(stderr, "ERROR: DEX parse failed\n");
1795 goto bail;
1796 }
1797
Andy McFadden0198b142009-04-02 14:48:56 -07001798 if (gOptions.checksumOnly) {
1799 printf("Checksum verified\n");
1800 } else {
1801 processDexFile(fileName, pDexFile);
1802 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001803
1804 result = 0;
1805
1806bail:
1807 if (mapped)
1808 sysReleaseShmem(&map);
1809 if (pDexFile != NULL)
1810 dexFileFree(pDexFile);
1811 return result;
1812}
1813
1814
1815/*
1816 * Show usage.
1817 */
1818void usage(void)
1819{
1820 fprintf(stderr, "Copyright (C) 2007 The Android Open Source Project\n\n");
Andy McFadden0198b142009-04-02 14:48:56 -07001821 fprintf(stderr,
Andy McFaddend18aff32009-05-06 10:19:16 -07001822 "%s: [-c] [-d] [-f] [-h] [-i] [-l layout] [-m] [-t tempfile] dexfile...\n",
The Android Open Source Project99409882009-03-18 22:20:24 -07001823 gProgName);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001824 fprintf(stderr, "\n");
Andy McFadden0198b142009-04-02 14:48:56 -07001825 fprintf(stderr, " -c : verify checksum and exit\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001826 fprintf(stderr, " -d : disassemble code sections\n");
1827 fprintf(stderr, " -f : display summary information from file header\n");
1828 fprintf(stderr, " -h : display file header details\n");
Andy McFadden2124cb82009-03-25 15:37:39 -07001829 fprintf(stderr, " -i : ignore checksum failures\n");
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001830 fprintf(stderr, " -l : output layout, either 'plain' or 'xml'\n");
The Android Open Source Project99409882009-03-18 22:20:24 -07001831 fprintf(stderr, " -m : dump register maps (and nothing else)\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001832 fprintf(stderr, " -t : temp file name (defaults to /sdcard/dex-temp-*)\n");
1833}
1834
1835/*
1836 * Parse args.
1837 *
1838 * I'm not using getopt_long() because we may not have it in libc.
1839 */
1840int main(int argc, char* const argv[])
1841{
1842 bool wantUsage = false;
1843 int ic;
1844
1845 memset(&gOptions, 0, sizeof(gOptions));
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001846 gOptions.verbose = true;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001847
1848 while (1) {
Andy McFaddend18aff32009-05-06 10:19:16 -07001849 ic = getopt(argc, argv, "cdfhil:mt:");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001850 if (ic < 0)
1851 break;
1852
1853 switch (ic) {
Andy McFadden0198b142009-04-02 14:48:56 -07001854 case 'c': // verify the checksum then exit
1855 gOptions.checksumOnly = true;
1856 break;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001857 case 'd': // disassemble Dalvik instructions
1858 gOptions.disassemble = true;
1859 break;
1860 case 'f': // dump outer file header
1861 gOptions.showFileHeaders = true;
1862 break;
1863 case 'h': // dump section headers, i.e. all meta-data
1864 gOptions.showSectionHeaders = true;
1865 break;
Andy McFadden2124cb82009-03-25 15:37:39 -07001866 case 'i': // continue even if checksum is bad
1867 gOptions.ignoreBadChecksum = true;
1868 break;
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001869 case 'l': // layout
1870 if (strcmp(optarg, "plain") == 0) {
1871 gOptions.outputFormat = OUTPUT_PLAIN;
1872 } else if (strcmp(optarg, "xml") == 0) {
1873 gOptions.outputFormat = OUTPUT_XML;
1874 gOptions.verbose = false;
1875 gOptions.exportsOnly = true;
1876 } else {
1877 wantUsage = true;
1878 }
1879 break;
The Android Open Source Project99409882009-03-18 22:20:24 -07001880 case 'm': // dump register maps only
1881 gOptions.dumpRegisterMaps = true;
1882 break;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001883 case 't': // temp file, used when opening compressed Jar
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001884 gOptions.tempFileName = optarg;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001885 break;
1886 default:
1887 wantUsage = true;
1888 break;
1889 }
1890 }
1891
1892 if (optind == argc) {
1893 fprintf(stderr, "%s: no file specified\n", gProgName);
1894 wantUsage = true;
1895 }
1896
Andy McFadden0198b142009-04-02 14:48:56 -07001897 if (gOptions.checksumOnly && gOptions.ignoreBadChecksum) {
1898 fprintf(stderr, "Can't specify both -c and -i\n");
1899 wantUsage = true;
1900 }
1901
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001902 if (wantUsage) {
1903 usage();
1904 return 2;
1905 }
1906
Andy McFadden0198b142009-04-02 14:48:56 -07001907 int result = 0;
1908 while (optind < argc) {
1909 result |= process(argv[optind++]);
1910 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001911
Andy McFadden0198b142009-04-02 14:48:56 -07001912 return (result != 0);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001913}