Fix "PR c++/92804 ICE trying to use concept as a nested-name-specifier"
[official-gcc.git] / libgo / runtime / go-caller.c
bloba18787671d1f89cf305e8b82b4e812150f10f5ae
1 /* go-caller.c -- look up function/file/line/entry info
3 Copyright 2009 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 /* Implement runtime.Caller. */
9 #include <stdint.h>
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <unistd.h>
14 #include "backtrace.h"
16 #include "runtime.h"
18 /* Get the function name, file name, and line number for a PC value.
19 We use the backtrace library to get this. */
21 /* Data structure to gather file/line information. */
23 struct caller
25 String fn;
26 String file;
27 intgo line;
28 intgo index;
29 intgo frames;
30 bool more;
33 /* Collect file/line information for a PC value. If this is called
34 more than once, due to inlined functions, we record the number of
35 inlined frames but return file/func/line for the last call, as
36 that is usually the most useful one. */
38 static int
39 callback (void *data, uintptr_t pc __attribute__ ((unused)),
40 const char *filename, int lineno, const char *function)
42 struct caller *c = (struct caller *) data;
44 /* We want to make sure we return at least one frame. If we already
45 have at least one frame, see if we should skip this one. */
46 if (c->frames > 0
47 && function != NULL
48 && runtime_skipInCallback (function, NULL))
49 return 0;
51 /* If we already have a frame, don't increment frames if we should
52 skip that one. */
53 if (c->frames == 0
54 || c->fn.len == 0
55 || !runtime_skipInCallback ((const char *) c->fn.str, NULL))
56 c->frames++;
58 /* The libbacktrace library says that these strings might disappear,
59 but with the current implementation they won't. We can't easily
60 allocate memory here, so for now assume that we can save a
61 pointer to the strings. */
62 c->fn = runtime_gostringnocopy ((const byte *) function);
63 c->file = runtime_gostringnocopy ((const byte *) filename);
64 c->line = lineno;
66 if (c->index == 0)
68 /* If there are more frames after the indexed one, and we should
69 skip this one, then skip it. */
70 if (c->more
71 && c->fn.len > 0
72 && runtime_skipInCallback((const char *) c->fn.str, NULL))
73 return 0;
75 return 1;
78 if (c->index > 0)
79 --c->index;
81 return 0;
84 /* The error callback for backtrace_pcinfo and backtrace_syminfo. */
86 static void
87 error_callback (void *data __attribute__ ((unused)),
88 const char *msg, int errnum)
90 if (errnum == -1)
91 return;
92 if (errnum > 0)
93 runtime_printf ("%s errno %d\n", msg, errnum);
94 runtime_throw (msg);
97 /* The backtrace library state. */
99 static void *back_state;
101 /* A lock to control creating back_state. */
103 static uint32 back_state_lock;
105 /* The program arguments. */
107 extern Slice runtime_get_args(void);
109 /* Fetch back_state, creating it if necessary. */
111 struct backtrace_state *
112 __go_get_backtrace_state ()
114 uint32 set;
116 /* We may not have a g here, so we can't use runtime_lock. */
117 set = 0;
118 while (!__atomic_compare_exchange_n (&back_state_lock, &set, 1, false, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED))
120 runtime_osyield ();
121 set = 0;
123 if (back_state == NULL)
125 Slice args;
126 const char *filename;
127 struct stat s;
129 args = runtime_get_args();
130 filename = NULL;
131 if (args.__count > 0)
132 filename = (const char*)((String*)args.__values)[0].str;
134 /* If there is no '/' in FILENAME, it was found on PATH, and
135 might not be the same as the file with the same name in the
136 current directory. */
137 if (filename != NULL && __builtin_strchr (filename, '/') == NULL)
138 filename = NULL;
140 /* If the file is small, then it's not the real executable.
141 This is specifically to deal with Docker, which uses a bogus
142 argv[0] (http://gcc.gnu.org/PR61895). It would be nice to
143 have a better check for whether this file is the real
144 executable. */
145 if (filename != NULL && (stat (filename, &s) < 0 || s.st_size < 1024))
146 filename = NULL;
148 back_state = backtrace_create_state (filename, 1, error_callback, NULL);
150 __atomic_store_n (&back_state_lock, 0, __ATOMIC_RELEASE);
151 return back_state;
154 /* Return function/file/line/nframes information for PC. The index
155 parameter is the entry on the stack of inlined functions; -1 means
156 the last one, with *nframes set to the count of inlined frames for
157 this PC. If index is not -1, more is whether there are more frames
158 after this one. */
160 static _Bool
161 __go_file_line (uintptr pc, int index, bool more, String *fn, String *file, intgo *line, intgo *nframes)
163 struct caller c;
164 struct backtrace_state *state;
166 runtime_memclr (&c, sizeof c);
167 c.index = index;
168 c.more = more;
169 c.frames = 0;
170 runtime_xadd (&__go_runtime_in_callers, 1);
171 state = __go_get_backtrace_state ();
172 runtime_xadd (&__go_runtime_in_callers, -1);
173 backtrace_pcinfo (state, pc, callback, error_callback, &c);
174 *fn = c.fn;
175 *file = c.file;
176 *line = c.line;
177 *nframes = c.frames;
179 // If backtrace_pcinfo didn't get the function name from the debug
180 // info, try to get it from the symbol table.
181 if (fn->len == 0)
182 backtrace_syminfo (state, pc, __go_syminfo_fnname_callback,
183 error_callback, fn);
185 return c.file.len > 0;
188 /* Collect symbol information. */
190 static void
191 syminfo_callback (void *data, uintptr_t pc __attribute__ ((unused)),
192 const char *symname __attribute__ ((unused)),
193 uintptr_t address, uintptr_t size __attribute__ ((unused)))
195 uintptr_t *pval = (uintptr_t *) data;
197 *pval = address;
200 /* Set *VAL to the value of the symbol for PC. */
202 static _Bool
203 __go_symbol_value (uintptr pc, uintptr *val)
205 struct backtrace_state *state;
207 *val = 0;
208 runtime_xadd (&__go_runtime_in_callers, 1);
209 state = __go_get_backtrace_state ();
210 runtime_xadd (&__go_runtime_in_callers, -1);
211 backtrace_syminfo (state, pc, syminfo_callback,
212 error_callback, val);
213 return *val != 0;
216 /* The values returned by runtime.Caller. */
218 struct caller_ret
220 uintptr_t pc;
221 String file;
222 intgo line;
223 _Bool ok;
226 struct caller_ret Caller (intgo n) __asm__ (GOSYM_PREFIX "runtime.Caller");
228 /* Implement runtime.Caller. */
230 struct caller_ret
231 Caller (intgo skip)
233 struct caller_ret ret;
234 Location loc;
235 int32 n;
237 runtime_memclr (&ret, sizeof ret);
238 n = runtime_callers (skip + 1, &loc, 1, false);
239 if (n < 1 || loc.pc == 0)
240 return ret;
241 ret.pc = loc.pc;
242 ret.file = loc.filename;
243 ret.line = loc.lineno;
244 ret.ok = 1;
245 return ret;
248 /* Look up the function name, file name, and line number for a PC. */
250 struct funcfileline_return
251 runtime_funcfileline (uintptr targetpc, int32 index, bool more)
253 struct funcfileline_return ret;
255 if (!__go_file_line (targetpc, index, more, &ret.retfn, &ret.retfile,
256 &ret.retline, &ret.retframes))
257 runtime_memclr (&ret, sizeof ret);
258 return ret;
261 /* Return the entry point of a function. */
262 uintptr runtime_funcentry(uintptr)
263 __asm__ (GOSYM_PREFIX "runtime.funcentry");
265 uintptr
266 runtime_funcentry (uintptr pc)
268 uintptr val;
270 if (!__go_symbol_value (pc, &val))
271 return 0;
272 return val;