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 funcinit; | |
197 static Lock funclock; | |
198 static uintptr lastvalue; | 196 static uintptr lastvalue; |
199 | 197 |
200 static void | 198 static void |
201 dofunc(Sym *sym) | 199 dofunc(Sym *sym) |
202 { | 200 { |
203 Func *f; | 201 Func *f; |
204 | 202 » uintgo cap; |
| 203 »······· |
205 switch(sym->symtype) { | 204 switch(sym->symtype) { |
206 case 't': | 205 case 't': |
207 case 'T': | 206 case 'T': |
208 case 'l': | 207 case 'l': |
209 case 'L': | 208 case 'L': |
210 if(runtime·strcmp(sym->name, (byte*)"etext") == 0) | 209 if(runtime·strcmp(sym->name, (byte*)"etext") == 0) |
211 break; | 210 break; |
212 if(sym->value < lastvalue) { | 211 if(sym->value < lastvalue) { |
213 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); |
214 runtime·throw("malformed symbol table"); | 213 runtime·throw("malformed symbol table"); |
215 } | 214 } |
216 lastvalue = sym->value; | 215 lastvalue = sym->value; |
217 if(func == nil) { | 216 if(func == nil) { |
218 nfunc++; | 217 nfunc++; |
219 break; | 218 break; |
220 } | 219 } |
221 f = &func[nfunc++]; | 220 f = &func[nfunc++]; |
222 f->name = runtime·gostringnocopy(sym->name); | 221 f->name = runtime·gostringnocopy(sym->name); |
223 f->entry = sym->value; | 222 f->entry = sym->value; |
224 if(sym->symtype == 'L' || sym->symtype == 'l') | 223 if(sym->symtype == 'L' || sym->symtype == 'l') |
225 f->frame = -sizeof(uintptr); | 224 f->frame = -sizeof(uintptr); |
226 break; | 225 break; |
227 case 'm': | 226 case 'm': |
228 if(nfunc <= 0 || func == nil) | 227 if(nfunc <= 0 || func == nil) |
229 break; | 228 break; |
230 if(runtime·strcmp(sym->name, (byte*)".frame") == 0) | 229 if(runtime·strcmp(sym->name, (byte*)".frame") == 0) |
231 func[nfunc-1].frame = sym->value; | 230 func[nfunc-1].frame = sym->value; |
232 else if(runtime·strcmp(sym->name, (byte*)".locals") == 0) | 231 else if(runtime·strcmp(sym->name, (byte*)".locals") == 0) |
233 func[nfunc-1].locals = sym->value; | 232 func[nfunc-1].locals = sym->value; |
234 » » else if(runtime·strcmp(sym->name, (byte*)".args") == 0) { | 233 » » else if(runtime·strcmp(sym->name, (byte*)".args") == 0) |
235 func[nfunc-1].args = sym->value; | 234 func[nfunc-1].args = sym->value; |
236 //if(func[nfunc-1].args==ArgsSizeUnknown)runtime·printf(
"unknown: %S\n",func[nfunc-1].name); | |
237 } | |
238 else if(runtime·strcmp(sym->name, (byte*)".nptrs") == 0) { | 235 else if(runtime·strcmp(sym->name, (byte*)".nptrs") == 0) { |
239 // TODO(cshapiro): use a dense representation for gc inf
ormation | 236 // TODO(cshapiro): use a dense representation for gc inf
ormation |
240 » » » if (sym->value > func[nfunc-1].args/sizeof(uintptr)) { | 237 » » » if(sym->value > func[nfunc-1].args/sizeof(uintptr)) { |
241 runtime·printf("more pointer map entries than ar
gument words\n"); | 238 runtime·printf("more pointer map entries than ar
gument words\n"); |
242 runtime·throw("mangled symbol table"); | 239 runtime·throw("mangled symbol table"); |
243 } | 240 } |
244 » » » func[nfunc-1].ptrs.array = runtime·mallocgc(sym->value*s
izeof(uint32), FlagNoPointers|FlagNoGC, 0, 1); | 241 » » » cap = ROUND(sym->value, 32) / 32; |
| 242 » » » func[nfunc-1].ptrs.array = runtime·mallocgc(cap*sizeof(u
int32), FlagNoPointers|FlagNoGC, 0, 1); |
245 func[nfunc-1].ptrs.len = 0; | 243 func[nfunc-1].ptrs.len = 0; |
246 » » » func[nfunc-1].ptrs.cap = sym->value; | 244 » » » func[nfunc-1].ptrs.cap = cap; |
247 } else if(runtime·strcmp(sym->name, (byte*)".ptrs") == 0) { | 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 } |
248 ((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; |
249 } else { | 251 } else { |
250 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); |
251 runtime·throw("mangled symbol table"); | 253 runtime·throw("mangled symbol table"); |
252 } | 254 } |
253 break; | 255 break; |
254 case 'f': | 256 case 'f': |
255 if(fname == nil) { | 257 if(fname == nil) { |
256 if(sym->value >= nfname) { | 258 if(sym->value >= nfname) { |
257 if(sym->value >= 0x10000) { | 259 if(sym->value >= 0x10000) { |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
313 hugestring_len += l; | 315 hugestring_len += l; |
314 return runtime·emptystring; | 316 return runtime·emptystring; |
315 } | 317 } |
316 s.str = hugestring.str + hugestring.len; | 318 s.str = hugestring.str + hugestring.len; |
317 s.len = l; | 319 s.len = l; |
318 hugestring.len += s.len; | 320 hugestring.len += s.len; |
319 runtime·memmove(s.str, p, l); | 321 runtime·memmove(s.str, p, l); |
320 return s; | 322 return s; |
321 } | 323 } |
322 | 324 |
| 325 static struct |
| 326 { |
| 327 String srcstring; |
| 328 int32 aline; |
| 329 int32 delta; |
| 330 } *files; |
| 331 |
| 332 enum { maxfiles = 200 }; |
| 333 |
323 // walk symtab accumulating path names for use by pc/ln table. | 334 // walk symtab accumulating path names for use by pc/ln table. |
324 // 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 |
325 // 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); |
326 // assume code only appear in top-level files. | 337 // assume code only appear in top-level files. |
327 static void | 338 static void |
328 dosrcline(Sym *sym) | 339 dosrcline(Sym *sym) |
329 { | 340 { |
| 341 #pragma dataflag 16 // no pointers |
330 static byte srcbuf[1000]; | 342 static byte srcbuf[1000]; |
331 static struct { | |
332 String srcstring; | |
333 int32 aline; | |
334 int32 delta; | |
335 } files[200]; | |
336 static int32 incstart; | 343 static int32 incstart; |
337 static int32 nfunc, nfile, nhist; | 344 static int32 nfunc, nfile, nhist; |
338 Func *f; | 345 Func *f; |
339 int32 i, l; | 346 int32 i, l; |
340 | 347 |
341 switch(sym->symtype) { | 348 switch(sym->symtype) { |
342 case 't': | 349 case 't': |
343 case 'T': | 350 case 'T': |
344 if(hugestring.str == nil) | 351 if(hugestring.str == nil) |
345 break; | 352 break; |
346 if(runtime·strcmp(sym->name, (byte*)"etext") == 0) | 353 if(runtime·strcmp(sym->name, (byte*)"etext") == 0) |
347 break; | 354 break; |
348 f = &func[nfunc++]; | 355 f = &func[nfunc++]; |
349 // find source file | 356 // find source file |
350 for(i = 0; i < nfile - 1; i++) { | 357 for(i = 0; i < nfile - 1; i++) { |
351 if (files[i+1].aline > f->ln0) | 358 if (files[i+1].aline > f->ln0) |
352 break; | 359 break; |
353 } | 360 } |
354 f->src = files[i].srcstring; | 361 f->src = files[i].srcstring; |
355 f->ln0 -= files[i].delta; | 362 f->ln0 -= files[i].delta; |
356 break; | 363 break; |
357 case 'z': | 364 case 'z': |
358 if(sym->value == 1) { | 365 if(sym->value == 1) { |
359 // entry for main source file for a new object. | 366 // entry for main source file for a new object. |
360 l = makepath(srcbuf, sizeof srcbuf, sym->name+1); | 367 l = makepath(srcbuf, sizeof srcbuf, sym->name+1); |
361 nhist = 0; | 368 nhist = 0; |
362 nfile = 0; | 369 nfile = 0; |
363 » » » if(nfile == nelem(files)) | 370 » » » if(nfile == maxfiles) |
364 return; | 371 return; |
365 files[nfile].srcstring = gostringn(srcbuf, l); | 372 files[nfile].srcstring = gostringn(srcbuf, l); |
366 files[nfile].aline = 0; | 373 files[nfile].aline = 0; |
367 files[nfile++].delta = 0; | 374 files[nfile++].delta = 0; |
368 } else { | 375 } else { |
369 // push or pop of included file. | 376 // push or pop of included file. |
370 l = makepath(srcbuf, sizeof srcbuf, sym->name+1); | 377 l = makepath(srcbuf, sizeof srcbuf, sym->name+1); |
371 if(srcbuf[0] != '\0') { | 378 if(srcbuf[0] != '\0') { |
372 if(nhist++ == 0) | 379 if(nhist++ == 0) |
373 incstart = sym->value; | 380 incstart = sym->value; |
374 » » » » if(nhist == 0 && nfile < nelem(files)) { | 381 » » » » if(nhist == 0 && nfile < maxfiles) { |
375 // new top-level file | 382 // new top-level file |
376 files[nfile].srcstring = gostringn(srcbu
f, l); | 383 files[nfile].srcstring = gostringn(srcbu
f, l); |
377 files[nfile].aline = sym->value; | 384 files[nfile].aline = sym->value; |
378 // this is "line 0" | 385 // this is "line 0" |
379 files[nfile++].delta = sym->value - 1; | 386 files[nfile++].delta = sym->value - 1; |
380 } | 387 } |
381 }else{ | 388 }else{ |
382 if(--nhist == 0) | 389 if(--nhist == 0) |
383 files[nfile-1].delta += sym->value - inc
start; | 390 files[nfile-1].delta += sym->value - inc
start; |
384 } | 391 } |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
540 | 547 |
541 void | 548 void |
542 runtime·funcline_go(Func *f, uintptr targetpc, String retfile, intgo retline) | 549 runtime·funcline_go(Func *f, uintptr targetpc, String retfile, intgo retline) |
543 { | 550 { |
544 retfile = f->src; | 551 retfile = f->src; |
545 retline = runtime·funcline(f, targetpc); | 552 retline = runtime·funcline(f, targetpc); |
546 FLUSH(&retfile); | 553 FLUSH(&retfile); |
547 FLUSH(&retline); | 554 FLUSH(&retline); |
548 } | 555 } |
549 | 556 |
550 static void | 557 void |
551 buildfuncs(void) | 558 runtime·symtabinit(void) |
552 { | 559 { |
553 extern byte etext[]; | 560 extern byte etext[]; |
554 | 561 |
555 if(func != nil) | 562 if(func != nil) |
556 return; | 563 return; |
557 | 564 |
558 // Memory profiling uses this code; | 565 // Memory profiling uses this code; |
559 // can deadlock if the profiler ends | 566 // can deadlock if the profiler ends |
560 // up back here. | 567 // up back here. |
561 m->nomemprof++; | 568 m->nomemprof++; |
(...skipping 11 matching lines...) Expand all Loading... |
573 func[nfunc].entry = (uint64)etext; | 580 func[nfunc].entry = (uint64)etext; |
574 fname = runtime·mallocgc(nfname*sizeof fname[0], FlagNoPointers, 0, 1); | 581 fname = runtime·mallocgc(nfname*sizeof fname[0], FlagNoPointers, 0, 1); |
575 nfunc = 0; | 582 nfunc = 0; |
576 lastvalue = 0; | 583 lastvalue = 0; |
577 walksymtab(dofunc); | 584 walksymtab(dofunc); |
578 | 585 |
579 // split pc/ln table by func | 586 // split pc/ln table by func |
580 splitpcln(); | 587 splitpcln(); |
581 | 588 |
582 // 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])); |
583 walksymtab(dosrcline); // pass 1: determine hugestring_len | 591 walksymtab(dosrcline); // pass 1: determine hugestring_len |
584 hugestring.str = runtime·mallocgc(hugestring_len, FlagNoPointers, 0, 0); | 592 hugestring.str = runtime·mallocgc(hugestring_len, FlagNoPointers, 0, 0); |
585 hugestring.len = 0; | 593 hugestring.len = 0; |
586 walksymtab(dosrcline); // pass 2: fill and use hugestring | 594 walksymtab(dosrcline); // pass 2: fill and use hugestring |
| 595 files = nil; |
587 | 596 |
588 if(hugestring.len != hugestring_len) | 597 if(hugestring.len != hugestring_len) |
589 runtime·throw("buildfunc: problem in initialization procedure"); | 598 runtime·throw("buildfunc: problem in initialization procedure"); |
590 | 599 |
591 m->nomemprof--; | 600 m->nomemprof--; |
592 } | 601 } |
593 | 602 |
594 Func* | 603 Func* |
595 runtime·findfunc(uintptr addr) | 604 runtime·findfunc(uintptr addr) |
596 { | 605 { |
597 Func *f; | 606 Func *f; |
598 int32 nf, n; | 607 int32 nf, n; |
599 | |
600 // Use atomic double-checked locking, | |
601 // because when called from pprof signal | |
602 // handler, findfunc must run without | |
603 // grabbing any locks. | |
604 // (Before enabling the signal handler, | |
605 // SetCPUProfileRate calls findfunc to trigger | |
606 // the initialization outside the handler.) | |
607 // Avoid deadlock on fault during malloc | |
608 // by not calling buildfuncs if we're already in malloc. | |
609 if(!m->mallocing && !m->gcing) { | |
610 if(runtime·atomicload(&funcinit) == 0) { | |
611 runtime·lock(&funclock); | |
612 if(funcinit == 0) { | |
613 buildfuncs(); | |
614 runtime·atomicstore(&funcinit, 1); | |
615 } | |
616 runtime·unlock(&funclock); | |
617 } | |
618 } | |
619 | 608 |
620 if(nfunc == 0) | 609 if(nfunc == 0) |
621 return nil; | 610 return nil; |
622 if(addr < func[0].entry || addr >= func[nfunc].entry) | 611 if(addr < func[0].entry || addr >= func[nfunc].entry) |
623 return nil; | 612 return nil; |
624 | 613 |
625 // binary search to find func with entry <= addr. | 614 // binary search to find func with entry <= addr. |
626 f = func; | 615 f = func; |
627 nf = nfunc; | 616 nf = nfunc; |
628 while(nf > 0) { | 617 while(nf > 0) { |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
679 runtime·showframe(Func *f, bool current) | 668 runtime·showframe(Func *f, bool current) |
680 { | 669 { |
681 static int32 traceback = -1; | 670 static int32 traceback = -1; |
682 | 671 |
683 if(current && m->throwing > 0) | 672 if(current && m->throwing > 0) |
684 return 1; | 673 return 1; |
685 if(traceback < 0) | 674 if(traceback < 0) |
686 traceback = runtime·gotraceback(nil); | 675 traceback = runtime·gotraceback(nil); |
687 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."); |
688 } | 677 } |
LEFT | RIGHT |