blob: 2ab98ec8840250c8288ab38b1baaeb424b7aad3d [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>
Orion Hodson261fcf42022-02-24 12:59:57 +000044#include <string_view>
Aart Bik69ae54a2015-07-01 14:52:26 -070045#include <vector>
46
David Sehr999646d2018-02-16 10:22:33 -080047#include "android-base/file.h"
Andreas Gampe221d9812018-01-22 17:48:56 -080048#include "android-base/logging.h"
Andreas Gampe46ee31b2016-12-14 10:11:49 -080049#include "android-base/stringprintf.h"
50
Alex Lightcefebc82020-07-22 17:59:34 -070051#include "base/bit_utils.h"
Mathieu Chartierc2b4db62018-05-18 13:58:12 -070052#include "dex/class_accessor-inl.h"
David Sehr0225f8e2018-01-31 08:52:24 +000053#include "dex/code_item_accessors-inl.h"
David Sehr9e734c72018-01-04 17:56:19 -080054#include "dex/dex_file-inl.h"
55#include "dex/dex_file_exception_helpers.h"
56#include "dex/dex_file_loader.h"
57#include "dex/dex_file_types.h"
58#include "dex/dex_instruction-inl.h"
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070059#include "dexdump_cfg.h"
Aart Bik69ae54a2015-07-01 14:52:26 -070060
61namespace art {
62
63/*
64 * Options parsed in main driver.
65 */
66struct Options gOptions;
67
68/*
Aart Bik4e149602015-07-09 11:45:28 -070069 * Output file. Defaults to stdout.
Aart Bik69ae54a2015-07-01 14:52:26 -070070 */
71FILE* gOutFile = stdout;
72
73/*
74 * Data types that match the definitions in the VM specification.
75 */
Andreas Gampec55bb392018-09-21 00:02:02 +000076using u1 = uint8_t;
77using u2 = uint16_t;
78using u4 = uint32_t;
79using u8 = uint64_t;
80using s1 = int8_t;
81using s2 = int16_t;
82using s4 = int32_t;
83using s8 = int64_t;
Aart Bik69ae54a2015-07-01 14:52:26 -070084
85/*
86 * Basic information about a field or a method.
87 */
88struct FieldMethodInfo {
89 const char* classDescriptor;
90 const char* name;
91 const char* signature;
92};
93
94/*
95 * Flags for use with createAccessFlagStr().
96 */
97enum AccessFor {
98 kAccessForClass = 0, kAccessForMethod = 1, kAccessForField = 2, kAccessForMAX
99};
100const int kNumFlags = 18;
101
102/*
103 * Gets 2 little-endian bytes.
104 */
105static inline u2 get2LE(unsigned char const* pSrc) {
106 return pSrc[0] | (pSrc[1] << 8);
107}
108
109/*
110 * Converts a single-character primitive type into human-readable form.
111 */
112static const char* primitiveTypeLabel(char typeChar) {
113 switch (typeChar) {
114 case 'B': return "byte";
115 case 'C': return "char";
116 case 'D': return "double";
117 case 'F': return "float";
118 case 'I': return "int";
119 case 'J': return "long";
120 case 'S': return "short";
121 case 'V': return "void";
122 case 'Z': return "boolean";
123 default: return "UNKNOWN";
124 } // switch
125}
126
127/*
128 * Converts a type descriptor to human-readable "dotted" form. For
129 * example, "Ljava/lang/String;" becomes "java.lang.String", and
Orion Hodsonfe42d212018-08-24 14:01:14 +0100130 * "[I" becomes "int[]".
Aart Bik69ae54a2015-07-01 14:52:26 -0700131 */
Aart Bikc05e2f22016-07-12 15:53:13 -0700132static std::unique_ptr<char[]> descriptorToDot(const char* str) {
Aart Bik69ae54a2015-07-01 14:52:26 -0700133 int targetLen = strlen(str);
134 int offset = 0;
135
136 // Strip leading [s; will be added to end.
137 while (targetLen > 1 && str[offset] == '[') {
138 offset++;
139 targetLen--;
140 } // while
141
142 const int arrayDepth = offset;
143
144 if (targetLen == 1) {
145 // Primitive type.
146 str = primitiveTypeLabel(str[offset]);
147 offset = 0;
148 targetLen = strlen(str);
149 } else {
150 // Account for leading 'L' and trailing ';'.
151 if (targetLen >= 2 && str[offset] == 'L' &&
152 str[offset + targetLen - 1] == ';') {
153 targetLen -= 2;
154 offset++;
155 }
156 }
157
158 // Copy class name over.
Aart Bikc05e2f22016-07-12 15:53:13 -0700159 std::unique_ptr<char[]> newStr(new char[targetLen + arrayDepth * 2 + 1]);
Aart Bik69ae54a2015-07-01 14:52:26 -0700160 int i = 0;
161 for (; i < targetLen; i++) {
162 const char ch = str[offset + i];
Orion Hodsonfe42d212018-08-24 14:01:14 +0100163 newStr[i] = (ch == '/') ? '.' : ch;
Aart Bik69ae54a2015-07-01 14:52:26 -0700164 } // for
165
166 // Add the appropriate number of brackets for arrays.
167 for (int j = 0; j < arrayDepth; j++) {
168 newStr[i++] = '[';
169 newStr[i++] = ']';
170 } // for
171
172 newStr[i] = '\0';
173 return newStr;
174}
175
176/*
Orion Hodsonfe42d212018-08-24 14:01:14 +0100177 * Retrieves the class name portion of a type descriptor.
Aart Bik69ae54a2015-07-01 14:52:26 -0700178 */
Orion Hodsonfe42d212018-08-24 14:01:14 +0100179static std::unique_ptr<char[]> descriptorClassToName(const char* str) {
Aart Bikc05e2f22016-07-12 15:53:13 -0700180 // Reduce to just the class name prefix.
Aart Bik69ae54a2015-07-01 14:52:26 -0700181 const char* lastSlash = strrchr(str, '/');
182 if (lastSlash == nullptr) {
183 lastSlash = str + 1; // start past 'L'
184 } else {
185 lastSlash++; // start past '/'
186 }
187
Aart Bikc05e2f22016-07-12 15:53:13 -0700188 // Copy class name over, trimming trailing ';'.
189 const int targetLen = strlen(lastSlash);
190 std::unique_ptr<char[]> newStr(new char[targetLen]);
191 for (int i = 0; i < targetLen - 1; i++) {
Orion Hodsonfe42d212018-08-24 14:01:14 +0100192 newStr[i] = lastSlash[i];
Aart Bik69ae54a2015-07-01 14:52:26 -0700193 } // for
Aart Bikc05e2f22016-07-12 15:53:13 -0700194 newStr[targetLen - 1] = '\0';
Aart Bik69ae54a2015-07-01 14:52:26 -0700195 return newStr;
196}
197
198/*
Aart Bikdce50862016-06-10 16:04:03 -0700199 * Returns string representing the boolean value.
200 */
201static const char* strBool(bool val) {
202 return val ? "true" : "false";
203}
204
205/*
Aart Bik69ae54a2015-07-01 14:52:26 -0700206 * Returns a quoted string representing the boolean value.
207 */
208static const char* quotedBool(bool val) {
209 return val ? "\"true\"" : "\"false\"";
210}
211
212/*
213 * Returns a quoted string representing the access flags.
214 */
215static const char* quotedVisibility(u4 accessFlags) {
216 if (accessFlags & kAccPublic) {
217 return "\"public\"";
218 } else if (accessFlags & kAccProtected) {
219 return "\"protected\"";
220 } else if (accessFlags & kAccPrivate) {
221 return "\"private\"";
222 } else {
223 return "\"package\"";
224 }
225}
226
227/*
228 * Counts the number of '1' bits in a word.
229 */
230static int countOnes(u4 val) {
231 val = val - ((val >> 1) & 0x55555555);
232 val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
233 return (((val + (val >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
234}
235
236/*
237 * Creates a new string with human-readable access flags.
238 *
239 * In the base language the access_flags fields are type u2; in Dalvik
240 * they're u4.
241 */
242static char* createAccessFlagStr(u4 flags, AccessFor forWhat) {
243 static const char* kAccessStrings[kAccessForMAX][kNumFlags] = {
244 {
245 "PUBLIC", /* 0x00001 */
246 "PRIVATE", /* 0x00002 */
247 "PROTECTED", /* 0x00004 */
248 "STATIC", /* 0x00008 */
249 "FINAL", /* 0x00010 */
250 "?", /* 0x00020 */
251 "?", /* 0x00040 */
252 "?", /* 0x00080 */
253 "?", /* 0x00100 */
254 "INTERFACE", /* 0x00200 */
255 "ABSTRACT", /* 0x00400 */
256 "?", /* 0x00800 */
257 "SYNTHETIC", /* 0x01000 */
258 "ANNOTATION", /* 0x02000 */
259 "ENUM", /* 0x04000 */
260 "?", /* 0x08000 */
261 "VERIFIED", /* 0x10000 */
262 "OPTIMIZED", /* 0x20000 */
263 }, {
264 "PUBLIC", /* 0x00001 */
265 "PRIVATE", /* 0x00002 */
266 "PROTECTED", /* 0x00004 */
267 "STATIC", /* 0x00008 */
268 "FINAL", /* 0x00010 */
269 "SYNCHRONIZED", /* 0x00020 */
270 "BRIDGE", /* 0x00040 */
271 "VARARGS", /* 0x00080 */
272 "NATIVE", /* 0x00100 */
273 "?", /* 0x00200 */
274 "ABSTRACT", /* 0x00400 */
275 "STRICT", /* 0x00800 */
276 "SYNTHETIC", /* 0x01000 */
277 "?", /* 0x02000 */
278 "?", /* 0x04000 */
279 "MIRANDA", /* 0x08000 */
280 "CONSTRUCTOR", /* 0x10000 */
281 "DECLARED_SYNCHRONIZED", /* 0x20000 */
282 }, {
283 "PUBLIC", /* 0x00001 */
284 "PRIVATE", /* 0x00002 */
285 "PROTECTED", /* 0x00004 */
286 "STATIC", /* 0x00008 */
287 "FINAL", /* 0x00010 */
288 "?", /* 0x00020 */
289 "VOLATILE", /* 0x00040 */
290 "TRANSIENT", /* 0x00080 */
291 "?", /* 0x00100 */
292 "?", /* 0x00200 */
293 "?", /* 0x00400 */
294 "?", /* 0x00800 */
295 "SYNTHETIC", /* 0x01000 */
296 "?", /* 0x02000 */
297 "ENUM", /* 0x04000 */
298 "?", /* 0x08000 */
299 "?", /* 0x10000 */
300 "?", /* 0x20000 */
301 },
302 };
303
304 // Allocate enough storage to hold the expected number of strings,
305 // plus a space between each. We over-allocate, using the longest
306 // string above as the base metric.
307 const int kLongest = 21; // The strlen of longest string above.
308 const int count = countOnes(flags);
309 char* str;
310 char* cp;
311 cp = str = reinterpret_cast<char*>(malloc(count * (kLongest + 1) + 1));
312
313 for (int i = 0; i < kNumFlags; i++) {
314 if (flags & 0x01) {
315 const char* accessStr = kAccessStrings[forWhat][i];
316 const int len = strlen(accessStr);
317 if (cp != str) {
318 *cp++ = ' ';
319 }
320 memcpy(cp, accessStr, len);
321 cp += len;
322 }
323 flags >>= 1;
324 } // for
325
326 *cp = '\0';
327 return str;
328}
329
330/*
331 * Copies character data from "data" to "out", converting non-ASCII values
332 * to fprintf format chars or an ASCII filler ('.' or '?').
333 *
334 * The output buffer must be able to hold (2*len)+1 bytes. The result is
335 * NULL-terminated.
336 */
337static void asciify(char* out, const unsigned char* data, size_t len) {
Andreas Gampec74d9cb2018-09-20 13:44:44 -0700338 for (; len != 0u; --len) {
Aart Bik69ae54a2015-07-01 14:52:26 -0700339 if (*data < 0x20) {
340 // Could do more here, but we don't need them yet.
341 switch (*data) {
342 case '\0':
343 *out++ = '\\';
344 *out++ = '0';
345 break;
346 case '\n':
347 *out++ = '\\';
348 *out++ = 'n';
349 break;
350 default:
351 *out++ = '.';
352 break;
353 } // switch
354 } else if (*data >= 0x80) {
355 *out++ = '?';
356 } else {
357 *out++ = *data;
358 }
359 data++;
360 } // while
361 *out = '\0';
362}
363
Orion Hodson261fcf42022-02-24 12:59:57 +0000364/* clang-format off */
365constexpr char kEscapedLength[256] = {
366 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 4, 2, 2, 4, 4, // \a, \b, \t, \n, \r
367 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
368 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // ",
369 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // '0'..'9'
370 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 'A'..'O'
371 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, // 'P'..'Z', '\'
372 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 'a'..'o'
373 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, // 'p'..'z', DEL
374 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // Unicode range, keep
375 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
376 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
377 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
378 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
379 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
380 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
381 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
382};
383/* clang-format on */
384
385/*
386 * Check if a UTF8 string contains characters we should quote.
387 */
388static bool needsEscape(std::string_view s) {
389 for (unsigned char c : s) {
390 if (kEscapedLength[c] != 1) {
391 return true;
392 }
393 }
394 return false;
395}
396
397std::string escapeString(std::string_view s) {
398 std::ostringstream oss;
399 for (unsigned char c : s) {
400 switch (kEscapedLength[c]) {
401 case 1:
402 oss << static_cast<char>(c);
403 break;
404 case 2:
405 switch (c) {
406 case '\b':
407 oss << '\\' << 'b';
408 break;
409 case '\f':
410 oss << '\\' << 'f';
411 break;
412 case '\n':
413 oss << '\\' << 'n';
414 break;
415 case '\r':
416 oss << '\\' << 'r';
417 break;
418 case '\t':
419 oss << '\\' << 't';
420 break;
421 case '\"':
422 oss << '\\' << '"';
423 break;
424 case '\\':
425 oss << '\\' << '\\';
426 break;
427 }
428 break;
429 case 4:
430 oss << '\\' << '0' + (c / 64) << '0' + ((c % 64) / 8) << '0' + (c % 8);
431 break;
432 }
433 }
434 return oss.str();
435}
436
Aart Bik69ae54a2015-07-01 14:52:26 -0700437/*
Aart Bikdce50862016-06-10 16:04:03 -0700438 * Dumps a string value with some escape characters.
439 */
Orion Hodson261fcf42022-02-24 12:59:57 +0000440static void dumpEscapedString(std::string_view s) {
Aart Bikdce50862016-06-10 16:04:03 -0700441 fputs("\"", gOutFile);
Orion Hodson261fcf42022-02-24 12:59:57 +0000442 if (needsEscape(s)) {
443 std::string e = escapeString(s);
444 fputs(e.c_str(), gOutFile);
445 } else {
446 for (char c : s) {
447 fputc(c, gOutFile);
448 }
449 }
Aart Bikdce50862016-06-10 16:04:03 -0700450 fputs("\"", gOutFile);
451}
452
Alex Lightcefebc82020-07-22 17:59:34 -0700453static size_t utf8Bytes(char start_byte) {
454 uint8_t sb = static_cast<uint8_t>(start_byte);
455 if ((sb & 0x80) == 0) {
456 return 1;
457 }
458 size_t msb = art::MostSignificantBit(static_cast<uint8_t>(~sb));
459 CHECK_LE(7u - msb, 4u);
460 return 7 - msb;
461}
462
Aart Bikdce50862016-06-10 16:04:03 -0700463/*
464 * Dumps a string as an XML attribute value.
465 */
Alex Lightcefebc82020-07-22 17:59:34 -0700466static void dumpXmlAttribute(std::string_view p) __attribute__((optnone)) {
467 for (const char* c = p.begin(); c < p.end(); ++c) {
468 if (std::isprint(*c)) {
469 switch (*c) {
470 case '&':
471 fputs("&amp;", gOutFile);
472 break;
473 case '<':
474 fputs("&lt;", gOutFile);
475 break;
476 case '>':
477 fputs("&gt;", gOutFile);
478 break;
479 case '"':
480 fputs("&quot;", gOutFile);
481 break;
482 case '\\':
483 fputs("\\\\", gOutFile);
484 break;
485 default:
486 putc(*c, gOutFile);
487 } // switch
488 } else {
489 uint32_t data = 0;
490 size_t remaining;
491 uint8_t uc = static_cast<uint8_t>(*c);
492 if (((uc) & 0x80) == 0) {
493 // Not a multi-byte char
494 data = static_cast<uint32_t>(*c);
495 remaining = 0;
496 } else if (utf8Bytes(uc) == 2) {
497 // 2 bytes
498 data = ((uc) & 0b00011111);
499 remaining = 1;
500 } else if (utf8Bytes(uc) == 3) {
501 // 3 bytes
502 data = ((uc) & 0b00001111);
503 remaining = 2;
504 } else {
505 // 4 bytes
506 CHECK_EQ(utf8Bytes(uc), 4u);
507 data = ((uc) & 0b00000111);
508 remaining = 3;
509 }
510 for (size_t i = 0; i < remaining; ++i) {
511 ++c;
512 data = data << 6;
513 uc = static_cast<uint8_t>(*c);
514 data |= static_cast<uint32_t>(uc & 0b00111111u);
515 }
516 // No good option so just use java encoding, too many chars are invalid
517 fprintf(gOutFile, "\\u%04x", data);
518 }
Aart Bikdce50862016-06-10 16:04:03 -0700519 } // for
520}
521
522/*
523 * Reads variable width value, possibly sign extended at the last defined byte.
524 */
525static u8 readVarWidth(const u1** data, u1 arg, bool sign_extend) {
526 u8 value = 0;
527 for (u4 i = 0; i <= arg; i++) {
528 value |= static_cast<u8>(*(*data)++) << (i * 8);
529 }
530 if (sign_extend) {
531 int shift = (7 - arg) * 8;
532 return (static_cast<s8>(value) << shift) >> shift;
533 }
534 return value;
535}
536
537/*
538 * Dumps encoded value.
539 */
540static void dumpEncodedValue(const DexFile* pDexFile, const u1** data); // forward
541static void dumpEncodedValue(const DexFile* pDexFile, const u1** data, u1 type, u1 arg) {
542 switch (type) {
543 case DexFile::kDexAnnotationByte:
544 fprintf(gOutFile, "%" PRId8, static_cast<s1>(readVarWidth(data, arg, false)));
545 break;
546 case DexFile::kDexAnnotationShort:
547 fprintf(gOutFile, "%" PRId16, static_cast<s2>(readVarWidth(data, arg, true)));
548 break;
549 case DexFile::kDexAnnotationChar:
550 fprintf(gOutFile, "%" PRIu16, static_cast<u2>(readVarWidth(data, arg, false)));
551 break;
552 case DexFile::kDexAnnotationInt:
553 fprintf(gOutFile, "%" PRId32, static_cast<s4>(readVarWidth(data, arg, true)));
554 break;
555 case DexFile::kDexAnnotationLong:
556 fprintf(gOutFile, "%" PRId64, static_cast<s8>(readVarWidth(data, arg, true)));
557 break;
558 case DexFile::kDexAnnotationFloat: {
559 // Fill on right.
560 union {
561 float f;
562 u4 data;
563 } conv;
564 conv.data = static_cast<u4>(readVarWidth(data, arg, false)) << (3 - arg) * 8;
565 fprintf(gOutFile, "%g", conv.f);
566 break;
567 }
568 case DexFile::kDexAnnotationDouble: {
569 // Fill on right.
570 union {
571 double d;
572 u8 data;
573 } conv;
574 conv.data = readVarWidth(data, arg, false) << (7 - arg) * 8;
575 fprintf(gOutFile, "%g", conv.d);
576 break;
577 }
578 case DexFile::kDexAnnotationString: {
579 const u4 idx = static_cast<u4>(readVarWidth(data, arg, false));
580 if (gOptions.outputFormat == OUTPUT_PLAIN) {
Alex Lightcefebc82020-07-22 17:59:34 -0700581 dumpEscapedString(pDexFile->StringViewByIdx(dex::StringIndex(idx)));
Aart Bikdce50862016-06-10 16:04:03 -0700582 } else {
Alex Lightcefebc82020-07-22 17:59:34 -0700583 dumpXmlAttribute(pDexFile->StringViewByIdx(dex::StringIndex(idx)));
Aart Bikdce50862016-06-10 16:04:03 -0700584 }
585 break;
586 }
587 case DexFile::kDexAnnotationType: {
588 const u4 str_idx = static_cast<u4>(readVarWidth(data, arg, false));
Andreas Gampea5b09a62016-11-17 15:21:22 -0800589 fputs(pDexFile->StringByTypeIdx(dex::TypeIndex(str_idx)), gOutFile);
Aart Bikdce50862016-06-10 16:04:03 -0700590 break;
591 }
592 case DexFile::kDexAnnotationField:
593 case DexFile::kDexAnnotationEnum: {
594 const u4 field_idx = static_cast<u4>(readVarWidth(data, arg, false));
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800595 const dex::FieldId& pFieldId = pDexFile->GetFieldId(field_idx);
Aart Bikdce50862016-06-10 16:04:03 -0700596 fputs(pDexFile->StringDataByIdx(pFieldId.name_idx_), gOutFile);
597 break;
598 }
599 case DexFile::kDexAnnotationMethod: {
600 const u4 method_idx = static_cast<u4>(readVarWidth(data, arg, false));
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800601 const dex::MethodId& pMethodId = pDexFile->GetMethodId(method_idx);
Aart Bikdce50862016-06-10 16:04:03 -0700602 fputs(pDexFile->StringDataByIdx(pMethodId.name_idx_), gOutFile);
603 break;
604 }
605 case DexFile::kDexAnnotationArray: {
606 fputc('{', gOutFile);
607 // Decode and display all elements.
608 const u4 size = DecodeUnsignedLeb128(data);
609 for (u4 i = 0; i < size; i++) {
610 fputc(' ', gOutFile);
611 dumpEncodedValue(pDexFile, data);
612 }
613 fputs(" }", gOutFile);
614 break;
615 }
616 case DexFile::kDexAnnotationAnnotation: {
617 const u4 type_idx = DecodeUnsignedLeb128(data);
Andreas Gampea5b09a62016-11-17 15:21:22 -0800618 fputs(pDexFile->StringByTypeIdx(dex::TypeIndex(type_idx)), gOutFile);
Aart Bikdce50862016-06-10 16:04:03 -0700619 // Decode and display all name=value pairs.
620 const u4 size = DecodeUnsignedLeb128(data);
621 for (u4 i = 0; i < size; i++) {
622 const u4 name_idx = DecodeUnsignedLeb128(data);
623 fputc(' ', gOutFile);
Andreas Gampe8a0128a2016-11-28 07:38:35 -0800624 fputs(pDexFile->StringDataByIdx(dex::StringIndex(name_idx)), gOutFile);
Aart Bikdce50862016-06-10 16:04:03 -0700625 fputc('=', gOutFile);
626 dumpEncodedValue(pDexFile, data);
627 }
628 break;
629 }
630 case DexFile::kDexAnnotationNull:
631 fputs("null", gOutFile);
632 break;
633 case DexFile::kDexAnnotationBoolean:
634 fputs(strBool(arg), gOutFile);
635 break;
636 default:
637 fputs("????", gOutFile);
638 break;
639 } // switch
640}
641
642/*
643 * Dumps encoded value with prefix.
644 */
645static void dumpEncodedValue(const DexFile* pDexFile, const u1** data) {
646 const u1 enc = *(*data)++;
647 dumpEncodedValue(pDexFile, data, enc & 0x1f, enc >> 5);
648}
649
650/*
Aart Bik69ae54a2015-07-01 14:52:26 -0700651 * Dumps the file header.
Aart Bik69ae54a2015-07-01 14:52:26 -0700652 */
653static void dumpFileHeader(const DexFile* pDexFile) {
654 const DexFile::Header& pHeader = pDexFile->GetHeader();
655 char sanitized[sizeof(pHeader.magic_) * 2 + 1];
656 fprintf(gOutFile, "DEX file header:\n");
657 asciify(sanitized, pHeader.magic_, sizeof(pHeader.magic_));
658 fprintf(gOutFile, "magic : '%s'\n", sanitized);
659 fprintf(gOutFile, "checksum : %08x\n", pHeader.checksum_);
660 fprintf(gOutFile, "signature : %02x%02x...%02x%02x\n",
661 pHeader.signature_[0], pHeader.signature_[1],
662 pHeader.signature_[DexFile::kSha1DigestSize - 2],
663 pHeader.signature_[DexFile::kSha1DigestSize - 1]);
664 fprintf(gOutFile, "file_size : %d\n", pHeader.file_size_);
665 fprintf(gOutFile, "header_size : %d\n", pHeader.header_size_);
666 fprintf(gOutFile, "link_size : %d\n", pHeader.link_size_);
667 fprintf(gOutFile, "link_off : %d (0x%06x)\n",
668 pHeader.link_off_, pHeader.link_off_);
669 fprintf(gOutFile, "string_ids_size : %d\n", pHeader.string_ids_size_);
670 fprintf(gOutFile, "string_ids_off : %d (0x%06x)\n",
671 pHeader.string_ids_off_, pHeader.string_ids_off_);
672 fprintf(gOutFile, "type_ids_size : %d\n", pHeader.type_ids_size_);
673 fprintf(gOutFile, "type_ids_off : %d (0x%06x)\n",
674 pHeader.type_ids_off_, pHeader.type_ids_off_);
Aart Bikdce50862016-06-10 16:04:03 -0700675 fprintf(gOutFile, "proto_ids_size : %d\n", pHeader.proto_ids_size_);
676 fprintf(gOutFile, "proto_ids_off : %d (0x%06x)\n",
Aart Bik69ae54a2015-07-01 14:52:26 -0700677 pHeader.proto_ids_off_, pHeader.proto_ids_off_);
678 fprintf(gOutFile, "field_ids_size : %d\n", pHeader.field_ids_size_);
679 fprintf(gOutFile, "field_ids_off : %d (0x%06x)\n",
680 pHeader.field_ids_off_, pHeader.field_ids_off_);
681 fprintf(gOutFile, "method_ids_size : %d\n", pHeader.method_ids_size_);
682 fprintf(gOutFile, "method_ids_off : %d (0x%06x)\n",
683 pHeader.method_ids_off_, pHeader.method_ids_off_);
684 fprintf(gOutFile, "class_defs_size : %d\n", pHeader.class_defs_size_);
685 fprintf(gOutFile, "class_defs_off : %d (0x%06x)\n",
686 pHeader.class_defs_off_, pHeader.class_defs_off_);
687 fprintf(gOutFile, "data_size : %d\n", pHeader.data_size_);
688 fprintf(gOutFile, "data_off : %d (0x%06x)\n\n",
689 pHeader.data_off_, pHeader.data_off_);
690}
691
692/*
693 * Dumps a class_def_item.
694 */
695static void dumpClassDef(const DexFile* pDexFile, int idx) {
696 // General class information.
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800697 const dex::ClassDef& pClassDef = pDexFile->GetClassDef(idx);
Aart Bik69ae54a2015-07-01 14:52:26 -0700698 fprintf(gOutFile, "Class #%d header:\n", idx);
Andreas Gampea5b09a62016-11-17 15:21:22 -0800699 fprintf(gOutFile, "class_idx : %d\n", pClassDef.class_idx_.index_);
Aart Bik69ae54a2015-07-01 14:52:26 -0700700 fprintf(gOutFile, "access_flags : %d (0x%04x)\n",
701 pClassDef.access_flags_, pClassDef.access_flags_);
Andreas Gampea5b09a62016-11-17 15:21:22 -0800702 fprintf(gOutFile, "superclass_idx : %d\n", pClassDef.superclass_idx_.index_);
Aart Bik69ae54a2015-07-01 14:52:26 -0700703 fprintf(gOutFile, "interfaces_off : %d (0x%06x)\n",
704 pClassDef.interfaces_off_, pClassDef.interfaces_off_);
Andreas Gampe8a0128a2016-11-28 07:38:35 -0800705 fprintf(gOutFile, "source_file_idx : %d\n", pClassDef.source_file_idx_.index_);
Aart Bik69ae54a2015-07-01 14:52:26 -0700706 fprintf(gOutFile, "annotations_off : %d (0x%06x)\n",
707 pClassDef.annotations_off_, pClassDef.annotations_off_);
708 fprintf(gOutFile, "class_data_off : %d (0x%06x)\n",
709 pClassDef.class_data_off_, pClassDef.class_data_off_);
710
711 // Fields and methods.
Mathieu Chartier18e26872018-06-04 17:19:02 -0700712 ClassAccessor accessor(*pDexFile, idx);
Mathieu Chartierc2b4db62018-05-18 13:58:12 -0700713 fprintf(gOutFile, "static_fields_size : %d\n", accessor.NumStaticFields());
714 fprintf(gOutFile, "instance_fields_size: %d\n", accessor.NumInstanceFields());
715 fprintf(gOutFile, "direct_methods_size : %d\n", accessor.NumDirectMethods());
716 fprintf(gOutFile, "virtual_methods_size: %d\n", accessor.NumVirtualMethods());
Aart Bik69ae54a2015-07-01 14:52:26 -0700717 fprintf(gOutFile, "\n");
718}
719
Aart Bikdce50862016-06-10 16:04:03 -0700720/**
721 * Dumps an annotation set item.
722 */
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800723static void dumpAnnotationSetItem(const DexFile* pDexFile, const dex::AnnotationSetItem* set_item) {
Aart Bikdce50862016-06-10 16:04:03 -0700724 if (set_item == nullptr || set_item->size_ == 0) {
725 fputs(" empty-annotation-set\n", gOutFile);
726 return;
727 }
728 for (u4 i = 0; i < set_item->size_; i++) {
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800729 const dex::AnnotationItem* annotation = pDexFile->GetAnnotationItem(set_item, i);
Aart Bikdce50862016-06-10 16:04:03 -0700730 if (annotation == nullptr) {
731 continue;
732 }
733 fputs(" ", gOutFile);
734 switch (annotation->visibility_) {
735 case DexFile::kDexVisibilityBuild: fputs("VISIBILITY_BUILD ", gOutFile); break;
736 case DexFile::kDexVisibilityRuntime: fputs("VISIBILITY_RUNTIME ", gOutFile); break;
737 case DexFile::kDexVisibilitySystem: fputs("VISIBILITY_SYSTEM ", gOutFile); break;
738 default: fputs("VISIBILITY_UNKNOWN ", gOutFile); break;
739 } // switch
740 // Decode raw bytes in annotation.
741 const u1* rData = annotation->annotation_;
742 dumpEncodedValue(pDexFile, &rData, DexFile::kDexAnnotationAnnotation, 0);
743 fputc('\n', gOutFile);
744 }
745}
746
747/*
748 * Dumps class annotations.
749 */
750static void dumpClassAnnotations(const DexFile* pDexFile, int idx) {
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800751 const dex::ClassDef& pClassDef = pDexFile->GetClassDef(idx);
752 const dex::AnnotationsDirectoryItem* dir = pDexFile->GetAnnotationsDirectory(pClassDef);
Aart Bikdce50862016-06-10 16:04:03 -0700753 if (dir == nullptr) {
754 return; // none
755 }
756
757 fprintf(gOutFile, "Class #%d annotations:\n", idx);
758
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800759 const dex::AnnotationSetItem* class_set_item = pDexFile->GetClassAnnotationSet(dir);
760 const dex::FieldAnnotationsItem* fields = pDexFile->GetFieldAnnotations(dir);
761 const dex::MethodAnnotationsItem* methods = pDexFile->GetMethodAnnotations(dir);
762 const dex::ParameterAnnotationsItem* pars = pDexFile->GetParameterAnnotations(dir);
Aart Bikdce50862016-06-10 16:04:03 -0700763
764 // Annotations on the class itself.
765 if (class_set_item != nullptr) {
766 fprintf(gOutFile, "Annotations on class\n");
767 dumpAnnotationSetItem(pDexFile, class_set_item);
768 }
769
770 // Annotations on fields.
771 if (fields != nullptr) {
772 for (u4 i = 0; i < dir->fields_size_; i++) {
773 const u4 field_idx = fields[i].field_idx_;
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800774 const dex::FieldId& pFieldId = pDexFile->GetFieldId(field_idx);
Aart Bikdce50862016-06-10 16:04:03 -0700775 const char* field_name = pDexFile->StringDataByIdx(pFieldId.name_idx_);
776 fprintf(gOutFile, "Annotations on field #%u '%s'\n", field_idx, field_name);
777 dumpAnnotationSetItem(pDexFile, pDexFile->GetFieldAnnotationSetItem(fields[i]));
778 }
779 }
780
781 // Annotations on methods.
782 if (methods != nullptr) {
783 for (u4 i = 0; i < dir->methods_size_; i++) {
784 const u4 method_idx = methods[i].method_idx_;
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800785 const dex::MethodId& pMethodId = pDexFile->GetMethodId(method_idx);
Aart Bikdce50862016-06-10 16:04:03 -0700786 const char* method_name = pDexFile->StringDataByIdx(pMethodId.name_idx_);
787 fprintf(gOutFile, "Annotations on method #%u '%s'\n", method_idx, method_name);
788 dumpAnnotationSetItem(pDexFile, pDexFile->GetMethodAnnotationSetItem(methods[i]));
789 }
790 }
791
792 // Annotations on method parameters.
793 if (pars != nullptr) {
794 for (u4 i = 0; i < dir->parameters_size_; i++) {
795 const u4 method_idx = pars[i].method_idx_;
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800796 const dex::MethodId& pMethodId = pDexFile->GetMethodId(method_idx);
Aart Bikdce50862016-06-10 16:04:03 -0700797 const char* method_name = pDexFile->StringDataByIdx(pMethodId.name_idx_);
798 fprintf(gOutFile, "Annotations on method #%u '%s' parameters\n", method_idx, method_name);
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800799 const dex::AnnotationSetRefList*
Aart Bikdce50862016-06-10 16:04:03 -0700800 list = pDexFile->GetParameterAnnotationSetRefList(&pars[i]);
801 if (list != nullptr) {
802 for (u4 j = 0; j < list->size_; j++) {
803 fprintf(gOutFile, "#%u\n", j);
804 dumpAnnotationSetItem(pDexFile, pDexFile->GetSetRefItemItem(&list->list_[j]));
805 }
806 }
807 }
808 }
809
810 fputc('\n', gOutFile);
811}
812
Aart Bik69ae54a2015-07-01 14:52:26 -0700813/*
814 * Dumps an interface that a class declares to implement.
815 */
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800816static void dumpInterface(const DexFile* pDexFile, const dex::TypeItem& pTypeItem, int i) {
Aart Bik69ae54a2015-07-01 14:52:26 -0700817 const char* interfaceName = pDexFile->StringByTypeIdx(pTypeItem.type_idx_);
818 if (gOptions.outputFormat == OUTPUT_PLAIN) {
819 fprintf(gOutFile, " #%d : '%s'\n", i, interfaceName);
820 } else {
Aart Bikc05e2f22016-07-12 15:53:13 -0700821 std::unique_ptr<char[]> dot(descriptorToDot(interfaceName));
822 fprintf(gOutFile, "<implements name=\"%s\">\n</implements>\n", dot.get());
Aart Bik69ae54a2015-07-01 14:52:26 -0700823 }
824}
825
826/*
827 * Dumps the catches table associated with the code.
828 */
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800829static void dumpCatches(const DexFile* pDexFile, const dex::CodeItem* pCode) {
Mathieu Chartier698ebbc2018-01-05 11:00:42 -0800830 CodeItemDataAccessor accessor(*pDexFile, pCode);
Mathieu Chartierdc578c72017-12-27 11:51:45 -0800831 const u4 triesSize = accessor.TriesSize();
Aart Bik69ae54a2015-07-01 14:52:26 -0700832
833 // No catch table.
834 if (triesSize == 0) {
835 fprintf(gOutFile, " catches : (none)\n");
836 return;
837 }
838
839 // Dump all table entries.
840 fprintf(gOutFile, " catches : %d\n", triesSize);
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800841 for (const dex::TryItem& try_item : accessor.TryItems()) {
Mathieu Chartierdc578c72017-12-27 11:51:45 -0800842 const u4 start = try_item.start_addr_;
843 const u4 end = start + try_item.insn_count_;
Aart Bik69ae54a2015-07-01 14:52:26 -0700844 fprintf(gOutFile, " 0x%04x - 0x%04x\n", start, end);
Mathieu Chartierdc578c72017-12-27 11:51:45 -0800845 for (CatchHandlerIterator it(accessor, try_item); it.HasNext(); it.Next()) {
Andreas Gampea5b09a62016-11-17 15:21:22 -0800846 const dex::TypeIndex tidx = it.GetHandlerTypeIndex();
847 const char* descriptor = (!tidx.IsValid()) ? "<any>" : pDexFile->StringByTypeIdx(tidx);
Aart Bik69ae54a2015-07-01 14:52:26 -0700848 fprintf(gOutFile, " %s -> 0x%04x\n", descriptor, it.GetHandlerAddress());
849 } // for
850 } // for
851}
852
853/*
Aart Bik69ae54a2015-07-01 14:52:26 -0700854 * Helper for dumpInstruction(), which builds the string
Aart Bika0e33fd2016-07-08 18:32:45 -0700855 * representation for the index in the given instruction.
856 * Returns a pointer to a buffer of sufficient size.
Aart Bik69ae54a2015-07-01 14:52:26 -0700857 */
Aart Bika0e33fd2016-07-08 18:32:45 -0700858static std::unique_ptr<char[]> indexString(const DexFile* pDexFile,
859 const Instruction* pDecInsn,
860 size_t bufSize) {
861 std::unique_ptr<char[]> buf(new char[bufSize]);
Aart Bik69ae54a2015-07-01 14:52:26 -0700862 // Determine index and width of the string.
863 u4 index = 0;
Orion Hodson06d10a72018-05-14 08:53:38 +0100864 u2 secondary_index = 0;
Aart Bik69ae54a2015-07-01 14:52:26 -0700865 u4 width = 4;
866 switch (Instruction::FormatOf(pDecInsn->Opcode())) {
867 // SOME NOT SUPPORTED:
868 // case Instruction::k20bc:
869 case Instruction::k21c:
870 case Instruction::k35c:
871 // case Instruction::k35ms:
872 case Instruction::k3rc:
873 // case Instruction::k3rms:
874 // case Instruction::k35mi:
875 // case Instruction::k3rmi:
876 index = pDecInsn->VRegB();
877 width = 4;
878 break;
879 case Instruction::k31c:
880 index = pDecInsn->VRegB();
881 width = 8;
882 break;
883 case Instruction::k22c:
884 // case Instruction::k22cs:
885 index = pDecInsn->VRegC();
886 width = 4;
887 break;
Orion Hodsonb34bb192016-10-18 17:02:58 +0100888 case Instruction::k45cc:
889 case Instruction::k4rcc:
890 index = pDecInsn->VRegB();
891 secondary_index = pDecInsn->VRegH();
892 width = 4;
893 break;
Aart Bik69ae54a2015-07-01 14:52:26 -0700894 default:
895 break;
896 } // switch
897
898 // Determine index type.
899 size_t outSize = 0;
900 switch (Instruction::IndexTypeOf(pDecInsn->Opcode())) {
901 case Instruction::kIndexUnknown:
902 // This function should never get called for this type, but do
903 // something sensible here, just to help with debugging.
Aart Bika0e33fd2016-07-08 18:32:45 -0700904 outSize = snprintf(buf.get(), bufSize, "<unknown-index>");
Aart Bik69ae54a2015-07-01 14:52:26 -0700905 break;
906 case Instruction::kIndexNone:
907 // This function should never get called for this type, but do
908 // something sensible here, just to help with debugging.
Aart Bika0e33fd2016-07-08 18:32:45 -0700909 outSize = snprintf(buf.get(), bufSize, "<no-index>");
Aart Bik69ae54a2015-07-01 14:52:26 -0700910 break;
911 case Instruction::kIndexTypeRef:
912 if (index < pDexFile->GetHeader().type_ids_size_) {
Andreas Gampea5b09a62016-11-17 15:21:22 -0800913 const char* tp = pDexFile->StringByTypeIdx(dex::TypeIndex(index));
Aart Bika0e33fd2016-07-08 18:32:45 -0700914 outSize = snprintf(buf.get(), bufSize, "%s // type@%0*x", tp, width, index);
Aart Bik69ae54a2015-07-01 14:52:26 -0700915 } else {
Aart Bika0e33fd2016-07-08 18:32:45 -0700916 outSize = snprintf(buf.get(), bufSize, "<type?> // type@%0*x", width, index);
Aart Bik69ae54a2015-07-01 14:52:26 -0700917 }
918 break;
919 case Instruction::kIndexStringRef:
920 if (index < pDexFile->GetHeader().string_ids_size_) {
Andreas Gampe8a0128a2016-11-28 07:38:35 -0800921 const char* st = pDexFile->StringDataByIdx(dex::StringIndex(index));
Orion Hodson261fcf42022-02-24 12:59:57 +0000922 if (needsEscape(std::string_view(st))) {
923 std::string escaped = escapeString(st);
924 outSize =
925 snprintf(buf.get(), bufSize, "\"%s\" // string@%0*x", escaped.c_str(), width, index);
926 } else {
927 outSize = snprintf(buf.get(), bufSize, "\"%s\" // string@%0*x", st, width, index);
928 }
Aart Bik69ae54a2015-07-01 14:52:26 -0700929 } else {
Aart Bika0e33fd2016-07-08 18:32:45 -0700930 outSize = snprintf(buf.get(), bufSize, "<string?> // string@%0*x", width, index);
Aart Bik69ae54a2015-07-01 14:52:26 -0700931 }
932 break;
933 case Instruction::kIndexMethodRef:
934 if (index < pDexFile->GetHeader().method_ids_size_) {
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800935 const dex::MethodId& pMethodId = pDexFile->GetMethodId(index);
Aart Bik69ae54a2015-07-01 14:52:26 -0700936 const char* name = pDexFile->StringDataByIdx(pMethodId.name_idx_);
937 const Signature signature = pDexFile->GetMethodSignature(pMethodId);
938 const char* backDescriptor = pDexFile->StringByTypeIdx(pMethodId.class_idx_);
Aart Bika0e33fd2016-07-08 18:32:45 -0700939 outSize = snprintf(buf.get(), bufSize, "%s.%s:%s // method@%0*x",
Aart Bik69ae54a2015-07-01 14:52:26 -0700940 backDescriptor, name, signature.ToString().c_str(), width, index);
941 } else {
Aart Bika0e33fd2016-07-08 18:32:45 -0700942 outSize = snprintf(buf.get(), bufSize, "<method?> // method@%0*x", width, index);
Aart Bik69ae54a2015-07-01 14:52:26 -0700943 }
944 break;
945 case Instruction::kIndexFieldRef:
946 if (index < pDexFile->GetHeader().field_ids_size_) {
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800947 const dex::FieldId& pFieldId = pDexFile->GetFieldId(index);
Aart Bik69ae54a2015-07-01 14:52:26 -0700948 const char* name = pDexFile->StringDataByIdx(pFieldId.name_idx_);
949 const char* typeDescriptor = pDexFile->StringByTypeIdx(pFieldId.type_idx_);
950 const char* backDescriptor = pDexFile->StringByTypeIdx(pFieldId.class_idx_);
Aart Bika0e33fd2016-07-08 18:32:45 -0700951 outSize = snprintf(buf.get(), bufSize, "%s.%s:%s // field@%0*x",
Aart Bik69ae54a2015-07-01 14:52:26 -0700952 backDescriptor, name, typeDescriptor, width, index);
953 } else {
Aart Bika0e33fd2016-07-08 18:32:45 -0700954 outSize = snprintf(buf.get(), bufSize, "<field?> // field@%0*x", width, index);
Aart Bik69ae54a2015-07-01 14:52:26 -0700955 }
956 break;
957 case Instruction::kIndexVtableOffset:
Aart Bika0e33fd2016-07-08 18:32:45 -0700958 outSize = snprintf(buf.get(), bufSize, "[%0*x] // vtable #%0*x",
Aart Bik69ae54a2015-07-01 14:52:26 -0700959 width, index, width, index);
960 break;
961 case Instruction::kIndexFieldOffset:
Aart Bika0e33fd2016-07-08 18:32:45 -0700962 outSize = snprintf(buf.get(), bufSize, "[obj+%0*x]", width, index);
Aart Bik69ae54a2015-07-01 14:52:26 -0700963 break;
Orion Hodsonb34bb192016-10-18 17:02:58 +0100964 case Instruction::kIndexMethodAndProtoRef: {
Orion Hodsonc069a302017-01-18 09:23:12 +0000965 std::string method("<method?>");
966 std::string proto("<proto?>");
967 if (index < pDexFile->GetHeader().method_ids_size_) {
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800968 const dex::MethodId& pMethodId = pDexFile->GetMethodId(index);
Orion Hodsonc069a302017-01-18 09:23:12 +0000969 const char* name = pDexFile->StringDataByIdx(pMethodId.name_idx_);
970 const Signature signature = pDexFile->GetMethodSignature(pMethodId);
971 const char* backDescriptor = pDexFile->StringByTypeIdx(pMethodId.class_idx_);
972 method = android::base::StringPrintf("%s.%s:%s",
973 backDescriptor,
974 name,
975 signature.ToString().c_str());
Orion Hodsonb34bb192016-10-18 17:02:58 +0100976 }
Orion Hodsonc069a302017-01-18 09:23:12 +0000977 if (secondary_index < pDexFile->GetHeader().proto_ids_size_) {
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800978 const dex::ProtoId& protoId = pDexFile->GetProtoId(dex::ProtoIndex(secondary_index));
Orion Hodsonc069a302017-01-18 09:23:12 +0000979 const Signature signature = pDexFile->GetProtoSignature(protoId);
980 proto = signature.ToString();
981 }
982 outSize = snprintf(buf.get(), bufSize, "%s, %s // method@%0*x, proto@%0*x",
983 method.c_str(), proto.c_str(), width, index, width, secondary_index);
984 break;
985 }
986 case Instruction::kIndexCallSiteRef:
987 // Call site information is too large to detail in disassembly so just output the index.
988 outSize = snprintf(buf.get(), bufSize, "call_site@%0*x", width, index);
Orion Hodsonb34bb192016-10-18 17:02:58 +0100989 break;
Orion Hodson2e599942017-09-22 16:17:41 +0100990 case Instruction::kIndexMethodHandleRef:
991 // Method handle information is too large to detail in disassembly so just output the index.
992 outSize = snprintf(buf.get(), bufSize, "method_handle@%0*x", width, index);
993 break;
994 case Instruction::kIndexProtoRef:
995 if (index < pDexFile->GetHeader().proto_ids_size_) {
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800996 const dex::ProtoId& protoId = pDexFile->GetProtoId(dex::ProtoIndex(index));
Orion Hodson2e599942017-09-22 16:17:41 +0100997 const Signature signature = pDexFile->GetProtoSignature(protoId);
998 const std::string& proto = signature.ToString();
999 outSize = snprintf(buf.get(), bufSize, "%s // proto@%0*x", proto.c_str(), width, index);
1000 } else {
1001 outSize = snprintf(buf.get(), bufSize, "<?> // proto@%0*x", width, index);
1002 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001003 break;
1004 } // switch
1005
Orion Hodson2e599942017-09-22 16:17:41 +01001006 if (outSize == 0) {
1007 // The index type has not been handled in the switch above.
1008 outSize = snprintf(buf.get(), bufSize, "<?>");
1009 }
1010
Aart Bik69ae54a2015-07-01 14:52:26 -07001011 // Determine success of string construction.
1012 if (outSize >= bufSize) {
Aart Bika0e33fd2016-07-08 18:32:45 -07001013 // The buffer wasn't big enough; retry with computed size. Note: snprintf()
1014 // doesn't count/ the '\0' as part of its returned size, so we add explicit
1015 // space for it here.
1016 return indexString(pDexFile, pDecInsn, outSize + 1);
Aart Bik69ae54a2015-07-01 14:52:26 -07001017 }
1018 return buf;
1019}
1020
1021/*
1022 * Dumps a single instruction.
1023 */
1024static void dumpInstruction(const DexFile* pDexFile,
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001025 const dex::CodeItem* pCode,
Aart Bik69ae54a2015-07-01 14:52:26 -07001026 u4 codeOffset, u4 insnIdx, u4 insnWidth,
1027 const Instruction* pDecInsn) {
1028 // Address of instruction (expressed as byte offset).
1029 fprintf(gOutFile, "%06x:", codeOffset + 0x10 + insnIdx * 2);
1030
1031 // Dump (part of) raw bytes.
Mathieu Chartier698ebbc2018-01-05 11:00:42 -08001032 CodeItemInstructionAccessor accessor(*pDexFile, pCode);
Aart Bik69ae54a2015-07-01 14:52:26 -07001033 for (u4 i = 0; i < 8; i++) {
1034 if (i < insnWidth) {
1035 if (i == 7) {
1036 fprintf(gOutFile, " ... ");
1037 } else {
1038 // Print 16-bit value in little-endian order.
Mathieu Chartier641a3af2017-12-15 11:42:58 -08001039 const u1* bytePtr = (const u1*) &accessor.Insns()[insnIdx + i];
Aart Bik69ae54a2015-07-01 14:52:26 -07001040 fprintf(gOutFile, " %02x%02x", bytePtr[0], bytePtr[1]);
1041 }
1042 } else {
1043 fputs(" ", gOutFile);
1044 }
1045 } // for
1046
1047 // Dump pseudo-instruction or opcode.
1048 if (pDecInsn->Opcode() == Instruction::NOP) {
Mathieu Chartier641a3af2017-12-15 11:42:58 -08001049 const u2 instr = get2LE((const u1*) &accessor.Insns()[insnIdx]);
Aart Bik69ae54a2015-07-01 14:52:26 -07001050 if (instr == Instruction::kPackedSwitchSignature) {
1051 fprintf(gOutFile, "|%04x: packed-switch-data (%d units)", insnIdx, insnWidth);
1052 } else if (instr == Instruction::kSparseSwitchSignature) {
1053 fprintf(gOutFile, "|%04x: sparse-switch-data (%d units)", insnIdx, insnWidth);
1054 } else if (instr == Instruction::kArrayDataSignature) {
1055 fprintf(gOutFile, "|%04x: array-data (%d units)", insnIdx, insnWidth);
1056 } else {
1057 fprintf(gOutFile, "|%04x: nop // spacer", insnIdx);
1058 }
1059 } else {
1060 fprintf(gOutFile, "|%04x: %s", insnIdx, pDecInsn->Name());
1061 }
1062
1063 // Set up additional argument.
Aart Bika0e33fd2016-07-08 18:32:45 -07001064 std::unique_ptr<char[]> indexBuf;
Aart Bik69ae54a2015-07-01 14:52:26 -07001065 if (Instruction::IndexTypeOf(pDecInsn->Opcode()) != Instruction::kIndexNone) {
Aart Bika0e33fd2016-07-08 18:32:45 -07001066 indexBuf = indexString(pDexFile, pDecInsn, 200);
Aart Bik69ae54a2015-07-01 14:52:26 -07001067 }
1068
1069 // Dump the instruction.
1070 //
1071 // NOTE: pDecInsn->DumpString(pDexFile) differs too much from original.
1072 //
1073 switch (Instruction::FormatOf(pDecInsn->Opcode())) {
1074 case Instruction::k10x: // op
1075 break;
1076 case Instruction::k12x: // op vA, vB
1077 fprintf(gOutFile, " v%d, v%d", pDecInsn->VRegA(), pDecInsn->VRegB());
1078 break;
1079 case Instruction::k11n: // op vA, #+B
1080 fprintf(gOutFile, " v%d, #int %d // #%x",
1081 pDecInsn->VRegA(), (s4) pDecInsn->VRegB(), (u1)pDecInsn->VRegB());
1082 break;
1083 case Instruction::k11x: // op vAA
1084 fprintf(gOutFile, " v%d", pDecInsn->VRegA());
1085 break;
1086 case Instruction::k10t: // op +AA
Aart Bikdce50862016-06-10 16:04:03 -07001087 case Instruction::k20t: { // op +AAAA
1088 const s4 targ = (s4) pDecInsn->VRegA();
1089 fprintf(gOutFile, " %04x // %c%04x",
1090 insnIdx + targ,
1091 (targ < 0) ? '-' : '+',
1092 (targ < 0) ? -targ : targ);
Aart Bik69ae54a2015-07-01 14:52:26 -07001093 break;
Aart Bikdce50862016-06-10 16:04:03 -07001094 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001095 case Instruction::k22x: // op vAA, vBBBB
1096 fprintf(gOutFile, " v%d, v%d", pDecInsn->VRegA(), pDecInsn->VRegB());
1097 break;
Aart Bikdce50862016-06-10 16:04:03 -07001098 case Instruction::k21t: { // op vAA, +BBBB
1099 const s4 targ = (s4) pDecInsn->VRegB();
1100 fprintf(gOutFile, " v%d, %04x // %c%04x", pDecInsn->VRegA(),
1101 insnIdx + targ,
1102 (targ < 0) ? '-' : '+',
1103 (targ < 0) ? -targ : targ);
Aart Bik69ae54a2015-07-01 14:52:26 -07001104 break;
Aart Bikdce50862016-06-10 16:04:03 -07001105 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001106 case Instruction::k21s: // op vAA, #+BBBB
1107 fprintf(gOutFile, " v%d, #int %d // #%x",
1108 pDecInsn->VRegA(), (s4) pDecInsn->VRegB(), (u2)pDecInsn->VRegB());
1109 break;
1110 case Instruction::k21h: // op vAA, #+BBBB0000[00000000]
1111 // The printed format varies a bit based on the actual opcode.
1112 if (pDecInsn->Opcode() == Instruction::CONST_HIGH16) {
1113 const s4 value = pDecInsn->VRegB() << 16;
1114 fprintf(gOutFile, " v%d, #int %d // #%x",
1115 pDecInsn->VRegA(), value, (u2) pDecInsn->VRegB());
1116 } else {
1117 const s8 value = ((s8) pDecInsn->VRegB()) << 48;
1118 fprintf(gOutFile, " v%d, #long %" PRId64 " // #%x",
1119 pDecInsn->VRegA(), value, (u2) pDecInsn->VRegB());
1120 }
1121 break;
1122 case Instruction::k21c: // op vAA, thing@BBBB
1123 case Instruction::k31c: // op vAA, thing@BBBBBBBB
Aart Bika0e33fd2016-07-08 18:32:45 -07001124 fprintf(gOutFile, " v%d, %s", pDecInsn->VRegA(), indexBuf.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001125 break;
1126 case Instruction::k23x: // op vAA, vBB, vCC
1127 fprintf(gOutFile, " v%d, v%d, v%d",
1128 pDecInsn->VRegA(), pDecInsn->VRegB(), pDecInsn->VRegC());
1129 break;
1130 case Instruction::k22b: // op vAA, vBB, #+CC
1131 fprintf(gOutFile, " v%d, v%d, #int %d // #%02x",
1132 pDecInsn->VRegA(), pDecInsn->VRegB(),
1133 (s4) pDecInsn->VRegC(), (u1) pDecInsn->VRegC());
1134 break;
Aart Bikdce50862016-06-10 16:04:03 -07001135 case Instruction::k22t: { // op vA, vB, +CCCC
1136 const s4 targ = (s4) pDecInsn->VRegC();
1137 fprintf(gOutFile, " v%d, v%d, %04x // %c%04x",
1138 pDecInsn->VRegA(), pDecInsn->VRegB(),
1139 insnIdx + targ,
1140 (targ < 0) ? '-' : '+',
1141 (targ < 0) ? -targ : targ);
Aart Bik69ae54a2015-07-01 14:52:26 -07001142 break;
Aart Bikdce50862016-06-10 16:04:03 -07001143 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001144 case Instruction::k22s: // op vA, vB, #+CCCC
1145 fprintf(gOutFile, " v%d, v%d, #int %d // #%04x",
1146 pDecInsn->VRegA(), pDecInsn->VRegB(),
1147 (s4) pDecInsn->VRegC(), (u2) pDecInsn->VRegC());
1148 break;
1149 case Instruction::k22c: // op vA, vB, thing@CCCC
1150 // NOT SUPPORTED:
1151 // case Instruction::k22cs: // [opt] op vA, vB, field offset CCCC
1152 fprintf(gOutFile, " v%d, v%d, %s",
Aart Bika0e33fd2016-07-08 18:32:45 -07001153 pDecInsn->VRegA(), pDecInsn->VRegB(), indexBuf.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001154 break;
1155 case Instruction::k30t:
1156 fprintf(gOutFile, " #%08x", pDecInsn->VRegA());
1157 break;
Aart Bikdce50862016-06-10 16:04:03 -07001158 case Instruction::k31i: { // op vAA, #+BBBBBBBB
1159 // This is often, but not always, a float.
1160 union {
1161 float f;
1162 u4 i;
1163 } conv;
1164 conv.i = pDecInsn->VRegB();
1165 fprintf(gOutFile, " v%d, #float %g // #%08x",
1166 pDecInsn->VRegA(), conv.f, pDecInsn->VRegB());
Aart Bik69ae54a2015-07-01 14:52:26 -07001167 break;
Aart Bikdce50862016-06-10 16:04:03 -07001168 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001169 case Instruction::k31t: // op vAA, offset +BBBBBBBB
1170 fprintf(gOutFile, " v%d, %08x // +%08x",
1171 pDecInsn->VRegA(), insnIdx + pDecInsn->VRegB(), pDecInsn->VRegB());
1172 break;
1173 case Instruction::k32x: // op vAAAA, vBBBB
1174 fprintf(gOutFile, " v%d, v%d", pDecInsn->VRegA(), pDecInsn->VRegB());
1175 break;
Orion Hodsonb34bb192016-10-18 17:02:58 +01001176 case Instruction::k35c: // op {vC, vD, vE, vF, vG}, thing@BBBB
1177 case Instruction::k45cc: { // op {vC, vD, vE, vF, vG}, method@BBBB, proto@HHHH
Aart Bik69ae54a2015-07-01 14:52:26 -07001178 // NOT SUPPORTED:
1179 // case Instruction::k35ms: // [opt] invoke-virtual+super
1180 // case Instruction::k35mi: // [opt] inline invoke
Aart Bikdce50862016-06-10 16:04:03 -07001181 u4 arg[Instruction::kMaxVarArgRegs];
1182 pDecInsn->GetVarArgs(arg);
1183 fputs(" {", gOutFile);
1184 for (int i = 0, n = pDecInsn->VRegA(); i < n; i++) {
1185 if (i == 0) {
1186 fprintf(gOutFile, "v%d", arg[i]);
1187 } else {
1188 fprintf(gOutFile, ", v%d", arg[i]);
1189 }
1190 } // for
Aart Bika0e33fd2016-07-08 18:32:45 -07001191 fprintf(gOutFile, "}, %s", indexBuf.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001192 break;
Aart Bikdce50862016-06-10 16:04:03 -07001193 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001194 case Instruction::k3rc: // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB
Orion Hodsonb34bb192016-10-18 17:02:58 +01001195 case Instruction::k4rcc: { // op {vCCCC .. v(CCCC+AA-1)}, method@BBBB, proto@HHHH
Aart Bik69ae54a2015-07-01 14:52:26 -07001196 // NOT SUPPORTED:
1197 // case Instruction::k3rms: // [opt] invoke-virtual+super/range
1198 // case Instruction::k3rmi: // [opt] execute-inline/range
Aart Bik69ae54a2015-07-01 14:52:26 -07001199 // This doesn't match the "dx" output when some of the args are
1200 // 64-bit values -- dx only shows the first register.
1201 fputs(" {", gOutFile);
1202 for (int i = 0, n = pDecInsn->VRegA(); i < n; i++) {
1203 if (i == 0) {
1204 fprintf(gOutFile, "v%d", pDecInsn->VRegC() + i);
1205 } else {
1206 fprintf(gOutFile, ", v%d", pDecInsn->VRegC() + i);
1207 }
1208 } // for
Aart Bika0e33fd2016-07-08 18:32:45 -07001209 fprintf(gOutFile, "}, %s", indexBuf.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001210 }
1211 break;
Aart Bikdce50862016-06-10 16:04:03 -07001212 case Instruction::k51l: { // op vAA, #+BBBBBBBBBBBBBBBB
1213 // This is often, but not always, a double.
1214 union {
1215 double d;
1216 u8 j;
1217 } conv;
1218 conv.j = pDecInsn->WideVRegB();
1219 fprintf(gOutFile, " v%d, #double %g // #%016" PRIx64,
1220 pDecInsn->VRegA(), conv.d, pDecInsn->WideVRegB());
Aart Bik69ae54a2015-07-01 14:52:26 -07001221 break;
Aart Bikdce50862016-06-10 16:04:03 -07001222 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001223 // NOT SUPPORTED:
1224 // case Instruction::k00x: // unknown op or breakpoint
1225 // break;
1226 default:
1227 fprintf(gOutFile, " ???");
1228 break;
1229 } // switch
1230
1231 fputc('\n', gOutFile);
Aart Bik69ae54a2015-07-01 14:52:26 -07001232}
1233
1234/*
1235 * Dumps a bytecode disassembly.
1236 */
1237static void dumpBytecodes(const DexFile* pDexFile, u4 idx,
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001238 const dex::CodeItem* pCode, u4 codeOffset) {
1239 const dex::MethodId& pMethodId = pDexFile->GetMethodId(idx);
Aart Bik69ae54a2015-07-01 14:52:26 -07001240 const char* name = pDexFile->StringDataByIdx(pMethodId.name_idx_);
1241 const Signature signature = pDexFile->GetMethodSignature(pMethodId);
1242 const char* backDescriptor = pDexFile->StringByTypeIdx(pMethodId.class_idx_);
1243
1244 // Generate header.
Aart Bikc05e2f22016-07-12 15:53:13 -07001245 std::unique_ptr<char[]> dot(descriptorToDot(backDescriptor));
1246 fprintf(gOutFile, "%06x: |[%06x] %s.%s:%s\n",
1247 codeOffset, codeOffset, dot.get(), name, signature.ToString().c_str());
Aart Bik69ae54a2015-07-01 14:52:26 -07001248
1249 // Iterate over all instructions.
Mathieu Chartier698ebbc2018-01-05 11:00:42 -08001250 CodeItemDataAccessor accessor(*pDexFile, pCode);
Aart Bik7a9aaf12018-02-05 17:00:40 -08001251 const u4 maxPc = accessor.InsnsSizeInCodeUnits();
Mathieu Chartier641a3af2017-12-15 11:42:58 -08001252 for (const DexInstructionPcPair& pair : accessor) {
Aart Bik7a9aaf12018-02-05 17:00:40 -08001253 const u4 dexPc = pair.DexPc();
1254 if (dexPc >= maxPc) {
1255 LOG(WARNING) << "GLITCH: run-away instruction at idx=0x" << std::hex << dexPc;
1256 break;
1257 }
Mathieu Chartier641a3af2017-12-15 11:42:58 -08001258 const Instruction* instruction = &pair.Inst();
Aart Bik69ae54a2015-07-01 14:52:26 -07001259 const u4 insnWidth = instruction->SizeInCodeUnits();
1260 if (insnWidth == 0) {
Aart Bik7a9aaf12018-02-05 17:00:40 -08001261 LOG(WARNING) << "GLITCH: zero-width instruction at idx=0x" << std::hex << dexPc;
Aart Bik69ae54a2015-07-01 14:52:26 -07001262 break;
1263 }
Aart Bik7a9aaf12018-02-05 17:00:40 -08001264 dumpInstruction(pDexFile, pCode, codeOffset, dexPc, insnWidth, instruction);
Aart Bik69ae54a2015-07-01 14:52:26 -07001265 } // for
1266}
1267
Ian Zerny7453a712022-02-02 10:47:08 +01001268static u4 findLastInstructionAddress(const CodeItemDebugInfoAccessor& accessor) {
1269 const u4 maxAddress = accessor.InsnsSizeInCodeUnits();
1270 u4 lastInstructionSize = 0;
1271 for (const DexInstructionPcPair& pair : accessor) {
1272 const u4 address = pair.DexPc();
1273 if (address >= maxAddress) {
1274 return 1;
1275 }
1276 lastInstructionSize = pair.Inst().SizeInCodeUnits();
1277 }
1278 return maxAddress - lastInstructionSize;
1279}
1280
Aart Bik69ae54a2015-07-01 14:52:26 -07001281/*
1282 * Dumps code of a method.
1283 */
1284static void dumpCode(const DexFile* pDexFile, u4 idx, u4 flags,
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001285 const dex::CodeItem* pCode, u4 codeOffset) {
Mathieu Chartier8892c6b2018-01-09 15:10:17 -08001286 CodeItemDebugInfoAccessor accessor(*pDexFile, pCode, idx);
Mathieu Chartier641a3af2017-12-15 11:42:58 -08001287
1288 fprintf(gOutFile, " registers : %d\n", accessor.RegistersSize());
1289 fprintf(gOutFile, " ins : %d\n", accessor.InsSize());
1290 fprintf(gOutFile, " outs : %d\n", accessor.OutsSize());
Aart Bik69ae54a2015-07-01 14:52:26 -07001291 fprintf(gOutFile, " insns size : %d 16-bit code units\n",
Mathieu Chartier641a3af2017-12-15 11:42:58 -08001292 accessor.InsnsSizeInCodeUnits());
Aart Bik69ae54a2015-07-01 14:52:26 -07001293
1294 // Bytecode disassembly, if requested.
1295 if (gOptions.disassemble) {
1296 dumpBytecodes(pDexFile, idx, pCode, codeOffset);
1297 }
1298
1299 // Try-catch blocks.
1300 dumpCatches(pDexFile, pCode);
1301
Ian Zerny19df0e92022-02-02 16:51:02 +01001302 if (gOptions.showDebugInfo) {
1303 const u4 lastInstructionAddress = findLastInstructionAddress(accessor);
1304 // Positions and locals table in the debug info.
1305 bool is_static = (flags & kAccStatic) != 0;
Orion Hodson3c83d0d2022-02-25 11:07:31 +00001306 fprintf(gOutFile, " positions :\n");
Ian Zerny19df0e92022-02-02 16:51:02 +01001307 accessor.DecodeDebugPositionInfo([&](const DexFile::PositionInfo& entry) {
1308 if (entry.address_ > lastInstructionAddress) {
1309 return true;
1310 } else {
1311 fprintf(gOutFile, " 0x%04x line=%d\n", entry.address_, entry.line_);
1312 return false;
1313 }
1314 });
Orion Hodson3c83d0d2022-02-25 11:07:31 +00001315 fprintf(gOutFile, " locals :\n");
Ian Zerny19df0e92022-02-02 16:51:02 +01001316 accessor.DecodeDebugLocalInfo(is_static,
1317 idx,
1318 [&](const DexFile::LocalInfo& entry) {
Ian Zerny19df0e92022-02-02 16:51:02 +01001319 fprintf(gOutFile,
Orion Hodson3c83d0d2022-02-25 11:07:31 +00001320 " 0x%04x - 0x%04x reg=%d %s %s",
Ian Zerny19df0e92022-02-02 16:51:02 +01001321 entry.start_address_,
1322 entry.end_address_,
1323 entry.reg_,
1324 entry.name_,
Orion Hodson3c83d0d2022-02-25 11:07:31 +00001325 entry.descriptor_);
1326 if (entry.signature_) {
1327 fputc(' ', gOutFile);
1328 fputs(entry.signature_, gOutFile);
1329 }
1330 fputc('\n', gOutFile);
Ian Zerny19df0e92022-02-02 16:51:02 +01001331 });
1332 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001333}
1334
David Brazdil8c4d7172019-01-21 19:45:28 +00001335static std::string GetHiddenapiFlagStr(uint32_t hiddenapi_flags) {
1336 std::stringstream ss;
1337 hiddenapi::ApiList api_list(hiddenapi_flags);
1338 api_list.Dump(ss);
1339 std::string str_api_list = ss.str();
1340 std::transform(str_api_list.begin(), str_api_list.end(), str_api_list.begin(), ::toupper);
1341 return str_api_list;
1342}
1343
Aart Bik69ae54a2015-07-01 14:52:26 -07001344/*
1345 * Dumps a method.
1346 */
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001347static void dumpMethod(const ClassAccessor::Method& method, int i) {
Aart Bik69ae54a2015-07-01 14:52:26 -07001348 // Bail for anything private if export only requested.
David Brazdil20c765f2018-10-27 21:45:15 +00001349 const uint32_t flags = method.GetAccessFlags();
Aart Bik69ae54a2015-07-01 14:52:26 -07001350 if (gOptions.exportsOnly && (flags & (kAccPublic | kAccProtected)) == 0) {
1351 return;
1352 }
1353
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001354 const DexFile& dex_file = method.GetDexFile();
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001355 const dex::MethodId& pMethodId = dex_file.GetMethodId(method.GetIndex());
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001356 const char* name = dex_file.StringDataByIdx(pMethodId.name_idx_);
1357 const Signature signature = dex_file.GetMethodSignature(pMethodId);
Aart Bik69ae54a2015-07-01 14:52:26 -07001358 char* typeDescriptor = strdup(signature.ToString().c_str());
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001359 const char* backDescriptor = dex_file.StringByTypeIdx(pMethodId.class_idx_);
Aart Bik69ae54a2015-07-01 14:52:26 -07001360 char* accessStr = createAccessFlagStr(flags, kAccessForMethod);
David Brazdil8c4d7172019-01-21 19:45:28 +00001361 const uint32_t hiddenapiFlags = method.GetHiddenapiFlags();
Aart Bik69ae54a2015-07-01 14:52:26 -07001362
1363 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1364 fprintf(gOutFile, " #%d : (in %s)\n", i, backDescriptor);
1365 fprintf(gOutFile, " name : '%s'\n", name);
1366 fprintf(gOutFile, " type : '%s'\n", typeDescriptor);
1367 fprintf(gOutFile, " access : 0x%04x (%s)\n", flags, accessStr);
Eric Holk4ac8d962020-03-30 10:44:30 -07001368 if (gOptions.showSectionHeaders) {
1369 fprintf(gOutFile, " method_idx : %d\n", method.GetIndex());
1370 }
David Brazdil8c4d7172019-01-21 19:45:28 +00001371 if (hiddenapiFlags != 0u) {
1372 fprintf(gOutFile,
1373 " hiddenapi : 0x%04x (%s)\n",
1374 hiddenapiFlags,
1375 GetHiddenapiFlagStr(hiddenapiFlags).c_str());
1376 }
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001377 if (method.GetCodeItem() == nullptr) {
Aart Bik69ae54a2015-07-01 14:52:26 -07001378 fprintf(gOutFile, " code : (none)\n");
1379 } else {
1380 fprintf(gOutFile, " code -\n");
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001381 dumpCode(&dex_file,
1382 method.GetIndex(),
1383 flags,
1384 method.GetCodeItem(),
1385 method.GetCodeItemOffset());
Aart Bik69ae54a2015-07-01 14:52:26 -07001386 }
1387 if (gOptions.disassemble) {
1388 fputc('\n', gOutFile);
1389 }
1390 } else if (gOptions.outputFormat == OUTPUT_XML) {
1391 const bool constructor = (name[0] == '<');
1392
1393 // Method name and prototype.
1394 if (constructor) {
Orion Hodsonfe42d212018-08-24 14:01:14 +01001395 std::unique_ptr<char[]> dot(descriptorClassToName(backDescriptor));
Aart Bikc05e2f22016-07-12 15:53:13 -07001396 fprintf(gOutFile, "<constructor name=\"%s\"\n", dot.get());
1397 dot = descriptorToDot(backDescriptor);
1398 fprintf(gOutFile, " type=\"%s\"\n", dot.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001399 } else {
1400 fprintf(gOutFile, "<method name=\"%s\"\n", name);
1401 const char* returnType = strrchr(typeDescriptor, ')');
1402 if (returnType == nullptr) {
Andreas Gampe221d9812018-01-22 17:48:56 -08001403 LOG(ERROR) << "bad method type descriptor '" << typeDescriptor << "'";
Aart Bik69ae54a2015-07-01 14:52:26 -07001404 goto bail;
1405 }
Aart Bikc05e2f22016-07-12 15:53:13 -07001406 std::unique_ptr<char[]> dot(descriptorToDot(returnType + 1));
1407 fprintf(gOutFile, " return=\"%s\"\n", dot.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001408 fprintf(gOutFile, " abstract=%s\n", quotedBool((flags & kAccAbstract) != 0));
1409 fprintf(gOutFile, " native=%s\n", quotedBool((flags & kAccNative) != 0));
1410 fprintf(gOutFile, " synchronized=%s\n", quotedBool(
1411 (flags & (kAccSynchronized | kAccDeclaredSynchronized)) != 0));
1412 }
1413
1414 // Additional method flags.
1415 fprintf(gOutFile, " static=%s\n", quotedBool((flags & kAccStatic) != 0));
1416 fprintf(gOutFile, " final=%s\n", quotedBool((flags & kAccFinal) != 0));
1417 // The "deprecated=" not knowable w/o parsing annotations.
1418 fprintf(gOutFile, " visibility=%s\n>\n", quotedVisibility(flags));
1419
1420 // Parameters.
1421 if (typeDescriptor[0] != '(') {
Andreas Gampe221d9812018-01-22 17:48:56 -08001422 LOG(ERROR) << "ERROR: bad descriptor '" << typeDescriptor << "'";
Aart Bik69ae54a2015-07-01 14:52:26 -07001423 goto bail;
1424 }
1425 char* tmpBuf = reinterpret_cast<char*>(malloc(strlen(typeDescriptor) + 1));
1426 const char* base = typeDescriptor + 1;
1427 int argNum = 0;
1428 while (*base != ')') {
1429 char* cp = tmpBuf;
1430 while (*base == '[') {
1431 *cp++ = *base++;
1432 }
1433 if (*base == 'L') {
1434 // Copy through ';'.
1435 do {
1436 *cp = *base++;
1437 } while (*cp++ != ';');
1438 } else {
1439 // Primitive char, copy it.
Aart Bikc05e2f22016-07-12 15:53:13 -07001440 if (strchr("ZBCSIFJD", *base) == nullptr) {
Andreas Gampe221d9812018-01-22 17:48:56 -08001441 LOG(ERROR) << "ERROR: bad method signature '" << base << "'";
Aart Bika0e33fd2016-07-08 18:32:45 -07001442 break; // while
Aart Bik69ae54a2015-07-01 14:52:26 -07001443 }
1444 *cp++ = *base++;
1445 }
1446 // Null terminate and display.
1447 *cp++ = '\0';
Aart Bikc05e2f22016-07-12 15:53:13 -07001448 std::unique_ptr<char[]> dot(descriptorToDot(tmpBuf));
Aart Bik69ae54a2015-07-01 14:52:26 -07001449 fprintf(gOutFile, "<parameter name=\"arg%d\" type=\"%s\">\n"
Aart Bikc05e2f22016-07-12 15:53:13 -07001450 "</parameter>\n", argNum++, dot.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001451 } // while
1452 free(tmpBuf);
1453 if (constructor) {
1454 fprintf(gOutFile, "</constructor>\n");
1455 } else {
1456 fprintf(gOutFile, "</method>\n");
1457 }
1458 }
1459
Orion Hodson219f81f2021-11-10 19:48:08 +00001460bail:
Aart Bik69ae54a2015-07-01 14:52:26 -07001461 free(typeDescriptor);
1462 free(accessStr);
1463}
1464
1465/*
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001466 * Dumps a static or instance (class) field.
Aart Bik69ae54a2015-07-01 14:52:26 -07001467 */
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001468static void dumpField(const ClassAccessor::Field& field, int i, const u1** data = nullptr) {
Aart Bik69ae54a2015-07-01 14:52:26 -07001469 // Bail for anything private if export only requested.
David Brazdil20c765f2018-10-27 21:45:15 +00001470 const uint32_t flags = field.GetAccessFlags();
Aart Bik69ae54a2015-07-01 14:52:26 -07001471 if (gOptions.exportsOnly && (flags & (kAccPublic | kAccProtected)) == 0) {
1472 return;
1473 }
1474
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001475 const DexFile& dex_file = field.GetDexFile();
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001476 const dex::FieldId& field_id = dex_file.GetFieldId(field.GetIndex());
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001477 const char* name = dex_file.StringDataByIdx(field_id.name_idx_);
1478 const char* typeDescriptor = dex_file.StringByTypeIdx(field_id.type_idx_);
1479 const char* backDescriptor = dex_file.StringByTypeIdx(field_id.class_idx_);
Aart Bik69ae54a2015-07-01 14:52:26 -07001480 char* accessStr = createAccessFlagStr(flags, kAccessForField);
David Brazdil8c4d7172019-01-21 19:45:28 +00001481 const uint32_t hiddenapiFlags = field.GetHiddenapiFlags();
Aart Bik69ae54a2015-07-01 14:52:26 -07001482
1483 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1484 fprintf(gOutFile, " #%d : (in %s)\n", i, backDescriptor);
1485 fprintf(gOutFile, " name : '%s'\n", name);
1486 fprintf(gOutFile, " type : '%s'\n", typeDescriptor);
1487 fprintf(gOutFile, " access : 0x%04x (%s)\n", flags, accessStr);
David Brazdil8c4d7172019-01-21 19:45:28 +00001488 if (hiddenapiFlags != 0u) {
1489 fprintf(gOutFile,
1490 " hiddenapi : 0x%04x (%s)\n",
1491 hiddenapiFlags,
1492 GetHiddenapiFlagStr(hiddenapiFlags).c_str());
1493 }
Aart Bikdce50862016-06-10 16:04:03 -07001494 if (data != nullptr) {
Shinichiro Hamaji82863f02015-11-05 16:51:33 +09001495 fputs(" value : ", gOutFile);
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001496 dumpEncodedValue(&dex_file, data);
Shinichiro Hamaji82863f02015-11-05 16:51:33 +09001497 fputs("\n", gOutFile);
1498 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001499 } else if (gOptions.outputFormat == OUTPUT_XML) {
1500 fprintf(gOutFile, "<field name=\"%s\"\n", name);
Aart Bikc05e2f22016-07-12 15:53:13 -07001501 std::unique_ptr<char[]> dot(descriptorToDot(typeDescriptor));
1502 fprintf(gOutFile, " type=\"%s\"\n", dot.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001503 fprintf(gOutFile, " transient=%s\n", quotedBool((flags & kAccTransient) != 0));
1504 fprintf(gOutFile, " volatile=%s\n", quotedBool((flags & kAccVolatile) != 0));
1505 // The "value=" is not knowable w/o parsing annotations.
1506 fprintf(gOutFile, " static=%s\n", quotedBool((flags & kAccStatic) != 0));
1507 fprintf(gOutFile, " final=%s\n", quotedBool((flags & kAccFinal) != 0));
1508 // The "deprecated=" is not knowable w/o parsing annotations.
1509 fprintf(gOutFile, " visibility=%s\n", quotedVisibility(flags));
Aart Bikdce50862016-06-10 16:04:03 -07001510 if (data != nullptr) {
Shinichiro Hamaji82863f02015-11-05 16:51:33 +09001511 fputs(" value=\"", gOutFile);
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001512 dumpEncodedValue(&dex_file, data);
Shinichiro Hamaji82863f02015-11-05 16:51:33 +09001513 fputs("\"\n", gOutFile);
1514 }
1515 fputs(">\n</field>\n", gOutFile);
Aart Bik69ae54a2015-07-01 14:52:26 -07001516 }
1517
1518 free(accessStr);
1519}
1520
1521/*
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001522 * Dumping a CFG.
Aart Bik69ae54a2015-07-01 14:52:26 -07001523 */
Andreas Gampe5073fed2015-08-10 11:40:25 -07001524static void dumpCfg(const DexFile* dex_file, int idx) {
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001525 ClassAccessor accessor(*dex_file, dex_file->GetClassDef(idx));
1526 for (const ClassAccessor::Method& method : accessor.GetMethods()) {
1527 if (method.GetCodeItem() != nullptr) {
1528 std::ostringstream oss;
1529 DumpMethodCFG(method, oss);
1530 fputs(oss.str().c_str(), gOutFile);
1531 }
Andreas Gampe5073fed2015-08-10 11:40:25 -07001532 }
Andreas Gampe5073fed2015-08-10 11:40:25 -07001533}
1534
1535/*
Aart Bik69ae54a2015-07-01 14:52:26 -07001536 * Dumps the class.
1537 *
1538 * Note "idx" is a DexClassDef index, not a DexTypeId index.
1539 *
1540 * If "*pLastPackage" is nullptr or does not match the current class' package,
1541 * the value will be replaced with a newly-allocated string.
1542 */
1543static void dumpClass(const DexFile* pDexFile, int idx, char** pLastPackage) {
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001544 const dex::ClassDef& pClassDef = pDexFile->GetClassDef(idx);
Aart Bik69ae54a2015-07-01 14:52:26 -07001545
1546 // Omitting non-public class.
1547 if (gOptions.exportsOnly && (pClassDef.access_flags_ & kAccPublic) == 0) {
1548 return;
1549 }
1550
Aart Bikdce50862016-06-10 16:04:03 -07001551 if (gOptions.showSectionHeaders) {
1552 dumpClassDef(pDexFile, idx);
1553 }
1554
1555 if (gOptions.showAnnotations) {
1556 dumpClassAnnotations(pDexFile, idx);
1557 }
1558
1559 if (gOptions.showCfg) {
Andreas Gampe5073fed2015-08-10 11:40:25 -07001560 dumpCfg(pDexFile, idx);
1561 return;
1562 }
1563
Aart Bik69ae54a2015-07-01 14:52:26 -07001564 // For the XML output, show the package name. Ideally we'd gather
1565 // up the classes, sort them, and dump them alphabetically so the
1566 // package name wouldn't jump around, but that's not a great plan
1567 // for something that needs to run on the device.
1568 const char* classDescriptor = pDexFile->StringByTypeIdx(pClassDef.class_idx_);
1569 if (!(classDescriptor[0] == 'L' &&
1570 classDescriptor[strlen(classDescriptor)-1] == ';')) {
1571 // Arrays and primitives should not be defined explicitly. Keep going?
Andreas Gampe221d9812018-01-22 17:48:56 -08001572 LOG(WARNING) << "Malformed class name '" << classDescriptor << "'";
Aart Bik69ae54a2015-07-01 14:52:26 -07001573 } else if (gOptions.outputFormat == OUTPUT_XML) {
1574 char* mangle = strdup(classDescriptor + 1);
1575 mangle[strlen(mangle)-1] = '\0';
1576
1577 // Reduce to just the package name.
1578 char* lastSlash = strrchr(mangle, '/');
1579 if (lastSlash != nullptr) {
1580 *lastSlash = '\0';
1581 } else {
1582 *mangle = '\0';
1583 }
1584
1585 for (char* cp = mangle; *cp != '\0'; cp++) {
1586 if (*cp == '/') {
1587 *cp = '.';
1588 }
1589 } // for
1590
1591 if (*pLastPackage == nullptr || strcmp(mangle, *pLastPackage) != 0) {
1592 // Start of a new package.
1593 if (*pLastPackage != nullptr) {
1594 fprintf(gOutFile, "</package>\n");
1595 }
1596 fprintf(gOutFile, "<package name=\"%s\"\n>\n", mangle);
1597 free(*pLastPackage);
1598 *pLastPackage = mangle;
1599 } else {
1600 free(mangle);
1601 }
1602 }
1603
1604 // General class information.
1605 char* accessStr = createAccessFlagStr(pClassDef.access_flags_, kAccessForClass);
1606 const char* superclassDescriptor;
Andreas Gampea5b09a62016-11-17 15:21:22 -08001607 if (!pClassDef.superclass_idx_.IsValid()) {
Aart Bik69ae54a2015-07-01 14:52:26 -07001608 superclassDescriptor = nullptr;
1609 } else {
1610 superclassDescriptor = pDexFile->StringByTypeIdx(pClassDef.superclass_idx_);
1611 }
1612 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1613 fprintf(gOutFile, "Class #%d -\n", idx);
1614 fprintf(gOutFile, " Class descriptor : '%s'\n", classDescriptor);
1615 fprintf(gOutFile, " Access flags : 0x%04x (%s)\n", pClassDef.access_flags_, accessStr);
1616 if (superclassDescriptor != nullptr) {
1617 fprintf(gOutFile, " Superclass : '%s'\n", superclassDescriptor);
1618 }
1619 fprintf(gOutFile, " Interfaces -\n");
1620 } else {
Orion Hodsonfe42d212018-08-24 14:01:14 +01001621 std::unique_ptr<char[]> dot(descriptorClassToName(classDescriptor));
Aart Bikc05e2f22016-07-12 15:53:13 -07001622 fprintf(gOutFile, "<class name=\"%s\"\n", dot.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001623 if (superclassDescriptor != nullptr) {
Aart Bikc05e2f22016-07-12 15:53:13 -07001624 dot = descriptorToDot(superclassDescriptor);
1625 fprintf(gOutFile, " extends=\"%s\"\n", dot.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001626 }
Alex Light1f12e282015-12-10 16:49:47 -08001627 fprintf(gOutFile, " interface=%s\n",
1628 quotedBool((pClassDef.access_flags_ & kAccInterface) != 0));
Aart Bik69ae54a2015-07-01 14:52:26 -07001629 fprintf(gOutFile, " abstract=%s\n", quotedBool((pClassDef.access_flags_ & kAccAbstract) != 0));
1630 fprintf(gOutFile, " static=%s\n", quotedBool((pClassDef.access_flags_ & kAccStatic) != 0));
1631 fprintf(gOutFile, " final=%s\n", quotedBool((pClassDef.access_flags_ & kAccFinal) != 0));
1632 // The "deprecated=" not knowable w/o parsing annotations.
1633 fprintf(gOutFile, " visibility=%s\n", quotedVisibility(pClassDef.access_flags_));
1634 fprintf(gOutFile, ">\n");
1635 }
1636
1637 // Interfaces.
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001638 const dex::TypeList* pInterfaces = pDexFile->GetInterfacesList(pClassDef);
Aart Bik69ae54a2015-07-01 14:52:26 -07001639 if (pInterfaces != nullptr) {
1640 for (u4 i = 0; i < pInterfaces->Size(); i++) {
1641 dumpInterface(pDexFile, pInterfaces->GetTypeItem(i), i);
1642 } // for
1643 }
1644
1645 // Fields and methods.
David Brazdil8c4d7172019-01-21 19:45:28 +00001646 ClassAccessor accessor(*pDexFile, pClassDef, /* parse_hiddenapi_class_data= */ true);
Aart Bikdce50862016-06-10 16:04:03 -07001647
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001648 // Prepare data for static fields.
1649 const u1* sData = pDexFile->GetEncodedStaticFieldValuesArray(pClassDef);
1650 const u4 sSize = sData != nullptr ? DecodeUnsignedLeb128(&sData) : 0;
Aart Bikdce50862016-06-10 16:04:03 -07001651
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001652 // Static fields.
1653 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1654 fprintf(gOutFile, " Static fields -\n");
1655 }
1656 uint32_t i = 0u;
1657 for (const ClassAccessor::Field& field : accessor.GetStaticFields()) {
1658 dumpField(field, i, i < sSize ? &sData : nullptr);
1659 ++i;
1660 }
Aart Bikdce50862016-06-10 16:04:03 -07001661
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001662 // Instance fields.
1663 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1664 fprintf(gOutFile, " Instance fields -\n");
1665 }
1666 i = 0u;
1667 for (const ClassAccessor::Field& field : accessor.GetInstanceFields()) {
1668 dumpField(field, i);
1669 ++i;
1670 }
Aart Bikdce50862016-06-10 16:04:03 -07001671
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001672 // Direct methods.
1673 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1674 fprintf(gOutFile, " Direct methods -\n");
1675 }
1676 i = 0u;
1677 for (const ClassAccessor::Method& method : accessor.GetDirectMethods()) {
1678 dumpMethod(method, i);
1679 ++i;
1680 }
Aart Bikdce50862016-06-10 16:04:03 -07001681
Mathieu Chartier4ac9ade2018-07-24 10:27:21 -07001682 // Virtual methods.
1683 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1684 fprintf(gOutFile, " Virtual methods -\n");
1685 }
1686 i = 0u;
1687 for (const ClassAccessor::Method& method : accessor.GetVirtualMethods()) {
1688 dumpMethod(method, i);
1689 ++i;
Aart Bik69ae54a2015-07-01 14:52:26 -07001690 }
1691
1692 // End of class.
1693 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1694 const char* fileName;
Andreas Gampe8a0128a2016-11-28 07:38:35 -08001695 if (pClassDef.source_file_idx_.IsValid()) {
Aart Bik69ae54a2015-07-01 14:52:26 -07001696 fileName = pDexFile->StringDataByIdx(pClassDef.source_file_idx_);
1697 } else {
1698 fileName = "unknown";
1699 }
1700 fprintf(gOutFile, " source_file_idx : %d (%s)\n\n",
Andreas Gampe8a0128a2016-11-28 07:38:35 -08001701 pClassDef.source_file_idx_.index_, fileName);
Aart Bik69ae54a2015-07-01 14:52:26 -07001702 } else if (gOptions.outputFormat == OUTPUT_XML) {
1703 fprintf(gOutFile, "</class>\n");
1704 }
1705
1706 free(accessStr);
1707}
1708
Orion Hodsonc069a302017-01-18 09:23:12 +00001709static void dumpMethodHandle(const DexFile* pDexFile, u4 idx) {
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001710 const dex::MethodHandleItem& mh = pDexFile->GetMethodHandle(idx);
Orion Hodson631827d2017-04-10 14:53:47 +01001711 const char* type = nullptr;
1712 bool is_instance = false;
Orion Hodsonc069a302017-01-18 09:23:12 +00001713 bool is_invoke = false;
Orion Hodsonc069a302017-01-18 09:23:12 +00001714 switch (static_cast<DexFile::MethodHandleType>(mh.method_handle_type_)) {
1715 case DexFile::MethodHandleType::kStaticPut:
1716 type = "put-static";
Orion Hodson631827d2017-04-10 14:53:47 +01001717 is_instance = false;
1718 is_invoke = false;
Orion Hodsonc069a302017-01-18 09:23:12 +00001719 break;
1720 case DexFile::MethodHandleType::kStaticGet:
1721 type = "get-static";
Orion Hodson631827d2017-04-10 14:53:47 +01001722 is_instance = false;
1723 is_invoke = false;
Orion Hodsonc069a302017-01-18 09:23:12 +00001724 break;
1725 case DexFile::MethodHandleType::kInstancePut:
1726 type = "put-instance";
Orion Hodson631827d2017-04-10 14:53:47 +01001727 is_instance = true;
1728 is_invoke = false;
Orion Hodsonc069a302017-01-18 09:23:12 +00001729 break;
1730 case DexFile::MethodHandleType::kInstanceGet:
1731 type = "get-instance";
Orion Hodson631827d2017-04-10 14:53:47 +01001732 is_instance = true;
1733 is_invoke = false;
Orion Hodsonc069a302017-01-18 09:23:12 +00001734 break;
1735 case DexFile::MethodHandleType::kInvokeStatic:
1736 type = "invoke-static";
Orion Hodson631827d2017-04-10 14:53:47 +01001737 is_instance = false;
Orion Hodsonc069a302017-01-18 09:23:12 +00001738 is_invoke = true;
1739 break;
1740 case DexFile::MethodHandleType::kInvokeInstance:
1741 type = "invoke-instance";
Orion Hodson631827d2017-04-10 14:53:47 +01001742 is_instance = true;
Orion Hodsonc069a302017-01-18 09:23:12 +00001743 is_invoke = true;
1744 break;
1745 case DexFile::MethodHandleType::kInvokeConstructor:
1746 type = "invoke-constructor";
Orion Hodson631827d2017-04-10 14:53:47 +01001747 is_instance = true;
1748 is_invoke = true;
1749 break;
1750 case DexFile::MethodHandleType::kInvokeDirect:
1751 type = "invoke-direct";
1752 is_instance = true;
1753 is_invoke = true;
1754 break;
1755 case DexFile::MethodHandleType::kInvokeInterface:
1756 type = "invoke-interface";
1757 is_instance = true;
Orion Hodsonc069a302017-01-18 09:23:12 +00001758 is_invoke = true;
1759 break;
1760 }
1761
1762 const char* declaring_class;
1763 const char* member;
1764 std::string member_type;
Orion Hodson631827d2017-04-10 14:53:47 +01001765 if (type != nullptr) {
1766 if (is_invoke) {
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001767 const dex::MethodId& method_id = pDexFile->GetMethodId(mh.field_or_method_idx_);
Orion Hodson631827d2017-04-10 14:53:47 +01001768 declaring_class = pDexFile->GetMethodDeclaringClassDescriptor(method_id);
1769 member = pDexFile->GetMethodName(method_id);
1770 member_type = pDexFile->GetMethodSignature(method_id).ToString();
1771 } else {
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001772 const dex::FieldId& field_id = pDexFile->GetFieldId(mh.field_or_method_idx_);
Orion Hodson631827d2017-04-10 14:53:47 +01001773 declaring_class = pDexFile->GetFieldDeclaringClassDescriptor(field_id);
1774 member = pDexFile->GetFieldName(field_id);
1775 member_type = pDexFile->GetFieldTypeDescriptor(field_id);
1776 }
1777 if (is_instance) {
1778 member_type = android::base::StringPrintf("(%s%s", declaring_class, member_type.c_str() + 1);
1779 }
Orion Hodsonc069a302017-01-18 09:23:12 +00001780 } else {
Orion Hodson631827d2017-04-10 14:53:47 +01001781 type = "?";
1782 declaring_class = "?";
1783 member = "?";
1784 member_type = "?";
Orion Hodsonc069a302017-01-18 09:23:12 +00001785 }
1786
1787 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1788 fprintf(gOutFile, "Method handle #%u:\n", idx);
1789 fprintf(gOutFile, " type : %s\n", type);
1790 fprintf(gOutFile, " target : %s %s\n", declaring_class, member);
1791 fprintf(gOutFile, " target_type : %s\n", member_type.c_str());
Orion Hodsonc069a302017-01-18 09:23:12 +00001792 }
1793}
1794
1795static void dumpCallSite(const DexFile* pDexFile, u4 idx) {
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001796 const dex::CallSiteIdItem& call_site_id = pDexFile->GetCallSiteId(idx);
Orion Hodsonc069a302017-01-18 09:23:12 +00001797 CallSiteArrayValueIterator it(*pDexFile, call_site_id);
1798 if (it.Size() < 3) {
Andreas Gampe221d9812018-01-22 17:48:56 -08001799 LOG(ERROR) << "ERROR: Call site " << idx << " has too few values.";
Orion Hodsonc069a302017-01-18 09:23:12 +00001800 return;
1801 }
1802
1803 uint32_t method_handle_idx = static_cast<uint32_t>(it.GetJavaValue().i);
1804 it.Next();
1805 dex::StringIndex method_name_idx = static_cast<dex::StringIndex>(it.GetJavaValue().i);
1806 const char* method_name = pDexFile->StringDataByIdx(method_name_idx);
1807 it.Next();
Orion Hodson06d10a72018-05-14 08:53:38 +01001808 dex::ProtoIndex method_type_idx = static_cast<dex::ProtoIndex>(it.GetJavaValue().i);
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001809 const dex::ProtoId& method_type_id = pDexFile->GetProtoId(method_type_idx);
Orion Hodsonc069a302017-01-18 09:23:12 +00001810 std::string method_type = pDexFile->GetProtoSignature(method_type_id).ToString();
1811 it.Next();
1812
1813 if (gOptions.outputFormat == OUTPUT_PLAIN) {
Orion Hodson775224d2017-07-05 11:04:01 +01001814 fprintf(gOutFile, "Call site #%u: // offset %u\n", idx, call_site_id.data_off_);
Orion Hodsonc069a302017-01-18 09:23:12 +00001815 fprintf(gOutFile, " link_argument[0] : %u (MethodHandle)\n", method_handle_idx);
1816 fprintf(gOutFile, " link_argument[1] : %s (String)\n", method_name);
1817 fprintf(gOutFile, " link_argument[2] : %s (MethodType)\n", method_type.c_str());
Orion Hodsonc069a302017-01-18 09:23:12 +00001818 }
1819
1820 size_t argument = 3;
1821 while (it.HasNext()) {
1822 const char* type;
1823 std::string value;
1824 switch (it.GetValueType()) {
1825 case EncodedArrayValueIterator::ValueType::kByte:
1826 type = "byte";
1827 value = android::base::StringPrintf("%u", it.GetJavaValue().b);
1828 break;
1829 case EncodedArrayValueIterator::ValueType::kShort:
1830 type = "short";
1831 value = android::base::StringPrintf("%d", it.GetJavaValue().s);
1832 break;
1833 case EncodedArrayValueIterator::ValueType::kChar:
1834 type = "char";
1835 value = android::base::StringPrintf("%u", it.GetJavaValue().c);
1836 break;
1837 case EncodedArrayValueIterator::ValueType::kInt:
1838 type = "int";
1839 value = android::base::StringPrintf("%d", it.GetJavaValue().i);
1840 break;
1841 case EncodedArrayValueIterator::ValueType::kLong:
1842 type = "long";
1843 value = android::base::StringPrintf("%" PRId64, it.GetJavaValue().j);
1844 break;
1845 case EncodedArrayValueIterator::ValueType::kFloat:
1846 type = "float";
1847 value = android::base::StringPrintf("%g", it.GetJavaValue().f);
1848 break;
1849 case EncodedArrayValueIterator::ValueType::kDouble:
1850 type = "double";
1851 value = android::base::StringPrintf("%g", it.GetJavaValue().d);
1852 break;
1853 case EncodedArrayValueIterator::ValueType::kMethodType: {
1854 type = "MethodType";
Orion Hodson06d10a72018-05-14 08:53:38 +01001855 dex::ProtoIndex proto_idx = static_cast<dex::ProtoIndex>(it.GetJavaValue().i);
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001856 const dex::ProtoId& proto_id = pDexFile->GetProtoId(proto_idx);
Orion Hodsonc069a302017-01-18 09:23:12 +00001857 value = pDexFile->GetProtoSignature(proto_id).ToString();
1858 break;
1859 }
1860 case EncodedArrayValueIterator::ValueType::kMethodHandle:
1861 type = "MethodHandle";
1862 value = android::base::StringPrintf("%d", it.GetJavaValue().i);
1863 break;
1864 case EncodedArrayValueIterator::ValueType::kString: {
1865 type = "String";
1866 dex::StringIndex string_idx = static_cast<dex::StringIndex>(it.GetJavaValue().i);
1867 value = pDexFile->StringDataByIdx(string_idx);
1868 break;
1869 }
1870 case EncodedArrayValueIterator::ValueType::kType: {
1871 type = "Class";
1872 dex::TypeIndex type_idx = static_cast<dex::TypeIndex>(it.GetJavaValue().i);
Andreas Gampe3f1dcd32018-12-28 09:39:56 -08001873 const dex::TypeId& type_id = pDexFile->GetTypeId(type_idx);
Orion Hodson0f6cc7f2018-05-25 15:33:44 +01001874 value = pDexFile->GetTypeDescriptor(type_id);
Orion Hodsonc069a302017-01-18 09:23:12 +00001875 break;
1876 }
1877 case EncodedArrayValueIterator::ValueType::kField:
1878 case EncodedArrayValueIterator::ValueType::kMethod:
1879 case EncodedArrayValueIterator::ValueType::kEnum:
1880 case EncodedArrayValueIterator::ValueType::kArray:
1881 case EncodedArrayValueIterator::ValueType::kAnnotation:
1882 // Unreachable based on current EncodedArrayValueIterator::Next().
Andreas Gampef45d61c2017-06-07 10:29:33 -07001883 UNIMPLEMENTED(FATAL) << " type " << it.GetValueType();
Orion Hodsonc069a302017-01-18 09:23:12 +00001884 UNREACHABLE();
Orion Hodsonc069a302017-01-18 09:23:12 +00001885 case EncodedArrayValueIterator::ValueType::kNull:
1886 type = "Null";
1887 value = "null";
1888 break;
1889 case EncodedArrayValueIterator::ValueType::kBoolean:
1890 type = "boolean";
1891 value = it.GetJavaValue().z ? "true" : "false";
1892 break;
1893 }
1894
1895 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1896 fprintf(gOutFile, " link_argument[%zu] : %s (%s)\n", argument, value.c_str(), type);
Orion Hodsonc069a302017-01-18 09:23:12 +00001897 }
1898
1899 it.Next();
1900 argument++;
1901 }
Orion Hodsonc069a302017-01-18 09:23:12 +00001902}
1903
Aart Bik69ae54a2015-07-01 14:52:26 -07001904/*
1905 * Dumps the requested sections of the file.
1906 */
Aart Bik7b45a8a2016-10-24 16:07:59 -07001907static void processDexFile(const char* fileName,
1908 const DexFile* pDexFile, size_t i, size_t n) {
Aart Bik69ae54a2015-07-01 14:52:26 -07001909 if (gOptions.verbose) {
Aart Bik7b45a8a2016-10-24 16:07:59 -07001910 fputs("Opened '", gOutFile);
1911 fputs(fileName, gOutFile);
1912 if (n > 1) {
Mathieu Chartier79c87da2017-10-10 11:54:29 -07001913 fprintf(gOutFile, ":%s", DexFileLoader::GetMultiDexClassesDexName(i).c_str());
Aart Bik7b45a8a2016-10-24 16:07:59 -07001914 }
1915 fprintf(gOutFile, "', DEX version '%.3s'\n", pDexFile->GetHeader().magic_ + 4);
Aart Bik69ae54a2015-07-01 14:52:26 -07001916 }
1917
1918 // Headers.
1919 if (gOptions.showFileHeaders) {
1920 dumpFileHeader(pDexFile);
1921 }
1922
Aart Bik69ae54a2015-07-01 14:52:26 -07001923 // Iterate over all classes.
1924 char* package = nullptr;
1925 const u4 classDefsSize = pDexFile->GetHeader().class_defs_size_;
Andreas Gampe70dfb692018-09-18 16:50:18 -07001926 for (u4 j = 0; j < classDefsSize; j++) {
1927 dumpClass(pDexFile, j, &package);
Aart Bik69ae54a2015-07-01 14:52:26 -07001928 } // for
1929
Orion Hodsonc069a302017-01-18 09:23:12 +00001930 // Iterate over all method handles.
Andreas Gampe70dfb692018-09-18 16:50:18 -07001931 for (u4 j = 0; j < pDexFile->NumMethodHandles(); ++j) {
1932 dumpMethodHandle(pDexFile, j);
Orion Hodsonc069a302017-01-18 09:23:12 +00001933 } // for
1934
1935 // Iterate over all call site ids.
Andreas Gampe70dfb692018-09-18 16:50:18 -07001936 for (u4 j = 0; j < pDexFile->NumCallSiteIds(); ++j) {
1937 dumpCallSite(pDexFile, j);
Orion Hodsonc069a302017-01-18 09:23:12 +00001938 } // for
1939
Aart Bik69ae54a2015-07-01 14:52:26 -07001940 // Free the last package allocated.
1941 if (package != nullptr) {
1942 fprintf(gOutFile, "</package>\n");
1943 free(package);
1944 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001945}
1946
1947/*
1948 * Processes a single file (either direct .dex or indirect .zip/.jar/.apk).
1949 */
1950int processFile(const char* fileName) {
1951 if (gOptions.verbose) {
1952 fprintf(gOutFile, "Processing '%s'...\n", fileName);
1953 }
1954
Nicolas Geoffrayc1d8caa2018-02-27 10:15:14 +00001955 const bool kVerifyChecksum = !gOptions.ignoreBadChecksum;
1956 const bool kVerify = !gOptions.disableVerifier;
1957 std::string content;
Aart Bik69ae54a2015-07-01 14:52:26 -07001958 // If the file is not a .dex file, the function tries .zip/.jar/.apk files,
Aart Bikdce50862016-06-10 16:04:03 -07001959 // all of which are Zip archives with "classes.dex" inside.
David Sehr999646d2018-02-16 10:22:33 -08001960 // TODO: add an api to android::base to read a std::vector<uint8_t>.
1961 if (!android::base::ReadFileToString(fileName, &content)) {
1962 LOG(ERROR) << "ReadFileToString failed";
David Sehr5a1f6292018-01-19 11:08:51 -08001963 return -1;
1964 }
1965 const DexFileLoader dex_file_loader;
Dario Frenie166fac2018-07-16 11:08:03 +01001966 DexFileLoaderErrorCode error_code;
David Sehr999646d2018-02-16 10:22:33 -08001967 std::string error_msg;
Aart Bik69ae54a2015-07-01 14:52:26 -07001968 std::vector<std::unique_ptr<const DexFile>> dex_files;
David Sehr999646d2018-02-16 10:22:33 -08001969 if (!dex_file_loader.OpenAll(reinterpret_cast<const uint8_t*>(content.data()),
1970 content.size(),
1971 fileName,
Nicolas Geoffrayc1d8caa2018-02-27 10:15:14 +00001972 kVerify,
David Sehr999646d2018-02-16 10:22:33 -08001973 kVerifyChecksum,
Dario Frenie166fac2018-07-16 11:08:03 +01001974 &error_code,
David Sehr999646d2018-02-16 10:22:33 -08001975 &error_msg,
1976 &dex_files)) {
Aart Bik69ae54a2015-07-01 14:52:26 -07001977 // Display returned error message to user. Note that this error behavior
1978 // differs from the error messages shown by the original Dalvik dexdump.
Andreas Gampe221d9812018-01-22 17:48:56 -08001979 LOG(ERROR) << error_msg;
Aart Bik69ae54a2015-07-01 14:52:26 -07001980 return -1;
1981 }
1982
Aart Bik4e149602015-07-09 11:45:28 -07001983 // Success. Either report checksum verification or process
1984 // all dex files found in given file.
Aart Bik69ae54a2015-07-01 14:52:26 -07001985 if (gOptions.checksumOnly) {
1986 fprintf(gOutFile, "Checksum verified\n");
1987 } else {
Paul Duffin4b64f6c2020-10-30 11:58:47 +00001988 // Open XML context.
1989 if (gOptions.outputFormat == OUTPUT_XML) {
1990 fprintf(gOutFile, "<api>\n");
1991 }
1992
Aart Bik7b45a8a2016-10-24 16:07:59 -07001993 for (size_t i = 0, n = dex_files.size(); i < n; i++) {
1994 processDexFile(fileName, dex_files[i].get(), i, n);
Aart Bik4e149602015-07-09 11:45:28 -07001995 }
Paul Duffin4b64f6c2020-10-30 11:58:47 +00001996
1997 // Close XML context.
1998 if (gOptions.outputFormat == OUTPUT_XML) {
1999 fprintf(gOutFile, "</api>\n");
2000 }
Aart Bik69ae54a2015-07-01 14:52:26 -07002001 }
2002 return 0;
2003}
2004
2005} // namespace art