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
GC_register_has_static_roots_callback(int (* callback)(const char *,void *,size_t))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 *
GC_FirstDLOpenedLinkMap()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 *
GC_FirstDLOpenedLinkMap()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.			*/
GC_first_common()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 *
GC_FirstDLOpenedLinkMap()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 
GC_register_map_entries(char * maps)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 
GC_register_dynamic_libraries()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: */
GC_register_main_static_data()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 
GC_register_dynlib_callback(info,size,ptr)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 
GC_register_dynamic_libraries_dl_iterate_phdr()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? */
GC_register_main_static_data()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 *
GC_FirstDLOpenedLinkMap()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 
GC_register_dynamic_libraries()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.		*/
GC_register_dynamic_libraries()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);
GC_cond_add_roots(char * base,char * limit)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
GC_cond_add_roots(char * base,char * limit)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? */
GC_register_main_static_data()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 
GC_register_main_static_data()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.				*/
is_frame_buffer(ptr_t start,size_t len,DWORD tp)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
GC_dump_meminfo(MEMORY_BASIC_INFORMATION * buf)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 
GC_register_dynamic_libraries()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 
1506