[Ada] Issue error on illegal ownership in SPARK
[official-gcc.git] / libgo / runtime / go-caller.c
blob5e31f912e0ae761ae3274f3a7e453f3284d14fff
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;
32 /* Collect file/line information for a PC value. If this is called
33 more than once, due to inlined functions, we record the number of
34 inlined frames but return file/func/line for the last call, as
35 that is usually the most useful one. */
37 static int
38 callback (void *data, uintptr_t pc __attribute__ ((unused)),
39 const char *filename, int lineno, const char *function)
41 struct caller *c = (struct caller *) data;
43 c->frames++;
45 /* The libbacktrace library says that these strings might disappear,
46 but with the current implementation they won't. We can't easily
47 allocate memory here, so for now assume that we can save a
48 pointer to the strings. */
49 c->fn = runtime_gostringnocopy ((const byte *) function);
50 c->file = runtime_gostringnocopy ((const byte *) filename);
51 c->line = lineno;
53 if (c->index == 0)
54 return 1;
56 if (c->index > 0)
57 --c->index;
59 return 0;
62 /* The error callback for backtrace_pcinfo and backtrace_syminfo. */
64 static void
65 error_callback (void *data __attribute__ ((unused)),
66 const char *msg, int errnum)
68 if (errnum == -1)
69 return;
70 if (errnum > 0)
71 runtime_printf ("%s errno %d\n", msg, errnum);
72 runtime_throw (msg);
75 /* The backtrace library state. */
77 static void *back_state;
79 /* A lock to control creating back_state. */
81 static uint32 back_state_lock;
83 /* The program arguments. */
85 extern Slice runtime_get_args(void);
87 /* Fetch back_state, creating it if necessary. */
89 struct backtrace_state *
90 __go_get_backtrace_state ()
92 uint32 set;
94 /* We may not have a g here, so we can't use runtime_lock. */
95 set = 0;
96 while (!__atomic_compare_exchange_n (&back_state_lock, &set, 1, false, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED))
98 runtime_osyield ();
99 set = 0;
101 if (back_state == NULL)
103 Slice args;
104 const char *filename;
105 struct stat s;
107 args = runtime_get_args();
108 filename = NULL;
109 if (args.__count > 0)
110 filename = (const char*)((String*)args.__values)[0].str;
112 /* If there is no '/' in FILENAME, it was found on PATH, and
113 might not be the same as the file with the same name in the
114 current directory. */
115 if (filename != NULL && __builtin_strchr (filename, '/') == NULL)
116 filename = NULL;
118 /* If the file is small, then it's not the real executable.
119 This is specifically to deal with Docker, which uses a bogus
120 argv[0] (http://gcc.gnu.org/PR61895). It would be nice to
121 have a better check for whether this file is the real
122 executable. */
123 if (filename != NULL && (stat (filename, &s) < 0 || s.st_size < 1024))
124 filename = NULL;
126 back_state = backtrace_create_state (filename, 1, error_callback, NULL);
128 __atomic_store_n (&back_state_lock, 0, __ATOMIC_RELEASE);
129 return back_state;
132 /* Return function/file/line/nframes information for PC. The index parameter
133 is the entry on the stack of inlined functions; -1 means the last
134 one, with *nframes set to the count of inlined frames for this PC. */
136 static _Bool
137 __go_file_line (uintptr pc, int index, String *fn, String *file, intgo *line, intgo *nframes)
139 struct caller c;
140 struct backtrace_state *state;
142 runtime_memclr (&c, sizeof c);
143 c.index = index;
144 c.frames = 0;
145 runtime_xadd (&__go_runtime_in_callers, 1);
146 state = __go_get_backtrace_state ();
147 runtime_xadd (&__go_runtime_in_callers, -1);
148 backtrace_pcinfo (state, pc, callback, error_callback, &c);
149 *fn = c.fn;
150 *file = c.file;
151 *line = c.line;
152 *nframes = c.frames;
154 // If backtrace_pcinfo didn't get the function name from the debug
155 // info, try to get it from the symbol table.
156 if (fn->len == 0)
157 backtrace_syminfo (state, pc, __go_syminfo_fnname_callback,
158 error_callback, fn);
160 return c.file.len > 0;
163 /* Collect symbol information. */
165 static void
166 syminfo_callback (void *data, uintptr_t pc __attribute__ ((unused)),
167 const char *symname __attribute__ ((unused)),
168 uintptr_t address, uintptr_t size __attribute__ ((unused)))
170 uintptr_t *pval = (uintptr_t *) data;
172 *pval = address;
175 /* Set *VAL to the value of the symbol for PC. */
177 static _Bool
178 __go_symbol_value (uintptr pc, uintptr *val)
180 struct backtrace_state *state;
182 *val = 0;
183 runtime_xadd (&__go_runtime_in_callers, 1);
184 state = __go_get_backtrace_state ();
185 runtime_xadd (&__go_runtime_in_callers, -1);
186 backtrace_syminfo (state, pc, syminfo_callback,
187 error_callback, val);
188 return *val != 0;
191 /* The values returned by runtime.Caller. */
193 struct caller_ret
195 uintptr_t pc;
196 String file;
197 intgo line;
198 _Bool ok;
201 struct caller_ret Caller (intgo n) __asm__ (GOSYM_PREFIX "runtime.Caller");
203 /* Implement runtime.Caller. */
205 struct caller_ret
206 Caller (intgo skip)
208 struct caller_ret ret;
209 Location loc;
210 int32 n;
212 runtime_memclr (&ret, sizeof ret);
213 n = runtime_callers (skip + 1, &loc, 1, false);
214 if (n < 1 || loc.pc == 0)
215 return ret;
216 ret.pc = loc.pc;
217 ret.file = loc.filename;
218 ret.line = loc.lineno;
219 ret.ok = 1;
220 return ret;
223 /* Look up the function name, file name, and line number for a PC. */
225 struct funcfileline_return
226 runtime_funcfileline (uintptr targetpc, int32 index)
228 struct funcfileline_return ret;
230 if (!__go_file_line (targetpc, index, &ret.retfn, &ret.retfile,
231 &ret.retline, &ret.retframes))
232 runtime_memclr (&ret, sizeof ret);
233 return ret;
236 /* Return the entry point of a function. */
237 uintptr runtime_funcentry(uintptr)
238 __asm__ (GOSYM_PREFIX "runtime.funcentry");
240 uintptr
241 runtime_funcentry (uintptr pc)
243 uintptr val;
245 if (!__go_symbol_value (pc, &val))
246 return 0;
247 return val;