dexlayout.cc revision a86210038524cecd0d96d6ba6f8f116da348a25c
1/*
2 * Copyright (C) 2016 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 dexlayout utility.
17 *
18 * This is a tool to read dex files into an internal representation,
19 * reorganize the representation, and emit dex files with a better
20 * file layout.
21 */
22
23#include "dexlayout.h"
24
25#include <inttypes.h>
26#include <stdio.h>
27
28#include <iostream>
29#include <memory>
30#include <sstream>
31#include <vector>
32
33#include "dex_ir_builder.h"
34#include "dex_file-inl.h"
35#include "dex_instruction-inl.h"
36#include "dex_visualize.h"
37#include "dex_writer.h"
38#include "jit/offline_profiling_info.h"
39#include "os.h"
40#include "utils.h"
41
42namespace art {
43
44/*
45 * Options parsed in main driver.
46 */
47struct Options options_;
48
49/*
50 * Output file. Defaults to stdout.
51 */
52FILE* out_file_ = stdout;
53
54/*
55 * Profile information file.
56 */
57ProfileCompilationInfo* profile_info_ = nullptr;
58
59/*
60 * Flags for use with createAccessFlagStr().
61 */
62enum AccessFor {
63  kAccessForClass = 0, kAccessForMethod = 1, kAccessForField = 2, kAccessForMAX
64};
65const int kNumFlags = 18;
66
67/*
68 * Gets 2 little-endian bytes.
69 */
70static inline uint16_t Get2LE(unsigned char const* src) {
71  return src[0] | (src[1] << 8);
72}
73
74/*
75 * Converts a type descriptor to human-readable "dotted" form.  For
76 * example, "Ljava/lang/String;" becomes "java.lang.String", and
77 * "[I" becomes "int[]".  Also converts '$' to '.', which means this
78 * form can't be converted back to a descriptor.
79 */
80static std::string DescriptorToDotWrapper(const char* descriptor) {
81  std::string result = DescriptorToDot(descriptor);
82  size_t found = result.find('$');
83  while (found != std::string::npos) {
84    result[found] = '.';
85    found = result.find('$', found);
86  }
87  return result;
88}
89
90/*
91 * Converts the class name portion of a type descriptor to human-readable
92 * "dotted" form. For example, "Ljava/lang/String;" becomes "String".
93 */
94static std::string DescriptorClassToDot(const char* str) {
95  std::string descriptor(str);
96  // Reduce to just the class name prefix.
97  size_t last_slash = descriptor.rfind('/');
98  if (last_slash == std::string::npos) {
99    last_slash = 0;
100  }
101  // Start past the '/' or 'L'.
102  last_slash++;
103
104  // Copy class name over, trimming trailing ';'.
105  size_t size = descriptor.size() - 1 - last_slash;
106  std::string result(descriptor.substr(last_slash, size));
107
108  // Replace '$' with '.'.
109  size_t dollar_sign = result.find('$');
110  while (dollar_sign != std::string::npos) {
111    result[dollar_sign] = '.';
112    dollar_sign = result.find('$', dollar_sign);
113  }
114
115  return result;
116}
117
118/*
119 * Returns string representing the boolean value.
120 */
121static const char* StrBool(bool val) {
122  return val ? "true" : "false";
123}
124
125/*
126 * Returns a quoted string representing the boolean value.
127 */
128static const char* QuotedBool(bool val) {
129  return val ? "\"true\"" : "\"false\"";
130}
131
132/*
133 * Returns a quoted string representing the access flags.
134 */
135static const char* QuotedVisibility(uint32_t access_flags) {
136  if (access_flags & kAccPublic) {
137    return "\"public\"";
138  } else if (access_flags & kAccProtected) {
139    return "\"protected\"";
140  } else if (access_flags & kAccPrivate) {
141    return "\"private\"";
142  } else {
143    return "\"package\"";
144  }
145}
146
147/*
148 * Counts the number of '1' bits in a word.
149 */
150static int CountOnes(uint32_t val) {
151  val = val - ((val >> 1) & 0x55555555);
152  val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
153  return (((val + (val >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
154}
155
156/*
157 * Creates a new string with human-readable access flags.
158 *
159 * In the base language the access_flags fields are type uint16_t; in Dalvik they're uint32_t.
160 */
161static char* CreateAccessFlagStr(uint32_t flags, AccessFor for_what) {
162  static const char* kAccessStrings[kAccessForMAX][kNumFlags] = {
163    {
164      "PUBLIC",                /* 0x00001 */
165      "PRIVATE",               /* 0x00002 */
166      "PROTECTED",             /* 0x00004 */
167      "STATIC",                /* 0x00008 */
168      "FINAL",                 /* 0x00010 */
169      "?",                     /* 0x00020 */
170      "?",                     /* 0x00040 */
171      "?",                     /* 0x00080 */
172      "?",                     /* 0x00100 */
173      "INTERFACE",             /* 0x00200 */
174      "ABSTRACT",              /* 0x00400 */
175      "?",                     /* 0x00800 */
176      "SYNTHETIC",             /* 0x01000 */
177      "ANNOTATION",            /* 0x02000 */
178      "ENUM",                  /* 0x04000 */
179      "?",                     /* 0x08000 */
180      "VERIFIED",              /* 0x10000 */
181      "OPTIMIZED",             /* 0x20000 */
182    }, {
183      "PUBLIC",                /* 0x00001 */
184      "PRIVATE",               /* 0x00002 */
185      "PROTECTED",             /* 0x00004 */
186      "STATIC",                /* 0x00008 */
187      "FINAL",                 /* 0x00010 */
188      "SYNCHRONIZED",          /* 0x00020 */
189      "BRIDGE",                /* 0x00040 */
190      "VARARGS",               /* 0x00080 */
191      "NATIVE",                /* 0x00100 */
192      "?",                     /* 0x00200 */
193      "ABSTRACT",              /* 0x00400 */
194      "STRICT",                /* 0x00800 */
195      "SYNTHETIC",             /* 0x01000 */
196      "?",                     /* 0x02000 */
197      "?",                     /* 0x04000 */
198      "MIRANDA",               /* 0x08000 */
199      "CONSTRUCTOR",           /* 0x10000 */
200      "DECLARED_SYNCHRONIZED", /* 0x20000 */
201    }, {
202      "PUBLIC",                /* 0x00001 */
203      "PRIVATE",               /* 0x00002 */
204      "PROTECTED",             /* 0x00004 */
205      "STATIC",                /* 0x00008 */
206      "FINAL",                 /* 0x00010 */
207      "?",                     /* 0x00020 */
208      "VOLATILE",              /* 0x00040 */
209      "TRANSIENT",             /* 0x00080 */
210      "?",                     /* 0x00100 */
211      "?",                     /* 0x00200 */
212      "?",                     /* 0x00400 */
213      "?",                     /* 0x00800 */
214      "SYNTHETIC",             /* 0x01000 */
215      "?",                     /* 0x02000 */
216      "ENUM",                  /* 0x04000 */
217      "?",                     /* 0x08000 */
218      "?",                     /* 0x10000 */
219      "?",                     /* 0x20000 */
220    },
221  };
222
223  // Allocate enough storage to hold the expected number of strings,
224  // plus a space between each.  We over-allocate, using the longest
225  // string above as the base metric.
226  const int kLongest = 21;  // The strlen of longest string above.
227  const int count = CountOnes(flags);
228  char* str;
229  char* cp;
230  cp = str = reinterpret_cast<char*>(malloc(count * (kLongest + 1) + 1));
231
232  for (int i = 0; i < kNumFlags; i++) {
233    if (flags & 0x01) {
234      const char* accessStr = kAccessStrings[for_what][i];
235      const int len = strlen(accessStr);
236      if (cp != str) {
237        *cp++ = ' ';
238      }
239      memcpy(cp, accessStr, len);
240      cp += len;
241    }
242    flags >>= 1;
243  }  // for
244
245  *cp = '\0';
246  return str;
247}
248
249static std::string GetSignatureForProtoId(const dex_ir::ProtoId* proto) {
250  if (proto == nullptr) {
251    return "<no signature>";
252  }
253
254  std::string result("(");
255  const dex_ir::TypeList* type_list = proto->Parameters();
256  if (type_list != nullptr) {
257    for (const dex_ir::TypeId* type_id : *type_list->GetTypeList()) {
258      result += type_id->GetStringId()->Data();
259    }
260  }
261  result += ")";
262  result += proto->ReturnType()->GetStringId()->Data();
263  return result;
264}
265
266/*
267 * Copies character data from "data" to "out", converting non-ASCII values
268 * to fprintf format chars or an ASCII filler ('.' or '?').
269 *
270 * The output buffer must be able to hold (2*len)+1 bytes.  The result is
271 * NULL-terminated.
272 */
273static void Asciify(char* out, const unsigned char* data, size_t len) {
274  while (len--) {
275    if (*data < 0x20) {
276      // Could do more here, but we don't need them yet.
277      switch (*data) {
278        case '\0':
279          *out++ = '\\';
280          *out++ = '0';
281          break;
282        case '\n':
283          *out++ = '\\';
284          *out++ = 'n';
285          break;
286        default:
287          *out++ = '.';
288          break;
289      }  // switch
290    } else if (*data >= 0x80) {
291      *out++ = '?';
292    } else {
293      *out++ = *data;
294    }
295    data++;
296  }  // while
297  *out = '\0';
298}
299
300/*
301 * Dumps a string value with some escape characters.
302 */
303static void DumpEscapedString(const char* p) {
304  fputs("\"", out_file_);
305  for (; *p; p++) {
306    switch (*p) {
307      case '\\':
308        fputs("\\\\", out_file_);
309        break;
310      case '\"':
311        fputs("\\\"", out_file_);
312        break;
313      case '\t':
314        fputs("\\t", out_file_);
315        break;
316      case '\n':
317        fputs("\\n", out_file_);
318        break;
319      case '\r':
320        fputs("\\r", out_file_);
321        break;
322      default:
323        putc(*p, out_file_);
324    }  // switch
325  }  // for
326  fputs("\"", out_file_);
327}
328
329/*
330 * Dumps a string as an XML attribute value.
331 */
332static void DumpXmlAttribute(const char* p) {
333  for (; *p; p++) {
334    switch (*p) {
335      case '&':
336        fputs("&amp;", out_file_);
337        break;
338      case '<':
339        fputs("&lt;", out_file_);
340        break;
341      case '>':
342        fputs("&gt;", out_file_);
343        break;
344      case '"':
345        fputs("&quot;", out_file_);
346        break;
347      case '\t':
348        fputs("&#x9;", out_file_);
349        break;
350      case '\n':
351        fputs("&#xA;", out_file_);
352        break;
353      case '\r':
354        fputs("&#xD;", out_file_);
355        break;
356      default:
357        putc(*p, out_file_);
358    }  // switch
359  }  // for
360}
361
362// Forward declare to resolve circular dependence.
363static void DumpEncodedValue(const dex_ir::EncodedValue* data);
364
365/*
366 * Dumps encoded annotation.
367 */
368static void DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation) {
369  fputs(annotation->GetType()->GetStringId()->Data(), out_file_);
370  // Display all name=value pairs.
371  for (auto& subannotation : *annotation->GetAnnotationElements()) {
372    fputc(' ', out_file_);
373    fputs(subannotation->GetName()->Data(), out_file_);
374    fputc('=', out_file_);
375    DumpEncodedValue(subannotation->GetValue());
376  }
377}
378/*
379 * Dumps encoded value.
380 */
381static void DumpEncodedValue(const dex_ir::EncodedValue* data) {
382  switch (data->Type()) {
383    case DexFile::kDexAnnotationByte:
384      fprintf(out_file_, "%" PRId8, data->GetByte());
385      break;
386    case DexFile::kDexAnnotationShort:
387      fprintf(out_file_, "%" PRId16, data->GetShort());
388      break;
389    case DexFile::kDexAnnotationChar:
390      fprintf(out_file_, "%" PRIu16, data->GetChar());
391      break;
392    case DexFile::kDexAnnotationInt:
393      fprintf(out_file_, "%" PRId32, data->GetInt());
394      break;
395    case DexFile::kDexAnnotationLong:
396      fprintf(out_file_, "%" PRId64, data->GetLong());
397      break;
398    case DexFile::kDexAnnotationFloat: {
399      fprintf(out_file_, "%g", data->GetFloat());
400      break;
401    }
402    case DexFile::kDexAnnotationDouble: {
403      fprintf(out_file_, "%g", data->GetDouble());
404      break;
405    }
406    case DexFile::kDexAnnotationString: {
407      dex_ir::StringId* string_id = data->GetStringId();
408      if (options_.output_format_ == kOutputPlain) {
409        DumpEscapedString(string_id->Data());
410      } else {
411        DumpXmlAttribute(string_id->Data());
412      }
413      break;
414    }
415    case DexFile::kDexAnnotationType: {
416      dex_ir::TypeId* type_id = data->GetTypeId();
417      fputs(type_id->GetStringId()->Data(), out_file_);
418      break;
419    }
420    case DexFile::kDexAnnotationField:
421    case DexFile::kDexAnnotationEnum: {
422      dex_ir::FieldId* field_id = data->GetFieldId();
423      fputs(field_id->Name()->Data(), out_file_);
424      break;
425    }
426    case DexFile::kDexAnnotationMethod: {
427      dex_ir::MethodId* method_id = data->GetMethodId();
428      fputs(method_id->Name()->Data(), out_file_);
429      break;
430    }
431    case DexFile::kDexAnnotationArray: {
432      fputc('{', out_file_);
433      // Display all elements.
434      for (auto& value : *data->GetEncodedArray()->GetEncodedValues()) {
435        fputc(' ', out_file_);
436        DumpEncodedValue(value.get());
437      }
438      fputs(" }", out_file_);
439      break;
440    }
441    case DexFile::kDexAnnotationAnnotation: {
442      DumpEncodedAnnotation(data->GetEncodedAnnotation());
443      break;
444    }
445    case DexFile::kDexAnnotationNull:
446      fputs("null", out_file_);
447      break;
448    case DexFile::kDexAnnotationBoolean:
449      fputs(StrBool(data->GetBoolean()), out_file_);
450      break;
451    default:
452      fputs("????", out_file_);
453      break;
454  }  // switch
455}
456
457/*
458 * Dumps the file header.
459 */
460static void DumpFileHeader(dex_ir::Header* header) {
461  char sanitized[8 * 2 + 1];
462  dex_ir::Collections& collections = header->GetCollections();
463  fprintf(out_file_, "DEX file header:\n");
464  Asciify(sanitized, header->Magic(), 8);
465  fprintf(out_file_, "magic               : '%s'\n", sanitized);
466  fprintf(out_file_, "checksum            : %08x\n", header->Checksum());
467  fprintf(out_file_, "signature           : %02x%02x...%02x%02x\n",
468          header->Signature()[0], header->Signature()[1],
469          header->Signature()[DexFile::kSha1DigestSize - 2],
470          header->Signature()[DexFile::kSha1DigestSize - 1]);
471  fprintf(out_file_, "file_size           : %d\n", header->FileSize());
472  fprintf(out_file_, "header_size         : %d\n", header->HeaderSize());
473  fprintf(out_file_, "link_size           : %d\n", header->LinkSize());
474  fprintf(out_file_, "link_off            : %d (0x%06x)\n",
475          header->LinkOffset(), header->LinkOffset());
476  fprintf(out_file_, "string_ids_size     : %d\n", collections.StringIdsSize());
477  fprintf(out_file_, "string_ids_off      : %d (0x%06x)\n",
478          collections.StringIdsOffset(), collections.StringIdsOffset());
479  fprintf(out_file_, "type_ids_size       : %d\n", collections.TypeIdsSize());
480  fprintf(out_file_, "type_ids_off        : %d (0x%06x)\n",
481          collections.TypeIdsOffset(), collections.TypeIdsOffset());
482  fprintf(out_file_, "proto_ids_size      : %d\n", collections.ProtoIdsSize());
483  fprintf(out_file_, "proto_ids_off       : %d (0x%06x)\n",
484          collections.ProtoIdsOffset(), collections.ProtoIdsOffset());
485  fprintf(out_file_, "field_ids_size      : %d\n", collections.FieldIdsSize());
486  fprintf(out_file_, "field_ids_off       : %d (0x%06x)\n",
487          collections.FieldIdsOffset(), collections.FieldIdsOffset());
488  fprintf(out_file_, "method_ids_size     : %d\n", collections.MethodIdsSize());
489  fprintf(out_file_, "method_ids_off      : %d (0x%06x)\n",
490          collections.MethodIdsOffset(), collections.MethodIdsOffset());
491  fprintf(out_file_, "class_defs_size     : %d\n", collections.ClassDefsSize());
492  fprintf(out_file_, "class_defs_off      : %d (0x%06x)\n",
493          collections.ClassDefsOffset(), collections.ClassDefsOffset());
494  fprintf(out_file_, "data_size           : %d\n", header->DataSize());
495  fprintf(out_file_, "data_off            : %d (0x%06x)\n\n",
496          header->DataOffset(), header->DataOffset());
497}
498
499/*
500 * Dumps a class_def_item.
501 */
502static void DumpClassDef(dex_ir::Header* header, int idx) {
503  // General class information.
504  dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(idx);
505  fprintf(out_file_, "Class #%d header:\n", idx);
506  fprintf(out_file_, "class_idx           : %d\n", class_def->ClassType()->GetIndex());
507  fprintf(out_file_, "access_flags        : %d (0x%04x)\n",
508          class_def->GetAccessFlags(), class_def->GetAccessFlags());
509  uint32_t superclass_idx =  class_def->Superclass() == nullptr ?
510      DexFile::kDexNoIndex16 : class_def->Superclass()->GetIndex();
511  fprintf(out_file_, "superclass_idx      : %d\n", superclass_idx);
512  fprintf(out_file_, "interfaces_off      : %d (0x%06x)\n",
513          class_def->InterfacesOffset(), class_def->InterfacesOffset());
514  uint32_t source_file_offset = 0xffffffffU;
515  if (class_def->SourceFile() != nullptr) {
516    source_file_offset = class_def->SourceFile()->GetIndex();
517  }
518  fprintf(out_file_, "source_file_idx     : %d\n", source_file_offset);
519  uint32_t annotations_offset = 0;
520  if (class_def->Annotations() != nullptr) {
521    annotations_offset = class_def->Annotations()->GetOffset();
522  }
523  fprintf(out_file_, "annotations_off     : %d (0x%06x)\n",
524          annotations_offset, annotations_offset);
525  if (class_def->GetClassData() == nullptr) {
526    fprintf(out_file_, "class_data_off      : %d (0x%06x)\n", 0, 0);
527  } else {
528    fprintf(out_file_, "class_data_off      : %d (0x%06x)\n",
529            class_def->GetClassData()->GetOffset(), class_def->GetClassData()->GetOffset());
530  }
531
532  // Fields and methods.
533  dex_ir::ClassData* class_data = class_def->GetClassData();
534  if (class_data != nullptr && class_data->StaticFields() != nullptr) {
535    fprintf(out_file_, "static_fields_size  : %zu\n", class_data->StaticFields()->size());
536  } else {
537    fprintf(out_file_, "static_fields_size  : 0\n");
538  }
539  if (class_data != nullptr && class_data->InstanceFields() != nullptr) {
540    fprintf(out_file_, "instance_fields_size: %zu\n", class_data->InstanceFields()->size());
541  } else {
542    fprintf(out_file_, "instance_fields_size: 0\n");
543  }
544  if (class_data != nullptr && class_data->DirectMethods() != nullptr) {
545    fprintf(out_file_, "direct_methods_size : %zu\n", class_data->DirectMethods()->size());
546  } else {
547    fprintf(out_file_, "direct_methods_size : 0\n");
548  }
549  if (class_data != nullptr && class_data->VirtualMethods() != nullptr) {
550    fprintf(out_file_, "virtual_methods_size: %zu\n", class_data->VirtualMethods()->size());
551  } else {
552    fprintf(out_file_, "virtual_methods_size: 0\n");
553  }
554  fprintf(out_file_, "\n");
555}
556
557/**
558 * Dumps an annotation set item.
559 */
560static void DumpAnnotationSetItem(dex_ir::AnnotationSetItem* set_item) {
561  if (set_item == nullptr || set_item->GetItems()->size() == 0) {
562    fputs("  empty-annotation-set\n", out_file_);
563    return;
564  }
565  for (dex_ir::AnnotationItem* annotation : *set_item->GetItems()) {
566    if (annotation == nullptr) {
567      continue;
568    }
569    fputs("  ", out_file_);
570    switch (annotation->GetVisibility()) {
571      case DexFile::kDexVisibilityBuild:   fputs("VISIBILITY_BUILD ",   out_file_); break;
572      case DexFile::kDexVisibilityRuntime: fputs("VISIBILITY_RUNTIME ", out_file_); break;
573      case DexFile::kDexVisibilitySystem:  fputs("VISIBILITY_SYSTEM ",  out_file_); break;
574      default:                             fputs("VISIBILITY_UNKNOWN ", out_file_); break;
575    }  // switch
576    DumpEncodedAnnotation(annotation->GetAnnotation());
577    fputc('\n', out_file_);
578  }
579}
580
581/*
582 * Dumps class annotations.
583 */
584static void DumpClassAnnotations(dex_ir::Header* header, int idx) {
585  dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(idx);
586  dex_ir::AnnotationsDirectoryItem* annotations_directory = class_def->Annotations();
587  if (annotations_directory == nullptr) {
588    return;  // none
589  }
590
591  fprintf(out_file_, "Class #%d annotations:\n", idx);
592
593  dex_ir::AnnotationSetItem* class_set_item = annotations_directory->GetClassAnnotation();
594  dex_ir::FieldAnnotationVector* fields = annotations_directory->GetFieldAnnotations();
595  dex_ir::MethodAnnotationVector* methods = annotations_directory->GetMethodAnnotations();
596  dex_ir::ParameterAnnotationVector* parameters = annotations_directory->GetParameterAnnotations();
597
598  // Annotations on the class itself.
599  if (class_set_item != nullptr) {
600    fprintf(out_file_, "Annotations on class\n");
601    DumpAnnotationSetItem(class_set_item);
602  }
603
604  // Annotations on fields.
605  if (fields != nullptr) {
606    for (auto& field : *fields) {
607      const dex_ir::FieldId* field_id = field->GetFieldId();
608      const uint32_t field_idx = field_id->GetIndex();
609      const char* field_name = field_id->Name()->Data();
610      fprintf(out_file_, "Annotations on field #%u '%s'\n", field_idx, field_name);
611      DumpAnnotationSetItem(field->GetAnnotationSetItem());
612    }
613  }
614
615  // Annotations on methods.
616  if (methods != nullptr) {
617    for (auto& method : *methods) {
618      const dex_ir::MethodId* method_id = method->GetMethodId();
619      const uint32_t method_idx = method_id->GetIndex();
620      const char* method_name = method_id->Name()->Data();
621      fprintf(out_file_, "Annotations on method #%u '%s'\n", method_idx, method_name);
622      DumpAnnotationSetItem(method->GetAnnotationSetItem());
623    }
624  }
625
626  // Annotations on method parameters.
627  if (parameters != nullptr) {
628    for (auto& parameter : *parameters) {
629      const dex_ir::MethodId* method_id = parameter->GetMethodId();
630      const uint32_t method_idx = method_id->GetIndex();
631      const char* method_name = method_id->Name()->Data();
632      fprintf(out_file_, "Annotations on method #%u '%s' parameters\n", method_idx, method_name);
633      uint32_t j = 0;
634      for (dex_ir::AnnotationSetItem* annotation : *parameter->GetAnnotations()->GetItems()) {
635        fprintf(out_file_, "#%u\n", j);
636        DumpAnnotationSetItem(annotation);
637        ++j;
638      }
639    }
640  }
641
642  fputc('\n', out_file_);
643}
644
645/*
646 * Dumps an interface that a class declares to implement.
647 */
648static void DumpInterface(const dex_ir::TypeId* type_item, int i) {
649  const char* interface_name = type_item->GetStringId()->Data();
650  if (options_.output_format_ == kOutputPlain) {
651    fprintf(out_file_, "    #%d              : '%s'\n", i, interface_name);
652  } else {
653    std::string dot(DescriptorToDotWrapper(interface_name));
654    fprintf(out_file_, "<implements name=\"%s\">\n</implements>\n", dot.c_str());
655  }
656}
657
658/*
659 * Dumps the catches table associated with the code.
660 */
661static void DumpCatches(const dex_ir::CodeItem* code) {
662  const uint16_t tries_size = code->TriesSize();
663
664  // No catch table.
665  if (tries_size == 0) {
666    fprintf(out_file_, "      catches       : (none)\n");
667    return;
668  }
669
670  // Dump all table entries.
671  fprintf(out_file_, "      catches       : %d\n", tries_size);
672  std::vector<std::unique_ptr<const dex_ir::TryItem>>* tries = code->Tries();
673  for (uint32_t i = 0; i < tries_size; i++) {
674    const dex_ir::TryItem* try_item = (*tries)[i].get();
675    const uint32_t start = try_item->StartAddr();
676    const uint32_t end = start + try_item->InsnCount();
677    fprintf(out_file_, "        0x%04x - 0x%04x\n", start, end);
678    for (auto& handler : *try_item->GetHandlers()->GetHandlers()) {
679      const dex_ir::TypeId* type_id = handler->GetTypeId();
680      const char* descriptor = (type_id == nullptr) ? "<any>" : type_id->GetStringId()->Data();
681      fprintf(out_file_, "          %s -> 0x%04x\n", descriptor, handler->GetAddress());
682    }  // for
683  }  // for
684}
685
686/*
687 * Dumps all positions table entries associated with the code.
688 */
689static void DumpPositionInfo(const dex_ir::CodeItem* code) {
690  dex_ir::DebugInfoItem* debug_info = code->DebugInfo();
691  if (debug_info == nullptr) {
692    return;
693  }
694  std::vector<std::unique_ptr<dex_ir::PositionInfo>>& positions = debug_info->GetPositionInfo();
695  for (size_t i = 0; i < positions.size(); ++i) {
696    fprintf(out_file_, "        0x%04x line=%d\n", positions[i]->address_, positions[i]->line_);
697  }
698}
699
700/*
701 * Dumps all locals table entries associated with the code.
702 */
703static void DumpLocalInfo(const dex_ir::CodeItem* code) {
704  dex_ir::DebugInfoItem* debug_info = code->DebugInfo();
705  if (debug_info == nullptr) {
706    return;
707  }
708  std::vector<std::unique_ptr<dex_ir::LocalInfo>>& locals = debug_info->GetLocalInfo();
709  for (size_t i = 0; i < locals.size(); ++i) {
710    dex_ir::LocalInfo* entry = locals[i].get();
711    fprintf(out_file_, "        0x%04x - 0x%04x reg=%d %s %s %s\n",
712            entry->start_address_, entry->end_address_, entry->reg_,
713            entry->name_.c_str(), entry->descriptor_.c_str(), entry->signature_.c_str());
714  }
715}
716
717/*
718 * Helper for dumpInstruction(), which builds the string
719 * representation for the index in the given instruction.
720 * Returns a pointer to a buffer of sufficient size.
721 */
722static std::unique_ptr<char[]> IndexString(dex_ir::Header* header,
723                                           const Instruction* dec_insn,
724                                           size_t buf_size) {
725  std::unique_ptr<char[]> buf(new char[buf_size]);
726  // Determine index and width of the string.
727  uint32_t index = 0;
728  uint32_t width = 4;
729  switch (Instruction::FormatOf(dec_insn->Opcode())) {
730    // SOME NOT SUPPORTED:
731    // case Instruction::k20bc:
732    case Instruction::k21c:
733    case Instruction::k35c:
734    // case Instruction::k35ms:
735    case Instruction::k3rc:
736    // case Instruction::k3rms:
737    // case Instruction::k35mi:
738    // case Instruction::k3rmi:
739      index = dec_insn->VRegB();
740      width = 4;
741      break;
742    case Instruction::k31c:
743      index = dec_insn->VRegB();
744      width = 8;
745      break;
746    case Instruction::k22c:
747    // case Instruction::k22cs:
748      index = dec_insn->VRegC();
749      width = 4;
750      break;
751    default:
752      break;
753  }  // switch
754
755  // Determine index type.
756  size_t outSize = 0;
757  switch (Instruction::IndexTypeOf(dec_insn->Opcode())) {
758    case Instruction::kIndexUnknown:
759      // This function should never get called for this type, but do
760      // something sensible here, just to help with debugging.
761      outSize = snprintf(buf.get(), buf_size, "<unknown-index>");
762      break;
763    case Instruction::kIndexNone:
764      // This function should never get called for this type, but do
765      // something sensible here, just to help with debugging.
766      outSize = snprintf(buf.get(), buf_size, "<no-index>");
767      break;
768    case Instruction::kIndexTypeRef:
769      if (index < header->GetCollections().TypeIdsSize()) {
770        const char* tp = header->GetCollections().GetTypeId(index)->GetStringId()->Data();
771        outSize = snprintf(buf.get(), buf_size, "%s // type@%0*x", tp, width, index);
772      } else {
773        outSize = snprintf(buf.get(), buf_size, "<type?> // type@%0*x", width, index);
774      }
775      break;
776    case Instruction::kIndexStringRef:
777      if (index < header->GetCollections().StringIdsSize()) {
778        const char* st = header->GetCollections().GetStringId(index)->Data();
779        outSize = snprintf(buf.get(), buf_size, "\"%s\" // string@%0*x", st, width, index);
780      } else {
781        outSize = snprintf(buf.get(), buf_size, "<string?> // string@%0*x", width, index);
782      }
783      break;
784    case Instruction::kIndexMethodRef:
785      if (index < header->GetCollections().MethodIdsSize()) {
786        dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index);
787        const char* name = method_id->Name()->Data();
788        std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
789        const char* back_descriptor = method_id->Class()->GetStringId()->Data();
790        outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // method@%0*x",
791                           back_descriptor, name, type_descriptor.c_str(), width, index);
792      } else {
793        outSize = snprintf(buf.get(), buf_size, "<method?> // method@%0*x", width, index);
794      }
795      break;
796    case Instruction::kIndexFieldRef:
797      if (index < header->GetCollections().FieldIdsSize()) {
798        dex_ir::FieldId* field_id = header->GetCollections().GetFieldId(index);
799        const char* name = field_id->Name()->Data();
800        const char* type_descriptor = field_id->Type()->GetStringId()->Data();
801        const char* back_descriptor = field_id->Class()->GetStringId()->Data();
802        outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // field@%0*x",
803                           back_descriptor, name, type_descriptor, width, index);
804      } else {
805        outSize = snprintf(buf.get(), buf_size, "<field?> // field@%0*x", width, index);
806      }
807      break;
808    case Instruction::kIndexVtableOffset:
809      outSize = snprintf(buf.get(), buf_size, "[%0*x] // vtable #%0*x",
810                         width, index, width, index);
811      break;
812    case Instruction::kIndexFieldOffset:
813      outSize = snprintf(buf.get(), buf_size, "[obj+%0*x]", width, index);
814      break;
815    // SOME NOT SUPPORTED:
816    // case Instruction::kIndexVaries:
817    // case Instruction::kIndexInlineMethod:
818    default:
819      outSize = snprintf(buf.get(), buf_size, "<?>");
820      break;
821  }  // switch
822
823  // Determine success of string construction.
824  if (outSize >= buf_size) {
825    // The buffer wasn't big enough; retry with computed size. Note: snprintf()
826    // doesn't count/ the '\0' as part of its returned size, so we add explicit
827    // space for it here.
828    return IndexString(header, dec_insn, outSize + 1);
829  }
830  return buf;
831}
832
833/*
834 * Dumps a single instruction.
835 */
836static void DumpInstruction(dex_ir::Header* header, const dex_ir::CodeItem* code,
837                            uint32_t code_offset, uint32_t insn_idx, uint32_t insn_width,
838                            const Instruction* dec_insn) {
839  // Address of instruction (expressed as byte offset).
840  fprintf(out_file_, "%06x:", code_offset + 0x10 + insn_idx * 2);
841
842  // Dump (part of) raw bytes.
843  const uint16_t* insns = code->Insns();
844  for (uint32_t i = 0; i < 8; i++) {
845    if (i < insn_width) {
846      if (i == 7) {
847        fprintf(out_file_, " ... ");
848      } else {
849        // Print 16-bit value in little-endian order.
850        const uint8_t* bytePtr = (const uint8_t*) &insns[insn_idx + i];
851        fprintf(out_file_, " %02x%02x", bytePtr[0], bytePtr[1]);
852      }
853    } else {
854      fputs("     ", out_file_);
855    }
856  }  // for
857
858  // Dump pseudo-instruction or opcode.
859  if (dec_insn->Opcode() == Instruction::NOP) {
860    const uint16_t instr = Get2LE((const uint8_t*) &insns[insn_idx]);
861    if (instr == Instruction::kPackedSwitchSignature) {
862      fprintf(out_file_, "|%04x: packed-switch-data (%d units)", insn_idx, insn_width);
863    } else if (instr == Instruction::kSparseSwitchSignature) {
864      fprintf(out_file_, "|%04x: sparse-switch-data (%d units)", insn_idx, insn_width);
865    } else if (instr == Instruction::kArrayDataSignature) {
866      fprintf(out_file_, "|%04x: array-data (%d units)", insn_idx, insn_width);
867    } else {
868      fprintf(out_file_, "|%04x: nop // spacer", insn_idx);
869    }
870  } else {
871    fprintf(out_file_, "|%04x: %s", insn_idx, dec_insn->Name());
872  }
873
874  // Set up additional argument.
875  std::unique_ptr<char[]> index_buf;
876  if (Instruction::IndexTypeOf(dec_insn->Opcode()) != Instruction::kIndexNone) {
877    index_buf = IndexString(header, dec_insn, 200);
878  }
879
880  // Dump the instruction.
881  //
882  // NOTE: pDecInsn->DumpString(pDexFile) differs too much from original.
883  //
884  switch (Instruction::FormatOf(dec_insn->Opcode())) {
885    case Instruction::k10x:        // op
886      break;
887    case Instruction::k12x:        // op vA, vB
888      fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB());
889      break;
890    case Instruction::k11n:        // op vA, #+B
891      fprintf(out_file_, " v%d, #int %d // #%x",
892              dec_insn->VRegA(), (int32_t) dec_insn->VRegB(), (uint8_t)dec_insn->VRegB());
893      break;
894    case Instruction::k11x:        // op vAA
895      fprintf(out_file_, " v%d", dec_insn->VRegA());
896      break;
897    case Instruction::k10t:        // op +AA
898    case Instruction::k20t: {      // op +AAAA
899      const int32_t targ = (int32_t) dec_insn->VRegA();
900      fprintf(out_file_, " %04x // %c%04x",
901              insn_idx + targ,
902              (targ < 0) ? '-' : '+',
903              (targ < 0) ? -targ : targ);
904      break;
905    }
906    case Instruction::k22x:        // op vAA, vBBBB
907      fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB());
908      break;
909    case Instruction::k21t: {     // op vAA, +BBBB
910      const int32_t targ = (int32_t) dec_insn->VRegB();
911      fprintf(out_file_, " v%d, %04x // %c%04x", dec_insn->VRegA(),
912              insn_idx + targ,
913              (targ < 0) ? '-' : '+',
914              (targ < 0) ? -targ : targ);
915      break;
916    }
917    case Instruction::k21s:        // op vAA, #+BBBB
918      fprintf(out_file_, " v%d, #int %d // #%x",
919              dec_insn->VRegA(), (int32_t) dec_insn->VRegB(), (uint16_t)dec_insn->VRegB());
920      break;
921    case Instruction::k21h:        // op vAA, #+BBBB0000[00000000]
922      // The printed format varies a bit based on the actual opcode.
923      if (dec_insn->Opcode() == Instruction::CONST_HIGH16) {
924        const int32_t value = dec_insn->VRegB() << 16;
925        fprintf(out_file_, " v%d, #int %d // #%x",
926                dec_insn->VRegA(), value, (uint16_t) dec_insn->VRegB());
927      } else {
928        const int64_t value = ((int64_t) dec_insn->VRegB()) << 48;
929        fprintf(out_file_, " v%d, #long %" PRId64 " // #%x",
930                dec_insn->VRegA(), value, (uint16_t) dec_insn->VRegB());
931      }
932      break;
933    case Instruction::k21c:        // op vAA, thing@BBBB
934    case Instruction::k31c:        // op vAA, thing@BBBBBBBB
935      fprintf(out_file_, " v%d, %s", dec_insn->VRegA(), index_buf.get());
936      break;
937    case Instruction::k23x:        // op vAA, vBB, vCC
938      fprintf(out_file_, " v%d, v%d, v%d",
939              dec_insn->VRegA(), dec_insn->VRegB(), dec_insn->VRegC());
940      break;
941    case Instruction::k22b:        // op vAA, vBB, #+CC
942      fprintf(out_file_, " v%d, v%d, #int %d // #%02x",
943              dec_insn->VRegA(), dec_insn->VRegB(),
944              (int32_t) dec_insn->VRegC(), (uint8_t) dec_insn->VRegC());
945      break;
946    case Instruction::k22t: {      // op vA, vB, +CCCC
947      const int32_t targ = (int32_t) dec_insn->VRegC();
948      fprintf(out_file_, " v%d, v%d, %04x // %c%04x",
949              dec_insn->VRegA(), dec_insn->VRegB(),
950              insn_idx + targ,
951              (targ < 0) ? '-' : '+',
952              (targ < 0) ? -targ : targ);
953      break;
954    }
955    case Instruction::k22s:        // op vA, vB, #+CCCC
956      fprintf(out_file_, " v%d, v%d, #int %d // #%04x",
957              dec_insn->VRegA(), dec_insn->VRegB(),
958              (int32_t) dec_insn->VRegC(), (uint16_t) dec_insn->VRegC());
959      break;
960    case Instruction::k22c:        // op vA, vB, thing@CCCC
961    // NOT SUPPORTED:
962    // case Instruction::k22cs:    // [opt] op vA, vB, field offset CCCC
963      fprintf(out_file_, " v%d, v%d, %s",
964              dec_insn->VRegA(), dec_insn->VRegB(), index_buf.get());
965      break;
966    case Instruction::k30t:
967      fprintf(out_file_, " #%08x", dec_insn->VRegA());
968      break;
969    case Instruction::k31i: {     // op vAA, #+BBBBBBBB
970      // This is often, but not always, a float.
971      union {
972        float f;
973        uint32_t i;
974      } conv;
975      conv.i = dec_insn->VRegB();
976      fprintf(out_file_, " v%d, #float %g // #%08x",
977              dec_insn->VRegA(), conv.f, dec_insn->VRegB());
978      break;
979    }
980    case Instruction::k31t:       // op vAA, offset +BBBBBBBB
981      fprintf(out_file_, " v%d, %08x // +%08x",
982              dec_insn->VRegA(), insn_idx + dec_insn->VRegB(), dec_insn->VRegB());
983      break;
984    case Instruction::k32x:        // op vAAAA, vBBBB
985      fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB());
986      break;
987    case Instruction::k35c: {      // op {vC, vD, vE, vF, vG}, thing@BBBB
988    // NOT SUPPORTED:
989    // case Instruction::k35ms:       // [opt] invoke-virtual+super
990    // case Instruction::k35mi:       // [opt] inline invoke
991      uint32_t arg[Instruction::kMaxVarArgRegs];
992      dec_insn->GetVarArgs(arg);
993      fputs(" {", out_file_);
994      for (int i = 0, n = dec_insn->VRegA(); i < n; i++) {
995        if (i == 0) {
996          fprintf(out_file_, "v%d", arg[i]);
997        } else {
998          fprintf(out_file_, ", v%d", arg[i]);
999        }
1000      }  // for
1001      fprintf(out_file_, "}, %s", index_buf.get());
1002      break;
1003    }
1004    case Instruction::k3rc:        // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB
1005    // NOT SUPPORTED:
1006    // case Instruction::k3rms:       // [opt] invoke-virtual+super/range
1007    // case Instruction::k3rmi:       // [opt] execute-inline/range
1008      {
1009        // This doesn't match the "dx" output when some of the args are
1010        // 64-bit values -- dx only shows the first register.
1011        fputs(" {", out_file_);
1012        for (int i = 0, n = dec_insn->VRegA(); i < n; i++) {
1013          if (i == 0) {
1014            fprintf(out_file_, "v%d", dec_insn->VRegC() + i);
1015          } else {
1016            fprintf(out_file_, ", v%d", dec_insn->VRegC() + i);
1017          }
1018        }  // for
1019        fprintf(out_file_, "}, %s", index_buf.get());
1020      }
1021      break;
1022    case Instruction::k51l: {      // op vAA, #+BBBBBBBBBBBBBBBB
1023      // This is often, but not always, a double.
1024      union {
1025        double d;
1026        uint64_t j;
1027      } conv;
1028      conv.j = dec_insn->WideVRegB();
1029      fprintf(out_file_, " v%d, #double %g // #%016" PRIx64,
1030              dec_insn->VRegA(), conv.d, dec_insn->WideVRegB());
1031      break;
1032    }
1033    // NOT SUPPORTED:
1034    // case Instruction::k00x:        // unknown op or breakpoint
1035    //    break;
1036    default:
1037      fprintf(out_file_, " ???");
1038      break;
1039  }  // switch
1040
1041  fputc('\n', out_file_);
1042}
1043
1044/*
1045 * Dumps a bytecode disassembly.
1046 */
1047static void DumpBytecodes(dex_ir::Header* header, uint32_t idx,
1048                          const dex_ir::CodeItem* code, uint32_t code_offset) {
1049  dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(idx);
1050  const char* name = method_id->Name()->Data();
1051  std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
1052  const char* back_descriptor = method_id->Class()->GetStringId()->Data();
1053
1054  // Generate header.
1055  std::string dot(DescriptorToDotWrapper(back_descriptor));
1056  fprintf(out_file_, "%06x:                                        |[%06x] %s.%s:%s\n",
1057          code_offset, code_offset, dot.c_str(), name, type_descriptor.c_str());
1058
1059  // Iterate over all instructions.
1060  const uint16_t* insns = code->Insns();
1061  for (uint32_t insn_idx = 0; insn_idx < code->InsnsSize();) {
1062    const Instruction* instruction = Instruction::At(&insns[insn_idx]);
1063    const uint32_t insn_width = instruction->SizeInCodeUnits();
1064    if (insn_width == 0) {
1065      fprintf(stderr, "GLITCH: zero-width instruction at idx=0x%04x\n", insn_idx);
1066      break;
1067    }
1068    DumpInstruction(header, code, code_offset, insn_idx, insn_width, instruction);
1069    insn_idx += insn_width;
1070  }  // for
1071}
1072
1073/*
1074 * Dumps code of a method.
1075 */
1076static void DumpCode(dex_ir::Header* header, uint32_t idx, const dex_ir::CodeItem* code,
1077                     uint32_t code_offset) {
1078  fprintf(out_file_, "      registers     : %d\n", code->RegistersSize());
1079  fprintf(out_file_, "      ins           : %d\n", code->InsSize());
1080  fprintf(out_file_, "      outs          : %d\n", code->OutsSize());
1081  fprintf(out_file_, "      insns size    : %d 16-bit code units\n",
1082          code->InsnsSize());
1083
1084  // Bytecode disassembly, if requested.
1085  if (options_.disassemble_) {
1086    DumpBytecodes(header, idx, code, code_offset);
1087  }
1088
1089  // Try-catch blocks.
1090  DumpCatches(code);
1091
1092  // Positions and locals table in the debug info.
1093  fprintf(out_file_, "      positions     : \n");
1094  DumpPositionInfo(code);
1095  fprintf(out_file_, "      locals        : \n");
1096  DumpLocalInfo(code);
1097}
1098
1099/*
1100 * Dumps a method.
1101 */
1102static void DumpMethod(dex_ir::Header* header, uint32_t idx, uint32_t flags,
1103                       const dex_ir::CodeItem* code, int i) {
1104  // Bail for anything private if export only requested.
1105  if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) {
1106    return;
1107  }
1108
1109  dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(idx);
1110  const char* name = method_id->Name()->Data();
1111  char* type_descriptor = strdup(GetSignatureForProtoId(method_id->Proto()).c_str());
1112  const char* back_descriptor = method_id->Class()->GetStringId()->Data();
1113  char* access_str = CreateAccessFlagStr(flags, kAccessForMethod);
1114
1115  if (options_.output_format_ == kOutputPlain) {
1116    fprintf(out_file_, "    #%d              : (in %s)\n", i, back_descriptor);
1117    fprintf(out_file_, "      name          : '%s'\n", name);
1118    fprintf(out_file_, "      type          : '%s'\n", type_descriptor);
1119    fprintf(out_file_, "      access        : 0x%04x (%s)\n", flags, access_str);
1120    if (code == nullptr) {
1121      fprintf(out_file_, "      code          : (none)\n");
1122    } else {
1123      fprintf(out_file_, "      code          -\n");
1124      DumpCode(header, idx, code, code->GetOffset());
1125    }
1126    if (options_.disassemble_) {
1127      fputc('\n', out_file_);
1128    }
1129  } else if (options_.output_format_ == kOutputXml) {
1130    const bool constructor = (name[0] == '<');
1131
1132    // Method name and prototype.
1133    if (constructor) {
1134      std::string dot(DescriptorClassToDot(back_descriptor));
1135      fprintf(out_file_, "<constructor name=\"%s\"\n", dot.c_str());
1136      dot = DescriptorToDotWrapper(back_descriptor);
1137      fprintf(out_file_, " type=\"%s\"\n", dot.c_str());
1138    } else {
1139      fprintf(out_file_, "<method name=\"%s\"\n", name);
1140      const char* return_type = strrchr(type_descriptor, ')');
1141      if (return_type == nullptr) {
1142        fprintf(stderr, "bad method type descriptor '%s'\n", type_descriptor);
1143        goto bail;
1144      }
1145      std::string dot(DescriptorToDotWrapper(return_type + 1));
1146      fprintf(out_file_, " return=\"%s\"\n", dot.c_str());
1147      fprintf(out_file_, " abstract=%s\n", QuotedBool((flags & kAccAbstract) != 0));
1148      fprintf(out_file_, " native=%s\n", QuotedBool((flags & kAccNative) != 0));
1149      fprintf(out_file_, " synchronized=%s\n", QuotedBool(
1150          (flags & (kAccSynchronized | kAccDeclaredSynchronized)) != 0));
1151    }
1152
1153    // Additional method flags.
1154    fprintf(out_file_, " static=%s\n", QuotedBool((flags & kAccStatic) != 0));
1155    fprintf(out_file_, " final=%s\n", QuotedBool((flags & kAccFinal) != 0));
1156    // The "deprecated=" not knowable w/o parsing annotations.
1157    fprintf(out_file_, " visibility=%s\n>\n", QuotedVisibility(flags));
1158
1159    // Parameters.
1160    if (type_descriptor[0] != '(') {
1161      fprintf(stderr, "ERROR: bad descriptor '%s'\n", type_descriptor);
1162      goto bail;
1163    }
1164    char* tmp_buf = reinterpret_cast<char*>(malloc(strlen(type_descriptor) + 1));
1165    const char* base = type_descriptor + 1;
1166    int arg_num = 0;
1167    while (*base != ')') {
1168      char* cp = tmp_buf;
1169      while (*base == '[') {
1170        *cp++ = *base++;
1171      }
1172      if (*base == 'L') {
1173        // Copy through ';'.
1174        do {
1175          *cp = *base++;
1176        } while (*cp++ != ';');
1177      } else {
1178        // Primitive char, copy it.
1179        if (strchr("ZBCSIFJD", *base) == nullptr) {
1180          fprintf(stderr, "ERROR: bad method signature '%s'\n", base);
1181          break;  // while
1182        }
1183        *cp++ = *base++;
1184      }
1185      // Null terminate and display.
1186      *cp++ = '\0';
1187      std::string dot(DescriptorToDotWrapper(tmp_buf));
1188      fprintf(out_file_, "<parameter name=\"arg%d\" type=\"%s\">\n"
1189                        "</parameter>\n", arg_num++, dot.c_str());
1190    }  // while
1191    free(tmp_buf);
1192    if (constructor) {
1193      fprintf(out_file_, "</constructor>\n");
1194    } else {
1195      fprintf(out_file_, "</method>\n");
1196    }
1197  }
1198
1199 bail:
1200  free(type_descriptor);
1201  free(access_str);
1202}
1203
1204/*
1205 * Dumps a static (class) field.
1206 */
1207static void DumpSField(dex_ir::Header* header, uint32_t idx, uint32_t flags,
1208                       int i, dex_ir::EncodedValue* init) {
1209  // Bail for anything private if export only requested.
1210  if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) {
1211    return;
1212  }
1213
1214  dex_ir::FieldId* field_id = header->GetCollections().GetFieldId(idx);
1215  const char* name = field_id->Name()->Data();
1216  const char* type_descriptor = field_id->Type()->GetStringId()->Data();
1217  const char* back_descriptor = field_id->Class()->GetStringId()->Data();
1218  char* access_str = CreateAccessFlagStr(flags, kAccessForField);
1219
1220  if (options_.output_format_ == kOutputPlain) {
1221    fprintf(out_file_, "    #%d              : (in %s)\n", i, back_descriptor);
1222    fprintf(out_file_, "      name          : '%s'\n", name);
1223    fprintf(out_file_, "      type          : '%s'\n", type_descriptor);
1224    fprintf(out_file_, "      access        : 0x%04x (%s)\n", flags, access_str);
1225    if (init != nullptr) {
1226      fputs("      value         : ", out_file_);
1227      DumpEncodedValue(init);
1228      fputs("\n", out_file_);
1229    }
1230  } else if (options_.output_format_ == kOutputXml) {
1231    fprintf(out_file_, "<field name=\"%s\"\n", name);
1232    std::string dot(DescriptorToDotWrapper(type_descriptor));
1233    fprintf(out_file_, " type=\"%s\"\n", dot.c_str());
1234    fprintf(out_file_, " transient=%s\n", QuotedBool((flags & kAccTransient) != 0));
1235    fprintf(out_file_, " volatile=%s\n", QuotedBool((flags & kAccVolatile) != 0));
1236    // The "value=" is not knowable w/o parsing annotations.
1237    fprintf(out_file_, " static=%s\n", QuotedBool((flags & kAccStatic) != 0));
1238    fprintf(out_file_, " final=%s\n", QuotedBool((flags & kAccFinal) != 0));
1239    // The "deprecated=" is not knowable w/o parsing annotations.
1240    fprintf(out_file_, " visibility=%s\n", QuotedVisibility(flags));
1241    if (init != nullptr) {
1242      fputs(" value=\"", out_file_);
1243      DumpEncodedValue(init);
1244      fputs("\"\n", out_file_);
1245    }
1246    fputs(">\n</field>\n", out_file_);
1247  }
1248
1249  free(access_str);
1250}
1251
1252/*
1253 * Dumps an instance field.
1254 */
1255static void DumpIField(dex_ir::Header* header, uint32_t idx, uint32_t flags, int i) {
1256  DumpSField(header, idx, flags, i, nullptr);
1257}
1258
1259/*
1260 * Dumping a CFG. Note that this will do duplicate work. utils.h doesn't expose the code-item
1261 * version, so the DumpMethodCFG code will have to iterate again to find it. But dexdump is a
1262 * tool, so this is not performance-critical.
1263 */
1264
1265static void DumpCFG(const DexFile* dex_file,
1266                    uint32_t dex_method_idx,
1267                    const DexFile::CodeItem* code) {
1268  if (code != nullptr) {
1269    std::ostringstream oss;
1270    DumpMethodCFG(dex_file, dex_method_idx, oss);
1271    fprintf(out_file_, "%s", oss.str().c_str());
1272  }
1273}
1274
1275static void DumpCFG(const DexFile* dex_file, int idx) {
1276  const DexFile::ClassDef& class_def = dex_file->GetClassDef(idx);
1277  const uint8_t* class_data = dex_file->GetClassData(class_def);
1278  if (class_data == nullptr) {  // empty class such as a marker interface?
1279    return;
1280  }
1281  ClassDataItemIterator it(*dex_file, class_data);
1282  while (it.HasNextStaticField()) {
1283    it.Next();
1284  }
1285  while (it.HasNextInstanceField()) {
1286    it.Next();
1287  }
1288  while (it.HasNextDirectMethod()) {
1289    DumpCFG(dex_file,
1290            it.GetMemberIndex(),
1291            it.GetMethodCodeItem());
1292    it.Next();
1293  }
1294  while (it.HasNextVirtualMethod()) {
1295    DumpCFG(dex_file,
1296            it.GetMemberIndex(),
1297            it.GetMethodCodeItem());
1298    it.Next();
1299  }
1300}
1301
1302/*
1303 * Dumps the class.
1304 *
1305 * Note "idx" is a DexClassDef index, not a DexTypeId index.
1306 *
1307 * If "*last_package" is nullptr or does not match the current class' package,
1308 * the value will be replaced with a newly-allocated string.
1309 */
1310static void DumpClass(const DexFile* dex_file,
1311                      dex_ir::Header* header,
1312                      int idx,
1313                      char** last_package) {
1314  dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(idx);
1315  // Omitting non-public class.
1316  if (options_.exports_only_ && (class_def->GetAccessFlags() & kAccPublic) == 0) {
1317    return;
1318  }
1319
1320  if (options_.show_section_headers_) {
1321    DumpClassDef(header, idx);
1322  }
1323
1324  if (options_.show_annotations_) {
1325    DumpClassAnnotations(header, idx);
1326  }
1327
1328  if (options_.show_cfg_) {
1329    DumpCFG(dex_file, idx);
1330    return;
1331  }
1332
1333  // For the XML output, show the package name.  Ideally we'd gather
1334  // up the classes, sort them, and dump them alphabetically so the
1335  // package name wouldn't jump around, but that's not a great plan
1336  // for something that needs to run on the device.
1337  const char* class_descriptor =
1338      header->GetCollections().GetClassDef(idx)->ClassType()->GetStringId()->Data();
1339  if (!(class_descriptor[0] == 'L' &&
1340        class_descriptor[strlen(class_descriptor)-1] == ';')) {
1341    // Arrays and primitives should not be defined explicitly. Keep going?
1342    fprintf(stderr, "Malformed class name '%s'\n", class_descriptor);
1343  } else if (options_.output_format_ == kOutputXml) {
1344    char* mangle = strdup(class_descriptor + 1);
1345    mangle[strlen(mangle)-1] = '\0';
1346
1347    // Reduce to just the package name.
1348    char* last_slash = strrchr(mangle, '/');
1349    if (last_slash != nullptr) {
1350      *last_slash = '\0';
1351    } else {
1352      *mangle = '\0';
1353    }
1354
1355    for (char* cp = mangle; *cp != '\0'; cp++) {
1356      if (*cp == '/') {
1357        *cp = '.';
1358      }
1359    }  // for
1360
1361    if (*last_package == nullptr || strcmp(mangle, *last_package) != 0) {
1362      // Start of a new package.
1363      if (*last_package != nullptr) {
1364        fprintf(out_file_, "</package>\n");
1365      }
1366      fprintf(out_file_, "<package name=\"%s\"\n>\n", mangle);
1367      free(*last_package);
1368      *last_package = mangle;
1369    } else {
1370      free(mangle);
1371    }
1372  }
1373
1374  // General class information.
1375  char* access_str = CreateAccessFlagStr(class_def->GetAccessFlags(), kAccessForClass);
1376  const char* superclass_descriptor = nullptr;
1377  if (class_def->Superclass() != nullptr) {
1378    superclass_descriptor = class_def->Superclass()->GetStringId()->Data();
1379  }
1380  if (options_.output_format_ == kOutputPlain) {
1381    fprintf(out_file_, "Class #%d            -\n", idx);
1382    fprintf(out_file_, "  Class descriptor  : '%s'\n", class_descriptor);
1383    fprintf(out_file_, "  Access flags      : 0x%04x (%s)\n",
1384            class_def->GetAccessFlags(), access_str);
1385    if (superclass_descriptor != nullptr) {
1386      fprintf(out_file_, "  Superclass        : '%s'\n", superclass_descriptor);
1387    }
1388    fprintf(out_file_, "  Interfaces        -\n");
1389  } else {
1390    std::string dot(DescriptorClassToDot(class_descriptor));
1391    fprintf(out_file_, "<class name=\"%s\"\n", dot.c_str());
1392    if (superclass_descriptor != nullptr) {
1393      dot = DescriptorToDotWrapper(superclass_descriptor);
1394      fprintf(out_file_, " extends=\"%s\"\n", dot.c_str());
1395    }
1396    fprintf(out_file_, " interface=%s\n",
1397            QuotedBool((class_def->GetAccessFlags() & kAccInterface) != 0));
1398    fprintf(out_file_, " abstract=%s\n",
1399            QuotedBool((class_def->GetAccessFlags() & kAccAbstract) != 0));
1400    fprintf(out_file_, " static=%s\n", QuotedBool((class_def->GetAccessFlags() & kAccStatic) != 0));
1401    fprintf(out_file_, " final=%s\n", QuotedBool((class_def->GetAccessFlags() & kAccFinal) != 0));
1402    // The "deprecated=" not knowable w/o parsing annotations.
1403    fprintf(out_file_, " visibility=%s\n", QuotedVisibility(class_def->GetAccessFlags()));
1404    fprintf(out_file_, ">\n");
1405  }
1406
1407  // Interfaces.
1408  const dex_ir::TypeIdVector* interfaces = class_def->Interfaces();
1409  if (interfaces != nullptr) {
1410    for (uint32_t i = 0; i < interfaces->size(); i++) {
1411      DumpInterface((*interfaces)[i], i);
1412    }  // for
1413  }
1414
1415  // Fields and methods.
1416  dex_ir::ClassData* class_data = class_def->GetClassData();
1417  // Prepare data for static fields.
1418  dex_ir::EncodedArrayItem* static_values = class_def->StaticValues();
1419  dex_ir::EncodedValueVector* encoded_values =
1420      static_values == nullptr ? nullptr : static_values->GetEncodedValues();
1421  const uint32_t encoded_values_size = (encoded_values == nullptr) ? 0 : encoded_values->size();
1422
1423  // Static fields.
1424  if (options_.output_format_ == kOutputPlain) {
1425    fprintf(out_file_, "  Static fields     -\n");
1426  }
1427  if (class_data != nullptr) {
1428    dex_ir::FieldItemVector* static_fields = class_data->StaticFields();
1429    if (static_fields != nullptr) {
1430      for (uint32_t i = 0; i < static_fields->size(); i++) {
1431        DumpSField(header,
1432                   (*static_fields)[i]->GetFieldId()->GetIndex(),
1433                   (*static_fields)[i]->GetAccessFlags(),
1434                   i,
1435                   i < encoded_values_size ? (*encoded_values)[i].get() : nullptr);
1436      }  // for
1437    }
1438  }
1439
1440  // Instance fields.
1441  if (options_.output_format_ == kOutputPlain) {
1442    fprintf(out_file_, "  Instance fields   -\n");
1443  }
1444  if (class_data != nullptr) {
1445    dex_ir::FieldItemVector* instance_fields = class_data->InstanceFields();
1446    if (instance_fields != nullptr) {
1447      for (uint32_t i = 0; i < instance_fields->size(); i++) {
1448        DumpIField(header,
1449                   (*instance_fields)[i]->GetFieldId()->GetIndex(),
1450                   (*instance_fields)[i]->GetAccessFlags(),
1451                   i);
1452      }  // for
1453    }
1454  }
1455
1456  // Direct methods.
1457  if (options_.output_format_ == kOutputPlain) {
1458    fprintf(out_file_, "  Direct methods    -\n");
1459  }
1460  if (class_data != nullptr) {
1461    dex_ir::MethodItemVector* direct_methods = class_data->DirectMethods();
1462    if (direct_methods != nullptr) {
1463      for (uint32_t i = 0; i < direct_methods->size(); i++) {
1464        DumpMethod(header,
1465                   (*direct_methods)[i]->GetMethodId()->GetIndex(),
1466                   (*direct_methods)[i]->GetAccessFlags(),
1467                   (*direct_methods)[i]->GetCodeItem(),
1468                 i);
1469      }  // for
1470    }
1471  }
1472
1473  // Virtual methods.
1474  if (options_.output_format_ == kOutputPlain) {
1475    fprintf(out_file_, "  Virtual methods   -\n");
1476  }
1477  if (class_data != nullptr) {
1478    dex_ir::MethodItemVector* virtual_methods = class_data->VirtualMethods();
1479    if (virtual_methods != nullptr) {
1480      for (uint32_t i = 0; i < virtual_methods->size(); i++) {
1481        DumpMethod(header,
1482                   (*virtual_methods)[i]->GetMethodId()->GetIndex(),
1483                   (*virtual_methods)[i]->GetAccessFlags(),
1484                   (*virtual_methods)[i]->GetCodeItem(),
1485                   i);
1486      }  // for
1487    }
1488  }
1489
1490  // End of class.
1491  if (options_.output_format_ == kOutputPlain) {
1492    const char* file_name = "unknown";
1493    if (class_def->SourceFile() != nullptr) {
1494      file_name = class_def->SourceFile()->Data();
1495    }
1496    const dex_ir::StringId* source_file = class_def->SourceFile();
1497    fprintf(out_file_, "  source_file_idx   : %d (%s)\n\n",
1498            source_file == nullptr ? 0xffffffffU : source_file->GetIndex(), file_name);
1499  } else if (options_.output_format_ == kOutputXml) {
1500    fprintf(out_file_, "</class>\n");
1501  }
1502
1503  free(access_str);
1504}
1505
1506/*
1507 * Dumps the requested sections of the file.
1508 */
1509static void ProcessDexFile(const char* file_name, const DexFile* dex_file, size_t dex_file_index) {
1510  if (options_.verbose_) {
1511    fprintf(out_file_, "Opened '%s', DEX version '%.3s'\n",
1512            file_name, dex_file->GetHeader().magic_ + 4);
1513  }
1514  std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file));
1515
1516  if (options_.visualize_pattern_) {
1517    VisualizeDexLayout(header.get(), dex_file, dex_file_index);
1518    return;
1519  }
1520
1521  // Headers.
1522  if (options_.show_file_headers_) {
1523    DumpFileHeader(header.get());
1524  }
1525
1526  // Open XML context.
1527  if (options_.output_format_ == kOutputXml) {
1528    fprintf(out_file_, "<api>\n");
1529  }
1530
1531  // Iterate over all classes.
1532  char* package = nullptr;
1533  const uint32_t class_defs_size = header->GetCollections().ClassDefsSize();
1534  for (uint32_t i = 0; i < class_defs_size; i++) {
1535    DumpClass(dex_file, header.get(), i, &package);
1536  }  // for
1537
1538  // Free the last package allocated.
1539  if (package != nullptr) {
1540    fprintf(out_file_, "</package>\n");
1541    free(package);
1542  }
1543
1544  // Close XML context.
1545  if (options_.output_format_ == kOutputXml) {
1546    fprintf(out_file_, "</api>\n");
1547  }
1548
1549  // Output dex file.
1550  if (options_.output_dex_directory_ != nullptr) {
1551    std::string output_location(options_.output_dex_directory_);
1552    size_t last_slash = dex_file->GetLocation().rfind("/");
1553    output_location.append(dex_file->GetLocation().substr(last_slash));
1554    DexWriter::OutputDexFile(*header, output_location.c_str());
1555  }
1556}
1557
1558/*
1559 * Processes a single file (either direct .dex or indirect .zip/.jar/.apk).
1560 */
1561int ProcessFile(const char* file_name) {
1562  if (options_.verbose_) {
1563    fprintf(out_file_, "Processing '%s'...\n", file_name);
1564  }
1565
1566  // If the file is not a .dex file, the function tries .zip/.jar/.apk files,
1567  // all of which are Zip archives with "classes.dex" inside.
1568  const bool verify_checksum = !options_.ignore_bad_checksum_;
1569  std::string error_msg;
1570  std::vector<std::unique_ptr<const DexFile>> dex_files;
1571  if (!DexFile::Open(file_name, file_name, verify_checksum, &error_msg, &dex_files)) {
1572    // Display returned error message to user. Note that this error behavior
1573    // differs from the error messages shown by the original Dalvik dexdump.
1574    fputs(error_msg.c_str(), stderr);
1575    fputc('\n', stderr);
1576    return -1;
1577  }
1578
1579  // Success. Either report checksum verification or process
1580  // all dex files found in given file.
1581  if (options_.checksum_only_) {
1582    fprintf(out_file_, "Checksum verified\n");
1583  } else {
1584    for (size_t i = 0; i < dex_files.size(); i++) {
1585      ProcessDexFile(file_name, dex_files[i].get(), i);
1586    }
1587  }
1588  return 0;
1589}
1590
1591}  // namespace art
1592