diff --git a/_fixtures/testvariables3.go b/_fixtures/testvariables3.go index e9329d5e..a75a0be7 100644 --- a/_fixtures/testvariables3.go +++ b/_fixtures/testvariables3.go @@ -43,11 +43,13 @@ func main() { var fn2 functype = nil var nilslice []int = nil var nilptr *int = nil + ch1 := make(chan int, 2) + var chnil chan int = 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) + fmt.Println(i1, i2, i3, p1, amb1, s1, a1, p2, p3, s2, as1, str1, f1, fn1, fn2, nilslice, nilptr, ch1, chnil) } diff --git a/proc/eval.go b/proc/eval.go index 5f8d0d8a..c605d1f2 100644 --- a/proc/eval.go +++ b/proc/eval.go @@ -596,7 +596,7 @@ func compareOp(op token.Token, xv *Variable, yv *Variable) (bool, error) { return false, fmt.Errorf("sturcture too deep for comparison") } eql, err = equalChildren(xv, yv, false) - case reflect.Slice, reflect.Map, reflect.Func: + case reflect.Slice, reflect.Map, reflect.Func, reflect.Chan: if xv != nilVariable && yv != nilVariable { return false, fmt.Errorf("can not compare %s variables", xv.Kind.String()) } diff --git a/proc/variables.go b/proc/variables.go index 0703081e..0710717e 100644 --- a/proc/variables.go +++ b/proc/variables.go @@ -42,6 +42,7 @@ type Variable struct { // base address of arrays, base address of the backing array for slices (0 for nil slices) // base address of the backing byte array for strings + // address of the struct backing a chan variable // address of the function entry point for function variables (0 for nil function pointers) base uintptr stride int64 @@ -122,7 +123,12 @@ func newVariable(name string, addr uintptr, dwarfType dwarf.Type, thread *Thread switch t := v.RealType.(type) { case *dwarf.PtrType: - v.Kind = reflect.Ptr + structtyp, isstruct := t.Type.(*dwarf.StructType) + if isstruct && strings.HasPrefix(structtyp.StructName, "hchan<") { + v.Kind = reflect.Chan + } else { + v.Kind = reflect.Ptr + } case *dwarf.StructType: switch { case t.StructName == "string": @@ -703,6 +709,13 @@ func (v *Variable) loadValueInternal(recurseLevel int) { // Don't increase the recursion level when dereferencing pointers v.Children[0].loadValueInternal(recurseLevel) + case reflect.Chan: + sv := v.maybeDereference() + sv.loadValueInternal(recurseLevel) + v.Children = sv.Children + v.Len = sv.Len + v.base = sv.Addr + case reflect.String: var val string val, v.Unreadable = v.thread.readStringValue(v.base, v.Len) diff --git a/service/api/prettyprint.go b/service/api/prettyprint.go index 3546e0c5..66f042c3 100644 --- a/service/api/prettyprint.go +++ b/service/api/prettyprint.go @@ -55,6 +55,12 @@ func (v *Variable) writeTo(buf *bytes.Buffer, top, newlines, includeType bool, i } case reflect.String: v.writeStringTo(buf) + case reflect.Chan: + if newlines { + v.writeStructTo(buf, newlines, includeType, indent) + } else { + fmt.Fprintf(buf, "%s %s/%s", v.Type, v.Children[0].Value, v.Children[1].Value) + } case reflect.Struct: v.writeStructTo(buf, newlines, includeType, indent) case reflect.Map: diff --git a/service/test/variables_test.go b/service/test/variables_test.go index 4df3ff21..1639563e 100644 --- a/service/test/variables_test.go +++ b/service/test/variables_test.go @@ -385,6 +385,10 @@ func TestEvalExpression(t *testing.T) { {"p3", true, "*int nil", "", "*int", nil}, {"*p3", false, "", "", "int", fmt.Errorf("nil pointer dereference")}, + // channels + {"ch1", true, "chan int 0/2", "", "chan int", nil}, + {"ch1+1", false, "", "", "", fmt.Errorf("can not convert 1 constant to chan int")}, + // combined expressions {"c1.pb.a.A", true, "1", "", "int", nil}, {"c1.sa[1].B", false, "3", "", "int", nil}, @@ -455,6 +459,9 @@ func TestEvalExpression(t *testing.T) { {"nilptr != nil", false, "false", "", "", nil}, {"p1 == nil", false, "false", "", "", nil}, {"p1 != nil", false, "true", "", "", nil}, + {"ch1 == nil", false, "false", "", "", nil}, + {"chnil == nil", false, "true", "", "", nil}, + {"ch1 == chnil", false, "", "", "", fmt.Errorf("can not compare chan variables")}, // errors {"&3", false, "", "", "", fmt.Errorf("can not take address of \"3\"")},