Home | History | Annotate | Download | only in base
      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