You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

732 lines
16 KiB

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