]>
Commit | Line | Data |
---|---|---|
2d2d80b8 | 1 | /* go-callers.c -- get callers for Go. |
2 | ||
3 | Copyright 2012 The Go Authors. All rights reserved. | |
4 | Use of this source code is governed by a BSD-style | |
5 | license that can be found in the LICENSE file. */ | |
6 | ||
7 | #include "config.h" | |
8 | ||
e4fbfaf5 | 9 | #include "backtrace.h" |
2d2d80b8 | 10 | |
11 | #include "runtime.h" | |
1b1f2abf | 12 | #include "array.h" |
2d2d80b8 | 13 | |
ebabd272 | 14 | /* This is set to non-zero when calling backtrace_full. This is used |
15 | to avoid getting hanging on a recursive lock in dl_iterate_phdr on | |
16 | older versions of glibc when a SIGPROF signal arrives while | |
17 | collecting a backtrace. */ | |
18 | ||
03118c21 | 19 | static uint32 runtime_in_callers; |
ebabd272 | 20 | |
e4fbfaf5 | 21 | /* Argument passed to callback function. */ |
2d2d80b8 | 22 | |
23 | struct callers_data | |
24 | { | |
051dc824 | 25 | Location *locbuf; |
c56ee3f1 | 26 | int skip; |
2d2d80b8 | 27 | int index; |
28 | int max; | |
02d42640 | 29 | int keep_thunks; |
2d2d80b8 | 30 | }; |
31 | ||
051dc824 | 32 | /* Callback function for backtrace_full. Just collect the locations. |
33 | Return zero to continue, non-zero to stop. */ | |
e4fbfaf5 | 34 | |
35 | static int | |
051dc824 | 36 | callback (void *data, uintptr_t pc, const char *filename, int lineno, |
37 | const char *function) | |
e4fbfaf5 | 38 | { |
39 | struct callers_data *arg = (struct callers_data *) data; | |
051dc824 | 40 | Location *loc; |
41 | ||
42 | /* Skip split stack functions. */ | |
43 | if (function != NULL) | |
44 | { | |
07eac010 | 45 | const char *p; |
051dc824 | 46 | |
07eac010 | 47 | p = function; |
051dc824 | 48 | if (__builtin_strncmp (p, "___", 3) == 0) |
49 | ++p; | |
50 | if (__builtin_strncmp (p, "__morestack_", 12) == 0) | |
51 | return 0; | |
52 | } | |
07eac010 | 53 | else if (filename != NULL) |
54 | { | |
55 | const char *p; | |
56 | ||
57 | p = strrchr (filename, '/'); | |
58 | if (p == NULL) | |
59 | p = filename; | |
a1afa647 | 60 | if (__builtin_strncmp (p, "/morestack.S", 12) == 0) |
07eac010 | 61 | return 0; |
62 | } | |
051dc824 | 63 | |
70c833a3 | 64 | /* Skip thunks and recover functions. There is no equivalent to |
65 | these functions in the gc toolchain, so returning them here means | |
66 | significantly different results for runtime.Caller(N). */ | |
02d42640 | 67 | if (function != NULL && !arg->keep_thunks) |
70c833a3 | 68 | { |
69 | const char *p; | |
70 | ||
13f2fdb8 | 71 | p = function + __builtin_strlen (function); |
72 | while (p > function && p[-1] >= '0' && p[-1] <= '9') | |
73 | --p; | |
74 | if (p - function > 7 && __builtin_strncmp (p - 7, "..thunk", 7) == 0) | |
70c833a3 | 75 | return 0; |
13f2fdb8 | 76 | if (p - function > 3 && __builtin_strcmp (p - 3, "..r") == 0) |
70c833a3 | 77 | return 0; |
13f2fdb8 | 78 | if (p - function > 6 && __builtin_strcmp (p - 6, "..stub") == 0) |
7446ae03 | 79 | return 0; |
70c833a3 | 80 | } |
81 | ||
c56ee3f1 | 82 | if (arg->skip > 0) |
83 | { | |
84 | --arg->skip; | |
85 | return 0; | |
86 | } | |
87 | ||
051dc824 | 88 | loc = &arg->locbuf[arg->index]; |
17ceef2d | 89 | |
90 | /* On the call to backtrace_full the pc value was most likely | |
91 | decremented if there was a normal call, since the pc referred to | |
92 | the instruction where the call returned and not the call itself. | |
93 | This was done so that the line number referred to the call | |
94 | instruction. To make sure the actual pc from the call stack is | |
95 | used, it is incremented here. | |
96 | ||
97 | In the case of a signal, the pc was not decremented by | |
98 | backtrace_full but still incremented here. That doesn't really | |
99 | hurt anything since the line number is right and the pc refers to | |
100 | the same instruction. */ | |
101 | ||
102 | loc->pc = pc + 1; | |
9dec9e25 | 103 | |
104 | /* The libbacktrace library says that these strings might disappear, | |
105 | but with the current implementation they won't. We can't easily | |
106 | allocate memory here, so for now assume that we can save a | |
107 | pointer to the strings. */ | |
108 | loc->filename = runtime_gostringnocopy ((const byte *) filename); | |
109 | loc->function = runtime_gostringnocopy ((const byte *) function); | |
110 | ||
051dc824 | 111 | loc->lineno = lineno; |
e4fbfaf5 | 112 | ++arg->index; |
bf43ea31 | 113 | |
114 | /* There is no point to tracing past certain runtime functions. | |
115 | Stopping the backtrace here can avoid problems on systems that | |
116 | don't provide proper unwind information for makecontext, such as | |
117 | Solaris (http://gcc.gnu.org/PR52583 comment #21). */ | |
118 | if (function != NULL) | |
119 | { | |
120 | if (__builtin_strcmp (function, "makecontext") == 0) | |
121 | return 1; | |
122 | if (filename != NULL) | |
123 | { | |
124 | const char *p; | |
125 | ||
126 | p = strrchr (filename, '/'); | |
127 | if (p == NULL) | |
128 | p = filename; | |
129 | if (__builtin_strcmp (p, "/proc.c") == 0) | |
130 | { | |
33d1d391 | 131 | if (__builtin_strcmp (function, "runtime_mstart") == 0) |
132 | return 1; | |
133 | } | |
134 | else if (__builtin_strcmp (p, "/proc.go") == 0) | |
135 | { | |
136 | if (__builtin_strcmp (function, "runtime.kickoff") == 0 | |
03118c21 | 137 | || __builtin_strcmp (function, "runtime.main") == 0) |
bf43ea31 | 138 | return 1; |
139 | } | |
140 | } | |
141 | } | |
142 | ||
e4fbfaf5 | 143 | return arg->index >= arg->max; |
144 | } | |
145 | ||
22b83eee | 146 | /* Syminfo callback. */ |
147 | ||
48cd836f | 148 | void |
149 | __go_syminfo_fnname_callback (void *data, | |
150 | uintptr_t pc __attribute__ ((unused)), | |
151 | const char *symname, | |
152 | uintptr_t address __attribute__ ((unused)), | |
153 | uintptr_t size __attribute__ ((unused))) | |
22b83eee | 154 | { |
48cd836f | 155 | String* strptr = (String*) data; |
22b83eee | 156 | |
157 | if (symname != NULL) | |
48cd836f | 158 | *strptr = runtime_gostringnocopy ((const byte *) symname); |
22b83eee | 159 | } |
160 | ||
e4fbfaf5 | 161 | /* Error callback. */ |
162 | ||
163 | static void | |
164 | error_callback (void *data __attribute__ ((unused)), | |
165 | const char *msg, int errnum) | |
2d2d80b8 | 166 | { |
a1a0f4b3 | 167 | if (errnum == -1) |
168 | { | |
169 | /* No debug info available. Carry on as best we can. */ | |
170 | return; | |
171 | } | |
e4fbfaf5 | 172 | if (errnum != 0) |
173 | runtime_printf ("%s errno %d\n", msg, errnum); | |
174 | runtime_throw (msg); | |
2d2d80b8 | 175 | } |
176 | ||
03118c21 | 177 | /* Return whether we are already collecting a stack trace. This is |
178 | called from the signal handler. */ | |
179 | ||
180 | bool alreadyInCallers(void) | |
181 | __attribute__ ((no_split_stack)); | |
182 | bool alreadyInCallers(void) | |
183 | __asm__ (GOSYM_PREFIX "runtime.alreadyInCallers"); | |
184 | ||
185 | bool | |
186 | alreadyInCallers() | |
187 | { | |
188 | return runtime_atomicload(&runtime_in_callers) > 0; | |
189 | } | |
190 | ||
e4fbfaf5 | 191 | /* Gather caller PC's. */ |
192 | ||
2d2d80b8 | 193 | int32 |
02d42640 | 194 | runtime_callers (int32 skip, Location *locbuf, int32 m, bool keep_thunks) |
2d2d80b8 | 195 | { |
e4fbfaf5 | 196 | struct callers_data data; |
22b83eee | 197 | struct backtrace_state* state; |
198 | int32 i; | |
e4fbfaf5 | 199 | |
051dc824 | 200 | data.locbuf = locbuf; |
c56ee3f1 | 201 | data.skip = skip + 1; |
e4fbfaf5 | 202 | data.index = 0; |
203 | data.max = m; | |
02d42640 | 204 | data.keep_thunks = keep_thunks; |
22b83eee | 205 | state = __go_get_backtrace_state (); |
ebabd272 | 206 | runtime_xadd (&runtime_in_callers, 1); |
22b83eee | 207 | backtrace_full (state, 0, callback, error_callback, &data); |
ebabd272 | 208 | runtime_xadd (&runtime_in_callers, -1); |
33d1d391 | 209 | |
210 | /* For some reason GCC sometimes loses the name of a thunk function | |
211 | at the top of the stack. If we are skipping thunks, skip that | |
212 | one too. */ | |
213 | if (!keep_thunks | |
214 | && data.index > 2 | |
215 | && locbuf[data.index - 2].function.len == 0 | |
216 | && locbuf[data.index - 1].function.str != NULL | |
217 | && __builtin_strcmp ((const char *) locbuf[data.index - 1].function.str, | |
218 | "runtime.kickoff") == 0) | |
219 | { | |
220 | locbuf[data.index - 2] = locbuf[data.index - 1]; | |
221 | --data.index; | |
222 | } | |
223 | ||
22b83eee | 224 | /* Try to use backtrace_syminfo to fill in any missing function |
225 | names. This can happen when tracing through an object which has | |
226 | no debug info; backtrace_syminfo will look at the symbol table to | |
227 | get the name. This should only happen when tracing through code | |
228 | that is not written in Go and is not part of libgo. */ | |
229 | for (i = 0; i < data.index; ++i) | |
230 | { | |
231 | if (locbuf[i].function.len == 0 && locbuf[i].pc != 0) | |
48cd836f | 232 | backtrace_syminfo (state, locbuf[i].pc, __go_syminfo_fnname_callback, |
233 | error_callback, &locbuf[i].function); | |
22b83eee | 234 | } |
235 | ||
e4fbfaf5 | 236 | return data.index; |
2d2d80b8 | 237 | } |
6275e0bf | 238 | |
239 | int Callers (int, struct __go_open_array) | |
9c03884a | 240 | __asm__ (GOSYM_PREFIX "runtime.Callers"); |
6275e0bf | 241 | |
242 | int | |
243 | Callers (int skip, struct __go_open_array pc) | |
244 | { | |
051dc824 | 245 | Location *locbuf; |
246 | int ret; | |
247 | int i; | |
248 | ||
03118c21 | 249 | /* Note that calling mallocgc here assumes that we are not going to |
250 | store any allocated Go pointers in the slice. */ | |
251 | locbuf = (Location *) runtime_mallocgc (pc.__count * sizeof (Location), | |
252 | nil, false); | |
051dc824 | 253 | |
d65d9e7a | 254 | /* In the Go 1 release runtime.Callers has an off-by-one error, |
255 | which we can not correct because it would break backward | |
94d40360 | 256 | compatibility. Normally we would add 1 to SKIP here, but we |
257 | don't so that we are compatible. */ | |
02d42640 | 258 | ret = runtime_callers (skip, locbuf, pc.__count, false); |
051dc824 | 259 | |
260 | for (i = 0; i < ret; i++) | |
261 | ((uintptr *) pc.__values)[i] = locbuf[i].pc; | |
262 | ||
263 | return ret; | |
6275e0bf | 264 | } |