1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-07-29 11:41:21 +03:00

PowerPC: fix backtrace to handle signal trampolines

This patch fixes backtrace for PPC32 and PPC64 to correctly handle
signal trampolines. The 'debug/tst-backtrace6.c' also check for
SA_SIGINFO handling, where is triggers another vDSO symbols for PPC32.
This commit is contained in:
Adhemerval Zanella
2013-08-20 15:01:59 -05:00
parent c980f2f4fe
commit d400dcac5e
8 changed files with 172 additions and 6 deletions

View File

@ -1,3 +1,20 @@
2013-07-23 Adhemerval Zanella <azanella@linux.vnet.ibm.com>
[BZ #15867]
* sysdeps/powerpc/powerpc32/backtrace.c (__backtrace): Handle signal
trampoline stack frame information.
* sysdeps/powerpc/powerpc64/backtrace.c (__backtrace): Likewise.
* sysdeps/unix/sysv/linux/powerpc/bits/libc-vdso.h
(__vdso_sigtramp_rt64): New variable: PPC64 signal trampoline.
(__vdso_sigtramp32): New variable: PPC32 signal trampoline.
(__vdso_sigtramp_rt32): New variable: PPC32 signal trampoline.
* sysdeps/unix/sysv/linux/powerpc/init-first.c
(_libc_vdso_platform_setup): Initialize the signal trampolines.
* debug/tst-backtrace5.c (fn): Add an option set modify sigaction
sa_flags value.
* debug/tst-backtrace6.c: New file: check backtrace for signal frames,
interrupting a syscall and set with option SA_SIGINFO.
2013-08-20 Joseph Myers <joseph@codesourcery.com> 2013-08-20 Joseph Myers <joseph@codesourcery.com>
[BZ #15531] [BZ #15531]

View File

@ -130,16 +130,18 @@ CFLAGS-tst-backtrace2.c += -funwind-tables
CFLAGS-tst-backtrace3.c += -funwind-tables CFLAGS-tst-backtrace3.c += -funwind-tables
CFLAGS-tst-backtrace4.c += -funwind-tables CFLAGS-tst-backtrace4.c += -funwind-tables
CFLAGS-tst-backtrace5.c += -funwind-tables CFLAGS-tst-backtrace5.c += -funwind-tables
CFLAGS-tst-backtrace6.c += -funwind-tables
LDFLAGS-tst-backtrace2 = -rdynamic LDFLAGS-tst-backtrace2 = -rdynamic
LDFLAGS-tst-backtrace3 = -rdynamic LDFLAGS-tst-backtrace3 = -rdynamic
LDFLAGS-tst-backtrace4 = -rdynamic LDFLAGS-tst-backtrace4 = -rdynamic
LDFLAGS-tst-backtrace5 = -rdynamic LDFLAGS-tst-backtrace5 = -rdynamic
LDFLAGS-tst-backtrace6 = -rdynamic
tests = backtrace-tst tst-longjmp_chk tst-chk1 tst-chk2 tst-chk3 \ tests = backtrace-tst tst-longjmp_chk tst-chk1 tst-chk2 tst-chk3 \
tst-lfschk1 tst-lfschk2 tst-lfschk3 test-strcpy_chk test-stpcpy_chk \ tst-lfschk1 tst-lfschk2 tst-lfschk3 test-strcpy_chk test-stpcpy_chk \
tst-chk4 tst-chk5 tst-chk6 tst-lfschk4 tst-lfschk5 tst-lfschk6 \ tst-chk4 tst-chk5 tst-chk6 tst-lfschk4 tst-lfschk5 tst-lfschk6 \
tst-longjmp_chk2 tst-backtrace2 tst-backtrace3 tst-backtrace4 \ tst-longjmp_chk2 tst-backtrace2 tst-backtrace3 tst-backtrace4 \
tst-backtrace5 tst-backtrace5 tst-backtrace6
tests-ifunc := $(stpcpy_chk strcpy_chk:%=test-%-ifunc) tests-ifunc := $(stpcpy_chk strcpy_chk:%=test-%-ifunc)
tests += $(tests-ifunc) tests += $(tests-ifunc)

View File

@ -28,6 +28,10 @@
#include "tst-backtrace.h" #include "tst-backtrace.h"
#ifndef SIGACTION_FLAGS
# define SIGACTION_FLAGS 0
#endif
static int do_test (void); static int do_test (void);
#define TEST_FUNCTION do_test () #define TEST_FUNCTION do_test ()
#include "../test-skeleton.c" #include "../test-skeleton.c"
@ -91,7 +95,7 @@ handle_signal (int signum)
} }
NO_INLINE int NO_INLINE int
fn (int c) fn (int c, int flags)
{ {
pid_t parent_pid, child_pid; pid_t parent_pid, child_pid;
int pipefd[2]; int pipefd[2];
@ -100,12 +104,13 @@ fn (int c)
if (c > 0) if (c > 0)
{ {
fn (c - 1); fn (c - 1, flags);
return x; return x;
} }
memset (&act, 0, sizeof (act)); memset (&act, 0, sizeof (act));
act.sa_handler = handle_signal; act.sa_handler = handle_signal;
act.sa_flags = flags;
sigemptyset (&act.sa_mask); sigemptyset (&act.sa_mask);
sigaction (SIGUSR1, &act, NULL); sigaction (SIGUSR1, &act, NULL);
parent_pid = getpid (); parent_pid = getpid ();
@ -131,6 +136,6 @@ fn (int c)
NO_INLINE static int NO_INLINE static int
do_test (void) do_test (void)
{ {
fn (2); fn (2, SIGACTION_FLAGS);
return ret; return ret;
} }

21
debug/tst-backtrace6.c Normal file
View File

@ -0,0 +1,21 @@
/* Test backtrace and backtrace_symbols for signal frames, where a
system call was interrupted by a signal.
Copyright (C) 2013 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
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, see
<http://www.gnu.org/licenses/>. */
#define SIGACTION_FLAGS SA_SIGINFO
#include <debug/tst-backtrace5.c>

View File

@ -18,6 +18,9 @@
#include <execinfo.h> #include <execinfo.h>
#include <stddef.h> #include <stddef.h>
#include <string.h>
#include <signal.h>
#include <bits/libc-vdso.h>
/* This is the stack layout we see with every stack frame. /* This is the stack layout we see with every stack frame.
Note that every routine is required by the ABI to lay out the stack Note that every routine is required by the ABI to lay out the stack
@ -35,6 +38,46 @@ struct layout
void *return_address; void *return_address;
}; };
#define SIGNAL_FRAMESIZE 64
/* Since the signal handler is just like any other function it needs to
save/restore its LR and it will save it into callers stack frame.
Since a signal handler doesn't have a caller, the kernel creates a
dummy frame to make it look like it has a caller. */
struct signal_frame_32 {
char dummy[SIGNAL_FRAMESIZE];
struct sigcontext sctx;
mcontext_t mctx;
/* We don't care about the rest, since IP value is at 'mctx' field. */
};
static inline int
is_sigtramp_address (unsigned int nip)
{
#ifdef SHARED
if (nip == (unsigned int)__vdso_sigtramp32)
return 1;
#endif
return 0;
}
struct rt_signal_frame_32 {
char dummy[SIGNAL_FRAMESIZE + 16];
siginfo_t info;
struct ucontext uc;
/* We don't care about the rest, since IP value is at 'uc' field. */
};
static inline int
is_sigtramp_address_rt (unsigned int nip)
{
#ifdef SHARED
if (nip == (unsigned int)__vdso_sigtramp_rt32)
return 1;
#endif
return 0;
}
int int
__backtrace (void **array, int size) __backtrace (void **array, int size)
{ {
@ -50,7 +93,28 @@ __backtrace (void **array, int size)
for ( count = 0; for ( count = 0;
current != NULL && count < size; current != NULL && count < size;
current = current->next, count++) current = current->next, count++)
array[count] = current->return_address; {
gregset_t *gregset = NULL;
array[count] = current->return_address;
/* Check if the symbol is the signal trampoline and get the interrupted
* symbol address from the trampoline saved area. */
if (is_sigtramp_address ((unsigned int)current->return_address))
{
struct signal_frame_32 *sigframe =
(struct signal_frame_32*) current;
gregset = &sigframe->mctx.gregs;
}
else if (is_sigtramp_address_rt ((unsigned int)current->return_address))
{
struct rt_signal_frame_32 *sigframe =
(struct rt_signal_frame_32*) current;
gregset = &sigframe->uc.uc_mcontext.uc_regs->gregs;
}
if (gregset)
array[++count] = (void*)((*gregset)[PT_NIP]);
}
/* It's possible the second-last stack frame can't return /* It's possible the second-last stack frame can't return
(that is, it's __libc_start_main), in which case (that is, it's __libc_start_main), in which case

View File

@ -18,6 +18,9 @@
#include <execinfo.h> #include <execinfo.h>
#include <stddef.h> #include <stddef.h>
#include <string.h>
#include <signal.h>
#include <bits/libc-vdso.h>
/* This is the stack layout we see with every stack frame. /* This is the stack layout we see with every stack frame.
Note that every routine is required by the ABI to lay out the stack Note that every routine is required by the ABI to lay out the stack
@ -38,6 +41,27 @@ struct layout
void *return_address; void *return_address;
}; };
/* Since the signal handler is just like any other function it needs to
save/restore its LR and it will save it into callers stack frame.
Since a signal handler doesn't have a caller, the kernel creates a
dummy frame to make it look like it has a caller. */
struct signal_frame_64 {
#define SIGNAL_FRAMESIZE 128
char dummy[SIGNAL_FRAMESIZE];
struct ucontext uc;
/* We don't care about the rest, since the IP value is at 'uc' field. */
};
static inline int
is_sigtramp_address (unsigned long nip)
{
#ifdef SHARED
if (nip == (unsigned long)__vdso_sigtramp_rt64)
return 1;
#endif
return 0;
}
int int
__backtrace (void **array, int size) __backtrace (void **array, int size)
{ {
@ -53,7 +77,17 @@ __backtrace (void **array, int size)
for ( count = 0; for ( count = 0;
current != NULL && count < size; current != NULL && count < size;
current = current->next, count++) current = current->next, count++)
array[count] = current->return_address; {
array[count] = current->return_address;
/* Check if the symbol is the signal trampoline and get the interrupted
* symbol address from the trampoline saved area. */
if (is_sigtramp_address ((unsigned long)current->return_address))
{
struct signal_frame_64 *sigframe = (struct signal_frame_64*) current;
array[++count] = (void*)sigframe->uc.uc_mcontext.gp_regs[PT_NIP];
}
}
/* It's possible the second-last stack frame can't return /* It's possible the second-last stack frame can't return
(that is, it's __libc_start_main), in which case (that is, it's __libc_start_main), in which case

View File

@ -34,6 +34,13 @@ extern void *__vdso_getcpu;
extern void *__vdso_time; extern void *__vdso_time;
#if defined(__PPC64__) || defined(__powerpc64__)
extern void *__vdso_sigtramp_rt64;
#else
extern void *__vdso_sigtramp32;
extern void *__vdso_sigtramp_rt32;
#endif
/* This macro is needed for PPC64 to return a skeleton OPD entry of a vDSO /* This macro is needed for PPC64 to return a skeleton OPD entry of a vDSO
symbol. This works because _dl_vdso_vsym always return the function symbol. This works because _dl_vdso_vsym always return the function
address, and no vDSO symbols use the TOC or chain pointers from the OPD address, and no vDSO symbols use the TOC or chain pointers from the OPD

View File

@ -29,6 +29,12 @@ void *__vdso_clock_getres;
void *__vdso_get_tbfreq; void *__vdso_get_tbfreq;
void *__vdso_getcpu; void *__vdso_getcpu;
void *__vdso_time; void *__vdso_time;
#if defined(__PPC64__) || defined(__powerpc64__)
void *__vdso_sigtramp_rt64;
#else
void *__vdso_sigtramp32;
void *__vdso_sigtramp_rt32;
#endif
static inline void static inline void
_libc_vdso_platform_setup (void) _libc_vdso_platform_setup (void)
@ -46,6 +52,16 @@ _libc_vdso_platform_setup (void)
__vdso_getcpu = _dl_vdso_vsym ("__kernel_getcpu", &linux2615); __vdso_getcpu = _dl_vdso_vsym ("__kernel_getcpu", &linux2615);
__vdso_time = _dl_vdso_vsym ("__kernel_time", &linux2615); __vdso_time = _dl_vdso_vsym ("__kernel_time", &linux2615);
/* PPC64 uses only one signal trampoline symbol, while PPC32 will use
two depending if SA_SIGINFO is used (__kernel_sigtramp_rt32) or not
(__kernel_sigtramp32). */
#if defined(__PPC64__) || defined(__powerpc64__)
__vdso_sigtramp_rt64 = _dl_vdso_vsym ("__kernel_sigtramp_rt64", &linux2615);
#else
__vdso_sigtramp32 = _dl_vdso_vsym ("__kernel_sigtramp32", &linux2615);
__vdso_sigtramp_rt32 = _dl_vdso_vsym ("__kernel_sigtramp_rt32", &linux2615);
#endif
} }
# define VDSO_SETUP _libc_vdso_platform_setup # define VDSO_SETUP _libc_vdso_platform_setup