/* * Copyright 2004 The WebRTC Project Authors. All rights reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "webrtc/base/latebindingsymboltable.h" #if defined(WEBRTC_POSIX) #include <dlfcn.h> #endif #include "webrtc/base/logging.h" namespace rtc { #if defined(WEBRTC_POSIX) static const DllHandle kInvalidDllHandle = NULL; #else #error Not implemented #endif static const char *GetDllError() { #if defined(WEBRTC_POSIX) const char *err = dlerror(); if (err) { return err; } else { return "No error"; } #else #error Not implemented #endif } static bool LoadSymbol(DllHandle handle, const char *symbol_name, void **symbol) { #if defined(WEBRTC_POSIX) *symbol = dlsym(handle, symbol_name); const char *err = dlerror(); if (err) { LOG(LS_ERROR) << "Error loading symbol " << symbol_name << ": " << err; return false; } else if (!*symbol) { // ELF allows for symbols to be NULL, but that should never happen for our // usage. LOG(LS_ERROR) << "Symbol " << symbol_name << " is NULL"; return false; } return true; #else #error Not implemented #endif } LateBindingSymbolTable::LateBindingSymbolTable(const TableInfo *info, void **table) : info_(info), table_(table), handle_(kInvalidDllHandle), undefined_symbols_(false) { ClearSymbols(); } LateBindingSymbolTable::~LateBindingSymbolTable() { Unload(); } bool LateBindingSymbolTable::IsLoaded() const { return handle_ != kInvalidDllHandle; } bool LateBindingSymbolTable::Load() { ASSERT(info_->dll_name != NULL); return LoadFromPath(info_->dll_name); } bool LateBindingSymbolTable::LoadFromPath(const char *dll_path) { if (IsLoaded()) { return true; } if (undefined_symbols_) { // We do not attempt to load again because repeated attempts are not // likely to succeed and DLL loading is costly. LOG(LS_ERROR) << "We know there are undefined symbols"; return false; } #if defined(WEBRTC_POSIX) handle_ = dlopen(dll_path, // RTLD_NOW front-loads symbol resolution so that errors are // caught early instead of causing a process abort later. // RTLD_LOCAL prevents other modules from automatically // seeing symbol definitions in the newly-loaded tree. This // is necessary for same-named symbols in different ABI // versions of the same library to not explode. RTLD_NOW|RTLD_LOCAL #if defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID) // RTLD_DEEPBIND makes symbol dependencies in the // newly-loaded tree prefer to resolve to definitions within // that tree (the default on OS X). This is necessary for // same-named symbols in different ABI versions of the same // library to not explode. |RTLD_DEEPBIND #endif ); // NOLINT #else #error Not implemented #endif if (handle_ == kInvalidDllHandle) { LOG(LS_WARNING) << "Can't load " << dll_path << ": " << GetDllError(); return false; } #if defined(WEBRTC_POSIX) // Clear any old errors. dlerror(); #endif for (int i = 0; i < info_->num_symbols; ++i) { if (!LoadSymbol(handle_, info_->symbol_names[i], &table_[i])) { undefined_symbols_ = true; Unload(); return false; } } return true; } void LateBindingSymbolTable::Unload() { if (!IsLoaded()) { return; } #if defined(WEBRTC_POSIX) if (dlclose(handle_) != 0) { LOG(LS_ERROR) << GetDllError(); } #else #error Not implemented #endif handle_ = kInvalidDllHandle; ClearSymbols(); } void LateBindingSymbolTable::ClearSymbols() { memset(table_, 0, sizeof(void *) * info_->num_symbols); } } // namespace rtc