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