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 DumpOatWithRuntime(Runtime* runtime,
   2848                               std::unique_ptr<OatFile> oat_file,
   2849                               OatDumperOptions* options,
   2850                               std::ostream* os) {
   2851   CHECK(runtime != nullptr && oat_file != nullptr && options != nullptr);
   2852   ScopedObjectAccess soa(Thread::Current());
   2853 
   2854   OatFile* oat_file_ptr = oat_file.get();
   2855   std::vector<const DexFile*> class_path;
   2856   jobject class_loader = InstallOatFile(runtime, std::move(oat_file), &class_path);
   2857 
   2858   // Use the class loader while dumping.
   2859   StackHandleScope<1> scope(soa.Self());
   2860   Handle<mirror::ClassLoader> loader_handle = scope.NewHandle(
   2861       soa.Decode<mirror::ClassLoader>(class_loader));
   2862   options->class_loader_ = &loader_handle;
   2863 
   2864   OatDumper oat_dumper(*oat_file_ptr, *options);
   2865   bool success = oat_dumper.Dump(*os);
   2866   return (success) ? EXIT_SUCCESS : EXIT_FAILURE;
   2867 }
   2868 
   2869 static int DumpOatWithoutRuntime(OatFile* oat_file, OatDumperOptions* options, std::ostream* os) {
   2870   CHECK(oat_file != nullptr && options != nullptr);
   2871   // No image = no class loader.
   2872   ScopedNullHandle<mirror::ClassLoader> null_class_loader;
   2873   options->class_loader_ = &null_class_loader;
   2874 
   2875   OatDumper oat_dumper(*oat_file, *options);
   2876   bool success = oat_dumper.Dump(*os);
   2877   return (success) ? EXIT_SUCCESS : EXIT_FAILURE;
   2878 }
   2879 
   2880 static int DumpOat(Runtime* runtime, const char* oat_filename, OatDumperOptions* options,
   2881                    std::ostream* os) {
   2882   std::string error_msg;
   2883   std::unique_ptr<OatFile> oat_file(OatFile::Open(oat_filename,
   2884                                                   oat_filename,
   2885                                                   nullptr,
   2886                                                   nullptr,
   2887                                                   false,
   2888                                                   /*low_4gb*/false,
   2889                                                   nullptr,
   2890                                                   &error_msg));
   2891   if (oat_file == nullptr) {
   2892     fprintf(stderr, "Failed to open oat file from '%s': %s\n", oat_filename, error_msg.c_str());
   2893     return EXIT_FAILURE;
   2894   }
   2895 
   2896   if (runtime != nullptr) {
   2897     return DumpOatWithRuntime(runtime, std::move(oat_file), options, os);
   2898   } else {
   2899     return DumpOatWithoutRuntime(oat_file.get(), options, os);
   2900   }
   2901 }
   2902 
   2903 static int SymbolizeOat(const char* oat_filename, std::string& output_name, bool no_bits) {
   2904   std::string error_msg;
   2905   std::unique_ptr<OatFile> oat_file(OatFile::Open(oat_filename,
   2906                                                   oat_filename,
   2907                                                   nullptr,
   2908                                                   nullptr,
   2909                                                   false,
   2910                                                   /*low_4gb*/false,
   2911                                                   nullptr,
   2912                                                   &error_msg));
   2913   if (oat_file == nullptr) {
   2914     fprintf(stderr, "Failed to open oat file from '%s': %s\n", oat_filename, error_msg.c_str());
   2915     return EXIT_FAILURE;
   2916   }
   2917 
   2918   bool result;
   2919   // Try to produce an ELF file of the same type. This is finicky, as we have used 32-bit ELF
   2920   // files for 64-bit code in the past.
   2921   if (Is64BitInstructionSet(oat_file->GetOatHeader().GetInstructionSet())) {
   2922     OatSymbolizer<ElfTypes64> oat_symbolizer(oat_file.get(), output_name, no_bits);
   2923     result = oat_symbolizer.Symbolize();
   2924   } else {
   2925     OatSymbolizer<ElfTypes32> oat_symbolizer(oat_file.get(), output_name, no_bits);
   2926     result = oat_symbolizer.Symbolize();
   2927   }
   2928   if (!result) {
   2929     fprintf(stderr, "Failed to symbolize\n");
   2930     return EXIT_FAILURE;
   2931   }
   2932 
   2933   return EXIT_SUCCESS;
   2934 }
   2935 
   2936 class IMTDumper {
   2937  public:
   2938   static bool Dump(Runtime* runtime,
   2939                    const std::string& imt_file,
   2940                    bool dump_imt_stats,
   2941                    const char* oat_filename) {
   2942     Thread* self = Thread::Current();
   2943 
   2944     ScopedObjectAccess soa(self);
   2945     StackHandleScope<1> scope(self);
   2946     MutableHandle<mirror::ClassLoader> class_loader = scope.NewHandle<mirror::ClassLoader>(nullptr);
   2947     std::vector<const DexFile*> class_path;
   2948 
   2949     if (oat_filename != nullptr) {
   2950       std::string error_msg;
   2951       std::unique_ptr<OatFile> oat_file(OatFile::Open(oat_filename,
   2952                                                       oat_filename,
   2953                                                       nullptr,
   2954                                                       nullptr,
   2955                                                       false,
   2956                                                       /*low_4gb*/false,
   2957                                                       nullptr,
   2958                                                       &error_msg));
   2959       if (oat_file == nullptr) {
   2960         fprintf(stderr, "Failed to open oat file from '%s': %s\n", oat_filename, error_msg.c_str());
   2961         return false;
   2962       }
   2963 
   2964       class_loader.Assign(soa.Decode<mirror::ClassLoader>(
   2965           InstallOatFile(runtime, std::move(oat_file), &class_path)));
   2966     } else {
   2967       class_loader.Assign(nullptr);  // Boot classloader. Just here for explicit documentation.
   2968       class_path = runtime->GetClassLinker()->GetBootClassPath();
   2969     }
   2970 
   2971     if (!imt_file.empty()) {
   2972       return DumpImt(runtime, imt_file, class_loader);
   2973     }
   2974 
   2975     if (dump_imt_stats) {
   2976       return DumpImtStats(runtime, class_path, class_loader);
   2977     }
   2978 
   2979     LOG(FATAL) << "Should not reach here";
   2980     UNREACHABLE();
   2981   }
   2982 
   2983  private:
   2984   static bool DumpImt(Runtime* runtime,
   2985                       const std::string& imt_file,
   2986                       Handle<mirror::ClassLoader> h_class_loader)
   2987       REQUIRES_SHARED(Locks::mutator_lock_) {
   2988     std::vector<std::string> lines = ReadCommentedInputFromFile(imt_file);
   2989     std::unordered_set<std::string> prepared;
   2990 
   2991     for (const std::string& line : lines) {
   2992       // A line should be either a class descriptor, in which case we will dump the complete IMT,
   2993       // or a class descriptor and an interface method, in which case we will lookup the method,
   2994       // determine its IMT slot, and check the class' IMT.
   2995       size_t first_space = line.find(' ');
   2996       if (first_space == std::string::npos) {
   2997         DumpIMTForClass(runtime, line, h_class_loader, &prepared);
   2998       } else {
   2999         DumpIMTForMethod(runtime,
   3000                          line.substr(0, first_space),
   3001                          line.substr(first_space + 1, std::string::npos),
   3002                          h_class_loader,
   3003                          &prepared);
   3004       }
   3005       std::cerr << std::endl;
   3006     }
   3007 
   3008     return true;
   3009   }
   3010 
   3011   static bool DumpImtStats(Runtime* runtime,
   3012                            const std::vector<const DexFile*>& dex_files,
   3013                            Handle<mirror::ClassLoader> h_class_loader)
   3014       REQUIRES_SHARED(Locks::mutator_lock_) {
   3015     size_t without_imt = 0;
   3016     size_t with_imt = 0;
   3017     std::map<size_t, size_t> histogram;
   3018 
   3019     ClassLinker* class_linker = runtime->GetClassLinker();
   3020     const PointerSize pointer_size = class_linker->GetImagePointerSize();
   3021     std::unordered_set<std::string> prepared;
   3022 
   3023     Thread* self = Thread::Current();
   3024     StackHandleScope<1> scope(self);
   3025     MutableHandle<mirror::Class> h_klass(scope.NewHandle<mirror::Class>(nullptr));
   3026 
   3027     for (const DexFile* dex_file : dex_files) {
   3028       for (uint32_t class_def_index = 0;
   3029            class_def_index != dex_file->NumClassDefs();
   3030            ++class_def_index) {
   3031         const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
   3032         const char* descriptor = dex_file->GetClassDescriptor(class_def);
   3033         h_klass.Assign(class_linker->FindClass(self, descriptor, h_class_loader));
   3034         if (h_klass == nullptr) {
   3035           std::cerr << "Warning: could not load " << descriptor << std::endl;
   3036           continue;
   3037         }
   3038 
   3039         if (HasNoIMT(runtime, h_klass, pointer_size, &prepared)) {
   3040           without_imt++;
   3041           continue;
   3042         }
   3043 
   3044         ImTable* im_table = PrepareAndGetImTable(runtime, h_klass, pointer_size, &prepared);
   3045         if (im_table == nullptr) {
   3046           // Should not happen, but accept.
   3047           without_imt++;
   3048           continue;
   3049         }
   3050 
   3051         with_imt++;
   3052         for (size_t imt_index = 0; imt_index != ImTable::kSize; ++imt_index) {
   3053           ArtMethod* ptr = im_table->Get(imt_index, pointer_size);
   3054           if (ptr->IsRuntimeMethod()) {
   3055             if (ptr->IsImtUnimplementedMethod()) {
   3056               histogram[0]++;
   3057             } else {
   3058               ImtConflictTable* current_table = ptr->GetImtConflictTable(pointer_size);
   3059               histogram[current_table->NumEntries(pointer_size)]++;
   3060             }
   3061           } else {
   3062             histogram[1]++;
   3063           }
   3064         }
   3065       }
   3066     }
   3067 
   3068     std::cerr << "IMT stats:"
   3069               << std::endl << std::endl;
   3070 
   3071     std::cerr << "  " << with_imt << " classes with IMT."
   3072               << std::endl << std::endl;
   3073     std::cerr << "  " << without_imt << " classes without IMT (or copy from Object)."
   3074               << std::endl << std::endl;
   3075 
   3076     double sum_one = 0;
   3077     size_t count_one = 0;
   3078 
   3079     std::cerr << "  " << "IMT histogram" << std::endl;
   3080     for (auto& bucket : histogram) {
   3081       std::cerr << "    " << bucket.first << " " << bucket.second << std::endl;
   3082       if (bucket.first > 0) {
   3083         sum_one += bucket.second * bucket.first;
   3084         count_one += bucket.second;
   3085       }
   3086     }
   3087 
   3088     double count_zero = count_one + histogram[0];
   3089     std::cerr << "   Stats:" << std::endl;
   3090     std::cerr << "     Average depth (including empty): " << (sum_one / count_zero) << std::endl;
   3091     std::cerr << "     Average depth (excluding empty): " << (sum_one / count_one) << std::endl;
   3092 
   3093     return true;
   3094   }
   3095 
   3096   // Return whether the given class has no IMT (or the one shared with java.lang.Object).
   3097   static bool HasNoIMT(Runtime* runtime,
   3098                        Handle<mirror::Class> klass,
   3099                        const PointerSize pointer_size,
   3100                        std::unordered_set<std::string>* prepared)
   3101       REQUIRES_SHARED(Locks::mutator_lock_) {
   3102     if (klass->IsObjectClass() || !klass->ShouldHaveImt()) {
   3103       return true;
   3104     }
   3105 
   3106     if (klass->GetImt(pointer_size) == nullptr) {
   3107       PrepareClass(runtime, klass, prepared);
   3108     }
   3109 
   3110     mirror::Class* object_class = mirror::Class::GetJavaLangClass()->GetSuperClass();
   3111     DCHECK(object_class->IsObjectClass());
   3112 
   3113     bool result = klass->GetImt(pointer_size) == object_class->GetImt(pointer_size);
   3114 
   3115     if (klass->GetIfTable()->Count() == 0) {
   3116       DCHECK(result);
   3117     }
   3118 
   3119     return result;
   3120   }
   3121 
   3122   static void PrintTable(ImtConflictTable* table, PointerSize pointer_size)
   3123       REQUIRES_SHARED(Locks::mutator_lock_) {
   3124     if (table == nullptr) {
   3125       std::cerr << "    <No IMT?>" << std::endl;
   3126       return;
   3127     }
   3128     size_t table_index = 0;
   3129     for (;;) {
   3130       ArtMethod* ptr = table->GetInterfaceMethod(table_index, pointer_size);
   3131       if (ptr == nullptr) {
   3132         return;
   3133       }
   3134       table_index++;
   3135       std::cerr << "    " << ptr->PrettyMethod(true) << std::endl;
   3136     }
   3137   }
   3138 
   3139   static ImTable* PrepareAndGetImTable(Runtime* runtime,
   3140                                        Thread* self,
   3141                                        Handle<mirror::ClassLoader> h_loader,
   3142                                        const std::string& class_name,
   3143                                        const PointerSize pointer_size,
   3144                                        mirror::Class** klass_out,
   3145                                        std::unordered_set<std::string>* prepared)
   3146       REQUIRES_SHARED(Locks::mutator_lock_) {
   3147     if (class_name.empty()) {
   3148       return nullptr;
   3149     }
   3150 
   3151     std::string descriptor;
   3152     if (class_name[0] == 'L') {
   3153       descriptor = class_name;
   3154     } else {
   3155       descriptor = DotToDescriptor(class_name.c_str());
   3156     }
   3157 
   3158     mirror::Class* klass = runtime->GetClassLinker()->FindClass(self, descriptor.c_str(), h_loader);
   3159 
   3160     if (klass == nullptr) {
   3161       self->ClearException();
   3162       std::cerr << "Did not find " <<  class_name << std::endl;
   3163       *klass_out = nullptr;
   3164       return nullptr;
   3165     }
   3166 
   3167     StackHandleScope<1> scope(Thread::Current());
   3168     Handle<mirror::Class> h_klass = scope.NewHandle<mirror::Class>(klass);
   3169 
   3170     ImTable* ret = PrepareAndGetImTable(runtime, h_klass, pointer_size, prepared);
   3171     *klass_out = h_klass.Get();
   3172     return ret;
   3173   }
   3174 
   3175   static ImTable* PrepareAndGetImTable(Runtime* runtime,
   3176                                        Handle<mirror::Class> h_klass,
   3177                                        const PointerSize pointer_size,
   3178                                        std::unordered_set<std::string>* prepared)
   3179       REQUIRES_SHARED(Locks::mutator_lock_) {
   3180     PrepareClass(runtime, h_klass, prepared);
   3181     return h_klass->GetImt(pointer_size);
   3182   }
   3183 
   3184   static void DumpIMTForClass(Runtime* runtime,
   3185                               const std::string& class_name,
   3186                               Handle<mirror::ClassLoader> h_loader,
   3187                               std::unordered_set<std::string>* prepared)
   3188       REQUIRES_SHARED(Locks::mutator_lock_) {
   3189     const PointerSize pointer_size = runtime->GetClassLinker()->GetImagePointerSize();
   3190     mirror::Class* klass;
   3191     ImTable* imt = PrepareAndGetImTable(runtime,
   3192                                         Thread::Current(),
   3193                                         h_loader,
   3194                                         class_name,
   3195                                         pointer_size,
   3196                                         &klass,
   3197                                         prepared);
   3198     if (imt == nullptr) {
   3199       return;
   3200     }
   3201 
   3202     std::cerr << class_name << std::endl << " IMT:" << std::endl;
   3203     for (size_t index = 0; index < ImTable::kSize; ++index) {
   3204       std::cerr << "  " << index << ":" << std::endl;
   3205       ArtMethod* ptr = imt->Get(index, pointer_size);
   3206       if (ptr->IsRuntimeMethod()) {
   3207         if (ptr->IsImtUnimplementedMethod()) {
   3208           std::cerr << "    <empty>" << std::endl;
   3209         } else {
   3210           ImtConflictTable* current_table = ptr->GetImtConflictTable(pointer_size);
   3211           PrintTable(current_table, pointer_size);
   3212         }
   3213       } else {
   3214         std::cerr << "    " << ptr->PrettyMethod(true) << std::endl;
   3215       }
   3216     }
   3217 
   3218     std::cerr << " Interfaces:" << std::endl;
   3219     // Run through iftable, find methods that slot here, see if they fit.
   3220     mirror::IfTable* if_table = klass->GetIfTable();
   3221     for (size_t i = 0, num_interfaces = klass->GetIfTableCount(); i < num_interfaces; ++i) {
   3222       mirror::Class* iface = if_table->GetInterface(i);
   3223       std::string iface_name;
   3224       std::cerr << "  " << iface->GetDescriptor(&iface_name) << std::endl;
   3225 
   3226       for (ArtMethod& iface_method : iface->GetVirtualMethods(pointer_size)) {
   3227         uint32_t class_hash, name_hash, signature_hash;
   3228         ImTable::GetImtHashComponents(&iface_method, &class_hash, &name_hash, &signature_hash);
   3229         uint32_t imt_slot = ImTable::GetImtIndex(&iface_method);
   3230         std::cerr << "    " << iface_method.PrettyMethod(true)
   3231             << " slot=" << imt_slot
   3232             << std::hex
   3233             << " class_hash=0x" << class_hash
   3234             << " name_hash=0x" << name_hash
   3235             << " signature_hash=0x" << signature_hash
   3236             << std::dec
   3237             << std::endl;
   3238       }
   3239     }
   3240   }
   3241 
   3242   static void DumpIMTForMethod(Runtime* runtime,
   3243                                const std::string& class_name,
   3244                                const std::string& method,
   3245                                Handle<mirror::ClassLoader> h_loader,
   3246                                std::unordered_set<std::string>* prepared)
   3247       REQUIRES_SHARED(Locks::mutator_lock_) {
   3248     const PointerSize pointer_size = runtime->GetClassLinker()->GetImagePointerSize();
   3249     mirror::Class* klass;
   3250     ImTable* imt = PrepareAndGetImTable(runtime,
   3251                                         Thread::Current(),
   3252                                         h_loader,
   3253                                         class_name,
   3254                                         pointer_size,
   3255                                         &klass,
   3256                                         prepared);
   3257     if (imt == nullptr) {
   3258       return;
   3259     }
   3260 
   3261     std::cerr << class_name << " <" << method << ">" << std::endl;
   3262     for (size_t index = 0; index < ImTable::kSize; ++index) {
   3263       ArtMethod* ptr = imt->Get(index, pointer_size);
   3264       if (ptr->IsRuntimeMethod()) {
   3265         if (ptr->IsImtUnimplementedMethod()) {
   3266           continue;
   3267         }
   3268 
   3269         ImtConflictTable* current_table = ptr->GetImtConflictTable(pointer_size);
   3270         if (current_table == nullptr) {
   3271           continue;
   3272         }
   3273 
   3274         size_t table_index = 0;
   3275         for (;;) {
   3276           ArtMethod* ptr2 = current_table->GetInterfaceMethod(table_index, pointer_size);
   3277           if (ptr2 == nullptr) {
   3278             break;
   3279           }
   3280           table_index++;
   3281 
   3282           std::string p_name = ptr2->PrettyMethod(true);
   3283           if (android::base::StartsWith(p_name, method.c_str())) {
   3284             std::cerr << "  Slot "
   3285                       << index
   3286                       << " ("
   3287                       << current_table->NumEntries(pointer_size)
   3288                       << ")"
   3289                       << std::endl;
   3290             PrintTable(current_table, pointer_size);
   3291             return;
   3292           }
   3293         }
   3294       } else {
   3295         std::string p_name = ptr->PrettyMethod(true);
   3296         if (android::base::StartsWith(p_name, method.c_str())) {
   3297           std::cerr << "  Slot " << index << " (1)" << std::endl;
   3298           std::cerr << "    " << p_name << std::endl;
   3299         } else {
   3300           // Run through iftable, find methods that slot here, see if they fit.
   3301           mirror::IfTable* if_table = klass->GetIfTable();
   3302           for (size_t i = 0, num_interfaces = klass->GetIfTableCount(); i < num_interfaces; ++i) {
   3303             mirror::Class* iface = if_table->GetInterface(i);
   3304             size_t num_methods = iface->NumDeclaredVirtualMethods();
   3305             if (num_methods > 0) {
   3306               for (ArtMethod& iface_method : iface->GetMethods(pointer_size)) {
   3307                 if (ImTable::GetImtIndex(&iface_method) == index) {
   3308                   std::string i_name = iface_method.PrettyMethod(true);
   3309                   if (android::base::StartsWith(i_name, method.c_str())) {
   3310                     std::cerr << "  Slot " << index << " (1)" << std::endl;
   3311                     std::cerr << "    " << p_name << " (" << i_name << ")" << std::endl;
   3312                   }
   3313                 }
   3314               }
   3315             }
   3316           }
   3317         }
   3318       }
   3319     }
   3320   }
   3321 
   3322   // Read lines from the given stream, dropping comments and empty lines
   3323   static std::vector<std::string> ReadCommentedInputStream(std::istream& in_stream) {
   3324     std::vector<std::string> output;
   3325     while (in_stream.good()) {
   3326       std::string dot;
   3327       std::getline(in_stream, dot);
   3328       if (android::base::StartsWith(dot, "#") || dot.empty()) {
   3329         continue;
   3330       }
   3331       output.push_back(dot);
   3332     }
   3333     return output;
   3334   }
   3335 
   3336   // Read lines from the given file, dropping comments and empty lines.
   3337   static std::vector<std::string> ReadCommentedInputFromFile(const std::string& input_filename) {
   3338     std::unique_ptr<std::ifstream> input_file(new std::ifstream(input_filename, std::ifstream::in));
   3339     if (input_file.get() == nullptr) {
   3340       LOG(ERROR) << "Failed to open input file " << input_filename;
   3341       return std::vector<std::string>();
   3342     }
   3343     std::vector<std::string> result = ReadCommentedInputStream(*input_file);
   3344     input_file->close();
   3345     return result;
   3346   }
   3347 
   3348   // Prepare a class, i.e., ensure it has a filled IMT. Will do so recursively for superclasses,
   3349   // and note in the given set that the work was done.
   3350   static void PrepareClass(Runtime* runtime,
   3351                            Handle<mirror::Class> h_klass,
   3352                            std::unordered_set<std::string>* done)
   3353       REQUIRES_SHARED(Locks::mutator_lock_) {
   3354     if (!h_klass->ShouldHaveImt()) {
   3355       return;
   3356     }
   3357 
   3358     std::string name;
   3359     name = h_klass->GetDescriptor(&name);
   3360 
   3361     if (done->find(name) != done->end()) {
   3362       return;
   3363     }
   3364     done->insert(name);
   3365 
   3366     if (h_klass->HasSuperClass()) {
   3367       StackHandleScope<1> h(Thread::Current());
   3368       PrepareClass(runtime, h.NewHandle<mirror::Class>(h_klass->GetSuperClass()), done);
   3369     }
   3370 
   3371     if (!h_klass->IsTemp()) {
   3372       runtime->GetClassLinker()->FillIMTAndConflictTables(h_klass.Get());
   3373     }
   3374   }
   3375 };
   3376 
   3377 struct OatdumpArgs : public CmdlineArgs {
   3378  protected:
   3379   using Base = CmdlineArgs;
   3380 
   3381   virtual ParseStatus ParseCustom(const StringPiece& option,
   3382                                   std::string* error_msg) OVERRIDE {
   3383     {
   3384       ParseStatus base_parse = Base::ParseCustom(option, error_msg);
   3385       if (base_parse != kParseUnknownArgument) {
   3386         return base_parse;
   3387       }
   3388     }
   3389 
   3390     if (option.starts_with("--oat-file=")) {
   3391       oat_filename_ = option.substr(strlen("--oat-file=")).data();
   3392     } else if (option.starts_with("--image=")) {
   3393       image_location_ = option.substr(strlen("--image=")).data();
   3394     } else if (option == "--no-dump:vmap") {
   3395       dump_vmap_ = false;
   3396     } else if (option =="--dump:code_info_stack_maps") {
   3397       dump_code_info_stack_maps_ = true;
   3398     } else if (option == "--no-disassemble") {
   3399       disassemble_code_ = false;
   3400     } else if (option =="--header-only") {
   3401       dump_header_only_ = true;
   3402     } else if (option.starts_with("--symbolize=")) {
   3403       oat_filename_ = option.substr(strlen("--symbolize=")).data();
   3404       symbolize_ = true;
   3405     } else if (option.starts_with("--only-keep-debug")) {
   3406       only_keep_debug_ = true;
   3407     } else if (option.starts_with("--class-filter=")) {
   3408       class_filter_ = option.substr(strlen("--class-filter=")).data();
   3409     } else if (option.starts_with("--method-filter=")) {
   3410       method_filter_ = option.substr(strlen("--method-filter=")).data();
   3411     } else if (option.starts_with("--list-classes")) {
   3412       list_classes_ = true;
   3413     } else if (option.starts_with("--list-methods")) {
   3414       list_methods_ = true;
   3415     } else if (option.starts_with("--export-dex-to=")) {
   3416       export_dex_location_ = option.substr(strlen("--export-dex-to=")).data();
   3417     } else if (option.starts_with("--addr2instr=")) {
   3418       if (!ParseUint(option.substr(strlen("--addr2instr=")).data(), &addr2instr_)) {
   3419         *error_msg = "Address conversion failed";
   3420         return kParseError;
   3421       }
   3422     } else if (option.starts_with("--app-image=")) {
   3423       app_image_ = option.substr(strlen("--app-image=")).data();
   3424     } else if (option.starts_with("--app-oat=")) {
   3425       app_oat_ = option.substr(strlen("--app-oat=")).data();
   3426     } else if (option.starts_with("--dump-imt=")) {
   3427       imt_dump_ = option.substr(strlen("--dump-imt=")).data();
   3428     } else if (option == "--dump-imt-stats") {
   3429       imt_stat_dump_ = true;
   3430     } else {
   3431       return kParseUnknownArgument;
   3432     }
   3433 
   3434     return kParseOk;
   3435   }
   3436 
   3437   virtual ParseStatus ParseChecks(std::string* error_msg) OVERRIDE {
   3438     // Infer boot image location from the image location if possible.
   3439     if (boot_image_location_ == nullptr) {
   3440       boot_image_location_ = image_location_;
   3441     }
   3442 
   3443     // Perform the parent checks.
   3444     ParseStatus parent_checks = Base::ParseChecks(error_msg);
   3445     if (parent_checks != kParseOk) {
   3446       return parent_checks;
   3447     }
   3448 
   3449     // Perform our own checks.
   3450     if (image_location_ == nullptr && oat_filename_ == nullptr) {
   3451       *error_msg = "Either --image or --oat-file must be specified";
   3452       return kParseError;
   3453     } else if (image_location_ != nullptr && oat_filename_ != nullptr) {
   3454       *error_msg = "Either --image or --oat-file must be specified but not both";
   3455       return kParseError;
   3456     }
   3457 
   3458     return kParseOk;
   3459   }
   3460 
   3461   virtual std::string GetUsage() const {
   3462     std::string usage;
   3463 
   3464     usage +=
   3465         "Usage: oatdump [options] ...\n"
   3466         "    Example: oatdump --image=$ANDROID_PRODUCT_OUT/system/framework/boot.art\n"
   3467         "    Example: adb shell oatdump --image=/system/framework/boot.art\n"
   3468         "\n"
   3469         // Either oat-file or image is required.
   3470         "  --oat-file=<file.oat>: specifies an input oat filename.\n"
   3471         "      Example: --oat-file=/system/framework/boot.oat\n"
   3472         "\n"
   3473         "  --image=<file.art>: specifies an input image location.\n"
   3474         "      Example: --image=/system/framework/boot.art\n"
   3475         "\n"
   3476         "  --app-image=<file.art>: specifies an input app image. Must also have a specified\n"
   3477         " boot image (with --image) and app oat file (with --app-oat).\n"
   3478         "      Example: --app-image=app.art\n"
   3479         "\n"
   3480         "  --app-oat=<file.odex>: specifies an input app oat.\n"
   3481         "      Example: --app-oat=app.odex\n"
   3482         "\n";
   3483 
   3484     usage += Base::GetUsage();
   3485 
   3486     usage +=  // Optional.
   3487         "  --no-dump:vmap may be used to disable vmap dumping.\n"
   3488         "      Example: --no-dump:vmap\n"
   3489         "\n"
   3490         "  --dump:code_info_stack_maps enables dumping of stack maps in CodeInfo sections.\n"
   3491         "      Example: --dump:code_info_stack_maps\n"
   3492         "\n"
   3493         "  --no-disassemble may be used to disable disassembly.\n"
   3494         "      Example: --no-disassemble\n"
   3495         "\n"
   3496         "  --header-only may be used to print only the oat header.\n"
   3497         "      Example: --header-only\n"
   3498         "\n"
   3499         "  --list-classes may be used to list target file classes (can be used with filters).\n"
   3500         "      Example: --list-classes\n"
   3501         "      Example: --list-classes --class-filter=com.example.foo\n"
   3502         "\n"
   3503         "  --list-methods may be used to list target file methods (can be used with filters).\n"
   3504         "      Example: --list-methods\n"
   3505         "      Example: --list-methods --class-filter=com.example --method-filter=foo\n"
   3506         "\n"
   3507         "  --symbolize=<file.oat>: output a copy of file.oat with elf symbols included.\n"
   3508         "      Example: --symbolize=/system/framework/boot.oat\n"
   3509         "\n"
   3510         "  --only-keep-debug<file.oat>: Modifies the behaviour of --symbolize so that\n"
   3511         "      .rodata and .text sections are omitted in the output file to save space.\n"
   3512         "      Example: --symbolize=/system/framework/boot.oat --only-keep-debug\n"
   3513         "\n"
   3514         "  --class-filter=<class name>: only dumps classes that contain the filter.\n"
   3515         "      Example: --class-filter=com.example.foo\n"
   3516         "\n"
   3517         "  --method-filter=<method name>: only dumps methods that contain the filter.\n"
   3518         "      Example: --method-filter=foo\n"
   3519         "\n"
   3520         "  --export-dex-to=<directory>: may be used to export oat embedded dex files.\n"
   3521         "      Example: --export-dex-to=/data/local/tmp\n"
   3522         "\n"
   3523         "  --addr2instr=<address>: output matching method disassembled code from relative\n"
   3524         "                          address (e.g. PC from crash dump)\n"
   3525         "      Example: --addr2instr=0x00001a3b\n"
   3526         "\n"
   3527         "  --dump-imt=<file.txt>: output IMT collisions (if any) for the given receiver\n"
   3528         "                         types and interface methods in the given file. The file\n"
   3529         "                         is read line-wise, where each line should either be a class\n"
   3530         "                         name or descriptor, or a class name/descriptor and a prefix\n"
   3531         "                         of a complete method name (separated by a whitespace).\n"
   3532         "      Example: --dump-imt=imt.txt\n"
   3533         "\n"
   3534         "  --dump-imt-stats: output IMT statistics for the given boot image\n"
   3535         "      Example: --dump-imt-stats"
   3536         "\n";
   3537 
   3538     return usage;
   3539   }
   3540 
   3541  public:
   3542   const char* oat_filename_ = nullptr;
   3543   const char* class_filter_ = "";
   3544   const char* method_filter_ = "";
   3545   const char* image_location_ = nullptr;
   3546   std::string elf_filename_prefix_;
   3547   std::string imt_dump_;
   3548   bool dump_vmap_ = true;
   3549   bool dump_code_info_stack_maps_ = false;
   3550   bool disassemble_code_ = true;
   3551   bool symbolize_ = false;
   3552   bool only_keep_debug_ = false;
   3553   bool list_classes_ = false;
   3554   bool list_methods_ = false;
   3555   bool dump_header_only_ = false;
   3556   bool imt_stat_dump_ = false;
   3557   uint32_t addr2instr_ = 0;
   3558   const char* export_dex_location_ = nullptr;
   3559   const char* app_image_ = nullptr;
   3560   const char* app_oat_ = nullptr;
   3561 };
   3562 
   3563 struct OatdumpMain : public CmdlineMain<OatdumpArgs> {
   3564   virtual bool NeedsRuntime() OVERRIDE {
   3565     CHECK(args_ != nullptr);
   3566 
   3567     // If we are only doing the oat file, disable absolute_addresses. Keep them for image dumping.
   3568     bool absolute_addresses = (args_->oat_filename_ == nullptr);
   3569 
   3570     oat_dumper_options_.reset(new OatDumperOptions(
   3571         args_->dump_vmap_,
   3572         args_->dump_code_info_stack_maps_,
   3573         args_->disassemble_code_,
   3574         absolute_addresses,
   3575         args_->class_filter_,
   3576         args_->method_filter_,
   3577         args_->list_classes_,
   3578         args_->list_methods_,
   3579         args_->dump_header_only_,
   3580         args_->export_dex_location_,
   3581         args_->app_image_,
   3582         args_->app_oat_,
   3583         args_->addr2instr_));
   3584 
   3585     return (args_->boot_image_location_ != nullptr ||
   3586             args_->image_location_ != nullptr ||
   3587             !args_->imt_dump_.empty()) &&
   3588           !args_->symbolize_;
   3589   }
   3590 
   3591   virtual bool ExecuteWithoutRuntime() OVERRIDE {
   3592     CHECK(args_ != nullptr);
   3593     CHECK(args_->oat_filename_ != nullptr);
   3594 
   3595     MemMap::Init();
   3596 
   3597     if (args_->symbolize_) {
   3598       // ELF has special kind of section called SHT_NOBITS which allows us to create
   3599       // sections which exist but their data is omitted from the ELF file to save space.
   3600       // This is what "strip --only-keep-debug" does when it creates separate ELF file
   3601       // with only debug data. We use it in similar way to exclude .rodata and .text.
   3602       bool no_bits = args_->only_keep_debug_;
   3603       return SymbolizeOat(args_->oat_filename_, args_->output_name_, no_bits) == EXIT_SUCCESS;
   3604     } else {
   3605       return DumpOat(nullptr,
   3606                      args_->oat_filename_,
   3607                      oat_dumper_options_.get(),
   3608                      args_->os_) == EXIT_SUCCESS;
   3609     }
   3610   }
   3611 
   3612   virtual bool ExecuteWithRuntime(Runtime* runtime) {
   3613     CHECK(args_ != nullptr);
   3614 
   3615     if (!args_->imt_dump_.empty() || args_->imt_stat_dump_) {
   3616       return IMTDumper::Dump(runtime,
   3617                              args_->imt_dump_,
   3618                              args_->imt_stat_dump_,
   3619                              args_->oat_filename_);
   3620     }
   3621 
   3622     if (args_->oat_filename_ != nullptr) {
   3623       return DumpOat(runtime,
   3624                      args_->oat_filename_,
   3625                      oat_dumper_options_.get(),
   3626                      args_->os_) == EXIT_SUCCESS;
   3627     }
   3628 
   3629     return DumpImages(runtime, oat_dumper_options_.get(), args_->os_) == EXIT_SUCCESS;
   3630   }
   3631 
   3632   std::unique_ptr<OatDumperOptions> oat_dumper_options_;
   3633 };
   3634 
   3635 }  // namespace art
   3636 
   3637 int main(int argc, char** argv) {
   3638   art::OatdumpMain main;
   3639   return main.Main(argc, argv);
   3640 }
   3641