github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/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  //
     7  // The Go tools use a symbol table derived from the Plan 9 symbol table
     8  // format. The symbol table is kept in its own section treated as
     9  // read-only memory when the binary is running: the binary consults the
    10  // table.
    11  // 
    12  // The format used by Go 1.0 was basically the Plan 9 format. Each entry
    13  // is variable sized but had this format:
    14  // 
    15  // 	4-byte value, big endian
    16  // 	1-byte type ([A-Za-z] + 0x80)
    17  // 	name, NUL terminated (or for 'z' and 'Z' entries, double-NUL terminated)
    18  // 	4-byte Go type address, big endian (new in Go)
    19  // 
    20  // In order to support greater interoperation with standard toolchains,
    21  // Go 1.1 uses a more flexible yet smaller encoding of the entries.
    22  // The overall structure is unchanged from Go 1.0 and, for that matter,
    23  // from Plan 9.
    24  // 
    25  // The Go 1.1 table is a re-encoding of the data in a Go 1.0 table.
    26  // To identify a new table as new, it begins one of two eight-byte
    27  // sequences:
    28  // 
    29  // 	FF FF FF FD 00 00 00 xx - big endian new table
    30  // 	FD FF FF FF 00 00 00 xx - little endian new table
    31  // 
    32  // This sequence was chosen because old tables stop at an entry with type
    33  // 0, so old code reading a new table will see only an empty table. The
    34  // first four bytes are the target-endian encoding of 0xfffffffd. The
    35  // final xx gives AddrSize, the width of a full-width address.
    36  // 
    37  // After that header, each entry is encoded as follows.
    38  // 
    39  // 	1-byte type (0-51 + two flag bits)
    40  // 	AddrSize-byte value, host-endian OR varint-encoded value
    41  // 	AddrSize-byte Go type address OR nothing
    42  // 	[n] name, terminated as before
    43  // 
    44  // The type byte comes first, but 'A' encodes as 0 and 'a' as 26, so that
    45  // the type itself is only in the low 6 bits. The upper two bits specify
    46  // the format of the next two fields. If the 0x40 bit is set, the value
    47  // is encoded as an full-width 4- or 8-byte target-endian word. Otherwise
    48  // the value is a varint-encoded number. If the 0x80 bit is set, the Go
    49  // type is present, again as a 4- or 8-byte target-endian word. If not,
    50  // there is no Go type in this entry. The NUL-terminated name ends the
    51  // entry.
    52  
    53  #include "runtime.h"
    54  #include "defs_GOOS_GOARCH.h"
    55  #include "os_GOOS.h"
    56  #include "arch_GOARCH.h"
    57  #include "malloc.h"
    58  
    59  extern byte pclntab[], epclntab[], symtab[], esymtab[];
    60  
    61  typedef struct Sym Sym;
    62  struct Sym
    63  {
    64  	uintptr value;
    65  	byte symtype;
    66  	byte *name;
    67  //	byte *gotype;
    68  };
    69  
    70  static uintptr mainoffset;
    71  
    72  // A dynamically allocated string containing multiple substrings.
    73  // Individual strings are slices of hugestring.
    74  static String hugestring;
    75  static int32 hugestring_len;
    76  
    77  extern void main·main(void);
    78  
    79  static uintptr
    80  readword(byte **pp, byte *ep)
    81  {
    82  	byte *p; 
    83  
    84  	p = *pp;
    85  	if(ep - p < sizeof(void*)) {
    86  		*pp = ep;
    87  		return 0;
    88  	}
    89  	*pp = p + sizeof(void*);
    90  
    91  	// Hairy, but only one of these four cases gets compiled.
    92  	if(sizeof(void*) == 8) {
    93  		if(BigEndian) {
    94  			return ((uint64)p[0]<<56) | ((uint64)p[1]<<48) | ((uint64)p[2]<<40) | ((uint64)p[3]<<32) |
    95  				((uint64)p[4]<<24) | ((uint64)p[5]<<16) | ((uint64)p[6]<<8) | ((uint64)p[7]);
    96  		}
    97  		return ((uint64)p[7]<<56) | ((uint64)p[6]<<48) | ((uint64)p[5]<<40) | ((uint64)p[4]<<32) |
    98  			((uint64)p[3]<<24) | ((uint64)p[2]<<16) | ((uint64)p[1]<<8) | ((uint64)p[0]);
    99  	}
   100  	if(BigEndian) {
   101  		return ((uint32)p[0]<<24) | ((uint32)p[1]<<16) | ((uint32)p[2]<<8) | ((uint32)p[3]);
   102  	}
   103  	return ((uint32)p[3]<<24) | ((uint32)p[2]<<16) | ((uint32)p[1]<<8) | ((uint32)p[0]);
   104  }
   105  
   106  // Walk over symtab, calling fn(&s) for each symbol.
   107  static void
   108  walksymtab(void (*fn)(Sym*))
   109  {
   110  	byte *p, *ep, *q;
   111  	Sym s;
   112  	int32 widevalue, havetype, shift;
   113  
   114  	p = symtab;
   115  	ep = esymtab;
   116  
   117  	// Table must begin with correct magic number.
   118  	if(ep - p < 8 || p[4] != 0x00 || p[5] != 0x00 || p[6] != 0x00 || p[7] != sizeof(void*))
   119  		return;
   120  	if(BigEndian) {
   121  		if(p[0] != 0xff || p[1] != 0xff || p[2] != 0xff || p[3] != 0xfd)
   122  			return;
   123  	} else {
   124  		if(p[0] != 0xfd || p[1] != 0xff || p[2] != 0xff || p[3] != 0xff)
   125  			return;
   126  	}
   127  	p += 8;
   128  
   129  	while(p < ep) {
   130  		s.symtype = p[0]&0x3F;
   131  		widevalue = p[0]&0x40;
   132  		havetype = p[0]&0x80;
   133  		if(s.symtype < 26)
   134  			s.symtype += 'A';
   135  		else
   136  			s.symtype += 'a' - 26;
   137  		p++;
   138  
   139  		// Value, either full-width or varint-encoded.
   140  		if(widevalue) {
   141  			s.value = readword(&p, ep);
   142  		} else {
   143  			s.value = 0;
   144  			shift = 0;
   145  			while(p < ep && (p[0]&0x80) != 0) {
   146  				s.value |= (uintptr)(p[0]&0x7F)<<shift;
   147  				shift += 7;
   148  				p++;
   149  			}
   150  			if(p >= ep)
   151  				break;
   152  			s.value |= (uintptr)p[0]<<shift;
   153  			p++;
   154  		}
   155  		
   156  		// Go type, if present. Ignored but must skip over.
   157  		if(havetype)
   158  			readword(&p, ep);
   159  
   160  		// Name.
   161  		if(ep - p < 2)
   162  			break;
   163  
   164  		s.name = p;
   165  		if(s.symtype == 'z' || s.symtype == 'Z') {
   166  			// path reference string - skip first byte,
   167  			// then 2-byte pairs ending at two zeros.
   168  			q = p+1;
   169  			for(;;) {
   170  				if(q+2 > ep)
   171  					return;
   172  				if(q[0] == '\0' && q[1] == '\0')
   173  					break;
   174  				q += 2;
   175  			}
   176  			p = q+2;
   177  		}else{
   178  			q = runtime·mchr(p, '\0', ep);
   179  			if(q == nil)
   180  				break;
   181  			p = q+1;
   182  		}
   183  	
   184  		fn(&s);
   185  	}
   186  }
   187  
   188  // Symtab walker; accumulates info about functions.
   189  
   190  static Func *func;
   191  static int32 nfunc;
   192  
   193  static byte **fname;
   194  static int32 nfname;
   195  
   196  static uint32 funcinit;
   197  static Lock funclock;
   198  static uintptr lastvalue;
   199  
   200  static void
   201  dofunc(Sym *sym)
   202  {
   203  	Func *f;
   204  	
   205  	switch(sym->symtype) {
   206  	case 't':
   207  	case 'T':
   208  	case 'l':
   209  	case 'L':
   210  		if(runtime·strcmp(sym->name, (byte*)"etext") == 0)
   211  			break;
   212  		if(sym->value < lastvalue) {
   213  			runtime·printf("symbols out of order: %p before %p\n", lastvalue, sym->value);
   214  			runtime·throw("malformed symbol table");
   215  		}
   216  		lastvalue = sym->value;
   217  		if(func == nil) {
   218  			nfunc++;
   219  			break;
   220  		}
   221  		f = &func[nfunc++];
   222  		f->name = runtime·gostringnocopy(sym->name);
   223  		f->entry = sym->value;
   224  		if(sym->symtype == 'L' || sym->symtype == 'l')
   225  			f->frame = -sizeof(uintptr);
   226  		break;
   227  	case 'm':
   228  		if(nfunc <= 0 || func == nil)
   229  			break;
   230  		if(runtime·strcmp(sym->name, (byte*)".frame") == 0)
   231  			func[nfunc-1].frame = sym->value;
   232  		else if(runtime·strcmp(sym->name, (byte*)".locals") == 0)
   233  			func[nfunc-1].locals = sym->value;
   234  		else if(runtime·strcmp(sym->name, (byte*)".args") == 0)
   235  			func[nfunc-1].args = sym->value;
   236  		else {
   237  			runtime·printf("invalid 'm' symbol named '%s'\n", sym->name);
   238  			runtime·throw("mangled symbol table");
   239  		}
   240  		break;
   241  	case 'f':
   242  		if(fname == nil) {
   243  			if(sym->value >= nfname) {
   244  				if(sym->value >= 0x10000) {
   245  					runtime·printf("runtime: invalid symbol file index %p\n", sym->value);
   246  					runtime·throw("mangled symbol table");
   247  				}
   248  				nfname = sym->value+1;
   249  			}
   250  			break;
   251  		}
   252  		fname[sym->value] = sym->name;
   253  		break;
   254  	}
   255  }
   256  
   257  // put together the path name for a z entry.
   258  // the f entries have been accumulated into fname already.
   259  // returns the length of the path name.
   260  static int32
   261  makepath(byte *buf, int32 nbuf, byte *path)
   262  {
   263  	int32 n, len;
   264  	byte *p, *ep, *q;
   265  
   266  	if(nbuf <= 0)
   267  		return 0;
   268  
   269  	p = buf;
   270  	ep = buf + nbuf;
   271  	*p = '\0';
   272  	for(;;) {
   273  		if(path[0] == 0 && path[1] == 0)
   274  			break;
   275  		n = (path[0]<<8) | path[1];
   276  		path += 2;
   277  		if(n >= nfname)
   278  			break;
   279  		q = fname[n];
   280  		len = runtime·findnull(q);
   281  		if(p+1+len >= ep)
   282  			break;
   283  		if(p > buf && p[-1] != '/')
   284  			*p++ = '/';
   285  		runtime·memmove(p, q, len+1);
   286  		p += len;
   287  	}
   288  	return p - buf;
   289  }
   290  
   291  // appends p to hugestring
   292  static String
   293  gostringn(byte *p, int32 l)
   294  {
   295  	String s;
   296  
   297  	if(l == 0)
   298  		return runtime·emptystring;
   299  	if(hugestring.str == nil) {
   300  		hugestring_len += l;
   301  		return runtime·emptystring;
   302  	}
   303  	s.str = hugestring.str + hugestring.len;
   304  	s.len = l;
   305  	hugestring.len += s.len;
   306  	runtime·memmove(s.str, p, l);
   307  	return s;
   308  }
   309  
   310  // walk symtab accumulating path names for use by pc/ln table.
   311  // don't need the full generality of the z entry history stack because
   312  // there are no includes in go (and only sensible includes in our c);
   313  // assume code only appear in top-level files.
   314  static void
   315  dosrcline(Sym *sym)
   316  {
   317  	static byte srcbuf[1000];
   318  	static struct {
   319  		String srcstring;
   320  		int32 aline;
   321  		int32 delta;
   322  	} files[200];
   323  	static int32 incstart;
   324  	static int32 nfunc, nfile, nhist;
   325  	Func *f;
   326  	int32 i, l;
   327  
   328  	switch(sym->symtype) {
   329  	case 't':
   330  	case 'T':
   331  		if(hugestring.str == nil)
   332  			break;
   333  		if(runtime·strcmp(sym->name, (byte*)"etext") == 0)
   334  			break;
   335  		f = &func[nfunc++];
   336  		// find source file
   337  		for(i = 0; i < nfile - 1; i++) {
   338  			if (files[i+1].aline > f->ln0)
   339  				break;
   340  		}
   341  		f->src = files[i].srcstring;
   342  		f->ln0 -= files[i].delta;
   343  		break;
   344  	case 'z':
   345  		if(sym->value == 1) {
   346  			// entry for main source file for a new object.
   347  			l = makepath(srcbuf, sizeof srcbuf, sym->name+1);
   348  			nhist = 0;
   349  			nfile = 0;
   350  			if(nfile == nelem(files))
   351  				return;
   352  			files[nfile].srcstring = gostringn(srcbuf, l);
   353  			files[nfile].aline = 0;
   354  			files[nfile++].delta = 0;
   355  		} else {
   356  			// push or pop of included file.
   357  			l = makepath(srcbuf, sizeof srcbuf, sym->name+1);
   358  			if(srcbuf[0] != '\0') {
   359  				if(nhist++ == 0)
   360  					incstart = sym->value;
   361  				if(nhist == 0 && nfile < nelem(files)) {
   362  					// new top-level file
   363  					files[nfile].srcstring = gostringn(srcbuf, l);
   364  					files[nfile].aline = sym->value;
   365  					// this is "line 0"
   366  					files[nfile++].delta = sym->value - 1;
   367  				}
   368  			}else{
   369  				if(--nhist == 0)
   370  					files[nfile-1].delta += sym->value - incstart;
   371  			}
   372  		}
   373  	}
   374  }
   375  
   376  // Interpret pc/ln table, saving the subpiece for each func.
   377  static void
   378  splitpcln(void)
   379  {
   380  	int32 line;
   381  	uintptr pc;
   382  	byte *p, *ep;
   383  	Func *f, *ef;
   384  	int32 pcquant;
   385  
   386  	if(pclntab == epclntab || nfunc == 0)
   387  		return;
   388  
   389  	switch(thechar) {
   390  	case '5':
   391  		pcquant = 4;
   392  		break;
   393  	default:	// 6, 8
   394  		pcquant = 1;
   395  		break;
   396  	}
   397  
   398  	// pc/ln table bounds
   399  	p = pclntab;
   400  	ep = epclntab;
   401  
   402  	f = func;
   403  	ef = func + nfunc;
   404  	pc = func[0].entry;	// text base
   405  	f->pcln.array = p;
   406  	f->pc0 = pc;
   407  	line = 0;
   408  	for(;;) {
   409  		while(p < ep && *p > 128)
   410  			pc += pcquant * (*p++ - 128);
   411  		// runtime·printf("pc<%p targetpc=%p line=%d\n", pc, targetpc, line);
   412  		if(*p == 0) {
   413  			if(p+5 > ep)
   414  				break;
   415  			// 4 byte add to line
   416  			line += (p[1]<<24) | (p[2]<<16) | (p[3]<<8) | p[4];
   417  			p += 5;
   418  		} else if(*p <= 64)
   419  			line += *p++;
   420  		else
   421  			line -= *p++ - 64;
   422  
   423  		// pc, line now match.
   424  		// Because the state machine begins at pc==entry and line==0,
   425  		// it can happen - just at the beginning! - that the update may
   426  		// have updated line but left pc alone, to tell us the true line
   427  		// number for pc==entry.  In that case, update f->ln0.
   428  		// Having the correct initial line number is important for choosing
   429  		// the correct file in dosrcline above.
   430  		if(f == func && pc == f->pc0) {
   431  			f->pcln.array = p;
   432  			f->pc0 = pc + pcquant;
   433  			f->ln0 = line;
   434  		}
   435  
   436  		if(f < ef && pc >= (f+1)->entry) {
   437  			f->pcln.len = p - f->pcln.array;
   438  			f->pcln.cap = f->pcln.len;
   439  			do
   440  				f++;
   441  			while(f < ef && pc >= (f+1)->entry);
   442  			f->pcln.array = p;
   443  			// pc0 and ln0 are the starting values for
   444  			// the loop over f->pcln, so pc must be
   445  			// adjusted by the same pcquant update
   446  			// that we're going to do as we continue our loop.
   447  			f->pc0 = pc + pcquant;
   448  			f->ln0 = line;
   449  		}
   450  
   451  		pc += pcquant;
   452  	}
   453  	if(f < ef) {
   454  		f->pcln.len = p - f->pcln.array;
   455  		f->pcln.cap = f->pcln.len;
   456  	}
   457  }
   458  
   459  
   460  // Return actual file line number for targetpc in func f.
   461  // (Source file is f->src.)
   462  // NOTE(rsc): If you edit this function, also edit extern.go:/FileLine
   463  int32
   464  runtime·funcline(Func *f, uintptr targetpc)
   465  {
   466  	byte *p, *ep;
   467  	uintptr pc;
   468  	int32 line;
   469  	int32 pcquant;
   470  
   471  	enum {
   472  		debug = 0
   473  	};
   474  
   475  	switch(thechar) {
   476  	case '5':
   477  		pcquant = 4;
   478  		break;
   479  	default:	// 6, 8
   480  		pcquant = 1;
   481  		break;
   482  	}
   483  
   484  	p = f->pcln.array;
   485  	ep = p + f->pcln.len;
   486  	pc = f->pc0;
   487  	line = f->ln0;
   488  	if(debug && !runtime·panicking)
   489  		runtime·printf("funcline start pc=%p targetpc=%p line=%d tab=%p+%d\n",
   490  			pc, targetpc, line, p, (int32)f->pcln.len);
   491  	for(;;) {
   492  		// Table is a sequence of updates.
   493  
   494  		// Each update says first how to adjust the pc,
   495  		// in possibly multiple instructions...
   496  		while(p < ep && *p > 128)
   497  			pc += pcquant * (*p++ - 128);
   498  
   499  		if(debug && !runtime·panicking)
   500  			runtime·printf("pc<%p targetpc=%p line=%d\n", pc, targetpc, line);
   501  
   502  		// If the pc has advanced too far or we're out of data,
   503  		// stop and the last known line number.
   504  		if(pc > targetpc || p >= ep)
   505  			break;
   506  
   507  		// ... and then how to adjust the line number,
   508  		// in a single instruction.
   509  		if(*p == 0) {
   510  			if(p+5 > ep)
   511  				break;
   512  			line += (p[1]<<24) | (p[2]<<16) | (p[3]<<8) | p[4];
   513  			p += 5;
   514  		} else if(*p <= 64)
   515  			line += *p++;
   516  		else
   517  			line -= *p++ - 64;
   518  		// Now pc, line pair is consistent.
   519  		if(debug && !runtime·panicking)
   520  			runtime·printf("pc=%p targetpc=%p line=%d\n", pc, targetpc, line);
   521  
   522  		// PC increments implicitly on each iteration.
   523  		pc += pcquant;
   524  	}
   525  	return line;
   526  }
   527  
   528  void
   529  runtime·funcline_go(Func *f, uintptr targetpc, String retfile, intgo retline)
   530  {
   531  	retfile = f->src;
   532  	retline = runtime·funcline(f, targetpc);
   533  	FLUSH(&retfile);
   534  	FLUSH(&retline);
   535  }
   536  
   537  static void
   538  buildfuncs(void)
   539  {
   540  	extern byte etext[];
   541  
   542  	if(func != nil)
   543  		return;
   544  
   545  	// Memory profiling uses this code;
   546  	// can deadlock if the profiler ends
   547  	// up back here.
   548  	m->nomemprof++;
   549  
   550  	// count funcs, fnames
   551  	nfunc = 0;
   552  	nfname = 0;
   553  	lastvalue = 0;
   554  	walksymtab(dofunc);
   555  
   556  	// Initialize tables.
   557  	// Can use FlagNoPointers - all pointers either point into sections of the executable
   558  	// or point into hugestring.
   559  	func = runtime·mallocgc((nfunc+1)*sizeof func[0], FlagNoPointers, 0, 1);
   560  	func[nfunc].entry = (uint64)etext;
   561  	fname = runtime·mallocgc(nfname*sizeof fname[0], FlagNoPointers, 0, 1);
   562  	nfunc = 0;
   563  	lastvalue = 0;
   564  	walksymtab(dofunc);
   565  
   566  	// split pc/ln table by func
   567  	splitpcln();
   568  
   569  	// record src file and line info for each func
   570  	walksymtab(dosrcline);  // pass 1: determine hugestring_len
   571  	hugestring.str = runtime·mallocgc(hugestring_len, FlagNoPointers, 0, 0);
   572  	hugestring.len = 0;
   573  	walksymtab(dosrcline);  // pass 2: fill and use hugestring
   574  
   575  	if(hugestring.len != hugestring_len)
   576  		runtime·throw("buildfunc: problem in initialization procedure");
   577  
   578  	m->nomemprof--;
   579  }
   580  
   581  Func*
   582  runtime·findfunc(uintptr addr)
   583  {
   584  	Func *f;
   585  	int32 nf, n;
   586  
   587  	// Use atomic double-checked locking,
   588  	// because when called from pprof signal
   589  	// handler, findfunc must run without
   590  	// grabbing any locks.
   591  	// (Before enabling the signal handler,
   592  	// SetCPUProfileRate calls findfunc to trigger
   593  	// the initialization outside the handler.)
   594  	// Avoid deadlock on fault during malloc
   595  	// by not calling buildfuncs if we're already in malloc.
   596  	if(!m->mallocing && !m->gcing) {
   597  		if(runtime·atomicload(&funcinit) == 0) {
   598  			runtime·lock(&funclock);
   599  			if(funcinit == 0) {
   600  				buildfuncs();
   601  				runtime·atomicstore(&funcinit, 1);
   602  			}
   603  			runtime·unlock(&funclock);
   604  		}
   605  	}
   606  
   607  	if(nfunc == 0)
   608  		return nil;
   609  	if(addr < func[0].entry || addr >= func[nfunc].entry)
   610  		return nil;
   611  
   612  	// binary search to find func with entry <= addr.
   613  	f = func;
   614  	nf = nfunc;
   615  	while(nf > 0) {
   616  		n = nf/2;
   617  		if(f[n].entry <= addr && addr < f[n+1].entry)
   618  			return &f[n];
   619  		else if(addr < f[n].entry)
   620  			nf = n;
   621  		else {
   622  			f += n+1;
   623  			nf -= n+1;
   624  		}
   625  	}
   626  
   627  	// can't get here -- we already checked above
   628  	// that the address was in the table bounds.
   629  	// this can only happen if the table isn't sorted
   630  	// by address or if the binary search above is buggy.
   631  	runtime·prints("findfunc unreachable\n");
   632  	return nil;
   633  }
   634  
   635  static bool
   636  hasprefix(String s, int8 *p)
   637  {
   638  	int32 i;
   639  
   640  	for(i=0; i<s.len; i++) {
   641  		if(p[i] == 0)
   642  			return 1;
   643  		if(p[i] != s.str[i])
   644  			return 0;
   645  	}
   646  	return p[i] == 0;
   647  }
   648  
   649  static bool
   650  contains(String s, int8 *p)
   651  {
   652  	int32 i;
   653  
   654  	if(p[0] == 0)
   655  		return 1;
   656  	for(i=0; i<s.len; i++) {
   657  		if(s.str[i] != p[0])
   658  			continue;
   659  		if(hasprefix((String){s.str + i, s.len - i}, p))
   660  			return 1;
   661  	}
   662  	return 0;
   663  }
   664  
   665  bool
   666  runtime·showframe(Func *f, bool current)
   667  {
   668  	static int32 traceback = -1;
   669  
   670  	if(current && m->throwing > 0)
   671  		return 1;
   672  	if(traceback < 0)
   673  		traceback = runtime·gotraceback(nil);
   674  	return traceback > 1 || f != nil && contains(f->name, ".") && !hasprefix(f->name, "runtime.");
   675  }