ogle/probe: start of package
Implement functions to test validity of addresses for read and write.
Needs some very hacky assembly support; provide this for amd64
only, darwin and linux only.

LGTM=nigeltao
R=nigeltao
https://golang.org/cl/60070045
diff --git a/probe/addr_test.go b/probe/addr_test.go
new file mode 100644
index 0000000..65b1cc9
--- /dev/null
+++ b/probe/addr_test.go
@@ -0,0 +1,123 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"reflect"
+	"testing"
+)
+
+var dataItem = 3
+var bssItem [100]int
+
+// addr turns an arbitrary address into a uintptr.
+func addr(p interface{}) uintptr {
+	v := reflect.ValueOf(p)
+	switch v.Kind() {
+	case reflect.Ptr:
+		return v.Elem().UnsafeAddr()
+	default:
+		// TODO: how do we find the address of a text symbol?
+		panic("unknown type " + v.Type().String())
+	}
+}
+
+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) {
+			t.Errorf("%#x is invalid; should be valid", a)
+		}
+	}
+}
+
+func TestBadReadAddresses(t *testing.T) {
+	addrs := []uintptr{
+		0,
+		base() - 1,
+		heapUsed() + 1,
+		^uintptr(0),
+	}
+	for _, a := range addrs {
+		if validRead(a, 1) {
+			t.Errorf("%#x is valid; should be invalid", a)
+		}
+	}
+}
+
+func TestGoodWriteAddresses(t *testing.T) {
+	addrs := []uintptr{
+		addr(&t),        // On the stack.
+		addr(&dataItem), // In data.
+		addr(&bssItem),  // In bss.
+		heapUsed() - 1,
+	}
+	for _, a := range addrs {
+		if !validWrite(a, 1) {
+			t.Errorf("%#x is invalid; should be valid", a)
+		}
+	}
+}
+
+func TestBadWriteAddresses(t *testing.T) {
+	addrs := []uintptr{
+		0,
+		base(), // In the text segment.
+		base() - 1,
+		heapUsed(),
+		^uintptr(0),
+	}
+	for _, a := range addrs {
+		if validWrite(a, 1) {
+			t.Errorf("%#x is valid; should be invalid", a)
+		}
+	}
+}
+
+type span struct {
+	p    uintptr
+	size int
+	ok   bool
+}
+
+func TestReadAddressSpan(t *testing.T) {
+	spans := []span{
+		{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(), 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/probe.go b/probe/probe.go
new file mode 100644
index 0000000..002f671
--- /dev/null
+++ b/probe/probe.go
@@ -0,0 +1,52 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package probe is imported by programs to provide (possibly remote)
+// access to a separate debugger program.
+package main
+
+func base() uintptr
+func etext() uintptr
+func edata() uintptr
+func end() uintptr
+
+func heapStart() uintptr
+func heapUsed() uintptr
+func heapEnd() uintptr
+
+// validRead reports whether a read of the specified size can be done at address p.
+func validRead(p uintptr, size int) bool {
+	if size <= 0 {
+		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()
+	}
+	return false
+}
+
+// validWrite reports whether a write of the specified size can be done at address p.
+func validWrite(p uintptr, size int) bool {
+	if size <= 0 {
+		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()
+	}
+	return false
+}
diff --git a/probe/probe_darwin_amd64.s b/probe/probe_darwin_amd64.s
new file mode 100644
index 0000000..a29a792
--- /dev/null
+++ b/probe/probe_darwin_amd64.s
@@ -0,0 +1,62 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// TODO #include "../../cmd/ld/textflag.h"
+
+#define NOSPLIT 4
+
+// Functions that return details about our address space.
+// They use the C-defined symbols like edata and also know
+// a little about the heap and memory layout.
+
+// From the linker. Well-known but might change.
+// TODO: Is there a better way to know this?
+#define	INITTEXT 0x2000
+
+// base of the address space.
+TEXT ·base(SB), NOSPLIT, $0
+	MOVQ	$INITTEXT, ret+0(FP)
+	RET
+
+// end of the text segment.
+TEXT ·etext(SB), NOSPLIT, $0
+	LEAQ	etext+0(SB), BX
+	MOVQ	BX, ret+0(FP)
+	RET
+
+// end of the data segment.
+TEXT ·edata(SB), NOSPLIT, $0
+	LEAQ	edata+0(SB), BX
+	MOVQ	BX, ret+0(FP)
+	RET
+
+// end of the pre-defined address space.
+TEXT ·end(SB), NOSPLIT, $0
+	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
new file mode 100644
index 0000000..f373f8c
--- /dev/null
+++ b/probe/probe_linux_amd64.s
@@ -0,0 +1,63 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// TODO #include "../../cmd/ld/textflag.h"
+
+#define	NOSPLIT 4
+
+// Functions that return details about our address space.
+// They use the C-defined symbols like edata and also know
+// a little about the heap and memory layout.
+
+// From the linker. Well-known but might change.
+// TODO: Is there a better way to know this?
+#define	ELFRESERVE	3072
+#define	INITTEXT ((1<<22)+ELFRESERVE)
+
+// base of the address space.
+TEXT ·base(SB), NOSPLIT, $0
+	MOVQ	$INITTEXT, ret+0(FP)
+	RET
+
+// end of the text segment.
+TEXT ·etext(SB), NOSPLIT, $0
+	LEAQ	etext+0(SB), BX
+	MOVQ	BX, ret+0(FP)
+	RET
+
+// end of the data segment.
+TEXT ·edata(SB), NOSPLIT, $0
+	LEAQ	edata+0(SB), BX
+	MOVQ	BX, ret+0(FP)
+	RET
+
+// end of the pre-defined address space.
+TEXT ·end(SB), NOSPLIT, $0
+	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 28840
+#define arena_used_offset 28848
+#define arena_end_offset 28856
+
+// 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