github.com/guyezi/gofrontend@v0.0.0-20200228202240-7a62a49e62c0/libgo/runtime/go-caller.c (about) 1 /* go-caller.c -- look up function/file/line/entry info 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> 10 #include <sys/types.h> 11 #include <sys/stat.h> 12 #include <unistd.h> 13 14 #include "backtrace.h" 15 16 #include "runtime.h" 17 18 /* Get the function name, file name, and line number for a PC value. 19 We use the backtrace library to get this. */ 20 21 /* Data structure to gather file/line information. */ 22 23 struct caller 24 { 25 String fn; 26 String file; 27 intgo line; 28 intgo index; 29 intgo frames; 30 bool more; 31 }; 32 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. */ 37 38 static int 39 callback (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 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++; 57 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); 64 c->line = lineno; 65 66 if (c->index == 0) 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 } 77 78 if (c->index > 0) 79 --c->index; 80 81 return 0; 82 } 83 84 /* The error callback for backtrace_pcinfo and backtrace_syminfo. */ 85 86 static void 87 error_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. */ 98 99 static void *back_state; 100 101 /* A lock to control creating back_state. */ 102 103 static uint32 back_state_lock; 104 105 /* The program arguments. */ 106 107 extern Slice runtime_get_args(void); 108 109 /* Fetch back_state, creating it if necessary. */ 110 111 struct backtrace_state * 112 __go_get_backtrace_state () 113 { 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 } 123 if (back_state == NULL) 124 { 125 Slice args; 126 const char *filename; 127 struct stat s; 128 129 args = runtime_get_args(); 130 filename = NULL; 131 if (args.__count > 0) 132 filename = (const char*)((String*)args.__values)[0].str; 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. */ 137 if (filename != NULL && __builtin_strchr (filename, '/') == NULL) 138 filename = NULL; 139 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. */ 145 if (filename != NULL && (stat (filename, &s) < 0 || s.st_size < 1024)) 146 filename = NULL; 147 148 back_state = backtrace_create_state (filename, 1, error_callback, NULL); 149 } 150 __atomic_store_n (&back_state_lock, 0, __ATOMIC_RELEASE); 151 return back_state; 152 } 153 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. */ 159 160 static _Bool 161 __go_file_line (uintptr pc, int index, bool more, String *fn, String *file, intgo *line, intgo *nframes) 162 { 163 struct caller c; 164 struct backtrace_state *state; 165 166 runtime_memclr (&c, sizeof c); 167 c.index = index; 168 c.more = more; 169 c.frames = 0; 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); 174 *fn = c.fn; 175 *file = c.file; 176 *line = c.line; 177 *nframes = c.frames; 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 185 return c.file.len > 0; 186 } 187 188 /* Collect symbol information. */ 189 190 static void 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))) 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 202 static _Bool 203 __go_symbol_value (uintptr pc, uintptr *val) 204 { 205 struct backtrace_state *state; 206 207 *val = 0; 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); 213 return *val != 0; 214 } 215 216 /* The values returned by runtime.Caller. */ 217 218 struct caller_ret 219 { 220 uintptr_t pc; 221 String file; 222 intgo line; 223 _Bool ok; 224 }; 225 226 struct caller_ret Caller (intgo n) __asm__ (GOSYM_PREFIX "runtime.Caller"); 227 228 /* Implement runtime.Caller. */ 229 230 struct caller_ret 231 Caller (intgo skip) 232 { 233 struct caller_ret ret; 234 Location loc; 235 int32 n; 236 237 runtime_memclr (&ret, sizeof ret); 238 n = runtime_callers (skip + 1, &loc, 1, false); 239 if (n < 1 || loc.pc == 0) 240 return ret; 241 ret.pc = loc.pc; 242 ret.file = loc.filename; 243 ret.line = loc.lineno; 244 ret.ok = 1; 245 return ret; 246 } 247 248 /* Look up the function name, file name, and line number for a PC. */ 249 250 struct funcfileline_return 251 runtime_funcfileline (uintptr targetpc, int32 index, bool more) 252 { 253 struct funcfileline_return ret; 254 255 if (!__go_file_line (targetpc, index, more, &ret.retfn, &ret.retfile, 256 &ret.retline, &ret.retframes)) 257 runtime_memclr (&ret, sizeof ret); 258 return ret; 259 } 260 261 /* Return the entry point of a function. */ 262 uintptr runtime_funcentry(uintptr) 263 __asm__ (GOSYM_PREFIX "runtime.funcentry"); 264 265 uintptr 266 runtime_funcentry (uintptr pc) 267 { 268 uintptr val; 269 270 if (!__go_symbol_value (pc, &val)) 271 return 0; 272 return val; 273 }