diff -r 950f4ee58444 libgo/runtime/go-panic.c
--- a/libgo/runtime/go-panic.c	Tue Dec 20 10:48:30 2011 -0800
+++ b/libgo/runtime/go-panic.c	Wed Dec 21 14:21:31 2011 -0800
@@ -24,13 +24,13 @@
   if (p->__next != NULL)
     {
       __printpanics (p->__next);
-      printf ("\t");
+      fprintf (stderr, "\t");
     }
-  printf ("panic: ");
+  fprintf (stderr, "panic: ");
   printany (p->__arg);
   if (p->__was_recovered)
-    printf (" [recovered]");
-  putchar ('\n');
+    fprintf (stderr, " [recovered]");
+  fputc ('\n', stderr);
 }
 
 /* This implements __go_panic which is used for the panic
diff -r 950f4ee58444 libgo/runtime/go-signal.c
--- a/libgo/runtime/go-signal.c	Tue Dec 20 10:48:30 2011 -0800
+++ b/libgo/runtime/go-signal.c	Wed Dec 21 14:21:31 2011 -0800
@@ -17,109 +17,133 @@
   #define SA_RESTART 0
 #endif
 
-/* What to do for a signal.  */
+#ifdef USING_SPLIT_STACK
 
-struct sigtab
-{
-  /* Signal number.  */
-  int sig;
-  /* Nonzero if the signal should be caught.  */
-  _Bool catch;
-  /* Nonzero if the signal should be queued.  */
-  _Bool queue;
-  /* Nonzero if the signal should be ignored.  */
-  _Bool ignore;
-  /* Nonzero if we should restart system calls.  */
-  _Bool restart;
-};
+extern void __splitstack_getcontext(void *context[10]);
 
-/* What to do for signals.  */
+extern void __splitstack_setcontext(void *context[10]);
 
