ogle/probe: rewrite validRead and validWrite to use the new SetPanicOnFault function

LGTM=nigeltao
R=nigeltao
https://golang.org/cl/66700043
diff --git a/probe/addr_test.go b/probe/addr_test.go
index eca60c1..48ff2ac 100644
--- a/probe/addr_test.go
+++ b/probe/addr_test.go
@@ -9,6 +9,12 @@
 	"testing"
 )
 
+// Defined in assembler.
+func base() uintptr
+func etext() uintptr
+func edata() uintptr
+func end() uintptr
+
 var dataItem = 3
 var bssItem [100]int
 
@@ -24,20 +30,12 @@
 	}
 }
 
-func TestHeapRange(t *testing.T) {
-	p := addr(new(int)) // On the heap.
-	if p < heapStart() || heapUsed() <= p {
-		t.Fatalf("%#x is not in [%#x, %#x)", p, heapStart(), heapUsed())
-	}
-}
-
 func TestGoodReadAddresses(t *testing.T) {
 	addrs := []uintptr{
 		base(),
 		addr(&t),        // On the stack.
 		addr(&dataItem), // In data.
 		addr(&bssItem),  // In bss.
-		heapUsed() - 1,
 	}
 	for _, a := range addrs {
 		if !validRead(a, 1) {
@@ -49,8 +47,7 @@
 func TestBadReadAddresses(t *testing.T) {
 	addrs := []uintptr{
 		0,
-		base() - 1,
-		heapUsed() + 1,
+		base()/2 - 1, // Pull well down below; the Mac only unmaps up to 0x1000.
 		^uintptr(0),
 	}
 	for _, a := range addrs {
@@ -65,7 +62,6 @@
 		addr(&t),        // On the stack.
 		addr(&dataItem), // In data.
 		addr(&bssItem),  // In bss.
-		heapUsed() - 1,
 	}
 	for _, a := range addrs {
 		if !validWrite(a, 1) {
@@ -79,7 +75,6 @@
 		0,
 		base(), // In the text segment.
 		base() - 1,
-		heapUsed(),
 		^uintptr(0),
 	}
 	for _, a := range addrs {
@@ -88,45 +83,3 @@
 		}
 	}
 }
-
-type span struct {
-	p    uintptr
-	size int
-	ok   bool
-}
-
-func TestReadAddressSpan(t *testing.T) {
-	spans := []span{
-		{base(), 0, true},
-		{base(), 1, true},
-		{base(), 4096, true},
-		{base(), int(heapStart() - base()), false},
-		{base(), 1e9, false},
-		{heapStart(), 1, true},
-		{heapStart(), 4096, true},
-		{heapStart(), 1e9, false},
-	}
-	for _, s := range spans {
-		if validRead(s.p, s.size) != s.ok {
-			t.Errorf("(%#x,%d) should be %t; is %t", s.p, s.size, s.ok, !s.ok)
-		}
-	}
-}
-
-func TestWriteAddressSpan(t *testing.T) {
-	spans := []span{
-		{etext(), 0, true},
-		{etext(), 1, true},
-		{etext(), 4096, true},
-		{etext(), int(heapStart() - base()), false},
-		{etext(), 1e9, false},
-		{heapStart(), 1, true},
-		{heapStart(), 4096, true},
-		{heapStart(), 1e9, false},
-	}
-	for _, s := range spans {
-		if validWrite(s.p, s.size) != s.ok {
-			t.Errorf("(%#x,%d) should be %t; is %t", s.p, s.size, s.ok, !s.ok)
-		}
-	}
-}
diff --git a/probe/net_test.go b/probe/net_test.go
index 7fbb4ad..fbee543 100644
--- a/probe/net_test.go
+++ b/probe/net_test.go
@@ -73,7 +73,7 @@
 	// Request a read of a bad address.
 	conn.output.WriteByte('r')
 	// Address.
-	n := putUvarint(tmp[:], uint64(base()-8))
+	n := putUvarint(tmp[:], 0)
 	conn.output.Write(tmp[:n])
 	// Length. Any length will do.
 	n = putUvarint(tmp[:], 8)
diff --git a/probe/probe.go b/probe/probe.go
index c3fdc3d..24b75af 100644
--- a/probe/probe.go
+++ b/probe/probe.go
@@ -7,63 +7,58 @@
 package probe
 
 import (
+	"runtime/debug"
 	"unsafe"
 )
 
-// Defined in assembler.
-func base() uintptr
-func etext() uintptr
-func edata() uintptr
-func end() uintptr
-
-func heapStart() uintptr
-func heapUsed() uintptr
-func heapEnd() uintptr
+// catchFault is used by the read and write routines to turn a panic into an error return.
+func catchFault(ok *bool) {
+	if e := recover(); e != nil {
+		*ok = false
+	}
+}
 
 // validRead reports whether a read of the specified size can be done at address p.
-func validRead(p uintptr, size int) bool {
+// TODO: It does this by actually doing the read and seeing if it succeeds. Do better.
+func validRead(p uintptr, size int) (ok bool) {
 	// Check for negative size and for (p + size) overflow.
 	if size < 0 || uint64(^uintptr(0)-p) < uint64(size) {
 		return false
 	}
-	// The read must be in a single contiguous valid region.
-	switch {
-	case base() <= p && p < end():
-		// Assumes text is before data, but ld's binaries always satisfy that constraint.
-		p += uintptr(size)
-		return base() <= p && p <= end()
-	case heapStart() <= p && p < heapUsed(): // Don't allow reads past the used part of the heap.
-		p += uintptr(size)
-		return heapStart() <= p && p <= heapUsed()
+	defer catchFault(&ok)
+	defer debug.SetPanicOnFault(debug.SetPanicOnFault(true))
+	ep := p + uintptr(size)
+	var b byte
+	for p < ep {
+		b = *(*byte)(unsafe.Pointer(p))
+		_ = b
+		p++
 	}
-	return false
+	return true
 }
 
 // validWrite reports whether a write of the specified size can be done at address p.
-func validWrite(p uintptr, size int) bool {
+// TODO: It does this by actually doing a write and seeing if it succeeds. Do better.
+func validWrite(p uintptr, size int) (ok bool) {
 	// Check for negative size and for (p + size) overflow.
 	if size < 0 || uint64(^uintptr(0)-p) < uint64(size) {
 		return false
 	}
-	// The write must be in a single contiguous valid region.
-	switch {
-	case etext() <= p && p < end():
-		// Assumes text is before data, but ld's binaries always satisfy that constraint.
-		p += uintptr(size)
-		return etext() <= p && p <= end()
-	case heapStart() <= p && p < heapUsed(): // Don't allow writes past the used part of the heap.
-		p += uintptr(size)
-		return heapStart() <= p && p <= heapUsed()
+	defer catchFault(&ok)
+	defer debug.SetPanicOnFault(debug.SetPanicOnFault(true))
+	ep := p + uintptr(size)
+	for p < ep {
+		*(*byte)(unsafe.Pointer(p)) = *(*byte)(unsafe.Pointer(p))
+		p++
 	}
-	return false
+	return true
 }
 
 // read copies into the argument buffer the contents of memory starting at address p.
 // Its boolean return tells whether it succeeded. If it fails, no bytes were copied.
-func read(p uintptr, buf []byte) bool {
-	if !validRead(p, len(buf)) {
-		return false
-	}
+func read(p uintptr, buf []byte) (ok bool) {
+	defer catchFault(&ok)
+	defer debug.SetPanicOnFault(debug.SetPanicOnFault(true))
 	for i := range buf {
 		buf[i] = *(*byte)(unsafe.Pointer(p))
 		p++
@@ -73,10 +68,9 @@
 
 // write copies the argument buffer to memory starting at address p.
 // Its boolean return tells whether it succeeded. If it fails, no bytes were copied.
-func write(p uintptr, buf []byte) bool {
-	if !validWrite(p, len(buf)) {
-		return false
-	}
+func write(p uintptr, buf []byte) (ok bool) {
+	defer catchFault(&ok)
+	defer debug.SetPanicOnFault(debug.SetPanicOnFault(true))
 	for i := range buf {
 		*(*byte)(unsafe.Pointer(p)) = buf[i]
 		p++
diff --git a/probe/probe_darwin_amd64.s b/probe/probe_darwin_amd64.s
index a29a792..90ec8cc 100644
--- a/probe/probe_darwin_amd64.s
+++ b/probe/probe_darwin_amd64.s
@@ -36,27 +36,3 @@
 	LEAQ	end+0(SB), BX
 	MOVQ	BX, ret+0(FP)
 	RET
-
-// These are offsets of critical fields of runtime.mheap.
-// TODO: Very susceptible to change! They (or something equivalent) need to be published by runtime.
-#define arena_start_offset 14504
-#define arena_used_offset 14512
-#define arena_end_offset 14520
-
-// start of heap.
-TEXT ·heapStart(SB), NOSPLIT, $0
-	MOVQ	runtime·mheap+arena_start_offset(SB), BX
-	MOVQ	BX, ret+0(FP)
-	RET
-
-// end of active region of heap.
-TEXT ·heapUsed(SB), NOSPLIT, $0
-	MOVQ	runtime·mheap+arena_used_offset(SB), BX
-	MOVQ	BX, ret+0(FP)
-	RET
-
-// end of all of heap.
-TEXT ·heapEnd(SB), NOSPLIT, $0
-	MOVQ	runtime·mheap+arena_end_offset(SB), BX
-	MOVQ	BX, ret+0(FP)
-	RET
diff --git a/probe/probe_linux_amd64.s b/probe/probe_linux_amd64.s
index 9922332..37999a2 100644
--- a/probe/probe_linux_amd64.s
+++ b/probe/probe_linux_amd64.s
@@ -37,27 +37,3 @@
 	LEAQ	end+0(SB), BX
 	MOVQ	BX, ret+0(FP)
 	RET
-
-// These are offsets of critical fields of runtime.mheap.
-// TODO: Very susceptible to change! They (or something equivalent) need to be published by runtime.
-#define arena_start_offset 14504
-#define arena_used_offset 14512
-#define arena_end_offset 14520
-
-// start of heap.
-TEXT ·heapStart(SB), NOSPLIT, $0
-	MOVQ	runtime·mheap+arena_start_offset(SB), BX
-	MOVQ	BX, ret+0(FP)
-	RET
-
-// end of active region of heap.
-TEXT ·heapUsed(SB), NOSPLIT, $0
-	MOVQ	runtime·mheap+arena_used_offset(SB), BX
-	MOVQ	BX, ret+0(FP)
-	RET
-
-// end of all of heap.
-TEXT ·heapEnd(SB), NOSPLIT, $0
-	MOVQ	runtime·mheap+arena_end_offset(SB), BX
-	MOVQ	BX, ret+0(FP)
-	RET