1 /* 2 * Copyright (c) 2010 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 #ifndef AUDIO_DEVICE_LATEBINDINGSYMBOLTABLE_LINUX_H_ 12 #define AUDIO_DEVICE_LATEBINDINGSYMBOLTABLE_LINUX_H_ 13 14 #include <stddef.h> // for NULL 15 #include <string.h> 16 17 #include "absl/strings/string_view.h" 18 #include "rtc_base/checks.h" 19 20 // This file provides macros for creating "symbol table" classes to simplify the 21 // dynamic loading of symbols from DLLs. Currently the implementation only 22 // supports Linux and pure C symbols. 23 // See talk/sound/pulseaudiosymboltable.(h|cc) for an example. 24 25 namespace webrtc { 26 namespace adm_linux { 27 28 #ifdef WEBRTC_LINUX 29 typedef void* DllHandle; 30 31 const DllHandle kInvalidDllHandle = NULL; 32 #else 33 #error Not implemented 34 #endif 35 36 // These are helpers for use only by the class below. 37 DllHandle InternalLoadDll(absl::string_view); 38 39 void InternalUnloadDll(DllHandle handle); 40 41 bool InternalLoadSymbols(DllHandle handle, 42 int num_symbols, 43 const char* const symbol_names[], 44 void* symbols[]); 45 46 template <int SYMBOL_TABLE_SIZE, 47 const char kDllName[], 48 const char* const kSymbolNames[]> 49 class LateBindingSymbolTable { 50 public: LateBindingSymbolTable()51 LateBindingSymbolTable() 52 : handle_(kInvalidDllHandle), undefined_symbols_(false) { 53 memset(symbols_, 0, sizeof(symbols_)); 54 } 55 ~LateBindingSymbolTable()56 ~LateBindingSymbolTable() { Unload(); } 57 58 LateBindingSymbolTable(const LateBindingSymbolTable&) = delete; 59 LateBindingSymbolTable& operator=(LateBindingSymbolTable&) = delete; 60 NumSymbols()61 static int NumSymbols() { return SYMBOL_TABLE_SIZE; } 62 63 // We do not use this, but we offer it for theoretical convenience. GetSymbolName(int index)64 static const char* GetSymbolName(int index) { 65 RTC_DCHECK_LT(index, NumSymbols()); 66 return kSymbolNames[index]; 67 } 68 IsLoaded()69 bool IsLoaded() const { return handle_ != kInvalidDllHandle; } 70 71 // Loads the DLL and the symbol table. Returns true iff the DLL and symbol 72 // table loaded successfully. Load()73 bool Load() { 74 if (IsLoaded()) { 75 return true; 76 } 77 if (undefined_symbols_) { 78 // We do not attempt to load again because repeated attempts are not 79 // likely to succeed and DLL loading is costly. 80 return false; 81 } 82 handle_ = InternalLoadDll(kDllName); 83 if (!IsLoaded()) { 84 return false; 85 } 86 if (!InternalLoadSymbols(handle_, NumSymbols(), kSymbolNames, symbols_)) { 87 undefined_symbols_ = true; 88 Unload(); 89 return false; 90 } 91 return true; 92 } 93 Unload()94 void Unload() { 95 if (!IsLoaded()) { 96 return; 97 } 98 InternalUnloadDll(handle_); 99 handle_ = kInvalidDllHandle; 100 memset(symbols_, 0, sizeof(symbols_)); 101 } 102 103 // Retrieves the given symbol. NOTE: Recommended to use LATESYM_GET below 104 // instead of this. GetSymbol(int index)105 void* GetSymbol(int index) const { 106 RTC_DCHECK(IsLoaded()); 107 RTC_DCHECK_LT(index, NumSymbols()); 108 return symbols_[index]; 109 } 110 111 private: 112 DllHandle handle_; 113 bool undefined_symbols_; 114 void* symbols_[SYMBOL_TABLE_SIZE]; 115 }; 116 117 // This macro must be invoked in a header to declare a symbol table class. 118 #define LATE_BINDING_SYMBOL_TABLE_DECLARE_BEGIN(ClassName) enum { 119 // This macro must be invoked in the header declaration once for each symbol 120 // (recommended to use an X-Macro to avoid duplication). 121 // This macro defines an enum with names built from the symbols, which 122 // essentially creates a hash table in the compiler from symbol names to their 123 // indices in the symbol table class. 124 #define LATE_BINDING_SYMBOL_TABLE_DECLARE_ENTRY(ClassName, sym) \ 125 ClassName##_SYMBOL_TABLE_INDEX_##sym, 126 127 // This macro completes the header declaration. 128 #define LATE_BINDING_SYMBOL_TABLE_DECLARE_END(ClassName) \ 129 ClassName##_SYMBOL_TABLE_SIZE \ 130 } \ 131 ; \ 132 \ 133 extern const char ClassName##_kDllName[]; \ 134 extern const char* const \ 135 ClassName##_kSymbolNames[ClassName##_SYMBOL_TABLE_SIZE]; \ 136 \ 137 typedef ::webrtc::adm_linux::LateBindingSymbolTable< \ 138 ClassName##_SYMBOL_TABLE_SIZE, ClassName##_kDllName, \ 139 ClassName##_kSymbolNames> \ 140 ClassName; 141 142 // This macro must be invoked in a .cc file to define a previously-declared 143 // symbol table class. 144 #define LATE_BINDING_SYMBOL_TABLE_DEFINE_BEGIN(ClassName, dllName) \ 145 const char ClassName##_kDllName[] = dllName; \ 146 const char* const ClassName##_kSymbolNames[ClassName##_SYMBOL_TABLE_SIZE] = { 147 // This macro must be invoked in the .cc definition once for each symbol 148 // (recommended to use an X-Macro to avoid duplication). 149 // This would have to use the mangled name if we were to ever support C++ 150 // symbols. 151 #define LATE_BINDING_SYMBOL_TABLE_DEFINE_ENTRY(ClassName, sym) #sym, 152 153 #define LATE_BINDING_SYMBOL_TABLE_DEFINE_END(ClassName) \ 154 } \ 155 ; 156 157 // Index of a given symbol in the given symbol table class. 158 #define LATESYM_INDEXOF(ClassName, sym) (ClassName##_SYMBOL_TABLE_INDEX_##sym) 159 160 // Returns a reference to the given late-binded symbol, with the correct type. 161 #define LATESYM_GET(ClassName, inst, sym) \ 162 (*reinterpret_cast<__typeof__(&sym)>( \ 163 (inst)->GetSymbol(LATESYM_INDEXOF(ClassName, sym)))) 164 165 } // namespace adm_linux 166 } // namespace webrtc 167 168 #endif // ADM_LATEBINDINGSYMBOLTABLE_LINUX_H_ 169