-static struct sigtab signals[] =
-{
-  { SIGHUP, 0, 1, 0, 1 },
-  { SIGINT, 0, 1, 0, 1 },
-  { SIGQUIT, 0, 1, 0, 1 },
-  { SIGALRM, 0, 1, 1, 1 },
-  { SIGTERM, 0, 1, 0, 1 },
+#endif
+
+#define C SigCatch
+#define I SigIgnore
+#define R SigRestart
+#define Q SigQueue
+#define P SigPanic
+
+/* Signal actions.  This collects the sigtab tables for several
+   different targets from the master library.  SIGKILL, SIGCONT, and
+   SIGSTOP are not listed, as we don't want to set signal handlers for
+   them.  */
+
+SigTab runtime_sigtab[] = {
+#ifdef SIGHUP
+  { SIGHUP,	Q + R },
+#endif
+#ifdef SIGINT
+  { SIGINT, 	Q + R },
+#endif
+#ifdef SIGQUIT
+  { SIGQUIT, 	C },
+#endif
 #ifdef SIGILL
-  { SIGILL, 1, 0, 0, 0 },
+  { SIGILL, 	C },
 #endif
 #ifdef SIGTRAP
-  { SIGTRAP, 1, 0, 0, 0 },
+  { SIGTRAP, 	C },
 #endif
 #ifdef SIGABRT
-  { SIGABRT, 1, 0, 0, 0 },
+  { SIGABRT, 	C },
 #endif
 #ifdef SIGBUS
-  { SIGBUS, 1, 0, 0, 0 },
+  { SIGBUS, 	C + P },
 #endif
 #ifdef SIGFPE
-  { SIGFPE, 1, 0, 0, 0 },
+  { SIGFPE, 	C + P },
 #endif
 #ifdef SIGUSR1
-  { SIGUSR1, 0, 1, 1, 1 },
+  { SIGUSR1, 	Q + I + R },
 #endif
 #ifdef SIGSEGV
-  { SIGSEGV, 1, 0, 0, 0 },
+  { SIGSEGV, 	C + P },
 #endif
 #ifdef SIGUSR2
-  { SIGUSR2, 0, 1, 1, 1 },
+  { SIGUSR2, 	Q + I + R },
 #endif
 #ifdef SIGPIPE
-  { SIGPIPE, 0, 0, 1, 0 },
+  { SIGPIPE, 	I },
+#endif
+#ifdef SIGALRM
+  { SIGALRM, 	Q + I + R },
+#endif
+#ifdef SIGTERM
+  { SIGTERM, 	Q + R },
 #endif
 #ifdef SIGSTKFLT
-  { SIGSTKFLT, 1, 0, 0, 0 },
+  { SIGSTKFLT, 	C },
 #endif
 #ifdef SIGCHLD
-  { SIGCHLD, 0, 1, 1, 1 },
+  { SIGCHLD, 	Q + I + R },
 #endif
 #ifdef SIGTSTP
-  { SIGTSTP, 0, 1, 1, 1 },
+  { SIGTSTP, 	Q + I + R },
 #endif
 #ifdef SIGTTIN
-  { SIGTTIN, 0, 1, 1, 1 },
+  { SIGTTIN, 	Q + I + R },
 #endif
 #ifdef SIGTTOU
-  { SIGTTOU, 0, 1, 1, 1 },
+  { SIGTTOU, 	Q + I + R },
 #endif
 #ifdef SIGURG
-  { SIGURG, 0, 1, 1, 1 },
+  { SIGURG, 	Q + I + R },
 #endif
 #ifdef SIGXCPU
-  { SIGXCPU, 0, 1, 1, 1 },
+  { SIGXCPU, 	Q + I + R },
 #endif
 #ifdef SIGXFSZ
-  { SIGXFSZ, 0, 1, 1, 1 },
+  { SIGXFSZ, 	Q + I + R },
 #endif
-#ifdef SIGVTARLM
-  { SIGVTALRM, 0, 1, 1, 1 },
+#ifdef SIGVTALRM
+  { SIGVTALRM, 	Q + I + R },
 #endif
 #ifdef SIGPROF
-  { SIGPROF, 0, 1, 1, 1 },
+  { SIGPROF, 	Q + I + R },
 #endif
 #ifdef SIGWINCH
-  { SIGWINCH, 0, 1, 1, 1 },
+  { SIGWINCH, 	Q + I + R },
 #endif
 #ifdef SIGIO
-  { SIGIO, 0, 1, 1, 1 },
+  { SIGIO, 	Q + I + R },
 #endif
 #ifdef SIGPWR
-  { SIGPWR, 0, 1, 1, 1 },
+  { SIGPWR, 	Q + I + R },
 #endif
 #ifdef SIGSYS
-  { SIGSYS, 1, 0, 0, 0 },
+  { SIGSYS, 	C },
 #endif
-  { -1, 0, 0, 0, 0 }
+#ifdef SIGEMT
+  { SIGEMT,	C },
+#endif
+#ifdef SIGINFO
+  { SIGINFO,	Q + I + R },
+#endif
+#ifdef SIGTHR
+  { SIGTHR,	Q + I + R },
+#endif
+  { -1,		0 }
 };
+#undef C
+#undef I
+#undef R
+#undef Q
+#undef P
 
-/* The Go signal handler.  */
+/* Handle a signal, for cases where we don't panic.  We can split the
+   stack here.  */
 
 static void
-sighandler (int sig)
+sig_handler (int sig)
 {
-  const char *msg;
   int i;
 
 #ifdef SIGPROF
@@ -131,99 +155,223 @@
     }
 #endif
 
-  /* FIXME: Should check siginfo for more information when
-     available.  */
-  msg = NULL;
+  for (i = 0; runtime_sigtab[i].sig != -1; ++i)
+    {
+      struct sigaction sa;
+
+      if (runtime_sigtab[i].sig != sig)
+	continue;
+
+      if ((runtime_sigtab[i].flags & SigQueue) != 0)
+	{
+	  if (__go_sigsend (sig)
+	      || (runtime_sigtab[sig].flags & SigIgnore) != 0)
+	    return;
+	  runtime_exit (2);		// SIGINT, SIGTERM, etc
+	}
+
+      if (runtime_panicking)
+	runtime_exit (2);
+      runtime_panicking = 1;
+
+      /* We should do a stack backtrace here.  Until we can do that,
+	 we reraise the signal in order to get a slightly better
+	 report from the shell.  */
+
+      memset (&sa, 0, sizeof sa);
+
+      sa.sa_handler = SIG_DFL;
+
+      i = sigemptyset (&sa.sa_mask);
+      __go_assert (i == 0);
+
+      if (sigaction (sig, &sa, NULL) != 0)
+	abort ();
+
+      raise (sig);
+
+      runtime_exit (2);
+    }
+
+  __builtin_unreachable ();
+}
+
+/* The start of handling a signal which panics.  */
+
+static void
+sig_panic_leadin (int sig)
+{
+  int i;
+  sigset_t clear;
+
+  if (runtime_m ()->mallocing)
+    {
+      runtime_printf ("caught signal while mallocing: %d\n", sig);
+      runtime_throw ("caught signal while mallocing");
+    }
+
+  /* The signal handler blocked signals; unblock them.  */
+  i = sigfillset (&clear);
+  __go_assert (i == 0);
+  i = sigprocmask (SIG_UNBLOCK, &clear, NULL);
+  __go_assert (i == 0);
+}
+
+#ifdef SA_SIGINFO
+
+/* Signal dispatch for signals which panic, on systems which support
+   SA_SIGINFO.  This is called on the thread stack, and as such it is
+   permitted to split the stack.  */
+
+static void
+sig_panic_info_handler (int sig, siginfo_t *info,
+			void *context __attribute__ ((unused)))
+{
+  if (runtime_g () == NULL)
+    {
+      sig_handler (sig);
+      return;
+    }
+
+  sig_panic_leadin (sig);
+
   switch (sig)
     {
-#ifdef SIGILL
-    case SIGILL:
-      msg = "illegal instruction";
-      break;
+#ifdef SIGBUS
+    case SIGBUS:
+      if (info->si_code == BUS_ADRERR && (uintptr_t) info->si_addr < 0x1000)
+	runtime_panicstring ("invalid memory address or "
+			     "nil pointer dereference");
+      runtime_printf ("unexpected fault address %p\n", info->si_addr);
+      runtime_throw ("fault");
 #endif
 
-#ifdef SIGBUS
-    case SIGBUS:
-      msg = "invalid memory address or nil pointer dereference";
-      break;
+#ifdef SIGSEGV
+    case SIGSEGV:
+      if ((info->si_code == 0
+	   || info->si_code == SEGV_MAPERR
+	   || info->si_code == SEGV_ACCERR)
+	  && (uintptr_t) info->si_addr < 0x1000)
+	runtime_panicstring ("invalid memory address or "
+			     "nil pointer dereference");
+      runtime_printf ("unexpected fault address %p\n", info->si_addr);
+      runtime_throw ("fault");
 #endif
 
 #ifdef SIGFPE
     case SIGFPE:
-      msg = "integer divide by zero or floating point error";
-      break;
+      switch (info->si_code)
+	{
+	case FPE_INTDIV:
+	  runtime_panicstring ("integer divide by zero");
+	case FPE_INTOVF:
+	  runtime_panicstring ("integer overflow");
+	}
+      runtime_panicstring ("floating point error");
+#endif
+    }
+
+  /* All signals with SigPanic should be in cases above, and this
+     handler should only be invoked for those signals.  */
+  __builtin_unreachable ();
+}
+
+#else /* !defined (SA_SIGINFO) */
+
+static void
+sig_panic_handler (int sig)
+{
+  if (runtime_g () == NULL)
+    {
+      sig_handler (sig);
+      return;
+    }
+
+  sig_panic_leadin (sig);
+
+  switch (sig)
+    {
+#ifdef SIGBUS
+    case SIGBUS:
+      runtime_panicstring ("invalid memory address or "
+			   "nil pointer dereference");
 #endif
 
 #ifdef SIGSEGV
     case SIGSEGV:
-      msg = "invalid memory address or nil pointer dereference";
-      break;
+      runtime_panicstring ("invalid memory address or "
+			   "nil pointer dereference");
 #endif
 
-    default:
-      break;
+#ifdef SIGFPE
+    case SIGFPE:
+      runtime_panicstring ("integer divide by zero or floating point error");
+#endif
     }
 
-  if (msg != NULL)
-    {
-      sigset_t clear;
-
-      if (runtime_m()->mallocing)
-	{
-	  fprintf (stderr, "caught signal while mallocing: %s\n", msg);
-	  __go_assert (0);
-	}
-
-      /* The signal handler blocked signals; unblock them.  */
-      i = sigfillset (&clear);
-      __go_assert (i == 0);
-      i = sigprocmask (SIG_UNBLOCK, &clear, NULL);
-      __go_assert (i == 0);
-
-      runtime_panicstring (msg);
-    }
-
-  for (i = 0; signals[i].sig != -1; ++i)
-    {
-      if (signals[i].sig == sig)
-	{
-	  struct sigaction sa;
-
-	  if (signals[i].queue)
-	    {
-	      if (__go_sigsend (sig) || signals[i].ignore)
-		return;
-	      runtime_exit (2);		// SIGINT, SIGTERM, etc
-	    }
-
-	  if (runtime_panicking)
-	    runtime_exit (2);
-	  runtime_panicking = 1;
-
-	  memset (&sa, 0, sizeof sa);
-
-	  sa.sa_handler = SIG_DFL;
-
-	  i = sigemptyset (&sa.sa_mask);
-	  __go_assert (i == 0);
-
-	  if (sigaction (sig, &sa, NULL) != 0)
-	    abort ();
-
-	  raise (sig);
-	  exit (2);
-	}
-    }
-  abort ();
+  /* All signals with SigPanic should be in cases above, and this
+     handler should only be invoked for those signals.  */
+  __builtin_unreachable ();
 }
 
