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  }