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