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