-/* Ignore a signal.  */
+#endif /* !defined (SA_SIGINFO) */
+
+/* Ignore a signal.  This is called on the alternate signal stack so
+   it may not split the stack.  */
+
+static void sig_ignore (int) __attribute__ ((no_split_stack));
 
 static void
 sig_ignore (int sig __attribute__ ((unused)))
 {
 }
 
+/* A signal handler used for signals which are not going to panic.
+   This is called on the alternate signal stack so it may not split
+   the stack.  */
+
+static void
+sig_tramp (int) __attribute__ ((no_split_stack));
+
+static void
+sig_tramp (int sig)
+{
+  G *gp;
+  M *mp;
+
+  /* We are now running on the stack registered via sigaltstack.
+     (Actually there is a small span of time between runtime_siginit
+     and sigaltstack when the program starts.)  */
+  gp = runtime_g ();
+  mp = runtime_m ();
+
+  if (gp != NULL)
+    __splitstack_getcontext (&gp->stack_context[0]);
+
+  if (gp != NULL && mp->gsignal != NULL)
+    {
+      /* We are running on the signal stack.  Set the split stack
+	 context so that the stack guards are checked correctly.  */
+#ifdef USING_SPLIT_STACK
+      __splitstack_setcontext (&mp->gsignal->stack_context[0]);
+#endif
+    }
+
+  sig_handler (sig);
+
+  /* We are going to return back to the signal trampoline and then to
+     whatever we were doing before we got the signal.  Restore the
+     split stack context so that stack guards are checked
+     correctly.  */
+
+  if (gp != NULL)
+    {
+#ifdef USING_SPLIT_STACK
+      __splitstack_setcontext (&gp->stack_context[0]);
+#endif
+    }
+}
+
 /* Initialize signal handling for Go.  This is called when the program
    starts.  */
 
