dexlayout.cc revision 095c6c96236476b605b3ac672f6d2b8c151e9479
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
55static constexpr uint32_t kDexCodeItemAlignment = 4;
56
57/*
58 * Flags for use with createAccessFlagStr().
59 */
60enum AccessFor {
61  kAccessForClass = 0, kAccessForMethod = 1, kAccessForField = 2, kAccessForMAX
62};
63const int kNumFlags = 18;
64
65/*
66 * Gets 2 little-endian bytes.
67 */
68static inline uint16_t Get2LE(unsigned char const* src) {
69  return src[0] | (src[1] << 8);
70}
71
72/*
73 * Converts a type descriptor to human-readable "dotted" form.  For
74 * example, "Ljava/lang/String;" becomes "java.lang.String", and
75 * "[I" becomes "int[]".  Also converts '$' to '.', which means this
76 * form can't be converted back to a descriptor.
77 */
78static std::string DescriptorToDotWrapper(const char* descriptor) {
79  std::string result = DescriptorToDot(descriptor);
80  size_t found = result.find('$');
81  while (found != std::string::npos) {
82    result[found] = '.';
83    found = result.find('$', found);
84  }
85  return result;
86}
87
88/*
89 * Converts the class name portion of a type descriptor to human-readable
90 * "dotted" form. For example, "Ljava/lang/String;" becomes "String".
91 */
92static std::string DescriptorClassToDot(const char* str) {
93  std::string descriptor(str);
94  // Reduce to just the class name prefix.
95  size_t last_slash = descriptor.rfind('/');
96  if (last_slash == std::string::npos) {
97    last_slash = 0;
98  }
99  // Start past the '/' or 'L'.
100  last_slash++;
101
102  // Copy class name over, trimming trailing ';'.
103  size_t size = descriptor.size() - 1 - last_slash;
104  std::string result(descriptor.substr(last_slash, size));
105
106  // Replace '$' with '.'.
107  size_t dollar_sign = result.find('$');
108  while (dollar_sign != std::string::npos) {
109    result[dollar_sign] = '.';
110    dollar_sign = result.find('$', dollar_sign);
111  }
112
113  return result;
114}
115
116/*
117 * Returns string representing the boolean value.
118 */
119static const char* StrBool(bool val) {
120  return val ? "true" : "false";
121}
122
123/*
124 * Returns a quoted string representing the boolean value.
125 */
126static const char* QuotedBool(bool val) {
127  return val ? "\"true\"" : "\"false\"";
128}
129
130/*
131 * Returns a quoted string representing the access flags.
132 */
133static const char* QuotedVisibility(uint32_t access_flags) {
134  if (access_flags & kAccPublic) {
135    return "\"public\"";
136  } else if (access_flags & kAccProtected) {
137    return "\"protected\"";
138  } else if (access_flags & kAccPrivate) {
139    return "\"private\"";
140  } else {
141    return "\"package\"";
142  }
143}
144
145/*
146 * Counts the number of '1' bits in a word.
147 */
148static int CountOnes(uint32_t val) {
149  val = val - ((val >> 1) & 0x55555555);
150  val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
151  return (((val + (val >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
152}
153
154/*
155 * Creates a new string with human-readable access flags.
156 *
157 * In the base language the access_flags fields are type uint16_t; in Dalvik they're uint32_t.
158 */
159static char* CreateAccessFlagStr(uint32_t flags, AccessFor for_what) {
160  static const char* kAccessStrings[kAccessForMAX][kNumFlags] = {
161    {
162      "PUBLIC",                /* 0x00001 */
163      "PRIVATE",               /* 0x00002 */
164      "PROTECTED",             /* 0x00004 */
165      "STATIC",                /* 0x00008 */
166      "FINAL",                 /* 0x00010 */
167      "?",                     /* 0x00020 */
168      "?",                     /* 0x00040 */
169      "?",                     /* 0x00080 */
170      "?",                     /* 0x00100 */
171      "INTERFACE",             /* 0x00200 */
172      "ABSTRACT",              /* 0x00400 */
173      "?",                     /* 0x00800 */
174      "SYNTHETIC",             /* 0x01000 */
175      "ANNOTATION",            /* 0x02000 */
176      "ENUM",                  /* 0x04000 */
177      "?",                     /* 0x08000 */
178      "VERIFIED",              /* 0x10000 */
179      "OPTIMIZED",             /* 0x20000 */
180    }, {
181      "PUBLIC",                /* 0x00001 */
182      "PRIVATE",               /* 0x00002 */
183      "PROTECTED",             /* 0x00004 */
184      "STATIC",                /* 0x00008 */
185      "FINAL",                 /* 0x00010 */
186      "SYNCHRONIZED",          /* 0x00020 */
187      "BRIDGE",                /* 0x00040 */
188      "VARARGS",               /* 0x00080 */
189      "NATIVE",                /* 0x00100 */
190      "?",                     /* 0x00200 */
191      "ABSTRACT",              /* 0x00400 */
192      "STRICT",                /* 0x00800 */
193      "SYNTHETIC",             /* 0x01000 */
194      "?",                     /* 0x02000 */
195      "?",                     /* 0x04000 */
196      "MIRANDA",               /* 0x08000 */
197      "CONSTRUCTOR",           /* 0x10000 */
198      "DECLARED_SYNCHRONIZED", /* 0x20000 */
199    }, {
200      "PUBLIC",                /* 0x00001 */
201      "PRIVATE",               /* 0x00002 */
202      "PROTECTED",             /* 0x00004 */
203      "STATIC",                /* 0x00008 */
204      "FINAL",                 /* 0x00010 */
205      "?",                     /* 0x00020 */
206      "VOLATILE",              /* 0x00040 */
207      "TRANSIENT",             /* 0x00080 */
208      "?",                     /* 0x00100 */
209      "?",                     /* 0x00200 */
210      "?",                     /* 0x00400 */
211      "?",                     /* 0x00800 */
212      "SYNTHETIC",             /* 0x01000 */
213      "?",                     /* 0x02000 */
214      "ENUM",                  /* 0x04000 */
215      "?",                     /* 0x08000 */
216      "?",                     /* 0x10000 */
217      "?",                     /* 0x20000 */
218    },
219  };
220
221  // Allocate enough storage to hold the expected number of strings,
222  // plus a space between each.  We over-allocate, using the longest
223  // string above as the base metric.
224  const int kLongest = 21;  // The strlen of longest string above.
225  const int count = CountOnes(flags);
226  char* str;
227  char* cp;
228  cp = str = reinterpret_cast<char*>(malloc(count * (kLongest + 1) + 1));
229
230  for (int i = 0; i < kNumFlags; i++) {
231    if (flags & 0x01) {
232      const char* accessStr = kAccessStrings[for_what][i];
233      const int len = strlen(accessStr);
234      if (cp != str) {
235        *cp++ = ' ';
236      }
237      memcpy(cp, accessStr, len);
238      cp += len;
239    }
240    flags >>= 1;
241  }  // for
242
243  *cp = '\0';
244  return str;
245}
246
247static std::string GetSignatureForProtoId(const dex_ir::ProtoId* proto) {
248  if (proto == nullptr) {
249    return "<no signature>";
250  }
251
252  std::string result("(");
253  const dex_ir::TypeList* type_list = proto->Parameters();
254  if (type_list != nullptr) {
255    for (const dex_ir::TypeId* type_id : *type_list->GetTypeList()) {
256      result += type_id->GetStringId()->Data();
257    }
258  }
259  result += ")";
260  result += proto->ReturnType()->GetStringId()->Data();
261  return result;
262}
263
264/*
265 * Copies character data from "data" to "out", converting non-ASCII values
266 * to fprintf format chars or an ASCII filler ('.' or '?').
267 *
268 * The output buffer must be able to hold (2*len)+1 bytes.  The result is
269 * NULL-terminated.
270 */
271static void Asciify(char* out, const unsigned char* data, size_t len) {
272  while (len--) {
273    if (*data < 0x20) {
274      // Could do more here, but we don't need them yet.
275      switch (*data) {
276        case '\0':
277          *out++ = '\\';
278          *out++ = '0';
279          break;
280        case '\n':
281          *out++ = '\\';
282          *out++ = 'n';
283          break;
284        default:
285          *out++ = '.';
286          break;
287      }  // switch
288    } else if (*data >= 0x80) {
289      *out++ = '?';
290    } else {
291      *out++ = *data;
292    }
293    data++;
294  }  // while
295  *out = '\0';
296}
297
298/*
299 * Dumps a string value with some escape characters.
300 */
301static void DumpEscapedString(const char* p, FILE* out_file) {
302  fputs("\"", out_file);
303  for (; *p; p++) {
304    switch (*p) {
305      case '\\':
306        fputs("\\\\", out_file);
307        break;
308      case '\"':
309        fputs("\\\"", out_file);
310        break;
311      case '\t':
312        fputs("\\t", out_file);
313        break;
314      case '\n':
315        fputs("\\n", out_file);
316        break;
317      case '\r':
318        fputs("\\r", out_file);
319        break;
320      default:
321        putc(*p, out_file);
322    }  // switch
323  }  // for
324  fputs("\"", out_file);
325}
326
327/*
328 * Dumps a string as an XML attribute value.
329 */
330static void DumpXmlAttribute(const char* p, FILE* out_file) {
331  for (; *p; p++) {
332    switch (*p) {
333      case '&':
334        fputs("&amp;", out_file);
335        break;
336      case '<':
337        fputs("&lt;", out_file);
338        break;
339      case '>':
340        fputs("&gt;", out_file);
341        break;
342      case '"':
343        fputs("&quot;", out_file);
344        break;
345      case '\t':
346        fputs("&#x9;", out_file);
347        break;
348      case '\n':
349        fputs("&#xA;", out_file);
350        break;
351      case '\r':
352        fputs("&#xD;", out_file);
353        break;
354      default:
355        putc(*p, out_file);
356    }  // switch
357  }  // for
358}
359
360/*
361 * Helper for dumpInstruction(), which builds the string
362 * representation for the index in the given instruction.
363 * Returns a pointer to a buffer of sufficient size.
364 */
365static std::unique_ptr<char[]> IndexString(dex_ir::Header* header,
366                                           const Instruction* dec_insn,
367                                           size_t buf_size) {
368  std::unique_ptr<char[]> buf(new char[buf_size]);
369  // Determine index and width of the string.
370  uint32_t index = 0;
371  uint32_t secondary_index = dex::kDexNoIndex;
372  uint32_t width = 4;
373  switch (Instruction::FormatOf(dec_insn->Opcode())) {
374    // SOME NOT SUPPORTED:
375    // case Instruction::k20bc:
376    case Instruction::k21c:
377    case Instruction::k35c:
378    // case Instruction::k35ms:
379    case Instruction::k3rc:
380    // case Instruction::k3rms:
381    // case Instruction::k35mi:
382    // case Instruction::k3rmi:
383      index = dec_insn->VRegB();
384      width = 4;
385      break;
386    case Instruction::k31c:
387      index = dec_insn->VRegB();
388      width = 8;
389      break;
390    case Instruction::k22c:
391    // case Instruction::k22cs:
392      index = dec_insn->VRegC();
393      width = 4;
394      break;
395    case Instruction::k45cc:
396    case Instruction::k4rcc:
397      index = dec_insn->VRegB();
398      secondary_index = dec_insn->VRegH();
399      width = 4;
400      break;
401    default:
402      break;
403  }  // switch
404
405  // Determine index type.
406  size_t outSize = 0;
407  switch (Instruction::IndexTypeOf(dec_insn->Opcode())) {
408    case Instruction::kIndexUnknown:
409      // This function should never get called for this type, but do
410      // something sensible here, just to help with debugging.
411      outSize = snprintf(buf.get(), buf_size, "<unknown-index>");
412      break;
413    case Instruction::kIndexNone:
414      // This function should never get called for this type, but do
415      // something sensible here, just to help with debugging.
416      outSize = snprintf(buf.get(), buf_size, "<no-index>");
417      break;
418    case Instruction::kIndexTypeRef:
419      if (index < header->GetCollections().TypeIdsSize()) {
420        const char* tp = header->GetCollections().GetTypeId(index)->GetStringId()->Data();
421        outSize = snprintf(buf.get(), buf_size, "%s // type@%0*x", tp, width, index);
422      } else {
423        outSize = snprintf(buf.get(), buf_size, "<type?> // type@%0*x", width, index);
424      }
425      break;
426    case Instruction::kIndexStringRef:
427      if (index < header->GetCollections().StringIdsSize()) {
428        const char* st = header->GetCollections().GetStringId(index)->Data();
429        outSize = snprintf(buf.get(), buf_size, "\"%s\" // string@%0*x", st, width, index);
430      } else {
431        outSize = snprintf(buf.get(), buf_size, "<string?> // string@%0*x", width, index);
432      }
433      break;
434    case Instruction::kIndexMethodRef:
435      if (index < header->GetCollections().MethodIdsSize()) {
436        dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index);
437        const char* name = method_id->Name()->Data();
438        std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
439        const char* back_descriptor = method_id->Class()->GetStringId()->Data();
440        outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // method@%0*x",
441                           back_descriptor, name, type_descriptor.c_str(), width, index);
442      } else {
443        outSize = snprintf(buf.get(), buf_size, "<method?> // method@%0*x", width, index);
444      }
445      break;
446    case Instruction::kIndexFieldRef:
447      if (index < header->GetCollections().FieldIdsSize()) {
448        dex_ir::FieldId* field_id = header->GetCollections().GetFieldId(index);
449        const char* name = field_id->Name()->Data();
450        const char* type_descriptor = field_id->Type()->GetStringId()->Data();
451        const char* back_descriptor = field_id->Class()->GetStringId()->Data();
452        outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // field@%0*x",
453                           back_descriptor, name, type_descriptor, width, index);
454      } else {
455        outSize = snprintf(buf.get(), buf_size, "<field?> // field@%0*x", width, index);
456      }
457      break;
458    case Instruction::kIndexVtableOffset:
459      outSize = snprintf(buf.get(), buf_size, "[%0*x] // vtable #%0*x",
460                         width, index, width, index);
461      break;
462    case Instruction::kIndexFieldOffset:
463      outSize = snprintf(buf.get(), buf_size, "[obj+%0*x]", width, index);
464      break;
465    case Instruction::kIndexMethodAndProtoRef: {
466      std::string method("<method?>");
467      std::string proto("<proto?>");
468      if (index < header->GetCollections().MethodIdsSize()) {
469        dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index);
470        const char* name = method_id->Name()->Data();
471        std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
472        const char* back_descriptor = method_id->Class()->GetStringId()->Data();
473        method = StringPrintf("%s.%s:%s", back_descriptor, name, type_descriptor.c_str());
474      }
475      if (secondary_index < header->GetCollections().ProtoIdsSize()) {
476        dex_ir::ProtoId* proto_id = header->GetCollections().GetProtoId(secondary_index);
477        proto = GetSignatureForProtoId(proto_id);
478      }
479      outSize = snprintf(buf.get(), buf_size, "%s, %s // method@%0*x, proto@%0*x",
480                         method.c_str(), proto.c_str(), width, index, width, secondary_index);
481    }
482    break;
483    // SOME NOT SUPPORTED:
484    // case Instruction::kIndexVaries:
485    // case Instruction::kIndexInlineMethod:
486    default:
487      outSize = snprintf(buf.get(), buf_size, "<?>");
488      break;
489  }  // switch
490
491  // Determine success of string construction.
492  if (outSize >= buf_size) {
493    // The buffer wasn't big enough; retry with computed size. Note: snprintf()
494    // doesn't count/ the '\0' as part of its returned size, so we add explicit
495    // space for it here.
496    return IndexString(header, dec_insn, outSize + 1);
497  }
498  return buf;
499}
500
501/*
502 * Dumps encoded annotation.
503 */
504void DexLayout::DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation) {
505  fputs(annotation->GetType()->GetStringId()->Data(), out_file_);
506  // Display all name=value pairs.
507  for (auto& subannotation : *annotation->GetAnnotationElements()) {
508    fputc(' ', out_file_);
509    fputs(subannotation->GetName()->Data(), out_file_);
510    fputc('=', out_file_);
511    DumpEncodedValue(subannotation->GetValue());
512  }
513}
514/*
515 * Dumps encoded value.
516 */
517void DexLayout::DumpEncodedValue(const dex_ir::EncodedValue* data) {
518  switch (data->Type()) {
519    case DexFile::kDexAnnotationByte:
520      fprintf(out_file_, "%" PRId8, data->GetByte());
521      break;
522    case DexFile::kDexAnnotationShort:
523      fprintf(out_file_, "%" PRId16, data->GetShort());
524      break;
525    case DexFile::kDexAnnotationChar:
526      fprintf(out_file_, "%" PRIu16, data->GetChar());
527      break;
528    case DexFile::kDexAnnotationInt:
529      fprintf(out_file_, "%" PRId32, data->GetInt());
530      break;
531    case DexFile::kDexAnnotationLong:
532      fprintf(out_file_, "%" PRId64, data->GetLong());
533      break;
534    case DexFile::kDexAnnotationFloat: {
535      fprintf(out_file_, "%g", data->GetFloat());
536      break;
537    }
538    case DexFile::kDexAnnotationDouble: {
539      fprintf(out_file_, "%g", data->GetDouble());
540      break;
541    }
542    case DexFile::kDexAnnotationString: {
543      dex_ir::StringId* string_id = data->GetStringId();
544      if (options_.output_format_ == kOutputPlain) {
545        DumpEscapedString(string_id->Data(), out_file_);
546      } else {
547        DumpXmlAttribute(string_id->Data(), out_file_);
548      }
549      break;
550    }
551    case DexFile::kDexAnnotationType: {
552      dex_ir::TypeId* type_id = data->GetTypeId();
553      fputs(type_id->GetStringId()->Data(), out_file_);
554      break;
555    }
556    case DexFile::kDexAnnotationField:
557    case DexFile::kDexAnnotationEnum: {
558      dex_ir::FieldId* field_id = data->GetFieldId();
559      fputs(field_id->Name()->Data(), out_file_);
560      break;
561    }
562    case DexFile::kDexAnnotationMethod: {
563      dex_ir::MethodId* method_id = data->GetMethodId();
564      fputs(method_id->Name()->Data(), out_file_);
565      break;
566    }
567    case DexFile::kDexAnnotationArray: {
568      fputc('{', out_file_);
569      // Display all elements.
570      for (auto& value : *data->GetEncodedArray()->GetEncodedValues()) {
571        fputc(' ', out_file_);
572        DumpEncodedValue(value.get());
573      }
574      fputs(" }", out_file_);
575      break;
576    }
577    case DexFile::kDexAnnotationAnnotation: {
578      DumpEncodedAnnotation(data->GetEncodedAnnotation());
579      break;
580    }
581    case DexFile::kDexAnnotationNull:
582      fputs("null", out_file_);
583      break;
584    case DexFile::kDexAnnotationBoolean:
585      fputs(StrBool(data->GetBoolean()), out_file_);
586      break;
587    default:
588      fputs("????", out_file_);
589      break;
590  }  // switch
591}
592
593/*
594 * Dumps the file header.
595 */
596void DexLayout::DumpFileHeader() {
597  char sanitized[8 * 2 + 1];
598  dex_ir::Collections& collections = header_->GetCollections();
599  fprintf(out_file_, "DEX file header:\n");
600  Asciify(sanitized, header_->Magic(), 8);
601  fprintf(out_file_, "magic               : '%s'\n", sanitized);
602  fprintf(out_file_, "checksum            : %08x\n", header_->Checksum());
603  fprintf(out_file_, "signature           : %02x%02x...%02x%02x\n",
604          header_->Signature()[0], header_->Signature()[1],
605          header_->Signature()[DexFile::kSha1DigestSize - 2],
606          header_->Signature()[DexFile::kSha1DigestSize - 1]);
607  fprintf(out_file_, "file_size           : %d\n", header_->FileSize());
608  fprintf(out_file_, "header_size         : %d\n", header_->HeaderSize());
609  fprintf(out_file_, "link_size           : %d\n", header_->LinkSize());
610  fprintf(out_file_, "link_off            : %d (0x%06x)\n",
611          header_->LinkOffset(), header_->LinkOffset());
612  fprintf(out_file_, "string_ids_size     : %d\n", collections.StringIdsSize());
613  fprintf(out_file_, "string_ids_off      : %d (0x%06x)\n",
614          collections.StringIdsOffset(), collections.StringIdsOffset());
615  fprintf(out_file_, "type_ids_size       : %d\n", collections.TypeIdsSize());
616  fprintf(out_file_, "type_ids_off        : %d (0x%06x)\n",
617          collections.TypeIdsOffset(), collections.TypeIdsOffset());
618  fprintf(out_file_, "proto_ids_size      : %d\n", collections.ProtoIdsSize());
619  fprintf(out_file_, "proto_ids_off       : %d (0x%06x)\n",
620          collections.ProtoIdsOffset(), collections.ProtoIdsOffset());
621  fprintf(out_file_, "field_ids_size      : %d\n", collections.FieldIdsSize());
622  fprintf(out_file_, "field_ids_off       : %d (0x%06x)\n",
623          collections.FieldIdsOffset(), collections.FieldIdsOffset());
624  fprintf(out_file_, "method_ids_size     : %d\n", collections.MethodIdsSize());
625  fprintf(out_file_, "method_ids_off      : %d (0x%06x)\n",
626          collections.MethodIdsOffset(), collections.MethodIdsOffset());
627  fprintf(out_file_, "class_defs_size     : %d\n", collections.ClassDefsSize());
628  fprintf(out_file_, "class_defs_off      : %d (0x%06x)\n",
629          collections.ClassDefsOffset(), collections.ClassDefsOffset());
630  fprintf(out_file_, "data_size           : %d\n", header_->DataSize());
631  fprintf(out_file_, "data_off            : %d (0x%06x)\n\n",
632          header_->DataOffset(), header_->DataOffset());
633}
634
635/*
636 * Dumps a class_def_item.
637 */
638void DexLayout::DumpClassDef(int idx) {
639  // General class information.
640  dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx);
641  fprintf(out_file_, "Class #%d header:\n", idx);
642  fprintf(out_file_, "class_idx           : %d\n", class_def->ClassType()->GetIndex());
643  fprintf(out_file_, "access_flags        : %d (0x%04x)\n",
644          class_def->GetAccessFlags(), class_def->GetAccessFlags());
645  uint32_t superclass_idx =  class_def->Superclass() == nullptr ?
646      DexFile::kDexNoIndex16 : class_def->Superclass()->GetIndex();
647  fprintf(out_file_, "superclass_idx      : %d\n", superclass_idx);
648  fprintf(out_file_, "interfaces_off      : %d (0x%06x)\n",
649          class_def->InterfacesOffset(), class_def->InterfacesOffset());
650  uint32_t source_file_offset = 0xffffffffU;
651  if (class_def->SourceFile() != nullptr) {
652    source_file_offset = class_def->SourceFile()->GetIndex();
653  }
654  fprintf(out_file_, "source_file_idx     : %d\n", source_file_offset);
655  uint32_t annotations_offset = 0;
656  if (class_def->Annotations() != nullptr) {
657    annotations_offset = class_def->Annotations()->GetOffset();
658  }
659  fprintf(out_file_, "annotations_off     : %d (0x%06x)\n",
660          annotations_offset, annotations_offset);
661  if (class_def->GetClassData() == nullptr) {
662    fprintf(out_file_, "class_data_off      : %d (0x%06x)\n", 0, 0);
663  } else {
664    fprintf(out_file_, "class_data_off      : %d (0x%06x)\n",
665            class_def->GetClassData()->GetOffset(), class_def->GetClassData()->GetOffset());
666  }
667
668  // Fields and methods.
669  dex_ir::ClassData* class_data = class_def->GetClassData();
670  if (class_data != nullptr && class_data->StaticFields() != nullptr) {
671    fprintf(out_file_, "static_fields_size  : %zu\n", class_data->StaticFields()->size());
672  } else {
673    fprintf(out_file_, "static_fields_size  : 0\n");
674  }
675  if (class_data != nullptr && class_data->InstanceFields() != nullptr) {
676    fprintf(out_file_, "instance_fields_size: %zu\n", class_data->InstanceFields()->size());
677  } else {
678    fprintf(out_file_, "instance_fields_size: 0\n");
679  }
680  if (class_data != nullptr && class_data->DirectMethods() != nullptr) {
681    fprintf(out_file_, "direct_methods_size : %zu\n", class_data->DirectMethods()->size());
682  } else {
683    fprintf(out_file_, "direct_methods_size : 0\n");
684  }
685  if (class_data != nullptr && class_data->VirtualMethods() != nullptr) {
686    fprintf(out_file_, "virtual_methods_size: %zu\n", class_data->VirtualMethods()->size());
687  } else {
688    fprintf(out_file_, "virtual_methods_size: 0\n");
689  }
690  fprintf(out_file_, "\n");
691}
692
693/**
694 * Dumps an annotation set item.
695 */
696void DexLayout::DumpAnnotationSetItem(dex_ir::AnnotationSetItem* set_item) {
697  if (set_item == nullptr || set_item->GetItems()->size() == 0) {
698    fputs("  empty-annotation-set\n", out_file_);
699    return;
700  }
701  for (dex_ir::AnnotationItem* annotation : *set_item->GetItems()) {
702    if (annotation == nullptr) {
703      continue;
704    }
705    fputs("  ", out_file_);
706    switch (annotation->GetVisibility()) {
707      case DexFile::kDexVisibilityBuild:   fputs("VISIBILITY_BUILD ",   out_file_); break;
708      case DexFile::kDexVisibilityRuntime: fputs("VISIBILITY_RUNTIME ", out_file_); break;
709      case DexFile::kDexVisibilitySystem:  fputs("VISIBILITY_SYSTEM ",  out_file_); break;
710      default:                             fputs("VISIBILITY_UNKNOWN ", out_file_); break;
711    }  // switch
712    DumpEncodedAnnotation(annotation->GetAnnotation());
713    fputc('\n', out_file_);
714  }
715}
716
717/*
718 * Dumps class annotations.
719 */
720void DexLayout::DumpClassAnnotations(int idx) {
721  dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx);
722  dex_ir::AnnotationsDirectoryItem* annotations_directory = class_def->Annotations();
723  if (annotations_directory == nullptr) {
724    return;  // none
725  }
726
727  fprintf(out_file_, "Class #%d annotations:\n", idx);
728
729  dex_ir::AnnotationSetItem* class_set_item = annotations_directory->GetClassAnnotation();
730  dex_ir::FieldAnnotationVector* fields = annotations_directory->GetFieldAnnotations();
731  dex_ir::MethodAnnotationVector* methods = annotations_directory->GetMethodAnnotations();
732  dex_ir::ParameterAnnotationVector* parameters = annotations_directory->GetParameterAnnotations();
733
734  // Annotations on the class itself.
735  if (class_set_item != nullptr) {
736    fprintf(out_file_, "Annotations on class\n");
737    DumpAnnotationSetItem(class_set_item);
738  }
739
740  // Annotations on fields.
741  if (fields != nullptr) {
742    for (auto& field : *fields) {
743      const dex_ir::FieldId* field_id = field->GetFieldId();
744      const uint32_t field_idx = field_id->GetIndex();
745      const char* field_name = field_id->Name()->Data();
746      fprintf(out_file_, "Annotations on field #%u '%s'\n", field_idx, field_name);
747      DumpAnnotationSetItem(field->GetAnnotationSetItem());
748    }
749  }
750
751  // Annotations on methods.
752  if (methods != nullptr) {
753    for (auto& method : *methods) {
754      const dex_ir::MethodId* method_id = method->GetMethodId();
755      const uint32_t method_idx = method_id->GetIndex();
756      const char* method_name = method_id->Name()->Data();
757      fprintf(out_file_, "Annotations on method #%u '%s'\n", method_idx, method_name);
758      DumpAnnotationSetItem(method->GetAnnotationSetItem());
759    }
760  }
761
762  // Annotations on method parameters.
763  if (parameters != nullptr) {
764    for (auto& parameter : *parameters) {
765      const dex_ir::MethodId* method_id = parameter->GetMethodId();
766      const uint32_t method_idx = method_id->GetIndex();
767      const char* method_name = method_id->Name()->Data();
768      fprintf(out_file_, "Annotations on method #%u '%s' parameters\n", method_idx, method_name);
769      uint32_t j = 0;
770      for (dex_ir::AnnotationSetItem* annotation : *parameter->GetAnnotations()->GetItems()) {
771        fprintf(out_file_, "#%u\n", j);
772        DumpAnnotationSetItem(annotation);
773        ++j;
774      }
775    }
776  }
777
778  fputc('\n', out_file_);
779}
780
781/*
782 * Dumps an interface that a class declares to implement.
783 */
784void DexLayout::DumpInterface(const dex_ir::TypeId* type_item, int i) {
785  const char* interface_name = type_item->GetStringId()->Data();
786  if (options_.output_format_ == kOutputPlain) {
787    fprintf(out_file_, "    #%d              : '%s'\n", i, interface_name);
788  } else {
789    std::string dot(DescriptorToDotWrapper(interface_name));
790    fprintf(out_file_, "<implements name=\"%s\">\n</implements>\n", dot.c_str());
791  }
792}
793
794/*
795 * Dumps the catches table associated with the code.
796 */
797void DexLayout::DumpCatches(const dex_ir::CodeItem* code) {
798  const uint16_t tries_size = code->TriesSize();
799
800  // No catch table.
801  if (tries_size == 0) {
802    fprintf(out_file_, "      catches       : (none)\n");
803    return;
804  }
805
806  // Dump all table entries.
807  fprintf(out_file_, "      catches       : %d\n", tries_size);
808  std::vector<std::unique_ptr<const dex_ir::TryItem>>* tries = code->Tries();
809  for (uint32_t i = 0; i < tries_size; i++) {
810    const dex_ir::TryItem* try_item = (*tries)[i].get();
811    const uint32_t start = try_item->StartAddr();
812    const uint32_t end = start + try_item->InsnCount();
813    fprintf(out_file_, "        0x%04x - 0x%04x\n", start, end);
814    for (auto& handler : *try_item->GetHandlers()->GetHandlers()) {
815      const dex_ir::TypeId* type_id = handler->GetTypeId();
816      const char* descriptor = (type_id == nullptr) ? "<any>" : type_id->GetStringId()->Data();
817      fprintf(out_file_, "          %s -> 0x%04x\n", descriptor, handler->GetAddress());
818    }  // for
819  }  // for
820}
821
822/*
823 * Dumps a single instruction.
824 */
825void DexLayout::DumpInstruction(const dex_ir::CodeItem* code,
826                                uint32_t code_offset,
827                                uint32_t insn_idx,
828                                uint32_t insn_width,
829                                const Instruction* dec_insn) {
830  // Address of instruction (expressed as byte offset).
831  fprintf(out_file_, "%06x:", code_offset + 0x10 + insn_idx * 2);
832
833  // Dump (part of) raw bytes.
834  const uint16_t* insns = code->Insns();
835  for (uint32_t i = 0; i < 8; i++) {
836    if (i < insn_width) {
837      if (i == 7) {
838        fprintf(out_file_, " ... ");
839      } else {
840        // Print 16-bit value in little-endian order.
841        const uint8_t* bytePtr = (const uint8_t*) &insns[insn_idx + i];
842        fprintf(out_file_, " %02x%02x", bytePtr[0], bytePtr[1]);
843      }
844    } else {
845      fputs("     ", out_file_);
846    }
847  }  // for
848
849  // Dump pseudo-instruction or opcode.
850  if (dec_insn->Opcode() == Instruction::NOP) {
851    const uint16_t instr = Get2LE((const uint8_t*) &insns[insn_idx]);
852    if (instr == Instruction::kPackedSwitchSignature) {
853      fprintf(out_file_, "|%04x: packed-switch-data (%d units)", insn_idx, insn_width);
854    } else if (instr == Instruction::kSparseSwitchSignature) {
855      fprintf(out_file_, "|%04x: sparse-switch-data (%d units)", insn_idx, insn_width);
856    } else if (instr == Instruction::kArrayDataSignature) {
857      fprintf(out_file_, "|%04x: array-data (%d units)", insn_idx, insn_width);
858    } else {
859      fprintf(out_file_, "|%04x: nop // spacer", insn_idx);
860    }
861  } else {
862    fprintf(out_file_, "|%04x: %s", insn_idx, dec_insn->Name());
863  }
864
865  // Set up additional argument.
866  std::unique_ptr<char[]> index_buf;
867  if (Instruction::IndexTypeOf(dec_insn->Opcode()) != Instruction::kIndexNone) {
868    index_buf = IndexString(header_, dec_insn, 200);
869  }
870
871  // Dump the instruction.
872  //
873  // NOTE: pDecInsn->DumpString(pDexFile) differs too much from original.
874  //
875  switch (Instruction::FormatOf(dec_insn->Opcode())) {
876    case Instruction::k10x:        // op
877      break;
878    case Instruction::k12x:        // op vA, vB
879      fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB());
880      break;
881    case Instruction::k11n:        // op vA, #+B
882      fprintf(out_file_, " v%d, #int %d // #%x",
883              dec_insn->VRegA(), (int32_t) dec_insn->VRegB(), (uint8_t)dec_insn->VRegB());
884      break;
885    case Instruction::k11x:        // op vAA
886      fprintf(out_file_, " v%d", dec_insn->VRegA());
887      break;
888    case Instruction::k10t:        // op +AA
889    case Instruction::k20t: {      // op +AAAA
890      const int32_t targ = (int32_t) dec_insn->VRegA();
891      fprintf(out_file_, " %04x // %c%04x",
892              insn_idx + targ,
893              (targ < 0) ? '-' : '+',
894              (targ < 0) ? -targ : targ);
895      break;
896    }
897    case Instruction::k22x:        // op vAA, vBBBB
898      fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB());
899      break;
900    case Instruction::k21t: {     // op vAA, +BBBB
901      const int32_t targ = (int32_t) dec_insn->VRegB();
902      fprintf(out_file_, " v%d, %04x // %c%04x", dec_insn->VRegA(),
903              insn_idx + targ,
904              (targ < 0) ? '-' : '+',
905              (targ < 0) ? -targ : targ);
906      break;
907    }
908    case Instruction::k21s:        // op vAA, #+BBBB
909      fprintf(out_file_, " v%d, #int %d // #%x",
910              dec_insn->VRegA(), (int32_t) dec_insn->VRegB(), (uint16_t)dec_insn->VRegB());
911      break;
912    case Instruction::k21h:        // op vAA, #+BBBB0000[00000000]
913      // The printed format varies a bit based on the actual opcode.
914      if (dec_insn->Opcode() == Instruction::CONST_HIGH16) {
915        const int32_t value = dec_insn->VRegB() << 16;
916        fprintf(out_file_, " v%d, #int %d // #%x",
917                dec_insn->VRegA(), value, (uint16_t) dec_insn->VRegB());
918      } else {
919        const int64_t value = ((int64_t) dec_insn->VRegB()) << 48;
920        fprintf(out_file_, " v%d, #long %" PRId64 " // #%x",
921                dec_insn->VRegA(), value, (uint16_t) dec_insn->VRegB());
922      }
923      break;
924    case Instruction::k21c:        // op vAA, thing@BBBB
925    case Instruction::k31c:        // op vAA, thing@BBBBBBBB
926      fprintf(out_file_, " v%d, %s", dec_insn->VRegA(), index_buf.get());
927      break;
928    case Instruction::k23x:        // op vAA, vBB, vCC
929      fprintf(out_file_, " v%d, v%d, v%d",
930              dec_insn->VRegA(), dec_insn->VRegB(), dec_insn->VRegC());
931      break;
932    case Instruction::k22b:        // op vAA, vBB, #+CC
933      fprintf(out_file_, " v%d, v%d, #int %d // #%02x",
934              dec_insn->VRegA(), dec_insn->VRegB(),
935              (int32_t) dec_insn->VRegC(), (uint8_t) dec_insn->VRegC());
936      break;
937    case Instruction::k22t: {      // op vA, vB, +CCCC
938      const int32_t targ = (int32_t) dec_insn->VRegC();
939      fprintf(out_file_, " v%d, v%d, %04x // %c%04x",
940              dec_insn->VRegA(), dec_insn->VRegB(),
941              insn_idx + targ,
942              (targ < 0) ? '-' : '+',
943              (targ < 0) ? -targ : targ);
944      break;
945    }
946    case Instruction::k22s:        // op vA, vB, #+CCCC
947      fprintf(out_file_, " v%d, v%d, #int %d // #%04x",
948              dec_insn->VRegA(), dec_insn->VRegB(),
949              (int32_t) dec_insn->VRegC(), (uint16_t) dec_insn->VRegC());
950      break;
951    case Instruction::k22c:        // op vA, vB, thing@CCCC
952    // NOT SUPPORTED:
953    // case Instruction::k22cs:    // [opt] op vA, vB, field offset CCCC
954      fprintf(out_file_, " v%d, v%d, %s",
955              dec_insn->VRegA(), dec_insn->VRegB(), index_buf.get());
956      break;
957    case Instruction::k30t:
958      fprintf(out_file_, " #%08x", dec_insn->VRegA());
959      break;
960    case Instruction::k31i: {     // op vAA, #+BBBBBBBB
961      // This is often, but not always, a float.
962      union {
963        float f;
964        uint32_t i;
965      } conv;
966      conv.i = dec_insn->VRegB();
967      fprintf(out_file_, " v%d, #float %g // #%08x",
968              dec_insn->VRegA(), conv.f, dec_insn->VRegB());
969      break;
970    }
971    case Instruction::k31t:       // op vAA, offset +BBBBBBBB
972      fprintf(out_file_, " v%d, %08x // +%08x",
973              dec_insn->VRegA(), insn_idx + dec_insn->VRegB(), dec_insn->VRegB());
974      break;
975    case Instruction::k32x:        // op vAAAA, vBBBB
976      fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB());
977      break;
978    case Instruction::k35c:           // op {vC, vD, vE, vF, vG}, thing@BBBB
979    case Instruction::k45cc: {        // op {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH
980    // NOT SUPPORTED:
981    // case Instruction::k35ms:       // [opt] invoke-virtual+super
982    // case Instruction::k35mi:       // [opt] inline invoke
983      uint32_t arg[Instruction::kMaxVarArgRegs];
984      dec_insn->GetVarArgs(arg);
985      fputs(" {", out_file_);
986      for (int i = 0, n = dec_insn->VRegA(); i < n; i++) {
987        if (i == 0) {
988          fprintf(out_file_, "v%d", arg[i]);
989        } else {
990          fprintf(out_file_, ", v%d", arg[i]);
991        }
992      }  // for
993      fprintf(out_file_, "}, %s", index_buf.get());
994      break;
995    }
996    case Instruction::k3rc:           // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB
997    case Instruction::k4rcc:          // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB, proto@HHHH
998    // NOT SUPPORTED:
999    // case Instruction::k3rms:       // [opt] invoke-virtual+super/range
1000    // case Instruction::k3rmi:       // [opt] execute-inline/range
1001      {
1002        // This doesn't match the "dx" output when some of the args are
1003        // 64-bit values -- dx only shows the first register.
1004        fputs(" {", out_file_);
1005        for (int i = 0, n = dec_insn->VRegA(); i < n; i++) {
1006          if (i == 0) {
1007            fprintf(out_file_, "v%d", dec_insn->VRegC() + i);
1008          } else {
1009            fprintf(out_file_, ", v%d", dec_insn->VRegC() + i);
1010          }
1011        }  // for
1012        fprintf(out_file_, "}, %s", index_buf.get());
1013      }
1014      break;
1015    case Instruction::k51l: {      // op vAA, #+BBBBBBBBBBBBBBBB
1016      // This is often, but not always, a double.
1017      union {
1018        double d;
1019        uint64_t j;
1020      } conv;
1021      conv.j = dec_insn->WideVRegB();
1022      fprintf(out_file_, " v%d, #double %g // #%016" PRIx64,
1023              dec_insn->VRegA(), conv.d, dec_insn->WideVRegB());
1024      break;
1025    }
1026    // NOT SUPPORTED:
1027    // case Instruction::k00x:        // unknown op or breakpoint
1028    //    break;
1029    default:
1030      fprintf(out_file_, " ???");
1031      break;
1032  }  // switch
1033
1034  fputc('\n', out_file_);
1035}
1036
1037/*
1038 * Dumps a bytecode disassembly.
1039 */
1040void DexLayout::DumpBytecodes(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset) {
1041  dex_ir::MethodId* method_id = header_->GetCollections().GetMethodId(idx);
1042  const char* name = method_id->Name()->Data();
1043  std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
1044  const char* back_descriptor = method_id->Class()->GetStringId()->Data();
1045
1046  // Generate header.
1047  std::string dot(DescriptorToDotWrapper(back_descriptor));
1048  fprintf(out_file_, "%06x:                                        |[%06x] %s.%s:%s\n",
1049          code_offset, code_offset, dot.c_str(), name, type_descriptor.c_str());
1050
1051  // Iterate over all instructions.
1052  IterationRange<DexInstructionIterator> instructions = code->Instructions();
1053  for (auto inst = instructions.begin(); inst != instructions.end(); ++inst) {
1054    const uint32_t dex_pc = inst.GetDexPC(instructions.begin());
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", dex_pc);
1058      break;
1059    }
1060    DumpInstruction(code, code_offset, dex_pc, insn_width, &*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
1564std::vector<dex_ir::ClassData*> 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  uint32_t class_defs_offset = header_->GetCollections().ClassDefsOffset();
1579  uint32_t class_data_offset = header_->GetCollections().ClassDatasOffset();
1580  std::unordered_set<dex_ir::ClassData*> visited_class_data;
1581  std::vector<dex_ir::ClassData*> new_class_data_order;
1582  for (uint32_t i = 0; i < new_class_def_order.size(); ++i) {
1583    dex_ir::ClassDef* class_def = new_class_def_order[i];
1584    class_def->SetIndex(i);
1585    class_def->SetOffset(class_defs_offset);
1586    class_defs_offset += dex_ir::ClassDef::ItemSize();
1587    dex_ir::ClassData* class_data = class_def->GetClassData();
1588    if (class_data != nullptr && visited_class_data.find(class_data) == visited_class_data.end()) {
1589      class_data->SetOffset(class_data_offset);
1590      class_data_offset += class_data->GetSize();
1591      visited_class_data.insert(class_data);
1592      new_class_data_order.push_back(class_data);
1593    }
1594  }
1595  return new_class_data_order;
1596}
1597
1598void DexLayout::LayoutStringData(const DexFile* dex_file) {
1599  const size_t num_strings = header_->GetCollections().StringIds().size();
1600  std::vector<bool> is_shorty(num_strings, false);
1601  std::vector<bool> from_hot_method(num_strings, false);
1602  for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
1603    // A name of a profile class is probably going to get looked up by ClassTable::Lookup, mark it
1604    // as hot. Add its super class and interfaces as well, which can be used during initialization.
1605    const bool is_profile_class =
1606        info_->ContainsClass(*dex_file, dex::TypeIndex(class_def->ClassType()->GetIndex()));
1607    if (is_profile_class) {
1608      from_hot_method[class_def->ClassType()->GetStringId()->GetIndex()] = true;
1609      const dex_ir::TypeId* superclass = class_def->Superclass();
1610      if (superclass != nullptr) {
1611        from_hot_method[superclass->GetStringId()->GetIndex()] = true;
1612      }
1613      const dex_ir::TypeList* interfaces = class_def->Interfaces();
1614      if (interfaces != nullptr) {
1615        for (const dex_ir::TypeId* interface_type : *interfaces->GetTypeList()) {
1616          from_hot_method[interface_type->GetStringId()->GetIndex()] = true;
1617        }
1618      }
1619    }
1620    dex_ir::ClassData* data = class_def->GetClassData();
1621    if (data == nullptr) {
1622      continue;
1623    }
1624    for (size_t i = 0; i < 2; ++i) {
1625      for (auto& method : *(i == 0 ? data->DirectMethods() : data->VirtualMethods())) {
1626        const dex_ir::MethodId* method_id = method->GetMethodId();
1627        dex_ir::CodeItem* code_item = method->GetCodeItem();
1628        if (code_item == nullptr) {
1629          continue;
1630        }
1631        const bool is_clinit = is_profile_class &&
1632            (method->GetAccessFlags() & kAccConstructor) != 0 &&
1633            (method->GetAccessFlags() & kAccStatic) != 0;
1634        const bool method_executed = is_clinit ||
1635            info_->GetMethodHotness(MethodReference(dex_file, method_id->GetIndex())).IsInProfile();
1636        if (!method_executed) {
1637          continue;
1638        }
1639        is_shorty[method_id->Proto()->Shorty()->GetIndex()] = true;
1640        dex_ir::CodeFixups* fixups = code_item->GetCodeFixups();
1641        if (fixups == nullptr) {
1642          continue;
1643        }
1644        // Add const-strings.
1645        for (dex_ir::StringId* id : *fixups->StringIds()) {
1646          from_hot_method[id->GetIndex()] = true;
1647        }
1648        // Add field classes, names, and types.
1649        for (dex_ir::FieldId* id : *fixups->FieldIds()) {
1650          // TODO: Only visit field ids from static getters and setters.
1651          from_hot_method[id->Class()->GetStringId()->GetIndex()] = true;
1652          from_hot_method[id->Name()->GetIndex()] = true;
1653          from_hot_method[id->Type()->GetStringId()->GetIndex()] = true;
1654        }
1655        // For clinits, add referenced method classes, names, and protos.
1656        if (is_clinit) {
1657          for (dex_ir::MethodId* id : *fixups->MethodIds()) {
1658            from_hot_method[id->Class()->GetStringId()->GetIndex()] = true;
1659            from_hot_method[id->Name()->GetIndex()] = true;
1660            is_shorty[id->Proto()->Shorty()->GetIndex()] = true;
1661          }
1662        }
1663      }
1664    }
1665  }
1666  // Sort string data by specified order.
1667  std::vector<dex_ir::StringId*> string_ids;
1668  size_t min_offset = std::numeric_limits<size_t>::max();
1669  size_t max_offset = 0;
1670  size_t hot_bytes = 0;
1671  for (auto& string_id : header_->GetCollections().StringIds()) {
1672    string_ids.push_back(string_id.get());
1673    const size_t cur_offset = string_id->DataItem()->GetOffset();
1674    CHECK_NE(cur_offset, 0u);
1675    min_offset = std::min(min_offset, cur_offset);
1676    dex_ir::StringData* data = string_id->DataItem();
1677    const size_t element_size = data->GetSize() + 1;  // Add one extra for null.
1678    size_t end_offset = cur_offset + element_size;
1679    if (is_shorty[string_id->GetIndex()] || from_hot_method[string_id->GetIndex()]) {
1680      hot_bytes += element_size;
1681    }
1682    max_offset = std::max(max_offset, end_offset);
1683  }
1684  VLOG(compiler) << "Hot string data bytes " << hot_bytes << "/" << max_offset - min_offset;
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    // Preserve order.
1701    return a->DataItem()->GetOffset() < b->DataItem()->GetOffset();
1702  });
1703  // Now we know what order we want the string data, reorder the offsets.
1704  size_t offset = min_offset;
1705  for (dex_ir::StringId* string_id : string_ids) {
1706    dex_ir::StringData* data = string_id->DataItem();
1707    data->SetOffset(offset);
1708    offset += data->GetSize() + 1;  // Add one extra for null.
1709  }
1710  if (offset > max_offset) {
1711    const uint32_t diff = offset - max_offset;
1712    // If we expanded the string data section, we need to update the offsets or else we will
1713    // corrupt the next section when writing out.
1714    FixupSections(header_->GetCollections().StringDatasOffset(), diff);
1715    // Update file size.
1716    header_->SetFileSize(header_->FileSize() + diff);
1717  }
1718}
1719
1720// Orders code items according to specified class data ordering.
1721// NOTE: If the section following the code items is byte aligned, the last code item is left in
1722// place to preserve alignment. Layout needs an overhaul to handle movement of other sections.
1723int32_t DexLayout::LayoutCodeItems(const DexFile* dex_file,
1724                                   std::vector<dex_ir::ClassData*> new_class_data_order) {
1725  // Do not move code items if class data section precedes code item section.
1726  // ULEB encoding is variable length, causing problems determining the offset of the code items.
1727  // TODO: We should swap the order of these sections in the future to avoid this issue.
1728  uint32_t class_data_offset = header_->GetCollections().ClassDatasOffset();
1729  uint32_t code_item_offset = header_->GetCollections().CodeItemsOffset();
1730  if (class_data_offset < code_item_offset) {
1731    return 0;
1732  }
1733
1734  // Find the last code item so we can leave it in place if the next section is not 4 byte aligned.
1735  dex_ir::CodeItem* last_code_item = nullptr;
1736  std::unordered_set<dex_ir::CodeItem*> visited_code_items;
1737  bool is_code_item_aligned = IsNextSectionCodeItemAligned(code_item_offset);
1738  if (!is_code_item_aligned) {
1739    for (auto& code_item_pair : header_->GetCollections().CodeItems()) {
1740      std::unique_ptr<dex_ir::CodeItem>& code_item = code_item_pair.second;
1741      if (last_code_item == nullptr
1742          || last_code_item->GetOffset() < code_item->GetOffset()) {
1743        last_code_item = code_item.get();
1744      }
1745    }
1746  }
1747
1748  static constexpr InvokeType invoke_types[] = {
1749    kDirect,
1750    kVirtual
1751  };
1752
1753  const size_t num_layout_types = static_cast<size_t>(LayoutType::kLayoutTypeCount);
1754  std::unordered_set<dex_ir::CodeItem*> code_items[num_layout_types];
1755  for (InvokeType invoke_type : invoke_types) {
1756    for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
1757      const bool is_profile_class =
1758          info_->ContainsClass(*dex_file, dex::TypeIndex(class_def->ClassType()->GetIndex()));
1759
1760      // Skip classes that are not defined in this dex file.
1761      dex_ir::ClassData* class_data = class_def->GetClassData();
1762      if (class_data == nullptr) {
1763        continue;
1764      }
1765      for (auto& method : *(invoke_type == InvokeType::kDirect
1766                                ? class_data->DirectMethods()
1767                                : class_data->VirtualMethods())) {
1768        const dex_ir::MethodId *method_id = method->GetMethodId();
1769        dex_ir::CodeItem *code_item = method->GetCodeItem();
1770        if (code_item == last_code_item || code_item == nullptr) {
1771          continue;
1772        }
1773        // Separate executed methods (clinits and profiled methods) from unexecuted methods.
1774        const bool is_clinit = (method->GetAccessFlags() & kAccConstructor) != 0 &&
1775            (method->GetAccessFlags() & kAccStatic) != 0;
1776        const bool is_startup_clinit = is_profile_class && is_clinit;
1777        using Hotness = ProfileCompilationInfo::MethodHotness;
1778        Hotness hotness = info_->GetMethodHotness(MethodReference(dex_file, method_id->GetIndex()));
1779        LayoutType state = LayoutType::kLayoutTypeUnused;
1780        if (hotness.IsHot()) {
1781          // Hot code is compiled, maybe one day it won't be accessed. So lay it out together for
1782          // now.
1783          state = LayoutType::kLayoutTypeHot;
1784        } else if (is_startup_clinit || hotness.GetFlags() == Hotness::kFlagStartup) {
1785          // Startup clinit or a method that only has the startup flag.
1786          state = LayoutType::kLayoutTypeStartupOnly;
1787        } else if (is_clinit) {
1788          state = LayoutType::kLayoutTypeUsedOnce;
1789        } else if (hotness.IsInProfile()) {
1790          state = LayoutType::kLayoutTypeSometimesUsed;
1791        }
1792        code_items[static_cast<size_t>(state)].insert(code_item);
1793      }
1794    }
1795  }
1796
1797  // Total_diff includes diffs generated by clinits, executed, and non-executed methods.
1798  int32_t total_diff = 0;
1799  // The relative placement has no effect on correctness; it is used to ensure
1800  // the layout is deterministic
1801  for (size_t index = 0; index < num_layout_types; ++index) {
1802    const std::unordered_set<dex_ir::CodeItem*>& code_items_set = code_items[index];
1803    // diff is reset for each class of code items.
1804    int32_t diff = 0;
1805    const uint32_t start_offset = code_item_offset;
1806    for (dex_ir::ClassData* data : new_class_data_order) {
1807      data->SetOffset(data->GetOffset() + diff);
1808      for (InvokeType invoke_type : invoke_types) {
1809        for (auto &method : *(invoke_type == InvokeType::kDirect
1810                                  ? data->DirectMethods()
1811                                  : data->VirtualMethods())) {
1812          dex_ir::CodeItem* code_item = method->GetCodeItem();
1813          if (code_item != nullptr &&
1814              code_items_set.find(code_item) != code_items_set.end()) {
1815            diff += UnsignedLeb128Size(code_item_offset)
1816                - UnsignedLeb128Size(code_item->GetOffset());
1817            code_item->SetOffset(code_item_offset);
1818            code_item_offset +=
1819                RoundUp(code_item->GetSize(), kDexCodeItemAlignment);
1820          }
1821        }
1822      }
1823    }
1824    DexLayoutSection& code_section = dex_sections_.sections_[static_cast<size_t>(
1825        DexLayoutSections::SectionType::kSectionTypeCode)];
1826    code_section.parts_[index].offset_ = start_offset;
1827    code_section.parts_[index].size_ = code_item_offset - start_offset;
1828    for (size_t i = 0; i < num_layout_types; ++i) {
1829      VLOG(dex) << "Code item layout bucket " << i << " count=" << code_items[i].size()
1830                << " bytes=" << code_section.parts_[i].size_;
1831    }
1832    total_diff += diff;
1833  }
1834  // Adjust diff to be 4-byte aligned.
1835  return RoundUp(total_diff, kDexCodeItemAlignment);
1836}
1837
1838bool DexLayout::IsNextSectionCodeItemAligned(uint32_t offset) {
1839  dex_ir::Collections& collections = header_->GetCollections();
1840  std::set<uint32_t> section_offsets;
1841  section_offsets.insert(collections.MapListOffset());
1842  section_offsets.insert(collections.TypeListsOffset());
1843  section_offsets.insert(collections.AnnotationSetRefListsOffset());
1844  section_offsets.insert(collections.AnnotationSetItemsOffset());
1845  section_offsets.insert(collections.ClassDatasOffset());
1846  section_offsets.insert(collections.CodeItemsOffset());
1847  section_offsets.insert(collections.StringDatasOffset());
1848  section_offsets.insert(collections.DebugInfoItemsOffset());
1849  section_offsets.insert(collections.AnnotationItemsOffset());
1850  section_offsets.insert(collections.EncodedArrayItemsOffset());
1851  section_offsets.insert(collections.AnnotationsDirectoryItemsOffset());
1852
1853  auto found = section_offsets.find(offset);
1854  if (found != section_offsets.end()) {
1855    found++;
1856    if (found != section_offsets.end()) {
1857      return *found % kDexCodeItemAlignment == 0;
1858    }
1859  }
1860  return false;
1861}
1862
1863// Adjust offsets of every item in the specified section by diff bytes.
1864template<class T> void DexLayout::FixupSection(std::map<uint32_t, std::unique_ptr<T>>& map,
1865                                               uint32_t diff) {
1866  for (auto& pair : map) {
1867    std::unique_ptr<T>& item = pair.second;
1868    item->SetOffset(item->GetOffset() + diff);
1869  }
1870}
1871
1872// Adjust offsets of all sections with an address after the specified offset by diff bytes.
1873void DexLayout::FixupSections(uint32_t offset, uint32_t diff) {
1874  dex_ir::Collections& collections = header_->GetCollections();
1875  uint32_t map_list_offset = collections.MapListOffset();
1876  if (map_list_offset > offset) {
1877    collections.SetMapListOffset(map_list_offset + diff);
1878  }
1879
1880  uint32_t type_lists_offset = collections.TypeListsOffset();
1881  if (type_lists_offset > offset) {
1882    collections.SetTypeListsOffset(type_lists_offset + diff);
1883    FixupSection(collections.TypeLists(), diff);
1884  }
1885
1886  uint32_t annotation_set_ref_lists_offset = collections.AnnotationSetRefListsOffset();
1887  if (annotation_set_ref_lists_offset > offset) {
1888    collections.SetAnnotationSetRefListsOffset(annotation_set_ref_lists_offset + diff);
1889    FixupSection(collections.AnnotationSetRefLists(), diff);
1890  }
1891
1892  uint32_t annotation_set_items_offset = collections.AnnotationSetItemsOffset();
1893  if (annotation_set_items_offset > offset) {
1894    collections.SetAnnotationSetItemsOffset(annotation_set_items_offset + diff);
1895    FixupSection(collections.AnnotationSetItems(), diff);
1896  }
1897
1898  uint32_t class_datas_offset = collections.ClassDatasOffset();
1899  if (class_datas_offset > offset) {
1900    collections.SetClassDatasOffset(class_datas_offset + diff);
1901    FixupSection(collections.ClassDatas(), diff);
1902  }
1903
1904  uint32_t code_items_offset = collections.CodeItemsOffset();
1905  if (code_items_offset > offset) {
1906    collections.SetCodeItemsOffset(code_items_offset + diff);
1907    FixupSection(collections.CodeItems(), diff);
1908  }
1909
1910  uint32_t string_datas_offset = collections.StringDatasOffset();
1911  if (string_datas_offset > offset) {
1912    collections.SetStringDatasOffset(string_datas_offset + diff);
1913    FixupSection(collections.StringDatas(), diff);
1914  }
1915
1916  uint32_t debug_info_items_offset = collections.DebugInfoItemsOffset();
1917  if (debug_info_items_offset > offset) {
1918    collections.SetDebugInfoItemsOffset(debug_info_items_offset + diff);
1919    FixupSection(collections.DebugInfoItems(), diff);
1920  }
1921
1922  uint32_t annotation_items_offset = collections.AnnotationItemsOffset();
1923  if (annotation_items_offset > offset) {
1924    collections.SetAnnotationItemsOffset(annotation_items_offset + diff);
1925    FixupSection(collections.AnnotationItems(), diff);
1926  }
1927
1928  uint32_t encoded_array_items_offset = collections.EncodedArrayItemsOffset();
1929  if (encoded_array_items_offset > offset) {
1930    collections.SetEncodedArrayItemsOffset(encoded_array_items_offset + diff);
1931    FixupSection(collections.EncodedArrayItems(), diff);
1932  }
1933
1934  uint32_t annotations_directory_items_offset = collections.AnnotationsDirectoryItemsOffset();
1935  if (annotations_directory_items_offset > offset) {
1936    collections.SetAnnotationsDirectoryItemsOffset(annotations_directory_items_offset + diff);
1937    FixupSection(collections.AnnotationsDirectoryItems(), diff);
1938  }
1939}
1940
1941void DexLayout::LayoutOutputFile(const DexFile* dex_file) {
1942  LayoutStringData(dex_file);
1943  std::vector<dex_ir::ClassData*> new_class_data_order = LayoutClassDefsAndClassData(dex_file);
1944  int32_t diff = LayoutCodeItems(dex_file, new_class_data_order);
1945  // Move sections after ClassData by diff bytes.
1946  FixupSections(header_->GetCollections().ClassDatasOffset(), diff);
1947  // Update file size.
1948  header_->SetFileSize(header_->FileSize() + diff);
1949}
1950
1951void DexLayout::OutputDexFile(const DexFile* dex_file) {
1952  const std::string& dex_file_location = dex_file->GetLocation();
1953  std::string error_msg;
1954  std::unique_ptr<File> new_file;
1955  if (!options_.output_to_memmap_) {
1956    std::string output_location(options_.output_dex_directory_);
1957    size_t last_slash = dex_file_location.rfind('/');
1958    std::string dex_file_directory = dex_file_location.substr(0, last_slash + 1);
1959    if (output_location == dex_file_directory) {
1960      output_location = dex_file_location + ".new";
1961    } else if (last_slash != std::string::npos) {
1962      output_location += dex_file_location.substr(last_slash);
1963    } else {
1964      output_location += "/" + dex_file_location + ".new";
1965    }
1966    new_file.reset(OS::CreateEmptyFile(output_location.c_str()));
1967    if (new_file == nullptr) {
1968      LOG(ERROR) << "Could not create dex writer output file: " << output_location;
1969      return;
1970    }
1971    if (ftruncate(new_file->Fd(), header_->FileSize()) != 0) {
1972      LOG(ERROR) << "Could not grow dex writer output file: " << output_location;;
1973      new_file->Erase();
1974      return;
1975    }
1976    mem_map_.reset(MemMap::MapFile(header_->FileSize(), PROT_READ | PROT_WRITE, MAP_SHARED,
1977        new_file->Fd(), 0, /*low_4gb*/ false, output_location.c_str(), &error_msg));
1978  } else {
1979    mem_map_.reset(MemMap::MapAnonymous("layout dex", nullptr, header_->FileSize(),
1980        PROT_READ | PROT_WRITE, /* low_4gb */ false, /* reuse */ false, &error_msg));
1981  }
1982  if (mem_map_ == nullptr) {
1983    LOG(ERROR) << "Could not create mem map for dex writer output: " << error_msg;
1984    if (new_file != nullptr) {
1985      new_file->Erase();
1986    }
1987    return;
1988  }
1989  DexWriter::Output(header_, mem_map_.get());
1990  if (new_file != nullptr) {
1991    UNUSED(new_file->FlushCloseOrErase());
1992  }
1993  // Verify the output dex file's structure for debug builds.
1994  if (kIsDebugBuild) {
1995    std::string location = "memory mapped file for " + dex_file_location;
1996    std::unique_ptr<const DexFile> output_dex_file(DexFileLoader::Open(mem_map_->Begin(),
1997                                                                       mem_map_->Size(),
1998                                                                       location,
1999                                                                       header_->Checksum(),
2000                                                                       /*oat_dex_file*/ nullptr,
2001                                                                       /*verify*/ true,
2002                                                                       /*verify_checksum*/ false,
2003                                                                       &error_msg));
2004    DCHECK(output_dex_file != nullptr) << "Failed to re-open output file:" << error_msg;
2005  }
2006  // Do IR-level comparison between input and output. This check ignores potential differences
2007  // due to layout, so offsets are not checked. Instead, it checks the data contents of each item.
2008  if (kIsDebugBuild || options_.verify_output_) {
2009    std::unique_ptr<dex_ir::Header> orig_header(dex_ir::DexIrBuilder(*dex_file));
2010    CHECK(VerifyOutputDexFile(orig_header.get(), header_, &error_msg)) << error_msg;
2011  }
2012}
2013
2014/*
2015 * Dumps the requested sections of the file.
2016 */
2017void DexLayout::ProcessDexFile(const char* file_name,
2018                               const DexFile* dex_file,
2019                               size_t dex_file_index) {
2020  std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file));
2021  SetHeader(header.get());
2022
2023  if (options_.verbose_) {
2024    fprintf(out_file_, "Opened '%s', DEX version '%.3s'\n",
2025            file_name, dex_file->GetHeader().magic_ + 4);
2026  }
2027
2028  if (options_.visualize_pattern_) {
2029    VisualizeDexLayout(header_, dex_file, dex_file_index, info_);
2030    return;
2031  }
2032
2033  if (options_.show_section_statistics_) {
2034    ShowDexSectionStatistics(header_, dex_file_index);
2035    return;
2036  }
2037
2038  // Dump dex file.
2039  if (options_.dump_) {
2040    DumpDexFile();
2041  }
2042
2043  // Output dex file as file or memmap.
2044  if (options_.output_dex_directory_ != nullptr || options_.output_to_memmap_) {
2045    if (info_ != nullptr) {
2046      LayoutOutputFile(dex_file);
2047    }
2048    OutputDexFile(dex_file);
2049  }
2050}
2051
2052/*
2053 * Processes a single file (either direct .dex or indirect .zip/.jar/.apk).
2054 */
2055int DexLayout::ProcessFile(const char* file_name) {
2056  if (options_.verbose_) {
2057    fprintf(out_file_, "Processing '%s'...\n", file_name);
2058  }
2059
2060  // If the file is not a .dex file, the function tries .zip/.jar/.apk files,
2061  // all of which are Zip archives with "classes.dex" inside.
2062  const bool verify_checksum = !options_.ignore_bad_checksum_;
2063  std::string error_msg;
2064  std::vector<std::unique_ptr<const DexFile>> dex_files;
2065  if (!DexFileLoader::Open(
2066        file_name, file_name, /* verify */ true, verify_checksum, &error_msg, &dex_files)) {
2067    // Display returned error message to user. Note that this error behavior
2068    // differs from the error messages shown by the original Dalvik dexdump.
2069    fputs(error_msg.c_str(), stderr);
2070    fputc('\n', stderr);
2071    return -1;
2072  }
2073
2074  // Success. Either report checksum verification or process
2075  // all dex files found in given file.
2076  if (options_.checksum_only_) {
2077    fprintf(out_file_, "Checksum verified\n");
2078  } else {
2079    for (size_t i = 0; i < dex_files.size(); i++) {
2080      ProcessDexFile(file_name, dex_files[i].get(), i);
2081    }
2082  }
2083  return 0;
2084}
2085
2086}  // namespace art
2087