[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Emacs-diffs] Changes to emacs/gc/os_dep.c [Boehm-GC]
From: |
Dave Love |
Subject: |
[Emacs-diffs] Changes to emacs/gc/os_dep.c [Boehm-GC] |
Date: |
Mon, 16 Jun 2003 11:41:53 -0400 |
Index: emacs/gc/os_dep.c
diff -c emacs/gc/os_dep.c:1.2.2.2 emacs/gc/os_dep.c:1.2.2.3
*** emacs/gc/os_dep.c:1.2.2.2 Fri Jun 6 05:44:19 2003
--- emacs/gc/os_dep.c Mon Jun 16 11:41:51 2003
***************
*** 132,137 ****
--- 132,142 ----
# define jmp_buf sigjmp_buf
#endif
+ #ifdef DARWIN
+ /* for get_etext and friends */
+ #include <mach-o/getsect.h>
+ #endif
+
#ifdef DJGPP
/* Apparently necessary for djgpp 2.01. May cause problems with */
/* other versions. */
***************
*** 150,155 ****
--- 155,310 ----
# define OPT_PROT_EXEC 0
#endif
+ #if defined(LINUX) && \
+ (defined(USE_PROC_FOR_LIBRARIES) || defined(IA64) ||
!defined(SMALL_CONFIG))
+
+ /* We need to parse /proc/self/maps, either to find dynamic libraries,
*/
+ /* and/or to find the register backing store base (IA64). Do it once */
+ /* here. */
+
+ #define READ read
+
+ /* Repeatedly perform a read call until the buffer is filled or */
+ /* we encounter EOF. */
+ ssize_t GC_repeat_read(int fd, char *buf, size_t count)
+ {
+ ssize_t num_read = 0;
+ ssize_t result;
+
+ while (num_read < count) {
+ result = READ(fd, buf + num_read, count - num_read);
+ if (result < 0) return result;
+ if (result == 0) break;
+ num_read += result;
+ }
+ return num_read;
+ }
+
+ /*
+ * Apply fn to a buffer containing the contents of /proc/self/maps.
+ * Return the result of fn or, if we failed, 0.
+ */
+
+ 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;
+ 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);
+ 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';
+
+ /* Apply fn to result. */
+ return fn(maps_buf);
+ }
+
+ #endif /* Need GC_apply_to_maps */
+
+ #if defined(LINUX) && (defined(USE_PROC_FOR_LIBRARIES) || defined(IA64))
+ //
+ // GC_parse_map_entry parses an entry from /proc/self/maps so we can
+ // locate all writable data segments that belong to shared libraries.
+ // The format of one of these entries and the fields we care about
+ // is as follows:
+ // 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'.)
+ //
+ #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,
+ * *prot_buf and *maj_dev. Only *prot_buf may be set for unwritable maps.
+ */
+ char *GC_parse_map_entry(char *buf_ptr, word *start, word *end,
+ char *prot_buf, unsigned int *maj_dev)
+ {
+ int i;
+ char *tok;
+
+ if (buf_ptr == NULL || *buf_ptr == '\0') {
+ return NULL;
+ }
+
+ memcpy(prot_buf, buf_ptr+OFFSET_MAP_PROT, 4);
+ /* do the protections first. */
+ 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);
+ }
+
+ while (*buf_ptr && *buf_ptr++ != '\n');
+
+ return buf_ptr;
+ }
+
+ #endif /* Need to parse /proc/self/maps. */
+
#if defined(SEARCH_FOR_DATA_START)
/* The I386 case can be handled without a search. The Alpha case */
/* used to be handled differently as well, but the rules changed */
***************
*** 679,684 ****
--- 834,866 ----
extern ptr_t __libc_stack_end;
# ifdef IA64
+ /* Try to read the backing store base from /proc/self/maps. */
+ /* We look for the writable mapping with a 0 major device, */
+ /* which is as close to our frame as possible, but below it.*/
+ static word backing_store_base_from_maps(char *maps)
+ {
+ char prot_buf[5];
+ char *buf_ptr = maps;
+ word start, end;
+ unsigned int maj_dev;
+ word current_best = 0;
+ word dummy;
+
+ for (;;) {
+ buf_ptr = GC_parse_map_entry(buf_ptr, &start, &end, prot_buf,
&maj_dev);
+ if (buf_ptr == NULL) return current_best;
+ if (prot_buf[1] == 'w' && maj_dev == 0) {
+ if (end < (word)(&dummy) && start > current_best) current_best =
start;
+ }
+ }
+ return current_best;
+ }
+
+ static word backing_store_base_from_proc(void)
+ {
+ 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;
***************
*** 688,700 ****
&& 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 ininitialized during constructor calls. */
/* Hence we check for both nonzero address and value. */
return __libc_ia64_register_backing_store_base;
} else {
! word result = (word)GC_stackbottom - BACKING_STORE_DISPLACEMENT;
! result += BACKING_STORE_ALIGNMENT - 1;
! result &= ~(BACKING_STORE_ALIGNMENT - 1);
return (ptr_t)result;
}
}
--- 870,888 ----
&& 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) {
! /* 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;
}
}
***************
*** 706,716 ****
/* using direct I/O system calls in order to avoid calling malloc */
/* in case REDIRECT_MALLOC is defined. */
# define STAT_BUF_SIZE 4096
! # if defined(GC_USE_LD_WRAP)
! # define STAT_READ __real_read
! # else
! # define STAT_READ read
! # endif
char stat_buf[STAT_BUF_SIZE];
int f;
char c;
--- 894,901 ----
/* using direct I/O system calls in order to avoid calling malloc */
/* in case REDIRECT_MALLOC is defined. */
# define STAT_BUF_SIZE 4096
! # define STAT_READ read
! /* Should probably call the real read, if read is wrapped. */
char stat_buf[STAT_BUF_SIZE];
int f;
char c;
***************
*** 782,789 ****
--- 967,977 ----
ptr_t GC_get_stack_base()
{
+ # if defined(HEURISTIC1) || defined(HEURISTIC2) || \
+ defined(LINUX_STACKBOTTOM) || defined(FREEBSD_STACKBOTTOM)
word dummy;
ptr_t result;
+ # endif
# define STACKBOTTOM_ALIGNMENT_M1 ((word)STACK_GRAN - 1)
***************
*** 945,956 ****
/* all real work is done by GC_register_dynamic_libraries. Under */
/* win32s, we cannot find the data segments associated with dll's. */
/* We register the main data segment here. */
- # ifdef __GCC__
- GC_bool GC_no_win32_dlls = TRUE;
- /* GCC can't do SEH, so we can't use VirtualQuery */
- # else
GC_bool GC_no_win32_dlls = FALSE;
! # endif
void GC_init_win32()
{
--- 1133,1142 ----
/* all real work is done by GC_register_dynamic_libraries. Under */
/* win32s, we cannot find the data segments associated with dll's. */
/* We register the main data segment here. */
GC_bool GC_no_win32_dlls = FALSE;
! /* 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. */
void GC_init_win32()
{
***************
*** 1830,1836 ****
* make sure that other system calls are similarly protected
* or write only to the stack.
*/
-
GC_bool GC_dirty_maintained = FALSE;
# ifdef DEFAULT_VDB
--- 2016,2021 ----
***************
*** 1844,1849 ****
--- 2029,2037 ----
/* Initialize virtual dirty bit implementation. */
void GC_dirty_init()
{
+ # ifdef PRINTSTATS
+ GC_printf0("Initializing DEFAULT_VDB...\n");
+ # endif
GC_dirty_maintained = TRUE;
}
***************
*** 1926,1932 ****
* objects only if they are the same.
*/
! # if !defined(MSWIN32) && !defined(MSWINCE)
# include <sys/mman.h>
# include <signal.h>
--- 2114,2120 ----
* objects only if they are the same.
*/
! # if !defined(MSWIN32) && !defined(MSWINCE) && !defined(DARWIN)
# include <sys/mman.h>
# include <signal.h>
***************
*** 1945,1950 ****
--- 2133,2155 ----
# else
+ # ifdef DARWIN
+ /* Using vm_protect (mach syscall) over mprotect (BSD syscall) seems to
+ decrease the likelihood of some of the problems described below. */
+ #include <mach/vm_map.h>
+ extern 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) { \
+ ABORT("vm_portect failed"); \
+ }
+ #define UNPROTECT(addr,len) \
+ if(vm_protect(GC_task_self,(vm_address_t)(addr),(vm_size_t)(len), \
+ FALSE,VM_PROT_READ|VM_PROT_WRITE) != KERN_SUCCESS) { \
+ ABORT("vm_portect failed"); \
+ }
+ # else
+
# ifndef MSWINCE
# include <signal.h>
# endif
***************
*** 1962,1981 ****
&protect_junk)) { \
ABORT("un-VirtualProtect failed"); \
}
!
! # endif
#if defined(SUNOS4) || defined(FREEBSD)
typedef void (* SIG_PF)();
! #endif
#if defined(SUNOS5SIGS) || defined(OSF1) || defined(LINUX) \
! || defined(MACOSX) || defined(HURD)
# ifdef __STDC__
typedef void (* SIG_PF)(int);
# else
typedef void (* SIG_PF)();
# endif
! #endif
#if defined(MSWIN32)
typedef LPTOP_LEVEL_EXCEPTION_FILTER SIG_PF;
# undef SIG_DFL
--- 2167,2188 ----
&protect_junk)) { \
ABORT("un-VirtualProtect failed"); \
}
! # endif /* !DARWIN */
! # endif /* MSWIN32 || MSWINCE || DARWIN */
#if defined(SUNOS4) || defined(FREEBSD)
typedef void (* SIG_PF)();
! #endif /* SUNOS4 || FREEBSD */
!
#if defined(SUNOS5SIGS) || defined(OSF1) || defined(LINUX) \
! || defined(HURD)
# ifdef __STDC__
typedef void (* SIG_PF)(int);
# else
typedef void (* SIG_PF)();
# endif
! #endif /* SUNOS5SIGS || OSF1 || LINUX || HURD */
!
#if defined(MSWIN32)
typedef LPTOP_LEVEL_EXCEPTION_FILTER SIG_PF;
# undef SIG_DFL
***************
*** 1989,1995 ****
#if defined(IRIX5) || defined(OSF1) || defined(HURD)
typedef void (* REAL_SIG_PF)(int, int, struct sigcontext *);
! #endif
#if defined(SUNOS5SIGS)
# ifdef HPUX
# define SIGINFO __siginfo
--- 2196,2203 ----
#if defined(IRIX5) || defined(OSF1) || defined(HURD)
typedef void (* REAL_SIG_PF)(int, int, struct sigcontext *);
! #endif /* IRIX5 || OSF1 || HURD */
!
#if defined(SUNOS5SIGS)
# ifdef HPUX
# define SIGINFO __siginfo
***************
*** 2001,2007 ****
# else
typedef void (* REAL_SIG_PF)();
# endif
! #endif
#if defined(LINUX)
# if __GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ >= 2
typedef struct sigcontext s_c;
--- 2209,2216 ----
# else
typedef void (* REAL_SIG_PF)();
# endif
! #endif /* SUNOS5SIGS */
!
#if defined(LINUX)
# if __GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ >= 2
typedef struct sigcontext s_c;
***************
*** 2035,2173 ****
return (char *)faultaddr;
}
# endif /* !ALPHA */
! # endif
!
! # if defined(MACOSX) /* Should also test for PowerPC? */
! typedef void (* REAL_SIG_PF)(int, int, struct sigcontext *);
!
! /* Decodes the machine instruction which was responsible for the sending of
the
! SIGBUS signal. Sadly this is the only way to find the faulting address
because
! the signal handler doesn't get it directly from the kernel (although it is
! available on the Mach level, but droppped by the BSD personality before it
! calls our signal handler...)
! This code should be able to deal correctly with all PPCs starting from the
! 601 up to and including the G4s (including Velocity Engine). */
! #define EXTRACT_OP1(iw) (((iw) & 0xFC000000) >> 26)
! #define EXTRACT_OP2(iw) (((iw) & 0x000007FE) >> 1)
! #define EXTRACT_REGA(iw) (((iw) & 0x001F0000) >> 16)
! #define EXTRACT_REGB(iw) (((iw) & 0x03E00000) >> 21)
! #define EXTRACT_REGC(iw) (((iw) & 0x0000F800) >> 11)
! #define EXTRACT_DISP(iw) ((short *) &(iw))[1]
!
! static char *get_fault_addr(struct sigcontext *scp)
! {
! unsigned int instr = *((unsigned int *) scp->sc_ir);
! unsigned int * regs = &((unsigned int *) scp->sc_regs)[2];
! int disp = 0, tmp;
! unsigned int baseA = 0, baseB = 0;
! unsigned int addr, alignmask = 0xFFFFFFFF;
!
! #ifdef GC_DEBUG_DECODER
! GC_err_printf1("Instruction: 0x%lx\n", instr);
! GC_err_printf1("Opcode 1: d\n", (int)EXTRACT_OP1(instr));
! #endif
! switch(EXTRACT_OP1(instr)) {
! case 38: /* stb */
! case 39: /* stbu */
! case 54: /* stfd */
! case 55: /* stfdu */
! case 52: /* stfs */
! case 53: /* stfsu */
! case 44: /* sth */
! case 45: /* sthu */
! case 47: /* stmw */
! case 36: /* stw */
! case 37: /* stwu */
! tmp = EXTRACT_REGA(instr);
! if(tmp > 0)
! baseA = regs[tmp];
! disp = EXTRACT_DISP(instr);
! break;
! case 31:
! #ifdef GC_DEBUG_DECODER
! GC_err_printf1("Opcode 2: %d\n", (int)EXTRACT_OP2(instr));
! #endif
! switch(EXTRACT_OP2(instr)) {
! case 86: /* dcbf */
! case 54: /* dcbst */
! case 1014: /* dcbz */
! case 247: /* stbux */
! case 215: /* stbx */
! case 759: /* stfdux */
! case 727: /* stfdx */
! case 983: /* stfiwx */
! case 695: /* stfsux */
! case 663: /* stfsx */
! case 918: /* sthbrx */
! case 439: /* sthux */
! case 407: /* sthx */
! case 661: /* stswx */
! case 662: /* stwbrx */
! case 150: /* stwcx. */
! case 183: /* stwux */
! case 151: /* stwx */
! case 135: /* stvebx */
! case 167: /* stvehx */
! case 199: /* stvewx */
! case 231: /* stvx */
! case 487: /* stvxl */
! tmp = EXTRACT_REGA(instr);
! if(tmp > 0)
! baseA = regs[tmp];
! baseB = regs[EXTRACT_REGC(instr)];
! /* determine Altivec alignment mask */
! switch(EXTRACT_OP2(instr)) {
! case 167: /* stvehx */
! alignmask = 0xFFFFFFFE;
! break;
! case 199: /* stvewx */
! alignmask = 0xFFFFFFFC;
! break;
! case 231: /* stvx */
! alignmask = 0xFFFFFFF0;
! break;
! case 487: /* stvxl */
! alignmask = 0xFFFFFFF0;
! break;
! }
! break;
! case 725: /* stswi */
! tmp = EXTRACT_REGA(instr);
! if(tmp > 0)
! baseA = regs[tmp];
! break;
! default: /* ignore instruction */
! #ifdef GC_DEBUG_DECODER
! GC_err_printf("Ignored by inner handler\n");
! #endif
! return NULL;
! break;
! }
! break;
! default: /* ignore instruction */
! #ifdef GC_DEBUG_DECODER
! GC_err_printf("Ignored by main handler\n");
! #endif
! return NULL;
! break;
! }
!
! addr = (baseA + baseB) + disp;
! addr &= alignmask;
! #ifdef GC_DEBUG_DECODER
! GC_err_printf1("BaseA: %d\n", baseA);
! GC_err_printf1("BaseB: %d\n", baseB);
! GC_err_printf1("Disp: %d\n", disp);
! GC_err_printf1("Address: %d\n", addr);
! #endif
! return (char *)addr;
! }
! #endif /* MACOSX */
SIG_PF GC_old_bus_handler;
SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */
! #ifdef THREADS
/* We need to lock around the bitmap update in the write fault handler
*/
/* in order to avoid the risk of losing a bit. We do this with a */
/* test-and-set spin lock if we know how to do that. Otherwise we */
--- 2244,2257 ----
return (char *)faultaddr;
}
# endif /* !ALPHA */
! # endif /* LINUX */
+ #ifndef DARWIN
SIG_PF GC_old_bus_handler;
SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */
+ #endif /* !DARWIN */
! #if defined(THREADS)
/* We need to lock around the bitmap update in the write fault handler
*/
/* in order to avoid the risk of losing a bit. We do this with a */
/* test-and-set spin lock if we know how to do that. Otherwise we */
***************
*** 2216,2221 ****
--- 2300,2306 ----
#endif /* !THREADS */
/*ARGSUSED*/
+ #if !defined(DARWIN)
# if defined (SUNOS4) || defined(FREEBSD)
void GC_write_fault_handler(sig, code, scp, addr)
int sig, code;
***************
*** 2231,2237 ****
# define SIG_OK (sig == SIGBUS)
# define CODE_OK (code == BUS_PAGE_FAULT)
# endif
! # endif
# if defined(IRIX5) || defined(OSF1) || defined(HURD)
# include <errno.h>
void GC_write_fault_handler(int sig, int code, struct sigcontext *scp)
--- 2316,2323 ----
# define SIG_OK (sig == SIGBUS)
# define CODE_OK (code == BUS_PAGE_FAULT)
# endif
! # endif /* SUNOS4 || FREEBSD */
!
# if defined(IRIX5) || defined(OSF1) || defined(HURD)
# include <errno.h>
void GC_write_fault_handler(int sig, int code, struct sigcontext *scp)
***************
*** 2247,2253 ****
# define SIG_OK (sig == SIGBUS || sig == SIGSEGV)
# define CODE_OK TRUE
# endif
! # endif
# if defined(LINUX)
# if defined(ALPHA) || defined(M68K)
void GC_write_fault_handler(int sig, int code, s_c * sc)
--- 2333,2340 ----
# define SIG_OK (sig == SIGBUS || sig == SIGSEGV)
# define CODE_OK TRUE
# endif
! # endif /* IRIX5 || OSF1 || HURD */
!
# if defined(LINUX)
# if defined(ALPHA) || defined(M68K)
void GC_write_fault_handler(int sig, int code, s_c * sc)
***************
*** 2267,2273 ****
/* Empirically c.trapno == 14, on IA32, but is that useful? */
/* Should probably consider alignment issues on other */
/* architectures. */
! # endif
# if defined(SUNOS5SIGS)
# ifdef __STDC__
void GC_write_fault_handler(int sig, struct SIGINFO *scp, void * context)
--- 2354,2361 ----
/* Empirically c.trapno == 14, on IA32, but is that useful? */
/* Should probably consider alignment issues on other */
/* architectures. */
! # endif /* LINUX */
!
# if defined(SUNOS5SIGS)
# ifdef __STDC__
void GC_write_fault_handler(int sig, struct SIGINFO *scp, void * context)
***************
*** 2288,2300 ****
# define SIG_OK (sig == SIGSEGV)
# define CODE_OK (scp -> si_code == SEGV_ACCERR)
# endif
! # endif
!
! # if defined(MACOSX)
! void GC_write_fault_handler(int sig, int code, struct sigcontext *scp)
! # define SIG_OK (sig == SIGBUS)
! # define CODE_OK (code == 0 /* experimentally determined */)
! # endif
# if defined(MSWIN32) || defined(MSWINCE)
LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info)
--- 2376,2382 ----
# define SIG_OK (sig == SIGSEGV)
# define CODE_OK (scp -> si_code == SEGV_ACCERR)
# endif
! # endif /* SUNOS5SIGS */
# if defined(MSWIN32) || defined(MSWINCE)
LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info)
***************
*** 2302,2308 ****
STATUS_ACCESS_VIOLATION)
# define CODE_OK (exc_info -> ExceptionRecord -> ExceptionInformation[0] ==
1)
/* Write fault */
! # endif
{
register unsigned i;
# if defined(HURD)
--- 2384,2390 ----
STATUS_ACCESS_VIOLATION)
# define CODE_OK (exc_info -> ExceptionRecord -> ExceptionInformation[0] ==
1)
/* Write fault */
! # endif /* MSWIN32 || MSWINCE */
{
register unsigned i;
# if defined(HURD)
***************
*** 2373,2381 ****
# endif
# endif
# endif
- # if defined(MACOSX)
- char * addr = get_fault_addr(scp);
- # endif
# if defined(MSWIN32) || defined(MSWINCE)
char * addr = (char *) (exc_info -> ExceptionRecord
-> ExceptionInformation[1]);
--- 2455,2460 ----
***************
*** 2439,2447 ****
(*(REAL_SIG_PF)old_handler) (sig, code, scp);
return;
# endif
- # ifdef MACOSX
- (*(REAL_SIG_PF)old_handler) (sig, code, scp);
- # endif
# ifdef MSWIN32
return((*old_handler)(exc_info));
# endif
--- 2518,2523 ----
***************
*** 2483,2488 ****
--- 2559,2565 ----
ABORT("Unexpected bus error or segmentation fault");
#endif
}
+ #endif /* !DARWIN */
/*
* We hold the allocation lock. We expect block h to be written
***************
*** 2515,2520 ****
--- 2592,2598 ----
UNPROTECT(h_trunc, (ptr_t)h_end - (ptr_t)h_trunc);
}
+ #if !defined(DARWIN)
void GC_dirty_init()
{
# if defined(SUNOS5SIGS) || defined(IRIX5) || defined(LINUX) || \
***************
*** 2537,2549 ****
(void)sigaddset(&act.sa_mask, SIG_SUSPEND);
# endif /* SIG_SUSPEND */
# endif
- # if defined(MACOSX)
- struct sigaction act, oldact;
-
- act.sa_flags = SA_RESTART;
- act.sa_handler = GC_write_fault_handler;
- sigemptyset(&act.sa_mask);
- # endif
# ifdef PRINTSTATS
GC_printf0("Inititalizing mprotect virtual dirty bit implementation\n");
# endif
--- 2615,2620 ----
***************
*** 2583,2589 ****
sigaction(SIGSEGV, 0, &oldact);
sigaction(SIGSEGV, &act, 0);
# else
! sigaction(SIGSEGV, &act, &oldact);
# endif
# if defined(_sigargs) || defined(HURD) || !defined(SA_SIGINFO)
/* This is Irix 5.x, not 6.x. Irix 5.x does not have */
--- 2654,2663 ----
sigaction(SIGSEGV, 0, &oldact);
sigaction(SIGSEGV, &act, 0);
# else
! {
! int res = sigaction(SIGSEGV, &act, &oldact);
! if (res != 0) ABORT("Sigaction failed");
! }
# endif
# if defined(_sigargs) || defined(HURD) || !defined(SA_SIGINFO)
/* This is Irix 5.x, not 6.x. Irix 5.x does not have */
***************
*** 2606,2612 ****
# endif
}
# endif
! # if defined(MACOSX) || defined(HPUX) || defined(LINUX) || defined(HURD)
sigaction(SIGBUS, &act, &oldact);
GC_old_bus_handler = oldact.sa_handler;
if (GC_old_bus_handler == SIG_IGN) {
--- 2680,2686 ----
# endif
}
# endif
! # if defined(HPUX) || defined(LINUX) || defined(HURD)
sigaction(SIGBUS, &act, &oldact);
GC_old_bus_handler = oldact.sa_handler;
if (GC_old_bus_handler == SIG_IGN) {
***************
*** 2618,2624 ****
GC_err_printf0("Replaced other SIGBUS handler\n");
# endif
}
! # endif /* MACOS || HPUX || LINUX */
# if defined(MSWIN32)
GC_old_segv_handler =
SetUnhandledExceptionFilter(GC_write_fault_handler);
if (GC_old_segv_handler != NULL) {
--- 2692,2698 ----
GC_err_printf0("Replaced other SIGBUS handler\n");
# endif
}
! # endif /* HPUX || LINUX || HURD */
# if defined(MSWIN32)
GC_old_segv_handler =
SetUnhandledExceptionFilter(GC_write_fault_handler);
if (GC_old_segv_handler != NULL) {
***************
*** 2630,2635 ****
--- 2704,2710 ----
}
# endif
}
+ #endif /* !DARWIN */
int GC_incremental_protection_needs()
{
***************
*** 2879,2891 ****
{
}
- # else /* !MPROTECT_VDB */
-
- # ifdef GC_USE_LD_WRAP
- ssize_t __wrap_read(int fd, void *buf, size_t nbyte)
- { return __real_read(fd, buf, nbyte); }
- # endif
-
# endif /* MPROTECT_VDB */
# ifdef PROC_VDB
--- 2954,2959 ----
***************
*** 3204,3209 ****
--- 3272,3824 ----
# endif /* PCR_VDB */
+ #if defined(MPROTECT_VDB) && defined(DARWIN)
+ /* The following sources were used as a *reference* for this exception
handling
+ code:
+ 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
+ 3. macosx-nat.c from Apple's GDB source code.
+ */
+
+ /* There seem to be numerous problems with darwin's mach exception handling.
+ I'm pretty sure they are not problems in my code. Search for
+ BROKEN_EXCEPTION_HANDLING for more information. */
+ #define BROKEN_EXCEPTION_HANDLING
+
+ #include <mach/mach.h>
+ #include <mach/mach_error.h>
+ #include <mach/thread_status.h>
+ #include <mach/exception.h>
+ #include <mach/task.h>
+ #include <pthread.h>
+
+ /* These are not defined in any header, although they are documented */
+ extern boolean_t exc_server(mach_msg_header_t *,mach_msg_header_t *);
+ extern kern_return_t exception_raise(
+ mach_port_t,mach_port_t,mach_port_t,
+ exception_type_t,exception_data_t,mach_msg_type_number_t);
+ extern kern_return_t exception_raise_state(
+ mach_port_t,mach_port_t,mach_port_t,
+ exception_type_t,exception_data_t,mach_msg_type_number_t,
+ thread_state_flavor_t*,thread_state_t,mach_msg_type_number_t,
+ thread_state_t,mach_msg_type_number_t*);
+ extern kern_return_t exception_raise_state_identity(
+ mach_port_t,mach_port_t,mach_port_t,
+ exception_type_t,exception_data_t,mach_msg_type_number_t,
+ thread_state_flavor_t*,thread_state_t,mach_msg_type_number_t,
+ thread_state_t,mach_msg_type_number_t*);
+
+
+ #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];
+ exception_handler_t ports[MAX_EXCEPTION_PORTS];
+ exception_behavior_t behaviors[MAX_EXCEPTION_PORTS];
+ thread_state_flavor_t flavors[MAX_EXCEPTION_PORTS];
+ } GC_old_exc_ports;
+
+ static struct {
+ mach_port_t exception;
+ #if defined(THREADS)
+ mach_port_t reply;
+ #endif
+ } GC_ports;
+
+ typedef struct {
+ mach_msg_header_t head;
+ } GC_msg_t;
+
+ typedef enum {
+ GC_MP_NORMAL, GC_MP_DISCARDING, GC_MP_STOPPED
+ } GC_mprotect_state_t;
+
+ /* FIXME: 1 and 2 seem to be safe to use in the msgh_id field,
+ but it isn't documented. Use the source and see if they
+ should be ok. */
+ #define ID_STOP 1
+ #define ID_RESUME 2
+
+ /* These values are only used on the reply port */
+ #define ID_ACK 3
+
+ #if defined(THREADS)
+
+ GC_mprotect_state_t GC_mprotect_state;
+
+ /* The following should ONLY be called when the world is stopped */
+ static void GC_mprotect_thread_notify(mach_msg_id_t id) {
+ struct {
+ GC_msg_t msg;
+ mach_msg_trailer_t trailer;
+ } buf;
+ mach_msg_return_t r;
+ /* remote, local */
+ buf.msg.head.msgh_bits =
+ MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND,0);
+ buf.msg.head.msgh_size = sizeof(buf.msg);
+ buf.msg.head.msgh_remote_port = GC_ports.exception;
+ buf.msg.head.msgh_local_port = MACH_PORT_NULL;
+ buf.msg.head.msgh_id = id;
+
+ r = mach_msg(
+ &buf.msg.head,
+ MACH_SEND_MSG|MACH_RCV_MSG|MACH_RCV_LARGE,
+ sizeof(buf.msg),
+ sizeof(buf),
+ GC_ports.reply,
+ MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
+ if(r != MACH_MSG_SUCCESS)
+ ABORT("mach_msg failed in GC_mprotect_thread_notify");
+ if(buf.msg.head.msgh_id != ID_ACK)
+ ABORT("invalid ack in GC_mprotect_thread_notify");
+ }
+
+ /* Should only be called by the mprotect thread */
+ static void GC_mprotect_thread_reply() {
+ GC_msg_t msg;
+ mach_msg_return_t r;
+ /* remote, local */
+ msg.head.msgh_bits =
+ MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND,0);
+ msg.head.msgh_size = sizeof(msg);
+ msg.head.msgh_remote_port = GC_ports.reply;
+ msg.head.msgh_local_port = MACH_PORT_NULL;
+ msg.head.msgh_id = ID_ACK;
+
+ r = mach_msg(
+ &msg.head,
+ MACH_SEND_MSG,
+ sizeof(msg),
+ 0,
+ MACH_PORT_NULL,
+ MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
+ if(r != MACH_MSG_SUCCESS)
+ ABORT("mach_msg failed in GC_mprotect_thread_reply");
+ }
+
+ void GC_mprotect_stop() {
+ GC_mprotect_thread_notify(ID_STOP);
+ }
+ void GC_mprotect_resume() {
+ GC_mprotect_thread_notify(ID_RESUME);
+ }
+
+ #else /* !THREADS */
+ /* The compiler should optimize away any GC_mprotect_state computations */
+ #define GC_mprotect_state GC_MP_NORMAL
+ #endif
+
+ static void *GC_mprotect_thread(void *arg) {
+ mach_msg_return_t r;
+ /* These two structures contain some private kernel data. We don't need to
+ access any of it so we don't bother defining a proper struct. The
+ correct definitions are in the xnu source code. */
+ struct {
+ mach_msg_header_t head;
+ char data[256];
+ } reply;
+ struct {
+ mach_msg_header_t head;
+ mach_msg_body_t msgh_body;
+ char data[1024];
+ } msg;
+
+ mach_msg_id_t id;
+
+ for(;;) {
+ r = mach_msg(
+ &msg.head,
+ MACH_RCV_MSG|MACH_RCV_LARGE|
+ (GC_mprotect_state == GC_MP_DISCARDING ? MACH_RCV_TIMEOUT :
0),
+ 0,
+ sizeof(msg),
+ GC_ports.exception,
+ GC_mprotect_state == GC_MP_DISCARDING ? 0 : MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
+
+ id = r == MACH_MSG_SUCCESS ? msg.head.msgh_id : -1;
+
+ #if defined(THREADS)
+ if(GC_mprotect_state == GC_MP_DISCARDING) {
+ if(r == MACH_RCV_TIMED_OUT) {
+ GC_mprotect_state = GC_MP_STOPPED;
+ GC_mprotect_thread_reply();
+ continue;
+ }
+ if(r == MACH_MSG_SUCCESS && (id == ID_STOP || id == ID_RESUME))
+ ABORT("out of order mprotect thread request");
+ }
+ #endif
+
+ if(r != MACH_MSG_SUCCESS) {
+ GC_err_printf2("mach_msg failed with %d %s\n",
+ (int)r,mach_error_string(r));
+ ABORT("mach_msg failed");
+ }
+
+ switch(id) {
+ #if defined(THREADS)
+ case ID_STOP:
+ if(GC_mprotect_state != GC_MP_NORMAL)
+ ABORT("Called mprotect_stop when state wasn't normal");
+ GC_mprotect_state = GC_MP_DISCARDING;
+ break;
+ case ID_RESUME:
+ if(GC_mprotect_state != GC_MP_STOPPED)
+ ABORT("Called mprotect_resume when state wasn't stopped");
+ GC_mprotect_state = GC_MP_NORMAL;
+ GC_mprotect_thread_reply();
+ break;
+ #endif /* THREADS */
+ default:
+ /* Handle the message (calls catch_exception_raise) */
+ if(!exc_server(&msg.head,&reply.head))
+ ABORT("exc_server failed");
+ /* Send the reply */
+ r = mach_msg(
+ &reply.head,
+ MACH_SEND_MSG,
+ reply.head.msgh_size,
+ 0,
+ MACH_PORT_NULL,
+ MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
+ if(r != MACH_MSG_SUCCESS) {
+ /* This will fail if the thread dies, but the thread
shouldn't
+ die... */
+ #ifdef BROKEN_EXCEPTION_HANDLING
+ GC_err_printf2(
+ "mach_msg failed with %d %s while sending exc
reply\n",
+ (int)r,mach_error_string(r));
+ #else
+ ABORT("mach_msg failed while sending exception reply");
+ #endif
+ }
+ } /* switch */
+ } /* for(;;) */
+ /* NOT REACHED */
+ return NULL;
+ }
+
+ /* All this SIGBUS code shouldn't be necessary. All protection faults should
+ be going throught the mach exception handler. However, it seems a SIGBUS is
+ occasionally sent for some unknown reason. Even more odd, it seems to be
+ meaningless and safe to ignore. */
+ #ifdef BROKEN_EXCEPTION_HANDLING
+
+ typedef void (* SIG_PF)();
+ static SIG_PF GC_old_bus_handler;
+
+ /* Updates to this aren't atomic, but the SIGBUSs seem pretty rare.
+ Even if this doesn't get updated property, it isn't really a problem */
+ static int GC_sigbus_count;
+
+ static void GC_darwin_sigbus(int num,siginfo_t *sip,void *context) {
+ if(num != SIGBUS) ABORT("Got a non-sigbus signal in the sigbus handler");
+
+ /* Ugh... some seem safe to ignore, but too many in a row probably means
+ trouble. GC_sigbus_count is reset for each mach exception that is
+ handled */
+ if(GC_sigbus_count >= 8) {
+ ABORT("Got more than 8 SIGBUSs in a row!");
+ } else {
+ GC_sigbus_count++;
+ GC_err_printf0("GC: WARNING: Ignoring SIGBUS.\n");
+ }
+ }
+ #endif /* BROKEN_EXCEPTION_HANDLING */
+
+ void GC_dirty_init() {
+ kern_return_t r;
+ mach_port_t me;
+ pthread_t thread;
+ pthread_attr_t attr;
+ exception_mask_t mask;
+
+ # ifdef PRINTSTATS
+ GC_printf0("Inititalizing mach/darwin mprotect virtual dirty bit "
+ "implementation\n");
+ # endif
+ # ifdef BROKEN_EXCEPTION_HANDLING
+ GC_err_printf0("GC: WARNING: Enabling workarounds for various darwin "
+ "exception handling bugs.\n");
+ # endif
+ GC_dirty_maintained = TRUE;
+ if (GC_page_size % HBLKSIZE != 0) {
+ GC_err_printf0("Page size not multiple of HBLKSIZE\n");
+ ABORT("Page size not multiple of HBLKSIZE");
+ }
+
+ GC_task_self = me = mach_task_self();
+
+ r = mach_port_allocate(me,MACH_PORT_RIGHT_RECEIVE,&GC_ports.exception);
+ if(r != KERN_SUCCESS) ABORT("mach_port_allocate failed (exception port)");
+
+ r = mach_port_insert_right(me,GC_ports.exception,GC_ports.exception,
+ MACH_MSG_TYPE_MAKE_SEND);
+ if(r != KERN_SUCCESS)
+ ABORT("mach_port_insert_right failed (exception port)");
+
+ #if defined(THREADS)
+ r = mach_port_allocate(me,MACH_PORT_RIGHT_RECEIVE,&GC_ports.reply);
+ if(r != KERN_SUCCESS) ABORT("mach_port_allocate failed (reply port)");
+ #endif
+
+ /* The exceptions we want to catch */
+ mask = EXC_MASK_BAD_ACCESS;
+
+ r = task_get_exception_ports(
+ me,
+ mask,
+ GC_old_exc_ports.masks,
+ &GC_old_exc_ports.count,
+ GC_old_exc_ports.ports,
+ GC_old_exc_ports.behaviors,
+ GC_old_exc_ports.flavors
+ );
+ if(r != KERN_SUCCESS) ABORT("task_get_exception_ports failed");
+
+ r = task_set_exception_ports(
+ me,
+ mask,
+ GC_ports.exception,
+ EXCEPTION_DEFAULT,
+ MACHINE_THREAD_STATE
+ );
+ if(r != KERN_SUCCESS) ABORT("task_set_exception_ports failed");
+
+ if(pthread_attr_init(&attr) != 0) ABORT("pthread_attr_init failed");
+ if(pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED) != 0)
+ ABORT("pthread_attr_setdetachedstate failed");
+
+ # undef pthread_create
+ /* This will call the real pthread function, not our wrapper */
+ if(pthread_create(&thread,&attr,GC_mprotect_thread,NULL) != 0)
+ ABORT("pthread_create failed");
+ pthread_attr_destroy(&attr);
+
+ /* Setup the sigbus handler for ignoring the meaningless SIGBUSs */
+ #ifdef BROKEN_EXCEPTION_HANDLING
+ {
+ struct sigaction sa, oldsa;
+ sa.sa_handler = (SIG_PF)GC_darwin_sigbus;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_RESTART|SA_SIGINFO;
+ if(sigaction(SIGBUS,&sa,&oldsa) < 0) ABORT("sigaction");
+ GC_old_bus_handler = (SIG_PF)oldsa.sa_handler;
+ if (GC_old_bus_handler != SIG_DFL) {
+ # ifdef PRINTSTATS
+ GC_err_printf0("Replaced other SIGBUS handler\n");
+ # endif
+ }
+ }
+ #endif /* BROKEN_EXCEPTION_HANDLING */
+ }
+
+ /* The source code for Apple's GDB was used as a reference for the exception
+ forwarding code. This code is similar to be GDB code only because there is
+ only one way to do it. */
+ static kern_return_t GC_forward_exception(
+ mach_port_t thread,
+ mach_port_t task,
+ exception_type_t exception,
+ exception_data_t data,
+ mach_msg_type_number_t data_count
+ ) {
+ int i;
+ kern_return_t r;
+ mach_port_t port;
+ exception_behavior_t behavior;
+ thread_state_flavor_t flavor;
+
+ thread_state_data_t thread_state;
+ mach_msg_type_number_t thread_state_count = THREAD_STATE_MAX;
+
+ for(i=0;i<GC_old_exc_ports.count;i++)
+ if(GC_old_exc_ports.masks[i] & (1 << exception))
+ break;
+ if(i==GC_old_exc_ports.count) ABORT("No handler for exception!");
+
+ port = GC_old_exc_ports.ports[i];
+ behavior = GC_old_exc_ports.behaviors[i];
+ flavor = GC_old_exc_ports.flavors[i];
+
+ if(behavior != EXCEPTION_DEFAULT) {
+ r = thread_get_state(thread,flavor,thread_state,&thread_state_count);
+ if(r != KERN_SUCCESS)
+ ABORT("thread_get_state failed in forward_exception");
+ }
+
+ switch(behavior) {
+ case EXCEPTION_DEFAULT:
+ r = exception_raise(port,thread,task,exception,data,data_count);
+ break;
+ case EXCEPTION_STATE:
+ r = exception_raise_state(port,thread,task,exception,data,
+ data_count,&flavor,thread_state,thread_state_count,
+ thread_state,&thread_state_count);
+ break;
+ case EXCEPTION_STATE_IDENTITY:
+ r =
exception_raise_state_identity(port,thread,task,exception,data,
+ data_count,&flavor,thread_state,thread_state_count,
+ thread_state,&thread_state_count);
+ break;
+ default:
+ r = KERN_FAILURE; /* make gcc happy */
+ ABORT("forward_exception: unknown behavior");
+ break;
+ }
+
+ if(behavior != EXCEPTION_DEFAULT) {
+ r = thread_set_state(thread,flavor,thread_state,thread_state_count);
+ if(r != KERN_SUCCESS)
+ ABORT("thread_set_state failed in forward_exception");
+ }
+
+ return r;
+ }
+
+ #define FWD() GC_forward_exception(thread,task,exception,code,code_count)
+
+ /* This violates the namespace rules but there isn't anything that can be done
+ about it. The exception handling stuff is hard coded to call this */
+ kern_return_t
+ catch_exception_raise(
+ mach_port_t exception_port,mach_port_t thread,mach_port_t task,
+ exception_type_t exception,exception_data_t code,
+ mach_msg_type_number_t code_count
+ ) {
+ kern_return_t r;
+ char *addr;
+ struct hblk *h;
+ int i;
+ #ifdef POWERPC
+ thread_state_flavor_t flavor = PPC_EXCEPTION_STATE;
+ mach_msg_type_number_t exc_state_count = PPC_EXCEPTION_STATE_COUNT;
+ ppc_exception_state_t exc_state;
+ #else
+ # error FIXME for non-ppc darwin
+ #endif
+
+
+ if(exception != EXC_BAD_ACCESS || code[0] != KERN_PROTECTION_FAILURE) {
+ #ifdef DEBUG_EXCEPTION_HANDLING
+ /* We aren't interested, pass it on to the old handler */
+ GC_printf3("Exception: 0x%x Code: 0x%x 0x%x in catch....\n",
+ exception,
+ code_count > 0 ? code[0] : -1,
+ code_count > 1 ? code[1] : -1);
+ #endif
+ return FWD();
+ }
+
+ r = thread_get_state(thread,flavor,
+ (natural_t*)&exc_state,&exc_state_count);
+ if(r != KERN_SUCCESS) {
+ /* The thread is supposed to be suspended while the exception handler
+ is called. This shouldn't fail. */
+ #ifdef BROKEN_EXCEPTION_HANDLING
+ GC_err_printf0("thread_get_state failed in "
+ "catch_exception_raise\n");
+ return KERN_SUCCESS;
+ #else
+ ABORT("thread_get_state failed in catch_exception_raise");
+ #endif
+ }
+
+ /* This is the address that caused the fault */
+ addr = (char*) exc_state.dar;
+
+ if((HDR(addr)) == 0) {
+ /* Ugh... just like the SIGBUS problem above, it seems we get a bogus
+ KERN_PROTECTION_FAILURE every once and a while. We wait till we get
+ a bunch in a row before doing anything about it. If a "real" fault
+ ever occurres it'll just keep faulting over and over and we'll hit
+ the limit pretty quickly. */
+ #ifdef BROKEN_EXCEPTION_HANDLING
+ static char *last_fault;
+ static int last_fault_count;
+
+ if(addr != last_fault) {
+ last_fault = addr;
+ last_fault_count = 0;
+ }
+ if(++last_fault_count < 32) {
+ if(last_fault_count == 1)
+ GC_err_printf1(
+ "GC: WARNING: Ignoring KERN_PROTECTION_FAILURE at
%p\n",
+ addr);
+ return KERN_SUCCESS;
+ }
+
+ GC_err_printf1("Unexpected KERN_PROTECTION_FAILURE at %p\n",addr);
+ /* Can't pass it along to the signal handler because that is
+ ignoring SIGBUS signals. We also shouldn't call ABORT here as
+ signals don't always work too well from the exception handler.
*/
+ GC_err_printf0("Aborting\n");
+ exit(EXIT_FAILURE);
+ #else /* BROKEN_EXCEPTION_HANDLING */
+ /* Pass it along to the next exception handler
+ (which should call SIGBUS/SIGSEGV) */
+ return FWD();
+ #endif /* !BROKEN_EXCEPTION_HANDLING */
+ }
+
+ #ifdef BROKEN_EXCEPTION_HANDLING
+ /* Reset the number of consecutive SIGBUSs */
+ GC_sigbus_count = 0;
+ #endif
+
+ if(GC_mprotect_state == GC_MP_NORMAL) { /* common case */
+ h = (struct hblk*)((word)addr & ~(GC_page_size-1));
+ UNPROTECT(h, GC_page_size);
+ for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
+ register int index = PHT_HASH(h+i);
+ async_set_pht_entry_from_index(GC_dirty_pages, index);
+ }
+ } else if(GC_mprotect_state == GC_MP_DISCARDING) {
+ /* Lie to the thread for now. No sense UNPROTECT()ing the memory
+ when we're just going to PROTECT() it again later. The thread
+ will just fault again once it resumes */
+ } else {
+ /* Shouldn't happen, i don't think */
+ GC_printf0("KERN_PROTECTION_FAILURE while world is stopped\n");
+ return FWD();
+ }
+ return KERN_SUCCESS;
+ }
+ #undef FWD
+
+ /* These should never be called, but just in case... */
+ kern_return_t catch_exception_raise_state(mach_port_name_t exception_port,
+ int exception, exception_data_t code, mach_msg_type_number_t codeCnt,
+ int flavor, thread_state_t old_state, int old_stateCnt,
+ thread_state_t new_state, int new_stateCnt)
+ {
+ ABORT("catch_exception_raise_state");
+ return(KERN_INVALID_ARGUMENT);
+ }
+ kern_return_t catch_exception_raise_state_identity(
+ mach_port_name_t exception_port, mach_port_t thread, mach_port_t task,
+ int exception, exception_data_t code, mach_msg_type_number_t codeCnt,
+ int flavor, thread_state_t old_state, int old_stateCnt,
+ thread_state_t new_state, int new_stateCnt)
+ {
+ ABORT("catch_exception_raise_state_identity");
+ return(KERN_INVALID_ARGUMENT);
+ }
+
+
+ #endif /* DARWIN && MPROTECT_VDB */
+
# ifndef HAVE_INCREMENTAL_PROTECTION_NEEDS
int GC_incremental_protection_needs()
{
***************
*** 3323,3330 ****
asm("movl %%ebp,%0" : "=r"(frame));
fp = frame;
# else
- word GC_save_regs_in_stack();
-
frame = (struct frame *) GC_save_regs_in_stack ();
fp = (struct frame *)((long) frame -> FR_SAVFP + BIAS);
#endif
--- 3938,3943 ----
***************
*** 3465,3471 ****
}
name = result_buf;
pclose(pipe);
! out:
}
# endif /* LINUX */
GC_err_printf1("\t\t%s\n", name);
--- 4078,4084 ----
}
name = result_buf;
pclose(pipe);
! out:;
}
# endif /* LINUX */
GC_err_printf1("\t\t%s\n", name);
***************
*** 3481,3511 ****
#endif /* NEED_CALLINFO */
- #if defined(LINUX) && defined(__ELF__) && \
- (!defined(SMALL_CONFIG) || defined(USE_PROC_FOR_LIBRARIES))
- #ifdef GC_USE_LD_WRAP
- # define READ __real_read
- #else
- # define READ read
- #endif
-
-
- /* Repeatedly perform a read call until the buffer is filled or */
- /* we encounter EOF. */
- ssize_t GC_repeat_read(int fd, char *buf, size_t count)
- {
- ssize_t num_read = 0;
- ssize_t result;
-
- while (num_read < count) {
- result = READ(fd, buf + num_read, count - num_read);
- if (result < 0) return result;
- if (result == 0) break;
- num_read += result;
- }
- return num_read;
- }
- #endif /* LINUX && ... */
#if defined(LINUX) && defined(__ELF__) && !defined(SMALL_CONFIG)
--- 4094,4099 ----
***************
*** 3513,3532 ****
/* Dump /proc/self/maps to GC_stderr, to enable looking up names for
addresses in FIND_LEAK output. */
void GC_print_address_map()
{
- int f;
- int result;
- char maps_temp[32768];
GC_err_printf0("---------- Begin address map ----------\n");
! f = open("/proc/self/maps", O_RDONLY);
! if (-1 == f) ABORT("Couldn't open /proc/self/maps");
! do {
! result = GC_repeat_read(f, maps_temp, sizeof(maps_temp));
! if (result <= 0) ABORT("Couldn't read /proc/self/maps");
! GC_err_write(maps_temp, result);
! } while (result == sizeof(maps_temp));
! close(f);
GC_err_printf0("---------- End address map ----------\n");
}
--- 4101,4116 ----
/* Dump /proc/self/maps to GC_stderr, to enable looking up names for
addresses in FIND_LEAK output. */
+ static word dump_maps(char *maps)
+ {
+ GC_err_write(maps, strlen(maps));
+ return 1;
+ }
+
void GC_print_address_map()
{
GC_err_printf0("---------- Begin address map ----------\n");
! GC_apply_to_maps(dump_maps);
GC_err_printf0("---------- End address map ----------\n");
}
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Emacs-diffs] Changes to emacs/gc/os_dep.c [Boehm-GC],
Dave Love <=