• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <map>
23 #include <set>
24 #include <string>
25 #include <unordered_map>
26 #include <vector>
27 
28 #include "arch/instruction_set_features.h"
29 #include "art_field-inl.h"
30 #include "art_method-inl.h"
31 #include "base/stl_util.h"
32 #include "base/unix_file/fd_file.h"
33 #include "class_linker.h"
34 #include "class_linker-inl.h"
35 #include "debug/elf_debug_writer.h"
36 #include "debug/method_debug_info.h"
37 #include "dex_file-inl.h"
38 #include "dex_instruction.h"
39 #include "disassembler.h"
40 #include "elf_builder.h"
41 #include "gc/space/image_space.h"
42 #include "gc/space/large_object_space.h"
43 #include "gc/space/space-inl.h"
44 #include "image-inl.h"
45 #include "indenter.h"
46 #include "linker/buffered_output_stream.h"
47 #include "linker/file_output_stream.h"
48 #include "mirror/array-inl.h"
49 #include "mirror/class-inl.h"
50 #include "mirror/dex_cache-inl.h"
51 #include "mirror/object-inl.h"
52 #include "mirror/object_array-inl.h"
53 #include "oat.h"
54 #include "oat_file-inl.h"
55 #include "oat_file_manager.h"
56 #include "os.h"
57 #include "safe_map.h"
58 #include "scoped_thread_state_change.h"
59 #include "stack_map.h"
60 #include "ScopedLocalRef.h"
61 #include "thread_list.h"
62 #include "type_lookup_table.h"
63 #include "verifier/method_verifier.h"
64 #include "well_known_classes.h"
65 
66 #include <sys/stat.h>
67 #include "cmdline.h"
68 
69 namespace art {
70 
71 const char* image_methods_descriptions_[] = {
72   "kResolutionMethod",
73   "kImtConflictMethod",
74   "kImtUnimplementedMethod",
75   "kCalleeSaveMethod",
76   "kRefsOnlySaveMethod",
77   "kRefsAndArgsSaveMethod",
78 };
79 
80 const char* image_roots_descriptions_[] = {
81   "kDexCaches",
82   "kClassRoots",
83 };
84 
85 // Map is so that we don't allocate multiple dex files for the same OatDexFile.
86 static std::map<const OatFile::OatDexFile*,
87                 std::unique_ptr<const DexFile>> opened_dex_files;
88 
OpenDexFile(const OatFile::OatDexFile * oat_dex_file,std::string * error_msg)89 const DexFile* OpenDexFile(const OatFile::OatDexFile* oat_dex_file, std::string* error_msg) {
90   DCHECK(oat_dex_file != nullptr);
91   auto it = opened_dex_files.find(oat_dex_file);
92   if (it != opened_dex_files.end()) {
93     return it->second.get();
94   }
95   const DexFile* ret = oat_dex_file->OpenDexFile(error_msg).release();
96   opened_dex_files.emplace(oat_dex_file, std::unique_ptr<const DexFile>(ret));
97   return ret;
98 }
99 
100 template <typename ElfTypes>
101 class OatSymbolizer FINAL {
102  public:
OatSymbolizer(const OatFile * oat_file,const std::string & output_name,bool no_bits)103   OatSymbolizer(const OatFile* oat_file, const std::string& output_name, bool no_bits) :
104       oat_file_(oat_file),
105       builder_(nullptr),
106       output_name_(output_name.empty() ? "symbolized.oat" : output_name),
107       no_bits_(no_bits) {
108   }
109 
Symbolize()110   bool Symbolize() {
111     const InstructionSet isa = oat_file_->GetOatHeader().GetInstructionSet();
112     const InstructionSetFeatures* features = InstructionSetFeatures::FromBitmap(
113         isa, oat_file_->GetOatHeader().GetInstructionSetFeaturesBitmap());
114 
115     File* elf_file = OS::CreateEmptyFile(output_name_.c_str());
116     std::unique_ptr<BufferedOutputStream> output_stream(
117         MakeUnique<BufferedOutputStream>(MakeUnique<FileOutputStream>(elf_file)));
118     builder_.reset(new ElfBuilder<ElfTypes>(isa, features, output_stream.get()));
119 
120     builder_->Start();
121 
122     auto* rodata = builder_->GetRoData();
123     auto* text = builder_->GetText();
124     auto* bss = builder_->GetBss();
125 
126     const uint8_t* rodata_begin = oat_file_->Begin();
127     const size_t rodata_size = oat_file_->GetOatHeader().GetExecutableOffset();
128     if (no_bits_) {
129       rodata->WriteNoBitsSection(rodata_size);
130     } else {
131       rodata->Start();
132       rodata->WriteFully(rodata_begin, rodata_size);
133       rodata->End();
134     }
135 
136     const uint8_t* text_begin = oat_file_->Begin() + rodata_size;
137     const size_t text_size = oat_file_->End() - text_begin;
138     if (no_bits_) {
139       text->WriteNoBitsSection(text_size);
140     } else {
141       text->Start();
142       text->WriteFully(text_begin, text_size);
143       text->End();
144     }
145 
146     if (oat_file_->BssSize() != 0) {
147       bss->WriteNoBitsSection(oat_file_->BssSize());
148     }
149 
150     if (isa == kMips || isa == kMips64) {
151       builder_->WriteMIPSabiflagsSection();
152     }
153     builder_->PrepareDynamicSection(
154         elf_file->GetPath(), rodata_size, text_size, oat_file_->BssSize());
155     builder_->WriteDynamicSection();
156 
157     Walk();
158     for (const auto& trampoline : debug::MakeTrampolineInfos(oat_file_->GetOatHeader())) {
159       method_debug_infos_.push_back(trampoline);
160     }
161 
162     debug::WriteDebugInfo(builder_.get(),
163                           ArrayRef<const debug::MethodDebugInfo>(method_debug_infos_),
164                           dwarf::DW_DEBUG_FRAME_FORMAT,
165                           true /* write_oat_patches */);
166 
167     builder_->End();
168 
169     return builder_->Good();
170   }
171 
Walk()172   void Walk() {
173     std::vector<const OatFile::OatDexFile*> oat_dex_files = oat_file_->GetOatDexFiles();
174     for (size_t i = 0; i < oat_dex_files.size(); i++) {
175       const OatFile::OatDexFile* oat_dex_file = oat_dex_files[i];
176       CHECK(oat_dex_file != nullptr);
177       WalkOatDexFile(oat_dex_file);
178     }
179   }
180 
WalkOatDexFile(const OatFile::OatDexFile * oat_dex_file)181   void WalkOatDexFile(const OatFile::OatDexFile* oat_dex_file) {
182     std::string error_msg;
183     const DexFile* const dex_file = OpenDexFile(oat_dex_file, &error_msg);
184     if (dex_file == nullptr) {
185       return;
186     }
187     for (size_t class_def_index = 0;
188         class_def_index < dex_file->NumClassDefs();
189         class_def_index++) {
190       const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index);
191       OatClassType type = oat_class.GetType();
192       switch (type) {
193         case kOatClassAllCompiled:
194         case kOatClassSomeCompiled:
195           WalkOatClass(oat_class, *dex_file, class_def_index);
196           break;
197 
198         case kOatClassNoneCompiled:
199         case kOatClassMax:
200           // Ignore.
201           break;
202       }
203     }
204   }
205 
WalkOatClass(const OatFile::OatClass & oat_class,const DexFile & dex_file,uint32_t class_def_index)206   void WalkOatClass(const OatFile::OatClass& oat_class,
207                     const DexFile& dex_file,
208                     uint32_t class_def_index) {
209     const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
210     const uint8_t* class_data = dex_file.GetClassData(class_def);
211     if (class_data == nullptr) {  // empty class such as a marker interface?
212       return;
213     }
214     // Note: even if this is an interface or a native class, we still have to walk it, as there
215     //       might be a static initializer.
216     ClassDataItemIterator it(dex_file, class_data);
217     uint32_t class_method_idx = 0;
218     for (; it.HasNextStaticField(); it.Next()) { /* skip */ }
219     for (; it.HasNextInstanceField(); it.Next()) { /* skip */ }
220     for (; it.HasNextDirectMethod() || it.HasNextVirtualMethod(); it.Next()) {
221       WalkOatMethod(oat_class.GetOatMethod(class_method_idx++),
222                     dex_file,
223                     class_def_index,
224                     it.GetMemberIndex(),
225                     it.GetMethodCodeItem(),
226                     it.GetMethodAccessFlags());
227     }
228     DCHECK(!it.HasNext());
229   }
230 
WalkOatMethod(const OatFile::OatMethod & oat_method,const DexFile & dex_file,uint32_t class_def_index,uint32_t dex_method_index,const DexFile::CodeItem * code_item,uint32_t method_access_flags)231   void WalkOatMethod(const OatFile::OatMethod& oat_method,
232                      const DexFile& dex_file,
233                      uint32_t class_def_index,
234                      uint32_t dex_method_index,
235                      const DexFile::CodeItem* code_item,
236                      uint32_t method_access_flags) {
237     if ((method_access_flags & kAccAbstract) != 0) {
238       // Abstract method, no code.
239       return;
240     }
241     const OatHeader& oat_header = oat_file_->GetOatHeader();
242     const OatQuickMethodHeader* method_header = oat_method.GetOatQuickMethodHeader();
243     if (method_header == nullptr || method_header->GetCodeSize() == 0) {
244       // No code.
245       return;
246     }
247 
248     uint32_t entry_point = oat_method.GetCodeOffset() - oat_header.GetExecutableOffset();
249     // Clear Thumb2 bit.
250     const void* code_address = EntryPointToCodePointer(reinterpret_cast<void*>(entry_point));
251 
252     debug::MethodDebugInfo info = debug::MethodDebugInfo();
253     info.trampoline_name = nullptr;
254     info.dex_file = &dex_file;
255     info.class_def_index = class_def_index;
256     info.dex_method_index = dex_method_index;
257     info.access_flags = method_access_flags;
258     info.code_item = code_item;
259     info.isa = oat_header.GetInstructionSet();
260     info.deduped = !seen_offsets_.insert(oat_method.GetCodeOffset()).second;
261     info.is_native_debuggable = oat_header.IsNativeDebuggable();
262     info.is_optimized = method_header->IsOptimized();
263     info.is_code_address_text_relative = true;
264     info.code_address = reinterpret_cast<uintptr_t>(code_address);
265     info.code_size = method_header->GetCodeSize();
266     info.frame_size_in_bytes = method_header->GetFrameSizeInBytes();
267     info.code_info = info.is_optimized ? method_header->GetOptimizedCodeInfoPtr() : nullptr;
268     info.cfi = ArrayRef<uint8_t>();
269     method_debug_infos_.push_back(info);
270   }
271 
272  private:
273   const OatFile* oat_file_;
274   std::unique_ptr<ElfBuilder<ElfTypes> > builder_;
275   std::vector<debug::MethodDebugInfo> method_debug_infos_;
276   std::unordered_set<uint32_t> seen_offsets_;
277   const std::string output_name_;
278   bool no_bits_;
279 };
280 
281 class OatDumperOptions {
282  public:
OatDumperOptions(bool dump_vmap,bool dump_code_info_stack_maps,bool disassemble_code,bool absolute_addresses,const char * class_filter,const char * method_filter,bool list_classes,bool list_methods,bool dump_header_only,const char * export_dex_location,const char * app_image,const char * app_oat,uint32_t addr2instr)283   OatDumperOptions(bool dump_vmap,
284                    bool dump_code_info_stack_maps,
285                    bool disassemble_code,
286                    bool absolute_addresses,
287                    const char* class_filter,
288                    const char* method_filter,
289                    bool list_classes,
290                    bool list_methods,
291                    bool dump_header_only,
292                    const char* export_dex_location,
293                    const char* app_image,
294                    const char* app_oat,
295                    uint32_t addr2instr)
296     : dump_vmap_(dump_vmap),
297       dump_code_info_stack_maps_(dump_code_info_stack_maps),
298       disassemble_code_(disassemble_code),
299       absolute_addresses_(absolute_addresses),
300       class_filter_(class_filter),
301       method_filter_(method_filter),
302       list_classes_(list_classes),
303       list_methods_(list_methods),
304       dump_header_only_(dump_header_only),
305       export_dex_location_(export_dex_location),
306       app_image_(app_image),
307       app_oat_(app_oat),
308       addr2instr_(addr2instr),
309       class_loader_(nullptr) {}
310 
311   const bool dump_vmap_;
312   const bool dump_code_info_stack_maps_;
313   const bool disassemble_code_;
314   const bool absolute_addresses_;
315   const char* const class_filter_;
316   const char* const method_filter_;
317   const bool list_classes_;
318   const bool list_methods_;
319   const bool dump_header_only_;
320   const char* const export_dex_location_;
321   const char* const app_image_;
322   const char* const app_oat_;
323   uint32_t addr2instr_;
324   Handle<mirror::ClassLoader>* class_loader_;
325 };
326 
327 class OatDumper {
328  public:
OatDumper(const OatFile & oat_file,const OatDumperOptions & options)329   OatDumper(const OatFile& oat_file, const OatDumperOptions& options)
330     : oat_file_(oat_file),
331       oat_dex_files_(oat_file.GetOatDexFiles()),
332       options_(options),
333       resolved_addr2instr_(0),
334       instruction_set_(oat_file_.GetOatHeader().GetInstructionSet()),
335       disassembler_(Disassembler::Create(instruction_set_,
336                                          new DisassemblerOptions(options_.absolute_addresses_,
337                                                                  oat_file.Begin(),
338                                                                  oat_file.End(),
339                                                                  true /* can_read_literals_ */))) {
340     CHECK(options_.class_loader_ != nullptr);
341     CHECK(options_.class_filter_ != nullptr);
342     CHECK(options_.method_filter_ != nullptr);
343     AddAllOffsets();
344   }
345 
~OatDumper()346   ~OatDumper() {
347     delete disassembler_;
348   }
349 
GetInstructionSet()350   InstructionSet GetInstructionSet() {
351     return instruction_set_;
352   }
353 
Dump(std::ostream & os)354   bool Dump(std::ostream& os) {
355     bool success = true;
356     const OatHeader& oat_header = oat_file_.GetOatHeader();
357 
358     os << "MAGIC:\n";
359     os << oat_header.GetMagic() << "\n\n";
360 
361     os << "LOCATION:\n";
362     os << oat_file_.GetLocation() << "\n\n";
363 
364     os << "CHECKSUM:\n";
365     os << StringPrintf("0x%08x\n\n", oat_header.GetChecksum());
366 
367     os << "INSTRUCTION SET:\n";
368     os << oat_header.GetInstructionSet() << "\n\n";
369 
370     {
371       std::unique_ptr<const InstructionSetFeatures> features(
372           InstructionSetFeatures::FromBitmap(oat_header.GetInstructionSet(),
373                                              oat_header.GetInstructionSetFeaturesBitmap()));
374       os << "INSTRUCTION SET FEATURES:\n";
375       os << features->GetFeatureString() << "\n\n";
376     }
377 
378     os << "DEX FILE COUNT:\n";
379     os << oat_header.GetDexFileCount() << "\n\n";
380 
381 #define DUMP_OAT_HEADER_OFFSET(label, offset) \
382     os << label " OFFSET:\n"; \
383     os << StringPrintf("0x%08x", oat_header.offset()); \
384     if (oat_header.offset() != 0 && options_.absolute_addresses_) { \
385       os << StringPrintf(" (%p)", oat_file_.Begin() + oat_header.offset()); \
386     } \
387     os << StringPrintf("\n\n");
388 
389     DUMP_OAT_HEADER_OFFSET("EXECUTABLE", GetExecutableOffset);
390     DUMP_OAT_HEADER_OFFSET("INTERPRETER TO INTERPRETER BRIDGE",
391                            GetInterpreterToInterpreterBridgeOffset);
392     DUMP_OAT_HEADER_OFFSET("INTERPRETER TO COMPILED CODE BRIDGE",
393                            GetInterpreterToCompiledCodeBridgeOffset);
394     DUMP_OAT_HEADER_OFFSET("JNI DLSYM LOOKUP",
395                            GetJniDlsymLookupOffset);
396     DUMP_OAT_HEADER_OFFSET("QUICK GENERIC JNI TRAMPOLINE",
397                            GetQuickGenericJniTrampolineOffset);
398     DUMP_OAT_HEADER_OFFSET("QUICK IMT CONFLICT TRAMPOLINE",
399                            GetQuickImtConflictTrampolineOffset);
400     DUMP_OAT_HEADER_OFFSET("QUICK RESOLUTION TRAMPOLINE",
401                            GetQuickResolutionTrampolineOffset);
402     DUMP_OAT_HEADER_OFFSET("QUICK TO INTERPRETER BRIDGE",
403                            GetQuickToInterpreterBridgeOffset);
404 #undef DUMP_OAT_HEADER_OFFSET
405 
406     os << "IMAGE PATCH DELTA:\n";
407     os << StringPrintf("%d (0x%08x)\n\n",
408                        oat_header.GetImagePatchDelta(),
409                        oat_header.GetImagePatchDelta());
410 
411     os << "IMAGE FILE LOCATION OAT CHECKSUM:\n";
412     os << StringPrintf("0x%08x\n\n", oat_header.GetImageFileLocationOatChecksum());
413 
414     os << "IMAGE FILE LOCATION OAT BEGIN:\n";
415     os << StringPrintf("0x%08x\n\n", oat_header.GetImageFileLocationOatDataBegin());
416 
417     // Print the key-value store.
418     {
419       os << "KEY VALUE STORE:\n";
420       size_t index = 0;
421       const char* key;
422       const char* value;
423       while (oat_header.GetStoreKeyValuePairByIndex(index, &key, &value)) {
424         os << key << " = " << value << "\n";
425         index++;
426       }
427       os << "\n";
428     }
429 
430     if (options_.absolute_addresses_) {
431       os << "BEGIN:\n";
432       os << reinterpret_cast<const void*>(oat_file_.Begin()) << "\n\n";
433 
434       os << "END:\n";
435       os << reinterpret_cast<const void*>(oat_file_.End()) << "\n\n";
436     }
437 
438     os << "SIZE:\n";
439     os << oat_file_.Size() << "\n\n";
440 
441     os << std::flush;
442 
443     // If set, adjust relative address to be searched
444     if (options_.addr2instr_ != 0) {
445       resolved_addr2instr_ = options_.addr2instr_ + oat_header.GetExecutableOffset();
446       os << "SEARCH ADDRESS (executable offset + input):\n";
447       os << StringPrintf("0x%08x\n\n", resolved_addr2instr_);
448     }
449 
450     if (!options_.dump_header_only_) {
451       for (size_t i = 0; i < oat_dex_files_.size(); i++) {
452         const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
453         CHECK(oat_dex_file != nullptr);
454 
455         // If file export selected skip file analysis
456         if (options_.export_dex_location_) {
457           if (!ExportDexFile(os, *oat_dex_file)) {
458             success = false;
459           }
460         } else {
461           if (!DumpOatDexFile(os, *oat_dex_file)) {
462             success = false;
463           }
464         }
465       }
466     }
467 
468     os << std::flush;
469     return success;
470   }
471 
ComputeSize(const void * oat_data)472   size_t ComputeSize(const void* oat_data) {
473     if (reinterpret_cast<const uint8_t*>(oat_data) < oat_file_.Begin() ||
474         reinterpret_cast<const uint8_t*>(oat_data) > oat_file_.End()) {
475       return 0;  // Address not in oat file
476     }
477     uintptr_t begin_offset = reinterpret_cast<uintptr_t>(oat_data) -
478                              reinterpret_cast<uintptr_t>(oat_file_.Begin());
479     auto it = offsets_.upper_bound(begin_offset);
480     CHECK(it != offsets_.end());
481     uintptr_t end_offset = *it;
482     return end_offset - begin_offset;
483   }
484 
GetOatInstructionSet()485   InstructionSet GetOatInstructionSet() {
486     return oat_file_.GetOatHeader().GetInstructionSet();
487   }
488 
GetQuickOatCode(ArtMethod * m)489   const void* GetQuickOatCode(ArtMethod* m) SHARED_REQUIRES(Locks::mutator_lock_) {
490     for (size_t i = 0; i < oat_dex_files_.size(); i++) {
491       const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
492       CHECK(oat_dex_file != nullptr);
493       std::string error_msg;
494       const DexFile* const dex_file = OpenDexFile(oat_dex_file, &error_msg);
495       if (dex_file == nullptr) {
496         LOG(WARNING) << "Failed to open dex file '" << oat_dex_file->GetDexFileLocation()
497             << "': " << error_msg;
498       } else {
499         const char* descriptor = m->GetDeclaringClassDescriptor();
500         const DexFile::ClassDef* class_def =
501             dex_file->FindClassDef(descriptor, ComputeModifiedUtf8Hash(descriptor));
502         if (class_def != nullptr) {
503           uint16_t class_def_index = dex_file->GetIndexForClassDef(*class_def);
504           const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index);
505           size_t method_index = m->GetMethodIndex();
506           return oat_class.GetOatMethod(method_index).GetQuickCode();
507         }
508       }
509     }
510     return nullptr;
511   }
512 
513  private:
AddAllOffsets()514   void AddAllOffsets() {
515     // We don't know the length of the code for each method, but we need to know where to stop
516     // when disassembling. What we do know is that a region of code will be followed by some other
517     // region, so if we keep a sorted sequence of the start of each region, we can infer the length
518     // of a piece of code by using upper_bound to find the start of the next region.
519     for (size_t i = 0; i < oat_dex_files_.size(); i++) {
520       const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
521       CHECK(oat_dex_file != nullptr);
522       std::string error_msg;
523       const DexFile* const dex_file = OpenDexFile(oat_dex_file, &error_msg);
524       if (dex_file == nullptr) {
525         LOG(WARNING) << "Failed to open dex file '" << oat_dex_file->GetDexFileLocation()
526             << "': " << error_msg;
527         continue;
528       }
529       offsets_.insert(reinterpret_cast<uintptr_t>(&dex_file->GetHeader()));
530       for (size_t class_def_index = 0;
531            class_def_index < dex_file->NumClassDefs();
532            class_def_index++) {
533         const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
534         const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index);
535         const uint8_t* class_data = dex_file->GetClassData(class_def);
536         if (class_data != nullptr) {
537           ClassDataItemIterator it(*dex_file, class_data);
538           SkipAllFields(it);
539           uint32_t class_method_index = 0;
540           while (it.HasNextDirectMethod()) {
541             AddOffsets(oat_class.GetOatMethod(class_method_index++));
542             it.Next();
543           }
544           while (it.HasNextVirtualMethod()) {
545             AddOffsets(oat_class.GetOatMethod(class_method_index++));
546             it.Next();
547           }
548         }
549       }
550     }
551 
552     // If the last thing in the file is code for a method, there won't be an offset for the "next"
553     // thing. Instead of having a special case in the upper_bound code, let's just add an entry
554     // for the end of the file.
555     offsets_.insert(oat_file_.Size());
556   }
557 
AlignCodeOffset(uint32_t maybe_thumb_offset)558   static uint32_t AlignCodeOffset(uint32_t maybe_thumb_offset) {
559     return maybe_thumb_offset & ~0x1;  // TODO: Make this Thumb2 specific.
560   }
561 
AddOffsets(const OatFile::OatMethod & oat_method)562   void AddOffsets(const OatFile::OatMethod& oat_method) {
563     uint32_t code_offset = oat_method.GetCodeOffset();
564     if (oat_file_.GetOatHeader().GetInstructionSet() == kThumb2) {
565       code_offset &= ~0x1;
566     }
567     offsets_.insert(code_offset);
568     offsets_.insert(oat_method.GetVmapTableOffset());
569   }
570 
DumpOatDexFile(std::ostream & os,const OatFile::OatDexFile & oat_dex_file)571   bool DumpOatDexFile(std::ostream& os, const OatFile::OatDexFile& oat_dex_file) {
572     bool success = true;
573     bool stop_analysis = false;
574     os << "OatDexFile:\n";
575     os << StringPrintf("location: %s\n", oat_dex_file.GetDexFileLocation().c_str());
576     os << StringPrintf("checksum: 0x%08x\n", oat_dex_file.GetDexFileLocationChecksum());
577 
578     // Print embedded dex file data range.
579     const uint8_t* const oat_file_begin = oat_dex_file.GetOatFile()->Begin();
580     const uint8_t* const dex_file_pointer = oat_dex_file.GetDexFilePointer();
581     uint32_t dex_offset = dchecked_integral_cast<uint32_t>(dex_file_pointer - oat_file_begin);
582     os << StringPrintf("dex-file: 0x%08x..0x%08x\n",
583                        dex_offset,
584                        dchecked_integral_cast<uint32_t>(dex_offset + oat_dex_file.FileSize() - 1));
585 
586     // Create the dex file early. A lot of print-out things depend on it.
587     std::string error_msg;
588     const DexFile* const dex_file = OpenDexFile(&oat_dex_file, &error_msg);
589     if (dex_file == nullptr) {
590       os << "NOT FOUND: " << error_msg << "\n\n";
591       os << std::flush;
592       return false;
593     }
594 
595     // Print lookup table, if it exists.
596     if (oat_dex_file.GetLookupTableData() != nullptr) {
597       uint32_t table_offset = dchecked_integral_cast<uint32_t>(
598           oat_dex_file.GetLookupTableData() - oat_file_begin);
599       uint32_t table_size = TypeLookupTable::RawDataLength(*dex_file);
600       os << StringPrintf("type-table: 0x%08x..0x%08x\n",
601                          table_offset,
602                          table_offset + table_size - 1);
603     }
604 
605     VariableIndentationOutputStream vios(&os);
606     ScopedIndentation indent1(&vios);
607     for (size_t class_def_index = 0;
608          class_def_index < dex_file->NumClassDefs();
609          class_def_index++) {
610       const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
611       const char* descriptor = dex_file->GetClassDescriptor(class_def);
612 
613       // TODO: Support regex
614       if (DescriptorToDot(descriptor).find(options_.class_filter_) == std::string::npos) {
615         continue;
616       }
617 
618       uint32_t oat_class_offset = oat_dex_file.GetOatClassOffset(class_def_index);
619       const OatFile::OatClass oat_class = oat_dex_file.GetOatClass(class_def_index);
620       os << StringPrintf("%zd: %s (offset=0x%08x) (type_idx=%d)",
621                          class_def_index, descriptor, oat_class_offset, class_def.class_idx_)
622          << " (" << oat_class.GetStatus() << ")"
623          << " (" << oat_class.GetType() << ")\n";
624       // TODO: include bitmap here if type is kOatClassSomeCompiled?
625       if (options_.list_classes_) continue;
626       if (!DumpOatClass(&vios, oat_class, *dex_file, class_def, &stop_analysis)) {
627         success = false;
628       }
629       if (stop_analysis) {
630         os << std::flush;
631         return success;
632       }
633     }
634 
635     os << std::flush;
636     return success;
637   }
638 
ExportDexFile(std::ostream & os,const OatFile::OatDexFile & oat_dex_file)639   bool ExportDexFile(std::ostream& os, const OatFile::OatDexFile& oat_dex_file) {
640     std::string error_msg;
641     std::string dex_file_location = oat_dex_file.GetDexFileLocation();
642 
643     const DexFile* const dex_file = OpenDexFile(&oat_dex_file, &error_msg);
644     if (dex_file == nullptr) {
645       os << "Failed to open dex file '" << dex_file_location << "': " << error_msg;
646       return false;
647     }
648     size_t fsize = oat_dex_file.FileSize();
649 
650     // Some quick checks just in case
651     if (fsize == 0 || fsize < sizeof(DexFile::Header)) {
652       os << "Invalid dex file\n";
653       return false;
654     }
655 
656     // Verify output directory exists
657     if (!OS::DirectoryExists(options_.export_dex_location_)) {
658       // TODO: Extend OS::DirectoryExists if symlink support is required
659       os << options_.export_dex_location_ << " output directory not found or symlink\n";
660       return false;
661     }
662 
663     // Beautify path names
664     if (dex_file_location.size() > PATH_MAX || dex_file_location.size() <= 0) {
665       return false;
666     }
667 
668     std::string dex_orig_name;
669     size_t dex_orig_pos = dex_file_location.rfind('/');
670     if (dex_orig_pos == std::string::npos)
671       dex_orig_name = dex_file_location;
672     else
673       dex_orig_name = dex_file_location.substr(dex_orig_pos + 1);
674 
675     // A more elegant approach to efficiently name user installed apps is welcome
676     if (dex_orig_name.size() == 8 && !dex_orig_name.compare("base.apk")) {
677       dex_file_location.erase(dex_orig_pos, strlen("base.apk") + 1);
678       size_t apk_orig_pos = dex_file_location.rfind('/');
679       if (apk_orig_pos != std::string::npos) {
680         dex_orig_name = dex_file_location.substr(++apk_orig_pos);
681       }
682     }
683 
684     std::string out_dex_path(options_.export_dex_location_);
685     if (out_dex_path.back() != '/') {
686       out_dex_path.append("/");
687     }
688     out_dex_path.append(dex_orig_name);
689     out_dex_path.append("_export.dex");
690     if (out_dex_path.length() > PATH_MAX) {
691       return false;
692     }
693 
694     std::unique_ptr<File> file(OS::CreateEmptyFile(out_dex_path.c_str()));
695     if (file.get() == nullptr) {
696       os << "Failed to open output dex file " << out_dex_path;
697       return false;
698     }
699 
700     if (!file->WriteFully(dex_file->Begin(), fsize)) {
701       os << "Failed to write dex file";
702       file->Erase();
703       return false;
704     }
705 
706     if (file->FlushCloseOrErase() != 0) {
707       os << "Flush and close failed";
708       return false;
709     }
710 
711     os << StringPrintf("Dex file exported at %s (%zd bytes)\n", out_dex_path.c_str(), fsize);
712     os << std::flush;
713 
714     return true;
715   }
716 
SkipAllFields(ClassDataItemIterator & it)717   static void SkipAllFields(ClassDataItemIterator& it) {
718     while (it.HasNextStaticField()) {
719       it.Next();
720     }
721     while (it.HasNextInstanceField()) {
722       it.Next();
723     }
724   }
725 
DumpOatClass(VariableIndentationOutputStream * vios,const OatFile::OatClass & oat_class,const DexFile & dex_file,const DexFile::ClassDef & class_def,bool * stop_analysis)726   bool DumpOatClass(VariableIndentationOutputStream* vios,
727                     const OatFile::OatClass& oat_class, const DexFile& dex_file,
728                     const DexFile::ClassDef& class_def, bool* stop_analysis) {
729     bool success = true;
730     bool addr_found = false;
731     const uint8_t* class_data = dex_file.GetClassData(class_def);
732     if (class_data == nullptr) {  // empty class such as a marker interface?
733       vios->Stream() << std::flush;
734       return success;
735     }
736     ClassDataItemIterator it(dex_file, class_data);
737     SkipAllFields(it);
738     uint32_t class_method_index = 0;
739     while (it.HasNextDirectMethod()) {
740       if (!DumpOatMethod(vios, class_def, class_method_index, oat_class, dex_file,
741                          it.GetMemberIndex(), it.GetMethodCodeItem(),
742                          it.GetRawMemberAccessFlags(), &addr_found)) {
743         success = false;
744       }
745       if (addr_found) {
746         *stop_analysis = true;
747         return success;
748       }
749       class_method_index++;
750       it.Next();
751     }
752     while (it.HasNextVirtualMethod()) {
753       if (!DumpOatMethod(vios, class_def, class_method_index, oat_class, dex_file,
754                          it.GetMemberIndex(), it.GetMethodCodeItem(),
755                          it.GetRawMemberAccessFlags(), &addr_found)) {
756         success = false;
757       }
758       if (addr_found) {
759         *stop_analysis = true;
760         return success;
761       }
762       class_method_index++;
763       it.Next();
764     }
765     DCHECK(!it.HasNext());
766     vios->Stream() << std::flush;
767     return success;
768   }
769 
770   static constexpr uint32_t kPrologueBytes = 16;
771 
772   // When this was picked, the largest arm method was 55,256 bytes and arm64 was 50,412 bytes.
773   static constexpr uint32_t kMaxCodeSize = 100 * 1000;
774 
DumpOatMethod(VariableIndentationOutputStream * vios,const DexFile::ClassDef & class_def,uint32_t class_method_index,const OatFile::OatClass & oat_class,const DexFile & dex_file,uint32_t dex_method_idx,const DexFile::CodeItem * code_item,uint32_t method_access_flags,bool * addr_found)775   bool DumpOatMethod(VariableIndentationOutputStream* vios,
776                      const DexFile::ClassDef& class_def,
777                      uint32_t class_method_index,
778                      const OatFile::OatClass& oat_class, const DexFile& dex_file,
779                      uint32_t dex_method_idx, const DexFile::CodeItem* code_item,
780                      uint32_t method_access_flags, bool* addr_found) {
781     bool success = true;
782 
783     // TODO: Support regex
784     std::string method_name = dex_file.GetMethodName(dex_file.GetMethodId(dex_method_idx));
785     if (method_name.find(options_.method_filter_) == std::string::npos) {
786       return success;
787     }
788 
789     std::string pretty_method = PrettyMethod(dex_method_idx, dex_file, true);
790     vios->Stream() << StringPrintf("%d: %s (dex_method_idx=%d)\n",
791                                    class_method_index, pretty_method.c_str(),
792                                    dex_method_idx);
793     if (options_.list_methods_) return success;
794 
795     uint32_t oat_method_offsets_offset = oat_class.GetOatMethodOffsetsOffset(class_method_index);
796     const OatMethodOffsets* oat_method_offsets = oat_class.GetOatMethodOffsets(class_method_index);
797     const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_index);
798     uint32_t code_offset = oat_method.GetCodeOffset();
799     uint32_t code_size = oat_method.GetQuickCodeSize();
800     if (resolved_addr2instr_ != 0) {
801       if (resolved_addr2instr_ > code_offset + code_size) {
802         return success;
803       } else {
804         *addr_found = true;  // stop analyzing file at next iteration
805       }
806     }
807 
808     // Everything below is indented at least once.
809     ScopedIndentation indent1(vios);
810 
811     {
812       vios->Stream() << "DEX CODE:\n";
813       ScopedIndentation indent2(vios);
814       DumpDexCode(vios->Stream(), dex_file, code_item);
815     }
816 
817     std::unique_ptr<StackHandleScope<1>> hs;
818     std::unique_ptr<verifier::MethodVerifier> verifier;
819     if (Runtime::Current() != nullptr) {
820       // We need to have the handle scope stay live until after the verifier since the verifier has
821       // a handle to the dex cache from hs.
822       hs.reset(new StackHandleScope<1>(Thread::Current()));
823       vios->Stream() << "VERIFIER TYPE ANALYSIS:\n";
824       ScopedIndentation indent2(vios);
825       verifier.reset(DumpVerifier(vios, hs.get(),
826                                   dex_method_idx, &dex_file, class_def, code_item,
827                                   method_access_flags));
828     }
829     {
830       vios->Stream() << "OatMethodOffsets ";
831       if (options_.absolute_addresses_) {
832         vios->Stream() << StringPrintf("%p ", oat_method_offsets);
833       }
834       vios->Stream() << StringPrintf("(offset=0x%08x)\n", oat_method_offsets_offset);
835       if (oat_method_offsets_offset > oat_file_.Size()) {
836         vios->Stream() << StringPrintf(
837             "WARNING: oat method offsets offset 0x%08x is past end of file 0x%08zx.\n",
838             oat_method_offsets_offset, oat_file_.Size());
839         // If we can't read OatMethodOffsets, the rest of the data is dangerous to read.
840         vios->Stream() << std::flush;
841         return false;
842       }
843 
844       ScopedIndentation indent2(vios);
845       vios->Stream() << StringPrintf("code_offset: 0x%08x ", code_offset);
846       uint32_t aligned_code_begin = AlignCodeOffset(oat_method.GetCodeOffset());
847       if (aligned_code_begin > oat_file_.Size()) {
848         vios->Stream() << StringPrintf("WARNING: "
849                                        "code offset 0x%08x is past end of file 0x%08zx.\n",
850                                        aligned_code_begin, oat_file_.Size());
851         success = false;
852       }
853       vios->Stream() << "\n";
854     }
855     {
856       vios->Stream() << "OatQuickMethodHeader ";
857       uint32_t method_header_offset = oat_method.GetOatQuickMethodHeaderOffset();
858       const OatQuickMethodHeader* method_header = oat_method.GetOatQuickMethodHeader();
859 
860       if (options_.absolute_addresses_) {
861         vios->Stream() << StringPrintf("%p ", method_header);
862       }
863       vios->Stream() << StringPrintf("(offset=0x%08x)\n", method_header_offset);
864       if (method_header_offset > oat_file_.Size()) {
865         vios->Stream() << StringPrintf(
866             "WARNING: oat quick method header offset 0x%08x is past end of file 0x%08zx.\n",
867             method_header_offset, oat_file_.Size());
868         // If we can't read the OatQuickMethodHeader, the rest of the data is dangerous to read.
869         vios->Stream() << std::flush;
870         return false;
871       }
872 
873       ScopedIndentation indent2(vios);
874       vios->Stream() << "vmap_table: ";
875       if (options_.absolute_addresses_) {
876         vios->Stream() << StringPrintf("%p ", oat_method.GetVmapTable());
877       }
878       uint32_t vmap_table_offset = oat_method.GetVmapTableOffset();
879       vios->Stream() << StringPrintf("(offset=0x%08x)\n", vmap_table_offset);
880       if (vmap_table_offset > oat_file_.Size()) {
881         vios->Stream() << StringPrintf("WARNING: "
882                                        "vmap table offset 0x%08x is past end of file 0x%08zx. "
883                                        "vmap table offset was loaded from offset 0x%08x.\n",
884                                        vmap_table_offset, oat_file_.Size(),
885                                        oat_method.GetVmapTableOffsetOffset());
886         success = false;
887       } else if (options_.dump_vmap_) {
888         DumpVmapData(vios, oat_method, code_item);
889       }
890     }
891     {
892       vios->Stream() << "QuickMethodFrameInfo\n";
893 
894       ScopedIndentation indent2(vios);
895       vios->Stream()
896           << StringPrintf("frame_size_in_bytes: %zd\n", oat_method.GetFrameSizeInBytes());
897       vios->Stream() << StringPrintf("core_spill_mask: 0x%08x ", oat_method.GetCoreSpillMask());
898       DumpSpillMask(vios->Stream(), oat_method.GetCoreSpillMask(), false);
899       vios->Stream() << "\n";
900       vios->Stream() << StringPrintf("fp_spill_mask: 0x%08x ", oat_method.GetFpSpillMask());
901       DumpSpillMask(vios->Stream(), oat_method.GetFpSpillMask(), true);
902       vios->Stream() << "\n";
903     }
904     {
905       // Based on spill masks from QuickMethodFrameInfo so placed
906       // after it is dumped, but useful for understanding quick
907       // code, so dumped here.
908       ScopedIndentation indent2(vios);
909       DumpVregLocations(vios->Stream(), oat_method, code_item);
910     }
911     {
912       vios->Stream() << "CODE: ";
913       uint32_t code_size_offset = oat_method.GetQuickCodeSizeOffset();
914       if (code_size_offset > oat_file_.Size()) {
915         ScopedIndentation indent2(vios);
916         vios->Stream() << StringPrintf("WARNING: "
917                                        "code size offset 0x%08x is past end of file 0x%08zx.",
918                                        code_size_offset, oat_file_.Size());
919         success = false;
920       } else {
921         const void* code = oat_method.GetQuickCode();
922         uint32_t aligned_code_begin = AlignCodeOffset(code_offset);
923         uint64_t aligned_code_end = aligned_code_begin + code_size;
924 
925         if (options_.absolute_addresses_) {
926           vios->Stream() << StringPrintf("%p ", code);
927         }
928         vios->Stream() << StringPrintf("(code_offset=0x%08x size_offset=0x%08x size=%u)%s\n",
929                                        code_offset,
930                                        code_size_offset,
931                                        code_size,
932                                        code != nullptr ? "..." : "");
933 
934         ScopedIndentation indent2(vios);
935         if (aligned_code_begin > oat_file_.Size()) {
936           vios->Stream() << StringPrintf("WARNING: "
937                                          "start of code at 0x%08x is past end of file 0x%08zx.",
938                                          aligned_code_begin, oat_file_.Size());
939           success = false;
940         } else if (aligned_code_end > oat_file_.Size()) {
941           vios->Stream() << StringPrintf(
942               "WARNING: "
943               "end of code at 0x%08" PRIx64 " is past end of file 0x%08zx. "
944               "code size is 0x%08x loaded from offset 0x%08x.\n",
945               aligned_code_end, oat_file_.Size(),
946               code_size, code_size_offset);
947           success = false;
948           if (options_.disassemble_code_) {
949             if (code_size_offset + kPrologueBytes <= oat_file_.Size()) {
950               DumpCode(vios, oat_method, code_item, true, kPrologueBytes);
951             }
952           }
953         } else if (code_size > kMaxCodeSize) {
954           vios->Stream() << StringPrintf(
955               "WARNING: "
956               "code size %d is bigger than max expected threshold of %d. "
957               "code size is 0x%08x loaded from offset 0x%08x.\n",
958               code_size, kMaxCodeSize,
959               code_size, code_size_offset);
960           success = false;
961           if (options_.disassemble_code_) {
962             if (code_size_offset + kPrologueBytes <= oat_file_.Size()) {
963               DumpCode(vios, oat_method, code_item, true, kPrologueBytes);
964             }
965           }
966         } else if (options_.disassemble_code_) {
967           DumpCode(vios, oat_method, code_item, !success, 0);
968         }
969       }
970     }
971     vios->Stream() << std::flush;
972     return success;
973   }
974 
DumpSpillMask(std::ostream & os,uint32_t spill_mask,bool is_float)975   void DumpSpillMask(std::ostream& os, uint32_t spill_mask, bool is_float) {
976     if (spill_mask == 0) {
977       return;
978     }
979     os << "(";
980     for (size_t i = 0; i < 32; i++) {
981       if ((spill_mask & (1 << i)) != 0) {
982         if (is_float) {
983           os << "fr" << i;
984         } else {
985           os << "r" << i;
986         }
987         spill_mask ^= 1 << i;  // clear bit
988         if (spill_mask != 0) {
989           os << ", ";
990         } else {
991           break;
992         }
993       }
994     }
995     os << ")";
996   }
997 
998   // Display data stored at the the vmap offset of an oat method.
DumpVmapData(VariableIndentationOutputStream * vios,const OatFile::OatMethod & oat_method,const DexFile::CodeItem * code_item)999   void DumpVmapData(VariableIndentationOutputStream* vios,
1000                     const OatFile::OatMethod& oat_method,
1001                     const DexFile::CodeItem* code_item) {
1002     if (IsMethodGeneratedByOptimizingCompiler(oat_method, code_item)) {
1003       // The optimizing compiler outputs its CodeInfo data in the vmap table.
1004       const void* raw_code_info = oat_method.GetVmapTable();
1005       if (raw_code_info != nullptr) {
1006         CodeInfo code_info(raw_code_info);
1007         DCHECK(code_item != nullptr);
1008         ScopedIndentation indent1(vios);
1009         DumpCodeInfo(vios, code_info, oat_method, *code_item);
1010       }
1011     } else if (IsMethodGeneratedByDexToDexCompiler(oat_method, code_item)) {
1012       // We don't encode the size in the table, so just emit that we have quickened
1013       // information.
1014       ScopedIndentation indent(vios);
1015       vios->Stream() << "quickened data\n";
1016     } else {
1017       // Otherwise, there is nothing to display.
1018     }
1019   }
1020 
1021   // Display a CodeInfo object emitted by the optimizing compiler.
DumpCodeInfo(VariableIndentationOutputStream * vios,const CodeInfo & code_info,const OatFile::OatMethod & oat_method,const DexFile::CodeItem & code_item)1022   void DumpCodeInfo(VariableIndentationOutputStream* vios,
1023                     const CodeInfo& code_info,
1024                     const OatFile::OatMethod& oat_method,
1025                     const DexFile::CodeItem& code_item) {
1026     code_info.Dump(vios,
1027                    oat_method.GetCodeOffset(),
1028                    code_item.registers_size_,
1029                    options_.dump_code_info_stack_maps_);
1030   }
1031 
DumpVregLocations(std::ostream & os,const OatFile::OatMethod & oat_method,const DexFile::CodeItem * code_item)1032   void DumpVregLocations(std::ostream& os, const OatFile::OatMethod& oat_method,
1033                          const DexFile::CodeItem* code_item) {
1034     if (code_item != nullptr) {
1035       size_t num_locals_ins = code_item->registers_size_;
1036       size_t num_ins = code_item->ins_size_;
1037       size_t num_locals = num_locals_ins - num_ins;
1038       size_t num_outs = code_item->outs_size_;
1039 
1040       os << "vr_stack_locations:";
1041       for (size_t reg = 0; reg <= num_locals_ins; reg++) {
1042         // For readability, delimit the different kinds of VRs.
1043         if (reg == num_locals_ins) {
1044           os << "\n\tmethod*:";
1045         } else if (reg == num_locals && num_ins > 0) {
1046           os << "\n\tins:";
1047         } else if (reg == 0 && num_locals > 0) {
1048           os << "\n\tlocals:";
1049         }
1050 
1051         uint32_t offset = StackVisitor::GetVRegOffsetFromQuickCode(
1052             code_item,
1053             oat_method.GetCoreSpillMask(),
1054             oat_method.GetFpSpillMask(),
1055             oat_method.GetFrameSizeInBytes(),
1056             reg,
1057             GetInstructionSet());
1058         os << " v" << reg << "[sp + #" << offset << "]";
1059       }
1060 
1061       for (size_t out_reg = 0; out_reg < num_outs; out_reg++) {
1062         if (out_reg == 0) {
1063           os << "\n\touts:";
1064         }
1065 
1066         uint32_t offset = StackVisitor::GetOutVROffset(out_reg, GetInstructionSet());
1067         os << " v" << out_reg << "[sp + #" << offset << "]";
1068       }
1069 
1070       os << "\n";
1071     }
1072   }
1073 
DumpDexCode(std::ostream & os,const DexFile & dex_file,const DexFile::CodeItem * code_item)1074   void DumpDexCode(std::ostream& os, const DexFile& dex_file, const DexFile::CodeItem* code_item) {
1075     if (code_item != nullptr) {
1076       size_t i = 0;
1077       while (i < code_item->insns_size_in_code_units_) {
1078         const Instruction* instruction = Instruction::At(&code_item->insns_[i]);
1079         os << StringPrintf("0x%04zx: ", i) << instruction->DumpHexLE(5)
1080            << StringPrintf("\t| %s\n", instruction->DumpString(&dex_file).c_str());
1081         i += instruction->SizeInCodeUnits();
1082       }
1083     }
1084   }
1085 
1086   // Has `oat_method` -- corresponding to the Dex `code_item` -- been compiled by
1087   // the optimizing compiler?
IsMethodGeneratedByOptimizingCompiler(const OatFile::OatMethod & oat_method,const DexFile::CodeItem * code_item)1088   static bool IsMethodGeneratedByOptimizingCompiler(const OatFile::OatMethod& oat_method,
1089                                                     const DexFile::CodeItem* code_item) {
1090     // If the native GC map is null and the Dex `code_item` is not
1091     // null, then this method has been compiled with the optimizing
1092     // compiler.
1093     return oat_method.GetQuickCode() != nullptr &&
1094            oat_method.GetVmapTable() != nullptr &&
1095            code_item != nullptr;
1096   }
1097 
1098   // Has `oat_method` -- corresponding to the Dex `code_item` -- been compiled by
1099   // the dextodex compiler?
IsMethodGeneratedByDexToDexCompiler(const OatFile::OatMethod & oat_method,const DexFile::CodeItem * code_item)1100   static bool IsMethodGeneratedByDexToDexCompiler(const OatFile::OatMethod& oat_method,
1101                                                   const DexFile::CodeItem* code_item) {
1102     // If the quick code is null, the Dex `code_item` is not
1103     // null, and the vmap table is not null, then this method has been compiled
1104     // with the dextodex compiler.
1105     return oat_method.GetQuickCode() == nullptr &&
1106            oat_method.GetVmapTable() != nullptr &&
1107            code_item != nullptr;
1108   }
1109 
DumpVerifier(VariableIndentationOutputStream * vios,StackHandleScope<1> * hs,uint32_t dex_method_idx,const DexFile * dex_file,const DexFile::ClassDef & class_def,const DexFile::CodeItem * code_item,uint32_t method_access_flags)1110   verifier::MethodVerifier* DumpVerifier(VariableIndentationOutputStream* vios,
1111                                          StackHandleScope<1>* hs,
1112                                          uint32_t dex_method_idx,
1113                                          const DexFile* dex_file,
1114                                          const DexFile::ClassDef& class_def,
1115                                          const DexFile::CodeItem* code_item,
1116                                          uint32_t method_access_flags) {
1117     if ((method_access_flags & kAccNative) == 0) {
1118       ScopedObjectAccess soa(Thread::Current());
1119       Runtime* const runtime = Runtime::Current();
1120       Handle<mirror::DexCache> dex_cache(
1121           hs->NewHandle(runtime->GetClassLinker()->RegisterDexFile(*dex_file, nullptr)));
1122       DCHECK(options_.class_loader_ != nullptr);
1123       return verifier::MethodVerifier::VerifyMethodAndDump(
1124           soa.Self(), vios, dex_method_idx, dex_file, dex_cache, *options_.class_loader_,
1125           &class_def, code_item, nullptr, method_access_flags);
1126     }
1127 
1128     return nullptr;
1129   }
1130 
1131   // The StackMapsHelper provides the stack maps in the native PC order.
1132   // For identical native PCs, the order from the CodeInfo is preserved.
1133   class StackMapsHelper {
1134    public:
StackMapsHelper(const uint8_t * raw_code_info)1135     explicit StackMapsHelper(const uint8_t* raw_code_info)
1136         : code_info_(raw_code_info),
1137           encoding_(code_info_.ExtractEncoding()),
1138           number_of_stack_maps_(code_info_.GetNumberOfStackMaps(encoding_)),
1139           indexes_(),
1140           offset_(static_cast<size_t>(-1)),
1141           stack_map_index_(0u) {
1142       if (number_of_stack_maps_ != 0u) {
1143         // Check if native PCs are ordered.
1144         bool ordered = true;
1145         StackMap last = code_info_.GetStackMapAt(0u, encoding_);
1146         for (size_t i = 1; i != number_of_stack_maps_; ++i) {
1147           StackMap current = code_info_.GetStackMapAt(i, encoding_);
1148           if (last.GetNativePcOffset(encoding_.stack_map_encoding) >
1149               current.GetNativePcOffset(encoding_.stack_map_encoding)) {
1150             ordered = false;
1151             break;
1152           }
1153           last = current;
1154         }
1155         if (!ordered) {
1156           // Create indirection indexes for access in native PC order. We do not optimize
1157           // for the fact that there can currently be only two separately ordered ranges,
1158           // namely normal stack maps and catch-point stack maps.
1159           indexes_.resize(number_of_stack_maps_);
1160           std::iota(indexes_.begin(), indexes_.end(), 0u);
1161           std::sort(indexes_.begin(),
1162                     indexes_.end(),
1163                     [this](size_t lhs, size_t rhs) {
1164                       StackMap left = code_info_.GetStackMapAt(lhs, encoding_);
1165                       uint32_t left_pc = left.GetNativePcOffset(encoding_.stack_map_encoding);
1166                       StackMap right = code_info_.GetStackMapAt(rhs, encoding_);
1167                       uint32_t right_pc = right.GetNativePcOffset(encoding_.stack_map_encoding);
1168                       // If the PCs are the same, compare indexes to preserve the original order.
1169                       return (left_pc < right_pc) || (left_pc == right_pc && lhs < rhs);
1170                     });
1171         }
1172         offset_ = GetStackMapAt(0).GetNativePcOffset(encoding_.stack_map_encoding);
1173       }
1174     }
1175 
GetCodeInfo() const1176     const CodeInfo& GetCodeInfo() const {
1177       return code_info_;
1178     }
1179 
GetEncoding() const1180     const CodeInfoEncoding& GetEncoding() const {
1181       return encoding_;
1182     }
1183 
GetOffset() const1184     size_t GetOffset() const {
1185       return offset_;
1186     }
1187 
GetStackMap() const1188     StackMap GetStackMap() const {
1189       return GetStackMapAt(stack_map_index_);
1190     }
1191 
Next()1192     void Next() {
1193       ++stack_map_index_;
1194       offset_ = (stack_map_index_ == number_of_stack_maps_)
1195           ? static_cast<size_t>(-1)
1196           : GetStackMapAt(stack_map_index_).GetNativePcOffset(encoding_.stack_map_encoding);
1197     }
1198 
1199    private:
GetStackMapAt(size_t i) const1200     StackMap GetStackMapAt(size_t i) const {
1201       if (!indexes_.empty()) {
1202         i = indexes_[i];
1203       }
1204       DCHECK_LT(i, number_of_stack_maps_);
1205       return code_info_.GetStackMapAt(i, encoding_);
1206     }
1207 
1208     const CodeInfo code_info_;
1209     const CodeInfoEncoding encoding_;
1210     const size_t number_of_stack_maps_;
1211     dchecked_vector<size_t> indexes_;  // Used if stack map native PCs are not ordered.
1212     size_t offset_;
1213     size_t stack_map_index_;
1214   };
1215 
DumpCode(VariableIndentationOutputStream * vios,const OatFile::OatMethod & oat_method,const DexFile::CodeItem * code_item,bool bad_input,size_t code_size)1216   void DumpCode(VariableIndentationOutputStream* vios,
1217                 const OatFile::OatMethod& oat_method, const DexFile::CodeItem* code_item,
1218                 bool bad_input, size_t code_size) {
1219     const void* quick_code = oat_method.GetQuickCode();
1220 
1221     if (code_size == 0) {
1222       code_size = oat_method.GetQuickCodeSize();
1223     }
1224     if (code_size == 0 || quick_code == nullptr) {
1225       vios->Stream() << "NO CODE!\n";
1226       return;
1227     } else if (!bad_input && IsMethodGeneratedByOptimizingCompiler(oat_method, code_item)) {
1228       // The optimizing compiler outputs its CodeInfo data in the vmap table.
1229       StackMapsHelper helper(oat_method.GetVmapTable());
1230       const uint8_t* quick_native_pc = reinterpret_cast<const uint8_t*>(quick_code);
1231       size_t offset = 0;
1232       while (offset < code_size) {
1233         offset += disassembler_->Dump(vios->Stream(), quick_native_pc + offset);
1234         if (offset == helper.GetOffset()) {
1235           ScopedIndentation indent1(vios);
1236           StackMap stack_map = helper.GetStackMap();
1237           DCHECK(stack_map.IsValid());
1238           stack_map.Dump(vios,
1239                          helper.GetCodeInfo(),
1240                          helper.GetEncoding(),
1241                          oat_method.GetCodeOffset(),
1242                          code_item->registers_size_);
1243           do {
1244             helper.Next();
1245             // There may be multiple stack maps at a given PC. We display only the first one.
1246           } while (offset == helper.GetOffset());
1247         }
1248         DCHECK_LT(offset, helper.GetOffset());
1249       }
1250     } else {
1251       const uint8_t* quick_native_pc = reinterpret_cast<const uint8_t*>(quick_code);
1252       size_t offset = 0;
1253       while (offset < code_size) {
1254         offset += disassembler_->Dump(vios->Stream(), quick_native_pc + offset);
1255       }
1256     }
1257   }
1258 
1259   const OatFile& oat_file_;
1260   const std::vector<const OatFile::OatDexFile*> oat_dex_files_;
1261   const OatDumperOptions& options_;
1262   uint32_t resolved_addr2instr_;
1263   InstructionSet instruction_set_;
1264   std::set<uintptr_t> offsets_;
1265   Disassembler* disassembler_;
1266 };
1267 
1268 class ImageDumper {
1269  public:
ImageDumper(std::ostream * os,gc::space::ImageSpace & image_space,const ImageHeader & image_header,OatDumperOptions * oat_dumper_options)1270   ImageDumper(std::ostream* os,
1271               gc::space::ImageSpace& image_space,
1272               const ImageHeader& image_header,
1273               OatDumperOptions* oat_dumper_options)
1274       : os_(os),
1275         vios_(os),
1276         indent1_(&vios_),
1277         image_space_(image_space),
1278         image_header_(image_header),
1279         oat_dumper_options_(oat_dumper_options) {}
1280 
Dump()1281   bool Dump() SHARED_REQUIRES(Locks::mutator_lock_) {
1282     std::ostream& os = *os_;
1283     std::ostream& indent_os = vios_.Stream();
1284 
1285     os << "MAGIC: " << image_header_.GetMagic() << "\n\n";
1286 
1287     os << "IMAGE LOCATION: " << image_space_.GetImageLocation() << "\n\n";
1288 
1289     os << "IMAGE BEGIN: " << reinterpret_cast<void*>(image_header_.GetImageBegin()) << "\n\n";
1290 
1291     os << "IMAGE SIZE: " << image_header_.GetImageSize() << "\n\n";
1292 
1293     for (size_t i = 0; i < ImageHeader::kSectionCount; ++i) {
1294       auto section = static_cast<ImageHeader::ImageSections>(i);
1295       os << "IMAGE SECTION " << section << ": " << image_header_.GetImageSection(section) << "\n\n";
1296     }
1297 
1298     os << "OAT CHECKSUM: " << StringPrintf("0x%08x\n\n", image_header_.GetOatChecksum());
1299 
1300     os << "OAT FILE BEGIN:" << reinterpret_cast<void*>(image_header_.GetOatFileBegin()) << "\n\n";
1301 
1302     os << "OAT DATA BEGIN:" << reinterpret_cast<void*>(image_header_.GetOatDataBegin()) << "\n\n";
1303 
1304     os << "OAT DATA END:" << reinterpret_cast<void*>(image_header_.GetOatDataEnd()) << "\n\n";
1305 
1306     os << "OAT FILE END:" << reinterpret_cast<void*>(image_header_.GetOatFileEnd()) << "\n\n";
1307 
1308     os << "PATCH DELTA:" << image_header_.GetPatchDelta() << "\n\n";
1309 
1310     os << "COMPILE PIC: " << (image_header_.CompilePic() ? "yes" : "no") << "\n\n";
1311 
1312     {
1313       os << "ROOTS: " << reinterpret_cast<void*>(image_header_.GetImageRoots()) << "\n";
1314       static_assert(arraysize(image_roots_descriptions_) ==
1315           static_cast<size_t>(ImageHeader::kImageRootsMax), "sizes must match");
1316       for (int i = 0; i < ImageHeader::kImageRootsMax; i++) {
1317         ImageHeader::ImageRoot image_root = static_cast<ImageHeader::ImageRoot>(i);
1318         const char* image_root_description = image_roots_descriptions_[i];
1319         mirror::Object* image_root_object = image_header_.GetImageRoot(image_root);
1320         indent_os << StringPrintf("%s: %p\n", image_root_description, image_root_object);
1321         if (image_root_object->IsObjectArray()) {
1322           mirror::ObjectArray<mirror::Object>* image_root_object_array
1323               = image_root_object->AsObjectArray<mirror::Object>();
1324           ScopedIndentation indent2(&vios_);
1325           for (int j = 0; j < image_root_object_array->GetLength(); j++) {
1326             mirror::Object* value = image_root_object_array->Get(j);
1327             size_t run = 0;
1328             for (int32_t k = j + 1; k < image_root_object_array->GetLength(); k++) {
1329               if (value == image_root_object_array->Get(k)) {
1330                 run++;
1331               } else {
1332                 break;
1333               }
1334             }
1335             if (run == 0) {
1336               indent_os << StringPrintf("%d: ", j);
1337             } else {
1338               indent_os << StringPrintf("%d to %zd: ", j, j + run);
1339               j = j + run;
1340             }
1341             if (value != nullptr) {
1342               PrettyObjectValue(indent_os, value->GetClass(), value);
1343             } else {
1344               indent_os << j << ": null\n";
1345             }
1346           }
1347         }
1348       }
1349     }
1350 
1351     {
1352       os << "METHOD ROOTS\n";
1353       static_assert(arraysize(image_methods_descriptions_) ==
1354           static_cast<size_t>(ImageHeader::kImageMethodsCount), "sizes must match");
1355       for (int i = 0; i < ImageHeader::kImageMethodsCount; i++) {
1356         auto image_root = static_cast<ImageHeader::ImageMethod>(i);
1357         const char* description = image_methods_descriptions_[i];
1358         auto* image_method = image_header_.GetImageMethod(image_root);
1359         indent_os << StringPrintf("%s: %p\n", description, image_method);
1360       }
1361     }
1362     os << "\n";
1363 
1364     Runtime* const runtime = Runtime::Current();
1365     ClassLinker* class_linker = runtime->GetClassLinker();
1366     std::string image_filename = image_space_.GetImageFilename();
1367     std::string oat_location = ImageHeader::GetOatLocationFromImageLocation(image_filename);
1368     os << "OAT LOCATION: " << oat_location;
1369     os << "\n";
1370     std::string error_msg;
1371     const OatFile* oat_file = image_space_.GetOatFile();
1372     if (oat_file == nullptr) {
1373       oat_file = runtime->GetOatFileManager().FindOpenedOatFileFromOatLocation(oat_location);
1374     }
1375     if (oat_file == nullptr) {
1376       oat_file = OatFile::Open(oat_location,
1377                                oat_location,
1378                                nullptr,
1379                                nullptr,
1380                                false,
1381                                /*low_4gb*/false,
1382                                nullptr,
1383                                &error_msg);
1384     }
1385     if (oat_file == nullptr) {
1386       os << "OAT FILE NOT FOUND: " << error_msg << "\n";
1387       return EXIT_FAILURE;
1388     }
1389     os << "\n";
1390 
1391     stats_.oat_file_bytes = oat_file->Size();
1392 
1393     oat_dumper_.reset(new OatDumper(*oat_file, *oat_dumper_options_));
1394 
1395     for (const OatFile::OatDexFile* oat_dex_file : oat_file->GetOatDexFiles()) {
1396       CHECK(oat_dex_file != nullptr);
1397       stats_.oat_dex_file_sizes.push_back(std::make_pair(oat_dex_file->GetDexFileLocation(),
1398                                                          oat_dex_file->FileSize()));
1399     }
1400 
1401     os << "OBJECTS:\n" << std::flush;
1402 
1403     // Loop through the image space and dump its objects.
1404     gc::Heap* heap = runtime->GetHeap();
1405     Thread* self = Thread::Current();
1406     {
1407       {
1408         WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
1409         heap->FlushAllocStack();
1410       }
1411       // Since FlushAllocStack() above resets the (active) allocation
1412       // stack. Need to revoke the thread-local allocation stacks that
1413       // point into it.
1414       ScopedThreadSuspension sts(self, kNative);
1415       ScopedSuspendAll ssa(__FUNCTION__);
1416       heap->RevokeAllThreadLocalAllocationStacks(self);
1417     }
1418     {
1419       // Mark dex caches.
1420       dex_caches_.clear();
1421       {
1422         ReaderMutexLock mu(self, *class_linker->DexLock());
1423         for (const ClassLinker::DexCacheData& data : class_linker->GetDexCachesData()) {
1424           mirror::DexCache* dex_cache =
1425               down_cast<mirror::DexCache*>(self->DecodeJObject(data.weak_root));
1426           if (dex_cache != nullptr) {
1427             dex_caches_.insert(dex_cache);
1428           }
1429         }
1430       }
1431       ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
1432       // Dump the normal objects before ArtMethods.
1433       image_space_.GetLiveBitmap()->Walk(ImageDumper::Callback, this);
1434       indent_os << "\n";
1435       // TODO: Dump fields.
1436       // Dump methods after.
1437       DumpArtMethodVisitor visitor(this);
1438       image_header_.VisitPackedArtMethods(&visitor,
1439                                           image_space_.Begin(),
1440                                           image_header_.GetPointerSize());
1441       // Dump the large objects separately.
1442       heap->GetLargeObjectsSpace()->GetLiveBitmap()->Walk(ImageDumper::Callback, this);
1443       indent_os << "\n";
1444     }
1445     os << "STATS:\n" << std::flush;
1446     std::unique_ptr<File> file(OS::OpenFileForReading(image_filename.c_str()));
1447     size_t data_size = image_header_.GetDataSize();  // stored size in file.
1448     if (file == nullptr) {
1449       LOG(WARNING) << "Failed to find image in " << image_filename;
1450     } else {
1451       stats_.file_bytes = file->GetLength();
1452       // If the image is compressed, adjust to decompressed size.
1453       size_t uncompressed_size = image_header_.GetImageSize() - sizeof(ImageHeader);
1454       if (image_header_.GetStorageMode() == ImageHeader::kStorageModeUncompressed) {
1455         DCHECK_EQ(uncompressed_size, data_size) << "Sizes should match for uncompressed image";
1456       }
1457       stats_.file_bytes += uncompressed_size - data_size;
1458     }
1459     size_t header_bytes = sizeof(ImageHeader);
1460     const auto& object_section = image_header_.GetImageSection(ImageHeader::kSectionObjects);
1461     const auto& field_section = image_header_.GetImageSection(ImageHeader::kSectionArtFields);
1462     const auto& method_section = image_header_.GetMethodsSection();
1463     const auto& dex_cache_arrays_section = image_header_.GetImageSection(
1464         ImageHeader::kSectionDexCacheArrays);
1465     const auto& intern_section = image_header_.GetImageSection(
1466         ImageHeader::kSectionInternedStrings);
1467     const auto& class_table_section = image_header_.GetImageSection(
1468         ImageHeader::kSectionClassTable);
1469     const auto& bitmap_section = image_header_.GetImageSection(ImageHeader::kSectionImageBitmap);
1470 
1471     stats_.header_bytes = header_bytes;
1472 
1473     // Objects are kObjectAlignment-aligned.
1474     // CHECK_EQ(RoundUp(header_bytes, kObjectAlignment), object_section.Offset());
1475     if (object_section.Offset() > header_bytes) {
1476       stats_.alignment_bytes += object_section.Offset() - header_bytes;
1477     }
1478 
1479     // Field section is 4-byte aligned.
1480     constexpr size_t kFieldSectionAlignment = 4U;
1481     uint32_t end_objects = object_section.Offset() + object_section.Size();
1482     CHECK_EQ(RoundUp(end_objects, kFieldSectionAlignment), field_section.Offset());
1483     stats_.alignment_bytes += field_section.Offset() - end_objects;
1484 
1485     // Method section is 4/8 byte aligned depending on target. Just check for 4-byte alignment.
1486     uint32_t end_fields = field_section.Offset() + field_section.Size();
1487     CHECK_ALIGNED(method_section.Offset(), 4);
1488     stats_.alignment_bytes += method_section.Offset() - end_fields;
1489 
1490     // Dex cache arrays section is aligned depending on the target. Just check for 4-byte alignment.
1491     uint32_t end_methods = method_section.Offset() + method_section.Size();
1492     CHECK_ALIGNED(dex_cache_arrays_section.Offset(), 4);
1493     stats_.alignment_bytes += dex_cache_arrays_section.Offset() - end_methods;
1494 
1495     // Intern table is 8-byte aligned.
1496     uint32_t end_caches = dex_cache_arrays_section.Offset() + dex_cache_arrays_section.Size();
1497     CHECK_EQ(RoundUp(end_caches, 8U), intern_section.Offset());
1498     stats_.alignment_bytes += intern_section.Offset() - end_caches;
1499 
1500     // Add space between intern table and class table.
1501     uint32_t end_intern = intern_section.Offset() + intern_section.Size();
1502     stats_.alignment_bytes += class_table_section.Offset() - end_intern;
1503 
1504     // Add space between end of image data and bitmap. Expect the bitmap to be page-aligned.
1505     const size_t bitmap_offset = sizeof(ImageHeader) + data_size;
1506     CHECK_ALIGNED(bitmap_section.Offset(), kPageSize);
1507     stats_.alignment_bytes += RoundUp(bitmap_offset, kPageSize) - bitmap_offset;
1508 
1509     stats_.bitmap_bytes += bitmap_section.Size();
1510     stats_.art_field_bytes += field_section.Size();
1511     stats_.art_method_bytes += method_section.Size();
1512     stats_.dex_cache_arrays_bytes += dex_cache_arrays_section.Size();
1513     stats_.interned_strings_bytes += intern_section.Size();
1514     stats_.class_table_bytes += class_table_section.Size();
1515     stats_.Dump(os, indent_os);
1516     os << "\n";
1517 
1518     os << std::flush;
1519 
1520     return oat_dumper_->Dump(os);
1521   }
1522 
1523  private:
1524   class DumpArtMethodVisitor : public ArtMethodVisitor {
1525    public:
DumpArtMethodVisitor(ImageDumper * image_dumper)1526     explicit DumpArtMethodVisitor(ImageDumper* image_dumper) : image_dumper_(image_dumper) {}
1527 
Visit(ArtMethod * method)1528     virtual void Visit(ArtMethod* method) OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_) {
1529       std::ostream& indent_os = image_dumper_->vios_.Stream();
1530       indent_os << method << " " << " ArtMethod: " << PrettyMethod(method) << "\n";
1531       image_dumper_->DumpMethod(method, indent_os);
1532       indent_os << "\n";
1533     }
1534 
1535    private:
1536     ImageDumper* const image_dumper_;
1537   };
1538 
PrettyObjectValue(std::ostream & os,mirror::Class * type,mirror::Object * value)1539   static void PrettyObjectValue(std::ostream& os, mirror::Class* type, mirror::Object* value)
1540       SHARED_REQUIRES(Locks::mutator_lock_) {
1541     CHECK(type != nullptr);
1542     if (value == nullptr) {
1543       os << StringPrintf("null   %s\n", PrettyDescriptor(type).c_str());
1544     } else if (type->IsStringClass()) {
1545       mirror::String* string = value->AsString();
1546       os << StringPrintf("%p   String: %s\n", string,
1547                          PrintableString(string->ToModifiedUtf8().c_str()).c_str());
1548     } else if (type->IsClassClass()) {
1549       mirror::Class* klass = value->AsClass();
1550       os << StringPrintf("%p   Class: %s\n", klass, PrettyDescriptor(klass).c_str());
1551     } else {
1552       os << StringPrintf("%p   %s\n", value, PrettyDescriptor(type).c_str());
1553     }
1554   }
1555 
PrintField(std::ostream & os,ArtField * field,mirror::Object * obj)1556   static void PrintField(std::ostream& os, ArtField* field, mirror::Object* obj)
1557       SHARED_REQUIRES(Locks::mutator_lock_) {
1558     os << StringPrintf("%s: ", field->GetName());
1559     switch (field->GetTypeAsPrimitiveType()) {
1560       case Primitive::kPrimLong:
1561         os << StringPrintf("%" PRId64 " (0x%" PRIx64 ")\n", field->Get64(obj), field->Get64(obj));
1562         break;
1563       case Primitive::kPrimDouble:
1564         os << StringPrintf("%f (%a)\n", field->GetDouble(obj), field->GetDouble(obj));
1565         break;
1566       case Primitive::kPrimFloat:
1567         os << StringPrintf("%f (%a)\n", field->GetFloat(obj), field->GetFloat(obj));
1568         break;
1569       case Primitive::kPrimInt:
1570         os << StringPrintf("%d (0x%x)\n", field->Get32(obj), field->Get32(obj));
1571         break;
1572       case Primitive::kPrimChar:
1573         os << StringPrintf("%u (0x%x)\n", field->GetChar(obj), field->GetChar(obj));
1574         break;
1575       case Primitive::kPrimShort:
1576         os << StringPrintf("%d (0x%x)\n", field->GetShort(obj), field->GetShort(obj));
1577         break;
1578       case Primitive::kPrimBoolean:
1579         os << StringPrintf("%s (0x%x)\n", field->GetBoolean(obj)? "true" : "false",
1580             field->GetBoolean(obj));
1581         break;
1582       case Primitive::kPrimByte:
1583         os << StringPrintf("%d (0x%x)\n", field->GetByte(obj), field->GetByte(obj));
1584         break;
1585       case Primitive::kPrimNot: {
1586         // Get the value, don't compute the type unless it is non-null as we don't want
1587         // to cause class loading.
1588         mirror::Object* value = field->GetObj(obj);
1589         if (value == nullptr) {
1590           os << StringPrintf("null   %s\n", PrettyDescriptor(field->GetTypeDescriptor()).c_str());
1591         } else {
1592           // Grab the field type without causing resolution.
1593           mirror::Class* field_type = field->GetType<false>();
1594           if (field_type != nullptr) {
1595             PrettyObjectValue(os, field_type, value);
1596           } else {
1597             os << StringPrintf("%p   %s\n", value,
1598                                PrettyDescriptor(field->GetTypeDescriptor()).c_str());
1599           }
1600         }
1601         break;
1602       }
1603       default:
1604         os << "unexpected field type: " << field->GetTypeDescriptor() << "\n";
1605         break;
1606     }
1607   }
1608 
DumpFields(std::ostream & os,mirror::Object * obj,mirror::Class * klass)1609   static void DumpFields(std::ostream& os, mirror::Object* obj, mirror::Class* klass)
1610       SHARED_REQUIRES(Locks::mutator_lock_) {
1611     mirror::Class* super = klass->GetSuperClass();
1612     if (super != nullptr) {
1613       DumpFields(os, obj, super);
1614     }
1615     for (ArtField& field : klass->GetIFields()) {
1616       PrintField(os, &field, obj);
1617     }
1618   }
1619 
InDumpSpace(const mirror::Object * object)1620   bool InDumpSpace(const mirror::Object* object) {
1621     return image_space_.Contains(object);
1622   }
1623 
GetQuickOatCodeBegin(ArtMethod * m)1624   const void* GetQuickOatCodeBegin(ArtMethod* m) SHARED_REQUIRES(Locks::mutator_lock_) {
1625     const void* quick_code = m->GetEntryPointFromQuickCompiledCodePtrSize(
1626         image_header_.GetPointerSize());
1627     if (Runtime::Current()->GetClassLinker()->IsQuickResolutionStub(quick_code)) {
1628       quick_code = oat_dumper_->GetQuickOatCode(m);
1629     }
1630     if (oat_dumper_->GetInstructionSet() == kThumb2) {
1631       quick_code = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(quick_code) & ~0x1);
1632     }
1633     return quick_code;
1634   }
1635 
GetQuickOatCodeSize(ArtMethod * m)1636   uint32_t GetQuickOatCodeSize(ArtMethod* m)
1637       SHARED_REQUIRES(Locks::mutator_lock_) {
1638     const uint32_t* oat_code_begin = reinterpret_cast<const uint32_t*>(GetQuickOatCodeBegin(m));
1639     if (oat_code_begin == nullptr) {
1640       return 0;
1641     }
1642     return oat_code_begin[-1];
1643   }
1644 
GetQuickOatCodeEnd(ArtMethod * m)1645   const void* GetQuickOatCodeEnd(ArtMethod* m)
1646       SHARED_REQUIRES(Locks::mutator_lock_) {
1647     const uint8_t* oat_code_begin = reinterpret_cast<const uint8_t*>(GetQuickOatCodeBegin(m));
1648     if (oat_code_begin == nullptr) {
1649       return nullptr;
1650     }
1651     return oat_code_begin + GetQuickOatCodeSize(m);
1652   }
1653 
Callback(mirror::Object * obj,void * arg)1654   static void Callback(mirror::Object* obj, void* arg) SHARED_REQUIRES(Locks::mutator_lock_) {
1655     DCHECK(obj != nullptr);
1656     DCHECK(arg != nullptr);
1657     ImageDumper* state = reinterpret_cast<ImageDumper*>(arg);
1658     if (!state->InDumpSpace(obj)) {
1659       return;
1660     }
1661 
1662     size_t object_bytes = obj->SizeOf();
1663     size_t alignment_bytes = RoundUp(object_bytes, kObjectAlignment) - object_bytes;
1664     state->stats_.object_bytes += object_bytes;
1665     state->stats_.alignment_bytes += alignment_bytes;
1666 
1667     std::ostream& os = state->vios_.Stream();
1668 
1669     mirror::Class* obj_class = obj->GetClass();
1670     if (obj_class->IsArrayClass()) {
1671       os << StringPrintf("%p: %s length:%d\n", obj, PrettyDescriptor(obj_class).c_str(),
1672                          obj->AsArray()->GetLength());
1673     } else if (obj->IsClass()) {
1674       mirror::Class* klass = obj->AsClass();
1675       os << StringPrintf("%p: java.lang.Class \"%s\" (", obj, PrettyDescriptor(klass).c_str())
1676          << klass->GetStatus() << ")\n";
1677     } else if (obj_class->IsStringClass()) {
1678       os << StringPrintf("%p: java.lang.String %s\n", obj,
1679                          PrintableString(obj->AsString()->ToModifiedUtf8().c_str()).c_str());
1680     } else {
1681       os << StringPrintf("%p: %s\n", obj, PrettyDescriptor(obj_class).c_str());
1682     }
1683     ScopedIndentation indent1(&state->vios_);
1684     DumpFields(os, obj, obj_class);
1685     const size_t image_pointer_size = state->image_header_.GetPointerSize();
1686     if (obj->IsObjectArray()) {
1687       auto* obj_array = obj->AsObjectArray<mirror::Object>();
1688       for (int32_t i = 0, length = obj_array->GetLength(); i < length; i++) {
1689         mirror::Object* value = obj_array->Get(i);
1690         size_t run = 0;
1691         for (int32_t j = i + 1; j < length; j++) {
1692           if (value == obj_array->Get(j)) {
1693             run++;
1694           } else {
1695             break;
1696           }
1697         }
1698         if (run == 0) {
1699           os << StringPrintf("%d: ", i);
1700         } else {
1701           os << StringPrintf("%d to %zd: ", i, i + run);
1702           i = i + run;
1703         }
1704         mirror::Class* value_class =
1705             (value == nullptr) ? obj_class->GetComponentType() : value->GetClass();
1706         PrettyObjectValue(os, value_class, value);
1707       }
1708     } else if (obj->IsClass()) {
1709       mirror::Class* klass = obj->AsClass();
1710       if (klass->NumStaticFields() != 0) {
1711         os << "STATICS:\n";
1712         ScopedIndentation indent2(&state->vios_);
1713         for (ArtField& field : klass->GetSFields()) {
1714           PrintField(os, &field, field.GetDeclaringClass());
1715         }
1716       }
1717     } else {
1718       auto it = state->dex_caches_.find(obj);
1719       if (it != state->dex_caches_.end()) {
1720         auto* dex_cache = down_cast<mirror::DexCache*>(obj);
1721         const auto& field_section = state->image_header_.GetImageSection(
1722             ImageHeader::kSectionArtFields);
1723         const auto& method_section = state->image_header_.GetMethodsSection();
1724         size_t num_methods = dex_cache->NumResolvedMethods();
1725         if (num_methods != 0u) {
1726           os << "Methods (size=" << num_methods << "):";
1727           ScopedIndentation indent2(&state->vios_);
1728           auto* resolved_methods = dex_cache->GetResolvedMethods();
1729           for (size_t i = 0, length = dex_cache->NumResolvedMethods(); i < length; ++i) {
1730             auto* elem = mirror::DexCache::GetElementPtrSize(resolved_methods,
1731                                                              i,
1732                                                              image_pointer_size);
1733             size_t run = 0;
1734             for (size_t j = i + 1;
1735                 j != length && elem == mirror::DexCache::GetElementPtrSize(resolved_methods,
1736                                                                            j,
1737                                                                            image_pointer_size);
1738                 ++j, ++run) {}
1739             if (run == 0) {
1740               os << StringPrintf("%zd: ", i);
1741             } else {
1742               os << StringPrintf("%zd to %zd: ", i, i + run);
1743               i = i + run;
1744             }
1745             std::string msg;
1746             if (elem == nullptr) {
1747               msg = "null";
1748             } else if (method_section.Contains(
1749                 reinterpret_cast<uint8_t*>(elem) - state->image_space_.Begin())) {
1750               msg = PrettyMethod(reinterpret_cast<ArtMethod*>(elem));
1751             } else {
1752               msg = "<not in method section>";
1753             }
1754             os << StringPrintf("%p   %s\n", elem, msg.c_str());
1755           }
1756         }
1757         size_t num_fields = dex_cache->NumResolvedFields();
1758         if (num_fields != 0u) {
1759           os << "Fields (size=" << num_fields << "):";
1760           ScopedIndentation indent2(&state->vios_);
1761           auto* resolved_fields = dex_cache->GetResolvedFields();
1762           for (size_t i = 0, length = dex_cache->NumResolvedFields(); i < length; ++i) {
1763             auto* elem = mirror::DexCache::GetElementPtrSize(resolved_fields, i, image_pointer_size);
1764             size_t run = 0;
1765             for (size_t j = i + 1;
1766                 j != length && elem == mirror::DexCache::GetElementPtrSize(resolved_fields,
1767                                                                            j,
1768                                                                            image_pointer_size);
1769                 ++j, ++run) {}
1770             if (run == 0) {
1771               os << StringPrintf("%zd: ", i);
1772             } else {
1773               os << StringPrintf("%zd to %zd: ", i, i + run);
1774               i = i + run;
1775             }
1776             std::string msg;
1777             if (elem == nullptr) {
1778               msg = "null";
1779             } else if (field_section.Contains(
1780                 reinterpret_cast<uint8_t*>(elem) - state->image_space_.Begin())) {
1781               msg = PrettyField(reinterpret_cast<ArtField*>(elem));
1782             } else {
1783               msg = "<not in field section>";
1784             }
1785             os << StringPrintf("%p   %s\n", elem, msg.c_str());
1786           }
1787         }
1788       }
1789     }
1790     std::string temp;
1791     state->stats_.Update(obj_class->GetDescriptor(&temp), object_bytes);
1792   }
1793 
DumpMethod(ArtMethod * method,std::ostream & indent_os)1794   void DumpMethod(ArtMethod* method, std::ostream& indent_os)
1795       SHARED_REQUIRES(Locks::mutator_lock_) {
1796     DCHECK(method != nullptr);
1797     const void* quick_oat_code_begin = GetQuickOatCodeBegin(method);
1798     const void* quick_oat_code_end = GetQuickOatCodeEnd(method);
1799     const size_t pointer_size = image_header_.GetPointerSize();
1800     OatQuickMethodHeader* method_header = reinterpret_cast<OatQuickMethodHeader*>(
1801         reinterpret_cast<uintptr_t>(quick_oat_code_begin) - sizeof(OatQuickMethodHeader));
1802     if (method->IsNative()) {
1803       bool first_occurrence;
1804       uint32_t quick_oat_code_size = GetQuickOatCodeSize(method);
1805       ComputeOatSize(quick_oat_code_begin, &first_occurrence);
1806       if (first_occurrence) {
1807         stats_.native_to_managed_code_bytes += quick_oat_code_size;
1808       }
1809       if (quick_oat_code_begin != method->GetEntryPointFromQuickCompiledCodePtrSize(
1810           image_header_.GetPointerSize())) {
1811         indent_os << StringPrintf("OAT CODE: %p\n", quick_oat_code_begin);
1812       }
1813     } else if (method->IsAbstract() || method->IsClassInitializer()) {
1814       // Don't print information for these.
1815     } else if (method->IsRuntimeMethod()) {
1816       ImtConflictTable* table = method->GetImtConflictTable(image_header_.GetPointerSize());
1817       if (table != nullptr) {
1818         indent_os << "IMT conflict table " << table << " method: ";
1819         for (size_t i = 0, count = table->NumEntries(pointer_size); i < count; ++i) {
1820           indent_os << PrettyMethod(table->GetImplementationMethod(i, pointer_size)) << " ";
1821         }
1822       }
1823     } else {
1824       const DexFile::CodeItem* code_item = method->GetCodeItem();
1825       size_t dex_instruction_bytes = code_item->insns_size_in_code_units_ * 2;
1826       stats_.dex_instruction_bytes += dex_instruction_bytes;
1827 
1828       bool first_occurrence;
1829       size_t vmap_table_bytes = 0u;
1830       if (!method_header->IsOptimized()) {
1831         // Method compiled with the optimizing compiler have no vmap table.
1832         vmap_table_bytes = ComputeOatSize(method_header->GetVmapTable(), &first_occurrence);
1833         if (first_occurrence) {
1834           stats_.vmap_table_bytes += vmap_table_bytes;
1835         }
1836       }
1837 
1838       uint32_t quick_oat_code_size = GetQuickOatCodeSize(method);
1839       ComputeOatSize(quick_oat_code_begin, &first_occurrence);
1840       if (first_occurrence) {
1841         stats_.managed_code_bytes += quick_oat_code_size;
1842         if (method->IsConstructor()) {
1843           if (method->IsStatic()) {
1844             stats_.class_initializer_code_bytes += quick_oat_code_size;
1845           } else if (dex_instruction_bytes > kLargeConstructorDexBytes) {
1846             stats_.large_initializer_code_bytes += quick_oat_code_size;
1847           }
1848         } else if (dex_instruction_bytes > kLargeMethodDexBytes) {
1849           stats_.large_method_code_bytes += quick_oat_code_size;
1850         }
1851       }
1852       stats_.managed_code_bytes_ignoring_deduplication += quick_oat_code_size;
1853 
1854       uint32_t method_access_flags = method->GetAccessFlags();
1855 
1856       indent_os << StringPrintf("OAT CODE: %p-%p\n", quick_oat_code_begin, quick_oat_code_end);
1857       indent_os << StringPrintf("SIZE: Dex Instructions=%zd StackMaps=%zd AccessFlags=0x%x\n",
1858                                 dex_instruction_bytes,
1859                                 vmap_table_bytes,
1860                                 method_access_flags);
1861 
1862       size_t total_size = dex_instruction_bytes +
1863           vmap_table_bytes + quick_oat_code_size + ArtMethod::Size(image_header_.GetPointerSize());
1864 
1865       double expansion =
1866       static_cast<double>(quick_oat_code_size) / static_cast<double>(dex_instruction_bytes);
1867       stats_.ComputeOutliers(total_size, expansion, method);
1868     }
1869   }
1870 
1871   std::set<const void*> already_seen_;
1872   // Compute the size of the given data within the oat file and whether this is the first time
1873   // this data has been requested
ComputeOatSize(const void * oat_data,bool * first_occurrence)1874   size_t ComputeOatSize(const void* oat_data, bool* first_occurrence) {
1875     if (already_seen_.count(oat_data) == 0) {
1876       *first_occurrence = true;
1877       already_seen_.insert(oat_data);
1878     } else {
1879       *first_occurrence = false;
1880     }
1881     return oat_dumper_->ComputeSize(oat_data);
1882   }
1883 
1884  public:
1885   struct Stats {
1886     size_t oat_file_bytes;
1887     size_t file_bytes;
1888 
1889     size_t header_bytes;
1890     size_t object_bytes;
1891     size_t art_field_bytes;
1892     size_t art_method_bytes;
1893     size_t dex_cache_arrays_bytes;
1894     size_t interned_strings_bytes;
1895     size_t class_table_bytes;
1896     size_t bitmap_bytes;
1897     size_t alignment_bytes;
1898 
1899     size_t managed_code_bytes;
1900     size_t managed_code_bytes_ignoring_deduplication;
1901     size_t managed_to_native_code_bytes;
1902     size_t native_to_managed_code_bytes;
1903     size_t class_initializer_code_bytes;
1904     size_t large_initializer_code_bytes;
1905     size_t large_method_code_bytes;
1906 
1907     size_t vmap_table_bytes;
1908 
1909     size_t dex_instruction_bytes;
1910 
1911     std::vector<ArtMethod*> method_outlier;
1912     std::vector<size_t> method_outlier_size;
1913     std::vector<double> method_outlier_expansion;
1914     std::vector<std::pair<std::string, size_t>> oat_dex_file_sizes;
1915 
Statsart::ImageDumper::Stats1916     Stats()
1917         : oat_file_bytes(0),
1918           file_bytes(0),
1919           header_bytes(0),
1920           object_bytes(0),
1921           art_field_bytes(0),
1922           art_method_bytes(0),
1923           dex_cache_arrays_bytes(0),
1924           interned_strings_bytes(0),
1925           class_table_bytes(0),
1926           bitmap_bytes(0),
1927           alignment_bytes(0),
1928           managed_code_bytes(0),
1929           managed_code_bytes_ignoring_deduplication(0),
1930           managed_to_native_code_bytes(0),
1931           native_to_managed_code_bytes(0),
1932           class_initializer_code_bytes(0),
1933           large_initializer_code_bytes(0),
1934           large_method_code_bytes(0),
1935           vmap_table_bytes(0),
1936           dex_instruction_bytes(0) {}
1937 
1938     struct SizeAndCount {
SizeAndCountart::ImageDumper::Stats::SizeAndCount1939       SizeAndCount(size_t bytes_in, size_t count_in) : bytes(bytes_in), count(count_in) {}
1940       size_t bytes;
1941       size_t count;
1942     };
1943     typedef SafeMap<std::string, SizeAndCount> SizeAndCountTable;
1944     SizeAndCountTable sizes_and_counts;
1945 
Updateart::ImageDumper::Stats1946     void Update(const char* descriptor, size_t object_bytes_in) {
1947       SizeAndCountTable::iterator it = sizes_and_counts.find(descriptor);
1948       if (it != sizes_and_counts.end()) {
1949         it->second.bytes += object_bytes_in;
1950         it->second.count += 1;
1951       } else {
1952         sizes_and_counts.Put(descriptor, SizeAndCount(object_bytes_in, 1));
1953       }
1954     }
1955 
PercentOfOatBytesart::ImageDumper::Stats1956     double PercentOfOatBytes(size_t size) {
1957       return (static_cast<double>(size) / static_cast<double>(oat_file_bytes)) * 100;
1958     }
1959 
PercentOfFileBytesart::ImageDumper::Stats1960     double PercentOfFileBytes(size_t size) {
1961       return (static_cast<double>(size) / static_cast<double>(file_bytes)) * 100;
1962     }
1963 
PercentOfObjectBytesart::ImageDumper::Stats1964     double PercentOfObjectBytes(size_t size) {
1965       return (static_cast<double>(size) / static_cast<double>(object_bytes)) * 100;
1966     }
1967 
ComputeOutliersart::ImageDumper::Stats1968     void ComputeOutliers(size_t total_size, double expansion, ArtMethod* method) {
1969       method_outlier_size.push_back(total_size);
1970       method_outlier_expansion.push_back(expansion);
1971       method_outlier.push_back(method);
1972     }
1973 
DumpOutliersart::ImageDumper::Stats1974     void DumpOutliers(std::ostream& os)
1975         SHARED_REQUIRES(Locks::mutator_lock_) {
1976       size_t sum_of_sizes = 0;
1977       size_t sum_of_sizes_squared = 0;
1978       size_t sum_of_expansion = 0;
1979       size_t sum_of_expansion_squared = 0;
1980       size_t n = method_outlier_size.size();
1981       if (n == 0) {
1982         return;
1983       }
1984       for (size_t i = 0; i < n; i++) {
1985         size_t cur_size = method_outlier_size[i];
1986         sum_of_sizes += cur_size;
1987         sum_of_sizes_squared += cur_size * cur_size;
1988         double cur_expansion = method_outlier_expansion[i];
1989         sum_of_expansion += cur_expansion;
1990         sum_of_expansion_squared += cur_expansion * cur_expansion;
1991       }
1992       size_t size_mean = sum_of_sizes / n;
1993       size_t size_variance = (sum_of_sizes_squared - sum_of_sizes * size_mean) / (n - 1);
1994       double expansion_mean = sum_of_expansion / n;
1995       double expansion_variance =
1996           (sum_of_expansion_squared - sum_of_expansion * expansion_mean) / (n - 1);
1997 
1998       // Dump methods whose size is a certain number of standard deviations from the mean
1999       size_t dumped_values = 0;
2000       size_t skipped_values = 0;
2001       for (size_t i = 100; i > 0; i--) {  // i is the current number of standard deviations
2002         size_t cur_size_variance = i * i * size_variance;
2003         bool first = true;
2004         for (size_t j = 0; j < n; j++) {
2005           size_t cur_size = method_outlier_size[j];
2006           if (cur_size > size_mean) {
2007             size_t cur_var = cur_size - size_mean;
2008             cur_var = cur_var * cur_var;
2009             if (cur_var > cur_size_variance) {
2010               if (dumped_values > 20) {
2011                 if (i == 1) {
2012                   skipped_values++;
2013                 } else {
2014                   i = 2;  // jump to counting for 1 standard deviation
2015                   break;
2016                 }
2017               } else {
2018                 if (first) {
2019                   os << "\nBig methods (size > " << i << " standard deviations the norm):\n";
2020                   first = false;
2021                 }
2022                 os << PrettyMethod(method_outlier[j]) << " requires storage of "
2023                     << PrettySize(cur_size) << "\n";
2024                 method_outlier_size[j] = 0;  // don't consider this method again
2025                 dumped_values++;
2026               }
2027             }
2028           }
2029         }
2030       }
2031       if (skipped_values > 0) {
2032         os << "... skipped " << skipped_values
2033            << " methods with size > 1 standard deviation from the norm\n";
2034       }
2035       os << std::flush;
2036 
2037       // Dump methods whose expansion is a certain number of standard deviations from the mean
2038       dumped_values = 0;
2039       skipped_values = 0;
2040       for (size_t i = 10; i > 0; i--) {  // i is the current number of standard deviations
2041         double cur_expansion_variance = i * i * expansion_variance;
2042         bool first = true;
2043         for (size_t j = 0; j < n; j++) {
2044           double cur_expansion = method_outlier_expansion[j];
2045           if (cur_expansion > expansion_mean) {
2046             size_t cur_var = cur_expansion - expansion_mean;
2047             cur_var = cur_var * cur_var;
2048             if (cur_var > cur_expansion_variance) {
2049               if (dumped_values > 20) {
2050                 if (i == 1) {
2051                   skipped_values++;
2052                 } else {
2053                   i = 2;  // jump to counting for 1 standard deviation
2054                   break;
2055                 }
2056               } else {
2057                 if (first) {
2058                   os << "\nLarge expansion methods (size > " << i
2059                       << " standard deviations the norm):\n";
2060                   first = false;
2061                 }
2062                 os << PrettyMethod(method_outlier[j]) << " expanded code by "
2063                    << cur_expansion << "\n";
2064                 method_outlier_expansion[j] = 0.0;  // don't consider this method again
2065                 dumped_values++;
2066               }
2067             }
2068           }
2069         }
2070       }
2071       if (skipped_values > 0) {
2072         os << "... skipped " << skipped_values
2073            << " methods with expansion > 1 standard deviation from the norm\n";
2074       }
2075       os << "\n" << std::flush;
2076     }
2077 
Dumpart::ImageDumper::Stats2078     void Dump(std::ostream& os, std::ostream& indent_os)
2079         SHARED_REQUIRES(Locks::mutator_lock_) {
2080       {
2081         os << "art_file_bytes = " << PrettySize(file_bytes) << "\n\n"
2082            << "art_file_bytes = header_bytes + object_bytes + alignment_bytes\n";
2083         indent_os << StringPrintf("header_bytes           =  %8zd (%2.0f%% of art file bytes)\n"
2084                                   "object_bytes           =  %8zd (%2.0f%% of art file bytes)\n"
2085                                   "art_field_bytes        =  %8zd (%2.0f%% of art file bytes)\n"
2086                                   "art_method_bytes       =  %8zd (%2.0f%% of art file bytes)\n"
2087                                   "dex_cache_arrays_bytes =  %8zd (%2.0f%% of art file bytes)\n"
2088                                   "interned_string_bytes  =  %8zd (%2.0f%% of art file bytes)\n"
2089                                   "class_table_bytes      =  %8zd (%2.0f%% of art file bytes)\n"
2090                                   "bitmap_bytes           =  %8zd (%2.0f%% of art file bytes)\n"
2091                                   "alignment_bytes        =  %8zd (%2.0f%% of art file bytes)\n\n",
2092                                   header_bytes, PercentOfFileBytes(header_bytes),
2093                                   object_bytes, PercentOfFileBytes(object_bytes),
2094                                   art_field_bytes, PercentOfFileBytes(art_field_bytes),
2095                                   art_method_bytes, PercentOfFileBytes(art_method_bytes),
2096                                   dex_cache_arrays_bytes,
2097                                   PercentOfFileBytes(dex_cache_arrays_bytes),
2098                                   interned_strings_bytes,
2099                                   PercentOfFileBytes(interned_strings_bytes),
2100                                   class_table_bytes, PercentOfFileBytes(class_table_bytes),
2101                                   bitmap_bytes, PercentOfFileBytes(bitmap_bytes),
2102                                   alignment_bytes, PercentOfFileBytes(alignment_bytes))
2103             << std::flush;
2104         CHECK_EQ(file_bytes,
2105                  header_bytes + object_bytes + art_field_bytes + art_method_bytes +
2106                  dex_cache_arrays_bytes + interned_strings_bytes + class_table_bytes +
2107                  bitmap_bytes + alignment_bytes);
2108       }
2109 
2110       os << "object_bytes breakdown:\n";
2111       size_t object_bytes_total = 0;
2112       for (const auto& sizes_and_count : sizes_and_counts) {
2113         const std::string& descriptor(sizes_and_count.first);
2114         double average = static_cast<double>(sizes_and_count.second.bytes) /
2115             static_cast<double>(sizes_and_count.second.count);
2116         double percent = PercentOfObjectBytes(sizes_and_count.second.bytes);
2117         os << StringPrintf("%32s %8zd bytes %6zd instances "
2118                            "(%4.0f bytes/instance) %2.0f%% of object_bytes\n",
2119                            descriptor.c_str(), sizes_and_count.second.bytes,
2120                            sizes_and_count.second.count, average, percent);
2121         object_bytes_total += sizes_and_count.second.bytes;
2122       }
2123       os << "\n" << std::flush;
2124       CHECK_EQ(object_bytes, object_bytes_total);
2125 
2126       os << StringPrintf("oat_file_bytes               = %8zd\n"
2127                          "managed_code_bytes           = %8zd (%2.0f%% of oat file bytes)\n"
2128                          "managed_to_native_code_bytes = %8zd (%2.0f%% of oat file bytes)\n"
2129                          "native_to_managed_code_bytes = %8zd (%2.0f%% of oat file bytes)\n\n"
2130                          "class_initializer_code_bytes = %8zd (%2.0f%% of oat file bytes)\n"
2131                          "large_initializer_code_bytes = %8zd (%2.0f%% of oat file bytes)\n"
2132                          "large_method_code_bytes      = %8zd (%2.0f%% of oat file bytes)\n\n",
2133                          oat_file_bytes,
2134                          managed_code_bytes,
2135                          PercentOfOatBytes(managed_code_bytes),
2136                          managed_to_native_code_bytes,
2137                          PercentOfOatBytes(managed_to_native_code_bytes),
2138                          native_to_managed_code_bytes,
2139                          PercentOfOatBytes(native_to_managed_code_bytes),
2140                          class_initializer_code_bytes,
2141                          PercentOfOatBytes(class_initializer_code_bytes),
2142                          large_initializer_code_bytes,
2143                          PercentOfOatBytes(large_initializer_code_bytes),
2144                          large_method_code_bytes,
2145                          PercentOfOatBytes(large_method_code_bytes))
2146             << "DexFile sizes:\n";
2147       for (const std::pair<std::string, size_t>& oat_dex_file_size : oat_dex_file_sizes) {
2148         os << StringPrintf("%s = %zd (%2.0f%% of oat file bytes)\n",
2149                            oat_dex_file_size.first.c_str(), oat_dex_file_size.second,
2150                            PercentOfOatBytes(oat_dex_file_size.second));
2151       }
2152 
2153       os << "\n" << StringPrintf("vmap_table_bytes       = %7zd (%2.0f%% of oat file bytes)\n\n",
2154                                  vmap_table_bytes, PercentOfOatBytes(vmap_table_bytes))
2155          << std::flush;
2156 
2157       os << StringPrintf("dex_instruction_bytes = %zd\n", dex_instruction_bytes)
2158          << StringPrintf("managed_code_bytes expansion = %.2f (ignoring deduplication %.2f)\n\n",
2159                          static_cast<double>(managed_code_bytes) /
2160                              static_cast<double>(dex_instruction_bytes),
2161                          static_cast<double>(managed_code_bytes_ignoring_deduplication) /
2162                              static_cast<double>(dex_instruction_bytes))
2163          << std::flush;
2164 
2165       DumpOutliers(os);
2166     }
2167   } stats_;
2168 
2169  private:
2170   enum {
2171     // Number of bytes for a constructor to be considered large. Based on the 1000 basic block
2172     // threshold, we assume 2 bytes per instruction and 2 instructions per block.
2173     kLargeConstructorDexBytes = 4000,
2174     // Number of bytes for a method to be considered large. Based on the 4000 basic block
2175     // threshold, we assume 2 bytes per instruction and 2 instructions per block.
2176     kLargeMethodDexBytes = 16000
2177   };
2178 
2179   // For performance, use the *os_ directly for anything that doesn't need indentation
2180   // and prepare an indentation stream with default indentation 1.
2181   std::ostream* os_;
2182   VariableIndentationOutputStream vios_;
2183   ScopedIndentation indent1_;
2184 
2185   gc::space::ImageSpace& image_space_;
2186   const ImageHeader& image_header_;
2187   std::unique_ptr<OatDumper> oat_dumper_;
2188   OatDumperOptions* oat_dumper_options_;
2189   std::set<mirror::Object*> dex_caches_;
2190 
2191   DISALLOW_COPY_AND_ASSIGN(ImageDumper);
2192 };
2193 
DumpImage(gc::space::ImageSpace * image_space,OatDumperOptions * options,std::ostream * os)2194 static int DumpImage(gc::space::ImageSpace* image_space,
2195                      OatDumperOptions* options,
2196                      std::ostream* os) SHARED_REQUIRES(Locks::mutator_lock_) {
2197   const ImageHeader& image_header = image_space->GetImageHeader();
2198   if (!image_header.IsValid()) {
2199     fprintf(stderr, "Invalid image header %s\n", image_space->GetImageLocation().c_str());
2200     return EXIT_FAILURE;
2201   }
2202   ImageDumper image_dumper(os, *image_space, image_header, options);
2203   if (!image_dumper.Dump()) {
2204     return EXIT_FAILURE;
2205   }
2206   return EXIT_SUCCESS;
2207 }
2208 
DumpImages(Runtime * runtime,OatDumperOptions * options,std::ostream * os)2209 static int DumpImages(Runtime* runtime, OatDumperOptions* options, std::ostream* os) {
2210   // Dumping the image, no explicit class loader.
2211   ScopedNullHandle<mirror::ClassLoader> null_class_loader;
2212   options->class_loader_ = &null_class_loader;
2213 
2214   ScopedObjectAccess soa(Thread::Current());
2215   if (options->app_image_ != nullptr) {
2216     if (options->app_oat_ == nullptr) {
2217       LOG(ERROR) << "Can not dump app image without app oat file";
2218       return EXIT_FAILURE;
2219     }
2220     // We can't know if the app image is 32 bits yet, but it contains pointers into the oat file.
2221     // We need to map the oat file in the low 4gb or else the fixup wont be able to fit oat file
2222     // pointers into 32 bit pointer sized ArtMethods.
2223     std::string error_msg;
2224     std::unique_ptr<OatFile> oat_file(OatFile::Open(options->app_oat_,
2225                                                     options->app_oat_,
2226                                                     nullptr,
2227                                                     nullptr,
2228                                                     false,
2229                                                     /*low_4gb*/true,
2230                                                     nullptr,
2231                                                     &error_msg));
2232     if (oat_file == nullptr) {
2233       LOG(ERROR) << "Failed to open oat file " << options->app_oat_ << " with error " << error_msg;
2234       return EXIT_FAILURE;
2235     }
2236     std::unique_ptr<gc::space::ImageSpace> space(
2237         gc::space::ImageSpace::CreateFromAppImage(options->app_image_, oat_file.get(), &error_msg));
2238     if (space == nullptr) {
2239       LOG(ERROR) << "Failed to open app image " << options->app_image_ << " with error "
2240                  << error_msg;
2241     }
2242     // Open dex files for the image.
2243     std::vector<std::unique_ptr<const DexFile>> dex_files;
2244     if (!runtime->GetClassLinker()->OpenImageDexFiles(space.get(), &dex_files, &error_msg)) {
2245       LOG(ERROR) << "Failed to open app image dex files " << options->app_image_ << " with error "
2246                  << error_msg;
2247     }
2248     // Dump the actual image.
2249     int result = DumpImage(space.get(), options, os);
2250     if (result != EXIT_SUCCESS) {
2251       return result;
2252     }
2253     // Fall through to dump the boot images.
2254   }
2255 
2256   gc::Heap* heap = runtime->GetHeap();
2257   CHECK(heap->HasBootImageSpace()) << "No image spaces";
2258   for (gc::space::ImageSpace* image_space : heap->GetBootImageSpaces()) {
2259     int result = DumpImage(image_space, options, os);
2260     if (result != EXIT_SUCCESS) {
2261       return result;
2262     }
2263   }
2264   return EXIT_SUCCESS;
2265 }
2266 
DumpOatWithRuntime(Runtime * runtime,OatFile * oat_file,OatDumperOptions * options,std::ostream * os)2267 static int DumpOatWithRuntime(Runtime* runtime, OatFile* oat_file, OatDumperOptions* options,
2268                               std::ostream* os) {
2269   CHECK(runtime != nullptr && oat_file != nullptr && options != nullptr);
2270 
2271   Thread* self = Thread::Current();
2272   CHECK(self != nullptr);
2273   // Need well-known-classes.
2274   WellKnownClasses::Init(self->GetJniEnv());
2275 
2276   // Need to register dex files to get a working dex cache.
2277   ScopedObjectAccess soa(self);
2278   ClassLinker* class_linker = runtime->GetClassLinker();
2279   runtime->GetOatFileManager().RegisterOatFile(std::unique_ptr<const OatFile>(oat_file));
2280   std::vector<const DexFile*> class_path;
2281   for (const OatFile::OatDexFile* odf : oat_file->GetOatDexFiles()) {
2282     std::string error_msg;
2283     const DexFile* const dex_file = OpenDexFile(odf, &error_msg);
2284     CHECK(dex_file != nullptr) << error_msg;
2285     class_linker->RegisterDexFile(*dex_file, nullptr);
2286     class_path.push_back(dex_file);
2287   }
2288 
2289   // Need a class loader.
2290   // Fake that we're a compiler.
2291   jobject class_loader = class_linker->CreatePathClassLoader(self, class_path);
2292 
2293   // Use the class loader while dumping.
2294   StackHandleScope<1> scope(self);
2295   Handle<mirror::ClassLoader> loader_handle = scope.NewHandle(
2296       soa.Decode<mirror::ClassLoader*>(class_loader));
2297   options->class_loader_ = &loader_handle;
2298 
2299   OatDumper oat_dumper(*oat_file, *options);
2300   bool success = oat_dumper.Dump(*os);
2301   return (success) ? EXIT_SUCCESS : EXIT_FAILURE;
2302 }
2303 
DumpOatWithoutRuntime(OatFile * oat_file,OatDumperOptions * options,std::ostream * os)2304 static int DumpOatWithoutRuntime(OatFile* oat_file, OatDumperOptions* options, std::ostream* os) {
2305   CHECK(oat_file != nullptr && options != nullptr);
2306   // No image = no class loader.
2307   ScopedNullHandle<mirror::ClassLoader> null_class_loader;
2308   options->class_loader_ = &null_class_loader;
2309 
2310   OatDumper oat_dumper(*oat_file, *options);
2311   bool success = oat_dumper.Dump(*os);
2312   return (success) ? EXIT_SUCCESS : EXIT_FAILURE;
2313 }
2314 
DumpOat(Runtime * runtime,const char * oat_filename,OatDumperOptions * options,std::ostream * os)2315 static int DumpOat(Runtime* runtime, const char* oat_filename, OatDumperOptions* options,
2316                    std::ostream* os) {
2317   std::string error_msg;
2318   OatFile* oat_file = OatFile::Open(oat_filename,
2319                                     oat_filename,
2320                                     nullptr,
2321                                     nullptr,
2322                                     false,
2323                                     /*low_4gb*/false,
2324                                     nullptr,
2325                                     &error_msg);
2326   if (oat_file == nullptr) {
2327     fprintf(stderr, "Failed to open oat file from '%s': %s\n", oat_filename, error_msg.c_str());
2328     return EXIT_FAILURE;
2329   }
2330 
2331   if (runtime != nullptr) {
2332     return DumpOatWithRuntime(runtime, oat_file, options, os);
2333   } else {
2334     return DumpOatWithoutRuntime(oat_file, options, os);
2335   }
2336 }
2337 
SymbolizeOat(const char * oat_filename,std::string & output_name,bool no_bits)2338 static int SymbolizeOat(const char* oat_filename, std::string& output_name, bool no_bits) {
2339   std::string error_msg;
2340   OatFile* oat_file = OatFile::Open(oat_filename,
2341                                     oat_filename,
2342                                     nullptr,
2343                                     nullptr,
2344                                     false,
2345                                     /*low_4gb*/false,
2346                                     nullptr,
2347                                     &error_msg);
2348   if (oat_file == nullptr) {
2349     fprintf(stderr, "Failed to open oat file from '%s': %s\n", oat_filename, error_msg.c_str());
2350     return EXIT_FAILURE;
2351   }
2352 
2353   bool result;
2354   // Try to produce an ELF file of the same type. This is finicky, as we have used 32-bit ELF
2355   // files for 64-bit code in the past.
2356   if (Is64BitInstructionSet(oat_file->GetOatHeader().GetInstructionSet())) {
2357     OatSymbolizer<ElfTypes64> oat_symbolizer(oat_file, output_name, no_bits);
2358     result = oat_symbolizer.Symbolize();
2359   } else {
2360     OatSymbolizer<ElfTypes32> oat_symbolizer(oat_file, output_name, no_bits);
2361     result = oat_symbolizer.Symbolize();
2362   }
2363   if (!result) {
2364     fprintf(stderr, "Failed to symbolize\n");
2365     return EXIT_FAILURE;
2366   }
2367 
2368   return EXIT_SUCCESS;
2369 }
2370 
2371 struct OatdumpArgs : public CmdlineArgs {
2372  protected:
2373   using Base = CmdlineArgs;
2374 
ParseCustomart::OatdumpArgs2375   virtual ParseStatus ParseCustom(const StringPiece& option,
2376                                   std::string* error_msg) OVERRIDE {
2377     {
2378       ParseStatus base_parse = Base::ParseCustom(option, error_msg);
2379       if (base_parse != kParseUnknownArgument) {
2380         return base_parse;
2381       }
2382     }
2383 
2384     if (option.starts_with("--oat-file=")) {
2385       oat_filename_ = option.substr(strlen("--oat-file=")).data();
2386     } else if (option.starts_with("--image=")) {
2387       image_location_ = option.substr(strlen("--image=")).data();
2388     } else if (option == "--no-dump:vmap") {
2389       dump_vmap_ = false;
2390     } else if (option =="--dump:code_info_stack_maps") {
2391       dump_code_info_stack_maps_ = true;
2392     } else if (option == "--no-disassemble") {
2393       disassemble_code_ = false;
2394     } else if (option =="--header-only") {
2395       dump_header_only_ = true;
2396     } else if (option.starts_with("--symbolize=")) {
2397       oat_filename_ = option.substr(strlen("--symbolize=")).data();
2398       symbolize_ = true;
2399     } else if (option.starts_with("--only-keep-debug")) {
2400       only_keep_debug_ = true;
2401     } else if (option.starts_with("--class-filter=")) {
2402       class_filter_ = option.substr(strlen("--class-filter=")).data();
2403     } else if (option.starts_with("--method-filter=")) {
2404       method_filter_ = option.substr(strlen("--method-filter=")).data();
2405     } else if (option.starts_with("--list-classes")) {
2406       list_classes_ = true;
2407     } else if (option.starts_with("--list-methods")) {
2408       list_methods_ = true;
2409     } else if (option.starts_with("--export-dex-to=")) {
2410       export_dex_location_ = option.substr(strlen("--export-dex-to=")).data();
2411     } else if (option.starts_with("--addr2instr=")) {
2412       if (!ParseUint(option.substr(strlen("--addr2instr=")).data(), &addr2instr_)) {
2413         *error_msg = "Address conversion failed";
2414         return kParseError;
2415       }
2416     } else if (option.starts_with("--app-image=")) {
2417       app_image_ = option.substr(strlen("--app-image=")).data();
2418     } else if (option.starts_with("--app-oat=")) {
2419       app_oat_ = option.substr(strlen("--app-oat=")).data();
2420     } else {
2421       return kParseUnknownArgument;
2422     }
2423 
2424     return kParseOk;
2425   }
2426 
ParseChecksart::OatdumpArgs2427   virtual ParseStatus ParseChecks(std::string* error_msg) OVERRIDE {
2428     // Infer boot image location from the image location if possible.
2429     if (boot_image_location_ == nullptr) {
2430       boot_image_location_ = image_location_;
2431     }
2432 
2433     // Perform the parent checks.
2434     ParseStatus parent_checks = Base::ParseChecks(error_msg);
2435     if (parent_checks != kParseOk) {
2436       return parent_checks;
2437     }
2438 
2439     // Perform our own checks.
2440     if (image_location_ == nullptr && oat_filename_ == nullptr) {
2441       *error_msg = "Either --image or --oat-file must be specified";
2442       return kParseError;
2443     } else if (image_location_ != nullptr && oat_filename_ != nullptr) {
2444       *error_msg = "Either --image or --oat-file must be specified but not both";
2445       return kParseError;
2446     }
2447 
2448     return kParseOk;
2449   }
2450 
GetUsageart::OatdumpArgs2451   virtual std::string GetUsage() const {
2452     std::string usage;
2453 
2454     usage +=
2455         "Usage: oatdump [options] ...\n"
2456         "    Example: oatdump --image=$ANDROID_PRODUCT_OUT/system/framework/boot.art\n"
2457         "    Example: adb shell oatdump --image=/system/framework/boot.art\n"
2458         "\n"
2459         // Either oat-file or image is required.
2460         "  --oat-file=<file.oat>: specifies an input oat filename.\n"
2461         "      Example: --oat-file=/system/framework/boot.oat\n"
2462         "\n"
2463         "  --image=<file.art>: specifies an input image location.\n"
2464         "      Example: --image=/system/framework/boot.art\n"
2465         "\n"
2466         "  --app-image=<file.art>: specifies an input app image. Must also have a specified\n"
2467         " boot image and app oat file.\n"
2468         "      Example: --app-image=app.art\n"
2469         "\n"
2470         "  --app-oat=<file.odex>: specifies an input app oat.\n"
2471         "      Example: --app-oat=app.odex\n"
2472         "\n";
2473 
2474     usage += Base::GetUsage();
2475 
2476     usage +=  // Optional.
2477         "  --no-dump:vmap may be used to disable vmap dumping.\n"
2478         "      Example: --no-dump:vmap\n"
2479         "\n"
2480         "  --dump:code_info_stack_maps enables dumping of stack maps in CodeInfo sections.\n"
2481         "      Example: --dump:code_info_stack_maps\n"
2482         "\n"
2483         "  --no-disassemble may be used to disable disassembly.\n"
2484         "      Example: --no-disassemble\n"
2485         "\n"
2486         "  --header-only may be used to print only the oat header.\n"
2487         "      Example: --header-only\n"
2488         "\n"
2489         "  --list-classes may be used to list target file classes (can be used with filters).\n"
2490         "      Example: --list-classes\n"
2491         "      Example: --list-classes --class-filter=com.example.foo\n"
2492         "\n"
2493         "  --list-methods may be used to list target file methods (can be used with filters).\n"
2494         "      Example: --list-methods\n"
2495         "      Example: --list-methods --class-filter=com.example --method-filter=foo\n"
2496         "\n"
2497         "  --symbolize=<file.oat>: output a copy of file.oat with elf symbols included.\n"
2498         "      Example: --symbolize=/system/framework/boot.oat\n"
2499         "\n"
2500         "  --only-keep-debug<file.oat>: Modifies the behaviour of --symbolize so that\n"
2501         "      .rodata and .text sections are omitted in the output file to save space.\n"
2502         "      Example: --symbolize=/system/framework/boot.oat --only-keep-debug\n"
2503         "\n"
2504         "  --class-filter=<class name>: only dumps classes that contain the filter.\n"
2505         "      Example: --class-filter=com.example.foo\n"
2506         "\n"
2507         "  --method-filter=<method name>: only dumps methods that contain the filter.\n"
2508         "      Example: --method-filter=foo\n"
2509         "\n"
2510         "  --export-dex-to=<directory>: may be used to export oat embedded dex files.\n"
2511         "      Example: --export-dex-to=/data/local/tmp\n"
2512         "\n"
2513         "  --addr2instr=<address>: output matching method disassembled code from relative\n"
2514         "                          address (e.g. PC from crash dump)\n"
2515         "      Example: --addr2instr=0x00001a3b\n"
2516         "\n";
2517 
2518     return usage;
2519   }
2520 
2521  public:
2522   const char* oat_filename_ = nullptr;
2523   const char* class_filter_ = "";
2524   const char* method_filter_ = "";
2525   const char* image_location_ = nullptr;
2526   std::string elf_filename_prefix_;
2527   bool dump_vmap_ = true;
2528   bool dump_code_info_stack_maps_ = false;
2529   bool disassemble_code_ = true;
2530   bool symbolize_ = false;
2531   bool only_keep_debug_ = false;
2532   bool list_classes_ = false;
2533   bool list_methods_ = false;
2534   bool dump_header_only_ = false;
2535   uint32_t addr2instr_ = 0;
2536   const char* export_dex_location_ = nullptr;
2537   const char* app_image_ = nullptr;
2538   const char* app_oat_ = nullptr;
2539 };
2540 
2541 struct OatdumpMain : public CmdlineMain<OatdumpArgs> {
NeedsRuntimeart::OatdumpMain2542   virtual bool NeedsRuntime() OVERRIDE {
2543     CHECK(args_ != nullptr);
2544 
2545     // If we are only doing the oat file, disable absolute_addresses. Keep them for image dumping.
2546     bool absolute_addresses = (args_->oat_filename_ == nullptr);
2547 
2548     oat_dumper_options_.reset(new OatDumperOptions(
2549         args_->dump_vmap_,
2550         args_->dump_code_info_stack_maps_,
2551         args_->disassemble_code_,
2552         absolute_addresses,
2553         args_->class_filter_,
2554         args_->method_filter_,
2555         args_->list_classes_,
2556         args_->list_methods_,
2557         args_->dump_header_only_,
2558         args_->export_dex_location_,
2559         args_->app_image_,
2560         args_->app_oat_,
2561         args_->addr2instr_));
2562 
2563     return (args_->boot_image_location_ != nullptr || args_->image_location_ != nullptr) &&
2564           !args_->symbolize_;
2565   }
2566 
ExecuteWithoutRuntimeart::OatdumpMain2567   virtual bool ExecuteWithoutRuntime() OVERRIDE {
2568     CHECK(args_ != nullptr);
2569     CHECK(args_->oat_filename_ != nullptr);
2570 
2571     MemMap::Init();
2572 
2573     if (args_->symbolize_) {
2574       // ELF has special kind of section called SHT_NOBITS which allows us to create
2575       // sections which exist but their data is omitted from the ELF file to save space.
2576       // This is what "strip --only-keep-debug" does when it creates separate ELF file
2577       // with only debug data. We use it in similar way to exclude .rodata and .text.
2578       bool no_bits = args_->only_keep_debug_;
2579       return SymbolizeOat(args_->oat_filename_, args_->output_name_, no_bits) == EXIT_SUCCESS;
2580     } else {
2581       return DumpOat(nullptr,
2582                      args_->oat_filename_,
2583                      oat_dumper_options_.get(),
2584                      args_->os_) == EXIT_SUCCESS;
2585     }
2586   }
2587 
ExecuteWithRuntimeart::OatdumpMain2588   virtual bool ExecuteWithRuntime(Runtime* runtime) {
2589     CHECK(args_ != nullptr);
2590 
2591     if (args_->oat_filename_ != nullptr) {
2592       return DumpOat(runtime,
2593                      args_->oat_filename_,
2594                      oat_dumper_options_.get(),
2595                      args_->os_) == EXIT_SUCCESS;
2596     }
2597 
2598     return DumpImages(runtime, oat_dumper_options_.get(), args_->os_) == EXIT_SUCCESS;
2599   }
2600 
2601   std::unique_ptr<OatDumperOptions> oat_dumper_options_;
2602 };
2603 
2604 }  // namespace art
2605 
main(int argc,char ** argv)2606 int main(int argc, char** argv) {
2607   art::OatdumpMain main;
2608   return main.Main(argc, argv);
2609 }
2610