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}}
|
||||
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 {
|
||||
benchparr[i] = &benchstruct{}
|
||||
}
|
||||
@ -197,5 +207,5 @@ func main() {
|
||||
fmt.Println(amb1)
|
||||
}
|
||||
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,
|
||||
// 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 {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,8 +3,10 @@ package proc
|
||||
import (
|
||||
"github.com/derekparker/delve/dwarf/reader"
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"golang.org/x/debug/dwarf"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
@ -24,13 +26,20 @@ func (dbp *Process) pointerTo(typ dwarf.Type) dwarf.Type {
|
||||
|
||||
func (dbp *Process) findTypeExpr(expr ast.Expr) (dwarf.Type, error) {
|
||||
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)
|
||||
if snode, ok := expr.(*ast.StarExpr); ok {
|
||||
// Pointer types only appear in the dwarf informations when
|
||||
// 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
|
||||
// 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 {
|
||||
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, "", "", "", fmt.Errorf("expression \"(i2 + i3)\" (int) can not be dereferenced")},
|
||||
{"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("operator ! can not be applied to \"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