Add support for ARMv8-R architecture
[official-gcc.git] / libgo / runtime / go-callers.c
blob09def91b1e80bbd7d31006faa4907e1a2247fe35
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 = __builtin_strchr (function, '.');
72 if (p != NULL && __builtin_strncmp (p + 1, "$thunk", 6) == 0)
73 return 0;
74 p = __builtin_strrchr (function, '$');
75 if (p != NULL && __builtin_strcmp(p, "$recover") == 0)
76 return 0;
77 if (p != NULL && __builtin_strncmp(p, "$stub", 5) == 0)
78 return 0;
81 if (arg->skip > 0)
83 --arg->skip;
84 return 0;
87 loc = &arg->locbuf[arg->index];
89 /* On the call to backtrace_full the pc value was most likely
90 decremented if there was a normal call, since the pc referred to
91 the instruction where the call returned and not the call itself.
92 This was done so that the line number referred to the call
93 instruction. To make sure the actual pc from the call stack is
94 used, it is incremented here.
96 In the case of a signal, the pc was not decremented by
97 backtrace_full but still incremented here. That doesn't really
98 hurt anything since the line number is right and the pc refers to
99 the same instruction. */
101 loc->pc = pc + 1;
103 /* The libbacktrace library says that these strings might disappear,
104 but with the current implementation they won't. We can't easily
105 allocate memory here, so for now assume that we can save a
106 pointer to the strings. */
107 loc->filename = runtime_gostringnocopy ((const byte *) filename);
108 loc->function = runtime_gostringnocopy ((const byte *) function);
110 loc->lineno = lineno;
111 ++arg->index;
113 /* There is no point to tracing past certain runtime functions.
114 Stopping the backtrace here can avoid problems on systems that
115 don't provide proper unwind information for makecontext, such as
116 Solaris (http://gcc.gnu.org/PR52583 comment #21). */
117 if (function != NULL)
119 if (__builtin_strcmp (function, "makecontext") == 0)
120 return 1;
121 if (filename != NULL)
123 const char *p;
125 p = strrchr (filename, '/');
126 if (p == NULL)
127 p = filename;
128 if (__builtin_strcmp (p, "/proc.c") == 0)
130 if (__builtin_strcmp (function, "kickoff") == 0
131 || __builtin_strcmp (function, "runtime.mstart") == 0
132 || __builtin_strcmp (function, "runtime.main") == 0)
133 return 1;
138 return arg->index >= arg->max;
141 /* Error callback. */
143 static void
144 error_callback (void *data __attribute__ ((unused)),
145 const char *msg, int errnum)
147 if (errnum == -1)
149 /* No debug info available. Carry on as best we can. */
150 return;
152 if (errnum != 0)
153 runtime_printf ("%s errno %d\n", msg, errnum);
154 runtime_throw (msg);
157 /* Return whether we are already collecting a stack trace. This is
158 called from the signal handler. */
160 bool alreadyInCallers(void)
161 __attribute__ ((no_split_stack));
162 bool alreadyInCallers(void)
163 __asm__ (GOSYM_PREFIX "runtime.alreadyInCallers");
165 bool
166 alreadyInCallers()
168 return runtime_atomicload(&runtime_in_callers) > 0;
171 /* Gather caller PC's. */
173 int32
174 runtime_callers (int32 skip, Location *locbuf, int32 m, bool keep_thunks)
176 struct callers_data data;
178 data.locbuf = locbuf;
179 data.skip = skip + 1;
180 data.index = 0;
181 data.max = m;
182 data.keep_thunks = keep_thunks;
183 runtime_xadd (&runtime_in_callers, 1);
184 backtrace_full (__go_get_backtrace_state (), 0, callback, error_callback,
185 &data);
186 runtime_xadd (&runtime_in_callers, -1);
187 return data.index;
190 int Callers (int, struct __go_open_array)
191 __asm__ (GOSYM_PREFIX "runtime.Callers");
194 Callers (int skip, struct __go_open_array pc)
196 Location *locbuf;
197 int ret;
198 int i;
200 /* Note that calling mallocgc here assumes that we are not going to
201 store any allocated Go pointers in the slice. */
202 locbuf = (Location *) runtime_mallocgc (pc.__count * sizeof (Location),
203 nil, false);
205 /* In the Go 1 release runtime.Callers has an off-by-one error,
206 which we can not correct because it would break backward
207 compatibility. Normally we would add 1 to SKIP here, but we
208 don't so that we are compatible. */
209 ret = runtime_callers (skip, locbuf, pc.__count, false);
211 for (i = 0; i < ret; i++)
212 ((uintptr *) pc.__values)[i] = locbuf[i].pc;
214 return ret;