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