X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=boehm-gc%2Fos_dep.c;h=3f0f20e834cedda24483ba09fb3d93222b2497af;hb=cecc75a931d754df7d180ca5a6c52b02c2e18f0b;hp=fd195e1c806c6b9acdfa775fd4d0b4a5d584b984;hpb=c307b7ee13dd201204f66b1ce176103179ea0c70;p=pf3gnuchains%2Fgcc-fork.git diff --git a/boehm-gc/os_dep.c b/boehm-gc/os_dep.c index fd195e1c806..3f0f20e834c 100644 --- a/boehm-gc/os_dep.c +++ b/boehm-gc/os_dep.c @@ -60,6 +60,10 @@ # include # endif +#if defined(LINUX) || defined(LINUX_STACKBOTTOM) +# include +#endif + /* Blatantly OS dependent routines, except for those that are related */ /* to dynamic loading. */ @@ -80,13 +84,19 @@ # define NEED_FIND_LIMIT # endif -#if defined(FREEBSD) && defined(I386) +#if defined(FREEBSD) && (defined(I386) || defined(X86_64) || defined(powerpc) || defined(__powerpc__)) # include # if !defined(PCR) # define NEED_FIND_LIMIT # endif #endif +#if (defined(NETBSD) || defined(OPENBSD)) && defined(__ELF__) \ + && !defined(NEED_FIND_LIMIT) + /* Used by GC_init_netbsd_elf() below. */ +# define NEED_FIND_LIMIT +#endif + #ifdef NEED_FIND_LIMIT # include #endif @@ -111,25 +121,30 @@ # include # include /* for locking */ #endif -#ifdef USE_MMAP +#if defined(USE_MMAP) || defined(USE_MUNMAP) +# ifndef USE_MMAP + --> USE_MUNMAP requires USE_MMAP +# endif # include # include # include +# include #endif #ifdef UNIX_LIKE # include -#endif - -#if defined(SUNOS5SIGS) || defined (HURD) || defined(LINUX) -# ifdef SUNOS5SIGS +# if defined(SUNOS5SIGS) && !defined(FREEBSD) # include # endif -# undef setjmp -# undef longjmp -# define setjmp(env) sigsetjmp(env, 1) -# define longjmp(env, val) siglongjmp(env, val) -# define jmp_buf sigjmp_buf + /* Define SETJMP and friends to be the version that restores */ + /* the signal mask. */ +# define SETJMP(env) sigsetjmp(env, 1) +# define LONGJMP(env, val) siglongjmp(env, val) +# define JMP_BUF sigjmp_buf +#else +# define SETJMP(env) setjmp(env) +# define LONGJMP(env, val) longjmp(env, val) +# define JMP_BUF jmp_buf #endif #ifdef DARWIN @@ -183,45 +198,41 @@ ssize_t GC_repeat_read(int fd, char *buf, size_t count) /* * Apply fn to a buffer containing the contents of /proc/self/maps. * Return the result of fn or, if we failed, 0. + * We currently do nothing to /proc/self/maps other than simply read + * it. This code could be simplified if we could determine its size + * ahead of time. */ word GC_apply_to_maps(word (*fn)(char *)) { int f; int result; - int maps_size; - char maps_temp[32768]; - char *maps_buf; - - /* Read /proc/self/maps */ - /* Note that we may not allocate, and thus can't use stdio. */ - f = open("/proc/self/maps", O_RDONLY); - if (-1 == f) return 0; - /* stat() doesn't work for /proc/self/maps, so we have to - read it to find out how large it is... */ - maps_size = 0; + size_t maps_size = 4000; /* Initial guess. */ + static char init_buf[1]; + static char *maps_buf = init_buf; + static size_t maps_buf_sz = 1; + + /* Read /proc/self/maps, growing maps_buf as necessary. */ + /* Note that we may not allocate conventionally, and */ + /* thus can't use stdio. */ do { - result = GC_repeat_read(f, maps_temp, sizeof(maps_temp)); - if (result <= 0) return 0; - maps_size += result; - } while (result == sizeof(maps_temp)); - - if (maps_size > sizeof(maps_temp)) { - /* If larger than our buffer, close and re-read it. */ - close(f); + if (maps_size >= maps_buf_sz) { + /* Grow only by powers of 2, since we leak "too small" buffers. */ + while (maps_size >= maps_buf_sz) maps_buf_sz *= 2; + maps_buf = GC_scratch_alloc(maps_buf_sz); + if (maps_buf == 0) return 0; + } f = open("/proc/self/maps", O_RDONLY); if (-1 == f) return 0; - maps_buf = alloca(maps_size); - if (NULL == maps_buf) return 0; - result = GC_repeat_read(f, maps_buf, maps_size); - if (result <= 0) return 0; - } else { - /* Otherwise use the fixed size buffer */ - maps_buf = maps_temp; - } - - close(f); - maps_buf[result] = '\0'; + maps_size = 0; + do { + result = GC_repeat_read(f, maps_buf, maps_buf_sz-1); + if (result <= 0) return 0; + maps_size += result; + } while (result == maps_buf_sz-1); + close(f); + } while (maps_size >= maps_buf_sz); + maps_buf[maps_size] = '\0'; /* Apply fn to result. */ return fn(maps_buf); @@ -238,30 +249,11 @@ word GC_apply_to_maps(word (*fn)(char *)) // XXXXXXXX-XXXXXXXX r-xp 00000000 30:05 260537 name of mapping...\n // ^^^^^^^^ ^^^^^^^^ ^^^^ ^^ // start end prot maj_dev -// 0 9 18 32 -// -// For 64 bit ABIs: -// 0 17 34 56 // -// The parser is called with a pointer to the entry and the return value -// is either NULL or is advanced to the next entry(the byte after the -// trailing '\n'.) +// Note that since about auguat 2003 kernels, the columns no longer have +// fixed offsets on 64-bit kernels. Hence we no longer rely on fixed offsets +// anywhere, which is safer anyway. // -#if CPP_WORDSZ == 32 -# define OFFSET_MAP_START 0 -# define OFFSET_MAP_END 9 -# define OFFSET_MAP_PROT 18 -# define OFFSET_MAP_MAJDEV 32 -# define ADDR_WIDTH 8 -#endif - -#if CPP_WORDSZ == 64 -# define OFFSET_MAP_START 0 -# define OFFSET_MAP_END 17 -# define OFFSET_MAP_PROT 34 -# define OFFSET_MAP_MAJDEV 56 -# define ADDR_WIDTH 16 -#endif /* * Assign various fields of the first line in buf_ptr to *start, *end, @@ -270,37 +262,46 @@ word GC_apply_to_maps(word (*fn)(char *)) char *GC_parse_map_entry(char *buf_ptr, word *start, word *end, char *prot_buf, unsigned int *maj_dev) { - int i; - char *tok; + char *start_start, *end_start, *prot_start, *maj_dev_start; + char *p; + char *endp; if (buf_ptr == NULL || *buf_ptr == '\0') { return NULL; } - memcpy(prot_buf, buf_ptr+OFFSET_MAP_PROT, 4); - /* do the protections first. */ + p = buf_ptr; + while (isspace(*p)) ++p; + start_start = p; + GC_ASSERT(isxdigit(*start_start)); + *start = strtoul(start_start, &endp, 16); p = endp; + GC_ASSERT(*p=='-'); + + ++p; + end_start = p; + GC_ASSERT(isxdigit(*end_start)); + *end = strtoul(end_start, &endp, 16); p = endp; + GC_ASSERT(isspace(*p)); + + while (isspace(*p)) ++p; + prot_start = p; + GC_ASSERT(*prot_start == 'r' || *prot_start == '-'); + memcpy(prot_buf, prot_start, 4); prot_buf[4] = '\0'; - - if (prot_buf[1] == 'w') {/* we can skip all of this if it's not writable. */ - - tok = buf_ptr; - buf_ptr[OFFSET_MAP_START+ADDR_WIDTH] = '\0'; - *start = strtoul(tok, NULL, 16); - - tok = buf_ptr+OFFSET_MAP_END; - buf_ptr[OFFSET_MAP_END+ADDR_WIDTH] = '\0'; - *end = strtoul(tok, NULL, 16); - - buf_ptr += OFFSET_MAP_MAJDEV; - tok = buf_ptr; - while (*buf_ptr != ':') buf_ptr++; - *buf_ptr++ = '\0'; - *maj_dev = strtoul(tok, NULL, 16); + if (prot_buf[1] == 'w') {/* we can skip the rest if it's not writable. */ + /* Skip past protection field to offset field */ + while (!isspace(*p)) ++p; while (isspace(*p)) ++p; + GC_ASSERT(isxdigit(*p)); + /* Skip past offset field, which we ignore */ + while (!isspace(*p)) ++p; while (isspace(*p)) ++p; + maj_dev_start = p; + GC_ASSERT(isxdigit(*maj_dev_start)); + *maj_dev = strtoul(maj_dev_start, NULL, 16); } - while (*buf_ptr && *buf_ptr++ != '\n'); + while (*p && *p++ != '\n'); - return buf_ptr; + return p; } #endif /* Need to parse /proc/self/maps. */ @@ -352,7 +353,8 @@ char *GC_parse_map_entry(char *buf_ptr, word *start, word *end, # endif /* ECOS_GC_MEMORY_SIZE */ // setjmp() function, as described in ANSI para 7.6.1.1 -#define setjmp( __env__ ) hal_setjmp( __env__ ) +#undef SETJMP +#define SETJMP( __env__ ) hal_setjmp( __env__ ) // FIXME: This is a simple way of allocating memory which is // compatible with ECOS early releases. Later releases use a more @@ -688,9 +690,11 @@ ptr_t GC_get_stack_base() typedef void (*handler)(); # endif -# if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1) || defined(HURD) +# if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1) \ + || defined(HURD) || defined(NETBSD) static struct sigaction old_segv_act; -# if defined(_sigargs) /* !Irix6.x */ || defined(HPUX) || defined(HURD) +# if defined(IRIX5) || defined(HPUX) \ + || defined(HURD) || defined(NETBSD) static struct sigaction old_bus_act; # endif # else @@ -704,21 +708,17 @@ ptr_t GC_get_stack_base() handler h; # endif { -# if defined(SUNOS5SIGS) || defined(IRIX5) \ - || defined(OSF1) || defined(HURD) +# if defined(SUNOS5SIGS) || defined(IRIX5) \ + || defined(OSF1) || defined(HURD) || defined(NETBSD) struct sigaction act; act.sa_handler = h; -# ifdef SUNOS5SIGS +# if 0 /* Was necessary for Solaris 2.3 and very temporary */ + /* NetBSD bugs. */ act.sa_flags = SA_RESTART | SA_NODEFER; # else act.sa_flags = SA_RESTART; # endif - /* The presence of SA_NODEFER represents yet another gross */ - /* hack. Under Solaris 2.3, siglongjmp doesn't appear to */ - /* interact correctly with -lthread. We hide the confusion */ - /* by making sure that signal handling doesn't affect the */ - /* signal mask. */ (void) sigemptyset(&act.sa_mask); # ifdef GC_IRIX_THREADS @@ -726,10 +726,12 @@ ptr_t GC_get_stack_base() /* and setting a handler at the same time. */ (void) sigaction(SIGSEGV, 0, &old_segv_act); (void) sigaction(SIGSEGV, &act, 0); + (void) sigaction(SIGBUS, 0, &old_bus_act); + (void) sigaction(SIGBUS, &act, 0); # else (void) sigaction(SIGSEGV, &act, &old_segv_act); -# if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \ - || defined(HPUX) || defined(HURD) +# if defined(IRIX5) \ + || defined(HPUX) || defined(HURD) || defined(NETBSD) /* Under Irix 5.x or HP/UX, we may get SIGBUS. */ /* Pthreads doesn't exist under Irix 5.x, so we */ /* don't have to worry in the threads case. */ @@ -748,13 +750,13 @@ ptr_t GC_get_stack_base() # ifdef NEED_FIND_LIMIT /* Some tools to implement HEURISTIC2 */ # define MIN_PAGE_SIZE 256 /* Smallest conceivable page size, bytes */ - /* static */ jmp_buf GC_jmp_buf; + /* static */ JMP_BUF GC_jmp_buf; /*ARGSUSED*/ void GC_fault_handler(sig) int sig; { - longjmp(GC_jmp_buf, 1); + LONGJMP(GC_jmp_buf, 1); } void GC_setup_temporary_fault_handler() @@ -764,19 +766,19 @@ ptr_t GC_get_stack_base() void GC_reset_fault_handler() { -# if defined(SUNOS5SIGS) || defined(IRIX5) \ - || defined(OSF1) || defined(HURD) - (void) sigaction(SIGSEGV, &old_segv_act, 0); -# if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \ - || defined(HPUX) || defined(HURD) - (void) sigaction(SIGBUS, &old_bus_act, 0); -# endif -# else - (void) signal(SIGSEGV, old_segv_handler); -# ifdef SIGBUS - (void) signal(SIGBUS, old_bus_handler); -# endif -# endif +# if defined(SUNOS5SIGS) || defined(IRIX5) \ + || defined(OSF1) || defined(HURD) || defined(NETBSD) + (void) sigaction(SIGSEGV, &old_segv_act, 0); +# if defined(IRIX5) \ + || defined(HPUX) || defined(HURD) || defined(NETBSD) + (void) sigaction(SIGBUS, &old_bus_act, 0); +# endif +# else + (void) signal(SIGSEGV, old_segv_handler); +# ifdef SIGBUS + (void) signal(SIGBUS, old_bus_handler); +# endif +# endif } /* Return the first nonaddressible location > p (up) or */ @@ -786,31 +788,31 @@ ptr_t GC_get_stack_base() ptr_t p; GC_bool up; { - static VOLATILE ptr_t result; - /* Needs to be static, since otherwise it may not be */ - /* preserved across the longjmp. Can safely be */ - /* static since it's only called once, with the */ - /* allocation lock held. */ - - - GC_setup_temporary_fault_handler(); - if (setjmp(GC_jmp_buf) == 0) { - result = (ptr_t)(((word)(p)) - & ~(MIN_PAGE_SIZE-1)); - for (;;) { - if (up) { - result += MIN_PAGE_SIZE; - } else { - result -= MIN_PAGE_SIZE; - } - GC_noop1((word)(*result)); + static VOLATILE ptr_t result; + /* Needs to be static, since otherwise it may not be */ + /* preserved across the longjmp. Can safely be */ + /* static since it's only called once, with the */ + /* allocation lock held. */ + + + GC_setup_temporary_fault_handler(); + if (SETJMP(GC_jmp_buf) == 0) { + result = (ptr_t)(((word)(p)) + & ~(MIN_PAGE_SIZE-1)); + for (;;) { + if (up) { + result += MIN_PAGE_SIZE; + } else { + result -= MIN_PAGE_SIZE; + } + GC_noop1((word)(*result)); + } } - } - GC_reset_fault_handler(); - if (!up) { - result += MIN_PAGE_SIZE; - } - return(result); + GC_reset_fault_handler(); + if (!up) { + result += MIN_PAGE_SIZE; + } + return(result); } # endif @@ -821,17 +823,41 @@ ptr_t GC_get_stack_base() } #endif +#ifdef HPUX_STACKBOTTOM + +#include +#include + + ptr_t GC_get_register_stack_base(void) + { + struct pst_vm_status vm_status; + + int i = 0; + while (pstat_getprocvm(&vm_status, sizeof(vm_status), 0, i++) == 1) { + if (vm_status.pst_type == PS_RSESTACK) { + return (ptr_t) vm_status.pst_vaddr; + } + } + + /* old way to get the register stackbottom */ + return (ptr_t)(((word)GC_stackbottom - BACKING_STORE_DISPLACEMENT - 1) + & ~(BACKING_STORE_ALIGNMENT - 1)); + } + +#endif /* HPUX_STACK_BOTTOM */ + #ifdef LINUX_STACKBOTTOM #include #include -#include # define STAT_SKIP 27 /* Number of fields preceding startstack */ /* field in /proc/self/stat */ +#ifdef USE_LIBC_PRIVATES # pragma weak __libc_stack_end extern ptr_t __libc_stack_end; +#endif # ifdef IA64 /* Try to read the backing store base from /proc/self/maps. */ @@ -861,30 +887,33 @@ ptr_t GC_get_stack_base() return GC_apply_to_maps(backing_store_base_from_maps); } -# pragma weak __libc_ia64_register_backing_store_base - extern ptr_t __libc_ia64_register_backing_store_base; +# ifdef USE_LIBC_PRIVATES +# pragma weak __libc_ia64_register_backing_store_base + extern ptr_t __libc_ia64_register_backing_store_base; +# endif ptr_t GC_get_register_stack_base(void) { - if (0 != &__libc_ia64_register_backing_store_base - && 0 != __libc_ia64_register_backing_store_base) { - /* Glibc 2.2.4 has a bug such that for dynamically linked */ - /* executables __libc_ia64_register_backing_store_base is */ - /* defined but uninitialized during constructor calls. */ - /* Hence we check for both nonzero address and value. */ - return __libc_ia64_register_backing_store_base; - } else { - word result = backing_store_base_from_proc(); - if (0 == result) { +# ifdef USE_LIBC_PRIVATES + if (0 != &__libc_ia64_register_backing_store_base + && 0 != __libc_ia64_register_backing_store_base) { + /* Glibc 2.2.4 has a bug such that for dynamically linked */ + /* executables __libc_ia64_register_backing_store_base is */ + /* defined but uninitialized during constructor calls. */ + /* Hence we check for both nonzero address and value. */ + return __libc_ia64_register_backing_store_base; + } +# endif + word result = backing_store_base_from_proc(); + if (0 == result) { /* Use dumb heuristics. Works only for default configuration. */ result = (word)GC_stackbottom - BACKING_STORE_DISPLACEMENT; result += BACKING_STORE_ALIGNMENT - 1; result &= ~(BACKING_STORE_ALIGNMENT - 1); /* Verify that it's at least readable. If not, we goofed. */ GC_noop1(*(word *)result); - } - return (ptr_t)result; } + return (ptr_t)result; } # endif @@ -903,7 +932,12 @@ ptr_t GC_get_stack_base() size_t i, buf_offset = 0; /* First try the easy way. This should work for glibc 2.2 */ - if (0 != &__libc_stack_end) { + /* This fails in a prelinked ("prelink" command) executable */ + /* since the correct value of __libc_stack_end never */ + /* becomes visible to us. The second test works around */ + /* this. */ +# ifdef USE_LIBC_PRIVATES + if (0 != &__libc_stack_end && 0 != __libc_stack_end ) { # ifdef IA64 /* Some versions of glibc set the address 16 bytes too */ /* low while the initialization code is running. */ @@ -912,9 +946,19 @@ ptr_t GC_get_stack_base() } /* Otherwise it's not safe to add 16 bytes and we fall */ /* back to using /proc. */ # else +# ifdef SPARC + /* Older versions of glibc for 64-bit Sparc do not set + * this variable correctly, it gets set to either zero + * or one. + */ + if (__libc_stack_end != (ptr_t) (unsigned long)0x1) + return __libc_stack_end; +# else return __libc_stack_end; # endif +# endif } +# endif f = open("/proc/self/stat", O_RDONLY); if (f < 0 || STAT_READ(f, stat_buf, STAT_BUF_SIZE) < 2 * STAT_SKIP) { ABORT("Couldn't read /proc/self/stat"); @@ -1137,12 +1181,15 @@ void GC_register_data_segments() /* This used to be set for gcc, to avoid dealing with */ /* the structured exception handling issues. But we now have */ /* assembly code to do that right. */ + GC_bool GC_wnt = FALSE; + /* This is a Windows NT derivative, i.e. NT, W2K, XP or later. */ void GC_init_win32() { /* if we're running under win32s, assume that no DLLs will be loaded */ DWORD v = GetVersion(); - GC_no_win32_dlls |= ((v & 0x80000000) && (v & 0xff) <= 3); + GC_wnt = !(v & 0x80000000); + GC_no_win32_dlls |= ((!GC_wnt) && (v & 0xff) <= 3); } /* Return the smallest address a such that VirtualQuery */ @@ -1328,7 +1375,7 @@ int * etext_addr; /* max_page_size to &etext if &etext is at a page boundary */ GC_setup_temporary_fault_handler(); - if (setjmp(GC_jmp_buf) == 0) { + if (SETJMP(GC_jmp_buf) == 0) { /* Try writing to the address. */ *result = *result; GC_reset_fault_handler(); @@ -1345,7 +1392,7 @@ int * etext_addr; } # endif -# if defined(FREEBSD) && defined(I386) && !defined(PCR) +# if defined(FREEBSD) && (defined(I386) || defined(X86_64) || defined(powerpc) || defined(__powerpc__)) && !defined(PCR) /* Its unclear whether this should be identical to the above, or */ /* whether it should apply to non-X86 architectures. */ /* For now we don't assume that there is always an empty page after */ @@ -1362,7 +1409,7 @@ int * etext_addr; & ~((word)max_page_size - 1); VOLATILE ptr_t result = (ptr_t)text_end; GC_setup_temporary_fault_handler(); - if (setjmp(GC_jmp_buf) == 0) { + if (SETJMP(GC_jmp_buf) == 0) { /* Try reading at the address. */ /* This should happen before there is another thread. */ for (; next_page < (word)(DATAEND); next_page += (word)max_page_size) @@ -1466,7 +1513,7 @@ void GC_register_data_segments() # endif -# ifdef RS6000 +# if 0 && defined(RS6000) /* We now use mmap */ /* The compiler seems to generate speculative reads one past the end of */ /* an allocated object. Hence we need to make sure that the page */ /* following the last heap page is also mapped. */ @@ -1497,8 +1544,7 @@ word bytes; #else /* Not RS6000 */ -#if defined(USE_MMAP) -/* Tested only under Linux, IRIX5 and Solaris 2 */ +#if defined(USE_MMAP) || defined(USE_MUNMAP) #ifdef USE_MMAP_FIXED # define GC_MMAP_FLAGS MAP_FIXED | MAP_PRIVATE @@ -1508,6 +1554,23 @@ word bytes; # define GC_MMAP_FLAGS MAP_PRIVATE #endif +#ifdef USE_MMAP_ANON +# define zero_fd -1 +# if defined(MAP_ANONYMOUS) +# define OPT_MAP_ANON MAP_ANONYMOUS +# else +# define OPT_MAP_ANON MAP_ANON +# endif +#else + static int zero_fd; +# define OPT_MAP_ANON 0 +#endif + +#endif /* defined(USE_MMAP) || defined(USE_MUNMAP) */ + +#if defined(USE_MMAP) +/* Tested only under Linux, IRIX5 and Solaris 2 */ + #ifndef HEAP_START # define HEAP_START 0 #endif @@ -1520,23 +1583,17 @@ word bytes; # ifndef USE_MMAP_ANON static GC_bool initialized = FALSE; - static int fd; if (!initialized) { - fd = open("/dev/zero", O_RDONLY); - fcntl(fd, F_SETFD, FD_CLOEXEC); + zero_fd = open("/dev/zero", O_RDONLY); + fcntl(zero_fd, F_SETFD, FD_CLOEXEC); initialized = TRUE; } # endif if (bytes & (GC_page_size -1)) ABORT("Bad GET_MEM arg"); -# ifdef USE_MMAP_ANON - result = mmap(last_addr, bytes, PROT_READ | PROT_WRITE | OPT_PROT_EXEC, - GC_MMAP_FLAGS | MAP_ANON, -1, 0/* offset */); -# else - result = mmap(last_addr, bytes, PROT_READ | PROT_WRITE | OPT_PROT_EXEC, - GC_MMAP_FLAGS, fd, 0/* offset */); -# endif + result = mmap(last_addr, bytes, PROT_READ | PROT_WRITE | OPT_PROT_EXEC, + GC_MMAP_FLAGS | OPT_MAP_ANON, zero_fd, 0/* offset */); if (result == MAP_FAILED) return(0); last_addr = (ptr_t)result + bytes + GC_page_size - 1; last_addr = (ptr_t)((word)last_addr & ~(GC_page_size - 1)); @@ -1794,7 +1851,15 @@ void GC_unmap(ptr_t start, word bytes) len -= free_len; } # else - if (munmap(start_addr, len) != 0) ABORT("munmap failed"); + /* We immediately remap it to prevent an intervening mmap from */ + /* accidentally grabbing the same address space. */ + { + void * result; + result = mmap(start_addr, len, PROT_NONE, + MAP_PRIVATE | MAP_FIXED | OPT_MAP_ANON, + zero_fd, 0/* offset */); + if (result != (void *)start_addr) ABORT("mmap(...PROT_NONE...) failed"); + } GC_unmapped_bytes += len; # endif } @@ -1802,13 +1867,13 @@ void GC_unmap(ptr_t start, word bytes) void GC_remap(ptr_t start, word bytes) { - static int zero_descr = -1; ptr_t start_addr = GC_unmap_start(start, bytes); ptr_t end_addr = GC_unmap_end(start, bytes); word len = end_addr - start_addr; - ptr_t result; # if defined(MSWIN32) || defined(MSWINCE) + ptr_t result; + if (0 == start_addr) return; while (len != 0) { MEMORY_BASIC_INFORMATION mem_info; @@ -1828,13 +1893,17 @@ void GC_remap(ptr_t start, word bytes) len -= alloc_len; } # else - if (-1 == zero_descr) zero_descr = open("/dev/zero", O_RDWR); - fcntl(zero_descr, F_SETFD, FD_CLOEXEC); + /* It was already remapped with PROT_NONE. */ + int result; + if (0 == start_addr) return; - result = mmap(start_addr, len, PROT_READ | PROT_WRITE | OPT_PROT_EXEC, - MAP_FIXED | MAP_PRIVATE, zero_descr, 0); - if (result != start_addr) { - ABORT("mmap remapping failed"); + result = mprotect(start_addr, len, + PROT_READ | PROT_WRITE | OPT_PROT_EXEC); + if (result != 0) { + GC_err_printf3( + "Mprotect failed at 0x%lx (length %ld) with errno %ld\n", + start_addr, len, errno); + ABORT("Mprotect remapping failed"); } GC_unmapped_bytes -= len; # endif @@ -2137,7 +2206,7 @@ GC_bool is_ptrfree; /* Using vm_protect (mach syscall) over mprotect (BSD syscall) seems to decrease the likelihood of some of the problems described below. */ #include - extern mach_port_t GC_task_self; + static mach_port_t GC_task_self; #define PROTECT(addr,len) \ if(vm_protect(GC_task_self,(vm_address_t)(addr),(vm_size_t)(len), \ FALSE,VM_PROT_READ) != KERN_SUCCESS) { \ @@ -2170,9 +2239,9 @@ GC_bool is_ptrfree; # endif /* !DARWIN */ # endif /* MSWIN32 || MSWINCE || DARWIN */ -#if defined(SUNOS4) || defined(FREEBSD) +#if defined(SUNOS4) || (defined(FREEBSD) && !defined(SUNOS5SIGS)) typedef void (* SIG_PF)(); -#endif /* SUNOS4 || FREEBSD */ +#endif /* SUNOS4 || (FREEBSD && !SUNOS5SIGS) */ #if defined(SUNOS5SIGS) || defined(OSF1) || defined(LINUX) \ || defined(HURD) @@ -2199,13 +2268,13 @@ GC_bool is_ptrfree; #endif /* IRIX5 || OSF1 || HURD */ #if defined(SUNOS5SIGS) -# ifdef HPUX -# define SIGINFO __siginfo +# if defined(HPUX) || defined(FREEBSD) +# define SIGINFO_T siginfo_t # else -# define SIGINFO siginfo +# define SIGINFO_T struct siginfo # endif # ifdef __STDC__ - typedef void (* REAL_SIG_PF)(int, struct SIGINFO *, void *); + typedef void (* REAL_SIG_PF)(int, SIGINFO_T *, void *); # else typedef void (* REAL_SIG_PF)(); # endif @@ -2225,8 +2294,11 @@ GC_bool is_ptrfree; # if defined(ALPHA) || defined(M68K) typedef void (* REAL_SIG_PF)(int, int, s_c *); # else -# if defined(IA64) || defined(HP_PA) +# if defined(IA64) || defined(HP_PA) || defined(X86_64) typedef void (* REAL_SIG_PF)(int, siginfo_t *, s_c *); + /* FIXME: */ + /* According to SUSV3, the last argument should have type */ + /* void * or ucontext_t * */ # else typedef void (* REAL_SIG_PF)(int, s_c); # endif @@ -2301,7 +2373,7 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ /*ARGSUSED*/ #if !defined(DARWIN) -# if defined (SUNOS4) || defined(FREEBSD) +# if defined (SUNOS4) || (defined(FREEBSD) && !defined(SUNOS5SIGS)) void GC_write_fault_handler(sig, code, scp, addr) int sig, code; struct sigcontext *scp; @@ -2314,9 +2386,9 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ # endif # ifdef FREEBSD # define SIG_OK (sig == SIGBUS) -# define CODE_OK (code == BUS_PAGE_FAULT) +# define CODE_OK TRUE # endif -# endif /* SUNOS4 || FREEBSD */ +# endif /* SUNOS4 || (FREEBSD && !SUNOS5SIGS) */ # if defined(IRIX5) || defined(OSF1) || defined(HURD) # include @@ -2339,7 +2411,7 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ # if defined(ALPHA) || defined(M68K) void GC_write_fault_handler(int sig, int code, s_c * sc) # else -# if defined(IA64) || defined(HP_PA) +# if defined(IA64) || defined(HP_PA) || defined(X86_64) void GC_write_fault_handler(int sig, siginfo_t * si, s_c * scp) # else # if defined(ARM32) @@ -2358,11 +2430,11 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ # if defined(SUNOS5SIGS) # ifdef __STDC__ - void GC_write_fault_handler(int sig, struct SIGINFO *scp, void * context) + void GC_write_fault_handler(int sig, SIGINFO_T *scp, void * context) # else void GC_write_fault_handler(sig, scp, context) int sig; - struct SIGINFO *scp; + SIGINFO_T *scp; void * context; # endif # ifdef HPUX @@ -2373,9 +2445,14 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ || (scp -> si_code == SEGV_UNKNOWN) \ || (scp -> si_code == BUS_OBJERR) # else -# define SIG_OK (sig == SIGSEGV) -# define CODE_OK (scp -> si_code == SEGV_ACCERR) -# endif +# ifdef FREEBSD +# define SIG_OK (sig == SIGBUS) +# define CODE_OK (scp -> si_code == BUS_PAGE_FAULT) +# else +# define SIG_OK (sig == SIGSEGV) +# define CODE_OK (scp -> si_code == SEGV_ACCERR) +# endif +# endif # endif /* SUNOS5SIGS */ # if defined(MSWIN32) || defined(MSWINCE) @@ -2400,7 +2477,7 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ char * addr = (char *) (scp -> si_addr); # endif # ifdef LINUX -# if defined(I386) || defined (X86_64) +# if defined(I386) char * addr = (char *) (sc.cr2); # else # if defined(M68K) @@ -2435,7 +2512,7 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ # ifdef ALPHA char * addr = get_fault_addr(sc); # else -# if defined(IA64) || defined(HP_PA) +# if defined(IA64) || defined(HP_PA) || defined(X86_64) char * addr = si -> si_addr; /* I believe this is claimed to work on all platforms for */ /* Linux 2.3.47 and later. Hopefully we don't have to */ @@ -2447,7 +2524,11 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ # if defined(ARM32) char * addr = (char *)sc.fault_address; # else - --> architecture not supported +# if defined(CRIS) + char * addr = (char *)sc.regs.csraddr; +# else + --> architecture not supported +# endif # endif # endif # endif @@ -2478,6 +2559,10 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ in_allocd_block = (HDR(addr) != 0); # endif if (!in_allocd_block) { + /* FIXME - We should make sure that we invoke the */ + /* old handler with the appropriate calling */ + /* sequence, which often depends on SA_SIGINFO. */ + /* Heap blocks now begin and end on page boundaries */ SIG_PF old_handler; @@ -2494,11 +2579,17 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ return(EXCEPTION_CONTINUE_SEARCH); # endif } else { -# if defined (SUNOS4) || defined(FREEBSD) +# if defined (SUNOS4) \ + || (defined(FREEBSD) && !defined(SUNOS5SIGS)) (*old_handler) (sig, code, scp, addr); return; # endif # if defined (SUNOS5SIGS) + /* + * FIXME: For FreeBSD, this code should check if the + * old signal handler used the traditional BSD style and + * if so call it using that style. + */ (*(REAL_SIG_PF)old_handler) (sig, scp, context); return; # endif @@ -2506,7 +2597,7 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ # if defined(ALPHA) || defined(M68K) (*(REAL_SIG_PF)old_handler) (sig, code, sc); # else -# if defined(IA64) || defined(HP_PA) +# if defined(IA64) || defined(HP_PA) || defined(X86_64) (*(REAL_SIG_PF)old_handler) (sig, si, scp); # else (*(REAL_SIG_PF)old_handler) (sig, sc); @@ -2600,7 +2691,8 @@ void GC_dirty_init() struct sigaction act, oldact; /* We should probably specify SA_SIGINFO for Linux, and handle */ /* the different architectures more uniformly. */ -# if defined(IRIX5) || defined(LINUX) || defined(OSF1) || defined(HURD) +# if defined(IRIX5) || defined(LINUX) && !defined(X86_64) \ + || defined(OSF1) || defined(HURD) act.sa_flags = SA_RESTART; act.sa_handler = (SIG_PF)GC_write_fault_handler; # else @@ -2623,7 +2715,7 @@ void GC_dirty_init() GC_err_printf0("Page size not multiple of HBLKSIZE\n"); ABORT("Page size not multiple of HBLKSIZE"); } -# if defined(SUNOS4) || defined(FREEBSD) +# if defined(SUNOS4) || (defined(FREEBSD) && !defined(SUNOS5SIGS)) GC_old_bus_handler = signal(SIGBUS, GC_write_fault_handler); if (GC_old_bus_handler == SIG_IGN) { GC_err_printf0("Previously ignored bus error!?"); @@ -2647,13 +2739,13 @@ void GC_dirty_init() # endif } # endif -# if defined(SUNOS5SIGS) || defined(IRIX5) || defined(LINUX) \ - || defined(OSF1) || defined(HURD) +# if (defined(SUNOS5SIGS) && !defined(FREEBSD)) || defined(IRIX5) \ + || defined(LINUX) || defined(OSF1) || defined(HURD) /* SUNOS5SIGS includes HPUX */ # if defined(GC_IRIX_THREADS) sigaction(SIGSEGV, 0, &oldact); sigaction(SIGSEGV, &act, 0); -# else +# else { int res = sigaction(SIGSEGV, &act, &oldact); if (res != 0) ABORT("Sigaction failed"); @@ -2679,8 +2771,9 @@ void GC_dirty_init() GC_err_printf0("Replaced other SIGSEGV handler\n"); # endif } -# endif -# if defined(HPUX) || defined(LINUX) || defined(HURD) +# endif /* (SUNOS5SIGS && !FREEBSD) || IRIX5 || LINUX || OSF1 || HURD */ +# if defined(HPUX) || defined(LINUX) || defined(HURD) \ + || (defined(FREEBSD) && defined(SUNOS5SIGS)) sigaction(SIGBUS, &act, &oldact); GC_old_bus_handler = oldact.sa_handler; if (GC_old_bus_handler == SIG_IGN) { @@ -2692,7 +2785,7 @@ void GC_dirty_init() GC_err_printf0("Replaced other SIGBUS handler\n"); # endif } -# endif /* HPUX || LINUX || HURD */ +# endif /* HPUX || LINUX || HURD || (FREEBSD && SUNOS5SIGS) */ # if defined(MSWIN32) GC_old_segv_handler = SetUnhandledExceptionFilter(GC_write_fault_handler); if (GC_old_segv_handler != NULL) { @@ -2977,7 +3070,7 @@ word n; #include #include -#define INITIAL_BUF_SZ 4096 +#define INITIAL_BUF_SZ 16384 word GC_proc_buf_size = INITIAL_BUF_SZ; char *GC_proc_buf; @@ -3091,7 +3184,7 @@ int dummy; GC_proc_buf = bufp = new_buf; GC_proc_buf_size = new_size; } - if (syscall(SYS_read, GC_proc_fd, bufp, GC_proc_buf_size) <= 0) { + if (READ(GC_proc_fd, bufp, GC_proc_buf_size) <= 0) { WARN("Insufficient space for /proc read\n", 0); /* Punt: */ memset(GC_grungy_pages, 0xff, sizeof (page_hash_table)); @@ -3278,7 +3371,7 @@ GC_bool is_ptrfree; 1. Apple's mach/xnu documentation 2. Timothy J. Wood's "Mach Exception Handlers 101" post to the omnigroup's macosx-dev list. - www.omnigroup.com/mailman/archive/macosx-dev/2000-June/002030.html + www.omnigroup.com/mailman/archive/macosx-dev/2000-June/014178.html 3. macosx-nat.c from Apple's GDB source code. */ @@ -3312,8 +3405,6 @@ extern kern_return_t exception_raise_state_identity( #define MAX_EXCEPTION_PORTS 16 -static mach_port_t GC_task_self; - static struct { mach_msg_type_number_t count; exception_mask_t masks[MAX_EXCEPTION_PORTS]; @@ -3431,6 +3522,8 @@ static void *GC_mprotect_thread(void *arg) { } msg; mach_msg_id_t id; + + GC_darwin_register_mach_handler_thread(mach_thread_self()); for(;;) { r = mach_msg( @@ -3590,7 +3683,7 @@ void GC_dirty_init() { mask, GC_ports.exception, EXCEPTION_DEFAULT, - MACHINE_THREAD_STATE + GC_MACH_THREAD_STATE ); if(r != KERN_SUCCESS) ABORT("task_set_exception_ports failed"); @@ -3638,7 +3731,7 @@ static kern_return_t GC_forward_exception( exception_behavior_t behavior; thread_state_flavor_t flavor; - thread_state_data_t thread_state; + thread_state_t thread_state; mach_msg_type_number_t thread_state_count = THREAD_STATE_MAX; for(i=0;i # else -# if defined(OPENBSD) || defined(NETBSD) +# if defined(OPENBSD) # include # else -# include +# if defined(FREEBSD) || defined(NETBSD) +# include +# else +# include +# endif # endif # endif # endif @@ -3888,12 +4007,24 @@ kern_return_t catch_exception_raise_state_identity( #endif /* NEED_CALLINFO */ +#if defined(GC_HAVE_BUILTIN_BACKTRACE) +# include +#endif + #ifdef SAVE_CALL_CHAIN #if NARGS == 0 && NFRAMES % 2 == 0 /* No padding */ \ && defined(GC_HAVE_BUILTIN_BACKTRACE) -#include +#ifdef REDIRECT_MALLOC + /* Deal with possible malloc calls in backtrace by omitting */ + /* the infinitely recursing backtrace. */ +# ifdef THREADS + __thread /* If your compiler doesn't understand this */ + /* you could use something like pthread_getspecific. */ +# endif + GC_in_save_callers = FALSE; +#endif void GC_save_callers (info) struct callinfo info[NFRAMES]; @@ -3904,15 +4035,26 @@ struct callinfo info[NFRAMES]; /* We retrieve NFRAMES+1 pc values, but discard the first, since it */ /* points to our own frame. */ +# ifdef REDIRECT_MALLOC + if (GC_in_save_callers) { + info[0].ci_pc = (word)(&GC_save_callers); + for (i = 1; i < NFRAMES; ++i) info[i].ci_pc = 0; + return; + } + GC_in_save_callers = TRUE; +# endif GC_ASSERT(sizeof(struct callinfo) == sizeof(void *)); npcs = backtrace((void **)tmp_info, NFRAMES + IGNORE_FRAMES); BCOPY(tmp_info+IGNORE_FRAMES, info, (npcs - IGNORE_FRAMES) * sizeof(void *)); for (i = npcs - IGNORE_FRAMES; i < NFRAMES; ++i) info[i].ci_pc = 0; +# ifdef REDIRECT_MALLOC + GC_in_save_callers = FALSE; +# endif } #else /* No builtin backtrace; do it ourselves */ -#if (defined(OPENBSD) || defined(NETBSD)) && defined(SPARC) +#if (defined(OPENBSD) || defined(NETBSD) || defined(FREEBSD)) && defined(SPARC) # define FR_SAVFP fr_fp # define FR_SAVPC fr_pc #else @@ -3970,6 +4112,8 @@ struct callinfo info[NFRAMES]; static int reentry_count = 0; GC_bool stop = FALSE; + /* FIXME: This should probably use a different lock, so that we */ + /* become callable with or without the allocation lock. */ LOCK(); ++reentry_count; UNLOCK(); @@ -4004,7 +4148,8 @@ struct callinfo info[NFRAMES]; # ifdef LINUX FILE *pipe; # endif -# if defined(GC_HAVE_BUILTIN_BACKTRACE) +# if defined(GC_HAVE_BUILTIN_BACKTRACE) \ + && !defined(GC_BACKTRACE_SYMBOLS_BROKEN) char **sym_name = backtrace_symbols((void **)(&(info[i].ci_pc)), 1); char *name = sym_name[0]; @@ -4023,6 +4168,9 @@ struct callinfo info[NFRAMES]; # define RESULT_SZ 200 static char result_buf[RESULT_SZ]; size_t result_len; + char *old_preload; +# define PRELOAD_SZ 200 + char preload_buf[PRELOAD_SZ]; static GC_bool found_exe_name = FALSE; static GC_bool will_fail = FALSE; int ret_code; @@ -4044,7 +4192,20 @@ struct callinfo info[NFRAMES]; /* isn't time critical. */ sprintf(cmd_buf, "/usr/bin/addr2line -f -e %s 0x%lx", exe_name, (unsigned long)info[i].ci_pc); + old_preload = getenv ("LD_PRELOAD"); + if (0 != old_preload) { + if (strlen (old_preload) >= PRELOAD_SZ) { + will_fail = TRUE; + goto out; + } + strcpy (preload_buf, old_preload); + unsetenv ("LD_PRELOAD"); + } pipe = popen(cmd_buf, "r"); + if (0 != old_preload + && 0 != setenv ("LD_PRELOAD", preload_buf, 0)) { + WARN("Failed to reset LD_PRELOAD\n", 0); + } if (pipe == NULL || (result_len = fread(result_buf, 1, RESULT_SZ - 1, pipe)) == 0) { @@ -4081,7 +4242,8 @@ struct callinfo info[NFRAMES]; } # endif /* LINUX */ GC_err_printf1("\t\t%s\n", name); -# if defined(GC_HAVE_BUILTIN_BACKTRACE) +# if defined(GC_HAVE_BUILTIN_BACKTRACE) \ + && !defined(GC_BACKTRACE_SYMBOLS_BROKEN) free(sym_name); /* May call GC_free; that's OK */ # endif }