dexlayout.cc revision 219cb9021fa74af7773066ffb8fc77ac85f3d0de
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#include <sys/mman.h>  // For the PROT_* and MAP_* constants.
28
29#include <iostream>
30#include <memory>
31#include <sstream>
32#include <vector>
33
34#include "android-base/stringprintf.h"
35
36#include "dex_file-inl.h"
37#include "dex_file_layout.h"
38#include "dex_file_loader.h"
39#include "dex_file_types.h"
40#include "dex_file_verifier.h"
41#include "dex_instruction-inl.h"
42#include "dex_ir_builder.h"
43#include "dex_verify.h"
44#include "dex_visualize.h"
45#include "dex_writer.h"
46#include "jit/profile_compilation_info.h"
47#include "mem_map.h"
48#include "os.h"
49#include "utils.h"
50
51namespace art {
52
53using android::base::StringPrintf;
54
55// Setting this to false disables class def layout entirely, which is stronger than strictly
56// necessary to ensure the partial order w.r.t. class derivation. TODO: Re-enable (b/68317550).
57static constexpr bool kChangeClassDefOrder = false;
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, FILE* out_file) {
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, FILE* out_file) {
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/*
363 * Helper for dumpInstruction(), which builds the string
364 * representation for the index in the given instruction.
365 * Returns a pointer to a buffer of sufficient size.
366 */
367static std::unique_ptr<char[]> IndexString(dex_ir::Header* header,
368                                           const Instruction* dec_insn,
369                                           size_t buf_size) {
370  std::unique_ptr<char[]> buf(new char[buf_size]);
371  // Determine index and width of the string.
372  uint32_t index = 0;
373  uint32_t secondary_index = dex::kDexNoIndex;
374  uint32_t width = 4;
375  switch (Instruction::FormatOf(dec_insn->Opcode())) {
376    // SOME NOT SUPPORTED:
377    // case Instruction::k20bc:
378    case Instruction::k21c:
379    case Instruction::k35c:
380    // case Instruction::k35ms:
381    case Instruction::k3rc:
382    // case Instruction::k3rms:
383    // case Instruction::k35mi:
384    // case Instruction::k3rmi:
385      index = dec_insn->VRegB();
386      width = 4;
387      break;
388    case Instruction::k31c:
389      index = dec_insn->VRegB();
390      width = 8;
391      break;
392    case Instruction::k22c:
393    // case Instruction::k22cs:
394      index = dec_insn->VRegC();
395      width = 4;
396      break;
397    case Instruction::k45cc:
398    case Instruction::k4rcc:
399      index = dec_insn->VRegB();
400      secondary_index = dec_insn->VRegH();
401      width = 4;
402      break;
403    default:
404      break;
405  }  // switch
406
407  // Determine index type.
408  size_t outSize = 0;
409  switch (Instruction::IndexTypeOf(dec_insn->Opcode())) {
410    case Instruction::kIndexUnknown:
411      // This function should never get called for this type, but do
412      // something sensible here, just to help with debugging.
413      outSize = snprintf(buf.get(), buf_size, "<unknown-index>");
414      break;
415    case Instruction::kIndexNone:
416      // This function should never get called for this type, but do
417      // something sensible here, just to help with debugging.
418      outSize = snprintf(buf.get(), buf_size, "<no-index>");
419      break;
420    case Instruction::kIndexTypeRef:
421      if (index < header->GetCollections().TypeIdsSize()) {
422        const char* tp = header->GetCollections().GetTypeId(index)->GetStringId()->Data();
423        outSize = snprintf(buf.get(), buf_size, "%s // type@%0*x", tp, width, index);
424      } else {
425        outSize = snprintf(buf.get(), buf_size, "<type?> // type@%0*x", width, index);
426      }
427      break;
428    case Instruction::kIndexStringRef:
429      if (index < header->GetCollections().StringIdsSize()) {
430        const char* st = header->GetCollections().GetStringId(index)->Data();
431        outSize = snprintf(buf.get(), buf_size, "\"%s\" // string@%0*x", st, width, index);
432      } else {
433        outSize = snprintf(buf.get(), buf_size, "<string?> // string@%0*x", width, index);
434      }
435      break;
436    case Instruction::kIndexMethodRef:
437      if (index < header->GetCollections().MethodIdsSize()) {
438        dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index);
439        const char* name = method_id->Name()->Data();
440        std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
441        const char* back_descriptor = method_id->Class()->GetStringId()->Data();
442        outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // method@%0*x",
443                           back_descriptor, name, type_descriptor.c_str(), width, index);
444      } else {
445        outSize = snprintf(buf.get(), buf_size, "<method?> // method@%0*x", width, index);
446      }
447      break;
448    case Instruction::kIndexFieldRef:
449      if (index < header->GetCollections().FieldIdsSize()) {
450        dex_ir::FieldId* field_id = header->GetCollections().GetFieldId(index);
451        const char* name = field_id->Name()->Data();
452        const char* type_descriptor = field_id->Type()->GetStringId()->Data();
453        const char* back_descriptor = field_id->Class()->GetStringId()->Data();
454        outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // field@%0*x",
455                           back_descriptor, name, type_descriptor, width, index);
456      } else {
457        outSize = snprintf(buf.get(), buf_size, "<field?> // field@%0*x", width, index);
458      }
459      break;
460    case Instruction::kIndexVtableOffset:
461      outSize = snprintf(buf.get(), buf_size, "[%0*x] // vtable #%0*x",
462                         width, index, width, index);
463      break;
464    case Instruction::kIndexFieldOffset:
465      outSize = snprintf(buf.get(), buf_size, "[obj+%0*x]", width, index);
466      break;
467    case Instruction::kIndexMethodAndProtoRef: {
468      std::string method("<method?>");
469      std::string proto("<proto?>");
470      if (index < header->GetCollections().MethodIdsSize()) {
471        dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index);
472        const char* name = method_id->Name()->Data();
473        std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
474        const char* back_descriptor = method_id->Class()->GetStringId()->Data();
475        method = StringPrintf("%s.%s:%s", back_descriptor, name, type_descriptor.c_str());
476      }
477      if (secondary_index < header->GetCollections().ProtoIdsSize()) {
478        dex_ir::ProtoId* proto_id = header->GetCollections().GetProtoId(secondary_index);
479        proto = GetSignatureForProtoId(proto_id);
480      }
481      outSize = snprintf(buf.get(), buf_size, "%s, %s // method@%0*x, proto@%0*x",
482                         method.c_str(), proto.c_str(), width, index, width, secondary_index);
483    }
484    break;
485    // SOME NOT SUPPORTED:
486    // case Instruction::kIndexVaries:
487    // case Instruction::kIndexInlineMethod:
488    default:
489      outSize = snprintf(buf.get(), buf_size, "<?>");
490      break;
491  }  // switch
492
493  // Determine success of string construction.
494  if (outSize >= buf_size) {
495    // The buffer wasn't big enough; retry with computed size. Note: snprintf()
496    // doesn't count/ the '\0' as part of its returned size, so we add explicit
497    // space for it here.
498    return IndexString(header, dec_insn, outSize + 1);
499  }
500  return buf;
501}
502
503/*
504 * Dumps encoded annotation.
505 */
506void DexLayout::DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation) {
507  fputs(annotation->GetType()->GetStringId()->Data(), out_file_);
508  // Display all name=value pairs.
509  for (auto& subannotation : *annotation->GetAnnotationElements()) {
510    fputc(' ', out_file_);
511    fputs(subannotation->GetName()->Data(), out_file_);
512    fputc('=', out_file_);
513    DumpEncodedValue(subannotation->GetValue());
514  }
515}
516/*
517 * Dumps encoded value.
518 */
519void DexLayout::DumpEncodedValue(const dex_ir::EncodedValue* data) {
520  switch (data->Type()) {
521    case DexFile::kDexAnnotationByte:
522      fprintf(out_file_, "%" PRId8, data->GetByte());
523      break;
524    case DexFile::kDexAnnotationShort:
525      fprintf(out_file_, "%" PRId16, data->GetShort());
526      break;
527    case DexFile::kDexAnnotationChar:
528      fprintf(out_file_, "%" PRIu16, data->GetChar());
529      break;
530    case DexFile::kDexAnnotationInt:
531      fprintf(out_file_, "%" PRId32, data->GetInt());
532      break;
533    case DexFile::kDexAnnotationLong:
534      fprintf(out_file_, "%" PRId64, data->GetLong());
535      break;
536    case DexFile::kDexAnnotationFloat: {
537      fprintf(out_file_, "%g", data->GetFloat());
538      break;
539    }
540    case DexFile::kDexAnnotationDouble: {
541      fprintf(out_file_, "%g", data->GetDouble());
542      break;
543    }
544    case DexFile::kDexAnnotationString: {
545      dex_ir::StringId* string_id = data->GetStringId();
546      if (options_.output_format_ == kOutputPlain) {
547        DumpEscapedString(string_id->Data(), out_file_);
548      } else {
549        DumpXmlAttribute(string_id->Data(), out_file_);
550      }
551      break;
552    }
553    case DexFile::kDexAnnotationType: {
554      dex_ir::TypeId* type_id = data->GetTypeId();
555      fputs(type_id->GetStringId()->Data(), out_file_);
556      break;
557    }
558    case DexFile::kDexAnnotationField:
559    case DexFile::kDexAnnotationEnum: {
560      dex_ir::FieldId* field_id = data->GetFieldId();
561      fputs(field_id->Name()->Data(), out_file_);
562      break;
563    }
564    case DexFile::kDexAnnotationMethod: {
565      dex_ir::MethodId* method_id = data->GetMethodId();
566      fputs(method_id->Name()->Data(), out_file_);
567      break;
568    }
569    case DexFile::kDexAnnotationArray: {
570      fputc('{', out_file_);
571      // Display all elements.
572      for (auto& value : *data->GetEncodedArray()->GetEncodedValues()) {
573        fputc(' ', out_file_);
574        DumpEncodedValue(value.get());
575      }
576      fputs(" }", out_file_);
577      break;
578    }
579    case DexFile::kDexAnnotationAnnotation: {
580      DumpEncodedAnnotation(data->GetEncodedAnnotation());
581      break;
582    }
583    case DexFile::kDexAnnotationNull:
584      fputs("null", out_file_);
585      break;
586    case DexFile::kDexAnnotationBoolean:
587      fputs(StrBool(data->GetBoolean()), out_file_);
588      break;
589    default:
590      fputs("????", out_file_);
591      break;
592  }  // switch
593}
594
595/*
596 * Dumps the file header.
597 */
598void DexLayout::DumpFileHeader() {
599  char sanitized[8 * 2 + 1];
600  dex_ir::Collections& collections = header_->GetCollections();
601  fprintf(out_file_, "DEX file header:\n");
602  Asciify(sanitized, header_->Magic(), 8);
603  fprintf(out_file_, "magic               : '%s'\n", sanitized);
604  fprintf(out_file_, "checksum            : %08x\n", header_->Checksum());
605  fprintf(out_file_, "signature           : %02x%02x...%02x%02x\n",
606          header_->Signature()[0], header_->Signature()[1],
607          header_->Signature()[DexFile::kSha1DigestSize - 2],
608          header_->Signature()[DexFile::kSha1DigestSize - 1]);
609  fprintf(out_file_, "file_size           : %d\n", header_->FileSize());
610  fprintf(out_file_, "header_size         : %d\n", header_->HeaderSize());
611  fprintf(out_file_, "link_size           : %d\n", header_->LinkSize());
612  fprintf(out_file_, "link_off            : %d (0x%06x)\n",
613          header_->LinkOffset(), header_->LinkOffset());
614  fprintf(out_file_, "string_ids_size     : %d\n", collections.StringIdsSize());
615  fprintf(out_file_, "string_ids_off      : %d (0x%06x)\n",
616          collections.StringIdsOffset(), collections.StringIdsOffset());
617  fprintf(out_file_, "type_ids_size       : %d\n", collections.TypeIdsSize());
618  fprintf(out_file_, "type_ids_off        : %d (0x%06x)\n",
619          collections.TypeIdsOffset(), collections.TypeIdsOffset());
620  fprintf(out_file_, "proto_ids_size      : %d\n", collections.ProtoIdsSize());
621  fprintf(out_file_, "proto_ids_off       : %d (0x%06x)\n",
622          collections.ProtoIdsOffset(), collections.ProtoIdsOffset());
623  fprintf(out_file_, "field_ids_size      : %d\n", collections.FieldIdsSize());
624  fprintf(out_file_, "field_ids_off       : %d (0x%06x)\n",
625          collections.FieldIdsOffset(), collections.FieldIdsOffset());
626  fprintf(out_file_, "method_ids_size     : %d\n", collections.MethodIdsSize());
627  fprintf(out_file_, "method_ids_off      : %d (0x%06x)\n",
628          collections.MethodIdsOffset(), collections.MethodIdsOffset());
629  fprintf(out_file_, "class_defs_size     : %d\n", collections.ClassDefsSize());
630  fprintf(out_file_, "class_defs_off      : %d (0x%06x)\n",
631          collections.ClassDefsOffset(), collections.ClassDefsOffset());
632  fprintf(out_file_, "data_size           : %d\n", header_->DataSize());
633  fprintf(out_file_, "data_off            : %d (0x%06x)\n\n",
634          header_->DataOffset(), header_->DataOffset());
635}
636
637/*
638 * Dumps a class_def_item.
639 */
640void DexLayout::DumpClassDef(int idx) {
641  // General class information.
642  dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx);
643  fprintf(out_file_, "Class #%d header:\n", idx);
644  fprintf(out_file_, "class_idx           : %d\n", class_def->ClassType()->GetIndex());
645  fprintf(out_file_, "access_flags        : %d (0x%04x)\n",
646          class_def->GetAccessFlags(), class_def->GetAccessFlags());
647  uint32_t superclass_idx =  class_def->Superclass() == nullptr ?
648      DexFile::kDexNoIndex16 : class_def->Superclass()->GetIndex();
649  fprintf(out_file_, "superclass_idx      : %d\n", superclass_idx);
650  fprintf(out_file_, "interfaces_off      : %d (0x%06x)\n",
651          class_def->InterfacesOffset(), class_def->InterfacesOffset());
652  uint32_t source_file_offset = 0xffffffffU;
653  if (class_def->SourceFile() != nullptr) {
654    source_file_offset = class_def->SourceFile()->GetIndex();
655  }
656  fprintf(out_file_, "source_file_idx     : %d\n", source_file_offset);
657  uint32_t annotations_offset = 0;
658  if (class_def->Annotations() != nullptr) {
659    annotations_offset = class_def->Annotations()->GetOffset();
660  }
661  fprintf(out_file_, "annotations_off     : %d (0x%06x)\n",
662          annotations_offset, annotations_offset);
663  if (class_def->GetClassData() == nullptr) {
664    fprintf(out_file_, "class_data_off      : %d (0x%06x)\n", 0, 0);
665  } else {
666    fprintf(out_file_, "class_data_off      : %d (0x%06x)\n",
667            class_def->GetClassData()->GetOffset(), class_def->GetClassData()->GetOffset());
668  }
669
670  // Fields and methods.
671  dex_ir::ClassData* class_data = class_def->GetClassData();
672  if (class_data != nullptr && class_data->StaticFields() != nullptr) {
673    fprintf(out_file_, "static_fields_size  : %zu\n", class_data->StaticFields()->size());
674  } else {
675    fprintf(out_file_, "static_fields_size  : 0\n");
676  }
677  if (class_data != nullptr && class_data->InstanceFields() != nullptr) {
678    fprintf(out_file_, "instance_fields_size: %zu\n", class_data->InstanceFields()->size());
679  } else {
680    fprintf(out_file_, "instance_fields_size: 0\n");
681  }
682  if (class_data != nullptr && class_data->DirectMethods() != nullptr) {
683    fprintf(out_file_, "direct_methods_size : %zu\n", class_data->DirectMethods()->size());
684  } else {
685    fprintf(out_file_, "direct_methods_size : 0\n");
686  }
687  if (class_data != nullptr && class_data->VirtualMethods() != nullptr) {
688    fprintf(out_file_, "virtual_methods_size: %zu\n", class_data->VirtualMethods()->size());
689  } else {
690    fprintf(out_file_, "virtual_methods_size: 0\n");
691  }
692  fprintf(out_file_, "\n");
693}
694
695/**
696 * Dumps an annotation set item.
697 */
698void DexLayout::DumpAnnotationSetItem(dex_ir::AnnotationSetItem* set_item) {
699  if (set_item == nullptr || set_item->GetItems()->size() == 0) {
700    fputs("  empty-annotation-set\n", out_file_);
701    return;
702  }
703  for (dex_ir::AnnotationItem* annotation : *set_item->GetItems()) {
704    if (annotation == nullptr) {
705      continue;
706    }
707    fputs("  ", out_file_);
708    switch (annotation->GetVisibility()) {
709      case DexFile::kDexVisibilityBuild:   fputs("VISIBILITY_BUILD ",   out_file_); break;
710      case DexFile::kDexVisibilityRuntime: fputs("VISIBILITY_RUNTIME ", out_file_); break;
711      case DexFile::kDexVisibilitySystem:  fputs("VISIBILITY_SYSTEM ",  out_file_); break;
712      default:                             fputs("VISIBILITY_UNKNOWN ", out_file_); break;
713    }  // switch
714    DumpEncodedAnnotation(annotation->GetAnnotation());
715    fputc('\n', out_file_);
716  }
717}
718
719/*
720 * Dumps class annotations.
721 */
722void DexLayout::DumpClassAnnotations(int idx) {
723  dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx);
724  dex_ir::AnnotationsDirectoryItem* annotations_directory = class_def->Annotations();
725  if (annotations_directory == nullptr) {
726    return;  // none
727  }
728
729  fprintf(out_file_, "Class #%d annotations:\n", idx);
730
731  dex_ir::AnnotationSetItem* class_set_item = annotations_directory->GetClassAnnotation();
732  dex_ir::FieldAnnotationVector* fields = annotations_directory->GetFieldAnnotations();
733  dex_ir::MethodAnnotationVector* methods = annotations_directory->GetMethodAnnotations();
734  dex_ir::ParameterAnnotationVector* parameters = annotations_directory->GetParameterAnnotations();
735
736  // Annotations on the class itself.
737  if (class_set_item != nullptr) {
738    fprintf(out_file_, "Annotations on class\n");
739    DumpAnnotationSetItem(class_set_item);
740  }
741
742  // Annotations on fields.
743  if (fields != nullptr) {
744    for (auto& field : *fields) {
745      const dex_ir::FieldId* field_id = field->GetFieldId();
746      const uint32_t field_idx = field_id->GetIndex();
747      const char* field_name = field_id->Name()->Data();
748      fprintf(out_file_, "Annotations on field #%u '%s'\n", field_idx, field_name);
749      DumpAnnotationSetItem(field->GetAnnotationSetItem());
750    }
751  }
752
753  // Annotations on methods.
754  if (methods != nullptr) {
755    for (auto& method : *methods) {
756      const dex_ir::MethodId* method_id = method->GetMethodId();
757      const uint32_t method_idx = method_id->GetIndex();
758      const char* method_name = method_id->Name()->Data();
759      fprintf(out_file_, "Annotations on method #%u '%s'\n", method_idx, method_name);
760      DumpAnnotationSetItem(method->GetAnnotationSetItem());
761    }
762  }
763
764  // Annotations on method parameters.
765  if (parameters != nullptr) {
766    for (auto& parameter : *parameters) {
767      const dex_ir::MethodId* method_id = parameter->GetMethodId();
768      const uint32_t method_idx = method_id->GetIndex();
769      const char* method_name = method_id->Name()->Data();
770      fprintf(out_file_, "Annotations on method #%u '%s' parameters\n", method_idx, method_name);
771      uint32_t j = 0;
772      for (dex_ir::AnnotationSetItem* annotation : *parameter->GetAnnotations()->GetItems()) {
773        fprintf(out_file_, "#%u\n", j);
774        DumpAnnotationSetItem(annotation);
775        ++j;
776      }
777    }
778  }
779
780  fputc('\n', out_file_);
781}
782
783/*
784 * Dumps an interface that a class declares to implement.
785 */
786void DexLayout::DumpInterface(const dex_ir::TypeId* type_item, int i) {
787  const char* interface_name = type_item->GetStringId()->Data();
788  if (options_.output_format_ == kOutputPlain) {
789    fprintf(out_file_, "    #%d              : '%s'\n", i, interface_name);
790  } else {
791    std::string dot(DescriptorToDotWrapper(interface_name));
792    fprintf(out_file_, "<implements name=\"%s\">\n</implements>\n", dot.c_str());
793  }
794}
795
796/*
797 * Dumps the catches table associated with the code.
798 */
799void DexLayout::DumpCatches(const dex_ir::CodeItem* code) {
800  const uint16_t tries_size = code->TriesSize();
801
802  // No catch table.
803  if (tries_size == 0) {
804    fprintf(out_file_, "      catches       : (none)\n");
805    return;
806  }
807
808  // Dump all table entries.
809  fprintf(out_file_, "      catches       : %d\n", tries_size);
810  std::vector<std::unique_ptr<const dex_ir::TryItem>>* tries = code->Tries();
811  for (uint32_t i = 0; i < tries_size; i++) {
812    const dex_ir::TryItem* try_item = (*tries)[i].get();
813    const uint32_t start = try_item->StartAddr();
814    const uint32_t end = start + try_item->InsnCount();
815    fprintf(out_file_, "        0x%04x - 0x%04x\n", start, end);
816    for (auto& handler : *try_item->GetHandlers()->GetHandlers()) {
817      const dex_ir::TypeId* type_id = handler->GetTypeId();
818      const char* descriptor = (type_id == nullptr) ? "<any>" : type_id->GetStringId()->Data();
819      fprintf(out_file_, "          %s -> 0x%04x\n", descriptor, handler->GetAddress());
820    }  // for
821  }  // for
822}
823
824/*
825 * Dumps a single instruction.
826 */
827void DexLayout::DumpInstruction(const dex_ir::CodeItem* code,
828                                uint32_t code_offset,
829                                uint32_t insn_idx,
830                                uint32_t insn_width,
831                                const Instruction* dec_insn) {
832  // Address of instruction (expressed as byte offset).
833  fprintf(out_file_, "%06x:", code_offset + 0x10 + insn_idx * 2);
834
835  // Dump (part of) raw bytes.
836  const uint16_t* insns = code->Insns();
837  for (uint32_t i = 0; i < 8; i++) {
838    if (i < insn_width) {
839      if (i == 7) {
840        fprintf(out_file_, " ... ");
841      } else {
842        // Print 16-bit value in little-endian order.
843        const uint8_t* bytePtr = (const uint8_t*) &insns[insn_idx + i];
844        fprintf(out_file_, " %02x%02x", bytePtr[0], bytePtr[1]);
845      }
846    } else {
847      fputs("     ", out_file_);
848    }
849  }  // for
850
851  // Dump pseudo-instruction or opcode.
852  if (dec_insn->Opcode() == Instruction::NOP) {
853    const uint16_t instr = Get2LE((const uint8_t*) &insns[insn_idx]);
854    if (instr == Instruction::kPackedSwitchSignature) {
855      fprintf(out_file_, "|%04x: packed-switch-data (%d units)", insn_idx, insn_width);
856    } else if (instr == Instruction::kSparseSwitchSignature) {
857      fprintf(out_file_, "|%04x: sparse-switch-data (%d units)", insn_idx, insn_width);
858    } else if (instr == Instruction::kArrayDataSignature) {
859      fprintf(out_file_, "|%04x: array-data (%d units)", insn_idx, insn_width);
860    } else {
861      fprintf(out_file_, "|%04x: nop // spacer", insn_idx);
862    }
863  } else {
864    fprintf(out_file_, "|%04x: %s", insn_idx, dec_insn->Name());
865  }
866
867  // Set up additional argument.
868  std::unique_ptr<char[]> index_buf;
869  if (Instruction::IndexTypeOf(dec_insn->Opcode()) != Instruction::kIndexNone) {
870    index_buf = IndexString(header_, dec_insn, 200);
871  }
872
873  // Dump the instruction.
874  //
875  // NOTE: pDecInsn->DumpString(pDexFile) differs too much from original.
876  //
877  switch (Instruction::FormatOf(dec_insn->Opcode())) {
878    case Instruction::k10x:        // op
879      break;
880    case Instruction::k12x:        // op vA, vB
881      fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB());
882      break;
883    case Instruction::k11n:        // op vA, #+B
884      fprintf(out_file_, " v%d, #int %d // #%x",
885              dec_insn->VRegA(), (int32_t) dec_insn->VRegB(), (uint8_t)dec_insn->VRegB());
886      break;
887    case Instruction::k11x:        // op vAA
888      fprintf(out_file_, " v%d", dec_insn->VRegA());
889      break;
890    case Instruction::k10t:        // op +AA
891    case Instruction::k20t: {      // op +AAAA
892      const int32_t targ = (int32_t) dec_insn->VRegA();
893      fprintf(out_file_, " %04x // %c%04x",
894              insn_idx + targ,
895              (targ < 0) ? '-' : '+',
896              (targ < 0) ? -targ : targ);
897      break;
898    }
899    case Instruction::k22x:        // op vAA, vBBBB
900      fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB());
901      break;
902    case Instruction::k21t: {     // op vAA, +BBBB
903      const int32_t targ = (int32_t) dec_insn->VRegB();
904      fprintf(out_file_, " v%d, %04x // %c%04x", dec_insn->VRegA(),
905              insn_idx + targ,
906              (targ < 0) ? '-' : '+',
907              (targ < 0) ? -targ : targ);
908      break;
909    }
910    case Instruction::k21s:        // op vAA, #+BBBB
911      fprintf(out_file_, " v%d, #int %d // #%x",
912              dec_insn->VRegA(), (int32_t) dec_insn->VRegB(), (uint16_t)dec_insn->VRegB());
913      break;
914    case Instruction::k21h:        // op vAA, #+BBBB0000[00000000]
915      // The printed format varies a bit based on the actual opcode.
916      if (dec_insn->Opcode() == Instruction::CONST_HIGH16) {
917        const int32_t value = dec_insn->VRegB() << 16;
918        fprintf(out_file_, " v%d, #int %d // #%x",
919                dec_insn->VRegA(), value, (uint16_t) dec_insn->VRegB());
920      } else {
921        const int64_t value = ((int64_t) dec_insn->VRegB()) << 48;
922        fprintf(out_file_, " v%d, #long %" PRId64 " // #%x",
923                dec_insn->VRegA(), value, (uint16_t) dec_insn->VRegB());
924      }
925      break;
926    case Instruction::k21c:        // op vAA, thing@BBBB
927    case Instruction::k31c:        // op vAA, thing@BBBBBBBB
928      fprintf(out_file_, " v%d, %s", dec_insn->VRegA(), index_buf.get());
929      break;
930    case Instruction::k23x:        // op vAA, vBB, vCC
931      fprintf(out_file_, " v%d, v%d, v%d",
932              dec_insn->VRegA(), dec_insn->VRegB(), dec_insn->VRegC());
933      break;
934    case Instruction::k22b:        // op vAA, vBB, #+CC
935      fprintf(out_file_, " v%d, v%d, #int %d // #%02x",
936              dec_insn->VRegA(), dec_insn->VRegB(),
937              (int32_t) dec_insn->VRegC(), (uint8_t) dec_insn->VRegC());
938      break;
939    case Instruction::k22t: {      // op vA, vB, +CCCC
940      const int32_t targ = (int32_t) dec_insn->VRegC();
941      fprintf(out_file_, " v%d, v%d, %04x // %c%04x",
942              dec_insn->VRegA(), dec_insn->VRegB(),
943              insn_idx + targ,
944              (targ < 0) ? '-' : '+',
945              (targ < 0) ? -targ : targ);
946      break;
947    }
948    case Instruction::k22s:        // op vA, vB, #+CCCC
949      fprintf(out_file_, " v%d, v%d, #int %d // #%04x",
950              dec_insn->VRegA(), dec_insn->VRegB(),
951              (int32_t) dec_insn->VRegC(), (uint16_t) dec_insn->VRegC());
952      break;
953    case Instruction::k22c:        // op vA, vB, thing@CCCC
954    // NOT SUPPORTED:
955    // case Instruction::k22cs:    // [opt] op vA, vB, field offset CCCC
956      fprintf(out_file_, " v%d, v%d, %s",
957              dec_insn->VRegA(), dec_insn->VRegB(), index_buf.get());
958      break;
959    case Instruction::k30t:
960      fprintf(out_file_, " #%08x", dec_insn->VRegA());
961      break;
962    case Instruction::k31i: {     // op vAA, #+BBBBBBBB
963      // This is often, but not always, a float.
964      union {
965        float f;
966        uint32_t i;
967      } conv;
968      conv.i = dec_insn->VRegB();
969      fprintf(out_file_, " v%d, #float %g // #%08x",
970              dec_insn->VRegA(), conv.f, dec_insn->VRegB());
971      break;
972    }
973    case Instruction::k31t:       // op vAA, offset +BBBBBBBB
974      fprintf(out_file_, " v%d, %08x // +%08x",
975              dec_insn->VRegA(), insn_idx + dec_insn->VRegB(), dec_insn->VRegB());
976      break;
977    case Instruction::k32x:        // op vAAAA, vBBBB
978      fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB());
979      break;
980    case Instruction::k35c:           // op {vC, vD, vE, vF, vG}, thing@BBBB
981    case Instruction::k45cc: {        // op {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH
982    // NOT SUPPORTED:
983    // case Instruction::k35ms:       // [opt] invoke-virtual+super
984    // case Instruction::k35mi:       // [opt] inline invoke
985      uint32_t arg[Instruction::kMaxVarArgRegs];
986      dec_insn->GetVarArgs(arg);
987      fputs(" {", out_file_);
988      for (int i = 0, n = dec_insn->VRegA(); i < n; i++) {
989        if (i == 0) {
990          fprintf(out_file_, "v%d", arg[i]);
991        } else {
992          fprintf(out_file_, ", v%d", arg[i]);
993        }
994      }  // for
995      fprintf(out_file_, "}, %s", index_buf.get());
996      break;
997    }
998    case Instruction::k3rc:           // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB
999    case Instruction::k4rcc:          // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB, proto@HHHH
1000    // NOT SUPPORTED:
1001    // case Instruction::k3rms:       // [opt] invoke-virtual+super/range
1002    // case Instruction::k3rmi:       // [opt] execute-inline/range
1003      {
1004        // This doesn't match the "dx" output when some of the args are
1005        // 64-bit values -- dx only shows the first register.
1006        fputs(" {", out_file_);
1007        for (int i = 0, n = dec_insn->VRegA(); i < n; i++) {
1008          if (i == 0) {
1009            fprintf(out_file_, "v%d", dec_insn->VRegC() + i);
1010          } else {
1011            fprintf(out_file_, ", v%d", dec_insn->VRegC() + i);
1012          }
1013        }  // for
1014        fprintf(out_file_, "}, %s", index_buf.get());
1015      }
1016      break;
1017    case Instruction::k51l: {      // op vAA, #+BBBBBBBBBBBBBBBB
1018      // This is often, but not always, a double.
1019      union {
1020        double d;
1021        uint64_t j;
1022      } conv;
1023      conv.j = dec_insn->WideVRegB();
1024      fprintf(out_file_, " v%d, #double %g // #%016" PRIx64,
1025              dec_insn->VRegA(), conv.d, dec_insn->WideVRegB());
1026      break;
1027    }
1028    // NOT SUPPORTED:
1029    // case Instruction::k00x:        // unknown op or breakpoint
1030    //    break;
1031    default:
1032      fprintf(out_file_, " ???");
1033      break;
1034  }  // switch
1035
1036  fputc('\n', out_file_);
1037}
1038
1039/*
1040 * Dumps a bytecode disassembly.
1041 */
1042void DexLayout::DumpBytecodes(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset) {
1043  dex_ir::MethodId* method_id = header_->GetCollections().GetMethodId(idx);
1044  const char* name = method_id->Name()->Data();
1045  std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
1046  const char* back_descriptor = method_id->Class()->GetStringId()->Data();
1047
1048  // Generate header.
1049  std::string dot(DescriptorToDotWrapper(back_descriptor));
1050  fprintf(out_file_, "%06x:                                        |[%06x] %s.%s:%s\n",
1051          code_offset, code_offset, dot.c_str(), name, type_descriptor.c_str());
1052
1053  // Iterate over all instructions.
1054  for (const DexInstructionPcPair& inst : code->Instructions()) {
1055    const uint32_t insn_width = inst->SizeInCodeUnits();
1056    if (insn_width == 0) {
1057      fprintf(stderr, "GLITCH: zero-width instruction at idx=0x%04x\n", inst.DexPc());
1058      break;
1059    }
1060    DumpInstruction(code, code_offset, inst.DexPc(), insn_width, &inst.Inst());
1061  }  // for
1062}
1063
1064/*
1065 * Callback for dumping each positions table entry.
1066 */
1067static bool DumpPositionsCb(void* context, const DexFile::PositionInfo& entry) {
1068  FILE* out_file = reinterpret_cast<FILE*>(context);
1069  fprintf(out_file, "        0x%04x line=%d\n", entry.address_, entry.line_);
1070  return false;
1071}
1072
1073/*
1074 * Callback for dumping locals table entry.
1075 */
1076static void DumpLocalsCb(void* context, const DexFile::LocalInfo& entry) {
1077  const char* signature = entry.signature_ != nullptr ? entry.signature_ : "";
1078  FILE* out_file = reinterpret_cast<FILE*>(context);
1079  fprintf(out_file, "        0x%04x - 0x%04x reg=%d %s %s %s\n",
1080          entry.start_address_, entry.end_address_, entry.reg_,
1081          entry.name_, entry.descriptor_, signature);
1082}
1083
1084/*
1085 * Lookup functions.
1086 */
1087static const char* StringDataByIdx(uint32_t idx, dex_ir::Collections& collections) {
1088  dex_ir::StringId* string_id = collections.GetStringIdOrNullPtr(idx);
1089  if (string_id == nullptr) {
1090    return nullptr;
1091  }
1092  return string_id->Data();
1093}
1094
1095static const char* StringDataByTypeIdx(uint16_t idx, dex_ir::Collections& collections) {
1096  dex_ir::TypeId* type_id = collections.GetTypeIdOrNullPtr(idx);
1097  if (type_id == nullptr) {
1098    return nullptr;
1099  }
1100  dex_ir::StringId* string_id = type_id->GetStringId();
1101  if (string_id == nullptr) {
1102    return nullptr;
1103  }
1104  return string_id->Data();
1105}
1106
1107
1108/*
1109 * Dumps code of a method.
1110 */
1111void DexLayout::DumpCode(uint32_t idx,
1112                         const dex_ir::CodeItem* code,
1113                         uint32_t code_offset,
1114                         const char* declaring_class_descriptor,
1115                         const char* method_name,
1116                         bool is_static,
1117                         const dex_ir::ProtoId* proto) {
1118  fprintf(out_file_, "      registers     : %d\n", code->RegistersSize());
1119  fprintf(out_file_, "      ins           : %d\n", code->InsSize());
1120  fprintf(out_file_, "      outs          : %d\n", code->OutsSize());
1121  fprintf(out_file_, "      insns size    : %d 16-bit code units\n",
1122          code->InsnsSize());
1123
1124  // Bytecode disassembly, if requested.
1125  if (options_.disassemble_) {
1126    DumpBytecodes(idx, code, code_offset);
1127  }
1128
1129  // Try-catch blocks.
1130  DumpCatches(code);
1131
1132  // Positions and locals table in the debug info.
1133  dex_ir::DebugInfoItem* debug_info = code->DebugInfo();
1134  fprintf(out_file_, "      positions     : \n");
1135  if (debug_info != nullptr) {
1136    DexFile::DecodeDebugPositionInfo(debug_info->GetDebugInfo(),
1137                                     [this](uint32_t idx) {
1138                                       return StringDataByIdx(idx, this->header_->GetCollections());
1139                                     },
1140                                     DumpPositionsCb,
1141                                     out_file_);
1142  }
1143  fprintf(out_file_, "      locals        : \n");
1144  if (debug_info != nullptr) {
1145    std::vector<const char*> arg_descriptors;
1146    const dex_ir::TypeList* parameters = proto->Parameters();
1147    if (parameters != nullptr) {
1148      const dex_ir::TypeIdVector* parameter_type_vector = parameters->GetTypeList();
1149      if (parameter_type_vector != nullptr) {
1150        for (const dex_ir::TypeId* type_id : *parameter_type_vector) {
1151          arg_descriptors.push_back(type_id->GetStringId()->Data());
1152        }
1153      }
1154    }
1155    DexFile::DecodeDebugLocalInfo(debug_info->GetDebugInfo(),
1156                                  "DexLayout in-memory",
1157                                  declaring_class_descriptor,
1158                                  arg_descriptors,
1159                                  method_name,
1160                                  is_static,
1161                                  code->RegistersSize(),
1162                                  code->InsSize(),
1163                                  code->InsnsSize(),
1164                                  [this](uint32_t idx) {
1165                                    return StringDataByIdx(idx, this->header_->GetCollections());
1166                                  },
1167                                  [this](uint32_t idx) {
1168                                    return
1169                                        StringDataByTypeIdx(dchecked_integral_cast<uint16_t>(idx),
1170                                                            this->header_->GetCollections());
1171                                  },
1172                                  DumpLocalsCb,
1173                                  out_file_);
1174  }
1175}
1176
1177/*
1178 * Dumps a method.
1179 */
1180void DexLayout::DumpMethod(uint32_t idx, uint32_t flags, const dex_ir::CodeItem* code, int i) {
1181  // Bail for anything private if export only requested.
1182  if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) {
1183    return;
1184  }
1185
1186  dex_ir::MethodId* method_id = header_->GetCollections().GetMethodId(idx);
1187  const char* name = method_id->Name()->Data();
1188  char* type_descriptor = strdup(GetSignatureForProtoId(method_id->Proto()).c_str());
1189  const char* back_descriptor = method_id->Class()->GetStringId()->Data();
1190  char* access_str = CreateAccessFlagStr(flags, kAccessForMethod);
1191
1192  if (options_.output_format_ == kOutputPlain) {
1193    fprintf(out_file_, "    #%d              : (in %s)\n", i, back_descriptor);
1194    fprintf(out_file_, "      name          : '%s'\n", name);
1195    fprintf(out_file_, "      type          : '%s'\n", type_descriptor);
1196    fprintf(out_file_, "      access        : 0x%04x (%s)\n", flags, access_str);
1197    if (code == nullptr) {
1198      fprintf(out_file_, "      code          : (none)\n");
1199    } else {
1200      fprintf(out_file_, "      code          -\n");
1201      DumpCode(idx,
1202               code,
1203               code->GetOffset(),
1204               back_descriptor,
1205               name,
1206               (flags & kAccStatic) != 0,
1207               method_id->Proto());
1208    }
1209    if (options_.disassemble_) {
1210      fputc('\n', out_file_);
1211    }
1212  } else if (options_.output_format_ == kOutputXml) {
1213    const bool constructor = (name[0] == '<');
1214
1215    // Method name and prototype.
1216    if (constructor) {
1217      std::string dot(DescriptorClassToDot(back_descriptor));
1218      fprintf(out_file_, "<constructor name=\"%s\"\n", dot.c_str());
1219      dot = DescriptorToDotWrapper(back_descriptor);
1220      fprintf(out_file_, " type=\"%s\"\n", dot.c_str());
1221    } else {
1222      fprintf(out_file_, "<method name=\"%s\"\n", name);
1223      const char* return_type = strrchr(type_descriptor, ')');
1224      if (return_type == nullptr) {
1225        fprintf(stderr, "bad method type descriptor '%s'\n", type_descriptor);
1226        goto bail;
1227      }
1228      std::string dot(DescriptorToDotWrapper(return_type + 1));
1229      fprintf(out_file_, " return=\"%s\"\n", dot.c_str());
1230      fprintf(out_file_, " abstract=%s\n", QuotedBool((flags & kAccAbstract) != 0));
1231      fprintf(out_file_, " native=%s\n", QuotedBool((flags & kAccNative) != 0));
1232      fprintf(out_file_, " synchronized=%s\n", QuotedBool(
1233          (flags & (kAccSynchronized | kAccDeclaredSynchronized)) != 0));
1234    }
1235
1236    // Additional method flags.
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=" not knowable w/o parsing annotations.
1240    fprintf(out_file_, " visibility=%s\n>\n", QuotedVisibility(flags));
1241
1242    // Parameters.
1243    if (type_descriptor[0] != '(') {
1244      fprintf(stderr, "ERROR: bad descriptor '%s'\n", type_descriptor);
1245      goto bail;
1246    }
1247    char* tmp_buf = reinterpret_cast<char*>(malloc(strlen(type_descriptor) + 1));
1248    const char* base = type_descriptor + 1;
1249    int arg_num = 0;
1250    while (*base != ')') {
1251      char* cp = tmp_buf;
1252      while (*base == '[') {
1253        *cp++ = *base++;
1254      }
1255      if (*base == 'L') {
1256        // Copy through ';'.
1257        do {
1258          *cp = *base++;
1259        } while (*cp++ != ';');
1260      } else {
1261        // Primitive char, copy it.
1262        if (strchr("ZBCSIFJD", *base) == nullptr) {
1263          fprintf(stderr, "ERROR: bad method signature '%s'\n", base);
1264          break;  // while
1265        }
1266        *cp++ = *base++;
1267      }
1268      // Null terminate and display.
1269      *cp++ = '\0';
1270      std::string dot(DescriptorToDotWrapper(tmp_buf));
1271      fprintf(out_file_, "<parameter name=\"arg%d\" type=\"%s\">\n"
1272                        "</parameter>\n", arg_num++, dot.c_str());
1273    }  // while
1274    free(tmp_buf);
1275    if (constructor) {
1276      fprintf(out_file_, "</constructor>\n");
1277    } else {
1278      fprintf(out_file_, "</method>\n");
1279    }
1280  }
1281
1282 bail:
1283  free(type_descriptor);
1284  free(access_str);
1285}
1286
1287/*
1288 * Dumps a static (class) field.
1289 */
1290void DexLayout::DumpSField(uint32_t idx, uint32_t flags, int i, dex_ir::EncodedValue* init) {
1291  // Bail for anything private if export only requested.
1292  if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) {
1293    return;
1294  }
1295
1296  dex_ir::FieldId* field_id = header_->GetCollections().GetFieldId(idx);
1297  const char* name = field_id->Name()->Data();
1298  const char* type_descriptor = field_id->Type()->GetStringId()->Data();
1299  const char* back_descriptor = field_id->Class()->GetStringId()->Data();
1300  char* access_str = CreateAccessFlagStr(flags, kAccessForField);
1301
1302  if (options_.output_format_ == kOutputPlain) {
1303    fprintf(out_file_, "    #%d              : (in %s)\n", i, back_descriptor);
1304    fprintf(out_file_, "      name          : '%s'\n", name);
1305    fprintf(out_file_, "      type          : '%s'\n", type_descriptor);
1306    fprintf(out_file_, "      access        : 0x%04x (%s)\n", flags, access_str);
1307    if (init != nullptr) {
1308      fputs("      value         : ", out_file_);
1309      DumpEncodedValue(init);
1310      fputs("\n", out_file_);
1311    }
1312  } else if (options_.output_format_ == kOutputXml) {
1313    fprintf(out_file_, "<field name=\"%s\"\n", name);
1314    std::string dot(DescriptorToDotWrapper(type_descriptor));
1315    fprintf(out_file_, " type=\"%s\"\n", dot.c_str());
1316    fprintf(out_file_, " transient=%s\n", QuotedBool((flags & kAccTransient) != 0));
1317    fprintf(out_file_, " volatile=%s\n", QuotedBool((flags & kAccVolatile) != 0));
1318    // The "value=" is not knowable w/o parsing annotations.
1319    fprintf(out_file_, " static=%s\n", QuotedBool((flags & kAccStatic) != 0));
1320    fprintf(out_file_, " final=%s\n", QuotedBool((flags & kAccFinal) != 0));
1321    // The "deprecated=" is not knowable w/o parsing annotations.
1322    fprintf(out_file_, " visibility=%s\n", QuotedVisibility(flags));
1323    if (init != nullptr) {
1324      fputs(" value=\"", out_file_);
1325      DumpEncodedValue(init);
1326      fputs("\"\n", out_file_);
1327    }
1328    fputs(">\n</field>\n", out_file_);
1329  }
1330
1331  free(access_str);
1332}
1333
1334/*
1335 * Dumps an instance field.
1336 */
1337void DexLayout::DumpIField(uint32_t idx, uint32_t flags, int i) {
1338  DumpSField(idx, flags, i, nullptr);
1339}
1340
1341/*
1342 * Dumps the class.
1343 *
1344 * Note "idx" is a DexClassDef index, not a DexTypeId index.
1345 *
1346 * If "*last_package" is nullptr or does not match the current class' package,
1347 * the value will be replaced with a newly-allocated string.
1348 */
1349void DexLayout::DumpClass(int idx, char** last_package) {
1350  dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx);
1351  // Omitting non-public class.
1352  if (options_.exports_only_ && (class_def->GetAccessFlags() & kAccPublic) == 0) {
1353    return;
1354  }
1355
1356  if (options_.show_section_headers_) {
1357    DumpClassDef(idx);
1358  }
1359
1360  if (options_.show_annotations_) {
1361    DumpClassAnnotations(idx);
1362  }
1363
1364  // For the XML output, show the package name.  Ideally we'd gather
1365  // up the classes, sort them, and dump them alphabetically so the
1366  // package name wouldn't jump around, but that's not a great plan
1367  // for something that needs to run on the device.
1368  const char* class_descriptor =
1369      header_->GetCollections().GetClassDef(idx)->ClassType()->GetStringId()->Data();
1370  if (!(class_descriptor[0] == 'L' &&
1371        class_descriptor[strlen(class_descriptor)-1] == ';')) {
1372    // Arrays and primitives should not be defined explicitly. Keep going?
1373    fprintf(stderr, "Malformed class name '%s'\n", class_descriptor);
1374  } else if (options_.output_format_ == kOutputXml) {
1375    char* mangle = strdup(class_descriptor + 1);
1376    mangle[strlen(mangle)-1] = '\0';
1377
1378    // Reduce to just the package name.
1379    char* last_slash = strrchr(mangle, '/');
1380    if (last_slash != nullptr) {
1381      *last_slash = '\0';
1382    } else {
1383      *mangle = '\0';
1384    }
1385
1386    for (char* cp = mangle; *cp != '\0'; cp++) {
1387      if (*cp == '/') {
1388        *cp = '.';
1389      }
1390    }  // for
1391
1392    if (*last_package == nullptr || strcmp(mangle, *last_package) != 0) {
1393      // Start of a new package.
1394      if (*last_package != nullptr) {
1395        fprintf(out_file_, "</package>\n");
1396      }
1397      fprintf(out_file_, "<package name=\"%s\"\n>\n", mangle);
1398      free(*last_package);
1399      *last_package = mangle;
1400    } else {
1401      free(mangle);
1402    }
1403  }
1404
1405  // General class information.
1406  char* access_str = CreateAccessFlagStr(class_def->GetAccessFlags(), kAccessForClass);
1407  const char* superclass_descriptor = nullptr;
1408  if (class_def->Superclass() != nullptr) {
1409    superclass_descriptor = class_def->Superclass()->GetStringId()->Data();
1410  }
1411  if (options_.output_format_ == kOutputPlain) {
1412    fprintf(out_file_, "Class #%d            -\n", idx);
1413    fprintf(out_file_, "  Class descriptor  : '%s'\n", class_descriptor);
1414    fprintf(out_file_, "  Access flags      : 0x%04x (%s)\n",
1415            class_def->GetAccessFlags(), access_str);
1416    if (superclass_descriptor != nullptr) {
1417      fprintf(out_file_, "  Superclass        : '%s'\n", superclass_descriptor);
1418    }
1419    fprintf(out_file_, "  Interfaces        -\n");
1420  } else {
1421    std::string dot(DescriptorClassToDot(class_descriptor));
1422    fprintf(out_file_, "<class name=\"%s\"\n", dot.c_str());
1423    if (superclass_descriptor != nullptr) {
1424      dot = DescriptorToDotWrapper(superclass_descriptor);
1425      fprintf(out_file_, " extends=\"%s\"\n", dot.c_str());
1426    }
1427    fprintf(out_file_, " interface=%s\n",
1428            QuotedBool((class_def->GetAccessFlags() & kAccInterface) != 0));
1429    fprintf(out_file_, " abstract=%s\n",
1430            QuotedBool((class_def->GetAccessFlags() & kAccAbstract) != 0));
1431    fprintf(out_file_, " static=%s\n", QuotedBool((class_def->GetAccessFlags() & kAccStatic) != 0));
1432    fprintf(out_file_, " final=%s\n", QuotedBool((class_def->GetAccessFlags() & kAccFinal) != 0));
1433    // The "deprecated=" not knowable w/o parsing annotations.
1434    fprintf(out_file_, " visibility=%s\n", QuotedVisibility(class_def->GetAccessFlags()));
1435    fprintf(out_file_, ">\n");
1436  }
1437
1438  // Interfaces.
1439  const dex_ir::TypeList* interfaces = class_def->Interfaces();
1440  if (interfaces != nullptr) {
1441    const dex_ir::TypeIdVector* interfaces_vector = interfaces->GetTypeList();
1442    for (uint32_t i = 0; i < interfaces_vector->size(); i++) {
1443      DumpInterface((*interfaces_vector)[i], i);
1444    }  // for
1445  }
1446
1447  // Fields and methods.
1448  dex_ir::ClassData* class_data = class_def->GetClassData();
1449  // Prepare data for static fields.
1450  dex_ir::EncodedArrayItem* static_values = class_def->StaticValues();
1451  dex_ir::EncodedValueVector* encoded_values =
1452      static_values == nullptr ? nullptr : static_values->GetEncodedValues();
1453  const uint32_t encoded_values_size = (encoded_values == nullptr) ? 0 : encoded_values->size();
1454
1455  // Static fields.
1456  if (options_.output_format_ == kOutputPlain) {
1457    fprintf(out_file_, "  Static fields     -\n");
1458  }
1459  if (class_data != nullptr) {
1460    dex_ir::FieldItemVector* static_fields = class_data->StaticFields();
1461    if (static_fields != nullptr) {
1462      for (uint32_t i = 0; i < static_fields->size(); i++) {
1463        DumpSField((*static_fields)[i]->GetFieldId()->GetIndex(),
1464                   (*static_fields)[i]->GetAccessFlags(),
1465                   i,
1466                   i < encoded_values_size ? (*encoded_values)[i].get() : nullptr);
1467      }  // for
1468    }
1469  }
1470
1471  // Instance fields.
1472  if (options_.output_format_ == kOutputPlain) {
1473    fprintf(out_file_, "  Instance fields   -\n");
1474  }
1475  if (class_data != nullptr) {
1476    dex_ir::FieldItemVector* instance_fields = class_data->InstanceFields();
1477    if (instance_fields != nullptr) {
1478      for (uint32_t i = 0; i < instance_fields->size(); i++) {
1479        DumpIField((*instance_fields)[i]->GetFieldId()->GetIndex(),
1480                   (*instance_fields)[i]->GetAccessFlags(),
1481                   i);
1482      }  // for
1483    }
1484  }
1485
1486  // Direct methods.
1487  if (options_.output_format_ == kOutputPlain) {
1488    fprintf(out_file_, "  Direct methods    -\n");
1489  }
1490  if (class_data != nullptr) {
1491    dex_ir::MethodItemVector* direct_methods = class_data->DirectMethods();
1492    if (direct_methods != nullptr) {
1493      for (uint32_t i = 0; i < direct_methods->size(); i++) {
1494        DumpMethod((*direct_methods)[i]->GetMethodId()->GetIndex(),
1495                   (*direct_methods)[i]->GetAccessFlags(),
1496                   (*direct_methods)[i]->GetCodeItem(),
1497                 i);
1498      }  // for
1499    }
1500  }
1501
1502  // Virtual methods.
1503  if (options_.output_format_ == kOutputPlain) {
1504    fprintf(out_file_, "  Virtual methods   -\n");
1505  }
1506  if (class_data != nullptr) {
1507    dex_ir::MethodItemVector* virtual_methods = class_data->VirtualMethods();
1508    if (virtual_methods != nullptr) {
1509      for (uint32_t i = 0; i < virtual_methods->size(); i++) {
1510        DumpMethod((*virtual_methods)[i]->GetMethodId()->GetIndex(),
1511                   (*virtual_methods)[i]->GetAccessFlags(),
1512                   (*virtual_methods)[i]->GetCodeItem(),
1513                   i);
1514      }  // for
1515    }
1516  }
1517
1518  // End of class.
1519  if (options_.output_format_ == kOutputPlain) {
1520    const char* file_name = "unknown";
1521    if (class_def->SourceFile() != nullptr) {
1522      file_name = class_def->SourceFile()->Data();
1523    }
1524    const dex_ir::StringId* source_file = class_def->SourceFile();
1525    fprintf(out_file_, "  source_file_idx   : %d (%s)\n\n",
1526            source_file == nullptr ? 0xffffffffU : source_file->GetIndex(), file_name);
1527  } else if (options_.output_format_ == kOutputXml) {
1528    fprintf(out_file_, "</class>\n");
1529  }
1530
1531  free(access_str);
1532}
1533
1534void DexLayout::DumpDexFile() {
1535  // Headers.
1536  if (options_.show_file_headers_) {
1537    DumpFileHeader();
1538  }
1539
1540  // Open XML context.
1541  if (options_.output_format_ == kOutputXml) {
1542    fprintf(out_file_, "<api>\n");
1543  }
1544
1545  // Iterate over all classes.
1546  char* package = nullptr;
1547  const uint32_t class_defs_size = header_->GetCollections().ClassDefsSize();
1548  for (uint32_t i = 0; i < class_defs_size; i++) {
1549    DumpClass(i, &package);
1550  }  // for
1551
1552  // Free the last package allocated.
1553  if (package != nullptr) {
1554    fprintf(out_file_, "</package>\n");
1555    free(package);
1556  }
1557
1558  // Close XML context.
1559  if (options_.output_format_ == kOutputXml) {
1560    fprintf(out_file_, "</api>\n");
1561  }
1562}
1563
1564void DexLayout::LayoutClassDefsAndClassData(const DexFile* dex_file) {
1565  std::vector<dex_ir::ClassDef*> new_class_def_order;
1566  for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
1567    dex::TypeIndex type_idx(class_def->ClassType()->GetIndex());
1568    if (info_->ContainsClass(*dex_file, type_idx)) {
1569      new_class_def_order.push_back(class_def.get());
1570    }
1571  }
1572  for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
1573    dex::TypeIndex type_idx(class_def->ClassType()->GetIndex());
1574    if (!info_->ContainsClass(*dex_file, type_idx)) {
1575      new_class_def_order.push_back(class_def.get());
1576    }
1577  }
1578  std::unordered_set<dex_ir::ClassData*> visited_class_data;
1579  size_t class_data_index = 0;
1580  dex_ir::CollectionVector<dex_ir::ClassData>::Vector& class_datas =
1581      header_->GetCollections().ClassDatas();
1582  for (dex_ir::ClassDef* class_def : new_class_def_order) {
1583    dex_ir::ClassData* class_data = class_def->GetClassData();
1584    if (class_data != nullptr && visited_class_data.find(class_data) == visited_class_data.end()) {
1585      visited_class_data.insert(class_data);
1586      // Overwrite the existing vector with the new ordering, note that the sets of objects are
1587      // equivalent, but the order changes. This is why this is not a memory leak.
1588      // TODO: Consider cleaning this up with a shared_ptr.
1589      class_datas[class_data_index].release();
1590      class_datas[class_data_index].reset(class_data);
1591      ++class_data_index;
1592    }
1593  }
1594  CHECK_EQ(class_data_index, class_datas.size());
1595
1596  if (kChangeClassDefOrder) {
1597    // This currently produces dex files that violate the spec since the super class class_def is
1598    // supposed to occur before any subclasses.
1599    dex_ir::CollectionVector<dex_ir::ClassDef>::Vector& class_defs =
1600        header_->GetCollections().ClassDefs();
1601    CHECK_EQ(new_class_def_order.size(), class_defs.size());
1602    for (size_t i = 0; i < class_defs.size(); ++i) {
1603      // Overwrite the existing vector with the new ordering, note that the sets of objects are
1604      // equivalent, but the order changes. This is why this is not a memory leak.
1605      // TODO: Consider cleaning this up with a shared_ptr.
1606      class_defs[i].release();
1607      class_defs[i].reset(new_class_def_order[i]);
1608    }
1609  }
1610}
1611
1612void DexLayout::LayoutStringData(const DexFile* dex_file) {
1613  const size_t num_strings = header_->GetCollections().StringIds().size();
1614  std::vector<bool> is_shorty(num_strings, false);
1615  std::vector<bool> from_hot_method(num_strings, false);
1616  for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
1617    // A name of a profile class is probably going to get looked up by ClassTable::Lookup, mark it
1618    // as hot. Add its super class and interfaces as well, which can be used during initialization.
1619    const bool is_profile_class =
1620        info_->ContainsClass(*dex_file, dex::TypeIndex(class_def->ClassType()->GetIndex()));
1621    if (is_profile_class) {
1622      from_hot_method[class_def->ClassType()->GetStringId()->GetIndex()] = true;
1623      const dex_ir::TypeId* superclass = class_def->Superclass();
1624      if (superclass != nullptr) {
1625        from_hot_method[superclass->GetStringId()->GetIndex()] = true;
1626      }
1627      const dex_ir::TypeList* interfaces = class_def->Interfaces();
1628      if (interfaces != nullptr) {
1629        for (const dex_ir::TypeId* interface_type : *interfaces->GetTypeList()) {
1630          from_hot_method[interface_type->GetStringId()->GetIndex()] = true;
1631        }
1632      }
1633    }
1634    dex_ir::ClassData* data = class_def->GetClassData();
1635    if (data == nullptr) {
1636      continue;
1637    }
1638    for (size_t i = 0; i < 2; ++i) {
1639      for (auto& method : *(i == 0 ? data->DirectMethods() : data->VirtualMethods())) {
1640        const dex_ir::MethodId* method_id = method->GetMethodId();
1641        dex_ir::CodeItem* code_item = method->GetCodeItem();
1642        if (code_item == nullptr) {
1643          continue;
1644        }
1645        const bool is_clinit = is_profile_class &&
1646            (method->GetAccessFlags() & kAccConstructor) != 0 &&
1647            (method->GetAccessFlags() & kAccStatic) != 0;
1648        const bool method_executed = is_clinit ||
1649            info_->GetMethodHotness(MethodReference(dex_file, method_id->GetIndex())).IsInProfile();
1650        if (!method_executed) {
1651          continue;
1652        }
1653        is_shorty[method_id->Proto()->Shorty()->GetIndex()] = true;
1654        dex_ir::CodeFixups* fixups = code_item->GetCodeFixups();
1655        if (fixups == nullptr) {
1656          continue;
1657        }
1658        // Add const-strings.
1659        for (dex_ir::StringId* id : fixups->StringIds()) {
1660          from_hot_method[id->GetIndex()] = true;
1661        }
1662        // Add field classes, names, and types.
1663        for (dex_ir::FieldId* id : fixups->FieldIds()) {
1664          // TODO: Only visit field ids from static getters and setters.
1665          from_hot_method[id->Class()->GetStringId()->GetIndex()] = true;
1666          from_hot_method[id->Name()->GetIndex()] = true;
1667          from_hot_method[id->Type()->GetStringId()->GetIndex()] = true;
1668        }
1669        // For clinits, add referenced method classes, names, and protos.
1670        if (is_clinit) {
1671          for (dex_ir::MethodId* id : fixups->MethodIds()) {
1672            from_hot_method[id->Class()->GetStringId()->GetIndex()] = true;
1673            from_hot_method[id->Name()->GetIndex()] = true;
1674            is_shorty[id->Proto()->Shorty()->GetIndex()] = true;
1675          }
1676        }
1677      }
1678    }
1679  }
1680  // Sort string data by specified order.
1681  std::vector<dex_ir::StringId*> string_ids;
1682  for (auto& string_id : header_->GetCollections().StringIds()) {
1683    string_ids.push_back(string_id.get());
1684  }
1685  std::sort(string_ids.begin(),
1686            string_ids.end(),
1687            [&is_shorty, &from_hot_method](const dex_ir::StringId* a,
1688                                           const dex_ir::StringId* b) {
1689    const bool a_is_hot = from_hot_method[a->GetIndex()];
1690    const bool b_is_hot = from_hot_method[b->GetIndex()];
1691    if (a_is_hot != b_is_hot) {
1692      return a_is_hot < b_is_hot;
1693    }
1694    // After hot methods are partitioned, subpartition shorties.
1695    const bool a_is_shorty = is_shorty[a->GetIndex()];
1696    const bool b_is_shorty = is_shorty[b->GetIndex()];
1697    if (a_is_shorty != b_is_shorty) {
1698      return a_is_shorty < b_is_shorty;
1699    }
1700    // Order by index by default.
1701    return a->GetIndex() < b->GetIndex();
1702  });
1703  dex_ir::CollectionVector<dex_ir::StringData>::Vector& string_datas =
1704      header_->GetCollections().StringDatas();
1705  // Now we know what order we want the string data, reorder them.
1706  size_t data_index = 0;
1707  for (dex_ir::StringId* string_id : string_ids) {
1708    string_datas[data_index].release();
1709    string_datas[data_index].reset(string_id->DataItem());
1710    ++data_index;
1711  }
1712  if (kIsDebugBuild) {
1713    std::unordered_set<dex_ir::StringData*> visited;
1714    for (const std::unique_ptr<dex_ir::StringData>& data : string_datas) {
1715      visited.insert(data.get());
1716    }
1717    for (auto& string_id : header_->GetCollections().StringIds()) {
1718      CHECK(visited.find(string_id->DataItem()) != visited.end());
1719    }
1720  }
1721  CHECK_EQ(data_index, string_datas.size());
1722}
1723
1724// Orders code items according to specified class data ordering.
1725void DexLayout::LayoutCodeItems(const DexFile* dex_file) {
1726  static constexpr InvokeType invoke_types[] = {
1727    kDirect,
1728    kVirtual
1729  };
1730
1731  std::unordered_map<dex_ir::CodeItem*, LayoutType>& code_item_layout =
1732      layout_hotness_info_.code_item_layout_;
1733
1734  // Assign hotness flags to all code items.
1735  for (InvokeType invoke_type : invoke_types) {
1736    for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
1737      const bool is_profile_class =
1738          info_->ContainsClass(*dex_file, dex::TypeIndex(class_def->ClassType()->GetIndex()));
1739
1740      // Skip classes that are not defined in this dex file.
1741      dex_ir::ClassData* class_data = class_def->GetClassData();
1742      if (class_data == nullptr) {
1743        continue;
1744      }
1745      for (auto& method : *(invoke_type == InvokeType::kDirect
1746                                ? class_data->DirectMethods()
1747                                : class_data->VirtualMethods())) {
1748        const dex_ir::MethodId *method_id = method->GetMethodId();
1749        dex_ir::CodeItem *code_item = method->GetCodeItem();
1750        if (code_item == nullptr) {
1751          continue;
1752        }
1753        // Separate executed methods (clinits and profiled methods) from unexecuted methods.
1754        const bool is_clinit = (method->GetAccessFlags() & kAccConstructor) != 0 &&
1755            (method->GetAccessFlags() & kAccStatic) != 0;
1756        const bool is_startup_clinit = is_profile_class && is_clinit;
1757        using Hotness = ProfileCompilationInfo::MethodHotness;
1758        Hotness hotness = info_->GetMethodHotness(MethodReference(dex_file, method_id->GetIndex()));
1759        LayoutType state = LayoutType::kLayoutTypeUnused;
1760        if (hotness.IsHot()) {
1761          // Hot code is compiled, maybe one day it won't be accessed. So lay it out together for
1762          // now.
1763          state = LayoutType::kLayoutTypeHot;
1764        } else if (is_startup_clinit || hotness.GetFlags() == Hotness::kFlagStartup) {
1765          // Startup clinit or a method that only has the startup flag.
1766          state = LayoutType::kLayoutTypeStartupOnly;
1767        } else if (is_clinit) {
1768          state = LayoutType::kLayoutTypeUsedOnce;
1769        } else if (hotness.IsInProfile()) {
1770          state = LayoutType::kLayoutTypeSometimesUsed;
1771        }
1772        auto it = code_item_layout.emplace(code_item, state);
1773        if (!it.second) {
1774          LayoutType& layout_type = it.first->second;
1775          // Already exists, merge the hotness.
1776          layout_type = MergeLayoutType(layout_type, state);
1777        }
1778      }
1779    }
1780  }
1781
1782  dex_ir::CollectionVector<dex_ir::CodeItem>::Vector& code_items =
1783        header_->GetCollections().CodeItems();
1784  if (VLOG_IS_ON(dex)) {
1785    size_t layout_count[static_cast<size_t>(LayoutType::kLayoutTypeCount)] = {};
1786    for (const std::unique_ptr<dex_ir::CodeItem>& code_item : code_items) {
1787      auto it = code_item_layout.find(code_item.get());
1788      DCHECK(it != code_item_layout.end());
1789      ++layout_count[static_cast<size_t>(it->second)];
1790    }
1791    for (size_t i = 0; i < static_cast<size_t>(LayoutType::kLayoutTypeCount); ++i) {
1792      LOG(INFO) << "Code items in category " << i << " count=" << layout_count[i];
1793    }
1794  }
1795
1796  // Sort the code items vector by new layout. The writing process will take care of calculating
1797  // all the offsets. Stable sort to preserve any existing locality that might be there.
1798  std::stable_sort(code_items.begin(),
1799                   code_items.end(),
1800                   [&](const std::unique_ptr<dex_ir::CodeItem>& a,
1801                       const std::unique_ptr<dex_ir::CodeItem>& b) {
1802    auto it_a = code_item_layout.find(a.get());
1803    auto it_b = code_item_layout.find(b.get());
1804    DCHECK(it_a != code_item_layout.end());
1805    DCHECK(it_b != code_item_layout.end());
1806    const LayoutType layout_type_a = it_a->second;
1807    const LayoutType layout_type_b = it_b->second;
1808    return layout_type_a < layout_type_b;
1809  });
1810}
1811
1812void DexLayout::LayoutOutputFile(const DexFile* dex_file) {
1813  LayoutStringData(dex_file);
1814  LayoutClassDefsAndClassData(dex_file);
1815  LayoutCodeItems(dex_file);
1816}
1817
1818void DexLayout::OutputDexFile(const DexFile* dex_file, bool compute_offsets) {
1819  const std::string& dex_file_location = dex_file->GetLocation();
1820  std::string error_msg;
1821  std::unique_ptr<File> new_file;
1822  // Since we allow dex growth, we need to size the map larger than the original input to be safe.
1823  // Reserve an extra 10% to add some buffer room. Note that this is probably more than
1824  // necessary.
1825  constexpr size_t kReserveFraction = 10;
1826  const size_t max_size = header_->FileSize() + header_->FileSize() / kReserveFraction;
1827  if (!options_.output_to_memmap_) {
1828    std::string output_location(options_.output_dex_directory_);
1829    size_t last_slash = dex_file_location.rfind('/');
1830    std::string dex_file_directory = dex_file_location.substr(0, last_slash + 1);
1831    if (output_location == dex_file_directory) {
1832      output_location = dex_file_location + ".new";
1833    } else if (last_slash != std::string::npos) {
1834      output_location += dex_file_location.substr(last_slash);
1835    } else {
1836      output_location += "/" + dex_file_location + ".new";
1837    }
1838    new_file.reset(OS::CreateEmptyFile(output_location.c_str()));
1839    if (new_file == nullptr) {
1840      LOG(ERROR) << "Could not create dex writer output file: " << output_location;
1841      return;
1842    }
1843    if (ftruncate(new_file->Fd(), max_size) != 0) {
1844      LOG(ERROR) << "Could not grow dex writer output file: " << output_location;;
1845      new_file->Erase();
1846      return;
1847    }
1848    mem_map_.reset(MemMap::MapFile(max_size, PROT_READ | PROT_WRITE, MAP_SHARED,
1849        new_file->Fd(), 0, /*low_4gb*/ false, output_location.c_str(), &error_msg));
1850  } else {
1851    mem_map_.reset(MemMap::MapAnonymous("layout dex", nullptr, max_size,
1852        PROT_READ | PROT_WRITE, /* low_4gb */ false, /* reuse */ false, &error_msg));
1853  }
1854  if (mem_map_ == nullptr) {
1855    LOG(ERROR) << "Could not create mem map for dex writer output: " << error_msg;
1856    if (new_file != nullptr) {
1857      new_file->Erase();
1858    }
1859    return;
1860  }
1861  DexWriter::Output(header_, mem_map_.get(), this, compute_offsets, options_.compact_dex_level_);
1862  if (new_file != nullptr) {
1863    // Since we make the memmap larger than needed, shrink the file back down to not leave extra
1864    // padding.
1865    int res = new_file->SetLength(header_->FileSize());
1866    if (res != 0) {
1867      LOG(ERROR) << "Truncating file resulted in " << res;
1868    }
1869    UNUSED(new_file->FlushCloseOrErase());
1870  }
1871}
1872
1873/*
1874 * Dumps the requested sections of the file.
1875 */
1876void DexLayout::ProcessDexFile(const char* file_name,
1877                               const DexFile* dex_file,
1878                               size_t dex_file_index) {
1879  const bool output = options_.output_dex_directory_ != nullptr || options_.output_to_memmap_;
1880  // Try to avoid eagerly assigning offsets to find bugs since GetOffset will abort if the offset
1881  // is unassigned.
1882  bool eagerly_assign_offsets = false;
1883  if (options_.visualize_pattern_ || options_.show_section_statistics_ || options_.dump_) {
1884    // These options required the offsets for dumping purposes.
1885    eagerly_assign_offsets = true;
1886  }
1887  std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file, eagerly_assign_offsets));
1888  SetHeader(header.get());
1889
1890  if (options_.verbose_) {
1891    fprintf(out_file_, "Opened '%s', DEX version '%.3s'\n",
1892            file_name, dex_file->GetHeader().magic_ + 4);
1893  }
1894
1895  if (options_.visualize_pattern_) {
1896    VisualizeDexLayout(header_, dex_file, dex_file_index, info_);
1897    return;
1898  }
1899
1900  if (options_.show_section_statistics_) {
1901    ShowDexSectionStatistics(header_, dex_file_index);
1902    return;
1903  }
1904
1905  // Dump dex file.
1906  if (options_.dump_) {
1907    DumpDexFile();
1908  }
1909
1910  // In case we are outputting to a file, keep it open so we can verify.
1911  if (output) {
1912    // Layout information about what strings and code items are hot. Used by the writing process
1913    // to generate the sections that are stored in the oat file.
1914    bool do_layout = info_ != nullptr;
1915    if (do_layout) {
1916      LayoutOutputFile(dex_file);
1917    }
1918    OutputDexFile(dex_file, do_layout);
1919
1920    // Clear header before verifying to reduce peak RAM usage.
1921    const size_t file_size = header_->FileSize();
1922    header.reset();
1923
1924    // Verify the output dex file's structure, only enabled by default for debug builds.
1925    if (options_.verify_output_) {
1926      std::string error_msg;
1927      std::string location = "memory mapped file for " + std::string(file_name);
1928      std::unique_ptr<const DexFile> output_dex_file(DexFileLoader::Open(mem_map_->Begin(),
1929                                                                         file_size,
1930                                                                         location,
1931                                                                         /* checksum */ 0,
1932                                                                         /*oat_dex_file*/ nullptr,
1933                                                                         /*verify*/ true,
1934                                                                         /*verify_checksum*/ false,
1935                                                                         &error_msg));
1936      CHECK(output_dex_file != nullptr) << "Failed to re-open output file:" << error_msg;
1937
1938      // Do IR-level comparison between input and output. This check ignores potential differences
1939      // due to layout, so offsets are not checked. Instead, it checks the data contents of each
1940      // item.
1941      //
1942      // Regenerate output IR to catch any bugs that might happen during writing.
1943      std::unique_ptr<dex_ir::Header> output_header(
1944          dex_ir::DexIrBuilder(*output_dex_file,
1945                               /*eagerly_assign_offsets*/ true));
1946      std::unique_ptr<dex_ir::Header> orig_header(
1947          dex_ir::DexIrBuilder(*dex_file,
1948                               /*eagerly_assign_offsets*/ true));
1949      CHECK(VerifyOutputDexFile(output_header.get(), orig_header.get(), &error_msg)) << error_msg;
1950    }
1951  }
1952}
1953
1954/*
1955 * Processes a single file (either direct .dex or indirect .zip/.jar/.apk).
1956 */
1957int DexLayout::ProcessFile(const char* file_name) {
1958  if (options_.verbose_) {
1959    fprintf(out_file_, "Processing '%s'...\n", file_name);
1960  }
1961
1962  // If the file is not a .dex file, the function tries .zip/.jar/.apk files,
1963  // all of which are Zip archives with "classes.dex" inside.
1964  const bool verify_checksum = !options_.ignore_bad_checksum_;
1965  std::string error_msg;
1966  std::vector<std::unique_ptr<const DexFile>> dex_files;
1967  if (!DexFileLoader::Open(
1968        file_name, file_name, /* verify */ true, verify_checksum, &error_msg, &dex_files)) {
1969    // Display returned error message to user. Note that this error behavior
1970    // differs from the error messages shown by the original Dalvik dexdump.
1971    fputs(error_msg.c_str(), stderr);
1972    fputc('\n', stderr);
1973    return -1;
1974  }
1975
1976  // Success. Either report checksum verification or process
1977  // all dex files found in given file.
1978  if (options_.checksum_only_) {
1979    fprintf(out_file_, "Checksum verified\n");
1980  } else {
1981    for (size_t i = 0; i < dex_files.size(); i++) {
1982      ProcessDexFile(file_name, dex_files[i].get(), i);
1983    }
1984  }
1985  return 0;
1986}
1987
1988}  // namespace art
1989