aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJosh Bleecher Snyder <josharian@gmail.com>2021-09-23 13:11:04 -0700
committerJosh Bleecher Snyder <josharian@gmail.com>2021-09-29 22:11:50 +0000
commited57d7bb15992bf7ffbbe643401b03f0a418663c (patch)
treeaa7bd9dd8eb85add0b6430a314ad5155b0fd4c1d /src
parent40fa8c200cc18a361843a526f3e0116e5dfd006f (diff)
downloadgo-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.go83
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 {