OSDN Git Service

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