From 4c54df0c818d20fb2471bd454b8281488658c600 Mon Sep 17 00:00:00 2001 From: Nikolay Sivko Date: Mon, 15 Jul 2024 12:16:44 +0300 Subject: [PATCH] python: search for `pthread_cond_timedwait` in both libc.so and libpthread.so --- ebpftracer/python.go | 74 +++++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/ebpftracer/python.go b/ebpftracer/python.go index 3d061ca..227c1bf 100644 --- a/ebpftracer/python.go +++ b/ebpftracer/python.go @@ -8,6 +8,7 @@ import ( "github.com/cilium/ebpf/link" "github.com/coroot/coroot-node-agent/proc" + "golang.org/x/exp/maps" "k8s.io/klog/v2" ) @@ -17,68 +18,69 @@ var ( ) func (t *Tracer) AttachPythonThreadLockProbes(pid uint32) []link.Link { - exePath := getPthreadLib(pid) - if exePath == "" { - return nil - } - - log := func(msg string, err error) { + log := func(libPath, msg string, err error) { if err != nil { for _, s := range []string{"no such file or directory", "no such process", "permission denied"} { if strings.HasSuffix(err.Error(), s) { return } } - klog.ErrorfDepth(1, "pid=%d lib=%s: %s: %s", pid, exePath, msg, err) + klog.ErrorfDepth(1, "pid=%d lib=%s: %s: %s", pid, libPath, msg, err) return } - klog.InfofDepth(1, "pid=%d lib=%s: %s", pid, exePath, msg) - } - exe, err := link.OpenExecutable(exePath) - if err != nil { - log("failed to open executable", err) - return nil + klog.InfofDepth(1, "pid=%d lib=%s: %s", pid, libPath, msg) } - var links []link.Link - uprobe, err := exe.Uprobe("pthread_cond_timedwait", t.uprobes["pthread_cond_timedwait_enter"], nil) - if err != nil { - log("failed to attach uprobe", err) - return nil + + var ( + lastErr error + links []link.Link + libPath string + ) + + for _, libPath = range getPthreadLibs(pid) { + exe, err := link.OpenExecutable(libPath) + if err != nil { + log(libPath, "failed to open executable", err) + return nil + } + var uprobe, uretprobe link.Link + uprobe, lastErr = exe.Uprobe("pthread_cond_timedwait", t.uprobes["pthread_cond_timedwait_enter"], nil) + if lastErr != nil { + continue + } + links = append(links, uprobe) + uretprobe, lastErr = exe.Uretprobe("pthread_cond_timedwait", t.uprobes["pthread_cond_timedwait_exit"], nil) + if lastErr != nil { + continue + } + links = append(links, uretprobe) + log(libPath, "python uprobes attached", nil) + break } - links = append(links, uprobe) - uretprobe, err := exe.Uretprobe("pthread_cond_timedwait", t.uprobes["pthread_cond_timedwait_exit"], nil) - if err != nil { - log("failed to attach uretprobe", err) - return nil + if lastErr != nil { + log(libPath, "failed to attach uprobe", lastErr) } - links = append(links, uretprobe) - log("python uprobes attached", nil) return links } -func getPthreadLib(pid uint32) string { +func getPthreadLibs(pid uint32) []string { f, err := os.Open(proc.Path(pid, "maps")) if err != nil { - return "" + return nil } defer f.Close() scanner := bufio.NewScanner(f) scanner.Split(bufio.ScanLines) - libc := "" + libs := map[string]bool{} for scanner.Scan() { parts := strings.Fields(scanner.Text()) if len(parts) <= 5 { continue } libPath := parts[5] - switch { - case libcRegexp.MatchString(libPath): - libc = proc.Path(pid, "root", libPath) - case muslRegexp.MatchString(libPath): - return proc.Path(pid, "root", libPath) - case strings.Contains(libPath, "libpthread"): - return proc.Path(pid, "root", libPath) + if libcRegexp.MatchString(libPath) || muslRegexp.MatchString(libPath) || strings.Contains(libPath, "libpthread") { + libs[proc.Path(pid, "root", libPath)] = true } } - return libc + return maps.Keys(libs) }