blob: 1d1eab8f017bd18565fa676399c4e04822369853 [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
37#include <inttypes.h>
38#include <stdio.h>
39
Alex Lightcefebc82020-07-22 17:59:34 -070040#include <cctype>
41#include <iomanip>
Aart Bik69ae54a2015-07-01 14:52:26 -070042#include <memory>
Andreas Gampe5073fed2015-08-10 11:40:25 -070043#include <sstream>
Aart Bik69ae54a2015-07-01 14:52:26 -070044#include <vector>
45
David Sehr999646d2018-02-16 10:22:33 -080046#include "android-base/file.h"
Andreas Gampe221d9812018-01-22 17:48:56 -080047#include "android-base/logging.h"
Andreas Gampe46ee31b2016-12-14 10:11:49 -080048#include "android-base/stringprintf.h"
49
Alex Lightcefebc82020-07-22 17:59:34 -070050#include "base/bit_utils.h"
Mathieu Chartierc2b4db62018-05-18 13:58:12 -070051#include "dex/class_accessor-inl.h"
David Sehr0225f8e2018-01-31 08:52:24 +000052#include "dex/code_item_accessors-inl.h"
David Sehr9e734c72018-01-04 17:56:19 -080053#include "dex/dex_file-inl.h"
54#include "dex/dex_file_exception_helpers.h"
55#include "dex/dex_file_loader.h"
56#include "dex/dex_file_types.h"
57#include "dex/dex_instruction-inl.h"
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070058#include "dexdump_cfg.h"
Aart Bik69ae54a2015-07-01 14:52:26 -070059
60namespace art {
61
62/*
63 * Options parsed in main driver.
64 */
65struct Options gOptions;
66
67/*
Aart Bik4e149602015-07-09 11:45:28 -070068 * Output file. Defaults to stdout.
Aart Bik69ae54a2015-07-01 14:52:26 -070069 */
70FILE* gOutFile = stdout;
71
72/*
73 * Data types that match the definitions in the VM specification.
74 */
Andreas Gampec55bb392018-09-21 00:02:02 +000075using u1 = uint8_t;
76using u2 = uint16_t;
77using u4 = uint32_t;
78using u8 = uint64_t;
79using s1 = int8_t;
80using s2 = int16_t;
81using s4 = int32_t;
82using s8 = int64_t;
Aart Bik69ae54a2015-07-01 14:52:26 -070083
84/*
85 * Basic information about a field or a method.
86 */
87struct FieldMethodInfo {
88 const char* classDescriptor;
89 const char* name;
90 const char* signature;
91};
92
93/*
94 * Flags for use with createAccessFlagStr().
95 */
96enum AccessFor {
97 kAccessForClass = 0, kAccessForMethod = 1, kAccessForField = 2, kAccessForMAX
98};
99const int kNumFlags = 18;
100
101/*
102 * Gets 2 little-endian bytes.
103 */
104static inline u2 get2LE(unsigned char const* pSrc) {
105 return pSrc[0] | (pSrc[1] << 8);
106}
107
108/*
109 * Converts a single-character primitive type into human-readable form.
110 */
111static const char* primitiveTypeLabel(char typeChar) {
112 switch (typeChar) {
113 case 'B': return "byte";
114 case 'C': return "char";
115 case 'D': return "double";
116 case 'F': return "float";
117 case 'I': return "int";
118 case 'J': return "long";
119 case 'S': return "short";
120 case 'V': return "void";
121 case 'Z': return "boolean";
122 default: return "UNKNOWN";
123 } // switch
124}
125
126/*
127 * Converts a type descriptor to human-readable "dotted" form. For
128 * example, "Ljava/lang/String;" becomes "java.lang.String", and
Orion Hodsonfe42d212018-08-24 14:01:14 +0100129 * "[I" becomes "int[]".
Aart Bik69ae54a2015-07-01 14:52:26 -0700130 */
Aart Bikc05e2f22016-07-12 15:53:13 -0700131static std::unique_ptr<char[]> descriptorToDot(const char* str) {
Aart Bik69ae54a2015-07-01 14:52:26 -0700132 int targetLen = strlen(str);
133 int offset = 0;
134
135 // Strip leading [s; will be added to end.
136 while (targetLen > 1 && str[offset] == '[') {
137 offset++;
138 targetLen--;
139 } // while
140
141 const int arrayDepth = offset;
142
143 if (targetLen == 1) {
144 // Primitive type.
145 str = primitiveTypeLabel(str[offset]);
146 offset = 0;
147 targetLen = strlen(str);
148 } else {
149 // Account for leading 'L' and trailing ';'.
150 if (targetLen >= 2 && str[offset] == 'L' &&
151 str[offset + targetLen - 1] == ';') {
152 targetLen -= 2;
153 offset++;
154 }
155 }
156
157 // Copy class name over.
Aart Bikc05e2f22016-07-12 15:53:13 -0700158 std::unique_ptr<char[]> newStr(new char[targetLen + arrayDepth * 2 + 1]);
Aart Bik69ae54a2015-07-01 14:52:26 -0700159 int i = 0;
160 for (; i < targetLen; i++) {
161 const char ch = str[offset + i];
Orion Hodsonfe42d212018-08-24 14:01:14 +0100162 newStr[i] = (ch == '/') ? '.' : ch;
Aart Bik69ae54a2015-07-01 14:52:26 -0700163 } // for
164
165 // Add the appropriate number of brackets for arrays.
166 for (int j = 0; j < arrayDepth; j++) {
167 newStr[i++] = '[';
168 newStr[i++] = ']';
169 } // for
170
171 newStr[i] = '\0';
172 return newStr;
173}
174
175/*
Orion Hodsonfe42d212018-08-24 14:01:14 +0100176 * Retrieves the class name portion of a type descriptor.
Aart Bik69ae54a2015-07-01 14:52:26 -0700177 */
Orion Hodsonfe42d212018-08-24 14:01:14 +0100178static std::unique_ptr<char[]> descriptorClassToName(const char* str) {
Aart Bikc05e2f22016-07-12 15:53:13 -0700179 // Reduce to just the class name prefix.
Aart Bik69ae54a2015-07-01 14:52:26 -0700180 const char* lastSlash = strrchr(str, '/');
181 if (lastSlash == nullptr) {
182 lastSlash = str + 1; // start past 'L'
183 } else {
184 lastSlash++; // start past '/'
185 }
186
Aart Bikc05e2f22016-07-12 15:53:13 -0700187 // Copy class name over, trimming trailing ';'.
188 const int targetLen = strlen(lastSlash);
189 std::unique_ptr<char[]> newStr(new char[targetLen]);
190 for (int i = 0; i < targetLen - 1; i++) {
Orion Hodsonfe42d212018-08-24 14:01:14 +0100191 newStr[i] = lastSlash[i];
Aart Bik69ae54a2015-07-01 14:52:26 -0700192 } // for
Aart Bikc05e2f22016-07-12 15:53:13 -0700193 newStr[targetLen - 1] = '\0';
Aart Bik69ae54a2015-07-01 14:52:26 -0700194 return newStr;
195}
196
197/*
Aart Bikdce50862016-06-10 16:04:03 -0700198 * Returns string representing the boolean value.
199 */
200static const char* strBool(bool val) {
201 return val ? "true" : "false";
202}
203
204/*
Aart Bik69ae54a2015-07-01 14:52:26 -0700205 * Returns a quoted string representing the boolean value.
206 */
207static const char* quotedBool(bool val) {
208 return val ? "\"true\"" : "\"false\"";
209}
210
211/*
212 * Returns a quoted string representing the access flags.
213 */
214static const char* quotedVisibility(u4 accessFlags) {
215 if (accessFlags & kAccPublic) {
216 return "\"public\"";
217 } else if (accessFlags & kAccProtected) {
218 return "\"protected\"";
219 } else if (accessFlags & kAccPrivate) {
220 return "\"private\"";
221 } else {
222 return "\"package\"";
223 }
224}
225
226/*
227 * Counts the number of '1' bits in a word.
228 */
229static int countOnes(u4 val) {
230 val = val - ((val >> 1) & 0x55555555);
231 val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
232 return (((val + (val >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
233}
234
235/*
236 * Creates a new string with human-readable access flags.
237 *
238 * In the base language the access_flags fields are type u2; in Dalvik
239 * they're u4.
240 */
241static char* createAccessFlagStr(u4 flags, AccessFor forWhat) {
242 static const char* kAccessStrings[kAccessForMAX][kNumFlags] = {
243 {
244 "PUBLIC", /* 0x00001 */
245 "PRIVATE", /* 0x00002 */
246 "PROTECTED", /* 0x00004 */
247 "STATIC", /* 0x00008 */
248 "FINAL", /* 0x00010 */
249 "?", /* 0x00020 */
250 "?", /* 0x00040 */
251 "?", /* 0x00080 */
252 "?", /* 0x00100 */
253 "INTERFACE", /* 0x00200 */
254 "ABSTRACT", /* 0x00400 */
255 "?", /* 0x00800 */
256 "SYNTHETIC", /* 0x01000 */
257 "ANNOTATION", /* 0x02000 */
258 "ENUM", /* 0x04000 */
259 "?", /* 0x08000 */
260 "VERIFIED", /* 0x10000 */
261 "OPTIMIZED", /* 0x20000 */
262 }, {
263 "PUBLIC", /* 0x00001 */
264 "PRIVATE", /* 0x00002 */
265 "PROTECTED", /* 0x00004 */
266 "STATIC", /* 0x00008 */
267 "FINAL", /* 0x00010 */
268 "SYNCHRONIZED", /* 0x00020 */
269 "BRIDGE", /* 0x00040 */
270 "VARARGS", /* 0x00080 */
271 "NATIVE", /* 0x00100 */
272 "?", /* 0x00200 */
273 "ABSTRACT", /* 0x00400 */
274 "STRICT", /* 0x00800 */
275 "SYNTHETIC", /* 0x01000 */
276 "?", /* 0x02000 */
277 "?", /* 0x04000 */
278 "MIRANDA", /* 0x08000 */
279 "CONSTRUCTOR", /* 0x10000 */
280 "DECLARED_SYNCHRONIZED", /* 0x20000 */
281 }, {
282 "PUBLIC", /* 0x00001 */
283 "PRIVATE", /* 0x00002 */
284 "PROTECTED", /* 0x00004 */
285 "STATIC", /* 0x00008 */
286 "FINAL", /* 0x00010 */
287 "?", /* 0x00020 */
288 "VOLATILE", /* 0x00040 */
289 "TRANSIENT", /* 0x00080 */
290 "?", /* 0x00100 */
291 "?", /* 0x00200 */
292 "?", /* 0x00400 */
293 "?", /* 0x00800 */
294 "SYNTHETIC", /* 0x01000 */
295 "?", /* 0x02000 */
296 "ENUM", /* 0x04000 */
297 "?", /* 0x08000 */
298 "?", /* 0x10000 */
299 "?", /* 0x20000 */
300 },
301 };
302
303 // Allocate enough storage to hold the expected number of strings,
304 // plus a space between each. We over-allocate, using the longest
305 // string above as the base metric.
306 const int kLongest = 21; // The strlen of longest string above.
307 const int count = countOnes(flags);
308 char* str;
309 char* cp;
310 cp = str = reinterpret_cast<char*>(malloc(count * (kLongest + 1) + 1));
311
312 for (int i = 0; i < kNumFlags; i++) {
313 if (flags & 0x01) {
314 const char* accessStr = kAccessStrings[forWhat][i];
315 const int len = strlen(accessStr);
316 if (cp != str) {
317 *cp++ = ' ';
318 }
319 memcpy(cp, accessStr, len);
320 cp += len;
321 }
322 flags >>= 1;
323 } // for
324
325 *cp = '\0';
326 return str;
327}
328
329/*
330 * Copies character data from "data" to "out", converting non-ASCII values
331 * to fprintf format chars or an ASCII filler ('.' or '?').
332 *
333 * The output buffer must be able to hold (2*len)+1 bytes. The result is
334 * NULL-terminated.
335 */
336static void asciify(char* out, const unsigned char* data, size_t len) {
Andreas Gampec74d9cb2018-09-20 13:44:44 -0700337 for (; len != 0u; --len) {
Aart Bik69ae54a2015-07-01 14:52:26 -0700338 if (*data < 0x20) {
339 // Could do more here, but we don't need them yet.
340 switch (*data) {
341 case '\0':
342 *out++ = '\\';
343 *out++ = '0';
344 break;
345 case '\n':
346 *out++ = '\\';
347 *out++ = 'n';
348 break;
349 default:
350 *out++ = '.';
351 break;
352 } // switch
353 } else if (*data >= 0x80) {
354 *out++ = '?';
355 } else {
356 *out++ = *data;
357 }
358 data++;
359 } // while
360 *out = '\0';
361}
362
363/*
Aart Bikdce50862016-06-10 16:04:03 -0700364 * Dumps a string value with some escape characters.
365 */
Alex Lightcefebc82020-07-22 17:59:34 -0700366static void dumpEscapedString(std::string_view p) {
Aart Bikdce50862016-06-10 16:04:03 -0700367 fputs("\"", gOutFile);
Alex Lightcefebc82020-07-22 17:59:34 -0700368 for (char c : p) {
369 switch (c) {
Aart Bikdce50862016-06-10 16:04:03 -0700370 case '\\':
371 fputs("\\\\", gOutFile);
372 break;
373 case '\"':
374 fputs("\\\"", gOutFile);
375 break;
376 case '\t':
377 fputs("\\t", gOutFile);
378 break;
379 case '\n':
380 fputs("\\n", gOutFile);
381 break;
382 case '\r':
383 fputs("\\r", gOutFile);
384 break;
385 default:
Alex Lightcefebc82020-07-22 17:59:34 -0700386 putc(c, gOutFile);
Aart Bikdce50862016-06-10 16:04:03 -0700387 } // switch
388 } // for
389 fputs("\"", gOutFile);
390}
391
Alex Lightcefebc82020-07-22 17:59:34 -0700392static size_t utf8Bytes(char start_byte) {
393 uint8_t sb = static_cast<uint8_t>(start_byte);
394 if ((sb & 0x80) == 0) {
395 return 1;
396 }
397 size_t msb = art::MostSignificantBit(static_cast<uint8_t>(~sb));
398 CHECK_LE(7u - msb, 4u);
399 return 7 - msb;
400}
401
Aart Bikdce50862016-06-10 16:04:03 -0700402/*
403 * Dumps a string as an XML attribute value.
404 */
Alex Lightcefebc82020-07-22 17:59:34 -0700405static void dumpXmlAttribute(std::string_view p) __attribute__((optnone)) {
406 for (const char* c = p.begin(); c < p.end(); ++c) {
407 if (std::isprint(*c)) {
408 switch (*c) {
409 case '&':
410 fputs("&amp;", gOutFile);
411 break;
412 case '<':
413 fputs("&lt;", gOutFile);
414 break;
415 case '>':
416 fputs("&gt;", gOutFile);
417 break;
418 case '"':
419 fputs("&quot;", gOutFile);
420 break;
421 case '\\':
422 fputs("\\\\", gOutFile);
423 break;
424 default:
425 putc(*c, gOutFile);
426 } // switch
427 } else {
428 uint32_t data = 0;
429 size_t remaining;
430 uint8_t uc = static_cast<uint8_t>(*c);
431 if (((uc) & 0x80) == 0) {
432 // Not a multi-byte char
433 data = static_cast<uint32_t>(*c);
434 remaining = 0;
435 } else if (utf8Bytes(uc) == 2) {
436 // 2 bytes
437 data = ((uc) & 0b00011111);
438 remaining = 1;
439 } else if (utf8Bytes(uc) == 3) {
440 // 3 bytes
441 data = ((uc) & 0b00001111);
442 remaining = 2;
443 } else {
444 // 4 bytes
445 CHECK_EQ(utf8Bytes(uc), 4u);
446 data = ((uc) & 0b00000111);
447 remaining = 3;
448 }
449 for (size_t i = 0; i < remaining; ++i) {
450 ++c;
451 data = data << 6;
452 uc = static_cast<uint8_t>(*c);
453 data |= static_cast<uint32_t>(uc & 0b00111111u);
454 }
455 // No good option so just use java encoding, too many chars are invalid
456 fprintf(gOutFile, "\\u%04x", data);
457 }
Aart Bikdce50862016-06-10 16:04:03 -0700458 } // for
459}
460
461/*
462 * Reads variable width value, possibly sign extended at the last defined byte.
463 */
464static u8 readVarWidth(const u1** data, u1 arg, bool sign_extend) {
465 u8 value = 0;
466 for (u4 i = 0; i <= arg; i++) {
467 value |= static_cast<u8>(*(*data)++) << (i * 8);
468 }
469 if (sign_extend) {
470 int shift = (7 - arg) * 8;
471 return (static_cast<s8>(value) << shift) >> shift;
472 }
473 return value;
474}
475
476/*
477 * Dumps encoded value.
478 */
479static void dumpEncodedValue(const DexFile* pDexFile, const u1** data); // forward
480static void dumpEncodedValue(const DexFile* pDexFile, const u1** data, u1 type, u1 arg) {
481 switch (type) {
482 case DexFile::kDexAnnotationByte:
483 fprintf(gOutFile, "%" PRId8, static_cast<s1>(readVarWidth(data, arg, false)));
484 break;
485 case DexFile::kDexAnnotationShort:
486 fprintf(gOutFile, "%" PRId16, static_cast<s2>(readVarWidth(data, arg, true)));
487 break;
488 case DexFile::kDexAnnotationChar:
489 fprintf(gOutFile, "%" PRIu16, static_cast<u2>(readVarWidth(data, arg, false)));
490 break;
491 case DexFile::kDexAnnotationInt:
492 fprintf(gOutFile, "%" PRId32, static_cast<s4>(readVarWidth(data, arg, true)));
493 break;
494 case DexFile::kDexAnnotationLong:
495 fprintf(gOutFile, "%" PRId64, static_cast<s8>(readVarWidth(data, arg, true)));
496 break;
497 case DexFile::kDexAnnotationFloat: {
498 // Fill on right.
499 union {
500 float f;
501 u4 data;
502 } conv;
503 conv.data = static_cast<u4>(readVarWidth(data, arg, false)) << (3 - arg) * 8;
504 fprintf(gOutFile, "%g", conv.f);
505 break;
506 }
507 case DexFile::kDexAnnotationDouble: {
508 // Fill on right.
509 union {
510 double d;
511 u8 data;
512 } conv;
513 conv.data = readVarWidth(data, arg, false) << (7 - arg) * 8;
514 fprintf(gOutFile, "%g", conv.d);
515 break;
516 }
517 case DexFile::kDexAnnotationString: {
518 const u4 idx = static_cast<u4>(readVarWidth(data, arg, false));
519 if (gOptions.outputFormat == OUTPUT_PLAIN) {
Alex Lightcefebc82020-07-22 17:59:34 -0700520 dumpEscapedString(pDexFile->StringViewByIdx(dex::StringIndex(idx)));
Aart Bikdce50862016-06-10 16:04:03 -0700521 } else {
Alex Lightcefebc82020-07-22 17:59:34 -0700522 dumpXmlAttribute(pDexFile->StringViewByIdx(dex::StringIndex(idx)));
Aart Bikdce50862016-06-10 16:04:03 -0700523 }
524 break;
525 }
526 case DexFile::kDexAnnotationType: {
527 const u4 str_idx = static_cast<u4>(readVarWidth(data, arg, false));
Andreas Gampea5b09a62016-11-17 15:21:22 -0800528 fputs(pDexFile->StringByTypeIdx(dex::TypeIndex(str_idx)), gOutFile);
Aart Bikdce50862016-06-10 16:04:03 -0700529 break;
530 }
531 case DexFile::kDexAnnotationField:
532 case DexFile::kDexAnnotationEnum: {
533 const u4 field_idx = static_cast<u4>(readVarWidth(data, arg, false));
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800534 const dex::FieldId& pFieldId = pDexFile->GetFieldId(field_idx);
Aart Bikdce50862016-06-10 16:04:03 -0700535 fputs(pDexFile->StringDataByIdx(pFieldId.name_idx_), gOutFile);
536 break;
537 }
538 case DexFile::kDexAnnotationMethod: {
539 const u4 method_idx = static_cast<u4>(readVarWidth(data, arg, false));
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800540 const dex::MethodId& pMethodId = pDexFile->GetMethodId(method_idx);
Aart Bikdce50862016-06-10 16:04:03 -0700541 fputs(pDexFile->StringDataByIdx(pMethodId.name_idx_), gOutFile);
542 break;
543 }
544 case DexFile::kDexAnnotationArray: {
545 fputc('{', gOutFile);
546 // Decode and display all elements.
547 const u4 size = DecodeUnsignedLeb128(data);
548 for (u4 i = 0; i < size; i++) {
549 fputc(' ', gOutFile);
550 dumpEncodedValue(pDexFile, data);
551 }
552 fputs(" }", gOutFile);
553 break;
554 }
555 case DexFile::kDexAnnotationAnnotation: {
556 const u4 type_idx = DecodeUnsignedLeb128(data);
Andreas Gampea5b09a62016-11-17 15:21:22 -0800557 fputs(pDexFile->StringByTypeIdx(dex::TypeIndex(type_idx)), gOutFile);
Aart Bikdce50862016-06-10 16:04:03 -0700558 // Decode and display all name=value pairs.
559 const u4 size = DecodeUnsignedLeb128(data);
560 for (u4 i = 0; i < size; i++) {
561 const u4 name_idx = DecodeUnsignedLeb128(data);
562 fputc(' ', gOutFile);
Andreas Gampe8a0128a2016-11-28 07:38:35 -0800563 fputs(pDexFile->StringDataByIdx(dex::StringIndex(name_idx)), gOutFile);
Aart Bikdce50862016-06-10 16:04:03 -0700564 fputc('=', gOutFile);
565 dumpEncodedValue(pDexFile, data);
566 }
567 break;
568 }
569 case DexFile::kDexAnnotationNull:
570 fputs("null", gOutFile);
571 break;
572 case DexFile::kDexAnnotationBoolean:
573 fputs(strBool(arg), gOutFile);
574 break;
575 default:
576 fputs("????", gOutFile);
577 break;
578 } // switch
579}
580
581/*
582 * Dumps encoded value with prefix.
583 */
584static void dumpEncodedValue(const DexFile* pDexFile, const u1** data) {
585 const u1 enc = *(*data)++;
586 dumpEncodedValue(pDexFile, data, enc & 0x1f, enc >> 5);
587}
588
589/*
Aart Bik69ae54a2015-07-01 14:52:26 -0700590 * Dumps the file header.
Aart Bik69ae54a2015-07-01 14:52:26 -0700591 */
592static void dumpFileHeader(const DexFile* pDexFile) {
593 const DexFile::Header& pHeader = pDexFile->GetHeader();
594 char sanitized[sizeof(pHeader.magic_) * 2 + 1];
595 fprintf(gOutFile, "DEX file header:\n");
596 asciify(sanitized, pHeader.magic_, sizeof(pHeader.magic_));
597 fprintf(gOutFile, "magic : '%s'\n", sanitized);
598 fprintf(gOutFile, "checksum : %08x\n", pHeader.checksum_);
599 fprintf(gOutFile, "signature : %02x%02x...%02x%02x\n",
600 pHeader.signature_[0], pHeader.signature_[1],
601 pHeader.signature_[DexFile::kSha1DigestSize - 2],
602 pHeader.signature_[DexFile::kSha1DigestSize - 1]);
603 fprintf(gOutFile, "file_size : %d\n", pHeader.file_size_);
604 fprintf(gOutFile, "header_size : %d\n", pHeader.header_size_);
605 fprintf(gOutFile, "link_size : %d\n", pHeader.link_size_);
606 fprintf(gOutFile, "link_off : %d (0x%06x)\n",
607 pHeader.link_off_, pHeader.link_off_);
608 fprintf(gOutFile, "string_ids_size : %d\n", pHeader.string_ids_size_);
609 fprintf(gOutFile, "string_ids_off : %d (0x%06x)\n",
610 pHeader.string_ids_off_, pHeader.string_ids_off_);
611 fprintf(gOutFile, "type_ids_size : %d\n", pHeader.type_ids_size_);
612 fprintf(gOutFile, "type_ids_off : %d (0x%06x)\n",
613 pHeader.type_ids_off_, pHeader.type_ids_off_);
Aart Bikdce50862016-06-10 16:04:03 -0700614 fprintf(gOutFile, "proto_ids_size : %d\n", pHeader.proto_ids_size_);
615 fprintf(gOutFile, "proto_ids_off : %d (0x%06x)\n",
Aart Bik69ae54a2015-07-01 14:52:26 -0700616 pHeader.proto_ids_off_, pHeader.proto_ids_off_);
617 fprintf(gOutFile, "field_ids_size : %d\n", pHeader.field_ids_size_);
618 fprintf(gOutFile, "field_ids_off : %d (0x%06x)\n",
619 pHeader.field_ids_off_, pHeader.field_ids_off_);
620 fprintf(gOutFile, "method_ids_size : %d\n", pHeader.method_ids_size_);
621 fprintf(gOutFile, "method_ids_off : %d (0x%06x)\n",
622 pHeader.method_ids_off_, pHeader.method_ids_off_);
623 fprintf(gOutFile, "class_defs_size : %d\n", pHeader.class_defs_size_);
624 fprintf(gOutFile, "class_defs_off : %d (0x%06x)\n",
625 pHeader.class_defs_off_, pHeader.class_defs_off_);
626 fprintf(gOutFile, "data_size : %d\n", pHeader.data_size_);
627 fprintf(gOutFile, "data_off : %d (0x%06x)\n\n",
628 pHeader.data_off_, pHeader.data_off_);
629}
630
631/*
632 * Dumps a class_def_item.
633 */
634static void dumpClassDef(const DexFile* pDexFile, int idx) {
635 // General class information.
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800636 const dex::ClassDef& pClassDef = pDexFile->GetClassDef(idx);
Aart Bik69ae54a2015-07-01 14:52:26 -0700637 fprintf(gOutFile, "Class #%d header:\n", idx);
Andreas Gampea5b09a62016-11-17 15:21:22 -0800638 fprintf(gOutFile, "class_idx : %d\n", pClassDef.class_idx_.index_);
Aart Bik69ae54a2015-07-01 14:52:26 -0700639 fprintf(gOutFile, "access_flags : %d (0x%04x)\n",
640 pClassDef.access_flags_, pClassDef.access_flags_);
Andreas Gampea5b09a62016-11-17 15:21:22 -0800641 fprintf(gOutFile, "superclass_idx : %d\n", pClassDef.superclass_idx_.index_);
Aart Bik69ae54a2015-07-01 14:52:26 -0700642 fprintf(gOutFile, "interfaces_off : %d (0x%06x)\n",
643 pClassDef.interfaces_off_, pClassDef.interfaces_off_);
Andreas Gampe8a0128a2016-11-28 07:38:35 -0800644 fprintf(gOutFile, "source_file_idx : %d\n", pClassDef.source_file_idx_.index_);
Aart Bik69ae54a2015-07-01 14:52:26 -0700645 fprintf(gOutFile, "annotations_off : %d (0x%06x)\n",
646 pClassDef.annotations_off_, pClassDef.annotations_off_);
647 fprintf(gOutFile, "class_data_off : %d (0x%06x)\n",
648 pClassDef.class_data_off_, pClassDef.class_data_off_);
649
650 // Fields and methods.
Mathieu Chartier18e26872018-06-04 17:19:02 -0700651 ClassAccessor accessor(*pDexFile, idx);
Mathieu Chartierc2b4db62018-05-18 13:58:12 -0700652 fprintf(gOutFile, "static_fields_size : %d\n", accessor.NumStaticFields());
653 fprintf(gOutFile, "instance_fields_size: %d\n", accessor.NumInstanceFields());
654 fprintf(gOutFile, "direct_methods_size : %d\n", accessor.NumDirectMethods());
655 fprintf(gOutFile, "virtual_methods_size: %d\n", accessor.NumVirtualMethods());
Aart Bik69ae54a2015-07-01 14:52:26 -0700656 fprintf(gOutFile, "\n");
657}
658
Aart Bikdce50862016-06-10 16:04:03 -0700659/**
660 * Dumps an annotation set item.
661 */
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800662static void dumpAnnotationSetItem(const DexFile* pDexFile, const dex::AnnotationSetItem* set_item) {
Aart Bikdce50862016-06-10 16:04:03 -0700663 if (set_item == nullptr || set_item->size_ == 0) {
664 fputs(" empty-annotation-set\n", gOutFile);
665 return;
666 }
667 for (u4 i = 0; i < set_item->size_; i++) {
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800668 const dex::AnnotationItem* annotation = pDexFile->GetAnnotationItem(set_item, i);
Aart Bikdce50862016-06-10 16:04:03 -0700669 if (annotation == nullptr) {
670 continue;
671 }
672 fputs(" ", gOutFile);
673 switch (annotation->visibility_) {
674 case DexFile::kDexVisibilityBuild: fputs("VISIBILITY_BUILD ", gOutFile); break;
675 case DexFile::kDexVisibilityRuntime: fputs("VISIBILITY_RUNTIME ", gOutFile); break;
676 case DexFile::kDexVisibilitySystem: fputs("VISIBILITY_SYSTEM ", gOutFile); break;
677 default: fputs("VISIBILITY_UNKNOWN ", gOutFile); break;
678 } // switch
679 // Decode raw bytes in annotation.
680 const u1* rData = annotation->annotation_;
681 dumpEncodedValue(pDexFile, &rData, DexFile::kDexAnnotationAnnotation, 0);
682 fputc('\n', gOutFile);
683 }
684}
685
686/*
687 * Dumps class annotations.
688 */
689static void dumpClassAnnotations(const DexFile* pDexFile, int idx) {
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800690 const dex::ClassDef& pClassDef = pDexFile->GetClassDef(idx);
691 const dex::AnnotationsDirectoryItem* dir = pDexFile->GetAnnotationsDirectory(pClassDef);
Aart Bikdce50862016-06-10 16:04:03 -0700692 if (dir == nullptr) {
693 return; // none
694 }
695
696 fprintf(gOutFile, "Class #%d annotations:\n", idx);
697
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800698 const dex::AnnotationSetItem* class_set_item = pDexFile->GetClassAnnotationSet(dir);
699 const dex::FieldAnnotationsItem* fields = pDexFile->GetFieldAnnotations(dir);
700 const dex::MethodAnnotationsItem* methods = pDexFile->GetMethodAnnotations(dir);
701 const dex::ParameterAnnotationsItem* pars = pDexFile->GetParameterAnnotations(dir);
Aart Bikdce50862016-06-10 16:04:03 -0700702
703 // Annotations on the class itself.
704 if (class_set_item != nullptr) {
705 fprintf(gOutFile, "Annotations on class\n");
706 dumpAnnotationSetItem(pDexFile, class_set_item);
707 }
708
709 // Annotations on fields.
710 if (fields != nullptr) {
711 for (u4 i = 0; i < dir->fields_size_; i++) {
712 const u4 field_idx = fields[i].field_idx_;
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800713 const dex::FieldId& pFieldId = pDexFile->GetFieldId(field_idx);
Aart Bikdce50862016-06-10 16:04:03 -0700714 const char* field_name = pDexFile->StringDataByIdx(pFieldId.name_idx_);
715 fprintf(gOutFile, "Annotations on field #%u '%s'\n", field_idx, field_name);
716 dumpAnnotationSetItem(pDexFile, pDexFile->GetFieldAnnotationSetItem(fields[i]));
717 }
718 }
719
720 // Annotations on methods.
721 if (methods != nullptr) {
722 for (u4 i = 0; i < dir->methods_size_; i++) {
723 const u4 method_idx = methods[i].method_idx_;
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800724 const dex::MethodId& pMethodId = pDexFile->GetMethodId(method_idx);
Aart Bikdce50862016-06-10 16:04:03 -0700725 const char* method_name = pDexFile->StringDataByIdx(pMethodId.name_idx_);
726 fprintf(gOutFile, "Annotations on method #%u '%s'\n", method_idx, method_name);
727 dumpAnnotationSetItem(pDexFile, pDexFile->GetMethodAnnotationSetItem(methods[i]));
728 }
729 }
730
731 // Annotations on method parameters.
732 if (pars != nullptr) {
733 for (u4 i = 0; i < dir->parameters_size_; i++) {
734 const u4 method_idx = pars[i].method_idx_;
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800735 const dex::MethodId& pMethodId = pDexFile->GetMethodId(method_idx);
Aart Bikdce50862016-06-10 16:04:03 -0700736 const char* method_name = pDexFile->StringDataByIdx(pMethodId.name_idx_);
737 fprintf(gOutFile, "Annotations on method #%u '%s' parameters\n", method_idx, method_name);
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800738 const dex::AnnotationSetRefList*
Aart Bikdce50862016-06-10 16:04:03 -0700739 list = pDexFile->GetParameterAnnotationSetRefList(&pars[i]);
740 if (list != nullptr) {
741 for (u4 j = 0; j < list->size_; j++) {
742 fprintf(gOutFile, "#%u\n", j);
743 dumpAnnotationSetItem(pDexFile, pDexFile->GetSetRefItemItem(&list->list_[j]));
744 }
745 }
746 }
747 }
748
749 fputc('\n', gOutFile);
750}
751
Aart Bik69ae54a2015-07-01 14:52:26 -0700752/*
753 * Dumps an interface that a class declares to implement.
754 */
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800755static void dumpInterface(const DexFile* pDexFile, const dex::TypeItem& pTypeItem, int i) {
Aart Bik69ae54a2015-07-01 14:52:26 -0700756 const char* interfaceName = pDexFile->StringByTypeIdx(pTypeItem.type_idx_);
757 if (gOptions.outputFormat == OUTPUT_PLAIN) {
758 fprintf(gOutFile, " #%d : '%s'\n", i, interfaceName);
759 } else {
Aart Bikc05e2f22016-07-12 15:53:13 -0700760 std::unique_ptr<char[]> dot(descriptorToDot(interfaceName));
761 fprintf(gOutFile, "<implements name=\"%s\">\n</implements>\n", dot.get());
Aart Bik69ae54a2015-07-01 14:52:26 -0700762 }
763}
764
765/*
766 * Dumps the catches table associated with the code.
767 */
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800768static void dumpCatches(const DexFile* pDexFile, const dex::CodeItem* pCode) {
Mathieu Chartier698ebbc2018-01-05 11:00:42 -0800769 CodeItemDataAccessor accessor(*pDexFile, pCode);
Mathieu Chartierdc578c72017-12-27 11:51:45 -0800770 const u4 triesSize = accessor.TriesSize();
Aart Bik69ae54a2015-07-01 14:52:26 -0700771
772 // No catch table.
773 if (triesSize == 0) {
774 fprintf(gOutFile, " catches : (none)\n");
775 return;
776 }
777
778 // Dump all table entries.
779 fprintf(gOutFile, " catches : %d\n", triesSize);
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800780 for (const dex::TryItem& try_item : accessor.TryItems()) {
Mathieu Chartierdc578c72017-12-27 11:51:45 -0800781 const u4 start = try_item.start_addr_;
782 const u4 end = start + try_item.insn_count_;
Aart Bik69ae54a2015-07-01 14:52:26 -0700783 fprintf(gOutFile, " 0x%04x - 0x%04x\n", start, end);
Mathieu Chartierdc578c72017-12-27 11:51:45 -0800784 for (CatchHandlerIterator it(accessor, try_item); it.HasNext(); it.Next()) {
Andreas Gampea5b09a62016-11-17 15:21:22 -0800785 const dex::TypeIndex tidx = it.GetHandlerTypeIndex();
786 const char* descriptor = (!tidx.IsValid()) ? "<any>" : pDexFile->StringByTypeIdx(tidx);
Aart Bik69ae54a2015-07-01 14:52:26 -0700787 fprintf(gOutFile, " %s -> 0x%04x\n", descriptor, it.GetHandlerAddress());
788 } // for
789 } // for
790}
791
792/*
Aart Bik69ae54a2015-07-01 14:52:26 -0700793 * Helper for dumpInstruction(), which builds the string
Aart Bika0e33fd2016-07-08 18:32:45 -0700794 * representation for the index in the given instruction.
795 * Returns a pointer to a buffer of sufficient size.
Aart Bik69ae54a2015-07-01 14:52:26 -0700796 */
Aart Bika0e33fd2016-07-08 18:32:45 -0700797static std::unique_ptr<char[]> indexString(const DexFile* pDexFile,
798 const Instruction* pDecInsn,
799 size_t bufSize) {
800 std::unique_ptr<char[]> buf(new char[bufSize]);
Aart Bik69ae54a2015-07-01 14:52:26 -0700801 // Determine index and width of the string.
802 u4 index = 0;
Orion Hodson06d10a72018-05-14 08:53:38 +0100803 u2 secondary_index = 0;
Aart Bik69ae54a2015-07-01 14:52:26 -0700804 u4 width = 4;
805 switch (Instruction::FormatOf(pDecInsn->Opcode())) {
806 // SOME NOT SUPPORTED:
807 // case Instruction::k20bc:
808 case Instruction::k21c:
809 case Instruction::k35c:
810 // case Instruction::k35ms:
811 case Instruction::k3rc:
812 // case Instruction::k3rms:
813 // case Instruction::k35mi:
814 // case Instruction::k3rmi:
815 index = pDecInsn->VRegB();
816 width = 4;
817 break;
818 case Instruction::k31c:
819 index = pDecInsn->VRegB();
820 width = 8;
821 break;
822 case Instruction::k22c:
823 // case Instruction::k22cs:
824 index = pDecInsn->VRegC();
825 width = 4;
826 break;
Orion Hodsonb34bb192016-10-18 17:02:58 +0100827 case Instruction::k45cc:
828 case Instruction::k4rcc:
829 index = pDecInsn->VRegB();
830 secondary_index = pDecInsn->VRegH();
831 width = 4;
832 break;
Aart Bik69ae54a2015-07-01 14:52:26 -0700833 default:
834 break;
835 } // switch
836
837 // Determine index type.
838 size_t outSize = 0;
839 switch (Instruction::IndexTypeOf(pDecInsn->Opcode())) {
840 case Instruction::kIndexUnknown:
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, "<unknown-index>");
Aart Bik69ae54a2015-07-01 14:52:26 -0700844 break;
845 case Instruction::kIndexNone:
846 // This function should never get called for this type, but do
847 // something sensible here, just to help with debugging.
Aart Bika0e33fd2016-07-08 18:32:45 -0700848 outSize = snprintf(buf.get(), bufSize, "<no-index>");
Aart Bik69ae54a2015-07-01 14:52:26 -0700849 break;
850 case Instruction::kIndexTypeRef:
851 if (index < pDexFile->GetHeader().type_ids_size_) {
Andreas Gampea5b09a62016-11-17 15:21:22 -0800852 const char* tp = pDexFile->StringByTypeIdx(dex::TypeIndex(index));
Aart Bika0e33fd2016-07-08 18:32:45 -0700853 outSize = snprintf(buf.get(), bufSize, "%s // type@%0*x", tp, width, index);
Aart Bik69ae54a2015-07-01 14:52:26 -0700854 } else {
Aart Bika0e33fd2016-07-08 18:32:45 -0700855 outSize = snprintf(buf.get(), bufSize, "<type?> // type@%0*x", width, index);
Aart Bik69ae54a2015-07-01 14:52:26 -0700856 }
857 break;
858 case Instruction::kIndexStringRef:
859 if (index < pDexFile->GetHeader().string_ids_size_) {
Andreas Gampe8a0128a2016-11-28 07:38:35 -0800860 const char* st = pDexFile->StringDataByIdx(dex::StringIndex(index));
Aart Bika0e33fd2016-07-08 18:32:45 -0700861 outSize = snprintf(buf.get(), bufSize, "\"%s\" // string@%0*x", st, width, index);
Aart Bik69ae54a2015-07-01 14:52:26 -0700862 } else {
Aart Bika0e33fd2016-07-08 18:32:45 -0700863 outSize = snprintf(buf.get(), bufSize, "<string?> // string@%0*x", width, index);
Aart Bik69ae54a2015-07-01 14:52:26 -0700864 }
865 break;
866 case Instruction::kIndexMethodRef:
867 if (index < pDexFile->GetHeader().method_ids_size_) {
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800868 const dex::MethodId& pMethodId = pDexFile->GetMethodId(index);
Aart Bik69ae54a2015-07-01 14:52:26 -0700869 const char* name = pDexFile->StringDataByIdx(pMethodId.name_idx_);
870 const Signature signature = pDexFile->GetMethodSignature(pMethodId);
871 const char* backDescriptor = pDexFile->StringByTypeIdx(pMethodId.class_idx_);
Aart Bika0e33fd2016-07-08 18:32:45 -0700872 outSize = snprintf(buf.get(), bufSize, "%s.%s:%s // method@%0*x",
Aart Bik69ae54a2015-07-01 14:52:26 -0700873 backDescriptor, name, signature.ToString().c_str(), width, index);
874 } else {
Aart Bika0e33fd2016-07-08 18:32:45 -0700875 outSize = snprintf(buf.get(), bufSize, "<method?> // method@%0*x", width, index);
Aart Bik69ae54a2015-07-01 14:52:26 -0700876 }
877 break;
878 case Instruction::kIndexFieldRef:
879 if (index < pDexFile->GetHeader().field_ids_size_) {
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800880 const dex::FieldId& pFieldId = pDexFile->GetFieldId(index);
Aart Bik69ae54a2015-07-01 14:52:26 -0700881 const char* name = pDexFile->StringDataByIdx(pFieldId.name_idx_);
882 const char* typeDescriptor = pDexFile->StringByTypeIdx(pFieldId.type_idx_);
883 const char* backDescriptor = pDexFile->StringByTypeIdx(pFieldId.class_idx_);
Aart Bika0e33fd2016-07-08 18:32:45 -0700884 outSize = snprintf(buf.get(), bufSize, "%s.%s:%s // field@%0*x",
Aart Bik69ae54a2015-07-01 14:52:26 -0700885 backDescriptor, name, typeDescriptor, width, index);
886 } else {
Aart Bika0e33fd2016-07-08 18:32:45 -0700887 outSize = snprintf(buf.get(), bufSize, "<field?> // field@%0*x", width, index);
Aart Bik69ae54a2015-07-01 14:52:26 -0700888 }
889 break;
890 case Instruction::kIndexVtableOffset:
Aart Bika0e33fd2016-07-08 18:32:45 -0700891 outSize = snprintf(buf.get(), bufSize, "[%0*x] // vtable #%0*x",
Aart Bik69ae54a2015-07-01 14:52:26 -0700892 width, index, width, index);
893 break;
894 case Instruction::kIndexFieldOffset:
Aart Bika0e33fd2016-07-08 18:32:45 -0700895 outSize = snprintf(buf.get(), bufSize, "[obj+%0*x]", width, index);
Aart Bik69ae54a2015-07-01 14:52:26 -0700896 break;
Orion Hodsonb34bb192016-10-18 17:02:58 +0100897 case Instruction::kIndexMethodAndProtoRef: {
Orion Hodsonc069a302017-01-18 09:23:12 +0000898 std::string method("<method?>");
899 std::string proto("<proto?>");
900 if (index < pDexFile->GetHeader().method_ids_size_) {
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800901 const dex::MethodId& pMethodId = pDexFile->GetMethodId(index);
Orion Hodsonc069a302017-01-18 09:23:12 +0000902 const char* name = pDexFile->StringDataByIdx(pMethodId.name_idx_);
903 const Signature signature = pDexFile->GetMethodSignature(pMethodId);
904 const char* backDescriptor = pDexFile->StringByTypeIdx(pMethodId.class_idx_);
905 method = android::base::StringPrintf("%s.%s:%s",
906 backDescriptor,
907 name,
908 signature.ToString().c_str());
Orion Hodsonb34bb192016-10-18 17:02:58 +0100909 }
Orion Hodsonc069a302017-01-18 09:23:12 +0000910 if (secondary_index < pDexFile->GetHeader().proto_ids_size_) {
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800911 const dex::ProtoId& protoId = pDexFile->GetProtoId(dex::ProtoIndex(secondary_index));
Orion Hodsonc069a302017-01-18 09:23:12 +0000912 const Signature signature = pDexFile->GetProtoSignature(protoId);
913 proto = signature.ToString();
914 }
915 outSize = snprintf(buf.get(), bufSize, "%s, %s // method@%0*x, proto@%0*x",
916 method.c_str(), proto.c_str(), width, index, width, secondary_index);
917 break;
918 }
919 case Instruction::kIndexCallSiteRef:
920 // Call site information is too large to detail in disassembly so just output the index.
921 outSize = snprintf(buf.get(), bufSize, "call_site@%0*x", width, index);
Orion Hodsonb34bb192016-10-18 17:02:58 +0100922 break;
Orion Hodson2e599942017-09-22 16:17:41 +0100923 case Instruction::kIndexMethodHandleRef:
924 // Method handle information is too large to detail in disassembly so just output the index.
925 outSize = snprintf(buf.get(), bufSize, "method_handle@%0*x", width, index);
926 break;
927 case Instruction::kIndexProtoRef:
928 if (index < pDexFile->GetHeader().proto_ids_size_) {
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800929 const dex::ProtoId& protoId = pDexFile->GetProtoId(dex::ProtoIndex(index));
Orion Hodson2e599942017-09-22 16:17:41 +0100930 const Signature signature = pDexFile->GetProtoSignature(protoId);
931 const std::string& proto = signature.ToString();
932 outSize = snprintf(buf.get(), bufSize, "%s // proto@%0*x", proto.c_str(), width, index);
933 } else {
934 outSize = snprintf(buf.get(), bufSize, "<?> // proto@%0*x", width, index);
935 }
Aart Bik69ae54a2015-07-01 14:52:26 -0700936 break;
937 } // switch
938
Orion Hodson2e599942017-09-22 16:17:41 +0100939 if (outSize == 0) {
940 // The index type has not been handled in the switch above.
941 outSize = snprintf(buf.get(), bufSize, "<?>");
942 }
943
Aart Bik69ae54a2015-07-01 14:52:26 -0700944 // Determine success of string construction.
945 if (outSize >= bufSize) {
Aart Bika0e33fd2016-07-08 18:32:45 -0700946 // The buffer wasn't big enough; retry with computed size. Note: snprintf()
947 // doesn't count/ the '\0' as part of its returned size, so we add explicit
948 // space for it here.
949 return indexString(pDexFile, pDecInsn, outSize + 1);
Aart Bik69ae54a2015-07-01 14:52:26 -0700950 }
951 return buf;
952}
953
954/*
955 * Dumps a single instruction.
956 */
957static void dumpInstruction(const DexFile* pDexFile,
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800958 const dex::CodeItem* pCode,
Aart Bik69ae54a2015-07-01 14:52:26 -0700959 u4 codeOffset, u4 insnIdx, u4 insnWidth,
960 const Instruction* pDecInsn) {
961 // Address of instruction (expressed as byte offset).
962 fprintf(gOutFile, "%06x:", codeOffset + 0x10 + insnIdx * 2);
963
964 // Dump (part of) raw bytes.
Mathieu Chartier698ebbc2018-01-05 11:00:42 -0800965 CodeItemInstructionAccessor accessor(*pDexFile, pCode);
Aart Bik69ae54a2015-07-01 14:52:26 -0700966 for (u4 i = 0; i < 8; i++) {
967 if (i < insnWidth) {
968 if (i == 7) {
969 fprintf(gOutFile, " ... ");
970 } else {
971 // Print 16-bit value in little-endian order.
Mathieu Chartier641a3af2017-12-15 11:42:58 -0800972 const u1* bytePtr = (const u1*) &accessor.Insns()[insnIdx + i];
Aart Bik69ae54a2015-07-01 14:52:26 -0700973 fprintf(gOutFile, " %02x%02x", bytePtr[0], bytePtr[1]);
974 }
975 } else {
976 fputs(" ", gOutFile);
977 }
978 } // for
979
980 // Dump pseudo-instruction or opcode.
981 if (pDecInsn->Opcode() == Instruction::NOP) {
Mathieu Chartier641a3af2017-12-15 11:42:58 -0800982 const u2 instr = get2LE((const u1*) &accessor.Insns()[insnIdx]);
Aart Bik69ae54a2015-07-01 14:52:26 -0700983 if (instr == Instruction::kPackedSwitchSignature) {
984 fprintf(gOutFile, "|%04x: packed-switch-data (%d units)", insnIdx, insnWidth);
985 } else if (instr == Instruction::kSparseSwitchSignature) {
986 fprintf(gOutFile, "|%04x: sparse-switch-data (%d units)", insnIdx, insnWidth);
987 } else if (instr == Instruction::kArrayDataSignature) {
988 fprintf(gOutFile, "|%04x: array-data (%d units)", insnIdx, insnWidth);
989 } else {
990 fprintf(gOutFile, "|%04x: nop // spacer", insnIdx);
991 }
992 } else {
993 fprintf(gOutFile, "|%04x: %s", insnIdx, pDecInsn->Name());
994 }
995
996 // Set up additional argument.
Aart Bika0e33fd2016-07-08 18:32:45 -0700997 std::unique_ptr<char[]> indexBuf;
Aart Bik69ae54a2015-07-01 14:52:26 -0700998 if (Instruction::IndexTypeOf(pDecInsn->Opcode()) != Instruction::kIndexNone) {
Aart Bika0e33fd2016-07-08 18:32:45 -0700999 indexBuf = indexString(pDexFile, pDecInsn, 200);
Aart Bik69ae54a2015-07-01 14:52:26 -07001000 }
1001
1002 // Dump the instruction.
1003 //
1004 // NOTE: pDecInsn->DumpString(pDexFile) differs too much from original.
1005 //
1006 switch (Instruction::FormatOf(pDecInsn->Opcode())) {
1007 case Instruction::k10x: // op
1008 break;
1009 case Instruction::k12x: // op vA, vB
1010 fprintf(gOutFile, " v%d, v%d", pDecInsn->VRegA(), pDecInsn->VRegB());
1011 break;
1012 case Instruction::k11n: // op vA, #+B
1013 fprintf(gOutFile, " v%d, #int %d // #%x",
1014 pDecInsn->VRegA(), (s4) pDecInsn->VRegB(), (u1)pDecInsn->VRegB());
1015 break;
1016 case Instruction::k11x: // op vAA
1017 fprintf(gOutFile, " v%d", pDecInsn->VRegA());
1018 break;
1019 case Instruction::k10t: // op +AA
Aart Bikdce50862016-06-10 16:04:03 -07001020 case Instruction::k20t: { // op +AAAA
1021 const s4 targ = (s4) pDecInsn->VRegA();
1022 fprintf(gOutFile, " %04x // %c%04x",
1023 insnIdx + targ,
1024 (targ < 0) ? '-' : '+',
1025 (targ < 0) ? -targ : targ);
Aart Bik69ae54a2015-07-01 14:52:26 -07001026 break;
Aart Bikdce50862016-06-10 16:04:03 -07001027 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001028 case Instruction::k22x: // op vAA, vBBBB
1029 fprintf(gOutFile, " v%d, v%d", pDecInsn->VRegA(), pDecInsn->VRegB());
1030 break;
Aart Bikdce50862016-06-10 16:04:03 -07001031 case Instruction::k21t: { // op vAA, +BBBB
1032 const s4 targ = (s4) pDecInsn->VRegB();
1033 fprintf(gOutFile, " v%d, %04x // %c%04x", pDecInsn->VRegA(),
1034 insnIdx + targ,
1035 (targ < 0) ? '-' : '+',
1036 (targ < 0) ? -targ : targ);
Aart Bik69ae54a2015-07-01 14:52:26 -07001037 break;
Aart Bikdce50862016-06-10 16:04:03 -07001038 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001039 case Instruction::k21s: // op vAA, #+BBBB
1040 fprintf(gOutFile, " v%d, #int %d // #%x",
1041 pDecInsn->VRegA(), (s4) pDecInsn->VRegB(), (u2)pDecInsn->VRegB());
1042 break;
1043 case Instruction::k21h: // op vAA, #+BBBB0000[00000000]
1044 // The printed format varies a bit based on the actual opcode.
1045 if (pDecInsn->Opcode() == Instruction::CONST_HIGH16) {
1046 const s4 value = pDecInsn->VRegB() << 16;
1047 fprintf(gOutFile, " v%d, #int %d // #%x",
1048 pDecInsn->VRegA(), value, (u2) pDecInsn->VRegB());
1049 } else {
1050 const s8 value = ((s8) pDecInsn->VRegB()) << 48;
1051 fprintf(gOutFile, " v%d, #long %" PRId64 " // #%x",
1052 pDecInsn->VRegA(), value, (u2) pDecInsn->VRegB());
1053 }
1054 break;
1055 case Instruction::k21c: // op vAA, thing@BBBB
1056 case Instruction::k31c: // op vAA, thing@BBBBBBBB
Aart Bika0e33fd2016-07-08 18:32:45 -07001057 fprintf(gOutFile, " v%d, %s", pDecInsn->VRegA(), indexBuf.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001058 break;
1059 case Instruction::k23x: // op vAA, vBB, vCC
1060 fprintf(gOutFile, " v%d, v%d, v%d",
1061 pDecInsn->VRegA(), pDecInsn->VRegB(), pDecInsn->VRegC());
1062 break;
1063 case Instruction::k22b: // op vAA, vBB, #+CC
1064 fprintf(gOutFile, " v%d, v%d, #int %d // #%02x",
1065 pDecInsn->VRegA(), pDecInsn->VRegB(),
1066 (s4) pDecInsn->VRegC(), (u1) pDecInsn->VRegC());
1067 break;
Aart Bikdce50862016-06-10 16:04:03 -07001068 case Instruction::k22t: { // op vA, vB, +CCCC
1069 const s4 targ = (s4) pDecInsn->VRegC();
1070 fprintf(gOutFile, " v%d, v%d, %04x // %c%04x",
1071 pDecInsn->VRegA(), pDecInsn->VRegB(),
1072 insnIdx + targ,
1073 (targ < 0) ? '-' : '+',
1074 (targ < 0) ? -targ : targ);
Aart Bik69ae54a2015-07-01 14:52:26 -07001075 break;
Aart Bikdce50862016-06-10 16:04:03 -07001076 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001077 case Instruction::k22s: // op vA, vB, #+CCCC
1078 fprintf(gOutFile, " v%d, v%d, #int %d // #%04x",
1079 pDecInsn->VRegA(), pDecInsn->VRegB(),
1080 (s4) pDecInsn->VRegC(), (u2) pDecInsn->VRegC());
1081 break;
1082 case Instruction::k22c: // op vA, vB, thing@CCCC
1083 // NOT SUPPORTED:
1084 // case Instruction::k22cs: // [opt] op vA, vB, field offset CCCC
1085 fprintf(gOutFile, " v%d, v%d, %s",
Aart Bika0e33fd2016-07-08 18:32:45 -07001086 pDecInsn->VRegA(), pDecInsn->VRegB(), indexBuf.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001087 break;
1088 case Instruction::k30t:
1089 fprintf(gOutFile, " #%08x", pDecInsn->VRegA());
1090 break;
Aart Bikdce50862016-06-10 16:04:03 -07001091 case Instruction::k31i: { // op vAA, #+BBBBBBBB
1092 // This is often, but not always, a float.
1093 union {
1094 float f;
1095 u4 i;
1096 } conv;
1097 conv.i = pDecInsn->VRegB();
1098 fprintf(gOutFile, " v%d, #float %g // #%08x",
1099 pDecInsn->VRegA(), conv.f, pDecInsn->VRegB());
Aart Bik69ae54a2015-07-01 14:52:26 -07001100 break;
Aart Bikdce50862016-06-10 16:04:03 -07001101 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001102 case Instruction::k31t: // op vAA, offset +BBBBBBBB
1103 fprintf(gOutFile, " v%d, %08x // +%08x",
1104 pDecInsn->VRegA(), insnIdx + pDecInsn->VRegB(), pDecInsn->VRegB());
1105 break;
1106 case Instruction::k32x: // op vAAAA, vBBBB
1107 fprintf(gOutFile, " v%d, v%d", pDecInsn->VRegA(), pDecInsn->VRegB());
1108 break;
Orion Hodsonb34bb192016-10-18 17:02:58 +01001109 case Instruction::k35c: // op {vC, vD, vE, vF, vG}, thing@BBBB
1110 case Instruction::k45cc: { // op {vC, vD, vE, vF, vG}, method@BBBB, proto@HHHH
Aart Bik69ae54a2015-07-01 14:52:26 -07001111 // NOT SUPPORTED:
1112 // case Instruction::k35ms: // [opt] invoke-virtual+super
1113 // case Instruction::k35mi: // [opt] inline invoke
Aart Bikdce50862016-06-10 16:04:03 -07001114 u4 arg[Instruction::kMaxVarArgRegs];
1115 pDecInsn->GetVarArgs(arg);
1116 fputs(" {", gOutFile);
1117 for (int i = 0, n = pDecInsn->VRegA(); i < n; i++) {
1118 if (i == 0) {
1119 fprintf(gOutFile, "v%d", arg[i]);
1120 } else {
1121 fprintf(gOutFile, ", v%d", arg[i]);
1122 }
1123 } // for
Aart Bika0e33fd2016-07-08 18:32:45 -07001124 fprintf(gOutFile, "}, %s", indexBuf.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001125 break;
Aart Bikdce50862016-06-10 16:04:03 -07001126 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001127 case Instruction::k3rc: // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB
Orion Hodsonb34bb192016-10-18 17:02:58 +01001128 case Instruction::k4rcc: { // op {vCCCC .. v(CCCC+AA-1)}, method@BBBB, proto@HHHH
Aart Bik69ae54a2015-07-01 14:52:26 -07001129 // NOT SUPPORTED:
1130 // case Instruction::k3rms: // [opt] invoke-virtual+super/range
1131 // case Instruction::k3rmi: // [opt] execute-inline/range
Aart Bik69ae54a2015-07-01 14:52:26 -07001132 // This doesn't match the "dx" output when some of the args are
1133 // 64-bit values -- dx only shows the first register.
1134 fputs(" {", gOutFile);
1135 for (int i = 0, n = pDecInsn->VRegA(); i < n; i++) {
1136 if (i == 0) {
1137 fprintf(gOutFile, "v%d", pDecInsn->VRegC() + i);
1138 } else {
1139 fprintf(gOutFile, ", v%d", pDecInsn->VRegC() + i);
1140 }
1141 } // for
Aart Bika0e33fd2016-07-08 18:32:45 -07001142 fprintf(gOutFile, "}, %s", indexBuf.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001143 }
1144 break;
Aart Bikdce50862016-06-10 16:04:03 -07001145 case Instruction::k51l: { // op vAA, #+BBBBBBBBBBBBBBBB
1146 // This is often, but not always, a double.
1147 union {
1148 double d;
1149 u8 j;
1150 } conv;
1151 conv.j = pDecInsn->WideVRegB();
1152 fprintf(gOutFile, " v%d, #double %g // #%016" PRIx64,
1153 pDecInsn->VRegA(), conv.d, pDecInsn->WideVRegB());
Aart Bik69ae54a2015-07-01 14:52:26 -07001154 break;
Aart Bikdce50862016-06-10 16:04:03 -07001155 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001156 // NOT SUPPORTED:
1157 // case Instruction::k00x: // unknown op or breakpoint
1158 // break;
1159 default:
1160 fprintf(gOutFile, " ???");
1161 break;
1162 } // switch
1163
1164 fputc('\n', gOutFile);
Aart Bik69ae54a2015-07-01 14:52:26 -07001165}
1166
1167/*
1168 * Dumps a bytecode disassembly.
1169 */
1170static void dumpBytecodes(const DexFile* pDexFile, u4 idx,
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001171 const dex::CodeItem* pCode, u4 codeOffset) {
1172 const dex::MethodId& pMethodId = pDexFile->GetMethodId(idx);
Aart Bik69ae54a2015-07-01 14:52:26 -07001173 const char* name = pDexFile->StringDataByIdx(pMethodId.name_idx_);
1174 const Signature signature = pDexFile->GetMethodSignature(pMethodId);
1175 const char* backDescriptor = pDexFile->StringByTypeIdx(pMethodId.class_idx_);
1176
1177 // Generate header.
Aart Bikc05e2f22016-07-12 15:53:13 -07001178 std::unique_ptr<char[]> dot(descriptorToDot(backDescriptor));
1179 fprintf(gOutFile, "%06x: |[%06x] %s.%s:%s\n",
1180 codeOffset, codeOffset, dot.get(), name, signature.ToString().c_str());
Aart Bik69ae54a2015-07-01 14:52:26 -07001181
1182 // Iterate over all instructions.
Mathieu Chartier698ebbc2018-01-05 11:00:42 -08001183 CodeItemDataAccessor accessor(*pDexFile, pCode);
Aart Bik7a9aaf12018-02-05 17:00:40 -08001184 const u4 maxPc = accessor.InsnsSizeInCodeUnits();
Mathieu Chartier641a3af2017-12-15 11:42:58 -08001185 for (const DexInstructionPcPair& pair : accessor) {
Aart Bik7a9aaf12018-02-05 17:00:40 -08001186 const u4 dexPc = pair.DexPc();
1187 if (dexPc >= maxPc) {
1188 LOG(WARNING) << "GLITCH: run-away instruction at idx=0x" << std::hex << dexPc;
1189 break;
1190 }
Mathieu Chartier641a3af2017-12-15 11:42:58 -08001191 const Instruction* instruction = &pair.Inst();
Aart Bik69ae54a2015-07-01 14:52:26 -07001192 const u4 insnWidth = instruction->SizeInCodeUnits();
1193 if (insnWidth == 0) {
Aart Bik7a9aaf12018-02-05 17:00:40 -08001194 LOG(WARNING) << "GLITCH: zero-width instruction at idx=0x" << std::hex << dexPc;
Aart Bik69ae54a2015-07-01 14:52:26 -07001195 break;
1196 }
Aart Bik7a9aaf12018-02-05 17:00:40 -08001197 dumpInstruction(pDexFile, pCode, codeOffset, dexPc, insnWidth, instruction);
Aart Bik69ae54a2015-07-01 14:52:26 -07001198 } // for
1199}
1200
1201/*
1202 * Dumps code of a method.
1203 */
1204static void dumpCode(const DexFile* pDexFile, u4 idx, u4 flags,
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001205 const dex::CodeItem* pCode, u4 codeOffset) {
Mathieu Chartier8892c6b2018-01-09 15:10:17 -08001206 CodeItemDebugInfoAccessor accessor(*pDexFile, pCode, idx);
Mathieu Chartier641a3af2017-12-15 11:42:58 -08001207
1208 fprintf(gOutFile, " registers : %d\n", accessor.RegistersSize());
1209 fprintf(gOutFile, " ins : %d\n", accessor.InsSize());
1210 fprintf(gOutFile, " outs : %d\n", accessor.OutsSize());
Aart Bik69ae54a2015-07-01 14:52:26 -07001211 fprintf(gOutFile, " insns size : %d 16-bit code units\n",
Mathieu Chartier641a3af2017-12-15 11:42:58 -08001212 accessor.InsnsSizeInCodeUnits());
Aart Bik69ae54a2015-07-01 14:52:26 -07001213
1214 // Bytecode disassembly, if requested.
1215 if (gOptions.disassemble) {
1216 dumpBytecodes(pDexFile, idx, pCode, codeOffset);
1217 }
1218
1219 // Try-catch blocks.
1220 dumpCatches(pDexFile, pCode);
1221
1222 // Positions and locals table in the debug info.
1223 bool is_static = (flags & kAccStatic) != 0;
1224 fprintf(gOutFile, " positions : \n");
Mathieu Chartier3e2e1232018-09-11 12:35:30 -07001225 accessor.DecodeDebugPositionInfo([&](const DexFile::PositionInfo& entry) {
1226 fprintf(gOutFile, " 0x%04x line=%d\n", entry.address_, entry.line_);
1227 return false;
1228 });
Aart Bik69ae54a2015-07-01 14:52:26 -07001229 fprintf(gOutFile, " locals : \n");
Mathieu Chartiere5afbf32018-09-12 17:51:54 -07001230 accessor.DecodeDebugLocalInfo(is_static,
1231 idx,
1232 [&](const DexFile::LocalInfo& entry) {
1233 const char* signature = entry.signature_ != nullptr ? entry.signature_ : "";
1234 fprintf(gOutFile,
1235 " 0x%04x - 0x%04x reg=%d %s %s %s\n",
1236 entry.start_address_,
1237 entry.end_address_,
1238 entry.reg_,
1239 entry.name_,
1240 entry.descriptor_,
1241 signature);
1242 });
Aart Bik69ae54a2015-07-01 14:52:26 -07001243}
1244
David Brazdil8c4d7172019-01-21 19:45:28 +00001245static std::string GetHiddenapiFlagStr(uint32_t hiddenapi_flags) {
1246 std::stringstream ss;
1247 hiddenapi::ApiList api_list(hiddenapi_flags);
1248 api_list.Dump(ss);
1249 std::string str_api_list = ss.str();
1250 std::transform(str_api_list.begin(), str_api_list.end(), str_api_list.begin(), ::toupper);
1251 return str_api_list;
1252}
1253
Aart Bik69ae54a2015-07-01 14:52:26 -07001254/*
1255 * Dumps a method.
1256 */
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001257static void dumpMethod(const ClassAccessor::Method& method, int i) {
Aart Bik69ae54a2015-07-01 14:52:26 -07001258 // Bail for anything private if export only requested.
David Brazdil20c765f2018-10-27 21:45:15 +00001259 const uint32_t flags = method.GetAccessFlags();
Aart Bik69ae54a2015-07-01 14:52:26 -07001260 if (gOptions.exportsOnly && (flags & (kAccPublic | kAccProtected)) == 0) {
1261 return;
1262 }
1263
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001264 const DexFile& dex_file = method.GetDexFile();
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001265 const dex::MethodId& pMethodId = dex_file.GetMethodId(method.GetIndex());
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001266 const char* name = dex_file.StringDataByIdx(pMethodId.name_idx_);
1267 const Signature signature = dex_file.GetMethodSignature(pMethodId);
Aart Bik69ae54a2015-07-01 14:52:26 -07001268 char* typeDescriptor = strdup(signature.ToString().c_str());
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001269 const char* backDescriptor = dex_file.StringByTypeIdx(pMethodId.class_idx_);
Aart Bik69ae54a2015-07-01 14:52:26 -07001270 char* accessStr = createAccessFlagStr(flags, kAccessForMethod);
David Brazdil8c4d7172019-01-21 19:45:28 +00001271 const uint32_t hiddenapiFlags = method.GetHiddenapiFlags();
Aart Bik69ae54a2015-07-01 14:52:26 -07001272
1273 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1274 fprintf(gOutFile, " #%d : (in %s)\n", i, backDescriptor);
1275 fprintf(gOutFile, " name : '%s'\n", name);
1276 fprintf(gOutFile, " type : '%s'\n", typeDescriptor);
1277 fprintf(gOutFile, " access : 0x%04x (%s)\n", flags, accessStr);
Eric Holk4ac8d962020-03-30 10:44:30 -07001278 if (gOptions.showSectionHeaders) {
1279 fprintf(gOutFile, " method_idx : %d\n", method.GetIndex());
1280 }
David Brazdil8c4d7172019-01-21 19:45:28 +00001281 if (hiddenapiFlags != 0u) {
1282 fprintf(gOutFile,
1283 " hiddenapi : 0x%04x (%s)\n",
1284 hiddenapiFlags,
1285 GetHiddenapiFlagStr(hiddenapiFlags).c_str());
1286 }
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001287 if (method.GetCodeItem() == nullptr) {
Aart Bik69ae54a2015-07-01 14:52:26 -07001288 fprintf(gOutFile, " code : (none)\n");
1289 } else {
1290 fprintf(gOutFile, " code -\n");
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001291 dumpCode(&dex_file,
1292 method.GetIndex(),
1293 flags,
1294 method.GetCodeItem(),
1295 method.GetCodeItemOffset());
Aart Bik69ae54a2015-07-01 14:52:26 -07001296 }
1297 if (gOptions.disassemble) {
1298 fputc('\n', gOutFile);
1299 }
1300 } else if (gOptions.outputFormat == OUTPUT_XML) {
1301 const bool constructor = (name[0] == '<');
1302
1303 // Method name and prototype.
1304 if (constructor) {
Orion Hodsonfe42d212018-08-24 14:01:14 +01001305 std::unique_ptr<char[]> dot(descriptorClassToName(backDescriptor));
Aart Bikc05e2f22016-07-12 15:53:13 -07001306 fprintf(gOutFile, "<constructor name=\"%s\"\n", dot.get());
1307 dot = descriptorToDot(backDescriptor);
1308 fprintf(gOutFile, " type=\"%s\"\n", dot.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001309 } else {
1310 fprintf(gOutFile, "<method name=\"%s\"\n", name);
1311 const char* returnType = strrchr(typeDescriptor, ')');
1312 if (returnType == nullptr) {
Andreas Gampe221d9812018-01-22 17:48:56 -08001313 LOG(ERROR) << "bad method type descriptor '" << typeDescriptor << "'";
Aart Bik69ae54a2015-07-01 14:52:26 -07001314 goto bail;
1315 }
Aart Bikc05e2f22016-07-12 15:53:13 -07001316 std::unique_ptr<char[]> dot(descriptorToDot(returnType + 1));
1317 fprintf(gOutFile, " return=\"%s\"\n", dot.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001318 fprintf(gOutFile, " abstract=%s\n", quotedBool((flags & kAccAbstract) != 0));
1319 fprintf(gOutFile, " native=%s\n", quotedBool((flags & kAccNative) != 0));
1320 fprintf(gOutFile, " synchronized=%s\n", quotedBool(
1321 (flags & (kAccSynchronized | kAccDeclaredSynchronized)) != 0));
1322 }
1323
1324 // Additional method flags.
1325 fprintf(gOutFile, " static=%s\n", quotedBool((flags & kAccStatic) != 0));
1326 fprintf(gOutFile, " final=%s\n", quotedBool((flags & kAccFinal) != 0));
1327 // The "deprecated=" not knowable w/o parsing annotations.
1328 fprintf(gOutFile, " visibility=%s\n>\n", quotedVisibility(flags));
1329
1330 // Parameters.
1331 if (typeDescriptor[0] != '(') {
Andreas Gampe221d9812018-01-22 17:48:56 -08001332 LOG(ERROR) << "ERROR: bad descriptor '" << typeDescriptor << "'";
Aart Bik69ae54a2015-07-01 14:52:26 -07001333 goto bail;
1334 }
1335 char* tmpBuf = reinterpret_cast<char*>(malloc(strlen(typeDescriptor) + 1));
1336 const char* base = typeDescriptor + 1;
1337 int argNum = 0;
1338 while (*base != ')') {
1339 char* cp = tmpBuf;
1340 while (*base == '[') {
1341 *cp++ = *base++;
1342 }
1343 if (*base == 'L') {
1344 // Copy through ';'.
1345 do {
1346 *cp = *base++;
1347 } while (*cp++ != ';');
1348 } else {
1349 // Primitive char, copy it.
Aart Bikc05e2f22016-07-12 15:53:13 -07001350 if (strchr("ZBCSIFJD", *base) == nullptr) {
Andreas Gampe221d9812018-01-22 17:48:56 -08001351 LOG(ERROR) << "ERROR: bad method signature '" << base << "'";
Aart Bika0e33fd2016-07-08 18:32:45 -07001352 break; // while
Aart Bik69ae54a2015-07-01 14:52:26 -07001353 }
1354 *cp++ = *base++;
1355 }
1356 // Null terminate and display.
1357 *cp++ = '\0';
Aart Bikc05e2f22016-07-12 15:53:13 -07001358 std::unique_ptr<char[]> dot(descriptorToDot(tmpBuf));
Aart Bik69ae54a2015-07-01 14:52:26 -07001359 fprintf(gOutFile, "<parameter name=\"arg%d\" type=\"%s\">\n"
Aart Bikc05e2f22016-07-12 15:53:13 -07001360 "</parameter>\n", argNum++, dot.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001361 } // while
1362 free(tmpBuf);
1363 if (constructor) {
1364 fprintf(gOutFile, "</constructor>\n");
1365 } else {
1366 fprintf(gOutFile, "</method>\n");
1367 }
1368 }
1369
1370 bail:
1371 free(typeDescriptor);
1372 free(accessStr);
1373}
1374
1375/*
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001376 * Dumps a static or instance (class) field.
Aart Bik69ae54a2015-07-01 14:52:26 -07001377 */
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001378static void dumpField(const ClassAccessor::Field& field, int i, const u1** data = nullptr) {
Aart Bik69ae54a2015-07-01 14:52:26 -07001379 // Bail for anything private if export only requested.
David Brazdil20c765f2018-10-27 21:45:15 +00001380 const uint32_t flags = field.GetAccessFlags();
Aart Bik69ae54a2015-07-01 14:52:26 -07001381 if (gOptions.exportsOnly && (flags & (kAccPublic | kAccProtected)) == 0) {
1382 return;
1383 }
1384
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001385 const DexFile& dex_file = field.GetDexFile();
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001386 const dex::FieldId& field_id = dex_file.GetFieldId(field.GetIndex());
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001387 const char* name = dex_file.StringDataByIdx(field_id.name_idx_);
1388 const char* typeDescriptor = dex_file.StringByTypeIdx(field_id.type_idx_);
1389 const char* backDescriptor = dex_file.StringByTypeIdx(field_id.class_idx_);
Aart Bik69ae54a2015-07-01 14:52:26 -07001390 char* accessStr = createAccessFlagStr(flags, kAccessForField);
David Brazdil8c4d7172019-01-21 19:45:28 +00001391 const uint32_t hiddenapiFlags = field.GetHiddenapiFlags();
Aart Bik69ae54a2015-07-01 14:52:26 -07001392
1393 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1394 fprintf(gOutFile, " #%d : (in %s)\n", i, backDescriptor);
1395 fprintf(gOutFile, " name : '%s'\n", name);
1396 fprintf(gOutFile, " type : '%s'\n", typeDescriptor);
1397 fprintf(gOutFile, " access : 0x%04x (%s)\n", flags, accessStr);
David Brazdil8c4d7172019-01-21 19:45:28 +00001398 if (hiddenapiFlags != 0u) {
1399 fprintf(gOutFile,
1400 " hiddenapi : 0x%04x (%s)\n",
1401 hiddenapiFlags,
1402 GetHiddenapiFlagStr(hiddenapiFlags).c_str());
1403 }
Aart Bikdce50862016-06-10 16:04:03 -07001404 if (data != nullptr) {
Shinichiro Hamaji82863f02015-11-05 16:51:33 +09001405 fputs(" value : ", gOutFile);
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001406 dumpEncodedValue(&dex_file, data);
Shinichiro Hamaji82863f02015-11-05 16:51:33 +09001407 fputs("\n", gOutFile);
1408 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001409 } else if (gOptions.outputFormat == OUTPUT_XML) {
1410 fprintf(gOutFile, "<field name=\"%s\"\n", name);
Aart Bikc05e2f22016-07-12 15:53:13 -07001411 std::unique_ptr<char[]> dot(descriptorToDot(typeDescriptor));
1412 fprintf(gOutFile, " type=\"%s\"\n", dot.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001413 fprintf(gOutFile, " transient=%s\n", quotedBool((flags & kAccTransient) != 0));
1414 fprintf(gOutFile, " volatile=%s\n", quotedBool((flags & kAccVolatile) != 0));
1415 // The "value=" is not knowable w/o parsing annotations.
1416 fprintf(gOutFile, " static=%s\n", quotedBool((flags & kAccStatic) != 0));
1417 fprintf(gOutFile, " final=%s\n", quotedBool((flags & kAccFinal) != 0));
1418 // The "deprecated=" is not knowable w/o parsing annotations.
1419 fprintf(gOutFile, " visibility=%s\n", quotedVisibility(flags));
Aart Bikdce50862016-06-10 16:04:03 -07001420 if (data != nullptr) {
Shinichiro Hamaji82863f02015-11-05 16:51:33 +09001421 fputs(" value=\"", gOutFile);
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001422 dumpEncodedValue(&dex_file, data);
Shinichiro Hamaji82863f02015-11-05 16:51:33 +09001423 fputs("\"\n", gOutFile);
1424 }
1425 fputs(">\n</field>\n", gOutFile);
Aart Bik69ae54a2015-07-01 14:52:26 -07001426 }
1427
1428 free(accessStr);
1429}
1430
1431/*
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001432 * Dumping a CFG.
Aart Bik69ae54a2015-07-01 14:52:26 -07001433 */
Andreas Gampe5073fed2015-08-10 11:40:25 -07001434static void dumpCfg(const DexFile* dex_file, int idx) {
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001435 ClassAccessor accessor(*dex_file, dex_file->GetClassDef(idx));
1436 for (const ClassAccessor::Method& method : accessor.GetMethods()) {
1437 if (method.GetCodeItem() != nullptr) {
1438 std::ostringstream oss;
1439 DumpMethodCFG(method, oss);
1440 fputs(oss.str().c_str(), gOutFile);
1441 }
Andreas Gampe5073fed2015-08-10 11:40:25 -07001442 }
Andreas Gampe5073fed2015-08-10 11:40:25 -07001443}
1444
1445/*
Aart Bik69ae54a2015-07-01 14:52:26 -07001446 * Dumps the class.
1447 *
1448 * Note "idx" is a DexClassDef index, not a DexTypeId index.
1449 *
1450 * If "*pLastPackage" is nullptr or does not match the current class' package,
1451 * the value will be replaced with a newly-allocated string.
1452 */
1453static void dumpClass(const DexFile* pDexFile, int idx, char** pLastPackage) {
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001454 const dex::ClassDef& pClassDef = pDexFile->GetClassDef(idx);
Aart Bik69ae54a2015-07-01 14:52:26 -07001455
1456 // Omitting non-public class.
1457 if (gOptions.exportsOnly && (pClassDef.access_flags_ & kAccPublic) == 0) {
1458 return;
1459 }
1460
Aart Bikdce50862016-06-10 16:04:03 -07001461 if (gOptions.showSectionHeaders) {
1462 dumpClassDef(pDexFile, idx);
1463 }
1464
1465 if (gOptions.showAnnotations) {
1466 dumpClassAnnotations(pDexFile, idx);
1467 }
1468
1469 if (gOptions.showCfg) {
Andreas Gampe5073fed2015-08-10 11:40:25 -07001470 dumpCfg(pDexFile, idx);
1471 return;
1472 }
1473
Aart Bik69ae54a2015-07-01 14:52:26 -07001474 // For the XML output, show the package name. Ideally we'd gather
1475 // up the classes, sort them, and dump them alphabetically so the
1476 // package name wouldn't jump around, but that's not a great plan
1477 // for something that needs to run on the device.
1478 const char* classDescriptor = pDexFile->StringByTypeIdx(pClassDef.class_idx_);
1479 if (!(classDescriptor[0] == 'L' &&
1480 classDescriptor[strlen(classDescriptor)-1] == ';')) {
1481 // Arrays and primitives should not be defined explicitly. Keep going?
Andreas Gampe221d9812018-01-22 17:48:56 -08001482 LOG(WARNING) << "Malformed class name '" << classDescriptor << "'";
Aart Bik69ae54a2015-07-01 14:52:26 -07001483 } else if (gOptions.outputFormat == OUTPUT_XML) {
1484 char* mangle = strdup(classDescriptor + 1);
1485 mangle[strlen(mangle)-1] = '\0';
1486
1487 // Reduce to just the package name.
1488 char* lastSlash = strrchr(mangle, '/');
1489 if (lastSlash != nullptr) {
1490 *lastSlash = '\0';
1491 } else {
1492 *mangle = '\0';
1493 }
1494
1495 for (char* cp = mangle; *cp != '\0'; cp++) {
1496 if (*cp == '/') {
1497 *cp = '.';
1498 }
1499 } // for
1500
1501 if (*pLastPackage == nullptr || strcmp(mangle, *pLastPackage) != 0) {
1502 // Start of a new package.
1503 if (*pLastPackage != nullptr) {
1504 fprintf(gOutFile, "</package>\n");
1505 }
1506 fprintf(gOutFile, "<package name=\"%s\"\n>\n", mangle);
1507 free(*pLastPackage);
1508 *pLastPackage = mangle;
1509 } else {
1510 free(mangle);
1511 }
1512 }
1513
1514 // General class information.
1515 char* accessStr = createAccessFlagStr(pClassDef.access_flags_, kAccessForClass);
1516 const char* superclassDescriptor;
Andreas Gampea5b09a62016-11-17 15:21:22 -08001517 if (!pClassDef.superclass_idx_.IsValid()) {
Aart Bik69ae54a2015-07-01 14:52:26 -07001518 superclassDescriptor = nullptr;
1519 } else {
1520 superclassDescriptor = pDexFile->StringByTypeIdx(pClassDef.superclass_idx_);
1521 }
1522 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1523 fprintf(gOutFile, "Class #%d -\n", idx);
1524 fprintf(gOutFile, " Class descriptor : '%s'\n", classDescriptor);
1525 fprintf(gOutFile, " Access flags : 0x%04x (%s)\n", pClassDef.access_flags_, accessStr);
1526 if (superclassDescriptor != nullptr) {
1527 fprintf(gOutFile, " Superclass : '%s'\n", superclassDescriptor);
1528 }
1529 fprintf(gOutFile, " Interfaces -\n");
1530 } else {
Orion Hodsonfe42d212018-08-24 14:01:14 +01001531 std::unique_ptr<char[]> dot(descriptorClassToName(classDescriptor));
Aart Bikc05e2f22016-07-12 15:53:13 -07001532 fprintf(gOutFile, "<class name=\"%s\"\n", dot.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001533 if (superclassDescriptor != nullptr) {
Aart Bikc05e2f22016-07-12 15:53:13 -07001534 dot = descriptorToDot(superclassDescriptor);
1535 fprintf(gOutFile, " extends=\"%s\"\n", dot.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001536 }
Alex Light1f12e282015-12-10 16:49:47 -08001537 fprintf(gOutFile, " interface=%s\n",
1538 quotedBool((pClassDef.access_flags_ & kAccInterface) != 0));
Aart Bik69ae54a2015-07-01 14:52:26 -07001539 fprintf(gOutFile, " abstract=%s\n", quotedBool((pClassDef.access_flags_ & kAccAbstract) != 0));
1540 fprintf(gOutFile, " static=%s\n", quotedBool((pClassDef.access_flags_ & kAccStatic) != 0));
1541 fprintf(gOutFile, " final=%s\n", quotedBool((pClassDef.access_flags_ & kAccFinal) != 0));
1542 // The "deprecated=" not knowable w/o parsing annotations.
1543 fprintf(gOutFile, " visibility=%s\n", quotedVisibility(pClassDef.access_flags_));
1544 fprintf(gOutFile, ">\n");
1545 }
1546
1547 // Interfaces.
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001548 const dex::TypeList* pInterfaces = pDexFile->GetInterfacesList(pClassDef);
Aart Bik69ae54a2015-07-01 14:52:26 -07001549 if (pInterfaces != nullptr) {
1550 for (u4 i = 0; i < pInterfaces->Size(); i++) {
1551 dumpInterface(pDexFile, pInterfaces->GetTypeItem(i), i);
1552 } // for
1553 }
1554
1555 // Fields and methods.
David Brazdil8c4d7172019-01-21 19:45:28 +00001556 ClassAccessor accessor(*pDexFile, pClassDef, /* parse_hiddenapi_class_data= */ true);
Aart Bikdce50862016-06-10 16:04:03 -07001557
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001558 // Prepare data for static fields.
1559 const u1* sData = pDexFile->GetEncodedStaticFieldValuesArray(pClassDef);
1560 const u4 sSize = sData != nullptr ? DecodeUnsignedLeb128(&sData) : 0;
Aart Bikdce50862016-06-10 16:04:03 -07001561
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001562 // Static fields.
1563 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1564 fprintf(gOutFile, " Static fields -\n");
1565 }
1566 uint32_t i = 0u;
1567 for (const ClassAccessor::Field& field : accessor.GetStaticFields()) {
1568 dumpField(field, i, i < sSize ? &sData : nullptr);
1569 ++i;
1570 }
Aart Bikdce50862016-06-10 16:04:03 -07001571
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001572 // Instance fields.
1573 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1574 fprintf(gOutFile, " Instance fields -\n");
1575 }
1576 i = 0u;
1577 for (const ClassAccessor::Field& field : accessor.GetInstanceFields()) {
1578 dumpField(field, i);
1579 ++i;
1580 }
Aart Bikdce50862016-06-10 16:04:03 -07001581
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001582 // Direct methods.
1583 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1584 fprintf(gOutFile, " Direct methods -\n");
1585 }
1586 i = 0u;
1587 for (const ClassAccessor::Method& method : accessor.GetDirectMethods()) {
1588 dumpMethod(method, i);
1589 ++i;
1590 }
Aart Bikdce50862016-06-10 16:04:03 -07001591
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001592 // Virtual methods.
1593 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1594 fprintf(gOutFile, " Virtual methods -\n");
1595 }
1596 i = 0u;
1597 for (const ClassAccessor::Method& method : accessor.GetVirtualMethods()) {
1598 dumpMethod(method, i);
1599 ++i;
Aart Bik69ae54a2015-07-01 14:52:26 -07001600 }
1601
1602 // End of class.
1603 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1604 const char* fileName;
Andreas Gampe8a0128a2016-11-28 07:38:35 -08001605 if (pClassDef.source_file_idx_.IsValid()) {
Aart Bik69ae54a2015-07-01 14:52:26 -07001606 fileName = pDexFile->StringDataByIdx(pClassDef.source_file_idx_);
1607 } else {
1608 fileName = "unknown";
1609 }
1610 fprintf(gOutFile, " source_file_idx : %d (%s)\n\n",
Andreas Gampe8a0128a2016-11-28 07:38:35 -08001611 pClassDef.source_file_idx_.index_, fileName);
Aart Bik69ae54a2015-07-01 14:52:26 -07001612 } else if (gOptions.outputFormat == OUTPUT_XML) {
1613 fprintf(gOutFile, "</class>\n");
1614 }
1615
1616 free(accessStr);
1617}
1618
Orion Hodsonc069a302017-01-18 09:23:12 +00001619static void dumpMethodHandle(const DexFile* pDexFile, u4 idx) {
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001620 const dex::MethodHandleItem& mh = pDexFile->GetMethodHandle(idx);
Orion Hodson631827d2017-04-10 14:53:47 +01001621 const char* type = nullptr;
1622 bool is_instance = false;
Orion Hodsonc069a302017-01-18 09:23:12 +00001623 bool is_invoke = false;
Orion Hodsonc069a302017-01-18 09:23:12 +00001624 switch (static_cast<DexFile::MethodHandleType>(mh.method_handle_type_)) {
1625 case DexFile::MethodHandleType::kStaticPut:
1626 type = "put-static";
Orion Hodson631827d2017-04-10 14:53:47 +01001627 is_instance = false;
1628 is_invoke = false;
Orion Hodsonc069a302017-01-18 09:23:12 +00001629 break;
1630 case DexFile::MethodHandleType::kStaticGet:
1631 type = "get-static";
Orion Hodson631827d2017-04-10 14:53:47 +01001632 is_instance = false;
1633 is_invoke = false;
Orion Hodsonc069a302017-01-18 09:23:12 +00001634 break;
1635 case DexFile::MethodHandleType::kInstancePut:
1636 type = "put-instance";
Orion Hodson631827d2017-04-10 14:53:47 +01001637 is_instance = true;
1638 is_invoke = false;
Orion Hodsonc069a302017-01-18 09:23:12 +00001639 break;
1640 case DexFile::MethodHandleType::kInstanceGet:
1641 type = "get-instance";
Orion Hodson631827d2017-04-10 14:53:47 +01001642 is_instance = true;
1643 is_invoke = false;
Orion Hodsonc069a302017-01-18 09:23:12 +00001644 break;
1645 case DexFile::MethodHandleType::kInvokeStatic:
1646 type = "invoke-static";
Orion Hodson631827d2017-04-10 14:53:47 +01001647 is_instance = false;
Orion Hodsonc069a302017-01-18 09:23:12 +00001648 is_invoke = true;
1649 break;
1650 case DexFile::MethodHandleType::kInvokeInstance:
1651 type = "invoke-instance";
Orion Hodson631827d2017-04-10 14:53:47 +01001652 is_instance = true;
Orion Hodsonc069a302017-01-18 09:23:12 +00001653 is_invoke = true;
1654 break;
1655 case DexFile::MethodHandleType::kInvokeConstructor:
1656 type = "invoke-constructor";
Orion Hodson631827d2017-04-10 14:53:47 +01001657 is_instance = true;
1658 is_invoke = true;
1659 break;
1660 case DexFile::MethodHandleType::kInvokeDirect:
1661 type = "invoke-direct";
1662 is_instance = true;
1663 is_invoke = true;
1664 break;
1665 case DexFile::MethodHandleType::kInvokeInterface:
1666 type = "invoke-interface";
1667 is_instance = true;
Orion Hodsonc069a302017-01-18 09:23:12 +00001668 is_invoke = true;
1669 break;
1670 }
1671
1672 const char* declaring_class;
1673 const char* member;
1674 std::string member_type;
Orion Hodson631827d2017-04-10 14:53:47 +01001675 if (type != nullptr) {
1676 if (is_invoke) {
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001677 const dex::MethodId& method_id = pDexFile->GetMethodId(mh.field_or_method_idx_);
Orion Hodson631827d2017-04-10 14:53:47 +01001678 declaring_class = pDexFile->GetMethodDeclaringClassDescriptor(method_id);
1679 member = pDexFile->GetMethodName(method_id);
1680 member_type = pDexFile->GetMethodSignature(method_id).ToString();
1681 } else {
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001682 const dex::FieldId& field_id = pDexFile->GetFieldId(mh.field_or_method_idx_);
Orion Hodson631827d2017-04-10 14:53:47 +01001683 declaring_class = pDexFile->GetFieldDeclaringClassDescriptor(field_id);
1684 member = pDexFile->GetFieldName(field_id);
1685 member_type = pDexFile->GetFieldTypeDescriptor(field_id);
1686 }
1687 if (is_instance) {
1688 member_type = android::base::StringPrintf("(%s%s", declaring_class, member_type.c_str() + 1);
1689 }
Orion Hodsonc069a302017-01-18 09:23:12 +00001690 } else {
Orion Hodson631827d2017-04-10 14:53:47 +01001691 type = "?";
1692 declaring_class = "?";
1693 member = "?";
1694 member_type = "?";
Orion Hodsonc069a302017-01-18 09:23:12 +00001695 }
1696
1697 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1698 fprintf(gOutFile, "Method handle #%u:\n", idx);
1699 fprintf(gOutFile, " type : %s\n", type);
1700 fprintf(gOutFile, " target : %s %s\n", declaring_class, member);
1701 fprintf(gOutFile, " target_type : %s\n", member_type.c_str());
Orion Hodsonc069a302017-01-18 09:23:12 +00001702 }
1703}
1704
1705static void dumpCallSite(const DexFile* pDexFile, u4 idx) {
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001706 const dex::CallSiteIdItem& call_site_id = pDexFile->GetCallSiteId(idx);
Orion Hodsonc069a302017-01-18 09:23:12 +00001707 CallSiteArrayValueIterator it(*pDexFile, call_site_id);
1708 if (it.Size() < 3) {
Andreas Gampe221d9812018-01-22 17:48:56 -08001709 LOG(ERROR) << "ERROR: Call site " << idx << " has too few values.";
Orion Hodsonc069a302017-01-18 09:23:12 +00001710 return;
1711 }
1712
1713 uint32_t method_handle_idx = static_cast<uint32_t>(it.GetJavaValue().i);
1714 it.Next();
1715 dex::StringIndex method_name_idx = static_cast<dex::StringIndex>(it.GetJavaValue().i);
1716 const char* method_name = pDexFile->StringDataByIdx(method_name_idx);
1717 it.Next();
Orion Hodson06d10a72018-05-14 08:53:38 +01001718 dex::ProtoIndex method_type_idx = static_cast<dex::ProtoIndex>(it.GetJavaValue().i);
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001719 const dex::ProtoId& method_type_id = pDexFile->GetProtoId(method_type_idx);
Orion Hodsonc069a302017-01-18 09:23:12 +00001720 std::string method_type = pDexFile->GetProtoSignature(method_type_id).ToString();
1721 it.Next();
1722
1723 if (gOptions.outputFormat == OUTPUT_PLAIN) {
Orion Hodson775224d2017-07-05 11:04:01 +01001724 fprintf(gOutFile, "Call site #%u: // offset %u\n", idx, call_site_id.data_off_);
Orion Hodsonc069a302017-01-18 09:23:12 +00001725 fprintf(gOutFile, " link_argument[0] : %u (MethodHandle)\n", method_handle_idx);
1726 fprintf(gOutFile, " link_argument[1] : %s (String)\n", method_name);
1727 fprintf(gOutFile, " link_argument[2] : %s (MethodType)\n", method_type.c_str());
Orion Hodsonc069a302017-01-18 09:23:12 +00001728 }
1729
1730 size_t argument = 3;
1731 while (it.HasNext()) {
1732 const char* type;
1733 std::string value;
1734 switch (it.GetValueType()) {
1735 case EncodedArrayValueIterator::ValueType::kByte:
1736 type = "byte";
1737 value = android::base::StringPrintf("%u", it.GetJavaValue().b);
1738 break;
1739 case EncodedArrayValueIterator::ValueType::kShort:
1740 type = "short";
1741 value = android::base::StringPrintf("%d", it.GetJavaValue().s);
1742 break;
1743 case EncodedArrayValueIterator::ValueType::kChar:
1744 type = "char";
1745 value = android::base::StringPrintf("%u", it.GetJavaValue().c);
1746 break;
1747 case EncodedArrayValueIterator::ValueType::kInt:
1748 type = "int";
1749 value = android::base::StringPrintf("%d", it.GetJavaValue().i);
1750 break;
1751 case EncodedArrayValueIterator::ValueType::kLong:
1752 type = "long";
1753 value = android::base::StringPrintf("%" PRId64, it.GetJavaValue().j);
1754 break;
1755 case EncodedArrayValueIterator::ValueType::kFloat:
1756 type = "float";
1757 value = android::base::StringPrintf("%g", it.GetJavaValue().f);
1758 break;
1759 case EncodedArrayValueIterator::ValueType::kDouble:
1760 type = "double";
1761 value = android::base::StringPrintf("%g", it.GetJavaValue().d);
1762 break;
1763 case EncodedArrayValueIterator::ValueType::kMethodType: {
1764 type = "MethodType";
Orion Hodson06d10a72018-05-14 08:53:38 +01001765 dex::ProtoIndex proto_idx = static_cast<dex::ProtoIndex>(it.GetJavaValue().i);
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001766 const dex::ProtoId& proto_id = pDexFile->GetProtoId(proto_idx);
Orion Hodsonc069a302017-01-18 09:23:12 +00001767 value = pDexFile->GetProtoSignature(proto_id).ToString();
1768 break;
1769 }
1770 case EncodedArrayValueIterator::ValueType::kMethodHandle:
1771 type = "MethodHandle";
1772 value = android::base::StringPrintf("%d", it.GetJavaValue().i);
1773 break;
1774 case EncodedArrayValueIterator::ValueType::kString: {
1775 type = "String";
1776 dex::StringIndex string_idx = static_cast<dex::StringIndex>(it.GetJavaValue().i);
1777 value = pDexFile->StringDataByIdx(string_idx);
1778 break;
1779 }
1780 case EncodedArrayValueIterator::ValueType::kType: {
1781 type = "Class";
1782 dex::TypeIndex type_idx = static_cast<dex::TypeIndex>(it.GetJavaValue().i);
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001783 const dex::TypeId& type_id = pDexFile->GetTypeId(type_idx);
Orion Hodson0f6cc7f2018-05-25 15:33:44 +01001784 value = pDexFile->GetTypeDescriptor(type_id);
Orion Hodsonc069a302017-01-18 09:23:12 +00001785 break;
1786 }
1787 case EncodedArrayValueIterator::ValueType::kField:
1788 case EncodedArrayValueIterator::ValueType::kMethod:
1789 case EncodedArrayValueIterator::ValueType::kEnum:
1790 case EncodedArrayValueIterator::ValueType::kArray:
1791 case EncodedArrayValueIterator::ValueType::kAnnotation:
1792 // Unreachable based on current EncodedArrayValueIterator::Next().
Andreas Gampef45d61c2017-06-07 10:29:33 -07001793 UNIMPLEMENTED(FATAL) << " type " << it.GetValueType();
Orion Hodsonc069a302017-01-18 09:23:12 +00001794 UNREACHABLE();
Orion Hodsonc069a302017-01-18 09:23:12 +00001795 case EncodedArrayValueIterator::ValueType::kNull:
1796 type = "Null";
1797 value = "null";
1798 break;
1799 case EncodedArrayValueIterator::ValueType::kBoolean:
1800 type = "boolean";
1801 value = it.GetJavaValue().z ? "true" : "false";
1802 break;
1803 }
1804
1805 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1806 fprintf(gOutFile, " link_argument[%zu] : %s (%s)\n", argument, value.c_str(), type);
Orion Hodsonc069a302017-01-18 09:23:12 +00001807 }
1808
1809 it.Next();
1810 argument++;
1811 }
Orion Hodsonc069a302017-01-18 09:23:12 +00001812}
1813
Aart Bik69ae54a2015-07-01 14:52:26 -07001814/*
1815 * Dumps the requested sections of the file.
1816 */
Aart Bik7b45a8a2016-10-24 16:07:59 -07001817static void processDexFile(const char* fileName,
1818 const DexFile* pDexFile, size_t i, size_t n) {
Aart Bik69ae54a2015-07-01 14:52:26 -07001819 if (gOptions.verbose) {
Aart Bik7b45a8a2016-10-24 16:07:59 -07001820 fputs("Opened '", gOutFile);
1821 fputs(fileName, gOutFile);
1822 if (n > 1) {
Mathieu Chartier79c87da2017-10-10 11:54:29 -07001823 fprintf(gOutFile, ":%s", DexFileLoader::GetMultiDexClassesDexName(i).c_str());
Aart Bik7b45a8a2016-10-24 16:07:59 -07001824 }
1825 fprintf(gOutFile, "', DEX version '%.3s'\n", pDexFile->GetHeader().magic_ + 4);
Aart Bik69ae54a2015-07-01 14:52:26 -07001826 }
1827
1828 // Headers.
1829 if (gOptions.showFileHeaders) {
1830 dumpFileHeader(pDexFile);
1831 }
1832
Aart Bik69ae54a2015-07-01 14:52:26 -07001833 // Iterate over all classes.
1834 char* package = nullptr;
1835 const u4 classDefsSize = pDexFile->GetHeader().class_defs_size_;
Andreas Gampe70dfb692018-09-18 16:50:18 -07001836 for (u4 j = 0; j < classDefsSize; j++) {
1837 dumpClass(pDexFile, j, &package);
Aart Bik69ae54a2015-07-01 14:52:26 -07001838 } // for
1839
Orion Hodsonc069a302017-01-18 09:23:12 +00001840 // Iterate over all method handles.
Andreas Gampe70dfb692018-09-18 16:50:18 -07001841 for (u4 j = 0; j < pDexFile->NumMethodHandles(); ++j) {
1842 dumpMethodHandle(pDexFile, j);
Orion Hodsonc069a302017-01-18 09:23:12 +00001843 } // for
1844
1845 // Iterate over all call site ids.
Andreas Gampe70dfb692018-09-18 16:50:18 -07001846 for (u4 j = 0; j < pDexFile->NumCallSiteIds(); ++j) {
1847 dumpCallSite(pDexFile, j);
Orion Hodsonc069a302017-01-18 09:23:12 +00001848 } // for
1849
Aart Bik69ae54a2015-07-01 14:52:26 -07001850 // Free the last package allocated.
1851 if (package != nullptr) {
1852 fprintf(gOutFile, "</package>\n");
1853 free(package);
1854 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001855}
1856
1857/*
1858 * Processes a single file (either direct .dex or indirect .zip/.jar/.apk).
1859 */
1860int processFile(const char* fileName) {
1861 if (gOptions.verbose) {
1862 fprintf(gOutFile, "Processing '%s'...\n", fileName);
1863 }
1864
Nicolas Geoffrayc1d8caa2018-02-27 10:15:14 +00001865 const bool kVerifyChecksum = !gOptions.ignoreBadChecksum;
1866 const bool kVerify = !gOptions.disableVerifier;
1867 std::string content;
Aart Bik69ae54a2015-07-01 14:52:26 -07001868 // If the file is not a .dex file, the function tries .zip/.jar/.apk files,
Aart Bikdce50862016-06-10 16:04:03 -07001869 // all of which are Zip archives with "classes.dex" inside.
David Sehr999646d2018-02-16 10:22:33 -08001870 // TODO: add an api to android::base to read a std::vector<uint8_t>.
1871 if (!android::base::ReadFileToString(fileName, &content)) {
1872 LOG(ERROR) << "ReadFileToString failed";
David Sehr5a1f6292018-01-19 11:08:51 -08001873 return -1;
1874 }
1875 const DexFileLoader dex_file_loader;
Dario Frenie166fac2018-07-16 11:08:03 +01001876 DexFileLoaderErrorCode error_code;
David Sehr999646d2018-02-16 10:22:33 -08001877 std::string error_msg;
Aart Bik69ae54a2015-07-01 14:52:26 -07001878 std::vector<std::unique_ptr<const DexFile>> dex_files;
David Sehr999646d2018-02-16 10:22:33 -08001879 if (!dex_file_loader.OpenAll(reinterpret_cast<const uint8_t*>(content.data()),
1880 content.size(),
1881 fileName,
Nicolas Geoffrayc1d8caa2018-02-27 10:15:14 +00001882 kVerify,
David Sehr999646d2018-02-16 10:22:33 -08001883 kVerifyChecksum,
Dario Frenie166fac2018-07-16 11:08:03 +01001884 &error_code,
David Sehr999646d2018-02-16 10:22:33 -08001885 &error_msg,
1886 &dex_files)) {
Aart Bik69ae54a2015-07-01 14:52:26 -07001887 // Display returned error message to user. Note that this error behavior
1888 // differs from the error messages shown by the original Dalvik dexdump.
Andreas Gampe221d9812018-01-22 17:48:56 -08001889 LOG(ERROR) << error_msg;
Aart Bik69ae54a2015-07-01 14:52:26 -07001890 return -1;
1891 }
1892
Aart Bik4e149602015-07-09 11:45:28 -07001893 // Success. Either report checksum verification or process
1894 // all dex files found in given file.
Aart Bik69ae54a2015-07-01 14:52:26 -07001895 if (gOptions.checksumOnly) {
1896 fprintf(gOutFile, "Checksum verified\n");
1897 } else {
Paul Duffin4b64f6c2020-10-30 11:58:47 +00001898 // Open XML context.
1899 if (gOptions.outputFormat == OUTPUT_XML) {
1900 fprintf(gOutFile, "<api>\n");
1901 }
1902
Aart Bik7b45a8a2016-10-24 16:07:59 -07001903 for (size_t i = 0, n = dex_files.size(); i < n; i++) {
1904 processDexFile(fileName, dex_files[i].get(), i, n);
Aart Bik4e149602015-07-09 11:45:28 -07001905 }
Paul Duffin4b64f6c2020-10-30 11:58:47 +00001906
1907 // Close XML context.
1908 if (gOptions.outputFormat == OUTPUT_XML) {
1909 fprintf(gOutFile, "</api>\n");
1910 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001911 }
1912 return 0;
1913}
1914
1915} // namespace art