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:
17
ChangeLog
17
ChangeLog
@ -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]
|
||||||
|
@ -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)
|
||||||
|
@ -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
21
debug/tst-backtrace6.c
Normal 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>
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
Reference in New Issue
Block a user