1 /*
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
20 * 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.
22 * 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
30 * - 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
40 #include <cctype>
41 #include <iomanip>
42 #include <memory>
43 #include <sstream>
44 #include <string_view>
45 #include <vector>
46
47 #include "android-base/file.h"
48 #include "android-base/logging.h"
49 #include "android-base/stringprintf.h"
50
51 #include "base/bit_utils.h"
52 #include "dex/class_accessor-inl.h"
53 #include "dex/code_item_accessors-inl.h"
54 #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"
59 #include "dexdump_cfg.h"
60
61 namespace art {
62
63 /*
64 * Options parsed in main driver.
65 */
66 struct Options gOptions;
67
68 /*
69 * Output file. Defaults to stdout.
70 */
71 FILE* gOutFile = stdout;
72
73 /*
74 * Data types that match the definitions in the VM specification.
75 */
76 using u1 = uint8_t;
77 using u2 = uint16_t;
78 using u4 = uint32_t;
79 using u8 = uint64_t;
80 using s1 = int8_t;
81 using s2 = int16_t;
82 using s4 = int32_t;
83 using s8 = int64_t;
84
85 /*
86 * Basic information about a field or a method.
87 */
88 struct FieldMethodInfo {
89 const char* classDescriptor;
90 const char* name;
91 const char* signature;
92 };
93
94 /*
95 * Flags for use with createAccessFlagStr().
96 */
97 enum AccessFor {
98 kAccessForClass = 0, kAccessForMethod = 1, kAccessForField = 2, kAccessForMAX
99 };
100 const int kNumFlags = 18;
101
102 /*
103 * Gets 2 little-endian bytes.
104 */
get2LE(unsigned char const * pSrc)105 static 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 */
primitiveTypeLabel(char typeChar)112 static const char* primitiveTypeLabel(char typeChar) {
113 switch (typeChar) {
114 case 'B': return "byte";
115 case 'C': return "char";
116 case 'D': return "double";
117 case 'F': return "float";
118 case 'I': return "int";
119 case 'J': return "long";
120 case 'S': return "short";
121 case 'V': return "void";
122 case 'Z': return "boolean";
123 default: return "UNKNOWN";
124 } // switch
125 }
126
127 /*
128 * Converts a type descriptor to human-readable "dotted" form. For
129 * example, "Ljava/lang/String;" becomes "java.lang.String", and
130 * "[I" becomes "int[]".
131 */
descriptorToDot(const char * str)132 static std::unique_ptr<char[]> descriptorToDot(const char* str) {
133 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.
159 std::unique_ptr<char[]> newStr(new char[targetLen + arrayDepth * 2 + 1]);
160 int i = 0;
161 for (; i < targetLen; i++) {
162 const char ch = str[offset + i];
163 newStr[i] = (ch == '/') ? '.' : ch;
164 } // 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 /*
177 * Retrieves the class name portion of a type descriptor.
178 */
descriptorClassToName(const char * str)179 static std::unique_ptr<char[]> descriptorClassToName(const char* str) {
180 // Reduce to just the class name prefix.
181 const char* lastSlash = strrchr(str, '/');
182 if (lastSlash == nullptr) {
183 lastSlash = str + 1; // start past 'L'
184 } else {
185 lastSlash++; // start past '/'
186 }
187
188 // 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++) {
192 newStr[i] = lastSlash[i];
193 } // for
194 newStr[targetLen - 1] = '\0';
195 return newStr;
196 }
197
198 /*
199 * Returns string representing the boolean value.
200 */
strBool(bool val)201 static const char* strBool(bool val) {
202 return val ? "true" : "false";
203 }
204
205 /*
206 * Returns a quoted string representing the boolean value.
207 */
quotedBool(bool val)208 static const char* quotedBool(bool val) {
209 return val ? "\"true\"" : "\"false\"";
210 }
211
212 /*
213 * Returns a quoted string representing the access flags.
214 */
quotedVisibility(u4 accessFlags)215 static 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 */
countOnes(u4 val)230 static 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 */
createAccessFlagStr(u4 flags,AccessFor forWhat)242 static 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 */
asciify(char * out,const unsigned char * data,size_t len)337 static void asciify(char* out, const unsigned char* data, size_t len) {
338 for (; len != 0u; --len) {
339 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
364 /* clang-format off */
365 constexpr 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 */
needsEscape(std::string_view s)388 static 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
escapeString(std::string_view s)397 std::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
437 /*
438 * Dumps a string value with some escape characters.
439 */
dumpEscapedString(std::string_view s)440 static void dumpEscapedString(std::string_view s) {
441 fputs("\"", gOutFile);
442 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 }
450 fputs("\"", gOutFile);
451 }
452
utf8Bytes(char start_byte)453 static 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
463 /*
464 * Dumps a string as an XML attribute value.
465 */
dumpXmlAttribute(std::string_view p)466 static 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("&", gOutFile);
472 break;
473 case '<':
474 fputs("<", gOutFile);
475 break;
476 case '>':
477 fputs(">", gOutFile);
478 break;
479 case '"':
480 fputs(""", 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 }
519 } // for
520 }
521
522 /*
523 * Reads variable width value, possibly sign extended at the last defined byte.
524 */
readVarWidth(const u1 ** data,u1 arg,bool sign_extend)525 static 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 */
540 static void dumpEncodedValue(const DexFile* pDexFile, const u1** data); // forward
dumpEncodedValue(const DexFile * pDexFile,const u1 ** data,u1 type,u1 arg)541 static 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) {
581 dumpEscapedString(pDexFile->GetStringView(dex::StringIndex(idx)));
582 } else {
583 dumpXmlAttribute(pDexFile->GetStringView(dex::StringIndex(idx)));
584 }
585 break;
586 }
587 case DexFile::kDexAnnotationType: {
588 const u4 str_idx = static_cast<u4>(readVarWidth(data, arg, false));
589 fputs(pDexFile->GetTypeDescriptor(dex::TypeIndex(str_idx)), gOutFile);
590 break;
591 }
592 case DexFile::kDexAnnotationField:
593 case DexFile::kDexAnnotationEnum: {
594 const u4 field_idx = static_cast<u4>(readVarWidth(data, arg, false));
595 const dex::FieldId& pFieldId = pDexFile->GetFieldId(field_idx);
596 fputs(pDexFile->GetStringData(pFieldId.name_idx_), gOutFile);
597 break;
598 }
599 case DexFile::kDexAnnotationMethod: {
600 const u4 method_idx = static_cast<u4>(readVarWidth(data, arg, false));
601 const dex::MethodId& pMethodId = pDexFile->GetMethodId(method_idx);
602 fputs(pDexFile->GetStringData(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);
618 fputs(pDexFile->GetTypeDescriptor(dex::TypeIndex(type_idx)), gOutFile);
619 // 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);
624 fputs(pDexFile->GetStringData(dex::StringIndex(name_idx)), gOutFile);
625 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 */
dumpEncodedValue(const DexFile * pDexFile,const u1 ** data)645 static void dumpEncodedValue(const DexFile* pDexFile, const u1** data) {
646 const u1 enc = *(*data)++;
647 dumpEncodedValue(pDexFile, data, enc & 0x1f, enc >> 5);
648 }
649
650 /*
651 * Dumps the file header.
652 */
dumpFileHeader(const DexFile * pDexFile)653 static 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_.data(), pHeader.magic_.size());
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_);
675 fprintf(gOutFile, "proto_ids_size : %d\n", pHeader.proto_ids_size_);
676 fprintf(gOutFile, "proto_ids_off : %d (0x%06x)\n",
677 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 */
dumpClassDef(const DexFile * pDexFile,int idx)695 static void dumpClassDef(const DexFile* pDexFile, int idx) {
696 // General class information.
697 const dex::ClassDef& pClassDef = pDexFile->GetClassDef(idx);
698 fprintf(gOutFile, "Class #%d header:\n", idx);
699 fprintf(gOutFile, "class_idx : %d\n", pClassDef.class_idx_.index_);
700 fprintf(gOutFile, "access_flags : %d (0x%04x)\n",
701 pClassDef.access_flags_, pClassDef.access_flags_);
702 fprintf(gOutFile, "superclass_idx : %d\n", pClassDef.superclass_idx_.index_);
703 fprintf(gOutFile, "interfaces_off : %d (0x%06x)\n",
704 pClassDef.interfaces_off_, pClassDef.interfaces_off_);
705 fprintf(gOutFile, "source_file_idx : %d\n", pClassDef.source_file_idx_.index_);
706 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.
712 ClassAccessor accessor(*pDexFile, idx);
713 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());
717 fprintf(gOutFile, "\n");
718 }
719
720 /**
721 * Dumps an annotation set item.
722 */
dumpAnnotationSetItem(const DexFile * pDexFile,const dex::AnnotationSetItem * set_item)723 static void dumpAnnotationSetItem(const DexFile* pDexFile, const dex::AnnotationSetItem* set_item) {
724 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++) {
729 const dex::AnnotationItem* annotation = pDexFile->GetAnnotationItem(set_item, i);
730 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 */
dumpClassAnnotations(const DexFile * pDexFile,int idx)750 static void dumpClassAnnotations(const DexFile* pDexFile, int idx) {
751 const dex::ClassDef& pClassDef = pDexFile->GetClassDef(idx);
752 const dex::AnnotationsDirectoryItem* dir = pDexFile->GetAnnotationsDirectory(pClassDef);
753 if (dir == nullptr) {
754 return; // none
755 }
756
757 fprintf(gOutFile, "Class #%d annotations:\n", idx);
758
759 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);
763
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_;
774 const dex::FieldId& pFieldId = pDexFile->GetFieldId(field_idx);
775 const char* field_name = pDexFile->GetStringData(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_;
785 const dex::MethodId& pMethodId = pDexFile->GetMethodId(method_idx);
786 const char* method_name = pDexFile->GetStringData(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_;
796 const dex::MethodId& pMethodId = pDexFile->GetMethodId(method_idx);
797 const char* method_name = pDexFile->GetStringData(pMethodId.name_idx_);
798 fprintf(gOutFile, "Annotations on method #%u '%s' parameters\n", method_idx, method_name);
799 const dex::AnnotationSetRefList*
800 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
813 /*
814 * Dumps an interface that a class declares to implement.
815 */
dumpInterface(const DexFile * pDexFile,const dex::TypeItem & pTypeItem,int i)816 static void dumpInterface(const DexFile* pDexFile, const dex::TypeItem& pTypeItem, int i) {
817 const char* interfaceName = pDexFile->GetTypeDescriptor(pTypeItem.type_idx_);
818 if (gOptions.outputFormat == OUTPUT_PLAIN) {
819 fprintf(gOutFile, " #%d : '%s'\n", i, interfaceName);
820 } else {
821 std::unique_ptr<char[]> dot(descriptorToDot(interfaceName));
822 fprintf(gOutFile, "<implements name=\"%s\">\n</implements>\n", dot.get());
823 }
824 }
825
826 /*
827 * Dumps the catches table associated with the code.
828 */
dumpCatches(const DexFile * pDexFile,const dex::CodeItem * pCode)829 static void dumpCatches(const DexFile* pDexFile, const dex::CodeItem* pCode) {
830 CodeItemDataAccessor accessor(*pDexFile, pCode);
831 const u4 triesSize = accessor.TriesSize();
832
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);
841 for (const dex::TryItem& try_item : accessor.TryItems()) {
842 const u4 start = try_item.start_addr_;
843 const u4 end = start + try_item.insn_count_;
844 fprintf(gOutFile, " 0x%04x - 0x%04x\n", start, end);
845 for (CatchHandlerIterator it(accessor, try_item); it.HasNext(); it.Next()) {
846 const dex::TypeIndex tidx = it.GetHandlerTypeIndex();
847 const char* descriptor = (!tidx.IsValid()) ? "<any>" : pDexFile->GetTypeDescriptor(tidx);
848 fprintf(gOutFile, " %s -> 0x%04x\n", descriptor, it.GetHandlerAddress());
849 } // for
850 } // for
851 }
852
853 /*
854 * Helper for dumpInstruction(), which builds the string
855 * representation for the index in the given instruction.
856 * Returns a pointer to a buffer of sufficient size.
857 */
indexString(const DexFile * pDexFile,const Instruction * pDecInsn,size_t bufSize)858 static 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]);
862 // Determine index and width of the string.
863 u4 index = 0;
864 u2 secondary_index = 0;
865 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;
888 case Instruction::k45cc:
889 case Instruction::k4rcc:
890 index = pDecInsn->VRegB();
891 secondary_index = pDecInsn->VRegH();
892 width = 4;
893 break;
894 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.
904 outSize = snprintf(buf.get(), bufSize, "<unknown-index>");
905 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.
909 outSize = snprintf(buf.get(), bufSize, "<no-index>");
910 break;
911 case Instruction::kIndexTypeRef:
912 if (index < pDexFile->GetHeader().type_ids_size_) {
913 const char* tp = pDexFile->GetTypeDescriptor(dex::TypeIndex(index));
914 outSize = snprintf(buf.get(), bufSize, "%s // type@%0*x", tp, width, index);
915 } else {
916 outSize = snprintf(buf.get(), bufSize, "<type?> // type@%0*x", width, index);
917 }
918 break;
919 case Instruction::kIndexStringRef:
920 if (index < pDexFile->GetHeader().string_ids_size_) {
921 const char* st = pDexFile->GetStringData(dex::StringIndex(index));
922 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 }
929 } else {
930 outSize = snprintf(buf.get(), bufSize, "<string?> // string@%0*x", width, index);
931 }
932 break;
933 case Instruction::kIndexMethodRef:
934 if (index < pDexFile->GetHeader().method_ids_size_) {
935 const dex::MethodId& pMethodId = pDexFile->GetMethodId(index);
936 const char* name = pDexFile->GetStringData(pMethodId.name_idx_);
937 const Signature signature = pDexFile->GetMethodSignature(pMethodId);
938 const char* backDescriptor = pDexFile->GetTypeDescriptor(pMethodId.class_idx_);
939 outSize = snprintf(buf.get(), bufSize, "%s.%s:%s // method@%0*x",
940 backDescriptor, name, signature.ToString().c_str(), width, index);
941 } else {
942 outSize = snprintf(buf.get(), bufSize, "<method?> // method@%0*x", width, index);
943 }
944 break;
945 case Instruction::kIndexFieldRef:
946 if (index < pDexFile->GetHeader().field_ids_size_) {
947 const dex::FieldId& pFieldId = pDexFile->GetFieldId(index);
948 const char* name = pDexFile->GetStringData(pFieldId.name_idx_);
949 const char* typeDescriptor = pDexFile->GetTypeDescriptor(pFieldId.type_idx_);
950 const char* backDescriptor = pDexFile->GetTypeDescriptor(pFieldId.class_idx_);
951 outSize = snprintf(buf.get(), bufSize, "%s.%s:%s // field@%0*x",
952 backDescriptor, name, typeDescriptor, width, index);
953 } else {
954 outSize = snprintf(buf.get(), bufSize, "<field?> // field@%0*x", width, index);
955 }
956 break;
957 case Instruction::kIndexVtableOffset:
958 outSize = snprintf(buf.get(), bufSize, "[%0*x] // vtable #%0*x",
959 width, index, width, index);
960 break;
961 case Instruction::kIndexFieldOffset:
962 outSize = snprintf(buf.get(), bufSize, "[obj+%0*x]", width, index);
963 break;
964 case Instruction::kIndexMethodAndProtoRef: {
965 std::string method("<method?>");
966 std::string proto("<proto?>");
967 if (index < pDexFile->GetHeader().method_ids_size_) {
968 const dex::MethodId& pMethodId = pDexFile->GetMethodId(index);
969 const char* name = pDexFile->GetStringData(pMethodId.name_idx_);
970 const Signature signature = pDexFile->GetMethodSignature(pMethodId);
971 const char* backDescriptor = pDexFile->GetTypeDescriptor(pMethodId.class_idx_);
972 method = android::base::StringPrintf("%s.%s:%s",
973 backDescriptor,
974 name,
975 signature.ToString().c_str());
976 }
977 if (secondary_index < pDexFile->GetHeader().proto_ids_size_) {
978 const dex::ProtoId& protoId = pDexFile->GetProtoId(dex::ProtoIndex(secondary_index));
979 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);
989 break;
990 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_) {
996 const dex::ProtoId& protoId = pDexFile->GetProtoId(dex::ProtoIndex(index));
997 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 }
1003 break;
1004 } // switch
1005
1006 if (outSize == 0) {
1007 // The index type has not been handled in the switch above.
1008 outSize = snprintf(buf.get(), bufSize, "<?>");
1009 }
1010
1011 // Determine success of string construction.
1012 if (outSize >= bufSize) {
1013 // 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);
1017 }
1018 return buf;
1019 }
1020
1021 /*
1022 * Dumps a single instruction.
1023 */
dumpInstruction(const DexFile * pDexFile,const dex::CodeItem * pCode,u4 codeOffset,u4 insnIdx,u4 insnWidth,const Instruction * pDecInsn)1024 static void dumpInstruction(const DexFile* pDexFile,
1025 const dex::CodeItem* pCode,
1026 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.
1032 CodeItemInstructionAccessor accessor(*pDexFile, pCode);
1033 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.
1039 const u1* bytePtr = (const u1*) &accessor.Insns()[insnIdx + i];
1040 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) {
1049 const u2 instr = get2LE((const u1*) &accessor.Insns()[insnIdx]);
1050 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.
1064 std::unique_ptr<char[]> indexBuf;
1065 if (Instruction::IndexTypeOf(pDecInsn->Opcode()) != Instruction::kIndexNone) {
1066 indexBuf = indexString(pDexFile, pDecInsn, 200);
1067 }
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
1087 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);
1093 break;
1094 }
1095 case Instruction::k22x: // op vAA, vBBBB
1096 fprintf(gOutFile, " v%d, v%d", pDecInsn->VRegA(), pDecInsn->VRegB());
1097 break;
1098 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);
1104 break;
1105 }
1106 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
1124 fprintf(gOutFile, " v%d, %s", pDecInsn->VRegA(), indexBuf.get());
1125 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;
1135 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);
1142 break;
1143 }
1144 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",
1153 pDecInsn->VRegA(), pDecInsn->VRegB(), indexBuf.get());
1154 break;
1155 case Instruction::k30t:
1156 fprintf(gOutFile, " #%08x", pDecInsn->VRegA());
1157 break;
1158 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());
1167 break;
1168 }
1169 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;
1176 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
1178 // NOT SUPPORTED:
1179 // case Instruction::k35ms: // [opt] invoke-virtual+super
1180 // case Instruction::k35mi: // [opt] inline invoke
1181 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
1191 fprintf(gOutFile, "}, %s", indexBuf.get());
1192 break;
1193 }
1194 case Instruction::k3rc: // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB
1195 case Instruction::k4rcc: { // op {vCCCC .. v(CCCC+AA-1)}, method@BBBB, proto@HHHH
1196 // NOT SUPPORTED:
1197 // case Instruction::k3rms: // [opt] invoke-virtual+super/range
1198 // case Instruction::k3rmi: // [opt] execute-inline/range
1199 // 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
1209 fprintf(gOutFile, "}, %s", indexBuf.get());
1210 }
1211 break;
1212 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());
1221 break;
1222 }
1223 // 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);
1232 }
1233
1234 /*
1235 * Dumps a bytecode disassembly.
1236 */
dumpBytecodes(const DexFile * pDexFile,u4 idx,const dex::CodeItem * pCode,u4 codeOffset)1237 static void dumpBytecodes(const DexFile* pDexFile, u4 idx,
1238 const dex::CodeItem* pCode, u4 codeOffset) {
1239 const dex::MethodId& pMethodId = pDexFile->GetMethodId(idx);
1240 const char* name = pDexFile->GetStringData(pMethodId.name_idx_);
1241 const Signature signature = pDexFile->GetMethodSignature(pMethodId);
1242 const char* backDescriptor = pDexFile->GetTypeDescriptor(pMethodId.class_idx_);
1243
1244 // Generate header.
1245 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());
1248
1249 // Iterate over all instructions.
1250 CodeItemDataAccessor accessor(*pDexFile, pCode);
1251 const u4 maxPc = accessor.InsnsSizeInCodeUnits();
1252 for (const DexInstructionPcPair& pair : accessor) {
1253 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 }
1258 const Instruction* instruction = &pair.Inst();
1259 const u4 insnWidth = instruction->SizeInCodeUnits();
1260 if (insnWidth == 0) {
1261 LOG(WARNING) << "GLITCH: zero-width instruction at idx=0x" << std::hex << dexPc;
1262 break;
1263 }
1264 dumpInstruction(pDexFile, pCode, codeOffset, dexPc, insnWidth, instruction);
1265 } // for
1266 }
1267
findLastInstructionAddress(const CodeItemDebugInfoAccessor & accessor)1268 static 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
1281 /*
1282 * Dumps code of a method.
1283 */
dumpCode(const DexFile * pDexFile,u4 idx,u4 flags,const dex::CodeItem * pCode,u4 codeOffset)1284 static void dumpCode(const DexFile* pDexFile, u4 idx, u4 flags,
1285 const dex::CodeItem* pCode, u4 codeOffset) {
1286 CodeItemDebugInfoAccessor accessor(*pDexFile, pCode, idx);
1287
1288 fprintf(gOutFile, " registers : %d\n", accessor.RegistersSize());
1289 fprintf(gOutFile, " ins : %d\n", accessor.InsSize());
1290 fprintf(gOutFile, " outs : %d\n", accessor.OutsSize());
1291 fprintf(gOutFile, " insns size : %d 16-bit code units\n",
1292 accessor.InsnsSizeInCodeUnits());
1293
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
1302 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;
1306 fprintf(gOutFile, " positions :\n");
1307 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 });
1315 fprintf(gOutFile, " locals :\n");
1316 accessor.DecodeDebugLocalInfo(is_static,
1317 idx,
1318 [&](const DexFile::LocalInfo& entry) {
1319 fprintf(gOutFile,
1320 " 0x%04x - 0x%04x reg=%d %s %s",
1321 entry.start_address_,
1322 entry.end_address_,
1323 entry.reg_,
1324 entry.name_,
1325 entry.descriptor_);
1326 if (entry.signature_) {
1327 fputc(' ', gOutFile);
1328 fputs(entry.signature_, gOutFile);
1329 }
1330 fputc('\n', gOutFile);
1331 });
1332 }
1333 }
1334
GetHiddenapiFlagStr(uint32_t hiddenapi_flags)1335 static 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
1344 /*
1345 * Dumps a method.
1346 */
dumpMethod(const ClassAccessor::Method & method,int i)1347 static void dumpMethod(const ClassAccessor::Method& method, int i) {
1348 // Bail for anything private if export only requested.
1349 const uint32_t flags = method.GetAccessFlags();
1350 if (gOptions.exportsOnly && (flags & (kAccPublic | kAccProtected)) == 0) {
1351 return;
1352 }
1353
1354 const DexFile& dex_file = method.GetDexFile();
1355 const dex::MethodId& pMethodId = dex_file.GetMethodId(method.GetIndex());
1356 const char* name = dex_file.GetStringData(pMethodId.name_idx_);
1357 const Signature signature = dex_file.GetMethodSignature(pMethodId);
1358 char* typeDescriptor = strdup(signature.ToString().c_str());
1359 const char* backDescriptor = dex_file.GetTypeDescriptor(pMethodId.class_idx_);
1360 char* accessStr = createAccessFlagStr(flags, kAccessForMethod);
1361 const uint32_t hiddenapiFlags = method.GetHiddenapiFlags();
1362
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);
1368 if (gOptions.showSectionHeaders) {
1369 fprintf(gOutFile, " method_idx : %d\n", method.GetIndex());
1370 }
1371 if (hiddenapiFlags != 0u) {
1372 fprintf(gOutFile,
1373 " hiddenapi : 0x%04x (%s)\n",
1374 hiddenapiFlags,
1375 GetHiddenapiFlagStr(hiddenapiFlags).c_str());
1376 }
1377 if (method.GetCodeItem() == nullptr) {
1378 fprintf(gOutFile, " code : (none)\n");
1379 } else {
1380 fprintf(gOutFile, " code -\n");
1381 dumpCode(&dex_file,
1382 method.GetIndex(),
1383 flags,
1384 method.GetCodeItem(),
1385 method.GetCodeItemOffset());
1386 }
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) {
1395 std::unique_ptr<char[]> dot(descriptorClassToName(backDescriptor));
1396 fprintf(gOutFile, "<constructor name=\"%s\"\n", dot.get());
1397 dot = descriptorToDot(backDescriptor);
1398 fprintf(gOutFile, " type=\"%s\"\n", dot.get());
1399 } else {
1400 fprintf(gOutFile, "<method name=\"%s\"\n", name);
1401 const char* returnType = strrchr(typeDescriptor, ')');
1402 if (returnType == nullptr) {
1403 LOG(ERROR) << "bad method type descriptor '" << typeDescriptor << "'";
1404 goto bail;
1405 }
1406 std::unique_ptr<char[]> dot(descriptorToDot(returnType + 1));
1407 fprintf(gOutFile, " return=\"%s\"\n", dot.get());
1408 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] != '(') {
1422 LOG(ERROR) << "ERROR: bad descriptor '" << typeDescriptor << "'";
1423 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.
1440 if (strchr("ZBCSIFJD", *base) == nullptr) {
1441 LOG(ERROR) << "ERROR: bad method signature '" << base << "'";
1442 break; // while
1443 }
1444 *cp++ = *base++;
1445 }
1446 // Null terminate and display.
1447 *cp++ = '\0';
1448 std::unique_ptr<char[]> dot(descriptorToDot(tmpBuf));
1449 fprintf(gOutFile, "<parameter name=\"arg%d\" type=\"%s\">\n"
1450 "</parameter>\n", argNum++, dot.get());
1451 } // while
1452 free(tmpBuf);
1453 if (constructor) {
1454 fprintf(gOutFile, "</constructor>\n");
1455 } else {
1456 fprintf(gOutFile, "</method>\n");
1457 }
1458 }
1459
1460 bail:
1461 free(typeDescriptor);
1462 free(accessStr);
1463 }
1464
1465 /*
1466 * Dumps a static or instance (class) field.
1467 */
dumpField(const ClassAccessor::Field & field,int i,const u1 ** data=nullptr)1468 static void dumpField(const ClassAccessor::Field& field, int i, const u1** data = nullptr) {
1469 // Bail for anything private if export only requested.
1470 const uint32_t flags = field.GetAccessFlags();
1471 if (gOptions.exportsOnly && (flags & (kAccPublic | kAccProtected)) == 0) {
1472 return;
1473 }
1474
1475 const DexFile& dex_file = field.GetDexFile();
1476 const dex::FieldId& field_id = dex_file.GetFieldId(field.GetIndex());
1477 const char* name = dex_file.GetStringData(field_id.name_idx_);
1478 const char* typeDescriptor = dex_file.GetTypeDescriptor(field_id.type_idx_);
1479 const char* backDescriptor = dex_file.GetTypeDescriptor(field_id.class_idx_);
1480 char* accessStr = createAccessFlagStr(flags, kAccessForField);
1481 const uint32_t hiddenapiFlags = field.GetHiddenapiFlags();
1482
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);
1488 if (hiddenapiFlags != 0u) {
1489 fprintf(gOutFile,
1490 " hiddenapi : 0x%04x (%s)\n",
1491 hiddenapiFlags,
1492 GetHiddenapiFlagStr(hiddenapiFlags).c_str());
1493 }
1494 if (data != nullptr) {
1495 fputs(" value : ", gOutFile);
1496 dumpEncodedValue(&dex_file, data);
1497 fputs("\n", gOutFile);
1498 }
1499 } else if (gOptions.outputFormat == OUTPUT_XML) {
1500 fprintf(gOutFile, "<field name=\"%s\"\n", name);
1501 std::unique_ptr<char[]> dot(descriptorToDot(typeDescriptor));
1502 fprintf(gOutFile, " type=\"%s\"\n", dot.get());
1503 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));
1510 if (data != nullptr) {
1511 fputs(" value=\"", gOutFile);
1512 dumpEncodedValue(&dex_file, data);
1513 fputs("\"\n", gOutFile);
1514 }
1515 fputs(">\n</field>\n", gOutFile);
1516 }
1517
1518 free(accessStr);
1519 }
1520
1521 /*
1522 * Dumping a CFG.
1523 */
dumpCfg(const DexFile * dex_file,int idx)1524 static void dumpCfg(const DexFile* dex_file, int idx) {
1525 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 }
1532 }
1533 }
1534
1535 /*
1536 * 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 */
dumpClass(const DexFile * pDexFile,int idx,char ** pLastPackage)1543 static void dumpClass(const DexFile* pDexFile, int idx, char** pLastPackage) {
1544 const dex::ClassDef& pClassDef = pDexFile->GetClassDef(idx);
1545
1546 // Omitting non-public class.
1547 if (gOptions.exportsOnly && (pClassDef.access_flags_ & kAccPublic) == 0) {
1548 return;
1549 }
1550
1551 if (gOptions.showSectionHeaders) {
1552 dumpClassDef(pDexFile, idx);
1553 }
1554
1555 if (gOptions.showAnnotations) {
1556 dumpClassAnnotations(pDexFile, idx);
1557 }
1558
1559 if (gOptions.showCfg) {
1560 dumpCfg(pDexFile, idx);
1561 return;
1562 }
1563
1564 // 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->GetTypeDescriptor(pClassDef.class_idx_);
1569 if (!(classDescriptor[0] == 'L' &&
1570 classDescriptor[strlen(classDescriptor)-1] == ';')) {
1571 // Arrays and primitives should not be defined explicitly. Keep going?
1572 LOG(WARNING) << "Malformed class name '" << classDescriptor << "'";
1573 } 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;
1607 if (!pClassDef.superclass_idx_.IsValid()) {
1608 superclassDescriptor = nullptr;
1609 } else {
1610 superclassDescriptor = pDexFile->GetTypeDescriptor(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 {
1621 std::unique_ptr<char[]> dot(descriptorClassToName(classDescriptor));
1622 fprintf(gOutFile, "<class name=\"%s\"\n", dot.get());
1623 if (superclassDescriptor != nullptr) {
1624 dot = descriptorToDot(superclassDescriptor);
1625 fprintf(gOutFile, " extends=\"%s\"\n", dot.get());
1626 }
1627 fprintf(gOutFile, " interface=%s\n",
1628 quotedBool((pClassDef.access_flags_ & kAccInterface) != 0));
1629 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.
1638 const dex::TypeList* pInterfaces = pDexFile->GetInterfacesList(pClassDef);
1639 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.
1646 ClassAccessor accessor(*pDexFile, pClassDef, /* parse_hiddenapi_class_data= */ true);
1647
1648 // Prepare data for static fields.
1649 const u1* sData = pDexFile->GetEncodedStaticFieldValuesArray(pClassDef);
1650 const u4 sSize = sData != nullptr ? DecodeUnsignedLeb128(&sData) : 0;
1651
1652 // 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 }
1661
1662 // 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 }
1671
1672 // 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 }
1681
1682 // 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;
1690 }
1691
1692 // End of class.
1693 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1694 const char* fileName;
1695 if (pClassDef.source_file_idx_.IsValid()) {
1696 fileName = pDexFile->GetStringData(pClassDef.source_file_idx_);
1697 } else {
1698 fileName = "unknown";
1699 }
1700 fprintf(gOutFile, " source_file_idx : %d (%s)\n\n",
1701 pClassDef.source_file_idx_.index_, fileName);
1702 } else if (gOptions.outputFormat == OUTPUT_XML) {
1703 fprintf(gOutFile, "</class>\n");
1704 }
1705
1706 free(accessStr);
1707 }
1708
dumpMethodHandle(const DexFile * pDexFile,u4 idx)1709 static void dumpMethodHandle(const DexFile* pDexFile, u4 idx) {
1710 const dex::MethodHandleItem& mh = pDexFile->GetMethodHandle(idx);
1711 const char* type = nullptr;
1712 bool is_instance = false;
1713 bool is_invoke = false;
1714 switch (static_cast<DexFile::MethodHandleType>(mh.method_handle_type_)) {
1715 case DexFile::MethodHandleType::kStaticPut:
1716 type = "put-static";
1717 is_instance = false;
1718 is_invoke = false;
1719 break;
1720 case DexFile::MethodHandleType::kStaticGet:
1721 type = "get-static";
1722 is_instance = false;
1723 is_invoke = false;
1724 break;
1725 case DexFile::MethodHandleType::kInstancePut:
1726 type = "put-instance";
1727 is_instance = true;
1728 is_invoke = false;
1729 break;
1730 case DexFile::MethodHandleType::kInstanceGet:
1731 type = "get-instance";
1732 is_instance = true;
1733 is_invoke = false;
1734 break;
1735 case DexFile::MethodHandleType::kInvokeStatic:
1736 type = "invoke-static";
1737 is_instance = false;
1738 is_invoke = true;
1739 break;
1740 case DexFile::MethodHandleType::kInvokeInstance:
1741 type = "invoke-instance";
1742 is_instance = true;
1743 is_invoke = true;
1744 break;
1745 case DexFile::MethodHandleType::kInvokeConstructor:
1746 type = "invoke-constructor";
1747 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;
1758 is_invoke = true;
1759 break;
1760 }
1761
1762 const char* declaring_class;
1763 const char* member;
1764 std::string member_type;
1765 if (type != nullptr) {
1766 if (is_invoke) {
1767 const dex::MethodId& method_id = pDexFile->GetMethodId(mh.field_or_method_idx_);
1768 declaring_class = pDexFile->GetMethodDeclaringClassDescriptor(method_id);
1769 member = pDexFile->GetMethodName(method_id);
1770 member_type = pDexFile->GetMethodSignature(method_id).ToString();
1771 } else {
1772 const dex::FieldId& field_id = pDexFile->GetFieldId(mh.field_or_method_idx_);
1773 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 }
1780 } else {
1781 type = "?";
1782 declaring_class = "?";
1783 member = "?";
1784 member_type = "?";
1785 }
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());
1792 }
1793 }
1794
dumpCallSite(const DexFile * pDexFile,u4 idx)1795 static void dumpCallSite(const DexFile* pDexFile, u4 idx) {
1796 const dex::CallSiteIdItem& call_site_id = pDexFile->GetCallSiteId(idx);
1797 CallSiteArrayValueIterator it(*pDexFile, call_site_id);
1798 if (it.Size() < 3) {
1799 LOG(ERROR) << "ERROR: Call site " << idx << " has too few values.";
1800 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->GetStringData(method_name_idx);
1807 it.Next();
1808 dex::ProtoIndex method_type_idx = static_cast<dex::ProtoIndex>(it.GetJavaValue().i);
1809 const dex::ProtoId& method_type_id = pDexFile->GetProtoId(method_type_idx);
1810 std::string method_type = pDexFile->GetProtoSignature(method_type_id).ToString();
1811 it.Next();
1812
1813 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1814 fprintf(gOutFile, "Call site #%u: // offset %u\n", idx, call_site_id.data_off_);
1815 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());
1818 }
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";
1855 dex::ProtoIndex proto_idx = static_cast<dex::ProtoIndex>(it.GetJavaValue().i);
1856 const dex::ProtoId& proto_id = pDexFile->GetProtoId(proto_idx);
1857 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->GetStringData(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);
1873 const dex::TypeId& type_id = pDexFile->GetTypeId(type_idx);
1874 value = pDexFile->GetTypeDescriptor(type_id);
1875 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().
1883 UNIMPLEMENTED(FATAL) << " type " << it.GetValueType();
1884 UNREACHABLE();
1885 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 case EncodedArrayValueIterator::ValueType::kEndOfInput:
1894 LOG(FATAL) << "Unreachable";
1895 UNREACHABLE();
1896 }
1897
1898 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1899 fprintf(gOutFile, " link_argument[%zu] : %s (%s)\n", argument, value.c_str(), type);
1900 }
1901
1902 it.Next();
1903 argument++;
1904 }
1905 }
1906
1907 /*
1908 * Used to decide if we want to print or skip a string from string_ids
1909 */
isPrintable(const char * s)1910 static int isPrintable(const char* s) {
1911 for (size_t i = 0; i < strlen(s); i++) {
1912 if (!isprint((s[i]))) {
1913 return false;
1914 }
1915 }
1916 return true;
1917 }
1918
1919 /*
1920 * Show all printable string in the string_ids section
1921 */
dumpStrings(const DexFile * pDexFile)1922 static void dumpStrings(const DexFile* pDexFile) {
1923 const DexFile::Header& pHeader = pDexFile->GetHeader();
1924 fprintf(gOutFile, "\nDisplaying %u strings from string_ids:\n", pHeader.string_ids_size_);
1925
1926 for (uint32_t i = 0; i < pHeader.string_ids_size_; i++) {
1927 dex::StringIndex idx = static_cast<dex::StringIndex>(i);
1928 const char* string = pDexFile->GetStringData(idx);
1929 if (!isPrintable(string)) {
1930 string = "skipped (not printable)";
1931 }
1932 fprintf(gOutFile, " string[%06u] - '%s'\n", i, string);
1933 }
1934
1935 fprintf(gOutFile, "\n");
1936 }
1937
1938 /*
1939 * Dumps the requested sections of the file.
1940 */
processDexFile(const char * fileName,const DexFile * pDexFile,size_t i,size_t n)1941 static void processDexFile(const char* fileName,
1942 const DexFile* pDexFile, size_t i, size_t n) {
1943 if (gOptions.verbose) {
1944 fputs("Opened '", gOutFile);
1945 fputs(fileName, gOutFile);
1946 if (n > 1) {
1947 fprintf(gOutFile, ":%s", DexFileLoader::GetMultiDexClassesDexName(i).c_str());
1948 }
1949 fprintf(gOutFile, "', DEX version '%.3s'\n", pDexFile->GetHeader().magic_.data() + 4);
1950 }
1951
1952 // Headers.
1953 if (gOptions.showFileHeaders) {
1954 dumpFileHeader(pDexFile);
1955 }
1956
1957 // Strings.
1958 if (gOptions.showAllStrings) {
1959 dumpStrings(pDexFile);
1960 }
1961
1962 // Iterate over all classes.
1963 char* package = nullptr;
1964 const u4 classDefsSize = pDexFile->GetHeader().class_defs_size_;
1965 for (u4 j = 0; j < classDefsSize; j++) {
1966 dumpClass(pDexFile, j, &package);
1967 } // for
1968
1969 // Iterate over all method handles.
1970 for (u4 j = 0; j < pDexFile->NumMethodHandles(); ++j) {
1971 dumpMethodHandle(pDexFile, j);
1972 } // for
1973
1974 // Iterate over all call site ids.
1975 for (u4 j = 0; j < pDexFile->NumCallSiteIds(); ++j) {
1976 dumpCallSite(pDexFile, j);
1977 } // for
1978
1979 // Free the last package allocated.
1980 if (package != nullptr) {
1981 fprintf(gOutFile, "</package>\n");
1982 free(package);
1983 }
1984 }
1985
1986 /*
1987 * Processes a single file (either direct .dex or indirect .zip/.jar/.apk).
1988 */
processFile(const char * fileName)1989 int processFile(const char* fileName) {
1990 if (gOptions.verbose) {
1991 fprintf(gOutFile, "Processing '%s'...\n", fileName);
1992 }
1993
1994 const bool kVerifyChecksum = !gOptions.ignoreBadChecksum;
1995 const bool kVerify = !gOptions.disableVerifier;
1996 std::string content;
1997 // If the file is not a .dex file, the function tries .zip/.jar/.apk files,
1998 // all of which are Zip archives with "classes.dex" inside.
1999 // TODO: add an api to android::base to read a std::vector<uint8_t>.
2000 if (!android::base::ReadFileToString(fileName, &content)) {
2001 LOG(ERROR) << "ReadFileToString failed";
2002 return -1;
2003 }
2004 DexFileLoaderErrorCode error_code;
2005 std::string error_msg;
2006 std::vector<std::unique_ptr<const DexFile>> dex_files;
2007 DexFileLoader dex_file_loader(
2008 reinterpret_cast<const uint8_t*>(content.data()), content.size(), fileName);
2009 if (!dex_file_loader.Open(kVerify, kVerifyChecksum, &error_code, &error_msg, &dex_files)) {
2010 // Display returned error message to user. Note that this error behavior
2011 // differs from the error messages shown by the original Dalvik dexdump.
2012 LOG(ERROR) << error_msg;
2013 return -1;
2014 }
2015
2016 // Success. Either report checksum verification or process
2017 // all dex files found in given file.
2018 if (gOptions.checksumOnly) {
2019 fprintf(gOutFile, "Checksum verified\n");
2020 } else {
2021 // Open XML context.
2022 if (gOptions.outputFormat == OUTPUT_XML) {
2023 fprintf(gOutFile, "<api>\n");
2024 }
2025
2026 for (size_t i = 0, n = dex_files.size(); i < n; i++) {
2027 processDexFile(fileName, dex_files[i].get(), i, n);
2028 }
2029
2030 // Close XML context.
2031 if (gOptions.outputFormat == OUTPUT_XML) {
2032 fprintf(gOutFile, "</api>\n");
2033 }
2034 }
2035 return 0;
2036 }
2037
2038 } // namespace art
2039