]>
Commit | Line | Data |
---|---|---|
2de7874e | 1 | /* Return backtrace of current program state. |
f7a9f785 | 2 | Copyright (C) 1998-2016 Free Software Foundation, Inc. |
2de7874e UD |
3 | This file is part of the GNU C Library. |
4 | Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998. | |
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. | |
2de7874e UD |
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. |
2de7874e | 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/>. */ | |
2de7874e | 19 | |
ec999b8e | 20 | #include <libc-lock.h> |
dde31996 | 21 | #include <dlfcn.h> |
2de7874e | 22 | #include <execinfo.h> |
dde31996 UD |
23 | #include <stdlib.h> |
24 | #include <unwind.h> | |
25 | ||
26 | struct trace_arg | |
27 | { | |
28 | void **array; | |
29 | int cnt, size; | |
30 | void *lastebp, *lastesp; | |
31 | }; | |
32 | ||
33 | #ifdef SHARED | |
34 | static _Unwind_Reason_Code (*unwind_backtrace) (_Unwind_Trace_Fn, void *); | |
35 | static _Unwind_Ptr (*unwind_getip) (struct _Unwind_Context *); | |
36 | static _Unwind_Ptr (*unwind_getcfa) (struct _Unwind_Context *); | |
37 | static _Unwind_Ptr (*unwind_getgr) (struct _Unwind_Context *, int); | |
05d69147 | 38 | static void *libgcc_handle; |
dde31996 UD |
39 | |
40 | static void | |
41 | init (void) | |
42 | { | |
05d69147 | 43 | libgcc_handle = __libc_dlopen ("libgcc_s.so.1"); |
dde31996 | 44 | |
05d69147 | 45 | if (libgcc_handle == NULL) |
dde31996 UD |
46 | return; |
47 | ||
05d69147 UD |
48 | unwind_backtrace = __libc_dlsym (libgcc_handle, "_Unwind_Backtrace"); |
49 | unwind_getip = __libc_dlsym (libgcc_handle, "_Unwind_GetIP"); | |
50 | unwind_getcfa = __libc_dlsym (libgcc_handle, "_Unwind_GetCFA"); | |
51 | unwind_getgr = __libc_dlsym (libgcc_handle, "_Unwind_GetGR"); | |
dde31996 | 52 | if (unwind_getip == NULL || unwind_getgr == NULL || unwind_getcfa == NULL) |
05d69147 UD |
53 | { |
54 | unwind_backtrace = NULL; | |
55 | __libc_dlclose (libgcc_handle); | |
56 | libgcc_handle = NULL; | |
57 | } | |
dde31996 UD |
58 | } |
59 | #else | |
60 | # define unwind_backtrace _Unwind_Backtrace | |
61 | # define unwind_getip _Unwind_GetIP | |
62 | # define unwind_getcfa _Unwind_GetCFA | |
63 | # define unwind_getgr _Unwind_GetGR | |
64 | #endif | |
65 | ||
66 | static _Unwind_Reason_Code | |
67 | backtrace_helper (struct _Unwind_Context *ctx, void *a) | |
68 | { | |
69 | struct trace_arg *arg = a; | |
70 | ||
71 | /* We are first called with address in the __backtrace function. | |
72 | Skip it. */ | |
73 | if (arg->cnt != -1) | |
74 | arg->array[arg->cnt] = (void *) unwind_getip (ctx); | |
75 | if (++arg->cnt == arg->size) | |
76 | return _URC_END_OF_STACK; | |
77 | ||
78 | /* %ebp is DWARF2 register 5 on IA-32. */ | |
79 | arg->lastebp = (void *) unwind_getgr (ctx, 5); | |
80 | arg->lastesp = (void *) unwind_getcfa (ctx); | |
81 | return _URC_NO_REASON; | |
82 | } | |
2de7874e UD |
83 | |
84 | ||
69f234e8 UD |
85 | /* This is a global variable set at program start time. It marks the |
86 | highest used stack address. */ | |
87 | extern void *__libc_stack_end; | |
88 | ||
89 | ||
dde31996 UD |
90 | /* This is the stack layout we see with every stack frame |
91 | if not compiled without frame pointer. | |
2de7874e UD |
92 | |
93 | +-----------------+ +-----------------+ | |
94 | %ebp -> | %ebp last frame--------> | %ebp last frame--->... | |
95 | | | | | | |
96 | | return address | | return address | | |
97 | +-----------------+ +-----------------+ | |
dde31996 UD |
98 | |
99 | First try as far to get as far as possible using | |
100 | _Unwind_Backtrace which handles -fomit-frame-pointer | |
101 | as well, but requires .eh_frame info. Then fall back to | |
102 | walking the stack manually. */ | |
103 | ||
2de7874e UD |
104 | struct layout |
105 | { | |
dde31996 UD |
106 | struct layout *ebp; |
107 | void *ret; | |
2de7874e UD |
108 | }; |
109 | ||
dde31996 | 110 | |
2de7874e | 111 | int |
bd2260a2 | 112 | __backtrace (void **array, int size) |
2de7874e | 113 | { |
dde31996 | 114 | struct trace_arg arg = { .array = array, .size = size, .cnt = -1 }; |
d5dff793 PP |
115 | |
116 | if (size <= 0) | |
117 | return 0; | |
118 | ||
dde31996 UD |
119 | #ifdef SHARED |
120 | __libc_once_define (static, once); | |
121 | ||
122 | __libc_once (once, init); | |
123 | if (unwind_backtrace == NULL) | |
124 | return 0; | |
125 | #endif | |
126 | ||
d5dff793 | 127 | unwind_backtrace (backtrace_helper, &arg); |
dde31996 UD |
128 | |
129 | if (arg.cnt > 1 && arg.array[arg.cnt - 1] == NULL) | |
130 | --arg.cnt; | |
131 | else if (arg.cnt < size) | |
2de7874e | 132 | { |
dde31996 | 133 | struct layout *ebp = (struct layout *) arg.lastebp; |
2de7874e | 134 | |
dde31996 UD |
135 | while (arg.cnt < size) |
136 | { | |
137 | /* Check for out of range. */ | |
138 | if ((void *) ebp < arg.lastesp || (void *) ebp > __libc_stack_end | |
139 | || ((long) ebp & 3)) | |
140 | break; | |
2de7874e | 141 | |
dde31996 UD |
142 | array[arg.cnt++] = ebp->ret; |
143 | ebp = ebp->ebp; | |
144 | } | |
2de7874e | 145 | } |
dde31996 | 146 | return arg.cnt != -1 ? arg.cnt : 0; |
2de7874e UD |
147 | } |
148 | weak_alias (__backtrace, backtrace) | |
0e66ade5 | 149 | libc_hidden_def (__backtrace) |
05d69147 UD |
150 | |
151 | ||
152 | #ifdef SHARED | |
153 | /* Free all resources if necessary. */ | |
154 | libc_freeres_fn (free_mem) | |
155 | { | |
156 | unwind_backtrace = NULL; | |
157 | if (libgcc_handle != NULL) | |
158 | { | |
159 | __libc_dlclose (libgcc_handle); | |
160 | libgcc_handle = NULL; | |
161 | } | |
162 | } | |
163 | #endif |