blob: 1896bd0f9b9df3a6be44abc89dde6d950a2535ab [file] [log] [blame]
henrike@webrtc.orgf7795df2014-05-13 18:00:26 +00001/*
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
19namespace rtc {
20
21#if defined(WEBRTC_POSIX)
22static const DllHandle kInvalidDllHandle = NULL;
23#else
24#error Not implemented
25#endif
26
27static 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
40static 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
61LateBindingSymbolTable::LateBindingSymbolTable(const TableInfo *info,
62 void **table)
63 : info_(info),
64 table_(table),
65 handle_(kInvalidDllHandle),
66 undefined_symbols_(false) {
67 ClearSymbols();
68}
69
70LateBindingSymbolTable::~LateBindingSymbolTable() {
71 Unload();
72}
73
74bool LateBindingSymbolTable::IsLoaded() const {
75 return handle_ != kInvalidDllHandle;
76}
77
78bool LateBindingSymbolTable::Load() {
79 ASSERT(info_->dll_name != NULL);
80 return LoadFromPath(info_->dll_name);
81}
82
83bool 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)
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
135void 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
152void LateBindingSymbolTable::ClearSymbols() {
153 memset(table_, 0, sizeof(void *) * info_->num_symbols);
154}
155
156} // namespace rtc