source: trunk/gcc/boehm-gc/dyn_load.c@ 3232

Last change on this file since 3232 was 1392, checked in by bird, 21 years ago

This commit was generated by cvs2svn to compensate for changes in r1391,
which included commits to RCS files with non-trunk default branches.

  • Property cvs2svn:cvs-rev set to 1.1.1.2
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 32.8 KB
Line 
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) && \
59 !(defined(FREEBSD) && defined(__ELF__)) && \
60 !(defined(NETBSD) && defined(__ELF__)) && !defined(HURD)
61 --> We only know how to find data segments of dynamic libraries for the
62 --> above. Additional SVR4 variants might not be too
63 --> hard to add.
64#endif
65
66#include <stdio.h>
67#ifdef SUNOS5DL
68# include <sys/elf.h>
69# include <dlfcn.h>
70# include <link.h>
71#endif
72#ifdef SUNOS4
73# include <dlfcn.h>
74# include <link.h>
75# include <a.out.h>
76 /* struct link_map field overrides */
77# define l_next lm_next
78# define l_addr lm_addr
79# define l_name lm_name
80#endif
81
82#if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \
83 (defined(FREEBSD) && defined(__ELF__)) || \
84 (defined(NETBSD) && defined(__ELF__)) || defined(HURD)
85# include <stddef.h>
86# include <elf.h>
87# include <link.h>
88#endif
89
90/* Newer versions of GNU/Linux define this macro. We
91 * define it similarly for any ELF systems that don't. */
92# ifndef ElfW
93# if !defined(ELF_CLASS) || ELF_CLASS == ELFCLASS32
94# define ElfW(type) Elf32_##type
95# else
96# define ElfW(type) Elf64_##type
97# endif
98# endif
99
100#if defined(SUNOS5DL) && !defined(USE_PROC_FOR_LIBRARIES)
101
102#ifdef LINT
103 Elf32_Dyn _DYNAMIC;
104#endif
105
106static struct link_map *
107GC_FirstDLOpenedLinkMap()
108{
109 extern ElfW(Dyn) _DYNAMIC;
110 ElfW(Dyn) *dp;
111 struct r_debug *r;
112 static struct link_map * cachedResult = 0;
113 static ElfW(Dyn) *dynStructureAddr = 0;
114 /* BTL: added to avoid Solaris 5.3 ld.so _DYNAMIC bug */
115
116# ifdef SUNOS53_SHARED_LIB
117 /* BTL: Avoid the Solaris 5.3 bug that _DYNAMIC isn't being set */
118 /* up properly in dynamically linked .so's. This means we have */
119 /* to use its value in the set of original object files loaded */
120 /* at program startup. */
121 if( dynStructureAddr == 0 ) {
122 void* startupSyms = dlopen(0, RTLD_LAZY);
123 dynStructureAddr = (ElfW(Dyn)*)dlsym(startupSyms, "_DYNAMIC");
124 }
125# else
126 dynStructureAddr = &_DYNAMIC;
127# endif
128
129 if( dynStructureAddr == 0) {
130 return(0);
131 }
132 if( cachedResult == 0 ) {
133 int tag;
134 for( dp = ((ElfW(Dyn) *)(&_DYNAMIC)); (tag = dp->d_tag) != 0; dp++ ) {
135 if( tag == DT_DEBUG ) {
136 struct link_map *lm
137 = ((struct r_debug *)(dp->d_un.d_ptr))->r_map;
138 if( lm != 0 ) cachedResult = lm->l_next; /* might be NIL */
139 break;
140 }
141 }
142 }
143 return cachedResult;
144}
145
146#endif /* SUNOS5DL ... */
147
148/* BTL: added to fix circular dlopen definition if GC_SOLARIS_THREADS defined */
149# if defined(GC_must_restore_redefined_dlopen)
150# define dlopen GC_dlopen
151# endif
152
153#if defined(SUNOS4) && !defined(USE_PROC_FOR_LIBRARIES)
154
155#ifdef LINT
156 struct link_dynamic _DYNAMIC;
157#endif
158
159static struct link_map *
160GC_FirstDLOpenedLinkMap()
161{
162 extern struct link_dynamic _DYNAMIC;
163
164 if( &_DYNAMIC == 0) {
165 return(0);
166 }
167 return(_DYNAMIC.ld_un.ld_1->ld_loaded);
168}
169
170/* Return the address of the ld.so allocated common symbol */
171/* with the least address, or 0 if none. */
172static ptr_t GC_first_common()
173{
174 ptr_t result = 0;
175 extern struct link_dynamic _DYNAMIC;
176 struct rtc_symb * curr_symbol;
177
178 if( &_DYNAMIC == 0) {
179 return(0);
180 }
181 curr_symbol = _DYNAMIC.ldd -> ldd_cp;
182 for (; curr_symbol != 0; curr_symbol = curr_symbol -> rtc_next) {
183 if (result == 0
184 || (ptr_t)(curr_symbol -> rtc_sp -> n_value) < result) {
185 result = (ptr_t)(curr_symbol -> rtc_sp -> n_value);
186 }
187 }
188 return(result);
189}
190
191#endif /* SUNOS4 ... */
192
193# if defined(SUNOS4) || defined(SUNOS5DL)
194/* Add dynamic library data sections to the root set. */
195# if !defined(PCR) && !defined(GC_SOLARIS_THREADS) && defined(THREADS)
196# ifndef SRC_M3
197 --> fix mutual exclusion with dlopen
198# endif /* We assume M3 programs don't call dlopen for now */
199# endif
200
201# ifndef USE_PROC_FOR_LIBRARIES
202void GC_register_dynamic_libraries()
203{
204 struct link_map *lm = GC_FirstDLOpenedLinkMap();
205
206
207 for (lm = GC_FirstDLOpenedLinkMap();
208 lm != (struct link_map *) 0; lm = lm->l_next)
209 {
210# ifdef SUNOS4
211 struct exec *e;
212
213 e = (struct exec *) lm->lm_addr;
214 GC_add_roots_inner(
215 ((char *) (N_DATOFF(*e) + lm->lm_addr)),
216 ((char *) (N_BSSADDR(*e) + e->a_bss + lm->lm_addr)),
217 TRUE);
218# endif
219# ifdef SUNOS5DL
220 ElfW(Ehdr) * e;
221 ElfW(Phdr) * p;
222 unsigned long offset;
223 char * start;
224 register int i;
225
226 e = (ElfW(Ehdr) *) lm->l_addr;
227 p = ((ElfW(Phdr) *)(((char *)(e)) + e->e_phoff));
228 offset = ((unsigned long)(lm->l_addr));
229 for( i = 0; i < (int)(e->e_phnum); ((i++),(p++)) ) {
230 switch( p->p_type ) {
231 case PT_LOAD:
232 {
233 if( !(p->p_flags & PF_W) ) break;
234 start = ((char *)(p->p_vaddr)) + offset;
235 GC_add_roots_inner(
236 start,
237 start + p->p_memsz,
238 TRUE
239 );
240 }
241 break;
242 default:
243 break;
244 }
245 }
246# endif
247 }
248# ifdef SUNOS4
249 {
250 static ptr_t common_start = 0;
251 ptr_t common_end;
252 extern ptr_t GC_find_limit();
253
254 if (common_start == 0) common_start = GC_first_common();
255 if (common_start != 0) {
256 common_end = GC_find_limit(common_start, TRUE);
257 GC_add_roots_inner((char *)common_start, (char *)common_end, TRUE);
258 }
259 }
260# endif
261}
262
263# endif /* !USE_PROC ... */
264# endif /* SUNOS */
265
266#if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \
267 (defined(FREEBSD) && defined(__ELF__)) || \
268 (defined(NETBSD) && defined(__ELF__)) || defined(HURD)
269
270
271#ifdef USE_PROC_FOR_LIBRARIES
272
273#include <string.h>
274
275#include <sys/stat.h>
276#include <fcntl.h>
277#include <unistd.h>
278
279#define MAPS_BUF_SIZE (32*1024)
280
281extern ssize_t GC_repeat_read(int fd, char *buf, size_t count);
282 /* Repeatedly read until buffer is filled, or EOF is encountered */
283 /* Defined in os_dep.c. */
284
285static char *parse_map_entry(char *buf_ptr, word *start, word *end,
286 char *prot_buf, unsigned int *maj_dev);
287
288void GC_register_dynamic_libraries()
289{
290 int f;
291 int result;
292 char prot_buf[5];
293 int maps_size;
294 char maps_temp[32768];
295 char *maps_buf;
296 char *buf_ptr;
297 int count;
298 word start, end;
299 unsigned int maj_dev, min_dev;
300 word least_ha, greatest_ha;
301 unsigned i;
302 word datastart = (word)(DATASTART);
303
304 /* Read /proc/self/maps */
305 /* Note that we may not allocate, and thus can't use stdio. */
306 f = open("/proc/self/maps", O_RDONLY);
307 if (-1 == f) ABORT("Couldn't open /proc/self/maps");
308 /* stat() doesn't work for /proc/self/maps, so we have to
309 read it to find out how large it is... */
310 maps_size = 0;
311 do {
312 result = GC_repeat_read(f, maps_temp, sizeof(maps_temp));
313 if (result <= 0) ABORT("Couldn't read /proc/self/maps");
314 maps_size += result;
315 } while (result == sizeof(maps_temp));
316
317 if (maps_size > sizeof(maps_temp)) {
318 /* If larger than our buffer, close and re-read it. */
319 close(f);
320 f = open("/proc/self/maps", O_RDONLY);
321 if (-1 == f) ABORT("Couldn't open /proc/self/maps");
322 maps_buf = alloca(maps_size);
323 if (NULL == maps_buf) ABORT("/proc/self/maps alloca failed");
324 result = GC_repeat_read(f, maps_buf, maps_size);
325 if (result <= 0) ABORT("Couldn't read /proc/self/maps");
326 } else {
327 /* Otherwise use the fixed size buffer */
328 maps_buf = maps_temp;
329 }
330
331 close(f);
332 maps_buf[result] = '\0';
333 buf_ptr = maps_buf;
334 /* Compute heap bounds. Should be done by add_to_heap? */
335 least_ha = (word)(-1);
336 greatest_ha = 0;
337 for (i = 0; i < GC_n_heap_sects; ++i) {
338 word sect_start = (word)GC_heap_sects[i].hs_start;
339 word sect_end = sect_start + GC_heap_sects[i].hs_bytes;
340 if (sect_start < least_ha) least_ha = sect_start;
341 if (sect_end > greatest_ha) greatest_ha = sect_end;
342 }
343 if (greatest_ha < (word)GC_scratch_last_end_ptr)
344 greatest_ha = (word)GC_scratch_last_end_ptr;
345 for (;;) {
346
347 buf_ptr = parse_map_entry(buf_ptr, &start, &end, prot_buf, &maj_dev);
348 if (buf_ptr == NULL) return;
349
350 if (prot_buf[1] == 'w') {
351 /* This is a writable mapping. Add it to */
352 /* the root set unless it is already otherwise */
353 /* accounted for. */
354 if (start <= (word)GC_stackbottom && end >= (word)GC_stackbottom) {
355 /* Stack mapping; discard */
356 continue;
357 }
358# ifdef THREADS
359 if (GC_segment_is_thread_stack(start, end)) continue;
360# endif
361 /* The rest of this assumes that there is no mapping */
362 /* spanning the beginning of the data segment, or extending */
363 /* beyond the entire heap at both ends. */
364 /* Empirically these assumptions hold. */
365
366 if (start < (word)DATAEND && end > (word)DATAEND) {
367 /* Rld may use space at the end of the main data */
368 /* segment. Thus we add that in. */
369 start = (word)DATAEND;
370 }
371 if (start < least_ha && end > least_ha) {
372 end = least_ha;
373 }
374 if (start < greatest_ha && end > greatest_ha) {
375 start = greatest_ha;
376 }
377 if (start >= least_ha && end <= greatest_ha) continue;
378 GC_add_roots_inner((char *)start, (char *)end, TRUE);
379 }
380 }
381}
382
383/* We now take care of the main data segment ourselves: */
384GC_bool GC_register_main_static_data()
385{
386 return FALSE;
387}
388
389# define HAVE_REGISTER_MAIN_STATIC_DATA
390//
391// parse_map_entry parses an entry from /proc/self/maps so we can
392// locate all writable data segments that belong to shared libraries.
393// The format of one of these entries and the fields we care about
394// is as follows:
395// XXXXXXXX-XXXXXXXX r-xp 00000000 30:05 260537 name of mapping...\n
396// ^^^^^^^^ ^^^^^^^^ ^^^^ ^^
397// start end prot maj_dev
398// 0 9 18 32
399//
400// The parser is called with a pointer to the entry and the return value
401// is either NULL or is advanced to the next entry(the byte after the
402// trailing '\n'.)
403//
404#define OFFSET_MAP_START 0
405#define OFFSET_MAP_END 9
406#define OFFSET_MAP_PROT 18
407#define OFFSET_MAP_MAJDEV 32
408
409static char *parse_map_entry(char *buf_ptr, word *start, word *end,
410 char *prot_buf, unsigned int *maj_dev)
411{
412 int i;
413 unsigned int val;
414 char *tok;
415
416 if (buf_ptr == NULL || *buf_ptr == '\0') {
417 return NULL;
418 }
419
420 memcpy(prot_buf, buf_ptr+OFFSET_MAP_PROT, 4); // do the protections first
421 prot_buf[4] = '\0';
422
423 if (prot_buf[1] == 'w') { // we can skip all of this if it's not writable
424
425 tok = buf_ptr;
426 buf_ptr[OFFSET_MAP_START+8] = '\0';
427 *start = strtoul(tok, NULL, 16);
428
429 tok = buf_ptr+OFFSET_MAP_END;
430 buf_ptr[OFFSET_MAP_END+8] = '\0';
431 *end = strtoul(tok, NULL, 16);
432
433 buf_ptr += OFFSET_MAP_MAJDEV;
434 tok = buf_ptr;
435 while (*buf_ptr != ':') buf_ptr++;
436 *buf_ptr++ = '\0';
437 *maj_dev = strtoul(tok, NULL, 16);
438 }
439
440 while (*buf_ptr && *buf_ptr++ != '\n');
441
442 return buf_ptr;
443}
444
445#endif /* USE_PROC_FOR_LIBRARIES */
446
447#if !defined(USE_PROC_FOR_LIBRARIES)
448/* The following is the preferred way to walk dynamic libraries */
449/* For glibc 2.2.4+. Unfortunately, it doesn't work for older */
450/* versions. Thanks to Jakub Jelinek for most of the code. */
451
452# if defined(LINUX) /* Are others OK here, too? */ \
453 && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) \
454 || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && defined(DT_CONFIG)))
455
456/* We have the header files for a glibc that includes dl_iterate_phdr. */
457/* It may still not be available in the library on the target system. */
458/* Thus we also treat it as a weak symbol. */
459#define HAVE_DL_ITERATE_PHDR
460
461static int GC_register_dynlib_callback(info, size, ptr)
462 struct dl_phdr_info * info;
463 size_t size;
464 void * ptr;
465{
466 const ElfW(Phdr) * p;
467 char * start;
468 register int i;
469
470 /* Make sure struct dl_phdr_info is at least as big as we need. */
471 if (size < offsetof (struct dl_phdr_info, dlpi_phnum)
472 + sizeof (info->dlpi_phnum))
473 return -1;
474
475 p = info->dlpi_phdr;
476 for( i = 0; i < (int)(info->dlpi_phnum); ((i++),(p++)) ) {
477 switch( p->p_type ) {
478 case PT_LOAD:
479 {
480 if( !(p->p_flags & PF_W) ) break;
481 start = ((char *)(p->p_vaddr)) + info->dlpi_addr;
482 GC_add_roots_inner(start, start + p->p_memsz, TRUE);
483 }
484 break;
485 default:
486 break;
487 }
488 }
489
490 * (int *)ptr = 1; /* Signal that we were called */
491 return 0;
492}
493
494/* Return TRUE if we succeed, FALSE if dl_iterate_phdr wasn't there. */
495
496#pragma weak dl_iterate_phdr
497
498GC_bool GC_register_dynamic_libraries_dl_iterate_phdr()
499{
500 if (dl_iterate_phdr) {
501 int did_something = 0;
502 dl_iterate_phdr(GC_register_dynlib_callback, &did_something);
503 if (!did_something) {
504 /* dl_iterate_phdr may forget the static data segment in */
505 /* statically linked executables. */
506 GC_add_roots_inner(DATASTART, (char *)(DATAEND), TRUE);
507# if defined(DATASTART2)
508 GC_add_roots_inner(DATASTART2, (char *)(DATAEND2), TRUE);
509# endif
510 }
511 return TRUE;
512 } else {
513 return FALSE;
514 }
515}
516
517/* Do we need to separately register the main static data segment? */
518GC_bool GC_register_main_static_data()
519{
520 return (dl_iterate_phdr == 0);
521}
522
523#define HAVE_REGISTER_MAIN_STATIC_DATA
524
525# else /* !LINUX || version(glibc) < 2.2.4 */
526
527/* Dynamic loading code for Linux running ELF. Somewhat tested on
528 * Linux/x86, untested but hopefully should work on Linux/Alpha.
529 * This code was derived from the Solaris/ELF support. Thanks to
530 * whatever kind soul wrote that. - Patrick Bridges */
531
532/* This doesn't necessarily work in all cases, e.g. with preloaded
533 * dynamic libraries. */
534
535#if defined(NETBSD)
536# include <sys/exec_elf.h>
537#else
538# include <elf.h>
539#endif
540#include <link.h>
541
542# endif
543
544#ifdef __GNUC__
545# pragma weak _DYNAMIC
546#endif
547extern ElfW(Dyn) _DYNAMIC[];
548
549static struct link_map *
550GC_FirstDLOpenedLinkMap()
551{
552 ElfW(Dyn) *dp;
553 struct r_debug *r;
554 static struct link_map *cachedResult = 0;
555
556 if( _DYNAMIC == 0) {
557 return(0);
558 }
559 if( cachedResult == 0 ) {
560 int tag;
561 for( dp = _DYNAMIC; (tag = dp->d_tag) != 0; dp++ ) {
562 if( tag == DT_DEBUG ) {
563 struct link_map *lm
564 = ((struct r_debug *)(dp->d_un.d_ptr))->r_map;
565 if( lm != 0 ) cachedResult = lm->l_next; /* might be NIL */
566 break;
567 }
568 }
569 }
570 return cachedResult;
571}
572
573
574void GC_register_dynamic_libraries()
575{
576 struct link_map *lm;
577
578
579# ifdef HAVE_DL_ITERATE_PHDR
580 if (GC_register_dynamic_libraries_dl_iterate_phdr()) {
581 return;
582 }
583# endif
584 lm = GC_FirstDLOpenedLinkMap();
585 for (lm = GC_FirstDLOpenedLinkMap();
586 lm != (struct link_map *) 0; lm = lm->l_next)
587 {
588 ElfW(Ehdr) * e;
589 ElfW(Phdr) * p;
590 unsigned long offset;
591 char * start;
592 register int i;
593
594 e = (ElfW(Ehdr) *) lm->l_addr;
595 p = ((ElfW(Phdr) *)(((char *)(e)) + e->e_phoff));
596 offset = ((unsigned long)(lm->l_addr));
597 for( i = 0; i < (int)(e->e_phnum); ((i++),(p++)) ) {
598 switch( p->p_type ) {
599 case PT_LOAD:
600 {
601 if( !(p->p_flags & PF_W) ) break;
602 start = ((char *)(p->p_vaddr)) + offset;
603 GC_add_roots_inner(start, start + p->p_memsz, TRUE);
604 }
605 break;
606 default:
607 break;
608 }
609 }
610 }
611}
612
613#endif /* !USE_PROC_FOR_LIBRARIES */
614
615#endif /* LINUX */
616
617#if defined(IRIX5) || (defined(USE_PROC_FOR_LIBRARIES) && !defined(LINUX))
618
619#include <sys/procfs.h>
620#include <sys/stat.h>
621#include <fcntl.h>
622#include <elf.h>
623#include <errno.h>
624#include <signal.h> /* Only for the following test. */
625#ifndef _sigargs
626# define IRIX6
627#endif
628
629extern void * GC_roots_present();
630 /* The type is a lie, since the real type doesn't make sense here, */
631 /* and we only test for NULL. */
632
633/* We use /proc to track down all parts of the address space that are */
634/* mapped by the process, and throw out regions we know we shouldn't */
635/* worry about. This may also work under other SVR4 variants. */
636void GC_register_dynamic_libraries()
637{
638 static int fd = -1;
639 char buf[30];
640 static prmap_t * addr_map = 0;
641 static int current_sz = 0; /* Number of records currently in addr_map */
642 static int needed_sz; /* Required size of addr_map */
643 register int i;
644 register long flags;
645 register ptr_t start;
646 register ptr_t limit;
647 ptr_t heap_start = (ptr_t)HEAP_START;
648 ptr_t heap_end = heap_start;
649
650# ifdef SUNOS5DL
651# define MA_PHYS 0
652# endif /* SUNOS5DL */
653
654 if (fd < 0) {
655 sprintf(buf, "/proc/%d", getpid());
656 /* The above generates a lint complaint, since pid_t varies. */
657 /* It's unclear how to improve this. */
658 fd = open(buf, O_RDONLY);
659 if (fd < 0) {
660 ABORT("/proc open failed");
661 }
662 }
663 if (ioctl(fd, PIOCNMAP, &needed_sz) < 0) {
664 GC_err_printf2("fd = %d, errno = %d\n", fd, errno);
665 ABORT("/proc PIOCNMAP ioctl failed");
666 }
667 if (needed_sz >= current_sz) {
668 current_sz = needed_sz * 2 + 1;
669 /* Expansion, plus room for 0 record */
670 addr_map = (prmap_t *)GC_scratch_alloc((word)
671 (current_sz * sizeof(prmap_t)));
672 }
673 if (ioctl(fd, PIOCMAP, addr_map) < 0) {
674 GC_err_printf4("fd = %d, errno = %d, needed_sz = %d, addr_map = 0x%X\n",
675 fd, errno, needed_sz, addr_map);
676 ABORT("/proc PIOCMAP ioctl failed");
677 };
678 if (GC_n_heap_sects > 0) {
679 heap_end = GC_heap_sects[GC_n_heap_sects-1].hs_start
680 + GC_heap_sects[GC_n_heap_sects-1].hs_bytes;
681 if (heap_end < GC_scratch_last_end_ptr) heap_end = GC_scratch_last_end_ptr;
682 }
683 for (i = 0; i < needed_sz; i++) {
684 flags = addr_map[i].pr_mflags;
685 if ((flags & (MA_BREAK | MA_STACK | MA_PHYS)) != 0) goto irrelevant;
686 if ((flags & (MA_READ | MA_WRITE)) != (MA_READ | MA_WRITE))
687 goto irrelevant;
688 /* The latter test is empirically useless in very old Irix */
689 /* versions. Other than the */
690 /* main data and stack segments, everything appears to be */
691 /* mapped readable, writable, executable, and shared(!!). */
692 /* This makes no sense to me. - HB */
693 start = (ptr_t)(addr_map[i].pr_vaddr);
694 if (GC_roots_present(start)) goto irrelevant;
695 if (start < heap_end && start >= heap_start)
696 goto irrelevant;
697# ifdef MMAP_STACKS
698 if (GC_is_thread_stack(start)) goto irrelevant;
699# endif /* MMAP_STACKS */
700
701 limit = start + addr_map[i].pr_size;
702 /* The following seemed to be necessary for very old versions */
703 /* of Irix, but it has been reported to discard relevant */
704 /* segments under Irix 6.5. */
705# ifndef IRIX6
706 if (addr_map[i].pr_off == 0 && strncmp(start, ELFMAG, 4) == 0) {
707 /* Discard text segments, i.e. 0-offset mappings against */
708 /* executable files which appear to have ELF headers. */
709 caddr_t arg;
710 int obj;
711# define MAP_IRR_SZ 10
712 static ptr_t map_irr[MAP_IRR_SZ];
713 /* Known irrelevant map entries */
714 static int n_irr = 0;
715 struct stat buf;
716 register int i;
717
718 for (i = 0; i < n_irr; i++) {
719 if (map_irr[i] == start) goto irrelevant;
720 }
721 arg = (caddr_t)start;
722 obj = ioctl(fd, PIOCOPENM, &arg);
723 if (obj >= 0) {
724 fstat(obj, &buf);
725 close(obj);
726 if ((buf.st_mode & 0111) != 0) {
727 if (n_irr < MAP_IRR_SZ) {
728 map_irr[n_irr++] = start;
729 }
730 goto irrelevant;
731 }
732 }
733 }
734# endif /* !IRIX6 */
735 GC_add_roots_inner(start, limit, TRUE);
736 irrelevant: ;
737 }
738 /* Dont keep cached descriptor, for now. Some kernels don't like us */
739 /* to keep a /proc file descriptor around during kill -9. */
740 if (close(fd) < 0) ABORT("Couldnt close /proc file");
741 fd = -1;
742}
743
744# endif /* USE_PROC || IRIX5 */
745
746# if defined(MSWIN32) || defined(MSWINCE)
747
748# define WIN32_LEAN_AND_MEAN
749# define NOSERVICE
750# include <windows.h>
751# include <stdlib.h>
752
753 /* We traverse the entire address space and register all segments */
754 /* that could possibly have been written to. */
755
756 extern GC_bool GC_is_heap_base (ptr_t p);
757
758# ifdef GC_WIN32_THREADS
759 extern void GC_get_next_stack(char *start, char **lo, char **hi);
760 void GC_cond_add_roots(char *base, char * limit)
761 {
762 char * curr_base = base;
763 char * next_stack_lo;
764 char * next_stack_hi;
765
766 if (base == limit) return;
767 for(;;) {
768 GC_get_next_stack(curr_base, &next_stack_lo, &next_stack_hi);
769 if (next_stack_lo >= limit) break;
770 GC_add_roots_inner(curr_base, next_stack_lo, TRUE);
771 curr_base = next_stack_hi;
772 }
773 if (curr_base < limit) GC_add_roots_inner(curr_base, limit, TRUE);
774 }
775# else
776 void GC_cond_add_roots(char *base, char * limit)
777 {
778 char dummy;
779 char * stack_top
780 = (char *) ((word)(&dummy) & ~(GC_sysinfo.dwAllocationGranularity-1));
781 if (base == limit) return;
782 if (limit > stack_top && base < GC_stackbottom) {
783 /* Part of the stack; ignore it. */
784 return;
785 }
786 GC_add_roots_inner(base, limit, TRUE);
787 }
788# endif
789
790# ifdef MSWINCE
791 /* Do we need to separately register the main static data segment? */
792 GC_bool GC_register_main_static_data()
793 {
794 return FALSE;
795 }
796# else /* win32 */
797 extern GC_bool GC_no_win32_dlls;
798
799 GC_bool GC_register_main_static_data()
800 {
801 return GC_no_win32_dlls;
802 }
803# endif /* win32 */
804
805# define HAVE_REGISTER_MAIN_STATIC_DATA
806
807 void GC_register_dynamic_libraries()
808 {
809 MEMORY_BASIC_INFORMATION buf;
810 DWORD result;
811 DWORD protect;
812 LPVOID p;
813 char * base;
814 char * limit, * new_limit;
815
816# ifdef MSWIN32
817 if (GC_no_win32_dlls) return;
818# endif
819 base = limit = p = GC_sysinfo.lpMinimumApplicationAddress;
820# if defined(MSWINCE) && !defined(_WIN32_WCE_EMULATION)
821 /* Only the first 32 MB of address space belongs to the current process */
822 while (p < (LPVOID)0x02000000) {
823 result = VirtualQuery(p, &buf, sizeof(buf));
824 if (result == 0) {
825 /* Page is free; advance to the next possible allocation base */
826 new_limit = (char *)
827 (((DWORD) p + GC_sysinfo.dwAllocationGranularity)
828 & ~(GC_sysinfo.dwAllocationGranularity-1));
829 } else
830# else
831 while (p < GC_sysinfo.lpMaximumApplicationAddress) {
832 result = VirtualQuery(p, &buf, sizeof(buf));
833# endif
834 {
835 if (result != sizeof(buf)) {
836 ABORT("Weird VirtualQuery result");
837 }
838 new_limit = (char *)p + buf.RegionSize;
839 protect = buf.Protect;
840 if (buf.State == MEM_COMMIT
841 && (protect == PAGE_EXECUTE_READWRITE
842 || protect == PAGE_READWRITE)
843 && !GC_is_heap_base(buf.AllocationBase)) {
844 if ((char *)p != limit) {
845 GC_cond_add_roots(base, limit);
846 base = p;
847 }
848 limit = new_limit;
849 }
850 }
851 if (p > (LPVOID)new_limit /* overflow */) break;
852 p = (LPVOID)new_limit;
853 }
854 GC_cond_add_roots(base, limit);
855 }
856
857#endif /* MSWIN32 || MSWINCE */
858
859#if defined(ALPHA) && defined(OSF1)
860
861#include <loader.h>
862
863void GC_register_dynamic_libraries()
864{
865 int status;
866 ldr_process_t mypid;
867
868 /* module */
869 ldr_module_t moduleid = LDR_NULL_MODULE;
870 ldr_module_info_t moduleinfo;
871 size_t moduleinfosize = sizeof(moduleinfo);
872 size_t modulereturnsize;
873
874 /* region */
875 ldr_region_t region;
876 ldr_region_info_t regioninfo;
877 size_t regioninfosize = sizeof(regioninfo);
878 size_t regionreturnsize;
879
880 /* Obtain id of this process */
881 mypid = ldr_my_process();
882
883 /* For each module */
884 while (TRUE) {
885
886 /* Get the next (first) module */
887 status = ldr_next_module(mypid, &moduleid);
888
889 /* Any more modules? */
890 if (moduleid == LDR_NULL_MODULE)
891 break; /* No more modules */
892
893 /* Check status AFTER checking moduleid because */
894 /* of a bug in the non-shared ldr_next_module stub */
895 if (status != 0 ) {
896 GC_printf1("dynamic_load: status = %ld\n", (long)status);
897 {
898 extern char *sys_errlist[];
899 extern int sys_nerr;
900 extern int errno;
901 if (errno <= sys_nerr) {
902 GC_printf1("dynamic_load: %s\n", (long)sys_errlist[errno]);
903 } else {
904 GC_printf1("dynamic_load: %d\n", (long)errno);
905 }
906 }
907 ABORT("ldr_next_module failed");
908 }
909
910 /* Get the module information */
911 status = ldr_inq_module(mypid, moduleid, &moduleinfo,
912 moduleinfosize, &modulereturnsize);
913 if (status != 0 )
914 ABORT("ldr_inq_module failed");
915
916 /* is module for the main program (i.e. nonshared portion)? */
917 if (moduleinfo.lmi_flags & LDR_MAIN)
918 continue; /* skip the main module */
919
920# ifdef VERBOSE
921 GC_printf("---Module---\n");
922 GC_printf("Module ID = %16ld\n", moduleinfo.lmi_modid);
923 GC_printf("Count of regions = %16d\n", moduleinfo.lmi_nregion);
924 GC_printf("flags for module = %16lx\n", moduleinfo.lmi_flags);
925 GC_printf("pathname of module = \"%s\"\n", moduleinfo.lmi_name);
926# endif
927
928 /* For each region in this module */
929 for (region = 0; region < moduleinfo.lmi_nregion; region++) {
930
931 /* Get the region information */
932 status = ldr_inq_region(mypid, moduleid, region, &regioninfo,
933 regioninfosize, &regionreturnsize);
934 if (status != 0 )
935 ABORT("ldr_inq_region failed");
936
937 /* only process writable (data) regions */
938 if (! (regioninfo.lri_prot & LDR_W))
939 continue;
940
941# ifdef VERBOSE
942 GC_printf("--- Region ---\n");
943 GC_printf("Region number = %16ld\n",
944 regioninfo.lri_region_no);
945 GC_printf("Protection flags = %016x\n", regioninfo.lri_prot);
946 GC_printf("Virtual address = %16p\n", regioninfo.lri_vaddr);
947 GC_printf("Mapped address = %16p\n", regioninfo.lri_mapaddr);
948 GC_printf("Region size = %16ld\n", regioninfo.lri_size);
949 GC_printf("Region name = \"%s\"\n", regioninfo.lri_name);
950# endif
951
952 /* register region as a garbage collection root */
953 GC_add_roots_inner (
954 (char *)regioninfo.lri_mapaddr,
955 (char *)regioninfo.lri_mapaddr + regioninfo.lri_size,
956 TRUE);
957
958 }
959 }
960}
961#endif
962
963#if defined(HPUX)
964
965#include <errno.h>
966#include <dl.h>
967
968extern int errno;
969extern char *sys_errlist[];
970extern int sys_nerr;
971
972void GC_register_dynamic_libraries()
973{
974 int status;
975 int index = 1; /* Ordinal position in shared library search list */
976 struct shl_descriptor *shl_desc; /* Shared library info, see dl.h */
977
978 /* For each dynamic library loaded */
979 while (TRUE) {
980
981 /* Get info about next shared library */
982 status = shl_get(index, &shl_desc);
983
984 /* Check if this is the end of the list or if some error occured */
985 if (status != 0) {
986# ifdef GC_HPUX_THREADS
987 /* I've seen errno values of 0. The man page is not clear */
988 /* as to whether errno should get set on a -1 return. */
989 break;
990# else
991 if (errno == EINVAL) {
992 break; /* Moved past end of shared library list --> finished */
993 } else {
994 if (errno <= sys_nerr) {
995 GC_printf1("dynamic_load: %s\n", (long) sys_errlist[errno]);
996 } else {
997 GC_printf1("dynamic_load: %d\n", (long) errno);
998 }
999 ABORT("shl_get failed");
1000 }
1001# endif
1002 }
1003
1004# ifdef VERBOSE
1005 GC_printf0("---Shared library---\n");
1006 GC_printf1("\tfilename = \"%s\"\n", shl_desc->filename);
1007 GC_printf1("\tindex = %d\n", index);
1008 GC_printf1("\thandle = %08x\n",
1009 (unsigned long) shl_desc->handle);
1010 GC_printf1("\ttext seg. start = %08x\n", shl_desc->tstart);
1011 GC_printf1("\ttext seg. end = %08x\n", shl_desc->tend);
1012 GC_printf1("\tdata seg. start = %08x\n", shl_desc->dstart);
1013 GC_printf1("\tdata seg. end = %08x\n", shl_desc->dend);
1014 GC_printf1("\tref. count = %lu\n", shl_desc->ref_count);
1015# endif
1016
1017 /* register shared library's data segment as a garbage collection root */
1018 GC_add_roots_inner((char *) shl_desc->dstart,
1019 (char *) shl_desc->dend, TRUE);
1020
1021 index++;
1022 }
1023}
1024#endif /* HPUX */
1025
1026#ifdef RS6000
1027#pragma alloca
1028#include <sys/ldr.h>
1029#include <sys/errno.h>
1030void GC_register_dynamic_libraries()
1031{
1032 int len;
1033 char *ldibuf;
1034 int ldibuflen;
1035 struct ld_info *ldi;
1036
1037 ldibuf = alloca(ldibuflen = 8192);
1038
1039 while ( (len = loadquery(L_GETINFO,ldibuf,ldibuflen)) < 0) {
1040 if (errno != ENOMEM) {
1041 ABORT("loadquery failed");
1042 }
1043 ldibuf = alloca(ldibuflen *= 2);
1044 }
1045
1046 ldi = (struct ld_info *)ldibuf;
1047 while (ldi) {
1048 len = ldi->ldinfo_next;
1049 GC_add_roots_inner(
1050 ldi->ldinfo_dataorg,
1051 (unsigned long)ldi->ldinfo_dataorg
1052 + ldi->ldinfo_datasize,
1053 TRUE);
1054 ldi = len ? (struct ld_info *)((char *)ldi + len) : 0;
1055 }
1056}
1057#endif /* RS6000 */
1058
1059
1060
1061#else /* !DYNAMIC_LOADING */
1062
1063#ifdef PCR
1064
1065# include "il/PCR_IL.h"
1066# include "th/PCR_ThCtl.h"
1067# include "mm/PCR_MM.h"
1068
1069void GC_register_dynamic_libraries()
1070{
1071 /* Add new static data areas of dynamically loaded modules. */
1072 {
1073 PCR_IL_LoadedFile * p = PCR_IL_GetLastLoadedFile();
1074 PCR_IL_LoadedSegment * q;
1075
1076 /* Skip uncommited files */
1077 while (p != NIL && !(p -> lf_commitPoint)) {
1078 /* The loading of this file has not yet been committed */
1079 /* Hence its description could be inconsistent. */
1080 /* Furthermore, it hasn't yet been run. Hence its data */
1081 /* segments can't possibly reference heap allocated */
1082 /* objects. */
1083 p = p -> lf_prev;
1084 }
1085 for (; p != NIL; p = p -> lf_prev) {
1086 for (q = p -> lf_ls; q != NIL; q = q -> ls_next) {
1087 if ((q -> ls_flags & PCR_IL_SegFlags_Traced_MASK)
1088 == PCR_IL_SegFlags_Traced_on) {
1089 GC_add_roots_inner
1090 ((char *)(q -> ls_addr),
1091 (char *)(q -> ls_addr) + q -> ls_bytes,
1092 TRUE);
1093 }
1094 }
1095 }
1096 }
1097}
1098
1099
1100#else /* !PCR */
1101
1102void GC_register_dynamic_libraries(){}
1103
1104int GC_no_dynamic_loading;
1105
1106#endif /* !PCR */
1107
1108#endif /* !DYNAMIC_LOADING */
1109
1110#ifndef HAVE_REGISTER_MAIN_STATIC_DATA
1111
1112/* Do we need to separately register the main static data segment? */
1113GC_bool GC_register_main_static_data()
1114{
1115 return TRUE;
1116}
1117#endif /* HAVE_REGISTER_MAIN_STATIC_DATA */
1118
Note: See TracBrowser for help on using the repository browser.