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 nilslice []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
|
||||
m1 := map[string]astruct{
|
||||
"Malone": astruct{2, 3},
|
||||
|
@ -647,12 +647,27 @@ func (scope *EvalScope) evalIndex(node *ast.IndexExpr) (*Variable, error) {
|
||||
return nil, xev.Unreadable
|
||||
}
|
||||
|
||||
xev = xev.maybeDereference()
|
||||
|
||||
idxev, err := scope.evalAST(node.Index)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cantindex := fmt.Errorf("expression \"%s\" (%s) does not support indexing", exprToString(node.X), xev.TypeString())
|
||||
|
||||
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:
|
||||
if xev.Base == 0 {
|
||||
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)
|
||||
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:
|
||||
v.Kind = reflect.Chan
|
||||
if v.Addr != 0 {
|
||||
v.loadChanInfo()
|
||||
}
|
||||
case *godwarf.MapType:
|
||||
v.Kind = reflect.Map
|
||||
case *godwarf.StringType:
|
||||
@ -663,6 +666,11 @@ func (v *Variable) structMember(memberName string) (*Variable, error) {
|
||||
if v.Unreadable != 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.Name = v.Name
|
||||
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) {
|
||||
if v.Unreadable != nil {
|
||||
return
|
||||
|
@ -534,7 +534,7 @@ func TestEvalExpression(t *testing.T) {
|
||||
{"*p3", false, "", "", "int", fmt.Errorf("nil pointer dereference")},
|
||||
|
||||
// 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},
|
||||
{"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},
|
||||
{"cap(nilslice)", false, "0", "0", "", nil},
|
||||
{"len(nilslice)", false, "0", "0", "", nil},
|
||||
{"cap(ch1)", false, "2", "2", "", nil},
|
||||
{"len(ch1)", false, "0", "0", "", nil},
|
||||
{"cap(ch1)", false, "10", "10", "", nil},
|
||||
{"len(ch1)", false, "4", "4", "", nil},
|
||||
{"cap(chnil)", false, "0", "0", "", nil},
|
||||
{"len(chnil)", false, "0", "0", "", nil},
|
||||
{"len(m1)", false, "41", "41", "", nil},
|
||||
@ -727,6 +727,12 @@ func TestEvalExpression(t *testing.T) {
|
||||
{"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},
|
||||
{"*(*[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())
|
||||
|
Loading…
Reference in New Issue
Block a user