@@ -237,21 +385,44 @@
 
   memset (&sa, 0, sizeof sa);
 
-  sa.sa_handler = sighandler;
-
   i = sigfillset (&sa.sa_mask);
   __go_assert (i == 0);
 
-  for (i = 0; signals[i].sig != -1; ++i)
+  for (i = 0; runtime_sigtab[i].sig != -1; ++i)
     {
-      if (signals[i].queue != (queue ? 1 : 0))
+      if (runtime_sigtab[i].flags == 0)
 	continue;
-      if (signals[i].catch || signals[i].queue)
-	sa.sa_handler = sighandler;
+      if ((runtime_sigtab[i].flags & SigQueue) != queue)
+	continue;
+
+      if ((runtime_sigtab[i].flags & (SigCatch | SigQueue)) != 0)
+	{
+	  if ((runtime_sigtab[i].flags & SigPanic) == 0)
+	    {
+	      sa.sa_flags = SA_ONSTACK;
+	      sa.sa_handler = sig_tramp;
+	    }
+	  else
+	    {
+#ifdef SA_SIGINFO
+	      sa.sa_flags = SA_SIGINFO;
+	      sa.sa_sigaction = sig_panic_info_handler;
+#else
+	      sa.sa_flags = 0;
+	      sa.sa_handler = sig_panic_handler;
+#endif
+	    }
+	}
       else
-	sa.sa_handler = sig_ignore;
-      sa.sa_flags = signals[i].restart ? SA_RESTART : 0;
-      if (sigaction (signals[i].sig, &sa, NULL) != 0)
+	{
+	  sa.sa_flags = SA_ONSTACK;
+	  sa.sa_handler = sig_ignore;
+	}
+
+      if ((runtime_sigtab[i].flags & SigRestart) != 0)
+	sa.sa_flags |= SA_RESTART;
+
+      if (sigaction (runtime_sigtab[i].sig, &sa, NULL) != 0)
 	__go_assert (0);
     }
 }
