~john-koepi/ubuntu/trusty/golang/default

« back to all changes in this revision

Viewing changes to src/pkg/runtime/symtab.c

  • Committer: Bazaar Package Importer
  • Author(s): Ondřej Surý
  • Date: 2011-04-20 17:36:48 UTC
  • Revision ID: james.westby@ubuntu.com-20110420173648-ifergoxyrm832trd
Tags: upstream-2011.03.07.1
Import upstream version 2011.03.07.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 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.
 
10
//
 
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.
 
14
 
 
15
#include "runtime.h"
 
16
#include "defs.h"
 
17
#include "os.h"
 
18
#include "arch.h"
 
19
 
 
20
extern byte pclntab[], epclntab[], symtab[], esymtab[];
 
21
 
 
22
typedef struct Sym Sym;
 
23
struct Sym
 
24
{
 
25
        uintptr value;
 
26
        byte symtype;
 
27
        byte *name;
 
28
//      byte *gotype;
 
29
};
 
30
 
 
31
// Walk over symtab, calling fn(&s) for each symbol.
 
32
static void
 
33
walksymtab(void (*fn)(Sym*))
 
34
{
 
35
        byte *p, *ep, *q;
 
36
        Sym s;
 
37
 
 
38
        p = symtab;
 
39
        ep = esymtab;
 
40
        while(p < ep) {
 
41
                if(p + 7 > ep)
 
42
                        break;
 
43
                s.value = ((uint32)p[0]<<24) | ((uint32)p[1]<<16) | ((uint32)p[2]<<8) | ((uint32)p[3]);
 
44
 
 
45
                if(!(p[4]&0x80))
 
46
                        break;
 
47
                s.symtype = p[4] & ~0x80;
 
48
                p += 5;
 
49
                s.name = p;
 
50
                if(s.symtype == 'z' || s.symtype == 'Z') {
 
51
                        // path reference string - skip first byte,
 
52
                        // then 2-byte pairs ending at two zeros.
 
53
                        q = p+1;
 
54
                        for(;;) {
 
55
                                if(q+2 > ep)
 
56
                                        return;
 
57
                                if(q[0] == '\0' && q[1] == '\0')
 
58
                                        break;
 
59
                                q += 2;
 
60
                        }
 
61
                        p = q+2;
 
62
                }else{
 
63
                        q = runtime·mchr(p, '\0', ep);
 
64
                        if(q == nil)
 
65
                                break;
 
66
                        p = q+1;
 
67
                }
 
68
                p += 4; // go type
 
69
                fn(&s);
 
70
        }
 
71
}
 
72
 
 
73
// Symtab walker; accumulates info about functions.
 
74
 
 
75
static Func *func;
 
76
static int32 nfunc;
 
77
 
 
78
static byte **fname;
 
79
static int32 nfname;
 
80
 
 
81
static Lock funclock;
 
82
 
 
83
static void
 
84
dofunc(Sym *sym)
 
85
{
 
86
        Func *f;
 
87
 
 
88
        switch(sym->symtype) {
 
89
        case 't':
 
90
        case 'T':
 
91
        case 'l':
 
92
        case 'L':
 
93
                if(runtime·strcmp(sym->name, (byte*)"etext") == 0)
 
94
                        break;
 
95
                if(func == nil) {
 
96
                        nfunc++;
 
97
                        break;
 
98
                }
 
99
                f = &func[nfunc++];
 
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);
 
104
                break;
 
105
        case 'm':
 
106
                if(nfunc > 0 && func != nil)
 
107
                        func[nfunc-1].frame += sym->value;
 
108
                break;
 
109
        case 'p':
 
110
                if(nfunc > 0 && func != nil) {
 
111
                        f = &func[nfunc-1];
 
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;
 
117
                }
 
118
                break;
 
119
        case 'f':
 
120
                if(fname == nil) {
 
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");
 
125
                                }
 
126
                                nfname = sym->value+1;
 
127
                        }
 
128
                        break;
 
129
                }
 
130
                fname[sym->value] = sym->name;
 
131
                break;
 
132
        }
 
133
}
 
134
 
 
135
// put together the path name for a z entry.
 
136
// the f entries have been accumulated into fname already.
 
137
static void
 
138
makepath(byte *buf, int32 nbuf, byte *path)
 
