diff --git a/pkg/proc/core.go b/pkg/proc/core.go index 63dfa5b9..f7d936da 100644 --- a/pkg/proc/core.go +++ b/pkg/proc/core.go @@ -9,15 +9,6 @@ import ( "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, // each of which may override previously regions. For example, in the following // core, the program text was loaded at 0x400000: @@ -203,13 +194,12 @@ func (p *CoreProcess) BinInfo() *BinaryInfo { return &p.bi } -func (thread *CoreThread) readMemory(addr uintptr, size int) (data []byte, err error) { - data = make([]byte, size) - n, err := thread.p.core.ReadMemory(data, addr) +func (thread *CoreThread) ReadMemory(data []byte, addr uintptr) (n int, err error) { + n, err = thread.p.core.ReadMemory(data, addr) if err == nil && n != len(data) { err = ErrShortRead } - return data, err + return n, err } func (thread *CoreThread) writeMemory(addr uintptr, data []byte) (int, error) { diff --git a/pkg/proc/disasm.go b/pkg/proc/disasm.go index 765e7b2d..330b0d50 100644 --- a/pkg/proc/disasm.go +++ b/pkg/proc/disasm.go @@ -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) { - mem, err := memrw.readMemory(uintptr(startPC), int(endPC-startPC)) + mem := make([]byte, int(endPC-startPC)) + _, err := memrw.ReadMemory(mem, uintptr(startPC)) if err != nil { return nil, err } diff --git a/pkg/proc/disasm_amd64.go b/pkg/proc/disasm_amd64.go index 2138f9da..dc7a135d 100644 --- a/pkg/proc/disasm_amd64.go +++ b/pkg/proc/disasm_amd64.go @@ -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) //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 { return nil } diff --git a/pkg/proc/gdbserver.go b/pkg/proc/gdbserver.go index 62912c80..c0fc58d8 100644 --- a/pkg/proc/gdbserver.go +++ b/pkg/proc/gdbserver.go @@ -841,8 +841,12 @@ func (p *GdbserverProcess) setCurrentBreakpoints() error { return nil } -func (t *GdbserverThread) readMemory(addr uintptr, size int) (data []byte, err error) { - return t.p.conn.readMemory(addr, size) +func (t *GdbserverThread) ReadMemory(data []byte, addr uintptr) (n int, err error) { + 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) { @@ -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 { return err } diff --git a/pkg/proc/gdbserver_conn.go b/pkg/proc/gdbserver_conn.go index a5b0ed42..c1c2a8fa 100644 --- a/pkg/proc/gdbserver_conn.go +++ b/pkg/proc/gdbserver_conn.go @@ -778,8 +778,9 @@ func (conn *gdbConn) appendThreadSelector(threadID string) { } // executes 'm' (read memory) command -func (conn *gdbConn) readMemory(addr uintptr, size int) (data []byte, err error) { - data = make([]byte, 0, size) +func (conn *gdbConn) readMemory(data []byte, addr uintptr) error { + size := len(data) + data = data[:0] for size > 0 { 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) resp, err := conn.exec(conn.outbuf.Bytes(), "memory read") if err != nil { - return nil, err + return err } 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)) } } - return data, nil + return nil } // executes 'M' (write memory) command diff --git a/pkg/proc/mem.go b/pkg/proc/mem.go index ea45360b..7e11c01d 100644 --- a/pkg/proc/mem.go +++ b/pkg/proc/mem.go @@ -2,8 +2,17 @@ package proc 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 { - readMemory(addr uintptr, size int) (data []byte, err error) + MemoryReader 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)) } -func (m *memCache) readMemory(addr uintptr, size int) (data []byte, err error) { - if m.contains(addr, size) { - d := make([]byte, size) - copy(d, m.cache[addr-m.cacheAddr:]) - return d, nil +func (m *memCache) ReadMemory(data []byte, addr uintptr) (n int, err error) { + if m.contains(addr, len(data)) { + copy(data, m.cache[addr-m.cacheAddr:]) + return len(data), 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) { @@ -42,14 +50,16 @@ func cacheMemory(mem memoryReadWriter, addr uintptr, size int) memoryReadWriter if cacheMem.contains(addr, size) { return mem } else { - cache, err := cacheMem.mem.readMemory(addr, size) + cache := make([]byte, size) + _, err := cacheMem.mem.ReadMemory(cache, addr) if err != nil { return mem } return &memCache{addr, cache, mem} } } - cache, err := mem.readMemory(addr, size) + cache := make([]byte, size) + _, err := mem.ReadMemory(cache, addr) if err != nil { return mem } diff --git a/pkg/proc/moduledata.go b/pkg/proc/moduledata.go index 914b4aa6..77390336 100644 --- a/pkg/proc/moduledata.go +++ b/pkg/proc/moduledata.go @@ -142,7 +142,8 @@ const ( func loadName(bi *BinaryInfo, addr uintptr, mem memoryReadWriter) (name, tag string, pkgpathoff int32, err error) { off := addr - namedata, err := mem.readMemory(off, 3) + namedata := make([]byte, 3) + _, err = mem.ReadMemory(namedata, off) off += 3 if err != nil { 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]) - rawstr, err := mem.readMemory(off, int(namelen)) + rawstr := make([]byte, int(namelen)) + _, err = mem.ReadMemory(rawstr, off) off += uintptr(namelen) if err != nil { return "", "", 0, err @@ -159,14 +161,16 @@ func loadName(bi *BinaryInfo, addr uintptr, mem memoryReadWriter) (name, tag str name = string(rawstr) if namedata[0]&nameflagHasTag != 0 { - taglendata, err := mem.readMemory(off, 2) + taglendata := make([]byte, 2) + _, err = mem.ReadMemory(taglendata, off) off += 2 if err != nil { return "", "", 0, err } 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) if err != nil { return "", "", 0, err @@ -176,7 +180,8 @@ func loadName(bi *BinaryInfo, addr uintptr, mem memoryReadWriter) (name, tag str } if namedata[0]&nameflagHasPkg != 0 { - pkgdata, err := mem.readMemory(off, 4) + pkgdata := make([]byte, 4) + _, err = mem.ReadMemory(pkgdata, off) if err != nil { return "", "", 0, err } diff --git a/pkg/proc/proc.go b/pkg/proc/proc.go index f06a9c86..5281c10c 100644 --- a/pkg/proc/proc.go +++ b/pkg/proc/proc.go @@ -282,7 +282,8 @@ func (dbp *Process) SetBreakpoint(addr uint64, kind BreakpointKind, cond ast.Exp } 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 { return nil, err } @@ -707,7 +708,8 @@ func GoroutinesInfo(dbp EvalScopeConvertible) ([]*G, error) { if err != nil { 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 { return nil, err } @@ -722,7 +724,8 @@ func GoroutinesInfo(dbp EvalScopeConvertible) ([]*G, error) { 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) for i := uint64(0); i < allglen; i++ { diff --git a/pkg/proc/proc_test.go b/pkg/proc/proc_test.go index 07fe86ae..b067f205 100644 --- a/pkg/proc/proc_test.go +++ b/pkg/proc/proc_test.go @@ -135,7 +135,9 @@ func getRegisters(p IProcess, t *testing.T) Registers { } 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) { diff --git a/pkg/proc/proc_windows.go b/pkg/proc/proc_windows.go index bcfb0531..d3b43c7a 100644 --- a/pkg/proc/proc_windows.go +++ b/pkg/proc/proc_windows.go @@ -330,7 +330,8 @@ func (dbp *Process) waitForDebugEvent(flags waitForDebugEventFlags) (threadID, e // this exception anymore. atbp := true 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() for i := range instr { if data[i] != instr[i] { diff --git a/pkg/proc/threads.go b/pkg/proc/threads.go index a2182a98..8a501ccf 100644 --- a/pkg/proc/threads.go +++ b/pkg/proc/threads.go @@ -385,7 +385,8 @@ func getGVariable(thread IThread) (*Variable, error) { gaddr, hasgaddr := regs.GAddr() 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 { return nil, err } diff --git a/pkg/proc/threads_darwin.go b/pkg/proc/threads_darwin.go index bf1e557a..33a8c5fb 100644 --- a/pkg/proc/threads_darwin.go +++ b/pkg/proc/threads_darwin.go @@ -119,20 +119,19 @@ func (t *Thread) writeMemory(addr uintptr, data []byte) (int, error) { return len(data), nil } -func (t *Thread) readMemory(addr uintptr, size int) ([]byte, error) { - if size == 0 { - return nil, nil +func (t *Thread) ReadMemory(buf []byte, addr uintptr) (int, error) { + if len(buf) == 0 { + return 0, nil } var ( - buf = make([]byte, size) vmData = unsafe.Pointer(&buf[0]) 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) 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 } diff --git a/pkg/proc/threads_linux.go b/pkg/proc/threads_linux.go index 2b276717..76fb72a2 100644 --- a/pkg/proc/threads_linux.go +++ b/pkg/proc/threads_linux.go @@ -102,11 +102,10 @@ func (t *Thread) writeMemory(addr uintptr, data []byte) (written int, err error) return } -func (t *Thread) readMemory(addr uintptr, size int) (data []byte, err error) { - if size == 0 { +func (t *Thread) ReadMemory(data []byte, addr uintptr) (n int, err error) { + if len(data) == 0 { return } - data = make([]byte, size) t.dbp.execPtraceFunc(func() { _, err = sys.PtracePeekData(t.ID, addr, data) }) return } diff --git a/pkg/proc/threads_windows.go b/pkg/proc/threads_windows.go index 89445da3..2899d71f 100644 --- a/pkg/proc/threads_windows.go +++ b/pkg/proc/threads_windows.go @@ -138,15 +138,14 @@ func (t *Thread) writeMemory(addr uintptr, data []byte) (int, error) { return int(count), nil } -func (t *Thread) readMemory(addr uintptr, size int) ([]byte, error) { - if size == 0 { - return nil, nil +func (t *Thread) ReadMemory(buf []byte, addr uintptr) (int, error) { + if len(buf) == 0 { + return 0, nil } var count uintptr - buf := make([]byte, size) - err := _ReadProcessMemory(t.dbp.os.hProcess, addr, &buf[0], uintptr(size), &count) - if err != nil { - return nil, err + err := _ReadProcessMemory(t.dbp.os.hProcess, addr, &buf[0], uintptr(len(buf)), &count) + if err == nil && count != uintptr(len(buf)) { + err = ErrShortRead } - return buf[:count], nil + return int(count), err } diff --git a/pkg/proc/variables.go b/pkg/proc/variables.go index 9a3fac34..12af9f94 100644 --- a/pkg/proc/variables.go +++ b/pkg/proc/variables.go @@ -367,7 +367,8 @@ func (gvar *Variable) parseG() (*G, error) { _, deref := gvar.RealType.(*dwarf.PtrType) 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 { 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) 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 if err == nil { 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) // 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 { 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 - val, err = mem.readMemory(addr, arch.PtrSize()) + _, err = mem.ReadMemory(val, addr) if err != nil { 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) } - val, err := mem.readMemory(addr, int(count)) + val := make([]byte, int(count)) + _, err := mem.ReadMemory(val, addr) if err != nil { 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) { var n int64 - val, err := mem.readMemory(addr, int(size)) + val := make([]byte, int(size)) + _, err := mem.ReadMemory(val, addr) if err != nil { 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) { var n uint64 - val, err := mem.readMemory(addr, int(size)) + val := make([]byte, int(size)) + _, err := mem.ReadMemory(val, addr) if err != nil { 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) { - val, err := v.mem.readMemory(v.Addr, int(size)) + val := make([]byte, int(size)) + _, err := v.mem.ReadMemory(val, v.Addr) if err != nil { return 0.0, err } @@ -1206,7 +1213,8 @@ func (v *Variable) writeBool(value bool) error { } 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 { v.Unreadable = err return @@ -1220,7 +1228,7 @@ func (v *Variable) readFunctionPtr() { return } - val, err = v.mem.readMemory(fnaddr, v.bi.arch.PtrSize()) + _, err = v.mem.ReadMemory(val, fnaddr) if err != nil { v.Unreadable = err return