This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Re: add support for `S´ augmentation in dwarf2 debug info
- From: Mark Kettenis <mark dot kettenis at xs4all dot nl>
- To: aoliva at redhat dot com
- Cc: gdb-patches at sources dot redhat dot com
- Date: Sat, 4 Mar 2006 11:39:13 +0100 (CET)
- Subject: Re: add support for `S´ augmentation in dwarf2 debug info
- References: <orbqwnpne4.fsf@free.oliva.athome.lsd.ic.unicamp.br>
> From: Alexandre Oliva <aoliva@redhat.com>
> Date: Fri, 03 Mar 2006 12:18:43 -0300
>
> --=-=-=
> Content-Type: text/plain; charset=iso-8859-1
> Content-Transfer-Encoding: quoted-printable
>
> Jakub Jelinek has recently introduced support in GCC for unwinding
> frames with the `S=B4 augmentation, used to denote signal stack frames.
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=3D26208
>
> Although GDB already does a lot of grunt work in recognizing signal
> stack frames to avoid the same kind of unwinding problem, it could
> take advantage of this to (a) remove machine-specific code that does
> so, when the augmentation is widely available, and (b) speed up
> recognizing such frames when it is only partially available.
Hmm, removing the machine-specific code won't be possible for quite a
long time I think, but it certainly isolates us from changes made to
the signal trampolines in glibc.
> This patch introduces code to recognize and take advantage of the "S"
> augmentation, but makes no effort to remove existing machine-specific
> code. The testcase probably already worked without the change, but
> it's good to have it there to avoid regressions when someone decides
> to experiment with taking code out.
>
> Ok to install? Tested on amd64-linux-gnu.
Hmm, I'm wondering whether we should give saw_z_augmentation a more
meaningful name too (not sure if there is one though).
Here it the testcases are really Linux-specific (and yuck, that i386
sigaction hack is ugly). Hopefully they're not too fragile. Could
you please change bug-gdb@prep.ai.mit.edu into bug-gdb@gnu.org before
checking this in?
Thanks,
Mark
> for gdb/ChangeLog
> from Alexandre Oliva <aoliva@redhat.com>
>
> * dwarf2-frame.c (struct dwarf2_cie): Add signal_frame field.
> (dwarf2_frame_sniffer): Use it.
> (decode_frame_entry_1): Set it according to augmentation "S".
>
> for gdb/testsuite/ChangeLog
> from Alexandre Oliva <aoliva@redhat.com>
>
> * gdb.dwarf2/signal-augm.exp: New test.
> * gdb.dwarf2/signal-augm.c, gdb.dwarf2/signal-augm.S: Its sources.
>
> Index: gdb/dwarf2-frame.c
> ===================================================================
> --- gdb/dwarf2-frame.c.orig 2006-03-03 11:51:41.000000000 -0300
> +++ gdb/dwarf2-frame.c 2006-03-03 11:57:45.000000000 -0300
> @@ -69,6 +69,9 @@ struct dwarf2_cie
> /* True if a 'z' augmentation existed. */
> unsigned char saw_z_augmentation;
>
> + /* True if an 'S' augmentation existed. */
> + unsigned char signal_frame;
> +
> struct dwarf2_cie *next;
> };
>
> @@ -1032,15 +1035,17 @@ dwarf2_frame_sniffer (struct frame_info
> function. frame_pc_unwind(), for a no-return next function, can
> end up returning something past the end of this function's body. */
> CORE_ADDR block_addr = frame_unwind_address_in_block (next_frame);
> - if (!dwarf2_frame_find_fde (&block_addr))
> + struct dwarf2_fde *fde = dwarf2_frame_find_fde (&block_addr);
> + if (!fde)
> return NULL;
>
> /* On some targets, signal trampolines may have unwind information.
> We need to recognize them so that we set the frame type
> correctly. */
>
> - if (dwarf2_frame_signal_frame_p (get_frame_arch (next_frame),
> - next_frame))
> + if (fde->cie->signal_frame
> + || dwarf2_frame_signal_frame_p (get_frame_arch (next_frame),
> + next_frame))
> return &dwarf2_signal_frame_unwind;
>
> return &dwarf2_frame_unwind;
> @@ -1500,6 +1505,10 @@ decode_frame_entry_1 (struct comp_unit *
> depends on the target address size. */
> cie->encoding = DW_EH_PE_absptr;
>
> + /* We'll determine the final value later, but we need to
> + initialize it conservatively. */
> + cie->signal_frame = 0;
> +
> /* Check version number. */
> cie_version = read_1_byte (unit->abfd, buf);
> if (cie_version != 1 && cie_version != 3)
> @@ -1578,6 +1587,17 @@ decode_frame_entry_1 (struct comp_unit *
> augmentation++;
> }
>
> + /* "S" indicates a signal frame, such that the return
> + address must not be decremented to locate the call frame
> + info for the previous frame; it might even be the first
> + instruction of a function, so decrementing it would take
> + us to a different function. */
> + else if (*augmentation == 'S')
> + {
> + cie->signal_frame = 1;
> + augmentation++;
> + }
> +
> /* Otherwise we have an unknown augmentation.
> Bail out unless we saw a 'z' prefix. */
> else
> Index: gdb/testsuite/gdb.dwarf2/signal-augm.S
> ===================================================================
> --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> +++ gdb/testsuite/gdb.dwarf2/signal-augm.S 2006-03-03 11:57:45.000000000 -0300
> @@ -0,0 +1,207 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> + Copyright 2006 Free Software Foundation, Inc.
> +
> + This program is free software; you can redistribute it and/or modify
> + it under the terms of the GNU General Public License as published by
> + the Free Software Foundation; either version 2 of the License, or
> + (at your option) any later version.
> +
> + This program 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 General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program; if not, write to the Free Software
> + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
> +
> + Written by Jakub Jelinek, as testcase for GCC PR 26208. */
> +
> + .globl fn3
> + .type fn3, @function
> +#ifdef __powerpc64__
> + .section ".opd","aw"
> + .align 3
> +fn3:
> + .quad .L.fn3,.TOC.@tocbase,0
> + .text
> +.L.fn3:
> +#else
> + .text
> + .p2align 4,,15
> +fn3:
> +#endif
> + .cfi_startproc
> +#if defined __x86_64__
> + movl $10, %eax
> + movl $11, %ecx
> +1: pushq %rax
> + .cfi_adjust_cfa_offset 8
> + pushq %rcx
> + .cfi_adjust_cfa_offset 8
> + popq %rax
> + .cfi_adjust_cfa_offset -8
> + popq %rcx
> + .cfi_adjust_cfa_offset -8
> + pushq %rax
> + .cfi_adjust_cfa_offset 8
> + pushq %rcx
> + .cfi_adjust_cfa_offset 8
> + popq %rax
> + .cfi_adjust_cfa_offset -8
> + popq %rcx
> + .cfi_adjust_cfa_offset -8
> + pushq %rax
> + .cfi_adjust_cfa_offset 8
> + pushq %rcx
> + .cfi_adjust_cfa_offset 8
> + popq %rax
> + .cfi_adjust_cfa_offset -8
> + popq %rcx
> + .cfi_adjust_cfa_offset -8
> + pushq %rax
> + .cfi_adjust_cfa_offset 8
> + pushq %rcx
> + .cfi_adjust_cfa_offset 8
> + popq %rax
> + .cfi_adjust_cfa_offset -8
> + popq %rcx
> + .cfi_adjust_cfa_offset -8
> + jmp 1b
> +#elif defined __i386__
> + movl $10, %eax
> + movl $11, %ecx
> +1: pushl %eax
> + .cfi_adjust_cfa_offset 4
> + pushl %ecx
> + .cfi_adjust_cfa_offset 4
> + popl %eax
> + .cfi_adjust_cfa_offset -4
> + popl %ecx
> + .cfi_adjust_cfa_offset -4
> + pushl %eax
> + .cfi_adjust_cfa_offset 4
> + pushl %ecx
> + .cfi_adjust_cfa_offset 4
> + popl %eax
> + .cfi_adjust_cfa_offset -4
> + popl %ecx
> + .cfi_adjust_cfa_offset -4
> + pushl %eax
> + .cfi_adjust_cfa_offset 4
> + pushl %ecx
> + .cfi_adjust_cfa_offset 4
> + popl %eax
> + .cfi_adjust_cfa_offset -4
> + popl %ecx
> + .cfi_adjust_cfa_offset -4
> + pushl %eax
> + .cfi_adjust_cfa_offset 4
> + pushl %ecx
> + .cfi_adjust_cfa_offset 4
> + popl %eax
> + .cfi_adjust_cfa_offset -4
> + popl %ecx
> + .cfi_adjust_cfa_offset -4
> + jmp 1b
> +#elif defined __powerpc64__
> + mflr 0
> + mr 9,1
> + std 0,16(1)
> + .cfi_offset lr, 8
> + bl 1f
> +1: stdu 1,-64(1)
> + .cfi_adjust_cfa_offset 64
> + stdu 9,-64(1)
> + .cfi_adjust_cfa_offset 64
> + addi 1,1,64
> + .cfi_adjust_cfa_offset -64
> + addi 1,1,64
> + .cfi_adjust_cfa_offset -64
> + stdu 1,-64(1)
> + .cfi_adjust_cfa_offset 64
> + stdu 9,-64(1)
> + .cfi_adjust_cfa_offset 64
> + addi 1,1,64
> + .cfi_adjust_cfa_offset -64
> + addi 1,1,64
> + .cfi_adjust_cfa_offset -64
> + b 1b
> +#elif defined __powerpc__
> + mflr 0
> + mr 9,1
> + stwu 1,-16(1)
> + .cfi_adjust_cfa_offset 16
> + stw 0,20(1)
> + .cfi_offset lr, 4
> + bl 1f
> +1: stwu 9,-64(1)
> + .cfi_adjust_cfa_offset 64
> + stwu 9,-64(1)
> + .cfi_adjust_cfa_offset 64
> + addi 1,1,64
> + .cfi_adjust_cfa_offset -64
> + addi 1,1,64
> + .cfi_adjust_cfa_offset -64
> + stwu 9,-64(1)
> + .cfi_adjust_cfa_offset 64
> + stwu 9,-64(1)
> + .cfi_adjust_cfa_offset 64
> + addi 1,1,64
> + .cfi_adjust_cfa_offset -64
> + addi 1,1,64
> + .cfi_adjust_cfa_offset -64
> + b 1b
> +#elif defined __s390x__
> + stmg %r14,%r15,112(%r15)
> + .cfi_offset %r14, -48
> + .cfi_offset %r15, -40
> + lghi %r14,6
> +1: aghi %r15,-160
> + .cfi_adjust_cfa_offset 160
> + aghi %r15,-160
> + .cfi_adjust_cfa_offset 160
> + aghi %r15,160
> + .cfi_adjust_cfa_offset -160
> + aghi %r15,160
> + .cfi_adjust_cfa_offset -160
> + aghi %r15,-160
> + .cfi_adjust_cfa_offset 160
> + aghi %r15,-160
> + .cfi_adjust_cfa_offset 160
> + aghi %r15,160
> + .cfi_adjust_cfa_offset -160
> + aghi %r15,160
> + .cfi_adjust_cfa_offset -160
> + j 1b
> +#elif defined __s390__
> + stm %r14,%r15,56(%r15)
> + .cfi_offset %r14, -40
> + .cfi_offset %r15, -36
> + lgi %r14,6
> +1: ahi %r15,-96
> + .cfi_adjust_cfa_offset 96
> + ahi %r15,-96
> + .cfi_adjust_cfa_offset 96
> + ahi %r15,96
> + .cfi_adjust_cfa_offset -96
> + ahi %r15,96
> + .cfi_adjust_cfa_offset -96
> + ahi %r15,-96
> + .cfi_adjust_cfa_offset 96
> + ahi %r15,-96
> + .cfi_adjust_cfa_offset 96
> + ahi %r15,96
> + .cfi_adjust_cfa_offset -96
> + ahi %r15,96
> + .cfi_adjust_cfa_offset -96
> + j 1b
> +#endif
> + .cfi_endproc
> +#ifdef __powerpc64__
> + .size fn3, . - .L.fn3
> +#else
> + .size fn3, .-fn3
> +#endif
> + .section .note.GNU-stack,"",@progbits
> Index: gdb/testsuite/gdb.dwarf2/signal-augm.c
> ===================================================================
> --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> +++ gdb/testsuite/gdb.dwarf2/signal-augm.c 2006-03-03 11:57:45.000000000 -0300
> @@ -0,0 +1,198 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> + Copyright 2006 Free Software Foundation, Inc.
> +
> + This program is free software; you can redistribute it and/or modify
> + it under the terms of the GNU General Public License as published by
> + the Free Software Foundation; either version 2 of the License, or
> + (at your option) any later version.
> +
> + This program 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 General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program; if not, write to the Free Software
> + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
> +
> + Written by Jakub Jelinek, as testcase for GCC PR 26208. GDB does
> + not need all of it, since all we do is to try to recognize signal
> + stack frames. If the compiler does not support the S augmentation
> + used to denote stack frames, and GDB does not otherwise recognize
> + stack frames, the test fails. */
> +
> +#include <unwind.h>
> +#include <stdlib.h>
> +#include <signal.h>
> +#include <string.h>
> +#include <stdio.h>
> +#include <pthread.h>
> +#include <unistd.h>
> +#include <sys/wait.h>
> +#include <sys/syscall.h>
> +
> +static _Unwind_Reason_Code
> +force_unwind_stop (int version, _Unwind_Action actions,
> + _Unwind_Exception_Class exc_class,
> + struct _Unwind_Exception *exc_obj,
> + struct _Unwind_Context *context,
> + void *stop_parameter)
> +{
> + if (actions & _UA_END_OF_STACK)
> + abort ();
> + return _URC_NO_REASON;
> +}
> +
> +static void
> +force_unwind ()
> +{
> + struct _Unwind_Exception *exc = malloc (sizeof (*exc));
> + memset (&exc->exception_class, 0, sizeof (exc->exception_class));
> + exc->exception_cleanup = 0;
> +
> +#ifndef __USING_SJLJ_EXCEPTIONS__
> + _Unwind_ForcedUnwind (exc, force_unwind_stop, 0);
> +#else
> + _Unwind_SjLj_ForcedUnwind (exc, force_unwind_stop, 0);
> +#endif
> +
> + abort ();
> +}
> +
> +int count;
> +
> +static void
> +counter (void *p __attribute__((unused)))
> +{
> + ++count;
> +}
> +
> +static void
> +handler (void *p __attribute__((unused)))
> +{
> + if (count != 2)
> + abort ();
> + _exit (0);
> +}
> +
> +static int __attribute__((noinline))
> +fn5 (void)
> +{
> + char dummy __attribute__((cleanup (counter)));
> + force_unwind ();
> + return 0;
> +}
> +
> +static void
> +fn4 (int sig, siginfo_t *info, void *ctx)
> +{
> + char dummy __attribute__((cleanup (counter)));
> + fn5 ();
> +}
> +
> +extern void fn3 (long a, long b, long c, long d, long e, long f, long g);
> +
> +static int __attribute__((noinline))
> +fn2 (void)
> +{
> + fn3 (1, 2, 3, 4, 5, 6, 7);
> + return 0;
> +}
> +
> +static int __attribute__((noinline))
> +fn1 (void)
> +{
> +#if defined __i386__ && defined SIGACTION_DIRECT_SYSCALL
> + struct i386_kernel_sigaction
> + {
> + void (*k_sa_handler) (int, siginfo_t *, void *);
> + unsigned long k_sa_flags;
> + void (*sa_restorer) (void);
> + unsigned long long k_sa_mask;
> + } s;
> + extern void __cleanup12_rt_sigreturn (void);
> + s.k_sa_handler = fn4;
> + s.k_sa_mask = 0;
> + s.k_sa_flags = 0x4000000 | SA_RESETHAND | SA_SIGINFO;
> + s.sa_restorer = __cleanup12_rt_sigreturn;
> + asm volatile (".subsection 1; nop; __cleanup12_rt_sigreturn:"
> + "movl %0, %%eax; int $0x80; .previous"
> + : : "i" (__NR_rt_sigreturn));
> + syscall (SYS_rt_sigaction, SIGUSR1, &s, NULL, 8);
> +#else
> + struct sigaction s;
> + sigemptyset (&s.sa_mask);
> + s.sa_sigaction = fn4;
> + s.sa_flags = SA_RESETHAND | SA_SIGINFO;
> + sigaction (SIGUSR1, &s, NULL);
> +#endif
> + fn2 ();
> + return 0;
> +}
> +
> +static void *
> +tf (void *arg)
> +{
> + char dummy __attribute__((cleanup (handler)));
> + (void) arg;
> + fn1 ();
> + return 0;
> +}
> +
> +void
> +do_test (void)
> +{
> + pthread_t th;
> + struct timespec ts;
> + if (pthread_create (&th, 0, tf, 0))
> + {
> + fputs ("pthread_create failed\n", stderr);
> + _exit (1);
> + }
> + ts.tv_sec = 1;
> + ts.tv_nsec = 0;
> + nanosleep (&ts, NULL);
> + if (pthread_kill (th, SIGUSR1))
> + {
> + fputs ("pthread_kill failed\n", stderr);
> + _exit (1);
> + }
> + ts.tv_sec = 3;
> + ts.tv_nsec = 0;
> + nanosleep (&ts, NULL);
> + _exit (1);
> +}
> +
> +int
> +main (int argc, char **argv)
> +{
> + int i, failures = 0, status;
> + if (argc == 2 && strcmp (argv[1], "-d") == 0)
> + do_test ();
> + else
> + for (i = 0; i < 50; i++)
> + {
> + pid_t pid = fork ();
> + if (pid < 0)
> + {
> + perror ("fork");
> + failures++;
> + }
> + else if (pid == 0)
> + do_test ();
> + else if (waitpid (pid, &status, 0) < 0)
> + {
> + perror ("waitpid");
> + failures++;
> + }
> + else if (! WIFEXITED (status) || WEXITSTATUS (status))
> + {
> + fprintf (stderr, "Failure in round %d\n", i);
> + failures++;
> + }
> + }
> + if (failures)
> + abort ();
> + return 0;
> +}
> Index: gdb/testsuite/gdb.dwarf2/signal-augm.exp
> ===================================================================
> --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> +++ gdb/testsuite/gdb.dwarf2/signal-augm.exp 2006-03-03 12:08:40.000000000 -0300
> @@ -0,0 +1,77 @@
> +# Copyright 2006 Free Software Foundation, Inc.
> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 2 of the License, or
> +# (at your option) any later version.
> +#
> +# This program 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 General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program; if not, write to the Free Software
> +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
> +
> +# Please email any bugs, comments, and/or additions to this file to:
> +# bug-gdb@prep.ai.mit.edu
> +
> +# This file was written by Alexandre Oliva <aoliva@redhat.com>
> +
> +if $tracelevel then {
> + strace $tracelevel
> + }
> +
> +set prms_id 0
> +set bug_id 0
> +
> +# signal-augm.S needs hand-coded assembly
> +if {![istarget i*86-*-linux*]
> + && ![istarget x86_64-*-linux*]
> + && ![istarget powerpc*-*-linux*]
> + && ![istarget s390*-*-linux*]} {
> + return -1;
> +}
> +
> +if [get_compiler_info "ignored"] {
> + return -1
> +}
> +
> +if {$gcc_compiled == 0} {
> + return -1
> +}
> +
> +set testfile "signal-augm"
> +
> +set srcbasename ${srcdir}/${subdir}/${testfile}
> +set binfile ${objdir}/${subdir}/${testfile}
> +if { [gdb_compile "${srcbasename}.c ${srcbasename}.S" "${binfile}" executable [list debug "additional_flags=-pthread -fexceptions -fnon-call-exceptions -fasynchronous-unwind-tables -O2"]] != ""} {
> + return -1;
> +}
> +
> +gdb_exit
> +gdb_start
> +gdb_reinitialize_dir $srcdir/$subdir
> +gdb_load ${binfile}
> +
> +if [target_info exists gdb_stub] {
> + gdb_step_for_stub;
> +}
> +
> +gdb_test "break fn5" "Breakpoint.*at.*" "breakpoint fn5"
> +
> +set test "stop at fn5"
> +gdb_test_multiple "run -d" "$test" {
> + -re "received signal" {
> + send_gdb "continue\n"
> + }
> + -re "Breakpoint 1" {
> + pass "$test"
> + }
> +}
> +
> +gdb_test "backtrace" ".*\#0 .* fn5 .*\#1 .* fn4 .*\#2 .*signal handler.*\#3 .* fn3 .*\#4 .* fn2 .*\#5 .* fn1 .*\#6 .* tf.*" "$test"
> +
> +return 0
> +