139
{
 
140
        int32 n, len;
 
141
        byte *p, *ep, *q;
 
142
 
 
143
        if(nbuf <= 0)
 
144
                return;
 
145
 
 
146
        p = buf;
 
147
        ep = buf + nbuf;
 
148
        *p = '\0';
 
149
        for(;;) {
 
150
                if(path[0] == 0 && path[1] == 0)
 
151
                        break;
 
152
                n = (path[0]<<8) | path[1];
 
153
                path += 2;
 
154
                if(n >= nfname)
 
155
                        break;
 
156
                q = fname[n];
 
157
                len = runtime·findnull(q);
 
158
                if(p+1+len >= ep)
 
159
                        break;
 
160
                if(p > buf && p[-1] != '/')
 
161
                        *p++ = '/';
 
162
                runtime·mcpy(p, q, len+1);
 
163
                p += len;
 
164
        }
 
165
}
 
166
 
 
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.
 
171
static void
 
172
dosrcline(Sym *sym)
 
173
{
 
174
        static byte srcbuf[1000];
 
175
        static struct {
 
176
                String srcstring;
 
177
                int32 aline;
 
178
                int32 delta;
 
179
        } files[200];
 
180
        static int32 incstart;
 
181
        static int32 nfunc, nfile, nhist;
 
182
        Func *f;
 
183
        int32 i;
 
184
 
 
185
        switch(sym->symtype) {
 
186
        case 't':
 
187
        case 'T':
 
188
                if(runtime·strcmp(sym->name, (byte*)"etext") == 0)
 
189
                        break;
 
190
                f = &func[nfunc++];
 
191
                // find source file
 
192
                for(i = 0; i < nfile - 1; i++) {
 
193
                        if (files[i+1].aline > f->ln0)
 
194
                                break;
 
195
                }
 
196
                f->src = files[i].srcstring;
 
197
                f->ln0 -= files[i].delta;
 
198
                break;
 
199
        case 'z':
 
200
                if(sym->value == 1) {
 
201
                        // entry for main source file for a new object.
 
202
                        makepath(srcbuf, sizeof srcbuf, sym->name+1);
 
203
                        nhist = 0;
 
204
                        nfile = 0;
 
205
                        if(nfile == nelem(files))
 
206
                                return;
 
207
                        files[nfile].srcstring = runtime·gostring(srcbuf);
 
208
                        files[nfile].aline = 0;
 
209
                        files[nfile++].delta = 0;
 
210
                } else {
 
211
                        // push or pop of included file.
 
212
                        makepath(srcbuf, sizeof srcbuf, sym->name+1);
 
213
                        if(srcbuf[0] != '\0') {
 
214
                                if(nhist++ == 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;
 
220
                                        // this is "line 0"
 
221
                                        files[nfile++].delta = sym->value - 1;
 
222
                                }
 
223
                        }else{
 
224
                                if(--nhist == 0)
 
225
                                        files[nfile-1].delta += sym->value - incstart;
 
226
                        }
 
227
                }
 
228
        }
 
229
}
 
230
 
 
231
// Interpret pc/ln table, saving the subpiece for each func.
 
232
static void
 
233
splitpcln(void)
 
234
{
 
235
        int32 line;
 
236
        uintptr pc;
 
237
        byte *p, *ep;
 
238
        Func *f, *ef;
 
239
        int32 pcquant;
 
240
 
 
241
        if(pclntab == epclntab || nfunc == 0)
 
242
                return;
 
243
 
 
244
        switch(thechar) {
 
245
        case '5':
 
246
                pcquant = 4;
 
247
                break;
 
248
        default:        // 6, 8
 
249
                pcquant = 1;
 
250
                break;
 
251
        }
 
252
 
 
253
        // pc/ln table bounds
 
254
        p = pclntab;
 
255
        ep = epclntab;
 
256
 
 
257
        f = func;
 
258
        ef = func + nfunc;
 
259
        pc = func[0].entry;     // text base
 
260
        f->pcln.array = p;
 
261
        f->pc0 = pc;
 
262
        line = 0;
 
263
        for(;;) {
 
264
                while(p < ep && *p > 128)
 
265
                        pc += pcquant * (*p++ - 128);
 
266
                // runtime·printf("pc<%p targetpc=%p line=%d\n", pc, targetpc, line);
 
267
                if(*p == 0) {
 
268
                        if(p+5 > ep)
 
269
                                break;
 
270
                        // 4 byte add to line
 
271
                        line += (p[1]<<24) | (p[2]<<16) | (p[3]<<8) | p[4];
 
272
                        p += 5;
 
273
                } else if(*p <= 64)
 
274
                        line += *p++;
 
275
                else
 
276
                        line -= *p++ - 64;
 
277
                
 
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) {
 
286
                        f->pcln.array = p;
 
287
                        f->pc0 = pc + pcquant;
 
288
                        f->ln0 = line;
 
289
                }
 
290
 
 
291
                if(f < ef && pc >= (f+1)->entry) {
 
292
                        f->pcln.len = p - f->pcln.array;
 
293
                        f->pcln.cap = f->pcln.len;
 
294
                        f++;
 
295
                        f->pcln.array = p;
 
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;
 
301
                        f->ln0 = line;
 
302
                }
 
303
 
 
304
                pc += pcquant;
 
305
        }
 
