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