1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen/* 2ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * libjingle 3ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * Copyright 2004--2010, Google Inc. 4ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * 5ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * Redistribution and use in source and binary forms, with or without 6ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * modification, are permitted provided that the following conditions are met: 7ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * 8ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * 1. Redistributions of source code must retain the above copyright notice, 9ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * this list of conditions and the following disclaimer. 10ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * 2. Redistributions in binary form must reproduce the above copyright notice, 11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * this list of conditions and the following disclaimer in the documentation 12ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * and/or other materials provided with the distribution. 13ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * 3. The name of the author may not be used to endorse or promote products 14ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * derived from this software without specific prior written permission. 15ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * 16ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen */ 27ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 28ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#ifndef TALK_BASE_LATEBINDINGSYMBOLTABLE_H_ 29ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#define TALK_BASE_LATEBINDINGSYMBOLTABLE_H_ 30ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 31ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include <stddef.h> // for NULL 32ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include <string.h> 33ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 34ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "talk/base/common.h" 35ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "talk/base/logging.h" 36ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 37ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// This file provides macros for creating "symbol table" classes to simplify the 38ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// dynamic loading of symbols from DLLs. Currently the implementation only 39ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// supports Linux and pure C symbols. 40ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// See talk/sound/pulseaudiosymboltable.(h|cc) for an example. 41ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 42ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsennamespace talk_base { 43ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 44ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#ifdef LINUX 45ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsentypedef void *DllHandle; 46ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 47ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenconst DllHandle kInvalidDllHandle = NULL; 48ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#else 49ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#error Not implemented 50ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#endif 51ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 52ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// These are helpers for use only by the class below. 53ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenDllHandle InternalLoadDll(const char dll_name[]); 54ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 55ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid InternalUnloadDll(DllHandle handle); 56ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 57ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool InternalLoadSymbols(DllHandle handle, 58ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen int num_symbols, 59ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const char *const symbol_names[], 60ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen void *symbols[]); 61ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 62ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsentemplate <int SYMBOL_TABLE_SIZE, 63ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const char kDllName[], 64ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const char *const kSymbolNames[]> 65ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenclass LateBindingSymbolTable { 66ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen public: 67ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen LateBindingSymbolTable() 68ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen : handle_(kInvalidDllHandle), 69ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen undefined_symbols_(false) { 70ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen memset(symbols_, 0, sizeof(symbols_)); 71ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 72ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 73ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ~LateBindingSymbolTable() { 74ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen Unload(); 75ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 76ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 77ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen static int NumSymbols() { 78ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return SYMBOL_TABLE_SIZE; 79ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 80ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 81ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // We do not use this, but we offer it for theoretical convenience. 82ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen static const char *GetSymbolName(int index) { 83ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ASSERT(index < NumSymbols()); 84ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return kSymbolNames[index]; 85ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 86ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 87ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bool IsLoaded() const { 88ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return handle_ != kInvalidDllHandle; 89ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 90ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 91ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Loads the DLL and the symbol table. Returns true iff the DLL and symbol 92ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // table loaded successfully. 93ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bool Load() { 94ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (IsLoaded()) { 95ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return true; 96ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 97ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (undefined_symbols_) { 98ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // We do not attempt to load again because repeated attempts are not 99ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // likely to succeed and DLL loading is costly. 100ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen LOG(LS_ERROR) << "We know there are undefined symbols"; 101ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return false; 102ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 103ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen handle_ = InternalLoadDll(kDllName); 104ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!IsLoaded()) { 105ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return false; 106ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 107ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!InternalLoadSymbols(handle_, NumSymbols(), kSymbolNames, symbols_)) { 108ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen undefined_symbols_ = true; 109ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen Unload(); 110ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return false; 111ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 112ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return true; 113ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 114ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 115ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen void Unload() { 116ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (!IsLoaded()) { 117ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return; 118ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 119ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen InternalUnloadDll(handle_); 120ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen handle_ = kInvalidDllHandle; 121ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen memset(symbols_, 0, sizeof(symbols_)); 122ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 123ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 124ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Retrieves the given symbol. NOTE: Recommended to use LATESYM_GET below 125ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // instead of this. 126ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen void *GetSymbol(int index) const { 127ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ASSERT(IsLoaded()); 128ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ASSERT(index < NumSymbols()); 129ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return symbols_[index]; 130ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 131ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 132ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen private: 133ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DllHandle handle_; 134ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bool undefined_symbols_; 135ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen void *symbols_[SYMBOL_TABLE_SIZE]; 136ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 137ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DISALLOW_COPY_AND_ASSIGN(LateBindingSymbolTable); 138ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}; 139ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 140ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// This macro must be invoked in a header to declare a symbol table class. 141ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#define LATE_BINDING_SYMBOL_TABLE_DECLARE_BEGIN(ClassName) \ 142ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenenum { 143ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 144ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// This macro must be invoked in the header declaration once for each symbol 145ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// (recommended to use an X-Macro to avoid duplication). 146ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// This macro defines an enum with names built from the symbols, which 147ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// essentially creates a hash table in the compiler from symbol names to their 148ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// indices in the symbol table class. 149ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#define LATE_BINDING_SYMBOL_TABLE_DECLARE_ENTRY(ClassName, sym) \ 150ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ClassName##_SYMBOL_TABLE_INDEX_##sym, 151ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 152ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// This macro completes the header declaration. 153ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#define LATE_BINDING_SYMBOL_TABLE_DECLARE_END(ClassName) \ 154ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ClassName##_SYMBOL_TABLE_SIZE \ 155ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}; \ 156ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen\ 157ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenextern const char ClassName##_kDllName[]; \ 158ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenextern const char *const \ 159ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ClassName##_kSymbolNames[ClassName##_SYMBOL_TABLE_SIZE]; \ 160ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen\ 161ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsentypedef ::talk_base::LateBindingSymbolTable<ClassName##_SYMBOL_TABLE_SIZE, \ 162ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ClassName##_kDllName, \ 163ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ClassName##_kSymbolNames> \ 164ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ClassName; 165ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 166ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// This macro must be invoked in a .cc file to define a previously-declared 167ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// symbol table class. 168ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#define LATE_BINDING_SYMBOL_TABLE_DEFINE_BEGIN(ClassName, dllName) \ 169ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenconst char ClassName##_kDllName[] = dllName; \ 170ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenconst char *const ClassName##_kSymbolNames[ClassName##_SYMBOL_TABLE_SIZE] = { 171ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 172ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// This macro must be invoked in the .cc definition once for each symbol 173ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// (recommended to use an X-Macro to avoid duplication). 174ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// This would have to use the mangled name if we were to ever support C++ 175ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// symbols. 176ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#define LATE_BINDING_SYMBOL_TABLE_DEFINE_ENTRY(ClassName, sym) \ 177ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen #sym, 178ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 179ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#define LATE_BINDING_SYMBOL_TABLE_DEFINE_END(ClassName) \ 180ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}; 181ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 182ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Index of a given symbol in the given symbol table class. 183ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#define LATESYM_INDEXOF(ClassName, sym) \ 184ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen (ClassName##_SYMBOL_TABLE_INDEX_##sym) 185ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 186ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Returns a reference to the given late-binded symbol, with the correct type. 187ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#define LATESYM_GET(ClassName, inst, sym) \ 188ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen (*reinterpret_cast<typeof(&sym)>( \ 189ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen (inst)->GetSymbol(LATESYM_INDEXOF(ClassName, sym)))) 190ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 191ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} // namespace talk_base 192ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 193ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#endif // TALK_BASE_LATEBINDINGSYMBOLTABLE_H_ 194