proc: allow use of quoted type names in type casts (#434)
If we are unable to correctly guess how a type is serialized in debug_info let the user specify it directly. Workaround for #455
This commit is contained in:
parent
7820921b7e
commit
a7a0cc75e1
@ -187,6 +187,16 @@ func main() {
|
|||||||
b2 := B{A: A{42}, a: A{47}}
|
b2 := B{A: A{42}, a: A{47}}
|
||||||
var sd D
|
var sd D
|
||||||
|
|
||||||
|
var mapanonstruct1 map[string]struct{}
|
||||||
|
var anonstruct1 struct{ val constant.Value }
|
||||||
|
var anonstruct2 struct{ i, j int }
|
||||||
|
var anoniface1 interface {
|
||||||
|
SomeFunction(struct{ val constant.Value })
|
||||||
|
OtherFunction(i, j int)
|
||||||
|
}
|
||||||
|
var anonfunc func(a struct{ i int }, b interface{}, c struct{ val constant.Value })
|
||||||
|
|
||||||
|
|
||||||
for i := range benchparr {
|
for i := range benchparr {
|
||||||
benchparr[i] = &benchstruct{}
|
benchparr[i] = &benchstruct{}
|
||||||
}
|
}
|
||||||
@ -197,5 +207,5 @@ func main() {
|
|||||||
fmt.Println(amb1)
|
fmt.Println(amb1)
|
||||||
}
|
}
|
||||||
runtime.Breakpoint()
|
runtime.Breakpoint()
|
||||||
fmt.Println(i1, i2, i3, p1, amb1, s1, s3, a1, p2, p3, s2, as1, str1, f1, fn1, fn2, nilslice, nilptr, ch1, chnil, m1, mnil, m2, m3, up1, i4, i5, i6, err1, err2, errnil, iface1, iface2, ifacenil, arr1, parr, cpx1, const1, iface3, iface4, recursive1, recursive1.x, iface5, iface2fn1, iface2fn2, bencharr, benchparr, mapinf, mainMenu, b, b2, sd)
|
fmt.Println(i1, i2, i3, p1, amb1, s1, s3, a1, p2, p3, s2, as1, str1, f1, fn1, fn2, nilslice, nilptr, ch1, chnil, m1, mnil, m2, m3, up1, i4, i5, i6, err1, err2, errnil, iface1, iface2, ifacenil, arr1, parr, cpx1, const1, iface3, iface4, recursive1, recursive1.x, iface5, iface2fn1, iface2fn2, bencharr, benchparr, mapinf, mainMenu, b, b2, sd, anonstruct1, anonstruct2, anoniface1, anonfunc, mapanonstruct1)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -104,7 +104,7 @@ func (reader *Reader) AddrForMember(member string, initialInstructions []byte) (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var TypeNotFoundErr = errors.New("no type entry found")
|
var TypeNotFoundErr = errors.New("no type entry found, use 'types' for a list of valid types")
|
||||||
|
|
||||||
// SeekToType moves the reader to the type specified by the entry,
|
// SeekToType moves the reader to the type specified by the entry,
|
||||||
// optionally resolving typedefs and pointer types. If the reader is set
|
// optionally resolving typedefs and pointer types. If the reader is set
|
||||||
|
|||||||
@ -41,7 +41,13 @@ func (scope *EvalScope) evalAST(t ast.Expr) (*Variable, error) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
if err != reader.TypeNotFoundErr {
|
_, isident := node.Fun.(*ast.Ident)
|
||||||
|
// we don't support function calls at the moment except for a few
|
||||||
|
// builtin functions so just return the type error here if the function
|
||||||
|
// isn't an identifier.
|
||||||
|
// More sophisticated logic will be required when function calls
|
||||||
|
// are implemented.
|
||||||
|
if err != reader.TypeNotFoundErr || !isident {
|
||||||
return v, err
|
return v, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,8 +3,10 @@ package proc
|
|||||||
import (
|
import (
|
||||||
"github.com/derekparker/delve/dwarf/reader"
|
"github.com/derekparker/delve/dwarf/reader"
|
||||||
"go/ast"
|
"go/ast"
|
||||||
|
"go/token"
|
||||||
"golang.org/x/debug/dwarf"
|
"golang.org/x/debug/dwarf"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
@ -24,13 +26,20 @@ func (dbp *Process) pointerTo(typ dwarf.Type) dwarf.Type {
|
|||||||
|
|
||||||
func (dbp *Process) findTypeExpr(expr ast.Expr) (dwarf.Type, error) {
|
func (dbp *Process) findTypeExpr(expr ast.Expr) (dwarf.Type, error) {
|
||||||
dbp.loadPackageMap()
|
dbp.loadPackageMap()
|
||||||
|
if lit, islit := expr.(*ast.BasicLit); islit && lit.Kind == token.STRING {
|
||||||
|
// Allow users to specify type names verbatim as quoted
|
||||||
|
// string. Useful as a catch-all workaround for cases where we don't
|
||||||
|
// parse/serialize types correctly or can not resolve package paths.
|
||||||
|
typn, _ := strconv.Unquote(lit.Value)
|
||||||
|
return dbp.findType(typn)
|
||||||
|
}
|
||||||
dbp.expandPackagesInType(expr)
|
dbp.expandPackagesInType(expr)
|
||||||
if snode, ok := expr.(*ast.StarExpr); ok {
|
if snode, ok := expr.(*ast.StarExpr); ok {
|
||||||
// Pointer types only appear in the dwarf informations when
|
// Pointer types only appear in the dwarf informations when
|
||||||
// a pointer to the type is used in the target program, here
|
// a pointer to the type is used in the target program, here
|
||||||
// we create a pointer type on the fly so that the user can
|
// we create a pointer type on the fly so that the user can
|
||||||
// specify a pointer to any variable used in the target program
|
// specify a pointer to any variable used in the target program
|
||||||
ptyp, err := dbp.findType(exprToString(snode.X))
|
ptyp, err := dbp.findTypeExpr(snode.X)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -598,7 +598,7 @@ func TestEvalExpression(t *testing.T) {
|
|||||||
{"i2 << i3", false, "", "", "int", fmt.Errorf("shift count type int, must be unsigned integer")},
|
{"i2 << i3", false, "", "", "int", fmt.Errorf("shift count type int, must be unsigned integer")},
|
||||||
{"*(i2 + i3)", false, "", "", "", fmt.Errorf("expression \"(i2 + i3)\" (int) can not be dereferenced")},
|
{"*(i2 + i3)", false, "", "", "", fmt.Errorf("expression \"(i2 + i3)\" (int) can not be dereferenced")},
|
||||||
{"i2.member", false, "", "", "", fmt.Errorf("i2 (type int) is not a struct")},
|
{"i2.member", false, "", "", "", fmt.Errorf("i2 (type int) is not a struct")},
|
||||||
{"fmt.Println(\"hello\")", false, "", "", "", fmt.Errorf("function calls are not supported")},
|
{"fmt.Println(\"hello\")", false, "", "", "", fmt.Errorf("no type entry found, use 'types' for a list of valid types")},
|
||||||
{"*nil", false, "", "", "", fmt.Errorf("nil can not be dereferenced")},
|
{"*nil", false, "", "", "", fmt.Errorf("nil can not be dereferenced")},
|
||||||
{"!nil", false, "", "", "", fmt.Errorf("operator ! can not be applied to \"nil\"")},
|
{"!nil", false, "", "", "", fmt.Errorf("operator ! can not be applied to \"nil\"")},
|
||||||
{"&nil", false, "", "", "", fmt.Errorf("can not take address of \"nil\"")},
|
{"&nil", false, "", "", "", fmt.Errorf("can not take address of \"nil\"")},
|
||||||
@ -718,3 +718,34 @@ func TestUnsafePointer(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type issue426TestCase struct {
|
||||||
|
name string
|
||||||
|
typ string
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIssue426(t *testing.T) {
|
||||||
|
// type casts using quoted type names
|
||||||
|
testcases := []issue426TestCase{
|
||||||
|
{"iface1", `interface {}`},
|
||||||
|
{"mapanonstruct1", `map[string]struct {}`},
|
||||||
|
{"anonstruct1", `struct { val go/constant.Value }`},
|
||||||
|
{"anonfunc", `func(struct { i int }, interface {}, struct { val go/constant.Value })`},
|
||||||
|
{"anonstruct2", `struct { i int; j int }`},
|
||||||
|
{"anoniface1", `interface { OtherFunction(int, int); SomeFunction(struct { val go/constant.Value }) }`},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serialization of type expressions (go/ast.Expr) containing anonymous structs or interfaces
|
||||||
|
// differs from the serialization used by the linker to produce DWARF type information
|
||||||
|
withTestProcess("testvariables2", t, func(p *proc.Process, fixture protest.Fixture) {
|
||||||
|
assertNoError(p.Continue(), t, "Continue() returned an error")
|
||||||
|
for _, testcase := range testcases {
|
||||||
|
v, err := evalVariable(p, testcase.name, pnormalLoadConfig)
|
||||||
|
assertNoError(err, t, fmt.Sprintf("EvalVariable(%s)", testcase.name))
|
||||||
|
t.Logf("%s → %s", testcase.name, v.RealType.String())
|
||||||
|
expr := fmt.Sprintf("(*%q)(%d)", testcase.typ, v.Addr)
|
||||||
|
_, err = evalVariable(p, expr, pnormalLoadConfig)
|
||||||
|
assertNoError(err, t, fmt.Sprintf("EvalVariable(%s)", expr))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user