diff --git a/_fixtures/testvariables3.go b/_fixtures/testvariables3.go index f0d816d213c69cab2d65a76b7ca3f7a42d581b05..8e7c5305b858de244c90276c6921dcd91af0de26 100644 --- a/_fixtures/testvariables3.go +++ b/_fixtures/testvariables3.go @@ -93,11 +93,14 @@ func main() { m2 := map[int]*astruct{1: &astruct{10, 11}} m3 := map[astruct]int{{1, 1}: 42, {2, 2}: 43} up1 := unsafe.Pointer(&i1) + i4 := 800 + i5 := -3 + i6 := -500 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) + 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) } diff --git a/proc/eval.go b/proc/eval.go index 348095858f4f7e26b7108445b2c13394be679952..1a23caf419b3f2d7c4e6f2c77b5ac4b2fd5d5fc7 100644 --- a/proc/eval.go +++ b/proc/eval.go @@ -3,6 +3,7 @@ package proc import ( "bytes" "debug/dwarf" + "encoding/binary" "fmt" "go/ast" "go/constant" @@ -165,7 +166,7 @@ func (scope *EvalScope) evalTypeCast(node *ast.CallExpr) (*Variable, error) { fnnode = p.X } - var typ dwarf.Type + var styp, typ dwarf.Type if snode, ok := fnnode.(*ast.StarExpr); ok { // Pointer types only appear in the dwarf informations when @@ -177,33 +178,103 @@ func (scope *EvalScope) evalTypeCast(node *ast.CallExpr) (*Variable, error) { return nil, err } typ = &dwarf.PtrType{dwarf.CommonType{int64(scope.Thread.dbp.arch.PtrSize()), exprToString(fnnode)}, ptyp} + styp = typ } else { - typ, err = scope.findType(exprToString(fnnode)) + styp, err = scope.findType(exprToString(fnnode)) if err != nil { return nil, err } + typ = resolveTypedef(styp) } - // only supports cast of integer constants into pointers - ptyp, isptrtyp := typ.(*dwarf.PtrType) - if !isptrtyp { - return nil, fmt.Errorf("can not convert \"%s\" to %s", exprToString(node.Args[0]), typ.String()) - } + converr := fmt.Errorf("can not convert \"%s\" to %s", exprToString(node.Args[0]), typ.String()) - switch argv.Kind { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - // ok - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - // ok - default: - return nil, fmt.Errorf("can not convert \"%s\" to %s", exprToString(node.Args[0]), typ.String()) + v := newVariable("", 0, styp, scope.Thread) + v.loaded = true + + switch ttyp := typ.(type) { + case *dwarf.PtrType: + switch argv.Kind { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + // ok + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + // ok + default: + return nil, converr + } + + n, _ := constant.Int64Val(argv.Value) + + v.Children = []Variable{*newVariable("", uintptr(n), ttyp.Type, scope.Thread)} + return v, nil + + case *dwarf.UintType: + switch argv.Kind { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + n, _ := constant.Int64Val(argv.Value) + v.Value = constant.MakeUint64(convertInt(uint64(n), false, ttyp.Size())) + return v, nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + n, _ := constant.Uint64Val(argv.Value) + v.Value = constant.MakeUint64(convertInt(n, false, ttyp.Size())) + return v, nil + case reflect.Float32, reflect.Float64: + x, _ := constant.Float64Val(argv.Value) + v.Value = constant.MakeUint64(uint64(x)) + return v, nil + } + case *dwarf.IntType: + switch argv.Kind { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + n, _ := constant.Int64Val(argv.Value) + v.Value = constant.MakeInt64(int64(convertInt(uint64(n), true, ttyp.Size()))) + return v, nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + n, _ := constant.Uint64Val(argv.Value) + v.Value = constant.MakeInt64(int64(convertInt(n, true, ttyp.Size()))) + return v, nil + case reflect.Float32, reflect.Float64: + x, _ := constant.Float64Val(argv.Value) + v.Value = constant.MakeInt64(int64(x)) + return v, nil + } + case *dwarf.FloatType: + switch argv.Kind { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + fallthrough + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + fallthrough + case reflect.Float32, reflect.Float64: + v.Value = argv.Value + return v, nil + } + case *dwarf.ComplexType: + switch argv.Kind { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + fallthrough + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + fallthrough + case reflect.Float32, reflect.Float64: + v.Value = argv.Value + return v, nil + } } - n, _ := constant.Int64Val(argv.Value) + return nil, converr +} - v := newVariable("", 0, ptyp, scope.Thread) - v.Children = []Variable{*newVariable("", uintptr(n), ptyp.Type, scope.Thread)} - return v, nil +func convertInt(n uint64, signed bool, size int64) uint64 { + buf := make([]byte, 64/8) + binary.BigEndian.PutUint64(buf, n) + m := 64/8 - int(size) + s := byte(0) + if signed && (buf[m]&0x80 > 0) { + s = 0xff + } + for i := 0; i < m; i++ { + buf[i] = s + } + return uint64(binary.BigEndian.Uint64(buf)) } // Evaluates identifier expressions diff --git a/proc/variables.go b/proc/variables.go index 6d4176b0440fd1519474f9d284e3485802237b5e..2d8670874a470347f51ff11884ea1632d9505a40 100644 --- a/proc/variables.go +++ b/proc/variables.go @@ -118,14 +118,7 @@ func newVariable(name string, addr uintptr, dwarfType dwarf.Type, thread *Thread thread: thread, } - v.RealType = v.DwarfType - for { - if tt, ok := v.RealType.(*dwarf.TypedefType); ok { - v.RealType = tt.Type - } else { - break - } - } + v.RealType = resolveTypedef(v.DwarfType) switch t := v.RealType.(type) { case *dwarf.PtrType: @@ -201,6 +194,16 @@ func newVariable(name string, addr uintptr, dwarfType dwarf.Type, thread *Thread return v } +func resolveTypedef(typ dwarf.Type) dwarf.Type { + for { + if tt, ok := typ.(*dwarf.TypedefType); ok { + typ = tt.Type + } else { + return typ + } + } +} + func newConstant(val constant.Value, thread *Thread) *Variable { v := &Variable{Value: val, thread: thread, loaded: true} switch val.Kind() { diff --git a/service/test/variables_test.go b/service/test/variables_test.go index 8295fee651e31bd78b1b7d495c5d9c5031078dc7..196f91b26c2f6357b26890f8dc6c2d2b663a04ca 100644 --- a/service/test/variables_test.go +++ b/service/test/variables_test.go @@ -487,6 +487,16 @@ func TestEvalExpression(t *testing.T) { {"*(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("no type entry found")}, + + // typecasts + {"uint(i2)", false, "2", "", "uint", nil}, + {"int8(i2)", false, "2", "", "int8", nil}, + {"int(f1)", false, "3", "", "int", nil}, + {"complex128(f1)", false, "(3 + 0i)", "", "complex128", nil}, + {"uint8(i4)", false, "32", "", "uint8", nil}, + {"uint8(i5)", false, "253", "", "uint8", nil}, + {"int8(i5)", false, "-3", "", "int8", nil}, + {"int8(i6)", false, "12", "", "int8", nil}, } withTestProcess("testvariables3", t, func(p *proc.Process, fixture protest.Fixture) {