]>
Commit | Line | Data |
---|---|---|
ffeac417 | 1 | /* Return backtrace of current program state. 64 bit S/390 version. |
b168057a | 2 | Copyright (C) 2001-2015 Free Software Foundation, Inc. |
0e66ade5 | 3 | Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>. |
847b055c AJ |
4 | This file is part of the GNU C Library. |
5 | ||
6 | The GNU C Library is free software; you can redistribute it and/or | |
41bdb6e2 AJ |
7 | modify it under the terms of the GNU Lesser General Public |
8 | License as published by the Free Software Foundation; either | |
9 | version 2.1 of the License, or (at your option) any later version. | |
847b055c AJ |
10 | |
11 | The GNU C Library is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
41bdb6e2 | 14 | Lesser General Public License for more details. |
847b055c | 15 | |
41bdb6e2 | 16 | You should have received a copy of the GNU Lesser General Public |
59ba27a6 PE |
17 | License along with the GNU C Library; if not, see |
18 | <http://www.gnu.org/licenses/>. */ | |
847b055c | 19 | |
844a34a2 UD |
20 | #include <bits/libc-lock.h> |
21 | #include <dlfcn.h> | |
847b055c AJ |
22 | #include <execinfo.h> |
23 | #include <stddef.h> | |
844a34a2 UD |
24 | #include <stdlib.h> |
25 | #include <unwind.h> | |
847b055c | 26 | |
ffeac417 | 27 | |
847b055c AJ |
28 | /* This is a global variable set at program start time. It marks the |
29 | highest used stack address. */ | |
30 | extern void *__libc_stack_end; | |
31 | ||
32 | ||
33 | /* This is the stack layout we see for every non-leaf function. | |
34 | size offset | |
35 | %r15 -> +------------------+ | |
ffeac417 UD |
36 | 8 | back chain | 0 |
37 | 8 | end of stack | 8 | |
38 | 32 | scratch | 16 | |
39 | 80 | save area r6-r15 | 48 | |
40 | 16 | save area f4,f6 | 128 | |
41 | 16 | empty | 144 | |
847b055c AJ |
42 | +------------------+ |
43 | r14 in the save area holds the return address. | |
44 | */ | |
45 | ||
46 | struct layout | |
47 | { | |
ffeac417 UD |
48 | long back_chain; |
49 | long end_of_stack; | |
50 | long scratch[4]; | |
51 | long save_grps[10]; | |
52 | long save_fp[2]; | |
53 | long empty[2]; | |
847b055c AJ |
54 | }; |
55 | ||
844a34a2 UD |
56 | struct trace_arg |
57 | { | |
58 | void **array; | |
59 | int cnt, size; | |
60 | }; | |
61 | ||
a9e526e7 | 62 | #ifdef SHARED |
844a34a2 UD |
63 | static _Unwind_Reason_Code (*unwind_backtrace) (_Unwind_Trace_Fn, void *); |
64 | static _Unwind_Ptr (*unwind_getip) (struct _Unwind_Context *); | |
65 | ||
66 | static void | |
67 | init (void) | |
68 | { | |
69 | void *handle = __libc_dlopen ("libgcc_s.so.1"); | |
70 | ||
71 | if (handle == NULL) | |
72 | return; | |
73 | ||
74 | unwind_backtrace = __libc_dlsym (handle, "_Unwind_Backtrace"); | |
75 | unwind_getip = __libc_dlsym (handle, "_Unwind_GetIP"); | |
76 | if (unwind_getip == NULL) | |
77 | unwind_backtrace = NULL; | |
78 | } | |
79 | ||
618cebef | 80 | static int |
844a34a2 | 81 | __backchain_backtrace (void **array, int size) |
847b055c AJ |
82 | { |
83 | /* We assume that all the code is generated with frame pointers set. */ | |
84 | struct layout *stack; | |
85 | int cnt = 0; | |
86 | ||
ffeac417 | 87 | asm ("LGR %0,%%r15" : "=d" (stack) ); |
847b055c AJ |
88 | /* We skip the call to this function, it makes no sense to record it. */ |
89 | stack = (struct layout *) stack->back_chain; | |
90 | while (cnt < size) | |
91 | { | |
92 | if (stack == NULL || (void *) stack > __libc_stack_end) | |
93 | /* This means the address is out of range. Note that for the | |
94 | toplevel we see a frame pointer with value NULL which clearly is | |
95 | out of range. */ | |
96 | break; | |
97 | ||
4661a153 | 98 | array[cnt++] = (void *) stack->save_grps[8]; |
847b055c AJ |
99 | |
100 | stack = (struct layout *) stack->back_chain; | |
101 | } | |
102 | ||
103 | return cnt; | |
104 | } | |
618cebef SL |
105 | #else |
106 | # define unwind_backtrace _Unwind_Backtrace | |
107 | # define unwind_getip _Unwind_GetIP | |
108 | #endif | |
844a34a2 UD |
109 | |
110 | static _Unwind_Reason_Code | |
111 | backtrace_helper (struct _Unwind_Context *ctx, void *a) | |
112 | { | |
113 | struct trace_arg *arg = a; | |
114 | ||
115 | /* We are first called with address in the __backtrace function. | |
116 | Skip it. */ | |
117 | if (arg->cnt != -1) | |
118 | arg->array[arg->cnt] = (void *) unwind_getip (ctx); | |
119 | if (++arg->cnt == arg->size) | |
120 | return _URC_END_OF_STACK; | |
121 | return _URC_NO_REASON; | |
122 | } | |
123 | ||
124 | int | |
125 | __backtrace (void **array, int size) | |
126 | { | |
127 | struct trace_arg arg = { .array = array, .size = size, .cnt = -1 }; | |
a9e526e7 | 128 | #ifdef SHARED |
844a34a2 UD |
129 | __libc_once_define (static, once); |
130 | ||
131 | __libc_once (once, init); | |
618cebef | 132 | |
844a34a2 UD |
133 | if (unwind_backtrace == NULL) |
134 | return __backchain_backtrace (array, size); | |
618cebef | 135 | #endif |
844a34a2 UD |
136 | |
137 | if (size >= 1) | |
138 | unwind_backtrace (backtrace_helper, &arg); | |
139 | ||
140 | return arg.cnt != -1 ? arg.cnt : 0; | |
141 | } | |
142 | ||
847b055c | 143 | weak_alias (__backtrace, backtrace) |
0e66ade5 | 144 | libc_hidden_def (__backtrace) |