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 <vector>
     27 
     28 #include "arch/instruction_set_features.h"
     29 #include "art_field-inl.h"
     30 #include "art_method-inl.h"
     31 #include "base/unix_file/fd_file.h"
     32 #include "class_linker.h"
     33 #include "class_linker-inl.h"
     34 #include "dex_file-inl.h"
     35 #include "dex_instruction.h"
     36 #include "disassembler.h"
     37 #include "elf_builder.h"
     38 #include "gc_map.h"
     39 #include "gc/space/image_space.h"
     40 #include "gc/space/large_object_space.h"
     41 #include "gc/space/space-inl.h"
     42 #include "image.h"
     43 #include "indenter.h"
     44 #include "mapping_table.h"
     45 #include "mirror/array-inl.h"
     46 #include "mirror/class-inl.h"
     47 #include "mirror/object-inl.h"
     48 #include "mirror/object_array-inl.h"
     49 #include "oat.h"
     50 #include "oat_file-inl.h"
     51 #include "os.h"
     52 #include "output_stream.h"
     53 #include "safe_map.h"
     54 #include "scoped_thread_state_change.h"
     55 #include "ScopedLocalRef.h"
     56 #include "thread_list.h"
     57 #include "verifier/dex_gc_map.h"
     58 #include "verifier/method_verifier.h"
     59 #include "vmap_table.h"
     60 #include "well_known_classes.h"
     61 
     62 #include <sys/stat.h>
     63 #include "cmdline.h"
     64 
     65 namespace art {
     66 
     67 const char* image_methods_descriptions_[] = {
     68   "kResolutionMethod",
     69   "kImtConflictMethod",
     70   "kImtUnimplementedMethod",
     71   "kCalleeSaveMethod",
     72   "kRefsOnlySaveMethod",
     73   "kRefsAndArgsSaveMethod",
     74 };
     75 
     76 const char* image_roots_descriptions_[] = {
     77   "kDexCaches",
     78   "kClassRoots",
     79 };
     80 
     81 class OatSymbolizer FINAL {
     82  public:
     83   class RodataWriter FINAL : public CodeOutput {
     84    public:
     85     explicit RodataWriter(const OatFile* oat_file) : oat_file_(oat_file) {}
     86 
     87     bool Write(OutputStream* out) OVERRIDE {
     88       const size_t rodata_size = oat_file_->GetOatHeader().GetExecutableOffset();
     89       return out->WriteFully(oat_file_->Begin(), rodata_size);
     90     }
     91 
     92    private:
     93     const OatFile* oat_file_;
     94   };
     95 
     96   class TextWriter FINAL : public CodeOutput {
     97    public:
     98     explicit TextWriter(const OatFile* oat_file) : oat_file_(oat_file) {}
     99 
    100     bool Write(OutputStream* out) OVERRIDE {
    101       const size_t rodata_size = oat_file_->GetOatHeader().GetExecutableOffset();
    102       const uint8_t* text_begin = oat_file_->Begin() + rodata_size;
    103       return out->WriteFully(text_begin, oat_file_->End() - text_begin);
    104     }
    105 
    106    private:
    107     const OatFile* oat_file_;
    108   };
    109 
    110   explicit OatSymbolizer(const OatFile* oat_file, const std::string& output_name) :
    111       oat_file_(oat_file), builder_(nullptr),
    112       output_name_(output_name.empty() ? "symbolized.oat" : output_name) {
    113   }
    114 
    115   typedef void (OatSymbolizer::*Callback)(const DexFile::ClassDef&,
    116                                           uint32_t,
    117                                           const OatFile::OatMethod&,
    118                                           const DexFile&,
    119                                           uint32_t,
    120                                           const DexFile::CodeItem*,
    121                                           uint32_t);
    122 
    123   bool Symbolize() {
    124     Elf32_Word rodata_size = oat_file_->GetOatHeader().GetExecutableOffset();
    125     uint32_t size = static_cast<uint32_t>(oat_file_->End() - oat_file_->Begin());
    126     uint32_t text_size = size - rodata_size;
    127     uint32_t bss_size = oat_file_->BssSize();
    128     RodataWriter rodata_writer(oat_file_);
    129     TextWriter text_writer(oat_file_);
    130     builder_.reset(new ElfBuilder<ElfTypes32>(
    131         oat_file_->GetOatHeader().GetInstructionSet(),
    132         rodata_size, &rodata_writer,
    133         text_size, &text_writer,
    134         bss_size));
    135 
    136     Walk(&art::OatSymbolizer::RegisterForDedup);
    137 
    138     NormalizeState();
    139 
    140     Walk(&art::OatSymbolizer::AddSymbol);
    141 
    142     File* elf_output = OS::CreateEmptyFile(output_name_.c_str());
    143     bool result = builder_->Write(elf_output);
    144 
    145     // Ignore I/O errors.
    146     UNUSED(elf_output->FlushClose());
    147 
    148     return result;
    149   }
    150 
    151   void Walk(Callback callback) {
    152     std::vector<const OatFile::OatDexFile*> oat_dex_files = oat_file_->GetOatDexFiles();
    153     for (size_t i = 0; i < oat_dex_files.size(); i++) {
    154       const OatFile::OatDexFile* oat_dex_file = oat_dex_files[i];
    155       CHECK(oat_dex_file != nullptr);
    156       WalkOatDexFile(oat_dex_file, callback);
    157     }
    158   }
    159 
    160   void WalkOatDexFile(const OatFile::OatDexFile* oat_dex_file, Callback callback) {
    161     std::string error_msg;
    162     std::unique_ptr<const DexFile> dex_file(oat_dex_file->OpenDexFile(&error_msg));
    163     if (dex_file.get() == nullptr) {
    164       return;
    165     }
    166     for (size_t class_def_index = 0;
    167         class_def_index < dex_file->NumClassDefs();
    168         class_def_index++) {
    169       const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
    170       const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index);
    171       OatClassType type = oat_class.GetType();
    172       switch (type) {
    173         case kOatClassAllCompiled:
    174         case kOatClassSomeCompiled:
    175           WalkOatClass(oat_class, *dex_file.get(), class_def, callback);
    176           break;
    177 
    178         case kOatClassNoneCompiled:
    179         case kOatClassMax:
    180           // Ignore.
    181           break;
    182       }
    183     }
    184   }
    185 
    186   void WalkOatClass(const OatFile::OatClass& oat_class, const DexFile& dex_file,
    187                     const DexFile::ClassDef& class_def, Callback callback) {
    188     const uint8_t* class_data = dex_file.GetClassData(class_def);
    189     if (class_data == nullptr) {  // empty class such as a marker interface?
    190       return;
    191     }
    192     // Note: even if this is an interface or a native class, we still have to walk it, as there
    193     //       might be a static initializer.
    194     ClassDataItemIterator it(dex_file, class_data);
    195     SkipAllFields(&it);
    196     uint32_t class_method_idx = 0;
    197     while (it.HasNextDirectMethod()) {
    198       const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_idx);
    199       WalkOatMethod(class_def, class_method_idx, oat_method, dex_file, it.GetMemberIndex(),
    200                     it.GetMethodCodeItem(), it.GetMethodAccessFlags(), callback);
    201       class_method_idx++;
    202       it.Next();
    203     }
    204     while (it.HasNextVirtualMethod()) {
    205       const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_idx);
    206       WalkOatMethod(class_def, class_method_idx, oat_method, dex_file, it.GetMemberIndex(),
    207                     it.GetMethodCodeItem(), it.GetMethodAccessFlags(), callback);
    208       class_method_idx++;
    209       it.Next();
    210     }
    211     DCHECK(!it.HasNext());
    212   }
    213 
    214   void WalkOatMethod(const DexFile::ClassDef& class_def, uint32_t class_method_index,
    215                      const OatFile::OatMethod& oat_method, const DexFile& dex_file,
    216                      uint32_t dex_method_idx, const DexFile::CodeItem* code_item,
    217                      uint32_t method_access_flags, Callback callback) {
    218     if ((method_access_flags & kAccAbstract) != 0) {
    219       // Abstract method, no code.
    220       return;
    221     }
    222     if (oat_method.GetCodeOffset() == 0) {
    223       // No code.
    224       return;
    225     }
    226 
    227     (this->*callback)(class_def, class_method_index, oat_method, dex_file, dex_method_idx, code_item,
    228                       method_access_flags);
    229   }
    230 
    231   void RegisterForDedup(const DexFile::ClassDef& class_def ATTRIBUTE_UNUSED,
    232                         uint32_t class_method_index ATTRIBUTE_UNUSED,
    233                         const OatFile::OatMethod& oat_method,
    234                         const DexFile& dex_file ATTRIBUTE_UNUSED,
    235                         uint32_t dex_method_idx ATTRIBUTE_UNUSED,
    236                         const DexFile::CodeItem* code_item ATTRIBUTE_UNUSED,
    237                         uint32_t method_access_flags ATTRIBUTE_UNUSED) {
    238     state_[oat_method.GetCodeOffset()]++;
    239   }
    240 
    241   void NormalizeState() {
    242     for (auto& x : state_) {
    243       if (x.second == 1) {
    244         state_[x.first] = 0;
    245       }
    246     }
    247   }
    248 
    249   enum class DedupState {  // private
    250     kNotDeduplicated,
    251     kDeduplicatedFirst,
    252     kDeduplicatedOther
    253   };
    254   DedupState IsDuplicated(uint32_t offset) {
    255     if (state_[offset] == 0) {
    256       return DedupState::kNotDeduplicated;
    257     }
    258     if (state_[offset] == 1) {
    259       return DedupState::kDeduplicatedOther;
    260     }
    261     state_[offset] = 1;
    262     return DedupState::kDeduplicatedFirst;
    263   }
    264 
    265   void AddSymbol(const DexFile::ClassDef& class_def ATTRIBUTE_UNUSED,
    266                  uint32_t class_method_index ATTRIBUTE_UNUSED,
    267                  const OatFile::OatMethod& oat_method,
    268                  const DexFile& dex_file,
    269                  uint32_t dex_method_idx,
    270                  const DexFile::CodeItem* code_item ATTRIBUTE_UNUSED,
    271                  uint32_t method_access_flags ATTRIBUTE_UNUSED) {
    272     DedupState dedup = IsDuplicated(oat_method.GetCodeOffset());
    273     if (dedup != DedupState::kDeduplicatedOther) {
    274       std::string pretty_name = PrettyMethod(dex_method_idx, dex_file, true);
    275 
    276       if (dedup == DedupState::kDeduplicatedFirst) {
    277         pretty_name = "[Dedup]" + pretty_name;
    278       }
    279 
    280       auto* symtab = builder_->GetSymtab();
    281 
    282       symtab->AddSymbol(pretty_name, builder_->GetText(),
    283           oat_method.GetCodeOffset() - oat_file_->GetOatHeader().GetExecutableOffset(),
    284           true, oat_method.GetQuickCodeSize(), STB_GLOBAL, STT_FUNC);
    285     }
    286   }
    287 
    288  private:
    289   static void SkipAllFields(ClassDataItemIterator* it) {
    290     while (it->HasNextStaticField()) {
    291       it->Next();
    292     }
    293     while (it->HasNextInstanceField()) {
    294       it->Next();
    295     }
    296   }
    297 
    298   const OatFile* oat_file_;
    299   std::unique_ptr<ElfBuilder<ElfTypes32> > builder_;
    300   std::unordered_map<uint32_t, uint32_t> state_;
    301   const std::string output_name_;
    302 };
    303 
    304 class OatDumperOptions {
    305  public:
    306   OatDumperOptions(bool dump_raw_mapping_table,
    307                    bool dump_raw_gc_map,
    308                    bool dump_vmap,
    309                    bool disassemble_code,
    310                    bool absolute_addresses,
    311                    const char* class_filter,
    312                    const char* method_filter,
    313                    bool list_classes,
    314                    bool list_methods,
    315                    const char* export_dex_location,
    316                    uint32_t addr2instr)
    317     : dump_raw_mapping_table_(dump_raw_mapping_table),
    318       dump_raw_gc_map_(dump_raw_gc_map),
    319       dump_vmap_(dump_vmap),
    320       disassemble_code_(disassemble_code),
    321       absolute_addresses_(absolute_addresses),
    322       class_filter_(class_filter),
    323       method_filter_(method_filter),
    324       list_classes_(list_classes),
    325       list_methods_(list_methods),
    326       export_dex_location_(export_dex_location),
    327       addr2instr_(addr2instr),
    328       class_loader_(nullptr) {}
    329 
    330   const bool dump_raw_mapping_table_;
    331   const bool dump_raw_gc_map_;
    332   const bool dump_vmap_;
    333   const bool disassemble_code_;
    334   const bool absolute_addresses_;
    335   const char* const class_filter_;
    336   const char* const method_filter_;
    337   const bool list_classes_;
    338   const bool list_methods_;
    339   const char* const export_dex_location_;
    340   uint32_t addr2instr_;
    341   Handle<mirror::ClassLoader>* class_loader_;
    342 };
    343 
    344 class OatDumper {
    345  public:
    346   explicit OatDumper(const OatFile& oat_file, const OatDumperOptions& options)
    347     : oat_file_(oat_file),
    348       oat_dex_files_(oat_file.GetOatDexFiles()),
    349       options_(options),
    350       resolved_addr2instr_(0),
    351       instruction_set_(oat_file_.GetOatHeader().GetInstructionSet()),
    352       disassembler_(Disassembler::Create(instruction_set_,
    353                                          new DisassemblerOptions(options_.absolute_addresses_,
    354                                                                  oat_file.Begin(),
    355                                                                  true /* can_read_litals_ */))) {
    356     CHECK(options_.class_loader_ != nullptr);
    357     CHECK(options_.class_filter_ != nullptr);
    358     CHECK(options_.method_filter_ != nullptr);
    359     AddAllOffsets();
    360   }
    361 
    362   ~OatDumper() {
    363     delete disassembler_;
    364   }
    365 
    366   InstructionSet GetInstructionSet() {
    367     return instruction_set_;
    368   }
    369 
    370   bool Dump(std::ostream& os) {
    371     bool success = true;
    372     const OatHeader& oat_header = oat_file_.GetOatHeader();
    373 
    374     os << "MAGIC:\n";
    375     os << oat_header.GetMagic() << "\n\n";
    376 
    377     os << "CHECKSUM:\n";
    378     os << StringPrintf("0x%08x\n\n", oat_header.GetChecksum());
    379 
    380     os << "INSTRUCTION SET:\n";
    381     os << oat_header.GetInstructionSet() << "\n\n";
    382 
    383     {
    384       std::unique_ptr<const InstructionSetFeatures> features(
    385           InstructionSetFeatures::FromBitmap(oat_header.GetInstructionSet(),
    386                                              oat_header.GetInstructionSetFeaturesBitmap()));
    387       os << "INSTRUCTION SET FEATURES:\n";
    388       os << features->GetFeatureString() << "\n\n";
    389     }
    390 
    391     os << "DEX FILE COUNT:\n";
    392     os << oat_header.GetDexFileCount() << "\n\n";
    393 
    394 #define DUMP_OAT_HEADER_OFFSET(label, offset) \
    395     os << label " OFFSET:\n"; \
    396     os << StringPrintf("0x%08x", oat_header.offset()); \
    397     if (oat_header.offset() != 0 && options_.absolute_addresses_) { \
    398       os << StringPrintf(" (%p)", oat_file_.Begin() + oat_header.offset()); \
    399     } \
    400     os << StringPrintf("\n\n");
    401 
    402     DUMP_OAT_HEADER_OFFSET("EXECUTABLE", GetExecutableOffset);
    403     DUMP_OAT_HEADER_OFFSET("INTERPRETER TO INTERPRETER BRIDGE",
    404                            GetInterpreterToInterpreterBridgeOffset);
    405     DUMP_OAT_HEADER_OFFSET("INTERPRETER TO COMPILED CODE BRIDGE",
    406                            GetInterpreterToCompiledCodeBridgeOffset);
    407     DUMP_OAT_HEADER_OFFSET("JNI DLSYM LOOKUP",
    408                            GetJniDlsymLookupOffset);
    409     DUMP_OAT_HEADER_OFFSET("QUICK GENERIC JNI TRAMPOLINE",
    410                            GetQuickGenericJniTrampolineOffset);
    411     DUMP_OAT_HEADER_OFFSET("QUICK IMT CONFLICT TRAMPOLINE",
    412                            GetQuickImtConflictTrampolineOffset);
    413     DUMP_OAT_HEADER_OFFSET("QUICK RESOLUTION TRAMPOLINE",
    414                            GetQuickResolutionTrampolineOffset);
    415     DUMP_OAT_HEADER_OFFSET("QUICK TO INTERPRETER BRIDGE",
    416                            GetQuickToInterpreterBridgeOffset);
    417 #undef DUMP_OAT_HEADER_OFFSET
    418 
    419     os << "IMAGE PATCH DELTA:\n";
    420     os << StringPrintf("%d (0x%08x)\n\n",
    421                        oat_header.GetImagePatchDelta(),
    422                        oat_header.GetImagePatchDelta());
    423 
    424     os << "IMAGE FILE LOCATION OAT CHECKSUM:\n";
    425     os << StringPrintf("0x%08x\n\n", oat_header.GetImageFileLocationOatChecksum());
    426 
    427     os << "IMAGE FILE LOCATION OAT BEGIN:\n";
    428     os << StringPrintf("0x%08x\n\n", oat_header.GetImageFileLocationOatDataBegin());
    429 
    430     // Print the key-value store.
    431     {
    432       os << "KEY VALUE STORE:\n";
    433       size_t index = 0;
    434       const char* key;
    435       const char* value;
    436       while (oat_header.GetStoreKeyValuePairByIndex(index, &key, &value)) {
    437         os << key << " = " << value << "\n";
    438         index++;
    439       }
    440       os << "\n";
    441     }
    442 
    443     if (options_.absolute_addresses_) {
    444       os << "BEGIN:\n";
    445       os << reinterpret_cast<const void*>(oat_file_.Begin()) << "\n\n";
    446 
    447       os << "END:\n";
    448       os << reinterpret_cast<const void*>(oat_file_.End()) << "\n\n";
    449     }
    450 
    451     os << "SIZE:\n";
    452     os << oat_file_.Size() << "\n\n";
    453 
    454     os << std::flush;
    455 
    456     // If set, adjust relative address to be searched
    457     if (options_.addr2instr_ != 0) {
    458       resolved_addr2instr_ = options_.addr2instr_ + oat_header.GetExecutableOffset();
    459       os << "SEARCH ADDRESS (executable offset + input):\n";
    460       os << StringPrintf("0x%08x\n\n", resolved_addr2instr_);
    461     }
    462 
    463     for (size_t i = 0; i < oat_dex_files_.size(); i++) {
    464       const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
    465       CHECK(oat_dex_file != nullptr);
    466 
    467       // If file export selected skip file analysis
    468       if (options_.export_dex_location_) {
    469         if (!ExportDexFile(os, *oat_dex_file)) {
    470           success = false;
    471         }
    472       } else {
    473         if (!DumpOatDexFile(os, *oat_dex_file)) {
    474           success = false;
    475         }
    476       }
    477     }
    478     os << std::flush;
    479     return success;
    480   }
    481 
    482   size_t ComputeSize(const void* oat_data) {
    483     if (reinterpret_cast<const uint8_t*>(oat_data) < oat_file_.Begin() ||
    484         reinterpret_cast<const uint8_t*>(oat_data) > oat_file_.End()) {
    485       return 0;  // Address not in oat file
    486     }
    487     uintptr_t begin_offset = reinterpret_cast<uintptr_t>(oat_data) -
    488                              reinterpret_cast<uintptr_t>(oat_file_.Begin());
    489     auto it = offsets_.upper_bound(begin_offset);
    490     CHECK(it != offsets_.end());
    491     uintptr_t end_offset = *it;
    492     return end_offset - begin_offset;
    493   }
    494 
    495   InstructionSet GetOatInstructionSet() {
    496     return oat_file_.GetOatHeader().GetInstructionSet();
    497   }
    498 
    499   const void* GetQuickOatCode(ArtMethod* m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    500     for (size_t i = 0; i < oat_dex_files_.size(); i++) {
    501       const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
    502       CHECK(oat_dex_file != nullptr);
    503       std::string error_msg;
    504       std::unique_ptr<const DexFile> dex_file(oat_dex_file->OpenDexFile(&error_msg));
    505       if (dex_file.get() == nullptr) {
    506         LOG(WARNING) << "Failed to open dex file '" << oat_dex_file->GetDexFileLocation()
    507             << "': " << error_msg;
    508       } else {
    509         const char* descriptor = m->GetDeclaringClassDescriptor();
    510         const DexFile::ClassDef* class_def =
    511             dex_file->FindClassDef(descriptor, ComputeModifiedUtf8Hash(descriptor));
    512         if (class_def != nullptr) {
    513           uint16_t class_def_index = dex_file->GetIndexForClassDef(*class_def);
    514           const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index);
    515           size_t method_index = m->GetMethodIndex();
    516           return oat_class.GetOatMethod(method_index).GetQuickCode();
    517         }
    518       }
    519     }
    520     return nullptr;
    521   }
    522 
    523  private:
    524   void AddAllOffsets() {
    525     // We don't know the length of the code for each method, but we need to know where to stop
    526     // when disassembling. What we do know is that a region of code will be followed by some other
    527     // region, so if we keep a sorted sequence of the start of each region, we can infer the length
    528     // of a piece of code by using upper_bound to find the start of the next region.
    529     for (size_t i = 0; i < oat_dex_files_.size(); i++) {
    530       const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
    531       CHECK(oat_dex_file != nullptr);
    532       std::string error_msg;
    533       std::unique_ptr<const DexFile> dex_file(oat_dex_file->OpenDexFile(&error_msg));
    534       if (dex_file.get() == nullptr) {
    535         LOG(WARNING) << "Failed to open dex file '" << oat_dex_file->GetDexFileLocation()
    536             << "': " << error_msg;
    537         continue;
    538       }
    539       offsets_.insert(reinterpret_cast<uintptr_t>(&dex_file->GetHeader()));
    540       for (size_t class_def_index = 0;
    541            class_def_index < dex_file->NumClassDefs();
    542            class_def_index++) {
    543         const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
    544         const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index);
    545         const uint8_t* class_data = dex_file->GetClassData(class_def);
    546         if (class_data != nullptr) {
    547           ClassDataItemIterator it(*dex_file, class_data);
    548           SkipAllFields(it);
    549           uint32_t class_method_index = 0;
    550           while (it.HasNextDirectMethod()) {
    551             AddOffsets(oat_class.GetOatMethod(class_method_index++));
    552             it.Next();
    553           }
    554           while (it.HasNextVirtualMethod()) {
    555             AddOffsets(oat_class.GetOatMethod(class_method_index++));
    556             it.Next();
    557           }
    558         }
    559       }
    560     }
    561 
    562     // If the last thing in the file is code for a method, there won't be an offset for the "next"
    563     // thing. Instead of having a special case in the upper_bound code, let's just add an entry
    564     // for the end of the file.
    565     offsets_.insert(oat_file_.Size());
    566   }
    567 
    568   static uint32_t AlignCodeOffset(uint32_t maybe_thumb_offset) {
    569     return maybe_thumb_offset & ~0x1;  // TODO: Make this Thumb2 specific.
    570   }
    571 
    572   void AddOffsets(const OatFile::OatMethod& oat_method) {
    573     uint32_t code_offset = oat_method.GetCodeOffset();
    574     if (oat_file_.GetOatHeader().GetInstructionSet() == kThumb2) {
    575       code_offset &= ~0x1;
    576     }
    577     offsets_.insert(code_offset);
    578     offsets_.insert(oat_method.GetMappingTableOffset());
    579     offsets_.insert(oat_method.GetVmapTableOffset());
    580     offsets_.insert(oat_method.GetGcMapOffset());
    581   }
    582 
    583   bool DumpOatDexFile(std::ostream& os, const OatFile::OatDexFile& oat_dex_file) {
    584     bool success = true;
    585     bool stop_analysis = false;
    586     os << "OatDexFile:\n";
    587     os << StringPrintf("location: %s\n", oat_dex_file.GetDexFileLocation().c_str());
    588     os << StringPrintf("checksum: 0x%08x\n", oat_dex_file.GetDexFileLocationChecksum());
    589 
    590     // Create the verifier early.
    591 
    592     std::string error_msg;
    593     std::unique_ptr<const DexFile> dex_file(oat_dex_file.OpenDexFile(&error_msg));
    594     if (dex_file.get() == nullptr) {
    595       os << "NOT FOUND: " << error_msg << "\n\n";
    596       os << std::flush;
    597       return false;
    598     }
    599     for (size_t class_def_index = 0;
    600          class_def_index < dex_file->NumClassDefs();
    601          class_def_index++) {
    602       const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
    603       const char* descriptor = dex_file->GetClassDescriptor(class_def);
    604 
    605       // TODO: Support regex
    606       if (DescriptorToDot(descriptor).find(options_.class_filter_) == std::string::npos) {
    607         continue;
    608       }
    609 
    610       uint32_t oat_class_offset = oat_dex_file.GetOatClassOffset(class_def_index);
    611       const OatFile::OatClass oat_class = oat_dex_file.GetOatClass(class_def_index);
    612       os << StringPrintf("%zd: %s (offset=0x%08x) (type_idx=%d)",
    613                          class_def_index, descriptor, oat_class_offset, class_def.class_idx_)
    614          << " (" << oat_class.GetStatus() << ")"
    615          << " (" << oat_class.GetType() << ")\n";
    616       // TODO: include bitmap here if type is kOatClassSomeCompiled?
    617       Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
    618       std::ostream indented_os(&indent_filter);
    619       if (options_.list_classes_) continue;
    620       if (!DumpOatClass(indented_os, oat_class, *(dex_file.get()), class_def, &stop_analysis)) {
    621         success = false;
    622       }
    623       if (stop_analysis) {
    624         os << std::flush;
    625         return success;
    626       }
    627     }
    628 
    629     os << std::flush;
    630     return success;
    631   }
    632 
    633   bool ExportDexFile(std::ostream& os, const OatFile::OatDexFile& oat_dex_file) {
    634     std::string error_msg;
    635     std::string dex_file_location = oat_dex_file.GetDexFileLocation();
    636 
    637     std::unique_ptr<const DexFile> dex_file(oat_dex_file.OpenDexFile(&error_msg));
    638     if (dex_file == nullptr) {
    639       os << "Failed to open dex file '" << dex_file_location << "': " << error_msg;
    640       return false;
    641     }
    642     size_t fsize = oat_dex_file.FileSize();
    643 
    644     // Some quick checks just in case
    645     if (fsize == 0 || fsize < sizeof(DexFile::Header)) {
    646       os << "Invalid dex file\n";
    647       return false;
    648     }
    649 
    650     // Verify output directory exists
    651     if (!OS::DirectoryExists(options_.export_dex_location_)) {
    652       // TODO: Extend OS::DirectoryExists if symlink support is required
    653       os << options_.export_dex_location_ << " output directory not found or symlink\n";
    654       return false;
    655     }
    656 
    657     // Beautify path names
    658     if (dex_file_location.size() > PATH_MAX || dex_file_location.size() <= 0) {
    659       return false;
    660     }
    661 
    662     std::string dex_orig_name;
    663     size_t dex_orig_pos = dex_file_location.rfind('/');
    664     if (dex_orig_pos == std::string::npos)
    665       dex_orig_name = dex_file_location;
    666     else
    667       dex_orig_name = dex_file_location.substr(dex_orig_pos + 1);
    668 
    669     // A more elegant approach to efficiently name user installed apps is welcome
    670     if (dex_orig_name.size() == 8 && !dex_orig_name.compare("base.apk")) {
    671       dex_file_location.erase(dex_orig_pos, strlen("base.apk") + 1);
    672       size_t apk_orig_pos = dex_file_location.rfind('/');
    673       if (apk_orig_pos != std::string::npos) {
    674         dex_orig_name = dex_file_location.substr(++apk_orig_pos);
    675       }
    676     }
    677 
    678     std::string out_dex_path(options_.export_dex_location_);
    679     if (out_dex_path.back() != '/') {
    680       out_dex_path.append("/");
    681     }
    682     out_dex_path.append(dex_orig_name);
    683     out_dex_path.append("_export.dex");
    684     if (out_dex_path.length() > PATH_MAX) {
    685       return false;
    686     }
    687 
    688     std::unique_ptr<File> file(OS::CreateEmptyFile(out_dex_path.c_str()));
    689     if (file.get() == nullptr) {
    690       os << "Failed to open output dex file " << out_dex_path;
    691       return false;
    692     }
    693 
    694     if (!file->WriteFully(dex_file->Begin(), fsize)) {
    695       os << "Failed to write dex file";
    696       file->Erase();
    697       return false;
    698     }
    699 
    700     if (file->FlushCloseOrErase() != 0) {
    701       os << "Flush and close failed";
    702       return false;
    703     }
    704 
    705     os << StringPrintf("Dex file exported at %s (%zd bytes)\n", out_dex_path.c_str(), fsize);
    706     os << std::flush;
    707 
    708     return true;
    709   }
    710 
    711   static void SkipAllFields(ClassDataItemIterator& it) {
    712     while (it.HasNextStaticField()) {
    713       it.Next();
    714     }
    715     while (it.HasNextInstanceField()) {
    716       it.Next();
    717     }
    718   }
    719 
    720   bool DumpOatClass(std::ostream& os, const OatFile::OatClass& oat_class, const DexFile& dex_file,
    721                     const DexFile::ClassDef& class_def, bool* stop_analysis) {
    722     bool success = true;
    723     bool addr_found = false;
    724     const uint8_t* class_data = dex_file.GetClassData(class_def);
    725     if (class_data == nullptr) {  // empty class such as a marker interface?
    726       os << std::flush;
    727       return success;
    728     }
    729     ClassDataItemIterator it(dex_file, class_data);
    730     SkipAllFields(it);
    731     uint32_t class_method_index = 0;
    732     while (it.HasNextDirectMethod()) {
    733       if (!DumpOatMethod(os, class_def, class_method_index, oat_class, dex_file,
    734                          it.GetMemberIndex(), it.GetMethodCodeItem(),
    735                          it.GetRawMemberAccessFlags(), &addr_found)) {
    736         success = false;
    737       }
    738       if (addr_found) {
    739         *stop_analysis = true;
    740         return success;
    741       }
    742       class_method_index++;
    743       it.Next();
    744     }
    745     while (it.HasNextVirtualMethod()) {
    746       if (!DumpOatMethod(os, class_def, class_method_index, oat_class, dex_file,
    747                          it.GetMemberIndex(), it.GetMethodCodeItem(),
    748                          it.GetRawMemberAccessFlags(), &addr_found)) {
    749         success = false;
    750       }
    751       if (addr_found) {
    752         *stop_analysis = true;
    753         return success;
    754       }
    755       class_method_index++;
    756       it.Next();
    757     }
    758     DCHECK(!it.HasNext());
    759     os << std::flush;
    760     return success;
    761   }
    762 
    763   static constexpr uint32_t kPrologueBytes = 16;
    764 
    765   // When this was picked, the largest arm method was 55,256 bytes and arm64 was 50,412 bytes.
    766   static constexpr uint32_t kMaxCodeSize = 100 * 1000;
    767 
    768   bool DumpOatMethod(std::ostream& os, const DexFile::ClassDef& class_def,
    769                      uint32_t class_method_index,
    770                      const OatFile::OatClass& oat_class, const DexFile& dex_file,
    771                      uint32_t dex_method_idx, const DexFile::CodeItem* code_item,
    772                      uint32_t method_access_flags, bool* addr_found) {
    773     bool success = true;
    774 
    775     // TODO: Support regex
    776     std::string method_name = dex_file.GetMethodName(dex_file.GetMethodId(dex_method_idx));
    777     if (method_name.find(options_.method_filter_) == std::string::npos) {
    778       return success;
    779     }
    780 
    781     std::string pretty_method = PrettyMethod(dex_method_idx, dex_file, true);
    782     os << StringPrintf("%d: %s (dex_method_idx=%d)\n",
    783                        class_method_index, pretty_method.c_str(),
    784                        dex_method_idx);
    785     if (options_.list_methods_) return success;
    786 
    787     Indenter indent1_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
    788     std::unique_ptr<std::ostream> indent1_os(new std::ostream(&indent1_filter));
    789     Indenter indent2_filter(indent1_os->rdbuf(), kIndentChar, kIndentBy1Count);
    790     std::unique_ptr<std::ostream> indent2_os(new std::ostream(&indent2_filter));
    791 
    792     uint32_t oat_method_offsets_offset = oat_class.GetOatMethodOffsetsOffset(class_method_index);
    793     const OatMethodOffsets* oat_method_offsets = oat_class.GetOatMethodOffsets(class_method_index);
    794     const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_index);
    795     uint32_t code_offset = oat_method.GetCodeOffset();
    796     uint32_t code_size = oat_method.GetQuickCodeSize();
    797     if (resolved_addr2instr_ != 0) {
    798       if (resolved_addr2instr_ > code_offset + code_size) {
    799         return success;
    800       } else {
    801         *addr_found = true;  // stop analyzing file at next iteration
    802       }
    803     }
    804 
    805     {
    806       *indent1_os << "DEX CODE:\n";
    807       DumpDexCode(*indent2_os, dex_file, code_item);
    808     }
    809 
    810     std::unique_ptr<verifier::MethodVerifier> verifier;
    811     if (Runtime::Current() != nullptr) {
    812       *indent1_os << "VERIFIER TYPE ANALYSIS:\n";
    813       verifier.reset(DumpVerifier(*indent2_os, dex_method_idx, &dex_file, class_def, code_item,
    814                                   method_access_flags));
    815     }
    816     {
    817       *indent1_os << "OatMethodOffsets ";
    818       if (options_.absolute_addresses_) {
    819         *indent1_os << StringPrintf("%p ", oat_method_offsets);
    820       }
    821       *indent1_os << StringPrintf("(offset=0x%08x)\n", oat_method_offsets_offset);
    822       if (oat_method_offsets_offset > oat_file_.Size()) {
    823         *indent1_os << StringPrintf(
    824             "WARNING: oat method offsets offset 0x%08x is past end of file 0x%08zx.\n",
    825             oat_method_offsets_offset, oat_file_.Size());
    826         // If we can't read OatMethodOffsets, the rest of the data is dangerous to read.
    827         os << std::flush;
    828         return false;
    829       }
    830 
    831       *indent2_os << StringPrintf("code_offset: 0x%08x ", code_offset);
    832       uint32_t aligned_code_begin = AlignCodeOffset(oat_method.GetCodeOffset());
    833       if (aligned_code_begin > oat_file_.Size()) {
    834         *indent2_os << StringPrintf("WARNING: "
    835                                     "code offset 0x%08x is past end of file 0x%08zx.\n",
    836                                     aligned_code_begin, oat_file_.Size());
    837         success = false;
    838       }
    839       *indent2_os << "\n";
    840 
    841       *indent2_os << "gc_map: ";
    842       if (options_.absolute_addresses_) {
    843         *indent2_os << StringPrintf("%p ", oat_method.GetGcMap());
    844       }
    845       uint32_t gc_map_offset = oat_method.GetGcMapOffset();
    846       *indent2_os << StringPrintf("(offset=0x%08x)\n", gc_map_offset);
    847       if (gc_map_offset > oat_file_.Size()) {
    848         *indent2_os << StringPrintf("WARNING: "
    849                                     "gc map table offset 0x%08x is past end of file 0x%08zx.\n",
    850                                     gc_map_offset, oat_file_.Size());
    851         success = false;
    852       } else if (options_.dump_raw_gc_map_) {
    853         Indenter indent3_filter(indent2_os->rdbuf(), kIndentChar, kIndentBy1Count);
    854         std::ostream indent3_os(&indent3_filter);
    855         DumpGcMap(indent3_os, oat_method, code_item);
    856       }
    857     }
    858     {
    859       *indent1_os << "OatQuickMethodHeader ";
    860       uint32_t method_header_offset = oat_method.GetOatQuickMethodHeaderOffset();
    861       const OatQuickMethodHeader* method_header = oat_method.GetOatQuickMethodHeader();
    862 
    863       if (options_.absolute_addresses_) {
    864         *indent1_os << StringPrintf("%p ", method_header);
    865       }
    866       *indent1_os << StringPrintf("(offset=0x%08x)\n", method_header_offset);
    867       if (method_header_offset > oat_file_.Size()) {
    868         *indent1_os << StringPrintf(
    869             "WARNING: oat quick method header offset 0x%08x is past end of file 0x%08zx.\n",
    870             method_header_offset, oat_file_.Size());
    871         // If we can't read the OatQuickMethodHeader, the rest of the data is dangerous to read.
    872         os << std::flush;
    873         return false;
    874       }
    875 
    876       *indent2_os << "mapping_table: ";
    877       if (options_.absolute_addresses_) {
    878         *indent2_os << StringPrintf("%p ", oat_method.GetMappingTable());
    879       }
    880       uint32_t mapping_table_offset = oat_method.GetMappingTableOffset();
    881       *indent2_os << StringPrintf("(offset=0x%08x)\n", oat_method.GetMappingTableOffset());
    882       if (mapping_table_offset > oat_file_.Size()) {
    883         *indent2_os << StringPrintf("WARNING: "
    884                                     "mapping table offset 0x%08x is past end of file 0x%08zx. "
    885                                     "mapping table offset was loaded from offset 0x%08x.\n",
    886                                     mapping_table_offset, oat_file_.Size(),
    887                                     oat_method.GetMappingTableOffsetOffset());
    888         success = false;
    889       } else if (options_.dump_raw_mapping_table_) {
    890         Indenter indent3_filter(indent2_os->rdbuf(), kIndentChar, kIndentBy1Count);
    891         std::ostream indent3_os(&indent3_filter);
    892         DumpMappingTable(indent3_os, oat_method);
    893       }
    894 
    895       *indent2_os << "vmap_table: ";
    896       if (options_.absolute_addresses_) {
    897         *indent2_os << StringPrintf("%p ", oat_method.GetVmapTable());
    898       }
    899       uint32_t vmap_table_offset = oat_method.GetVmapTableOffset();
    900       *indent2_os << StringPrintf("(offset=0x%08x)\n", vmap_table_offset);
    901       if (vmap_table_offset > oat_file_.Size()) {
    902         *indent2_os << StringPrintf("WARNING: "
    903                                     "vmap table offset 0x%08x is past end of file 0x%08zx. "
    904                                     "vmap table offset was loaded from offset 0x%08x.\n",
    905                                     vmap_table_offset, oat_file_.Size(),
    906                                     oat_method.GetVmapTableOffsetOffset());
    907         success = false;
    908       } else if (options_.dump_vmap_) {
    909         DumpVmapData(*indent2_os, oat_method, code_item);
    910       }
    911     }
    912     {
    913       *indent1_os << "QuickMethodFrameInfo\n";
    914 
    915       *indent2_os << StringPrintf("frame_size_in_bytes: %zd\n", oat_method.GetFrameSizeInBytes());
    916       *indent2_os << StringPrintf("core_spill_mask: 0x%08x ", oat_method.GetCoreSpillMask());
    917       DumpSpillMask(*indent2_os, oat_method.GetCoreSpillMask(), false);
    918       *indent2_os << "\n";
    919       *indent2_os << StringPrintf("fp_spill_mask: 0x%08x ", oat_method.GetFpSpillMask());
    920       DumpSpillMask(*indent2_os, oat_method.GetFpSpillMask(), true);
    921       *indent2_os << "\n";
    922     }
    923     {
    924         // Based on spill masks from QuickMethodFrameInfo so placed
    925         // after it is dumped, but useful for understanding quick
    926         // code, so dumped here.
    927         DumpVregLocations(*indent2_os, oat_method, code_item);
    928     }
    929     {
    930       *indent1_os << "CODE: ";
    931       uint32_t code_size_offset = oat_method.GetQuickCodeSizeOffset();
    932       if (code_size_offset > oat_file_.Size()) {
    933         *indent2_os << StringPrintf("WARNING: "
    934                                     "code size offset 0x%08x is past end of file 0x%08zx.",
    935                                     code_size_offset, oat_file_.Size());
    936         success = false;
    937       } else {
    938         const void* code = oat_method.GetQuickCode();
    939         uint32_t aligned_code_begin = AlignCodeOffset(code_offset);
    940         uint64_t aligned_code_end = aligned_code_begin + code_size;
    941 
    942         if (options_.absolute_addresses_) {
    943           *indent1_os << StringPrintf("%p ", code);
    944         }
    945         *indent1_os << StringPrintf("(code_offset=0x%08x size_offset=0x%08x size=%u)%s\n",
    946                                     code_offset,
    947                                     code_size_offset,
    948                                     code_size,
    949                                     code != nullptr ? "..." : "");
    950 
    951         if (aligned_code_begin > oat_file_.Size()) {
    952           *indent2_os << StringPrintf("WARNING: "
    953                                       "start of code at 0x%08x is past end of file 0x%08zx.",
    954                                       aligned_code_begin, oat_file_.Size());
    955           success = false;
    956         } else if (aligned_code_end > oat_file_.Size()) {
    957           *indent2_os << StringPrintf("WARNING: "
    958                                       "end of code at 0x%08" PRIx64 " is past end of file 0x%08zx. "
    959                                       "code size is 0x%08x loaded from offset 0x%08x.\n",
    960                                       aligned_code_end, oat_file_.Size(),
    961                                       code_size, code_size_offset);
    962           success = false;
    963           if (options_.disassemble_code_) {
    964             if (code_size_offset + kPrologueBytes <= oat_file_.Size()) {
    965               DumpCode(*indent2_os, verifier.get(), oat_method, code_item, true, kPrologueBytes);
    966             }
    967           }
    968         } else if (code_size > kMaxCodeSize) {
    969           *indent2_os << StringPrintf("WARNING: "
    970                                       "code size %d is bigger than max expected threshold of %d. "
    971                                       "code size is 0x%08x loaded from offset 0x%08x.\n",
    972                                       code_size, kMaxCodeSize,
    973                                       code_size, code_size_offset);
    974           success = false;
    975           if (options_.disassemble_code_) {
    976             if (code_size_offset + kPrologueBytes <= oat_file_.Size()) {
    977               DumpCode(*indent2_os, verifier.get(), oat_method, code_item, true, kPrologueBytes);
    978             }
    979           }
    980         } else if (options_.disassemble_code_) {
    981           DumpCode(*indent2_os, verifier.get(), oat_method, code_item, !success, 0);
    982         }
    983       }
    984     }
    985     os << std::flush;
    986     return success;
    987   }
    988 
    989   void DumpSpillMask(std::ostream& os, uint32_t spill_mask, bool is_float) {
    990     if (spill_mask == 0) {
    991       return;
    992     }
    993     os << "(";
    994     for (size_t i = 0; i < 32; i++) {
    995       if ((spill_mask & (1 << i)) != 0) {
    996         if (is_float) {
    997           os << "fr" << i;
    998         } else {
    999           os << "r" << i;
   1000         }
   1001         spill_mask ^= 1 << i;  // clear bit
   1002         if (spill_mask != 0) {
   1003           os << ", ";
   1004         } else {
   1005           break;
   1006         }
   1007       }
   1008     }
   1009     os << ")";
   1010   }
   1011 
   1012   // Display data stored at the the vmap offset of an oat method.
   1013   void DumpVmapData(std::ostream& os,
   1014                     const OatFile::OatMethod& oat_method,
   1015                     const DexFile::CodeItem* code_item) {
   1016     if (oat_method.GetGcMap() == nullptr) {
   1017       // If the native GC map is null, then this method has been
   1018       // compiled with the optimizing compiler. The optimizing
   1019       // compiler currently outputs its stack maps in the vmap table.
   1020       const void* raw_code_info = oat_method.GetVmapTable();
   1021       if (raw_code_info != nullptr) {
   1022         CodeInfo code_info(raw_code_info);
   1023         DCHECK(code_item != nullptr);
   1024         DumpCodeInfo(os, code_info, *code_item);
   1025       }
   1026     } else {
   1027       // Otherwise, display the vmap table.
   1028       const uint8_t* raw_table = oat_method.GetVmapTable();
   1029       if (raw_table != nullptr) {
   1030         VmapTable vmap_table(raw_table);
   1031         DumpVmapTable(os, oat_method, vmap_table);
   1032       }
   1033     }
   1034   }
   1035 
   1036   // Display a CodeInfo object emitted by the optimizing compiler.
   1037   void DumpCodeInfo(std::ostream& os,
   1038                     const CodeInfo& code_info,
   1039                     const DexFile::CodeItem& code_item) {
   1040     code_info.Dump(os, code_item.registers_size_);
   1041   }
   1042 
   1043   // Display a vmap table.
   1044   void DumpVmapTable(std::ostream& os,
   1045                      const OatFile::OatMethod& oat_method,
   1046                      const VmapTable& vmap_table) {
   1047     bool first = true;
   1048     bool processing_fp = false;
   1049     uint32_t spill_mask = oat_method.GetCoreSpillMask();
   1050     for (size_t i = 0; i < vmap_table.Size(); i++) {
   1051       uint16_t dex_reg = vmap_table[i];
   1052       uint32_t cpu_reg = vmap_table.ComputeRegister(spill_mask, i,
   1053                                                     processing_fp ? kFloatVReg : kIntVReg);
   1054       os << (first ? "v" : ", v")  << dex_reg;
   1055       if (!processing_fp) {
   1056         os << "/r" << cpu_reg;
   1057       } else {
   1058         os << "/fr" << cpu_reg;
   1059       }
   1060       first = false;
   1061       if (!processing_fp && dex_reg == 0xFFFF) {
   1062         processing_fp = true;
   1063         spill_mask = oat_method.GetFpSpillMask();
   1064       }
   1065     }
   1066     os << "\n";
   1067   }
   1068 
   1069   void DumpVregLocations(std::ostream& os, const OatFile::OatMethod& oat_method,
   1070                          const DexFile::CodeItem* code_item) {
   1071     if (code_item != nullptr) {
   1072       size_t num_locals_ins = code_item->registers_size_;
   1073       size_t num_ins = code_item->ins_size_;
   1074       size_t num_locals = num_locals_ins - num_ins;
   1075       size_t num_outs = code_item->outs_size_;
   1076 
   1077       os << "vr_stack_locations:";
   1078       for (size_t reg = 0; reg <= num_locals_ins; reg++) {
   1079         // For readability, delimit the different kinds of VRs.
   1080         if (reg == num_locals_ins) {
   1081           os << "\n\tmethod*:";
   1082         } else if (reg == num_locals && num_ins > 0) {
   1083           os << "\n\tins:";
   1084         } else if (reg == 0 && num_locals > 0) {
   1085           os << "\n\tlocals:";
   1086         }
   1087 
   1088         uint32_t offset = StackVisitor::GetVRegOffsetFromQuickCode(
   1089             code_item,
   1090             oat_method.GetCoreSpillMask(),
   1091             oat_method.GetFpSpillMask(),
   1092             oat_method.GetFrameSizeInBytes(),
   1093             reg,
   1094             GetInstructionSet());
   1095         os << " v" << reg << "[sp + #" << offset << "]";
   1096       }
   1097 
   1098       for (size_t out_reg = 0; out_reg < num_outs; out_reg++) {
   1099         if (out_reg == 0) {
   1100           os << "\n\touts:";
   1101         }
   1102 
   1103         uint32_t offset = StackVisitor::GetOutVROffset(out_reg, GetInstructionSet());
   1104         os << " v" << out_reg << "[sp + #" << offset << "]";
   1105       }
   1106 
   1107       os << "\n";
   1108     }
   1109   }
   1110 
   1111   void DescribeVReg(std::ostream& os, const OatFile::OatMethod& oat_method,
   1112                     const DexFile::CodeItem* code_item, size_t reg, VRegKind kind) {
   1113     const uint8_t* raw_table = oat_method.GetVmapTable();
   1114     if (raw_table != nullptr) {
   1115       const VmapTable vmap_table(raw_table);
   1116       uint32_t vmap_offset;
   1117       if (vmap_table.IsInContext(reg, kind, &vmap_offset)) {
   1118         bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg);
   1119         uint32_t spill_mask = is_float ? oat_method.GetFpSpillMask()
   1120                                        : oat_method.GetCoreSpillMask();
   1121         os << (is_float ? "fr" : "r") << vmap_table.ComputeRegister(spill_mask, vmap_offset, kind);
   1122       } else {
   1123         uint32_t offset = StackVisitor::GetVRegOffsetFromQuickCode(
   1124             code_item,
   1125             oat_method.GetCoreSpillMask(),
   1126             oat_method.GetFpSpillMask(),
   1127             oat_method.GetFrameSizeInBytes(),
   1128             reg,
   1129             GetInstructionSet());
   1130         os << "[sp + #" << offset << "]";
   1131       }
   1132     }
   1133   }
   1134 
   1135   void DumpGcMapRegisters(std::ostream& os, const OatFile::OatMethod& oat_method,
   1136                           const DexFile::CodeItem* code_item,
   1137                           size_t num_regs, const uint8_t* reg_bitmap) {
   1138     bool first = true;
   1139     for (size_t reg = 0; reg < num_regs; reg++) {
   1140       if (((reg_bitmap[reg / 8] >> (reg % 8)) & 0x01) != 0) {
   1141         if (first) {
   1142           os << "  v" << reg << " (";
   1143           DescribeVReg(os, oat_method, code_item, reg, kReferenceVReg);
   1144           os << ")";
   1145           first = false;
   1146         } else {
   1147           os << ", v" << reg << " (";
   1148           DescribeVReg(os, oat_method, code_item, reg, kReferenceVReg);
   1149           os << ")";
   1150         }
   1151       }
   1152     }
   1153     if (first) {
   1154       os << "No registers in GC map\n";
   1155     } else {
   1156       os << "\n";
   1157     }
   1158   }
   1159   void DumpGcMap(std::ostream& os, const OatFile::OatMethod& oat_method,
   1160                  const DexFile::CodeItem* code_item) {
   1161     const uint8_t* gc_map_raw = oat_method.GetGcMap();
   1162     if (gc_map_raw == nullptr) {
   1163       return;  // No GC map.
   1164     }
   1165     const void* quick_code = oat_method.GetQuickCode();
   1166     NativePcOffsetToReferenceMap map(gc_map_raw);
   1167     for (size_t entry = 0; entry < map.NumEntries(); entry++) {
   1168       const uint8_t* native_pc = reinterpret_cast<const uint8_t*>(quick_code) +
   1169           map.GetNativePcOffset(entry);
   1170       os << StringPrintf("%p", native_pc);
   1171       DumpGcMapRegisters(os, oat_method, code_item, map.RegWidth() * 8, map.GetBitMap(entry));
   1172     }
   1173   }
   1174 
   1175   void DumpMappingTable(std::ostream& os, const OatFile::OatMethod& oat_method) {
   1176     const void* quick_code = oat_method.GetQuickCode();
   1177     if (quick_code == nullptr) {
   1178       return;
   1179     }
   1180     MappingTable table(oat_method.GetMappingTable());
   1181     if (table.TotalSize() != 0) {
   1182       Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
   1183       std::ostream indent_os(&indent_filter);
   1184       if (table.PcToDexSize() != 0) {
   1185         typedef MappingTable::PcToDexIterator It;
   1186         os << "suspend point mappings {\n";
   1187         for (It cur = table.PcToDexBegin(), end = table.PcToDexEnd(); cur != end; ++cur) {
   1188           indent_os << StringPrintf("0x%04x -> 0x%04x\n", cur.NativePcOffset(), cur.DexPc());
   1189         }
   1190         os << "}\n";
   1191       }
   1192       if (table.DexToPcSize() != 0) {
   1193         typedef MappingTable::DexToPcIterator It;
   1194         os << "catch entry mappings {\n";
   1195         for (It cur = table.DexToPcBegin(), end = table.DexToPcEnd(); cur != end; ++cur) {
   1196           indent_os << StringPrintf("0x%04x -> 0x%04x\n", cur.NativePcOffset(), cur.DexPc());
   1197         }
   1198         os << "}\n";
   1199       }
   1200     }
   1201   }
   1202 
   1203   uint32_t DumpMappingAtOffset(std::ostream& os, const OatFile::OatMethod& oat_method,
   1204                                size_t offset, bool suspend_point_mapping) {
   1205     MappingTable table(oat_method.GetMappingTable());
   1206     if (suspend_point_mapping && table.PcToDexSize() > 0) {
   1207       typedef MappingTable::PcToDexIterator It;
   1208       for (It cur = table.PcToDexBegin(), end = table.PcToDexEnd(); cur != end; ++cur) {
   1209         if (offset == cur.NativePcOffset()) {
   1210           os << StringPrintf("suspend point dex PC: 0x%04x\n", cur.DexPc());
   1211           return cur.DexPc();
   1212         }
   1213       }
   1214     } else if (!suspend_point_mapping && table.DexToPcSize() > 0) {
   1215       typedef MappingTable::DexToPcIterator It;
   1216       for (It cur = table.DexToPcBegin(), end = table.DexToPcEnd(); cur != end; ++cur) {
   1217         if (offset == cur.NativePcOffset()) {
   1218           os << StringPrintf("catch entry dex PC: 0x%04x\n", cur.DexPc());
   1219           return cur.DexPc();
   1220         }
   1221       }
   1222     }
   1223     return DexFile::kDexNoIndex;
   1224   }
   1225 
   1226   void DumpGcMapAtNativePcOffset(std::ostream& os, const OatFile::OatMethod& oat_method,
   1227                                  const DexFile::CodeItem* code_item, size_t native_pc_offset) {
   1228     const uint8_t* gc_map_raw = oat_method.GetGcMap();
   1229     if (gc_map_raw != nullptr) {
   1230       NativePcOffsetToReferenceMap map(gc_map_raw);
   1231       if (map.HasEntry(native_pc_offset)) {
   1232         size_t num_regs = map.RegWidth() * 8;
   1233         const uint8_t* reg_bitmap = map.FindBitMap(native_pc_offset);
   1234         bool first = true;
   1235         for (size_t reg = 0; reg < num_regs; reg++) {
   1236           if (((reg_bitmap[reg / 8] >> (reg % 8)) & 0x01) != 0) {
   1237             if (first) {
   1238               os << "GC map objects:  v" << reg << " (";
   1239               DescribeVReg(os, oat_method, code_item, reg, kReferenceVReg);
   1240               os << ")";
   1241               first = false;
   1242             } else {
   1243               os << ", v" << reg << " (";
   1244               DescribeVReg(os, oat_method, code_item, reg, kReferenceVReg);
   1245               os << ")";
   1246             }
   1247           }
   1248         }
   1249         if (!first) {
   1250           os << "\n";
   1251         }
   1252       }
   1253     }
   1254   }
   1255 
   1256   void DumpVRegsAtDexPc(std::ostream& os, verifier::MethodVerifier* verifier,
   1257                         const OatFile::OatMethod& oat_method,
   1258                         const DexFile::CodeItem* code_item, uint32_t dex_pc) {
   1259     DCHECK(verifier != nullptr);
   1260     std::vector<int32_t> kinds = verifier->DescribeVRegs(dex_pc);
   1261     bool first = true;
   1262     for (size_t reg = 0; reg < code_item->registers_size_; reg++) {
   1263       VRegKind kind = static_cast<VRegKind>(kinds.at(reg * 2));
   1264       if (kind != kUndefined) {
   1265         if (first) {
   1266           os << "VRegs:  v";
   1267           first = false;
   1268         } else {
   1269           os << ", v";
   1270         }
   1271         os << reg << " (";
   1272         switch (kind) {
   1273           case kImpreciseConstant:
   1274             os << "Imprecise Constant: " << kinds.at((reg * 2) + 1) << ", ";
   1275             DescribeVReg(os, oat_method, code_item, reg, kind);
   1276             break;
   1277           case kConstant:
   1278             os << "Constant: " << kinds.at((reg * 2) + 1);
   1279             break;
   1280           default:
   1281             DescribeVReg(os, oat_method, code_item, reg, kind);
   1282             break;
   1283         }
   1284         os << ")";
   1285       }
   1286     }
   1287     if (!first) {
   1288       os << "\n";
   1289     }
   1290   }
   1291 
   1292 
   1293   void DumpDexCode(std::ostream& os, const DexFile& dex_file, const DexFile::CodeItem* code_item) {
   1294     if (code_item != nullptr) {
   1295       size_t i = 0;
   1296       while (i < code_item->insns_size_in_code_units_) {
   1297         const Instruction* instruction = Instruction::At(&code_item->insns_[i]);
   1298         os << StringPrintf("0x%04zx: ", i) << instruction->DumpHexLE(5)
   1299            << StringPrintf("\t| %s\n", instruction->DumpString(&dex_file).c_str());
   1300         i += instruction->SizeInCodeUnits();
   1301       }
   1302     }
   1303   }
   1304 
   1305   verifier::MethodVerifier* DumpVerifier(std::ostream& os, uint32_t dex_method_idx,
   1306                                          const DexFile* dex_file,
   1307                                          const DexFile::ClassDef& class_def,
   1308                                          const DexFile::CodeItem* code_item,
   1309                                          uint32_t method_access_flags) {
   1310     if ((method_access_flags & kAccNative) == 0) {
   1311       ScopedObjectAccess soa(Thread::Current());
   1312       StackHandleScope<1> hs(soa.Self());
   1313       Handle<mirror::DexCache> dex_cache(
   1314           hs.NewHandle(Runtime::Current()->GetClassLinker()->FindDexCache(*dex_file)));
   1315       DCHECK(options_.class_loader_ != nullptr);
   1316       return verifier::MethodVerifier::VerifyMethodAndDump(
   1317           soa.Self(), os, dex_method_idx, dex_file, dex_cache, *options_.class_loader_, &class_def,
   1318           code_item, nullptr, method_access_flags);
   1319     }
   1320 
   1321     return nullptr;
   1322   }
   1323 
   1324   void DumpCode(std::ostream& os, verifier::MethodVerifier* verifier,
   1325                 const OatFile::OatMethod& oat_method, const DexFile::CodeItem* code_item,
   1326                 bool bad_input, size_t code_size) {
   1327     const void* quick_code = oat_method.GetQuickCode();
   1328 
   1329     if (code_size == 0) {
   1330       code_size = oat_method.GetQuickCodeSize();
   1331     }
   1332     if (code_size == 0 || quick_code == nullptr) {
   1333       os << "NO CODE!\n";
   1334       return;
   1335     } else {
   1336       const uint8_t* quick_native_pc = reinterpret_cast<const uint8_t*>(quick_code);
   1337       size_t offset = 0;
   1338       while (offset < code_size) {
   1339         if (!bad_input) {
   1340           DumpMappingAtOffset(os, oat_method, offset, false);
   1341         }
   1342         offset += disassembler_->Dump(os, quick_native_pc + offset);
   1343         if (!bad_input) {
   1344           uint32_t dex_pc = DumpMappingAtOffset(os, oat_method, offset, true);
   1345           if (dex_pc != DexFile::kDexNoIndex) {
   1346             DumpGcMapAtNativePcOffset(os, oat_method, code_item, offset);
   1347             if (verifier != nullptr) {
   1348               DumpVRegsAtDexPc(os, verifier, oat_method, code_item, dex_pc);
   1349             }
   1350           }
   1351         }
   1352       }
   1353     }
   1354   }
   1355 
   1356   const OatFile& oat_file_;
   1357   const std::vector<const OatFile::OatDexFile*> oat_dex_files_;
   1358   const OatDumperOptions& options_;
   1359   uint32_t resolved_addr2instr_;
   1360   InstructionSet instruction_set_;
   1361   std::set<uintptr_t> offsets_;
   1362   Disassembler* disassembler_;
   1363 };
   1364 
   1365 class ImageDumper {
   1366  public:
   1367   explicit ImageDumper(std::ostream* os, gc::space::ImageSpace& image_space,
   1368                        const ImageHeader& image_header, OatDumperOptions* oat_dumper_options)
   1369       : os_(os),
   1370         image_space_(image_space),
   1371         image_header_(image_header),
   1372         oat_dumper_options_(oat_dumper_options) {}
   1373 
   1374   bool Dump() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   1375     std::ostream& os = *os_;
   1376     os << "MAGIC: " << image_header_.GetMagic() << "\n\n";
   1377 
   1378     os << "IMAGE BEGIN: " << reinterpret_cast<void*>(image_header_.GetImageBegin()) << "\n\n";
   1379 
   1380     os << "IMAGE SIZE: " << image_header_.GetImageSize() << "\n\n";
   1381 
   1382     for (size_t i = 0; i < ImageHeader::kSectionCount; ++i) {
   1383       auto section = static_cast<ImageHeader::ImageSections>(i);
   1384       os << "IMAGE SECTION " << section << ": " << image_header_.GetImageSection(section) << "\n\n";
   1385     }
   1386 
   1387     os << "OAT CHECKSUM: " << StringPrintf("0x%08x\n\n", image_header_.GetOatChecksum());
   1388 
   1389     os << "OAT FILE BEGIN:" << reinterpret_cast<void*>(image_header_.GetOatFileBegin()) << "\n\n";
   1390 
   1391     os << "OAT DATA BEGIN:" << reinterpret_cast<void*>(image_header_.GetOatDataBegin()) << "\n\n";
   1392 
   1393     os << "OAT DATA END:" << reinterpret_cast<void*>(image_header_.GetOatDataEnd()) << "\n\n";
   1394 
   1395     os << "OAT FILE END:" << reinterpret_cast<void*>(image_header_.GetOatFileEnd()) << "\n\n";
   1396 
   1397     os << "PATCH DELTA:" << image_header_.GetPatchDelta() << "\n\n";
   1398 
   1399     os << "COMPILE PIC: " << (image_header_.CompilePic() ? "yes" : "no") << "\n\n";
   1400 
   1401     {
   1402       os << "ROOTS: " << reinterpret_cast<void*>(image_header_.GetImageRoots()) << "\n";
   1403       Indenter indent1_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
   1404       std::ostream indent1_os(&indent1_filter);
   1405       static_assert(arraysize(image_roots_descriptions_) ==
   1406           static_cast<size_t>(ImageHeader::kImageRootsMax), "sizes must match");
   1407       for (int i = 0; i < ImageHeader::kImageRootsMax; i++) {
   1408         ImageHeader::ImageRoot image_root = static_cast<ImageHeader::ImageRoot>(i);
   1409         const char* image_root_description = image_roots_descriptions_[i];
   1410         mirror::Object* image_root_object = image_header_.GetImageRoot(image_root);
   1411         indent1_os << StringPrintf("%s: %p\n", image_root_description, image_root_object);
   1412         if (image_root_object->IsObjectArray()) {
   1413           Indenter indent2_filter(indent1_os.rdbuf(), kIndentChar, kIndentBy1Count);
   1414           std::ostream indent2_os(&indent2_filter);
   1415           mirror::ObjectArray<mirror::Object>* image_root_object_array
   1416               = image_root_object->AsObjectArray<mirror::Object>();
   1417           for (int j = 0; j < image_root_object_array->GetLength(); j++) {
   1418             mirror::Object* value = image_root_object_array->Get(j);
   1419             size_t run = 0;
   1420             for (int32_t k = j + 1; k < image_root_object_array->GetLength(); k++) {
   1421               if (value == image_root_object_array->Get(k)) {
   1422                 run++;
   1423               } else {
   1424                 break;
   1425               }
   1426             }
   1427             if (run == 0) {
   1428               indent2_os << StringPrintf("%d: ", j);
   1429             } else {
   1430               indent2_os << StringPrintf("%d to %zd: ", j, j + run);
   1431               j = j + run;
   1432             }
   1433             if (value != nullptr) {
   1434               PrettyObjectValue(indent2_os, value->GetClass(), value);
   1435             } else {
   1436               indent2_os << j << ": null\n";
   1437             }
   1438           }
   1439         }
   1440       }
   1441 
   1442       os << "METHOD ROOTS\n";
   1443       static_assert(arraysize(image_methods_descriptions_) ==
   1444           static_cast<size_t>(ImageHeader::kImageMethodsCount), "sizes must match");
   1445       for (int i = 0; i < ImageHeader::kImageMethodsCount; i++) {
   1446         auto image_root = static_cast<ImageHeader::ImageMethod>(i);
   1447         const char* description = image_methods_descriptions_[i];
   1448         auto* image_method = image_header_.GetImageMethod(image_root);
   1449         indent1_os << StringPrintf("%s: %p\n", description, image_method);
   1450       }
   1451     }
   1452     os << "\n";
   1453 
   1454     ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   1455     std::string image_filename = image_space_.GetImageFilename();
   1456     std::string oat_location = ImageHeader::GetOatLocationFromImageLocation(image_filename);
   1457     os << "OAT LOCATION: " << oat_location;
   1458     os << "\n";
   1459     std::string error_msg;
   1460     const OatFile* oat_file = class_linker->FindOpenedOatFileFromOatLocation(oat_location);
   1461     if (oat_file == nullptr) {
   1462       oat_file = OatFile::Open(oat_location, oat_location,
   1463                                nullptr, nullptr, false, nullptr,
   1464                                &error_msg);
   1465       if (oat_file == nullptr) {
   1466         os << "NOT FOUND: " << error_msg << "\n";
   1467         return false;
   1468       }
   1469     }
   1470     os << "\n";
   1471 
   1472     stats_.oat_file_bytes = oat_file->Size();
   1473 
   1474     oat_dumper_.reset(new OatDumper(*oat_file, *oat_dumper_options_));
   1475 
   1476     for (const OatFile::OatDexFile* oat_dex_file : oat_file->GetOatDexFiles()) {
   1477       CHECK(oat_dex_file != nullptr);
   1478       stats_.oat_dex_file_sizes.push_back(std::make_pair(oat_dex_file->GetDexFileLocation(),
   1479                                                          oat_dex_file->FileSize()));
   1480     }
   1481 
   1482     os << "OBJECTS:\n" << std::flush;
   1483 
   1484     // Loop through all the image spaces and dump their objects.
   1485     gc::Heap* heap = Runtime::Current()->GetHeap();
   1486     const std::vector<gc::space::ContinuousSpace*>& spaces = heap->GetContinuousSpaces();
   1487     Thread* self = Thread::Current();
   1488     {
   1489       {
   1490         WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
   1491         heap->FlushAllocStack();
   1492       }
   1493       // Since FlushAllocStack() above resets the (active) allocation
   1494       // stack. Need to revoke the thread-local allocation stacks that
   1495       // point into it.
   1496       {
   1497         self->TransitionFromRunnableToSuspended(kNative);
   1498         ThreadList* thread_list = Runtime::Current()->GetThreadList();
   1499         thread_list->SuspendAll(__FUNCTION__);
   1500         heap->RevokeAllThreadLocalAllocationStacks(self);
   1501         thread_list->ResumeAll();
   1502         self->TransitionFromSuspendedToRunnable();
   1503       }
   1504     }
   1505     {
   1506       std::ostream* saved_os = os_;
   1507       Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
   1508       std::ostream indent_os(&indent_filter);
   1509       os_ = &indent_os;
   1510 
   1511       // Mark dex caches.
   1512       dex_cache_arrays_.clear();
   1513       {
   1514         ReaderMutexLock mu(self, *class_linker->DexLock());
   1515         for (size_t i = 0; i < class_linker->GetDexCacheCount(); ++i) {
   1516           auto* dex_cache = class_linker->GetDexCache(i);
   1517           dex_cache_arrays_.insert(dex_cache->GetResolvedFields());
   1518           dex_cache_arrays_.insert(dex_cache->GetResolvedMethods());
   1519         }
   1520       }
   1521       ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
   1522       for (const auto& space : spaces) {
   1523         if (space->IsImageSpace()) {
   1524           auto* image_space = space->AsImageSpace();
   1525           // Dump the normal objects before ArtMethods.
   1526           image_space->GetLiveBitmap()->Walk(ImageDumper::Callback, this);
   1527           indent_os << "\n";
   1528           // TODO: Dump fields.
   1529           // Dump methods after.
   1530           const auto& methods_section = image_header_.GetMethodsSection();
   1531           const auto pointer_size =
   1532               InstructionSetPointerSize(oat_dumper_->GetOatInstructionSet());
   1533           const auto method_size = ArtMethod::ObjectSize(pointer_size);
   1534           for (size_t pos = 0; pos < methods_section.Size(); pos += method_size) {
   1535             auto* method = reinterpret_cast<ArtMethod*>(
   1536                 image_space->Begin() + pos + methods_section.Offset());
   1537             indent_os << method << " " << " ArtMethod: " << PrettyMethod(method) << "\n";
   1538             DumpMethod(method, this, indent_os);
   1539             indent_os << "\n";
   1540           }
   1541         }
   1542       }
   1543       // Dump the large objects separately.
   1544       heap->GetLargeObjectsSpace()->GetLiveBitmap()->Walk(ImageDumper::Callback, this);
   1545       indent_os << "\n";
   1546       os_ = saved_os;
   1547     }
   1548     os << "STATS:\n" << std::flush;
   1549     std::unique_ptr<File> file(OS::OpenFileForReading(image_filename.c_str()));
   1550     if (file.get() == nullptr) {
   1551       LOG(WARNING) << "Failed to find image in " << image_filename;
   1552     }
   1553     if (file.get() != nullptr) {
   1554       stats_.file_bytes = file->GetLength();
   1555     }
   1556     size_t header_bytes = sizeof(ImageHeader);
   1557     const auto& bitmap_section = image_header_.GetImageSection(ImageHeader::kSectionImageBitmap);
   1558     const auto& field_section = image_header_.GetImageSection(ImageHeader::kSectionArtFields);
   1559     const auto& method_section = image_header_.GetMethodsSection();
   1560     const auto& intern_section = image_header_.GetImageSection(
   1561         ImageHeader::kSectionInternedStrings);
   1562     stats_.header_bytes = header_bytes;
   1563     size_t alignment_bytes = RoundUp(header_bytes, kObjectAlignment) - header_bytes;
   1564     stats_.alignment_bytes += alignment_bytes;
   1565     stats_.alignment_bytes += bitmap_section.Offset() - image_header_.GetImageSize();
   1566     stats_.bitmap_bytes += bitmap_section.Size();
   1567     stats_.art_field_bytes += field_section.Size();
   1568     stats_.art_method_bytes += method_section.Size();
   1569     stats_.interned_strings_bytes += intern_section.Size();
   1570     stats_.Dump(os);
   1571     os << "\n";
   1572 
   1573     os << std::flush;
   1574 
   1575     return oat_dumper_->Dump(os);
   1576   }
   1577 
   1578  private:
   1579   static void PrettyObjectValue(std::ostream& os, mirror::Class* type, mirror::Object* value)
   1580       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   1581     CHECK(type != nullptr);
   1582     if (value == nullptr) {
   1583       os << StringPrintf("null   %s\n", PrettyDescriptor(type).c_str());
   1584     } else if (type->IsStringClass()) {
   1585       mirror::String* string = value->AsString();
   1586       os << StringPrintf("%p   String: %s\n", string,
   1587                          PrintableString(string->ToModifiedUtf8().c_str()).c_str());
   1588     } else if (type->IsClassClass()) {
   1589       mirror::Class* klass = value->AsClass();
   1590       os << StringPrintf("%p   Class: %s\n", klass, PrettyDescriptor(klass).c_str());
   1591     } else {
   1592       os << StringPrintf("%p   %s\n", value, PrettyDescriptor(type).c_str());
   1593     }
   1594   }
   1595 
   1596   static void PrintField(std::ostream& os, ArtField* field, mirror::Object* obj)
   1597       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   1598     os << StringPrintf("%s: ", field->GetName());
   1599     switch (field->GetTypeAsPrimitiveType()) {
   1600       case Primitive::kPrimLong:
   1601         os << StringPrintf("%" PRId64 " (0x%" PRIx64 ")\n", field->Get64(obj), field->Get64(obj));
   1602         break;
   1603       case Primitive::kPrimDouble:
   1604         os << StringPrintf("%f (%a)\n", field->GetDouble(obj), field->GetDouble(obj));
   1605         break;
   1606       case Primitive::kPrimFloat:
   1607         os << StringPrintf("%f (%a)\n", field->GetFloat(obj), field->GetFloat(obj));
   1608         break;
   1609       case Primitive::kPrimInt:
   1610         os << StringPrintf("%d (0x%x)\n", field->Get32(obj), field->Get32(obj));
   1611         break;
   1612       case Primitive::kPrimChar:
   1613         os << StringPrintf("%u (0x%x)\n", field->GetChar(obj), field->GetChar(obj));
   1614         break;
   1615       case Primitive::kPrimShort:
   1616         os << StringPrintf("%d (0x%x)\n", field->GetShort(obj), field->GetShort(obj));
   1617         break;
   1618       case Primitive::kPrimBoolean:
   1619         os << StringPrintf("%s (0x%x)\n", field->GetBoolean(obj)? "true" : "false",
   1620             field->GetBoolean(obj));
   1621         break;
   1622       case Primitive::kPrimByte:
   1623         os << StringPrintf("%d (0x%x)\n", field->GetByte(obj), field->GetByte(obj));
   1624         break;
   1625       case Primitive::kPrimNot: {
   1626         // Get the value, don't compute the type unless it is non-null as we don't want
   1627         // to cause class loading.
   1628         mirror::Object* value = field->GetObj(obj);
   1629         if (value == nullptr) {
   1630           os << StringPrintf("null   %s\n", PrettyDescriptor(field->GetTypeDescriptor()).c_str());
   1631         } else {
   1632           // Grab the field type without causing resolution.
   1633           mirror::Class* field_type = field->GetType<false>();
   1634           if (field_type != nullptr) {
   1635             PrettyObjectValue(os, field_type, value);
   1636           } else {
   1637             os << StringPrintf("%p   %s\n", value,
   1638                                PrettyDescriptor(field->GetTypeDescriptor()).c_str());
   1639           }
   1640         }
   1641         break;
   1642       }
   1643       default:
   1644         os << "unexpected field type: " << field->GetTypeDescriptor() << "\n";
   1645         break;
   1646     }
   1647   }
   1648 
   1649   static void DumpFields(std::ostream& os, mirror::Object* obj, mirror::Class* klass)
   1650       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   1651     mirror::Class* super = klass->GetSuperClass();
   1652     if (super != nullptr) {
   1653       DumpFields(os, obj, super);
   1654     }
   1655     ArtField* fields = klass->GetIFields();
   1656     for (size_t i = 0, count = klass->NumInstanceFields(); i < count; i++) {
   1657       PrintField(os, &fields[i], obj);
   1658     }
   1659   }
   1660 
   1661   bool InDumpSpace(const mirror::Object* object) {
   1662     return image_space_.Contains(object);
   1663   }
   1664 
   1665   const void* GetQuickOatCodeBegin(ArtMethod* m)
   1666       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   1667     const void* quick_code = m->GetEntryPointFromQuickCompiledCodePtrSize(
   1668         InstructionSetPointerSize(oat_dumper_->GetOatInstructionSet()));
   1669     if (Runtime::Current()->GetClassLinker()->IsQuickResolutionStub(quick_code)) {
   1670       quick_code = oat_dumper_->GetQuickOatCode(m);
   1671     }
   1672     if (oat_dumper_->GetInstructionSet() == kThumb2) {
   1673       quick_code = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(quick_code) & ~0x1);
   1674     }
   1675     return quick_code;
   1676   }
   1677 
   1678   uint32_t GetQuickOatCodeSize(ArtMethod* m)
   1679       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   1680     const uint32_t* oat_code_begin = reinterpret_cast<const uint32_t*>(GetQuickOatCodeBegin(m));
   1681     if (oat_code_begin == nullptr) {
   1682       return 0;
   1683     }
   1684     return oat_code_begin[-1];
   1685   }
   1686 
   1687   const void* GetQuickOatCodeEnd(ArtMethod* m)
   1688       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   1689     const uint8_t* oat_code_begin = reinterpret_cast<const uint8_t*>(GetQuickOatCodeBegin(m));
   1690     if (oat_code_begin == nullptr) {
   1691       return nullptr;
   1692     }
   1693     return oat_code_begin + GetQuickOatCodeSize(m);
   1694   }
   1695 
   1696   static void Callback(mirror::Object* obj, void* arg) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   1697     DCHECK(obj != nullptr);
   1698     DCHECK(arg != nullptr);
   1699     ImageDumper* state = reinterpret_cast<ImageDumper*>(arg);
   1700     if (!state->InDumpSpace(obj)) {
   1701       return;
   1702     }
   1703 
   1704     size_t object_bytes = obj->SizeOf();
   1705     size_t alignment_bytes = RoundUp(object_bytes, kObjectAlignment) - object_bytes;
   1706     state->stats_.object_bytes += object_bytes;
   1707     state->stats_.alignment_bytes += alignment_bytes;
   1708 
   1709     std::ostream& os = *state->os_;
   1710     mirror::Class* obj_class = obj->GetClass();
   1711     if (obj_class->IsArrayClass()) {
   1712       os << StringPrintf("%p: %s length:%d\n", obj, PrettyDescriptor(obj_class).c_str(),
   1713                          obj->AsArray()->GetLength());
   1714     } else if (obj->IsClass()) {
   1715       mirror::Class* klass = obj->AsClass();
   1716       os << StringPrintf("%p: java.lang.Class \"%s\" (", obj, PrettyDescriptor(klass).c_str())
   1717          << klass->GetStatus() << ")\n";
   1718     } else if (obj_class->IsStringClass()) {
   1719       os << StringPrintf("%p: java.lang.String %s\n", obj,
   1720                          PrintableString(obj->AsString()->ToModifiedUtf8().c_str()).c_str());
   1721     } else {
   1722       os << StringPrintf("%p: %s\n", obj, PrettyDescriptor(obj_class).c_str());
   1723     }
   1724     Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
   1725     std::ostream indent_os(&indent_filter);
   1726     DumpFields(indent_os, obj, obj_class);
   1727     const auto image_pointer_size =
   1728         InstructionSetPointerSize(state->oat_dumper_->GetOatInstructionSet());
   1729     if (obj->IsObjectArray()) {
   1730       auto* obj_array = obj->AsObjectArray<mirror::Object>();
   1731       for (int32_t i = 0, length = obj_array->GetLength(); i < length; i++) {
   1732         mirror::Object* value = obj_array->Get(i);
   1733         size_t run = 0;
   1734         for (int32_t j = i + 1; j < length; j++) {
   1735           if (value == obj_array->Get(j)) {
   1736             run++;
   1737           } else {
   1738             break;
   1739           }
   1740         }
   1741         if (run == 0) {
   1742           indent_os << StringPrintf("%d: ", i);
   1743         } else {
   1744           indent_os << StringPrintf("%d to %zd: ", i, i + run);
   1745           i = i + run;
   1746         }
   1747         mirror::Class* value_class =
   1748             (value == nullptr) ? obj_class->GetComponentType() : value->GetClass();
   1749         PrettyObjectValue(indent_os, value_class, value);
   1750       }
   1751     } else if (obj->IsClass()) {
   1752       mirror::Class* klass = obj->AsClass();
   1753       ArtField* sfields = klass->GetSFields();
   1754       const size_t num_fields = klass->NumStaticFields();
   1755       if (num_fields != 0) {
   1756         indent_os << "STATICS:\n";
   1757         Indenter indent2_filter(indent_os.rdbuf(), kIndentChar, kIndentBy1Count);
   1758         std::ostream indent2_os(&indent2_filter);
   1759         for (size_t i = 0; i < num_fields; i++) {
   1760           PrintField(indent2_os, &sfields[i], sfields[i].GetDeclaringClass());
   1761         }
   1762       }
   1763     } else {
   1764       auto it = state->dex_cache_arrays_.find(obj);
   1765       if (it != state->dex_cache_arrays_.end()) {
   1766         const auto& field_section = state->image_header_.GetImageSection(
   1767             ImageHeader::kSectionArtFields);
   1768         const auto& method_section = state->image_header_.GetMethodsSection();
   1769         auto* arr = down_cast<mirror::PointerArray*>(obj);
   1770         for (int32_t i = 0, length = arr->GetLength(); i < length; i++) {
   1771           void* elem = arr->GetElementPtrSize<void*>(i, image_pointer_size);
   1772           size_t run = 0;
   1773           for (int32_t j = i + 1; j < length &&
   1774               elem == arr->GetElementPtrSize<void*>(j, image_pointer_size); j++, run++) { }
   1775           if (run == 0) {
   1776             indent_os << StringPrintf("%d: ", i);
   1777           } else {
   1778             indent_os << StringPrintf("%d to %zd: ", i, i + run);
   1779             i = i + run;
   1780           }
   1781           auto offset = reinterpret_cast<uint8_t*>(elem) - state->image_space_.Begin();
   1782           std::string msg;
   1783           if (field_section.Contains(offset)) {
   1784             msg = PrettyField(reinterpret_cast<ArtField*>(elem));
   1785           } else if (method_section.Contains(offset)) {
   1786             msg = PrettyMethod(reinterpret_cast<ArtMethod*>(elem));
   1787           } else {
   1788             msg = "Unknown type";
   1789           }
   1790           indent_os << StringPrintf("%p   %s\n", elem, msg.c_str());
   1791         }
   1792       }
   1793     }
   1794     std::string temp;
   1795     state->stats_.Update(obj_class->GetDescriptor(&temp), object_bytes);
   1796   }
   1797 
   1798   void DumpMethod(ArtMethod* method, ImageDumper* state, std::ostream& indent_os)
   1799       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   1800     DCHECK(method != nullptr);
   1801     const auto image_pointer_size =
   1802         InstructionSetPointerSize(state->oat_dumper_->GetOatInstructionSet());
   1803     if (method->IsNative()) {
   1804       DCHECK(method->GetNativeGcMap(image_pointer_size) == nullptr) << PrettyMethod(method);
   1805       DCHECK(method->GetMappingTable(image_pointer_size) == nullptr) << PrettyMethod(method);
   1806       bool first_occurrence;
   1807       const void* quick_oat_code = state->GetQuickOatCodeBegin(method);
   1808       uint32_t quick_oat_code_size = state->GetQuickOatCodeSize(method);
   1809       state->ComputeOatSize(quick_oat_code, &first_occurrence);
   1810       if (first_occurrence) {
   1811         state->stats_.native_to_managed_code_bytes += quick_oat_code_size;
   1812       }
   1813       if (quick_oat_code != method->GetEntryPointFromQuickCompiledCodePtrSize(image_pointer_size)) {
   1814         indent_os << StringPrintf("OAT CODE: %p\n", quick_oat_code);
   1815       }
   1816     } else if (method->IsAbstract() || method->IsCalleeSaveMethod() ||
   1817       method->IsResolutionMethod() || method->IsImtConflictMethod() ||
   1818       method->IsImtUnimplementedMethod() || method->IsClassInitializer()) {
   1819       DCHECK(method->GetNativeGcMap(image_pointer_size) == nullptr) << PrettyMethod(method);
   1820       DCHECK(method->GetMappingTable(image_pointer_size) == nullptr) << PrettyMethod(method);
   1821     } else {
   1822       const DexFile::CodeItem* code_item = method->GetCodeItem();
   1823       size_t dex_instruction_bytes = code_item->insns_size_in_code_units_ * 2;
   1824       state->stats_.dex_instruction_bytes += dex_instruction_bytes;
   1825 
   1826       bool first_occurrence;
   1827       size_t gc_map_bytes = state->ComputeOatSize(
   1828           method->GetNativeGcMap(image_pointer_size), &first_occurrence);
   1829       if (first_occurrence) {
   1830         state->stats_.gc_map_bytes += gc_map_bytes;
   1831       }
   1832 
   1833       size_t pc_mapping_table_bytes = state->ComputeOatSize(
   1834           method->GetMappingTable(image_pointer_size), &first_occurrence);
   1835       if (first_occurrence) {
   1836         state->stats_.pc_mapping_table_bytes += pc_mapping_table_bytes;
   1837       }
   1838 
   1839       size_t vmap_table_bytes = state->ComputeOatSize(
   1840           method->GetVmapTable(image_pointer_size), &first_occurrence);
   1841       if (first_occurrence) {
   1842         state->stats_.vmap_table_bytes += vmap_table_bytes;
   1843       }
   1844 
   1845       const void* quick_oat_code_begin = state->GetQuickOatCodeBegin(method);
   1846       const void* quick_oat_code_end = state->GetQuickOatCodeEnd(method);
   1847       uint32_t quick_oat_code_size = state->GetQuickOatCodeSize(method);
   1848       state->ComputeOatSize(quick_oat_code_begin, &first_occurrence);
   1849       if (first_occurrence) {
   1850         state->stats_.managed_code_bytes += quick_oat_code_size;
   1851         if (method->IsConstructor()) {
   1852           if (method->IsStatic()) {
   1853             state->stats_.class_initializer_code_bytes += quick_oat_code_size;
   1854           } else if (dex_instruction_bytes > kLargeConstructorDexBytes) {
   1855             state->stats_.large_initializer_code_bytes += quick_oat_code_size;
   1856           }
   1857         } else if (dex_instruction_bytes > kLargeMethodDexBytes) {
   1858           state->stats_.large_method_code_bytes += quick_oat_code_size;
   1859         }
   1860       }
   1861       state->stats_.managed_code_bytes_ignoring_deduplication += quick_oat_code_size;
   1862 
   1863       indent_os << StringPrintf("OAT CODE: %p-%p\n", quick_oat_code_begin, quick_oat_code_end);
   1864       indent_os << StringPrintf("SIZE: Dex Instructions=%zd GC=%zd Mapping=%zd\n",
   1865       dex_instruction_bytes, gc_map_bytes, pc_mapping_table_bytes);
   1866 
   1867       size_t total_size = dex_instruction_bytes + gc_map_bytes + pc_mapping_table_bytes +
   1868           vmap_table_bytes + quick_oat_code_size + ArtMethod::ObjectSize(image_pointer_size);
   1869 
   1870       double expansion =
   1871       static_cast<double>(quick_oat_code_size) / static_cast<double>(dex_instruction_bytes);
   1872       state->stats_.ComputeOutliers(total_size, expansion, method);
   1873     }
   1874   }
   1875 
   1876   std::set<const void*> already_seen_;
   1877   // Compute the size of the given data within the oat file and whether this is the first time
   1878   // this data has been requested
   1879   size_t ComputeOatSize(const void* oat_data, bool* first_occurrence) {
   1880     if (already_seen_.count(oat_data) == 0) {
   1881       *first_occurrence = true;
   1882       already_seen_.insert(oat_data);
   1883     } else {
   1884       *first_occurrence = false;
   1885     }
   1886     return oat_dumper_->ComputeSize(oat_data);
   1887   }
   1888 
   1889  public:
   1890   struct Stats {
   1891     size_t oat_file_bytes;
   1892     size_t file_bytes;
   1893 
   1894     size_t header_bytes;
   1895     size_t object_bytes;
   1896     size_t art_field_bytes;
   1897     size_t art_method_bytes;
   1898     size_t interned_strings_bytes;
   1899     size_t bitmap_bytes;
   1900     size_t alignment_bytes;
   1901 
   1902     size_t managed_code_bytes;
   1903     size_t managed_code_bytes_ignoring_deduplication;
   1904     size_t managed_to_native_code_bytes;
   1905     size_t native_to_managed_code_bytes;
   1906     size_t class_initializer_code_bytes;
   1907     size_t large_initializer_code_bytes;
   1908     size_t large_method_code_bytes;
   1909 
   1910     size_t gc_map_bytes;
   1911     size_t pc_mapping_table_bytes;
   1912     size_t vmap_table_bytes;
   1913 
   1914     size_t dex_instruction_bytes;
   1915 
   1916     std::vector<ArtMethod*> method_outlier;
   1917     std::vector<size_t> method_outlier_size;
   1918     std::vector<double> method_outlier_expansion;
   1919     std::vector<std::pair<std::string, size_t>> oat_dex_file_sizes;
   1920 
   1921     explicit Stats()
   1922         : oat_file_bytes(0),
   1923           file_bytes(0),
   1924           header_bytes(0),
   1925           object_bytes(0),
   1926           art_field_bytes(0),
   1927           art_method_bytes(0),
   1928           interned_strings_bytes(0),
   1929           bitmap_bytes(0),
   1930           alignment_bytes(0),
   1931           managed_code_bytes(0),
   1932           managed_code_bytes_ignoring_deduplication(0),
   1933           managed_to_native_code_bytes(0),
   1934           native_to_managed_code_bytes(0),
   1935           class_initializer_code_bytes(0),
   1936           large_initializer_code_bytes(0),
   1937           large_method_code_bytes(0),
   1938           gc_map_bytes(0),
   1939           pc_mapping_table_bytes(0),
   1940           vmap_table_bytes(0),
   1941           dex_instruction_bytes(0) {}
   1942 
   1943     struct SizeAndCount {
   1944       SizeAndCount(size_t bytes_in, size_t count_in) : bytes(bytes_in), count(count_in) {}
   1945       size_t bytes;
   1946       size_t count;
   1947     };
   1948     typedef SafeMap<std::string, SizeAndCount> SizeAndCountTable;
   1949     SizeAndCountTable sizes_and_counts;
   1950 
   1951     void Update(const char* descriptor, size_t object_bytes_in) {
   1952       SizeAndCountTable::iterator it = sizes_and_counts.find(descriptor);
   1953       if (it != sizes_and_counts.end()) {
   1954         it->second.bytes += object_bytes_in;
   1955         it->second.count += 1;
   1956       } else {
   1957         sizes_and_counts.Put(descriptor, SizeAndCount(object_bytes_in, 1));
   1958       }
   1959     }
   1960 
   1961     double PercentOfOatBytes(size_t size) {
   1962       return (static_cast<double>(size) / static_cast<double>(oat_file_bytes)) * 100;
   1963     }
   1964 
   1965     double PercentOfFileBytes(size_t size) {
   1966       return (static_cast<double>(size) / static_cast<double>(file_bytes)) * 100;
   1967     }
   1968 
   1969     double PercentOfObjectBytes(size_t size) {
   1970       return (static_cast<double>(size) / static_cast<double>(object_bytes)) * 100;
   1971     }
   1972 
   1973     void ComputeOutliers(size_t total_size, double expansion, ArtMethod* method) {
   1974       method_outlier_size.push_back(total_size);
   1975       method_outlier_expansion.push_back(expansion);
   1976       method_outlier.push_back(method);
   1977     }
   1978 
   1979     void DumpOutliers(std::ostream& os)
   1980         SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   1981       size_t sum_of_sizes = 0;
   1982       size_t sum_of_sizes_squared = 0;
   1983       size_t sum_of_expansion = 0;
   1984       size_t sum_of_expansion_squared = 0;
   1985       size_t n = method_outlier_size.size();
   1986       for (size_t i = 0; i < n; i++) {
   1987         size_t cur_size = method_outlier_size[i];
   1988         sum_of_sizes += cur_size;
   1989         sum_of_sizes_squared += cur_size * cur_size;
   1990         double cur_expansion = method_outlier_expansion[i];
   1991         sum_of_expansion += cur_expansion;
   1992         sum_of_expansion_squared += cur_expansion * cur_expansion;
   1993       }
   1994       size_t size_mean = sum_of_sizes / n;
   1995       size_t size_variance = (sum_of_sizes_squared - sum_of_sizes * size_mean) / (n - 1);
   1996       double expansion_mean = sum_of_expansion / n;
   1997       double expansion_variance =
   1998           (sum_of_expansion_squared - sum_of_expansion * expansion_mean) / (n - 1);
   1999 
   2000       // Dump methods whose size is a certain number of standard deviations from the mean
   2001       size_t dumped_values = 0;
   2002       size_t skipped_values = 0;
   2003       for (size_t i = 100; i > 0; i--) {  // i is the current number of standard deviations
   2004         size_t cur_size_variance = i * i * size_variance;
   2005         bool first = true;
   2006         for (size_t j = 0; j < n; j++) {
   2007           size_t cur_size = method_outlier_size[j];
   2008           if (cur_size > size_mean) {
   2009             size_t cur_var = cur_size - size_mean;
   2010             cur_var = cur_var * cur_var;
   2011             if (cur_var > cur_size_variance) {
   2012               if (dumped_values > 20) {
   2013                 if (i == 1) {
   2014                   skipped_values++;
   2015                 } else {
   2016                   i = 2;  // jump to counting for 1 standard deviation
   2017                   break;
   2018                 }
   2019               } else {
   2020                 if (first) {
   2021                   os << "\nBig methods (size > " << i << " standard deviations the norm):\n";
   2022                   first = false;
   2023                 }
   2024                 os << PrettyMethod(method_outlier[j]) << " requires storage of "
   2025                     << PrettySize(cur_size) << "\n";
   2026                 method_outlier_size[j] = 0;  // don't consider this method again
   2027                 dumped_values++;
   2028               }
   2029             }
   2030           }
   2031         }
   2032       }
   2033       if (skipped_values > 0) {
   2034         os << "... skipped " << skipped_values
   2035            << " methods with size > 1 standard deviation from the norm\n";
   2036       }
   2037       os << std::flush;
   2038 
   2039       // Dump methods whose expansion is a certain number of standard deviations from the mean
   2040       dumped_values = 0;
   2041       skipped_values = 0;
   2042       for (size_t i = 10; i > 0; i--) {  // i is the current number of standard deviations
   2043         double cur_expansion_variance = i * i * expansion_variance;
   2044         bool first = true;
   2045         for (size_t j = 0; j < n; j++) {
   2046           double cur_expansion = method_outlier_expansion[j];
   2047           if (cur_expansion > expansion_mean) {
   2048             size_t cur_var = cur_expansion - expansion_mean;
   2049             cur_var = cur_var * cur_var;
   2050             if (cur_var > cur_expansion_variance) {
   2051               if (dumped_values > 20) {
   2052                 if (i == 1) {
   2053                   skipped_values++;
   2054                 } else {
   2055                   i = 2;  // jump to counting for 1 standard deviation
   2056                   break;
   2057                 }
   2058               } else {
   2059                 if (first) {
   2060                   os << "\nLarge expansion methods (size > " << i
   2061                       << " standard deviations the norm):\n";
   2062                   first = false;
   2063                 }
   2064                 os << PrettyMethod(method_outlier[j]) << " expanded code by "
   2065                    << cur_expansion << "\n";
   2066                 method_outlier_expansion[j] = 0.0;  // don't consider this method again
   2067                 dumped_values++;
   2068               }
   2069             }
   2070           }
   2071         }
   2072       }
   2073       if (skipped_values > 0) {
   2074         os << "... skipped " << skipped_values
   2075            << " methods with expansion > 1 standard deviation from the norm\n";
   2076       }
   2077       os << "\n" << std::flush;
   2078     }
   2079 
   2080     void Dump(std::ostream& os) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   2081       {
   2082         os << "art_file_bytes = " << PrettySize(file_bytes) << "\n\n"
   2083            << "art_file_bytes = header_bytes + object_bytes + alignment_bytes\n";
   2084         Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
   2085         std::ostream indent_os(&indent_filter);
   2086         indent_os << StringPrintf("header_bytes          =  %8zd (%2.0f%% of art file bytes)\n"
   2087                                   "object_bytes          =  %8zd (%2.0f%% of art file bytes)\n"
   2088                                   "art_field_bytes       =  %8zd (%2.0f%% of art file bytes)\n"
   2089                                   "art_method_bytes      =  %8zd (%2.0f%% of art file bytes)\n"
   2090                                   "interned_string_bytes =  %8zd (%2.0f%% of art file bytes)\n"
   2091                                   "bitmap_bytes          =  %8zd (%2.0f%% of art file bytes)\n"
   2092                                   "alignment_bytes       =  %8zd (%2.0f%% of art file bytes)\n\n",
   2093                                   header_bytes, PercentOfFileBytes(header_bytes),
   2094                                   object_bytes, PercentOfFileBytes(object_bytes),
   2095                                   art_field_bytes, PercentOfFileBytes(art_field_bytes),
   2096                                   art_method_bytes, PercentOfFileBytes(art_method_bytes),
   2097                                   interned_strings_bytes,
   2098                                   PercentOfFileBytes(interned_strings_bytes),
   2099                                   bitmap_bytes, PercentOfFileBytes(bitmap_bytes),
   2100                                   alignment_bytes, PercentOfFileBytes(alignment_bytes))
   2101             << std::flush;
   2102         CHECK_EQ(file_bytes, header_bytes + object_bytes + art_field_bytes + art_method_bytes +
   2103                  interned_strings_bytes + bitmap_bytes + alignment_bytes);
   2104       }
   2105 
   2106       os << "object_bytes breakdown:\n";
   2107       size_t object_bytes_total = 0;
   2108       for (const auto& sizes_and_count : sizes_and_counts) {
   2109         const std::string& descriptor(sizes_and_count.first);
   2110         double average = static_cast<double>(sizes_and_count.second.bytes) /
   2111             static_cast<double>(sizes_and_count.second.count);
   2112         double percent = PercentOfObjectBytes(sizes_and_count.second.bytes);
   2113         os << StringPrintf("%32s %8zd bytes %6zd instances "
   2114                            "(%4.0f bytes/instance) %2.0f%% of object_bytes\n",
   2115                            descriptor.c_str(), sizes_and_count.second.bytes,
   2116                            sizes_and_count.second.count, average, percent);
   2117         object_bytes_total += sizes_and_count.second.bytes;
   2118       }
   2119       os << "\n" << std::flush;
   2120       CHECK_EQ(object_bytes, object_bytes_total);
   2121 
   2122       os << StringPrintf("oat_file_bytes               = %8zd\n"
   2123                          "managed_code_bytes           = %8zd (%2.0f%% of oat file bytes)\n"
   2124                          "managed_to_native_code_bytes = %8zd (%2.0f%% of oat file bytes)\n"
   2125                          "native_to_managed_code_bytes = %8zd (%2.0f%% of oat file bytes)\n\n"
   2126                          "class_initializer_code_bytes = %8zd (%2.0f%% of oat file bytes)\n"
   2127                          "large_initializer_code_bytes = %8zd (%2.0f%% of oat file bytes)\n"
   2128                          "large_method_code_bytes      = %8zd (%2.0f%% of oat file bytes)\n\n",
   2129                          oat_file_bytes,
   2130                          managed_code_bytes,
   2131                          PercentOfOatBytes(managed_code_bytes),
   2132                          managed_to_native_code_bytes,
   2133                          PercentOfOatBytes(managed_to_native_code_bytes),
   2134                          native_to_managed_code_bytes,
   2135                          PercentOfOatBytes(native_to_managed_code_bytes),
   2136                          class_initializer_code_bytes,
   2137                          PercentOfOatBytes(class_initializer_code_bytes),
   2138                          large_initializer_code_bytes,
   2139                          PercentOfOatBytes(large_initializer_code_bytes),
   2140                          large_method_code_bytes,
   2141                          PercentOfOatBytes(large_method_code_bytes))
   2142             << "DexFile sizes:\n";
   2143       for (const std::pair<std::string, size_t>& oat_dex_file_size : oat_dex_file_sizes) {
   2144         os << StringPrintf("%s = %zd (%2.0f%% of oat file bytes)\n",
   2145                            oat_dex_file_size.first.c_str(), oat_dex_file_size.second,
   2146                            PercentOfOatBytes(oat_dex_file_size.second));
   2147       }
   2148 
   2149       os << "\n" << StringPrintf("gc_map_bytes           = %7zd (%2.0f%% of oat file bytes)\n"
   2150                                  "pc_mapping_table_bytes = %7zd (%2.0f%% of oat file bytes)\n"
   2151                                  "vmap_table_bytes       = %7zd (%2.0f%% of oat file bytes)\n\n",
   2152                                  gc_map_bytes, PercentOfOatBytes(gc_map_bytes),
   2153                                  pc_mapping_table_bytes, PercentOfOatBytes(pc_mapping_table_bytes),
   2154                                  vmap_table_bytes, PercentOfOatBytes(vmap_table_bytes))
   2155          << std::flush;
   2156 
   2157       os << StringPrintf("dex_instruction_bytes = %zd\n", dex_instruction_bytes)
   2158          << StringPrintf("managed_code_bytes expansion = %.2f (ignoring deduplication %.2f)\n\n",
   2159                          static_cast<double>(managed_code_bytes) /
   2160                              static_cast<double>(dex_instruction_bytes),
   2161                          static_cast<double>(managed_code_bytes_ignoring_deduplication) /
   2162                              static_cast<double>(dex_instruction_bytes))
   2163          << std::flush;
   2164 
   2165       DumpOutliers(os);
   2166     }
   2167   } stats_;
   2168 
   2169  private:
   2170   enum {
   2171     // Number of bytes for a constructor to be considered large. Based on the 1000 basic block
   2172     // threshold, we assume 2 bytes per instruction and 2 instructions per block.
   2173     kLargeConstructorDexBytes = 4000,
   2174     // Number of bytes for a method to be considered large. Based on the 4000 basic block
   2175     // threshold, we assume 2 bytes per instruction and 2 instructions per block.
   2176     kLargeMethodDexBytes = 16000
   2177   };
   2178   std::ostream* os_;
   2179   gc::space::ImageSpace& image_space_;
   2180   const ImageHeader& image_header_;
   2181   std::unique_ptr<OatDumper> oat_dumper_;
   2182   OatDumperOptions* oat_dumper_options_;
   2183   std::set<mirror::Object*> dex_cache_arrays_;
   2184 
   2185   DISALLOW_COPY_AND_ASSIGN(ImageDumper);
   2186 };
   2187 
   2188 static int DumpImage(Runtime* runtime, const char* image_location, OatDumperOptions* options,
   2189                      std::ostream* os) {
   2190   // Dumping the image, no explicit class loader.
   2191   NullHandle<mirror::ClassLoader> null_class_loader;
   2192   options->class_loader_ = &null_class_loader;
   2193 
   2194   ScopedObjectAccess soa(Thread::Current());
   2195   gc::Heap* heap = runtime->GetHeap();
   2196   gc::space::ImageSpace* image_space = heap->GetImageSpace();
   2197   CHECK(image_space != nullptr);
   2198   const ImageHeader& image_header = image_space->GetImageHeader();
   2199   if (!image_header.IsValid()) {
   2200     fprintf(stderr, "Invalid image header %s\n", image_location);
   2201     return EXIT_FAILURE;
   2202   }
   2203 
   2204   ImageDumper image_dumper(os, *image_space, image_header, options);
   2205 
   2206   bool success = image_dumper.Dump();
   2207   return (success) ? EXIT_SUCCESS : EXIT_FAILURE;
   2208 }
   2209 
   2210 static int DumpOatWithRuntime(Runtime* runtime, OatFile* oat_file, OatDumperOptions* options,
   2211                               std::ostream* os) {
   2212   CHECK(runtime != nullptr && oat_file != nullptr && options != nullptr);
   2213 
   2214   Thread* self = Thread::Current();
   2215   CHECK(self != nullptr);
   2216   // Need well-known-classes.
   2217   WellKnownClasses::Init(self->GetJniEnv());
   2218 
   2219   // Need to register dex files to get a working dex cache.
   2220   ScopedObjectAccess soa(self);
   2221   ClassLinker* class_linker = runtime->GetClassLinker();
   2222   class_linker->RegisterOatFile(oat_file);
   2223   std::vector<std::unique_ptr<const DexFile>> dex_files;
   2224   for (const OatFile::OatDexFile* odf : oat_file->GetOatDexFiles()) {
   2225     std::string error_msg;
   2226     std::unique_ptr<const DexFile> dex_file = odf->OpenDexFile(&error_msg);
   2227     CHECK(dex_file != nullptr) << error_msg;
   2228     class_linker->RegisterDexFile(*dex_file);
   2229     dex_files.push_back(std::move(dex_file));
   2230   }
   2231 
   2232   // Need a class loader.
   2233   // Fake that we're a compiler.
   2234   std::vector<const DexFile*> class_path;
   2235   for (auto& dex_file : dex_files) {
   2236     class_path.push_back(dex_file.get());
   2237   }
   2238   jobject class_loader = class_linker->CreatePathClassLoader(self, class_path);
   2239 
   2240   // Use the class loader while dumping.
   2241   StackHandleScope<1> scope(self);
   2242   Handle<mirror::ClassLoader> loader_handle = scope.NewHandle(
   2243       soa.Decode<mirror::ClassLoader*>(class_loader));
   2244   options->class_loader_ = &loader_handle;
   2245 
   2246   OatDumper oat_dumper(*oat_file, *options);
   2247   bool success = oat_dumper.Dump(*os);
   2248   return (success) ? EXIT_SUCCESS : EXIT_FAILURE;
   2249 }
   2250 
   2251 static int DumpOatWithoutRuntime(OatFile* oat_file, OatDumperOptions* options, std::ostream* os) {
   2252   CHECK(oat_file != nullptr && options != nullptr);
   2253   // No image = no class loader.
   2254   NullHandle<mirror::ClassLoader> null_class_loader;
   2255   options->class_loader_ = &null_class_loader;
   2256 
   2257   OatDumper oat_dumper(*oat_file, *options);
   2258   bool success = oat_dumper.Dump(*os);
   2259   return (success) ? EXIT_SUCCESS : EXIT_FAILURE;
   2260 }
   2261 
   2262 static int DumpOat(Runtime* runtime, const char* oat_filename, OatDumperOptions* options,
   2263                    std::ostream* os) {
   2264   std::string error_msg;
   2265   OatFile* oat_file = OatFile::Open(oat_filename, oat_filename, nullptr, nullptr, false,
   2266                                     nullptr, &error_msg);
   2267   if (oat_file == nullptr) {
   2268     fprintf(stderr, "Failed to open oat file from '%s': %s\n", oat_filename, error_msg.c_str());
   2269     return EXIT_FAILURE;
   2270   }
   2271 
   2272   if (runtime != nullptr) {
   2273     return DumpOatWithRuntime(runtime, oat_file, options, os);
   2274   } else {
   2275     return DumpOatWithoutRuntime(oat_file, options, os);
   2276   }
   2277 }
   2278 
   2279 static int SymbolizeOat(const char* oat_filename, std::string& output_name) {
   2280   std::string error_msg;
   2281   OatFile* oat_file = OatFile::Open(oat_filename, oat_filename, nullptr, nullptr, false,
   2282                                     nullptr, &error_msg);
   2283   if (oat_file == nullptr) {
   2284     fprintf(stderr, "Failed to open oat file from '%s': %s\n", oat_filename, error_msg.c_str());
   2285     return EXIT_FAILURE;
   2286   }
   2287 
   2288   OatSymbolizer oat_symbolizer(oat_file, output_name);
   2289   if (!oat_symbolizer.Symbolize()) {
   2290     fprintf(stderr, "Failed to symbolize\n");
   2291     return EXIT_FAILURE;
   2292   }
   2293 
   2294   return EXIT_SUCCESS;
   2295 }
   2296 
   2297 struct OatdumpArgs : public CmdlineArgs {
   2298  protected:
   2299   using Base = CmdlineArgs;
   2300 
   2301   virtual ParseStatus ParseCustom(const StringPiece& option,
   2302                                   std::string* error_msg) OVERRIDE {
   2303     {
   2304       ParseStatus base_parse = Base::ParseCustom(option, error_msg);
   2305       if (base_parse != kParseUnknownArgument) {
   2306         return base_parse;
   2307       }
   2308     }
   2309 
   2310     if (option.starts_with("--oat-file=")) {
   2311       oat_filename_ = option.substr(strlen("--oat-file=")).data();
   2312     } else if (option.starts_with("--image=")) {
   2313       image_location_ = option.substr(strlen("--image=")).data();
   2314     } else if (option =="--dump:raw_mapping_table") {
   2315       dump_raw_mapping_table_ = true;
   2316     } else if (option == "--dump:raw_gc_map") {
   2317       dump_raw_gc_map_ = true;
   2318     } else if (option == "--no-dump:vmap") {
   2319       dump_vmap_ = false;
   2320     } else if (option == "--no-disassemble") {
   2321       disassemble_code_ = false;
   2322     } else if (option.starts_with("--symbolize=")) {
   2323       oat_filename_ = option.substr(strlen("--symbolize=")).data();
   2324       symbolize_ = true;
   2325     } else if (option.starts_with("--class-filter=")) {
   2326       class_filter_ = option.substr(strlen("--class-filter=")).data();
   2327     } else if (option.starts_with("--method-filter=")) {
   2328       method_filter_ = option.substr(strlen("--method-filter=")).data();
   2329     } else if (option.starts_with("--list-classes")) {
   2330       list_classes_ = true;
   2331     } else if (option.starts_with("--list-methods")) {
   2332       list_methods_ = true;
   2333     } else if (option.starts_with("--export-dex-to=")) {
   2334       export_dex_location_ = option.substr(strlen("--export-dex-to=")).data();
   2335     } else if (option.starts_with("--addr2instr=")) {
   2336       if (!ParseUint(option.substr(strlen("--addr2instr=")).data(), &addr2instr_)) {
   2337         *error_msg = "Address conversion failed";
   2338         return kParseError;
   2339       }
   2340     } else {
   2341       return kParseUnknownArgument;
   2342     }
   2343 
   2344     return kParseOk;
   2345   }
   2346 
   2347   virtual ParseStatus ParseChecks(std::string* error_msg) OVERRIDE {
   2348     // Infer boot image location from the image location if possible.
   2349     if (boot_image_location_ == nullptr) {
   2350       boot_image_location_ = image_location_;
   2351     }
   2352 
   2353     // Perform the parent checks.
   2354     ParseStatus parent_checks = Base::ParseChecks(error_msg);
   2355     if (parent_checks != kParseOk) {
   2356       return parent_checks;
   2357     }
   2358 
   2359     // Perform our own checks.
   2360     if (image_location_ == nullptr && oat_filename_ == nullptr) {
   2361       *error_msg = "Either --image or --oat-file must be specified";
   2362       return kParseError;
   2363     } else if (image_location_ != nullptr && oat_filename_ != nullptr) {
   2364       *error_msg = "Either --image or --oat-file must be specified but not both";
   2365       return kParseError;
   2366     }
   2367 
   2368     return kParseOk;
   2369   }
   2370 
   2371   virtual std::string GetUsage() const {
   2372     std::string usage;
   2373 
   2374     usage +=
   2375         "Usage: oatdump [options] ...\n"
   2376         "    Example: oatdump --image=$ANDROID_PRODUCT_OUT/system/framework/boot.art\n"
   2377         "    Example: adb shell oatdump --image=/system/framework/boot.art\n"
   2378         "\n"
   2379         // Either oat-file or image is required.
   2380         "  --oat-file=<file.oat>: specifies an input oat filename.\n"
   2381         "      Example: --oat-file=/system/framework/boot.oat\n"
   2382         "\n"
   2383         "  --image=<file.art>: specifies an input image location.\n"
   2384         "      Example: --image=/system/framework/boot.art\n"
   2385         "\n";
   2386 
   2387     usage += Base::GetUsage();
   2388 
   2389     usage +=  // Optional.
   2390         "  --dump:raw_mapping_table enables dumping of the mapping table.\n"
   2391         "      Example: --dump:raw_mapping_table\n"
   2392         "\n"
   2393         "  --dump:raw_gc_map enables dumping of the GC map.\n"
   2394         "      Example: --dump:raw_gc_map\n"
   2395         "\n"
   2396         "  --no-dump:vmap may be used to disable vmap dumping.\n"
   2397         "      Example: --no-dump:vmap\n"
   2398         "\n"
   2399         "  --no-disassemble may be used to disable disassembly.\n"
   2400         "      Example: --no-disassemble\n"
   2401         "\n"
   2402         "  --list-classes may be used to list target file classes (can be used with filters).\n"
   2403         "      Example: --list-classes\n"
   2404         "      Example: --list-classes --class-filter=com.example.foo\n"
   2405         "\n"
   2406         "  --list-methods may be used to list target file methods (can be used with filters).\n"
   2407         "      Example: --list-methods\n"
   2408         "      Example: --list-methods --class-filter=com.example --method-filter=foo\n"
   2409         "\n"
   2410         "  --symbolize=<file.oat>: output a copy of file.oat with elf symbols included.\n"
   2411         "      Example: --symbolize=/system/framework/boot.oat\n"
   2412         "\n"
   2413         "  --class-filter=<class name>: only dumps classes that contain the filter.\n"
   2414         "      Example: --class-filter=com.example.foo\n"
   2415         "\n"
   2416         "  --method-filter=<method name>: only dumps methods that contain the filter.\n"
   2417         "      Example: --method-filter=foo\n"
   2418         "\n"
   2419         "  --export-dex-to=<directory>: may be used to export oat embedded dex files.\n"
   2420         "      Example: --export-dex-to=/data/local/tmp\n"
   2421         "\n"
   2422         "  --addr2instr=<address>: output matching method disassembled code from relative\n"
   2423         "                          address (e.g. PC from crash dump)\n"
   2424         "      Example: --addr2instr=0x00001a3b\n"
   2425         "\n";
   2426 
   2427     return usage;
   2428   }
   2429 
   2430  public:
   2431   const char* oat_filename_ = nullptr;
   2432   const char* class_filter_ = "";
   2433   const char* method_filter_ = "";
   2434   const char* image_location_ = nullptr;
   2435   std::string elf_filename_prefix_;
   2436   bool dump_raw_mapping_table_ = false;
   2437   bool dump_raw_gc_map_ = false;
   2438   bool dump_vmap_ = true;
   2439   bool disassemble_code_ = true;
   2440   bool symbolize_ = false;
   2441   bool list_classes_ = false;
   2442   bool list_methods_ = false;
   2443   uint32_t addr2instr_ = 0;
   2444   const char* export_dex_location_ = nullptr;
   2445 };
   2446 
   2447 struct OatdumpMain : public CmdlineMain<OatdumpArgs> {
   2448   virtual bool NeedsRuntime() OVERRIDE {
   2449     CHECK(args_ != nullptr);
   2450 
   2451     // If we are only doing the oat file, disable absolute_addresses. Keep them for image dumping.
   2452     bool absolute_addresses = (args_->oat_filename_ == nullptr);
   2453 
   2454     oat_dumper_options_ = std::unique_ptr<OatDumperOptions>(new OatDumperOptions(
   2455         args_->dump_raw_mapping_table_,
   2456         args_->dump_raw_gc_map_,
   2457         args_->dump_vmap_,
   2458         args_->disassemble_code_,
   2459         absolute_addresses,
   2460         args_->class_filter_,
   2461         args_->method_filter_,
   2462         args_->list_classes_,
   2463         args_->list_methods_,
   2464         args_->export_dex_location_,
   2465         args_->addr2instr_));
   2466 
   2467     return (args_->boot_image_location_ != nullptr || args_->image_location_ != nullptr) &&
   2468           !args_->symbolize_;
   2469   }
   2470 
   2471   virtual bool ExecuteWithoutRuntime() OVERRIDE {
   2472     CHECK(args_ != nullptr);
   2473     CHECK(args_->oat_filename_ != nullptr);
   2474 
   2475     MemMap::Init();
   2476 
   2477     if (args_->symbolize_) {
   2478       return SymbolizeOat(args_->oat_filename_, args_->output_name_) == EXIT_SUCCESS;
   2479     } else {
   2480       return DumpOat(nullptr,
   2481                      args_->oat_filename_,
   2482                      oat_dumper_options_.get(),
   2483                      args_->os_) == EXIT_SUCCESS;
   2484     }
   2485   }
   2486 
   2487   virtual bool ExecuteWithRuntime(Runtime* runtime) {
   2488     CHECK(args_ != nullptr);
   2489 
   2490     if (args_->oat_filename_ != nullptr) {
   2491       return DumpOat(runtime,
   2492                      args_->oat_filename_,
   2493                      oat_dumper_options_.get(),
   2494                      args_->os_) == EXIT_SUCCESS;
   2495     }
   2496 
   2497     return DumpImage(runtime, args_->image_location_, oat_dumper_options_.get(), args_->os_)
   2498       == EXIT_SUCCESS;
   2499   }
   2500 
   2501   std::unique_ptr<OatDumperOptions> oat_dumper_options_;
   2502 };
   2503 
   2504 }  // namespace art
   2505 
   2506 int main(int argc, char** argv) {
   2507   art::OatdumpMain main;
   2508   return main.Main(argc, argv);
   2509 }
   2510