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