debug: Prints more specific error messages.

Change-Id: Ib59508eff6c84e1653cfe365429b7c3851c680b6
Reviewed-on: https://go-review.googlesource.com/1997
Reviewed-by: Rob Pike <r@golang.org>
Reviewed-by: Nigel Tao <nigeltao@golang.org>
diff --git a/ogle/program/server/print.go b/ogle/program/server/print.go
index ccf8df3..7e2d8b5 100644
--- a/ogle/program/server/print.go
+++ b/ogle/program/server/print.go
@@ -43,32 +43,21 @@
 	cacheAddr address // Starting address of cache.
 }
 
-// printf prints to printBuf, unless there has been an error.
+// printf prints to printBuf.
 func (p *Printer) printf(format string, args ...interface{}) {
-	if p.err != nil {
-		return
-	}
 	fmt.Fprintf(&p.printBuf, format, args...)
 }
 
-// errorf sets the sticky error for the printer, if not already set.
+// errorf prints the error to printBuf, then sets the sticky error for the
+// printer, if not already set.
 func (p *Printer) errorf(format string, args ...interface{}) {
+	fmt.Fprintf(&p.printBuf, "<"+format+">", args...)
 	if p.err != nil {
 		return
 	}
 	p.err = fmt.Errorf(format, args...)
 }
 
-// ok checks the error. If it is the first non-nil error encountered,
-// it is printed to printBuf, parenthesized for discrimination, and remembered.
-func (p *Printer) ok(err error) bool {
-	if p.err == nil && err != nil {
-		p.printf("(%s)", err)
-		p.err = err
-	}
-	return p.err == nil
-}
-
 // peek reads len bytes at offset, leaving p.tmp with the data and sized appropriately.
 // It uses the cache if the request is within it.
 func (p *Printer) peek(a address, length int64) bool {
@@ -77,7 +66,8 @@
 		copy(p.tmp, p.cache[a-p.cacheAddr:])
 		return true
 	}
-	return p.ok(p.peeker.peek(uintptr(a), p.tmp))
+	err := p.peeker.peek(uintptr(a), p.tmp)
+	return err == nil
 }
 
 // setCache initializes the cache to contain the contents of the
@@ -89,11 +79,13 @@
 		p.cache = make([]byte, length)
 	}
 	p.cacheAddr = a
-	ok := p.ok(p.peeker.peek(uintptr(a), p.cache))
-	if !ok {
+	err := p.peeker.peek(uintptr(a), p.cache)
+	if err != nil {
+		// If the peek failed, don't cache anything.
 		p.resetCache()
+		return false
 	}
-	return ok
+	return true
 }
 
 func (p *Printer) resetCache() {
@@ -221,23 +213,32 @@
 		}
 		if p.peek(a, 1) {
 			p.printf("%t", p.tmp[0] != 0)
+		} else {
+			p.errorf("couldn't read bool")
 		}
 	case *dwarf.PtrType:
 		// This type doesn't define the ByteSize attribute.
 		if p.peek(a, int64(p.arch.PointerSize)) {
 			p.printf("%#x", p.arch.Uintptr(p.tmp))
+		} else {
+			p.errorf("couldn't read pointer")
 		}
 	case *dwarf.IntType:
 		// Sad we can't tell a rune from an int32.
 		if p.peek(a, typ.ByteSize) {
 			p.printf("%d", p.arch.IntN(p.tmp))
+		} else {
+			p.errorf("couldn't read int")
 		}
 	case *dwarf.UintType:
 		if p.peek(a, typ.ByteSize) {
 			p.printf("%d", p.arch.UintN(p.tmp))
+		} else {
+			p.errorf("couldn't read uint")
 		}
 	case *dwarf.FloatType:
 		if !p.peek(a, typ.ByteSize) {
+			p.errorf("couldn't read float")
 			return
 		}
 		switch typ.ByteSize {
@@ -250,6 +251,7 @@
 		}
 	case *dwarf.ComplexType:
 		if !p.peek(a, typ.ByteSize) {
+			p.errorf("couldn't read complex")
 			return
 		}
 		switch typ.ByteSize {
@@ -343,11 +345,13 @@
 	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")
 		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")
 		return
 	}
 	// From runtime/hashmap.go; We need to walk the map data structure.
@@ -398,6 +402,7 @@
 		// 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)
@@ -434,7 +439,7 @@
 	// Slices look like a struct with fields array *elemtype, len uint32/64, cap uint32/64.
 	// BUG: Slice header appears to have fields with ByteSize == 0
 	if !p.peek(a, typ.ByteSize) {
-		p.errorf("slice header has no known size")
+		p.errorf("couldn't read slice")
 		return
 	}
 	lo := typ.Field[0].ByteOffset
@@ -464,7 +469,7 @@
 	// Strings look like a struct with fields array *elemtype, len uint64.
 	// TODO uint64 on 386 too?
 	if !p.peek(a, typ.ByteSize) {
-		p.errorf("string header has no known size")
+		p.errorf("couldn't read string")
 		return
 	}
 	// BUG: String header appears to have fields with ByteSize == 0
@@ -477,10 +482,16 @@
 	if length > uint64(cap(p.tmp)) {
 		if p.peek(address(ptr), int64(cap(p.tmp))) {
 			p.printf("%q...", p.tmp)
+		} else {
+			p.errorf("couldn't read string")
+			return
 		}
 	} else {
 		if p.peek(address(ptr), int64(length)) {
 			p.printf("%q", p.tmp[:length])
+		} else {
+			p.errorf("couldn't read string")
+			return
 		}
 	}
 }