This is the mail archive of the libc-hacker@sources.redhat.com mailing list for the glibc project.

Note that libc-hacker is a closed list. You may look at the archives of this list, but subscription and posting are not open.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Use backtrace(3) in libSegFault.so, register dumping on ia64


Hi!

The first change is using backtrace (3) instead of doing the backtrace
by hand.  The disadvantage is that at most 256 frames will be printed,
not more as before, the advantage is that ia64, x86-64, s390* start
working.

The other change is a REGISTER_DUMP implementation for ia64.
I chose to print only registers that kernel actually fills in in
setup_sigcontext.

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.

--- libc/sysdeps/unix/sysv/linux/ia64/bits/sigcontext.h.jj	2003-11-29 10:20:18.000000000 +0100
+++ libc/sysdeps/unix/sysv/linux/ia64/bits/sigcontext.h	2004-10-12 17:01:10.749786149 +0200
@@ -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 */
 
--- libc/sysdeps/unix/sysv/linux/ia64/register-dump.h.jj	2004-10-12 17:08:39.000000000 +0200
+++ libc/sysdeps/unix/sysv/linux/ia64/register-dump.h	2004-10-12 20:08:16.930645446 +0200
@@ -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)
--- libc/sysdeps/unix/sysv/linux/ia64/sigcontextinfo.h.jj	2002-07-27 10:41:38.000000000 +0200
+++ libc/sysdeps/unix/sysv/linux/ia64/sigcontextinfo.h	2004-10-12 18:28:06.000000000 +0200
@@ -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)
 
--- libc/sysdeps/generic/segfault.c.jj	2004-01-27 15:44:25.000000000 +0100
+++ libc/sysdeps/generic/segfault.c	2004-10-12 17:07:22.000000000 +0200
@@ -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 c
 
   WRITE_STRING ("\nBacktrace:\n");
 
-  top_frame = GET_FRAME (ctx);
-  top_stack = GET_STACK (ctx);
-
-  /* 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);
-    }
-
-  /* If the last return address was NULL, assume that it doesn't count.  */
-  if (arr[cnt-1] == NULL)
-    cnt--;
+  /* Get the backtrace.  */
+  arr = alloca (256 * sizeof (void *));
+  cnt = backtrace (arr, 256);
+
+  /* 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 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.  */

	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]