~ubuntu-branches/ubuntu/trusty/librep/trusty

« back to all changes in this revision

Viewing changes to src/unix_dl.c

  • Committer: Bazaar Package Importer
  • Author(s): Christian Marillat
  • Date: 2001-11-13 15:06:22 UTC
  • Revision ID: james.westby@ubuntu.com-20011113150622-vgmgmk6srj3kldr3
Tags: upstream-0.15.2
ImportĀ upstreamĀ versionĀ 0.15.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 $
 
4
 
 
5
   This file is part of Jade.
 
6
 
 
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)
 
10
   any later version.
 
11
 
 
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.
 
16
 
 
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.  */
 
20
 
 
21
#define _GNU_SOURCE
 
22
 
 
23
/* AIX requires this to be the first thing in the file.  */
 
24
#include <config.h>
 
25
#ifdef __GNUC__
 
26
# define alloca __builtin_alloca
 
27
#else
 
28
# if HAVE_ALLOCA_H
 
29
#  include <alloca.h>
 
30
# else
 
31
#  ifdef _AIX
 
32
 #pragma alloca
 
33
#  else
 
34
#   ifndef alloca /* predefined by HP cc +Olibcalls */
 
35
char *alloca ();
 
36
#   endif
 
37
#  endif
 
38
# endif
 
39
#endif
 
40
 
 
41
#include "repint.h"
 
42
#include <assert.h>
 
43
#include <string.h>
 
44
 
 
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:
 
47
 
 
48
     rep_open_globally=[yes|no]
 
49
 
 
50
        whether or not to open with RTLD_GLOBAL
 
51
 
 
52
     rep_requires='FEATURES...'
 
53
 
 
54
        FEATURES is space separated list of feature symbols.
 
55
        Each of which must be provided by a dl object. */
 
56
 
 
57
#ifdef HAVE_DYNAMIC_LOADING
 
58
 
 
59
#if defined (HAVE_DLFCN_H)
 
60
# include <dlfcn.h>
 
61
# if ! defined (RTLD_LAZY)
 
62
#  if defined (DL_LAZY)
 
63
#   define RTLD_LAZY DL_LAZY
 
64
#  else
 
65
    /* from gmodule-dl.c ``The Perl sources say, RTLD_LAZY needs to be
 
66
       defined as (1), at least for Solaris 1.'' */
 
67
#   define RTLD_LAZY 1
 
68
#  endif
 
69
# endif
 
70
# if ! defined (RTLD_GLOBAL)
 
71
#  if defined (DL_GLOBAL)
 
72
#   define RTLD_GLOBAL DL_GLOBAL
 
73
#  else
 
74
#   define RTLD_GLOBAL 0
 
75
#  endif
 
76
# endif
 
77
# if ! defined (RTLD_LOCAL)
 
78
#  if defined (DL_LOCAL)
 
79
#   define RTLD_LOCAL DL_LOCAL
 
80
#  else
 
81
#   define RTLD_LOCAL 0
 
82
#  endif
 
83
# endif
 
84
# if ! defined (RTLD_NOW)
 
85
#  if defined (DL_NOW)
 
86
#   define RTLD_NOW DL_NOW
 
87
#  else
 
88
#   define RTLD_NOW 0
 
89
#  endif
 
90
# endif
 
91
# if defined (BROKEN_RTLD_GLOBAL)
 
92
#  undef RTLD_GLOBAL
 
93
#  define RTLD_GLOBAL 0
 
94
# endif
 
95
 
 
96
#elif defined (HAVE_DL_H) || defined (HAVE_SYS_DL_H)
 
97
# if defined (HAVE_DL_H)
 
98
#  include <dl.h>
 
99
# else
 
100
#  include <sys/dl.h>
 
101
# endif
 
102
# if ! defined (BIND_IMMEDIATE)
 
103
#  define BIND_IMMEDIATE 0
 
104
# endif
 
105
# if ! defined (BIND_DEFERRED)
 
106
#  define BIND_DEFERRED 0
 
107
# endif
 
108
# if ! defined (BIND_NONFATAL)
 
109
#  define BIND_NONFATAL 0
 
110
# endif
 
111
# if ! defined (DYNAMIC_PATH)
 
