func newVariable(name string, addr uintptr, dwarfType dwarf.Type, thread *Thread) (*Variable, error) { v := &Variable{ Name: name, Addr: addr, dwarfType: dwarfType, thread: thread, Type: dwarfType.String(), } switch t := dwarfType.(type) { case *dwarf.StructType: if strings.HasPrefix(t.StructName, "[]") { err := v.loadSliceInfo(t) if err != nil { return nil, err } } case *dwarf.ArrayType: v.base = v.Addr v.Len = t.Count v.Cap = -1 v.fieldType = t.Type v.stride = 0 if t.Count > 0 { v.stride = t.ByteSize / t.Count } } return v, nil }
func (v *Variable) isType(typ dwarf.Type, kind reflect.Kind) error { if v.DwarfType != nil { if typ != nil && typ.String() != v.RealType.String() { return fmt.Errorf("can not convert value of type %s to %s", v.DwarfType.String(), typ.String()) } return nil } if typ == nil { return nil } if v == nilVariable { switch kind { case reflect.Slice, reflect.Map, reflect.Func, reflect.Ptr, reflect.Chan, reflect.Interface: return nil default: return fmt.Errorf("mismatched types nil and %s", typ.String()) } } converr := fmt.Errorf("can not convert %s constant to %s", v.Value, typ.String()) if v.Value == nil { return converr } switch t := typ.(type) { case *dwarf.IntType: if v.Value.Kind() != constant.Int { return converr } case *dwarf.UintType: if v.Value.Kind() != constant.Int { return converr } case *dwarf.FloatType: if (v.Value.Kind() != constant.Int) && (v.Value.Kind() != constant.Float) { return converr } case *dwarf.BoolType: if v.Value.Kind() != constant.Bool { return converr } case *dwarf.StructType: if t.StructName != "string" { return converr } if v.Value.Kind() != constant.String { return converr } case *dwarf.ComplexType: if v.Value.Kind() != constant.Complex && v.Value.Kind() != constant.Float && v.Value.Kind() != constant.Int { return converr } default: return converr } return nil }
// Eval type cast expressions func (scope *EvalScope) evalTypeCast(node *ast.CallExpr) (*Variable, error) { if len(node.Args) != 1 { return nil, fmt.Errorf("wrong number of arguments for a type cast") } argv, err := scope.evalAST(node.Args[0]) if err != nil { return nil, err } argv.loadValue() if argv.Unreadable != nil { return nil, argv.Unreadable } fnnode := node.Fun // remove all enclosing parenthesis from the type name for { p, ok := fnnode.(*ast.ParenExpr) if !ok { break } fnnode = p.X } var 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} } else { typ, err = scope.findType(exprToString(fnnode)) if err != nil { return nil, err } } // 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()) } 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()) } n, _ := constant.Int64Val(argv.Value) v := newVariable("", 0, ptyp, scope.Thread) v.Children = []Variable{*newVariable("", uintptr(n), ptyp.Type, scope.Thread)} return v, nil }