| Index: third_party/crazy_linker/crazy_linker/src/crazy_linker_library_list.cpp
|
| diff --git a/third_party/crazy_linker/crazy_linker/src/crazy_linker_library_list.cpp b/third_party/crazy_linker/crazy_linker/src/crazy_linker_library_list.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..6894b782c13183fb95702427e323ee9158de238f
|
| --- /dev/null
|
| +++ b/third_party/crazy_linker/crazy_linker/src/crazy_linker_library_list.cpp
|
| @@ -0,0 +1,398 @@
|
| +// 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_library_list.h"
|
| +
|
| +#include <dlfcn.h>
|
| +
|
| +#include "crazy_linker_debug.h"
|
| +#include "crazy_linker_library_view.h"
|
| +#include "crazy_linker_globals.h"
|
| +#include "crazy_linker_rdebug.h"
|
| +#include "crazy_linker_shared_library.h"
|
| +#include "crazy_linker_system.h"
|
| +
|
| +namespace crazy {
|
| +
|
| +namespace {
|
| +
|
| +// A helper struct used when looking up symbols in libraries.
|
| +struct SymbolLookupState {
|
| + void* found_addr;
|
| + void* weak_addr;
|
| + int weak_count;
|
| +
|
| + SymbolLookupState()
|
| + : found_addr(NULL),
|
| + weak_addr(NULL),
|
| + weak_count(0) {}
|
| +
|
| + // Check a symbol entry.
|
| + bool CheckSymbol(const char* symbol, SharedLibrary* lib) {
|
| + ELF::Sym* entry = lib->LookupSymbolEntry(symbol);
|
| + if (!entry)
|
| + return false;
|
| +
|
| + void* address = reinterpret_cast<void*>(lib->base + entry->st_value);
|
| +
|
| + // If this is a strong symbol, record it and return true.
|
| + if (ELF_ST_BIND(entry->st_info) == STB_GLOBAL) {
|
| + found_addr = address;
|
| + return true;
|
| + }
|
| + // If this is a weak symbol, record the first one and
|
| + // increment the weak_count.
|
| + if (++weak_count == 1)
|
| + weak_addr = address;
|
| +
|
| + return false;
|
| + }
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +LibraryList::LibraryList()
|
| + : head_(0), count_(0), has_error_(false) {
|
| + // Nothing for now
|
| +}
|
| +
|
| +LibraryList::~LibraryList() {\
|
| + // Invalidate crazy library list.
|
| + head_ = NULL;
|
| +
|
| + // Destroy all known libraries.
|
| + while (!known_libraries_.IsEmpty()) {
|
| + LibraryView* wrap = known_libraries_.PopLast();
|
| + delete wrap;
|
| + }
|
| +}
|
| +
|
| +LibraryView* LibraryList::FindLibraryByName(const char* base_name) {
|
| + // Sanity check.
|
| + if (!base_name || strchr(base_name, '/'))
|
| + return NULL;
|
| +
|
| + for (size_t n = 0; n < known_libraries_.GetCount(); ++n) {
|
| + LibraryView* wrap = known_libraries_[n];
|
| + if (!strcmp(base_name, wrap->GetName()))
|
| + return wrap;
|
| + }
|
| + return NULL;
|
| +}
|
| +
|
| +void* LibraryList::FindSymbolFrom(const char* symbol_name,
|
| + LibraryView* from) {
|
| + SymbolLookupState lookup_state;
|
| +
|
| + if (!from)
|
| + return NULL;
|
| +
|
| + // Use a work-queue and a set to ensure to perform a breadth-first
|
| + // search.
|
| + Vector<LibraryView*> work_queue;
|
| + Set<LibraryView*> visited_set;
|
| +
|
| + work_queue.PushBack(from);
|
| +
|
| + while (!work_queue.IsEmpty()) {
|
| + LibraryView* lib = work_queue.PopFirst();
|
| + if (lib->IsCrazy()) {
|
| + if (lookup_state.CheckSymbol(symbol_name, lib->GetCrazy()))
|
| + return lookup_state.found_addr;
|
| + } else if (lib->IsSystem()) {
|
| + // TODO(digit): Support weak symbols in system libraries.
|
| + // With the current code, all symbols in system libraries
|
| + // are assumed to be non-weak.
|
| + void* addr = lib->LookupSymbol(symbol_name);
|
| + if (addr)
|
| + return addr;
|
| + }
|
| +
|
| + // If this is a crazy library, add non-visited dependencies
|
| + // to the work queue.
|
| + if (lib->IsCrazy()) {
|
| + SharedLibrary::DependencyIterator iter(lib->GetCrazy());
|
| + while (iter.GetNext()) {
|
| + LibraryView* dependency = FindKnownLibrary(iter.GetName());
|
| + if (dependency && !visited_set.Has(dependency)) {
|
| + work_queue.PushBack(dependency);
|
| + visited_set.Add(dependency);
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + if (lookup_state.weak_count >= 1) {
|
| + // There was at least a single weak symbol definition, so use
|
| + // the first one found in breadth-first search order.
|
| + return lookup_state.weak_addr;
|
| + }
|
| +
|
| + // There was no symbol definition.
|
| + return NULL;
|
| +}
|
| +
|
| +LibraryView* LibraryList::FindLibraryForAddress(void* address) {
|
| + // Linearly scan all libraries, looking for one that contains
|
| + // a given address. NOTE: This doesn't check that this falls
|
| + // inside one of the mapped library segments.
|
| + uintptr_t addr = reinterpret_cast<uintptr_t>(address);
|
| +
|
| + for (size_t n = 0; n < known_libraries_.GetCount(); ++n) {
|
| + LibraryView* wrap = known_libraries_[n];
|
| + // TODO(digit): Search addresses inside system libraries.
|
| + if (wrap->IsCrazy()) {
|
| + SharedLibrary* lib = wrap->GetCrazy();
|
| + if (lib->base <= addr && addr < lib->base + lib->size)
|
| + return wrap;
|
| + }
|
| + }
|
| + return NULL;
|
| +}
|
| +
|
| +#ifdef __arm__
|
| +_Unwind_Ptr LibraryList::FindArmExIdx(void* pc, int* count) {
|
| + uintptr_t addr = reinterpret_cast<uintptr_t>(pc);
|
| +
|
| + for (SharedLibrary* lib = head_; lib; lib = lib->list_next) {
|
| + if (addr >= lib->base && addr < lib->base + lib->size) {
|
| + *count = static_cast<int>(lib->ARM_exidx_count);
|
| + return reinterpret_cast<_Unwind_Ptr>(lib->ARM_exidx);
|
| + }
|
| + }
|
| + *count = 0;
|
| + return NULL;
|
| +}
|
| +#else // !__arm__
|
| +int LibraryList::IteratePhdr(PhdrIterationCallback callback,
|
| + void* data) {
|
| + int result = 0;
|
| + for (SharedLibrary* lib = head_; lib; lib = lib->list_next) {
|
| + dl_phdr_info info;
|
| + info.dlpi_addr = lib->link_map.l_addr;
|
| + info.dlpi_name = lib->link_map.l_name;
|
| + info.dlpi_phdr = lib->phdr;
|
| + info.dlpi_phnum = lib->phnum;
|
| + result = callback(&info, sizeof(info), data);
|
| + if (result)
|
| + break;
|
| + }
|
| + return result;
|
| +}
|
| +#endif // !__arm__
|
| +
|
| +void LibraryList::UnloadLibrary(LibraryView* wrap) {
|
| + // Sanity check.
|
| + LOG("%s: for %s (ref_count=%d)\n",
|
| + __FUNCTION__, wrap->GetName(), wrap->ref_count());
|
| +
|
| + if (!wrap->IsSystem() && !wrap->IsCrazy())
|
| + return;
|
| +
|
| + if (!wrap->SafeDeref())
|
| + return;
|
| +
|
| + // If this is a crazy library, perform manual cleanup first.
|
| + if (wrap->IsCrazy()) {
|
| + SharedLibrary* lib = wrap->GetCrazy();
|
| +
|
| + // Remove from internal list of crazy libraries.
|
| + if (lib->list_next)
|
| + lib->list_next->list_prev = lib->list_prev;
|
| + if (lib->list_prev)
|
| + lib->list_prev->list_next = lib->list_next;
|
| + if (lib == head_)
|
| + head_ = lib->list_next;
|
| +
|
| + // Call the destructors.
|
| + lib->CallDestructors();
|
| +
|
| + // Unload the dependencies recursively.
|
| + SharedLibrary::DependencyIterator iter(lib);
|
| + while (iter.GetNext()) {
|
| + LibraryView* dependency = FindKnownLibrary(iter.GetName());
|
| + if (dependency)
|
| + UnloadLibrary(dependency);
|
| + }
|
| +
|
| + // Tell GDB of this removal.
|
| + Globals::GetRDebug()->DelEntry(&lib->link_map);
|
| + }
|
| +
|
| + known_libraries_.Remove(wrap);
|
| +
|
| + // Delete the wrapper, which will delete the crazy library, or
|
| + // dlclose() the system one.
|
| + delete wrap;
|
| +}
|
| +
|
| +LibraryView* LibraryList::LoadLibrary(const char* lib_name,
|
| + int dlopen_mode,
|
| + uintptr_t load_address,
|
| + off_t file_offset,
|
| + SearchPathList* search_path_list,
|
| + Error* error) {
|
| +
|
| + const char* base_name = GetBaseNamePtr(lib_name);
|
| +
|
| + LOG("%s: lib_name='%s'\n", __FUNCTION__, lib_name);
|
| +
|
| + // First check whether a library with the same base name was
|
| + // already loaded.
|
| + LibraryView* wrap = FindKnownLibrary(lib_name);
|
| + if (wrap) {
|
| + if (load_address) {
|
| + // Check that this is a crazy library and that is was loaded at
|
| + // the correct address.
|
| + if (!wrap->IsCrazy()) {
|
| + error->Format("System library can't be loaded at fixed address %08x",
|
| + load_address);
|
| + return NULL;
|
| + }
|
| + uintptr_t actual_address = wrap->GetCrazy()->base;
|
| + if (actual_address != load_address) {
|
| + error->Format(
|
| + "Library already loaded at @%08x, can't load it at @%08x",
|
| + actual_address, load_address);
|
| + return NULL;
|
| + }
|
| + }
|
| + wrap->AddRef();
|
| + return wrap;
|
| + }
|
| +
|
| + if (IsSystemLibrary(lib_name)) {
|
| + // This is a system library, probably because we're loading the
|
| + // library as a dependency.
|
| + LOG("%s: Loading system library '%s'\n", __FUNCTION__, lib_name);
|
| + ::dlerror();
|
| + void* system_lib = dlopen(lib_name, dlopen_mode);
|
| + if (!system_lib) {
|
| + error->Format("Can't load system library %s: %s",
|
| + lib_name, ::dlerror());
|
| + return NULL;
|
| + }
|
| +
|
| + LibraryView* wrap = new LibraryView();
|
| + wrap->SetSystem(system_lib, lib_name);
|
| + known_libraries_.PushBack(wrap);
|
| +
|
| + LOG("%s: System library %s loaded at %p\n", __FUNCTION__, lib_name, wrap);
|
| + LOG(" name=%s\n", wrap->GetName());
|
| + return wrap;
|
| + }
|
| +
|
| + ScopedPtr<SharedLibrary> lib(new SharedLibrary());
|
| +
|
| + // Find the full library path.
|
| + String full_path;
|
| +
|
| + if (!strchr(lib_name, '/')) {
|
| + LOG("%s: Looking through the search path list\n", __FUNCTION__);
|
| + const char* path = search_path_list->FindFile(lib_name);
|
| + if (!path) {
|
| + error->Format("Can't find library file %s", lib_name);
|
| + return NULL;
|
| + }
|
| + full_path = path;
|
| + } else {
|
| + if (lib_name[0] != '/') {
|
| + // Need to transform this into a full path.
|
| + full_path = GetCurrentDirectory();
|
| + if (full_path.size() && full_path[full_path.size() - 1] != '/')
|
| + full_path += '/';
|
| + full_path += lib_name;
|
| + } else {
|
| + // Absolute path. Easy.
|
| + full_path = lib_name;
|
| + }
|
| + LOG("%s: Full library path: %s\n", __FUNCTION__, full_path.c_str());
|
| + if (!PathIsFile(full_path.c_str())) {
|
| + error->Format("Library file doesn't exist: %s", full_path.c_str());
|
| + return NULL;
|
| + }
|
| + }
|
| +
|
| + // Load the library
|
| + if (!lib->Load(full_path.c_str(), load_address, file_offset, error))
|
| + return NULL;
|
| +
|
| + // Load all dependendent libraries.
|
| + LOG("%s: Loading dependencies of %s\n", __FUNCTION__, base_name);
|
| + SharedLibrary::DependencyIterator iter(lib.Get());
|
| + Vector<LibraryView*> dependencies;
|
| + while (iter.GetNext()) {
|
| + Error dep_error;
|
| + LibraryView* dependency =
|
| + LoadLibrary(iter.GetName(),
|
| + dlopen_mode,
|
| + 0U /* load address */,
|
| + 0U /* file offset */,
|
| + search_path_list,
|
| + &dep_error);
|
| + if (!dependency) {
|
| + error->Format("When loading %s: %s",
|
| + base_name, dep_error.c_str());
|
| + return NULL;
|
| + }
|
| + dependencies.PushBack(dependency);
|
| + }
|
| + if (CRAZY_DEBUG) {
|
| + LOG("%s: Dependencies loaded for %s\n", __FUNCTION__, base_name);
|
| + for (size_t n = 0; n < dependencies.GetCount(); ++n)
|
| + LOG(" ... %p %s\n", dependencies[n], dependencies[n]->GetName());
|
| + LOG(" dependencies @%p\n", &dependencies);
|
| + }
|
| +
|
| + // Relocate the library.
|
| + LOG("%s: Relocating %s", __FUNCTION__, base_name);
|
| + if (!lib->Relocate(this, &dependencies, error))
|
| + return NULL;
|
| +
|
| + // Notify GDB of load.
|
| + lib->link_map.l_addr = lib->base;
|
| + lib->link_map.l_name = const_cast<char*>(lib->base_name);
|
| + lib->link_map.l_ld = reinterpret_cast<uintptr_t>(lib->dynamic);
|
| + Globals::GetRDebug()->AddEntry(&lib->link_map);
|
| +
|
| + // The library was properly loaded, add it to the list of crazy
|
| + // libraries. IMPORTANT: Do this _before_ calling the constructors
|
| + // because these could call dlopen().
|
| + lib->list_next = head_;
|
| + lib->list_prev = NULL;
|
| + if (head_)
|
| + head_->list_prev = lib.Get();
|
| + head_ = lib.Get();
|
| +
|
| + // Then create a new LibraryView for it.
|
| + wrap = new LibraryView();
|
| + wrap->SetCrazy(lib.Get(), lib_name);
|
| + known_libraries_.PushBack(wrap);
|
| +
|
| + LOG("%s: Running constructors for %s\n", __FUNCTION__, base_name);
|
| +
|
| + // Now run the constructors.
|
| + lib->CallConstructors();
|
| +
|
| + LOG("%s: Done loading %s\n", __FUNCTION__, base_name);
|
| + lib.Release();
|
| +
|
| + return wrap;
|
| +}
|
| +
|
| +void LibraryList::AddLibrary(LibraryView* wrap) {
|
| + known_libraries_.PushBack(wrap);
|
| +}
|
| +
|
| +LibraryView* LibraryList::FindKnownLibrary(const char* name) {
|
| + const char* base_name = GetBaseNamePtr(name);
|
| + for (size_t n = 0; n < known_libraries_.GetCount(); ++n) {
|
| + LibraryView* wrap = known_libraries_[n];
|
| + if (!strcmp(base_name, wrap->GetName()))
|
| + return wrap;
|
| + }
|
| + return NULL;
|
| +}
|
| +
|
| +} // namespace crazy
|
|
|