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