2016-01-10 12:49:03 +00:00
|
|
|
package proc
|
|
|
|
|
|
|
|
const cacheEnabled = true
|
|
|
|
|
2017-04-18 14:24:45 +00:00
|
|
|
// 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)
|
|
|
|
}
|
|
|
|
|
2017-04-21 06:55:53 +00:00
|
|
|
type MemoryReadWriter interface {
|
2017-04-18 14:24:45 +00:00
|
|
|
MemoryReader
|
2017-04-21 06:55:53 +00:00
|
|
|
WriteMemory(addr uintptr, data []byte) (written int, err error)
|
2016-01-10 12:49:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type memCache struct {
|
|
|
|
cacheAddr uintptr
|
|
|
|
cache []byte
|
2017-04-21 06:55:53 +00:00
|
|
|
mem MemoryReadWriter
|
2016-01-10 12:49:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (m *memCache) contains(addr uintptr, size int) bool {
|
2016-04-21 10:19:21 +00:00
|
|
|
return addr >= m.cacheAddr && addr <= (m.cacheAddr+uintptr(len(m.cache)-size))
|
2016-01-10 12:49:03 +00:00
|
|
|
}
|
|
|
|
|
2017-04-18 14:24:45 +00:00
|
|
|
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
|
2016-01-10 12:49:03 +00:00
|
|
|
}
|
|
|
|
|
2017-04-18 14:24:45 +00:00
|
|
|
return m.mem.ReadMemory(data, addr)
|
2016-01-10 12:49:03 +00:00
|
|
|
}
|
|
|
|
|
2017-04-21 06:55:53 +00:00
|
|
|
func (m *memCache) WriteMemory(addr uintptr, data []byte) (written int, err error) {
|
|
|
|
return m.mem.WriteMemory(addr, data)
|
2016-01-10 12:49:03 +00:00
|
|
|
}
|
|
|
|
|
2017-04-21 06:55:53 +00:00
|
|
|
func cacheMemory(mem MemoryReadWriter, addr uintptr, size int) MemoryReadWriter {
|
2016-01-10 12:49:03 +00:00
|
|
|
if !cacheEnabled {
|
|
|
|
return mem
|
|
|
|
}
|
2016-01-27 12:21:26 +00:00
|
|
|
if size <= 0 {
|
|
|
|
return mem
|
|
|
|
}
|
2016-01-10 12:49:03 +00:00
|
|
|
if cacheMem, isCache := mem.(*memCache); isCache {
|
|
|
|
if cacheMem.contains(addr, size) {
|
|
|
|
return mem
|
|
|
|
} else {
|
2017-04-18 14:24:45 +00:00
|
|
|
cache := make([]byte, size)
|
|
|
|
_, err := cacheMem.mem.ReadMemory(cache, addr)
|
2016-01-10 12:49:03 +00:00
|
|
|
if err != nil {
|
|
|
|
return mem
|
|
|
|
}
|
|
|
|
return &memCache{addr, cache, mem}
|
|
|
|
}
|
|
|
|
}
|
2017-04-18 14:24:45 +00:00
|
|
|
cache := make([]byte, size)
|
|
|
|
_, err := mem.ReadMemory(cache, addr)
|
2016-01-10 12:49:03 +00:00
|
|
|
if err != nil {
|
|
|
|
return mem
|
|
|
|
}
|
|
|
|
return &memCache{addr, cache, mem}
|
|
|
|
}
|