github.com/zxy12/go_duplicate_112_new@v0.0.0-20200807091221-747231827200/src/debug/gosym/symtab.go (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 // Package gosym implements access to the Go symbol 6 // and line number tables embedded in Go binaries generated 7 // by the gc compilers. 8 package gosym 9 10 import ( 11 "bytes" 12 "encoding/binary" 13 "fmt" 14 "strconv" 15 "strings" 16 ) 17 18 /* 19 * Symbols 20 */ 21 22 // A Sym represents a single symbol table entry. 23 type Sym struct { 24 Value uint64 25 Type byte 26 Name string 27 GoType uint64 28 // If this symbol is a function symbol, the corresponding Func 29 Func *Func 30 } 31 32 // Static reports whether this symbol is static (not visible outside its file). 33 func (s *Sym) Static() bool { return s.Type >= 'a' } 34 35 // PackageName returns the package part of the symbol name, 36 // or the empty string if there is none. 37 func (s *Sym) PackageName() string { 38 pathend := strings.LastIndex(s.Name, "/") 39 if pathend < 0 { 40 pathend = 0 41 } 42 43 if i := strings.Index(s.Name[pathend:], "."); i != -1 { 44 return s.Name[:pathend+i] 45 } 46 return "" 47 } 48 49 // ReceiverName returns the receiver type name of this symbol, 50 // or the empty string if there is none. 51 func (s *Sym) ReceiverName() string { 52 pathend := strings.LastIndex(s.Name, "/") 53 if pathend < 0 { 54 pathend = 0 55 } 56 l := strings.Index(s.Name[pathend:], ".") 57 r := strings.LastIndex(s.Name[pathend:], ".") 58 if l == -1 || r == -1 || l == r { 59 return "" 60 } 61 return s.Name[pathend+l+1 : pathend+r] 62 } 63 64 // BaseName returns the symbol name without the package or receiver name. 65 func (s *Sym) BaseName() string { 66 if i := strings.LastIndex(s.Name, "."); i != -1 { 67 return s.Name[i+1:] 68 } 69 return s.Name 70 } 71 72 // A Func collects information about a single function. 73 type Func struct { 74 Entry uint64 75 *Sym 76 End uint64 77 Params []*Sym // nil for Go 1.3 and later binaries 78 Locals []*Sym // nil for Go 1.3 and later binaries 79 FrameSize int 80 LineTable *LineTable 81 Obj *Obj 82 } 83 84 // An Obj represents a collection of functions in a symbol table. 85 // 86 // The exact method of division of a binary into separate Objs is an internal detail 87 // of the symbol table format. 88 // 89 // In early versions of Go each source file became a different Obj. 90 // 91 // In Go 1 and Go 1.1, each package produced one Obj for all Go sources 92 // and one Obj per C source file. 93 // 94 // In Go 1.2, there is a single Obj for the entire program. 95 type Obj struct { 96 // Funcs is a list of functions in the Obj. 97 Funcs []Func 98 99 // In Go 1.1 and earlier, Paths is a list of symbols corresponding 100 // to the source file names that produced the Obj. 101 // In Go 1.2, Paths is nil. 102 // Use the keys of Table.Files to obtain a list of source files. 103 Paths []Sym // meta 104 } 105 106 /* 107 * Symbol tables 108 */ 109 110 // Table represents a Go symbol table. It stores all of the 111 // symbols decoded from the program and provides methods to translate 112 // between symbols, names, and addresses. 113 type Table struct { 114 Syms []Sym // nil for Go 1.3 and later binaries 115 Funcs []Func 116 Files map[string]*Obj // nil for Go 1.2 and later binaries 117 Objs []Obj // nil for Go 1.2 and later binaries 118 119 go12line *LineTable // Go 1.2 line number table 120 } 121 122 type sym struct { 123 value uint64 124 gotype uint64 125 typ byte 126 name []byte 127 } 128 129 var ( 130 littleEndianSymtab = []byte{0xFD, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00} 131 bigEndianSymtab = []byte{0xFF, 0xFF, 0xFF, 0xFD, 0x00, 0x00, 0x00} 132 oldLittleEndianSymtab = []byte{0xFE, 0xFF, 0xFF, 0xFF, 0x00, 0x00} 133 ) 134 135 func walksymtab(data []byte, fn func(sym) error) error { 136 if len(data) == 0 { // missing symtab is okay 137 return nil 138 } 139 var order binary.ByteOrder = binary.BigEndian 140 newTable := false 141 switch { 142 case bytes.HasPrefix(data, oldLittleEndianSymtab): 143 // Same as Go 1.0, but little endian. 144 // Format was used during interim development between Go 1.0 and Go 1.1. 145 // Should not be widespread, but easy to support. 146 data = data[6:] 147 order = binary.LittleEndian 148 case bytes.HasPrefix(data, bigEndianSymtab): 149 newTable = true 150 case bytes.HasPrefix(data, littleEndianSymtab): 151 newTable = true 152 order = binary.LittleEndian 153 } 154 var ptrsz int 155 if newTable { 156 if len(data) < 8 { 157 return &DecodingError{len(data), "unexpected EOF", nil} 158 } 159 ptrsz = int(data[7]) 160 if ptrsz != 4 && ptrsz != 8 { 161 return &DecodingError{7, "invalid pointer size", ptrsz} 162 } 163 data = data[8:] 164 } 165 var s sym 166 p := data 167 for len(p) >= 4 { 168 var typ byte 169 if newTable { 170 // Symbol type, value, Go type. 171 typ = p[0] & 0x3F 172 wideValue := p[0]&0x40 != 0 173 goType := p[0]&0x80 != 0 174 if typ < 26 { 175 typ += 'A' 176 } else { 177 typ += 'a' - 26 178 } 179 s.typ = typ 180 p = p[1:] 181 if wideValue { 182 if len(p) < ptrsz { 183 return &DecodingError{len(data), "unexpected EOF", nil} 184 } 185 // fixed-width value 186 if ptrsz == 8 { 187 s.value = order.Uint64(p[0:8]) 188 p = p[8:] 189 } else { 190 s.value = uint64(order.Uint32(p[0:4])) 191 p = p[4:] 192 } 193 } else { 194 // varint value 195 s.value = 0 196 shift := uint(0) 197 for len(p) > 0 && p[0]&0x80 != 0 { 198 s.value |= uint64(p[0]&0x7F) << shift 199 shift += 7 200 p = p[1:] 201 } 202 if len(p) == 0 { 203 return &DecodingError{len(data), "unexpected EOF", nil} 204 } 205 s.value |= uint64(p[0]) << shift 206 p = p[1:] 207 } 208 if goType { 209 if len(p) < ptrsz { 210 return &DecodingError{len(data), "unexpected EOF", nil} 211 } 212 // fixed-width go type 213 if ptrsz == 8 { 214 s.gotype = order.Uint64(p[0:8]) 215 p = p[8:] 216 } else { 217 s.gotype = uint64(order.Uint32(p[0:4])) 218 p = p[4:] 219 } 220 } 221 } else { 222 // Value, symbol type. 223 s.value = uint64(order.Uint32(p[0:4])) 224 if len(p) < 5 { 225 return &DecodingError{len(data), "unexpected EOF", nil} 226 } 227 typ = p[4] 228 if typ&0x80 == 0 { 229 return &DecodingError{len(data) - len(p) + 4, "bad symbol type", typ} 230 } 231 typ &^= 0x80 232 s.typ = typ 233 p = p[5:] 234 } 235 236 // Name. 237 var i int 238 var nnul int 239 for i = 0; i < len(p); i++ { 240 if p[i] == 0 { 241 nnul = 1 242 break 243 } 244 } 245 switch typ { 246 case 'z', 'Z': 247 p = p[i+nnul:] 248 for i = 0; i+2 <= len(p); i += 2 { 249 if p[i] == 0 && p[i+1] == 0 { 250 nnul = 2 251 break 252 } 253 } 254 } 255 if len(p) < i+nnul { 256 return &DecodingError{len(data), "unexpected EOF", nil} 257 } 258 s.name = p[0:i] 259 i += nnul 260 p = p[i:] 261 262 if !newTable { 263 if len(p) < 4 { 264 return &DecodingError{len(data), "unexpected EOF", nil} 265 } 266 // Go type. 267 s.gotype = uint64(order.Uint32(p[:4])) 268 p = p[4:] 269 } 270 fn(s) 271 } 272 return nil 273 } 274 275 // NewTable decodes the Go symbol table (the ".gosymtab" section in ELF), 276 // returning an in-memory representation. 277 // Starting with Go 1.3, the Go symbol table no longer includes symbol data. 278 func NewTable(symtab []byte, pcln *LineTable) (*Table, error) { 279 var n int 280 err := walksymtab(symtab, func(s sym) error { 281 n++ 282 return nil 283 }) 284 if err != nil { 285 return nil, err 286 } 287 288 var t Table 289 if pcln.isGo12() { 290 t.go12line = pcln 291 } 292 fname := make(map[uint16]string) 293 t.Syms = make([]Sym, 0, n) 294 nf := 0 295 nz := 0 296 lasttyp := uint8(0) 297 err = walksymtab(symtab, func(s sym) error { 298 n := len(t.Syms) 299 t.Syms = t.Syms[0 : n+1] 300 ts := &t.Syms[n] 301 ts.Type = s.typ 302 ts.Value = s.value 303 ts.GoType = s.gotype 304 switch s.typ { 305 default: 306 // rewrite name to use . instead of ยท (c2 b7) 307 w := 0 308 b := s.name 309 for i := 0; i < len(b); i++ { 310 if b[i] == 0xc2 && i+1 < len(b) && b[i+1] == 0xb7 { 311 i++ 312 b[i] = '.' 313 } 314 b[w] = b[i] 315 w++ 316 } 317 ts.Name = string(s.name[0:w]) 318 case 'z', 'Z': 319 if lasttyp != 'z' && lasttyp != 'Z' { 320 nz++ 321 } 322 for i := 0; i < len(s.name); i += 2 { 323 eltIdx := binary.BigEndian.Uint16(s.name[i : i+2]) 324 elt, ok := fname[eltIdx] 325 if !ok { 326 return &DecodingError{-1, "bad filename code", eltIdx} 327 } 328 if n := len(ts.Name); n > 0 && ts.Name[n-1] != '/' { 329 ts.Name += "/" 330 } 331 ts.Name += elt 332 } 333 } 334 switch s.typ { 335 case 'T', 't', 'L', 'l': 336 nf++ 337 case 'f': 338 fname[uint16(s.value)] = ts.Name 339 } 340 lasttyp = s.typ 341 return nil 342 }) 343 if err != nil { 344 return nil, err 345 } 346 347 t.Funcs = make([]Func, 0, nf) 348 t.Files = make(map[string]*Obj) 349 350 var obj *Obj 351 if t.go12line != nil { 352 // Put all functions into one Obj. 353 t.Objs = make([]Obj, 1) 354 obj = &t.Objs[0] 355 t.go12line.go12MapFiles(t.Files, obj) 356 } else { 357 t.Objs = make([]Obj, 0, nz) 358 } 359 360 // Count text symbols and attach frame sizes, parameters, and 361 // locals to them. Also, find object file boundaries. 362 lastf := 0 363 for i := 0; i < len(t.Syms); i++ { 364 sym := &t.Syms[i] 365 switch sym.Type { 366 case 'Z', 'z': // path symbol 367 if t.go12line != nil { 368 // Go 1.2 binaries have the file information elsewhere. Ignore. 369 break 370 } 371 // Finish the current object 372 if obj != nil { 373 obj.Funcs = t.Funcs[lastf:] 374 } 375 lastf = len(t.Funcs) 376 377 // Start new object 378 n := len(t.Objs) 379 t.Objs = t.Objs[0 : n+1] 380 obj = &t.Objs[n] 381 382 // Count & copy path symbols 383 var end int 384 for end = i + 1; end < len(t.Syms); end++ { 385 if c := t.Syms[end].Type; c != 'Z' && c != 'z' { 386 break 387 } 388 } 389 obj.Paths = t.Syms[i:end] 390 i = end - 1 // loop will i++ 391 392 // Record file names 393 depth := 0 394 for j := range obj.Paths { 395 s := &obj.Paths[j] 396 if s.Name == "" { 397 depth-- 398 } else { 399 if depth == 0 { 400 t.Files[s.Name] = obj 401 } 402 depth++ 403 } 404 } 405 406 case 'T', 't', 'L', 'l': // text symbol 407 if n := len(t.Funcs); n > 0 { 408 t.Funcs[n-1].End = sym.Value 409 } 410 if sym.Name == "runtime.etext" || sym.Name == "etext" { 411 continue 412 } 413 414 // Count parameter and local (auto) syms 415 var np, na int 416 var end int 417 countloop: 418 for end = i + 1; end < len(t.Syms); end++ { 419 switch t.Syms[end].Type { 420 case 'T', 't', 'L', 'l', 'Z', 'z': 421 break countloop 422 case 'p': 423 np++ 424 case 'a': 425 na++ 426 } 427 } 428 429 // Fill in the function symbol 430 n := len(t.Funcs) 431 t.Funcs = t.Funcs[0 : n+1] 432 fn := &t.Funcs[n] 433 sym.Func = fn 434 fn.Params = make([]*Sym, 0, np) 435 fn.Locals = make([]*Sym, 0, na) 436 fn.Sym = sym 437 fn.Entry = sym.Value 438 fn.Obj = obj 439 if t.go12line != nil { 440 // All functions share the same line table. 441 // It knows how to narrow down to a specific 442 // function quickly. 443 fn.LineTable = t.go12line 444 } else if pcln != nil { 445 fn.LineTable = pcln.slice(fn.Entry) 446 pcln = fn.LineTable 447 } 448 for j := i; j < end; j++ { 449 s := &t.Syms[j] 450 switch s.Type { 451 case 'm': 452 fn.FrameSize = int(s.Value) 453 case 'p': 454 n := len(fn.Params) 455 fn.Params = fn.Params[0 : n+1] 456 fn.Params[n] = s 457 case 'a': 458 n := len(fn.Locals) 459 fn.Locals = fn.Locals[0 : n+1] 460 fn.Locals[n] = s 461 } 462 } 463 i = end - 1 // loop will i++ 464 } 465 } 466 467 if t.go12line != nil && nf == 0 { 468 t.Funcs = t.go12line.go12Funcs() 469 } 470 if obj != nil { 471 obj.Funcs = t.Funcs[lastf:] 472 } 473 return &t, nil 474 } 475 476 // PCToFunc returns the function containing the program counter pc, 477 // or nil if there is no such function. 478 func (t *Table) PCToFunc(pc uint64) *Func { 479 funcs := t.Funcs 480 for len(funcs) > 0 { 481 m := len(funcs) / 2 482 fn := &funcs[m] 483 switch { 484 case pc < fn.Entry: 485 funcs = funcs[0:m] 486 case fn.Entry <= pc && pc < fn.End: 487 return fn 488 default: 489 funcs = funcs[m+1:] 490 } 491 } 492 return nil 493 } 494 495 // PCToLine looks up line number information for a program counter. 496 // If there is no information, it returns fn == nil. 497 func (t *Table) PCToLine(pc uint64) (file string, line int, fn *Func) { 498 if fn = t.PCToFunc(pc); fn == nil { 499 return 500 } 501 if t.go12line != nil { 502 file = t.go12line.go12PCToFile(pc) 503 line = t.go12line.go12PCToLine(pc) 504 } else { 505 file, line = fn.Obj.lineFromAline(fn.LineTable.PCToLine(pc)) 506 } 507 return 508 } 509 510 // LineToPC looks up the first program counter on the given line in 511 // the named file. It returns UnknownPathError or UnknownLineError if 512 // there is an error looking up this line. 513 func (t *Table) LineToPC(file string, line int) (pc uint64, fn *Func, err error) { 514 obj, ok := t.Files[file] 515 if !ok { 516 return 0, nil, UnknownFileError(file) 517 } 518 519 if t.go12line != nil { 520 pc := t.go12line.go12LineToPC(file, line) 521 if pc == 0 { 522 return 0, nil, &UnknownLineError{file, line} 523 } 524 return pc, t.PCToFunc(pc), nil 525 } 526 527 abs, err := obj.alineFromLine(file, line) 528 if err != nil { 529 return 530 } 531 for i := range obj.Funcs { 532 f := &obj.Funcs[i] 533 pc := f.LineTable.LineToPC(abs, f.End) 534 if pc != 0 { 535 return pc, f, nil 536 } 537 } 538 return 0, nil, &UnknownLineError{file, line} 539 } 540 541 // LookupSym returns the text, data, or bss symbol with the given name, 542 // or nil if no such symbol is found. 543 func (t *Table) LookupSym(name string) *Sym { 544 // TODO(austin) Maybe make a map 545 for i := range t.Syms { 546 s := &t.Syms[i] 547 switch s.Type { 548 case 'T', 't', 'L', 'l', 'D', 'd', 'B', 'b': 549 if s.Name == name { 550 return s 551 } 552 } 553 } 554 return nil 555 } 556 557 // LookupFunc returns the text, data, or bss symbol with the given name, 558 // or nil if no such symbol is found. 559 func (t *Table) LookupFunc(name string) *Func { 560 for i := range t.Funcs { 561 f := &t.Funcs[i] 562 if f.Sym.Name == name { 563 return f 564 } 565 } 566 return nil 567 } 568 569 // SymByAddr returns the text, data, or bss symbol starting at the given address. 570 func (t *Table) SymByAddr(addr uint64) *Sym { 571 for i := range t.Syms { 572 s := &t.Syms[i] 573 switch s.Type { 574 case 'T', 't', 'L', 'l', 'D', 'd', 'B', 'b': 575 if s.Value == addr { 576 return s 577 } 578 } 579 } 580 return nil 581 } 582 583 /* 584 * Object files 585 */ 586 587 // This is legacy code for Go 1.1 and earlier, which used the 588 // Plan 9 format for pc-line tables. This code was never quite 589 // correct. It's probably very close, and it's usually correct, but 590 // we never quite found all the corner cases. 591 // 592 // Go 1.2 and later use a simpler format, documented at golang.org/s/go12symtab. 593 594 func (o *Obj) lineFromAline(aline int) (string, int) { 595 type stackEnt struct { 596 path string 597 start int 598 offset int 599 prev *stackEnt 600 } 601 602 noPath := &stackEnt{"", 0, 0, nil} 603 tos := noPath 604 605 pathloop: 606 for _, s := range o.Paths { 607 val := int(s.Value) 608 switch { 609 case val > aline: 610 break pathloop 611 612 case val == 1: 613 // Start a new stack 614 tos = &stackEnt{s.Name, val, 0, noPath} 615 616 case s.Name == "": 617 // Pop 618 if tos == noPath { 619 return "<malformed symbol table>", 0 620 } 621 tos.prev.offset += val - tos.start 622 tos = tos.prev 623 624 default: 625 // Push 626 tos = &stackEnt{s.Name, val, 0, tos} 627 } 628 } 629 630 if tos == noPath { 631 return "", 0 632 } 633 return tos.path, aline - tos.start - tos.offset + 1 634 } 635 636 func (o *Obj) alineFromLine(path string, line int) (int, error) { 637 if line < 1 { 638 return 0, &UnknownLineError{path, line} 639 } 640 641 for i, s := range o.Paths { 642 // Find this path 643 if s.Name != path { 644 continue 645 } 646 647 // Find this line at this stack level 648 depth := 0 649 var incstart int 650 line += int(s.Value) 651 pathloop: 652 for _, s := range o.Paths[i:] { 653 val := int(s.Value) 654 switch { 655 case depth == 1 && val >= line: 656 return line - 1, nil 657 658 case s.Name == "": 659 depth-- 660 if depth == 0 { 661 break pathloop 662 } else if depth == 1 { 663 line += val - incstart 664 } 665 666 default: 667 if depth == 1 { 668 incstart = val 669 } 670 depth++ 671 } 672 } 673 return 0, &UnknownLineError{path, line} 674 } 675 return 0, UnknownFileError(path) 676 } 677 678 /* 679 * Errors 680 */ 681 682 // UnknownFileError represents a failure to find the specific file in 683 // the symbol table. 684 type UnknownFileError string 685 686 func (e UnknownFileError) Error() string { return "unknown file: " + string(e) } 687 688 // UnknownLineError represents a failure to map a line to a program 689 // counter, either because the line is beyond the bounds of the file 690 // or because there is no code on the given line. 691 type UnknownLineError struct { 692 File string 693 Line int 694 } 695 696 func (e *UnknownLineError) Error() string { 697 return "no code at " + e.File + ":" + strconv.Itoa(e.Line) 698 } 699 700 // DecodingError represents an error during the decoding of 701 // the symbol table. 702 type DecodingError struct { 703 off int 704 msg string 705 val interface{} 706 } 707 708 func (e *DecodingError) Error() string { 709 msg := e.msg 710 if e.val != nil { 711 msg += fmt.Sprintf(" '%v'", e.val) 712 } 713 msg += fmt.Sprintf(" at byte %#x", e.off) 714 return msg 715 }