112
#  define DYNAMIC_PATH 0
 
113
# endif
 
114
#endif
 
115
 
 
116
struct dl_lib_info {
 
117
    struct dl_lib_info *next;
 
118
    repv file_name;
 
119
    repv feature_sym;
 
120
    repv structure;
 
121
    void *handle;
 
122
};
 
123
 
 
124
static struct dl_lib_info *dl_list;
 
125
 
 
126
#if !defined (HAVE_DLOPEN) && defined (HAVE_SHL_LOAD)
 
127
static inline void *
 
128
dlsym (void *handle, char *sym)
 
129
{
 
130
    void *addr;
 
131
    if (shl_findsym (&handle, sym, TYPE_UNDEFINED, &addr) == 0)
 
132
        return addr;
 
133
    else
 
134
        return 0;
 
135
}
 
136
 
 
137
static inline void
 
138
dlclose (void *handle)
 
139
{
 
140
    shl_unload (handle);
 
141
}
 
142
#endif
 
143
 
 
144
#ifndef DLSYM_NEED_USCORE
 
145
# define x_dlsym dlsym
 
146
#else
 
147
static void *
 
148
x_dlsym (void *handle, char *sym)
 
149
{
 
150
    void *ptr = 0;
 
151
    char *tem = alloca (strlen(sym) + 2);
 
152
    tem[0] = '_';
 
153
    strcpy (tem + 1, sym);
 
154
    ptr = dlsym (handle, tem);
 
155
    return ptr;
 
156
}
 
157
#endif
 
158
 
 
159
static struct dl_lib_info *
 
160
find_dl(repv file)
 
161
{
 
162
    struct dl_lib_info *x = dl_list;
 
163
    assert(rep_STRINGP(file));
 
164
    while(x != 0)
 
165
    {
 
166
        assert(rep_STRINGP(x->file_name));
 
167
        if(!strcmp(rep_STR(file), rep_STR(x->file_name)))
 
168
            return x;
 
169
        x = x->next;
 
170
    }
 
171
    return 0;
 
172
}
 
173
 
 
174
static struct dl_lib_info *
 
175
find_dl_by_feature(repv feature)
 
176
{
 
177
    struct dl_lib_info *x = dl_list;
 
178
    assert (rep_STRINGP(feature));
 
179
    while(x != 0)
 
180
    {
 
181
        if(rep_SYMBOLP(x->feature_sym)
 
182
           && strcmp (rep_STR(rep_SYM(x->feature_sym)->name),
 
183
                      rep_STR(feature)) == 0)
 
184
        {
 
185
            return x;
 
186
        }
 
187
        x = x->next;
 
188
    }
 
189
    return 0;
 
190
}
 
191
 
 
192
static rep_bool
 
193
load_requires (char *ptr)
 
194
{
 
195
    ptr += strspn (ptr, " \t");
 
196
    while (*ptr != 0)
 
197
    {
 
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)
 
201
            return rep_FALSE;
 
202
        ptr = end + strspn (end, " \t");
 
203
    }
 
204
    return rep_TRUE;
 
205
}
 
206
 
 
207
static void
 
208
signal_error (char *msg)
 
209
{
 
210
    if (Qerror != 0)
 
211
        Fsignal (Qerror, rep_LIST_1 (rep_string_dup (msg)));
 
212
    else
 
213
        fprintf (stderr, "error: %s\n", msg);
 
214
}
 
215
 
 
216
repv
 
217
rep_open_dl_library(repv file_name)
 
