OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [boehm-gc/] [dyn_load.c] - Blame information for rev 841

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 721 jeremybenn
/*
2
 * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
3
 * Copyright (c) 1997 by Silicon Graphics.  All rights reserved.
4
 *
5
 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
6
 * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
7
 *
8
 * Permission is hereby granted to use or copy this program
9
 * for any purpose,  provided the above notices are retained on all copies.
10
 * Permission to modify the code and to distribute modified code is granted,
11
 * provided the above notices are retained, and a notice that the code was
12
 * modified is included with the above copyright notice.
13
 *
14
 * Original author: Bill Janssen
15
 * Heavily modified by Hans Boehm and others
16
 */
17
 
18
/*
19
 * This is incredibly OS specific code for tracking down data sections in
20
 * dynamic libraries.  There appears to be no way of doing this quickly
21
 * without groveling through undocumented data structures.  We would argue
22
 * that this is a bug in the design of the dlopen interface.  THIS CODE
23
 * MAY BREAK IN FUTURE OS RELEASES.  If this matters to you, don't hesitate
24
 * to let your vendor know ...
25
 *
26
 * None of this is safe with dlclose and incremental collection.
27
 * But then not much of anything is safe in the presence of dlclose.
28
 */
29
#if (defined(__linux__) || defined(__GLIBC__)) && !defined(_GNU_SOURCE)
30
    /* Can't test LINUX, since this must be define before other includes */
31
#   define _GNU_SOURCE
32
#endif
33
#if !defined(MACOS) && !defined(_WIN32_WCE)
34
#  include <sys/types.h>
35
#endif
36
#include "private/gc_priv.h"
37
 
38
/* BTL: avoid circular redefinition of dlopen if GC_SOLARIS_THREADS defined */
39
# if (defined(GC_PTHREADS) || defined(GC_SOLARIS_THREADS)) \
40
      && defined(dlopen) && !defined(GC_USE_LD_WRAP)
41
    /* To support threads in Solaris, gc.h interposes on dlopen by       */
42
    /* defining "dlopen" to be "GC_dlopen", which is implemented below.  */
43
    /* However, both GC_FirstDLOpenedLinkMap() and GC_dlopen() use the   */
44
    /* real system dlopen() in their implementation. We first remove     */
45
    /* gc.h's dlopen definition and restore it later, after GC_dlopen(). */
46
#   undef dlopen
47
#   define GC_must_restore_redefined_dlopen
48
# else
49
#   undef GC_must_restore_redefined_dlopen
50
# endif
51
 
52
#if (defined(DYNAMIC_LOADING) \
53
        || defined(MSWIN32)   \
54
        || defined(MSWINCE)   \
55
        || defined(CYGWIN32)) \
56
    && !defined(PCR)
57
#if !defined(SUNOS4) && !defined(SUNOS5DL) && !defined(IRIX5) && \
58
    !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32) && \
59
    !(defined(ALPHA) && defined(OSF1)) && \
60
    !defined(HPUX) && !(defined(LINUX) && defined(__ELF__)) && \
61
    !defined(RS6000) && !defined(SCO_ELF) && !defined(DGUX) && \
62
    !(defined(FREEBSD) && defined(__ELF__)) && \
63
    !(defined(NETBSD) && defined(__ELF__)) && !defined(HURD) && \
64
    !defined(DARWIN)
65
 --> We only know how to find data segments of dynamic libraries for the
66
 --> above.  Additional SVR4 variants might not be too
67
 --> hard to add.
68
#endif
69
 
70
#include <stdio.h>
71
#ifdef SUNOS5DL
72
#   include <sys/elf.h>
73
#   include <dlfcn.h>
74
#   include <link.h>
75
#endif
76
#ifdef SUNOS4
77
#   include <dlfcn.h>
78
#   include <link.h>
79
#   include <a.out.h>
80
  /* struct link_map field overrides */
81
#   define l_next       lm_next
82
#   define l_addr       lm_addr
83
#   define l_name       lm_name
84
#endif
85
#ifdef IRIX5
86
#   include <elf.h>
87
#   if _MIPS_SIM == _MIPS_SIM_ABI32 /* O32 ABI */
88
     /* Don't include <obj_list.h> here. */
89
#     include <obj.h>
90
#   else /* N32 or N64 ABIs */
91
#     include <objlist.h>
92
#   endif
93
#endif
94
 
95
#if defined(NETBSD)
96
#   include <machine/elf_machdep.h>
97
#   define ELFSIZE ARCH_ELFSIZE
98
#endif
99
 
100
#if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \
101
    (defined(FREEBSD) && defined(__ELF__)) || defined(DGUX) || \
102
    (defined(NETBSD) && defined(__ELF__)) || defined(HURD)
103
#   include <stddef.h>
104
#   include <elf.h>
105
#   include <link.h>
106
#endif
107
 
108
/* Newer versions of GNU/Linux define this macro.  We
109
 * define it similarly for any ELF systems that don't.  */
110
#  ifndef ElfW
111
#    if defined(FREEBSD)
112
#      if __ELF_WORD_SIZE == 32
113
#        define ElfW(type) Elf32_##type
114
#      else
115
#        define ElfW(type) Elf64_##type
116
#      endif
117
#    else
118
#      ifdef NETBSD
119
#        if ELFSIZE == 32
120
#          define ElfW(type) Elf32_##type
121
#        else
122
#          define ElfW(type) Elf64_##type
123
#        endif
124
#      else
125
#        if !defined(ELF_CLASS) || ELF_CLASS == ELFCLASS32
126
#          define ElfW(type) Elf32_##type
127
#        else
128
#          define ElfW(type) Elf64_##type
129
#        endif
130
#      endif
131
#    endif
132
#  endif
133
 
134
/* An user-supplied routine that is called to determine if a DSO must
135
   be scanned by the gc.  */
136
static int (*GC_has_static_roots)(const char *, void *, size_t);
137
/* Register the routine.  */
138
void
139
GC_register_has_static_roots_callback
140
  (int (*callback)(const char *, void *, size_t))
141
{
142
  GC_has_static_roots = callback;
143
}
144
 
145
#if defined(SUNOS5DL) && !defined(USE_PROC_FOR_LIBRARIES)
146
 
147
#ifdef LINT
148
    Elf32_Dyn _DYNAMIC;
149
#endif
150
 
151
#define obj_offset(lm) ((unsigned long)(lm->l_addr))
152
 
153
static struct link_map *
154
GC_FirstDLOpenedLinkMap()
155
{
156
    extern ElfW(Dyn) _DYNAMIC;
157
    ElfW(Dyn) *dp;
158
    struct r_debug *r;
159
    static struct link_map * cachedResult = 0;
160
    static ElfW(Dyn) *dynStructureAddr = 0;
161
                        /* BTL: added to avoid Solaris 5.3 ld.so _DYNAMIC bug */
162
 
163
#   ifdef SUNOS53_SHARED_LIB
164
        /* BTL: Avoid the Solaris 5.3 bug that _DYNAMIC isn't being set */
165
        /* up properly in dynamically linked .so's. This means we have  */
166
        /* to use its value in the set of original object files loaded  */
167
        /* at program startup.                                          */
168
        if( dynStructureAddr == 0 ) {
169
          void* startupSyms = dlopen(0, RTLD_LAZY);
170
          dynStructureAddr = (ElfW(Dyn)*)dlsym(startupSyms, "_DYNAMIC");
171
                }
172
#   else
173
        dynStructureAddr = &_DYNAMIC;
174
#   endif
175
 
176
    if( dynStructureAddr == 0) {
177
        return(0);
178
    }
179
    if( cachedResult == 0 ) {
180
        int tag;
181
        for( dp = ((ElfW(Dyn) *)(&_DYNAMIC)); (tag = dp->d_tag) != 0; dp++ ) {
182
            if( tag == DT_DEBUG ) {
183
                struct link_map *lm
184
                        = ((struct r_debug *)(dp->d_un.d_ptr))->r_map;
185
                if( lm != 0 ) cachedResult = lm->l_next; /* might be NIL */
186
                break;
187
            }
188
        }
189
    }
190
    return cachedResult;
191
}
192
 
