diff options
author | Paolo Molaro <lupus@oddwiz.org> | 2006-01-24 14:37:10 +0300 |
---|---|---|
committer | Paolo Molaro <lupus@oddwiz.org> | 2006-01-24 14:37:10 +0300 |
commit | d58dfa185af1d48fb93efdef1d046762f214f0a7 (patch) | |
tree | f851d10caf20d342811d58d624fcdcbd92fe4151 /libgc/os_dep.c | |
parent | 3be1eb27881d243559d4ab0baf7b538334c7e1b3 (diff) |
Tue Jan 24 12:34:06 CET 2006 Paolo Molaro <lupus@ximian.com>
* *: update from upstream changes.
svn path=/trunk/mono/; revision=55979
Diffstat (limited to 'libgc/os_dep.c')
-rw-r--r-- | libgc/os_dep.c | 230 |
1 files changed, 139 insertions, 91 deletions
diff --git a/libgc/os_dep.c b/libgc/os_dep.c index e224af79d83..d7beb58dd9b 100644 --- a/libgc/os_dep.c +++ b/libgc/os_dep.c @@ -60,6 +60,10 @@ # include <signal.h> # endif +#if defined(LINUX) || defined(LINUX_STACKBOTTOM) +# include <ctype.h> +#endif + /* Blatantly OS dependent routines, except for those that are related */ /* to dynamic loading. */ @@ -80,7 +84,7 @@ # define NEED_FIND_LIMIT # endif -#if defined(FREEBSD) && defined(I386) +#if defined(FREEBSD) && (defined(I386) || defined(powerpc) || defined(__powerpc__)) # include <machine/trap.h> # if !defined(PCR) # define NEED_FIND_LIMIT @@ -250,30 +254,11 @@ word GC_apply_to_maps(word (*fn)(char *)) // XXXXXXXX-XXXXXXXX r-xp 00000000 30:05 260537 name of mapping...\n // ^^^^^^^^ ^^^^^^^^ ^^^^ ^^ // start end prot maj_dev -// 0 9 18 32 -// -// For 64 bit ABIs: -// 0 17 34 56 // -// The parser is called with a pointer to the entry and the return value -// is either NULL or is advanced to the next entry(the byte after the -// trailing '\n'.) +// Note that since about auguat 2003 kernels, the columns no longer have +// fixed offsets on 64-bit kernels. Hence we no longer rely on fixed offsets +// anywhere, which is safer anyway. // -#if CPP_WORDSZ == 32 -# define OFFSET_MAP_START 0 -# define OFFSET_MAP_END 9 -# define OFFSET_MAP_PROT 18 -# define OFFSET_MAP_MAJDEV 32 -# define ADDR_WIDTH 8 -#endif - -#if CPP_WORDSZ == 64 -# define OFFSET_MAP_START 0 -# define OFFSET_MAP_END 17 -# define OFFSET_MAP_PROT 34 -# define OFFSET_MAP_MAJDEV 56 -# define ADDR_WIDTH 16 -#endif /* * Assign various fields of the first line in buf_ptr to *start, *end, @@ -282,37 +267,46 @@ word GC_apply_to_maps(word (*fn)(char *)) char *GC_parse_map_entry(char *buf_ptr, word *start, word *end, char *prot_buf, unsigned int *maj_dev) { - int i; - char *tok; + char *start_start, *end_start, *prot_start, *maj_dev_start; + char *p; + char *endp; if (buf_ptr == NULL || *buf_ptr == '\0') { return NULL; } - memcpy(prot_buf, buf_ptr+OFFSET_MAP_PROT, 4); - /* do the protections first. */ + p = buf_ptr; + while (isspace(*p)) ++p; + start_start = p; + GC_ASSERT(isxdigit(*start_start)); + *start = strtoul(start_start, &endp, 16); p = endp; + GC_ASSERT(*p=='-'); + + ++p; + end_start = p; + GC_ASSERT(isxdigit(*end_start)); + *end = strtoul(end_start, &endp, 16); p = endp; + GC_ASSERT(isspace(*p)); + + while (isspace(*p)) ++p; + prot_start = p; + GC_ASSERT(*prot_start == 'r' || *prot_start == '-'); + memcpy(prot_buf, prot_start, 4); prot_buf[4] = '\0'; - - if (prot_buf[1] == 'w') {/* we can skip all of this if it's not writable. */ - - tok = buf_ptr; - buf_ptr[OFFSET_MAP_START+ADDR_WIDTH] = '\0'; - *start = strtoul(tok, NULL, 16); - - tok = buf_ptr+OFFSET_MAP_END; - buf_ptr[OFFSET_MAP_END+ADDR_WIDTH] = '\0'; - *end = strtoul(tok, NULL, 16); - - buf_ptr += OFFSET_MAP_MAJDEV; - tok = buf_ptr; - while (*buf_ptr != ':') buf_ptr++; - *buf_ptr++ = '\0'; - *maj_dev = strtoul(tok, NULL, 16); + if (prot_buf[1] == 'w') {/* we can skip the rest if it's not writable. */ + /* Skip past protection field to offset field */ + while (!isspace(*p)) ++p; while (isspace(*p)) ++p; + GC_ASSERT(isxdigit(*p)); + /* Skip past offset field, which we ignore */ + while (!isspace(*p)) ++p; while (isspace(*p)) ++p; + maj_dev_start = p; + GC_ASSERT(isxdigit(*maj_dev_start)); + *maj_dev = strtoul(maj_dev_start, NULL, 16); } - while (*buf_ptr && *buf_ptr++ != '\n'); + while (*p && *p++ != '\n'); - return buf_ptr; + return p; } #endif /* Need to parse /proc/self/maps. */ @@ -704,8 +698,8 @@ ptr_t GC_get_stack_base() # if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1) \ || defined(HURD) || defined(NETBSD) || defined(FREEBSD) static struct sigaction old_segv_act; -# if defined(_sigargs) /* !Irix6.x */ || defined(HPUX) \ - || defined(HURD) || defined(NETBSD) || defined(FREEBSD) +# if defined(IRIX5) || defined(HPUX) \ + || defined(HURD) || defined(NETBSD) static struct sigaction old_bus_act; # endif # else @@ -737,10 +731,12 @@ ptr_t GC_get_stack_base() /* and setting a handler at the same time. */ (void) sigaction(SIGSEGV, 0, &old_segv_act); (void) sigaction(SIGSEGV, &act, 0); + (void) sigaction(SIGBUS, 0, &old_bus_act); + (void) sigaction(SIGBUS, &act, 0); # else (void) sigaction(SIGSEGV, &act, &old_segv_act); -# if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \ - || defined(HPUX) || defined(HURD) || defined(NETBSD) || defined(FREEBSD) +# if defined(IRIX5) \ + || defined(HPUX) || defined(HURD) || defined(NETBSD) /* Under Irix 5.x or HP/UX, we may get SIGBUS. */ /* Pthreads doesn't exist under Irix 5.x, so we */ /* don't have to worry in the threads case. */ @@ -778,8 +774,8 @@ ptr_t GC_get_stack_base() # if defined(SUNOS5SIGS) || defined(IRIX5) \ || defined(OSF1) || defined(HURD) || defined(NETBSD) || defined(FREEBSD) (void) sigaction(SIGSEGV, &old_segv_act, 0); -# if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \ - || defined(HPUX) || defined(HURD) || defined(NETBSD) || defined(FREEBSD) +# if defined(IRIX5) \ + || defined(HPUX) || defined(HURD) || defined(NETBSD) (void) sigaction(SIGBUS, &old_bus_act, 0); # endif # else @@ -859,13 +855,14 @@ ptr_t GC_get_stack_base() #include <sys/types.h> #include <sys/stat.h> -#include <ctype.h> # define STAT_SKIP 27 /* Number of fields preceding startstack */ /* field in /proc/self/stat */ +#ifdef USE_LIBC_PRIVATES # pragma weak __libc_stack_end extern ptr_t __libc_stack_end; +#endif # ifdef IA64 /* Try to read the backing store base from /proc/self/maps. */ @@ -895,33 +892,38 @@ ptr_t GC_get_stack_base() return GC_apply_to_maps(backing_store_base_from_maps); } -# pragma weak __libc_ia64_register_backing_store_base - extern ptr_t __libc_ia64_register_backing_store_base; +# ifdef USE_LIBC_PRIVATES +# pragma weak __libc_ia64_register_backing_store_base + extern ptr_t __libc_ia64_register_backing_store_base; +# endif ptr_t GC_get_register_stack_base(void) { - if (0 != &__libc_ia64_register_backing_store_base - && 0 != __libc_ia64_register_backing_store_base) { - /* Glibc 2.2.4 has a bug such that for dynamically linked */ - /* executables __libc_ia64_register_backing_store_base is */ - /* defined but uninitialized during constructor calls. */ - /* Hence we check for both nonzero address and value. */ - return __libc_ia64_register_backing_store_base; - } else { - word result = backing_store_base_from_proc(); - if (0 == result) { +# ifdef USE_LIBC_PRIVATES + if (0 != &__libc_ia64_register_backing_store_base + && 0 != __libc_ia64_register_backing_store_base) { + /* Glibc 2.2.4 has a bug such that for dynamically linked */ + /* executables __libc_ia64_register_backing_store_base is */ + /* defined but uninitialized during constructor calls. */ + /* Hence we check for both nonzero address and value. */ + return __libc_ia64_register_backing_store_base; + } +# endif + word result = backing_store_base_from_proc(); + if (0 == result) { /* Use dumb heuristics. Works only for default configuration. */ result = (word)GC_stackbottom - BACKING_STORE_DISPLACEMENT; result += BACKING_STORE_ALIGNMENT - 1; result &= ~(BACKING_STORE_ALIGNMENT - 1); /* Verify that it's at least readable. If not, we goofed. */ GC_noop1(*(word *)result); - } - return (ptr_t)result; } + return (ptr_t)result; } # endif +void *GC_set_stackbottom = NULL; + ptr_t GC_linux_stack_base(void) { /* We read the stack base value from /proc/self/stat. We do this */ @@ -941,7 +943,7 @@ ptr_t GC_get_stack_base() /* since the correct value of __libc_stack_end never */ /* becomes visible to us. The second test works around */ /* this. */ -#if USE_LIBC_PRIVATE_SYMBOLS +# ifdef USE_LIBC_PRIVATES if (0 != &__libc_stack_end && 0 != __libc_stack_end ) { # ifdef IA64 /* Some versions of glibc set the address 16 bytes too */ @@ -951,10 +953,19 @@ ptr_t GC_get_stack_base() } /* Otherwise it's not safe to add 16 bytes and we fall */ /* back to using /proc. */ # else +# ifdef SPARC + /* Older versions of glibc for 64-bit Sparc do not set + * this variable correctly, it gets set to either zero + * or one. + */ + if (__libc_stack_end != (ptr_t) (unsigned long)0x1) + return __libc_stack_end; +# else return __libc_stack_end; # endif +# endif } -#endif +# endif f = open("/proc/self/stat", O_RDONLY); if (f < 0 || STAT_READ(f, stat_buf, STAT_BUF_SIZE) < 2 * STAT_SKIP) { ABORT("Couldn't read /proc/self/stat"); @@ -1385,7 +1396,7 @@ int * etext_addr; } # endif -# if defined(FREEBSD) && defined(I386) && !defined(PCR) +# if defined(FREEBSD) && (defined(I386) || defined(powerpc) || defined(__powerpc__)) && !defined(PCR) /* Its unclear whether this should be identical to the above, or */ /* whether it should apply to non-X86 architectures. */ /* For now we don't assume that there is always an empty page after */ @@ -1506,7 +1517,7 @@ void GC_register_data_segments() # endif -# ifdef RS6000 +# if 0 && defined(RS6000) /* We now use mmap */ /* The compiler seems to generate speculative reads one past the end of */ /* an allocated object. Hence we need to make sure that the page */ /* following the last heap page is also mapped. */ @@ -2300,8 +2311,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 @@ -2389,7 +2403,7 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ # endif # ifdef FREEBSD # define SIG_OK (sig == SIGBUS) -# define CODE_OK (code == BUS_PAGE_FAULT) +# define CODE_OK TRUE # endif # endif /* SUNOS4 || (FREEBSD && !SUNOS5SIGS) */ @@ -2414,7 +2428,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) @@ -2480,7 +2494,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) @@ -2515,7 +2529,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 */ @@ -2527,7 +2541,11 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ # if defined(ARM32) char * addr = (char *)sc.fault_address; # else - --> architecture not supported +# if defined(CRIS) + char * addr = (char *)sc.regs.csraddr; +# else + --> architecture not supported +# endif # endif # endif # endif @@ -2596,7 +2614,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); @@ -2690,7 +2708,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 @@ -3068,7 +3087,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; @@ -3403,8 +3422,6 @@ extern kern_return_t exception_raise_state_identity( #define MAX_EXCEPTION_PORTS 16 -static mach_port_t GC_task_self; - static struct { mach_msg_type_number_t count; exception_mask_t masks[MAX_EXCEPTION_PORTS]; @@ -3731,7 +3748,7 @@ static kern_return_t GC_forward_exception( exception_behavior_t behavior; thread_state_flavor_t flavor; - thread_state_data_t thread_state; + thread_state_t thread_state; mach_msg_type_number_t thread_state_count = THREAD_STATE_MAX; for(i=0;i<GC_old_exc_ports.count;i++) @@ -3792,13 +3809,19 @@ catch_exception_raise( 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 +# if defined(POWERPC) +# if CPP_WORDSZ == 32 + 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 + thread_state_flavor_t flavor = PPC_EXCEPTION_STATE64; + mach_msg_type_number_t exc_state_count = PPC_EXCEPTION_STATE64_COUNT; + ppc_exception_state64_t exc_state; +# endif +# else # error FIXME for non-ppc darwin -#endif +# endif if(exception != EXC_BAD_ACCESS || code[0] != KERN_PROTECTION_FAILURE) { @@ -3958,10 +3981,14 @@ kern_return_t catch_exception_raise_state_identity( # if defined (DRSNX) # include <sys/sparc/frame.h> # else -# if defined(OPENBSD) || defined(NETBSD) +# if defined(OPENBSD) # include <frame.h> # else -# include <sys/frame.h> +# if defined(FREEBSD) || defined(NETBSD) +# include <machine/frame.h> +# else +# include <sys/frame.h> +# endif # endif # endif # endif @@ -3990,6 +4017,16 @@ kern_return_t catch_exception_raise_state_identity( #if NARGS == 0 && NFRAMES % 2 == 0 /* No padding */ \ && defined(GC_HAVE_BUILTIN_BACKTRACE) +#ifdef REDIRECT_MALLOC + /* Deal with possible malloc calls in backtrace by omitting */ + /* the infinitely recursing backtrace. */ +# ifdef THREADS + __thread /* If your compiler doesn't understand this */ + /* you could use something like pthread_getspecific. */ +# endif + GC_in_save_callers = FALSE; +#endif + void GC_save_callers (info) struct callinfo info[NFRAMES]; { @@ -3999,15 +4036,26 @@ struct callinfo info[NFRAMES]; /* We retrieve NFRAMES+1 pc values, but discard the first, since it */ /* points to our own frame. */ +# ifdef REDIRECT_MALLOC + if (GC_in_save_callers) { + info[0].ci_pc = (word)(&GC_save_callers); + for (i = 1; i < NFRAMES; ++i) info[i].ci_pc = 0; + return; + } + GC_in_save_callers = TRUE; +# endif GC_ASSERT(sizeof(struct callinfo) == sizeof(void *)); npcs = backtrace((void **)tmp_info, NFRAMES + IGNORE_FRAMES); BCOPY(tmp_info+IGNORE_FRAMES, info, (npcs - IGNORE_FRAMES) * sizeof(void *)); for (i = npcs - IGNORE_FRAMES; i < NFRAMES; ++i) info[i].ci_pc = 0; +# ifdef REDIRECT_MALLOC + GC_in_save_callers = FALSE; +# endif } #else /* No builtin backtrace; do it ourselves */ -#if (defined(OPENBSD) || defined(NETBSD)) && defined(SPARC) +#if (defined(OPENBSD) || defined(NETBSD) || defined(FREEBSD)) && defined(SPARC) # define FR_SAVFP fr_fp # define FR_SAVPC fr_pc #else |