[Ada] Issue error on illegal ownership in SPARK
[official-gcc.git] / libgo / runtime / go-callers.c
blobe7d53a32a5fb8a7d9b17b5adf0e3dbcdc3a74cfc
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 uint32 __go_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). See also
67 similar code in runtime/mprof.go that strips out such functions
68 for block/mutex/memory profiles. */
69 if (function != NULL && !arg->keep_thunks)
71 const char *p;
73 p = function + __builtin_strlen (function);
74 while (p > function && p[-1] >= '0' && p[-1] <= '9')
75 --p;
76 if (p - function > 7 && __builtin_strncmp (p - 7, "..thunk", 7) == 0)
77 return 0;
78 if (p - function > 3 && __builtin_strcmp (p - 3, "..r") == 0)
79 return 0;
80 if (p - function > 6 && __builtin_strncmp (p - 6, "..stub", 6) == 0)
81 return 0;
84 if (arg->skip > 0)
86 --arg->skip;
87 return 0;
90 loc = &arg->locbuf[arg->index];
92 /* On the call to backtrace_full the pc value was most likely
93 decremented if there was a normal call, since the pc referred to
94 the instruction where the call returned and not the call itself.
95 This was done so that the line number referred to the call
96 instruction. To make sure the actual pc from the call stack is
97 used, it is incremented here.
99 In the case of a signal, the pc was not decremented by
100 backtrace_full but still incremented here. That doesn't really
101 hurt anything since the line number is right and the pc refers to
102 the same instruction. */
104 loc->pc = pc + 1;
106 /* The libbacktrace library says that these strings might disappear,
107 but with the current implementation they won't. We can't easily
108 allocate memory here, so for now assume that we can save a
109 pointer to the strings. */
110 loc->filename = runtime_gostringnocopy ((const byte *) filename);
111 loc->function = runtime_gostringnocopy ((const byte *) function);
113 loc->lineno = lineno;
114 ++arg->index;
116 /* There is no point to tracing past certain runtime functions.
117 Stopping the backtrace here can avoid problems on systems that
118 don't provide proper unwind information for makecontext, such as
119 Solaris (http://gcc.gnu.org/PR52583 comment #21). */
120 if (function != NULL)
122 if (__builtin_strcmp (function, "makecontext") == 0)
123 return 1;
124 if (filename != NULL)
126 const char *p;
128 p = strrchr (filename, '/');
129 if (p == NULL)
130 p = filename;
131 if (__builtin_strcmp (p, "/proc.c") == 0)
133 if (__builtin_strcmp (function, "runtime_mstart") == 0)
134 return 1;
136 else if (__builtin_strcmp (p, "/proc.go") == 0)
138 if (__builtin_strcmp (function, "runtime.kickoff") == 0
139 || __builtin_strcmp (function, "runtime.main") == 0)
140 return 1;
145 return arg->index >= arg->max;
148 /* Syminfo callback. */
150 void
151 __go_syminfo_fnname_callback (void *data,
152 uintptr_t pc __attribute__ ((unused)),
153 const char *symname,
154 uintptr_t address __attribute__ ((unused)),
155 uintptr_t size __attribute__ ((unused)))
157 String* strptr = (String*) data;
159 if (symname != NULL)
160 *strptr = runtime_gostringnocopy ((const byte *) symname);
163 /* Error callback. */
165 static void
166 error_callback (void *data __attribute__ ((unused)),
167 const char *msg, int errnum)
169 if (errnum == -1)
171 /* No debug info available. Carry on as best we can. */
172 return;
174 if (errnum != 0)
175 runtime_printf ("%s errno %d\n", msg, errnum);
176 runtime_throw (msg);
179 /* Return whether we are already collecting a stack trace. This is
180 called from the signal handler. */
182 bool alreadyInCallers(void)
183 __attribute__ ((no_split_stack));
184 bool alreadyInCallers(void)
185 __asm__ (GOSYM_PREFIX "runtime.alreadyInCallers");
187 bool
188 alreadyInCallers()
190 return runtime_atomicload(&__go_runtime_in_callers) > 0;
193 /* Gather caller PC's. */
195 int32
196 runtime_callers (int32 skip, Location *locbuf, int32 m, bool keep_thunks)
198 struct callers_data data;
199 struct backtrace_state* state;
200 int32 i;
202 data.locbuf = locbuf;
203 data.skip = skip + 1;
204 data.index = 0;
205 data.max = m;
206 data.keep_thunks = keep_thunks;
207 runtime_xadd (&__go_runtime_in_callers, 1);
208 state = __go_get_backtrace_state ();
209 backtrace_full (state, 0, callback, error_callback, &data);
210 runtime_xadd (&__go_runtime_in_callers, -1);
212 /* For some reason GCC sometimes loses the name of a thunk function
213 at the top of the stack. If we are skipping thunks, skip that
214 one too. */
215 if (!keep_thunks
216 && data.index > 2
217 && locbuf[data.index - 2].function.len == 0
218 && locbuf[data.index - 1].function.str != NULL
219 && __builtin_strcmp ((const char *) locbuf[data.index - 1].function.str,
220 "runtime.kickoff") == 0)
222 locbuf[data.index - 2] = locbuf[data.index - 1];
223 --data.index;
226 /* Try to use backtrace_syminfo to fill in any missing function
227 names. This can happen when tracing through an object which has
228 no debug info; backtrace_syminfo will look at the symbol table to
229 get the name. This should only happen when tracing through code
230 that is not written in Go and is not part of libgo. */
231 for (i = 0; i < data.index; ++i)
233 if (locbuf[i].function.len == 0 && locbuf[i].pc != 0)
234 backtrace_syminfo (state, locbuf[i].pc, __go_syminfo_fnname_callback,
235 error_callback, &locbuf[i].function);
238 return data.index;
241 intgo Callers (intgo, struct __go_open_array)
242 __asm__ (GOSYM_PREFIX "runtime.Callers");
244 intgo
245 Callers (intgo skip, struct __go_open_array pc)
247 Location *locbuf;
248 int ret;
249 int i;
251 /* Note that calling mallocgc here assumes that we are not going to
252 store any allocated Go pointers in the slice. */
253 locbuf = (Location *) runtime_mallocgc (pc.__count * sizeof (Location),
254 nil, false);
256 /* In the Go 1 release runtime.Callers has an off-by-one error,
257 which we can not correct because it would break backward
258 compatibility. Normally we would add 1 to SKIP here, but we
259 don't so that we are compatible. */
260 ret = runtime_callers (skip, locbuf, pc.__count, false);
262 for (i = 0; i < ret; i++)
263 ((uintptr *) pc.__values)[i] = locbuf[i].pc;
265 return ret;
268 struct callersRaw_data
270 uintptr* pcbuf;
271 int index;
272 int max;
275 // Callback function for backtrace_simple. Just collect pc's.
276 // Return zero to continue, non-zero to stop.
278 static int callback_raw (void *data, uintptr_t pc)
280 struct callersRaw_data *arg = (struct callersRaw_data *) data;
282 /* On the call to backtrace_simple the pc value was most likely
283 decremented if there was a normal call, since the pc referred to
284 the instruction where the call returned and not the call itself.
285 This was done so that the line number referred to the call
286 instruction. To make sure the actual pc from the call stack is
287 used, it is incremented here.
289 In the case of a signal, the pc was not decremented by
290 backtrace_full but still incremented here. That doesn't really
291 hurt anything since the line number is right and the pc refers to
292 the same instruction. */
294 arg->pcbuf[arg->index] = pc + 1;
295 arg->index++;
296 return arg->index >= arg->max;
299 /* runtime_callersRaw is similar to runtime_callers() above, but
300 it returns raw PC values as opposed to file/func/line locations. */
301 int32
302 runtime_callersRaw (uintptr *pcbuf, int32 m)
304 struct callersRaw_data data;
305 struct backtrace_state* state;
307 data.pcbuf = pcbuf;
308 data.index = 0;
309 data.max = m;
310 runtime_xadd (&__go_runtime_in_callers, 1);
311 state = __go_get_backtrace_state ();
312 backtrace_simple (state, 0, callback_raw, error_callback, &data);
313 runtime_xadd (&__go_runtime_in_callers, -1);
315 return data.index;