147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org/*
247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *
447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  Use of this source code is governed by a BSD-style license
547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  that can be found in the LICENSE file in the root of the source
647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  tree. An additional intellectual property rights grant can be found
747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  in the file PATENTS.  All contributing project authors may
847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org */
1047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
1147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/latebindingsymboltable.h"
1247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
1347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#if defined(WEBRTC_POSIX)
1447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include <dlfcn.h>
1547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#endif
1647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
1747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/logging.h"
1847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
1947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgnamespace rtc {
2047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
2147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#if defined(WEBRTC_POSIX)
2247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic const DllHandle kInvalidDllHandle = NULL;
2347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#else
2447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#error Not implemented
2547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#endif
2647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
2747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic const char *GetDllError() {
2847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#if defined(WEBRTC_POSIX)
2947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  const char *err = dlerror();
3047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (err) {
3147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return err;
3247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  } else {
3347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return "No error";
3447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
3547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#else
3647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#error Not implemented
3747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#endif
3847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
3947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
4047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic bool LoadSymbol(DllHandle handle,
4147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                       const char *symbol_name,
4247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                       void **symbol) {
4347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#if defined(WEBRTC_POSIX)
4447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  *symbol = dlsym(handle, symbol_name);
4547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  const char *err = dlerror();
4647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (err) {
4747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    LOG(LS_ERROR) << "Error loading symbol " << symbol_name << ": " << err;
4847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return false;
4947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  } else if (!*symbol) {
5047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // ELF allows for symbols to be NULL, but that should never happen for our
5147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // usage.
5247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    LOG(LS_ERROR) << "Symbol " << symbol_name << " is NULL";
5347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return false;
5447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
5547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return true;
5647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#else
5747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#error Not implemented
5847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#endif
5947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
6047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
6147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgLateBindingSymbolTable::LateBindingSymbolTable(const TableInfo *info,
6247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    void **table)
6347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    : info_(info),
6447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      table_(table),
6547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      handle_(kInvalidDllHandle),
6647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      undefined_symbols_(false) {
6747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ClearSymbols();
6847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
6947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
7047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgLateBindingSymbolTable::~LateBindingSymbolTable() {
7147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  Unload();
7247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
7347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
7447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgbool LateBindingSymbolTable::IsLoaded() const {
7547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return handle_ != kInvalidDllHandle;
7647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
7747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
7847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgbool LateBindingSymbolTable::Load() {
7947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ASSERT(info_->dll_name != NULL);
8047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return LoadFromPath(info_->dll_name);
8147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
8247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
8347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgbool LateBindingSymbolTable::LoadFromPath(const char *dll_path) {
8447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (IsLoaded()) {
8547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return true;
8647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
8747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (undefined_symbols_) {
8847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // We do not attempt to load again because repeated attempts are not
8947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // likely to succeed and DLL loading is costly.
9047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    LOG(LS_ERROR) << "We know there are undefined symbols";
9147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return false;
9247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
9347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
9447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#if defined(WEBRTC_POSIX)
9547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  handle_ = dlopen(dll_path,
9647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                   // RTLD_NOW front-loads symbol resolution so that errors are
9747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                   // caught early instead of causing a process abort later.
9847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                   // RTLD_LOCAL prevents other modules from automatically
9947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                   // seeing symbol definitions in the newly-loaded tree. This
10047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                   // is necessary for same-named symbols in different ABI
10147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                   // versions of the same library to not explode.
10247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                   RTLD_NOW|RTLD_LOCAL
103f854f30d7981795f687f9b4379100c037934535dniklas.enbom@webrtc.org#if defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID) && defined(RTLD_DEEPBIND)
10447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                   // RTLD_DEEPBIND makes symbol dependencies in the
10547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                   // newly-loaded tree prefer to resolve to definitions within
10647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                   // that tree (the default on OS X). This is necessary for
10747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                   // same-named symbols in different ABI versions of the same
10847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                   // library to not explode.
10947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                   |RTLD_DEEPBIND
11047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#endif
11147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                   );  // NOLINT
11247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#else
11347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#error Not implemented
11447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#endif
11547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
11647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (handle_ == kInvalidDllHandle) {
11747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    LOG(LS_WARNING) << "Can't load " << dll_path << ": "
11847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                    << GetDllError();
11947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return false;
12047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
12147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#if defined(WEBRTC_POSIX)
12247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Clear any old errors.
12347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  dlerror();
12447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#endif
12547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  for (int i = 0; i < info_->num_symbols; ++i) {
12647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (!LoadSymbol(handle_, info_->symbol_names[i], &table_[i])) {
12747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      undefined_symbols_ = true;
12847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      Unload();
12947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return false;
13047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
13147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
13247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return true;
13347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
13447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
13547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid LateBindingSymbolTable::Unload() {
13647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!IsLoaded()) {
13747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return;
13847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
13947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
14047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#if defined(WEBRTC_POSIX)
14147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (dlclose(handle_) != 0) {
14247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    LOG(LS_ERROR) << GetDllError();
14347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
14447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#else
14547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#error Not implemented
14647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#endif
14747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
14847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  handle_ = kInvalidDllHandle;
14947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ClearSymbols();
15047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
15147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
15247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid LateBindingSymbolTable::ClearSymbols() {
15347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  memset(table_, 0, sizeof(void *) * info_->num_symbols);
15447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
15547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
15647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}  // namespace rtc
157