diff options
author | 2016-03-08 16:49:58 -0800 | |
---|---|---|
committer | 2016-03-14 15:41:49 -0700 | |
commit | bcb6a72569a1401b36a3ad3b6aa4d13e29966cf0 (patch) | |
tree | 75f7f56b3d158b14f20cfc30e30fb3e48ed9327f | |
parent | 3a1b33df0df7db2b8685f8616b9240accd6a23c5 (diff) |
Add oatdump support for app images
Example usage on host:
oatdumpd --app-oat=art/plus32.odex --app-image=art/plus32.art
--image=art/oats/system@framework@boot.art --instruction-set=arm
TODO: Add to oatdump test.
Bug: 27408512
Bug: 22858531
Change-Id: I320db8b76c780c6eadabcb45ce88f45950741484
-rw-r--r-- | compiler/elf_writer.cc | 8 | ||||
-rw-r--r-- | compiler/elf_writer_test.cc | 20 | ||||
-rw-r--r-- | compiler/oat_test.cc | 30 | ||||
-rw-r--r-- | oatdump/oatdump.cc | 235 | ||||
-rw-r--r-- | runtime/art_method-inl.h | 23 | ||||
-rw-r--r-- | runtime/art_method.h | 4 | ||||
-rw-r--r-- | runtime/class_linker.cc | 83 | ||||
-rw-r--r-- | runtime/class_linker.h | 6 | ||||
-rw-r--r-- | runtime/elf_file.cc | 81 | ||||
-rw-r--r-- | runtime/elf_file.h | 13 | ||||
-rw-r--r-- | runtime/elf_file_impl.h | 18 | ||||
-rw-r--r-- | runtime/gc/space/image_space.cc | 58 | ||||
-rw-r--r-- | runtime/oat_file.cc | 36 | ||||
-rw-r--r-- | runtime/oat_file.h | 1 | ||||
-rw-r--r-- | runtime/oat_file_assistant.cc | 18 | ||||
-rw-r--r-- | runtime/oat_file_assistant_test.cc | 44 | ||||
-rw-r--r-- | runtime/runtime.cc | 6 |
17 files changed, 489 insertions, 195 deletions
diff --git a/compiler/elf_writer.cc b/compiler/elf_writer.cc index 4219d97411..ca0869a839 100644 --- a/compiler/elf_writer.cc +++ b/compiler/elf_writer.cc @@ -42,7 +42,11 @@ void ElfWriter::GetOatElfInformation(File* file, size_t* oat_loaded_size, size_t* oat_data_offset) { std::string error_msg; - std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file, false, false, &error_msg)); + std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file, + false, + false, + /*low_4gb*/false, + &error_msg)); CHECK(elf_file.get() != nullptr) << error_msg; bool success = elf_file->GetLoadedSize(oat_loaded_size, &error_msg); @@ -54,7 +58,7 @@ void ElfWriter::GetOatElfInformation(File* file, bool ElfWriter::Fixup(File* file, uintptr_t oat_data_begin) { std::string error_msg; - std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file, true, false, &error_msg)); + std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file, true, false, /*low_4gb*/false, &error_msg)); CHECK(elf_file.get() != nullptr) << error_msg; // Lookup "oatdata" symbol address. diff --git a/compiler/elf_writer_test.cc b/compiler/elf_writer_test.cc index 7cf774e95f..449f514184 100644 --- a/compiler/elf_writer_test.cc +++ b/compiler/elf_writer_test.cc @@ -64,7 +64,11 @@ TEST_F(ElfWriterTest, dlsym) { ASSERT_TRUE(file.get() != nullptr); { std::string error_msg; - std::unique_ptr<ElfFile> ef(ElfFile::Open(file.get(), false, false, &error_msg)); + std::unique_ptr<ElfFile> ef(ElfFile::Open(file.get(), + false, + false, + /*low_4gb*/false, + &error_msg)); CHECK(ef.get() != nullptr) << error_msg; EXPECT_ELF_FILE_ADDRESS(ef, dl_oatdata, "oatdata", false); EXPECT_ELF_FILE_ADDRESS(ef, dl_oatexec, "oatexec", false); @@ -72,7 +76,11 @@ TEST_F(ElfWriterTest, dlsym) { } { std::string error_msg; - std::unique_ptr<ElfFile> ef(ElfFile::Open(file.get(), false, false, &error_msg)); + std::unique_ptr<ElfFile> ef(ElfFile::Open(file.get(), + false, + false, + /*low_4gb*/false, + &error_msg)); CHECK(ef.get() != nullptr) << error_msg; EXPECT_ELF_FILE_ADDRESS(ef, dl_oatdata, "oatdata", true); EXPECT_ELF_FILE_ADDRESS(ef, dl_oatexec, "oatexec", true); @@ -80,9 +88,13 @@ TEST_F(ElfWriterTest, dlsym) { } { std::string error_msg; - std::unique_ptr<ElfFile> ef(ElfFile::Open(file.get(), false, true, &error_msg)); + std::unique_ptr<ElfFile> ef(ElfFile::Open(file.get(), + false, + true, + /*low_4gb*/false, + &error_msg)); CHECK(ef.get() != nullptr) << error_msg; - CHECK(ef->Load(false, &error_msg)) << error_msg; + CHECK(ef->Load(false, /*low_4gb*/false, &error_msg)) << error_msg; EXPECT_EQ(dl_oatdata, ef->FindDynamicSymbolAddress("oatdata")); EXPECT_EQ(dl_oatexec, ef->FindDynamicSymbolAddress("oatexec")); EXPECT_EQ(dl_oatlastword, ef->FindDynamicSymbolAddress("oatlastword")); diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc index d22044aca3..4b48107848 100644 --- a/compiler/oat_test.cc +++ b/compiler/oat_test.cc @@ -230,7 +230,7 @@ class OatTest : public CommonCompilerTest { return elf_writer->End(); } - void TestDexFileInput(bool verify); + void TestDexFileInput(bool verify, bool low_4gb); void TestZipFileInput(bool verify); std::unique_ptr<const InstructionSetFeatures> insn_features_; @@ -374,8 +374,14 @@ TEST_F(OatTest, WriteRead) { if (kCompile) { // OatWriter strips the code, regenerate to compare compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), &timings); } - std::unique_ptr<OatFile> oat_file(OatFile::Open(tmp.GetFilename(), tmp.GetFilename(), nullptr, - nullptr, false, nullptr, &error_msg)); + std::unique_ptr<OatFile> oat_file(OatFile::Open(tmp.GetFilename(), + tmp.GetFilename(), + nullptr, + nullptr, + false, + /*low_4gb*/true, + nullptr, + &error_msg)); ASSERT_TRUE(oat_file.get() != nullptr) << error_msg; const OatHeader& oat_header = oat_file->GetOatHeader(); ASSERT_TRUE(oat_header.IsValid()); @@ -504,6 +510,7 @@ TEST_F(OatTest, EmptyTextSection) { nullptr, nullptr, false, + /*low_4gb*/false, nullptr, &error_msg)); ASSERT_TRUE(oat_file != nullptr); @@ -518,7 +525,7 @@ static void MaybeModifyDexFileToFail(bool verify, std::unique_ptr<const DexFile> } } -void OatTest::TestDexFileInput(bool verify) { +void OatTest::TestDexFileInput(bool verify, bool low_4gb) { TimingLogger timings("OatTest::DexFileInput", false, false); std::vector<const char*> input_filenames; @@ -572,8 +579,13 @@ void OatTest::TestDexFileInput(bool verify) { nullptr, nullptr, false, + low_4gb, nullptr, &error_msg)); + if (low_4gb) { + uintptr_t begin = reinterpret_cast<uintptr_t>(opened_oat_file->Begin()); + EXPECT_EQ(begin, static_cast<uint32_t>(begin)); + } ASSERT_TRUE(opened_oat_file != nullptr); ASSERT_EQ(2u, opened_oat_file->GetOatDexFiles().size()); std::unique_ptr<const DexFile> opened_dex_file1 = @@ -595,11 +607,15 @@ void OatTest::TestDexFileInput(bool verify) { } TEST_F(OatTest, DexFileInputCheckOutput) { - TestDexFileInput(false); + TestDexFileInput(false, /*low_4gb*/false); +} + +TEST_F(OatTest, DexFileInputCheckOutputLow4GB) { + TestDexFileInput(false, /*low_4gb*/true); } TEST_F(OatTest, DexFileInputCheckVerifier) { - TestDexFileInput(true); + TestDexFileInput(true, /*low_4gb*/false); } void OatTest::TestZipFileInput(bool verify) { @@ -667,6 +683,7 @@ void OatTest::TestZipFileInput(bool verify) { nullptr, nullptr, false, + /*low_4gb*/false, nullptr, &error_msg)); ASSERT_TRUE(opened_oat_file != nullptr); @@ -714,6 +731,7 @@ void OatTest::TestZipFileInput(bool verify) { nullptr, nullptr, false, + /*low_4gb*/false, nullptr, &error_msg)); ASSERT_TRUE(opened_oat_file != nullptr); diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index 3ed57664bc..2cdd4c7d4f 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -280,6 +280,8 @@ class OatDumperOptions { bool list_methods, bool dump_header_only, const char* export_dex_location, + const char* app_image, + const char* app_oat, uint32_t addr2instr) : dump_raw_mapping_table_(dump_raw_mapping_table), dump_raw_gc_map_(dump_raw_gc_map), @@ -293,6 +295,8 @@ class OatDumperOptions { list_methods_(list_methods), dump_header_only_(dump_header_only), export_dex_location_(export_dex_location), + app_image_(app_image), + app_oat_(app_oat), addr2instr_(addr2instr), class_loader_(nullptr) {} @@ -308,6 +312,8 @@ class OatDumperOptions { const bool list_methods_; const bool dump_header_only_; const char* const export_dex_location_; + const char* const app_image_; + const char* const app_oat_; uint32_t addr2instr_; Handle<mirror::ClassLoader>* class_loader_; }; @@ -1433,8 +1439,10 @@ class OatDumper { class ImageDumper { public: - ImageDumper(std::ostream* os, gc::space::ImageSpace& image_space, - const ImageHeader& image_header, OatDumperOptions* oat_dumper_options) + ImageDumper(std::ostream* os, + gc::space::ImageSpace& image_space, + const ImageHeader& image_header, + OatDumperOptions* oat_dumper_options) : os_(os), vios_(os), indent1_(&vios_), @@ -1532,16 +1540,23 @@ class ImageDumper { os << "OAT LOCATION: " << oat_location; os << "\n"; std::string error_msg; - const OatFile* oat_file = runtime->GetOatFileManager().FindOpenedOatFileFromOatLocation( - oat_location); + const OatFile* oat_file = image_space_.GetOatFile(); if (oat_file == nullptr) { - oat_file = OatFile::Open(oat_location, oat_location, - nullptr, nullptr, false, nullptr, + oat_file = runtime->GetOatFileManager().FindOpenedOatFileFromOatLocation(oat_location); + } + if (oat_file == nullptr) { + oat_file = OatFile::Open(oat_location, + oat_location, + nullptr, + nullptr, + false, + /*low_4gb*/false, + nullptr, &error_msg); - if (oat_file == nullptr) { - os << "NOT FOUND: " << error_msg << "\n"; - return false; - } + } + if (oat_file == nullptr) { + os << "OAT FILE NOT FOUND: " << error_msg << "\n"; + return EXIT_FAILURE; } os << "\n"; @@ -1592,21 +1607,27 @@ class ImageDumper { // TODO: Dump fields. // Dump methods after. const auto& methods_section = image_header_.GetMethodsSection(); - const size_t pointer_size = - InstructionSetPointerSize(oat_dumper_->GetOatInstructionSet()); DumpArtMethodVisitor visitor(this); - methods_section.VisitPackedArtMethods(&visitor, image_space_.Begin(), pointer_size); + methods_section.VisitPackedArtMethods(&visitor, + image_space_.Begin(), + image_header_.GetPointerSize()); // Dump the large objects separately. heap->GetLargeObjectsSpace()->GetLiveBitmap()->Walk(ImageDumper::Callback, this); indent_os << "\n"; } os << "STATS:\n" << std::flush; std::unique_ptr<File> file(OS::OpenFileForReading(image_filename.c_str())); - if (file.get() == nullptr) { + size_t data_size = image_header_.GetDataSize(); // stored size in file. + if (file == nullptr) { LOG(WARNING) << "Failed to find image in " << image_filename; - } - if (file.get() != nullptr) { + } else { stats_.file_bytes = file->GetLength(); + // If the image is compressed, adjust to decompressed size. + size_t uncompressed_size = image_header_.GetImageSize() - sizeof(ImageHeader); + if (image_header_.GetStorageMode() == ImageHeader::kStorageModeUncompressed) { + DCHECK_EQ(uncompressed_size, data_size) << "Sizes should match for uncompressed image"; + } + stats_.file_bytes += uncompressed_size - data_size; } size_t header_bytes = sizeof(ImageHeader); const auto& object_section = image_header_.GetImageSection(ImageHeader::kSectionObjects); @@ -1653,10 +1674,10 @@ class ImageDumper { uint32_t end_intern = intern_section.Offset() + intern_section.Size(); stats_.alignment_bytes += class_table_section.Offset() - end_intern; - // Add space between class table and bitmap. Expect the bitmap to be page-aligned. - uint32_t end_ctable = class_table_section.Offset() + class_table_section.Size(); + // Add space between end of image data and bitmap. Expect the bitmap to be page-aligned. + const size_t bitmap_offset = sizeof(ImageHeader) + data_size; CHECK_ALIGNED(bitmap_section.Offset(), kPageSize); - stats_.alignment_bytes += bitmap_section.Offset() - end_ctable; + stats_.alignment_bytes += RoundUp(bitmap_offset, kPageSize) - bitmap_offset; stats_.bitmap_bytes += bitmap_section.Size(); stats_.art_field_bytes += field_section.Size(); @@ -1680,7 +1701,7 @@ class ImageDumper { virtual void Visit(ArtMethod* method) OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_) { std::ostream& indent_os = image_dumper_->vios_.Stream(); indent_os << method << " " << " ArtMethod: " << PrettyMethod(method) << "\n"; - image_dumper_->DumpMethod(method, image_dumper_, indent_os); + image_dumper_->DumpMethod(method, indent_os); indent_os << "\n"; } @@ -1773,10 +1794,9 @@ class ImageDumper { return image_space_.Contains(object); } - const void* GetQuickOatCodeBegin(ArtMethod* m) - SHARED_REQUIRES(Locks::mutator_lock_) { + const void* GetQuickOatCodeBegin(ArtMethod* m) SHARED_REQUIRES(Locks::mutator_lock_) { const void* quick_code = m->GetEntryPointFromQuickCompiledCodePtrSize( - InstructionSetPointerSize(oat_dumper_->GetOatInstructionSet())); + image_header_.GetPointerSize()); if (Runtime::Current()->GetClassLinker()->IsQuickResolutionStub(quick_code)) { quick_code = oat_dumper_->GetQuickOatCode(m); } @@ -1835,8 +1855,7 @@ class ImageDumper { } ScopedIndentation indent1(&state->vios_); DumpFields(os, obj, obj_class); - const auto image_pointer_size = - InstructionSetPointerSize(state->oat_dumper_->GetOatInstructionSet()); + const size_t image_pointer_size = state->image_header_.GetPointerSize(); if (obj->IsObjectArray()) { auto* obj_array = obj->AsObjectArray<mirror::Object>(); for (int32_t i = 0, length = obj_array->GetLength(); i < length; i++) { @@ -1881,7 +1900,9 @@ class ImageDumper { ScopedIndentation indent2(&state->vios_); auto* resolved_methods = dex_cache->GetResolvedMethods(); for (size_t i = 0, length = dex_cache->NumResolvedMethods(); i < length; ++i) { - auto* elem = mirror::DexCache::GetElementPtrSize(resolved_methods, i, image_pointer_size); + auto* elem = mirror::DexCache::GetElementPtrSize(resolved_methods, + i, + image_pointer_size); size_t run = 0; for (size_t j = i + 1; j != length && elem == mirror::DexCache::GetElementPtrSize(resolved_methods, @@ -1943,13 +1964,11 @@ class ImageDumper { state->stats_.Update(obj_class->GetDescriptor(&temp), object_bytes); } - void DumpMethod(ArtMethod* method, ImageDumper* state, std::ostream& indent_os) + void DumpMethod(ArtMethod* method, std::ostream& indent_os) SHARED_REQUIRES(Locks::mutator_lock_) { DCHECK(method != nullptr); - const auto image_pointer_size = - InstructionSetPointerSize(state->oat_dumper_->GetOatInstructionSet()); - const void* quick_oat_code_begin = state->GetQuickOatCodeBegin(method); - const void* quick_oat_code_end = state->GetQuickOatCodeEnd(method); + const void* quick_oat_code_begin = GetQuickOatCodeBegin(method); + const void* quick_oat_code_end = GetQuickOatCodeEnd(method); OatQuickMethodHeader* method_header = reinterpret_cast<OatQuickMethodHeader*>( reinterpret_cast<uintptr_t>(quick_oat_code_begin) - sizeof(OatQuickMethodHeader)); if (method->IsNative()) { @@ -1958,13 +1977,13 @@ class ImageDumper { DCHECK(method_header->GetMappingTable() == nullptr) << PrettyMethod(method); } bool first_occurrence; - uint32_t quick_oat_code_size = state->GetQuickOatCodeSize(method); - state->ComputeOatSize(quick_oat_code_begin, &first_occurrence); + uint32_t quick_oat_code_size = GetQuickOatCodeSize(method); + ComputeOatSize(quick_oat_code_begin, &first_occurrence); if (first_occurrence) { - state->stats_.native_to_managed_code_bytes += quick_oat_code_size; + stats_.native_to_managed_code_bytes += quick_oat_code_size; } - if (quick_oat_code_begin != - method->GetEntryPointFromQuickCompiledCodePtrSize(image_pointer_size)) { + if (quick_oat_code_begin != method->GetEntryPointFromQuickCompiledCodePtrSize( + image_header_.GetPointerSize())) { indent_os << StringPrintf("OAT CODE: %p\n", quick_oat_code_begin); } } else if (method->IsAbstract() || method->IsCalleeSaveMethod() || @@ -1973,46 +1992,44 @@ class ImageDumper { } else { const DexFile::CodeItem* code_item = method->GetCodeItem(); size_t dex_instruction_bytes = code_item->insns_size_in_code_units_ * 2; - state->stats_.dex_instruction_bytes += dex_instruction_bytes; + stats_.dex_instruction_bytes += dex_instruction_bytes; bool first_occurrence; - size_t gc_map_bytes = state->ComputeOatSize( - method_header->GetNativeGcMap(), &first_occurrence); + size_t gc_map_bytes = ComputeOatSize(method_header->GetNativeGcMap(), &first_occurrence); if (first_occurrence) { - state->stats_.gc_map_bytes += gc_map_bytes; + stats_.gc_map_bytes += gc_map_bytes; } - size_t pc_mapping_table_bytes = state->ComputeOatSize( + size_t pc_mapping_table_bytes = ComputeOatSize( method_header->GetMappingTable(), &first_occurrence); if (first_occurrence) { - state->stats_.pc_mapping_table_bytes += pc_mapping_table_bytes; + stats_.pc_mapping_table_bytes += pc_mapping_table_bytes; } size_t vmap_table_bytes = 0u; if (!method_header->IsOptimized()) { // Method compiled with the optimizing compiler have no vmap table. - vmap_table_bytes = state->ComputeOatSize( - method_header->GetVmapTable(), &first_occurrence); + vmap_table_bytes = ComputeOatSize(method_header->GetVmapTable(), &first_occurrence); if (first_occurrence) { - state->stats_.vmap_table_bytes += vmap_table_bytes; + stats_.vmap_table_bytes += vmap_table_bytes; } } - uint32_t quick_oat_code_size = state->GetQuickOatCodeSize(method); - state->ComputeOatSize(quick_oat_code_begin, &first_occurrence); + uint32_t quick_oat_code_size = GetQuickOatCodeSize(method); + ComputeOatSize(quick_oat_code_begin, &first_occurrence); if (first_occurrence) { - state->stats_.managed_code_bytes += quick_oat_code_size; + stats_.managed_code_bytes += quick_oat_code_size; if (method->IsConstructor()) { if (method->IsStatic()) { - state->stats_.class_initializer_code_bytes += quick_oat_code_size; + stats_.class_initializer_code_bytes += quick_oat_code_size; } else if (dex_instruction_bytes > kLargeConstructorDexBytes) { - state->stats_.large_initializer_code_bytes += quick_oat_code_size; + stats_.large_initializer_code_bytes += quick_oat_code_size; } } else if (dex_instruction_bytes > kLargeMethodDexBytes) { - state->stats_.large_method_code_bytes += quick_oat_code_size; + stats_.large_method_code_bytes += quick_oat_code_size; } } - state->stats_.managed_code_bytes_ignoring_deduplication += quick_oat_code_size; + stats_.managed_code_bytes_ignoring_deduplication += quick_oat_code_size; uint32_t method_access_flags = method->GetAccessFlags(); @@ -2022,11 +2039,11 @@ class ImageDumper { method_access_flags); size_t total_size = dex_instruction_bytes + gc_map_bytes + pc_mapping_table_bytes + - vmap_table_bytes + quick_oat_code_size + ArtMethod::Size(image_pointer_size); + vmap_table_bytes + quick_oat_code_size + ArtMethod::Size(image_header_.GetPointerSize()); double expansion = static_cast<double>(quick_oat_code_size) / static_cast<double>(dex_instruction_bytes); - state->stats_.ComputeOutliers(total_size, expansion, method); + stats_.ComputeOutliers(total_size, expansion, method); } } @@ -2361,26 +2378,75 @@ class ImageDumper { DISALLOW_COPY_AND_ASSIGN(ImageDumper); }; -static int DumpImage(Runtime* runtime, OatDumperOptions* options, std::ostream* os) { +static int DumpImage(gc::space::ImageSpace* image_space, + OatDumperOptions* options, + std::ostream* os) SHARED_REQUIRES(Locks::mutator_lock_) { + const ImageHeader& image_header = image_space->GetImageHeader(); + if (!image_header.IsValid()) { + fprintf(stderr, "Invalid image header %s\n", image_space->GetImageLocation().c_str()); + return EXIT_FAILURE; + } + ImageDumper image_dumper(os, *image_space, image_header, options); + if (!image_dumper.Dump()) { + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} + +static int DumpImages(Runtime* runtime, OatDumperOptions* options, std::ostream* os) { // Dumping the image, no explicit class loader. ScopedNullHandle<mirror::ClassLoader> null_class_loader; options->class_loader_ = &null_class_loader; ScopedObjectAccess soa(Thread::Current()); - gc::Heap* heap = runtime->GetHeap(); - std::vector<gc::space::ImageSpace*> image_spaces = heap->GetBootImageSpaces(); - CHECK(!image_spaces.empty()); - for (gc::space::ImageSpace* image_space : image_spaces) { - const ImageHeader& image_header = image_space->GetImageHeader(); - if (!image_header.IsValid()) { - fprintf(stderr, "Invalid image header %s\n", image_space->GetImageLocation().c_str()); + if (options->app_image_ != nullptr) { + if (options->app_oat_ == nullptr) { + LOG(ERROR) << "Can not dump app image without app oat file"; return EXIT_FAILURE; } - - ImageDumper image_dumper(os, *image_space, image_header, options); - if (!image_dumper.Dump()) { + // We can't know if the app image is 32 bits yet, but it contains pointers into the oat file. + // We need to map the oat file in the low 4gb or else the fixup wont be able to fit oat file + // pointers into 32 bit pointer sized ArtMethods. + std::string error_msg; + std::unique_ptr<OatFile> oat_file(OatFile::Open(options->app_oat_, + options->app_oat_, + nullptr, + nullptr, + false, + /*low_4gb*/true, + nullptr, + &error_msg)); + if (oat_file == nullptr) { + LOG(ERROR) << "Failed to open oat file " << options->app_oat_ << " with error " << error_msg; return EXIT_FAILURE; } + std::unique_ptr<gc::space::ImageSpace> space( + gc::space::ImageSpace::CreateFromAppImage(options->app_image_, oat_file.get(), &error_msg)); + if (space == nullptr) { + LOG(ERROR) << "Failed to open app image " << options->app_image_ << " with error " + << error_msg; + } + // Open dex files for the image. + std::vector<std::unique_ptr<const DexFile>> dex_files; + if (!runtime->GetClassLinker()->OpenImageDexFiles(space.get(), &dex_files, &error_msg)) { + LOG(ERROR) << "Failed to open app image dex files " << options->app_image_ << " with error " + << error_msg; + } + // Dump the actual image. + int result = DumpImage(space.get(), options, os); + if (result != EXIT_SUCCESS) { + return result; + } + // Fall through to dump the boot images. + } + + gc::Heap* heap = runtime->GetHeap(); + CHECK(heap->HasBootImageSpace()) << "No image spaces"; + for (gc::space::ImageSpace* image_space : heap->GetBootImageSpaces()) { + int result = DumpImage(image_space, options, os); + if (result != EXIT_SUCCESS) { + return result; + } } return EXIT_SUCCESS; } @@ -2436,8 +2502,14 @@ static int DumpOatWithoutRuntime(OatFile* oat_file, OatDumperOptions* options, s static int DumpOat(Runtime* runtime, const char* oat_filename, OatDumperOptions* options, std::ostream* os) { std::string error_msg; - OatFile* oat_file = OatFile::Open(oat_filename, oat_filename, nullptr, nullptr, false, - nullptr, &error_msg); + OatFile* oat_file = OatFile::Open(oat_filename, + oat_filename, + nullptr, + nullptr, + false, + /*low_4gb*/false, + nullptr, + &error_msg); if (oat_file == nullptr) { fprintf(stderr, "Failed to open oat file from '%s': %s\n", oat_filename, error_msg.c_str()); return EXIT_FAILURE; @@ -2452,8 +2524,14 @@ static int DumpOat(Runtime* runtime, const char* oat_filename, OatDumperOptions* static int SymbolizeOat(const char* oat_filename, std::string& output_name) { std::string error_msg; - OatFile* oat_file = OatFile::Open(oat_filename, oat_filename, nullptr, nullptr, false, - nullptr, &error_msg); + OatFile* oat_file = OatFile::Open(oat_filename, + oat_filename, + nullptr, + nullptr, + false, + /*low_4gb*/false, + nullptr, + &error_msg); if (oat_file == nullptr) { fprintf(stderr, "Failed to open oat file from '%s': %s\n", oat_filename, error_msg.c_str()); return EXIT_FAILURE; @@ -2524,6 +2602,10 @@ struct OatdumpArgs : public CmdlineArgs { *error_msg = "Address conversion failed"; return kParseError; } + } else if (option.starts_with("--app-image=")) { + app_image_ = option.substr(strlen("--app-image=")).data(); + } else if (option.starts_with("--app-oat=")) { + app_oat_ = option.substr(strlen("--app-oat=")).data(); } else { return kParseUnknownArgument; } @@ -2569,6 +2651,13 @@ struct OatdumpArgs : public CmdlineArgs { "\n" " --image=<file.art>: specifies an input image location.\n" " Example: --image=/system/framework/boot.art\n" + "\n" + " --app-image=<file.art>: specifies an input app image. Must also have a specified\n" + " boot image and app oat file.\n" + " Example: --app-image=app.art\n" + "\n" + " --app-oat=<file.odex>: specifies an input app oat.\n" + " Example: --app-oat=app.odex\n" "\n"; usage += Base::GetUsage(); @@ -2637,6 +2726,8 @@ struct OatdumpArgs : public CmdlineArgs { bool dump_header_only_ = false; uint32_t addr2instr_ = 0; const char* export_dex_location_ = nullptr; + const char* app_image_ = nullptr; + const char* app_oat_ = nullptr; }; struct OatdumpMain : public CmdlineMain<OatdumpArgs> { @@ -2646,7 +2737,7 @@ struct OatdumpMain : public CmdlineMain<OatdumpArgs> { // If we are only doing the oat file, disable absolute_addresses. Keep them for image dumping. bool absolute_addresses = (args_->oat_filename_ == nullptr); - oat_dumper_options_ = std::unique_ptr<OatDumperOptions>(new OatDumperOptions( + oat_dumper_options_.reset(new OatDumperOptions( args_->dump_raw_mapping_table_, args_->dump_raw_gc_map_, args_->dump_vmap_, @@ -2659,6 +2750,8 @@ struct OatdumpMain : public CmdlineMain<OatdumpArgs> { args_->list_methods_, args_->dump_header_only_, args_->export_dex_location_, + args_->app_image_, + args_->app_oat_, args_->addr2instr_)); return (args_->boot_image_location_ != nullptr || args_->image_location_ != nullptr) && @@ -2691,7 +2784,7 @@ struct OatdumpMain : public CmdlineMain<OatdumpArgs> { args_->os_) == EXIT_SUCCESS; } - return DumpImage(runtime, oat_dumper_options_.get(), args_->os_) == EXIT_SUCCESS; + return DumpImages(runtime, oat_dumper_options_.get(), args_->os_) == EXIT_SUCCESS; } std::unique_ptr<OatDumperOptions> oat_dumper_options_; diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h index ebe89bbbd2..8541210791 100644 --- a/runtime/art_method-inl.h +++ b/runtime/art_method-inl.h @@ -473,39 +473,40 @@ void ArtMethod::VisitRoots(RootVisitorType& visitor, size_t pointer_size) { } template <typename Visitor> -inline void ArtMethod::UpdateObjectsForImageRelocation(const Visitor& visitor) { +inline void ArtMethod::UpdateObjectsForImageRelocation(const Visitor& visitor, + size_t pointer_size) { mirror::Class* old_class = GetDeclaringClassUnchecked<kWithoutReadBarrier>(); mirror::Class* new_class = visitor(old_class); if (old_class != new_class) { SetDeclaringClass(new_class); } - ArtMethod** old_methods = GetDexCacheResolvedMethods(sizeof(void*)); + ArtMethod** old_methods = GetDexCacheResolvedMethods(pointer_size); ArtMethod** new_methods = visitor(old_methods); if (old_methods != new_methods) { - SetDexCacheResolvedMethods(new_methods, sizeof(void*)); + SetDexCacheResolvedMethods(new_methods, pointer_size); } - GcRoot<mirror::Class>* old_types = GetDexCacheResolvedTypes(sizeof(void*)); + GcRoot<mirror::Class>* old_types = GetDexCacheResolvedTypes(pointer_size); GcRoot<mirror::Class>* new_types = visitor(old_types); if (old_types != new_types) { - SetDexCacheResolvedTypes(new_types, sizeof(void*)); + SetDexCacheResolvedTypes(new_types, pointer_size); } } template <ReadBarrierOption kReadBarrierOption, typename Visitor> -inline void ArtMethod::UpdateEntrypoints(const Visitor& visitor) { +inline void ArtMethod::UpdateEntrypoints(const Visitor& visitor, size_t pointer_size) { if (IsNative<kReadBarrierOption>()) { - const void* old_native_code = GetEntryPointFromJni(); + const void* old_native_code = GetEntryPointFromJniPtrSize(pointer_size); const void* new_native_code = visitor(old_native_code); if (old_native_code != new_native_code) { - SetEntryPointFromJni(new_native_code); + SetEntryPointFromJniPtrSize(new_native_code, pointer_size); } } else { - DCHECK(GetEntryPointFromJni() == nullptr); + DCHECK(GetEntryPointFromJniPtrSize(pointer_size) == nullptr); } - const void* old_code = GetEntryPointFromQuickCompiledCode(); + const void* old_code = GetEntryPointFromQuickCompiledCodePtrSize(pointer_size); const void* new_code = visitor(old_code); if (old_code != new_code) { - SetEntryPointFromQuickCompiledCode(new_code); + SetEntryPointFromQuickCompiledCodePtrSize(new_code, pointer_size); } } diff --git a/runtime/art_method.h b/runtime/art_method.h index ec00a7b900..5ca362ce2c 100644 --- a/runtime/art_method.h +++ b/runtime/art_method.h @@ -490,12 +490,12 @@ class ArtMethod FINAL { // Update heap objects and non-entrypoint pointers by the passed in visitor for image relocation. // Does not use read barrier. template <typename Visitor> - ALWAYS_INLINE void UpdateObjectsForImageRelocation(const Visitor& visitor) + ALWAYS_INLINE void UpdateObjectsForImageRelocation(const Visitor& visitor, size_t pointer_size) SHARED_REQUIRES(Locks::mutator_lock_); // Update entry points by passing them through the visitor. template <ReadBarrierOption kReadBarrierOption = kWithReadBarrier, typename Visitor> - ALWAYS_INLINE void UpdateEntrypoints(const Visitor& visitor); + ALWAYS_INLINE void UpdateEntrypoints(const Visitor& visitor, size_t pointer_size); protected: // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses". diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 06895891a4..6a2b702056 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -1489,6 +1489,64 @@ class UpdateClassLoaderAndResolvedStringsVisitor { const bool forward_strings_; }; +static std::unique_ptr<const DexFile> OpenOatDexFile(const OatFile* oat_file, + const char* location, + std::string* error_msg) + SHARED_REQUIRES(Locks::mutator_lock_) { + DCHECK(error_msg != nullptr); + std::unique_ptr<const DexFile> dex_file; + const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(location, nullptr); + if (oat_dex_file == nullptr) { + *error_msg = StringPrintf("Failed finding oat dex file for %s %s", + oat_file->GetLocation().c_str(), + location); + return std::unique_ptr<const DexFile>(); + } + std::string inner_error_msg; + dex_file = oat_dex_file->OpenDexFile(&inner_error_msg); + if (dex_file == nullptr) { + *error_msg = StringPrintf("Failed to open dex file %s from within oat file %s error '%s'", + location, + oat_file->GetLocation().c_str(), + inner_error_msg.c_str()); + return std::unique_ptr<const DexFile>(); + } + + if (dex_file->GetLocationChecksum() != oat_dex_file->GetDexFileLocationChecksum()) { + *error_msg = StringPrintf("Checksums do not match for %s: %x vs %x", + location, + dex_file->GetLocationChecksum(), + oat_dex_file->GetDexFileLocationChecksum()); + return std::unique_ptr<const DexFile>(); + } + return dex_file; +} + +bool ClassLinker::OpenImageDexFiles(gc::space::ImageSpace* space, + std::vector<std::unique_ptr<const DexFile>>* out_dex_files, + std::string* error_msg) { + ScopedAssertNoThreadSuspension nts(Thread::Current(), __FUNCTION__); + const ImageHeader& header = space->GetImageHeader(); + mirror::Object* dex_caches_object = header.GetImageRoot(ImageHeader::kDexCaches); + DCHECK(dex_caches_object != nullptr); + mirror::ObjectArray<mirror::DexCache>* dex_caches = + dex_caches_object->AsObjectArray<mirror::DexCache>(); + const OatFile* oat_file = space->GetOatFile(); + for (int32_t i = 0; i < dex_caches->GetLength(); i++) { + mirror::DexCache* dex_cache = dex_caches->Get(i); + std::string dex_file_location(dex_cache->GetLocation()->ToModifiedUtf8()); + std::unique_ptr<const DexFile> dex_file = OpenOatDexFile(oat_file, + dex_file_location.c_str(), + error_msg); + if (dex_file == nullptr) { + return false; + } + dex_cache->SetDexFile(dex_file.get()); + out_dex_files->push_back(std::move(dex_file)); + } + return true; +} + bool ClassLinker::AddImageSpace( gc::space::ImageSpace* space, Handle<mirror::ClassLoader> class_loader, @@ -1555,29 +1613,10 @@ bool ClassLinker::AddImageSpace( dex_location_path = dex_location_path.substr(0, pos + 1); // Keep trailing '/' dex_file_location = dex_location_path + dex_file_location; } - const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file_location.c_str(), - nullptr); - if (oat_dex_file == nullptr) { - *error_msg = StringPrintf("Failed finding oat dex file for %s %s", - oat_file->GetLocation().c_str(), - dex_file_location.c_str()); - return false; - } - std::string inner_error_msg; - std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&inner_error_msg); + std::unique_ptr<const DexFile> dex_file = OpenOatDexFile(oat_file, + dex_file_location.c_str(), + error_msg); if (dex_file == nullptr) { - *error_msg = StringPrintf("Failed to open dex file %s from within oat file %s error '%s'", - dex_file_location.c_str(), - oat_file->GetLocation().c_str(), - inner_error_msg.c_str()); - return false; - } - - if (dex_file->GetLocationChecksum() != oat_dex_file->GetDexFileLocationChecksum()) { - *error_msg = StringPrintf("Checksums do not match for %s: %x vs %x", - dex_file_location.c_str(), - dex_file->GetLocationChecksum(), - oat_dex_file->GetDexFileLocationChecksum()); return false; } diff --git a/runtime/class_linker.h b/runtime/class_linker.h index 492a228522..36ed8204a6 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -149,6 +149,12 @@ class ClassLinker { REQUIRES(!dex_lock_) SHARED_REQUIRES(Locks::mutator_lock_); + bool OpenImageDexFiles(gc::space::ImageSpace* space, + std::vector<std::unique_ptr<const DexFile>>* out_dex_files, + std::string* error_msg) + REQUIRES(!dex_lock_) + SHARED_REQUIRES(Locks::mutator_lock_); + // Finds a class by its descriptor, loading it if necessary. // If class_loader is null, searches boot_class_path_. mirror::Class* FindClass(Thread* self, diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc index 52da28bb50..3b4b88d437 100644 --- a/runtime/elf_file.cc +++ b/runtime/elf_file.cc @@ -57,9 +57,12 @@ ElfFileImpl<ElfTypes>::ElfFileImpl(File* file, bool writable, } template <typename ElfTypes> -ElfFileImpl<ElfTypes>* ElfFileImpl<ElfTypes>::Open( - File* file, bool writable, bool program_header_only, - std::string* error_msg, uint8_t* requested_base) { +ElfFileImpl<ElfTypes>* ElfFileImpl<ElfTypes>::Open(File* file, + bool writable, + bool program_header_only, + bool low_4gb, + std::string* error_msg, + uint8_t* requested_base) { std::unique_ptr<ElfFileImpl<ElfTypes>> elf_file(new ElfFileImpl<ElfTypes> (file, writable, program_header_only, requested_base)); int prot; @@ -71,26 +74,29 @@ ElfFileImpl<ElfTypes>* ElfFileImpl<ElfTypes>::Open( prot = PROT_READ; flags = MAP_PRIVATE; } - if (!elf_file->Setup(prot, flags, error_msg)) { + if (!elf_file->Setup(prot, flags, low_4gb, error_msg)) { return nullptr; } return elf_file.release(); } template <typename ElfTypes> -ElfFileImpl<ElfTypes>* ElfFileImpl<ElfTypes>::Open( - File* file, int prot, int flags, std::string* error_msg) { +ElfFileImpl<ElfTypes>* ElfFileImpl<ElfTypes>::Open(File* file, + int prot, + int flags, + bool low_4gb, + std::string* error_msg) { std::unique_ptr<ElfFileImpl<ElfTypes>> elf_file(new ElfFileImpl<ElfTypes> (file, (prot & PROT_WRITE) == PROT_WRITE, /*program_header_only*/false, /*requested_base*/nullptr)); - if (!elf_file->Setup(prot, flags, error_msg)) { + if (!elf_file->Setup(prot, flags, low_4gb, error_msg)) { return nullptr; } return elf_file.release(); } template <typename ElfTypes> -bool ElfFileImpl<ElfTypes>::Setup(int prot, int flags, std::string* error_msg) { +bool ElfFileImpl<ElfTypes>::Setup(int prot, int flags, bool low_4gb, std::string* error_msg) { int64_t temp_file_length = file_->GetLength(); if (temp_file_length < 0) { errno = -temp_file_length; @@ -114,7 +120,7 @@ bool ElfFileImpl<ElfTypes>::Setup(int prot, int flags, std::string* error_msg) { flags, file_->Fd(), 0, - /*low4_gb*/false, + low_4gb, file_->GetPath().c_str(), error_msg), error_msg)) { @@ -133,7 +139,7 @@ bool ElfFileImpl<ElfTypes>::Setup(int prot, int flags, std::string* error_msg) { flags, file_->Fd(), 0, - /*low4_gb*/false, + low_4gb, file_->GetPath().c_str(), error_msg), error_msg)) { @@ -147,7 +153,7 @@ bool ElfFileImpl<ElfTypes>::Setup(int prot, int flags, std::string* error_msg) { flags, file_->Fd(), 0, - /*low4_gb*/false, + low_4gb, file_->GetPath().c_str(), error_msg), error_msg)) { @@ -1058,7 +1064,7 @@ bool ElfFileImpl<ElfTypes>::GetLoadedSize(size_t* size, std::string* error_msg) } template <typename ElfTypes> -bool ElfFileImpl<ElfTypes>::Load(bool executable, std::string* error_msg) { +bool ElfFileImpl<ElfTypes>::Load(bool executable, bool low_4gb, std::string* error_msg) { CHECK(program_header_only_) << file_->GetPath(); if (executable) { @@ -1124,7 +1130,10 @@ bool ElfFileImpl<ElfTypes>::Load(bool executable, std::string* error_msg) { } std::unique_ptr<MemMap> reserve(MemMap::MapAnonymous(reservation_name.c_str(), reserve_base_override, - loaded_size, PROT_NONE, false, false, + loaded_size, + PROT_NONE, + low_4gb, + false, error_msg)); if (reserve.get() == nullptr) { *error_msg = StringPrintf("Failed to allocate %s: %s", @@ -1656,7 +1665,11 @@ ElfFile::~ElfFile() { CHECK_NE(elf32_.get() == nullptr, elf64_.get() == nullptr); } -ElfFile* ElfFile::Open(File* file, bool writable, bool program_header_only, std::string* error_msg, +ElfFile* ElfFile::Open(File* file, + bool writable, + bool program_header_only, + bool low_4gb, + std::string* error_msg, uint8_t* requested_base) { if (file->GetLength() < EI_NIDENT) { *error_msg = StringPrintf("File %s is too short to be a valid ELF file", @@ -1668,7 +1681,7 @@ ElfFile* ElfFile::Open(File* file, bool writable, bool program_header_only, std: MAP_PRIVATE, file->Fd(), 0, - /*low4_gb*/false, + low_4gb, file->GetPath().c_str(), error_msg)); if (map == nullptr && map->Size() != EI_NIDENT) { @@ -1676,14 +1689,22 @@ ElfFile* ElfFile::Open(File* file, bool writable, bool program_header_only, std: } uint8_t* header = map->Begin(); if (header[EI_CLASS] == ELFCLASS64) { - ElfFileImpl64* elf_file_impl = ElfFileImpl64::Open(file, writable, program_header_only, - error_msg, requested_base); + ElfFileImpl64* elf_file_impl = ElfFileImpl64::Open(file, + writable, + program_header_only, + low_4gb, + error_msg, + requested_base); if (elf_file_impl == nullptr) return nullptr; return new ElfFile(elf_file_impl); } else if (header[EI_CLASS] == ELFCLASS32) { - ElfFileImpl32* elf_file_impl = ElfFileImpl32::Open(file, writable, program_header_only, - error_msg, requested_base); + ElfFileImpl32* elf_file_impl = ElfFileImpl32::Open(file, + writable, + program_header_only, + low_4gb, + error_msg, + requested_base); if (elf_file_impl == nullptr) { return nullptr; } @@ -1698,6 +1719,8 @@ ElfFile* ElfFile::Open(File* file, bool writable, bool program_header_only, std: } ElfFile* ElfFile::Open(File* file, int mmap_prot, int mmap_flags, std::string* error_msg) { + // low_4gb support not required for this path. + constexpr bool low_4gb = false; if (file->GetLength() < EI_NIDENT) { *error_msg = StringPrintf("File %s is too short to be a valid ELF file", file->GetPath().c_str()); @@ -1708,7 +1731,7 @@ ElfFile* ElfFile::Open(File* file, int mmap_prot, int mmap_flags, std::string* e MAP_PRIVATE, file->Fd(), 0, - /*low4_gb*/false, + low_4gb, file->GetPath().c_str(), error_msg)); if (map == nullptr && map->Size() != EI_NIDENT) { @@ -1716,13 +1739,21 @@ ElfFile* ElfFile::Open(File* file, int mmap_prot, int mmap_flags, std::string* e } uint8_t* header = map->Begin(); if (header[EI_CLASS] == ELFCLASS64) { - ElfFileImpl64* elf_file_impl = ElfFileImpl64::Open(file, mmap_prot, mmap_flags, error_msg); + ElfFileImpl64* elf_file_impl = ElfFileImpl64::Open(file, + mmap_prot, + mmap_flags, + low_4gb, + error_msg); if (elf_file_impl == nullptr) { return nullptr; } return new ElfFile(elf_file_impl); } else if (header[EI_CLASS] == ELFCLASS32) { - ElfFileImpl32* elf_file_impl = ElfFileImpl32::Open(file, mmap_prot, mmap_flags, error_msg); + ElfFileImpl32* elf_file_impl = ElfFileImpl32::Open(file, + mmap_prot, + mmap_flags, + low_4gb, + error_msg); if (elf_file_impl == nullptr) { return nullptr; } @@ -1744,8 +1775,8 @@ ElfFile* ElfFile::Open(File* file, int mmap_prot, int mmap_flags, std::string* e return elf32_->func(__VA_ARGS__); \ } -bool ElfFile::Load(bool executable, std::string* error_msg) { - DELEGATE_TO_IMPL(Load, executable, error_msg); +bool ElfFile::Load(bool executable, bool low_4gb, std::string* error_msg) { + DELEGATE_TO_IMPL(Load, executable, low_4gb, error_msg); } const uint8_t* ElfFile::FindDynamicSymbolAddress(const std::string& symbol_name) const { @@ -1810,7 +1841,7 @@ bool ElfFile::GetLoadedSize(size_t* size, std::string* error_msg) const { } bool ElfFile::Strip(File* file, std::string* error_msg) { - std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file, true, false, error_msg)); + std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file, true, false, /*low_4gb*/false, error_msg)); if (elf_file.get() == nullptr) { return false; } diff --git a/runtime/elf_file.h b/runtime/elf_file.h index 1188c97658..b5229b579c 100644 --- a/runtime/elf_file.h +++ b/runtime/elf_file.h @@ -38,15 +38,22 @@ typedef ElfFileImpl<ElfTypes64> ElfFileImpl64; // ELFObjectFile. class ElfFile { public: - static ElfFile* Open(File* file, bool writable, bool program_header_only, std::string* error_msg, + static ElfFile* Open(File* file, + bool writable, + bool program_header_only, + bool low_4gb, + std::string* error_msg, uint8_t* requested_base = nullptr); // TODO: move arg to before error_msg. // Open with specific mmap flags, Always maps in the whole file, not just the // program header sections. - static ElfFile* Open(File* file, int mmap_prot, int mmap_flags, std::string* error_msg); + static ElfFile* Open(File* file, + int mmap_prot, + int mmap_flags, + std::string* error_msg); ~ElfFile(); // Load segments into memory based on PT_LOAD program headers - bool Load(bool executable, std::string* error_msg); + bool Load(bool executable, bool low_4gb, std::string* error_msg); const uint8_t* FindDynamicSymbolAddress(const std::string& symbol_name) const; diff --git a/runtime/elf_file_impl.h b/runtime/elf_file_impl.h index 2af31dc554..1cdbedc057 100644 --- a/runtime/elf_file_impl.h +++ b/runtime/elf_file_impl.h @@ -48,9 +48,17 @@ class ElfFileImpl { using Elf_Phdr = typename ElfTypes::Phdr; using Elf_Dyn = typename ElfTypes::Dyn; - static ElfFileImpl* Open(File* file, bool writable, bool program_header_only, - std::string* error_msg, uint8_t* requested_base = nullptr); - static ElfFileImpl* Open(File* file, int mmap_prot, int mmap_flags, std::string* error_msg); + static ElfFileImpl* Open(File* file, + bool writable, + bool program_header_only, + bool low_4gb, + std::string* error_msg, + uint8_t* requested_base = nullptr); + static ElfFileImpl* Open(File* file, + int mmap_prot, + int mmap_flags, + bool low_4gb, + std::string* error_msg); ~ElfFileImpl(); const File& GetFile() const { @@ -111,7 +119,7 @@ class ElfFileImpl { // Load segments into memory based on PT_LOAD program headers. // executable is true at run time, false at compile time. - bool Load(bool executable, std::string* error_msg); + bool Load(bool executable, bool low_4gb, std::string* error_msg); bool Fixup(Elf_Addr base_address); bool FixupDynamic(Elf_Addr base_address); @@ -129,7 +137,7 @@ class ElfFileImpl { private: ElfFileImpl(File* file, bool writable, bool program_header_only, uint8_t* requested_base); - bool Setup(int prot, int flags, std::string* error_msg); + bool Setup(int prot, int flags, bool low_4gb, std::string* error_msg); bool SetMap(MemMap* map, std::string* error_msg); diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc index bea1dcc57d..895d3d3739 100644 --- a/runtime/gc/space/image_space.cc +++ b/runtime/gc/space/image_space.cc @@ -617,7 +617,7 @@ class RelocationRange { } // Returns the delta between the dest from the source. - off_t Delta() const { + uintptr_t Delta() const { return dest_ - source_; } @@ -639,6 +639,13 @@ class RelocationRange { const uintptr_t length_; }; +std::ostream& operator<<(std::ostream& os, const RelocationRange& reloc) { + return os << "(" << reinterpret_cast<const void*>(reloc.Source()) << "-" + << reinterpret_cast<const void*>(reloc.Source() + reloc.Length()) << ")->(" + << reinterpret_cast<const void*>(reloc.Dest()) << "-" + << reinterpret_cast<const void*>(reloc.Dest() + reloc.Length()) << ")"; +} + class FixupVisitor : public ValueObject { public: FixupVisitor(const RelocationRange& boot_image, @@ -670,7 +677,7 @@ class FixupVisitor : public ValueObject { ALWAYS_INLINE const void* ForwardCode(const void* src) const { const uintptr_t uint_src = reinterpret_cast<uintptr_t>(src); if (boot_oat_.InSource(uint_src)) { - return reinterpret_cast<const void*>(boot_oat_.ToDest(uint_src)); + return reinterpret_cast<const void*>(boot_oat_.ToDest(uint_src)); } if (app_oat_.InSource(uint_src)) { return reinterpret_cast<const void*>(app_oat_.ToDest(uint_src)); @@ -687,13 +694,6 @@ class FixupVisitor : public ValueObject { const RelocationRange app_oat_; }; -std::ostream& operator<<(std::ostream& os, const RelocationRange& reloc) { - return os << "(" << reinterpret_cast<const void*>(reloc.Source()) << "-" - << reinterpret_cast<const void*>(reloc.Source() + reloc.Length()) << ")->(" - << reinterpret_cast<const void*>(reloc.Dest()) << "-" - << reinterpret_cast<const void*>(reloc.Dest() + reloc.Length()) << ")"; -} - // Adapt for mirror::Class::FixupNativePointers. class FixupObjectAdapter : public FixupVisitor { public: @@ -756,8 +756,10 @@ class FixupObjectVisitor : public FixupVisitor { public: template<typename... Args> explicit FixupObjectVisitor(gc::accounting::ContinuousSpaceBitmap* pointer_array_visited, + const size_t pointer_size, Args... args) : FixupVisitor(args...), + pointer_size_(pointer_size), pointer_array_visited_(pointer_array_visited) {} // Fix up separately since we also need to fix up method entrypoints. @@ -791,7 +793,7 @@ class FixupObjectVisitor : public FixupVisitor { if (array != nullptr && visitor.IsInAppImage(array) && !pointer_array_visited_->Test(array)) { - array->Fixup<kVerifyNone, kWithoutReadBarrier>(array, sizeof(void*), visitor); + array->Fixup<kVerifyNone, kWithoutReadBarrier>(array, pointer_size_, visitor); pointer_array_visited_->Set(array); } } @@ -813,7 +815,7 @@ class FixupObjectVisitor : public FixupVisitor { if (obj->IsClass<kVerifyNone, kWithoutReadBarrier>()) { mirror::Class* klass = obj->AsClass<kVerifyNone, kWithoutReadBarrier>(); FixupObjectAdapter visitor(boot_image_, boot_oat_, app_image_, app_oat_); - klass->FixupNativePointers<kVerifyNone, kWithoutReadBarrier>(klass, sizeof(void*), visitor); + klass->FixupNativePointers<kVerifyNone, kWithoutReadBarrier>(klass, pointer_size_, visitor); // Deal with the pointer arrays. Use the helper function since multiple classes can reference // the same arrays. VisitPointerArray(klass->GetVTable<kVerifyNone, kWithoutReadBarrier>(), visitor); @@ -832,6 +834,7 @@ class FixupObjectVisitor : public FixupVisitor { } private: + const size_t pointer_size_; gc::accounting::ContinuousSpaceBitmap* const pointer_array_visited_; }; @@ -850,7 +853,8 @@ class ForwardObjectAdapter { class ForwardCodeAdapter { public: - ALWAYS_INLINE ForwardCodeAdapter(const FixupVisitor* visitor) : visitor_(visitor) {} + ALWAYS_INLINE ForwardCodeAdapter(const FixupVisitor* visitor) + : visitor_(visitor) {} template <typename T> ALWAYS_INLINE T* operator()(T* src) const { @@ -864,19 +868,21 @@ class ForwardCodeAdapter { class FixupArtMethodVisitor : public FixupVisitor, public ArtMethodVisitor { public: template<typename... Args> - explicit FixupArtMethodVisitor(bool fixup_heap_objects, Args... args) + explicit FixupArtMethodVisitor(bool fixup_heap_objects, size_t pointer_size, Args... args) : FixupVisitor(args...), - fixup_heap_objects_(fixup_heap_objects) {} + fixup_heap_objects_(fixup_heap_objects), + pointer_size_(pointer_size) {} virtual void Visit(ArtMethod* method) NO_THREAD_SAFETY_ANALYSIS { if (fixup_heap_objects_) { - method->UpdateObjectsForImageRelocation(ForwardObjectAdapter(this)); + method->UpdateObjectsForImageRelocation(ForwardObjectAdapter(this), pointer_size_); } - method->UpdateEntrypoints<kWithoutReadBarrier>(ForwardCodeAdapter(this)); + method->UpdateEntrypoints<kWithoutReadBarrier>(ForwardCodeAdapter(this), pointer_size_); } private: const bool fixup_heap_objects_; + const size_t pointer_size_; }; class FixupArtFieldVisitor : public FixupVisitor, public ArtFieldVisitor { @@ -912,6 +918,7 @@ static bool RelocateInPlace(ImageHeader& image_header, uint32_t boot_image_end = 0; uint32_t boot_oat_begin = 0; uint32_t boot_oat_end = 0; + const size_t pointer_size = image_header.GetPointerSize(); gc::Heap* const heap = Runtime::Current()->GetHeap(); heap->GetBootImagesSize(&boot_image_begin, &boot_image_end, &boot_oat_begin, &boot_oat_end); CHECK_NE(boot_image_begin, boot_image_end) @@ -974,6 +981,7 @@ static bool RelocateInPlace(ImageHeader& image_header, target_base, image_header.GetImageSize())); FixupObjectVisitor fixup_object_visitor(visited_bitmap.get(), + pointer_size, boot_image, boot_oat, app_image, @@ -1023,10 +1031,10 @@ static bool RelocateInPlace(ImageHeader& image_header, dex_cache->SetResolvedMethods(new_methods); } for (size_t j = 0, num = dex_cache->NumResolvedMethods(); j != num; ++j) { - ArtMethod* orig = mirror::DexCache::GetElementPtrSize(new_methods, j, sizeof(void*)); + ArtMethod* orig = mirror::DexCache::GetElementPtrSize(new_methods, j, pointer_size); ArtMethod* copy = fixup_adapter.ForwardObject(orig); if (orig != copy) { - mirror::DexCache::SetElementPtrSize(new_methods, j, copy, sizeof(void*)); + mirror::DexCache::SetElementPtrSize(new_methods, j, copy, pointer_size); } } } @@ -1037,10 +1045,10 @@ static bool RelocateInPlace(ImageHeader& image_header, dex_cache->SetResolvedFields(new_fields); } for (size_t j = 0, num = dex_cache->NumResolvedFields(); j != num; ++j) { - ArtField* orig = mirror::DexCache::GetElementPtrSize(new_fields, j, sizeof(void*)); + ArtField* orig = mirror::DexCache::GetElementPtrSize(new_fields, j, pointer_size); ArtField* copy = fixup_adapter.ForwardObject(orig); if (orig != copy) { - mirror::DexCache::SetElementPtrSize(new_fields, j, copy, sizeof(void*)); + mirror::DexCache::SetElementPtrSize(new_fields, j, copy, pointer_size); } } } @@ -1049,11 +1057,16 @@ static bool RelocateInPlace(ImageHeader& image_header, { // Only touches objects in the app image, no need for mutator lock. TimingLogger::ScopedTiming timing("Fixup methods", &logger); - FixupArtMethodVisitor method_visitor(fixup_image, boot_image, boot_oat, app_image, app_oat); + FixupArtMethodVisitor method_visitor(fixup_image, + pointer_size, + boot_image, + boot_oat, + app_image, + app_oat); image_header.GetImageSection(ImageHeader::kSectionArtMethods).VisitPackedArtMethods( &method_visitor, target_base, - sizeof(void*)); + pointer_size); } if (fixup_image) { { @@ -1381,6 +1394,7 @@ OatFile* ImageSpace::OpenOatFile(const char* image_path, std::string* error_msg) image_header.GetOatDataBegin(), image_header.GetOatFileBegin(), !Runtime::Current()->IsAotCompiler(), + /*low_4gb*/false, nullptr, error_msg); if (oat_file == nullptr) { diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index 7155c79afb..033ea563b4 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -89,6 +89,7 @@ class OatFileBase : public OatFile { uint8_t* oat_file_begin, bool writable, bool executable, + bool low_4gb, const char* abs_dex_location, std::string* error_msg); @@ -102,6 +103,7 @@ class OatFileBase : public OatFile { uint8_t* oat_file_begin, bool writable, bool executable, + bool low_4gb, std::string* error_msg) = 0; bool ComputeFields(uint8_t* requested_base, @@ -133,6 +135,7 @@ OatFileBase* OatFileBase::OpenOatFile(const std::string& elf_filename, uint8_t* oat_file_begin, bool writable, bool executable, + bool low_4gb, const char* abs_dex_location, std::string* error_msg) { std::unique_ptr<OatFileBase> ret(new kOatFileBaseSubType(location, executable)); @@ -140,6 +143,7 @@ OatFileBase* OatFileBase::OpenOatFile(const std::string& elf_filename, oat_file_begin, writable, executable, + low_4gb, error_msg)) { return nullptr; } @@ -147,7 +151,6 @@ OatFileBase* OatFileBase::OpenOatFile(const std::string& elf_filename, if (!ret->ComputeFields(requested_base, elf_filename, error_msg)) { return nullptr; } - ret->PreSetup(elf_filename); if (!ret->Setup(abs_dex_location, error_msg)) { @@ -532,6 +535,7 @@ class DlOpenOatFile FINAL : public OatFileBase { uint8_t* oat_file_begin, bool writable, bool executable, + bool low_4gb, std::string* error_msg) OVERRIDE; // Ask the linker where it mmaped the file and notify our mmap wrapper of the regions. @@ -558,6 +562,7 @@ bool DlOpenOatFile::Load(const std::string& elf_filename, uint8_t* oat_file_begin, bool writable, bool executable, + bool low_4gb, std::string* error_msg) { // Use dlopen only when flagged to do so, and when it's OK to load things executable. // TODO: Also try when not executable? The issue here could be re-mapping as writable (as @@ -567,6 +572,10 @@ bool DlOpenOatFile::Load(const std::string& elf_filename, *error_msg = "DlOpen is disabled."; return false; } + if (low_4gb) { + *error_msg = "DlOpen does not support low 4gb loading."; + return false; + } if (writable) { *error_msg = "DlOpen does not support writable loading."; return false; @@ -702,6 +711,7 @@ class ElfOatFile FINAL : public OatFileBase { uint8_t* oat_file_begin, // Override base if not null bool writable, bool executable, + bool low_4gb, const char* abs_dex_location, std::string* error_msg); @@ -723,6 +733,7 @@ class ElfOatFile FINAL : public OatFileBase { uint8_t* oat_file_begin, // Override where the file is loaded to if not null bool writable, bool executable, + bool low_4gb, std::string* error_msg) OVERRIDE; void PreSetup(const std::string& elf_filename ATTRIBUTE_UNUSED) OVERRIDE { @@ -733,6 +744,7 @@ class ElfOatFile FINAL : public OatFileBase { uint8_t* oat_file_begin, // Override where the file is loaded to if not null bool writable, bool executable, + bool low_4gb, std::string* error_msg); private: @@ -748,11 +760,17 @@ ElfOatFile* ElfOatFile::OpenElfFile(File* file, uint8_t* oat_file_begin, // Override base if not null bool writable, bool executable, + bool low_4gb, const char* abs_dex_location, std::string* error_msg) { ScopedTrace trace("Open elf file " + location); std::unique_ptr<ElfOatFile> oat_file(new ElfOatFile(location, executable)); - bool success = oat_file->ElfFileOpen(file, oat_file_begin, writable, executable, error_msg); + bool success = oat_file->ElfFileOpen(file, + oat_file_begin, + writable, + low_4gb, + executable, + error_msg); if (!success) { CHECK(!error_msg->empty()); return nullptr; @@ -792,6 +810,7 @@ bool ElfOatFile::Load(const std::string& elf_filename, uint8_t* oat_file_begin, // Override where the file is loaded to if not null bool writable, bool executable, + bool low_4gb, std::string* error_msg) { ScopedTrace trace(__PRETTY_FUNCTION__); std::unique_ptr<File> file(OS::OpenFileForReading(elf_filename.c_str())); @@ -803,6 +822,7 @@ bool ElfOatFile::Load(const std::string& elf_filename, oat_file_begin, writable, executable, + low_4gb, error_msg); } @@ -810,19 +830,21 @@ bool ElfOatFile::ElfFileOpen(File* file, uint8_t* oat_file_begin, bool writable, bool executable, + bool low_4gb, std::string* error_msg) { ScopedTrace trace(__PRETTY_FUNCTION__); // TODO: rename requested_base to oat_data_begin elf_file_.reset(ElfFile::Open(file, writable, /*program_header_only*/true, + low_4gb, error_msg, oat_file_begin)); if (elf_file_ == nullptr) { DCHECK(!error_msg->empty()); return false; } - bool loaded = elf_file_->Load(executable, error_msg); + bool loaded = elf_file_->Load(executable, low_4gb, error_msg); DCHECK(loaded || !error_msg->empty()); return loaded; } @@ -870,6 +892,7 @@ OatFile* OatFile::Open(const std::string& filename, uint8_t* requested_base, uint8_t* oat_file_begin, bool executable, + bool low_4gb, const char* abs_dex_location, std::string* error_msg) { ScopedTrace trace("Open oat file " + location); @@ -885,15 +908,15 @@ OatFile* OatFile::Open(const std::string& filename, oat_file_begin, false, executable, + low_4gb, abs_dex_location, error_msg); if (with_dlopen != nullptr) { return with_dlopen; } if (kPrintDlOpenErrorMessage) { - LOG(ERROR) << "Failed to dlopen: " << *error_msg; + LOG(ERROR) << "Failed to dlopen: " << filename << " with error " << *error_msg; } - // If we aren't trying to execute, we just use our own ElfFile loader for a couple reasons: // // On target, dlopen may fail when compiling due to selinux restrictions on installd. @@ -913,6 +936,7 @@ OatFile* OatFile::Open(const std::string& filename, oat_file_begin, false, executable, + low_4gb, abs_dex_location, error_msg); return with_internal; @@ -929,6 +953,7 @@ OatFile* OatFile::OpenWritable(File* file, nullptr, true, false, + /*low_4gb*/false, abs_dex_location, error_msg); } @@ -944,6 +969,7 @@ OatFile* OatFile::OpenReadable(File* file, nullptr, false, false, + /*low_4gb*/false, abs_dex_location, error_msg); } diff --git a/runtime/oat_file.h b/runtime/oat_file.h index 1084253a88..7af77aee8f 100644 --- a/runtime/oat_file.h +++ b/runtime/oat_file.h @@ -64,6 +64,7 @@ class OatFile { uint8_t* requested_base, uint8_t* oat_file_begin, bool executable, + bool low_4gb, const char* abs_dex_location, std::string* error_msg); diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc index 90712c625c..cbc0ec6d28 100644 --- a/runtime/oat_file_assistant.cc +++ b/runtime/oat_file_assistant.cc @@ -815,8 +815,13 @@ const OatFile* OatFileAssistant::GetOdexFile() { const std::string& odex_file_name = *OdexFileName(); std::string error_msg; cached_odex_file_.reset(OatFile::Open(odex_file_name.c_str(), - odex_file_name.c_str(), nullptr, nullptr, load_executable_, - dex_location_.c_str(), &error_msg)); + odex_file_name.c_str(), + nullptr, + nullptr, + load_executable_, + /*low_4gb*/false, + dex_location_.c_str(), + &error_msg)); if (cached_odex_file_.get() == nullptr) { VLOG(oat) << "OatFileAssistant test for existing pre-compiled oat file " << odex_file_name << ": " << error_msg; @@ -846,8 +851,13 @@ const OatFile* OatFileAssistant::GetOatFile() { const std::string& oat_file_name = *OatFileName(); std::string error_msg; cached_oat_file_.reset(OatFile::Open(oat_file_name.c_str(), - oat_file_name.c_str(), nullptr, nullptr, load_executable_, - dex_location_.c_str(), &error_msg)); + oat_file_name.c_str(), + nullptr, + nullptr, + load_executable_, + /*low_4gb*/false, + dex_location_.c_str(), + &error_msg)); if (cached_oat_file_.get() == nullptr) { VLOG(oat) << "OatFileAssistant test for existing oat file " << oat_file_name << ": " << error_msg; diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc index 4541468cb3..046d8ae779 100644 --- a/runtime/oat_file_assistant_test.cc +++ b/runtime/oat_file_assistant_test.cc @@ -218,9 +218,14 @@ class OatFileAssistantTest : public CommonRuntimeTest { // Verify the odex file was generated as expected and really is // unrelocated. - std::unique_ptr<OatFile> odex_file(OatFile::Open( - odex_location.c_str(), odex_location.c_str(), nullptr, nullptr, - false, dex_location.c_str(), &error_msg)); + std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(), + odex_location.c_str(), + nullptr, + nullptr, + false, + /*low_4gb*/false, + dex_location.c_str(), + &error_msg)); ASSERT_TRUE(odex_file.get() != nullptr) << error_msg; const std::vector<gc::space::ImageSpace*> image_spaces = @@ -252,9 +257,14 @@ class OatFileAssistantTest : public CommonRuntimeTest { setenv("ANDROID_DATA", android_data_.c_str(), 1); // Verify the odex file was generated as expected. - std::unique_ptr<OatFile> odex_file(OatFile::Open( - odex_location.c_str(), odex_location.c_str(), nullptr, nullptr, - false, dex_location.c_str(), &error_msg)); + std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(), + odex_location.c_str(), + nullptr, + nullptr, + false, + /*low_4gb*/false, + dex_location.c_str(), + &error_msg)); ASSERT_TRUE(odex_file.get() != nullptr) << error_msg; EXPECT_TRUE(odex_file->IsPic()); } @@ -269,9 +279,14 @@ class OatFileAssistantTest : public CommonRuntimeTest { ASSERT_TRUE(OatFileAssistant::Dex2Oat(args, &error_msg)) << error_msg; // Verify the odex file was generated as expected. - std::unique_ptr<OatFile> odex_file(OatFile::Open( - odex_location.c_str(), odex_location.c_str(), nullptr, nullptr, - false, dex_location.c_str(), &error_msg)); + std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(), + odex_location.c_str(), + nullptr, + nullptr, + false, + /*low_4gb*/false, + dex_location.c_str(), + &error_msg)); ASSERT_TRUE(odex_file.get() != nullptr) << error_msg; EXPECT_TRUE(odex_file->IsExtractOnly()); EXPECT_EQ(odex_file->GetOatHeader().GetImageFileLocationOatChecksum(), 0u); @@ -290,9 +305,14 @@ class OatFileAssistantTest : public CommonRuntimeTest { ASSERT_TRUE(OatFileAssistant::Dex2Oat(args, &error_msg)) << error_msg; // Verify the odex file was generated as expected. - std::unique_ptr<OatFile> odex_file(OatFile::Open( - odex_location.c_str(), odex_location.c_str(), nullptr, nullptr, - false, dex_location.c_str(), &error_msg)); + std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(), + odex_location.c_str(), + nullptr, + nullptr, + false, + /*low_4gb*/false, + dex_location.c_str(), + &error_msg)); printf("error %s", error_msg.c_str()); ASSERT_TRUE(odex_file.get() != nullptr) << error_msg; EXPECT_TRUE(odex_file->IsProfileGuideCompiled()); diff --git a/runtime/runtime.cc b/runtime/runtime.cc index e95f2c539f..0dfb0cf921 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -810,7 +810,11 @@ static bool OpenDexFilesFromImage(const std::string& image_location, return false; } std::string error_msg; - std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file.release(), false, false, &error_msg)); + std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file.release(), + false, + false, + /*low_4gb*/false, + &error_msg)); if (elf_file.get() == nullptr) { return false; } |