diff options
| author | 2018-01-10 13:57:04 +0000 | |
|---|---|---|
| committer | 2018-01-10 13:57:04 +0000 | |
| commit | f4bf58d9b13972117c640ea1d7bfa6e6dfc189ea (patch) | |
| tree | a6bdf10f36796c1924e9dca6bfcf1477269c8073 | |
| parent | d6b7e8c63f8eca25460f56f66dcae15eaa897ff0 (diff) | |
| parent | ec2cdf4286921131a5f9b3ed12060657ec40f636 (diff) | |
Merge "Try to mmap vdex file within the address range of the ELF file."
| -rw-r--r-- | build/Android.gtest.mk | 5 | ||||
| -rw-r--r-- | compiler/linker/elf_builder.h | 21 | ||||
| -rw-r--r-- | dex2oat/dex2oat.cc | 4 | ||||
| -rw-r--r-- | dex2oat/linker/elf_writer.h | 8 | ||||
| -rw-r--r-- | dex2oat/linker/elf_writer_quick.cc | 9 | ||||
| -rw-r--r-- | dex2oat/linker/image_test.h | 3 | ||||
| -rw-r--r-- | dex2oat/linker/oat_writer.h | 4 | ||||
| -rw-r--r-- | dex2oat/linker/oat_writer_test.cc | 3 | ||||
| -rw-r--r-- | oatdump/oatdump.cc | 3 | ||||
| -rw-r--r-- | runtime/oat_file.cc | 68 | ||||
| -rw-r--r-- | runtime/oat_file.h | 13 | ||||
| -rw-r--r-- | runtime/oat_file_test.cc | 28 | ||||
| -rw-r--r-- | runtime/vdex_file.cc | 55 | ||||
| -rw-r--r-- | runtime/vdex_file.h | 48 |
14 files changed, 227 insertions, 45 deletions
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk index 1f36cb4e46..45f4e2d4d8 100644 --- a/build/Android.gtest.mk +++ b/build/Android.gtest.mk @@ -155,6 +155,11 @@ ART_GTEST_dex2oat_environment_tests_TARGET_DEPS := \ $(TARGET_CORE_IMAGE_interpreter_32) \ patchoatd-target +ART_GTEST_oat_file_test_HOST_DEPS := \ + $(ART_GTEST_dex2oat_environment_tests_HOST_DEPS) +ART_GTEST_oat_file_test_TARGET_DEPS := \ + $(ART_GTEST_dex2oat_environment_tests_TARGET_DEPS) + ART_GTEST_oat_file_assistant_test_HOST_DEPS := \ $(ART_GTEST_dex2oat_environment_tests_HOST_DEPS) ART_GTEST_oat_file_assistant_test_TARGET_DEPS := \ diff --git a/compiler/linker/elf_builder.h b/compiler/linker/elf_builder.h index aa3cd98595..5262ab6f3b 100644 --- a/compiler/linker/elf_builder.h +++ b/compiler/linker/elf_builder.h @@ -38,9 +38,10 @@ namespace linker { // Elf_Ehdr - The ELF header. // Elf_Phdr[] - Program headers for the linker. // .note.gnu.build-id - Optional build ID section (SHA-1 digest). -// .rodata - DEX files and oat metadata. +// .rodata - Oat metadata. // .text - Compiled code. // .bss - Zero-initialized writeable section. +// .dex - Reserved NOBITS space for dex-related data. // .MIPS.abiflags - MIPS specific section. // .dynstr - Names for .dynsym. // .dynsym - A few oat-specific dynamic symbols. @@ -503,6 +504,7 @@ class ElfBuilder FINAL { rodata_(this, ".rodata", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0), text_(this, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, nullptr, 0, kPageSize, 0), bss_(this, ".bss", SHT_NOBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0), + dex_(this, ".dex", SHT_NOBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0), dynstr_(this, ".dynstr", SHF_ALLOC, kPageSize), dynsym_(this, ".dynsym", SHT_DYNSYM, SHF_ALLOC, &dynstr_), hash_(this, ".hash", SHT_HASH, SHF_ALLOC, &dynsym_, 0, sizeof(Elf_Word), sizeof(Elf_Word)), @@ -525,6 +527,7 @@ class ElfBuilder FINAL { virtual_address_(0) { text_.phdr_flags_ = PF_R | PF_X; bss_.phdr_flags_ = PF_R | PF_W; + dex_.phdr_flags_ = PF_R; dynamic_.phdr_flags_ = PF_R | PF_W; dynamic_.phdr_type_ = PT_DYNAMIC; eh_frame_hdr_.phdr_type_ = PT_GNU_EH_FRAME; @@ -538,6 +541,7 @@ class ElfBuilder FINAL { Section* GetRoData() { return &rodata_; } Section* GetText() { return &text_; } Section* GetBss() { return &bss_; } + Section* GetDex() { return &dex_; } StringSection* GetStrTab() { return &strtab_; } SymbolSection* GetSymTab() { return &symtab_; } Section* GetEhFrame() { return &eh_frame_; } @@ -666,7 +670,8 @@ class ElfBuilder FINAL { Elf_Word text_size, Elf_Word bss_size, Elf_Word bss_methods_offset, - Elf_Word bss_roots_offset) { + Elf_Word bss_roots_offset, + Elf_Word dex_size) { std::string soname(elf_file_path); size_t directory_separator_pos = soname.rfind('/'); if (directory_separator_pos != std::string::npos) { @@ -679,6 +684,9 @@ class ElfBuilder FINAL { if (bss_size != 0) { bss_.AllocateVirtualMemory(bss_size); } + if (dex_size != 0) { + dex_.AllocateVirtualMemory(dex_size); + } if (isa_ == InstructionSet::kMips || isa_ == InstructionSet::kMips64) { abiflags_.AllocateVirtualMemory(abiflags_.GetSize()); } @@ -725,6 +733,14 @@ class ElfBuilder FINAL { Elf_Word bsslastword_address = bss_.GetAddress() + bss_size - 4; dynsym_.Add(oatbsslastword, &bss_, bsslastword_address, 4, STB_GLOBAL, STT_OBJECT); } + if (dex_size != 0u) { + Elf_Word oatdex = dynstr_.Add("oatdex"); + dynsym_.Add(oatdex, &dex_, dex_.GetAddress(), dex_size, STB_GLOBAL, STT_OBJECT); + Elf_Word oatdexlastword = dynstr_.Add("oatdexlastword"); + Elf_Word oatdexlastword_address = dex_.GetAddress() + dex_size - 4; + dynsym_.Add(oatdexlastword, &dex_, oatdexlastword_address, 4, STB_GLOBAL, STT_OBJECT); + } + Elf_Word soname_offset = dynstr_.Add(soname); // We do not really need a hash-table since there is so few entries. @@ -967,6 +983,7 @@ class ElfBuilder FINAL { Section rodata_; Section text_; Section bss_; + Section dex_; CachedStringSection dynstr_; SymbolSection dynsym_; CachedSection hash_; diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index dabe07f9ce..8d0d89ed5c 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -2015,8 +2015,8 @@ class Dex2Oat FINAL { text_size, oat_writer->GetBssSize(), oat_writer->GetBssMethodsOffset(), - oat_writer->GetBssRootsOffset()); - + oat_writer->GetBssRootsOffset(), + oat_writer->GetVdexSize()); if (IsImage()) { // Update oat layout. DCHECK(image_writer_ != nullptr); diff --git a/dex2oat/linker/elf_writer.h b/dex2oat/linker/elf_writer.h index 0eb36eda0f..a49112bfe6 100644 --- a/dex2oat/linker/elf_writer.h +++ b/dex2oat/linker/elf_writer.h @@ -55,11 +55,17 @@ class ElfWriter { virtual ~ElfWriter() {} virtual void Start() = 0; + // Prepares memory layout of the whole ELF file, and creates dynamic symbols + // which point to specific areas of interest (usually section begin and end). + // This is needed as multi-image needs to know the memory layout of all ELF + // files, before starting to write them. + // This method must be called before calling GetLoadedSize(). virtual void PrepareDynamicSection(size_t rodata_size, size_t text_size, size_t bss_size, size_t bss_methods_offset, - size_t bss_roots_offset) = 0; + size_t bss_roots_offset, + size_t dex_section_size) = 0; virtual void PrepareDebugInfo(const ArrayRef<const debug::MethodDebugInfo>& method_infos) = 0; virtual OutputStream* StartRoData() = 0; virtual void EndRoData(OutputStream* rodata) = 0; diff --git a/dex2oat/linker/elf_writer_quick.cc b/dex2oat/linker/elf_writer_quick.cc index aa64b7d59e..af11d5864d 100644 --- a/dex2oat/linker/elf_writer_quick.cc +++ b/dex2oat/linker/elf_writer_quick.cc @@ -99,7 +99,8 @@ class ElfWriterQuick FINAL : public ElfWriter { size_t text_size, size_t bss_size, size_t bss_methods_offset, - size_t bss_roots_offset) OVERRIDE; + size_t bss_roots_offset, + size_t dex_section_size) OVERRIDE; void PrepareDebugInfo(const ArrayRef<const debug::MethodDebugInfo>& method_infos) OVERRIDE; OutputStream* StartRoData() OVERRIDE; void EndRoData(OutputStream* rodata) OVERRIDE; @@ -183,7 +184,8 @@ void ElfWriterQuick<ElfTypes>::PrepareDynamicSection(size_t rodata_size, size_t text_size, size_t bss_size, size_t bss_methods_offset, - size_t bss_roots_offset) { + size_t bss_roots_offset, + size_t dex_section_size) { DCHECK_EQ(rodata_size_, 0u); rodata_size_ = rodata_size; DCHECK_EQ(text_size_, 0u); @@ -195,7 +197,8 @@ void ElfWriterQuick<ElfTypes>::PrepareDynamicSection(size_t rodata_size, text_size_, bss_size_, bss_methods_offset, - bss_roots_offset); + bss_roots_offset, + dex_section_size); } template <typename ElfTypes> diff --git a/dex2oat/linker/image_test.h b/dex2oat/linker/image_test.h index 85145d3d64..067111824a 100644 --- a/dex2oat/linker/image_test.h +++ b/dex2oat/linker/image_test.h @@ -316,7 +316,8 @@ inline void CompilationHelper::Compile(CompilerDriver* driver, text_size, oat_writer->GetBssSize(), oat_writer->GetBssMethodsOffset(), - oat_writer->GetBssRootsOffset()); + oat_writer->GetBssRootsOffset(), + oat_writer->GetVdexSize()); writer->UpdateOatFileLayout(i, elf_writer->GetLoadedSize(), diff --git a/dex2oat/linker/oat_writer.h b/dex2oat/linker/oat_writer.h index ba29e3b3a2..c9deea9a4b 100644 --- a/dex2oat/linker/oat_writer.h +++ b/dex2oat/linker/oat_writer.h @@ -230,6 +230,10 @@ class OatWriter { return bss_roots_offset_; } + size_t GetVdexSize() const { + return vdex_size_; + } + size_t GetOatDataOffset() const { return oat_data_offset_; } diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc index 488806092b..99bc1adabb 100644 --- a/dex2oat/linker/oat_writer_test.cc +++ b/dex2oat/linker/oat_writer_test.cc @@ -219,7 +219,8 @@ class OatTest : public CommonCompilerTest { text_size, oat_writer.GetBssSize(), oat_writer.GetBssMethodsOffset(), - oat_writer.GetBssRootsOffset()); + oat_writer.GetBssRootsOffset(), + oat_writer.GetVdexSize()); std::unique_ptr<BufferedOutputStream> vdex_out = std::make_unique<BufferedOutputStream>(std::make_unique<FileOutputStream>(vdex_file)); diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index ca8077fea1..6668dace89 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -171,7 +171,8 @@ class OatSymbolizer FINAL { text_size, oat_file_->BssSize(), oat_file_->BssMethodsOffset(), - oat_file_->BssRootsOffset()); + oat_file_->BssRootsOffset(), + oat_file_->VdexSize()); builder_->WriteDynamicSection(); const OatHeader& oat_header = oat_file_->GetOatHeader(); diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index df07a191bc..8548d2c67d 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -194,10 +194,6 @@ OatFileBase* OatFileBase::OpenOatFile(const std::string& vdex_filename, ret->PreLoad(); - if (!ret->LoadVdex(vdex_filename, writable, low_4gb, error_msg)) { - return nullptr; - } - if (!ret->Load(elf_filename, oat_file_begin, writable, @@ -211,6 +207,10 @@ OatFileBase* OatFileBase::OpenOatFile(const std::string& vdex_filename, return nullptr; } + if (!ret->LoadVdex(vdex_filename, writable, low_4gb, error_msg)) { + return nullptr; + } + ret->PreSetup(elf_filename); if (!ret->Setup(abs_dex_location, error_msg)) { @@ -234,10 +234,6 @@ OatFileBase* OatFileBase::OpenOatFile(int vdex_fd, std::string* error_msg) { std::unique_ptr<OatFileBase> ret(new kOatFileBaseSubType(oat_location, executable)); - if (!ret->LoadVdex(vdex_fd, vdex_location, writable, low_4gb, error_msg)) { - return nullptr; - } - if (!ret->Load(oat_fd, oat_file_begin, writable, @@ -251,6 +247,10 @@ OatFileBase* OatFileBase::OpenOatFile(int vdex_fd, return nullptr; } + if (!ret->LoadVdex(vdex_fd, vdex_location, writable, low_4gb, error_msg)) { + return nullptr; + } + ret->PreSetup(oat_location); if (!ret->Setup(abs_dex_location, error_msg)) { @@ -264,7 +264,14 @@ bool OatFileBase::LoadVdex(const std::string& vdex_filename, bool writable, bool low_4gb, std::string* error_msg) { - vdex_ = VdexFile::Open(vdex_filename, writable, low_4gb, /* unquicken*/ false, error_msg); + vdex_ = VdexFile::OpenAtAddress(vdex_begin_, + vdex_end_ - vdex_begin_, + true /* mmap_reuse */, + vdex_filename, + writable, + low_4gb, + /* unquicken*/ false, + error_msg); if (vdex_.get() == nullptr) { *error_msg = StringPrintf("Failed to load vdex file '%s' %s", vdex_filename.c_str(), @@ -285,13 +292,16 @@ bool OatFileBase::LoadVdex(int vdex_fd, if (rc == -1) { PLOG(WARNING) << "Failed getting length of vdex file"; } else { - vdex_ = VdexFile::Open(vdex_fd, - s.st_size, - vdex_filename, - writable, - low_4gb, - false /* unquicken */, - error_msg); + vdex_ = VdexFile::OpenAtAddress(vdex_begin_, + vdex_end_ - vdex_begin_, + true /* mmap_reuse */, + vdex_fd, + s.st_size, + vdex_filename, + writable, + low_4gb, + false /* unquicken */, + error_msg); if (vdex_.get() == nullptr) { *error_msg = "Failed opening vdex file."; return false; @@ -339,7 +349,7 @@ bool OatFileBase::ComputeFields(uint8_t* requested_base, } else { bss_end_ = const_cast<uint8_t*>(FindDynamicSymbolAddress("oatbsslastword", &symbol_error_msg)); if (bss_end_ == nullptr) { - *error_msg = StringPrintf("Failed to find oatbasslastword symbol in '%s'", file_path.c_str()); + *error_msg = StringPrintf("Failed to find oatbsslastword symbol in '%s'", file_path.c_str()); return false; } // Readjust to be non-inclusive upper bound. @@ -351,6 +361,20 @@ bool OatFileBase::ComputeFields(uint8_t* requested_base, bss_roots_ = const_cast<uint8_t*>(FindDynamicSymbolAddress("oatbssroots", &symbol_error_msg)); } + vdex_begin_ = const_cast<uint8_t*>(FindDynamicSymbolAddress("oatdex", &symbol_error_msg)); + if (vdex_begin_ == nullptr) { + // No .vdex section. + vdex_end_ = nullptr; + } else { + vdex_end_ = const_cast<uint8_t*>(FindDynamicSymbolAddress("oatdexlastword", &symbol_error_msg)); + if (vdex_end_ == nullptr) { + *error_msg = StringPrintf("Failed to find oatdexlastword symbol in '%s'", file_path.c_str()); + return false; + } + // Readjust to be non-inclusive upper bound. + vdex_end_ += sizeof(uint32_t); + } + return true; } @@ -1441,6 +1465,8 @@ OatFile::OatFile(const std::string& location, bool is_executable) bss_methods_(nullptr), bss_roots_(nullptr), is_executable_(is_executable), + vdex_begin_(nullptr), + vdex_end_(nullptr), secondary_lookup_lock_("OatFile secondary lookup lock", kOatFileSecondaryLookupLock) { CHECK(!location_.empty()); } @@ -1471,6 +1497,14 @@ const uint8_t* OatFile::BssEnd() const { return bss_end_; } +const uint8_t* OatFile::VdexBegin() const { + return vdex_begin_; +} + +const uint8_t* OatFile::VdexEnd() const { + return vdex_end_; +} + const uint8_t* OatFile::DexBegin() const { return vdex_->Begin(); } diff --git a/runtime/oat_file.h b/runtime/oat_file.h index 02318b68b7..e9f7edca61 100644 --- a/runtime/oat_file.h +++ b/runtime/oat_file.h @@ -279,6 +279,10 @@ class OatFile { return BssEnd() - BssBegin(); } + size_t VdexSize() const { + return VdexEnd() - VdexBegin(); + } + size_t BssMethodsOffset() const { // Note: This is used only for symbolizer and needs to return a valid .bss offset. return (bss_methods_ != nullptr) ? bss_methods_ - BssBegin() : BssRootsOffset(); @@ -299,6 +303,9 @@ class OatFile { const uint8_t* BssBegin() const; const uint8_t* BssEnd() const; + const uint8_t* VdexBegin() const; + const uint8_t* VdexEnd() const; + const uint8_t* DexBegin() const; const uint8_t* DexEnd() const; @@ -358,6 +365,12 @@ class OatFile { // Was this oat_file loaded executable? const bool is_executable_; + // Pointer to the .vdex section, if present, otherwise null. + uint8_t* vdex_begin_; + + // Pointer to the end of the .vdex section, if present, otherwise null. + uint8_t* vdex_end_; + // Owning storage for the OatDexFile objects. std::vector<const OatDexFile*> oat_dex_files_storage_; diff --git a/runtime/oat_file_test.cc b/runtime/oat_file_test.cc index 7bf0f84596..8d864018ab 100644 --- a/runtime/oat_file_test.cc +++ b/runtime/oat_file_test.cc @@ -21,11 +21,13 @@ #include <gtest/gtest.h> #include "common_runtime_test.h" +#include "dexopt_test.h" #include "scoped_thread_state_change-inl.h" +#include "vdex_file.h" namespace art { -class OatFileTest : public CommonRuntimeTest { +class OatFileTest : public DexoptTest { }; TEST_F(OatFileTest, ResolveRelativeEncodedDexLocation) { @@ -62,4 +64,28 @@ TEST_F(OatFileTest, ResolveRelativeEncodedDexLocation) { "/data/app/foo/base.apk", "o/base.apk")); } +TEST_F(OatFileTest, LoadOat) { + std::string dex_location = GetScratchDir() + "/LoadOat.jar"; + + Copy(GetDexSrc1(), dex_location); + GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed); + + std::string oat_location; + std::string error_msg; + ASSERT_TRUE(OatFileAssistant::DexLocationToOatFilename( + dex_location, kRuntimeISA, &oat_location, &error_msg)) << error_msg; + std::unique_ptr<OatFile> odex_file(OatFile::Open(oat_location.c_str(), + oat_location.c_str(), + nullptr, + nullptr, + false, + /*low_4gb*/false, + dex_location.c_str(), + &error_msg)); + ASSERT_TRUE(odex_file.get() != nullptr); + + // Check that the vdex file was loaded in the reserved space of odex file. + EXPECT_EQ(odex_file->GetVdexFile()->Begin(), odex_file->VdexBegin()); +} + } // namespace art diff --git a/runtime/vdex_file.cc b/runtime/vdex_file.cc index a53556ffcc..b6dd2f0123 100644 --- a/runtime/vdex_file.cc +++ b/runtime/vdex_file.cc @@ -57,11 +57,14 @@ VdexFile::Header::Header(uint32_t number_of_dex_files, DCHECK(IsVersionValid()); } -std::unique_ptr<VdexFile> VdexFile::Open(const std::string& vdex_filename, - bool writable, - bool low_4gb, - bool unquicken, - std::string* error_msg) { +std::unique_ptr<VdexFile> VdexFile::OpenAtAddress(uint8_t* mmap_addr, + size_t mmap_size, + bool mmap_reuse, + const std::string& vdex_filename, + bool writable, + bool low_4gb, + bool unquicken, + std::string* error_msg) { if (!OS::FileExists(vdex_filename.c_str())) { *error_msg = "File " + vdex_filename + " does not exist."; return nullptr; @@ -85,23 +88,47 @@ std::unique_ptr<VdexFile> VdexFile::Open(const std::string& vdex_filename, return nullptr; } - return Open(vdex_file->Fd(), vdex_length, vdex_filename, writable, low_4gb, unquicken, error_msg); + return OpenAtAddress(mmap_addr, + mmap_size, + mmap_reuse, + vdex_file->Fd(), + vdex_length, + vdex_filename, + writable, + low_4gb, + unquicken, + error_msg); } -std::unique_ptr<VdexFile> VdexFile::Open(int file_fd, - size_t vdex_length, - const std::string& vdex_filename, - bool writable, - bool low_4gb, - bool unquicken, - std::string* error_msg) { - std::unique_ptr<MemMap> mmap(MemMap::MapFile( +std::unique_ptr<VdexFile> VdexFile::OpenAtAddress(uint8_t* mmap_addr, + size_t mmap_size, + bool mmap_reuse, + int file_fd, + size_t vdex_length, + const std::string& vdex_filename, + bool writable, + bool low_4gb, + bool unquicken, + std::string* error_msg) { + if (low_4gb) { + LOG(WARNING) << "Can not mmap vdex in low 4GB"; // TODO: Implement in MemMap. + mmap_addr = nullptr; + mmap_reuse = false; + } + if (mmap_addr != nullptr && mmap_size < vdex_length) { + LOG(WARNING) << "Insufficient pre-allocated space to mmap vdex."; + mmap_addr = nullptr; + mmap_reuse = false; + } + std::unique_ptr<MemMap> mmap(MemMap::MapFileAtAddress( + mmap_addr, vdex_length, (writable || unquicken) ? PROT_READ | PROT_WRITE : PROT_READ, unquicken ? MAP_PRIVATE : MAP_SHARED, file_fd, 0 /* start offset */, low_4gb, + mmap_reuse, vdex_filename.c_str(), error_msg)); if (mmap == nullptr) { diff --git a/runtime/vdex_file.h b/runtime/vdex_file.h index 2d9fcab59c..f78335d347 100644 --- a/runtime/vdex_file.h +++ b/runtime/vdex_file.h @@ -102,11 +102,44 @@ class VdexFile { explicit VdexFile(MemMap* mmap) : mmap_(mmap) {} // Returns nullptr if the vdex file cannot be opened or is not valid. + // The mmap_* parameters can be left empty (nullptr/0/false) to allocate at random address. + static std::unique_ptr<VdexFile> OpenAtAddress(uint8_t* mmap_addr, + size_t mmap_size, + bool mmap_reuse, + const std::string& vdex_filename, + bool writable, + bool low_4gb, + bool unquicken, + std::string* error_msg); + + // Returns nullptr if the vdex file cannot be opened or is not valid. + // The mmap_* parameters can be left empty (nullptr/0/false) to allocate at random address. + static std::unique_ptr<VdexFile> OpenAtAddress(uint8_t* mmap_addr, + size_t mmap_size, + bool mmap_reuse, + int file_fd, + size_t vdex_length, + const std::string& vdex_filename, + bool writable, + bool low_4gb, + bool unquicken, + std::string* error_msg); + + // Returns nullptr if the vdex file cannot be opened or is not valid. static std::unique_ptr<VdexFile> Open(const std::string& vdex_filename, bool writable, bool low_4gb, bool unquicken, - std::string* error_msg); + std::string* error_msg) { + return OpenAtAddress(nullptr, + 0, + false, + vdex_filename, + writable, + low_4gb, + unquicken, + error_msg); + } // Returns nullptr if the vdex file cannot be opened or is not valid. static std::unique_ptr<VdexFile> Open(int file_fd, @@ -115,7 +148,18 @@ class VdexFile { bool writable, bool low_4gb, bool unquicken, - std::string* error_msg); + std::string* error_msg) { + return OpenAtAddress(nullptr, + 0, + false, + file_fd, + vdex_length, + vdex_filename, + writable, + low_4gb, + unquicken, + error_msg); + } const uint8_t* Begin() const { return mmap_->Begin(); } const uint8_t* End() const { return mmap_->End(); } |