2005-01-12 Andrew J. Schorr <ajschorr@alumni.princeton.edu>

	* configure.ac: Test for header file <ucontext.h> (for use in
	  signal processing).
	* sigevent.c: (trap_default_signals) Use the SA_SIGINFO flag to
	  pass additional siginfo_t and ucontext_t arguments to core_handler
	  and exit_handler.
	  (core_handler,exit_handler) Now invoked with 3 arguments (using
	  SA_SIGINFO).  Pass additional info to zlog_signal.
	  (program_counter) New function to find program counter in ucontext_t,
	  needs to be enhanced to support more platforms (currently works only
	  on Linux/x86).
	* log.h: Change the zlog_signal prototype to add new arguments
	  siginfo_t * and program_counter.
	* log.c: (zlog_signal) Add new arguments siginfo and program_counter.
	  Include si_addr and program counter (if non-NULL) in message.
	  And remove #ifdef HAVE_GLIBC_BACKTRACE around hex_append, since
	  that is now used to render the si_addr and PC pointers.
diff --git a/ChangeLog b/ChangeLog
index fdcfd99..b6780eb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2005-01-12 Andrew J. Schorr <ajschorr@alumni.princeton.edu>
 
+	* configure.ac: Test for header file <ucontext.h> (for use in
+	  signal processing).
+
+2005-01-12 Andrew J. Schorr <ajschorr@alumni.princeton.edu>
+
 	* configure.ac: If configure is invoked with --enable-snmp, but
 	  the configure script is unable to find SNMP support on the platform,
 	  then configure should give an error message and exit.
diff --git a/configure.ac b/configure.ac
index 61a00d9..ff424e8 100755
--- a/configure.ac
+++ b/configure.ac
@@ -5,7 +5,7 @@
 ##  Copyright (c) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro <kunihiro@zebra.org>
 ##  Portions Copyright (c) 2003 Paul Jakma <paul@dishone.st>
 ##
