github.com/eh-steve/goloader@v0.0.0-20240111193454-90ff3cfdae39/mmap/syscall_unix.go (about) 1 //go:build darwin || dragonfly || freebsd || linux || openbsd || solaris || netbsd 2 // +build darwin dragonfly freebsd linux openbsd solaris netbsd 3 4 package mmap 5 6 import ( 7 "reflect" 8 "sync" 9 "syscall" 10 "unsafe" 11 ) 12 13 var ( 14 errEAGAIN error = syscall.EAGAIN 15 errEINVAL error = syscall.EINVAL 16 errENOENT error = syscall.ENOENT 17 ) 18 19 // errnoErr returns common boxed Errno values, to prevent 20 // allocations at runtime. 21 func errnoErr(e syscall.Errno) error { 22 switch e { 23 case 0: 24 return nil 25 case syscall.EAGAIN: 26 return errEAGAIN 27 case syscall.EINVAL: 28 return errEINVAL 29 case syscall.ENOENT: 30 return errENOENT 31 } 32 return e 33 } 34 35 type mmapper struct { 36 sync.Mutex 37 active map[*byte][]byte // active mappings; key is last byte in mapping 38 mmap func(addr, length uintptr, prot, flags, fd int, offset int64) (uintptr, error) 39 munmap func(addr uintptr, length uintptr) error 40 } 41 42 var mapper = &mmapper{ 43 active: make(map[*byte][]byte), 44 mmap: mmap, 45 munmap: munmap, 46 } 47 48 func (m *mmapper) Mmap(addr uintptr, fd int, offset int64, length int, prot int, flags int) (data []byte, err error) { 49 if length <= 0 { 50 return nil, syscall.EINVAL 51 } 52 53 // Map the requested memory. 54 addr, errno := m.mmap(addr, uintptr(length), prot, flags, fd, offset) 55 if errno != nil { 56 return nil, errno 57 } 58 59 // Use unsafe to turn addr into a []byte. 60 var b []byte 61 hdr := (*reflect.SliceHeader)(unsafe.Pointer(&b)) 62 hdr.Data = addr 63 hdr.Cap = length 64 hdr.Len = length 65 66 // Register mapping in m and return it. 67 p := &b[cap(b)-1] 68 m.Lock() 69 defer m.Unlock() 70 m.active[p] = b 71 return b, nil 72 } 73 74 func (m *mmapper) Munmap(data []byte) (err error) { 75 if len(data) == 0 || len(data) != cap(data) { 76 return syscall.EINVAL 77 } 78 79 // Find the base of the mapping. 80 p := &data[cap(data)-1] 81 m.Lock() 82 defer m.Unlock() 83 b := m.active[p] 84 if b == nil || &b[0] != &data[0] { 85 return syscall.EINVAL 86 } 87 88 // Unmap the memory and update m. 89 if errno := m.munmap(uintptr(unsafe.Pointer(&b[0])), uintptr(len(b))); errno != nil { 90 return errno 91 } 92 delete(m.active, p) 93 return nil 94 }