blob: f1077df6b774ce71ca2282ebec75748d450e16e0 [file] [log] [blame]
Ian Lance Taylor99384062016-10-14 09:21:16 -07001/* go-caller.c -- look up function/file/line/entry info
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -08002
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>
Ian Lance Taylor088a1092014-08-01 17:43:51 -070010#include <sys/types.h>
11#include <sys/stat.h>
12#include <unistd.h>
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -080013
Ian Lance Taylor72b878e2012-09-28 07:26:19 -070014#include "backtrace.h"
15
Ian Lance Taylor8267f1d2012-03-06 17:06:46 -080016#include "runtime.h"
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -080017
Ian Lance Taylor8267f1d2012-03-06 17:06:46 -080018/* Get the function name, file name, and line number for a PC value.
Ian Lance Taylor72b878e2012-09-28 07:26:19 -070019 We use the backtrace library to get this. */
Ian Lance Taylor8267f1d2012-03-06 17:06:46 -080020
Ian Lance Taylor72b878e2012-09-28 07:26:19 -070021/* Data structure to gather file/line information. */
Ian Lance Taylor8267f1d2012-03-06 17:06:46 -080022
Ian Lance Taylor72b878e2012-09-28 07:26:19 -070023struct caller
Ian Lance Taylor8267f1d2012-03-06 17:06:46 -080024{
Ian Lance Taylor6516c342012-10-31 19:57:58 -070025 String fn;
26 String file;
27 intgo line;
Ian Lance Taylorb156d712016-07-22 07:41:34 -070028 intgo index;
Than McIntosh6112f9b2019-04-10 14:42:24 -040029 intgo frames;
Ian Lance Taylorc2225a72020-01-02 15:05:27 -080030 bool more;
Ian Lance Taylor72b878e2012-09-28 07:26:19 -070031};
32
33/* Collect file/line information for a PC value. If this is called
Than McIntosh6112f9b2019-04-10 14:42:24 -040034 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. */
Ian Lance Taylor72b878e2012-09-28 07:26:19 -070037
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
Ian Lance Taylorc2225a72020-01-02 15:05:27 -080044 /* 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++;
Than McIntosh6112f9b2019-04-10 14:42:24 -040057
Ian Lance Taylorc7f54082015-03-09 16:36:59 -070058 /* 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);
Ian Lance Taylor72b878e2012-09-28 07:26:19 -070064 c->line = lineno;
65
Ian Lance Taylorb156d712016-07-22 07:41:34 -070066 if (c->index == 0)
Ian Lance Taylorc2225a72020-01-02 15:05:27 -080067 {
Ian Lance Taylor49b07692020-12-23 09:57:37 -080068 /* If we should skip the frame we have, then see if we can get
69 another one. */
70 if (c->fn.len > 0
Ian Lance Taylorc2225a72020-01-02 15:05:27 -080071 && runtime_skipInCallback((const char *) c->fn.str, NULL))
72 return 0;
73
74 return 1;
75 }
Ian Lance Taylorb156d712016-07-22 07:41:34 -070076
77 if (c->index > 0)
78 --c->index;
79
Ian Lance Taylor72b878e2012-09-28 07:26:19 -070080 return 0;
81}
82
83/* The error callback for backtrace_pcinfo and backtrace_syminfo. */
84
85static void
86error_callback (void *data __attribute__ ((unused)),
87 const char *msg, int errnum)
88{
89 if (errnum == -1)
90 return;
91 if (errnum > 0)
92 runtime_printf ("%s errno %d\n", msg, errnum);
93 runtime_throw (msg);
94}
95
96/* The backtrace library state. */
97
98static void *back_state;
99
100/* A lock to control creating back_state. */
101
Ian Lance Taylorb712bac2017-07-21 10:12:24 -0700102static uint32 back_state_lock;
Ian Lance Taylor72b878e2012-09-28 07:26:19 -0700103
Ian Lance Taylore51657a2016-09-28 16:44:01 -0700104/* The program arguments. */
105
106extern Slice runtime_get_args(void);
107
Ian Lance Taylor72b878e2012-09-28 07:26:19 -0700108/* Fetch back_state, creating it if necessary. */
109
110struct backtrace_state *
111__go_get_backtrace_state ()
112{
Ian Lance Taylorb712bac2017-07-21 10:12:24 -0700113 uint32 set;
114
115 /* We may not have a g here, so we can't use runtime_lock. */
116 set = 0;
117 while (!__atomic_compare_exchange_n (&back_state_lock, &set, 1, false, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED))
118 {
119 runtime_osyield ();
120 set = 0;
121 }
Ian Lance Taylor72b878e2012-09-28 07:26:19 -0700122 if (back_state == NULL)
Ian Lance Taylor3084cfc2012-10-05 06:41:53 -0700123 {
Ian Lance Taylore51657a2016-09-28 16:44:01 -0700124 Slice args;
Ian Lance Taylor3084cfc2012-10-05 06:41:53 -0700125 const char *filename;
Ian Lance Taylor088a1092014-08-01 17:43:51 -0700126 struct stat s;
Ian Lance Taylor3084cfc2012-10-05 06:41:53 -0700127
Ian Lance Taylore51657a2016-09-28 16:44:01 -0700128 args = runtime_get_args();
129 filename = NULL;
130 if (args.__count > 0)
131 filename = (const char*)((String*)args.__values)[0].str;
Ian Lance Taylor77b809e2013-11-14 14:29:49 -0800132
133 /* If there is no '/' in FILENAME, it was found on PATH, and
134 might not be the same as the file with the same name in the
135 current directory. */
Ian Lance Taylore51657a2016-09-28 16:44:01 -0700136 if (filename != NULL && __builtin_strchr (filename, '/') == NULL)
Ian Lance Taylor77b809e2013-11-14 14:29:49 -0800137 filename = NULL;
138
Ian Lance Taylor088a1092014-08-01 17:43:51 -0700139 /* If the file is small, then it's not the real executable.
140 This is specifically to deal with Docker, which uses a bogus
141 argv[0] (http://gcc.gnu.org/PR61895). It would be nice to
142 have a better check for whether this file is the real
143 executable. */
Ian Lance Taylore1fcce02018-06-28 12:14:12 -0700144 if (filename != NULL && (stat (filename, &s) < 0 || s.st_size < 1024))
Ian Lance Taylor088a1092014-08-01 17:43:51 -0700145 filename = NULL;
146
Ian Lance Taylor3084cfc2012-10-05 06:41:53 -0700147 back_state = backtrace_create_state (filename, 1, error_callback, NULL);
148 }
Ian Lance Taylorb712bac2017-07-21 10:12:24 -0700149 __atomic_store_n (&back_state_lock, 0, __ATOMIC_RELEASE);
Ian Lance Taylor72b878e2012-09-28 07:26:19 -0700150 return back_state;
Ian Lance Taylor8267f1d2012-03-06 17:06:46 -0800151}
152
Ian Lance Taylorc2225a72020-01-02 15:05:27 -0800153/* Return function/file/line/nframes information for PC. The index
154 parameter is the entry on the stack of inlined functions; -1 means
155 the last one, with *nframes set to the count of inlined frames for
156 this PC. If index is not -1, more is whether there are more frames
157 after this one. */
Ian Lance Taylor8267f1d2012-03-06 17:06:46 -0800158
Ian Lance Taylored8647c2018-02-21 17:29:47 -0800159static _Bool
Ian Lance Taylorc2225a72020-01-02 15:05:27 -0800160__go_file_line (uintptr pc, int index, bool more, String *fn, String *file, intgo *line, intgo *nframes)
Ian Lance Taylor8267f1d2012-03-06 17:06:46 -0800161{
Ian Lance Taylor72b878e2012-09-28 07:26:19 -0700162 struct caller c;
Ian Lance Taylored8647c2018-02-21 17:29:47 -0800163 struct backtrace_state *state;
Ian Lance Taylor72b878e2012-09-28 07:26:19 -0700164
165 runtime_memclr (&c, sizeof c);
Ian Lance Taylorb156d712016-07-22 07:41:34 -0700166 c.index = index;
Ian Lance Taylorc2225a72020-01-02 15:05:27 -0800167 c.more = more;
Than McIntosh6112f9b2019-04-10 14:42:24 -0400168 c.frames = 0;
Cherry Zhang2ce291e2018-12-30 22:21:25 -0500169 runtime_xadd (&__go_runtime_in_callers, 1);
Ian Lance Taylored8647c2018-02-21 17:29:47 -0800170 state = __go_get_backtrace_state ();
Cherry Zhang2ce291e2018-12-30 22:21:25 -0500171 runtime_xadd (&__go_runtime_in_callers, -1);
Ian Lance Taylored8647c2018-02-21 17:29:47 -0800172 backtrace_pcinfo (state, pc, callback, error_callback, &c);
Ian Lance Taylor72b878e2012-09-28 07:26:19 -0700173 *fn = c.fn;
174 *file = c.file;
175 *line = c.line;
Than McIntosh6112f9b2019-04-10 14:42:24 -0400176 *nframes = c.frames;
Ian Lance Taylored8647c2018-02-21 17:29:47 -0800177
178 // If backtrace_pcinfo didn't get the function name from the debug
179 // info, try to get it from the symbol table.
180 if (fn->len == 0)
181 backtrace_syminfo (state, pc, __go_syminfo_fnname_callback,
182 error_callback, fn);
183
Ian Lance Taylor6516c342012-10-31 19:57:58 -0700184 return c.file.len > 0;
Ian Lance Taylor8267f1d2012-03-06 17:06:46 -0800185}
186
Ian Lance Taylor72b878e2012-09-28 07:26:19 -0700187/* Collect symbol information. */
Ian Lance Taylor8267f1d2012-03-06 17:06:46 -0800188
Ian Lance Taylor72b878e2012-09-28 07:26:19 -0700189static void
190syminfo_callback (void *data, uintptr_t pc __attribute__ ((unused)),
191 const char *symname __attribute__ ((unused)),
Ian Lance Taylor1cf820e2013-11-19 07:02:05 -0800192 uintptr_t address, uintptr_t size __attribute__ ((unused)))
Ian Lance Taylor8267f1d2012-03-06 17:06:46 -0800193{
Ian Lance Taylor72b878e2012-09-28 07:26:19 -0700194 uintptr_t *pval = (uintptr_t *) data;
195
196 *pval = address;
197}
198
199/* Set *VAL to the value of the symbol for PC. */
200
201static _Bool
Tony Reixaf46ad12017-10-11 11:04:53 +0200202__go_symbol_value (uintptr pc, uintptr *val)
Ian Lance Taylor72b878e2012-09-28 07:26:19 -0700203{
Cherry Zhang2ce291e2018-12-30 22:21:25 -0500204 struct backtrace_state *state;
205
Ian Lance Taylor72b878e2012-09-28 07:26:19 -0700206 *val = 0;
Cherry Zhang2ce291e2018-12-30 22:21:25 -0500207 runtime_xadd (&__go_runtime_in_callers, 1);
208 state = __go_get_backtrace_state ();
209 runtime_xadd (&__go_runtime_in_callers, -1);
210 backtrace_syminfo (state, pc, syminfo_callback,
Ian Lance Taylor8d71d302012-10-07 21:29:09 -0700211 error_callback, val);
Ian Lance Taylor72b878e2012-09-28 07:26:19 -0700212 return *val != 0;
Ian Lance Taylor8267f1d2012-03-06 17:06:46 -0800213}
214
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -0800215/* The values returned by runtime.Caller. */
216
217struct caller_ret
218{
219 uintptr_t pc;
Ian Lance Taylor6516c342012-10-31 19:57:58 -0700220 String file;
221 intgo line;
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -0800222 _Bool ok;
223};
224
Nikhil Benesch03e28272019-01-29 14:53:58 -0500225struct caller_ret Caller (intgo n) __asm__ (GOSYM_PREFIX "runtime.Caller");
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -0800226
Ian Lance Taylor8267f1d2012-03-06 17:06:46 -0800227/* Implement runtime.Caller. */
228
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -0800229struct caller_ret
Nikhil Benesch03e28272019-01-29 14:53:58 -0500230Caller (intgo skip)
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -0800231{
232 struct caller_ret ret;
Ian Lance Taylor1ef56882013-01-30 14:00:04 -0800233 Location loc;
Ian Lance Taylor8267f1d2012-03-06 17:06:46 -0800234 int32 n;
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -0800235
Ian Lance Taylor8267f1d2012-03-06 17:06:46 -0800236 runtime_memclr (&ret, sizeof ret);
Ian Lance Taylor7e1c63c2014-07-19 14:35:30 -0700237 n = runtime_callers (skip + 1, &loc, 1, false);
Ian Lance Taylor5b97c052015-04-17 14:58:05 -0700238 if (n < 1 || loc.pc == 0)
Ian Lance Taylor8267f1d2012-03-06 17:06:46 -0800239 return ret;
Ian Lance Taylor1ef56882013-01-30 14:00:04 -0800240 ret.pc = loc.pc;
241 ret.file = loc.filename;
242 ret.line = loc.lineno;
Ian Lance Taylor6097dec2012-09-28 10:41:20 -0700243 ret.ok = 1;
Ian Lance Taylor0ef89c42010-01-29 13:33:36 -0800244 return ret;
245}
Ian Lance Taylor747bb222010-07-01 12:38:25 -0700246
Ian Lance Taylor99384062016-10-14 09:21:16 -0700247/* Look up the function name, file name, and line number for a PC. */
Ian Lance Taylor747bb222010-07-01 12:38:25 -0700248
Ian Lance Taylor99384062016-10-14 09:21:16 -0700249struct funcfileline_return
Ian Lance Taylorc2225a72020-01-02 15:05:27 -0800250runtime_funcfileline (uintptr targetpc, int32 index, bool more)
Ian Lance Taylor8267f1d2012-03-06 17:06:46 -0800251{
Ian Lance Taylor99384062016-10-14 09:21:16 -0700252 struct funcfileline_return ret;
Ian Lance Taylor8267f1d2012-03-06 17:06:46 -0800253
Ian Lance Taylorc2225a72020-01-02 15:05:27 -0800254 if (!__go_file_line (targetpc, index, more, &ret.retfn, &ret.retfile,
Than McIntosh6112f9b2019-04-10 14:42:24 -0400255 &ret.retline, &ret.retframes))
Ian Lance Taylor8267f1d2012-03-06 17:06:46 -0800256 runtime_memclr (&ret, sizeof ret);
257 return ret;
Ian Lance Taylor747bb222010-07-01 12:38:25 -0700258}
Ian Lance Taylorf8f0cb42013-11-06 11:23:33 -0800259
Ian Lance Taylorf8f0cb42013-11-06 11:23:33 -0800260/* Return the entry point of a function. */
Ian Lance Taylor99384062016-10-14 09:21:16 -0700261uintptr runtime_funcentry(uintptr)
262 __asm__ (GOSYM_PREFIX "runtime.funcentry");
Ian Lance Taylorf8f0cb42013-11-06 11:23:33 -0800263
264uintptr
Ian Lance Taylor99384062016-10-14 09:21:16 -0700265runtime_funcentry (uintptr pc)
Ian Lance Taylorf8f0cb42013-11-06 11:23:33 -0800266{
Ian Lance Taylor99384062016-10-14 09:21:16 -0700267 uintptr val;
Ian Lance Taylorb156d712016-07-22 07:41:34 -0700268
Ian Lance Taylor99384062016-10-14 09:21:16 -0700269 if (!__go_symbol_value (pc, &val))
270 return 0;
271 return val;
Ian Lance Taylorb156d712016-07-22 07:41:34 -0700272}