pkg/proc: use DW_AT_decl_line to determine var visibility
Fixes #186, #83
This commit is contained in:
parent
b3246296d7
commit
85669434f6
15
_fixtures/decllinetest.go
Normal file
15
_fixtures/decllinetest.go
Normal file
@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
a := 0
|
||||
runtime.Breakpoint()
|
||||
a++
|
||||
b := 0
|
||||
runtime.Breakpoint()
|
||||
fmt.Println(a, b)
|
||||
}
|
@ -15,16 +15,17 @@ type VariableReader struct {
|
||||
depth int
|
||||
onlyVisible bool
|
||||
pc uint64
|
||||
line int
|
||||
err error
|
||||
}
|
||||
|
||||
// Variables returns a VariableReader for the function or lexical block at off.
|
||||
// If onlyVisible is true only variables visible at pc will be returned by
|
||||
// the VariableReader.
|
||||
func Variables(dwarf *dwarf.Data, off dwarf.Offset, pc uint64, onlyVisible bool) *VariableReader {
|
||||
func Variables(dwarf *dwarf.Data, off dwarf.Offset, pc uint64, line int, onlyVisible bool) *VariableReader {
|
||||
reader := dwarf.Reader()
|
||||
reader.Seek(off)
|
||||
return &VariableReader{dwarf: dwarf, reader: reader, entry: nil, depth: 0, onlyVisible: onlyVisible, pc: pc, err: nil}
|
||||
return &VariableReader{dwarf: dwarf, reader: reader, entry: nil, depth: 0, onlyVisible: onlyVisible, pc: pc, line: line, err: nil}
|
||||
}
|
||||
|
||||
// Next reads the next variable entry, returns false if there aren't any.
|
||||
@ -69,7 +70,9 @@ func (vrdr *VariableReader) Next() bool {
|
||||
vrdr.err = errors.New("offset was not lexical block or subprogram")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
if declLine, ok := vrdr.entry.Val(dwarf.AttrDeclLine).(int64); !ok || vrdr.line >= int(declLine) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1681,6 +1681,14 @@ func TestStepIntoFunction(t *testing.T) {
|
||||
|
||||
func TestIssue384(t *testing.T) {
|
||||
// Crash related to reading uninitialized memory, introduced by the memory prefetching optimization
|
||||
|
||||
ver, _ := goversion.Parse(runtime.Version())
|
||||
if ver.Major < 0 || ver.AfterOrEqual(goversion.GoVersion{1, 10, -1, 0, 0, ""}) {
|
||||
// go 1.10 emits DW_AT_decl_line and we won't be able to evaluate 'st'
|
||||
// which is declared after line 13.
|
||||
return
|
||||
}
|
||||
|
||||
protest.AllowRecording(t)
|
||||
withTestProcess("issue384", t, func(p proc.Process, fixture protest.Fixture) {
|
||||
start, _, err := p.BinInfo().LineToPC(fixture.Source, 13)
|
||||
@ -3374,3 +3382,31 @@ func TestIssue1008(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestDeclLine(t *testing.T) {
|
||||
ver, _ := goversion.Parse(runtime.Version())
|
||||
if ver.Major > 0 && !ver.AfterOrEqual(goversion.GoVersion{1, 10, -1, 0, 0, ""}) {
|
||||
t.Skip("go 1.9 and prior versions do not emit DW_AT_decl_line")
|
||||
}
|
||||
|
||||
withTestProcess("decllinetest", t, func(p proc.Process, fixture protest.Fixture) {
|
||||
assertNoError(proc.Continue(p), t, "Continue")
|
||||
scope, err := proc.GoroutineScope(p.CurrentThread())
|
||||
assertNoError(err, t, "GoroutineScope (1)")
|
||||
vars, err := scope.LocalVariables(normalLoadConfig)
|
||||
assertNoError(err, t, "LocalVariables (1)")
|
||||
if len(vars) != 1 {
|
||||
t.Fatalf("wrong number of variables %d", len(vars))
|
||||
}
|
||||
|
||||
assertNoError(proc.Continue(p), t, "Continue")
|
||||
scope, err = proc.GoroutineScope(p.CurrentThread())
|
||||
assertNoError(err, t, "GoroutineScope (2)")
|
||||
scope.LocalVariables(normalLoadConfig)
|
||||
vars, err = scope.LocalVariables(normalLoadConfig)
|
||||
assertNoError(err, t, "LocalVariables (2)")
|
||||
if len(vars) != 2 {
|
||||
t.Fatalf("wrong number of variables %d", len(vars))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -1745,9 +1745,11 @@ func (scope *EvalScope) variablesByTag(tag dwarf.Tag, cfg *LoadConfig) ([]*Varia
|
||||
return nil, errors.New("unable to find function context")
|
||||
}
|
||||
|
||||
_, line, _ := scope.BinInfo.PCToLine(scope.PC)
|
||||
|
||||
var vars []*Variable
|
||||
var depths []int
|
||||
varReader := reader.Variables(scope.BinInfo.dwarf, fn.offset, scope.PC, tag == dwarf.TagVariable)
|
||||
varReader := reader.Variables(scope.BinInfo.dwarf, fn.offset, scope.PC, line, tag == dwarf.TagVariable)
|
||||
hasScopes := false
|
||||
for varReader.Next() {
|
||||
entry := varReader.Entry()
|
||||
|
Loading…
Reference in New Issue
Block a user