]>
Commit | Line | Data |
---|---|---|
21a6f56d TT |
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 | #ifndef MACOS | |
30 | # include <sys/types.h> | |
31 | #endif | |
32 | #include "gc_priv.h" | |
33 | ||
34 | /* BTL: avoid circular redefinition of dlopen if SOLARIS_THREADS defined */ | |
35 | # if defined(SOLARIS_THREADS) && defined(dlopen) | |
36 | /* To support threads in Solaris, gc.h interposes on dlopen by */ | |
37 | /* defining "dlopen" to be "GC_dlopen", which is implemented below. */ | |
38 | /* However, both GC_FirstDLOpenedLinkMap() and GC_dlopen() use the */ | |
39 | /* real system dlopen() in their implementation. We first remove */ | |
40 | /* gc.h's dlopen definition and restore it later, after GC_dlopen(). */ | |
41 | # undef dlopen | |
42 | # define GC_must_restore_redefined_dlopen | |
43 | # else | |
44 | # undef GC_must_restore_redefined_dlopen | |
45 | # endif | |
46 | ||
47 | #if (defined(DYNAMIC_LOADING) || defined(MSWIN32)) && !defined(PCR) | |
48 | #if !defined(SUNOS4) && !defined(SUNOS5DL) && !defined(IRIX5) && \ | |
49 | !defined(MSWIN32) && !(defined(ALPHA) && defined(OSF1)) && \ | |
20bbd3cd | 50 | !defined(HPUX) && !(defined(LINUX) && defined(__ELF__)) && \ |
21a6f56d TT |
51 | !defined(RS6000) && !defined(SCO_ELF) |
52 | --> We only know how to find data segments of dynamic libraries for the | |
53 | --> above. Additional SVR4 variants might not be too | |
54 | --> hard to add. | |
55 | #endif | |
56 | ||
57 | #include <stdio.h> | |
58 | #ifdef SUNOS5DL | |
59 | # include <sys/elf.h> | |
60 | # include <dlfcn.h> | |
61 | # include <link.h> | |
62 | #endif | |
63 | #ifdef SUNOS4 | |
64 | # include <dlfcn.h> | |
65 | # include <link.h> | |
66 | # include <a.out.h> | |
67 | /* struct link_map field overrides */ | |
68 | # define l_next lm_next | |
69 | # define l_addr lm_addr | |
70 | # define l_name lm_name | |
71 | #endif | |
72 | ||
73 | ||
74 | #if defined(SUNOS5DL) && !defined(USE_PROC_FOR_LIBRARIES) | |
75 | ||
76 | #ifdef LINT | |
77 | Elf32_Dyn _DYNAMIC; | |
78 | #endif | |
79 | ||
80 | static struct link_map * | |
81 | GC_FirstDLOpenedLinkMap() | |
82 | { | |
83 | extern Elf32_Dyn _DYNAMIC; | |
84 | Elf32_Dyn *dp; | |
85 | struct r_debug *r; | |
86 | static struct link_map * cachedResult = 0; | |
87 | static Elf32_Dyn *dynStructureAddr = 0; | |
88 | /* BTL: added to avoid Solaris 5.3 ld.so _DYNAMIC bug */ | |
89 | ||
90 | # ifdef SUNOS53_SHARED_LIB | |
91 | /* BTL: Avoid the Solaris 5.3 bug that _DYNAMIC isn't being set */ | |
92 | /* up properly in dynamically linked .so's. This means we have */ | |
93 | /* to use its value in the set of original object files loaded */ | |
94 | /* at program startup. */ | |
95 | if( dynStructureAddr == 0 ) { | |
96 | void* startupSyms = dlopen(0, RTLD_LAZY); | |
97 | dynStructureAddr = (Elf32_Dyn*)dlsym(startupSyms, "_DYNAMIC"); | |
98 | } | |
99 | # else | |
100 | dynStructureAddr = &_DYNAMIC; | |
101 | # endif | |
102 | ||
103 | if( dynStructureAddr == 0) { | |
104 | return(0); | |
105 | } | |
106 | if( cachedResult == 0 ) { | |
107 | int tag; | |
108 | for( dp = ((Elf32_Dyn *)(&_DYNAMIC)); (tag = dp->d_tag) != 0; dp++ ) { | |
109 | if( tag == DT_DEBUG ) { | |
110 | struct link_map *lm | |
111 | = ((struct r_debug *)(dp->d_un.d_ptr))->r_map; | |
112 | if( lm != 0 ) cachedResult = lm->l_next; /* might be NIL */ | |
113 | break; | |
114 | } | |
115 | } | |
116 | } | |
117 | return cachedResult; | |
118 | } | |
119 | ||
120 | #endif /* SUNOS5DL ... */ | |
121 | ||
122 | #if defined(SUNOS4) && !defined(USE_PROC_FOR_LIBRARIES) | |
123 | ||
124 | #ifdef LINT | |
125 | struct link_dynamic _DYNAMIC; | |
126 | #endif | |
127 | ||
128 | static struct link_map * | |
129 | GC_FirstDLOpenedLinkMap() | |
130 | { | |
131 | extern struct link_dynamic _DYNAMIC; | |
132 | ||
133 | if( &_DYNAMIC == 0) { | |
134 | return(0); | |
135 | } | |
136 | return(_DYNAMIC.ld_un.ld_1->ld_loaded); | |
137 | } | |
138 | ||
139 | /* Return the address of the ld.so allocated common symbol */ | |
140 | /* with the least address, or 0 if none. */ | |
141 | static ptr_t GC_first_common() | |
142 | { | |
143 | ptr_t result = 0; | |
144 | extern struct link_dynamic _DYNAMIC; | |
145 | struct rtc_symb * curr_symbol; | |
146 | ||
147 | if( &_DYNAMIC == 0) { | |
148 | return(0); | |
149 | } | |
150 | curr_symbol = _DYNAMIC.ldd -> ldd_cp; | |
151 | for (; curr_symbol != 0; curr_symbol = curr_symbol -> rtc_next) { | |
152 | if (result == 0 | |
153 | || (ptr_t)(curr_symbol -> rtc_sp -> n_value) < result) { | |
154 | result = (ptr_t)(curr_symbol -> rtc_sp -> n_value); | |
155 | } | |
156 | } | |
157 | return(result); | |
158 | } | |
159 | ||
160 | #endif /* SUNOS4 ... */ | |
161 | ||
162 | # if defined(SUNOS4) || defined(SUNOS5DL) | |
163 | /* Add dynamic library data sections to the root set. */ | |
1530be84 TT |
164 | # if !defined(PCR) && !defined(SOLARIS_THREADS) \ |
165 | && !defined(QUICK_THREADS) && defined(THREADS) | |
21a6f56d TT |
166 | # ifndef SRC_M3 |
167 | --> fix mutual exclusion with dlopen | |
168 | # endif /* We assume M3 programs don't call dlopen for now */ | |
169 | # endif | |
170 | ||
171 | # ifdef SOLARIS_THREADS | |
172 | /* Redefine dlopen to guarantee mutual exclusion with */ | |
173 | /* GC_register_dynamic_libraries. */ | |
174 | /* assumes that dlopen doesn't need to call GC_malloc */ | |
175 | /* and friends. */ | |
176 | # include <thread.h> | |
177 | # include <synch.h> | |
178 | ||
179 | void * GC_dlopen(const char *path, int mode) | |
180 | { | |
181 | void * result; | |
182 | ||
183 | # ifndef USE_PROC_FOR_LIBRARIES | |
184 | mutex_lock(&GC_allocate_ml); | |
185 | # endif | |
186 | result = dlopen(path, mode); | |
187 | # ifndef USE_PROC_FOR_LIBRARIES | |
188 | mutex_unlock(&GC_allocate_ml); | |
189 | # endif | |
190 | return(result); | |
191 | } | |
192 | # endif /* SOLARIS_THREADS */ | |
193 | ||
194 | /* BTL: added to fix circular dlopen definition if SOLARIS_THREADS defined */ | |
195 | # if defined(GC_must_restore_redefined_dlopen) | |
196 | # define dlopen GC_dlopen | |
197 | # endif | |
198 | ||
199 | # ifndef USE_PROC_FOR_LIBRARIES | |
200 | void GC_register_dynamic_libraries() | |
201 | { | |
202 | struct link_map *lm = GC_FirstDLOpenedLinkMap(); | |
203 | ||
204 | ||
205 | for (lm = GC_FirstDLOpenedLinkMap(); | |
206 | lm != (struct link_map *) 0; lm = lm->l_next) | |
207 | { | |
208 | # ifdef SUNOS4 | |
209 | struct exec *e; | |
210 | ||
211 | e = (struct exec *) lm->lm_addr; | |
212 | GC_add_roots_inner( | |
213 | ((char *) (N_DATOFF(*e) + lm->lm_addr)), | |
214 | ((char *) (N_BSSADDR(*e) + e->a_bss + lm->lm_addr)), | |
215 | TRUE); | |
216 | # endif | |
217 | # ifdef SUNOS5DL | |
218 | Elf32_Ehdr * e; | |
219 | Elf32_Phdr * p; | |
220 | unsigned long offset; | |
221 | char * start; | |
222 | register int i; | |
223 | ||
224 | e = (Elf32_Ehdr *) lm->l_addr; | |
225 | p = ((Elf32_Phdr *)(((char *)(e)) + e->e_phoff)); | |
226 | offset = ((unsigned long)(lm->l_addr)); | |
227 | for( i = 0; i < (int)(e->e_phnum); ((i++),(p++)) ) { | |
228 | switch( p->p_type ) { | |
229 | case PT_LOAD: | |
230 | { | |
231 | if( !(p->p_flags & PF_W) ) break; | |
232 | start = ((char *)(p->p_vaddr)) + offset; | |
233 | GC_add_roots_inner( | |
234 | start, | |
235 | start + p->p_memsz, | |
236 | TRUE | |
237 | ); | |
238 | } | |
239 | break; | |
240 | default: | |
241 | break; | |
242 | } | |
243 | } | |
244 | # endif | |
245 | } | |
246 | # ifdef SUNOS4 | |
247 | { | |
248 | static ptr_t common_start = 0; | |
249 | ptr_t common_end; | |
250 | extern ptr_t GC_find_limit(); | |
251 | ||
252 | if (common_start == 0) common_start = GC_first_common(); | |
253 | if (common_start != 0) { | |
254 | common_end = GC_find_limit(common_start, TRUE); | |
255 | GC_add_roots_inner((char *)common_start, (char *)common_end, TRUE); | |
256 | } | |
257 | } | |
258 | # endif | |
259 | } | |
260 | ||
261 | # endif /* !USE_PROC ... */ | |
262 | # endif /* SUNOS */ | |
263 | ||
264 | #if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) | |
265 | ||
266 | /* Dynamic loading code for Linux running ELF. Somewhat tested on | |
267 | * Linux/x86, untested but hopefully should work on Linux/Alpha. | |
268 | * This code was derived from the Solaris/ELF support. Thanks to | |
269 | * whatever kind soul wrote that. - Patrick Bridges */ | |
270 | ||
271 | #include <elf.h> | |
272 | #include <link.h> | |
273 | ||
274 | /* Newer versions of Linux/Alpha and Linux/x86 define this macro. We | |
275 | * define it for those older versions that don't. */ | |
276 | # ifndef ElfW | |
277 | # if !defined(ELF_CLASS) || ELF_CLASS == ELFCLASS32 | |
278 | # define ElfW(type) Elf32_##type | |
279 | # else | |
280 | # define ElfW(type) Elf64_##type | |
281 | # endif | |
282 | # endif | |
283 | ||
284 | static struct link_map * | |
285 | GC_FirstDLOpenedLinkMap() | |
286 | { | |
20bbd3cd TT |
287 | # ifdef __GNUC__ |
288 | # pragma weak _DYNAMIC | |
289 | # endif | |
21a6f56d TT |
290 | extern ElfW(Dyn) _DYNAMIC[]; |
291 | ElfW(Dyn) *dp; | |
292 | struct r_debug *r; | |
293 | static struct link_map *cachedResult = 0; | |
294 | ||
295 | if( _DYNAMIC == 0) { | |
296 | return(0); | |
297 | } | |
298 | if( cachedResult == 0 ) { | |
299 | int tag; | |
300 | for( dp = _DYNAMIC; (tag = dp->d_tag) != 0; dp++ ) { | |
301 | if( tag == DT_DEBUG ) { | |
302 | struct link_map *lm | |
303 | = ((struct r_debug *)(dp->d_un.d_ptr))->r_map; | |
304 | if( lm != 0 ) cachedResult = lm->l_next; /* might be NIL */ | |
305 | break; | |
306 | } | |
307 | } | |
308 | } | |
309 | return cachedResult; | |
310 | } | |
311 | ||
312 | ||
313 | void GC_register_dynamic_libraries() | |
314 | { | |
315 | struct link_map *lm = GC_FirstDLOpenedLinkMap(); | |
316 | ||
317 | ||
318 | for (lm = GC_FirstDLOpenedLinkMap(); | |
319 | lm != (struct link_map *) 0; lm = lm->l_next) | |
320 | { | |
321 | ElfW(Ehdr) * e; | |
322 | ElfW(Phdr) * p; | |
323 | unsigned long offset; | |
324 | char * start; | |
325 | register int i; | |
326 | ||
327 | e = (ElfW(Ehdr) *) lm->l_addr; | |
328 | p = ((ElfW(Phdr) *)(((char *)(e)) + e->e_phoff)); | |
329 | offset = ((unsigned long)(lm->l_addr)); | |
330 | for( i = 0; i < (int)(e->e_phnum); ((i++),(p++)) ) { | |
331 | switch( p->p_type ) { | |
332 | case PT_LOAD: | |
333 | { | |
334 | if( !(p->p_flags & PF_W) ) break; | |
335 | start = ((char *)(p->p_vaddr)) + offset; | |
336 | GC_add_roots_inner(start, start + p->p_memsz, TRUE); | |
337 | } | |
338 | break; | |
339 | default: | |
340 | break; | |
341 | } | |
342 | } | |
343 | } | |
344 | } | |
345 | ||
346 | #endif | |
347 | ||
348 | #if defined(IRIX5) || defined(USE_PROC_FOR_LIBRARIES) | |
349 | ||
350 | #include <sys/procfs.h> | |
351 | #include <sys/stat.h> | |
352 | #include <fcntl.h> | |
353 | #include <elf.h> | |
354 | #include <errno.h> | |
355 | ||
356 | extern void * GC_roots_present(); | |
20bbd3cd TT |
357 | /* The type is a lie, since the real type doesn't make sense here, */ |
358 | /* and we only test for NULL. */ | |
21a6f56d TT |
359 | |
360 | extern ptr_t GC_scratch_last_end_ptr; /* End of GC_scratch_alloc arena */ | |
361 | ||
362 | /* We use /proc to track down all parts of the address space that are */ | |
363 | /* mapped by the process, and throw out regions we know we shouldn't */ | |
364 | /* worry about. This may also work under other SVR4 variants. */ | |
365 | void GC_register_dynamic_libraries() | |
366 | { | |
367 | static int fd = -1; | |
368 | char buf[30]; | |
369 | static prmap_t * addr_map = 0; | |
370 | static int current_sz = 0; /* Number of records currently in addr_map */ | |
371 | static int needed_sz; /* Required size of addr_map */ | |
372 | register int i; | |
373 | register long flags; | |
374 | register ptr_t start; | |
375 | register ptr_t limit; | |
376 | ptr_t heap_start = (ptr_t)HEAP_START; | |
377 | ptr_t heap_end = heap_start; | |
378 | ||
379 | # ifdef SUNOS5DL | |
380 | # define MA_PHYS 0 | |
381 | # endif /* SUNOS5DL */ | |
382 | ||
383 | if (fd < 0) { | |
384 | sprintf(buf, "/proc/%d", getpid()); | |
20bbd3cd TT |
385 | /* The above generates a lint complaint, since pid_t varies. */ |
386 | /* It's unclear how to improve this. */ | |
21a6f56d TT |
387 | fd = open(buf, O_RDONLY); |
388 | if (fd < 0) { | |
389 | ABORT("/proc open failed"); | |
390 | } | |
391 | } | |
392 | if (ioctl(fd, PIOCNMAP, &needed_sz) < 0) { | |
393 | GC_err_printf2("fd = %d, errno = %d\n", fd, errno); | |
394 | ABORT("/proc PIOCNMAP ioctl failed"); | |
395 | } | |
396 | if (needed_sz >= current_sz) { | |
397 | current_sz = needed_sz * 2 + 1; | |
398 | /* Expansion, plus room for 0 record */ | |
20bbd3cd TT |
399 | addr_map = (prmap_t *)GC_scratch_alloc((word) |
400 | (current_sz * sizeof(prmap_t))); | |
21a6f56d TT |
401 | } |
402 | if (ioctl(fd, PIOCMAP, addr_map) < 0) { | |
403 | GC_err_printf4("fd = %d, errno = %d, needed_sz = %d, addr_map = 0x%X\n", | |
404 | fd, errno, needed_sz, addr_map); | |
405 | ABORT("/proc PIOCMAP ioctl failed"); | |
406 | }; | |
407 | if (GC_n_heap_sects > 0) { | |
408 | heap_end = GC_heap_sects[GC_n_heap_sects-1].hs_start | |
409 | + GC_heap_sects[GC_n_heap_sects-1].hs_bytes; | |
410 | if (heap_end < GC_scratch_last_end_ptr) heap_end = GC_scratch_last_end_ptr; | |
411 | } | |
412 | for (i = 0; i < needed_sz; i++) { | |
413 | flags = addr_map[i].pr_mflags; | |
414 | if ((flags & (MA_BREAK | MA_STACK | MA_PHYS)) != 0) goto irrelevant; | |
415 | if ((flags & (MA_READ | MA_WRITE)) != (MA_READ | MA_WRITE)) | |
416 | goto irrelevant; | |
417 | /* The latter test is empirically useless. Other than the */ | |
418 | /* main data and stack segments, everything appears to be */ | |
419 | /* mapped readable, writable, executable, and shared(!!). */ | |
420 | /* This makes no sense to me. - HB */ | |
421 | start = (ptr_t)(addr_map[i].pr_vaddr); | |
422 | if (GC_roots_present(start)) goto irrelevant; | |
423 | if (start < heap_end && start >= heap_start) | |
424 | goto irrelevant; | |
425 | # ifdef MMAP_STACKS | |
426 | if (GC_is_thread_stack(start)) goto irrelevant; | |
427 | # endif /* MMAP_STACKS */ | |
428 | ||
429 | limit = start + addr_map[i].pr_size; | |
430 | if (addr_map[i].pr_off == 0 && strncmp(start, ELFMAG, 4) == 0) { | |
431 | /* Discard text segments, i.e. 0-offset mappings against */ | |
432 | /* executable files which appear to have ELF headers. */ | |
433 | caddr_t arg; | |
434 | int obj; | |
435 | # define MAP_IRR_SZ 10 | |
436 | static ptr_t map_irr[MAP_IRR_SZ]; | |
437 | /* Known irrelevant map entries */ | |
438 | static int n_irr = 0; | |
439 | struct stat buf; | |
440 | register int i; | |
441 | ||
442 | for (i = 0; i < n_irr; i++) { | |
443 | if (map_irr[i] == start) goto irrelevant; | |
444 | } | |
445 | arg = (caddr_t)start; | |
446 | obj = ioctl(fd, PIOCOPENM, &arg); | |
447 | if (obj >= 0) { | |
448 | fstat(obj, &buf); | |
449 | close(obj); | |
450 | if ((buf.st_mode & 0111) != 0) { | |
451 | if (n_irr < MAP_IRR_SZ) { | |
452 | map_irr[n_irr++] = start; | |
453 | } | |
454 | goto irrelevant; | |
455 | } | |
456 | } | |
457 | } | |
458 | GC_add_roots_inner(start, limit, TRUE); | |
459 | irrelevant: ; | |
460 | } | |
461 | /* Dont keep cached descriptor, for now. Some kernels don't like us */ | |
462 | /* to keep a /proc file descriptor around during kill -9. */ | |
463 | if (close(fd) < 0) ABORT("Couldnt close /proc file"); | |
464 | fd = -1; | |
465 | } | |
466 | ||
467 | # endif /* USE_PROC || IRIX5 */ | |
468 | ||
469 | # ifdef MSWIN32 | |
470 | ||
471 | # define WIN32_LEAN_AND_MEAN | |
472 | # define NOSERVICE | |
473 | # include <windows.h> | |
474 | # include <stdlib.h> | |
475 | ||
476 | /* We traverse the entire address space and register all segments */ | |
477 | /* that could possibly have been written to. */ | |
478 | DWORD GC_allocation_granularity; | |
479 | ||
480 | extern GC_bool GC_is_heap_base (ptr_t p); | |
481 | ||
482 | # ifdef WIN32_THREADS | |
483 | extern void GC_get_next_stack(char *start, char **lo, char **hi); | |
484 | # endif | |
485 | ||
486 | void GC_cond_add_roots(char *base, char * limit) | |
487 | { | |
488 | char dummy; | |
489 | char * stack_top | |
490 | = (char *) ((word)(&dummy) & ~(GC_allocation_granularity-1)); | |
491 | if (base == limit) return; | |
492 | # ifdef WIN32_THREADS | |
493 | { | |
494 | char * curr_base = base; | |
495 | char * next_stack_lo; | |
496 | char * next_stack_hi; | |
497 | ||
498 | for(;;) { | |
499 | GC_get_next_stack(curr_base, &next_stack_lo, &next_stack_hi); | |
500 | if (next_stack_lo >= limit) break; | |
501 | GC_add_roots_inner(curr_base, next_stack_lo, TRUE); | |
502 | curr_base = next_stack_hi; | |
503 | } | |
504 | if (curr_base < limit) GC_add_roots_inner(curr_base, limit, TRUE); | |
505 | } | |
506 | # else | |
507 | if (limit > stack_top && base < GC_stackbottom) { | |
508 | /* Part of the stack; ignore it. */ | |
509 | return; | |
510 | } | |
511 | GC_add_roots_inner(base, limit, TRUE); | |
512 | # endif | |
513 | } | |
514 | ||
515 | extern GC_bool GC_win32s; | |
516 | ||
517 | void GC_register_dynamic_libraries() | |
518 | { | |
519 | MEMORY_BASIC_INFORMATION buf; | |
520 | SYSTEM_INFO sysinfo; | |
521 | DWORD result; | |
522 | DWORD protect; | |
523 | LPVOID p; | |
524 | char * base; | |
525 | char * limit, * new_limit; | |
526 | ||
527 | if (GC_win32s) return; | |
528 | GetSystemInfo(&sysinfo); | |
529 | base = limit = p = sysinfo.lpMinimumApplicationAddress; | |
530 | GC_allocation_granularity = sysinfo.dwAllocationGranularity; | |
531 | while (p < sysinfo.lpMaximumApplicationAddress) { | |
532 | result = VirtualQuery(p, &buf, sizeof(buf)); | |
533 | if (result != sizeof(buf)) { | |
534 | ABORT("Weird VirtualQuery result"); | |
535 | } | |
536 | new_limit = (char *)p + buf.RegionSize; | |
537 | protect = buf.Protect; | |
538 | if (buf.State == MEM_COMMIT | |
539 | && (protect == PAGE_EXECUTE_READWRITE | |
540 | || protect == PAGE_READWRITE) | |
541 | && !GC_is_heap_base(buf.AllocationBase)) { | |
542 | if ((char *)p == limit) { | |
543 | limit = new_limit; | |
544 | } else { | |
545 | GC_cond_add_roots(base, limit); | |
546 | base = p; | |
547 | limit = new_limit; | |
548 | } | |
549 | } | |
550 | if (p > (LPVOID)new_limit /* overflow */) break; | |
551 | p = (LPVOID)new_limit; | |
552 | } | |
553 | GC_cond_add_roots(base, limit); | |
554 | } | |
555 | ||
556 | #endif /* MSWIN32 */ | |
557 | ||
558 | #if defined(ALPHA) && defined(OSF1) | |
559 | ||
560 | #include <loader.h> | |
561 | ||
562 | void GC_register_dynamic_libraries() | |
563 | { | |
564 | int status; | |
565 | ldr_process_t mypid; | |
566 | ||
567 | /* module */ | |
568 | ldr_module_t moduleid = LDR_NULL_MODULE; | |
569 | ldr_module_info_t moduleinfo; | |
570 | size_t moduleinfosize = sizeof(moduleinfo); | |
571 | size_t modulereturnsize; | |
572 | ||
573 | /* region */ | |
574 | ldr_region_t region; | |
575 | ldr_region_info_t regioninfo; | |
576 | size_t regioninfosize = sizeof(regioninfo); | |
577 | size_t regionreturnsize; | |
578 | ||
579 | /* Obtain id of this process */ | |
580 | mypid = ldr_my_process(); | |
581 | ||
582 | /* For each module */ | |
583 | while (TRUE) { | |
584 | ||
585 | /* Get the next (first) module */ | |
586 | status = ldr_next_module(mypid, &moduleid); | |
587 | ||
588 | /* Any more modules? */ | |
589 | if (moduleid == LDR_NULL_MODULE) | |
590 | break; /* No more modules */ | |
591 | ||
592 | /* Check status AFTER checking moduleid because */ | |
593 | /* of a bug in the non-shared ldr_next_module stub */ | |
594 | if (status != 0 ) { | |
595 | GC_printf1("dynamic_load: status = %ld\n", (long)status); | |
596 | { | |
597 | extern char *sys_errlist[]; | |
598 | extern int sys_nerr; | |
599 | extern int errno; | |
600 | if (errno <= sys_nerr) { | |
601 | GC_printf1("dynamic_load: %s\n", (long)sys_errlist[errno]); | |
602 | } else { | |
603 | GC_printf1("dynamic_load: %d\n", (long)errno); | |
604 | } | |
605 | } | |
606 | ABORT("ldr_next_module failed"); | |
607 | } | |
608 | ||
609 | /* Get the module information */ | |
610 | status = ldr_inq_module(mypid, moduleid, &moduleinfo, | |
611 | moduleinfosize, &modulereturnsize); | |
612 | if (status != 0 ) | |
613 | ABORT("ldr_inq_module failed"); | |
614 | ||
615 | /* is module for the main program (i.e. nonshared portion)? */ | |
616 | if (moduleinfo.lmi_flags & LDR_MAIN) | |
617 | continue; /* skip the main module */ | |
618 | ||
619 | # ifdef VERBOSE | |
620 | GC_printf("---Module---\n"); | |
621 | GC_printf("Module ID = %16ld\n", moduleinfo.lmi_modid); | |
622 | GC_printf("Count of regions = %16d\n", moduleinfo.lmi_nregion); | |
623 | GC_printf("flags for module = %16lx\n", moduleinfo.lmi_flags); | |
624 | GC_printf("pathname of module = \"%s\"\n", moduleinfo.lmi_name); | |
625 | # endif | |
626 | ||
627 | /* For each region in this module */ | |
628 | for (region = 0; region < moduleinfo.lmi_nregion; region++) { | |
629 | ||
630 | /* Get the region information */ | |
631 | status = ldr_inq_region(mypid, moduleid, region, ®ioninfo, | |
632 | regioninfosize, ®ionreturnsize); | |
633 | if (status != 0 ) | |
634 | ABORT("ldr_inq_region failed"); | |
635 | ||
636 | /* only process writable (data) regions */ | |
637 | if (! (regioninfo.lri_prot & LDR_W)) | |
638 | continue; | |
639 | ||
640 | # ifdef VERBOSE | |
641 | GC_printf("--- Region ---\n"); | |
642 | GC_printf("Region number = %16ld\n", | |
643 | regioninfo.lri_region_no); | |
644 | GC_printf("Protection flags = %016x\n", regioninfo.lri_prot); | |
645 | GC_printf("Virtual address = %16p\n", regioninfo.lri_vaddr); | |
646 | GC_printf("Mapped address = %16p\n", regioninfo.lri_mapaddr); | |
647 | GC_printf("Region size = %16ld\n", regioninfo.lri_size); | |
648 | GC_printf("Region name = \"%s\"\n", regioninfo.lri_name); | |
649 | # endif | |
650 | ||
651 | /* register region as a garbage collection root */ | |
652 | GC_add_roots_inner ( | |
653 | (char *)regioninfo.lri_mapaddr, | |
654 | (char *)regioninfo.lri_mapaddr + regioninfo.lri_size, | |
655 | TRUE); | |
656 | ||
657 | } | |
658 | } | |
659 | } | |
660 | #endif | |
661 | ||
20bbd3cd | 662 | #if defined(HPUX) |
21a6f56d TT |
663 | |
664 | #include <errno.h> | |
665 | #include <dl.h> | |
666 | ||
667 | extern int errno; | |
668 | extern char *sys_errlist[]; | |
669 | extern int sys_nerr; | |
670 | ||
671 | void GC_register_dynamic_libraries() | |
672 | { | |
673 | int status; | |
674 | int index = 1; /* Ordinal position in shared library search list */ | |
675 | struct shl_descriptor *shl_desc; /* Shared library info, see dl.h */ | |
676 | ||
677 | /* For each dynamic library loaded */ | |
678 | while (TRUE) { | |
679 | ||
680 | /* Get info about next shared library */ | |
681 | status = shl_get(index, &shl_desc); | |
682 | ||
683 | /* Check if this is the end of the list or if some error occured */ | |
684 | if (status != 0) { | |
20bbd3cd TT |
685 | # ifdef HPUX_THREADS |
686 | /* I've seen errno values of 0. The man page is not clear */ | |
687 | /* as to whether errno should get set on a -1 return. */ | |
688 | break; | |
689 | # else | |
21a6f56d TT |
690 | if (errno == EINVAL) { |
691 | break; /* Moved past end of shared library list --> finished */ | |
692 | } else { | |
693 | if (errno <= sys_nerr) { | |
694 | GC_printf1("dynamic_load: %s\n", (long) sys_errlist[errno]); | |
695 | } else { | |
696 | GC_printf1("dynamic_load: %d\n", (long) errno); | |
697 | } | |
698 | ABORT("shl_get failed"); | |
699 | } | |
20bbd3cd | 700 | # endif |
21a6f56d TT |
701 | } |
702 | ||
703 | # ifdef VERBOSE | |
704 | GC_printf0("---Shared library---\n"); | |
705 | GC_printf1("\tfilename = \"%s\"\n", shl_desc->filename); | |
706 | GC_printf1("\tindex = %d\n", index); | |
707 | GC_printf1("\thandle = %08x\n", | |
708 | (unsigned long) shl_desc->handle); | |
709 | GC_printf1("\ttext seg. start = %08x\n", shl_desc->tstart); | |
710 | GC_printf1("\ttext seg. end = %08x\n", shl_desc->tend); | |
711 | GC_printf1("\tdata seg. start = %08x\n", shl_desc->dstart); | |
712 | GC_printf1("\tdata seg. end = %08x\n", shl_desc->dend); | |
713 | GC_printf1("\tref. count = %lu\n", shl_desc->ref_count); | |
714 | # endif | |
715 | ||
716 | /* register shared library's data segment as a garbage collection root */ | |
717 | GC_add_roots_inner((char *) shl_desc->dstart, | |
718 | (char *) shl_desc->dend, TRUE); | |
719 | ||
720 | index++; | |
721 | } | |
722 | } | |
20bbd3cd | 723 | #endif /* HPUX */ |
21a6f56d TT |
724 | |
725 | #ifdef RS6000 | |
726 | #pragma alloca | |
727 | #include <sys/ldr.h> | |
728 | #include <sys/errno.h> | |
729 | void GC_register_dynamic_libraries() | |
730 | { | |
731 | int len; | |
732 | char *ldibuf; | |
733 | int ldibuflen; | |
734 | struct ld_info *ldi; | |
735 | ||
736 | ldibuf = alloca(ldibuflen = 8192); | |
737 | ||
738 | while ( (len = loadquery(L_GETINFO,ldibuf,ldibuflen)) < 0) { | |
739 | if (errno != ENOMEM) { | |
740 | ABORT("loadquery failed"); | |
741 | } | |
742 | ldibuf = alloca(ldibuflen *= 2); | |
743 | } | |
744 | ||
745 | ldi = (struct ld_info *)ldibuf; | |
746 | while (ldi) { | |
747 | len = ldi->ldinfo_next; | |
748 | GC_add_roots_inner( | |
749 | ldi->ldinfo_dataorg, | |
750 | (unsigned long)ldi->ldinfo_dataorg | |
751 | + ldi->ldinfo_datasize, | |
752 | TRUE); | |
753 | ldi = len ? (struct ld_info *)((char *)ldi + len) : 0; | |
754 | } | |
755 | } | |
756 | #endif /* RS6000 */ | |
757 | ||
758 | ||
759 | ||
760 | #else /* !DYNAMIC_LOADING */ | |
761 | ||
762 | #ifdef PCR | |
763 | ||
764 | # include "il/PCR_IL.h" | |
765 | # include "th/PCR_ThCtl.h" | |
766 | # include "mm/PCR_MM.h" | |
767 | ||
768 | void GC_register_dynamic_libraries() | |
769 | { | |
770 | /* Add new static data areas of dynamically loaded modules. */ | |
771 | { | |
772 | PCR_IL_LoadedFile * p = PCR_IL_GetLastLoadedFile(); | |
773 | PCR_IL_LoadedSegment * q; | |
774 | ||
775 | /* Skip uncommited files */ | |
776 | while (p != NIL && !(p -> lf_commitPoint)) { | |
777 | /* The loading of this file has not yet been committed */ | |
778 | /* Hence its description could be inconsistent. */ | |
779 | /* Furthermore, it hasn't yet been run. Hence its data */ | |
780 | /* segments can't possibly reference heap allocated */ | |
781 | /* objects. */ | |
782 | p = p -> lf_prev; | |
783 | } | |
784 | for (; p != NIL; p = p -> lf_prev) { | |
785 | for (q = p -> lf_ls; q != NIL; q = q -> ls_next) { | |
786 | if ((q -> ls_flags & PCR_IL_SegFlags_Traced_MASK) | |
787 | == PCR_IL_SegFlags_Traced_on) { | |
788 | GC_add_roots_inner | |
789 | ((char *)(q -> ls_addr), | |
790 | (char *)(q -> ls_addr) + q -> ls_bytes, | |
791 | TRUE); | |
792 | } | |
793 | } | |
794 | } | |
795 | } | |
796 | } | |
797 | ||
798 | ||
799 | #else /* !PCR */ | |
800 | ||
801 | void GC_register_dynamic_libraries(){} | |
802 | ||
803 | int GC_no_dynamic_loading; | |
804 | ||
805 | #endif /* !PCR */ | |
806 | #endif /* !DYNAMIC_LOADING */ |