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