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("&amp;", gOutFile);
411           break;
412         case '<':
413           fputs("&lt;", gOutFile);
414           break;
415         case '>':
416           fputs("&gt;", gOutFile);
417           break;
418         case '"':
419           fputs("&quot;", gOutFile);
420           break;
421         case '\\':
422           fputs("\\\\", gOutFile);
423           break;
424         default:
425           putc(*c, gOutFile);
426       }  // switch
427     } else {
428       uint32_t data = 0;
429       size_t remaining;
430       uint8_t uc = static_cast<uint8_t>(*c);
431       if (((uc) & 0x80) == 0) {
432         // Not a multi-byte char
433         data = static_cast<uint32_t>(*c);
434         remaining = 0;
435       } else if (utf8Bytes(uc) == 2) {
436         // 2 bytes
437         data = ((uc) & 0b00011111);
438         remaining = 1;
439       } else if (utf8Bytes(uc) == 3) {
440         // 3 bytes
441         data = ((uc) & 0b00001111);
442         remaining = 2;
443       } else {
444         // 4 bytes
445         CHECK_EQ(utf8Bytes(uc), 4u);
446         data = ((uc) & 0b00000111);
447         remaining = 3;
448       }
449       for (size_t i = 0; i < remaining; ++i) {
450         ++c;
451         data = data << 6;
452         uc = static_cast<uint8_t>(*c);
453         data |= static_cast<uint32_t>(uc & 0b00111111u);
454       }
455       // No good option so just use java encoding, too many chars are invalid
456       fprintf(gOutFile, "\\u%04x", data);
457     }
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