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