proc: support access to chan buffers
Replace the unsafe.Pointer type of the buf field of channels with the appropriate array type, allow expressions accessing member field of the channel struct. Fixes #962
This commit is contained in:
parent
1ced7c3a60
commit
844762a853
@ -108,7 +108,11 @@ func main() {
|
|||||||
var fn2 functype = nil
|
var fn2 functype = nil
|
||||||
var nilslice []int = nil
|
var nilslice []int = nil
|
||||||
var nilptr *int = nil
|
var nilptr *int = nil
|
||||||
ch1 := make(chan int, 2)
|
ch1 := make(chan int, 10)
|
||||||
|
ch1 <- 1
|
||||||
|
ch1 <- 4
|
||||||
|
ch1 <- 3
|
||||||
|
ch1 <- 2
|
||||||
var chnil chan int = nil
|
var chnil chan int = nil
|
||||||
m1 := map[string]astruct{
|
m1 := map[string]astruct{
|
||||||
"Malone": astruct{2, 3},
|
"Malone": astruct{2, 3},
|
||||||
|
@ -647,12 +647,27 @@ func (scope *EvalScope) evalIndex(node *ast.IndexExpr) (*Variable, error) {
|
|||||||
return nil, xev.Unreadable
|
return nil, xev.Unreadable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xev = xev.maybeDereference()
|
||||||
|
|
||||||
idxev, err := scope.evalAST(node.Index)
|
idxev, err := scope.evalAST(node.Index)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cantindex := fmt.Errorf("expression \"%s\" (%s) does not support indexing", exprToString(node.X), xev.TypeString())
|
||||||
|
|
||||||
switch xev.Kind {
|
switch xev.Kind {
|
||||||
|
case reflect.Ptr:
|
||||||
|
if xev == nilVariable {
|
||||||
|
return nil, cantindex
|
||||||
|
}
|
||||||
|
_, isarrptr := xev.RealType.(*godwarf.PtrType).Type.(*godwarf.ArrayType)
|
||||||
|
if !isarrptr {
|
||||||
|
return nil, cantindex
|
||||||
|
}
|
||||||
|
xev = xev.maybeDereference()
|
||||||
|
fallthrough
|
||||||
|
|
||||||
case reflect.Slice, reflect.Array, reflect.String:
|
case reflect.Slice, reflect.Array, reflect.String:
|
||||||
if xev.Base == 0 {
|
if xev.Base == 0 {
|
||||||
return nil, fmt.Errorf("can not index \"%s\"", exprToString(node.X))
|
return nil, fmt.Errorf("can not index \"%s\"", exprToString(node.X))
|
||||||
@ -670,8 +685,7 @@ func (scope *EvalScope) evalIndex(node *ast.IndexExpr) (*Variable, error) {
|
|||||||
}
|
}
|
||||||
return xev.mapAccess(idxev)
|
return xev.mapAccess(idxev)
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("expression \"%s\" (%s) does not support indexing", exprToString(node.X), xev.TypeString())
|
return nil, cantindex
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,6 +198,9 @@ func newVariable(name string, addr uintptr, dwarfType godwarf.Type, bi *BinaryIn
|
|||||||
}
|
}
|
||||||
case *godwarf.ChanType:
|
case *godwarf.ChanType:
|
||||||
v.Kind = reflect.Chan
|
v.Kind = reflect.Chan
|
||||||
|
if v.Addr != 0 {
|
||||||
|
v.loadChanInfo()
|
||||||
|
}
|
||||||
case *godwarf.MapType:
|
case *godwarf.MapType:
|
||||||
v.Kind = reflect.Map
|
v.Kind = reflect.Map
|
||||||
case *godwarf.StringType:
|
case *godwarf.StringType:
|
||||||
@ -663,6 +666,11 @@ func (v *Variable) structMember(memberName string) (*Variable, error) {
|
|||||||
if v.Unreadable != nil {
|
if v.Unreadable != nil {
|
||||||
return v.clone(), nil
|
return v.clone(), nil
|
||||||
}
|
}
|
||||||
|
switch v.Kind {
|
||||||
|
case reflect.Chan:
|
||||||
|
v = v.clone()
|
||||||
|
v.RealType = resolveTypedef(&(v.RealType.(*godwarf.ChanType).TypedefType))
|
||||||
|
}
|
||||||
structVar := v.maybeDereference()
|
structVar := v.maybeDereference()
|
||||||
structVar.Name = v.Name
|
structVar.Name = v.Name
|
||||||
if structVar.Unreadable != nil {
|
if structVar.Unreadable != nil {
|
||||||
@ -1010,6 +1018,66 @@ func (v *Variable) loadSliceInfo(t *godwarf.SliceType) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// loadChanInfo loads the buffer size of the channel and changes the type of
|
||||||
|
// the buf field from unsafe.Pointer to an array of the correct type.
|
||||||
|
func (v *Variable) loadChanInfo() {
|
||||||
|
chanType, ok := v.RealType.(*godwarf.ChanType)
|
||||||
|
if !ok {
|
||||||
|
v.Unreadable = errors.New("bad channel type")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sv := v.clone()
|
||||||
|
sv.RealType = resolveTypedef(&(chanType.TypedefType))
|
||||||
|
sv = sv.maybeDereference()
|
||||||
|
if sv.Unreadable != nil || sv.Addr == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
structType, ok := sv.DwarfType.(*godwarf.StructType)
|
||||||
|
if !ok {
|
||||||
|
v.Unreadable = errors.New("bad channel type")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
lenAddr, _ := sv.toField(structType.Field[1])
|
||||||
|
lenAddr.loadValue(loadSingleValue)
|
||||||
|
if lenAddr.Unreadable != nil {
|
||||||
|
v.Unreadable = fmt.Errorf("unreadable length: %v", lenAddr.Unreadable)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
chanLen, _ := constant.Uint64Val(lenAddr.Value)
|
||||||
|
|
||||||
|
newStructType := &godwarf.StructType{}
|
||||||
|
*newStructType = *structType
|
||||||
|
newStructType.Field = make([]*godwarf.StructField, len(structType.Field))
|
||||||
|
|
||||||
|
for i := range structType.Field {
|
||||||
|
field := &godwarf.StructField{}
|
||||||
|
*field = *structType.Field[i]
|
||||||
|
if field.Name == "buf" {
|
||||||
|
stride := chanType.ElemType.Common().ByteSize
|
||||||
|
atyp := &godwarf.ArrayType{
|
||||||
|
CommonType: godwarf.CommonType{
|
||||||
|
ReflectKind: reflect.Array,
|
||||||
|
ByteSize: int64(chanLen) * stride,
|
||||||
|
Name: fmt.Sprintf("[%d]%s", chanLen, chanType.ElemType.String())},
|
||||||
|
Type: chanType.ElemType,
|
||||||
|
StrideBitSize: stride * 8,
|
||||||
|
Count: int64(chanLen)}
|
||||||
|
|
||||||
|
field.Type = pointerTo(atyp, v.bi.Arch)
|
||||||
|
}
|
||||||
|
newStructType.Field[i] = field
|
||||||
|
}
|
||||||
|
|
||||||
|
v.RealType = &godwarf.ChanType{
|
||||||
|
TypedefType: godwarf.TypedefType{
|
||||||
|
CommonType: chanType.TypedefType.CommonType,
|
||||||
|
Type: pointerTo(newStructType, v.bi.Arch),
|
||||||
|
},
|
||||||
|
ElemType: chanType.ElemType,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (v *Variable) loadArrayValues(recurseLevel int, cfg LoadConfig) {
|
func (v *Variable) loadArrayValues(recurseLevel int, cfg LoadConfig) {
|
||||||
if v.Unreadable != nil {
|
if v.Unreadable != nil {
|
||||||
return
|
return
|
||||||
|
@ -534,7 +534,7 @@ func TestEvalExpression(t *testing.T) {
|
|||||||
{"*p3", false, "", "", "int", fmt.Errorf("nil pointer dereference")},
|
{"*p3", false, "", "", "int", fmt.Errorf("nil pointer dereference")},
|
||||||
|
|
||||||
// channels
|
// channels
|
||||||
{"ch1", true, "chan int 0/2", "chan int 0/2", "chan int", nil},
|
{"ch1", true, "chan int 4/10", "chan int 4/10", "chan int", nil},
|
||||||
{"chnil", true, "chan int nil", "chan int nil", "chan int", nil},
|
{"chnil", true, "chan int nil", "chan int nil", "chan int", nil},
|
||||||
{"ch1+1", false, "", "", "", fmt.Errorf("can not convert 1 constant to chan int")},
|
{"ch1+1", false, "", "", "", fmt.Errorf("can not convert 1 constant to chan int")},
|
||||||
|
|
||||||
@ -626,8 +626,8 @@ func TestEvalExpression(t *testing.T) {
|
|||||||
{"len(s3)", false, "0", "0", "", nil},
|
{"len(s3)", false, "0", "0", "", nil},
|
||||||
{"cap(nilslice)", false, "0", "0", "", nil},
|
{"cap(nilslice)", false, "0", "0", "", nil},
|
||||||
{"len(nilslice)", false, "0", "0", "", nil},
|
{"len(nilslice)", false, "0", "0", "", nil},
|
||||||
{"cap(ch1)", false, "2", "2", "", nil},
|
{"cap(ch1)", false, "10", "10", "", nil},
|
||||||
{"len(ch1)", false, "0", "0", "", nil},
|
{"len(ch1)", false, "4", "4", "", nil},
|
||||||
{"cap(chnil)", false, "0", "0", "", nil},
|
{"cap(chnil)", false, "0", "0", "", nil},
|
||||||
{"len(chnil)", false, "0", "0", "", nil},
|
{"len(chnil)", false, "0", "0", "", nil},
|
||||||
{"len(m1)", false, "41", "41", "", nil},
|
{"len(m1)", false, "41", "41", "", nil},
|
||||||
@ -727,6 +727,12 @@ func TestEvalExpression(t *testing.T) {
|
|||||||
{"string(runeslice)", false, `"tèst"`, `""`, "string", nil},
|
{"string(runeslice)", false, `"tèst"`, `""`, "string", nil},
|
||||||
{"[]byte(string(runeslice))", false, `[]uint8 len: 5, cap: 5, [116,195,168,115,116]`, `[]uint8 len: 0, cap: 0, nil`, "[]uint8", nil},
|
{"[]byte(string(runeslice))", false, `[]uint8 len: 5, cap: 5, [116,195,168,115,116]`, `[]uint8 len: 0, cap: 0, nil`, "[]uint8", nil},
|
||||||
{"*(*[5]byte)(uintptr(&byteslice[0]))", false, `[5]uint8 [116,195,168,115,116]`, `[5]uint8 [...]`, "[5]uint8", nil},
|
{"*(*[5]byte)(uintptr(&byteslice[0]))", false, `[5]uint8 [116,195,168,115,116]`, `[5]uint8 [...]`, "[5]uint8", nil},
|
||||||
|
|
||||||
|
// access to channel field members
|
||||||
|
{"ch1.qcount", false, "4", "4", "uint", nil},
|
||||||
|
{"ch1.dataqsiz", false, "10", "10", "uint", nil},
|
||||||
|
{"ch1.buf", false, `*[10]int [1,4,3,2,0,0,0,0,0,0]`, `(*[10]int)(…`, "*[10]int", nil},
|
||||||
|
{"ch1.buf[0]", false, "1", "1", "int", nil},
|
||||||
}
|
}
|
||||||
|
|
||||||
ver, _ := goversion.Parse(runtime.Version())
|
ver, _ := goversion.Parse(runtime.Version())
|
||||||
|
Loading…
Reference in New Issue
Block a user