218
{
 
219
    struct dl_lib_info *x = find_dl(file_name);
 
220
    if(x == 0)
 
221
    {
 
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). */
 
225
 
 
226
        char buf[256];
 
227
        char *dlname = 0;
 
228
        rep_bool open_globally = rep_FALSE;
 
229
        FILE *fh = fopen(rep_STR(file_name), "r");
 
230
        if (fh == 0)
 
231
        {
 
232
            rep_signal_file_error(file_name);
 
233
            return 0;
 
234
        }
 
235
        while (fgets(buf, sizeof(buf), fh))
 
236
        {
 
237
            if (strncmp("dlname='", buf, sizeof("dlname='") - 1) == 0)
 
238
            {
 
239
                char *ptr = buf + sizeof("dlname='") - 1;
 
240
                u_char *base;
 
241
                char *end = strchr(ptr, '\'');
 
242
                if (end != 0 && end > ptr)
 
243
                {
 
244
                    *end = 0;
 
245
                    base = strrchr(rep_STR(file_name), '/');
 
246
                    if (base == 0)
 
247
                    {
 
248
                        dlname = alloca (strlen (ptr) + 1);
 
249
                        strcpy (dlname, ptr);
 
250
                    }
 
251
                    else
 
252
                    {
 
253
                        base++;
 
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);
 
259
                    }
 
260
                }
 
261
            }
 
262
            else if (strncmp("rep_open_globally=", buf,
 
263
                             sizeof("rep_open_globally=") - 1) == 0)
 
264
            {
 
265
                char *ptr = buf + sizeof ("rep_open_globally=") - 1;
 
266
                if (strncmp ("yes", ptr, 3) == 0)
 
267
                    open_globally = rep_TRUE;
 
268
            }
 
269
            else if (strncmp("rep_requires='", buf,
 
270
                             sizeof ("rep_requires='") - 1) == 0)
 
271
            {
 
272
                char *ptr = buf + sizeof ("rep_requires='") - 1;
 
273
                char *end = strchr (ptr, '\'');
 
274
                if (end != 0)
 
275
                {
 
276
                    rep_GC_root gc_file_name;
 
277
                    rep_bool success;
 
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);
 
283
                    rep_POPGC;
 
284
                    if (!success)
 
285
                        goto out;
 
286
                }
 
287
            }
 
288
        }
 
289
        fclose(fh);
 
290
        if (!dlname)
 
291
        {
 
292
            char err[256];
 
293
#ifdef HAVE_SNPRINTF
 
294
            snprintf (err, sizeof (err), "Can't find dlname in %s",
 
295
                      rep_STR (file_name));
 
296
#else
 
297
            sprintf (err, "Can't find dlname in %s", rep_STR (file_name));
 
298
#endif
 
299
            signal_error (err);
 
300
        }
 
301
        else
 
302
        {
 
303
            rep_xsubr **functions;
 
304
            repv (*init_func)(repv);
 
305
            repv *feature_sym;
 
306
            void *handle;
 
307
            rep_bool relocate_now = rep_FALSE;
 
308
            if (Qdl_load_reloc_now
 
309
                && Fsymbol_value (Qdl_load_reloc_now, Qt) != Qnil)
 
310
            {
 
311
                relocate_now = rep_TRUE;
 
312
            }
 
313
 
 
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);
 
323
#endif
 
324
            if(handle == 0)
 
325
            {
 
326
                char *err;
 
327
#ifdef HAVE_DLERROR
 
328
                err = dlerror();
 
329
#else
 
330
                err = "unknown dl error";
 
331
#endif
 
332
                if(err != 0)
 
333
                    signal_error (err);
 
334
                return 0;
 
335
            }
 
336
            x = rep_alloc(sizeof(struct dl_lib_info));
 
337
            if(x == 0)
 
338
            {
 
339
                rep_mem_error();
 
340
                dlclose(handle);
 
341
                return 0;
 
342
            }
 
343
            x->file_name = file_name;
 
344
            x->handle = handle;
 
345
            x->feature_sym = Qnil;
 
346
            x->structure = Qnil;
 
347
 
 
348
            x->next = dl_list;
 
349
            dl_list = x;
 
350
 
 
351
            init_func = x_dlsym(handle, "rep_dl_init");
 
352
            if(init_func != 0)
 
353
            {
 
354
                repv ret = init_func(file_name);
 
355
                if(Qnil != rep_NULL                     /* initialising */
 
356
                   && (ret == rep_NULL || ret == Qnil))
 
357
                {
 
358
                    /* error. abort abort.. */
 
359
                    struct dl_lib_info **ptr;
 
360
                    for (ptr = &dl_list; *ptr != 0; ptr = &((*ptr)->next))
 
361
                    {
 
362
                        if (*ptr == x)
 
363
                            *ptr = x->next;
 
364
                        break;
 
365
                    }               
 
366
                    rep_free(x);
 
367
                    dlclose(handle);
 
368
                    return 0;
 
369
                }
 
370
                else if (ret && rep_SYMBOLP(ret) && ret != Qt)
 
371
                    x->feature_sym = ret;
 
372
                else if (ret && rep_STRUCTUREP (ret))
 
373
                {
 
374
                    x->structure = ret;
 
375
                    ret = rep_STRUCTURE (ret)->name;
 
376
                    if (ret && rep_SYMBOLP (ret))
 
377
                        x->feature_sym = ret;
 
378
                }
 
379
            }
 
