about summary refs log tree commit diff
path: root/sysdeps
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2004-10-14 02:24:44 +0000
committerUlrich Drepper <drepper@redhat.com>2004-10-14 02:24:44 +0000
commitc701ab9f0e231592427e0602431d4156a21d4afd (patch)
tree84d8b777f95f0e47178ab5946e9b25181b393b47 /sysdeps
parentc0f62c56788c48b9fb36dc609c0a9f9db3667306 (diff)
downloadglibc-c701ab9f0e231592427e0602431d4156a21d4afd.tar.gz
glibc-c701ab9f0e231592427e0602431d4156a21d4afd.tar.xz
glibc-c701ab9f0e231592427e0602431d4156a21d4afd.zip
2004-10-12  Jakub Jelinek  <jakub@redhat.com>

	* sysdeps/generic/segfault.c: Include alloca.h and stdint.h.
	Don't include frame.h.
	(CURRENT_STACK_FRAME, INNER_THAN, ADVANCE_STACK_FRAME): Remove.
	(catch_segfault): Use backtrace function.

	* sysdeps/unix/sysv/linux/ia64/bits/sigcontext.h: Fix comment.
	* sysdeps/unix/sysv/linux/ia64/register-dump.h: New file.
	* sysdeps/unix/sysv/linux/ia64/sigcontextinfo.h (GET_PC): Return sc_ip
	field.
Diffstat (limited to 'sysdeps')
-rw-r--r--sysdeps/generic/segfault.c88
-rw-r--r--sysdeps/unix/sysv/linux/ia64/bits/sigcontext.h5
-rw-r--r--sysdeps/unix/sysv/linux/ia64/register-dump.h182
-rw-r--r--sysdeps/unix/sysv/linux/ia64/sigcontextinfo.h4
4 files changed, 207 insertions, 72 deletions
diff --git a/sysdeps/generic/segfault.c b/sysdeps/generic/segfault.c
index 47f2447169..f141fff661 100644
--- a/sysdeps/generic/segfault.c
+++ b/sysdeps/generic/segfault.c
@@ -19,11 +19,13 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
+#include <alloca.h>
 #include <ctype.h>
 #include <errno.h>
 #include <execinfo.h>
 #include <fcntl.h>
 #include <signal.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -33,9 +35,6 @@
 
 #include <bp-checks.h>
 
-/* Get the definition of "struct layout".  */
-#include <frame.h>
-
 /* This file defines macros to access the content of the sigcontext element
    passed up by the signal handler.  */
 #include <sigcontextinfo.h>
@@ -43,35 +42,6 @@
 /* Get code to possibly dump the content of all registers.  */
 #include <register-dump.h>
 
-/* This implementation assumes a stack layout that matches the defaults
-   used by gcc's `__builtin_frame_address' and `__builtin_return_address'
-   (FP is the frame pointer register):
-
-	  +-----------------+     +-----------------+
-    FP -> | previous FP --------> | previous FP ------>...
-	  |                 |     |                 |
-	  | return address  |     | return address  |
-	  +-----------------+     +-----------------+
-
-  */
-
-/* Get some notion of the current stack.  Need not be exactly the top
-   of the stack, just something somewhere in the current frame.  */
-#ifndef CURRENT_STACK_FRAME
-# define CURRENT_STACK_FRAME  ({ char __csf; &__csf; })
-#endif
-
-/* By default we assume that the stack grows downward.  */
-#ifndef INNER_THAN
-# define INNER_THAN <
-#endif
-
-/* By default assume the `next' pointer in struct layout points to the
-   next struct layout.  */
-#ifndef ADVANCE_STACK_FRAME
-# define ADVANCE_STACK_FRAME(next) BOUNDED_1 ((struct layout *) (next))
-#endif
-
 /* We'll use tis a lot.  */
 #define WRITE_STRING(s) write (fd, s, strlen (s))
 
