diff options
| author | Josh Bleecher Snyder <josharian@gmail.com> | 2021-09-23 13:11:04 -0700 |
|---|---|---|
| committer | Josh Bleecher Snyder <josharian@gmail.com> | 2021-09-29 22:11:50 +0000 |
| commit | ed57d7bb15992bf7ffbbe643401b03f0a418663c (patch) | |
| tree | aa7bd9dd8eb85add0b6430a314ad5155b0fd4c1d /src | |
| parent | 40fa8c200cc18a361843a526f3e0116e5dfd006f (diff) | |
| download | go-ed57d7bb15992bf7ffbbe643401b03f0a418663c.tar.xz | |
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>
Diffstat (limited to 'src')
| -rw-r--r-- | src/debug/gosym/pclntab.go | 83 |
1 files changed, 62 insertions, 21 deletions
diff --git a/src/debug/gosym/pclntab.go b/src/debug/gosym/pclntab.go index 5d18410a78..bf97976b3c 100644 --- a/src/debug/gosym/pclntab.go +++ b/src/debug/gosym/pclntab.go @@ -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 { |
