debug: update Ogle to read Go 1.4 maps.

The internal structures have changed to this:

type hmap struct {
	count int
	flags uint32
	hash0 uint32
	B     uint8
	buckets    unsafe.Pointer
	oldbuckets unsafe.Pointer
	nevacuate  uintptr
}
type bmap struct {
	tophash [bucketCnt]uint8
	// Followed by bucketCnt keys and then bucketCnt values.
}

Change-Id: I8811907ad84729999ded6a80d2504c680b93984b
Reviewed-on: https://go-review.googlesource.com/2712
Reviewed-by: Rob Pike <r@golang.org>
diff --git a/ogle/demo/ogler/ogler_test.go b/ogle/demo/ogler/ogler_test.go
index ae726db..dcf0904 100644
--- a/ogle/demo/ogler/ogler_test.go
+++ b/ogle/demo/ogler/ogler_test.go
@@ -41,6 +41,10 @@
 	`main.Z_interface`:           `struct runtime.iface {0xX, 0xX}`,
 	`main.Z_interface_nil`:       `struct runtime.iface {0x0, 0x0}`,
 	`main.Z_interface_typed_nil`: `struct runtime.iface {0xX, 0x0}`,
+	`main.Z_map`:                 `{-21:3.54321}`,
+	`main.Z_map_2`:               `{1024:1}`,
+	`main.Z_map_empty`:           `{}`,
+	`main.Z_map_nil`:             `<nil>`,
 	`main.Z_pointer`:             `0xX`,
 	`main.Z_pointer_nil`:         `0x0`,
 	`main.Z_slice`:               `[]uint8{115, 108, 105, 99, 101}`,
diff --git a/ogle/demo/tracee/main.go b/ogle/demo/tracee/main.go
index f1426d5..9d4a36c 100644
--- a/ogle/demo/tracee/main.go
+++ b/ogle/demo/tracee/main.go
@@ -53,6 +53,10 @@
 	Z_interface           FooInterface = &Z_struct
 	Z_interface_typed_nil FooInterface = Z_pointer_nil
 	Z_interface_nil       FooInterface
+	Z_map                 map[int8]float32 = map[int8]float32{-21: 3.54321}
+	Z_map_2               map[int16]int8   = map[int16]int8{1024: 1}
+	Z_map_empty           map[int8]float32 = map[int8]float32{}
+	Z_map_nil             map[int8]float32
 	Z_pointer             *FooStruct = &Z_struct
 	Z_pointer_nil         *FooStruct
 	Z_slice               []byte = []byte{'s', 'l', 'i', 'c', 'e'}
@@ -73,6 +77,7 @@
 	fmt.Println(Z_channel, Z_channel_buffered, Z_channel_nil)
 	fmt.Println(Z_func_bar, Z_func_int8_r_int8, Z_func_int8_r_pint8)
 	fmt.Println(Z_interface, Z_interface_nil, Z_interface_typed_nil)
+	fmt.Println(Z_map, Z_map_2, Z_map_empty, Z_map_nil)
 	fmt.Println(Z_pointer, Z_pointer_nil)
 	fmt.Println(Z_slice, Z_slice_2, Z_slice_nil)
 	fmt.Println(Z_string, Z_struct)
diff --git a/ogle/program/server/print.go b/ogle/program/server/print.go
index 01db102..2f81904 100644
--- a/ogle/program/server/print.go
+++ b/ogle/program/server/print.go
@@ -404,108 +404,173 @@
 	p.printf("}")
 }
 
