diff options
Diffstat (limited to 'runtime/oat_file.cc')
| -rw-r--r-- | runtime/oat_file.cc | 240 |
1 files changed, 184 insertions, 56 deletions
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index a4a159e0da..680f4ac027 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -18,6 +18,7 @@ #include <dlfcn.h> #include <string.h> +#include <type_traits> #include <unistd.h> #include <cstdlib> @@ -42,9 +43,11 @@ #include "mirror/class.h" #include "mirror/object-inl.h" #include "oat_file-inl.h" +#include "oat_file_manager.h" #include "os.h" #include "runtime.h" #include "utils.h" +#include "utils/dex_cache_arrays_layout-inl.h" #include "vmap_table.h" namespace art { @@ -115,15 +118,35 @@ OatFile* OatFile::Open(const std::string& filename, // TODO: Also try when not executable? The issue here could be re-mapping as writable (as // !executable is a sign that we may want to patch), which may not be allowed for // various reasons. - if (kUseDlopen && (kIsTargetBuild || kUseDlopenOnHost) && executable) { - // Try to use dlopen. This may fail for various reasons, outlined below. We try dlopen, as - // this will register the oat file with the linker and allows libunwind to find our info. - ret.reset(OpenDlopen(filename, location, requested_base, abs_dex_location, error_msg)); - if (ret.get() != nullptr) { - return ret.release(); + // dlopen always returns the same library if it is already opened on the host. For this reason + // we only use dlopen if we are the target or we do not already have the dex file opened. Having + // the same library loaded multiple times at different addresses is required for class unloading + // and for having dex caches arrays in the .bss section. + Runtime* const runtime = Runtime::Current(); + OatFileManager* const manager = (runtime != nullptr) ? &runtime->GetOatFileManager() : nullptr; + if (kUseDlopen && executable) { + bool success = kIsTargetBuild; + bool reserved_location = false; + // Manager may be null if we are running without a runtime. + if (!success && kUseDlopenOnHost && manager != nullptr) { + // RegisterOatFileLocation returns false if we are not the first caller to register that + // location. + reserved_location = manager->RegisterOatFileLocation(location); + success = reserved_location; } - if (kPrintDlOpenErrorMessage) { - LOG(ERROR) << "Failed to dlopen: " << *error_msg; + if (success) { + // Try to use dlopen. This may fail for various reasons, outlined below. We try dlopen, as + // this will register the oat file with the linker and allows libunwind to find our info. + ret.reset(OpenDlopen(filename, location, requested_base, abs_dex_location, error_msg)); + if (reserved_location) { + manager->UnRegisterOatFileLocation(location); + } + if (ret != nullptr) { + return ret.release(); + } + if (kPrintDlOpenErrorMessage) { + LOG(ERROR) << "Failed to dlopen: " << *error_msg; + } } } @@ -204,6 +227,10 @@ OatFile::OatFile(const std::string& location, bool is_executable) is_executable_(is_executable), dlopen_handle_(nullptr), secondary_lookup_lock_("OatFile secondary lookup lock", kOatFileSecondaryLookupLock) { CHECK(!location_.empty()); + Runtime* const runtime = Runtime::Current(); + if (runtime != nullptr && !runtime->IsAotCompiler()) { + runtime->GetOatFileManager().RegisterOatFileLocation(location); + } } OatFile::~OatFile() { @@ -211,6 +238,10 @@ OatFile::~OatFile() { if (dlopen_handle_ != nullptr) { dlclose(dlopen_handle_); } + Runtime* const runtime = Runtime::Current(); + if (runtime != nullptr && !runtime->IsAotCompiler()) { + runtime->GetOatFileManager().UnRegisterOatFileLocation(location_); + } } bool OatFile::Dlopen(const std::string& elf_filename, uint8_t* requested_base, @@ -218,10 +249,7 @@ bool OatFile::Dlopen(const std::string& elf_filename, uint8_t* requested_base, #ifdef __APPLE__ // The dl_iterate_phdr syscall is missing. There is similar API on OSX, // but let's fallback to the custom loading code for the time being. - UNUSED(elf_filename); - UNUSED(requested_base); - UNUSED(abs_dex_location); - UNUSED(error_msg); + UNUSED(elf_filename, requested_base, abs_dex_location, error_msg); return false; #else { @@ -361,13 +389,13 @@ bool OatFile::ElfFileOpen(File* file, uint8_t* requested_base, uint8_t* oat_file // Readjust to be non-inclusive upper bound. end_ += sizeof(uint32_t); - bss_begin_ = elf_file_->FindDynamicSymbolAddress("oatbss"); + bss_begin_ = const_cast<uint8_t*>(elf_file_->FindDynamicSymbolAddress("oatbss")); if (bss_begin_ == nullptr) { // No .bss section. Clear dlerror(). bss_end_ = nullptr; dlerror(); } else { - bss_end_ = elf_file_->FindDynamicSymbolAddress("oatbsslastword"); + bss_end_ = const_cast<uint8_t*>(elf_file_->FindDynamicSymbolAddress("oatbsslastword")); if (bss_end_ == nullptr) { *error_msg = StringPrintf("Failed to find oatbasslastword symbol in '%s'", file->GetPath().c_str()); @@ -380,10 +408,31 @@ bool OatFile::ElfFileOpen(File* file, uint8_t* requested_base, uint8_t* oat_file return Setup(abs_dex_location, error_msg); } +// Read an unaligned entry from the OatDexFile data in OatFile and advance the read +// position by the number of bytes read, i.e. sizeof(T). +// Return true on success, false if the read would go beyond the end of the OatFile. +template <typename T> +inline static bool ReadOatDexFileData(const OatFile& oat_file, + /*inout*/const uint8_t** oat, + /*out*/T* value) { + DCHECK(oat != nullptr); + DCHECK(value != nullptr); + DCHECK_LE(*oat, oat_file.End()); + if (UNLIKELY(static_cast<size_t>(oat_file.End() - *oat) < sizeof(T))) { + return false; + } + static_assert(std::is_trivial<T>::value, "T must be a trivial type"); + typedef __attribute__((__aligned__(1))) T unaligned_type; + *value = *reinterpret_cast<const unaligned_type*>(*oat); + *oat += sizeof(T); + return true; +} + bool OatFile::Setup(const char* abs_dex_location, std::string* error_msg) { if (!GetOatHeader().IsValid()) { std::string cause = GetOatHeader().GetValidationErrorMessage(); - *error_msg = StringPrintf("Invalid oat header for '%s': %s", GetLocation().c_str(), + *error_msg = StringPrintf("Invalid oat header for '%s': %s", + GetLocation().c_str(), cause.c_str()); return false; } @@ -397,33 +446,42 @@ bool OatFile::Setup(const char* abs_dex_location, std::string* error_msg) { oat += GetOatHeader().GetKeyValueStoreSize(); if (oat > End()) { *error_msg = StringPrintf("In oat file '%s' found truncated variable-size data: " - "%p + %zd + %ud <= %p", GetLocation().c_str(), - Begin(), sizeof(OatHeader), GetOatHeader().GetKeyValueStoreSize(), + "%p + %zu + %u <= %p", + GetLocation().c_str(), + Begin(), + sizeof(OatHeader), + GetOatHeader().GetKeyValueStoreSize(), End()); return false; } + size_t pointer_size = GetInstructionSetPointerSize(GetOatHeader().GetInstructionSet()); + uint8_t* dex_cache_arrays = bss_begin_; uint32_t dex_file_count = GetOatHeader().GetDexFileCount(); oat_dex_files_storage_.reserve(dex_file_count); for (size_t i = 0; i < dex_file_count; i++) { - uint32_t dex_file_location_size = *reinterpret_cast<const uint32_t*>(oat); - if (UNLIKELY(dex_file_location_size == 0U)) { - *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd with empty location name", - GetLocation().c_str(), i); + uint32_t dex_file_location_size; + if (UNLIKELY(!ReadOatDexFileData(*this, &oat, &dex_file_location_size))) { + *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu truncated after dex file " + "location size", + GetLocation().c_str(), + i); return false; } - oat += sizeof(dex_file_location_size); - if (UNLIKELY(oat > End())) { - *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd truncated after dex file " - "location size", GetLocation().c_str(), i); + if (UNLIKELY(dex_file_location_size == 0U)) { + *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu with empty location name", + GetLocation().c_str(), + i); return false; } const char* dex_file_location_data = reinterpret_cast<const char*>(oat); oat += dex_file_location_size; if (UNLIKELY(oat > End())) { - *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd with truncated dex file " - "location", GetLocation().c_str(), i); + *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu with truncated dex file " + "location", + GetLocation().c_str(), + i); return false; } @@ -431,59 +489,114 @@ bool OatFile::Setup(const char* abs_dex_location, std::string* error_msg) { abs_dex_location, std::string(dex_file_location_data, dex_file_location_size)); - uint32_t dex_file_checksum = *reinterpret_cast<const uint32_t*>(oat); - oat += sizeof(dex_file_checksum); - if (UNLIKELY(oat > End())) { - *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' truncated after " - "dex file checksum", GetLocation().c_str(), i, + uint32_t dex_file_checksum; + if (UNLIKELY(!ReadOatDexFileData(*this, &oat, &dex_file_checksum))) { + *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' truncated after " + "dex file checksum", + GetLocation().c_str(), + i, dex_file_location.c_str()); return false; } - uint32_t dex_file_offset = *reinterpret_cast<const uint32_t*>(oat); - if (UNLIKELY(dex_file_offset == 0U)) { - *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with zero dex " - "file offset", GetLocation().c_str(), i, dex_file_location.c_str()); + uint32_t dex_file_offset; + if (UNLIKELY(!ReadOatDexFileData(*this, &oat, &dex_file_offset))) { + *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' truncated " + "after dex file offsets", + GetLocation().c_str(), + i, + dex_file_location.c_str()); return false; } - if (UNLIKELY(dex_file_offset > Size())) { - *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with dex file " - "offset %ud > %zd", GetLocation().c_str(), i, - dex_file_location.c_str(), dex_file_offset, Size()); + if (UNLIKELY(dex_file_offset == 0U)) { + *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with zero dex " + "file offset", + GetLocation().c_str(), + i, + dex_file_location.c_str()); return false; } - oat += sizeof(dex_file_offset); - if (UNLIKELY(oat > End())) { - *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' truncated " - "after dex file offsets", GetLocation().c_str(), i, - dex_file_location.c_str()); + if (UNLIKELY(dex_file_offset > Size())) { + *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with dex file " + "offset %u > %zu", + GetLocation().c_str(), + i, + dex_file_location.c_str(), + dex_file_offset, + Size()); return false; } const uint8_t* dex_file_pointer = Begin() + dex_file_offset; if (UNLIKELY(!DexFile::IsMagicValid(dex_file_pointer))) { - *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with invalid " - "dex file magic '%s'", GetLocation().c_str(), i, - dex_file_location.c_str(), dex_file_pointer); + *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with invalid " + "dex file magic '%s'", + GetLocation().c_str(), + i, + dex_file_location.c_str(), + dex_file_pointer); return false; } if (UNLIKELY(!DexFile::IsVersionValid(dex_file_pointer))) { - *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with invalid " - "dex file version '%s'", GetLocation().c_str(), i, - dex_file_location.c_str(), dex_file_pointer); + *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with invalid " + "dex file version '%s'", + GetLocation().c_str(), + i, + dex_file_location.c_str(), + dex_file_pointer); return false; } const DexFile::Header* header = reinterpret_cast<const DexFile::Header*>(dex_file_pointer); + + if (UNLIKELY(oat > End())) { + *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with truncated " + "lookup table offset", GetLocation().c_str(), i, + dex_file_location.c_str()); + return false; + } + uint32_t lookup_table_offset = *reinterpret_cast<const uint32_t*>(oat); + oat += sizeof(lookup_table_offset); + if (Begin() + lookup_table_offset > End()) { + *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with truncated " + "lookup table", GetLocation().c_str(), i, + dex_file_location.c_str()); + return false; + } + const uint8_t* lookup_table_data = lookup_table_offset != 0u + ? Begin() + lookup_table_offset + : nullptr; + const uint32_t* methods_offsets_pointer = reinterpret_cast<const uint32_t*>(oat); oat += (sizeof(*methods_offsets_pointer) * header->class_defs_size_); if (UNLIKELY(oat > End())) { - *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with truncated " - "method offsets", GetLocation().c_str(), i, + *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with truncated " + "method offsets", + GetLocation().c_str(), + i, dex_file_location.c_str()); return false; } + uint8_t* current_dex_cache_arrays = nullptr; + if (dex_cache_arrays != nullptr) { + DexCacheArraysLayout layout(pointer_size, *header); + if (layout.Size() != 0u) { + if (static_cast<size_t>(bss_end_ - dex_cache_arrays) < layout.Size()) { + *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with " + "truncated dex cache arrays, %zu < %zu.", + GetLocation().c_str(), + i, + dex_file_location.c_str(), + static_cast<size_t>(bss_end_ - dex_cache_arrays), + layout.Size()); + return false; + } + current_dex_cache_arrays = dex_cache_arrays; + dex_cache_arrays += layout.Size(); + } + } + std::string canonical_location = DexFile::GetDexCanonicalLocation(dex_file_location.c_str()); // Create the OatDexFile and add it to the owning container. @@ -492,7 +605,9 @@ bool OatFile::Setup(const char* abs_dex_location, std::string* error_msg) { canonical_location, dex_file_checksum, dex_file_pointer, - methods_offsets_pointer); + lookup_table_data, + methods_offsets_pointer, + current_dex_cache_arrays); oat_dex_files_storage_.push_back(oat_dex_file); // Add the location and canonical location (if different) to the oat_dex_files_ table. @@ -503,6 +618,15 @@ bool OatFile::Setup(const char* abs_dex_location, std::string* error_msg) { oat_dex_files_.Put(canonical_key, oat_dex_file); } } + + if (dex_cache_arrays != bss_end_) { + // We expect the bss section to be either empty (dex_cache_arrays and bss_end_ + // both null) or contain just the dex cache arrays and nothing else. + *error_msg = StringPrintf("In oat file '%s' found unexpected bss size bigger by %zu bytes.", + GetLocation().c_str(), + static_cast<size_t>(bss_end_ - dex_cache_arrays)); + return false; + } return true; } @@ -605,13 +729,17 @@ OatFile::OatDexFile::OatDexFile(const OatFile* oat_file, const std::string& canonical_dex_file_location, uint32_t dex_file_location_checksum, const uint8_t* dex_file_pointer, - const uint32_t* oat_class_offsets_pointer) + const uint8_t* lookup_table_data, + const uint32_t* oat_class_offsets_pointer, + uint8_t* dex_cache_arrays) : oat_file_(oat_file), dex_file_location_(dex_file_location), canonical_dex_file_location_(canonical_dex_file_location), dex_file_location_checksum_(dex_file_location_checksum), dex_file_pointer_(dex_file_pointer), - oat_class_offsets_pointer_(oat_class_offsets_pointer) {} + lookup_table_data_(lookup_table_data), + oat_class_offsets_pointer_(oat_class_offsets_pointer), + dex_cache_arrays_(dex_cache_arrays) {} OatFile::OatDexFile::~OatDexFile() {} |