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