2 * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
3 * Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved.
4 * Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved.
5 * Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved.
7 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
8 * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
10 * Permission is hereby granted to use or copy this program
11 * for any purpose, provided the above notices are retained on all copies.
12 * Permission to modify the code and to distribute modified code is granted,
13 * provided the above notices are retained, and a notice that the code was
14 * modified is included with the above copyright notice.
17 #include "private/gc_priv.h"
19 #if defined(LINUX) && !defined(POWERPC)
20 # include <linux/version.h>
21 # if (LINUX_VERSION_CODE <= 0x10400)
22 /* Ugly hack to get struct sigcontext_struct definition. Required */
23 /* for some early 1.3.X releases. Will hopefully go away soon. */
24 /* in some later Linux releases, asm/sigcontext.h may have to */
25 /* be included instead. */
27 # include <asm/signal.h>
30 /* Kernels prior to 2.1.1 defined struct sigcontext_struct instead of */
31 /* struct sigcontext. libc6 (glibc2) uses "struct sigcontext" in */
32 /* prototypes, so we have to include the top-level sigcontext.h to */
33 /* make sure the former gets defined to be the latter if appropriate. */
34 # include <features.h>
36 # if 2 == __GLIBC__ && 0 == __GLIBC_MINOR__
37 /* glibc 2.1 no longer has sigcontext.h. But signal.h */
38 /* has the right declaration for glibc 2.1. */
39 # include <sigcontext.h>
40 # endif /* 0 == __GLIBC_MINOR__ */
41 # else /* not 2 <= __GLIBC__ */
42 /* libc5 doesn't have <sigcontext.h>: go directly with the kernel */
43 /* one. Check LINUX_VERSION_CODE to see which we should reference. */
44 # include <asm/sigcontext.h>
45 # endif /* 2 <= __GLIBC__ */
49 #if !defined(OS2) && !defined(PCR) && !defined(AMIGA) && !defined(MACOS) \
51 # include <sys/types.h>
52 # if !defined(MSWIN32)
59 # define SIGSEGV 0 /* value is irrelevant */
64 #if defined(UNIX_LIKE) || defined(CYGWIN32)
68 #if defined(LINUX) || defined(LINUX_STACKBOTTOM)
72 /* Blatantly OS dependent routines, except for those that are related */
73 /* to dynamic loading. */
77 # include "extra/AmigaOS.c"
81 #if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
82 # ifndef WIN32_LEAN_AND_MEAN
83 # define WIN32_LEAN_AND_MEAN 1
87 /* It's not clear this is completely kosher under Cygwin. But it */
88 /* allows us to get a working GC_get_stack_base. */
92 # include <Processes.h>
97 # include <malloc.h> /* for locking */
100 #if defined(LINUX) || defined(FREEBSD) || defined(SOLARIS) || defined(IRIX5) \
101 || ((defined(USE_MMAP) || defined(USE_MUNMAP)) \
102 && !defined(MSWIN32) && !defined(MSWINCE))
103 # define MMAP_SUPPORTED
106 #if defined(MMAP_SUPPORTED) || defined(ADD_HEAP_GUARD_PAGES)
107 # if defined(USE_MUNMAP) && !defined(USE_MMAP)
108 # error "invalid config - USE_MUNMAP requires USE_MMAP"
110 # include <sys/types.h>
111 # include <sys/mman.h>
112 # include <sys/stat.h>
117 /* for get_etext and friends */
118 # include <mach-o/getsect.h>
122 /* Apparently necessary for djgpp 2.01. May cause problems with */
123 /* other versions. */
124 typedef long unsigned int caddr_t;
128 # include "il/PCR_IL.h"
129 # include "th/PCR_ThCtl.h"
130 # include "mm/PCR_MM.h"
133 #if !defined(NO_EXECUTE_PERMISSION)
134 # define OPT_PROT_EXEC PROT_EXEC
136 # define OPT_PROT_EXEC 0
139 #if defined(LINUX) && (defined(USE_PROC_FOR_LIBRARIES) || defined(IA64) \
140 || !defined(SMALL_CONFIG))
141 # define NEED_PROC_MAPS
144 #ifdef NEED_PROC_MAPS
145 /* We need to parse /proc/self/maps, either to find dynamic libraries, */
146 /* and/or to find the register backing store base (IA64). Do it once */
151 /* Repeatedly perform a read call until the buffer is filled or */
152 /* we encounter EOF. */
153 STATIC ssize_t GC_repeat_read(int fd, char *buf, size_t count)
155 ssize_t num_read = 0;
158 ASSERT_CANCEL_DISABLED();
159 while (num_read < count) {
160 result = READ(fd, buf + num_read, count - num_read);
161 if (result < 0) return result;
162 if (result == 0) break;
169 /* Determine the length of a file by incrementally reading it into a */
170 /* This would be silly to use on a file supporting lseek, but Linux */
171 /* /proc files usually do not. */
172 STATIC size_t GC_get_file_len(int f)
176 # define GET_FILE_LEN_BUF_SZ 500
177 char buf[GET_FILE_LEN_BUF_SZ];
180 result = read(f, buf, GET_FILE_LEN_BUF_SZ);
181 if (result == -1) return 0;
183 } while (result > 0);
187 STATIC size_t GC_get_maps_len(void)
189 int f = open("/proc/self/maps", O_RDONLY);
190 size_t result = GC_get_file_len(f);
197 * Copy the contents of /proc/self/maps to a buffer in our address space.
198 * Return the address of the buffer, or zero on failure.
199 * This code could be simplified if we could determine its size
202 GC_INNER char * GC_get_maps(void)
206 static char init_buf[1];
207 static char *maps_buf = init_buf;
208 static size_t maps_buf_sz = 1;
209 size_t maps_size, old_maps_size = 0;
211 /* The buffer is essentially static, so there must be a single client. */
212 GC_ASSERT(I_HOLD_LOCK());
214 /* Note that in the presence of threads, the maps file can */
215 /* essentially shrink asynchronously and unexpectedly as */
216 /* threads that we already think of as dead release their */
217 /* stacks. And there is no easy way to read the entire */
218 /* file atomically. This is arguably a misfeature of the */
219 /* /proc/.../maps interface. */
221 /* Since we don't believe the file can grow */
222 /* asynchronously, it should suffice to first determine */
223 /* the size (using lseek or read), and then to reread the */
224 /* file. If the size is inconsistent we have to retry. */
225 /* This only matters with threads enabled, and if we use */
226 /* this to locate roots (not the default). */
228 /* Determine the initial size of /proc/self/maps. */
229 /* Note that lseek doesn't work, at least as of 2.6.15. */
231 maps_size = GC_get_maps_len();
232 if (0 == maps_size) return 0;
234 maps_size = 4000; /* Guess */
237 /* Read /proc/self/maps, growing maps_buf as necessary. */
238 /* Note that we may not allocate conventionally, and */
239 /* thus can't use stdio. */
241 while (maps_size >= maps_buf_sz) {
242 /* Grow only by powers of 2, since we leak "too small" buffers. */
243 while (maps_size >= maps_buf_sz) maps_buf_sz *= 2;
244 maps_buf = GC_scratch_alloc(maps_buf_sz);
246 /* Recompute initial length, since we allocated. */
247 /* This can only happen a few times per program */
249 maps_size = GC_get_maps_len();
250 if (0 == maps_size) return 0;
252 if (maps_buf == 0) return 0;
254 GC_ASSERT(maps_buf_sz >= maps_size + 1);
255 f = open("/proc/self/maps", O_RDONLY);
256 if (-1 == f) return 0;
258 old_maps_size = maps_size;
262 result = GC_repeat_read(f, maps_buf, maps_buf_sz-1);
263 if (result <= 0) return 0;
265 } while (result == maps_buf_sz-1);
268 if (maps_size > old_maps_size) {
269 GC_err_printf("Old maps size = %lu, new maps size = %lu\n",
270 (unsigned long)old_maps_size,
271 (unsigned long)maps_size);
272 ABORT("Unexpected asynchronous /proc/self/maps growth: "
273 "Unregistered thread?");
276 } while (maps_size >= maps_buf_sz || maps_size < old_maps_size);
277 /* In the single-threaded case, the second clause is false. */
278 maps_buf[maps_size] = '\0';
280 /* Apply fn to result. */
285 * GC_parse_map_entry parses an entry from /proc/self/maps so we can
286 * locate all writable data segments that belong to shared libraries.
287 * The format of one of these entries and the fields we care about
289 * XXXXXXXX-XXXXXXXX r-xp 00000000 30:05 260537 name of mapping...\n
290 * ^^^^^^^^ ^^^^^^^^ ^^^^ ^^
291 * start end prot maj_dev
293 * Note that since about august 2003 kernels, the columns no longer have
294 * fixed offsets on 64-bit kernels. Hence we no longer rely on fixed offsets
295 * anywhere, which is safer anyway.
299 * Assign various fields of the first line in buf_ptr to *start, *end,
300 * *prot, *maj_dev and *mapping_name. Mapping_name may be NULL.
301 * *prot and *mapping_name are assigned pointers into the original
304 GC_INNER char *GC_parse_map_entry(char *buf_ptr, ptr_t *start, ptr_t *end,
305 char **prot, unsigned int *maj_dev,
308 char *start_start, *end_start, *maj_dev_start;
312 if (buf_ptr == NULL || *buf_ptr == '\0') {
317 while (isspace(*p)) ++p;
319 GC_ASSERT(isxdigit(*start_start));
320 *start = (ptr_t)strtoul(start_start, &endp, 16); p = endp;
325 GC_ASSERT(isxdigit(*end_start));
326 *end = (ptr_t)strtoul(end_start, &endp, 16); p = endp;
327 GC_ASSERT(isspace(*p));
329 while (isspace(*p)) ++p;
330 GC_ASSERT(*p == 'r' || *p == '-');
332 /* Skip past protection field to offset field */
333 while (!isspace(*p)) ++p; while (isspace(*p)) ++p;
334 GC_ASSERT(isxdigit(*p));
335 /* Skip past offset field, which we ignore */
336 while (!isspace(*p)) ++p; while (isspace(*p)) ++p;
338 GC_ASSERT(isxdigit(*maj_dev_start));
339 *maj_dev = strtoul(maj_dev_start, NULL, 16);
341 if (mapping_name == 0) {
342 while (*p && *p++ != '\n');
344 while (*p && *p != '\n' && *p != '/' && *p != '[') p++;
346 while (*p && *p++ != '\n');
352 /* Try to read the backing store base from /proc/self/maps. */
353 /* Return the bounds of the writable mapping with a 0 major device, */
354 /* which includes the address passed as data. */
355 /* Return FALSE if there is no such mapping. */
356 GC_bool GC_enclosing_mapping(ptr_t addr, ptr_t *startp, ptr_t *endp)
359 ptr_t my_start, my_end;
360 unsigned int maj_dev;
361 char *maps = GC_get_maps();
362 char *buf_ptr = maps;
364 if (0 == maps) return(FALSE);
366 buf_ptr = GC_parse_map_entry(buf_ptr, &my_start, &my_end,
369 if (buf_ptr == NULL) return FALSE;
370 if (prot[1] == 'w' && maj_dev == 0) {
371 if (my_end > addr && my_start <= addr) {
381 #if defined(REDIRECT_MALLOC)
382 /* Find the text(code) mapping for the library whose name, after */
383 /* stripping the directory part, starts with nm. */
384 GC_INNER GC_bool GC_text_mapping(char *nm, ptr_t *startp, ptr_t *endp)
386 size_t nm_len = strlen(nm);
389 ptr_t my_start, my_end;
390 unsigned int maj_dev;
391 char *maps = GC_get_maps();
392 char *buf_ptr = maps;
394 if (0 == maps) return(FALSE);
396 buf_ptr = GC_parse_map_entry(buf_ptr, &my_start, &my_end,
397 &prot, &maj_dev, &map_path);
399 if (buf_ptr == NULL) return FALSE;
400 if (prot[0] == 'r' && prot[1] == '-' && prot[2] == 'x') {
402 /* Set p to point just past last slash, if any. */
403 while (*p != '\0' && *p != '\n' && *p != ' ' && *p != '\t') ++p;
404 while (*p != '/' && p >= map_path) --p;
406 if (strncmp(nm, p, nm_len) == 0) {
415 #endif /* REDIRECT_MALLOC */
418 static ptr_t backing_store_base_from_proc(void)
420 ptr_t my_start, my_end;
421 if (!GC_enclosing_mapping(GC_save_regs_in_stack(), &my_start, &my_end)) {
422 if (GC_print_stats) {
423 GC_log_printf("Failed to find backing store base from /proc\n");
431 #endif /* NEED_PROC_MAPS */
433 #if defined(SEARCH_FOR_DATA_START)
434 /* The I386 case can be handled without a search. The Alpha case */
435 /* used to be handled differently as well, but the rules changed */
436 /* for recent Linux versions. This seems to be the easiest way to */
437 /* cover all versions. */
439 # if defined(LINUX) || defined(HURD)
440 /* Some Linux distributions arrange to define __data_start. Some */
441 /* define data_start as a weak symbol. The latter is technically */
442 /* broken, since the user program may define data_start, in which */
443 /* case we lose. Nonetheless, we try both, preferring __data_start.*/
444 /* We assume gcc-compatible pragmas. */
445 # pragma weak __data_start
446 extern int __data_start[];
447 # pragma weak data_start
448 extern int data_start[];
452 ptr_t GC_data_start = NULL;
454 ptr_t GC_find_limit(ptr_t, GC_bool);
456 GC_INNER void GC_init_linux_data_start(void)
459 # if defined(LINUX) || defined(HURD)
460 /* Try the easy approaches first: */
461 if ((ptr_t)__data_start != 0) {
462 GC_data_start = (ptr_t)(__data_start);
465 if ((ptr_t)data_start != 0) {
466 GC_data_start = (ptr_t)(data_start);
470 GC_data_start = GC_find_limit((ptr_t)(_end), FALSE);
476 # ifndef ECOS_GC_MEMORY_SIZE
477 # define ECOS_GC_MEMORY_SIZE (448 * 1024)
478 # endif /* ECOS_GC_MEMORY_SIZE */
480 /* FIXME: This is a simple way of allocating memory which is */
481 /* compatible with ECOS early releases. Later releases use a more */
482 /* sophisticated means of allocating memory than this simple static */
483 /* allocator, but this method is at least bound to work. */
484 static char ecos_gc_memory[ECOS_GC_MEMORY_SIZE];
485 static char *ecos_gc_brk = ecos_gc_memory;
487 static void *tiny_sbrk(ptrdiff_t increment)
489 void *p = ecos_gc_brk;
490 ecos_gc_brk += increment;
491 if (ecos_gc_brk > ecos_gc_memory + sizeof(ecos_gc_memory)) {
492 ecos_gc_brk -= increment;
497 #define sbrk tiny_sbrk
500 #if defined(NETBSD) && defined(__ELF__)
501 ptr_t GC_data_start = NULL;
502 ptr_t GC_find_limit(ptr_t, GC_bool);
504 extern char **environ;
506 GC_INNER void GC_init_netbsd_elf(void)
508 /* This may need to be environ, without the underscore, for */
510 GC_data_start = GC_find_limit((ptr_t)&environ, FALSE);
515 static struct sigaction old_segv_act;
516 STATIC sigjmp_buf GC_jmp_buf_openbsd;
519 # include <sys/syscall.h>
520 extern sigset_t __syscall(quad_t, ...);
523 /* Don't use GC_find_limit() because siglongjmp() outside of the */
524 /* signal handler by-passes our userland pthreads lib, leaving */
525 /* SIGSEGV and SIGPROF masked. Instead, use this custom one that */
526 /* works-around the issues. */
529 STATIC void GC_fault_handler_openbsd(int sig)
531 siglongjmp(GC_jmp_buf_openbsd, 1);
534 /* Return the first non-addressible location > p or bound. */
535 /* Requires the allocation lock. */
536 STATIC ptr_t GC_find_limit_openbsd(ptr_t p, ptr_t bound)
538 static volatile ptr_t result;
539 /* Safer if static, since otherwise it may not be */
540 /* preserved across the longjmp. Can safely be */
541 /* static since it's only called with the */
542 /* allocation lock held. */
544 struct sigaction act;
545 size_t pgsz = (size_t)sysconf(_SC_PAGESIZE);
546 GC_ASSERT(I_HOLD_LOCK());
548 act.sa_handler = GC_fault_handler_openbsd;
549 sigemptyset(&act.sa_mask);
550 act.sa_flags = SA_NODEFER | SA_RESTART;
551 sigaction(SIGSEGV, &act, &old_segv_act);
553 if (sigsetjmp(GC_jmp_buf_openbsd, 1) == 0) {
554 result = (ptr_t)((word)p & ~(pgsz-1));
557 if (result >= bound) {
561 GC_noop1((word)(*result));
566 /* Due to the siglongjump we need to manually unmask SIGPROF. */
567 __syscall(SYS_sigprocmask, SIG_UNBLOCK, sigmask(SIGPROF));
570 sigaction(SIGSEGV, &old_segv_act, 0);
574 /* Return first addressable location > p or bound. */
575 /* Requires the allocation lock. */
576 STATIC ptr_t GC_skip_hole_openbsd(ptr_t p, ptr_t bound)
578 static volatile ptr_t result;
579 static volatile int firstpass;
581 struct sigaction act;
582 size_t pgsz = (size_t)sysconf(_SC_PAGESIZE);
583 GC_ASSERT(I_HOLD_LOCK());
585 act.sa_handler = GC_fault_handler_openbsd;
586 sigemptyset(&act.sa_mask);
587 act.sa_flags = SA_NODEFER | SA_RESTART;
588 sigaction(SIGSEGV, &act, &old_segv_act);
591 result = (ptr_t)((word)p & ~(pgsz-1));
592 if (sigsetjmp(GC_jmp_buf_openbsd, 1) != 0 || firstpass) {
595 if (result >= bound) {
598 GC_noop1((word)(*result));
602 sigaction(SIGSEGV, &old_segv_act, 0);
611 # if !defined(__IBMC__) && !defined(__WATCOMC__) /* e.g. EMX */
614 unsigned short magic_number;
615 unsigned short padding[29];
619 #define E_MAGIC(x) (x).magic_number
620 #define EMAGIC 0x5A4D
621 #define E_LFANEW(x) (x).new_exe_offset
624 unsigned char magic_number[2];
625 unsigned char byte_order;
626 unsigned char word_order;
627 unsigned long exe_format_level;
630 unsigned long padding1[13];
631 unsigned long object_table_offset;
632 unsigned long object_count;
633 unsigned long padding2[31];
636 #define E32_MAGIC1(x) (x).magic_number[0]
637 #define E32MAGIC1 'L'
638 #define E32_MAGIC2(x) (x).magic_number[1]
639 #define E32MAGIC2 'X'
640 #define E32_BORDER(x) (x).byte_order
642 #define E32_WORDER(x) (x).word_order
644 #define E32_CPU(x) (x).cpu
646 #define E32_OBJTAB(x) (x).object_table_offset
647 #define E32_OBJCNT(x) (x).object_count
653 unsigned long pagemap;
654 unsigned long mapsize;
655 unsigned long reserved;
658 #define O32_FLAGS(x) (x).flags
659 #define OBJREAD 0x0001L
660 #define OBJWRITE 0x0002L
661 #define OBJINVALID 0x0080L
662 #define O32_SIZE(x) (x).size
663 #define O32_BASE(x) (x).base
665 # else /* IBM's compiler */
667 /* A kludge to get around what appears to be a header file bug */
669 # define WORD unsigned short
672 # define DWORD unsigned long
679 # endif /* __IBMC__ */
681 # define INCL_DOSEXCEPTIONS
682 # define INCL_DOSPROCESS
683 # define INCL_DOSERRORS
684 # define INCL_DOSMODULEMGR
685 # define INCL_DOSMEMMGR
690 /* Find the page size */
691 GC_INNER word GC_page_size = 0;
693 # if defined(MSWIN32) || defined(MSWINCE)
695 # ifndef VER_PLATFORM_WIN32_CE
696 # define VER_PLATFORM_WIN32_CE 3
699 # if defined(MSWINCE) && defined(THREADS)
700 GC_INNER GC_bool GC_dont_query_stack_min = FALSE;
703 GC_INNER void GC_setpagesize(void)
705 GetSystemInfo(&GC_sysinfo);
706 GC_page_size = GC_sysinfo.dwPageSize;
707 # if defined(MSWINCE) && !defined(_WIN32_WCE_EMULATION)
709 OSVERSIONINFO verInfo;
710 /* Check the current WinCE version. */
711 verInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
712 if (!GetVersionEx(&verInfo))
713 ABORT("GetVersionEx failed");
714 if (verInfo.dwPlatformId == VER_PLATFORM_WIN32_CE &&
715 verInfo.dwMajorVersion < 6) {
716 /* Only the first 32 MB of address space belongs to the */
717 /* current process (unless WinCE 6.0+ or emulation). */
718 GC_sysinfo.lpMaximumApplicationAddress = (LPVOID)((word)32 << 20);
720 /* On some old WinCE versions, it's observed that */
721 /* VirtualQuery calls don't work properly when used to */
722 /* get thread current stack committed minimum. */
723 if (verInfo.dwMajorVersion < 5)
724 GC_dont_query_stack_min = TRUE;
732 GC_INNER void GC_setpagesize(void)
734 # if defined(MPROTECT_VDB) || defined(PROC_VDB) || defined(USE_MMAP)
735 GC_page_size = GETPAGESIZE();
737 /* It's acceptable to fake it. */
738 GC_page_size = HBLKSIZE;
743 # if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
747 # define is_writable(prot) ((prot) == PAGE_READWRITE \
748 || (prot) == PAGE_WRITECOPY \
749 || (prot) == PAGE_EXECUTE_READWRITE \
750 || (prot) == PAGE_EXECUTE_WRITECOPY)
751 /* Return the number of bytes that are writable starting at p. */
752 /* The pointer p is assumed to be page aligned. */
753 /* If base is not 0, *base becomes the beginning of the */
754 /* allocation region containing p. */
755 STATIC word GC_get_writable_length(ptr_t p, ptr_t *base)
757 MEMORY_BASIC_INFORMATION buf;
761 result = VirtualQuery(p, &buf, sizeof(buf));
762 if (result != sizeof(buf)) ABORT("Weird VirtualQuery result");
763 if (base != 0) *base = (ptr_t)(buf.AllocationBase);
764 protect = (buf.Protect & ~(PAGE_GUARD | PAGE_NOCACHE));
765 if (!is_writable(protect)) {
768 if (buf.State != MEM_COMMIT) return(0);
769 return(buf.RegionSize);
772 GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *sb)
775 ptr_t sp = (ptr_t)(&dummy);
776 ptr_t trunc_sp = (ptr_t)((word)sp & ~(GC_page_size - 1));
777 /* FIXME: This won't work if called from a deeply recursive */
778 /* client code (and the committed stack space has grown). */
779 word size = GC_get_writable_length(trunc_sp, 0);
780 GC_ASSERT(size != 0);
781 sb -> mem_base = trunc_sp + size;
787 /* An alternate version for Cygwin (adapted from Dave Korn's */
788 /* gcc version of boehm-gc). */
789 GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *sb)
791 extern void * _tlsbase __asm__ ("%fs:4");
792 sb -> mem_base = _tlsbase;
796 #endif /* CYGWIN32 */
798 # define HAVE_GET_STACK_BASE
800 /* This is always called from the main thread. */
801 ptr_t GC_get_main_stack_base(void)
803 struct GC_stack_base sb;
804 GC_get_stack_base(&sb);
805 GC_ASSERT((void *)&sb HOTTER_THAN sb.mem_base);
806 return (ptr_t)sb.mem_base;
809 # endif /* MS Windows */
812 # include <kernel/OS.h>
813 ptr_t GC_get_main_stack_base(void)
816 get_thread_info(find_thread(NULL),&th);
824 ptr_t GC_get_main_stack_base(void)
829 if (DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR) {
830 GC_err_printf("DosGetInfoBlocks failed\n");
831 ABORT("DosGetInfoBlocks failed\n");
833 return((ptr_t)(ptib -> tib_pstacklimit));
840 # include "extra/AmigaOS.c"
844 # if defined(NEED_FIND_LIMIT) || defined(UNIX_LIKE)
846 typedef void (*GC_fault_handler_t)(int);
848 # if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1) \
849 || defined(HURD) || defined(NETBSD)
850 static struct sigaction old_segv_act;
851 # if defined(_sigargs) /* !Irix6.x */ || defined(HPUX) \
852 || defined(HURD) || defined(NETBSD) || defined(FREEBSD)
853 static struct sigaction old_bus_act;
856 static GC_fault_handler_t old_segv_handler, old_bus_handler;
859 GC_INNER void GC_set_and_save_fault_handler(GC_fault_handler_t h)
861 # if defined(SUNOS5SIGS) || defined(IRIX5) \
862 || defined(OSF1) || defined(HURD) || defined(NETBSD)
863 struct sigaction act;
866 # if 0 /* Was necessary for Solaris 2.3 and very temporary */
868 act.sa_flags = SA_RESTART | SA_NODEFER;
870 act.sa_flags = SA_RESTART;
873 (void) sigemptyset(&act.sa_mask);
874 # ifdef GC_IRIX_THREADS
875 /* Older versions have a bug related to retrieving and */
876 /* and setting a handler at the same time. */
877 (void) sigaction(SIGSEGV, 0, &old_segv_act);
878 (void) sigaction(SIGSEGV, &act, 0);
880 (void) sigaction(SIGSEGV, &act, &old_segv_act);
881 # if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \
882 || defined(HPUX) || defined(HURD) || defined(NETBSD) \
884 /* Under Irix 5.x or HP/UX, we may get SIGBUS. */
885 /* Pthreads doesn't exist under Irix 5.x, so we */
886 /* don't have to worry in the threads case. */
887 (void) sigaction(SIGBUS, &act, &old_bus_act);
889 # endif /* GC_IRIX_THREADS */
891 old_segv_handler = signal(SIGSEGV, h);
893 old_bus_handler = signal(SIGBUS, h);
897 # endif /* NEED_FIND_LIMIT || UNIX_LIKE */
899 # if defined(NEED_FIND_LIMIT) || \
900 defined(USE_PROC_FOR_LIBRARIES) && defined(THREADS)
901 /* Some tools to implement HEURISTIC2 */
902 # define MIN_PAGE_SIZE 256 /* Smallest conceivable page size, bytes */
905 STATIC void GC_fault_handler(int sig)
907 LONGJMP(GC_jmp_buf, 1);
910 GC_INNER void GC_setup_temporary_fault_handler(void)
912 /* Handler is process-wide, so this should only happen in */
913 /* one thread at a time. */
914 GC_ASSERT(I_HOLD_LOCK());
915 GC_set_and_save_fault_handler(GC_fault_handler);
918 GC_INNER void GC_reset_fault_handler(void)
920 # if defined(SUNOS5SIGS) || defined(IRIX5) \
921 || defined(OSF1) || defined(HURD) || defined(NETBSD)
922 (void) sigaction(SIGSEGV, &old_segv_act, 0);
923 # if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \
924 || defined(HPUX) || defined(HURD) || defined(NETBSD) \
926 (void) sigaction(SIGBUS, &old_bus_act, 0);
929 (void) signal(SIGSEGV, old_segv_handler);
931 (void) signal(SIGBUS, old_bus_handler);
936 /* Return the first non-addressable location > p (up) or */
937 /* the smallest location q s.t. [q,p) is addressable (!up). */
938 /* We assume that p (up) or p-1 (!up) is addressable. */
939 /* Requires allocation lock. */
940 STATIC ptr_t GC_find_limit_with_bound(ptr_t p, GC_bool up, ptr_t bound)
942 static volatile ptr_t result;
943 /* Safer if static, since otherwise it may not be */
944 /* preserved across the longjmp. Can safely be */
945 /* static since it's only called with the */
946 /* allocation lock held. */
948 GC_ASSERT(I_HOLD_LOCK());
949 GC_setup_temporary_fault_handler();
950 if (SETJMP(GC_jmp_buf) == 0) {
951 result = (ptr_t)(((word)(p))
952 & ~(MIN_PAGE_SIZE-1));
955 result += MIN_PAGE_SIZE;
956 if (result >= bound) return bound;
958 result -= MIN_PAGE_SIZE;
959 if (result <= bound) return bound;
961 GC_noop1((word)(*result));
964 GC_reset_fault_handler();
966 result += MIN_PAGE_SIZE;
971 ptr_t GC_find_limit(ptr_t p, GC_bool up)
973 return GC_find_limit_with_bound(p, up, up ? (ptr_t)(word)(-1) : 0);
977 #if defined(ECOS) || defined(NOSYS)
978 ptr_t GC_get_main_stack_base(void)
984 #ifdef HPUX_STACKBOTTOM
986 #include <sys/param.h>
987 #include <sys/pstat.h>
989 GC_INNER ptr_t GC_get_register_stack_base(void)
991 struct pst_vm_status vm_status;
994 while (pstat_getprocvm(&vm_status, sizeof(vm_status), 0, i++) == 1) {
995 if (vm_status.pst_type == PS_RSESTACK) {
996 return (ptr_t) vm_status.pst_vaddr;
1000 /* old way to get the register stackbottom */
1001 return (ptr_t)(((word)GC_stackbottom - BACKING_STORE_DISPLACEMENT - 1)
1002 & ~(BACKING_STORE_ALIGNMENT - 1));
1005 #endif /* HPUX_STACK_BOTTOM */
1007 #ifdef LINUX_STACKBOTTOM
1009 #include <sys/types.h>
1010 #include <sys/stat.h>
1012 # define STAT_SKIP 27 /* Number of fields preceding startstack */
1013 /* field in /proc/self/stat */
1015 #ifdef USE_LIBC_PRIVATES
1016 # pragma weak __libc_stack_end
1017 extern ptr_t __libc_stack_end;
1021 # ifdef USE_LIBC_PRIVATES
1022 # pragma weak __libc_ia64_register_backing_store_base
1023 extern ptr_t __libc_ia64_register_backing_store_base;
1026 GC_INNER ptr_t GC_get_register_stack_base(void)
1030 # ifdef USE_LIBC_PRIVATES
1031 if (0 != &__libc_ia64_register_backing_store_base
1032 && 0 != __libc_ia64_register_backing_store_base) {
1033 /* Glibc 2.2.4 has a bug such that for dynamically linked */
1034 /* executables __libc_ia64_register_backing_store_base is */
1035 /* defined but uninitialized during constructor calls. */
1036 /* Hence we check for both nonzero address and value. */
1037 return __libc_ia64_register_backing_store_base;
1040 result = backing_store_base_from_proc();
1042 result = GC_find_limit(GC_save_regs_in_stack(), FALSE);
1043 /* Now seems to work better than constant displacement */
1044 /* heuristic used in 6.X versions. The latter seems to */
1045 /* fail for 2.6 kernels. */
1051 STATIC ptr_t GC_linux_stack_base(void)
1053 /* We read the stack base value from /proc/self/stat. We do this */
1054 /* using direct I/O system calls in order to avoid calling malloc */
1055 /* in case REDIRECT_MALLOC is defined. */
1057 /* Also defined in pthread_support.c. */
1058 # define STAT_BUF_SIZE 4096
1059 # define STAT_READ read
1061 /* Should probably call the real read, if read is wrapped. */
1062 char stat_buf[STAT_BUF_SIZE];
1066 size_t i, buf_offset = 0;
1068 /* First try the easy way. This should work for glibc 2.2 */
1069 /* This fails in a prelinked ("prelink" command) executable */
1070 /* since the correct value of __libc_stack_end never */
1071 /* becomes visible to us. The second test works around */
1073 # ifdef USE_LIBC_PRIVATES
1074 if (0 != &__libc_stack_end && 0 != __libc_stack_end ) {
1076 /* Some versions of glibc set the address 16 bytes too */
1077 /* low while the initialization code is running. */
1078 if (((word)__libc_stack_end & 0xfff) + 0x10 < 0x1000) {
1079 return __libc_stack_end + 0x10;
1080 } /* Otherwise it's not safe to add 16 bytes and we fall */
1081 /* back to using /proc. */
1082 # elif defined(SPARC)
1083 /* Older versions of glibc for 64-bit Sparc do not set
1084 * this variable correctly, it gets set to either zero
1087 if (__libc_stack_end != (ptr_t) (unsigned long)0x1)
1088 return __libc_stack_end;
1090 return __libc_stack_end;
1094 f = open("/proc/self/stat", O_RDONLY);
1095 if (f < 0 || STAT_READ(f, stat_buf, STAT_BUF_SIZE) < 2 * STAT_SKIP) {
1096 ABORT("Couldn't read /proc/self/stat");
1098 c = stat_buf[buf_offset++];
1099 /* Skip the required number of fields. This number is hopefully */
1100 /* constant across all Linux implementations. */
1101 for (i = 0; i < STAT_SKIP; ++i) {
1102 while (isspace(c)) c = stat_buf[buf_offset++];
1103 while (!isspace(c)) c = stat_buf[buf_offset++];
1105 while (isspace(c)) c = stat_buf[buf_offset++];
1106 while (isdigit(c)) {
1109 c = stat_buf[buf_offset++];
1112 if (result < 0x100000) ABORT("Absurd stack bottom value");
1113 return (ptr_t)result;
1116 #endif /* LINUX_STACKBOTTOM */
1118 #ifdef FREEBSD_STACKBOTTOM
1120 /* This uses an undocumented sysctl call, but at least one expert */
1121 /* believes it will stay. */
1124 #include <sys/types.h>
1125 #include <sys/sysctl.h>
1127 STATIC ptr_t GC_freebsd_stack_base(void)
1129 int nm[2] = {CTL_KERN, KERN_USRSTACK};
1131 size_t len = sizeof(ptr_t);
1132 int r = sysctl(nm, 2, &base, &len, NULL, 0);
1134 if (r) ABORT("Error getting stack base");
1139 #endif /* FREEBSD_STACKBOTTOM */
1141 #if !defined(BEOS) && !defined(AMIGA) && !defined(MSWIN32) \
1142 && !defined(MSWINCE) && !defined(OS2) && !defined(NOSYS) && !defined(ECOS) \
1143 && !defined(CYGWIN32) && !defined(GC_OPENBSD_THREADS)
1145 ptr_t GC_get_main_stack_base(void)
1148 return(STACKBOTTOM);
1150 # if defined(HEURISTIC1) || defined(HEURISTIC2)
1154 # define STACKBOTTOM_ALIGNMENT_M1 ((word)STACK_GRAN - 1)
1156 # ifdef STACK_GROWS_DOWN
1157 result = (ptr_t)((((word)(&dummy))
1158 + STACKBOTTOM_ALIGNMENT_M1)
1159 & ~STACKBOTTOM_ALIGNMENT_M1);
1161 result = (ptr_t)(((word)(&dummy))
1162 & ~STACKBOTTOM_ALIGNMENT_M1);
1164 # endif /* HEURISTIC1 */
1165 # ifdef LINUX_STACKBOTTOM
1166 result = GC_linux_stack_base();
1168 # ifdef FREEBSD_STACKBOTTOM
1169 result = GC_freebsd_stack_base();
1172 # ifdef STACK_GROWS_DOWN
1173 result = GC_find_limit((ptr_t)(&dummy), TRUE);
1174 # ifdef HEURISTIC2_LIMIT
1175 if (result > HEURISTIC2_LIMIT
1176 && (ptr_t)(&dummy) < HEURISTIC2_LIMIT) {
1177 result = HEURISTIC2_LIMIT;
1181 result = GC_find_limit((ptr_t)(&dummy), FALSE);
1182 # ifdef HEURISTIC2_LIMIT
1183 if (result < HEURISTIC2_LIMIT
1184 && (ptr_t)(&dummy) > HEURISTIC2_LIMIT) {
1185 result = HEURISTIC2_LIMIT;
1190 # endif /* HEURISTIC2 */
1191 # ifdef STACK_GROWS_DOWN
1192 if (result == 0) result = (ptr_t)(signed_word)(-sizeof(ptr_t));
1195 # endif /* STACKBOTTOM */
1198 # endif /* ! AMIGA, !OS 2, ! MS Windows, !BEOS, !NOSYS, !ECOS */
1200 #if defined(GC_LINUX_THREADS) && !defined(HAVE_GET_STACK_BASE)
1202 #include <pthread.h>
1203 /* extern int pthread_getattr_np(pthread_t, pthread_attr_t *); */
1206 GC_INNER ptr_t GC_greatest_stack_base_below(ptr_t bound);
1207 /* From pthread_support.c */
1210 GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *b)
1212 pthread_attr_t attr;
1215 if (pthread_getattr_np(pthread_self(), &attr) != 0) {
1216 WARN("pthread_getattr_np failed\n", 0);
1217 return GC_UNIMPLEMENTED;
1219 if (pthread_attr_getstack(&attr, &(b -> mem_base), &size) != 0) {
1220 ABORT("pthread_attr_getstack failed");
1222 pthread_attr_destroy(&attr);
1223 # ifdef STACK_GROWS_DOWN
1224 b -> mem_base = (char *)(b -> mem_base) + size;
1227 /* We could try backing_store_base_from_proc, but that's safe */
1228 /* only if no mappings are being asynchronously created. */
1229 /* Subtracting the size from the stack base doesn't work for at */
1230 /* least the main thread. */
1233 IF_CANCEL(int cancel_state;)
1237 DISABLE_CANCEL(cancel_state);
1238 bsp = GC_save_regs_in_stack();
1239 next_stack = GC_greatest_stack_base_below(bsp);
1240 if (0 == next_stack) {
1241 b -> reg_base = GC_find_limit(bsp, FALSE);
1243 /* Avoid walking backwards into preceding memory stack and */
1245 b -> reg_base = GC_find_limit_with_bound(bsp, FALSE, next_stack);
1247 RESTORE_CANCEL(cancel_state);
1254 # define HAVE_GET_STACK_BASE
1256 #endif /* GC_LINUX_THREADS */
1258 #ifdef GC_OPENBSD_THREADS
1260 # include <sys/signal.h>
1261 # include <pthread.h>
1262 # include <pthread_np.h>
1264 /* Find the stack using pthread_stackseg_np(). */
1265 GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *sb)
1268 pthread_stackseg_np(pthread_self(), &stack);
1269 sb->mem_base = stack.ss_sp;
1273 # define HAVE_GET_STACK_BASE
1275 /* This is always called from the main thread. */
1276 ptr_t GC_get_main_stack_base(void)
1278 struct GC_stack_base sb;
1279 GC_get_stack_base(&sb);
1280 GC_ASSERT((void *)&sb HOTTER_THAN sb.mem_base);
1281 return (ptr_t)sb.mem_base;
1284 #endif /* GC_OPENBSD_THREADS */
1286 #ifndef HAVE_GET_STACK_BASE
1287 /* Retrieve stack base. */
1288 /* Using the GC_find_limit version is risky. */
1289 /* On IA64, for example, there is no guard page between the */
1290 /* stack of one thread and the register backing store of the */
1291 /* next. Thus this is likely to identify way too large a */
1292 /* "stack" and thus at least result in disastrous performance. */
1293 /* FIXME - Implement better strategies here. */
1294 GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *b)
1296 # ifdef NEED_FIND_LIMIT
1298 IF_CANCEL(int cancel_state;)
1299 DISABLE_CANCEL(cancel_state); /* May be unnecessary? */
1300 # ifdef STACK_GROWS_DOWN
1301 b -> mem_base = GC_find_limit((ptr_t)(&dummy), TRUE);
1303 b -> reg_base = GC_find_limit(GC_save_regs_in_stack(), FALSE);
1306 b -> mem_base = GC_find_limit(&dummy, FALSE);
1308 RESTORE_CANCEL(cancel_state);
1311 return GC_UNIMPLEMENTED;
1317 * Register static data segment(s) as roots.
1318 * If more data segments are added later then they need to be registered
1319 * add that point (as we do with SunOS dynamic loading),
1320 * or GC_mark_roots needs to check for them (as we do with PCR).
1321 * Called with allocator lock held.
1326 void GC_register_data_segments(void)
1330 HMODULE module_handle;
1331 # define PBUFSIZ 512
1332 UCHAR path[PBUFSIZ];
1334 struct exe_hdr hdrdos; /* MSDOS header. */
1335 struct e32_exe hdr386; /* Real header for my executable */
1336 struct o32_obj seg; /* Currrent segment */
1340 if (DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR) {
1341 GC_err_printf("DosGetInfoBlocks failed\n");
1342 ABORT("DosGetInfoBlocks failed\n");
1344 module_handle = ppib -> pib_hmte;
1345 if (DosQueryModuleName(module_handle, PBUFSIZ, path) != NO_ERROR) {
1346 GC_err_printf("DosQueryModuleName failed\n");
1347 ABORT("DosGetInfoBlocks failed\n");
1349 myexefile = fopen(path, "rb");
1350 if (myexefile == 0) {
1351 GC_err_puts("Couldn't open executable ");
1352 GC_err_puts(path); GC_err_puts("\n");
1353 ABORT("Failed to open executable\n");
1355 if (fread((char *)(&hdrdos), 1, sizeof hdrdos, myexefile) < sizeof hdrdos) {
1356 GC_err_puts("Couldn't read MSDOS header from ");
1357 GC_err_puts(path); GC_err_puts("\n");
1358 ABORT("Couldn't read MSDOS header");
1360 if (E_MAGIC(hdrdos) != EMAGIC) {
1361 GC_err_puts("Executable has wrong DOS magic number: ");
1362 GC_err_puts(path); GC_err_puts("\n");
1363 ABORT("Bad DOS magic number");
1365 if (fseek(myexefile, E_LFANEW(hdrdos), SEEK_SET) != 0) {
1366 GC_err_puts("Seek to new header failed in ");
1367 GC_err_puts(path); GC_err_puts("\n");
1368 ABORT("Bad DOS magic number");
1370 if (fread((char *)(&hdr386), 1, sizeof hdr386, myexefile) < sizeof hdr386) {
1371 GC_err_puts("Couldn't read MSDOS header from ");
1372 GC_err_puts(path); GC_err_puts("\n");
1373 ABORT("Couldn't read OS/2 header");
1375 if (E32_MAGIC1(hdr386) != E32MAGIC1 || E32_MAGIC2(hdr386) != E32MAGIC2) {
1376 GC_err_puts("Executable has wrong OS/2 magic number:");
1377 GC_err_puts(path); GC_err_puts("\n");
1378 ABORT("Bad OS/2 magic number");
1380 if ( E32_BORDER(hdr386) != E32LEBO || E32_WORDER(hdr386) != E32LEWO) {
1381 GC_err_puts("Executable %s has wrong byte order: ");
1382 GC_err_puts(path); GC_err_puts("\n");
1383 ABORT("Bad byte order");
1385 if ( E32_CPU(hdr386) == E32CPU286) {
1386 GC_err_puts("GC can't handle 80286 executables: ");
1387 GC_err_puts(path); GC_err_puts("\n");
1390 if (fseek(myexefile, E_LFANEW(hdrdos) + E32_OBJTAB(hdr386),
1392 GC_err_puts("Seek to object table failed: ");
1393 GC_err_puts(path); GC_err_puts("\n");
1394 ABORT("Seek to object table failed");
1396 for (nsegs = E32_OBJCNT(hdr386); nsegs > 0; nsegs--) {
1398 if (fread((char *)(&seg), 1, sizeof seg, myexefile) < sizeof seg) {
1399 GC_err_puts("Couldn't read obj table entry from ");
1400 GC_err_puts(path); GC_err_puts("\n");
1401 ABORT("Couldn't read obj table entry");
1403 flags = O32_FLAGS(seg);
1404 if (!(flags & OBJWRITE)) continue;
1405 if (!(flags & OBJREAD)) continue;
1406 if (flags & OBJINVALID) {
1407 GC_err_printf("Object with invalid pages?\n");
1410 GC_add_roots_inner((ptr_t)O32_BASE(seg),
1411 (ptr_t)(O32_BASE(seg)+O32_SIZE(seg)), FALSE);
1417 # if defined(GWW_VDB)
1419 # ifndef MEM_WRITE_WATCH
1420 # define MEM_WRITE_WATCH 0x200000
1423 # ifndef WRITE_WATCH_FLAG_RESET
1424 # define WRITE_WATCH_FLAG_RESET 1
1427 /* Since we can't easily check whether ULONG_PTR and SIZE_T are */
1428 /* defined in Win32 basetsd.h, we define own ULONG_PTR. */
1429 # define GC_ULONG_PTR word
1431 typedef UINT (WINAPI * GetWriteWatch_type)(
1432 DWORD, PVOID, GC_ULONG_PTR /* SIZE_T */,
1433 PVOID *, GC_ULONG_PTR *, PULONG);
1434 static GetWriteWatch_type GetWriteWatch_func;
1435 static DWORD GetWriteWatch_alloc_flag;
1437 # define GC_GWW_AVAILABLE() (GetWriteWatch_func != NULL)
1439 static void detect_GetWriteWatch(void)
1441 static GC_bool done;
1446 # if defined(MPROTECT_VDB)
1448 char * str = GETENV("GC_USE_GETWRITEWATCH");
1449 # if defined(GC_PREFER_MPROTECT_VDB)
1450 if (str == NULL || (*str == '0' && *(str + 1) == '\0')) {
1451 /* GC_USE_GETWRITEWATCH is unset or set to "0". */
1452 done = TRUE; /* falling back to MPROTECT_VDB strategy. */
1453 /* This should work as if GWW_VDB is undefined. */
1457 if (str != NULL && *str == '0' && *(str + 1) == '\0') {
1458 /* GC_USE_GETWRITEWATCH is set "0". */
1459 done = TRUE; /* falling back to MPROTECT_VDB strategy. */
1466 hK32 = GetModuleHandle(TEXT("kernel32.dll"));
1467 if (hK32 != (HMODULE)0 &&
1468 (GetWriteWatch_func = (GetWriteWatch_type)GetProcAddress(hK32,
1469 "GetWriteWatch")) != NULL) {
1470 /* Also check whether VirtualAlloc accepts MEM_WRITE_WATCH, */
1471 /* as some versions of kernel32.dll have one but not the */
1472 /* other, making the feature completely broken. */
1473 void * page = VirtualAlloc(NULL, GC_page_size,
1474 MEM_WRITE_WATCH | MEM_RESERVE,
1478 GC_ULONG_PTR count = 16;
1480 /* Check that it actually works. In spite of some */
1481 /* documentation it actually seems to exist on W2K. */
1482 /* This test may be unnecessary, but ... */
1483 if (GetWriteWatch_func(WRITE_WATCH_FLAG_RESET,
1488 /* GetWriteWatch always fails. */
1489 GetWriteWatch_func = NULL;
1491 GetWriteWatch_alloc_flag = MEM_WRITE_WATCH;
1493 VirtualFree(page, GC_page_size, MEM_RELEASE);
1495 /* GetWriteWatch will be useless. */
1496 GetWriteWatch_func = NULL;
1499 if (GC_print_stats) {
1500 if (GetWriteWatch_func == NULL) {
1501 GC_log_printf("Did not find a usable GetWriteWatch()\n");
1503 GC_log_printf("Using GetWriteWatch()\n");
1509 # else /* !GWW_VDB */
1510 # define GetWriteWatch_alloc_flag 0
1511 # endif /* GWW_VDB */
1513 # if defined(MSWIN32) || defined(MSWINCE)
1516 /* Unfortunately, we have to handle win32s very differently from NT, */
1517 /* Since VirtualQuery has very different semantics. In particular, */
1518 /* under win32s a VirtualQuery call on an unmapped page returns an */
1519 /* invalid result. Under NT, GC_register_data_segments is a no-op */
1520 /* and all real work is done by GC_register_dynamic_libraries. Under */
1521 /* win32s, we cannot find the data segments associated with dll's. */
1522 /* We register the main data segment here. */
1523 GC_INNER GC_bool GC_no_win32_dlls = FALSE;
1524 /* This used to be set for gcc, to avoid dealing with */
1525 /* the structured exception handling issues. But we now have */
1526 /* assembly code to do that right. */
1528 GC_INNER GC_bool GC_wnt = FALSE;
1529 /* This is a Windows NT derivative, i.e. NT, W2K, XP or later. */
1531 GC_INNER void GC_init_win32(void)
1533 /* Set GC_wnt. If we're running under win32s, assume that no DLLs */
1534 /* will be loaded. I doubt anyone still runs win32s, but... */
1535 DWORD v = GetVersion();
1536 GC_wnt = !(v & 0x80000000);
1537 GC_no_win32_dlls |= ((!GC_wnt) && (v & 0xff) <= 3);
1539 if (GC_no_win32_dlls) {
1540 /* Turn off unmapping for safety (since may not work well with */
1542 GC_unmap_threshold = 0;
1547 /* Return the smallest address a such that VirtualQuery */
1548 /* returns correct results for all addresses between a and start. */
1549 /* Assumes VirtualQuery returns correct information for start. */
1550 STATIC ptr_t GC_least_described_address(ptr_t start)
1552 MEMORY_BASIC_INFORMATION buf;
1558 limit = GC_sysinfo.lpMinimumApplicationAddress;
1559 p = (ptr_t)((word)start & ~(GC_page_size - 1));
1561 q = (LPVOID)(p - GC_page_size);
1562 if ((ptr_t)q > (ptr_t)p /* underflow */ || q < limit) break;
1563 result = VirtualQuery(q, &buf, sizeof(buf));
1564 if (result != sizeof(buf) || buf.AllocationBase == 0) break;
1565 p = (ptr_t)(buf.AllocationBase);
1571 # ifndef REDIRECT_MALLOC
1572 /* We maintain a linked list of AllocationBase values that we know */
1573 /* correspond to malloc heap sections. Currently this is only called */
1574 /* during a GC. But there is some hope that for long running */
1575 /* programs we will eventually see most heap sections. */
1577 /* In the long run, it would be more reliable to occasionally walk */
1578 /* the malloc heap with HeapWalk on the default heap. But that */
1579 /* apparently works only for NT-based Windows. */
1581 /* In the long run, a better data structure would also be nice ... */
1582 STATIC struct GC_malloc_heap_list {
1583 void * allocation_base;
1584 struct GC_malloc_heap_list *next;
1585 } *GC_malloc_heap_l = 0;
1587 /* Is p the base of one of the malloc heap sections we already know */
1589 STATIC GC_bool GC_is_malloc_heap_base(ptr_t p)
1591 struct GC_malloc_heap_list *q = GC_malloc_heap_l;
1594 if (q -> allocation_base == p) return TRUE;
1600 STATIC void *GC_get_allocation_base(void *p)
1602 MEMORY_BASIC_INFORMATION buf;
1603 size_t result = VirtualQuery(p, &buf, sizeof(buf));
1604 if (result != sizeof(buf)) {
1605 ABORT("Weird VirtualQuery result");
1607 return buf.AllocationBase;
1610 STATIC size_t GC_max_root_size = 100000; /* Appr. largest root size. */
1612 GC_INNER void GC_add_current_malloc_heap(void)
1614 struct GC_malloc_heap_list *new_l =
1615 malloc(sizeof(struct GC_malloc_heap_list));
1616 void * candidate = GC_get_allocation_base(new_l);
1618 if (new_l == 0) return;
1619 if (GC_is_malloc_heap_base(candidate)) {
1620 /* Try a little harder to find malloc heap. */
1621 size_t req_size = 10000;
1623 void *p = malloc(req_size);
1624 if (0 == p) { free(new_l); return; }
1625 candidate = GC_get_allocation_base(p);
1628 } while (GC_is_malloc_heap_base(candidate)
1629 && req_size < GC_max_root_size/10 && req_size < 500000);
1630 if (GC_is_malloc_heap_base(candidate)) {
1631 free(new_l); return;
1635 GC_log_printf("Found new system malloc AllocationBase at %p\n",
1637 new_l -> allocation_base = candidate;
1638 new_l -> next = GC_malloc_heap_l;
1639 GC_malloc_heap_l = new_l;
1641 # endif /* REDIRECT_MALLOC */
1643 STATIC word GC_n_heap_bases = 0; /* See GC_heap_bases. */
1645 /* Is p the start of either the malloc heap, or of one of our */
1646 /* heap sections? */
1647 GC_INNER GC_bool GC_is_heap_base(ptr_t p)
1650 # ifndef REDIRECT_MALLOC
1651 if (GC_root_size > GC_max_root_size) GC_max_root_size = GC_root_size;
1652 if (GC_is_malloc_heap_base(p)) return TRUE;
1654 for (i = 0; i < GC_n_heap_bases; i++) {
1655 if (GC_heap_bases[i] == p) return TRUE;
1661 STATIC void GC_register_root_section(ptr_t static_root)
1663 MEMORY_BASIC_INFORMATION buf;
1668 char * limit, * new_limit;
1670 if (!GC_no_win32_dlls) return;
1671 p = base = limit = GC_least_described_address(static_root);
1672 while (p < GC_sysinfo.lpMaximumApplicationAddress) {
1673 result = VirtualQuery(p, &buf, sizeof(buf));
1674 if (result != sizeof(buf) || buf.AllocationBase == 0
1675 || GC_is_heap_base(buf.AllocationBase)) break;
1676 new_limit = (char *)p + buf.RegionSize;
1677 protect = buf.Protect;
1678 if (buf.State == MEM_COMMIT
1679 && is_writable(protect)) {
1680 if ((char *)p == limit) {
1683 if (base != limit) GC_add_roots_inner(base, limit, FALSE);
1688 if (p > (LPVOID)new_limit /* overflow */) break;
1689 p = (LPVOID)new_limit;
1691 if (base != limit) GC_add_roots_inner(base, limit, FALSE);
1695 void GC_register_data_segments(void)
1699 GC_register_root_section((ptr_t)(&dummy));
1703 # else /* !OS2 && !Windows */
1705 # if (defined(SVR4) || defined(AUX) || defined(DGUX) \
1706 || (defined(LINUX) && defined(SPARC))) && !defined(PCR)
1707 ptr_t GC_SysVGetDataStart(size_t max_page_size, ptr_t etext_addr)
1709 word text_end = ((word)(etext_addr) + sizeof(word) - 1)
1710 & ~(sizeof(word) - 1);
1711 /* etext rounded to word boundary */
1712 word next_page = ((text_end + (word)max_page_size - 1)
1713 & ~((word)max_page_size - 1));
1714 word page_offset = (text_end & ((word)max_page_size - 1));
1715 volatile char * result = (char *)(next_page + page_offset);
1716 /* Note that this isnt equivalent to just adding */
1717 /* max_page_size to &etext if &etext is at a page boundary */
1719 GC_setup_temporary_fault_handler();
1720 if (SETJMP(GC_jmp_buf) == 0) {
1721 /* Try writing to the address. */
1723 GC_reset_fault_handler();
1725 GC_reset_fault_handler();
1726 /* We got here via a longjmp. The address is not readable. */
1727 /* This is known to happen under Solaris 2.4 + gcc, which place */
1728 /* string constants in the text segment, but after etext. */
1729 /* Use plan B. Note that we now know there is a gap between */
1730 /* text and data segments, so plan A bought us something. */
1731 result = (char *)GC_find_limit((ptr_t)(DATAEND), FALSE);
1733 return((ptr_t)result);
1737 # if defined(FREEBSD) && !defined(PCR) && (defined(I386) || defined(X86_64) \
1738 || defined(powerpc) || defined(__powerpc__))
1740 /* Its unclear whether this should be identical to the above, or */
1741 /* whether it should apply to non-X86 architectures. */
1742 /* For now we don't assume that there is always an empty page after */
1743 /* etext. But in some cases there actually seems to be slightly more. */
1744 /* This also deals with holes between read-only data and writable data. */
1745 ptr_t GC_FreeBSDGetDataStart(size_t max_page_size, ptr_t etext_addr)
1747 word text_end = ((word)(etext_addr) + sizeof(word) - 1)
1748 & ~(sizeof(word) - 1);
1749 /* etext rounded to word boundary */
1750 volatile word next_page = (text_end + (word)max_page_size - 1)
1751 & ~((word)max_page_size - 1);
1752 volatile ptr_t result = (ptr_t)text_end;
1753 GC_setup_temporary_fault_handler();
1754 if (SETJMP(GC_jmp_buf) == 0) {
1755 /* Try reading at the address. */
1756 /* This should happen before there is another thread. */
1757 for (; next_page < (word)(DATAEND); next_page += (word)max_page_size)
1758 *(volatile char *)next_page;
1759 GC_reset_fault_handler();
1761 GC_reset_fault_handler();
1762 /* As above, we go to plan B */
1763 result = GC_find_limit((ptr_t)(DATAEND), FALSE);
1768 # endif /* FREEBSD */
1773 # define GC_AMIGA_DS
1774 # include "extra/AmigaOS.c"
1777 #elif defined(OPENBSD)
1779 /* Depending on arch alignment, there can be multiple holes */
1780 /* between DATASTART and DATAEND. Scan in DATASTART .. DATAEND */
1781 /* and register each region. */
1782 void GC_register_data_segments(void)
1784 ptr_t region_start = DATASTART;
1788 region_end = GC_find_limit_openbsd(region_start, DATAEND);
1789 GC_add_roots_inner(region_start, region_end, FALSE);
1790 if (region_end >= DATAEND)
1792 region_start = GC_skip_hole_openbsd(region_end, DATAEND);
1796 # else /* !OS2 && !Windows && !AMIGA && !OPENBSD */
1798 void GC_register_data_segments(void)
1800 # if !defined(PCR) && !defined(MACOS)
1801 # if defined(REDIRECT_MALLOC) && defined(GC_SOLARIS_THREADS)
1802 /* As of Solaris 2.3, the Solaris threads implementation */
1803 /* allocates the data structure for the initial thread with */
1804 /* sbrk at process startup. It needs to be scanned, so that */
1805 /* we don't lose some malloc allocated data structures */
1806 /* hanging from it. We're on thin ice here ... */
1807 extern caddr_t sbrk(int);
1809 GC_add_roots_inner(DATASTART, (ptr_t)sbrk(0), FALSE);
1811 GC_add_roots_inner(DATASTART, (ptr_t)(DATAEND), FALSE);
1812 # if defined(DATASTART2)
1813 GC_add_roots_inner(DATASTART2, (ptr_t)(DATAEND2), FALSE);
1819 # if defined(THINK_C)
1820 extern void* GC_MacGetDataStart(void);
1821 /* globals begin above stack and end at a5. */
1822 GC_add_roots_inner((ptr_t)GC_MacGetDataStart(),
1823 (ptr_t)LMGetCurrentA5(), FALSE);
1825 # if defined(__MWERKS__)
1827 extern void* GC_MacGetDataStart(void);
1828 /* MATTHEW: Function to handle Far Globals (CW Pro 3) */
1829 # if __option(far_data)
1830 extern void* GC_MacGetDataEnd(void);
1832 /* globals begin above stack and end at a5. */
1833 GC_add_roots_inner((ptr_t)GC_MacGetDataStart(),
1834 (ptr_t)LMGetCurrentA5(), FALSE);
1835 /* MATTHEW: Handle Far Globals */
1836 # if __option(far_data)
1837 /* Far globals follow he QD globals: */
1838 GC_add_roots_inner((ptr_t)LMGetCurrentA5(),
1839 (ptr_t)GC_MacGetDataEnd(), FALSE);
1842 extern char __data_start__[], __data_end__[];
1843 GC_add_roots_inner((ptr_t)&__data_start__,
1844 (ptr_t)&__data_end__, FALSE);
1845 # endif /* __POWERPC__ */
1846 # endif /* __MWERKS__ */
1847 # endif /* !THINK_C */
1851 /* Dynamic libraries are added at every collection, since they may */
1855 # endif /* ! AMIGA */
1856 # endif /* ! MSWIN32 && ! MSWINCE*/
1860 * Auxiliary routines for obtaining memory from OS.
1863 # if !defined(OS2) && !defined(PCR) && !defined(AMIGA) \
1864 && !defined(MSWIN32) && !defined(MSWINCE) \
1865 && !defined(MACOS) && !defined(DOS4GW) && !defined(NONSTOP)
1867 # define SBRK_ARG_T ptrdiff_t
1869 #if defined(MMAP_SUPPORTED)
1871 #ifdef USE_MMAP_FIXED
1872 # define GC_MMAP_FLAGS MAP_FIXED | MAP_PRIVATE
1873 /* Seems to yield better performance on Solaris 2, but can */
1874 /* be unreliable if something is already mapped at the address. */
1876 # define GC_MMAP_FLAGS MAP_PRIVATE
1879 #ifdef USE_MMAP_ANON
1881 # if defined(MAP_ANONYMOUS)
1882 # define OPT_MAP_ANON MAP_ANONYMOUS
1884 # define OPT_MAP_ANON MAP_ANON
1888 # define OPT_MAP_ANON 0
1892 # define HEAP_START ((ptr_t)0)
1895 STATIC ptr_t GC_unix_mmap_get_mem(word bytes)
1898 static ptr_t last_addr = HEAP_START;
1900 # ifndef USE_MMAP_ANON
1901 static GC_bool initialized = FALSE;
1904 zero_fd = open("/dev/zero", O_RDONLY);
1905 fcntl(zero_fd, F_SETFD, FD_CLOEXEC);
1910 if (bytes & (GC_page_size - 1)) ABORT("Bad GET_MEM arg");
1911 result = mmap(last_addr, bytes, PROT_READ | PROT_WRITE | OPT_PROT_EXEC,
1912 GC_MMAP_FLAGS | OPT_MAP_ANON, zero_fd, 0/* offset */);
1913 if (result == MAP_FAILED) return(0);
1914 last_addr = (ptr_t)result + bytes + GC_page_size - 1;
1915 last_addr = (ptr_t)((word)last_addr & ~(GC_page_size - 1));
1916 # if !defined(LINUX)
1917 if (last_addr == 0) {
1918 /* Oops. We got the end of the address space. This isn't */
1919 /* usable by arbitrary C code, since one-past-end pointers */
1920 /* don't work, so we discard it and try again. */
1921 munmap(result, (size_t)(-GC_page_size) - (size_t)result);
1922 /* Leave last page mapped, so we can't repeat. */
1923 return GC_unix_mmap_get_mem(bytes);
1926 GC_ASSERT(last_addr != 0);
1928 return((ptr_t)result);
1931 # endif /* MMAP_SUPPORTED */
1933 #if defined(USE_MMAP)
1935 ptr_t GC_unix_get_mem(word bytes)
1937 return GC_unix_mmap_get_mem(bytes);
1940 #else /* Not USE_MMAP */
1942 STATIC ptr_t GC_unix_sbrk_get_mem(word bytes)
1946 /* Bare sbrk isn't thread safe. Play by malloc rules. */
1947 /* The equivalent may be needed on other systems as well. */
1951 ptr_t cur_brk = (ptr_t)sbrk(0);
1952 SBRK_ARG_T lsbs = (word)cur_brk & (GC_page_size-1);
1954 if ((SBRK_ARG_T)bytes < 0) {
1955 result = 0; /* too big */
1959 if((ptr_t)sbrk(GC_page_size - lsbs) == (ptr_t)(-1)) {
1964 # ifdef ADD_HEAP_GUARD_PAGES
1965 /* This is useful for catching severe memory overwrite problems that */
1966 /* span heap sections. It shouldn't otherwise be turned on. */
1968 ptr_t guard = (ptr_t)sbrk((SBRK_ARG_T)GC_page_size);
1969 if (mprotect(guard, GC_page_size, PROT_NONE) != 0)
1970 ABORT("ADD_HEAP_GUARD_PAGES: mprotect failed");
1972 # endif /* ADD_HEAP_GUARD_PAGES */
1973 result = (ptr_t)sbrk((SBRK_ARG_T)bytes);
1974 if (result == (ptr_t)(-1)) result = 0;
1983 #if defined(MMAP_SUPPORTED)
1984 /* By default, we try both sbrk and mmap, in that order. */
1985 ptr_t GC_unix_get_mem(word bytes)
1987 static GC_bool sbrk_failed = FALSE;
1990 if (!sbrk_failed) result = GC_unix_sbrk_get_mem(bytes);
1993 result = GC_unix_mmap_get_mem(bytes);
1996 /* Try sbrk again, in case sbrk memory became available. */
1997 result = GC_unix_sbrk_get_mem(bytes);
2001 #else /* !MMAP_SUPPORTED */
2002 ptr_t GC_unix_get_mem(word bytes)
2004 return GC_unix_sbrk_get_mem(bytes);
2008 #endif /* Not USE_MMAP */
2014 void * os2_alloc(size_t bytes)
2018 if (DosAllocMem(&result, bytes, PAG_EXECUTE | PAG_READ |
2019 PAG_WRITE | PAG_COMMIT)
2023 if (result == 0) return(os2_alloc(bytes));
2030 # if defined(MSWIN32) || defined(MSWINCE)
2031 GC_INNER SYSTEM_INFO GC_sysinfo;
2036 # ifdef USE_GLOBAL_ALLOC
2037 # define GLOBAL_ALLOC_TEST 1
2039 # define GLOBAL_ALLOC_TEST GC_no_win32_dlls
2042 #ifdef GC_USE_MEM_TOP_DOWN
2043 STATIC DWORD GC_mem_top_down = MEM_TOP_DOWN;
2044 /* Use GC_USE_MEM_TOP_DOWN for better 64-bit */
2045 /* testing. Otherwise all addresses tend to */
2046 /* end up in first 4GB, hiding bugs. */
2048 STATIC DWORD GC_mem_top_down = 0;
2051 ptr_t GC_win32_get_mem(word bytes)
2055 if (GLOBAL_ALLOC_TEST) {
2056 /* VirtualAlloc doesn't like PAGE_EXECUTE_READWRITE. */
2057 /* There are also unconfirmed rumors of other */
2058 /* problems, so we dodge the issue. */
2059 result = (ptr_t) GlobalAlloc(0, bytes + HBLKSIZE);
2060 result = (ptr_t)(((word)result + HBLKSIZE - 1) & ~(HBLKSIZE-1));
2062 /* VirtualProtect only works on regions returned by a */
2063 /* single VirtualAlloc call. Thus we allocate one */
2064 /* extra page, which will prevent merging of blocks */
2065 /* in separate regions, and eliminate any temptation */
2066 /* to call VirtualProtect on a range spanning regions. */
2067 /* This wastes a small amount of memory, and risks */
2068 /* increased fragmentation. But better alternatives */
2069 /* would require effort. */
2070 # ifdef MPROTECT_VDB
2071 /* We can't check for GC_incremental here (because */
2072 /* GC_enable_incremental() might be called some time */
2073 /* later after the GC initialization). */
2075 # define VIRTUAL_ALLOC_PAD (GC_GWW_AVAILABLE() ? 0 : 1)
2077 # define VIRTUAL_ALLOC_PAD 1
2080 # define VIRTUAL_ALLOC_PAD 0
2082 /* Pass the MEM_WRITE_WATCH only if GetWriteWatch-based */
2083 /* VDBs are enabled and the GetWriteWatch function is */
2084 /* available. Otherwise we waste resources or possibly */
2085 /* cause VirtualAlloc to fail (observed in Windows 2000 */
2087 result = (ptr_t) VirtualAlloc(NULL, bytes + VIRTUAL_ALLOC_PAD,
2088 GetWriteWatch_alloc_flag |
2089 MEM_COMMIT | MEM_RESERVE
2091 PAGE_EXECUTE_READWRITE);
2093 if (HBLKDISPL(result) != 0) ABORT("Bad VirtualAlloc result");
2094 /* If I read the documentation correctly, this can */
2095 /* only happen if HBLKSIZE > 64k or not a power of 2. */
2096 if (GC_n_heap_bases >= MAX_HEAP_SECTS) ABORT("Too many heap sections");
2097 if (0 != result) GC_heap_bases[GC_n_heap_bases++] = result;
2101 GC_API void GC_CALL GC_win32_free_heap(void)
2103 if (GC_no_win32_dlls) {
2104 while (GC_n_heap_bases > 0) {
2105 GlobalFree (GC_heap_bases[--GC_n_heap_bases]);
2106 GC_heap_bases[GC_n_heap_bases] = 0;
2113 # define GC_AMIGA_AM
2114 # include "extra/AmigaOS.c"
2120 ptr_t GC_wince_get_mem(word bytes)
2122 ptr_t result = 0; /* initialized to prevent warning. */
2125 /* Round up allocation size to multiple of page size */
2126 bytes = (bytes + GC_page_size-1) & ~(GC_page_size-1);
2128 /* Try to find reserved, uncommitted pages */
2129 for (i = 0; i < GC_n_heap_bases; i++) {
2130 if (((word)(-(signed_word)GC_heap_lengths[i])
2131 & (GC_sysinfo.dwAllocationGranularity-1))
2133 result = GC_heap_bases[i] + GC_heap_lengths[i];
2138 if (i == GC_n_heap_bases) {
2139 /* Reserve more pages */
2140 word res_bytes = (bytes + GC_sysinfo.dwAllocationGranularity-1)
2141 & ~(GC_sysinfo.dwAllocationGranularity-1);
2142 /* If we ever support MPROTECT_VDB here, we will probably need to */
2143 /* ensure that res_bytes is strictly > bytes, so that VirtualProtect */
2144 /* never spans regions. It seems to be OK for a VirtualFree */
2145 /* argument to span regions, so we should be OK for now. */
2146 result = (ptr_t) VirtualAlloc(NULL, res_bytes,
2147 MEM_RESERVE | MEM_TOP_DOWN,
2148 PAGE_EXECUTE_READWRITE);
2149 if (HBLKDISPL(result) != 0) ABORT("Bad VirtualAlloc result");
2150 /* If I read the documentation correctly, this can */
2151 /* only happen if HBLKSIZE > 64k or not a power of 2. */
2152 if (GC_n_heap_bases >= MAX_HEAP_SECTS) ABORT("Too many heap sections");
2153 if (result == NULL) return NULL;
2154 GC_heap_bases[GC_n_heap_bases] = result;
2155 GC_heap_lengths[GC_n_heap_bases] = 0;
2160 result = (ptr_t) VirtualAlloc(result, bytes,
2162 PAGE_EXECUTE_READWRITE);
2163 if (result != NULL) {
2164 if (HBLKDISPL(result) != 0) ABORT("Bad VirtualAlloc result");
2165 GC_heap_lengths[i] += bytes;
2174 /* For now, this only works on Win32/WinCE and some Unix-like */
2175 /* systems. If you have something else, don't define */
2178 #if !defined(MSWIN32) && !defined(MSWINCE)
2181 #include <sys/mman.h>
2182 #include <sys/stat.h>
2183 #include <sys/types.h>
2187 /* Compute a page aligned starting address for the unmap */
2188 /* operation on a block of size bytes starting at start. */
2189 /* Return 0 if the block is too small to make this feasible. */
2190 STATIC ptr_t GC_unmap_start(ptr_t start, size_t bytes)
2193 /* Round start to next page boundary. */
2194 result = (ptr_t)((word)(start + GC_page_size - 1) & ~(GC_page_size - 1));
2195 if (result + GC_page_size > start + bytes) return 0;
2199 /* Compute end address for an unmap operation on the indicated */
2201 STATIC ptr_t GC_unmap_end(ptr_t start, size_t bytes)
2203 return (ptr_t)((word)(start + bytes) & ~(GC_page_size - 1));
2206 /* Under Win32/WinCE we commit (map) and decommit (unmap) */
2207 /* memory using VirtualAlloc and VirtualFree. These functions */
2208 /* work on individual allocations of virtual memory, made */
2209 /* previously using VirtualAlloc with the MEM_RESERVE flag. */
2210 /* The ranges we need to (de)commit may span several of these */
2211 /* allocations; therefore we use VirtualQuery to check */
2212 /* allocation lengths, and split up the range as necessary. */
2214 /* We assume that GC_remap is called on exactly the same range */
2215 /* as a previous call to GC_unmap. It is safe to consistently */
2216 /* round the endpoints in both places. */
2217 GC_INNER void GC_unmap(ptr_t start, size_t bytes)
2219 ptr_t start_addr = GC_unmap_start(start, bytes);
2220 ptr_t end_addr = GC_unmap_end(start, bytes);
2221 word len = end_addr - start_addr;
2222 if (0 == start_addr) return;
2223 # if defined(MSWIN32) || defined(MSWINCE)
2225 MEMORY_BASIC_INFORMATION mem_info;
2227 if (VirtualQuery(start_addr, &mem_info, sizeof(mem_info))
2228 != sizeof(mem_info))
2229 ABORT("Weird VirtualQuery result");
2230 free_len = (len < mem_info.RegionSize) ? len : mem_info.RegionSize;
2231 if (!VirtualFree(start_addr, free_len, MEM_DECOMMIT))
2232 ABORT("VirtualFree failed");
2233 GC_unmapped_bytes += free_len;
2234 start_addr += free_len;
2238 /* We immediately remap it to prevent an intervening mmap from */
2239 /* accidentally grabbing the same address space. */
2242 result = mmap(start_addr, len, PROT_NONE,
2243 MAP_PRIVATE | MAP_FIXED | OPT_MAP_ANON,
2244 zero_fd, 0/* offset */);
2245 if (result != (void *)start_addr) ABORT("mmap(...PROT_NONE...) failed");
2247 GC_unmapped_bytes += len;
2251 GC_INNER void GC_remap(ptr_t start, size_t bytes)
2253 ptr_t start_addr = GC_unmap_start(start, bytes);
2254 ptr_t end_addr = GC_unmap_end(start, bytes);
2255 word len = end_addr - start_addr;
2257 /* FIXME: Handle out-of-memory correctly (at least for Win32) */
2258 # if defined(MSWIN32) || defined(MSWINCE)
2261 if (0 == start_addr) return;
2263 MEMORY_BASIC_INFORMATION mem_info;
2265 if (VirtualQuery(start_addr, &mem_info, sizeof(mem_info))
2266 != sizeof(mem_info))
2267 ABORT("Weird VirtualQuery result");
2268 alloc_len = (len < mem_info.RegionSize) ? len : mem_info.RegionSize;
2269 result = VirtualAlloc(start_addr, alloc_len,
2271 PAGE_EXECUTE_READWRITE);
2272 if (result != start_addr) {
2273 if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY ||
2274 GetLastError() == ERROR_OUTOFMEMORY) {
2275 ABORT("Not enough memory to process remapping");
2277 ABORT("VirtualAlloc remapping failed");
2280 GC_unmapped_bytes -= alloc_len;
2281 start_addr += alloc_len;
2285 /* It was already remapped with PROT_NONE. */
2288 if (0 == start_addr) return;
2289 result = mprotect(start_addr, len,
2290 PROT_READ | PROT_WRITE | OPT_PROT_EXEC);
2293 "Mprotect failed at %p (length %ld) with errno %d\n",
2294 start_addr, (unsigned long)len, errno);
2295 ABORT("Mprotect remapping failed");
2297 GC_unmapped_bytes -= len;
2301 /* Two adjacent blocks have already been unmapped and are about to */
2302 /* be merged. Unmap the whole block. This typically requires */
2303 /* that we unmap a small section in the middle that was not previously */
2304 /* unmapped due to alignment constraints. */
2305 GC_INNER void GC_unmap_gap(ptr_t start1, size_t bytes1, ptr_t start2,
2308 ptr_t start1_addr = GC_unmap_start(start1, bytes1);
2309 ptr_t end1_addr = GC_unmap_end(start1, bytes1);
2310 ptr_t start2_addr = GC_unmap_start(start2, bytes2);
2311 ptr_t start_addr = end1_addr;
2312 ptr_t end_addr = start2_addr;
2314 GC_ASSERT(start1 + bytes1 == start2);
2315 if (0 == start1_addr) start_addr = GC_unmap_start(start1, bytes1 + bytes2);
2316 if (0 == start2_addr) end_addr = GC_unmap_end(start1, bytes1 + bytes2);
2317 if (0 == start_addr) return;
2318 len = end_addr - start_addr;
2319 # if defined(MSWIN32) || defined(MSWINCE)
2321 MEMORY_BASIC_INFORMATION mem_info;
2323 if (VirtualQuery(start_addr, &mem_info, sizeof(mem_info))
2324 != sizeof(mem_info))
2325 ABORT("Weird VirtualQuery result");
2326 free_len = (len < mem_info.RegionSize) ? len : mem_info.RegionSize;
2327 if (!VirtualFree(start_addr, free_len, MEM_DECOMMIT))
2328 ABORT("VirtualFree failed");
2329 GC_unmapped_bytes += free_len;
2330 start_addr += free_len;
2335 /* Immediately remap as above. */
2337 result = mmap(start_addr, len, PROT_NONE,
2338 MAP_PRIVATE | MAP_FIXED | OPT_MAP_ANON,
2339 zero_fd, 0/* offset */);
2340 if (result != (void *)start_addr) ABORT("mmap(...PROT_NONE...) failed");
2342 GC_unmapped_bytes += len;
2346 #endif /* USE_MUNMAP */
2348 /* Routine for pushing any additional roots. In THREADS */
2349 /* environment, this is also responsible for marking from */
2350 /* thread stacks. */
2352 GC_INNER void (*GC_push_other_roots)(void) = 0;
2356 PCR_ERes GC_push_thread_stack(PCR_Th_T *t, PCR_Any dummy)
2358 struct PCR_ThCtl_TInfoRep info;
2361 info.ti_stkLow = info.ti_stkHi = 0;
2362 result = PCR_ThCtl_GetInfo(t, &info);
2363 GC_push_all_stack((ptr_t)(info.ti_stkLow), (ptr_t)(info.ti_stkHi));
2367 /* Push the contents of an old object. We treat this as stack */
2368 /* data only because that makes it robust against mark stack */
2370 PCR_ERes GC_push_old_obj(void *p, size_t size, PCR_Any data)
2372 GC_push_all_stack((ptr_t)p, (ptr_t)p + size);
2373 return(PCR_ERes_okay);
2376 extern struct PCR_MM_ProcsRep * GC_old_allocator;
2377 /* defined in pcr_interface.c. */
2379 STATIC void GC_default_push_other_roots(void)
2381 /* Traverse data allocated by previous memory managers. */
2382 if ((*(GC_old_allocator->mmp_enumerate))(PCR_Bool_false,
2385 ABORT("Old object enumeration failed");
2387 /* Traverse all thread stacks. */
2389 PCR_ThCtl_ApplyToAllOtherThreads(GC_push_thread_stack,0))
2390 || PCR_ERes_IsErr(GC_push_thread_stack(PCR_Th_CurrThread(), 0))) {
2391 ABORT("Thread stack marking failed\n");
2398 # if defined(GC_PTHREADS) || defined(GC_WIN32_THREADS)
2400 GC_INNER void GC_push_all_stacks(void);
2402 STATIC void GC_default_push_other_roots(void)
2404 GC_push_all_stacks();
2407 # endif /* GC_WIN32_THREADS || GC_PTHREADS */
2409 GC_INNER void (*GC_push_other_roots)(void) = GC_default_push_other_roots;
2411 #endif /* THREADS */
2414 * Routines for accessing dirty bits on virtual pages.
2415 * There are six ways to maintain this information:
2416 * DEFAULT_VDB: A simple dummy implementation that treats every page
2417 * as possibly dirty. This makes incremental collection
2418 * useless, but the implementation is still correct.
2419 * MANUAL_VDB: Stacks and static data are always considered dirty.
2420 * Heap pages are considered dirty if GC_dirty(p) has been
2421 * called on some pointer p pointing to somewhere inside
2422 * an object on that page. A GC_dirty() call on a large
2423 * object directly dirties only a single page, but for
2424 * MANUAL_VDB we are careful to treat an object with a dirty
2425 * page as completely dirty.
2426 * In order to avoid races, an object must be marked dirty
2427 * after it is written, and a reference to the object
2428 * must be kept on a stack or in a register in the interim.
2429 * With threads enabled, an object directly reachable from the
2430 * stack at the time of a collection is treated as dirty.
2431 * In single-threaded mode, it suffices to ensure that no
2432 * collection can take place between the pointer assignment
2433 * and the GC_dirty() call.
2434 * PCR_VDB: Use PPCRs virtual dirty bit facility.
2435 * PROC_VDB: Use the /proc facility for reading dirty bits. Only
2436 * works under some SVR4 variants. Even then, it may be
2437 * too slow to be entirely satisfactory. Requires reading
2438 * dirty bits for entire address space. Implementations tend
2439 * to assume that the client is a (slow) debugger.
2440 * MPROTECT_VDB:Protect pages and then catch the faults to keep track of
2441 * dirtied pages. The implementation (and implementability)
2442 * is highly system dependent. This usually fails when system
2443 * calls write to a protected page. We prevent the read system
2444 * call from doing so. It is the clients responsibility to
2445 * make sure that other system calls are similarly protected
2446 * or write only to the stack.
2447 * GWW_VDB: Use the Win32 GetWriteWatch functions, if available, to
2448 * read dirty bits. In case it is not available (because we
2449 * are running on Windows 95, Windows 2000 or earlier),
2450 * MPROTECT_VDB may be defined as a fallback strategy.
2452 GC_INNER GC_bool GC_dirty_maintained = FALSE;
2454 #if defined(PROC_VDB) || defined(GWW_VDB)
2456 /* Add all pages in pht2 to pht1 */
2457 STATIC void GC_or_pages(page_hash_table pht1, page_hash_table pht2)
2461 for (i = 0; i < PHT_SIZE; i++) pht1[i] |= pht2[i];
2468 # define GC_GWW_BUF_LEN (MAXHINCR * HBLKSIZE / 4096 /* X86 page size */)
2469 /* Still susceptible to overflow, if there are very large allocations, */
2470 /* and everything is dirty. */
2471 static PVOID gww_buf[GC_GWW_BUF_LEN];
2473 # ifdef MPROTECT_VDB
2474 GC_INNER GC_bool GC_gww_dirty_init(void)
2476 detect_GetWriteWatch();
2477 return GC_GWW_AVAILABLE();
2480 GC_INNER void GC_dirty_init(void)
2482 detect_GetWriteWatch();
2483 GC_dirty_maintained = GC_GWW_AVAILABLE();
2487 # ifdef MPROTECT_VDB
2488 STATIC void GC_gww_read_dirty(void)
2490 GC_INNER void GC_read_dirty(void)
2495 BZERO(GC_grungy_pages, sizeof(GC_grungy_pages));
2497 for (i = 0; i != GC_n_heap_sects; ++i) {
2501 PVOID * pages, * pages_end;
2505 count = GC_GWW_BUF_LEN;
2507 * GetWriteWatch is documented as returning non-zero when it fails,
2508 * but the documentation doesn't explicitly say why it would fail or
2509 * what its behaviour will be if it fails.
2510 * It does appear to fail, at least on recent W2K instances, if
2511 * the underlying memory was not allocated with the appropriate
2512 * flag. This is common if GC_enable_incremental is called
2513 * shortly after GC initialization. To avoid modifying the
2514 * interface, we silently work around such a failure, it it only
2515 * affects the initial (small) heap allocation.
2516 * If there are more dirty
2517 * pages than will fit in the buffer, this is not treated as a
2518 * failure; we must check the page count in the loop condition.
2519 * Since each partial call will reset the status of some
2520 * pages, this should eventually terminate even in the overflow
2523 if (GetWriteWatch_func(WRITE_WATCH_FLAG_RESET,
2524 GC_heap_sects[i].hs_start,
2525 GC_heap_sects[i].hs_bytes,
2529 static int warn_count = 0;
2531 struct hblk * start = (struct hblk *)GC_heap_sects[i].hs_start;
2532 static struct hblk *last_warned = 0;
2533 size_t nblocks = divHBLKSZ(GC_heap_sects[i].hs_bytes);
2535 if ( i != 0 && last_warned != start && warn_count++ < 5) {
2536 last_warned = start;
2538 "GC_gww_read_dirty unexpectedly failed at %p: "
2539 "Falling back to marking all pages dirty\n", start);
2541 for (j = 0; j < nblocks; ++j) {
2542 word hash = PHT_HASH(start + j);
2543 set_pht_entry_from_index(GC_grungy_pages, hash);
2545 count = 1; /* Done with this section. */
2546 } else /* succeeded */{
2547 pages_end = pages + count;
2548 while (pages != pages_end) {
2549 struct hblk * h = (struct hblk *) *pages++;
2550 struct hblk * h_end = (struct hblk *) ((char *) h + page_size);
2552 set_pht_entry_from_index(GC_grungy_pages, PHT_HASH(h));
2553 while (++h < h_end);
2556 } while (count == GC_GWW_BUF_LEN);
2557 /* FIXME: It's unclear from Microsoft's documentation if this loop */
2558 /* is useful. We suspect the call just fails if the buffer fills */
2559 /* up. But that should still be handled correctly. */
2562 GC_or_pages(GC_written_pages, GC_grungy_pages);
2565 # ifdef MPROTECT_VDB
2566 STATIC GC_bool GC_gww_page_was_dirty(struct hblk * h)
2568 GC_INNER GC_bool GC_page_was_dirty(struct hblk * h)
2571 return HDR(h) == 0 ||
2572 get_pht_entry_from_index(GC_grungy_pages, PHT_HASH(h));
2576 /* Used only if PROC_VDB. */
2577 # ifdef MPROTECT_VDB
2578 STATIC GC_bool GC_gww_page_was_ever_dirty(struct hblk * h)
2580 GC_INNER GC_bool GC_page_was_ever_dirty(struct hblk * h)
2583 return HDR(h) == 0 ||
2584 get_pht_entry_from_index(GC_written_pages, PHT_HASH(h));
2588 # ifndef MPROTECT_VDB
2590 GC_INNER void GC_remove_protection(struct hblk *h, word nblocks,
2591 GC_bool is_ptrfree) {}
2594 # endif /* GWW_VDB */
2598 /* All of the following assume the allocation lock is held. */
2600 /* The client asserts that unallocated pages in the heap are never */
2603 /* Initialize virtual dirty bit implementation. */
2604 GC_INNER void GC_dirty_init(void)
2606 if (GC_print_stats == VERBOSE)
2607 GC_log_printf("Initializing DEFAULT_VDB...\n");
2608 GC_dirty_maintained = TRUE;
2611 /* Retrieve system dirty bits for heap to a local buffer. */
2612 /* Restore the systems notion of which pages are dirty. */
2613 GC_INNER void GC_read_dirty(void) {}
2615 /* Is the HBLKSIZE sized page at h marked dirty in the local buffer? */
2616 /* If the actual page size is different, this returns TRUE if any */
2617 /* of the pages overlapping h are dirty. This routine may err on the */
2618 /* side of labeling pages as dirty (and this implementation does). */
2620 GC_INNER GC_bool GC_page_was_dirty(struct hblk *h)
2626 * The following two routines are typically less crucial. They matter
2627 * most with large dynamic libraries, or if we can't accurately identify
2628 * stacks, e.g. under Solaris 2.X. Otherwise the following default
2629 * versions are adequate.
2633 /* Could any valid GC heap pointer ever have been written to this page? */
2635 GC_INNER GC_bool GC_page_was_ever_dirty(struct hblk *h)
2642 /* I) hints that [h, h+nblocks) is about to be written. */
2643 /* II) guarantees that protection is removed. */
2644 /* (I) may speed up some dirty bit implementations. */
2645 /* (II) may be essential if we need to ensure that */
2646 /* pointer-free system call buffers in the heap are */
2647 /* not protected. */
2649 GC_INNER void GC_remove_protection(struct hblk *h, word nblocks,
2650 GC_bool is_ptrfree) {}
2652 # endif /* DEFAULT_VDB */
2656 /* Initialize virtual dirty bit implementation. */
2657 GC_INNER void GC_dirty_init(void)
2659 if (GC_print_stats == VERBOSE)
2660 GC_log_printf("Initializing MANUAL_VDB...\n");
2661 /* GC_dirty_pages and GC_grungy_pages are already cleared. */
2662 GC_dirty_maintained = TRUE;
2665 /* Retrieve system dirty bits for heap to a local buffer. */
2666 /* Restore the systems notion of which pages are dirty. */
2667 GC_INNER void GC_read_dirty(void)
2669 BCOPY((word *)GC_dirty_pages, GC_grungy_pages,
2670 (sizeof GC_dirty_pages));
2671 BZERO((word *)GC_dirty_pages, (sizeof GC_dirty_pages));
2674 /* Is the HBLKSIZE sized page at h marked dirty in the local buffer? */
2675 /* If the actual page size is different, this returns TRUE if any */
2676 /* of the pages overlapping h are dirty. This routine may err on the */
2677 /* side of labeling pages as dirty (and this implementation does). */
2678 GC_INNER GC_bool GC_page_was_dirty(struct hblk *h)
2680 register word index;
2682 index = PHT_HASH(h);
2683 return(HDR(h) == 0 || get_pht_entry_from_index(GC_grungy_pages, index));
2686 /* Mark the page containing p as dirty. Logically, this dirties the */
2687 /* entire object. */
2688 void GC_dirty(ptr_t p)
2690 word index = PHT_HASH(p);
2691 async_set_pht_entry_from_index(GC_dirty_pages, index);
2695 GC_INNER void GC_remove_protection(struct hblk *h, word nblocks,
2696 GC_bool is_ptrfree) {}
2698 # endif /* MANUAL_VDB */
2701 # ifdef MPROTECT_VDB
2704 * See DEFAULT_VDB for interface descriptions.
2708 * This implementation maintains dirty bits itself by catching write
2709 * faults and keeping track of them. We assume nobody else catches
2710 * SIGBUS or SIGSEGV. We assume no write faults occur in system calls.
2711 * This means that clients must ensure that system calls don't write
2712 * to the write-protected heap. Probably the best way to do this is to
2713 * ensure that system calls write at most to POINTERFREE objects in the
2714 * heap, and do even that only if we are on a platform on which those
2715 * are not protected. Another alternative is to wrap system calls
2716 * (see example for read below), but the current implementation holds
2718 * We assume the page size is a multiple of HBLKSIZE.
2719 * We prefer them to be the same. We avoid protecting POINTERFREE
2720 * objects only if they are the same.
2723 # if !defined(MSWIN32) && !defined(MSWINCE) && !defined(DARWIN)
2725 # include <sys/mman.h>
2726 # include <signal.h>
2727 # include <sys/syscall.h>
2729 # define PROTECT(addr, len) \
2730 if (mprotect((caddr_t)(addr), (size_t)(len), \
2731 PROT_READ | OPT_PROT_EXEC) < 0) { \
2732 ABORT("mprotect failed"); \
2734 # define UNPROTECT(addr, len) \
2735 if (mprotect((caddr_t)(addr), (size_t)(len), \
2736 PROT_WRITE | PROT_READ | OPT_PROT_EXEC ) < 0) { \
2737 ABORT("un-mprotect failed"); \
2743 /* Using vm_protect (mach syscall) over mprotect (BSD syscall) seems to
2744 decrease the likelihood of some of the problems described below. */
2745 # include <mach/vm_map.h>
2746 STATIC mach_port_t GC_task_self = 0;
2747 # define PROTECT(addr,len) \
2748 if(vm_protect(GC_task_self,(vm_address_t)(addr),(vm_size_t)(len), \
2749 FALSE,VM_PROT_READ) != KERN_SUCCESS) { \
2750 ABORT("vm_protect (PROTECT) failed"); \
2752 # define UNPROTECT(addr,len) \
2753 if(vm_protect(GC_task_self,(vm_address_t)(addr),(vm_size_t)(len), \
2754 FALSE,VM_PROT_READ|VM_PROT_WRITE) != KERN_SUCCESS) { \
2755 ABORT("vm_protect (UNPROTECT) failed"); \
2760 # include <signal.h>
2763 static DWORD protect_junk;
2764 # define PROTECT(addr, len) \
2765 if (!VirtualProtect((addr), (len), PAGE_EXECUTE_READ, \
2767 GC_printf("Last error code: 0x%lx\n", (long)GetLastError()); \
2768 ABORT("VirtualProtect failed"); \
2770 # define UNPROTECT(addr, len) \
2771 if (!VirtualProtect((addr), (len), PAGE_EXECUTE_READWRITE, \
2773 ABORT("un-VirtualProtect failed"); \
2775 # endif /* !DARWIN */
2776 # endif /* MSWIN32 || MSWINCE || DARWIN */
2778 #if defined(MSWIN32)
2779 typedef LPTOP_LEVEL_EXCEPTION_FILTER SIG_HNDLR_PTR;
2781 # define SIG_DFL (LPTOP_LEVEL_EXCEPTION_FILTER)((signed_word)-1)
2782 #elif defined(MSWINCE)
2783 typedef LONG (WINAPI *SIG_HNDLR_PTR)(struct _EXCEPTION_POINTERS *);
2785 # define SIG_DFL (SIG_HNDLR_PTR) (-1)
2786 #elif defined(DARWIN)
2787 typedef void (* SIG_HNDLR_PTR)();
2789 typedef void (* SIG_HNDLR_PTR)(int, siginfo_t *, void *);
2790 typedef void (* PLAIN_HNDLR_PTR)(int);
2793 #if defined(__GLIBC__)
2794 # if __GLIBC__ < 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ < 2
2795 # error glibc too old?
2800 STATIC SIG_HNDLR_PTR GC_old_segv_handler = 0;
2801 /* Also old MSWIN32 ACCESS_VIOLATION filter */
2802 # if !defined(MSWIN32) && !defined(MSWINCE)
2803 STATIC SIG_HNDLR_PTR GC_old_bus_handler = 0;
2804 STATIC GC_bool GC_old_bus_handler_used_si = FALSE;
2805 STATIC GC_bool GC_old_segv_handler_used_si = FALSE;
2807 #endif /* !DARWIN */
2809 #if defined(THREADS)
2810 /* We need to lock around the bitmap update in the write fault handler */
2811 /* in order to avoid the risk of losing a bit. We do this with a */
2812 /* test-and-set spin lock if we know how to do that. Otherwise we */
2813 /* check whether we are already in the handler and use the dumb but */
2814 /* safe fallback algorithm of setting all bits in the word. */
2815 /* Contention should be very rare, so we do the minimum to handle it */
2817 #ifdef AO_HAVE_test_and_set_acquire
2818 GC_INNER volatile AO_TS_t GC_fault_handler_lock = AO_TS_INITIALIZER;
2819 static void async_set_pht_entry_from_index(volatile page_hash_table db,
2822 while (AO_test_and_set_acquire(&GC_fault_handler_lock) == AO_TS_SET) {
2825 /* Could also revert to set_pht_entry_from_index_safe if initial */
2826 /* GC_test_and_set fails. */
2827 set_pht_entry_from_index(db, index);
2828 AO_CLEAR(&GC_fault_handler_lock);
2830 #else /* !AO_HAVE_test_and_set_acquire */
2831 # error No test_and_set operation: Introduces a race.
2832 /* THIS WOULD BE INCORRECT! */
2833 /* The dirty bit vector may be temporarily wrong, */
2834 /* just before we notice the conflict and correct it. We may end up */
2835 /* looking at it while it's wrong. But this requires contention */
2836 /* exactly when a GC is triggered, which seems far less likely to */
2837 /* fail than the old code, which had no reported failures. Thus we */
2838 /* leave it this way while we think of something better, or support */
2839 /* GC_test_and_set on the remaining platforms. */
2840 static volatile word currently_updating = 0;
2841 static void async_set_pht_entry_from_index(volatile page_hash_table db,
2844 unsigned int update_dummy;
2845 currently_updating = (word)(&update_dummy);
2846 set_pht_entry_from_index(db, index);
2847 /* If we get contention in the 10 or so instruction window here, */
2848 /* and we get stopped by a GC between the two updates, we lose! */
2849 if (currently_updating != (word)(&update_dummy)) {
2850 set_pht_entry_from_index_safe(db, index);
2851 /* We claim that if two threads concurrently try to update the */
2852 /* dirty bit vector, the first one to execute UPDATE_START */
2853 /* will see it changed when UPDATE_END is executed. (Note that */
2854 /* &update_dummy must differ in two distinct threads.) It */
2855 /* will then execute set_pht_entry_from_index_safe, thus */
2856 /* returning us to a safe state, though not soon enough. */
2859 #endif /* !AO_HAVE_test_and_set_acquire */
2860 #else /* !THREADS */
2861 # define async_set_pht_entry_from_index(db, index) \
2862 set_pht_entry_from_index(db, index)
2863 #endif /* !THREADS */
2866 void GC_record_fault(struct hblk * h);
2867 /* From checksums.c */
2870 #if !defined(DARWIN)
2872 # if defined(FREEBSD)
2873 # define SIG_OK TRUE
2874 # define CODE_OK (si -> si_code == BUS_PAGE_FAULT)
2875 # elif defined(OSF1)
2876 # define SIG_OK (sig == SIGSEGV)
2877 # define CODE_OK (si -> si_code == 2 /* experimentally determined */)
2878 # elif defined(IRIX5)
2879 # define SIG_OK (sig == SIGSEGV)
2880 # define CODE_OK (si -> si_code == EACCES)
2881 # elif defined(HURD)
2882 # define SIG_OK (sig == SIGBUS || sig == SIGSEGV)
2883 # define CODE_OK TRUE
2884 # elif defined(LINUX)
2885 # define SIG_OK (sig == SIGSEGV)
2886 # define CODE_OK TRUE
2887 /* Empirically c.trapno == 14, on IA32, but is that useful? */
2888 /* Should probably consider alignment issues on other */
2889 /* architectures. */
2890 # elif defined(HPUX)
2891 # define SIG_OK (sig == SIGSEGV || sig == SIGBUS)
2892 # define CODE_OK (si -> si_code == SEGV_ACCERR) \
2893 || (si -> si_code == BUS_ADRERR) \
2894 || (si -> si_code == BUS_UNKNOWN) \
2895 || (si -> si_code == SEGV_UNKNOWN) \
2896 || (si -> si_code == BUS_OBJERR)
2897 # elif defined(SUNOS5SIGS)
2898 # define SIG_OK (sig == SIGSEGV)
2899 # define CODE_OK (si -> si_code == SEGV_ACCERR)
2900 # elif defined(MSWIN32) || defined(MSWINCE)
2901 # define SIG_OK (exc_info -> ExceptionRecord -> ExceptionCode \
2902 == STATUS_ACCESS_VIOLATION)
2903 # define CODE_OK (exc_info -> ExceptionRecord -> ExceptionInformation[0] \
2904 == 1) /* Write fault */
2907 # if defined(MSWIN32) || defined(MSWINCE)
2908 GC_INNER LONG WINAPI GC_write_fault_handler(
2909 struct _EXCEPTION_POINTERS *exc_info)
2911 # include <ucontext.h>
2913 STATIC void GC_write_fault_handler(int sig, siginfo_t *si, void *raw_sc)
2914 # endif /* MSWIN32 || MSWINCE */
2916 # if !defined(MSWIN32) && !defined(MSWINCE)
2917 char *addr = si -> si_addr;
2919 char * addr = (char *) (exc_info -> ExceptionRecord
2920 -> ExceptionInformation[1]);
2924 if (SIG_OK && CODE_OK) {
2925 register struct hblk * h =
2926 (struct hblk *)((word)addr & ~(GC_page_size-1));
2927 GC_bool in_allocd_block;
2930 # endif /* CHECKSUMS */
2933 /* Address is only within the correct physical page. */
2934 in_allocd_block = FALSE;
2935 for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
2936 if (HDR(h+i) != 0) {
2937 in_allocd_block = TRUE;
2941 in_allocd_block = (HDR(addr) != 0);
2943 if (!in_allocd_block) {
2944 /* FIXME - We should make sure that we invoke the */
2945 /* old handler with the appropriate calling */
2946 /* sequence, which often depends on SA_SIGINFO. */
2948 /* Heap blocks now begin and end on page boundaries */
2949 SIG_HNDLR_PTR old_handler;
2951 # if defined(MSWIN32) || defined(MSWINCE)
2952 old_handler = GC_old_segv_handler;
2956 if (sig == SIGSEGV) {
2957 old_handler = GC_old_segv_handler;
2958 used_si = GC_old_segv_handler_used_si;
2960 old_handler = GC_old_bus_handler;
2961 used_si = GC_old_bus_handler_used_si;
2965 if (old_handler == (SIG_HNDLR_PTR)SIG_DFL) {
2966 # if !defined(MSWIN32) && !defined(MSWINCE)
2967 GC_err_printf("Segfault at %p\n", addr);
2968 ABORT("Unexpected bus error or segmentation fault");
2970 return(EXCEPTION_CONTINUE_SEARCH);
2974 * FIXME: This code should probably check if the
2975 * old signal handler used the traditional style and
2976 * if so call it using that style.
2978 # if defined(MSWIN32) || defined(MSWINCE)
2979 return((*old_handler)(exc_info));
2982 ((SIG_HNDLR_PTR)old_handler) (sig, si, raw_sc);
2984 /* FIXME: should pass nonstandard args as well. */
2985 ((PLAIN_HNDLR_PTR)old_handler) (sig);
2990 UNPROTECT(h, GC_page_size);
2991 /* We need to make sure that no collection occurs between */
2992 /* the UNPROTECT and the setting of the dirty bit. Otherwise */
2993 /* a write by a third thread might go unnoticed. Reversing */
2994 /* the order is just as bad, since we would end up unprotecting */
2995 /* a page in a GC cycle during which it's not marked. */
2996 /* Currently we do this by disabling the thread stopping */
2997 /* signals while this handler is running. An alternative might */
2998 /* be to record the fact that we're about to unprotect, or */
2999 /* have just unprotected a page in the GC's thread structure, */
3000 /* and then to have the thread stopping code set the dirty */
3001 /* flag, if necessary. */
3002 for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
3003 size_t index = PHT_HASH(h+i);
3005 async_set_pht_entry_from_index(GC_dirty_pages, index);
3007 /* The write may not take place before dirty bits are read. */
3008 /* But then we'll fault again ... */
3009 # if defined(MSWIN32) || defined(MSWINCE)
3010 return(EXCEPTION_CONTINUE_EXECUTION);
3015 #if defined(MSWIN32) || defined(MSWINCE)
3016 return EXCEPTION_CONTINUE_SEARCH;
3018 GC_err_printf("Segfault at %p\n", addr);
3019 ABORT("Unexpected bus error or segmentation fault");
3022 #endif /* !DARWIN */
3025 * We hold the allocation lock. We expect block h to be written
3026 * shortly. Ensure that all pages containing any part of the n hblks
3027 * starting at h are no longer protected. If is_ptrfree is false,
3028 * also ensure that they will subsequently appear to be dirty.
3029 * Not allowed to call GC_printf (and the friends) here, see Win32
3030 * GC_stop_world() for the information.
3032 GC_INNER void GC_remove_protection(struct hblk *h, word nblocks,
3035 struct hblk * h_trunc; /* Truncated to page boundary */
3036 struct hblk * h_end; /* Page boundary following block end */
3037 struct hblk * current;
3039 # if defined(GWW_VDB)
3040 if (GC_GWW_AVAILABLE()) return;
3042 if (!GC_dirty_maintained) return;
3043 h_trunc = (struct hblk *)((word)h & ~(GC_page_size-1));
3044 h_end = (struct hblk *)(((word)(h + nblocks) + GC_page_size-1)
3045 & ~(GC_page_size-1));
3046 if (h_end == h_trunc + 1 &&
3047 get_pht_entry_from_index(GC_dirty_pages, PHT_HASH(h_trunc))) {
3048 /* already marked dirty, and hence unprotected. */
3051 for (current = h_trunc; current < h_end; ++current) {
3052 size_t index = PHT_HASH(current);
3053 if (!is_ptrfree || current < h || current >= h + nblocks) {
3054 async_set_pht_entry_from_index(GC_dirty_pages, index);
3057 UNPROTECT(h_trunc, (ptr_t)h_end - (ptr_t)h_trunc);
3060 #if !defined(DARWIN)
3061 GC_INNER void GC_dirty_init(void)
3063 # if !defined(MSWIN32) && !defined(MSWINCE)
3064 struct sigaction act, oldact;
3065 act.sa_flags = SA_RESTART | SA_SIGINFO;
3066 act.sa_sigaction = GC_write_fault_handler;
3067 (void)sigemptyset(&act.sa_mask);
3069 /* Arrange to postpone SIG_SUSPEND while we're in a write fault */
3070 /* handler. This effectively makes the handler atomic w.r.t. */
3071 /* stopping the world for GC. */
3072 (void)sigaddset(&act.sa_mask, SIG_SUSPEND);
3073 # endif /* SIG_SUSPEND */
3075 if (GC_print_stats == VERBOSE)
3077 "Initializing mprotect virtual dirty bit implementation\n");
3078 GC_dirty_maintained = TRUE;
3079 if (GC_page_size % HBLKSIZE != 0) {
3080 GC_err_printf("Page size not multiple of HBLKSIZE\n");
3081 ABORT("Page size not multiple of HBLKSIZE");
3083 # if !defined(MSWIN32) && !defined(MSWINCE)
3084 # if defined(GC_IRIX_THREADS)
3085 sigaction(SIGSEGV, 0, &oldact);
3086 sigaction(SIGSEGV, &act, 0);
3089 int res = sigaction(SIGSEGV, &act, &oldact);
3090 if (res != 0) ABORT("Sigaction failed");
3093 if (oldact.sa_flags & SA_SIGINFO) {
3094 GC_old_segv_handler = oldact.sa_sigaction;
3095 GC_old_segv_handler_used_si = TRUE;
3097 GC_old_segv_handler = (SIG_HNDLR_PTR)oldact.sa_handler;
3098 GC_old_segv_handler_used_si = FALSE;
3100 if (GC_old_segv_handler == (SIG_HNDLR_PTR)SIG_IGN) {
3101 GC_err_printf("Previously ignored segmentation violation!?\n");
3102 GC_old_segv_handler = (SIG_HNDLR_PTR)SIG_DFL;
3104 if (GC_old_segv_handler != (SIG_HNDLR_PTR)SIG_DFL) {
3105 if (GC_print_stats == VERBOSE)
3106 GC_log_printf("Replaced other SIGSEGV handler\n");
3108 # if defined(HPUX) || defined(LINUX) || defined(HURD) \
3109 || (defined(FREEBSD) && defined(SUNOS5SIGS))
3110 sigaction(SIGBUS, &act, &oldact);
3111 if (oldact.sa_flags & SA_SIGINFO) {
3112 GC_old_bus_handler = oldact.sa_sigaction;
3113 GC_old_bus_handler_used_si = TRUE;
3115 GC_old_bus_handler = (SIG_HNDLR_PTR)oldact.sa_handler;
3116 GC_old_bus_handler_used_si = FALSE;
3118 if (GC_old_bus_handler == (SIG_HNDLR_PTR)SIG_IGN) {
3119 GC_err_printf("Previously ignored bus error!?\n");
3120 GC_old_bus_handler = (SIG_HNDLR_PTR)SIG_DFL;
3122 if (GC_old_bus_handler != (SIG_HNDLR_PTR)SIG_DFL) {
3123 if (GC_print_stats == VERBOSE)
3124 GC_log_printf("Replaced other SIGBUS handler\n");
3126 # endif /* HPUX || LINUX || HURD || (FREEBSD && SUNOS5SIGS) */
3127 # endif /* ! MS windows */
3128 # if defined(GWW_VDB)
3129 if (GC_gww_dirty_init())
3132 # if defined(MSWIN32)
3133 GC_old_segv_handler = SetUnhandledExceptionFilter(GC_write_fault_handler);
3134 if (GC_old_segv_handler != NULL) {
3136 GC_log_printf("Replaced other UnhandledExceptionFilter\n");
3138 GC_old_segv_handler = SIG_DFL;
3140 # elif defined(MSWINCE)
3141 /* MPROTECT_VDB is unsupported for WinCE at present. */
3142 /* FIXME: implement it (if possible). */
3145 #endif /* !DARWIN */
3147 GC_API int GC_CALL GC_incremental_protection_needs(void)
3149 if (GC_page_size == HBLKSIZE) {
3150 return GC_PROTECTS_POINTER_HEAP;
3152 return GC_PROTECTS_POINTER_HEAP | GC_PROTECTS_PTRFREE_HEAP;
3156 #define HAVE_INCREMENTAL_PROTECTION_NEEDS
3158 #define IS_PTRFREE(hhdr) ((hhdr)->hb_descr == 0)
3160 #define PAGE_ALIGNED(x) !((word)(x) & (GC_page_size - 1))
3161 STATIC void GC_protect_heap(void)
3165 struct hblk * current;
3166 struct hblk * current_start; /* Start of block to be protected. */
3167 struct hblk * limit;
3169 GC_bool protect_all =
3170 (0 != (GC_incremental_protection_needs() & GC_PROTECTS_PTRFREE_HEAP));
3171 for (i = 0; i < GC_n_heap_sects; i++) {
3172 start = GC_heap_sects[i].hs_start;
3173 len = GC_heap_sects[i].hs_bytes;
3175 PROTECT(start, len);
3177 GC_ASSERT(PAGE_ALIGNED(len))
3178 GC_ASSERT(PAGE_ALIGNED(start))
3179 current_start = current = (struct hblk *)start;
3180 limit = (struct hblk *)(start + len);
3181 while (current < limit) {
3186 GC_ASSERT(PAGE_ALIGNED(current));
3187 GET_HDR(current, hhdr);
3188 if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
3189 /* This can happen only if we're at the beginning of a */
3190 /* heap segment, and a block spans heap segments. */
3191 /* We will handle that block as part of the preceding */
3193 GC_ASSERT(current_start == current);
3194 current_start = ++current;
3197 if (HBLK_IS_FREE(hhdr)) {
3198 GC_ASSERT(PAGE_ALIGNED(hhdr -> hb_sz));
3199 nhblks = divHBLKSZ(hhdr -> hb_sz);
3200 is_ptrfree = TRUE; /* dirty on alloc */
3202 nhblks = OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz);
3203 is_ptrfree = IS_PTRFREE(hhdr);
3206 if (current_start < current) {
3207 PROTECT(current_start, (ptr_t)current - (ptr_t)current_start);
3209 current_start = (current += nhblks);
3214 if (current_start < current) {
3215 PROTECT(current_start, (ptr_t)current - (ptr_t)current_start);
3221 /* We assume that either the world is stopped or its OK to lose dirty */
3222 /* bits while this is happenning (as in GC_enable_incremental). */
3223 GC_INNER void GC_read_dirty(void)
3225 # if defined(GWW_VDB)
3226 if (GC_GWW_AVAILABLE()) {
3227 GC_gww_read_dirty();
3231 BCOPY((word *)GC_dirty_pages, GC_grungy_pages,
3232 (sizeof GC_dirty_pages));
3233 BZERO((word *)GC_dirty_pages, (sizeof GC_dirty_pages));
3237 GC_INNER GC_bool GC_page_was_dirty(struct hblk *h)
3239 register word index;
3241 # if defined(GWW_VDB)
3242 if (GC_GWW_AVAILABLE())
3243 return GC_gww_page_was_dirty(h);
3246 index = PHT_HASH(h);
3247 return(HDR(h) == 0 || get_pht_entry_from_index(GC_grungy_pages, index));
3251 * Acquiring the allocation lock here is dangerous, since this
3252 * can be called from within GC_call_with_alloc_lock, and the cord
3253 * package does so. On systems that allow nested lock acquisition, this
3255 * On other systems, SET_LOCK_HOLDER and friends must be suitably defined.
3259 static GC_bool syscall_acquired_lock = FALSE; /* Protected by GC lock. */
3261 void GC_begin_syscall(void)
3263 /* FIXME: Resurrecting this code would require fixing the */
3264 /* test, which can spuriously return TRUE. */
3265 if (!I_HOLD_LOCK()) {
3267 syscall_acquired_lock = TRUE;
3271 void GC_end_syscall(void)
3273 if (syscall_acquired_lock) {
3274 syscall_acquired_lock = FALSE;
3279 void GC_unprotect_range(ptr_t addr, word len)
3281 struct hblk * start_block;
3282 struct hblk * end_block;
3283 register struct hblk *h;
3286 if (!GC_dirty_maintained) return;
3287 obj_start = GC_base(addr);
3288 if (obj_start == 0) return;
3289 if (GC_base(addr + len - 1) != obj_start) {
3290 ABORT("GC_unprotect_range(range bigger than object)");
3292 start_block = (struct hblk *)((word)addr & ~(GC_page_size - 1));
3293 end_block = (struct hblk *)((word)(addr + len - 1) & ~(GC_page_size - 1));
3294 end_block += GC_page_size/HBLKSIZE - 1;
3295 for (h = start_block; h <= end_block; h++) {
3296 register word index = PHT_HASH(h);
3298 async_set_pht_entry_from_index(GC_dirty_pages, index);
3300 UNPROTECT(start_block,
3301 ((ptr_t)end_block - (ptr_t)start_block) + HBLKSIZE);
3305 /* We no longer wrap read by default, since that was causing too many */
3306 /* problems. It is preferred that the client instead avoids writing */
3307 /* to the write-protected heap with a system call. */
3308 /* This still serves as sample code if you do want to wrap system calls.*/
3310 #if !defined(MSWIN32) && !defined(MSWINCE) && !defined(GC_USE_LD_WRAP)
3311 /* Replacement for UNIX system call. */
3312 /* Other calls that write to the heap should be handled similarly. */
3313 /* Note that this doesn't work well for blocking reads: It will hold */
3314 /* the allocation lock for the entire duration of the call. Multithreaded */
3315 /* clients should really ensure that it won't block, either by setting */
3316 /* the descriptor nonblocking, or by calling select or poll first, to */
3317 /* make sure that input is available. */
3318 /* Another, preferred alternative is to ensure that system calls never */
3319 /* write to the protected heap (see above). */
3320 # include <unistd.h>
3321 # include <sys/uio.h>
3322 ssize_t read(int fd, void *buf, size_t nbyte)
3327 GC_unprotect_range(buf, (word)nbyte);
3328 # if defined(IRIX5) || defined(GC_LINUX_THREADS)
3329 /* Indirect system call may not always be easily available. */
3330 /* We could call _read, but that would interfere with the */
3331 /* libpthread interception of read. */
3332 /* On Linux, we have to be careful with the linuxthreads */
3333 /* read interception. */
3338 iov.iov_len = nbyte;
3339 result = readv(fd, &iov, 1);
3343 result = __read(fd, buf, nbyte);
3345 /* The two zero args at the end of this list are because one
3346 IA-64 syscall() implementation actually requires six args
3347 to be passed, even though they aren't always used. */
3348 result = syscall(SYS_read, fd, buf, nbyte, 0, 0);
3354 #endif /* !MSWIN32 && !MSWINCE && !GC_LINUX_THREADS */
3356 #if defined(GC_USE_LD_WRAP) && !defined(THREADS)
3357 /* We use the GNU ld call wrapping facility. */
3358 /* This requires that the linker be invoked with "--wrap read". */
3359 /* This can be done by passing -Wl,"--wrap read" to gcc. */
3360 /* I'm not sure that this actually wraps whatever version of read */
3361 /* is called by stdio. That code also mentions __read. */
3362 # include <unistd.h>
3363 ssize_t __wrap_read(int fd, void *buf, size_t nbyte)
3368 GC_unprotect_range(buf, (word)nbyte);
3369 result = __real_read(fd, buf, nbyte);
3374 /* We should probably also do this for __read, or whatever stdio */
3375 /* actually calls. */
3379 GC_INNER GC_bool GC_page_was_ever_dirty(struct hblk *h)
3381 # if defined(GWW_VDB)
3382 if (GC_GWW_AVAILABLE())
3383 return GC_gww_page_was_ever_dirty(h);
3390 # endif /* MPROTECT_VDB */
3395 * See DEFAULT_VDB for interface descriptions.
3399 * This implementation assumes a Solaris 2.X like /proc pseudo-file-system
3400 * from which we can read page modified bits. This facility is far from
3401 * optimal (e.g. we would like to get the info for only some of the
3402 * address space), but it avoids intercepting system calls.
3406 #include <sys/types.h>
3407 #include <sys/signal.h>
3408 #include <sys/fault.h>
3409 #include <sys/syscall.h>
3410 #include <sys/procfs.h>
3411 #include <sys/stat.h>
3413 #define INITIAL_BUF_SZ 16384
3414 STATIC word GC_proc_buf_size = INITIAL_BUF_SZ;
3415 STATIC char *GC_proc_buf = NULL;
3417 STATIC int GC_proc_fd = 0;
3419 GC_INNER void GC_dirty_init(void)
3424 GC_dirty_maintained = TRUE;
3425 if (GC_bytes_allocd != 0 || GC_bytes_allocd_before_gc != 0) {
3428 for (i = 0; i < PHT_SIZE; i++) GC_written_pages[i] = (word)(-1);
3429 if (GC_print_stats == VERBOSE)
3431 "Allocated bytes:%lu:all pages may have been written\n",
3433 (GC_bytes_allocd + GC_bytes_allocd_before_gc));
3435 sprintf(buf, "/proc/%ld", (long)getpid());
3436 fd = open(buf, O_RDONLY);
3438 ABORT("/proc open failed");
3440 GC_proc_fd = syscall(SYS_ioctl, fd, PIOCOPENPD, 0);
3442 syscall(SYS_fcntl, GC_proc_fd, F_SETFD, FD_CLOEXEC);
3443 if (GC_proc_fd < 0) {
3444 ABORT("/proc ioctl failed");
3446 GC_proc_buf = GC_scratch_alloc(GC_proc_buf_size);
3449 /* Ignore write hints. They don't help us here. */
3451 GC_INNER void GC_remove_protection(struct hblk *h, word nblocks,
3452 GC_bool is_ptrfree) {}
3454 # define READ(fd,buf,nbytes) read(fd, buf, nbytes)
3456 GC_INNER void GC_read_dirty(void)
3458 unsigned long ps, np;
3461 struct prasmap * map;
3463 ptr_t current_addr, limit;
3466 BZERO(GC_grungy_pages, (sizeof GC_grungy_pages));
3469 if (READ(GC_proc_fd, bufp, GC_proc_buf_size) <= 0) {
3471 GC_log_printf("/proc read failed: GC_proc_buf_size = %lu\n",
3472 (unsigned long)GC_proc_buf_size);
3474 /* Retry with larger buffer. */
3475 word new_size = 2 * GC_proc_buf_size;
3476 char * new_buf = GC_scratch_alloc(new_size);
3479 GC_proc_buf = bufp = new_buf;
3480 GC_proc_buf_size = new_size;
3482 if (READ(GC_proc_fd, bufp, GC_proc_buf_size) <= 0) {
3483 WARN("Insufficient space for /proc read\n", 0);
3485 memset(GC_grungy_pages, 0xff, sizeof (page_hash_table));
3486 memset(GC_written_pages, 0xff, sizeof(page_hash_table));
3491 /* Copy dirty bits into GC_grungy_pages */
3492 nmaps = ((struct prpageheader *)bufp) -> pr_nmap;
3493 /* printf( "nmaps = %d, PG_REFERENCED = %d, PG_MODIFIED = %d\n",
3494 nmaps, PG_REFERENCED, PG_MODIFIED); */
3495 bufp = bufp + sizeof(struct prpageheader);
3496 for (i = 0; i < nmaps; i++) {
3497 map = (struct prasmap *)bufp;
3498 vaddr = (ptr_t)(map -> pr_vaddr);
3499 ps = map -> pr_pagesize;
3500 np = map -> pr_npage;
3501 /* printf("vaddr = 0x%X, ps = 0x%X, np = 0x%X\n", vaddr, ps, np); */
3502 limit = vaddr + ps * np;
3503 bufp += sizeof (struct prasmap);
3504 for (current_addr = vaddr;
3505 current_addr < limit; current_addr += ps) {
3506 if ((*bufp++) & PG_MODIFIED) {
3507 register struct hblk * h = (struct hblk *) current_addr;
3509 while ((ptr_t)h < current_addr + ps) {
3510 register word index = PHT_HASH(h);
3512 set_pht_entry_from_index(GC_grungy_pages, index);
3517 bufp += sizeof(long) - 1;
3518 bufp = (char *)((unsigned long)bufp & ~(sizeof(long)-1));
3520 /* Update GC_written_pages. */
3521 GC_or_pages(GC_written_pages, GC_grungy_pages);
3526 GC_INNER GC_bool GC_page_was_dirty(struct hblk *h)
3528 register word index = PHT_HASH(h);
3529 return get_pht_entry_from_index(GC_grungy_pages, index);
3532 GC_INNER GC_bool GC_page_was_ever_dirty(struct hblk *h)
3534 register word index = PHT_HASH(h);
3535 return get_pht_entry_from_index(GC_written_pages, index);
3538 # endif /* PROC_VDB */
3543 # include "vd/PCR_VD.h"
3545 # define NPAGES (32*1024) /* 128 MB */
3547 PCR_VD_DB GC_grungy_bits[NPAGES];
3549 STATIC ptr_t GC_vd_base = NULL;
3550 /* Address corresponding to GC_grungy_bits[0] */
3551 /* HBLKSIZE aligned. */
3553 GC_INNER void GC_dirty_init(void)
3555 GC_dirty_maintained = TRUE;
3556 /* For the time being, we assume the heap generally grows up */
3557 GC_vd_base = GC_heap_sects[0].hs_start;
3558 if (GC_vd_base == 0) {
3559 ABORT("Bad initial heap segment");
3561 if (PCR_VD_Start(HBLKSIZE, GC_vd_base, NPAGES*HBLKSIZE)
3563 ABORT("dirty bit initialization failed");
3567 GC_INNER void GC_read_dirty(void)
3569 /* lazily enable dirty bits on newly added heap sects */
3571 static int onhs = 0;
3572 int nhs = GC_n_heap_sects;
3573 for(; onhs < nhs; onhs++) {
3574 PCR_VD_WriteProtectEnable(
3575 GC_heap_sects[onhs].hs_start,
3576 GC_heap_sects[onhs].hs_bytes );
3580 if (PCR_VD_Clear(GC_vd_base, NPAGES*HBLKSIZE, GC_grungy_bits)
3582 ABORT("dirty bit read failed");
3586 GC_INNER GC_bool GC_page_was_dirty(struct hblk *h)
3588 if((ptr_t)h < GC_vd_base || (ptr_t)h >= GC_vd_base + NPAGES*HBLKSIZE) {
3591 return(GC_grungy_bits[h - (struct hblk *)GC_vd_base] & PCR_VD_DB_dirtyBit);
3595 GC_INNER void GC_remove_protection(struct hblk *h, word nblocks,
3598 PCR_VD_WriteProtectDisable(h, nblocks*HBLKSIZE);
3599 PCR_VD_WriteProtectEnable(h, nblocks*HBLKSIZE);
3602 # endif /* PCR_VDB */
3604 #if defined(MPROTECT_VDB) && defined(DARWIN)
3605 /* The following sources were used as a *reference* for this exception handling
3607 1. Apple's mach/xnu documentation
3608 2. Timothy J. Wood's "Mach Exception Handlers 101" post to the
3609 omnigroup's macosx-dev list.
3610 www.omnigroup.com/mailman/archive/macosx-dev/2000-June/014178.html
3611 3. macosx-nat.c from Apple's GDB source code.
3614 /* The bug that caused all this trouble should now be fixed. This should
3615 eventually be removed if all goes well. */
3617 /* #define BROKEN_EXCEPTION_HANDLING */
3619 #include <mach/mach.h>
3620 #include <mach/mach_error.h>
3621 #include <mach/thread_status.h>
3622 #include <mach/exception.h>
3623 #include <mach/task.h>
3624 #include <pthread.h>
3626 /* These are not defined in any header, although they are documented */
3628 exc_server(mach_msg_header_t *, mach_msg_header_t *);
3630 extern kern_return_t
3631 exception_raise(mach_port_t, mach_port_t, mach_port_t, exception_type_t,
3632 exception_data_t, mach_msg_type_number_t);
3634 extern kern_return_t
3635 exception_raise_state(mach_port_t, mach_port_t, mach_port_t, exception_type_t,
3636 exception_data_t, mach_msg_type_number_t,
3637 thread_state_flavor_t*, thread_state_t,
3638 mach_msg_type_number_t, thread_state_t,
3639 mach_msg_type_number_t*);
3641 extern kern_return_t
3642 exception_raise_state_identity(mach_port_t, mach_port_t, mach_port_t,
3643 exception_type_t, exception_data_t,
3644 mach_msg_type_number_t, thread_state_flavor_t*,
3645 thread_state_t, mach_msg_type_number_t,
3646 thread_state_t, mach_msg_type_number_t*);
3648 #define MAX_EXCEPTION_PORTS 16
3651 mach_msg_type_number_t count;
3652 exception_mask_t masks[MAX_EXCEPTION_PORTS];
3653 exception_handler_t ports[MAX_EXCEPTION_PORTS];
3654 exception_behavior_t behaviors[MAX_EXCEPTION_PORTS];
3655 thread_state_flavor_t flavors[MAX_EXCEPTION_PORTS];
3659 mach_port_t exception;
3660 # if defined(THREADS)
3666 mach_msg_header_t head;
3670 GC_MP_NORMAL, GC_MP_DISCARDING, GC_MP_STOPPED
3671 } GC_mprotect_state_t;
3673 /* FIXME: 1 and 2 seem to be safe to use in the msgh_id field,
3674 but it isn't documented. Use the source and see if they
3679 /* These values are only used on the reply port */
3682 #if defined(THREADS)
3684 STATIC GC_mprotect_state_t GC_mprotect_state = 0;
3686 /* The following should ONLY be called when the world is stopped */
3687 STATIC void GC_mprotect_thread_notify(mach_msg_id_t id)
3692 mach_msg_trailer_t trailer;
3695 mach_msg_return_t r;
3697 buf.msg.head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);
3698 buf.msg.head.msgh_size = sizeof(buf.msg);
3699 buf.msg.head.msgh_remote_port = GC_ports.exception;
3700 buf.msg.head.msgh_local_port = MACH_PORT_NULL;
3701 buf.msg.head.msgh_id = id;
3703 r = mach_msg(&buf.msg.head, MACH_SEND_MSG | MACH_RCV_MSG | MACH_RCV_LARGE,
3704 sizeof(buf.msg), sizeof(buf), GC_ports.reply,
3705 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
3706 if(r != MACH_MSG_SUCCESS)
3707 ABORT("mach_msg failed in GC_mprotect_thread_notify");
3708 if(buf.msg.head.msgh_id != ID_ACK)
3709 ABORT("invalid ack in GC_mprotect_thread_notify");
3712 /* Should only be called by the mprotect thread */
3713 STATIC void GC_mprotect_thread_reply(void)
3716 mach_msg_return_t r;
3718 msg.head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);
3719 msg.head.msgh_size = sizeof(msg);
3720 msg.head.msgh_remote_port = GC_ports.reply;
3721 msg.head.msgh_local_port = MACH_PORT_NULL;
3722 msg.head.msgh_id = ID_ACK;
3724 r = mach_msg(&msg.head, MACH_SEND_MSG, sizeof(msg), 0, MACH_PORT_NULL,
3725 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
3726 if(r != MACH_MSG_SUCCESS)
3727 ABORT("mach_msg failed in GC_mprotect_thread_reply");
3730 GC_INNER void GC_mprotect_stop(void)
3732 GC_mprotect_thread_notify(ID_STOP);
3735 GC_INNER void GC_mprotect_resume(void)
3737 GC_mprotect_thread_notify(ID_RESUME);
3740 #else /* !THREADS */
3741 /* The compiler should optimize away any GC_mprotect_state computations */
3742 #define GC_mprotect_state GC_MP_NORMAL
3745 GC_INNER void GC_darwin_register_mach_handler_thread(mach_port_t thread);
3747 STATIC void *GC_mprotect_thread(void *arg)
3749 mach_msg_return_t r;
3750 /* These two structures contain some private kernel data. We don't need to
3751 access any of it so we don't bother defining a proper struct. The
3752 correct definitions are in the xnu source code. */
3754 mach_msg_header_t head;
3758 mach_msg_header_t head;
3759 mach_msg_body_t msgh_body;
3765 GC_darwin_register_mach_handler_thread(mach_thread_self());
3768 r = mach_msg(&msg.head, MACH_RCV_MSG | MACH_RCV_LARGE |
3769 (GC_mprotect_state == GC_MP_DISCARDING ? MACH_RCV_TIMEOUT : 0),
3770 0, sizeof(msg), GC_ports.exception,
3771 GC_mprotect_state == GC_MP_DISCARDING ? 0
3772 : MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
3774 id = r == MACH_MSG_SUCCESS ? msg.head.msgh_id : -1;
3776 # if defined(THREADS)
3777 if(GC_mprotect_state == GC_MP_DISCARDING) {
3778 if(r == MACH_RCV_TIMED_OUT) {
3779 GC_mprotect_state = GC_MP_STOPPED;
3780 GC_mprotect_thread_reply();
3783 if(r == MACH_MSG_SUCCESS && (id == ID_STOP || id == ID_RESUME))
3784 ABORT("out of order mprotect thread request");
3786 # endif /* THREADS */
3788 if(r != MACH_MSG_SUCCESS) {
3789 GC_err_printf("mach_msg failed with %d %s\n", (int)r,
3790 mach_error_string(r));
3791 ABORT("mach_msg failed");
3795 # if defined(THREADS)
3797 if(GC_mprotect_state != GC_MP_NORMAL)
3798 ABORT("Called mprotect_stop when state wasn't normal");
3799 GC_mprotect_state = GC_MP_DISCARDING;
3802 if(GC_mprotect_state != GC_MP_STOPPED)
3803 ABORT("Called mprotect_resume when state wasn't stopped");
3804 GC_mprotect_state = GC_MP_NORMAL;
3805 GC_mprotect_thread_reply();
3807 # endif /* THREADS */
3809 /* Handle the message (calls catch_exception_raise) */
3810 if(!exc_server(&msg.head, &reply.head))
3811 ABORT("exc_server failed");
3812 /* Send the reply */
3813 r = mach_msg(&reply.head, MACH_SEND_MSG, reply.head.msgh_size, 0,
3814 MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE,
3816 if(r != MACH_MSG_SUCCESS) {
3817 /* This will fail if the thread dies, but the thread */
3818 /* shouldn't die... */
3819 # ifdef BROKEN_EXCEPTION_HANDLING
3820 GC_err_printf("mach_msg failed with %d %s while sending "
3821 "exc reply\n", (int)r,mach_error_string(r));
3823 ABORT("mach_msg failed while sending exception reply");
3832 /* All this SIGBUS code shouldn't be necessary. All protection faults should
3833 be going through the mach exception handler. However, it seems a SIGBUS is
3834 occasionally sent for some unknown reason. Even more odd, it seems to be
3835 meaningless and safe to ignore. */
3836 #ifdef BROKEN_EXCEPTION_HANDLING
3838 /* Updates to this aren't atomic, but the SIGBUSs seem pretty rare.
3839 Even if this doesn't get updated property, it isn't really a problem */
3840 STATIC int GC_sigbus_count = 0;
3842 STATIC void GC_darwin_sigbus(int num, siginfo_t *sip, void *context)
3845 ABORT("Got a non-sigbus signal in the sigbus handler");
3847 /* Ugh... some seem safe to ignore, but too many in a row probably means
3848 trouble. GC_sigbus_count is reset for each mach exception that is
3850 if(GC_sigbus_count >= 8) {
3851 ABORT("Got more than 8 SIGBUSs in a row!");
3854 WARN("Ignoring SIGBUS.\n", 0);
3857 #endif /* BROKEN_EXCEPTION_HANDLING */
3859 GC_INNER void GC_dirty_init(void)
3864 pthread_attr_t attr;
3865 exception_mask_t mask;
3867 if (GC_print_stats == VERBOSE)
3868 GC_log_printf("Initializing mach/darwin mprotect virtual dirty bit "
3869 "implementation\n");
3870 # ifdef BROKEN_EXCEPTION_HANDLING
3871 WARN("Enabling workarounds for various darwin "
3872 "exception handling bugs.\n", 0);
3874 GC_dirty_maintained = TRUE;
3875 if (GC_page_size % HBLKSIZE != 0) {
3876 GC_err_printf("Page size not multiple of HBLKSIZE\n");
3877 ABORT("Page size not multiple of HBLKSIZE");
3880 GC_task_self = me = mach_task_self();
3882 r = mach_port_allocate(me, MACH_PORT_RIGHT_RECEIVE, &GC_ports.exception);
3883 if(r != KERN_SUCCESS)
3884 ABORT("mach_port_allocate failed (exception port)");
3886 r = mach_port_insert_right(me, GC_ports.exception, GC_ports.exception,
3887 MACH_MSG_TYPE_MAKE_SEND);
3888 if(r != KERN_SUCCESS)
3889 ABORT("mach_port_insert_right failed (exception port)");
3891 # if defined(THREADS)
3892 r = mach_port_allocate(me, MACH_PORT_RIGHT_RECEIVE, &GC_ports.reply);
3893 if(r != KERN_SUCCESS)
3894 ABORT("mach_port_allocate failed (reply port)");
3897 /* The exceptions we want to catch */
3898 mask = EXC_MASK_BAD_ACCESS;
3900 r = task_get_exception_ports(me, mask, GC_old_exc_ports.masks,
3901 &GC_old_exc_ports.count, GC_old_exc_ports.ports,
3902 GC_old_exc_ports.behaviors,
3903 GC_old_exc_ports.flavors);
3904 if(r != KERN_SUCCESS)
3905 ABORT("task_get_exception_ports failed");
3907 r = task_set_exception_ports(me, mask, GC_ports.exception, EXCEPTION_DEFAULT,
3908 GC_MACH_THREAD_STATE);
3909 if(r != KERN_SUCCESS)
3910 ABORT("task_set_exception_ports failed");
3911 if(pthread_attr_init(&attr) != 0)
3912 ABORT("pthread_attr_init failed");
3913 if(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0)
3914 ABORT("pthread_attr_setdetachedstate failed");
3916 # undef pthread_create
3917 /* This will call the real pthread function, not our wrapper */
3918 if(pthread_create(&thread, &attr, GC_mprotect_thread, NULL) != 0)
3919 ABORT("pthread_create failed");
3920 pthread_attr_destroy(&attr);
3922 /* Setup the sigbus handler for ignoring the meaningless SIGBUSs */
3923 # ifdef BROKEN_EXCEPTION_HANDLING
3925 struct sigaction sa, oldsa;
3926 sa.sa_handler = (SIG_HNDLR_PTR)GC_darwin_sigbus;
3927 sigemptyset(&sa.sa_mask);
3928 sa.sa_flags = SA_RESTART|SA_SIGINFO;
3929 if(sigaction(SIGBUS, &sa, &oldsa) < 0)
3931 if ((SIG_HNDLR_PTR)oldsa.sa_handler != SIG_DFL) {
3932 if (GC_print_stats == VERBOSE)
3933 GC_err_printf("Replaced other SIGBUS handler\n");
3936 # endif /* BROKEN_EXCEPTION_HANDLING */
3939 /* The source code for Apple's GDB was used as a reference for the exception
3940 forwarding code. This code is similar to be GDB code only because there is
3941 only one way to do it. */
3942 STATIC kern_return_t GC_forward_exception(mach_port_t thread, mach_port_t task,
3943 exception_type_t exception,
3944 exception_data_t data,
3945 mach_msg_type_number_t data_count)
3950 exception_behavior_t behavior;
3951 thread_state_flavor_t flavor;
3953 thread_state_data_t thread_state;
3954 mach_msg_type_number_t thread_state_count = THREAD_STATE_MAX;
3956 for(i=0; i < GC_old_exc_ports.count; i++)
3957 if(GC_old_exc_ports.masks[i] & (1 << exception))
3959 if(i==GC_old_exc_ports.count)
3960 ABORT("No handler for exception!");
3962 port = GC_old_exc_ports.ports[i];
3963 behavior = GC_old_exc_ports.behaviors[i];
3964 flavor = GC_old_exc_ports.flavors[i];
3966 if(behavior == EXCEPTION_STATE || behavior == EXCEPTION_STATE_IDENTITY) {
3967 r = thread_get_state(thread, flavor, thread_state, &thread_state_count);
3968 if(r != KERN_SUCCESS)
3969 ABORT("thread_get_state failed in forward_exception");
3973 case EXCEPTION_STATE:
3974 r = exception_raise_state(port, thread, task, exception, data, data_count,
3975 &flavor, thread_state, thread_state_count,
3976 thread_state, &thread_state_count);
3978 case EXCEPTION_STATE_IDENTITY:
3979 r = exception_raise_state_identity(port, thread, task, exception, data,
3980 data_count, &flavor, thread_state,
3981 thread_state_count, thread_state,
3982 &thread_state_count);
3984 /* case EXCEPTION_DEFAULT: */ /* default signal handlers */
3985 default: /* user-supplied signal handlers */
3986 r = exception_raise(port, thread, task, exception, data, data_count);
3989 if(behavior == EXCEPTION_STATE || behavior == EXCEPTION_STATE_IDENTITY) {
3990 r = thread_set_state(thread, flavor, thread_state, thread_state_count);
3991 if(r != KERN_SUCCESS)
3992 ABORT("thread_set_state failed in forward_exception");
3998 #define FWD() GC_forward_exception(thread, task, exception, code, code_count)
4000 /* This violates the namespace rules but there isn't anything that can be done
4001 about it. The exception handling stuff is hard coded to call this. */
4003 catch_exception_raise(mach_port_t exception_port, mach_port_t thread,
4004 mach_port_t task, exception_type_t exception,
4005 exception_data_t code, mach_msg_type_number_t code_count)
4011 # if defined(POWERPC)
4012 # if CPP_WORDSZ == 32
4013 thread_state_flavor_t flavor = PPC_EXCEPTION_STATE;
4014 mach_msg_type_number_t exc_state_count = PPC_EXCEPTION_STATE_COUNT;
4015 ppc_exception_state_t exc_state;
4017 thread_state_flavor_t flavor = PPC_EXCEPTION_STATE64;
4018 mach_msg_type_number_t exc_state_count = PPC_EXCEPTION_STATE64_COUNT;
4019 ppc_exception_state64_t exc_state;
4021 # elif defined(I386) || defined(X86_64)
4022 # if CPP_WORDSZ == 32
4023 thread_state_flavor_t flavor = x86_EXCEPTION_STATE32;
4024 mach_msg_type_number_t exc_state_count = x86_EXCEPTION_STATE32_COUNT;
4025 x86_exception_state32_t exc_state;
4027 thread_state_flavor_t flavor = x86_EXCEPTION_STATE64;
4028 mach_msg_type_number_t exc_state_count = x86_EXCEPTION_STATE64_COUNT;
4029 x86_exception_state64_t exc_state;
4032 # error FIXME for non-ppc/x86 darwin
4036 if(exception != EXC_BAD_ACCESS || code[0] != KERN_PROTECTION_FAILURE) {
4037 # ifdef DEBUG_EXCEPTION_HANDLING
4038 /* We aren't interested, pass it on to the old handler */
4039 GC_printf("Exception: 0x%x Code: 0x%x 0x%x in catch....\n", exception,
4040 code_count > 0 ? code[0] : -1, code_count > 1 ? code[1] : -1);
4045 r = thread_get_state(thread, flavor, (natural_t*)&exc_state,
4047 if(r != KERN_SUCCESS) {
4048 /* The thread is supposed to be suspended while the exception handler
4049 is called. This shouldn't fail. */
4050 # ifdef BROKEN_EXCEPTION_HANDLING
4051 GC_err_printf("thread_get_state failed in catch_exception_raise\n");
4052 return KERN_SUCCESS;
4054 ABORT("thread_get_state failed in catch_exception_raise");
4058 /* This is the address that caused the fault */
4059 # if defined(POWERPC)
4060 addr = (char*) exc_state. THREAD_FLD(dar);
4061 # elif defined (I386) || defined (X86_64)
4062 addr = (char*) exc_state. THREAD_FLD(faultvaddr);
4064 # error FIXME for non POWERPC/I386
4067 if((HDR(addr)) == 0) {
4068 /* Ugh... just like the SIGBUS problem above, it seems we get a bogus
4069 KERN_PROTECTION_FAILURE every once and a while. We wait till we get
4070 a bunch in a row before doing anything about it. If a "real" fault
4071 ever occurs it'll just keep faulting over and over and we'll hit
4072 the limit pretty quickly. */
4073 # ifdef BROKEN_EXCEPTION_HANDLING
4074 static char *last_fault;
4075 static int last_fault_count;
4077 if(addr != last_fault) {
4079 last_fault_count = 0;
4081 if(++last_fault_count < 32) {
4082 if(last_fault_count == 1)
4083 WARN("Ignoring KERN_PROTECTION_FAILURE at %p\n", addr);
4084 return KERN_SUCCESS;
4087 GC_err_printf("Unexpected KERN_PROTECTION_FAILURE at %p\n",addr);
4088 /* Can't pass it along to the signal handler because that is
4089 ignoring SIGBUS signals. We also shouldn't call ABORT here as
4090 signals don't always work too well from the exception handler. */
4091 GC_err_printf("Aborting\n");
4093 # else /* BROKEN_EXCEPTION_HANDLING */
4094 /* Pass it along to the next exception handler
4095 (which should call SIGBUS/SIGSEGV) */
4097 # endif /* !BROKEN_EXCEPTION_HANDLING */
4100 # ifdef BROKEN_EXCEPTION_HANDLING
4101 /* Reset the number of consecutive SIGBUSs */
4102 GC_sigbus_count = 0;
4105 if(GC_mprotect_state == GC_MP_NORMAL) { /* common case */
4106 h = (struct hblk*)((word)addr & ~(GC_page_size-1));
4107 UNPROTECT(h, GC_page_size);
4108 for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
4109 register int index = PHT_HASH(h+i);
4110 async_set_pht_entry_from_index(GC_dirty_pages, index);
4112 } else if(GC_mprotect_state == GC_MP_DISCARDING) {
4113 /* Lie to the thread for now. No sense UNPROTECT()ing the memory
4114 when we're just going to PROTECT() it again later. The thread
4115 will just fault again once it resumes */
4117 /* Shouldn't happen, i don't think */
4118 GC_printf("KERN_PROTECTION_FAILURE while world is stopped\n");
4121 return KERN_SUCCESS;
4125 /* These should never be called, but just in case... */
4127 catch_exception_raise_state(mach_port_name_t exception_port, int exception,
4128 exception_data_t code,
4129 mach_msg_type_number_t codeCnt, int flavor,
4130 thread_state_t old_state, int old_stateCnt,
4131 thread_state_t new_state, int new_stateCnt)
4133 ABORT("catch_exception_raise_state");
4134 return(KERN_INVALID_ARGUMENT);
4138 catch_exception_raise_state_identity(mach_port_name_t exception_port,
4139 mach_port_t thread, mach_port_t task,
4140 int exception, exception_data_t code,
4141 mach_msg_type_number_t codeCnt, int flavor,
4142 thread_state_t old_state, int old_stateCnt,
4143 thread_state_t new_state, int new_stateCnt)
4145 ABORT("catch_exception_raise_state_identity");
4146 return(KERN_INVALID_ARGUMENT);
4149 #endif /* DARWIN && MPROTECT_VDB */
4151 # ifndef HAVE_INCREMENTAL_PROTECTION_NEEDS
4152 GC_API int GC_CALL GC_incremental_protection_needs(void)
4154 return GC_PROTECTS_NONE;
4156 # endif /* !HAVE_INCREMENTAL_PROTECTION_NEEDS */
4159 /* Undo sbrk() redirection. */
4164 * Call stack save code for debugging.
4165 * Should probably be in mach_dep.c, but that requires reorganization.
4168 /* I suspect the following works for most X86 *nix variants, so */
4169 /* long as the frame pointer is explicitly stored. In the case of gcc, */
4170 /* compiler flags (e.g. -fomit-frame-pointer) determine whether it is. */
4171 #if defined(I386) && defined(LINUX) && defined(SAVE_CALL_CHAIN)
4172 # include <features.h>
4175 struct frame *fr_savfp;
4177 long fr_arg[NARGS]; /* All the arguments go here. */
4183 # include <features.h>
4188 struct frame *fr_savfp;
4196 # elif defined (DRSNX)
4197 # include <sys/sparc/frame.h>
4198 # elif defined(OPENBSD)
4200 # elif defined(FREEBSD) || defined(NETBSD)
4201 # include <machine/frame.h>
4203 # include <sys/frame.h>
4206 # error We only know how to to get the first 6 arguments
4210 #ifdef NEED_CALLINFO
4211 /* Fill in the pc and argument information for up to NFRAMES of my */
4212 /* callers. Ignore my frame and my callers frame. */
4215 # include <unistd.h>
4218 #endif /* NEED_CALLINFO */
4220 #if defined(GC_HAVE_BUILTIN_BACKTRACE)
4222 # include "private/msvc_dbg.h"
4224 # include <execinfo.h>
4228 #ifdef SAVE_CALL_CHAIN
4230 #if NARGS == 0 && NFRAMES % 2 == 0 /* No padding */ \
4231 && defined(GC_HAVE_BUILTIN_BACKTRACE)
4233 #ifdef REDIRECT_MALLOC
4234 /* Deal with possible malloc calls in backtrace by omitting */
4235 /* the infinitely recursing backtrace. */
4237 __thread /* If your compiler doesn't understand this */
4238 /* you could use something like pthread_getspecific. */
4240 GC_in_save_callers = FALSE;
4243 GC_INNER void GC_save_callers(struct callinfo info[NFRAMES])
4245 void * tmp_info[NFRAMES + 1];
4247 # define IGNORE_FRAMES 1
4249 /* We retrieve NFRAMES+1 pc values, but discard the first, since it */
4250 /* points to our own frame. */
4251 # ifdef REDIRECT_MALLOC
4252 if (GC_in_save_callers) {
4253 info[0].ci_pc = (word)(&GC_save_callers);
4254 for (i = 1; i < NFRAMES; ++i) info[i].ci_pc = 0;
4257 GC_in_save_callers = TRUE;
4259 GC_STATIC_ASSERT(sizeof(struct callinfo) == sizeof(void *));
4260 npcs = backtrace((void **)tmp_info, NFRAMES + IGNORE_FRAMES);
4261 BCOPY(tmp_info+IGNORE_FRAMES, info, (npcs - IGNORE_FRAMES) * sizeof(void *));
4262 for (i = npcs - IGNORE_FRAMES; i < NFRAMES; ++i) info[i].ci_pc = 0;
4263 # ifdef REDIRECT_MALLOC
4264 GC_in_save_callers = FALSE;
4268 #else /* No builtin backtrace; do it ourselves */
4270 #if (defined(OPENBSD) || defined(NETBSD) || defined(FREEBSD)) && defined(SPARC)
4271 # define FR_SAVFP fr_fp
4272 # define FR_SAVPC fr_pc
4274 # define FR_SAVFP fr_savfp
4275 # define FR_SAVPC fr_savpc
4278 #if defined(SPARC) && (defined(__arch64__) || defined(__sparcv9))
4284 GC_INNER void GC_save_callers(struct callinfo info[NFRAMES])
4286 struct frame *frame;
4290 /* We assume this is turned on only with gcc as the compiler. */
4291 asm("movl %%ebp,%0" : "=r"(frame));
4294 frame = (struct frame *)GC_save_regs_in_stack();
4295 fp = (struct frame *)((long) frame -> FR_SAVFP + BIAS);
4298 for (; (!(fp HOTTER_THAN frame) && !(GC_stackbottom HOTTER_THAN (ptr_t)fp)
4299 && (nframes < NFRAMES));
4300 fp = (struct frame *)((long) fp -> FR_SAVFP + BIAS), nframes++) {
4303 info[nframes].ci_pc = fp->FR_SAVPC;
4305 for (i = 0; i < NARGS; i++) {
4306 info[nframes].ci_arg[i] = ~(fp->fr_arg[i]);
4308 # endif /* NARGS > 0 */
4310 if (nframes < NFRAMES) info[nframes].ci_pc = 0;
4313 #endif /* No builtin backtrace */
4315 #endif /* SAVE_CALL_CHAIN */
4317 #ifdef NEED_CALLINFO
4319 /* Print info to stderr. We do NOT hold the allocation lock */
4320 GC_INNER void GC_print_callers(struct callinfo info[NFRAMES])
4323 static int reentry_count = 0;
4324 GC_bool stop = FALSE;
4326 /* FIXME: This should probably use a different lock, so that we */
4327 /* become callable with or without the allocation lock. */
4333 GC_err_printf("\tCaller at allocation:\n");
4335 GC_err_printf("\tCall chain at allocation:\n");
4337 for (i = 0; i < NFRAMES && !stop; i++) {
4338 if (info[i].ci_pc == 0) break;
4343 GC_err_printf("\t\targs: ");
4344 for (j = 0; j < NARGS; j++) {
4345 if (j != 0) GC_err_printf(", ");
4346 GC_err_printf("%d (0x%X)", ~(info[i].ci_arg[j]),
4347 ~(info[i].ci_arg[j]));
4349 GC_err_printf("\n");
4352 if (reentry_count > 1) {
4353 /* We were called during an allocation during */
4354 /* a previous GC_print_callers call; punt. */
4355 GC_err_printf("\t\t##PC##= 0x%lx\n", info[i].ci_pc);
4362 # if defined(GC_HAVE_BUILTIN_BACKTRACE) \
4363 && !defined(GC_BACKTRACE_SYMBOLS_BROKEN)
4365 backtrace_symbols((void **)(&(info[i].ci_pc)), 1);
4366 char *name = sym_name[0];
4370 sprintf(buf, "##PC##= 0x%lx", info[i].ci_pc);
4372 # if defined(LINUX) && !defined(SMALL_CONFIG)
4373 /* Try for a line number. */
4376 static char exe_name[EXE_SZ];
4378 char cmd_buf[CMD_SZ];
4379 # define RESULT_SZ 200
4380 static char result_buf[RESULT_SZ];
4383 # define PRELOAD_SZ 200
4384 char preload_buf[PRELOAD_SZ];
4385 static GC_bool found_exe_name = FALSE;
4386 static GC_bool will_fail = FALSE;
4388 /* Try to get it via a hairy and expensive scheme. */
4389 /* First we get the name of the executable: */
4390 if (will_fail) goto out;
4391 if (!found_exe_name) {
4392 ret_code = readlink("/proc/self/exe", exe_name, EXE_SZ);
4393 if (ret_code < 0 || ret_code >= EXE_SZ
4394 || exe_name[0] != '/') {
4395 will_fail = TRUE; /* Don't try again. */
4398 exe_name[ret_code] = '\0';
4399 found_exe_name = TRUE;
4401 /* Then we use popen to start addr2line -e <exe> <addr> */
4402 /* There are faster ways to do this, but hopefully this */
4403 /* isn't time critical. */
4404 sprintf(cmd_buf, "/usr/bin/addr2line -f -e %s 0x%lx", exe_name,
4405 (unsigned long)info[i].ci_pc);
4406 old_preload = GETENV("LD_PRELOAD");
4407 if (0 != old_preload) {
4408 if (strlen (old_preload) >= PRELOAD_SZ) {
4412 strcpy (preload_buf, old_preload);
4413 unsetenv ("LD_PRELOAD");
4415 pipe = popen(cmd_buf, "r");
4416 if (0 != old_preload
4417 && 0 != setenv ("LD_PRELOAD", preload_buf, 0)) {
4418 WARN("Failed to reset LD_PRELOAD\n", 0);
4421 || (result_len = fread(result_buf, 1, RESULT_SZ - 1, pipe))
4423 if (pipe != NULL) pclose(pipe);
4427 if (result_buf[result_len - 1] == '\n') --result_len;
4428 result_buf[result_len] = 0;
4429 if (result_buf[0] == '?'
4430 || (result_buf[result_len-2] == ':'
4431 && result_buf[result_len-1] == '0')) {
4435 /* Get rid of embedded newline, if any. Test for "main" */
4437 char * nl = strchr(result_buf, '\n');
4438 if (nl != NULL && nl < result_buf + result_len) {
4441 if (strncmp(result_buf, "main", nl - result_buf) == 0) {
4445 if (result_len < RESULT_SZ - 25) {
4446 /* Add in hex address */
4447 sprintf(result_buf + result_len, " [0x%lx]",
4448 (unsigned long)info[i].ci_pc);
4455 GC_err_printf("\t\t%s\n", name);
4456 # if defined(GC_HAVE_BUILTIN_BACKTRACE) \
4457 && !defined(GC_BACKTRACE_SYMBOLS_BROKEN)
4458 free(sym_name); /* May call GC_free; that's OK */
4467 #endif /* NEED_CALLINFO */
4469 #if defined(LINUX) && defined(__ELF__) && !defined(SMALL_CONFIG)
4471 /* Dump /proc/self/maps to GC_stderr, to enable looking up names for
4472 addresses in FIND_LEAK output. */
4474 static word dump_maps(char *maps)
4476 GC_err_write(maps, strlen(maps));
4480 void GC_print_address_map(void)
4482 GC_err_printf("---------- Begin address map ----------\n");
4483 dump_maps(GC_get_maps());
4484 GC_err_printf("---------- End address map ----------\n");