1
/* unix_dl.c -- Dynamic loading of C modules
2
Copyright (C) 1998 John Harper <john@dcs.warwick.ac.uk>
3
$Id: unix_dl.c,v 1.38 2001/04/16 22:13:22 jsh Exp $
5
This file is part of Jade.
7
Jade is free software; you can redistribute it and/or modify it
8
under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 2, or (at your option)
12
Jade 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
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with Jade; see the file COPYING. If not, write to
19
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
23
/* AIX requires this to be the first thing in the file. */
26
# define alloca __builtin_alloca
34
# ifndef alloca /* predefined by HP cc +Olibcalls */
45
/* we define some extensions to the libtool .la file. As well as using
46
the dlname entry to find the .so file to open, we also look for:
48
rep_open_globally=[yes|no]
50
whether or not to open with RTLD_GLOBAL
52
rep_requires='FEATURES...'
54
FEATURES is space separated list of feature symbols.
55
Each of which must be provided by a dl object. */
57
#ifdef HAVE_DYNAMIC_LOADING
59
#if defined (HAVE_DLFCN_H)
61
# if ! defined (RTLD_LAZY)
62
# if defined (DL_LAZY)
63
# define RTLD_LAZY DL_LAZY
65
/* from gmodule-dl.c ``The Perl sources say, RTLD_LAZY needs to be
66
defined as (1), at least for Solaris 1.'' */
70
# if ! defined (RTLD_GLOBAL)
71
# if defined (DL_GLOBAL)
72
# define RTLD_GLOBAL DL_GLOBAL
74
# define RTLD_GLOBAL 0
77
# if ! defined (RTLD_LOCAL)
78
# if defined (DL_LOCAL)
79
# define RTLD_LOCAL DL_LOCAL
84
# if ! defined (RTLD_NOW)
86
# define RTLD_NOW DL_NOW
91
# if defined (BROKEN_RTLD_GLOBAL)
93
# define RTLD_GLOBAL 0
96
#elif defined (HAVE_DL_H) || defined (HAVE_SYS_DL_H)
97
# if defined (HAVE_DL_H)
102
# if ! defined (BIND_IMMEDIATE)
103
# define BIND_IMMEDIATE 0
105
# if ! defined (BIND_DEFERRED)
106
# define BIND_DEFERRED 0
108
# if ! defined (BIND_NONFATAL)
109
# define BIND_NONFATAL 0
111
# if ! defined (DYNAMIC_PATH)
112
# define DYNAMIC_PATH 0
117
struct dl_lib_info *next;
124
static struct dl_lib_info *dl_list;
126
#if !defined (HAVE_DLOPEN) && defined (HAVE_SHL_LOAD)
128
dlsym (void *handle, char *sym)
131
if (shl_findsym (&handle, sym, TYPE_UNDEFINED, &addr) == 0)
138
dlclose (void *handle)
144
#ifndef DLSYM_NEED_USCORE
145
# define x_dlsym dlsym
148
x_dlsym (void *handle, char *sym)
151
char *tem = alloca (strlen(sym) + 2);
153
strcpy (tem + 1, sym);
154
ptr = dlsym (handle, tem);
159
static struct dl_lib_info *
162
struct dl_lib_info *x = dl_list;
163
assert(rep_STRINGP(file));
166
assert(rep_STRINGP(x->file_name));
167
if(!strcmp(rep_STR(file), rep_STR(x->file_name)))
174
static struct dl_lib_info *
175
find_dl_by_feature(repv feature)
177
struct dl_lib_info *x = dl_list;
178
assert (rep_STRINGP(feature));
181
if(rep_SYMBOLP(x->feature_sym)
182
&& strcmp (rep_STR(rep_SYM(x->feature_sym)->name),
183
rep_STR(feature)) == 0)
193
load_requires (char *ptr)
195
ptr += strspn (ptr, " \t");
198
char *end = ptr + strcspn (ptr, " \t");
199
repv sym = Fintern (rep_string_dupn (ptr, end - ptr), Qnil);
200
if (Fintern_structure (sym) == rep_NULL)
202
ptr = end + strspn (end, " \t");
208
signal_error (char *msg)
211
Fsignal (Qerror, rep_LIST_1 (rep_string_dup (msg)));
213
fprintf (stderr, "error: %s\n", msg);
217
rep_open_dl_library(repv file_name)
219
struct dl_lib_info *x = find_dl(file_name);
222
/* We're trying to open a _libtool_ dl object. i.e it's a
223
file ending in .la that contains a dlname=FOO line
224
pointing to the actual DL object (in the same directory). */
228
rep_bool open_globally = rep_FALSE;
229
FILE *fh = fopen(rep_STR(file_name), "r");
232
rep_signal_file_error(file_name);
235
while (fgets(buf, sizeof(buf), fh))
237
if (strncmp("dlname='", buf, sizeof("dlname='") - 1) == 0)
239
char *ptr = buf + sizeof("dlname='") - 1;
241
char *end = strchr(ptr, '\'');
242
if (end != 0 && end > ptr)
245
base = strrchr(rep_STR(file_name), '/');
248
dlname = alloca (strlen (ptr) + 1);
249
strcpy (dlname, ptr);
254
dlname = alloca (strlen(ptr) +
255
base - rep_STR(file_name) + 1);
256
memcpy(dlname, rep_STR(file_name),
257
base - rep_STR(file_name));
258
strcpy(dlname + (base - rep_STR(file_name)), ptr);
262
else if (strncmp("rep_open_globally=", buf,
263
sizeof("rep_open_globally=") - 1) == 0)
265
char *ptr = buf + sizeof ("rep_open_globally=") - 1;
266
if (strncmp ("yes", ptr, 3) == 0)
267
open_globally = rep_TRUE;
269
else if (strncmp("rep_requires='", buf,
270
sizeof ("rep_requires='") - 1) == 0)
272
char *ptr = buf + sizeof ("rep_requires='") - 1;
273
char *end = strchr (ptr, '\'');
276
rep_GC_root gc_file_name;
278
char *string = alloca (end - ptr + 1);
279
memcpy (string, ptr, end - ptr);
280
string[end - ptr] = 0;
281
rep_PUSHGC (gc_file_name, file_name);
282
success = load_requires (string);
294
snprintf (err, sizeof (err), "Can't find dlname in %s",
295
rep_STR (file_name));
297
sprintf (err, "Can't find dlname in %s", rep_STR (file_name));
303
rep_xsubr **functions;
304
repv (*init_func)(repv);
307
rep_bool relocate_now = rep_FALSE;
308
if (Qdl_load_reloc_now
309
&& Fsymbol_value (Qdl_load_reloc_now, Qt) != Qnil)
311
relocate_now = rep_TRUE;
314
#if defined (HAVE_DLOPEN)
315
handle = dlopen(dlname,
316
(relocate_now ? RTLD_NOW : RTLD_LAZY)
317
| (open_globally ? RTLD_GLOBAL : RTLD_LOCAL));
318
#elif defined (HAVE_SHL_LOAD)
319
/* XXX how do we open these locally/globally? */
320
handle = shl_load (dlname,
321
(relocate_now ? BIND_IMMEDIATE : BIND_DEFERRED)
322
| BIND_NONFATAL | DYNAMIC_PATH, 0L);
330
err = "unknown dl error";
336
x = rep_alloc(sizeof(struct dl_lib_info));
343
x->file_name = file_name;
345
x->feature_sym = Qnil;
351
init_func = x_dlsym(handle, "rep_dl_init");
354
repv ret = init_func(file_name);
355
if(Qnil != rep_NULL /* initialising */
356
&& (ret == rep_NULL || ret == Qnil))
358
/* error. abort abort.. */
359
struct dl_lib_info **ptr;
360
for (ptr = &dl_list; *ptr != 0; ptr = &((*ptr)->next))
370
else if (ret && rep_SYMBOLP(ret) && ret != Qt)
371
x->feature_sym = ret;
372
else if (ret && rep_STRUCTUREP (ret))
375
ret = rep_STRUCTURE (ret)->name;
376
if (ret && rep_SYMBOLP (ret))
377
x->feature_sym = ret;
381
feature_sym = x_dlsym (handle, "rep_dl_feature");
382
if (feature_sym != 0)
384
fprintf (stderr, "warning: %s uses obsolete `rep_dl_feature'\n",
385
rep_STR (file_name));
388
functions = x_dlsym(handle, "rep_dl_subrs");
391
fprintf (stderr, "warning: %s uses obsolete `rep_dl_subrs'\n",
392
rep_STR (file_name));
400
if (x->feature_sym != Qnil && x->structure == Qnil)
402
/* only `provide' the feature if there's no associated
403
structure (since we haven't actually imported it) */
404
Fprovide (x->feature_sym);
413
rep_mark_dl_data(void)
415
struct dl_lib_info *x = dl_list;
418
rep_MARKVAL(x->file_name);
419
rep_MARKVAL(x->feature_sym);
420
rep_MARKVAL(x->structure);
426
rep_kill_dl_libraries(void)
428
struct dl_lib_info *x = dl_list;
432
struct dl_lib_info *next = x->next;
433
void (*exit_func)(void) = x_dlsym(x->handle, "rep_dl_kill");
437
/* Closing libraries is a _bad_ idea. There's no way
438
of knowing if any pointers to their contents exist.
439
For example, it's impossible to completely expunge
440
libgtk/libgdk, since they install an atexit () handler.. */
449
rep_find_dl_symbol (repv feature, char *symbol)
451
struct dl_lib_info *x;
452
assert(rep_SYMBOLP(feature));
453
x = find_dl_by_feature (rep_SYM(feature)->name);
455
return x_dlsym (x->handle, symbol);
460
/* Attempt to find the name and address of the nearest symbol before or
463
rep_find_c_symbol(void *ptr, char **symbol_name_p, void **symbol_addr_p)
467
if(dladdr(ptr, &info) != 0)
469
*symbol_name_p = (char *)info.dli_sname;
470
*symbol_addr_p = info.dli_saddr;
478
#else /* HAVE_DYNAMIC_LOADING */
481
rep_find_c_symbol(void *ptr, char **name_p, void **addr_p)
486
#endif /* !HAVE_DYNAMIC_LOADING */