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