blob: c3fdc3dcd6c956ad42a97def5458b21505461173 [file] [log] [blame]
// 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 probe
import (
"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
// validRead reports whether a read of the specified size can be done at address p.
func validRead(p uintptr, size int) 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()
}
return false
}
// validWrite reports whether a write of the specified size can be done at address p.
func validWrite(p uintptr, size int) 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()
}
return false
}
// 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
}
for i := range buf {
buf[i] = *(*byte)(unsafe.Pointer(p))
p++
}
return true
}
// 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
}
for i := range buf {
*(*byte)(unsafe.Pointer(p)) = buf[i]
p++
}
return true
}