-## $Id: configure.ac,v 1.86 2005/01/12 16:52:55 ajs Exp $
+## $Id: configure.ac,v 1.87 2005/01/12 17:27:27 ajs Exp $
 AC_PREREQ(2.53)
 
 AC_INIT(Quagga, 0.98.0, [http://bugzilla.quagga.net])
@@ -1107,6 +1107,11 @@
 fi
 AC_SUBST(LIBCAP)
 
+dnl -------------------
+dnl test for ucontext.h
+dnl -------------------
+AC_CHECK_HEADERS(ucontext.h)
+
 dnl ---------------------------
 dnl check for glibc 'backtrace'
 dnl --------------------------- 
diff --git a/lib/ChangeLog b/lib/ChangeLog
index 4b245be..4410fb2 100644
--- a/lib/ChangeLog
+++ b/lib/ChangeLog
@@ -1,5 +1,22 @@
 2005-01-12 Andrew J. Schorr <ajschorr@alumni.princeton.edu>
 
+	* sigevent.c: (trap_default_signals) Use the SA_SIGINFO flag to
+	  pass additional siginfo_t and ucontext_t arguments to core_handler
+	  and exit_handler.
+	  (core_handler,exit_handler) Now invoked with 3 arguments (using
+	  SA_SIGINFO).  Pass additional info to zlog_signal.
+	  (program_counter) New function to find program counter in ucontext_t,
+	  needs to be enhanced to support more platforms (currently works only
+	  on Linux/x86).
+	* log.h: Change the zlog_signal prototype to add new arguments
+	  siginfo_t * and program_counter.
+	* log.c: (zlog_signal) Add new arguments siginfo and program_counter.
+	  Include si_addr and program counter (if non-NULL) in message.
+	  And remove #ifdef HAVE_GLIBC_BACKTRACE around hex_append, since
+	  that is now used to render the si_addr and PC pointers.
+
+2005-01-12 Andrew J. Schorr <ajschorr@alumni.princeton.edu>
+
 	* zebra.h: If not C99 and no va_copy macro available, fall back to
 	  memcpy (solves a build problem on FreeBSD 4.x).
 
diff --git a/lib/log.c b/lib/log.c
index 1be1c0b..fcf7c5d 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -1,5 +1,5 @@
 /*
- * $Id: log.c,v 1.20 2004/12/10 22:43:17 ajs Exp $
+ * $Id: log.c,v 1.21 2005/01/12 17:27:27 ajs Exp $
  *
  * Logging of zebra
  * Copyright (C) 1997, 1998, 1999 Kunihiro Ishiguro
@@ -177,10 +177,6 @@
   return str_append(s,len,t);
 }
 
-#ifdef HAVE_GLIBC_BACKTRACE
-
-/* This function is used only in zlog_backtrace_sigsafe when glibc
-   backtraces are available. */
 static char *
 hex_append(char *s, int len, u_long x)
 {
@@ -199,8 +195,6 @@
   return str_append(s,len,t);
 }
 
-#endif /* HAVE_GLIBC_BACKTRACE */
-
 static int syslog_fd = -1;
 
 /* Needs to be enhanced to support Solaris. */
@@ -264,10 +258,11 @@
 
 /* Note: the goal here is to use only async-signal-safe functions. */
 void
-zlog_signal(int signo, const char *action)
+zlog_signal(int signo, const char *action, siginfo_t *siginfo,
+	    void *program_counter)
 {
   time_t now;
-  char buf[sizeof("DEFAULT: Received signal S at T; aborting...")+60];
+  char buf[sizeof("DEFAULT: Received signal S at T (si_addr 0xP, PC 0xP); aborting...")+100];
   char *s = buf;
   char *msgstart = buf;
 #define LOC s,buf+sizeof(buf)-s
@@ -284,7 +279,14 @@
   s = num_append(LOC,signo);
   s = str_append(LOC," at ");
   s = num_append(LOC,now);
-  s = str_append(LOC,"; ");
+  s = str_append(LOC," (si_addr 0x");
+  s = hex_append(LOC,(u_long)(siginfo->si_addr));
+  if (program_counter)
+    {
+      s = str_append(LOC,", PC 0x");
+      s = hex_append(LOC,(u_long)program_counter);
+    }
+  s = str_append(LOC,"); ");
   s = str_append(LOC,action);
   if (s < buf+sizeof(buf))
     *s++ = '\n';
diff --git a/lib/log.h b/lib/log.h
index 1f9f23c..b828829 100644
--- a/lib/log.h
+++ b/lib/log.h
@@ -1,5 +1,5 @@
 /*
- * $Id: log.h,v 1.14 2004/12/07 15:39:32 ajs Exp $
+ * $Id: log.h,v 1.15 2005/01/12 17:27:27 ajs Exp $
  *
  * Zebra logging funcions.
  * Copyright (C) 1997, 1998, 1999 Kunihiro Ishiguro
@@ -153,7 +153,8 @@
 extern const char *safe_strerror(int errnum);
 
 /* To be called when a fatal signal is caught. */
-extern void zlog_signal(int signo, const char *action);
+extern void zlog_signal(int signo, const char *action,
+			siginfo_t *siginfo, void *program_counter);
 
 /* Log a backtrace. */
 extern void zlog_backtrace(int priority);
diff --git a/lib/sigevent.c b/lib/sigevent.c
index 5ac226a..7acdad2 100644
--- a/lib/sigevent.c
+++ b/lib/sigevent.c
@@ -23,6 +23,15 @@
 #include <sigevent.h>
 #include <log.h>
 
+#ifdef HAVE_UCONTEXT_H
+#ifdef GNU_LINUX
+/* get REG_EIP from ucontext.h */
+#define __USE_GNU
+#endif /* GNU_LINUX */
+#include <ucontext.h>
+#endif /* HAVE_UCONTEXT_H */
+
+
 /* master signals descriptor struct */
 struct quagga_sigevent_master_t
 {
@@ -124,7 +133,7 @@
 #endif /* SIGEVENT_SCHEDULE_THREAD */
 
 /* Initialization of signal handles. */
-/* Signale wrapper. */
+/* Signal wrapper. */
 static int
 signal_set (int signo)
 {
@@ -152,17 +161,33 @@
     return 0;
 }
 
-static void
-exit_handler(int signo)
+/* XXX This function should be enhanced to support more platforms
+       (it currently works only on Linux/x86). */
+static void *
+program_counter(void *context)
 {
-  zlog_signal(signo,"exiting...");
+#ifdef HAVE_UCONTEXT_H
+#ifdef GNU_LINUX
+#ifdef REG_EIP
+  if (context)
+    return (void *)(((ucontext_t *)context)->uc_mcontext.gregs[REG_EIP]);
+#endif /* REG_EIP */
+#endif /* GNU_LINUX */
+#endif /* HAVE_UCONTEXT_H */
+  return NULL;
+}
+
+static void
+exit_handler(int signo, siginfo_t *siginfo, void *context)
+{
+  zlog_signal(signo, "exiting...", siginfo, program_counter(context));
   _exit(128+signo);
 }
 
 static void
-core_handler(int signo)
+core_handler(int signo, siginfo_t *siginfo, void *context)
 {
-  zlog_signal(signo,"aborting...");
+  zlog_signal(signo, "aborting...", siginfo, program_counter(context));
   abort();
 }
 
@@ -211,11 +236,11 @@
   static const struct {
     const int *sigs;
     u_int nsigs;
-    void (*handler)(int);
+    void (*handler)(int signo, siginfo_t *info, void *context);
   } sigmap[] = {
-    { core_signals, sizeof(core_signals)/sizeof(core_signals[0]),core_handler },
-    { exit_signals, sizeof(exit_signals)/sizeof(exit_signals[0]),exit_handler },
-    { ignore_signals, sizeof(ignore_signals)/sizeof(ignore_signals[0]),SIG_IGN},
+    { core_signals, sizeof(core_signals)/sizeof(core_signals[0]), core_handler},
+    { exit_signals, sizeof(exit_signals)/sizeof(exit_signals[0]), exit_handler},
+    { ignore_signals, sizeof(ignore_signals)/sizeof(ignore_signals[0]), NULL},
   };
   u_int i;
 
@@ -230,9 +255,18 @@
 	      (oact.sa_handler == SIG_DFL))
 	    {
 	      struct sigaction act;
-	      act.sa_handler = sigmap[i].handler;
 	      sigfillset (&act.sa_mask);
-	      act.sa_flags = 0;
+	      if (sigmap[i].handler == NULL)
+	        {
+		  act.sa_handler = SIG_IGN;
+		  act.sa_flags = 0;
+	        }
+	      else
+	        {
+		  /* Request extra arguments to signal handler. */
+		  act.sa_sigaction = sigmap[i].handler;
+		  act.sa_flags = SA_SIGINFO;
+	        }
 	      if (sigaction(sigmap[i].sigs[j],&act,NULL) < 0)
 	        zlog_warn("Unable to set signal handler for signal %d: %s",
 			  sigmap[i].sigs[j],safe_strerror(errno));