# endif
# include <stdio.h>
-# if defined(MSWINCE)
+# if defined(MSWINCE) || defined (SN_TARGET_PS3)
# define SIGSEGV 0 /* value is irrelevant */
# else
# 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. */
# 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
// 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,
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. */
{
extern ptr_t GC_find_limit();
+ if (GC_no_dls)
+ /*
+ * Not needed, avoids the SIGSEGV caused by GC_find_limit which
+ * complicates debugging.
+ */
+ return;
+
# ifdef LINUX
/* Try the easy approaches first: */
if ((ptr_t)__data_start != 0) {
# if !defined(PCR) && !defined(AMIGA) && !defined(MSWIN32) \
&& !defined(MSWINCE) \
&& !defined(MACOS) && !defined(DJGPP) && !defined(DOS4GW) \
- && !defined(NOSYS) && !defined(ECOS)
+ && !defined(NOSYS) && !defined(ECOS) && !defined(SN_TARGET_PS3)
# if defined(sigmask) && !defined(UTS4) && !defined(HURD)
/* Use the traditional BSD interface */
# 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
/* 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. */
# 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
#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. */
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 */
/* 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 */
} /* 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");
}
# endif
-# if defined(FREEBSD) && defined(I386) && !defined(PCR)
+# if defined(FREEBSD) && (defined(I386) || defined(powerpc) || defined(__powerpc__) || defined(__x86_64__)) && !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 */
/* hanging from it. We're on thin ice here ... */
extern caddr_t sbrk();
+ GC_ASSERT(DATASTART);
GC_add_roots_inner(DATASTART, (char *)sbrk(0), FALSE);
# else
+ GC_ASSERT(DATASTART);
GC_add_roots_inner(DATASTART, (char *)(DATAEND), FALSE);
# if defined(DATASTART2)
GC_add_roots_inner(DATASTART2, (char *)(DATAEND2), FALSE);
# if !defined(OS2) && !defined(PCR) && !defined(AMIGA) \
&& !defined(MSWIN32) && !defined(MSWINCE) \
- && !defined(MACOS) && !defined(DOS4GW)
+ && !defined(MACOS) && !defined(DOS4GW) && !defined(SN_TARGET_PS3)
# ifdef SUNOS4
extern caddr_t sbrk();
# 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. */
# else
GC_ASSERT(last_addr != 0);
# endif
+ if (((word)result % HBLKSIZE) != 0)
+ ABORT ("GC_unix_get_mem: Memory returned by mmap is not aligned to HBLKSIZE.");
return((ptr_t)result);
}
# 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
# endif
# ifdef FREEBSD
# define SIG_OK (sig == SIGBUS)
-# define CODE_OK (code == BUS_PAGE_FAULT)
+# define CODE_OK TRUE
# endif
# endif /* SUNOS4 || (FREEBSD && !SUNOS5SIGS) */
# 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)
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)
# 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 */
# 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
# 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);
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
#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;
#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];
mask,
GC_ports.exception,
EXCEPTION_DEFAULT,
- MACHINE_THREAD_STATE
+ GC_MACH_THREAD_STATE_FLAVOR
);
if(r != KERN_SUCCESS) ABORT("task_set_exception_ports failed");
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++)
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
+# elif defined(I386)
+ thread_state_flavor_t flavor = i386_EXCEPTION_STATE;
+ mach_msg_type_number_t exc_state_count = i386_EXCEPTION_STATE_COUNT;
+ i386_exception_state_t exc_state;
+# else
# error FIXME for non-ppc darwin
-#endif
+# endif
if(exception != EXC_BAD_ACCESS || code[0] != KERN_PROTECTION_FAILURE) {
}
/* This is the address that caused the fault */
+#if defined(POWERPC)
addr = (char*) exc_state.dar;
+#elif defined (I386)
+ addr = (char*) exc_state.faultvaddr;
+#else
+# error FIXME for non POWERPC/I386
+#endif
if((HDR(addr)) == 0) {
/* Ugh... just like the SIGBUS problem above, it seems we get a bogus
# 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
#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];
{
/* 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