@@ -281,7 +452,7 @@
     }
   else
     {
-      sa.sa_handler = sighandler;
+      sa.sa_handler = sig_handler;
       sa.sa_flags = SA_RESTART;
       i = sigaction (SIGPROF, &sa, NULL);
       __go_assert (i == 0);
diff -r 950f4ee58444 libgo/runtime/mem.c
--- a/libgo/runtime/mem.c	Tue Dec 20 10:48:30 2011 -0800
+++ b/libgo/runtime/mem.c	Wed Dec 21 14:21:31 2011 -0800
@@ -47,7 +47,7 @@
 	if (dev_zero == -1) {
 		dev_zero = open("/dev/zero", O_RDONLY);
 		if (dev_zero < 0) {
-			printf("open /dev/zero: errno=%d\n", errno);
+			runtime_printf("open /dev/zero: errno=%d\n", errno);
 			exit(2);
 		}
 	}
@@ -57,8 +57,8 @@
 	p = runtime_mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, fd, 0);
 	if (p == MAP_FAILED) {
 		if(errno == EACCES) {
-			printf("runtime: mmap: access denied\n");
-			printf("if you're running SELinux, enable execmem for this process.\n");
+			runtime_printf("runtime: mmap: access denied\n");
+			runtime_printf("if you're running SELinux, enable execmem for this process.\n");
 			exit(2);
 		}
 		return nil;
@@ -97,7 +97,7 @@
 	if (dev_zero == -1) {
 		dev_zero = open("/dev/zero", O_RDONLY);
 		if (dev_zero < 0) {
-			printf("open /dev/zero: errno=%d\n", errno);
+			runtime_printf("open /dev/zero: errno=%d\n", errno);
 			exit(2);
 		}
 	}
@@ -123,7 +123,7 @@
 	if (dev_zero == -1) {
 		dev_zero = open("/dev/zero", O_RDONLY);
 		if (dev_zero < 0) {
-			printf("open /dev/zero: errno=%d\n", errno);
+			runtime_printf("open /dev/zero: errno=%d\n", errno);
 			exit(2);
 		}
 	}
diff -r 950f4ee58444 libgo/runtime/proc.c
--- a/libgo/runtime/proc.c	Tue Dec 20 10:48:30 2011 -0800
+++ b/libgo/runtime/proc.c	Wed Dec 21 14:21:31 2011 -0800
@@ -29,6 +29,11 @@
 extern void *__splitstack_find(void *, void *, size_t *, void **, void **,
 			       void **);
 
+extern void __splitstack_block_signals (int *, int *);
+
+extern void __splitstack_block_signals_context (void *context[10], int *,
+						int *);
+
 #endif
 
 #if defined(USING_SPLIT_STACK) && defined(LINKER_SUPPORTS_SPLIT_STACK)
@@ -862,6 +867,14 @@
 		*(int*)0x21 = 0x21;
 	}
 	runtime_minit();
