OSDN Git Service

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