summaryrefslogtreecommitdiff
path: root/runtime/oat_file.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/oat_file.cc')
-rw-r--r--runtime/oat_file.cc240
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() {}