summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dex2oat/dex2oat_test.cc3
-rw-r--r--dex2oat/linker/elf_writer_test.cc9
-rw-r--r--libartbase/base/os.h28
-rw-r--r--libartbase/base/os_linux.cc75
-rw-r--r--libartbase/base/zip_archive.cc14
-rw-r--r--libartbase/base/zip_archive.h10
-rw-r--r--runtime/oat/elf_file.cc333
-rw-r--r--runtime/oat/elf_file.h33
-rw-r--r--runtime/oat/elf_file_impl.h33
-rw-r--r--runtime/oat/oat_file.cc41
-rw-r--r--runtime/oat/oat_file.h5
-rw-r--r--test/generate-boot-image/Android.bp2
-rw-r--r--tools/create_minidebuginfo/Android.bp2
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".
],
}