1 | /* loader-preopen.c -- emulate dynamic linking using preloaded_symbols |
2 | |
3 | Copyright (C) 1998-2000, 2004, 2006-2008, 2011-2015 Free Software |
4 | 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 loader_data LT__UNUSED) |
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 loader_data LT__UNUSED) |
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 loader_data LT__UNUSED, const char *filename, |
146 | lt_dladvise advise LT__UNUSED) |
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 loader_data LT__UNUSED, lt_module module LT__UNUSED) |
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 loader_data LT__UNUSED, lt_module module, const char *name) |
210 | { |
211 | lt_dlsymlist *symbol = (lt_dlsymlist*) module; |
212 | |
213 | if (symbol[1].name && STREQ (symbol[1].name, "@INIT@" )) |
214 | { |
215 | symbol++; /* Skip optional init entry. */ |
216 | } |
217 | |
218 | symbol +=2; /* Skip header (originator then libname). */ |
219 | |
220 | while (symbol->name) |
221 | { |
222 | if (STREQ (symbol->name, name)) |
223 | { |
224 | return symbol->address; |
225 | } |
226 | |
227 | ++symbol; |
228 | } |
229 | |
230 | LT__SETERROR (SYMBOL_NOT_FOUND); |
231 | |
232 | return 0; |
233 | } |
234 | |
235 | |
236 | |
237 | /* --- HELPER FUNCTIONS --- */ |
238 | |
239 | |
240 | /* The symbol lists themselves are not allocated from the heap, but |
241 | we can unhook them and free up the chain of links between them. */ |
242 | static int |
243 | free_symlists (void) |
244 | { |
245 | symlist_chain *lists; |
246 | |
247 | lists = preloaded_symlists; |
248 | while (lists) |
249 | { |
250 | symlist_chain *next = lists->next; |
251 | FREE (lists); |
252 | lists = next; |
253 | } |
254 | preloaded_symlists = 0; |
255 | |
256 | return 0; |
257 | } |
258 | |
259 | /* Add a new symbol list to the global chain. */ |
260 | static int |
261 | add_symlist (const lt_dlsymlist *symlist) |
262 | { |
263 | symlist_chain *lists; |
264 | int errors = 0; |
265 | |
266 | /* Search for duplicate entries: */ |
267 | for (lists = preloaded_symlists; |
268 | lists && lists->symlist != symlist; lists = lists->next) |
269 | /*NOWORK*/; |
270 | |
271 | /* Don't add the same list twice: */ |
272 | if (!lists) |
273 | { |
274 | symlist_chain *tmp = (symlist_chain *) lt__zalloc (sizeof *tmp); |
275 | |
276 | if (tmp) |
277 | { |
278 | tmp->symlist = symlist; |
279 | tmp->next = preloaded_symlists; |
280 | preloaded_symlists = tmp; |
281 | |
282 | if (symlist[1].name && STREQ (symlist[1].name, "@INIT@" )) |
283 | { |
284 | void (*init_symlist)(void); |
285 | *(void **)(&init_symlist) = symlist[1].address; |
286 | (*init_symlist)(); |
287 | } |
288 | } |
289 | else |
290 | { |
291 | ++errors; |
292 | } |
293 | } |
294 | |
295 | return errors; |
296 | } |
297 | |
298 | |
299 | |
300 | /* --- PRELOADING API CALL IMPLEMENTATIONS --- */ |
301 | |
302 | |
303 | /* Save a default symbol list for later. */ |
304 | int |
305 | lt_dlpreload_default (const lt_dlsymlist *preloaded) |
306 | { |
307 | default_preloaded_symbols = preloaded; |
308 | return 0; |
309 | } |
310 | |
311 | |
312 | /* Add a symbol list to the global chain, or with a NULL argument, |
313 | revert to just the default list. */ |
314 | int |
315 | lt_dlpreload (const lt_dlsymlist *preloaded) |
316 | { |
317 | int errors = 0; |
318 | |
319 | if (preloaded) |
320 | { |
321 | errors = add_symlist (preloaded); |
322 | } |
323 | else |
324 | { |
325 | free_symlists(); |
326 | |
327 | if (default_preloaded_symbols) |
328 | { |
329 | errors = lt_dlpreload (default_preloaded_symbols); |
330 | } |
331 | } |
332 | |
333 | return errors; |
334 | } |
335 | |
336 | |
337 | /* Open all the preloaded modules from the named originator, executing |
338 | a callback for each one. If ORIGINATOR is NULL, then call FUNC for |
339 | each preloaded module from the program itself. */ |
340 | int |
341 | lt_dlpreload_open (const char *originator, lt_dlpreload_callback_func *func) |
342 | { |
343 | symlist_chain *list; |
344 | int errors = 0; |
345 | int found = 0; |
346 | |
347 | /* For each symlist in the chain... */ |
348 | for (list = preloaded_symlists; list; list = list->next) |
349 | { |
350 | /* ...that was preloaded by the requesting ORIGINATOR... */ |
351 | if ((originator && STREQ (list->symlist->name, originator)) |
352 | || (!originator && STREQ (list->symlist->name, "@PROGRAM@" ))) |
353 | { |
354 | const lt_dlsymlist *symbol; |
355 | unsigned int idx = 0; |
356 | |
357 | ++found; |
358 | |
359 | /* ...load the symbols per source compilation unit: |
360 | (we preincrement the index to skip over the originator entry) */ |
361 | while ((symbol = &list->symlist[++idx])->name != 0) |
362 | { |
363 | if ((symbol->address == 0) |
364 | && (STRNEQ (symbol->name, "@PROGRAM@" ))) |
365 | { |
366 | lt_dlhandle handle = lt_dlopen (symbol->name); |
367 | if (handle == 0) |
368 | { |
369 | ++errors; |
370 | } |
371 | else |
372 | { |
373 | errors += (*func) (handle); |
374 | } |
375 | } |
376 | } |
377 | } |
378 | } |
379 | |
380 | if (!found) |
381 | { |
382 | LT__SETERROR(CANNOT_OPEN); |
383 | ++errors; |
384 | } |
385 | |
386 | return errors; |
387 | } |
388 | |