diff options
-rw-r--r-- | dex2oat/dex2oat_test.cc | 3 | ||||
-rw-r--r-- | dex2oat/linker/elf_writer_test.cc | 9 | ||||
-rw-r--r-- | libartbase/base/os.h | 28 | ||||
-rw-r--r-- | libartbase/base/os_linux.cc | 75 | ||||
-rw-r--r-- | libartbase/base/zip_archive.cc | 14 | ||||
-rw-r--r-- | libartbase/base/zip_archive.h | 10 | ||||
-rw-r--r-- | runtime/oat/elf_file.cc | 333 | ||||
-rw-r--r-- | runtime/oat/elf_file.h | 33 | ||||
-rw-r--r-- | runtime/oat/elf_file_impl.h | 33 | ||||
-rw-r--r-- | runtime/oat/oat_file.cc | 41 | ||||
-rw-r--r-- | runtime/oat/oat_file.h | 5 | ||||
-rw-r--r-- | test/generate-boot-image/Android.bp | 2 | ||||
-rw-r--r-- | tools/create_minidebuginfo/Android.bp | 2 |
13 files changed, 372 insertions, 216 deletions
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc index da97a4effd..31891fd2b5 100644 --- a/dex2oat/dex2oat_test.cc +++ b/dex2oat/dex2oat_test.cc @@ -2032,8 +2032,7 @@ TEST_F(Dex2oatTest, LoadOutOfDateOatFile) { /*low_4gb=*/false, &error_msg)); ASSERT_TRUE(elf_file != nullptr) << error_msg; - ASSERT_TRUE(elf_file->Load(file.get(), - /*executable=*/false, + ASSERT_TRUE(elf_file->Load(/*executable=*/false, /*low_4gb=*/false, /*reservation=*/nullptr, &error_msg)) diff --git a/dex2oat/linker/elf_writer_test.cc b/dex2oat/linker/elf_writer_test.cc index 913f865e8f..38eec45611 100644 --- a/dex2oat/linker/elf_writer_test.cc +++ b/dex2oat/linker/elf_writer_test.cc @@ -152,8 +152,7 @@ TEST_F(ElfWriterTest, dlsym) { &error_msg); CHECK(reservation.IsValid()) << error_msg; uint8_t* base = reservation.Begin(); - success = - ef->Load(file.get(), /*executable=*/false, /*low_4gb=*/false, &reservation, &error_msg); + success = ef->Load(/*executable=*/false, /*low_4gb=*/false, &reservation, &error_msg); CHECK(success) << error_msg; CHECK(!reservation.IsValid()); EXPECT_EQ(reinterpret_cast<uintptr_t>(dl_oatdata) + reinterpret_cast<uintptr_t>(base), @@ -253,11 +252,11 @@ TEST_F(ElfWriterTest, CheckDynamicSection) { /*low_4gb=*/false, &error_msg)); ASSERT_NE(ef.get(), nullptr) << error_msg; - ASSERT_TRUE(ef->Load(tmp_oat.GetFile(), - /*executable=*/false, + ASSERT_TRUE(ef->Load(/*executable=*/false, /*low_4gb=*/false, /*reservation=*/nullptr, - &error_msg)) << error_msg; + &error_msg)) + << error_msg; const uint8_t* oatdata_ptr = ef->FindDynamicSymbolAddress("oatdata"); ASSERT_NE(oatdata_ptr, nullptr); diff --git a/libartbase/base/os.h b/libartbase/base/os.h index cb71d211af..7880937949 100644 --- a/libartbase/base/os.h +++ b/libartbase/base/os.h @@ -18,6 +18,11 @@ #define ART_LIBARTBASE_BASE_OS_H_ #include <stdint.h> +#include <sys/types.h> + +#include <cstddef> +#include <memory> +#include <string> namespace unix_file { class FdFile; @@ -27,8 +32,15 @@ namespace art { using File = ::unix_file::FdFile; -// Interface to the underlying OS platform. +struct FileWithRange { + std::unique_ptr<File> file; + off_t start; + size_t length; + + static FileWithRange Invalid(); +}; +// Interface to the underlying OS platform. class OS { public: // Open an existing file with read only access. @@ -56,6 +68,20 @@ class OS { // Get the size of a file (or -1 if it does not exist). static int64_t GetFileSizeBytes(const char* name); + + // Open an existing file or an entry in a zip file with read only access. + // `name_and_zip_entry` should be either a path to an existing file, or a path to a zip file and + // the name of the zip entry, separated by `zip_separator`. + // `alignment` is the expected alignment of the specified zip entry, in bytes. Only applicable if + // `name_and_zip_entry` points to a zip entry. + // Returns `file` being the file at the specified path and the range being the entire range of the + // file, if `name_and_zip_entry` points to a file. Returns `file` being the zip file and the range + // being the range of the zip entry, if `name_and_zip_entry` points to a zip entry. Returns `file` + // being nullptr on failure. + static FileWithRange OpenFileDirectlyOrFromZip(const std::string& name_and_zip_entry, + const char* zip_separator, + size_t alignment, + std::string* error_msg); }; } // namespace art diff --git a/libartbase/base/os_linux.cc b/libartbase/base/os_linux.cc index 337c54f1d1..6ea200169e 100644 --- a/libartbase/base/os_linux.cc +++ b/libartbase/base/os_linux.cc @@ -14,21 +14,23 @@ * limitations under the License. */ -#include "os.h" - +#include <android-base/logging.h> #include <fcntl.h> #include <sys/stat.h> #include <sys/types.h> #include <cstddef> +#include <cstring> #include <memory> -#include <android-base/logging.h> - +#include "base/zip_archive.h" +#include "os.h" #include "unix_file/fd_file.h" namespace art { +FileWithRange FileWithRange::Invalid() { return {.file = nullptr, .start = 0, .length = 0}; } + File* OS::OpenFileForReading(const char* name) { return OpenFileWithFlags(name, O_RDONLY); } @@ -103,4 +105,69 @@ int64_t OS::GetFileSizeBytes(const char* name) { } } +FileWithRange OS::OpenFileDirectlyOrFromZip(const std::string& name_and_zip_entry, + const char* zip_separator, + size_t alignment, + std::string* error_msg) { + std::string filename = name_and_zip_entry; + std::string zip_entry_name; + size_t pos = filename.find(zip_separator); + if (pos != std::string::npos) { + zip_entry_name = filename.substr(pos + strlen(zip_separator)); + filename.resize(pos); + if (filename.empty() || zip_entry_name.empty()) { + *error_msg = ART_FORMAT("Malformed zip path '{}'", name_and_zip_entry); + return FileWithRange::Invalid(); + } + } + + std::unique_ptr<File> file(OS::OpenFileForReading(filename.c_str())); + if (file == nullptr) { + *error_msg = ART_FORMAT("Failed to open '{}' for reading: {}", filename, strerror(errno)); + return FileWithRange::Invalid(); + } + + off_t start = 0; + int64_t total_file_length = file->GetLength(); + if (total_file_length < 0) { + *error_msg = ART_FORMAT("Failed to get file length of '{}': {}", filename, strerror(errno)); + return FileWithRange::Invalid(); + } + size_t length = total_file_length; + + if (!zip_entry_name.empty()) { + std::unique_ptr<ZipArchive> zip_archive( + ZipArchive::OpenFromOwnedFd(file->Fd(), filename.c_str(), error_msg)); + if (zip_archive == nullptr) { + *error_msg = ART_FORMAT("Failed to open '{}' as zip", filename); + return FileWithRange::Invalid(); + } + std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(zip_entry_name.c_str(), error_msg)); + if (zip_entry == nullptr) { + *error_msg = ART_FORMAT("Failed to find entry '{}' in zip '{}'", zip_entry_name, filename); + return FileWithRange::Invalid(); + } + if (!zip_entry->IsUncompressed() || !zip_entry->IsAlignedTo(alignment)) { + *error_msg = + ART_FORMAT("The entry '{}' in zip '{}' must be uncompressed and aligned to {} bytes", + zip_entry_name, + filename, + alignment); + return FileWithRange::Invalid(); + } + start = zip_entry->GetOffset(); + length = zip_entry->GetUncompressedLength(); + if (start + length > static_cast<size_t>(total_file_length)) { + *error_msg = ART_FORMAT( + "Invalid zip entry offset or length (offset: {}, length: {}, total_file_length: {})", + start, + length, + total_file_length); + return FileWithRange::Invalid(); + } + } + + return {.file = std::move(file), .start = start, .length = length}; +} + } // namespace art diff --git a/libartbase/base/zip_archive.cc b/libartbase/base/zip_archive.cc index 5e441a2aab..f90a92d769 100644 --- a/libartbase/base/zip_archive.cc +++ b/libartbase/base/zip_archive.cc @@ -37,23 +37,19 @@ static constexpr const bool kDebugZipMapDirectly = false; using android::base::StringPrintf; -uint32_t ZipEntry::GetUncompressedLength() { - return zip_entry_->uncompressed_length; -} +uint32_t ZipEntry::GetUncompressedLength() const { return zip_entry_->uncompressed_length; } -uint32_t ZipEntry::GetCrc32() { - return zip_entry_->crc32; -} +uint32_t ZipEntry::GetCrc32() const { return zip_entry_->crc32; } -bool ZipEntry::IsUncompressed() { - return zip_entry_->method == kCompressStored; -} +bool ZipEntry::IsUncompressed() const { return zip_entry_->method == kCompressStored; } bool ZipEntry::IsAlignedTo(size_t alignment) const { DCHECK(IsPowerOfTwo(alignment)) << alignment; return IsAlignedParam(zip_entry_->offset, static_cast<int>(alignment)); } +off_t ZipEntry::GetOffset() const { return zip_entry_->offset; } + ZipEntry::~ZipEntry() { delete zip_entry_; } diff --git a/libartbase/base/zip_archive.h b/libartbase/base/zip_archive.h index 741a0a1655..8991a572ab 100644 --- a/libartbase/base/zip_archive.h +++ b/libartbase/base/zip_archive.h @@ -18,11 +18,10 @@ #define ART_LIBARTBASE_BASE_ZIP_ARCHIVE_H_ #include <stdint.h> + #include <memory> #include <string> -#include <android-base/logging.h> - #include "globals.h" #include "mem_map.h" #include "os.h" @@ -67,11 +66,12 @@ class ZipEntry { std::string* error_msg, size_t alignment); - uint32_t GetUncompressedLength(); - uint32_t GetCrc32(); + uint32_t GetUncompressedLength() const; + uint32_t GetCrc32() const; - bool IsUncompressed(); + bool IsUncompressed() const; bool IsAlignedTo(size_t alignment) const; + off_t GetOffset() const; private: ZipEntry(ZipArchiveHandle handle, diff --git a/runtime/oat/elf_file.cc b/runtime/oat/elf_file.cc index 3bcecc5205..6db09f2d1e 100644 --- a/runtime/oat/elf_file.cc +++ b/runtime/oat/elf_file.cc @@ -21,6 +21,7 @@ #include <sys/types.h> #include <unistd.h> +#include <cstddef> #include <memory> #include "android-base/stringprintf.h" @@ -36,83 +37,65 @@ namespace art HIDDEN { using android::base::StringPrintf; template <typename ElfTypes> -ElfFileImpl<ElfTypes>::ElfFileImpl(File* file) - : header_(nullptr), - section_headers_start_(nullptr), - dynamic_program_header_(nullptr), - dynamic_section_start_(nullptr), - symtab_section_start_(nullptr), - dynsym_section_start_(nullptr), - strtab_section_start_(nullptr), - dynstr_section_start_(nullptr), - hash_section_start_(nullptr) { - CHECK(file != nullptr); -} - -template <typename ElfTypes> ElfFileImpl<ElfTypes>* ElfFileImpl<ElfTypes>::Open(File* file, + off_t start, + size_t file_length, + const std::string& file_location, bool low_4gb, std::string* error_msg) { - std::unique_ptr<ElfFileImpl<ElfTypes>> elf_file(new ElfFileImpl<ElfTypes>(file)); - if (!elf_file->Setup(file, PROT_READ, MAP_PRIVATE, low_4gb, error_msg)) { + std::unique_ptr<ElfFileImpl<ElfTypes>> elf_file( + new ElfFileImpl<ElfTypes>(file, start, file_length, file_location)); + if (!elf_file->Setup(low_4gb, error_msg)) { return nullptr; } return elf_file.release(); } template <typename ElfTypes> -bool ElfFileImpl<ElfTypes>::Setup(File* file, - 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; - *error_msg = StringPrintf("Failed to get length of file: '%s' fd=%d: %s", - file->GetPath().c_str(), file->Fd(), strerror(errno)); - return false; - } - size_t file_length = static_cast<size_t>(temp_file_length); - if (file_length < sizeof(Elf_Ehdr)) { - *error_msg = StringPrintf("File size of %zd bytes not large enough to contain ELF header of " - "%zd bytes: '%s'", file_length, sizeof(Elf_Ehdr), - file->GetPath().c_str()); +bool ElfFileImpl<ElfTypes>::Setup(bool low_4gb, std::string* error_msg) { + if (file_length_ < sizeof(Elf_Ehdr)) { + *error_msg = StringPrintf( + "File size of %zd bytes not large enough to contain ELF header of " + "%zd bytes: '%s'", + file_length_, + sizeof(Elf_Ehdr), + file_location_.c_str()); return false; } + int prot = PROT_READ; + int flags = MAP_PRIVATE; + // first just map ELF header to get program header size information size_t elf_header_size = sizeof(Elf_Ehdr); - if (!SetMap(file, - MemMap::MapFile(elf_header_size, + if (!SetMap(MemMap::MapFile(elf_header_size, prot, flags, - file->Fd(), - 0, + file_->Fd(), + start_, low_4gb, - file->GetPath().c_str(), + file_location_.c_str(), error_msg), error_msg)) { return false; } // then remap to cover program header size_t program_header_size = header_->e_phoff + (header_->e_phentsize * header_->e_phnum); - if (file_length < program_header_size) { + if (file_length_ < program_header_size) { *error_msg = StringPrintf( "File size of %zd bytes not large enough to contain ELF program header of %zd bytes: '%s'", - file_length, + file_length_, sizeof(Elf_Ehdr), - file->GetPath().c_str()); + file_location_.c_str()); return false; } - if (!SetMap(file, - MemMap::MapFile(program_header_size, + if (!SetMap(MemMap::MapFile(program_header_size, prot, flags, - file->Fd(), - 0, + file_->Fd(), + start_, low_4gb, - file->GetPath().c_str(), + file_location_.c_str(), error_msg), error_msg)) { *error_msg = StringPrintf("Failed to map ELF program headers: %s", error_msg->c_str()); @@ -125,18 +108,18 @@ bool ElfFileImpl<ElfTypes>::Setup(File* file, } template <typename ElfTypes> -bool ElfFileImpl<ElfTypes>::CheckSectionsExist(File* file, std::string* error_msg) const { +bool ElfFileImpl<ElfTypes>::CheckSectionsExist(std::string* error_msg) const { // This is redundant, but defensive. if (dynamic_program_header_ == nullptr) { *error_msg = StringPrintf("Failed to find PT_DYNAMIC program header in ELF file: '%s'", - file->GetPath().c_str()); + file_location_.c_str()); return false; } // Need a dynamic section. This is redundant, but defensive. if (dynamic_section_start_ == nullptr) { - *error_msg = StringPrintf("Failed to find dynamic section in ELF file: '%s'", - file->GetPath().c_str()); + *error_msg = + StringPrintf("Failed to find dynamic section in ELF file: '%s'", file_location_.c_str()); return false; } @@ -145,36 +128,35 @@ bool ElfFileImpl<ElfTypes>::CheckSectionsExist(File* file, std::string* error_ms if (symtab_section_start_ != nullptr) { // When there's a symtab, there should be a strtab. if (strtab_section_start_ == nullptr) { - *error_msg = StringPrintf("No strtab for symtab in ELF file: '%s'", file->GetPath().c_str()); + *error_msg = StringPrintf("No strtab for symtab in ELF file: '%s'", file_location_.c_str()); return false; } } // We always need a dynstr & dynsym. if (dynstr_section_start_ == nullptr) { - *error_msg = StringPrintf("No dynstr in ELF file: '%s'", file->GetPath().c_str()); + *error_msg = StringPrintf("No dynstr in ELF file: '%s'", file_location_.c_str()); return false; } if (dynsym_section_start_ == nullptr) { - *error_msg = StringPrintf("No dynsym in ELF file: '%s'", file->GetPath().c_str()); + *error_msg = StringPrintf("No dynsym in ELF file: '%s'", file_location_.c_str()); return false; } // Need a hash section for dynamic symbol lookup. if (hash_section_start_ == nullptr) { - *error_msg = StringPrintf("Failed to find hash section in ELF file: '%s'", - file->GetPath().c_str()); + *error_msg = + StringPrintf("Failed to find hash section in ELF file: '%s'", file_location_.c_str()); return false; } // We'd also like to confirm a shstrtab. This is usually the last in an oat file, and a good // indicator of whether writing was successful (or the process crashed and left garbage). // It might not be mapped, but we can compare against the file size. - int64_t offset = static_cast<int64_t>(GetHeader().e_shoff + - (GetHeader().e_shstrndx * GetHeader().e_shentsize)); - if (offset >= file->GetLength()) { + size_t offset = GetHeader().e_shoff + (GetHeader().e_shstrndx * GetHeader().e_shentsize); + if (offset >= file_length_) { *error_msg = - StringPrintf("Shstrtab is not in the mapped ELF file: '%s'", file->GetPath().c_str()); + StringPrintf("Shstrtab is not in the mapped ELF file: '%s'", file_location_.c_str()); return false; } @@ -182,15 +164,15 @@ bool ElfFileImpl<ElfTypes>::CheckSectionsExist(File* file, std::string* error_ms } template <typename ElfTypes> -bool ElfFileImpl<ElfTypes>::SetMap(File* file, MemMap&& map, std::string* error_msg) { +bool ElfFileImpl<ElfTypes>::SetMap(MemMap&& map, std::string* error_msg) { if (!map.IsValid()) { // MemMap::Open should have already set an error. DCHECK(!error_msg->empty()); return false; } map_ = std::move(map); - CHECK(map_.IsValid()) << file->GetPath(); - CHECK(map_.Begin() != nullptr) << file->GetPath(); + CHECK(map_.IsValid()) << file_location_; + CHECK(map_.Begin() != nullptr) << file_location_; header_ = reinterpret_cast<Elf_Ehdr*>(map_.Begin()); if ((ELFMAG0 != header_->e_ident[EI_MAG0]) @@ -198,8 +180,11 @@ bool ElfFileImpl<ElfTypes>::SetMap(File* file, MemMap&& map, std::string* error_ || (ELFMAG2 != header_->e_ident[EI_MAG2]) || (ELFMAG3 != header_->e_ident[EI_MAG3])) { *error_msg = StringPrintf("Failed to find ELF magic value %d %d %d %d in %s, found %d %d %d %d", - ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3, - file->GetPath().c_str(), + ELFMAG0, + ELFMAG1, + ELFMAG2, + ELFMAG3, + file_location_.c_str(), header_->e_ident[EI_MAG0], header_->e_ident[EI_MAG1], header_->e_ident[EI_MAG2], @@ -210,90 +195,90 @@ bool ElfFileImpl<ElfTypes>::SetMap(File* file, MemMap&& map, std::string* error_ if (elf_class != header_->e_ident[EI_CLASS]) { *error_msg = StringPrintf("Failed to find expected EI_CLASS value %d in %s, found %d", elf_class, - file->GetPath().c_str(), + file_location_.c_str(), header_->e_ident[EI_CLASS]); return false; } if (ELFDATA2LSB != header_->e_ident[EI_DATA]) { *error_msg = StringPrintf("Failed to find expected EI_DATA value %d in %s, found %d", ELFDATA2LSB, - file->GetPath().c_str(), + file_location_.c_str(), header_->e_ident[EI_CLASS]); return false; } if (EV_CURRENT != header_->e_ident[EI_VERSION]) { *error_msg = StringPrintf("Failed to find expected EI_VERSION value %d in %s, found %d", EV_CURRENT, - file->GetPath().c_str(), + file_location_.c_str(), header_->e_ident[EI_CLASS]); return false; } if (ET_DYN != header_->e_type) { *error_msg = StringPrintf("Failed to find expected e_type value %d in %s, found %d", ET_DYN, - file->GetPath().c_str(), + file_location_.c_str(), header_->e_type); return false; } if (EV_CURRENT != header_->e_version) { *error_msg = StringPrintf("Failed to find expected e_version value %d in %s, found %d", EV_CURRENT, - file->GetPath().c_str(), + file_location_.c_str(), header_->e_version); return false; } if (0 != header_->e_entry) { *error_msg = StringPrintf("Failed to find expected e_entry value %d in %s, found %d", 0, - file->GetPath().c_str(), + file_location_.c_str(), static_cast<int32_t>(header_->e_entry)); return false; } if (0 == header_->e_phoff) { - *error_msg = StringPrintf("Failed to find non-zero e_phoff value in %s", - file->GetPath().c_str()); + *error_msg = + StringPrintf("Failed to find non-zero e_phoff value in %s", file_location_.c_str()); return false; } if (0 == header_->e_shoff) { - *error_msg = StringPrintf("Failed to find non-zero e_shoff value in %s", - file->GetPath().c_str()); + *error_msg = + StringPrintf("Failed to find non-zero e_shoff value in %s", file_location_.c_str()); return false; } if (0 == header_->e_ehsize) { - *error_msg = StringPrintf("Failed to find non-zero e_ehsize value in %s", - file->GetPath().c_str()); + *error_msg = + StringPrintf("Failed to find non-zero e_ehsize value in %s", file_location_.c_str()); return false; } if (0 == header_->e_phentsize) { - *error_msg = StringPrintf("Failed to find non-zero e_phentsize value in %s", - file->GetPath().c_str()); + *error_msg = + StringPrintf("Failed to find non-zero e_phentsize value in %s", file_location_.c_str()); return false; } if (0 == header_->e_phnum) { - *error_msg = StringPrintf("Failed to find non-zero e_phnum value in %s", - file->GetPath().c_str()); + *error_msg = + StringPrintf("Failed to find non-zero e_phnum value in %s", file_location_.c_str()); return false; } if (0 == header_->e_shentsize) { - *error_msg = StringPrintf("Failed to find non-zero e_shentsize value in %s", - file->GetPath().c_str()); + *error_msg = + StringPrintf("Failed to find non-zero e_shentsize value in %s", file_location_.c_str()); return false; } if (0 == header_->e_shnum) { - *error_msg = StringPrintf("Failed to find non-zero e_shnum value in %s", - file->GetPath().c_str()); + *error_msg = + StringPrintf("Failed to find non-zero e_shnum value in %s", file_location_.c_str()); return false; } if (0 == header_->e_shstrndx) { - *error_msg = StringPrintf("Failed to find non-zero e_shstrndx value in %s", - file->GetPath().c_str()); + *error_msg = + StringPrintf("Failed to find non-zero e_shstrndx value in %s", file_location_.c_str()); return false; } if (header_->e_shstrndx >= header_->e_shnum) { *error_msg = StringPrintf("Failed to find e_shnum value %d less than %d in %s", header_->e_shstrndx, header_->e_shnum, - file->GetPath().c_str()); + file_location_.c_str()); return false; } return true; @@ -326,7 +311,7 @@ typename ElfTypes::Dyn* ElfFileImpl<ElfTypes>::GetDynamicSectionStart() const { template <typename ElfTypes> typename ElfTypes::Sym* ElfFileImpl<ElfTypes>::GetSymbolSectionStart( Elf_Word section_type) const { - CHECK(IsSymbolSectionType(section_type)) << file_path_ << " " << section_type; + CHECK(IsSymbolSectionType(section_type)) << file_location_ << " " << section_type; switch (section_type) { case SHT_SYMTAB: { return symtab_section_start_; @@ -346,7 +331,7 @@ typename ElfTypes::Sym* ElfFileImpl<ElfTypes>::GetSymbolSectionStart( template <typename ElfTypes> const char* ElfFileImpl<ElfTypes>::GetStringSectionStart( Elf_Word section_type) const { - CHECK(IsSymbolSectionType(section_type)) << file_path_ << " " << section_type; + CHECK(IsSymbolSectionType(section_type)) << file_location_ << " " << section_type; switch (section_type) { case SHT_SYMTAB: { return strtab_section_start_; @@ -364,7 +349,7 @@ const char* ElfFileImpl<ElfTypes>::GetStringSectionStart( template <typename ElfTypes> const char* ElfFileImpl<ElfTypes>::GetString(Elf_Word section_type, Elf_Word i) const { - CHECK(IsSymbolSectionType(section_type)) << file_path_ << " " << section_type; + CHECK(IsSymbolSectionType(section_type)) << file_location_ << " " << section_type; if (i == 0) { return nullptr; } @@ -422,7 +407,7 @@ typename ElfTypes::Word ElfFileImpl<ElfTypes>::GetProgramHeaderNum() const { template <typename ElfTypes> typename ElfTypes::Phdr* ElfFileImpl<ElfTypes>::GetProgramHeader(Elf_Word i) const { - CHECK_LT(i, GetProgramHeaderNum()) << file_path_; // Validity check for caller. + CHECK_LT(i, GetProgramHeaderNum()) << file_location_; // Validity check for caller. uint8_t* program_header = GetProgramHeadersStart() + (i * GetHeader().e_phentsize); CHECK_LT(program_header, End()); return reinterpret_cast<Elf_Phdr*>(program_header); @@ -515,8 +500,8 @@ bool ElfFileImpl<ElfTypes>::IsSymbolSectionType(Elf_Word section_type) { template <typename ElfTypes> typename ElfTypes::Word ElfFileImpl<ElfTypes>::GetSymbolNum(Elf_Shdr& section_header) const { CHECK(IsSymbolSectionType(section_header.sh_type)) - << file_path_ << " " << section_header.sh_type; - CHECK_NE(0U, section_header.sh_entsize) << file_path_; + << file_location_ << " " << section_header.sh_type; + CHECK_NE(0U, section_header.sh_entsize) << file_location_; return section_header.sh_size / section_header.sh_entsize; } @@ -536,7 +521,7 @@ typename ElfTypes::Word ElfFileImpl<ElfTypes>::GetDynamicNum() const { template <typename ElfTypes> typename ElfTypes::Dyn& ElfFileImpl<ElfTypes>::GetDynamic(Elf_Word i) const { - CHECK_LT(i, GetDynamicNum()) << file_path_; + CHECK_LT(i, GetDynamicNum()) << file_location_; return *(GetDynamicSectionStart() + i); } @@ -556,7 +541,7 @@ size_t ElfFileImpl<ElfTypes>::GetElfSegmentAlignmentFromFile() const { } return program_header->p_align; } - LOG(ERROR) << "No loadable segment found in ELF file " << file_path_; + LOG(ERROR) << "No loadable segment found in ELF file " << file_location_; return 0; } @@ -581,7 +566,7 @@ bool ElfFileImpl<ElfTypes>::GetLoadedAddressRange(/*out*/uint8_t** vaddr_begin, std::ostringstream oss; oss << "Program header #" << i << " has overflow in p_vaddr+p_memsz: 0x" << std::hex << program_header->p_vaddr << "+0x" << program_header->p_memsz << "=0x" << end_vaddr - << " in ELF file \"" << file_path_ << "\""; + << " in ELF file \"" << file_location_ << "\""; *error_msg = oss.str(); *vaddr_begin = nullptr; *vaddr_size = static_cast<size_t>(-1); @@ -593,13 +578,13 @@ bool ElfFileImpl<ElfTypes>::GetLoadedAddressRange(/*out*/uint8_t** vaddr_begin, } min_vaddr = RoundDown(min_vaddr, kElfSegmentAlignment); max_vaddr = RoundUp(max_vaddr, kElfSegmentAlignment); - CHECK_LT(min_vaddr, max_vaddr) << file_path_; + CHECK_LT(min_vaddr, max_vaddr) << file_location_; // Check that the range fits into the runtime address space. if (UNLIKELY(max_vaddr - 1u > std::numeric_limits<size_t>::max())) { std::ostringstream oss; oss << "Loaded range is 0x" << std::hex << min_vaddr << "-0x" << max_vaddr - << " but maximum size_t is 0x" << std::numeric_limits<size_t>::max() - << " for ELF file \"" << file_path_ << "\""; + << " but maximum size_t is 0x" << std::numeric_limits<size_t>::max() << " for ELF file \"" + << file_location_ << "\""; *error_msg = oss.str(); *vaddr_begin = nullptr; *vaddr_size = static_cast<size_t>(-1); @@ -628,8 +613,7 @@ static InstructionSet GetInstructionSetFromELF(uint16_t e_machine, } template <typename ElfTypes> -bool ElfFileImpl<ElfTypes>::Load(File* file, - bool executable, +bool ElfFileImpl<ElfTypes>::Load(bool executable, bool low_4gb, /*inout*/ MemMap* reservation, /*out*/ std::string* error_msg) { @@ -667,14 +651,6 @@ bool ElfFileImpl<ElfTypes>::Load(File* file, // non-zero, the segments require the specific address specified, // which either was specified in the file because we already set // base_address_ after the first zero segment). - int64_t temp_file_length = file->GetLength(); - if (temp_file_length < 0) { - errno = -temp_file_length; - *error_msg = StringPrintf("Failed to get length of file: '%s' fd=%d: %s", - file->GetPath().c_str(), file->Fd(), strerror(errno)); - return false; - } - size_t file_length = static_cast<size_t>(temp_file_length); if (!reserved) { uint8_t* vaddr_begin; size_t vaddr_size; @@ -682,16 +658,16 @@ bool ElfFileImpl<ElfTypes>::Load(File* file, DCHECK(!error_msg->empty()); return false; } - std::string reservation_name = "ElfFile reservation for " + file->GetPath(); - MemMap local_reservation = MemMap::MapAnonymous( - reservation_name.c_str(), - (reservation != nullptr) ? reservation->Begin() : nullptr, - vaddr_size, - PROT_NONE, - low_4gb, - /* reuse= */ false, - reservation, - error_msg); + std::string reservation_name = "ElfFile reservation for " + file_location_; + MemMap local_reservation = + MemMap::MapAnonymous(reservation_name.c_str(), + (reservation != nullptr) ? reservation->Begin() : nullptr, + vaddr_size, + PROT_NONE, + low_4gb, + /*reuse=*/false, + reservation, + error_msg); if (!local_reservation.IsValid()) { *error_msg = StringPrintf("Failed to allocate %s: %s", reservation_name.c_str(), @@ -729,23 +705,26 @@ bool ElfFileImpl<ElfTypes>::Load(File* file, *error_msg = StringPrintf("Invalid p_filesz > p_memsz (%" PRIu64 " > %" PRIu64 "): %s", static_cast<uint64_t>(program_header->p_filesz), static_cast<uint64_t>(program_header->p_memsz), - file->GetPath().c_str()); + file_location_.c_str()); return false; } if (program_header->p_filesz < program_header->p_memsz && !IsAligned<kElfSegmentAlignment>(program_header->p_filesz)) { - *error_msg = StringPrintf("Unsupported unaligned p_filesz < p_memsz (%" PRIu64 - " < %" PRIu64 "): %s", - static_cast<uint64_t>(program_header->p_filesz), - static_cast<uint64_t>(program_header->p_memsz), - file->GetPath().c_str()); + *error_msg = + StringPrintf("Unsupported unaligned p_filesz < p_memsz (%" PRIu64 " < %" PRIu64 "): %s", + static_cast<uint64_t>(program_header->p_filesz), + static_cast<uint64_t>(program_header->p_memsz), + file_location_.c_str()); return false; } - if (file_length < (program_header->p_offset + program_header->p_filesz)) { - *error_msg = StringPrintf("File size of %zd bytes not large enough to contain ELF segment " - "%d of %" PRIu64 " bytes: '%s'", file_length, i, - static_cast<uint64_t>(program_header->p_offset + program_header->p_filesz), - file->GetPath().c_str()); + if (file_length_ < (program_header->p_offset + program_header->p_filesz)) { + *error_msg = StringPrintf( + "File size of %zd bytes not large enough to contain ELF segment " + "%d of %" PRIu64 " bytes: '%s'", + file_length_, + i, + static_cast<uint64_t>(program_header->p_offset + program_header->p_filesz), + file_location_.c_str()); return false; } if (program_header->p_filesz != 0u) { @@ -753,29 +732,36 @@ bool ElfFileImpl<ElfTypes>::Load(File* file, program_header->p_filesz, prot, MAP_PRIVATE, - file->Fd(), - program_header->p_offset, + file_->Fd(), + start_ + program_header->p_offset, /*low_4gb=*/false, - file->GetPath().c_str(), + file_location_.c_str(), /*reuse=*/true, // implies MAP_FIXED /*reservation=*/nullptr, error_msg); if (!segment.IsValid()) { *error_msg = StringPrintf("Failed to map ELF file segment %d from %s: %s", - i, file->GetPath().c_str(), error_msg->c_str()); + i, + file_location_.c_str(), + error_msg->c_str()); return false; } if (segment.Begin() != p_vaddr) { - *error_msg = StringPrintf("Failed to map ELF file segment %d from %s at expected address %p, " - "instead mapped to %p", - i, file->GetPath().c_str(), p_vaddr, segment.Begin()); + *error_msg = StringPrintf( + "Failed to map ELF file segment %d from %s at expected address %p, " + "instead mapped to %p", + i, + file_location_.c_str(), + p_vaddr, + segment.Begin()); return false; } segments_.push_back(std::move(segment)); } if (program_header->p_filesz < program_header->p_memsz) { std::string name = StringPrintf("Zero-initialized segment %" PRIu64 " of ELF file %s", - static_cast<uint64_t>(i), file->GetPath().c_str()); + static_cast<uint64_t>(i), + file_location_.c_str()); MemMap segment = MemMap::MapAnonymous(name.c_str(), p_vaddr + program_header->p_filesz, program_header->p_memsz - program_header->p_filesz, @@ -786,13 +772,19 @@ bool ElfFileImpl<ElfTypes>::Load(File* file, error_msg); if (!segment.IsValid()) { *error_msg = StringPrintf("Failed to map zero-initialized ELF file segment %d from %s: %s", - i, file->GetPath().c_str(), error_msg->c_str()); + i, + file_location_.c_str(), + error_msg->c_str()); return false; } if (segment.Begin() != p_vaddr) { - *error_msg = StringPrintf("Failed to map zero-initialized ELF file segment %d from %s " - "at expected address %p, instead mapped to %p", - i, file->GetPath().c_str(), p_vaddr, segment.Begin()); + *error_msg = StringPrintf( + "Failed to map zero-initialized ELF file segment %d from %s " + "at expected address %p, instead mapped to %p", + i, + file_location_.c_str(), + p_vaddr, + segment.Begin()); return false; } segments_.push_back(std::move(segment)); @@ -802,8 +794,8 @@ bool ElfFileImpl<ElfTypes>::Load(File* file, // Now that we are done loading, .dynamic should be in memory to find .dynstr, .dynsym, .hash uint8_t* dsptr = base_address_ + GetDynamicProgramHeader().p_vaddr; if ((dsptr < Begin() || dsptr >= End()) && !ValidPointer(dsptr)) { - *error_msg = StringPrintf("dynamic section address invalid in ELF file %s", - file->GetPath().c_str()); + *error_msg = + StringPrintf("dynamic section address invalid in ELF file %s", file_location_.c_str()); return false; } dynamic_section_start_ = reinterpret_cast<Elf_Dyn*>(dsptr); @@ -815,7 +807,8 @@ bool ElfFileImpl<ElfTypes>::Load(File* file, case DT_HASH: { if (!ValidPointer(d_ptr)) { *error_msg = StringPrintf("DT_HASH value %p does not refer to a loaded ELF segment of %s", - d_ptr, file->GetPath().c_str()); + d_ptr, + file_location_.c_str()); return false; } hash_section_start_ = reinterpret_cast<Elf_Word*>(d_ptr); @@ -824,7 +817,8 @@ bool ElfFileImpl<ElfTypes>::Load(File* file, case DT_STRTAB: { if (!ValidPointer(d_ptr)) { *error_msg = StringPrintf("DT_HASH value %p does not refer to a loaded ELF segment of %s", - d_ptr, file->GetPath().c_str()); + d_ptr, + file_location_.c_str()); return false; } dynstr_section_start_ = reinterpret_cast<char*>(d_ptr); @@ -833,7 +827,8 @@ bool ElfFileImpl<ElfTypes>::Load(File* file, case DT_SYMTAB: { if (!ValidPointer(d_ptr)) { *error_msg = StringPrintf("DT_HASH value %p does not refer to a loaded ELF segment of %s", - d_ptr, file->GetPath().c_str()); + d_ptr, + file_location_.c_str()); return false; } dynsym_section_start_ = reinterpret_cast<Elf_Sym*>(d_ptr); @@ -841,9 +836,12 @@ bool ElfFileImpl<ElfTypes>::Load(File* file, } case DT_NULL: { if (GetDynamicNum() != i+1) { - *error_msg = StringPrintf("DT_NULL found after %d .dynamic entries, " - "expected %d as implied by size of PT_DYNAMIC segment in %s", - i + 1, GetDynamicNum(), file->GetPath().c_str()); + *error_msg = StringPrintf( + "DT_NULL found after %d .dynamic entries, " + "expected %d as implied by size of PT_DYNAMIC segment in %s", + i + 1, + GetDynamicNum(), + file_location_.c_str()); return false; } break; @@ -852,7 +850,7 @@ bool ElfFileImpl<ElfTypes>::Load(File* file, } // Check for the existence of some sections. - if (!CheckSectionsExist(file, error_msg)) { + if (!CheckSectionsExist(error_msg)) { return false; } @@ -874,36 +872,51 @@ template class ElfFileImpl<ElfTypes32>; template class ElfFileImpl<ElfTypes64>; ElfFile* ElfFile::Open(File* file, + off_t start, + size_t file_length, + const std::string& file_location, bool low_4gb, /*out*/ std::string* error_msg) { - if (file->GetLength() < EI_NIDENT) { - *error_msg = StringPrintf("File %s is too short to be a valid ELF file", - file->GetPath().c_str()); + if (file_length < EI_NIDENT) { + *error_msg = StringPrintf("File %s is too short to be a valid ELF file", file_location.c_str()); return nullptr; } MemMap map = MemMap::MapFile(EI_NIDENT, PROT_READ, MAP_PRIVATE, file->Fd(), - 0, + start, low_4gb, - file->GetPath().c_str(), + file_location.c_str(), error_msg); if (!map.IsValid() || map.Size() != EI_NIDENT) { return nullptr; } uint8_t* header = map.Begin(); if (header[EI_CLASS] == ELFCLASS64) { - return ElfFileImpl64::Open(file, low_4gb, error_msg); + return ElfFileImpl64::Open(file, start, file_length, file_location, low_4gb, error_msg); } else if (header[EI_CLASS] == ELFCLASS32) { - return ElfFileImpl32::Open(file, low_4gb, error_msg); + return ElfFileImpl32::Open(file, start, file_length, file_location, low_4gb, error_msg); } else { *error_msg = StringPrintf("Failed to find expected EI_CLASS value %d or %d in %s, found %d", - ELFCLASS32, ELFCLASS64, - file->GetPath().c_str(), + ELFCLASS32, + ELFCLASS64, + file_location.c_str(), header[EI_CLASS]); return nullptr; } } +ElfFile* ElfFile::Open(File* file, + bool low_4gb, + /*out*/ std::string* error_msg) { + int64_t file_length = file->GetLength(); + if (file_length < 0) { + *error_msg = + ART_FORMAT("Failed to get file length of '{}': {}", file->GetPath(), strerror(errno)); + return nullptr; + } + return Open(file, /*start=*/0, file_length, file->GetPath(), low_4gb, error_msg); +} + } // namespace art diff --git a/runtime/oat/elf_file.h b/runtime/oat/elf_file.h index fa49e86e55..d86f4fb4e4 100644 --- a/runtime/oat/elf_file.h +++ b/runtime/oat/elf_file.h @@ -17,9 +17,11 @@ #ifndef ART_RUNTIME_OAT_ELF_FILE_H_ #define ART_RUNTIME_OAT_ELF_FILE_H_ +#include <cstddef> #include <string> #include <vector> +#include "android-base/logging.h" #include "base/macros.h" #include "base/mem_map.h" #include "base/os.h" @@ -39,22 +41,33 @@ using ElfFileImpl64 = ElfFileImpl<ElfTypes64>; // ELFObjectFile. class ElfFile { public: + // Loads the program headers. + // Does not take the ownership of the file. It must stay alive during the `Load` call. + static ElfFile* Open(File* file, + off_t start, + size_t file_length, + const std::string& file_location, + bool low_4gb, + /*out*/ std::string* error_msg); + static ElfFile* Open(File* file, bool low_4gb, /*out*/ std::string* error_msg); virtual ~ElfFile() = default; - // Load segments into memory based on PT_LOAD program headers - virtual bool Load(File* file, - bool executable, + // Load segments into memory based on PT_LOAD program headers. + virtual bool Load(bool executable, bool low_4gb, /*inout*/ MemMap* reservation, /*out*/ std::string* error_msg) = 0; virtual const uint8_t* FindDynamicSymbolAddress(const std::string& symbol_name) const = 0; - const std::string& GetFilePath() const { return file_path_; } + // Returns the location of the ELF file, for debugging purposes only. + // Note that the location is not necessarily a path to a file on disk. It can also be a zip entry + // inside a zip file. + const std::string& GetFileLocation() const { return file_location_; } uint8_t* GetBaseAddress() const { return base_address_; } @@ -71,9 +84,15 @@ class ElfFile { virtual bool Is64Bit() const = 0; protected: - ElfFile() = default; - - const std::string file_path_; + ElfFile(File* file, off_t start, size_t file_length, const std::string& file_location) + : file_(file), start_(start), file_length_(file_length), file_location_(file_location) { + CHECK(file != nullptr); + } + + File* const file_; + const off_t start_; + const size_t file_length_; + const std::string file_location_; // ELF header mapping. If program_header_only_ is false, will // actually point to the entire elf file. diff --git a/runtime/oat/elf_file_impl.h b/runtime/oat/elf_file_impl.h index b117c82d74..6db86d011f 100644 --- a/runtime/oat/elf_file_impl.h +++ b/runtime/oat/elf_file_impl.h @@ -44,6 +44,9 @@ class ElfFileImpl : public ElfFile { using Elf_Dyn = typename ElfTypes::Dyn; static ElfFileImpl* Open(File* file, + off_t start, + size_t file_length, + const std::string& file_location, bool low_4gb, /*out*/ std::string* error_msg); @@ -73,8 +76,7 @@ class ElfFileImpl : public ElfFile { // Load segments into memory based on PT_LOAD program headers. // executable is true at run time, false at compile time. - bool Load(File* file, - bool executable, + bool Load(bool executable, bool low_4gb, /*inout*/ MemMap* reservation, /*out*/ std::string* error_msg) override; @@ -82,15 +84,16 @@ class ElfFileImpl : public ElfFile { bool Is64Bit() const override { return std::is_same_v<ElfTypes, ElfTypes64>; } private: - explicit ElfFileImpl(File* file); + ElfFileImpl(File* file, off_t start, size_t file_length, const std::string& file_location) + : ElfFile(file, start, file_length, file_location) {} bool GetLoadedAddressRange(/*out*/uint8_t** vaddr_begin, /*out*/size_t* vaddr_size, /*out*/std::string* error_msg) const; - bool Setup(File* file, int prot, int flags, bool low_4gb, std::string* error_msg); + bool Setup(bool low_4gb, std::string* error_msg); - bool SetMap(File* file, MemMap&& map, std::string* error_msg); + bool SetMap(MemMap&& map, std::string* error_msg); uint8_t* GetProgramHeadersStart() const; Elf_Phdr& GetDynamicProgramHeader() const; @@ -108,24 +111,24 @@ class ElfFileImpl : public ElfFile { const Elf_Sym* FindDynamicSymbol(const std::string& symbol_name) const; // Check that certain sections and their dependencies exist. - bool CheckSectionsExist(File* file, std::string* error_msg) const; + bool CheckSectionsExist(std::string* error_msg) const; Elf_Phdr* FindProgamHeaderByType(Elf_Word type) const; // Lookup a string by section type. Returns null for special 0 offset. const char* GetString(Elf_Word section_type, Elf_Word) const; - Elf_Ehdr* header_; + Elf_Ehdr* header_ = nullptr; // Conditionally available values. Use accessors to ensure they exist if they are required. - uint8_t* section_headers_start_; - Elf_Phdr* dynamic_program_header_; - Elf_Dyn* dynamic_section_start_; - Elf_Sym* symtab_section_start_; - Elf_Sym* dynsym_section_start_; - char* strtab_section_start_; - char* dynstr_section_start_; - Elf_Word* hash_section_start_; + uint8_t* section_headers_start_ = nullptr; + Elf_Phdr* dynamic_program_header_ = nullptr; + Elf_Dyn* dynamic_section_start_ = nullptr; + Elf_Sym* symtab_section_start_ = nullptr; + Elf_Sym* dynsym_section_start_ = nullptr; + char* strtab_section_start_ = nullptr; + char* dynstr_section_start_ = nullptr; + Elf_Word* hash_section_start_ = nullptr; DISALLOW_COPY_AND_ASSIGN(ElfFileImpl); }; diff --git a/runtime/oat/oat_file.cc b/runtime/oat/oat_file.cc index c5b53b7021..1652674de7 100644 --- a/runtime/oat/oat_file.cc +++ b/runtime/oat/oat_file.cc @@ -23,6 +23,7 @@ #include <cstdint> #include <cstdlib> #include <cstring> +#include <optional> #include <sstream> #include <type_traits> @@ -40,6 +41,7 @@ #include "base/systrace.h" #include "base/unix_file/fd_file.h" #include "base/utils.h" +#include "base/zip_archive.h" #include "class_loader_context.h" #include "dex/art_dex_file_loader.h" #include "dex/dex_file.h" @@ -1622,6 +1624,9 @@ class ElfOatFile final : public OatFileBase { private: bool ElfFileOpen(File* file, + off_t start, + size_t file_length, + const std::string& file_location, bool executable, bool low_4gb, /*inout*/ MemMap* reservation, // Where to load if not null. @@ -1640,12 +1645,18 @@ bool ElfOatFile::Load(const std::string& elf_filename, /*inout*/ MemMap* reservation, /*out*/ std::string* error_msg) { ScopedTrace trace(__PRETTY_FUNCTION__); - std::unique_ptr<File> file(OS::OpenFileForReading(elf_filename.c_str())); + + // Mirrors the alignment in the Bionic's dlopen. Actually, ART's MemMap only requires 4096 byte + // alignment, but we want to be more strict here, to reflect what the Bionic's dlopen would be + // able to load. + auto [file, start, length] = OS::OpenFileDirectlyOrFromZip( + elf_filename, kZipSeparator, /*alignment=*/MemMap::GetPageSize(), error_msg); if (file == nullptr) { - *error_msg = StringPrintf("Failed to open oat filename for reading: %s", strerror(errno)); return false; } - return ElfOatFile::ElfFileOpen(file.get(), executable, low_4gb, reservation, error_msg); + + return ElfOatFile::ElfFileOpen( + file.get(), start, length, elf_filename, executable, low_4gb, reservation, error_msg); } bool ElfOatFile::Load(int oat_fd, @@ -1658,27 +1669,41 @@ bool ElfOatFile::Load(int oat_fd, int duped_fd = DupCloexec(oat_fd); std::unique_ptr<File> file = std::make_unique<File>(duped_fd, false); if (file == nullptr) { - *error_msg = StringPrintf("Failed to open oat filename for reading: %s", - strerror(errno)); + *error_msg = StringPrintf("Failed to open oat file for reading: %s", strerror(errno)); + return false; + } + int64_t file_length = file->GetLength(); + if (file_length < 0) { + *error_msg = StringPrintf("Failed to get file length of oat file: %s", strerror(errno)); return false; } - return ElfOatFile::ElfFileOpen(file.get(), executable, low_4gb, reservation, error_msg); + return ElfOatFile::ElfFileOpen(file.get(), + /*start=*/0, + file_length, + file->GetPath(), + executable, + low_4gb, + reservation, + error_msg); } return false; } bool ElfOatFile::ElfFileOpen(File* file, + off_t start, + size_t file_length, + const std::string& file_location, bool executable, bool low_4gb, /*inout*/ MemMap* reservation, /*out*/ std::string* error_msg) { ScopedTrace trace(__PRETTY_FUNCTION__); - elf_file_.reset(ElfFile::Open(file, low_4gb, error_msg)); + elf_file_.reset(ElfFile::Open(file, start, file_length, file_location, low_4gb, error_msg)); if (elf_file_ == nullptr) { DCHECK(!error_msg->empty()); return false; } - bool loaded = elf_file_->Load(file, executable, low_4gb, reservation, error_msg); + bool loaded = elf_file_->Load(executable, low_4gb, reservation, error_msg); DCHECK(loaded || !error_msg->empty()); return loaded; } diff --git a/runtime/oat/oat_file.h b/runtime/oat/oat_file.h index 39304f6a8c..9e66e1d4a7 100644 --- a/runtime/oat/oat_file.h +++ b/runtime/oat/oat_file.h @@ -102,6 +102,11 @@ class PACKED(4) OatMethodOffsets { class OatFile { public: + // The zip separator. This has to be the one that Bionic's dlopen recognizes because oat files are + // opened through dlopen in `DlOpenOatFile`. This is different from the ART's zip separator for + // MultiDex. + static constexpr const char* kZipSeparator = "!/"; + // Open an oat file. Returns null on failure. // The `dex_filenames` argument, if provided, overrides the dex locations // from oat file when opening the dex files if they are not embedded in the diff --git a/test/generate-boot-image/Android.bp b/test/generate-boot-image/Android.bp index 60aac13e91..e555e2b9d3 100644 --- a/test/generate-boot-image/Android.bp +++ b/test/generate-boot-image/Android.bp @@ -44,11 +44,13 @@ art_cc_binary { srcs: ["generate-boot-image.cc"], shared_libs: [ "liblog", + "libz", // For "libartbase". ], static_libs: [ "libartbase", "libartbase-testing", "libbase", + "libziparchive", // For "libartbase". ], stl: "c++_static", tidy: true, diff --git a/tools/create_minidebuginfo/Android.bp b/tools/create_minidebuginfo/Android.bp index e78beef8f3..e921cf33b5 100644 --- a/tools/create_minidebuginfo/Android.bp +++ b/tools/create_minidebuginfo/Android.bp @@ -37,5 +37,7 @@ art_cc_binary { "libelffile", "liblzma", "liblog", + "libz", // For "libartbase". + "libziparchive", // For "libartbase". ], } |