marshalers.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. package ebpf
  2. import (
  3. "bytes"
  4. "encoding"
  5. "encoding/binary"
  6. "errors"
  7. "fmt"
  8. "reflect"
  9. "runtime"
  10. "sync"
  11. "unsafe"
  12. "github.com/cilium/ebpf/internal"
  13. )
  14. // marshalPtr converts an arbitrary value into a pointer suitable
  15. // to be passed to the kernel.
  16. //
  17. // As an optimization, it returns the original value if it is an
  18. // unsafe.Pointer.
  19. func marshalPtr(data interface{}, length int) (internal.Pointer, error) {
  20. if ptr, ok := data.(unsafe.Pointer); ok {
  21. return internal.NewPointer(ptr), nil
  22. }
  23. buf, err := marshalBytes(data, length)
  24. if err != nil {
  25. return internal.Pointer{}, err
  26. }
  27. return internal.NewSlicePointer(buf), nil
  28. }
  29. // marshalBytes converts an arbitrary value into a byte buffer.
  30. //
  31. // Prefer using Map.marshalKey and Map.marshalValue if possible, since
  32. // those have special cases that allow more types to be encoded.
  33. //
  34. // Returns an error if the given value isn't representable in exactly
  35. // length bytes.
  36. func marshalBytes(data interface{}, length int) (buf []byte, err error) {
  37. if data == nil {
  38. return nil, errors.New("can't marshal a nil value")
  39. }
  40. switch value := data.(type) {
  41. case encoding.BinaryMarshaler:
  42. buf, err = value.MarshalBinary()
  43. case string:
  44. buf = []byte(value)
  45. case []byte:
  46. buf = value
  47. case unsafe.Pointer:
  48. err = errors.New("can't marshal from unsafe.Pointer")
  49. case Map, *Map, Program, *Program:
  50. err = fmt.Errorf("can't marshal %T", value)
  51. default:
  52. var wr bytes.Buffer
  53. err = binary.Write(&wr, internal.NativeEndian, value)
  54. if err != nil {
  55. err = fmt.Errorf("encoding %T: %v", value, err)
  56. }
  57. buf = wr.Bytes()
  58. }
  59. if err != nil {
  60. return nil, err
  61. }
  62. if len(buf) != length {
  63. return nil, fmt.Errorf("%T doesn't marshal to %d bytes", data, length)
  64. }
  65. return buf, nil
  66. }
  67. func makeBuffer(dst interface{}, length int) (internal.Pointer, []byte) {
  68. if ptr, ok := dst.(unsafe.Pointer); ok {
  69. return internal.NewPointer(ptr), nil
  70. }
  71. buf := make([]byte, length)
  72. return internal.NewSlicePointer(buf), buf
  73. }
  74. var bytesReaderPool = sync.Pool{
  75. New: func() interface{} {
  76. return new(bytes.Reader)
  77. },
  78. }
  79. // unmarshalBytes converts a byte buffer into an arbitrary value.
  80. //
  81. // Prefer using Map.unmarshalKey and Map.unmarshalValue if possible, since
  82. // those have special cases that allow more types to be encoded.
  83. //
  84. // The common int32 and int64 types are directly handled to avoid
  85. // unnecessary heap allocations as happening in the default case.
  86. func unmarshalBytes(data interface{}, buf []byte) error {
  87. switch value := data.(type) {
  88. case unsafe.Pointer:
  89. var dst []byte
  90. // Use unsafe.Slice when we drop support for pre1.17 (https://github.com/golang/go/issues/19367)
  91. // We could opt for removing unsafe.Pointer support in the lib as well
  92. sh := (*reflect.SliceHeader)(unsafe.Pointer(&dst))
  93. sh.Data = uintptr(value)
  94. sh.Len = len(buf)
  95. sh.Cap = len(buf)
  96. copy(dst, buf)
  97. runtime.KeepAlive(value)
  98. return nil
  99. case Map, *Map, Program, *Program:
  100. return fmt.Errorf("can't unmarshal into %T", value)
  101. case encoding.BinaryUnmarshaler:
  102. return value.UnmarshalBinary(buf)
  103. case *string:
  104. *value = string(buf)
  105. return nil
  106. case *[]byte:
  107. *value = buf
  108. return nil
  109. case *int32:
  110. if len(buf) < 4 {
  111. return errors.New("int32 requires 4 bytes")
  112. }
  113. *value = int32(internal.NativeEndian.Uint32(buf))
  114. return nil
  115. case *uint32:
  116. if len(buf) < 4 {
  117. return errors.New("uint32 requires 4 bytes")
  118. }
  119. *value = internal.NativeEndian.Uint32(buf)
  120. return nil
  121. case *int64:
  122. if len(buf) < 8 {
  123. return errors.New("int64 requires 8 bytes")
  124. }
  125. *value = int64(internal.NativeEndian.Uint64(buf))
  126. return nil
  127. case *uint64:
  128. if len(buf) < 8 {
  129. return errors.New("uint64 requires 8 bytes")
  130. }
  131. *value = internal.NativeEndian.Uint64(buf)
  132. return nil
  133. case string:
  134. return errors.New("require pointer to string")
  135. case []byte:
  136. return errors.New("require pointer to []byte")
  137. default:
  138. rd := bytesReaderPool.Get().(*bytes.Reader)
  139. rd.Reset(buf)
  140. defer bytesReaderPool.Put(rd)
  141. if err := binary.Read(rd, internal.NativeEndian, value); err != nil {
  142. return fmt.Errorf("decoding %T: %v", value, err)
  143. }
  144. return nil
  145. }
  146. }
  147. // marshalPerCPUValue encodes a slice containing one value per
  148. // possible CPU into a buffer of bytes.
  149. //
  150. // Values are initialized to zero if the slice has less elements than CPUs.
  151. //
  152. // slice must have a type like []elementType.
  153. func marshalPerCPUValue(slice interface{}, elemLength int) (internal.Pointer, error) {
  154. sliceType := reflect.TypeOf(slice)
  155. if sliceType.Kind() != reflect.Slice {
  156. return internal.Pointer{}, errors.New("per-CPU value requires slice")
  157. }
  158. possibleCPUs, err := internal.PossibleCPUs()
  159. if err != nil {
  160. return internal.Pointer{}, err
  161. }
  162. sliceValue := reflect.ValueOf(slice)
  163. sliceLen := sliceValue.Len()
  164. if sliceLen > possibleCPUs {
  165. return internal.Pointer{}, fmt.Errorf("per-CPU value exceeds number of CPUs")
  166. }
  167. alignedElemLength := internal.Align(elemLength, 8)
  168. buf := make([]byte, alignedElemLength*possibleCPUs)
  169. for i := 0; i < sliceLen; i++ {
  170. elem := sliceValue.Index(i).Interface()
  171. elemBytes, err := marshalBytes(elem, elemLength)
  172. if err != nil {
  173. return internal.Pointer{}, err
  174. }
  175. offset := i * alignedElemLength
  176. copy(buf[offset:offset+elemLength], elemBytes)
  177. }
  178. return internal.NewSlicePointer(buf), nil
  179. }
  180. // unmarshalPerCPUValue decodes a buffer into a slice containing one value per
  181. // possible CPU.
  182. //
  183. // valueOut must have a type like *[]elementType
  184. func unmarshalPerCPUValue(slicePtr interface{}, elemLength int, buf []byte) error {
  185. slicePtrType := reflect.TypeOf(slicePtr)
  186. if slicePtrType.Kind() != reflect.Ptr || slicePtrType.Elem().Kind() != reflect.Slice {
  187. return fmt.Errorf("per-cpu value requires pointer to slice")
  188. }
  189. possibleCPUs, err := internal.PossibleCPUs()
  190. if err != nil {
  191. return err
  192. }
  193. sliceType := slicePtrType.Elem()
  194. slice := reflect.MakeSlice(sliceType, possibleCPUs, possibleCPUs)
  195. sliceElemType := sliceType.Elem()
  196. sliceElemIsPointer := sliceElemType.Kind() == reflect.Ptr
  197. if sliceElemIsPointer {
  198. sliceElemType = sliceElemType.Elem()
  199. }
  200. step := len(buf) / possibleCPUs
  201. if step < elemLength {
  202. return fmt.Errorf("per-cpu element length is larger than available data")
  203. }
  204. for i := 0; i < possibleCPUs; i++ {
  205. var elem interface{}
  206. if sliceElemIsPointer {
  207. newElem := reflect.New(sliceElemType)
  208. slice.Index(i).Set(newElem)
  209. elem = newElem.Interface()
  210. } else {
  211. elem = slice.Index(i).Addr().Interface()
  212. }
  213. // Make a copy, since unmarshal can hold on to itemBytes
  214. elemBytes := make([]byte, elemLength)
  215. copy(elemBytes, buf[:elemLength])
  216. err := unmarshalBytes(elem, elemBytes)
  217. if err != nil {
  218. return fmt.Errorf("cpu %d: %w", i, err)
  219. }
  220. buf = buf[step:]
  221. }
  222. reflect.ValueOf(slicePtr).Elem().Set(slice)
  223. return nil
  224. }