diff options
author | Tom Tromey <tromey@cygnus.com> | 1999-11-01 23:15:51 +0000 |
---|---|---|
committer | Tom Tromey <tromey@gcc.gnu.org> | 1999-11-01 23:15:51 +0000 |
commit | 20bbd3cd53a80ddafa56a5d21337aae0c24f94ca (patch) | |
tree | 9c24ba1ebabff472b9caddbff07ef957dbf2c24c /boehm-gc/os_dep.c | |
parent | c05ddfa745d68f6d9db1a7d0992650a41986d376 (diff) | |
download | gcc-20bbd3cd53a80ddafa56a5d21337aae0c24f94ca.tar.gz |
Merged GC 5.0alpha4 with local changes, plus:
* Makefile.in: Rebuilt.
* Makefile.am (gctest_LDADD): Added THREADLIB.
(TESTS): New macro.
* configure: Rebuilt.
* configure.in (INCLUDES): New subst.
From-SVN: r30332
Diffstat (limited to 'boehm-gc/os_dep.c')
-rw-r--r-- | boehm-gc/os_dep.c | 574 |
1 files changed, 440 insertions, 134 deletions
diff --git a/boehm-gc/os_dep.c b/boehm-gc/os_dep.c index 29cf8ff99ec..744b1e0898b 100644 --- a/boehm-gc/os_dep.c +++ b/boehm-gc/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. @@ -30,8 +32,12 @@ /* prototypes, so we have to include the top-level sigcontext.h to */ /* make sure the former gets defined to be the latter if appropriate. */ # include <features.h> -# if 2 <= __GLIBC__ && 0 == __GLIBC_MINOR__ -# include <sigcontext.h> +# if 2 <= __GLIBC__ +# 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> +# endif /* 0 == __GLIBC_MINOR__ */ # else /* not 2 <= __GLIBC__ */ /* libc5 doesn't have <sigcontext.h>: go directly with the kernel */ /* one. Check LINUX_VERSION_CODE to see which we should reference. */ @@ -50,13 +56,13 @@ # 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 @@ -68,7 +74,8 @@ # define NEED_FIND_LIMIT # endif -# if defined(LINUX) && (defined(POWERPC) || defined(ALPHA)) +# if defined(LINUX) && \ + (defined(POWERPC) || defined(SPARC) || defined(ALPHA) || defined(IA64)) # define NEED_FIND_LIMIT # endif @@ -135,92 +142,21 @@ # define OPT_PROT_EXEC 0 #endif -#if defined(LINUX) && defined(POWERPC) +#if defined(LINUX) && (defined(POWERPC) || defined(SPARC) || defined(ALPHA) \ + || defined(IA64)) + /* 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 */ + /* cover all versions. */ ptr_t GC_data_start; - void GC_init_linuxppc() - { - extern ptr_t GC_find_limit(); - extern char **_environ; - /* This may need to be environ, without the underscore, for */ - /* some versions. */ - GC_data_start = GC_find_limit((ptr_t)&_environ, FALSE); - } -#endif + extern char * GC_copyright[]; /* Any data symbol would do. */ -#if defined(LINUX) && defined(ALPHA) - ptr_t GC_data_start; - - void GC_init_linuxalpha() + void GC_init_linux_data_start() { -# ifdef USE_PROC - FILE *fp = fopen("/proc/self/maps", "r"); - - if (fp) { - extern void *_etext; - ptr_t stacktop = 0, stackbottom = 0; - ptr_t textstart = 0, textend = 0; - ptr_t datastart = 0, dataend = 0; - ptr_t bssstart = 0, bssend = 0; - - while (!feof(fp)) { - ptr_t start, end, offset; - unsigned short major, minor; - char r, w, x, p; - unsigned int inode; - - int n = fscanf(fp, "%lx-%lx %c%c%c%c %lx %hx:%hx %d", - &start, &end, &r, &w, &x, &p, &offset, &major, &minor, &inode); - if (n < 10) break; - - /* - * If local variable lies within segment, it is stack. - * Else if segment lies below _end and is executable, - * it is text. Otherwise, if segment start lies between - * _etext and _end and segment is writable and is mapped - * to the executable image it is data, otherwise bss. - */ - if (start < (ptr_t)&fp && end > (ptr_t)&fp && w == 'w') { - stacktop = start; - stackbottom = end; - } else if (start < (ptr_t)&_end && w == '-' && x == 'x') { - textstart = start; - textend = end; - } else if (start >= (ptr_t)&_etext && - start < (ptr_t)&_end && w == 'w') { - if (inode > 0) { - datastart = start; - dataend = end; - } else { - bssstart = start; - bssend = end; - } - } - - //printf("%016lx-%016lx %c%c%c%c %016lx %02hx:%02hx %d\n", - // start, end, r, w, x, p, offset, major, minor, inode); - - while (fgetc(fp) != '\n') ; - } - fclose(fp); - - //fprintf(stderr, "text: %lx-%lx\n", textstart, textend); - //fprintf(stderr, "data: %lx-%lx\n", datastart, dataend); - //fprintf(stderr, "bss: %lx-%lx\n", bssstart, bssend); - //fprintf(stderr, "stack: %lx-%lx\n", stacktop, stackbottom); + extern ptr_t GC_find_limit(); - GC_data_start = datastart; - } else { -# endif - extern ptr_t GC_find_limit(); - extern int _edata; - /* This may need to be environ, without the underscore, for */ - /* some versions. */ - GC_data_start = GC_find_limit((ptr_t)&_edata, FALSE); -# ifdef USE_PROC - } -# endif - //fprintf(stderr, "GC_data_start = %p\n", GC_data_start); + GC_data_start = GC_find_limit((ptr_t)GC_copyright, FALSE); } #endif @@ -455,7 +391,8 @@ word GC_page_size; } # else -# if defined(MPROTECT_VDB) || defined(PROC_VDB) || defined(USE_MMAP) +# if defined(MPROTECT_VDB) || defined(PROC_VDB) || defined(USE_MMAP) \ + || defined(USE_MUNMAP) void GC_setpagesize() { GC_page_size = GETPAGESIZE(); @@ -534,6 +471,24 @@ ptr_t GC_get_stack_base() ptr_t GC_get_stack_base() { + struct Process *proc = (struct Process*)SysBase->ThisTask; + + /* Reference: Amiga Guru Book Pages: 42,567,574 */ + if (proc->pr_Task.tc_Node.ln_Type==NT_PROCESS + && proc->pr_CLI != NULL) { + /* first ULONG is StackSize */ + /*longPtr = proc->pr_ReturnAddr; + size = longPtr[0];*/ + + return (char *)proc->pr_ReturnAddr + sizeof(ULONG); + } else { + return (char *)proc->pr_Task.tc_SPUpper; + } +} + +#if 0 /* old version */ +ptr_t GC_get_stack_base() +{ extern struct WBStartup *_WBenchMsg; extern long __base; extern long __stack; @@ -556,10 +511,9 @@ ptr_t GC_get_stack_base() } return (ptr_t)(__base + GC_max(size, __stack)); } +#endif /* 0 */ -# else - - +# else /* !AMIGA, !OS2, ... */ # ifdef NEED_FIND_LIMIT /* Some tools to implement HEURISTIC2 */ @@ -579,9 +533,11 @@ ptr_t GC_get_stack_base() typedef void (*handler)(); # endif -# if defined(SUNOS5SIGS) || defined(IRIX5) +# if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1) static struct sigaction old_segv_act; - static struct sigaction old_bus_act; +# if defined(_sigargs) || defined(HPUX) /* !Irix6.x */ + static struct sigaction old_bus_act; +# endif # else static handler old_segv_handler, old_bus_handler; # endif @@ -589,7 +545,7 @@ ptr_t GC_get_stack_base() void GC_setup_temporary_fault_handler() { # ifndef ECOS -# if defined(SUNOS5SIGS) || defined(IRIX5) +# if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1) struct sigaction act; act.sa_handler = GC_fault_handler; @@ -608,10 +564,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 */ @@ -627,9 +584,10 @@ ptr_t GC_get_stack_base() void GC_reset_fault_handler() { # ifndef ECOS -# if defined(SUNOS5SIGS) || defined(IRIX5) +# 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 @@ -679,8 +637,43 @@ ptr_t GC_get_stack_base() } # endif - # ifndef ECOS + +#ifdef LINUX_STACKBOTTOM + +# define STAT_SKIP 27 /* Number of fields preceding startstack */ + /* field in /proc/<pid>/stat */ + + ptr_t GC_linux_stack_base(void) + { + char buf[50]; + FILE *f; + char c; + word result = 0; + int i; + + sprintf(buf, "/proc/%d/stat", getpid()); + f = fopen(buf, "r"); + if (NULL == f) ABORT("Couldn't open /proc/<pid>/stat"); + c = getc(f); + /* 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 = getc(f); + while (!isspace(c)) c = getc(f); + } + while (isspace(c)) c = getc(f); + while (isdigit(c)) { + result *= 10; + result += c - '0'; + c = getc(f); + } + if (result < 0x10000000) ABORT("Absurd stack bottom value"); + return (ptr_t)result; + } + +#endif /* LINUX_STACKBOTTOM */ + ptr_t GC_get_stack_base() { word dummy; @@ -705,6 +698,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); @@ -725,6 +721,9 @@ ptr_t GC_get_stack_base() # endif # endif /* HEURISTIC2 */ +# ifdef STACK_GROWS_DOWN + if (result == 0) result = (ptr_t)(signed_word)(-sizeof(ptr_t)); +# endif return(result); # endif /* STACKBOTTOM */ # endif /* STACKBASE */ @@ -954,6 +953,72 @@ void GC_register_data_segments() # else # ifdef AMIGA + void GC_register_data_segments() + { + struct Process *proc; + struct CommandLineInterface *cli; + BPTR myseglist; + ULONG *data; + + int num; + + +# ifdef __GNUC__ + ULONG dataSegSize; + GC_bool found_segment = FALSE; + extern char __data_size[]; + + dataSegSize=__data_size+8; + /* Can`t find the Location of __data_size, because + it`s possible that is it, inside the segment. */ + +# endif + + proc= (struct Process*)SysBase->ThisTask; + + /* Reference: Amiga Guru Book Pages: 538ff,565,573 + and XOper.asm */ + if (proc->pr_Task.tc_Node.ln_Type==NT_PROCESS) { + if (proc->pr_CLI == NULL) { + myseglist = proc->pr_SegList; + } else { + /* ProcLoaded 'Loaded as a command: '*/ + cli = BADDR(proc->pr_CLI); + myseglist = cli->cli_Module; + } + } else { + ABORT("Not a Process."); + } + + if (myseglist == NULL) { + ABORT("Arrrgh.. can't find segments, aborting"); + } + + /* xoper hunks Shell Process */ + + num=0; + for (data = (ULONG *)BADDR(myseglist); data != NULL; + data = (ULONG *)BADDR(data[0])) { + if (((ULONG) GC_register_data_segments < (ULONG) &data[1]) || + ((ULONG) GC_register_data_segments > (ULONG) &data[1] + data[-1])) { +# ifdef __GNUC__ + if (dataSegSize == data[-1]) { + found_segment = TRUE; + } +# endif + GC_add_roots_inner((char *)&data[1], + ((char *)&data[1]) + data[-1], FALSE); + } + ++num; + } /* for */ +# ifdef __GNUC__ + if (!found_segment) { + ABORT("Can`t find correct Segments.\nSolution: Use an newer version of ixemul.library"); + } +# endif + } + +#if 0 /* old version */ void GC_register_data_segments() { extern struct WBStartup *_WBenchMsg; @@ -995,6 +1060,7 @@ void GC_register_data_segments() } } } +#endif /* old version */ # else @@ -1035,7 +1101,8 @@ int * etext_addr; void GC_register_data_segments() { -# if !defined(PCR) && !defined(SRC_M3) && !defined(NEXT) && !defined(MACOS) +# if !defined(PCR) && !defined(SRC_M3) && !defined(NEXT) && !defined(MACOS) \ + && !defined(MACOSX) # if defined(REDIRECT_MALLOC) && defined(SOLARIS_THREADS) /* As of Solaris 2.3, the Solaris threads implementation */ /* allocates the data structure for the initial thread with */ @@ -1049,7 +1116,7 @@ void GC_register_data_segments() GC_add_roots_inner(DATASTART, (char *)(DATAEND), FALSE); # endif # endif -# if !defined(PCR) && defined(NEXT) +# if !defined(PCR) && (defined(NEXT) || defined(MACOSX)) GC_add_roots_inner(DATASTART, (char *) get_end(), FALSE); # endif # if defined(MACOS) @@ -1063,9 +1130,19 @@ void GC_register_data_segments() # if defined(__MWERKS__) # if !__POWERPC__ extern void* GC_MacGetDataStart(void); + /* MATTHEW: Function to handle Far Globals (CW Pro 3) */ +# if __option(far_data) + extern void* GC_MacGetDataEnd(void); +# endif /* globals begin above stack and end at a5. */ GC_add_roots_inner((ptr_t)GC_MacGetDataStart(), (ptr_t)LMGetCurrentA5(), FALSE); + /* MATTHEW: Handle Far Globals */ +# if __option(far_data) + /* Far globals follow he QD globals: */ + GC_add_roots_inner((ptr_t)LMGetCurrentA5(), + (ptr_t)GC_MacGetDataEnd(), FALSE); +# endif # else extern char __data_start__[], __data_end__[]; GC_add_roots_inner((ptr_t)&__data_start__, @@ -1132,7 +1209,15 @@ word bytes; #else /* Not RS6000 */ #if defined(USE_MMAP) -/* Tested only under IRIX5 */ +/* Tested only under IRIX5 and Solaris 2 */ + +#ifdef USE_MMAP_FIXED +# define GC_MMAP_FLAGS MAP_FIXED | MAP_PRIVATE + /* Seems to yield better performance on Solaris 2, but can */ + /* be unreliable if something is already mapped at the address. */ +#else +# define GC_MMAP_FLAGS MAP_PRIVATE +#endif ptr_t GC_unix_get_mem(bytes) word bytes; @@ -1148,7 +1233,7 @@ word bytes; } if (bytes & (GC_page_size -1)) ABORT("Bad GET_MEM arg"); result = mmap(last_addr, bytes, PROT_READ | PROT_WRITE | OPT_PROT_EXEC, - MAP_PRIVATE | MAP_FIXED, fd, 0/* offset */); + GC_MMAP_FLAGS, 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)); @@ -1232,8 +1317,108 @@ word bytes; return(result); } +void GC_win32_free_heap () +{ + if (GC_win32s) { + while (GC_n_heap_bases > 0) { + GlobalFree (GC_heap_bases[--GC_n_heap_bases]); + GC_heap_bases[GC_n_heap_bases] = 0; + } + } +} + + # endif +#ifdef USE_MUNMAP + +/* For now, this only works on some Unix-like systems. If you */ +/* have something else, don't define USE_MUNMAP. */ +/* We assume ANSI C to support this feature. */ +#include <unistd.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <fcntl.h> + +/* Compute a page aligned starting address for the unmap */ +/* operation on a block of size bytes starting at start. */ +/* Return 0 if the block is too small to make this feasible. */ +ptr_t GC_unmap_start(ptr_t start, word bytes) +{ + ptr_t result = start; + /* Round start to next page boundary. */ + result += GC_page_size - 1; + result = (ptr_t)((word)result & ~(GC_page_size - 1)); + if (result + GC_page_size > start + bytes) return 0; + return result; +} + +/* Compute end address for an unmap operation on the indicated */ +/* block. */ +ptr_t GC_unmap_end(ptr_t start, word bytes) +{ + ptr_t end_addr = start + bytes; + end_addr = (ptr_t)((word)end_addr & ~(GC_page_size - 1)); + return end_addr; +} + +/* We assume that GC_remap is called on exactly the same range */ +/* as a previous call to GC_unmap. It is safe to consistently */ +/* round the endpoints in both places. */ +void GC_unmap(ptr_t start, word bytes) +{ + ptr_t start_addr = GC_unmap_start(start, bytes); + ptr_t end_addr = GC_unmap_end(start, bytes); + word len = end_addr - start_addr; + if (0 == start_addr) return; + if (munmap(start_addr, len) != 0) ABORT("munmap failed"); + GC_unmapped_bytes += len; +} + + +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 (-1 == zero_descr) zero_descr = open("/dev/zero", O_RDWR); + 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"); + } + GC_unmapped_bytes -= len; +} + +/* Two adjacent blocks have already been unmapped and are about to */ +/* be merged. Unmap the whole block. This typically requires */ +/* that we unmap a small section in the middle that was not previously */ +/* unmapped due to alignment constraints. */ +void GC_unmap_gap(ptr_t start1, word bytes1, ptr_t start2, word bytes2) +{ + ptr_t start1_addr = GC_unmap_start(start1, bytes1); + ptr_t end1_addr = GC_unmap_end(start1, bytes1); + ptr_t start2_addr = GC_unmap_start(start2, bytes2); + ptr_t end2_addr = GC_unmap_end(start2, bytes2); + ptr_t start_addr = end1_addr; + ptr_t end_addr = start2_addr; + word len; + GC_ASSERT(start1 + bytes1 == start2); + if (0 == start1_addr) start_addr = GC_unmap_start(start1, bytes1 + bytes2); + if (0 == start2_addr) end_addr = GC_unmap_end(start1, bytes1 + bytes2); + if (0 == start_addr) return; + len = end_addr - start_addr; + if (len != 0 && munmap(start_addr, len) != 0) ABORT("munmap failed"); + GC_unmapped_bytes += len; +} + +#endif /* USE_MUNMAP */ + /* Routine for pushing any additional roots. In THREADS */ /* environment, this is also responsible for marking from */ /* thread stacks. In the SRC_M3 case, it also handles */ @@ -1351,6 +1536,7 @@ void GC_default_push_other_roots() # if defined(SOLARIS_THREADS) || defined(WIN32_THREADS) \ || defined(IRIX_THREADS) || defined(LINUX_THREADS) \ + || defined(IRIX_JDK_THREADS) || defined(HPUX_THREADS) \ || defined(QUICK_THREADS) extern void GC_push_all_stacks(); @@ -1478,12 +1664,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"); \ } @@ -1508,14 +1694,15 @@ struct hblk *h; # endif -VOLATILE page_hash_table GC_dirty_pages; - /* Pages dirtied since last GC_read_dirty. */ - #if defined(SUNOS4) || defined(FREEBSD) 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; @@ -1527,15 +1714,46 @@ VOLATILE page_hash_table GC_dirty_pages; 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) - typedef void (* REAL_SIG_PF)(int, struct sigcontext); +# 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 - typedef void (* REAL_SIG_PF)(int, struct sigcontext_struct); +# 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 + /* Retrieve fault address from sigcontext structure by decoding */ + /* instruction. */ + char * get_fault_addr(s_c *sc) { + unsigned instr; + word faultaddr; + + instr = *((unsigned *)(sc->sc_pc)); + faultaddr = sc->sc_regs[(instr >> 16) & 0x1f]; + faultaddr += (word) (((int)instr << 16) >> 16); + return (char *)faultaddr; + } +# endif /* !ALPHA */ # endif SIG_PF GC_old_bus_handler; @@ -1570,21 +1788,41 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ # endif # endif # if defined(LINUX) -# if (LINUX_VERSION_CODE >= 0x20100) - void GC_write_fault_handler(int sig, struct sigcontext sc) +# 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, struct sigcontext_struct 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) @@ -1608,7 +1846,45 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ # ifdef I386 char * addr = (char *) (sc.cr2); # else - char * addr = /* As of 1.3.90 there seemed to be no way to do this. */; +# if defined(M68K) + char * addr = NULL; + + struct sigcontext *scp = (struct sigcontext *)(&sc); + + int format = (scp->sc_formatvec >> 12) & 0xf; + unsigned long *framedata = (unsigned long *)(scp + 1); + unsigned long ea; + + if (format == 0xa || format == 0xb) { + /* 68020/030 */ + ea = framedata[2]; + } else if (format == 7) { + /* 68040 */ + ea = framedata[3]; + } else if (format == 4) { + /* 68060 */ + ea = framedata[0]; + if (framedata[1] & 0x08000000) { + /* correct addr on misaligned access */ + ea = (ea+4095)&(~4095); + } + } + addr = (char *)ea; +# else +# ifdef ALPHA + char * addr = get_fault_addr(sc); +# else +# ifdef IA64 + char * addr = si -> si_addr; +# else +# if defined(POWERPC) + char * addr = (char *) (sc.regs->dar); +# else + --> architecture not supported +# endif +# endif +# endif +# endif # endif # endif # if defined(MSWIN32) @@ -1644,6 +1920,7 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ } if (old_handler == SIG_DFL) { # ifndef MSWIN32 + GC_err_printf1("Segfault at 0x%lx\n", addr); ABORT("Unexpected bus error or segmentation fault"); # else return(EXCEPTION_CONTINUE_SEARCH); @@ -1658,7 +1935,15 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ return; # endif # if defined (LINUX) - (*(REAL_SIG_PF)old_handler) (sig, sc); +# 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 # if defined (IRIX5) || defined(OSF1) @@ -1691,6 +1976,7 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ #ifdef MSWIN32 return EXCEPTION_CONTINUE_SEARCH; #else + GC_err_printf1("Segfault at 0x%lx\n", addr); ABORT("Unexpected bus error or segmentation fault"); #endif } @@ -1724,7 +2010,7 @@ struct hblk *h; void GC_dirty_init() { -#if defined(SUNOS5SIGS) || defined(IRIX5) +#if defined(SUNOS5SIGS) || defined(IRIX5) /* || defined(OSF1) */ struct sigaction act, oldact; # ifdef IRIX5 act.sa_flags = SA_RESTART; @@ -1768,7 +2054,7 @@ void GC_dirty_init() } # endif # if defined(SUNOS5SIGS) || defined(IRIX5) -# ifdef IRIX_THREADS +# if defined(IRIX_THREADS) || defined(IRIX_JDK_THREADS) sigaction(SIGSEGV, 0, &oldact); sigaction(SIGSEGV, &act, 0); # else @@ -1794,6 +2080,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); @@ -1969,8 +2264,6 @@ word n; word GC_proc_buf_size = INITIAL_BUF_SZ; char *GC_proc_buf; -page_hash_table GC_written_pages = { 0 }; /* Pages ever dirtied */ - #ifdef SOLARIS_THREADS /* We don't have exact sp values for threads. So we count on */ /* occasionally declaring stack pages to be fresh. Thus we */ @@ -2261,14 +2554,18 @@ struct hblk *h; * Call stack save code for debugging. * Should probably be in mach_dep.c, but that requires reorganization. */ -#if defined(SPARC) +#if defined(SPARC) && !defined(LINUX) # if defined(SUNOS4) # include <machine/frame.h> # else # if defined (DRSNX) # include <sys/sparc/frame.h> # else -# include <sys/frame.h> +# if defined(OPENBSD) +# include <frame.h> +# else +# include <sys/frame.h> +# endif # endif # endif # if NARGS > 6 @@ -2278,6 +2575,15 @@ struct hblk *h; #ifdef SAVE_CALL_CHAIN /* Fill in the pc and argument information for up to NFRAMES of my */ /* callers. Ignore my frame and my callers frame. */ + +#ifdef OPENBSD +# define FR_SAVFP fr_fp +# define FR_SAVPC fr_pc +#else +# define FR_SAVFP fr_savfp +# define FR_SAVPC fr_savpc +#endif + void GC_save_callers (info) struct callinfo info[NFRAMES]; { @@ -2288,11 +2594,11 @@ struct callinfo info[NFRAMES]; frame = (struct frame *) GC_save_regs_in_stack (); - for (fp = frame -> fr_savfp; fp != 0 && nframes < NFRAMES; - fp = fp -> fr_savfp, nframes++) { + for (fp = frame -> FR_SAVFP; fp != 0 && nframes < NFRAMES; + fp = fp -> FR_SAVFP, nframes++) { register int i; - info[nframes].ci_pc = fp->fr_savpc; + info[nframes].ci_pc = fp->FR_SAVPC; for (i = 0; i < NARGS; i++) { info[nframes].ci_arg[i] = ~(fp->fr_arg[i]); } |