github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gofrontend/libgo/runtime/go-callers.c (about) 1 /* go-callers.c -- get callers for Go. 2 3 Copyright 2012 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 #include "config.h" 8 9 #include "backtrace.h" 10 11 #include "runtime.h" 12 #include "array.h" 13 14 /* This is set to non-zero when calling backtrace_full. This is used 15 to avoid getting hanging on a recursive lock in dl_iterate_phdr on 16 older versions of glibc when a SIGPROF signal arrives while 17 collecting a backtrace. */ 18 19 uint32 runtime_in_callers; 20 21 /* Argument passed to callback function. */ 22 23 struct callers_data 24 { 25 Location *locbuf; 26 int skip; 27 int index; 28 int max; 29 int keep_thunks; 30 }; 31 32 /* Callback function for backtrace_full. Just collect the locations. 33 Return zero to continue, non-zero to stop. */ 34 35 static int 36 callback (void *data, uintptr_t pc, const char *filename, int lineno, 37 const char *function) 38 { 39 struct callers_data *arg = (struct callers_data *) data; 40 Location *loc; 41 42 /* Skip split stack functions. */ 43 if (function != NULL) 44 { 45 const char *p; 46 47 p = function; 48 if (__builtin_strncmp (p, "___", 3) == 0) 49 ++p; 50 if (__builtin_strncmp (p, "__morestack_", 12) == 0) 51 return 0; 52 } 53 else if (filename != NULL) 54 { 55 const char *p; 56 57 p = strrchr (filename, '/'); 58 if (p == NULL) 59 p = filename; 60 if (__builtin_strncmp (p, "/morestack.S", 12) == 0) 61 return 0; 62 } 63 64 /* Skip thunks and recover functions. There is no equivalent to 65 these functions in the gc toolchain, so returning them here means 66 significantly different results for runtime.Caller(N). */ 67 if (function != NULL && !arg->keep_thunks) 68 { 69 const char *p; 70 71 p = __builtin_strchr (function, '.'); 72 if (p != NULL && __builtin_strncmp (p + 1, "$thunk", 6) == 0) 73 return 0; 74 p = __builtin_strrchr (function, '$'); 75 if (p != NULL && __builtin_strcmp(p, "$recover") == 0) 76 return 0; 77 } 78 79 if (arg->skip > 0) 80 { 81 --arg->skip; 82 return 0; 83 } 84 85 loc = &arg->locbuf[arg->index]; 86 87 /* On the call to backtrace_full the pc value was most likely 88 decremented if there was a normal call, since the pc referred to 89 the instruction where the call returned and not the call itself. 90 This was done so that the line number referred to the call 91 instruction. To make sure the actual pc from the call stack is 92 used, it is incremented here. 93 94 In the case of a signal, the pc was not decremented by 95 backtrace_full but still incremented here. That doesn't really 96 hurt anything since the line number is right and the pc refers to 97 the same instruction. */ 98 99 loc->pc = pc + 1; 100 101 /* The libbacktrace library says that these strings might disappear, 102 but with the current implementation they won't. We can't easily 103 allocate memory here, so for now assume that we can save a 104 pointer to the strings. */ 105 loc->filename = runtime_gostringnocopy ((const byte *) filename); 106 loc->function = runtime_gostringnocopy ((const byte *) function); 107 108 loc->lineno = lineno; 109 ++arg->index; 110 111 /* There is no point to tracing past certain runtime functions. 112 Stopping the backtrace here can avoid problems on systems that 113 don't provide proper unwind information for makecontext, such as 114 Solaris (http://gcc.gnu.org/PR52583 comment #21). */ 115 if (function != NULL) 116 { 117 if (__builtin_strcmp (function, "makecontext") == 0) 118 return 1; 119 if (filename != NULL) 120 { 121 const char *p; 122 123 p = strrchr (filename, '/'); 124 if (p == NULL) 125 p = filename; 126 if (__builtin_strcmp (p, "/proc.c") == 0) 127 { 128 if (__builtin_strcmp (function, "kickoff") == 0 129 || __builtin_strcmp (function, "runtime_mstart") == 0 130 || __builtin_strcmp (function, "runtime_main") == 0) 131 return 1; 132 } 133 } 134 } 135 136 return arg->index >= arg->max; 137 } 138 139 /* Error callback. */ 140 141 static void 142 error_callback (void *data __attribute__ ((unused)), 143 const char *msg, int errnum) 144 { 145 if (errnum == -1) 146 { 147 /* No debug info available. Carry on as best we can. */ 148 return; 149 } 150 if (errnum != 0) 151 runtime_printf ("%s errno %d\n", msg, errnum); 152 runtime_throw (msg); 153 } 154 155 /* Gather caller PC's. */ 156 157 int32 158 runtime_callers (int32 skip, Location *locbuf, int32 m, bool keep_thunks) 159 { 160 struct callers_data data; 161 162 data.locbuf = locbuf; 163 data.skip = skip + 1; 164 data.index = 0; 165 data.max = m; 166 data.keep_thunks = keep_thunks; 167 runtime_xadd (&runtime_in_callers, 1); 168 backtrace_full (__go_get_backtrace_state (), 0, callback, error_callback, 169 &data); 170 runtime_xadd (&runtime_in_callers, -1); 171 return data.index; 172 } 173 174 int Callers (int, struct __go_open_array) 175 __asm__ (GOSYM_PREFIX "runtime.Callers"); 176 177 int 178 Callers (int skip, struct __go_open_array pc) 179 { 180 Location *locbuf; 181 int ret; 182 int i; 183 184 locbuf = (Location *) runtime_mal (pc.__count * sizeof (Location)); 185 186 /* In the Go 1 release runtime.Callers has an off-by-one error, 187 which we can not correct because it would break backward 188 compatibility. Normally we would add 1 to SKIP here, but we 189 don't so that we are compatible. */ 190 ret = runtime_callers (skip, locbuf, pc.__count, false); 191 192 for (i = 0; i < ret; i++) 193 ((uintptr *) pc.__values)[i] = locbuf[i].pc; 194 195 return ret; 196 }