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 "gc_map.h"
     33 #include "gc/space/image_space.h"
     34 #include "gc/space/large_object_space.h"
     35 #include "gc/space/space-inl.h"
     36 #include "image.h"
     37 #include "indenter.h"
     38 #include "mapping_table.h"
     39 #include "mirror/art_field-inl.h"
     40 #include "mirror/art_method-inl.h"
     41 #include "mirror/array-inl.h"
     42 #include "mirror/class-inl.h"
     43 #include "mirror/object-inl.h"
     44 #include "mirror/object_array-inl.h"
     45 #include "oat.h"
     46 #include "object_utils.h"
     47 #include "os.h"
     48 #include "runtime.h"
     49 #include "safe_map.h"
     50 #include "scoped_thread_state_change.h"
     51 #include "verifier/method_verifier.h"
     52 #include "vmap_table.h"
     53 
     54 namespace art {
     55 
     56 static void usage() {
     57   fprintf(stderr,
     58           "Usage: oatdump [options] ...\n"
     59           "    Example: oatdump --image=$ANDROID_PRODUCT_OUT/system/framework/boot.art --host-prefix=$ANDROID_PRODUCT_OUT\n"
     60           "    Example: adb shell oatdump --image=/system/framework/boot.art\n"
     61           "\n");
     62   fprintf(stderr,
     63           "  --oat-file=<file.oat>: specifies an input oat filename.\n"
     64           "      Example: --oat-file=/system/framework/boot.oat\n"
     65           "\n");
     66   fprintf(stderr,
     67           "  --image=<file.art>: specifies an input image filename.\n"
     68           "      Example: --image=/system/framework/boot.art\n"
     69           "\n");
     70   fprintf(stderr,
     71           "  --boot-image=<file.art>: provide the image file for the boot class path.\n"
     72           "      Example: --boot-image=/system/framework/boot.art\n"
     73           "\n");
     74   fprintf(stderr,
     75           "  --host-prefix may be used to translate host paths to target paths during\n"
     76           "      cross compilation.\n"
     77           "      Example: --host-prefix=out/target/product/crespo\n"
     78           "      Default: $ANDROID_PRODUCT_OUT\n"
     79           "\n");
     80   fprintf(stderr,
     81           "  --output=<file> may be used to send the output to a file.\n"
     82           "      Example: --output=/tmp/oatdump.txt\n"
     83           "\n");
     84   exit(EXIT_FAILURE);
     85 }
     86 
     87 const char* image_roots_descriptions_[] = {
     88   "kResolutionMethod",
     89   "kCalleeSaveMethod",
     90   "kRefsOnlySaveMethod",
     91   "kRefsAndArgsSaveMethod",
     92   "kOatLocation",
     93   "kDexCaches",
     94   "kClassRoots",
     95 };
     96 
     97 class OatDumper {
     98  public:
     99   explicit OatDumper(const std::string& host_prefix, const OatFile& oat_file)
    100     : host_prefix_(host_prefix),
    101       oat_file_(oat_file),
    102       oat_dex_files_(oat_file.GetOatDexFiles()),
    103       disassembler_(Disassembler::Create(oat_file_.GetOatHeader().GetInstructionSet())) {
    104     AddAllOffsets();
    105   }
    106 
    107   void Dump(std::ostream& os) {
    108     const OatHeader& oat_header = oat_file_.GetOatHeader();
    109 
    110     os << "MAGIC:\n";
    111     os << oat_header.GetMagic() << "\n\n";
    112 
    113     os << "CHECKSUM:\n";
    114     os << StringPrintf("0x%08x\n\n", oat_header.GetChecksum());
    115 
    116     os << "INSTRUCTION SET:\n";
    117     os << oat_header.GetInstructionSet() << "\n\n";
    118 
    119     os << "DEX FILE COUNT:\n";
    120     os << oat_header.GetDexFileCount() << "\n\n";
    121 
    122     os << "EXECUTABLE OFFSET:\n";
    123     os << StringPrintf("0x%08x\n\n", oat_header.GetExecutableOffset());
    124 
    125     os << "IMAGE FILE LOCATION OAT CHECKSUM:\n";
    126     os << StringPrintf("0x%08x\n\n", oat_header.GetImageFileLocationOatChecksum());
    127 
    128     os << "IMAGE FILE LOCATION OAT BEGIN:\n";
    129     os << StringPrintf("0x%08x\n\n", oat_header.GetImageFileLocationOatDataBegin());
    130 
    131     os << "IMAGE FILE LOCATION:\n";
    132     const std::string image_file_location(oat_header.GetImageFileLocation());
    133     os << image_file_location;
    134     if (!image_file_location.empty() && !host_prefix_.empty()) {
    135       os << " (" << host_prefix_ << image_file_location << ")";
    136     }
    137     os << "\n\n";
    138 
    139     os << "BEGIN:\n";
    140     os << reinterpret_cast<const void*>(oat_file_.Begin()) << "\n\n";
    141 
    142     os << "END:\n";
    143     os << reinterpret_cast<const void*>(oat_file_.End()) << "\n\n";
    144 
    145     os << std::flush;
    146 
    147     for (size_t i = 0; i < oat_dex_files_.size(); i++) {
    148       const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
    149       CHECK(oat_dex_file != NULL);
    150       DumpOatDexFile(os, *oat_dex_file);
    151     }
    152   }
    153 
    154   size_t ComputeSize(const void* oat_data) {
    155     if (reinterpret_cast<const byte*>(oat_data) < oat_file_.Begin() ||
    156         reinterpret_cast<const byte*>(oat_data) > oat_file_.End()) {
    157       return 0;  // Address not in oat file
    158     }
    159     uint32_t begin_offset = reinterpret_cast<size_t>(oat_data) -
    160                             reinterpret_cast<size_t>(oat_file_.Begin());
    161     typedef std::set<uint32_t>::iterator It;
    162     It it = offsets_.upper_bound(begin_offset);
    163     CHECK(it != offsets_.end());
    164     uint32_t end_offset = *it;
    165     return end_offset - begin_offset;
    166   }
    167 
    168   InstructionSet GetInstructionSet() {
    169     return oat_file_.GetOatHeader().GetInstructionSet();
    170   }
    171 
    172   const void* GetOatCode(mirror::ArtMethod* m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    173     MethodHelper mh(m);
    174     for (size_t i = 0; i < oat_dex_files_.size(); i++) {
    175       const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
    176       CHECK(oat_dex_file != NULL);
    177       UniquePtr<const DexFile> dex_file(oat_dex_file->OpenDexFile());
    178       if (dex_file.get() != NULL) {
    179         const DexFile::ClassDef* class_def =
    180             dex_file->FindClassDef(mh.GetDeclaringClassDescriptor());
    181         if (class_def != NULL) {
    182           uint16_t class_def_index = dex_file->GetIndexForClassDef(*class_def);
    183           const OatFile::OatClass* oat_class = oat_dex_file->GetOatClass(class_def_index);
    184           CHECK(oat_class != NULL);
    185           size_t method_index = m->GetMethodIndex();
    186           return oat_class->GetOatMethod(method_index).GetCode();
    187         }
    188       }
    189     }
    190     return NULL;
    191   }
    192 
    193  private:
    194   void AddAllOffsets() {
    195     // We don't know the length of the code for each method, but we need to know where to stop
    196     // when disassembling. What we do know is that a region of code will be followed by some other
    197     // region, so if we keep a sorted sequence of the start of each region, we can infer the length
    198     // of a piece of code by using upper_bound to find the start of the next region.
    199     for (size_t i = 0; i < oat_dex_files_.size(); i++) {
    200       const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
    201       CHECK(oat_dex_file != NULL);
    202       UniquePtr<const DexFile> dex_file(oat_dex_file->OpenDexFile());
    203       if (dex_file.get() == NULL) {
    204         continue;
    205       }
    206       offsets_.insert(reinterpret_cast<uint32_t>(&dex_file->GetHeader()));
    207       for (size_t class_def_index = 0; class_def_index < dex_file->NumClassDefs(); class_def_index++) {
    208         const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
    209         UniquePtr<const OatFile::OatClass> oat_class(oat_dex_file->GetOatClass(class_def_index));
    210         const byte* class_data = dex_file->GetClassData(class_def);
    211         if (class_data != NULL) {
    212           ClassDataItemIterator it(*dex_file, class_data);
    213           SkipAllFields(it);
    214           uint32_t class_method_index = 0;
    215           while (it.HasNextDirectMethod()) {
    216             AddOffsets(oat_class->GetOatMethod(class_method_index++));
    217             it.Next();
    218           }
    219           while (it.HasNextVirtualMethod()) {
    220             AddOffsets(oat_class->GetOatMethod(class_method_index++));
    221             it.Next();
    222           }
    223         }
    224       }
    225     }
    226 
    227     // If the last thing in the file is code for a method, there won't be an offset for the "next"
    228     // thing. Instead of having a special case in the upper_bound code, let's just add an entry
    229     // for the end of the file.
    230     offsets_.insert(static_cast<uint32_t>(oat_file_.Size()));
    231   }
    232 
    233   void AddOffsets(const OatFile::OatMethod& oat_method) {
    234     uint32_t code_offset = oat_method.GetCodeOffset();
    235     if (oat_file_.GetOatHeader().GetInstructionSet() == kThumb2) {
    236       code_offset &= ~0x1;
    237     }
    238     offsets_.insert(code_offset);
    239     offsets_.insert(oat_method.GetMappingTableOffset());
    240     offsets_.insert(oat_method.GetVmapTableOffset());
    241     offsets_.insert(oat_method.GetNativeGcMapOffset());
    242   }
    243 
    244   void DumpOatDexFile(std::ostream& os, const OatFile::OatDexFile& oat_dex_file) {
    245     os << "OAT DEX FILE:\n";
    246     os << StringPrintf("location: %s\n", oat_dex_file.GetDexFileLocation().c_str());
    247     os << StringPrintf("checksum: 0x%08x\n", oat_dex_file.GetDexFileLocationChecksum());
    248     UniquePtr<const DexFile> dex_file(oat_dex_file.OpenDexFile());
    249     if (dex_file.get() == NULL) {
    250       os << "NOT FOUND\n\n";
    251       return;
    252     }
    253     for (size_t class_def_index = 0; class_def_index < dex_file->NumClassDefs(); class_def_index++) {
    254       const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
    255       const char* descriptor = dex_file->GetClassDescriptor(class_def);
    256       UniquePtr<const OatFile::OatClass> oat_class(oat_dex_file.GetOatClass(class_def_index));
    257       CHECK(oat_class.get() != NULL);
    258       os << StringPrintf("%zd: %s (type_idx=%d) (", class_def_index, descriptor, class_def.class_idx_)
    259          << oat_class->GetStatus() << ")\n";
    260       Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
    261       std::ostream indented_os(&indent_filter);
    262       DumpOatClass(indented_os, *oat_class.get(), *(dex_file.get()), class_def);
    263     }
    264 
    265     os << std::flush;
    266   }
    267 
    268   static void SkipAllFields(ClassDataItemIterator& it) {
    269     while (it.HasNextStaticField()) {
    270       it.Next();
    271     }
    272     while (it.HasNextInstanceField()) {
    273       it.Next();
    274     }
    275   }
    276 
    277   void DumpOatClass(std::ostream& os, const OatFile::OatClass& oat_class, const DexFile& dex_file,
    278                     const DexFile::ClassDef& class_def) {
    279     const byte* class_data = dex_file.GetClassData(class_def);
    280     if (class_data == NULL) {  // empty class such as a marker interface?
    281       return;
    282     }
    283     ClassDataItemIterator it(dex_file, class_data);
    284     SkipAllFields(it);
    285     uint32_t class_method_idx = 0;
    286     while (it.HasNextDirectMethod()) {
    287       const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_idx);
    288       DumpOatMethod(os, class_def, class_method_idx, oat_method, dex_file,
    289                     it.GetMemberIndex(), it.GetMethodCodeItem(), it.GetMemberAccessFlags());
    290       class_method_idx++;
    291       it.Next();
    292     }
    293     while (it.HasNextVirtualMethod()) {
    294       const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_idx);
    295       DumpOatMethod(os, class_def, class_method_idx, oat_method, dex_file,
    296                     it.GetMemberIndex(), it.GetMethodCodeItem(), it.GetMemberAccessFlags());
    297       class_method_idx++;
    298       it.Next();
    299     }
    300     DCHECK(!it.HasNext());
    301     os << std::flush;
    302   }
    303 
    304   void DumpOatMethod(std::ostream& os, const DexFile::ClassDef& class_def,
    305                      uint32_t class_method_index,
    306                      const OatFile::OatMethod& oat_method, const DexFile& dex_file,
    307                      uint32_t dex_method_idx, const DexFile::CodeItem* code_item,
    308                      uint32_t method_access_flags) {
    309     os << StringPrintf("%d: %s (dex_method_idx=%d)\n",
    310                        class_method_index, PrettyMethod(dex_method_idx, dex_file, true).c_str(),
    311                        dex_method_idx);
    312     Indenter indent1_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
    313     std::ostream indent1_os(&indent1_filter);
    314     {
    315       indent1_os << "DEX CODE:\n";
    316       Indenter indent2_filter(indent1_os.rdbuf(), kIndentChar, kIndentBy1Count);
    317       std::ostream indent2_os(&indent2_filter);
    318       DumpDexCode(indent2_os, dex_file, code_item);
    319     }
    320     if (Runtime::Current() != NULL) {
    321       indent1_os << "VERIFIER TYPE ANALYSIS:\n";
    322       Indenter indent2_filter(indent1_os.rdbuf(), kIndentChar, kIndentBy1Count);
    323       std::ostream indent2_os(&indent2_filter);
    324       DumpVerifier(indent2_os, dex_method_idx, &dex_file, class_def, code_item,
    325                    method_access_flags);
    326     }
    327     {
    328       indent1_os << "OAT DATA:\n";
    329       Indenter indent2_filter(indent1_os.rdbuf(), kIndentChar, kIndentBy1Count);
    330       std::ostream indent2_os(&indent2_filter);
    331 
    332       indent2_os << StringPrintf("frame_size_in_bytes: %zd\n", oat_method.GetFrameSizeInBytes());
    333       indent2_os << StringPrintf("core_spill_mask: 0x%08x ", oat_method.GetCoreSpillMask());
    334       DumpSpillMask(indent2_os, oat_method.GetCoreSpillMask(), false);
    335       indent2_os << StringPrintf("\nfp_spill_mask: 0x%08x ", oat_method.GetFpSpillMask());
    336       DumpSpillMask(indent2_os, oat_method.GetFpSpillMask(), true);
    337       indent2_os << StringPrintf("\nvmap_table: %p (offset=0x%08x)\n",
    338                                  oat_method.GetVmapTable(), oat_method.GetVmapTableOffset());
    339       DumpVmap(indent2_os, oat_method);
    340       indent2_os << StringPrintf("mapping_table: %p (offset=0x%08x)\n",
    341                                  oat_method.GetMappingTable(), oat_method.GetMappingTableOffset());
    342       const bool kDumpRawMappingTable = false;
    343       if (kDumpRawMappingTable) {
    344         Indenter indent3_filter(indent2_os.rdbuf(), kIndentChar, kIndentBy1Count);
    345         std::ostream indent3_os(&indent3_filter);
    346         DumpMappingTable(indent3_os, oat_method);
    347       }
    348       indent2_os << StringPrintf("gc_map: %p (offset=0x%08x)\n",
    349                                  oat_method.GetNativeGcMap(), oat_method.GetNativeGcMapOffset());
    350       const bool kDumpRawGcMap = false;
    351       if (kDumpRawGcMap) {
    352         Indenter indent3_filter(indent2_os.rdbuf(), kIndentChar, kIndentBy1Count);
    353         std::ostream indent3_os(&indent3_filter);
    354         DumpGcMap(indent3_os, oat_method, code_item);
    355       }
    356     }
    357     {
    358       indent1_os << StringPrintf("CODE: %p (offset=0x%08x size=%d)%s\n",
    359                                  oat_method.GetCode(),
    360                                  oat_method.GetCodeOffset(),
    361                                  oat_method.GetCodeSize(),
    362                                  oat_method.GetCode() != NULL ? "..." : "");
    363       Indenter indent2_filter(indent1_os.rdbuf(), kIndentChar, kIndentBy1Count);
    364       std::ostream indent2_os(&indent2_filter);
    365       DumpCode(indent2_os, oat_method, dex_method_idx, &dex_file, class_def, code_item,
    366                method_access_flags);
    367     }
    368   }
    369 
    370   void DumpSpillMask(std::ostream& os, uint32_t spill_mask, bool is_float) {
    371     if (spill_mask == 0) {
    372       return;
    373     }
    374     os << "(";
    375     for (size_t i = 0; i < 32; i++) {
    376       if ((spill_mask & (1 << i)) != 0) {
    377         if (is_float) {
    378           os << "fr" << i;
    379         } else {
    380           os << "r" << i;
    381         }
    382         spill_mask ^= 1 << i;  // clear bit
    383         if (spill_mask != 0) {
    384           os << ", ";
    385         } else {
    386           break;
    387         }
    388       }
    389     }
    390     os << ")";
    391   }
    392 
    393   void DumpVmap(std::ostream& os, const OatFile::OatMethod& oat_method) {
    394     const uint8_t* raw_table = oat_method.GetVmapTable();
    395     if (raw_table != NULL) {
    396       const VmapTable vmap_table(raw_table);
    397       bool first = true;
    398       bool processing_fp = false;
    399       uint32_t spill_mask = oat_method.GetCoreSpillMask();
    400       for (size_t i = 0; i < vmap_table.Size(); i++) {
    401         uint16_t dex_reg = vmap_table[i];
    402         uint32_t cpu_reg = vmap_table.ComputeRegister(spill_mask, i,
    403                                                       processing_fp ? kFloatVReg : kIntVReg);
    404         os << (first ? "v" : ", v")  << dex_reg;
    405         if (!processing_fp) {
    406           os << "/r" << cpu_reg;
    407         } else {
    408           os << "/fr" << cpu_reg;
    409         }
    410         first = false;
    411         if (!processing_fp && dex_reg == 0xFFFF) {
    412           processing_fp = true;
    413           spill_mask = oat_method.GetFpSpillMask();
    414         }
    415       }
    416       os << "\n";
    417     }
    418   }
    419 
    420   void DescribeVReg(std::ostream& os, const OatFile::OatMethod& oat_method,
    421                     const DexFile::CodeItem* code_item, size_t reg, VRegKind kind) {
    422     const uint8_t* raw_table = oat_method.GetVmapTable();
    423     if (raw_table != NULL) {
    424       const VmapTable vmap_table(raw_table);
    425       uint32_t vmap_offset;
    426       if (vmap_table.IsInContext(reg, kind, &vmap_offset)) {
    427         bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg);
    428         uint32_t spill_mask = is_float ? oat_method.GetFpSpillMask()
    429                                        : oat_method.GetCoreSpillMask();
    430         os << (is_float ? "fr" : "r") << vmap_table.ComputeRegister(spill_mask, vmap_offset, kind);
    431       } else {
    432         uint32_t offset = StackVisitor::GetVRegOffset(code_item, oat_method.GetCoreSpillMask(),
    433                                                       oat_method.GetFpSpillMask(),
    434                                                       oat_method.GetFrameSizeInBytes(), reg);
    435         os << "[sp + #" << offset << "]";
    436       }
    437     }
    438   }
    439 
    440   void DumpGcMap(std::ostream& os, const OatFile::OatMethod& oat_method,
    441                  const DexFile::CodeItem* code_item) {
    442     const uint8_t* gc_map_raw = oat_method.GetNativeGcMap();
    443     if (gc_map_raw == NULL) {
    444       return;
    445     }
    446     NativePcOffsetToReferenceMap map(gc_map_raw);
    447     const void* code = oat_method.GetCode();
    448     for (size_t entry = 0; entry < map.NumEntries(); entry++) {
    449       const uint8_t* native_pc = reinterpret_cast<const uint8_t*>(code) +
    450                                  map.GetNativePcOffset(entry);
    451       os << StringPrintf("%p", native_pc);
    452       size_t num_regs = map.RegWidth() * 8;
    453       const uint8_t* reg_bitmap = map.GetBitMap(entry);
    454       bool first = true;
    455       for (size_t reg = 0; reg < num_regs; reg++) {
    456         if (((reg_bitmap[reg / 8] >> (reg % 8)) & 0x01) != 0) {
    457           if (first) {
    458             os << "  v" << reg << " (";
    459             DescribeVReg(os, oat_method, code_item, reg, kReferenceVReg);
    460             os << ")";
    461             first = false;
    462           } else {
    463             os << ", v" << reg << " (";
    464             DescribeVReg(os, oat_method, code_item, reg, kReferenceVReg);
    465             os << ")";
    466           }
    467         }
    468       }
    469       os << "\n";
    470     }
    471   }
    472 
    473   void DumpMappingTable(std::ostream& os, const OatFile::OatMethod& oat_method) {
    474     const void* code = oat_method.GetCode();
    475     if (code == NULL) {
    476       return;
    477     }
    478     MappingTable table(oat_method.GetMappingTable());
    479     if (table.TotalSize() != 0) {
    480       Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
    481       std::ostream indent_os(&indent_filter);
    482       if (table.PcToDexSize() != 0) {
    483         typedef MappingTable::PcToDexIterator It;
    484         os << "suspend point mappings {\n";
    485         for (It cur = table.PcToDexBegin(), end = table.PcToDexEnd(); cur != end; ++cur) {
    486           indent_os << StringPrintf("0x%04x -> 0x%04x\n", cur.NativePcOffset(), cur.DexPc());
    487         }
    488         os << "}\n";
    489       }
    490       if (table.DexToPcSize() != 0) {
    491         typedef MappingTable::DexToPcIterator It;
    492         os << "catch entry mappings {\n";
    493         for (It cur = table.DexToPcBegin(), end = table.DexToPcEnd(); cur != end; ++cur) {
    494           indent_os << StringPrintf("0x%04x -> 0x%04x\n", cur.NativePcOffset(), cur.DexPc());
    495         }
    496         os << "}\n";
    497       }
    498     }
    499   }
    500 
    501   uint32_t DumpMappingAtOffset(std::ostream& os, const OatFile::OatMethod& oat_method,
    502                                size_t offset, bool suspend_point_mapping) {
    503     MappingTable table(oat_method.GetMappingTable());
    504     if (suspend_point_mapping && table.PcToDexSize() > 0) {
    505       typedef MappingTable::PcToDexIterator It;
    506       for (It cur = table.PcToDexBegin(), end = table.PcToDexEnd(); cur != end; ++cur) {
    507         if (offset == cur.NativePcOffset()) {
    508           os << StringPrintf("suspend point dex PC: 0x%04x\n", cur.DexPc());
    509           return cur.DexPc();
    510         }
    511       }
    512     } else if (!suspend_point_mapping && table.DexToPcSize() > 0) {
    513       typedef MappingTable::DexToPcIterator It;
    514       for (It cur = table.DexToPcBegin(), end = table.DexToPcEnd(); cur != end; ++cur) {
    515         if (offset == cur.NativePcOffset()) {
    516           os << StringPrintf("catch entry dex PC: 0x%04x\n", cur.DexPc());
    517           return cur.DexPc();
    518         }
    519       }
    520     }
    521     return DexFile::kDexNoIndex;
    522   }
    523 
    524   void DumpGcMapAtNativePcOffset(std::ostream& os, const OatFile::OatMethod& oat_method,
    525                                  const DexFile::CodeItem* code_item, size_t native_pc_offset) {
    526     const uint8_t* gc_map_raw = oat_method.GetNativeGcMap();
    527     if (gc_map_raw != NULL) {
    528       NativePcOffsetToReferenceMap map(gc_map_raw);
    529       if (map.HasEntry(native_pc_offset)) {
    530         size_t num_regs = map.RegWidth() * 8;
    531         const uint8_t* reg_bitmap = map.FindBitMap(native_pc_offset);
    532         bool first = true;
    533         for (size_t reg = 0; reg < num_regs; reg++) {
    534           if (((reg_bitmap[reg / 8] >> (reg % 8)) & 0x01) != 0) {
    535             if (first) {
    536               os << "GC map objects:  v" << reg << " (";
    537               DescribeVReg(os, oat_method, code_item, reg, kReferenceVReg);
    538               os << ")";
    539               first = false;
    540             } else {
    541               os << ", v" << reg << " (";
    542               DescribeVReg(os, oat_method, code_item, reg, kReferenceVReg);
    543               os << ")";
    544             }
    545           }
    546         }
    547         if (!first) {
    548           os << "\n";
    549         }
    550       }
    551     }
    552   }
    553 
    554   void DumpVRegsAtDexPc(std::ostream& os,  const OatFile::OatMethod& oat_method,
    555                         uint32_t dex_method_idx, const DexFile* dex_file,
    556                         const DexFile::ClassDef& class_def, const DexFile::CodeItem* code_item,
    557                         uint32_t method_access_flags, uint32_t dex_pc) {
    558     static UniquePtr<verifier::MethodVerifier> verifier;
    559     static const DexFile* verified_dex_file = NULL;
    560     static uint32_t verified_dex_method_idx = DexFile::kDexNoIndex;
    561     if (dex_file != verified_dex_file || verified_dex_method_idx != dex_method_idx) {
    562       ScopedObjectAccess soa(Thread::Current());
    563       mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(*dex_file);
    564       mirror::ClassLoader* class_loader = NULL;
    565       verifier.reset(new verifier::MethodVerifier(dex_file, dex_cache, class_loader, &class_def,
    566                                                   code_item, dex_method_idx, NULL,
    567                                                   method_access_flags, true, true));
    568       verifier->Verify();
    569       verified_dex_file = dex_file;
    570       verified_dex_method_idx = dex_method_idx;
    571     }
    572     std::vector<int32_t> kinds = verifier->DescribeVRegs(dex_pc);
    573     bool first = true;
    574     for (size_t reg = 0; reg < code_item->registers_size_; reg++) {
    575       VRegKind kind = static_cast<VRegKind>(kinds.at(reg * 2));
    576       if (kind != kUndefined) {
    577         if (first) {
    578           os << "VRegs:  v";
    579           first = false;
    580         } else {
    581           os << ", v";
    582         }
    583         os << reg << " (";
    584         switch (kind) {
    585           case kImpreciseConstant:
    586             os << "Imprecise Constant: " << kinds.at((reg * 2) + 1) << ", ";
    587             DescribeVReg(os, oat_method, code_item, reg, kind);
    588             break;
    589           case kConstant:
    590             os << "Constant: " << kinds.at((reg * 2) + 1);
    591             break;
    592           default:
    593             DescribeVReg(os, oat_method, code_item, reg, kind);
    594             break;
    595         }
    596         os << ")";
    597       }
    598     }
    599     if (!first) {
    600       os << "\n";
    601     }
    602   }
    603 
    604 
    605   void DumpDexCode(std::ostream& os, const DexFile& dex_file, const DexFile::CodeItem* code_item) {
    606     if (code_item != NULL) {
    607       size_t i = 0;
    608       while (i < code_item->insns_size_in_code_units_) {
    609         const Instruction* instruction = Instruction::At(&code_item->insns_[i]);
    610         os << StringPrintf("0x%04zx: %s\n", i, instruction->DumpString(&dex_file).c_str());
    611         i += instruction->SizeInCodeUnits();
    612       }
    613     }
    614   }
    615 
    616   void DumpVerifier(std::ostream& os, uint32_t dex_method_idx, const DexFile* dex_file,
    617                     const DexFile::ClassDef& class_def, const DexFile::CodeItem* code_item,
    618                     uint32_t method_access_flags) {
    619     if ((method_access_flags & kAccNative) == 0) {
    620       ScopedObjectAccess soa(Thread::Current());
    621       mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(*dex_file);
    622       mirror::ClassLoader* class_loader = NULL;
    623       verifier::MethodVerifier::VerifyMethodAndDump(os, dex_method_idx, dex_file, dex_cache,
    624                                                     class_loader, &class_def, code_item, NULL,
    625                                                     method_access_flags);
    626     }
    627   }
    628 
    629   void DumpCode(std::ostream& os,  const OatFile::OatMethod& oat_method,
    630                 uint32_t dex_method_idx, const DexFile* dex_file,
    631                 const DexFile::ClassDef& class_def, const DexFile::CodeItem* code_item,
    632                 uint32_t method_access_flags) {
    633     const void* code = oat_method.GetCode();
    634     size_t code_size = oat_method.GetCodeSize();
    635     if (code == NULL || code_size == 0) {
    636       os << "NO CODE!\n";
    637       return;
    638     }
    639     const uint8_t* native_pc = reinterpret_cast<const uint8_t*>(code);
    640     size_t offset = 0;
    641     const bool kDumpVRegs = (Runtime::Current() != NULL);
    642     while (offset < code_size) {
    643       DumpMappingAtOffset(os, oat_method, offset, false);
    644       offset += disassembler_->Dump(os, native_pc + offset);
    645       uint32_t dex_pc = DumpMappingAtOffset(os, oat_method, offset, true);
    646       if (dex_pc != DexFile::kDexNoIndex) {
    647         DumpGcMapAtNativePcOffset(os, oat_method, code_item, offset);
    648         if (kDumpVRegs) {
    649           DumpVRegsAtDexPc(os, oat_method, dex_method_idx, dex_file, class_def, code_item,
    650                            method_access_flags, dex_pc);
    651         }
    652       }
    653     }
    654   }
    655 
    656   const std::string host_prefix_;
    657   const OatFile& oat_file_;
    658   std::vector<const OatFile::OatDexFile*> oat_dex_files_;
    659   std::set<uint32_t> offsets_;
    660   UniquePtr<Disassembler> disassembler_;
    661 };
    662 
    663 class ImageDumper {
    664  public:
    665   explicit ImageDumper(std::ostream* os, const std::string& image_filename,
    666                        const std::string& host_prefix, gc::space::ImageSpace& image_space,
    667                        const ImageHeader& image_header)
    668       : os_(os), image_filename_(image_filename), host_prefix_(host_prefix),
    669         image_space_(image_space), image_header_(image_header) {}
    670 
    671   void Dump() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    672     std::ostream& os = *os_;
    673     os << "MAGIC: " << image_header_.GetMagic() << "\n\n";
    674 
    675     os << "IMAGE BEGIN: " << reinterpret_cast<void*>(image_header_.GetImageBegin()) << "\n\n";
    676 
    677     os << "IMAGE BITMAP OFFSET: " << reinterpret_cast<void*>(image_header_.GetImageBitmapOffset())
    678        << " SIZE: " << reinterpret_cast<void*>(image_header_.GetImageBitmapSize()) << "\n\n";
    679 
    680     os << "OAT CHECKSUM: " << StringPrintf("0x%08x\n\n", image_header_.GetOatChecksum());
    681 
    682     os << "OAT FILE BEGIN:" << reinterpret_cast<void*>(image_header_.GetOatFileBegin()) << "\n\n";
    683 
    684     os << "OAT DATA BEGIN:" << reinterpret_cast<void*>(image_header_.GetOatDataBegin()) << "\n\n";
    685 
    686     os << "OAT DATA END:" << reinterpret_cast<void*>(image_header_.GetOatDataEnd()) << "\n\n";
    687 
    688     os << "OAT FILE END:" << reinterpret_cast<void*>(image_header_.GetOatFileEnd()) << "\n\n";
    689 
    690     {
    691       os << "ROOTS: " << reinterpret_cast<void*>(image_header_.GetImageRoots()) << "\n";
    692       Indenter indent1_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
    693       std::ostream indent1_os(&indent1_filter);
    694       CHECK_EQ(arraysize(image_roots_descriptions_), size_t(ImageHeader::kImageRootsMax));
    695       for (int i = 0; i < ImageHeader::kImageRootsMax; i++) {
    696         ImageHeader::ImageRoot image_root = static_cast<ImageHeader::ImageRoot>(i);
    697         const char* image_root_description = image_roots_descriptions_[i];
    698         mirror::Object* image_root_object = image_header_.GetImageRoot(image_root);
    699         indent1_os << StringPrintf("%s: %p\n", image_root_description, image_root_object);
    700         if (image_root_object->IsObjectArray()) {
    701           Indenter indent2_filter(indent1_os.rdbuf(), kIndentChar, kIndentBy1Count);
    702           std::ostream indent2_os(&indent2_filter);
    703           // TODO: replace down_cast with AsObjectArray (g++ currently has a problem with this)
    704           mirror::ObjectArray<mirror::Object>* image_root_object_array
    705               = down_cast<mirror::ObjectArray<mirror::Object>*>(image_root_object);
    706           //  = image_root_object->AsObjectArray<Object>();
    707           for (int i = 0; i < image_root_object_array->GetLength(); i++) {
    708             mirror::Object* value = image_root_object_array->Get(i);
    709             if (value != NULL) {
    710               indent2_os << i << ": ";
    711               PrettyObjectValue(indent2_os, value->GetClass(), value);
    712             } else {
    713               indent2_os << i << ": null\n";
    714             }
    715           }
    716         }
    717       }
    718     }
    719     os << "\n";
    720 
    721     ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
    722     mirror::Object* oat_location_object = image_header_.GetImageRoot(ImageHeader::kOatLocation);
    723     std::string oat_location(oat_location_object->AsString()->ToModifiedUtf8());
    724     os << "OAT LOCATION: " << oat_location;
    725     if (!host_prefix_.empty()) {
    726       oat_location = host_prefix_ + oat_location;
    727       os << " (" << oat_location << ")";
    728     }
    729     os << "\n";
    730     const OatFile* oat_file = class_linker->FindOatFileFromOatLocation(oat_location);
    731     if (oat_file == NULL) {
    732       os << "NOT FOUND\n";
    733       return;
    734     }
    735     os << "\n";
    736 
    737     stats_.oat_file_bytes = oat_file->Size();
    738 
    739     oat_dumper_.reset(new OatDumper(host_prefix_, *oat_file));
    740 
    741     for (const OatFile::OatDexFile* oat_dex_file : oat_file->GetOatDexFiles()) {
    742       CHECK(oat_dex_file != NULL);
    743       stats_.oat_dex_file_sizes.push_back(std::make_pair(oat_dex_file->GetDexFileLocation(),
    744                                                          oat_dex_file->FileSize()));
    745     }
    746 
    747     os << "OBJECTS:\n" << std::flush;
    748 
    749     // Loop through all the image spaces and dump their objects.
    750     gc::Heap* heap = Runtime::Current()->GetHeap();
    751     const std::vector<gc::space::ContinuousSpace*>& spaces = heap->GetContinuousSpaces();
    752     Thread* self = Thread::Current();
    753     {
    754       WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
    755       heap->FlushAllocStack();
    756     }
    757     {
    758       std::ostream* saved_os = os_;
    759       Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
    760       std::ostream indent_os(&indent_filter);
    761       os_ = &indent_os;
    762       ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
    763       for (const auto& space : spaces) {
    764         if (space->IsImageSpace()) {
    765           gc::space::ImageSpace* image_space = space->AsImageSpace();
    766           image_space->GetLiveBitmap()->Walk(ImageDumper::Callback, this);
    767           indent_os << "\n";
    768         }
    769       }
    770       // Dump the large objects separately.
    771       heap->GetLargeObjectsSpace()->GetLiveObjects()->Walk(ImageDumper::Callback, this);
    772       indent_os << "\n";
    773       os_ = saved_os;
    774     }
    775     os << "STATS:\n" << std::flush;
    776     UniquePtr<File> file(OS::OpenFileForReading(image_filename_.c_str()));
    777     if (file.get() == NULL) {
    778       std::string cache_location(GetDalvikCacheFilenameOrDie(image_filename_));
    779       file.reset(OS::OpenFileForReading(cache_location.c_str()));
    780       if (file.get() == NULL) {
    781           LOG(WARNING) << "Failed to find image in " << image_filename_
    782                        << " and " << cache_location;
    783       }
    784     }
    785     if (file.get() != NULL) {
    786         stats_.file_bytes = file->GetLength();
    787     }
    788     size_t header_bytes = sizeof(ImageHeader);
    789     stats_.header_bytes = header_bytes;
    790     size_t alignment_bytes = RoundUp(header_bytes, kObjectAlignment) - header_bytes;
    791     stats_.alignment_bytes += alignment_bytes;
    792     stats_.alignment_bytes += image_header_.GetImageBitmapOffset() - image_header_.GetImageSize();
    793     stats_.bitmap_bytes += image_header_.GetImageBitmapSize();
    794     stats_.Dump(os);
    795     os << "\n";
    796 
    797     os << std::flush;
    798 
    799     oat_dumper_->Dump(os);
    800   }
    801 
    802  private:
    803   static void PrettyObjectValue(std::ostream& os, mirror::Class* type, mirror::Object* value)
    804       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    805     CHECK(type != NULL);
    806     if (value == NULL) {
    807       os << StringPrintf("null   %s\n", PrettyDescriptor(type).c_str());
    808     } else if (type->IsStringClass()) {
    809       mirror::String* string = value->AsString();
    810       os << StringPrintf("%p   String: %s\n", string,
    811                          PrintableString(string->ToModifiedUtf8()).c_str());
    812     } else if (type->IsClassClass()) {
    813       mirror::Class* klass = value->AsClass();
    814       os << StringPrintf("%p   Class: %s\n", klass, PrettyDescriptor(klass).c_str());
    815     } else if (type->IsArtFieldClass()) {
    816       mirror::ArtField* field = value->AsArtField();
    817       os << StringPrintf("%p   Field: %s\n", field, PrettyField(field).c_str());
    818     } else if (type->IsArtMethodClass()) {
    819       mirror::ArtMethod* method = value->AsArtMethod();
    820       os << StringPrintf("%p   Method: %s\n", method, PrettyMethod(method).c_str());
    821     } else {
    822       os << StringPrintf("%p   %s\n", value, PrettyDescriptor(type).c_str());
    823     }
    824   }
    825 
    826   static void PrintField(std::ostream& os, mirror::ArtField* field, mirror::Object* obj)
    827       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    828     FieldHelper fh(field);
    829     const char* descriptor = fh.GetTypeDescriptor();
    830     os << StringPrintf("%s: ", fh.GetName());
    831     if (descriptor[0] != 'L' && descriptor[0] != '[') {
    832       mirror::Class* type = fh.GetType();
    833       if (type->IsPrimitiveLong()) {
    834         os << StringPrintf("%lld (0x%llx)\n", field->Get64(obj), field->Get64(obj));
    835       } else if (type->IsPrimitiveDouble()) {
    836         os << StringPrintf("%f (%a)\n", field->GetDouble(obj), field->GetDouble(obj));
    837       } else if (type->IsPrimitiveFloat()) {
    838         os << StringPrintf("%f (%a)\n", field->GetFloat(obj), field->GetFloat(obj));
    839       } else {
    840         DCHECK(type->IsPrimitive());
    841         os << StringPrintf("%d (0x%x)\n", field->Get32(obj), field->Get32(obj));
    842       }
    843     } else {
    844       // Get the value, don't compute the type unless it is non-null as we don't want
    845       // to cause class loading.
    846       mirror::Object* value = field->GetObj(obj);
    847       if (value == NULL) {
    848         os << StringPrintf("null   %s\n", PrettyDescriptor(descriptor).c_str());
    849       } else {
    850         // Grab the field type without causing resolution.
    851         mirror::Class* field_type = fh.GetType(false);
    852         if (field_type != NULL) {
    853           PrettyObjectValue(os, field_type, value);
    854         } else {
    855           os << StringPrintf("%p   %s\n", value, PrettyDescriptor(descriptor).c_str());
    856         }
    857       }
    858     }
    859   }
    860 
    861   static void DumpFields(std::ostream& os, mirror::Object* obj, mirror::Class* klass)
    862       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    863     mirror::Class* super = klass->GetSuperClass();
    864     if (super != NULL) {
    865       DumpFields(os, obj, super);
    866     }
    867     mirror::ObjectArray<mirror::ArtField>* fields = klass->GetIFields();
    868     if (fields != NULL) {
    869       for (int32_t i = 0; i < fields->GetLength(); i++) {
    870         mirror::ArtField* field = fields->Get(i);
    871         PrintField(os, field, obj);
    872       }
    873     }
    874   }
    875 
    876   bool InDumpSpace(const mirror::Object* object) {
    877     return image_space_.Contains(object);
    878   }
    879 
    880   const void* GetOatCodeBegin(mirror::ArtMethod* m)
    881       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    882     const void* code = m->GetEntryPointFromCompiledCode();
    883     if (code == GetResolutionTrampoline(Runtime::Current()->GetClassLinker())) {
    884       code = oat_dumper_->GetOatCode(m);
    885     }
    886     if (oat_dumper_->GetInstructionSet() == kThumb2) {
    887       code = reinterpret_cast<void*>(reinterpret_cast<uint32_t>(code) & ~0x1);
    888     }
    889     return code;
    890   }
    891 
    892   uint32_t GetOatCodeSize(mirror::ArtMethod* m)
    893       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    894     const uint32_t* oat_code_begin = reinterpret_cast<const uint32_t*>(GetOatCodeBegin(m));
    895     if (oat_code_begin == NULL) {
    896       return 0;
    897     }
    898     return oat_code_begin[-1];
    899   }
    900 
    901   const void* GetOatCodeEnd(mirror::ArtMethod* m)
    902       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    903     const uint8_t* oat_code_begin = reinterpret_cast<const uint8_t*>(GetOatCodeBegin(m));
    904     if (oat_code_begin == NULL) {
    905       return NULL;
    906     }
    907     return oat_code_begin + GetOatCodeSize(m);
    908   }
    909 
    910   static void Callback(mirror::Object* obj, void* arg)
    911       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    912     DCHECK(obj != NULL);
    913     DCHECK(arg != NULL);
    914     ImageDumper* state = reinterpret_cast<ImageDumper*>(arg);
    915     if (!state->InDumpSpace(obj)) {
    916       return;
    917     }
    918 
    919     size_t object_bytes = obj->SizeOf();
    920     size_t alignment_bytes = RoundUp(object_bytes, kObjectAlignment) - object_bytes;
    921     state->stats_.object_bytes += object_bytes;
    922     state->stats_.alignment_bytes += alignment_bytes;
    923 
    924     std::ostream& os = *state->os_;
    925     mirror::Class* obj_class = obj->GetClass();
    926     if (obj_class->IsArrayClass()) {
    927       os << StringPrintf("%p: %s length:%d\n", obj, PrettyDescriptor(obj_class).c_str(),
    928                          obj->AsArray()->GetLength());
    929     } else if (obj->IsClass()) {
    930       mirror::Class* klass = obj->AsClass();
    931       os << StringPrintf("%p: java.lang.Class \"%s\" (", obj, PrettyDescriptor(klass).c_str())
    932          << klass->GetStatus() << ")\n";
    933     } else if (obj->IsArtField()) {
    934       os << StringPrintf("%p: java.lang.reflect.ArtField %s\n", obj,
    935                          PrettyField(obj->AsArtField()).c_str());
    936     } else if (obj->IsArtMethod()) {
    937       os << StringPrintf("%p: java.lang.reflect.ArtMethod %s\n", obj,
    938                          PrettyMethod(obj->AsArtMethod()).c_str());
    939     } else if (obj_class->IsStringClass()) {
    940       os << StringPrintf("%p: java.lang.String %s\n", obj,
    941                          PrintableString(obj->AsString()->ToModifiedUtf8()).c_str());
    942     } else {
    943       os << StringPrintf("%p: %s\n", obj, PrettyDescriptor(obj_class).c_str());
    944     }
    945     Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
    946     std::ostream indent_os(&indent_filter);
    947     DumpFields(indent_os, obj, obj_class);
    948     if (obj->IsObjectArray()) {
    949       mirror::ObjectArray<mirror::Object>* obj_array = obj->AsObjectArray<mirror::Object>();
    950       int32_t length = obj_array->GetLength();
    951       for (int32_t i = 0; i < length; i++) {
    952         mirror::Object* value = obj_array->Get(i);
    953         size_t run = 0;
    954         for (int32_t j = i + 1; j < length; j++) {
    955           if (value == obj_array->Get(j)) {
    956             run++;
    957           } else {
    958             break;
    959           }
    960         }
    961         if (run == 0) {
    962           indent_os << StringPrintf("%d: ", i);
    963         } else {
    964           indent_os << StringPrintf("%d to %zd: ", i, i + run);
    965           i = i + run;
    966         }
    967         mirror::Class* value_class = value == NULL ? obj_class->GetComponentType() : value->GetClass();
    968         PrettyObjectValue(indent_os, value_class, value);
    969       }
    970     } else if (obj->IsClass()) {
    971       mirror::ObjectArray<mirror::ArtField>* sfields = obj->AsClass()->GetSFields();
    972       if (sfields != NULL) {
    973         indent_os << "STATICS:\n";
    974         Indenter indent2_filter(indent_os.rdbuf(), kIndentChar, kIndentBy1Count);
    975         std::ostream indent2_os(&indent2_filter);
    976         for (int32_t i = 0; i < sfields->GetLength(); i++) {
    977           mirror::ArtField* field = sfields->Get(i);
    978           PrintField(indent2_os, field, field->GetDeclaringClass());
    979         }
    980       }
    981     } else if (obj->IsArtMethod()) {
    982       mirror::ArtMethod* method = obj->AsArtMethod();
    983       if (method->IsNative()) {
    984         DCHECK(method->GetNativeGcMap() == NULL) << PrettyMethod(method);
    985         DCHECK(method->GetMappingTable() == NULL) << PrettyMethod(method);
    986         bool first_occurrence;
    987         const void* oat_code = state->GetOatCodeBegin(method);
    988         uint32_t oat_code_size = state->GetOatCodeSize(method);
    989         state->ComputeOatSize(oat_code, &first_occurrence);
    990         if (first_occurrence) {
    991           state->stats_.native_to_managed_code_bytes += oat_code_size;
    992         }
    993         if (oat_code != method->GetEntryPointFromCompiledCode()) {
    994           indent_os << StringPrintf("OAT CODE: %p\n", oat_code);
    995         }
    996       } else if (method->IsAbstract() || method->IsCalleeSaveMethod() ||
    997           method->IsResolutionMethod() || MethodHelper(method).IsClassInitializer()) {
    998         DCHECK(method->GetNativeGcMap() == NULL) << PrettyMethod(method);
    999         DCHECK(method->GetMappingTable() == NULL) << PrettyMethod(method);
   1000       } else {
   1001         // TODO: we check there is a GC map here, we may not have a GC map if the code is pointing
   1002         //       to the quick/portable to interpreter bridge.
   1003         CHECK(method->GetNativeGcMap() != NULL) << PrettyMethod(method);
   1004 
   1005         const DexFile::CodeItem* code_item = MethodHelper(method).GetCodeItem();
   1006         size_t dex_instruction_bytes = code_item->insns_size_in_code_units_ * 2;
   1007         state->stats_.dex_instruction_bytes += dex_instruction_bytes;
   1008 
   1009         bool first_occurrence;
   1010         size_t gc_map_bytes = state->ComputeOatSize(method->GetNativeGcMap(), &first_occurrence);
   1011         if (first_occurrence) {
   1012           state->stats_.gc_map_bytes += gc_map_bytes;
   1013         }
   1014 
   1015         size_t pc_mapping_table_bytes =
   1016             state->ComputeOatSize(method->GetMappingTable(), &first_occurrence);
   1017         if (first_occurrence) {
   1018           state->stats_.pc_mapping_table_bytes += pc_mapping_table_bytes;
   1019         }
   1020 
   1021         size_t vmap_table_bytes =
   1022             state->ComputeOatSize(method->GetVmapTable(), &first_occurrence);
   1023         if (first_occurrence) {
   1024           state->stats_.vmap_table_bytes += vmap_table_bytes;
   1025         }
   1026 
   1027         const void* oat_code_begin = state->GetOatCodeBegin(method);
   1028         const void* oat_code_end = state->GetOatCodeEnd(method);
   1029         uint32_t oat_code_size = state->GetOatCodeSize(method);
   1030         state->ComputeOatSize(oat_code_begin, &first_occurrence);
   1031         if (first_occurrence) {
   1032           state->stats_.managed_code_bytes += oat_code_size;
   1033           if (method->IsConstructor()) {
   1034             if (method->IsStatic()) {
   1035               state->stats_.class_initializer_code_bytes += oat_code_size;
   1036             } else if (dex_instruction_bytes > kLargeConstructorDexBytes) {
   1037               state->stats_.large_initializer_code_bytes += oat_code_size;
   1038             }
   1039           } else if (dex_instruction_bytes > kLargeMethodDexBytes) {
   1040             state->stats_.large_method_code_bytes += oat_code_size;
   1041           }
   1042         }
   1043         state->stats_.managed_code_bytes_ignoring_deduplication += oat_code_size;
   1044 
   1045         indent_os << StringPrintf("OAT CODE: %p-%p\n", oat_code_begin, oat_code_end);
   1046         indent_os << StringPrintf("SIZE: Dex Instructions=%zd GC=%zd Mapping=%zd\n",
   1047                                   dex_instruction_bytes, gc_map_bytes, pc_mapping_table_bytes);
   1048 
   1049         size_t total_size = dex_instruction_bytes + gc_map_bytes + pc_mapping_table_bytes +
   1050             vmap_table_bytes + oat_code_size + object_bytes;
   1051 
   1052         double expansion =
   1053             static_cast<double>(oat_code_size) / static_cast<double>(dex_instruction_bytes);
   1054         state->stats_.ComputeOutliers(total_size, expansion, method);
   1055       }
   1056     }
   1057     state->stats_.Update(ClassHelper(obj_class).GetDescriptor(), object_bytes);
   1058   }
   1059 
   1060   std::set<const void*> already_seen_;
   1061   // Compute the size of the given data within the oat file and whether this is the first time
   1062   // this data has been requested
   1063   size_t ComputeOatSize(const void* oat_data, bool* first_occurrence) {
   1064     if (already_seen_.count(oat_data) == 0) {
   1065       *first_occurrence = true;
   1066       already_seen_.insert(oat_data);
   1067     } else {
   1068       *first_occurrence = false;
   1069     }
   1070     return oat_dumper_->ComputeSize(oat_data);
   1071   }
   1072 
   1073  public:
   1074   struct Stats {
   1075     size_t oat_file_bytes;
   1076     size_t file_bytes;
   1077 
   1078     size_t header_bytes;
   1079     size_t object_bytes;
   1080     size_t bitmap_bytes;
   1081     size_t alignment_bytes;
   1082 
   1083     size_t managed_code_bytes;
   1084     size_t managed_code_bytes_ignoring_deduplication;
   1085     size_t managed_to_native_code_bytes;
   1086     size_t native_to_managed_code_bytes;
   1087     size_t class_initializer_code_bytes;
   1088     size_t large_initializer_code_bytes;
   1089     size_t large_method_code_bytes;
   1090 
   1091     size_t gc_map_bytes;
   1092     size_t pc_mapping_table_bytes;
   1093     size_t vmap_table_bytes;
   1094 
   1095     size_t dex_instruction_bytes;
   1096 
   1097     std::vector<mirror::ArtMethod*> method_outlier;
   1098     std::vector<size_t> method_outlier_size;
   1099     std::vector<double> method_outlier_expansion;
   1100     std::vector<std::pair<std::string, size_t> > oat_dex_file_sizes;
   1101 
   1102     explicit Stats()
   1103         : oat_file_bytes(0),
   1104           file_bytes(0),
   1105           header_bytes(0),
   1106           object_bytes(0),
   1107           bitmap_bytes(0),
   1108           alignment_bytes(0),
   1109           managed_code_bytes(0),
   1110           managed_code_bytes_ignoring_deduplication(0),
   1111           managed_to_native_code_bytes(0),
   1112           native_to_managed_code_bytes(0),
   1113           class_initializer_code_bytes(0),
   1114           large_initializer_code_bytes(0),
   1115           large_method_code_bytes(0),
   1116           gc_map_bytes(0),
   1117           pc_mapping_table_bytes(0),
   1118           vmap_table_bytes(0),
   1119           dex_instruction_bytes(0) {}
   1120 
   1121     struct SizeAndCount {
   1122       SizeAndCount(size_t bytes, size_t count) : bytes(bytes), count(count) {}
   1123       size_t bytes;
   1124       size_t count;
   1125     };
   1126     typedef SafeMap<std::string, SizeAndCount> SizeAndCountTable;
   1127     SizeAndCountTable sizes_and_counts;
   1128 
   1129     void Update(const std::string& descriptor, size_t object_bytes) {
   1130       SizeAndCountTable::iterator it = sizes_and_counts.find(descriptor);
   1131       if (it != sizes_and_counts.end()) {
   1132         it->second.bytes += object_bytes;
   1133         it->second.count += 1;
   1134       } else {
   1135         sizes_and_counts.Put(descriptor, SizeAndCount(object_bytes, 1));
   1136       }
   1137     }
   1138 
   1139     double PercentOfOatBytes(size_t size) {
   1140       return (static_cast<double>(size) / static_cast<double>(oat_file_bytes)) * 100;
   1141     }
   1142 
   1143     double PercentOfFileBytes(size_t size) {
   1144       return (static_cast<double>(size) / static_cast<double>(file_bytes)) * 100;
   1145     }
   1146 
   1147     double PercentOfObjectBytes(size_t size) {
   1148       return (static_cast<double>(size) / static_cast<double>(object_bytes)) * 100;
   1149     }
   1150 
   1151     void ComputeOutliers(size_t total_size, double expansion, mirror::ArtMethod* method) {
   1152       method_outlier_size.push_back(total_size);
   1153       method_outlier_expansion.push_back(expansion);
   1154       method_outlier.push_back(method);
   1155     }
   1156 
   1157     void DumpOutliers(std::ostream& os)
   1158         SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   1159       size_t sum_of_sizes = 0;
   1160       size_t sum_of_sizes_squared = 0;
   1161       size_t sum_of_expansion = 0;
   1162       size_t sum_of_expansion_squared = 0;
   1163       size_t n = method_outlier_size.size();
   1164       for (size_t i = 0; i < n; i++) {
   1165         size_t cur_size = method_outlier_size[i];
   1166         sum_of_sizes += cur_size;
   1167         sum_of_sizes_squared += cur_size * cur_size;
   1168         double cur_expansion = method_outlier_expansion[i];
   1169         sum_of_expansion += cur_expansion;
   1170         sum_of_expansion_squared += cur_expansion * cur_expansion;
   1171       }
   1172       size_t size_mean = sum_of_sizes / n;
   1173       size_t size_variance = (sum_of_sizes_squared - sum_of_sizes * size_mean) / (n - 1);
   1174       double expansion_mean = sum_of_expansion / n;
   1175       double expansion_variance =
   1176           (sum_of_expansion_squared - sum_of_expansion * expansion_mean) / (n - 1);
   1177 
   1178       // Dump methods whose size is a certain number of standard deviations from the mean
   1179       size_t dumped_values = 0;
   1180       size_t skipped_values = 0;
   1181       for (size_t i = 100; i > 0; i--) {  // i is the current number of standard deviations
   1182         size_t cur_size_variance = i * i * size_variance;
   1183         bool first = true;
   1184         for (size_t j = 0; j < n; j++) {
   1185           size_t cur_size = method_outlier_size[j];
   1186           if (cur_size > size_mean) {
   1187             size_t cur_var = cur_size - size_mean;
   1188             cur_var = cur_var * cur_var;
   1189             if (cur_var > cur_size_variance) {
   1190               if (dumped_values > 20) {
   1191                 if (i == 1) {
   1192                   skipped_values++;
   1193                 } else {
   1194                   i = 2;  // jump to counting for 1 standard deviation
   1195                   break;
   1196                 }
   1197               } else {
   1198                 if (first) {
   1199                   os << "\nBig methods (size > " << i << " standard deviations the norm):\n";
   1200                   first = false;
   1201                 }
   1202                 os << PrettyMethod(method_outlier[j]) << " requires storage of "
   1203                     << PrettySize(cur_size) << "\n";
   1204                 method_outlier_size[j] = 0;  // don't consider this method again
   1205                 dumped_values++;
   1206               }
   1207             }
   1208           }
   1209         }
   1210       }
   1211       if (skipped_values > 0) {
   1212         os << "... skipped " << skipped_values
   1213            << " methods with size > 1 standard deviation from the norm\n";
   1214       }
   1215       os << std::flush;
   1216 
   1217       // Dump methods whose expansion is a certain number of standard deviations from the mean
   1218       dumped_values = 0;
   1219       skipped_values = 0;
   1220       for (size_t i = 10; i > 0; i--) {  // i is the current number of standard deviations
   1221         double cur_expansion_variance = i * i * expansion_variance;
   1222         bool first = true;
   1223         for (size_t j = 0; j < n; j++) {
   1224           double cur_expansion = method_outlier_expansion[j];
   1225           if (cur_expansion > expansion_mean) {
   1226             size_t cur_var = cur_expansion - expansion_mean;
   1227             cur_var = cur_var * cur_var;
   1228             if (cur_var > cur_expansion_variance) {
   1229               if (dumped_values > 20) {
   1230                 if (i == 1) {
   1231                   skipped_values++;
   1232                 } else {
   1233                   i = 2;  // jump to counting for 1 standard deviation
   1234                   break;
   1235                 }
   1236               } else {
   1237                 if (first) {
   1238                   os << "\nLarge expansion methods (size > " << i
   1239                       << " standard deviations the norm):\n";
   1240                   first = false;
   1241                 }
   1242                 os << PrettyMethod(method_outlier[j]) << " expanded code by "
   1243                    << cur_expansion << "\n";
   1244                 method_outlier_expansion[j] = 0.0;  // don't consider this method again
   1245                 dumped_values++;
   1246               }
   1247             }
   1248           }
   1249         }
   1250       }
   1251       if (skipped_values > 0) {
   1252         os << "... skipped " << skipped_values
   1253            << " methods with expansion > 1 standard deviation from the norm\n";
   1254       }
   1255       os << "\n" << std::flush;
   1256     }
   1257 
   1258     void Dump(std::ostream& os) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   1259       {
   1260         os << "art_file_bytes = " << PrettySize(file_bytes) << "\n\n"
   1261            << "art_file_bytes = header_bytes + object_bytes + alignment_bytes\n";
   1262         Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
   1263         std::ostream indent_os(&indent_filter);
   1264         indent_os << StringPrintf("header_bytes    =  %8zd (%2.0f%% of art file bytes)\n"
   1265                                   "object_bytes    =  %8zd (%2.0f%% of art file bytes)\n"
   1266                                   "bitmap_bytes    =  %8zd (%2.0f%% of art file bytes)\n"
   1267                                   "alignment_bytes =  %8zd (%2.0f%% of art file bytes)\n\n",
   1268                                   header_bytes, PercentOfFileBytes(header_bytes),
   1269                                   object_bytes, PercentOfFileBytes(object_bytes),
   1270                                   bitmap_bytes, PercentOfFileBytes(bitmap_bytes),
   1271                                   alignment_bytes, PercentOfFileBytes(alignment_bytes))
   1272             << std::flush;
   1273         CHECK_EQ(file_bytes, bitmap_bytes + header_bytes + object_bytes + alignment_bytes);
   1274       }
   1275 
   1276       os << "object_bytes breakdown:\n";
   1277       size_t object_bytes_total = 0;
   1278       for (const auto& sizes_and_count : sizes_and_counts) {
   1279         const std::string& descriptor(sizes_and_count.first);
   1280         double average = static_cast<double>(sizes_and_count.second.bytes) /
   1281             static_cast<double>(sizes_and_count.second.count);
   1282         double percent = PercentOfObjectBytes(sizes_and_count.second.bytes);
   1283         os << StringPrintf("%32s %8zd bytes %6zd instances "
   1284                            "(%4.0f bytes/instance) %2.0f%% of object_bytes\n",
   1285                            descriptor.c_str(), sizes_and_count.second.bytes,
   1286                            sizes_and_count.second.count, average, percent);
   1287         object_bytes_total += sizes_and_count.second.bytes;
   1288       }
   1289       os << "\n" << std::flush;
   1290       CHECK_EQ(object_bytes, object_bytes_total);
   1291 
   1292       os << StringPrintf("oat_file_bytes               = %8zd\n"
   1293                          "managed_code_bytes           = %8zd (%2.0f%% of oat file bytes)\n"
   1294                          "managed_to_native_code_bytes = %8zd (%2.0f%% of oat file bytes)\n"
   1295                          "native_to_managed_code_bytes = %8zd (%2.0f%% of oat file bytes)\n\n"
   1296                          "class_initializer_code_bytes = %8zd (%2.0f%% of oat file bytes)\n"
   1297                          "large_initializer_code_bytes = %8zd (%2.0f%% of oat file bytes)\n"
   1298                          "large_method_code_bytes      = %8zd (%2.0f%% of oat file bytes)\n\n",
   1299                          oat_file_bytes,
   1300                          managed_code_bytes, PercentOfOatBytes(managed_code_bytes),
   1301                          managed_to_native_code_bytes, PercentOfOatBytes(managed_to_native_code_bytes),
   1302                          native_to_managed_code_bytes, PercentOfOatBytes(native_to_managed_code_bytes),
   1303                          class_initializer_code_bytes, PercentOfOatBytes(class_initializer_code_bytes),
   1304                          large_initializer_code_bytes, PercentOfOatBytes(large_initializer_code_bytes),
   1305                          large_method_code_bytes, PercentOfOatBytes(large_method_code_bytes))
   1306             << "DexFile sizes:\n";
   1307       for (const std::pair<std::string, size_t>& oat_dex_file_size : oat_dex_file_sizes) {
   1308         os << StringPrintf("%s = %zd (%2.0f%% of oat file bytes)\n",
   1309                            oat_dex_file_size.first.c_str(), oat_dex_file_size.second,
   1310                            PercentOfOatBytes(oat_dex_file_size.second));
   1311       }
   1312 
   1313       os << "\n" << StringPrintf("gc_map_bytes           = %7zd (%2.0f%% of oat file bytes)\n"
   1314                                  "pc_mapping_table_bytes = %7zd (%2.0f%% of oat file bytes)\n"
   1315                                  "vmap_table_bytes       = %7zd (%2.0f%% of oat file bytes)\n\n",
   1316                                  gc_map_bytes, PercentOfOatBytes(gc_map_bytes),
   1317                                  pc_mapping_table_bytes, PercentOfOatBytes(pc_mapping_table_bytes),
   1318                                  vmap_table_bytes, PercentOfOatBytes(vmap_table_bytes))
   1319          << std::flush;
   1320 
   1321       os << StringPrintf("dex_instruction_bytes = %zd\n", dex_instruction_bytes)
   1322          << StringPrintf("managed_code_bytes expansion = %.2f (ignoring deduplication %.2f)\n\n",
   1323                          static_cast<double>(managed_code_bytes) / static_cast<double>(dex_instruction_bytes),
   1324                          static_cast<double>(managed_code_bytes_ignoring_deduplication) /
   1325                              static_cast<double>(dex_instruction_bytes))
   1326          << std::flush;
   1327 
   1328       DumpOutliers(os);
   1329     }
   1330   } stats_;
   1331 
   1332  private:
   1333   enum {
   1334     // Number of bytes for a constructor to be considered large. Based on the 1000 basic block
   1335     // threshold, we assume 2 bytes per instruction and 2 instructions per block.
   1336     kLargeConstructorDexBytes = 4000,
   1337     // Number of bytes for a method to be considered large. Based on the 4000 basic block
   1338     // threshold, we assume 2 bytes per instruction and 2 instructions per block.
   1339     kLargeMethodDexBytes = 16000
   1340   };
   1341   UniquePtr<OatDumper> oat_dumper_;
   1342   std::ostream* os_;
   1343   const std::string image_filename_;
   1344   const std::string host_prefix_;
   1345   gc::space::ImageSpace& image_space_;
   1346   const ImageHeader& image_header_;
   1347 
   1348   DISALLOW_COPY_AND_ASSIGN(ImageDumper);
   1349 };
   1350 
   1351 static int oatdump(int argc, char** argv) {
   1352   InitLogging(argv);
   1353 
   1354   // Skip over argv[0].
   1355   argv++;
   1356   argc--;
   1357 
   1358   if (argc == 0) {
   1359     fprintf(stderr, "No arguments specified\n");
   1360     usage();
   1361   }
   1362 
   1363   const char* oat_filename = NULL;
   1364   const char* image_filename = NULL;
   1365   const char* boot_image_filename = NULL;
   1366   std::string elf_filename_prefix;
   1367   UniquePtr<std::string> host_prefix;
   1368   std::ostream* os = &std::cout;
   1369   UniquePtr<std::ofstream> out;
   1370 
   1371   for (int i = 0; i < argc; i++) {
   1372     const StringPiece option(argv[i]);
   1373     if (option.starts_with("--oat-file=")) {
   1374       oat_filename = option.substr(strlen("--oat-file=")).data();
   1375     } else if (option.starts_with("--image=")) {
   1376       image_filename = option.substr(strlen("--image=")).data();
   1377     } else if (option.starts_with("--boot-image=")) {
   1378       boot_image_filename = option.substr(strlen("--boot-image=")).data();
   1379     } else if (option.starts_with("--host-prefix=")) {
   1380       host_prefix.reset(new std::string(option.substr(strlen("--host-prefix=")).data()));
   1381     } else if (option.starts_with("--output=")) {
   1382       const char* filename = option.substr(strlen("--output=")).data();
   1383       out.reset(new std::ofstream(filename));
   1384       if (!out->good()) {
   1385         fprintf(stderr, "Failed to open output filename %s\n", filename);
   1386         usage();
   1387       }
   1388       os = out.get();
   1389     } else {
   1390       fprintf(stderr, "Unknown argument %s\n", option.data());
   1391       usage();
   1392     }
   1393   }
   1394 
   1395   if (image_filename == NULL && oat_filename == NULL) {
   1396     fprintf(stderr, "Either --image or --oat must be specified\n");
   1397     return EXIT_FAILURE;
   1398   }
   1399 
   1400   if (image_filename != NULL && oat_filename != NULL) {
   1401     fprintf(stderr, "Either --image or --oat must be specified but not both\n");
   1402     return EXIT_FAILURE;
   1403   }
   1404 
   1405   if (host_prefix.get() == NULL) {
   1406     const char* android_product_out = getenv("ANDROID_PRODUCT_OUT");
   1407     if (android_product_out != NULL) {
   1408         host_prefix.reset(new std::string(android_product_out));
   1409     } else {
   1410         host_prefix.reset(new std::string(""));
   1411     }
   1412   }
   1413 
   1414   if (oat_filename != NULL) {
   1415     OatFile* oat_file =
   1416         OatFile::Open(oat_filename, oat_filename, NULL, false);
   1417     if (oat_file == NULL) {
   1418       fprintf(stderr, "Failed to open oat file from %s\n", oat_filename);
   1419       return EXIT_FAILURE;
   1420     }
   1421     OatDumper oat_dumper(*host_prefix.get(), *oat_file);
   1422     oat_dumper.Dump(*os);
   1423     return EXIT_SUCCESS;
   1424   }
   1425 
   1426   Runtime::Options options;
   1427   std::string image_option;
   1428   std::string oat_option;
   1429   std::string boot_image_option;
   1430   std::string boot_oat_option;
   1431 
   1432   // We are more like a compiler than a run-time. We don't want to execute code.
   1433   options.push_back(std::make_pair("compiler", reinterpret_cast<void*>(NULL)));
   1434 
   1435   if (boot_image_filename != NULL) {
   1436     boot_image_option += "-Ximage:";
   1437     boot_image_option += boot_image_filename;
   1438     options.push_back(std::make_pair(boot_image_option.c_str(), reinterpret_cast<void*>(NULL)));
   1439   }
   1440   if (image_filename != NULL) {
   1441     image_option += "-Ximage:";
   1442     image_option += image_filename;
   1443     options.push_back(std::make_pair(image_option.c_str(), reinterpret_cast<void*>(NULL)));
   1444   }
   1445 
   1446   if (!host_prefix->empty()) {
   1447     options.push_back(std::make_pair("host-prefix", host_prefix->c_str()));
   1448   }
   1449 
   1450   if (!Runtime::Create(options, false)) {
   1451     fprintf(stderr, "Failed to create runtime\n");
   1452     return EXIT_FAILURE;
   1453   }
   1454   UniquePtr<Runtime> runtime(Runtime::Current());
   1455   // Runtime::Create acquired the mutator_lock_ that is normally given away when we Runtime::Start,
   1456   // give it away now and then switch to a more managable ScopedObjectAccess.
   1457   Thread::Current()->TransitionFromRunnableToSuspended(kNative);
   1458   ScopedObjectAccess soa(Thread::Current());
   1459 
   1460   gc::Heap* heap = Runtime::Current()->GetHeap();
   1461   gc::space::ImageSpace* image_space = heap->GetImageSpace();
   1462   CHECK(image_space != NULL);
   1463   const ImageHeader& image_header = image_space->GetImageHeader();
   1464   if (!image_header.IsValid()) {
   1465     fprintf(stderr, "Invalid image header %s\n", image_filename);
   1466     return EXIT_FAILURE;
   1467   }
   1468   ImageDumper image_dumper(os, image_filename, *host_prefix.get(), *image_space, image_header);
   1469   image_dumper.Dump();
   1470   return EXIT_SUCCESS;
   1471 }
   1472 
   1473 }  // namespace art
   1474 
   1475 int main(int argc, char** argv) {
   1476   return art::oatdump(argc, argv);
   1477 }
   1478