193
#endif /* SUNOS5DL ... */
194
 
195
/* BTL: added to fix circular dlopen definition if GC_SOLARIS_THREADS defined */
196
# if defined(GC_must_restore_redefined_dlopen)
197
#   define dlopen GC_dlopen
198
# endif
199
 
200
#if defined(SUNOS4) && !defined(USE_PROC_FOR_LIBRARIES)
201
 
202
#ifdef LINT
203
    struct link_dynamic _DYNAMIC;
204
#endif
205
 
206
#define obj_offset(lm) ((unsigned long)(lm->l_addr))
207
 
208
static struct link_map *
209
GC_FirstDLOpenedLinkMap()
210
{
211
    extern struct link_dynamic _DYNAMIC;
212
 
213
    if( &_DYNAMIC == 0) {
214
        return(0);
215
    }
216
    return(_DYNAMIC.ld_un.ld_1->ld_loaded);
217
}
218
 
219
/* Return the address of the ld.so allocated common symbol      */
220
/* with the least address, or 0 if none.                        */
221
static ptr_t GC_first_common()
222
{
223
    ptr_t result = 0;
224
    extern struct link_dynamic _DYNAMIC;
225
    struct rtc_symb * curr_symbol;
226
 
227
    if( &_DYNAMIC == 0) {
228
        return(0);
229
    }
230
    curr_symbol = _DYNAMIC.ldd -> ldd_cp;
231
    for (; curr_symbol != 0; curr_symbol = curr_symbol -> rtc_next) {
232
        if (result == 0
233
            || (ptr_t)(curr_symbol -> rtc_sp -> n_value) < result) {
234
            result = (ptr_t)(curr_symbol -> rtc_sp -> n_value);
235
        }
236
    }
237
    return(result);
238
}
239
 
240
#endif  /* SUNOS4 ... */
241
 
242
#if defined(IRIX5) && !defined(USE_PROC_FOR_LIBRARIES)
243
 
244
/* Provide struct link map. */
245
#  if _MIPS_SIM == _MIPS_SIM_ABI32 /* O32 ABI */
246
/* Provide our own version of struct obj_list in <obj_list.h> with
247
   correctly typed data member.  */
248
struct obj_list {
249
    struct obj *data;
250
    struct obj_list *next;
251
    struct obj_list *prev;
252
} objList;
253
 
254
struct link_map {
255
    objList l_ol;
256
};
257
 
258
extern objList *__rld_obj_head;
259
 
260
/* Map field names */
261
#    define l_next      l_ol.next
262
#    define l_addr      l_ol.data->o_pelfhdr    
263
 
264
#    define obj_offset(lm) \
265
        ((unsigned long)(lm->l_ol.o_praw - (char *)lm->l_ol.o_base_address))
266
#  else /* N32 or N64 ABIs */
267
struct link_map {
268
    ElfW(Obj_Info) l_oi;
269
};
270
 
271
extern ElfW(Obj_Info) *__rld_obj_head;
272
 
273
/* Map field names */
274
#    define l_next      l_oi.oi_next
275
#    define l_addr      l_oi.oi_ehdr
276
 
277
/* See gdb/solib-irix.c (fetch_lm_info).  */
278
#    define obj_offset(lm) \
279
         ((unsigned long)(lm->l_oi.oi_ehdr - lm->l_oi.oi_orig_ehdr))
280
#  endif
281
 
282
static struct link_map *
283
GC_FirstDLOpenedLinkMap()
284
{
285
    return (struct link_map *)__rld_obj_head;
286
}
287
 
288
#endif /* IRIX5 ... */
289
 
290
# if defined(SUNOS4) || defined(SUNOS5DL) || defined(IRIX5)
291
/* Add dynamic library data sections to the root set.           */
292
# if !defined(PCR) \
293
     && !defined(GC_SOLARIS_PTHREADS) && !defined(GC_IRIX_THREADS) \
294
     && defined(THREADS)
295
#   ifndef SRC_M3
296
        --> fix mutual exclusion with dlopen
297
#   endif  /* We assume M3 programs don't call dlopen for now */
298
# endif
299
 
300
# ifndef USE_PROC_FOR_LIBRARIES
301
void GC_register_dynamic_libraries()
302
{
303
  struct link_map *lm = GC_FirstDLOpenedLinkMap();
304
 
305
 
306
  for (lm = GC_FirstDLOpenedLinkMap();
307
       lm != (struct link_map *) 0;  lm = (struct link_map *) lm->l_next)
308
    {
309
#     ifdef SUNOS4
310
        struct exec *e;
311
 
312
        e = (struct exec *) lm->lm_addr;
313
        GC_add_roots_inner(
314
                    ((char *) (N_DATOFF(*e) + lm->lm_addr)),
315
                    ((char *) (N_BSSADDR(*e) + e->a_bss + lm->lm_addr)),
316
                    TRUE);
317
#     endif
318
#     if defined(SUNOS5DL) || defined(IRIX5)
319
        ElfW(Ehdr) * e;
320
        ElfW(Phdr) * p;
321
        unsigned long offset;
322
        char * start;
323
        register int i;
324
 
325
        e = (ElfW(Ehdr) *) lm->l_addr;
326
        p = ((ElfW(Phdr) *)(((char *)(e)) + e->e_phoff));
327
        offset = obj_offset(lm);
328
        for( i = 0; i < (int)(e->e_phnum); ((i++),(p++)) ) {
329
          switch( p->p_type ) {
330
            case PT_LOAD:
331
              {
332
                if( !(p->p_flags & PF_W) ) break;
333
                start = ((char *)(p->p_vaddr)) + offset;
334
                GC_add_roots_inner(
335
                  start,
336
                  start + p->p_memsz,
337
                  TRUE
338
                );
339
              }
340
              break;
341
            default:
342
              break;
343
          }
344
        }
345
#     endif
346
    }
347
#   ifdef SUNOS4
348
      {
349
        static ptr_t common_start = 0;
350
        ptr_t common_end;
351
        extern ptr_t GC_find_limit();
352
 
353
        if (common_start == 0) common_start = GC_first_common();
354
        if (common_start != 0) {
355
            common_end = GC_find_limit(common_start, TRUE);
356
            GC_add_roots_inner((char *)common_start, (char *)common_end, TRUE);
357
        }
358
      }
359
#   endif
360
}
361
 
362
# endif /* !USE_PROC ... */
363
# endif /* SUNOS */
364
 
365
#if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \
366
    (defined(FREEBSD) && defined(__ELF__)) || defined(DGUX) || \
367
    (defined(NETBSD) && defined(__ELF__)) || defined(HURD)
368
 
369
 
370
#ifdef USE_PROC_FOR_LIBRARIES
371
 
372
#include <string.h>
373
 
374
#include <sys/stat.h>
375
#include <fcntl.h>
376
#include <unistd.h>
377
 
378
#define MAPS_BUF_SIZE (32*1024)
379
 
380
extern ssize_t GC_repeat_read(int fd, char *buf, size_t count);
381
        /* Repeatedly read until buffer is filled, or EOF is encountered */
382
        /* Defined in os_dep.c.                                          */
383
 
384
char *GC_parse_map_entry(char *buf_ptr, word *start, word *end,
385
                         char *prot_buf, unsigned int *maj_dev);
