From 39ee31d8c5d6b16e558a409a0035ac247809580e Mon Sep 17 00:00:00 2001 From: Timo Beckers Date: Thu, 28 Jul 2022 11:10:19 +0200 Subject: [PATCH] link: sync PMU and tracefs error strings The tracefs probes have used a 'token' to represent their ksym:offset tuples for some time, but PMUs take those values as separate fields in the syscall. This commit harmonizes the two, making errors more consistent across both APIs. Also makes sure the token is included in all errors, regardless of the type. Signed-off-by: Timo Beckers --- link/kprobe.go | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/link/kprobe.go b/link/kprobe.go index c30d0a3f6..d1574d2f0 100644 --- a/link/kprobe.go +++ b/link/kprobe.go @@ -253,8 +253,9 @@ func pmuProbe(typ probeType, args probeArgs) (*perfEvent, error) { } var ( - attr unix.PerfEventAttr - sp unsafe.Pointer + attr unix.PerfEventAttr + sp unsafe.Pointer + token string ) switch typ { case kprobeType: @@ -264,6 +265,8 @@ func pmuProbe(typ probeType, args probeArgs) (*perfEvent, error) { return nil, err } + token = kprobeToken(args) + attr = unix.PerfEventAttr{ // The minimum size required for PMU kprobes is PERF_ATTR_SIZE_VER1, // since it added the config2 (Ext2) field. Use Ext2 as probe_offset. @@ -283,6 +286,8 @@ func pmuProbe(typ probeType, args probeArgs) (*perfEvent, error) { config |= args.refCtrOffset << uprobeRefCtrOffsetShift } + token = uprobeToken(args) + attr = unix.PerfEventAttr{ // The minimum size required for PMU uprobes is PERF_ATTR_SIZE_VER1, // since it added the config2 (Ext2) field. The Size field controls the @@ -302,26 +307,27 @@ func pmuProbe(typ probeType, args probeArgs) (*perfEvent, error) { // return -EINVAL. Return ErrNotSupported to allow falling back to tracefs. // https://github.com/torvalds/linux/blob/94710cac0ef4/kernel/trace/trace_kprobe.c#L340-L343 if errors.Is(err, unix.EINVAL) && strings.Contains(args.symbol, ".") { - return nil, fmt.Errorf("symbol '%s+%#x': older kernels don't accept dots: %w", args.symbol, args.offset, ErrNotSupported) + return nil, fmt.Errorf("token %s: older kernels don't accept dots: %w", token, ErrNotSupported) } // Since commit 97c753e62e6c, ENOENT is correctly returned instead of EINVAL // when trying to create a retprobe for a missing symbol. if errors.Is(err, os.ErrNotExist) { - return nil, fmt.Errorf("symbol '%s+%#x' not found: %w", args.symbol, args.offset, err) + return nil, fmt.Errorf("token %s: not found: %w", token, err) } // Since commit ab105a4fb894, EILSEQ is returned when a kprobe sym+offset is resolved // to an invalid insn boundary. The exact conditions that trigger this error are // arch specific however. if errors.Is(err, unix.EILSEQ) { - return nil, fmt.Errorf("symbol '%s+%#x' not found (bad insn boundary): %w", args.symbol, args.offset, os.ErrNotExist) + return nil, fmt.Errorf("token %s: bad insn boundary: %w", token, os.ErrNotExist) } // Since at least commit cb9a19fe4aa51, ENOTSUPP is returned // when attempting to set a uprobe on a trap instruction. if errors.Is(err, sys.ENOTSUPP) { - return nil, fmt.Errorf("failed setting uprobe on offset %#x (possible trap insn): %w", args.offset, err) + return nil, fmt.Errorf("token %s: failed setting uprobe on offset %#x (possible trap insn): %w", token, args.offset, err) } + if err != nil { - return nil, fmt.Errorf("opening perf event: %w", err) + return nil, fmt.Errorf("token %s: opening perf event: %w", token, err) } // Ensure the string pointer is not collected before PerfEventOpen returns. @@ -457,13 +463,15 @@ func createTraceFSProbeEvent(typ probeType, args probeArgs) error { pe = fmt.Sprintf("%s:%s/%s %s", probePrefix(args.ret), args.group, args.symbol, token) } _, err = f.WriteString(pe) + // Since commit 97c753e62e6c, ENOENT is correctly returned instead of EINVAL // when trying to create a retprobe for a missing symbol. if errors.Is(err, os.ErrNotExist) { return fmt.Errorf("token %s: not found: %w", token, err) } - // Since commit ab105a4fb894, -EILSEQ is returned when a kprobe sym+offset is resolved - // to an invalid insn boundary. + // Since commit ab105a4fb894, EILSEQ is returned when a kprobe sym+offset is resolved + // to an invalid insn boundary. The exact conditions that trigger this error are + // arch specific however. if errors.Is(err, syscall.EILSEQ) { return fmt.Errorf("token %s: bad insn boundary: %w", token, os.ErrNotExist) } @@ -472,8 +480,9 @@ func createTraceFSProbeEvent(typ probeType, args probeArgs) error { if errors.Is(err, syscall.ERANGE) { return fmt.Errorf("token %s: offset too big: %w", token, os.ErrNotExist) } + if err != nil { - return fmt.Errorf("writing '%s' to '%s': %w", pe, typ.EventsPath(), err) + return fmt.Errorf("token %s: writing '%s': %w", token, pe, err) } return nil