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 <unordered_set> 27 #include <vector> 28 29 #include "android-base/stringprintf.h" 30 #include "android-base/strings.h" 31 32 #include "arch/instruction_set_features.h" 33 #include "art_field-inl.h" 34 #include "art_method-inl.h" 35 #include "base/stl_util.h" 36 #include "base/unix_file/fd_file.h" 37 #include "class_linker-inl.h" 38 #include "class_linker.h" 39 #include "debug/elf_debug_writer.h" 40 #include "debug/method_debug_info.h" 41 #include "dex_file-inl.h" 42 #include "dex_instruction-inl.h" 43 #include "disassembler.h" 44 #include "elf_builder.h" 45 #include "gc/accounting/space_bitmap-inl.h" 46 #include "gc/space/image_space.h" 47 #include "gc/space/large_object_space.h" 48 #include "gc/space/space-inl.h" 49 #include "image-inl.h" 50 #include "imtable-inl.h" 51 #include "indenter.h" 52 #include "interpreter/unstarted_runtime.h" 53 #include "linker/buffered_output_stream.h" 54 #include "linker/file_output_stream.h" 55 #include "mirror/array-inl.h" 56 #include "mirror/class-inl.h" 57 #include "mirror/dex_cache-inl.h" 58 #include "mirror/object-inl.h" 59 #include "mirror/object_array-inl.h" 60 #include "nativehelper/ScopedLocalRef.h" 61 #include "oat.h" 62 #include "oat_file-inl.h" 63 #include "oat_file_manager.h" 64 #include "os.h" 65 #include "safe_map.h" 66 #include "scoped_thread_state_change-inl.h" 67 #include "stack.h" 68 #include "stack_map.h" 69 #include "string_reference.h" 70 #include "thread_list.h" 71 #include "type_lookup_table.h" 72 #include "vdex_file.h" 73 #include "verifier/method_verifier.h" 74 #include "verifier/verifier_deps.h" 75 #include "well_known_classes.h" 76 77 #include <sys/stat.h> 78 #include "cmdline.h" 79 80 namespace art { 81 82 using android::base::StringPrintf; 83 84 const char* image_methods_descriptions_[] = { 85 "kResolutionMethod", 86 "kImtConflictMethod", 87 "kImtUnimplementedMethod", 88 "kSaveAllCalleeSavesMethod", 89 "kSaveRefsOnlyMethod", 90 "kSaveRefsAndArgsMethod", 91 "kSaveEverythingMethod", 92 }; 93 94 const char* image_roots_descriptions_[] = { 95 "kDexCaches", 96 "kClassRoots", 97 "kClassLoader", 98 }; 99 100 // Map is so that we don't allocate multiple dex files for the same OatDexFile. 101 static std::map<const OatFile::OatDexFile*, 102 std::unique_ptr<const DexFile>> opened_dex_files; 103 104 const DexFile* OpenDexFile(const OatFile::OatDexFile* oat_dex_file, std::string* error_msg) { 105 DCHECK(oat_dex_file != nullptr); 106 auto it = opened_dex_files.find(oat_dex_file); 107 if (it != opened_dex_files.end()) { 108 return it->second.get(); 109 } 110 const DexFile* ret = oat_dex_file->OpenDexFile(error_msg).release(); 111 opened_dex_files.emplace(oat_dex_file, std::unique_ptr<const DexFile>(ret)); 112 return ret; 113 } 114 115 template <typename ElfTypes> 116 class OatSymbolizer FINAL { 117 public: 118 OatSymbolizer(const OatFile* oat_file, const std::string& output_name, bool no_bits) : 119 oat_file_(oat_file), 120 builder_(nullptr), 121 output_name_(output_name.empty() ? "symbolized.oat" : output_name), 122 no_bits_(no_bits) { 123 } 124 125 bool Symbolize() { 126 const InstructionSet isa = oat_file_->GetOatHeader().GetInstructionSet(); 127 std::unique_ptr<const InstructionSetFeatures> features = InstructionSetFeatures::FromBitmap( 128 isa, oat_file_->GetOatHeader().GetInstructionSetFeaturesBitmap()); 129 130 std::unique_ptr<File> elf_file(OS::CreateEmptyFile(output_name_.c_str())); 131 if (elf_file == nullptr) { 132 return false; 133 } 134 std::unique_ptr<BufferedOutputStream> output_stream = 135 std::make_unique<BufferedOutputStream>(std::make_unique<FileOutputStream>(elf_file.get())); 136 builder_.reset(new ElfBuilder<ElfTypes>(isa, features.get(), output_stream.get())); 137 138 builder_->Start(); 139 140 auto* rodata = builder_->GetRoData(); 141 auto* text = builder_->GetText(); 142 auto* bss = builder_->GetBss(); 143 144 const uint8_t* rodata_begin = oat_file_->Begin(); 145 const size_t rodata_size = oat_file_->GetOatHeader().GetExecutableOffset(); 146 if (no_bits_) { 147 rodata->WriteNoBitsSection(rodata_size); 148 } else { 149 rodata->Start(); 150 rodata->WriteFully(rodata_begin, rodata_size); 151 rodata->End(); 152 } 153 154 const uint8_t* text_begin = oat_file_->Begin() + rodata_size; 155 const size_t text_size = oat_file_->End() - text_begin; 156 if (no_bits_) { 157 text->WriteNoBitsSection(text_size); 158 } else { 159 text->Start(); 160 text->WriteFully(text_begin, text_size); 161 text->End(); 162 } 163 164 if (oat_file_->BssSize() != 0) { 165 bss->WriteNoBitsSection(oat_file_->BssSize()); 166 } 167 168 if (isa == kMips || isa == kMips64) { 169 builder_->WriteMIPSabiflagsSection(); 170 } 171 builder_->PrepareDynamicSection(elf_file->GetPath(), 172 rodata_size, 173 text_size, 174 oat_file_->BssSize(), 175 oat_file_->BssMethodsOffset(), 176 oat_file_->BssRootsOffset()); 177 builder_->WriteDynamicSection(); 178 179 Walk(); 180 for (const auto& trampoline : debug::MakeTrampolineInfos(oat_file_->GetOatHeader())) { 181 method_debug_infos_.push_back(trampoline); 182 } 183 184 debug::WriteDebugInfo(builder_.get(), 185 ArrayRef<const debug::MethodDebugInfo>(method_debug_infos_), 186 dwarf::DW_DEBUG_FRAME_FORMAT, 187 true /* write_oat_patches */); 188 189 builder_->End(); 190 191 bool ret_value = builder_->Good(); 192 193 builder_.reset(); 194 output_stream.reset(); 195 196 if (elf_file->FlushCloseOrErase() != 0) { 197 return false; 198 } 199 elf_file.reset(); 200 201 return ret_value; 202 } 203 204 void Walk() { 205 std::vector<const OatFile::OatDexFile*> oat_dex_files = oat_file_->GetOatDexFiles(); 206 for (size_t i = 0; i < oat_dex_files.size(); i++) { 207 const OatFile::OatDexFile* oat_dex_file = oat_dex_files[i]; 208 CHECK(oat_dex_file != nullptr); 209 WalkOatDexFile(oat_dex_file); 210 } 211 } 212 213 void WalkOatDexFile(const OatFile::OatDexFile* oat_dex_file) { 214 std::string error_msg; 215 const DexFile* const dex_file = OpenDexFile(oat_dex_file, &error_msg); 216 if (dex_file == nullptr) { 217 return; 218 } 219 for (size_t class_def_index = 0; 220 class_def_index < dex_file->NumClassDefs(); 221 class_def_index++) { 222 const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index); 223 OatClassType type = oat_class.GetType(); 224 switch (type) { 225 case kOatClassAllCompiled: 226 case kOatClassSomeCompiled: 227 WalkOatClass(oat_class, *dex_file, class_def_index); 228 break; 229 230 case kOatClassNoneCompiled: 231 case kOatClassMax: 232 // Ignore. 233 break; 234 } 235 } 236 } 237 238 void WalkOatClass(const OatFile::OatClass& oat_class, 239 const DexFile& dex_file, 240 uint32_t class_def_index) { 241 const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index); 242 const uint8_t* class_data = dex_file.GetClassData(class_def); 243 if (class_data == nullptr) { // empty class such as a marker interface? 244 return; 245 } 246 // Note: even if this is an interface or a native class, we still have to walk it, as there 247 // might be a static initializer. 248 ClassDataItemIterator it(dex_file, class_data); 249 uint32_t class_method_idx = 0; 250 it.SkipAllFields(); 251 for (; it.HasNextDirectMethod() || it.HasNextVirtualMethod(); it.Next()) { 252 WalkOatMethod(oat_class.GetOatMethod(class_method_idx++), 253 dex_file, 254 class_def_index, 255 it.GetMemberIndex(), 256 it.GetMethodCodeItem(), 257 it.GetMethodAccessFlags()); 258 } 259 DCHECK(!it.HasNext()); 260 } 261 262 void WalkOatMethod(const OatFile::OatMethod& oat_method, 263 const DexFile& dex_file, 264 uint32_t class_def_index, 265 uint32_t dex_method_index, 266 const DexFile::CodeItem* code_item, 267 uint32_t method_access_flags) { 268 if ((method_access_flags & kAccAbstract) != 0) { 269 // Abstract method, no code. 270 return; 271 } 272 const OatHeader& oat_header = oat_file_->GetOatHeader(); 273 const OatQuickMethodHeader* method_header = oat_method.GetOatQuickMethodHeader(); 274 if (method_header == nullptr || method_header->GetCodeSize() == 0) { 275 // No code. 276 return; 277 } 278 279 uint32_t entry_point = oat_method.GetCodeOffset() - oat_header.GetExecutableOffset(); 280 // Clear Thumb2 bit. 281 const void* code_address = EntryPointToCodePointer(reinterpret_cast<void*>(entry_point)); 282 283 debug::MethodDebugInfo info = debug::MethodDebugInfo(); 284 info.trampoline_name = nullptr; 285 info.dex_file = &dex_file; 286 info.class_def_index = class_def_index; 287 info.dex_method_index = dex_method_index; 288 info.access_flags = method_access_flags; 289 info.code_item = code_item; 290 info.isa = oat_header.GetInstructionSet(); 291 info.deduped = !seen_offsets_.insert(oat_method.GetCodeOffset()).second; 292 info.is_native_debuggable = oat_header.IsNativeDebuggable(); 293 info.is_optimized = method_header->IsOptimized(); 294 info.is_code_address_text_relative = true; 295 info.code_address = reinterpret_cast<uintptr_t>(code_address); 296 info.code_size = method_header->GetCodeSize(); 297 info.frame_size_in_bytes = method_header->GetFrameSizeInBytes(); 298 info.code_info = info.is_optimized ? method_header->GetOptimizedCodeInfoPtr() : nullptr; 299 info.cfi = ArrayRef<uint8_t>(); 300 method_debug_infos_.push_back(info); 301 } 302 303 private: 304 const OatFile* oat_file_; 305 std::unique_ptr<ElfBuilder<ElfTypes> > builder_; 306 std::vector<debug::MethodDebugInfo> method_debug_infos_; 307 std::unordered_set<uint32_t> seen_offsets_; 308 const std::string output_name_; 309 bool no_bits_; 310 }; 311 312 class OatDumperOptions { 313 public: 314 OatDumperOptions(bool dump_vmap, 315 bool dump_code_info_stack_maps, 316 bool disassemble_code, 317 bool absolute_addresses, 318 const char* class_filter, 319 const char* method_filter, 320 bool list_classes, 321 bool list_methods, 322 bool dump_header_only, 323 const char* export_dex_location, 324 const char* app_image, 325 const char* app_oat, 326 uint32_t addr2instr) 327 : dump_vmap_(dump_vmap), 328 dump_code_info_stack_maps_(dump_code_info_stack_maps), 329 disassemble_code_(disassemble_code), 330 absolute_addresses_(absolute_addresses), 331 class_filter_(class_filter), 332 method_filter_(method_filter), 333 list_classes_(list_classes), 334 list_methods_(list_methods), 335 dump_header_only_(dump_header_only), 336 export_dex_location_(export_dex_location), 337 app_image_(app_image), 338 app_oat_(app_oat), 339 addr2instr_(addr2instr), 340 class_loader_(nullptr) {} 341 342 const bool dump_vmap_; 343 const bool dump_code_info_stack_maps_; 344 const bool disassemble_code_; 345 const bool absolute_addresses_; 346 const char* const class_filter_; 347 const char* const method_filter_; 348 const bool list_classes_; 349 const bool list_methods_; 350 const bool dump_header_only_; 351 const char* const export_dex_location_; 352 const char* const app_image_; 353 const char* const app_oat_; 354 uint32_t addr2instr_; 355 Handle<mirror::ClassLoader>* class_loader_; 356 }; 357 358 class OatDumper { 359 public: 360 OatDumper(const OatFile& oat_file, const OatDumperOptions& options) 361 : oat_file_(oat_file), 362 oat_dex_files_(oat_file.GetOatDexFiles()), 363 options_(options), 364 resolved_addr2instr_(0), 365 instruction_set_(oat_file_.GetOatHeader().GetInstructionSet()), 366 disassembler_(Disassembler::Create(instruction_set_, 367 new DisassemblerOptions( 368 options_.absolute_addresses_, 369 oat_file.Begin(), 370 oat_file.End(), 371 true /* can_read_literals_ */, 372 Is64BitInstructionSet(instruction_set_) 373 ? &Thread::DumpThreadOffset<PointerSize::k64> 374 : &Thread::DumpThreadOffset<PointerSize::k32>))) { 375 CHECK(options_.class_loader_ != nullptr); 376 CHECK(options_.class_filter_ != nullptr); 377 CHECK(options_.method_filter_ != nullptr); 378 AddAllOffsets(); 379 } 380 381 ~OatDumper() { 382 delete disassembler_; 383 } 384 385 InstructionSet GetInstructionSet() { 386 return instruction_set_; 387 } 388 389 bool Dump(std::ostream& os) { 390 bool success = true; 391 const OatHeader& oat_header = oat_file_.GetOatHeader(); 392 393 os << "MAGIC:\n"; 394 os << oat_header.GetMagic() << "\n\n"; 395 396 os << "LOCATION:\n"; 397 os << oat_file_.GetLocation() << "\n\n"; 398 399 os << "CHECKSUM:\n"; 400 os << StringPrintf("0x%08x\n\n", oat_header.GetChecksum()); 401 402 os << "INSTRUCTION SET:\n"; 403 os << oat_header.GetInstructionSet() << "\n\n"; 404 405 { 406 std::unique_ptr<const InstructionSetFeatures> features( 407 InstructionSetFeatures::FromBitmap(oat_header.GetInstructionSet(), 408 oat_header.GetInstructionSetFeaturesBitmap())); 409 os << "INSTRUCTION SET FEATURES:\n"; 410 os << features->GetFeatureString() << "\n\n"; 411 } 412 413 os << "DEX FILE COUNT:\n"; 414 os << oat_header.GetDexFileCount() << "\n\n"; 415 416 #define DUMP_OAT_HEADER_OFFSET(label, offset) \ 417 os << label " OFFSET:\n"; \ 418 os << StringPrintf("0x%08x", oat_header.offset()); \ 419 if (oat_header.offset() != 0 && options_.absolute_addresses_) { \ 420 os << StringPrintf(" (%p)", oat_file_.Begin() + oat_header.offset()); \ 421 } \ 422 os << StringPrintf("\n\n"); 423 424 DUMP_OAT_HEADER_OFFSET("EXECUTABLE", GetExecutableOffset); 425 DUMP_OAT_HEADER_OFFSET("INTERPRETER TO INTERPRETER BRIDGE", 426 GetInterpreterToInterpreterBridgeOffset); 427 DUMP_OAT_HEADER_OFFSET("INTERPRETER TO COMPILED CODE BRIDGE", 428 GetInterpreterToCompiledCodeBridgeOffset); 429 DUMP_OAT_HEADER_OFFSET("JNI DLSYM LOOKUP", 430 GetJniDlsymLookupOffset); 431 DUMP_OAT_HEADER_OFFSET("QUICK GENERIC JNI TRAMPOLINE", 432 GetQuickGenericJniTrampolineOffset); 433 DUMP_OAT_HEADER_OFFSET("QUICK IMT CONFLICT TRAMPOLINE", 434 GetQuickImtConflictTrampolineOffset); 435 DUMP_OAT_HEADER_OFFSET("QUICK RESOLUTION TRAMPOLINE", 436 GetQuickResolutionTrampolineOffset); 437 DUMP_OAT_HEADER_OFFSET("QUICK TO INTERPRETER BRIDGE", 438 GetQuickToInterpreterBridgeOffset); 439 #undef DUMP_OAT_HEADER_OFFSET 440 441 os << "IMAGE PATCH DELTA:\n"; 442 os << StringPrintf("%d (0x%08x)\n\n", 443 oat_header.GetImagePatchDelta(), 444 oat_header.GetImagePatchDelta()); 445 446 os << "IMAGE FILE LOCATION OAT CHECKSUM:\n"; 447 os << StringPrintf("0x%08x\n\n", oat_header.GetImageFileLocationOatChecksum()); 448 449 os << "IMAGE FILE LOCATION OAT BEGIN:\n"; 450 os << StringPrintf("0x%08x\n\n", oat_header.GetImageFileLocationOatDataBegin()); 451 452 // Print the key-value store. 453 { 454 os << "KEY VALUE STORE:\n"; 455 size_t index = 0; 456 const char* key; 457 const char* value; 458 while (oat_header.GetStoreKeyValuePairByIndex(index, &key, &value)) { 459 os << key << " = " << value << "\n"; 460 index++; 461 } 462 os << "\n"; 463 } 464 465 if (options_.absolute_addresses_) { 466 os << "BEGIN:\n"; 467 os << reinterpret_cast<const void*>(oat_file_.Begin()) << "\n\n"; 468 469 os << "END:\n"; 470 os << reinterpret_cast<const void*>(oat_file_.End()) << "\n\n"; 471 } 472 473 os << "SIZE:\n"; 474 os << oat_file_.Size() << "\n\n"; 475 476 os << std::flush; 477 478 // If set, adjust relative address to be searched 479 if (options_.addr2instr_ != 0) { 480 resolved_addr2instr_ = options_.addr2instr_ + oat_header.GetExecutableOffset(); 481 os << "SEARCH ADDRESS (executable offset + input):\n"; 482 os << StringPrintf("0x%08x\n\n", resolved_addr2instr_); 483 } 484 485 // Dumping the dex file overview is compact enough to do even if header only. 486 DexFileData cumulative; 487 for (size_t i = 0; i < oat_dex_files_.size(); i++) { 488 const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i]; 489 CHECK(oat_dex_file != nullptr); 490 std::string error_msg; 491 const DexFile* const dex_file = OpenDexFile(oat_dex_file, &error_msg); 492 if (dex_file == nullptr) { 493 os << "Failed to open dex file '" << oat_dex_file->GetDexFileLocation() << "': " 494 << error_msg; 495 continue; 496 } 497 DexFileData data(*dex_file); 498 os << "Dex file data for " << dex_file->GetLocation() << "\n"; 499 data.Dump(os); 500 os << "\n"; 501 const DexLayoutSections* const layout_sections = oat_dex_file->GetDexLayoutSections(); 502 if (layout_sections != nullptr) { 503 os << "Layout data\n"; 504 os << *layout_sections; 505 os << "\n"; 506 } 507 508 cumulative.Add(data); 509 } 510 os << "Cumulative dex file data\n"; 511 cumulative.Dump(os); 512 os << "\n"; 513 514 if (!options_.dump_header_only_) { 515 VariableIndentationOutputStream vios(&os); 516 VdexFile::Header vdex_header = oat_file_.GetVdexFile()->GetHeader(); 517 if (vdex_header.IsValid()) { 518 std::string error_msg; 519 std::vector<const DexFile*> dex_files; 520 for (size_t i = 0; i < oat_dex_files_.size(); i++) { 521 const DexFile* dex_file = OpenDexFile(oat_dex_files_[i], &error_msg); 522 if (dex_file == nullptr) { 523 os << "Error opening dex file: " << error_msg << std::endl; 524 return false; 525 } 526 dex_files.push_back(dex_file); 527 } 528 verifier::VerifierDeps deps(dex_files, oat_file_.GetVdexFile()->GetVerifierDepsData()); 529 deps.Dump(&vios); 530 } else { 531 os << "UNRECOGNIZED vdex file, magic " 532 << vdex_header.GetMagic() 533 << ", version " 534 << vdex_header.GetVersion() 535 << "\n"; 536 } 537 for (size_t i = 0; i < oat_dex_files_.size(); i++) { 538 const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i]; 539 CHECK(oat_dex_file != nullptr); 540 541 // If file export selected skip file analysis 542 if (options_.export_dex_location_) { 543 if (!ExportDexFile(os, *oat_dex_file)) { 544 success = false; 545 } 546 } else { 547 if (!DumpOatDexFile(os, *oat_dex_file)) { 548 success = false; 549 } 550 } 551 } 552 } 553 554 { 555 os << "OAT FILE STATS:\n"; 556 VariableIndentationOutputStream vios(&os); 557 stats_.Dump(vios); 558 } 559 560 os << std::flush; 561 return success; 562 } 563 564 size_t ComputeSize(const void* oat_data) { 565 if (reinterpret_cast<const uint8_t*>(oat_data) < oat_file_.Begin() || 566 reinterpret_cast<const uint8_t*>(oat_data) > oat_file_.End()) { 567 return 0; // Address not in oat file 568 } 569 uintptr_t begin_offset = reinterpret_cast<uintptr_t>(oat_data) - 570 reinterpret_cast<uintptr_t>(oat_file_.Begin()); 571 auto it = offsets_.upper_bound(begin_offset); 572 CHECK(it != offsets_.end()); 573 uintptr_t end_offset = *it; 574 return end_offset - begin_offset; 575 } 576 577 InstructionSet GetOatInstructionSet() { 578 return oat_file_.GetOatHeader().GetInstructionSet(); 579 } 580 581 const void* GetQuickOatCode(ArtMethod* m) REQUIRES_SHARED(Locks::mutator_lock_) { 582 for (size_t i = 0; i < oat_dex_files_.size(); i++) { 583 const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i]; 584 CHECK(oat_dex_file != nullptr); 585 std::string error_msg; 586 const DexFile* const dex_file = OpenDexFile(oat_dex_file, &error_msg); 587 if (dex_file == nullptr) { 588 LOG(WARNING) << "Failed to open dex file '" << oat_dex_file->GetDexFileLocation() 589 << "': " << error_msg; 590 } else { 591 const char* descriptor = m->GetDeclaringClassDescriptor(); 592 const DexFile::ClassDef* class_def = 593 OatDexFile::FindClassDef(*dex_file, descriptor, ComputeModifiedUtf8Hash(descriptor)); 594 if (class_def != nullptr) { 595 uint16_t class_def_index = dex_file->GetIndexForClassDef(*class_def); 596 const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index); 597 size_t method_index = m->GetMethodIndex(); 598 return oat_class.GetOatMethod(method_index).GetQuickCode(); 599 } 600 } 601 } 602 return nullptr; 603 } 604 605 struct Stats { 606 enum ByteKind { 607 kByteKindCode, 608 kByteKindQuickMethodHeader, 609 kByteKindCodeInfoLocationCatalog, 610 kByteKindCodeInfoDexRegisterMap, 611 kByteKindCodeInfoEncoding, 612 kByteKindCodeInfoInvokeInfo, 613 kByteKindCodeInfoStackMasks, 614 kByteKindCodeInfoRegisterMasks, 615 kByteKindStackMapNativePc, 616 kByteKindStackMapDexPc, 617 kByteKindStackMapDexRegisterMap, 618 kByteKindStackMapInlineInfoIndex, 619 kByteKindStackMapRegisterMaskIndex, 620 kByteKindStackMapStackMaskIndex, 621 kByteKindInlineInfoMethodIndexIdx, 622 kByteKindInlineInfoDexPc, 623 kByteKindInlineInfoExtraData, 624 kByteKindInlineInfoDexRegisterMap, 625 kByteKindInlineInfoIsLast, 626 kByteKindCount, 627 // Special ranges for std::accumulate convenience. 628 kByteKindStackMapFirst = kByteKindStackMapNativePc, 629 kByteKindStackMapLast = kByteKindStackMapStackMaskIndex, 630 kByteKindInlineInfoFirst = kByteKindInlineInfoMethodIndexIdx, 631 kByteKindInlineInfoLast = kByteKindInlineInfoIsLast, 632 }; 633 int64_t bits[kByteKindCount] = {}; 634 // Since code has deduplication, seen tracks already seen pointers to avoid double counting 635 // deduplicated code and tables. 636 std::unordered_set<const void*> seen; 637 638 // Returns true if it was newly added. 639 bool AddBitsIfUnique(ByteKind kind, int64_t count, const void* address) { 640 if (seen.insert(address).second == true) { 641 // True means the address was not already in the set. 642 AddBits(kind, count); 643 return true; 644 } 645 return false; 646 } 647 648 void AddBits(ByteKind kind, int64_t count) { 649 bits[kind] += count; 650 } 651 652 void Dump(VariableIndentationOutputStream& os) { 653 const int64_t sum = std::accumulate(bits, bits + kByteKindCount, 0u); 654 os.Stream() << "Dumping cumulative use of " << sum / kBitsPerByte << " accounted bytes\n"; 655 if (sum > 0) { 656 Dump(os, "Code ", bits[kByteKindCode], sum); 657 Dump(os, "QuickMethodHeader ", bits[kByteKindQuickMethodHeader], sum); 658 Dump(os, "CodeInfoEncoding ", bits[kByteKindCodeInfoEncoding], sum); 659 Dump(os, "CodeInfoLocationCatalog ", bits[kByteKindCodeInfoLocationCatalog], sum); 660 Dump(os, "CodeInfoDexRegisterMap ", bits[kByteKindCodeInfoDexRegisterMap], sum); 661 Dump(os, "CodeInfoStackMasks ", bits[kByteKindCodeInfoStackMasks], sum); 662 Dump(os, "CodeInfoRegisterMasks ", bits[kByteKindCodeInfoRegisterMasks], sum); 663 Dump(os, "CodeInfoInvokeInfo ", bits[kByteKindCodeInfoInvokeInfo], sum); 664 // Stack map section. 665 const int64_t stack_map_bits = std::accumulate(bits + kByteKindStackMapFirst, 666 bits + kByteKindStackMapLast + 1, 667 0u); 668 Dump(os, "CodeInfoStackMap ", stack_map_bits, sum); 669 { 670 ScopedIndentation indent1(&os); 671 Dump(os, 672 "StackMapNativePc ", 673 bits[kByteKindStackMapNativePc], 674 stack_map_bits, 675 "stack map"); 676 Dump(os, 677 "StackMapDexPcEncoding ", 678 bits[kByteKindStackMapDexPc], 679 stack_map_bits, 680 "stack map"); 681 Dump(os, 682 "StackMapDexRegisterMap ", 683 bits[kByteKindStackMapDexRegisterMap], 684 stack_map_bits, 685 "stack map"); 686 Dump(os, 687 "StackMapInlineInfoIndex ", 688 bits[kByteKindStackMapInlineInfoIndex], 689 stack_map_bits, 690 "stack map"); 691 Dump(os, 692 "StackMapRegisterMaskIndex ", 693 bits[kByteKindStackMapRegisterMaskIndex], 694 stack_map_bits, 695 "stack map"); 696 Dump(os, 697 "StackMapStackMaskIndex ", 698 bits[kByteKindStackMapStackMaskIndex], 699 stack_map_bits, 700 "stack map"); 701 } 702 // Inline info section. 703 const int64_t inline_info_bits = std::accumulate(bits + kByteKindInlineInfoFirst, 704 bits + kByteKindInlineInfoLast + 1, 705 0u); 706 Dump(os, "CodeInfoInlineInfo ", inline_info_bits, sum); 707 { 708 ScopedIndentation indent1(&os); 709 Dump(os, 710 "InlineInfoMethodIndexIdx ", 711 bits[kByteKindInlineInfoMethodIndexIdx], 712 inline_info_bits, 713 "inline info"); 714 Dump(os, 715 "InlineInfoDexPc ", 716 bits[kByteKindStackMapDexPc], 717 inline_info_bits, 718 "inline info"); 719 Dump(os, 720 "InlineInfoExtraData ", 721 bits[kByteKindInlineInfoExtraData], 722 inline_info_bits, 723 "inline info"); 724 Dump(os, 725 "InlineInfoDexRegisterMap ", 726 bits[kByteKindInlineInfoDexRegisterMap], 727 inline_info_bits, 728 "inline info"); 729 Dump(os, 730 "InlineInfoIsLast ", 731 bits[kByteKindInlineInfoIsLast], 732 inline_info_bits, 733 "inline info"); 734 } 735 } 736 os.Stream() << "\n" << std::flush; 737 } 738 739 private: 740 void Dump(VariableIndentationOutputStream& os, 741 const char* name, 742 int64_t size, 743 int64_t total, 744 const char* sum_of = "total") { 745 const double percent = (static_cast<double>(size) / static_cast<double>(total)) * 100; 746 os.Stream() << StringPrintf("%s = %8" PRId64 " (%2.0f%% of %s)\n", 747 name, 748 size / kBitsPerByte, 749 percent, 750 sum_of); 751 } 752 }; 753 754 private: 755 void AddAllOffsets() { 756 // We don't know the length of the code for each method, but we need to know where to stop 757 // when disassembling. What we do know is that a region of code will be followed by some other 758 // region, so if we keep a sorted sequence of the start of each region, we can infer the length 759 // of a piece of code by using upper_bound to find the start of the next region. 760 for (size_t i = 0; i < oat_dex_files_.size(); i++) { 761 const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i]; 762 CHECK(oat_dex_file != nullptr); 763 std::string error_msg; 764 const DexFile* const dex_file = OpenDexFile(oat_dex_file, &error_msg); 765 if (dex_file == nullptr) { 766 LOG(WARNING) << "Failed to open dex file '" << oat_dex_file->GetDexFileLocation() 767 << "': " << error_msg; 768 continue; 769 } 770 offsets_.insert(reinterpret_cast<uintptr_t>(&dex_file->GetHeader())); 771 for (size_t class_def_index = 0; 772 class_def_index < dex_file->NumClassDefs(); 773 class_def_index++) { 774 const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index); 775 const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index); 776 const uint8_t* class_data = dex_file->GetClassData(class_def); 777 if (class_data != nullptr) { 778 ClassDataItemIterator it(*dex_file, class_data); 779 it.SkipAllFields(); 780 uint32_t class_method_index = 0; 781 while (it.HasNextDirectMethod()) { 782 AddOffsets(oat_class.GetOatMethod(class_method_index++)); 783 it.Next(); 784 } 785 while (it.HasNextVirtualMethod()) { 786 AddOffsets(oat_class.GetOatMethod(class_method_index++)); 787 it.Next(); 788 } 789 } 790 } 791 } 792 793 // If the last thing in the file is code for a method, there won't be an offset for the "next" 794 // thing. Instead of having a special case in the upper_bound code, let's just add an entry 795 // for the end of the file. 796 offsets_.insert(oat_file_.Size()); 797 } 798 799 static uint32_t AlignCodeOffset(uint32_t maybe_thumb_offset) { 800 return maybe_thumb_offset & ~0x1; // TODO: Make this Thumb2 specific. 801 } 802 803 void AddOffsets(const OatFile::OatMethod& oat_method) { 804 uint32_t code_offset = oat_method.GetCodeOffset(); 805 if (oat_file_.GetOatHeader().GetInstructionSet() == kThumb2) { 806 code_offset &= ~0x1; 807 } 808 offsets_.insert(code_offset); 809 offsets_.insert(oat_method.GetVmapTableOffset()); 810 } 811 812 // Dex file data, may be for multiple different dex files. 813 class DexFileData { 814 public: 815 DexFileData() {} 816 817 explicit DexFileData(const DexFile& dex_file) 818 : num_string_ids_(dex_file.NumStringIds()), 819 num_method_ids_(dex_file.NumMethodIds()), 820 num_field_ids_(dex_file.NumFieldIds()), 821 num_type_ids_(dex_file.NumTypeIds()), 822 num_class_defs_(dex_file.NumClassDefs()) { 823 for (size_t class_def_index = 0; class_def_index < num_class_defs_; ++class_def_index) { 824 const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index); 825 WalkClass(dex_file, class_def); 826 } 827 } 828 829 void Add(const DexFileData& other) { 830 AddAll(unique_string_ids_from_code_, other.unique_string_ids_from_code_); 831 num_string_ids_from_code_ += other.num_string_ids_from_code_; 832 AddAll(dex_code_item_ptrs_, other.dex_code_item_ptrs_); 833 dex_code_bytes_ += other.dex_code_bytes_; 834 num_string_ids_ += other.num_string_ids_; 835 num_method_ids_ += other.num_method_ids_; 836 num_field_ids_ += other.num_field_ids_; 837 num_type_ids_ += other.num_type_ids_; 838 num_class_defs_ += other.num_class_defs_; 839 } 840 841 void Dump(std::ostream& os) { 842 os << "Num string ids: " << num_string_ids_ << "\n"; 843 os << "Num method ids: " << num_method_ids_ << "\n"; 844 os << "Num field ids: " << num_field_ids_ << "\n"; 845 os << "Num type ids: " << num_type_ids_ << "\n"; 846 os << "Num class defs: " << num_class_defs_ << "\n"; 847 os << "Unique strings loaded from dex code: " << unique_string_ids_from_code_.size() << "\n"; 848 os << "Total strings loaded from dex code: " << num_string_ids_from_code_ << "\n"; 849 os << "Number of unique dex code items: " << dex_code_item_ptrs_.size() << "\n"; 850 os << "Total number of dex code bytes: " << dex_code_bytes_ << "\n"; 851 } 852 853 private: 854 // All of the elements from one container to another. 855 template <typename Dest, typename Src> 856 static void AddAll(Dest& dest, const Src& src) { 857 dest.insert(src.begin(), src.end()); 858 } 859 860 void WalkClass(const DexFile& dex_file, const DexFile::ClassDef& class_def) { 861 const uint8_t* class_data = dex_file.GetClassData(class_def); 862 if (class_data == nullptr) { // empty class such as a marker interface? 863 return; 864 } 865 ClassDataItemIterator it(dex_file, class_data); 866 it.SkipAllFields(); 867 while (it.HasNextDirectMethod()) { 868 WalkCodeItem(dex_file, it.GetMethodCodeItem()); 869 it.Next(); 870 } 871 while (it.HasNextVirtualMethod()) { 872 WalkCodeItem(dex_file, it.GetMethodCodeItem()); 873 it.Next(); 874 } 875 DCHECK(!it.HasNext()); 876 } 877 878 void WalkCodeItem(const DexFile& dex_file, const DexFile::CodeItem* code_item) { 879 if (code_item == nullptr) { 880 return; 881 } 882 const size_t code_item_size = code_item->insns_size_in_code_units_; 883 const uint16_t* code_ptr = code_item->insns_; 884 const uint16_t* code_end = code_item->insns_ + code_item_size; 885 886 // If we inserted a new dex code item pointer, add to total code bytes. 887 if (dex_code_item_ptrs_.insert(code_ptr).second) { 888 dex_code_bytes_ += code_item_size * sizeof(code_ptr[0]); 889 } 890 891 while (code_ptr < code_end) { 892 const Instruction* inst = Instruction::At(code_ptr); 893 switch (inst->Opcode()) { 894 case Instruction::CONST_STRING: { 895 const dex::StringIndex string_index(inst->VRegB_21c()); 896 unique_string_ids_from_code_.insert(StringReference(&dex_file, string_index)); 897 ++num_string_ids_from_code_; 898 break; 899 } 900 case Instruction::CONST_STRING_JUMBO: { 901 const dex::StringIndex string_index(inst->VRegB_31c()); 902 unique_string_ids_from_code_.insert(StringReference(&dex_file, string_index)); 903 ++num_string_ids_from_code_; 904 break; 905 } 906 default: 907 break; 908 } 909 910 code_ptr += inst->SizeInCodeUnits(); 911 } 912 } 913 914 // Unique string ids loaded from dex code. 915 std::set<StringReference, StringReferenceComparator> unique_string_ids_from_code_; 916 917 // Total string ids loaded from dex code. 918 size_t num_string_ids_from_code_ = 0; 919 920 // Unique code pointers. 921 std::set<const void*> dex_code_item_ptrs_; 922 923 // Total "unique" dex code bytes. 924 size_t dex_code_bytes_ = 0; 925 926 // Other dex ids. 927 size_t num_string_ids_ = 0; 928 size_t num_method_ids_ = 0; 929 size_t num_field_ids_ = 0; 930 size_t num_type_ids_ = 0; 931 size_t num_class_defs_ = 0; 932 }; 933 934 bool DumpOatDexFile(std::ostream& os, const OatFile::OatDexFile& oat_dex_file) { 935 bool success = true; 936 bool stop_analysis = false; 937 os << "OatDexFile:\n"; 938 os << StringPrintf("location: %s\n", oat_dex_file.GetDexFileLocation().c_str()); 939 os << StringPrintf("checksum: 0x%08x\n", oat_dex_file.GetDexFileLocationChecksum()); 940 941 const uint8_t* const oat_file_begin = oat_dex_file.GetOatFile()->Begin(); 942 const uint8_t* const vdex_file_begin = oat_dex_file.GetOatFile()->DexBegin(); 943 944 // Print data range of the dex file embedded inside the corresponding vdex file. 945 const uint8_t* const dex_file_pointer = oat_dex_file.GetDexFilePointer(); 946 uint32_t dex_offset = dchecked_integral_cast<uint32_t>(dex_file_pointer - vdex_file_begin); 947 os << StringPrintf("dex-file: 0x%08x..0x%08x\n", 948 dex_offset, 949 dchecked_integral_cast<uint32_t>(dex_offset + oat_dex_file.FileSize() - 1)); 950 951 // Create the dex file early. A lot of print-out things depend on it. 952 std::string error_msg; 953 const DexFile* const dex_file = OpenDexFile(&oat_dex_file, &error_msg); 954 if (dex_file == nullptr) { 955 os << "NOT FOUND: " << error_msg << "\n\n"; 956 os << std::flush; 957 return false; 958 } 959 960 // Print lookup table, if it exists. 961 if (oat_dex_file.GetLookupTableData() != nullptr) { 962 uint32_t table_offset = dchecked_integral_cast<uint32_t>( 963 oat_dex_file.GetLookupTableData() - oat_file_begin); 964 uint32_t table_size = TypeLookupTable::RawDataLength(dex_file->NumClassDefs()); 965 os << StringPrintf("type-table: 0x%08x..0x%08x\n", 966 table_offset, 967 table_offset + table_size - 1); 968 } 969 970 VariableIndentationOutputStream vios(&os); 971 ScopedIndentation indent1(&vios); 972 for (size_t class_def_index = 0; 973 class_def_index < dex_file->NumClassDefs(); 974 class_def_index++) { 975 const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index); 976 const char* descriptor = dex_file->GetClassDescriptor(class_def); 977 978 // TODO: Support regex 979 if (DescriptorToDot(descriptor).find(options_.class_filter_) == std::string::npos) { 980 continue; 981 } 982 983 uint32_t oat_class_offset = oat_dex_file.GetOatClassOffset(class_def_index); 984 const OatFile::OatClass oat_class = oat_dex_file.GetOatClass(class_def_index); 985 os << StringPrintf("%zd: %s (offset=0x%08x) (type_idx=%d)", 986 class_def_index, descriptor, oat_class_offset, class_def.class_idx_.index_) 987 << " (" << oat_class.GetStatus() << ")" 988 << " (" << oat_class.GetType() << ")\n"; 989 // TODO: include bitmap here if type is kOatClassSomeCompiled? 990 if (options_.list_classes_) { 991 continue; 992 } 993 if (!DumpOatClass(&vios, oat_class, *dex_file, class_def, &stop_analysis)) { 994 success = false; 995 } 996 if (stop_analysis) { 997 os << std::flush; 998 return success; 999 } 1000 } 1001 os << "\n"; 1002 os << std::flush; 1003 return success; 1004 } 1005 1006 bool ExportDexFile(std::ostream& os, const OatFile::OatDexFile& oat_dex_file) { 1007 std::string error_msg; 1008 std::string dex_file_location = oat_dex_file.GetDexFileLocation(); 1009 1010 const DexFile* const dex_file = OpenDexFile(&oat_dex_file, &error_msg); 1011 if (dex_file == nullptr) { 1012 os << "Failed to open dex file '" << dex_file_location << "': " << error_msg; 1013 return false; 1014 } 1015 size_t fsize = oat_dex_file.FileSize(); 1016 1017 // Some quick checks just in case 1018 if (fsize == 0 || fsize < sizeof(DexFile::Header)) { 1019 os << "Invalid dex file\n"; 1020 return false; 1021 } 1022 1023 // Verify output directory exists 1024 if (!OS::DirectoryExists(options_.export_dex_location_)) { 1025 // TODO: Extend OS::DirectoryExists if symlink support is required 1026 os << options_.export_dex_location_ << " output directory not found or symlink\n"; 1027 return false; 1028 } 1029 1030 // Beautify path names 1031 if (dex_file_location.size() > PATH_MAX || dex_file_location.size() <= 0) { 1032 return false; 1033 } 1034 1035 std::string dex_orig_name; 1036 size_t dex_orig_pos = dex_file_location.rfind('/'); 1037 if (dex_orig_pos == std::string::npos) 1038 dex_orig_name = dex_file_location; 1039 else 1040 dex_orig_name = dex_file_location.substr(dex_orig_pos + 1); 1041 1042 // A more elegant approach to efficiently name user installed apps is welcome 1043 if (dex_orig_name.size() == 8 && 1044 dex_orig_name.compare("base.apk") == 0 && 1045 dex_orig_pos != std::string::npos) { 1046 dex_file_location.erase(dex_orig_pos, strlen("base.apk") + 1); 1047 size_t apk_orig_pos = dex_file_location.rfind('/'); 1048 if (apk_orig_pos != std::string::npos) { 1049 dex_orig_name = dex_file_location.substr(++apk_orig_pos); 1050 } 1051 } 1052 1053 std::string out_dex_path(options_.export_dex_location_); 1054 if (out_dex_path.back() != '/') { 1055 out_dex_path.append("/"); 1056 } 1057 out_dex_path.append(dex_orig_name); 1058 out_dex_path.append("_export.dex"); 1059 if (out_dex_path.length() > PATH_MAX) { 1060 return false; 1061 } 1062 1063 std::unique_ptr<File> file(OS::CreateEmptyFile(out_dex_path.c_str())); 1064 if (file.get() == nullptr) { 1065 os << "Failed to open output dex file " << out_dex_path; 1066 return false; 1067 } 1068 1069 if (!file->WriteFully(dex_file->Begin(), fsize)) { 1070 os << "Failed to write dex file"; 1071 file->Erase(); 1072 return false; 1073 } 1074 1075 if (file->FlushCloseOrErase() != 0) { 1076 os << "Flush and close failed"; 1077 return false; 1078 } 1079 1080 os << StringPrintf("Dex file exported at %s (%zd bytes)\n", out_dex_path.c_str(), fsize); 1081 os << std::flush; 1082 1083 return true; 1084 } 1085 1086 bool DumpOatClass(VariableIndentationOutputStream* vios, 1087 const OatFile::OatClass& oat_class, const DexFile& dex_file, 1088 const DexFile::ClassDef& class_def, bool* stop_analysis) { 1089 bool success = true; 1090 bool addr_found = false; 1091 const uint8_t* class_data = dex_file.GetClassData(class_def); 1092 if (class_data == nullptr) { // empty class such as a marker interface? 1093 vios->Stream() << std::flush; 1094 return success; 1095 } 1096 ClassDataItemIterator it(dex_file, class_data); 1097 it.SkipAllFields(); 1098 uint32_t class_method_index = 0; 1099 while (it.HasNextDirectMethod()) { 1100 if (!DumpOatMethod(vios, class_def, class_method_index, oat_class, dex_file, 1101 it.GetMemberIndex(), it.GetMethodCodeItem(), 1102 it.GetRawMemberAccessFlags(), &addr_found)) { 1103 success = false; 1104 } 1105 if (addr_found) { 1106 *stop_analysis = true; 1107 return success; 1108 } 1109 class_method_index++; 1110 it.Next(); 1111 } 1112 while (it.HasNextVirtualMethod()) { 1113 if (!DumpOatMethod(vios, class_def, class_method_index, oat_class, dex_file, 1114 it.GetMemberIndex(), it.GetMethodCodeItem(), 1115 it.GetRawMemberAccessFlags(), &addr_found)) { 1116 success = false; 1117 } 1118 if (addr_found) { 1119 *stop_analysis = true; 1120 return success; 1121 } 1122 class_method_index++; 1123 it.Next(); 1124 } 1125 DCHECK(!it.HasNext()); 1126 vios->Stream() << std::flush; 1127 return success; 1128 } 1129 1130 static constexpr uint32_t kPrologueBytes = 16; 1131 1132 // When this was picked, the largest arm method was 55,256 bytes and arm64 was 50,412 bytes. 1133 static constexpr uint32_t kMaxCodeSize = 100 * 1000; 1134 1135 bool DumpOatMethod(VariableIndentationOutputStream* vios, 1136 const DexFile::ClassDef& class_def, 1137 uint32_t class_method_index, 1138 const OatFile::OatClass& oat_class, const DexFile& dex_file, 1139 uint32_t dex_method_idx, const DexFile::CodeItem* code_item, 1140 uint32_t method_access_flags, bool* addr_found) { 1141 bool success = true; 1142 1143 // TODO: Support regex 1144 std::string method_name = dex_file.GetMethodName(dex_file.GetMethodId(dex_method_idx)); 1145 if (method_name.find(options_.method_filter_) == std::string::npos) { 1146 return success; 1147 } 1148 1149 std::string pretty_method = dex_file.PrettyMethod(dex_method_idx, true); 1150 vios->Stream() << StringPrintf("%d: %s (dex_method_idx=%d)\n", 1151 class_method_index, pretty_method.c_str(), 1152 dex_method_idx); 1153 if (options_.list_methods_) return success; 1154 1155 uint32_t oat_method_offsets_offset = oat_class.GetOatMethodOffsetsOffset(class_method_index); 1156 const OatMethodOffsets* oat_method_offsets = oat_class.GetOatMethodOffsets(class_method_index); 1157 const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_index); 1158 uint32_t code_offset = oat_method.GetCodeOffset(); 1159 uint32_t code_size = oat_method.GetQuickCodeSize(); 1160 if (resolved_addr2instr_ != 0) { 1161 if (resolved_addr2instr_ > code_offset + code_size) { 1162 return success; 1163 } else { 1164 *addr_found = true; // stop analyzing file at next iteration 1165 } 1166 } 1167 1168 // Everything below is indented at least once. 1169 ScopedIndentation indent1(vios); 1170 1171 { 1172 vios->Stream() << "DEX CODE:\n"; 1173 ScopedIndentation indent2(vios); 1174 DumpDexCode(vios->Stream(), dex_file, code_item); 1175 } 1176 1177 std::unique_ptr<StackHandleScope<1>> hs; 1178 std::unique_ptr<verifier::MethodVerifier> verifier; 1179 if (Runtime::Current() != nullptr) { 1180 // We need to have the handle scope stay live until after the verifier since the verifier has 1181 // a handle to the dex cache from hs. 1182 hs.reset(new StackHandleScope<1>(Thread::Current())); 1183 vios->Stream() << "VERIFIER TYPE ANALYSIS:\n"; 1184 ScopedIndentation indent2(vios); 1185 verifier.reset(DumpVerifier(vios, hs.get(), 1186 dex_method_idx, &dex_file, class_def, code_item, 1187 method_access_flags)); 1188 } 1189 { 1190 vios->Stream() << "OatMethodOffsets "; 1191 if (options_.absolute_addresses_) { 1192 vios->Stream() << StringPrintf("%p ", oat_method_offsets); 1193 } 1194 vios->Stream() << StringPrintf("(offset=0x%08x)\n", oat_method_offsets_offset); 1195 if (oat_method_offsets_offset > oat_file_.Size()) { 1196 vios->Stream() << StringPrintf( 1197 "WARNING: oat method offsets offset 0x%08x is past end of file 0x%08zx.\n", 1198 oat_method_offsets_offset, oat_file_.Size()); 1199 // If we can't read OatMethodOffsets, the rest of the data is dangerous to read. 1200 vios->Stream() << std::flush; 1201 return false; 1202 } 1203 1204 ScopedIndentation indent2(vios); 1205 vios->Stream() << StringPrintf("code_offset: 0x%08x ", code_offset); 1206 uint32_t aligned_code_begin = AlignCodeOffset(oat_method.GetCodeOffset()); 1207 if (aligned_code_begin > oat_file_.Size()) { 1208 vios->Stream() << StringPrintf("WARNING: " 1209 "code offset 0x%08x is past end of file 0x%08zx.\n", 1210 aligned_code_begin, oat_file_.Size()); 1211 success = false; 1212 } 1213 vios->Stream() << "\n"; 1214 } 1215 { 1216 vios->Stream() << "OatQuickMethodHeader "; 1217 uint32_t method_header_offset = oat_method.GetOatQuickMethodHeaderOffset(); 1218 const OatQuickMethodHeader* method_header = oat_method.GetOatQuickMethodHeader(); 1219 stats_.AddBitsIfUnique(Stats::kByteKindQuickMethodHeader, 1220 sizeof(*method_header) * kBitsPerByte, 1221 method_header); 1222 if (options_.absolute_addresses_) { 1223 vios->Stream() << StringPrintf("%p ", method_header); 1224 } 1225 vios->Stream() << StringPrintf("(offset=0x%08x)\n", method_header_offset); 1226 if (method_header_offset > oat_file_.Size()) { 1227 vios->Stream() << StringPrintf( 1228 "WARNING: oat quick method header offset 0x%08x is past end of file 0x%08zx.\n", 1229 method_header_offset, oat_file_.Size()); 1230 // If we can't read the OatQuickMethodHeader, the rest of the data is dangerous to read. 1231 vios->Stream() << std::flush; 1232 return false; 1233 } 1234 1235 ScopedIndentation indent2(vios); 1236 vios->Stream() << "vmap_table: "; 1237 if (options_.absolute_addresses_) { 1238 vios->Stream() << StringPrintf("%p ", oat_method.GetVmapTable()); 1239 } 1240 uint32_t vmap_table_offset = method_header == 1241 nullptr ? 0 : method_header->GetVmapTableOffset(); 1242 vios->Stream() << StringPrintf("(offset=0x%08x)\n", vmap_table_offset); 1243 1244 size_t vmap_table_offset_limit = 1245 (kIsVdexEnabled && IsMethodGeneratedByDexToDexCompiler(oat_method, code_item)) 1246 ? oat_file_.GetVdexFile()->Size() 1247 : method_header->GetCode() - oat_file_.Begin(); 1248 if (vmap_table_offset >= vmap_table_offset_limit) { 1249 vios->Stream() << StringPrintf("WARNING: " 1250 "vmap table offset 0x%08x is past end of file 0x%08zx. " 1251 "vmap table offset was loaded from offset 0x%08x.\n", 1252 vmap_table_offset, 1253 vmap_table_offset_limit, 1254 oat_method.GetVmapTableOffsetOffset()); 1255 success = false; 1256 } else if (options_.dump_vmap_) { 1257 DumpVmapData(vios, oat_method, code_item); 1258 } 1259 } 1260 { 1261 vios->Stream() << "QuickMethodFrameInfo\n"; 1262 1263 ScopedIndentation indent2(vios); 1264 vios->Stream() 1265 << StringPrintf("frame_size_in_bytes: %zd\n", oat_method.GetFrameSizeInBytes()); 1266 vios->Stream() << StringPrintf("core_spill_mask: 0x%08x ", oat_method.GetCoreSpillMask()); 1267 DumpSpillMask(vios->Stream(), oat_method.GetCoreSpillMask(), false); 1268 vios->Stream() << "\n"; 1269 vios->Stream() << StringPrintf("fp_spill_mask: 0x%08x ", oat_method.GetFpSpillMask()); 1270 DumpSpillMask(vios->Stream(), oat_method.GetFpSpillMask(), true); 1271 vios->Stream() << "\n"; 1272 } 1273 { 1274 // Based on spill masks from QuickMethodFrameInfo so placed 1275 // after it is dumped, but useful for understanding quick 1276 // code, so dumped here. 1277 ScopedIndentation indent2(vios); 1278 DumpVregLocations(vios->Stream(), oat_method, code_item); 1279 } 1280 { 1281 vios->Stream() << "CODE: "; 1282 uint32_t code_size_offset = oat_method.GetQuickCodeSizeOffset(); 1283 if (code_size_offset > oat_file_.Size()) { 1284 ScopedIndentation indent2(vios); 1285 vios->Stream() << StringPrintf("WARNING: " 1286 "code size offset 0x%08x is past end of file 0x%08zx.", 1287 code_size_offset, oat_file_.Size()); 1288 success = false; 1289 } else { 1290 const void* code = oat_method.GetQuickCode(); 1291 uint32_t aligned_code_begin = AlignCodeOffset(code_offset); 1292 uint64_t aligned_code_end = aligned_code_begin + code_size; 1293 stats_.AddBitsIfUnique(Stats::kByteKindCode, code_size * kBitsPerByte, code); 1294 1295 if (options_.absolute_addresses_) { 1296 vios->Stream() << StringPrintf("%p ", code); 1297 } 1298 vios->Stream() << StringPrintf("(code_offset=0x%08x size_offset=0x%08x size=%u)%s\n", 1299 code_offset, 1300 code_size_offset, 1301 code_size, 1302 code != nullptr ? "..." : ""); 1303 1304 ScopedIndentation indent2(vios); 1305 if (aligned_code_begin > oat_file_.Size()) { 1306 vios->Stream() << StringPrintf("WARNING: " 1307 "start of code at 0x%08x is past end of file 0x%08zx.", 1308 aligned_code_begin, oat_file_.Size()); 1309 success = false; 1310 } else if (aligned_code_end > oat_file_.Size()) { 1311 vios->Stream() << StringPrintf( 1312 "WARNING: " 1313 "end of code at 0x%08" PRIx64 " is past end of file 0x%08zx. " 1314 "code size is 0x%08x loaded from offset 0x%08x.\n", 1315 aligned_code_end, oat_file_.Size(), 1316 code_size, code_size_offset); 1317 success = false; 1318 if (options_.disassemble_code_) { 1319 if (code_size_offset + kPrologueBytes <= oat_file_.Size()) { 1320 DumpCode(vios, oat_method, code_item, true, kPrologueBytes); 1321 } 1322 } 1323 } else if (code_size > kMaxCodeSize) { 1324 vios->Stream() << StringPrintf( 1325 "WARNING: " 1326 "code size %d is bigger than max expected threshold of %d. " 1327 "code size is 0x%08x loaded from offset 0x%08x.\n", 1328 code_size, kMaxCodeSize, 1329 code_size, code_size_offset); 1330 success = false; 1331 if (options_.disassemble_code_) { 1332 if (code_size_offset + kPrologueBytes <= oat_file_.Size()) { 1333 DumpCode(vios, oat_method, code_item, true, kPrologueBytes); 1334 } 1335 } 1336 } else if (options_.disassemble_code_) { 1337 DumpCode(vios, oat_method, code_item, !success, 0); 1338 } 1339 } 1340 } 1341 vios->Stream() << std::flush; 1342 return success; 1343 } 1344 1345 void DumpSpillMask(std::ostream& os, uint32_t spill_mask, bool is_float) { 1346 if (spill_mask == 0) { 1347 return; 1348 } 1349 os << "("; 1350 for (size_t i = 0; i < 32; i++) { 1351 if ((spill_mask & (1 << i)) != 0) { 1352 if (is_float) { 1353 os << "fr" << i; 1354 } else { 1355 os << "r" << i; 1356 } 1357 spill_mask ^= 1 << i; // clear bit 1358 if (spill_mask != 0) { 1359 os << ", "; 1360 } else { 1361 break; 1362 } 1363 } 1364 } 1365 os << ")"; 1366 } 1367 1368 // Display data stored at the the vmap offset of an oat method. 1369 void DumpVmapData(VariableIndentationOutputStream* vios, 1370 const OatFile::OatMethod& oat_method, 1371 const DexFile::CodeItem* code_item) { 1372 if (IsMethodGeneratedByOptimizingCompiler(oat_method, code_item)) { 1373 // The optimizing compiler outputs its CodeInfo data in the vmap table. 1374 const void* raw_code_info = oat_method.GetVmapTable(); 1375 if (raw_code_info != nullptr) { 1376 CodeInfo code_info(raw_code_info); 1377 DCHECK(code_item != nullptr); 1378 ScopedIndentation indent1(vios); 1379 MethodInfo method_info = oat_method.GetOatQuickMethodHeader()->GetOptimizedMethodInfo(); 1380 DumpCodeInfo(vios, code_info, oat_method, *code_item, method_info); 1381 } 1382 } else if (IsMethodGeneratedByDexToDexCompiler(oat_method, code_item)) { 1383 // We don't encode the size in the table, so just emit that we have quickened 1384 // information. 1385 ScopedIndentation indent(vios); 1386 vios->Stream() << "quickened data\n"; 1387 } else { 1388 // Otherwise, there is nothing to display. 1389 } 1390 } 1391 1392 // Display a CodeInfo object emitted by the optimizing compiler. 1393 void DumpCodeInfo(VariableIndentationOutputStream* vios, 1394 const CodeInfo& code_info, 1395 const OatFile::OatMethod& oat_method, 1396 const DexFile::CodeItem& code_item, 1397 const MethodInfo& method_info) { 1398 code_info.Dump(vios, 1399 oat_method.GetCodeOffset(), 1400 code_item.registers_size_, 1401 options_.dump_code_info_stack_maps_, 1402 instruction_set_, 1403 method_info); 1404 } 1405 1406 static int GetOutVROffset(uint16_t out_num, InstructionSet isa) { 1407 // According to stack model, the first out is above the Method referernce. 1408 return static_cast<size_t>(InstructionSetPointerSize(isa)) + out_num * sizeof(uint32_t); 1409 } 1410 1411 static uint32_t GetVRegOffsetFromQuickCode(const DexFile::CodeItem* code_item, 1412 uint32_t core_spills, 1413 uint32_t fp_spills, 1414 size_t frame_size, 1415 int reg, 1416 InstructionSet isa) { 1417 PointerSize pointer_size = InstructionSetPointerSize(isa); 1418 if (kIsDebugBuild) { 1419 auto* runtime = Runtime::Current(); 1420 if (runtime != nullptr) { 1421 CHECK_EQ(runtime->GetClassLinker()->GetImagePointerSize(), pointer_size); 1422 } 1423 } 1424 DCHECK_ALIGNED(frame_size, kStackAlignment); 1425 DCHECK_NE(reg, -1); 1426 int spill_size = POPCOUNT(core_spills) * GetBytesPerGprSpillLocation(isa) 1427 + POPCOUNT(fp_spills) * GetBytesPerFprSpillLocation(isa) 1428 + sizeof(uint32_t); // Filler. 1429 int num_regs = code_item->registers_size_ - code_item->ins_size_; 1430 int temp_threshold = code_item->registers_size_; 1431 const int max_num_special_temps = 1; 1432 if (reg == temp_threshold) { 1433 // The current method pointer corresponds to special location on stack. 1434 return 0; 1435 } else if (reg >= temp_threshold + max_num_special_temps) { 1436 /* 1437 * Special temporaries may have custom locations and the logic above deals with that. 1438 * However, non-special temporaries are placed relative to the outs. 1439 */ 1440 int temps_start = code_item->outs_size_ * sizeof(uint32_t) 1441 + static_cast<size_t>(pointer_size) /* art method */; 1442 int relative_offset = (reg - (temp_threshold + max_num_special_temps)) * sizeof(uint32_t); 1443 return temps_start + relative_offset; 1444 } else if (reg < num_regs) { 1445 int locals_start = frame_size - spill_size - num_regs * sizeof(uint32_t); 1446 return locals_start + (reg * sizeof(uint32_t)); 1447 } else { 1448 // Handle ins. 1449 return frame_size + ((reg - num_regs) * sizeof(uint32_t)) 1450 + static_cast<size_t>(pointer_size) /* art method */; 1451 } 1452 } 1453 1454 void DumpVregLocations(std::ostream& os, const OatFile::OatMethod& oat_method, 1455 const DexFile::CodeItem* code_item) { 1456 if (code_item != nullptr) { 1457 size_t num_locals_ins = code_item->registers_size_; 1458 size_t num_ins = code_item->ins_size_; 1459 size_t num_locals = num_locals_ins - num_ins; 1460 size_t num_outs = code_item->outs_size_; 1461 1462 os << "vr_stack_locations:"; 1463 for (size_t reg = 0; reg <= num_locals_ins; reg++) { 1464 // For readability, delimit the different kinds of VRs. 1465 if (reg == num_locals_ins) { 1466 os << "\n\tmethod*:"; 1467 } else if (reg == num_locals && num_ins > 0) { 1468 os << "\n\tins:"; 1469 } else if (reg == 0 && num_locals > 0) { 1470 os << "\n\tlocals:"; 1471 } 1472 1473 uint32_t offset = GetVRegOffsetFromQuickCode(code_item, 1474 oat_method.GetCoreSpillMask(), 1475 oat_method.GetFpSpillMask(), 1476 oat_method.GetFrameSizeInBytes(), 1477 reg, 1478 GetInstructionSet()); 1479 os << " v" << reg << "[sp + #" << offset << "]"; 1480 } 1481 1482 for (size_t out_reg = 0; out_reg < num_outs; out_reg++) { 1483 if (out_reg == 0) { 1484 os << "\n\touts:"; 1485 } 1486 1487 uint32_t offset = GetOutVROffset(out_reg, GetInstructionSet()); 1488 os << " v" << out_reg << "[sp + #" << offset << "]"; 1489 } 1490 1491 os << "\n"; 1492 } 1493 } 1494 1495 void DumpDexCode(std::ostream& os, const DexFile& dex_file, const DexFile::CodeItem* code_item) { 1496 if (code_item != nullptr) { 1497 size_t i = 0; 1498 while (i < code_item->insns_size_in_code_units_) { 1499 const Instruction* instruction = Instruction::At(&code_item->insns_[i]); 1500 os << StringPrintf("0x%04zx: ", i) << instruction->DumpHexLE(5) 1501 << StringPrintf("\t| %s\n", instruction->DumpString(&dex_file).c_str()); 1502 i += instruction->SizeInCodeUnits(); 1503 } 1504 } 1505 } 1506 1507 // Has `oat_method` -- corresponding to the Dex `code_item` -- been compiled by 1508 // the optimizing compiler? 1509 static bool IsMethodGeneratedByOptimizingCompiler(const OatFile::OatMethod& oat_method, 1510 const DexFile::CodeItem* code_item) { 1511 // If the native GC map is null and the Dex `code_item` is not 1512 // null, then this method has been compiled with the optimizing 1513 // compiler. 1514 return oat_method.GetQuickCode() != nullptr && 1515 oat_method.GetVmapTable() != nullptr && 1516 code_item != nullptr; 1517 } 1518 1519 // Has `oat_method` -- corresponding to the Dex `code_item` -- been compiled by 1520 // the dextodex compiler? 1521 static bool IsMethodGeneratedByDexToDexCompiler(const OatFile::OatMethod& oat_method, 1522 const DexFile::CodeItem* code_item) { 1523 // If the quick code is null, the Dex `code_item` is not 1524 // null, and the vmap table is not null, then this method has been compiled 1525 // with the dextodex compiler. 1526 return oat_method.GetQuickCode() == nullptr && 1527 oat_method.GetVmapTable() != nullptr && 1528 code_item != nullptr; 1529 } 1530 1531 verifier::MethodVerifier* DumpVerifier(VariableIndentationOutputStream* vios, 1532 StackHandleScope<1>* hs, 1533 uint32_t dex_method_idx, 1534 const DexFile* dex_file, 1535 const DexFile::ClassDef& class_def, 1536 const DexFile::CodeItem* code_item, 1537 uint32_t method_access_flags) { 1538 if ((method_access_flags & kAccNative) == 0) { 1539 ScopedObjectAccess soa(Thread::Current()); 1540 Runtime* const runtime = Runtime::Current(); 1541 Handle<mirror::DexCache> dex_cache( 1542 hs->NewHandle(runtime->GetClassLinker()->RegisterDexFile(*dex_file, nullptr))); 1543 CHECK(dex_cache != nullptr); 1544 DCHECK(options_.class_loader_ != nullptr); 1545 return verifier::MethodVerifier::VerifyMethodAndDump( 1546 soa.Self(), vios, dex_method_idx, dex_file, dex_cache, *options_.class_loader_, 1547 class_def, code_item, nullptr, method_access_flags); 1548 } 1549 1550 return nullptr; 1551 } 1552 1553 // The StackMapsHelper provides the stack maps in the native PC order. 1554 // For identical native PCs, the order from the CodeInfo is preserved. 1555 class StackMapsHelper { 1556 public: 1557 explicit StackMapsHelper(const uint8_t* raw_code_info, InstructionSet instruction_set) 1558 : code_info_(raw_code_info), 1559 encoding_(code_info_.ExtractEncoding()), 1560 number_of_stack_maps_(code_info_.GetNumberOfStackMaps(encoding_)), 1561 indexes_(), 1562 offset_(static_cast<uint32_t>(-1)), 1563 stack_map_index_(0u), 1564 instruction_set_(instruction_set) { 1565 if (number_of_stack_maps_ != 0u) { 1566 // Check if native PCs are ordered. 1567 bool ordered = true; 1568 StackMap last = code_info_.GetStackMapAt(0u, encoding_); 1569 for (size_t i = 1; i != number_of_stack_maps_; ++i) { 1570 StackMap current = code_info_.GetStackMapAt(i, encoding_); 1571 if (last.GetNativePcOffset(encoding_.stack_map.encoding, instruction_set) > 1572 current.GetNativePcOffset(encoding_.stack_map.encoding, instruction_set)) { 1573 ordered = false; 1574 break; 1575 } 1576 last = current; 1577 } 1578 if (!ordered) { 1579 // Create indirection indexes for access in native PC order. We do not optimize 1580 // for the fact that there can currently be only two separately ordered ranges, 1581 // namely normal stack maps and catch-point stack maps. 1582 indexes_.resize(number_of_stack_maps_); 1583 std::iota(indexes_.begin(), indexes_.end(), 0u); 1584 std::sort(indexes_.begin(), 1585 indexes_.end(), 1586 [this](size_t lhs, size_t rhs) { 1587 StackMap left = code_info_.GetStackMapAt(lhs, encoding_); 1588 uint32_t left_pc = left.GetNativePcOffset(encoding_.stack_map.encoding, 1589 instruction_set_); 1590 StackMap right = code_info_.GetStackMapAt(rhs, encoding_); 1591 uint32_t right_pc = right.GetNativePcOffset(encoding_.stack_map.encoding, 1592 instruction_set_); 1593 // If the PCs are the same, compare indexes to preserve the original order. 1594 return (left_pc < right_pc) || (left_pc == right_pc && lhs < rhs); 1595 }); 1596 } 1597 offset_ = GetStackMapAt(0).GetNativePcOffset(encoding_.stack_map.encoding, 1598 instruction_set_); 1599 } 1600 } 1601 1602 const CodeInfo& GetCodeInfo() const { 1603 return code_info_; 1604 } 1605 1606 const CodeInfoEncoding& GetEncoding() const { 1607 return encoding_; 1608 } 1609 1610 uint32_t GetOffset() const { 1611 return offset_; 1612 } 1613 1614 StackMap GetStackMap() const { 1615 return GetStackMapAt(stack_map_index_); 1616 } 1617 1618 void Next() { 1619 ++stack_map_index_; 1620 offset_ = (stack_map_index_ == number_of_stack_maps_) 1621 ? static_cast<uint32_t>(-1) 1622 : GetStackMapAt(stack_map_index_).GetNativePcOffset(encoding_.stack_map.encoding, 1623 instruction_set_); 1624 } 1625 1626 private: 1627 StackMap GetStackMapAt(size_t i) const { 1628 if (!indexes_.empty()) { 1629 i = indexes_[i]; 1630 } 1631 DCHECK_LT(i, number_of_stack_maps_); 1632 return code_info_.GetStackMapAt(i, encoding_); 1633 } 1634 1635 const CodeInfo code_info_; 1636 const CodeInfoEncoding encoding_; 1637 const size_t number_of_stack_maps_; 1638 dchecked_vector<size_t> indexes_; // Used if stack map native PCs are not ordered. 1639 uint32_t offset_; 1640 size_t stack_map_index_; 1641 const InstructionSet instruction_set_; 1642 }; 1643 1644 void DumpCode(VariableIndentationOutputStream* vios, 1645 const OatFile::OatMethod& oat_method, const DexFile::CodeItem* code_item, 1646 bool bad_input, size_t code_size) { 1647 const void* quick_code = oat_method.GetQuickCode(); 1648 1649 if (code_size == 0) { 1650 code_size = oat_method.GetQuickCodeSize(); 1651 } 1652 if (code_size == 0 || quick_code == nullptr) { 1653 vios->Stream() << "NO CODE!\n"; 1654 return; 1655 } else if (!bad_input && IsMethodGeneratedByOptimizingCompiler(oat_method, code_item)) { 1656 // The optimizing compiler outputs its CodeInfo data in the vmap table. 1657 StackMapsHelper helper(oat_method.GetVmapTable(), instruction_set_); 1658 MethodInfo method_info(oat_method.GetOatQuickMethodHeader()->GetOptimizedMethodInfo()); 1659 { 1660 CodeInfoEncoding encoding(helper.GetEncoding()); 1661 StackMapEncoding stack_map_encoding(encoding.stack_map.encoding); 1662 const size_t num_stack_maps = encoding.stack_map.num_entries; 1663 if (stats_.AddBitsIfUnique(Stats::kByteKindCodeInfoEncoding, 1664 encoding.HeaderSize() * kBitsPerByte, 1665 oat_method.GetVmapTable())) { 1666 // Stack maps 1667 stats_.AddBits( 1668 Stats::kByteKindStackMapNativePc, 1669 stack_map_encoding.GetNativePcEncoding().BitSize() * num_stack_maps); 1670 stats_.AddBits( 1671 Stats::kByteKindStackMapDexPc, 1672 stack_map_encoding.GetDexPcEncoding().BitSize() * num_stack_maps); 1673 stats_.AddBits( 1674 Stats::kByteKindStackMapDexRegisterMap, 1675 stack_map_encoding.GetDexRegisterMapEncoding().BitSize() * num_stack_maps); 1676 stats_.AddBits( 1677 Stats::kByteKindStackMapInlineInfoIndex, 1678 stack_map_encoding.GetInlineInfoEncoding().BitSize() * num_stack_maps); 1679 stats_.AddBits( 1680 Stats::kByteKindStackMapRegisterMaskIndex, 1681 stack_map_encoding.GetRegisterMaskIndexEncoding().BitSize() * num_stack_maps); 1682 stats_.AddBits( 1683 Stats::kByteKindStackMapStackMaskIndex, 1684 stack_map_encoding.GetStackMaskIndexEncoding().BitSize() * num_stack_maps); 1685 1686 // Stack masks 1687 stats_.AddBits( 1688 Stats::kByteKindCodeInfoStackMasks, 1689 encoding.stack_mask.encoding.BitSize() * encoding.stack_mask.num_entries); 1690 1691 // Register masks 1692 stats_.AddBits( 1693 Stats::kByteKindCodeInfoRegisterMasks, 1694 encoding.register_mask.encoding.BitSize() * encoding.register_mask.num_entries); 1695 1696 // Invoke infos 1697 if (encoding.invoke_info.num_entries > 0u) { 1698 stats_.AddBits( 1699 Stats::kByteKindCodeInfoInvokeInfo, 1700 encoding.invoke_info.encoding.BitSize() * encoding.invoke_info.num_entries); 1701 } 1702 1703 // Location catalog 1704 const size_t location_catalog_bytes = 1705 helper.GetCodeInfo().GetDexRegisterLocationCatalogSize(encoding); 1706 stats_.AddBits(Stats::kByteKindCodeInfoLocationCatalog, 1707 kBitsPerByte * location_catalog_bytes); 1708 // Dex register bytes. 1709 const size_t dex_register_bytes = 1710 helper.GetCodeInfo().GetDexRegisterMapsSize(encoding, code_item->registers_size_); 1711 stats_.AddBits( 1712 Stats::kByteKindCodeInfoDexRegisterMap, 1713 kBitsPerByte * dex_register_bytes); 1714 1715 // Inline infos. 1716 const size_t num_inline_infos = encoding.inline_info.num_entries; 1717 if (num_inline_infos > 0u) { 1718 stats_.AddBits( 1719 Stats::kByteKindInlineInfoMethodIndexIdx, 1720 encoding.inline_info.encoding.GetMethodIndexIdxEncoding().BitSize() * 1721 num_inline_infos); 1722 stats_.AddBits( 1723 Stats::kByteKindInlineInfoDexPc, 1724 encoding.inline_info.encoding.GetDexPcEncoding().BitSize() * num_inline_infos); 1725 stats_.AddBits( 1726 Stats::kByteKindInlineInfoExtraData, 1727 encoding.inline_info.encoding.GetExtraDataEncoding().BitSize() * num_inline_infos); 1728 stats_.AddBits( 1729 Stats::kByteKindInlineInfoDexRegisterMap, 1730 encoding.inline_info.encoding.GetDexRegisterMapEncoding().BitSize() * 1731 num_inline_infos); 1732 stats_.AddBits(Stats::kByteKindInlineInfoIsLast, num_inline_infos); 1733 } 1734 } 1735 } 1736 const uint8_t* quick_native_pc = reinterpret_cast<const uint8_t*>(quick_code); 1737 size_t offset = 0; 1738 while (offset < code_size) { 1739 offset += disassembler_->Dump(vios->Stream(), quick_native_pc + offset); 1740 if (offset == helper.GetOffset()) { 1741 ScopedIndentation indent1(vios); 1742 StackMap stack_map = helper.GetStackMap(); 1743 DCHECK(stack_map.IsValid()); 1744 stack_map.Dump(vios, 1745 helper.GetCodeInfo(), 1746 helper.GetEncoding(), 1747 method_info, 1748 oat_method.GetCodeOffset(), 1749 code_item->registers_size_, 1750 instruction_set_); 1751 do { 1752 helper.Next(); 1753 // There may be multiple stack maps at a given PC. We display only the first one. 1754 } while (offset == helper.GetOffset()); 1755 } 1756 DCHECK_LT(offset, helper.GetOffset()); 1757 } 1758 } else { 1759 const uint8_t* quick_native_pc = reinterpret_cast<const uint8_t*>(quick_code); 1760 size_t offset = 0; 1761 while (offset < code_size) { 1762 offset += disassembler_->Dump(vios->Stream(), quick_native_pc + offset); 1763 } 1764 } 1765 } 1766 1767 const OatFile& oat_file_; 1768 const std::vector<const OatFile::OatDexFile*> oat_dex_files_; 1769 const OatDumperOptions& options_; 1770 uint32_t resolved_addr2instr_; 1771 const InstructionSet instruction_set_; 1772 std::set<uintptr_t> offsets_; 1773 Disassembler* disassembler_; 1774 Stats stats_; 1775 }; 1776 1777 class ImageDumper { 1778 public: 1779 ImageDumper(std::ostream* os, 1780 gc::space::ImageSpace& image_space, 1781 const ImageHeader& image_header, 1782 OatDumperOptions* oat_dumper_options) 1783 : os_(os), 1784 vios_(os), 1785 indent1_(&vios_), 1786 image_space_(image_space), 1787 image_header_(image_header), 1788 oat_dumper_options_(oat_dumper_options) {} 1789 1790 bool Dump() REQUIRES_SHARED(Locks::mutator_lock_) { 1791 std::ostream& os = *os_; 1792 std::ostream& indent_os = vios_.Stream(); 1793 1794 os << "MAGIC: " << image_header_.GetMagic() << "\n\n"; 1795 1796 os << "IMAGE LOCATION: " << image_space_.GetImageLocation() << "\n\n"; 1797 1798 os << "IMAGE BEGIN: " << reinterpret_cast<void*>(image_header_.GetImageBegin()) << "\n\n"; 1799 1800 os << "IMAGE SIZE: " << image_header_.GetImageSize() << "\n\n"; 1801 1802 for (size_t i = 0; i < ImageHeader::kSectionCount; ++i) { 1803 auto section = static_cast<ImageHeader::ImageSections>(i); 1804 os << "IMAGE SECTION " << section << ": " << image_header_.GetImageSection(section) << "\n\n"; 1805 } 1806 1807 os << "OAT CHECKSUM: " << StringPrintf("0x%08x\n\n", image_header_.GetOatChecksum()); 1808 1809 os << "OAT FILE BEGIN:" << reinterpret_cast<void*>(image_header_.GetOatFileBegin()) << "\n\n"; 1810 1811 os << "OAT DATA BEGIN:" << reinterpret_cast<void*>(image_header_.GetOatDataBegin()) << "\n\n"; 1812 1813 os << "OAT DATA END:" << reinterpret_cast<void*>(image_header_.GetOatDataEnd()) << "\n\n"; 1814 1815 os << "OAT FILE END:" << reinterpret_cast<void*>(image_header_.GetOatFileEnd()) << "\n\n"; 1816 1817 os << "PATCH DELTA:" << image_header_.GetPatchDelta() << "\n\n"; 1818 1819 os << "COMPILE PIC: " << (image_header_.CompilePic() ? "yes" : "no") << "\n\n"; 1820 1821 { 1822 os << "ROOTS: " << reinterpret_cast<void*>(image_header_.GetImageRoots()) << "\n"; 1823 static_assert(arraysize(image_roots_descriptions_) == 1824 static_cast<size_t>(ImageHeader::kImageRootsMax), "sizes must match"); 1825 DCHECK_LE(image_header_.GetImageRoots()->GetLength(), ImageHeader::kImageRootsMax); 1826 for (int32_t i = 0, size = image_header_.GetImageRoots()->GetLength(); i != size; ++i) { 1827 ImageHeader::ImageRoot image_root = static_cast<ImageHeader::ImageRoot>(i); 1828 const char* image_root_description = image_roots_descriptions_[i]; 1829 mirror::Object* image_root_object = image_header_.GetImageRoot(image_root); 1830 indent_os << StringPrintf("%s: %p\n", image_root_description, image_root_object); 1831 if (image_root_object != nullptr && image_root_object->IsObjectArray()) { 1832 mirror::ObjectArray<mirror::Object>* image_root_object_array 1833 = image_root_object->AsObjectArray<mirror::Object>(); 1834 ScopedIndentation indent2(&vios_); 1835 for (int j = 0; j < image_root_object_array->GetLength(); j++) { 1836 mirror::Object* value = image_root_object_array->Get(j); 1837 size_t run = 0; 1838 for (int32_t k = j + 1; k < image_root_object_array->GetLength(); k++) { 1839 if (value == image_root_object_array->Get(k)) { 1840 run++; 1841 } else { 1842 break; 1843 } 1844 } 1845 if (run == 0) { 1846 indent_os << StringPrintf("%d: ", j); 1847 } else { 1848 indent_os << StringPrintf("%d to %zd: ", j, j + run); 1849 j = j + run; 1850 } 1851 if (value != nullptr) { 1852 PrettyObjectValue(indent_os, value->GetClass(), value); 1853 } else { 1854 indent_os << j << ": null\n"; 1855 } 1856 } 1857 } 1858 } 1859 } 1860 1861 { 1862 os << "METHOD ROOTS\n"; 1863 static_assert(arraysize(image_methods_descriptions_) == 1864 static_cast<size_t>(ImageHeader::kImageMethodsCount), "sizes must match"); 1865 for (int i = 0; i < ImageHeader::kImageMethodsCount; i++) { 1866 auto image_root = static_cast<ImageHeader::ImageMethod>(i); 1867 const char* description = image_methods_descriptions_[i]; 1868 auto* image_method = image_header_.GetImageMethod(image_root); 1869 indent_os << StringPrintf("%s: %p\n", description, image_method); 1870 } 1871 } 1872 os << "\n"; 1873 1874 Runtime* const runtime = Runtime::Current(); 1875 ClassLinker* class_linker = runtime->GetClassLinker(); 1876 std::string image_filename = image_space_.GetImageFilename(); 1877 std::string oat_location = ImageHeader::GetOatLocationFromImageLocation(image_filename); 1878 os << "OAT LOCATION: " << oat_location; 1879 os << "\n"; 1880 std::string error_msg; 1881 const OatFile* oat_file = image_space_.GetOatFile(); 1882 if (oat_file == nullptr) { 1883 oat_file = runtime->GetOatFileManager().FindOpenedOatFileFromOatLocation(oat_location); 1884 } 1885 if (oat_file == nullptr) { 1886 oat_file = OatFile::Open(oat_location, 1887 oat_location, 1888 nullptr, 1889 nullptr, 1890 false, 1891 /*low_4gb*/false, 1892 nullptr, 1893 &error_msg); 1894 } 1895 if (oat_file == nullptr) { 1896 os << "OAT FILE NOT FOUND: " << error_msg << "\n"; 1897 return EXIT_FAILURE; 1898 } 1899 os << "\n"; 1900 1901 stats_.oat_file_bytes = oat_file->Size(); 1902 1903 oat_dumper_.reset(new OatDumper(*oat_file, *oat_dumper_options_)); 1904 1905 for (const OatFile::OatDexFile* oat_dex_file : oat_file->GetOatDexFiles()) { 1906 CHECK(oat_dex_file != nullptr); 1907 stats_.oat_dex_file_sizes.push_back(std::make_pair(oat_dex_file->GetDexFileLocation(), 1908 oat_dex_file->FileSize())); 1909 } 1910 1911 os << "OBJECTS:\n" << std::flush; 1912 1913 // Loop through the image space and dump its objects. 1914 gc::Heap* heap = runtime->GetHeap(); 1915 Thread* self = Thread::Current(); 1916 { 1917 { 1918 WriterMutexLock mu(self, *Locks::heap_bitmap_lock_); 1919 heap->FlushAllocStack(); 1920 } 1921 // Since FlushAllocStack() above resets the (active) allocation 1922 // stack. Need to revoke the thread-local allocation stacks that 1923 // point into it. 1924 ScopedThreadSuspension sts(self, kNative); 1925 ScopedSuspendAll ssa(__FUNCTION__); 1926 heap->RevokeAllThreadLocalAllocationStacks(self); 1927 } 1928 { 1929 // Mark dex caches. 1930 dex_caches_.clear(); 1931 { 1932 ReaderMutexLock mu(self, *Locks::dex_lock_); 1933 for (const ClassLinker::DexCacheData& data : class_linker->GetDexCachesData()) { 1934 ObjPtr<mirror::DexCache> dex_cache = 1935 ObjPtr<mirror::DexCache>::DownCast(self->DecodeJObject(data.weak_root)); 1936 if (dex_cache != nullptr) { 1937 dex_caches_.insert(dex_cache.Ptr()); 1938 } 1939 } 1940 } 1941 auto dump_visitor = [&](mirror::Object* obj) REQUIRES_SHARED(Locks::mutator_lock_) { 1942 DumpObject(obj); 1943 }; 1944 ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_); 1945 // Dump the normal objects before ArtMethods. 1946 image_space_.GetLiveBitmap()->Walk(dump_visitor); 1947 indent_os << "\n"; 1948 // TODO: Dump fields. 1949 // Dump methods after. 1950 DumpArtMethodVisitor visitor(this); 1951 image_header_.VisitPackedArtMethods(&visitor, 1952 image_space_.Begin(), 1953 image_header_.GetPointerSize()); 1954 // Dump the large objects separately. 1955 heap->GetLargeObjectsSpace()->GetLiveBitmap()->Walk(dump_visitor); 1956 indent_os << "\n"; 1957 } 1958 os << "STATS:\n" << std::flush; 1959 std::unique_ptr<File> file(OS::OpenFileForReading(image_filename.c_str())); 1960 size_t data_size = image_header_.GetDataSize(); // stored size in file. 1961 if (file == nullptr) { 1962 LOG(WARNING) << "Failed to find image in " << image_filename; 1963 } else { 1964 stats_.file_bytes = file->GetLength(); 1965 // If the image is compressed, adjust to decompressed size. 1966 size_t uncompressed_size = image_header_.GetImageSize() - sizeof(ImageHeader); 1967 if (image_header_.GetStorageMode() == ImageHeader::kStorageModeUncompressed) { 1968 DCHECK_EQ(uncompressed_size, data_size) << "Sizes should match for uncompressed image"; 1969 } 1970 stats_.file_bytes += uncompressed_size - data_size; 1971 } 1972 size_t header_bytes = sizeof(ImageHeader); 1973 const auto& object_section = image_header_.GetImageSection(ImageHeader::kSectionObjects); 1974 const auto& field_section = image_header_.GetImageSection(ImageHeader::kSectionArtFields); 1975 const auto& method_section = image_header_.GetMethodsSection(); 1976 const auto& dex_cache_arrays_section = image_header_.GetImageSection( 1977 ImageHeader::kSectionDexCacheArrays); 1978 const auto& intern_section = image_header_.GetImageSection( 1979 ImageHeader::kSectionInternedStrings); 1980 const auto& class_table_section = image_header_.GetImageSection( 1981 ImageHeader::kSectionClassTable); 1982 const auto& bitmap_section = image_header_.GetImageSection(ImageHeader::kSectionImageBitmap); 1983 1984 stats_.header_bytes = header_bytes; 1985 1986 // Objects are kObjectAlignment-aligned. 1987 // CHECK_EQ(RoundUp(header_bytes, kObjectAlignment), object_section.Offset()); 1988 if (object_section.Offset() > header_bytes) { 1989 stats_.alignment_bytes += object_section.Offset() - header_bytes; 1990 } 1991 1992 // Field section is 4-byte aligned. 1993 constexpr size_t kFieldSectionAlignment = 4U; 1994 uint32_t end_objects = object_section.Offset() + object_section.Size(); 1995 CHECK_EQ(RoundUp(end_objects, kFieldSectionAlignment), field_section.Offset()); 1996 stats_.alignment_bytes += field_section.Offset() - end_objects; 1997 1998 // Method section is 4/8 byte aligned depending on target. Just check for 4-byte alignment. 1999 uint32_t end_fields = field_section.Offset() + field_section.Size(); 2000 CHECK_ALIGNED(method_section.Offset(), 4); 2001 stats_.alignment_bytes += method_section.Offset() - end_fields; 2002 2003 // Dex cache arrays section is aligned depending on the target. Just check for 4-byte alignment. 2004 uint32_t end_methods = method_section.Offset() + method_section.Size(); 2005 CHECK_ALIGNED(dex_cache_arrays_section.Offset(), 4); 2006 stats_.alignment_bytes += dex_cache_arrays_section.Offset() - end_methods; 2007 2008 // Intern table is 8-byte aligned. 2009 uint32_t end_caches = dex_cache_arrays_section.Offset() + dex_cache_arrays_section.Size(); 2010 CHECK_EQ(RoundUp(end_caches, 8U), intern_section.Offset()); 2011 stats_.alignment_bytes += intern_section.Offset() - end_caches; 2012 2013 // Add space between intern table and class table. 2014 uint32_t end_intern = intern_section.Offset() + intern_section.Size(); 2015 stats_.alignment_bytes += class_table_section.Offset() - end_intern; 2016 2017 // Add space between end of image data and bitmap. Expect the bitmap to be page-aligned. 2018 const size_t bitmap_offset = sizeof(ImageHeader) + data_size; 2019 CHECK_ALIGNED(bitmap_section.Offset(), kPageSize); 2020 stats_.alignment_bytes += RoundUp(bitmap_offset, kPageSize) - bitmap_offset; 2021 2022 stats_.bitmap_bytes += bitmap_section.Size(); 2023 stats_.art_field_bytes += field_section.Size(); 2024 stats_.art_method_bytes += method_section.Size(); 2025 stats_.dex_cache_arrays_bytes += dex_cache_arrays_section.Size(); 2026 stats_.interned_strings_bytes += intern_section.Size(); 2027 stats_.class_table_bytes += class_table_section.Size(); 2028 stats_.Dump(os, indent_os); 2029 os << "\n"; 2030 2031 os << std::flush; 2032 2033 return oat_dumper_->Dump(os); 2034 } 2035 2036 private: 2037 class DumpArtMethodVisitor : public ArtMethodVisitor { 2038 public: 2039 explicit DumpArtMethodVisitor(ImageDumper* image_dumper) : image_dumper_(image_dumper) {} 2040 2041 virtual void Visit(ArtMethod* method) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { 2042 std::ostream& indent_os = image_dumper_->vios_.Stream(); 2043 indent_os << method << " " << " ArtMethod: " << ArtMethod::PrettyMethod(method) << "\n"; 2044 image_dumper_->DumpMethod(method, indent_os); 2045 indent_os << "\n"; 2046 } 2047 2048 private: 2049 ImageDumper* const image_dumper_; 2050 }; 2051 2052 static void PrettyObjectValue(std::ostream& os, 2053 ObjPtr<mirror::Class> type, 2054 ObjPtr<mirror::Object> value) 2055 REQUIRES_SHARED(Locks::mutator_lock_) { 2056 CHECK(type != nullptr); 2057 if (value == nullptr) { 2058 os << StringPrintf("null %s\n", type->PrettyDescriptor().c_str()); 2059 } else if (type->IsStringClass()) { 2060 mirror::String* string = value->AsString(); 2061 os << StringPrintf("%p String: %s\n", string, 2062 PrintableString(string->ToModifiedUtf8().c_str()).c_str()); 2063 } else if (type->IsClassClass()) { 2064 mirror::Class* klass = value->AsClass(); 2065 os << StringPrintf("%p Class: %s\n", klass, mirror::Class::PrettyDescriptor(klass).c_str()); 2066 } else { 2067 os << StringPrintf("%p %s\n", value.Ptr(), type->PrettyDescriptor().c_str()); 2068 } 2069 } 2070 2071 static void PrintField(std::ostream& os, ArtField* field, ObjPtr<mirror::Object> obj) 2072 REQUIRES_SHARED(Locks::mutator_lock_) { 2073 os << StringPrintf("%s: ", field->GetName()); 2074 switch (field->GetTypeAsPrimitiveType()) { 2075 case Primitive::kPrimLong: 2076 os << StringPrintf("%" PRId64 " (0x%" PRIx64 ")\n", field->Get64(obj), field->Get64(obj)); 2077 break; 2078 case Primitive::kPrimDouble: 2079 os << StringPrintf("%f (%a)\n", field->GetDouble(obj), field->GetDouble(obj)); 2080 break; 2081 case Primitive::kPrimFloat: 2082 os << StringPrintf("%f (%a)\n", field->GetFloat(obj), field->GetFloat(obj)); 2083 break; 2084 case Primitive::kPrimInt: 2085 os << StringPrintf("%d (0x%x)\n", field->Get32(obj), field->Get32(obj)); 2086 break; 2087 case Primitive::kPrimChar: 2088 os << StringPrintf("%u (0x%x)\n", field->GetChar(obj), field->GetChar(obj)); 2089 break; 2090 case Primitive::kPrimShort: 2091 os << StringPrintf("%d (0x%x)\n", field->GetShort(obj), field->GetShort(obj)); 2092 break; 2093 case Primitive::kPrimBoolean: 2094 os << StringPrintf("%s (0x%x)\n", field->GetBoolean(obj) ? "true" : "false", 2095 field->GetBoolean(obj)); 2096 break; 2097 case Primitive::kPrimByte: 2098 os << StringPrintf("%d (0x%x)\n", field->GetByte(obj), field->GetByte(obj)); 2099 break; 2100 case Primitive::kPrimNot: { 2101 // Get the value, don't compute the type unless it is non-null as we don't want 2102 // to cause class loading. 2103 ObjPtr<mirror::Object> value = field->GetObj(obj); 2104 if (value == nullptr) { 2105 os << StringPrintf("null %s\n", PrettyDescriptor(field->GetTypeDescriptor()).c_str()); 2106 } else { 2107 // Grab the field type without causing resolution. 2108 ObjPtr<mirror::Class> field_type = field->GetType<false>(); 2109 if (field_type != nullptr) { 2110 PrettyObjectValue(os, field_type, value); 2111 } else { 2112 os << StringPrintf("%p %s\n", 2113 value.Ptr(), 2114 PrettyDescriptor(field->GetTypeDescriptor()).c_str()); 2115 } 2116 } 2117 break; 2118 } 2119 default: 2120 os << "unexpected field type: " << field->GetTypeDescriptor() << "\n"; 2121 break; 2122 } 2123 } 2124 2125 static void DumpFields(std::ostream& os, mirror::Object* obj, mirror::Class* klass) 2126 REQUIRES_SHARED(Locks::mutator_lock_) { 2127 mirror::Class* super = klass->GetSuperClass(); 2128 if (super != nullptr) { 2129 DumpFields(os, obj, super); 2130 } 2131 for (ArtField& field : klass->GetIFields()) { 2132 PrintField(os, &field, obj); 2133 } 2134 } 2135 2136 bool InDumpSpace(const mirror::Object* object) { 2137 return image_space_.Contains(object); 2138 } 2139 2140 const void* GetQuickOatCodeBegin(ArtMethod* m) REQUIRES_SHARED(Locks::mutator_lock_) { 2141 const void* quick_code = m->GetEntryPointFromQuickCompiledCodePtrSize( 2142 image_header_.GetPointerSize()); 2143 if (Runtime::Current()->GetClassLinker()->IsQuickResolutionStub(quick_code)) { 2144 quick_code = oat_dumper_->GetQuickOatCode(m); 2145 } 2146 if (oat_dumper_->GetInstructionSet() == kThumb2) { 2147 quick_code = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(quick_code) & ~0x1); 2148 } 2149 return quick_code; 2150 } 2151 2152 uint32_t GetQuickOatCodeSize(ArtMethod* m) 2153 REQUIRES_SHARED(Locks::mutator_lock_) { 2154 const uint32_t* oat_code_begin = reinterpret_cast<const uint32_t*>(GetQuickOatCodeBegin(m)); 2155 if (oat_code_begin == nullptr) { 2156 return 0; 2157 } 2158 return oat_code_begin[-1]; 2159 } 2160 2161 const void* GetQuickOatCodeEnd(ArtMethod* m) 2162 REQUIRES_SHARED(Locks::mutator_lock_) { 2163 const uint8_t* oat_code_begin = reinterpret_cast<const uint8_t*>(GetQuickOatCodeBegin(m)); 2164 if (oat_code_begin == nullptr) { 2165 return nullptr; 2166 } 2167 return oat_code_begin + GetQuickOatCodeSize(m); 2168 } 2169 2170 void DumpObject(mirror::Object* obj) REQUIRES_SHARED(Locks::mutator_lock_) { 2171 DCHECK(obj != nullptr); 2172 if (!InDumpSpace(obj)) { 2173 return; 2174 } 2175 2176 size_t object_bytes = obj->SizeOf(); 2177 size_t alignment_bytes = RoundUp(object_bytes, kObjectAlignment) - object_bytes; 2178 stats_.object_bytes += object_bytes; 2179 stats_.alignment_bytes += alignment_bytes; 2180 2181 std::ostream& os = vios_.Stream(); 2182 2183 mirror::Class* obj_class = obj->GetClass(); 2184 if (obj_class->IsArrayClass()) { 2185 os << StringPrintf("%p: %s length:%d\n", obj, obj_class->PrettyDescriptor().c_str(), 2186 obj->AsArray()->GetLength()); 2187 } else if (obj->IsClass()) { 2188 mirror::Class* klass = obj->AsClass(); 2189 os << StringPrintf("%p: java.lang.Class \"%s\" (", obj, 2190 mirror::Class::PrettyDescriptor(klass).c_str()) 2191 << klass->GetStatus() << ")\n"; 2192 } else if (obj_class->IsStringClass()) { 2193 os << StringPrintf("%p: java.lang.String %s\n", obj, 2194 PrintableString(obj->AsString()->ToModifiedUtf8().c_str()).c_str()); 2195 } else { 2196 os << StringPrintf("%p: %s\n", obj, obj_class->PrettyDescriptor().c_str()); 2197 } 2198 ScopedIndentation indent1(&vios_); 2199 DumpFields(os, obj, obj_class); 2200 const PointerSize image_pointer_size = image_header_.GetPointerSize(); 2201 if (obj->IsObjectArray()) { 2202 auto* obj_array = obj->AsObjectArray<mirror::Object>(); 2203 for (int32_t i = 0, length = obj_array->GetLength(); i < length; i++) { 2204 mirror::Object* value = obj_array->Get(i); 2205 size_t run = 0; 2206 for (int32_t j = i + 1; j < length; j++) { 2207 if (value == obj_array->Get(j)) { 2208 run++; 2209 } else { 2210 break; 2211 } 2212 } 2213 if (run == 0) { 2214 os << StringPrintf("%d: ", i); 2215 } else { 2216 os << StringPrintf("%d to %zd: ", i, i + run); 2217 i = i + run; 2218 } 2219 mirror::Class* value_class = 2220 (value == nullptr) ? obj_class->GetComponentType() : value->GetClass(); 2221 PrettyObjectValue(os, value_class, value); 2222 } 2223 } else if (obj->IsClass()) { 2224 mirror::Class* klass = obj->AsClass(); 2225 if (klass->NumStaticFields() != 0) { 2226 os << "STATICS:\n"; 2227 ScopedIndentation indent2(&vios_); 2228 for (ArtField& field : klass->GetSFields()) { 2229 PrintField(os, &field, field.GetDeclaringClass()); 2230 } 2231 } 2232 } else { 2233 auto it = dex_caches_.find(obj); 2234 if (it != dex_caches_.end()) { 2235 auto* dex_cache = down_cast<mirror::DexCache*>(obj); 2236 const auto& field_section = image_header_.GetImageSection( 2237 ImageHeader::kSectionArtFields); 2238 const auto& method_section = image_header_.GetMethodsSection(); 2239 size_t num_methods = dex_cache->NumResolvedMethods(); 2240 if (num_methods != 0u) { 2241 os << "Methods (size=" << num_methods << "):\n"; 2242 ScopedIndentation indent2(&vios_); 2243 mirror::MethodDexCacheType* resolved_methods = dex_cache->GetResolvedMethods(); 2244 for (size_t i = 0, length = dex_cache->NumResolvedMethods(); i < length; ++i) { 2245 ArtMethod* elem = mirror::DexCache::GetNativePairPtrSize( 2246 resolved_methods, i, image_pointer_size).object; 2247 size_t run = 0; 2248 for (size_t j = i + 1; 2249 j != length && 2250 elem == mirror::DexCache::GetNativePairPtrSize( 2251 resolved_methods, j, image_pointer_size).object; 2252 ++j) { 2253 ++run; 2254 } 2255 if (run == 0) { 2256 os << StringPrintf("%zd: ", i); 2257 } else { 2258 os << StringPrintf("%zd to %zd: ", i, i + run); 2259 i = i + run; 2260 } 2261 std::string msg; 2262 if (elem == nullptr) { 2263 msg = "null"; 2264 } else if (method_section.Contains( 2265 reinterpret_cast<uint8_t*>(elem) - image_space_.Begin())) { 2266 msg = reinterpret_cast<ArtMethod*>(elem)->PrettyMethod(); 2267 } else { 2268 msg = "<not in method section>"; 2269 } 2270 os << StringPrintf("%p %s\n", elem, msg.c_str()); 2271 } 2272 } 2273 size_t num_fields = dex_cache->NumResolvedFields(); 2274 if (num_fields != 0u) { 2275 os << "Fields (size=" << num_fields << "):\n"; 2276 ScopedIndentation indent2(&vios_); 2277 auto* resolved_fields = dex_cache->GetResolvedFields(); 2278 for (size_t i = 0, length = dex_cache->NumResolvedFields(); i < length; ++i) { 2279 ArtField* elem = mirror::DexCache::GetNativePairPtrSize( 2280 resolved_fields, i, image_pointer_size).object; 2281 size_t run = 0; 2282 for (size_t j = i + 1; 2283 j != length && 2284 elem == mirror::DexCache::GetNativePairPtrSize( 2285 resolved_fields, j, image_pointer_size).object; 2286 ++j) { 2287 ++run; 2288 } 2289 if (run == 0) { 2290 os << StringPrintf("%zd: ", i); 2291 } else { 2292 os << StringPrintf("%zd to %zd: ", i, i + run); 2293 i = i + run; 2294 } 2295 std::string msg; 2296 if (elem == nullptr) { 2297 msg = "null"; 2298 } else if (field_section.Contains( 2299 reinterpret_cast<uint8_t*>(elem) - image_space_.Begin())) { 2300 msg = reinterpret_cast<ArtField*>(elem)->PrettyField(); 2301 } else { 2302 msg = "<not in field section>"; 2303 } 2304 os << StringPrintf("%p %s\n", elem, msg.c_str()); 2305 } 2306 } 2307 size_t num_types = dex_cache->NumResolvedTypes(); 2308 if (num_types != 0u) { 2309 os << "Types (size=" << num_types << "):\n"; 2310 ScopedIndentation indent2(&vios_); 2311 auto* resolved_types = dex_cache->GetResolvedTypes(); 2312 for (size_t i = 0; i < num_types; ++i) { 2313 auto pair = resolved_types[i].load(std::memory_order_relaxed); 2314 size_t run = 0; 2315 for (size_t j = i + 1; j != num_types; ++j) { 2316 auto other_pair = resolved_types[j].load(std::memory_order_relaxed); 2317 if (pair.index != other_pair.index || 2318 pair.object.Read() != other_pair.object.Read()) { 2319 break; 2320 } 2321 ++run; 2322 } 2323 if (run == 0) { 2324 os << StringPrintf("%zd: ", i); 2325 } else { 2326 os << StringPrintf("%zd to %zd: ", i, i + run); 2327 i = i + run; 2328 } 2329 std::string msg; 2330 auto* elem = pair.object.Read(); 2331 if (elem == nullptr) { 2332 msg = "null"; 2333 } else { 2334 msg = elem->PrettyClass(); 2335 } 2336 os << StringPrintf("%p %u %s\n", elem, pair.index, msg.c_str()); 2337 } 2338 } 2339 } 2340 } 2341 std::string temp; 2342 stats_.Update(obj_class->GetDescriptor(&temp), object_bytes); 2343 } 2344 2345 void DumpMethod(ArtMethod* method, std::ostream& indent_os) 2346 REQUIRES_SHARED(Locks::mutator_lock_) { 2347 DCHECK(method != nullptr); 2348 const void* quick_oat_code_begin = GetQuickOatCodeBegin(method); 2349 const void* quick_oat_code_end = GetQuickOatCodeEnd(method); 2350 const PointerSize pointer_size = image_header_.GetPointerSize(); 2351 OatQuickMethodHeader* method_header = reinterpret_cast<OatQuickMethodHeader*>( 2352 reinterpret_cast<uintptr_t>(quick_oat_code_begin) - sizeof(OatQuickMethodHeader)); 2353 if (method->IsNative()) { 2354 bool first_occurrence; 2355 uint32_t quick_oat_code_size = GetQuickOatCodeSize(method); 2356 ComputeOatSize(quick_oat_code_begin, &first_occurrence); 2357 if (first_occurrence) { 2358 stats_.native_to_managed_code_bytes += quick_oat_code_size; 2359 } 2360 if (quick_oat_code_begin != method->GetEntryPointFromQuickCompiledCodePtrSize( 2361 image_header_.GetPointerSize())) { 2362 indent_os << StringPrintf("OAT CODE: %p\n", quick_oat_code_begin); 2363 } 2364 } else if (method->IsAbstract() || method->IsClassInitializer()) { 2365 // Don't print information for these. 2366 } else if (method->IsRuntimeMethod()) { 2367 ImtConflictTable* table = method->GetImtConflictTable(image_header_.GetPointerSize()); 2368 if (table != nullptr) { 2369 indent_os << "IMT conflict table " << table << " method: "; 2370 for (size_t i = 0, count = table->NumEntries(pointer_size); i < count; ++i) { 2371 indent_os << ArtMethod::PrettyMethod(table->GetImplementationMethod(i, pointer_size)) 2372 << " "; 2373 } 2374 } 2375 } else { 2376 const DexFile::CodeItem* code_item = method->GetCodeItem(); 2377 size_t dex_instruction_bytes = code_item->insns_size_in_code_units_ * 2; 2378 stats_.dex_instruction_bytes += dex_instruction_bytes; 2379 2380 bool first_occurrence; 2381 size_t vmap_table_bytes = 0u; 2382 if (!method_header->IsOptimized()) { 2383 // Method compiled with the optimizing compiler have no vmap table. 2384 vmap_table_bytes = ComputeOatSize(method_header->GetVmapTable(), &first_occurrence); 2385 if (first_occurrence) { 2386 stats_.vmap_table_bytes += vmap_table_bytes; 2387 } 2388 } 2389 2390 uint32_t quick_oat_code_size = GetQuickOatCodeSize(method); 2391 ComputeOatSize(quick_oat_code_begin, &first_occurrence); 2392 if (first_occurrence) { 2393 stats_.managed_code_bytes += quick_oat_code_size; 2394 if (method->IsConstructor()) { 2395 if (method->IsStatic()) { 2396 stats_.class_initializer_code_bytes += quick_oat_code_size; 2397 } else if (dex_instruction_bytes > kLargeConstructorDexBytes) { 2398 stats_.large_initializer_code_bytes += quick_oat_code_size; 2399 } 2400 } else if (dex_instruction_bytes > kLargeMethodDexBytes) { 2401 stats_.large_method_code_bytes += quick_oat_code_size; 2402 } 2403 } 2404 stats_.managed_code_bytes_ignoring_deduplication += quick_oat_code_size; 2405 2406 uint32_t method_access_flags = method->GetAccessFlags(); 2407 2408 indent_os << StringPrintf("OAT CODE: %p-%p\n", quick_oat_code_begin, quick_oat_code_end); 2409 indent_os << StringPrintf("SIZE: Dex Instructions=%zd StackMaps=%zd AccessFlags=0x%x\n", 2410 dex_instruction_bytes, 2411 vmap_table_bytes, 2412 method_access_flags); 2413 2414 size_t total_size = dex_instruction_bytes + 2415 vmap_table_bytes + quick_oat_code_size + ArtMethod::Size(image_header_.GetPointerSize()); 2416 2417 double expansion = 2418 static_cast<double>(quick_oat_code_size) / static_cast<double>(dex_instruction_bytes); 2419 stats_.ComputeOutliers(total_size, expansion, method); 2420 } 2421 } 2422 2423 std::set<const void*> already_seen_; 2424 // Compute the size of the given data within the oat file and whether this is the first time 2425 // this data has been requested 2426 size_t ComputeOatSize(const void* oat_data, bool* first_occurrence) { 2427 if (already_seen_.count(oat_data) == 0) { 2428 *first_occurrence = true; 2429 already_seen_.insert(oat_data); 2430 } else { 2431 *first_occurrence = false; 2432 } 2433 return oat_dumper_->ComputeSize(oat_data); 2434 } 2435 2436 public: 2437 struct Stats { 2438 size_t oat_file_bytes; 2439 size_t file_bytes; 2440 2441 size_t header_bytes; 2442 size_t object_bytes; 2443 size_t art_field_bytes; 2444 size_t art_method_bytes; 2445 size_t dex_cache_arrays_bytes; 2446 size_t interned_strings_bytes; 2447 size_t class_table_bytes; 2448 size_t bitmap_bytes; 2449 size_t alignment_bytes; 2450 2451 size_t managed_code_bytes; 2452 size_t managed_code_bytes_ignoring_deduplication; 2453 size_t native_to_managed_code_bytes; 2454 size_t class_initializer_code_bytes; 2455 size_t large_initializer_code_bytes; 2456 size_t large_method_code_bytes; 2457 2458 size_t vmap_table_bytes; 2459 2460 size_t dex_instruction_bytes; 2461 2462 std::vector<ArtMethod*> method_outlier; 2463 std::vector<size_t> method_outlier_size; 2464 std::vector<double> method_outlier_expansion; 2465 std::vector<std::pair<std::string, size_t>> oat_dex_file_sizes; 2466 2467 Stats() 2468 : oat_file_bytes(0), 2469 file_bytes(0), 2470 header_bytes(0), 2471 object_bytes(0), 2472 art_field_bytes(0), 2473 art_method_bytes(0), 2474 dex_cache_arrays_bytes(0), 2475 interned_strings_bytes(0), 2476 class_table_bytes(0), 2477 bitmap_bytes(0), 2478 alignment_bytes(0), 2479 managed_code_bytes(0), 2480 managed_code_bytes_ignoring_deduplication(0), 2481 native_to_managed_code_bytes(0), 2482 class_initializer_code_bytes(0), 2483 large_initializer_code_bytes(0), 2484 large_method_code_bytes(0), 2485 vmap_table_bytes(0), 2486 dex_instruction_bytes(0) {} 2487 2488 struct SizeAndCount { 2489 SizeAndCount(size_t bytes_in, size_t count_in) : bytes(bytes_in), count(count_in) {} 2490 size_t bytes; 2491 size_t count; 2492 }; 2493 typedef SafeMap<std::string, SizeAndCount> SizeAndCountTable; 2494 SizeAndCountTable sizes_and_counts; 2495 2496 void Update(const char* descriptor, size_t object_bytes_in) { 2497 SizeAndCountTable::iterator it = sizes_and_counts.find(descriptor); 2498 if (it != sizes_and_counts.end()) { 2499 it->second.bytes += object_bytes_in; 2500 it->second.count += 1; 2501 } else { 2502 sizes_and_counts.Put(descriptor, SizeAndCount(object_bytes_in, 1)); 2503 } 2504 } 2505 2506 double PercentOfOatBytes(size_t size) { 2507 return (static_cast<double>(size) / static_cast<double>(oat_file_bytes)) * 100; 2508 } 2509 2510 double PercentOfFileBytes(size_t size) { 2511 return (static_cast<double>(size) / static_cast<double>(file_bytes)) * 100; 2512 } 2513 2514 double PercentOfObjectBytes(size_t size) { 2515 return (static_cast<double>(size) / static_cast<double>(object_bytes)) * 100; 2516 } 2517 2518 void ComputeOutliers(size_t total_size, double expansion, ArtMethod* method) { 2519 method_outlier_size.push_back(total_size); 2520 method_outlier_expansion.push_back(expansion); 2521 method_outlier.push_back(method); 2522 } 2523 2524 void DumpOutliers(std::ostream& os) 2525 REQUIRES_SHARED(Locks::mutator_lock_) { 2526 size_t sum_of_sizes = 0; 2527 size_t sum_of_sizes_squared = 0; 2528 size_t sum_of_expansion = 0; 2529 size_t sum_of_expansion_squared = 0; 2530 size_t n = method_outlier_size.size(); 2531 if (n <= 1) { 2532 return; 2533 } 2534 for (size_t i = 0; i < n; i++) { 2535 size_t cur_size = method_outlier_size[i]; 2536 sum_of_sizes += cur_size; 2537 sum_of_sizes_squared += cur_size * cur_size; 2538 double cur_expansion = method_outlier_expansion[i]; 2539 sum_of_expansion += cur_expansion; 2540 sum_of_expansion_squared += cur_expansion * cur_expansion; 2541 } 2542 size_t size_mean = sum_of_sizes / n; 2543 size_t size_variance = (sum_of_sizes_squared - sum_of_sizes * size_mean) / (n - 1); 2544 double expansion_mean = sum_of_expansion / n; 2545 double expansion_variance = 2546 (sum_of_expansion_squared - sum_of_expansion * expansion_mean) / (n - 1); 2547 2548 // Dump methods whose size is a certain number of standard deviations from the mean 2549 size_t dumped_values = 0; 2550 size_t skipped_values = 0; 2551 for (size_t i = 100; i > 0; i--) { // i is the current number of standard deviations 2552 size_t cur_size_variance = i * i * size_variance; 2553 bool first = true; 2554 for (size_t j = 0; j < n; j++) { 2555 size_t cur_size = method_outlier_size[j]; 2556 if (cur_size > size_mean) { 2557 size_t cur_var = cur_size - size_mean; 2558 cur_var = cur_var * cur_var; 2559 if (cur_var > cur_size_variance) { 2560 if (dumped_values > 20) { 2561 if (i == 1) { 2562 skipped_values++; 2563 } else { 2564 i = 2; // jump to counting for 1 standard deviation 2565 break; 2566 } 2567 } else { 2568 if (first) { 2569 os << "\nBig methods (size > " << i << " standard deviations the norm):\n"; 2570 first = false; 2571 } 2572 os << ArtMethod::PrettyMethod(method_outlier[j]) << " requires storage of " 2573 << PrettySize(cur_size) << "\n"; 2574 method_outlier_size[j] = 0; // don't consider this method again 2575 dumped_values++; 2576 } 2577 } 2578 } 2579 } 2580 } 2581 if (skipped_values > 0) { 2582 os << "... skipped " << skipped_values 2583 << " methods with size > 1 standard deviation from the norm\n"; 2584 } 2585 os << std::flush; 2586 2587 // Dump methods whose expansion is a certain number of standard deviations from the mean 2588 dumped_values = 0; 2589 skipped_values = 0; 2590 for (size_t i = 10; i > 0; i--) { // i is the current number of standard deviations 2591 double cur_expansion_variance = i * i * expansion_variance; 2592 bool first = true; 2593 for (size_t j = 0; j < n; j++) { 2594 double cur_expansion = method_outlier_expansion[j]; 2595 if (cur_expansion > expansion_mean) { 2596 size_t cur_var = cur_expansion - expansion_mean; 2597 cur_var = cur_var * cur_var; 2598 if (cur_var > cur_expansion_variance) { 2599 if (dumped_values > 20) { 2600 if (i == 1) { 2601 skipped_values++; 2602 } else { 2603 i = 2; // jump to counting for 1 standard deviation 2604 break; 2605 } 2606 } else { 2607 if (first) { 2608 os << "\nLarge expansion methods (size > " << i 2609 << " standard deviations the norm):\n"; 2610 first = false; 2611 } 2612 os << ArtMethod::PrettyMethod(method_outlier[j]) << " expanded code by " 2613 << cur_expansion << "\n"; 2614 method_outlier_expansion[j] = 0.0; // don't consider this method again 2615 dumped_values++; 2616 } 2617 } 2618 } 2619 } 2620 } 2621 if (skipped_values > 0) { 2622 os << "... skipped " << skipped_values 2623 << " methods with expansion > 1 standard deviation from the norm\n"; 2624 } 2625 os << "\n" << std::flush; 2626 } 2627 2628 void Dump(std::ostream& os, std::ostream& indent_os) 2629 REQUIRES_SHARED(Locks::mutator_lock_) { 2630 { 2631 os << "art_file_bytes = " << PrettySize(file_bytes) << "\n\n" 2632 << "art_file_bytes = header_bytes + object_bytes + alignment_bytes\n"; 2633 indent_os << StringPrintf("header_bytes = %8zd (%2.0f%% of art file bytes)\n" 2634 "object_bytes = %8zd (%2.0f%% of art file bytes)\n" 2635 "art_field_bytes = %8zd (%2.0f%% of art file bytes)\n" 2636 "art_method_bytes = %8zd (%2.0f%% of art file bytes)\n" 2637 "dex_cache_arrays_bytes = %8zd (%2.0f%% of art file bytes)\n" 2638 "interned_string_bytes = %8zd (%2.0f%% of art file bytes)\n" 2639 "class_table_bytes = %8zd (%2.0f%% of art file bytes)\n" 2640 "bitmap_bytes = %8zd (%2.0f%% of art file bytes)\n" 2641 "alignment_bytes = %8zd (%2.0f%% of art file bytes)\n\n", 2642 header_bytes, PercentOfFileBytes(header_bytes), 2643 object_bytes, PercentOfFileBytes(object_bytes), 2644 art_field_bytes, PercentOfFileBytes(art_field_bytes), 2645 art_method_bytes, PercentOfFileBytes(art_method_bytes), 2646 dex_cache_arrays_bytes, 2647 PercentOfFileBytes(dex_cache_arrays_bytes), 2648 interned_strings_bytes, 2649 PercentOfFileBytes(interned_strings_bytes), 2650 class_table_bytes, PercentOfFileBytes(class_table_bytes), 2651 bitmap_bytes, PercentOfFileBytes(bitmap_bytes), 2652 alignment_bytes, PercentOfFileBytes(alignment_bytes)) 2653 << std::flush; 2654 CHECK_EQ(file_bytes, 2655 header_bytes + object_bytes + art_field_bytes + art_method_bytes + 2656 dex_cache_arrays_bytes + interned_strings_bytes + class_table_bytes + 2657 bitmap_bytes + alignment_bytes); 2658 } 2659 2660 os << "object_bytes breakdown:\n"; 2661 size_t object_bytes_total = 0; 2662 for (const auto& sizes_and_count : sizes_and_counts) { 2663 const std::string& descriptor(sizes_and_count.first); 2664 double average = static_cast<double>(sizes_and_count.second.bytes) / 2665 static_cast<double>(sizes_and_count.second.count); 2666 double percent = PercentOfObjectBytes(sizes_and_count.second.bytes); 2667 os << StringPrintf("%32s %8zd bytes %6zd instances " 2668 "(%4.0f bytes/instance) %2.0f%% of object_bytes\n", 2669 descriptor.c_str(), sizes_and_count.second.bytes, 2670 sizes_and_count.second.count, average, percent); 2671 object_bytes_total += sizes_and_count.second.bytes; 2672 } 2673 os << "\n" << std::flush; 2674 CHECK_EQ(object_bytes, object_bytes_total); 2675 2676 os << StringPrintf("oat_file_bytes = %8zd\n" 2677 "managed_code_bytes = %8zd (%2.0f%% of oat file bytes)\n" 2678 "native_to_managed_code_bytes = %8zd (%2.0f%% of oat file bytes)\n\n" 2679 "class_initializer_code_bytes = %8zd (%2.0f%% of oat file bytes)\n" 2680 "large_initializer_code_bytes = %8zd (%2.0f%% of oat file bytes)\n" 2681 "large_method_code_bytes = %8zd (%2.0f%% of oat file bytes)\n\n", 2682 oat_file_bytes, 2683 managed_code_bytes, 2684 PercentOfOatBytes(managed_code_bytes), 2685 native_to_managed_code_bytes, 2686 PercentOfOatBytes(native_to_managed_code_bytes), 2687 class_initializer_code_bytes, 2688 PercentOfOatBytes(class_initializer_code_bytes), 2689 large_initializer_code_bytes, 2690 PercentOfOatBytes(large_initializer_code_bytes), 2691 large_method_code_bytes, 2692 PercentOfOatBytes(large_method_code_bytes)) 2693 << "DexFile sizes:\n"; 2694 for (const std::pair<std::string, size_t>& oat_dex_file_size : oat_dex_file_sizes) { 2695 os << StringPrintf("%s = %zd (%2.0f%% of oat file bytes)\n", 2696 oat_dex_file_size.first.c_str(), oat_dex_file_size.second, 2697 PercentOfOatBytes(oat_dex_file_size.second)); 2698 } 2699 2700 os << "\n" << StringPrintf("vmap_table_bytes = %7zd (%2.0f%% of oat file bytes)\n\n", 2701 vmap_table_bytes, PercentOfOatBytes(vmap_table_bytes)) 2702 << std::flush; 2703 2704 os << StringPrintf("dex_instruction_bytes = %zd\n", dex_instruction_bytes) 2705 << StringPrintf("managed_code_bytes expansion = %.2f (ignoring deduplication %.2f)\n\n", 2706 static_cast<double>(managed_code_bytes) / 2707 static_cast<double>(dex_instruction_bytes), 2708 static_cast<double>(managed_code_bytes_ignoring_deduplication) / 2709 static_cast<double>(dex_instruction_bytes)) 2710 << std::flush; 2711 2712 DumpOutliers(os); 2713 } 2714 } stats_; 2715 2716 private: 2717 enum { 2718 // Number of bytes for a constructor to be considered large. Based on the 1000 basic block 2719 // threshold, we assume 2 bytes per instruction and 2 instructions per block. 2720 kLargeConstructorDexBytes = 4000, 2721 // Number of bytes for a method to be considered large. Based on the 4000 basic block 2722 // threshold, we assume 2 bytes per instruction and 2 instructions per block. 2723 kLargeMethodDexBytes = 16000 2724 }; 2725 2726 // For performance, use the *os_ directly for anything that doesn't need indentation 2727 // and prepare an indentation stream with default indentation 1. 2728 std::ostream* os_; 2729 VariableIndentationOutputStream vios_; 2730 ScopedIndentation indent1_; 2731 2732 gc::space::ImageSpace& image_space_; 2733 const ImageHeader& image_header_; 2734 std::unique_ptr<OatDumper> oat_dumper_; 2735 OatDumperOptions* oat_dumper_options_; 2736 std::set<mirror::Object*> dex_caches_; 2737 2738 DISALLOW_COPY_AND_ASSIGN(ImageDumper); 2739 }; 2740 2741 static int DumpImage(gc::space::ImageSpace* image_space, 2742 OatDumperOptions* options, 2743 std::ostream* os) REQUIRES_SHARED(Locks::mutator_lock_) { 2744 const ImageHeader& image_header = image_space->GetImageHeader(); 2745 if (!image_header.IsValid()) { 2746 fprintf(stderr, "Invalid image header %s\n", image_space->GetImageLocation().c_str()); 2747 return EXIT_FAILURE; 2748 } 2749 ImageDumper image_dumper(os, *image_space, image_header, options); 2750 if (!image_dumper.Dump()) { 2751 return EXIT_FAILURE; 2752 } 2753 return EXIT_SUCCESS; 2754 } 2755 2756 static int DumpImages(Runtime* runtime, OatDumperOptions* options, std::ostream* os) { 2757 // Dumping the image, no explicit class loader. 2758 ScopedNullHandle<mirror::ClassLoader> null_class_loader; 2759 options->class_loader_ = &null_class_loader; 2760 2761 ScopedObjectAccess soa(Thread::Current()); 2762 if (options->app_image_ != nullptr) { 2763 if (options->app_oat_ == nullptr) { 2764 LOG(ERROR) << "Can not dump app image without app oat file"; 2765 return EXIT_FAILURE; 2766 } 2767 // We can't know if the app image is 32 bits yet, but it contains pointers into the oat file. 2768 // We need to map the oat file in the low 4gb or else the fixup wont be able to fit oat file 2769 // pointers into 32 bit pointer sized ArtMethods. 2770 std::string error_msg; 2771 std::unique_ptr<OatFile> oat_file(OatFile::Open(options->app_oat_, 2772 options->app_oat_, 2773 nullptr, 2774 nullptr, 2775 false, 2776 /*low_4gb*/true, 2777 nullptr, 2778 &error_msg)); 2779 if (oat_file == nullptr) { 2780 LOG(ERROR) << "Failed to open oat file " << options->app_oat_ << " with error " << error_msg; 2781 return EXIT_FAILURE; 2782 } 2783 std::unique_ptr<gc::space::ImageSpace> space( 2784 gc::space::ImageSpace::CreateFromAppImage(options->app_image_, oat_file.get(), &error_msg)); 2785 if (space == nullptr) { 2786 LOG(ERROR) << "Failed to open app image " << options->app_image_ << " with error " 2787 << error_msg; 2788 } 2789 // Open dex files for the image. 2790 std::vector<std::unique_ptr<const DexFile>> dex_files; 2791 if (!runtime->GetClassLinker()->OpenImageDexFiles(space.get(), &dex_files, &error_msg)) { 2792 LOG(ERROR) << "Failed to open app image dex files " << options->app_image_ << " with error " 2793 << error_msg; 2794 } 2795 // Dump the actual image. 2796 int result = DumpImage(space.get(), options, os); 2797 if (result != EXIT_SUCCESS) { 2798 return result; 2799 } 2800 // Fall through to dump the boot images. 2801 } 2802 2803 gc::Heap* heap = runtime->GetHeap(); 2804 CHECK(heap->HasBootImageSpace()) << "No image spaces"; 2805 for (gc::space::ImageSpace* image_space : heap->GetBootImageSpaces()) { 2806 int result = DumpImage(image_space, options, os); 2807 if (result != EXIT_SUCCESS) { 2808 return result; 2809 } 2810 } 2811 return EXIT_SUCCESS; 2812 } 2813 2814 static jobject InstallOatFile(Runtime* runtime, 2815 std::unique_ptr<OatFile> oat_file, 2816 std::vector<const DexFile*>* class_path) 2817 REQUIRES_SHARED(Locks::mutator_lock_) { 2818 Thread* self = Thread::Current(); 2819 CHECK(self != nullptr); 2820 // Need well-known-classes. 2821 WellKnownClasses::Init(self->GetJniEnv()); 2822 2823 // Need to register dex files to get a working dex cache. 2824 OatFile* oat_file_ptr = oat_file.get(); 2825 ClassLinker* class_linker = runtime->GetClassLinker(); 2826 runtime->GetOatFileManager().RegisterOatFile(std::move(oat_file)); 2827 for (const OatFile::OatDexFile* odf : oat_file_ptr->GetOatDexFiles()) { 2828 std::string error_msg; 2829 const DexFile* const dex_file = OpenDexFile(odf, &error_msg); 2830 CHECK(dex_file != nullptr) << error_msg; 2831 ObjPtr<mirror::DexCache> dex_cache = 2832 class_linker->RegisterDexFile(*dex_file, nullptr); 2833 CHECK(dex_cache != nullptr); 2834 class_path->push_back(dex_file); 2835 } 2836 2837 // Need a class loader. Fake that we're a compiler. 2838 // Note: this will run initializers through the unstarted runtime, so make sure it's 2839 // initialized. 2840 interpreter::UnstartedRuntime::Initialize(); 2841 2842 jobject class_loader = class_linker->CreatePathClassLoader(self, *class_path); 2843 2844 return class_loader; 2845 } 2846 2847 static int DumpOatWithRuntime(Runtime* runtime, 2848 std::unique_ptr<OatFile> oat_file, 2849 OatDumperOptions* options, 2850 std::ostream* os) { 2851 CHECK(runtime != nullptr && oat_file != nullptr && options != nullptr); 2852 ScopedObjectAccess soa(Thread::Current()); 2853 2854 OatFile* oat_file_ptr = oat_file.get(); 2855 std::vector<const DexFile*> class_path; 2856 jobject class_loader = InstallOatFile(runtime, std::move(oat_file), &class_path); 2857 2858 // Use the class loader while dumping. 2859 StackHandleScope<1> scope(soa.Self()); 2860 Handle<mirror::ClassLoader> loader_handle = scope.NewHandle( 2861 soa.Decode<mirror::ClassLoader>(class_loader)); 2862 options->class_loader_ = &loader_handle; 2863 2864 OatDumper oat_dumper(*oat_file_ptr, *options); 2865 bool success = oat_dumper.Dump(*os); 2866 return (success) ? EXIT_SUCCESS : EXIT_FAILURE; 2867 } 2868 2869 static int DumpOatWithoutRuntime(OatFile* oat_file, OatDumperOptions* options, std::ostream* os) { 2870 CHECK(oat_file != nullptr && options != nullptr); 2871 // No image = no class loader. 2872 ScopedNullHandle<mirror::ClassLoader> null_class_loader; 2873 options->class_loader_ = &null_class_loader; 2874 2875 OatDumper oat_dumper(*oat_file, *options); 2876 bool success = oat_dumper.Dump(*os); 2877 return (success) ? EXIT_SUCCESS : EXIT_FAILURE; 2878 } 2879 2880 static int DumpOat(Runtime* runtime, const char* oat_filename, OatDumperOptions* options, 2881 std::ostream* os) { 2882 std::string error_msg; 2883 std::unique_ptr<OatFile> oat_file(OatFile::Open(oat_filename, 2884 oat_filename, 2885 nullptr, 2886 nullptr, 2887 false, 2888 /*low_4gb*/false, 2889 nullptr, 2890 &error_msg)); 2891 if (oat_file == nullptr) { 2892 fprintf(stderr, "Failed to open oat file from '%s': %s\n", oat_filename, error_msg.c_str()); 2893 return EXIT_FAILURE; 2894 } 2895 2896 if (runtime != nullptr) { 2897 return DumpOatWithRuntime(runtime, std::move(oat_file), options, os); 2898 } else { 2899 return DumpOatWithoutRuntime(oat_file.get(), options, os); 2900 } 2901 } 2902 2903 static int SymbolizeOat(const char* oat_filename, std::string& output_name, bool no_bits) { 2904 std::string error_msg; 2905 std::unique_ptr<OatFile> oat_file(OatFile::Open(oat_filename, 2906 oat_filename, 2907 nullptr, 2908 nullptr, 2909 false, 2910 /*low_4gb*/false, 2911 nullptr, 2912 &error_msg)); 2913 if (oat_file == nullptr) { 2914 fprintf(stderr, "Failed to open oat file from '%s': %s\n", oat_filename, error_msg.c_str()); 2915 return EXIT_FAILURE; 2916 } 2917 2918 bool result; 2919 // Try to produce an ELF file of the same type. This is finicky, as we have used 32-bit ELF 2920 // files for 64-bit code in the past. 2921 if (Is64BitInstructionSet(oat_file->GetOatHeader().GetInstructionSet())) { 2922 OatSymbolizer<ElfTypes64> oat_symbolizer(oat_file.get(), output_name, no_bits); 2923 result = oat_symbolizer.Symbolize(); 2924 } else { 2925 OatSymbolizer<ElfTypes32> oat_symbolizer(oat_file.get(), output_name, no_bits); 2926 result = oat_symbolizer.Symbolize(); 2927 } 2928 if (!result) { 2929 fprintf(stderr, "Failed to symbolize\n"); 2930 return EXIT_FAILURE; 2931 } 2932 2933 return EXIT_SUCCESS; 2934 } 2935 2936 class IMTDumper { 2937 public: 2938 static bool Dump(Runtime* runtime, 2939 const std::string& imt_file, 2940 bool dump_imt_stats, 2941 const char* oat_filename) { 2942 Thread* self = Thread::Current(); 2943 2944 ScopedObjectAccess soa(self); 2945 StackHandleScope<1> scope(self); 2946 MutableHandle<mirror::ClassLoader> class_loader = scope.NewHandle<mirror::ClassLoader>(nullptr); 2947 std::vector<const DexFile*> class_path; 2948 2949 if (oat_filename != nullptr) { 2950 std::string error_msg; 2951 std::unique_ptr<OatFile> oat_file(OatFile::Open(oat_filename, 2952 oat_filename, 2953 nullptr, 2954 nullptr, 2955 false, 2956 /*low_4gb*/false, 2957 nullptr, 2958 &error_msg)); 2959 if (oat_file == nullptr) { 2960 fprintf(stderr, "Failed to open oat file from '%s': %s\n", oat_filename, error_msg.c_str()); 2961 return false; 2962 } 2963 2964 class_loader.Assign(soa.Decode<mirror::ClassLoader>( 2965 InstallOatFile(runtime, std::move(oat_file), &class_path))); 2966 } else { 2967 class_loader.Assign(nullptr); // Boot classloader. Just here for explicit documentation. 2968 class_path = runtime->GetClassLinker()->GetBootClassPath(); 2969 } 2970 2971 if (!imt_file.empty()) { 2972 return DumpImt(runtime, imt_file, class_loader); 2973 } 2974 2975 if (dump_imt_stats) { 2976 return DumpImtStats(runtime, class_path, class_loader); 2977 } 2978 2979 LOG(FATAL) << "Should not reach here"; 2980 UNREACHABLE(); 2981 } 2982 2983 private: 2984 static bool DumpImt(Runtime* runtime, 2985 const std::string& imt_file, 2986 Handle<mirror::ClassLoader> h_class_loader) 2987 REQUIRES_SHARED(Locks::mutator_lock_) { 2988 std::vector<std::string> lines = ReadCommentedInputFromFile(imt_file); 2989 std::unordered_set<std::string> prepared; 2990 2991 for (const std::string& line : lines) { 2992 // A line should be either a class descriptor, in which case we will dump the complete IMT, 2993 // or a class descriptor and an interface method, in which case we will lookup the method, 2994 // determine its IMT slot, and check the class' IMT. 2995 size_t first_space = line.find(' '); 2996 if (first_space == std::string::npos) { 2997 DumpIMTForClass(runtime, line, h_class_loader, &prepared); 2998 } else { 2999 DumpIMTForMethod(runtime, 3000 line.substr(0, first_space), 3001 line.substr(first_space + 1, std::string::npos), 3002 h_class_loader, 3003 &prepared); 3004 } 3005 std::cerr << std::endl; 3006 } 3007 3008 return true; 3009 } 3010 3011 static bool DumpImtStats(Runtime* runtime, 3012 const std::vector<const DexFile*>& dex_files, 3013 Handle<mirror::ClassLoader> h_class_loader) 3014 REQUIRES_SHARED(Locks::mutator_lock_) { 3015 size_t without_imt = 0; 3016 size_t with_imt = 0; 3017 std::map<size_t, size_t> histogram; 3018 3019 ClassLinker* class_linker = runtime->GetClassLinker(); 3020 const PointerSize pointer_size = class_linker->GetImagePointerSize(); 3021 std::unordered_set<std::string> prepared; 3022 3023 Thread* self = Thread::Current(); 3024 StackHandleScope<1> scope(self); 3025 MutableHandle<mirror::Class> h_klass(scope.NewHandle<mirror::Class>(nullptr)); 3026 3027 for (const DexFile* dex_file : dex_files) { 3028 for (uint32_t class_def_index = 0; 3029 class_def_index != dex_file->NumClassDefs(); 3030 ++class_def_index) { 3031 const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index); 3032 const char* descriptor = dex_file->GetClassDescriptor(class_def); 3033 h_klass.Assign(class_linker->FindClass(self, descriptor, h_class_loader)); 3034 if (h_klass == nullptr) { 3035 std::cerr << "Warning: could not load " << descriptor << std::endl; 3036 continue; 3037 } 3038 3039 if (HasNoIMT(runtime, h_klass, pointer_size, &prepared)) { 3040 without_imt++; 3041 continue; 3042 } 3043 3044 ImTable* im_table = PrepareAndGetImTable(runtime, h_klass, pointer_size, &prepared); 3045 if (im_table == nullptr) { 3046 // Should not happen, but accept. 3047 without_imt++; 3048 continue; 3049 } 3050 3051 with_imt++; 3052 for (size_t imt_index = 0; imt_index != ImTable::kSize; ++imt_index) { 3053 ArtMethod* ptr = im_table->Get(imt_index, pointer_size); 3054 if (ptr->IsRuntimeMethod()) { 3055 if (ptr->IsImtUnimplementedMethod()) { 3056 histogram[0]++; 3057 } else { 3058 ImtConflictTable* current_table = ptr->GetImtConflictTable(pointer_size); 3059 histogram[current_table->NumEntries(pointer_size)]++; 3060 } 3061 } else { 3062 histogram[1]++; 3063 } 3064 } 3065 } 3066 } 3067 3068 std::cerr << "IMT stats:" 3069 << std::endl << std::endl; 3070 3071 std::cerr << " " << with_imt << " classes with IMT." 3072 << std::endl << std::endl; 3073 std::cerr << " " << without_imt << " classes without IMT (or copy from Object)." 3074 << std::endl << std::endl; 3075 3076 double sum_one = 0; 3077 size_t count_one = 0; 3078 3079 std::cerr << " " << "IMT histogram" << std::endl; 3080 for (auto& bucket : histogram) { 3081 std::cerr << " " << bucket.first << " " << bucket.second << std::endl; 3082 if (bucket.first > 0) { 3083 sum_one += bucket.second * bucket.first; 3084 count_one += bucket.second; 3085 } 3086 } 3087 3088 double count_zero = count_one + histogram[0]; 3089 std::cerr << " Stats:" << std::endl; 3090 std::cerr << " Average depth (including empty): " << (sum_one / count_zero) << std::endl; 3091 std::cerr << " Average depth (excluding empty): " << (sum_one / count_one) << std::endl; 3092 3093 return true; 3094 } 3095 3096 // Return whether the given class has no IMT (or the one shared with java.lang.Object). 3097 static bool HasNoIMT(Runtime* runtime, 3098 Handle<mirror::Class> klass, 3099 const PointerSize pointer_size, 3100 std::unordered_set<std::string>* prepared) 3101 REQUIRES_SHARED(Locks::mutator_lock_) { 3102 if (klass->IsObjectClass() || !klass->ShouldHaveImt()) { 3103 return true; 3104 } 3105 3106 if (klass->GetImt(pointer_size) == nullptr) { 3107 PrepareClass(runtime, klass, prepared); 3108 } 3109 3110 mirror::Class* object_class = mirror::Class::GetJavaLangClass()->GetSuperClass(); 3111 DCHECK(object_class->IsObjectClass()); 3112 3113 bool result = klass->GetImt(pointer_size) == object_class->GetImt(pointer_size); 3114 3115 if (klass->GetIfTable()->Count() == 0) { 3116 DCHECK(result); 3117 } 3118 3119 return result; 3120 } 3121 3122 static void PrintTable(ImtConflictTable* table, PointerSize pointer_size) 3123 REQUIRES_SHARED(Locks::mutator_lock_) { 3124 if (table == nullptr) { 3125 std::cerr << " <No IMT?>" << std::endl; 3126 return; 3127 } 3128 size_t table_index = 0; 3129 for (;;) { 3130 ArtMethod* ptr = table->GetInterfaceMethod(table_index, pointer_size); 3131 if (ptr == nullptr) { 3132 return; 3133 } 3134 table_index++; 3135 std::cerr << " " << ptr->PrettyMethod(true) << std::endl; 3136 } 3137 } 3138 3139 static ImTable* PrepareAndGetImTable(Runtime* runtime, 3140 Thread* self, 3141 Handle<mirror::ClassLoader> h_loader, 3142 const std::string& class_name, 3143 const PointerSize pointer_size, 3144 mirror::Class** klass_out, 3145 std::unordered_set<std::string>* prepared) 3146 REQUIRES_SHARED(Locks::mutator_lock_) { 3147 if (class_name.empty()) { 3148 return nullptr; 3149 } 3150 3151 std::string descriptor; 3152 if (class_name[0] == 'L') { 3153 descriptor = class_name; 3154 } else { 3155 descriptor = DotToDescriptor(class_name.c_str()); 3156 } 3157 3158 mirror::Class* klass = runtime->GetClassLinker()->FindClass(self, descriptor.c_str(), h_loader); 3159 3160 if (klass == nullptr) { 3161 self->ClearException(); 3162 std::cerr << "Did not find " << class_name << std::endl; 3163 *klass_out = nullptr; 3164 return nullptr; 3165 } 3166 3167 StackHandleScope<1> scope(Thread::Current()); 3168 Handle<mirror::Class> h_klass = scope.NewHandle<mirror::Class>(klass); 3169 3170 ImTable* ret = PrepareAndGetImTable(runtime, h_klass, pointer_size, prepared); 3171 *klass_out = h_klass.Get(); 3172 return ret; 3173 } 3174 3175 static ImTable* PrepareAndGetImTable(Runtime* runtime, 3176 Handle<mirror::Class> h_klass, 3177 const PointerSize pointer_size, 3178 std::unordered_set<std::string>* prepared) 3179 REQUIRES_SHARED(Locks::mutator_lock_) { 3180 PrepareClass(runtime, h_klass, prepared); 3181 return h_klass->GetImt(pointer_size); 3182 } 3183 3184 static void DumpIMTForClass(Runtime* runtime, 3185 const std::string& class_name, 3186 Handle<mirror::ClassLoader> h_loader, 3187 std::unordered_set<std::string>* prepared) 3188 REQUIRES_SHARED(Locks::mutator_lock_) { 3189 const PointerSize pointer_size = runtime->GetClassLinker()->GetImagePointerSize(); 3190 mirror::Class* klass; 3191 ImTable* imt = PrepareAndGetImTable(runtime, 3192 Thread::Current(), 3193 h_loader, 3194 class_name, 3195 pointer_size, 3196 &klass, 3197 prepared); 3198 if (imt == nullptr) { 3199 return; 3200 } 3201 3202 std::cerr << class_name << std::endl << " IMT:" << std::endl; 3203 for (size_t index = 0; index < ImTable::kSize; ++index) { 3204 std::cerr << " " << index << ":" << std::endl; 3205 ArtMethod* ptr = imt->Get(index, pointer_size); 3206 if (ptr->IsRuntimeMethod()) { 3207 if (ptr->IsImtUnimplementedMethod()) { 3208 std::cerr << " <empty>" << std::endl; 3209 } else { 3210 ImtConflictTable* current_table = ptr->GetImtConflictTable(pointer_size); 3211 PrintTable(current_table, pointer_size); 3212 } 3213 } else { 3214 std::cerr << " " << ptr->PrettyMethod(true) << std::endl; 3215 } 3216 } 3217 3218 std::cerr << " Interfaces:" << std::endl; 3219 // Run through iftable, find methods that slot here, see if they fit. 3220 mirror::IfTable* if_table = klass->GetIfTable(); 3221 for (size_t i = 0, num_interfaces = klass->GetIfTableCount(); i < num_interfaces; ++i) { 3222 mirror::Class* iface = if_table->GetInterface(i); 3223 std::string iface_name; 3224 std::cerr << " " << iface->GetDescriptor(&iface_name) << std::endl; 3225 3226 for (ArtMethod& iface_method : iface->GetVirtualMethods(pointer_size)) { 3227 uint32_t class_hash, name_hash, signature_hash; 3228 ImTable::GetImtHashComponents(&iface_method, &class_hash, &name_hash, &signature_hash); 3229 uint32_t imt_slot = ImTable::GetImtIndex(&iface_method); 3230 std::cerr << " " << iface_method.PrettyMethod(true) 3231 << " slot=" << imt_slot 3232 << std::hex 3233 << " class_hash=0x" << class_hash 3234 << " name_hash=0x" << name_hash 3235 << " signature_hash=0x" << signature_hash 3236 << std::dec 3237 << std::endl; 3238 } 3239 } 3240 } 3241 3242 static void DumpIMTForMethod(Runtime* runtime, 3243 const std::string& class_name, 3244 const std::string& method, 3245 Handle<mirror::ClassLoader> h_loader, 3246 std::unordered_set<std::string>* prepared) 3247 REQUIRES_SHARED(Locks::mutator_lock_) { 3248 const PointerSize pointer_size = runtime->GetClassLinker()->GetImagePointerSize(); 3249 mirror::Class* klass; 3250 ImTable* imt = PrepareAndGetImTable(runtime, 3251 Thread::Current(), 3252 h_loader, 3253 class_name, 3254 pointer_size, 3255 &klass, 3256 prepared); 3257 if (imt == nullptr) { 3258 return; 3259 } 3260 3261 std::cerr << class_name << " <" << method << ">" << std::endl; 3262 for (size_t index = 0; index < ImTable::kSize; ++index) { 3263 ArtMethod* ptr = imt->Get(index, pointer_size); 3264 if (ptr->IsRuntimeMethod()) { 3265 if (ptr->IsImtUnimplementedMethod()) { 3266 continue; 3267 } 3268 3269 ImtConflictTable* current_table = ptr->GetImtConflictTable(pointer_size); 3270 if (current_table == nullptr) { 3271 continue; 3272 } 3273 3274 size_t table_index = 0; 3275 for (;;) { 3276 ArtMethod* ptr2 = current_table->GetInterfaceMethod(table_index, pointer_size); 3277 if (ptr2 == nullptr) { 3278 break; 3279 } 3280 table_index++; 3281 3282 std::string p_name = ptr2->PrettyMethod(true); 3283 if (android::base::StartsWith(p_name, method.c_str())) { 3284 std::cerr << " Slot " 3285 << index 3286 << " (" 3287 << current_table->NumEntries(pointer_size) 3288 << ")" 3289 << std::endl; 3290 PrintTable(current_table, pointer_size); 3291 return; 3292 } 3293 } 3294 } else { 3295 std::string p_name = ptr->PrettyMethod(true); 3296 if (android::base::StartsWith(p_name, method.c_str())) { 3297 std::cerr << " Slot " << index << " (1)" << std::endl; 3298 std::cerr << " " << p_name << std::endl; 3299 } else { 3300 // Run through iftable, find methods that slot here, see if they fit. 3301 mirror::IfTable* if_table = klass->GetIfTable(); 3302 for (size_t i = 0, num_interfaces = klass->GetIfTableCount(); i < num_interfaces; ++i) { 3303 mirror::Class* iface = if_table->GetInterface(i); 3304 size_t num_methods = iface->NumDeclaredVirtualMethods(); 3305 if (num_methods > 0) { 3306 for (ArtMethod& iface_method : iface->GetMethods(pointer_size)) { 3307 if (ImTable::GetImtIndex(&iface_method) == index) { 3308 std::string i_name = iface_method.PrettyMethod(true); 3309 if (android::base::StartsWith(i_name, method.c_str())) { 3310 std::cerr << " Slot " << index << " (1)" << std::endl; 3311 std::cerr << " " << p_name << " (" << i_name << ")" << std::endl; 3312 } 3313 } 3314 } 3315 } 3316 } 3317 } 3318 } 3319 } 3320 } 3321 3322 // Read lines from the given stream, dropping comments and empty lines 3323 static std::vector<std::string> ReadCommentedInputStream(std::istream& in_stream) { 3324 std::vector<std::string> output; 3325 while (in_stream.good()) { 3326 std::string dot; 3327 std::getline(in_stream, dot); 3328 if (android::base::StartsWith(dot, "#") || dot.empty()) { 3329 continue; 3330 } 3331 output.push_back(dot); 3332 } 3333 return output; 3334 } 3335 3336 // Read lines from the given file, dropping comments and empty lines. 3337 static std::vector<std::string> ReadCommentedInputFromFile(const std::string& input_filename) { 3338 std::unique_ptr<std::ifstream> input_file(new std::ifstream(input_filename, std::ifstream::in)); 3339 if (input_file.get() == nullptr) { 3340 LOG(ERROR) << "Failed to open input file " << input_filename; 3341 return std::vector<std::string>(); 3342 } 3343 std::vector<std::string> result = ReadCommentedInputStream(*input_file); 3344 input_file->close(); 3345 return result; 3346 } 3347 3348 // Prepare a class, i.e., ensure it has a filled IMT. Will do so recursively for superclasses, 3349 // and note in the given set that the work was done. 3350 static void PrepareClass(Runtime* runtime, 3351 Handle<mirror::Class> h_klass, 3352 std::unordered_set<std::string>* done) 3353 REQUIRES_SHARED(Locks::mutator_lock_) { 3354 if (!h_klass->ShouldHaveImt()) { 3355 return; 3356 } 3357 3358 std::string name; 3359 name = h_klass->GetDescriptor(&name); 3360 3361 if (done->find(name) != done->end()) { 3362 return; 3363 } 3364 done->insert(name); 3365 3366 if (h_klass->HasSuperClass()) { 3367 StackHandleScope<1> h(Thread::Current()); 3368 PrepareClass(runtime, h.NewHandle<mirror::Class>(h_klass->GetSuperClass()), done); 3369 } 3370 3371 if (!h_klass->IsTemp()) { 3372 runtime->GetClassLinker()->FillIMTAndConflictTables(h_klass.Get()); 3373 } 3374 } 3375 }; 3376 3377 struct OatdumpArgs : public CmdlineArgs { 3378 protected: 3379 using Base = CmdlineArgs; 3380 3381 virtual ParseStatus ParseCustom(const StringPiece& option, 3382 std::string* error_msg) OVERRIDE { 3383 { 3384 ParseStatus base_parse = Base::ParseCustom(option, error_msg); 3385 if (base_parse != kParseUnknownArgument) { 3386 return base_parse; 3387 } 3388 } 3389 3390 if (option.starts_with("--oat-file=")) { 3391 oat_filename_ = option.substr(strlen("--oat-file=")).data(); 3392 } else if (option.starts_with("--image=")) { 3393 image_location_ = option.substr(strlen("--image=")).data(); 3394 } else if (option == "--no-dump:vmap") { 3395 dump_vmap_ = false; 3396 } else if (option =="--dump:code_info_stack_maps") { 3397 dump_code_info_stack_maps_ = true; 3398 } else if (option == "--no-disassemble") { 3399 disassemble_code_ = false; 3400 } else if (option =="--header-only") { 3401 dump_header_only_ = true; 3402 } else if (option.starts_with("--symbolize=")) { 3403 oat_filename_ = option.substr(strlen("--symbolize=")).data(); 3404 symbolize_ = true; 3405 } else if (option.starts_with("--only-keep-debug")) { 3406 only_keep_debug_ = true; 3407 } else if (option.starts_with("--class-filter=")) { 3408 class_filter_ = option.substr(strlen("--class-filter=")).data(); 3409 } else if (option.starts_with("--method-filter=")) { 3410 method_filter_ = option.substr(strlen("--method-filter=")).data(); 3411 } else if (option.starts_with("--list-classes")) { 3412 list_classes_ = true; 3413 } else if (option.starts_with("--list-methods")) { 3414 list_methods_ = true; 3415 } else if (option.starts_with("--export-dex-to=")) { 3416 export_dex_location_ = option.substr(strlen("--export-dex-to=")).data(); 3417 } else if (option.starts_with("--addr2instr=")) { 3418 if (!ParseUint(option.substr(strlen("--addr2instr=")).data(), &addr2instr_)) { 3419 *error_msg = "Address conversion failed"; 3420 return kParseError; 3421 } 3422 } else if (option.starts_with("--app-image=")) { 3423 app_image_ = option.substr(strlen("--app-image=")).data(); 3424 } else if (option.starts_with("--app-oat=")) { 3425 app_oat_ = option.substr(strlen("--app-oat=")).data(); 3426 } else if (option.starts_with("--dump-imt=")) { 3427 imt_dump_ = option.substr(strlen("--dump-imt=")).data(); 3428 } else if (option == "--dump-imt-stats") { 3429 imt_stat_dump_ = true; 3430 } else { 3431 return kParseUnknownArgument; 3432 } 3433 3434 return kParseOk; 3435 } 3436 3437 virtual ParseStatus ParseChecks(std::string* error_msg) OVERRIDE { 3438 // Infer boot image location from the image location if possible. 3439 if (boot_image_location_ == nullptr) { 3440 boot_image_location_ = image_location_; 3441 } 3442 3443 // Perform the parent checks. 3444 ParseStatus parent_checks = Base::ParseChecks(error_msg); 3445 if (parent_checks != kParseOk) { 3446 return parent_checks; 3447 } 3448 3449 // Perform our own checks. 3450 if (image_location_ == nullptr && oat_filename_ == nullptr) { 3451 *error_msg = "Either --image or --oat-file must be specified"; 3452 return kParseError; 3453 } else if (image_location_ != nullptr && oat_filename_ != nullptr) { 3454 *error_msg = "Either --image or --oat-file must be specified but not both"; 3455 return kParseError; 3456 } 3457 3458 return kParseOk; 3459 } 3460 3461 virtual std::string GetUsage() const { 3462 std::string usage; 3463 3464 usage += 3465 "Usage: oatdump [options] ...\n" 3466 " Example: oatdump --image=$ANDROID_PRODUCT_OUT/system/framework/boot.art\n" 3467 " Example: adb shell oatdump --image=/system/framework/boot.art\n" 3468 "\n" 3469 // Either oat-file or image is required. 3470 " --oat-file=<file.oat>: specifies an input oat filename.\n" 3471 " Example: --oat-file=/system/framework/boot.oat\n" 3472 "\n" 3473 " --image=<file.art>: specifies an input image location.\n" 3474 " Example: --image=/system/framework/boot.art\n" 3475 "\n" 3476 " --app-image=<file.art>: specifies an input app image. Must also have a specified\n" 3477 " boot image (with --image) and app oat file (with --app-oat).\n" 3478 " Example: --app-image=app.art\n" 3479 "\n" 3480 " --app-oat=<file.odex>: specifies an input app oat.\n" 3481 " Example: --app-oat=app.odex\n" 3482 "\n"; 3483 3484 usage += Base::GetUsage(); 3485 3486 usage += // Optional. 3487 " --no-dump:vmap may be used to disable vmap dumping.\n" 3488 " Example: --no-dump:vmap\n" 3489 "\n" 3490 " --dump:code_info_stack_maps enables dumping of stack maps in CodeInfo sections.\n" 3491 " Example: --dump:code_info_stack_maps\n" 3492 "\n" 3493 " --no-disassemble may be used to disable disassembly.\n" 3494 " Example: --no-disassemble\n" 3495 "\n" 3496 " --header-only may be used to print only the oat header.\n" 3497 " Example: --header-only\n" 3498 "\n" 3499 " --list-classes may be used to list target file classes (can be used with filters).\n" 3500 " Example: --list-classes\n" 3501 " Example: --list-classes --class-filter=com.example.foo\n" 3502 "\n" 3503 " --list-methods may be used to list target file methods (can be used with filters).\n" 3504 " Example: --list-methods\n" 3505 " Example: --list-methods --class-filter=com.example --method-filter=foo\n" 3506 "\n" 3507 " --symbolize=<file.oat>: output a copy of file.oat with elf symbols included.\n" 3508 " Example: --symbolize=/system/framework/boot.oat\n" 3509 "\n" 3510 " --only-keep-debug<file.oat>: Modifies the behaviour of --symbolize so that\n" 3511 " .rodata and .text sections are omitted in the output file to save space.\n" 3512 " Example: --symbolize=/system/framework/boot.oat --only-keep-debug\n" 3513 "\n" 3514 " --class-filter=<class name>: only dumps classes that contain the filter.\n" 3515 " Example: --class-filter=com.example.foo\n" 3516 "\n" 3517 " --method-filter=<method name>: only dumps methods that contain the filter.\n" 3518 " Example: --method-filter=foo\n" 3519 "\n" 3520 " --export-dex-to=<directory>: may be used to export oat embedded dex files.\n" 3521 " Example: --export-dex-to=/data/local/tmp\n" 3522 "\n" 3523 " --addr2instr=<address>: output matching method disassembled code from relative\n" 3524 " address (e.g. PC from crash dump)\n" 3525 " Example: --addr2instr=0x00001a3b\n" 3526 "\n" 3527 " --dump-imt=<file.txt>: output IMT collisions (if any) for the given receiver\n" 3528 " types and interface methods in the given file. The file\n" 3529 " is read line-wise, where each line should either be a class\n" 3530 " name or descriptor, or a class name/descriptor and a prefix\n" 3531 " of a complete method name (separated by a whitespace).\n" 3532 " Example: --dump-imt=imt.txt\n" 3533 "\n" 3534 " --dump-imt-stats: output IMT statistics for the given boot image\n" 3535 " Example: --dump-imt-stats" 3536 "\n"; 3537 3538 return usage; 3539 } 3540 3541 public: 3542 const char* oat_filename_ = nullptr; 3543 const char* class_filter_ = ""; 3544 const char* method_filter_ = ""; 3545 const char* image_location_ = nullptr; 3546 std::string elf_filename_prefix_; 3547 std::string imt_dump_; 3548 bool dump_vmap_ = true; 3549 bool dump_code_info_stack_maps_ = false; 3550 bool disassemble_code_ = true; 3551 bool symbolize_ = false; 3552 bool only_keep_debug_ = false; 3553 bool list_classes_ = false; 3554 bool list_methods_ = false; 3555 bool dump_header_only_ = false; 3556 bool imt_stat_dump_ = false; 3557 uint32_t addr2instr_ = 0; 3558 const char* export_dex_location_ = nullptr; 3559 const char* app_image_ = nullptr; 3560 const char* app_oat_ = nullptr; 3561 }; 3562 3563 struct OatdumpMain : public CmdlineMain<OatdumpArgs> { 3564 virtual bool NeedsRuntime() OVERRIDE { 3565 CHECK(args_ != nullptr); 3566 3567 // If we are only doing the oat file, disable absolute_addresses. Keep them for image dumping. 3568 bool absolute_addresses = (args_->oat_filename_ == nullptr); 3569 3570 oat_dumper_options_.reset(new OatDumperOptions( 3571 args_->dump_vmap_, 3572 args_->dump_code_info_stack_maps_, 3573 args_->disassemble_code_, 3574 absolute_addresses, 3575 args_->class_filter_, 3576 args_->method_filter_, 3577 args_->list_classes_, 3578 args_->list_methods_, 3579 args_->dump_header_only_, 3580 args_->export_dex_location_, 3581 args_->app_image_, 3582 args_->app_oat_, 3583 args_->addr2instr_)); 3584 3585 return (args_->boot_image_location_ != nullptr || 3586 args_->image_location_ != nullptr || 3587 !args_->imt_dump_.empty()) && 3588 !args_->symbolize_; 3589 } 3590 3591 virtual bool ExecuteWithoutRuntime() OVERRIDE { 3592 CHECK(args_ != nullptr); 3593 CHECK(args_->oat_filename_ != nullptr); 3594 3595 MemMap::Init(); 3596 3597 if (args_->symbolize_) { 3598 // ELF has special kind of section called SHT_NOBITS which allows us to create 3599 // sections which exist but their data is omitted from the ELF file to save space. 3600 // This is what "strip --only-keep-debug" does when it creates separate ELF file 3601 // with only debug data. We use it in similar way to exclude .rodata and .text. 3602 bool no_bits = args_->only_keep_debug_; 3603 return SymbolizeOat(args_->oat_filename_, args_->output_name_, no_bits) == EXIT_SUCCESS; 3604 } else { 3605 return DumpOat(nullptr, 3606 args_->oat_filename_, 3607 oat_dumper_options_.get(), 3608 args_->os_) == EXIT_SUCCESS; 3609 } 3610 } 3611 3612 virtual bool ExecuteWithRuntime(Runtime* runtime) { 3613 CHECK(args_ != nullptr); 3614 3615 if (!args_->imt_dump_.empty() || args_->imt_stat_dump_) { 3616 return IMTDumper::Dump(runtime, 3617 args_->imt_dump_, 3618 args_->imt_stat_dump_, 3619 args_->oat_filename_); 3620 } 3621 3622 if (args_->oat_filename_ != nullptr) { 3623 return DumpOat(runtime, 3624 args_->oat_filename_, 3625 oat_dumper_options_.get(), 3626 args_->os_) == EXIT_SUCCESS; 3627 } 3628 3629 return DumpImages(runtime, oat_dumper_options_.get(), args_->os_) == EXIT_SUCCESS; 3630 } 3631 3632 std::unique_ptr<OatDumperOptions> oat_dumper_options_; 3633 }; 3634 3635 } // namespace art 3636 3637 int main(int argc, char** argv) { 3638 art::OatdumpMain main; 3639 return main.Main(argc, argv); 3640 } 3641