offset.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. package tracer
  2. import (
  3. "debug/dwarf"
  4. "debug/elf"
  5. "errors"
  6. "fmt"
  7. "github.com/cilium/ebpf"
  8. "github.com/coroot/coroot-node-agent/utils"
  9. . "github.com/coroot/coroot-node-agent/utils/modelse"
  10. "github.com/coroot/coroot-node-agent/utils/try"
  11. klog "github.com/sirupsen/logrus"
  12. "io"
  13. "net"
  14. "strings"
  15. )
  16. const (
  17. offsetInferServerAddr = "127.0.0.1"
  18. offsetInferServerPort = 54583
  19. bufferSize = 16
  20. )
  21. type ID struct {
  22. // ModPath is the module path containing the struct field package.
  23. //
  24. // If set to "std", the struct field belongs to the standard Go library.
  25. ModPath string
  26. // PkgPath package import path containing the struct field.
  27. PkgPath string
  28. // Struct is the name of the struct containing the field.
  29. Struct string
  30. // Field is the field name.
  31. Field string
  32. }
  33. func kernelOffsetInferServer(listener net.Listener) error {
  34. klog.Info("[eBPF Kernel Adapt] kernel_offset_infer_server started.")
  35. //cpuOnlineCount := runtime.NumCPU()
  36. try.Go(func() {
  37. for {
  38. conn, err := listener.Accept()
  39. if err != nil {
  40. klog.Errorf("[eBPF Kernel Adapt] Fail to accept client request: %v", err)
  41. return
  42. }
  43. //go handleConnection(conn)
  44. try.GoParams(handleConnection, utils.CatchFn, conn)
  45. }
  46. }, utils.CatchFn)
  47. return nil
  48. }
  49. func handleConnection(conn net.Conn) {
  50. defer conn.Close()
  51. buffer := make([]byte, bufferSize)
  52. for {
  53. n, err := conn.Read(buffer)
  54. if err != nil {
  55. if err == io.EOF {
  56. klog.Errorf("[eBPF Kernel Adapt] client connection closed: %v", err)
  57. return
  58. }
  59. klog.Errorf("[eBPF Kernel Adapt] Error reading from connection: %v", err)
  60. return
  61. }
  62. //if n == 0 {
  63. // *clientCount++
  64. // break
  65. //}
  66. request := strings.TrimSpace(string(buffer[:n]))
  67. klog.Infof("[eBPF Kernel Adapt] Request received: %v", request)
  68. if request == "hello" {
  69. _, err := conn.Write([]byte("OK"))
  70. if err != nil {
  71. klog.Errorf("[eBPF Kernel Adapt] Error writing response: %v", err)
  72. break
  73. }
  74. }
  75. }
  76. }
  77. func kernelOffsetInferClient() error {
  78. conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", offsetInferServerAddr, offsetInferServerPort))
  79. if err != nil {
  80. return fmt.Errorf("failed to connect to server: %v", err)
  81. }
  82. defer conn.Close()
  83. klog.Infoln("[eBPF Kernel Adapt] kernel_offset_infer_client started.")
  84. request := "hello"
  85. _, err = conn.Write([]byte(request))
  86. if err != nil {
  87. return fmt.Errorf("failed to send request to server: %v", err)
  88. }
  89. buffer := make([]byte, bufferSize)
  90. for {
  91. n, err := conn.Read(buffer)
  92. if err != nil {
  93. klog.Errorf("[eBPF Kernel Adapt] Error reading from connection: %v", err)
  94. break
  95. }
  96. if n == 0 {
  97. break
  98. }
  99. response := strings.TrimSpace(string(buffer[:n]))
  100. klog.Infof("[eBPF Kernel Adapt] Response received: %v", response)
  101. if response == "OK" {
  102. break
  103. }
  104. }
  105. klog.Infoln("[eBPF Kernel Adapt] kernel_offset_infer_client finished.")
  106. return nil
  107. }
  108. func NewID(mod, pkg, strct, field string) ID {
  109. return ID{ModPath: mod, PkgPath: pkg, Struct: strct, Field: field}
  110. }
  111. func gotoEntry(r *dwarf.Reader, tag dwarf.Tag, name string) bool {
  112. _, err := findEntry(r, tag, name)
  113. return err == nil
  114. }
  115. // findEntry returns the DWARF entry with a tag equal to name read from r. An
  116. // error is returned if the entry cannot be found.
  117. func findEntry(r *dwarf.Reader, tag dwarf.Tag, name string) (*dwarf.Entry, error) {
  118. for {
  119. entry, err := r.Next()
  120. if err == io.EOF || entry == nil {
  121. break
  122. }
  123. if entry.Tag == tag {
  124. if f, ok := entryField(entry, dwarf.AttrName); ok {
  125. if name == f.Val.(string) {
  126. return entry, nil
  127. }
  128. }
  129. }
  130. }
  131. return nil, errors.New("not found")
  132. }
  133. // entryField returns the DWARF field from DWARF entry e that has the passed
  134. // DWARF attribute a.
  135. func entryField(e *dwarf.Entry, a dwarf.Attr) (dwarf.Field, bool) {
  136. for _, f := range e.Field {
  137. if f.Attr == a {
  138. return f, true
  139. }
  140. }
  141. return dwarf.Field{}, false
  142. }
  143. func GetOffset(id ID, path string) (uint64, bool) {
  144. strct := fmt.Sprintf("%s.%s", id.PkgPath, id.Struct)
  145. elfF, err := elf.Open(path)
  146. if err != nil {
  147. klog.Error(err)
  148. return 0, false
  149. }
  150. defer elfF.Close()
  151. data, err := elfF.DWARF()
  152. //fmt.Println(err)
  153. r := data.Reader()
  154. if !gotoEntry(r, dwarf.TagStructType, strct) {
  155. return 0, false
  156. }
  157. e, err := findEntry(r, dwarf.TagMember, id.Field)
  158. if err != nil {
  159. klog.Error(err)
  160. return 0, false
  161. }
  162. f, ok := entryField(e, dwarf.AttrDataMemberLoc)
  163. if !ok {
  164. return 0, false
  165. }
  166. return uint64(f.Val.(int64)), true
  167. }
  168. func UpdateProcInfoToMap(collection *ebpf.Collection, pid uint32, proc any) (int, error) {
  169. return bpf_table_set_value(collection, MAP_PROC_INFO_MAP_NAME, pid, proc)
  170. }
  171. func DelProcInfoFromMap(collection *ebpf.Collection, pid uint32) (int, error) {
  172. return bpf_table_delete_key(collection, MAP_PROC_INFO_MAP_NAME, pid)
  173. }