bee/vendor/github.com/derekparker/delve/pkg/proc/mem.go

157 lines
4.5 KiB
Go

package proc
import (
"errors"
"github.com/derekparker/delve/pkg/dwarf/op"
)
const cacheEnabled = true
// MemoryReader is like io.ReaderAt, but the offset is a uintptr so that it
// can address all of 64-bit memory.
// Redundant with memoryReadWriter but more easily suited to working with
// the standard io package.
type MemoryReader interface {
// ReadMemory is just like io.ReaderAt.ReadAt.
ReadMemory(buf []byte, addr uintptr) (n int, err error)
}
// MemoryReadWriter is an interface for reading or writing to
// the targets memory. This allows us to read from the actual
// target memory or possibly a cache.
type MemoryReadWriter interface {
MemoryReader
WriteMemory(addr uintptr, data []byte) (written int, err error)
}
type memCache struct {
loaded bool
cacheAddr uintptr
cache []byte
mem MemoryReadWriter
}
func (m *memCache) contains(addr uintptr, size int) bool {
return addr >= m.cacheAddr && addr <= (m.cacheAddr+uintptr(len(m.cache)-size))
}
func (m *memCache) ReadMemory(data []byte, addr uintptr) (n int, err error) {
if m.contains(addr, len(data)) {
if !m.loaded {
_, err := m.mem.ReadMemory(m.cache, m.cacheAddr)
if err != nil {
return 0, err
}
m.loaded = true
}
copy(data, m.cache[addr-m.cacheAddr:])
return len(data), nil
}
return m.mem.ReadMemory(data, addr)
}
func (m *memCache) WriteMemory(addr uintptr, data []byte) (written int, err error) {
return m.mem.WriteMemory(addr, data)
}
func cacheMemory(mem MemoryReadWriter, addr uintptr, size int) MemoryReadWriter {
if !cacheEnabled {
return mem
}
if size <= 0 {
return mem
}
switch cacheMem := mem.(type) {
case *memCache:
if cacheMem.contains(addr, size) {
return mem
}
case *compositeMemory:
return mem
}
return &memCache{false, addr, make([]byte, size), mem}
}
// fakeAddress used by extractVarInfoFromEntry for variables that do not
// have a memory address, we can't use 0 because a lot of code (likely
// including client code) assumes that addr == 0 is nil
const fakeAddress = 0xbeef0000
// compositeMemory represents a chunk of memory that is stored in CPU
// registers or non-contiguously.
//
// When optimizations are enabled the compiler will store some variables
// into registers and sometimes it will also store structs non-contiguously
// with some fields stored into CPU registers and other fields stored in
// memory.
type compositeMemory struct {
realmem MemoryReadWriter
regs op.DwarfRegisters
pieces []op.Piece
data []byte
}
func newCompositeMemory(mem MemoryReadWriter, regs op.DwarfRegisters, pieces []op.Piece) *compositeMemory {
cmem := &compositeMemory{realmem: mem, regs: regs, pieces: pieces, data: []byte{}}
for _, piece := range pieces {
if piece.IsRegister {
reg := regs.Bytes(piece.RegNum)
sz := piece.Size
if sz == 0 && len(pieces) == 1 {
sz = len(reg)
}
cmem.data = append(cmem.data, reg[:sz]...)
} else {
buf := make([]byte, piece.Size)
mem.ReadMemory(buf, uintptr(piece.Addr))
cmem.data = append(cmem.data, buf...)
}
}
return cmem
}
func (mem *compositeMemory) ReadMemory(data []byte, addr uintptr) (int, error) {
addr -= fakeAddress
if addr >= uintptr(len(mem.data)) || addr+uintptr(len(data)) > uintptr(len(mem.data)) {
return 0, errors.New("read out of bounds")
}
copy(data, mem.data[addr:addr+uintptr(len(data))])
return len(data), nil
}
func (mem *compositeMemory) WriteMemory(addr uintptr, data []byte) (int, error) {
//TODO(aarzilli): implement
return 0, errors.New("can't write composite memory")
}
// DereferenceMemory returns a MemoryReadWriter that can read and write the
// memory pointed to by pointers in this memory.
// Normally mem and mem.Dereference are the same object, they are different
// only if this MemoryReadWriter is used to access memory outside of the
// normal address space of the inferior process (such as data contained in
// registers, or composite memory).
func DereferenceMemory(mem MemoryReadWriter) MemoryReadWriter {
switch mem := mem.(type) {
case *compositeMemory:
return mem.realmem
}
return mem
}
// bufferMemoryReadWriter is dummy a MemoryReadWriter backed by a []byte.
type bufferMemoryReadWriter struct {
buf []byte
}
func (mem *bufferMemoryReadWriter) ReadMemory(buf []byte, addr uintptr) (n int, err error) {
copy(buf, mem.buf[addr-fakeAddress:][:len(buf)])
return len(buf), nil
}
func (mem *bufferMemoryReadWriter) WriteMemory(addr uintptr, data []byte) (written int, err error) {
copy(mem.buf[addr-fakeAddress:], data)
return len(data), nil
}