306
        if(f < ef) {
 
307
                f->pcln.len = p - f->pcln.array;
 
308
                f->pcln.cap = f->pcln.len;
 
309
        }
 
310
}
 
311
 
 
312
 
 
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
 
316
int32
 
317
runtime·funcline(Func *f, uintptr targetpc)
 
318
{
 
319
        byte *p, *ep;
 
320
        uintptr pc;
 
321
        int32 line;
 
322
        int32 pcquant;
 
323
        
 
324
        enum {
 
325
                debug = 0
 
326
        };
 
327
        
 
328
        switch(thechar) {
 
329
        case '5':
 
330
                pcquant = 4;
 
331
                break;
 
332
        default:        // 6, 8
 
333
                pcquant = 1;
 
334
                break;
 
335
        }
 
336
 
 
337
        p = f->pcln.array;
 
338
        ep = p + f->pcln.len;
 
339
        pc = f->pc0;
 
340
        line = f->ln0;
 
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);
 
344
        for(;;) {
 
345
                // Table is a sequence of updates.
 
346
 
 
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);
 
351
 
 
352
                if(debug && !runtime·panicking)
 
353
                        runtime·printf("pc<%p targetpc=%p line=%d\n", pc, targetpc, line);
 
354
                
 
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)
 
358
                        break;
 
359
 
 
360
                // ... and then how to adjust the line number,
 
361
                // in a single instruction.
 
362
                if(*p == 0) {
 
363
                        if(p+5 > ep)
 
364
                                break;
 
365
                        line += (p[1]<<24) | (p[2]<<16) | (p[3]<<8) | p[4];
 
366
                        p += 5;
 
367
                } else if(*p <= 64)
 
368
                        line += *p++;
 
369
                else
 
370
                        line -= *p++ - 64;
 
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);
 
374
 
 
375
                // PC increments implicitly on each iteration.
 
376
                pc += pcquant;
 
377
        }
 
378
        return line;
 
379
}
 
380
 
 
381
static void
 
382
buildfuncs(void)
 
383
{
 
384
        extern byte etext[];
 
385
 
 
386
        if(func != nil)
 
387
                return;
 
388
 
 
389
        // Memory profiling uses this code;
 
390
        // can deadlock if the profiler ends
 
391
        // up back here.
 
392
        m->nomemprof++;
 
393
 
 
394
        // count funcs, fnames
 
395
        nfunc = 0;
 
396
        nfname = 0;
 
397
        walksymtab(dofunc);
 
398
 
 
399
        // initialize tables
 
400
        func = runtime·mal((nfunc+1)*sizeof func[0]);
 
401
        func[nfunc].entry = (uint64)etext;
 
402
        fname = runtime·mal(nfname*sizeof fname[0]);
 
403
        nfunc = 0;
 
404
        walksymtab(dofunc);
 
405
 
 
406
        // split pc/ln table by func
 
407
        splitpcln();
 
408
 
 
409
        // record src file and line info for each func
 
410
        walksymtab(dosrcline);
 
411
 
 
412
        m->nomemprof--;
 
413
}
 
414
 
 
415
Func*
 
416
runtime·findfunc(uintptr addr)
 
417
{
 
418
        Func *f;
 
419
        int32 nf, n;
 
420
 
 
421
        runtime·lock(&funclock);
 
422
        if(func == nil)
 
423
                buildfuncs();
 
424
        runtime·unlock(&funclock);
 
425
 
 
426
        if(nfunc == 0)
 
427
                return nil;
 
428
        if(addr < func[0].entry || addr >= func[nfunc].entry)
 
429
                return nil;
 
430
 
 
431
        // binary search to find func with entry <= addr.
 
432
        f = func;
 
433
        nf = nfunc;
 
434
        while(nf > 0) {
 
435
                n = nf/2;
 
436
                if(f[n].entry <= addr && addr < f[n+1].entry)
 
437
                        return &f[n];
 
438
                else if(addr < f[n].entry)
 
439
                        nf = n;
 
440
                else {
 
441
                        f += n+1;
 
442
                        nf -= n+1;
 
443
                }
 
444
        }
 
445
 
 
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");
 
451
        return nil;
 
452
}