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