diff --git a/_fixtures/testvariables.go b/_fixtures/testvariables.go index c9d741ef..1946f210 100644 --- a/_fixtures/testvariables.go +++ b/_fixtures/testvariables.go @@ -7,6 +7,11 @@ type FooBar struct { Bur string } +func barfoo() { + a1 := "bur" + fmt.Println(a1) +} + func foobar(baz string) { var ( a1 = "foo" @@ -21,6 +26,7 @@ func foobar(baz string) { f32 = float32(1.2) ) + barfoo() fmt.Println(a1, a2, a3, a4, a5, a6, a7, baz, neg, i8, f32) } diff --git a/proctl/variables_linux_amd64.go b/proctl/variables_linux_amd64.go index 11ff598b..ef187875 100644 --- a/proctl/variables_linux_amd64.go +++ b/proctl/variables_linux_amd64.go @@ -24,20 +24,21 @@ func (dbp *DebuggedProcess) PrintGoroutinesInfo() error { if err != nil { return err } + reader := data.Reader() - allglen, err := allglenval(dbp, data) + allglen, err := allglenval(dbp, reader) if err != nil { return err } - goidoffset, err := parsegoidoffset(dbp, data) + goidoffset, err := parsegoidoffset(dbp, reader) if err != nil { return err } - schedoffset, err := parseschedoffset(dbp, data) + schedoffset, err := parseschedoffset(dbp, reader) if err != nil { return err } - allgentryaddr, err := allgentryptr(dbp, data) + allgentryaddr, err := allgentryptr(dbp, reader) if err != nil { return err } @@ -76,8 +77,8 @@ func printGoroutineInfo(dbp *DebuggedProcess, addr uint64, goidoffset, schedoffs return nil } -func allglenval(dbp *DebuggedProcess, data *dwarf.Data) (uint64, error) { - entry, err := findDwarfEntry("runtime.allglen", data) +func allglenval(dbp *DebuggedProcess, reader *dwarf.Reader) (uint64, error) { + entry, err := findDwarfEntry("runtime.allglen", reader) if err != nil { return 0, err } @@ -97,8 +98,8 @@ func allglenval(dbp *DebuggedProcess, data *dwarf.Data) (uint64, error) { return binary.LittleEndian.Uint64(val), nil } -func allgentryptr(dbp *DebuggedProcess, data *dwarf.Data) (uint64, error) { - entry, err := findDwarfEntry("runtime.allg", data) +func allgentryptr(dbp *DebuggedProcess, reader *dwarf.Reader) (uint64, error) { + entry, err := findDwarfEntry("runtime.allg", reader) if err != nil { return 0, err } @@ -115,8 +116,8 @@ func allgentryptr(dbp *DebuggedProcess, data *dwarf.Data) (uint64, error) { return uint64(addr), nil } -func parsegoidoffset(dbp *DebuggedProcess, data *dwarf.Data) (uint64, error) { - entry, err := findDwarfEntry("goid", data) +func parsegoidoffset(dbp *DebuggedProcess, reader *dwarf.Reader) (uint64, error) { + entry, err := findDwarfEntry("goid", reader) if err != nil { return 0, err } @@ -132,8 +133,8 @@ func parsegoidoffset(dbp *DebuggedProcess, data *dwarf.Data) (uint64, error) { return uint64(offset), nil } -func parseschedoffset(dbp *DebuggedProcess, data *dwarf.Data) (uint64, error) { - entry, err := findDwarfEntry("sched", data) +func parseschedoffset(dbp *DebuggedProcess, reader *dwarf.Reader) (uint64, error) { + entry, err := findDwarfEntry("sched", reader) if err != nil { return 0, err } @@ -156,7 +157,18 @@ func (thread *ThreadContext) EvalSymbol(name string) (*Variable, error) { return nil, err } - entry, err := findDwarfEntry(name, data) + pc, err := thread.CurrentPC() + if err != nil { + return nil, err + } + fn := thread.Process.GoSymTable.PCToFunc(pc) + if fn == nil { + return nil, fmt.Errorf("could not func function scope") + } + reader := data.Reader() + err = findFunction(fn.Name, reader) + + entry, err := findDwarfEntry(name, reader) if err != nil { return nil, err } @@ -184,9 +196,34 @@ func (thread *ThreadContext) EvalSymbol(name string) (*Variable, error) { return &Variable{Name: name, Type: t.String(), Value: val}, nil } -func findDwarfEntry(name string, data *dwarf.Data) (*dwarf.Entry, error) { - reader := data.Reader() +// findFunction is basically used to seek the dwarf.Reader to +// the function entry that represents our current scope. From there +// we can find the first child entry that matches the var name and +// use it to determine the value of the variable. +func findFunction(name string, reader *dwarf.Reader) error { + for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() { + if err != nil { + return err + } + if entry.Tag != dwarf.TagSubprogram { + continue + } + + n, ok := entry.Val(dwarf.AttrName).(string) + if !ok { + continue + } + + if n == name { + break + } + } + + return nil +} + +func findDwarfEntry(name string, reader *dwarf.Reader) (*dwarf.Entry, error) { for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() { if err != nil { return nil, err diff --git a/proctl/variables_test.go b/proctl/variables_test.go index 226912f4..e3e28fd3 100644 --- a/proctl/variables_test.go +++ b/proctl/variables_test.go @@ -24,7 +24,7 @@ func TestVariableEvaluation(t *testing.T) { {"a1", "foo", "struct string"}, {"a2", "6", "int"}, {"a3", "7.23", "float64"}, - {"a4", "[2]int [1 2]", "[97]int"}, + {"a4", "[2]int [1 2]", "[65]int"}, {"a5", "len: 5 cap: 5 [1 2 3 4 5]", "struct []int"}, {"a6", "main.FooBar {Baz: 8, Bur: word}", "main.FooBar"}, {"a7", "*main.FooBar {Baz: 5, Bur: strum}", "*main.FooBar"}, @@ -35,7 +35,7 @@ func TestVariableEvaluation(t *testing.T) { } helper.WithTestProcess(executablePath, t, func(p *proctl.DebuggedProcess) { - pc, _, _ := p.GoSymTable.LineToPC(fp, 24) + pc, _, _ := p.GoSymTable.LineToPC(fp, 29) _, err := p.Break(uintptr(pc)) assertNoError(err, t, "Break() returned an error")