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