x/debug: add support for selector expressions on structs and pointers to structs.

Change-Id: I008ab99e35716263a9ad4250f9cc9e899d242ddb
Reviewed-on: https://go-review.googlesource.com/16348
Reviewed-by: Dave Day <djd@golang.org>
diff --git a/ogle/demo/ogler/ogler_test.go b/ogle/demo/ogler/ogler_test.go
index 522fab0..d825fc9 100644
--- a/ogle/demo/ogler/ogler_test.go
+++ b/ogle/demo/ogler/ogler_test.go
@@ -222,6 +222,13 @@
 	`local_slice[1:3]`:          program.Slice{program.Array{42, 42, 2, 8}, 4},
 	`local_slice[:3:4]`:         program.Slice{program.Array{42, 42, 3, 8}, 4},
 	`local_slice[1:3:4]`:        program.Slice{program.Array{42, 42, 2, 8}, 3},
+	`local_struct.a`:            21,
+	`(&local_struct).a`:         21,
+	`(*local_pointer).a`:        21,
+	`(&*local_pointer).a`:       21,
+	`(*local_pointer).b`:        program.String{2, `hi`},
+	`local_pointer.a`:           21,
+	`local_pointer.b`:           program.String{2, `hi`},
 	`5 + false`:                 nil,
 	``:                          nil,
 	`x + ""`:                    nil,
@@ -241,6 +248,10 @@
 	`local_string[22]`:          nil,
 	`"hello"[-2]`:               nil,
 	`"hello"[22]`:               nil,
+	`local_pointer_nil.a`:       nil,
+	`(local_struct).c`:          nil,
+	`(&local_struct).c`:         nil,
+	`(*local_pointer).c`:        nil,
 }
 
 func isHex(r uint8) bool {
diff --git a/ogle/program/server/eval.go b/ogle/program/server/eval.go
index 475331a..72c3f56 100644
--- a/ogle/program/server/eval.go
+++ b/ogle/program/server/eval.go
@@ -294,6 +294,50 @@
 		}
 		return e.err("invalid indirect")
 
+	case *ast.SelectorExpr:
+		x := e.evalNode(n.X, false)
+		sel := n.Sel.Name
+		switch v := x.v.(type) {
+		case program.Struct:
+			for _, f := range v.Fields {
+				if f.Name == sel {
+					t, err := e.server.dwarfData.Type(dwarf.Offset(f.Var.TypeID))
+					if err != nil {
+						return e.err(err.Error())
+					}
+					return e.resultFrom(f.Var.Address, t, getAddress)
+				}
+			}
+			return e.err("struct field not found")
+		case program.Pointer:
+			pt, ok := followTypedefs(x.d).(*dwarf.PtrType) // x.d should be a pointer to struct.
+			if !ok {
+				return e.err("invalid DWARF information for pointer")
+			}
+			st, ok := followTypedefs(pt.Type).(*dwarf.StructType)
+			if !ok {
+				break
+			}
+			for _, f := range st.Field {
+				if f.Name == sel {
+					return e.resultFrom(v.Address+uint64(f.ByteOffset), f.Type, getAddress)
+				}
+			}
+			return e.err("struct field not found")
+		case pointerToValue:
+			st, ok := followTypedefs(x.d).(*dwarf.StructType) // x.d should be a struct.
+			if !ok {
+				break
+			}
+			for _, f := range st.Field {
+				if f.Name == sel {
+					return e.resultFrom(v.a+uint64(f.ByteOffset), f.Type, getAddress)
+				}
+			}
+			return e.err("struct field not found")
+		}
+		return e.err("invalid selector expression")
+
 	case *ast.IndexExpr:
 		x, index := e.evalNode(n.X, false), e.evalNode(n.Index, false)
 		if x.v == nil || index.v == nil {
diff --git a/ogle/program/server/eval.m4 b/ogle/program/server/eval.m4
index 694b7c1..8540ba5 100644
--- a/ogle/program/server/eval.m4
+++ b/ogle/program/server/eval.m4
@@ -294,6 +294,50 @@
 		}
 		return e.err("invalid indirect")
 
+	case *ast.SelectorExpr:
+		x := e.evalNode(n.X, false)
+		sel := n.Sel.Name
+		switch v := x.v.(type) {
+		case program.Struct:
+			for _, f := range v.Fields {
+				if f.Name == sel {
+					t, err := e.server.dwarfData.Type(dwarf.Offset(f.Var.TypeID))
+					if err != nil {
+						return e.err(err.Error())
+					}
+					return e.resultFrom(f.Var.Address, t, getAddress)
+				}
+			}
+			return e.err("struct field not found")
+		case program.Pointer:
+			pt, ok := followTypedefs(x.d).(*dwarf.PtrType) // x.d should be a pointer to struct.
+			if !ok {
+				return e.err("invalid DWARF information for pointer")
+			}
+			st, ok := followTypedefs(pt.Type).(*dwarf.StructType)
+			if !ok {
+				break
+			}
+			for _, f := range st.Field {
+				if f.Name == sel {
+					return e.resultFrom(v.Address+uint64(f.ByteOffset), f.Type, getAddress)
+				}
+			}
+			return e.err("struct field not found")
+		case pointerToValue:
+			st, ok := followTypedefs(x.d).(*dwarf.StructType) // x.d should be a struct.
+			if !ok {
+				break
+			}
+			for _, f := range st.Field {
+				if f.Name == sel {
+					return e.resultFrom(v.a+uint64(f.ByteOffset), f.Type, getAddress)
+				}
+			}
+			return e.err("struct field not found")
+		}
+		return e.err("invalid selector expression")
+
 	case *ast.IndexExpr:
 		x, index := e.evalNode(n.X, false), e.evalNode(n.Index, false)
 		if x.v == nil || index.v == nil {