1 /* 2 * Copyright 2004 The WebRTC Project Authors. All rights reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "webrtc/base/latebindingsymboltable.h" 12 13 #if defined(WEBRTC_POSIX) 14 #include <dlfcn.h> 15 #endif 16 17 #include "webrtc/base/logging.h" 18 19 namespace rtc { 20 21 #if defined(WEBRTC_POSIX) 22 static const DllHandle kInvalidDllHandle = NULL; 23 #else 24 #error Not implemented 25 #endif 26 27 static const char *GetDllError() { 28 #if defined(WEBRTC_POSIX) 29 const char *err = dlerror(); 30 if (err) { 31 return err; 32 } else { 33 return "No error"; 34 } 35 #else 36 #error Not implemented 37 #endif 38 } 39 40 static bool LoadSymbol(DllHandle handle, 41 const char *symbol_name, 42 void **symbol) { 43 #if defined(WEBRTC_POSIX) 44 *symbol = dlsym(handle, symbol_name); 45 const char *err = dlerror(); 46 if (err) { 47 LOG(LS_ERROR) << "Error loading symbol " << symbol_name << ": " << err; 48 return false; 49 } else if (!*symbol) { 50 // ELF allows for symbols to be NULL, but that should never happen for our 51 // usage. 52 LOG(LS_ERROR) << "Symbol " << symbol_name << " is NULL"; 53 return false; 54 } 55 return true; 56 #else 57 #error Not implemented 58 #endif 59 } 60 61 LateBindingSymbolTable::LateBindingSymbolTable(const TableInfo *info, 62 void **table) 63 : info_(info), 64 table_(table), 65 handle_(kInvalidDllHandle), 66 undefined_symbols_(false) { 67 ClearSymbols(); 68 } 69 70 LateBindingSymbolTable::~LateBindingSymbolTable() { 71 Unload(); 72 } 73 74 bool LateBindingSymbolTable::IsLoaded() const { 75 return handle_ != kInvalidDllHandle; 76 } 77 78 bool LateBindingSymbolTable::Load() { 79 ASSERT(info_->dll_name != NULL); 80 return LoadFromPath(info_->dll_name); 81 } 82 83 bool LateBindingSymbolTable::LoadFromPath(const char *dll_path) { 84 if (IsLoaded()) { 85 return true; 86 } 87 if (undefined_symbols_) { 88 // We do not attempt to load again because repeated attempts are not 89 // likely to succeed and DLL loading is costly. 90 LOG(LS_ERROR) << "We know there are undefined symbols"; 91 return false; 92 } 93 94 #if defined(WEBRTC_POSIX) 95 handle_ = dlopen(dll_path, 96 // RTLD_NOW front-loads symbol resolution so that errors are 97 // caught early instead of causing a process abort later. 98 // RTLD_LOCAL prevents other modules from automatically 99 // seeing symbol definitions in the newly-loaded tree. This 100 // is necessary for same-named symbols in different ABI 101 // versions of the same library to not explode. 102 RTLD_NOW|RTLD_LOCAL 103 #if defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID) && defined(RTLD_DEEPBIND) 104 // RTLD_DEEPBIND makes symbol dependencies in the 105 // newly-loaded tree prefer to resolve to definitions within 106 // that tree (the default on OS X). This is necessary for 107 // same-named symbols in different ABI versions of the same 108 // library to not explode. 109 |RTLD_DEEPBIND 110 #endif 111 ); // NOLINT 112 #else 113 #error Not implemented 114 #endif 115 116 if (handle_ == kInvalidDllHandle) { 117 LOG(LS_WARNING) << "Can't load " << dll_path << ": " 118 << GetDllError(); 119 return false; 120 } 121 #if defined(WEBRTC_POSIX) 122 // Clear any old errors. 123 dlerror(); 124 #endif 125 for (int i = 0; i < info_->num_symbols; ++i) { 126 if (!LoadSymbol(handle_, info_->symbol_names[i], &table_[i])) { 127 undefined_symbols_ = true; 128 Unload(); 129 return false; 130 } 131 } 132 return true; 133 } 134 135 void LateBindingSymbolTable::Unload() { 136 if (!IsLoaded()) { 137 return; 138 } 139 140 #if defined(WEBRTC_POSIX) 141 if (dlclose(handle_) != 0) { 142 LOG(LS_ERROR) << GetDllError(); 143 } 144 #else 145 #error Not implemented 146 #endif 147 148 handle_ = kInvalidDllHandle; 149 ClearSymbols(); 150 } 151 152 void LateBindingSymbolTable::ClearSymbols() { 153 memset(table_, 0, sizeof(void *) * info_->num_symbols); 154 } 155 156 } // namespace rtc 157