summaryrefslogtreecommitdiff
path: root/boehm-gc/os_dep.c
diff options
context:
space:
mode:
authorbryce <bryce@138bc75d-0d04-0410-961f-82ee72b054a4>2004-08-13 23:05:36 +0000
committerbryce <bryce@138bc75d-0d04-0410-961f-82ee72b054a4>2004-08-13 23:05:36 +0000
commite08a5204e5f7a3c3a15588de39202f9579ba0e79 (patch)
tree863181355c9339e1361dad10263a322aaabe426e /boehm-gc/os_dep.c
parent7cde58555127f31ba0a5b2a222c81d160e7168e9 (diff)
downloadgcc-e08a5204e5f7a3c3a15588de39202f9579ba0e79.tar.gz
libjava:
2004-08-13 Bryce McKinlay <mckinlay@redhat.com> * configure.in (GCINCS): Don't use "boehm-cflags". Instead, -I boehm-gc's include dirs. * configure: Rebuilt. * include/boehm-gc.h: Include gc_config.h. boehm-gc: 2004-08-13 Bryce McKinlay <mckinlay@redhat.com> * configure.ac (gc_cflags): Add -Iinclude. (AC_CONFIG_HEADERS): New. Configure gc_config.h header. Don't write DEFS to boehm-cflags file. * configure: Rebuilt. * gcj_mlc.c: Check #ifdef GC_GCJ_SUPPORT after including headers. * specific.c: Check #ifdef GC_LINUX_THREADS after including headers. * include/gc_config_macros.h: Remove backward-compatibility redefinitions of GC_ names. * include/gc.h: Include <gc_config.h>. 2004-08-13 Bryce McKinlay <mckinlay@redhat.com> Import Boehm GC version 6.3. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@85972 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'boehm-gc/os_dep.c')
-rw-r--r--boehm-gc/os_dep.c395
1 files changed, 247 insertions, 148 deletions
diff --git a/boehm-gc/os_dep.c b/boehm-gc/os_dep.c
index 2defc7174a1..21d05635ab8 100644
--- a/boehm-gc/os_dep.c
+++ b/boehm-gc/os_dep.c
@@ -87,6 +87,12 @@
# 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 <setjmp.h>
#endif
@@ -111,25 +117,30 @@
# include <sys/uio.h>
# include <malloc.h> /* for locking */
#endif
-#ifdef USE_MMAP
+#if defined(USE_MMAP) || defined(USE_MUNMAP)
+# ifndef USE_MMAP
+ --> USE_MUNMAP requires USE_MMAP
+# endif
# include <sys/types.h>
# include <sys/mman.h>
# include <sys/stat.h>
+# include <errno.h>
#endif
#ifdef UNIX_LIKE
# include <fcntl.h>
-#endif
-
-#if defined(SUNOS5SIGS) || defined (HURD) || defined(LINUX)
-# ifdef SUNOS5SIGS
+# if defined(SUNOS5SIGS) && !defined(FREEBSD)
# include <sys/siginfo.h>
# 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 +194,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);
@@ -352,7 +359,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 +696,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(_sigargs) /* !Irix6.x */ || defined(HPUX) \
+ || defined(HURD) || defined(NETBSD)
static struct sigaction old_bus_act;
# endif
# else
@@ -704,21 +714,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
@@ -729,7 +735,7 @@ ptr_t GC_get_stack_base()
# else
(void) sigaction(SIGSEGV, &act, &old_segv_act);
# if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \
- || defined(HPUX) || defined(HURD)
+ || 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 +754,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 +770,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(_sigargs) /* Irix 5.x, not 6.x */ \
+ || 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 +792,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,6 +827,29 @@ ptr_t GC_get_stack_base()
}
#endif
+#ifdef HPUX_STACKBOTTOM
+
+#include <sys/param.h>
+#include <sys/pstat.h>
+
+ 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 <sys/types.h>
@@ -903,7 +932,11 @@ 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. */
+ 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. */
@@ -1328,7 +1361,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();
@@ -1362,7 +1395,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)
@@ -1497,8 +1530,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 +1540,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 +1569,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 +1837,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 +1853,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 +1879,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
@@ -2170,9 +2225,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 +2254,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 +2280,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 +2359,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;
@@ -2316,7 +2374,7 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */
# define SIG_OK (sig == SIGBUS)
# define CODE_OK (code == BUS_PAGE_FAULT)
# endif
-# endif /* SUNOS4 || FREEBSD */
+# endif /* SUNOS4 || (FREEBSD && !SUNOS5SIGS) */
# if defined(IRIX5) || defined(OSF1) || defined(HURD)
# include <errno.h>
@@ -2339,7 +2397,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 +2416,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 +2431,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 +2463,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 +2498,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 */
@@ -2478,6 +2541,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 +2561,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 +2579,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 +2673,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 +2697,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 +2721,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 +2753,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 +2767,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 +3052,7 @@ word n;
#include <sys/procfs.h>
#include <sys/stat.h>
-#define INITIAL_BUF_SZ 4096
+#define INITIAL_BUF_SZ 16384
word GC_proc_buf_size = INITIAL_BUF_SZ;
char *GC_proc_buf;
@@ -3091,7 +3166,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));
@@ -3429,6 +3504,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(
@@ -3886,13 +3963,15 @@ kern_return_t catch_exception_raise_state_identity(
#endif /* NEED_CALLINFO */
+#if defined(GC_HAVE_BUILTIN_BACKTRACE)
+# include <execinfo.h>
+#endif
+
#ifdef SAVE_CALL_CHAIN
#if NARGS == 0 && NFRAMES % 2 == 0 /* No padding */ \
&& defined(GC_HAVE_BUILTIN_BACKTRACE)
-#include <execinfo.h>
-
void GC_save_callers (info)
struct callinfo info[NFRAMES];
{
@@ -3968,6 +4047,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();
@@ -4002,7 +4083,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];
@@ -4021,6 +4103,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;
@@ -4042,7 +4127,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) {
@@ -4079,7 +4177,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
}