Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

link/kprobe: specify symbol offset #618

Merged
merged 2 commits into from Apr 12, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
22 changes: 21 additions & 1 deletion link/kprobe.go
Expand Up @@ -50,6 +50,10 @@ type KprobeOptions struct {
//
// Needs kernel 5.15+.
Cookie uint64
// Offset of the kprobe relative to the traced symbol.
// Can be used to insert kprobes at arbitrary offsets in kernel functions,
// e.g. in places where functions have been inlined.
Offset uint64
}

const (
Expand Down Expand Up @@ -163,6 +167,7 @@ func kprobe(symbol string, prog *ebpf.Program, opts *KprobeOptions, ret bool) (*

if opts != nil {
args.cookie = opts.Cookie
args.offset = opts.Offset
}

// Use kprobe PMU if the kernel has it available.
Expand Down Expand Up @@ -235,8 +240,12 @@ func pmuProbe(typ probeType, args probeArgs) (*perfEvent, error) {
}

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.
Size: unix.PERF_ATTR_SIZE_VER1,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to https://classes.engineering.wustl.edu/cse522/man-pages/perf_event_open.2.pdf VER1 is available from 2.6 so this doesn't change the minimum required version.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we don't set .size , the kernel will use the PERF_ATTR_SIZE_VER0 64B as default. The config2 will be not included in perf_event_attr.

the kernel code:
static int perf_copy_attr(struct perf_event_attr __user *uattr, struct perf_event_attr attr)
.....
/
ABI compatibility quirk: */
if (!size)
size = PERF_ATTR_SIZE_VER0; // config2 is not in VER0

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Offset == 0 is ok, it is an option for linux kernel.
https://www.kernel.org/doc/html/latest/trace/kprobetrace.html

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I should've been clearer, using ver1 LGTM.

Type: uint32(et), // PMU event type read from sysfs
Ext1: uint64(uintptr(sp)), // Kernel symbol to trace
Ext2: args.offset, // Kernel symbol offset
Config: config, // Retprobe flag
}
case uprobeType:
Expand Down Expand Up @@ -392,7 +401,7 @@ func createTraceFSProbeEvent(typ probeType, args probeArgs) error {
// subsampling or rate limiting logic can be more accurately implemented in
// the eBPF program itself.
// See Documentation/kprobes.txt for more details.
pe = fmt.Sprintf("%s:%s/%s %s", probePrefix(args.ret), args.group, sanitizedSymbol(args.symbol), args.symbol)
pe = fmt.Sprintf("%s:%s/%s %s", probePrefix(args.ret), args.group, sanitizedSymbol(args.symbol), kprobeToken(args))
case uprobeType:
// The uprobe_events syntax is as follows:
// p[:[GRP/]EVENT] PATH:OFFSET [FETCHARGS] : Set a probe
Expand Down Expand Up @@ -496,3 +505,14 @@ func kretprobeBit() (uint64, error) {
})
return kprobeRetprobeBit.value, kprobeRetprobeBit.err
}

// kprobeToken creates the SYM[+offs] token for the tracefs api.
func kprobeToken(args probeArgs) string {
po := args.symbol

if args.offset != 0 {
po += fmt.Sprintf("+%#x", args.offset)
}

return po
}
22 changes: 22 additions & 0 deletions link/kprobe_test.go
Expand Up @@ -2,6 +2,7 @@ package link

import (
"errors"
"fmt"
"os"
"testing"

Expand Down Expand Up @@ -405,3 +406,24 @@ func TestKprobeCookie(t *testing.T) {
}
k.Close()
}

func TestKprobeToken(t *testing.T) {
tests := []struct {
args probeArgs
expected string
}{
{probeArgs{symbol: "symbol"}, "symbol"},
{probeArgs{symbol: "symbol", offset: 1}, "symbol+0x1"},
{probeArgs{symbol: "symbol", offset: 65535}, "symbol+0xffff"},
{probeArgs{symbol: "symbol", offset: 65536}, "symbol+0x10000"},
}

for i, tt := range tests {
t.Run(fmt.Sprint(i), func(t *testing.T) {
po := kprobeToken(tt.args)
if tt.expected != po {
t.Errorf("Expected symbol+offset to be '%s', got '%s'", tt.expected, po)
}
})
}
}