blob: bfb5aa1d90e9fe3356163b75938a475c20a185bd [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
Carl Shapirobfc97992011-04-27 14:16:08 -070055enum OutputFormat {
Andy McFaddena2ee53b2009-05-05 16:52:10 -070056 OUTPUT_PLAIN = 0, /* default */
57 OUTPUT_XML, /* fancy */
Carl Shapirobfc97992011-04-27 14:16:08 -070058};
Andy McFaddena2ee53b2009-05-05 16:52:10 -070059
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080060/* command-line options */
Carl Shapirobfc97992011-04-27 14:16:08 -070061struct Options {
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;
Carl Shapirobfc97992011-04-27 14:16:08 -070072};
73
74struct Options gOptions;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080075
76/* basic info about a field or method */
Carl Shapirobfc97992011-04-27 14:16:08 -070077struct FieldMethodInfo {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080078 const char* classDescriptor;
79 const char* name;
80 const char* signature;
Carl Shapirobfc97992011-04-27 14:16:08 -070081};
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080082
83/*
Carl Shapirode750892010-06-08 16:37:12 -070084 * Get 2 little-endian bytes.
85 */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080086static inline u2 get2LE(unsigned char const* pSrc)
87{
88 return pSrc[0] | (pSrc[1] << 8);
Carl Shapirode750892010-06-08 16:37:12 -070089}
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080090
91/*
Carl Shapirode750892010-06-08 16:37:12 -070092 * Get 4 little-endian bytes.
93 */
The Android Open Source Project99409882009-03-18 22:20:24 -070094static inline u4 get4LE(unsigned char const* pSrc)
95{
96 return pSrc[0] | (pSrc[1] << 8) | (pSrc[2] << 16) | (pSrc[3] << 24);
Carl Shapirode750892010-06-08 16:37:12 -070097}
The Android Open Source Project99409882009-03-18 22:20:24 -070098
99/*
Andy McFaddena2ee53b2009-05-05 16:52:10 -0700100 * Converts a single-character primitive type into its human-readable
101 * equivalent.
102 */
103static const char* primitiveTypeLabel(char typeChar)
104{
105 switch (typeChar) {
106 case 'B': return "byte";
107 case 'C': return "char";
108 case 'D': return "double";
109 case 'F': return "float";
110 case 'I': return "int";
111 case 'J': return "long";
112 case 'S': return "short";
113 case 'V': return "void";
114 case 'Z': return "boolean";
115 default:
116 return "UNKNOWN";
117 }
118}
119
120/*
121 * Converts a type descriptor to human-readable "dotted" form. For
122 * example, "Ljava/lang/String;" becomes "java.lang.String", and
123 * "[I" becomes "int[]". Also converts '$' to '.', which means this
124 * form can't be converted back to a descriptor.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800125 */
126static char* descriptorToDot(const char* str)
127{
Andy McFaddena2ee53b2009-05-05 16:52:10 -0700128 int targetLen = strlen(str);
129 int offset = 0;
130 int arrayDepth = 0;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800131 char* newStr;
132
Andy McFaddena2ee53b2009-05-05 16:52:10 -0700133 /* strip leading [s; will be added to end */
134 while (targetLen > 1 && str[offset] == '[') {
135 offset++;
136 targetLen--;
137 }
138 arrayDepth = offset;
139
140 if (targetLen == 1) {
141 /* primitive type */
142 str = primitiveTypeLabel(str[offset]);
143 offset = 0;
144 targetLen = strlen(str);
145 } else {
146 /* account for leading 'L' and trailing ';' */
147 if (targetLen >= 2 && str[offset] == 'L' &&
148 str[offset+targetLen-1] == ';')
149 {
150 targetLen -= 2;
151 offset++;
152 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800153 }
154
Carl Shapirobfc97992011-04-27 14:16:08 -0700155 newStr = (char*)malloc(targetLen + arrayDepth * 2 +1);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800156
Andy McFaddena2ee53b2009-05-05 16:52:10 -0700157 /* copy class name over */
158 int i;
159 for (i = 0; i < targetLen; i++) {
160 char ch = str[offset + i];
161 newStr[i] = (ch == '/' || ch == '$') ? '.' : ch;
162 }
163
164 /* add the appropriate number of brackets for arrays */
165 while (arrayDepth-- > 0) {
166 newStr[i++] = '[';
167 newStr[i++] = ']';
168 }
169 newStr[i] = '\0';
170 assert(i == targetLen + arrayDepth * 2);
171
172 return newStr;
173}
174
175/*
176 * Converts the class name portion of a type descriptor to human-readable
177 * "dotted" form.
178 *
179 * Returns a newly-allocated string.
180 */
181static char* descriptorClassToDot(const char* str)
182{
183 const char* lastSlash;
184 char* newStr;
185 char* cp;
186
187 /* reduce to just the class name, trimming trailing ';' */
188 lastSlash = strrchr(str, '/');
189 if (lastSlash == NULL)
190 lastSlash = str + 1; /* start past 'L' */
191 else
192 lastSlash++; /* start past '/' */
193
194 newStr = strdup(lastSlash);
195 newStr[strlen(lastSlash)-1] = '\0';
196 for (cp = newStr; *cp != '\0'; cp++) {
197 if (*cp == '$')
198 *cp = '.';
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800199 }
200
201 return newStr;
202}
203
204/*
Andy McFaddena2ee53b2009-05-05 16:52:10 -0700205 * Returns a quoted string representing the boolean value.
206 */
207static const char* quotedBool(bool val)
208{
209 if (val)
210 return "\"true\"";
211 else
212 return "\"false\"";
213}
214
215static const char* quotedVisibility(u4 accessFlags)
216{
217 if ((accessFlags & ACC_PUBLIC) != 0)
218 return "\"public\"";
219 else if ((accessFlags & ACC_PROTECTED) != 0)
220 return "\"protected\"";
221 else if ((accessFlags & ACC_PRIVATE) != 0)
222 return "\"private\"";
223 else
224 return "\"package\"";
225}
226
227/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800228 * Count the number of '1' bits in a word.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800229 */
230static int countOnes(u4 val)
231{
232 int count = 0;
233
Cosmin Cojocare3393432010-04-18 18:25:06 +0200234 val = val - ((val >> 1) & 0x55555555);
235 val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
236 count = (((val + (val >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800237
238 return count;
239}
240
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800241/*
242 * Flag for use with createAccessFlagStr().
243 */
Carl Shapirod862faa2011-04-27 23:00:01 -0700244enum AccessFor {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800245 kAccessForClass = 0, kAccessForMethod = 1, kAccessForField = 2,
246 kAccessForMAX
Carl Shapirod862faa2011-04-27 23:00:01 -0700247};
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800248
249/*
250 * Create a new string with human-readable access flags.
251 *
252 * In the base language the access_flags fields are type u2; in Dalvik
253 * they're u4.
254 */
255static char* createAccessFlagStr(u4 flags, AccessFor forWhat)
256{
257#define NUM_FLAGS 18
258 static const char* kAccessStrings[kAccessForMAX][NUM_FLAGS] = {
Carl Shapirode750892010-06-08 16:37:12 -0700259 {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800260 /* class, inner class */
261 "PUBLIC", /* 0x0001 */
262 "PRIVATE", /* 0x0002 */
263 "PROTECTED", /* 0x0004 */
264 "STATIC", /* 0x0008 */
265 "FINAL", /* 0x0010 */
266 "?", /* 0x0020 */
267 "?", /* 0x0040 */
268 "?", /* 0x0080 */
269 "?", /* 0x0100 */
270 "INTERFACE", /* 0x0200 */
271 "ABSTRACT", /* 0x0400 */
272 "?", /* 0x0800 */
273 "SYNTHETIC", /* 0x1000 */
274 "ANNOTATION", /* 0x2000 */
275 "ENUM", /* 0x4000 */
276 "?", /* 0x8000 */
277 "VERIFIED", /* 0x10000 */
278 "OPTIMIZED", /* 0x20000 */
279 },
280 {
281 /* method */
282 "PUBLIC", /* 0x0001 */
283 "PRIVATE", /* 0x0002 */
284 "PROTECTED", /* 0x0004 */
285 "STATIC", /* 0x0008 */
286 "FINAL", /* 0x0010 */
287 "SYNCHRONIZED", /* 0x0020 */
288 "BRIDGE", /* 0x0040 */
289 "VARARGS", /* 0x0080 */
290 "NATIVE", /* 0x0100 */
291 "?", /* 0x0200 */
292 "ABSTRACT", /* 0x0400 */
293 "STRICT", /* 0x0800 */
294 "SYNTHETIC", /* 0x1000 */
295 "?", /* 0x2000 */
296 "?", /* 0x4000 */
297 "MIRANDA", /* 0x8000 */
298 "CONSTRUCTOR", /* 0x10000 */
299 "DECLARED_SYNCHRONIZED", /* 0x20000 */
300 },
301 {
302 /* field */
303 "PUBLIC", /* 0x0001 */
304 "PRIVATE", /* 0x0002 */
305 "PROTECTED", /* 0x0004 */
306 "STATIC", /* 0x0008 */
307 "FINAL", /* 0x0010 */
308 "?", /* 0x0020 */
309 "VOLATILE", /* 0x0040 */
310 "TRANSIENT", /* 0x0080 */
311 "?", /* 0x0100 */
312 "?", /* 0x0200 */
313 "?", /* 0x0400 */
314 "?", /* 0x0800 */
315 "SYNTHETIC", /* 0x1000 */
316 "?", /* 0x2000 */
317 "ENUM", /* 0x4000 */
318 "?", /* 0x8000 */
319 "?", /* 0x10000 */
320 "?", /* 0x20000 */
321 },
322 };
323 const int kLongest = 21; /* strlen of longest string above */
324 int i, count;
325 char* str;
326 char* cp;
327
328 /*
329 * Allocate enough storage to hold the expected number of strings,
330 * plus a space between each. We over-allocate, using the longest
331 * string above as the base metric.
332 */
333 count = countOnes(flags);
334 cp = str = (char*) malloc(count * (kLongest+1) +1);
335
336 for (i = 0; i < NUM_FLAGS; i++) {
337 if (flags & 0x01) {
338 const char* accessStr = kAccessStrings[forWhat][i];
339 int len = strlen(accessStr);
340 if (cp != str)
341 *cp++ = ' ';
342
343 memcpy(cp, accessStr, len);
344 cp += len;
345 }
346 flags >>= 1;
347 }
348 *cp = '\0';
349
350 return str;
351}
352
353
354/*
Andy McFadden0ea77b92010-04-20 14:18:59 -0700355 * Copy character data from "data" to "out", converting non-ASCII values
356 * to printf format chars or an ASCII filler ('.' or '?').
357 *
358 * The output buffer must be able to hold (2*len)+1 bytes. The result is
359 * NUL-terminated.
360 */
361static void asciify(char* out, const unsigned char* data, size_t len)
362{
363 while (len--) {
364 if (*data < 0x20) {
365 /* could do more here, but we don't need them yet */
366 switch (*data) {
367 case '\0':
368 *out++ = '\\';
369 *out++ = '0';
370 break;
371 case '\n':
372 *out++ = '\\';
373 *out++ = 'n';
374 break;
375 default:
376 *out++ = '.';
377 break;
378 }
379 } else if (*data >= 0x80) {
380 *out++ = '?';
381 } else {
382 *out++ = *data;
383 }
384 data++;
385 }
386 *out = '\0';
387}
388
389/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800390 * Dump the file header.
391 */
392void dumpFileHeader(const DexFile* pDexFile)
393{
Andy McFadden0ea77b92010-04-20 14:18:59 -0700394 const DexOptHeader* pOptHeader = pDexFile->pOptHeader;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800395 const DexHeader* pHeader = pDexFile->pHeader;
Andy McFadden0ea77b92010-04-20 14:18:59 -0700396 char sanitized[sizeof(pHeader->magic)*2 +1];
397
398 assert(sizeof(pHeader->magic) == sizeof(pOptHeader->magic));
399
400 if (pOptHeader != NULL) {
401 printf("Optimized DEX file header:\n");
402
403 asciify(sanitized, pOptHeader->magic, sizeof(pOptHeader->magic));
404 printf("magic : '%s'\n", sanitized);
405 printf("dex_offset : %d (0x%06x)\n",
406 pOptHeader->dexOffset, pOptHeader->dexOffset);
407 printf("dex_length : %d\n", pOptHeader->dexLength);
408 printf("deps_offset : %d (0x%06x)\n",
409 pOptHeader->depsOffset, pOptHeader->depsOffset);
410 printf("deps_length : %d\n", pOptHeader->depsLength);
Dan Bornsteine377ef62010-08-31 16:50:00 -0700411 printf("opt_offset : %d (0x%06x)\n",
412 pOptHeader->optOffset, pOptHeader->optOffset);
413 printf("opt_length : %d\n", pOptHeader->optLength);
Andy McFadden0ea77b92010-04-20 14:18:59 -0700414 printf("flags : %08x\n", pOptHeader->flags);
415 printf("checksum : %08x\n", pOptHeader->checksum);
416 printf("\n");
417 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800418
419 printf("DEX file header:\n");
Andy McFadden0ea77b92010-04-20 14:18:59 -0700420 asciify(sanitized, pHeader->magic, sizeof(pHeader->magic));
421 printf("magic : '%s'\n", sanitized);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800422 printf("checksum : %08x\n", pHeader->checksum);
423 printf("signature : %02x%02x...%02x%02x\n",
424 pHeader->signature[0], pHeader->signature[1],
425 pHeader->signature[kSHA1DigestLen-2],
426 pHeader->signature[kSHA1DigestLen-1]);
427 printf("file_size : %d\n", pHeader->fileSize);
428 printf("header_size : %d\n", pHeader->headerSize);
429 printf("link_size : %d\n", pHeader->linkSize);
430 printf("link_off : %d (0x%06x)\n",
431 pHeader->linkOff, pHeader->linkOff);
432 printf("string_ids_size : %d\n", pHeader->stringIdsSize);
433 printf("string_ids_off : %d (0x%06x)\n",
434 pHeader->stringIdsOff, pHeader->stringIdsOff);
435 printf("type_ids_size : %d\n", pHeader->typeIdsSize);
436 printf("type_ids_off : %d (0x%06x)\n",
437 pHeader->typeIdsOff, pHeader->typeIdsOff);
Carl Shapiroda4a0992011-08-03 19:38:17 -0700438 printf("proto_ids_size : %d\n", pHeader->protoIdsSize);
439 printf("proto_ids_off : %d (0x%06x)\n",
440 pHeader->protoIdsOff, pHeader->protoIdsOff);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800441 printf("field_ids_size : %d\n", pHeader->fieldIdsSize);
442 printf("field_ids_off : %d (0x%06x)\n",
443 pHeader->fieldIdsOff, pHeader->fieldIdsOff);
444 printf("method_ids_size : %d\n", pHeader->methodIdsSize);
445 printf("method_ids_off : %d (0x%06x)\n",
446 pHeader->methodIdsOff, pHeader->methodIdsOff);
447 printf("class_defs_size : %d\n", pHeader->classDefsSize);
448 printf("class_defs_off : %d (0x%06x)\n",
449 pHeader->classDefsOff, pHeader->classDefsOff);
450 printf("data_size : %d\n", pHeader->dataSize);
451 printf("data_off : %d (0x%06x)\n",
452 pHeader->dataOff, pHeader->dataOff);
453 printf("\n");
454}
455
456/*
Dan Bornsteine377ef62010-08-31 16:50:00 -0700457 * Dump the "table of contents" for the opt area.
Andy McFadden0ea77b92010-04-20 14:18:59 -0700458 */
Dan Bornsteine377ef62010-08-31 16:50:00 -0700459void dumpOptDirectory(const DexFile* pDexFile)
Andy McFadden0ea77b92010-04-20 14:18:59 -0700460{
461 const DexOptHeader* pOptHeader = pDexFile->pOptHeader;
462 if (pOptHeader == NULL)
463 return;
464
Dan Bornsteine377ef62010-08-31 16:50:00 -0700465 printf("OPT section contents:\n");
Andy McFadden0ea77b92010-04-20 14:18:59 -0700466
Dan Bornsteine377ef62010-08-31 16:50:00 -0700467 const u4* pOpt = (const u4*) ((u1*) pOptHeader + pOptHeader->optOffset);
Andy McFadden0ea77b92010-04-20 14:18:59 -0700468
Dan Bornsteine377ef62010-08-31 16:50:00 -0700469 if (*pOpt == 0) {
Andy McFadden0ea77b92010-04-20 14:18:59 -0700470 printf("(1.0 format, only class lookup table is present)\n\n");
471 return;
472 }
473
474 /*
Dan Bornsteine377ef62010-08-31 16:50:00 -0700475 * The "opt" section is in "chunk" format: a 32-bit identifier, a 32-bit
Andy McFadden0ea77b92010-04-20 14:18:59 -0700476 * length, then the data. Chunks start on 64-bit boundaries.
477 */
Dan Bornsteine377ef62010-08-31 16:50:00 -0700478 while (*pOpt != kDexChunkEnd) {
Andy McFadden0ea77b92010-04-20 14:18:59 -0700479 const char* verboseStr;
480
Dan Bornsteine377ef62010-08-31 16:50:00 -0700481 u4 size = *(pOpt+1);
Andy McFadden0ea77b92010-04-20 14:18:59 -0700482
Dan Bornsteine377ef62010-08-31 16:50:00 -0700483 switch (*pOpt) {
Andy McFadden0ea77b92010-04-20 14:18:59 -0700484 case kDexChunkClassLookup:
485 verboseStr = "class lookup hash table";
486 break;
487 case kDexChunkRegisterMaps:
488 verboseStr = "register maps";
489 break;
Andy McFadden0ea77b92010-04-20 14:18:59 -0700490 default:
491 verboseStr = "(unknown chunk type)";
492 break;
493 }
494
Dan Bornsteine377ef62010-08-31 16:50:00 -0700495 printf("Chunk %08x (%c%c%c%c) - %s (%d bytes)\n", *pOpt,
496 *pOpt >> 24, (char)(*pOpt >> 16), (char)(*pOpt >> 8), (char)*pOpt,
Andy McFadden0ea77b92010-04-20 14:18:59 -0700497 verboseStr, size);
498
499 size = (size + 8 + 7) & ~7;
Dan Bornsteine377ef62010-08-31 16:50:00 -0700500 pOpt += size / sizeof(u4);
Andy McFadden0ea77b92010-04-20 14:18:59 -0700501 }
502 printf("\n");
503}
504
505/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800506 * Dump a class_def_item.
507 */
508void dumpClassDef(DexFile* pDexFile, int idx)
509{
510 const DexClassDef* pClassDef;
511 const u1* pEncodedData;
512 DexClassData* pClassData;
513
514 pClassDef = dexGetClassDef(pDexFile, idx);
515 pEncodedData = dexGetClassData(pDexFile, pClassDef);
516 pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL);
517
518 if (pClassData == NULL) {
519 fprintf(stderr, "Trouble reading class data\n");
520 return;
521 }
522
523 printf("Class #%d header:\n", idx);
524 printf("class_idx : %d\n", pClassDef->classIdx);
525 printf("access_flags : %d (0x%04x)\n",
526 pClassDef->accessFlags, pClassDef->accessFlags);
527 printf("superclass_idx : %d\n", pClassDef->superclassIdx);
528 printf("interfaces_off : %d (0x%06x)\n",
529 pClassDef->interfacesOff, pClassDef->interfacesOff);
530 printf("source_file_idx : %d\n", pClassDef->sourceFileIdx);
531 printf("annotations_off : %d (0x%06x)\n",
532 pClassDef->annotationsOff, pClassDef->annotationsOff);
533 printf("class_data_off : %d (0x%06x)\n",
534 pClassDef->classDataOff, pClassDef->classDataOff);
535 printf("static_fields_size : %d\n", pClassData->header.staticFieldsSize);
536 printf("instance_fields_size: %d\n",
537 pClassData->header.instanceFieldsSize);
538 printf("direct_methods_size : %d\n", pClassData->header.directMethodsSize);
539 printf("virtual_methods_size: %d\n",
540 pClassData->header.virtualMethodsSize);
541 printf("\n");
542
543 free(pClassData);
544}
545
546/*
Andy McFaddena2ee53b2009-05-05 16:52:10 -0700547 * Dump an interface that a class declares to implement.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800548 */
549void dumpInterface(const DexFile* pDexFile, const DexTypeItem* pTypeItem,
550 int i)
551{
552 const char* interfaceName =
553 dexStringByTypeIdx(pDexFile, pTypeItem->typeIdx);
554
Andy McFaddena2ee53b2009-05-05 16:52:10 -0700555 if (gOptions.outputFormat == OUTPUT_PLAIN) {
556 printf(" #%d : '%s'\n", i, interfaceName);
557 } else {
558 char* dotted = descriptorToDot(interfaceName);
559 printf("<implements name=\"%s\">\n</implements>\n", dotted);
560 free(dotted);
561 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800562}
563
564/*
565 * Dump the catches table associated with the code.
566 */
567void dumpCatches(DexFile* pDexFile, const DexCode* pCode)
568{
569 u4 triesSize = pCode->triesSize;
570
571 if (triesSize == 0) {
572 printf(" catches : (none)\n");
573 return;
Carl Shapirode750892010-06-08 16:37:12 -0700574 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800575
576 printf(" catches : %d\n", triesSize);
577
578 const DexTry* pTries = dexGetTries(pCode);
579 u4 i;
580
581 for (i = 0; i < triesSize; i++) {
582 const DexTry* pTry = &pTries[i];
583 u4 start = pTry->startAddr;
584 u4 end = start + pTry->insnCount;
585 DexCatchIterator iterator;
Carl Shapirode750892010-06-08 16:37:12 -0700586
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800587 printf(" 0x%04x - 0x%04x\n", start, end);
588
589 dexCatchIteratorInit(&iterator, pCode, pTry->handlerOff);
590
591 for (;;) {
592 DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
593 const char* descriptor;
Carl Shapirode750892010-06-08 16:37:12 -0700594
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800595 if (handler == NULL) {
596 break;
597 }
Carl Shapirode750892010-06-08 16:37:12 -0700598
599 descriptor = (handler->typeIdx == kDexNoIndex) ? "<any>" :
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800600 dexStringByTypeIdx(pDexFile, handler->typeIdx);
Carl Shapirode750892010-06-08 16:37:12 -0700601
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800602 printf(" %s -> 0x%04x\n", descriptor,
603 handler->address);
604 }
605 }
606}
607
608static int dumpPositionsCb(void *cnxt, u4 address, u4 lineNum)
609{
610 printf(" 0x%04x line=%d\n", address, lineNum);
611 return 0;
612}
613
614/*
615 * Dump the positions list.
616 */
Carl Shapirode750892010-06-08 16:37:12 -0700617void dumpPositions(DexFile* pDexFile, const DexCode* pCode,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800618 const DexMethod *pDexMethod)
619{
620 printf(" positions : \n");
Carl Shapirode750892010-06-08 16:37:12 -0700621 const DexMethodId *pMethodId
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800622 = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
623 const char *classDescriptor
624 = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
625
626 dexDecodeDebugInfo(pDexFile, pCode, classDescriptor, pMethodId->protoIdx,
627 pDexMethod->accessFlags, dumpPositionsCb, NULL, NULL);
628}
629
630static void dumpLocalsCb(void *cnxt, u2 reg, u4 startAddress,
631 u4 endAddress, const char *name, const char *descriptor,
632 const char *signature)
633{
634 printf(" 0x%04x - 0x%04x reg=%d %s %s %s\n",
Carl Shapirode750892010-06-08 16:37:12 -0700635 startAddress, endAddress, reg, name, descriptor,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800636 signature);
637}
638
639/*
640 * Dump the locals list.
641 */
642void dumpLocals(DexFile* pDexFile, const DexCode* pCode,
643 const DexMethod *pDexMethod)
644{
645 printf(" locals : \n");
646
Carl Shapirode750892010-06-08 16:37:12 -0700647 const DexMethodId *pMethodId
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800648 = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
Carl Shapirode750892010-06-08 16:37:12 -0700649 const char *classDescriptor
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800650 = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
651
652 dexDecodeDebugInfo(pDexFile, pCode, classDescriptor, pMethodId->protoIdx,
653 pDexMethod->accessFlags, NULL, dumpLocalsCb, NULL);
654}
655
656/*
657 * Get information about a method.
658 */
659bool getMethodInfo(DexFile* pDexFile, u4 methodIdx, FieldMethodInfo* pMethInfo)
660{
661 const DexMethodId* pMethodId;
662
663 if (methodIdx >= pDexFile->pHeader->methodIdsSize)
664 return false;
665
666 pMethodId = dexGetMethodId(pDexFile, methodIdx);
667 pMethInfo->name = dexStringById(pDexFile, pMethodId->nameIdx);
668 pMethInfo->signature = dexCopyDescriptorFromMethodId(pDexFile, pMethodId);
669
Carl Shapirode750892010-06-08 16:37:12 -0700670 pMethInfo->classDescriptor =
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800671 dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
672 return true;
673}
674
675/*
676 * Get information about a field.
677 */
678bool getFieldInfo(DexFile* pDexFile, u4 fieldIdx, FieldMethodInfo* pFieldInfo)
679{
680 const DexFieldId* pFieldId;
681
682 if (fieldIdx >= pDexFile->pHeader->fieldIdsSize)
683 return false;
684
685 pFieldId = dexGetFieldId(pDexFile, fieldIdx);
686 pFieldInfo->name = dexStringById(pDexFile, pFieldId->nameIdx);
687 pFieldInfo->signature = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx);
688 pFieldInfo->classDescriptor =
689 dexStringByTypeIdx(pDexFile, pFieldId->classIdx);
690 return true;
691}
692
693
694/*
695 * Look up a class' descriptor.
696 */
697const char* getClassDescriptor(DexFile* pDexFile, u4 classIdx)
698{
699 return dexStringByTypeIdx(pDexFile, classIdx);
700}
701
702/*
Dan Bornstein4a6b4822010-11-11 12:26:58 -0800703 * Helper for dumpInstruction(), which builds the string
704 * representation for the index in the given instruction. This will
705 * first try to use the given buffer, but if the result won't fit,
706 * then this will allocate a new buffer to hold the result. A pointer
707 * to the buffer which holds the full result is always returned, and
708 * this can be compared with the one passed in, to see if the result
709 * needs to be free()d.
710 */
711static char* indexString(DexFile* pDexFile,
712 const DecodedInstruction* pDecInsn, char* buf, size_t bufSize)
713{
714 int outSize;
715 u4 index;
716 u4 width;
717
718 /* TODO: Make the index *always* be in field B, to simplify this code. */
Dan Bornsteine4852762010-12-02 12:45:00 -0800719 switch (dexGetFormatFromOpcode(pDecInsn->opcode)) {
Dan Bornstein4a6b4822010-11-11 12:26:58 -0800720 case kFmt20bc:
721 case kFmt21c:
722 case kFmt35c:
723 case kFmt35ms:
724 case kFmt3rc:
725 case kFmt3rms:
726 case kFmt35mi:
727 case kFmt3rmi:
728 index = pDecInsn->vB;
729 width = 4;
730 break;
731 case kFmt31c:
Dan Bornstein4a6b4822010-11-11 12:26:58 -0800732 index = pDecInsn->vB;
733 width = 8;
734 break;
735 case kFmt22c:
736 case kFmt22cs:
737 index = pDecInsn->vC;
738 width = 4;
739 break;
Dan Bornstein4a6b4822010-11-11 12:26:58 -0800740 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:
Elliott Hughes35ecedd2012-08-06 09:51:21 -0700770 if (index < pDexFile->pHeader->typeIdsSize) {
771 outSize = snprintf(buf, bufSize, "%s // type@%0*x",
772 getClassDescriptor(pDexFile, index), width, index);
773 } else {
774 outSize = snprintf(buf, bufSize, "<type?> // type@%0*x", width, index);
775 }
Dan Bornstein4a6b4822010-11-11 12:26:58 -0800776 break;
777 case kIndexStringRef:
Elliott Hughes35ecedd2012-08-06 09:51:21 -0700778 if (index < pDexFile->pHeader->stringIdsSize) {
779 outSize = snprintf(buf, bufSize, "\"%s\" // string@%0*x",
780 dexStringById(pDexFile, index), width, index);
781 } else {
782 outSize = snprintf(buf, bufSize, "<string?> // string@%0*x",
783 width, index);
784 }
Dan Bornstein4a6b4822010-11-11 12:26:58 -0800785 break;
786 case kIndexMethodRef:
787 {
788 FieldMethodInfo methInfo;
789 if (getMethodInfo(pDexFile, index, &methInfo)) {
790 outSize = snprintf(buf, bufSize, "%s.%s:%s // method@%0*x",
791 methInfo.classDescriptor, methInfo.name,
792 methInfo.signature, width, index);
You Kimf1aa8712012-12-25 23:51:01 +0900793 free((void *) methInfo.signature);
Dan Bornstein4a6b4822010-11-11 12:26:58 -0800794 } else {
795 outSize = snprintf(buf, bufSize, "<method?> // method@%0*x",
796 width, index);
797 }
798 }
799 break;
800 case kIndexFieldRef:
801 {
802 FieldMethodInfo fieldInfo;
803 if (getFieldInfo(pDexFile, index, &fieldInfo)) {
804 outSize = snprintf(buf, bufSize, "%s.%s:%s // field@%0*x",
805 fieldInfo.classDescriptor, fieldInfo.name,
806 fieldInfo.signature, width, index);
807 } else {
808 outSize = snprintf(buf, bufSize, "<field?> // field@%0*x",
809 width, index);
810 }
811 }
812 break;
813 case kIndexInlineMethod:
814 outSize = snprintf(buf, bufSize, "[%0*x] // inline #%0*x",
815 width, index, width, index);
816 break;
817 case kIndexVtableOffset:
818 outSize = snprintf(buf, bufSize, "[%0*x] // vtable #%0*x",
819 width, index, width, index);
820 break;
821 case kIndexFieldOffset:
822 outSize = snprintf(buf, bufSize, "[obj+%0*x]", width, index);
823 break;
824 default:
825 outSize = snprintf(buf, bufSize, "<?>");
826 break;
827 }
828
829 if (outSize >= (int) bufSize) {
830 /*
831 * The buffer wasn't big enough; allocate and retry. Note:
832 * snprintf() doesn't count the '\0' as part of its returned
833 * size, so we add explicit space for it here.
834 */
835 outSize++;
Carl Shapirobfc97992011-04-27 14:16:08 -0700836 buf = (char*)malloc(outSize);
Dan Bornstein4a6b4822010-11-11 12:26:58 -0800837 if (buf == NULL) {
838 return NULL;
839 }
840 return indexString(pDexFile, pDecInsn, buf, outSize);
841 } else {
842 return buf;
843 }
844}
845
846/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800847 * Dump a single instruction.
848 */
849void dumpInstruction(DexFile* pDexFile, const DexCode* pCode, int insnIdx,
850 int insnWidth, const DecodedInstruction* pDecInsn)
851{
Dan Bornstein4a6b4822010-11-11 12:26:58 -0800852 char indexBufChars[200];
853 char *indexBuf = indexBufChars;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800854 const u2* insns = pCode->insns;
855 int i;
856
857 printf("%06x:", ((u1*)insns - pDexFile->baseAddr) + insnIdx*2);
858 for (i = 0; i < 8; i++) {
859 if (i < insnWidth) {
860 if (i == 7) {
861 printf(" ... ");
862 } else {
863 /* print 16-bit value in little-endian order */
864 const u1* bytePtr = (const u1*) &insns[insnIdx+i];
865 printf(" %02x%02x", bytePtr[0], bytePtr[1]);
866 }
867 } else {
868 fputs(" ", stdout);
869 }
870 }
871
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800872 if (pDecInsn->opcode == OP_NOP) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800873 u2 instr = get2LE((const u1*) &insns[insnIdx]);
874 if (instr == kPackedSwitchSignature) {
875 printf("|%04x: packed-switch-data (%d units)",
876 insnIdx, insnWidth);
877 } else if (instr == kSparseSwitchSignature) {
878 printf("|%04x: sparse-switch-data (%d units)",
879 insnIdx, insnWidth);
880 } else if (instr == kArrayDataSignature) {
881 printf("|%04x: array-data (%d units)",
882 insnIdx, insnWidth);
883 } else {
884 printf("|%04x: nop // spacer", insnIdx);
885 }
886 } else {
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800887 printf("|%04x: %s", insnIdx, dexGetOpcodeName(pDecInsn->opcode));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800888 }
889
Dan Bornstein4a6b4822010-11-11 12:26:58 -0800890 if (pDecInsn->indexType != kIndexNone) {
891 indexBuf = indexString(pDexFile, pDecInsn,
892 indexBufChars, sizeof(indexBufChars));
893 }
894
Dan Bornsteine4852762010-12-02 12:45:00 -0800895 switch (dexGetFormatFromOpcode(pDecInsn->opcode)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800896 case kFmt10x: // op
897 break;
898 case kFmt12x: // op vA, vB
899 printf(" v%d, v%d", pDecInsn->vA, pDecInsn->vB);
900 break;
901 case kFmt11n: // op vA, #+B
902 printf(" v%d, #int %d // #%x",
903 pDecInsn->vA, (s4)pDecInsn->vB, (u1)pDecInsn->vB);
904 break;
905 case kFmt11x: // op vAA
906 printf(" v%d", pDecInsn->vA);
907 break;
908 case kFmt10t: // op +AA
909 case kFmt20t: // op +AAAA
910 {
911 s4 targ = (s4) pDecInsn->vA;
912 printf(" %04x // %c%04x",
913 insnIdx + targ,
914 (targ < 0) ? '-' : '+',
915 (targ < 0) ? -targ : targ);
916 }
917 break;
918 case kFmt22x: // op vAA, vBBBB
919 printf(" v%d, v%d", pDecInsn->vA, pDecInsn->vB);
920 break;
921 case kFmt21t: // op vAA, +BBBB
922 {
923 s4 targ = (s4) pDecInsn->vB;
924 printf(" v%d, %04x // %c%04x", pDecInsn->vA,
925 insnIdx + targ,
926 (targ < 0) ? '-' : '+',
927 (targ < 0) ? -targ : targ);
928 }
929 break;
930 case kFmt21s: // op vAA, #+BBBB
931 printf(" v%d, #int %d // #%x",
932 pDecInsn->vA, (s4)pDecInsn->vB, (u2)pDecInsn->vB);
933 break;
934 case kFmt21h: // op vAA, #+BBBB0000[00000000]
935 // The printed format varies a bit based on the actual opcode.
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800936 if (pDecInsn->opcode == OP_CONST_HIGH16) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800937 s4 value = pDecInsn->vB << 16;
938 printf(" v%d, #int %d // #%x",
939 pDecInsn->vA, value, (u2)pDecInsn->vB);
940 } else {
941 s8 value = ((s8) pDecInsn->vB) << 48;
942 printf(" v%d, #long %lld // #%x",
943 pDecInsn->vA, value, (u2)pDecInsn->vB);
944 }
945 break;
946 case kFmt21c: // op vAA, thing@BBBB
Dan Bornstein4a6b4822010-11-11 12:26:58 -0800947 case kFmt31c: // op vAA, thing@BBBBBBBB
Dan Bornstein4a6b4822010-11-11 12:26:58 -0800948 printf(" v%d, %s", pDecInsn->vA, indexBuf);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800949 break;
950 case kFmt23x: // op vAA, vBB, vCC
951 printf(" v%d, v%d, v%d", pDecInsn->vA, pDecInsn->vB, pDecInsn->vC);
952 break;
953 case kFmt22b: // op vAA, vBB, #+CC
954 printf(" v%d, v%d, #int %d // #%02x",
955 pDecInsn->vA, pDecInsn->vB, (s4)pDecInsn->vC, (u1)pDecInsn->vC);
956 break;
957 case kFmt22t: // op vA, vB, +CCCC
958 {
959 s4 targ = (s4) pDecInsn->vC;
960 printf(" v%d, v%d, %04x // %c%04x", pDecInsn->vA, pDecInsn->vB,
961 insnIdx + targ,
962 (targ < 0) ? '-' : '+',
963 (targ < 0) ? -targ : targ);
964 }
965 break;
966 case kFmt22s: // op vA, vB, #+CCCC
967 printf(" v%d, v%d, #int %d // #%04x",
968 pDecInsn->vA, pDecInsn->vB, (s4)pDecInsn->vC, (u2)pDecInsn->vC);
969 break;
970 case kFmt22c: // op vA, vB, thing@CCCC
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800971 case kFmt22cs: // [opt] op vA, vB, field offset CCCC
Dan Bornstein4a6b4822010-11-11 12:26:58 -0800972 printf(" v%d, v%d, %s", pDecInsn->vA, pDecInsn->vB, indexBuf);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800973 break;
974 case kFmt30t:
975 printf(" #%08x", pDecInsn->vA);
976 break;
977 case kFmt31i: // op vAA, #+BBBBBBBB
978 {
979 /* this is often, but not always, a float */
980 union {
981 float f;
982 u4 i;
983 } conv;
984 conv.i = pDecInsn->vB;
985 printf(" v%d, #float %f // #%08x",
986 pDecInsn->vA, conv.f, pDecInsn->vB);
987 }
988 break;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800989 case kFmt31t: // op vAA, offset +BBBBBBBB
990 printf(" v%d, %08x // +%08x",
991 pDecInsn->vA, insnIdx + pDecInsn->vB, pDecInsn->vB);
992 break;
993 case kFmt32x: // op vAAAA, vBBBB
994 printf(" v%d, v%d", pDecInsn->vA, pDecInsn->vB);
995 break;
Dan Bornstein7b3e9b02010-11-09 17:15:10 -0800996 case kFmt35c: // op {vC, vD, vE, vF, vG}, thing@BBBB
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800997 case kFmt35ms: // [opt] invoke-virtual+super
Dan Bornstein7b3e9b02010-11-09 17:15:10 -0800998 case kFmt35mi: // [opt] inline invoke
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800999 {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001000 fputs(" {", stdout);
1001 for (i = 0; i < (int) pDecInsn->vA; i++) {
1002 if (i == 0)
1003 printf("v%d", pDecInsn->arg[i]);
1004 else
1005 printf(", v%d", pDecInsn->arg[i]);
1006 }
Dan Bornstein4a6b4822010-11-11 12:26:58 -08001007 printf("}, %s", indexBuf);
1008 }
1009 break;
1010 case kFmt3rc: // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB
1011 case kFmt3rms: // [opt] invoke-virtual+super/range
1012 case kFmt3rmi: // [opt] execute-inline/range
Dan Bornstein4a6b4822010-11-11 12:26:58 -08001013 {
1014 /*
1015 * This doesn't match the "dx" output when some of the args are
1016 * 64-bit values -- dx only shows the first register.
1017 */
1018 fputs(" {", stdout);
1019 for (i = 0; i < (int) pDecInsn->vA; i++) {
1020 if (i == 0)
1021 printf("v%d", pDecInsn->vC + i);
1022 else
1023 printf(", v%d", pDecInsn->vC + i);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001024 }
Dan Bornstein4a6b4822010-11-11 12:26:58 -08001025 printf("}, %s", indexBuf);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001026 }
1027 break;
1028 case kFmt51l: // op vAA, #+BBBBBBBBBBBBBBBB
1029 {
1030 /* this is often, but not always, a double */
1031 union {
1032 double d;
1033 u8 j;
1034 } conv;
1035 conv.j = pDecInsn->vB_wide;
1036 printf(" v%d, #double %f // #%016llx",
1037 pDecInsn->vA, conv.d, pDecInsn->vB_wide);
1038 }
1039 break;
Dan Bornstein84244322010-11-17 12:05:04 -08001040 case kFmt00x: // unknown op or breakpoint
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001041 break;
1042 default:
1043 printf(" ???");
1044 break;
1045 }
1046
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001047 putchar('\n');
1048
Dan Bornstein4a6b4822010-11-11 12:26:58 -08001049 if (indexBuf != indexBufChars) {
1050 free(indexBuf);
1051 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001052}
1053
1054/*
1055 * Dump a bytecode disassembly.
1056 */
1057void dumpBytecodes(DexFile* pDexFile, const DexMethod* pDexMethod)
1058{
1059 const DexCode* pCode = dexGetCode(pDexFile, pDexMethod);
1060 const u2* insns;
1061 int insnIdx;
1062 FieldMethodInfo methInfo;
1063 int startAddr;
1064 char* className = NULL;
1065
1066 assert(pCode->insnsSize > 0);
1067 insns = pCode->insns;
1068
1069 getMethodInfo(pDexFile, pDexMethod->methodIdx, &methInfo);
1070 startAddr = ((u1*)pCode - pDexFile->baseAddr);
1071 className = descriptorToDot(methInfo.classDescriptor);
1072
1073 printf("%06x: |[%06x] %s.%s:%s\n",
1074 startAddr, startAddr,
1075 className, methInfo.name, methInfo.signature);
You Kimf1aa8712012-12-25 23:51:01 +09001076 free((void *) methInfo.signature);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001077
1078 insnIdx = 0;
1079 while (insnIdx < (int) pCode->insnsSize) {
1080 int insnWidth;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001081 DecodedInstruction decInsn;
1082 u2 instr;
1083
Dan Bornstein11122162010-12-01 12:30:21 -08001084 /*
1085 * Note: This code parallels the function
Dan Bornsteine4852762010-12-02 12:45:00 -08001086 * dexGetWidthFromInstruction() in InstrUtils.c, but this version
Dan Bornstein11122162010-12-01 12:30:21 -08001087 * can deal with data in either endianness.
1088 *
1089 * TODO: Figure out if this really matters, and possibly change
Dan Bornsteine4852762010-12-02 12:45:00 -08001090 * this to just use dexGetWidthFromInstruction().
Dan Bornstein11122162010-12-01 12:30:21 -08001091 */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001092 instr = get2LE((const u1*)insns);
1093 if (instr == kPackedSwitchSignature) {
1094 insnWidth = 4 + get2LE((const u1*)(insns+1)) * 2;
1095 } else if (instr == kSparseSwitchSignature) {
1096 insnWidth = 2 + get2LE((const u1*)(insns+1)) * 4;
1097 } else if (instr == kArrayDataSignature) {
1098 int width = get2LE((const u1*)(insns+1));
Carl Shapirode750892010-06-08 16:37:12 -07001099 int size = get2LE((const u1*)(insns+2)) |
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001100 (get2LE((const u1*)(insns+3))<<16);
Dan Bornstein11122162010-12-01 12:30:21 -08001101 // The plus 1 is to round up for odd size and width.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001102 insnWidth = 4 + ((size * width) + 1) / 2;
1103 } else {
Dan Bornstein9a1f8162010-12-01 17:02:26 -08001104 Opcode opcode = dexOpcodeFromCodeUnit(instr);
Dan Bornsteine4852762010-12-02 12:45:00 -08001105 insnWidth = dexGetWidthFromOpcode(opcode);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001106 if (insnWidth == 0) {
1107 fprintf(stderr,
1108 "GLITCH: zero-width instruction at idx=0x%04x\n", insnIdx);
1109 break;
1110 }
1111 }
1112
Dan Bornstein54322392010-11-17 14:16:56 -08001113 dexDecodeInstruction(insns, &decInsn);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001114 dumpInstruction(pDexFile, pCode, insnIdx, insnWidth, &decInsn);
1115
1116 insns += insnWidth;
1117 insnIdx += insnWidth;
1118 }
1119
1120 free(className);
1121}
1122
1123/*
1124 * Dump a "code" struct.
1125 */
1126void dumpCode(DexFile* pDexFile, const DexMethod* pDexMethod)
1127{
1128 const DexCode* pCode = dexGetCode(pDexFile, pDexMethod);
1129
1130 printf(" registers : %d\n", pCode->registersSize);
1131 printf(" ins : %d\n", pCode->insSize);
1132 printf(" outs : %d\n", pCode->outsSize);
1133 printf(" insns size : %d 16-bit code units\n", pCode->insnsSize);
1134
1135 if (gOptions.disassemble)
1136 dumpBytecodes(pDexFile, pDexMethod);
1137
1138 dumpCatches(pDexFile, pCode);
1139 /* both of these are encoded in debug info */
1140 dumpPositions(pDexFile, pCode, pDexMethod);
1141 dumpLocals(pDexFile, pCode, pDexMethod);
1142}
1143
1144/*
1145 * Dump a method.
1146 */
1147void dumpMethod(DexFile* pDexFile, const DexMethod* pDexMethod, int i)
1148{
1149 const DexMethodId* pMethodId;
1150 const char* backDescriptor;
1151 const char* name;
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001152 char* typeDescriptor = NULL;
1153 char* accessStr = NULL;
1154
1155 if (gOptions.exportsOnly &&
1156 (pDexMethod->accessFlags & (ACC_PUBLIC | ACC_PROTECTED)) == 0)
1157 {
1158 return;
1159 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001160
1161 pMethodId = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
1162 name = dexStringById(pDexFile, pMethodId->nameIdx);
1163 typeDescriptor = dexCopyDescriptorFromMethodId(pDexFile, pMethodId);
1164
1165 backDescriptor = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
1166
1167 accessStr = createAccessFlagStr(pDexMethod->accessFlags,
1168 kAccessForMethod);
1169
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001170 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1171 printf(" #%d : (in %s)\n", i, backDescriptor);
1172 printf(" name : '%s'\n", name);
1173 printf(" type : '%s'\n", typeDescriptor);
1174 printf(" access : 0x%04x (%s)\n",
1175 pDexMethod->accessFlags, accessStr);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001176
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001177 if (pDexMethod->codeOff == 0) {
1178 printf(" code : (none)\n");
1179 } else {
1180 printf(" code -\n");
1181 dumpCode(pDexFile, pDexMethod);
1182 }
1183
1184 if (gOptions.disassemble)
1185 putchar('\n');
1186 } else if (gOptions.outputFormat == OUTPUT_XML) {
1187 bool constructor = (name[0] == '<');
1188
1189 if (constructor) {
1190 char* tmp;
1191
1192 tmp = descriptorClassToDot(backDescriptor);
1193 printf("<constructor name=\"%s\"\n", tmp);
1194 free(tmp);
1195
1196 tmp = descriptorToDot(backDescriptor);
1197 printf(" type=\"%s\"\n", tmp);
1198 free(tmp);
1199 } else {
1200 printf("<method name=\"%s\"\n", name);
1201
1202 const char* returnType = strrchr(typeDescriptor, ')');
1203 if (returnType == NULL) {
1204 fprintf(stderr, "bad method type descriptor '%s'\n",
1205 typeDescriptor);
1206 goto bail;
1207 }
1208
1209 char* tmp = descriptorToDot(returnType+1);
1210 printf(" return=\"%s\"\n", tmp);
1211 free(tmp);
1212
1213 printf(" abstract=%s\n",
1214 quotedBool((pDexMethod->accessFlags & ACC_ABSTRACT) != 0));
1215 printf(" native=%s\n",
1216 quotedBool((pDexMethod->accessFlags & ACC_NATIVE) != 0));
1217
1218 bool isSync =
1219 (pDexMethod->accessFlags & ACC_SYNCHRONIZED) != 0 ||
1220 (pDexMethod->accessFlags & ACC_DECLARED_SYNCHRONIZED) != 0;
1221 printf(" synchronized=%s\n", quotedBool(isSync));
1222 }
1223
1224 printf(" static=%s\n",
1225 quotedBool((pDexMethod->accessFlags & ACC_STATIC) != 0));
1226 printf(" final=%s\n",
1227 quotedBool((pDexMethod->accessFlags & ACC_FINAL) != 0));
1228 // "deprecated=" not knowable w/o parsing annotations
1229 printf(" visibility=%s\n",
1230 quotedVisibility(pDexMethod->accessFlags));
1231
1232 printf(">\n");
1233
1234 /*
1235 * Parameters.
1236 */
1237 if (typeDescriptor[0] != '(') {
1238 fprintf(stderr, "ERROR: bad descriptor '%s'\n", typeDescriptor);
1239 goto bail;
1240 }
1241
1242 char tmpBuf[strlen(typeDescriptor)+1]; /* more than big enough */
1243 int argNum = 0;
1244
1245 const char* base = typeDescriptor+1;
1246
1247 while (*base != ')') {
1248 char* cp = tmpBuf;
1249
1250 while (*base == '[')
1251 *cp++ = *base++;
1252
1253 if (*base == 'L') {
1254 /* copy through ';' */
1255 do {
1256 *cp = *base++;
1257 } while (*cp++ != ';');
1258 } else {
1259 /* primitive char, copy it */
1260 if (strchr("ZBCSIFJD", *base) == NULL) {
1261 fprintf(stderr, "ERROR: bad method signature '%s'\n", base);
1262 goto bail;
1263 }
1264 *cp++ = *base++;
1265 }
1266
1267 /* null terminate and display */
1268 *cp++ = '\0';
1269
1270 char* tmp = descriptorToDot(tmpBuf);
1271 printf("<parameter name=\"arg%d\" type=\"%s\">\n</parameter>\n",
1272 argNum++, tmp);
1273 free(tmp);
1274 }
1275
1276 if (constructor)
1277 printf("</constructor>\n");
1278 else
1279 printf("</method>\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001280 }
1281
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001282bail:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001283 free(typeDescriptor);
1284 free(accessStr);
1285}
1286
1287/*
1288 * Dump a static (class) field.
1289 */
1290void dumpSField(const DexFile* pDexFile, const DexField* pSField, int i)
1291{
1292 const DexFieldId* pFieldId;
1293 const char* backDescriptor;
1294 const char* name;
1295 const char* typeDescriptor;
1296 char* accessStr;
1297
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001298 if (gOptions.exportsOnly &&
1299 (pSField->accessFlags & (ACC_PUBLIC | ACC_PROTECTED)) == 0)
1300 {
1301 return;
1302 }
1303
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001304 pFieldId = dexGetFieldId(pDexFile, pSField->fieldIdx);
1305 name = dexStringById(pDexFile, pFieldId->nameIdx);
1306 typeDescriptor = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx);
1307 backDescriptor = dexStringByTypeIdx(pDexFile, pFieldId->classIdx);
1308
1309 accessStr = createAccessFlagStr(pSField->accessFlags, kAccessForField);
1310
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001311 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1312 printf(" #%d : (in %s)\n", i, backDescriptor);
1313 printf(" name : '%s'\n", name);
1314 printf(" type : '%s'\n", typeDescriptor);
1315 printf(" access : 0x%04x (%s)\n",
1316 pSField->accessFlags, accessStr);
1317 } else if (gOptions.outputFormat == OUTPUT_XML) {
1318 char* tmp;
1319
1320 printf("<field name=\"%s\"\n", name);
1321
1322 tmp = descriptorToDot(typeDescriptor);
1323 printf(" type=\"%s\"\n", tmp);
1324 free(tmp);
1325
1326 printf(" transient=%s\n",
1327 quotedBool((pSField->accessFlags & ACC_TRANSIENT) != 0));
1328 printf(" volatile=%s\n",
1329 quotedBool((pSField->accessFlags & ACC_VOLATILE) != 0));
1330 // "value=" not knowable w/o parsing annotations
1331 printf(" static=%s\n",
1332 quotedBool((pSField->accessFlags & ACC_STATIC) != 0));
1333 printf(" final=%s\n",
1334 quotedBool((pSField->accessFlags & ACC_FINAL) != 0));
1335 // "deprecated=" not knowable w/o parsing annotations
1336 printf(" visibility=%s\n",
1337 quotedVisibility(pSField->accessFlags));
1338 printf(">\n</field>\n");
1339 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001340
1341 free(accessStr);
1342}
1343
1344/*
1345 * Dump an instance field.
1346 */
1347void dumpIField(const DexFile* pDexFile, const DexField* pIField, int i)
1348{
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001349 dumpSField(pDexFile, pIField, i);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001350}
1351
1352/*
1353 * Dump the class.
The Android Open Source Project99409882009-03-18 22:20:24 -07001354 *
1355 * Note "idx" is a DexClassDef index, not a DexTypeId index.
Andy McFaddend18aff32009-05-06 10:19:16 -07001356 *
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001357 * If "*pLastPackage" is NULL or does not match the current class' package,
1358 * the value will be replaced with a newly-allocated string.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001359 */
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001360void dumpClass(DexFile* pDexFile, int idx, char** pLastPackage)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001361{
1362 const DexTypeList* pInterfaces;
1363 const DexClassDef* pClassDef;
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001364 DexClassData* pClassData = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001365 const u1* pEncodedData;
1366 const char* fileName;
1367 const char* classDescriptor;
1368 const char* superclassDescriptor;
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001369 char* accessStr = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001370 int i;
1371
1372 pClassDef = dexGetClassDef(pDexFile, idx);
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001373
1374 if (gOptions.exportsOnly && (pClassDef->accessFlags & ACC_PUBLIC) == 0) {
1375 //printf("<!-- omitting non-public class %s -->\n",
1376 // classDescriptor);
1377 goto bail;
1378 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001379
1380 pEncodedData = dexGetClassData(pDexFile, pClassDef);
1381 pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL);
1382
1383 if (pClassData == NULL) {
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001384 printf("Trouble reading class data (#%d)\n", idx);
1385 goto bail;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001386 }
Carl Shapirode750892010-06-08 16:37:12 -07001387
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001388 classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001389
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001390 /*
1391 * For the XML output, show the package name. Ideally we'd gather
1392 * up the classes, sort them, and dump them alphabetically so the
1393 * package name wouldn't jump around, but that's not a great plan
1394 * for something that needs to run on the device.
1395 */
1396 if (!(classDescriptor[0] == 'L' &&
1397 classDescriptor[strlen(classDescriptor)-1] == ';'))
1398 {
1399 /* arrays and primitives should not be defined explicitly */
1400 fprintf(stderr, "Malformed class name '%s'\n", classDescriptor);
1401 /* keep going? */
1402 } else if (gOptions.outputFormat == OUTPUT_XML) {
1403 char* mangle;
1404 char* lastSlash;
1405 char* cp;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001406
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001407 mangle = strdup(classDescriptor + 1);
1408 mangle[strlen(mangle)-1] = '\0';
1409
1410 /* reduce to just the package name */
1411 lastSlash = strrchr(mangle, '/');
1412 if (lastSlash != NULL) {
1413 *lastSlash = '\0';
1414 } else {
1415 *mangle = '\0';
1416 }
1417
1418 for (cp = mangle; *cp != '\0'; cp++) {
1419 if (*cp == '/')
1420 *cp = '.';
1421 }
1422
1423 if (*pLastPackage == NULL || strcmp(mangle, *pLastPackage) != 0) {
1424 /* start of a new package */
1425 if (*pLastPackage != NULL)
1426 printf("</package>\n");
1427 printf("<package name=\"%s\"\n>\n", mangle);
1428 free(*pLastPackage);
1429 *pLastPackage = mangle;
1430 } else {
1431 free(mangle);
1432 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001433 }
1434
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001435 accessStr = createAccessFlagStr(pClassDef->accessFlags, kAccessForClass);
1436
1437 if (pClassDef->superclassIdx == kDexNoIndex) {
1438 superclassDescriptor = NULL;
1439 } else {
1440 superclassDescriptor =
1441 dexStringByTypeIdx(pDexFile, pClassDef->superclassIdx);
1442 }
1443
1444 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1445 printf("Class #%d -\n", idx);
1446 printf(" Class descriptor : '%s'\n", classDescriptor);
1447 printf(" Access flags : 0x%04x (%s)\n",
1448 pClassDef->accessFlags, accessStr);
1449
1450 if (superclassDescriptor != NULL)
1451 printf(" Superclass : '%s'\n", superclassDescriptor);
1452
1453 printf(" Interfaces -\n");
1454 } else {
1455 char* tmp;
1456
1457 tmp = descriptorClassToDot(classDescriptor);
1458 printf("<class name=\"%s\"\n", tmp);
1459 free(tmp);
1460
1461 if (superclassDescriptor != NULL) {
1462 tmp = descriptorToDot(superclassDescriptor);
1463 printf(" extends=\"%s\"\n", tmp);
1464 free(tmp);
1465 }
1466 printf(" abstract=%s\n",
1467 quotedBool((pClassDef->accessFlags & ACC_ABSTRACT) != 0));
1468 printf(" static=%s\n",
1469 quotedBool((pClassDef->accessFlags & ACC_STATIC) != 0));
1470 printf(" final=%s\n",
1471 quotedBool((pClassDef->accessFlags & ACC_FINAL) != 0));
1472 // "deprecated=" not knowable w/o parsing annotations
1473 printf(" visibility=%s\n",
1474 quotedVisibility(pClassDef->accessFlags));
1475 printf(">\n");
1476 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001477 pInterfaces = dexGetInterfacesList(pDexFile, pClassDef);
1478 if (pInterfaces != NULL) {
1479 for (i = 0; i < (int) pInterfaces->size; i++)
1480 dumpInterface(pDexFile, dexGetTypeItem(pInterfaces, i), i);
1481 }
1482
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001483 if (gOptions.outputFormat == OUTPUT_PLAIN)
1484 printf(" Static fields -\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001485 for (i = 0; i < (int) pClassData->header.staticFieldsSize; i++) {
1486 dumpSField(pDexFile, &pClassData->staticFields[i], i);
1487 }
1488
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001489 if (gOptions.outputFormat == OUTPUT_PLAIN)
1490 printf(" Instance fields -\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001491 for (i = 0; i < (int) pClassData->header.instanceFieldsSize; i++) {
1492 dumpIField(pDexFile, &pClassData->instanceFields[i], i);
1493 }
1494
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001495 if (gOptions.outputFormat == OUTPUT_PLAIN)
1496 printf(" Direct methods -\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001497 for (i = 0; i < (int) pClassData->header.directMethodsSize; i++) {
1498 dumpMethod(pDexFile, &pClassData->directMethods[i], i);
1499 }
1500
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001501 if (gOptions.outputFormat == OUTPUT_PLAIN)
1502 printf(" Virtual methods -\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001503 for (i = 0; i < (int) pClassData->header.virtualMethodsSize; i++) {
1504 dumpMethod(pDexFile, &pClassData->virtualMethods[i], i);
1505 }
1506
1507 // TODO: Annotations.
1508
1509 if (pClassDef->sourceFileIdx != kDexNoIndex)
1510 fileName = dexStringById(pDexFile, pClassDef->sourceFileIdx);
1511 else
1512 fileName = "unknown";
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001513
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001514 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1515 printf(" source_file_idx : %d (%s)\n",
1516 pClassDef->sourceFileIdx, fileName);
1517 printf("\n");
1518 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001519
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001520 if (gOptions.outputFormat == OUTPUT_XML) {
1521 printf("</class>\n");
1522 }
1523
1524bail:
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001525 free(pClassData);
1526 free(accessStr);
1527}
1528
The Android Open Source Project99409882009-03-18 22:20:24 -07001529
1530/*
1531 * Advance "ptr" to ensure 32-bit alignment.
1532 */
1533static inline const u1* align32(const u1* ptr)
1534{
SangWook Hanb210a9f2012-07-15 22:42:28 +09001535 return (u1*) (((uintptr_t) ptr + 3) & ~0x03);
The Android Open Source Project99409882009-03-18 22:20:24 -07001536}
1537
Andy McFadden10351272009-03-24 21:30:32 -07001538
1539/*
1540 * Dump a map in the "differential" format.
1541 *
1542 * TODO: show a hex dump of the compressed data. (We can show the
1543 * uncompressed data if we move the compression code to libdex; otherwise
1544 * it's too complex to merit a fast & fragile implementation here.)
1545 */
1546void dumpDifferentialCompressedMap(const u1** pData)
1547{
1548 const u1* data = *pData;
1549 const u1* dataStart = data -1; // format byte already removed
1550 u1 regWidth;
1551 u2 numEntries;
1552
1553 /* standard header */
1554 regWidth = *data++;
1555 numEntries = *data++;
1556 numEntries |= (*data++) << 8;
1557
1558 /* compressed data begins with the compressed data length */
1559 int compressedLen = readUnsignedLeb128(&data);
1560 int addrWidth = 1;
1561 if ((*data & 0x80) != 0)
1562 addrWidth++;
1563
1564 int origLen = 4 + (addrWidth + regWidth) * numEntries;
1565 int compLen = (data - dataStart) + compressedLen;
1566
1567 printf(" (differential compression %d -> %d [%d -> %d])\n",
1568 origLen, compLen,
1569 (addrWidth + regWidth) * numEntries, compressedLen);
1570
1571 /* skip past end of entry */
1572 data += compressedLen;
1573
1574 *pData = data;
1575}
1576
The Android Open Source Project99409882009-03-18 22:20:24 -07001577/*
1578 * Dump register map contents of the current method.
1579 *
1580 * "*pData" should point to the start of the register map data. Advances
1581 * "*pData" to the start of the next map.
1582 */
1583void dumpMethodMap(DexFile* pDexFile, const DexMethod* pDexMethod, int idx,
1584 const u1** pData)
1585{
1586 const u1* data = *pData;
1587 const DexMethodId* pMethodId;
1588 const char* name;
1589 int offset = data - (u1*) pDexFile->pOptHeader;
1590
1591 pMethodId = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
1592 name = dexStringById(pDexFile, pMethodId->nameIdx);
1593 printf(" #%d: 0x%08x %s\n", idx, offset, name);
1594
1595 u1 format;
1596 int addrWidth;
1597
1598 format = *data++;
1599 if (format == 1) { /* kRegMapFormatNone */
1600 /* no map */
1601 printf(" (no map)\n");
1602 addrWidth = 0;
1603 } else if (format == 2) { /* kRegMapFormatCompact8 */
1604 addrWidth = 1;
1605 } else if (format == 3) { /* kRegMapFormatCompact16 */
1606 addrWidth = 2;
Andy McFadden10351272009-03-24 21:30:32 -07001607 } else if (format == 4) { /* kRegMapFormatDifferential */
1608 dumpDifferentialCompressedMap(&data);
1609 goto bail;
The Android Open Source Project99409882009-03-18 22:20:24 -07001610 } else {
1611 printf(" (unknown format %d!)\n", format);
Andy McFadden10351272009-03-24 21:30:32 -07001612 /* don't know how to skip data; failure will cascade to end of class */
1613 goto bail;
The Android Open Source Project99409882009-03-18 22:20:24 -07001614 }
1615
1616 if (addrWidth > 0) {
1617 u1 regWidth;
1618 u2 numEntries;
1619 int idx, addr, byte;
1620
1621 regWidth = *data++;
1622 numEntries = *data++;
1623 numEntries |= (*data++) << 8;
1624
1625 for (idx = 0; idx < numEntries; idx++) {
1626 addr = *data++;
1627 if (addrWidth > 1)
1628 addr |= (*data++) << 8;
1629
1630 printf(" %4x:", addr);
1631 for (byte = 0; byte < regWidth; byte++) {
1632 printf(" %02x", *data++);
1633 }
1634 printf("\n");
1635 }
1636 }
1637
Andy McFadden10351272009-03-24 21:30:32 -07001638bail:
The Android Open Source Project99409882009-03-18 22:20:24 -07001639 //if (addrWidth >= 0)
1640 // *pData = align32(data);
1641 *pData = data;
1642}
1643
1644/*
1645 * Dump the contents of the register map area.
1646 *
1647 * These are only present in optimized DEX files, and the structure is
1648 * not really exposed to other parts of the VM itself. We're going to
1649 * dig through them here, but this is pretty fragile. DO NOT rely on
1650 * this or derive other code from it.
1651 */
1652void dumpRegisterMaps(DexFile* pDexFile)
1653{
Carl Shapirobfc97992011-04-27 14:16:08 -07001654 const u1* pClassPool = (const u1*)pDexFile->pRegisterMapPool;
The Android Open Source Project99409882009-03-18 22:20:24 -07001655 const u4* classOffsets;
1656 const u1* ptr;
1657 u4 numClasses;
1658 int baseFileOffset = (u1*) pClassPool - (u1*) pDexFile->pOptHeader;
1659 int idx;
1660
1661 if (pClassPool == NULL) {
1662 printf("No register maps found\n");
1663 return;
1664 }
1665
1666 ptr = pClassPool;
1667 numClasses = get4LE(ptr);
1668 ptr += sizeof(u4);
1669 classOffsets = (const u4*) ptr;
1670
1671 printf("RMAP begins at offset 0x%07x\n", baseFileOffset);
1672 printf("Maps for %d classes\n", numClasses);
1673 for (idx = 0; idx < (int) numClasses; idx++) {
1674 const DexClassDef* pClassDef;
1675 const char* classDescriptor;
1676
1677 pClassDef = dexGetClassDef(pDexFile, idx);
1678 classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
1679
1680 printf("%4d: +%d (0x%08x) %s\n", idx, classOffsets[idx],
1681 baseFileOffset + classOffsets[idx], classDescriptor);
1682
1683 if (classOffsets[idx] == 0)
1684 continue;
1685
1686 /*
1687 * What follows is a series of RegisterMap entries, one for every
1688 * direct method, then one for every virtual method.
1689 */
1690 DexClassData* pClassData;
1691 const u1* pEncodedData;
1692 const u1* data = (u1*) pClassPool + classOffsets[idx];
1693 u2 methodCount;
1694 int i;
1695
1696 pEncodedData = dexGetClassData(pDexFile, pClassDef);
1697 pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL);
1698 if (pClassData == NULL) {
1699 fprintf(stderr, "Trouble reading class data\n");
1700 continue;
1701 }
1702
1703 methodCount = *data++;
1704 methodCount |= (*data++) << 8;
1705 data += 2; /* two pad bytes follow methodCount */
1706 if (methodCount != pClassData->header.directMethodsSize
1707 + pClassData->header.virtualMethodsSize)
1708 {
1709 printf("NOTE: method count discrepancy (%d != %d + %d)\n",
1710 methodCount, pClassData->header.directMethodsSize,
1711 pClassData->header.virtualMethodsSize);
1712 /* this is bad, but keep going anyway */
1713 }
1714
1715 printf(" direct methods: %d\n",
1716 pClassData->header.directMethodsSize);
1717 for (i = 0; i < (int) pClassData->header.directMethodsSize; i++) {
1718 dumpMethodMap(pDexFile, &pClassData->directMethods[i], i, &data);
1719 }
1720
1721 printf(" virtual methods: %d\n",
1722 pClassData->header.virtualMethodsSize);
1723 for (i = 0; i < (int) pClassData->header.virtualMethodsSize; i++) {
1724 dumpMethodMap(pDexFile, &pClassData->virtualMethods[i], i, &data);
1725 }
1726
1727 free(pClassData);
1728 }
1729}
1730
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001731/*
1732 * Dump the requested sections of the file.
1733 */
1734void processDexFile(const char* fileName, DexFile* pDexFile)
1735{
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001736 char* package = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001737 int i;
1738
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001739 if (gOptions.verbose) {
1740 printf("Opened '%s', DEX version '%.3s'\n", fileName,
1741 pDexFile->pHeader->magic +4);
1742 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001743
The Android Open Source Project99409882009-03-18 22:20:24 -07001744 if (gOptions.dumpRegisterMaps) {
1745 dumpRegisterMaps(pDexFile);
1746 return;
1747 }
1748
Andy McFadden0ea77b92010-04-20 14:18:59 -07001749 if (gOptions.showFileHeaders) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001750 dumpFileHeader(pDexFile);
Dan Bornsteine377ef62010-08-31 16:50:00 -07001751 dumpOptDirectory(pDexFile);
Andy McFadden0ea77b92010-04-20 14:18:59 -07001752 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001753
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001754 if (gOptions.outputFormat == OUTPUT_XML)
1755 printf("<api>\n");
1756
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001757 for (i = 0; i < (int) pDexFile->pHeader->classDefsSize; i++) {
1758 if (gOptions.showSectionHeaders)
1759 dumpClassDef(pDexFile, i);
1760
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001761 dumpClass(pDexFile, i, &package);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001762 }
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001763
1764 /* free the last one allocated */
1765 if (package != NULL) {
1766 printf("</package>\n");
1767 free(package);
1768 }
1769
1770 if (gOptions.outputFormat == OUTPUT_XML)
1771 printf("</api>\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001772}
1773
1774
1775/*
1776 * Process one file.
1777 */
1778int process(const char* fileName)
1779{
1780 DexFile* pDexFile = NULL;
1781 MemMapping map;
1782 bool mapped = false;
1783 int result = -1;
1784
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001785 if (gOptions.verbose)
1786 printf("Processing '%s'...\n", fileName);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001787
Carl Shapirobfc97992011-04-27 14:16:08 -07001788 if (dexOpenAndMap(fileName, gOptions.tempFileName, &map, false) != 0) {
1789 return result;
1790 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001791 mapped = true;
1792
Andy McFadden2124cb82009-03-25 15:37:39 -07001793 int flags = kDexParseVerifyChecksum;
1794 if (gOptions.ignoreBadChecksum)
1795 flags |= kDexParseContinueOnError;
1796
Carl Shapirobfc97992011-04-27 14:16:08 -07001797 pDexFile = dexFileParse((u1*)map.addr, map.length, flags);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001798 if (pDexFile == NULL) {
1799 fprintf(stderr, "ERROR: DEX parse failed\n");
1800 goto bail;
1801 }
1802
Andy McFadden0198b142009-04-02 14:48:56 -07001803 if (gOptions.checksumOnly) {
1804 printf("Checksum verified\n");
1805 } else {
1806 processDexFile(fileName, pDexFile);
1807 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001808
1809 result = 0;
1810
1811bail:
1812 if (mapped)
1813 sysReleaseShmem(&map);
1814 if (pDexFile != NULL)
1815 dexFileFree(pDexFile);
1816 return result;
1817}
1818
1819
1820/*
1821 * Show usage.
1822 */
1823void usage(void)
1824{
1825 fprintf(stderr, "Copyright (C) 2007 The Android Open Source Project\n\n");
Andy McFadden0198b142009-04-02 14:48:56 -07001826 fprintf(stderr,
Andy McFaddend18aff32009-05-06 10:19:16 -07001827 "%s: [-c] [-d] [-f] [-h] [-i] [-l layout] [-m] [-t tempfile] dexfile...\n",
The Android Open Source Project99409882009-03-18 22:20:24 -07001828 gProgName);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001829 fprintf(stderr, "\n");
Andy McFadden0198b142009-04-02 14:48:56 -07001830 fprintf(stderr, " -c : verify checksum and exit\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001831 fprintf(stderr, " -d : disassemble code sections\n");
1832 fprintf(stderr, " -f : display summary information from file header\n");
1833 fprintf(stderr, " -h : display file header details\n");
Andy McFadden2124cb82009-03-25 15:37:39 -07001834 fprintf(stderr, " -i : ignore checksum failures\n");
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001835 fprintf(stderr, " -l : output layout, either 'plain' or 'xml'\n");
The Android Open Source Project99409882009-03-18 22:20:24 -07001836 fprintf(stderr, " -m : dump register maps (and nothing else)\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001837 fprintf(stderr, " -t : temp file name (defaults to /sdcard/dex-temp-*)\n");
1838}
1839
1840/*
1841 * Parse args.
1842 *
1843 * I'm not using getopt_long() because we may not have it in libc.
1844 */
1845int main(int argc, char* const argv[])
1846{
1847 bool wantUsage = false;
1848 int ic;
1849
1850 memset(&gOptions, 0, sizeof(gOptions));
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001851 gOptions.verbose = true;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001852
1853 while (1) {
Andy McFaddend18aff32009-05-06 10:19:16 -07001854 ic = getopt(argc, argv, "cdfhil:mt:");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001855 if (ic < 0)
1856 break;
1857
1858 switch (ic) {
Andy McFadden0198b142009-04-02 14:48:56 -07001859 case 'c': // verify the checksum then exit
1860 gOptions.checksumOnly = true;
1861 break;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001862 case 'd': // disassemble Dalvik instructions
1863 gOptions.disassemble = true;
1864 break;
1865 case 'f': // dump outer file header
1866 gOptions.showFileHeaders = true;
1867 break;
1868 case 'h': // dump section headers, i.e. all meta-data
1869 gOptions.showSectionHeaders = true;
1870 break;
Andy McFadden2124cb82009-03-25 15:37:39 -07001871 case 'i': // continue even if checksum is bad
1872 gOptions.ignoreBadChecksum = true;
1873 break;
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001874 case 'l': // layout
1875 if (strcmp(optarg, "plain") == 0) {
1876 gOptions.outputFormat = OUTPUT_PLAIN;
1877 } else if (strcmp(optarg, "xml") == 0) {
1878 gOptions.outputFormat = OUTPUT_XML;
1879 gOptions.verbose = false;
1880 gOptions.exportsOnly = true;
1881 } else {
1882 wantUsage = true;
1883 }
1884 break;
The Android Open Source Project99409882009-03-18 22:20:24 -07001885 case 'm': // dump register maps only
1886 gOptions.dumpRegisterMaps = true;
1887 break;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001888 case 't': // temp file, used when opening compressed Jar
Andy McFaddena2ee53b2009-05-05 16:52:10 -07001889 gOptions.tempFileName = optarg;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001890 break;
1891 default:
1892 wantUsage = true;
1893 break;
1894 }
1895 }
1896
1897 if (optind == argc) {
1898 fprintf(stderr, "%s: no file specified\n", gProgName);
1899 wantUsage = true;
1900 }
1901
Andy McFadden0198b142009-04-02 14:48:56 -07001902 if (gOptions.checksumOnly && gOptions.ignoreBadChecksum) {
1903 fprintf(stderr, "Can't specify both -c and -i\n");
1904 wantUsage = true;
1905 }
1906
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001907 if (wantUsage) {
1908 usage();
1909 return 2;
1910 }
1911
Andy McFadden0198b142009-04-02 14:48:56 -07001912 int result = 0;
1913 while (optind < argc) {
1914 result |= process(argv[optind++]);
1915 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001916
Andy McFadden0198b142009-04-02 14:48:56 -07001917 return (result != 0);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001918}