-// mapDesc collects the information necessary to print a map.
-type mapDesc struct {
-	typ        *dwarf.MapType
-	count      int
-	numBuckets int
-	keySize    address
-	elemSize   address
-	bucketSize address
-}
+// maxMapValuesToPrint values are printed for each map; any remaining values are
+// truncated to "...".
+const maxMapValuesToPrint = 8
 
 func (p *Printer) printMapAt(typ *dwarf.MapType, a address) {
-	// Maps are pointers to a struct type.
-	structType := typ.Type.(*dwarf.PtrType).Type.(*dwarf.StructType)
-	// Indirect through the pointer.
-	if !p.peek(a, int64(p.arch.PointerSize)) {
-		p.errorf("couldn't read map")
+	// Maps are pointers to structs.
+	pst, ok := typ.Type.(*dwarf.PtrType)
+	if !ok {
+		p.errorf("bad map type: not a pointer")
 		return
 	}
-	a = address(p.arch.Uintptr(p.tmp[:p.arch.PointerSize]))
-	// Now read the struct.
-	if !p.peek(a, structType.ByteSize) {
-		p.errorf("couldn't read map")
+	st, ok := pst.Type.(*dwarf.StructType)
+	if !ok {
+		p.errorf("bad map type: not a pointer to a struct")
 		return
 	}
-	// From runtime/hashmap.go; We need to walk the map data structure.
-	// Load the struct, then iterate over the buckets.
-	// uintgo count (occupancy).
-	offset := int(structType.Field[0].ByteOffset)
-	count := int(p.arch.Uint(p.tmp[offset : offset+p.arch.IntSize]))
-	// uint8 Log2 of number of buckets.
-	b := uint(p.tmp[structType.Field[3].ByteOffset])
-	// uint8 key size in bytes.
-	keySize := address(p.tmp[structType.Field[4].ByteOffset])
-	// uint8 element size in bytes.
-	elemSize := address(p.tmp[structType.Field[5].ByteOffset])
-	// uint16 bucket size in bytes.
-	bucketSize := address(p.arch.Uint16(p.tmp[structType.Field[6].ByteOffset:]))
-	// pointer to buckets
-	offset = int(structType.Field[7].ByteOffset)
-	bucketPtr := address(p.arch.Uintptr(p.tmp[offset : offset+p.arch.PointerSize]))
-	// pointer to old buckets.
-	offset = int(structType.Field[8].ByteOffset)
-	oldBucketPtr := address(p.arch.Uintptr(p.tmp[offset : offset+p.arch.PointerSize]))
-	// Ready to print.
-	p.printf("%s{", typ)
-	desc := mapDesc{
-		typ:        typ,
-		count:      count,
-		numBuckets: 1 << b,
-		keySize:    keySize,
-		elemSize:   elemSize,
-		bucketSize: bucketSize,
+	a, ok = p.peekPtr(a)
+	if !ok {
+		p.errorf("couldn't read map pointer")
+		return
 	}
-	p.printMapBucketsAt(desc, bucketPtr)
-	p.printMapBucketsAt(desc, oldBucketPtr)
+	if a == 0 {
+		p.printf("<nil>")
+		return
+	}
+	b, ok := p.peekUintStructField(st, a, "B")
+	if !ok {
+		p.errorf(`couldn't read map field "B"`)
+		return
+	}
+	buckets, ok := p.peekPtrStructField(st, a, "buckets")
+	if !ok {
+		p.errorf(`couldn't read map field "buckets"`)
+		return
+	}
+	oldbuckets, ok := p.peekPtrStructField(st, a, "oldbuckets")
+	if !ok {
+		p.errorf(`couldn't read map field "oldbuckets"`)
+		return
+	}
+
+	p.printf("{")
+	// Limit how many values are printed per map.
+	numValues := address(0)
+	{
+		bf, err := getField(st, "buckets")
+		if err != nil {
+			p.errorf("%s", err)
+		} else {
+			p.printMapBucketsAt(bf.Type, buckets, 1<<b, &numValues)
+		}
+	}
+	if b > 0 {
+		bf, err := getField(st, "oldbuckets")
+		if err != nil {
+			p.errorf("%s", err)
+		} else {
+			p.printMapBucketsAt(bf.Type, oldbuckets, 1<<(b-1), &numValues)
+		}
+	}
 	p.printf("}")
 }
 
-// Map bucket layout from runtime/hashmap.go
-const (
-	bucketCnt  = 8
-	minTopHash = 4
-)
-
-func (p *Printer) printMapBucketsAt(desc mapDesc, a address) {
+func (p *Printer) printMapBucketsAt(t dwarf.Type, a, numBuckets address, numValues *address) {
+	if *numValues > maxMapValuesToPrint {
+		return
+	}
 	if a == 0 {
 		return
 	}
-	for i := 0; desc.count > 0 && i < desc.numBuckets; i++ {
-		// After the header, the bucket struct has an array of keys followed by an array of elements.
-		// Load this bucket struct into p's cache and initialize "pointers" to the key and value slices.
-		if !p.setCache(a, desc.bucketSize) {
-			p.errorf("couldn't read map")
-			return
-		}
-		keyAddr := a + bucketCnt + address(p.arch.PointerSize)
-		elemAddr := keyAddr + bucketCnt*desc.keySize
-		a += desc.bucketSize // Advance to next bucket; keyAddr and elemAddr are all we need now.
-		// tophash uint8 [bucketCnt] tells us which buckets are occupied.
-		// p.cache has the data but calls to printValueAt below may overwrite the
-		// cache, so grab a copy of the relevant data.
-		var tophash [bucketCnt]byte
-		if copy(tophash[:], p.cache) != bucketCnt {
-			p.errorf("bad count copying hash flags")
-			return
-		}
-		overflow := address(p.arch.Uintptr(p.cache[bucketCnt : bucketCnt+p.arch.PointerSize]))
-		for j := 0; desc.count > 0 && j < bucketCnt; j++ {
-			if tophash[j] >= minTopHash {
-				p.printValueAt(desc.typ.KeyType, keyAddr)
-				p.printf(":")
-				p.printValueAt(desc.typ.ElemType, elemAddr)
-				desc.count--
-				if desc.count > 0 {
+	// From runtime/hashmap.go
+	const minTopHash = 4
+	// t is a pointer to a struct.
+	bucketPtrType, ok := t.(*dwarf.PtrType)
+	if !ok {
+		p.errorf("bad map bucket type: not a pointer")
+		return
+	}
+	bt, ok := bucketPtrType.Type.(*dwarf.StructType)
+	if !ok {
+		p.errorf("bad map bucket type: not a pointer to a struct")
+		return
+	}
+	bucketSize, ok := p.sizeof(bucketPtrType.Type)
+	if !ok {
+		p.errorf("can't get bucket size")
+		return
+	}
+	tophashField, err := getField(bt, "tophash")
+	if err != nil {
+		p.errorf("%s", err)
+		return
+	}
+	bucketCnt, ok := p.sizeof(tophashField.Type)
+	if !ok {
+		p.errorf("can't get tophash size")
+		return
+	}
+	keysField, err := getField(bt, "keys")
+	if err != nil {
+		p.errorf("%s", err)
+		return
+	}
+	keysType, ok := keysField.Type.(*dwarf.ArrayType)
+	if !ok {
+		p.errorf(`bad map bucket type: "keys" is not an array`)
+		return
+	}
+	keysStride, ok := p.arrayStride(keysType)
+	if !ok {
+		p.errorf("unknown key size")
+		keysStride = 1
+	}
+	valuesField, err := getField(bt, "values")
+	if err != nil {
+		p.errorf("%s", err)
+		return
+	}
+	valuesType, ok := valuesField.Type.(*dwarf.ArrayType)
+	if !ok {
+		p.errorf(`bad map bucket type: "values" is not an array`)
+		return
+	}
+	valuesStride, ok := p.arrayStride(valuesType)
+	if !ok {
+		p.errorf("unknown value size")
+		keysStride = 1
+	}
+
+	for i := address(0); i < numBuckets; i++ {
+		bucketAddr := a + i*bucketSize
+		// TODO: check for repeated bucket pointers.
+		for bucketAddr != 0 {
+			for j := address(0); j < bucketCnt; j++ {
+				tophash, ok := p.peekUint8(bucketAddr + address(tophashField.ByteOffset) + j)
+				if !ok {
+					p.errorf("couldn't read map")
+					return
+				}
+				if tophash < minTopHash {
+					continue
+				}
+
+				// Limit how many values are printed per map.
+				(*numValues)++
+				if *numValues > maxMapValuesToPrint {
+					p.printf(", ...")
+					return
+				}
+				if *numValues > 1 {
 					p.printf(", ")
 				}
+
+				p.printValueAt(keysType.Type,
+					bucketAddr+address(keysField.ByteOffset)+j*keysStride)
+				p.printf(":")
+				p.printValueAt(valuesType.Type,
+					bucketAddr+address(valuesField.ByteOffset)+j*valuesStride)
 			}
-			keyAddr += desc.keySize
-			elemAddr += desc.elemSize
+
+			var ok bool
+			bucketAddr, ok = p.peekPtrStructField(bt, bucketAddr, "overflow")
+			if !ok {
+				p.errorf("couldn't read map")
+				return
+			}
 		}
-		// pointer to overflow bucket, if any.
-		p.printMapBucketsAt(desc, overflow)
 	}
 }