]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgo/runtime/go-caller.c
libgo: update to Go1.14beta1
[thirdparty/gcc.git] / libgo / runtime / go-caller.c
CommitLineData
db2fb304 1/* go-caller.c -- look up function/file/line/entry info
7a938933
ILT
2
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. */
6
7/* Implement runtime.Caller. */
8
9#include <stdint.h>
dc14e88e
ILT
10#include <sys/types.h>
11#include <sys/stat.h>
12#include <unistd.h>
7a938933 13
0e56e590
ILT
14#include "backtrace.h"
15
0effc3f9 16#include "runtime.h"
7a938933 17
0effc3f9 18/* Get the function name, file name, and line number for a PC value.
0e56e590
ILT
19 We use the backtrace library to get this. */
20
21/* Data structure to gather file/line information. */
22
23struct caller
24{
776f27a6
ILT
25 String fn;
26 String file;
27 intgo line;
22b955cc 28 intgo index;
1ac09ef2 29 intgo frames;
5a8ea165 30 bool more;
0e56e590
ILT
31};
32
33/* Collect file/line information for a PC value. If this is called
1ac09ef2
ILT
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. */
0e56e590
ILT
37
38static int
39callback (void *data, uintptr_t pc __attribute__ ((unused)),
40 const char *filename, int lineno, const char *function)
41{
42 struct caller *c = (struct caller *) data;
43
5a8ea165
ILT
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;
50
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++;
1ac09ef2 57
4729d772
ILT
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);
0e56e590
ILT
64 c->line = lineno;
65
22b955cc 66 if (c->index == 0)
5a8ea165
ILT
67 {
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;
74
75 return 1;
76 }
22b955cc
ILT
77
78 if (c->index > 0)
79 --c->index;
80
0e56e590
ILT
81 return 0;
82}
0effc3f9 83
0e56e590 84/* The error callback for backtrace_pcinfo and backtrace_syminfo. */
0effc3f9 85
0e56e590
ILT
86static void
87error_callback (void *data __attribute__ ((unused)),
88 const char *msg, int errnum)
89{
90 if (errnum == -1)
91 return;
92 if (errnum > 0)
93 runtime_printf ("%s errno %d\n", msg, errnum);
94 runtime_throw (msg);
95}
96
97/* The backtrace library state. */
0effc3f9 98
0e56e590 99static void *back_state;
0effc3f9 100
0e56e590 101/* A lock to control creating back_state. */
0effc3f9 102
df206c6e 103static uint32 back_state_lock;
0effc3f9 104
67487878
ILT
105/* The program arguments. */
106
107extern Slice runtime_get_args(void);
108
0e56e590 109/* Fetch back_state, creating it if necessary. */
0effc3f9 110
0e56e590
ILT
111struct backtrace_state *
112__go_get_backtrace_state ()
0effc3f9 113{
df206c6e
ILT
114 uint32 set;
115
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))
119 {
120 runtime_osyield ();
121 set = 0;
122 }
0e56e590 123 if (back_state == NULL)
686750d2 124 {
67487878 125 Slice args;
686750d2 126 const char *filename;
dc14e88e 127 struct stat s;
686750d2 128
67487878
ILT
129 args = runtime_get_args();
130 filename = NULL;
131 if (args.__count > 0)
132 filename = (const char*)((String*)args.__values)[0].str;
37512c03
ILT
133
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. */
67487878 137 if (filename != NULL && __builtin_strchr (filename, '/') == NULL)
37512c03
ILT
138 filename = NULL;
139
dc14e88e
ILT
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. */
94e12bd4 145 if (filename != NULL && (stat (filename, &s) < 0 || s.st_size < 1024))
dc14e88e
ILT
146 filename = NULL;
147
686750d2
ILT
148 back_state = backtrace_create_state (filename, 1, error_callback, NULL);
149 }
df206c6e 150 __atomic_store_n (&back_state_lock, 0, __ATOMIC_RELEASE);
0e56e590 151 return back_state;
0effc3f9
ILT
152}
153
5a8ea165
ILT
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. */
0effc3f9 159
afedc99b 160static _Bool
5a8ea165 161__go_file_line (uintptr pc, int index, bool more, String *fn, String *file, intgo *line, intgo *nframes)
0effc3f9 162{
0e56e590 163 struct caller c;
afedc99b 164 struct backtrace_state *state;
0e56e590
ILT
165
166 runtime_memclr (&c, sizeof c);
22b955cc 167 c.index = index;
5a8ea165 168 c.more = more;
1ac09ef2 169 c.frames = 0;
f6be1179 170 runtime_xadd (&__go_runtime_in_callers, 1);
afedc99b 171 state = __go_get_backtrace_state ();
f6be1179 172 runtime_xadd (&__go_runtime_in_callers, -1);
afedc99b 173 backtrace_pcinfo (state, pc, callback, error_callback, &c);
0e56e590
ILT
174 *fn = c.fn;
175 *file = c.file;
176 *line = c.line;
1ac09ef2 177 *nframes = c.frames;
afedc99b
ILT
178
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);
184
776f27a6 185 return c.file.len > 0;
0effc3f9
ILT
186}
187
0e56e590 188/* Collect symbol information. */
0effc3f9 189
0e56e590
ILT
190static void
191syminfo_callback (void *data, uintptr_t pc __attribute__ ((unused)),
192 const char *symname __attribute__ ((unused)),
92495ff6 193 uintptr_t address, uintptr_t size __attribute__ ((unused)))
0e56e590
ILT
194{
195 uintptr_t *pval = (uintptr_t *) data;
196
197 *pval = address;
198}
199
200/* Set *VAL to the value of the symbol for PC. */
201
202static _Bool
3ff1b2b0 203__go_symbol_value (uintptr pc, uintptr *val)
0effc3f9 204{
f6be1179
ILT
205 struct backtrace_state *state;
206
0e56e590 207 *val = 0;
f6be1179
ILT
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,
fb521d54 212 error_callback, val);
0e56e590 213 return *val != 0;
0effc3f9
ILT
214}
215
7a938933
ILT
216/* The values returned by runtime.Caller. */
217
218struct caller_ret
219{
220 uintptr_t pc;
776f27a6
ILT
221 String file;
222 intgo line;
7a938933
ILT
223 _Bool ok;
224};
225
8a9f2a6b 226struct caller_ret Caller (intgo n) __asm__ (GOSYM_PREFIX "runtime.Caller");
7a938933 227
0effc3f9
ILT
228/* Implement runtime.Caller. */
229
7a938933 230struct caller_ret
8a9f2a6b 231Caller (intgo skip)
7a938933
ILT
232{
233 struct caller_ret ret;
27741f93 234 Location loc;
0effc3f9 235 int32 n;
7a938933 236
0effc3f9 237 runtime_memclr (&ret, sizeof ret);
dffa7328 238 n = runtime_callers (skip + 1, &loc, 1, false);
46f120ca 239 if (n < 1 || loc.pc == 0)
0effc3f9 240 return ret;
27741f93
ILT
241 ret.pc = loc.pc;
242 ret.file = loc.filename;
243 ret.line = loc.lineno;
92aecb44 244 ret.ok = 1;
7a938933
ILT
245 return ret;
246}
247
db2fb304 248/* Look up the function name, file name, and line number for a PC. */
7a938933 249
db2fb304 250struct funcfileline_return
5a8ea165 251runtime_funcfileline (uintptr targetpc, int32 index, bool more)
0effc3f9 252{
db2fb304 253 struct funcfileline_return ret;
0effc3f9 254
5a8ea165 255 if (!__go_file_line (targetpc, index, more, &ret.retfn, &ret.retfile,
1ac09ef2 256 &ret.retline, &ret.retframes))
0effc3f9
ILT
257 runtime_memclr (&ret, sizeof ret);
258 return ret;
7a938933 259}
f038dae6 260
f038dae6 261/* Return the entry point of a function. */
db2fb304
ILT
262uintptr runtime_funcentry(uintptr)
263 __asm__ (GOSYM_PREFIX "runtime.funcentry");
f038dae6
ILT
264
265uintptr
db2fb304 266runtime_funcentry (uintptr pc)
f038dae6 267{
db2fb304 268 uintptr val;
22b955cc 269
db2fb304
ILT
270 if (!__go_symbol_value (pc, &val))
271 return 0;
272 return val;
22b955cc 273}