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 
GetDllError()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 
LoadSymbol(DllHandle handle,const char * symbol_name,void ** symbol)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 
LateBindingSymbolTable(const TableInfo * info,void ** table)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 
~LateBindingSymbolTable()70 LateBindingSymbolTable::~LateBindingSymbolTable() {
71   Unload();
72 }
73 
IsLoaded() const74 bool LateBindingSymbolTable::IsLoaded() const {
75   return handle_ != kInvalidDllHandle;
76 }
77 
Load()78 bool LateBindingSymbolTable::Load() {
79   ASSERT(info_->dll_name != NULL);
80   return LoadFromPath(info_->dll_name);
81 }
82 
LoadFromPath(const char * dll_path)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 
Unload()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 
ClearSymbols()152 void LateBindingSymbolTable::ClearSymbols() {
153   memset(table_, 0, sizeof(void *) * info_->num_symbols);
154 }
155 
156 }  // namespace rtc
157