Update LOCAL_PATCHES after libsanitizer merge.
[official-gcc.git] / libgo / runtime / go-callers.c
blobb16ae0c40368c0a4af914e4e3f7b7beaaad08eae
1 /* go-callers.c -- get callers for Go.
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. */
7 #include "config.h"
9 #include "backtrace.h"
11 #include "runtime.h"
12 #include "array.h"
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. */
19 static uint32 runtime_in_callers;
21 /* Argument passed to callback function. */
23 struct callers_data
25 Location *locbuf;
26 int skip;
27 int index;
28 int max;
29 int keep_thunks;
32 /* Callback function for backtrace_full. Just collect the locations.
33 Return zero to continue, non-zero to stop. */
35 static int
36 callback (void *data, uintptr_t pc, const char *filename, int lineno,
37 const char *function)
39 struct callers_data *arg = (struct callers_data *) data;
40 Location *loc;
42 /* Skip split stack functions. */
43 if (function != NULL)
45 const char *p;
47 p = function;
48 if (__builtin_strncmp (p, "___", 3) == 0)
49 ++p;
50 if (__builtin_strncmp (p, "__morestack_", 12) == 0)
51 return 0;
53 else if (filename != NULL)
55 const char *p;
57 p = strrchr (filename, '/');
58 if (p == NULL)
59 p = filename;
60 if (__builtin_strncmp (p, "/morestack.S", 12) == 0)
61 return 0;
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). */
67 if (function != NULL && !arg->keep_thunks)
69 const char *p;
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)
75 return 0;
76 if (p - function > 3 && __builtin_strcmp (p - 3, "..r") == 0)
77 return 0;
78 if (p - function > 6 && __builtin_strcmp (p - 6, "..stub") == 0)
79 return 0;
82 if (arg->skip > 0)
84 --arg->skip;
85 return 0;
88 loc = &arg->locbuf[arg->index];
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.
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. */
102 loc->pc = pc + 1;
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);
111 loc->lineno = lineno;
112 ++arg->index;
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)
120 if (__builtin_strcmp (function, "makecontext") == 0)
121 return 1;
122 if (filename != NULL)
124 const char *p;
126 p = strrchr (filename, '/');
127 if (p == NULL)
128 p = filename;
129 if (__builtin_strcmp (p, "/proc.c") == 0)
131 if (__builtin_strcmp (function, "runtime_mstart") == 0)
132 return 1;
134 else if (__builtin_strcmp (p, "/proc.go") == 0)
136 if (__builtin_strcmp (function, "runtime.kickoff") == 0
137 || __builtin_strcmp (function, "runtime.main") == 0)
138 return 1;
143 return arg->index >= arg->max;
146 /* Syminfo callback. */
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)))
155 String* strptr = (String*) data;
157 if (symname != NULL)
158 *strptr = runtime_gostringnocopy ((const byte *) symname);
161 /* Error callback. */
163 static void
164 error_callback (void *data __attribute__ ((unused)),
165 const char *msg, int errnum)
167 if (errnum == -1)
169 /* No debug info available. Carry on as best we can. */
170 return;
172 if (errnum != 0)
173 runtime_printf ("%s errno %d\n", msg, errnum);
174 runtime_throw (msg);
177 /* Return whether we are already collecting a stack trace. This is
178 called from the signal handler. */
180 bool alreadyInCallers(void)
181 __attribute__ ((no_split_stack));
182 bool alreadyInCallers(void)
183 __asm__ (GOSYM_PREFIX "runtime.alreadyInCallers");
185 bool
186 alreadyInCallers()
188 return runtime_atomicload(&runtime_in_callers) > 0;
191 /* Gather caller PC's. */
193 int32
194 runtime_callers (int32 skip, Location *locbuf, int32 m, bool keep_thunks)
196 struct callers_data data;
197 struct backtrace_state* state;
198 int32 i;
200 data.locbuf = locbuf;
201 data.skip = skip + 1;
202 data.index = 0;
203 data.max = m;
204 data.keep_thunks = keep_thunks;
205 state = __go_get_backtrace_state ();
206 runtime_xadd (&runtime_in_callers, 1);
207 backtrace_full (state, 0, callback, error_callback, &data);
208 runtime_xadd (&runtime_in_callers, -1);
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)
220 locbuf[data.index - 2] = locbuf[data.index - 1];
221 --data.index;
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)
231 if (locbuf[i].function.len == 0 && locbuf[i].pc != 0)
232 backtrace_syminfo (state, locbuf[i].pc, __go_syminfo_fnname_callback,
233 error_callback, &locbuf[i].function);
236 return data.index;
239 int Callers (int, struct __go_open_array)
240 __asm__ (GOSYM_PREFIX "runtime.Callers");
243 Callers (int skip, struct __go_open_array pc)
245 Location *locbuf;
246 int ret;
247 int i;
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);
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
256 compatibility. Normally we would add 1 to SKIP here, but we
257 don't so that we are compatible. */
258 ret = runtime_callers (skip, locbuf, pc.__count, false);
260 for (i = 0; i < ret; i++)
261 ((uintptr *) pc.__values)[i] = locbuf[i].pc;
263 return ret;