@@ -102,13 +72,10 @@ write_strsignal (int fd, int signal)
 static void
 catch_segfault (int signal, SIGCONTEXT ctx)
 {
-  struct layout *current;
-  void *__unbounded top_frame;
-  void *__unbounded top_stack;
-  int fd;
+  int fd, cnt, i;
   void **arr;
-  size_t cnt;
   struct sigaction sa;
+  uintptr_t pc;
 
   /* This is the name of the file we are writing to.  If none is given
      or we cannot write to this file write to stderr.  */
@@ -130,41 +97,26 @@ catch_segfault (int signal, SIGCONTEXT ctx)
 
   WRITE_STRING ("\nBacktrace:\n");
 
-  top_frame = GET_FRAME (ctx);
-  top_stack = GET_STACK (ctx);
+  /* Get the backtrace.  */
+  arr = alloca (256 * sizeof (void *));
+  cnt = backtrace (arr, 256);
 
-  /* First count how many entries we'll have.  */
-  cnt = 1;
-  current = BOUNDED_1 ((struct layout *) top_frame);
-  while (!((void *) current INNER_THAN top_stack
-	   || !((void *) current INNER_THAN __libc_stack_end)))
-    {
-      ++cnt;
-
-      current = ADVANCE_STACK_FRAME (current->next);
-    }
-
-  arr = alloca (cnt * sizeof (void *));
-
-  /* First handle the program counter from the structure.  */
-  arr[0] = GET_PC (ctx);
-
-  current = BOUNDED_1 ((struct layout *) top_frame);
-  cnt = 1;
-  while (!((void *) current INNER_THAN top_stack
-	   || !((void *) current INNER_THAN __libc_stack_end)))
-    {
-      arr[cnt++] = current->return_address;
-
-      current = ADVANCE_STACK_FRAME (current->next);
-    }
+  /* Now try to locate the PC from signal context in the backtrace.
+     Normally it will be found at arr[2], but it might appear later
+     if there were some signal handler wrappers.  Allow a few bytes
+     difference to cope with as many arches as possible.  */
+  pc = (uintptr_t) GET_PC (ctx);
+  for (i = 0; i < cnt; ++i)
+    if ((uintptr_t) arr[i] >= pc - 16 && (uintptr_t) arr[i] <= pc + 16)
+      break;
 
-  /* If the last return address was NULL, assume that it doesn't count.  */
-  if (arr[cnt-1] == NULL)
-    cnt--;
+  /* If we haven't found it, better dump full backtrace even including
+     the signal handler frames instead of not dumping anything.  */
+  if (i == cnt)
+    i = 0;
 
   /* Now generate nicely formatted output.  */
-  __backtrace_symbols_fd (arr, cnt, fd);
+  __backtrace_symbols_fd (arr + i, cnt - i, fd);
 
 #ifdef HAVE_PROC_SELF
   /* Now the link map.  */
diff --git a/sysdeps/unix/sysv/linux/ia64/bits/sigcontext.h b/sysdeps/unix/sysv/linux/ia64/bits/sigcontext.h
index 61eb67c075..72c60ec240 100644
--- a/sysdeps/unix/sysv/linux/ia64/bits/sigcontext.h
+++ b/sysdeps/unix/sysv/linux/ia64/bits/sigcontext.h
@@ -1,4 +1,5 @@
-/* Copyright (C) 1996, 1997, 1998, 2000, 2001, 2003 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998, 2000, 2001, 2003, 2004
+   Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Jes Sorensen <jes@linuxcare.com>, July 2000
 
@@ -36,7 +37,7 @@ struct ia64_fpreg
 
 struct sigcontext
 {
-  unsigned long int sc_flags;	/* see manifest constants above */
+  unsigned long int sc_flags;	/* see manifest constants below */
   unsigned long int sc_nat;	/* bit i == 1 iff scratch reg gr[i] is a NaT */
   stack_t sc_stack;		/* previously active stack */
 
diff --git a/sysdeps/unix/sysv/linux/ia64/register-dump.h b/sysdeps/unix/sysv/linux/ia64/register-dump.h
new file mode 100644
index 0000000000..513db974f8
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/ia64/register-dump.h
@@ -0,0 +1,182 @@
+/* Dump registers.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2004.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <string.h>
+#include <sys/uio.h>
+#include <stdio-common/_itoa.h>
+
+/* We will print the register dump in this format:
+
+ GP:   XXXXXXXXXXXXXXXX R2:   XXXXXXXXXXXXXXXX R3:   XXXXXXXXXXXXXXXX
+ R8:   XXXXXXXXXXXXXXXX R9:   XXXXXXXXXXXXXXXX R10:  XXXXXXXXXXXXXXXX
+ R11:  XXXXXXXXXXXXXXXX SP:   XXXXXXXXXXXXXXXX TP:   XXXXXXXXXXXXXXXX
+ R14:  XXXXXXXXXXXXXXXX R15:  XXXXXXXXXXXXXXXX R16:  XXXXXXXXXXXXXXXX
+ R17:  XXXXXXXXXXXXXXXX R18:  XXXXXXXXXXXXXXXX R19:  XXXXXXXXXXXXXXXX
+ R20:  XXXXXXXXXXXXXXXX R21:  XXXXXXXXXXXXXXXX R22:  XXXXXXXXXXXXXXXX
+ R23:  XXXXXXXXXXXXXXXX R24:  XXXXXXXXXXXXXXXX R25:  XXXXXXXXXXXXXXXX
+ R26:  XXXXXXXXXXXXXXXX R27:  XXXXXXXXXXXXXXXX R28:  XXXXXXXXXXXXXXXX
+ R29:  XXXXXXXXXXXXXXXX R30:  XXXXXXXXXXXXXXXX R31:  XXXXXXXXXXXXXXXX
+
+ RP:   XXXXXXXXXXXXXXXX B6:   XXXXXXXXXXXXXXXX B7:   XXXXXXXXXXXXXXXX
+
+ IP:   XXXXXXXXXXXXXXXX RSC:  XXXXXXXXXXXXXXXX PR:   XXXXXXXXXXXXXXXX
+ PFS:  XXXXXXXXXXXXXXXX UNAT: XXXXXXXXXXXXXXXX CFM:  XXXXXXXXXXXXXXXX
+ CCV:  XXXXXXXXXXXXXXXX FPSR: XXXXXXXXXXXXXXXX
+
+ F32:  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX F33:  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+ F34:  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX F35:  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+...
+ F124: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX F125: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+ F126: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX F127: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+ */
+
+static void
+hexvalue (unsigned long int value, char *buf, size_t len)
+{
+  char *cp = _itoa_word (value, buf + len, 16, 0);
+  while (cp > buf)
+    *--cp = '0';
+}
+
+static void
+regvalue (unsigned long int *value, char letter, int regno, char *buf)
+{
+  int n = regno >= 100 ? 3 : regno >= 10 ? 2 : 1;
+  buf[0] = ' ';
+  buf[1] = letter;
+  _itoa_word (regno, buf + 2 + n, 10, 0);
+  buf[2 + n] = ':';
+  for (++n; n <= 4; ++n)
+    buf[2 + n] = ' ';
+  hexvalue (value[0], buf + 7, 16);
+  if (letter == 'F')
+    {
+      hexvalue (value[1], buf + 7 + 16, 16);
+      buf[7 + 32] = '\n';
+    }
+  else
+    buf[7 + 16] = '\n';
+}
+
+static void
+register_dump (int fd, struct sigcontext *ctx)
+{
+  char gpregs[32 - 5][8 + 16];
+  char fpregs[128 - 32][8 + 32];
+  char bpregs[3][8 + 16];
+  char spregs[8][16];
+  struct iovec iov[146];
+  size_t nr = 0;
+  int i;
+
+#define ADD_STRING(str) \
+  do									      \
+    {									      \
+      iov[nr].iov_base = (char *) str;					      \
+      iov[nr].iov_len = strlen (str);					      \
+      ++nr;								      \
+    }									      \
+  while (0)
+#define ADD_MEM(str, len) \
+  do									      \
+    {									      \
+      iov[nr].iov_base = str;						      \
+      iov[nr].iov_len = len;						      \
+      ++nr;								      \
+    }									      \
+  while (0)
+
+  /* Generate strings of register contents.  */
+  for (i = 1; i < 4; ++i)
+    {
+      regvalue (&ctx->sc_gr[i], 'R', i, gpregs[i - 1]);
+      if (ctx->sc_nat & (1L << i))
+        memcpy (gpregs[i - 1] + 7, "NaT             ", 16);
+    }
+  for (i = 8; i < 32; ++i)
+    {
+      regvalue (&ctx->sc_gr[i], 'R', i, gpregs[i - 5]);
+      if (ctx->sc_nat & (1L << i))
+        memcpy (gpregs[i - 1] + 7, "NaT             ", 16);
+    }
+  memcpy (gpregs[0] + 1, "GP:", 3);
+  memcpy (gpregs[7] + 1, "SP: ", 4);
+  memcpy (gpregs[8] + 1, "TP: ", 4);
+
+  regvalue (&ctx->sc_br[0], 'B', 0, bpregs[0]);
+  regvalue (&ctx->sc_br[6], 'B', 6, bpregs[1]);
+  regvalue (&ctx->sc_br[7], 'B', 7, bpregs[2]);
+  memcpy (bpregs[0] + 1, "RP:", 3);
+
+  if (ctx->sc_flags & IA64_SC_FLAG_FPH_VALID)
+    for (i = 32; i < 128; ++i)
+      regvalue (&ctx->sc_fr[i].u.bits[0], 'F', i, fpregs[i - 32]);
+
+  hexvalue (ctx->sc_ip, spregs[0], sizeof (spregs[0]));
+  hexvalue (ctx->sc_ar_rsc, spregs[1], sizeof (spregs[1]));
+  hexvalue (ctx->sc_pr, spregs[2], sizeof (spregs[2]));
+  hexvalue (ctx->sc_ar_pfs, spregs[3], sizeof (spregs[3]));
+  hexvalue (ctx->sc_ar_unat, spregs[4], sizeof (spregs[4]));
+  hexvalue (ctx->sc_cfm, spregs[5], sizeof (spregs[5]));
+  hexvalue (ctx->sc_ar_ccv, spregs[6], sizeof (spregs[6]));
+  hexvalue (ctx->sc_ar_fpsr, spregs[7], sizeof (spregs[7]));
+
+  /* Generate the output.  */
+  ADD_STRING ("Register dump:\n\n");
+
+  for (i = 0; i < 32 - 5; ++i)
+    ADD_MEM (gpregs[i], sizeof (gpregs[0]) - 1 + ((i % 3) == 2));
+  ADD_STRING ("\n");
+
+  for (i = 0; i < 3; ++i)
+    ADD_MEM (bpregs[i], sizeof (bpregs[0]) - 1);
+    
+  ADD_STRING ("\n\n IP:   ");
+  ADD_MEM (spregs[0], sizeof (spregs[0]));
+  ADD_STRING (" RSC:  ");
+  ADD_MEM (spregs[1], sizeof (spregs[0]));
+  ADD_STRING (" PR:   ");
+  ADD_MEM (spregs[2], sizeof (spregs[0]));
+  ADD_STRING ("\n PFS:  ");
+  ADD_MEM (spregs[3], sizeof (spregs[0]));
+  ADD_STRING (" UNAT: ");
+  ADD_MEM (spregs[4], sizeof (spregs[0]));
+  ADD_STRING (" CFM:  ");
+  ADD_MEM (spregs[5], sizeof (spregs[0]));
+  ADD_STRING ("\n CCV:  ");
+  ADD_MEM (spregs[6], sizeof (spregs[0]));
+  ADD_STRING (" FPSR: ");
+  ADD_MEM (spregs[7], sizeof (spregs[0]));
+  ADD_STRING ("\n");
+
+  if (ctx->sc_flags & IA64_SC_FLAG_FPH_VALID)
+    {
+      ADD_STRING ("\n");
+
+      for (i = 0; i < 128 - 32; ++i)
+        ADD_MEM (fpregs[i], sizeof (fpregs[0]) - 1 + (i & 1));
+    }
+
+  /* Write the stuff out.  */
+  writev (fd, iov, nr);
+}
+
+
+#define REGISTER_DUMP register_dump (fd, ctx)
diff --git a/sysdeps/unix/sysv/linux/ia64/sigcontextinfo.h b/sysdeps/unix/sysv/linux/ia64/sigcontextinfo.h
index b5ce1d9108..51c11e6b46 100644
--- a/sysdeps/unix/sysv/linux/ia64/sigcontextinfo.h
+++ b/sysdeps/unix/sysv/linux/ia64/sigcontextinfo.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2004 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -18,7 +18,7 @@
 
 #define SIGCONTEXT siginfo_t *_si, struct sigcontext *
 #define SIGCONTEXT_EXTRA_ARGS _si,
-#define GET_PC(ctx)	((void *) 0)
+#define GET_PC(ctx)	((ctx)->sc_ip)
 #define GET_FRAME(ctx)	((void *) 0)
 #define GET_STACK(ctx)	((void *) 0)