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