proc: Use MemoryReader inside memoryReadWriter

This commit is contained in:
aarzilli 2017-04-18 16:24:45 +02:00 committed by Derek Parker
parent 329bc7e69d
commit 182f805094
15 changed files with 95 additions and 70 deletions

@ -9,15 +9,6 @@ import (
"sync" "sync"
) )
// 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)
}
// A SplicedMemory represents a memory space formed from multiple regions, // A SplicedMemory represents a memory space formed from multiple regions,
// each of which may override previously regions. For example, in the following // each of which may override previously regions. For example, in the following
// core, the program text was loaded at 0x400000: // core, the program text was loaded at 0x400000:
@ -203,13 +194,12 @@ func (p *CoreProcess) BinInfo() *BinaryInfo {
return &p.bi return &p.bi
} }
func (thread *CoreThread) readMemory(addr uintptr, size int) (data []byte, err error) { func (thread *CoreThread) ReadMemory(data []byte, addr uintptr) (n int, err error) {
data = make([]byte, size) n, err = thread.p.core.ReadMemory(data, addr)
n, err := thread.p.core.ReadMemory(data, addr)
if err == nil && n != len(data) { if err == nil && n != len(data) {
err = ErrShortRead err = ErrShortRead
} }
return data, err return n, err
} }
func (thread *CoreThread) writeMemory(addr uintptr, data []byte) (int, error) { func (thread *CoreThread) writeMemory(addr uintptr, data []byte) (int, error) {

@ -45,7 +45,8 @@ func Disassemble(dbp DisassembleInfo, g *G, startPC, endPC uint64) ([]AsmInstruc
} }
func disassemble(memrw memoryReadWriter, regs Registers, breakpoints map[uint64]*Breakpoint, bi *BinaryInfo, startPC, endPC uint64) ([]AsmInstruction, error) { func disassemble(memrw memoryReadWriter, regs Registers, breakpoints map[uint64]*Breakpoint, bi *BinaryInfo, startPC, endPC uint64) ([]AsmInstruction, error) {
mem, err := memrw.readMemory(uintptr(startPC), int(endPC-startPC)) mem := make([]byte, int(endPC-startPC))
_, err := memrw.ReadMemory(mem, uintptr(startPC))
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -96,7 +96,8 @@ func resolveCallArg(inst *ArchInst, currentGoroutine bool, regs Registers, mem m
} }
addr := uintptr(int64(base) + int64(index*uint64(arg.Scale)) + arg.Disp) addr := uintptr(int64(base) + int64(index*uint64(arg.Scale)) + arg.Disp)
//TODO: should this always be 64 bits instead of inst.MemBytes? //TODO: should this always be 64 bits instead of inst.MemBytes?
pcbytes, err := mem.readMemory(addr, inst.MemBytes) pcbytes := make([]byte, inst.MemBytes)
_, err := mem.ReadMemory(pcbytes, addr)
if err != nil { if err != nil {
return nil return nil
} }

@ -841,8 +841,12 @@ func (p *GdbserverProcess) setCurrentBreakpoints() error {
return nil return nil
} }
func (t *GdbserverThread) readMemory(addr uintptr, size int) (data []byte, err error) { func (t *GdbserverThread) ReadMemory(data []byte, addr uintptr) (n int, err error) {
return t.p.conn.readMemory(addr, size) err = t.p.conn.readMemory(data, addr)
if err != nil {
return 0, err
}
return len(data), nil
} }
func (t *GdbserverThread) writeMemory(addr uintptr, data []byte) (written int, err error) { func (t *GdbserverThread) writeMemory(addr uintptr, data []byte) (written int, err error) {
@ -1028,7 +1032,8 @@ func (t *GdbserverThread) reloadGAtPC() error {
} }
} }
savedcode, err := t.readMemory(uintptr(pc), len(movinstr)) savedcode := make([]byte, len(movinstr))
_, err := t.ReadMemory(savedcode, uintptr(pc))
if err != nil { if err != nil {
return err return err
} }

