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