summaryrefslogtreecommitdiffstats
path: root/runtime
diff options
context:
space:
mode:
authorAndreas Gampe <agampe@google.com>2015-04-18 00:52:30 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2015-04-18 00:52:31 +0000
commitf5091eee4abe73c64959e53bda684bd689569643 (patch)
treeee188b62e08b03084cb5a997932020121b719751 /runtime
parent33259fdfcd350793d10f67f2ea7dfc6051a8afa2 (diff)
parentfa8429b967fe2260ece572337534c9dda6c50d8a (diff)
downloadart-f5091eee4abe73c64959e53bda684bd689569643.zip
art-f5091eee4abe73c64959e53bda684bd689569643.tar.gz
art-f5091eee4abe73c64959e53bda684bd689569643.tar.bz2
Merge "ART: Re-add dlopen"
Diffstat (limited to 'runtime')
-rw-r--r--runtime/oat_file.cc136
-rw-r--r--runtime/oat_file.h8
2 files changed, 131 insertions, 13 deletions
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index d3c4b49..eddbd8a 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -23,6 +23,11 @@
#include <cstdlib>
#include <sstream>
+// dlopen_ext support from bionic.
+#ifdef HAVE_ANDROID_OS
+#include "android/dlext.h"
+#endif
+
#include "base/bit_vector.h"
#include "base/stl_util.h"
#include "base/unix_file/fd_file.h"
@@ -40,6 +45,18 @@
namespace art {
+// Whether OatFile::Open will try DlOpen() first. Fallback is our own ELF loader.
+static constexpr bool kUseDlopen = false;
+
+// Whether OatFile::Open will try DlOpen() on the host. On the host we're not linking against
+// bionic, so cannot take advantage of the support for changed semantics (loading the same soname
+// multiple times). However, if/when we switch the above, we likely want to switch this, too,
+// to get test coverage of the code paths.
+static constexpr bool kUseDlopenOnHost = false;
+
+// For debugging, Open will print DlOpen error message if set to true.
+static constexpr bool kPrintDlOpenErrorMessage = false;
+
std::string OatFile::ResolveRelativeEncodedDexLocation(
const char* abs_dex_location, const std::string& rel_dex_location) {
if (abs_dex_location != nullptr && rel_dex_location[0] != '/') {
@@ -89,6 +106,23 @@ OatFile* OatFile::Open(const std::string& filename,
CHECK(!filename.empty()) << location;
CheckLocation(location);
std::unique_ptr<OatFile> ret;
+
+ // Use dlopen only when flagged to do so, and when it's OK to load things executable.
+ // 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();
+ }
+ if (kPrintDlOpenErrorMessage) {
+ LOG(ERROR) << "Failed to dlopen: " << *error_msg;
+ }
+ }
+
// If we aren't trying to execute, we just use our own ElfFile loader for a couple reasons:
//
// On target, dlopen may fail when compiling due to selinux restrictions on installd.
@@ -98,8 +132,12 @@ OatFile* OatFile::Open(const std::string& filename,
// another generated dex file with the same name. http://b/10614658
//
// On host, dlopen is expected to fail when cross compiling, so fall back to OpenElfFile.
+ //
+ //
+ // Another independent reason is the absolute placement of boot.oat. dlopen on the host usually
+ // does honor the virtual address encoded in the ELF file only for ET_EXEC files, not ET_DYN.
std::unique_ptr<File> file(OS::OpenFileForReading(filename.c_str()));
- if (file.get() == NULL) {
+ if (file == nullptr) {
*error_msg = StringPrintf("Failed to open oat filename for reading: %s", strerror(errno));
return nullptr;
}
@@ -126,6 +164,19 @@ OatFile* OatFile::OpenReadable(File* file, const std::string& location,
return OpenElfFile(file, location, nullptr, nullptr, false, false, abs_dex_location, error_msg);
}
+OatFile* OatFile::OpenDlopen(const std::string& elf_filename,
+ const std::string& location,
+ uint8_t* requested_base,
+ const char* abs_dex_location,
+ std::string* error_msg) {
+ std::unique_ptr<OatFile> oat_file(new OatFile(location, true));
+ bool success = oat_file->Dlopen(elf_filename, requested_base, abs_dex_location, error_msg);
+ if (!success) {
+ return nullptr;
+ }
+ return oat_file.release();
+}
+
OatFile* OatFile::OpenElfFile(File* file,
const std::string& location,
uint8_t* requested_base,
@@ -145,19 +196,78 @@ OatFile* OatFile::OpenElfFile(File* file,
}
OatFile::OatFile(const std::string& location, bool is_executable)
- : location_(location), begin_(NULL), end_(NULL), bss_begin_(nullptr), bss_end_(nullptr),
- is_executable_(is_executable), dlopen_handle_(NULL),
+ : location_(location), begin_(nullptr), end_(nullptr), bss_begin_(nullptr), bss_end_(nullptr),
+ is_executable_(is_executable), dlopen_handle_(nullptr),
secondary_lookup_lock_("OatFile secondary lookup lock", kOatFileSecondaryLookupLock) {
CHECK(!location_.empty());
}
OatFile::~OatFile() {
STLDeleteElements(&oat_dex_files_storage_);
- if (dlopen_handle_ != NULL) {
+ if (dlopen_handle_ != nullptr) {
dlclose(dlopen_handle_);
}
}
+bool OatFile::Dlopen(const std::string& elf_filename, uint8_t* requested_base,
+ const char* abs_dex_location, std::string* error_msg) {
+ std::unique_ptr<char> absolute_path(realpath(elf_filename.c_str(), nullptr));
+ if (absolute_path == nullptr) {
+ *error_msg = StringPrintf("Failed to find absolute path for '%s'", elf_filename.c_str());
+ return false;
+ }
+#ifdef HAVE_ANDROID_OS
+ android_dlextinfo extinfo;
+ extinfo.flags = ANDROID_DLEXT_FORCE_LOAD;
+ dlopen_handle_ = android_dlopen_ext(absolute_path.get(), RTLD_NOW, &extinfo);
+#else
+ dlopen_handle_ = dlopen(absolute_path.get(), RTLD_NOW);
+#endif
+ if (dlopen_handle_ == nullptr) {
+ *error_msg = StringPrintf("Failed to dlopen '%s': %s", elf_filename.c_str(), dlerror());
+ return false;
+ }
+ begin_ = reinterpret_cast<uint8_t*>(dlsym(dlopen_handle_, "oatdata"));
+ if (begin_ == nullptr) {
+ *error_msg = StringPrintf("Failed to find oatdata symbol in '%s': %s", elf_filename.c_str(),
+ dlerror());
+ return false;
+ }
+ if (requested_base != nullptr && begin_ != requested_base) {
+ PrintFileToLog("/proc/self/maps", LogSeverity::WARNING);
+ *error_msg = StringPrintf("Failed to find oatdata symbol at expected address: "
+ "oatdata=%p != expected=%p, %s. See process maps in the log.",
+ begin_, requested_base, elf_filename.c_str());
+ return false;
+ }
+ end_ = reinterpret_cast<uint8_t*>(dlsym(dlopen_handle_, "oatlastword"));
+ if (end_ == nullptr) {
+ *error_msg = StringPrintf("Failed to find oatlastword symbol in '%s': %s", elf_filename.c_str(),
+ dlerror());
+ return false;
+ }
+ // Readjust to be non-inclusive upper bound.
+ end_ += sizeof(uint32_t);
+
+ bss_begin_ = reinterpret_cast<uint8_t*>(dlsym(dlopen_handle_, "oatbss"));
+ if (bss_begin_ == nullptr) {
+ // No .bss section. Clear dlerror().
+ bss_end_ = nullptr;
+ dlerror();
+ } else {
+ bss_end_ = reinterpret_cast<uint8_t*>(dlsym(dlopen_handle_, "oatbsslastword"));
+ if (bss_end_ == nullptr) {
+ *error_msg = StringPrintf("Failed to find oatbasslastword symbol in '%s'",
+ elf_filename.c_str());
+ return false;
+ }
+ // Readjust to be non-inclusive upper bound.
+ bss_end_ += sizeof(uint32_t);
+ }
+
+ return Setup(abs_dex_location, error_msg);
+}
+
bool OatFile::ElfFileOpen(File* file, uint8_t* requested_base, uint8_t* oat_file_begin,
bool writable, bool executable,
const char* abs_dex_location,
@@ -165,7 +275,7 @@ bool OatFile::ElfFileOpen(File* file, uint8_t* requested_base, uint8_t* oat_file
// TODO: rename requested_base to oat_data_begin
elf_file_.reset(ElfFile::Open(file, writable, /*program_header_only*/true, error_msg,
oat_file_begin));
- if (elf_file_.get() == nullptr) {
+ if (elf_file_ == nullptr) {
DCHECK(!error_msg->empty());
return false;
}
@@ -175,11 +285,11 @@ bool OatFile::ElfFileOpen(File* file, uint8_t* requested_base, uint8_t* oat_file
return false;
}
begin_ = elf_file_->FindDynamicSymbolAddress("oatdata");
- if (begin_ == NULL) {
+ if (begin_ == nullptr) {
*error_msg = StringPrintf("Failed to find oatdata symbol in '%s'", file->GetPath().c_str());
return false;
}
- if (requested_base != NULL && begin_ != requested_base) {
+ if (requested_base != nullptr && begin_ != requested_base) {
PrintFileToLog("/proc/self/maps", LogSeverity::WARNING);
*error_msg = StringPrintf("Failed to find oatdata symbol at expected address: "
"oatdata=%p != expected=%p. See process maps in the log.",
@@ -187,7 +297,7 @@ bool OatFile::ElfFileOpen(File* file, uint8_t* requested_base, uint8_t* oat_file
return false;
}
end_ = elf_file_->FindDynamicSymbolAddress("oatlastword");
- if (end_ == NULL) {
+ if (end_ == nullptr) {
*error_msg = StringPrintf("Failed to find oatlastword symbol in '%s'", file->GetPath().c_str());
return false;
}
@@ -344,12 +454,12 @@ const OatHeader& OatFile::GetOatHeader() const {
}
const uint8_t* OatFile::Begin() const {
- CHECK(begin_ != NULL);
+ CHECK(begin_ != nullptr);
return begin_;
}
const uint8_t* OatFile::End() const {
- CHECK(end_ != NULL);
+ CHECK(end_ != nullptr);
return end_;
}
@@ -414,7 +524,7 @@ const OatFile::OatDexFile* OatFile::GetOatDexFile(const char* dex_location,
if (warn_if_not_found) {
std::string dex_canonical_location = DexFile::GetDexCanonicalLocation(dex_location);
std::string checksum("<unspecified>");
- if (dex_location_checksum != NULL) {
+ if (dex_location_checksum != nullptr) {
checksum = StringPrintf("0x%08x", *dex_location_checksum);
}
LOG(WARNING) << "Failed to find OatDexFile for DexFile " << dex_location
@@ -430,7 +540,7 @@ const OatFile::OatDexFile* OatFile::GetOatDexFile(const char* dex_location,
}
}
- return NULL;
+ return nullptr;
}
OatFile::OatDexFile::OatDexFile(const OatFile* oat_file,
@@ -584,7 +694,7 @@ const OatFile::OatMethod OatFile::OatClass::GetOatMethod(uint32_t method_index)
}
void OatFile::OatMethod::LinkMethod(mirror::ArtMethod* method) const {
- CHECK(method != NULL);
+ CHECK(method != nullptr);
method->SetEntryPointFromQuickCompiledCode(GetQuickCode());
}
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index a5d5ae8..42c60dc 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -263,6 +263,12 @@ class OatFile FINAL {
private:
static void CheckLocation(const std::string& location);
+ static OatFile* OpenDlopen(const std::string& elf_filename,
+ const std::string& location,
+ uint8_t* requested_base,
+ const char* abs_dex_location,
+ std::string* error_msg);
+
static OatFile* OpenElfFile(File* file,
const std::string& location,
uint8_t* requested_base,
@@ -273,6 +279,8 @@ class OatFile FINAL {
std::string* error_msg);
explicit OatFile(const std::string& filename, bool executable);
+ bool Dlopen(const std::string& elf_filename, uint8_t* requested_base,
+ const char* abs_dex_location, std::string* error_msg);
bool ElfFileOpen(File* file, uint8_t* requested_base,
uint8_t* oat_file_begin, // Override where the file is loaded to if not null
bool writable, bool executable,