blob: 409ae552fef5b0d8837a82d9c120eba8f6b2f41b [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
Ian Zerny7453a712022-02-02 10:47:08 +01001201static u4 findLastInstructionAddress(const CodeItemDebugInfoAccessor& accessor) {
1202 const u4 maxAddress = accessor.InsnsSizeInCodeUnits();
1203 u4 lastInstructionSize = 0;
1204 for (const DexInstructionPcPair& pair : accessor) {
1205 const u4 address = pair.DexPc();
1206 if (address >= maxAddress) {
1207 return 1;
1208 }
1209 lastInstructionSize = pair.Inst().SizeInCodeUnits();
1210 }
1211 return maxAddress - lastInstructionSize;
1212}
1213
Aart Bik69ae54a2015-07-01 14:52:26 -07001214/*
1215 * Dumps code of a method.
1216 */
1217static void dumpCode(const DexFile* pDexFile, u4 idx, u4 flags,
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001218 const dex::CodeItem* pCode, u4 codeOffset) {
Mathieu Chartier8892c6b2018-01-09 15:10:17 -08001219 CodeItemDebugInfoAccessor accessor(*pDexFile, pCode, idx);
Mathieu Chartier641a3af2017-12-15 11:42:58 -08001220
1221 fprintf(gOutFile, " registers : %d\n", accessor.RegistersSize());
1222 fprintf(gOutFile, " ins : %d\n", accessor.InsSize());
1223 fprintf(gOutFile, " outs : %d\n", accessor.OutsSize());
Aart Bik69ae54a2015-07-01 14:52:26 -07001224 fprintf(gOutFile, " insns size : %d 16-bit code units\n",
Mathieu Chartier641a3af2017-12-15 11:42:58 -08001225 accessor.InsnsSizeInCodeUnits());
Aart Bik69ae54a2015-07-01 14:52:26 -07001226
1227 // Bytecode disassembly, if requested.
1228 if (gOptions.disassemble) {
1229 dumpBytecodes(pDexFile, idx, pCode, codeOffset);
1230 }
1231
1232 // Try-catch blocks.
1233 dumpCatches(pDexFile, pCode);
1234
Ian Zerny19df0e92022-02-02 16:51:02 +01001235 if (gOptions.showDebugInfo) {
1236 const u4 lastInstructionAddress = findLastInstructionAddress(accessor);
1237 // Positions and locals table in the debug info.
1238 bool is_static = (flags & kAccStatic) != 0;
1239 fprintf(gOutFile, " positions : \n");
1240 accessor.DecodeDebugPositionInfo([&](const DexFile::PositionInfo& entry) {
1241 if (entry.address_ > lastInstructionAddress) {
1242 return true;
1243 } else {
1244 fprintf(gOutFile, " 0x%04x line=%d\n", entry.address_, entry.line_);
1245 return false;
1246 }
1247 });
1248 fprintf(gOutFile, " locals : \n");
1249 accessor.DecodeDebugLocalInfo(is_static,
1250 idx,
1251 [&](const DexFile::LocalInfo& entry) {
1252 const char* signature = entry.signature_ != nullptr ? entry.signature_ : "";
1253 fprintf(gOutFile,
1254 " 0x%04x - 0x%04x reg=%d %s %s %s\n",
1255 entry.start_address_,
1256 entry.end_address_,
1257 entry.reg_,
1258 entry.name_,
1259 entry.descriptor_,
1260 signature);
1261 });
1262 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001263}
1264
David Brazdil8c4d7172019-01-21 19:45:28 +00001265static std::string GetHiddenapiFlagStr(uint32_t hiddenapi_flags) {
1266 std::stringstream ss;
1267 hiddenapi::ApiList api_list(hiddenapi_flags);
1268 api_list.Dump(ss);
1269 std::string str_api_list = ss.str();
1270 std::transform(str_api_list.begin(), str_api_list.end(), str_api_list.begin(), ::toupper);
1271 return str_api_list;
1272}
1273
Aart Bik69ae54a2015-07-01 14:52:26 -07001274/*
1275 * Dumps a method.
1276 */
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001277static void dumpMethod(const ClassAccessor::Method& method, int i) {
Aart Bik69ae54a2015-07-01 14:52:26 -07001278 // Bail for anything private if export only requested.
David Brazdil20c765f2018-10-27 21:45:15 +00001279 const uint32_t flags = method.GetAccessFlags();
Aart Bik69ae54a2015-07-01 14:52:26 -07001280 if (gOptions.exportsOnly && (flags & (kAccPublic | kAccProtected)) == 0) {
1281 return;
1282 }
1283
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001284 const DexFile& dex_file = method.GetDexFile();
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001285 const dex::MethodId& pMethodId = dex_file.GetMethodId(method.GetIndex());
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001286 const char* name = dex_file.StringDataByIdx(pMethodId.name_idx_);
1287 const Signature signature = dex_file.GetMethodSignature(pMethodId);
Aart Bik69ae54a2015-07-01 14:52:26 -07001288 char* typeDescriptor = strdup(signature.ToString().c_str());
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001289 const char* backDescriptor = dex_file.StringByTypeIdx(pMethodId.class_idx_);
Aart Bik69ae54a2015-07-01 14:52:26 -07001290 char* accessStr = createAccessFlagStr(flags, kAccessForMethod);
David Brazdil8c4d7172019-01-21 19:45:28 +00001291 const uint32_t hiddenapiFlags = method.GetHiddenapiFlags();
Aart Bik69ae54a2015-07-01 14:52:26 -07001292
1293 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1294 fprintf(gOutFile, " #%d : (in %s)\n", i, backDescriptor);
1295 fprintf(gOutFile, " name : '%s'\n", name);
1296 fprintf(gOutFile, " type : '%s'\n", typeDescriptor);
1297 fprintf(gOutFile, " access : 0x%04x (%s)\n", flags, accessStr);
Eric Holk4ac8d962020-03-30 10:44:30 -07001298 if (gOptions.showSectionHeaders) {
1299 fprintf(gOutFile, " method_idx : %d\n", method.GetIndex());
1300 }
David Brazdil8c4d7172019-01-21 19:45:28 +00001301 if (hiddenapiFlags != 0u) {
1302 fprintf(gOutFile,
1303 " hiddenapi : 0x%04x (%s)\n",
1304 hiddenapiFlags,
1305 GetHiddenapiFlagStr(hiddenapiFlags).c_str());
1306 }
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001307 if (method.GetCodeItem() == nullptr) {
Aart Bik69ae54a2015-07-01 14:52:26 -07001308 fprintf(gOutFile, " code : (none)\n");
1309 } else {
1310 fprintf(gOutFile, " code -\n");
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001311 dumpCode(&dex_file,
1312 method.GetIndex(),
1313 flags,
1314 method.GetCodeItem(),
1315 method.GetCodeItemOffset());
Aart Bik69ae54a2015-07-01 14:52:26 -07001316 }
1317 if (gOptions.disassemble) {
1318 fputc('\n', gOutFile);
1319 }
1320 } else if (gOptions.outputFormat == OUTPUT_XML) {
1321 const bool constructor = (name[0] == '<');
1322
1323 // Method name and prototype.
1324 if (constructor) {
Orion Hodsonfe42d212018-08-24 14:01:14 +01001325 std::unique_ptr<char[]> dot(descriptorClassToName(backDescriptor));
Aart Bikc05e2f22016-07-12 15:53:13 -07001326 fprintf(gOutFile, "<constructor name=\"%s\"\n", dot.get());
1327 dot = descriptorToDot(backDescriptor);
1328 fprintf(gOutFile, " type=\"%s\"\n", dot.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001329 } else {
1330 fprintf(gOutFile, "<method name=\"%s\"\n", name);
1331 const char* returnType = strrchr(typeDescriptor, ')');
1332 if (returnType == nullptr) {
Andreas Gampe221d9812018-01-22 17:48:56 -08001333 LOG(ERROR) << "bad method type descriptor '" << typeDescriptor << "'";
Aart Bik69ae54a2015-07-01 14:52:26 -07001334 goto bail;
1335 }
Aart Bikc05e2f22016-07-12 15:53:13 -07001336 std::unique_ptr<char[]> dot(descriptorToDot(returnType + 1));
1337 fprintf(gOutFile, " return=\"%s\"\n", dot.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001338 fprintf(gOutFile, " abstract=%s\n", quotedBool((flags & kAccAbstract) != 0));
1339 fprintf(gOutFile, " native=%s\n", quotedBool((flags & kAccNative) != 0));
1340 fprintf(gOutFile, " synchronized=%s\n", quotedBool(
1341 (flags & (kAccSynchronized | kAccDeclaredSynchronized)) != 0));
1342 }
1343
1344 // Additional method flags.
1345 fprintf(gOutFile, " static=%s\n", quotedBool((flags & kAccStatic) != 0));
1346 fprintf(gOutFile, " final=%s\n", quotedBool((flags & kAccFinal) != 0));
1347 // The "deprecated=" not knowable w/o parsing annotations.
1348 fprintf(gOutFile, " visibility=%s\n>\n", quotedVisibility(flags));
1349
1350 // Parameters.
1351 if (typeDescriptor[0] != '(') {
Andreas Gampe221d9812018-01-22 17:48:56 -08001352 LOG(ERROR) << "ERROR: bad descriptor '" << typeDescriptor << "'";
Aart Bik69ae54a2015-07-01 14:52:26 -07001353 goto bail;
1354 }
1355 char* tmpBuf = reinterpret_cast<char*>(malloc(strlen(typeDescriptor) + 1));
1356 const char* base = typeDescriptor + 1;
1357 int argNum = 0;
1358 while (*base != ')') {
1359 char* cp = tmpBuf;
1360 while (*base == '[') {
1361 *cp++ = *base++;
1362 }
1363 if (*base == 'L') {
1364 // Copy through ';'.
1365 do {
1366 *cp = *base++;
1367 } while (*cp++ != ';');
1368 } else {
1369 // Primitive char, copy it.
Aart Bikc05e2f22016-07-12 15:53:13 -07001370 if (strchr("ZBCSIFJD", *base) == nullptr) {
Andreas Gampe221d9812018-01-22 17:48:56 -08001371 LOG(ERROR) << "ERROR: bad method signature '" << base << "'";
Aart Bika0e33fd2016-07-08 18:32:45 -07001372 break; // while
Aart Bik69ae54a2015-07-01 14:52:26 -07001373 }
1374 *cp++ = *base++;
1375 }
1376 // Null terminate and display.
1377 *cp++ = '\0';
Aart Bikc05e2f22016-07-12 15:53:13 -07001378 std::unique_ptr<char[]> dot(descriptorToDot(tmpBuf));
Aart Bik69ae54a2015-07-01 14:52:26 -07001379 fprintf(gOutFile, "<parameter name=\"arg%d\" type=\"%s\">\n"
Aart Bikc05e2f22016-07-12 15:53:13 -07001380 "</parameter>\n", argNum++, dot.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001381 } // while
1382 free(tmpBuf);
1383 if (constructor) {
1384 fprintf(gOutFile, "</constructor>\n");
1385 } else {
1386 fprintf(gOutFile, "</method>\n");
1387 }
1388 }
1389
Orion Hodson219f81f2021-11-10 19:48:08 +00001390bail:
Aart Bik69ae54a2015-07-01 14:52:26 -07001391 free(typeDescriptor);
1392 free(accessStr);
1393}
1394
1395/*
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001396 * Dumps a static or instance (class) field.
Aart Bik69ae54a2015-07-01 14:52:26 -07001397 */
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001398static void dumpField(const ClassAccessor::Field& field, int i, const u1** data = nullptr) {
Aart Bik69ae54a2015-07-01 14:52:26 -07001399 // Bail for anything private if export only requested.
David Brazdil20c765f2018-10-27 21:45:15 +00001400 const uint32_t flags = field.GetAccessFlags();
Aart Bik69ae54a2015-07-01 14:52:26 -07001401 if (gOptions.exportsOnly && (flags & (kAccPublic | kAccProtected)) == 0) {
1402 return;
1403 }
1404
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001405 const DexFile& dex_file = field.GetDexFile();
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001406 const dex::FieldId& field_id = dex_file.GetFieldId(field.GetIndex());
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001407 const char* name = dex_file.StringDataByIdx(field_id.name_idx_);
1408 const char* typeDescriptor = dex_file.StringByTypeIdx(field_id.type_idx_);
1409 const char* backDescriptor = dex_file.StringByTypeIdx(field_id.class_idx_);
Aart Bik69ae54a2015-07-01 14:52:26 -07001410 char* accessStr = createAccessFlagStr(flags, kAccessForField);
David Brazdil8c4d7172019-01-21 19:45:28 +00001411 const uint32_t hiddenapiFlags = field.GetHiddenapiFlags();
Aart Bik69ae54a2015-07-01 14:52:26 -07001412
1413 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1414 fprintf(gOutFile, " #%d : (in %s)\n", i, backDescriptor);
1415 fprintf(gOutFile, " name : '%s'\n", name);
1416 fprintf(gOutFile, " type : '%s'\n", typeDescriptor);
1417 fprintf(gOutFile, " access : 0x%04x (%s)\n", flags, accessStr);
David Brazdil8c4d7172019-01-21 19:45:28 +00001418 if (hiddenapiFlags != 0u) {
1419 fprintf(gOutFile,
1420 " hiddenapi : 0x%04x (%s)\n",
1421 hiddenapiFlags,
1422 GetHiddenapiFlagStr(hiddenapiFlags).c_str());
1423 }
Aart Bikdce50862016-06-10 16:04:03 -07001424 if (data != nullptr) {
Shinichiro Hamaji82863f02015-11-05 16:51:33 +09001425 fputs(" value : ", gOutFile);
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001426 dumpEncodedValue(&dex_file, data);
Shinichiro Hamaji82863f02015-11-05 16:51:33 +09001427 fputs("\n", gOutFile);
1428 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001429 } else if (gOptions.outputFormat == OUTPUT_XML) {
1430 fprintf(gOutFile, "<field name=\"%s\"\n", name);
Aart Bikc05e2f22016-07-12 15:53:13 -07001431 std::unique_ptr<char[]> dot(descriptorToDot(typeDescriptor));
1432 fprintf(gOutFile, " type=\"%s\"\n", dot.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001433 fprintf(gOutFile, " transient=%s\n", quotedBool((flags & kAccTransient) != 0));
1434 fprintf(gOutFile, " volatile=%s\n", quotedBool((flags & kAccVolatile) != 0));
1435 // The "value=" is not knowable w/o parsing annotations.
1436 fprintf(gOutFile, " static=%s\n", quotedBool((flags & kAccStatic) != 0));
1437 fprintf(gOutFile, " final=%s\n", quotedBool((flags & kAccFinal) != 0));
1438 // The "deprecated=" is not knowable w/o parsing annotations.
1439 fprintf(gOutFile, " visibility=%s\n", quotedVisibility(flags));
Aart Bikdce50862016-06-10 16:04:03 -07001440 if (data != nullptr) {
Shinichiro Hamaji82863f02015-11-05 16:51:33 +09001441 fputs(" value=\"", gOutFile);
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001442 dumpEncodedValue(&dex_file, data);
Shinichiro Hamaji82863f02015-11-05 16:51:33 +09001443 fputs("\"\n", gOutFile);
1444 }
1445 fputs(">\n</field>\n", gOutFile);
Aart Bik69ae54a2015-07-01 14:52:26 -07001446 }
1447
1448 free(accessStr);
1449}
1450
1451/*
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001452 * Dumping a CFG.
Aart Bik69ae54a2015-07-01 14:52:26 -07001453 */
Andreas Gampe5073fed2015-08-10 11:40:25 -07001454static void dumpCfg(const DexFile* dex_file, int idx) {
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001455 ClassAccessor accessor(*dex_file, dex_file->GetClassDef(idx));
1456 for (const ClassAccessor::Method& method : accessor.GetMethods()) {
1457 if (method.GetCodeItem() != nullptr) {
1458 std::ostringstream oss;
1459 DumpMethodCFG(method, oss);
1460 fputs(oss.str().c_str(), gOutFile);
1461 }
Andreas Gampe5073fed2015-08-10 11:40:25 -07001462 }
Andreas Gampe5073fed2015-08-10 11:40:25 -07001463}
1464
1465/*
Aart Bik69ae54a2015-07-01 14:52:26 -07001466 * Dumps the class.
1467 *
1468 * Note "idx" is a DexClassDef index, not a DexTypeId index.
1469 *
1470 * If "*pLastPackage" is nullptr or does not match the current class' package,
1471 * the value will be replaced with a newly-allocated string.
1472 */
1473static void dumpClass(const DexFile* pDexFile, int idx, char** pLastPackage) {
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001474 const dex::ClassDef& pClassDef = pDexFile->GetClassDef(idx);
Aart Bik69ae54a2015-07-01 14:52:26 -07001475
1476 // Omitting non-public class.
1477 if (gOptions.exportsOnly && (pClassDef.access_flags_ & kAccPublic) == 0) {
1478 return;
1479 }
1480
Aart Bikdce50862016-06-10 16:04:03 -07001481 if (gOptions.showSectionHeaders) {
1482 dumpClassDef(pDexFile, idx);
1483 }
1484
1485 if (gOptions.showAnnotations) {
1486 dumpClassAnnotations(pDexFile, idx);
1487 }
1488
1489 if (gOptions.showCfg) {
Andreas Gampe5073fed2015-08-10 11:40:25 -07001490 dumpCfg(pDexFile, idx);
1491 return;
1492 }
1493
Aart Bik69ae54a2015-07-01 14:52:26 -07001494 // For the XML output, show the package name. Ideally we'd gather
1495 // up the classes, sort them, and dump them alphabetically so the
1496 // package name wouldn't jump around, but that's not a great plan
1497 // for something that needs to run on the device.
1498 const char* classDescriptor = pDexFile->StringByTypeIdx(pClassDef.class_idx_);
1499 if (!(classDescriptor[0] == 'L' &&
1500 classDescriptor[strlen(classDescriptor)-1] == ';')) {
1501 // Arrays and primitives should not be defined explicitly. Keep going?
Andreas Gampe221d9812018-01-22 17:48:56 -08001502 LOG(WARNING) << "Malformed class name '" << classDescriptor << "'";
Aart Bik69ae54a2015-07-01 14:52:26 -07001503 } else if (gOptions.outputFormat == OUTPUT_XML) {
1504 char* mangle = strdup(classDescriptor + 1);
1505 mangle[strlen(mangle)-1] = '\0';
1506
1507 // Reduce to just the package name.
1508 char* lastSlash = strrchr(mangle, '/');
1509 if (lastSlash != nullptr) {
1510 *lastSlash = '\0';
1511 } else {
1512 *mangle = '\0';
1513 }
1514
1515 for (char* cp = mangle; *cp != '\0'; cp++) {
1516 if (*cp == '/') {
1517 *cp = '.';
1518 }
1519 } // for
1520
1521 if (*pLastPackage == nullptr || strcmp(mangle, *pLastPackage) != 0) {
1522 // Start of a new package.
1523 if (*pLastPackage != nullptr) {
1524 fprintf(gOutFile, "</package>\n");
1525 }
1526 fprintf(gOutFile, "<package name=\"%s\"\n>\n", mangle);
1527 free(*pLastPackage);
1528 *pLastPackage = mangle;
1529 } else {
1530 free(mangle);
1531 }
1532 }
1533
1534 // General class information.
1535 char* accessStr = createAccessFlagStr(pClassDef.access_flags_, kAccessForClass);
1536 const char* superclassDescriptor;
Andreas Gampea5b09a62016-11-17 15:21:22 -08001537 if (!pClassDef.superclass_idx_.IsValid()) {
Aart Bik69ae54a2015-07-01 14:52:26 -07001538 superclassDescriptor = nullptr;
1539 } else {
1540 superclassDescriptor = pDexFile->StringByTypeIdx(pClassDef.superclass_idx_);
1541 }
1542 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1543 fprintf(gOutFile, "Class #%d -\n", idx);
1544 fprintf(gOutFile, " Class descriptor : '%s'\n", classDescriptor);
1545 fprintf(gOutFile, " Access flags : 0x%04x (%s)\n", pClassDef.access_flags_, accessStr);
1546 if (superclassDescriptor != nullptr) {
1547 fprintf(gOutFile, " Superclass : '%s'\n", superclassDescriptor);
1548 }
1549 fprintf(gOutFile, " Interfaces -\n");
1550 } else {
Orion Hodsonfe42d212018-08-24 14:01:14 +01001551 std::unique_ptr<char[]> dot(descriptorClassToName(classDescriptor));
Aart Bikc05e2f22016-07-12 15:53:13 -07001552 fprintf(gOutFile, "<class name=\"%s\"\n", dot.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001553 if (superclassDescriptor != nullptr) {
Aart Bikc05e2f22016-07-12 15:53:13 -07001554 dot = descriptorToDot(superclassDescriptor);
1555 fprintf(gOutFile, " extends=\"%s\"\n", dot.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001556 }
Alex Light1f12e282015-12-10 16:49:47 -08001557 fprintf(gOutFile, " interface=%s\n",
1558 quotedBool((pClassDef.access_flags_ & kAccInterface) != 0));
Aart Bik69ae54a2015-07-01 14:52:26 -07001559 fprintf(gOutFile, " abstract=%s\n", quotedBool((pClassDef.access_flags_ & kAccAbstract) != 0));
1560 fprintf(gOutFile, " static=%s\n", quotedBool((pClassDef.access_flags_ & kAccStatic) != 0));
1561 fprintf(gOutFile, " final=%s\n", quotedBool((pClassDef.access_flags_ & kAccFinal) != 0));
1562 // The "deprecated=" not knowable w/o parsing annotations.
1563 fprintf(gOutFile, " visibility=%s\n", quotedVisibility(pClassDef.access_flags_));
1564 fprintf(gOutFile, ">\n");
1565 }
1566
1567 // Interfaces.
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001568 const dex::TypeList* pInterfaces = pDexFile->GetInterfacesList(pClassDef);
Aart Bik69ae54a2015-07-01 14:52:26 -07001569 if (pInterfaces != nullptr) {
1570 for (u4 i = 0; i < pInterfaces->Size(); i++) {
1571 dumpInterface(pDexFile, pInterfaces->GetTypeItem(i), i);
1572 } // for
1573 }
1574
1575 // Fields and methods.
David Brazdil8c4d7172019-01-21 19:45:28 +00001576 ClassAccessor accessor(*pDexFile, pClassDef, /* parse_hiddenapi_class_data= */ true);
Aart Bikdce50862016-06-10 16:04:03 -07001577
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001578 // Prepare data for static fields.
1579 const u1* sData = pDexFile->GetEncodedStaticFieldValuesArray(pClassDef);
1580 const u4 sSize = sData != nullptr ? DecodeUnsignedLeb128(&sData) : 0;
Aart Bikdce50862016-06-10 16:04:03 -07001581
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001582 // Static fields.
1583 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1584 fprintf(gOutFile, " Static fields -\n");
1585 }
1586 uint32_t i = 0u;
1587 for (const ClassAccessor::Field& field : accessor.GetStaticFields()) {
1588 dumpField(field, i, i < sSize ? &sData : nullptr);
1589 ++i;
1590 }
Aart Bikdce50862016-06-10 16:04:03 -07001591
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001592 // Instance fields.
1593 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1594 fprintf(gOutFile, " Instance fields -\n");
1595 }
1596 i = 0u;
1597 for (const ClassAccessor::Field& field : accessor.GetInstanceFields()) {
1598 dumpField(field, i);
1599 ++i;
1600 }
Aart Bikdce50862016-06-10 16:04:03 -07001601
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001602 // Direct methods.
1603 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1604 fprintf(gOutFile, " Direct methods -\n");
1605 }
1606 i = 0u;
1607 for (const ClassAccessor::Method& method : accessor.GetDirectMethods()) {
1608 dumpMethod(method, i);
1609 ++i;
1610 }
Aart Bikdce50862016-06-10 16:04:03 -07001611
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001612 // Virtual methods.
1613 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1614 fprintf(gOutFile, " Virtual methods -\n");
1615 }
1616 i = 0u;
1617 for (const ClassAccessor::Method& method : accessor.GetVirtualMethods()) {
1618 dumpMethod(method, i);
1619 ++i;
Aart Bik69ae54a2015-07-01 14:52:26 -07001620 }
1621
1622 // End of class.
1623 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1624 const char* fileName;
Andreas Gampe8a0128a2016-11-28 07:38:35 -08001625 if (pClassDef.source_file_idx_.IsValid()) {
Aart Bik69ae54a2015-07-01 14:52:26 -07001626 fileName = pDexFile->StringDataByIdx(pClassDef.source_file_idx_);
1627 } else {
1628 fileName = "unknown";
1629 }
1630 fprintf(gOutFile, " source_file_idx : %d (%s)\n\n",
Andreas Gampe8a0128a2016-11-28 07:38:35 -08001631 pClassDef.source_file_idx_.index_, fileName);
Aart Bik69ae54a2015-07-01 14:52:26 -07001632 } else if (gOptions.outputFormat == OUTPUT_XML) {
1633 fprintf(gOutFile, "</class>\n");
1634 }
1635
1636 free(accessStr);
1637}
1638
Orion Hodsonc069a302017-01-18 09:23:12 +00001639static void dumpMethodHandle(const DexFile* pDexFile, u4 idx) {
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001640 const dex::MethodHandleItem& mh = pDexFile->GetMethodHandle(idx);
Orion Hodson631827d2017-04-10 14:53:47 +01001641 const char* type = nullptr;
1642 bool is_instance = false;
Orion Hodsonc069a302017-01-18 09:23:12 +00001643 bool is_invoke = false;
Orion Hodsonc069a302017-01-18 09:23:12 +00001644 switch (static_cast<DexFile::MethodHandleType>(mh.method_handle_type_)) {
1645 case DexFile::MethodHandleType::kStaticPut:
1646 type = "put-static";
Orion Hodson631827d2017-04-10 14:53:47 +01001647 is_instance = false;
1648 is_invoke = false;
Orion Hodsonc069a302017-01-18 09:23:12 +00001649 break;
1650 case DexFile::MethodHandleType::kStaticGet:
1651 type = "get-static";
Orion Hodson631827d2017-04-10 14:53:47 +01001652 is_instance = false;
1653 is_invoke = false;
Orion Hodsonc069a302017-01-18 09:23:12 +00001654 break;
1655 case DexFile::MethodHandleType::kInstancePut:
1656 type = "put-instance";
Orion Hodson631827d2017-04-10 14:53:47 +01001657 is_instance = true;
1658 is_invoke = false;
Orion Hodsonc069a302017-01-18 09:23:12 +00001659 break;
1660 case DexFile::MethodHandleType::kInstanceGet:
1661 type = "get-instance";
Orion Hodson631827d2017-04-10 14:53:47 +01001662 is_instance = true;
1663 is_invoke = false;
Orion Hodsonc069a302017-01-18 09:23:12 +00001664 break;
1665 case DexFile::MethodHandleType::kInvokeStatic:
1666 type = "invoke-static";
Orion Hodson631827d2017-04-10 14:53:47 +01001667 is_instance = false;
Orion Hodsonc069a302017-01-18 09:23:12 +00001668 is_invoke = true;
1669 break;
1670 case DexFile::MethodHandleType::kInvokeInstance:
1671 type = "invoke-instance";
Orion Hodson631827d2017-04-10 14:53:47 +01001672 is_instance = true;
Orion Hodsonc069a302017-01-18 09:23:12 +00001673 is_invoke = true;
1674 break;
1675 case DexFile::MethodHandleType::kInvokeConstructor:
1676 type = "invoke-constructor";
Orion Hodson631827d2017-04-10 14:53:47 +01001677 is_instance = true;
1678 is_invoke = true;
1679 break;
1680 case DexFile::MethodHandleType::kInvokeDirect:
1681 type = "invoke-direct";
1682 is_instance = true;
1683 is_invoke = true;
1684 break;
1685 case DexFile::MethodHandleType::kInvokeInterface:
1686 type = "invoke-interface";
1687 is_instance = true;
Orion Hodsonc069a302017-01-18 09:23:12 +00001688 is_invoke = true;
1689 break;
1690 }
1691
1692 const char* declaring_class;
1693 const char* member;
1694 std::string member_type;
Orion Hodson631827d2017-04-10 14:53:47 +01001695 if (type != nullptr) {
1696 if (is_invoke) {
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001697 const dex::MethodId& method_id = pDexFile->GetMethodId(mh.field_or_method_idx_);
Orion Hodson631827d2017-04-10 14:53:47 +01001698 declaring_class = pDexFile->GetMethodDeclaringClassDescriptor(method_id);
1699 member = pDexFile->GetMethodName(method_id);
1700 member_type = pDexFile->GetMethodSignature(method_id).ToString();
1701 } else {
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001702 const dex::FieldId& field_id = pDexFile->GetFieldId(mh.field_or_method_idx_);
Orion Hodson631827d2017-04-10 14:53:47 +01001703 declaring_class = pDexFile->GetFieldDeclaringClassDescriptor(field_id);
1704 member = pDexFile->GetFieldName(field_id);
1705 member_type = pDexFile->GetFieldTypeDescriptor(field_id);
1706 }
1707 if (is_instance) {
1708 member_type = android::base::StringPrintf("(%s%s", declaring_class, member_type.c_str() + 1);
1709 }
Orion Hodsonc069a302017-01-18 09:23:12 +00001710 } else {
Orion Hodson631827d2017-04-10 14:53:47 +01001711 type = "?";
1712 declaring_class = "?";
1713 member = "?";
1714 member_type = "?";
Orion Hodsonc069a302017-01-18 09:23:12 +00001715 }
1716
1717 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1718 fprintf(gOutFile, "Method handle #%u:\n", idx);
1719 fprintf(gOutFile, " type : %s\n", type);
1720 fprintf(gOutFile, " target : %s %s\n", declaring_class, member);
1721 fprintf(gOutFile, " target_type : %s\n", member_type.c_str());
Orion Hodsonc069a302017-01-18 09:23:12 +00001722 }
1723}
1724
1725static void dumpCallSite(const DexFile* pDexFile, u4 idx) {
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001726 const dex::CallSiteIdItem& call_site_id = pDexFile->GetCallSiteId(idx);
Orion Hodsonc069a302017-01-18 09:23:12 +00001727 CallSiteArrayValueIterator it(*pDexFile, call_site_id);
1728 if (it.Size() < 3) {
Andreas Gampe221d9812018-01-22 17:48:56 -08001729 LOG(ERROR) << "ERROR: Call site " << idx << " has too few values.";
Orion Hodsonc069a302017-01-18 09:23:12 +00001730 return;
1731 }
1732
1733 uint32_t method_handle_idx = static_cast<uint32_t>(it.GetJavaValue().i);
1734 it.Next();
1735 dex::StringIndex method_name_idx = static_cast<dex::StringIndex>(it.GetJavaValue().i);
1736 const char* method_name = pDexFile->StringDataByIdx(method_name_idx);
1737 it.Next();
Orion Hodson06d10a72018-05-14 08:53:38 +01001738 dex::ProtoIndex method_type_idx = static_cast<dex::ProtoIndex>(it.GetJavaValue().i);
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001739 const dex::ProtoId& method_type_id = pDexFile->GetProtoId(method_type_idx);
Orion Hodsonc069a302017-01-18 09:23:12 +00001740 std::string method_type = pDexFile->GetProtoSignature(method_type_id).ToString();
1741 it.Next();
1742
1743 if (gOptions.outputFormat == OUTPUT_PLAIN) {
Orion Hodson775224d2017-07-05 11:04:01 +01001744 fprintf(gOutFile, "Call site #%u: // offset %u\n", idx, call_site_id.data_off_);
Orion Hodsonc069a302017-01-18 09:23:12 +00001745 fprintf(gOutFile, " link_argument[0] : %u (MethodHandle)\n", method_handle_idx);
1746 fprintf(gOutFile, " link_argument[1] : %s (String)\n", method_name);
1747 fprintf(gOutFile, " link_argument[2] : %s (MethodType)\n", method_type.c_str());
Orion Hodsonc069a302017-01-18 09:23:12 +00001748 }
1749
1750 size_t argument = 3;
1751 while (it.HasNext()) {
1752 const char* type;
1753 std::string value;
1754 switch (it.GetValueType()) {
1755 case EncodedArrayValueIterator::ValueType::kByte:
1756 type = "byte";
1757 value = android::base::StringPrintf("%u", it.GetJavaValue().b);
1758 break;
1759 case EncodedArrayValueIterator::ValueType::kShort:
1760 type = "short";
1761 value = android::base::StringPrintf("%d", it.GetJavaValue().s);
1762 break;
1763 case EncodedArrayValueIterator::ValueType::kChar:
1764 type = "char";
1765 value = android::base::StringPrintf("%u", it.GetJavaValue().c);
1766 break;
1767 case EncodedArrayValueIterator::ValueType::kInt:
1768 type = "int";
1769 value = android::base::StringPrintf("%d", it.GetJavaValue().i);
1770 break;
1771 case EncodedArrayValueIterator::ValueType::kLong:
1772 type = "long";
1773 value = android::base::StringPrintf("%" PRId64, it.GetJavaValue().j);
1774 break;
1775 case EncodedArrayValueIterator::ValueType::kFloat:
1776 type = "float";
1777 value = android::base::StringPrintf("%g", it.GetJavaValue().f);
1778 break;
1779 case EncodedArrayValueIterator::ValueType::kDouble:
1780 type = "double";
1781 value = android::base::StringPrintf("%g", it.GetJavaValue().d);
1782 break;
1783 case EncodedArrayValueIterator::ValueType::kMethodType: {
1784 type = "MethodType";
Orion Hodson06d10a72018-05-14 08:53:38 +01001785 dex::ProtoIndex proto_idx = static_cast<dex::ProtoIndex>(it.GetJavaValue().i);
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001786 const dex::ProtoId& proto_id = pDexFile->GetProtoId(proto_idx);
Orion Hodsonc069a302017-01-18 09:23:12 +00001787 value = pDexFile->GetProtoSignature(proto_id).ToString();
1788 break;
1789 }
1790 case EncodedArrayValueIterator::ValueType::kMethodHandle:
1791 type = "MethodHandle";
1792 value = android::base::StringPrintf("%d", it.GetJavaValue().i);
1793 break;
1794 case EncodedArrayValueIterator::ValueType::kString: {
1795 type = "String";
1796 dex::StringIndex string_idx = static_cast<dex::StringIndex>(it.GetJavaValue().i);
1797 value = pDexFile->StringDataByIdx(string_idx);
1798 break;
1799 }
1800 case EncodedArrayValueIterator::ValueType::kType: {
1801 type = "Class";
1802 dex::TypeIndex type_idx = static_cast<dex::TypeIndex>(it.GetJavaValue().i);
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001803 const dex::TypeId& type_id = pDexFile->GetTypeId(type_idx);
Orion Hodson0f6cc7f2018-05-25 15:33:44 +01001804 value = pDexFile->GetTypeDescriptor(type_id);
Orion Hodsonc069a302017-01-18 09:23:12 +00001805 break;
1806 }
1807 case EncodedArrayValueIterator::ValueType::kField:
1808 case EncodedArrayValueIterator::ValueType::kMethod:
1809 case EncodedArrayValueIterator::ValueType::kEnum:
1810 case EncodedArrayValueIterator::ValueType::kArray:
1811 case EncodedArrayValueIterator::ValueType::kAnnotation:
1812 // Unreachable based on current EncodedArrayValueIterator::Next().
Andreas Gampef45d61c2017-06-07 10:29:33 -07001813 UNIMPLEMENTED(FATAL) << " type " << it.GetValueType();
Orion Hodsonc069a302017-01-18 09:23:12 +00001814 UNREACHABLE();
Orion Hodsonc069a302017-01-18 09:23:12 +00001815 case EncodedArrayValueIterator::ValueType::kNull:
1816 type = "Null";
1817 value = "null";
1818 break;
1819 case EncodedArrayValueIterator::ValueType::kBoolean:
1820 type = "boolean";
1821 value = it.GetJavaValue().z ? "true" : "false";
1822 break;
1823 }
1824
1825 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1826 fprintf(gOutFile, " link_argument[%zu] : %s (%s)\n", argument, value.c_str(), type);
Orion Hodsonc069a302017-01-18 09:23:12 +00001827 }
1828
1829 it.Next();
1830 argument++;
1831 }
Orion Hodsonc069a302017-01-18 09:23:12 +00001832}
1833
Aart Bik69ae54a2015-07-01 14:52:26 -07001834/*
1835 * Dumps the requested sections of the file.
1836 */
Aart Bik7b45a8a2016-10-24 16:07:59 -07001837static void processDexFile(const char* fileName,
1838 const DexFile* pDexFile, size_t i, size_t n) {
Aart Bik69ae54a2015-07-01 14:52:26 -07001839 if (gOptions.verbose) {
Aart Bik7b45a8a2016-10-24 16:07:59 -07001840 fputs("Opened '", gOutFile);
1841 fputs(fileName, gOutFile);
1842 if (n > 1) {
Mathieu Chartier79c87da2017-10-10 11:54:29 -07001843 fprintf(gOutFile, ":%s", DexFileLoader::GetMultiDexClassesDexName(i).c_str());
Aart Bik7b45a8a2016-10-24 16:07:59 -07001844 }
1845 fprintf(gOutFile, "', DEX version '%.3s'\n", pDexFile->GetHeader().magic_ + 4);
Aart Bik69ae54a2015-07-01 14:52:26 -07001846 }
1847
1848 // Headers.
1849 if (gOptions.showFileHeaders) {
1850 dumpFileHeader(pDexFile);
1851 }
1852
Aart Bik69ae54a2015-07-01 14:52:26 -07001853 // Iterate over all classes.
1854 char* package = nullptr;
1855 const u4 classDefsSize = pDexFile->GetHeader().class_defs_size_;
Andreas Gampe70dfb692018-09-18 16:50:18 -07001856 for (u4 j = 0; j < classDefsSize; j++) {
1857 dumpClass(pDexFile, j, &package);
Aart Bik69ae54a2015-07-01 14:52:26 -07001858 } // for
1859
Orion Hodsonc069a302017-01-18 09:23:12 +00001860 // Iterate over all method handles.
Andreas Gampe70dfb692018-09-18 16:50:18 -07001861 for (u4 j = 0; j < pDexFile->NumMethodHandles(); ++j) {
1862 dumpMethodHandle(pDexFile, j);
Orion Hodsonc069a302017-01-18 09:23:12 +00001863 } // for
1864
1865 // Iterate over all call site ids.
Andreas Gampe70dfb692018-09-18 16:50:18 -07001866 for (u4 j = 0; j < pDexFile->NumCallSiteIds(); ++j) {
1867 dumpCallSite(pDexFile, j);
Orion Hodsonc069a302017-01-18 09:23:12 +00001868 } // 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 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001875}
1876
1877/*
1878 * Processes a single file (either direct .dex or indirect .zip/.jar/.apk).
1879 */
1880int processFile(const char* fileName) {
1881 if (gOptions.verbose) {
1882 fprintf(gOutFile, "Processing '%s'...\n", fileName);
1883 }
1884
Nicolas Geoffrayc1d8caa2018-02-27 10:15:14 +00001885 const bool kVerifyChecksum = !gOptions.ignoreBadChecksum;
1886 const bool kVerify = !gOptions.disableVerifier;
1887 std::string content;
Aart Bik69ae54a2015-07-01 14:52:26 -07001888 // If the file is not a .dex file, the function tries .zip/.jar/.apk files,
Aart Bikdce50862016-06-10 16:04:03 -07001889 // all of which are Zip archives with "classes.dex" inside.
David Sehr999646d2018-02-16 10:22:33 -08001890 // TODO: add an api to android::base to read a std::vector<uint8_t>.
1891 if (!android::base::ReadFileToString(fileName, &content)) {
1892 LOG(ERROR) << "ReadFileToString failed";
David Sehr5a1f6292018-01-19 11:08:51 -08001893 return -1;
1894 }
1895 const DexFileLoader dex_file_loader;
Dario Frenie166fac2018-07-16 11:08:03 +01001896 DexFileLoaderErrorCode error_code;
David Sehr999646d2018-02-16 10:22:33 -08001897 std::string error_msg;
Aart Bik69ae54a2015-07-01 14:52:26 -07001898 std::vector<std::unique_ptr<const DexFile>> dex_files;
David Sehr999646d2018-02-16 10:22:33 -08001899 if (!dex_file_loader.OpenAll(reinterpret_cast<const uint8_t*>(content.data()),
1900 content.size(),
1901 fileName,
Nicolas Geoffrayc1d8caa2018-02-27 10:15:14 +00001902 kVerify,
David Sehr999646d2018-02-16 10:22:33 -08001903 kVerifyChecksum,
Dario Frenie166fac2018-07-16 11:08:03 +01001904 &error_code,
David Sehr999646d2018-02-16 10:22:33 -08001905 &error_msg,
1906 &dex_files)) {
Aart Bik69ae54a2015-07-01 14:52:26 -07001907 // Display returned error message to user. Note that this error behavior
1908 // differs from the error messages shown by the original Dalvik dexdump.
Andreas Gampe221d9812018-01-22 17:48:56 -08001909 LOG(ERROR) << error_msg;
Aart Bik69ae54a2015-07-01 14:52:26 -07001910 return -1;
1911 }
1912
Aart Bik4e149602015-07-09 11:45:28 -07001913 // Success. Either report checksum verification or process
1914 // all dex files found in given file.
Aart Bik69ae54a2015-07-01 14:52:26 -07001915 if (gOptions.checksumOnly) {
1916 fprintf(gOutFile, "Checksum verified\n");
1917 } else {
Paul Duffin4b64f6c2020-10-30 11:58:47 +00001918 // Open XML context.
1919 if (gOptions.outputFormat == OUTPUT_XML) {
1920 fprintf(gOutFile, "<api>\n");
1921 }
1922
Aart Bik7b45a8a2016-10-24 16:07:59 -07001923 for (size_t i = 0, n = dex_files.size(); i < n; i++) {
1924 processDexFile(fileName, dex_files[i].get(), i, n);
Aart Bik4e149602015-07-09 11:45:28 -07001925 }
Paul Duffin4b64f6c2020-10-30 11:58:47 +00001926
1927 // Close XML context.
1928 if (gOptions.outputFormat == OUTPUT_XML) {
1929 fprintf(gOutFile, "</api>\n");
1930 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001931 }
1932 return 0;
1933}
1934
1935} // namespace art