Skip to content

Commit

Permalink
link: sync PMU and tracefs error strings
Browse files Browse the repository at this point in the history
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 <timo@isovalent.com>
  • Loading branch information
ti-mo committed Jul 29, 2022
1 parent 9bd82c7 commit 375841a
Showing 1 changed file with 19 additions and 10 deletions.
29 changes: 19 additions & 10 deletions link/kprobe.go
Expand Up @@ -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:
Expand All @@ -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.
Expand All @@ -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
Expand All @@ -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.
Expand Down Expand Up @@ -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)
}
Expand All @@ -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
Expand Down

0 comments on commit 375841a

Please sign in to comment.