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