380
 
 
381
            feature_sym = x_dlsym (handle, "rep_dl_feature");
 
382
            if (feature_sym != 0)
 
383
            {
 
384
                fprintf (stderr, "warning: %s uses obsolete `rep_dl_feature'\n",
 
385
                         rep_STR (file_name));
 
386
            }
 
387
 
 
388
            functions = x_dlsym(handle, "rep_dl_subrs");
 
389
            if(functions != 0)
 
390
            {
 
391
                fprintf (stderr, "warning: %s uses obsolete `rep_dl_subrs'\n",
 
392
                         rep_STR (file_name));
 
393
            }
 
394
        }
 
395
    }
 
396
out:
 
397
 
 
398
    if (x != 0)
 
399
    {
 
400
        if (x->feature_sym != Qnil && x->structure == Qnil)
 
401
        {
 
402
            /* only `provide' the feature if there's no associated
 
403
               structure (since we haven't actually imported it) */
 
404
            Fprovide (x->feature_sym);
 
405
        }
 
406
        return x->structure;
 
407
    }
 
408
    else
 
409
        return rep_NULL;
 
410
}
 
411
 
 
412
void
 
413
rep_mark_dl_data(void)
 
414
{
 
415
    struct dl_lib_info *x = dl_list;
 
416
    while(x != 0)
 
417
    {
 
418
        rep_MARKVAL(x->file_name);
 
419
        rep_MARKVAL(x->feature_sym);
 
420
        rep_MARKVAL(x->structure);
 
421
        x = x->next;
 
422
    }
 
423
}
 
424
 
 
425
void
 
426
rep_kill_dl_libraries(void)
 
427
{
 
428
    struct dl_lib_info *x = dl_list;
 
429
    dl_list = 0;
 
430
    while(x != 0)
 
431
    {
 
432
        struct dl_lib_info *next = x->next;
 
433
        void (*exit_func)(void) = x_dlsym(x->handle, "rep_dl_kill");
 
434
        if(exit_func != 0)
 
435
            exit_func();
 
436
#if 0
 
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.. */
 
441
        dlclose(x->handle);
 
442
#endif
 
443
        rep_free(x);
 
444
        x = next;
 
445
    }
 
446
}
 
447
 
 
448
void *
 
449
rep_find_dl_symbol (repv feature, char *symbol)
 
450
{
 
451
    struct dl_lib_info *x;
 
452
    assert(rep_SYMBOLP(feature));
 
453
    x = find_dl_by_feature (rep_SYM(feature)->name);
 
454
    if (x != 0)
 
455
        return x_dlsym (x->handle, symbol);
 
456
    else
 
457
        return 0;
 
458
}
 
459
 
 
460
/* Attempt to find the name and address of the nearest symbol before or
 
461
   equal to PTR */
 
462
rep_bool
 
463
rep_find_c_symbol(void *ptr, char **symbol_name_p, void **symbol_addr_p)
 
464
{
 
465
#ifdef HAVE_DLADDR
 
466
    Dl_info info;
 
467
    if(dladdr(ptr, &info) != 0)
 
468
    {
 
469
        *symbol_name_p = (char *)info.dli_sname;
 
470
        *symbol_addr_p = info.dli_saddr;
 
471
        return rep_TRUE;
 
472
    }
 
473
    else
 
474
#endif
 
475
        return rep_FALSE;
 
476
}
 
477
        
 
478
#else /* HAVE_DYNAMIC_LOADING */
 
479
 
 
480
rep_bool
 
481
rep_find_c_symbol(void *ptr, char **name_p, void **addr_p)
 
482
{
 
483
    return rep_FALSE;
 
484
}
 
485
 
 
486
#endif /* !HAVE_DYNAMIC_LOADING */