blob: 8778b129c5e4d784a17f40981e398d99669724be [file] [log] [blame]
Aart Bik69ae54a2015-07-01 14:52:26 -07001/*
2 * Copyright (C) 2015 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 *
16 * Implementation file of the dexdump utility.
17 *
18 * This is a re-implementation of the original dexdump utility that was
19 * based on Dalvik functions in libdex into a new dexdump that is now
Aart Bikdce50862016-06-10 16:04:03 -070020 * based on Art functions in libart instead. The output is very similar to
21 * to the original for correct DEX files. Error messages may differ, however.
Aart Bik69ae54a2015-07-01 14:52:26 -070022 * Also, ODEX files are no longer supported.
23 *
24 * The dexdump tool is intended to mimic objdump. When possible, use
25 * similar command-line arguments.
26 *
27 * Differences between XML output and the "current.xml" file:
28 * - classes in same package are not all grouped together; nothing is sorted
29 * - no "deprecated" on fields and methods
Aart Bik69ae54a2015-07-01 14:52:26 -070030 * - no parameter names
31 * - no generic signatures on parameters, e.g. type="java.lang.Class<?>"
32 * - class shows declared fields and methods; does not show inherited fields
33 */
34
35#include "dexdump.h"
36
David Sehr5a1f6292018-01-19 11:08:51 -080037#include <fcntl.h>
Aart Bik69ae54a2015-07-01 14:52:26 -070038#include <inttypes.h>
39#include <stdio.h>
David Sehr5a1f6292018-01-19 11:08:51 -080040#include <sys/mman.h>
41#include <sys/types.h>
42#include <sys/stat.h>
43#include <unistd.h>
Aart Bik69ae54a2015-07-01 14:52:26 -070044
Andreas Gampe5073fed2015-08-10 11:40:25 -070045#include <iostream>
Aart Bik69ae54a2015-07-01 14:52:26 -070046#include <memory>
Andreas Gampe5073fed2015-08-10 11:40:25 -070047#include <sstream>
Aart Bik69ae54a2015-07-01 14:52:26 -070048#include <vector>
49
Andreas Gampe221d9812018-01-22 17:48:56 -080050#include "android-base/logging.h"
Andreas Gampe46ee31b2016-12-14 10:11:49 -080051#include "android-base/stringprintf.h"
52
David Sehr0225f8e2018-01-31 08:52:24 +000053#include "dex/code_item_accessors-inl.h"
David Sehr9e734c72018-01-04 17:56:19 -080054#include "dex/dex_file-inl.h"
55#include "dex/dex_file_exception_helpers.h"
56#include "dex/dex_file_loader.h"
57#include "dex/dex_file_types.h"
58#include "dex/dex_instruction-inl.h"
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070059#include "dexdump_cfg.h"
Aart Bik69ae54a2015-07-01 14:52:26 -070060
61namespace art {
62
63/*
64 * Options parsed in main driver.
65 */
66struct Options gOptions;
67
68/*
Aart Bik4e149602015-07-09 11:45:28 -070069 * Output file. Defaults to stdout.
Aart Bik69ae54a2015-07-01 14:52:26 -070070 */
71FILE* gOutFile = stdout;
72
73/*
74 * Data types that match the definitions in the VM specification.
75 */
76typedef uint8_t u1;
77typedef uint16_t u2;
78typedef uint32_t u4;
79typedef uint64_t u8;
Aart Bikdce50862016-06-10 16:04:03 -070080typedef int8_t s1;
81typedef int16_t s2;
Aart Bik69ae54a2015-07-01 14:52:26 -070082typedef int32_t s4;
83typedef int64_t s8;
84
85/*
86 * Basic information about a field or a method.
87 */
88struct FieldMethodInfo {
89 const char* classDescriptor;
90 const char* name;
91 const char* signature;
92};
93
94/*
95 * Flags for use with createAccessFlagStr().
96 */
97enum AccessFor {
98 kAccessForClass = 0, kAccessForMethod = 1, kAccessForField = 2, kAccessForMAX
99};
100const int kNumFlags = 18;
101
102/*
103 * Gets 2 little-endian bytes.
104 */
105static inline u2 get2LE(unsigned char const* pSrc) {
106 return pSrc[0] | (pSrc[1] << 8);
107}
108
109/*
110 * Converts a single-character primitive type into human-readable form.
111 */
112static const char* primitiveTypeLabel(char typeChar) {
113 switch (typeChar) {
114 case 'B': return "byte";
115 case 'C': return "char";
116 case 'D': return "double";
117 case 'F': return "float";
118 case 'I': return "int";
119 case 'J': return "long";
120 case 'S': return "short";
121 case 'V': return "void";
122 case 'Z': return "boolean";
123 default: return "UNKNOWN";
124 } // switch
125}
126
127/*
128 * Converts a type descriptor to human-readable "dotted" form. For
129 * example, "Ljava/lang/String;" becomes "java.lang.String", and
130 * "[I" becomes "int[]". Also converts '$' to '.', which means this
131 * form can't be converted back to a descriptor.
132 */
Aart Bikc05e2f22016-07-12 15:53:13 -0700133static std::unique_ptr<char[]> descriptorToDot(const char* str) {
Aart Bik69ae54a2015-07-01 14:52:26 -0700134 int targetLen = strlen(str);
135 int offset = 0;
136
137 // Strip leading [s; will be added to end.
138 while (targetLen > 1 && str[offset] == '[') {
139 offset++;
140 targetLen--;
141 } // while
142
143 const int arrayDepth = offset;
144
145 if (targetLen == 1) {
146 // Primitive type.
147 str = primitiveTypeLabel(str[offset]);
148 offset = 0;
149 targetLen = strlen(str);
150 } else {
151 // Account for leading 'L' and trailing ';'.
152 if (targetLen >= 2 && str[offset] == 'L' &&
153 str[offset + targetLen - 1] == ';') {
154 targetLen -= 2;
155 offset++;
156 }
157 }
158
159 // Copy class name over.
Aart Bikc05e2f22016-07-12 15:53:13 -0700160 std::unique_ptr<char[]> newStr(new char[targetLen + arrayDepth * 2 + 1]);
Aart Bik69ae54a2015-07-01 14:52:26 -0700161 int i = 0;
162 for (; i < targetLen; i++) {
163 const char ch = str[offset + i];
164 newStr[i] = (ch == '/' || ch == '$') ? '.' : ch;
165 } // for
166
167 // Add the appropriate number of brackets for arrays.
168 for (int j = 0; j < arrayDepth; j++) {
169 newStr[i++] = '[';
170 newStr[i++] = ']';
171 } // for
172
173 newStr[i] = '\0';
174 return newStr;
175}
176
177/*
178 * Converts the class name portion of a type descriptor to human-readable
Aart Bikc05e2f22016-07-12 15:53:13 -0700179 * "dotted" form. For example, "Ljava/lang/String;" becomes "String".
Aart Bik69ae54a2015-07-01 14:52:26 -0700180 */
Aart Bikc05e2f22016-07-12 15:53:13 -0700181static std::unique_ptr<char[]> descriptorClassToDot(const char* str) {
182 // Reduce to just the class name prefix.
Aart Bik69ae54a2015-07-01 14:52:26 -0700183 const char* lastSlash = strrchr(str, '/');
184 if (lastSlash == nullptr) {
185 lastSlash = str + 1; // start past 'L'
186 } else {
187 lastSlash++; // start past '/'
188 }
189
Aart Bikc05e2f22016-07-12 15:53:13 -0700190 // Copy class name over, trimming trailing ';'.
191 const int targetLen = strlen(lastSlash);
192 std::unique_ptr<char[]> newStr(new char[targetLen]);
193 for (int i = 0; i < targetLen - 1; i++) {
194 const char ch = lastSlash[i];
195 newStr[i] = ch == '$' ? '.' : ch;
Aart Bik69ae54a2015-07-01 14:52:26 -0700196 } // for
Aart Bikc05e2f22016-07-12 15:53:13 -0700197 newStr[targetLen - 1] = '\0';
Aart Bik69ae54a2015-07-01 14:52:26 -0700198 return newStr;
199}
200
201/*
Aart Bikdce50862016-06-10 16:04:03 -0700202 * Returns string representing the boolean value.
203 */
204static const char* strBool(bool val) {
205 return val ? "true" : "false";
206}
207
208/*
Aart Bik69ae54a2015-07-01 14:52:26 -0700209 * Returns a quoted string representing the boolean value.
210 */
211static const char* quotedBool(bool val) {
212 return val ? "\"true\"" : "\"false\"";
213}
214
215/*
216 * Returns a quoted string representing the access flags.
217 */
218static const char* quotedVisibility(u4 accessFlags) {
219 if (accessFlags & kAccPublic) {
220 return "\"public\"";
221 } else if (accessFlags & kAccProtected) {
222 return "\"protected\"";
223 } else if (accessFlags & kAccPrivate) {
224 return "\"private\"";
225 } else {
226 return "\"package\"";
227 }
228}
229
230/*
231 * Counts the number of '1' bits in a word.
232 */
233static int countOnes(u4 val) {
234 val = val - ((val >> 1) & 0x55555555);
235 val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
236 return (((val + (val >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
237}
238
239/*
240 * Creates a new string with human-readable access flags.
241 *
242 * In the base language the access_flags fields are type u2; in Dalvik
243 * they're u4.
244 */
245static char* createAccessFlagStr(u4 flags, AccessFor forWhat) {
246 static const char* kAccessStrings[kAccessForMAX][kNumFlags] = {
247 {
248 "PUBLIC", /* 0x00001 */
249 "PRIVATE", /* 0x00002 */
250 "PROTECTED", /* 0x00004 */
251 "STATIC", /* 0x00008 */
252 "FINAL", /* 0x00010 */
253 "?", /* 0x00020 */
254 "?", /* 0x00040 */
255 "?", /* 0x00080 */
256 "?", /* 0x00100 */
257 "INTERFACE", /* 0x00200 */
258 "ABSTRACT", /* 0x00400 */
259 "?", /* 0x00800 */
260 "SYNTHETIC", /* 0x01000 */
261 "ANNOTATION", /* 0x02000 */
262 "ENUM", /* 0x04000 */
263 "?", /* 0x08000 */
264 "VERIFIED", /* 0x10000 */
265 "OPTIMIZED", /* 0x20000 */
266 }, {
267 "PUBLIC", /* 0x00001 */
268 "PRIVATE", /* 0x00002 */
269 "PROTECTED", /* 0x00004 */
270 "STATIC", /* 0x00008 */
271 "FINAL", /* 0x00010 */
272 "SYNCHRONIZED", /* 0x00020 */
273 "BRIDGE", /* 0x00040 */
274 "VARARGS", /* 0x00080 */
275 "NATIVE", /* 0x00100 */
276 "?", /* 0x00200 */
277 "ABSTRACT", /* 0x00400 */
278 "STRICT", /* 0x00800 */
279 "SYNTHETIC", /* 0x01000 */
280 "?", /* 0x02000 */
281 "?", /* 0x04000 */
282 "MIRANDA", /* 0x08000 */
283 "CONSTRUCTOR", /* 0x10000 */
284 "DECLARED_SYNCHRONIZED", /* 0x20000 */
285 }, {
286 "PUBLIC", /* 0x00001 */
287 "PRIVATE", /* 0x00002 */
288 "PROTECTED", /* 0x00004 */
289 "STATIC", /* 0x00008 */
290 "FINAL", /* 0x00010 */
291 "?", /* 0x00020 */
292 "VOLATILE", /* 0x00040 */
293 "TRANSIENT", /* 0x00080 */
294 "?", /* 0x00100 */
295 "?", /* 0x00200 */
296 "?", /* 0x00400 */
297 "?", /* 0x00800 */
298 "SYNTHETIC", /* 0x01000 */
299 "?", /* 0x02000 */
300 "ENUM", /* 0x04000 */
301 "?", /* 0x08000 */
302 "?", /* 0x10000 */
303 "?", /* 0x20000 */
304 },
305 };
306
307 // Allocate enough storage to hold the expected number of strings,
308 // plus a space between each. We over-allocate, using the longest
309 // string above as the base metric.
310 const int kLongest = 21; // The strlen of longest string above.
311 const int count = countOnes(flags);
312 char* str;
313 char* cp;
314 cp = str = reinterpret_cast<char*>(malloc(count * (kLongest + 1) + 1));
315
316 for (int i = 0; i < kNumFlags; i++) {
317 if (flags & 0x01) {
318 const char* accessStr = kAccessStrings[forWhat][i];
319 const int len = strlen(accessStr);
320 if (cp != str) {
321 *cp++ = ' ';
322 }
323 memcpy(cp, accessStr, len);
324 cp += len;
325 }
326 flags >>= 1;
327 } // for
328
329 *cp = '\0';
330 return str;
331}
332
333/*
334 * Copies character data from "data" to "out", converting non-ASCII values
335 * to fprintf format chars or an ASCII filler ('.' or '?').
336 *
337 * The output buffer must be able to hold (2*len)+1 bytes. The result is
338 * NULL-terminated.
339 */
340static void asciify(char* out, const unsigned char* data, size_t len) {
341 while (len--) {
342 if (*data < 0x20) {
343 // Could do more here, but we don't need them yet.
344 switch (*data) {
345 case '\0':
346 *out++ = '\\';
347 *out++ = '0';
348 break;
349 case '\n':
350 *out++ = '\\';
351 *out++ = 'n';
352 break;
353 default:
354 *out++ = '.';
355 break;
356 } // switch
357 } else if (*data >= 0x80) {
358 *out++ = '?';
359 } else {
360 *out++ = *data;
361 }
362 data++;
363 } // while
364 *out = '\0';
365}
366
367/*
Aart Bikdce50862016-06-10 16:04:03 -0700368 * Dumps a string value with some escape characters.
369 */
370static void dumpEscapedString(const char* p) {
371 fputs("\"", gOutFile);
372 for (; *p; p++) {
373 switch (*p) {
374 case '\\':
375 fputs("\\\\", gOutFile);
376 break;
377 case '\"':
378 fputs("\\\"", gOutFile);
379 break;
380 case '\t':
381 fputs("\\t", gOutFile);
382 break;
383 case '\n':
384 fputs("\\n", gOutFile);
385 break;
386 case '\r':
387 fputs("\\r", gOutFile);
388 break;
389 default:
390 putc(*p, gOutFile);
391 } // switch
392 } // for
393 fputs("\"", gOutFile);
394}
395
396/*
397 * Dumps a string as an XML attribute value.
398 */
399static void dumpXmlAttribute(const char* p) {
400 for (; *p; p++) {
401 switch (*p) {
402 case '&':
403 fputs("&amp;", gOutFile);
404 break;
405 case '<':
406 fputs("&lt;", gOutFile);
407 break;
408 case '>':
409 fputs("&gt;", gOutFile);
410 break;
411 case '"':
412 fputs("&quot;", gOutFile);
413 break;
414 case '\t':
415 fputs("&#x9;", gOutFile);
416 break;
417 case '\n':
418 fputs("&#xA;", gOutFile);
419 break;
420 case '\r':
421 fputs("&#xD;", gOutFile);
422 break;
423 default:
424 putc(*p, gOutFile);
425 } // switch
426 } // for
427}
428
429/*
430 * Reads variable width value, possibly sign extended at the last defined byte.
431 */
432static u8 readVarWidth(const u1** data, u1 arg, bool sign_extend) {
433 u8 value = 0;
434 for (u4 i = 0; i <= arg; i++) {
435 value |= static_cast<u8>(*(*data)++) << (i * 8);
436 }
437 if (sign_extend) {
438 int shift = (7 - arg) * 8;
439 return (static_cast<s8>(value) << shift) >> shift;
440 }
441 return value;
442}
443
444/*
445 * Dumps encoded value.
446 */
447static void dumpEncodedValue(const DexFile* pDexFile, const u1** data); // forward
448static void dumpEncodedValue(const DexFile* pDexFile, const u1** data, u1 type, u1 arg) {
449 switch (type) {
450 case DexFile::kDexAnnotationByte:
451 fprintf(gOutFile, "%" PRId8, static_cast<s1>(readVarWidth(data, arg, false)));
452 break;
453 case DexFile::kDexAnnotationShort:
454 fprintf(gOutFile, "%" PRId16, static_cast<s2>(readVarWidth(data, arg, true)));
455 break;
456 case DexFile::kDexAnnotationChar:
457 fprintf(gOutFile, "%" PRIu16, static_cast<u2>(readVarWidth(data, arg, false)));
458 break;
459 case DexFile::kDexAnnotationInt:
460 fprintf(gOutFile, "%" PRId32, static_cast<s4>(readVarWidth(data, arg, true)));
461 break;
462 case DexFile::kDexAnnotationLong:
463 fprintf(gOutFile, "%" PRId64, static_cast<s8>(readVarWidth(data, arg, true)));
464 break;
465 case DexFile::kDexAnnotationFloat: {
466 // Fill on right.
467 union {
468 float f;
469 u4 data;
470 } conv;
471 conv.data = static_cast<u4>(readVarWidth(data, arg, false)) << (3 - arg) * 8;
472 fprintf(gOutFile, "%g", conv.f);
473 break;
474 }
475 case DexFile::kDexAnnotationDouble: {
476 // Fill on right.
477 union {
478 double d;
479 u8 data;
480 } conv;
481 conv.data = readVarWidth(data, arg, false) << (7 - arg) * 8;
482 fprintf(gOutFile, "%g", conv.d);
483 break;
484 }
485 case DexFile::kDexAnnotationString: {
486 const u4 idx = static_cast<u4>(readVarWidth(data, arg, false));
487 if (gOptions.outputFormat == OUTPUT_PLAIN) {
Andreas Gampe8a0128a2016-11-28 07:38:35 -0800488 dumpEscapedString(pDexFile->StringDataByIdx(dex::StringIndex(idx)));
Aart Bikdce50862016-06-10 16:04:03 -0700489 } else {
Andreas Gampe8a0128a2016-11-28 07:38:35 -0800490 dumpXmlAttribute(pDexFile->StringDataByIdx(dex::StringIndex(idx)));
Aart Bikdce50862016-06-10 16:04:03 -0700491 }
492 break;
493 }
494 case DexFile::kDexAnnotationType: {
495 const u4 str_idx = static_cast<u4>(readVarWidth(data, arg, false));
Andreas Gampea5b09a62016-11-17 15:21:22 -0800496 fputs(pDexFile->StringByTypeIdx(dex::TypeIndex(str_idx)), gOutFile);
Aart Bikdce50862016-06-10 16:04:03 -0700497 break;
498 }
499 case DexFile::kDexAnnotationField:
500 case DexFile::kDexAnnotationEnum: {
501 const u4 field_idx = static_cast<u4>(readVarWidth(data, arg, false));
502 const DexFile::FieldId& pFieldId = pDexFile->GetFieldId(field_idx);
503 fputs(pDexFile->StringDataByIdx(pFieldId.name_idx_), gOutFile);
504 break;
505 }
506 case DexFile::kDexAnnotationMethod: {
507 const u4 method_idx = static_cast<u4>(readVarWidth(data, arg, false));
508 const DexFile::MethodId& pMethodId = pDexFile->GetMethodId(method_idx);
509 fputs(pDexFile->StringDataByIdx(pMethodId.name_idx_), gOutFile);
510 break;
511 }
512 case DexFile::kDexAnnotationArray: {
513 fputc('{', gOutFile);
514 // Decode and display all elements.
515 const u4 size = DecodeUnsignedLeb128(data);
516 for (u4 i = 0; i < size; i++) {
517 fputc(' ', gOutFile);
518 dumpEncodedValue(pDexFile, data);
519 }
520 fputs(" }", gOutFile);
521 break;
522 }
523 case DexFile::kDexAnnotationAnnotation: {
524 const u4 type_idx = DecodeUnsignedLeb128(data);
Andreas Gampea5b09a62016-11-17 15:21:22 -0800525 fputs(pDexFile->StringByTypeIdx(dex::TypeIndex(type_idx)), gOutFile);
Aart Bikdce50862016-06-10 16:04:03 -0700526 // Decode and display all name=value pairs.
527 const u4 size = DecodeUnsignedLeb128(data);
528 for (u4 i = 0; i < size; i++) {
529 const u4 name_idx = DecodeUnsignedLeb128(data);
530 fputc(' ', gOutFile);
Andreas Gampe8a0128a2016-11-28 07:38:35 -0800531 fputs(pDexFile->StringDataByIdx(dex::StringIndex(name_idx)), gOutFile);
Aart Bikdce50862016-06-10 16:04:03 -0700532 fputc('=', gOutFile);
533 dumpEncodedValue(pDexFile, data);
534 }
535 break;
536 }
537 case DexFile::kDexAnnotationNull:
538 fputs("null", gOutFile);
539 break;
540 case DexFile::kDexAnnotationBoolean:
541 fputs(strBool(arg), gOutFile);
542 break;
543 default:
544 fputs("????", gOutFile);
545 break;
546 } // switch
547}
548
549/*
550 * Dumps encoded value with prefix.
551 */
552static void dumpEncodedValue(const DexFile* pDexFile, const u1** data) {
553 const u1 enc = *(*data)++;
554 dumpEncodedValue(pDexFile, data, enc & 0x1f, enc >> 5);
555}
556
557/*
Aart Bik69ae54a2015-07-01 14:52:26 -0700558 * Dumps the file header.
Aart Bik69ae54a2015-07-01 14:52:26 -0700559 */
560static void dumpFileHeader(const DexFile* pDexFile) {
561 const DexFile::Header& pHeader = pDexFile->GetHeader();
562 char sanitized[sizeof(pHeader.magic_) * 2 + 1];
563 fprintf(gOutFile, "DEX file header:\n");
564 asciify(sanitized, pHeader.magic_, sizeof(pHeader.magic_));
565 fprintf(gOutFile, "magic : '%s'\n", sanitized);
566 fprintf(gOutFile, "checksum : %08x\n", pHeader.checksum_);
567 fprintf(gOutFile, "signature : %02x%02x...%02x%02x\n",
568 pHeader.signature_[0], pHeader.signature_[1],
569 pHeader.signature_[DexFile::kSha1DigestSize - 2],
570 pHeader.signature_[DexFile::kSha1DigestSize - 1]);
571 fprintf(gOutFile, "file_size : %d\n", pHeader.file_size_);
572 fprintf(gOutFile, "header_size : %d\n", pHeader.header_size_);
573 fprintf(gOutFile, "link_size : %d\n", pHeader.link_size_);
574 fprintf(gOutFile, "link_off : %d (0x%06x)\n",
575 pHeader.link_off_, pHeader.link_off_);
576 fprintf(gOutFile, "string_ids_size : %d\n", pHeader.string_ids_size_);
577 fprintf(gOutFile, "string_ids_off : %d (0x%06x)\n",
578 pHeader.string_ids_off_, pHeader.string_ids_off_);
579 fprintf(gOutFile, "type_ids_size : %d\n", pHeader.type_ids_size_);
580 fprintf(gOutFile, "type_ids_off : %d (0x%06x)\n",
581 pHeader.type_ids_off_, pHeader.type_ids_off_);
Aart Bikdce50862016-06-10 16:04:03 -0700582 fprintf(gOutFile, "proto_ids_size : %d\n", pHeader.proto_ids_size_);
583 fprintf(gOutFile, "proto_ids_off : %d (0x%06x)\n",
Aart Bik69ae54a2015-07-01 14:52:26 -0700584 pHeader.proto_ids_off_, pHeader.proto_ids_off_);
585 fprintf(gOutFile, "field_ids_size : %d\n", pHeader.field_ids_size_);
586 fprintf(gOutFile, "field_ids_off : %d (0x%06x)\n",
587 pHeader.field_ids_off_, pHeader.field_ids_off_);
588 fprintf(gOutFile, "method_ids_size : %d\n", pHeader.method_ids_size_);
589 fprintf(gOutFile, "method_ids_off : %d (0x%06x)\n",
590 pHeader.method_ids_off_, pHeader.method_ids_off_);
591 fprintf(gOutFile, "class_defs_size : %d\n", pHeader.class_defs_size_);
592 fprintf(gOutFile, "class_defs_off : %d (0x%06x)\n",
593 pHeader.class_defs_off_, pHeader.class_defs_off_);
594 fprintf(gOutFile, "data_size : %d\n", pHeader.data_size_);
595 fprintf(gOutFile, "data_off : %d (0x%06x)\n\n",
596 pHeader.data_off_, pHeader.data_off_);
597}
598
599/*
600 * Dumps a class_def_item.
601 */
602static void dumpClassDef(const DexFile* pDexFile, int idx) {
603 // General class information.
604 const DexFile::ClassDef& pClassDef = pDexFile->GetClassDef(idx);
605 fprintf(gOutFile, "Class #%d header:\n", idx);
Andreas Gampea5b09a62016-11-17 15:21:22 -0800606 fprintf(gOutFile, "class_idx : %d\n", pClassDef.class_idx_.index_);
Aart Bik69ae54a2015-07-01 14:52:26 -0700607 fprintf(gOutFile, "access_flags : %d (0x%04x)\n",
608 pClassDef.access_flags_, pClassDef.access_flags_);
Andreas Gampea5b09a62016-11-17 15:21:22 -0800609 fprintf(gOutFile, "superclass_idx : %d\n", pClassDef.superclass_idx_.index_);
Aart Bik69ae54a2015-07-01 14:52:26 -0700610 fprintf(gOutFile, "interfaces_off : %d (0x%06x)\n",
611 pClassDef.interfaces_off_, pClassDef.interfaces_off_);
Andreas Gampe8a0128a2016-11-28 07:38:35 -0800612 fprintf(gOutFile, "source_file_idx : %d\n", pClassDef.source_file_idx_.index_);
Aart Bik69ae54a2015-07-01 14:52:26 -0700613 fprintf(gOutFile, "annotations_off : %d (0x%06x)\n",
614 pClassDef.annotations_off_, pClassDef.annotations_off_);
615 fprintf(gOutFile, "class_data_off : %d (0x%06x)\n",
616 pClassDef.class_data_off_, pClassDef.class_data_off_);
617
618 // Fields and methods.
619 const u1* pEncodedData = pDexFile->GetClassData(pClassDef);
620 if (pEncodedData != nullptr) {
621 ClassDataItemIterator pClassData(*pDexFile, pEncodedData);
622 fprintf(gOutFile, "static_fields_size : %d\n", pClassData.NumStaticFields());
623 fprintf(gOutFile, "instance_fields_size: %d\n", pClassData.NumInstanceFields());
624 fprintf(gOutFile, "direct_methods_size : %d\n", pClassData.NumDirectMethods());
625 fprintf(gOutFile, "virtual_methods_size: %d\n", pClassData.NumVirtualMethods());
626 } else {
627 fprintf(gOutFile, "static_fields_size : 0\n");
628 fprintf(gOutFile, "instance_fields_size: 0\n");
629 fprintf(gOutFile, "direct_methods_size : 0\n");
630 fprintf(gOutFile, "virtual_methods_size: 0\n");
631 }
632 fprintf(gOutFile, "\n");
633}
634
Aart Bikdce50862016-06-10 16:04:03 -0700635/**
636 * Dumps an annotation set item.
637 */
638static void dumpAnnotationSetItem(const DexFile* pDexFile, const DexFile::AnnotationSetItem* set_item) {
639 if (set_item == nullptr || set_item->size_ == 0) {
640 fputs(" empty-annotation-set\n", gOutFile);
641 return;
642 }
643 for (u4 i = 0; i < set_item->size_; i++) {
644 const DexFile::AnnotationItem* annotation = pDexFile->GetAnnotationItem(set_item, i);
645 if (annotation == nullptr) {
646 continue;
647 }
648 fputs(" ", gOutFile);
649 switch (annotation->visibility_) {
650 case DexFile::kDexVisibilityBuild: fputs("VISIBILITY_BUILD ", gOutFile); break;
651 case DexFile::kDexVisibilityRuntime: fputs("VISIBILITY_RUNTIME ", gOutFile); break;
652 case DexFile::kDexVisibilitySystem: fputs("VISIBILITY_SYSTEM ", gOutFile); break;
653 default: fputs("VISIBILITY_UNKNOWN ", gOutFile); break;
654 } // switch
655 // Decode raw bytes in annotation.
656 const u1* rData = annotation->annotation_;
657 dumpEncodedValue(pDexFile, &rData, DexFile::kDexAnnotationAnnotation, 0);
658 fputc('\n', gOutFile);
659 }
660}
661
662/*
663 * Dumps class annotations.
664 */
665static void dumpClassAnnotations(const DexFile* pDexFile, int idx) {
666 const DexFile::ClassDef& pClassDef = pDexFile->GetClassDef(idx);
667 const DexFile::AnnotationsDirectoryItem* dir = pDexFile->GetAnnotationsDirectory(pClassDef);
668 if (dir == nullptr) {
669 return; // none
670 }
671
672 fprintf(gOutFile, "Class #%d annotations:\n", idx);
673
674 const DexFile::AnnotationSetItem* class_set_item = pDexFile->GetClassAnnotationSet(dir);
675 const DexFile::FieldAnnotationsItem* fields = pDexFile->GetFieldAnnotations(dir);
676 const DexFile::MethodAnnotationsItem* methods = pDexFile->GetMethodAnnotations(dir);
677 const DexFile::ParameterAnnotationsItem* pars = pDexFile->GetParameterAnnotations(dir);
678
679 // Annotations on the class itself.
680 if (class_set_item != nullptr) {
681 fprintf(gOutFile, "Annotations on class\n");
682 dumpAnnotationSetItem(pDexFile, class_set_item);
683 }
684
685 // Annotations on fields.
686 if (fields != nullptr) {
687 for (u4 i = 0; i < dir->fields_size_; i++) {
688 const u4 field_idx = fields[i].field_idx_;
689 const DexFile::FieldId& pFieldId = pDexFile->GetFieldId(field_idx);
690 const char* field_name = pDexFile->StringDataByIdx(pFieldId.name_idx_);
691 fprintf(gOutFile, "Annotations on field #%u '%s'\n", field_idx, field_name);
692 dumpAnnotationSetItem(pDexFile, pDexFile->GetFieldAnnotationSetItem(fields[i]));
693 }
694 }
695
696 // Annotations on methods.
697 if (methods != nullptr) {
698 for (u4 i = 0; i < dir->methods_size_; i++) {
699 const u4 method_idx = methods[i].method_idx_;
700 const DexFile::MethodId& pMethodId = pDexFile->GetMethodId(method_idx);
701 const char* method_name = pDexFile->StringDataByIdx(pMethodId.name_idx_);
702 fprintf(gOutFile, "Annotations on method #%u '%s'\n", method_idx, method_name);
703 dumpAnnotationSetItem(pDexFile, pDexFile->GetMethodAnnotationSetItem(methods[i]));
704 }
705 }
706
707 // Annotations on method parameters.
708 if (pars != nullptr) {
709 for (u4 i = 0; i < dir->parameters_size_; i++) {
710 const u4 method_idx = pars[i].method_idx_;
711 const DexFile::MethodId& pMethodId = pDexFile->GetMethodId(method_idx);
712 const char* method_name = pDexFile->StringDataByIdx(pMethodId.name_idx_);
713 fprintf(gOutFile, "Annotations on method #%u '%s' parameters\n", method_idx, method_name);
714 const DexFile::AnnotationSetRefList*
715 list = pDexFile->GetParameterAnnotationSetRefList(&pars[i]);
716 if (list != nullptr) {
717 for (u4 j = 0; j < list->size_; j++) {
718 fprintf(gOutFile, "#%u\n", j);
719 dumpAnnotationSetItem(pDexFile, pDexFile->GetSetRefItemItem(&list->list_[j]));
720 }
721 }
722 }
723 }
724
725 fputc('\n', gOutFile);
726}
727
Aart Bik69ae54a2015-07-01 14:52:26 -0700728/*
729 * Dumps an interface that a class declares to implement.
730 */
731static void dumpInterface(const DexFile* pDexFile, const DexFile::TypeItem& pTypeItem, int i) {
732 const char* interfaceName = pDexFile->StringByTypeIdx(pTypeItem.type_idx_);
733 if (gOptions.outputFormat == OUTPUT_PLAIN) {
734 fprintf(gOutFile, " #%d : '%s'\n", i, interfaceName);
735 } else {
Aart Bikc05e2f22016-07-12 15:53:13 -0700736 std::unique_ptr<char[]> dot(descriptorToDot(interfaceName));
737 fprintf(gOutFile, "<implements name=\"%s\">\n</implements>\n", dot.get());
Aart Bik69ae54a2015-07-01 14:52:26 -0700738 }
739}
740
741/*
742 * Dumps the catches table associated with the code.
743 */
744static void dumpCatches(const DexFile* pDexFile, const DexFile::CodeItem* pCode) {
Mathieu Chartier698ebbc2018-01-05 11:00:42 -0800745 CodeItemDataAccessor accessor(*pDexFile, pCode);
Mathieu Chartierdc578c72017-12-27 11:51:45 -0800746 const u4 triesSize = accessor.TriesSize();
Aart Bik69ae54a2015-07-01 14:52:26 -0700747
748 // No catch table.
749 if (triesSize == 0) {
750 fprintf(gOutFile, " catches : (none)\n");
751 return;
752 }
753
754 // Dump all table entries.
755 fprintf(gOutFile, " catches : %d\n", triesSize);
Mathieu Chartierdc578c72017-12-27 11:51:45 -0800756 for (const DexFile::TryItem& try_item : accessor.TryItems()) {
757 const u4 start = try_item.start_addr_;
758 const u4 end = start + try_item.insn_count_;
Aart Bik69ae54a2015-07-01 14:52:26 -0700759 fprintf(gOutFile, " 0x%04x - 0x%04x\n", start, end);
Mathieu Chartierdc578c72017-12-27 11:51:45 -0800760 for (CatchHandlerIterator it(accessor, try_item); it.HasNext(); it.Next()) {
Andreas Gampea5b09a62016-11-17 15:21:22 -0800761 const dex::TypeIndex tidx = it.GetHandlerTypeIndex();
762 const char* descriptor = (!tidx.IsValid()) ? "<any>" : pDexFile->StringByTypeIdx(tidx);
Aart Bik69ae54a2015-07-01 14:52:26 -0700763 fprintf(gOutFile, " %s -> 0x%04x\n", descriptor, it.GetHandlerAddress());
764 } // for
765 } // for
766}
767
768/*
769 * Callback for dumping each positions table entry.
770 */
David Srbeckyb06e28e2015-12-10 13:15:00 +0000771static bool dumpPositionsCb(void* /*context*/, const DexFile::PositionInfo& entry) {
772 fprintf(gOutFile, " 0x%04x line=%d\n", entry.address_, entry.line_);
Aart Bik69ae54a2015-07-01 14:52:26 -0700773 return false;
774}
775
776/*
777 * Callback for dumping locals table entry.
778 */
David Srbeckyb06e28e2015-12-10 13:15:00 +0000779static void dumpLocalsCb(void* /*context*/, const DexFile::LocalInfo& entry) {
780 const char* signature = entry.signature_ != nullptr ? entry.signature_ : "";
Aart Bik69ae54a2015-07-01 14:52:26 -0700781 fprintf(gOutFile, " 0x%04x - 0x%04x reg=%d %s %s %s\n",
David Srbeckyb06e28e2015-12-10 13:15:00 +0000782 entry.start_address_, entry.end_address_, entry.reg_,
783 entry.name_, entry.descriptor_, signature);
Aart Bik69ae54a2015-07-01 14:52:26 -0700784}
785
786/*
787 * Helper for dumpInstruction(), which builds the string
Aart Bika0e33fd2016-07-08 18:32:45 -0700788 * representation for the index in the given instruction.
789 * Returns a pointer to a buffer of sufficient size.
Aart Bik69ae54a2015-07-01 14:52:26 -0700790 */
Aart Bika0e33fd2016-07-08 18:32:45 -0700791static std::unique_ptr<char[]> indexString(const DexFile* pDexFile,
792 const Instruction* pDecInsn,
793 size_t bufSize) {
Orion Hodsonb34bb192016-10-18 17:02:58 +0100794 static const u4 kInvalidIndex = std::numeric_limits<u4>::max();
Aart Bika0e33fd2016-07-08 18:32:45 -0700795 std::unique_ptr<char[]> buf(new char[bufSize]);
Aart Bik69ae54a2015-07-01 14:52:26 -0700796 // Determine index and width of the string.
797 u4 index = 0;
Orion Hodsonb34bb192016-10-18 17:02:58 +0100798 u4 secondary_index = kInvalidIndex;
Aart Bik69ae54a2015-07-01 14:52:26 -0700799 u4 width = 4;
800 switch (Instruction::FormatOf(pDecInsn->Opcode())) {
801 // SOME NOT SUPPORTED:
802 // case Instruction::k20bc:
803 case Instruction::k21c:
804 case Instruction::k35c:
805 // case Instruction::k35ms:
806 case Instruction::k3rc:
807 // case Instruction::k3rms:
808 // case Instruction::k35mi:
809 // case Instruction::k3rmi:
810 index = pDecInsn->VRegB();
811 width = 4;
812 break;
813 case Instruction::k31c:
814 index = pDecInsn->VRegB();
815 width = 8;
816 break;
817 case Instruction::k22c:
818 // case Instruction::k22cs:
819 index = pDecInsn->VRegC();
820 width = 4;
821 break;
Orion Hodsonb34bb192016-10-18 17:02:58 +0100822 case Instruction::k45cc:
823 case Instruction::k4rcc:
824 index = pDecInsn->VRegB();
825 secondary_index = pDecInsn->VRegH();
826 width = 4;
827 break;
Aart Bik69ae54a2015-07-01 14:52:26 -0700828 default:
829 break;
830 } // switch
831
832 // Determine index type.
833 size_t outSize = 0;
834 switch (Instruction::IndexTypeOf(pDecInsn->Opcode())) {
835 case Instruction::kIndexUnknown:
836 // This function should never get called for this type, but do
837 // something sensible here, just to help with debugging.
Aart Bika0e33fd2016-07-08 18:32:45 -0700838 outSize = snprintf(buf.get(), bufSize, "<unknown-index>");
Aart Bik69ae54a2015-07-01 14:52:26 -0700839 break;
840 case Instruction::kIndexNone:
841 // This function should never get called for this type, but do
842 // something sensible here, just to help with debugging.
Aart Bika0e33fd2016-07-08 18:32:45 -0700843 outSize = snprintf(buf.get(), bufSize, "<no-index>");
Aart Bik69ae54a2015-07-01 14:52:26 -0700844 break;
845 case Instruction::kIndexTypeRef:
846 if (index < pDexFile->GetHeader().type_ids_size_) {
Andreas Gampea5b09a62016-11-17 15:21:22 -0800847 const char* tp = pDexFile->StringByTypeIdx(dex::TypeIndex(index));
Aart Bika0e33fd2016-07-08 18:32:45 -0700848 outSize = snprintf(buf.get(), bufSize, "%s // type@%0*x", tp, width, index);
Aart Bik69ae54a2015-07-01 14:52:26 -0700849 } else {
Aart Bika0e33fd2016-07-08 18:32:45 -0700850 outSize = snprintf(buf.get(), bufSize, "<type?> // type@%0*x", width, index);
Aart Bik69ae54a2015-07-01 14:52:26 -0700851 }
852 break;
853 case Instruction::kIndexStringRef:
854 if (index < pDexFile->GetHeader().string_ids_size_) {
Andreas Gampe8a0128a2016-11-28 07:38:35 -0800855 const char* st = pDexFile->StringDataByIdx(dex::StringIndex(index));
Aart Bika0e33fd2016-07-08 18:32:45 -0700856 outSize = snprintf(buf.get(), bufSize, "\"%s\" // string@%0*x", st, width, index);
Aart Bik69ae54a2015-07-01 14:52:26 -0700857 } else {
Aart Bika0e33fd2016-07-08 18:32:45 -0700858 outSize = snprintf(buf.get(), bufSize, "<string?> // string@%0*x", width, index);
Aart Bik69ae54a2015-07-01 14:52:26 -0700859 }
860 break;
861 case Instruction::kIndexMethodRef:
862 if (index < pDexFile->GetHeader().method_ids_size_) {
863 const DexFile::MethodId& pMethodId = pDexFile->GetMethodId(index);
864 const char* name = pDexFile->StringDataByIdx(pMethodId.name_idx_);
865 const Signature signature = pDexFile->GetMethodSignature(pMethodId);
866 const char* backDescriptor = pDexFile->StringByTypeIdx(pMethodId.class_idx_);
Aart Bika0e33fd2016-07-08 18:32:45 -0700867 outSize = snprintf(buf.get(), bufSize, "%s.%s:%s // method@%0*x",
Aart Bik69ae54a2015-07-01 14:52:26 -0700868 backDescriptor, name, signature.ToString().c_str(), width, index);
869 } else {
Aart Bika0e33fd2016-07-08 18:32:45 -0700870 outSize = snprintf(buf.get(), bufSize, "<method?> // method@%0*x", width, index);
Aart Bik69ae54a2015-07-01 14:52:26 -0700871 }
872 break;
873 case Instruction::kIndexFieldRef:
874 if (index < pDexFile->GetHeader().field_ids_size_) {
875 const DexFile::FieldId& pFieldId = pDexFile->GetFieldId(index);
876 const char* name = pDexFile->StringDataByIdx(pFieldId.name_idx_);
877 const char* typeDescriptor = pDexFile->StringByTypeIdx(pFieldId.type_idx_);
878 const char* backDescriptor = pDexFile->StringByTypeIdx(pFieldId.class_idx_);
Aart Bika0e33fd2016-07-08 18:32:45 -0700879 outSize = snprintf(buf.get(), bufSize, "%s.%s:%s // field@%0*x",
Aart Bik69ae54a2015-07-01 14:52:26 -0700880 backDescriptor, name, typeDescriptor, width, index);
881 } else {
Aart Bika0e33fd2016-07-08 18:32:45 -0700882 outSize = snprintf(buf.get(), bufSize, "<field?> // field@%0*x", width, index);
Aart Bik69ae54a2015-07-01 14:52:26 -0700883 }
884 break;
885 case Instruction::kIndexVtableOffset:
Aart Bika0e33fd2016-07-08 18:32:45 -0700886 outSize = snprintf(buf.get(), bufSize, "[%0*x] // vtable #%0*x",
Aart Bik69ae54a2015-07-01 14:52:26 -0700887 width, index, width, index);
888 break;
889 case Instruction::kIndexFieldOffset:
Aart Bika0e33fd2016-07-08 18:32:45 -0700890 outSize = snprintf(buf.get(), bufSize, "[obj+%0*x]", width, index);
Aart Bik69ae54a2015-07-01 14:52:26 -0700891 break;
Orion Hodsonb34bb192016-10-18 17:02:58 +0100892 case Instruction::kIndexMethodAndProtoRef: {
Orion Hodsonc069a302017-01-18 09:23:12 +0000893 std::string method("<method?>");
894 std::string proto("<proto?>");
895 if (index < pDexFile->GetHeader().method_ids_size_) {
896 const DexFile::MethodId& pMethodId = pDexFile->GetMethodId(index);
897 const char* name = pDexFile->StringDataByIdx(pMethodId.name_idx_);
898 const Signature signature = pDexFile->GetMethodSignature(pMethodId);
899 const char* backDescriptor = pDexFile->StringByTypeIdx(pMethodId.class_idx_);
900 method = android::base::StringPrintf("%s.%s:%s",
901 backDescriptor,
902 name,
903 signature.ToString().c_str());
Orion Hodsonb34bb192016-10-18 17:02:58 +0100904 }
Orion Hodsonc069a302017-01-18 09:23:12 +0000905 if (secondary_index < pDexFile->GetHeader().proto_ids_size_) {
906 const DexFile::ProtoId& protoId = pDexFile->GetProtoId(secondary_index);
907 const Signature signature = pDexFile->GetProtoSignature(protoId);
908 proto = signature.ToString();
909 }
910 outSize = snprintf(buf.get(), bufSize, "%s, %s // method@%0*x, proto@%0*x",
911 method.c_str(), proto.c_str(), width, index, width, secondary_index);
912 break;
913 }
914 case Instruction::kIndexCallSiteRef:
915 // Call site information is too large to detail in disassembly so just output the index.
916 outSize = snprintf(buf.get(), bufSize, "call_site@%0*x", width, index);
Orion Hodsonb34bb192016-10-18 17:02:58 +0100917 break;
Orion Hodson2e599942017-09-22 16:17:41 +0100918 case Instruction::kIndexMethodHandleRef:
919 // Method handle information is too large to detail in disassembly so just output the index.
920 outSize = snprintf(buf.get(), bufSize, "method_handle@%0*x", width, index);
921 break;
922 case Instruction::kIndexProtoRef:
923 if (index < pDexFile->GetHeader().proto_ids_size_) {
924 const DexFile::ProtoId& protoId = pDexFile->GetProtoId(index);
925 const Signature signature = pDexFile->GetProtoSignature(protoId);
926 const std::string& proto = signature.ToString();
927 outSize = snprintf(buf.get(), bufSize, "%s // proto@%0*x", proto.c_str(), width, index);
928 } else {
929 outSize = snprintf(buf.get(), bufSize, "<?> // proto@%0*x", width, index);
930 }
Aart Bik69ae54a2015-07-01 14:52:26 -0700931 break;
932 } // switch
933
Orion Hodson2e599942017-09-22 16:17:41 +0100934 if (outSize == 0) {
935 // The index type has not been handled in the switch above.
936 outSize = snprintf(buf.get(), bufSize, "<?>");
937 }
938
Aart Bik69ae54a2015-07-01 14:52:26 -0700939 // Determine success of string construction.
940 if (outSize >= bufSize) {
Aart Bika0e33fd2016-07-08 18:32:45 -0700941 // The buffer wasn't big enough; retry with computed size. Note: snprintf()
942 // doesn't count/ the '\0' as part of its returned size, so we add explicit
943 // space for it here.
944 return indexString(pDexFile, pDecInsn, outSize + 1);
Aart Bik69ae54a2015-07-01 14:52:26 -0700945 }
946 return buf;
947}
948
949/*
950 * Dumps a single instruction.
951 */
952static void dumpInstruction(const DexFile* pDexFile,
953 const DexFile::CodeItem* pCode,
954 u4 codeOffset, u4 insnIdx, u4 insnWidth,
955 const Instruction* pDecInsn) {
956 // Address of instruction (expressed as byte offset).
957 fprintf(gOutFile, "%06x:", codeOffset + 0x10 + insnIdx * 2);
958
959 // Dump (part of) raw bytes.
Mathieu Chartier698ebbc2018-01-05 11:00:42 -0800960 CodeItemInstructionAccessor accessor(*pDexFile, pCode);
Aart Bik69ae54a2015-07-01 14:52:26 -0700961 for (u4 i = 0; i < 8; i++) {
962 if (i < insnWidth) {
963 if (i == 7) {
964 fprintf(gOutFile, " ... ");
965 } else {
966 // Print 16-bit value in little-endian order.
Mathieu Chartier641a3af2017-12-15 11:42:58 -0800967 const u1* bytePtr = (const u1*) &accessor.Insns()[insnIdx + i];
Aart Bik69ae54a2015-07-01 14:52:26 -0700968 fprintf(gOutFile, " %02x%02x", bytePtr[0], bytePtr[1]);
969 }
970 } else {
971 fputs(" ", gOutFile);
972 }
973 } // for
974
975 // Dump pseudo-instruction or opcode.
976 if (pDecInsn->Opcode() == Instruction::NOP) {
Mathieu Chartier641a3af2017-12-15 11:42:58 -0800977 const u2 instr = get2LE((const u1*) &accessor.Insns()[insnIdx]);
Aart Bik69ae54a2015-07-01 14:52:26 -0700978 if (instr == Instruction::kPackedSwitchSignature) {
979 fprintf(gOutFile, "|%04x: packed-switch-data (%d units)", insnIdx, insnWidth);
980 } else if (instr == Instruction::kSparseSwitchSignature) {
981 fprintf(gOutFile, "|%04x: sparse-switch-data (%d units)", insnIdx, insnWidth);
982 } else if (instr == Instruction::kArrayDataSignature) {
983 fprintf(gOutFile, "|%04x: array-data (%d units)", insnIdx, insnWidth);
984 } else {
985 fprintf(gOutFile, "|%04x: nop // spacer", insnIdx);
986 }
987 } else {
988 fprintf(gOutFile, "|%04x: %s", insnIdx, pDecInsn->Name());
989 }
990
991 // Set up additional argument.
Aart Bika0e33fd2016-07-08 18:32:45 -0700992 std::unique_ptr<char[]> indexBuf;
Aart Bik69ae54a2015-07-01 14:52:26 -0700993 if (Instruction::IndexTypeOf(pDecInsn->Opcode()) != Instruction::kIndexNone) {
Aart Bika0e33fd2016-07-08 18:32:45 -0700994 indexBuf = indexString(pDexFile, pDecInsn, 200);
Aart Bik69ae54a2015-07-01 14:52:26 -0700995 }
996
997 // Dump the instruction.
998 //
999 // NOTE: pDecInsn->DumpString(pDexFile) differs too much from original.
1000 //
1001 switch (Instruction::FormatOf(pDecInsn->Opcode())) {
1002 case Instruction::k10x: // op
1003 break;
1004 case Instruction::k12x: // op vA, vB
1005 fprintf(gOutFile, " v%d, v%d", pDecInsn->VRegA(), pDecInsn->VRegB());
1006 break;
1007 case Instruction::k11n: // op vA, #+B
1008 fprintf(gOutFile, " v%d, #int %d // #%x",
1009 pDecInsn->VRegA(), (s4) pDecInsn->VRegB(), (u1)pDecInsn->VRegB());
1010 break;
1011 case Instruction::k11x: // op vAA
1012 fprintf(gOutFile, " v%d", pDecInsn->VRegA());
1013 break;
1014 case Instruction::k10t: // op +AA
Aart Bikdce50862016-06-10 16:04:03 -07001015 case Instruction::k20t: { // op +AAAA
1016 const s4 targ = (s4) pDecInsn->VRegA();
1017 fprintf(gOutFile, " %04x // %c%04x",
1018 insnIdx + targ,
1019 (targ < 0) ? '-' : '+',
1020 (targ < 0) ? -targ : targ);
Aart Bik69ae54a2015-07-01 14:52:26 -07001021 break;
Aart Bikdce50862016-06-10 16:04:03 -07001022 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001023 case Instruction::k22x: // op vAA, vBBBB
1024 fprintf(gOutFile, " v%d, v%d", pDecInsn->VRegA(), pDecInsn->VRegB());
1025 break;
Aart Bikdce50862016-06-10 16:04:03 -07001026 case Instruction::k21t: { // op vAA, +BBBB
1027 const s4 targ = (s4) pDecInsn->VRegB();
1028 fprintf(gOutFile, " v%d, %04x // %c%04x", pDecInsn->VRegA(),
1029 insnIdx + targ,
1030 (targ < 0) ? '-' : '+',
1031 (targ < 0) ? -targ : targ);
Aart Bik69ae54a2015-07-01 14:52:26 -07001032 break;
Aart Bikdce50862016-06-10 16:04:03 -07001033 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001034 case Instruction::k21s: // op vAA, #+BBBB
1035 fprintf(gOutFile, " v%d, #int %d // #%x",
1036 pDecInsn->VRegA(), (s4) pDecInsn->VRegB(), (u2)pDecInsn->VRegB());
1037 break;
1038 case Instruction::k21h: // op vAA, #+BBBB0000[00000000]
1039 // The printed format varies a bit based on the actual opcode.
1040 if (pDecInsn->Opcode() == Instruction::CONST_HIGH16) {
1041 const s4 value = pDecInsn->VRegB() << 16;
1042 fprintf(gOutFile, " v%d, #int %d // #%x",
1043 pDecInsn->VRegA(), value, (u2) pDecInsn->VRegB());
1044 } else {
1045 const s8 value = ((s8) pDecInsn->VRegB()) << 48;
1046 fprintf(gOutFile, " v%d, #long %" PRId64 " // #%x",
1047 pDecInsn->VRegA(), value, (u2) pDecInsn->VRegB());
1048 }
1049 break;
1050 case Instruction::k21c: // op vAA, thing@BBBB
1051 case Instruction::k31c: // op vAA, thing@BBBBBBBB
Aart Bika0e33fd2016-07-08 18:32:45 -07001052 fprintf(gOutFile, " v%d, %s", pDecInsn->VRegA(), indexBuf.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001053 break;
1054 case Instruction::k23x: // op vAA, vBB, vCC
1055 fprintf(gOutFile, " v%d, v%d, v%d",
1056 pDecInsn->VRegA(), pDecInsn->VRegB(), pDecInsn->VRegC());
1057 break;
1058 case Instruction::k22b: // op vAA, vBB, #+CC
1059 fprintf(gOutFile, " v%d, v%d, #int %d // #%02x",
1060 pDecInsn->VRegA(), pDecInsn->VRegB(),
1061 (s4) pDecInsn->VRegC(), (u1) pDecInsn->VRegC());
1062 break;
Aart Bikdce50862016-06-10 16:04:03 -07001063 case Instruction::k22t: { // op vA, vB, +CCCC
1064 const s4 targ = (s4) pDecInsn->VRegC();
1065 fprintf(gOutFile, " v%d, v%d, %04x // %c%04x",
1066 pDecInsn->VRegA(), pDecInsn->VRegB(),
1067 insnIdx + targ,
1068 (targ < 0) ? '-' : '+',
1069 (targ < 0) ? -targ : targ);
Aart Bik69ae54a2015-07-01 14:52:26 -07001070 break;
Aart Bikdce50862016-06-10 16:04:03 -07001071 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001072 case Instruction::k22s: // op vA, vB, #+CCCC
1073 fprintf(gOutFile, " v%d, v%d, #int %d // #%04x",
1074 pDecInsn->VRegA(), pDecInsn->VRegB(),
1075 (s4) pDecInsn->VRegC(), (u2) pDecInsn->VRegC());
1076 break;
1077 case Instruction::k22c: // op vA, vB, thing@CCCC
1078 // NOT SUPPORTED:
1079 // case Instruction::k22cs: // [opt] op vA, vB, field offset CCCC
1080 fprintf(gOutFile, " v%d, v%d, %s",
Aart Bika0e33fd2016-07-08 18:32:45 -07001081 pDecInsn->VRegA(), pDecInsn->VRegB(), indexBuf.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001082 break;
1083 case Instruction::k30t:
1084 fprintf(gOutFile, " #%08x", pDecInsn->VRegA());
1085 break;
Aart Bikdce50862016-06-10 16:04:03 -07001086 case Instruction::k31i: { // op vAA, #+BBBBBBBB
1087 // This is often, but not always, a float.
1088 union {
1089 float f;
1090 u4 i;
1091 } conv;
1092 conv.i = pDecInsn->VRegB();
1093 fprintf(gOutFile, " v%d, #float %g // #%08x",
1094 pDecInsn->VRegA(), conv.f, pDecInsn->VRegB());
Aart Bik69ae54a2015-07-01 14:52:26 -07001095 break;
Aart Bikdce50862016-06-10 16:04:03 -07001096 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001097 case Instruction::k31t: // op vAA, offset +BBBBBBBB
1098 fprintf(gOutFile, " v%d, %08x // +%08x",
1099 pDecInsn->VRegA(), insnIdx + pDecInsn->VRegB(), pDecInsn->VRegB());
1100 break;
1101 case Instruction::k32x: // op vAAAA, vBBBB
1102 fprintf(gOutFile, " v%d, v%d", pDecInsn->VRegA(), pDecInsn->VRegB());
1103 break;
Orion Hodsonb34bb192016-10-18 17:02:58 +01001104 case Instruction::k35c: // op {vC, vD, vE, vF, vG}, thing@BBBB
1105 case Instruction::k45cc: { // op {vC, vD, vE, vF, vG}, method@BBBB, proto@HHHH
Aart Bik69ae54a2015-07-01 14:52:26 -07001106 // NOT SUPPORTED:
1107 // case Instruction::k35ms: // [opt] invoke-virtual+super
1108 // case Instruction::k35mi: // [opt] inline invoke
Aart Bikdce50862016-06-10 16:04:03 -07001109 u4 arg[Instruction::kMaxVarArgRegs];
1110 pDecInsn->GetVarArgs(arg);
1111 fputs(" {", gOutFile);
1112 for (int i = 0, n = pDecInsn->VRegA(); i < n; i++) {
1113 if (i == 0) {
1114 fprintf(gOutFile, "v%d", arg[i]);
1115 } else {
1116 fprintf(gOutFile, ", v%d", arg[i]);
1117 }
1118 } // for
Aart Bika0e33fd2016-07-08 18:32:45 -07001119 fprintf(gOutFile, "}, %s", indexBuf.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001120 break;
Aart Bikdce50862016-06-10 16:04:03 -07001121 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001122 case Instruction::k3rc: // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB
Orion Hodsonb34bb192016-10-18 17:02:58 +01001123 case Instruction::k4rcc: { // op {vCCCC .. v(CCCC+AA-1)}, method@BBBB, proto@HHHH
Aart Bik69ae54a2015-07-01 14:52:26 -07001124 // NOT SUPPORTED:
1125 // case Instruction::k3rms: // [opt] invoke-virtual+super/range
1126 // case Instruction::k3rmi: // [opt] execute-inline/range
Aart Bik69ae54a2015-07-01 14:52:26 -07001127 // This doesn't match the "dx" output when some of the args are
1128 // 64-bit values -- dx only shows the first register.
1129 fputs(" {", gOutFile);
1130 for (int i = 0, n = pDecInsn->VRegA(); i < n; i++) {
1131 if (i == 0) {
1132 fprintf(gOutFile, "v%d", pDecInsn->VRegC() + i);
1133 } else {
1134 fprintf(gOutFile, ", v%d", pDecInsn->VRegC() + i);
1135 }
1136 } // for
Aart Bika0e33fd2016-07-08 18:32:45 -07001137 fprintf(gOutFile, "}, %s", indexBuf.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001138 }
1139 break;
Aart Bikdce50862016-06-10 16:04:03 -07001140 case Instruction::k51l: { // op vAA, #+BBBBBBBBBBBBBBBB
1141 // This is often, but not always, a double.
1142 union {
1143 double d;
1144 u8 j;
1145 } conv;
1146 conv.j = pDecInsn->WideVRegB();
1147 fprintf(gOutFile, " v%d, #double %g // #%016" PRIx64,
1148 pDecInsn->VRegA(), conv.d, pDecInsn->WideVRegB());
Aart Bik69ae54a2015-07-01 14:52:26 -07001149 break;
Aart Bikdce50862016-06-10 16:04:03 -07001150 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001151 // NOT SUPPORTED:
1152 // case Instruction::k00x: // unknown op or breakpoint
1153 // break;
1154 default:
1155 fprintf(gOutFile, " ???");
1156 break;
1157 } // switch
1158
1159 fputc('\n', gOutFile);
Aart Bik69ae54a2015-07-01 14:52:26 -07001160}
1161
1162/*
1163 * Dumps a bytecode disassembly.
1164 */
1165static void dumpBytecodes(const DexFile* pDexFile, u4 idx,
1166 const DexFile::CodeItem* pCode, u4 codeOffset) {
1167 const DexFile::MethodId& pMethodId = pDexFile->GetMethodId(idx);
1168 const char* name = pDexFile->StringDataByIdx(pMethodId.name_idx_);
1169 const Signature signature = pDexFile->GetMethodSignature(pMethodId);
1170 const char* backDescriptor = pDexFile->StringByTypeIdx(pMethodId.class_idx_);
1171
1172 // Generate header.
Aart Bikc05e2f22016-07-12 15:53:13 -07001173 std::unique_ptr<char[]> dot(descriptorToDot(backDescriptor));
1174 fprintf(gOutFile, "%06x: |[%06x] %s.%s:%s\n",
1175 codeOffset, codeOffset, dot.get(), name, signature.ToString().c_str());
Aart Bik69ae54a2015-07-01 14:52:26 -07001176
1177 // Iterate over all instructions.
Mathieu Chartier698ebbc2018-01-05 11:00:42 -08001178 CodeItemDataAccessor accessor(*pDexFile, pCode);
Aart Bik7a9aaf12018-02-05 17:00:40 -08001179 const u4 maxPc = accessor.InsnsSizeInCodeUnits();
Mathieu Chartier641a3af2017-12-15 11:42:58 -08001180 for (const DexInstructionPcPair& pair : accessor) {
Aart Bik7a9aaf12018-02-05 17:00:40 -08001181 const u4 dexPc = pair.DexPc();
1182 if (dexPc >= maxPc) {
1183 LOG(WARNING) << "GLITCH: run-away instruction at idx=0x" << std::hex << dexPc;
1184 break;
1185 }
Mathieu Chartier641a3af2017-12-15 11:42:58 -08001186 const Instruction* instruction = &pair.Inst();
Aart Bik69ae54a2015-07-01 14:52:26 -07001187 const u4 insnWidth = instruction->SizeInCodeUnits();
1188 if (insnWidth == 0) {
Aart Bik7a9aaf12018-02-05 17:00:40 -08001189 LOG(WARNING) << "GLITCH: zero-width instruction at idx=0x" << std::hex << dexPc;
Aart Bik69ae54a2015-07-01 14:52:26 -07001190 break;
1191 }
Aart Bik7a9aaf12018-02-05 17:00:40 -08001192 dumpInstruction(pDexFile, pCode, codeOffset, dexPc, insnWidth, instruction);
Aart Bik69ae54a2015-07-01 14:52:26 -07001193 } // for
1194}
1195
1196/*
1197 * Dumps code of a method.
1198 */
1199static void dumpCode(const DexFile* pDexFile, u4 idx, u4 flags,
1200 const DexFile::CodeItem* pCode, u4 codeOffset) {
Mathieu Chartier8892c6b2018-01-09 15:10:17 -08001201 CodeItemDebugInfoAccessor accessor(*pDexFile, pCode, idx);
Mathieu Chartier641a3af2017-12-15 11:42:58 -08001202
1203 fprintf(gOutFile, " registers : %d\n", accessor.RegistersSize());
1204 fprintf(gOutFile, " ins : %d\n", accessor.InsSize());
1205 fprintf(gOutFile, " outs : %d\n", accessor.OutsSize());
Aart Bik69ae54a2015-07-01 14:52:26 -07001206 fprintf(gOutFile, " insns size : %d 16-bit code units\n",
Mathieu Chartier641a3af2017-12-15 11:42:58 -08001207 accessor.InsnsSizeInCodeUnits());
Aart Bik69ae54a2015-07-01 14:52:26 -07001208
1209 // Bytecode disassembly, if requested.
1210 if (gOptions.disassemble) {
1211 dumpBytecodes(pDexFile, idx, pCode, codeOffset);
1212 }
1213
1214 // Try-catch blocks.
1215 dumpCatches(pDexFile, pCode);
1216
1217 // Positions and locals table in the debug info.
1218 bool is_static = (flags & kAccStatic) != 0;
1219 fprintf(gOutFile, " positions : \n");
Mathieu Chartier641a3af2017-12-15 11:42:58 -08001220 pDexFile->DecodeDebugPositionInfo(accessor.DebugInfoOffset(), dumpPositionsCb, nullptr);
Aart Bik69ae54a2015-07-01 14:52:26 -07001221 fprintf(gOutFile, " locals : \n");
Mathieu Chartier641a3af2017-12-15 11:42:58 -08001222 accessor.DecodeDebugLocalInfo(is_static, idx, dumpLocalsCb, nullptr);
Aart Bik69ae54a2015-07-01 14:52:26 -07001223}
1224
1225/*
1226 * Dumps a method.
1227 */
1228static void dumpMethod(const DexFile* pDexFile, u4 idx, u4 flags,
1229 const DexFile::CodeItem* pCode, u4 codeOffset, int i) {
1230 // Bail for anything private if export only requested.
1231 if (gOptions.exportsOnly && (flags & (kAccPublic | kAccProtected)) == 0) {
1232 return;
1233 }
1234
1235 const DexFile::MethodId& pMethodId = pDexFile->GetMethodId(idx);
1236 const char* name = pDexFile->StringDataByIdx(pMethodId.name_idx_);
1237 const Signature signature = pDexFile->GetMethodSignature(pMethodId);
1238 char* typeDescriptor = strdup(signature.ToString().c_str());
1239 const char* backDescriptor = pDexFile->StringByTypeIdx(pMethodId.class_idx_);
1240 char* accessStr = createAccessFlagStr(flags, kAccessForMethod);
1241
1242 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1243 fprintf(gOutFile, " #%d : (in %s)\n", i, backDescriptor);
1244 fprintf(gOutFile, " name : '%s'\n", name);
1245 fprintf(gOutFile, " type : '%s'\n", typeDescriptor);
1246 fprintf(gOutFile, " access : 0x%04x (%s)\n", flags, accessStr);
1247 if (pCode == nullptr) {
1248 fprintf(gOutFile, " code : (none)\n");
1249 } else {
1250 fprintf(gOutFile, " code -\n");
1251 dumpCode(pDexFile, idx, flags, pCode, codeOffset);
1252 }
1253 if (gOptions.disassemble) {
1254 fputc('\n', gOutFile);
1255 }
1256 } else if (gOptions.outputFormat == OUTPUT_XML) {
1257 const bool constructor = (name[0] == '<');
1258
1259 // Method name and prototype.
1260 if (constructor) {
Aart Bikc05e2f22016-07-12 15:53:13 -07001261 std::unique_ptr<char[]> dot(descriptorClassToDot(backDescriptor));
1262 fprintf(gOutFile, "<constructor name=\"%s\"\n", dot.get());
1263 dot = descriptorToDot(backDescriptor);
1264 fprintf(gOutFile, " type=\"%s\"\n", dot.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001265 } else {
1266 fprintf(gOutFile, "<method name=\"%s\"\n", name);
1267 const char* returnType = strrchr(typeDescriptor, ')');
1268 if (returnType == nullptr) {
Andreas Gampe221d9812018-01-22 17:48:56 -08001269 LOG(ERROR) << "bad method type descriptor '" << typeDescriptor << "'";
Aart Bik69ae54a2015-07-01 14:52:26 -07001270 goto bail;
1271 }
Aart Bikc05e2f22016-07-12 15:53:13 -07001272 std::unique_ptr<char[]> dot(descriptorToDot(returnType + 1));
1273 fprintf(gOutFile, " return=\"%s\"\n", dot.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001274 fprintf(gOutFile, " abstract=%s\n", quotedBool((flags & kAccAbstract) != 0));
1275 fprintf(gOutFile, " native=%s\n", quotedBool((flags & kAccNative) != 0));
1276 fprintf(gOutFile, " synchronized=%s\n", quotedBool(
1277 (flags & (kAccSynchronized | kAccDeclaredSynchronized)) != 0));
1278 }
1279
1280 // Additional method flags.
1281 fprintf(gOutFile, " static=%s\n", quotedBool((flags & kAccStatic) != 0));
1282 fprintf(gOutFile, " final=%s\n", quotedBool((flags & kAccFinal) != 0));
1283 // The "deprecated=" not knowable w/o parsing annotations.
1284 fprintf(gOutFile, " visibility=%s\n>\n", quotedVisibility(flags));
1285
1286 // Parameters.
1287 if (typeDescriptor[0] != '(') {
Andreas Gampe221d9812018-01-22 17:48:56 -08001288 LOG(ERROR) << "ERROR: bad descriptor '" << typeDescriptor << "'";
Aart Bik69ae54a2015-07-01 14:52:26 -07001289 goto bail;
1290 }
1291 char* tmpBuf = reinterpret_cast<char*>(malloc(strlen(typeDescriptor) + 1));
1292 const char* base = typeDescriptor + 1;
1293 int argNum = 0;
1294 while (*base != ')') {
1295 char* cp = tmpBuf;
1296 while (*base == '[') {
1297 *cp++ = *base++;
1298 }
1299 if (*base == 'L') {
1300 // Copy through ';'.
1301 do {
1302 *cp = *base++;
1303 } while (*cp++ != ';');
1304 } else {
1305 // Primitive char, copy it.
Aart Bikc05e2f22016-07-12 15:53:13 -07001306 if (strchr("ZBCSIFJD", *base) == nullptr) {
Andreas Gampe221d9812018-01-22 17:48:56 -08001307 LOG(ERROR) << "ERROR: bad method signature '" << base << "'";
Aart Bika0e33fd2016-07-08 18:32:45 -07001308 break; // while
Aart Bik69ae54a2015-07-01 14:52:26 -07001309 }
1310 *cp++ = *base++;
1311 }
1312 // Null terminate and display.
1313 *cp++ = '\0';
Aart Bikc05e2f22016-07-12 15:53:13 -07001314 std::unique_ptr<char[]> dot(descriptorToDot(tmpBuf));
Aart Bik69ae54a2015-07-01 14:52:26 -07001315 fprintf(gOutFile, "<parameter name=\"arg%d\" type=\"%s\">\n"
Aart Bikc05e2f22016-07-12 15:53:13 -07001316 "</parameter>\n", argNum++, dot.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001317 } // while
1318 free(tmpBuf);
1319 if (constructor) {
1320 fprintf(gOutFile, "</constructor>\n");
1321 } else {
1322 fprintf(gOutFile, "</method>\n");
1323 }
1324 }
1325
1326 bail:
1327 free(typeDescriptor);
1328 free(accessStr);
1329}
1330
1331/*
1332 * Dumps a static (class) field.
1333 */
Aart Bikdce50862016-06-10 16:04:03 -07001334static void dumpSField(const DexFile* pDexFile, u4 idx, u4 flags, int i, const u1** data) {
Aart Bik69ae54a2015-07-01 14:52:26 -07001335 // Bail for anything private if export only requested.
1336 if (gOptions.exportsOnly && (flags & (kAccPublic | kAccProtected)) == 0) {
1337 return;
1338 }
1339
1340 const DexFile::FieldId& pFieldId = pDexFile->GetFieldId(idx);
1341 const char* name = pDexFile->StringDataByIdx(pFieldId.name_idx_);
1342 const char* typeDescriptor = pDexFile->StringByTypeIdx(pFieldId.type_idx_);
1343 const char* backDescriptor = pDexFile->StringByTypeIdx(pFieldId.class_idx_);
1344 char* accessStr = createAccessFlagStr(flags, kAccessForField);
1345
1346 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1347 fprintf(gOutFile, " #%d : (in %s)\n", i, backDescriptor);
1348 fprintf(gOutFile, " name : '%s'\n", name);
1349 fprintf(gOutFile, " type : '%s'\n", typeDescriptor);
1350 fprintf(gOutFile, " access : 0x%04x (%s)\n", flags, accessStr);
Aart Bikdce50862016-06-10 16:04:03 -07001351 if (data != nullptr) {
Shinichiro Hamaji82863f02015-11-05 16:51:33 +09001352 fputs(" value : ", gOutFile);
Aart Bikdce50862016-06-10 16:04:03 -07001353 dumpEncodedValue(pDexFile, data);
Shinichiro Hamaji82863f02015-11-05 16:51:33 +09001354 fputs("\n", gOutFile);
1355 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001356 } else if (gOptions.outputFormat == OUTPUT_XML) {
1357 fprintf(gOutFile, "<field name=\"%s\"\n", name);
Aart Bikc05e2f22016-07-12 15:53:13 -07001358 std::unique_ptr<char[]> dot(descriptorToDot(typeDescriptor));
1359 fprintf(gOutFile, " type=\"%s\"\n", dot.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001360 fprintf(gOutFile, " transient=%s\n", quotedBool((flags & kAccTransient) != 0));
1361 fprintf(gOutFile, " volatile=%s\n", quotedBool((flags & kAccVolatile) != 0));
1362 // The "value=" is not knowable w/o parsing annotations.
1363 fprintf(gOutFile, " static=%s\n", quotedBool((flags & kAccStatic) != 0));
1364 fprintf(gOutFile, " final=%s\n", quotedBool((flags & kAccFinal) != 0));
1365 // The "deprecated=" is not knowable w/o parsing annotations.
1366 fprintf(gOutFile, " visibility=%s\n", quotedVisibility(flags));
Aart Bikdce50862016-06-10 16:04:03 -07001367 if (data != nullptr) {
Shinichiro Hamaji82863f02015-11-05 16:51:33 +09001368 fputs(" value=\"", gOutFile);
Aart Bikdce50862016-06-10 16:04:03 -07001369 dumpEncodedValue(pDexFile, data);
Shinichiro Hamaji82863f02015-11-05 16:51:33 +09001370 fputs("\"\n", gOutFile);
1371 }
1372 fputs(">\n</field>\n", gOutFile);
Aart Bik69ae54a2015-07-01 14:52:26 -07001373 }
1374
1375 free(accessStr);
1376}
1377
1378/*
1379 * Dumps an instance field.
1380 */
1381static void dumpIField(const DexFile* pDexFile, u4 idx, u4 flags, int i) {
Aart Bikdce50862016-06-10 16:04:03 -07001382 dumpSField(pDexFile, idx, flags, i, nullptr);
Aart Bik69ae54a2015-07-01 14:52:26 -07001383}
1384
1385/*
Andreas Gampe5073fed2015-08-10 11:40:25 -07001386 * Dumping a CFG. Note that this will do duplicate work. utils.h doesn't expose the code-item
1387 * version, so the DumpMethodCFG code will have to iterate again to find it. But dexdump is a
1388 * tool, so this is not performance-critical.
1389 */
1390
1391static void dumpCfg(const DexFile* dex_file,
Aart Bikdce50862016-06-10 16:04:03 -07001392 u4 dex_method_idx,
Andreas Gampe5073fed2015-08-10 11:40:25 -07001393 const DexFile::CodeItem* code_item) {
1394 if (code_item != nullptr) {
1395 std::ostringstream oss;
1396 DumpMethodCFG(dex_file, dex_method_idx, oss);
David Sehrcaacd112016-10-20 16:27:02 -07001397 fputs(oss.str().c_str(), gOutFile);
Andreas Gampe5073fed2015-08-10 11:40:25 -07001398 }
1399}
1400
1401static void dumpCfg(const DexFile* dex_file, int idx) {
1402 const DexFile::ClassDef& class_def = dex_file->GetClassDef(idx);
Aart Bikdce50862016-06-10 16:04:03 -07001403 const u1* class_data = dex_file->GetClassData(class_def);
Andreas Gampe5073fed2015-08-10 11:40:25 -07001404 if (class_data == nullptr) { // empty class such as a marker interface?
1405 return;
1406 }
1407 ClassDataItemIterator it(*dex_file, class_data);
Mathieu Chartiere17cf242017-06-19 11:05:51 -07001408 it.SkipAllFields();
Mathieu Chartierb7c273c2017-11-10 18:07:56 -08001409 while (it.HasNextMethod()) {
Andreas Gampe5073fed2015-08-10 11:40:25 -07001410 dumpCfg(dex_file,
1411 it.GetMemberIndex(),
1412 it.GetMethodCodeItem());
1413 it.Next();
1414 }
Andreas Gampe5073fed2015-08-10 11:40:25 -07001415}
1416
1417/*
Aart Bik69ae54a2015-07-01 14:52:26 -07001418 * Dumps the class.
1419 *
1420 * Note "idx" is a DexClassDef index, not a DexTypeId index.
1421 *
1422 * If "*pLastPackage" is nullptr or does not match the current class' package,
1423 * the value will be replaced with a newly-allocated string.
1424 */
1425static void dumpClass(const DexFile* pDexFile, int idx, char** pLastPackage) {
1426 const DexFile::ClassDef& pClassDef = pDexFile->GetClassDef(idx);
1427
1428 // Omitting non-public class.
1429 if (gOptions.exportsOnly && (pClassDef.access_flags_ & kAccPublic) == 0) {
1430 return;
1431 }
1432
Aart Bikdce50862016-06-10 16:04:03 -07001433 if (gOptions.showSectionHeaders) {
1434 dumpClassDef(pDexFile, idx);
1435 }
1436
1437 if (gOptions.showAnnotations) {
1438 dumpClassAnnotations(pDexFile, idx);
1439 }
1440
1441 if (gOptions.showCfg) {
Andreas Gampe5073fed2015-08-10 11:40:25 -07001442 dumpCfg(pDexFile, idx);
1443 return;
1444 }
1445
Aart Bik69ae54a2015-07-01 14:52:26 -07001446 // For the XML output, show the package name. Ideally we'd gather
1447 // up the classes, sort them, and dump them alphabetically so the
1448 // package name wouldn't jump around, but that's not a great plan
1449 // for something that needs to run on the device.
1450 const char* classDescriptor = pDexFile->StringByTypeIdx(pClassDef.class_idx_);
1451 if (!(classDescriptor[0] == 'L' &&
1452 classDescriptor[strlen(classDescriptor)-1] == ';')) {
1453 // Arrays and primitives should not be defined explicitly. Keep going?
Andreas Gampe221d9812018-01-22 17:48:56 -08001454 LOG(WARNING) << "Malformed class name '" << classDescriptor << "'";
Aart Bik69ae54a2015-07-01 14:52:26 -07001455 } else if (gOptions.outputFormat == OUTPUT_XML) {
1456 char* mangle = strdup(classDescriptor + 1);
1457 mangle[strlen(mangle)-1] = '\0';
1458
1459 // Reduce to just the package name.
1460 char* lastSlash = strrchr(mangle, '/');
1461 if (lastSlash != nullptr) {
1462 *lastSlash = '\0';
1463 } else {
1464 *mangle = '\0';
1465 }
1466
1467 for (char* cp = mangle; *cp != '\0'; cp++) {
1468 if (*cp == '/') {
1469 *cp = '.';
1470 }
1471 } // for
1472
1473 if (*pLastPackage == nullptr || strcmp(mangle, *pLastPackage) != 0) {
1474 // Start of a new package.
1475 if (*pLastPackage != nullptr) {
1476 fprintf(gOutFile, "</package>\n");
1477 }
1478 fprintf(gOutFile, "<package name=\"%s\"\n>\n", mangle);
1479 free(*pLastPackage);
1480 *pLastPackage = mangle;
1481 } else {
1482 free(mangle);
1483 }
1484 }
1485
1486 // General class information.
1487 char* accessStr = createAccessFlagStr(pClassDef.access_flags_, kAccessForClass);
1488 const char* superclassDescriptor;
Andreas Gampea5b09a62016-11-17 15:21:22 -08001489 if (!pClassDef.superclass_idx_.IsValid()) {
Aart Bik69ae54a2015-07-01 14:52:26 -07001490 superclassDescriptor = nullptr;
1491 } else {
1492 superclassDescriptor = pDexFile->StringByTypeIdx(pClassDef.superclass_idx_);
1493 }
1494 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1495 fprintf(gOutFile, "Class #%d -\n", idx);
1496 fprintf(gOutFile, " Class descriptor : '%s'\n", classDescriptor);
1497 fprintf(gOutFile, " Access flags : 0x%04x (%s)\n", pClassDef.access_flags_, accessStr);
1498 if (superclassDescriptor != nullptr) {
1499 fprintf(gOutFile, " Superclass : '%s'\n", superclassDescriptor);
1500 }
1501 fprintf(gOutFile, " Interfaces -\n");
1502 } else {
Aart Bikc05e2f22016-07-12 15:53:13 -07001503 std::unique_ptr<char[]> dot(descriptorClassToDot(classDescriptor));
1504 fprintf(gOutFile, "<class name=\"%s\"\n", dot.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001505 if (superclassDescriptor != nullptr) {
Aart Bikc05e2f22016-07-12 15:53:13 -07001506 dot = descriptorToDot(superclassDescriptor);
1507 fprintf(gOutFile, " extends=\"%s\"\n", dot.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001508 }
Alex Light1f12e282015-12-10 16:49:47 -08001509 fprintf(gOutFile, " interface=%s\n",
1510 quotedBool((pClassDef.access_flags_ & kAccInterface) != 0));
Aart Bik69ae54a2015-07-01 14:52:26 -07001511 fprintf(gOutFile, " abstract=%s\n", quotedBool((pClassDef.access_flags_ & kAccAbstract) != 0));
1512 fprintf(gOutFile, " static=%s\n", quotedBool((pClassDef.access_flags_ & kAccStatic) != 0));
1513 fprintf(gOutFile, " final=%s\n", quotedBool((pClassDef.access_flags_ & kAccFinal) != 0));
1514 // The "deprecated=" not knowable w/o parsing annotations.
1515 fprintf(gOutFile, " visibility=%s\n", quotedVisibility(pClassDef.access_flags_));
1516 fprintf(gOutFile, ">\n");
1517 }
1518
1519 // Interfaces.
1520 const DexFile::TypeList* pInterfaces = pDexFile->GetInterfacesList(pClassDef);
1521 if (pInterfaces != nullptr) {
1522 for (u4 i = 0; i < pInterfaces->Size(); i++) {
1523 dumpInterface(pDexFile, pInterfaces->GetTypeItem(i), i);
1524 } // for
1525 }
1526
1527 // Fields and methods.
1528 const u1* pEncodedData = pDexFile->GetClassData(pClassDef);
1529 if (pEncodedData == nullptr) {
1530 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1531 fprintf(gOutFile, " Static fields -\n");
1532 fprintf(gOutFile, " Instance fields -\n");
1533 fprintf(gOutFile, " Direct methods -\n");
1534 fprintf(gOutFile, " Virtual methods -\n");
1535 }
1536 } else {
1537 ClassDataItemIterator pClassData(*pDexFile, pEncodedData);
Aart Bikdce50862016-06-10 16:04:03 -07001538
1539 // Prepare data for static fields.
1540 const u1* sData = pDexFile->GetEncodedStaticFieldValuesArray(pClassDef);
1541 const u4 sSize = sData != nullptr ? DecodeUnsignedLeb128(&sData) : 0;
1542
1543 // Static fields.
Aart Bik69ae54a2015-07-01 14:52:26 -07001544 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1545 fprintf(gOutFile, " Static fields -\n");
1546 }
Aart Bikdce50862016-06-10 16:04:03 -07001547 for (u4 i = 0; pClassData.HasNextStaticField(); i++, pClassData.Next()) {
1548 dumpSField(pDexFile,
1549 pClassData.GetMemberIndex(),
1550 pClassData.GetRawMemberAccessFlags(),
1551 i,
1552 i < sSize ? &sData : nullptr);
Aart Bik69ae54a2015-07-01 14:52:26 -07001553 } // for
Aart Bikdce50862016-06-10 16:04:03 -07001554
1555 // Instance fields.
Aart Bik69ae54a2015-07-01 14:52:26 -07001556 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1557 fprintf(gOutFile, " Instance fields -\n");
1558 }
Aart Bikdce50862016-06-10 16:04:03 -07001559 for (u4 i = 0; pClassData.HasNextInstanceField(); i++, pClassData.Next()) {
1560 dumpIField(pDexFile,
1561 pClassData.GetMemberIndex(),
1562 pClassData.GetRawMemberAccessFlags(),
1563 i);
Aart Bik69ae54a2015-07-01 14:52:26 -07001564 } // for
Aart Bikdce50862016-06-10 16:04:03 -07001565
1566 // Direct methods.
Aart Bik69ae54a2015-07-01 14:52:26 -07001567 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1568 fprintf(gOutFile, " Direct methods -\n");
1569 }
1570 for (int i = 0; pClassData.HasNextDirectMethod(); i++, pClassData.Next()) {
1571 dumpMethod(pDexFile, pClassData.GetMemberIndex(),
1572 pClassData.GetRawMemberAccessFlags(),
1573 pClassData.GetMethodCodeItem(),
1574 pClassData.GetMethodCodeItemOffset(), i);
1575 } // for
Aart Bikdce50862016-06-10 16:04:03 -07001576
1577 // Virtual methods.
Aart Bik69ae54a2015-07-01 14:52:26 -07001578 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1579 fprintf(gOutFile, " Virtual methods -\n");
1580 }
1581 for (int i = 0; pClassData.HasNextVirtualMethod(); i++, pClassData.Next()) {
1582 dumpMethod(pDexFile, pClassData.GetMemberIndex(),
1583 pClassData.GetRawMemberAccessFlags(),
1584 pClassData.GetMethodCodeItem(),
1585 pClassData.GetMethodCodeItemOffset(), i);
1586 } // for
1587 }
1588
1589 // End of class.
1590 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1591 const char* fileName;
Andreas Gampe8a0128a2016-11-28 07:38:35 -08001592 if (pClassDef.source_file_idx_.IsValid()) {
Aart Bik69ae54a2015-07-01 14:52:26 -07001593 fileName = pDexFile->StringDataByIdx(pClassDef.source_file_idx_);
1594 } else {
1595 fileName = "unknown";
1596 }
1597 fprintf(gOutFile, " source_file_idx : %d (%s)\n\n",
Andreas Gampe8a0128a2016-11-28 07:38:35 -08001598 pClassDef.source_file_idx_.index_, fileName);
Aart Bik69ae54a2015-07-01 14:52:26 -07001599 } else if (gOptions.outputFormat == OUTPUT_XML) {
1600 fprintf(gOutFile, "</class>\n");
1601 }
1602
1603 free(accessStr);
1604}
1605
Orion Hodsonc069a302017-01-18 09:23:12 +00001606static void dumpMethodHandle(const DexFile* pDexFile, u4 idx) {
1607 const DexFile::MethodHandleItem& mh = pDexFile->GetMethodHandle(idx);
Orion Hodson631827d2017-04-10 14:53:47 +01001608 const char* type = nullptr;
1609 bool is_instance = false;
Orion Hodsonc069a302017-01-18 09:23:12 +00001610 bool is_invoke = false;
Orion Hodsonc069a302017-01-18 09:23:12 +00001611 switch (static_cast<DexFile::MethodHandleType>(mh.method_handle_type_)) {
1612 case DexFile::MethodHandleType::kStaticPut:
1613 type = "put-static";
Orion Hodson631827d2017-04-10 14:53:47 +01001614 is_instance = false;
1615 is_invoke = false;
Orion Hodsonc069a302017-01-18 09:23:12 +00001616 break;
1617 case DexFile::MethodHandleType::kStaticGet:
1618 type = "get-static";
Orion Hodson631827d2017-04-10 14:53:47 +01001619 is_instance = false;
1620 is_invoke = false;
Orion Hodsonc069a302017-01-18 09:23:12 +00001621 break;
1622 case DexFile::MethodHandleType::kInstancePut:
1623 type = "put-instance";
Orion Hodson631827d2017-04-10 14:53:47 +01001624 is_instance = true;
1625 is_invoke = false;
Orion Hodsonc069a302017-01-18 09:23:12 +00001626 break;
1627 case DexFile::MethodHandleType::kInstanceGet:
1628 type = "get-instance";
Orion Hodson631827d2017-04-10 14:53:47 +01001629 is_instance = true;
1630 is_invoke = false;
Orion Hodsonc069a302017-01-18 09:23:12 +00001631 break;
1632 case DexFile::MethodHandleType::kInvokeStatic:
1633 type = "invoke-static";
Orion Hodson631827d2017-04-10 14:53:47 +01001634 is_instance = false;
Orion Hodsonc069a302017-01-18 09:23:12 +00001635 is_invoke = true;
1636 break;
1637 case DexFile::MethodHandleType::kInvokeInstance:
1638 type = "invoke-instance";
Orion Hodson631827d2017-04-10 14:53:47 +01001639 is_instance = true;
Orion Hodsonc069a302017-01-18 09:23:12 +00001640 is_invoke = true;
1641 break;
1642 case DexFile::MethodHandleType::kInvokeConstructor:
1643 type = "invoke-constructor";
Orion Hodson631827d2017-04-10 14:53:47 +01001644 is_instance = true;
1645 is_invoke = true;
1646 break;
1647 case DexFile::MethodHandleType::kInvokeDirect:
1648 type = "invoke-direct";
1649 is_instance = true;
1650 is_invoke = true;
1651 break;
1652 case DexFile::MethodHandleType::kInvokeInterface:
1653 type = "invoke-interface";
1654 is_instance = true;
Orion Hodsonc069a302017-01-18 09:23:12 +00001655 is_invoke = true;
1656 break;
1657 }
1658
1659 const char* declaring_class;
1660 const char* member;
1661 std::string member_type;
Orion Hodson631827d2017-04-10 14:53:47 +01001662 if (type != nullptr) {
1663 if (is_invoke) {
1664 const DexFile::MethodId& method_id = pDexFile->GetMethodId(mh.field_or_method_idx_);
1665 declaring_class = pDexFile->GetMethodDeclaringClassDescriptor(method_id);
1666 member = pDexFile->GetMethodName(method_id);
1667 member_type = pDexFile->GetMethodSignature(method_id).ToString();
1668 } else {
1669 const DexFile::FieldId& field_id = pDexFile->GetFieldId(mh.field_or_method_idx_);
1670 declaring_class = pDexFile->GetFieldDeclaringClassDescriptor(field_id);
1671 member = pDexFile->GetFieldName(field_id);
1672 member_type = pDexFile->GetFieldTypeDescriptor(field_id);
1673 }
1674 if (is_instance) {
1675 member_type = android::base::StringPrintf("(%s%s", declaring_class, member_type.c_str() + 1);
1676 }
Orion Hodsonc069a302017-01-18 09:23:12 +00001677 } else {
Orion Hodson631827d2017-04-10 14:53:47 +01001678 type = "?";
1679 declaring_class = "?";
1680 member = "?";
1681 member_type = "?";
Orion Hodsonc069a302017-01-18 09:23:12 +00001682 }
1683
1684 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1685 fprintf(gOutFile, "Method handle #%u:\n", idx);
1686 fprintf(gOutFile, " type : %s\n", type);
1687 fprintf(gOutFile, " target : %s %s\n", declaring_class, member);
1688 fprintf(gOutFile, " target_type : %s\n", member_type.c_str());
1689 } else {
1690 fprintf(gOutFile, "<method_handle index=\"%u\"\n", idx);
1691 fprintf(gOutFile, " type=\"%s\"\n", type);
1692 fprintf(gOutFile, " target_class=\"%s\"\n", declaring_class);
1693 fprintf(gOutFile, " target_member=\"%s\"\n", member);
1694 fprintf(gOutFile, " target_member_type=");
1695 dumpEscapedString(member_type.c_str());
1696 fprintf(gOutFile, "\n>\n</method_handle>\n");
1697 }
1698}
1699
1700static void dumpCallSite(const DexFile* pDexFile, u4 idx) {
1701 const DexFile::CallSiteIdItem& call_site_id = pDexFile->GetCallSiteId(idx);
1702 CallSiteArrayValueIterator it(*pDexFile, call_site_id);
1703 if (it.Size() < 3) {
Andreas Gampe221d9812018-01-22 17:48:56 -08001704 LOG(ERROR) << "ERROR: Call site " << idx << " has too few values.";
Orion Hodsonc069a302017-01-18 09:23:12 +00001705 return;
1706 }
1707
1708 uint32_t method_handle_idx = static_cast<uint32_t>(it.GetJavaValue().i);
1709 it.Next();
1710 dex::StringIndex method_name_idx = static_cast<dex::StringIndex>(it.GetJavaValue().i);
1711 const char* method_name = pDexFile->StringDataByIdx(method_name_idx);
1712 it.Next();
1713 uint32_t method_type_idx = static_cast<uint32_t>(it.GetJavaValue().i);
1714 const DexFile::ProtoId& method_type_id = pDexFile->GetProtoId(method_type_idx);
1715 std::string method_type = pDexFile->GetProtoSignature(method_type_id).ToString();
1716 it.Next();
1717
1718 if (gOptions.outputFormat == OUTPUT_PLAIN) {
Orion Hodson775224d2017-07-05 11:04:01 +01001719 fprintf(gOutFile, "Call site #%u: // offset %u\n", idx, call_site_id.data_off_);
Orion Hodsonc069a302017-01-18 09:23:12 +00001720 fprintf(gOutFile, " link_argument[0] : %u (MethodHandle)\n", method_handle_idx);
1721 fprintf(gOutFile, " link_argument[1] : %s (String)\n", method_name);
1722 fprintf(gOutFile, " link_argument[2] : %s (MethodType)\n", method_type.c_str());
1723 } else {
Orion Hodson775224d2017-07-05 11:04:01 +01001724 fprintf(gOutFile, "<call_site index=\"%u\" offset=\"%u\">\n", idx, call_site_id.data_off_);
Orion Hodsonc069a302017-01-18 09:23:12 +00001725 fprintf(gOutFile,
1726 "<link_argument index=\"0\" type=\"MethodHandle\" value=\"%u\"/>\n",
1727 method_handle_idx);
1728 fprintf(gOutFile,
1729 "<link_argument index=\"1\" type=\"String\" values=\"%s\"/>\n",
1730 method_name);
1731 fprintf(gOutFile,
1732 "<link_argument index=\"2\" type=\"MethodType\" value=\"%s\"/>\n",
1733 method_type.c_str());
1734 }
1735
1736 size_t argument = 3;
1737 while (it.HasNext()) {
1738 const char* type;
1739 std::string value;
1740 switch (it.GetValueType()) {
1741 case EncodedArrayValueIterator::ValueType::kByte:
1742 type = "byte";
1743 value = android::base::StringPrintf("%u", it.GetJavaValue().b);
1744 break;
1745 case EncodedArrayValueIterator::ValueType::kShort:
1746 type = "short";
1747 value = android::base::StringPrintf("%d", it.GetJavaValue().s);
1748 break;
1749 case EncodedArrayValueIterator::ValueType::kChar:
1750 type = "char";
1751 value = android::base::StringPrintf("%u", it.GetJavaValue().c);
1752 break;
1753 case EncodedArrayValueIterator::ValueType::kInt:
1754 type = "int";
1755 value = android::base::StringPrintf("%d", it.GetJavaValue().i);
1756 break;
1757 case EncodedArrayValueIterator::ValueType::kLong:
1758 type = "long";
1759 value = android::base::StringPrintf("%" PRId64, it.GetJavaValue().j);
1760 break;
1761 case EncodedArrayValueIterator::ValueType::kFloat:
1762 type = "float";
1763 value = android::base::StringPrintf("%g", it.GetJavaValue().f);
1764 break;
1765 case EncodedArrayValueIterator::ValueType::kDouble:
1766 type = "double";
1767 value = android::base::StringPrintf("%g", it.GetJavaValue().d);
1768 break;
1769 case EncodedArrayValueIterator::ValueType::kMethodType: {
1770 type = "MethodType";
1771 uint32_t proto_idx = static_cast<uint32_t>(it.GetJavaValue().i);
1772 const DexFile::ProtoId& proto_id = pDexFile->GetProtoId(proto_idx);
1773 value = pDexFile->GetProtoSignature(proto_id).ToString();
1774 break;
1775 }
1776 case EncodedArrayValueIterator::ValueType::kMethodHandle:
1777 type = "MethodHandle";
1778 value = android::base::StringPrintf("%d", it.GetJavaValue().i);
1779 break;
1780 case EncodedArrayValueIterator::ValueType::kString: {
1781 type = "String";
1782 dex::StringIndex string_idx = static_cast<dex::StringIndex>(it.GetJavaValue().i);
1783 value = pDexFile->StringDataByIdx(string_idx);
1784 break;
1785 }
1786 case EncodedArrayValueIterator::ValueType::kType: {
1787 type = "Class";
1788 dex::TypeIndex type_idx = static_cast<dex::TypeIndex>(it.GetJavaValue().i);
1789 const DexFile::ClassDef* class_def = pDexFile->FindClassDef(type_idx);
1790 value = pDexFile->GetClassDescriptor(*class_def);
1791 value = descriptorClassToDot(value.c_str()).get();
1792 break;
1793 }
1794 case EncodedArrayValueIterator::ValueType::kField:
1795 case EncodedArrayValueIterator::ValueType::kMethod:
1796 case EncodedArrayValueIterator::ValueType::kEnum:
1797 case EncodedArrayValueIterator::ValueType::kArray:
1798 case EncodedArrayValueIterator::ValueType::kAnnotation:
1799 // Unreachable based on current EncodedArrayValueIterator::Next().
Andreas Gampef45d61c2017-06-07 10:29:33 -07001800 UNIMPLEMENTED(FATAL) << " type " << it.GetValueType();
Orion Hodsonc069a302017-01-18 09:23:12 +00001801 UNREACHABLE();
Orion Hodsonc069a302017-01-18 09:23:12 +00001802 case EncodedArrayValueIterator::ValueType::kNull:
1803 type = "Null";
1804 value = "null";
1805 break;
1806 case EncodedArrayValueIterator::ValueType::kBoolean:
1807 type = "boolean";
1808 value = it.GetJavaValue().z ? "true" : "false";
1809 break;
1810 }
1811
1812 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1813 fprintf(gOutFile, " link_argument[%zu] : %s (%s)\n", argument, value.c_str(), type);
1814 } else {
1815 fprintf(gOutFile, "<link_argument index=\"%zu\" type=\"%s\" value=", argument, type);
1816 dumpEscapedString(value.c_str());
1817 fprintf(gOutFile, "/>\n");
1818 }
1819
1820 it.Next();
1821 argument++;
1822 }
1823
1824 if (gOptions.outputFormat == OUTPUT_XML) {
1825 fprintf(gOutFile, "</call_site>\n");
1826 }
1827}
1828
Aart Bik69ae54a2015-07-01 14:52:26 -07001829/*
1830 * Dumps the requested sections of the file.
1831 */
Aart Bik7b45a8a2016-10-24 16:07:59 -07001832static void processDexFile(const char* fileName,
1833 const DexFile* pDexFile, size_t i, size_t n) {
Aart Bik69ae54a2015-07-01 14:52:26 -07001834 if (gOptions.verbose) {
Aart Bik7b45a8a2016-10-24 16:07:59 -07001835 fputs("Opened '", gOutFile);
1836 fputs(fileName, gOutFile);
1837 if (n > 1) {
Mathieu Chartier79c87da2017-10-10 11:54:29 -07001838 fprintf(gOutFile, ":%s", DexFileLoader::GetMultiDexClassesDexName(i).c_str());
Aart Bik7b45a8a2016-10-24 16:07:59 -07001839 }
1840 fprintf(gOutFile, "', DEX version '%.3s'\n", pDexFile->GetHeader().magic_ + 4);
Aart Bik69ae54a2015-07-01 14:52:26 -07001841 }
1842
1843 // Headers.
1844 if (gOptions.showFileHeaders) {
1845 dumpFileHeader(pDexFile);
1846 }
1847
1848 // Open XML context.
1849 if (gOptions.outputFormat == OUTPUT_XML) {
1850 fprintf(gOutFile, "<api>\n");
1851 }
1852
1853 // Iterate over all classes.
1854 char* package = nullptr;
1855 const u4 classDefsSize = pDexFile->GetHeader().class_defs_size_;
1856 for (u4 i = 0; i < classDefsSize; i++) {
Aart Bik69ae54a2015-07-01 14:52:26 -07001857 dumpClass(pDexFile, i, &package);
1858 } // for
1859
Orion Hodsonc069a302017-01-18 09:23:12 +00001860 // Iterate over all method handles.
1861 for (u4 i = 0; i < pDexFile->NumMethodHandles(); ++i) {
1862 dumpMethodHandle(pDexFile, i);
1863 } // for
1864
1865 // Iterate over all call site ids.
1866 for (u4 i = 0; i < pDexFile->NumCallSiteIds(); ++i) {
1867 dumpCallSite(pDexFile, i);
1868 } // for
1869
Aart Bik69ae54a2015-07-01 14:52:26 -07001870 // Free the last package allocated.
1871 if (package != nullptr) {
1872 fprintf(gOutFile, "</package>\n");
1873 free(package);
1874 }
1875
1876 // Close XML context.
1877 if (gOptions.outputFormat == OUTPUT_XML) {
1878 fprintf(gOutFile, "</api>\n");
1879 }
1880}
1881
David Sehr5a1f6292018-01-19 11:08:51 -08001882static bool openAndMapFile(const char* fileName,
1883 const uint8_t** base,
1884 size_t* size,
1885 std::string* error_msg) {
1886 int fd = open(fileName, O_RDONLY);
1887 if (fd < 0) {
1888 *error_msg = "open failed";
1889 return false;
1890 }
1891 struct stat st;
1892 if (fstat(fd, &st) < 0) {
1893 *error_msg = "stat failed";
1894 return false;
1895 }
1896 *size = st.st_size;
1897 if (*size == 0) {
1898 *error_msg = "size == 0";
1899 return false;
1900 }
1901 void* addr = mmap(nullptr /*addr*/, *size, PROT_READ, MAP_PRIVATE, fd, 0 /*offset*/);
1902 if (addr == MAP_FAILED) {
1903 *error_msg = "mmap failed";
1904 return false;
1905 }
1906 *base = reinterpret_cast<const uint8_t*>(addr);
1907 return true;
1908}
1909
Aart Bik69ae54a2015-07-01 14:52:26 -07001910/*
1911 * Processes a single file (either direct .dex or indirect .zip/.jar/.apk).
1912 */
1913int processFile(const char* fileName) {
1914 if (gOptions.verbose) {
1915 fprintf(gOutFile, "Processing '%s'...\n", fileName);
1916 }
1917
1918 // If the file is not a .dex file, the function tries .zip/.jar/.apk files,
Aart Bikdce50862016-06-10 16:04:03 -07001919 // all of which are Zip archives with "classes.dex" inside.
Aart Bik37d6a3b2016-06-21 18:30:10 -07001920 const bool kVerifyChecksum = !gOptions.ignoreBadChecksum;
David Sehr5a1f6292018-01-19 11:08:51 -08001921 const uint8_t* base = nullptr;
1922 size_t size = 0;
Aart Bik69ae54a2015-07-01 14:52:26 -07001923 std::string error_msg;
David Sehr5a1f6292018-01-19 11:08:51 -08001924 if (!openAndMapFile(fileName, &base, &size, &error_msg)) {
Andreas Gampe221d9812018-01-22 17:48:56 -08001925 LOG(ERROR) << error_msg;
David Sehr5a1f6292018-01-19 11:08:51 -08001926 return -1;
1927 }
1928 const DexFileLoader dex_file_loader;
Aart Bik69ae54a2015-07-01 14:52:26 -07001929 std::vector<std::unique_ptr<const DexFile>> dex_files;
David Sehr5a1f6292018-01-19 11:08:51 -08001930 if (!dex_file_loader.OpenAll(
1931 base, size, fileName, /*verify*/ true, kVerifyChecksum, &error_msg, &dex_files)) {
Aart Bik69ae54a2015-07-01 14:52:26 -07001932 // Display returned error message to user. Note that this error behavior
1933 // differs from the error messages shown by the original Dalvik dexdump.
Andreas Gampe221d9812018-01-22 17:48:56 -08001934 LOG(ERROR) << error_msg;
Aart Bik69ae54a2015-07-01 14:52:26 -07001935 return -1;
1936 }
1937
Aart Bik4e149602015-07-09 11:45:28 -07001938 // Success. Either report checksum verification or process
1939 // all dex files found in given file.
Aart Bik69ae54a2015-07-01 14:52:26 -07001940 if (gOptions.checksumOnly) {
1941 fprintf(gOutFile, "Checksum verified\n");
1942 } else {
Aart Bik7b45a8a2016-10-24 16:07:59 -07001943 for (size_t i = 0, n = dex_files.size(); i < n; i++) {
1944 processDexFile(fileName, dex_files[i].get(), i, n);
Aart Bik4e149602015-07-09 11:45:28 -07001945 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001946 }
1947 return 0;
1948}
1949
1950} // namespace art