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/logging.h"
     30 #include "android-base/stringprintf.h"
     31 #include "android-base/strings.h"
     32 
     33 #include "arch/instruction_set_features.h"
     34 #include "art_field-inl.h"
     35 #include "art_method-inl.h"
     36 #include "base/bit_utils_iterator.h"
     37 #include "base/os.h"
     38 #include "base/safe_map.h"
     39 #include "base/stl_util.h"
     40 #include "base/unix_file/fd_file.h"
     41 #include "class_linker-inl.h"
     42 #include "class_linker.h"
     43 #include "compiled_method.h"
     44 #include "debug/debug_info.h"
     45 #include "debug/elf_debug_writer.h"
     46 #include "debug/method_debug_info.h"
     47 #include "dex/code_item_accessors-inl.h"
     48 #include "dex/descriptors_names.h"
     49 #include "dex/dex_file-inl.h"
     50 #include "dex/dex_instruction-inl.h"
     51 #include "dex/string_reference.h"
     52 #include "disassembler.h"
     53 #include "gc/accounting/space_bitmap-inl.h"
     54 #include "gc/space/image_space.h"
     55 #include "gc/space/large_object_space.h"
     56 #include "gc/space/space-inl.h"
     57 #include "image-inl.h"
     58 #include "imtable-inl.h"
     59 #include "indenter.h"
     60 #include "subtype_check.h"
     61 #include "index_bss_mapping.h"
     62 #include "interpreter/unstarted_runtime.h"
     63 #include "linker/buffered_output_stream.h"
     64 #include "linker/elf_builder.h"
     65 #include "linker/file_output_stream.h"
     66 #include "mirror/array-inl.h"
     67 #include "mirror/class-inl.h"
     68 #include "mirror/dex_cache-inl.h"
     69 #include "mirror/object-inl.h"
     70 #include "mirror/object_array-inl.h"
     71 #include "oat.h"
     72 #include "oat_file-inl.h"
     73 #include "oat_file_manager.h"
     74 #include "scoped_thread_state_change-inl.h"
     75 #include "stack.h"
     76 #include "stack_map.h"
     77 #include "thread_list.h"
     78 #include "type_lookup_table.h"
     79 #include "vdex_file.h"
     80 #include "verifier/method_verifier.h"
     81 #include "verifier/verifier_deps.h"
     82 #include "well_known_classes.h"
     83 
     84 #include <sys/stat.h>
     85 #include "cmdline.h"
     86 
     87 namespace art {
     88 
     89 using android::base::StringPrintf;
     90 
     91 const char* image_methods_descriptions_[] = {
     92   "kResolutionMethod",
     93   "kImtConflictMethod",
     94   "kImtUnimplementedMethod",
     95   "kSaveAllCalleeSavesMethod",
     96   "kSaveRefsOnlyMethod",
     97   "kSaveRefsAndArgsMethod",
     98   "kSaveEverythingMethod",
     99   "kSaveEverythingMethodForClinit",
    100   "kSaveEverythingMethodForSuspendCheck",
    101 };
    102 
    103 const char* image_roots_descriptions_[] = {
    104   "kDexCaches",
    105   "kClassRoots",
    106   "kClassLoader",
    107 };
    108 
    109 // Map is so that we don't allocate multiple dex files for the same OatDexFile.
    110 static std::map<const OatFile::OatDexFile*,
    111                 std::unique_ptr<const DexFile>> opened_dex_files;
    112 
    113 const DexFile* OpenDexFile(const OatFile::OatDexFile* oat_dex_file, std::string* error_msg) {
    114   DCHECK(oat_dex_file != nullptr);
    115   auto it = opened_dex_files.find(oat_dex_file);
    116   if (it != opened_dex_files.end()) {
    117     return it->second.get();
    118   }
    119   const DexFile* ret = oat_dex_file->OpenDexFile(error_msg).release();
    120   opened_dex_files.emplace(oat_dex_file, std::unique_ptr<const DexFile>(ret));
    121   return ret;
    122 }
    123 
    124 template <typename ElfTypes>
    125 class OatSymbolizer FINAL {
    126  public:
    127   OatSymbolizer(const OatFile* oat_file, const std::string& output_name, bool no_bits) :
    128       oat_file_(oat_file),
    129       builder_(nullptr),
    130       output_name_(output_name.empty() ? "symbolized.oat" : output_name),
    131       no_bits_(no_bits) {
    132   }
    133 
    134   bool Symbolize() {
    135     const InstructionSet isa = oat_file_->GetOatHeader().GetInstructionSet();
    136     std::unique_ptr<const InstructionSetFeatures> features = InstructionSetFeatures::FromBitmap(
    137         isa, oat_file_->GetOatHeader().GetInstructionSetFeaturesBitmap());
    138 
    139     std::unique_ptr<File> elf_file(OS::CreateEmptyFile(output_name_.c_str()));
    140     if (elf_file == nullptr) {
    141       return false;
    142     }
    143     std::unique_ptr<linker::BufferedOutputStream> output_stream =
    144         std::make_unique<linker::BufferedOutputStream>(
    145             std::make_unique<linker::FileOutputStream>(elf_file.get()));
    146     builder_.reset(new linker::ElfBuilder<ElfTypes>(isa, features.get(), output_stream.get()));
    147 
    148     builder_->Start();
    149 
    150     auto* rodata = builder_->GetRoData();
    151     auto* text = builder_->GetText();
    152 
    153     const uint8_t* rodata_begin = oat_file_->Begin();
    154     const size_t rodata_size = oat_file_->GetOatHeader().GetExecutableOffset();
    155     if (!no_bits_) {
    156       rodata->Start();
    157       rodata->WriteFully(rodata_begin, rodata_size);
    158       rodata->End();
    159     }
    160 
    161     const uint8_t* text_begin = oat_file_->Begin() + rodata_size;
    162     const size_t text_size = oat_file_->End() - text_begin;
    163     if (!no_bits_) {
    164       text->Start();
    165       text->WriteFully(text_begin, text_size);
    166       text->End();
    167     }
    168 
    169     if (isa == InstructionSet::kMips || isa == InstructionSet::kMips64) {
    170       builder_->WriteMIPSabiflagsSection();
    171     }
    172     builder_->PrepareDynamicSection(elf_file->GetPath(),
    173                                     rodata_size,
    174                                     text_size,
    175                                     oat_file_->BssSize(),
    176                                     oat_file_->BssMethodsOffset(),
    177                                     oat_file_->BssRootsOffset(),
    178                                     oat_file_->VdexSize());
    179     builder_->WriteDynamicSection();
    180 
    181     const OatHeader& oat_header = oat_file_->GetOatHeader();
    182     #define DO_TRAMPOLINE(fn_name)                                                \
    183       if (oat_header.Get ## fn_name ## Offset() != 0) {                           \
    184         debug::MethodDebugInfo info = {};                                         \
    185         info.custom_name = #fn_name;                                              \
    186         info.isa = oat_header.GetInstructionSet();                                \
    187         info.is_code_address_text_relative = true;                                \
    188         size_t code_offset = oat_header.Get ## fn_name ## Offset();               \
    189         code_offset -= CompiledCode::CodeDelta(oat_header.GetInstructionSet());   \
    190         info.code_address = code_offset - oat_header.GetExecutableOffset();       \
    191         info.code_size = 0;  /* The symbol lasts until the next symbol. */        \
    192         method_debug_infos_.push_back(std::move(info));                           \
    193       }
    194     DO_TRAMPOLINE(InterpreterToInterpreterBridge)
    195     DO_TRAMPOLINE(InterpreterToCompiledCodeBridge)
    196     DO_TRAMPOLINE(JniDlsymLookup);
    197     DO_TRAMPOLINE(QuickGenericJniTrampoline);
    198     DO_TRAMPOLINE(QuickImtConflictTrampoline);
    199     DO_TRAMPOLINE(QuickResolutionTrampoline);
    200     DO_TRAMPOLINE(QuickToInterpreterBridge);
    201     #undef DO_TRAMPOLINE
    202 
    203     Walk();
    204 
    205     // TODO: Try to symbolize link-time thunks?
    206     // This would require disassembling all methods to find branches outside the method code.
    207 
    208     // TODO: Add symbols for dex bytecode in the .dex section.
    209 
    210     debug::DebugInfo debug_info{};
    211     debug_info.compiled_methods = ArrayRef<const debug::MethodDebugInfo>(method_debug_infos_);
    212 
    213     debug::WriteDebugInfo(builder_.get(),
    214                           debug_info,
    215                           dwarf::DW_DEBUG_FRAME_FORMAT,
    216                           true /* write_oat_patches */);
    217 
    218     builder_->End();
    219 
    220     bool ret_value = builder_->Good();
    221 
    222     builder_.reset();
    223     output_stream.reset();
    224 
    225     if (elf_file->FlushCloseOrErase() != 0) {
    226       return false;
    227     }
    228     elf_file.reset();
    229 
    230     return ret_value;
    231   }
    232 
    233   void Walk() {
    234     std::vector<const OatFile::OatDexFile*> oat_dex_files = oat_file_->GetOatDexFiles();
    235     for (size_t i = 0; i < oat_dex_files.size(); i++) {
    236       const OatFile::OatDexFile* oat_dex_file = oat_dex_files[i];
    237       CHECK(oat_dex_file != nullptr);
    238       WalkOatDexFile(oat_dex_file);
    239     }
    240   }
    241 
    242   void WalkOatDexFile(const OatFile::OatDexFile* oat_dex_file) {
    243     std::string error_msg;
    244     const DexFile* const dex_file = OpenDexFile(oat_dex_file, &error_msg);
    245     if (dex_file == nullptr) {
    246       return;
    247     }
    248     for (size_t class_def_index = 0;
    249         class_def_index < dex_file->NumClassDefs();
    250         class_def_index++) {
    251       const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index);
    252       OatClassType type = oat_class.GetType();
    253       switch (type) {
    254         case kOatClassAllCompiled:
    255         case kOatClassSomeCompiled:
    256           WalkOatClass(oat_class, *dex_file, class_def_index);
    257           break;
    258 
    259         case kOatClassNoneCompiled:
    260         case kOatClassMax:
    261           // Ignore.
    262           break;
    263       }
    264     }
    265   }
    266 
    267   void WalkOatClass(const OatFile::OatClass& oat_class,
    268                     const DexFile& dex_file,
    269                     uint32_t class_def_index) {
    270     const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
    271     const uint8_t* class_data = dex_file.GetClassData(class_def);
    272     if (class_data == nullptr) {  // empty class such as a marker interface?
    273       return;
    274     }
    275     // Note: even if this is an interface or a native class, we still have to walk it, as there
    276     //       might be a static initializer.
    277     ClassDataItemIterator it(dex_file, class_data);
    278     uint32_t class_method_idx = 0;
    279     it.SkipAllFields();
    280     for (; it.HasNextMethod(); it.Next()) {
    281       WalkOatMethod(oat_class.GetOatMethod(class_method_idx++),
    282                     dex_file,
    283                     class_def_index,
    284                     it.GetMemberIndex(),
    285                     it.GetMethodCodeItem(),
    286                     it.GetMethodAccessFlags());
    287     }
    288     DCHECK(!it.HasNext());
    289   }
    290 
    291   void WalkOatMethod(const OatFile::OatMethod& oat_method,
    292                      const DexFile& dex_file,
    293                      uint32_t class_def_index,
    294                      uint32_t dex_method_index,
    295                      const DexFile::CodeItem* code_item,
    296                      uint32_t method_access_flags) {
    297     if ((method_access_flags & kAccAbstract) != 0) {
    298       // Abstract method, no code.
    299       return;
    300     }
    301     const OatHeader& oat_header = oat_file_->GetOatHeader();
    302     const OatQuickMethodHeader* method_header = oat_method.GetOatQuickMethodHeader();
    303     if (method_header == nullptr || method_header->GetCodeSize() == 0) {
    304       // No code.
    305       return;
    306     }
    307 
    308     uint32_t entry_point = oat_method.GetCodeOffset() - oat_header.GetExecutableOffset();
    309     // Clear Thumb2 bit.
    310     const void* code_address = EntryPointToCodePointer(reinterpret_cast<void*>(entry_point));
    311 
    312     debug::MethodDebugInfo info = {};
    313     DCHECK(info.custom_name.empty());
    314     info.dex_file = &dex_file;
    315     info.class_def_index = class_def_index;
    316     info.dex_method_index = dex_method_index;
    317     info.access_flags = method_access_flags;
    318     info.code_item = code_item;
    319     info.isa = oat_header.GetInstructionSet();
    320     info.deduped = !seen_offsets_.insert(oat_method.GetCodeOffset()).second;
    321     info.is_native_debuggable = oat_header.IsNativeDebuggable();
    322     info.is_optimized = method_header->IsOptimized();
    323     info.is_code_address_text_relative = true;
    324     info.code_address = reinterpret_cast<uintptr_t>(code_address);
    325     info.code_size = method_header->GetCodeSize();
    326     info.frame_size_in_bytes = method_header->GetFrameSizeInBytes();
    327     info.code_info = info.is_optimized ? method_header->GetOptimizedCodeInfoPtr() : nullptr;
    328     info.cfi = ArrayRef<uint8_t>();
    329     method_debug_infos_.push_back(info);
    330   }
    331 
    332  private:
    333   const OatFile* oat_file_;
    334   std::unique_ptr<linker::ElfBuilder<ElfTypes>> builder_;
    335   std::vector<debug::MethodDebugInfo> method_debug_infos_;
    336   std::unordered_set<uint32_t> seen_offsets_;
    337   const std::string output_name_;
    338   bool no_bits_;
    339 };
    340 
    341 class OatDumperOptions {
    342  public:
    343   OatDumperOptions(bool dump_vmap,
    344                    bool dump_code_info_stack_maps,
    345                    bool disassemble_code,
    346                    bool absolute_addresses,
    347                    const char* class_filter,
    348                    const char* method_filter,
    349                    bool list_classes,
    350                    bool list_methods,
    351                    bool dump_header_only,
    352                    const char* export_dex_location,
    353                    const char* app_image,
    354                    const char* app_oat,
    355                    uint32_t addr2instr)
    356     : dump_vmap_(dump_vmap),
    357       dump_code_info_stack_maps_(dump_code_info_stack_maps),
    358       disassemble_code_(disassemble_code),
    359       absolute_addresses_(absolute_addresses),
    360       class_filter_(class_filter),
    361       method_filter_(method_filter),
    362       list_classes_(list_classes),
    363       list_methods_(list_methods),
    364       dump_header_only_(dump_header_only),
    365       export_dex_location_(export_dex_location),
    366       app_image_(app_image),
    367       app_oat_(app_oat),
    368       addr2instr_(addr2instr),
    369       class_loader_(nullptr) {}
    370 
    371   const bool dump_vmap_;
    372   const bool dump_code_info_stack_maps_;
    373   const bool disassemble_code_;
    374   const bool absolute_addresses_;
    375   const char* const class_filter_;
    376   const char* const method_filter_;
    377   const bool list_classes_;
    378   const bool list_methods_;
    379   const bool dump_header_only_;
    380   const char* const export_dex_location_;
    381   const char* const app_image_;
    382   const char* const app_oat_;
    383   uint32_t addr2instr_;
    384   Handle<mirror::ClassLoader>* class_loader_;
    385 };
    386 
    387 class OatDumper {
    388  public:
    389   OatDumper(const OatFile& oat_file, const OatDumperOptions& options)
    390     : oat_file_(oat_file),
    391       oat_dex_files_(oat_file.GetOatDexFiles()),
    392       options_(options),
    393       resolved_addr2instr_(0),
    394       instruction_set_(oat_file_.GetOatHeader().GetInstructionSet()),
    395       disassembler_(Disassembler::Create(instruction_set_,
    396                                          new DisassemblerOptions(
    397                                              options_.absolute_addresses_,
    398                                              oat_file.Begin(),
    399                                              oat_file.End(),
    400                                              true /* can_read_literals_ */,
    401                                              Is64BitInstructionSet(instruction_set_)
    402                                                  ? &Thread::DumpThreadOffset<PointerSize::k64>
    403                                                  : &Thread::DumpThreadOffset<PointerSize::k32>))) {
    404     CHECK(options_.class_loader_ != nullptr);
    405     CHECK(options_.class_filter_ != nullptr);
    406     CHECK(options_.method_filter_ != nullptr);
    407     AddAllOffsets();
    408   }
    409 
    410   ~OatDumper() {
    411     delete disassembler_;
    412   }
    413 
    414   InstructionSet GetInstructionSet() {
    415     return instruction_set_;
    416   }
    417 
    418   typedef std::vector<std::unique_ptr<const DexFile>> DexFileUniqV;
    419 
    420   bool Dump(std::ostream& os) {
    421     bool success = true;
    422     const OatHeader& oat_header = oat_file_.GetOatHeader();
    423 
    424     os << "MAGIC:\n";
    425     os << oat_header.GetMagic() << "\n\n";
    426 
    427     os << "LOCATION:\n";
    428     os << oat_file_.GetLocation() << "\n\n";
    429 
    430     os << "CHECKSUM:\n";
    431     os << StringPrintf("0x%08x\n\n", oat_header.GetChecksum());
    432 
    433     os << "INSTRUCTION SET:\n";
    434     os << oat_header.GetInstructionSet() << "\n\n";
    435 
    436     {
    437       std::unique_ptr<const InstructionSetFeatures> features(
    438           InstructionSetFeatures::FromBitmap(oat_header.GetInstructionSet(),
    439                                              oat_header.GetInstructionSetFeaturesBitmap()));
    440       os << "INSTRUCTION SET FEATURES:\n";
    441       os << features->GetFeatureString() << "\n\n";
    442     }
    443 
    444     os << "DEX FILE COUNT:\n";
    445     os << oat_header.GetDexFileCount() << "\n\n";
    446 
    447 #define DUMP_OAT_HEADER_OFFSET(label, offset) \
    448     os << label " OFFSET:\n"; \
    449     os << StringPrintf("0x%08x", oat_header.offset()); \
    450     if (oat_header.offset() != 0 && options_.absolute_addresses_) { \
    451       os << StringPrintf(" (%p)", oat_file_.Begin() + oat_header.offset()); \
    452     } \
    453     os << StringPrintf("\n\n");
    454 
    455     DUMP_OAT_HEADER_OFFSET("EXECUTABLE", GetExecutableOffset);
    456     DUMP_OAT_HEADER_OFFSET("INTERPRETER TO INTERPRETER BRIDGE",
    457                            GetInterpreterToInterpreterBridgeOffset);
    458     DUMP_OAT_HEADER_OFFSET("INTERPRETER TO COMPILED CODE BRIDGE",
    459                            GetInterpreterToCompiledCodeBridgeOffset);
    460     DUMP_OAT_HEADER_OFFSET("JNI DLSYM LOOKUP",
    461                            GetJniDlsymLookupOffset);
    462     DUMP_OAT_HEADER_OFFSET("QUICK GENERIC JNI TRAMPOLINE",
    463                            GetQuickGenericJniTrampolineOffset);
    464     DUMP_OAT_HEADER_OFFSET("QUICK IMT CONFLICT TRAMPOLINE",
    465                            GetQuickImtConflictTrampolineOffset);
    466     DUMP_OAT_HEADER_OFFSET("QUICK RESOLUTION TRAMPOLINE",
    467                            GetQuickResolutionTrampolineOffset);
    468     DUMP_OAT_HEADER_OFFSET("QUICK TO INTERPRETER BRIDGE",
    469                            GetQuickToInterpreterBridgeOffset);
    470 #undef DUMP_OAT_HEADER_OFFSET
    471 
    472     os << "IMAGE PATCH DELTA:\n";
    473     os << StringPrintf("%d (0x%08x)\n\n",
    474                        oat_header.GetImagePatchDelta(),
    475                        oat_header.GetImagePatchDelta());
    476 
    477     os << "IMAGE FILE LOCATION OAT CHECKSUM:\n";
    478     os << StringPrintf("0x%08x\n\n", oat_header.GetImageFileLocationOatChecksum());
    479 
    480     os << "IMAGE FILE LOCATION OAT BEGIN:\n";
    481     os << StringPrintf("0x%08x\n\n", oat_header.GetImageFileLocationOatDataBegin());
    482 
    483     // Print the key-value store.
    484     {
    485       os << "KEY VALUE STORE:\n";
    486       size_t index = 0;
    487       const char* key;
    488       const char* value;
    489       while (oat_header.GetStoreKeyValuePairByIndex(index, &key, &value)) {
    490         os << key << " = " << value << "\n";
    491         index++;
    492       }
    493       os << "\n";
    494     }
    495 
    496     if (options_.absolute_addresses_) {
    497       os << "BEGIN:\n";
    498       os << reinterpret_cast<const void*>(oat_file_.Begin()) << "\n\n";
    499 
    500       os << "END:\n";
    501       os << reinterpret_cast<const void*>(oat_file_.End()) << "\n\n";
    502     }
    503 
    504     os << "SIZE:\n";
    505     os << oat_file_.Size() << "\n\n";
    506 
    507     os << std::flush;
    508 
    509     // If set, adjust relative address to be searched
    510     if (options_.addr2instr_ != 0) {
    511       resolved_addr2instr_ = options_.addr2instr_ + oat_header.GetExecutableOffset();
    512       os << "SEARCH ADDRESS (executable offset + input):\n";
    513       os << StringPrintf("0x%08x\n\n", resolved_addr2instr_);
    514     }
    515 
    516     // Dumping the dex file overview is compact enough to do even if header only.
    517     DexFileData cumulative;
    518     for (size_t i = 0; i < oat_dex_files_.size(); i++) {
    519       const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
    520       CHECK(oat_dex_file != nullptr);
    521       std::string error_msg;
    522       const DexFile* const dex_file = OpenDexFile(oat_dex_file, &error_msg);
    523       if (dex_file == nullptr) {
    524         os << "Failed to open dex file '" << oat_dex_file->GetDexFileLocation() << "': "
    525            << error_msg;
    526         continue;
    527       }
    528       DexFileData data(*dex_file);
    529       os << "Dex file data for " << dex_file->GetLocation() << "\n";
    530       data.Dump(os);
    531       os << "\n";
    532       const DexLayoutSections* const layout_sections = oat_dex_file->GetDexLayoutSections();
    533       if (layout_sections != nullptr) {
    534         os << "Layout data\n";
    535         os << *layout_sections;
    536         os << "\n";
    537       }
    538 
    539       cumulative.Add(data);
    540 
    541       // Dump .bss entries.
    542       DumpBssEntries(
    543           os,
    544           "ArtMethod",
    545           oat_dex_file->GetMethodBssMapping(),
    546           dex_file->NumMethodIds(),
    547           static_cast<size_t>(GetInstructionSetPointerSize(instruction_set_)),
    548           [=](uint32_t index) { return dex_file->PrettyMethod(index); });
    549       DumpBssEntries(
    550           os,
    551           "Class",
    552           oat_dex_file->GetTypeBssMapping(),
    553           dex_file->NumTypeIds(),
    554           sizeof(GcRoot<mirror::Class>),
    555           [=](uint32_t index) { return dex_file->PrettyType(dex::TypeIndex(index)); });
    556       DumpBssEntries(
    557           os,
    558           "String",
    559           oat_dex_file->GetStringBssMapping(),
    560           dex_file->NumStringIds(),
    561           sizeof(GcRoot<mirror::Class>),
    562           [=](uint32_t index) { return dex_file->StringDataByIdx(dex::StringIndex(index)); });
    563     }
    564     os << "Cumulative dex file data\n";
    565     cumulative.Dump(os);
    566     os << "\n";
    567 
    568     if (!options_.dump_header_only_) {
    569       VariableIndentationOutputStream vios(&os);
    570       VdexFile::VerifierDepsHeader vdex_header = oat_file_.GetVdexFile()->GetVerifierDepsHeader();
    571       if (vdex_header.IsValid()) {
    572         std::string error_msg;
    573         std::vector<const DexFile*> dex_files;
    574         for (size_t i = 0; i < oat_dex_files_.size(); i++) {
    575           const DexFile* dex_file = OpenDexFile(oat_dex_files_[i], &error_msg);
    576           if (dex_file == nullptr) {
    577             os << "Error opening dex file: " << error_msg << std::endl;
    578             return false;
    579           }
    580           dex_files.push_back(dex_file);
    581         }
    582         verifier::VerifierDeps deps(dex_files, oat_file_.GetVdexFile()->GetVerifierDepsData());
    583         deps.Dump(&vios);
    584       } else {
    585         os << "UNRECOGNIZED vdex file, magic "
    586            << vdex_header.GetMagic()
    587            << ", verifier deps version "
    588            << vdex_header.GetVerifierDepsVersion()
    589            << ", dex section version "
    590            << vdex_header.GetDexSectionVersion()
    591            << "\n";
    592       }
    593       for (size_t i = 0; i < oat_dex_files_.size(); i++) {
    594         const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
    595         CHECK(oat_dex_file != nullptr);
    596         if (!DumpOatDexFile(os, *oat_dex_file)) {
    597           success = false;
    598         }
    599       }
    600     }
    601 
    602     if (options_.export_dex_location_) {
    603       std::string error_msg;
    604       std::string vdex_filename = GetVdexFilename(oat_file_.GetLocation());
    605       if (!OS::FileExists(vdex_filename.c_str())) {
    606         os << "File " << vdex_filename.c_str() << " does not exist\n";
    607         return false;
    608       }
    609 
    610       DexFileUniqV vdex_dex_files;
    611       std::unique_ptr<const VdexFile> vdex_file = OpenVdexUnquicken(vdex_filename,
    612                                                                     &vdex_dex_files,
    613                                                                     &error_msg);
    614       if (vdex_file.get() == nullptr) {
    615         os << "Failed to open vdex file: " << error_msg << "\n";
    616         return false;
    617       }
    618       if (oat_dex_files_.size() != vdex_dex_files.size()) {
    619         os << "Dex files number in Vdex file does not match Dex files number in Oat file: "
    620            << vdex_dex_files.size() << " vs " << oat_dex_files_.size() << '\n';
    621         return false;
    622       }
    623 
    624       size_t i = 0;
    625       for (const auto& vdex_dex_file : vdex_dex_files) {
    626         const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
    627         CHECK(oat_dex_file != nullptr);
    628         CHECK(vdex_dex_file != nullptr);
    629         if (!ExportDexFile(os, *oat_dex_file, vdex_dex_file.get())) {
    630           success = false;
    631         }
    632         i++;
    633       }
    634     }
    635 
    636     {
    637       os << "OAT FILE STATS:\n";
    638       VariableIndentationOutputStream vios(&os);
    639       stats_.Dump(vios);
    640     }
    641 
    642     os << std::flush;
    643     return success;
    644   }
    645 
    646   size_t ComputeSize(const void* oat_data) {
    647     if (reinterpret_cast<const uint8_t*>(oat_data) < oat_file_.Begin() ||
    648         reinterpret_cast<const uint8_t*>(oat_data) > oat_file_.End()) {
    649       return 0;  // Address not in oat file
    650     }
    651     uintptr_t begin_offset = reinterpret_cast<uintptr_t>(oat_data) -
    652                              reinterpret_cast<uintptr_t>(oat_file_.Begin());
    653     auto it = offsets_.upper_bound(begin_offset);
    654     CHECK(it != offsets_.end());
    655     uintptr_t end_offset = *it;
    656     return end_offset - begin_offset;
    657   }
    658 
    659   InstructionSet GetOatInstructionSet() {
    660     return oat_file_.GetOatHeader().GetInstructionSet();
    661   }
    662 
    663   const void* GetQuickOatCode(ArtMethod* m) REQUIRES_SHARED(Locks::mutator_lock_) {
    664     for (size_t i = 0; i < oat_dex_files_.size(); i++) {
    665       const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
    666       CHECK(oat_dex_file != nullptr);
    667       std::string error_msg;
    668       const DexFile* const dex_file = OpenDexFile(oat_dex_file, &error_msg);
    669       if (dex_file == nullptr) {
    670         LOG(WARNING) << "Failed to open dex file '" << oat_dex_file->GetDexFileLocation()
    671             << "': " << error_msg;
    672       } else {
    673         const char* descriptor = m->GetDeclaringClassDescriptor();
    674         const DexFile::ClassDef* class_def =
    675             OatDexFile::FindClassDef(*dex_file, descriptor, ComputeModifiedUtf8Hash(descriptor));
    676         if (class_def != nullptr) {
    677           uint16_t class_def_index = dex_file->GetIndexForClassDef(*class_def);
    678           const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index);
    679           size_t method_index = m->GetMethodIndex();
    680           return oat_class.GetOatMethod(method_index).GetQuickCode();
    681         }
    682       }
    683     }
    684     return nullptr;
    685   }
    686 
    687   // Returns nullptr and updates error_msg if the Vdex file cannot be opened, otherwise all Dex
    688   // files are fully unquickened and stored in dex_files
    689   std::unique_ptr<const VdexFile> OpenVdexUnquicken(const std::string& vdex_filename,
    690                                                     /* out */ DexFileUniqV* dex_files,
    691                                                     /* out */ std::string* error_msg) {
    692     std::unique_ptr<const File> file(OS::OpenFileForReading(vdex_filename.c_str()));
    693     if (file == nullptr) {
    694       *error_msg = "Could not open file " + vdex_filename + " for reading.";
    695       return nullptr;
    696     }
    697 
    698     int64_t vdex_length = file->GetLength();
    699     if (vdex_length == -1) {
    700       *error_msg = "Could not read the length of file " + vdex_filename;
    701       return nullptr;
    702     }
    703 
    704     std::unique_ptr<MemMap> mmap(MemMap::MapFile(
    705         file->GetLength(),
    706         PROT_READ | PROT_WRITE,
    707         MAP_PRIVATE,
    708         file->Fd(),
    709         /* start offset */ 0,
    710         /* low_4gb */ false,
    711         vdex_filename.c_str(),
    712         error_msg));
    713     if (mmap == nullptr) {
    714       *error_msg = "Failed to mmap file " + vdex_filename + ": " + *error_msg;
    715       return nullptr;
    716     }
    717 
    718     std::unique_ptr<VdexFile> vdex_file(new VdexFile(mmap.release()));
    719     if (!vdex_file->IsValid()) {
    720       *error_msg = "Vdex file is not valid";
    721       return nullptr;
    722     }
    723 
    724     DexFileUniqV tmp_dex_files;
    725     if (!vdex_file->OpenAllDexFiles(&tmp_dex_files, error_msg)) {
    726       *error_msg = "Failed to open Dex files from Vdex: " + *error_msg;
    727       return nullptr;
    728     }
    729 
    730     vdex_file->Unquicken(MakeNonOwningPointerVector(tmp_dex_files),
    731                          /* decompile_return_instruction */ true);
    732 
    733     *dex_files = std::move(tmp_dex_files);
    734     return vdex_file;
    735   }
    736 
    737   struct Stats {
    738     enum ByteKind {
    739       kByteKindCode,
    740       kByteKindQuickMethodHeader,
    741       kByteKindCodeInfoLocationCatalog,
    742       kByteKindCodeInfoDexRegisterMap,
    743       kByteKindCodeInfoEncoding,
    744       kByteKindCodeInfoInvokeInfo,
    745       kByteKindCodeInfoStackMasks,
    746       kByteKindCodeInfoRegisterMasks,
    747       kByteKindStackMapNativePc,
    748       kByteKindStackMapDexPc,
    749       kByteKindStackMapDexRegisterMap,
    750       kByteKindStackMapInlineInfoIndex,
    751       kByteKindStackMapRegisterMaskIndex,
    752       kByteKindStackMapStackMaskIndex,
    753       kByteKindInlineInfoMethodIndexIdx,
    754       kByteKindInlineInfoDexPc,
    755       kByteKindInlineInfoExtraData,
    756       kByteKindInlineInfoDexRegisterMap,
    757       kByteKindInlineInfoIsLast,
    758       kByteKindCount,
    759       // Special ranges for std::accumulate convenience.
    760       kByteKindStackMapFirst = kByteKindStackMapNativePc,
    761       kByteKindStackMapLast = kByteKindStackMapStackMaskIndex,
    762       kByteKindInlineInfoFirst = kByteKindInlineInfoMethodIndexIdx,
    763       kByteKindInlineInfoLast = kByteKindInlineInfoIsLast,
    764     };
    765     int64_t bits[kByteKindCount] = {};
    766     // Since code has deduplication, seen tracks already seen pointers to avoid double counting
    767     // deduplicated code and tables.
    768     std::unordered_set<const void*> seen;
    769 
    770     // Returns true if it was newly added.
    771     bool AddBitsIfUnique(ByteKind kind, int64_t count, const void* address) {
    772       if (seen.insert(address).second == true) {
    773         // True means the address was not already in the set.
    774         AddBits(kind, count);
    775         return true;
    776       }
    777       return false;
    778     }
    779 
    780     void AddBits(ByteKind kind, int64_t count) {
    781       bits[kind] += count;
    782     }
    783 
    784     void Dump(VariableIndentationOutputStream& os) {
    785       const int64_t sum = std::accumulate(bits, bits + kByteKindCount, 0u);
    786       os.Stream() << "Dumping cumulative use of " << sum / kBitsPerByte << " accounted bytes\n";
    787       if (sum > 0) {
    788         Dump(os, "Code                            ", bits[kByteKindCode], sum);
    789         Dump(os, "QuickMethodHeader               ", bits[kByteKindQuickMethodHeader], sum);
    790         Dump(os, "CodeInfoEncoding                ", bits[kByteKindCodeInfoEncoding], sum);
    791         Dump(os, "CodeInfoLocationCatalog         ", bits[kByteKindCodeInfoLocationCatalog], sum);
    792         Dump(os, "CodeInfoDexRegisterMap          ", bits[kByteKindCodeInfoDexRegisterMap], sum);
    793         Dump(os, "CodeInfoStackMasks              ", bits[kByteKindCodeInfoStackMasks], sum);
    794         Dump(os, "CodeInfoRegisterMasks           ", bits[kByteKindCodeInfoRegisterMasks], sum);
    795         Dump(os, "CodeInfoInvokeInfo              ", bits[kByteKindCodeInfoInvokeInfo], sum);
    796         // Stack map section.
    797         const int64_t stack_map_bits = std::accumulate(bits + kByteKindStackMapFirst,
    798                                                        bits + kByteKindStackMapLast + 1,
    799                                                        0u);
    800         Dump(os, "CodeInfoStackMap                ", stack_map_bits, sum);
    801         {
    802           ScopedIndentation indent1(&os);
    803           Dump(os,
    804                "StackMapNativePc              ",
    805                bits[kByteKindStackMapNativePc],
    806                stack_map_bits,
    807                "stack map");
    808           Dump(os,
    809                "StackMapDexPcEncoding         ",
    810                bits[kByteKindStackMapDexPc],
    811                stack_map_bits,
    812                "stack map");
    813           Dump(os,
    814                "StackMapDexRegisterMap        ",
    815                bits[kByteKindStackMapDexRegisterMap],
    816                stack_map_bits,
    817                "stack map");
    818           Dump(os,
    819                "StackMapInlineInfoIndex       ",
    820                bits[kByteKindStackMapInlineInfoIndex],
    821                stack_map_bits,
    822                "stack map");
    823           Dump(os,
    824                "StackMapRegisterMaskIndex     ",
    825                bits[kByteKindStackMapRegisterMaskIndex],
    826                stack_map_bits,
    827                "stack map");
    828           Dump(os,
    829                "StackMapStackMaskIndex        ",
    830                bits[kByteKindStackMapStackMaskIndex],
    831                stack_map_bits,
    832                "stack map");
    833         }
    834         // Inline info section.
    835         const int64_t inline_info_bits = std::accumulate(bits + kByteKindInlineInfoFirst,
    836                                                          bits + kByteKindInlineInfoLast + 1,
    837                                                          0u);
    838         Dump(os, "CodeInfoInlineInfo              ", inline_info_bits, sum);
    839         {
    840           ScopedIndentation indent1(&os);
    841           Dump(os,
    842                "InlineInfoMethodIndexIdx      ",
    843                bits[kByteKindInlineInfoMethodIndexIdx],
    844                inline_info_bits,
    845                "inline info");
    846           Dump(os,
    847                "InlineInfoDexPc               ",
    848                bits[kByteKindStackMapDexPc],
    849                inline_info_bits,
    850                "inline info");
    851           Dump(os,
    852                "InlineInfoExtraData           ",
    853                bits[kByteKindInlineInfoExtraData],
    854                inline_info_bits,
    855                "inline info");
    856           Dump(os,
    857                "InlineInfoDexRegisterMap      ",
    858                bits[kByteKindInlineInfoDexRegisterMap],
    859                inline_info_bits,
    860                "inline info");
    861           Dump(os,
    862                "InlineInfoIsLast              ",
    863                bits[kByteKindInlineInfoIsLast],
    864                inline_info_bits,
    865                "inline info");
    866         }
    867       }
    868       os.Stream() << "\n" << std::flush;
    869     }
    870 
    871    private:
    872     void Dump(VariableIndentationOutputStream& os,
    873               const char* name,
    874               int64_t size,
    875               int64_t total,
    876               const char* sum_of = "total") {
    877       const double percent = (static_cast<double>(size) / static_cast<double>(total)) * 100;
    878       os.Stream() << StringPrintf("%s = %8" PRId64 " (%2.0f%% of %s)\n",
    879                                   name,
    880                                   size / kBitsPerByte,
    881                                   percent,
    882                                   sum_of);
    883     }
    884   };
    885 
    886  private:
    887   void AddAllOffsets() {
    888     // We don't know the length of the code for each method, but we need to know where to stop
    889     // when disassembling. What we do know is that a region of code will be followed by some other
    890     // region, so if we keep a sorted sequence of the start of each region, we can infer the length
    891     // of a piece of code by using upper_bound to find the start of the next region.
    892     for (size_t i = 0; i < oat_dex_files_.size(); i++) {
    893       const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
    894       CHECK(oat_dex_file != nullptr);
    895       std::string error_msg;
    896       const DexFile* const dex_file = OpenDexFile(oat_dex_file, &error_msg);
    897       if (dex_file == nullptr) {
    898         LOG(WARNING) << "Failed to open dex file '" << oat_dex_file->GetDexFileLocation()
    899             << "': " << error_msg;
    900         continue;
    901       }
    902       offsets_.insert(reinterpret_cast<uintptr_t>(&dex_file->GetHeader()));
    903       for (size_t class_def_index = 0;
    904            class_def_index < dex_file->NumClassDefs();
    905            class_def_index++) {
    906         const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
    907         const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index);
    908         const uint8_t* class_data = dex_file->GetClassData(class_def);
    909         if (class_data != nullptr) {
    910           ClassDataItemIterator it(*dex_file, class_data);
    911           it.SkipAllFields();
    912           uint32_t class_method_index = 0;
    913           while (it.HasNextMethod()) {
    914             AddOffsets(oat_class.GetOatMethod(class_method_index++));
    915             it.Next();
    916           }
    917         }
    918       }
    919     }
    920 
    921     // If the last thing in the file is code for a method, there won't be an offset for the "next"
    922     // thing. Instead of having a special case in the upper_bound code, let's just add an entry
    923     // for the end of the file.
    924     offsets_.insert(oat_file_.Size());
    925   }
    926 
    927   static uint32_t AlignCodeOffset(uint32_t maybe_thumb_offset) {
    928     return maybe_thumb_offset & ~0x1;  // TODO: Make this Thumb2 specific.
    929   }
    930 
    931   void AddOffsets(const OatFile::OatMethod& oat_method) {
    932     uint32_t code_offset = oat_method.GetCodeOffset();
    933     if (oat_file_.GetOatHeader().GetInstructionSet() == InstructionSet::kThumb2) {
    934       code_offset &= ~0x1;
    935     }
    936     offsets_.insert(code_offset);
    937     offsets_.insert(oat_method.GetVmapTableOffset());
    938   }
    939 
    940   // Dex file data, may be for multiple different dex files.
    941   class DexFileData {
    942    public:
    943     DexFileData() {}
    944 
    945     explicit DexFileData(const DexFile& dex_file)
    946         : num_string_ids_(dex_file.NumStringIds()),
    947           num_method_ids_(dex_file.NumMethodIds()),
    948           num_field_ids_(dex_file.NumFieldIds()),
    949           num_type_ids_(dex_file.NumTypeIds()),
    950           num_class_defs_(dex_file.NumClassDefs()) {
    951       for (size_t class_def_index = 0; class_def_index < num_class_defs_; ++class_def_index) {
    952         const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
    953         WalkClass(dex_file, class_def);
    954       }
    955     }
    956 
    957     void Add(const DexFileData& other) {
    958       AddAll(unique_string_ids_from_code_, other.unique_string_ids_from_code_);
    959       num_string_ids_from_code_ += other.num_string_ids_from_code_;
    960       AddAll(dex_code_item_ptrs_, other.dex_code_item_ptrs_);
    961       dex_code_bytes_ += other.dex_code_bytes_;
    962       num_string_ids_ += other.num_string_ids_;
    963       num_method_ids_ += other.num_method_ids_;
    964       num_field_ids_ += other.num_field_ids_;
    965       num_type_ids_ += other.num_type_ids_;
    966       num_class_defs_ += other.num_class_defs_;
    967     }
    968 
    969     void Dump(std::ostream& os) {
    970       os << "Num string ids: " << num_string_ids_ << "\n";
    971       os << "Num method ids: " << num_method_ids_ << "\n";
    972       os << "Num field ids: " << num_field_ids_ << "\n";
    973       os << "Num type ids: " << num_type_ids_ << "\n";
    974       os << "Num class defs: " << num_class_defs_ << "\n";
    975       os << "Unique strings loaded from dex code: " << unique_string_ids_from_code_.size() << "\n";
    976       os << "Total strings loaded from dex code: " << num_string_ids_from_code_ << "\n";
    977       os << "Number of unique dex code items: " << dex_code_item_ptrs_.size() << "\n";
    978       os << "Total number of dex code bytes: " << dex_code_bytes_ << "\n";
    979     }
    980 
    981    private:
    982     // All of the elements from one container to another.
    983     template <typename Dest, typename Src>
    984     static void AddAll(Dest& dest, const Src& src) {
    985       dest.insert(src.begin(), src.end());
    986     }
    987 
    988     void WalkClass(const DexFile& dex_file, const DexFile::ClassDef& class_def) {
    989       const uint8_t* class_data = dex_file.GetClassData(class_def);
    990       if (class_data == nullptr) {  // empty class such as a marker interface?
    991         return;
    992       }
    993       ClassDataItemIterator it(dex_file, class_data);
    994       it.SkipAllFields();
    995       while (it.HasNextMethod()) {
    996         WalkCodeItem(dex_file, it.GetMethodCodeItem());
    997         it.Next();
    998       }
    999       DCHECK(!it.HasNext());
   1000     }
   1001 
   1002     void WalkCodeItem(const DexFile& dex_file, const DexFile::CodeItem* code_item) {
   1003       if (code_item == nullptr) {
   1004         return;
   1005       }
   1006       CodeItemInstructionAccessor instructions(dex_file, code_item);
   1007 
   1008       // If we inserted a new dex code item pointer, add to total code bytes.
   1009       const uint16_t* code_ptr = instructions.Insns();
   1010       if (dex_code_item_ptrs_.insert(code_ptr).second) {
   1011         dex_code_bytes_ += instructions.InsnsSizeInCodeUnits() * sizeof(code_ptr[0]);
   1012       }
   1013 
   1014       for (const DexInstructionPcPair& inst : instructions) {
   1015         switch (inst->Opcode()) {
   1016           case Instruction::CONST_STRING: {
   1017             const dex::StringIndex string_index(inst->VRegB_21c());
   1018             unique_string_ids_from_code_.insert(StringReference(&dex_file, string_index));
   1019             ++num_string_ids_from_code_;
   1020             break;
   1021           }
   1022           case Instruction::CONST_STRING_JUMBO: {
   1023             const dex::StringIndex string_index(inst->VRegB_31c());
   1024             unique_string_ids_from_code_.insert(StringReference(&dex_file, string_index));
   1025             ++num_string_ids_from_code_;
   1026             break;
   1027           }
   1028           default:
   1029             break;
   1030         }
   1031       }
   1032     }
   1033 
   1034     // Unique string ids loaded from dex code.
   1035     std::set<StringReference> unique_string_ids_from_code_;
   1036 
   1037     // Total string ids loaded from dex code.
   1038     size_t num_string_ids_from_code_ = 0;
   1039 
   1040     // Unique code pointers.
   1041     std::set<const void*> dex_code_item_ptrs_;
   1042 
   1043     // Total "unique" dex code bytes.
   1044     size_t dex_code_bytes_ = 0;
   1045 
   1046     // Other dex ids.
   1047     size_t num_string_ids_ = 0;
   1048     size_t num_method_ids_ = 0;
   1049     size_t num_field_ids_ = 0;
   1050     size_t num_type_ids_ = 0;
   1051     size_t num_class_defs_ = 0;
   1052   };
   1053 
   1054   bool DumpOatDexFile(std::ostream& os, const OatFile::OatDexFile& oat_dex_file) {
   1055     bool success = true;
   1056     bool stop_analysis = false;
   1057     os << "OatDexFile:\n";
   1058     os << StringPrintf("location: %s\n", oat_dex_file.GetDexFileLocation().c_str());
   1059     os << StringPrintf("checksum: 0x%08x\n", oat_dex_file.GetDexFileLocationChecksum());
   1060 
   1061     const uint8_t* const oat_file_begin = oat_dex_file.GetOatFile()->Begin();
   1062     if (oat_dex_file.GetOatFile()->ContainsDexCode()) {
   1063       const uint8_t* const vdex_file_begin = oat_dex_file.GetOatFile()->DexBegin();
   1064 
   1065       // Print data range of the dex file embedded inside the corresponding vdex file.
   1066       const uint8_t* const dex_file_pointer = oat_dex_file.GetDexFilePointer();
   1067       uint32_t dex_offset = dchecked_integral_cast<uint32_t>(dex_file_pointer - vdex_file_begin);
   1068       os << StringPrintf(
   1069           "dex-file: 0x%08x..0x%08x\n",
   1070           dex_offset,
   1071           dchecked_integral_cast<uint32_t>(dex_offset + oat_dex_file.FileSize() - 1));
   1072     } else {
   1073       os << StringPrintf("dex-file not in VDEX file\n");
   1074     }
   1075 
   1076     // Create the dex file early. A lot of print-out things depend on it.
   1077     std::string error_msg;
   1078     const DexFile* const dex_file = OpenDexFile(&oat_dex_file, &error_msg);
   1079     if (dex_file == nullptr) {
   1080       os << "NOT FOUND: " << error_msg << "\n\n";
   1081       os << std::flush;
   1082       return false;
   1083     }
   1084 
   1085     // Print lookup table, if it exists.
   1086     if (oat_dex_file.GetLookupTableData() != nullptr) {
   1087       uint32_t table_offset = dchecked_integral_cast<uint32_t>(
   1088           oat_dex_file.GetLookupTableData() - oat_file_begin);
   1089       uint32_t table_size = TypeLookupTable::RawDataLength(dex_file->NumClassDefs());
   1090       os << StringPrintf("type-table: 0x%08x..0x%08x\n",
   1091                          table_offset,
   1092                          table_offset + table_size - 1);
   1093     }
   1094 
   1095     VariableIndentationOutputStream vios(&os);
   1096     ScopedIndentation indent1(&vios);
   1097     for (size_t class_def_index = 0;
   1098          class_def_index < dex_file->NumClassDefs();
   1099          class_def_index++) {
   1100       const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
   1101       const char* descriptor = dex_file->GetClassDescriptor(class_def);
   1102 
   1103       // TODO: Support regex
   1104       if (DescriptorToDot(descriptor).find(options_.class_filter_) == std::string::npos) {
   1105         continue;
   1106       }
   1107 
   1108       uint32_t oat_class_offset = oat_dex_file.GetOatClassOffset(class_def_index);
   1109       const OatFile::OatClass oat_class = oat_dex_file.GetOatClass(class_def_index);
   1110       os << StringPrintf("%zd: %s (offset=0x%08x) (type_idx=%d)",
   1111                          class_def_index, descriptor, oat_class_offset, class_def.class_idx_.index_)
   1112          << " (" << oat_class.GetStatus() << ")"
   1113          << " (" << oat_class.GetType() << ")\n";
   1114       // TODO: include bitmap here if type is kOatClassSomeCompiled?
   1115       if (options_.list_classes_) {
   1116         continue;
   1117       }
   1118       if (!DumpOatClass(&vios, oat_class, *dex_file, class_def, &stop_analysis)) {
   1119         success = false;
   1120       }
   1121       if (stop_analysis) {
   1122         os << std::flush;
   1123         return success;
   1124       }
   1125     }
   1126     os << "\n";
   1127     os << std::flush;
   1128     return success;
   1129   }
   1130 
   1131   // Backwards compatible Dex file export. If dex_file is nullptr (valid Vdex file not present) the
   1132   // Dex resource is extracted from the oat_dex_file and its checksum is repaired since it's not
   1133   // unquickened. Otherwise the dex_file has been fully unquickened and is expected to verify the
   1134   // original checksum.
   1135   bool ExportDexFile(std::ostream& os,
   1136                      const OatFile::OatDexFile& oat_dex_file,
   1137                      const DexFile* dex_file) {
   1138     std::string error_msg;
   1139     std::string dex_file_location = oat_dex_file.GetDexFileLocation();
   1140     size_t fsize = oat_dex_file.FileSize();
   1141 
   1142     // Some quick checks just in case
   1143     if (fsize == 0 || fsize < sizeof(DexFile::Header)) {
   1144       os << "Invalid dex file\n";
   1145       return false;
   1146     }
   1147 
   1148     if (dex_file == nullptr) {
   1149       // Exported bytecode is quickened (dex-to-dex transformations present)
   1150       dex_file = OpenDexFile(&oat_dex_file, &error_msg);
   1151       if (dex_file == nullptr) {
   1152         os << "Failed to open dex file '" << dex_file_location << "': " << error_msg;
   1153         return false;
   1154       }
   1155 
   1156       // Recompute checksum
   1157       reinterpret_cast<DexFile::Header*>(const_cast<uint8_t*>(dex_file->Begin()))->checksum_ =
   1158           dex_file->CalculateChecksum();
   1159     } else {
   1160       // Vdex unquicken output should match original input bytecode
   1161       uint32_t orig_checksum =
   1162           reinterpret_cast<DexFile::Header*>(const_cast<uint8_t*>(dex_file->Begin()))->checksum_;
   1163       CHECK_EQ(orig_checksum, dex_file->CalculateChecksum());
   1164       if (orig_checksum != dex_file->CalculateChecksum()) {
   1165         os << "Unexpected checksum from unquicken dex file '" << dex_file_location << "'\n";
   1166         return false;
   1167       }
   1168     }
   1169 
   1170     // Update header for shared section.
   1171     uint32_t shared_section_offset = 0u;
   1172     uint32_t shared_section_size = 0u;
   1173     if (dex_file->IsCompactDexFile()) {
   1174       CompactDexFile::Header* const header =
   1175           reinterpret_cast<CompactDexFile::Header*>(const_cast<uint8_t*>(dex_file->Begin()));
   1176       shared_section_offset = header->data_off_;
   1177       shared_section_size = header->data_size_;
   1178       // The shared section will be serialized right after the dex file.
   1179       header->data_off_ = header->file_size_;
   1180     }
   1181     // Verify output directory exists
   1182     if (!OS::DirectoryExists(options_.export_dex_location_)) {
   1183       // TODO: Extend OS::DirectoryExists if symlink support is required
   1184       os << options_.export_dex_location_ << " output directory not found or symlink\n";
   1185       return false;
   1186     }
   1187 
   1188     // Beautify path names
   1189     if (dex_file_location.size() > PATH_MAX || dex_file_location.size() <= 0) {
   1190       return false;
   1191     }
   1192 
   1193     std::string dex_orig_name;
   1194     size_t dex_orig_pos = dex_file_location.rfind('/');
   1195     if (dex_orig_pos == std::string::npos)
   1196       dex_orig_name = dex_file_location;
   1197     else
   1198       dex_orig_name = dex_file_location.substr(dex_orig_pos + 1);
   1199 
   1200     // A more elegant approach to efficiently name user installed apps is welcome
   1201     if (dex_orig_name.size() == 8 &&
   1202         dex_orig_name.compare("base.apk") == 0 &&
   1203         dex_orig_pos != std::string::npos) {
   1204       dex_file_location.erase(dex_orig_pos, strlen("base.apk") + 1);
   1205       size_t apk_orig_pos = dex_file_location.rfind('/');
   1206       if (apk_orig_pos != std::string::npos) {
   1207         dex_orig_name = dex_file_location.substr(++apk_orig_pos);
   1208       }
   1209     }
   1210 
   1211     std::string out_dex_path(options_.export_dex_location_);
   1212     if (out_dex_path.back() != '/') {
   1213       out_dex_path.append("/");
   1214     }
   1215     out_dex_path.append(dex_orig_name);
   1216     out_dex_path.append("_export.dex");
   1217     if (out_dex_path.length() > PATH_MAX) {
   1218       return false;
   1219     }
   1220 
   1221     std::unique_ptr<File> file(OS::CreateEmptyFile(out_dex_path.c_str()));
   1222     if (file.get() == nullptr) {
   1223       os << "Failed to open output dex file " << out_dex_path;
   1224       return false;
   1225     }
   1226 
   1227     bool success = file->WriteFully(dex_file->Begin(), fsize);
   1228     if (!success) {
   1229       os << "Failed to write dex file";
   1230       file->Erase();
   1231       return false;
   1232     }
   1233 
   1234     if (shared_section_size != 0) {
   1235       success = file->WriteFully(dex_file->Begin() + shared_section_offset, shared_section_size);
   1236       if (!success) {
   1237         os << "Failed to write shared data section";
   1238         file->Erase();
   1239         return false;
   1240       }
   1241     }
   1242 
   1243     if (file->FlushCloseOrErase() != 0) {
   1244       os << "Flush and close failed";
   1245       return false;
   1246     }
   1247 
   1248     os << StringPrintf("Dex file exported at %s (%zd bytes)\n", out_dex_path.c_str(), fsize);
   1249     os << std::flush;
   1250 
   1251     return true;
   1252   }
   1253 
   1254   bool DumpOatClass(VariableIndentationOutputStream* vios,
   1255                     const OatFile::OatClass& oat_class, const DexFile& dex_file,
   1256                     const DexFile::ClassDef& class_def, bool* stop_analysis) {
   1257     bool success = true;
   1258     bool addr_found = false;
   1259     const uint8_t* class_data = dex_file.GetClassData(class_def);
   1260     if (class_data == nullptr) {  // empty class such as a marker interface?
   1261       vios->Stream() << std::flush;
   1262       return success;
   1263     }
   1264     ClassDataItemIterator it(dex_file, class_data);
   1265     it.SkipAllFields();
   1266     uint32_t class_method_index = 0;
   1267     while (it.HasNextMethod()) {
   1268       if (!DumpOatMethod(vios, class_def, class_method_index, oat_class, dex_file,
   1269                          it.GetMemberIndex(), it.GetMethodCodeItem(),
   1270                          it.GetRawMemberAccessFlags(), &addr_found)) {
   1271         success = false;
   1272       }
   1273       if (addr_found) {
   1274         *stop_analysis = true;
   1275         return success;
   1276       }
   1277       class_method_index++;
   1278       it.Next();
   1279     }
   1280     DCHECK(!it.HasNext());
   1281     vios->Stream() << std::flush;
   1282     return success;
   1283   }
   1284 
   1285   static constexpr uint32_t kPrologueBytes = 16;
   1286 
   1287   // When this was picked, the largest arm method was 55,256 bytes and arm64 was 50,412 bytes.
   1288   static constexpr uint32_t kMaxCodeSize = 100 * 1000;
   1289 
   1290   bool DumpOatMethod(VariableIndentationOutputStream* vios,
   1291                      const DexFile::ClassDef& class_def,
   1292                      uint32_t class_method_index,
   1293                      const OatFile::OatClass& oat_class,
   1294                      const DexFile& dex_file,
   1295                      uint32_t dex_method_idx,
   1296                      const DexFile::CodeItem* code_item,
   1297                      uint32_t method_access_flags,
   1298                      bool* addr_found) {
   1299     bool success = true;
   1300 
   1301     CodeItemDataAccessor code_item_accessor(dex_file, code_item);
   1302 
   1303     // TODO: Support regex
   1304     std::string method_name = dex_file.GetMethodName(dex_file.GetMethodId(dex_method_idx));
   1305     if (method_name.find(options_.method_filter_) == std::string::npos) {
   1306       return success;
   1307     }
   1308 
   1309     std::string pretty_method = dex_file.PrettyMethod(dex_method_idx, true);
   1310     vios->Stream() << StringPrintf("%d: %s (dex_method_idx=%d)\n",
   1311                                    class_method_index, pretty_method.c_str(),
   1312                                    dex_method_idx);
   1313     if (options_.list_methods_) {
   1314       return success;
   1315     }
   1316 
   1317     uint32_t oat_method_offsets_offset = oat_class.GetOatMethodOffsetsOffset(class_method_index);
   1318     const OatMethodOffsets* oat_method_offsets = oat_class.GetOatMethodOffsets(class_method_index);
   1319     const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_index);
   1320     uint32_t code_offset = oat_method.GetCodeOffset();
   1321     uint32_t code_size = oat_method.GetQuickCodeSize();
   1322     if (resolved_addr2instr_ != 0) {
   1323       if (resolved_addr2instr_ > code_offset + code_size) {
   1324         return success;
   1325       } else {
   1326         *addr_found = true;  // stop analyzing file at next iteration
   1327       }
   1328     }
   1329 
   1330     // Everything below is indented at least once.
   1331     ScopedIndentation indent1(vios);
   1332 
   1333     {
   1334       vios->Stream() << "DEX CODE:\n";
   1335       ScopedIndentation indent2(vios);
   1336       if (code_item_accessor.HasCodeItem()) {
   1337         for (const DexInstructionPcPair& inst : code_item_accessor) {
   1338           vios->Stream() << StringPrintf("0x%04x: ", inst.DexPc()) << inst->DumpHexLE(5)
   1339                          << StringPrintf("\t| %s\n", inst->DumpString(&dex_file).c_str());
   1340         }
   1341       }
   1342     }
   1343 
   1344     std::unique_ptr<StackHandleScope<1>> hs;
   1345     std::unique_ptr<verifier::MethodVerifier> verifier;
   1346     if (Runtime::Current() != nullptr) {
   1347       // We need to have the handle scope stay live until after the verifier since the verifier has
   1348       // a handle to the dex cache from hs.
   1349       hs.reset(new StackHandleScope<1>(Thread::Current()));
   1350       vios->Stream() << "VERIFIER TYPE ANALYSIS:\n";
   1351       ScopedIndentation indent2(vios);
   1352       verifier.reset(DumpVerifier(vios, hs.get(),
   1353                                   dex_method_idx, &dex_file, class_def, code_item,
   1354                                   method_access_flags));
   1355     }
   1356     {
   1357       vios->Stream() << "OatMethodOffsets ";
   1358       if (options_.absolute_addresses_) {
   1359         vios->Stream() << StringPrintf("%p ", oat_method_offsets);
   1360       }
   1361       vios->Stream() << StringPrintf("(offset=0x%08x)\n", oat_method_offsets_offset);
   1362       if (oat_method_offsets_offset > oat_file_.Size()) {
   1363         vios->Stream() << StringPrintf(
   1364             "WARNING: oat method offsets offset 0x%08x is past end of file 0x%08zx.\n",
   1365             oat_method_offsets_offset, oat_file_.Size());
   1366         // If we can't read OatMethodOffsets, the rest of the data is dangerous to read.
   1367         vios->Stream() << std::flush;
   1368         return false;
   1369       }
   1370 
   1371       ScopedIndentation indent2(vios);
   1372       vios->Stream() << StringPrintf("code_offset: 0x%08x ", code_offset);
   1373       uint32_t aligned_code_begin = AlignCodeOffset(oat_method.GetCodeOffset());
   1374       if (aligned_code_begin > oat_file_.Size()) {
   1375         vios->Stream() << StringPrintf("WARNING: "
   1376                                        "code offset 0x%08x is past end of file 0x%08zx.\n",
   1377                                        aligned_code_begin, oat_file_.Size());
   1378         success = false;
   1379       }
   1380       vios->Stream() << "\n";
   1381     }
   1382     {
   1383       vios->Stream() << "OatQuickMethodHeader ";
   1384       uint32_t method_header_offset = oat_method.GetOatQuickMethodHeaderOffset();
   1385       const OatQuickMethodHeader* method_header = oat_method.GetOatQuickMethodHeader();
   1386       stats_.AddBitsIfUnique(Stats::kByteKindQuickMethodHeader,
   1387                              sizeof(*method_header) * kBitsPerByte,
   1388                              method_header);
   1389       if (options_.absolute_addresses_) {
   1390         vios->Stream() << StringPrintf("%p ", method_header);
   1391       }
   1392       vios->Stream() << StringPrintf("(offset=0x%08x)\n", method_header_offset);
   1393       if (method_header_offset > oat_file_.Size()) {
   1394         vios->Stream() << StringPrintf(
   1395             "WARNING: oat quick method header offset 0x%08x is past end of file 0x%08zx.\n",
   1396             method_header_offset, oat_file_.Size());
   1397         // If we can't read the OatQuickMethodHeader, the rest of the data is dangerous to read.
   1398         vios->Stream() << std::flush;
   1399         return false;
   1400       }
   1401 
   1402       ScopedIndentation indent2(vios);
   1403       vios->Stream() << "vmap_table: ";
   1404       if (options_.absolute_addresses_) {
   1405         vios->Stream() << StringPrintf("%p ", oat_method.GetVmapTable());
   1406       }
   1407       uint32_t vmap_table_offset = method_header ==
   1408           nullptr ? 0 : method_header->GetVmapTableOffset();
   1409       vios->Stream() << StringPrintf("(offset=0x%08x)\n", vmap_table_offset);
   1410 
   1411       size_t vmap_table_offset_limit =
   1412           IsMethodGeneratedByDexToDexCompiler(oat_method, code_item_accessor)
   1413               ? oat_file_.GetVdexFile()->Size()
   1414               : method_header->GetCode() - oat_file_.Begin();
   1415       if (vmap_table_offset >= vmap_table_offset_limit) {
   1416         vios->Stream() << StringPrintf("WARNING: "
   1417                                        "vmap table offset 0x%08x is past end of file 0x%08zx. "
   1418                                        "vmap table offset was loaded from offset 0x%08x.\n",
   1419                                        vmap_table_offset,
   1420                                        vmap_table_offset_limit,
   1421                                        oat_method.GetVmapTableOffsetOffset());
   1422         success = false;
   1423       } else if (options_.dump_vmap_) {
   1424         DumpVmapData(vios, oat_method, code_item_accessor);
   1425       }
   1426     }
   1427     {
   1428       vios->Stream() << "QuickMethodFrameInfo\n";
   1429 
   1430       ScopedIndentation indent2(vios);
   1431       vios->Stream()
   1432           << StringPrintf("frame_size_in_bytes: %zd\n", oat_method.GetFrameSizeInBytes());
   1433       vios->Stream() << StringPrintf("core_spill_mask: 0x%08x ", oat_method.GetCoreSpillMask());
   1434       DumpSpillMask(vios->Stream(), oat_method.GetCoreSpillMask(), false);
   1435       vios->Stream() << "\n";
   1436       vios->Stream() << StringPrintf("fp_spill_mask: 0x%08x ", oat_method.GetFpSpillMask());
   1437       DumpSpillMask(vios->Stream(), oat_method.GetFpSpillMask(), true);
   1438       vios->Stream() << "\n";
   1439     }
   1440     {
   1441       // Based on spill masks from QuickMethodFrameInfo so placed
   1442       // after it is dumped, but useful for understanding quick
   1443       // code, so dumped here.
   1444       ScopedIndentation indent2(vios);
   1445       DumpVregLocations(vios->Stream(), oat_method, code_item_accessor);
   1446     }
   1447     {
   1448       vios->Stream() << "CODE: ";
   1449       uint32_t code_size_offset = oat_method.GetQuickCodeSizeOffset();
   1450       if (code_size_offset > oat_file_.Size()) {
   1451         ScopedIndentation indent2(vios);
   1452         vios->Stream() << StringPrintf("WARNING: "
   1453                                        "code size offset 0x%08x is past end of file 0x%08zx.",
   1454                                        code_size_offset, oat_file_.Size());
   1455         success = false;
   1456       } else {
   1457         const void* code = oat_method.GetQuickCode();
   1458         uint32_t aligned_code_begin = AlignCodeOffset(code_offset);
   1459         uint64_t aligned_code_end = aligned_code_begin + code_size;
   1460         stats_.AddBitsIfUnique(Stats::kByteKindCode, code_size * kBitsPerByte, code);
   1461 
   1462         if (options_.absolute_addresses_) {
   1463           vios->Stream() << StringPrintf("%p ", code);
   1464         }
   1465         vios->Stream() << StringPrintf("(code_offset=0x%08x size_offset=0x%08x size=%u)%s\n",
   1466                                        code_offset,
   1467                                        code_size_offset,
   1468                                        code_size,
   1469                                        code != nullptr ? "..." : "");
   1470 
   1471         ScopedIndentation indent2(vios);
   1472         if (aligned_code_begin > oat_file_.Size()) {
   1473           vios->Stream() << StringPrintf("WARNING: "
   1474                                          "start of code at 0x%08x is past end of file 0x%08zx.",
   1475                                          aligned_code_begin, oat_file_.Size());
   1476           success = false;
   1477         } else if (aligned_code_end > oat_file_.Size()) {
   1478           vios->Stream() << StringPrintf(
   1479               "WARNING: "
   1480               "end of code at 0x%08" PRIx64 " is past end of file 0x%08zx. "
   1481               "code size is 0x%08x loaded from offset 0x%08x.\n",
   1482               aligned_code_end, oat_file_.Size(),
   1483               code_size, code_size_offset);
   1484           success = false;
   1485           if (options_.disassemble_code_) {
   1486             if (code_size_offset + kPrologueBytes <= oat_file_.Size()) {
   1487               DumpCode(vios, oat_method, code_item_accessor, true, kPrologueBytes);
   1488             }
   1489           }
   1490         } else if (code_size > kMaxCodeSize) {
   1491           vios->Stream() << StringPrintf(
   1492               "WARNING: "
   1493               "code size %d is bigger than max expected threshold of %d. "
   1494               "code size is 0x%08x loaded from offset 0x%08x.\n",
   1495               code_size, kMaxCodeSize,
   1496               code_size, code_size_offset);
   1497           success = false;
   1498           if (options_.disassemble_code_) {
   1499             if (code_size_offset + kPrologueBytes <= oat_file_.Size()) {
   1500               DumpCode(vios, oat_method, code_item_accessor, true, kPrologueBytes);
   1501             }
   1502           }
   1503         } else if (options_.disassemble_code_) {
   1504           DumpCode(vios, oat_method, code_item_accessor, !success, 0);
   1505         }
   1506       }
   1507     }
   1508     vios->Stream() << std::flush;
   1509     return success;
   1510   }
   1511 
   1512   void DumpSpillMask(std::ostream& os, uint32_t spill_mask, bool is_float) {
   1513     if (spill_mask == 0) {
   1514       return;
   1515     }
   1516     os << "(";
   1517     for (size_t i = 0; i < 32; i++) {
   1518       if ((spill_mask & (1 << i)) != 0) {
   1519         if (is_float) {
   1520           os << "fr" << i;
   1521         } else {
   1522           os << "r" << i;
   1523         }
   1524         spill_mask ^= 1 << i;  // clear bit
   1525         if (spill_mask != 0) {
   1526           os << ", ";
   1527         } else {
   1528           break;
   1529         }
   1530       }
   1531     }
   1532     os << ")";
   1533   }
   1534 
   1535   // Display data stored at the the vmap offset of an oat method.
   1536   void DumpVmapData(VariableIndentationOutputStream* vios,
   1537                     const OatFile::OatMethod& oat_method,
   1538                     const CodeItemDataAccessor& code_item_accessor) {
   1539     if (IsMethodGeneratedByOptimizingCompiler(oat_method, code_item_accessor)) {
   1540       // The optimizing compiler outputs its CodeInfo data in the vmap table.
   1541       const void* raw_code_info = oat_method.GetVmapTable();
   1542       if (raw_code_info != nullptr) {
   1543         CodeInfo code_info(raw_code_info);
   1544         DCHECK(code_item_accessor.HasCodeItem());
   1545         ScopedIndentation indent1(vios);
   1546         MethodInfo method_info = oat_method.GetOatQuickMethodHeader()->GetOptimizedMethodInfo();
   1547         DumpCodeInfo(vios, code_info, oat_method, code_item_accessor, method_info);
   1548       }
   1549     } else if (IsMethodGeneratedByDexToDexCompiler(oat_method, code_item_accessor)) {
   1550       // We don't encode the size in the table, so just emit that we have quickened
   1551       // information.
   1552       ScopedIndentation indent(vios);
   1553       vios->Stream() << "quickened data\n";
   1554     } else {
   1555       // Otherwise, there is nothing to display.
   1556     }
   1557   }
   1558 
   1559   // Display a CodeInfo object emitted by the optimizing compiler.
   1560   void DumpCodeInfo(VariableIndentationOutputStream* vios,
   1561                     const CodeInfo& code_info,
   1562                     const OatFile::OatMethod& oat_method,
   1563                     const CodeItemDataAccessor& code_item_accessor,
   1564                     const MethodInfo& method_info) {
   1565     code_info.Dump(vios,
   1566                    oat_method.GetCodeOffset(),
   1567                    code_item_accessor.RegistersSize(),
   1568                    options_.dump_code_info_stack_maps_,
   1569                    instruction_set_,
   1570                    method_info);
   1571   }
   1572 
   1573   static int GetOutVROffset(uint16_t out_num, InstructionSet isa) {
   1574     // According to stack model, the first out is above the Method referernce.
   1575     return static_cast<size_t>(InstructionSetPointerSize(isa)) + out_num * sizeof(uint32_t);
   1576   }
   1577 
   1578   static uint32_t GetVRegOffsetFromQuickCode(const CodeItemDataAccessor& code_item_accessor,
   1579                                              uint32_t core_spills,
   1580                                              uint32_t fp_spills,
   1581                                              size_t frame_size,
   1582                                              int reg,
   1583                                              InstructionSet isa) {
   1584     PointerSize pointer_size = InstructionSetPointerSize(isa);
   1585     if (kIsDebugBuild) {
   1586       auto* runtime = Runtime::Current();
   1587       if (runtime != nullptr) {
   1588         CHECK_EQ(runtime->GetClassLinker()->GetImagePointerSize(), pointer_size);
   1589       }
   1590     }
   1591     DCHECK_ALIGNED(frame_size, kStackAlignment);
   1592     DCHECK_NE(reg, -1);
   1593     int spill_size = POPCOUNT(core_spills) * GetBytesPerGprSpillLocation(isa)
   1594         + POPCOUNT(fp_spills) * GetBytesPerFprSpillLocation(isa)
   1595         + sizeof(uint32_t);  // Filler.
   1596     int num_regs = code_item_accessor.RegistersSize() - code_item_accessor.InsSize();
   1597     int temp_threshold = code_item_accessor.RegistersSize();
   1598     const int max_num_special_temps = 1;
   1599     if (reg == temp_threshold) {
   1600       // The current method pointer corresponds to special location on stack.
   1601       return 0;
   1602     } else if (reg >= temp_threshold + max_num_special_temps) {
   1603       /*
   1604        * Special temporaries may have custom locations and the logic above deals with that.
   1605        * However, non-special temporaries are placed relative to the outs.
   1606        */
   1607       int temps_start = code_item_accessor.OutsSize() * sizeof(uint32_t)
   1608           + static_cast<size_t>(pointer_size) /* art method */;
   1609       int relative_offset = (reg - (temp_threshold + max_num_special_temps)) * sizeof(uint32_t);
   1610       return temps_start + relative_offset;
   1611     } else if (reg < num_regs) {
   1612       int locals_start = frame_size - spill_size - num_regs * sizeof(uint32_t);
   1613       return locals_start + (reg * sizeof(uint32_t));
   1614     } else {
   1615       // Handle ins.
   1616       return frame_size + ((reg - num_regs) * sizeof(uint32_t))
   1617           + static_cast<size_t>(pointer_size) /* art method */;
   1618     }
   1619   }
   1620 
   1621   void DumpVregLocations(std::ostream& os, const OatFile::OatMethod& oat_method,
   1622                          const CodeItemDataAccessor& code_item_accessor) {
   1623     if (code_item_accessor.HasCodeItem()) {
   1624       size_t num_locals_ins = code_item_accessor.RegistersSize();
   1625       size_t num_ins = code_item_accessor.InsSize();
   1626       size_t num_locals = num_locals_ins - num_ins;
   1627       size_t num_outs = code_item_accessor.OutsSize();
   1628 
   1629       os << "vr_stack_locations:";
   1630       for (size_t reg = 0; reg <= num_locals_ins; reg++) {
   1631         // For readability, delimit the different kinds of VRs.
   1632         if (reg == num_locals_ins) {
   1633           os << "\n\tmethod*:";
   1634         } else if (reg == num_locals && num_ins > 0) {
   1635           os << "\n\tins:";
   1636         } else if (reg == 0 && num_locals > 0) {
   1637           os << "\n\tlocals:";
   1638         }
   1639 
   1640         uint32_t offset = GetVRegOffsetFromQuickCode(code_item_accessor,
   1641                                                      oat_method.GetCoreSpillMask(),
   1642                                                      oat_method.GetFpSpillMask(),
   1643                                                      oat_method.GetFrameSizeInBytes(),
   1644                                                      reg,
   1645                                                      GetInstructionSet());
   1646         os << " v" << reg << "[sp + #" << offset << "]";
   1647       }
   1648 
   1649       for (size_t out_reg = 0; out_reg < num_outs; out_reg++) {
   1650         if (out_reg == 0) {
   1651           os << "\n\touts:";
   1652         }
   1653 
   1654         uint32_t offset = GetOutVROffset(out_reg, GetInstructionSet());
   1655         os << " v" << out_reg << "[sp + #" << offset << "]";
   1656       }
   1657 
   1658       os << "\n";
   1659     }
   1660   }
   1661 
   1662   // Has `oat_method` -- corresponding to the Dex `code_item` -- been compiled by
   1663   // the optimizing compiler?
   1664   static bool IsMethodGeneratedByOptimizingCompiler(
   1665       const OatFile::OatMethod& oat_method,
   1666       const CodeItemDataAccessor& code_item_accessor) {
   1667     // If the native GC map is null and the Dex `code_item` is not
   1668     // null, then this method has been compiled with the optimizing
   1669     // compiler.
   1670     return oat_method.GetQuickCode() != nullptr &&
   1671            oat_method.GetVmapTable() != nullptr &&
   1672            code_item_accessor.HasCodeItem();
   1673   }
   1674 
   1675   // Has `oat_method` -- corresponding to the Dex `code_item` -- been compiled by
   1676   // the dextodex compiler?
   1677   static bool IsMethodGeneratedByDexToDexCompiler(
   1678       const OatFile::OatMethod& oat_method,
   1679       const CodeItemDataAccessor& code_item_accessor) {
   1680     // If the quick code is null, the Dex `code_item` is not
   1681     // null, and the vmap table is not null, then this method has been compiled
   1682     // with the dextodex compiler.
   1683     return oat_method.GetQuickCode() == nullptr &&
   1684            oat_method.GetVmapTable() != nullptr &&
   1685            code_item_accessor.HasCodeItem();
   1686   }
   1687 
   1688   verifier::MethodVerifier* DumpVerifier(VariableIndentationOutputStream* vios,
   1689                                          StackHandleScope<1>* hs,
   1690                                          uint32_t dex_method_idx,
   1691                                          const DexFile* dex_file,
   1692                                          const DexFile::ClassDef& class_def,
   1693                                          const DexFile::CodeItem* code_item,
   1694                                          uint32_t method_access_flags) {
   1695     if ((method_access_flags & kAccNative) == 0) {
   1696       ScopedObjectAccess soa(Thread::Current());
   1697       Runtime* const runtime = Runtime::Current();
   1698       DCHECK(options_.class_loader_ != nullptr);
   1699       Handle<mirror::DexCache> dex_cache = hs->NewHandle(
   1700           runtime->GetClassLinker()->RegisterDexFile(*dex_file, options_.class_loader_->Get()));
   1701       CHECK(dex_cache != nullptr);
   1702       ArtMethod* method = runtime->GetClassLinker()->ResolveMethodWithoutInvokeType(
   1703           dex_method_idx, dex_cache, *options_.class_loader_);
   1704       CHECK(method != nullptr);
   1705       return verifier::MethodVerifier::VerifyMethodAndDump(
   1706           soa.Self(), vios, dex_method_idx, dex_file, dex_cache, *options_.class_loader_,
   1707           class_def, code_item, method, method_access_flags);
   1708     }
   1709 
   1710     return nullptr;
   1711   }
   1712 
   1713   // The StackMapsHelper provides the stack maps in the native PC order.
   1714   // For identical native PCs, the order from the CodeInfo is preserved.
   1715   class StackMapsHelper {
   1716    public:
   1717     explicit StackMapsHelper(const uint8_t* raw_code_info, InstructionSet instruction_set)
   1718         : code_info_(raw_code_info),
   1719           encoding_(code_info_.ExtractEncoding()),
   1720           number_of_stack_maps_(code_info_.GetNumberOfStackMaps(encoding_)),
   1721           indexes_(),
   1722           offset_(static_cast<uint32_t>(-1)),
   1723           stack_map_index_(0u),
   1724           instruction_set_(instruction_set) {
   1725       if (number_of_stack_maps_ != 0u) {
   1726         // Check if native PCs are ordered.
   1727         bool ordered = true;
   1728         StackMap last = code_info_.GetStackMapAt(0u, encoding_);
   1729         for (size_t i = 1; i != number_of_stack_maps_; ++i) {
   1730           StackMap current = code_info_.GetStackMapAt(i, encoding_);
   1731           if (last.GetNativePcOffset(encoding_.stack_map.encoding, instruction_set) >
   1732               current.GetNativePcOffset(encoding_.stack_map.encoding, instruction_set)) {
   1733             ordered = false;
   1734             break;
   1735           }
   1736           last = current;
   1737         }
   1738         if (!ordered) {
   1739           // Create indirection indexes for access in native PC order. We do not optimize
   1740           // for the fact that there can currently be only two separately ordered ranges,
   1741           // namely normal stack maps and catch-point stack maps.
   1742           indexes_.resize(number_of_stack_maps_);
   1743           std::iota(indexes_.begin(), indexes_.end(), 0u);
   1744           std::sort(indexes_.begin(),
   1745                     indexes_.end(),
   1746                     [this](size_t lhs, size_t rhs) {
   1747                       StackMap left = code_info_.GetStackMapAt(lhs, encoding_);
   1748                       uint32_t left_pc = left.GetNativePcOffset(encoding_.stack_map.encoding,
   1749                                                                 instruction_set_);
   1750                       StackMap right = code_info_.GetStackMapAt(rhs, encoding_);
   1751                       uint32_t right_pc = right.GetNativePcOffset(encoding_.stack_map.encoding,
   1752                                                                   instruction_set_);
   1753                       // If the PCs are the same, compare indexes to preserve the original order.
   1754                       return (left_pc < right_pc) || (left_pc == right_pc && lhs < rhs);
   1755                     });
   1756         }
   1757         offset_ = GetStackMapAt(0).GetNativePcOffset(encoding_.stack_map.encoding,
   1758                                                      instruction_set_);
   1759       }
   1760     }
   1761 
   1762     const CodeInfo& GetCodeInfo() const {
   1763       return code_info_;
   1764     }
   1765 
   1766     const CodeInfoEncoding& GetEncoding() const {
   1767       return encoding_;
   1768     }
   1769 
   1770     uint32_t GetOffset() const {
   1771       return offset_;
   1772     }
   1773 
   1774     StackMap GetStackMap() const {
   1775       return GetStackMapAt(stack_map_index_);
   1776     }
   1777 
   1778     void Next() {
   1779       ++stack_map_index_;
   1780       offset_ = (stack_map_index_ == number_of_stack_maps_)
   1781           ? static_cast<uint32_t>(-1)
   1782           : GetStackMapAt(stack_map_index_).GetNativePcOffset(encoding_.stack_map.encoding,
   1783                                                               instruction_set_);
   1784     }
   1785 
   1786    private:
   1787     StackMap GetStackMapAt(size_t i) const {
   1788       if (!indexes_.empty()) {
   1789         i = indexes_[i];
   1790       }
   1791       DCHECK_LT(i, number_of_stack_maps_);
   1792       return code_info_.GetStackMapAt(i, encoding_);
   1793     }
   1794 
   1795     const CodeInfo code_info_;
   1796     const CodeInfoEncoding encoding_;
   1797     const size_t number_of_stack_maps_;
   1798     dchecked_vector<size_t> indexes_;  // Used if stack map native PCs are not ordered.
   1799     uint32_t offset_;
   1800     size_t stack_map_index_;
   1801     const InstructionSet instruction_set_;
   1802   };
   1803 
   1804   void DumpCode(VariableIndentationOutputStream* vios,
   1805                 const OatFile::OatMethod& oat_method,
   1806                 const CodeItemDataAccessor& code_item_accessor,
   1807                 bool bad_input, size_t code_size) {
   1808     const void* quick_code = oat_method.GetQuickCode();
   1809 
   1810     if (code_size == 0) {
   1811       code_size = oat_method.GetQuickCodeSize();
   1812     }
   1813     if (code_size == 0 || quick_code == nullptr) {
   1814       vios->Stream() << "NO CODE!\n";
   1815       return;
   1816     } else if (!bad_input && IsMethodGeneratedByOptimizingCompiler(oat_method,
   1817                                                                    code_item_accessor)) {
   1818       // The optimizing compiler outputs its CodeInfo data in the vmap table.
   1819       StackMapsHelper helper(oat_method.GetVmapTable(), instruction_set_);
   1820       MethodInfo method_info(oat_method.GetOatQuickMethodHeader()->GetOptimizedMethodInfo());
   1821       {
   1822         CodeInfoEncoding encoding(helper.GetEncoding());
   1823         StackMapEncoding stack_map_encoding(encoding.stack_map.encoding);
   1824         const size_t num_stack_maps = encoding.stack_map.num_entries;
   1825         if (stats_.AddBitsIfUnique(Stats::kByteKindCodeInfoEncoding,
   1826                                    encoding.HeaderSize() * kBitsPerByte,
   1827                                    oat_method.GetVmapTable())) {
   1828           // Stack maps
   1829           stats_.AddBits(
   1830               Stats::kByteKindStackMapNativePc,
   1831               stack_map_encoding.GetNativePcEncoding().BitSize() * num_stack_maps);
   1832           stats_.AddBits(
   1833               Stats::kByteKindStackMapDexPc,
   1834               stack_map_encoding.GetDexPcEncoding().BitSize() * num_stack_maps);
   1835           stats_.AddBits(
   1836               Stats::kByteKindStackMapDexRegisterMap,
   1837               stack_map_encoding.GetDexRegisterMapEncoding().BitSize() * num_stack_maps);
   1838           stats_.AddBits(
   1839               Stats::kByteKindStackMapInlineInfoIndex,
   1840               stack_map_encoding.GetInlineInfoEncoding().BitSize() * num_stack_maps);
   1841           stats_.AddBits(
   1842               Stats::kByteKindStackMapRegisterMaskIndex,
   1843               stack_map_encoding.GetRegisterMaskIndexEncoding().BitSize() * num_stack_maps);
   1844           stats_.AddBits(
   1845               Stats::kByteKindStackMapStackMaskIndex,
   1846               stack_map_encoding.GetStackMaskIndexEncoding().BitSize() * num_stack_maps);
   1847 
   1848           // Stack masks
   1849           stats_.AddBits(
   1850               Stats::kByteKindCodeInfoStackMasks,
   1851               encoding.stack_mask.encoding.BitSize() * encoding.stack_mask.num_entries);
   1852 
   1853           // Register masks
   1854           stats_.AddBits(
   1855               Stats::kByteKindCodeInfoRegisterMasks,
   1856               encoding.register_mask.encoding.BitSize() * encoding.register_mask.num_entries);
   1857 
   1858           // Invoke infos
   1859           if (encoding.invoke_info.num_entries > 0u) {
   1860             stats_.AddBits(
   1861                 Stats::kByteKindCodeInfoInvokeInfo,
   1862                 encoding.invoke_info.encoding.BitSize() * encoding.invoke_info.num_entries);
   1863           }
   1864 
   1865           // Location catalog
   1866           const size_t location_catalog_bytes =
   1867               helper.GetCodeInfo().GetDexRegisterLocationCatalogSize(encoding);
   1868           stats_.AddBits(Stats::kByteKindCodeInfoLocationCatalog,
   1869                          kBitsPerByte * location_catalog_bytes);
   1870           // Dex register bytes.
   1871           const size_t dex_register_bytes =
   1872               helper.GetCodeInfo().GetDexRegisterMapsSize(encoding,
   1873                                                           code_item_accessor.RegistersSize());
   1874           stats_.AddBits(
   1875               Stats::kByteKindCodeInfoDexRegisterMap,
   1876               kBitsPerByte * dex_register_bytes);
   1877 
   1878           // Inline infos.
   1879           const size_t num_inline_infos = encoding.inline_info.num_entries;
   1880           if (num_inline_infos > 0u) {
   1881             stats_.AddBits(
   1882                 Stats::kByteKindInlineInfoMethodIndexIdx,
   1883                 encoding.inline_info.encoding.GetMethodIndexIdxEncoding().BitSize() *
   1884                     num_inline_infos);
   1885             stats_.AddBits(
   1886                 Stats::kByteKindInlineInfoDexPc,
   1887                 encoding.inline_info.encoding.GetDexPcEncoding().BitSize() * num_inline_infos);
   1888             stats_.AddBits(
   1889                 Stats::kByteKindInlineInfoExtraData,
   1890                 encoding.inline_info.encoding.GetExtraDataEncoding().BitSize() * num_inline_infos);
   1891             stats_.AddBits(
   1892                 Stats::kByteKindInlineInfoDexRegisterMap,
   1893                 encoding.inline_info.encoding.GetDexRegisterMapEncoding().BitSize() *
   1894                     num_inline_infos);
   1895             stats_.AddBits(Stats::kByteKindInlineInfoIsLast, num_inline_infos);
   1896           }
   1897         }
   1898       }
   1899       const uint8_t* quick_native_pc = reinterpret_cast<const uint8_t*>(quick_code);
   1900       size_t offset = 0;
   1901       while (offset < code_size) {
   1902         offset += disassembler_->Dump(vios->Stream(), quick_native_pc + offset);
   1903         if (offset == helper.GetOffset()) {
   1904           ScopedIndentation indent1(vios);
   1905           StackMap stack_map = helper.GetStackMap();
   1906           DCHECK(stack_map.IsValid());
   1907           stack_map.Dump(vios,
   1908                          helper.GetCodeInfo(),
   1909                          helper.GetEncoding(),
   1910                          method_info,
   1911                          oat_method.GetCodeOffset(),
   1912                          code_item_accessor.RegistersSize(),
   1913                          instruction_set_);
   1914           do {
   1915             helper.Next();
   1916             // There may be multiple stack maps at a given PC. We display only the first one.
   1917           } while (offset == helper.GetOffset());
   1918         }
   1919         DCHECK_LT(offset, helper.GetOffset());
   1920       }
   1921     } else {
   1922       const uint8_t* quick_native_pc = reinterpret_cast<const uint8_t*>(quick_code);
   1923       size_t offset = 0;
   1924       while (offset < code_size) {
   1925         offset += disassembler_->Dump(vios->Stream(), quick_native_pc + offset);
   1926       }
   1927     }
   1928   }
   1929 
   1930   template <typename NameGetter>
   1931   void DumpBssEntries(std::ostream& os,
   1932                       const char* slot_type,
   1933                       const IndexBssMapping* mapping,
   1934                       uint32_t number_of_indexes,
   1935                       size_t slot_size,
   1936                       NameGetter name) {
   1937     os << ".bss mapping for " << slot_type << ": ";
   1938     if (mapping == nullptr) {
   1939       os << "empty.\n";
   1940       return;
   1941     }
   1942     size_t index_bits = IndexBssMappingEntry::IndexBits(number_of_indexes);
   1943     size_t num_valid_indexes = 0u;
   1944     for (const IndexBssMappingEntry& entry : *mapping) {
   1945       num_valid_indexes += 1u + POPCOUNT(entry.GetMask(index_bits));
   1946     }
   1947     os << mapping->size() << " entries for " << num_valid_indexes << " valid indexes.\n";
   1948     os << std::hex;
   1949     for (const IndexBssMappingEntry& entry : *mapping) {
   1950       uint32_t index = entry.GetIndex(index_bits);
   1951       uint32_t mask = entry.GetMask(index_bits);
   1952       size_t bss_offset = entry.bss_offset - POPCOUNT(mask) * slot_size;
   1953       for (uint32_t n : LowToHighBits(mask)) {
   1954         size_t current_index = index - (32u - index_bits) + n;
   1955         os << "  0x" << bss_offset << ": " << slot_type << ": " << name(current_index) << "\n";
   1956         bss_offset += slot_size;
   1957       }
   1958       DCHECK_EQ(bss_offset, entry.bss_offset);
   1959       os << "  0x" << bss_offset << ": " << slot_type << ": " << name(index) << "\n";
   1960     }
   1961     os << std::dec;
   1962   }
   1963 
   1964   const OatFile& oat_file_;
   1965   const std::vector<const OatFile::OatDexFile*> oat_dex_files_;
   1966   const OatDumperOptions& options_;
   1967   uint32_t resolved_addr2instr_;
   1968   const InstructionSet instruction_set_;
   1969   std::set<uintptr_t> offsets_;
   1970   Disassembler* disassembler_;
   1971   Stats stats_;
   1972 };
   1973 
   1974 class ImageDumper {
   1975  public:
   1976   ImageDumper(std::ostream* os,
   1977               gc::space::ImageSpace& image_space,
   1978               const ImageHeader& image_header,
   1979               OatDumperOptions* oat_dumper_options)
   1980       : os_(os),
   1981         vios_(os),
   1982         indent1_(&vios_),
   1983         image_space_(image_space),
   1984         image_header_(image_header),
   1985         oat_dumper_options_(oat_dumper_options) {}
   1986 
   1987   bool Dump() REQUIRES_SHARED(Locks::mutator_lock_) {
   1988     std::ostream& os = *os_;
   1989     std::ostream& indent_os = vios_.Stream();
   1990 
   1991     os << "MAGIC: " << image_header_.GetMagic() << "\n\n";
   1992 
   1993     os << "IMAGE LOCATION: " << image_space_.GetImageLocation() << "\n\n";
   1994 
   1995     os << "IMAGE BEGIN: " << reinterpret_cast<void*>(image_header_.GetImageBegin()) << "\n\n";
   1996 
   1997     os << "IMAGE SIZE: " << image_header_.GetImageSize() << "\n\n";
   1998 
   1999     for (size_t i = 0; i < ImageHeader::kSectionCount; ++i) {
   2000       auto section = static_cast<ImageHeader::ImageSections>(i);
   2001       os << "IMAGE SECTION " << section << ": " << image_header_.GetImageSection(section) << "\n\n";
   2002     }
   2003 
   2004     os << "OAT CHECKSUM: " << StringPrintf("0x%08x\n\n", image_header_.GetOatChecksum());
   2005 
   2006     os << "OAT FILE BEGIN:" << reinterpret_cast<void*>(image_header_.GetOatFileBegin()) << "\n\n";
   2007 
   2008     os << "OAT DATA BEGIN:" << reinterpret_cast<void*>(image_header_.GetOatDataBegin()) << "\n\n";
   2009 
   2010     os << "OAT DATA END:" << reinterpret_cast<void*>(image_header_.GetOatDataEnd()) << "\n\n";
   2011 
   2012     os << "OAT FILE END:" << reinterpret_cast<void*>(image_header_.GetOatFileEnd()) << "\n\n";
   2013 
   2014     os << "PATCH DELTA:" << image_header_.GetPatchDelta() << "\n\n";
   2015 
   2016     os << "COMPILE PIC: " << (image_header_.CompilePic() ? "yes" : "no") << "\n\n";
   2017 
   2018     {
   2019       os << "ROOTS: " << reinterpret_cast<void*>(image_header_.GetImageRoots()) << "\n";
   2020       static_assert(arraysize(image_roots_descriptions_) ==
   2021           static_cast<size_t>(ImageHeader::kImageRootsMax), "sizes must match");
   2022       DCHECK_LE(image_header_.GetImageRoots()->GetLength(), ImageHeader::kImageRootsMax);
   2023       for (int32_t i = 0, size = image_header_.GetImageRoots()->GetLength(); i != size; ++i) {
   2024         ImageHeader::ImageRoot image_root = static_cast<ImageHeader::ImageRoot>(i);
   2025         const char* image_root_description = image_roots_descriptions_[i];
   2026         mirror::Object* image_root_object = image_header_.GetImageRoot(image_root);
   2027         indent_os << StringPrintf("%s: %p\n", image_root_description, image_root_object);
   2028         if (image_root_object != nullptr && image_root_object->IsObjectArray()) {
   2029           mirror::ObjectArray<mirror::Object>* image_root_object_array
   2030               = image_root_object->AsObjectArray<mirror::Object>();
   2031           ScopedIndentation indent2(&vios_);
   2032           for (int j = 0; j < image_root_object_array->GetLength(); j++) {
   2033             mirror::Object* value = image_root_object_array->Get(j);
   2034             size_t run = 0;
   2035             for (int32_t k = j + 1; k < image_root_object_array->GetLength(); k++) {
   2036               if (value == image_root_object_array->Get(k)) {
   2037                 run++;
   2038               } else {
   2039                 break;
   2040               }
   2041             }
   2042             if (run == 0) {
   2043               indent_os << StringPrintf("%d: ", j);
   2044             } else {
   2045               indent_os << StringPrintf("%d to %zd: ", j, j + run);
   2046               j = j + run;
   2047             }
   2048             if (value != nullptr) {
   2049               PrettyObjectValue(indent_os, value->GetClass(), value);
   2050             } else {
   2051               indent_os << j << ": null\n";
   2052             }
   2053           }
   2054         }
   2055       }
   2056     }
   2057 
   2058     {
   2059       os << "METHOD ROOTS\n";
   2060       static_assert(arraysize(image_methods_descriptions_) ==
   2061           static_cast<size_t>(ImageHeader::kImageMethodsCount), "sizes must match");
   2062       for (int i = 0; i < ImageHeader::kImageMethodsCount; i++) {
   2063         auto image_root = static_cast<ImageHeader::ImageMethod>(i);
   2064         const char* description = image_methods_descriptions_[i];
   2065         auto* image_method = image_header_.GetImageMethod(image_root);
   2066         indent_os << StringPrintf("%s: %p\n", description, image_method);
   2067       }
   2068     }
   2069     os << "\n";
   2070 
   2071     Runtime* const runtime = Runtime::Current();
   2072     ClassLinker* class_linker = runtime->GetClassLinker();
   2073     std::string image_filename = image_space_.GetImageFilename();
   2074     std::string oat_location = ImageHeader::GetOatLocationFromImageLocation(image_filename);
   2075     os << "OAT LOCATION: " << oat_location;
   2076     os << "\n";
   2077     std::string error_msg;
   2078     const OatFile* oat_file = image_space_.GetOatFile();
   2079     if (oat_file == nullptr) {
   2080       oat_file = runtime->GetOatFileManager().FindOpenedOatFileFromOatLocation(oat_location);
   2081     }
   2082     if (oat_file == nullptr) {
   2083       oat_file = OatFile::Open(/* zip_fd */ -1,
   2084                                oat_location,
   2085                                oat_location,
   2086                                nullptr,
   2087                                nullptr,
   2088                                false,
   2089                                /*low_4gb*/false,
   2090                                nullptr,
   2091                                &error_msg);
   2092     }
   2093     if (oat_file == nullptr) {
   2094       os << "OAT FILE NOT FOUND: " << error_msg << "\n";
   2095       return EXIT_FAILURE;
   2096     }
   2097     os << "\n";
   2098 
   2099     stats_.oat_file_bytes = oat_file->Size();
   2100 
   2101     oat_dumper_.reset(new OatDumper(*oat_file, *oat_dumper_options_));
   2102 
   2103     for (const OatFile::OatDexFile* oat_dex_file : oat_file->GetOatDexFiles()) {
   2104       CHECK(oat_dex_file != nullptr);
   2105       stats_.oat_dex_file_sizes.push_back(std::make_pair(oat_dex_file->GetDexFileLocation(),
   2106                                                          oat_dex_file->FileSize()));
   2107     }
   2108 
   2109     os << "OBJECTS:\n" << std::flush;
   2110 
   2111     // Loop through the image space and dump its objects.
   2112     gc::Heap* heap = runtime->GetHeap();
   2113     Thread* self = Thread::Current();
   2114     {
   2115       {
   2116         WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
   2117         heap->FlushAllocStack();
   2118       }
   2119       // Since FlushAllocStack() above resets the (active) allocation
   2120       // stack. Need to revoke the thread-local allocation stacks that
   2121       // point into it.
   2122       ScopedThreadSuspension sts(self, kNative);
   2123       ScopedSuspendAll ssa(__FUNCTION__);
   2124       heap->RevokeAllThreadLocalAllocationStacks(self);
   2125     }
   2126     {
   2127       // Mark dex caches.
   2128       dex_caches_.clear();
   2129       {
   2130         ReaderMutexLock mu(self, *Locks::dex_lock_);
   2131         for (const ClassLinker::DexCacheData& data : class_linker->GetDexCachesData()) {
   2132           ObjPtr<mirror::DexCache> dex_cache =
   2133               ObjPtr<mirror::DexCache>::DownCast(self->DecodeJObject(data.weak_root));
   2134           if (dex_cache != nullptr) {
   2135             dex_caches_.insert(dex_cache.Ptr());
   2136           }
   2137         }
   2138       }
   2139       auto dump_visitor = [&](mirror::Object* obj) REQUIRES_SHARED(Locks::mutator_lock_) {
   2140         DumpObject(obj);
   2141       };
   2142       ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
   2143       // Dump the normal objects before ArtMethods.
   2144       image_space_.GetLiveBitmap()->Walk(dump_visitor);
   2145       indent_os << "\n";
   2146       // TODO: Dump fields.
   2147       // Dump methods after.
   2148       DumpArtMethodVisitor visitor(this);
   2149       image_header_.VisitPackedArtMethods(&visitor,
   2150                                           image_space_.Begin(),
   2151                                           image_header_.GetPointerSize());
   2152       // Dump the large objects separately.
   2153       heap->GetLargeObjectsSpace()->GetLiveBitmap()->Walk(dump_visitor);
   2154       indent_os << "\n";
   2155     }
   2156     os << "STATS:\n" << std::flush;
   2157     std::unique_ptr<File> file(OS::OpenFileForReading(image_filename.c_str()));
   2158     size_t data_size = image_header_.GetDataSize();  // stored size in file.
   2159     if (file == nullptr) {
   2160       LOG(WARNING) << "Failed to find image in " << image_filename;
   2161     } else {
   2162       stats_.file_bytes = file->GetLength();
   2163       // If the image is compressed, adjust to decompressed size.
   2164       size_t uncompressed_size = image_header_.GetImageSize() - sizeof(ImageHeader);
   2165       if (image_header_.GetStorageMode() == ImageHeader::kStorageModeUncompressed) {
   2166         DCHECK_EQ(uncompressed_size, data_size) << "Sizes should match for uncompressed image";
   2167       }
   2168       stats_.file_bytes += uncompressed_size - data_size;
   2169     }
   2170     size_t header_bytes = sizeof(ImageHeader);
   2171     const auto& object_section = image_header_.GetObjectsSection();
   2172     const auto& field_section = image_header_.GetFieldsSection();
   2173     const auto& method_section = image_header_.GetMethodsSection();
   2174     const auto& dex_cache_arrays_section = image_header_.GetDexCacheArraysSection();
   2175     const auto& intern_section = image_header_.GetInternedStringsSection();
   2176     const auto& class_table_section = image_header_.GetClassTableSection();
   2177     const auto& bitmap_section = image_header_.GetImageBitmapSection();
   2178 
   2179     stats_.header_bytes = header_bytes;
   2180 
   2181     // Objects are kObjectAlignment-aligned.
   2182     // CHECK_EQ(RoundUp(header_bytes, kObjectAlignment), object_section.Offset());
   2183     if (object_section.Offset() > header_bytes) {
   2184       stats_.alignment_bytes += object_section.Offset() - header_bytes;
   2185     }
   2186 
   2187     // Field section is 4-byte aligned.
   2188     constexpr size_t kFieldSectionAlignment = 4U;
   2189     uint32_t end_objects = object_section.Offset() + object_section.Size();
   2190     CHECK_EQ(RoundUp(end_objects, kFieldSectionAlignment), field_section.Offset());
   2191     stats_.alignment_bytes += field_section.Offset() - end_objects;
   2192 
   2193     // Method section is 4/8 byte aligned depending on target. Just check for 4-byte alignment.
   2194     uint32_t end_fields = field_section.Offset() + field_section.Size();
   2195     CHECK_ALIGNED(method_section.Offset(), 4);
   2196     stats_.alignment_bytes += method_section.Offset() - end_fields;
   2197 
   2198     // Dex cache arrays section is aligned depending on the target. Just check for 4-byte alignment.
   2199     uint32_t end_methods = method_section.Offset() + method_section.Size();
   2200     CHECK_ALIGNED(dex_cache_arrays_section.Offset(), 4);
   2201     stats_.alignment_bytes += dex_cache_arrays_section.Offset() - end_methods;
   2202 
   2203     // Intern table is 8-byte aligned.
   2204     uint32_t end_caches = dex_cache_arrays_section.Offset() + dex_cache_arrays_section.Size();
   2205     CHECK_ALIGNED(intern_section.Offset(), sizeof(uint64_t));
   2206     stats_.alignment_bytes += intern_section.Offset() - end_caches;
   2207 
   2208     // Add space between intern table and class table.
   2209     uint32_t end_intern = intern_section.Offset() + intern_section.Size();
   2210     stats_.alignment_bytes += class_table_section.Offset() - end_intern;
   2211 
   2212     // Add space between end of image data and bitmap. Expect the bitmap to be page-aligned.
   2213     const size_t bitmap_offset = sizeof(ImageHeader) + data_size;
   2214     CHECK_ALIGNED(bitmap_section.Offset(), kPageSize);
   2215     stats_.alignment_bytes += RoundUp(bitmap_offset, kPageSize) - bitmap_offset;
   2216 
   2217     stats_.bitmap_bytes += bitmap_section.Size();
   2218     stats_.art_field_bytes += field_section.Size();
   2219     stats_.art_method_bytes += method_section.Size();
   2220     stats_.dex_cache_arrays_bytes += dex_cache_arrays_section.Size();
   2221     stats_.interned_strings_bytes += intern_section.Size();
   2222     stats_.class_table_bytes += class_table_section.Size();
   2223     stats_.Dump(os, indent_os);
   2224     os << "\n";
   2225 
   2226     os << std::flush;
   2227 
   2228     return oat_dumper_->Dump(os);
   2229   }
   2230 
   2231  private:
   2232   class DumpArtMethodVisitor : public ArtMethodVisitor {
   2233    public:
   2234     explicit DumpArtMethodVisitor(ImageDumper* image_dumper) : image_dumper_(image_dumper) {}
   2235 
   2236     virtual void Visit(ArtMethod* method) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
   2237       std::ostream& indent_os = image_dumper_->vios_.Stream();
   2238       indent_os << method << " " << " ArtMethod: " << ArtMethod::PrettyMethod(method) << "\n";
   2239       image_dumper_->DumpMethod(method, indent_os);
   2240       indent_os << "\n";
   2241     }
   2242 
   2243    private:
   2244     ImageDumper* const image_dumper_;
   2245   };
   2246 
   2247   static void PrettyObjectValue(std::ostream& os,
   2248                                 ObjPtr<mirror::Class> type,
   2249                                 ObjPtr<mirror::Object> value)
   2250       REQUIRES_SHARED(Locks::mutator_lock_) {
   2251     CHECK(type != nullptr);
   2252     if (value == nullptr) {
   2253       os << StringPrintf("null   %s\n", type->PrettyDescriptor().c_str());
   2254     } else if (type->IsStringClass()) {
   2255       mirror::String* string = value->AsString();
   2256       os << StringPrintf("%p   String: %s\n", string,
   2257                          PrintableString(string->ToModifiedUtf8().c_str()).c_str());
   2258     } else if (type->IsClassClass()) {
   2259       mirror::Class* klass = value->AsClass();
   2260       os << StringPrintf("%p   Class: %s\n", klass, mirror::Class::PrettyDescriptor(klass).c_str());
   2261     } else {
   2262       os << StringPrintf("%p   %s\n", value.Ptr(), type->PrettyDescriptor().c_str());
   2263     }
   2264   }
   2265 
   2266   static void PrintField(std::ostream& os, ArtField* field, ObjPtr<mirror::Object> obj)
   2267       REQUIRES_SHARED(Locks::mutator_lock_) {
   2268     os << StringPrintf("%s: ", field->GetName());
   2269     switch (field->GetTypeAsPrimitiveType()) {
   2270       case Primitive::kPrimLong:
   2271         os << StringPrintf("%" PRId64 " (0x%" PRIx64 ")\n", field->Get64(obj), field->Get64(obj));
   2272         break;
   2273       case Primitive::kPrimDouble:
   2274         os << StringPrintf("%f (%a)\n", field->GetDouble(obj), field->GetDouble(obj));
   2275         break;
   2276       case Primitive::kPrimFloat:
   2277         os << StringPrintf("%f (%a)\n", field->GetFloat(obj), field->GetFloat(obj));
   2278         break;
   2279       case Primitive::kPrimInt:
   2280         os << StringPrintf("%d (0x%x)\n", field->Get32(obj), field->Get32(obj));
   2281         break;
   2282       case Primitive::kPrimChar:
   2283         os << StringPrintf("%u (0x%x)\n", field->GetChar(obj), field->GetChar(obj));
   2284         break;
   2285       case Primitive::kPrimShort:
   2286         os << StringPrintf("%d (0x%x)\n", field->GetShort(obj), field->GetShort(obj));
   2287         break;
   2288       case Primitive::kPrimBoolean:
   2289         os << StringPrintf("%s (0x%x)\n", field->GetBoolean(obj) ? "true" : "false",
   2290             field->GetBoolean(obj));
   2291         break;
   2292       case Primitive::kPrimByte:
   2293         os << StringPrintf("%d (0x%x)\n", field->GetByte(obj), field->GetByte(obj));
   2294         break;
   2295       case Primitive::kPrimNot: {
   2296         // Get the value, don't compute the type unless it is non-null as we don't want
   2297         // to cause class loading.
   2298         ObjPtr<mirror::Object> value = field->GetObj(obj);
   2299         if (value == nullptr) {
   2300           os << StringPrintf("null   %s\n", PrettyDescriptor(field->GetTypeDescriptor()).c_str());
   2301         } else {
   2302           // Grab the field type without causing resolution.
   2303           ObjPtr<mirror::Class> field_type = field->LookupResolvedType();
   2304           if (field_type != nullptr) {
   2305             PrettyObjectValue(os, field_type, value);
   2306           } else {
   2307             os << StringPrintf("%p   %s\n",
   2308                                value.Ptr(),
   2309                                PrettyDescriptor(field->GetTypeDescriptor()).c_str());
   2310           }
   2311         }
   2312         break;
   2313       }
   2314       default:
   2315         os << "unexpected field type: " << field->GetTypeDescriptor() << "\n";
   2316         break;
   2317     }
   2318   }
   2319 
   2320   static void DumpFields(std::ostream& os, mirror::Object* obj, mirror::Class* klass)
   2321       REQUIRES_SHARED(Locks::mutator_lock_) {
   2322     mirror::Class* super = klass->GetSuperClass();
   2323     if (super != nullptr) {
   2324       DumpFields(os, obj, super);
   2325     }
   2326     for (ArtField& field : klass->GetIFields()) {
   2327       PrintField(os, &field, obj);
   2328     }
   2329   }
   2330 
   2331   bool InDumpSpace(const mirror::Object* object) {
   2332     return image_space_.Contains(object);
   2333   }
   2334 
   2335   const void* GetQuickOatCodeBegin(ArtMethod* m) REQUIRES_SHARED(Locks::mutator_lock_) {
   2336     const void* quick_code = m->GetEntryPointFromQuickCompiledCodePtrSize(
   2337         image_header_.GetPointerSize());
   2338     if (Runtime::Current()->GetClassLinker()->IsQuickResolutionStub(quick_code)) {
   2339       quick_code = oat_dumper_->GetQuickOatCode(m);
   2340     }
   2341     if (oat_dumper_->GetInstructionSet() == InstructionSet::kThumb2) {
   2342       quick_code = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(quick_code) & ~0x1);
   2343     }
   2344     return quick_code;
   2345   }
   2346 
   2347   uint32_t GetQuickOatCodeSize(ArtMethod* m)
   2348       REQUIRES_SHARED(Locks::mutator_lock_) {
   2349     const uint32_t* oat_code_begin = reinterpret_cast<const uint32_t*>(GetQuickOatCodeBegin(m));
   2350     if (oat_code_begin == nullptr) {
   2351       return 0;
   2352     }
   2353     return oat_code_begin[-1];
   2354   }
   2355 
   2356   const void* GetQuickOatCodeEnd(ArtMethod* m)
   2357       REQUIRES_SHARED(Locks::mutator_lock_) {
   2358     const uint8_t* oat_code_begin = reinterpret_cast<const uint8_t*>(GetQuickOatCodeBegin(m));
   2359     if (oat_code_begin == nullptr) {
   2360       return nullptr;
   2361     }
   2362     return oat_code_begin + GetQuickOatCodeSize(m);
   2363   }
   2364 
   2365   void DumpObject(mirror::Object* obj) REQUIRES_SHARED(Locks::mutator_lock_) {
   2366     DCHECK(obj != nullptr);
   2367     if (!InDumpSpace(obj)) {
   2368       return;
   2369     }
   2370 
   2371     size_t object_bytes = obj->SizeOf();
   2372     size_t alignment_bytes = RoundUp(object_bytes, kObjectAlignment) - object_bytes;
   2373     stats_.object_bytes += object_bytes;
   2374     stats_.alignment_bytes += alignment_bytes;
   2375 
   2376     std::ostream& os = vios_.Stream();
   2377 
   2378     mirror::Class* obj_class = obj->GetClass();
   2379     if (obj_class->IsArrayClass()) {
   2380       os << StringPrintf("%p: %s length:%d\n", obj, obj_class->PrettyDescriptor().c_str(),
   2381                          obj->AsArray()->GetLength());
   2382     } else if (obj->IsClass()) {
   2383       mirror::Class* klass = obj->AsClass();
   2384       os << StringPrintf("%p: java.lang.Class \"%s\" (", obj,
   2385                          mirror::Class::PrettyDescriptor(klass).c_str())
   2386          << klass->GetStatus() << ")\n";
   2387     } else if (obj_class->IsStringClass()) {
   2388       os << StringPrintf("%p: java.lang.String %s\n", obj,
   2389                          PrintableString(obj->AsString()->ToModifiedUtf8().c_str()).c_str());
   2390     } else {
   2391       os << StringPrintf("%p: %s\n", obj, obj_class->PrettyDescriptor().c_str());
   2392     }
   2393     ScopedIndentation indent1(&vios_);
   2394     DumpFields(os, obj, obj_class);
   2395     const PointerSize image_pointer_size = image_header_.GetPointerSize();
   2396     if (obj->IsObjectArray()) {
   2397       auto* obj_array = obj->AsObjectArray<mirror::Object>();
   2398       for (int32_t i = 0, length = obj_array->GetLength(); i < length; i++) {
   2399         mirror::Object* value = obj_array->Get(i);
   2400         size_t run = 0;
   2401         for (int32_t j = i + 1; j < length; j++) {
   2402           if (value == obj_array->Get(j)) {
   2403             run++;
   2404           } else {
   2405             break;
   2406           }
   2407         }
   2408         if (run == 0) {
   2409           os << StringPrintf("%d: ", i);
   2410         } else {
   2411           os << StringPrintf("%d to %zd: ", i, i + run);
   2412           i = i + run;
   2413         }
   2414         mirror::Class* value_class =
   2415             (value == nullptr) ? obj_class->GetComponentType() : value->GetClass();
   2416         PrettyObjectValue(os, value_class, value);
   2417       }
   2418     } else if (obj->IsClass()) {
   2419       ObjPtr<mirror::Class> klass = obj->AsClass();
   2420 
   2421       if (kBitstringSubtypeCheckEnabled) {
   2422         os << "SUBTYPE_CHECK_BITS: ";
   2423         SubtypeCheck<ObjPtr<mirror::Class>>::Dump(klass, os);
   2424         os << "\n";
   2425       }
   2426 
   2427       if (klass->NumStaticFields() != 0) {
   2428         os << "STATICS:\n";
   2429         ScopedIndentation indent2(&vios_);
   2430         for (ArtField& field : klass->GetSFields()) {
   2431           PrintField(os, &field, field.GetDeclaringClass());
   2432         }
   2433       }
   2434     } else {
   2435       auto it = dex_caches_.find(obj);
   2436       if (it != dex_caches_.end()) {
   2437         auto* dex_cache = down_cast<mirror::DexCache*>(obj);
   2438         const auto& field_section = image_header_.GetFieldsSection();
   2439         const auto& method_section = image_header_.GetMethodsSection();
   2440         size_t num_methods = dex_cache->NumResolvedMethods();
   2441         if (num_methods != 0u) {
   2442           os << "Methods (size=" << num_methods << "):\n";
   2443           ScopedIndentation indent2(&vios_);
   2444           mirror::MethodDexCacheType* resolved_methods = dex_cache->GetResolvedMethods();
   2445           for (size_t i = 0, length = dex_cache->NumResolvedMethods(); i < length; ++i) {
   2446             ArtMethod* elem = mirror::DexCache::GetNativePairPtrSize(
   2447                 resolved_methods, i, image_pointer_size).object;
   2448             size_t run = 0;
   2449             for (size_t j = i + 1;
   2450                  j != length &&
   2451                  elem == mirror::DexCache::GetNativePairPtrSize(
   2452                      resolved_methods, j, image_pointer_size).object;
   2453                  ++j) {
   2454               ++run;
   2455             }
   2456             if (run == 0) {
   2457               os << StringPrintf("%zd: ", i);
   2458             } else {
   2459               os << StringPrintf("%zd to %zd: ", i, i + run);
   2460               i = i + run;
   2461             }
   2462             std::string msg;
   2463             if (elem == nullptr) {
   2464               msg = "null";
   2465             } else if (method_section.Contains(
   2466                 reinterpret_cast<uint8_t*>(elem) - image_space_.Begin())) {
   2467               msg = reinterpret_cast<ArtMethod*>(elem)->PrettyMethod();
   2468             } else {
   2469               msg = "<not in method section>";
   2470             }
   2471             os << StringPrintf("%p   %s\n", elem, msg.c_str());
   2472           }
   2473         }
   2474         size_t num_fields = dex_cache->NumResolvedFields();
   2475         if (num_fields != 0u) {
   2476           os << "Fields (size=" << num_fields << "):\n";
   2477           ScopedIndentation indent2(&vios_);
   2478           auto* resolved_fields = dex_cache->GetResolvedFields();
   2479           for (size_t i = 0, length = dex_cache->NumResolvedFields(); i < length; ++i) {
   2480             ArtField* elem = mirror::DexCache::GetNativePairPtrSize(
   2481                 resolved_fields, i, image_pointer_size).object;
   2482             size_t run = 0;
   2483             for (size_t j = i + 1;
   2484                  j != length &&
   2485                  elem == mirror::DexCache::GetNativePairPtrSize(
   2486                      resolved_fields, j, image_pointer_size).object;
   2487                  ++j) {
   2488               ++run;
   2489             }
   2490             if (run == 0) {
   2491               os << StringPrintf("%zd: ", i);
   2492             } else {
   2493               os << StringPrintf("%zd to %zd: ", i, i + run);
   2494               i = i + run;
   2495             }
   2496             std::string msg;
   2497             if (elem == nullptr) {
   2498               msg = "null";
   2499             } else if (field_section.Contains(
   2500                 reinterpret_cast<uint8_t*>(elem) - image_space_.Begin())) {
   2501               msg = reinterpret_cast<ArtField*>(elem)->PrettyField();
   2502             } else {
   2503               msg = "<not in field section>";
   2504             }
   2505             os << StringPrintf("%p   %s\n", elem, msg.c_str());
   2506           }
   2507         }
   2508         size_t num_types = dex_cache->NumResolvedTypes();
   2509         if (num_types != 0u) {
   2510           os << "Types (size=" << num_types << "):\n";
   2511           ScopedIndentation indent2(&vios_);
   2512           auto* resolved_types = dex_cache->GetResolvedTypes();
   2513           for (size_t i = 0; i < num_types; ++i) {
   2514             auto pair = resolved_types[i].load(std::memory_order_relaxed);
   2515             size_t run = 0;
   2516             for (size_t j = i + 1; j != num_types; ++j) {
   2517               auto other_pair = resolved_types[j].load(std::memory_order_relaxed);
   2518               if (pair.index != other_pair.index ||
   2519                   pair.object.Read() != other_pair.object.Read()) {
   2520                 break;
   2521               }
   2522               ++run;
   2523             }
   2524             if (run == 0) {
   2525               os << StringPrintf("%zd: ", i);
   2526             } else {
   2527               os << StringPrintf("%zd to %zd: ", i, i + run);
   2528               i = i + run;
   2529             }
   2530             std::string msg;
   2531             auto* elem = pair.object.Read();
   2532             if (elem == nullptr) {
   2533               msg = "null";
   2534             } else {
   2535               msg = elem->PrettyClass();
   2536             }
   2537             os << StringPrintf("%p   %u %s\n", elem, pair.index, msg.c_str());
   2538           }
   2539         }
   2540       }
   2541     }
   2542     std::string temp;
   2543     stats_.Update(obj_class->GetDescriptor(&temp), object_bytes);
   2544   }
   2545 
   2546   void DumpMethod(ArtMethod* method, std::ostream& indent_os)
   2547       REQUIRES_SHARED(Locks::mutator_lock_) {
   2548     DCHECK(method != nullptr);
   2549     const void* quick_oat_code_begin = GetQuickOatCodeBegin(method);
   2550     const void* quick_oat_code_end = GetQuickOatCodeEnd(method);
   2551     const PointerSize pointer_size = image_header_.GetPointerSize();
   2552     OatQuickMethodHeader* method_header = reinterpret_cast<OatQuickMethodHeader*>(
   2553         reinterpret_cast<uintptr_t>(quick_oat_code_begin) - sizeof(OatQuickMethodHeader));
   2554     if (method->IsNative()) {
   2555       bool first_occurrence;
   2556       uint32_t quick_oat_code_size = GetQuickOatCodeSize(method);
   2557       ComputeOatSize(quick_oat_code_begin, &first_occurrence);
   2558       if (first_occurrence) {
   2559         stats_.native_to_managed_code_bytes += quick_oat_code_size;
   2560       }
   2561       if (quick_oat_code_begin != method->GetEntryPointFromQuickCompiledCodePtrSize(
   2562           image_header_.GetPointerSize())) {
   2563         indent_os << StringPrintf("OAT CODE: %p\n", quick_oat_code_begin);
   2564       }
   2565     } else if (method->IsAbstract() || method->IsClassInitializer()) {
   2566       // Don't print information for these.
   2567     } else if (method->IsRuntimeMethod()) {
   2568       ImtConflictTable* table = method->GetImtConflictTable(image_header_.GetPointerSize());
   2569       if (table != nullptr) {
   2570         indent_os << "IMT conflict table " << table << " method: ";
   2571         for (size_t i = 0, count = table->NumEntries(pointer_size); i < count; ++i) {
   2572           indent_os << ArtMethod::PrettyMethod(table->GetImplementationMethod(i, pointer_size))
   2573                     << " ";
   2574         }
   2575       }
   2576     } else {
   2577       CodeItemDataAccessor code_item_accessor(method->DexInstructionData());
   2578       size_t dex_instruction_bytes = code_item_accessor.InsnsSizeInCodeUnits() * 2;
   2579       stats_.dex_instruction_bytes += dex_instruction_bytes;
   2580 
   2581       bool first_occurrence;
   2582       size_t vmap_table_bytes = 0u;
   2583       if (!method_header->IsOptimized()) {
   2584         // Method compiled with the optimizing compiler have no vmap table.
   2585         vmap_table_bytes = ComputeOatSize(method_header->GetVmapTable(), &first_occurrence);
   2586         if (first_occurrence) {
   2587           stats_.vmap_table_bytes += vmap_table_bytes;
   2588         }
   2589       }
   2590 
   2591       uint32_t quick_oat_code_size = GetQuickOatCodeSize(method);
   2592       ComputeOatSize(quick_oat_code_begin, &first_occurrence);
   2593       if (first_occurrence) {
   2594         stats_.managed_code_bytes += quick_oat_code_size;
   2595         if (method->IsConstructor()) {
   2596           if (method->IsStatic()) {
   2597             stats_.class_initializer_code_bytes += quick_oat_code_size;
   2598           } else if (dex_instruction_bytes > kLargeConstructorDexBytes) {
   2599             stats_.large_initializer_code_bytes += quick_oat_code_size;
   2600           }
   2601         } else if (dex_instruction_bytes > kLargeMethodDexBytes) {
   2602           stats_.large_method_code_bytes += quick_oat_code_size;
   2603         }
   2604       }
   2605       stats_.managed_code_bytes_ignoring_deduplication += quick_oat_code_size;
   2606 
   2607       uint32_t method_access_flags = method->GetAccessFlags();
   2608 
   2609       indent_os << StringPrintf("OAT CODE: %p-%p\n", quick_oat_code_begin, quick_oat_code_end);
   2610       indent_os << StringPrintf("SIZE: Dex Instructions=%zd StackMaps=%zd AccessFlags=0x%x\n",
   2611                                 dex_instruction_bytes,
   2612                                 vmap_table_bytes,
   2613                                 method_access_flags);
   2614 
   2615       size_t total_size = dex_instruction_bytes +
   2616           vmap_table_bytes + quick_oat_code_size + ArtMethod::Size(image_header_.GetPointerSize());
   2617 
   2618       double expansion =
   2619       static_cast<double>(quick_oat_code_size) / static_cast<double>(dex_instruction_bytes);
   2620       stats_.ComputeOutliers(total_size, expansion, method);
   2621     }
   2622   }
   2623 
   2624   std::set<const void*> already_seen_;
   2625   // Compute the size of the given data within the oat file and whether this is the first time
   2626   // this data has been requested
   2627   size_t ComputeOatSize(const void* oat_data, bool* first_occurrence) {
   2628     if (already_seen_.count(oat_data) == 0) {
   2629       *first_occurrence = true;
   2630       already_seen_.insert(oat_data);
   2631     } else {
   2632       *first_occurrence = false;
   2633     }
   2634     return oat_dumper_->ComputeSize(oat_data);
   2635   }
   2636 
   2637  public:
   2638   struct Stats {
   2639     size_t oat_file_bytes;
   2640     size_t file_bytes;
   2641 
   2642     size_t header_bytes;
   2643     size_t object_bytes;
   2644     size_t art_field_bytes;
   2645     size_t art_method_bytes;
   2646     size_t dex_cache_arrays_bytes;
   2647     size_t interned_strings_bytes;
   2648     size_t class_table_bytes;
   2649     size_t bitmap_bytes;
   2650     size_t alignment_bytes;
   2651 
   2652     size_t managed_code_bytes;
   2653     size_t managed_code_bytes_ignoring_deduplication;
   2654     size_t native_to_managed_code_bytes;
   2655     size_t class_initializer_code_bytes;
   2656     size_t large_initializer_code_bytes;
   2657     size_t large_method_code_bytes;
   2658 
   2659     size_t vmap_table_bytes;
   2660 
   2661     size_t dex_instruction_bytes;
   2662 
   2663     std::vector<ArtMethod*> method_outlier;
   2664     std::vector<size_t> method_outlier_size;
   2665     std::vector<double> method_outlier_expansion;
   2666     std::vector<std::pair<std::string, size_t>> oat_dex_file_sizes;
   2667 
   2668     Stats()
   2669         : oat_file_bytes(0),
   2670           file_bytes(0),
   2671           header_bytes(0),
   2672           object_bytes(0),
   2673           art_field_bytes(0),
   2674           art_method_bytes(0),
   2675           dex_cache_arrays_bytes(0),
   2676           interned_strings_bytes(0),
   2677           class_table_bytes(0),
   2678           bitmap_bytes(0),
   2679           alignment_bytes(0),
   2680           managed_code_bytes(0),
   2681           managed_code_bytes_ignoring_deduplication(0),
   2682           native_to_managed_code_bytes(0),
   2683           class_initializer_code_bytes(0),
   2684           large_initializer_code_bytes(0),
   2685           large_method_code_bytes(0),
   2686           vmap_table_bytes(0),
   2687           dex_instruction_bytes(0) {}
   2688 
   2689     struct SizeAndCount {
   2690       SizeAndCount(size_t bytes_in, size_t count_in) : bytes(bytes_in), count(count_in) {}
   2691       size_t bytes;
   2692       size_t count;
   2693     };
   2694     typedef SafeMap<std::string, SizeAndCount> SizeAndCountTable;
   2695     SizeAndCountTable sizes_and_counts;
   2696 
   2697     void Update(const char* descriptor, size_t object_bytes_in) {
   2698       SizeAndCountTable::iterator it = sizes_and_counts.find(descriptor);
   2699       if (it != sizes_and_counts.end()) {
   2700         it->second.bytes += object_bytes_in;
   2701         it->second.count += 1;
   2702       } else {
   2703         sizes_and_counts.Put(descriptor, SizeAndCount(object_bytes_in, 1));
   2704       }
   2705     }
   2706 
   2707     double PercentOfOatBytes(size_t size) {
   2708       return (static_cast<double>(size) / static_cast<double>(oat_file_bytes)) * 100;
   2709     }
   2710 
   2711     double PercentOfFileBytes(size_t size) {
   2712       return (static_cast<double>(size) / static_cast<double>(file_bytes)) * 100;
   2713     }
   2714 
   2715     double PercentOfObjectBytes(size_t size) {
   2716       return (static_cast<double>(size) / static_cast<double>(object_bytes)) * 100;
   2717     }
   2718 
   2719     void ComputeOutliers(size_t total_size, double expansion, ArtMethod* method) {
   2720       method_outlier_size.push_back(total_size);
   2721       method_outlier_expansion.push_back(expansion);
   2722       method_outlier.push_back(method);
   2723     }
   2724 
   2725     void DumpOutliers(std::ostream& os)
   2726         REQUIRES_SHARED(Locks::mutator_lock_) {
   2727       size_t sum_of_sizes = 0;
   2728       size_t sum_of_sizes_squared = 0;
   2729       size_t sum_of_expansion = 0;
   2730       size_t sum_of_expansion_squared = 0;
   2731       size_t n = method_outlier_size.size();
   2732       if (n <= 1) {
   2733         return;
   2734       }
   2735       for (size_t i = 0; i < n; i++) {
   2736         size_t cur_size = method_outlier_size[i];
   2737         sum_of_sizes += cur_size;
   2738         sum_of_sizes_squared += cur_size * cur_size;
   2739         double cur_expansion = method_outlier_expansion[i];
   2740         sum_of_expansion += cur_expansion;
   2741         sum_of_expansion_squared += cur_expansion * cur_expansion;
   2742       }
   2743       size_t size_mean = sum_of_sizes / n;
   2744       size_t size_variance = (sum_of_sizes_squared - sum_of_sizes * size_mean) / (n - 1);
   2745       double expansion_mean = sum_of_expansion / n;
   2746       double expansion_variance =
   2747           (sum_of_expansion_squared - sum_of_expansion * expansion_mean) / (n - 1);
   2748 
   2749       // Dump methods whose size is a certain number of standard deviations from the mean
   2750       size_t dumped_values = 0;
   2751       size_t skipped_values = 0;
   2752       for (size_t i = 100; i > 0; i--) {  // i is the current number of standard deviations
   2753         size_t cur_size_variance = i * i * size_variance;
   2754         bool first = true;
   2755         for (size_t j = 0; j < n; j++) {
   2756           size_t cur_size = method_outlier_size[j];
   2757           if (cur_size > size_mean) {
   2758             size_t cur_var = cur_size - size_mean;
   2759             cur_var = cur_var * cur_var;
   2760             if (cur_var > cur_size_variance) {
   2761               if (dumped_values > 20) {
   2762                 if (i == 1) {
   2763                   skipped_values++;
   2764                 } else {
   2765                   i = 2;  // jump to counting for 1 standard deviation
   2766                   break;
   2767                 }
   2768               } else {
   2769                 if (first) {
   2770                   os << "\nBig methods (size > " << i << " standard deviations the norm):\n";
   2771                   first = false;
   2772                 }
   2773                 os << ArtMethod::PrettyMethod(method_outlier[j]) << " requires storage of "
   2774                     << PrettySize(cur_size) << "\n";
   2775                 method_outlier_size[j] = 0;  // don't consider this method again
   2776                 dumped_values++;
   2777               }
   2778             }
   2779           }
   2780         }
   2781       }
   2782       if (skipped_values > 0) {
   2783         os << "... skipped " << skipped_values
   2784            << " methods with size > 1 standard deviation from the norm\n";
   2785       }
   2786       os << std::flush;
   2787 
   2788       // Dump methods whose expansion is a certain number of standard deviations from the mean
   2789       dumped_values = 0;
   2790       skipped_values = 0;
   2791       for (size_t i = 10; i > 0; i--) {  // i is the current number of standard deviations
   2792         double cur_expansion_variance = i * i * expansion_variance;
   2793         bool first = true;
   2794         for (size_t j = 0; j < n; j++) {
   2795           double cur_expansion = method_outlier_expansion[j];
   2796           if (cur_expansion > expansion_mean) {
   2797             size_t cur_var = cur_expansion - expansion_mean;
   2798             cur_var = cur_var * cur_var;
   2799             if (cur_var > cur_expansion_variance) {
   2800               if (dumped_values > 20) {
   2801                 if (i == 1) {
   2802                   skipped_values++;
   2803                 } else {
   2804                   i = 2;  // jump to counting for 1 standard deviation
   2805                   break;
   2806                 }
   2807               } else {
   2808                 if (first) {
   2809                   os << "\nLarge expansion methods (size > " << i
   2810                       << " standard deviations the norm):\n";
   2811                   first = false;
   2812                 }
   2813                 os << ArtMethod::PrettyMethod(method_outlier[j]) << " expanded code by "
   2814                    << cur_expansion << "\n";
   2815                 method_outlier_expansion[j] = 0.0;  // don't consider this method again
   2816                 dumped_values++;
   2817               }
   2818             }
   2819           }
   2820         }
   2821       }
   2822       if (skipped_values > 0) {
   2823         os << "... skipped " << skipped_values
   2824            << " methods with expansion > 1 standard deviation from the norm\n";
   2825       }
   2826       os << "\n" << std::flush;
   2827     }
   2828 
   2829     void Dump(std::ostream& os, std::ostream& indent_os)
   2830         REQUIRES_SHARED(Locks::mutator_lock_) {
   2831       {
   2832         os << "art_file_bytes = " << PrettySize(file_bytes) << "\n\n"
   2833            << "art_file_bytes = header_bytes + object_bytes + alignment_bytes\n";
   2834         indent_os << StringPrintf("header_bytes           =  %8zd (%2.0f%% of art file bytes)\n"
   2835                                   "object_bytes           =  %8zd (%2.0f%% of art file bytes)\n"
   2836                                   "art_field_bytes        =  %8zd (%2.0f%% of art file bytes)\n"
   2837                                   "art_method_bytes       =  %8zd (%2.0f%% of art file bytes)\n"
   2838                                   "dex_cache_arrays_bytes =  %8zd (%2.0f%% of art file bytes)\n"
   2839                                   "interned_string_bytes  =  %8zd (%2.0f%% of art file bytes)\n"
   2840                                   "class_table_bytes      =  %8zd (%2.0f%% of art file bytes)\n"
   2841                                   "bitmap_bytes           =  %8zd (%2.0f%% of art file bytes)\n"
   2842                                   "alignment_bytes        =  %8zd (%2.0f%% of art file bytes)\n\n",
   2843                                   header_bytes, PercentOfFileBytes(header_bytes),
   2844                                   object_bytes, PercentOfFileBytes(object_bytes),
   2845                                   art_field_bytes, PercentOfFileBytes(art_field_bytes),
   2846                                   art_method_bytes, PercentOfFileBytes(art_method_bytes),
   2847                                   dex_cache_arrays_bytes,
   2848                                   PercentOfFileBytes(dex_cache_arrays_bytes),
   2849                                   interned_strings_bytes,
   2850                                   PercentOfFileBytes(interned_strings_bytes),
   2851                                   class_table_bytes, PercentOfFileBytes(class_table_bytes),
   2852                                   bitmap_bytes, PercentOfFileBytes(bitmap_bytes),
   2853                                   alignment_bytes, PercentOfFileBytes(alignment_bytes))
   2854             << std::flush;
   2855         CHECK_EQ(file_bytes,
   2856                  header_bytes + object_bytes + art_field_bytes + art_method_bytes +
   2857                  dex_cache_arrays_bytes + interned_strings_bytes + class_table_bytes +
   2858                  bitmap_bytes + alignment_bytes);
   2859       }
   2860 
   2861       os << "object_bytes breakdown:\n";
   2862       size_t object_bytes_total = 0;
   2863       for (const auto& sizes_and_count : sizes_and_counts) {
   2864         const std::string& descriptor(sizes_and_count.first);
   2865         double average = static_cast<double>(sizes_and_count.second.bytes) /
   2866             static_cast<double>(sizes_and_count.second.count);
   2867         double percent = PercentOfObjectBytes(sizes_and_count.second.bytes);
   2868         os << StringPrintf("%32s %8zd bytes %6zd instances "
   2869                            "(%4.0f bytes/instance) %2.0f%% of object_bytes\n",
   2870                            descriptor.c_str(), sizes_and_count.second.bytes,
   2871                            sizes_and_count.second.count, average, percent);
   2872         object_bytes_total += sizes_and_count.second.bytes;
   2873       }
   2874       os << "\n" << std::flush;
   2875       CHECK_EQ(object_bytes, object_bytes_total);
   2876 
   2877       os << StringPrintf("oat_file_bytes               = %8zd\n"
   2878                          "managed_code_bytes           = %8zd (%2.0f%% of oat file bytes)\n"
   2879                          "native_to_managed_code_bytes = %8zd (%2.0f%% of oat file bytes)\n\n"
   2880                          "class_initializer_code_bytes = %8zd (%2.0f%% of oat file bytes)\n"
   2881                          "large_initializer_code_bytes = %8zd (%2.0f%% of oat file bytes)\n"
   2882                          "large_method_code_bytes      = %8zd (%2.0f%% of oat file bytes)\n\n",
   2883                          oat_file_bytes,
   2884                          managed_code_bytes,
   2885                          PercentOfOatBytes(managed_code_bytes),
   2886                          native_to_managed_code_bytes,
   2887                          PercentOfOatBytes(native_to_managed_code_bytes),
   2888                          class_initializer_code_bytes,
   2889                          PercentOfOatBytes(class_initializer_code_bytes),
   2890                          large_initializer_code_bytes,
   2891                          PercentOfOatBytes(large_initializer_code_bytes),
   2892                          large_method_code_bytes,
   2893                          PercentOfOatBytes(large_method_code_bytes))
   2894             << "DexFile sizes:\n";
   2895       for (const std::pair<std::string, size_t>& oat_dex_file_size : oat_dex_file_sizes) {
   2896         os << StringPrintf("%s = %zd (%2.0f%% of oat file bytes)\n",
   2897                            oat_dex_file_size.first.c_str(), oat_dex_file_size.second,
   2898                            PercentOfOatBytes(oat_dex_file_size.second));
   2899       }
   2900 
   2901       os << "\n" << StringPrintf("vmap_table_bytes       = %7zd (%2.0f%% of oat file bytes)\n\n",
   2902                                  vmap_table_bytes, PercentOfOatBytes(vmap_table_bytes))
   2903          << std::flush;
   2904 
   2905       os << StringPrintf("dex_instruction_bytes = %zd\n", dex_instruction_bytes)
   2906          << StringPrintf("managed_code_bytes expansion = %.2f (ignoring deduplication %.2f)\n\n",
   2907                          static_cast<double>(managed_code_bytes) /
   2908                              static_cast<double>(dex_instruction_bytes),
   2909                          static_cast<double>(managed_code_bytes_ignoring_deduplication) /
   2910                              static_cast<double>(dex_instruction_bytes))
   2911          << std::flush;
   2912 
   2913       DumpOutliers(os);
   2914     }
   2915   } stats_;
   2916 
   2917  private:
   2918   enum {
   2919     // Number of bytes for a constructor to be considered large. Based on the 1000 basic block
   2920     // threshold, we assume 2 bytes per instruction and 2 instructions per block.
   2921     kLargeConstructorDexBytes = 4000,
   2922     // Number of bytes for a method to be considered large. Based on the 4000 basic block
   2923     // threshold, we assume 2 bytes per instruction and 2 instructions per block.
   2924     kLargeMethodDexBytes = 16000
   2925   };
   2926 
   2927   // For performance, use the *os_ directly for anything that doesn't need indentation
   2928   // and prepare an indentation stream with default indentation 1.
   2929   std::ostream* os_;
   2930   VariableIndentationOutputStream vios_;
   2931   ScopedIndentation indent1_;
   2932 
   2933   gc::space::ImageSpace& image_space_;
   2934   const ImageHeader& image_header_;
   2935   std::unique_ptr<OatDumper> oat_dumper_;
   2936   OatDumperOptions* oat_dumper_options_;
   2937   std::set<mirror::Object*> dex_caches_;
   2938 
   2939   DISALLOW_COPY_AND_ASSIGN(ImageDumper);
   2940 };
   2941 
   2942 static int DumpImage(gc::space::ImageSpace* image_space,
   2943                      OatDumperOptions* options,
   2944                      std::ostream* os) REQUIRES_SHARED(Locks::mutator_lock_) {
   2945   const ImageHeader& image_header = image_space->GetImageHeader();
   2946   if (!image_header.IsValid()) {
   2947     LOG(ERROR) << "Invalid image header " << image_space->GetImageLocation();
   2948     return EXIT_FAILURE;
   2949   }
   2950   ImageDumper image_dumper(os, *image_space, image_header, options);
   2951   if (!image_dumper.Dump()) {
   2952     return EXIT_FAILURE;
   2953   }
   2954   return EXIT_SUCCESS;
   2955 }
   2956 
   2957 static int DumpImages(Runtime* runtime, OatDumperOptions* options, std::ostream* os) {
   2958   // Dumping the image, no explicit class loader.
   2959   ScopedNullHandle<mirror::ClassLoader> null_class_loader;
   2960   options->class_loader_ = &null_class_loader;
   2961 
   2962   ScopedObjectAccess soa(Thread::Current());
   2963   if (options->app_image_ != nullptr) {
   2964     if (options->app_oat_ == nullptr) {
   2965       LOG(ERROR) << "Can not dump app image without app oat file";
   2966       return EXIT_FAILURE;
   2967     }
   2968     // We can't know if the app image is 32 bits yet, but it contains pointers into the oat file.
   2969     // We need to map the oat file in the low 4gb or else the fixup wont be able to fit oat file
   2970     // pointers into 32 bit pointer sized ArtMethods.
   2971     std::string error_msg;
   2972     std::unique_ptr<OatFile> oat_file(OatFile::Open(/* zip_fd */ -1,
   2973                                                     options->app_oat_,
   2974                                                     options->app_oat_,
   2975                                                     nullptr,
   2976                                                     nullptr,
   2977                                                     false,
   2978                                                     /*low_4gb*/true,
   2979                                                     nullptr,
   2980                                                     &error_msg));
   2981     if (oat_file == nullptr) {
   2982       LOG(ERROR) << "Failed to open oat file " << options->app_oat_ << " with error " << error_msg;
   2983       return EXIT_FAILURE;
   2984     }
   2985     std::unique_ptr<gc::space::ImageSpace> space(
   2986         gc::space::ImageSpace::CreateFromAppImage(options->app_image_, oat_file.get(), &error_msg));
   2987     if (space == nullptr) {
   2988       LOG(ERROR) << "Failed to open app image " << options->app_image_ << " with error "
   2989                  << error_msg;
   2990     }
   2991     // Open dex files for the image.
   2992     std::vector<std::unique_ptr<const DexFile>> dex_files;
   2993     if (!runtime->GetClassLinker()->OpenImageDexFiles(space.get(), &dex_files, &error_msg)) {
   2994       LOG(ERROR) << "Failed to open app image dex files " << options->app_image_ << " with error "
   2995                  << error_msg;
   2996     }
   2997     // Dump the actual image.
   2998     int result = DumpImage(space.get(), options, os);
   2999     if (result != EXIT_SUCCESS) {
   3000       return result;
   3001     }
   3002     // Fall through to dump the boot images.
   3003   }
   3004 
   3005   gc::Heap* heap = runtime->GetHeap();
   3006   CHECK(heap->HasBootImageSpace()) << "No image spaces";
   3007   for (gc::space::ImageSpace* image_space : heap->GetBootImageSpaces()) {
   3008     int result = DumpImage(image_space, options, os);
   3009     if (result != EXIT_SUCCESS) {
   3010       return result;
   3011     }
   3012   }
   3013   return EXIT_SUCCESS;
   3014 }
   3015 
   3016 static jobject InstallOatFile(Runtime* runtime,
   3017                               std::unique_ptr<OatFile> oat_file,
   3018                               std::vector<const DexFile*>* class_path)
   3019     REQUIRES_SHARED(Locks::mutator_lock_) {
   3020   Thread* self = Thread::Current();
   3021   CHECK(self != nullptr);
   3022   // Need well-known-classes.
   3023   WellKnownClasses::Init(self->GetJniEnv());
   3024 
   3025   // Open dex files.
   3026   OatFile* oat_file_ptr = oat_file.get();
   3027   ClassLinker* class_linker = runtime->GetClassLinker();
   3028   runtime->GetOatFileManager().RegisterOatFile(std::move(oat_file));
   3029   for (const OatFile::OatDexFile* odf : oat_file_ptr->GetOatDexFiles()) {
   3030     std::string error_msg;
   3031     const DexFile* const dex_file = OpenDexFile(odf, &error_msg);
   3032     CHECK(dex_file != nullptr) << error_msg;
   3033     class_path->push_back(dex_file);
   3034   }
   3035 
   3036   // Need a class loader. Fake that we're a compiler.
   3037   // Note: this will run initializers through the unstarted runtime, so make sure it's
   3038   //       initialized.
   3039   interpreter::UnstartedRuntime::Initialize();
   3040 
   3041   jobject class_loader = class_linker->CreatePathClassLoader(self, *class_path);
   3042 
   3043   // Need to register dex files to get a working dex cache.
   3044   for (const DexFile* dex_file : *class_path) {
   3045     ObjPtr<mirror::DexCache> dex_cache = class_linker->RegisterDexFile(
   3046         *dex_file, self->DecodeJObject(class_loader)->AsClassLoader());
   3047     CHECK(dex_cache != nullptr);
   3048   }
   3049 
   3050   return class_loader;
   3051 }
   3052 
   3053 static int DumpOatWithRuntime(Runtime* runtime,
   3054                               std::unique_ptr<OatFile> oat_file,
   3055                               OatDumperOptions* options,
   3056                               std::ostream* os) {
   3057   CHECK(runtime != nullptr && oat_file != nullptr && options != nullptr);
   3058   ScopedObjectAccess soa(Thread::Current());
   3059 
   3060   OatFile* oat_file_ptr = oat_file.get();
   3061   std::vector<const DexFile*> class_path;
   3062   jobject class_loader = InstallOatFile(runtime, std::move(oat_file), &class_path);
   3063 
   3064   // Use the class loader while dumping.
   3065   StackHandleScope<1> scope(soa.Self());
   3066   Handle<mirror::ClassLoader> loader_handle = scope.NewHandle(
   3067       soa.Decode<mirror::ClassLoader>(class_loader));
   3068   options->class_loader_ = &loader_handle;
   3069 
   3070   OatDumper oat_dumper(*oat_file_ptr, *options);
   3071   bool success = oat_dumper.Dump(*os);
   3072   return (success) ? EXIT_SUCCESS : EXIT_FAILURE;
   3073 }
   3074 
   3075 static int DumpOatWithoutRuntime(OatFile* oat_file, OatDumperOptions* options, std::ostream* os) {
   3076   CHECK(oat_file != nullptr && options != nullptr);
   3077   // No image = no class loader.
   3078   ScopedNullHandle<mirror::ClassLoader> null_class_loader;
   3079   options->class_loader_ = &null_class_loader;
   3080 
   3081   OatDumper oat_dumper(*oat_file, *options);
   3082   bool success = oat_dumper.Dump(*os);
   3083   return (success) ? EXIT_SUCCESS : EXIT_FAILURE;
   3084 }
   3085 
   3086 static int DumpOat(Runtime* runtime,
   3087                    const char* oat_filename,
   3088                    const char* dex_filename,
   3089                    OatDumperOptions* options,
   3090                    std::ostream* os) {
   3091   if (dex_filename == nullptr) {
   3092     LOG(WARNING) << "No dex filename provided, "
   3093                  << "oatdump might fail if the oat file does not contain the dex code.";
   3094   }
   3095   std::string error_msg;
   3096   std::unique_ptr<OatFile> oat_file(OatFile::Open(/* zip_fd */ -1,
   3097                                                   oat_filename,
   3098                                                   oat_filename,
   3099                                                   nullptr,
   3100                                                   nullptr,
   3101                                                   false,
   3102                                                   /*low_4gb*/false,
   3103                                                   dex_filename,
   3104                                                   &error_msg));
   3105   if (oat_file == nullptr) {
   3106     LOG(ERROR) << "Failed to open oat file from '" << oat_filename << "': " << error_msg;
   3107     return EXIT_FAILURE;
   3108   }
   3109 
   3110   if (runtime != nullptr) {
   3111     return DumpOatWithRuntime(runtime, std::move(oat_file), options, os);
   3112   } else {
   3113     return DumpOatWithoutRuntime(oat_file.get(), options, os);
   3114   }
   3115 }
   3116 
   3117 static int SymbolizeOat(const char* oat_filename,
   3118                         const char* dex_filename,
   3119                         std::string& output_name,
   3120                         bool no_bits) {
   3121   std::string error_msg;
   3122   std::unique_ptr<OatFile> oat_file(OatFile::Open(/* zip_fd */ -1,
   3123                                                   oat_filename,
   3124                                                   oat_filename,
   3125                                                   nullptr,
   3126                                                   nullptr,
   3127                                                   false,
   3128                                                   /*low_4gb*/false,
   3129                                                   dex_filename,
   3130                                                   &error_msg));
   3131   if (oat_file == nullptr) {
   3132     LOG(ERROR) << "Failed to open oat file from '" << oat_filename << "': " << error_msg;
   3133     return EXIT_FAILURE;
   3134   }
   3135 
   3136   bool result;
   3137   // Try to produce an ELF file of the same type. This is finicky, as we have used 32-bit ELF
   3138   // files for 64-bit code in the past.
   3139   if (Is64BitInstructionSet(oat_file->GetOatHeader().GetInstructionSet())) {
   3140     OatSymbolizer<ElfTypes64> oat_symbolizer(oat_file.get(), output_name, no_bits);
   3141     result = oat_symbolizer.Symbolize();
   3142   } else {
   3143     OatSymbolizer<ElfTypes32> oat_symbolizer(oat_file.get(), output_name, no_bits);
   3144     result = oat_symbolizer.Symbolize();
   3145   }
   3146   if (!result) {
   3147     LOG(ERROR) << "Failed to symbolize";
   3148     return EXIT_FAILURE;
   3149   }
   3150 
   3151   return EXIT_SUCCESS;
   3152 }
   3153 
   3154 class IMTDumper {
   3155  public:
   3156   static bool Dump(Runtime* runtime,
   3157                    const std::string& imt_file,
   3158                    bool dump_imt_stats,
   3159                    const char* oat_filename,
   3160                    const char* dex_filename) {
   3161     Thread* self = Thread::Current();
   3162 
   3163     ScopedObjectAccess soa(self);
   3164     StackHandleScope<1> scope(self);
   3165     MutableHandle<mirror::ClassLoader> class_loader = scope.NewHandle<mirror::ClassLoader>(nullptr);
   3166     std::vector<const DexFile*> class_path;
   3167 
   3168     if (oat_filename != nullptr) {
   3169       std::string error_msg;
   3170       std::unique_ptr<OatFile> oat_file(OatFile::Open(/* zip_fd */ -1,
   3171                                                       oat_filename,
   3172                                                       oat_filename,
   3173                                                       nullptr,
   3174                                                       nullptr,
   3175                                                       false,
   3176                                                       /*low_4gb*/false,
   3177                                                       dex_filename,
   3178                                                       &error_msg));
   3179       if (oat_file == nullptr) {
   3180         LOG(ERROR) << "Failed to open oat file from '" << oat_filename << "': " << error_msg;
   3181         return false;
   3182       }
   3183 
   3184       class_loader.Assign(soa.Decode<mirror::ClassLoader>(
   3185           InstallOatFile(runtime, std::move(oat_file), &class_path)));
   3186     } else {
   3187       class_loader.Assign(nullptr);  // Boot classloader. Just here for explicit documentation.
   3188       class_path = runtime->GetClassLinker()->GetBootClassPath();
   3189     }
   3190 
   3191     if (!imt_file.empty()) {
   3192       return DumpImt(runtime, imt_file, class_loader);
   3193     }
   3194 
   3195     if (dump_imt_stats) {
   3196       return DumpImtStats(runtime, class_path, class_loader);
   3197     }
   3198 
   3199     LOG(FATAL) << "Should not reach here";
   3200     UNREACHABLE();
   3201   }
   3202 
   3203  private:
   3204   static bool DumpImt(Runtime* runtime,
   3205                       const std::string& imt_file,
   3206                       Handle<mirror::ClassLoader> h_class_loader)
   3207       REQUIRES_SHARED(Locks::mutator_lock_) {
   3208     std::vector<std::string> lines = ReadCommentedInputFromFile(imt_file);
   3209     std::unordered_set<std::string> prepared;
   3210 
   3211     for (const std::string& line : lines) {
   3212       // A line should be either a class descriptor, in which case we will dump the complete IMT,
   3213       // or a class descriptor and an interface method, in which case we will lookup the method,
   3214       // determine its IMT slot, and check the class' IMT.
   3215       size_t first_space = line.find(' ');
   3216       if (first_space == std::string::npos) {
   3217         DumpIMTForClass(runtime, line, h_class_loader, &prepared);
   3218       } else {
   3219         DumpIMTForMethod(runtime,
   3220                          line.substr(0, first_space),
   3221                          line.substr(first_space + 1, std::string::npos),
   3222                          h_class_loader,
   3223                          &prepared);
   3224       }
   3225       std::cerr << std::endl;
   3226     }
   3227 
   3228     return true;
   3229   }
   3230 
   3231   static bool DumpImtStats(Runtime* runtime,
   3232                            const std::vector<const DexFile*>& dex_files,
   3233                            Handle<mirror::ClassLoader> h_class_loader)
   3234       REQUIRES_SHARED(Locks::mutator_lock_) {
   3235     size_t without_imt = 0;
   3236     size_t with_imt = 0;
   3237     std::map<size_t, size_t> histogram;
   3238 
   3239     ClassLinker* class_linker = runtime->GetClassLinker();
   3240     const PointerSize pointer_size = class_linker->GetImagePointerSize();
   3241     std::unordered_set<std::string> prepared;
   3242 
   3243     Thread* self = Thread::Current();
   3244     StackHandleScope<1> scope(self);
   3245     MutableHandle<mirror::Class> h_klass(scope.NewHandle<mirror::Class>(nullptr));
   3246 
   3247     for (const DexFile* dex_file : dex_files) {
   3248       for (uint32_t class_def_index = 0;
   3249            class_def_index != dex_file->NumClassDefs();
   3250            ++class_def_index) {
   3251         const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
   3252         const char* descriptor = dex_file->GetClassDescriptor(class_def);
   3253         h_klass.Assign(class_linker->FindClass(self, descriptor, h_class_loader));
   3254         if (h_klass == nullptr) {
   3255           std::cerr << "Warning: could not load " << descriptor << std::endl;
   3256           continue;
   3257         }
   3258 
   3259         if (HasNoIMT(runtime, h_klass, pointer_size, &prepared)) {
   3260           without_imt++;
   3261           continue;
   3262         }
   3263 
   3264         ImTable* im_table = PrepareAndGetImTable(runtime, h_klass, pointer_size, &prepared);
   3265         if (im_table == nullptr) {
   3266           // Should not happen, but accept.
   3267           without_imt++;
   3268           continue;
   3269         }
   3270 
   3271         with_imt++;
   3272         for (size_t imt_index = 0; imt_index != ImTable::kSize; ++imt_index) {
   3273           ArtMethod* ptr = im_table->Get(imt_index, pointer_size);
   3274           if (ptr->IsRuntimeMethod()) {
   3275             if (ptr->IsImtUnimplementedMethod()) {
   3276               histogram[0]++;
   3277             } else {
   3278               ImtConflictTable* current_table = ptr->GetImtConflictTable(pointer_size);
   3279               histogram[current_table->NumEntries(pointer_size)]++;
   3280             }
   3281           } else {
   3282             histogram[1]++;
   3283           }
   3284         }
   3285       }
   3286     }
   3287 
   3288     std::cerr << "IMT stats:"
   3289               << std::endl << std::endl;
   3290 
   3291     std::cerr << "  " << with_imt << " classes with IMT."
   3292               << std::endl << std::endl;
   3293     std::cerr << "  " << without_imt << " classes without IMT (or copy from Object)."
   3294               << std::endl << std::endl;
   3295 
   3296     double sum_one = 0;
   3297     size_t count_one = 0;
   3298 
   3299     std::cerr << "  " << "IMT histogram" << std::endl;
   3300     for (auto& bucket : histogram) {
   3301       std::cerr << "    " << bucket.first << " " << bucket.second << std::endl;
   3302       if (bucket.first > 0) {
   3303         sum_one += bucket.second * bucket.first;
   3304         count_one += bucket.second;
   3305       }
   3306     }
   3307 
   3308     double count_zero = count_one + histogram[0];
   3309     std::cerr << "   Stats:" << std::endl;
   3310     std::cerr << "     Average depth (including empty): " << (sum_one / count_zero) << std::endl;
   3311     std::cerr << "     Average depth (excluding empty): " << (sum_one / count_one) << std::endl;
   3312 
   3313     return true;
   3314   }
   3315 
   3316   // Return whether the given class has no IMT (or the one shared with java.lang.Object).
   3317   static bool HasNoIMT(Runtime* runtime,
   3318                        Handle<mirror::Class> klass,
   3319                        const PointerSize pointer_size,
   3320                        std::unordered_set<std::string>* prepared)
   3321       REQUIRES_SHARED(Locks::mutator_lock_) {
   3322     if (klass->IsObjectClass() || !klass->ShouldHaveImt()) {
   3323       return true;
   3324     }
   3325 
   3326     if (klass->GetImt(pointer_size) == nullptr) {
   3327       PrepareClass(runtime, klass, prepared);
   3328     }
   3329 
   3330     mirror::Class* object_class = mirror::Class::GetJavaLangClass()->GetSuperClass();
   3331     DCHECK(object_class->IsObjectClass());
   3332 
   3333     bool result = klass->GetImt(pointer_size) == object_class->GetImt(pointer_size);
   3334 
   3335     if (klass->GetIfTable()->Count() == 0) {
   3336       DCHECK(result);
   3337     }
   3338 
   3339     return result;
   3340   }
   3341 
   3342   static void PrintTable(ImtConflictTable* table, PointerSize pointer_size)
   3343       REQUIRES_SHARED(Locks::mutator_lock_) {
   3344     if (table == nullptr) {
   3345       std::cerr << "    <No IMT?>" << std::endl;
   3346       return;
   3347     }
   3348     size_t table_index = 0;
   3349     for (;;) {
   3350       ArtMethod* ptr = table->GetInterfaceMethod(table_index, pointer_size);
   3351       if (ptr == nullptr) {
   3352         return;
   3353       }
   3354       table_index++;
   3355       std::cerr << "    " << ptr->PrettyMethod(true) << std::endl;
   3356     }
   3357   }
   3358 
   3359   static ImTable* PrepareAndGetImTable(Runtime* runtime,
   3360                                        Thread* self,
   3361                                        Handle<mirror::ClassLoader> h_loader,
   3362                                        const std::string& class_name,
   3363                                        const PointerSize pointer_size,
   3364                                        mirror::Class** klass_out,
   3365                                        std::unordered_set<std::string>* prepared)
   3366       REQUIRES_SHARED(Locks::mutator_lock_) {
   3367     if (class_name.empty()) {
   3368       return nullptr;
   3369     }
   3370 
   3371     std::string descriptor;
   3372     if (class_name[0] == 'L') {
   3373       descriptor = class_name;
   3374     } else {
   3375       descriptor = DotToDescriptor(class_name.c_str());
   3376     }
   3377 
   3378     mirror::Class* klass = runtime->GetClassLinker()->FindClass(self, descriptor.c_str(), h_loader);
   3379 
   3380     if (klass == nullptr) {
   3381       self->ClearException();
   3382       std::cerr << "Did not find " <<  class_name << std::endl;
   3383       *klass_out = nullptr;
   3384       return nullptr;
   3385     }
   3386 
   3387     StackHandleScope<1> scope(Thread::Current());
   3388     Handle<mirror::Class> h_klass = scope.NewHandle<mirror::Class>(klass);
   3389 
   3390     ImTable* ret = PrepareAndGetImTable(runtime, h_klass, pointer_size, prepared);
   3391     *klass_out = h_klass.Get();
   3392     return ret;
   3393   }
   3394 
   3395   static ImTable* PrepareAndGetImTable(Runtime* runtime,
   3396                                        Handle<mirror::Class> h_klass,
   3397                                        const PointerSize pointer_size,
   3398                                        std::unordered_set<std::string>* prepared)
   3399       REQUIRES_SHARED(Locks::mutator_lock_) {
   3400     PrepareClass(runtime, h_klass, prepared);
   3401     return h_klass->GetImt(pointer_size);
   3402   }
   3403 
   3404   static void DumpIMTForClass(Runtime* runtime,
   3405                               const std::string& class_name,
   3406                               Handle<mirror::ClassLoader> h_loader,
   3407                               std::unordered_set<std::string>* prepared)
   3408       REQUIRES_SHARED(Locks::mutator_lock_) {
   3409     const PointerSize pointer_size = runtime->GetClassLinker()->GetImagePointerSize();
   3410     mirror::Class* klass;
   3411     ImTable* imt = PrepareAndGetImTable(runtime,
   3412                                         Thread::Current(),
   3413                                         h_loader,
   3414                                         class_name,
   3415                                         pointer_size,
   3416                                         &klass,
   3417                                         prepared);
   3418     if (imt == nullptr) {
   3419       return;
   3420     }
   3421 
   3422     std::cerr << class_name << std::endl << " IMT:" << std::endl;
   3423     for (size_t index = 0; index < ImTable::kSize; ++index) {
   3424       std::cerr << "  " << index << ":" << std::endl;
   3425       ArtMethod* ptr = imt->Get(index, pointer_size);
   3426       if (ptr->IsRuntimeMethod()) {
   3427         if (ptr->IsImtUnimplementedMethod()) {
   3428           std::cerr << "    <empty>" << std::endl;
   3429         } else {
   3430           ImtConflictTable* current_table = ptr->GetImtConflictTable(pointer_size);
   3431           PrintTable(current_table, pointer_size);
   3432         }
   3433       } else {
   3434         std::cerr << "    " << ptr->PrettyMethod(true) << std::endl;
   3435       }
   3436     }
   3437 
   3438     std::cerr << " Interfaces:" << std::endl;
   3439     // Run through iftable, find methods that slot here, see if they fit.
   3440     mirror::IfTable* if_table = klass->GetIfTable();
   3441     for (size_t i = 0, num_interfaces = klass->GetIfTableCount(); i < num_interfaces; ++i) {
   3442       mirror::Class* iface = if_table->GetInterface(i);
   3443       std::string iface_name;
   3444       std::cerr << "  " << iface->GetDescriptor(&iface_name) << std::endl;
   3445 
   3446       for (ArtMethod& iface_method : iface->GetVirtualMethods(pointer_size)) {
   3447         uint32_t class_hash, name_hash, signature_hash;
   3448         ImTable::GetImtHashComponents(&iface_method, &class_hash, &name_hash, &signature_hash);
   3449         uint32_t imt_slot = ImTable::GetImtIndex(&iface_method);
   3450         std::cerr << "    " << iface_method.PrettyMethod(true)
   3451             << " slot=" << imt_slot
   3452             << std::hex
   3453             << " class_hash=0x" << class_hash
   3454             << " name_hash=0x" << name_hash
   3455             << " signature_hash=0x" << signature_hash
   3456             << std::dec
   3457             << std::endl;
   3458       }
   3459     }
   3460   }
   3461 
   3462   static void DumpIMTForMethod(Runtime* runtime,
   3463                                const std::string& class_name,
   3464                                const std::string& method,
   3465                                Handle<mirror::ClassLoader> h_loader,
   3466                                std::unordered_set<std::string>* prepared)
   3467       REQUIRES_SHARED(Locks::mutator_lock_) {
   3468     const PointerSize pointer_size = runtime->GetClassLinker()->GetImagePointerSize();
   3469     mirror::Class* klass;
   3470     ImTable* imt = PrepareAndGetImTable(runtime,
   3471                                         Thread::Current(),
   3472                                         h_loader,
   3473                                         class_name,
   3474                                         pointer_size,
   3475                                         &klass,
   3476                                         prepared);
   3477     if (imt == nullptr) {
   3478       return;
   3479     }
   3480 
   3481     std::cerr << class_name << " <" << method << ">" << std::endl;
   3482     for (size_t index = 0; index < ImTable::kSize; ++index) {
   3483       ArtMethod* ptr = imt->Get(index, pointer_size);
   3484       if (ptr->IsRuntimeMethod()) {
   3485         if (ptr->IsImtUnimplementedMethod()) {
   3486           continue;
   3487         }
   3488 
   3489         ImtConflictTable* current_table = ptr->GetImtConflictTable(pointer_size);
   3490         if (current_table == nullptr) {
   3491           continue;
   3492         }
   3493 
   3494         size_t table_index = 0;
   3495         for (;;) {
   3496           ArtMethod* ptr2 = current_table->GetInterfaceMethod(table_index, pointer_size);
   3497           if (ptr2 == nullptr) {
   3498             break;
   3499           }
   3500           table_index++;
   3501 
   3502           std::string p_name = ptr2->PrettyMethod(true);
   3503           if (android::base::StartsWith(p_name, method.c_str())) {
   3504             std::cerr << "  Slot "
   3505                       << index
   3506                       << " ("
   3507                       << current_table->NumEntries(pointer_size)
   3508                       << ")"
   3509                       << std::endl;
   3510             PrintTable(current_table, pointer_size);
   3511             return;
   3512           }
   3513         }
   3514       } else {
   3515         std::string p_name = ptr->PrettyMethod(true);
   3516         if (android::base::StartsWith(p_name, method.c_str())) {
   3517           std::cerr << "  Slot " << index << " (1)" << std::endl;
   3518           std::cerr << "    " << p_name << std::endl;
   3519         } else {
   3520           // Run through iftable, find methods that slot here, see if they fit.
   3521           mirror::IfTable* if_table = klass->GetIfTable();
   3522           for (size_t i = 0, num_interfaces = klass->GetIfTableCount(); i < num_interfaces; ++i) {
   3523             mirror::Class* iface = if_table->GetInterface(i);
   3524             size_t num_methods = iface->NumDeclaredVirtualMethods();
   3525             if (num_methods > 0) {
   3526               for (ArtMethod& iface_method : iface->GetMethods(pointer_size)) {
   3527                 if (ImTable::GetImtIndex(&iface_method) == index) {
   3528                   std::string i_name = iface_method.PrettyMethod(true);
   3529                   if (android::base::StartsWith(i_name, method.c_str())) {
   3530                     std::cerr << "  Slot " << index << " (1)" << std::endl;
   3531                     std::cerr << "    " << p_name << " (" << i_name << ")" << std::endl;
   3532                   }
   3533                 }
   3534               }
   3535             }
   3536           }
   3537         }
   3538       }
   3539     }
   3540   }
   3541 
   3542   // Read lines from the given stream, dropping comments and empty lines
   3543   static std::vector<std::string> ReadCommentedInputStream(std::istream& in_stream) {
   3544     std::vector<std::string> output;
   3545     while (in_stream.good()) {
   3546       std::string dot;
   3547       std::getline(in_stream, dot);
   3548       if (android::base::StartsWith(dot, "#") || dot.empty()) {
   3549         continue;
   3550       }
   3551       output.push_back(dot);
   3552     }
   3553     return output;
   3554   }
   3555 
   3556   // Read lines from the given file, dropping comments and empty lines.
   3557   static std::vector<std::string> ReadCommentedInputFromFile(const std::string& input_filename) {
   3558     std::unique_ptr<std::ifstream> input_file(new std::ifstream(input_filename, std::ifstream::in));
   3559     if (input_file.get() == nullptr) {
   3560       LOG(ERROR) << "Failed to open input file " << input_filename;
   3561       return std::vector<std::string>();
   3562     }
   3563     std::vector<std::string> result = ReadCommentedInputStream(*input_file);
   3564     input_file->close();
   3565     return result;
   3566   }
   3567 
   3568   // Prepare a class, i.e., ensure it has a filled IMT. Will do so recursively for superclasses,
   3569   // and note in the given set that the work was done.
   3570   static void PrepareClass(Runtime* runtime,
   3571                            Handle<mirror::Class> h_klass,
   3572                            std::unordered_set<std::string>* done)
   3573       REQUIRES_SHARED(Locks::mutator_lock_) {
   3574     if (!h_klass->ShouldHaveImt()) {
   3575       return;
   3576     }
   3577 
   3578     std::string name;
   3579     name = h_klass->GetDescriptor(&name);
   3580 
   3581     if (done->find(name) != done->end()) {
   3582       return;
   3583     }
   3584     done->insert(name);
   3585 
   3586     if (h_klass->HasSuperClass()) {
   3587       StackHandleScope<1> h(Thread::Current());
   3588       PrepareClass(runtime, h.NewHandle<mirror::Class>(h_klass->GetSuperClass()), done);
   3589     }
   3590 
   3591     if (!h_klass->IsTemp()) {
   3592       runtime->GetClassLinker()->FillIMTAndConflictTables(h_klass.Get());
   3593     }
   3594   }
   3595 };
   3596 
   3597 struct OatdumpArgs : public CmdlineArgs {
   3598  protected:
   3599   using Base = CmdlineArgs;
   3600 
   3601   virtual ParseStatus ParseCustom(const StringPiece& option,
   3602                                   std::string* error_msg) OVERRIDE {
   3603     {
   3604       ParseStatus base_parse = Base::ParseCustom(option, error_msg);
   3605       if (base_parse != kParseUnknownArgument) {
   3606         return base_parse;
   3607       }
   3608     }
   3609 
   3610     if (option.starts_with("--oat-file=")) {
   3611       oat_filename_ = option.substr(strlen("--oat-file=")).data();
   3612     } else if (option.starts_with("--dex-file=")) {
   3613       dex_filename_ = option.substr(strlen("--dex-file=")).data();
   3614     } else if (option.starts_with("--image=")) {
   3615       image_location_ = option.substr(strlen("--image=")).data();
   3616     } else if (option == "--no-dump:vmap") {
   3617       dump_vmap_ = false;
   3618     } else if (option =="--dump:code_info_stack_maps") {
   3619       dump_code_info_stack_maps_ = true;
   3620     } else if (option == "--no-disassemble") {
   3621       disassemble_code_ = false;
   3622     } else if (option =="--header-only") {
   3623       dump_header_only_ = true;
   3624     } else if (option.starts_with("--symbolize=")) {
   3625       oat_filename_ = option.substr(strlen("--symbolize=")).data();
   3626       symbolize_ = true;
   3627     } else if (option.starts_with("--only-keep-debug")) {
   3628       only_keep_debug_ = true;
   3629     } else if (option.starts_with("--class-filter=")) {
   3630       class_filter_ = option.substr(strlen("--class-filter=")).data();
   3631     } else if (option.starts_with("--method-filter=")) {
   3632       method_filter_ = option.substr(strlen("--method-filter=")).data();
   3633     } else if (option.starts_with("--list-classes")) {
   3634       list_classes_ = true;
   3635     } else if (option.starts_with("--list-methods")) {
   3636       list_methods_ = true;
   3637     } else if (option.starts_with("--export-dex-to=")) {
   3638       export_dex_location_ = option.substr(strlen("--export-dex-to=")).data();
   3639     } else if (option.starts_with("--addr2instr=")) {
   3640       if (!ParseUint(option.substr(strlen("--addr2instr=")).data(), &addr2instr_)) {
   3641         *error_msg = "Address conversion failed";
   3642         return kParseError;
   3643       }
   3644     } else if (option.starts_with("--app-image=")) {
   3645       app_image_ = option.substr(strlen("--app-image=")).data();
   3646     } else if (option.starts_with("--app-oat=")) {
   3647       app_oat_ = option.substr(strlen("--app-oat=")).data();
   3648     } else if (option.starts_with("--dump-imt=")) {
   3649       imt_dump_ = option.substr(strlen("--dump-imt=")).data();
   3650     } else if (option == "--dump-imt-stats") {
   3651       imt_stat_dump_ = true;
   3652     } else {
   3653       return kParseUnknownArgument;
   3654     }
   3655 
   3656     return kParseOk;
   3657   }
   3658 
   3659   virtual ParseStatus ParseChecks(std::string* error_msg) OVERRIDE {
   3660     // Infer boot image location from the image location if possible.
   3661     if (boot_image_location_ == nullptr) {
   3662       boot_image_location_ = image_location_;
   3663     }
   3664 
   3665     // Perform the parent checks.
   3666     ParseStatus parent_checks = Base::ParseChecks(error_msg);
   3667     if (parent_checks != kParseOk) {
   3668       return parent_checks;
   3669     }
   3670 
   3671     // Perform our own checks.
   3672     if (image_location_ == nullptr && oat_filename_ == nullptr) {
   3673       *error_msg = "Either --image or --oat-file must be specified";
   3674       return kParseError;
   3675     } else if (image_location_ != nullptr && oat_filename_ != nullptr) {
   3676       *error_msg = "Either --image or --oat-file must be specified but not both";
   3677       return kParseError;
   3678     }
   3679 
   3680     return kParseOk;
   3681   }
   3682 
   3683   virtual std::string GetUsage() const {
   3684     std::string usage;
   3685 
   3686     usage +=
   3687         "Usage: oatdump [options] ...\n"
   3688         "    Example: oatdump --image=$ANDROID_PRODUCT_OUT/system/framework/boot.art\n"
   3689         "    Example: adb shell oatdump --image=/system/framework/boot.art\n"
   3690         "\n"
   3691         // Either oat-file or image is required.
   3692         "  --oat-file=<file.oat>: specifies an input oat filename.\n"
   3693         "      Example: --oat-file=/system/framework/boot.oat\n"
   3694         "\n"
   3695         "  --image=<file.art>: specifies an input image location.\n"
   3696         "      Example: --image=/system/framework/boot.art\n"
   3697         "\n"
   3698         "  --app-image=<file.art>: specifies an input app image. Must also have a specified\n"
   3699         " boot image (with --image) and app oat file (with --app-oat).\n"
   3700         "      Example: --app-image=app.art\n"
   3701         "\n"
   3702         "  --app-oat=<file.odex>: specifies an input app oat.\n"
   3703         "      Example: --app-oat=app.odex\n"
   3704         "\n";
   3705 
   3706     usage += Base::GetUsage();
   3707 
   3708     usage +=  // Optional.
   3709         "  --no-dump:vmap may be used to disable vmap dumping.\n"
   3710         "      Example: --no-dump:vmap\n"
   3711         "\n"
   3712         "  --dump:code_info_stack_maps enables dumping of stack maps in CodeInfo sections.\n"
   3713         "      Example: --dump:code_info_stack_maps\n"
   3714         "\n"
   3715         "  --no-disassemble may be used to disable disassembly.\n"
   3716         "      Example: --no-disassemble\n"
   3717         "\n"
   3718         "  --header-only may be used to print only the oat header.\n"
   3719         "      Example: --header-only\n"
   3720         "\n"
   3721         "  --list-classes may be used to list target file classes (can be used with filters).\n"
   3722         "      Example: --list-classes\n"
   3723         "      Example: --list-classes --class-filter=com.example.foo\n"
   3724         "\n"
   3725         "  --list-methods may be used to list target file methods (can be used with filters).\n"
   3726         "      Example: --list-methods\n"
   3727         "      Example: --list-methods --class-filter=com.example --method-filter=foo\n"
   3728         "\n"
   3729         "  --symbolize=<file.oat>: output a copy of file.oat with elf symbols included.\n"
   3730         "      Example: --symbolize=/system/framework/boot.oat\n"
   3731         "\n"
   3732         "  --only-keep-debug<file.oat>: Modifies the behaviour of --symbolize so that\n"
   3733         "      .rodata and .text sections are omitted in the output file to save space.\n"
   3734         "      Example: --symbolize=/system/framework/boot.oat --only-keep-debug\n"
   3735         "\n"
   3736         "  --class-filter=<class name>: only dumps classes that contain the filter.\n"
   3737         "      Example: --class-filter=com.example.foo\n"
   3738         "\n"
   3739         "  --method-filter=<method name>: only dumps methods that contain the filter.\n"
   3740         "      Example: --method-filter=foo\n"
   3741         "\n"
   3742         "  --export-dex-to=<directory>: may be used to export oat embedded dex files.\n"
   3743         "      Example: --export-dex-to=/data/local/tmp\n"
   3744         "\n"
   3745         "  --addr2instr=<address>: output matching method disassembled code from relative\n"
   3746         "                          address (e.g. PC from crash dump)\n"
   3747         "      Example: --addr2instr=0x00001a3b\n"
   3748         "\n"
   3749         "  --dump-imt=<file.txt>: output IMT collisions (if any) for the given receiver\n"
   3750         "                         types and interface methods in the given file. The file\n"
   3751         "                         is read line-wise, where each line should either be a class\n"
   3752         "                         name or descriptor, or a class name/descriptor and a prefix\n"
   3753         "                         of a complete method name (separated by a whitespace).\n"
   3754         "      Example: --dump-imt=imt.txt\n"
   3755         "\n"
   3756         "  --dump-imt-stats: output IMT statistics for the given boot image\n"
   3757         "      Example: --dump-imt-stats"
   3758         "\n";
   3759 
   3760     return usage;
   3761   }
   3762 
   3763  public:
   3764   const char* oat_filename_ = nullptr;
   3765   const char* dex_filename_ = nullptr;
   3766   const char* class_filter_ = "";
   3767   const char* method_filter_ = "";
   3768   const char* image_location_ = nullptr;
   3769   std::string elf_filename_prefix_;
   3770   std::string imt_dump_;
   3771   bool dump_vmap_ = true;
   3772   bool dump_code_info_stack_maps_ = false;
   3773   bool disassemble_code_ = true;
   3774   bool symbolize_ = false;
   3775   bool only_keep_debug_ = false;
   3776   bool list_classes_ = false;
   3777   bool list_methods_ = false;
   3778   bool dump_header_only_ = false;
   3779   bool imt_stat_dump_ = false;
   3780   uint32_t addr2instr_ = 0;
   3781   const char* export_dex_location_ = nullptr;
   3782   const char* app_image_ = nullptr;
   3783   const char* app_oat_ = nullptr;
   3784 };
   3785 
   3786 struct OatdumpMain : public CmdlineMain<OatdumpArgs> {
   3787   virtual bool NeedsRuntime() OVERRIDE {
   3788     CHECK(args_ != nullptr);
   3789 
   3790     // If we are only doing the oat file, disable absolute_addresses. Keep them for image dumping.
   3791     bool absolute_addresses = (args_->oat_filename_ == nullptr);
   3792 
   3793     oat_dumper_options_.reset(new OatDumperOptions(
   3794         args_->dump_vmap_,
   3795         args_->dump_code_info_stack_maps_,
   3796         args_->disassemble_code_,
   3797         absolute_addresses,
   3798         args_->class_filter_,
   3799         args_->method_filter_,
   3800         args_->list_classes_,
   3801         args_->list_methods_,
   3802         args_->dump_header_only_,
   3803         args_->export_dex_location_,
   3804         args_->app_image_,
   3805         args_->app_oat_,
   3806         args_->addr2instr_));
   3807 
   3808     return (args_->boot_image_location_ != nullptr ||
   3809             args_->image_location_ != nullptr ||
   3810             !args_->imt_dump_.empty()) &&
   3811           !args_->symbolize_;
   3812   }
   3813 
   3814   virtual bool ExecuteWithoutRuntime() OVERRIDE {
   3815     CHECK(args_ != nullptr);
   3816     CHECK(args_->oat_filename_ != nullptr);
   3817 
   3818     MemMap::Init();
   3819 
   3820     if (args_->symbolize_) {
   3821       // ELF has special kind of section called SHT_NOBITS which allows us to create
   3822       // sections which exist but their data is omitted from the ELF file to save space.
   3823       // This is what "strip --only-keep-debug" does when it creates separate ELF file
   3824       // with only debug data. We use it in similar way to exclude .rodata and .text.
   3825       bool no_bits = args_->only_keep_debug_;
   3826       return SymbolizeOat(args_->oat_filename_, args_->dex_filename_, args_->output_name_, no_bits)
   3827           == EXIT_SUCCESS;
   3828     } else {
   3829       return DumpOat(nullptr,
   3830                      args_->oat_filename_,
   3831                      args_->dex_filename_,
   3832                      oat_dumper_options_.get(),
   3833                      args_->os_) == EXIT_SUCCESS;
   3834     }
   3835   }
   3836 
   3837   virtual bool ExecuteWithRuntime(Runtime* runtime) {
   3838     CHECK(args_ != nullptr);
   3839 
   3840     if (!args_->imt_dump_.empty() || args_->imt_stat_dump_) {
   3841       return IMTDumper::Dump(runtime,
   3842                              args_->imt_dump_,
   3843                              args_->imt_stat_dump_,
   3844                              args_->oat_filename_,
   3845                              args_->dex_filename_);
   3846     }
   3847 
   3848     if (args_->oat_filename_ != nullptr) {
   3849       return DumpOat(runtime,
   3850                      args_->oat_filename_,
   3851                      args_->dex_filename_,
   3852                      oat_dumper_options_.get(),
   3853                      args_->os_) == EXIT_SUCCESS;
   3854     }
   3855 
   3856     return DumpImages(runtime, oat_dumper_options_.get(), args_->os_) == EXIT_SUCCESS;
   3857   }
   3858 
   3859   std::unique_ptr<OatDumperOptions> oat_dumper_options_;
   3860 };
   3861 
   3862 }  // namespace art
   3863 
   3864 int main(int argc, char** argv) {
   3865   // Output all logging to stderr.
   3866   android::base::SetLogger(android::base::StderrLogger);
   3867 
   3868   art::OatdumpMain main;
   3869   return main.Main(argc, argv);
   3870 }
   3871