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. */
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. */
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
;
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
);
62 /* The error callback for backtrace_pcinfo and backtrace_syminfo. */
65 error_callback (void *data
__attribute__ ((unused
)),
66 const char *msg
, int errnum
)
71 runtime_printf ("%s errno %d\n", msg
, errnum
);
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 ()
94 /* We may not have a g here, so we can't use runtime_lock. */
96 while (!__atomic_compare_exchange_n (&back_state_lock
, &set
, 1, false, __ATOMIC_ACQUIRE
, __ATOMIC_RELAXED
))
101 if (back_state
== NULL
)
104 const char *filename
;
107 args
= runtime_get_args();
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
)
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
123 if (filename
!= NULL
&& (stat (filename
, &s
) < 0 || s
.st_size
< 1024))
126 back_state
= backtrace_create_state (filename
, 1, error_callback
, NULL
);
128 __atomic_store_n (&back_state_lock
, 0, __ATOMIC_RELEASE
);
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. */
137 __go_file_line (uintptr pc
, int index
, String
*fn
, String
*file
, intgo
*line
, intgo
*nframes
)
140 struct backtrace_state
*state
;
142 runtime_memclr (&c
, sizeof c
);
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
);
154 // If backtrace_pcinfo didn't get the function name from the debug
155 // info, try to get it from the symbol table.
157 backtrace_syminfo (state
, pc
, __go_syminfo_fnname_callback
,
160 return c
.file
.len
> 0;
163 /* Collect symbol information. */
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
;
175 /* Set *VAL to the value of the symbol for PC. */
178 __go_symbol_value (uintptr pc
, uintptr
*val
)
180 struct backtrace_state
*state
;
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
);
191 /* The values returned by runtime.Caller. */
201 struct caller_ret
Caller (intgo n
) __asm__ (GOSYM_PREFIX
"runtime.Caller");
203 /* Implement runtime.Caller. */
208 struct caller_ret ret
;
212 runtime_memclr (&ret
, sizeof ret
);
213 n
= runtime_callers (skip
+ 1, &loc
, 1, false);
214 if (n
< 1 || loc
.pc
== 0)
217 ret
.file
= loc
.filename
;
218 ret
.line
= loc
.lineno
;
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
);
236 /* Return the entry point of a function. */
237 uintptr
runtime_funcentry(uintptr
)
238 __asm__ (GOSYM_PREFIX
"runtime.funcentry");
241 runtime_funcentry (uintptr pc
)
245 if (!__go_symbol_value (pc
, &val
))