root/gc/dyn_load.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. GC_FirstDLOpenedLinkMap
  2. GC_FirstDLOpenedLinkMap
  3. GC_first_common
  4. GC_register_dynamic_libraries
  5. GC_register_map_entries
  6. GC_register_dynamic_libraries
  7. GC_register_main_static_data
  8. GC_register_dynlib_callback
  9. GC_register_dynamic_libraries_dl_iterate_phdr
  10. GC_register_main_static_data
  11. ElfW
  12. GC_register_dynamic_libraries
  13. GC_register_dynamic_libraries
  14. GC_cond_add_roots
  15. GC_cond_add_roots
  16. GC_register_main_static_data
  17. GC_register_main_static_data
  18. is_frame_buffer
  19. GC_dump_meminfo
  20. GC_register_dynamic_libraries
  21. GC_register_dynamic_libraries
  22. GC_register_dynamic_libraries
  23. GC_register_dynamic_libraries
  24. GC_dyld_name_for_hdr
  25. GC_dyld_image_add
  26. GC_dyld_image_remove
  27. GC_register_dynamic_libraries
  28. GC_init_dyld
  29. GC_register_main_static_data
  30. GC_register_dynamic_libraries
  31. GC_register_dynamic_libraries
  32. GC_register_main_static_data

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

/* [<][>][^][v][top][bottom][index][help] */