386
word GC_apply_to_maps(word (*fn)(char *));
387
        /* From os_dep.c        */
388
 
389
word GC_register_map_entries(char *maps)
390
{
391
    char prot_buf[5];
392
    char *buf_ptr = maps;
393
    int count;
394
    word start, end;
395
    unsigned int maj_dev;
396
    word least_ha, greatest_ha;
397
    unsigned i;
398
    word datastart = (word)(DATASTART);
399
 
400
    /* Compute heap bounds. FIXME: Should be done by add_to_heap?       */
401
        least_ha = (word)(-1);
402
        greatest_ha = 0;
403
        for (i = 0; i < GC_n_heap_sects; ++i) {
404
            word sect_start = (word)GC_heap_sects[i].hs_start;
405
            word sect_end = sect_start + GC_heap_sects[i].hs_bytes;
406
            if (sect_start < least_ha) least_ha = sect_start;
407
            if (sect_end > greatest_ha) greatest_ha = sect_end;
408
        }
409
        if (greatest_ha < (word)GC_scratch_last_end_ptr)
410
            greatest_ha = (word)GC_scratch_last_end_ptr;
411
 
412
    for (;;) {
413
        buf_ptr = GC_parse_map_entry(buf_ptr, &start, &end, prot_buf, &maj_dev);
414
        if (buf_ptr == NULL) return 1;
415
        if (prot_buf[1] == 'w') {
416
            /* This is a writable mapping.  Add it to           */
417
            /* the root set unless it is already otherwise      */
418
            /* accounted for.                                   */
419
            if (start <= (word)GC_stackbottom && end >= (word)GC_stackbottom) {
420
                /* Stack mapping; discard       */
421
                continue;
422
            }
423
#           ifdef THREADS
424
              if (GC_segment_is_thread_stack(start, end)) continue;
425
#           endif
426
            /* We no longer exclude the main data segment.              */
427
            if (start < least_ha && end > least_ha) {
428
                end = least_ha;
429
            }
430
            if (start < greatest_ha && end > greatest_ha) {
431
                start = greatest_ha;
432
            }
433
            if (start >= least_ha && end <= greatest_ha) continue;
434
            GC_add_roots_inner((char *)start, (char *)end, TRUE);
435
        }
436
    }
437
    return 1;
438
}
439
 
440
void GC_register_dynamic_libraries()
441
{
442
   if (!GC_apply_to_maps(GC_register_map_entries))
443
       ABORT("Failed to read /proc for library registration.");
444
}
445
 
446
/* We now take care of the main data segment ourselves: */
447
GC_bool GC_register_main_static_data()
448
{
449
  return FALSE;
450
}
451
 
452
# define HAVE_REGISTER_MAIN_STATIC_DATA
453
 
454
#endif /* USE_PROC_FOR_LIBRARIES */
455
 
456
#if !defined(USE_PROC_FOR_LIBRARIES)
457
/* The following is the preferred way to walk dynamic libraries */
458
/* For glibc 2.2.4+.  Unfortunately, it doesn't work for older  */
459
/* versions.  Thanks to Jakub Jelinek for most of the code.     */
460
 
461
# if (defined(LINUX) || defined (__GLIBC__)) /* Are others OK here, too? */ \
462
     && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) \
463
         || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && defined(DT_CONFIG)))
464
 
465
/* We have the header files for a glibc that includes dl_iterate_phdr.  */
466
/* It may still not be available in the library on the target system.   */
467
/* Thus we also treat it as a weak symbol.                              */
468
#define HAVE_DL_ITERATE_PHDR
469
#pragma weak dl_iterate_phdr
470
#endif
471
 
472
# if (defined(FREEBSD) && __FreeBSD__ >= 7)
473
/* On the FreeBSD system, any target system at major version 7 shall    */
474
/* have dl_iterate_phdr; therefore, we need not make it weak as above.  */
475
#define HAVE_DL_ITERATE_PHDR
476
#endif
477
 
478
#if defined(HAVE_DL_ITERATE_PHDR)
479
 
480
static int GC_register_dynlib_callback(info, size, ptr)
481
     struct dl_phdr_info * info;
482
     size_t size;
483
     void * ptr;
484
{
485
  const ElfW(Phdr) * p;
486
  char * start;
487
  register int i;
488
 
489
  /* Make sure struct dl_phdr_info is at least as big as we need.  */
490
  if (size < offsetof (struct dl_phdr_info, dlpi_phnum)
491
      + sizeof (info->dlpi_phnum))
492
    return -1;
493
 
494
  p = info->dlpi_phdr;
495
  for( i = 0; i < (int)(info->dlpi_phnum); ((i++),(p++)) ) {
496
    switch( p->p_type ) {
497
      case PT_LOAD:
498
        {
499
          if( !(p->p_flags & PF_W) ) break;
500
          start = ((char *)(p->p_vaddr)) + info->dlpi_addr;
501
 
502
          if (GC_has_static_roots
503
              && !GC_has_static_roots(info->dlpi_name, start, p->p_memsz))
504
            break;
505
 
506
          GC_add_roots_inner(start, start + p->p_memsz, TRUE);
507
        }
508
      break;
509
      default:
510
        break;
511
    }
512
  }
513
 
514
  * (int *)ptr = 1;     /* Signal that we were called */
515
  return 0;
516
}
517
 
518
/* Return TRUE if we succeed, FALSE if dl_iterate_phdr wasn't there. */
519
 
520
GC_bool GC_register_dynamic_libraries_dl_iterate_phdr()
521
{
522
  if (dl_iterate_phdr) {
523
    int did_something = 0;
524
    dl_iterate_phdr(GC_register_dynlib_callback, &did_something);
525
    if (!did_something) {
526
        /* dl_iterate_phdr may forget the static data segment in        */
527
        /* statically linked executables.                               */
528
        GC_add_roots_inner(DATASTART, (char *)(DATAEND), TRUE);
529
#       if defined(DATASTART2)
530
          GC_add_roots_inner(DATASTART2, (char *)(DATAEND2), TRUE);
531
#       endif
532
    }
533
 
534
    return TRUE;
535
  } else {
536
    return FALSE;
537
  }
538
}
539
 
540
/* Do we need to separately register the main static data segment? */
541
GC_bool GC_register_main_static_data()
542
{
543
  return (dl_iterate_phdr == 0);
544
}
545
 
546
#define HAVE_REGISTER_MAIN_STATIC_DATA
547
 
548
# else /* !LINUX || version(glibc) < 2.2.4 */
549
 
550
/* Dynamic loading code for Linux running ELF. Somewhat tested on
551
 * Linux/x86, untested but hopefully should work on Linux/Alpha.
552
 * This code was derived from the Solaris/ELF support. Thanks to
553
 * whatever kind soul wrote that.  - Patrick Bridges */
554
 
555
/* This doesn't necessarily work in all cases, e.g. with preloaded
556
 * dynamic libraries.                                           */
557
 
558
#if defined(NETBSD)
559
#  include <sys/exec_elf.h>
560
/* for compatibility with 1.4.x */
561
#  ifndef DT_DEBUG
562
#  define DT_DEBUG     21
563
#  endif
564
#  ifndef PT_LOAD
565
#  define PT_LOAD      1
566
#  endif
567
#  ifndef PF_W
568
#  define PF_W         2
569
#  endif
570
#else
571
#  include <elf.h>
572
#endif
573
#include <link.h>
574
 
575
# endif
576
 
577
#ifdef __GNUC__
578
# pragma weak _DYNAMIC
579
#endif
580
extern ElfW(Dyn) _DYNAMIC[];
581
 
