LEFT | RIGHT |
1 // Copyright 2009 The Go Authors. All rights reserved. | 1 // Copyright 2009 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 // Runtime symbol table parsing. | 5 // Runtime symbol table parsing. |
6 // | 6 // |
7 // The Go tools use a symbol table derived from the Plan 9 symbol table | 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 | 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 | 9 // read-only memory when the binary is running: the binary consults the |
10 // table. | 10 // table. |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
186 } | 186 } |
187 | 187 |
188 // Symtab walker; accumulates info about functions. | 188 // Symtab walker; accumulates info about functions. |
189 | 189 |
190 static Func *func; | 190 static Func *func; |
191 static int32 nfunc; | 191 static int32 nfunc; |
192 | 192 |
193 static byte **fname; | 193 static byte **fname; |
194 static int32 nfname; | 194 static int32 nfname; |
195 | 195 |
196 static uint32 **fgc; | |
197 | |
198 static uint32 funcinit; | |
199 static Lock funclock; | |
200 static uintptr lastvalue; | 196 static uintptr lastvalue; |
201 | 197 |
202 static void | 198 static void |
203 dofunc(Sym *sym) | 199 dofunc(Sym *sym) |
204 { | 200 { |
205 Func *f; | 201 Func *f; |
| 202 uintgo cap; |
206 ········ | 203 ········ |
207 switch(sym->symtype) { | 204 switch(sym->symtype) { |
208 case 't': | 205 case 't': |
209 case 'T': | 206 case 'T': |
210 case 'l': | 207 case 'l': |
211 case 'L': | 208 case 'L': |
212 if(runtime·strcmp(sym->name, (byte*)"etext") == 0) | 209 if(runtime·strcmp(sym->name, (byte*)"etext") == 0) |
213 break; | 210 break; |
214 if(sym->value < lastvalue) { | 211 if(sym->value < lastvalue) { |
215 runtime·printf("symbols out of order: %p before %p\n", l
astvalue, sym->value); | 212 runtime·printf("symbols out of order: %p before %p\n", l
astvalue, sym->value); |
(...skipping 13 matching lines...) Expand all Loading... |
229 case 'm': | 226 case 'm': |
230 if(nfunc <= 0 || func == nil) | 227 if(nfunc <= 0 || func == nil) |
231 break; | 228 break; |
232 if(runtime·strcmp(sym->name, (byte*)".frame") == 0) | 229 if(runtime·strcmp(sym->name, (byte*)".frame") == 0) |
233 func[nfunc-1].frame = sym->value; | 230 func[nfunc-1].frame = sym->value; |
234 else if(runtime·strcmp(sym->name, (byte*)".locals") == 0) | 231 else if(runtime·strcmp(sym->name, (byte*)".locals") == 0) |
235 func[nfunc-1].locals = sym->value; | 232 func[nfunc-1].locals = sym->value; |
236 else if(runtime·strcmp(sym->name, (byte*)".args") == 0) | 233 else if(runtime·strcmp(sym->name, (byte*)".args") == 0) |
237 func[nfunc-1].args = sym->value; | 234 func[nfunc-1].args = sym->value; |
238 else if(runtime·strcmp(sym->name, (byte*)".nptrs") == 0) { | 235 else if(runtime·strcmp(sym->name, (byte*)".nptrs") == 0) { |
239 » » » fgc[nfunc-1] = runtime·mallocgc(sym->value*sizeof(**fgc)
, FlagNoPointers, 0, 1); | 236 » » » // TODO(cshapiro): use a dense representation for gc inf
ormation |
240 » » » func[nfunc-1].ptrs = (Slice){(byte*)fgc[nfunc-1], 0, sym
->value}; | 237 » » » if(sym->value > func[nfunc-1].args/sizeof(uintptr)) { |
241 » » } else if(runtime·strcmp(sym->name, (byte*)".ptrs") == 0) | 238 » » » » runtime·printf("more pointer map entries than ar
gument words\n"); |
| 239 » » » » runtime·throw("mangled symbol table"); |
| 240 » » » } |
| 241 » » » cap = ROUND(sym->value, 32) / 32; |
| 242 » » » func[nfunc-1].ptrs.array = runtime·mallocgc(cap*sizeof(u
int32), FlagNoPointers|FlagNoGC, 0, 1); |
| 243 » » » func[nfunc-1].ptrs.len = 0; |
| 244 » » » func[nfunc-1].ptrs.cap = cap; |
| 245 » » } else if(runtime·strcmp(sym->name, (byte*)".ptrs") == 0) { |
| 246 » » » if(func[nfunc-1].ptrs.len >= func[nfunc-1].ptrs.cap) { |
| 247 » » » » runtime·printf("more pointer map entries read th
an argument words\n"); |
| 248 » » » » runtime·throw("mangled symbol table"); |
| 249 » » » } |
242 ((uint32*)func[nfunc-1].ptrs.array)[func[nfunc-1].ptrs.l
en++] = sym->value; | 250 ((uint32*)func[nfunc-1].ptrs.array)[func[nfunc-1].ptrs.l
en++] = sym->value; |
243 » » else { | 251 » » } else { |
244 runtime·printf("invalid '%c' symbol named '%s'\n", (int8
)sym->symtype, sym->name); | 252 runtime·printf("invalid '%c' symbol named '%s'\n", (int8
)sym->symtype, sym->name); |
245 runtime·throw("mangled symbol table"); | 253 runtime·throw("mangled symbol table"); |
246 } | 254 } |
247 break; | 255 break; |
248 case 'f': | 256 case 'f': |
249 if(fname == nil) { | 257 if(fname == nil) { |
250 if(sym->value >= nfname) { | 258 if(sym->value >= nfname) { |
251 if(sym->value >= 0x10000) { | 259 if(sym->value >= 0x10000) { |
252 runtime·printf("runtime: invalid symbol
file index %p\n", sym->value); | 260 runtime·printf("runtime: invalid symbol
file index %p\n", sym->value); |
253 runtime·throw("mangled symbol table"); | 261 runtime·throw("mangled symbol table"); |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
307 hugestring_len += l; | 315 hugestring_len += l; |
308 return runtime·emptystring; | 316 return runtime·emptystring; |
309 } | 317 } |
310 s.str = hugestring.str + hugestring.len; | 318 s.str = hugestring.str + hugestring.len; |
311 s.len = l; | 319 s.len = l; |
312 hugestring.len += s.len; | 320 hugestring.len += s.len; |
313 runtime·memmove(s.str, p, l); | 321 runtime·memmove(s.str, p, l); |
314 return s; | 322 return s; |
315 } | 323 } |
316 | 324 |
| 325 static struct |
| 326 { |
| 327 String srcstring; |
| 328 int32 aline; |
| 329 int32 delta; |
| 330 } *files; |
| 331 |
| 332 enum { maxfiles = 200 }; |
| 333 |
317 // walk symtab accumulating path names for use by pc/ln table. | 334 // walk symtab accumulating path names for use by pc/ln table. |
318 // don't need the full generality of the z entry history stack because | 335 // don't need the full generality of the z entry history stack because |
319 // there are no includes in go (and only sensible includes in our c); | 336 // there are no includes in go (and only sensible includes in our c); |
320 // assume code only appear in top-level files. | 337 // assume code only appear in top-level files. |
321 static void | 338 static void |
322 dosrcline(Sym *sym) | 339 dosrcline(Sym *sym) |
323 { | 340 { |
| 341 #pragma dataflag 16 // no pointers |
324 static byte srcbuf[1000]; | 342 static byte srcbuf[1000]; |
325 static struct { | |
326 String srcstring; | |
327 int32 aline; | |
328 int32 delta; | |
329 } files[200]; | |
330 static int32 incstart; | 343 static int32 incstart; |
331 static int32 nfunc, nfile, nhist; | 344 static int32 nfunc, nfile, nhist; |
332 Func *f; | 345 Func *f; |
333 int32 i, l; | 346 int32 i, l; |
334 | 347 |
335 switch(sym->symtype) { | 348 switch(sym->symtype) { |
336 case 't': | 349 case 't': |
337 case 'T': | 350 case 'T': |
338 if(hugestring.str == nil) | 351 if(hugestring.str == nil) |
339 break; | 352 break; |
340 if(runtime·strcmp(sym->name, (byte*)"etext") == 0) | 353 if(runtime·strcmp(sym->name, (byte*)"etext") == 0) |
341 break; | 354 break; |
342 f = &func[nfunc++]; | 355 f = &func[nfunc++]; |
343 // find source file | 356 // find source file |
344 for(i = 0; i < nfile - 1; i++) { | 357 for(i = 0; i < nfile - 1; i++) { |
345 if (files[i+1].aline > f->ln0) | 358 if (files[i+1].aline > f->ln0) |
346 break; | 359 break; |
347 } | 360 } |
348 f->src = files[i].srcstring; | 361 f->src = files[i].srcstring; |
349 f->ln0 -= files[i].delta; | 362 f->ln0 -= files[i].delta; |
350 break; | 363 break; |
351 case 'z': | 364 case 'z': |
352 if(sym->value == 1) { | 365 if(sym->value == 1) { |
353 // entry for main source file for a new object. | 366 // entry for main source file for a new object. |
354 l = makepath(srcbuf, sizeof srcbuf, sym->name+1); | 367 l = makepath(srcbuf, sizeof srcbuf, sym->name+1); |
355 nhist = 0; | 368 nhist = 0; |
356 nfile = 0; | 369 nfile = 0; |
357 » » » if(nfile == nelem(files)) | 370 » » » if(nfile == maxfiles) |
358 return; | 371 return; |
359 files[nfile].srcstring = gostringn(srcbuf, l); | 372 files[nfile].srcstring = gostringn(srcbuf, l); |
360 files[nfile].aline = 0; | 373 files[nfile].aline = 0; |
361 files[nfile++].delta = 0; | 374 files[nfile++].delta = 0; |
362 } else { | 375 } else { |
363 // push or pop of included file. | 376 // push or pop of included file. |
364 l = makepath(srcbuf, sizeof srcbuf, sym->name+1); | 377 l = makepath(srcbuf, sizeof srcbuf, sym->name+1); |
365 if(srcbuf[0] != '\0') { | 378 if(srcbuf[0] != '\0') { |
366 if(nhist++ == 0) | 379 if(nhist++ == 0) |
367 incstart = sym->value; | 380 incstart = sym->value; |
368 » » » » if(nhist == 0 && nfile < nelem(files)) { | 381 » » » » if(nhist == 0 && nfile < maxfiles) { |
369 // new top-level file | 382 // new top-level file |
370 files[nfile].srcstring = gostringn(srcbu
f, l); | 383 files[nfile].srcstring = gostringn(srcbu
f, l); |
371 files[nfile].aline = sym->value; | 384 files[nfile].aline = sym->value; |
372 // this is "line 0" | 385 // this is "line 0" |
373 files[nfile++].delta = sym->value - 1; | 386 files[nfile++].delta = sym->value - 1; |
374 } | 387 } |
375 }else{ | 388 }else{ |
376 if(--nhist == 0) | 389 if(--nhist == 0) |
377 files[nfile-1].delta += sym->value - inc
start; | 390 files[nfile-1].delta += sym->value - inc
start; |
378 } | 391 } |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
534 | 547 |
535 void | 548 void |
536 runtime·funcline_go(Func *f, uintptr targetpc, String retfile, intgo retline) | 549 runtime·funcline_go(Func *f, uintptr targetpc, String retfile, intgo retline) |
537 { | 550 { |
538 retfile = f->src; | 551 retfile = f->src; |
539 retline = runtime·funcline(f, targetpc); | 552 retline = runtime·funcline(f, targetpc); |
540 FLUSH(&retfile); | 553 FLUSH(&retfile); |
541 FLUSH(&retline); | 554 FLUSH(&retline); |
542 } | 555 } |
543 | 556 |
544 static void | 557 void |
545 buildfuncs(void) | 558 runtime·symtabinit(void) |
546 { | 559 { |
547 extern byte etext[]; | 560 extern byte etext[]; |
548 | 561 |
549 if(func != nil) | 562 if(func != nil) |
550 return; | 563 return; |
551 | 564 |
552 // Memory profiling uses this code; | 565 // Memory profiling uses this code; |
553 // can deadlock if the profiler ends | 566 // can deadlock if the profiler ends |
554 // up back here. | 567 // up back here. |
555 m->nomemprof++; | 568 m->nomemprof++; |
556 | 569 |
557 // count funcs, fnames | 570 // count funcs, fnames |
558 nfunc = 0; | 571 nfunc = 0; |
559 nfname = 0; | 572 nfname = 0; |
560 lastvalue = 0; | 573 lastvalue = 0; |
561 walksymtab(dofunc); | 574 walksymtab(dofunc); |
562 | 575 |
563 // Initialize tables. | 576 // Initialize tables. |
564 // Can use FlagNoPointers - all pointers either point into sections of t
he executable | 577 // Can use FlagNoPointers - all pointers either point into sections of t
he executable |
565 // or point into hugestring. | 578 // or point into hugestring. |
566 func = runtime·mallocgc((nfunc+1)*sizeof func[0], FlagNoPointers, 0, 1); | 579 func = runtime·mallocgc((nfunc+1)*sizeof func[0], FlagNoPointers, 0, 1); |
567 func[nfunc].entry = (uint64)etext; | 580 func[nfunc].entry = (uint64)etext; |
568 fname = runtime·mallocgc(nfname*sizeof fname[0], FlagNoPointers, 0, 1); | 581 fname = runtime·mallocgc(nfname*sizeof fname[0], FlagNoPointers, 0, 1); |
569 fgc = runtime·mallocgc(nfunc*sizeof(*fgc), 0, 0, 1); | |
570 nfunc = 0; | 582 nfunc = 0; |
571 lastvalue = 0; | 583 lastvalue = 0; |
572 walksymtab(dofunc); | 584 walksymtab(dofunc); |
573 | 585 |
574 // split pc/ln table by func | 586 // split pc/ln table by func |
575 splitpcln(); | 587 splitpcln(); |
576 | 588 |
577 // record src file and line info for each func | 589 // record src file and line info for each func |
| 590 files = runtime·malloc(maxfiles * sizeof(files[0])); |
578 walksymtab(dosrcline); // pass 1: determine hugestring_len | 591 walksymtab(dosrcline); // pass 1: determine hugestring_len |
579 hugestring.str = runtime·mallocgc(hugestring_len, FlagNoPointers, 0, 0); | 592 hugestring.str = runtime·mallocgc(hugestring_len, FlagNoPointers, 0, 0); |
580 hugestring.len = 0; | 593 hugestring.len = 0; |
581 walksymtab(dosrcline); // pass 2: fill and use hugestring | 594 walksymtab(dosrcline); // pass 2: fill and use hugestring |
| 595 files = nil; |
582 | 596 |
583 if(hugestring.len != hugestring_len) | 597 if(hugestring.len != hugestring_len) |
584 runtime·throw("buildfunc: problem in initialization procedure"); | 598 runtime·throw("buildfunc: problem in initialization procedure"); |
585 | 599 |
586 m->nomemprof--; | 600 m->nomemprof--; |
587 } | 601 } |
588 | 602 |
589 Func* | 603 Func* |
590 runtime·findfunc(uintptr addr) | 604 runtime·findfunc(uintptr addr) |
591 { | 605 { |
592 Func *f; | 606 Func *f; |
593 int32 nf, n; | 607 int32 nf, n; |
594 | |
595 // Use atomic double-checked locking, | |
596 // because when called from pprof signal | |
597 // handler, findfunc must run without | |
598 // grabbing any locks. | |
599 // (Before enabling the signal handler, | |
600 // SetCPUProfileRate calls findfunc to trigger | |
601 // the initialization outside the handler.) | |
602 // Avoid deadlock on fault during malloc | |
603 // by not calling buildfuncs if we're already in malloc. | |
604 if(!m->mallocing && !m->gcing) { | |
605 if(runtime·atomicload(&funcinit) == 0) { | |
606 runtime·lock(&funclock); | |
607 if(funcinit == 0) { | |
608 buildfuncs(); | |
609 runtime·atomicstore(&funcinit, 1); | |
610 } | |
611 runtime·unlock(&funclock); | |
612 } | |
613 } | |
614 | 608 |
615 if(nfunc == 0) | 609 if(nfunc == 0) |
616 return nil; | 610 return nil; |
617 if(addr < func[0].entry || addr >= func[nfunc].entry) | 611 if(addr < func[0].entry || addr >= func[nfunc].entry) |
618 return nil; | 612 return nil; |
619 | 613 |
620 // binary search to find func with entry <= addr. | 614 // binary search to find func with entry <= addr. |
621 f = func; | 615 f = func; |
622 nf = nfunc; | 616 nf = nfunc; |
623 while(nf > 0) { | 617 while(nf > 0) { |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
674 runtime·showframe(Func *f, bool current) | 668 runtime·showframe(Func *f, bool current) |
675 { | 669 { |
676 static int32 traceback = -1; | 670 static int32 traceback = -1; |
677 | 671 |
678 if(current && m->throwing > 0) | 672 if(current && m->throwing > 0) |
679 return 1; | 673 return 1; |
680 if(traceback < 0) | 674 if(traceback < 0) |
681 traceback = runtime·gotraceback(nil); | 675 traceback = runtime·gotraceback(nil); |
682 return traceback > 1 || f != nil && contains(f->name, ".") && !hasprefix
(f->name, "runtime."); | 676 return traceback > 1 || f != nil && contains(f->name, ".") && !hasprefix
(f->name, "runtime."); |
683 } | 677 } |
LEFT | RIGHT |