x/debug: support getting values of string type.

The returned strings are truncated; some future code will allow getting
more of the string.

Change-Id: Ie4f4be081a521f90142754bbf475d7c4e020a9e9
Reviewed-on: https://go-review.googlesource.com/13788
Reviewed-by: Rob Pike <r@golang.org>
diff --git a/ogle/demo/ogler/ogler_test.go b/ogle/demo/ogler/ogler_test.go
index 4660ec4..e5803dd 100644
--- a/ogle/demo/ogler/ogler_test.go
+++ b/ogle/demo/ogler/ogler_test.go
@@ -501,4 +501,19 @@
 		}
 		return nil
 	})
+
+	checkValue("main.Z_string", func(val program.Value) error {
+		s, ok := val.(program.String)
+		if !ok {
+			return fmt.Errorf("got %T(%v) expected String", val, val)
+		}
+		if s.Length != 12 {
+			return fmt.Errorf("got string length %d expected 12", s.Length)
+		}
+		expected := "I'm a string"
+		if s.String != expected {
+			return fmt.Errorf("got %s expected %s", s.String, expected)
+		}
+		return nil
+	})
 }
diff --git a/ogle/program/program.go b/ogle/program/program.go
index 367c7d7..f80efe1 100644
--- a/ogle/program/program.go
+++ b/ogle/program/program.go
@@ -133,6 +133,15 @@
 	Capacity uint64
 }
 
+// String is a Var representing a string.
+// TODO: a method to access more of a truncated string.
+type String struct {
+	// Length contains the length of the remote string, in bytes.
+	Length uint64
+	// String contains the string itself; it may be truncated to fewer bytes than the value of the Length field.
+	String string
+}
+
 // Map is a Var representing a map.
 type Map struct {
 	TypeID  uint64
diff --git a/ogle/program/proxyrpc/proxyrpc.go b/ogle/program/proxyrpc/proxyrpc.go
index dc2de15..1a76110 100644
--- a/ogle/program/proxyrpc/proxyrpc.go
+++ b/ogle/program/proxyrpc/proxyrpc.go
@@ -19,6 +19,7 @@
 	gob.Register(program.Struct{})
 	gob.Register(program.Slice{})
 	gob.Register(program.Map{})
+	gob.Register(program.String{})
 }
 
 // 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 dea3b85..d53e5a8 100644
--- a/ogle/program/server/value.go
+++ b/ogle/program/server/value.go
@@ -180,6 +180,27 @@
 			Address: addr,
 			Length:  length,
 		}, nil
+	case *dwarf.StringType:
+		ptr, err := s.peekPtrStructField(&t.StructType, addr, "str")
+		if err != nil {
+			return nil, fmt.Errorf("reading string location: %s", err)
+		}
+		length, err := s.peekUintOrIntStructField(&t.StructType, addr, "len")
+		if err != nil {
+			return nil, fmt.Errorf("reading string length: %s", err)
+		}
+
+		const maxStringSize = 256
+
+		n := length
+		if n > maxStringSize {
+			n = maxStringSize
+		}
+		tmp := make([]byte, n)
+		if err := s.peekBytes(ptr, tmp); err != nil {
+			return nil, fmt.Errorf("reading string contents: %s", err)
+		}
+		return program.String{Length: length, String: string(tmp)}, nil
 		// TODO: more types
 	}
 	return nil, fmt.Errorf("Unsupported type %T", t)