parent
21be59469a
commit
7fd47749ef
21
_fixtures/issue951.go
Normal file
21
_fixtures/issue951.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
shadow(42)
|
||||||
|
}
|
||||||
|
|
||||||
|
func shadow(i int) {
|
||||||
|
for i := 0; i < 5; i++ {
|
||||||
|
for i := 20; i < 25; i++ {
|
||||||
|
runtime.Breakpoint()
|
||||||
|
fmt.Println("another shadow", i)
|
||||||
|
}
|
||||||
|
fmt.Println("shadow", i)
|
||||||
|
}
|
||||||
|
fmt.Println("arg", i)
|
||||||
|
}
|
@ -2,7 +2,6 @@ package proc
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"debug/dwarf"
|
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -564,7 +563,7 @@ func (scope *EvalScope) evalIdent(node *ast.Ident) (*Variable, error) {
|
|||||||
return nilVariable, nil
|
return nilVariable, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
vars, err := scope.variablesByTag(dwarf.TagVariable, nil)
|
vars, err := scope.Locals()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -573,15 +572,6 @@ func (scope *EvalScope) evalIdent(node *ast.Ident) (*Variable, error) {
|
|||||||
return vars[i], nil
|
return vars[i], nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
args, err := scope.variablesByTag(dwarf.TagFormalParameter, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
for i := range args {
|
|
||||||
if args[i].Name == node.Name {
|
|
||||||
return args[i], nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if it's not a local variable then it could be a package variable w/o explicit package name
|
// if it's not a local variable then it could be a package variable w/o explicit package name
|
||||||
if scope.Fn != nil {
|
if scope.Fn != nil {
|
||||||
|
@ -524,7 +524,7 @@ func FrameToScope(bi *BinaryInfo, thread MemoryReadWriter, g *G, frames ...Stack
|
|||||||
|
|
||||||
// Creates a cacheMem that will preload the entire stack frame the first
|
// Creates a cacheMem that will preload the entire stack frame the first
|
||||||
// time any local variable is read.
|
// time any local variable is read.
|
||||||
// Remember that the stack grows from downward in memory.
|
// Remember that the stack grows downward in memory.
|
||||||
minaddr := frames[0].Regs.SP()
|
minaddr := frames[0].Regs.SP()
|
||||||
var maxaddr uint64
|
var maxaddr uint64
|
||||||
if len(frames) > 1 && frames[0].SystemStack == frames[1].SystemStack {
|
if len(frames) > 1 && frames[0].SystemStack == frames[1].SystemStack {
|
||||||
|
@ -3665,3 +3665,35 @@ func TestInlineStepOut(t *testing.T) {
|
|||||||
{contStepout, 18},
|
{contStepout, 18},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIssue951(t *testing.T) {
|
||||||
|
if ver, _ := goversion.Parse(runtime.Version()); ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{1, 9, -1, 0, 0, ""}) {
|
||||||
|
t.Skip("scopes not implemented in <=go1.8")
|
||||||
|
}
|
||||||
|
|
||||||
|
withTestProcess("issue951", t, func(p proc.Process, fixture protest.Fixture) {
|
||||||
|
assertNoError(proc.Continue(p), t, "Continue()")
|
||||||
|
scope, err := proc.GoroutineScope(p.CurrentThread())
|
||||||
|
assertNoError(err, t, "GoroutineScope")
|
||||||
|
args, err := scope.FunctionArguments(normalLoadConfig)
|
||||||
|
assertNoError(err, t, "FunctionArguments")
|
||||||
|
t.Logf("%#v", args[0])
|
||||||
|
if args[0].Flags&proc.VariableShadowed == 0 {
|
||||||
|
t.Error("argument is not shadowed")
|
||||||
|
}
|
||||||
|
vars, err := scope.LocalVariables(normalLoadConfig)
|
||||||
|
assertNoError(err, t, "LocalVariables")
|
||||||
|
shadowed, notShadowed := 0, 0
|
||||||
|
for i := range vars {
|
||||||
|
t.Logf("var %d: %#v\n", i, vars[i])
|
||||||
|
if vars[i].Flags&proc.VariableShadowed != 0 {
|
||||||
|
shadowed++
|
||||||
|
} else {
|
||||||
|
notShadowed++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if shadowed != 1 || notShadowed != 1 {
|
||||||
|
t.Errorf("Wrong number of shadowed/non-shadowed local variables: %d %d", shadowed, notShadowed)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -58,6 +58,10 @@ const (
|
|||||||
VariableShadowed
|
VariableShadowed
|
||||||
// VariableConstant means this variable is a constant value
|
// VariableConstant means this variable is a constant value
|
||||||
VariableConstant
|
VariableConstant
|
||||||
|
// VariableArgument means this variable is a function argument
|
||||||
|
VariableArgument
|
||||||
|
// VariableReturnArgument means this variable is a function return value
|
||||||
|
VariableReturnArgument
|
||||||
)
|
)
|
||||||
|
|
||||||
// Variable represents a variable. It contains the address, name,
|
// Variable represents a variable. It contains the address, name,
|
||||||
@ -616,12 +620,38 @@ func (scope *EvalScope) SetVariable(name, value string) error {
|
|||||||
|
|
||||||
// LocalVariables returns all local variables from the current function scope.
|
// LocalVariables returns all local variables from the current function scope.
|
||||||
func (scope *EvalScope) LocalVariables(cfg LoadConfig) ([]*Variable, error) {
|
func (scope *EvalScope) LocalVariables(cfg LoadConfig) ([]*Variable, error) {
|
||||||
return scope.variablesByTag(dwarf.TagVariable, &cfg)
|
vars, err := scope.Locals()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
vars = filterVariables(vars, func(v *Variable) bool {
|
||||||
|
return (v.Flags & (VariableArgument | VariableReturnArgument)) == 0
|
||||||
|
})
|
||||||
|
loadValues(vars, cfg)
|
||||||
|
return vars, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// FunctionArguments returns the name, value, and type of all current function arguments.
|
// FunctionArguments returns the name, value, and type of all current function arguments.
|
||||||
func (scope *EvalScope) FunctionArguments(cfg LoadConfig) ([]*Variable, error) {
|
func (scope *EvalScope) FunctionArguments(cfg LoadConfig) ([]*Variable, error) {
|
||||||
return scope.variablesByTag(dwarf.TagFormalParameter, &cfg)
|
vars, err := scope.Locals()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
vars = filterVariables(vars, func(v *Variable) bool {
|
||||||
|
return (v.Flags & (VariableArgument | VariableReturnArgument)) != 0
|
||||||
|
})
|
||||||
|
loadValues(vars, cfg)
|
||||||
|
return vars, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func filterVariables(vars []*Variable, pred func(v *Variable) bool) []*Variable {
|
||||||
|
r := make([]*Variable, 0, len(vars))
|
||||||
|
for i := range vars {
|
||||||
|
if pred(vars[i]) {
|
||||||
|
r = append(r, vars[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
// PackageVariables returns the name, value, and type of all package variables in the application.
|
// PackageVariables returns the name, value, and type of all package variables in the application.
|
||||||
@ -825,6 +855,12 @@ func (v *Variable) maybeDereference() *Variable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func loadValues(vars []*Variable, cfg LoadConfig) {
|
||||||
|
for i := range vars {
|
||||||
|
vars[i].loadValueInternal(0, cfg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Extracts the value of the variable at the given address.
|
// Extracts the value of the variable at the given address.
|
||||||
func (v *Variable) loadValue(cfg LoadConfig) {
|
func (v *Variable) loadValue(cfg LoadConfig) {
|
||||||
v.loadValueInternal(0, cfg)
|
v.loadValueInternal(0, cfg)
|
||||||
@ -1876,20 +1912,17 @@ func (v *variablesByDepth) Swap(i int, j int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fetches all variables of a specific type in the current function scope
|
// Fetches all variables of a specific type in the current function scope
|
||||||
func (scope *EvalScope) variablesByTag(tag dwarf.Tag, cfg *LoadConfig) ([]*Variable, error) {
|
func (scope *EvalScope) Locals() ([]*Variable, error) {
|
||||||
if scope.Fn == nil {
|
if scope.Fn == nil {
|
||||||
return nil, errors.New("unable to find function context")
|
return nil, errors.New("unable to find function context")
|
||||||
}
|
}
|
||||||
|
|
||||||
var vars []*Variable
|
var vars []*Variable
|
||||||
var depths []int
|
var depths []int
|
||||||
varReader := reader.Variables(scope.BinInfo.dwarf, scope.Fn.offset, scope.PC, scope.Line, tag == dwarf.TagVariable)
|
varReader := reader.Variables(scope.BinInfo.dwarf, scope.Fn.offset, scope.PC, scope.Line, true)
|
||||||
hasScopes := false
|
hasScopes := false
|
||||||
for varReader.Next() {
|
for varReader.Next() {
|
||||||
entry := varReader.Entry()
|
entry := varReader.Entry()
|
||||||
if entry.Tag != tag {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
val, err := scope.extractVarInfoFromEntry(entry)
|
val, err := scope.extractVarInfoFromEntry(entry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// skip variables that we can't parse yet
|
// skip variables that we can't parse yet
|
||||||
@ -1897,6 +1930,17 @@ func (scope *EvalScope) variablesByTag(tag dwarf.Tag, cfg *LoadConfig) ([]*Varia
|
|||||||
}
|
}
|
||||||
vars = append(vars, val)
|
vars = append(vars, val)
|
||||||
depth := varReader.Depth()
|
depth := varReader.Depth()
|
||||||
|
if entry.Tag == dwarf.TagFormalParameter {
|
||||||
|
if depth <= 1 {
|
||||||
|
depth = 0
|
||||||
|
}
|
||||||
|
isret, _ := entry.Val(dwarf.AttrVarParam).(bool)
|
||||||
|
if isret {
|
||||||
|
val.Flags |= VariableReturnArgument
|
||||||
|
} else {
|
||||||
|
val.Flags |= VariableArgument
|
||||||
|
}
|
||||||
|
}
|
||||||
depths = append(depths, depth)
|
depths = append(depths, depth)
|
||||||
if depth > 1 {
|
if depth > 1 {
|
||||||
hasScopes = true
|
hasScopes = true
|
||||||
@ -1933,9 +1977,6 @@ func (scope *EvalScope) variablesByTag(tag dwarf.Tag, cfg *LoadConfig) ([]*Varia
|
|||||||
}
|
}
|
||||||
lvn[v.Name] = v
|
lvn[v.Name] = v
|
||||||
}
|
}
|
||||||
if cfg != nil {
|
|
||||||
v.loadValue(*cfg)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return vars, nil
|
return vars, nil
|
||||||
|
@ -170,6 +170,12 @@ const (
|
|||||||
|
|
||||||
// VariableConstant means this variable is a constant value
|
// VariableConstant means this variable is a constant value
|
||||||
VariableConstant
|
VariableConstant
|
||||||
|
|
||||||
|
// VariableArgument means this variable is a function argument
|
||||||
|
VariableArgument
|
||||||
|
|
||||||
|
// VariableReturnArgument means this variable is a function return value
|
||||||
|
VariableReturnArgument
|
||||||
)
|
)
|
||||||
|
|
||||||
// Variable describes a variable.
|
// Variable describes a variable.
|
||||||
|
Loading…
Reference in New Issue
Block a user