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.
5
// Runtime symbol table access. Work in progress.
6
// The Plan 9 symbol table is not in a particularly convenient form.
7
// The routines here massage it into a more usable form; eventually
8
// we'll change 6l to do this for us, but it is easier to experiment
9
// here than to change 6l and all the other tools.
11
// The symbol table also needs to be better integrated with the type
12
// strings table in the future. This is just a quick way to get started
13
// and figure out exactly what we want.
20
extern byte pclntab[], epclntab[], symtab[], esymtab[];
22
typedef struct Sym Sym;
31
// Walk over symtab, calling fn(&s) for each symbol.
33
walksymtab(void (*fn)(Sym*))
43
s.value = ((uint32)p[0]<<24) | ((uint32)p[1]<<16) | ((uint32)p[2]<<8) | ((uint32)p[3]);
47
s.symtype = p[4] & ~0x80;
50
if(s.symtype == 'z' || s.symtype == 'Z') {
51
// path reference string - skip first byte,
52
// then 2-byte pairs ending at two zeros.
57
if(q[0] == '\0' && q[1] == '\0')
63
q = runtime·mchr(p, '\0', ep);
73
// Symtab walker; accumulates info about functions.
88
switch(sym->symtype) {
93
if(runtime·strcmp(sym->name, (byte*)"etext") == 0)
100
f->name = runtime·gostringnocopy(sym->name);
101
f->entry = sym->value;
102
if(sym->symtype == 'L' || sym->symtype == 'l')
103
f->frame = -sizeof(uintptr);
106
if(nfunc > 0 && func != nil)
107
func[nfunc-1].frame += sym->value;
110
if(nfunc > 0 && func != nil) {
112
// args counts 32-bit words.
113
// sym->value is the arg's offset.
114
// don't know width of this arg, so assume it is 64 bits.
115
if(f->args < sym->value/4 + 2)
116
f->args = sym->value/4 + 2;
121
if(sym->value >= nfname) {
122
if(sym->value >= 0x10000) {
123
runtime·printf("invalid symbol file index %p\n", sym->value);
124
runtime·throw("mangled symbol table");
126
nfname = sym->value+1;
130
fname[sym->value] = sym->name;
135
// put together the path name for a z entry.
136
// the f entries have been accumulated into fname already.
138
makepath(byte *buf, int32 nbuf, byte *path)
150
if(path[0] == 0 && path[1] == 0)
152
n = (path[0]<<8) | path[1];
157
len = runtime·findnull(q);
160
if(p > buf && p[-1] != '/')
162
runtime·mcpy(p, q, len+1);
167
// walk symtab accumulating path names for use by pc/ln table.
168
// don't need the full generality of the z entry history stack because
169
// there are no includes in go (and only sensible includes in our c);
170
// assume code only appear in top-level files.
174
static byte srcbuf[1000];
180
static int32 incstart;
181
static int32 nfunc, nfile, nhist;
185
switch(sym->symtype) {
188
if(runtime·strcmp(sym->name, (byte*)"etext") == 0)
192
for(i = 0; i < nfile - 1; i++) {
193
if (files[i+1].aline > f->ln0)
196
f->src = files[i].srcstring;
197
f->ln0 -= files[i].delta;
200
if(sym->value == 1) {
201
// entry for main source file for a new object.
202
makepath(srcbuf, sizeof srcbuf, sym->name+1);
205
if(nfile == nelem(files))
207
files[nfile].srcstring = runtime·gostring(srcbuf);
208
files[nfile].aline = 0;
209
files[nfile++].delta = 0;
211
// push or pop of included file.
212
makepath(srcbuf, sizeof srcbuf, sym->name+1);
213
if(srcbuf[0] != '\0') {
215
incstart = sym->value;
216
if(nhist == 0 && nfile < nelem(files)) {
217
// new top-level file
218
files[nfile].srcstring = runtime·gostring(srcbuf);
219
files[nfile].aline = sym->value;
221
files[nfile++].delta = sym->value - 1;
225
files[nfile-1].delta += sym->value - incstart;
231
// Interpret pc/ln table, saving the subpiece for each func.
241
if(pclntab == epclntab || nfunc == 0)
253
// pc/ln table bounds
259
pc = func[0].entry; // text base
264
while(p < ep && *p > 128)
265
pc += pcquant * (*p++ - 128);
266
// runtime·printf("pc<%p targetpc=%p line=%d\n", pc, targetpc, line);
270
// 4 byte add to line
271
line += (p[1]<<24) | (p[2]<<16) | (p[3]<<8) | p[4];
278
// pc, line now match.
279
// Because the state machine begins at pc==entry and line==0,
280
// it can happen - just at the beginning! - that the update may
281
// have updated line but left pc alone, to tell us the true line
282
// number for pc==entry. In that case, update f->ln0.
283
// Having the correct initial line number is important for choosing
284
// the correct file in dosrcline above.
285
if(f == func && pc == f->pc0) {
287
f->pc0 = pc + pcquant;
291
if(f < ef && pc >= (f+1)->entry) {
292
f->pcln.len = p - f->pcln.array;
293
f->pcln.cap = f->pcln.len;
296
// pc0 and ln0 are the starting values for
297
// the loop over f->pcln, so pc must be
298
// adjusted by the same pcquant update
299
// that we're going to do as we continue our loop.
300
f->pc0 = pc + pcquant;
307
f->pcln.len = p - f->pcln.array;
308
f->pcln.cap = f->pcln.len;
313
// Return actual file line number for targetpc in func f.
314
// (Source file is f->src.)
315
// NOTE(rsc): If you edit this function, also edit extern.go:/FileLine
317
runtime·funcline(Func *f, uintptr targetpc)
338
ep = p + f->pcln.len;
341
if(debug && !runtime·panicking)
342
runtime·printf("funcline start pc=%p targetpc=%p line=%d tab=%p+%d\n",
343
pc, targetpc, line, p, (int32)f->pcln.len);
345
// Table is a sequence of updates.
347
// Each update says first how to adjust the pc,
348
// in possibly multiple instructions...
349
while(p < ep && *p > 128)
350
pc += pcquant * (*p++ - 128);
352
if(debug && !runtime·panicking)
353
runtime·printf("pc<%p targetpc=%p line=%d\n", pc, targetpc, line);
355
// If the pc has advanced too far or we're out of data,
356
// stop and the last known line number.
357
if(pc > targetpc || p >= ep)
360
// ... and then how to adjust the line number,
361
// in a single instruction.
365
line += (p[1]<<24) | (p[2]<<16) | (p[3]<<8) | p[4];
371
// Now pc, line pair is consistent.
372
if(debug && !runtime·panicking)
373
runtime·printf("pc=%p targetpc=%p line=%d\n", pc, targetpc, line);
375
// PC increments implicitly on each iteration.
389
// Memory profiling uses this code;
390
// can deadlock if the profiler ends
394
// count funcs, fnames
400
func = runtime·mal((nfunc+1)*sizeof func[0]);
401
func[nfunc].entry = (uint64)etext;
402
fname = runtime·mal(nfname*sizeof fname[0]);
406
// split pc/ln table by func
409
// record src file and line info for each func
410
walksymtab(dosrcline);
416
runtime·findfunc(uintptr addr)
421
runtime·lock(&funclock);
424
runtime·unlock(&funclock);
428
if(addr < func[0].entry || addr >= func[nfunc].entry)
431
// binary search to find func with entry <= addr.
436
if(f[n].entry <= addr && addr < f[n+1].entry)
438
else if(addr < f[n].entry)
446
// can't get here -- we already checked above
447
// that the address was in the table bounds.
448
// this can only happen if the table isn't sorted
449
// by address or if the binary search above is buggy.
450
runtime·prints("findfunc unreachable\n");