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