@ -778,8 +778,9 @@ func (conn *gdbConn) appendThreadSelector(threadID string) {
} }
// executes 'm' (read memory) command // executes 'm' (read memory) command
func (conn *gdbConn) readMemory(addr uintptr, size int) (data []byte, err error) { func (conn *gdbConn) readMemory(data []byte, addr uintptr) error {
data = make([]byte, 0, size) size := len(data)
data = data[:0]
for size > 0 { for size > 0 {
conn.outbuf.Reset() conn.outbuf.Reset()
@ -794,7 +795,7 @@ func (conn *gdbConn) readMemory(addr uintptr, size int) (data []byte, err error)
fmt.Fprintf(&conn.outbuf, "$m%x,%x", addr+uintptr(len(data)), sz) fmt.Fprintf(&conn.outbuf, "$m%x,%x", addr+uintptr(len(data)), sz)
resp, err := conn.exec(conn.outbuf.Bytes(), "memory read") resp, err := conn.exec(conn.outbuf.Bytes(), "memory read")
if err != nil { if err != nil {
return nil, err return err
} }
for i := 0; i < len(resp); i += 2 { for i := 0; i < len(resp); i += 2 {
@ -802,7 +803,7 @@ func (conn *gdbConn) readMemory(addr uintptr, size int) (data []byte, err error)
data = append(data, uint8(n)) data = append(data, uint8(n))
} }
} }
return data, nil return nil
} }
// executes 'M' (write memory) command // executes 'M' (write memory) command

@ -2,8 +2,17 @@ package proc
const cacheEnabled = true 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)
}
type memoryReadWriter interface { type memoryReadWriter interface {
readMemory(addr uintptr, size int) (data []byte, err error) MemoryReader
writeMemory(addr uintptr, data []byte) (written int, err error) writeMemory(addr uintptr, data []byte) (written int, err error)
} }
@ -17,14 +26,13 @@ func (m *memCache) contains(addr uintptr, size int) bool {
return addr >= m.cacheAddr && addr <= (m.cacheAddr+uintptr(len(m.cache)-size)) return addr >= m.cacheAddr && addr <= (m.cacheAddr+uintptr(len(m.cache)-size))
} }
func (m *memCache) readMemory(addr uintptr, size int) (data []byte, err error) { func (m *memCache) ReadMemory(data []byte, addr uintptr) (n int, err error) {
if m.contains(addr, size) { if m.contains(addr, len(data)) {
d := make([]byte, size) copy(data, m.cache[addr-m.cacheAddr:])
copy(d, m.cache[addr-m.cacheAddr:]) return len(data), nil
return d, nil
} }
return m.mem.readMemory(addr, size) return m.mem.ReadMemory(data, addr)
} }
func (m *memCache) writeMemory(addr uintptr, data []byte) (written int, err error) { func (m *memCache) writeMemory(addr uintptr, data []byte) (written int, err error) {
@ -42,14 +50,16 @@ func cacheMemory(mem memoryReadWriter, addr uintptr, size int) memoryReadWriter
if cacheMem.contains(addr, size) { if cacheMem.contains(addr, size) {
return mem return mem
} else { } else {
cache, err := cacheMem.mem.readMemory(addr, size) cache := make([]byte, size)
_, err := cacheMem.mem.ReadMemory(cache, addr)
if err != nil { if err != nil {
return mem return mem
} }
return &memCache{addr, cache, mem} return &memCache{addr, cache, mem}
} }
} }
cache, err := mem.readMemory(addr, size) cache := make([]byte, size)
_, err := mem.ReadMemory(cache, addr)
if err != nil { if err != nil {
return mem return mem
} }

