mem.go 1.6 KB
Newer Older
1 2 3 4
package proc

const cacheEnabled = true

5 6 7 8 9 10 11 12 13
// 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)
}

14
type MemoryReadWriter interface {
15
	MemoryReader
16
	WriteMemory(addr uintptr, data []byte) (written int, err error)
17 18 19 20 21
}

type memCache struct {
	cacheAddr uintptr
	cache     []byte
22
	mem       MemoryReadWriter
23 24 25
}

func (m *memCache) contains(addr uintptr, size int) bool {
26
	return addr >= m.cacheAddr && addr <= (m.cacheAddr+uintptr(len(m.cache)-size))
27 28
}

29 30 31 32
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
33 34
	}

35
	return m.mem.ReadMemory(data, addr)
36 37
}

38 39
func (m *memCache) WriteMemory(addr uintptr, data []byte) (written int, err error) {
	return m.mem.WriteMemory(addr, data)
40 41
}

42
func cacheMemory(mem MemoryReadWriter, addr uintptr, size int) MemoryReadWriter {
43 44 45
	if !cacheEnabled {
		return mem
	}
46 47 48
	if size <= 0 {
		return mem
	}
49 50 51 52
	if cacheMem, isCache := mem.(*memCache); isCache {
		if cacheMem.contains(addr, size) {
			return mem
		} else {
53 54
			cache := make([]byte, size)
			_, err := cacheMem.mem.ReadMemory(cache, addr)
55 56 57 58 59 60
			if err != nil {
				return mem
			}
			return &memCache{addr, cache, mem}
		}
	}
61 62
	cache := make([]byte, size)
	_, err := mem.ReadMemory(cache, addr)
63 64 65 66 67
	if err != nil {
		return mem
	}
	return &memCache{addr, cache, mem}
}