github.com/cilium/ebpf@v0.15.1-0.20240517100537-8079b37aa138/internal/sysenc/buffer.go (about) 1 package sysenc 2 3 import ( 4 "unsafe" 5 6 "github.com/cilium/ebpf/internal/sys" 7 ) 8 9 type Buffer struct { 10 ptr unsafe.Pointer 11 // Size of the buffer. syscallPointerOnly if created from UnsafeBuffer or when using 12 // zero-copy unmarshaling. 13 size int 14 } 15 16 const syscallPointerOnly = -1 17 18 func newBuffer(buf []byte) Buffer { 19 if len(buf) == 0 { 20 return Buffer{} 21 } 22 return Buffer{unsafe.Pointer(&buf[0]), len(buf)} 23 } 24 25 // UnsafeBuffer constructs a Buffer for zero-copy unmarshaling. 26 // 27 // [Pointer] is the only valid method to call on such a Buffer. 28 // Use [SyscallBuffer] instead if possible. 29 func UnsafeBuffer(ptr unsafe.Pointer) Buffer { 30 return Buffer{ptr, syscallPointerOnly} 31 } 32 33 // SyscallOutput prepares a Buffer for a syscall to write into. 34 // 35 // size is the length of the desired buffer in bytes. 36 // The buffer may point at the underlying memory of dst, in which case [Unmarshal] 37 // becomes a no-op. 38 // 39 // The contents of the buffer are undefined and may be non-zero. 40 func SyscallOutput(dst any, size int) Buffer { 41 if dstBuf := unsafeBackingMemory(dst); len(dstBuf) == size { 42 buf := newBuffer(dstBuf) 43 buf.size = syscallPointerOnly 44 return buf 45 } 46 47 return newBuffer(make([]byte, size)) 48 } 49 50 // CopyTo copies the buffer into dst. 51 // 52 // Returns the number of copied bytes. 53 func (b Buffer) CopyTo(dst []byte) int { 54 return copy(dst, b.unsafeBytes()) 55 } 56 57 // AppendTo appends the buffer onto dst. 58 func (b Buffer) AppendTo(dst []byte) []byte { 59 return append(dst, b.unsafeBytes()...) 60 } 61 62 // Pointer returns the location where a syscall should write. 63 func (b Buffer) Pointer() sys.Pointer { 64 // NB: This deliberately ignores b.length to support zero-copy 65 // marshaling / unmarshaling using unsafe.Pointer. 66 return sys.NewPointer(b.ptr) 67 } 68 69 // Unmarshal the buffer into the provided value. 70 func (b Buffer) Unmarshal(data any) error { 71 if b.size == syscallPointerOnly { 72 return nil 73 } 74 75 return Unmarshal(data, b.unsafeBytes()) 76 } 77 78 func (b Buffer) unsafeBytes() []byte { 79 if b.size == syscallPointerOnly { 80 return nil 81 } 82 return unsafe.Slice((*byte)(b.ptr), b.size) 83 }