@ -142,7 +142,8 @@ const (
func loadName(bi *BinaryInfo, addr uintptr, mem memoryReadWriter) (name, tag string, pkgpathoff int32, err error) { func loadName(bi *BinaryInfo, addr uintptr, mem memoryReadWriter) (name, tag string, pkgpathoff int32, err error) {
off := addr off := addr
namedata, err := mem.readMemory(off, 3) namedata := make([]byte, 3)
_, err = mem.ReadMemory(namedata, off)
off += 3 off += 3
if err != nil { if err != nil {
return "", "", 0, err return "", "", 0, err
@ -150,7 +151,8 @@ func loadName(bi *BinaryInfo, addr uintptr, mem memoryReadWriter) (name, tag str
namelen := uint16(namedata[1]<<8) | uint16(namedata[2]) namelen := uint16(namedata[1]<<8) | uint16(namedata[2])
rawstr, err := mem.readMemory(off, int(namelen)) rawstr := make([]byte, int(namelen))
_, err = mem.ReadMemory(rawstr, off)
off += uintptr(namelen) off += uintptr(namelen)
if err != nil { if err != nil {
return "", "", 0, err return "", "", 0, err
@ -159,14 +161,16 @@ func loadName(bi *BinaryInfo, addr uintptr, mem memoryReadWriter) (name, tag str
name = string(rawstr) name = string(rawstr)
if namedata[0]&nameflagHasTag != 0 { if namedata[0]&nameflagHasTag != 0 {
taglendata, err := mem.readMemory(off, 2) taglendata := make([]byte, 2)
_, err = mem.ReadMemory(taglendata, off)
off += 2 off += 2
if err != nil { if err != nil {
return "", "", 0, err return "", "", 0, err
} }
taglen := uint16(taglendata[0]<<8) | uint16(taglendata[1]) taglen := uint16(taglendata[0]<<8) | uint16(taglendata[1])
rawstr, err := mem.readMemory(off, int(taglen)) rawstr := make([]byte, int(taglen))
_, err = mem.ReadMemory(rawstr, off)
off += uintptr(taglen) off += uintptr(taglen)
if err != nil { if err != nil {
return "", "", 0, err return "", "", 0, err
@ -176,7 +180,8 @@ func loadName(bi *BinaryInfo, addr uintptr, mem memoryReadWriter) (name, tag str
} }
if namedata[0]&nameflagHasPkg != 0 { if namedata[0]&nameflagHasPkg != 0 {
pkgdata, err := mem.readMemory(off, 4) pkgdata := make([]byte, 4)
_, err = mem.ReadMemory(pkgdata, off)
if err != nil { if err != nil {
return "", "", 0, err return "", "", 0, err
} }

@ -282,7 +282,8 @@ func (dbp *Process) SetBreakpoint(addr uint64, kind BreakpointKind, cond ast.Exp
} }
thread := dbp.threads[tid] thread := dbp.threads[tid]
originalData, err := thread.readMemory(uintptr(addr), dbp.bi.arch.BreakpointSize()) originalData := make([]byte, dbp.bi.arch.BreakpointSize())
_, err := thread.ReadMemory(originalData, uintptr(addr))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -707,7 +708,8 @@ func GoroutinesInfo(dbp EvalScopeConvertible) ([]*G, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
allglenBytes, err := dbp.CurrentThread().readMemory(uintptr(addr), 8) allglenBytes := make([]byte, 8)
_, err = dbp.CurrentThread().ReadMemory(allglenBytes, uintptr(addr))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -722,7 +724,8 @@ func GoroutinesInfo(dbp EvalScopeConvertible) ([]*G, error) {
return nil, err return nil, err
} }
} }
faddr, err := dbp.CurrentThread().readMemory(uintptr(allgentryaddr), dbp.BinInfo().arch.PtrSize()) faddr := make([]byte, dbp.BinInfo().arch.PtrSize())
_, err = dbp.CurrentThread().ReadMemory(faddr, uintptr(allgentryaddr))
allgptr := binary.LittleEndian.Uint64(faddr) allgptr := binary.LittleEndian.Uint64(faddr)
for i := uint64(0); i < allglen; i++ { for i := uint64(0); i < allglen; i++ {

@ -135,7 +135,9 @@ func getRegisters(p IProcess, t *testing.T) Registers {
} }
func dataAtAddr(thread memoryReadWriter, addr uint64) ([]byte, error) { func dataAtAddr(thread memoryReadWriter, addr uint64) ([]byte, error) {
return thread.readMemory(uintptr(addr), 1) data := make([]byte, 1)
_, err := thread.ReadMemory(data, uintptr(addr))
return data, err
} }
func assertNoError(err error, t testing.TB, s string) { func assertNoError(err error, t testing.TB, s string) {

@ -330,7 +330,8 @@ func (dbp *Process) waitForDebugEvent(flags waitForDebugEventFlags) (threadID, e
// this exception anymore. // this exception anymore.
atbp := true atbp := true
if thread, found := dbp.threads[tid]; found { if thread, found := dbp.threads[tid]; found {
if data, err := thread.readMemory(exception.ExceptionRecord.ExceptionAddress, dbp.bi.arch.BreakpointSize()); err == nil { data := make([]byte, dbp.bi.arch.BreakpointSize())
if _, err := thread.ReadMemory(data, exception.ExceptionRecord.ExceptionAddress); err == nil {
instr := dbp.bi.arch.BreakpointInstruction() instr := dbp.bi.arch.BreakpointInstruction()
for i := range instr { for i := range instr {
if data[i] != instr[i] { if data[i] != instr[i] {

@ -385,7 +385,8 @@ func getGVariable(thread IThread) (*Variable, error) {
gaddr, hasgaddr := regs.GAddr() gaddr, hasgaddr := regs.GAddr()
if !hasgaddr { if !hasgaddr {
gaddrbs, err := thread.readMemory(uintptr(regs.TLS()+arch.GStructOffset()), arch.PtrSize()) gaddrbs := make([]byte, arch.PtrSize())
_, err := thread.ReadMemory(gaddrbs, uintptr(regs.TLS()+arch.GStructOffset()))
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -119,20 +119,19 @@ func (t *Thread) writeMemory(addr uintptr, data []byte) (int, error) {
return len(data), nil return len(data), nil
} }
func (t *Thread) readMemory(addr uintptr, size int) ([]byte, error) { func (t *Thread) ReadMemory(buf []byte, addr uintptr) (int, error) {
if size == 0 { if len(buf) == 0 {
return nil, nil return 0, nil
} }
var ( var (
buf = make([]byte, size)
vmData = unsafe.Pointer(&buf[0]) vmData = unsafe.Pointer(&buf[0])
vmAddr = C.mach_vm_address_t(addr) vmAddr = C.mach_vm_address_t(addr)
length = C.mach_msg_type_number_t(size) length = C.mach_msg_type_number_t(len(buf))
) )
ret := C.read_memory(t.dbp.os.task, vmAddr, vmData, length) ret := C.read_memory(t.dbp.os.task, vmAddr, vmData, length)
if ret < 0 { if ret < 0 {
return nil, fmt.Errorf("could not read memory") return 0, fmt.Errorf("could not read memory")
} }
return buf, nil return len(buf), nil
} }

@ -102,11 +102,10 @@ func (t *Thread) writeMemory(addr uintptr, data []byte) (written int, err error)
return return
} }
func (t *Thread) readMemory(addr uintptr, size int) (data []byte, err error) { func (t *Thread) ReadMemory(data []byte, addr uintptr) (n int, err error) {
if size == 0 { if len(data) == 0 {
return return
} }
data = make([]byte, size)
t.dbp.execPtraceFunc(func() { _, err = sys.PtracePeekData(t.ID, addr, data) }) t.dbp.execPtraceFunc(func() { _, err = sys.PtracePeekData(t.ID, addr, data) })
return return
} }

@ -138,15 +138,14 @@ func (t *Thread) writeMemory(addr uintptr, data []byte) (int, error) {
return int(count), nil return int(count), nil
} }
func (t *Thread) readMemory(addr uintptr, size int) ([]byte, error) { func (t *Thread) ReadMemory(buf []byte, addr uintptr) (int, error) {
if size == 0 { if len(buf) == 0 {
return nil, nil return 0, nil
} }
var count uintptr var count uintptr
buf := make([]byte, size) err := _ReadProcessMemory(t.dbp.os.hProcess, addr, &buf[0], uintptr(len(buf)), &count)
err := _ReadProcessMemory(t.dbp.os.hProcess, addr, &buf[0], uintptr(size), &count) if err == nil && count != uintptr(len(buf)) {
if err != nil { err = ErrShortRead
return nil, err
} }
return buf[:count], nil return int(count), err
} }

@ -367,7 +367,8 @@ func (gvar *Variable) parseG() (*G, error) {
_, deref := gvar.RealType.(*dwarf.PtrType) _, deref := gvar.RealType.(*dwarf.PtrType)
if deref { if deref {
gaddrbytes, err := mem.readMemory(uintptr(gaddr), gvar.bi.arch.PtrSize()) gaddrbytes := make([]byte, gvar.bi.arch.PtrSize())
_, err := mem.ReadMemory(gaddrbytes, uintptr(gaddr))
if err != nil { if err != nil {
return nil, fmt.Errorf("error derefing *G %s", err) return nil, fmt.Errorf("error derefing *G %s", err)
} }
@ -886,7 +887,8 @@ func (v *Variable) loadValueInternal(recurseLevel int, cfg LoadConfig) {
v.Value = constant.MakeUint64(val) v.Value = constant.MakeUint64(val)
case reflect.Bool: case reflect.Bool:
val, err := v.mem.readMemory(v.Addr, 1) val := make([]byte, 1)
_, err := v.mem.ReadMemory(val, v.Addr)
v.Unreadable = err v.Unreadable = err
if err == nil { if err == nil {
v.Value = constant.MakeBool(val[0] != 0) v.Value = constant.MakeBool(val[0] != 0)
@ -946,7 +948,8 @@ func readStringInfo(mem memoryReadWriter, arch Arch, addr uintptr) (uintptr, int
mem = cacheMemory(mem, addr, arch.PtrSize()*2) mem = cacheMemory(mem, addr, arch.PtrSize()*2)
// read len // read len
val, err := mem.readMemory(addr+uintptr(arch.PtrSize()), arch.PtrSize()) val := make([]byte, arch.PtrSize())
_, err := mem.ReadMemory(val, addr+uintptr(arch.PtrSize()))
if err != nil { if err != nil {
return 0, 0, fmt.Errorf("could not read string len %s", err) return 0, 0, fmt.Errorf("could not read string len %s", err)
} }
@ -956,7 +959,7 @@ func readStringInfo(mem memoryReadWriter, arch Arch, addr uintptr) (uintptr, int
} }
// read addr // read addr
val, err = mem.readMemory(addr, arch.PtrSize()) _, err = mem.ReadMemory(val, addr)
if err != nil { if err != nil {
return 0, 0, fmt.Errorf("could not read string pointer %s", err) return 0, 0, fmt.Errorf("could not read string pointer %s", err)
} }
@ -974,7 +977,8 @@ func readStringValue(mem memoryReadWriter, addr uintptr, strlen int64, cfg LoadC
count = int64(cfg.MaxStringLen) count = int64(cfg.MaxStringLen)
} }
val, err := mem.readMemory(addr, int(count)) val := make([]byte, int(count))
_, err := mem.ReadMemory(val, addr)
if err != nil { if err != nil {
return "", fmt.Errorf("could not read string at %#v due to %s", addr, err) return "", fmt.Errorf("could not read string at %#v due to %s", addr, err)
} }
@ -1102,7 +1106,8 @@ func (v *Variable) writeComplex(real, imag float64, size int64) error {
func readIntRaw(mem memoryReadWriter, addr uintptr, size int64) (int64, error) { func readIntRaw(mem memoryReadWriter, addr uintptr, size int64) (int64, error) {
var n int64 var n int64
val, err := mem.readMemory(addr, int(size)) val := make([]byte, int(size))
_, err := mem.ReadMemory(val, addr)
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -1142,7 +1147,8 @@ func (v *Variable) writeUint(value uint64, size int64) error {
func readUintRaw(mem memoryReadWriter, addr uintptr, size int64) (uint64, error) { func readUintRaw(mem memoryReadWriter, addr uintptr, size int64) (uint64, error) {
var n uint64 var n uint64
val, err := mem.readMemory(addr, int(size)) val := make([]byte, int(size))
_, err := mem.ReadMemory(val, addr)
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -1162,7 +1168,8 @@ func readUintRaw(mem memoryReadWriter, addr uintptr, size int64) (uint64, error)
} }
func (v *Variable) readFloatRaw(size int64) (float64, error) { func (v *Variable) readFloatRaw(size int64) (float64, error) {
val, err := v.mem.readMemory(v.Addr, int(size)) val := make([]byte, int(size))
_, err := v.mem.ReadMemory(val, v.Addr)
if err != nil { if err != nil {
return 0.0, err return 0.0, err
} }
@ -1206,7 +1213,8 @@ func (v *Variable) writeBool(value bool) error {
} }
func (v *Variable) readFunctionPtr() { func (v *Variable) readFunctionPtr() {
val, err := v.mem.readMemory(v.Addr, v.bi.arch.PtrSize()) val := make([]byte, v.bi.arch.PtrSize())
_, err := v.mem.ReadMemory(val, v.Addr)
if err != nil { if err != nil {
v.Unreadable = err v.Unreadable = err
return return
@ -1220,7 +1228,7 @@ func (v *Variable) readFunctionPtr() {
return return
} }
val, err = v.mem.readMemory(fnaddr, v.bi.arch.PtrSize()) _, err = v.mem.ReadMemory(val, fnaddr)
if err != nil { if err != nil {
v.Unreadable = err v.Unreadable = err
return return