marshalers.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. package ebpf
  2. import (
  3. "bytes"
  4. "encoding"
  5. "encoding/binary"
  6. "reflect"
  7. "runtime"
  8. "unsafe"
  9. "github.com/cilium/ebpf/internal"
  10. "github.com/pkg/errors"
  11. )
  12. func marshalPtr(data interface{}, length int) (syscallPtr, error) {
  13. if ptr, ok := data.(unsafe.Pointer); ok {
  14. return newPtr(ptr), nil
  15. }
  16. buf, err := marshalBytes(data, length)
  17. if err != nil {
  18. return syscallPtr{}, err
  19. }
  20. return newPtr(unsafe.Pointer(&buf[0])), nil
  21. }
  22. func marshalBytes(data interface{}, length int) (buf []byte, err error) {
  23. switch value := data.(type) {
  24. case encoding.BinaryMarshaler:
  25. buf, err = value.MarshalBinary()
  26. case string:
  27. buf = []byte(value)
  28. case []byte:
  29. buf = value
  30. case unsafe.Pointer:
  31. err = errors.New("can't marshal from unsafe.Pointer")
  32. default:
  33. var wr bytes.Buffer
  34. err = binary.Write(&wr, internal.NativeEndian, value)
  35. err = errors.Wrapf(err, "encoding %T", value)
  36. buf = wr.Bytes()
  37. }
  38. if err != nil {
  39. return nil, err
  40. }
  41. if len(buf) != length {
  42. return nil, errors.Errorf("%T doesn't marshal to %d bytes", data, length)
  43. }
  44. return buf, nil
  45. }
  46. func makeBuffer(dst interface{}, length int) (syscallPtr, []byte) {
  47. if ptr, ok := dst.(unsafe.Pointer); ok {
  48. return newPtr(ptr), nil
  49. }
  50. buf := make([]byte, length)
  51. return newPtr(unsafe.Pointer(&buf[0])), buf
  52. }
  53. func unmarshalBytes(data interface{}, buf []byte) error {
  54. switch value := data.(type) {
  55. case unsafe.Pointer:
  56. sh := &reflect.SliceHeader{
  57. Data: uintptr(value),
  58. Len: len(buf),
  59. Cap: len(buf),
  60. }
  61. dst := *(*[]byte)(unsafe.Pointer(sh))
  62. copy(dst, buf)
  63. runtime.KeepAlive(value)
  64. return nil
  65. case encoding.BinaryUnmarshaler:
  66. return value.UnmarshalBinary(buf)
  67. case *string:
  68. *value = string(buf)
  69. return nil
  70. case *[]byte:
  71. *value = buf
  72. return nil
  73. case string:
  74. return errors.New("require pointer to string")
  75. case []byte:
  76. return errors.New("require pointer to []byte")
  77. default:
  78. rd := bytes.NewReader(buf)
  79. err := binary.Read(rd, internal.NativeEndian, value)
  80. return errors.Wrapf(err, "decoding %T", value)
  81. }
  82. }
  83. // marshalPerCPUValue encodes a slice containing one value per
  84. // possible CPU into a buffer of bytes.
  85. //
  86. // Values are initialized to zero if the slice has less elements than CPUs.
  87. //
  88. // slice must have a type like []elementType.
  89. func marshalPerCPUValue(slice interface{}, elemLength int) (syscallPtr, error) {
  90. sliceType := reflect.TypeOf(slice)
  91. if sliceType.Kind() != reflect.Slice {
  92. return syscallPtr{}, errors.New("per-CPU value requires slice")
  93. }
  94. possibleCPUs, err := internal.PossibleCPUs()
  95. if err != nil {
  96. return syscallPtr{}, err
  97. }
  98. sliceValue := reflect.ValueOf(slice)
  99. sliceLen := sliceValue.Len()
  100. if sliceLen > possibleCPUs {
  101. return syscallPtr{}, errors.Errorf("per-CPU value exceeds number of CPUs")
  102. }
  103. alignedElemLength := align(elemLength, 8)
  104. buf := make([]byte, alignedElemLength*possibleCPUs)
  105. for i := 0; i < sliceLen; i++ {
  106. elem := sliceValue.Index(i).Interface()
  107. elemBytes, err := marshalBytes(elem, elemLength)
  108. if err != nil {
  109. return syscallPtr{}, err
  110. }
  111. offset := i * alignedElemLength
  112. copy(buf[offset:offset+elemLength], elemBytes)
  113. }
  114. return newPtr(unsafe.Pointer(&buf[0])), nil
  115. }
  116. // unmarshalPerCPUValue decodes a buffer into a slice containing one value per
  117. // possible CPU.
  118. //
  119. // valueOut must have a type like *[]elementType
  120. func unmarshalPerCPUValue(slicePtr interface{}, elemLength int, buf []byte) error {
  121. slicePtrType := reflect.TypeOf(slicePtr)
  122. if slicePtrType.Kind() != reflect.Ptr || slicePtrType.Elem().Kind() != reflect.Slice {
  123. return errors.Errorf("per-cpu value requires pointer to slice")
  124. }
  125. possibleCPUs, err := internal.PossibleCPUs()
  126. if err != nil {
  127. return err
  128. }
  129. sliceType := slicePtrType.Elem()
  130. slice := reflect.MakeSlice(sliceType, possibleCPUs, possibleCPUs)
  131. sliceElemType := sliceType.Elem()
  132. sliceElemIsPointer := sliceElemType.Kind() == reflect.Ptr
  133. if sliceElemIsPointer {
  134. sliceElemType = sliceElemType.Elem()
  135. }
  136. step := len(buf) / possibleCPUs
  137. if step < elemLength {
  138. return errors.Errorf("per-cpu element length is larger than available data")
  139. }
  140. for i := 0; i < possibleCPUs; i++ {
  141. var elem interface{}
  142. if sliceElemIsPointer {
  143. newElem := reflect.New(sliceElemType)
  144. slice.Index(i).Set(newElem)
  145. elem = newElem.Interface()
  146. } else {
  147. elem = slice.Index(i).Addr().Interface()
  148. }
  149. // Make a copy, since unmarshal can hold on to itemBytes
  150. elemBytes := make([]byte, elemLength)
  151. copy(elemBytes, buf[:elemLength])
  152. err := unmarshalBytes(elem, elemBytes)
  153. if err != nil {
  154. return errors.Wrapf(err, "cpu %d", i)
  155. }
  156. buf = buf[step:]
  157. }
  158. reflect.ValueOf(slicePtr).Elem().Set(slice)
  159. return nil
  160. }
  161. func align(n, alignment int) int {
  162. return (int(n) + alignment - 1) / alignment * alignment
  163. }