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 <string>
     23 #include <vector>
     24 
     25 #include "base/stringpiece.h"
     26 #include "base/unix_file/fd_file.h"
     27 #include "class_linker.h"
     28 #include "class_linker-inl.h"
     29 #include "dex_file-inl.h"
     30 #include "dex_instruction.h"
     31 #include "disassembler.h"
     32 #include "field_helper.h"
     33 #include "gc_map.h"
     34 #include "gc/space/image_space.h"
     35 #include "gc/space/large_object_space.h"
     36 #include "gc/space/space-inl.h"
     37 #include "image.h"
     38 #include "indenter.h"
     39 #include "mapping_table.h"
     40 #include "mirror/art_field-inl.h"
     41 #include "mirror/art_method-inl.h"
     42 #include "mirror/array-inl.h"
     43 #include "mirror/class-inl.h"
     44 #include "mirror/object-inl.h"
     45 #include "mirror/object_array-inl.h"
     46 #include "noop_compiler_callbacks.h"
     47 #include "oat.h"
     48 #include "oat_file-inl.h"
     49 #include "os.h"
     50 #include "runtime.h"
     51 #include "safe_map.h"
     52 #include "scoped_thread_state_change.h"
     53 #include "thread_list.h"
     54 #include "verifier/dex_gc_map.h"
     55 #include "verifier/method_verifier.h"
     56 #include "vmap_table.h"
     57 
     58 namespace art {
     59 
     60 static void usage() {
     61   fprintf(stderr,
     62           "Usage: oatdump [options] ...\n"
     63           "    Example: oatdump --image=$ANDROID_PRODUCT_OUT/system/framework/boot.art\n"
     64           "    Example: adb shell oatdump --image=/system/framework/boot.art\n"
     65           "\n");
     66   fprintf(stderr,
     67           "  --oat-file=<file.oat>: specifies an input oat filename.\n"
     68           "      Example: --oat-file=/system/framework/boot.oat\n"
     69           "\n");
     70   fprintf(stderr,
     71           "  --image=<file.art>: specifies an input image filename.\n"
     72           "      Example: --image=/system/framework/boot.art\n"
     73           "\n");
     74   fprintf(stderr,
     75           "  --boot-image=<file.art>: provide the image file for the boot class path.\n"
     76           "      Example: --boot-image=/system/framework/boot.art\n"
     77           "\n");
     78   fprintf(stderr,
     79           "  --instruction-set=(arm|arm64|mips|x86|x86_64): for locating the image\n"
     80           "      file based on the image location set.\n"
     81           "      Example: --instruction-set=x86\n"
     82           "      Default: %s\n"
     83           "\n",
     84           GetInstructionSetString(kRuntimeISA));
     85   fprintf(stderr,
     86           "  --output=<file> may be used to send the output to a file.\n"
     87           "      Example: --output=/tmp/oatdump.txt\n"
     88           "\n");
     89   fprintf(stderr,
     90           "  --dump:raw_mapping_table enables dumping of the mapping table.\n"
     91           "      Example: --dump:raw_mapping_table\n"
     92           "\n");
     93   fprintf(stderr,
     94           "  --dump:raw_mapping_table enables dumping of the GC map.\n"
     95           "      Example: --dump:raw_gc_map\n"
     96           "\n");
     97   fprintf(stderr,
     98           "  --no-dump:vmap may be used to disable vmap dumping.\n"
     99           "      Example: --no-dump:vmap\n"
    100           "\n");
    101   fprintf(stderr,
    102           "  --no-disassemble may be used to disable disassembly.\n"
    103           "      Example: --no-disassemble\n"
    104           "\n");
    105   exit(EXIT_FAILURE);
    106 }
    107 
    108 const char* image_roots_descriptions_[] = {
    109   "kResolutionMethod",
    110   "kImtConflictMethod",
    111   "kImtUnimplementedMethod",
    112   "kDefaultImt",
    113   "kCalleeSaveMethod",
    114   "kRefsOnlySaveMethod",
    115   "kRefsAndArgsSaveMethod",
    116   "kDexCaches",
    117   "kClassRoots",
    118 };
    119 
    120 class OatDumperOptions {
    121  public:
    122   OatDumperOptions(bool dump_raw_mapping_table,
    123                    bool dump_raw_gc_map,
    124                    bool dump_vmap,
    125                    bool disassemble_code,
    126                    bool absolute_addresses)
    127     : dump_raw_mapping_table_(dump_raw_mapping_table),
    128       dump_raw_gc_map_(dump_raw_gc_map),
    129       dump_vmap_(dump_vmap),
    130       disassemble_code_(disassemble_code),
    131       absolute_addresses_(absolute_addresses) {}
    132 
    133   const bool dump_raw_mapping_table_;
    134   const bool dump_raw_gc_map_;
    135   const bool dump_vmap_;
    136   const bool disassemble_code_;
    137   const bool absolute_addresses_;
    138 };
    139 
    140 class OatDumper {
    141  public:
    142   explicit OatDumper(const OatFile& oat_file, OatDumperOptions* options)
    143     : oat_file_(oat_file),
    144       oat_dex_files_(oat_file.GetOatDexFiles()),
    145       options_(options),
    146       instruction_set_(oat_file_.GetOatHeader().GetInstructionSet()),
    147       disassembler_(Disassembler::Create(instruction_set_,
    148                                          new DisassemblerOptions(options_->absolute_addresses_,
    149                                                                  oat_file.Begin()))) {
    150     AddAllOffsets();
    151   }
    152 
    153   ~OatDumper() {
    154     delete options_;
    155     delete disassembler_;
    156   }
    157 
    158   InstructionSet GetInstructionSet() {
    159     return instruction_set_;
    160   }
    161 
    162   bool Dump(std::ostream& os) {
    163     bool success = true;
    164     const OatHeader& oat_header = oat_file_.GetOatHeader();
    165 
    166     os << "MAGIC:\n";
    167     os << oat_header.GetMagic() << "\n\n";
    168 
    169     os << "CHECKSUM:\n";
    170     os << StringPrintf("0x%08x\n\n", oat_header.GetChecksum());
    171 
    172     os << "INSTRUCTION SET:\n";
    173     os << oat_header.GetInstructionSet() << "\n\n";
    174 
    175     os << "INSTRUCTION SET FEATURES:\n";
    176     os << oat_header.GetInstructionSetFeatures().GetFeatureString() << "\n\n";
    177 
    178     os << "DEX FILE COUNT:\n";
    179     os << oat_header.GetDexFileCount() << "\n\n";
    180 
    181 #define DUMP_OAT_HEADER_OFFSET(label, offset) \
    182     os << label " OFFSET:\n"; \
    183     os << StringPrintf("0x%08x", oat_header.offset()); \
    184     if (oat_header.offset() != 0 && options_->absolute_addresses_) { \
    185       os << StringPrintf(" (%p)", oat_file_.Begin() + oat_header.offset()); \
    186     } \
    187     os << StringPrintf("\n\n");
    188 
    189     DUMP_OAT_HEADER_OFFSET("EXECUTABLE", GetExecutableOffset);
    190     DUMP_OAT_HEADER_OFFSET("INTERPRETER TO INTERPRETER BRIDGE",
    191                            GetInterpreterToInterpreterBridgeOffset);
    192     DUMP_OAT_HEADER_OFFSET("INTERPRETER TO COMPILED CODE BRIDGE",
    193                            GetInterpreterToCompiledCodeBridgeOffset);
    194     DUMP_OAT_HEADER_OFFSET("JNI DLSYM LOOKUP",
    195                            GetJniDlsymLookupOffset);
    196     DUMP_OAT_HEADER_OFFSET("PORTABLE IMT CONFLICT TRAMPOLINE",
    197                            GetPortableImtConflictTrampolineOffset);
    198     DUMP_OAT_HEADER_OFFSET("PORTABLE RESOLUTION TRAMPOLINE",
    199                            GetPortableResolutionTrampolineOffset);
    200     DUMP_OAT_HEADER_OFFSET("PORTABLE TO INTERPRETER BRIDGE",
    201                            GetPortableToInterpreterBridgeOffset);
    202     DUMP_OAT_HEADER_OFFSET("QUICK GENERIC JNI TRAMPOLINE",
    203                            GetQuickGenericJniTrampolineOffset);
    204     DUMP_OAT_HEADER_OFFSET("QUICK IMT CONFLICT TRAMPOLINE",
    205                            GetQuickImtConflictTrampolineOffset);
    206     DUMP_OAT_HEADER_OFFSET("QUICK RESOLUTION TRAMPOLINE",
    207                            GetQuickResolutionTrampolineOffset);
    208     DUMP_OAT_HEADER_OFFSET("QUICK TO INTERPRETER BRIDGE",
    209                            GetQuickToInterpreterBridgeOffset);
    210 #undef DUMP_OAT_HEADER_OFFSET
    211 
    212     os << "IMAGE PATCH DELTA:\n";
    213     os << StringPrintf("%d (0x%08x)\n\n",
    214                        oat_header.GetImagePatchDelta(),
    215                        oat_header.GetImagePatchDelta());
    216 
    217     os << "IMAGE FILE LOCATION OAT CHECKSUM:\n";
    218     os << StringPrintf("0x%08x\n\n", oat_header.GetImageFileLocationOatChecksum());
    219 
    220     os << "IMAGE FILE LOCATION OAT BEGIN:\n";
    221     os << StringPrintf("0x%08x\n\n", oat_header.GetImageFileLocationOatDataBegin());
    222 
    223     // Print the key-value store.
    224     {
    225       os << "KEY VALUE STORE:\n";
    226       size_t index = 0;
    227       const char* key;
    228       const char* value;
    229       while (oat_header.GetStoreKeyValuePairByIndex(index, &key, &value)) {
    230         os << key << " = " << value << "\n";
    231         index++;
    232       }
    233       os << "\n";
    234     }
    235 
    236     if (options_->absolute_addresses_) {
    237       os << "BEGIN:\n";
    238       os << reinterpret_cast<const void*>(oat_file_.Begin()) << "\n\n";
    239 
    240       os << "END:\n";
    241       os << reinterpret_cast<const void*>(oat_file_.End()) << "\n\n";
    242     }
    243 
    244     os << "SIZE:\n";
    245     os << oat_file_.Size() << "\n\n";
    246 
    247     os << std::flush;
    248 
    249     for (size_t i = 0; i < oat_dex_files_.size(); i++) {
    250       const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
    251       CHECK(oat_dex_file != nullptr);
    252       if (!DumpOatDexFile(os, *oat_dex_file)) {
    253         success = false;
    254       }
    255     }
    256     os << std::flush;
    257     return success;
    258   }
    259 
    260   size_t ComputeSize(const void* oat_data) {
    261     if (reinterpret_cast<const byte*>(oat_data) < oat_file_.Begin() ||
    262         reinterpret_cast<const byte*>(oat_data) > oat_file_.End()) {
    263       return 0;  // Address not in oat file
    264     }
    265     uintptr_t begin_offset = reinterpret_cast<uintptr_t>(oat_data) -
    266                              reinterpret_cast<uintptr_t>(oat_file_.Begin());
    267     auto it = offsets_.upper_bound(begin_offset);
    268     CHECK(it != offsets_.end());
    269     uintptr_t end_offset = *it;
    270     return end_offset - begin_offset;
    271   }
    272 
    273   InstructionSet GetOatInstructionSet() {
    274     return oat_file_.GetOatHeader().GetInstructionSet();
    275   }
    276 
    277   const void* GetQuickOatCode(mirror::ArtMethod* m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    278     for (size_t i = 0; i < oat_dex_files_.size(); i++) {
    279       const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
    280       CHECK(oat_dex_file != nullptr);
    281       std::string error_msg;
    282       std::unique_ptr<const DexFile> dex_file(oat_dex_file->OpenDexFile(&error_msg));
    283       if (dex_file.get() == nullptr) {
    284         LOG(WARNING) << "Failed to open dex file '" << oat_dex_file->GetDexFileLocation()
    285             << "': " << error_msg;
    286       } else {
    287         const char* descriptor = m->GetDeclaringClassDescriptor();
    288         const DexFile::ClassDef* class_def =
    289             dex_file->FindClassDef(descriptor, ComputeModifiedUtf8Hash(descriptor));
    290         if (class_def != nullptr) {
    291           uint16_t class_def_index = dex_file->GetIndexForClassDef(*class_def);
    292           const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index);
    293           size_t method_index = m->GetMethodIndex();
    294           return oat_class.GetOatMethod(method_index).GetQuickCode();
    295         }
    296       }
    297     }
    298     return nullptr;
    299   }
    300 
    301  private:
    302   void AddAllOffsets() {
    303     // We don't know the length of the code for each method, but we need to know where to stop
    304     // when disassembling. What we do know is that a region of code will be followed by some other
    305     // region, so if we keep a sorted sequence of the start of each region, we can infer the length
    306     // of a piece of code by using upper_bound to find the start of the next region.
    307     for (size_t i = 0; i < oat_dex_files_.size(); i++) {
    308       const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
    309       CHECK(oat_dex_file != nullptr);
    310       std::string error_msg;
    311       std::unique_ptr<const DexFile> dex_file(oat_dex_file->OpenDexFile(&error_msg));
    312       if (dex_file.get() == nullptr) {
    313         LOG(WARNING) << "Failed to open dex file '" << oat_dex_file->GetDexFileLocation()
    314             << "': " << error_msg;
    315         continue;
    316       }
    317       offsets_.insert(reinterpret_cast<uintptr_t>(&dex_file->GetHeader()));
    318       for (size_t class_def_index = 0;
    319            class_def_index < dex_file->NumClassDefs();
    320            class_def_index++) {
    321         const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
    322         const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index);
    323         const byte* class_data = dex_file->GetClassData(class_def);
    324         if (class_data != nullptr) {
    325           ClassDataItemIterator it(*dex_file, class_data);
    326           SkipAllFields(it);
    327           uint32_t class_method_index = 0;
    328           while (it.HasNextDirectMethod()) {
    329             AddOffsets(oat_class.GetOatMethod(class_method_index++));
    330             it.Next();
    331           }
    332           while (it.HasNextVirtualMethod()) {
    333             AddOffsets(oat_class.GetOatMethod(class_method_index++));
    334             it.Next();
    335           }
    336         }
    337       }
    338     }
    339 
    340     // If the last thing in the file is code for a method, there won't be an offset for the "next"
    341     // thing. Instead of having a special case in the upper_bound code, let's just add an entry
    342     // for the end of the file.
    343     offsets_.insert(oat_file_.Size());
    344   }
    345 
    346   static uint32_t AlignCodeOffset(uint32_t maybe_thumb_offset) {
    347     return maybe_thumb_offset & ~0x1;  // TODO: Make this Thumb2 specific.
    348   }
    349 
    350   void AddOffsets(const OatFile::OatMethod& oat_method) {
    351     uint32_t code_offset = oat_method.GetCodeOffset();
    352     if (oat_file_.GetOatHeader().GetInstructionSet() == kThumb2) {
    353       code_offset &= ~0x1;
    354     }
    355     offsets_.insert(code_offset);
    356     offsets_.insert(oat_method.GetMappingTableOffset());
    357     offsets_.insert(oat_method.GetVmapTableOffset());
    358     offsets_.insert(oat_method.GetGcMapOffset());
    359   }
    360 
    361   bool DumpOatDexFile(std::ostream& os, const OatFile::OatDexFile& oat_dex_file) {
    362     bool success = true;
    363     os << "OatDexFile:\n";
    364     os << StringPrintf("location: %s\n", oat_dex_file.GetDexFileLocation().c_str());
    365     os << StringPrintf("checksum: 0x%08x\n", oat_dex_file.GetDexFileLocationChecksum());
    366 
    367     // Create the verifier early.
    368 
    369     std::string error_msg;
    370     std::unique_ptr<const DexFile> dex_file(oat_dex_file.OpenDexFile(&error_msg));
    371     if (dex_file.get() == nullptr) {
    372       os << "NOT FOUND: " << error_msg << "\n\n";
    373       os << std::flush;
    374       return false;
    375     }
    376     for (size_t class_def_index = 0;
    377          class_def_index < dex_file->NumClassDefs();
    378          class_def_index++) {
    379       const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
    380       const char* descriptor = dex_file->GetClassDescriptor(class_def);
    381       uint32_t oat_class_offset = oat_dex_file.GetOatClassOffset(class_def_index);
    382       const OatFile::OatClass oat_class = oat_dex_file.GetOatClass(class_def_index);
    383       os << StringPrintf("%zd: %s (offset=0x%08x) (type_idx=%d)",
    384                          class_def_index, descriptor, oat_class_offset, class_def.class_idx_)
    385          << " (" << oat_class.GetStatus() << ")"
    386          << " (" << oat_class.GetType() << ")\n";
    387       // TODO: include bitmap here if type is kOatClassSomeCompiled?
    388       Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
    389       std::ostream indented_os(&indent_filter);
    390       if (!DumpOatClass(indented_os, oat_class, *(dex_file.get()), class_def)) {
    391         success = false;
    392       }
    393     }
    394 
    395     os << std::flush;
    396     return success;
    397   }
    398 
    399   static void SkipAllFields(ClassDataItemIterator& it) {
    400     while (it.HasNextStaticField()) {
    401       it.Next();
    402     }
    403     while (it.HasNextInstanceField()) {
    404       it.Next();
    405     }
    406   }
    407 
    408   bool DumpOatClass(std::ostream& os, const OatFile::OatClass& oat_class, const DexFile& dex_file,
    409                     const DexFile::ClassDef& class_def) {
    410     bool success = true;
    411     const byte* class_data = dex_file.GetClassData(class_def);
    412     if (class_data == nullptr) {  // empty class such as a marker interface?
    413       os << std::flush;
    414       return success;
    415     }
    416     ClassDataItemIterator it(dex_file, class_data);
    417     SkipAllFields(it);
    418     uint32_t class_method_index = 0;
    419     while (it.HasNextDirectMethod()) {
    420       if (!DumpOatMethod(os, class_def, class_method_index, oat_class, dex_file,
    421                          it.GetMemberIndex(), it.GetMethodCodeItem(),
    422                          it.GetRawMemberAccessFlags())) {
    423         success = false;
    424       }
    425       class_method_index++;
    426       it.Next();
    427     }
    428     while (it.HasNextVirtualMethod()) {
    429       if (!DumpOatMethod(os, class_def, class_method_index, oat_class, dex_file,
    430                          it.GetMemberIndex(), it.GetMethodCodeItem(),
    431                          it.GetRawMemberAccessFlags())) {
    432         success = false;
    433       }
    434       class_method_index++;
    435       it.Next();
    436     }
    437     DCHECK(!it.HasNext());
    438     os << std::flush;
    439     return success;
    440   }
    441 
    442   static constexpr uint32_t kPrologueBytes = 16;
    443 
    444   // When this was picked, the largest arm method was 55,256 bytes and arm64 was 50,412 bytes.
    445   static constexpr uint32_t kMaxCodeSize = 100 * 1000;
    446 
    447   bool DumpOatMethod(std::ostream& os, const DexFile::ClassDef& class_def,
    448                      uint32_t class_method_index,
    449                      const OatFile::OatClass& oat_class, const DexFile& dex_file,
    450                      uint32_t dex_method_idx, const DexFile::CodeItem* code_item,
    451                      uint32_t method_access_flags) {
    452     bool success = true;
    453     os << StringPrintf("%d: %s (dex_method_idx=%d)\n",
    454                        class_method_index, PrettyMethod(dex_method_idx, dex_file, true).c_str(),
    455                        dex_method_idx);
    456     Indenter indent1_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
    457     std::unique_ptr<std::ostream> indent1_os(new std::ostream(&indent1_filter));
    458     Indenter indent2_filter(indent1_os->rdbuf(), kIndentChar, kIndentBy1Count);
    459     std::unique_ptr<std::ostream> indent2_os(new std::ostream(&indent2_filter));
    460     {
    461       *indent1_os << "DEX CODE:\n";
    462       DumpDexCode(*indent2_os, dex_file, code_item);
    463     }
    464 
    465     std::unique_ptr<verifier::MethodVerifier> verifier;
    466     if (Runtime::Current() != nullptr) {
    467       *indent1_os << "VERIFIER TYPE ANALYSIS:\n";
    468       verifier.reset(DumpVerifier(*indent2_os, dex_method_idx, &dex_file, class_def, code_item,
    469                                   method_access_flags));
    470     }
    471 
    472     uint32_t oat_method_offsets_offset = oat_class.GetOatMethodOffsetsOffset(class_method_index);
    473     const OatMethodOffsets* oat_method_offsets = oat_class.GetOatMethodOffsets(class_method_index);
    474     const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_index);
    475     {
    476       *indent1_os << "OatMethodOffsets ";
    477       if (options_->absolute_addresses_) {
    478         *indent1_os << StringPrintf("%p ", oat_method_offsets);
    479       }
    480       *indent1_os << StringPrintf("(offset=0x%08x)\n", oat_method_offsets_offset);
    481       if (oat_method_offsets_offset > oat_file_.Size()) {
    482         *indent1_os << StringPrintf(
    483             "WARNING: oat method offsets offset 0x%08x is past end of file 0x%08zx.\n",
    484             oat_method_offsets_offset, oat_file_.Size());
    485         // If we can't read OatMethodOffsets, the rest of the data is dangerous to read.
    486         os << std::flush;
    487         return false;
    488       }
    489 
    490       uint32_t code_offset = oat_method.GetCodeOffset();
    491       *indent2_os << StringPrintf("code_offset: 0x%08x ", code_offset);
    492       uint32_t aligned_code_begin = AlignCodeOffset(oat_method.GetCodeOffset());
    493       if (aligned_code_begin > oat_file_.Size()) {
    494         *indent2_os << StringPrintf("WARNING: "
    495                                     "code offset 0x%08x is past end of file 0x%08zx.\n",
    496                                     aligned_code_begin, oat_file_.Size());
    497         success = false;
    498       }
    499       *indent2_os << "\n";
    500 
    501       *indent2_os << "gc_map: ";
    502       if (options_->absolute_addresses_) {
    503         *indent2_os << StringPrintf("%p ", oat_method.GetGcMap());
    504       }
    505       uint32_t gc_map_offset = oat_method.GetGcMapOffset();
    506       *indent2_os << StringPrintf("(offset=0x%08x)\n", gc_map_offset);
    507       if (gc_map_offset > oat_file_.Size()) {
    508         *indent2_os << StringPrintf("WARNING: "
    509                                     "gc map table offset 0x%08x is past end of file 0x%08zx.\n",
    510                                     gc_map_offset, oat_file_.Size());
    511         success = false;
    512       } else if (options_->dump_raw_gc_map_) {
    513         Indenter indent3_filter(indent2_os->rdbuf(), kIndentChar, kIndentBy1Count);
    514         std::ostream indent3_os(&indent3_filter);
    515         DumpGcMap(indent3_os, oat_method, code_item);
    516       }
    517     }
    518     {
    519       *indent1_os << "OatQuickMethodHeader ";
    520       uint32_t method_header_offset = oat_method.GetOatQuickMethodHeaderOffset();
    521       const OatQuickMethodHeader* method_header = oat_method.GetOatQuickMethodHeader();
    522 
    523       if (options_->absolute_addresses_) {
    524         *indent1_os << StringPrintf("%p ", method_header);
    525       }
    526       *indent1_os << StringPrintf("(offset=0x%08x)\n", method_header_offset);
    527       if (method_header_offset > oat_file_.Size()) {
    528         *indent1_os << StringPrintf(
    529             "WARNING: oat quick method header offset 0x%08x is past end of file 0x%08zx.\n",
    530             method_header_offset, oat_file_.Size());
    531         // If we can't read the OatQuickMethodHeader, the rest of the data is dangerous to read.
    532         os << std::flush;
    533         return false;
    534       }
    535 
    536       *indent2_os << "mapping_table: ";
    537       if (options_->absolute_addresses_) {
    538         *indent2_os << StringPrintf("%p ", oat_method.GetMappingTable());
    539       }
    540       uint32_t mapping_table_offset = oat_method.GetMappingTableOffset();
    541       *indent2_os << StringPrintf("(offset=0x%08x)\n", oat_method.GetMappingTableOffset());
    542       if (mapping_table_offset > oat_file_.Size()) {
    543         *indent2_os << StringPrintf("WARNING: "
    544                                     "mapping table offset 0x%08x is past end of file 0x%08zx. "
    545                                     "mapping table offset was loaded from offset 0x%08x.\n",
    546                                     mapping_table_offset, oat_file_.Size(),
    547                                     oat_method.GetMappingTableOffsetOffset());
    548         success = false;
    549       } else if (options_->dump_raw_mapping_table_) {
    550         Indenter indent3_filter(indent2_os->rdbuf(), kIndentChar, kIndentBy1Count);
    551         std::ostream indent3_os(&indent3_filter);
    552         DumpMappingTable(indent3_os, oat_method);
    553       }
    554 
    555       *indent2_os << "vmap_table: ";
    556       if (options_->absolute_addresses_) {
    557         *indent2_os << StringPrintf("%p ", oat_method.GetVmapTable());
    558       }
    559       uint32_t vmap_table_offset = oat_method.GetVmapTableOffset();
    560       *indent2_os << StringPrintf("(offset=0x%08x)\n", vmap_table_offset);
    561       if (vmap_table_offset > oat_file_.Size()) {
    562         *indent2_os << StringPrintf("WARNING: "
    563                                     "vmap table offset 0x%08x is past end of file 0x%08zx. "
    564                                     "vmap table offset was loaded from offset 0x%08x.\n",
    565                                     vmap_table_offset, oat_file_.Size(),
    566                                     oat_method.GetVmapTableOffsetOffset());
    567         success = false;
    568       } else if (options_->dump_vmap_) {
    569         DumpVmap(*indent2_os, oat_method);
    570       }
    571     }
    572     {
    573       *indent1_os << "QuickMethodFrameInfo\n";
    574 
    575       *indent2_os << StringPrintf("frame_size_in_bytes: %zd\n", oat_method.GetFrameSizeInBytes());
    576       *indent2_os << StringPrintf("core_spill_mask: 0x%08x ", oat_method.GetCoreSpillMask());
    577       DumpSpillMask(*indent2_os, oat_method.GetCoreSpillMask(), false);
    578       *indent2_os << "\n";
    579       *indent2_os << StringPrintf("fp_spill_mask: 0x%08x ", oat_method.GetFpSpillMask());
    580       DumpSpillMask(*indent2_os, oat_method.GetFpSpillMask(), true);
    581       *indent2_os << "\n";
    582     }
    583     {
    584       *indent1_os << "CODE: ";
    585       uint32_t code_size_offset = oat_method.GetQuickCodeSizeOffset();
    586       if (code_size_offset > oat_file_.Size()) {
    587         *indent2_os << StringPrintf("WARNING: "
    588                                     "code size offset 0x%08x is past end of file 0x%08zx.",
    589                                     code_size_offset, oat_file_.Size());
    590         success = false;
    591       } else {
    592         const void* code = oat_method.GetQuickCode();
    593         uint32_t code_size = oat_method.GetQuickCodeSize();
    594         if (code == nullptr) {
    595           code = oat_method.GetPortableCode();
    596           code_size = oat_method.GetPortableCodeSize();
    597           code_size_offset = 0;
    598         }
    599         uint32_t code_offset = oat_method.GetCodeOffset();
    600         uint32_t aligned_code_begin = AlignCodeOffset(code_offset);
    601         uint64_t aligned_code_end = aligned_code_begin + code_size;
    602 
    603         if (options_->absolute_addresses_) {
    604           *indent1_os << StringPrintf("%p ", code);
    605         }
    606         *indent1_os << StringPrintf("(code_offset=0x%08x size_offset=0x%08x size=%u)%s\n",
    607                                     code_offset,
    608                                     code_size_offset,
    609                                     code_size,
    610                                     code != nullptr ? "..." : "");
    611 
    612         if (aligned_code_begin > oat_file_.Size()) {
    613           *indent2_os << StringPrintf("WARNING: "
    614                                       "start of code at 0x%08x is past end of file 0x%08zx.",
    615                                       aligned_code_begin, oat_file_.Size());
    616           success = false;
    617         } else if (aligned_code_end > oat_file_.Size()) {
    618           *indent2_os << StringPrintf("WARNING: "
    619                                       "end of code at 0x%08" PRIx64 " is past end of file 0x%08zx. "
    620                                       "code size is 0x%08x loaded from offset 0x%08x.\n",
    621                                       aligned_code_end, oat_file_.Size(),
    622                                       code_size, code_size_offset);
    623           success = false;
    624           if (options_->disassemble_code_) {
    625             if (code_size_offset + kPrologueBytes <= oat_file_.Size()) {
    626               DumpCode(*indent2_os, verifier.get(), oat_method, code_item, true, kPrologueBytes);
    627             }
    628           }
    629         } else if (code_size > kMaxCodeSize) {
    630           *indent2_os << StringPrintf("WARNING: "
    631                                       "code size %d is bigger than max expected threshold of %d. "
    632                                       "code size is 0x%08x loaded from offset 0x%08x.\n",
    633                                       code_size, kMaxCodeSize,
    634                                       code_size, code_size_offset);
    635           success = false;
    636           if (options_->disassemble_code_) {
    637             if (code_size_offset + kPrologueBytes <= oat_file_.Size()) {
    638               DumpCode(*indent2_os, verifier.get(), oat_method, code_item, true, kPrologueBytes);
    639             }
    640           }
    641         } else if (options_->disassemble_code_) {
    642           DumpCode(*indent2_os, verifier.get(), oat_method, code_item, !success, 0);
    643         }
    644       }
    645     }
    646     os << std::flush;
    647     return success;
    648   }
    649 
    650   void DumpSpillMask(std::ostream& os, uint32_t spill_mask, bool is_float) {
    651     if (spill_mask == 0) {
    652       return;
    653     }
    654     os << "(";
    655     for (size_t i = 0; i < 32; i++) {
    656       if ((spill_mask & (1 << i)) != 0) {
    657         if (is_float) {
    658           os << "fr" << i;
    659         } else {
    660           os << "r" << i;
    661         }
    662         spill_mask ^= 1 << i;  // clear bit
    663         if (spill_mask != 0) {
    664           os << ", ";
    665         } else {
    666           break;
    667         }
    668       }
    669     }
    670     os << ")";
    671   }
    672 
    673   void DumpVmap(std::ostream& os, const OatFile::OatMethod& oat_method) {
    674     const uint8_t* raw_table = oat_method.GetVmapTable();
    675     if (raw_table != nullptr) {
    676       const VmapTable vmap_table(raw_table);
    677       bool first = true;
    678       bool processing_fp = false;
    679       uint32_t spill_mask = oat_method.GetCoreSpillMask();
    680       for (size_t i = 0; i < vmap_table.Size(); i++) {
    681         uint16_t dex_reg = vmap_table[i];
    682         uint32_t cpu_reg = vmap_table.ComputeRegister(spill_mask, i,
    683                                                       processing_fp ? kFloatVReg : kIntVReg);
    684         os << (first ? "v" : ", v")  << dex_reg;
    685         if (!processing_fp) {
    686           os << "/r" << cpu_reg;
    687         } else {
    688           os << "/fr" << cpu_reg;
    689         }
    690         first = false;
    691         if (!processing_fp && dex_reg == 0xFFFF) {
    692           processing_fp = true;
    693           spill_mask = oat_method.GetFpSpillMask();
    694         }
    695       }
    696       os << "\n";
    697     }
    698   }
    699 
    700   void DescribeVReg(std::ostream& os, const OatFile::OatMethod& oat_method,
    701                     const DexFile::CodeItem* code_item, size_t reg, VRegKind kind) {
    702     const uint8_t* raw_table = oat_method.GetVmapTable();
    703     if (raw_table != nullptr) {
    704       const VmapTable vmap_table(raw_table);
    705       uint32_t vmap_offset;
    706       if (vmap_table.IsInContext(reg, kind, &vmap_offset)) {
    707         bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg);
    708         uint32_t spill_mask = is_float ? oat_method.GetFpSpillMask()
    709                                        : oat_method.GetCoreSpillMask();
    710         os << (is_float ? "fr" : "r") << vmap_table.ComputeRegister(spill_mask, vmap_offset, kind);
    711       } else {
    712         uint32_t offset = StackVisitor::GetVRegOffset(code_item, oat_method.GetCoreSpillMask(),
    713                                                       oat_method.GetFpSpillMask(),
    714                                                       oat_method.GetFrameSizeInBytes(), reg,
    715                                                       GetInstructionSet());
    716         os << "[sp + #" << offset << "]";
    717       }
    718     }
    719   }
    720 
    721   void DumpGcMapRegisters(std::ostream& os, const OatFile::OatMethod& oat_method,
    722                           const DexFile::CodeItem* code_item,
    723                           size_t num_regs, const uint8_t* reg_bitmap) {
    724     bool first = true;
    725     for (size_t reg = 0; reg < num_regs; reg++) {
    726       if (((reg_bitmap[reg / 8] >> (reg % 8)) & 0x01) != 0) {
    727         if (first) {
    728           os << "  v" << reg << " (";
    729           DescribeVReg(os, oat_method, code_item, reg, kReferenceVReg);
    730           os << ")";
    731           first = false;
    732         } else {
    733           os << ", v" << reg << " (";
    734           DescribeVReg(os, oat_method, code_item, reg, kReferenceVReg);
    735           os << ")";
    736         }
    737       }
    738     }
    739     if (first) {
    740       os << "No registers in GC map\n";
    741     } else {
    742       os << "\n";
    743     }
    744   }
    745   void DumpGcMap(std::ostream& os, const OatFile::OatMethod& oat_method,
    746                  const DexFile::CodeItem* code_item) {
    747     const uint8_t* gc_map_raw = oat_method.GetGcMap();
    748     if (gc_map_raw == nullptr) {
    749       return;  // No GC map.
    750     }
    751     const void* quick_code = oat_method.GetQuickCode();
    752     if (quick_code != nullptr) {
    753       NativePcOffsetToReferenceMap map(gc_map_raw);
    754       for (size_t entry = 0; entry < map.NumEntries(); entry++) {
    755         const uint8_t* native_pc = reinterpret_cast<const uint8_t*>(quick_code) +
    756             map.GetNativePcOffset(entry);
    757         os << StringPrintf("%p", native_pc);
    758         DumpGcMapRegisters(os, oat_method, code_item, map.RegWidth() * 8, map.GetBitMap(entry));
    759       }
    760     } else {
    761       const void* portable_code = oat_method.GetPortableCode();
    762       CHECK(portable_code != nullptr);
    763       verifier::DexPcToReferenceMap map(gc_map_raw);
    764       for (size_t entry = 0; entry < map.NumEntries(); entry++) {
    765         uint32_t dex_pc = map.GetDexPc(entry);
    766         os << StringPrintf("0x%08x", dex_pc);
    767         DumpGcMapRegisters(os, oat_method, code_item, map.RegWidth() * 8, map.GetBitMap(entry));
    768       }
    769     }
    770   }
    771 
    772   void DumpMappingTable(std::ostream& os, const OatFile::OatMethod& oat_method) {
    773     const void* quick_code = oat_method.GetQuickCode();
    774     if (quick_code == nullptr) {
    775       return;
    776     }
    777     MappingTable table(oat_method.GetMappingTable());
    778     if (table.TotalSize() != 0) {
    779       Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
    780       std::ostream indent_os(&indent_filter);
    781       if (table.PcToDexSize() != 0) {
    782         typedef MappingTable::PcToDexIterator It;
    783         os << "suspend point mappings {\n";
    784         for (It cur = table.PcToDexBegin(), end = table.PcToDexEnd(); cur != end; ++cur) {
    785           indent_os << StringPrintf("0x%04x -> 0x%04x\n", cur.NativePcOffset(), cur.DexPc());
    786         }
    787         os << "}\n";
    788       }
    789       if (table.DexToPcSize() != 0) {
    790         typedef MappingTable::DexToPcIterator It;
    791         os << "catch entry mappings {\n";
    792         for (It cur = table.DexToPcBegin(), end = table.DexToPcEnd(); cur != end; ++cur) {
    793           indent_os << StringPrintf("0x%04x -> 0x%04x\n", cur.NativePcOffset(), cur.DexPc());
    794         }
    795         os << "}\n";
    796       }
    797     }
    798   }
    799 
    800   uint32_t DumpMappingAtOffset(std::ostream& os, const OatFile::OatMethod& oat_method,
    801                                size_t offset, bool suspend_point_mapping) {
    802     MappingTable table(oat_method.GetMappingTable());
    803     if (suspend_point_mapping && table.PcToDexSize() > 0) {
    804       typedef MappingTable::PcToDexIterator It;
    805       for (It cur = table.PcToDexBegin(), end = table.PcToDexEnd(); cur != end; ++cur) {
    806         if (offset == cur.NativePcOffset()) {
    807           os << StringPrintf("suspend point dex PC: 0x%04x\n", cur.DexPc());
    808           return cur.DexPc();
    809         }
    810       }
    811     } else if (!suspend_point_mapping && table.DexToPcSize() > 0) {
    812       typedef MappingTable::DexToPcIterator It;
    813       for (It cur = table.DexToPcBegin(), end = table.DexToPcEnd(); cur != end; ++cur) {
    814         if (offset == cur.NativePcOffset()) {
    815           os << StringPrintf("catch entry dex PC: 0x%04x\n", cur.DexPc());
    816           return cur.DexPc();
    817         }
    818       }
    819     }
    820     return DexFile::kDexNoIndex;
    821   }
    822 
    823   void DumpGcMapAtNativePcOffset(std::ostream& os, const OatFile::OatMethod& oat_method,
    824                                  const DexFile::CodeItem* code_item, size_t native_pc_offset) {
    825     const uint8_t* gc_map_raw = oat_method.GetGcMap();
    826     if (gc_map_raw != nullptr) {
    827       NativePcOffsetToReferenceMap map(gc_map_raw);
    828       if (map.HasEntry(native_pc_offset)) {
    829         size_t num_regs = map.RegWidth() * 8;
    830         const uint8_t* reg_bitmap = map.FindBitMap(native_pc_offset);
    831         bool first = true;
    832         for (size_t reg = 0; reg < num_regs; reg++) {
    833           if (((reg_bitmap[reg / 8] >> (reg % 8)) & 0x01) != 0) {
    834             if (first) {
    835               os << "GC map objects:  v" << reg << " (";
    836               DescribeVReg(os, oat_method, code_item, reg, kReferenceVReg);
    837               os << ")";
    838               first = false;
    839             } else {
    840               os << ", v" << reg << " (";
    841               DescribeVReg(os, oat_method, code_item, reg, kReferenceVReg);
    842               os << ")";
    843             }
    844           }
    845         }
    846         if (!first) {
    847           os << "\n";
    848         }
    849       }
    850     }
    851   }
    852 
    853   void DumpVRegsAtDexPc(std::ostream& os, verifier::MethodVerifier* verifier,
    854                         const OatFile::OatMethod& oat_method,
    855                         const DexFile::CodeItem* code_item, uint32_t dex_pc) {
    856     DCHECK(verifier != nullptr);
    857     std::vector<int32_t> kinds = verifier->DescribeVRegs(dex_pc);
    858     bool first = true;
    859     for (size_t reg = 0; reg < code_item->registers_size_; reg++) {
    860       VRegKind kind = static_cast<VRegKind>(kinds.at(reg * 2));
    861       if (kind != kUndefined) {
    862         if (first) {
    863           os << "VRegs:  v";
    864           first = false;
    865         } else {
    866           os << ", v";
    867         }
    868         os << reg << " (";
    869         switch (kind) {
    870           case kImpreciseConstant:
    871             os << "Imprecise Constant: " << kinds.at((reg * 2) + 1) << ", ";
    872             DescribeVReg(os, oat_method, code_item, reg, kind);
    873             break;
    874           case kConstant:
    875             os << "Constant: " << kinds.at((reg * 2) + 1);
    876             break;
    877           default:
    878             DescribeVReg(os, oat_method, code_item, reg, kind);
    879             break;
    880         }
    881         os << ")";
    882       }
    883     }
    884     if (!first) {
    885       os << "\n";
    886     }
    887   }
    888 
    889 
    890   void DumpDexCode(std::ostream& os, const DexFile& dex_file, const DexFile::CodeItem* code_item) {
    891     if (code_item != nullptr) {
    892       size_t i = 0;
    893       while (i < code_item->insns_size_in_code_units_) {
    894         const Instruction* instruction = Instruction::At(&code_item->insns_[i]);
    895         os << StringPrintf("0x%04zx: %s\n", i, instruction->DumpString(&dex_file).c_str());
    896         i += instruction->SizeInCodeUnits();
    897       }
    898     }
    899   }
    900 
    901   verifier::MethodVerifier* DumpVerifier(std::ostream& os, uint32_t dex_method_idx,
    902                                          const DexFile* dex_file,
    903                                          const DexFile::ClassDef& class_def,
    904                                          const DexFile::CodeItem* code_item,
    905                                          uint32_t method_access_flags) {
    906     if ((method_access_flags & kAccNative) == 0) {
    907       ScopedObjectAccess soa(Thread::Current());
    908       StackHandleScope<2> hs(soa.Self());
    909       Handle<mirror::DexCache> dex_cache(
    910           hs.NewHandle(Runtime::Current()->GetClassLinker()->FindDexCache(*dex_file)));
    911       auto class_loader(hs.NewHandle<mirror::ClassLoader>(nullptr));
    912       return verifier::MethodVerifier::VerifyMethodAndDump(os, dex_method_idx, dex_file, dex_cache,
    913                                                            class_loader, &class_def, code_item,
    914                                                            nullptr, method_access_flags);
    915     }
    916 
    917     return nullptr;
    918   }
    919 
    920   void DumpCode(std::ostream& os, verifier::MethodVerifier* verifier,
    921                 const OatFile::OatMethod& oat_method, const DexFile::CodeItem* code_item,
    922                 bool bad_input, size_t code_size) {
    923     const void* portable_code = oat_method.GetPortableCode();
    924     const void* quick_code = oat_method.GetQuickCode();
    925 
    926     if (code_size == 0) {
    927       code_size = oat_method.GetQuickCodeSize();
    928     }
    929     if ((code_size == 0) || ((portable_code == nullptr) && (quick_code == nullptr))) {
    930       os << "NO CODE!\n";
    931       return;
    932     } else if (quick_code != nullptr) {
    933       const uint8_t* quick_native_pc = reinterpret_cast<const uint8_t*>(quick_code);
    934       size_t offset = 0;
    935       while (offset < code_size) {
    936         if (!bad_input) {
    937           DumpMappingAtOffset(os, oat_method, offset, false);
    938         }
    939         offset += disassembler_->Dump(os, quick_native_pc + offset);
    940         if (!bad_input) {
    941           uint32_t dex_pc = DumpMappingAtOffset(os, oat_method, offset, true);
    942           if (dex_pc != DexFile::kDexNoIndex) {
    943             DumpGcMapAtNativePcOffset(os, oat_method, code_item, offset);
    944             if (verifier != nullptr) {
    945               DumpVRegsAtDexPc(os, verifier, oat_method, code_item, dex_pc);
    946             }
    947           }
    948         }
    949       }
    950     } else {
    951       CHECK(portable_code != nullptr);
    952       CHECK_EQ(code_size, 0U);  // TODO: disassembly of portable is currently not supported.
    953     }
    954   }
    955 
    956   const OatFile& oat_file_;
    957   const std::vector<const OatFile::OatDexFile*> oat_dex_files_;
    958   const OatDumperOptions* options_;
    959   InstructionSet instruction_set_;
    960   std::set<uintptr_t> offsets_;
    961   Disassembler* disassembler_;
    962 };
    963 
    964 class ImageDumper {
    965  public:
    966   explicit ImageDumper(std::ostream* os, gc::space::ImageSpace& image_space,
    967                        const ImageHeader& image_header, OatDumperOptions* oat_dumper_options)
    968       : os_(os),
    969         image_space_(image_space),
    970         image_header_(image_header),
    971         oat_dumper_options_(oat_dumper_options) {}
    972 
    973   bool Dump() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    974     std::ostream& os = *os_;
    975     os << "MAGIC: " << image_header_.GetMagic() << "\n\n";
    976 
    977     os << "IMAGE BEGIN: " << reinterpret_cast<void*>(image_header_.GetImageBegin()) << "\n\n";
    978 
    979     os << "IMAGE BITMAP OFFSET: " << reinterpret_cast<void*>(image_header_.GetImageBitmapOffset())
    980        << " SIZE: " << reinterpret_cast<void*>(image_header_.GetImageBitmapSize()) << "\n\n";
    981 
    982     os << "OAT CHECKSUM: " << StringPrintf("0x%08x\n\n", image_header_.GetOatChecksum());
    983 
    984     os << "OAT FILE BEGIN:" << reinterpret_cast<void*>(image_header_.GetOatFileBegin()) << "\n\n";
    985 
    986     os << "OAT DATA BEGIN:" << reinterpret_cast<void*>(image_header_.GetOatDataBegin()) << "\n\n";
    987 
    988     os << "OAT DATA END:" << reinterpret_cast<void*>(image_header_.GetOatDataEnd()) << "\n\n";
    989 
    990     os << "OAT FILE END:" << reinterpret_cast<void*>(image_header_.GetOatFileEnd()) << "\n\n";
    991 
    992     os << "PATCH DELTA:" << image_header_.GetPatchDelta() << "\n\n";
    993 
    994     os << "COMPILE PIC: " << (image_header_.CompilePic() ? "yes" : "no") << "\n\n";
    995 
    996     {
    997       os << "ROOTS: " << reinterpret_cast<void*>(image_header_.GetImageRoots()) << "\n";
    998       Indenter indent1_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
    999       std::ostream indent1_os(&indent1_filter);
   1000       CHECK_EQ(arraysize(image_roots_descriptions_), size_t(ImageHeader::kImageRootsMax));
   1001       for (int i = 0; i < ImageHeader::kImageRootsMax; i++) {
   1002         ImageHeader::ImageRoot image_root = static_cast<ImageHeader::ImageRoot>(i);
   1003         const char* image_root_description = image_roots_descriptions_[i];
   1004         mirror::Object* image_root_object = image_header_.GetImageRoot(image_root);
   1005         indent1_os << StringPrintf("%s: %p\n", image_root_description, image_root_object);
   1006         if (image_root_object->IsObjectArray()) {
   1007           Indenter indent2_filter(indent1_os.rdbuf(), kIndentChar, kIndentBy1Count);
   1008           std::ostream indent2_os(&indent2_filter);
   1009           mirror::ObjectArray<mirror::Object>* image_root_object_array
   1010               = image_root_object->AsObjectArray<mirror::Object>();
   1011           for (int i = 0; i < image_root_object_array->GetLength(); i++) {
   1012             mirror::Object* value = image_root_object_array->Get(i);
   1013             size_t run = 0;
   1014             for (int32_t j = i + 1; j < image_root_object_array->GetLength(); j++) {
   1015               if (value == image_root_object_array->Get(j)) {
   1016                 run++;
   1017               } else {
   1018                 break;
   1019               }
   1020             }
   1021             if (run == 0) {
   1022               indent2_os << StringPrintf("%d: ", i);
   1023             } else {
   1024               indent2_os << StringPrintf("%d to %zd: ", i, i + run);
   1025               i = i + run;
   1026             }
   1027             if (value != nullptr) {
   1028               PrettyObjectValue(indent2_os, value->GetClass(), value);
   1029             } else {
   1030               indent2_os << i << ": null\n";
   1031             }
   1032           }
   1033         }
   1034       }
   1035     }
   1036     os << "\n";
   1037 
   1038     ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   1039     std::string image_filename = image_space_.GetImageFilename();
   1040     std::string oat_location = ImageHeader::GetOatLocationFromImageLocation(image_filename);
   1041     os << "OAT LOCATION: " << oat_location;
   1042     os << "\n";
   1043     std::string error_msg;
   1044     const OatFile* oat_file = class_linker->FindOpenedOatFileFromOatLocation(oat_location);
   1045     if (oat_file == nullptr) {
   1046       oat_file = OatFile::Open(oat_location, oat_location, nullptr, nullptr, false, &error_msg);
   1047       if (oat_file == nullptr) {
   1048         os << "NOT FOUND: " << error_msg << "\n";
   1049         return false;
   1050       }
   1051     }
   1052     os << "\n";
   1053 
   1054     stats_.oat_file_bytes = oat_file->Size();
   1055 
   1056     oat_dumper_.reset(new OatDumper(*oat_file, oat_dumper_options_.release()));
   1057 
   1058     for (const OatFile::OatDexFile* oat_dex_file : oat_file->GetOatDexFiles()) {
   1059       CHECK(oat_dex_file != nullptr);
   1060       stats_.oat_dex_file_sizes.push_back(std::make_pair(oat_dex_file->GetDexFileLocation(),
   1061                                                          oat_dex_file->FileSize()));
   1062     }
   1063 
   1064     os << "OBJECTS:\n" << std::flush;
   1065 
   1066     // Loop through all the image spaces and dump their objects.
   1067     gc::Heap* heap = Runtime::Current()->GetHeap();
   1068     const std::vector<gc::space::ContinuousSpace*>& spaces = heap->GetContinuousSpaces();
   1069     Thread* self = Thread::Current();
   1070     {
   1071       {
   1072         WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
   1073         heap->FlushAllocStack();
   1074       }
   1075       // Since FlushAllocStack() above resets the (active) allocation
   1076       // stack. Need to revoke the thread-local allocation stacks that
   1077       // point into it.
   1078       {
   1079         self->TransitionFromRunnableToSuspended(kNative);
   1080         ThreadList* thread_list = Runtime::Current()->GetThreadList();
   1081         thread_list->SuspendAll();
   1082         heap->RevokeAllThreadLocalAllocationStacks(self);
   1083         thread_list->ResumeAll();
   1084         self->TransitionFromSuspendedToRunnable();
   1085       }
   1086     }
   1087     {
   1088       std::ostream* saved_os = os_;
   1089       Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
   1090       std::ostream indent_os(&indent_filter);
   1091       os_ = &indent_os;
   1092       ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
   1093       for (const auto& space : spaces) {
   1094         if (space->IsImageSpace()) {
   1095           gc::space::ImageSpace* image_space = space->AsImageSpace();
   1096           image_space->GetLiveBitmap()->Walk(ImageDumper::Callback, this);
   1097           indent_os << "\n";
   1098         }
   1099       }
   1100       // Dump the large objects separately.
   1101       heap->GetLargeObjectsSpace()->GetLiveBitmap()->Walk(ImageDumper::Callback, this);
   1102       indent_os << "\n";
   1103       os_ = saved_os;
   1104     }
   1105     os << "STATS:\n" << std::flush;
   1106     std::unique_ptr<File> file(OS::OpenFileForReading(image_filename.c_str()));
   1107     if (file.get() == nullptr) {
   1108       LOG(WARNING) << "Failed to find image in " << image_filename;
   1109     }
   1110     if (file.get() != nullptr) {
   1111       stats_.file_bytes = file->GetLength();
   1112     }
   1113     size_t header_bytes = sizeof(ImageHeader);
   1114     stats_.header_bytes = header_bytes;
   1115     size_t alignment_bytes = RoundUp(header_bytes, kObjectAlignment) - header_bytes;
   1116     stats_.alignment_bytes += alignment_bytes;
   1117     stats_.alignment_bytes += image_header_.GetImageBitmapOffset() - image_header_.GetImageSize();
   1118     stats_.bitmap_bytes += image_header_.GetImageBitmapSize();
   1119     stats_.Dump(os);
   1120     os << "\n";
   1121 
   1122     os << std::flush;
   1123 
   1124     return oat_dumper_->Dump(os);
   1125   }
   1126 
   1127  private:
   1128   static void PrettyObjectValue(std::ostream& os, mirror::Class* type, mirror::Object* value)
   1129       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   1130     CHECK(type != nullptr);
   1131     if (value == nullptr) {
   1132       os << StringPrintf("null   %s\n", PrettyDescriptor(type).c_str());
   1133     } else if (type->IsStringClass()) {
   1134       mirror::String* string = value->AsString();
   1135       os << StringPrintf("%p   String: %s\n", string,
   1136                          PrintableString(string->ToModifiedUtf8().c_str()).c_str());
   1137     } else if (type->IsClassClass()) {
   1138       mirror::Class* klass = value->AsClass();
   1139       os << StringPrintf("%p   Class: %s\n", klass, PrettyDescriptor(klass).c_str());
   1140     } else if (type->IsArtFieldClass()) {
   1141       mirror::ArtField* field = value->AsArtField();
   1142       os << StringPrintf("%p   Field: %s\n", field, PrettyField(field).c_str());
   1143     } else if (type->IsArtMethodClass()) {
   1144       mirror::ArtMethod* method = value->AsArtMethod();
   1145       os << StringPrintf("%p   Method: %s\n", method, PrettyMethod(method).c_str());
   1146     } else {
   1147       os << StringPrintf("%p   %s\n", value, PrettyDescriptor(type).c_str());
   1148     }
   1149   }
   1150 
   1151   static void PrintField(std::ostream& os, mirror::ArtField* field, mirror::Object* obj)
   1152       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   1153     const char* descriptor = field->GetTypeDescriptor();
   1154     os << StringPrintf("%s: ", field->GetName());
   1155     if (descriptor[0] != 'L' && descriptor[0] != '[') {
   1156       StackHandleScope<1> hs(Thread::Current());
   1157       FieldHelper fh(hs.NewHandle(field));
   1158       mirror::Class* type = fh.GetType();
   1159       if (type->IsPrimitiveLong()) {
   1160         os << StringPrintf("%" PRId64 " (0x%" PRIx64 ")\n", field->Get64(obj), field->Get64(obj));
   1161       } else if (type->IsPrimitiveDouble()) {
   1162         os << StringPrintf("%f (%a)\n", field->GetDouble(obj), field->GetDouble(obj));
   1163       } else if (type->IsPrimitiveFloat()) {
   1164         os << StringPrintf("%f (%a)\n", field->GetFloat(obj), field->GetFloat(obj));
   1165       } else {
   1166         DCHECK(type->IsPrimitive());
   1167         os << StringPrintf("%d (0x%x)\n", field->Get32(obj), field->Get32(obj));
   1168       }
   1169     } else {
   1170       // Get the value, don't compute the type unless it is non-null as we don't want
   1171       // to cause class loading.
   1172       mirror::Object* value = field->GetObj(obj);
   1173       if (value == nullptr) {
   1174         os << StringPrintf("null   %s\n", PrettyDescriptor(descriptor).c_str());
   1175       } else {
   1176         // Grab the field type without causing resolution.
   1177         StackHandleScope<1> hs(Thread::Current());
   1178         FieldHelper fh(hs.NewHandle(field));
   1179         mirror::Class* field_type = fh.GetType(false);
   1180         if (field_type != nullptr) {
   1181           PrettyObjectValue(os, field_type, value);
   1182         } else {
   1183           os << StringPrintf("%p   %s\n", value, PrettyDescriptor(descriptor).c_str());
   1184         }
   1185       }
   1186     }
   1187   }
   1188 
   1189   static void DumpFields(std::ostream& os, mirror::Object* obj, mirror::Class* klass)
   1190       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   1191     mirror::Class* super = klass->GetSuperClass();
   1192     if (super != nullptr) {
   1193       DumpFields(os, obj, super);
   1194     }
   1195     mirror::ObjectArray<mirror::ArtField>* fields = klass->GetIFields();
   1196     if (fields != nullptr) {
   1197       for (int32_t i = 0; i < fields->GetLength(); i++) {
   1198         mirror::ArtField* field = fields->Get(i);
   1199         PrintField(os, field, obj);
   1200       }
   1201     }
   1202   }
   1203 
   1204   bool InDumpSpace(const mirror::Object* object) {
   1205     return image_space_.Contains(object);
   1206   }
   1207 
   1208   const void* GetQuickOatCodeBegin(mirror::ArtMethod* m)
   1209       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   1210     const void* quick_code = m->GetEntryPointFromQuickCompiledCodePtrSize(
   1211         InstructionSetPointerSize(oat_dumper_->GetOatInstructionSet()));
   1212     if (quick_code == Runtime::Current()->GetClassLinker()->GetQuickResolutionTrampoline()) {
   1213       quick_code = oat_dumper_->GetQuickOatCode(m);
   1214     }
   1215     if (oat_dumper_->GetInstructionSet() == kThumb2) {
   1216       quick_code = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(quick_code) & ~0x1);
   1217     }
   1218     return quick_code;
   1219   }
   1220 
   1221   uint32_t GetQuickOatCodeSize(mirror::ArtMethod* m)
   1222       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   1223     const uint32_t* oat_code_begin = reinterpret_cast<const uint32_t*>(GetQuickOatCodeBegin(m));
   1224     if (oat_code_begin == nullptr) {
   1225       return 0;
   1226     }
   1227     return oat_code_begin[-1];
   1228   }
   1229 
   1230   const void* GetQuickOatCodeEnd(mirror::ArtMethod* m)
   1231       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   1232     const uint8_t* oat_code_begin = reinterpret_cast<const uint8_t*>(GetQuickOatCodeBegin(m));
   1233     if (oat_code_begin == nullptr) {
   1234       return nullptr;
   1235     }
   1236     return oat_code_begin + GetQuickOatCodeSize(m);
   1237   }
   1238 
   1239   static void Callback(mirror::Object* obj, void* arg)
   1240       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   1241     DCHECK(obj != nullptr);
   1242     DCHECK(arg != nullptr);
   1243     ImageDumper* state = reinterpret_cast<ImageDumper*>(arg);
   1244     if (!state->InDumpSpace(obj)) {
   1245       return;
   1246     }
   1247 
   1248     size_t object_bytes = obj->SizeOf();
   1249     size_t alignment_bytes = RoundUp(object_bytes, kObjectAlignment) - object_bytes;
   1250     state->stats_.object_bytes += object_bytes;
   1251     state->stats_.alignment_bytes += alignment_bytes;
   1252 
   1253     std::ostream& os = *state->os_;
   1254     mirror::Class* obj_class = obj->GetClass();
   1255     if (obj_class->IsArrayClass()) {
   1256       os << StringPrintf("%p: %s length:%d\n", obj, PrettyDescriptor(obj_class).c_str(),
   1257                          obj->AsArray()->GetLength());
   1258     } else if (obj->IsClass()) {
   1259       mirror::Class* klass = obj->AsClass();
   1260       os << StringPrintf("%p: java.lang.Class \"%s\" (", obj, PrettyDescriptor(klass).c_str())
   1261          << klass->GetStatus() << ")\n";
   1262     } else if (obj->IsArtField()) {
   1263       os << StringPrintf("%p: java.lang.reflect.ArtField %s\n", obj,
   1264                          PrettyField(obj->AsArtField()).c_str());
   1265     } else if (obj->IsArtMethod()) {
   1266       os << StringPrintf("%p: java.lang.reflect.ArtMethod %s\n", obj,
   1267                          PrettyMethod(obj->AsArtMethod()).c_str());
   1268     } else if (obj_class->IsStringClass()) {
   1269       os << StringPrintf("%p: java.lang.String %s\n", obj,
   1270                          PrintableString(obj->AsString()->ToModifiedUtf8().c_str()).c_str());
   1271     } else {
   1272       os << StringPrintf("%p: %s\n", obj, PrettyDescriptor(obj_class).c_str());
   1273     }
   1274     Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
   1275     std::ostream indent_os(&indent_filter);
   1276     DumpFields(indent_os, obj, obj_class);
   1277     if (obj->IsObjectArray()) {
   1278       mirror::ObjectArray<mirror::Object>* obj_array = obj->AsObjectArray<mirror::Object>();
   1279       int32_t length = obj_array->GetLength();
   1280       for (int32_t i = 0; i < length; i++) {
   1281         mirror::Object* value = obj_array->Get(i);
   1282         size_t run = 0;
   1283         for (int32_t j = i + 1; j < length; j++) {
   1284           if (value == obj_array->Get(j)) {
   1285             run++;
   1286           } else {
   1287             break;
   1288           }
   1289         }
   1290         if (run == 0) {
   1291           indent_os << StringPrintf("%d: ", i);
   1292         } else {
   1293           indent_os << StringPrintf("%d to %zd: ", i, i + run);
   1294           i = i + run;
   1295         }
   1296         mirror::Class* value_class =
   1297             (value == nullptr) ? obj_class->GetComponentType() : value->GetClass();
   1298         PrettyObjectValue(indent_os, value_class, value);
   1299       }
   1300     } else if (obj->IsClass()) {
   1301       mirror::ObjectArray<mirror::ArtField>* sfields = obj->AsClass()->GetSFields();
   1302       if (sfields != nullptr) {
   1303         indent_os << "STATICS:\n";
   1304         Indenter indent2_filter(indent_os.rdbuf(), kIndentChar, kIndentBy1Count);
   1305         std::ostream indent2_os(&indent2_filter);
   1306         for (int32_t i = 0; i < sfields->GetLength(); i++) {
   1307           mirror::ArtField* field = sfields->Get(i);
   1308           PrintField(indent2_os, field, field->GetDeclaringClass());
   1309         }
   1310       }
   1311     } else if (obj->IsArtMethod()) {
   1312       const size_t image_pointer_size = InstructionSetPointerSize(
   1313           state->oat_dumper_->GetOatInstructionSet());
   1314       mirror::ArtMethod* method = obj->AsArtMethod();
   1315       if (method->IsNative()) {
   1316         // TODO: portable dumping.
   1317         DCHECK(method->GetNativeGcMap(image_pointer_size) == nullptr) << PrettyMethod(method);
   1318         DCHECK(method->GetMappingTable(image_pointer_size) == nullptr) << PrettyMethod(method);
   1319         bool first_occurrence;
   1320         const void* quick_oat_code = state->GetQuickOatCodeBegin(method);
   1321         uint32_t quick_oat_code_size = state->GetQuickOatCodeSize(method);
   1322         state->ComputeOatSize(quick_oat_code, &first_occurrence);
   1323         if (first_occurrence) {
   1324           state->stats_.native_to_managed_code_bytes += quick_oat_code_size;
   1325         }
   1326         if (quick_oat_code != method->GetEntryPointFromQuickCompiledCodePtrSize(
   1327             image_pointer_size)) {
   1328           indent_os << StringPrintf("OAT CODE: %p\n", quick_oat_code);
   1329         }
   1330       } else if (method->IsAbstract() || method->IsCalleeSaveMethod() ||
   1331           method->IsResolutionMethod() || method->IsImtConflictMethod() ||
   1332           method->IsImtUnimplementedMethod() || method->IsClassInitializer()) {
   1333         DCHECK(method->GetNativeGcMap(image_pointer_size) == nullptr) << PrettyMethod(method);
   1334         DCHECK(method->GetMappingTable(image_pointer_size) == nullptr) << PrettyMethod(method);
   1335       } else {
   1336         const DexFile::CodeItem* code_item = method->GetCodeItem();
   1337         size_t dex_instruction_bytes = code_item->insns_size_in_code_units_ * 2;
   1338         state->stats_.dex_instruction_bytes += dex_instruction_bytes;
   1339 
   1340         bool first_occurrence;
   1341         size_t gc_map_bytes =
   1342             state->ComputeOatSize(method->GetNativeGcMap(image_pointer_size), &first_occurrence);
   1343         if (first_occurrence) {
   1344           state->stats_.gc_map_bytes += gc_map_bytes;
   1345         }
   1346 
   1347         size_t pc_mapping_table_bytes =
   1348             state->ComputeOatSize(method->GetMappingTable(image_pointer_size), &first_occurrence);
   1349         if (first_occurrence) {
   1350           state->stats_.pc_mapping_table_bytes += pc_mapping_table_bytes;
   1351         }
   1352 
   1353         size_t vmap_table_bytes =
   1354             state->ComputeOatSize(method->GetVmapTable(image_pointer_size), &first_occurrence);
   1355         if (first_occurrence) {
   1356           state->stats_.vmap_table_bytes += vmap_table_bytes;
   1357         }
   1358 
   1359         // TODO: portable dumping.
   1360         const void* quick_oat_code_begin = state->GetQuickOatCodeBegin(method);
   1361         const void* quick_oat_code_end = state->GetQuickOatCodeEnd(method);
   1362         uint32_t quick_oat_code_size = state->GetQuickOatCodeSize(method);
   1363         state->ComputeOatSize(quick_oat_code_begin, &first_occurrence);
   1364         if (first_occurrence) {
   1365           state->stats_.managed_code_bytes += quick_oat_code_size;
   1366           if (method->IsConstructor()) {
   1367             if (method->IsStatic()) {
   1368               state->stats_.class_initializer_code_bytes += quick_oat_code_size;
   1369             } else if (dex_instruction_bytes > kLargeConstructorDexBytes) {
   1370               state->stats_.large_initializer_code_bytes += quick_oat_code_size;
   1371             }
   1372           } else if (dex_instruction_bytes > kLargeMethodDexBytes) {
   1373             state->stats_.large_method_code_bytes += quick_oat_code_size;
   1374           }
   1375         }
   1376         state->stats_.managed_code_bytes_ignoring_deduplication += quick_oat_code_size;
   1377 
   1378         indent_os << StringPrintf("OAT CODE: %p-%p\n", quick_oat_code_begin, quick_oat_code_end);
   1379         indent_os << StringPrintf("SIZE: Dex Instructions=%zd GC=%zd Mapping=%zd\n",
   1380                                   dex_instruction_bytes, gc_map_bytes, pc_mapping_table_bytes);
   1381 
   1382         size_t total_size = dex_instruction_bytes + gc_map_bytes + pc_mapping_table_bytes +
   1383             vmap_table_bytes + quick_oat_code_size + object_bytes;
   1384 
   1385         double expansion =
   1386             static_cast<double>(quick_oat_code_size) / static_cast<double>(dex_instruction_bytes);
   1387         state->stats_.ComputeOutliers(total_size, expansion, method);
   1388       }
   1389     }
   1390     std::string temp;
   1391     state->stats_.Update(obj_class->GetDescriptor(&temp), object_bytes);
   1392   }
   1393 
   1394   std::set<const void*> already_seen_;
   1395   // Compute the size of the given data within the oat file and whether this is the first time
   1396   // this data has been requested
   1397   size_t ComputeOatSize(const void* oat_data, bool* first_occurrence) {
   1398     if (already_seen_.count(oat_data) == 0) {
   1399       *first_occurrence = true;
   1400       already_seen_.insert(oat_data);
   1401     } else {
   1402       *first_occurrence = false;
   1403     }
   1404     return oat_dumper_->ComputeSize(oat_data);
   1405   }
   1406 
   1407  public:
   1408   struct Stats {
   1409     size_t oat_file_bytes;
   1410     size_t file_bytes;
   1411 
   1412     size_t header_bytes;
   1413     size_t object_bytes;
   1414     size_t bitmap_bytes;
   1415     size_t alignment_bytes;
   1416 
   1417     size_t managed_code_bytes;
   1418     size_t managed_code_bytes_ignoring_deduplication;
   1419     size_t managed_to_native_code_bytes;
   1420     size_t native_to_managed_code_bytes;
   1421     size_t class_initializer_code_bytes;
   1422     size_t large_initializer_code_bytes;
   1423     size_t large_method_code_bytes;
   1424 
   1425     size_t gc_map_bytes;
   1426     size_t pc_mapping_table_bytes;
   1427     size_t vmap_table_bytes;
   1428 
   1429     size_t dex_instruction_bytes;
   1430 
   1431     std::vector<mirror::ArtMethod*> method_outlier;
   1432     std::vector<size_t> method_outlier_size;
   1433     std::vector<double> method_outlier_expansion;
   1434     std::vector<std::pair<std::string, size_t>> oat_dex_file_sizes;
   1435 
   1436     explicit Stats()
   1437         : oat_file_bytes(0),
   1438           file_bytes(0),
   1439           header_bytes(0),
   1440           object_bytes(0),
   1441           bitmap_bytes(0),
   1442           alignment_bytes(0),
   1443           managed_code_bytes(0),
   1444           managed_code_bytes_ignoring_deduplication(0),
   1445           managed_to_native_code_bytes(0),
   1446           native_to_managed_code_bytes(0),
   1447           class_initializer_code_bytes(0),
   1448           large_initializer_code_bytes(0),
   1449           large_method_code_bytes(0),
   1450           gc_map_bytes(0),
   1451           pc_mapping_table_bytes(0),
   1452           vmap_table_bytes(0),
   1453           dex_instruction_bytes(0) {}
   1454 
   1455     struct SizeAndCount {
   1456       SizeAndCount(size_t bytes, size_t count) : bytes(bytes), count(count) {}
   1457       size_t bytes;
   1458       size_t count;
   1459     };
   1460     typedef SafeMap<std::string, SizeAndCount> SizeAndCountTable;
   1461     SizeAndCountTable sizes_and_counts;
   1462 
   1463     void Update(const char* descriptor, size_t object_bytes) {
   1464       SizeAndCountTable::iterator it = sizes_and_counts.find(descriptor);
   1465       if (it != sizes_and_counts.end()) {
   1466         it->second.bytes += object_bytes;
   1467         it->second.count += 1;
   1468       } else {
   1469         sizes_and_counts.Put(descriptor, SizeAndCount(object_bytes, 1));
   1470       }
   1471     }
   1472 
   1473     double PercentOfOatBytes(size_t size) {
   1474       return (static_cast<double>(size) / static_cast<double>(oat_file_bytes)) * 100;
   1475     }
   1476 
   1477     double PercentOfFileBytes(size_t size) {
   1478       return (static_cast<double>(size) / static_cast<double>(file_bytes)) * 100;
   1479     }
   1480 
   1481     double PercentOfObjectBytes(size_t size) {
   1482       return (static_cast<double>(size) / static_cast<double>(object_bytes)) * 100;
   1483     }
   1484 
   1485     void ComputeOutliers(size_t total_size, double expansion, mirror::ArtMethod* method) {
   1486       method_outlier_size.push_back(total_size);
   1487       method_outlier_expansion.push_back(expansion);
   1488       method_outlier.push_back(method);
   1489     }
   1490 
   1491     void DumpOutliers(std::ostream& os)
   1492         SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   1493       size_t sum_of_sizes = 0;
   1494       size_t sum_of_sizes_squared = 0;
   1495       size_t sum_of_expansion = 0;
   1496       size_t sum_of_expansion_squared = 0;
   1497       size_t n = method_outlier_size.size();
   1498       for (size_t i = 0; i < n; i++) {
   1499         size_t cur_size = method_outlier_size[i];
   1500         sum_of_sizes += cur_size;
   1501         sum_of_sizes_squared += cur_size * cur_size;
   1502         double cur_expansion = method_outlier_expansion[i];
   1503         sum_of_expansion += cur_expansion;
   1504         sum_of_expansion_squared += cur_expansion * cur_expansion;
   1505       }
   1506       size_t size_mean = sum_of_sizes / n;
   1507       size_t size_variance = (sum_of_sizes_squared - sum_of_sizes * size_mean) / (n - 1);
   1508       double expansion_mean = sum_of_expansion / n;
   1509       double expansion_variance =
   1510           (sum_of_expansion_squared - sum_of_expansion * expansion_mean) / (n - 1);
   1511 
   1512       // Dump methods whose size is a certain number of standard deviations from the mean
   1513       size_t dumped_values = 0;
   1514       size_t skipped_values = 0;
   1515       for (size_t i = 100; i > 0; i--) {  // i is the current number of standard deviations
   1516         size_t cur_size_variance = i * i * size_variance;
   1517         bool first = true;
   1518         for (size_t j = 0; j < n; j++) {
   1519           size_t cur_size = method_outlier_size[j];
   1520           if (cur_size > size_mean) {
   1521             size_t cur_var = cur_size - size_mean;
   1522             cur_var = cur_var * cur_var;
   1523             if (cur_var > cur_size_variance) {
   1524               if (dumped_values > 20) {
   1525                 if (i == 1) {
   1526                   skipped_values++;
   1527                 } else {
   1528                   i = 2;  // jump to counting for 1 standard deviation
   1529                   break;
   1530                 }
   1531               } else {
   1532                 if (first) {
   1533                   os << "\nBig methods (size > " << i << " standard deviations the norm):\n";
   1534                   first = false;
   1535                 }
   1536                 os << PrettyMethod(method_outlier[j]) << " requires storage of "
   1537                     << PrettySize(cur_size) << "\n";
   1538                 method_outlier_size[j] = 0;  // don't consider this method again
   1539                 dumped_values++;
   1540               }
   1541             }
   1542           }
   1543         }
   1544       }
   1545       if (skipped_values > 0) {
   1546         os << "... skipped " << skipped_values
   1547            << " methods with size > 1 standard deviation from the norm\n";
   1548       }
   1549       os << std::flush;
   1550 
   1551       // Dump methods whose expansion is a certain number of standard deviations from the mean
   1552       dumped_values = 0;
   1553       skipped_values = 0;
   1554       for (size_t i = 10; i > 0; i--) {  // i is the current number of standard deviations
   1555         double cur_expansion_variance = i * i * expansion_variance;
   1556         bool first = true;
   1557         for (size_t j = 0; j < n; j++) {
   1558           double cur_expansion = method_outlier_expansion[j];
   1559           if (cur_expansion > expansion_mean) {
   1560             size_t cur_var = cur_expansion - expansion_mean;
   1561             cur_var = cur_var * cur_var;
   1562             if (cur_var > cur_expansion_variance) {
   1563               if (dumped_values > 20) {
   1564                 if (i == 1) {
   1565                   skipped_values++;
   1566                 } else {
   1567                   i = 2;  // jump to counting for 1 standard deviation
   1568                   break;
   1569                 }
   1570               } else {
   1571                 if (first) {
   1572                   os << "\nLarge expansion methods (size > " << i
   1573                       << " standard deviations the norm):\n";
   1574                   first = false;
   1575                 }
   1576                 os << PrettyMethod(method_outlier[j]) << " expanded code by "
   1577                    << cur_expansion << "\n";
   1578                 method_outlier_expansion[j] = 0.0;  // don't consider this method again
   1579                 dumped_values++;
   1580               }
   1581             }
   1582           }
   1583         }
   1584       }
   1585       if (skipped_values > 0) {
   1586         os << "... skipped " << skipped_values
   1587            << " methods with expansion > 1 standard deviation from the norm\n";
   1588       }
   1589       os << "\n" << std::flush;
   1590     }
   1591 
   1592     void Dump(std::ostream& os) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   1593       {
   1594         os << "art_file_bytes = " << PrettySize(file_bytes) << "\n\n"
   1595            << "art_file_bytes = header_bytes + object_bytes + alignment_bytes\n";
   1596         Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
   1597         std::ostream indent_os(&indent_filter);
   1598         indent_os << StringPrintf("header_bytes    =  %8zd (%2.0f%% of art file bytes)\n"
   1599                                   "object_bytes    =  %8zd (%2.0f%% of art file bytes)\n"
   1600                                   "bitmap_bytes    =  %8zd (%2.0f%% of art file bytes)\n"
   1601                                   "alignment_bytes =  %8zd (%2.0f%% of art file bytes)\n\n",
   1602                                   header_bytes, PercentOfFileBytes(header_bytes),
   1603                                   object_bytes, PercentOfFileBytes(object_bytes),
   1604                                   bitmap_bytes, PercentOfFileBytes(bitmap_bytes),
   1605                                   alignment_bytes, PercentOfFileBytes(alignment_bytes))
   1606             << std::flush;
   1607         CHECK_EQ(file_bytes, bitmap_bytes + header_bytes + object_bytes + alignment_bytes);
   1608       }
   1609 
   1610       os << "object_bytes breakdown:\n";
   1611       size_t object_bytes_total = 0;
   1612       for (const auto& sizes_and_count : sizes_and_counts) {
   1613         const std::string& descriptor(sizes_and_count.first);
   1614         double average = static_cast<double>(sizes_and_count.second.bytes) /
   1615             static_cast<double>(sizes_and_count.second.count);
   1616         double percent = PercentOfObjectBytes(sizes_and_count.second.bytes);
   1617         os << StringPrintf("%32s %8zd bytes %6zd instances "
   1618                            "(%4.0f bytes/instance) %2.0f%% of object_bytes\n",
   1619                            descriptor.c_str(), sizes_and_count.second.bytes,
   1620                            sizes_and_count.second.count, average, percent);
   1621         object_bytes_total += sizes_and_count.second.bytes;
   1622       }
   1623       os << "\n" << std::flush;
   1624       CHECK_EQ(object_bytes, object_bytes_total);
   1625 
   1626       os << StringPrintf("oat_file_bytes               = %8zd\n"
   1627                          "managed_code_bytes           = %8zd (%2.0f%% of oat file bytes)\n"
   1628                          "managed_to_native_code_bytes = %8zd (%2.0f%% of oat file bytes)\n"
   1629                          "native_to_managed_code_bytes = %8zd (%2.0f%% of oat file bytes)\n\n"
   1630                          "class_initializer_code_bytes = %8zd (%2.0f%% of oat file bytes)\n"
   1631                          "large_initializer_code_bytes = %8zd (%2.0f%% of oat file bytes)\n"
   1632                          "large_method_code_bytes      = %8zd (%2.0f%% of oat file bytes)\n\n",
   1633                          oat_file_bytes,
   1634                          managed_code_bytes,
   1635                          PercentOfOatBytes(managed_code_bytes),
   1636                          managed_to_native_code_bytes,
   1637                          PercentOfOatBytes(managed_to_native_code_bytes),
   1638                          native_to_managed_code_bytes,
   1639                          PercentOfOatBytes(native_to_managed_code_bytes),
   1640                          class_initializer_code_bytes,
   1641                          PercentOfOatBytes(class_initializer_code_bytes),
   1642                          large_initializer_code_bytes,
   1643                          PercentOfOatBytes(large_initializer_code_bytes),
   1644                          large_method_code_bytes,
   1645                          PercentOfOatBytes(large_method_code_bytes))
   1646             << "DexFile sizes:\n";
   1647       for (const std::pair<std::string, size_t>& oat_dex_file_size : oat_dex_file_sizes) {
   1648         os << StringPrintf("%s = %zd (%2.0f%% of oat file bytes)\n",
   1649                            oat_dex_file_size.first.c_str(), oat_dex_file_size.second,
   1650                            PercentOfOatBytes(oat_dex_file_size.second));
   1651       }
   1652 
   1653       os << "\n" << StringPrintf("gc_map_bytes           = %7zd (%2.0f%% of oat file bytes)\n"
   1654                                  "pc_mapping_table_bytes = %7zd (%2.0f%% of oat file bytes)\n"
   1655                                  "vmap_table_bytes       = %7zd (%2.0f%% of oat file bytes)\n\n",
   1656                                  gc_map_bytes, PercentOfOatBytes(gc_map_bytes),
   1657                                  pc_mapping_table_bytes, PercentOfOatBytes(pc_mapping_table_bytes),
   1658                                  vmap_table_bytes, PercentOfOatBytes(vmap_table_bytes))
   1659          << std::flush;
   1660 
   1661       os << StringPrintf("dex_instruction_bytes = %zd\n", dex_instruction_bytes)
   1662          << StringPrintf("managed_code_bytes expansion = %.2f (ignoring deduplication %.2f)\n\n",
   1663                          static_cast<double>(managed_code_bytes) /
   1664                              static_cast<double>(dex_instruction_bytes),
   1665                          static_cast<double>(managed_code_bytes_ignoring_deduplication) /
   1666                              static_cast<double>(dex_instruction_bytes))
   1667          << std::flush;
   1668 
   1669       DumpOutliers(os);
   1670     }
   1671   } stats_;
   1672 
   1673  private:
   1674   enum {
   1675     // Number of bytes for a constructor to be considered large. Based on the 1000 basic block
   1676     // threshold, we assume 2 bytes per instruction and 2 instructions per block.
   1677     kLargeConstructorDexBytes = 4000,
   1678     // Number of bytes for a method to be considered large. Based on the 4000 basic block
   1679     // threshold, we assume 2 bytes per instruction and 2 instructions per block.
   1680     kLargeMethodDexBytes = 16000
   1681   };
   1682   std::ostream* os_;
   1683   gc::space::ImageSpace& image_space_;
   1684   const ImageHeader& image_header_;
   1685   std::unique_ptr<OatDumper> oat_dumper_;
   1686   std::unique_ptr<OatDumperOptions> oat_dumper_options_;
   1687 
   1688   DISALLOW_COPY_AND_ASSIGN(ImageDumper);
   1689 };
   1690 
   1691 static int oatdump(int argc, char** argv) {
   1692   InitLogging(argv);
   1693 
   1694   // Skip over argv[0].
   1695   argv++;
   1696   argc--;
   1697 
   1698   if (argc == 0) {
   1699     fprintf(stderr, "No arguments specified\n");
   1700     usage();
   1701   }
   1702 
   1703   const char* oat_filename = nullptr;
   1704   const char* image_location = nullptr;
   1705   const char* boot_image_location = nullptr;
   1706   InstructionSet instruction_set = kRuntimeISA;
   1707   std::string elf_filename_prefix;
   1708   std::ostream* os = &std::cout;
   1709   std::unique_ptr<std::ofstream> out;
   1710   bool dump_raw_mapping_table = false;
   1711   bool dump_raw_gc_map = false;
   1712   bool dump_vmap = true;
   1713   bool disassemble_code = true;
   1714 
   1715   for (int i = 0; i < argc; i++) {
   1716     const StringPiece option(argv[i]);
   1717     if (option.starts_with("--oat-file=")) {
   1718       oat_filename = option.substr(strlen("--oat-file=")).data();
   1719     } else if (option.starts_with("--image=")) {
   1720       image_location = option.substr(strlen("--image=")).data();
   1721     } else if (option.starts_with("--boot-image=")) {
   1722       boot_image_location = option.substr(strlen("--boot-image=")).data();
   1723     } else if (option.starts_with("--instruction-set=")) {
   1724       StringPiece instruction_set_str = option.substr(strlen("--instruction-set=")).data();
   1725       if (instruction_set_str == "arm") {
   1726         instruction_set = kThumb2;
   1727       } else if (instruction_set_str == "arm64") {
   1728         instruction_set = kArm64;
   1729       } else if (instruction_set_str == "mips") {
   1730         instruction_set = kMips;
   1731       } else if (instruction_set_str == "x86") {
   1732         instruction_set = kX86;
   1733       } else if (instruction_set_str == "x86_64") {
   1734         instruction_set = kX86_64;
   1735       }
   1736     } else if (option =="--dump:raw_mapping_table") {
   1737       dump_raw_mapping_table = true;
   1738     } else if (option == "--dump:raw_gc_map") {
   1739       dump_raw_gc_map = true;
   1740     } else if (option == "--no-dump:vmap") {
   1741       dump_vmap = false;
   1742     } else if (option == "--no-disassemble") {
   1743       disassemble_code = false;
   1744     } else if (option.starts_with("--output=")) {
   1745       const char* filename = option.substr(strlen("--output=")).data();
   1746       out.reset(new std::ofstream(filename));
   1747       if (!out->good()) {
   1748         fprintf(stderr, "Failed to open output filename %s\n", filename);
   1749         usage();
   1750       }
   1751       os = out.get();
   1752     } else {
   1753       fprintf(stderr, "Unknown argument %s\n", option.data());
   1754       usage();
   1755     }
   1756   }
   1757 
   1758   if (image_location == nullptr && oat_filename == nullptr) {
   1759     fprintf(stderr, "Either --image or --oat must be specified\n");
   1760     return EXIT_FAILURE;
   1761   }
   1762 
   1763   if (image_location != nullptr && oat_filename != nullptr) {
   1764     fprintf(stderr, "Either --image or --oat must be specified but not both\n");
   1765     return EXIT_FAILURE;
   1766   }
   1767 
   1768   // If we are only doing the oat file, disable absolute_addresses. Keep them for image dumping.
   1769   bool absolute_addresses = (oat_filename == nullptr);
   1770   std::unique_ptr<OatDumperOptions> oat_dumper_options(new OatDumperOptions(dump_raw_mapping_table,
   1771                                                                             dump_raw_gc_map,
   1772                                                                             dump_vmap,
   1773                                                                             disassemble_code,
   1774                                                                             absolute_addresses));
   1775   MemMap::Init();
   1776   if (oat_filename != nullptr) {
   1777     std::string error_msg;
   1778     OatFile* oat_file =
   1779         OatFile::Open(oat_filename, oat_filename, nullptr, nullptr, false, &error_msg);
   1780     if (oat_file == nullptr) {
   1781       fprintf(stderr, "Failed to open oat file from '%s': %s\n", oat_filename, error_msg.c_str());
   1782       return EXIT_FAILURE;
   1783     }
   1784     OatDumper oat_dumper(*oat_file, oat_dumper_options.release());
   1785     bool success = oat_dumper.Dump(*os);
   1786     return (success) ? EXIT_SUCCESS : EXIT_FAILURE;
   1787   }
   1788 
   1789   RuntimeOptions options;
   1790   std::string image_option;
   1791   std::string oat_option;
   1792   std::string boot_image_option;
   1793   std::string boot_oat_option;
   1794 
   1795   // We are more like a compiler than a run-time. We don't want to execute code.
   1796   NoopCompilerCallbacks callbacks;
   1797   options.push_back(std::make_pair("compilercallbacks", &callbacks));
   1798 
   1799   if (boot_image_location != nullptr) {
   1800     boot_image_option += "-Ximage:";
   1801     boot_image_option += boot_image_location;
   1802     options.push_back(std::make_pair(boot_image_option.c_str(), nullptr));
   1803   }
   1804   if (image_location != nullptr) {
   1805     image_option += "-Ximage:";
   1806     image_option += image_location;
   1807     options.push_back(std::make_pair(image_option.c_str(), nullptr));
   1808   }
   1809   options.push_back(
   1810       std::make_pair("imageinstructionset",
   1811                      reinterpret_cast<const void*>(GetInstructionSetString(instruction_set))));
   1812 
   1813   if (!Runtime::Create(options, false)) {
   1814     fprintf(stderr, "Failed to create runtime\n");
   1815     return EXIT_FAILURE;
   1816   }
   1817   std::unique_ptr<Runtime> runtime(Runtime::Current());
   1818   // Runtime::Create acquired the mutator_lock_ that is normally given away when we Runtime::Start,
   1819   // give it away now and then switch to a more manageable ScopedObjectAccess.
   1820   Thread::Current()->TransitionFromRunnableToSuspended(kNative);
   1821   ScopedObjectAccess soa(Thread::Current());
   1822   gc::Heap* heap = Runtime::Current()->GetHeap();
   1823   gc::space::ImageSpace* image_space = heap->GetImageSpace();
   1824   CHECK(image_space != nullptr);
   1825   const ImageHeader& image_header = image_space->GetImageHeader();
   1826   if (!image_header.IsValid()) {
   1827     fprintf(stderr, "Invalid image header %s\n", image_location);
   1828     return EXIT_FAILURE;
   1829   }
   1830   ImageDumper image_dumper(os, *image_space, image_header, oat_dumper_options.release());
   1831   bool success = image_dumper.Dump();
   1832   return (success) ? EXIT_SUCCESS : EXIT_FAILURE;
   1833 }
   1834 
   1835 }  // namespace art
   1836 
   1837 int main(int argc, char** argv) {
   1838   return art::oatdump(argc, argv);
   1839 }
   1840