Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1450)

Unified Diff: third_party/crazy_linker/crazy_linker/src/crazy_linker_wrappers.cpp

Issue 23717023: Android: Add chrome-specific dynamic linker. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix compile error (previous patch was a mistake). Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/crazy_linker/crazy_linker/src/crazy_linker_wrappers.cpp
diff --git a/third_party/crazy_linker/crazy_linker/src/crazy_linker_wrappers.cpp b/third_party/crazy_linker/crazy_linker/src/crazy_linker_wrappers.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d1cf35ba73b3adea61a0ffa4b24c0cd6f0147930
--- /dev/null
+++ b/third_party/crazy_linker/crazy_linker/src/crazy_linker_wrappers.cpp
@@ -0,0 +1,281 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "crazy_linker_wrappers.h"
+
+#include <dlfcn.h>
+#include <link.h>
+
+#include "crazy_linker_debug.h"
+#include "crazy_linker_globals.h"
+#include "crazy_linker_library_list.h"
+#include "crazy_linker_library_view.h"
+#include "crazy_linker_shared_library.h"
+#include "crazy_linker_thread.h"
+#include "crazy_linker_util.h"
+
+#ifdef __arm__
+// On ARM, this function is exported by the dynamic linker but never
+// declared in any official header. It is used at runtime to
+// find the base address of the .ARM.exidx section for the
+// shared library containing the instruction at |pc|, as well as
+// the number of 8-byte entries in that section, written into |*pcount|
+extern "C" _Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr, int*);
+#else
+// On other architectures, this function is exported by the dynamic linker
+// but never declared in any official header. It is used at runtime to
+// iterate over all loaded libraries and call the |cb|. When the function
+// returns non-0, the iteration returns and the function returns its
+// value.
+extern "C" int dl_iterate_phdr(
+ int (*cb)(dl_phdr_info *info, size_t size, void *data),
+ void *data);
+#endif
+
+namespace crazy {
+
+namespace {
+
+#ifdef __arm__
+extern "C" int __cxa_atexit(void(*)(void*), void*, void*);
+
+// On ARM, this function is defined as a weak symbol by libc.so.
+// Unfortunately its address cannot be found through dlsym(), which will
+// always return NULL. To work-around this, define a copy here that does
+// exactly the same thing. The ARM EABI mandates the function's behaviour.
+// __cxa_atexit() is implemented by the C library, but not declared by
+// any official header. It's part of the low-level C++ support runtime.
+int
+__aeabi_atexit (void *object, void (*destructor) (void *), void *dso_handle)
+{
+ return __cxa_atexit(destructor, object, dso_handle);
+}
+#endif
+
+// Used to save the system dlerror() into our thread-specific data.
+void SaveSystemError() {
+ ThreadData* data = GetThreadData();
+ data->SetError(::dlerror());
+}
+
+char* WrapDlerror() {
+ ThreadData* data = GetThreadData();
+ const char* error = data->GetError();
+ data->SwapErrorBuffers();
+ // dlerror() returns a 'char*', but no sane client code should ever
+ // try to write to this location.
+ return const_cast<char*>(error);
+}
+
+void* WrapDlopen(const char* path, int mode) {
+
+ ScopedGlobalLock lock;
bulach 2013/09/10 14:21:39 nit: indent
digit1 2013/09/10 16:40:28 Done, but I'll submit a single patch that "git cl
+
+ // NOTE: If |path| is NULL, the wrapper should return a handle
+ // corresponding to the current executable. This can't be a crazy
+ // library, so don't try to handle it with the crazy linker.
+ if (path) {
+ LibraryList* lib_list = Globals::GetLibraries();
+ Error error;
+ LibraryView* wrap = lib_list->LoadLibrary(path,
+ mode,
+ 0U /* load_address */,
+ 0U /* file_offset */,
+ Globals::GetSearchPaths(),
+ &error);
+ if (wrap)
+ return wrap;
+ }
+
+ // Try to load the executable with the system dlopen() instead.
+ ::dlerror();
+ void* system_lib = ::dlopen(path, mode);
+ if (system_lib == NULL) {
+ SaveSystemError();
+ return NULL;
+ }
+
+ LibraryView* wrap_lib = new LibraryView();
+ wrap_lib->SetSystem(system_lib, path ? path : "<executable>");
+ Globals::GetLibraries()->AddLibrary(wrap_lib);
+ return wrap_lib;
+}
+
+void* WrapDlsym(void* lib_handle, const char* symbol_name) {
+ LibraryView* wrap_lib = reinterpret_cast<LibraryView*>(lib_handle);
+
+ if (!symbol_name) {
+ SetLinkerError("dlsym: NULL symbol name");
+ return NULL;
+ }
+
+ if (!lib_handle) {
+ SetLinkerError("dlsym: NULL library handle");
+ return NULL;
+ }
+
+ // TODO(digit): Handle RTLD_DEFAULT / RTLD_NEXT
+ if (lib_handle == RTLD_DEFAULT || lib_handle == RTLD_NEXT) {
+ SetLinkerError("dlsym: RTLD_DEFAULT/RTLD_NEXT are not implemented!");
+ return NULL;
+ }
+
+ // NOTE: The Android dlsym() only looks inside the target library,
+ // while the GNU one will perform a breadth-first search into its
+ // dependency tree.
+
+ // This implementation performs a correct breadth-first search
+ // when |lib_handle| corresponds to a crazy library, except that
+ // it stops at system libraries that it depends on.
+
+ void* result = NULL;
+
+ if (wrap_lib->IsSystem()) {
+ // Note: the system dlsym() only looks into the target library,
+ // while the GNU linker performs a breadth-first search.
+ result = ::dlsym(wrap_lib->GetSystem(), symbol_name);
+ if (!result) {
+ SaveSystemError();
+ LOG("dlsym:%s: could not find symbol '%s' from system library\n%s",
+ wrap_lib->GetName(), symbol_name,
+ GetThreadData()->GetError());
+ }
+ return result;
+ }
+
+ if (wrap_lib->IsCrazy()) {
+ ScopedGlobalLock lock;
+ LibraryList* lib_list = Globals::GetLibraries();
+ void* addr = lib_list->FindSymbolFrom(symbol_name, wrap_lib);
+ if (addr)
+ return addr;
+
+ SetLinkerError("dlsym: Could not find '%s' from library '%s'",
+ symbol_name, wrap_lib->GetName());
+ return NULL;
+
+ }
+
+ SetLinkerError("dlsym: Invalid library handle %p looking for '%s'",
+ lib_handle, symbol_name);
+ return NULL;
+}
+
+int WrapDladdr(void* address, Dl_info* info) {
+ // First, perform search in crazy libraries.
+ {
+ ScopedGlobalLock lock;
+ LibraryList* lib_list = Globals::GetLibraries();
+ LibraryView* wrap = lib_list->FindLibraryForAddress(address);
+ if (wrap && wrap->IsCrazy()) {
+ SharedLibrary* lib = wrap->GetCrazy();
+ ::memset(info, 0, sizeof(*info));
+ info->dli_fname = lib->base_name;
+ info->dli_fbase = reinterpret_cast<void*>(lib->base);
+
+ // Determine if any symbol in the library contains the specified address.
+ ELF::Sym* sym = lib->FindSymbolForAddress(address);
+ if (sym != NULL) {
+ info->dli_sname = lib->strtab + sym->st_name;
+ info->dli_saddr =
+ reinterpret_cast<void*>(lib->load_bias + sym->st_value);
+ }
+ return 0;
+ }
+ }
+ // Otherwise, use system version.
+ ::dlerror();
+ int ret = ::dladdr(address, info);
+ if (ret != 0)
+ SaveSystemError();
+ return ret;
+}
+
+int WrapDlclose(void* lib_handle) {
+ LibraryView* wrap_lib = reinterpret_cast<LibraryView*>(lib_handle);
+ if (!wrap_lib) {
+ SetLinkerError("NULL library handle");
+ return -1;
+ }
+
+ if (wrap_lib->IsSystem() || wrap_lib->IsCrazy()) {
+ ScopedGlobalLock lock;
+ LibraryList* lib_list = Globals::GetLibraries();
+ lib_list->UnloadLibrary(wrap_lib);
+ return 0;
+ }
+
+ // Invalid library handle!!
+ SetLinkerError("Invalid library handle %p", lib_handle);
+ return -1;
+}
+
+#ifdef __arm__
+_Unwind_Ptr WrapDl_unwind_find_exidx(_Unwind_Ptr pc, int *pcount)
+{
+ // First lookup in crazy libraries.
+ {
+ ScopedGlobalLock lock;
+ LibraryList* list = Globals::GetLibraries();
+ _Unwind_Ptr result = list->FindArmExIdx(pc, pcount);
+ if (result)
+ return result;
+ }
+ // Lookup in system libraries.
+ return ::dl_unwind_find_exidx(pc, pcount);
+}
+#else // !__arm__
+int WrapDl_iterate_phdr(int (*cb)(dl_phdr_info*, size_t, void*),
+ void* data) {
+ // First, iterate over crazy libraries.
+ {
+ ScopedGlobalLock lock;
+ LibraryList* list = Globals::GetLibraries();
+ int result = list->IteratePhdr(cb, data);
+ if (result)
+ return result;
+ }
+ // Then lookup through system ones.
+ return ::dl_iterate_phdr(cb, data);
+}
+#endif // !__arm__
+
+} // namespace
+
+void* WrapLinkerSymbol(const char* name) {
+ // Shortcut, since all names begin with 'dl'
+ // Take care of __aeabi_atexit on ARM though.
+ if (name[0] != 'd' || name[1] != 'l') {
+#ifdef __arm__
+ if (name[0] == '_' && !strcmp("__aeabi_atexit", name))
+ return reinterpret_cast<void*>(&__aeabi_atexit);
+#endif
+ return NULL;
+ }
+
+ static const struct {
+ const char* name;
+ void* address;
+ } kSymbols[] = {
+ { "dlopen", reinterpret_cast<void*>(&WrapDlopen) },
+ { "dlclose", reinterpret_cast<void*>(&WrapDlclose) },
+ { "dlerror", reinterpret_cast<void*>(&WrapDlerror) },
+ { "dlsym", reinterpret_cast<void*>(&WrapDlsym) },
+ { "dladdr", reinterpret_cast<void*>(&WrapDladdr) },
+#ifdef __arm__
+ { "dl_unwind_find_exidx",
+ reinterpret_cast<void*>(&WrapDl_unwind_find_exidx) },
+#else
+ { "dl_iterate_phdr", reinterpret_cast<void*>(&WrapDl_iterate_phdr) },
+#endif
+ };
+ static const size_t kCount = sizeof(kSymbols)/sizeof(kSymbols[0]);
+ for (size_t n = 0; n < kCount; ++n) {
+ if (!strcmp(kSymbols[n].name, name))
+ return kSymbols[n].address;
+ }
+ return NULL;
+}
+
+} // namespace crazy

Powered by Google App Engine
This is Rietveld 408576698