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 #include "base/bit_utils.h"
51 #include "dex/class_accessor-inl.h"
52 #include "dex/code_item_accessors-inl.h"
53 #include "dex/dex_file-inl.h"
54 #include "dex/dex_file_exception_helpers.h"
55 #include "dex/dex_file_loader.h"
56 #include "dex/dex_file_structs.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 class AccessFor {
98 kClass = 0,
99 kMethod = 1,
100 kField = 2,
101 kCount
102 };
103 static constexpr int kNumFlags = 18;
104
105 /*
106 * Gets 2 little-endian bytes.
107 */
get2LE(unsigned char const * pSrc)108 static inline u2 get2LE(unsigned char const* pSrc) {
109 return pSrc[0] | (pSrc[1] << 8);
110 }
111
112 /*
113 * Converts a single-character primitive type into human-readable form.
114 */
primitiveTypeLabel(char typeChar)115 static const char* primitiveTypeLabel(char typeChar) {
116 switch (typeChar) {
117 case 'B': return "byte";
118 case 'C': return "char";
119 case 'D': return "double";
120 case 'F': return "float";
121 case 'I': return "int";
122 case 'J': return "long";
123 case 'S': return "short";
124 case 'V': return "void";
125 case 'Z': return "boolean";
126 default: return "UNKNOWN";
127 } // switch
128 }
129
130 /*
131 * Converts a type descriptor to human-readable "dotted" form. For
132 * example, "Ljava/lang/String;" becomes "java.lang.String", and
133 * "[I" becomes "int[]".
134 */
descriptorToDot(const char * str)135 static std::unique_ptr<char[]> descriptorToDot(const char* str) {
136 int targetLen = strlen(str);
137 int offset = 0;
138
139 // Strip leading [s; will be added to end.
140 while (targetLen > 1 && str[offset] == '[') {
141 offset++;
142 targetLen--;
143 } // while
144
145 const int arrayDepth = offset;
146
147 if (targetLen == 1) {
148 // Primitive type.
149 str = primitiveTypeLabel(str[offset]);
150 offset = 0;
151 targetLen = strlen(str);
152 } else {
153 // Account for leading 'L' and trailing ';'.
154 if (targetLen >= 2 && str[offset] == 'L' &&
155 str[offset + targetLen - 1] == ';') {
156 targetLen -= 2;
157 offset++;
158 }
159 }
160
161 // Copy class name over.
162 std::unique_ptr<char[]> newStr(new char[targetLen + arrayDepth * 2 + 1]);
163 int i = 0;
164 for (; i < targetLen; i++) {
165 const char ch = str[offset + i];
166 newStr[i] = (ch == '/') ? '.' : ch;
167 } // for
168
169 // Add the appropriate number of brackets for arrays.
170 for (int j = 0; j < arrayDepth; j++) {
171 newStr[i++] = '[';
172 newStr[i++] = ']';
173 } // for
174
175 newStr[i] = '\0';
176 return newStr;
177 }
178
179 /*
180 * Retrieves the class name portion of a type descriptor.
181 */
descriptorClassToName(const char * str)182 static std::unique_ptr<char[]> descriptorClassToName(const char* str) {
183 // Reduce to just the class name prefix.
184 const char* lastSlash = strrchr(str, '/');
185 if (lastSlash == nullptr) {
186 lastSlash = str + 1; // start past 'L'
187 } else {
188 lastSlash++; // start past '/'
189 }
190
191 // Copy class name over, trimming trailing ';'.
192 const int targetLen = strlen(lastSlash);
193 std::unique_ptr<char[]> newStr(new char[targetLen]);
194 for (int i = 0; i < targetLen - 1; i++) {
195 newStr[i] = lastSlash[i];
196 } // for
197 newStr[targetLen - 1] = '\0';
198 return newStr;
199 }
200
201 /*
202 * Returns string representing the boolean value.
203 */
strBool(bool val)204 static const char* strBool(bool val) {
205 return val ? "true" : "false";
206 }
207
208 /*
209 * Returns a quoted string representing the boolean value.
210 */
quotedBool(bool val)211 static const char* quotedBool(bool val) {
212 return val ? "\"true\"" : "\"false\"";
213 }
214
215 /*
216 * Returns a quoted string representing the access flags.
217 */
quotedVisibility(u4 accessFlags)218 static const char* quotedVisibility(u4 accessFlags) {
219 if (accessFlags & kAccPublic) {
220 return "\"public\"";
221 } else if (accessFlags & kAccProtected) {
222 return "\"protected\"";
223 } else if (accessFlags & kAccPrivate) {
224 return "\"private\"";
225 } else {
226 return "\"package\"";
227 }
228 }
229
230 /*
231 * Counts the number of '1' bits in a word.
232 */
countOnes(u4 val)233 static int countOnes(u4 val) {
234 val = val - ((val >> 1) & 0x55555555);
235 val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
236 return (((val + (val >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
237 }
238
239 /*
240 * Creates a new string with human-readable access flags.
241 *
242 * In the base language the access_flags fields are type u2; in Dalvik
243 * they're u4.
244 */
createAccessFlagStr(u4 flags,AccessFor forWhat)245 static char* createAccessFlagStr(u4 flags, AccessFor forWhat) {
246 static constexpr const char* kAccessStrings[static_cast<int>(AccessFor::kCount)][kNumFlags] = {
247 {
248 "PUBLIC", /* 0x00001 */
249 "PRIVATE", /* 0x00002 */
250 "PROTECTED", /* 0x00004 */
251 "STATIC", /* 0x00008 */
252 "FINAL", /* 0x00010 */
253 "?", /* 0x00020 */
254 "?", /* 0x00040 */
255 "?", /* 0x00080 */
256 "?", /* 0x00100 */
257 "INTERFACE", /* 0x00200 */
258 "ABSTRACT", /* 0x00400 */
259 "?", /* 0x00800 */
260 "SYNTHETIC", /* 0x01000 */
261 "ANNOTATION", /* 0x02000 */
262 "ENUM", /* 0x04000 */
263 "?", /* 0x08000 */
264 "VERIFIED", /* 0x10000 */
265 "OPTIMIZED", /* 0x20000 */
266 }, {
267 "PUBLIC", /* 0x00001 */
268 "PRIVATE", /* 0x00002 */
269 "PROTECTED", /* 0x00004 */
270 "STATIC", /* 0x00008 */
271 "FINAL", /* 0x00010 */
272 "SYNCHRONIZED", /* 0x00020 */
273 "BRIDGE", /* 0x00040 */
274 "VARARGS", /* 0x00080 */
275 "NATIVE", /* 0x00100 */
276 "?", /* 0x00200 */
277 "ABSTRACT", /* 0x00400 */
278 "STRICT", /* 0x00800 */
279 "SYNTHETIC", /* 0x01000 */
280 "?", /* 0x02000 */
281 "?", /* 0x04000 */
282 "MIRANDA", /* 0x08000 */
283 "CONSTRUCTOR", /* 0x10000 */
284 "DECLARED_SYNCHRONIZED", /* 0x20000 */
285 }, {
286 "PUBLIC", /* 0x00001 */
287 "PRIVATE", /* 0x00002 */
288 "PROTECTED", /* 0x00004 */
289 "STATIC", /* 0x00008 */
290 "FINAL", /* 0x00010 */
291 "?", /* 0x00020 */
292 "VOLATILE", /* 0x00040 */
293 "TRANSIENT", /* 0x00080 */
294 "?", /* 0x00100 */
295 "?", /* 0x00200 */
296 "?", /* 0x00400 */
297 "?", /* 0x00800 */
298 "SYNTHETIC", /* 0x01000 */
299 "?", /* 0x02000 */
300 "ENUM", /* 0x04000 */
301 "?", /* 0x08000 */
302 "?", /* 0x10000 */
303 "?", /* 0x20000 */
304 },
305 };
306
307 // Allocate enough storage to hold the expected number of strings,
308 // plus a space between each. We over-allocate, using the longest
309 // string above as the base metric.
310 static constexpr int kLongest = 21; // The strlen of longest string above.
311 const int count = countOnes(flags);
312 char* str;
313 char* cp;
314 cp = str = reinterpret_cast<char*>(malloc(count * (kLongest + 1) + 1));
315
316 for (int i = 0; i < kNumFlags; i++) {
317 if (flags & 0x01) {
318 const char* accessStr = kAccessStrings[static_cast<int>(forWhat)][i];
319 const int len = strlen(accessStr);
320 if (cp != str) {
321 *cp++ = ' ';
322 }
323 memcpy(cp, accessStr, len);
324 cp += len;
325 }
326 flags >>= 1;
327 } // for
328
329 *cp = '\0';
330 return str;
331 }
332
333 /*
334 * Copies character data from "data" to "out", converting non-ASCII values
335 * to fprintf format chars or an ASCII filler ('.' or '?').
336 *
337 * The output buffer must be able to hold (2*len)+1 bytes. The result is
338 * NULL-terminated.
339 */
asciify(char * out,const unsigned char * data,size_t len)340 static void asciify(char* out, const unsigned char* data, size_t len) {
341 for (; len != 0u; --len) {
342 if (*data < 0x20) {
343 // Could do more here, but we don't need them yet.
344 switch (*data) {
345 case '\0':
346 *out++ = '\\';
347 *out++ = '0';
348 break;
349 case '\n':
350 *out++ = '\\';
351 *out++ = 'n';
352 break;
353 default:
354 *out++ = '.';
355 break;
356 } // switch
357 } else if (*data >= 0x80) {
358 *out++ = '?';
359 } else {
360 *out++ = *data;
361 }
362 data++;
363 } // while
364 *out = '\0';
365 }
366
367 /* clang-format off */
368 constexpr char kEscapedLength[256] = {
369 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 4, 2, 2, 4, 4, // \a, \b, \t, \n, \r
370 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
371 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // ",
372 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // '0'..'9'
373 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 'A'..'O'
374 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, // 'P'..'Z', '\'
375 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 'a'..'o'
376 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, // 'p'..'z', DEL
377 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // Unicode range, keep
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 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
383 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
384 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
385 };
386 /* clang-format on */
387
388 /*
389 * Check if a UTF8 string contains characters we should quote.
390 */
needsEscape(std::string_view s)391 static bool needsEscape(std::string_view s) {
392 for (unsigned char c : s) {
393 if (kEscapedLength[c] != 1) {
394 return true;
395 }
396 }
397 return false;
398 }
399
escapeString(std::string_view s)400 std::string escapeString(std::string_view s) {
401 std::ostringstream oss;
402 for (unsigned char c : s) {
403 switch (kEscapedLength[c]) {
404 case 1:
405 oss << static_cast<char>(c);
406 break;
407 case 2:
408 switch (c) {
409 case '\b':
410 oss << '\\' << 'b';
411 break;
412 case '\f':
413 oss << '\\' << 'f';
414 break;
415 case '\n':
416 oss << '\\' << 'n';
417 break;
418 case '\r':
419 oss << '\\' << 'r';
420 break;
421 case '\t':
422 oss << '\\' << 't';
423 break;
424 case '\"':
425 oss << '\\' << '"';
426 break;
427 case '\\':
428 oss << '\\' << '\\';
429 break;
430 }
431 break;
432 case 4:
433 oss << '\\' << '0' + (c / 64) << '0' + ((c % 64) / 8) << '0' + (c % 8);
434 break;
435 }
436 }
437 return oss.str();
438 }
439
440 /*
441 * Dumps a string value with some escape characters.
442 */
dumpEscapedString(std::string_view s)443 static void dumpEscapedString(std::string_view s) {
444 fputs("\"", gOutFile);
445 if (needsEscape(s)) {
446 std::string e = escapeString(s);
447 fputs(e.c_str(), gOutFile);
448 } else {
449 for (char c : s) {
450 fputc(c, gOutFile);
451 }
452 }
453 fputs("\"", gOutFile);
454 }
455
utf8Bytes(char start_byte)456 static size_t utf8Bytes(char start_byte) {
457 uint8_t sb = static_cast<uint8_t>(start_byte);
458 if ((sb & 0x80) == 0) {
459 return 1;
460 }
461 size_t msb = art::MostSignificantBit(static_cast<uint8_t>(~sb));
462 CHECK_LE(7u - msb, 4u);
463 return 7 - msb;
464 }
465
466 /*
467 * Dumps a string as an XML attribute value.
468 */
dumpXmlAttribute(std::string_view p)469 static void dumpXmlAttribute(std::string_view p) __attribute__((optnone)) {
470 for (const char* c = p.begin(); c < p.end(); ++c) {
471 if (std::isprint(*c)) {
472 switch (*c) {
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 case '\\':
486 fputs("\\\\", gOutFile);
487 break;
488 default:
489 putc(*c, gOutFile);
490 } // switch
491 } else {
492 uint32_t data = 0;
493 size_t remaining;
494 uint8_t uc = static_cast<uint8_t>(*c);
495 if (((uc) & 0x80) == 0) {
496 // Not a multi-byte char
497 data = static_cast<uint32_t>(*c);
498 remaining = 0;
499 } else if (utf8Bytes(uc) == 2) {
500 // 2 bytes
501 data = ((uc) & 0b00011111);
502 remaining = 1;
503 } else if (utf8Bytes(uc) == 3) {
504 // 3 bytes
505 data = ((uc) & 0b00001111);
506 remaining = 2;
507 } else {
508 // 4 bytes
509 CHECK_EQ(utf8Bytes(uc), 4u);
510 data = ((uc) & 0b00000111);
511 remaining = 3;
512 }
513 for (size_t i = 0; i < remaining; ++i) {
514 ++c;
515 data = data << 6;
516 uc = static_cast<uint8_t>(*c);
517 data |= static_cast<uint32_t>(uc & 0b00111111u);
518 }
519 // No good option so just use java encoding, too many chars are invalid
520 fprintf(gOutFile, "\\u%04x", data);
521 }
522 } // for
523 }
524
525 /*
526 * Reads variable width value, possibly sign extended at the last defined byte.
527 */
readVarWidth(const u1 ** data,u1 arg,bool sign_extend)528 static u8 readVarWidth(const u1** data, u1 arg, bool sign_extend) {
529 u8 value = 0;
530 for (u4 i = 0; i <= arg; i++) {
531 value |= static_cast<u8>(*(*data)++) << (i * 8);
532 }
533 if (sign_extend) {
534 int shift = (7 - arg) * 8;
535 return (static_cast<s8>(value) << shift) >> shift;
536 }
537 return value;
538 }
539
540 /*
541 * Dumps encoded value.
542 */
543 static void dumpEncodedValue(const DexFile* pDexFile, const u1** data); // forward
dumpEncodedValue(const DexFile * pDexFile,const u1 ** data,u1 type,u1 arg)544 static void dumpEncodedValue(const DexFile* pDexFile, const u1** data, u1 type, u1 arg) {
545 switch (type) {
546 case DexFile::kDexAnnotationByte:
547 fprintf(gOutFile, "%" PRId8, static_cast<s1>(readVarWidth(data, arg, false)));
548 break;
549 case DexFile::kDexAnnotationShort:
550 fprintf(gOutFile, "%" PRId16, static_cast<s2>(readVarWidth(data, arg, true)));
551 break;
552 case DexFile::kDexAnnotationChar:
553 fprintf(gOutFile, "%" PRIu16, static_cast<u2>(readVarWidth(data, arg, false)));
554 break;
555 case DexFile::kDexAnnotationInt:
556 fprintf(gOutFile, "%" PRId32, static_cast<s4>(readVarWidth(data, arg, true)));
557 break;
558 case DexFile::kDexAnnotationLong:
559 fprintf(gOutFile, "%" PRId64, static_cast<s8>(readVarWidth(data, arg, true)));
560 break;
561 case DexFile::kDexAnnotationFloat: {
562 // Fill on right.
563 union {
564 float f;
565 u4 data;
566 } conv;
567 conv.data = static_cast<u4>(readVarWidth(data, arg, false)) << (3 - arg) * 8;
568 fprintf(gOutFile, "%g", conv.f);
569 break;
570 }
571 case DexFile::kDexAnnotationDouble: {
572 // Fill on right.
573 union {
574 double d;
575 u8 data;
576 } conv;
577 conv.data = readVarWidth(data, arg, false) << (7 - arg) * 8;
578 fprintf(gOutFile, "%g", conv.d);
579 break;
580 }
581 case DexFile::kDexAnnotationMethodType: {
582 const u4 proto_idx = static_cast<u4>(readVarWidth(data, arg, false));
583 const dex::ProtoId& pProtoId = pDexFile->GetProtoId(dex::ProtoIndex(proto_idx));
584 fputs(pDexFile->GetProtoSignature(pProtoId).ToString().c_str(), gOutFile);
585 break;
586 }
587 case DexFile::kDexAnnotationMethodHandle: {
588 const u4 method_handle_idx = static_cast<u4>(readVarWidth(data, arg, false));
589 fprintf(gOutFile, "method_handle@%u", method_handle_idx);
590 break;
591 }
592 case DexFile::kDexAnnotationString: {
593 const u4 idx = static_cast<u4>(readVarWidth(data, arg, false));
594 if (gOptions.outputFormat == OUTPUT_PLAIN) {
595 dumpEscapedString(pDexFile->GetStringView(dex::StringIndex(idx)));
596 } else {
597 dumpXmlAttribute(pDexFile->GetStringView(dex::StringIndex(idx)));
598 }
599 break;
600 }
601 case DexFile::kDexAnnotationType: {
602 const u4 str_idx = static_cast<u4>(readVarWidth(data, arg, false));
603 fputs(pDexFile->GetTypeDescriptor(dex::TypeIndex(str_idx)), gOutFile);
604 break;
605 }
606 case DexFile::kDexAnnotationField:
607 case DexFile::kDexAnnotationEnum: {
608 const u4 field_idx = static_cast<u4>(readVarWidth(data, arg, false));
609 const dex::FieldId& pFieldId = pDexFile->GetFieldId(field_idx);
610 fputs(pDexFile->GetStringData(pFieldId.name_idx_), gOutFile);
611 break;
612 }
613 case DexFile::kDexAnnotationMethod: {
614 const u4 method_idx = static_cast<u4>(readVarWidth(data, arg, false));
615 const dex::MethodId& pMethodId = pDexFile->GetMethodId(method_idx);
616 fputs(pDexFile->GetStringData(pMethodId.name_idx_), gOutFile);
617 break;
618 }
619 case DexFile::kDexAnnotationArray: {
620 fputc('{', gOutFile);
621 // Decode and display all elements.
622 const u4 size = DecodeUnsignedLeb128(data);
623 for (u4 i = 0; i < size; i++) {
624 fputc(' ', gOutFile);
625 dumpEncodedValue(pDexFile, data);
626 }
627 fputs(" }", gOutFile);
628 break;
629 }
630 case DexFile::kDexAnnotationAnnotation: {
631 const u4 type_idx = DecodeUnsignedLeb128(data);
632 fputs(pDexFile->GetTypeDescriptor(dex::TypeIndex(type_idx)), gOutFile);
633 // Decode and display all name=value pairs.
634 const u4 size = DecodeUnsignedLeb128(data);
635 for (u4 i = 0; i < size; i++) {
636 const u4 name_idx = DecodeUnsignedLeb128(data);
637 fputc(' ', gOutFile);
638 fputs(pDexFile->GetStringData(dex::StringIndex(name_idx)), gOutFile);
639 fputc('=', gOutFile);
640 dumpEncodedValue(pDexFile, data);
641 }
642 break;
643 }
644 case DexFile::kDexAnnotationNull:
645 fputs("null", gOutFile);
646 break;
647 case DexFile::kDexAnnotationBoolean:
648 fputs(strBool(arg), gOutFile);
649 break;
650 default:
651 fputs("????", gOutFile);
652 break;
653 } // switch
654 }
655
656 /*
657 * Dumps encoded value with prefix.
658 */
dumpEncodedValue(const DexFile * pDexFile,const u1 ** data)659 static void dumpEncodedValue(const DexFile* pDexFile, const u1** data) {
660 const u1 enc = *(*data)++;
661 dumpEncodedValue(pDexFile, data, enc & 0x1f, enc >> 5);
662 }
663
664 /*
665 * Dumps the file header.
666 */
dumpFileHeader(const DexFile * pDexFile)667 static void dumpFileHeader(const DexFile* pDexFile) {
668 const DexFile::Header& pHeader = pDexFile->GetHeader();
669 char sanitized[sizeof(pHeader.magic_) * 2 + 1];
670 fprintf(gOutFile, "DEX file header:\n");
671 asciify(sanitized, pHeader.magic_.data(), pHeader.magic_.size());
672 fprintf(gOutFile, "magic : '%s'\n", sanitized);
673 fprintf(gOutFile, "checksum : %08x\n", pHeader.checksum_);
674 fprintf(gOutFile, "signature : %02x%02x...%02x%02x\n",
675 pHeader.signature_[0], pHeader.signature_[1],
676 pHeader.signature_[DexFile::kSha1DigestSize - 2],
677 pHeader.signature_[DexFile::kSha1DigestSize - 1]);
678 fprintf(gOutFile, "file_size : %d\n", pHeader.file_size_);
679 fprintf(gOutFile, "header_size : %d\n", pHeader.header_size_);
680 fprintf(gOutFile, "link_size : %d\n", pHeader.link_size_);
681 fprintf(gOutFile, "link_off : %d (0x%06x)\n",
682 pHeader.link_off_, pHeader.link_off_);
683 fprintf(gOutFile, "string_ids_size : %d\n", pHeader.string_ids_size_);
684 fprintf(gOutFile, "string_ids_off : %d (0x%06x)\n",
685 pHeader.string_ids_off_, pHeader.string_ids_off_);
686 fprintf(gOutFile, "type_ids_size : %d\n", pHeader.type_ids_size_);
687 fprintf(gOutFile, "type_ids_off : %d (0x%06x)\n",
688 pHeader.type_ids_off_, pHeader.type_ids_off_);
689 fprintf(gOutFile, "proto_ids_size : %d\n", pHeader.proto_ids_size_);
690 fprintf(gOutFile, "proto_ids_off : %d (0x%06x)\n",
691 pHeader.proto_ids_off_, pHeader.proto_ids_off_);
692 fprintf(gOutFile, "field_ids_size : %d\n", pHeader.field_ids_size_);
693 fprintf(gOutFile, "field_ids_off : %d (0x%06x)\n",
694 pHeader.field_ids_off_, pHeader.field_ids_off_);
695 fprintf(gOutFile, "method_ids_size : %d\n", pHeader.method_ids_size_);
696 fprintf(gOutFile, "method_ids_off : %d (0x%06x)\n",
697 pHeader.method_ids_off_, pHeader.method_ids_off_);
698 fprintf(gOutFile, "class_defs_size : %d\n", pHeader.class_defs_size_);
699 fprintf(gOutFile, "class_defs_off : %d (0x%06x)\n",
700 pHeader.class_defs_off_, pHeader.class_defs_off_);
701 fprintf(gOutFile, "data_size : %d\n", pHeader.data_size_);
702 fprintf(gOutFile, "data_off : %d (0x%06x)\n\n",
703 pHeader.data_off_, pHeader.data_off_);
704 }
705
706 /*
707 * Dumps a class_def_item.
708 */
dumpClassDef(const DexFile * pDexFile,int idx)709 static void dumpClassDef(const DexFile* pDexFile, int idx) {
710 // General class information.
711 const dex::ClassDef& pClassDef = pDexFile->GetClassDef(idx);
712 fprintf(gOutFile, "Class #%d header:\n", idx);
713 fprintf(gOutFile, "class_idx : %d\n", pClassDef.class_idx_.index_);
714 fprintf(gOutFile, "access_flags : %d (0x%04x)\n",
715 pClassDef.access_flags_, pClassDef.access_flags_);
716 fprintf(gOutFile, "superclass_idx : %d\n", pClassDef.superclass_idx_.index_);
717 fprintf(gOutFile, "interfaces_off : %d (0x%06x)\n",
718 pClassDef.interfaces_off_, pClassDef.interfaces_off_);
719 fprintf(gOutFile, "source_file_idx : %d\n", pClassDef.source_file_idx_.index_);
720 fprintf(gOutFile, "annotations_off : %d (0x%06x)\n",
721 pClassDef.annotations_off_, pClassDef.annotations_off_);
722 fprintf(gOutFile, "class_data_off : %d (0x%06x)\n",
723 pClassDef.class_data_off_, pClassDef.class_data_off_);
724
725 // Fields and methods.
726 ClassAccessor accessor(*pDexFile, idx);
727 fprintf(gOutFile, "static_fields_size : %d\n", accessor.NumStaticFields());
728 fprintf(gOutFile, "instance_fields_size: %d\n", accessor.NumInstanceFields());
729 fprintf(gOutFile, "direct_methods_size : %d\n", accessor.NumDirectMethods());
730 fprintf(gOutFile, "virtual_methods_size: %d\n", accessor.NumVirtualMethods());
731 fprintf(gOutFile, "\n");
732 }
733
734 /**
735 * Dumps an annotation set item.
736 */
dumpAnnotationSetItem(const DexFile * pDexFile,const dex::AnnotationSetItem * set_item)737 static void dumpAnnotationSetItem(const DexFile* pDexFile, const dex::AnnotationSetItem* set_item) {
738 if (set_item == nullptr || set_item->size_ == 0) {
739 fputs(" empty-annotation-set\n", gOutFile);
740 return;
741 }
742 for (u4 i = 0; i < set_item->size_; i++) {
743 const dex::AnnotationItem* annotation = pDexFile->GetAnnotationItem(set_item, i);
744 if (annotation == nullptr) {
745 continue;
746 }
747 fputs(" ", gOutFile);
748 switch (annotation->visibility_) {
749 case DexFile::kDexVisibilityBuild: fputs("VISIBILITY_BUILD ", gOutFile); break;
750 case DexFile::kDexVisibilityRuntime: fputs("VISIBILITY_RUNTIME ", gOutFile); break;
751 case DexFile::kDexVisibilitySystem: fputs("VISIBILITY_SYSTEM ", gOutFile); break;
752 default: fputs("VISIBILITY_UNKNOWN ", gOutFile); break;
753 } // switch
754 // Decode raw bytes in annotation.
755 const u1* rData = annotation->annotation_;
756 dumpEncodedValue(pDexFile, &rData, DexFile::kDexAnnotationAnnotation, 0);
757 fputc('\n', gOutFile);
758 }
759 }
760
761 /*
762 * Dumps class annotations.
763 */
dumpClassAnnotations(const DexFile * pDexFile,int idx)764 static void dumpClassAnnotations(const DexFile* pDexFile, int idx) {
765 const dex::ClassDef& pClassDef = pDexFile->GetClassDef(idx);
766 const dex::AnnotationsDirectoryItem* dir = pDexFile->GetAnnotationsDirectory(pClassDef);
767 if (dir == nullptr) {
768 return; // none
769 }
770
771 fprintf(gOutFile, "Class #%d annotations:\n", idx);
772
773 const dex::AnnotationSetItem* class_set_item = pDexFile->GetClassAnnotationSet(dir);
774 const dex::FieldAnnotationsItem* fields = pDexFile->GetFieldAnnotations(dir);
775 const dex::MethodAnnotationsItem* methods = pDexFile->GetMethodAnnotations(dir);
776 const dex::ParameterAnnotationsItem* pars = pDexFile->GetParameterAnnotations(dir);
777
778 // Annotations on the class itself.
779 if (class_set_item != nullptr) {
780 fprintf(gOutFile, "Annotations on class\n");
781 dumpAnnotationSetItem(pDexFile, class_set_item);
782 }
783
784 // Annotations on fields.
785 if (fields != nullptr) {
786 for (u4 i = 0; i < dir->fields_size_; i++) {
787 const u4 field_idx = fields[i].field_idx_;
788 const dex::FieldId& pFieldId = pDexFile->GetFieldId(field_idx);
789 const char* field_name = pDexFile->GetStringData(pFieldId.name_idx_);
790 fprintf(gOutFile, "Annotations on field #%u '%s'\n", field_idx, field_name);
791 dumpAnnotationSetItem(pDexFile, pDexFile->GetFieldAnnotationSetItem(fields[i]));
792 }
793 }
794
795 // Annotations on methods.
796 if (methods != nullptr) {
797 for (u4 i = 0; i < dir->methods_size_; i++) {
798 const u4 method_idx = methods[i].method_idx_;
799 const dex::MethodId& pMethodId = pDexFile->GetMethodId(method_idx);
800 const char* method_name = pDexFile->GetStringData(pMethodId.name_idx_);
801 fprintf(gOutFile, "Annotations on method #%u '%s'\n", method_idx, method_name);
802 dumpAnnotationSetItem(pDexFile, pDexFile->GetMethodAnnotationSetItem(methods[i]));
803 }
804 }
805
806 // Annotations on method parameters.
807 if (pars != nullptr) {
808 for (u4 i = 0; i < dir->parameters_size_; i++) {
809 const u4 method_idx = pars[i].method_idx_;
810 const dex::MethodId& pMethodId = pDexFile->GetMethodId(method_idx);
811 const char* method_name = pDexFile->GetStringData(pMethodId.name_idx_);
812 fprintf(gOutFile, "Annotations on method #%u '%s' parameters\n", method_idx, method_name);
813 const dex::AnnotationSetRefList*
814 list = pDexFile->GetParameterAnnotationSetRefList(&pars[i]);
815 if (list != nullptr) {
816 for (u4 j = 0; j < list->size_; j++) {
817 fprintf(gOutFile, "#%u\n", j);
818 dumpAnnotationSetItem(pDexFile, pDexFile->GetSetRefItemItem(&list->list_[j]));
819 }
820 }
821 }
822 }
823
824 fputc('\n', gOutFile);
825 }
826
827 /*
828 * Dumps an interface that a class declares to implement.
829 */
dumpInterface(const DexFile * pDexFile,const dex::TypeItem & pTypeItem,int i)830 static void dumpInterface(const DexFile* pDexFile, const dex::TypeItem& pTypeItem, int i) {
831 const char* interfaceName = pDexFile->GetTypeDescriptor(pTypeItem.type_idx_);
832 if (gOptions.outputFormat == OUTPUT_PLAIN) {
833 fprintf(gOutFile, " #%d : '%s'\n", i, interfaceName);
834 } else {
835 std::unique_ptr<char[]> dot(descriptorToDot(interfaceName));
836 fprintf(gOutFile, "<implements name=\"%s\">\n</implements>\n", dot.get());
837 }
838 }
839
840 /*
841 * Dumps the catches table associated with the code.
842 */
dumpCatches(const DexFile * pDexFile,const dex::CodeItem * pCode)843 static void dumpCatches(const DexFile* pDexFile, const dex::CodeItem* pCode) {
844 CodeItemDataAccessor accessor(*pDexFile, pCode);
845 const u4 triesSize = accessor.TriesSize();
846
847 // No catch table.
848 if (triesSize == 0) {
849 fprintf(gOutFile, " catches : (none)\n");
850 return;
851 }
852
853 // Dump all table entries.
854 fprintf(gOutFile, " catches : %d\n", triesSize);
855 for (const dex::TryItem& try_item : accessor.TryItems()) {
856 const u4 start = try_item.start_addr_;
857 const u4 end = start + try_item.insn_count_;
858 fprintf(gOutFile, " 0x%04x - 0x%04x\n", start, end);
859 for (CatchHandlerIterator it(accessor, try_item); it.HasNext(); it.Next()) {
860 const dex::TypeIndex tidx = it.GetHandlerTypeIndex();
861 const char* descriptor = (!tidx.IsValid()) ? "<any>" : pDexFile->GetTypeDescriptor(tidx);
862 fprintf(gOutFile, " %s -> 0x%04x\n", descriptor, it.GetHandlerAddress());
863 } // for
864 } // for
865 }
866
867 /*
868 * Helper for dumpInstruction(), which builds the string
869 * representation for the index in the given instruction.
870 * Returns a pointer to a buffer of sufficient size.
871 */
indexString(const DexFile * pDexFile,const Instruction * pDecInsn,size_t bufSize)872 static std::unique_ptr<char[]> indexString(const DexFile* pDexFile,
873 const Instruction* pDecInsn,
874 size_t bufSize) {
875 std::unique_ptr<char[]> buf(new char[bufSize]);
876 // Determine index and width of the string.
877 u4 index = 0;
878 u2 secondary_index = 0;
879 u4 width = 4;
880 switch (Instruction::FormatOf(pDecInsn->Opcode())) {
881 // SOME NOT SUPPORTED:
882 // case Instruction::k20bc:
883 case Instruction::k21c:
884 case Instruction::k35c:
885 // case Instruction::k35ms:
886 case Instruction::k3rc:
887 // case Instruction::k3rms:
888 // case Instruction::k35mi:
889 // case Instruction::k3rmi:
890 index = pDecInsn->VRegB();
891 width = 4;
892 break;
893 case Instruction::k31c:
894 index = pDecInsn->VRegB();
895 width = 8;
896 break;
897 case Instruction::k22c:
898 // case Instruction::k22cs:
899 index = pDecInsn->VRegC();
900 width = 4;
901 break;
902 case Instruction::k45cc:
903 case Instruction::k4rcc:
904 index = pDecInsn->VRegB();
905 secondary_index = pDecInsn->VRegH();
906 width = 4;
907 break;
908 default:
909 break;
910 } // switch
911
912 // Determine index type.
913 size_t outSize = 0;
914 switch (Instruction::IndexTypeOf(pDecInsn->Opcode())) {
915 case Instruction::kIndexUnknown:
916 // This function should never get called for this type, but do
917 // something sensible here, just to help with debugging.
918 outSize = snprintf(buf.get(), bufSize, "<unknown-index>");
919 break;
920 case Instruction::kIndexNone:
921 // This function should never get called for this type, but do
922 // something sensible here, just to help with debugging.
923 outSize = snprintf(buf.get(), bufSize, "<no-index>");
924 break;
925 case Instruction::kIndexTypeRef:
926 if (index < pDexFile->GetHeader().type_ids_size_) {
927 const char* tp = pDexFile->GetTypeDescriptor(dex::TypeIndex(index));
928 outSize = snprintf(buf.get(), bufSize, "%s // type@%0*x", tp, width, index);
929 } else {
930 outSize = snprintf(buf.get(), bufSize, "<type?> // type@%0*x", width, index);
931 }
932 break;
933 case Instruction::kIndexStringRef:
934 if (index < pDexFile->GetHeader().string_ids_size_) {
935 const char* st = pDexFile->GetStringData(dex::StringIndex(index));
936 if (needsEscape(std::string_view(st))) {
937 std::string escaped = escapeString(st);
938 outSize =
939 snprintf(buf.get(), bufSize, "\"%s\" // string@%0*x", escaped.c_str(), width, index);
940 } else {
941 outSize = snprintf(buf.get(), bufSize, "\"%s\" // string@%0*x", st, width, index);
942 }
943 } else {
944 outSize = snprintf(buf.get(), bufSize, "<string?> // string@%0*x", width, index);
945 }
946 break;
947 case Instruction::kIndexMethodRef:
948 if (index < pDexFile->GetHeader().method_ids_size_) {
949 const dex::MethodId& pMethodId = pDexFile->GetMethodId(index);
950 const char* name = pDexFile->GetStringData(pMethodId.name_idx_);
951 const Signature signature = pDexFile->GetMethodSignature(pMethodId);
952 const char* backDescriptor = pDexFile->GetTypeDescriptor(pMethodId.class_idx_);
953 outSize = snprintf(buf.get(), bufSize, "%s.%s:%s // method@%0*x",
954 backDescriptor, name, signature.ToString().c_str(), width, index);
955 } else {
956 outSize = snprintf(buf.get(), bufSize, "<method?> // method@%0*x", width, index);
957 }
958 break;
959 case Instruction::kIndexFieldRef:
960 if (index < pDexFile->GetHeader().field_ids_size_) {
961 const dex::FieldId& pFieldId = pDexFile->GetFieldId(index);
962 const char* name = pDexFile->GetStringData(pFieldId.name_idx_);
963 const char* typeDescriptor = pDexFile->GetTypeDescriptor(pFieldId.type_idx_);
964 const char* backDescriptor = pDexFile->GetTypeDescriptor(pFieldId.class_idx_);
965 outSize = snprintf(buf.get(), bufSize, "%s.%s:%s // field@%0*x",
966 backDescriptor, name, typeDescriptor, width, index);
967 } else {
968 outSize = snprintf(buf.get(), bufSize, "<field?> // field@%0*x", width, index);
969 }
970 break;
971 case Instruction::kIndexMethodAndProtoRef: {
972 std::string method("<method?>");
973 std::string proto("<proto?>");
974 if (index < pDexFile->GetHeader().method_ids_size_) {
975 const dex::MethodId& pMethodId = pDexFile->GetMethodId(index);
976 const char* name = pDexFile->GetStringData(pMethodId.name_idx_);
977 const Signature signature = pDexFile->GetMethodSignature(pMethodId);
978 const char* backDescriptor = pDexFile->GetTypeDescriptor(pMethodId.class_idx_);
979 method = android::base::StringPrintf("%s.%s:%s",
980 backDescriptor,
981 name,
982 signature.ToString().c_str());
983 }
984 if (secondary_index < pDexFile->GetHeader().proto_ids_size_) {
985 const dex::ProtoId& protoId = pDexFile->GetProtoId(dex::ProtoIndex(secondary_index));
986 const Signature signature = pDexFile->GetProtoSignature(protoId);
987 proto = signature.ToString();
988 }
989 outSize = snprintf(buf.get(), bufSize, "%s, %s // method@%0*x, proto@%0*x",
990 method.c_str(), proto.c_str(), width, index, width, secondary_index);
991 break;
992 }
993 case Instruction::kIndexCallSiteRef:
994 // Call site information is too large to detail in disassembly so just output the index.
995 outSize = snprintf(buf.get(), bufSize, "call_site@%0*x", width, index);
996 break;
997 case Instruction::kIndexMethodHandleRef:
998 // Method handle information is too large to detail in disassembly so just output the index.
999 outSize = snprintf(buf.get(), bufSize, "method_handle@%0*x", width, index);
1000 break;
1001 case Instruction::kIndexProtoRef:
1002 if (index < pDexFile->GetHeader().proto_ids_size_) {
1003 const dex::ProtoId& protoId = pDexFile->GetProtoId(dex::ProtoIndex(index));
1004 const Signature signature = pDexFile->GetProtoSignature(protoId);
1005 const std::string& proto = signature.ToString();
1006 outSize = snprintf(buf.get(), bufSize, "%s // proto@%0*x", proto.c_str(), width, index);
1007 } else {
1008 outSize = snprintf(buf.get(), bufSize, "<?> // proto@%0*x", width, index);
1009 }
1010 break;
1011 } // switch
1012
1013 if (outSize == 0) {
1014 // The index type has not been handled in the switch above.
1015 outSize = snprintf(buf.get(), bufSize, "<?>");
1016 }
1017
1018 // Determine success of string construction.
1019 if (outSize >= bufSize) {
1020 // The buffer wasn't big enough; retry with computed size. Note: snprintf()
1021 // doesn't count/ the '\0' as part of its returned size, so we add explicit
1022 // space for it here.
1023 return indexString(pDexFile, pDecInsn, outSize + 1);
1024 }
1025 return buf;
1026 }
1027
1028 /*
1029 * Dumps a single instruction.
1030 */
dumpInstruction(const DexFile * pDexFile,const dex::CodeItem * pCode,u4 codeOffset,u4 insnIdx,u4 insnWidth,const Instruction * pDecInsn)1031 static void dumpInstruction(const DexFile* pDexFile,
1032 const dex::CodeItem* pCode,
1033 u4 codeOffset, u4 insnIdx, u4 insnWidth,
1034 const Instruction* pDecInsn) {
1035 // Address of instruction (expressed as byte offset).
1036 fprintf(gOutFile, "%06x:", codeOffset + 0x10 + insnIdx * 2);
1037
1038 // Dump (part of) raw bytes.
1039 CodeItemInstructionAccessor accessor(*pDexFile, pCode);
1040 for (u4 i = 0; i < 8; i++) {
1041 if (i < insnWidth) {
1042 if (i == 7) {
1043 fprintf(gOutFile, " ... ");
1044 } else {
1045 // Print 16-bit value in little-endian order.
1046 const u1* bytePtr = (const u1*) &accessor.Insns()[insnIdx + i];
1047 fprintf(gOutFile, " %02x%02x", bytePtr[0], bytePtr[1]);
1048 }
1049 } else {
1050 fputs(" ", gOutFile);
1051 }
1052 } // for
1053
1054 // Dump pseudo-instruction or opcode.
1055 if (pDecInsn->Opcode() == Instruction::NOP) {
1056 const u2 instr = get2LE((const u1*) &accessor.Insns()[insnIdx]);
1057 if (instr == Instruction::kPackedSwitchSignature) {
1058 fprintf(gOutFile, "|%04x: packed-switch-data (%d units)", insnIdx, insnWidth);
1059 } else if (instr == Instruction::kSparseSwitchSignature) {
1060 fprintf(gOutFile, "|%04x: sparse-switch-data (%d units)", insnIdx, insnWidth);
1061 } else if (instr == Instruction::kArrayDataSignature) {
1062 fprintf(gOutFile, "|%04x: array-data (%d units)", insnIdx, insnWidth);
1063 } else {
1064 fprintf(gOutFile, "|%04x: nop // spacer", insnIdx);
1065 }
1066 } else {
1067 fprintf(gOutFile, "|%04x: %s", insnIdx, pDecInsn->Name());
1068 }
1069
1070 // Set up additional argument.
1071 std::unique_ptr<char[]> indexBuf;
1072 if (Instruction::IndexTypeOf(pDecInsn->Opcode()) != Instruction::kIndexNone) {
1073 indexBuf = indexString(pDexFile, pDecInsn, 200);
1074 }
1075
1076 // Dump the instruction.
1077 //
1078 // NOTE: pDecInsn->DumpString(pDexFile) differs too much from original.
1079 //
1080 switch (Instruction::FormatOf(pDecInsn->Opcode())) {
1081 case Instruction::k10x: // op
1082 break;
1083 case Instruction::k12x: // op vA, vB
1084 fprintf(gOutFile, " v%d, v%d", pDecInsn->VRegA(), pDecInsn->VRegB());
1085 break;
1086 case Instruction::k11n: // op vA, #+B
1087 fprintf(gOutFile, " v%d, #int %d // #%x",
1088 pDecInsn->VRegA(), (s4) pDecInsn->VRegB(), (u1)pDecInsn->VRegB());
1089 break;
1090 case Instruction::k11x: // op vAA
1091 fprintf(gOutFile, " v%d", pDecInsn->VRegA());
1092 break;
1093 case Instruction::k10t: // op +AA
1094 case Instruction::k20t: { // op +AAAA
1095 const s4 targ = (s4) pDecInsn->VRegA();
1096 fprintf(gOutFile, " %04x // %c%04x",
1097 insnIdx + targ,
1098 (targ < 0) ? '-' : '+',
1099 (targ < 0) ? -targ : targ);
1100 break;
1101 }
1102 case Instruction::k22x: // op vAA, vBBBB
1103 fprintf(gOutFile, " v%d, v%d", pDecInsn->VRegA(), pDecInsn->VRegB());
1104 break;
1105 case Instruction::k21t: { // op vAA, +BBBB
1106 const s4 targ = (s4) pDecInsn->VRegB();
1107 fprintf(gOutFile, " v%d, %04x // %c%04x", pDecInsn->VRegA(),
1108 insnIdx + targ,
1109 (targ < 0) ? '-' : '+',
1110 (targ < 0) ? -targ : targ);
1111 break;
1112 }
1113 case Instruction::k21s: // op vAA, #+BBBB
1114 fprintf(gOutFile, " v%d, #int %d // #%x",
1115 pDecInsn->VRegA(), (s4) pDecInsn->VRegB(), (u2)pDecInsn->VRegB());
1116 break;
1117 case Instruction::k21h: // op vAA, #+BBBB0000[00000000]
1118 // The printed format varies a bit based on the actual opcode.
1119 if (pDecInsn->Opcode() == Instruction::CONST_HIGH16) {
1120 const s4 value = pDecInsn->VRegB() << 16;
1121 fprintf(gOutFile, " v%d, #int %d // #%x",
1122 pDecInsn->VRegA(), value, (u2) pDecInsn->VRegB());
1123 } else {
1124 const s8 value = ((s8) pDecInsn->VRegB()) << 48;
1125 fprintf(gOutFile, " v%d, #long %" PRId64 " // #%x",
1126 pDecInsn->VRegA(), value, (u2) pDecInsn->VRegB());
1127 }
1128 break;
1129 case Instruction::k21c: // op vAA, thing@BBBB
1130 case Instruction::k31c: // op vAA, thing@BBBBBBBB
1131 fprintf(gOutFile, " v%d, %s", pDecInsn->VRegA(), indexBuf.get());
1132 break;
1133 case Instruction::k23x: // op vAA, vBB, vCC
1134 fprintf(gOutFile, " v%d, v%d, v%d",
1135 pDecInsn->VRegA(), pDecInsn->VRegB(), pDecInsn->VRegC());
1136 break;
1137 case Instruction::k22b: // op vAA, vBB, #+CC
1138 fprintf(gOutFile, " v%d, v%d, #int %d // #%02x",
1139 pDecInsn->VRegA(), pDecInsn->VRegB(),
1140 (s4) pDecInsn->VRegC(), (u1) pDecInsn->VRegC());
1141 break;
1142 case Instruction::k22t: { // op vA, vB, +CCCC
1143 const s4 targ = (s4) pDecInsn->VRegC();
1144 fprintf(gOutFile, " v%d, v%d, %04x // %c%04x",
1145 pDecInsn->VRegA(), pDecInsn->VRegB(),
1146 insnIdx + targ,
1147 (targ < 0) ? '-' : '+',
1148 (targ < 0) ? -targ : targ);
1149 break;
1150 }
1151 case Instruction::k22s: // op vA, vB, #+CCCC
1152 fprintf(gOutFile, " v%d, v%d, #int %d // #%04x",
1153 pDecInsn->VRegA(), pDecInsn->VRegB(),
1154 (s4) pDecInsn->VRegC(), (u2) pDecInsn->VRegC());
1155 break;
1156 case Instruction::k22c: // op vA, vB, thing@CCCC
1157 // NOT SUPPORTED:
1158 // case Instruction::k22cs: // [opt] op vA, vB, field offset CCCC
1159 fprintf(gOutFile, " v%d, v%d, %s",
1160 pDecInsn->VRegA(), pDecInsn->VRegB(), indexBuf.get());
1161 break;
1162 case Instruction::k30t:
1163 fprintf(gOutFile, " #%08x", pDecInsn->VRegA());
1164 break;
1165 case Instruction::k31i: { // op vAA, #+BBBBBBBB
1166 // This is often, but not always, a float.
1167 union {
1168 float f;
1169 u4 i;
1170 } conv;
1171 conv.i = pDecInsn->VRegB();
1172 fprintf(gOutFile, " v%d, #float %g // #%08x",
1173 pDecInsn->VRegA(), conv.f, pDecInsn->VRegB());
1174 break;
1175 }
1176 case Instruction::k31t: // op vAA, offset +BBBBBBBB
1177 fprintf(gOutFile, " v%d, %08x // +%08x",
1178 pDecInsn->VRegA(), insnIdx + pDecInsn->VRegB(), pDecInsn->VRegB());
1179 break;
1180 case Instruction::k32x: // op vAAAA, vBBBB
1181 fprintf(gOutFile, " v%d, v%d", pDecInsn->VRegA(), pDecInsn->VRegB());
1182 break;
1183 case Instruction::k35c: // op {vC, vD, vE, vF, vG}, thing@BBBB
1184 case Instruction::k45cc: { // op {vC, vD, vE, vF, vG}, method@BBBB, proto@HHHH
1185 // NOT SUPPORTED:
1186 // case Instruction::k35ms: // [opt] invoke-virtual+super
1187 // case Instruction::k35mi: // [opt] inline invoke
1188 u4 arg[Instruction::kMaxVarArgRegs];
1189 pDecInsn->GetVarArgs(arg);
1190 fputs(" {", gOutFile);
1191 for (int i = 0, n = pDecInsn->VRegA(); i < n; i++) {
1192 if (i == 0) {
1193 fprintf(gOutFile, "v%d", arg[i]);
1194 } else {
1195 fprintf(gOutFile, ", v%d", arg[i]);
1196 }
1197 } // for
1198 fprintf(gOutFile, "}, %s", indexBuf.get());
1199 break;
1200 }
1201 case Instruction::k3rc: // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB
1202 case Instruction::k4rcc: { // op {vCCCC .. v(CCCC+AA-1)}, method@BBBB, proto@HHHH
1203 // NOT SUPPORTED:
1204 // case Instruction::k3rms: // [opt] invoke-virtual+super/range
1205 // case Instruction::k3rmi: // [opt] execute-inline/range
1206 // This doesn't match the "dx" output when some of the args are
1207 // 64-bit values -- dx only shows the first register.
1208 fputs(" {", gOutFile);
1209 for (int i = 0, n = pDecInsn->VRegA(); i < n; i++) {
1210 if (i == 0) {
1211 fprintf(gOutFile, "v%d", pDecInsn->VRegC() + i);
1212 } else {
1213 fprintf(gOutFile, ", v%d", pDecInsn->VRegC() + i);
1214 }
1215 } // for
1216 fprintf(gOutFile, "}, %s", indexBuf.get());
1217 }
1218 break;
1219 case Instruction::k51l: { // op vAA, #+BBBBBBBBBBBBBBBB
1220 // This is often, but not always, a double.
1221 union {
1222 double d;
1223 u8 j;
1224 } conv;
1225 conv.j = pDecInsn->WideVRegB();
1226 fprintf(gOutFile, " v%d, #double %g // #%016" PRIx64,
1227 pDecInsn->VRegA(), conv.d, pDecInsn->WideVRegB());
1228 break;
1229 }
1230 // NOT SUPPORTED:
1231 // case Instruction::k00x: // unknown op or breakpoint
1232 // break;
1233 default:
1234 fprintf(gOutFile, " ???");
1235 break;
1236 } // switch
1237
1238 fputc('\n', gOutFile);
1239 }
1240
1241 /*
1242 * Dumps a bytecode disassembly.
1243 */
dumpBytecodes(const DexFile * pDexFile,u4 idx,const dex::CodeItem * pCode,u4 codeOffset)1244 static void dumpBytecodes(const DexFile* pDexFile, u4 idx,
1245 const dex::CodeItem* pCode, u4 codeOffset) {
1246 const dex::MethodId& pMethodId = pDexFile->GetMethodId(idx);
1247 const char* name = pDexFile->GetStringData(pMethodId.name_idx_);
1248 const Signature signature = pDexFile->GetMethodSignature(pMethodId);
1249 const char* backDescriptor = pDexFile->GetTypeDescriptor(pMethodId.class_idx_);
1250
1251 // Generate header.
1252 std::unique_ptr<char[]> dot(descriptorToDot(backDescriptor));
1253 fprintf(gOutFile, "%06x: |[%06x] %s.%s:%s\n",
1254 codeOffset, codeOffset, dot.get(), name, signature.ToString().c_str());
1255
1256 // Iterate over all instructions.
1257 CodeItemDataAccessor accessor(*pDexFile, pCode);
1258 const u4 maxPc = accessor.InsnsSizeInCodeUnits();
1259 for (const DexInstructionPcPair& pair : accessor) {
1260 const u4 dexPc = pair.DexPc();
1261 if (dexPc >= maxPc) {
1262 LOG(WARNING) << "GLITCH: run-away instruction at idx=0x" << std::hex << dexPc;
1263 break;
1264 }
1265 const Instruction* instruction = &pair.Inst();
1266 const u4 insnWidth = instruction->SizeInCodeUnits();
1267 if (insnWidth == 0) {
1268 LOG(WARNING) << "GLITCH: zero-width instruction at idx=0x" << std::hex << dexPc;
1269 break;
1270 }
1271 dumpInstruction(pDexFile, pCode, codeOffset, dexPc, insnWidth, instruction);
1272 } // for
1273 }
1274
findLastInstructionAddress(const CodeItemDebugInfoAccessor & accessor)1275 static u4 findLastInstructionAddress(const CodeItemDebugInfoAccessor& accessor) {
1276 const u4 maxAddress = accessor.InsnsSizeInCodeUnits();
1277 u4 lastInstructionSize = 0;
1278 for (const DexInstructionPcPair& pair : accessor) {
1279 const u4 address = pair.DexPc();
1280 if (address >= maxAddress) {
1281 return 1;
1282 }
1283 lastInstructionSize = pair.Inst().SizeInCodeUnits();
1284 }
1285 return maxAddress - lastInstructionSize;
1286 }
1287
1288 /*
1289 * Dumps code of a method.
1290 */
dumpCode(const DexFile * pDexFile,u4 idx,u4 flags,const dex::CodeItem * pCode,u4 codeOffset)1291 static void dumpCode(const DexFile* pDexFile, u4 idx, u4 flags,
1292 const dex::CodeItem* pCode, u4 codeOffset) {
1293 CodeItemDebugInfoAccessor accessor(*pDexFile, pCode, idx);
1294
1295 fprintf(gOutFile, " registers : %d\n", accessor.RegistersSize());
1296 fprintf(gOutFile, " ins : %d\n", accessor.InsSize());
1297 fprintf(gOutFile, " outs : %d\n", accessor.OutsSize());
1298 fprintf(gOutFile, " insns size : %d 16-bit code units\n",
1299 accessor.InsnsSizeInCodeUnits());
1300
1301 // Bytecode disassembly, if requested.
1302 if (gOptions.disassemble) {
1303 dumpBytecodes(pDexFile, idx, pCode, codeOffset);
1304 }
1305
1306 // Try-catch blocks.
1307 dumpCatches(pDexFile, pCode);
1308
1309 if (gOptions.showDebugInfo) {
1310 const u4 lastInstructionAddress = findLastInstructionAddress(accessor);
1311 // Positions and locals table in the debug info.
1312 bool is_static = (flags & kAccStatic) != 0;
1313 fprintf(gOutFile, " positions :\n");
1314 accessor.DecodeDebugPositionInfo([&](const DexFile::PositionInfo& entry) {
1315 if (entry.address_ > lastInstructionAddress) {
1316 return true;
1317 } else {
1318 fprintf(gOutFile, " 0x%04x line=%d\n", entry.address_, entry.line_);
1319 return false;
1320 }
1321 });
1322 fprintf(gOutFile, " locals :\n");
1323 accessor.DecodeDebugLocalInfo(is_static,
1324 idx,
1325 [&](const DexFile::LocalInfo& entry) {
1326 fprintf(gOutFile,
1327 " 0x%04x - 0x%04x reg=%d %s %s",
1328 entry.start_address_,
1329 entry.end_address_,
1330 entry.reg_,
1331 entry.name_,
1332 entry.descriptor_);
1333 if (entry.signature_) {
1334 fputc(' ', gOutFile);
1335 fputs(entry.signature_, gOutFile);
1336 }
1337 fputc('\n', gOutFile);
1338 });
1339 }
1340 }
1341
GetHiddenapiFlagStr(uint32_t hiddenapi_flags)1342 static std::string GetHiddenapiFlagStr(uint32_t hiddenapi_flags) {
1343 std::stringstream ss;
1344 hiddenapi::ApiList api_list(hiddenapi_flags);
1345 api_list.Dump(ss);
1346 std::string str_api_list = ss.str();
1347 std::transform(str_api_list.begin(), str_api_list.end(), str_api_list.begin(), ::toupper);
1348 return str_api_list;
1349 }
1350
1351 /*
1352 * Dumps a method.
1353 */
dumpMethod(const ClassAccessor::Method & method,int i)1354 static void dumpMethod(const ClassAccessor::Method& method, int i) {
1355 // Bail for anything private if export only requested.
1356 const uint32_t flags = method.GetAccessFlags();
1357 if (gOptions.exportsOnly && (flags & (kAccPublic | kAccProtected)) == 0) {
1358 return;
1359 }
1360
1361 const DexFile& dex_file = method.GetDexFile();
1362 const dex::MethodId& pMethodId = dex_file.GetMethodId(method.GetIndex());
1363 const char* name = dex_file.GetStringData(pMethodId.name_idx_);
1364 const Signature signature = dex_file.GetMethodSignature(pMethodId);
1365 char* typeDescriptor = strdup(signature.ToString().c_str());
1366 const char* backDescriptor = dex_file.GetTypeDescriptor(pMethodId.class_idx_);
1367 char* accessStr = createAccessFlagStr(flags, AccessFor::kMethod);
1368 const uint32_t hiddenapiFlags = method.GetHiddenapiFlags();
1369
1370 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1371 fprintf(gOutFile, " #%d : (in %s)\n", i, backDescriptor);
1372 fprintf(gOutFile, " name : '%s'\n", name);
1373 fprintf(gOutFile, " type : '%s'\n", typeDescriptor);
1374 fprintf(gOutFile, " access : 0x%04x (%s)\n", flags, accessStr);
1375 if (gOptions.showSectionHeaders) {
1376 fprintf(gOutFile, " method_idx : %d\n", method.GetIndex());
1377 }
1378 if (hiddenapiFlags != 0u) {
1379 fprintf(gOutFile,
1380 " hiddenapi : 0x%04x (%s)\n",
1381 hiddenapiFlags,
1382 GetHiddenapiFlagStr(hiddenapiFlags).c_str());
1383 }
1384 if (method.GetCodeItem() == nullptr) {
1385 fprintf(gOutFile, " code : (none)\n");
1386 } else {
1387 fprintf(gOutFile, " code -\n");
1388 dumpCode(&dex_file,
1389 method.GetIndex(),
1390 flags,
1391 method.GetCodeItem(),
1392 method.GetCodeItemOffset());
1393 }
1394 if (gOptions.disassemble) {
1395 fputc('\n', gOutFile);
1396 }
1397 } else if (gOptions.outputFormat == OUTPUT_XML) {
1398 const bool constructor = (name[0] == '<');
1399
1400 // Method name and prototype.
1401 if (constructor) {
1402 std::unique_ptr<char[]> dot(descriptorClassToName(backDescriptor));
1403 fprintf(gOutFile, "<constructor name=\"%s\"\n", dot.get());
1404 dot = descriptorToDot(backDescriptor);
1405 fprintf(gOutFile, " type=\"%s\"\n", dot.get());
1406 } else {
1407 fprintf(gOutFile, "<method name=\"%s\"\n", name);
1408 const char* returnType = strrchr(typeDescriptor, ')');
1409 if (returnType == nullptr) {
1410 LOG(ERROR) << "bad method type descriptor '" << typeDescriptor << "'";
1411 goto bail;
1412 }
1413 std::unique_ptr<char[]> dot(descriptorToDot(returnType + 1));
1414 fprintf(gOutFile, " return=\"%s\"\n", dot.get());
1415 fprintf(gOutFile, " abstract=%s\n", quotedBool((flags & kAccAbstract) != 0));
1416 fprintf(gOutFile, " native=%s\n", quotedBool((flags & kAccNative) != 0));
1417 fprintf(gOutFile, " synchronized=%s\n", quotedBool(
1418 (flags & (kAccSynchronized | kAccDeclaredSynchronized)) != 0));
1419 }
1420
1421 // Additional method flags.
1422 fprintf(gOutFile, " static=%s\n", quotedBool((flags & kAccStatic) != 0));
1423 fprintf(gOutFile, " final=%s\n", quotedBool((flags & kAccFinal) != 0));
1424 // The "deprecated=" not knowable w/o parsing annotations.
1425 fprintf(gOutFile, " visibility=%s\n>\n", quotedVisibility(flags));
1426
1427 // Parameters.
1428 if (typeDescriptor[0] != '(') {
1429 LOG(ERROR) << "ERROR: bad descriptor '" << typeDescriptor << "'";
1430 goto bail;
1431 }
1432 char* tmpBuf = reinterpret_cast<char*>(malloc(strlen(typeDescriptor) + 1));
1433 const char* base = typeDescriptor + 1;
1434 int argNum = 0;
1435 while (*base != ')') {
1436 char* cp = tmpBuf;
1437 while (*base == '[') {
1438 *cp++ = *base++;
1439 }
1440 if (*base == 'L') {
1441 // Copy through ';'.
1442 do {
1443 *cp = *base++;
1444 } while (*cp++ != ';');
1445 } else {
1446 // Primitive char, copy it.
1447 if (strchr("ZBCSIFJD", *base) == nullptr) {
1448 LOG(ERROR) << "ERROR: bad method signature '" << base << "'";
1449 break; // while
1450 }
1451 *cp++ = *base++;
1452 }
1453 // Null terminate and display.
1454 *cp++ = '\0';
1455 std::unique_ptr<char[]> dot(descriptorToDot(tmpBuf));
1456 fprintf(gOutFile, "<parameter name=\"arg%d\" type=\"%s\">\n"
1457 "</parameter>\n", argNum++, dot.get());
1458 } // while
1459 free(tmpBuf);
1460 if (constructor) {
1461 fprintf(gOutFile, "</constructor>\n");
1462 } else {
1463 fprintf(gOutFile, "</method>\n");
1464 }
1465 }
1466
1467 bail:
1468 free(typeDescriptor);
1469 free(accessStr);
1470 }
1471
1472 /*
1473 * Dumps a static or instance (class) field.
1474 */
dumpField(const ClassAccessor::Field & field,int i,const u1 ** data=nullptr)1475 static void dumpField(const ClassAccessor::Field& field, int i, const u1** data = nullptr) {
1476 // Bail for anything private if export only requested.
1477 const uint32_t flags = field.GetAccessFlags();
1478 if (gOptions.exportsOnly && (flags & (kAccPublic | kAccProtected)) == 0) {
1479 return;
1480 }
1481
1482 const DexFile& dex_file = field.GetDexFile();
1483 const dex::FieldId& field_id = dex_file.GetFieldId(field.GetIndex());
1484 const char* name = dex_file.GetStringData(field_id.name_idx_);
1485 const char* typeDescriptor = dex_file.GetTypeDescriptor(field_id.type_idx_);
1486 const char* backDescriptor = dex_file.GetTypeDescriptor(field_id.class_idx_);
1487 char* accessStr = createAccessFlagStr(flags, AccessFor::kField);
1488 const uint32_t hiddenapiFlags = field.GetHiddenapiFlags();
1489
1490 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1491 fprintf(gOutFile, " #%d : (in %s)\n", i, backDescriptor);
1492 fprintf(gOutFile, " name : '%s'\n", name);
1493 fprintf(gOutFile, " type : '%s'\n", typeDescriptor);
1494 fprintf(gOutFile, " access : 0x%04x (%s)\n", flags, accessStr);
1495 if (hiddenapiFlags != 0u) {
1496 fprintf(gOutFile,
1497 " hiddenapi : 0x%04x (%s)\n",
1498 hiddenapiFlags,
1499 GetHiddenapiFlagStr(hiddenapiFlags).c_str());
1500 }
1501 if (data != nullptr) {
1502 fputs(" value : ", gOutFile);
1503 dumpEncodedValue(&dex_file, data);
1504 fputs("\n", gOutFile);
1505 }
1506 } else if (gOptions.outputFormat == OUTPUT_XML) {
1507 fprintf(gOutFile, "<field name=\"%s\"\n", name);
1508 std::unique_ptr<char[]> dot(descriptorToDot(typeDescriptor));
1509 fprintf(gOutFile, " type=\"%s\"\n", dot.get());
1510 fprintf(gOutFile, " transient=%s\n", quotedBool((flags & kAccTransient) != 0));
1511 fprintf(gOutFile, " volatile=%s\n", quotedBool((flags & kAccVolatile) != 0));
1512 // The "value=" is not knowable w/o parsing annotations.
1513 fprintf(gOutFile, " static=%s\n", quotedBool((flags & kAccStatic) != 0));
1514 fprintf(gOutFile, " final=%s\n", quotedBool((flags & kAccFinal) != 0));
1515 // The "deprecated=" is not knowable w/o parsing annotations.
1516 fprintf(gOutFile, " visibility=%s\n", quotedVisibility(flags));
1517 if (data != nullptr) {
1518 fputs(" value=\"", gOutFile);
1519 dumpEncodedValue(&dex_file, data);
1520 fputs("\"\n", gOutFile);
1521 }
1522 fputs(">\n</field>\n", gOutFile);
1523 }
1524
1525 free(accessStr);
1526 }
1527
1528 /*
1529 * Dumping a CFG.
1530 */
dumpCfg(const DexFile * dex_file,int idx)1531 static void dumpCfg(const DexFile* dex_file, int idx) {
1532 ClassAccessor accessor(*dex_file, dex_file->GetClassDef(idx));
1533 for (const ClassAccessor::Method& method : accessor.GetMethods()) {
1534 if (method.GetCodeItem() != nullptr) {
1535 std::ostringstream oss;
1536 DumpMethodCFG(method, oss);
1537 fputs(oss.str().c_str(), gOutFile);
1538 }
1539 }
1540 }
1541
1542 /*
1543 * Dumps the class.
1544 *
1545 * Note "idx" is a DexClassDef index, not a DexTypeId index.
1546 *
1547 * If "*pLastPackage" is nullptr or does not match the current class' package,
1548 * the value will be replaced with a newly-allocated string.
1549 */
dumpClass(const DexFile * pDexFile,int idx,char ** pLastPackage)1550 static void dumpClass(const DexFile* pDexFile, int idx, char** pLastPackage) {
1551 const dex::ClassDef& pClassDef = pDexFile->GetClassDef(idx);
1552
1553 // Omitting non-public class.
1554 if (gOptions.exportsOnly && (pClassDef.access_flags_ & kAccPublic) == 0) {
1555 return;
1556 }
1557
1558 if (gOptions.showSectionHeaders) {
1559 dumpClassDef(pDexFile, idx);
1560 }
1561
1562 if (gOptions.showAnnotations) {
1563 dumpClassAnnotations(pDexFile, idx);
1564 }
1565
1566 if (gOptions.showCfg) {
1567 dumpCfg(pDexFile, idx);
1568 return;
1569 }
1570
1571 // For the XML output, show the package name. Ideally we'd gather
1572 // up the classes, sort them, and dump them alphabetically so the
1573 // package name wouldn't jump around, but that's not a great plan
1574 // for something that needs to run on the device.
1575 const char* classDescriptor = pDexFile->GetTypeDescriptor(pClassDef.class_idx_);
1576 if (!(classDescriptor[0] == 'L' &&
1577 classDescriptor[strlen(classDescriptor)-1] == ';')) {
1578 // Arrays and primitives should not be defined explicitly. Keep going?
1579 LOG(WARNING) << "Malformed class name '" << classDescriptor << "'";
1580 } else if (gOptions.outputFormat == OUTPUT_XML) {
1581 char* mangle = strdup(classDescriptor + 1);
1582 mangle[strlen(mangle)-1] = '\0';
1583
1584 // Reduce to just the package name.
1585 char* lastSlash = strrchr(mangle, '/');
1586 if (lastSlash != nullptr) {
1587 *lastSlash = '\0';
1588 } else {
1589 *mangle = '\0';
1590 }
1591
1592 for (char* cp = mangle; *cp != '\0'; cp++) {
1593 if (*cp == '/') {
1594 *cp = '.';
1595 }
1596 } // for
1597
1598 if (*pLastPackage == nullptr || strcmp(mangle, *pLastPackage) != 0) {
1599 // Start of a new package.
1600 if (*pLastPackage != nullptr) {
1601 fprintf(gOutFile, "</package>\n");
1602 }
1603 fprintf(gOutFile, "<package name=\"%s\"\n>\n", mangle);
1604 free(*pLastPackage);
1605 *pLastPackage = mangle;
1606 } else {
1607 free(mangle);
1608 }
1609 }
1610
1611 // General class information.
1612 char* accessStr = createAccessFlagStr(pClassDef.access_flags_, AccessFor::kClass);
1613 const char* superclassDescriptor;
1614 if (!pClassDef.superclass_idx_.IsValid()) {
1615 superclassDescriptor = nullptr;
1616 } else {
1617 superclassDescriptor = pDexFile->GetTypeDescriptor(pClassDef.superclass_idx_);
1618 }
1619 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1620 fprintf(gOutFile, "Class #%d -\n", idx);
1621 fprintf(gOutFile, " Class descriptor : '%s'\n", classDescriptor);
1622 fprintf(gOutFile, " Access flags : 0x%04x (%s)\n", pClassDef.access_flags_, accessStr);
1623 if (superclassDescriptor != nullptr) {
1624 fprintf(gOutFile, " Superclass : '%s'\n", superclassDescriptor);
1625 }
1626 fprintf(gOutFile, " Interfaces -\n");
1627 } else {
1628 std::unique_ptr<char[]> dot(descriptorClassToName(classDescriptor));
1629 fprintf(gOutFile, "<class name=\"%s\"\n", dot.get());
1630 if (superclassDescriptor != nullptr) {
1631 dot = descriptorToDot(superclassDescriptor);
1632 fprintf(gOutFile, " extends=\"%s\"\n", dot.get());
1633 }
1634 fprintf(gOutFile, " interface=%s\n",
1635 quotedBool((pClassDef.access_flags_ & kAccInterface) != 0));
1636 fprintf(gOutFile, " abstract=%s\n", quotedBool((pClassDef.access_flags_ & kAccAbstract) != 0));
1637 fprintf(gOutFile, " static=%s\n", quotedBool((pClassDef.access_flags_ & kAccStatic) != 0));
1638 fprintf(gOutFile, " final=%s\n", quotedBool((pClassDef.access_flags_ & kAccFinal) != 0));
1639 // The "deprecated=" not knowable w/o parsing annotations.
1640 fprintf(gOutFile, " visibility=%s\n", quotedVisibility(pClassDef.access_flags_));
1641 fprintf(gOutFile, ">\n");
1642 }
1643
1644 // Interfaces.
1645 const dex::TypeList* pInterfaces = pDexFile->GetInterfacesList(pClassDef);
1646 if (pInterfaces != nullptr) {
1647 for (u4 i = 0; i < pInterfaces->Size(); i++) {
1648 dumpInterface(pDexFile, pInterfaces->GetTypeItem(i), i);
1649 } // for
1650 }
1651
1652 // Fields and methods.
1653 ClassAccessor accessor(*pDexFile, pClassDef, /* parse_hiddenapi_class_data= */ true);
1654
1655 // Prepare data for static fields.
1656 const u1* sData = pDexFile->GetEncodedStaticFieldValuesArray(pClassDef);
1657 const u4 sSize = sData != nullptr ? DecodeUnsignedLeb128(&sData) : 0;
1658
1659 // Static fields.
1660 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1661 fprintf(gOutFile, " Static fields -\n");
1662 }
1663 uint32_t i = 0u;
1664 for (const ClassAccessor::Field& field : accessor.GetStaticFields()) {
1665 dumpField(field, i, i < sSize ? &sData : nullptr);
1666 ++i;
1667 }
1668
1669 // Instance fields.
1670 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1671 fprintf(gOutFile, " Instance fields -\n");
1672 }
1673 i = 0u;
1674 for (const ClassAccessor::Field& field : accessor.GetInstanceFields()) {
1675 dumpField(field, i);
1676 ++i;
1677 }
1678
1679 // Direct methods.
1680 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1681 fprintf(gOutFile, " Direct methods -\n");
1682 }
1683 i = 0u;
1684 for (const ClassAccessor::Method& method : accessor.GetDirectMethods()) {
1685 dumpMethod(method, i);
1686 ++i;
1687 }
1688
1689 // Virtual methods.
1690 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1691 fprintf(gOutFile, " Virtual methods -\n");
1692 }
1693 i = 0u;
1694 for (const ClassAccessor::Method& method : accessor.GetVirtualMethods()) {
1695 dumpMethod(method, i);
1696 ++i;
1697 }
1698
1699 // End of class.
1700 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1701 const char* fileName;
1702 if (pClassDef.source_file_idx_.IsValid()) {
1703 fileName = pDexFile->GetStringData(pClassDef.source_file_idx_);
1704 } else {
1705 fileName = "unknown";
1706 }
1707 fprintf(gOutFile, " source_file_idx : %d (%s)\n\n",
1708 pClassDef.source_file_idx_.index_, fileName);
1709 } else if (gOptions.outputFormat == OUTPUT_XML) {
1710 fprintf(gOutFile, "</class>\n");
1711 }
1712
1713 free(accessStr);
1714 }
1715
dumpMethodHandle(const DexFile * pDexFile,u4 idx)1716 static void dumpMethodHandle(const DexFile* pDexFile, u4 idx) {
1717 const dex::MethodHandleItem& mh = pDexFile->GetMethodHandle(idx);
1718 const char* type = nullptr;
1719 bool is_instance = false;
1720 bool is_invoke = false;
1721 switch (static_cast<DexFile::MethodHandleType>(mh.method_handle_type_)) {
1722 case DexFile::MethodHandleType::kStaticPut:
1723 type = "put-static";
1724 is_instance = false;
1725 is_invoke = false;
1726 break;
1727 case DexFile::MethodHandleType::kStaticGet:
1728 type = "get-static";
1729 is_instance = false;
1730 is_invoke = false;
1731 break;
1732 case DexFile::MethodHandleType::kInstancePut:
1733 type = "put-instance";
1734 is_instance = true;
1735 is_invoke = false;
1736 break;
1737 case DexFile::MethodHandleType::kInstanceGet:
1738 type = "get-instance";
1739 is_instance = true;
1740 is_invoke = false;
1741 break;
1742 case DexFile::MethodHandleType::kInvokeStatic:
1743 type = "invoke-static";
1744 is_instance = false;
1745 is_invoke = true;
1746 break;
1747 case DexFile::MethodHandleType::kInvokeInstance:
1748 type = "invoke-instance";
1749 is_instance = true;
1750 is_invoke = true;
1751 break;
1752 case DexFile::MethodHandleType::kInvokeConstructor:
1753 type = "invoke-constructor";
1754 is_instance = true;
1755 is_invoke = true;
1756 break;
1757 case DexFile::MethodHandleType::kInvokeDirect:
1758 type = "invoke-direct";
1759 is_instance = true;
1760 is_invoke = true;
1761 break;
1762 case DexFile::MethodHandleType::kInvokeInterface:
1763 type = "invoke-interface";
1764 is_instance = true;
1765 is_invoke = true;
1766 break;
1767 }
1768
1769 const char* declaring_class;
1770 const char* member;
1771 std::string member_type;
1772 if (type != nullptr) {
1773 if (is_invoke) {
1774 const dex::MethodId& method_id = pDexFile->GetMethodId(mh.field_or_method_idx_);
1775 declaring_class = pDexFile->GetMethodDeclaringClassDescriptor(method_id);
1776 member = pDexFile->GetMethodName(method_id);
1777 member_type = pDexFile->GetMethodSignature(method_id).ToString();
1778 } else {
1779 const dex::FieldId& field_id = pDexFile->GetFieldId(mh.field_or_method_idx_);
1780 declaring_class = pDexFile->GetFieldDeclaringClassDescriptor(field_id);
1781 member = pDexFile->GetFieldName(field_id);
1782 member_type = pDexFile->GetFieldTypeDescriptor(field_id);
1783 }
1784 if (is_instance) {
1785 member_type = android::base::StringPrintf("(%s%s", declaring_class, member_type.c_str() + 1);
1786 }
1787 } else {
1788 type = "?";
1789 declaring_class = "?";
1790 member = "?";
1791 member_type = "?";
1792 }
1793
1794 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1795 fprintf(gOutFile, "Method handle #%u:\n", idx);
1796 fprintf(gOutFile, " type : %s\n", type);
1797 fprintf(gOutFile, " target : %s %s\n", declaring_class, member);
1798 fprintf(gOutFile, " target_type : %s\n", member_type.c_str());
1799 }
1800 }
1801
dumpCallSite(const DexFile * pDexFile,u4 idx)1802 static void dumpCallSite(const DexFile* pDexFile, u4 idx) {
1803 const dex::CallSiteIdItem& call_site_id = pDexFile->GetCallSiteId(idx);
1804 CallSiteArrayValueIterator it(*pDexFile, call_site_id);
1805 if (it.Size() < 3) {
1806 LOG(ERROR) << "ERROR: Call site " << idx << " has too few values.";
1807 return;
1808 }
1809
1810 uint32_t method_handle_idx = static_cast<uint32_t>(it.GetJavaValue().i);
1811 it.Next();
1812 dex::StringIndex method_name_idx = static_cast<dex::StringIndex>(it.GetJavaValue().i);
1813 const char* method_name = pDexFile->GetStringData(method_name_idx);
1814 it.Next();
1815 dex::ProtoIndex method_type_idx = static_cast<dex::ProtoIndex>(it.GetJavaValue().i);
1816 const dex::ProtoId& method_type_id = pDexFile->GetProtoId(method_type_idx);
1817 std::string method_type = pDexFile->GetProtoSignature(method_type_id).ToString();
1818 it.Next();
1819
1820 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1821 fprintf(gOutFile, "Call site #%u: // offset %u\n", idx, call_site_id.data_off_);
1822 fprintf(gOutFile, " link_argument[0] : %u (MethodHandle)\n", method_handle_idx);
1823 fprintf(gOutFile, " link_argument[1] : %s (String)\n", method_name);
1824 fprintf(gOutFile, " link_argument[2] : %s (MethodType)\n", method_type.c_str());
1825 }
1826
1827 size_t argument = 3;
1828 while (it.HasNext()) {
1829 const char* type;
1830 std::string value;
1831 switch (it.GetValueType()) {
1832 case EncodedArrayValueIterator::ValueType::kByte:
1833 type = "byte";
1834 value = android::base::StringPrintf("%u", it.GetJavaValue().b);
1835 break;
1836 case EncodedArrayValueIterator::ValueType::kShort:
1837 type = "short";
1838 value = android::base::StringPrintf("%d", it.GetJavaValue().s);
1839 break;
1840 case EncodedArrayValueIterator::ValueType::kChar:
1841 type = "char";
1842 value = android::base::StringPrintf("%u", it.GetJavaValue().c);
1843 break;
1844 case EncodedArrayValueIterator::ValueType::kInt:
1845 type = "int";
1846 value = android::base::StringPrintf("%d", it.GetJavaValue().i);
1847 break;
1848 case EncodedArrayValueIterator::ValueType::kLong:
1849 type = "long";
1850 value = android::base::StringPrintf("%" PRId64, it.GetJavaValue().j);
1851 break;
1852 case EncodedArrayValueIterator::ValueType::kFloat:
1853 type = "float";
1854 value = android::base::StringPrintf("%g", it.GetJavaValue().f);
1855 break;
1856 case EncodedArrayValueIterator::ValueType::kDouble:
1857 type = "double";
1858 value = android::base::StringPrintf("%g", it.GetJavaValue().d);
1859 break;
1860 case EncodedArrayValueIterator::ValueType::kMethodType: {
1861 type = "MethodType";
1862 dex::ProtoIndex proto_idx = static_cast<dex::ProtoIndex>(it.GetJavaValue().i);
1863 const dex::ProtoId& proto_id = pDexFile->GetProtoId(proto_idx);
1864 value = pDexFile->GetProtoSignature(proto_id).ToString();
1865 break;
1866 }
1867 case EncodedArrayValueIterator::ValueType::kMethodHandle:
1868 type = "MethodHandle";
1869 value = android::base::StringPrintf("%d", it.GetJavaValue().i);
1870 break;
1871 case EncodedArrayValueIterator::ValueType::kString: {
1872 type = "String";
1873 dex::StringIndex string_idx = static_cast<dex::StringIndex>(it.GetJavaValue().i);
1874 value = pDexFile->GetStringData(string_idx);
1875 break;
1876 }
1877 case EncodedArrayValueIterator::ValueType::kType: {
1878 type = "Class";
1879 dex::TypeIndex type_idx = static_cast<dex::TypeIndex>(it.GetJavaValue().i);
1880 const dex::TypeId& type_id = pDexFile->GetTypeId(type_idx);
1881 value = pDexFile->GetTypeDescriptor(type_id);
1882 break;
1883 }
1884 case EncodedArrayValueIterator::ValueType::kField:
1885 case EncodedArrayValueIterator::ValueType::kMethod:
1886 case EncodedArrayValueIterator::ValueType::kEnum:
1887 case EncodedArrayValueIterator::ValueType::kArray:
1888 case EncodedArrayValueIterator::ValueType::kAnnotation:
1889 // Unreachable based on current EncodedArrayValueIterator::Next().
1890 UNIMPLEMENTED(FATAL) << " type " << it.GetValueType();
1891 UNREACHABLE();
1892 case EncodedArrayValueIterator::ValueType::kNull:
1893 type = "Null";
1894 value = "null";
1895 break;
1896 case EncodedArrayValueIterator::ValueType::kBoolean:
1897 type = "boolean";
1898 value = it.GetJavaValue().z ? "true" : "false";
1899 break;
1900 case EncodedArrayValueIterator::ValueType::kEndOfInput:
1901 LOG(FATAL) << "Unreachable";
1902 UNREACHABLE();
1903 }
1904
1905 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1906 fprintf(gOutFile, " link_argument[%zu] : %s (%s)\n", argument, value.c_str(), type);
1907 }
1908
1909 it.Next();
1910 argument++;
1911 }
1912 }
1913
1914 /*
1915 * Used to decide if we want to print or skip a string from string_ids
1916 */
isPrintable(const char * s)1917 static int isPrintable(const char* s) {
1918 for (size_t i = 0; i < strlen(s); i++) {
1919 if (!isprint((s[i]))) {
1920 return false;
1921 }
1922 }
1923 return true;
1924 }
1925
1926 /*
1927 * Show all printable string in the string_ids section
1928 */
dumpStrings(const DexFile * pDexFile)1929 static void dumpStrings(const DexFile* pDexFile) {
1930 const DexFile::Header& pHeader = pDexFile->GetHeader();
1931 fprintf(gOutFile, "\nDisplaying %u strings from string_ids:\n", pHeader.string_ids_size_);
1932
1933 for (uint32_t i = 0; i < pHeader.string_ids_size_; i++) {
1934 dex::StringIndex idx = static_cast<dex::StringIndex>(i);
1935 const char* string = pDexFile->GetStringData(idx);
1936 if (!isPrintable(string)) {
1937 string = "skipped (not printable)";
1938 }
1939 fprintf(gOutFile, " string[%06u] - '%s'\n", i, string);
1940 }
1941
1942 fprintf(gOutFile, "\n");
1943 }
1944
1945 /*
1946 * Dumps the requested sections of the file.
1947 */
processDexFile(const char * fileName,const DexFile * pDexFile,size_t i,size_t n)1948 static void processDexFile(const char* fileName,
1949 const DexFile* pDexFile, size_t i, size_t n) {
1950 if (gOptions.verbose) {
1951 fputs("Opened '", gOutFile);
1952 fputs(fileName, gOutFile);
1953 if (n > 1) {
1954 fprintf(gOutFile, ":%s", DexFileLoader::GetMultiDexClassesDexName(i).c_str());
1955 }
1956 fprintf(gOutFile, "', DEX version '%.3s'\n", pDexFile->GetHeader().magic_.data() + 4);
1957 }
1958
1959 // Headers.
1960 if (gOptions.showFileHeaders) {
1961 dumpFileHeader(pDexFile);
1962 }
1963
1964 // Strings.
1965 if (gOptions.showAllStrings) {
1966 dumpStrings(pDexFile);
1967 }
1968
1969 // Iterate over all classes.
1970 char* package = nullptr;
1971 const u4 classDefsSize = pDexFile->GetHeader().class_defs_size_;
1972 for (u4 j = 0; j < classDefsSize; j++) {
1973 dumpClass(pDexFile, j, &package);
1974 } // for
1975
1976 // Iterate over all method handles.
1977 for (u4 j = 0; j < pDexFile->NumMethodHandles(); ++j) {
1978 dumpMethodHandle(pDexFile, j);
1979 } // for
1980
1981 // Iterate over all call site ids.
1982 for (u4 j = 0; j < pDexFile->NumCallSiteIds(); ++j) {
1983 dumpCallSite(pDexFile, j);
1984 } // for
1985
1986 // Free the last package allocated.
1987 if (package != nullptr) {
1988 fprintf(gOutFile, "</package>\n");
1989 free(package);
1990 }
1991 }
1992
1993 /*
1994 * Processes a single file (either direct .dex or indirect .zip/.jar/.apk).
1995 */
processFile(const char * fileName)1996 int processFile(const char* fileName) {
1997 if (gOptions.verbose) {
1998 fprintf(gOutFile, "Processing '%s'...\n", fileName);
1999 }
2000
2001 const bool kVerifyChecksum = !gOptions.ignoreBadChecksum;
2002 const bool kVerify = !gOptions.disableVerifier;
2003 std::string content;
2004 // If the file is not a .dex file, the function tries .zip/.jar/.apk files,
2005 // all of which are Zip archives with "classes.dex" inside.
2006 // TODO: add an api to android::base to read a std::vector<uint8_t>.
2007 if (!android::base::ReadFileToString(fileName, &content)) {
2008 LOG(ERROR) << "ReadFileToString failed";
2009 return -1;
2010 }
2011 DexFileLoaderErrorCode error_code;
2012 std::string error_msg;
2013 std::vector<std::unique_ptr<const DexFile>> dex_files;
2014 DexFileLoader dex_file_loader(
2015 reinterpret_cast<const uint8_t*>(content.data()), content.size(), fileName);
2016 if (!dex_file_loader.Open(kVerify, kVerifyChecksum, &error_code, &error_msg, &dex_files)) {
2017 // Display returned error message to user. Note that this error behavior
2018 // differs from the error messages shown by the original Dalvik dexdump.
2019 LOG(ERROR) << error_msg;
2020 return -1;
2021 }
2022
2023 // Success. Either report checksum verification or process
2024 // all dex files found in given file.
2025 if (gOptions.checksumOnly) {
2026 fprintf(gOutFile, "Checksum verified\n");
2027 } else {
2028 // Open XML context.
2029 if (gOptions.outputFormat == OUTPUT_XML) {
2030 fprintf(gOutFile, "<api>\n");
2031 }
2032
2033 for (size_t i = 0, n = dex_files.size(); i < n; i++) {
2034 processDexFile(fileName, dex_files[i].get(), i, n);
2035 }
2036
2037 // Close XML context.
2038 if (gOptions.outputFormat == OUTPUT_XML) {
2039 fprintf(gOutFile, "</api>\n");
2040 }
2041 }
2042 return 0;
2043 }
2044
2045 } // namespace art
2046