1 |
/* loader-preopen.c -- emulate dynamic linking using preloaded_symbols |
2 |
|
3 |
Copyright (C) 1998, 1999, 2000, 2004, 2006, |
4 |
2007, 2008 Free Software Foundation, Inc. |
5 |
Written by Thomas Tanner, 1998 |
6 |
|
7 |
NOTE: The canonical source of this file is maintained with the |
8 |
GNU Libtool package. Report bugs to bug-libtool@gnu.org. |
9 |
|
10 |
GNU Libltdl is free software; you can redistribute it and/or |
11 |
modify it under the terms of the GNU Lesser General Public |
12 |
License as published by the Free Software Foundation; either |
13 |
version 2 of the License, or (at your option) any later version. |
14 |
|
15 |
As a special exception to the GNU Lesser General Public License, |
16 |
if you distribute this file as part of a program or library that |
17 |
is built using GNU Libtool, you may include this file under the |
18 |
same distribution terms that you use for the rest of that program. |
19 |
|
20 |
GNU Libltdl is distributed in the hope that it will be useful, |
21 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
22 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
23 |
GNU Lesser General Public License for more details. |
24 |
|
25 |
You should have received a copy of the GNU Lesser General Public |
26 |
License along with GNU Libltdl; see the file COPYING.LIB. If not, a |
27 |
copy can be downloaded from http://www.gnu.org/licenses/lgpl.html, |
28 |
or obtained by writing to the Free Software Foundation, Inc., |
29 |
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
30 |
*/ |
31 |
|
32 |
#include "lt__private.h" |
33 |
#include "lt_dlloader.h" |
34 |
|
35 |
/* Use the preprocessor to rename non-static symbols to avoid namespace |
36 |
collisions when the loader code is statically linked into libltdl. |
37 |
Use the "<module_name>_LTX_" prefix so that the symbol addresses can |
38 |
be fetched from the preloaded symbol list by lt_dlsym(): */ |
39 |
#define get_vtable preopen_LTX_get_vtable |
40 |
|
41 |
LT_BEGIN_C_DECLS |
42 |
LT_SCOPE lt_dlvtable *get_vtable (lt_user_data loader_data); |
43 |
LT_END_C_DECLS |
44 |
|
45 |
|
46 |
/* Boilerplate code to set up the vtable for hooking this loader into |
47 |
libltdl's loader list: */ |
48 |
static int vl_init (lt_user_data loader_data); |
49 |
static int vl_exit (lt_user_data loader_data); |
50 |
static lt_module vm_open (lt_user_data loader_data, const char *filename, |
51 |
lt_dladvise advise); |
52 |
static int vm_close (lt_user_data loader_data, lt_module module); |
53 |
static void * vm_sym (lt_user_data loader_data, lt_module module, |
54 |
const char *symbolname); |
55 |
|
56 |
static lt_dlvtable *vtable = 0; |
57 |
|
58 |
/* Return the vtable for this loader, only the name and sym_prefix |
59 |
attributes (plus the virtual function implementations, obviously) |
60 |
change between loaders. */ |
61 |
lt_dlvtable * |
62 |
get_vtable (lt_user_data loader_data) |
63 |
{ |
64 |
if (!vtable) |
65 |
{ |
66 |
vtable = (lt_dlvtable *) lt__zalloc (sizeof *vtable); |
67 |
} |
68 |
|
69 |
if (vtable && !vtable->name) |
70 |
{ |
71 |
vtable->name = "lt_preopen"; |
72 |
vtable->sym_prefix = 0; |
73 |
vtable->module_open = vm_open; |
74 |
vtable->module_close = vm_close; |
75 |
vtable->find_sym = vm_sym; |
76 |
vtable->dlloader_init = vl_init; |
77 |
vtable->dlloader_exit = vl_exit; |
78 |
vtable->dlloader_data = loader_data; |
79 |
vtable->priority = LT_DLLOADER_PREPEND; |
80 |
} |
81 |
|
82 |
if (vtable && (vtable->dlloader_data != loader_data)) |
83 |
{ |
84 |
LT__SETERROR (INIT_LOADER); |
85 |
return 0; |
86 |
} |
87 |
|
88 |
return vtable; |
89 |
} |
90 |
|
91 |
|
92 |
|
93 |
/* --- IMPLEMENTATION --- */ |
94 |
|
95 |
|
96 |
/* Wrapper type to chain together symbol lists of various origins. */ |
97 |
typedef struct symlist_chain |
98 |
{ |
99 |
struct symlist_chain *next; |
100 |
const lt_dlsymlist *symlist; |
101 |
} symlist_chain; |
102 |
|
103 |
|
104 |
static int add_symlist (const lt_dlsymlist *symlist); |
105 |
static int free_symlists (void); |
106 |
|
107 |
/* The start of the symbol lists chain. */ |
108 |
static symlist_chain *preloaded_symlists = 0; |
109 |
|
110 |
/* A symbol list preloaded before lt_init() was called. */ |
111 |
static const lt_dlsymlist *default_preloaded_symbols = 0; |
112 |
|
113 |
|
114 |
/* A function called through the vtable to initialise this loader. */ |
115 |
static int |
116 |
vl_init (lt_user_data LT__UNUSED loader_data) |
117 |
{ |
118 |
int errors = 0; |
119 |
|
120 |
preloaded_symlists = 0; |
121 |
if (default_preloaded_symbols) |
122 |
{ |
123 |
errors = lt_dlpreload (default_preloaded_symbols); |
124 |
} |
125 |
|
126 |
return errors; |
127 |
} |
128 |
|
129 |
|
130 |
/* A function called through the vtable when this loader is no |
131 |
longer needed by the application. */ |
132 |
static int |
133 |
vl_exit (lt_user_data LT__UNUSED loader_data) |
134 |
{ |
135 |
vtable = NULL; |
136 |
free_symlists (); |
137 |
return 0; |
138 |
} |
139 |
|
140 |
|
141 |
/* A function called through the vtable to open a module with this |
142 |
loader. Returns an opaque representation of the newly opened |
143 |
module for processing with this loader's other vtable functions. */ |
144 |
static lt_module |
145 |
vm_open (lt_user_data LT__UNUSED loader_data, const char *filename, |
146 |
lt_dladvise LT__UNUSED advise) |
147 |
{ |
148 |
symlist_chain *lists; |
149 |
lt_module module = 0; |
150 |
|
151 |
if (!preloaded_symlists) |
152 |
{ |
153 |
LT__SETERROR (NO_SYMBOLS); |
154 |
goto done; |
155 |
} |
156 |
|
157 |
/* Can't use NULL as the reflective symbol header, as NULL is |
158 |
used to mark the end of the entire symbol list. Self-dlpreopened |
159 |
symbols follow this magic number, chosen to be an unlikely |
160 |
clash with a real module name. */ |
161 |
if (!filename) |
162 |
{ |
163 |
filename = "@PROGRAM@"; |
164 |
} |
165 |
|
166 |
for (lists = preloaded_symlists; lists; lists = lists->next) |
167 |
{ |
168 |
const lt_dlsymlist *symbol; |
169 |
for (symbol= lists->symlist; symbol->name; ++symbol) |
170 |
{ |
171 |
if (!symbol->address && streq (symbol->name, filename)) |
172 |
{ |
173 |
/* If the next symbol's name and address is 0, it means |
174 |
the module just contains the originator and no symbols. |
175 |
In this case we pretend that we never saw the module and |
176 |
hope that some other loader will be able to load the module |
177 |
and have access to its symbols */ |
178 |
const lt_dlsymlist *next_symbol = symbol +1; |
179 |
if (next_symbol->address && next_symbol->name) |
180 |
{ |
181 |
module = (lt_module) lists->symlist; |
182 |
goto done; |
183 |
} |
184 |
} |
185 |
} |
186 |
} |
187 |
|
188 |
LT__SETERROR (FILE_NOT_FOUND); |
189 |
|
190 |
done: |
191 |
return module; |
192 |
} |
193 |
|
194 |
|
195 |
/* A function called through the vtable when a particular module |
196 |
should be unloaded. */ |
197 |
static int |
198 |
vm_close (lt_user_data LT__UNUSED loader_data, lt_module LT__UNUSED module) |
199 |
{ |
200 |
/* Just to silence gcc -Wall */ |
201 |
module = 0; |
202 |
return 0; |
203 |
} |
204 |
|
205 |
|
206 |
/* A function called through the vtable to get the address of |
207 |
a symbol loaded from a particular module. */ |
208 |
static void * |
209 |
vm_sym (lt_user_data LT__UNUSED loader_data, lt_module module, const char *name) |
210 |
{ |
211 |
lt_dlsymlist *symbol = (lt_dlsymlist*) module; |
212 |
|
213 |
symbol +=2; /* Skip header (originator then libname). */ |
214 |
|
215 |
while (symbol->name) |
216 |
{ |
217 |
if (streq (symbol->name, name)) |
218 |
{ |
219 |
return symbol->address; |
220 |
} |
221 |
|
222 |
++symbol; |
223 |
} |
224 |
|
225 |
LT__SETERROR (SYMBOL_NOT_FOUND); |
226 |
|
227 |
return 0; |
228 |
} |
229 |
|
230 |
|
231 |
|
232 |
/* --- HELPER FUNCTIONS --- */ |
233 |
|
234 |
|
235 |
/* The symbol lists themselves are not allocated from the heap, but |
236 |
we can unhook them and free up the chain of links between them. */ |
237 |
static int |
238 |
free_symlists (void) |
239 |
{ |
240 |
symlist_chain *lists; |
241 |
|
242 |
lists = preloaded_symlists; |
243 |
while (lists) |
244 |
{ |
245 |
symlist_chain *next = lists->next; |
246 |
FREE (lists); |
247 |
lists = next; |
248 |
} |
249 |
preloaded_symlists = 0; |
250 |
|
251 |
return 0; |
252 |
} |
253 |
|
254 |
/* Add a new symbol list to the global chain. */ |
255 |
static int |
256 |
add_symlist (const lt_dlsymlist *symlist) |
257 |
{ |
258 |
symlist_chain *lists; |
259 |
int errors = 0; |
260 |
|
261 |
/* Search for duplicate entries: */ |
262 |
for (lists = preloaded_symlists; |
263 |
lists && lists->symlist != symlist; lists = lists->next) |
264 |
/*NOWORK*/; |
265 |
|
266 |
/* Don't add the same list twice: */ |
267 |
if (!lists) |
268 |
{ |
269 |
symlist_chain *tmp = (symlist_chain *) lt__zalloc (sizeof *tmp); |
270 |
|
271 |
if (tmp) |
272 |
{ |
273 |
tmp->symlist = symlist; |
274 |
tmp->next = preloaded_symlists; |
275 |
preloaded_symlists = tmp; |
276 |
} |
277 |
else |
278 |
{ |
279 |
++errors; |
280 |
} |
281 |
} |
282 |
|
283 |
return errors; |
284 |
} |
285 |
|
286 |
|
287 |
|
288 |
/* --- PRELOADING API CALL IMPLEMENTATIONS --- */ |
289 |
|
290 |
|
291 |
/* Save a default symbol list for later. */ |
292 |
int |
293 |
lt_dlpreload_default (const lt_dlsymlist *preloaded) |
294 |
{ |
295 |
default_preloaded_symbols = preloaded; |
296 |
return 0; |
297 |
} |
298 |
|
299 |
|
300 |
/* Add a symbol list to the global chain, or with a NULL argument, |
301 |
revert to just the default list. */ |
302 |
int |
303 |
lt_dlpreload (const lt_dlsymlist *preloaded) |
304 |
{ |
305 |
int errors = 0; |
306 |
|
307 |
if (preloaded) |
308 |
{ |
309 |
errors = add_symlist (preloaded); |
310 |
} |
311 |
else |
312 |
{ |
313 |
free_symlists(); |
314 |
|
315 |
if (default_preloaded_symbols) |
316 |
{ |
317 |
errors = lt_dlpreload (default_preloaded_symbols); |
318 |
} |
319 |
} |
320 |
|
321 |
return errors; |
322 |
} |
323 |
|
324 |
|
325 |
/* Open all the preloaded modules from the named originator, executing |
326 |
a callback for each one. If ORIGINATOR is NULL, then call FUNC for |
327 |
each preloaded module from the program itself. */ |
328 |
int |
329 |
lt_dlpreload_open (const char *originator, lt_dlpreload_callback_func *func) |
330 |
{ |
331 |
symlist_chain *list; |
332 |
int errors = 0; |
333 |
int found = 0; |
334 |
|
335 |
/* For each symlist in the chain... */ |
336 |
for (list = preloaded_symlists; list; list = list->next) |
337 |
{ |
338 |
/* ...that was preloaded by the requesting ORIGINATOR... */ |
339 |
if ((originator && streq (list->symlist->name, originator)) |
340 |
|| (!originator && streq (list->symlist->name, "@PROGRAM@"))) |
341 |
{ |
342 |
const lt_dlsymlist *symbol; |
343 |
unsigned int idx = 0; |
344 |
|
345 |
++found; |
346 |
|
347 |
/* ...load the symbols per source compilation unit: |
348 |
(we preincrement the index to skip over the originator entry) */ |
349 |
while ((symbol = &list->symlist[++idx])->name != 0) |
350 |
{ |
351 |
if ((symbol->address == 0) |
352 |
&& (strneq (symbol->name, "@PROGRAM@"))) |
353 |
{ |
354 |
lt_dlhandle handle = lt_dlopen (symbol->name); |
355 |
if (handle == 0) |
356 |
{ |
357 |
++errors; |
358 |
} |
359 |
else |
360 |
{ |
361 |
errors += (*func) (handle); |
362 |
} |
363 |
} |
364 |
} |
365 |
} |
366 |
} |
367 |
|
368 |
if (!found) |
369 |
{ |
370 |
LT__SETERROR(CANNOT_OPEN); |
371 |
++errors; |
372 |
} |
373 |
|
374 |
return errors; |
375 |
} |