• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***
2   This file is part of PulseAudio.
3 
4   Copyright 2004-2008 Lennart Poettering
5   Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6 
7   PulseAudio is free software; you can redistribute it and/or modify
8   it under the terms of the GNU Lesser General Public License as published
9   by the Free Software Foundation; either version 2.1 of the License,
10   or (at your option) any later version.
11 
12   PulseAudio is distributed in the hope that it will be useful, but
13   WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   General Public License for more details.
16 
17   You should have received a copy of the GNU Lesser General Public License
18   along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
19 ***/
20 
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 
25 #ifdef HAVE_DLFCN_H
26 #include <dlfcn.h>
27 #endif
28 
29 #ifdef HAVE_SYS_DL_H
30 #include <sys/dl.h>
31 #endif
32 
33 #include <string.h>
34 
35 #include <ltdl.h>
36 
37 #include <pulsecore/i18n.h>
38 #include <pulsecore/macro.h>
39 #include <pulsecore/log.h>
40 
41 #include "ltdl-bind-now.h"
42 
43 #ifdef RTLD_NOW
44 #define PA_BIND_NOW RTLD_NOW
45 #elif defined(DL_NOW)
46 #define PA_BIND_NOW DL_NOW
47 #else
48 #undef PA_BIND_NOW
49 #endif
50 
51 #ifdef OS_IS_WIN32
52 #undef PA_BIND_NOW
53 #endif
54 
55 #ifdef PA_BIND_NOW
56 
57 /*
58   To avoid lazy relocations during runtime in our RT threads we add
59   our own shared object loader with uses RTLD_NOW if it is
60   available. The standard ltdl loader prefers RTLD_LAZY.
61 
62   Please note that this loader doesn't have any influence on
63   relocations on any libraries that are already loaded into our
64   process, i.e. because the pulseaudio binary links directly to
65   them. To disable lazy relocations for those libraries it is possible
66   to set $LT_BIND_NOW before starting the pulseaudio binary.
67 */
68 
bind_now_open(lt_user_data d,const char * fname,lt_dladvise advise)69 static lt_module bind_now_open(lt_user_data d, const char *fname, lt_dladvise advise) {
70     lt_module m;
71 
72     pa_assert(fname);
73 
74     if (!(m = dlopen(fname, PA_BIND_NOW))) {
75         pa_log(_("Failed to open module %s: %s"), fname, dlerror());
76         lt_dlseterror(LT_ERROR_CANNOT_OPEN);
77         return NULL;
78     }
79 
80     return m;
81 }
82 
bind_now_close(lt_user_data d,lt_module m)83 static int bind_now_close(lt_user_data d, lt_module m) {
84 
85     pa_assert(m);
86 
87     if (dlclose(m) != 0) {
88         lt_dlseterror(LT_ERROR_CANNOT_CLOSE);
89         return 1;
90     }
91 
92     return 0;
93 }
94 
bind_now_find_sym(lt_user_data d,lt_module m,const char * symbol)95 static lt_ptr bind_now_find_sym(lt_user_data d, lt_module m, const char *symbol) {
96     lt_ptr ptr;
97 
98     pa_assert(m);
99     pa_assert(symbol);
100 
101     if (!(ptr = dlsym(m, symbol))) {
102         lt_dlseterror(LT_ERROR_SYMBOL_NOT_FOUND);
103         return NULL;
104     }
105 
106     return ptr;
107 }
108 
109 static lt_dlvtable *bindnow_loader = NULL;
110 #endif
111 
pa_ltdl_init(void)112 void pa_ltdl_init(void) {
113 
114 #ifdef PA_BIND_NOW
115     const lt_dlvtable *dlopen_loader;
116 #endif
117 
118     pa_assert_se(lt_dlinit() == 0);
119 
120 #ifdef PA_BIND_NOW
121     /* Already initialised */
122     if (bindnow_loader)
123         return;
124 
125     if (!(dlopen_loader = lt_dlloader_find((char*) "lt_dlopen"))) {
126         pa_log_warn(_("Failed to find original lt_dlopen loader."));
127         return;
128     }
129 
130     if (!(bindnow_loader = malloc(sizeof(lt_dlvtable)))) {
131         pa_log_error(_("Failed to allocate new dl loader."));
132         return;
133     }
134 
135     memcpy(bindnow_loader, dlopen_loader, sizeof(*bindnow_loader));
136     bindnow_loader->name = "bind-now-loader";
137     bindnow_loader->module_open = bind_now_open;
138     bindnow_loader->module_close = bind_now_close;
139     bindnow_loader->find_sym = bind_now_find_sym;
140     bindnow_loader->priority = LT_DLLOADER_PREPEND;
141 
142     /* Add our BIND_NOW loader as the default module loader. */
143     if (lt_dlloader_add(bindnow_loader) != 0) {
144         pa_log_warn(_("Failed to add bind-now-loader."));
145         free(bindnow_loader);
146         bindnow_loader = NULL;
147     }
148 #endif
149 }
150 
pa_ltdl_done(void)151 void pa_ltdl_done(void) {
152     pa_assert_se(lt_dlexit() == 0);
153 
154 #ifdef PA_BIND_NOW
155     /* lt_dlexit() will free our loader vtable, hence reset our
156      * pointer to it here */
157     bindnow_loader = NULL;
158 #endif
159 }
160