]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgo/runtime/go-callers.c
libgo: don't use wc in gotest
[thirdparty/gcc.git] / libgo / runtime / go-callers.c
CommitLineData
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 19static uint32 runtime_in_callers;
ebabd272 20
e4fbfaf5 21/* Argument passed to callback function. */
2d2d80b8 22
23struct 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
35static int
051dc824 36callback (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 148void
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
163static void
164error_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
180bool alreadyInCallers(void)
181 __attribute__ ((no_split_stack));
182bool alreadyInCallers(void)
183 __asm__ (GOSYM_PREFIX "runtime.alreadyInCallers");
184
185bool
186alreadyInCallers()
187{
188 return runtime_atomicload(&runtime_in_callers) > 0;
189}
190
e4fbfaf5 191/* Gather caller PC's. */
192
2d2d80b8 193int32
02d42640 194runtime_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
239int Callers (int, struct __go_open_array)
9c03884a 240 __asm__ (GOSYM_PREFIX "runtime.Callers");
6275e0bf 241
242int
243Callers (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}