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