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