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. */
10 #include <sys/types.h>
14 #include "backtrace.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. */
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. */
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. */
48 && runtime_skipInCallback (function
, NULL
))
51 /* If we already have a frame, don't increment frames if we should
55 || !runtime_skipInCallback ((const char *) c
->fn
.str
, NULL
))
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
);
68 /* If there are more frames after the indexed one, and we should
69 skip this one, then skip it. */
72 && runtime_skipInCallback((const char *) c
->fn
.str
, NULL
))
84 /* The error callback for backtrace_pcinfo and backtrace_syminfo. */
87 error_callback (void *data
__attribute__ ((unused
)),
88 const char *msg
, int errnum
)
93 runtime_printf ("%s errno %d\n", msg
, errnum
);
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 ()
116 /* We may not have a g here, so we can't use runtime_lock. */
118 while (!__atomic_compare_exchange_n (&back_state_lock
, &set
, 1, false, __ATOMIC_ACQUIRE
, __ATOMIC_RELAXED
))
123 if (back_state
== NULL
)
126 const char *filename
;
129 args
= runtime_get_args();
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
)
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
145 if (filename
!= NULL
&& (stat (filename
, &s
) < 0 || s
.st_size
< 1024))
148 back_state
= backtrace_create_state (filename
, 1, error_callback
, NULL
);
150 __atomic_store_n (&back_state_lock
, 0, __ATOMIC_RELEASE
);
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
161 __go_file_line (uintptr pc
, int index
, bool more
, String
*fn
, String
*file
, intgo
*line
, intgo
*nframes
)
164 struct backtrace_state
*state
;
166 runtime_memclr (&c
, sizeof c
);
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
);
179 // If backtrace_pcinfo didn't get the function name from the debug
180 // info, try to get it from the symbol table.
182 backtrace_syminfo (state
, pc
, __go_syminfo_fnname_callback
,
185 return c
.file
.len
> 0;
188 /* Collect symbol information. */
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
;
200 /* Set *VAL to the value of the symbol for PC. */
203 __go_symbol_value (uintptr pc
, uintptr
*val
)
205 struct backtrace_state
*state
;
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
);
216 /* The values returned by runtime.Caller. */
226 struct caller_ret
Caller (intgo n
) __asm__ (GOSYM_PREFIX
"runtime.Caller");
228 /* Implement runtime.Caller. */
233 struct caller_ret ret
;
237 runtime_memclr (&ret
, sizeof ret
);
238 n
= runtime_callers (skip
+ 1, &loc
, 1, false);
239 if (n
< 1 || loc
.pc
== 0)
242 ret
.file
= loc
.filename
;
243 ret
.line
= loc
.lineno
;
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
);
261 /* Return the entry point of a function. */
262 uintptr
runtime_funcentry(uintptr
)
263 __asm__ (GOSYM_PREFIX
"runtime.funcentry");
266 runtime_funcentry (uintptr pc
)
270 if (!__go_symbol_value (pc
, &val
))