1 /* 2 * libjingle 3 * Copyright 2004--2010, Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include "talk/base/latebindingsymboltable.h" 29 30 #ifdef POSIX 31 #include <dlfcn.h> 32 #endif 33 34 #include "talk/base/logging.h" 35 36 namespace talk_base { 37 38 #ifdef POSIX 39 static const DllHandle kInvalidDllHandle = NULL; 40 #else 41 #error Not implemented 42 #endif 43 44 static const char *GetDllError() { 45 #ifdef POSIX 46 const char *err = dlerror(); 47 if (err) { 48 return err; 49 } else { 50 return "No error"; 51 } 52 #else 53 #error Not implemented 54 #endif 55 } 56 57 static bool LoadSymbol(DllHandle handle, 58 const char *symbol_name, 59 void **symbol) { 60 #ifdef POSIX 61 *symbol = dlsym(handle, symbol_name); 62 const char *err = dlerror(); 63 if (err) { 64 LOG(LS_ERROR) << "Error loading symbol " << symbol_name << ": " << err; 65 return false; 66 } else if (!*symbol) { 67 // ELF allows for symbols to be NULL, but that should never happen for our 68 // usage. 69 LOG(LS_ERROR) << "Symbol " << symbol_name << " is NULL"; 70 return false; 71 } 72 return true; 73 #else 74 #error Not implemented 75 #endif 76 } 77 78 LateBindingSymbolTable::LateBindingSymbolTable(const TableInfo *info, 79 void **table) 80 : info_(info), 81 table_(table), 82 handle_(kInvalidDllHandle), 83 undefined_symbols_(false) { 84 ClearSymbols(); 85 } 86 87 LateBindingSymbolTable::~LateBindingSymbolTable() { 88 Unload(); 89 } 90 91 bool LateBindingSymbolTable::IsLoaded() const { 92 return handle_ != kInvalidDllHandle; 93 } 94 95 bool LateBindingSymbolTable::Load() { 96 ASSERT(info_->dll_name != NULL); 97 return LoadFromPath(info_->dll_name); 98 } 99 100 bool LateBindingSymbolTable::LoadFromPath(const char *dll_path) { 101 if (IsLoaded()) { 102 return true; 103 } 104 if (undefined_symbols_) { 105 // We do not attempt to load again because repeated attempts are not 106 // likely to succeed and DLL loading is costly. 107 LOG(LS_ERROR) << "We know there are undefined symbols"; 108 return false; 109 } 110 111 #ifdef POSIX 112 handle_ = dlopen(dll_path, 113 // RTLD_NOW front-loads symbol resolution so that errors are 114 // caught early instead of causing a process abort later. 115 // RTLD_LOCAL prevents other modules from automatically 116 // seeing symbol definitions in the newly-loaded tree. This 117 // is necessary for same-named symbols in different ABI 118 // versions of the same library to not explode. 119 RTLD_NOW|RTLD_LOCAL 120 #ifdef LINUX 121 // RTLD_DEEPBIND makes symbol dependencies in the 122 // newly-loaded tree prefer to resolve to definitions within 123 // that tree (the default on OS X). This is necessary for 124 // same-named symbols in different ABI versions of the same 125 // library to not explode. 126 |RTLD_DEEPBIND 127 #endif 128 ); // NOLINT 129 #else 130 #error Not implemented 131 #endif 132 133 if (handle_ == kInvalidDllHandle) { 134 LOG(LS_WARNING) << "Can't load " << dll_path << ": " 135 << GetDllError(); 136 return false; 137 } 138 #ifdef POSIX 139 // Clear any old errors. 140 dlerror(); 141 #endif 142 for (int i = 0; i < info_->num_symbols; ++i) { 143 if (!LoadSymbol(handle_, info_->symbol_names[i], &table_[i])) { 144 undefined_symbols_ = true; 145 Unload(); 146 return false; 147 } 148 } 149 return true; 150 } 151 152 void LateBindingSymbolTable::Unload() { 153 if (!IsLoaded()) { 154 return; 155 } 156 157 #ifdef POSIX 158 if (dlclose(handle_) != 0) { 159 LOG(LS_ERROR) << GetDllError(); 160 } 161 #else 162 #error Not implemented 163 #endif 164 165 handle_ = kInvalidDllHandle; 166 ClearSymbols(); 167 } 168 169 void LateBindingSymbolTable::ClearSymbols() { 170 memset(table_, 0, sizeof(void *) * info_->num_symbols); 171 } 172 173 } // namespace talk_base 174