|
|
@@ -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)
|
|
|
}
|