582
static struct link_map *
583
GC_FirstDLOpenedLinkMap()
584
{
585
    ElfW(Dyn) *dp;
586
    static struct link_map *cachedResult = 0;
587
 
588
    if( _DYNAMIC == 0) {
589
        return(0);
590
    }
591
    if( cachedResult == 0 ) {
592
        int tag;
593
        for( dp = _DYNAMIC; (tag = dp->d_tag) != 0; dp++ ) {
594
            /* FIXME: The DT_DEBUG header is not mandated by the        */
595
            /* ELF spec.  This code appears to be dependent on          */
596
            /* idiosynchracies of older GNU tool chains.  If this code  */
597
            /* fails for you, the real problem is probably that it is   */
598
            /* being used at all.  You should be getting the            */
599
            /* dl_iterate_phdr version.                                 */
600
            if( tag == DT_DEBUG ) {
601
                struct link_map *lm
602
                        = ((struct r_debug *)(dp->d_un.d_ptr))->r_map;
603
                if( lm != 0 ) cachedResult = lm->l_next; /* might be NIL */
604
                break;
605
            }
606
        }
607
    }
608
    return cachedResult;
609
}
610
 
611
 
612
void GC_register_dynamic_libraries()
613
{
614
  struct link_map *lm;
615
 
616
 
617
# ifdef HAVE_DL_ITERATE_PHDR
618
    if (GC_register_dynamic_libraries_dl_iterate_phdr()) {
619
        return;
620
    }
621
# endif
622
  lm = GC_FirstDLOpenedLinkMap();
623
  for (lm = GC_FirstDLOpenedLinkMap();
624
       lm != (struct link_map *) 0;  lm = lm->l_next)
625
    {
626
        ElfW(Ehdr) * e;
627
        ElfW(Phdr) * p;
628
        unsigned long offset;
629
        char * start;
630
        register int i;
631
 
632
        e = (ElfW(Ehdr) *) lm->l_addr;
633
        p = ((ElfW(Phdr) *)(((char *)(e)) + e->e_phoff));
634
        offset = ((unsigned long)(lm->l_addr));
635
        for( i = 0; i < (int)(e->e_phnum); ((i++),(p++)) ) {
636
          switch( p->p_type ) {
637
            case PT_LOAD:
638
              {
639
                if( !(p->p_flags & PF_W) ) break;
640
                start = ((char *)(p->p_vaddr)) + offset;
641
                GC_add_roots_inner(start, start + p->p_memsz, TRUE);
642
              }
643
              break;
644
            default:
645
              break;
646
          }
647
        }
648
    }
649
}
650
 
651
#endif /* !USE_PROC_FOR_LIBRARIES */
652
 
653
#endif /* LINUX */
654
 
655
#if defined(USE_PROC_FOR_LIBRARIES) && !defined(LINUX)
656
 
657
#include <sys/procfs.h>
658
#include <sys/stat.h>
659
#include <fcntl.h>
660
#include <elf.h>
661
#include <errno.h>
662
#include <signal.h>  /* Only for the following test. */
663
#ifndef _sigargs
664
# define IRIX6
665
#endif
666
 
667
extern void * GC_roots_present();
668
        /* The type is a lie, since the real type doesn't make sense here, */
669
        /* and we only test for NULL.                                      */
670
 
671
 
672
/* We use /proc to track down all parts of the address space that are   */
673
/* mapped by the process, and throw out regions we know we shouldn't    */
674
/* worry about.  This may also work under other SVR4 variants.          */
675
void GC_register_dynamic_libraries()
676
{
677
    static int fd = -1;
678
    char buf[30];
679
    static prmap_t * addr_map = 0;
680
    static int current_sz = 0;   /* Number of records currently in addr_map */
681
    static int needed_sz;       /* Required size of addr_map            */
682
    register int i;
683
    register long flags;
684
    register ptr_t start;
685
    register ptr_t limit;
686
    ptr_t heap_start = (ptr_t)HEAP_START;
687
    ptr_t heap_end = heap_start;
688
 
689
#   ifdef SUNOS5DL
690
#     define MA_PHYS 0
691
#   endif /* SUNOS5DL */
692
 
693
    if (fd < 0) {
694
      sprintf(buf, "/proc/%d", getpid());
695
        /* The above generates a lint complaint, since pid_t varies.    */
696
        /* It's unclear how to improve this.                            */
697
      fd = open(buf, O_RDONLY);
698
      if (fd < 0) {
699
        ABORT("/proc open failed");
700
      }
701
    }
702
    if (ioctl(fd, PIOCNMAP, &needed_sz) < 0) {
703
        GC_err_printf2("fd = %d, errno = %d\n", fd, errno);
704
        ABORT("/proc PIOCNMAP ioctl failed");
705
    }
706
    if (needed_sz >= current_sz) {
707
        current_sz = needed_sz * 2 + 1;
708
                        /* Expansion, plus room for 0 record */
709
        addr_map = (prmap_t *)GC_scratch_alloc((word)
710
                                                (current_sz * sizeof(prmap_t)));
711
    }
712
    if (ioctl(fd, PIOCMAP, addr_map) < 0) {
713
        GC_err_printf4("fd = %d, errno = %d, needed_sz = %d, addr_map = 0x%X\n",
714
                        fd, errno, needed_sz, addr_map);
715
        ABORT("/proc PIOCMAP ioctl failed");
716
    };
717
    if (GC_n_heap_sects > 0) {
718
        heap_end = GC_heap_sects[GC_n_heap_sects-1].hs_start
719
                        + GC_heap_sects[GC_n_heap_sects-1].hs_bytes;
720
        if (heap_end < GC_scratch_last_end_ptr) heap_end = GC_scratch_last_end_ptr;
721
    }
722
    for (i = 0; i < needed_sz; i++) {
723
        flags = addr_map[i].pr_mflags;
724
        if ((flags & (MA_BREAK | MA_STACK | MA_PHYS
725
                      | MA_FETCHOP | MA_NOTCACHED)) != 0) goto irrelevant;
726
        if ((flags & (MA_READ | MA_WRITE)) != (MA_READ | MA_WRITE))
727
            goto irrelevant;
728
          /* The latter test is empirically useless in very old Irix    */
729
          /* versions.  Other than the                                  */
730
          /* main data and stack segments, everything appears to be     */
731
          /* mapped readable, writable, executable, and shared(!!).     */
732
          /* This makes no sense to me. - HB                            */
733
        start = (ptr_t)(addr_map[i].pr_vaddr);
734
        if (GC_roots_present(start)) goto irrelevant;
735
        if (start < heap_end && start >= heap_start)
736
                goto irrelevant;
737
#       ifdef MMAP_STACKS
738
          if (GC_is_thread_stack(start)) goto irrelevant;
739
#       endif /* MMAP_STACKS */
740
 
741
        limit = start + addr_map[i].pr_size;
742
        /* The following seemed to be necessary for very old versions   */
743
        /* of Irix, but it has been reported to discard relevant        */
744
        /* segments under Irix 6.5.                                     */
745
#       ifndef IRIX6
746
          if (addr_map[i].pr_off == 0 && strncmp(start, ELFMAG, 4) == 0) {
747
            /* Discard text segments, i.e. 0-offset mappings against    */
748
            /* executable files which appear to have ELF headers.       */
749
            caddr_t arg;
750
            int obj;
751
#           define MAP_IRR_SZ 10
752
            static ptr_t map_irr[MAP_IRR_SZ];
753
                                        /* Known irrelevant map entries */
754
            static int n_irr = 0;
755
            struct stat buf;
756
            register int i;
757
 
758
            for (i = 0; i < n_irr; i++) {
759
                if (map_irr[i] == start) goto irrelevant;
760
            }
761
            arg = (caddr_t)start;
762
            obj = ioctl(fd, PIOCOPENM, &arg);
763
            if (obj >= 0) {
764
                fstat(obj, &buf);
765
                close(obj);
766
                if ((buf.st_mode & 0111) != 0) {
767
                    if (n_irr < MAP_IRR_SZ) {
768
                        map_irr[n_irr++] = start;
769
                    }
770
                    goto irrelevant;
771
                }
772
            }
773
          }
774
#       endif /* !IRIX6 */
775
        GC_add_roots_inner(start, limit, TRUE);
776
      irrelevant: ;
777
    }
778
    /* Dont keep cached descriptor, for now.  Some kernels don't like us */
779
    /* to keep a /proc file descriptor around during kill -9.            */
780
        if (close(fd) < 0) ABORT("Couldnt close /proc file");
781
        fd = -1;
782
}
783
 
