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