python.go 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. package ebpftracer
  2. import (
  3. "bufio"
  4. "os"
  5. "regexp"
  6. "strings"
  7. "github.com/cilium/ebpf/link"
  8. "github.com/coroot/coroot-node-agent/proc"
  9. "k8s.io/klog/v2"
  10. )
  11. var (
  12. libcRegexp = regexp.MustCompile(`libc[\.-]`)
  13. muslRegexp = regexp.MustCompile(`musl[\.-]`)
  14. )
  15. func (t *Tracer) AttachPythonThreadLockProbes(pid uint32) []link.Link {
  16. exePath := getPthreadLib(pid)
  17. if exePath == "" {
  18. return nil
  19. }
  20. log := func(msg string, err error) {
  21. if err != nil {
  22. for _, s := range []string{"no such file or directory", "no such process", "permission denied"} {
  23. if strings.HasSuffix(err.Error(), s) {
  24. return
  25. }
  26. }
  27. klog.ErrorfDepth(1, "pid=%d lib=%s: %s: %s", pid, exePath, msg, err)
  28. return
  29. }
  30. klog.InfofDepth(1, "pid=%d lib=%s: %s", pid, exePath, msg)
  31. }
  32. exe, err := link.OpenExecutable(exePath)
  33. if err != nil {
  34. log("failed to open executable", err)
  35. return nil
  36. }
  37. var links []link.Link
  38. uprobe, err := exe.Uprobe("pthread_cond_timedwait", t.uprobes["pthread_cond_timedwait_enter"], nil)
  39. if err != nil {
  40. log("failed to attach uprobe", err)
  41. return nil
  42. }
  43. links = append(links, uprobe)
  44. uretprobe, err := exe.Uretprobe("pthread_cond_timedwait", t.uprobes["pthread_cond_timedwait_exit"], nil)
  45. if err != nil {
  46. log("failed to attach uretprobe", err)
  47. return nil
  48. }
  49. links = append(links, uretprobe)
  50. log("python uprobes attached", nil)
  51. return links
  52. }
  53. func getPthreadLib(pid uint32) string {
  54. f, err := os.Open(proc.Path(pid, "maps"))
  55. if err != nil {
  56. return ""
  57. }
  58. defer f.Close()
  59. scanner := bufio.NewScanner(f)
  60. scanner.Split(bufio.ScanLines)
  61. libc := ""
  62. for scanner.Scan() {
  63. parts := strings.Fields(scanner.Text())
  64. if len(parts) <= 5 {
  65. continue
  66. }
  67. libPath := parts[5]
  68. switch {
  69. case libcRegexp.MatchString(libPath):
  70. libc = proc.Path(pid, "root", libPath)
  71. case muslRegexp.MatchString(libPath):
  72. return proc.Path(pid, "root", libPath)
  73. case strings.Contains(libPath, "libpthread"):
  74. return proc.Path(pid, "root", libPath)
  75. }
  76. }
  77. return libc
  78. }