784
# endif /* USE_PROC */
785
 
786
# if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
787
 
788
# define WIN32_LEAN_AND_MEAN
789
# define NOSERVICE
790
# include <windows.h>
791
# include <stdlib.h>
792
 
793
  /* We traverse the entire address space and register all segments     */
794
  /* that could possibly have been written to.                          */
795
 
796
  extern GC_bool GC_is_heap_base (ptr_t p);
797
 
798
# ifdef GC_WIN32_THREADS
799
    extern void GC_get_next_stack(char *start, char **lo, char **hi);
800
    void GC_cond_add_roots(char *base, char * limit)
801
    {
802
      char * curr_base = base;
803
      char * next_stack_lo;
804
      char * next_stack_hi;
805
 
806
      if (base == limit) return;
807
      for(;;) {
808
          GC_get_next_stack(curr_base, &next_stack_lo, &next_stack_hi);
809
          if (next_stack_lo >= limit) break;
810
          GC_add_roots_inner(curr_base, next_stack_lo, TRUE);
811
          curr_base = next_stack_hi;
812
      }
813
      if (curr_base < limit) GC_add_roots_inner(curr_base, limit, TRUE);
814
    }
815
# else
816
    void GC_cond_add_roots(char *base, char * limit)
817
    {
818
      char dummy;
819
      char * stack_top
820
         = (char *) ((word)(&dummy) & ~(GC_sysinfo.dwAllocationGranularity-1));
821
      if (base == limit) return;
822
      if (limit > stack_top && base < GC_stackbottom) {
823
          /* Part of the stack; ignore it. */
824
          return;
825
      }
826
      GC_add_roots_inner(base, limit, TRUE);
827
    }
828
# endif
829
 
830
# if defined(MSWINCE) || defined(CYGWIN32)
831
  /* Do we need to separately register the main static data segment? */
832
  GC_bool GC_register_main_static_data()
833
  {
834
    return FALSE;
835
  }
836
# else /* win32 */
837
  extern GC_bool GC_no_win32_dlls;
838
 
839
  GC_bool GC_register_main_static_data()
840
  {
841
    return GC_no_win32_dlls;
842
  }
843
# endif /* win32 */
844
 
845
# define HAVE_REGISTER_MAIN_STATIC_DATA
846
 
847
  /* The frame buffer testing code is dead in this version.     */
848
  /* We leave it here temporarily in case the switch to just    */
849
  /* testing for MEM_IMAGE sections causes un expected          */
850
  /* problems.                                                  */
851
  GC_bool GC_warn_fb = TRUE;    /* Warn about traced likely     */
852
                                /* graphics memory.             */
853
  GC_bool GC_disallow_ignore_fb = FALSE;
854
  int GC_ignore_fb_mb;  /* Ignore mappings bigger than the      */
855
                        /* specified number of MB.              */
856
  GC_bool GC_ignore_fb = FALSE; /* Enable frame buffer  */
857
                                /* checking.            */
858
 
859
  /* Issue warning if tracing apparent framebuffer.             */
860
  /* This limits us to one warning, and it's a back door to     */
861
  /* disable that.                                              */
862
 
863
  /* Should [start, start+len) be treated as a frame buffer     */
864
  /* and ignored?                                               */
865
  /* Unfortunately, we currently are not quite sure how to tell */
866
  /* this automatically, and rely largely on user input.        */
867
  /* We expect that any mapping with type MEM_MAPPED (which     */
868
  /* apparently excludes library data sections) can be safely   */
869
  /* ignored.  But we're too chicken to do that in this         */
870
  /* version.                                                   */
871
  /* Based on a very limited sample, it appears that:           */
872
  /*    - Frame buffer mappings appear as mappings of large     */
873
  /*      length, usually a bit less than a power of two.       */
874
  /*    - The definition of "a bit less" in the above cannot    */
875
  /*      be made more precise.                                 */
876
  /*    - Have a starting address at best 64K aligned.          */
877
  /*    - Have type == MEM_MAPPED.                              */
878
  static GC_bool is_frame_buffer(ptr_t start, size_t len, DWORD tp)
879
  {
880
    static GC_bool initialized = FALSE;
881
#   define MB (1024*1024)
882
#   define DEFAULT_FB_MB 15
883
#   define MIN_FB_MB 3
884
 
885
    if (GC_disallow_ignore_fb || tp != MEM_MAPPED) return FALSE;
886
    if (!initialized) {
887
      char * ignore_fb_string =  GETENV("GC_IGNORE_FB");
888
 
889
      if (0 != ignore_fb_string) {
890
        while (*ignore_fb_string == ' ' || *ignore_fb_string == '\t')
891
          ++ignore_fb_string;
892
        if (*ignore_fb_string == '\0') {
893
          GC_ignore_fb_mb = DEFAULT_FB_MB;
894
        } else {
895
          GC_ignore_fb_mb = atoi(ignore_fb_string);
896
          if (GC_ignore_fb_mb < MIN_FB_MB) {
897
            WARN("Bad GC_IGNORE_FB value.  Using %ld\n", DEFAULT_FB_MB);
898
            GC_ignore_fb_mb = DEFAULT_FB_MB;
899
          }
900
        }
901
        GC_ignore_fb = TRUE;
902
      } else {
903
        GC_ignore_fb_mb = DEFAULT_FB_MB;  /* For warning */
904
      }
905
      initialized = TRUE;
906
    }
907
    if (len >= ((size_t)GC_ignore_fb_mb << 20)) {
908
      if (GC_ignore_fb) {
909
        return TRUE;
910
      } else {
911
        if (GC_warn_fb) {
912
          WARN("Possible frame buffer mapping at 0x%lx: \n"
913
               "\tConsider setting GC_IGNORE_FB to improve performance.\n",
914
               start);
915
          GC_warn_fb = FALSE;
916
        }
917
        return FALSE;
918
      }
919
    } else {
920
      return FALSE;
921
    }
922
  }
923
 
924
# ifdef DEBUG_VIRTUALQUERY
925
  void GC_dump_meminfo(MEMORY_BASIC_INFORMATION *buf)
926
  {
927
    GC_printf4("BaseAddress = %lx, AllocationBase = %lx, RegionSize = %lx(%lu)\n",
928
               buf -> BaseAddress, buf -> AllocationBase, buf -> RegionSize,
929
               buf -> RegionSize);
930
    GC_printf4("\tAllocationProtect = %lx, State = %lx, Protect = %lx, "
931
               "Type = %lx\n",
932
               buf -> AllocationProtect, buf -> State, buf -> Protect,
933
               buf -> Type);
934
  }
935
# endif /* DEBUG_VIRTUALQUERY */
936
 
937
# ifdef CYGWIN32
938
#   define GC_wnt (TRUE)
939
# else
940
    extern GC_bool GC_wnt;  /* Is Windows NT derivative.        */
941
                            /* Defined and set in os_dep.c.     */
