Home | History | Annotate | Download | only in dexlayout
      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_ir_builder.h"
     37 #include "dex_file-inl.h"
     38 #include "dex_file_layout.h"
     39 #include "dex_file_verifier.h"
     40 #include "dex_instruction-inl.h"
     41 #include "dex_verify.h"
     42 #include "dex_visualize.h"
     43 #include "dex_writer.h"
     44 #include "jit/profile_compilation_info.h"
     45 #include "mem_map.h"
     46 #include "os.h"
     47 #include "utils.h"
     48 
     49 namespace art {
     50 
     51 using android::base::StringPrintf;
     52 
     53 static constexpr uint32_t kDexCodeItemAlignment = 4;
     54 
     55 /*
     56  * Flags for use with createAccessFlagStr().
     57  */
     58 enum AccessFor {
     59   kAccessForClass = 0, kAccessForMethod = 1, kAccessForField = 2, kAccessForMAX
     60 };
     61 const int kNumFlags = 18;
     62 
     63 /*
     64  * Gets 2 little-endian bytes.
     65  */
     66 static inline uint16_t Get2LE(unsigned char const* src) {
     67   return src[0] | (src[1] << 8);
     68 }
     69 
     70 /*
     71  * Converts a type descriptor to human-readable "dotted" form.  For
     72  * example, "Ljava/lang/String;" becomes "java.lang.String", and
     73  * "[I" becomes "int[]".  Also converts '$' to '.', which means this
     74  * form can't be converted back to a descriptor.
     75  */
     76 static std::string DescriptorToDotWrapper(const char* descriptor) {
     77   std::string result = DescriptorToDot(descriptor);
     78   size_t found = result.find('$');
     79   while (found != std::string::npos) {
     80     result[found] = '.';
     81     found = result.find('$', found);
     82   }
     83   return result;
     84 }
     85 
     86 /*
     87  * Converts the class name portion of a type descriptor to human-readable
     88  * "dotted" form. For example, "Ljava/lang/String;" becomes "String".
     89  */
     90 static std::string DescriptorClassToDot(const char* str) {
     91   std::string descriptor(str);
     92   // Reduce to just the class name prefix.
     93   size_t last_slash = descriptor.rfind('/');
     94   if (last_slash == std::string::npos) {
     95     last_slash = 0;
     96   }
     97   // Start past the '/' or 'L'.
     98   last_slash++;
     99 
    100   // Copy class name over, trimming trailing ';'.
    101   size_t size = descriptor.size() - 1 - last_slash;
    102   std::string result(descriptor.substr(last_slash, size));
    103 
    104   // Replace '$' with '.'.
    105   size_t dollar_sign = result.find('$');
    106   while (dollar_sign != std::string::npos) {
    107     result[dollar_sign] = '.';
    108     dollar_sign = result.find('$', dollar_sign);
    109   }
    110 
    111   return result;
    112 }
    113 
    114 /*
    115  * Returns string representing the boolean value.
    116  */
    117 static const char* StrBool(bool val) {
    118   return val ? "true" : "false";
    119 }
    120 
    121 /*
    122  * Returns a quoted string representing the boolean value.
    123  */
    124 static const char* QuotedBool(bool val) {
    125   return val ? "\"true\"" : "\"false\"";
    126 }
    127 
    128 /*
    129  * Returns a quoted string representing the access flags.
    130  */
    131 static const char* QuotedVisibility(uint32_t access_flags) {
    132   if (access_flags & kAccPublic) {
    133     return "\"public\"";
    134   } else if (access_flags & kAccProtected) {
    135     return "\"protected\"";
    136   } else if (access_flags & kAccPrivate) {
    137     return "\"private\"";
    138   } else {
    139     return "\"package\"";
    140   }
    141 }
    142 
    143 /*
    144  * Counts the number of '1' bits in a word.
    145  */
    146 static int CountOnes(uint32_t val) {
    147   val = val - ((val >> 1) & 0x55555555);
    148   val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
    149   return (((val + (val >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
    150 }
    151 
    152 /*
    153  * Creates a new string with human-readable access flags.
    154  *
    155  * In the base language the access_flags fields are type uint16_t; in Dalvik they're uint32_t.
    156  */
    157 static char* CreateAccessFlagStr(uint32_t flags, AccessFor for_what) {
    158   static const char* kAccessStrings[kAccessForMAX][kNumFlags] = {
    159     {
    160       "PUBLIC",                /* 0x00001 */
    161       "PRIVATE",               /* 0x00002 */
    162       "PROTECTED",             /* 0x00004 */
    163       "STATIC",                /* 0x00008 */
    164       "FINAL",                 /* 0x00010 */
    165       "?",                     /* 0x00020 */
    166       "?",                     /* 0x00040 */
    167       "?",                     /* 0x00080 */
    168       "?",                     /* 0x00100 */
    169       "INTERFACE",             /* 0x00200 */
    170       "ABSTRACT",              /* 0x00400 */
    171       "?",                     /* 0x00800 */
    172       "SYNTHETIC",             /* 0x01000 */
    173       "ANNOTATION",            /* 0x02000 */
    174       "ENUM",                  /* 0x04000 */
    175       "?",                     /* 0x08000 */
    176       "VERIFIED",              /* 0x10000 */
    177       "OPTIMIZED",             /* 0x20000 */
    178     }, {
    179       "PUBLIC",                /* 0x00001 */
    180       "PRIVATE",               /* 0x00002 */
    181       "PROTECTED",             /* 0x00004 */
    182       "STATIC",                /* 0x00008 */
    183       "FINAL",                 /* 0x00010 */
    184       "SYNCHRONIZED",          /* 0x00020 */
    185       "BRIDGE",                /* 0x00040 */
    186       "VARARGS",               /* 0x00080 */
    187       "NATIVE",                /* 0x00100 */
    188       "?",                     /* 0x00200 */
    189       "ABSTRACT",              /* 0x00400 */
    190       "STRICT",                /* 0x00800 */
    191       "SYNTHETIC",             /* 0x01000 */
    192       "?",                     /* 0x02000 */
    193       "?",                     /* 0x04000 */
    194       "MIRANDA",               /* 0x08000 */
    195       "CONSTRUCTOR",           /* 0x10000 */
    196       "DECLARED_SYNCHRONIZED", /* 0x20000 */
    197     }, {
    198       "PUBLIC",                /* 0x00001 */
    199       "PRIVATE",               /* 0x00002 */
    200       "PROTECTED",             /* 0x00004 */
    201       "STATIC",                /* 0x00008 */
    202       "FINAL",                 /* 0x00010 */
    203       "?",                     /* 0x00020 */
    204       "VOLATILE",              /* 0x00040 */
    205       "TRANSIENT",             /* 0x00080 */
    206       "?",                     /* 0x00100 */
    207       "?",                     /* 0x00200 */
    208       "?",                     /* 0x00400 */
    209       "?",                     /* 0x00800 */
    210       "SYNTHETIC",             /* 0x01000 */
    211       "?",                     /* 0x02000 */
    212       "ENUM",                  /* 0x04000 */
    213       "?",                     /* 0x08000 */
    214       "?",                     /* 0x10000 */
    215       "?",                     /* 0x20000 */
    216     },
    217   };
    218 
    219   // Allocate enough storage to hold the expected number of strings,
    220   // plus a space between each.  We over-allocate, using the longest
    221   // string above as the base metric.
    222   const int kLongest = 21;  // The strlen of longest string above.
    223   const int count = CountOnes(flags);
    224   char* str;
    225   char* cp;
    226   cp = str = reinterpret_cast<char*>(malloc(count * (kLongest + 1) + 1));
    227 
    228   for (int i = 0; i < kNumFlags; i++) {
    229     if (flags & 0x01) {
    230       const char* accessStr = kAccessStrings[for_what][i];
    231       const int len = strlen(accessStr);
    232       if (cp != str) {
    233         *cp++ = ' ';
    234       }
    235       memcpy(cp, accessStr, len);
    236       cp += len;
    237     }
    238     flags >>= 1;
    239   }  // for
    240 
    241   *cp = '\0';
    242   return str;
    243 }
    244 
    245 static std::string GetSignatureForProtoId(const dex_ir::ProtoId* proto) {
    246   if (proto == nullptr) {
    247     return "<no signature>";
    248   }
    249 
    250   std::string result("(");
    251   const dex_ir::TypeList* type_list = proto->Parameters();
    252   if (type_list != nullptr) {
    253     for (const dex_ir::TypeId* type_id : *type_list->GetTypeList()) {
    254       result += type_id->GetStringId()->Data();
    255     }
    256   }
    257   result += ")";
    258   result += proto->ReturnType()->GetStringId()->Data();
    259   return result;
    260 }
    261 
    262 /*
    263  * Copies character data from "data" to "out", converting non-ASCII values
    264  * to fprintf format chars or an ASCII filler ('.' or '?').
    265  *
    266  * The output buffer must be able to hold (2*len)+1 bytes.  The result is
    267  * NULL-terminated.
    268  */
    269 static void Asciify(char* out, const unsigned char* data, size_t len) {
    270   while (len--) {
    271     if (*data < 0x20) {
    272       // Could do more here, but we don't need them yet.
    273       switch (*data) {
    274         case '\0':
    275           *out++ = '\\';
    276           *out++ = '0';
    277           break;
    278         case '\n':
    279           *out++ = '\\';
    280           *out++ = 'n';
    281           break;
    282         default:
    283           *out++ = '.';
    284           break;
    285       }  // switch
    286     } else if (*data >= 0x80) {
    287       *out++ = '?';
    288     } else {
    289       *out++ = *data;
    290     }
    291     data++;
    292   }  // while
    293   *out = '\0';
    294 }
    295 
    296 /*
    297  * Dumps a string value with some escape characters.
    298  */
    299 static void DumpEscapedString(const char* p, FILE* out_file) {
    300   fputs("\"", out_file);
    301   for (; *p; p++) {
    302     switch (*p) {
    303       case '\\':
    304         fputs("\\\\", out_file);
    305         break;
    306       case '\"':
    307         fputs("\\\"", out_file);
    308         break;
    309       case '\t':
    310         fputs("\\t", out_file);
    311         break;
    312       case '\n':
    313         fputs("\\n", out_file);
    314         break;
    315       case '\r':
    316         fputs("\\r", out_file);
    317         break;
    318       default:
    319         putc(*p, out_file);
    320     }  // switch
    321   }  // for
    322   fputs("\"", out_file);
    323 }
    324 
    325 /*
    326  * Dumps a string as an XML attribute value.
    327  */
    328 static void DumpXmlAttribute(const char* p, FILE* out_file) {
    329   for (; *p; p++) {
    330     switch (*p) {
    331       case '&':
    332         fputs("&amp;", out_file);
    333         break;
    334       case '<':
    335         fputs("&lt;", out_file);
    336         break;
    337       case '>':
    338         fputs("&gt;", out_file);
    339         break;
    340       case '"':
    341         fputs("&quot;", out_file);
    342         break;
    343       case '\t':
    344         fputs("&#x9;", out_file);
    345         break;
    346       case '\n':
    347         fputs("&#xA;", out_file);
    348         break;
    349       case '\r':
    350         fputs("&#xD;", out_file);
    351         break;
    352       default:
    353         putc(*p, out_file);
    354     }  // switch
    355   }  // for
    356 }
    357 
    358 /*
    359  * Helper for dumpInstruction(), which builds the string
    360  * representation for the index in the given instruction.
    361  * Returns a pointer to a buffer of sufficient size.
    362  */
    363 static std::unique_ptr<char[]> IndexString(dex_ir::Header* header,
    364                                            const Instruction* dec_insn,
    365                                            size_t buf_size) {
    366   std::unique_ptr<char[]> buf(new char[buf_size]);
    367   // Determine index and width of the string.
    368   uint32_t index = 0;
    369   uint32_t secondary_index = DexFile::kDexNoIndex;
    370   uint32_t width = 4;
    371   switch (Instruction::FormatOf(dec_insn->Opcode())) {
    372     // SOME NOT SUPPORTED:
    373     // case Instruction::k20bc:
    374     case Instruction::k21c:
    375     case Instruction::k35c:
    376     // case Instruction::k35ms:
    377     case Instruction::k3rc:
    378     // case Instruction::k3rms:
    379     // case Instruction::k35mi:
    380     // case Instruction::k3rmi:
    381       index = dec_insn->VRegB();
    382       width = 4;
    383       break;
    384     case Instruction::k31c:
    385       index = dec_insn->VRegB();
    386       width = 8;
    387       break;
    388     case Instruction::k22c:
    389     // case Instruction::k22cs:
    390       index = dec_insn->VRegC();
    391       width = 4;
    392       break;
    393     case Instruction::k45cc:
    394     case Instruction::k4rcc:
    395       index = dec_insn->VRegB();
    396       secondary_index = dec_insn->VRegH();
    397       width = 4;
    398       break;
    399     default:
    400       break;
    401   }  // switch
    402 
    403   // Determine index type.
    404   size_t outSize = 0;
    405   switch (Instruction::IndexTypeOf(dec_insn->Opcode())) {
    406     case Instruction::kIndexUnknown:
    407       // This function should never get called for this type, but do
    408       // something sensible here, just to help with debugging.
    409       outSize = snprintf(buf.get(), buf_size, "<unknown-index>");
    410       break;
    411     case Instruction::kIndexNone:
    412       // This function should never get called for this type, but do
    413       // something sensible here, just to help with debugging.
    414       outSize = snprintf(buf.get(), buf_size, "<no-index>");
    415       break;
    416     case Instruction::kIndexTypeRef:
    417       if (index < header->GetCollections().TypeIdsSize()) {
    418         const char* tp = header->GetCollections().GetTypeId(index)->GetStringId()->Data();
    419         outSize = snprintf(buf.get(), buf_size, "%s // type@%0*x", tp, width, index);
    420       } else {
    421         outSize = snprintf(buf.get(), buf_size, "<type?> // type@%0*x", width, index);
    422       }
    423       break;
    424     case Instruction::kIndexStringRef:
    425       if (index < header->GetCollections().StringIdsSize()) {
    426         const char* st = header->GetCollections().GetStringId(index)->Data();
    427         outSize = snprintf(buf.get(), buf_size, "\"%s\" // string@%0*x", st, width, index);
    428       } else {
    429         outSize = snprintf(buf.get(), buf_size, "<string?> // string@%0*x", width, index);
    430       }
    431       break;
    432     case Instruction::kIndexMethodRef:
    433       if (index < header->GetCollections().MethodIdsSize()) {
    434         dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index);
    435         const char* name = method_id->Name()->Data();
    436         std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
    437         const char* back_descriptor = method_id->Class()->GetStringId()->Data();
    438         outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // method@%0*x",
    439                            back_descriptor, name, type_descriptor.c_str(), width, index);
    440       } else {
    441         outSize = snprintf(buf.get(), buf_size, "<method?> // method@%0*x", width, index);
    442       }
    443       break;
    444     case Instruction::kIndexFieldRef:
    445       if (index < header->GetCollections().FieldIdsSize()) {
    446         dex_ir::FieldId* field_id = header->GetCollections().GetFieldId(index);
    447         const char* name = field_id->Name()->Data();
    448         const char* type_descriptor = field_id->Type()->GetStringId()->Data();
    449         const char* back_descriptor = field_id->Class()->GetStringId()->Data();
    450         outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // field@%0*x",
    451                            back_descriptor, name, type_descriptor, width, index);
    452       } else {
    453         outSize = snprintf(buf.get(), buf_size, "<field?> // field@%0*x", width, index);
    454       }
    455       break;
    456     case Instruction::kIndexVtableOffset:
    457       outSize = snprintf(buf.get(), buf_size, "[%0*x] // vtable #%0*x",
    458                          width, index, width, index);
    459       break;
    460     case Instruction::kIndexFieldOffset:
    461       outSize = snprintf(buf.get(), buf_size, "[obj+%0*x]", width, index);
    462       break;
    463     case Instruction::kIndexMethodAndProtoRef: {
    464       std::string method("<method?>");
    465       std::string proto("<proto?>");
    466       if (index < header->GetCollections().MethodIdsSize()) {
    467         dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index);
    468         const char* name = method_id->Name()->Data();
    469         std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
    470         const char* back_descriptor = method_id->Class()->GetStringId()->Data();
    471         method = StringPrintf("%s.%s:%s", back_descriptor, name, type_descriptor.c_str());
    472       }
    473       if (secondary_index < header->GetCollections().ProtoIdsSize()) {
    474         dex_ir::ProtoId* proto_id = header->GetCollections().GetProtoId(secondary_index);
    475         proto = GetSignatureForProtoId(proto_id);
    476       }
    477       outSize = snprintf(buf.get(), buf_size, "%s, %s // method@%0*x, proto@%0*x",
    478                          method.c_str(), proto.c_str(), width, index, width, secondary_index);
    479     }
    480     break;
    481     // SOME NOT SUPPORTED:
    482     // case Instruction::kIndexVaries:
    483     // case Instruction::kIndexInlineMethod:
    484     default:
    485       outSize = snprintf(buf.get(), buf_size, "<?>");
    486       break;
    487   }  // switch
    488 
    489   // Determine success of string construction.
    490   if (outSize >= buf_size) {
    491     // The buffer wasn't big enough; retry with computed size. Note: snprintf()
    492     // doesn't count/ the '\0' as part of its returned size, so we add explicit
    493     // space for it here.
    494     return IndexString(header, dec_insn, outSize + 1);
    495   }
    496   return buf;
    497 }
    498 
    499 /*
    500  * Dumps encoded annotation.
    501  */
    502 void DexLayout::DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation) {
    503   fputs(annotation->GetType()->GetStringId()->Data(), out_file_);
    504   // Display all name=value pairs.
    505   for (auto& subannotation : *annotation->GetAnnotationElements()) {
    506     fputc(' ', out_file_);
    507     fputs(subannotation->GetName()->Data(), out_file_);
    508     fputc('=', out_file_);
    509     DumpEncodedValue(subannotation->GetValue());
    510   }
    511 }
    512 /*
    513  * Dumps encoded value.
    514  */
    515 void DexLayout::DumpEncodedValue(const dex_ir::EncodedValue* data) {
    516   switch (data->Type()) {
    517     case DexFile::kDexAnnotationByte:
    518       fprintf(out_file_, "%" PRId8, data->GetByte());
    519       break;
    520     case DexFile::kDexAnnotationShort:
    521       fprintf(out_file_, "%" PRId16, data->GetShort());
    522       break;
    523     case DexFile::kDexAnnotationChar:
    524       fprintf(out_file_, "%" PRIu16, data->GetChar());
    525       break;
    526     case DexFile::kDexAnnotationInt:
    527       fprintf(out_file_, "%" PRId32, data->GetInt());
    528       break;
    529     case DexFile::kDexAnnotationLong:
    530       fprintf(out_file_, "%" PRId64, data->GetLong());
    531       break;
    532     case DexFile::kDexAnnotationFloat: {
    533       fprintf(out_file_, "%g", data->GetFloat());
    534       break;
    535     }
    536     case DexFile::kDexAnnotationDouble: {
    537       fprintf(out_file_, "%g", data->GetDouble());
    538       break;
    539     }
    540     case DexFile::kDexAnnotationString: {
    541       dex_ir::StringId* string_id = data->GetStringId();
    542       if (options_.output_format_ == kOutputPlain) {
    543         DumpEscapedString(string_id->Data(), out_file_);
    544       } else {
    545         DumpXmlAttribute(string_id->Data(), out_file_);
    546       }
    547       break;
    548     }
    549     case DexFile::kDexAnnotationType: {
    550       dex_ir::TypeId* type_id = data->GetTypeId();
    551       fputs(type_id->GetStringId()->Data(), out_file_);
    552       break;
    553     }
    554     case DexFile::kDexAnnotationField:
    555     case DexFile::kDexAnnotationEnum: {
    556       dex_ir::FieldId* field_id = data->GetFieldId();
    557       fputs(field_id->Name()->Data(), out_file_);
    558       break;
    559     }
    560     case DexFile::kDexAnnotationMethod: {
    561       dex_ir::MethodId* method_id = data->GetMethodId();
    562       fputs(method_id->Name()->Data(), out_file_);
    563       break;
    564     }
    565     case DexFile::kDexAnnotationArray: {
    566       fputc('{', out_file_);
    567       // Display all elements.
    568       for (auto& value : *data->GetEncodedArray()->GetEncodedValues()) {
    569         fputc(' ', out_file_);
    570         DumpEncodedValue(value.get());
    571       }
    572       fputs(" }", out_file_);
    573       break;
    574     }
    575     case DexFile::kDexAnnotationAnnotation: {
    576       DumpEncodedAnnotation(data->GetEncodedAnnotation());
    577       break;
    578     }
    579     case DexFile::kDexAnnotationNull:
    580       fputs("null", out_file_);
    581       break;
    582     case DexFile::kDexAnnotationBoolean:
    583       fputs(StrBool(data->GetBoolean()), out_file_);
    584       break;
    585     default:
    586       fputs("????", out_file_);
    587       break;
    588   }  // switch
    589 }
    590 
    591 /*
    592  * Dumps the file header.
    593  */
    594 void DexLayout::DumpFileHeader() {
    595   char sanitized[8 * 2 + 1];
    596   dex_ir::Collections& collections = header_->GetCollections();
    597   fprintf(out_file_, "DEX file header:\n");
    598   Asciify(sanitized, header_->Magic(), 8);
    599   fprintf(out_file_, "magic               : '%s'\n", sanitized);
    600   fprintf(out_file_, "checksum            : %08x\n", header_->Checksum());
    601   fprintf(out_file_, "signature           : %02x%02x...%02x%02x\n",
    602           header_->Signature()[0], header_->Signature()[1],
    603           header_->Signature()[DexFile::kSha1DigestSize - 2],
    604           header_->Signature()[DexFile::kSha1DigestSize - 1]);
    605   fprintf(out_file_, "file_size           : %d\n", header_->FileSize());
    606   fprintf(out_file_, "header_size         : %d\n", header_->HeaderSize());
    607   fprintf(out_file_, "link_size           : %d\n", header_->LinkSize());
    608   fprintf(out_file_, "link_off            : %d (0x%06x)\n",
    609           header_->LinkOffset(), header_->LinkOffset());
    610   fprintf(out_file_, "string_ids_size     : %d\n", collections.StringIdsSize());
    611   fprintf(out_file_, "string_ids_off      : %d (0x%06x)\n",
    612           collections.StringIdsOffset(), collections.StringIdsOffset());
    613   fprintf(out_file_, "type_ids_size       : %d\n", collections.TypeIdsSize());
    614   fprintf(out_file_, "type_ids_off        : %d (0x%06x)\n",
    615           collections.TypeIdsOffset(), collections.TypeIdsOffset());
    616   fprintf(out_file_, "proto_ids_size      : %d\n", collections.ProtoIdsSize());
    617   fprintf(out_file_, "proto_ids_off       : %d (0x%06x)\n",
    618           collections.ProtoIdsOffset(), collections.ProtoIdsOffset());
    619   fprintf(out_file_, "field_ids_size      : %d\n", collections.FieldIdsSize());
    620   fprintf(out_file_, "field_ids_off       : %d (0x%06x)\n",
    621           collections.FieldIdsOffset(), collections.FieldIdsOffset());
    622   fprintf(out_file_, "method_ids_size     : %d\n", collections.MethodIdsSize());
    623   fprintf(out_file_, "method_ids_off      : %d (0x%06x)\n",
    624           collections.MethodIdsOffset(), collections.MethodIdsOffset());
    625   fprintf(out_file_, "class_defs_size     : %d\n", collections.ClassDefsSize());
    626   fprintf(out_file_, "class_defs_off      : %d (0x%06x)\n",
    627           collections.ClassDefsOffset(), collections.ClassDefsOffset());
    628   fprintf(out_file_, "data_size           : %d\n", header_->DataSize());
    629   fprintf(out_file_, "data_off            : %d (0x%06x)\n\n",
    630           header_->DataOffset(), header_->DataOffset());
    631 }
    632 
    633 /*
    634  * Dumps a class_def_item.
    635  */
    636 void DexLayout::DumpClassDef(int idx) {
    637   // General class information.
    638   dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx);
    639   fprintf(out_file_, "Class #%d header:\n", idx);
    640   fprintf(out_file_, "class_idx           : %d\n", class_def->ClassType()->GetIndex());
    641   fprintf(out_file_, "access_flags        : %d (0x%04x)\n",
    642           class_def->GetAccessFlags(), class_def->GetAccessFlags());
    643   uint32_t superclass_idx =  class_def->Superclass() == nullptr ?
    644       DexFile::kDexNoIndex16 : class_def->Superclass()->GetIndex();
    645   fprintf(out_file_, "superclass_idx      : %d\n", superclass_idx);
    646   fprintf(out_file_, "interfaces_off      : %d (0x%06x)\n",
    647           class_def->InterfacesOffset(), class_def->InterfacesOffset());
    648   uint32_t source_file_offset = 0xffffffffU;
    649   if (class_def->SourceFile() != nullptr) {
    650     source_file_offset = class_def->SourceFile()->GetIndex();
    651   }
    652   fprintf(out_file_, "source_file_idx     : %d\n", source_file_offset);
    653   uint32_t annotations_offset = 0;
    654   if (class_def->Annotations() != nullptr) {
    655     annotations_offset = class_def->Annotations()->GetOffset();
    656   }
    657   fprintf(out_file_, "annotations_off     : %d (0x%06x)\n",
    658           annotations_offset, annotations_offset);
    659   if (class_def->GetClassData() == nullptr) {
    660     fprintf(out_file_, "class_data_off      : %d (0x%06x)\n", 0, 0);
    661   } else {
    662     fprintf(out_file_, "class_data_off      : %d (0x%06x)\n",
    663             class_def->GetClassData()->GetOffset(), class_def->GetClassData()->GetOffset());
    664   }
    665 
    666   // Fields and methods.
    667   dex_ir::ClassData* class_data = class_def->GetClassData();
    668   if (class_data != nullptr && class_data->StaticFields() != nullptr) {
    669     fprintf(out_file_, "static_fields_size  : %zu\n", class_data->StaticFields()->size());
    670   } else {
    671     fprintf(out_file_, "static_fields_size  : 0\n");
    672   }
    673   if (class_data != nullptr && class_data->InstanceFields() != nullptr) {
    674     fprintf(out_file_, "instance_fields_size: %zu\n", class_data->InstanceFields()->size());
    675   } else {
    676     fprintf(out_file_, "instance_fields_size: 0\n");
    677   }
    678   if (class_data != nullptr && class_data->DirectMethods() != nullptr) {
    679     fprintf(out_file_, "direct_methods_size : %zu\n", class_data->DirectMethods()->size());
    680   } else {
    681     fprintf(out_file_, "direct_methods_size : 0\n");
    682   }
    683   if (class_data != nullptr && class_data->VirtualMethods() != nullptr) {
    684     fprintf(out_file_, "virtual_methods_size: %zu\n", class_data->VirtualMethods()->size());
    685   } else {
    686     fprintf(out_file_, "virtual_methods_size: 0\n");
    687   }
    688   fprintf(out_file_, "\n");
    689 }
    690 
    691 /**
    692  * Dumps an annotation set item.
    693  */
    694 void DexLayout::DumpAnnotationSetItem(dex_ir::AnnotationSetItem* set_item) {
    695   if (set_item == nullptr || set_item->GetItems()->size() == 0) {
    696     fputs("  empty-annotation-set\n", out_file_);
    697     return;
    698   }
    699   for (dex_ir::AnnotationItem* annotation : *set_item->GetItems()) {
    700     if (annotation == nullptr) {
    701       continue;
    702     }
    703     fputs("  ", out_file_);
    704     switch (annotation->GetVisibility()) {
    705       case DexFile::kDexVisibilityBuild:   fputs("VISIBILITY_BUILD ",   out_file_); break;
    706       case DexFile::kDexVisibilityRuntime: fputs("VISIBILITY_RUNTIME ", out_file_); break;
    707       case DexFile::kDexVisibilitySystem:  fputs("VISIBILITY_SYSTEM ",  out_file_); break;
    708       default:                             fputs("VISIBILITY_UNKNOWN ", out_file_); break;
    709     }  // switch
    710     DumpEncodedAnnotation(annotation->GetAnnotation());
    711     fputc('\n', out_file_);
    712   }
    713 }
    714 
    715 /*
    716  * Dumps class annotations.
    717  */
    718 void DexLayout::DumpClassAnnotations(int idx) {
    719   dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx);
    720   dex_ir::AnnotationsDirectoryItem* annotations_directory = class_def->Annotations();
    721   if (annotations_directory == nullptr) {
    722     return;  // none
    723   }
    724 
    725   fprintf(out_file_, "Class #%d annotations:\n", idx);
    726 
    727   dex_ir::AnnotationSetItem* class_set_item = annotations_directory->GetClassAnnotation();
    728   dex_ir::FieldAnnotationVector* fields = annotations_directory->GetFieldAnnotations();
    729   dex_ir::MethodAnnotationVector* methods = annotations_directory->GetMethodAnnotations();
    730   dex_ir::ParameterAnnotationVector* parameters = annotations_directory->GetParameterAnnotations();
    731 
    732   // Annotations on the class itself.
    733   if (class_set_item != nullptr) {
    734     fprintf(out_file_, "Annotations on class\n");
    735     DumpAnnotationSetItem(class_set_item);
    736   }
    737 
    738   // Annotations on fields.
    739   if (fields != nullptr) {
    740     for (auto& field : *fields) {
    741       const dex_ir::FieldId* field_id = field->GetFieldId();
    742       const uint32_t field_idx = field_id->GetIndex();
    743       const char* field_name = field_id->Name()->Data();
    744       fprintf(out_file_, "Annotations on field #%u '%s'\n", field_idx, field_name);
    745       DumpAnnotationSetItem(field->GetAnnotationSetItem());
    746     }
    747   }
    748 
    749   // Annotations on methods.
    750   if (methods != nullptr) {
    751     for (auto& method : *methods) {
    752       const dex_ir::MethodId* method_id = method->GetMethodId();
    753       const uint32_t method_idx = method_id->GetIndex();
    754       const char* method_name = method_id->Name()->Data();
    755       fprintf(out_file_, "Annotations on method #%u '%s'\n", method_idx, method_name);
    756       DumpAnnotationSetItem(method->GetAnnotationSetItem());
    757     }
    758   }
    759 
    760   // Annotations on method parameters.
    761   if (parameters != nullptr) {
    762     for (auto& parameter : *parameters) {
    763       const dex_ir::MethodId* method_id = parameter->GetMethodId();
    764       const uint32_t method_idx = method_id->GetIndex();
    765       const char* method_name = method_id->Name()->Data();
    766       fprintf(out_file_, "Annotations on method #%u '%s' parameters\n", method_idx, method_name);
    767       uint32_t j = 0;
    768       for (dex_ir::AnnotationSetItem* annotation : *parameter->GetAnnotations()->GetItems()) {
    769         fprintf(out_file_, "#%u\n", j);
    770         DumpAnnotationSetItem(annotation);
    771         ++j;
    772       }
    773     }
    774   }
    775 
    776   fputc('\n', out_file_);
    777 }
    778 
    779 /*
    780  * Dumps an interface that a class declares to implement.
    781  */
    782 void DexLayout::DumpInterface(const dex_ir::TypeId* type_item, int i) {
    783   const char* interface_name = type_item->GetStringId()->Data();
    784   if (options_.output_format_ == kOutputPlain) {
    785     fprintf(out_file_, "    #%d              : '%s'\n", i, interface_name);
    786   } else {
    787     std::string dot(DescriptorToDotWrapper(interface_name));
    788     fprintf(out_file_, "<implements name=\"%s\">\n</implements>\n", dot.c_str());
    789   }
    790 }
    791 
    792 /*
    793  * Dumps the catches table associated with the code.
    794  */
    795 void DexLayout::DumpCatches(const dex_ir::CodeItem* code) {
    796   const uint16_t tries_size = code->TriesSize();
    797 
    798   // No catch table.
    799   if (tries_size == 0) {
    800     fprintf(out_file_, "      catches       : (none)\n");
    801     return;
    802   }
    803 
    804   // Dump all table entries.
    805   fprintf(out_file_, "      catches       : %d\n", tries_size);
    806   std::vector<std::unique_ptr<const dex_ir::TryItem>>* tries = code->Tries();
    807   for (uint32_t i = 0; i < tries_size; i++) {
    808     const dex_ir::TryItem* try_item = (*tries)[i].get();
    809     const uint32_t start = try_item->StartAddr();
    810     const uint32_t end = start + try_item->InsnCount();
    811     fprintf(out_file_, "        0x%04x - 0x%04x\n", start, end);
    812     for (auto& handler : *try_item->GetHandlers()->GetHandlers()) {
    813       const dex_ir::TypeId* type_id = handler->GetTypeId();
    814       const char* descriptor = (type_id == nullptr) ? "<any>" : type_id->GetStringId()->Data();
    815       fprintf(out_file_, "          %s -> 0x%04x\n", descriptor, handler->GetAddress());
    816     }  // for
    817   }  // for
    818 }
    819 
    820 /*
    821  * Dumps all positions table entries associated with the code.
    822  */
    823 void DexLayout::DumpPositionInfo(const dex_ir::CodeItem* code) {
    824   dex_ir::DebugInfoItem* debug_info = code->DebugInfo();
    825   if (debug_info == nullptr) {
    826     return;
    827   }
    828   std::vector<std::unique_ptr<dex_ir::PositionInfo>>& positions = debug_info->GetPositionInfo();
    829   for (size_t i = 0; i < positions.size(); ++i) {
    830     fprintf(out_file_, "        0x%04x line=%d\n", positions[i]->address_, positions[i]->line_);
    831   }
    832 }
    833 
    834 /*
    835  * Dumps all locals table entries associated with the code.
    836  */
    837 void DexLayout::DumpLocalInfo(const dex_ir::CodeItem* code) {
    838   dex_ir::DebugInfoItem* debug_info = code->DebugInfo();
    839   if (debug_info == nullptr) {
    840     return;
    841   }
    842   std::vector<std::unique_ptr<dex_ir::LocalInfo>>& locals = debug_info->GetLocalInfo();
    843   for (size_t i = 0; i < locals.size(); ++i) {
    844     dex_ir::LocalInfo* entry = locals[i].get();
    845     fprintf(out_file_, "        0x%04x - 0x%04x reg=%d %s %s %s\n",
    846             entry->start_address_, entry->end_address_, entry->reg_,
    847             entry->name_.c_str(), entry->descriptor_.c_str(), entry->signature_.c_str());
    848   }
    849 }
    850 
    851 /*
    852  * Dumps a single instruction.
    853  */
    854 void DexLayout::DumpInstruction(const dex_ir::CodeItem* code,
    855                                 uint32_t code_offset,
    856                                 uint32_t insn_idx,
    857                                 uint32_t insn_width,
    858                                 const Instruction* dec_insn) {
    859   // Address of instruction (expressed as byte offset).
    860   fprintf(out_file_, "%06x:", code_offset + 0x10 + insn_idx * 2);
    861 
    862   // Dump (part of) raw bytes.
    863   const uint16_t* insns = code->Insns();
    864   for (uint32_t i = 0; i < 8; i++) {
    865     if (i < insn_width) {
    866       if (i == 7) {
    867         fprintf(out_file_, " ... ");
    868       } else {
    869         // Print 16-bit value in little-endian order.
    870         const uint8_t* bytePtr = (const uint8_t*) &insns[insn_idx + i];
    871         fprintf(out_file_, " %02x%02x", bytePtr[0], bytePtr[1]);
    872       }
    873     } else {
    874       fputs("     ", out_file_);
    875     }
    876   }  // for
    877 
    878   // Dump pseudo-instruction or opcode.
    879   if (dec_insn->Opcode() == Instruction::NOP) {
    880     const uint16_t instr = Get2LE((const uint8_t*) &insns[insn_idx]);
    881     if (instr == Instruction::kPackedSwitchSignature) {
    882       fprintf(out_file_, "|%04x: packed-switch-data (%d units)", insn_idx, insn_width);
    883     } else if (instr == Instruction::kSparseSwitchSignature) {
    884       fprintf(out_file_, "|%04x: sparse-switch-data (%d units)", insn_idx, insn_width);
    885     } else if (instr == Instruction::kArrayDataSignature) {
    886       fprintf(out_file_, "|%04x: array-data (%d units)", insn_idx, insn_width);
    887     } else {
    888       fprintf(out_file_, "|%04x: nop // spacer", insn_idx);
    889     }
    890   } else {
    891     fprintf(out_file_, "|%04x: %s", insn_idx, dec_insn->Name());
    892   }
    893 
    894   // Set up additional argument.
    895   std::unique_ptr<char[]> index_buf;
    896   if (Instruction::IndexTypeOf(dec_insn->Opcode()) != Instruction::kIndexNone) {
    897     index_buf = IndexString(header_, dec_insn, 200);
    898   }
    899 
    900   // Dump the instruction.
    901   //
    902   // NOTE: pDecInsn->DumpString(pDexFile) differs too much from original.
    903   //
    904   switch (Instruction::FormatOf(dec_insn->Opcode())) {
    905     case Instruction::k10x:        // op
    906       break;
    907     case Instruction::k12x:        // op vA, vB
    908       fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB());
    909       break;
    910     case Instruction::k11n:        // op vA, #+B
    911       fprintf(out_file_, " v%d, #int %d // #%x",
    912               dec_insn->VRegA(), (int32_t) dec_insn->VRegB(), (uint8_t)dec_insn->VRegB());
    913       break;
    914     case Instruction::k11x:        // op vAA
    915       fprintf(out_file_, " v%d", dec_insn->VRegA());
    916       break;
    917     case Instruction::k10t:        // op +AA
    918     case Instruction::k20t: {      // op +AAAA
    919       const int32_t targ = (int32_t) dec_insn->VRegA();
    920       fprintf(out_file_, " %04x // %c%04x",
    921               insn_idx + targ,
    922               (targ < 0) ? '-' : '+',
    923               (targ < 0) ? -targ : targ);
    924       break;
    925     }
    926     case Instruction::k22x:        // op vAA, vBBBB
    927       fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB());
    928       break;
    929     case Instruction::k21t: {     // op vAA, +BBBB
    930       const int32_t targ = (int32_t) dec_insn->VRegB();
    931       fprintf(out_file_, " v%d, %04x // %c%04x", dec_insn->VRegA(),
    932               insn_idx + targ,
    933               (targ < 0) ? '-' : '+',
    934               (targ < 0) ? -targ : targ);
    935       break;
    936     }
    937     case Instruction::k21s:        // op vAA, #+BBBB
    938       fprintf(out_file_, " v%d, #int %d // #%x",
    939               dec_insn->VRegA(), (int32_t) dec_insn->VRegB(), (uint16_t)dec_insn->VRegB());
    940       break;
    941     case Instruction::k21h:        // op vAA, #+BBBB0000[00000000]
    942       // The printed format varies a bit based on the actual opcode.
    943       if (dec_insn->Opcode() == Instruction::CONST_HIGH16) {
    944         const int32_t value = dec_insn->VRegB() << 16;
    945         fprintf(out_file_, " v%d, #int %d // #%x",
    946                 dec_insn->VRegA(), value, (uint16_t) dec_insn->VRegB());
    947       } else {
    948         const int64_t value = ((int64_t) dec_insn->VRegB()) << 48;
    949         fprintf(out_file_, " v%d, #long %" PRId64 " // #%x",
    950                 dec_insn->VRegA(), value, (uint16_t) dec_insn->VRegB());
    951       }
    952       break;
    953     case Instruction::k21c:        // op vAA, thing@BBBB
    954     case Instruction::k31c:        // op vAA, thing@BBBBBBBB
    955       fprintf(out_file_, " v%d, %s", dec_insn->VRegA(), index_buf.get());
    956       break;
    957     case Instruction::k23x:        // op vAA, vBB, vCC
    958       fprintf(out_file_, " v%d, v%d, v%d",
    959               dec_insn->VRegA(), dec_insn->VRegB(), dec_insn->VRegC());
    960       break;
    961     case Instruction::k22b:        // op vAA, vBB, #+CC
    962       fprintf(out_file_, " v%d, v%d, #int %d // #%02x",
    963               dec_insn->VRegA(), dec_insn->VRegB(),
    964               (int32_t) dec_insn->VRegC(), (uint8_t) dec_insn->VRegC());
    965       break;
    966     case Instruction::k22t: {      // op vA, vB, +CCCC
    967       const int32_t targ = (int32_t) dec_insn->VRegC();
    968       fprintf(out_file_, " v%d, v%d, %04x // %c%04x",
    969               dec_insn->VRegA(), dec_insn->VRegB(),
    970               insn_idx + targ,
    971               (targ < 0) ? '-' : '+',
    972               (targ < 0) ? -targ : targ);
    973       break;
    974     }
    975     case Instruction::k22s:        // op vA, vB, #+CCCC
    976       fprintf(out_file_, " v%d, v%d, #int %d // #%04x",
    977               dec_insn->VRegA(), dec_insn->VRegB(),
    978               (int32_t) dec_insn->VRegC(), (uint16_t) dec_insn->VRegC());
    979       break;
    980     case Instruction::k22c:        // op vA, vB, thing@CCCC
    981     // NOT SUPPORTED:
    982     // case Instruction::k22cs:    // [opt] op vA, vB, field offset CCCC
    983       fprintf(out_file_, " v%d, v%d, %s",
    984               dec_insn->VRegA(), dec_insn->VRegB(), index_buf.get());
    985       break;
    986     case Instruction::k30t:
    987       fprintf(out_file_, " #%08x", dec_insn->VRegA());
    988       break;
    989     case Instruction::k31i: {     // op vAA, #+BBBBBBBB
    990       // This is often, but not always, a float.
    991       union {
    992         float f;
    993         uint32_t i;
    994       } conv;
    995       conv.i = dec_insn->VRegB();
    996       fprintf(out_file_, " v%d, #float %g // #%08x",
    997               dec_insn->VRegA(), conv.f, dec_insn->VRegB());
    998       break;
    999     }
   1000     case Instruction::k31t:       // op vAA, offset +BBBBBBBB
   1001       fprintf(out_file_, " v%d, %08x // +%08x",
   1002               dec_insn->VRegA(), insn_idx + dec_insn->VRegB(), dec_insn->VRegB());
   1003       break;
   1004     case Instruction::k32x:        // op vAAAA, vBBBB
   1005       fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB());
   1006       break;
   1007     case Instruction::k35c:           // op {vC, vD, vE, vF, vG}, thing@BBBB
   1008     case Instruction::k45cc: {        // op {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH
   1009     // NOT SUPPORTED:
   1010     // case Instruction::k35ms:       // [opt] invoke-virtual+super
   1011     // case Instruction::k35mi:       // [opt] inline invoke
   1012       uint32_t arg[Instruction::kMaxVarArgRegs];
   1013       dec_insn->GetVarArgs(arg);
   1014       fputs(" {", out_file_);
   1015       for (int i = 0, n = dec_insn->VRegA(); i < n; i++) {
   1016         if (i == 0) {
   1017           fprintf(out_file_, "v%d", arg[i]);
   1018         } else {
   1019           fprintf(out_file_, ", v%d", arg[i]);
   1020         }
   1021       }  // for
   1022       fprintf(out_file_, "}, %s", index_buf.get());
   1023       break;
   1024     }
   1025     case Instruction::k3rc:           // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB
   1026     case Instruction::k4rcc:          // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB, proto@HHHH
   1027     // NOT SUPPORTED:
   1028     // case Instruction::k3rms:       // [opt] invoke-virtual+super/range
   1029     // case Instruction::k3rmi:       // [opt] execute-inline/range
   1030       {
   1031         // This doesn't match the "dx" output when some of the args are
   1032         // 64-bit values -- dx only shows the first register.
   1033         fputs(" {", out_file_);
   1034         for (int i = 0, n = dec_insn->VRegA(); i < n; i++) {
   1035           if (i == 0) {
   1036             fprintf(out_file_, "v%d", dec_insn->VRegC() + i);
   1037           } else {
   1038             fprintf(out_file_, ", v%d", dec_insn->VRegC() + i);
   1039           }
   1040         }  // for
   1041         fprintf(out_file_, "}, %s", index_buf.get());
   1042       }
   1043       break;
   1044     case Instruction::k51l: {      // op vAA, #+BBBBBBBBBBBBBBBB
   1045       // This is often, but not always, a double.
   1046       union {
   1047         double d;
   1048         uint64_t j;
   1049       } conv;
   1050       conv.j = dec_insn->WideVRegB();
   1051       fprintf(out_file_, " v%d, #double %g // #%016" PRIx64,
   1052               dec_insn->VRegA(), conv.d, dec_insn->WideVRegB());
   1053       break;
   1054     }
   1055     // NOT SUPPORTED:
   1056     // case Instruction::k00x:        // unknown op or breakpoint
   1057     //    break;
   1058     default:
   1059       fprintf(out_file_, " ???");
   1060       break;
   1061   }  // switch
   1062 
   1063   fputc('\n', out_file_);
   1064 }
   1065 
   1066 /*
   1067  * Dumps a bytecode disassembly.
   1068  */
   1069 void DexLayout::DumpBytecodes(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset) {
   1070   dex_ir::MethodId* method_id = header_->GetCollections().GetMethodId(idx);
   1071   const char* name = method_id->Name()->Data();
   1072   std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
   1073   const char* back_descriptor = method_id->Class()->GetStringId()->Data();
   1074 
   1075   // Generate header.
   1076   std::string dot(DescriptorToDotWrapper(back_descriptor));
   1077   fprintf(out_file_, "%06x:                                        |[%06x] %s.%s:%s\n",
   1078           code_offset, code_offset, dot.c_str(), name, type_descriptor.c_str());
   1079 
   1080   // Iterate over all instructions.
   1081   const uint16_t* insns = code->Insns();
   1082   for (uint32_t insn_idx = 0; insn_idx < code->InsnsSize();) {
   1083     const Instruction* instruction = Instruction::At(&insns[insn_idx]);
   1084     const uint32_t insn_width = instruction->SizeInCodeUnits();
   1085     if (insn_width == 0) {
   1086       fprintf(stderr, "GLITCH: zero-width instruction at idx=0x%04x\n", insn_idx);
   1087       break;
   1088     }
   1089     DumpInstruction(code, code_offset, insn_idx, insn_width, instruction);
   1090     insn_idx += insn_width;
   1091   }  // for
   1092 }
   1093 
   1094 /*
   1095  * Dumps code of a method.
   1096  */
   1097 void DexLayout::DumpCode(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset) {
   1098   fprintf(out_file_, "      registers     : %d\n", code->RegistersSize());
   1099   fprintf(out_file_, "      ins           : %d\n", code->InsSize());
   1100   fprintf(out_file_, "      outs          : %d\n", code->OutsSize());
   1101   fprintf(out_file_, "      insns size    : %d 16-bit code units\n",
   1102           code->InsnsSize());
   1103 
   1104   // Bytecode disassembly, if requested.
   1105   if (options_.disassemble_) {
   1106     DumpBytecodes(idx, code, code_offset);
   1107   }
   1108 
   1109   // Try-catch blocks.
   1110   DumpCatches(code);
   1111 
   1112   // Positions and locals table in the debug info.
   1113   fprintf(out_file_, "      positions     : \n");
   1114   DumpPositionInfo(code);
   1115   fprintf(out_file_, "      locals        : \n");
   1116   DumpLocalInfo(code);
   1117 }
   1118 
   1119 /*
   1120  * Dumps a method.
   1121  */
   1122 void DexLayout::DumpMethod(uint32_t idx, uint32_t flags, const dex_ir::CodeItem* code, int i) {
   1123   // Bail for anything private if export only requested.
   1124   if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) {
   1125     return;
   1126   }
   1127 
   1128   dex_ir::MethodId* method_id = header_->GetCollections().GetMethodId(idx);
   1129   const char* name = method_id->Name()->Data();
   1130   char* type_descriptor = strdup(GetSignatureForProtoId(method_id->Proto()).c_str());
   1131   const char* back_descriptor = method_id->Class()->GetStringId()->Data();
   1132   char* access_str = CreateAccessFlagStr(flags, kAccessForMethod);
   1133 
   1134   if (options_.output_format_ == kOutputPlain) {
   1135     fprintf(out_file_, "    #%d              : (in %s)\n", i, back_descriptor);
   1136     fprintf(out_file_, "      name          : '%s'\n", name);
   1137     fprintf(out_file_, "      type          : '%s'\n", type_descriptor);
   1138     fprintf(out_file_, "      access        : 0x%04x (%s)\n", flags, access_str);
   1139     if (code == nullptr) {
   1140       fprintf(out_file_, "      code          : (none)\n");
   1141     } else {
   1142       fprintf(out_file_, "      code          -\n");
   1143       DumpCode(idx, code, code->GetOffset());
   1144     }
   1145     if (options_.disassemble_) {
   1146       fputc('\n', out_file_);
   1147     }
   1148   } else if (options_.output_format_ == kOutputXml) {
   1149     const bool constructor = (name[0] == '<');
   1150 
   1151     // Method name and prototype.
   1152     if (constructor) {
   1153       std::string dot(DescriptorClassToDot(back_descriptor));
   1154       fprintf(out_file_, "<constructor name=\"%s\"\n", dot.c_str());
   1155       dot = DescriptorToDotWrapper(back_descriptor);
   1156       fprintf(out_file_, " type=\"%s\"\n", dot.c_str());
   1157     } else {
   1158       fprintf(out_file_, "<method name=\"%s\"\n", name);
   1159       const char* return_type = strrchr(type_descriptor, ')');
   1160       if (return_type == nullptr) {
   1161         fprintf(stderr, "bad method type descriptor '%s'\n", type_descriptor);
   1162         goto bail;
   1163       }
   1164       std::string dot(DescriptorToDotWrapper(return_type + 1));
   1165       fprintf(out_file_, " return=\"%s\"\n", dot.c_str());
   1166       fprintf(out_file_, " abstract=%s\n", QuotedBool((flags & kAccAbstract) != 0));
   1167       fprintf(out_file_, " native=%s\n", QuotedBool((flags & kAccNative) != 0));
   1168       fprintf(out_file_, " synchronized=%s\n", QuotedBool(
   1169           (flags & (kAccSynchronized | kAccDeclaredSynchronized)) != 0));
   1170     }
   1171 
   1172     // Additional method flags.
   1173     fprintf(out_file_, " static=%s\n", QuotedBool((flags & kAccStatic) != 0));
   1174     fprintf(out_file_, " final=%s\n", QuotedBool((flags & kAccFinal) != 0));
   1175     // The "deprecated=" not knowable w/o parsing annotations.
   1176     fprintf(out_file_, " visibility=%s\n>\n", QuotedVisibility(flags));
   1177 
   1178     // Parameters.
   1179     if (type_descriptor[0] != '(') {
   1180       fprintf(stderr, "ERROR: bad descriptor '%s'\n", type_descriptor);
   1181       goto bail;
   1182     }
   1183     char* tmp_buf = reinterpret_cast<char*>(malloc(strlen(type_descriptor) + 1));
   1184     const char* base = type_descriptor + 1;
   1185     int arg_num = 0;
   1186     while (*base != ')') {
   1187       char* cp = tmp_buf;
   1188       while (*base == '[') {
   1189         *cp++ = *base++;
   1190       }
   1191       if (*base == 'L') {
   1192         // Copy through ';'.
   1193         do {
   1194           *cp = *base++;
   1195         } while (*cp++ != ';');
   1196       } else {
   1197         // Primitive char, copy it.
   1198         if (strchr("ZBCSIFJD", *base) == nullptr) {
   1199           fprintf(stderr, "ERROR: bad method signature '%s'\n", base);
   1200           break;  // while
   1201         }
   1202         *cp++ = *base++;
   1203       }
   1204       // Null terminate and display.
   1205       *cp++ = '\0';
   1206       std::string dot(DescriptorToDotWrapper(tmp_buf));
   1207       fprintf(out_file_, "<parameter name=\"arg%d\" type=\"%s\">\n"
   1208                         "</parameter>\n", arg_num++, dot.c_str());
   1209     }  // while
   1210     free(tmp_buf);
   1211     if (constructor) {
   1212       fprintf(out_file_, "</constructor>\n");
   1213     } else {
   1214       fprintf(out_file_, "</method>\n");
   1215     }
   1216   }
   1217 
   1218  bail:
   1219   free(type_descriptor);
   1220   free(access_str);
   1221 }
   1222 
   1223 /*
   1224  * Dumps a static (class) field.
   1225  */
   1226 void DexLayout::DumpSField(uint32_t idx, uint32_t flags, int i, dex_ir::EncodedValue* init) {
   1227   // Bail for anything private if export only requested.
   1228   if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) {
   1229     return;
   1230   }
   1231 
   1232   dex_ir::FieldId* field_id = header_->GetCollections().GetFieldId(idx);
   1233   const char* name = field_id->Name()->Data();
   1234   const char* type_descriptor = field_id->Type()->GetStringId()->Data();
   1235   const char* back_descriptor = field_id->Class()->GetStringId()->Data();
   1236   char* access_str = CreateAccessFlagStr(flags, kAccessForField);
   1237 
   1238   if (options_.output_format_ == kOutputPlain) {
   1239     fprintf(out_file_, "    #%d              : (in %s)\n", i, back_descriptor);
   1240     fprintf(out_file_, "      name          : '%s'\n", name);
   1241     fprintf(out_file_, "      type          : '%s'\n", type_descriptor);
   1242     fprintf(out_file_, "      access        : 0x%04x (%s)\n", flags, access_str);
   1243     if (init != nullptr) {
   1244       fputs("      value         : ", out_file_);
   1245       DumpEncodedValue(init);
   1246       fputs("\n", out_file_);
   1247     }
   1248   } else if (options_.output_format_ == kOutputXml) {
   1249     fprintf(out_file_, "<field name=\"%s\"\n", name);
   1250     std::string dot(DescriptorToDotWrapper(type_descriptor));
   1251     fprintf(out_file_, " type=\"%s\"\n", dot.c_str());
   1252     fprintf(out_file_, " transient=%s\n", QuotedBool((flags & kAccTransient) != 0));
   1253     fprintf(out_file_, " volatile=%s\n", QuotedBool((flags & kAccVolatile) != 0));
   1254     // The "value=" is not knowable w/o parsing annotations.
   1255     fprintf(out_file_, " static=%s\n", QuotedBool((flags & kAccStatic) != 0));
   1256     fprintf(out_file_, " final=%s\n", QuotedBool((flags & kAccFinal) != 0));
   1257     // The "deprecated=" is not knowable w/o parsing annotations.
   1258     fprintf(out_file_, " visibility=%s\n", QuotedVisibility(flags));
   1259     if (init != nullptr) {
   1260       fputs(" value=\"", out_file_);
   1261       DumpEncodedValue(init);
   1262       fputs("\"\n", out_file_);
   1263     }
   1264     fputs(">\n</field>\n", out_file_);
   1265   }
   1266 
   1267   free(access_str);
   1268 }
   1269 
   1270 /*
   1271  * Dumps an instance field.
   1272  */
   1273 void DexLayout::DumpIField(uint32_t idx, uint32_t flags, int i) {
   1274   DumpSField(idx, flags, i, nullptr);
   1275 }
   1276 
   1277 /*
   1278  * Dumps the class.
   1279  *
   1280  * Note "idx" is a DexClassDef index, not a DexTypeId index.
   1281  *
   1282  * If "*last_package" is nullptr or does not match the current class' package,
   1283  * the value will be replaced with a newly-allocated string.
   1284  */
   1285 void DexLayout::DumpClass(int idx, char** last_package) {
   1286   dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx);
   1287   // Omitting non-public class.
   1288   if (options_.exports_only_ && (class_def->GetAccessFlags() & kAccPublic) == 0) {
   1289     return;
   1290   }
   1291 
   1292   if (options_.show_section_headers_) {
   1293     DumpClassDef(idx);
   1294   }
   1295 
   1296   if (options_.show_annotations_) {
   1297     DumpClassAnnotations(idx);
   1298   }
   1299 
   1300   // For the XML output, show the package name.  Ideally we'd gather
   1301   // up the classes, sort them, and dump them alphabetically so the
   1302   // package name wouldn't jump around, but that's not a great plan
   1303   // for something that needs to run on the device.
   1304   const char* class_descriptor =
   1305       header_->GetCollections().GetClassDef(idx)->ClassType()->GetStringId()->Data();
   1306   if (!(class_descriptor[0] == 'L' &&
   1307         class_descriptor[strlen(class_descriptor)-1] == ';')) {
   1308     // Arrays and primitives should not be defined explicitly. Keep going?
   1309     fprintf(stderr, "Malformed class name '%s'\n", class_descriptor);
   1310   } else if (options_.output_format_ == kOutputXml) {
   1311     char* mangle = strdup(class_descriptor + 1);
   1312     mangle[strlen(mangle)-1] = '\0';
   1313 
   1314     // Reduce to just the package name.
   1315     char* last_slash = strrchr(mangle, '/');
   1316     if (last_slash != nullptr) {
   1317       *last_slash = '\0';
   1318     } else {
   1319       *mangle = '\0';
   1320     }
   1321 
   1322     for (char* cp = mangle; *cp != '\0'; cp++) {
   1323       if (*cp == '/') {
   1324         *cp = '.';
   1325       }
   1326     }  // for
   1327 
   1328     if (*last_package == nullptr || strcmp(mangle, *last_package) != 0) {
   1329       // Start of a new package.
   1330       if (*last_package != nullptr) {
   1331         fprintf(out_file_, "</package>\n");
   1332       }
   1333       fprintf(out_file_, "<package name=\"%s\"\n>\n", mangle);
   1334       free(*last_package);
   1335       *last_package = mangle;
   1336     } else {
   1337       free(mangle);
   1338     }
   1339   }
   1340 
   1341   // General class information.
   1342   char* access_str = CreateAccessFlagStr(class_def->GetAccessFlags(), kAccessForClass);
   1343   const char* superclass_descriptor = nullptr;
   1344   if (class_def->Superclass() != nullptr) {
   1345     superclass_descriptor = class_def->Superclass()->GetStringId()->Data();
   1346   }
   1347   if (options_.output_format_ == kOutputPlain) {
   1348     fprintf(out_file_, "Class #%d            -\n", idx);
   1349     fprintf(out_file_, "  Class descriptor  : '%s'\n", class_descriptor);
   1350     fprintf(out_file_, "  Access flags      : 0x%04x (%s)\n",
   1351             class_def->GetAccessFlags(), access_str);
   1352     if (superclass_descriptor != nullptr) {
   1353       fprintf(out_file_, "  Superclass        : '%s'\n", superclass_descriptor);
   1354     }
   1355     fprintf(out_file_, "  Interfaces        -\n");
   1356   } else {
   1357     std::string dot(DescriptorClassToDot(class_descriptor));
   1358     fprintf(out_file_, "<class name=\"%s\"\n", dot.c_str());
   1359     if (superclass_descriptor != nullptr) {
   1360       dot = DescriptorToDotWrapper(superclass_descriptor);
   1361       fprintf(out_file_, " extends=\"%s\"\n", dot.c_str());
   1362     }
   1363     fprintf(out_file_, " interface=%s\n",
   1364             QuotedBool((class_def->GetAccessFlags() & kAccInterface) != 0));
   1365     fprintf(out_file_, " abstract=%s\n",
   1366             QuotedBool((class_def->GetAccessFlags() & kAccAbstract) != 0));
   1367     fprintf(out_file_, " static=%s\n", QuotedBool((class_def->GetAccessFlags() & kAccStatic) != 0));
   1368     fprintf(out_file_, " final=%s\n", QuotedBool((class_def->GetAccessFlags() & kAccFinal) != 0));
   1369     // The "deprecated=" not knowable w/o parsing annotations.
   1370     fprintf(out_file_, " visibility=%s\n", QuotedVisibility(class_def->GetAccessFlags()));
   1371     fprintf(out_file_, ">\n");
   1372   }
   1373 
   1374   // Interfaces.
   1375   const dex_ir::TypeList* interfaces = class_def->Interfaces();
   1376   if (interfaces != nullptr) {
   1377     const dex_ir::TypeIdVector* interfaces_vector = interfaces->GetTypeList();
   1378     for (uint32_t i = 0; i < interfaces_vector->size(); i++) {
   1379       DumpInterface((*interfaces_vector)[i], i);
   1380     }  // for
   1381   }
   1382 
   1383   // Fields and methods.
   1384   dex_ir::ClassData* class_data = class_def->GetClassData();
   1385   // Prepare data for static fields.
   1386   dex_ir::EncodedArrayItem* static_values = class_def->StaticValues();
   1387   dex_ir::EncodedValueVector* encoded_values =
   1388       static_values == nullptr ? nullptr : static_values->GetEncodedValues();
   1389   const uint32_t encoded_values_size = (encoded_values == nullptr) ? 0 : encoded_values->size();
   1390 
   1391   // Static fields.
   1392   if (options_.output_format_ == kOutputPlain) {
   1393     fprintf(out_file_, "  Static fields     -\n");
   1394   }
   1395   if (class_data != nullptr) {
   1396     dex_ir::FieldItemVector* static_fields = class_data->StaticFields();
   1397     if (static_fields != nullptr) {
   1398       for (uint32_t i = 0; i < static_fields->size(); i++) {
   1399         DumpSField((*static_fields)[i]->GetFieldId()->GetIndex(),
   1400                    (*static_fields)[i]->GetAccessFlags(),
   1401                    i,
   1402                    i < encoded_values_size ? (*encoded_values)[i].get() : nullptr);
   1403       }  // for
   1404     }
   1405   }
   1406 
   1407   // Instance fields.
   1408   if (options_.output_format_ == kOutputPlain) {
   1409     fprintf(out_file_, "  Instance fields   -\n");
   1410   }
   1411   if (class_data != nullptr) {
   1412     dex_ir::FieldItemVector* instance_fields = class_data->InstanceFields();
   1413     if (instance_fields != nullptr) {
   1414       for (uint32_t i = 0; i < instance_fields->size(); i++) {
   1415         DumpIField((*instance_fields)[i]->GetFieldId()->GetIndex(),
   1416                    (*instance_fields)[i]->GetAccessFlags(),
   1417                    i);
   1418       }  // for
   1419     }
   1420   }
   1421 
   1422   // Direct methods.
   1423   if (options_.output_format_ == kOutputPlain) {
   1424     fprintf(out_file_, "  Direct methods    -\n");
   1425   }
   1426   if (class_data != nullptr) {
   1427     dex_ir::MethodItemVector* direct_methods = class_data->DirectMethods();
   1428     if (direct_methods != nullptr) {
   1429       for (uint32_t i = 0; i < direct_methods->size(); i++) {
   1430         DumpMethod((*direct_methods)[i]->GetMethodId()->GetIndex(),
   1431                    (*direct_methods)[i]->GetAccessFlags(),
   1432                    (*direct_methods)[i]->GetCodeItem(),
   1433                  i);
   1434       }  // for
   1435     }
   1436   }
   1437 
   1438   // Virtual methods.
   1439   if (options_.output_format_ == kOutputPlain) {
   1440     fprintf(out_file_, "  Virtual methods   -\n");
   1441   }
   1442   if (class_data != nullptr) {
   1443     dex_ir::MethodItemVector* virtual_methods = class_data->VirtualMethods();
   1444     if (virtual_methods != nullptr) {
   1445       for (uint32_t i = 0; i < virtual_methods->size(); i++) {
   1446         DumpMethod((*virtual_methods)[i]->GetMethodId()->GetIndex(),
   1447                    (*virtual_methods)[i]->GetAccessFlags(),
   1448                    (*virtual_methods)[i]->GetCodeItem(),
   1449                    i);
   1450       }  // for
   1451     }
   1452   }
   1453 
   1454   // End of class.
   1455   if (options_.output_format_ == kOutputPlain) {
   1456     const char* file_name = "unknown";
   1457     if (class_def->SourceFile() != nullptr) {
   1458       file_name = class_def->SourceFile()->Data();
   1459     }
   1460     const dex_ir::StringId* source_file = class_def->SourceFile();
   1461     fprintf(out_file_, "  source_file_idx   : %d (%s)\n\n",
   1462             source_file == nullptr ? 0xffffffffU : source_file->GetIndex(), file_name);
   1463   } else if (options_.output_format_ == kOutputXml) {
   1464     fprintf(out_file_, "</class>\n");
   1465   }
   1466 
   1467   free(access_str);
   1468 }
   1469 
   1470 void DexLayout::DumpDexFile() {
   1471   // Headers.
   1472   if (options_.show_file_headers_) {
   1473     DumpFileHeader();
   1474   }
   1475 
   1476   // Open XML context.
   1477   if (options_.output_format_ == kOutputXml) {
   1478     fprintf(out_file_, "<api>\n");
   1479   }
   1480 
   1481   // Iterate over all classes.
   1482   char* package = nullptr;
   1483   const uint32_t class_defs_size = header_->GetCollections().ClassDefsSize();
   1484   for (uint32_t i = 0; i < class_defs_size; i++) {
   1485     DumpClass(i, &package);
   1486   }  // for
   1487 
   1488   // Free the last package allocated.
   1489   if (package != nullptr) {
   1490     fprintf(out_file_, "</package>\n");
   1491     free(package);
   1492   }
   1493 
   1494   // Close XML context.
   1495   if (options_.output_format_ == kOutputXml) {
   1496     fprintf(out_file_, "</api>\n");
   1497   }
   1498 }
   1499 
   1500 std::vector<dex_ir::ClassData*> DexLayout::LayoutClassDefsAndClassData(const DexFile* dex_file) {
   1501   std::vector<dex_ir::ClassDef*> new_class_def_order;
   1502   for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
   1503     dex::TypeIndex type_idx(class_def->ClassType()->GetIndex());
   1504     if (info_->ContainsClass(*dex_file, type_idx)) {
   1505       new_class_def_order.push_back(class_def.get());
   1506     }
   1507   }
   1508   for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
   1509     dex::TypeIndex type_idx(class_def->ClassType()->GetIndex());
   1510     if (!info_->ContainsClass(*dex_file, type_idx)) {
   1511       new_class_def_order.push_back(class_def.get());
   1512     }
   1513   }
   1514   uint32_t class_defs_offset = header_->GetCollections().ClassDefsOffset();
   1515   uint32_t class_data_offset = header_->GetCollections().ClassDatasOffset();
   1516   std::unordered_set<dex_ir::ClassData*> visited_class_data;
   1517   std::vector<dex_ir::ClassData*> new_class_data_order;
   1518   for (uint32_t i = 0; i < new_class_def_order.size(); ++i) {
   1519     dex_ir::ClassDef* class_def = new_class_def_order[i];
   1520     class_def->SetIndex(i);
   1521     class_def->SetOffset(class_defs_offset);
   1522     class_defs_offset += dex_ir::ClassDef::ItemSize();
   1523     dex_ir::ClassData* class_data = class_def->GetClassData();
   1524     if (class_data != nullptr && visited_class_data.find(class_data) == visited_class_data.end()) {
   1525       class_data->SetOffset(class_data_offset);
   1526       class_data_offset += class_data->GetSize();
   1527       visited_class_data.insert(class_data);
   1528       new_class_data_order.push_back(class_data);
   1529     }
   1530   }
   1531   return new_class_data_order;
   1532 }
   1533 
   1534 void DexLayout::LayoutStringData(const DexFile* dex_file) {
   1535   const size_t num_strings = header_->GetCollections().StringIds().size();
   1536   std::vector<bool> is_shorty(num_strings, false);
   1537   std::vector<bool> from_hot_method(num_strings, false);
   1538   for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
   1539     // A name of a profile class is probably going to get looked up by ClassTable::Lookup, mark it
   1540     // as hot. Add its super class and interfaces as well, which can be used during initialization.
   1541     const bool is_profile_class =
   1542         info_->ContainsClass(*dex_file, dex::TypeIndex(class_def->ClassType()->GetIndex()));
   1543     if (is_profile_class) {
   1544       from_hot_method[class_def->ClassType()->GetStringId()->GetIndex()] = true;
   1545       const dex_ir::TypeId* superclass = class_def->Superclass();
   1546       if (superclass != nullptr) {
   1547         from_hot_method[superclass->GetStringId()->GetIndex()] = true;
   1548       }
   1549       const dex_ir::TypeList* interfaces = class_def->Interfaces();
   1550       if (interfaces != nullptr) {
   1551         for (const dex_ir::TypeId* interface_type : *interfaces->GetTypeList()) {
   1552           from_hot_method[interface_type->GetStringId()->GetIndex()] = true;
   1553         }
   1554       }
   1555     }
   1556     dex_ir::ClassData* data = class_def->GetClassData();
   1557     if (data == nullptr) {
   1558       continue;
   1559     }
   1560     for (size_t i = 0; i < 2; ++i) {
   1561       for (auto& method : *(i == 0 ? data->DirectMethods() : data->VirtualMethods())) {
   1562         const dex_ir::MethodId* method_id = method->GetMethodId();
   1563         dex_ir::CodeItem* code_item = method->GetCodeItem();
   1564         if (code_item == nullptr) {
   1565           continue;
   1566         }
   1567         const bool is_clinit = is_profile_class &&
   1568             (method->GetAccessFlags() & kAccConstructor) != 0 &&
   1569             (method->GetAccessFlags() & kAccStatic) != 0;
   1570         const bool method_executed = is_clinit ||
   1571             info_->GetMethodHotness(MethodReference(dex_file, method_id->GetIndex())).IsInProfile();
   1572         if (!method_executed) {
   1573           continue;
   1574         }
   1575         is_shorty[method_id->Proto()->Shorty()->GetIndex()] = true;
   1576         dex_ir::CodeFixups* fixups = code_item->GetCodeFixups();
   1577         if (fixups == nullptr) {
   1578           continue;
   1579         }
   1580         // Add const-strings.
   1581         for (dex_ir::StringId* id : *fixups->StringIds()) {
   1582           from_hot_method[id->GetIndex()] = true;
   1583         }
   1584         // Add field classes, names, and types.
   1585         for (dex_ir::FieldId* id : *fixups->FieldIds()) {
   1586           // TODO: Only visit field ids from static getters and setters.
   1587           from_hot_method[id->Class()->GetStringId()->GetIndex()] = true;
   1588           from_hot_method[id->Name()->GetIndex()] = true;
   1589           from_hot_method[id->Type()->GetStringId()->GetIndex()] = true;
   1590         }
   1591         // For clinits, add referenced method classes, names, and protos.
   1592         if (is_clinit) {
   1593           for (dex_ir::MethodId* id : *fixups->MethodIds()) {
   1594             from_hot_method[id->Class()->GetStringId()->GetIndex()] = true;
   1595             from_hot_method[id->Name()->GetIndex()] = true;
   1596             is_shorty[id->Proto()->Shorty()->GetIndex()] = true;
   1597           }
   1598         }
   1599       }
   1600     }
   1601   }
   1602   // Sort string data by specified order.
   1603   std::vector<dex_ir::StringId*> string_ids;
   1604   size_t min_offset = std::numeric_limits<size_t>::max();
   1605   size_t max_offset = 0;
   1606   size_t hot_bytes = 0;
   1607   for (auto& string_id : header_->GetCollections().StringIds()) {
   1608     string_ids.push_back(string_id.get());
   1609     const size_t cur_offset = string_id->DataItem()->GetOffset();
   1610     CHECK_NE(cur_offset, 0u);
   1611     min_offset = std::min(min_offset, cur_offset);
   1612     dex_ir::StringData* data = string_id->DataItem();
   1613     const size_t element_size = data->GetSize() + 1;  // Add one extra for null.
   1614     size_t end_offset = cur_offset + element_size;
   1615     if (is_shorty[string_id->GetIndex()] || from_hot_method[string_id->GetIndex()]) {
   1616       hot_bytes += element_size;
   1617     }
   1618     max_offset = std::max(max_offset, end_offset);
   1619   }
   1620   VLOG(compiler) << "Hot string data bytes " << hot_bytes << "/" << max_offset - min_offset;
   1621   std::sort(string_ids.begin(),
   1622             string_ids.end(),
   1623             [&is_shorty, &from_hot_method](const dex_ir::StringId* a,
   1624                                            const dex_ir::StringId* b) {
   1625     const bool a_is_hot = from_hot_method[a->GetIndex()];
   1626     const bool b_is_hot = from_hot_method[b->GetIndex()];
   1627     if (a_is_hot != b_is_hot) {
   1628       return a_is_hot < b_is_hot;
   1629     }
   1630     // After hot methods are partitioned, subpartition shorties.
   1631     const bool a_is_shorty = is_shorty[a->GetIndex()];
   1632     const bool b_is_shorty = is_shorty[b->GetIndex()];
   1633     if (a_is_shorty != b_is_shorty) {
   1634       return a_is_shorty < b_is_shorty;
   1635     }
   1636     // Preserve order.
   1637     return a->DataItem()->GetOffset() < b->DataItem()->GetOffset();
   1638   });
   1639   // Now we know what order we want the string data, reorder the offsets.
   1640   size_t offset = min_offset;
   1641   for (dex_ir::StringId* string_id : string_ids) {
   1642     dex_ir::StringData* data = string_id->DataItem();
   1643     data->SetOffset(offset);
   1644     offset += data->GetSize() + 1;  // Add one extra for null.
   1645   }
   1646   if (offset > max_offset) {
   1647     const uint32_t diff = offset - max_offset;
   1648     // If we expanded the string data section, we need to update the offsets or else we will
   1649     // corrupt the next section when writing out.
   1650     FixupSections(header_->GetCollections().StringDatasOffset(), diff);
   1651     // Update file size.
   1652     header_->SetFileSize(header_->FileSize() + diff);
   1653   }
   1654 }
   1655 
   1656 // Orders code items according to specified class data ordering.
   1657 // NOTE: If the section following the code items is byte aligned, the last code item is left in
   1658 // place to preserve alignment. Layout needs an overhaul to handle movement of other sections.
   1659 int32_t DexLayout::LayoutCodeItems(const DexFile* dex_file,
   1660                                    std::vector<dex_ir::ClassData*> new_class_data_order) {
   1661   // Do not move code items if class data section precedes code item section.
   1662   // ULEB encoding is variable length, causing problems determining the offset of the code items.
   1663   // TODO: We should swap the order of these sections in the future to avoid this issue.
   1664   uint32_t class_data_offset = header_->GetCollections().ClassDatasOffset();
   1665   uint32_t code_item_offset = header_->GetCollections().CodeItemsOffset();
   1666   if (class_data_offset < code_item_offset) {
   1667     return 0;
   1668   }
   1669 
   1670   // Find the last code item so we can leave it in place if the next section is not 4 byte aligned.
   1671   dex_ir::CodeItem* last_code_item = nullptr;
   1672   std::unordered_set<dex_ir::CodeItem*> visited_code_items;
   1673   bool is_code_item_aligned = IsNextSectionCodeItemAligned(code_item_offset);
   1674   if (!is_code_item_aligned) {
   1675     for (auto& code_item_pair : header_->GetCollections().CodeItems()) {
   1676       std::unique_ptr<dex_ir::CodeItem>& code_item = code_item_pair.second;
   1677       if (last_code_item == nullptr
   1678           || last_code_item->GetOffset() < code_item->GetOffset()) {
   1679         last_code_item = code_item.get();
   1680       }
   1681     }
   1682   }
   1683 
   1684   static constexpr InvokeType invoke_types[] = {
   1685     kDirect,
   1686     kVirtual
   1687   };
   1688 
   1689   const size_t num_layout_types = static_cast<size_t>(LayoutType::kLayoutTypeCount);
   1690   std::unordered_set<dex_ir::CodeItem*> code_items[num_layout_types];
   1691   for (InvokeType invoke_type : invoke_types) {
   1692     for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
   1693       const bool is_profile_class =
   1694           info_->ContainsClass(*dex_file, dex::TypeIndex(class_def->ClassType()->GetIndex()));
   1695 
   1696       // Skip classes that are not defined in this dex file.
   1697       dex_ir::ClassData* class_data = class_def->GetClassData();
   1698       if (class_data == nullptr) {
   1699         continue;
   1700       }
   1701       for (auto& method : *(invoke_type == InvokeType::kDirect
   1702                                 ? class_data->DirectMethods()
   1703                                 : class_data->VirtualMethods())) {
   1704         const dex_ir::MethodId *method_id = method->GetMethodId();
   1705         dex_ir::CodeItem *code_item = method->GetCodeItem();
   1706         if (code_item == last_code_item || code_item == nullptr) {
   1707           continue;
   1708         }
   1709         // Separate executed methods (clinits and profiled methods) from unexecuted methods.
   1710         const bool is_clinit = (method->GetAccessFlags() & kAccConstructor) != 0 &&
   1711             (method->GetAccessFlags() & kAccStatic) != 0;
   1712         const bool is_startup_clinit = is_profile_class && is_clinit;
   1713         using Hotness = ProfileCompilationInfo::MethodHotness;
   1714         Hotness hotness = info_->GetMethodHotness(MethodReference(dex_file, method_id->GetIndex()));
   1715         LayoutType state = LayoutType::kLayoutTypeUnused;
   1716         if (hotness.IsHot()) {
   1717           // Hot code is compiled, maybe one day it won't be accessed. So lay it out together for
   1718           // now.
   1719           state = LayoutType::kLayoutTypeHot;
   1720         } else if (is_startup_clinit || hotness.GetFlags() == Hotness::kFlagStartup) {
   1721           // Startup clinit or a method that only has the startup flag.
   1722           state = LayoutType::kLayoutTypeStartupOnly;
   1723         } else if (is_clinit) {
   1724           state = LayoutType::kLayoutTypeUsedOnce;
   1725         } else if (hotness.IsInProfile()) {
   1726           state = LayoutType::kLayoutTypeSometimesUsed;
   1727         }
   1728         code_items[static_cast<size_t>(state)].insert(code_item);
   1729       }
   1730     }
   1731   }
   1732 
   1733   // Total_diff includes diffs generated by clinits, executed, and non-executed methods.
   1734   int32_t total_diff = 0;
   1735   // The relative placement has no effect on correctness; it is used to ensure
   1736   // the layout is deterministic
   1737   for (size_t index = 0; index < num_layout_types; ++index) {
   1738     const std::unordered_set<dex_ir::CodeItem*>& code_items_set = code_items[index];
   1739     // diff is reset for each class of code items.
   1740     int32_t diff = 0;
   1741     const uint32_t start_offset = code_item_offset;
   1742     for (dex_ir::ClassData* data : new_class_data_order) {
   1743       data->SetOffset(data->GetOffset() + diff);
   1744       for (InvokeType invoke_type : invoke_types) {
   1745         for (auto &method : *(invoke_type == InvokeType::kDirect
   1746                                   ? data->DirectMethods()
   1747                                   : data->VirtualMethods())) {
   1748           dex_ir::CodeItem* code_item = method->GetCodeItem();
   1749           if (code_item != nullptr &&
   1750               code_items_set.find(code_item) != code_items_set.end()) {
   1751             diff += UnsignedLeb128Size(code_item_offset)
   1752                 - UnsignedLeb128Size(code_item->GetOffset());
   1753             code_item->SetOffset(code_item_offset);
   1754             code_item_offset +=
   1755                 RoundUp(code_item->GetSize(), kDexCodeItemAlignment);
   1756           }
   1757         }
   1758       }
   1759     }
   1760     DexLayoutSection& code_section = dex_sections_.sections_[static_cast<size_t>(
   1761         DexLayoutSections::SectionType::kSectionTypeCode)];
   1762     code_section.parts_[index].offset_ = start_offset;
   1763     code_section.parts_[index].size_ = code_item_offset - start_offset;
   1764     for (size_t i = 0; i < num_layout_types; ++i) {
   1765       VLOG(dex) << "Code item layout bucket " << i << " count=" << code_items[i].size()
   1766                 << " bytes=" << code_section.parts_[i].size_;
   1767     }
   1768     total_diff += diff;
   1769   }
   1770   // Adjust diff to be 4-byte aligned.
   1771   return RoundUp(total_diff, kDexCodeItemAlignment);
   1772 }
   1773 
   1774 bool DexLayout::IsNextSectionCodeItemAligned(uint32_t offset) {
   1775   dex_ir::Collections& collections = header_->GetCollections();
   1776   std::set<uint32_t> section_offsets;
   1777   section_offsets.insert(collections.MapListOffset());
   1778   section_offsets.insert(collections.TypeListsOffset());
   1779   section_offsets.insert(collections.AnnotationSetRefListsOffset());
   1780   section_offsets.insert(collections.AnnotationSetItemsOffset());
   1781   section_offsets.insert(collections.ClassDatasOffset());
   1782   section_offsets.insert(collections.CodeItemsOffset());
   1783   section_offsets.insert(collections.StringDatasOffset());
   1784   section_offsets.insert(collections.DebugInfoItemsOffset());
   1785   section_offsets.insert(collections.AnnotationItemsOffset());
   1786   section_offsets.insert(collections.EncodedArrayItemsOffset());
   1787   section_offsets.insert(collections.AnnotationsDirectoryItemsOffset());
   1788 
   1789   auto found = section_offsets.find(offset);
   1790   if (found != section_offsets.end()) {
   1791     found++;
   1792     if (found != section_offsets.end()) {
   1793       return *found % kDexCodeItemAlignment == 0;
   1794     }
   1795   }
   1796   return false;
   1797 }
   1798 
   1799 // Adjust offsets of every item in the specified section by diff bytes.
   1800 template<class T> void DexLayout::FixupSection(std::map<uint32_t, std::unique_ptr<T>>& map,
   1801                                                uint32_t diff) {
   1802   for (auto& pair : map) {
   1803     std::unique_ptr<T>& item = pair.second;
   1804     item->SetOffset(item->GetOffset() + diff);
   1805   }
   1806 }
   1807 
   1808 // Adjust offsets of all sections with an address after the specified offset by diff bytes.
   1809 void DexLayout::FixupSections(uint32_t offset, uint32_t diff) {
   1810   dex_ir::Collections& collections = header_->GetCollections();
   1811   uint32_t map_list_offset = collections.MapListOffset();
   1812   if (map_list_offset > offset) {
   1813     collections.SetMapListOffset(map_list_offset + diff);
   1814   }
   1815 
   1816   uint32_t type_lists_offset = collections.TypeListsOffset();
   1817   if (type_lists_offset > offset) {
   1818     collections.SetTypeListsOffset(type_lists_offset + diff);
   1819     FixupSection(collections.TypeLists(), diff);
   1820   }
   1821 
   1822   uint32_t annotation_set_ref_lists_offset = collections.AnnotationSetRefListsOffset();
   1823   if (annotation_set_ref_lists_offset > offset) {
   1824     collections.SetAnnotationSetRefListsOffset(annotation_set_ref_lists_offset + diff);
   1825     FixupSection(collections.AnnotationSetRefLists(), diff);
   1826   }
   1827 
   1828   uint32_t annotation_set_items_offset = collections.AnnotationSetItemsOffset();
   1829   if (annotation_set_items_offset > offset) {
   1830     collections.SetAnnotationSetItemsOffset(annotation_set_items_offset + diff);
   1831     FixupSection(collections.AnnotationSetItems(), diff);
   1832   }
   1833 
   1834   uint32_t class_datas_offset = collections.ClassDatasOffset();
   1835   if (class_datas_offset > offset) {
   1836     collections.SetClassDatasOffset(class_datas_offset + diff);
   1837     FixupSection(collections.ClassDatas(), diff);
   1838   }
   1839 
   1840   uint32_t code_items_offset = collections.CodeItemsOffset();
   1841   if (code_items_offset > offset) {
   1842     collections.SetCodeItemsOffset(code_items_offset + diff);
   1843     FixupSection(collections.CodeItems(), diff);
   1844   }
   1845 
   1846   uint32_t string_datas_offset = collections.StringDatasOffset();
   1847   if (string_datas_offset > offset) {
   1848     collections.SetStringDatasOffset(string_datas_offset + diff);
   1849     FixupSection(collections.StringDatas(), diff);
   1850   }
   1851 
   1852   uint32_t debug_info_items_offset = collections.DebugInfoItemsOffset();
   1853   if (debug_info_items_offset > offset) {
   1854     collections.SetDebugInfoItemsOffset(debug_info_items_offset + diff);
   1855     FixupSection(collections.DebugInfoItems(), diff);
   1856   }
   1857 
   1858   uint32_t annotation_items_offset = collections.AnnotationItemsOffset();
   1859   if (annotation_items_offset > offset) {
   1860     collections.SetAnnotationItemsOffset(annotation_items_offset + diff);
   1861     FixupSection(collections.AnnotationItems(), diff);
   1862   }
   1863 
   1864   uint32_t encoded_array_items_offset = collections.EncodedArrayItemsOffset();
   1865   if (encoded_array_items_offset > offset) {
   1866     collections.SetEncodedArrayItemsOffset(encoded_array_items_offset + diff);
   1867     FixupSection(collections.EncodedArrayItems(), diff);
   1868   }
   1869 
   1870   uint32_t annotations_directory_items_offset = collections.AnnotationsDirectoryItemsOffset();
   1871   if (annotations_directory_items_offset > offset) {
   1872     collections.SetAnnotationsDirectoryItemsOffset(annotations_directory_items_offset + diff);
   1873     FixupSection(collections.AnnotationsDirectoryItems(), diff);
   1874   }
   1875 }
   1876 
   1877 void DexLayout::LayoutOutputFile(const DexFile* dex_file) {
   1878   LayoutStringData(dex_file);
   1879   std::vector<dex_ir::ClassData*> new_class_data_order = LayoutClassDefsAndClassData(dex_file);
   1880   int32_t diff = LayoutCodeItems(dex_file, new_class_data_order);
   1881   // Move sections after ClassData by diff bytes.
   1882   FixupSections(header_->GetCollections().ClassDatasOffset(), diff);
   1883   // Update file size.
   1884   header_->SetFileSize(header_->FileSize() + diff);
   1885 }
   1886 
   1887 void DexLayout::OutputDexFile(const DexFile* dex_file) {
   1888   const std::string& dex_file_location = dex_file->GetLocation();
   1889   std::string error_msg;
   1890   std::unique_ptr<File> new_file;
   1891   if (!options_.output_to_memmap_) {
   1892     std::string output_location(options_.output_dex_directory_);
   1893     size_t last_slash = dex_file_location.rfind('/');
   1894     std::string dex_file_directory = dex_file_location.substr(0, last_slash + 1);
   1895     if (output_location == dex_file_directory) {
   1896       output_location = dex_file_location + ".new";
   1897     } else if (last_slash != std::string::npos) {
   1898       output_location += dex_file_location.substr(last_slash);
   1899     } else {
   1900       output_location += "/" + dex_file_location + ".new";
   1901     }
   1902     new_file.reset(OS::CreateEmptyFile(output_location.c_str()));
   1903     if (new_file == nullptr) {
   1904       LOG(ERROR) << "Could not create dex writer output file: " << output_location;
   1905       return;
   1906     }
   1907     if (ftruncate(new_file->Fd(), header_->FileSize()) != 0) {
   1908       LOG(ERROR) << "Could not grow dex writer output file: " << output_location;;
   1909       new_file->Erase();
   1910       return;
   1911     }
   1912     mem_map_.reset(MemMap::MapFile(header_->FileSize(), PROT_READ | PROT_WRITE, MAP_SHARED,
   1913         new_file->Fd(), 0, /*low_4gb*/ false, output_location.c_str(), &error_msg));
   1914   } else {
   1915     mem_map_.reset(MemMap::MapAnonymous("layout dex", nullptr, header_->FileSize(),
   1916         PROT_READ | PROT_WRITE, /* low_4gb */ false, /* reuse */ false, &error_msg));
   1917   }
   1918   if (mem_map_ == nullptr) {
   1919     LOG(ERROR) << "Could not create mem map for dex writer output: " << error_msg;
   1920     if (new_file != nullptr) {
   1921       new_file->Erase();
   1922     }
   1923     return;
   1924   }
   1925   DexWriter::Output(header_, mem_map_.get());
   1926   if (new_file != nullptr) {
   1927     UNUSED(new_file->FlushCloseOrErase());
   1928   }
   1929   // Verify the output dex file's structure for debug builds.
   1930   if (kIsDebugBuild) {
   1931     std::string location = "memory mapped file for " + dex_file_location;
   1932     std::unique_ptr<const DexFile> output_dex_file(DexFile::Open(mem_map_->Begin(),
   1933                                                                  mem_map_->Size(),
   1934                                                                  location,
   1935                                                                  header_->Checksum(),
   1936                                                                  /*oat_dex_file*/ nullptr,
   1937                                                                  /*verify*/ true,
   1938                                                                  /*verify_checksum*/ false,
   1939                                                                  &error_msg));
   1940     DCHECK(output_dex_file != nullptr) << "Failed to re-open output file:" << error_msg;
   1941   }
   1942   // Do IR-level comparison between input and output. This check ignores potential differences
   1943   // due to layout, so offsets are not checked. Instead, it checks the data contents of each item.
   1944   if (kIsDebugBuild || options_.verify_output_) {
   1945     std::unique_ptr<dex_ir::Header> orig_header(dex_ir::DexIrBuilder(*dex_file));
   1946     CHECK(VerifyOutputDexFile(orig_header.get(), header_, &error_msg)) << error_msg;
   1947   }
   1948 }
   1949 
   1950 /*
   1951  * Dumps the requested sections of the file.
   1952  */
   1953 void DexLayout::ProcessDexFile(const char* file_name,
   1954                                const DexFile* dex_file,
   1955                                size_t dex_file_index) {
   1956   std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file));
   1957   SetHeader(header.get());
   1958 
   1959   if (options_.verbose_) {
   1960     fprintf(out_file_, "Opened '%s', DEX version '%.3s'\n",
   1961             file_name, dex_file->GetHeader().magic_ + 4);
   1962   }
   1963 
   1964   if (options_.visualize_pattern_) {
   1965     VisualizeDexLayout(header_, dex_file, dex_file_index, info_);
   1966     return;
   1967   }
   1968 
   1969   if (options_.show_section_statistics_) {
   1970     ShowDexSectionStatistics(header_, dex_file_index);
   1971     return;
   1972   }
   1973 
   1974   // Dump dex file.
   1975   if (options_.dump_) {
   1976     DumpDexFile();
   1977   }
   1978 
   1979   // Output dex file as file or memmap.
   1980   if (options_.output_dex_directory_ != nullptr || options_.output_to_memmap_) {
   1981     if (info_ != nullptr) {
   1982       LayoutOutputFile(dex_file);
   1983     }
   1984     OutputDexFile(dex_file);
   1985   }
   1986 }
   1987 
   1988 /*
   1989  * Processes a single file (either direct .dex or indirect .zip/.jar/.apk).
   1990  */
   1991 int DexLayout::ProcessFile(const char* file_name) {
   1992   if (options_.verbose_) {
   1993     fprintf(out_file_, "Processing '%s'...\n", file_name);
   1994   }
   1995 
   1996   // If the file is not a .dex file, the function tries .zip/.jar/.apk files,
   1997   // all of which are Zip archives with "classes.dex" inside.
   1998   const bool verify_checksum = !options_.ignore_bad_checksum_;
   1999   std::string error_msg;
   2000   std::vector<std::unique_ptr<const DexFile>> dex_files;
   2001   if (!DexFile::Open(file_name, file_name, verify_checksum, &error_msg, &dex_files)) {
   2002     // Display returned error message to user. Note that this error behavior
   2003     // differs from the error messages shown by the original Dalvik dexdump.
   2004     fputs(error_msg.c_str(), stderr);
   2005     fputc('\n', stderr);
   2006     return -1;
   2007   }
   2008 
   2009   // Success. Either report checksum verification or process
   2010   // all dex files found in given file.
   2011   if (options_.checksum_only_) {
   2012     fprintf(out_file_, "Checksum verified\n");
   2013   } else {
   2014     for (size_t i = 0; i < dex_files.size(); i++) {
   2015       ProcessDexFile(file_name, dex_files[i].get(), i);
   2016     }
   2017   }
   2018   return 0;
   2019 }
   2020 
   2021 }  // namespace art
   2022