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