942
# endif
943
 
944
  void GC_register_dynamic_libraries()
945
  {
946
    MEMORY_BASIC_INFORMATION buf;
947
    DWORD result;
948
    DWORD protect;
949
    LPVOID p;
950
    char * base;
951
    char * limit, * new_limit;
952
 
953
#   ifdef MSWIN32
954
      if (GC_no_win32_dlls) return;
955
#   endif
956
    base = limit = p = GC_sysinfo.lpMinimumApplicationAddress;
957
#   if defined(MSWINCE) && !defined(_WIN32_WCE_EMULATION)
958
    /* Only the first 32 MB of address space belongs to the current process */
959
    while (p < (LPVOID)0x02000000) {
960
        result = VirtualQuery(p, &buf, sizeof(buf));
961
        if (result == 0) {
962
            /* Page is free; advance to the next possible allocation base */
963
            new_limit = (char *)
964
                (((DWORD) p + GC_sysinfo.dwAllocationGranularity)
965
                 & ~(GC_sysinfo.dwAllocationGranularity-1));
966
        } else
967
#   else
968
    while (p < GC_sysinfo.lpMaximumApplicationAddress) {
969
        result = VirtualQuery(p, &buf, sizeof(buf));
970
#   endif
971
        {
972
            if (result != sizeof(buf)) {
973
                ABORT("Weird VirtualQuery result");
974
            }
975
            new_limit = (char *)p + buf.RegionSize;
976
            protect = buf.Protect;
977
            if (buf.State == MEM_COMMIT
978
                && (protect == PAGE_EXECUTE_READWRITE
979
                    || protect == PAGE_READWRITE)
980
                && !GC_is_heap_base(buf.AllocationBase)
981
                /* This used to check for
982
                 * !is_frame_buffer(p, buf.RegionSize, buf.Type)
983
                 * instead of just checking for MEM_IMAGE.
984
                 * If something breaks, change it back. */
985
                /* There is some evidence that we cannot always
986
                 * ignore MEM_PRIVATE sections under Windows ME
987
                 * and predecessors.  Hence we now also check for
988
                 * that case.   */
989
                && (buf.Type == MEM_IMAGE ||
990
                    !GC_wnt && buf.Type == MEM_PRIVATE)) {
991
#               ifdef DEBUG_VIRTUALQUERY
992
                  GC_dump_meminfo(&buf);
993
#               endif
994
                if ((char *)p != limit) {
995
                    GC_cond_add_roots(base, limit);
996
                    base = p;
997
                }
998
                limit = new_limit;
999
            }
1000
        }
1001
        if (p > (LPVOID)new_limit /* overflow */) break;
1002
        p = (LPVOID)new_limit;
1003
    }
1004
    GC_cond_add_roots(base, limit);
1005
  }
1006
 
1007
#endif /* MSWIN32 || MSWINCE || CYGWIN32 */
1008
 
1009
#if defined(ALPHA) && defined(OSF1)
1010
 
1011
#include <loader.h>
1012
 
1013
void GC_register_dynamic_libraries()
1014
{
1015
  int status;
1016
  ldr_process_t mypid;
1017
 
1018
  /* module */
1019
    ldr_module_t moduleid = LDR_NULL_MODULE;
1020
    ldr_module_info_t moduleinfo;
1021
    size_t moduleinfosize = sizeof(moduleinfo);
1022
    size_t modulereturnsize;
1023
 
1024
  /* region */
1025
    ldr_region_t region;
1026
    ldr_region_info_t regioninfo;
1027
    size_t regioninfosize = sizeof(regioninfo);
1028
    size_t regionreturnsize;
1029
 
1030
  /* Obtain id of this process */
1031
    mypid = ldr_my_process();
1032
 
1033
  /* For each module */
1034
    while (TRUE) {
1035
 
1036
      /* Get the next (first) module */
1037
        status = ldr_next_module(mypid, &moduleid);
1038
 
1039
      /* Any more modules? */
1040
        if (moduleid == LDR_NULL_MODULE)
1041
            break;    /* No more modules */
1042
 
1043
      /* Check status AFTER checking moduleid because */
1044
      /* of a bug in the non-shared ldr_next_module stub */
1045
        if (status != 0 ) {
1046
            GC_printf1("dynamic_load: status = %ld\n", (long)status);
1047
            {
1048
                extern char *sys_errlist[];
1049
                extern int sys_nerr;
1050
                extern int errno;
1051
                if (errno <= sys_nerr) {
1052
                    GC_printf1("dynamic_load: %s\n", (long)sys_errlist[errno]);
1053
               } else {
1054
                    GC_printf1("dynamic_load: %d\n", (long)errno);
1055
                }
1056
        }
1057
            ABORT("ldr_next_module failed");
1058
         }
1059
 
1060
      /* Get the module information */
1061
        status = ldr_inq_module(mypid, moduleid, &moduleinfo,
1062
                                moduleinfosize, &modulereturnsize);
1063
        if (status != 0 )
1064
            ABORT("ldr_inq_module failed");
1065
 
1066
      /* is module for the main program (i.e. nonshared portion)? */
1067
          if (moduleinfo.lmi_flags & LDR_MAIN)
1068
              continue;    /* skip the main module */
1069
 
1070
#     ifdef VERBOSE
1071
          GC_printf("---Module---\n");
1072
          GC_printf("Module ID            = %16ld\n", moduleinfo.lmi_modid);
1073
          GC_printf("Count of regions     = %16d\n", moduleinfo.lmi_nregion);
1074
          GC_printf("flags for module     = %16lx\n", moduleinfo.lmi_flags);
1075
          GC_printf("pathname of module   = \"%s\"\n", moduleinfo.lmi_name);
1076
#     endif
1077
 
1078
      /* For each region in this module */
1079
        for (region = 0; region < moduleinfo.lmi_nregion; region++) {
1080
 
1081
          /* Get the region information */
1082
            status = ldr_inq_region(mypid, moduleid, region, &regioninfo,
1083
                                    regioninfosize, &regionreturnsize);
1084
            if (status != 0 )
1085
                ABORT("ldr_inq_region failed");
1086
 
1087
          /* only process writable (data) regions */
1088
            if (! (regioninfo.lri_prot & LDR_W))
1089
                continue;
1090
 
1091
#         ifdef VERBOSE
1092
              GC_printf("--- Region ---\n");
1093
              GC_printf("Region number    = %16ld\n",
1094
                        regioninfo.lri_region_no);
1095
              GC_printf("Protection flags = %016x\n",  regioninfo.lri_prot);
1096
              GC_printf("Virtual address  = %16p\n",   regioninfo.lri_vaddr);
1097
              GC_printf("Mapped address   = %16p\n",   regioninfo.lri_mapaddr);
1098
              GC_printf("Region size      = %16ld\n",  regioninfo.lri_size);
1099
              GC_printf("Region name      = \"%s\"\n", regioninfo.lri_name);
1100
#         endif
1101
 
1102
          /* register region as a garbage collection root */
1103
            GC_add_roots_inner (
1104
                (char *)regioninfo.lri_mapaddr,
1105
                (char *)regioninfo.lri_mapaddr + regioninfo.lri_size,
1106
                TRUE);
1107
 
1108
        }
1109
    }
1110
}
1111
#endif
1112
 
1113
#if defined(HPUX)
1114
 
1115
#include <errno.h>
1116
#include <dl.h>
1117
 
1118
extern int errno;
1119
extern char *sys_errlist[];
1120
extern int sys_nerr;
1121
 
1122
void GC_register_dynamic_libraries()
1123
{
1124
  int status;
1125
  int index = 1; /* Ordinal position in shared library search list */
1126
  struct shl_descriptor *shl_desc; /* Shared library info, see dl.h */
1127
 
1128
  /* For each dynamic library loaded */
1129
    while (TRUE) {
1130
 
1131
      /* Get info about next shared library */
1132
        status = shl_get(index, &shl_desc);
1133
 
1134
      /* Check if this is the end of the list or if some error occured */
1135
        if (status != 0) {
1136
#        ifdef GC_HPUX_THREADS
1137
           /* I've seen errno values of 0.  The man page is not clear   */
1138
           /* as to whether errno should get set on a -1 return.        */
1139
           break;
1140
#        else
1141
          if (errno == EINVAL) {
1142
              break; /* Moved past end of shared library list --> finished */
1143
          } else {
1144
              if (errno <= sys_nerr) {
1145
                    GC_printf1("dynamic_load: %s\n", (long) sys_errlist[errno]);
1146
              } else {
1147
                    GC_printf1("dynamic_load: %d\n", (long) errno);
1148
              }
1149
              ABORT("shl_get failed");
1150
          }
1151
#        endif
1152
        }
1153
 
1154
#     ifdef VERBOSE
1155
          GC_printf0("---Shared library---\n");
1156
          GC_printf1("\tfilename        = \"%s\"\n", shl_desc->filename);
1157
          GC_printf1("\tindex           = %d\n", index);
1158
          GC_printf1("\thandle          = %08x\n",
1159
                                        (unsigned long) shl_desc->handle);
1160
          GC_printf1("\ttext seg. start = %08x\n", shl_desc->tstart);
1161
          GC_printf1("\ttext seg. end   = %08x\n", shl_desc->tend);
1162
          GC_printf1("\tdata seg. start = %08x\n", shl_desc->dstart);
1163
          GC_printf1("\tdata seg. end   = %08x\n", shl_desc->dend);
1164
          GC_printf1("\tref. count      = %lu\n", shl_desc->ref_count);
1165
#     endif
1166
 
1167
      /* register shared library's data segment as a garbage collection root */
1168
        GC_add_roots_inner((char *) shl_desc->dstart,
1169
                           (char *) shl_desc->dend, TRUE);
1170
 
1171
        index++;
1172
    }
1173
}
1174
#endif /* HPUX */
1175
 
1176
#ifdef RS6000
1177
#pragma alloca
1178
#include <sys/ldr.h>
1179
#include <sys/errno.h>
1180
void GC_register_dynamic_libraries()
1181
{
1182
        int len;
1183
        char *ldibuf;
1184
        int ldibuflen;
1185
        struct ld_info *ldi;
1186
 
1187
        ldibuf = alloca(ldibuflen = 8192);
1188
 
1189
        while ( (len = loadquery(L_GETINFO,ldibuf,ldibuflen)) < 0) {
1190
                if (errno != ENOMEM) {
1191
                        ABORT("loadquery failed");
1192
                }
1193
                ldibuf = alloca(ldibuflen *= 2);
1194
        }
1195
 
1196
        ldi = (struct ld_info *)ldibuf;
1197
        while (ldi) {
1198
                len = ldi->ldinfo_next;
1199
                GC_add_roots_inner(
1200
                                ldi->ldinfo_dataorg,
1201
                                (ptr_t)(unsigned long)ldi->ldinfo_dataorg
1202
                                + ldi->ldinfo_datasize,
1203
                                TRUE);
1204
                ldi = len ? (struct ld_info *)((char *)ldi + len) : 0;
1205
        }
1206
}
1207
#endif /* RS6000 */
1208
 
1209
#ifdef DARWIN
1210
 
1211
/* __private_extern__ hack required for pre-3.4 gcc versions.   */
1212
#ifndef __private_extern__
1213
# define __private_extern__ extern
1214
# include <mach-o/dyld.h>
1215
# undef __private_extern__
1216
#else
1217
# include <mach-o/dyld.h>
1218
#endif
1219
#include <mach-o/getsect.h>
1220
 
1221
/*#define DARWIN_DEBUG*/
1222
 
1223
/* Writeable sections generally available on Darwin.  */
1224
const static struct {
1225
        const char *seg;
1226
        const char *sect;
1227
} GC_dyld_sections[] = {
1228
        { SEG_DATA, SECT_DATA },
1229
        /* Used by FSF GCC, but not by OSX system tools, so far.  */
1230
        { SEG_DATA, "__static_data" },
1231
        { SEG_DATA, SECT_BSS },
1232
        { SEG_DATA, SECT_COMMON },
1233
        /* FSF GCC - zero-sized object sections for targets supporting section
1234
           anchors.  */
1235
        { SEG_DATA, "__zobj_data" },
1236
        { SEG_DATA, "__zobj_bss" }
1237
};
1238
 
1239
/* Additional writeable sections:
1240
 
1241
   GCC on Darwin constucts aligned sections "on demand", where the alignment
1242
   size is embedded in the section name.  Furthermore, there are distintions
1243
   between sections containing private vs. public symbols.
1244
 
1245
   It also constructs sections specifically for zero-sized objects, when the
1246
   target supports section anchors.  */
1247
const char * GC_dyld_add_sect_fmts[] =
1248
{
1249
  "__bss%u",
1250
  "__pu_bss%u",
1251
  "__zo_bss%u",
1252
  "__zo_pu_bss%u",
1253
  NULL
1254
} ;
1255
 
1256
/* Currently, mach-o will allow up to a max of 2^15 alignment in an
1257
   object file.  */
1258
#define L2_MAX_OFILE_ALIGNMENT 15
1259
 
1260
 
1261
#ifdef DARWIN_DEBUG
1262
static const char *
1263
GC_dyld_name_for_hdr (const struct GC_MACH_HEADER *hdr)
1264
{
1265
  unsigned long i,c;
1266
  c = _dyld_image_count();
1267
  for (i=0;i<c;i++)
1268
    if(_dyld_get_image_header(i) == hdr)
1269
      return _dyld_get_image_name(i);
1270
  return NULL;
1271
}
1272
#endif
1273
 
1274
 
1275
/* This should never be called by a thread holding the lock */
1276
static void
1277
GC_dyld_image_add (const struct GC_MACH_HEADER *hdr, intptr_t slide)
1278
{
1279
  char secnam[16];
1280
  unsigned long start,end,i,j;
1281
  const struct GC_MACH_SECTION *sec;
1282
  const char *fmt;
1283
 
1284
  if (GC_no_dls)
1285
    return;
1286
 
1287
  for (i=0; i<sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]); i++)
