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