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  }