1288
    {
1289
      sec = GC_GETSECTBYNAME (hdr, GC_dyld_sections[i].seg,
1290
                              GC_dyld_sections[i].sect);
1291
      if(sec == NULL || sec->size == 0)
1292
        continue;
1293
 
1294
      start = slide + sec->addr;
1295
      end = start + sec->size;
1296
 
1297
#     ifdef DARWIN_DEBUG
1298
      GC_printf5("Adding section __DATA,%s at %p-%p (%lu bytes) from image %s\n",
1299
                GC_dyld_sections[i].sect, start,end,sec->size,GC_dyld_name_for_hdr(hdr));
1300
#      endif
1301
      GC_add_roots((char*)start,(char*)end);
1302
    }
1303
 
1304
  /* Sections constructed on demand.  */
1305
  j=0;
1306
  while ((fmt = GC_dyld_add_sect_fmts[j]) != NULL)
1307
    {
1308
      /* Add our manufactured aligned BSS sections.  */
1309
      for (i=0; i<=L2_MAX_OFILE_ALIGNMENT; i++)
1310
        {
1311
          snprintf (secnam, 16, fmt, (unsigned)i);
1312
          sec = GC_GETSECTBYNAME (hdr, SEG_DATA, secnam);
1313
          if (sec == NULL || sec->size == 0)
1314
            continue;
1315
          start = slide + sec->addr;
1316
          end = start + sec->size;
1317
#         ifdef DARWIN_DEBUG
1318
          GC_printf5("Adding section __DATA,%s at %p-%p (%lu bytes) from image %s\n",
1319
                 secnam, start,end,sec->size,GC_dyld_name_for_hdr(hdr));
1320
#         endif
1321
          GC_add_roots((char*)start,(char*)end);
1322
        }
1323
      j++;
1324
    }
