x/debug: support getting values of slice type.

The type program.Slice that the user gets for slice variables just
embeds a program.Array and adds a capacity field.

The DWARF information for slices doesn't include stride, so the stride
is computed with the size of the element type.

Change-Id: I69c60998abd1b48b1986522f60f93ddcad0c155e
Reviewed-on: https://go-review.googlesource.com/12831
Reviewed-by: Rob Pike <r@golang.org>
diff --git a/ogle/demo/ogler/ogler_test.go b/ogle/demo/ogler/ogler_test.go
index 3b9e35b..b2ba5d7 100644
--- a/ogle/demo/ogler/ogler_test.go
+++ b/ogle/demo/ogler/ogler_test.go
@@ -414,4 +414,23 @@
 		}
 		return nil
 	})
+
+	checkValue("main.Z_slice", func(val program.Value) error {
+		s, ok := val.(program.Slice)
+		if !ok {
+			return fmt.Errorf("got %T(%v) expected Slice", val, val)
+		}
+		if s.Len() != 5 {
+			return fmt.Errorf("got slice length %d expected 5", s.Len())
+		}
+		expected := []uint8{115, 108, 105, 99, 101}
+		for i := uint64(0); i < 5; i++ {
+			if v, err := prog.Value(s.Element(i)); err != nil {
+				return fmt.Errorf("reading element %d: %s", i, err)
+			} else if v != expected[i] {
+				return fmt.Errorf("element %d: got %T(%v) want %T(%d)", i, v, v, expected[i], expected[i])
+			}
+		}
+		return nil
+	})
 }
diff --git a/ogle/program/program.go b/ogle/program/program.go
index 24619aa..9e45c26 100644
--- a/ogle/program/program.go
+++ b/ogle/program/program.go
@@ -123,6 +123,12 @@
 	}
 }
 
+// Slice is a Var representing a slice.
+type Slice struct {
+	Array
+	Capacity uint64
+}
+
 // Struct is a Var representing a struct.
 type Struct struct {
 	Fields []StructField
diff --git a/ogle/program/proxyrpc/proxyrpc.go b/ogle/program/proxyrpc/proxyrpc.go
index 91bb49e..568fdea 100644
--- a/ogle/program/proxyrpc/proxyrpc.go
+++ b/ogle/program/proxyrpc/proxyrpc.go
@@ -17,6 +17,7 @@
 	gob.Register(program.Pointer{})
 	gob.Register(program.Array{})
 	gob.Register(program.Struct{})
+	gob.Register(program.Slice{})
 }
 
 // For regularity, each method has a unique Request and a Response type even
diff --git a/ogle/program/server/value.go b/ogle/program/server/value.go
index d457b92..bbb1e4e 100644
--- a/ogle/program/server/value.go
+++ b/ogle/program/server/value.go
@@ -118,6 +118,32 @@
 			TypeID:  uint64(t.Type.Common().Offset),
 			Address: uint64(s.arch.Uintptr(buf)),
 		}, nil
+	case *dwarf.SliceType:
+		ptr, err := s.peekPtrStructField(&t.StructType, addr, "array")
+		if err != nil {
+			return nil, fmt.Errorf("reading slice location: %s", err)
+		}
+		length, err := s.peekUintOrIntStructField(&t.StructType, addr, "len")
+		if err != nil {
+			return nil, fmt.Errorf("reading slice length: %s", err)
+		}
+		capacity, err := s.peekUintOrIntStructField(&t.StructType, addr, "cap")
+		if err != nil {
+			return nil, fmt.Errorf("reading slice capacity: %s", err)
+		}
+		if capacity < length {
+			return nil, fmt.Errorf("slice's capacity %d is less than its length %d", capacity, length)
+		}
+
+		return program.Slice{
+			program.Array{
+				ElementTypeID: uint64(t.ElemType.Common().Offset),
+				Address:       uint64(ptr),
+				Length:        length,
+				StrideBits:    uint64(t.ElemType.Common().ByteSize) * 8,
+			},
+			capacity,
+		}, nil
 	case *dwarf.ArrayType:
 		length := t.Count
 		stride := t.StrideBitSize