+
+#ifdef USING_SPLIT_STACK
+	{
+	  int dont_block_signals = 0;
+	  __splitstack_block_signals(&dont_block_signals, nil);
+	}
+#endif
+
 	schedule(nil);
 	return nil;
 }
@@ -1142,9 +1155,13 @@
 	newg = runtime_malloc(sizeof(G));
 	if(stacksize >= 0) {
 #if USING_SPLIT_STACK
+		int dont_block_signals = 0;
+
 		*ret_stack = __splitstack_makecontext(stacksize,
 						      &newg->stack_context[0],
 						      ret_stacksize);
+		__splitstack_block_signals_context(&newg->stack_context[0],
+						   &dont_block_signals, nil);
 #else
 		*ret_stack = runtime_mallocgc(stacksize, FlagNoProfiling|FlagNoGC, 0, 0);
 		*ret_stacksize = stacksize;
@@ -1186,8 +1203,12 @@
 
 	if((newg = gfget()) != nil){
 #ifdef USING_SPLIT_STACK
+		int dont_block_signals = 0;
+
 		sp = __splitstack_resetcontext(&newg->stack_context[0],
 					       &spsize);
+		__splitstack_block_signals_context(&newg->stack_context[0],
+						   &dont_block_signals, nil);
 #else
 		sp = newg->gcinitial_sp;
 		spsize = newg->gcstack_size;
diff -r 950f4ee58444 libgo/runtime/runtime.h
--- a/libgo/runtime/runtime.h	Tue Dec 20 10:48:30 2011 -0800
+++ b/libgo/runtime/runtime.h	Wed Dec 21 14:21:31 2011 -0800
@@ -52,6 +52,7 @@
 typedef	union	Lock		Lock;
 typedef	struct	M		M;
 typedef	union	Note		Note;
+typedef	struct	SigTab		SigTab;
 typedef	struct	MCache		MCache;
 typedef struct	FixAlloc	FixAlloc;
 typedef	struct	Hchan		Hchan;
@@ -179,6 +180,20 @@
 	uint32	waitsemalock;
 };
 
+struct	SigTab
+{
+	int32	sig;
+	int32	flags;
+};
+enum
+{
+	SigCatch = 1<<0,
+	SigIgnore = 1<<1,
+	SigRestart = 1<<2,
+	SigQueue = 1<<3,
+	SigPanic = 1<<4,
+};
+
 /* Macros.  */
 
 #ifdef __WINDOWS__
@@ -251,7 +266,7 @@
 void	runtime_osinit();
 void	runtime_goargs(void);
 void	runtime_goenvs(void);
-void	runtime_throw(const char*);
+void	runtime_throw(const char*) __attribute__ ((noreturn));
 void	runtime_panicstring(const char*) __attribute__ ((noreturn));
 void*	runtime_mal(uintptr);
 void	runtime_schedinit(void);
diff -r 950f4ee58444 libgo/runtime/sigqueue.goc
--- a/libgo/runtime/sigqueue.goc	Tue Dec 20 10:48:30 2011 -0800
+++ b/libgo/runtime/sigqueue.goc	Wed Dec 21 14:21:31 2011 -0800
@@ -110,6 +110,6 @@
 }
 
 func Siginit() {
-	runtime_initsig(1);
+	runtime_initsig(SigQueue);
 	sig.inuse = true;	// enable reception of signals; cannot disable
 }