1325
# ifdef DARWIN_DEBUG
1326
  GC_print_static_roots();
1327
# endif
1328
}
1329
 
1330
/* This should never be called by a thread holding the lock */
1331
static void
1332
GC_dyld_image_remove (const struct GC_MACH_HEADER *hdr, intptr_t slide)
1333
{
1334
  char secnam[16];
1335
  unsigned long start,end,i,j;
1336
  const struct GC_MACH_SECTION *sec;
1337
  const char *fmt;
1338
 
1339
  for (i=0; i<sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]); i++)
1340
    {
1341
      sec = GC_GETSECTBYNAME (hdr, GC_dyld_sections[i].seg,
1342
                              GC_dyld_sections[i].sect);
1343
      if(sec == NULL || sec->size == 0)
1344
        continue;
1345
 
1346
      start = slide + sec->addr;
1347
      end = start + sec->size;
1348
#     ifdef DARWIN_DEBUG
1349
      GC_printf5("Removing section __DATA,%s at %p-%p (%lu bytes) from image %s\n",
1350
                  GC_dyld_sections[i].sect, start,end,sec->size,GC_dyld_name_for_hdr(hdr));
1351
#      endif
1352
      GC_remove_roots((char*)start,(char*)end);
1353
    }
1354
 
1355
  /* Remove our on-demand sections.  */
1356
  j=0;
1357
  while ((fmt = GC_dyld_add_sect_fmts[j]) != NULL)
1358
    {
1359
      for (i=0; i<=L2_MAX_OFILE_ALIGNMENT; i++)
1360
        {
1361
          snprintf (secnam, 16, fmt, (unsigned)i);
1362
          sec = GC_GETSECTBYNAME (hdr, SEG_DATA, secnam);
1363
          if (sec == NULL || sec->size == 0)
1364
            continue;
1365
          start = slide + sec->addr;
1366
          end = start + sec->size;
1367
#         ifdef DARWIN_DEBUG
1368
          GC_printf5("Removing section __DATA,%s at %p-%p (%lu bytes) from image %s\n",
1369
                      secnam, start,end,sec->size,GC_dyld_name_for_hdr(hdr));
1370
#         endif
1371
          GC_remove_roots((char*)start,(char*)end);
1372
        }
1373
      j++;
1374
    }
1375
 
1376
# ifdef DARWIN_DEBUG
1377
  GC_print_static_roots();
1378
# endif
1379
}
1380
 
1381
void
1382
GC_register_dynamic_libraries()
1383
{
1384
    /* Currently does nothing. The callbacks are setup by GC_init_dyld()
1385
    The dyld library takes it from there. */
1386
}
1387
 
1388
/* The _dyld_* functions have an internal lock so no _dyld functions
1389
   can be called while the world is stopped without the risk of a deadlock.
1390
   Because of this we MUST setup callbacks BEFORE we ever stop the world.
1391
   This should be called BEFORE any thread in created and WITHOUT the
1392
   allocation lock held. */
1393
 
1394
void
1395
GC_init_dyld()
1396
{
1397
  static GC_bool initialized = FALSE;
1398
  char *bind_fully_env = NULL;
1399
 
1400
  if(initialized)
1401
    return;
1402
 
1403
# ifdef DARWIN_DEBUG
1404
  GC_printf0("Registering dyld callbacks...\n");
1405
# endif
1406
 
1407
  /* Apple's Documentation:
1408
     When you call _dyld_register_func_for_add_image, the dynamic linker runtime
1409
     calls the specified callback (func) once for each of the images that is
1410
     currently loaded into the program. When a new image is added to the program,
1411
     your callback is called again with the mach_header for the new image, and the
1412
     virtual memory slide amount of the new image.
1413
 
1414
     This WILL properly register already linked libraries and libraries
1415
     linked in the future
1416
  */
1417
 
1418
  _dyld_register_func_for_add_image(GC_dyld_image_add);
1419
  _dyld_register_func_for_remove_image(GC_dyld_image_remove);
1420
 
1421
  /* Set this early to avoid reentrancy issues. */
1422
  initialized = TRUE;
1423
 
1424
  bind_fully_env = getenv("DYLD_BIND_AT_LAUNCH");
1425
 
1426
  if (bind_fully_env == NULL)
1427
    {
1428
#     ifdef DARWIN_DEBUG
1429
      GC_printf0("Forcing full bind of GC code...\n");
1430
#     endif
1431
 
1432
      if (!_dyld_bind_fully_image_containing_address((unsigned long*)GC_malloc))
1433
        GC_abort("_dyld_bind_fully_image_containing_address failed");
1434
    }
1435
}
1436
 
1437
#define HAVE_REGISTER_MAIN_STATIC_DATA
1438
GC_bool
1439
GC_register_main_static_data (void)
1440
{
1441
  /* Already done through dyld callbacks */
1442
  return FALSE;
1443
}
1444
 
1445
#endif /* DARWIN */
1446
 
1447
#else /* !DYNAMIC_LOADING */
1448
 
1449
#ifdef PCR
1450
 
1451
#   include "il/PCR_IL.h"
1452
#   include "th/PCR_ThCtl.h"
1453
#   include "mm/PCR_MM.h"
1454
 
1455
void GC_register_dynamic_libraries()
1456
{
1457
    /* Add new static data areas of dynamically loaded modules. */
1458
        {
1459
          PCR_IL_LoadedFile * p = PCR_IL_GetLastLoadedFile();
1460
          PCR_IL_LoadedSegment * q;
1461
 
1462
          /* Skip uncommited files */
1463
          while (p != NIL && !(p -> lf_commitPoint)) {
1464
              /* The loading of this file has not yet been committed    */
1465
              /* Hence its description could be inconsistent.           */
1466
              /* Furthermore, it hasn't yet been run.  Hence its data   */
1467
              /* segments can't possibly reference heap allocated       */
1468
              /* objects.                                               */
1469
              p = p -> lf_prev;
1470
          }
1471
          for (; p != NIL; p = p -> lf_prev) {
1472
            for (q = p -> lf_ls; q != NIL; q = q -> ls_next) {
1473
              if ((q -> ls_flags & PCR_IL_SegFlags_Traced_MASK)
1474
                  == PCR_IL_SegFlags_Traced_on) {
1475
                GC_add_roots_inner
1476
                        ((char *)(q -> ls_addr),
1477
                         (char *)(q -> ls_addr) + q -> ls_bytes,
1478
                         TRUE);
1479
              }
1480
            }
1481
          }
1482
        }
1483
}
1484
 
1485
 
1486
#else /* !PCR */
1487
 
1488
void GC_register_dynamic_libraries(){}
1489
 
1490
int GC_no_dynamic_loading;
1491
 
1492
#endif /* !PCR */
1493
 
1494
#endif /* !DYNAMIC_LOADING */
1495
 
1496
#ifndef HAVE_REGISTER_MAIN_STATIC_DATA
1497
 
1498
/* Do we need to separately register the main static data segment? */
1499
GC_bool GC_register_main_static_data()
1500
{
1501
  return TRUE;
1502
}
1503
#endif /* HAVE_REGISTER_MAIN_STATIC_DATA */
1504
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.