github.com/spotify/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/src/pkg/runtime/symtab.c (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Runtime symbol table parsing. 6 // See http://golang.org/s/go12symtab for an overview. 7 8 #include "runtime.h" 9 #include "defs_GOOS_GOARCH.h" 10 #include "os_GOOS.h" 11 #include "arch_GOARCH.h" 12 #include "malloc.h" 13 #include "funcdata.h" 14 15 typedef struct Ftab Ftab; 16 struct Ftab 17 { 18 uintptr entry; 19 uintptr funcoff; 20 }; 21 22 extern byte pclntab[]; 23 24 static Ftab *ftab; 25 static uintptr nftab; 26 static uint32 *filetab; 27 static uint32 nfiletab; 28 29 static String end = { (uint8*)"end", 3 }; 30 31 void 32 runtime·symtabinit(void) 33 { 34 int32 i, j; 35 Func *f1, *f2; 36 37 // See golang.org/s/go12symtab for header: 0xfffffffb, 38 // two zero bytes, a byte giving the PC quantum, 39 // and a byte giving the pointer width in bytes. 40 if(*(uint32*)pclntab != 0xfffffffb || pclntab[4] != 0 || pclntab[5] != 0 || pclntab[6] != PCQuantum || pclntab[7] != sizeof(void*)) { 41 runtime·printf("runtime: function symbol table header: 0x%x 0x%x\n", *(uint32*)pclntab, *(uint32*)(pclntab+4)); 42 runtime·throw("invalid function symbol table\n"); 43 } 44 45 nftab = *(uintptr*)(pclntab+8); 46 ftab = (Ftab*)(pclntab+8+sizeof(void*)); 47 for(i=0; i<nftab; i++) { 48 // NOTE: ftab[nftab].entry is legal; it is the address beyond the final function. 49 if(ftab[i].entry > ftab[i+1].entry) { 50 f1 = (Func*)(pclntab + ftab[i].funcoff); 51 f2 = (Func*)(pclntab + ftab[i+1].funcoff); 52 runtime·printf("function symbol table not sorted by program counter: %p %s > %p %s", ftab[i].entry, runtime·funcname(f1), ftab[i+1].entry, i+1 == nftab ? "end" : runtime·funcname(f2)); 53 for(j=0; j<=i; j++) 54 runtime·printf("\t%p %s\n", ftab[j].entry, runtime·funcname((Func*)(pclntab + ftab[j].funcoff))); 55 runtime·throw("invalid runtime symbol table"); 56 } 57 } 58 59 filetab = (uint32*)(pclntab + *(uint32*)&ftab[nftab].funcoff); 60 nfiletab = filetab[0]; 61 } 62 63 static uint32 64 readvarint(byte **pp) 65 { 66 byte *p; 67 uint32 v; 68 int32 shift; 69 70 v = 0; 71 p = *pp; 72 for(shift = 0;; shift += 7) { 73 v |= (*p & 0x7F) << shift; 74 if(!(*p++ & 0x80)) 75 break; 76 } 77 *pp = p; 78 return v; 79 } 80 81 void* 82 runtime·funcdata(Func *f, int32 i) 83 { 84 byte *p; 85 86 if(i < 0 || i >= f->nfuncdata) 87 return nil; 88 p = (byte*)&f->nfuncdata + 4 + f->npcdata*4; 89 if(sizeof(void*) == 8 && ((uintptr)p & 4)) 90 p += 4; 91 return ((void**)p)[i]; 92 } 93 94 static bool 95 step(byte **pp, uintptr *pc, int32 *value, bool first) 96 { 97 uint32 uvdelta, pcdelta; 98 int32 vdelta; 99 100 uvdelta = readvarint(pp); 101 if(uvdelta == 0 && !first) 102 return 0; 103 if(uvdelta&1) 104 uvdelta = ~(uvdelta>>1); 105 else 106 uvdelta >>= 1; 107 vdelta = (int32)uvdelta; 108 pcdelta = readvarint(pp) * PCQuantum; 109 *value += vdelta; 110 *pc += pcdelta; 111 return 1; 112 } 113 114 // Return associated data value for targetpc in func f. 115 // (Source file is f->src.) 116 static int32 117 pcvalue(Func *f, int32 off, uintptr targetpc, bool strict) 118 { 119 byte *p; 120 uintptr pc; 121 int32 value; 122 123 enum { 124 debug = 0 125 }; 126 127 // The table is a delta-encoded sequence of (value, pc) pairs. 128 // Each pair states the given value is in effect up to pc. 129 // The value deltas are signed, zig-zag encoded. 130 // The pc deltas are unsigned. 131 // The starting value is -1, the starting pc is the function entry. 132 // The table ends at a value delta of 0 except in the first pair. 133 if(off == 0) 134 return -1; 135 p = pclntab + off; 136 pc = f->entry; 137 value = -1; 138 139 if(debug && !runtime·panicking) 140 runtime·printf("pcvalue start f=%s [%p] pc=%p targetpc=%p value=%d tab=%p\n", 141 runtime·funcname(f), f, pc, targetpc, value, p); 142 143 while(step(&p, &pc, &value, pc == f->entry)) { 144 if(debug) 145 runtime·printf("\tvalue=%d until pc=%p\n", value, pc); 146 if(targetpc < pc) 147 return value; 148 } 149 150 // If there was a table, it should have covered all program counters. 151 // If not, something is wrong. 152 if(runtime·panicking || !strict) 153 return -1; 154 runtime·printf("runtime: invalid pc-encoded table f=%s pc=%p targetpc=%p tab=%p\n", 155 runtime·funcname(f), pc, targetpc, p); 156 p = (byte*)f + off; 157 pc = f->entry; 158 value = -1; 159 160 while(step(&p, &pc, &value, pc == f->entry)) 161 runtime·printf("\tvalue=%d until pc=%p\n", value, pc); 162 163 runtime·throw("invalid runtime symbol table"); 164 return -1; 165 } 166 167 static String unknown = { (uint8*)"?", 1 }; 168 169 int8* 170 runtime·funcname(Func *f) 171 { 172 if(f == nil || f->nameoff == 0) 173 return nil; 174 return (int8*)(pclntab + f->nameoff); 175 } 176 177 static int32 178 funcline(Func *f, uintptr targetpc, String *file, bool strict) 179 { 180 int32 line; 181 int32 fileno; 182 183 *file = unknown; 184 fileno = pcvalue(f, f->pcfile, targetpc, strict); 185 line = pcvalue(f, f->pcln, targetpc, strict); 186 if(fileno == -1 || line == -1 || fileno >= nfiletab) { 187 // runtime·printf("looking for %p in %S got file=%d line=%d\n", targetpc, *f->name, fileno, line); 188 return 0; 189 } 190 *file = runtime·gostringnocopy(pclntab + filetab[fileno]); 191 return line; 192 } 193 194 int32 195 runtime·funcline(Func *f, uintptr targetpc, String *file) 196 { 197 return funcline(f, targetpc, file, true); 198 } 199 200 int32 201 runtime·funcspdelta(Func *f, uintptr targetpc) 202 { 203 int32 x; 204 205 x = pcvalue(f, f->pcsp, targetpc, true); 206 if(x&(sizeof(void*)-1)) 207 runtime·printf("invalid spdelta %d %d\n", f->pcsp, x); 208 return x; 209 } 210 211 int32 212 runtime·pcdatavalue(Func *f, int32 table, uintptr targetpc) 213 { 214 if(table < 0 || table >= f->npcdata) 215 return -1; 216 return pcvalue(f, (&f->nfuncdata)[1+table], targetpc, true); 217 } 218 219 int32 220 runtime·funcarglen(Func *f, uintptr targetpc) 221 { 222 if(targetpc == f->entry) 223 return 0; 224 return runtime·pcdatavalue(f, PCDATA_ArgSize, targetpc-PCQuantum); 225 } 226 227 void 228 runtime·funcline_go(Func *f, uintptr targetpc, String retfile, intgo retline) 229 { 230 // Pass strict=false here, because anyone can call this function, 231 // and they might just be wrong about targetpc belonging to f. 232 retline = funcline(f, targetpc, &retfile, false); 233 FLUSH(&retline); 234 } 235 236 void 237 runtime·funcname_go(Func *f, String ret) 238 { 239 ret = runtime·gostringnocopy((uint8*)runtime·funcname(f)); 240 FLUSH(&ret); 241 } 242 243 void 244 runtime·funcentry_go(Func *f, uintptr ret) 245 { 246 ret = f->entry; 247 FLUSH(&ret); 248 } 249 250 Func* 251 runtime·findfunc(uintptr addr) 252 { 253 Ftab *f; 254 int32 nf, n; 255 256 if(nftab == 0) 257 return nil; 258 if(addr < ftab[0].entry || addr >= ftab[nftab].entry) 259 return nil; 260 261 // binary search to find func with entry <= addr. 262 f = ftab; 263 nf = nftab; 264 while(nf > 0) { 265 n = nf/2; 266 if(f[n].entry <= addr && addr < f[n+1].entry) 267 return (Func*)(pclntab + f[n].funcoff); 268 else if(addr < f[n].entry) 269 nf = n; 270 else { 271 f += n+1; 272 nf -= n+1; 273 } 274 } 275 276 // can't get here -- we already checked above 277 // that the address was in the table bounds. 278 // this can only happen if the table isn't sorted 279 // by address or if the binary search above is buggy. 280 runtime·prints("findfunc unreachable\n"); 281 return nil; 282 } 283 284 static bool 285 hasprefix(String s, int8 *p) 286 { 287 int32 i; 288 289 for(i=0; i<s.len; i++) { 290 if(p[i] == 0) 291 return 1; 292 if(p[i] != s.str[i]) 293 return 0; 294 } 295 return p[i] == 0; 296 } 297 298 static bool 299 contains(String s, int8 *p) 300 { 301 int32 i; 302 303 if(p[0] == 0) 304 return 1; 305 for(i=0; i<s.len; i++) { 306 if(s.str[i] != p[0]) 307 continue; 308 if(hasprefix((String){s.str + i, s.len - i}, p)) 309 return 1; 310 } 311 return 0; 312 } 313 314 bool 315 runtime·showframe(Func *f, G *gp) 316 { 317 static int32 traceback = -1; 318 String name; 319 320 if(m->throwing > 0 && gp != nil && (gp == m->curg || gp == m->caughtsig)) 321 return 1; 322 if(traceback < 0) 323 traceback = runtime·gotraceback(nil); 324 name = runtime·gostringnocopy((uint8*)runtime·funcname(f)); 325 326 // Special case: always show runtime.panic frame, so that we can 327 // see where a panic started in the middle of a stack trace. 328 // See golang.org/issue/5832. 329 if(name.len == 7+1+5 && hasprefix(name, "runtime.panic")) 330 return 1; 331 332 return traceback > 1 || f != nil && contains(name, ".") && !hasprefix(name, "runtime."); 333 }