]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/powerpc/powerpc64/backtrace.c
PowerPC: fix backtrace to handle signal trampolines
[thirdparty/glibc.git] / sysdeps / powerpc / powerpc64 / backtrace.c
CommitLineData
cfc91acd 1/* Return backtrace of current program state.
568035b7 2 Copyright (C) 1998-2013 Free Software Foundation, Inc.
cfc91acd
RM
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
59ba27a6
PE
16 License along with the GNU C Library; see the file COPYING.LIB. If
17 not, see <http://www.gnu.org/licenses/>. */
cfc91acd
RM
18
19#include <execinfo.h>
20#include <stddef.h>
d400dcac
AZ
21#include <string.h>
22#include <signal.h>
23#include <bits/libc-vdso.h>
cfc91acd
RM
24
25/* This is the stack layout we see with every stack frame.
26 Note that every routine is required by the ABI to lay out the stack
27 like this.
28
29 +----------------+ +-----------------+
30 %r1 -> | %r1 last frame--------> | %r1 last frame--->... --> NULL
31 | | | |
32 | cr save | | cr save |
33 | | | |
34 | (unused) | | return address |
35 +----------------+ +-----------------+
36*/
37struct layout
38{
70d9946a 39 struct layout *next;
cfc91acd 40 long condition_register;
70d9946a 41 void *return_address;
cfc91acd
RM
42};
43
d400dcac
AZ
44/* Since the signal handler is just like any other function it needs to
45 save/restore its LR and it will save it into callers stack frame.
46 Since a signal handler doesn't have a caller, the kernel creates a
47 dummy frame to make it look like it has a caller. */
48struct signal_frame_64 {
49#define SIGNAL_FRAMESIZE 128
50 char dummy[SIGNAL_FRAMESIZE];
51 struct ucontext uc;
52 /* We don't care about the rest, since the IP value is at 'uc' field. */
53};
54
55static inline int
56is_sigtramp_address (unsigned long nip)
57{
58#ifdef SHARED
59 if (nip == (unsigned long)__vdso_sigtramp_rt64)
60 return 1;
61#endif
62 return 0;
63}
64
cfc91acd
RM
65int
66__backtrace (void **array, int size)
67{
68 struct layout *current;
69 int count;
70
71 /* Force gcc to spill LR. */
72 asm volatile ("" : "=l"(current));
73
74 /* Get the address on top-of-stack. */
75 asm volatile ("ld %0,0(1)" : "=r"(current));
cfc91acd
RM
76
77 for ( count = 0;
78 current != NULL && count < size;
e782a927 79 current = current->next, count++)
d400dcac
AZ
80 {
81 array[count] = current->return_address;
82
83 /* Check if the symbol is the signal trampoline and get the interrupted
84 * symbol address from the trampoline saved area. */
85 if (is_sigtramp_address ((unsigned long)current->return_address))
86 {
87 struct signal_frame_64 *sigframe = (struct signal_frame_64*) current;
88 array[++count] = (void*)sigframe->uc.uc_mcontext.gp_regs[PT_NIP];
89 }
90 }
cfc91acd
RM
91
92 /* It's possible the second-last stack frame can't return
93 (that is, it's __libc_start_main), in which case
94 the CRT startup code will have set its LR to 'NULL'. */
95 if (count > 0 && array[count-1] == NULL)
96 count--;
97
98 return count;
99}
100weak_alias (__backtrace, backtrace)
0e66ade5 101libc_hidden_def (__backtrace)