diff options
author | Ulrich Drepper <drepper@redhat.com> | 2004-10-14 02:24:44 +0000 |
---|---|---|
committer | Ulrich Drepper <drepper@redhat.com> | 2004-10-14 02:24:44 +0000 |
commit | c701ab9f0e231592427e0602431d4156a21d4afd (patch) | |
tree | 84d8b777f95f0e47178ab5946e9b25181b393b47 /sysdeps | |
parent | c0f62c56788c48b9fb36dc609c0a9f9db3667306 (diff) | |
download | glibc-c701ab9f0e231592427e0602431d4156a21d4afd.tar glibc-c701ab9f0e231592427e0602431d4156a21d4afd.tar.gz glibc-c701ab9f0e231592427e0602431d4156a21d4afd.tar.bz2 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.c | 88 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/ia64/bits/sigcontext.h | 5 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/ia64/register-dump.h | 182 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/ia64/sigcontextinfo.h | 4 |
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) |