Annotation of OpenXM_contrib2/asir2000/gc/dyn_load.c, Revision 1.6
1.1 noro 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: */
1.6 ! noro 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
1.4 noro 33: #if !defined(MACOS) && !defined(_WIN32_WCE)
1.1 noro 34: # include <sys/types.h>
35: #endif
1.4 noro 36: #include "private/gc_priv.h"
1.1 noro 37:
1.6 ! noro 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)
1.1 noro 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:
1.4 noro 52: #if (defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(MSWINCE)) \
53: && !defined(PCR)
1.1 noro 54: #if !defined(SUNOS4) && !defined(SUNOS5DL) && !defined(IRIX5) && \
1.4 noro 55: !defined(MSWIN32) && !defined(MSWINCE) && \
56: !(defined(ALPHA) && defined(OSF1)) && \
1.2 noro 57: !defined(HPUX) && !(defined(LINUX) && defined(__ELF__)) && \
1.6 ! noro 58: !defined(RS6000) && !defined(SCO_ELF) && !defined(DGUX) && \
! 59: !(defined(FREEBSD) && defined(__ELF__)) && \
! 60: !(defined(NETBSD) && defined(__ELF__)) && !defined(HURD)
1.1 noro 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:
1.6 ! noro 82: #if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \
! 83: (defined(FREEBSD) && defined(__ELF__)) || defined(DGUX) || \
! 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
1.1 noro 99:
100: #if defined(SUNOS5DL) && !defined(USE_PROC_FOR_LIBRARIES)
101:
102: #ifdef LINT
103: Elf32_Dyn _DYNAMIC;
104: #endif
105:
106: static struct link_map *
107: GC_FirstDLOpenedLinkMap()
108: {
1.6 ! noro 109: extern ElfW(Dyn) _DYNAMIC;
! 110: ElfW(Dyn) *dp;
1.1 noro 111: struct r_debug *r;
112: static struct link_map * cachedResult = 0;
1.6 ! noro 113: static ElfW(Dyn) *dynStructureAddr = 0;
1.1 noro 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);
1.6 ! noro 123: dynStructureAddr = (ElfW(Dyn)*)dlsym(startupSyms, "_DYNAMIC");
1.1 noro 124: }
125: # else
126: dynStructureAddr = &_DYNAMIC;
127: # endif
128:
129: if( dynStructureAddr == 0) {
130: return(0);
131: }
132: if( cachedResult == 0 ) {
133: int tag;
1.6 ! noro 134: for( dp = ((ElfW(Dyn) *)(&_DYNAMIC)); (tag = dp->d_tag) != 0; dp++ ) {
1.1 noro 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:
1.6 ! noro 148: /* BTL: added to fix circular dlopen definition if GC_SOLARIS_THREADS defined */
1.4 noro 149: # if defined(GC_must_restore_redefined_dlopen)
150: # define dlopen GC_dlopen
151: # endif
152:
1.1 noro 153: #if defined(SUNOS4) && !defined(USE_PROC_FOR_LIBRARIES)
154:
155: #ifdef LINT
156: struct link_dynamic _DYNAMIC;
157: #endif
158:
159: static struct link_map *
160: GC_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. */
172: static 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:
1.3 noro 193: # if defined(SUNOS4) || defined(SUNOS5DL)
194: /* Add dynamic library data sections to the root set. */
1.6 ! noro 195: # if !defined(PCR) && !defined(GC_SOLARIS_THREADS) && defined(THREADS)
1.3 noro 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:
1.1 noro 201: # ifndef USE_PROC_FOR_LIBRARIES
202: void 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
1.6 ! noro 220: ElfW(Ehdr) * e;
! 221: ElfW(Phdr) * p;
1.1 noro 222: unsigned long offset;
223: char * start;
224: register int i;
225:
1.6 ! noro 226: e = (ElfW(Ehdr) *) lm->l_addr;
! 227: p = ((ElfW(Phdr) *)(((char *)(e)) + e->e_phoff));
1.1 noro 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:
1.4 noro 266: #if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \
1.6 ! noro 267: (defined(FREEBSD) && defined(__ELF__)) || defined(DGUX) || \
! 268: (defined(NETBSD) && defined(__ELF__)) || defined(HURD)
1.4 noro 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:
281: extern 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:
285: static char *parse_map_entry(char *buf_ptr, word *start, word *end,
286: char *prot_buf, unsigned int *maj_dev);
287:
288: void 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: if (start <= datastart && end > datastart && maj_dev != 0) {
359: /* Main data segment; discard */
360: continue;
361: }
362: # ifdef THREADS
363: if (GC_segment_is_thread_stack(start, end)) continue;
364: # endif
365: /* The rest of this assumes that there is no mapping */
366: /* spanning the beginning of the data segment, or extending */
367: /* beyond the entire heap at both ends. */
368: /* Empirically these assumptions hold. */
369:
370: if (start < (word)DATAEND && end > (word)DATAEND) {
371: /* Rld may use space at the end of the main data */
372: /* segment. Thus we add that in. */
373: start = (word)DATAEND;
374: }
375: if (start < least_ha && end > least_ha) {
376: end = least_ha;
377: }
378: if (start < greatest_ha && end > greatest_ha) {
379: start = greatest_ha;
380: }
381: if (start >= least_ha && end <= greatest_ha) continue;
382: GC_add_roots_inner((char *)start, (char *)end, TRUE);
383: }
384: }
385: }
386:
387: //
388: // parse_map_entry parses an entry from /proc/self/maps so we can
389: // locate all writable data segments that belong to shared libraries.
390: // The format of one of these entries and the fields we care about
391: // is as follows:
392: // XXXXXXXX-XXXXXXXX r-xp 00000000 30:05 260537 name of mapping...\n
393: // ^^^^^^^^ ^^^^^^^^ ^^^^ ^^
394: // start end prot maj_dev
395: // 0 9 18 32
396: //
397: // The parser is called with a pointer to the entry and the return value
398: // is either NULL or is advanced to the next entry(the byte after the
399: // trailing '\n'.)
400: //
401: #define OFFSET_MAP_START 0
402: #define OFFSET_MAP_END 9
403: #define OFFSET_MAP_PROT 18
404: #define OFFSET_MAP_MAJDEV 32
405:
406: static char *parse_map_entry(char *buf_ptr, word *start, word *end,
407: char *prot_buf, unsigned int *maj_dev)
408: {
409: int i;
410: unsigned int val;
411: char *tok;
412:
413: if (buf_ptr == NULL || *buf_ptr == '\0') {
414: return NULL;
415: }
416:
417: memcpy(prot_buf, buf_ptr+OFFSET_MAP_PROT, 4); // do the protections first
418: prot_buf[4] = '\0';
419:
420: if (prot_buf[1] == 'w') { // we can skip all of this if it's not writable
421:
422: tok = buf_ptr;
423: buf_ptr[OFFSET_MAP_START+8] = '\0';
424: *start = strtoul(tok, NULL, 16);
425:
426: tok = buf_ptr+OFFSET_MAP_END;
427: buf_ptr[OFFSET_MAP_END+8] = '\0';
428: *end = strtoul(tok, NULL, 16);
429:
430: buf_ptr += OFFSET_MAP_MAJDEV;
431: tok = buf_ptr;
432: while (*buf_ptr != ':') buf_ptr++;
433: *buf_ptr++ = '\0';
434: *maj_dev = strtoul(tok, NULL, 16);
435: }
436:
437: while (*buf_ptr && *buf_ptr++ != '\n');
438:
439: return buf_ptr;
440: }
441:
1.6 ! noro 442: #endif /* USE_PROC_FOR_LIBRARIES */
! 443:
! 444: #if !defined(USE_PROC_FOR_LIBRARIES)
! 445: /* The following is the preferred way to walk dynamic libraries */
! 446: /* For glibc 2.2.4+. Unfortunately, it doesn't work for older */
! 447: /* versions. Thanks to Jakub Jelinek for most of the code. */
! 448:
! 449: # if defined(LINUX) /* Are others OK here, too? */ \
! 450: && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) \
! 451: || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && defined(DT_CONFIG)))
! 452:
! 453: /* We have the header files for a glibc that includes dl_iterate_phdr. */
! 454: /* It may still not be available in the library on the target system. */
! 455: /* Thus we also treat it as a weak symbol. */
! 456: #define HAVE_DL_ITERATE_PHDR
! 457:
! 458: static int GC_register_dynlib_callback(info, size, ptr)
! 459: struct dl_phdr_info * info;
! 460: size_t size;
! 461: void * ptr;
! 462: {
! 463: const ElfW(Phdr) * p;
! 464: char * start;
! 465: register int i;
! 466:
! 467: /* Make sure struct dl_phdr_info is at least as big as we need. */
! 468: if (size < offsetof (struct dl_phdr_info, dlpi_phnum)
! 469: + sizeof (info->dlpi_phnum))
! 470: return -1;
! 471:
! 472: /* Skip the first object - it is the main program. */
! 473: if (*(int *)ptr == 0)
! 474: {
! 475: *(int *)ptr = 1;
! 476: return 0;
! 477: }
! 478:
! 479: p = info->dlpi_phdr;
! 480: for( i = 0; i < (int)(info->dlpi_phnum); ((i++),(p++)) ) {
! 481: switch( p->p_type ) {
! 482: case PT_LOAD:
! 483: {
! 484: if( !(p->p_flags & PF_W) ) break;
! 485: start = ((char *)(p->p_vaddr)) + info->dlpi_addr;
! 486: GC_add_roots_inner(start, start + p->p_memsz, TRUE);
! 487: }
! 488: break;
! 489: default:
! 490: break;
! 491: }
! 492: }
! 493:
! 494: return 0;
! 495: }
! 496:
! 497: /* Return TRUE if we succeed, FALSE if dl_iterate_phdr wasn't there. */
! 498:
! 499: #pragma weak dl_iterate_phdr
! 500:
! 501: GC_bool GC_register_dynamic_libraries_dl_iterate_phdr()
! 502: {
! 503: int tmp = 0;
! 504:
! 505: if (dl_iterate_phdr) {
! 506: dl_iterate_phdr(GC_register_dynlib_callback, &tmp);
! 507: return TRUE;
! 508: } else {
! 509: return FALSE;
! 510: }
! 511: }
! 512:
! 513: # else /* !LINUX || version(glibc) < 2.2.4 */
1.1 noro 514:
515: /* Dynamic loading code for Linux running ELF. Somewhat tested on
516: * Linux/x86, untested but hopefully should work on Linux/Alpha.
517: * This code was derived from the Solaris/ELF support. Thanks to
518: * whatever kind soul wrote that. - Patrick Bridges */
519:
1.6 ! noro 520: /* This doesn't necessarily work in all cases, e.g. with preloaded
! 521: * dynamic libraries. */
! 522:
1.4 noro 523: #if defined(NETBSD)
524: # include <sys/exec_elf.h>
525: #else
526: # include <elf.h>
527: #endif
1.1 noro 528: #include <link.h>
529:
1.6 ! noro 530: # endif
! 531:
! 532: #ifdef __GNUC__
! 533: # pragma weak _DYNAMIC
! 534: #endif
! 535: extern ElfW(Dyn) _DYNAMIC[];
1.1 noro 536:
537: static struct link_map *
538: GC_FirstDLOpenedLinkMap()
539: {
540: ElfW(Dyn) *dp;
541: struct r_debug *r;
542: static struct link_map *cachedResult = 0;
543:
544: if( _DYNAMIC == 0) {
545: return(0);
546: }
547: if( cachedResult == 0 ) {
548: int tag;
549: for( dp = _DYNAMIC; (tag = dp->d_tag) != 0; dp++ ) {
550: if( tag == DT_DEBUG ) {
551: struct link_map *lm
552: = ((struct r_debug *)(dp->d_un.d_ptr))->r_map;
553: if( lm != 0 ) cachedResult = lm->l_next; /* might be NIL */
554: break;
555: }
556: }
557: }
558: return cachedResult;
559: }
560:
561:
562: void GC_register_dynamic_libraries()
563: {
1.6 ! noro 564: struct link_map *lm;
1.1 noro 565:
566:
1.6 ! noro 567: # ifdef HAVE_DL_ITERATE_PHDR
! 568: if (GC_register_dynamic_libraries_dl_iterate_phdr()) {
! 569: return;
! 570: }
! 571: # endif
! 572: lm = GC_FirstDLOpenedLinkMap();
1.1 noro 573: for (lm = GC_FirstDLOpenedLinkMap();
574: lm != (struct link_map *) 0; lm = lm->l_next)
575: {
576: ElfW(Ehdr) * e;
577: ElfW(Phdr) * p;
578: unsigned long offset;
579: char * start;
580: register int i;
581:
582: e = (ElfW(Ehdr) *) lm->l_addr;
583: p = ((ElfW(Phdr) *)(((char *)(e)) + e->e_phoff));
584: offset = ((unsigned long)(lm->l_addr));
585: for( i = 0; i < (int)(e->e_phnum); ((i++),(p++)) ) {
586: switch( p->p_type ) {
587: case PT_LOAD:
588: {
589: if( !(p->p_flags & PF_W) ) break;
590: start = ((char *)(p->p_vaddr)) + offset;
591: GC_add_roots_inner(start, start + p->p_memsz, TRUE);
592: }
593: break;
594: default:
595: break;
596: }
597: }
598: }
599: }
600:
1.4 noro 601: #endif /* !USE_PROC_FOR_LIBRARIES */
602:
603: #endif /* LINUX */
1.1 noro 604:
1.4 noro 605: #if defined(IRIX5) || (defined(USE_PROC_FOR_LIBRARIES) && !defined(LINUX))
1.1 noro 606:
607: #include <sys/procfs.h>
608: #include <sys/stat.h>
609: #include <fcntl.h>
610: #include <elf.h>
611: #include <errno.h>
1.6 ! noro 612: #include <signal.h> /* Only for the following test. */
! 613: #ifndef _sigargs
! 614: # define IRIX6
! 615: #endif
1.1 noro 616:
617: extern void * GC_roots_present();
618: /* The type is a lie, since the real type doesn't make sense here, */
619: /* and we only test for NULL. */
620:
621:
622: /* We use /proc to track down all parts of the address space that are */
623: /* mapped by the process, and throw out regions we know we shouldn't */
624: /* worry about. This may also work under other SVR4 variants. */
625: void GC_register_dynamic_libraries()
626: {
627: static int fd = -1;
628: char buf[30];
629: static prmap_t * addr_map = 0;
630: static int current_sz = 0; /* Number of records currently in addr_map */
631: static int needed_sz; /* Required size of addr_map */
632: register int i;
633: register long flags;
634: register ptr_t start;
635: register ptr_t limit;
636: ptr_t heap_start = (ptr_t)HEAP_START;
637: ptr_t heap_end = heap_start;
638:
639: # ifdef SUNOS5DL
640: # define MA_PHYS 0
641: # endif /* SUNOS5DL */
642:
643: if (fd < 0) {
644: sprintf(buf, "/proc/%d", getpid());
645: /* The above generates a lint complaint, since pid_t varies. */
646: /* It's unclear how to improve this. */
647: fd = open(buf, O_RDONLY);
648: if (fd < 0) {
649: ABORT("/proc open failed");
650: }
651: }
652: if (ioctl(fd, PIOCNMAP, &needed_sz) < 0) {
653: GC_err_printf2("fd = %d, errno = %d\n", fd, errno);
654: ABORT("/proc PIOCNMAP ioctl failed");
655: }
656: if (needed_sz >= current_sz) {
657: current_sz = needed_sz * 2 + 1;
658: /* Expansion, plus room for 0 record */
659: addr_map = (prmap_t *)GC_scratch_alloc((word)
660: (current_sz * sizeof(prmap_t)));
661: }
662: if (ioctl(fd, PIOCMAP, addr_map) < 0) {
663: GC_err_printf4("fd = %d, errno = %d, needed_sz = %d, addr_map = 0x%X\n",
664: fd, errno, needed_sz, addr_map);
665: ABORT("/proc PIOCMAP ioctl failed");
666: };
667: if (GC_n_heap_sects > 0) {
668: heap_end = GC_heap_sects[GC_n_heap_sects-1].hs_start
669: + GC_heap_sects[GC_n_heap_sects-1].hs_bytes;
670: if (heap_end < GC_scratch_last_end_ptr) heap_end = GC_scratch_last_end_ptr;
671: }
672: for (i = 0; i < needed_sz; i++) {
673: flags = addr_map[i].pr_mflags;
674: if ((flags & (MA_BREAK | MA_STACK | MA_PHYS)) != 0) goto irrelevant;
675: if ((flags & (MA_READ | MA_WRITE)) != (MA_READ | MA_WRITE))
676: goto irrelevant;
1.6 ! noro 677: /* The latter test is empirically useless in very old Irix */
! 678: /* versions. Other than the */
1.1 noro 679: /* main data and stack segments, everything appears to be */
680: /* mapped readable, writable, executable, and shared(!!). */
681: /* This makes no sense to me. - HB */
682: start = (ptr_t)(addr_map[i].pr_vaddr);
683: if (GC_roots_present(start)) goto irrelevant;
684: if (start < heap_end && start >= heap_start)
685: goto irrelevant;
686: # ifdef MMAP_STACKS
687: if (GC_is_thread_stack(start)) goto irrelevant;
688: # endif /* MMAP_STACKS */
689:
690: limit = start + addr_map[i].pr_size;
1.6 ! noro 691: /* The following seemed to be necessary for very old versions */
! 692: /* of Irix, but it has been reported to discard relevant */
! 693: /* segments under Irix 6.5. */
! 694: # ifndef IRIX6
! 695: if (addr_map[i].pr_off == 0 && strncmp(start, ELFMAG, 4) == 0) {
1.1 noro 696: /* Discard text segments, i.e. 0-offset mappings against */
697: /* executable files which appear to have ELF headers. */
698: caddr_t arg;
699: int obj;
700: # define MAP_IRR_SZ 10
701: static ptr_t map_irr[MAP_IRR_SZ];
702: /* Known irrelevant map entries */
703: static int n_irr = 0;
704: struct stat buf;
705: register int i;
706:
707: for (i = 0; i < n_irr; i++) {
708: if (map_irr[i] == start) goto irrelevant;
709: }
710: arg = (caddr_t)start;
711: obj = ioctl(fd, PIOCOPENM, &arg);
712: if (obj >= 0) {
713: fstat(obj, &buf);
714: close(obj);
715: if ((buf.st_mode & 0111) != 0) {
716: if (n_irr < MAP_IRR_SZ) {
717: map_irr[n_irr++] = start;
718: }
719: goto irrelevant;
720: }
721: }
1.6 ! noro 722: }
! 723: # endif /* !IRIX6 */
1.1 noro 724: GC_add_roots_inner(start, limit, TRUE);
725: irrelevant: ;
726: }
727: /* Dont keep cached descriptor, for now. Some kernels don't like us */
728: /* to keep a /proc file descriptor around during kill -9. */
729: if (close(fd) < 0) ABORT("Couldnt close /proc file");
730: fd = -1;
731: }
732:
733: # endif /* USE_PROC || IRIX5 */
734:
1.4 noro 735: # if defined(MSWIN32) || defined(MSWINCE)
1.1 noro 736:
737: # define WIN32_LEAN_AND_MEAN
738: # define NOSERVICE
739: # include <windows.h>
740: # include <stdlib.h>
741:
742: /* We traverse the entire address space and register all segments */
743: /* that could possibly have been written to. */
744:
745: extern GC_bool GC_is_heap_base (ptr_t p);
746:
1.6 ! noro 747: # ifdef GC_WIN32_THREADS
1.1 noro 748: extern void GC_get_next_stack(char *start, char **lo, char **hi);
1.4 noro 749: void GC_cond_add_roots(char *base, char * limit)
750: {
751: char * curr_base = base;
752: char * next_stack_lo;
753: char * next_stack_hi;
754:
755: if (base == limit) return;
756: for(;;) {
757: GC_get_next_stack(curr_base, &next_stack_lo, &next_stack_hi);
758: if (next_stack_lo >= limit) break;
759: GC_add_roots_inner(curr_base, next_stack_lo, TRUE);
760: curr_base = next_stack_hi;
761: }
762: if (curr_base < limit) GC_add_roots_inner(curr_base, limit, TRUE);
763: }
764: # else
765: void GC_cond_add_roots(char *base, char * limit)
1.1 noro 766: {
1.4 noro 767: char dummy;
768: char * stack_top
769: = (char *) ((word)(&dummy) & ~(GC_sysinfo.dwAllocationGranularity-1));
770: if (base == limit) return;
771: if (limit > stack_top && base < GC_stackbottom) {
772: /* Part of the stack; ignore it. */
773: return;
774: }
775: GC_add_roots_inner(base, limit, TRUE);
1.1 noro 776: }
1.4 noro 777: # endif
778:
779: # ifndef MSWINCE
1.6 ! noro 780: extern GC_bool GC_no_win32_dlls;
1.4 noro 781: # endif
1.1 noro 782:
783: void GC_register_dynamic_libraries()
784: {
785: MEMORY_BASIC_INFORMATION buf;
786: DWORD result;
787: DWORD protect;
788: LPVOID p;
789: char * base;
790: char * limit, * new_limit;
1.4 noro 791:
792: # ifdef MSWIN32
1.6 ! noro 793: if (GC_no_win32_dlls) return;
1.4 noro 794: # endif
795: base = limit = p = GC_sysinfo.lpMinimumApplicationAddress;
796: # if defined(MSWINCE) && !defined(_WIN32_WCE_EMULATION)
797: /* Only the first 32 MB of address space belongs to the current process */
798: while (p < (LPVOID)0x02000000) {
799: result = VirtualQuery(p, &buf, sizeof(buf));
800: if (result == 0) {
801: /* Page is free; advance to the next possible allocation base */
802: new_limit = (char *)
803: (((DWORD) p + GC_sysinfo.dwAllocationGranularity)
804: & ~(GC_sysinfo.dwAllocationGranularity-1));
805: } else
806: # else
807: while (p < GC_sysinfo.lpMaximumApplicationAddress) {
1.1 noro 808: result = VirtualQuery(p, &buf, sizeof(buf));
1.4 noro 809: # endif
810: {
811: if (result != sizeof(buf)) {
812: ABORT("Weird VirtualQuery result");
813: }
814: new_limit = (char *)p + buf.RegionSize;
815: protect = buf.Protect;
816: if (buf.State == MEM_COMMIT
817: && (protect == PAGE_EXECUTE_READWRITE
818: || protect == PAGE_READWRITE)
819: && !GC_is_heap_base(buf.AllocationBase)) {
820: if ((char *)p != limit) {
821: GC_cond_add_roots(base, limit);
822: base = p;
823: }
824: limit = new_limit;
825: }
826: }
1.1 noro 827: if (p > (LPVOID)new_limit /* overflow */) break;
828: p = (LPVOID)new_limit;
829: }
830: GC_cond_add_roots(base, limit);
831: }
832:
1.4 noro 833: #endif /* MSWIN32 || MSWINCE */
834:
1.1 noro 835: #if defined(ALPHA) && defined(OSF1)
836:
837: #include <loader.h>
838:
839: void GC_register_dynamic_libraries()
840: {
841: int status;
842: ldr_process_t mypid;
843:
844: /* module */
845: ldr_module_t moduleid = LDR_NULL_MODULE;
846: ldr_module_info_t moduleinfo;
847: size_t moduleinfosize = sizeof(moduleinfo);
848: size_t modulereturnsize;
849:
850: /* region */
851: ldr_region_t region;
852: ldr_region_info_t regioninfo;
853: size_t regioninfosize = sizeof(regioninfo);
854: size_t regionreturnsize;
855:
856: /* Obtain id of this process */
857: mypid = ldr_my_process();
858:
859: /* For each module */
860: while (TRUE) {
861:
862: /* Get the next (first) module */
863: status = ldr_next_module(mypid, &moduleid);
864:
865: /* Any more modules? */
866: if (moduleid == LDR_NULL_MODULE)
867: break; /* No more modules */
868:
869: /* Check status AFTER checking moduleid because */
870: /* of a bug in the non-shared ldr_next_module stub */
871: if (status != 0 ) {
872: GC_printf1("dynamic_load: status = %ld\n", (long)status);
873: {
874: extern char *sys_errlist[];
875: extern int sys_nerr;
876: extern int errno;
877: if (errno <= sys_nerr) {
878: GC_printf1("dynamic_load: %s\n", (long)sys_errlist[errno]);
879: } else {
880: GC_printf1("dynamic_load: %d\n", (long)errno);
881: }
882: }
883: ABORT("ldr_next_module failed");
884: }
885:
886: /* Get the module information */
887: status = ldr_inq_module(mypid, moduleid, &moduleinfo,
888: moduleinfosize, &modulereturnsize);
889: if (status != 0 )
890: ABORT("ldr_inq_module failed");
891:
892: /* is module for the main program (i.e. nonshared portion)? */
893: if (moduleinfo.lmi_flags & LDR_MAIN)
894: continue; /* skip the main module */
895:
896: # ifdef VERBOSE
897: GC_printf("---Module---\n");
898: GC_printf("Module ID = %16ld\n", moduleinfo.lmi_modid);
899: GC_printf("Count of regions = %16d\n", moduleinfo.lmi_nregion);
900: GC_printf("flags for module = %16lx\n", moduleinfo.lmi_flags);
901: GC_printf("pathname of module = \"%s\"\n", moduleinfo.lmi_name);
902: # endif
903:
904: /* For each region in this module */
905: for (region = 0; region < moduleinfo.lmi_nregion; region++) {
906:
907: /* Get the region information */
908: status = ldr_inq_region(mypid, moduleid, region, ®ioninfo,
909: regioninfosize, ®ionreturnsize);
910: if (status != 0 )
911: ABORT("ldr_inq_region failed");
912:
913: /* only process writable (data) regions */
914: if (! (regioninfo.lri_prot & LDR_W))
915: continue;
916:
917: # ifdef VERBOSE
918: GC_printf("--- Region ---\n");
919: GC_printf("Region number = %16ld\n",
920: regioninfo.lri_region_no);
921: GC_printf("Protection flags = %016x\n", regioninfo.lri_prot);
922: GC_printf("Virtual address = %16p\n", regioninfo.lri_vaddr);
923: GC_printf("Mapped address = %16p\n", regioninfo.lri_mapaddr);
924: GC_printf("Region size = %16ld\n", regioninfo.lri_size);
925: GC_printf("Region name = \"%s\"\n", regioninfo.lri_name);
926: # endif
927:
928: /* register region as a garbage collection root */
929: GC_add_roots_inner (
930: (char *)regioninfo.lri_mapaddr,
931: (char *)regioninfo.lri_mapaddr + regioninfo.lri_size,
932: TRUE);
933:
934: }
935: }
936: }
937: #endif
938:
1.2 noro 939: #if defined(HPUX)
1.1 noro 940:
941: #include <errno.h>
942: #include <dl.h>
943:
944: extern int errno;
945: extern char *sys_errlist[];
946: extern int sys_nerr;
947:
948: void GC_register_dynamic_libraries()
949: {
950: int status;
951: int index = 1; /* Ordinal position in shared library search list */
952: struct shl_descriptor *shl_desc; /* Shared library info, see dl.h */
953:
954: /* For each dynamic library loaded */
955: while (TRUE) {
956:
957: /* Get info about next shared library */
958: status = shl_get(index, &shl_desc);
959:
960: /* Check if this is the end of the list or if some error occured */
961: if (status != 0) {
1.6 ! noro 962: # ifdef GC_HPUX_THREADS
1.2 noro 963: /* I've seen errno values of 0. The man page is not clear */
964: /* as to whether errno should get set on a -1 return. */
965: break;
966: # else
1.1 noro 967: if (errno == EINVAL) {
968: break; /* Moved past end of shared library list --> finished */
969: } else {
970: if (errno <= sys_nerr) {
971: GC_printf1("dynamic_load: %s\n", (long) sys_errlist[errno]);
972: } else {
973: GC_printf1("dynamic_load: %d\n", (long) errno);
974: }
975: ABORT("shl_get failed");
976: }
1.2 noro 977: # endif
1.1 noro 978: }
979:
980: # ifdef VERBOSE
981: GC_printf0("---Shared library---\n");
982: GC_printf1("\tfilename = \"%s\"\n", shl_desc->filename);
983: GC_printf1("\tindex = %d\n", index);
984: GC_printf1("\thandle = %08x\n",
985: (unsigned long) shl_desc->handle);
986: GC_printf1("\ttext seg. start = %08x\n", shl_desc->tstart);
987: GC_printf1("\ttext seg. end = %08x\n", shl_desc->tend);
988: GC_printf1("\tdata seg. start = %08x\n", shl_desc->dstart);
989: GC_printf1("\tdata seg. end = %08x\n", shl_desc->dend);
990: GC_printf1("\tref. count = %lu\n", shl_desc->ref_count);
991: # endif
992:
993: /* register shared library's data segment as a garbage collection root */
994: GC_add_roots_inner((char *) shl_desc->dstart,
995: (char *) shl_desc->dend, TRUE);
996:
997: index++;
998: }
999: }
1.2 noro 1000: #endif /* HPUX */
1.1 noro 1001:
1002: #ifdef RS6000
1003: #pragma alloca
1004: #include <sys/ldr.h>
1005: #include <sys/errno.h>
1006: void GC_register_dynamic_libraries()
1007: {
1008: int len;
1009: char *ldibuf;
1010: int ldibuflen;
1011: struct ld_info *ldi;
1012:
1013: ldibuf = alloca(ldibuflen = 8192);
1014:
1015: while ( (len = loadquery(L_GETINFO,ldibuf,ldibuflen)) < 0) {
1016: if (errno != ENOMEM) {
1017: ABORT("loadquery failed");
1018: }
1019: ldibuf = alloca(ldibuflen *= 2);
1020: }
1021:
1022: ldi = (struct ld_info *)ldibuf;
1023: while (ldi) {
1024: len = ldi->ldinfo_next;
1025: GC_add_roots_inner(
1026: ldi->ldinfo_dataorg,
1027: (unsigned long)ldi->ldinfo_dataorg
1028: + ldi->ldinfo_datasize,
1029: TRUE);
1030: ldi = len ? (struct ld_info *)((char *)ldi + len) : 0;
1031: }
1032: }
1033: #endif /* RS6000 */
1034:
1035:
1036:
1037: #else /* !DYNAMIC_LOADING */
1038:
1039: #ifdef PCR
1040:
1041: # include "il/PCR_IL.h"
1042: # include "th/PCR_ThCtl.h"
1043: # include "mm/PCR_MM.h"
1044:
1045: void GC_register_dynamic_libraries()
1046: {
1047: /* Add new static data areas of dynamically loaded modules. */
1048: {
1049: PCR_IL_LoadedFile * p = PCR_IL_GetLastLoadedFile();
1050: PCR_IL_LoadedSegment * q;
1051:
1052: /* Skip uncommited files */
1053: while (p != NIL && !(p -> lf_commitPoint)) {
1054: /* The loading of this file has not yet been committed */
1055: /* Hence its description could be inconsistent. */
1056: /* Furthermore, it hasn't yet been run. Hence its data */
1057: /* segments can't possibly reference heap allocated */
1058: /* objects. */
1059: p = p -> lf_prev;
1060: }
1061: for (; p != NIL; p = p -> lf_prev) {
1062: for (q = p -> lf_ls; q != NIL; q = q -> ls_next) {
1063: if ((q -> ls_flags & PCR_IL_SegFlags_Traced_MASK)
1064: == PCR_IL_SegFlags_Traced_on) {
1065: GC_add_roots_inner
1066: ((char *)(q -> ls_addr),
1067: (char *)(q -> ls_addr) + q -> ls_bytes,
1068: TRUE);
1069: }
1070: }
1071: }
1072: }
1073: }
1074:
1075:
1076: #else /* !PCR */
1077:
1078: void GC_register_dynamic_libraries(){}
1079:
1080: int GC_no_dynamic_loading;
1081:
1082: #endif /* !PCR */
1083: #endif /* !DYNAMIC_LOADING */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>