提交 48e13a90 编写于 作者: A aarzilli 提交者: Derek Parker

proc/variables: Support for interface types

上级 2deb7fba
......@@ -26,6 +26,14 @@ func afunc(x int) int {
type functype func(int) int
func (a *astruct) Error() string {
return "not an error"
}
func (b *bstruct) Error() string {
return "not an error"
}
func main() {
i1 := 1
i2 := 2
......@@ -96,11 +104,16 @@ func main() {
i4 := 800
i5 := -3
i6 := -500
var err1 error = c1.sa[0]
var err2 error = c1.pb
var errnil error = nil
var iface1 interface{} = c1.sa[0]
var ifacenil interface{} = nil
var amb1 = 1
runtime.Breakpoint()
for amb1 := 0; amb1 < 10; amb1++ {
fmt.Println(amb1)
}
fmt.Println(i1, i2, i3, p1, amb1, s1, a1, p2, p3, s2, as1, str1, f1, fn1, fn2, nilslice, nilptr, ch1, chnil, m1, mnil, m2, m3, up1, i4, i5, i6)
fmt.Println(i1, i2, i3, p1, amb1, s1, 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, ifacenil)
}
......@@ -55,6 +55,9 @@ func (scope *EvalScope) evalAST(t ast.Expr) (*Variable, error) {
// if it's not a package variable then it must be a struct member access
return scope.evalStructSelector(node)
case *ast.TypeAssertExpr: // <expression>.(<type>)
return scope.evalTypeAssert(node)
case *ast.IndexExpr:
return scope.evalIndex(node)
......@@ -166,26 +169,11 @@ func (scope *EvalScope) evalTypeCast(node *ast.CallExpr) (*Variable, error) {
fnnode = p.X
}
var styp, typ dwarf.Type
if snode, ok := fnnode.(*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 := scope.findType(exprToString(snode.X))
if err != nil {
return nil, err
}
typ = &dwarf.PtrType{dwarf.CommonType{int64(scope.Thread.dbp.arch.PtrSize()), exprToString(fnnode)}, ptyp}
styp = typ
} else {
styp, err = scope.findType(exprToString(fnnode))
if err != nil {
return nil, err
}
typ = resolveTypedef(styp)
styp, err := scope.Thread.dbp.findTypeExpr(fnnode)
if err != nil {
return nil, err
}
typ := resolveTypedef(styp)
converr := fmt.Errorf("can not convert \"%s\" to %s", exprToString(node.Args[0]), typ.String())
......@@ -312,6 +300,35 @@ func (scope *EvalScope) evalStructSelector(node *ast.SelectorExpr) (*Variable, e
return xv.structMember(node.Sel.Name)
}
// Evaluates expressions <subexpr>.(<type>)
func (scope *EvalScope) evalTypeAssert(node *ast.TypeAssertExpr) (*Variable, error) {
xv, err := scope.evalAST(node.X)
if err != nil {
return nil, err
}
if xv.Kind != reflect.Interface {
return nil, fmt.Errorf("expression \"%s\" not an interface", exprToString(node.X))
}
xv.loadInterface(0, false)
if xv.Unreadable != nil {
return nil, xv.Unreadable
}
if xv.Children[0].Unreadable != nil {
return nil, xv.Children[0].Unreadable
}
if xv.Children[0].Addr == 0 {
return nil, fmt.Errorf("interface conversion: %s is nil, not %s", xv.DwarfType.String(), exprToString(node.Type))
}
typ, err := scope.Thread.dbp.findTypeExpr(node.Type)
if err != nil {
return nil, err
}
if xv.Children[0].DwarfType.String() != typ.String() {
return nil, fmt.Errorf("interface conversion: %s is %s, not %s", xv.DwarfType.String(), xv.Children[0].TypeString(), typ)
}
return &xv.Children[0], nil
}
// Evaluates expressions <subexpr>[<subexpr>] (subscript access to arrays, slices and maps)
func (scope *EvalScope) evalIndex(node *ast.IndexExpr) (*Variable, error) {
xev, err := scope.evalAST(node.X)
......@@ -761,13 +778,13 @@ func equalChildren(xv, yv *Variable, shortcircuit bool) (bool, error) {
return r, nil
}
func (scope *EvalScope) findType(name string) (dwarf.Type, error) {
reader := scope.DwarfReader()
func (dbp *Process) findType(name string) (dwarf.Type, error) {
reader := dbp.DwarfReader()
typentry, err := reader.SeekToTypeNamed(name)
if err != nil {
return nil, err
}
return scope.Thread.dbp.dwarf.Type(typentry.Offset)
return dbp.dwarf.Type(typentry.Offset)
}
func (v *Variable) asInt() (int64, error) {
......
......@@ -5,6 +5,7 @@ import (
"debug/dwarf"
"encoding/binary"
"fmt"
"go/ast"
"go/constant"
"go/parser"
"go/token"
......@@ -110,6 +111,14 @@ type EvalScope struct {
CFA int64
}
type IsNilErr struct {
name string
}
func (err *IsNilErr) Error() string {
return fmt.Sprintf("%s is nil", err.name)
}
func newVariable(name string, addr uintptr, dwarfType dwarf.Type, thread *Thread) *Variable {
v := &Variable{
Name: name,
......@@ -142,6 +151,8 @@ func newVariable(name string, addr uintptr, dwarfType dwarf.Type, thread *Thread
if v.Addr != 0 {
v.base, v.Len, v.Unreadable = v.thread.readStringInfo(v.Addr)
}
case t.StructName == "runtime.iface" || t.StructName == "runtime.eface":
v.Kind = reflect.Interface
case strings.HasPrefix(t.StructName, "[]"):
v.Kind = reflect.Slice
if v.Addr != 0 {
......@@ -249,7 +260,7 @@ func (v *Variable) toField(field *dwarf.StructField) (*Variable, error) {
return v.clone(), nil
}
if v.Addr == 0 {
return nil, fmt.Errorf("%s is nil", v.Name)
return nil, &IsNilErr{v.Name}
}
name := ""
......@@ -770,6 +781,9 @@ func (v *Variable) loadValueInternal(recurseLevel int) {
}
}
case reflect.Interface:
v.loadInterface(recurseLevel, true)
case reflect.Complex64, reflect.Complex128:
v.readComplex(v.RealType.(*dwarf.ComplexType).ByteSize)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
......@@ -1366,6 +1380,101 @@ func mapEvacuated(b *Variable) bool {
return true
}
func (v *Variable) loadInterface(recurseLevel int, loadData bool) {
var typestring, data *Variable
isnil := false
for _, f := range v.RealType.(*dwarf.StructType).Field {
switch f.Name {
case "tab": // for runtime.iface
tab, _ := v.toField(f)
_type, err := tab.structMember("_type")
if err != nil {
_, isnil = err.(*IsNilErr)
if !isnil {
v.Unreadable = fmt.Errorf("invalid interface type: %v", err)
return
}
} else {
typestring, err = _type.structMember("_string")
if err != nil {
v.Unreadable = fmt.Errorf("invalid interface type: %v", err)
return
}
typestring = typestring.maybeDereference()
}
case "_type": // for runtime.eface
var err error
_type, _ := v.toField(f)
typestring, err = _type.structMember("_string")
if err != nil {
_, isnil = err.(*IsNilErr)
if !isnil {
v.Unreadable = fmt.Errorf("invalid interface type: %v", err)
return
}
} else {
typestring = typestring.maybeDereference()
}
case "data":
data, _ = v.toField(f)
}
}
if isnil {
// interface to nil
data = data.maybeDereference()
v.Children = []Variable{*data}
v.Children[0].loadValue()
return
}
if typestring == nil || data == nil || typestring.Addr == 0 || typestring.Kind != reflect.String {
v.Unreadable = fmt.Errorf("invalid interface type")
return
}
typestring.loadValue()
if typestring.Unreadable != nil {
v.Unreadable = fmt.Errorf("invalid interface type: %v", typestring.Unreadable)
return
}
t, err := parser.ParseExpr(constant.StringVal(typestring.Value))
if err != nil {
v.Unreadable = fmt.Errorf("invalid interface type, unparsable data type: %v", err)
return
}
typ, err := v.thread.dbp.findTypeExpr(t)
if err != nil {
v.Unreadable = fmt.Errorf("invalid interface type: %v", err)
return
}
data = newVariable("data", data.Addr, typ, data.thread)
v.Children = []Variable{*data}
if loadData {
v.Children[0].loadValue()
}
return
}
func (dbp *Process) findTypeExpr(expr ast.Expr) (dwarf.Type, error) {
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))
if err != nil {
return nil, err
}
return &dwarf.PtrType{dwarf.CommonType{int64(dbp.arch.PtrSize()), exprToString(expr)}, ptyp}, nil
}
return dbp.findType(exprToString(expr))
}
// Fetches all variables of a specific type in the current function scope
func (scope *EvalScope) variablesByTag(tag dwarf.Tag) ([]*Variable, error) {
reader := scope.DwarfReader()
......
......@@ -68,10 +68,16 @@ func ConvertVar(v *proc.Variable) *Variable {
if v.DwarfType != nil {
r.Type = v.DwarfType.String()
if r.Type == "*void" {
r.Type = "unsafe.Pointer"
}
}
if v.RealType != nil {
r.RealType = v.RealType.String()
if r.RealType == "*void" {
r.Type = "unsafe.Pointer"
}
}
if v.Unreadable != nil {
......
......@@ -69,6 +69,19 @@ func (v *Variable) writeTo(buf *bytes.Buffer, top, newlines, includeType bool, i
}
case reflect.Struct:
v.writeStructTo(buf, newlines, includeType, indent)
case reflect.Interface:
if includeType {
if v.Children[0].Kind == reflect.Invalid {
fmt.Fprintf(buf, "%s ", v.Type)
if v.Children[0].Addr == 0 {
fmt.Fprintf(buf, "nil")
return
}
} else {
fmt.Fprintf(buf, "%s(%s) ", v.Type, v.Children[0].Type)
}
}
v.Children[0].writeTo(buf, false, newlines, false, indent)
case reflect.Map:
v.writeMapTo(buf, newlines, includeType, indent)
case reflect.Func:
......@@ -192,7 +205,7 @@ func (v *Variable) shouldNewlineArray(newlines bool) bool {
kind, hasptr := (&v.Children[0]).recursiveKind()
switch kind {
case reflect.Slice, reflect.Array, reflect.Struct, reflect.Map:
case reflect.Slice, reflect.Array, reflect.Struct, reflect.Map, reflect.Interface:
return true
case reflect.String:
if hasptr {
......@@ -233,7 +246,7 @@ func (v *Variable) shouldNewlineStruct(newlines bool) bool {
kind, hasptr := (&v.Children[i]).recursiveKind()
switch kind {
case reflect.Slice, reflect.Array, reflect.Struct, reflect.Map:
case reflect.Slice, reflect.Array, reflect.Struct, reflect.Map, reflect.Interface:
return true
case reflect.String:
if hasptr {
......
......@@ -399,6 +399,20 @@ func TestEvalExpression(t *testing.T) {
{"mnil[\"Malone\"]", false, "", "", "", fmt.Errorf("key not found")},
{"m1[80:]", false, "", "", "", fmt.Errorf("map index out of bounds")},
// interfaces
{"err1", true, "error(*struct main.astruct) *{A: 1, B: 2}", "", "error", nil},
{"err2", true, "error(*struct main.bstruct) *{a: main.astruct {A: 1, B: 2}}", "", "error", nil},
{"errnil", true, "error nil", "", "error", nil},
{"iface1", true, "interface {}(*struct main.astruct) *{A: 1, B: 2}", "", "interface {}", nil},
{"ifacenil", true, "interface {} nil", "", "interface {}", nil},
{"err1 == err2", false, "false", "", "", nil},
{"err1 == iface1", false, "", "", "", fmt.Errorf("mismatched types \"error\" and \"interface {}\"")},
{"errnil == nil", false, "false", "", "", nil},
{"nil == errnil", false, "false", "", "", nil},
{"err1.(*main.astruct)", false, "*struct main.astruct {A: 1, B: 2}", "", "*struct main.astruct", nil},
{"err1.(*main.bstruct)", false, "", "", "", fmt.Errorf("interface conversion: error is *struct main.astruct, not *struct main.bstruct")},
{"errnil.(*main.astruct)", false, "", "", "", fmt.Errorf("interface conversion: error is nil, not *main.astruct")},
// combined expressions
{"c1.pb.a.A", true, "1", "", "int", nil},
{"c1.sa[1].B", false, "3", "", "int", nil},
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册