summaryrefslogtreecommitdiff
path: root/os_dep.c
diff options
context:
space:
mode:
Diffstat (limited to 'os_dep.c')
-rw-r--r--os_dep.c215
1 files changed, 181 insertions, 34 deletions
diff --git a/os_dep.c b/os_dep.c
index 81f74f3a..34b871d8 100644
--- a/os_dep.c
+++ b/os_dep.c
@@ -1,6 +1,8 @@
/*
+ * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
* Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved.
- * Copyright (c) 1996-1997 by Silicon Graphics. All rights reserved.
+ * Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved.
+ * Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved.
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
@@ -31,7 +33,7 @@
/* make sure the former gets defined to be the latter if appropriate. */
# include <features.h>
# if 2 <= __GLIBC__
-# if 0 == __GLIBC_MINOR__
+# if 2 == __GLIBC__ && 0 == __GLIBC_MINOR__
/* glibc 2.1 no longer has sigcontext.h. But signal.h */
/* has the right declaration for glibc 2.1. */
# include <sigcontext.h>
@@ -54,17 +56,17 @@
# include <signal.h>
/* Blatantly OS dependent routines, except for those that are related */
-/* dynamic loading. */
+/* to dynamic loading. */
# if !defined(THREADS) && !defined(STACKBOTTOM) && defined(HEURISTIC2)
# define NEED_FIND_LIMIT
# endif
-# if defined(IRIX_THREADS)
+# if defined(IRIX_THREADS) || defined(HPUX_THREADS)
# define NEED_FIND_LIMIT
# endif
-# if (defined(SUNOS4) & defined(DYNAMIC_LOADING)) && !defined(PCR)
+# if (defined(SUNOS4) && defined(DYNAMIC_LOADING)) && !defined(PCR)
# define NEED_FIND_LIMIT
# endif
@@ -72,7 +74,9 @@
# define NEED_FIND_LIMIT
# endif
-# if defined(LINUX) && (defined(POWERPC) || defined(SPARC) || defined(ALPHA))
+# if defined(LINUX) && \
+ (defined(POWERPC) || defined(SPARC) || defined(ALPHA) || defined(IA64) \
+ || defined(MIPS))
# define NEED_FIND_LIMIT
# endif
@@ -139,7 +143,8 @@
# define OPT_PROT_EXEC 0
#endif
-#if defined(LINUX) && (defined(POWERPC) || defined(SPARC) || defined(ALPHA))
+#if defined(SEARCH_FOR_DATA_START)
+ /* The following doesn't work if the GC is in a dynamic library. */
/* The I386 case can be handled without a search. The Alpha case */
/* used to be handled differently as well, but the rules changed */
/* for recent Linux versions. This seems to be the easiest way to */
@@ -497,7 +502,7 @@ ptr_t GC_get_stack_base()
# if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1)
static struct sigaction old_segv_act;
-# if defined(_sigargs) /* !Irix6.x */
+# if defined(_sigargs) || defined(HPUX) /* !Irix6.x */
static struct sigaction old_bus_act;
# endif
# else
@@ -525,10 +530,11 @@ ptr_t GC_get_stack_base()
(void) sigaction(SIGSEGV, &act, 0);
# else
(void) sigaction(SIGSEGV, &act, &old_segv_act);
-# ifdef _sigargs /* Irix 5.x, not 6.x */
- /* Under 5.x, we may get SIGBUS. */
- /* Pthreads doesn't exist under 5.x, so we don't */
- /* have to worry in the threads case. */
+# if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \
+ || defined(HPUX)
+ /* 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. */
(void) sigaction(SIGBUS, &act, &old_bus_act);
# endif
# endif /* IRIX_THREADS */
@@ -544,7 +550,8 @@ ptr_t GC_get_stack_base()
{
# if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1)
(void) sigaction(SIGSEGV, &old_segv_act, 0);
-# ifdef _sigargs /* Irix 5.x, not 6.x */
+# if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \
+ || defined(HPUX)
(void) sigaction(SIGBUS, &old_bus_act, 0);
# endif
# else
@@ -589,6 +596,55 @@ ptr_t GC_get_stack_base()
}
# endif
+#ifdef LINUX_STACKBOTTOM
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+# define STAT_SKIP 27 /* Number of fields preceding startstack */
+ /* field in /proc/self/stat */
+
+ ptr_t GC_linux_stack_base(void)
+ {
+ /* We read the stack base value from /proc/self/stat. We do this */
+ /* using direct I/O system calls in order to avoid calling malloc */
+ /* in case REDIRECT_MALLOC is defined. */
+# define STAT_BUF_SIZE 4096
+# ifdef USE_LD_WRAP
+# define STAT_READ __real_read
+# else
+# define STAT_READ read
+# endif
+ char stat_buf[STAT_BUF_SIZE];
+ int f;
+ char c;
+ word result = 0;
+ size_t i, buf_offset = 0;
+
+ 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");
+ }
+ c = stat_buf[buf_offset++];
+ /* Skip the required number of fields. This number is hopefully */
+ /* constant across all Linux implementations. */
+ for (i = 0; i < STAT_SKIP; ++i) {
+ while (isspace(c)) c = stat_buf[buf_offset++];
+ while (!isspace(c)) c = stat_buf[buf_offset++];
+ }
+ while (isspace(c)) c = stat_buf[buf_offset++];
+ while (isdigit(c)) {
+ result *= 10;
+ result += c - '0';
+ c = stat_buf[buf_offset++];
+ }
+ close(f);
+ if (result < 0x10000000) ABORT("Absurd stack bottom value");
+ return (ptr_t)result;
+ }
+
+#endif /* LINUX_STACKBOTTOM */
ptr_t GC_get_stack_base()
{
@@ -610,6 +666,9 @@ ptr_t GC_get_stack_base()
& ~STACKBOTTOM_ALIGNMENT_M1);
# endif
# endif /* HEURISTIC1 */
+# ifdef LINUX_STACKBOTTOM
+ result = GC_linux_stack_base();
+# endif
# ifdef HEURISTIC2
# ifdef STACK_GROWS_DOWN
result = GC_find_limit((ptr_t)(&dummy), TRUE);
@@ -1443,7 +1502,7 @@ void GC_default_push_other_roots()
# if defined(SOLARIS_THREADS) || defined(WIN32_THREADS) \
|| defined(IRIX_THREADS) || defined(LINUX_THREADS) \
- || defined(IRIX_PCR_THREADS)
+ || defined(IRIX_JDK_THREADS) || defined(HPUX_THREADS)
extern void GC_push_all_stacks();
@@ -1570,12 +1629,12 @@ struct hblk *h;
# include <sys/syscall.h>
# define PROTECT(addr, len) \
- if (mprotect((caddr_t)(addr), (int)(len), \
+ if (mprotect((caddr_t)(addr), (size_t)(len), \
PROT_READ | OPT_PROT_EXEC) < 0) { \
ABORT("mprotect failed"); \
}
# define UNPROTECT(addr, len) \
- if (mprotect((caddr_t)(addr), (int)(len), \
+ if (mprotect((caddr_t)(addr), (size_t)(len), \
PROT_WRITE | PROT_READ | OPT_PROT_EXEC ) < 0) { \
ABORT("un-mprotect failed"); \
}
@@ -1604,7 +1663,11 @@ struct hblk *h;
typedef void (* SIG_PF)();
#endif
#if defined(SUNOS5SIGS) || defined(OSF1) || defined(LINUX)
+# ifdef __STDC__
typedef void (* SIG_PF)(int);
+# else
+ typedef void (* SIG_PF)();
+# endif
#endif
#if defined(MSWIN32)
typedef LPTOP_LEVEL_EXCEPTION_FILTER SIG_PF;
@@ -1616,17 +1679,34 @@ struct hblk *h;
typedef void (* REAL_SIG_PF)(int, int, struct sigcontext *);
#endif
#if defined(SUNOS5SIGS)
- typedef void (* REAL_SIG_PF)(int, struct siginfo *, void *);
+# ifdef HPUX
+# define SIGINFO __siginfo
+# else
+# define SIGINFO siginfo
+# endif
+# ifdef __STDC__
+ typedef void (* REAL_SIG_PF)(int, struct SIGINFO *, void *);
+# else
+ typedef void (* REAL_SIG_PF)();
+# endif
#endif
#if defined(LINUX)
# include <linux/version.h>
-# if (LINUX_VERSION_CODE >= 0x20100) && !defined(M68K) || defined(ALPHA)
+# if (LINUX_VERSION_CODE >= 0x20100) && !defined(M68K) || defined(ALPHA) || defined(IA64)
typedef struct sigcontext s_c;
# else
typedef struct sigcontext_struct s_c;
# endif
+# if defined(ALPHA) || defined(M68K)
+ typedef void (* REAL_SIG_PF)(int, int, s_c *);
+# else
+# if defined(IA64)
+ typedef void (* REAL_SIG_PF)(int, siginfo_t *, s_c *);
+# else
+ typedef void (* REAL_SIG_PF)(int, s_c);
+# endif
+# endif
# ifdef ALPHA
- typedef void (* REAL_SIG_PF)(int, int, s_c *);
/* Retrieve fault address from sigcontext structure by decoding */
/* instruction. */
char * get_fault_addr(s_c *sc) {
@@ -1638,8 +1718,6 @@ struct hblk *h;
faultaddr += (word) (((int)instr << 16) >> 16);
return (char *)faultaddr;
}
-# else /* !ALPHA */
- typedef void (* REAL_SIG_PF)(int, s_c);
# endif /* !ALPHA */
# endif
@@ -1675,21 +1753,41 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */
# endif
# endif
# if defined(LINUX)
-# ifdef ALPHA
+# if defined(ALPHA) || defined(M68K)
void GC_write_fault_handler(int sig, int code, s_c * sc)
# else
- void GC_write_fault_handler(int sig, s_c sc)
+# if defined(IA64)
+ void GC_write_fault_handler(int sig, siginfo_t * si, s_c * scp)
+# else
+ void GC_write_fault_handler(int sig, s_c sc)
+# endif
# endif
# define SIG_OK (sig == SIGSEGV)
# define CODE_OK TRUE
- /* Empirically c.trapno == 14, but is that useful? */
- /* We assume Intel architecture, so alignment */
- /* faults are not possible. */
+ /* Empirically c.trapno == 14, on IA32, but is that useful? */
+ /* Should probably consider alignment issues on other */
+ /* architectures. */
# endif
# if defined(SUNOS5SIGS)
- void GC_write_fault_handler(int sig, struct siginfo *scp, void * context)
-# define SIG_OK (sig == SIGSEGV)
-# define CODE_OK (scp -> si_code == SEGV_ACCERR)
+# ifdef __STDC__
+ void GC_write_fault_handler(int sig, struct SIGINFO *scp, void * context)
+# else
+ void GC_write_fault_handler(sig, scp, context)
+ int sig;
+ struct SIGINFO *scp;
+ void * context;
+# endif
+# ifdef HPUX
+# define SIG_OK (sig == SIGSEGV || sig == SIGBUS)
+# define CODE_OK (scp -> si_code == SEGV_ACCERR) \
+ || (scp -> si_code == BUS_ADRERR) \
+ || (scp -> si_code == BUS_UNKNOWN) \
+ || (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
# endif
# if defined(MSWIN32)
LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info)
@@ -1741,7 +1839,18 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */
# ifdef ALPHA
char * addr = get_fault_addr(sc);
# else
+# ifdef IA64
+ 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 */
+ /* worry about earlier kernels on IA64. */
+# else
+# if defined(POWERPC)
+ char * addr = (char *) (sc.regs->dar);
+# else
--> architecture not supported
+# endif
+# endif
# endif
# endif
# endif
@@ -1794,10 +1903,14 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */
return;
# endif
# if defined (LINUX)
-# ifdef ALPHA
+# if defined(ALPHA) || defined(M68K)
(*(REAL_SIG_PF)old_handler) (sig, code, sc);
# else
+# if defined(IA64)
+ (*(REAL_SIG_PF)old_handler) (sig, si, scp);
+# else
(*(REAL_SIG_PF)old_handler) (sig, sc);
+# endif
# endif
return;
# endif
@@ -1909,7 +2022,7 @@ void GC_dirty_init()
}
# endif
# if defined(SUNOS5SIGS) || defined(IRIX5)
-# if defined(IRIX_THREADS) || defined(IRIX_PCR_THREADS)
+# if defined(IRIX_THREADS) || defined(IRIX_JDK_THREADS)
sigaction(SIGSEGV, 0, &oldact);
sigaction(SIGSEGV, &act, 0);
# else
@@ -1935,6 +2048,15 @@ void GC_dirty_init()
GC_err_printf0("Replaced other SIGSEGV handler\n");
# endif
}
+# ifdef HPUX
+ sigaction(SIGBUS, &act, &oldact);
+ GC_old_bus_handler = oldact.sa_handler;
+ if (GC_old_segv_handler != SIG_DFL) {
+# ifdef PRINTSTATS
+ GC_err_printf0("Replaced other SIGBUS handler\n");
+# endif
+ }
+# endif
# endif
# if defined(MSWIN32)
GC_old_segv_handler = SetUnhandledExceptionFilter(GC_write_fault_handler);
@@ -2026,12 +2148,13 @@ word len;
((ptr_t)end_block - (ptr_t)start_block) + HBLKSIZE);
}
-#ifndef MSWIN32
+#if !defined(MSWIN32) && !defined(LINUX_THREADS)
/* Replacement for UNIX system call. */
/* Other calls that write to the heap */
/* should be handled similarly. */
# if defined(__STDC__) && !defined(SUNOS4)
# include <unistd.h>
+# include <sys/uio.h>
ssize_t read(int fd, void *buf, size_t nbyte)
# else
# ifndef LINT
@@ -2048,10 +2171,12 @@ word len;
GC_begin_syscall();
GC_unprotect_range(buf, (word)nbyte);
-# ifdef IRIX5
+# if defined(IRIX5) || defined(LINUX_THREADS)
/* Indirect system call may not always be easily available. */
/* We could call _read, but that would interfere with the */
/* libpthread interception of read. */
+ /* On Linux, we have to be careful with the linuxthreads */
+ /* read interception. */
{
struct iovec iov;
@@ -2065,7 +2190,29 @@ word len;
GC_end_syscall();
return(result);
}
-#endif /* !MSWIN32 */
+#endif /* !MSWIN32 && !LINUX */
+
+#ifdef USE_LD_WRAP
+ /* We use the GNU ld call wrapping facility. */
+ /* This requires that the linker be invoked with "--wrap read". */
+ /* This can be done by passing -Wl,"--wrap read" to gcc. */
+ /* I'm not sure that this actually wraps whatever version of read */
+ /* is called by stdio. That code also mentions __read. */
+# include <unistd.h>
+ ssize_t __wrap_read(int fd, void *buf, size_t nbyte)
+ {
+ int result;
+
+ GC_begin_syscall();
+ GC_unprotect_range(buf, (word)nbyte);
+ result = __real_read(fd, buf, nbyte);
+ GC_end_syscall();
+ return(result);
+ }
+
+ /* We should probably also do this for __read, or whatever stdio */
+ /* actually calls. */
+#endif
/*ARGSUSED*/
GC_bool GC_page_was_ever_dirty(h)