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