mirror of
https://github.com/golang/go
synced 2024-11-17 03:04:44 -07:00
debug/gosym: refactor handling of funcdata
We do a bunch of manual offset calculations everywhere. Add a bit of type safety and some helpers. In addition to making the code clearer and providing a place to hang some documentation, it also makes upcoming changes easier. name old time/op new time/op delta 115/NewLineTable-8 79.9ns ± 1% 90.2ns ±23% ~ (p=0.234 n=9+10) 115/NewTable-8 72.0µs ± 1% 73.4µs ± 1% +1.96% (p=0.000 n=8+8) 115/LineToPC-8 53.3µs ± 1% 54.4µs ± 1% +2.02% (p=0.000 n=10+10) 115/PCToLine-8 249ns ± 0% 249ns ± 2% ~ (p=0.147 n=9+10) name old alloc/op new alloc/op delta 115/NewLineTable-8 384B ± 0% 384B ± 0% ~ (all equal) 115/NewTable-8 164kB ± 0% 164kB ± 0% ~ (p=0.610 n=10+10) 115/LineToPC-8 0.00B 0.00B ~ (all equal) 115/PCToLine-8 0.00B 0.00B ~ (all equal) name old allocs/op new allocs/op delta 115/NewLineTable-8 3.00 ± 0% 3.00 ± 0% ~ (all equal) 115/NewTable-8 1.04k ± 0% 1.04k ± 0% ~ (all equal) 115/LineToPC-8 0.00 0.00 ~ (all equal) 115/PCToLine-8 0.00 0.00 ~ (all equal) Change-Id: If357dce5ae4277e6ddc6d90ba6b5b83e470b9121 Reviewed-on: https://go-review.googlesource.com/c/go/+/352951 Trust: Josh Bleecher Snyder <josharian@gmail.com> Trust: Brad Fitzpatrick <bradfitz@golang.org> Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com> Reviewed-by: Cherry Mui <cherryyz@google.com> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Go Bot <gobot@golang.org>
This commit is contained in:
parent
40fa8c200c
commit
ed57d7bb15
@ -279,13 +279,13 @@ func (t *LineTable) go12Funcs() []Func {
|
||||
f := &funcs[i]
|
||||
f.Entry = t.uintptr(t.functab[2*i*int(t.ptrsize):])
|
||||
f.End = t.uintptr(t.functab[(2*i+2)*int(t.ptrsize):])
|
||||
info := t.funcdata[t.uintptr(t.functab[(2*i+1)*int(t.ptrsize):]):]
|
||||
info := t.funcData(uint32(i))
|
||||
f.LineTable = t
|
||||
f.FrameSize = int(t.binary.Uint32(info[t.ptrsize+2*4:]))
|
||||
f.FrameSize = int(info.deferreturn())
|
||||
f.Sym = &Sym{
|
||||
Value: f.Entry,
|
||||
Type: 'T',
|
||||
Name: t.funcName(t.binary.Uint32(info[t.ptrsize:])),
|
||||
Name: t.funcName(info.nameoff()),
|
||||
GoType: 0,
|
||||
Func: f,
|
||||
}
|
||||
@ -293,10 +293,10 @@ func (t *LineTable) go12Funcs() []Func {
|
||||
return funcs
|
||||
}
|
||||
|
||||
// findFunc returns the func corresponding to the given program counter.
|
||||
func (t *LineTable) findFunc(pc uint64) []byte {
|
||||
// findFunc returns the funcData corresponding to the given program counter.
|
||||
func (t *LineTable) findFunc(pc uint64) funcData {
|
||||
if pc < t.uintptr(t.functab) || pc >= t.uintptr(t.functab[len(t.functab)-int(t.ptrsize):]) {
|
||||
return nil
|
||||
return funcData{}
|
||||
}
|
||||
|
||||
// The function table is a list of 2*nfunctab+1 uintptrs,
|
||||
@ -307,7 +307,8 @@ func (t *LineTable) findFunc(pc uint64) []byte {
|
||||
m := nf / 2
|
||||
fm := f[2*t.ptrsize*m:]
|
||||
if t.uintptr(fm) <= pc && pc < t.uintptr(fm[2*t.ptrsize:]) {
|
||||
return t.funcdata[t.uintptr(fm[t.ptrsize:]):]
|
||||
data := t.funcdata[t.uintptr(fm[t.ptrsize:]):]
|
||||
return funcData{t: t, data: data}
|
||||
} else if pc < t.uintptr(fm) {
|
||||
nf = m
|
||||
} else {
|
||||
@ -315,7 +316,7 @@ func (t *LineTable) findFunc(pc uint64) []byte {
|
||||
nf -= m + 1
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return funcData{}
|
||||
}
|
||||
|
||||
// readvarint reads, removes, and returns a varint from *pp.
|
||||
@ -361,6 +362,47 @@ func (t *LineTable) string(off uint32) string {
|
||||
return t.stringFrom(t.funcdata, off)
|
||||
}
|
||||
|
||||
// funcData is memory corresponding to an _func struct.
|
||||
type funcData struct {
|
||||
t *LineTable // LineTable this data is a part of
|
||||
data []byte // raw memory for the function
|
||||
}
|
||||
|
||||
// funcData returns the ith funcData in t.functab.
|
||||
func (t *LineTable) funcData(i uint32) funcData {
|
||||
data := t.funcdata[t.uintptr(t.functab[2*t.ptrsize*i+t.ptrsize:]):]
|
||||
return funcData{t: t, data: data}
|
||||
}
|
||||
|
||||
// IsZero reports whether f is the zero value.
|
||||
func (f funcData) IsZero() bool {
|
||||
return f.t == nil && f.data == nil
|
||||
}
|
||||
|
||||
// entryPC returns the func's entry PC.
|
||||
func (f funcData) entryPC() uint64 {
|
||||
return f.t.uintptr(f.data)
|
||||
}
|
||||
|
||||
func (f funcData) nameoff() uint32 { return f.field(1) }
|
||||
func (f funcData) deferreturn() uint32 { return f.field(3) }
|
||||
func (f funcData) pcfile() uint32 { return f.field(5) }
|
||||
func (f funcData) pcln() uint32 { return f.field(6) }
|
||||
func (f funcData) cuOffset() uint32 { return f.field(8) }
|
||||
|
||||
// field returns the nth field of the _func struct.
|
||||
// It panics if n == 0 or n > 9; for n == 0, call f.entryPC.
|
||||
// Most callers should use a named field accessor (just above).
|
||||
func (f funcData) field(n uint32) uint32 {
|
||||
if n == 0 || n > 9 {
|
||||
panic("bad funcdata field")
|
||||
}
|
||||
sz0 := f.t.ptrsize
|
||||
off := sz0 + (n-1)*4 // subsequent fields are 4 bytes each
|
||||
data := f.data[off:]
|
||||
return f.t.binary.Uint32(data)
|
||||
}
|
||||
|
||||
// step advances to the next pc, value pair in the encoded table.
|
||||
func (t *LineTable) step(p *[]byte, pc *uint64, val *int32, first bool) bool {
|
||||
uvdelta := t.readvarint(p)
|
||||
@ -451,11 +493,11 @@ func (t *LineTable) go12PCToLine(pc uint64) (line int) {
|
||||
}()
|
||||
|
||||
f := t.findFunc(pc)
|
||||
if f == nil {
|
||||
if f.IsZero() {
|
||||
return -1
|
||||
}
|
||||
entry := t.uintptr(f)
|
||||
linetab := t.binary.Uint32(f[t.ptrsize+5*4:])
|
||||
entry := f.entryPC()
|
||||
linetab := f.pcln()
|
||||
return int(t.pcvalue(linetab, entry, pc))
|
||||
}
|
||||
|
||||
@ -468,11 +510,11 @@ func (t *LineTable) go12PCToFile(pc uint64) (file string) {
|
||||
}()
|
||||
|
||||
f := t.findFunc(pc)
|
||||
if f == nil {
|
||||
if f.IsZero() {
|
||||
return ""
|
||||
}
|
||||
entry := t.uintptr(f)
|
||||
filetab := t.binary.Uint32(f[t.ptrsize+4*4:])
|
||||
entry := f.entryPC()
|
||||
filetab := f.pcfile()
|
||||
fno := t.pcvalue(filetab, entry, pc)
|
||||
if t.version == ver12 {
|
||||
if fno <= 0 {
|
||||
@ -484,7 +526,7 @@ func (t *LineTable) go12PCToFile(pc uint64) (file string) {
|
||||
if fno < 0 { // 0 is valid for ≥ 1.16
|
||||
return ""
|
||||
}
|
||||
cuoff := t.binary.Uint32(f[t.ptrsize+7*4:])
|
||||
cuoff := f.cuOffset()
|
||||
if fnoff := t.binary.Uint32(t.cutab[(cuoff+uint32(fno))*4:]); fnoff != ^uint32(0) {
|
||||
return t.stringFrom(t.filetab, fnoff)
|
||||
}
|
||||
@ -510,13 +552,12 @@ func (t *LineTable) go12LineToPC(file string, line int) (pc uint64) {
|
||||
// mapping file number to a list of functions with code from that file.
|
||||
var cutab []byte
|
||||
for i := uint32(0); i < t.nfunctab; i++ {
|
||||
f := t.funcdata[t.uintptr(t.functab[2*t.ptrsize*i+t.ptrsize:]):]
|
||||
entry := t.uintptr(f)
|
||||
filetab := t.binary.Uint32(f[t.ptrsize+4*4:])
|
||||
linetab := t.binary.Uint32(f[t.ptrsize+5*4:])
|
||||
f := t.funcData(i)
|
||||
entry := f.entryPC()
|
||||
filetab := f.pcfile()
|
||||
linetab := f.pcln()
|
||||
if t.version == ver116 {
|
||||
cuoff := t.binary.Uint32(f[t.ptrsize+7*4:]) * 4
|
||||
cutab = t.cutab[cuoff:]
|
||||
cutab = t.cutab[f.cuOffset()*4:]
|
||||
}
|
||||
pc := t.findFileLine(entry, filetab, linetab, int32(filenum), int32(line), cutab)
|
||||
if pc != 0 {
|
||||
|
Loading…
Reference in New Issue
Block a user