Home | History | Annotate | Download | only in oatdump
      1 /*
      2  * Copyright (C) 2011 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 
     17 #include <stdio.h>
     18 #include <stdlib.h>
     19 
     20 #include <fstream>
     21 #include <iostream>
     22 #include <map>
     23 #include <set>
     24 #include <string>
     25 #include <unordered_map>
     26 #include <unordered_set>
     27 #include <vector>
     28 
     29 #include "android-base/stringprintf.h"
     30 #include "android-base/strings.h"
     31 
     32 #include "arch/instruction_set_features.h"
     33 #include "art_field-inl.h"
     34 #include "art_method-inl.h"
     35 #include "base/stl_util.h"
     36 #include "base/unix_file/fd_file.h"
     37 #include "class_linker-inl.h"
     38 #include "class_linker.h"
     39 #include "debug/elf_debug_writer.h"
     40 #include "debug/method_debug_info.h"
     41 #include "dex_file-inl.h"
     42 #include "dex_instruction-inl.h"
     43 #include "disassembler.h"
     44 #include "elf_builder.h"
     45 #include "gc/accounting/space_bitmap-inl.h"
     46 #include "gc/space/image_space.h"
     47 #include "gc/space/large_object_space.h"
     48 #include "gc/space/space-inl.h"
     49 #include "image-inl.h"
     50 #include "imtable-inl.h"
     51 #include "indenter.h"
     52 #include "interpreter/unstarted_runtime.h"
     53 #include "linker/buffered_output_stream.h"
     54 #include "linker/file_output_stream.h"
     55 #include "mirror/array-inl.h"
     56 #include "mirror/class-inl.h"
     57 #include "mirror/dex_cache-inl.h"
     58 #include "mirror/object-inl.h"
     59 #include "mirror/object_array-inl.h"
     60 #include "nativehelper/ScopedLocalRef.h"
     61 #include "oat.h"
     62 #include "oat_file-inl.h"
     63 #include "oat_file_manager.h"
     64 #include "os.h"
     65 #include "safe_map.h"
     66 #include "scoped_thread_state_change-inl.h"
     67 #include "stack.h"
     68 #include "stack_map.h"
     69 #include "string_reference.h"
     70 #include "thread_list.h"
     71 #include "type_lookup_table.h"
     72 #include "vdex_file.h"
     73 #include "verifier/method_verifier.h"
     74 #include "verifier/verifier_deps.h"
     75 #include "well_known_classes.h"
     76 
     77 #include <sys/stat.h>
     78 #include "cmdline.h"
     79 
     80 namespace art {
     81 
     82 using android::base::StringPrintf;
     83 
     84 const char* image_methods_descriptions_[] = {
     85   "kResolutionMethod",
     86   "kImtConflictMethod",
     87   "kImtUnimplementedMethod",
     88   "kSaveAllCalleeSavesMethod",
     89   "kSaveRefsOnlyMethod",
     90   "kSaveRefsAndArgsMethod",
     91   "kSaveEverythingMethod",
     92 };
     93 
     94 const char* image_roots_descriptions_[] = {
     95   "kDexCaches",
     96   "kClassRoots",
     97   "kClassLoader",
     98 };
     99 
    100 // Map is so that we don't allocate multiple dex files for the same OatDexFile.
    101 static std::map<const OatFile::OatDexFile*,
    102                 std::unique_ptr<const DexFile>> opened_dex_files;
    103 
    104 const DexFile* OpenDexFile(const OatFile::OatDexFile* oat_dex_file, std::string* error_msg) {
    105   DCHECK(oat_dex_file != nullptr);
    106   auto it = opened_dex_files.find(oat_dex_file);
    107   if (it != opened_dex_files.end()) {
    108     return it->second.get();
    109   }
    110   const DexFile* ret = oat_dex_file->OpenDexFile(error_msg).release();
    111   opened_dex_files.emplace(oat_dex_file, std::unique_ptr<const DexFile>(ret));
    112   return ret;
    113 }
    114 
    115 template <typename ElfTypes>
    116 class OatSymbolizer FINAL {
    117  public:
    118   OatSymbolizer(const OatFile* oat_file, const std::string& output_name, bool no_bits) :
    119       oat_file_(oat_file),
    120       builder_(nullptr),
    121       output_name_(output_name.empty() ? "symbolized.oat" : output_name),
    122       no_bits_(no_bits) {
    123   }
    124 
    125   bool Symbolize() {
    126     const InstructionSet isa = oat_file_->GetOatHeader().GetInstructionSet();
    127     std::unique_ptr<const InstructionSetFeatures> features = InstructionSetFeatures::FromBitmap(
    128         isa, oat_file_->GetOatHeader().GetInstructionSetFeaturesBitmap());
    129 
    130     std::unique_ptr<File> elf_file(OS::CreateEmptyFile(output_name_.c_str()));
    131     if (elf_file == nullptr) {
    132       return false;
    133     }
    134     std::unique_ptr<BufferedOutputStream> output_stream =
    135         std::make_unique<BufferedOutputStream>(std::make_unique<FileOutputStream>(elf_file.get()));
    136     builder_.reset(new ElfBuilder<ElfTypes>(isa, features.get(), output_stream.get()));
    137 
    138     builder_->Start();
    139 
    140     auto* rodata = builder_->GetRoData();
    141     auto* text = builder_->GetText();
    142     auto* bss = builder_->GetBss();
    143 
    144     const uint8_t* rodata_begin = oat_file_->Begin();
    145     const size_t rodata_size = oat_file_->GetOatHeader().GetExecutableOffset();
    146     if (no_bits_) {
    147       rodata->WriteNoBitsSection(rodata_size);
    148     } else {
    149       rodata->Start();
    150       rodata->WriteFully(rodata_begin, rodata_size);
    151       rodata->End();
    152     }
    153 
    154     const uint8_t* text_begin = oat_file_->Begin() + rodata_size;
    155     const size_t text_size = oat_file_->End() - text_begin;
    156     if (no_bits_) {
    157       text->WriteNoBitsSection(text_size);
    158     } else {
    159       text->Start();
    160       text->WriteFully(text_begin, text_size);
    161       text->End();
    162     }
    163 
    164     if (oat_file_->BssSize() != 0) {
    165       bss->WriteNoBitsSection(oat_file_->BssSize());
    166     }
    167 
    168     if (isa == kMips || isa == kMips64) {
    169       builder_->WriteMIPSabiflagsSection();
    170     }
    171     builder_->PrepareDynamicSection(elf_file->GetPath(),
    172                                     rodata_size,
    173                                     text_size,
    174                                     oat_file_->BssSize(),
    175                                     oat_file_->BssMethodsOffset(),
    176                                     oat_file_->BssRootsOffset());
    177     builder_->WriteDynamicSection();
    178 
    179     Walk();
    180     for (const auto& trampoline : debug::MakeTrampolineInfos(oat_file_->GetOatHeader())) {
    181       method_debug_infos_.push_back(trampoline);
    182     }
    183 
    184     debug::WriteDebugInfo(builder_.get(),
    185                           ArrayRef<const debug::MethodDebugInfo>(method_debug_infos_),
    186                           dwarf::DW_DEBUG_FRAME_FORMAT,
    187                           true /* write_oat_patches */);
    188 
    189     builder_->End();
    190 
    191     bool ret_value = builder_->Good();
    192 
    193     builder_.reset();
    194     output_stream.reset();
    195 
    196     if (elf_file->FlushCloseOrErase() != 0) {
    197       return false;
    198     }
    199     elf_file.reset();
    200 
    201     return ret_value;
    202   }
    203 
    204   void Walk() {
    205     std::vector<const OatFile::OatDexFile*> oat_dex_files = oat_file_->GetOatDexFiles();
    206     for (size_t i = 0; i < oat_dex_files.size(); i++) {
    207       const OatFile::OatDexFile* oat_dex_file = oat_dex_files[i];
    208       CHECK(oat_dex_file != nullptr);
    209       WalkOatDexFile(oat_dex_file);
    210     }
    211   }
    212 
    213   void WalkOatDexFile(const OatFile::OatDexFile* oat_dex_file) {
    214     std::string error_msg;
    215     const DexFile* const dex_file = OpenDexFile(oat_dex_file, &error_msg);
    216     if (dex_file == nullptr) {
    217       return;
    218     }
    219     for (size_t class_def_index = 0;
    220         class_def_index < dex_file->NumClassDefs();
    221         class_def_index++) {
    222       const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index);
    223       OatClassType type = oat_class.GetType();
    224       switch (type) {
    225         case kOatClassAllCompiled:
    226         case kOatClassSomeCompiled:
    227           WalkOatClass(oat_class, *dex_file, class_def_index);
    228           break;
    229 
    230         case kOatClassNoneCompiled:
    231         case kOatClassMax:
    232           // Ignore.
    233           break;
    234       }
    235     }
    236   }
    237 
    238   void WalkOatClass(const OatFile::OatClass& oat_class,
    239                     const DexFile& dex_file,
    240                     uint32_t class_def_index) {
    241     const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
    242     const uint8_t* class_data = dex_file.GetClassData(class_def);
    243     if (class_data == nullptr) {  // empty class such as a marker interface?
    244       return;
    245     }
    246     // Note: even if this is an interface or a native class, we still have to walk it, as there
    247     //       might be a static initializer.
    248     ClassDataItemIterator it(dex_file, class_data);
    249     uint32_t class_method_idx = 0;
    250     it.SkipAllFields();
    251     for (; it.HasNextDirectMethod() || it.HasNextVirtualMethod(); it.Next()) {
    252       WalkOatMethod(oat_class.GetOatMethod(class_method_idx++),
    253                     dex_file,
    254                     class_def_index,
    255                     it.GetMemberIndex(),
    256                     it.GetMethodCodeItem(),
    257                     it.GetMethodAccessFlags());
    258     }
    259     DCHECK(!it.HasNext());
    260   }
    261 
    262   void WalkOatMethod(const OatFile::OatMethod& oat_method,
    263                      const DexFile& dex_file,
    264                      uint32_t class_def_index,
    265                      uint32_t dex_method_index,
    266                      const DexFile::CodeItem* code_item,
    267                      uint32_t method_access_flags) {
    268     if ((method_access_flags & kAccAbstract) != 0) {
    269       // Abstract method, no code.
    270       return;
    271     }
    272     const OatHeader& oat_header = oat_file_->GetOatHeader();
    273     const OatQuickMethodHeader* method_header = oat_method.GetOatQuickMethodHeader();
    274     if (method_header == nullptr || method_header->GetCodeSize() == 0) {
    275       // No code.
    276       return;
    277     }
    278 
    279     uint32_t entry_point = oat_method.GetCodeOffset() - oat_header.GetExecutableOffset();
    280     // Clear Thumb2 bit.
    281     const void* code_address = EntryPointToCodePointer(reinterpret_cast<void*>(entry_point));
    282 
    283     debug::MethodDebugInfo info = debug::MethodDebugInfo();
    284     info.trampoline_name = nullptr;
    285     info.dex_file = &dex_file;
    286     info.class_def_index = class_def_index;
    287     info.dex_method_index = dex_method_index;
    288     info.access_flags = method_access_flags;
    289     info.code_item = code_item;
    290     info.isa = oat_header.GetInstructionSet();
    291     info.deduped = !seen_offsets_.insert(oat_method.GetCodeOffset()).second;
    292     info.is_native_debuggable = oat_header.IsNativeDebuggable();
    293     info.is_optimized = method_header->IsOptimized();
    294     info.is_code_address_text_relative = true;
    295     info.code_address = reinterpret_cast<uintptr_t>(code_address);
    296     info.code_size = method_header->GetCodeSize();
    297     info.frame_size_in_bytes = method_header->GetFrameSizeInBytes();
    298     info.code_info = info.is_optimized ? method_header->GetOptimizedCodeInfoPtr() : nullptr;
    299     info.cfi = ArrayRef<uint8_t>();
    300     method_debug_infos_.push_back(info);
    301   }
    302 
    303  private:
    304   const OatFile* oat_file_;
    305   std::unique_ptr<ElfBuilder<ElfTypes> > builder_;
    306   std::vector<debug::MethodDebugInfo> method_debug_infos_;
    307   std::unordered_set<uint32_t> seen_offsets_;
    308   const std::string output_name_;
    309   bool no_bits_;
    310 };
    311 
    312 class OatDumperOptions {
    313  public:
    314   OatDumperOptions(bool dump_vmap,
    315                    bool dump_code_info_stack_maps,
    316                    bool disassemble_code,
    317                    bool absolute_addresses,
    318                    const char* class_filter,
    319                    const char* method_filter,
    320                    bool list_classes,
    321                    bool list_methods,
    322                    bool dump_header_only,
    323                    const char* export_dex_location,
    324                    const char* app_image,
    325                    const char* app_oat,
    326                    uint32_t addr2instr)
    327     : dump_vmap_(dump_vmap),
    328       dump_code_info_stack_maps_(dump_code_info_stack_maps),
    329       disassemble_code_(disassemble_code),
    330       absolute_addresses_(absolute_addresses),
    331       class_filter_(class_filter),
    332       method_filter_(method_filter),
    333       list_classes_(list_classes),
    334       list_methods_(list_methods),
    335       dump_header_only_(dump_header_only),
    336       export_dex_location_(export_dex_location),
    337       app_image_(app_image),
    338       app_oat_(app_oat),
    339       addr2instr_(addr2instr),
    340       class_loader_(nullptr) {}
    341 
    342   const bool dump_vmap_;
    343   const bool dump_code_info_stack_maps_;
    344   const bool disassemble_code_;
    345   const bool absolute_addresses_;
    346   const char* const class_filter_;
    347   const char* const method_filter_;
    348   const bool list_classes_;
    349   const bool list_methods_;
    350   const bool dump_header_only_;
    351   const char* const export_dex_location_;
    352   const char* const app_image_;
    353   const char* const app_oat_;
    354   uint32_t addr2instr_;
    355   Handle<mirror::ClassLoader>* class_loader_;
    356 };
    357 
    358 class OatDumper {
    359  public:
    360   OatDumper(const OatFile& oat_file, const OatDumperOptions& options)
    361     : oat_file_(oat_file),
    362       oat_dex_files_(oat_file.GetOatDexFiles()),
    363       options_(options),
    364       resolved_addr2instr_(0),
    365       instruction_set_(oat_file_.GetOatHeader().GetInstructionSet()),
    366       disassembler_(Disassembler::Create(instruction_set_,
    367                                          new DisassemblerOptions(
    368                                              options_.absolute_addresses_,
    369                                              oat_file.Begin(),
    370                                              oat_file.End(),
    371                                              true /* can_read_literals_ */,
    372                                              Is64BitInstructionSet(instruction_set_)
    373                                                  ? &Thread::DumpThreadOffset<PointerSize::k64>
    374                                                  : &Thread::DumpThreadOffset<PointerSize::k32>))) {
    375     CHECK(options_.class_loader_ != nullptr);
    376     CHECK(options_.class_filter_ != nullptr);
    377     CHECK(options_.method_filter_ != nullptr);
    378     AddAllOffsets();
    379   }
    380 
    381   ~OatDumper() {
    382     delete disassembler_;
    383   }
    384 
    385   InstructionSet GetInstructionSet() {
    386     return instruction_set_;
    387   }
    388 
    389   bool Dump(std::ostream& os) {
    390     bool success = true;
    391     const OatHeader& oat_header = oat_file_.GetOatHeader();
    392 
    393     os << "MAGIC:\n";
    394     os << oat_header.GetMagic() << "\n\n";
    395 
    396     os << "LOCATION:\n";
    397     os << oat_file_.GetLocation() << "\n\n";
    398 
    399     os << "CHECKSUM:\n";
    400     os << StringPrintf("0x%08x\n\n", oat_header.GetChecksum());
    401 
    402     os << "INSTRUCTION SET:\n";
    403     os << oat_header.GetInstructionSet() << "\n\n";
    404 
    405     {
    406       std::unique_ptr<const InstructionSetFeatures> features(
    407           InstructionSetFeatures::FromBitmap(oat_header.GetInstructionSet(),
    408                                              oat_header.GetInstructionSetFeaturesBitmap()));
    409       os << "INSTRUCTION SET FEATURES:\n";
    410       os << features->GetFeatureString() << "\n\n";
    411     }
    412 
    413     os << "DEX FILE COUNT:\n";
    414     os << oat_header.GetDexFileCount() << "\n\n";
    415 
    416 #define DUMP_OAT_HEADER_OFFSET(label, offset) \
    417     os << label " OFFSET:\n"; \
    418     os << StringPrintf("0x%08x", oat_header.offset()); \
    419     if (oat_header.offset() != 0 && options_.absolute_addresses_) { \
    420       os << StringPrintf(" (%p)", oat_file_.Begin() + oat_header.offset()); \
    421     } \
    422     os << StringPrintf("\n\n");
    423 
    424     DUMP_OAT_HEADER_OFFSET("EXECUTABLE", GetExecutableOffset);
    425     DUMP_OAT_HEADER_OFFSET("INTERPRETER TO INTERPRETER BRIDGE",
    426                            GetInterpreterToInterpreterBridgeOffset);
    427     DUMP_OAT_HEADER_OFFSET("INTERPRETER TO COMPILED CODE BRIDGE",
    428                            GetInterpreterToCompiledCodeBridgeOffset);
    429     DUMP_OAT_HEADER_OFFSET("JNI DLSYM LOOKUP",
    430                            GetJniDlsymLookupOffset);
    431     DUMP_OAT_HEADER_OFFSET("QUICK GENERIC JNI TRAMPOLINE",
    432                            GetQuickGenericJniTrampolineOffset);
    433     DUMP_OAT_HEADER_OFFSET("QUICK IMT CONFLICT TRAMPOLINE",
    434                            GetQuickImtConflictTrampolineOffset);
    435     DUMP_OAT_HEADER_OFFSET("QUICK RESOLUTION TRAMPOLINE",
    436                            GetQuickResolutionTrampolineOffset);
    437     DUMP_OAT_HEADER_OFFSET("QUICK TO INTERPRETER BRIDGE",
    438                            GetQuickToInterpreterBridgeOffset);
    439 #undef DUMP_OAT_HEADER_OFFSET
    440 
    441     os << "IMAGE PATCH DELTA:\n";
    442     os << StringPrintf("%d (0x%08x)\n\n",
    443                        oat_header.GetImagePatchDelta(),
    444                        oat_header.GetImagePatchDelta());
    445 
    446     os << "IMAGE FILE LOCATION OAT CHECKSUM:\n";
    447     os << StringPrintf("0x%08x\n\n", oat_header.GetImageFileLocationOatChecksum());
    448 
    449     os << "IMAGE FILE LOCATION OAT BEGIN:\n";
    450     os << StringPrintf("0x%08x\n\n", oat_header.GetImageFileLocationOatDataBegin());
    451 
    452     // Print the key-value store.
    453     {
    454       os << "KEY VALUE STORE:\n";
    455       size_t index = 0;
    456       const char* key;
    457       const char* value;
    458       while (oat_header.GetStoreKeyValuePairByIndex(index, &key, &value)) {
    459         os << key << " = " << value << "\n";
    460         index++;
    461       }
    462       os << "\n";
    463     }
    464 
    465     if (options_.absolute_addresses_) {
    466       os << "BEGIN:\n";
    467       os << reinterpret_cast<const void*>(oat_file_.Begin()) << "\n\n";
    468 
    469       os << "END:\n";
    470       os << reinterpret_cast<const void*>(oat_file_.End()) << "\n\n";
    471     }
    472 
    473     os << "SIZE:\n";
    474     os << oat_file_.Size() << "\n\n";
    475 
    476     os << std::flush;
    477 
    478     // If set, adjust relative address to be searched
    479     if (options_.addr2instr_ != 0) {
    480       resolved_addr2instr_ = options_.addr2instr_ + oat_header.GetExecutableOffset();
    481       os << "SEARCH ADDRESS (executable offset + input):\n";
    482       os << StringPrintf("0x%08x\n\n", resolved_addr2instr_);
    483     }
    484 
    485     // Dumping the dex file overview is compact enough to do even if header only.
    486     DexFileData cumulative;
    487     for (size_t i = 0; i < oat_dex_files_.size(); i++) {
    488       const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
    489       CHECK(oat_dex_file != nullptr);
    490       std::string error_msg;
    491       const DexFile* const dex_file = OpenDexFile(oat_dex_file, &error_msg);
    492       if (dex_file == nullptr) {
    493         os << "Failed to open dex file '" << oat_dex_file->GetDexFileLocation() << "': "
    494            << error_msg;
    495         continue;
    496       }
    497       DexFileData data(*dex_file);
    498       os << "Dex file data for " << dex_file->GetLocation() << "\n";
    499       data.Dump(os);
    500       os << "\n";
    501       const DexLayoutSections* const layout_sections = oat_dex_file->GetDexLayoutSections();
    502       if (layout_sections != nullptr) {
    503         os << "Layout data\n";
    504         os << *layout_sections;
    505         os << "\n";
    506       }
    507 
    508       cumulative.Add(data);
    509     }
    510     os << "Cumulative dex file data\n";
    511     cumulative.Dump(os);
    512     os << "\n";
    513 
    514     if (!options_.dump_header_only_) {
    515       VariableIndentationOutputStream vios(&os);
    516       VdexFile::Header vdex_header = oat_file_.GetVdexFile()->GetHeader();
    517       if (vdex_header.IsValid()) {
    518         std::string error_msg;
    519         std::vector<const DexFile*> dex_files;
    520         for (size_t i = 0; i < oat_dex_files_.size(); i++) {
    521           const DexFile* dex_file = OpenDexFile(oat_dex_files_[i], &error_msg);
    522           if (dex_file == nullptr) {
    523             os << "Error opening dex file: " << error_msg << std::endl;
    524             return false;
    525           }
    526           dex_files.push_back(dex_file);
    527         }
    528         verifier::VerifierDeps deps(dex_files, oat_file_.GetVdexFile()->GetVerifierDepsData());
    529         deps.Dump(&vios);
    530       } else {
    531         os << "UNRECOGNIZED vdex file, magic "
    532            << vdex_header.GetMagic()
    533            << ", version "
    534            << vdex_header.GetVersion()
    535            << "\n";
    536       }
    537       for (size_t i = 0; i < oat_dex_files_.size(); i++) {
    538         const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
    539         CHECK(oat_dex_file != nullptr);
    540 
    541         // If file export selected skip file analysis
    542         if (options_.export_dex_location_) {
    543           if (!ExportDexFile(os, *oat_dex_file)) {
    544             success = false;
    545           }
    546         } else {
    547           if (!DumpOatDexFile(os, *oat_dex_file)) {
    548             success = false;
    549           }
    550         }
    551       }
    552     }
    553 
    554     {
    555       os << "OAT FILE STATS:\n";
    556       VariableIndentationOutputStream vios(&os);
    557       stats_.Dump(vios);
    558     }
    559 
    560     os << std::flush;
    561     return success;
    562   }
    563 
    564   size_t ComputeSize(const void* oat_data) {
    565     if (reinterpret_cast<const uint8_t*>(oat_data) < oat_file_.Begin() ||
    566         reinterpret_cast<const uint8_t*>(oat_data) > oat_file_.End()) {
    567       return 0;  // Address not in oat file
    568     }
    569     uintptr_t begin_offset = reinterpret_cast<uintptr_t>(oat_data) -
    570                              reinterpret_cast<uintptr_t>(oat_file_.Begin());
    571     auto it = offsets_.upper_bound(begin_offset);
    572     CHECK(it != offsets_.end());
    573     uintptr_t end_offset = *it;
    574     return end_offset - begin_offset;
    575   }
    576 
    577   InstructionSet GetOatInstructionSet() {
    578     return oat_file_.GetOatHeader().GetInstructionSet();
    579   }
    580 
    581   const void* GetQuickOatCode(ArtMethod* m) REQUIRES_SHARED(Locks::mutator_lock_) {
    582     for (size_t i = 0; i < oat_dex_files_.size(); i++) {
    583       const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
    584       CHECK(oat_dex_file != nullptr);
    585       std::string error_msg;
    586       const DexFile* const dex_file = OpenDexFile(oat_dex_file, &error_msg);
    587       if (dex_file == nullptr) {
    588         LOG(WARNING) << "Failed to open dex file '" << oat_dex_file->GetDexFileLocation()
    589             << "': " << error_msg;
    590       } else {
    591         const char* descriptor = m->GetDeclaringClassDescriptor();
    592         const DexFile::ClassDef* class_def =
    593             OatDexFile::FindClassDef(*dex_file, descriptor, ComputeModifiedUtf8Hash(descriptor));
    594         if (class_def != nullptr) {
    595           uint16_t class_def_index = dex_file->GetIndexForClassDef(*class_def);
    596           const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index);
    597           size_t method_index = m->GetMethodIndex();
    598           return oat_class.GetOatMethod(method_index).GetQuickCode();
    599         }
    600       }
    601     }
    602     return nullptr;
    603   }
    604 
    605   struct Stats {
    606     enum ByteKind {
    607       kByteKindCode,
    608       kByteKindQuickMethodHeader,
    609       kByteKindCodeInfoLocationCatalog,
    610       kByteKindCodeInfoDexRegisterMap,
    611       kByteKindCodeInfoEncoding,
    612       kByteKindCodeInfoInvokeInfo,
    613       kByteKindCodeInfoStackMasks,
    614       kByteKindCodeInfoRegisterMasks,
    615       kByteKindStackMapNativePc,
    616       kByteKindStackMapDexPc,
    617       kByteKindStackMapDexRegisterMap,
    618       kByteKindStackMapInlineInfoIndex,
    619       kByteKindStackMapRegisterMaskIndex,
    620       kByteKindStackMapStackMaskIndex,
    621       kByteKindInlineInfoMethodIndexIdx,
    622       kByteKindInlineInfoDexPc,
    623       kByteKindInlineInfoExtraData,
    624       kByteKindInlineInfoDexRegisterMap,
    625       kByteKindInlineInfoIsLast,
    626       kByteKindCount,
    627       // Special ranges for std::accumulate convenience.
    628       kByteKindStackMapFirst = kByteKindStackMapNativePc,
    629       kByteKindStackMapLast = kByteKindStackMapStackMaskIndex,
    630       kByteKindInlineInfoFirst = kByteKindInlineInfoMethodIndexIdx,
    631       kByteKindInlineInfoLast = kByteKindInlineInfoIsLast,
    632     };
    633     int64_t bits[kByteKindCount] = {};
    634     // Since code has deduplication, seen tracks already seen pointers to avoid double counting
    635     // deduplicated code and tables.
    636     std::unordered_set<const void*> seen;
    637 
    638     // Returns true if it was newly added.
    639     bool AddBitsIfUnique(ByteKind kind, int64_t count, const void* address) {
    640       if (seen.insert(address).second == true) {
    641         // True means the address was not already in the set.
    642         AddBits(kind, count);
    643         return true;
    644       }
    645       return false;
    646     }
    647 
    648     void AddBits(ByteKind kind, int64_t count) {
    649       bits[kind] += count;
    650     }
    651 
    652     void Dump(VariableIndentationOutputStream& os) {
    653       const int64_t sum = std::accumulate(bits, bits + kByteKindCount, 0u);
    654       os.Stream() << "Dumping cumulative use of " << sum / kBitsPerByte << " accounted bytes\n";
    655       if (sum > 0) {
    656         Dump(os, "Code                            ", bits[kByteKindCode], sum);
    657         Dump(os, "QuickMethodHeader               ", bits[kByteKindQuickMethodHeader], sum);
    658         Dump(os, "CodeInfoEncoding                ", bits[kByteKindCodeInfoEncoding], sum);
    659         Dump(os, "CodeInfoLocationCatalog         ", bits[kByteKindCodeInfoLocationCatalog], sum);
    660         Dump(os, "CodeInfoDexRegisterMap          ", bits[kByteKindCodeInfoDexRegisterMap], sum);
    661         Dump(os, "CodeInfoStackMasks              ", bits[kByteKindCodeInfoStackMasks], sum);
    662         Dump(os, "CodeInfoRegisterMasks           ", bits[kByteKindCodeInfoRegisterMasks], sum);
    663         Dump(os, "CodeInfoInvokeInfo              ", bits[kByteKindCodeInfoInvokeInfo], sum);
    664         // Stack map section.
    665         const int64_t stack_map_bits = std::accumulate(bits + kByteKindStackMapFirst,
    666                                                        bits + kByteKindStackMapLast + 1,
    667                                                        0u);
    668         Dump(os, "CodeInfoStackMap                ", stack_map_bits, sum);
    669         {
    670           ScopedIndentation indent1(&os);
    671           Dump(os,
    672                "StackMapNativePc              ",
    673                bits[kByteKindStackMapNativePc],
    674                stack_map_bits,
    675                "stack map");
    676           Dump(os,
    677                "StackMapDexPcEncoding         ",
    678                bits[kByteKindStackMapDexPc],
    679                stack_map_bits,
    680                "stack map");
    681           Dump(os,
    682                "StackMapDexRegisterMap        ",
    683                bits[kByteKindStackMapDexRegisterMap],
    684                stack_map_bits,
    685                "stack map");
    686           Dump(os,
    687                "StackMapInlineInfoIndex       ",
    688                bits[kByteKindStackMapInlineInfoIndex],
    689                stack_map_bits,
    690                "stack map");
    691           Dump(os,
    692                "StackMapRegisterMaskIndex     ",
    693                bits[kByteKindStackMapRegisterMaskIndex],
    694                stack_map_bits,
    695                "stack map");
    696           Dump(os,
    697                "StackMapStackMaskIndex        ",
    698                bits[kByteKindStackMapStackMaskIndex],
    699                stack_map_bits,
    700                "stack map");
    701         }
    702         // Inline info section.
    703         const int64_t inline_info_bits = std::accumulate(bits + kByteKindInlineInfoFirst,
    704                                                          bits + kByteKindInlineInfoLast + 1,
    705                                                          0u);
    706         Dump(os, "CodeInfoInlineInfo              ", inline_info_bits, sum);
    707         {
    708           ScopedIndentation indent1(&os);
    709           Dump(os,
    710                "InlineInfoMethodIndexIdx      ",
    711                bits[kByteKindInlineInfoMethodIndexIdx],
    712                inline_info_bits,
    713                "inline info");
    714           Dump(os,
    715                "InlineInfoDexPc               ",
    716                bits[kByteKindStackMapDexPc],
    717                inline_info_bits,
    718                "inline info");
    719           Dump(os,
    720                "InlineInfoExtraData           ",
    721                bits[kByteKindInlineInfoExtraData],
    722                inline_info_bits,
    723                "inline info");
    724           Dump(os,
    725                "InlineInfoDexRegisterMap      ",
    726                bits[kByteKindInlineInfoDexRegisterMap],
    727                inline_info_bits,
    728                "inline info");
    729           Dump(os,
    730                "InlineInfoIsLast              ",
    731                bits[kByteKindInlineInfoIsLast],
    732                inline_info_bits,
    733                "inline info");
    734         }
    735       }
    736       os.Stream() << "\n" << std::flush;
    737     }
    738 
    739    private:
    740     void Dump(VariableIndentationOutputStream& os,
    741               const char* name,
    742               int64_t size,
    743               int64_t total,
    744               const char* sum_of = "total") {
    745       const double percent = (static_cast<double>(size) / static_cast<double>(total)) * 100;
    746       os.Stream() << StringPrintf("%s = %8" PRId64 " (%2.0f%% of %s)\n",
    747                                   name,
    748                                   size / kBitsPerByte,
    749                                   percent,
    750                                   sum_of);
    751     }
    752   };
    753 
    754  private:
    755   void AddAllOffsets() {
    756     // We don't know the length of the code for each method, but we need to know where to stop
    757     // when disassembling. What we do know is that a region of code will be followed by some other
    758     // region, so if we keep a sorted sequence of the start of each region, we can infer the length
    759     // of a piece of code by using upper_bound to find the start of the next region.
    760     for (size_t i = 0; i < oat_dex_files_.size(); i++) {
    761       const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
    762       CHECK(oat_dex_file != nullptr);
    763       std::string error_msg;
    764       const DexFile* const dex_file = OpenDexFile(oat_dex_file, &error_msg);
    765       if (dex_file == nullptr) {
    766         LOG(WARNING) << "Failed to open dex file '" << oat_dex_file->GetDexFileLocation()
    767             << "': " << error_msg;
    768         continue;
    769       }
    770       offsets_.insert(reinterpret_cast<uintptr_t>(&dex_file->GetHeader()));
    771       for (size_t class_def_index = 0;
    772            class_def_index < dex_file->NumClassDefs();
    773            class_def_index++) {
    774         const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
    775         const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index);
    776         const uint8_t* class_data = dex_file->GetClassData(class_def);
    777         if (class_data != nullptr) {
    778           ClassDataItemIterator it(*dex_file, class_data);
    779           it.SkipAllFields();
    780           uint32_t class_method_index = 0;
    781           while (it.HasNextDirectMethod()) {
    782             AddOffsets(oat_class.GetOatMethod(class_method_index++));
    783             it.Next();
    784           }
    785           while (it.HasNextVirtualMethod()) {
    786             AddOffsets(oat_class.GetOatMethod(class_method_index++));
    787             it.Next();
    788           }
    789         }
    790       }
    791     }
    792 
    793     // If the last thing in the file is code for a method, there won't be an offset for the "next"
    794     // thing. Instead of having a special case in the upper_bound code, let's just add an entry
    795     // for the end of the file.
    796     offsets_.insert(oat_file_.Size());
    797   }
    798 
    799   static uint32_t AlignCodeOffset(uint32_t maybe_thumb_offset) {
    800     return maybe_thumb_offset & ~0x1;  // TODO: Make this Thumb2 specific.
    801   }
    802 
    803   void AddOffsets(const OatFile::OatMethod& oat_method) {
    804     uint32_t code_offset = oat_method.GetCodeOffset();
    805     if (oat_file_.GetOatHeader().GetInstructionSet() == kThumb2) {
    806       code_offset &= ~0x1;
    807     }
    808     offsets_.insert(code_offset);
    809     offsets_.insert(oat_method.GetVmapTableOffset());
    810   }
    811 
    812   // Dex file data, may be for multiple different dex files.
    813   class DexFileData {
    814    public:
    815     DexFileData() {}
    816 
    817     explicit DexFileData(const DexFile& dex_file)
    818         : num_string_ids_(dex_file.NumStringIds()),
    819           num_method_ids_(dex_file.NumMethodIds()),
    820           num_field_ids_(dex_file.NumFieldIds()),
    821           num_type_ids_(dex_file.NumTypeIds()),
    822           num_class_defs_(dex_file.NumClassDefs()) {
    823       for (size_t class_def_index = 0; class_def_index < num_class_defs_; ++class_def_index) {
    824         const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
    825         WalkClass(dex_file, class_def);
    826       }
    827     }
    828 
    829     void Add(const DexFileData& other) {
    830       AddAll(unique_string_ids_from_code_, other.unique_string_ids_from_code_);
    831       num_string_ids_from_code_ += other.num_string_ids_from_code_;
    832       AddAll(dex_code_item_ptrs_, other.dex_code_item_ptrs_);
    833       dex_code_bytes_ += other.dex_code_bytes_;
    834       num_string_ids_ += other.num_string_ids_;
    835       num_method_ids_ += other.num_method_ids_;
    836       num_field_ids_ += other.num_field_ids_;
    837       num_type_ids_ += other.num_type_ids_;
    838       num_class_defs_ += other.num_class_defs_;
    839     }
    840 
    841     void Dump(std::ostream& os) {
    842       os << "Num string ids: " << num_string_ids_ << "\n";
    843       os << "Num method ids: " << num_method_ids_ << "\n";
    844       os << "Num field ids: " << num_field_ids_ << "\n";
    845       os << "Num type ids: " << num_type_ids_ << "\n";
    846       os << "Num class defs: " << num_class_defs_ << "\n";
    847       os << "Unique strings loaded from dex code: " << unique_string_ids_from_code_.size() << "\n";
    848       os << "Total strings loaded from dex code: " << num_string_ids_from_code_ << "\n";
    849       os << "Number of unique dex code items: " << dex_code_item_ptrs_.size() << "\n";
    850       os << "Total number of dex code bytes: " << dex_code_bytes_ << "\n";
    851     }
    852 
    853   private:
    854     // All of the elements from one container to another.
    855     template <typename Dest, typename Src>
    856     static void AddAll(Dest& dest, const Src& src) {
    857       dest.insert(src.begin(), src.end());
    858     }
    859 
    860     void WalkClass(const DexFile& dex_file, const DexFile::ClassDef& class_def) {
    861       const uint8_t* class_data = dex_file.GetClassData(class_def);
    862       if (class_data == nullptr) {  // empty class such as a marker interface?
    863         return;
    864       }
    865       ClassDataItemIterator it(dex_file, class_data);
    866       it.SkipAllFields();
    867       while (it.HasNextDirectMethod()) {
    868         WalkCodeItem(dex_file, it.GetMethodCodeItem());
    869         it.Next();
    870       }
    871       while (it.HasNextVirtualMethod()) {
    872         WalkCodeItem(dex_file, it.GetMethodCodeItem());
    873         it.Next();
    874       }
    875       DCHECK(!it.HasNext());
    876     }
    877 
    878     void WalkCodeItem(const DexFile& dex_file, const DexFile::CodeItem* code_item) {
    879       if (code_item == nullptr) {
    880         return;
    881       }
    882       const size_t code_item_size = code_item->insns_size_in_code_units_;
    883       const uint16_t* code_ptr = code_item->insns_;
    884       const uint16_t* code_end = code_item->insns_ + code_item_size;
    885 
    886       // If we inserted a new dex code item pointer, add to total code bytes.
    887       if (dex_code_item_ptrs_.insert(code_ptr).second) {
    888         dex_code_bytes_ += code_item_size * sizeof(code_ptr[0]);
    889       }
    890 
    891       while (code_ptr < code_end) {
    892         const Instruction* inst = Instruction::At(code_ptr);
    893         switch (inst->Opcode()) {
    894           case Instruction::CONST_STRING: {
    895             const dex::StringIndex string_index(inst->VRegB_21c());
    896             unique_string_ids_from_code_.insert(StringReference(&dex_file, string_index));
    897             ++num_string_ids_from_code_;
    898             break;
    899           }
    900           case Instruction::CONST_STRING_JUMBO: {
    901             const dex::StringIndex string_index(inst->VRegB_31c());
    902             unique_string_ids_from_code_.insert(StringReference(&dex_file, string_index));
    903             ++num_string_ids_from_code_;
    904             break;
    905           }
    906           default:
    907             break;
    908         }
    909 
    910         code_ptr += inst->SizeInCodeUnits();
    911       }
    912     }
    913 
    914     // Unique string ids loaded from dex code.
    915     std::set<StringReference, StringReferenceComparator> unique_string_ids_from_code_;
    916 
    917     // Total string ids loaded from dex code.
    918     size_t num_string_ids_from_code_ = 0;
    919 
    920     // Unique code pointers.
    921     std::set<const void*> dex_code_item_ptrs_;
    922 
    923     // Total "unique" dex code bytes.
    924     size_t dex_code_bytes_ = 0;
    925 
    926     // Other dex ids.
    927     size_t num_string_ids_ = 0;
    928     size_t num_method_ids_ = 0;
    929     size_t num_field_ids_ = 0;
    930     size_t num_type_ids_ = 0;
    931     size_t num_class_defs_ = 0;
    932   };
    933 
    934   bool DumpOatDexFile(std::ostream& os, const OatFile::OatDexFile& oat_dex_file) {
    935     bool success = true;
    936     bool stop_analysis = false;
    937     os << "OatDexFile:\n";
    938     os << StringPrintf("location: %s\n", oat_dex_file.GetDexFileLocation().c_str());
    939     os << StringPrintf("checksum: 0x%08x\n", oat_dex_file.GetDexFileLocationChecksum());
    940 
    941     const uint8_t* const oat_file_begin = oat_dex_file.GetOatFile()->Begin();
    942     const uint8_t* const vdex_file_begin = oat_dex_file.GetOatFile()->DexBegin();
    943 
    944     // Print data range of the dex file embedded inside the corresponding vdex file.
    945     const uint8_t* const dex_file_pointer = oat_dex_file.GetDexFilePointer();
    946     uint32_t dex_offset = dchecked_integral_cast<uint32_t>(dex_file_pointer - vdex_file_begin);
    947     os << StringPrintf("dex-file: 0x%08x..0x%08x\n",
    948                        dex_offset,
    949                        dchecked_integral_cast<uint32_t>(dex_offset + oat_dex_file.FileSize() - 1));
    950 
    951     // Create the dex file early. A lot of print-out things depend on it.
    952     std::string error_msg;
    953     const DexFile* const dex_file = OpenDexFile(&oat_dex_file, &error_msg);
    954     if (dex_file == nullptr) {
    955       os << "NOT FOUND: " << error_msg << "\n\n";
    956       os << std::flush;
    957       return false;
    958     }
    959 
    960     // Print lookup table, if it exists.
    961     if (oat_dex_file.GetLookupTableData() != nullptr) {
    962       uint32_t table_offset = dchecked_integral_cast<uint32_t>(
    963           oat_dex_file.GetLookupTableData() - oat_file_begin);
    964       uint32_t table_size = TypeLookupTable::RawDataLength(dex_file->NumClassDefs());
    965       os << StringPrintf("type-table: 0x%08x..0x%08x\n",
    966                          table_offset,
    967                          table_offset + table_size - 1);
    968     }
    969 
    970     VariableIndentationOutputStream vios(&os);
    971     ScopedIndentation indent1(&vios);
    972     for (size_t class_def_index = 0;
    973          class_def_index < dex_file->NumClassDefs();
    974          class_def_index++) {
    975       const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
    976       const char* descriptor = dex_file->GetClassDescriptor(class_def);
    977 
    978       // TODO: Support regex
    979       if (DescriptorToDot(descriptor).find(options_.class_filter_) == std::string::npos) {
    980         continue;
    981       }
    982 
    983       uint32_t oat_class_offset = oat_dex_file.GetOatClassOffset(class_def_index);
    984       const OatFile::OatClass oat_class = oat_dex_file.GetOatClass(class_def_index);
    985       os << StringPrintf("%zd: %s (offset=0x%08x) (type_idx=%d)",
    986                          class_def_index, descriptor, oat_class_offset, class_def.class_idx_.index_)
    987          << " (" << oat_class.GetStatus() << ")"
    988          << " (" << oat_class.GetType() << ")\n";
    989       // TODO: include bitmap here if type is kOatClassSomeCompiled?
    990       if (options_.list_classes_) {
    991         continue;
    992       }
    993       if (!DumpOatClass(&vios, oat_class, *dex_file, class_def, &stop_analysis)) {
    994         success = false;
    995       }
    996       if (stop_analysis) {
    997         os << std::flush;
    998         return success;
    999       }
   1000     }
   1001     os << "\n";
   1002     os << std::flush;
   1003     return success;
   1004   }
   1005 
   1006   bool ExportDexFile(std::ostream& os, const OatFile::OatDexFile& oat_dex_file) {
   1007     std::string error_msg;
   1008     std::string dex_file_location = oat_dex_file.GetDexFileLocation();
   1009 
   1010     const DexFile* const dex_file = OpenDexFile(&oat_dex_file, &error_msg);
   1011     if (dex_file == nullptr) {
   1012       os << "Failed to open dex file '" << dex_file_location << "': " << error_msg;
   1013       return false;
   1014     }
   1015     size_t fsize = oat_dex_file.FileSize();
   1016 
   1017     // Some quick checks just in case
   1018     if (fsize == 0 || fsize < sizeof(DexFile::Header)) {
   1019       os << "Invalid dex file\n";
   1020       return false;
   1021     }
   1022 
   1023     // Verify output directory exists
   1024     if (!OS::DirectoryExists(options_.export_dex_location_)) {
   1025       // TODO: Extend OS::DirectoryExists if symlink support is required
   1026       os << options_.export_dex_location_ << " output directory not found or symlink\n";
   1027       return false;
   1028     }
   1029 
   1030     // Beautify path names
   1031     if (dex_file_location.size() > PATH_MAX || dex_file_location.size() <= 0) {
   1032       return false;
   1033     }
   1034 
   1035     std::string dex_orig_name;
   1036     size_t dex_orig_pos = dex_file_location.rfind('/');
   1037     if (dex_orig_pos == std::string::npos)
   1038       dex_orig_name = dex_file_location;
   1039     else
   1040       dex_orig_name = dex_file_location.substr(dex_orig_pos + 1);
   1041 
   1042     // A more elegant approach to efficiently name user installed apps is welcome
   1043     if (dex_orig_name.size() == 8 &&
   1044         dex_orig_name.compare("base.apk") == 0 &&
   1045         dex_orig_pos != std::string::npos) {
   1046       dex_file_location.erase(dex_orig_pos, strlen("base.apk") + 1);
   1047       size_t apk_orig_pos = dex_file_location.rfind('/');
   1048       if (apk_orig_pos != std::string::npos) {
   1049         dex_orig_name = dex_file_location.substr(++apk_orig_pos);
   1050       }
   1051     }
   1052 
   1053     std::string out_dex_path(options_.export_dex_location_);
   1054     if (out_dex_path.back() != '/') {
   1055       out_dex_path.append("/");
   1056     }
   1057     out_dex_path.append(dex_orig_name);
   1058     out_dex_path.append("_export.dex");
   1059     if (out_dex_path.length() > PATH_MAX) {
   1060       return false;
   1061     }
   1062 
   1063     std::unique_ptr<File> file(OS::CreateEmptyFile(out_dex_path.c_str()));
   1064     if (file.get() == nullptr) {
   1065       os << "Failed to open output dex file " << out_dex_path;
   1066       return false;
   1067     }
   1068 
   1069     if (!file->WriteFully(dex_file->Begin(), fsize)) {
   1070       os << "Failed to write dex file";
   1071       file->Erase();
   1072       return false;
   1073     }
   1074 
   1075     if (file->FlushCloseOrErase() != 0) {
   1076       os << "Flush and close failed";
   1077       return false;
   1078     }
   1079 
   1080     os << StringPrintf("Dex file exported at %s (%zd bytes)\n", out_dex_path.c_str(), fsize);
   1081     os << std::flush;
   1082 
   1083     return true;
   1084   }
   1085 
   1086   bool DumpOatClass(VariableIndentationOutputStream* vios,
   1087                     const OatFile::OatClass& oat_class, const DexFile& dex_file,
   1088                     const DexFile::ClassDef& class_def, bool* stop_analysis) {
   1089     bool success = true;
   1090     bool addr_found = false;
   1091     const uint8_t* class_data = dex_file.GetClassData(class_def);
   1092     if (class_data == nullptr) {  // empty class such as a marker interface?
   1093       vios->Stream() << std::flush;
   1094       return success;
   1095     }
   1096     ClassDataItemIterator it(dex_file, class_data);
   1097     it.SkipAllFields();
   1098     uint32_t class_method_index = 0;
   1099     while (it.HasNextDirectMethod()) {
   1100       if (!DumpOatMethod(vios, class_def, class_method_index, oat_class, dex_file,
   1101                          it.GetMemberIndex(), it.GetMethodCodeItem(),
   1102                          it.GetRawMemberAccessFlags(), &addr_found)) {
   1103         success = false;
   1104       }
   1105       if (addr_found) {
   1106         *stop_analysis = true;
   1107         return success;
   1108       }
   1109       class_method_index++;
   1110       it.Next();
   1111     }
   1112     while (it.HasNextVirtualMethod()) {
   1113       if (!DumpOatMethod(vios, class_def, class_method_index, oat_class, dex_file,
   1114                          it.GetMemberIndex(), it.GetMethodCodeItem(),
   1115                          it.GetRawMemberAccessFlags(), &addr_found)) {
   1116         success = false;
   1117       }
   1118       if (addr_found) {
   1119         *stop_analysis = true;
   1120         return success;
   1121       }
   1122       class_method_index++;
   1123       it.Next();
   1124     }
   1125     DCHECK(!it.HasNext());
   1126     vios->Stream() << std::flush;
   1127     return success;
   1128   }
   1129 
   1130   static constexpr uint32_t kPrologueBytes = 16;
   1131 
   1132   // When this was picked, the largest arm method was 55,256 bytes and arm64 was 50,412 bytes.
   1133   static constexpr uint32_t kMaxCodeSize = 100 * 1000;
   1134 
   1135   bool DumpOatMethod(VariableIndentationOutputStream* vios,
   1136                      const DexFile::ClassDef& class_def,
   1137                      uint32_t class_method_index,
   1138                      const OatFile::OatClass& oat_class, const DexFile& dex_file,
   1139                      uint32_t dex_method_idx, const DexFile::CodeItem* code_item,
   1140                      uint32_t method_access_flags, bool* addr_found) {
   1141     bool success = true;
   1142 
   1143     // TODO: Support regex
   1144     std::string method_name = dex_file.GetMethodName(dex_file.GetMethodId(dex_method_idx));
   1145     if (method_name.find(options_.method_filter_) == std::string::npos) {
   1146       return success;
   1147     }
   1148 
   1149     std::string pretty_method = dex_file.PrettyMethod(dex_method_idx, true);
   1150     vios->Stream() << StringPrintf("%d: %s (dex_method_idx=%d)\n",
   1151                                    class_method_index, pretty_method.c_str(),
   1152                                    dex_method_idx);
   1153     if (options_.list_methods_) return success;
   1154 
   1155     uint32_t oat_method_offsets_offset = oat_class.GetOatMethodOffsetsOffset(class_method_index);
   1156     const OatMethodOffsets* oat_method_offsets = oat_class.GetOatMethodOffsets(class_method_index);
   1157     const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_index);
   1158     uint32_t code_offset = oat_method.GetCodeOffset();
   1159     uint32_t code_size = oat_method.GetQuickCodeSize();
   1160     if (resolved_addr2instr_ != 0) {
   1161       if (resolved_addr2instr_ > code_offset + code_size) {
   1162         return success;
   1163       } else {
   1164         *addr_found = true;  // stop analyzing file at next iteration
   1165       }
   1166     }
   1167 
   1168     // Everything below is indented at least once.
   1169     ScopedIndentation indent1(vios);
   1170 
   1171     {
   1172       vios->Stream() << "DEX CODE:\n";
   1173       ScopedIndentation indent2(vios);
   1174       DumpDexCode(vios->Stream(), dex_file, code_item);
   1175     }
   1176 
   1177     std::unique_ptr<StackHandleScope<1>> hs;
   1178     std::unique_ptr<verifier::MethodVerifier> verifier;
   1179     if (Runtime::Current() != nullptr) {
   1180       // We need to have the handle scope stay live until after the verifier since the verifier has
   1181       // a handle to the dex cache from hs.
   1182       hs.reset(new StackHandleScope<1>(Thread::Current()));
   1183       vios->Stream() << "VERIFIER TYPE ANALYSIS:\n";
   1184       ScopedIndentation indent2(vios);
   1185       verifier.reset(DumpVerifier(vios, hs.get(),
   1186                                   dex_method_idx, &dex_file, class_def, code_item,
   1187                                   method_access_flags));
   1188     }
   1189     {
   1190       vios->Stream() << "OatMethodOffsets ";
   1191       if (options_.absolute_addresses_) {
   1192         vios->Stream() << StringPrintf("%p ", oat_method_offsets);
   1193       }
   1194       vios->Stream() << StringPrintf("(offset=0x%08x)\n", oat_method_offsets_offset);
   1195       if (oat_method_offsets_offset > oat_file_.Size()) {
   1196         vios->Stream() << StringPrintf(
   1197             "WARNING: oat method offsets offset 0x%08x is past end of file 0x%08zx.\n",
   1198             oat_method_offsets_offset, oat_file_.Size());
   1199         // If we can't read OatMethodOffsets, the rest of the data is dangerous to read.
   1200         vios->Stream() << std::flush;
   1201         return false;
   1202       }
   1203 
   1204       ScopedIndentation indent2(vios);
   1205       vios->Stream() << StringPrintf("code_offset: 0x%08x ", code_offset);
   1206       uint32_t aligned_code_begin = AlignCodeOffset(oat_method.GetCodeOffset());
   1207       if (aligned_code_begin > oat_file_.Size()) {
   1208         vios->Stream() << StringPrintf("WARNING: "
   1209                                        "code offset 0x%08x is past end of file 0x%08zx.\n",
   1210                                        aligned_code_begin, oat_file_.Size());
   1211         success = false;
   1212       }
   1213       vios->Stream() << "\n";
   1214     }
   1215     {
   1216       vios->Stream() << "OatQuickMethodHeader ";
   1217       uint32_t method_header_offset = oat_method.GetOatQuickMethodHeaderOffset();
   1218       const OatQuickMethodHeader* method_header = oat_method.GetOatQuickMethodHeader();
   1219       stats_.AddBitsIfUnique(Stats::kByteKindQuickMethodHeader,
   1220                              sizeof(*method_header) * kBitsPerByte,
   1221                              method_header);
   1222       if (options_.absolute_addresses_) {
   1223         vios->Stream() << StringPrintf("%p ", method_header);
   1224       }
   1225       vios->Stream() << StringPrintf("(offset=0x%08x)\n", method_header_offset);
   1226       if (method_header_offset > oat_file_.Size()) {
   1227         vios->Stream() << StringPrintf(
   1228             "WARNING: oat quick method header offset 0x%08x is past end of file 0x%08zx.\n",
   1229             method_header_offset, oat_file_.Size());
   1230         // If we can't read the OatQuickMethodHeader, the rest of the data is dangerous to read.
   1231         vios->Stream() << std::flush;
   1232         return false;
   1233       }
   1234 
   1235       ScopedIndentation indent2(vios);
   1236       vios->Stream() << "vmap_table: ";
   1237       if (options_.absolute_addresses_) {
   1238         vios->Stream() << StringPrintf("%p ", oat_method.GetVmapTable());
   1239       }
   1240       uint32_t vmap_table_offset = method_header ==
   1241           nullptr ? 0 : method_header->GetVmapTableOffset();
   1242       vios->Stream() << StringPrintf("(offset=0x%08x)\n", vmap_table_offset);
   1243 
   1244       size_t vmap_table_offset_limit =
   1245           (kIsVdexEnabled && IsMethodGeneratedByDexToDexCompiler(oat_method, code_item))
   1246               ? oat_file_.GetVdexFile()->Size()
   1247               : method_header->GetCode() - oat_file_.Begin();
   1248       if (vmap_table_offset >= vmap_table_offset_limit) {
   1249         vios->Stream() << StringPrintf("WARNING: "
   1250                                        "vmap table offset 0x%08x is past end of file 0x%08zx. "
   1251                                        "vmap table offset was loaded from offset 0x%08x.\n",
   1252                                        vmap_table_offset,
   1253                                        vmap_table_offset_limit,
   1254                                        oat_method.GetVmapTableOffsetOffset());
   1255         success = false;
   1256       } else if (options_.dump_vmap_) {
   1257         DumpVmapData(vios, oat_method, code_item);
   1258       }
   1259     }
   1260     {
   1261       vios->Stream() << "QuickMethodFrameInfo\n";
   1262 
   1263       ScopedIndentation indent2(vios);
   1264       vios->Stream()
   1265           << StringPrintf("frame_size_in_bytes: %zd\n", oat_method.GetFrameSizeInBytes());
   1266       vios->Stream() << StringPrintf("core_spill_mask: 0x%08x ", oat_method.GetCoreSpillMask());
   1267       DumpSpillMask(vios->Stream(), oat_method.GetCoreSpillMask(), false);
   1268       vios->Stream() << "\n";
   1269       vios->Stream() << StringPrintf("fp_spill_mask: 0x%08x ", oat_method.GetFpSpillMask());
   1270       DumpSpillMask(vios->Stream(), oat_method.GetFpSpillMask(), true);
   1271       vios->Stream() << "\n";
   1272     }
   1273     {
   1274       // Based on spill masks from QuickMethodFrameInfo so placed
   1275       // after it is dumped, but useful for understanding quick
   1276       // code, so dumped here.
   1277       ScopedIndentation indent2(vios);
   1278       DumpVregLocations(vios->Stream(), oat_method, code_item);
   1279     }
   1280     {
   1281       vios->Stream() << "CODE: ";
   1282       uint32_t code_size_offset = oat_method.GetQuickCodeSizeOffset();
   1283       if (code_size_offset > oat_file_.Size()) {
   1284         ScopedIndentation indent2(vios);
   1285         vios->Stream() << StringPrintf("WARNING: "
   1286                                        "code size offset 0x%08x is past end of file 0x%08zx.",
   1287                                        code_size_offset, oat_file_.Size());
   1288         success = false;
   1289       } else {
   1290         const void* code = oat_method.GetQuickCode();
   1291         uint32_t aligned_code_begin = AlignCodeOffset(code_offset);
   1292         uint64_t aligned_code_end = aligned_code_begin + code_size;
   1293         stats_.AddBitsIfUnique(Stats::kByteKindCode, code_size * kBitsPerByte, code);
   1294 
   1295         if (options_.absolute_addresses_) {
   1296           vios->Stream() << StringPrintf("%p ", code);
   1297         }
   1298         vios->Stream() << StringPrintf("(code_offset=0x%08x size_offset=0x%08x size=%u)%s\n",
   1299                                        code_offset,
   1300                                        code_size_offset,
   1301                                        code_size,
   1302                                        code != nullptr ? "..." : "");
   1303 
   1304         ScopedIndentation indent2(vios);
   1305         if (aligned_code_begin > oat_file_.Size()) {
   1306           vios->Stream() << StringPrintf("WARNING: "
   1307                                          "start of code at 0x%08x is past end of file 0x%08zx.",
   1308                                          aligned_code_begin, oat_file_.Size());
   1309           success = false;
   1310         } else if (aligned_code_end > oat_file_.Size()) {
   1311           vios->Stream() << StringPrintf(
   1312               "WARNING: "
   1313               "end of code at 0x%08" PRIx64 " is past end of file 0x%08zx. "
   1314               "code size is 0x%08x loaded from offset 0x%08x.\n",
   1315               aligned_code_end, oat_file_.Size(),
   1316               code_size, code_size_offset);
   1317           success = false;
   1318           if (options_.disassemble_code_) {
   1319             if (code_size_offset + kPrologueBytes <= oat_file_.Size()) {
   1320               DumpCode(vios, oat_method, code_item, true, kPrologueBytes);
   1321             }
   1322           }
   1323         } else if (code_size > kMaxCodeSize) {
   1324           vios->Stream() << StringPrintf(
   1325               "WARNING: "
   1326               "code size %d is bigger than max expected threshold of %d. "
   1327               "code size is 0x%08x loaded from offset 0x%08x.\n",
   1328               code_size, kMaxCodeSize,
   1329               code_size, code_size_offset);
   1330           success = false;
   1331           if (options_.disassemble_code_) {
   1332             if (code_size_offset + kPrologueBytes <= oat_file_.Size()) {
   1333               DumpCode(vios, oat_method, code_item, true, kPrologueBytes);
   1334             }
   1335           }
   1336         } else if (options_.disassemble_code_) {
   1337           DumpCode(vios, oat_method, code_item, !success, 0);
   1338         }
   1339       }
   1340     }
   1341     vios->Stream() << std::flush;
   1342     return success;
   1343   }
   1344 
   1345   void DumpSpillMask(std::ostream& os, uint32_t spill_mask, bool is_float) {
   1346     if (spill_mask == 0) {
   1347       return;
   1348     }
   1349     os << "(";
   1350     for (size_t i = 0; i < 32; i++) {
   1351       if ((spill_mask & (1 << i)) != 0) {
   1352         if (is_float) {
   1353           os << "fr" << i;
   1354         } else {
   1355           os << "r" << i;
   1356         }
   1357         spill_mask ^= 1 << i;  // clear bit
   1358         if (spill_mask != 0) {
   1359           os << ", ";
   1360         } else {
   1361           break;
   1362         }
   1363       }
   1364     }
   1365     os << ")";
   1366   }
   1367 
   1368   // Display data stored at the the vmap offset of an oat method.
   1369   void DumpVmapData(VariableIndentationOutputStream* vios,
   1370                     const OatFile::OatMethod& oat_method,
   1371                     const DexFile::CodeItem* code_item) {
   1372     if (IsMethodGeneratedByOptimizingCompiler(oat_method, code_item)) {
   1373       // The optimizing compiler outputs its CodeInfo data in the vmap table.
   1374       const void* raw_code_info = oat_method.GetVmapTable();
   1375       if (raw_code_info != nullptr) {
   1376         CodeInfo code_info(raw_code_info);
   1377         DCHECK(code_item != nullptr);
   1378         ScopedIndentation indent1(vios);
   1379         MethodInfo method_info = oat_method.GetOatQuickMethodHeader()->GetOptimizedMethodInfo();
   1380         DumpCodeInfo(vios, code_info, oat_method, *code_item, method_info);
   1381       }
   1382     } else if (IsMethodGeneratedByDexToDexCompiler(oat_method, code_item)) {
   1383       // We don't encode the size in the table, so just emit that we have quickened
   1384       // information.
   1385       ScopedIndentation indent(vios);
   1386       vios->Stream() << "quickened data\n";
   1387     } else {
   1388       // Otherwise, there is nothing to display.
   1389     }
   1390   }
   1391 
   1392   // Display a CodeInfo object emitted by the optimizing compiler.
   1393   void DumpCodeInfo(VariableIndentationOutputStream* vios,
   1394                     const CodeInfo& code_info,
   1395                     const OatFile::OatMethod& oat_method,
   1396                     const DexFile::CodeItem& code_item,
   1397                     const MethodInfo& method_info) {
   1398     code_info.Dump(vios,
   1399                    oat_method.GetCodeOffset(),
   1400                    code_item.registers_size_,
   1401                    options_.dump_code_info_stack_maps_,
   1402                    instruction_set_,
   1403                    method_info);
   1404   }
   1405 
   1406   static int GetOutVROffset(uint16_t out_num, InstructionSet isa) {
   1407     // According to stack model, the first out is above the Method referernce.
   1408     return static_cast<size_t>(InstructionSetPointerSize(isa)) + out_num * sizeof(uint32_t);
   1409   }
   1410 
   1411   static uint32_t GetVRegOffsetFromQuickCode(const DexFile::CodeItem* code_item,
   1412                                              uint32_t core_spills,
   1413                                              uint32_t fp_spills,
   1414                                              size_t frame_size,
   1415                                              int reg,
   1416                                              InstructionSet isa) {
   1417     PointerSize pointer_size = InstructionSetPointerSize(isa);
   1418     if (kIsDebugBuild) {
   1419       auto* runtime = Runtime::Current();
   1420       if (runtime != nullptr) {
   1421         CHECK_EQ(runtime->GetClassLinker()->GetImagePointerSize(), pointer_size);
   1422       }
   1423     }
   1424     DCHECK_ALIGNED(frame_size, kStackAlignment);
   1425     DCHECK_NE(reg, -1);
   1426     int spill_size = POPCOUNT(core_spills) * GetBytesPerGprSpillLocation(isa)
   1427         + POPCOUNT(fp_spills) * GetBytesPerFprSpillLocation(isa)
   1428         + sizeof(uint32_t);  // Filler.
   1429     int num_regs = code_item->registers_size_ - code_item->ins_size_;
   1430     int temp_threshold = code_item->registers_size_;
   1431     const int max_num_special_temps = 1;
   1432     if (reg == temp_threshold) {
   1433       // The current method pointer corresponds to special location on stack.
   1434       return 0;
   1435     } else if (reg >= temp_threshold + max_num_special_temps) {
   1436       /*
   1437        * Special temporaries may have custom locations and the logic above deals with that.
   1438        * However, non-special temporaries are placed relative to the outs.
   1439        */
   1440       int temps_start = code_item->outs_size_ * sizeof(uint32_t)
   1441           + static_cast<size_t>(pointer_size) /* art method */;
   1442       int relative_offset = (reg - (temp_threshold + max_num_special_temps)) * sizeof(uint32_t);
   1443       return temps_start + relative_offset;
   1444     } else if (reg < num_regs) {
   1445       int locals_start = frame_size - spill_size - num_regs * sizeof(uint32_t);
   1446       return locals_start + (reg * sizeof(uint32_t));
   1447     } else {
   1448       // Handle ins.
   1449       return frame_size + ((reg - num_regs) * sizeof(uint32_t))
   1450           + static_cast<size_t>(pointer_size) /* art method */;
   1451     }
   1452   }
   1453 
   1454   void DumpVregLocations(std::ostream& os, const OatFile::OatMethod& oat_method,
   1455                          const DexFile::CodeItem* code_item) {
   1456     if (code_item != nullptr) {
   1457       size_t num_locals_ins = code_item->registers_size_;
   1458       size_t num_ins = code_item->ins_size_;
   1459       size_t num_locals = num_locals_ins - num_ins;
   1460       size_t num_outs = code_item->outs_size_;
   1461 
   1462       os << "vr_stack_locations:";
   1463       for (size_t reg = 0; reg <= num_locals_ins; reg++) {
   1464         // For readability, delimit the different kinds of VRs.
   1465         if (reg == num_locals_ins) {
   1466           os << "\n\tmethod*:";
   1467         } else if (reg == num_locals && num_ins > 0) {
   1468           os << "\n\tins:";
   1469         } else if (reg == 0 && num_locals > 0) {
   1470           os << "\n\tlocals:";
   1471         }
   1472 
   1473         uint32_t offset = GetVRegOffsetFromQuickCode(code_item,
   1474                                                      oat_method.GetCoreSpillMask(),
   1475                                                      oat_method.GetFpSpillMask(),
   1476                                                      oat_method.GetFrameSizeInBytes(),
   1477                                                      reg,
   1478                                                      GetInstructionSet());
   1479         os << " v" << reg << "[sp + #" << offset << "]";
   1480       }
   1481 
   1482       for (size_t out_reg = 0; out_reg < num_outs; out_reg++) {
   1483         if (out_reg == 0) {
   1484           os << "\n\touts:";
   1485         }
   1486 
   1487         uint32_t offset = GetOutVROffset(out_reg, GetInstructionSet());
   1488         os << " v" << out_reg << "[sp + #" << offset << "]";
   1489       }
   1490 
   1491       os << "\n";
   1492     }
   1493   }
   1494 
   1495   void DumpDexCode(std::ostream& os, const DexFile& dex_file, const DexFile::CodeItem* code_item) {
   1496     if (code_item != nullptr) {
   1497       size_t i = 0;
   1498       while (i < code_item->insns_size_in_code_units_) {
   1499         const Instruction* instruction = Instruction::At(&code_item->insns_[i]);
   1500         os << StringPrintf("0x%04zx: ", i) << instruction->DumpHexLE(5)
   1501            << StringPrintf("\t| %s\n", instruction->DumpString(&dex_file).c_str());
   1502         i += instruction->SizeInCodeUnits();
   1503       }
   1504     }
   1505   }
   1506 
   1507   // Has `oat_method` -- corresponding to the Dex `code_item` -- been compiled by
   1508   // the optimizing compiler?
   1509   static bool IsMethodGeneratedByOptimizingCompiler(const OatFile::OatMethod& oat_method,
   1510                                                     const DexFile::CodeItem* code_item) {
   1511     // If the native GC map is null and the Dex `code_item` is not
   1512     // null, then this method has been compiled with the optimizing
   1513     // compiler.
   1514     return oat_method.GetQuickCode() != nullptr &&
   1515            oat_method.GetVmapTable() != nullptr &&
   1516            code_item != nullptr;
   1517   }
   1518 
   1519   // Has `oat_method` -- corresponding to the Dex `code_item` -- been compiled by
   1520   // the dextodex compiler?
   1521   static bool IsMethodGeneratedByDexToDexCompiler(const OatFile::OatMethod& oat_method,
   1522                                                   const DexFile::CodeItem* code_item) {
   1523     // If the quick code is null, the Dex `code_item` is not
   1524     // null, and the vmap table is not null, then this method has been compiled
   1525     // with the dextodex compiler.
   1526     return oat_method.GetQuickCode() == nullptr &&
   1527            oat_method.GetVmapTable() != nullptr &&
   1528            code_item != nullptr;
   1529   }
   1530 
   1531   verifier::MethodVerifier* DumpVerifier(VariableIndentationOutputStream* vios,
   1532                                          StackHandleScope<1>* hs,
   1533                                          uint32_t dex_method_idx,
   1534                                          const DexFile* dex_file,
   1535                                          const DexFile::ClassDef& class_def,
   1536                                          const DexFile::CodeItem* code_item,
   1537                                          uint32_t method_access_flags) {
   1538     if ((method_access_flags & kAccNative) == 0) {
   1539       ScopedObjectAccess soa(Thread::Current());
   1540       Runtime* const runtime = Runtime::Current();
   1541       Handle<mirror::DexCache> dex_cache(
   1542           hs->NewHandle(runtime->GetClassLinker()->RegisterDexFile(*dex_file, nullptr)));
   1543       CHECK(dex_cache != nullptr);
   1544       DCHECK(options_.class_loader_ != nullptr);
   1545       return verifier::MethodVerifier::VerifyMethodAndDump(
   1546           soa.Self(), vios, dex_method_idx, dex_file, dex_cache, *options_.class_loader_,
   1547           class_def, code_item, nullptr, method_access_flags);
   1548     }
   1549 
   1550     return nullptr;
   1551   }
   1552 
   1553   // The StackMapsHelper provides the stack maps in the native PC order.
   1554   // For identical native PCs, the order from the CodeInfo is preserved.
   1555   class StackMapsHelper {
   1556    public:
   1557     explicit StackMapsHelper(const uint8_t* raw_code_info, InstructionSet instruction_set)
   1558         : code_info_(raw_code_info),
   1559           encoding_(code_info_.ExtractEncoding()),
   1560           number_of_stack_maps_(code_info_.GetNumberOfStackMaps(encoding_)),
   1561           indexes_(),
   1562           offset_(static_cast<uint32_t>(-1)),
   1563           stack_map_index_(0u),
   1564           instruction_set_(instruction_set) {
   1565       if (number_of_stack_maps_ != 0u) {
   1566         // Check if native PCs are ordered.
   1567         bool ordered = true;
   1568         StackMap last = code_info_.GetStackMapAt(0u, encoding_);
   1569         for (size_t i = 1; i != number_of_stack_maps_; ++i) {
   1570           StackMap current = code_info_.GetStackMapAt(i, encoding_);
   1571           if (last.GetNativePcOffset(encoding_.stack_map.encoding, instruction_set) >
   1572               current.GetNativePcOffset(encoding_.stack_map.encoding, instruction_set)) {
   1573             ordered = false;
   1574             break;
   1575           }
   1576           last = current;
   1577         }
   1578         if (!ordered) {
   1579           // Create indirection indexes for access in native PC order. We do not optimize
   1580           // for the fact that there can currently be only two separately ordered ranges,
   1581           // namely normal stack maps and catch-point stack maps.
   1582           indexes_.resize(number_of_stack_maps_);
   1583           std::iota(indexes_.begin(), indexes_.end(), 0u);
   1584           std::sort(indexes_.begin(),
   1585                     indexes_.end(),
   1586                     [this](size_t lhs, size_t rhs) {
   1587                       StackMap left = code_info_.GetStackMapAt(lhs, encoding_);
   1588                       uint32_t left_pc = left.GetNativePcOffset(encoding_.stack_map.encoding,
   1589                                                                 instruction_set_);
   1590                       StackMap right = code_info_.GetStackMapAt(rhs, encoding_);
   1591                       uint32_t right_pc = right.GetNativePcOffset(encoding_.stack_map.encoding,
   1592                                                                   instruction_set_);
   1593                       // If the PCs are the same, compare indexes to preserve the original order.
   1594                       return (left_pc < right_pc) || (left_pc == right_pc && lhs < rhs);
   1595                     });
   1596         }
   1597         offset_ = GetStackMapAt(0).GetNativePcOffset(encoding_.stack_map.encoding,
   1598                                                      instruction_set_);
   1599       }
   1600     }
   1601 
   1602     const CodeInfo& GetCodeInfo() const {
   1603       return code_info_;
   1604     }
   1605 
   1606     const CodeInfoEncoding& GetEncoding() const {
   1607       return encoding_;
   1608     }
   1609 
   1610     uint32_t GetOffset() const {
   1611       return offset_;
   1612     }
   1613 
   1614     StackMap GetStackMap() const {
   1615       return GetStackMapAt(stack_map_index_);
   1616     }
   1617 
   1618     void Next() {
   1619       ++stack_map_index_;
   1620       offset_ = (stack_map_index_ == number_of_stack_maps_)
   1621           ? static_cast<uint32_t>(-1)
   1622           : GetStackMapAt(stack_map_index_).GetNativePcOffset(encoding_.stack_map.encoding,
   1623                                                               instruction_set_);
   1624     }
   1625 
   1626    private:
   1627     StackMap GetStackMapAt(size_t i) const {
   1628       if (!indexes_.empty()) {
   1629         i = indexes_[i];
   1630       }
   1631       DCHECK_LT(i, number_of_stack_maps_);
   1632       return code_info_.GetStackMapAt(i, encoding_);
   1633     }
   1634 
   1635     const CodeInfo code_info_;
   1636     const CodeInfoEncoding encoding_;
   1637     const size_t number_of_stack_maps_;
   1638     dchecked_vector<size_t> indexes_;  // Used if stack map native PCs are not ordered.
   1639     uint32_t offset_;
   1640     size_t stack_map_index_;
   1641     const InstructionSet instruction_set_;
   1642   };
   1643 
   1644   void DumpCode(VariableIndentationOutputStream* vios,
   1645                 const OatFile::OatMethod& oat_method, const DexFile::CodeItem* code_item,
   1646                 bool bad_input, size_t code_size) {
   1647     const void* quick_code = oat_method.GetQuickCode();
   1648 
   1649     if (code_size == 0) {
   1650       code_size = oat_method.GetQuickCodeSize();
   1651     }
   1652     if (code_size == 0 || quick_code == nullptr) {
   1653       vios->Stream() << "NO CODE!\n";
   1654       return;
   1655     } else if (!bad_input && IsMethodGeneratedByOptimizingCompiler(oat_method, code_item)) {
   1656       // The optimizing compiler outputs its CodeInfo data in the vmap table.
   1657       StackMapsHelper helper(oat_method.GetVmapTable(), instruction_set_);
   1658       MethodInfo method_info(oat_method.GetOatQuickMethodHeader()->GetOptimizedMethodInfo());
   1659       {
   1660         CodeInfoEncoding encoding(helper.GetEncoding());
   1661         StackMapEncoding stack_map_encoding(encoding.stack_map.encoding);
   1662         const size_t num_stack_maps = encoding.stack_map.num_entries;
   1663         if (stats_.AddBitsIfUnique(Stats::kByteKindCodeInfoEncoding,
   1664                                    encoding.HeaderSize() * kBitsPerByte,
   1665                                    oat_method.GetVmapTable())) {
   1666           // Stack maps
   1667           stats_.AddBits(
   1668               Stats::kByteKindStackMapNativePc,
   1669               stack_map_encoding.GetNativePcEncoding().BitSize() * num_stack_maps);
   1670           stats_.AddBits(
   1671               Stats::kByteKindStackMapDexPc,
   1672               stack_map_encoding.GetDexPcEncoding().BitSize() * num_stack_maps);
   1673           stats_.AddBits(
   1674               Stats::kByteKindStackMapDexRegisterMap,
   1675               stack_map_encoding.GetDexRegisterMapEncoding().BitSize() * num_stack_maps);
   1676           stats_.AddBits(
   1677               Stats::kByteKindStackMapInlineInfoIndex,
   1678               stack_map_encoding.GetInlineInfoEncoding().BitSize() * num_stack_maps);
   1679           stats_.AddBits(
   1680               Stats::kByteKindStackMapRegisterMaskIndex,
   1681               stack_map_encoding.GetRegisterMaskIndexEncoding().BitSize() * num_stack_maps);
   1682           stats_.AddBits(
   1683               Stats::kByteKindStackMapStackMaskIndex,
   1684               stack_map_encoding.GetStackMaskIndexEncoding().BitSize() * num_stack_maps);
   1685 
   1686           // Stack masks
   1687           stats_.AddBits(
   1688               Stats::kByteKindCodeInfoStackMasks,
   1689               encoding.stack_mask.encoding.BitSize() * encoding.stack_mask.num_entries);
   1690 
   1691           // Register masks
   1692           stats_.AddBits(
   1693               Stats::kByteKindCodeInfoRegisterMasks,
   1694               encoding.register_mask.encoding.BitSize() * encoding.register_mask.num_entries);
   1695 
   1696           // Invoke infos
   1697           if (encoding.invoke_info.num_entries > 0u) {
   1698             stats_.AddBits(
   1699                 Stats::kByteKindCodeInfoInvokeInfo,
   1700                 encoding.invoke_info.encoding.BitSize() * encoding.invoke_info.num_entries);
   1701           }
   1702 
   1703           // Location catalog
   1704           const size_t location_catalog_bytes =
   1705               helper.GetCodeInfo().GetDexRegisterLocationCatalogSize(encoding);
   1706           stats_.AddBits(Stats::kByteKindCodeInfoLocationCatalog,
   1707                          kBitsPerByte * location_catalog_bytes);
   1708           // Dex register bytes.
   1709           const size_t dex_register_bytes =
   1710               helper.GetCodeInfo().GetDexRegisterMapsSize(encoding, code_item->registers_size_);
   1711           stats_.AddBits(
   1712               Stats::kByteKindCodeInfoDexRegisterMap,
   1713               kBitsPerByte * dex_register_bytes);
   1714 
   1715           // Inline infos.
   1716           const size_t num_inline_infos = encoding.inline_info.num_entries;
   1717           if (num_inline_infos > 0u) {
   1718             stats_.AddBits(
   1719                 Stats::kByteKindInlineInfoMethodIndexIdx,
   1720                 encoding.inline_info.encoding.GetMethodIndexIdxEncoding().BitSize() *
   1721                     num_inline_infos);
   1722             stats_.AddBits(
   1723                 Stats::kByteKindInlineInfoDexPc,
   1724                 encoding.inline_info.encoding.GetDexPcEncoding().BitSize() * num_inline_infos);
   1725             stats_.AddBits(
   1726                 Stats::kByteKindInlineInfoExtraData,
   1727                 encoding.inline_info.encoding.GetExtraDataEncoding().BitSize() * num_inline_infos);
   1728             stats_.AddBits(
   1729                 Stats::kByteKindInlineInfoDexRegisterMap,
   1730                 encoding.inline_info.encoding.GetDexRegisterMapEncoding().BitSize() *
   1731                     num_inline_infos);
   1732             stats_.AddBits(Stats::kByteKindInlineInfoIsLast, num_inline_infos);
   1733           }
   1734         }
   1735       }
   1736       const uint8_t* quick_native_pc = reinterpret_cast<const uint8_t*>(quick_code);
   1737       size_t offset = 0;
   1738       while (offset < code_size) {
   1739         offset += disassembler_->Dump(vios->Stream(), quick_native_pc + offset);
   1740         if (offset == helper.GetOffset()) {
   1741           ScopedIndentation indent1(vios);
   1742           StackMap stack_map = helper.GetStackMap();
   1743           DCHECK(stack_map.IsValid());
   1744           stack_map.Dump(vios,
   1745                          helper.GetCodeInfo(),
   1746                          helper.GetEncoding(),
   1747                          method_info,
   1748                          oat_method.GetCodeOffset(),
   1749                          code_item->registers_size_,
   1750                          instruction_set_);
   1751           do {
   1752             helper.Next();
   1753             // There may be multiple stack maps at a given PC. We display only the first one.
   1754           } while (offset == helper.GetOffset());
   1755         }
   1756         DCHECK_LT(offset, helper.GetOffset());
   1757       }
   1758     } else {
   1759       const uint8_t* quick_native_pc = reinterpret_cast<const uint8_t*>(quick_code);
   1760       size_t offset = 0;
   1761       while (offset < code_size) {
   1762         offset += disassembler_->Dump(vios->Stream(), quick_native_pc + offset);
   1763       }
   1764     }
   1765   }
   1766 
   1767   const OatFile& oat_file_;
   1768   const std::vector<const OatFile::OatDexFile*> oat_dex_files_;
   1769   const OatDumperOptions& options_;
   1770   uint32_t resolved_addr2instr_;
   1771   const InstructionSet instruction_set_;
   1772   std::set<uintptr_t> offsets_;
   1773   Disassembler* disassembler_;
   1774   Stats stats_;
   1775 };
   1776 
   1777 class ImageDumper {
   1778  public:
   1779   ImageDumper(std::ostream* os,
   1780               gc::space::ImageSpace& image_space,
   1781               const ImageHeader& image_header,
   1782               OatDumperOptions* oat_dumper_options)
   1783       : os_(os),
   1784         vios_(os),
   1785         indent1_(&vios_),
   1786         image_space_(image_space),
   1787         image_header_(image_header),
   1788         oat_dumper_options_(oat_dumper_options) {}
   1789 
   1790   bool Dump() REQUIRES_SHARED(Locks::mutator_lock_) {
   1791     std::ostream& os = *os_;
   1792     std::ostream& indent_os = vios_.Stream();
   1793 
   1794     os << "MAGIC: " << image_header_.GetMagic() << "\n\n";
   1795 
   1796     os << "IMAGE LOCATION: " << image_space_.GetImageLocation() << "\n\n";
   1797 
   1798     os << "IMAGE BEGIN: " << reinterpret_cast<void*>(image_header_.GetImageBegin()) << "\n\n";
   1799 
   1800     os << "IMAGE SIZE: " << image_header_.GetImageSize() << "\n\n";
   1801 
   1802     for (size_t i = 0; i < ImageHeader::kSectionCount; ++i) {
   1803       auto section = static_cast<ImageHeader::ImageSections>(i);
   1804       os << "IMAGE SECTION " << section << ": " << image_header_.GetImageSection(section) << "\n\n";
   1805     }
   1806 
   1807     os << "OAT CHECKSUM: " << StringPrintf("0x%08x\n\n", image_header_.GetOatChecksum());
   1808 
   1809     os << "OAT FILE BEGIN:" << reinterpret_cast<void*>(image_header_.GetOatFileBegin()) << "\n\n";
   1810 
   1811     os << "OAT DATA BEGIN:" << reinterpret_cast<void*>(image_header_.GetOatDataBegin()) << "\n\n";
   1812 
   1813     os << "OAT DATA END:" << reinterpret_cast<void*>(image_header_.GetOatDataEnd()) << "\n\n";
   1814 
   1815     os << "OAT FILE END:" << reinterpret_cast<void*>(image_header_.GetOatFileEnd()) << "\n\n";
   1816 
   1817     os << "PATCH DELTA:" << image_header_.GetPatchDelta() << "\n\n";
   1818 
   1819     os << "COMPILE PIC: " << (image_header_.CompilePic() ? "yes" : "no") << "\n\n";
   1820 
   1821     {
   1822       os << "ROOTS: " << reinterpret_cast<void*>(image_header_.GetImageRoots()) << "\n";
   1823       static_assert(arraysize(image_roots_descriptions_) ==
   1824           static_cast<size_t>(ImageHeader::kImageRootsMax), "sizes must match");
   1825       DCHECK_LE(image_header_.GetImageRoots()->GetLength(), ImageHeader::kImageRootsMax);
   1826       for (int32_t i = 0, size = image_header_.GetImageRoots()->GetLength(); i != size; ++i) {
   1827         ImageHeader::ImageRoot image_root = static_cast<ImageHeader::ImageRoot>(i);
   1828         const char* image_root_description = image_roots_descriptions_[i];
   1829         mirror::Object* image_root_object = image_header_.GetImageRoot(image_root);
   1830         indent_os << StringPrintf("%s: %p\n", image_root_description, image_root_object);
   1831         if (image_root_object != nullptr && image_root_object->IsObjectArray()) {
   1832           mirror::ObjectArray<mirror::Object>* image_root_object_array
   1833               = image_root_object->AsObjectArray<mirror::Object>();
   1834           ScopedIndentation indent2(&vios_);
   1835           for (int j = 0; j < image_root_object_array->GetLength(); j++) {
   1836             mirror::Object* value = image_root_object_array->Get(j);
   1837             size_t run = 0;
   1838             for (int32_t k = j + 1; k < image_root_object_array->GetLength(); k++) {
   1839               if (value == image_root_object_array->Get(k)) {
   1840                 run++;
   1841               } else {
   1842                 break;
   1843               }
   1844             }
   1845             if (run == 0) {
   1846               indent_os << StringPrintf("%d: ", j);
   1847             } else {
   1848               indent_os << StringPrintf("%d to %zd: ", j, j + run);
   1849               j = j + run;
   1850             }
   1851             if (value != nullptr) {
   1852               PrettyObjectValue(indent_os, value->GetClass(), value);
   1853             } else {
   1854               indent_os << j << ": null\n";
   1855             }
   1856           }
   1857         }
   1858       }
   1859     }
   1860 
   1861     {
   1862       os << "METHOD ROOTS\n";
   1863       static_assert(arraysize(image_methods_descriptions_) ==
   1864           static_cast<size_t>(ImageHeader::kImageMethodsCount), "sizes must match");
   1865       for (int i = 0; i < ImageHeader::kImageMethodsCount; i++) {
   1866         auto image_root = static_cast<ImageHeader::ImageMethod>(i);
   1867         const char* description = image_methods_descriptions_[i];
   1868         auto* image_method = image_header_.GetImageMethod(image_root);
   1869         indent_os << StringPrintf("%s: %p\n", description, image_method);
   1870       }
   1871     }
   1872     os << "\n";
   1873 
   1874     Runtime* const runtime = Runtime::Current();
   1875     ClassLinker* class_linker = runtime->GetClassLinker();
   1876     std::string image_filename = image_space_.GetImageFilename();
   1877     std::string oat_location = ImageHeader::GetOatLocationFromImageLocation(image_filename);
   1878     os << "OAT LOCATION: " << oat_location;
   1879     os << "\n";
   1880     std::string error_msg;
   1881     const OatFile* oat_file = image_space_.GetOatFile();
   1882     if (oat_file == nullptr) {
   1883       oat_file = runtime->GetOatFileManager().FindOpenedOatFileFromOatLocation(oat_location);
   1884     }
   1885     if (oat_file == nullptr) {
   1886       oat_file = OatFile::Open(oat_location,
   1887                                oat_location,
   1888                                nullptr,
   1889                                nullptr,
   1890                                false,
   1891                                /*low_4gb*/false,
   1892                                nullptr,
   1893                                &error_msg);
   1894     }
   1895     if (oat_file == nullptr) {
   1896       os << "OAT FILE NOT FOUND: " << error_msg << "\n";
   1897       return EXIT_FAILURE;
   1898     }
   1899     os << "\n";
   1900 
   1901     stats_.oat_file_bytes = oat_file->Size();
   1902 
   1903     oat_dumper_.reset(new OatDumper(*oat_file, *oat_dumper_options_));
   1904 
   1905     for (const OatFile::OatDexFile* oat_dex_file : oat_file->GetOatDexFiles()) {
   1906       CHECK(oat_dex_file != nullptr);
   1907       stats_.oat_dex_file_sizes.push_back(std::make_pair(oat_dex_file->GetDexFileLocation(),
   1908                                                          oat_dex_file->FileSize()));
   1909     }
   1910 
   1911     os << "OBJECTS:\n" << std::flush;
   1912 
   1913     // Loop through the image space and dump its objects.
   1914     gc::Heap* heap = runtime->GetHeap();
   1915     Thread* self = Thread::Current();
   1916     {
   1917       {
   1918         WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
   1919         heap->FlushAllocStack();
   1920       }
   1921       // Since FlushAllocStack() above resets the (active) allocation
   1922       // stack. Need to revoke the thread-local allocation stacks that
   1923       // point into it.
   1924       ScopedThreadSuspension sts(self, kNative);
   1925       ScopedSuspendAll ssa(__FUNCTION__);
   1926       heap->RevokeAllThreadLocalAllocationStacks(self);
   1927     }
   1928     {
   1929       // Mark dex caches.
   1930       dex_caches_.clear();
   1931       {
   1932         ReaderMutexLock mu(self, *Locks::dex_lock_);
   1933         for (const ClassLinker::DexCacheData& data : class_linker->GetDexCachesData()) {
   1934           ObjPtr<mirror::DexCache> dex_cache =
   1935               ObjPtr<mirror::DexCache>::DownCast(self->DecodeJObject(data.weak_root));
   1936           if (dex_cache != nullptr) {
   1937             dex_caches_.insert(dex_cache.Ptr());
   1938           }
   1939         }
   1940       }
   1941       auto dump_visitor = [&](mirror::Object* obj) REQUIRES_SHARED(Locks::mutator_lock_) {
   1942         DumpObject(obj);
   1943       };
   1944       ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
   1945       // Dump the normal objects before ArtMethods.
   1946       image_space_.GetLiveBitmap()->Walk(dump_visitor);
   1947       indent_os << "\n";
   1948       // TODO: Dump fields.
   1949       // Dump methods after.
   1950       DumpArtMethodVisitor visitor(this);
   1951       image_header_.VisitPackedArtMethods(&visitor,
   1952                                           image_space_.Begin(),
   1953                                           image_header_.GetPointerSize());
   1954       // Dump the large objects separately.
   1955       heap->GetLargeObjectsSpace()->GetLiveBitmap()->Walk(dump_visitor);
   1956       indent_os << "\n";
   1957     }
   1958     os << "STATS:\n" << std::flush;
   1959     std::unique_ptr<File> file(OS::OpenFileForReading(image_filename.c_str()));
   1960     size_t data_size = image_header_.GetDataSize();  // stored size in file.
   1961     if (file == nullptr) {
   1962       LOG(WARNING) << "Failed to find image in " << image_filename;
   1963     } else {
   1964       stats_.file_bytes = file->GetLength();
   1965       // If the image is compressed, adjust to decompressed size.
   1966       size_t uncompressed_size = image_header_.GetImageSize() - sizeof(ImageHeader);
   1967       if (image_header_.GetStorageMode() == ImageHeader::kStorageModeUncompressed) {
   1968         DCHECK_EQ(uncompressed_size, data_size) << "Sizes should match for uncompressed image";
   1969       }
   1970       stats_.file_bytes += uncompressed_size - data_size;
   1971     }
   1972     size_t header_bytes = sizeof(ImageHeader);
   1973     const auto& object_section = image_header_.GetImageSection(ImageHeader::kSectionObjects);
   1974     const auto& field_section = image_header_.GetImageSection(ImageHeader::kSectionArtFields);
   1975     const auto& method_section = image_header_.GetMethodsSection();
   1976     const auto& dex_cache_arrays_section = image_header_.GetImageSection(
   1977         ImageHeader::kSectionDexCacheArrays);
   1978     const auto& intern_section = image_header_.GetImageSection(
   1979         ImageHeader::kSectionInternedStrings);
   1980     const auto& class_table_section = image_header_.GetImageSection(
   1981         ImageHeader::kSectionClassTable);
   1982     const auto& bitmap_section = image_header_.GetImageSection(ImageHeader::kSectionImageBitmap);
   1983 
   1984     stats_.header_bytes = header_bytes;
   1985 
   1986     // Objects are kObjectAlignment-aligned.
   1987     // CHECK_EQ(RoundUp(header_bytes, kObjectAlignment), object_section.Offset());
   1988     if (object_section.Offset() > header_bytes) {
   1989       stats_.alignment_bytes += object_section.Offset() - header_bytes;
   1990     }
   1991 
   1992     // Field section is 4-byte aligned.
   1993     constexpr size_t kFieldSectionAlignment = 4U;
   1994     uint32_t end_objects = object_section.Offset() + object_section.Size();
   1995     CHECK_EQ(RoundUp(end_objects, kFieldSectionAlignment), field_section.Offset());
   1996     stats_.alignment_bytes += field_section.Offset() - end_objects;
   1997 
   1998     // Method section is 4/8 byte aligned depending on target. Just check for 4-byte alignment.
   1999     uint32_t end_fields = field_section.Offset() + field_section.Size();
   2000     CHECK_ALIGNED(method_section.Offset(), 4);
   2001     stats_.alignment_bytes += method_section.Offset() - end_fields;
   2002 
   2003     // Dex cache arrays section is aligned depending on the target. Just check for 4-byte alignment.
   2004     uint32_t end_methods = method_section.Offset() + method_section.Size();
   2005     CHECK_ALIGNED(dex_cache_arrays_section.Offset(), 4);
   2006     stats_.alignment_bytes += dex_cache_arrays_section.Offset() - end_methods;
   2007 
   2008     // Intern table is 8-byte aligned.
   2009     uint32_t end_caches = dex_cache_arrays_section.Offset() + dex_cache_arrays_section.Size();
   2010     CHECK_EQ(RoundUp(end_caches, 8U), intern_section.Offset());
   2011     stats_.alignment_bytes += intern_section.Offset() - end_caches;
   2012 
   2013     // Add space between intern table and class table.
   2014     uint32_t end_intern = intern_section.Offset() + intern_section.Size();
   2015     stats_.alignment_bytes += class_table_section.Offset() - end_intern;
   2016 
   2017     // Add space between end of image data and bitmap. Expect the bitmap to be page-aligned.
   2018     const size_t bitmap_offset = sizeof(ImageHeader) + data_size;
   2019     CHECK_ALIGNED(bitmap_section.Offset(), kPageSize);
   2020     stats_.alignment_bytes += RoundUp(bitmap_offset, kPageSize) - bitmap_offset;
   2021 
   2022     stats_.bitmap_bytes += bitmap_section.Size();
   2023     stats_.art_field_bytes += field_section.Size();
   2024     stats_.art_method_bytes += method_section.Size();
   2025     stats_.dex_cache_arrays_bytes += dex_cache_arrays_section.Size();
   2026     stats_.interned_strings_bytes += intern_section.Size();
   2027     stats_.class_table_bytes += class_table_section.Size();
   2028     stats_.Dump(os, indent_os);
   2029     os << "\n";
   2030 
   2031     os << std::flush;
   2032 
   2033     return oat_dumper_->Dump(os);
   2034   }
   2035 
   2036  private:
   2037   class DumpArtMethodVisitor : public ArtMethodVisitor {
   2038    public:
   2039     explicit DumpArtMethodVisitor(ImageDumper* image_dumper) : image_dumper_(image_dumper) {}
   2040 
   2041     virtual void Visit(ArtMethod* method) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
   2042       std::ostream& indent_os = image_dumper_->vios_.Stream();
   2043       indent_os << method << " " << " ArtMethod: " << ArtMethod::PrettyMethod(method) << "\n";
   2044       image_dumper_->DumpMethod(method, indent_os);
   2045       indent_os << "\n";
   2046     }
   2047 
   2048    private:
   2049     ImageDumper* const image_dumper_;
   2050   };
   2051 
   2052   static void PrettyObjectValue(std::ostream& os,
   2053                                 ObjPtr<mirror::Class> type,
   2054                                 ObjPtr<mirror::Object> value)
   2055       REQUIRES_SHARED(Locks::mutator_lock_) {
   2056     CHECK(type != nullptr);
   2057     if (value == nullptr) {
   2058       os << StringPrintf("null   %s\n", type->PrettyDescriptor().c_str());
   2059     } else if (type->IsStringClass()) {
   2060       mirror::String* string = value->AsString();
   2061       os << StringPrintf("%p   String: %s\n", string,
   2062                          PrintableString(string->ToModifiedUtf8().c_str()).c_str());
   2063     } else if (type->IsClassClass()) {
   2064       mirror::Class* klass = value->AsClass();
   2065       os << StringPrintf("%p   Class: %s\n", klass, mirror::Class::PrettyDescriptor(klass).c_str());
   2066     } else {
   2067       os << StringPrintf("%p   %s\n", value.Ptr(), type->PrettyDescriptor().c_str());
   2068     }
   2069   }
   2070 
   2071   static void PrintField(std::ostream& os, ArtField* field, ObjPtr<mirror::Object> obj)
   2072       REQUIRES_SHARED(Locks::mutator_lock_) {
   2073     os << StringPrintf("%s: ", field->GetName());
   2074     switch (field->GetTypeAsPrimitiveType()) {
   2075       case Primitive::kPrimLong:
   2076         os << StringPrintf("%" PRId64 " (0x%" PRIx64 ")\n", field->Get64(obj), field->Get64(obj));
   2077         break;
   2078       case Primitive::kPrimDouble:
   2079         os << StringPrintf("%f (%a)\n", field->GetDouble(obj), field->GetDouble(obj));
   2080         break;
   2081       case Primitive::kPrimFloat:
   2082         os << StringPrintf("%f (%a)\n", field->GetFloat(obj), field->GetFloat(obj));
   2083         break;
   2084       case Primitive::kPrimInt:
   2085         os << StringPrintf("%d (0x%x)\n", field->Get32(obj), field->Get32(obj));
   2086         break;
   2087       case Primitive::kPrimChar:
   2088         os << StringPrintf("%u (0x%x)\n", field->GetChar(obj), field->GetChar(obj));
   2089         break;
   2090       case Primitive::kPrimShort:
   2091         os << StringPrintf("%d (0x%x)\n", field->GetShort(obj), field->GetShort(obj));
   2092         break;
   2093       case Primitive::kPrimBoolean:
   2094         os << StringPrintf("%s (0x%x)\n", field->GetBoolean(obj) ? "true" : "false",
   2095             field->GetBoolean(obj));
   2096         break;
   2097       case Primitive::kPrimByte:
   2098         os << StringPrintf("%d (0x%x)\n", field->GetByte(obj), field->GetByte(obj));
   2099         break;
   2100       case Primitive::kPrimNot: {
   2101         // Get the value, don't compute the type unless it is non-null as we don't want
   2102         // to cause class loading.
   2103         ObjPtr<mirror::Object> value = field->GetObj(obj);
   2104         if (value == nullptr) {
   2105           os << StringPrintf("null   %s\n", PrettyDescriptor(field->GetTypeDescriptor()).c_str());
   2106         } else {
   2107           // Grab the field type without causing resolution.
   2108           ObjPtr<mirror::Class> field_type = field->GetType<false>();
   2109           if (field_type != nullptr) {
   2110             PrettyObjectValue(os, field_type, value);
   2111           } else {
   2112             os << StringPrintf("%p   %s\n",
   2113                                value.Ptr(),
   2114                                PrettyDescriptor(field->GetTypeDescriptor()).c_str());
   2115           }
   2116         }
   2117         break;
   2118       }
   2119       default:
   2120         os << "unexpected field type: " << field->GetTypeDescriptor() << "\n";
   2121         break;
   2122     }
   2123   }
   2124 
   2125   static void DumpFields(std::ostream& os, mirror::Object* obj, mirror::Class* klass)
   2126       REQUIRES_SHARED(Locks::mutator_lock_) {
   2127     mirror::Class* super = klass->GetSuperClass();
   2128     if (super != nullptr) {
   2129       DumpFields(os, obj, super);
   2130     }
   2131     for (ArtField& field : klass->GetIFields()) {
   2132       PrintField(os, &field, obj);
   2133     }
   2134   }
   2135 
   2136   bool InDumpSpace(const mirror::Object* object) {
   2137     return image_space_.Contains(object);
   2138   }
   2139 
   2140   const void* GetQuickOatCodeBegin(ArtMethod* m) REQUIRES_SHARED(Locks::mutator_lock_) {
   2141     const void* quick_code = m->GetEntryPointFromQuickCompiledCodePtrSize(
   2142         image_header_.GetPointerSize());
   2143     if (Runtime::Current()->GetClassLinker()->IsQuickResolutionStub(quick_code)) {
   2144       quick_code = oat_dumper_->GetQuickOatCode(m);
   2145     }
   2146     if (oat_dumper_->GetInstructionSet() == kThumb2) {
   2147       quick_code = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(quick_code) & ~0x1);
   2148     }
   2149     return quick_code;
   2150   }
   2151 
   2152   uint32_t GetQuickOatCodeSize(ArtMethod* m)
   2153       REQUIRES_SHARED(Locks::mutator_lock_) {
   2154     const uint32_t* oat_code_begin = reinterpret_cast<const uint32_t*>(GetQuickOatCodeBegin(m));
   2155     if (oat_code_begin == nullptr) {
   2156       return 0;
   2157     }
   2158     return oat_code_begin[-1];
   2159   }
   2160 
   2161   const void* GetQuickOatCodeEnd(ArtMethod* m)
   2162       REQUIRES_SHARED(Locks::mutator_lock_) {
   2163     const uint8_t* oat_code_begin = reinterpret_cast<const uint8_t*>(GetQuickOatCodeBegin(m));
   2164     if (oat_code_begin == nullptr) {
   2165       return nullptr;
   2166     }
   2167     return oat_code_begin + GetQuickOatCodeSize(m);
   2168   }
   2169 
   2170   void DumpObject(mirror::Object* obj) REQUIRES_SHARED(Locks::mutator_lock_) {
   2171     DCHECK(obj != nullptr);
   2172     if (!InDumpSpace(obj)) {
   2173       return;
   2174     }
   2175 
   2176     size_t object_bytes = obj->SizeOf();
   2177     size_t alignment_bytes = RoundUp(object_bytes, kObjectAlignment) - object_bytes;
   2178     stats_.object_bytes += object_bytes;
   2179     stats_.alignment_bytes += alignment_bytes;
   2180 
   2181     std::ostream& os = vios_.Stream();
   2182 
   2183     mirror::Class* obj_class = obj->GetClass();
   2184     if (obj_class->IsArrayClass()) {
   2185       os << StringPrintf("%p: %s length:%d\n", obj, obj_class->PrettyDescriptor().c_str(),
   2186                          obj->AsArray()->GetLength());
   2187     } else if (obj->IsClass()) {
   2188       mirror::Class* klass = obj->AsClass();
   2189       os << StringPrintf("%p: java.lang.Class \"%s\" (", obj,
   2190                          mirror::Class::PrettyDescriptor(klass).c_str())
   2191          << klass->GetStatus() << ")\n";
   2192     } else if (obj_class->IsStringClass()) {
   2193       os << StringPrintf("%p: java.lang.String %s\n", obj,
   2194                          PrintableString(obj->AsString()->ToModifiedUtf8().c_str()).c_str());
   2195     } else {
   2196       os << StringPrintf("%p: %s\n", obj, obj_class->PrettyDescriptor().c_str());
   2197     }
   2198     ScopedIndentation indent1(&vios_);
   2199     DumpFields(os, obj, obj_class);
   2200     const PointerSize image_pointer_size = image_header_.GetPointerSize();
   2201     if (obj->IsObjectArray()) {
   2202       auto* obj_array = obj->AsObjectArray<mirror::Object>();
   2203       for (int32_t i = 0, length = obj_array->GetLength(); i < length; i++) {
   2204         mirror::Object* value = obj_array->Get(i);
   2205         size_t run = 0;
   2206         for (int32_t j = i + 1; j < length; j++) {
   2207           if (value == obj_array->Get(j)) {
   2208             run++;
   2209           } else {
   2210             break;
   2211           }
   2212         }
   2213         if (run == 0) {
   2214           os << StringPrintf("%d: ", i);
   2215         } else {
   2216           os << StringPrintf("%d to %zd: ", i, i + run);
   2217           i = i + run;
   2218         }
   2219         mirror::Class* value_class =
   2220             (value == nullptr) ? obj_class->GetComponentType() : value->GetClass();
   2221         PrettyObjectValue(os, value_class, value);
   2222       }
   2223     } else if (obj->IsClass()) {
   2224       mirror::Class* klass = obj->AsClass();
   2225       if (klass->NumStaticFields() != 0) {
   2226         os << "STATICS:\n";
   2227         ScopedIndentation indent2(&vios_);
   2228         for (ArtField& field : klass->GetSFields()) {
   2229           PrintField(os, &field, field.GetDeclaringClass());
   2230         }
   2231       }
   2232     } else {
   2233       auto it = dex_caches_.find(obj);
   2234       if (it != dex_caches_.end()) {
   2235         auto* dex_cache = down_cast<mirror::DexCache*>(obj);
   2236         const auto& field_section = image_header_.GetImageSection(
   2237             ImageHeader::kSectionArtFields);
   2238         const auto& method_section = image_header_.GetMethodsSection();
   2239         size_t num_methods = dex_cache->NumResolvedMethods();
   2240         if (num_methods != 0u) {
   2241           os << "Methods (size=" << num_methods << "):\n";
   2242           ScopedIndentation indent2(&vios_);
   2243           mirror::MethodDexCacheType* resolved_methods = dex_cache->GetResolvedMethods();
   2244           for (size_t i = 0, length = dex_cache->NumResolvedMethods(); i < length; ++i) {
   2245             ArtMethod* elem = mirror::DexCache::GetNativePairPtrSize(
   2246                 resolved_methods, i, image_pointer_size).object;
   2247             size_t run = 0;
   2248             for (size_t j = i + 1;
   2249                  j != length &&
   2250                  elem == mirror::DexCache::GetNativePairPtrSize(
   2251                      resolved_methods, j, image_pointer_size).object;
   2252                  ++j) {
   2253               ++run;
   2254             }
   2255             if (run == 0) {
   2256               os << StringPrintf("%zd: ", i);
   2257             } else {
   2258               os << StringPrintf("%zd to %zd: ", i, i + run);
   2259               i = i + run;
   2260             }
   2261             std::string msg;
   2262             if (elem == nullptr) {
   2263               msg = "null";
   2264             } else if (method_section.Contains(
   2265                 reinterpret_cast<uint8_t*>(elem) - image_space_.Begin())) {
   2266               msg = reinterpret_cast<ArtMethod*>(elem)->PrettyMethod();
   2267             } else {
   2268               msg = "<not in method section>";
   2269             }
   2270             os << StringPrintf("%p   %s\n", elem, msg.c_str());
   2271           }
   2272         }
   2273         size_t num_fields = dex_cache->NumResolvedFields();
   2274         if (num_fields != 0u) {
   2275           os << "Fields (size=" << num_fields << "):\n";
   2276           ScopedIndentation indent2(&vios_);
   2277           auto* resolved_fields = dex_cache->GetResolvedFields();
   2278           for (size_t i = 0, length = dex_cache->NumResolvedFields(); i < length; ++i) {
   2279             ArtField* elem = mirror::DexCache::GetNativePairPtrSize(
   2280                 resolved_fields, i, image_pointer_size).object;
   2281             size_t run = 0;
   2282             for (size_t j = i + 1;
   2283                  j != length &&
   2284                  elem == mirror::DexCache::GetNativePairPtrSize(
   2285                      resolved_fields, j, image_pointer_size).object;
   2286                  ++j) {
   2287               ++run;
   2288             }
   2289             if (run == 0) {
   2290               os << StringPrintf("%zd: ", i);
   2291             } else {
   2292               os << StringPrintf("%zd to %zd: ", i, i + run);
   2293               i = i + run;
   2294             }
   2295             std::string msg;
   2296             if (elem == nullptr) {
   2297               msg = "null";
   2298             } else if (field_section.Contains(
   2299                 reinterpret_cast<uint8_t*>(elem) - image_space_.Begin())) {
   2300               msg = reinterpret_cast<ArtField*>(elem)->PrettyField();
   2301             } else {
   2302               msg = "<not in field section>";
   2303             }
   2304             os << StringPrintf("%p   %s\n", elem, msg.c_str());
   2305           }
   2306         }
   2307         size_t num_types = dex_cache->NumResolvedTypes();
   2308         if (num_types != 0u) {
   2309           os << "Types (size=" << num_types << "):\n";
   2310           ScopedIndentation indent2(&vios_);
   2311           auto* resolved_types = dex_cache->GetResolvedTypes();
   2312           for (size_t i = 0; i < num_types; ++i) {
   2313             auto pair = resolved_types[i].load(std::memory_order_relaxed);
   2314             size_t run = 0;
   2315             for (size_t j = i + 1; j != num_types; ++j) {
   2316               auto other_pair = resolved_types[j].load(std::memory_order_relaxed);
   2317               if (pair.index != other_pair.index ||
   2318                   pair.object.Read() != other_pair.object.Read()) {
   2319                 break;
   2320               }
   2321               ++run;
   2322             }
   2323             if (run == 0) {
   2324               os << StringPrintf("%zd: ", i);
   2325             } else {
   2326               os << StringPrintf("%zd to %zd: ", i, i + run);
   2327               i = i + run;
   2328             }
   2329             std::string msg;
   2330             auto* elem = pair.object.Read();
   2331             if (elem == nullptr) {
   2332               msg = "null";
   2333             } else {
   2334               msg = elem->PrettyClass();
   2335             }
   2336             os << StringPrintf("%p   %u %s\n", elem, pair.index, msg.c_str());
   2337           }
   2338         }
   2339       }
   2340     }
   2341     std::string temp;
   2342     stats_.Update(obj_class->GetDescriptor(&temp), object_bytes);
   2343   }
   2344 
   2345   void DumpMethod(ArtMethod* method, std::ostream& indent_os)
   2346       REQUIRES_SHARED(Locks::mutator_lock_) {
   2347     DCHECK(method != nullptr);
   2348     const void* quick_oat_code_begin = GetQuickOatCodeBegin(method);
   2349     const void* quick_oat_code_end = GetQuickOatCodeEnd(method);
   2350     const PointerSize pointer_size = image_header_.GetPointerSize();
   2351     OatQuickMethodHeader* method_header = reinterpret_cast<OatQuickMethodHeader*>(
   2352         reinterpret_cast<uintptr_t>(quick_oat_code_begin) - sizeof(OatQuickMethodHeader));
   2353     if (method->IsNative()) {
   2354       bool first_occurrence;
   2355       uint32_t quick_oat_code_size = GetQuickOatCodeSize(method);
   2356       ComputeOatSize(quick_oat_code_begin, &first_occurrence);
   2357       if (first_occurrence) {
   2358         stats_.native_to_managed_code_bytes += quick_oat_code_size;
   2359       }
   2360       if (quick_oat_code_begin != method->GetEntryPointFromQuickCompiledCodePtrSize(
   2361           image_header_.GetPointerSize())) {
   2362         indent_os << StringPrintf("OAT CODE: %p\n", quick_oat_code_begin);
   2363       }
   2364     } else if (method->IsAbstract() || method->IsClassInitializer()) {
   2365       // Don't print information for these.
   2366     } else if (method->IsRuntimeMethod()) {
   2367       ImtConflictTable* table = method->GetImtConflictTable(image_header_.GetPointerSize());
   2368       if (table != nullptr) {
   2369         indent_os << "IMT conflict table " << table << " method: ";
   2370         for (size_t i = 0, count = table->NumEntries(pointer_size); i < count; ++i) {
   2371           indent_os << ArtMethod::PrettyMethod(table->GetImplementationMethod(i, pointer_size))
   2372                     << " ";
   2373         }
   2374       }
   2375     } else {
   2376       const DexFile::CodeItem* code_item = method->GetCodeItem();
   2377       size_t dex_instruction_bytes = code_item->insns_size_in_code_units_ * 2;
   2378       stats_.dex_instruction_bytes += dex_instruction_bytes;
   2379 
   2380       bool first_occurrence;
   2381       size_t vmap_table_bytes = 0u;
   2382       if (!method_header->IsOptimized()) {
   2383         // Method compiled with the optimizing compiler have no vmap table.
   2384         vmap_table_bytes = ComputeOatSize(method_header->GetVmapTable(), &first_occurrence);
   2385         if (first_occurrence) {
   2386           stats_.vmap_table_bytes += vmap_table_bytes;
   2387         }
   2388       }
   2389 
   2390       uint32_t quick_oat_code_size = GetQuickOatCodeSize(method);
   2391       ComputeOatSize(quick_oat_code_begin, &first_occurrence);
   2392       if (first_occurrence) {
   2393         stats_.managed_code_bytes += quick_oat_code_size;
   2394         if (method->IsConstructor()) {
   2395           if (method->IsStatic()) {
   2396             stats_.class_initializer_code_bytes += quick_oat_code_size;
   2397           } else if (dex_instruction_bytes > kLargeConstructorDexBytes) {
   2398             stats_.large_initializer_code_bytes += quick_oat_code_size;
   2399           }
   2400         } else if (dex_instruction_bytes > kLargeMethodDexBytes) {
   2401           stats_.large_method_code_bytes += quick_oat_code_size;
   2402         }
   2403       }
   2404       stats_.managed_code_bytes_ignoring_deduplication += quick_oat_code_size;
   2405 
   2406       uint32_t method_access_flags = method->GetAccessFlags();
   2407 
   2408       indent_os << StringPrintf("OAT CODE: %p-%p\n", quick_oat_code_begin, quick_oat_code_end);
   2409       indent_os << StringPrintf("SIZE: Dex Instructions=%zd StackMaps=%zd AccessFlags=0x%x\n",
   2410                                 dex_instruction_bytes,
   2411                                 vmap_table_bytes,
   2412                                 method_access_flags);
   2413 
   2414       size_t total_size = dex_instruction_bytes +
   2415           vmap_table_bytes + quick_oat_code_size + ArtMethod::Size(image_header_.GetPointerSize());
   2416 
   2417       double expansion =
   2418       static_cast<double>(quick_oat_code_size) / static_cast<double>(dex_instruction_bytes);
   2419       stats_.ComputeOutliers(total_size, expansion, method);
   2420     }
   2421   }
   2422 
   2423   std::set<const void*> already_seen_;
   2424   // Compute the size of the given data within the oat file and whether this is the first time
   2425   // this data has been requested
   2426   size_t ComputeOatSize(const void* oat_data, bool* first_occurrence) {
   2427     if (already_seen_.count(oat_data) == 0) {
   2428       *first_occurrence = true;
   2429       already_seen_.insert(oat_data);
   2430     } else {
   2431       *first_occurrence = false;
   2432     }
   2433     return oat_dumper_->ComputeSize(oat_data);
   2434   }
   2435 
   2436  public:
   2437   struct Stats {
   2438     size_t oat_file_bytes;
   2439     size_t file_bytes;
   2440 
   2441     size_t header_bytes;
   2442     size_t object_bytes;
   2443     size_t art_field_bytes;
   2444     size_t art_method_bytes;
   2445     size_t dex_cache_arrays_bytes;
   2446     size_t interned_strings_bytes;
   2447     size_t class_table_bytes;
   2448     size_t bitmap_bytes;
   2449     size_t alignment_bytes;
   2450 
   2451     size_t managed_code_bytes;
   2452     size_t managed_code_bytes_ignoring_deduplication;
   2453     size_t native_to_managed_code_bytes;
   2454     size_t class_initializer_code_bytes;
   2455     size_t large_initializer_code_bytes;
   2456     size_t large_method_code_bytes;
   2457 
   2458     size_t vmap_table_bytes;
   2459 
   2460     size_t dex_instruction_bytes;
   2461 
   2462     std::vector<ArtMethod*> method_outlier;
   2463     std::vector<size_t> method_outlier_size;
   2464     std::vector<double> method_outlier_expansion;
   2465     std::vector<std::pair<std::string, size_t>> oat_dex_file_sizes;
   2466 
   2467     Stats()
   2468         : oat_file_bytes(0),
   2469           file_bytes(0),
   2470           header_bytes(0),
   2471           object_bytes(0),
   2472           art_field_bytes(0),
   2473           art_method_bytes(0),
   2474           dex_cache_arrays_bytes(0),
   2475           interned_strings_bytes(0),
   2476           class_table_bytes(0),
   2477           bitmap_bytes(0),
   2478           alignment_bytes(0),
   2479           managed_code_bytes(0),
   2480           managed_code_bytes_ignoring_deduplication(0),
   2481           native_to_managed_code_bytes(0),
   2482           class_initializer_code_bytes(0),
   2483           large_initializer_code_bytes(0),
   2484           large_method_code_bytes(0),
   2485           vmap_table_bytes(0),
   2486           dex_instruction_bytes(0) {}
   2487 
   2488     struct SizeAndCount {
   2489       SizeAndCount(size_t bytes_in, size_t count_in) : bytes(bytes_in), count(count_in) {}
   2490       size_t bytes;
   2491       size_t count;
   2492     };
   2493     typedef SafeMap<std::string, SizeAndCount> SizeAndCountTable;
   2494     SizeAndCountTable sizes_and_counts;
   2495 
   2496     void Update(const char* descriptor, size_t object_bytes_in) {
   2497       SizeAndCountTable::iterator it = sizes_and_counts.find(descriptor);
   2498       if (it != sizes_and_counts.end()) {
   2499         it->second.bytes += object_bytes_in;
   2500         it->second.count += 1;
   2501       } else {
   2502         sizes_and_counts.Put(descriptor, SizeAndCount(object_bytes_in, 1));
   2503       }
   2504     }
   2505 
   2506     double PercentOfOatBytes(size_t size) {
   2507       return (static_cast<double>(size) / static_cast<double>(oat_file_bytes)) * 100;
   2508     }
   2509 
   2510     double PercentOfFileBytes(size_t size) {
   2511       return (static_cast<double>(size) / static_cast<double>(file_bytes)) * 100;
   2512     }
   2513 
   2514     double PercentOfObjectBytes(size_t size) {
   2515       return (static_cast<double>(size) / static_cast<double>(object_bytes)) * 100;
   2516     }
   2517 
   2518     void ComputeOutliers(size_t total_size, double expansion, ArtMethod* method) {
   2519       method_outlier_size.push_back(total_size);
   2520       method_outlier_expansion.push_back(expansion);
   2521       method_outlier.push_back(method);
   2522     }
   2523 
   2524     void DumpOutliers(std::ostream& os)
   2525         REQUIRES_SHARED(Locks::mutator_lock_) {
   2526       size_t sum_of_sizes = 0;
   2527       size_t sum_of_sizes_squared = 0;
   2528       size_t sum_of_expansion = 0;
   2529       size_t sum_of_expansion_squared = 0;
   2530       size_t n = method_outlier_size.size();
   2531       if (n <= 1) {
   2532         return;
   2533       }
   2534       for (size_t i = 0; i < n; i++) {
   2535         size_t cur_size = method_outlier_size[i];
   2536         sum_of_sizes += cur_size;
   2537         sum_of_sizes_squared += cur_size * cur_size;
   2538         double cur_expansion = method_outlier_expansion[i];
   2539         sum_of_expansion += cur_expansion;
   2540         sum_of_expansion_squared += cur_expansion * cur_expansion;
   2541       }
   2542       size_t size_mean = sum_of_sizes / n;
   2543       size_t size_variance = (sum_of_sizes_squared - sum_of_sizes * size_mean) / (n - 1);
   2544       double expansion_mean = sum_of_expansion / n;
   2545       double expansion_variance =
   2546           (sum_of_expansion_squared - sum_of_expansion * expansion_mean) / (n - 1);
   2547 
   2548       // Dump methods whose size is a certain number of standard deviations from the mean
   2549       size_t dumped_values = 0;
   2550       size_t skipped_values = 0;
   2551       for (size_t i = 100; i > 0; i--) {  // i is the current number of standard deviations
   2552         size_t cur_size_variance = i * i * size_variance;
   2553         bool first = true;
   2554         for (size_t j = 0; j < n; j++) {
   2555           size_t cur_size = method_outlier_size[j];
   2556           if (cur_size > size_mean) {
   2557             size_t cur_var = cur_size - size_mean;
   2558             cur_var = cur_var * cur_var;
   2559             if (cur_var > cur_size_variance) {
   2560               if (dumped_values > 20) {
   2561                 if (i == 1) {
   2562                   skipped_values++;
   2563                 } else {
   2564                   i = 2;  // jump to counting for 1 standard deviation
   2565                   break;
   2566                 }
   2567               } else {
   2568                 if (first) {
   2569                   os << "\nBig methods (size > " << i << " standard deviations the norm):\n";
   2570                   first = false;
   2571                 }
   2572                 os << ArtMethod::PrettyMethod(method_outlier[j]) << " requires storage of "
   2573                     << PrettySize(cur_size) << "\n";
   2574                 method_outlier_size[j] = 0;  // don't consider this method again
   2575                 dumped_values++;
   2576               }
   2577             }
   2578           }
   2579         }
   2580       }
   2581       if (skipped_values > 0) {
   2582         os << "... skipped " << skipped_values
   2583            << " methods with size > 1 standard deviation from the norm\n";
   2584       }
   2585       os << std::flush;
   2586 
   2587       // Dump methods whose expansion is a certain number of standard deviations from the mean
   2588       dumped_values = 0;
   2589       skipped_values = 0;
   2590       for (size_t i = 10; i > 0; i--) {  // i is the current number of standard deviations
   2591         double cur_expansion_variance = i * i * expansion_variance;
   2592         bool first = true;
   2593         for (size_t j = 0; j < n; j++) {
   2594           double cur_expansion = method_outlier_expansion[j];
   2595           if (cur_expansion > expansion_mean) {
   2596             size_t cur_var = cur_expansion - expansion_mean;
   2597             cur_var = cur_var * cur_var;
   2598             if (cur_var > cur_expansion_variance) {
   2599               if (dumped_values > 20) {
   2600                 if (i == 1) {
   2601                   skipped_values++;
   2602                 } else {
   2603                   i = 2;  // jump to counting for 1 standard deviation
   2604                   break;
   2605                 }
   2606               } else {
   2607                 if (first) {
   2608                   os << "\nLarge expansion methods (size > " << i
   2609                       << " standard deviations the norm):\n";
   2610                   first = false;
   2611                 }
   2612                 os << ArtMethod::PrettyMethod(method_outlier[j]) << " expanded code by "
   2613                    << cur_expansion << "\n";
   2614                 method_outlier_expansion[j] = 0.0;  // don't consider this method again
   2615                 dumped_values++;
   2616               }
   2617             }
   2618           }
   2619         }
   2620       }
   2621       if (skipped_values > 0) {
   2622         os << "... skipped " << skipped_values
   2623            << " methods with expansion > 1 standard deviation from the norm\n";
   2624       }
   2625       os << "\n" << std::flush;
   2626     }
   2627 
   2628     void Dump(std::ostream& os, std::ostream& indent_os)
   2629         REQUIRES_SHARED(Locks::mutator_lock_) {
   2630       {
   2631         os << "art_file_bytes = " << PrettySize(file_bytes) << "\n\n"
   2632            << "art_file_bytes = header_bytes + object_bytes + alignment_bytes\n";
   2633         indent_os << StringPrintf("header_bytes           =  %8zd (%2.0f%% of art file bytes)\n"
   2634                                   "object_bytes           =  %8zd (%2.0f%% of art file bytes)\n"
   2635                                   "art_field_bytes        =  %8zd (%2.0f%% of art file bytes)\n"
   2636                                   "art_method_bytes       =  %8zd (%2.0f%% of art file bytes)\n"
   2637                                   "dex_cache_arrays_bytes =  %8zd (%2.0f%% of art file bytes)\n"
   2638                                   "interned_string_bytes  =  %8zd (%2.0f%% of art file bytes)\n"
   2639                                   "class_table_bytes      =  %8zd (%2.0f%% of art file bytes)\n"
   2640                                   "bitmap_bytes           =  %8zd (%2.0f%% of art file bytes)\n"
   2641                                   "alignment_bytes        =  %8zd (%2.0f%% of art file bytes)\n\n",
   2642                                   header_bytes, PercentOfFileBytes(header_bytes),
   2643                                   object_bytes, PercentOfFileBytes(object_bytes),
   2644                                   art_field_bytes, PercentOfFileBytes(art_field_bytes),
   2645                                   art_method_bytes, PercentOfFileBytes(art_method_bytes),
   2646                                   dex_cache_arrays_bytes,
   2647                                   PercentOfFileBytes(dex_cache_arrays_bytes),
   2648                                   interned_strings_bytes,
   2649                                   PercentOfFileBytes(interned_strings_bytes),
   2650                                   class_table_bytes, PercentOfFileBytes(class_table_bytes),
   2651                                   bitmap_bytes, PercentOfFileBytes(bitmap_bytes),
   2652                                   alignment_bytes, PercentOfFileBytes(alignment_bytes))
   2653             << std::flush;
   2654         CHECK_EQ(file_bytes,
   2655                  header_bytes + object_bytes + art_field_bytes + art_method_bytes +
   2656                  dex_cache_arrays_bytes + interned_strings_bytes + class_table_bytes +
   2657                  bitmap_bytes + alignment_bytes);
   2658       }
   2659 
   2660       os << "object_bytes breakdown:\n";
   2661       size_t object_bytes_total = 0;
   2662       for (const auto& sizes_and_count : sizes_and_counts) {
   2663         const std::string& descriptor(sizes_and_count.first);
   2664         double average = static_cast<double>(sizes_and_count.second.bytes) /
   2665             static_cast<double>(sizes_and_count.second.count);
   2666         double percent = PercentOfObjectBytes(sizes_and_count.second.bytes);
   2667         os << StringPrintf("%32s %8zd bytes %6zd instances "
   2668                            "(%4.0f bytes/instance) %2.0f%% of object_bytes\n",
   2669                            descriptor.c_str(), sizes_and_count.second.bytes,
   2670                            sizes_and_count.second.count, average, percent);
   2671         object_bytes_total += sizes_and_count.second.bytes;
   2672       }
   2673       os << "\n" << std::flush;
   2674       CHECK_EQ(object_bytes, object_bytes_total);
   2675 
   2676       os << StringPrintf("oat_file_bytes               = %8zd\n"
   2677                          "managed_code_bytes           = %8zd (%2.0f%% of oat file bytes)\n"
   2678                          "native_to_managed_code_bytes = %8zd (%2.0f%% of oat file bytes)\n\n"
   2679                          "class_initializer_code_bytes = %8zd (%2.0f%% of oat file bytes)\n"
   2680                          "large_initializer_code_bytes = %8zd (%2.0f%% of oat file bytes)\n"
   2681                          "large_method_code_bytes      = %8zd (%2.0f%% of oat file bytes)\n\n",
   2682                          oat_file_bytes,
   2683                          managed_code_bytes,
   2684                          PercentOfOatBytes(managed_code_bytes),
   2685                          native_to_managed_code_bytes,
   2686                          PercentOfOatBytes(native_to_managed_code_bytes),
   2687                          class_initializer_code_bytes,
   2688                          PercentOfOatBytes(class_initializer_code_bytes),
   2689                          large_initializer_code_bytes,
   2690                          PercentOfOatBytes(large_initializer_code_bytes),
   2691                          large_method_code_bytes,
   2692                          PercentOfOatBytes(large_method_code_bytes))
   2693             << "DexFile sizes:\n";
   2694       for (const std::pair<std::string, size_t>& oat_dex_file_size : oat_dex_file_sizes) {
   2695         os << StringPrintf("%s = %zd (%2.0f%% of oat file bytes)\n",
   2696                            oat_dex_file_size.first.c_str(), oat_dex_file_size.second,
   2697                            PercentOfOatBytes(oat_dex_file_size.second));
   2698       }
   2699 
   2700       os << "\n" << StringPrintf("vmap_table_bytes       = %7zd (%2.0f%% of oat file bytes)\n\n",
   2701                                  vmap_table_bytes, PercentOfOatBytes(vmap_table_bytes))
   2702          << std::flush;
   2703 
   2704       os << StringPrintf("dex_instruction_bytes = %zd\n", dex_instruction_bytes)
   2705          << StringPrintf("managed_code_bytes expansion = %.2f (ignoring deduplication %.2f)\n\n",
   2706                          static_cast<double>(managed_code_bytes) /
   2707                              static_cast<double>(dex_instruction_bytes),
   2708                          static_cast<double>(managed_code_bytes_ignoring_deduplication) /
   2709                              static_cast<double>(dex_instruction_bytes))
   2710          << std::flush;
   2711 
   2712       DumpOutliers(os);
   2713     }
   2714   } stats_;
   2715 
   2716  private:
   2717   enum {
   2718     // Number of bytes for a constructor to be considered large. Based on the 1000 basic block
   2719     // threshold, we assume 2 bytes per instruction and 2 instructions per block.
   2720     kLargeConstructorDexBytes = 4000,
   2721     // Number of bytes for a method to be considered large. Based on the 4000 basic block
   2722     // threshold, we assume 2 bytes per instruction and 2 instructions per block.
   2723     kLargeMethodDexBytes = 16000
   2724   };
   2725 
   2726   // For performance, use the *os_ directly for anything that doesn't need indentation
   2727   // and prepare an indentation stream with default indentation 1.
   2728   std::ostream* os_;
   2729   VariableIndentationOutputStream vios_;
   2730   ScopedIndentation indent1_;
   2731 
   2732   gc::space::ImageSpace& image_space_;
   2733   const ImageHeader& image_header_;
   2734   std::unique_ptr<OatDumper> oat_dumper_;
   2735   OatDumperOptions* oat_dumper_options_;
   2736   std::set<mirror::Object*> dex_caches_;
   2737 
   2738   DISALLOW_COPY_AND_ASSIGN(ImageDumper);
   2739 };
   2740 
   2741 static int DumpImage(gc::space::ImageSpace* image_space,
   2742                      OatDumperOptions* options,
   2743                      std::ostream* os) REQUIRES_SHARED(Locks::mutator_lock_) {
   2744   const ImageHeader& image_header = image_space->GetImageHeader();
   2745   if (!image_header.IsValid()) {
   2746     fprintf(stderr, "Invalid image header %s\n", image_space->GetImageLocation().c_str());
   2747     return EXIT_FAILURE;
   2748   }
   2749   ImageDumper image_dumper(os, *image_space, image_header, options);
   2750   if (!image_dumper.Dump()) {
   2751     return EXIT_FAILURE;
   2752   }
   2753   return EXIT_SUCCESS;
   2754 }
   2755 
   2756 static int DumpImages(Runtime* runtime, OatDumperOptions* options, std::ostream* os) {
   2757   // Dumping the image, no explicit class loader.
   2758   ScopedNullHandle<mirror::ClassLoader> null_class_loader;
   2759   options->class_loader_ = &null_class_loader;
   2760 
   2761   ScopedObjectAccess soa(Thread::Current());
   2762   if (options->app_image_ != nullptr) {
   2763     if (options->app_oat_ == nullptr) {
   2764       LOG(ERROR) << "Can not dump app image without app oat file";
   2765       return EXIT_FAILURE;
   2766     }
   2767     // We can't know if the app image is 32 bits yet, but it contains pointers into the oat file.
   2768     // We need to map the oat file in the low 4gb or else the fixup wont be able to fit oat file
   2769     // pointers into 32 bit pointer sized ArtMethods.
   2770     std::string error_msg;
   2771     std::unique_ptr<OatFile> oat_file(OatFile::Open(options->app_oat_,
   2772                                                     options->app_oat_,
   2773                                                     nullptr,
   2774                                                     nullptr,
   2775                                                     false,
   2776                                                     /*low_4gb*/true,
   2777                                                     nullptr,
   2778                                                     &error_msg));
   2779     if (oat_file == nullptr) {
   2780       LOG(ERROR) << "Failed to open oat file " << options->app_oat_ << " with error " << error_msg;
   2781       return EXIT_FAILURE;
   2782     }
   2783     std::unique_ptr<gc::space::ImageSpace> space(
   2784         gc::space::ImageSpace::CreateFromAppImage(options->app_image_, oat_file.get(), &error_msg));
   2785     if (space == nullptr) {
   2786       LOG(ERROR) << "Failed to open app image " << options->app_image_ << " with error "
   2787                  << error_msg;
   2788     }
   2789     // Open dex files for the image.
   2790     std::vector<std::unique_ptr<const DexFile>> dex_files;
   2791     if (!runtime->GetClassLinker()->OpenImageDexFiles(space.get(), &dex_files, &error_msg)) {
   2792       LOG(ERROR) << "Failed to open app image dex files " << options->app_image_ << " with error "
   2793                  << error_msg;
   2794     }
   2795     // Dump the actual image.
   2796     int result = DumpImage(space.get(), options, os);
   2797     if (result != EXIT_SUCCESS) {
   2798       return result;
   2799     }
   2800     // Fall through to dump the boot images.
   2801   }
   2802 
   2803   gc::Heap* heap = runtime->GetHeap();
   2804   CHECK(heap->HasBootImageSpace()) << "No image spaces";
   2805   for (gc::space::ImageSpace* image_space : heap->GetBootImageSpaces()) {
   2806     int result = DumpImage(image_space, options, os);
   2807     if (result != EXIT_SUCCESS) {
   2808       return result;
   2809     }
   2810   }
   2811   return EXIT_SUCCESS;
   2812 }
   2813 
   2814 static jobject InstallOatFile(Runtime* runtime,
   2815                               std::unique_ptr<OatFile> oat_file,
   2816                               std::vector<const DexFile*>* class_path)
   2817     REQUIRES_SHARED(Locks::mutator_lock_) {
   2818   Thread* self = Thread::Current();
   2819   CHECK(self != nullptr);
   2820   // Need well-known-classes.
   2821   WellKnownClasses::Init(self->GetJniEnv());
   2822 
   2823   // Need to register dex files to get a working dex cache.
   2824   OatFile* oat_file_ptr = oat_file.get();
   2825   ClassLinker* class_linker = runtime->GetClassLinker();
   2826   runtime->GetOatFileManager().RegisterOatFile(std::move(oat_file));
   2827   for (const OatFile::OatDexFile* odf : oat_file_ptr->GetOatDexFiles()) {
   2828     std::string error_msg;
   2829     const DexFile* const dex_file = OpenDexFile(odf, &error_msg);
   2830     CHECK(dex_file != nullptr) << error_msg;
   2831     ObjPtr<mirror::DexCache> dex_cache =
   2832         class_linker->RegisterDexFile(*dex_file, nullptr);
   2833     CHECK(dex_cache != nullptr);
   2834     class_path->push_back(dex_file);
   2835   }
   2836 
   2837   // Need a class loader. Fake that we're a compiler.
   2838   // Note: this will run initializers through the unstarted runtime, so make sure it's
   2839   //       initialized.
   2840   interpreter::UnstartedRuntime::Initialize();
   2841 
   2842   jobject class_loader = class_linker->CreatePathClassLoader(self, *class_path);
   2843 
   2844   return class_loader;
   2845 }
   2846 
   2847 static int DumpOatWithR