-
Notifications
You must be signed in to change notification settings - Fork 10
/
kprobe.go
99 lines (84 loc) · 2.92 KB
/
kprobe.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package manager
import (
"errors"
"fmt"
"os"
)
type KprobeAttachMethod = AttachMethod
const (
AttachKprobeMethodNotSet = AttachMethodNotSet
AttachKprobeWithPerfEventOpen = AttachWithPerfEventOpen
AttachKprobeWithKprobeEvents = AttachWithProbeEvents
)
func (p *Probe) prefix() string {
return tracefsPrefix(p.isReturnProbe)
}
type attachFunc func() (*tracefsLink, error)
// attachKprobe - Attaches the probe to its kprobe
func (p *Probe) attachKprobe() error {
if len(p.HookFuncName) == 0 {
return fmt.Errorf("HookFuncName, MatchFuncName or SyscallFuncName is required")
}
var eventsFunc attachFunc = p.attachWithKprobeEvents
var pmuFunc attachFunc = func() (*tracefsLink, error) {
pfd, err := perfEventOpenPMU(p.HookFuncName, 0, -1, kprobe, p.isReturnProbe, 0)
if err != nil {
return nil, err
}
return &tracefsLink{perfEventLink: newPerfEventLink(pfd), Type: kprobe}, nil
}
startFunc, fallbackFunc := pmuFunc, eventsFunc
// currently the perf event open ABI doesn't allow to specify the max active parameter
if (p.KProbeMaxActive > 0 && p.isReturnProbe) || p.KprobeAttachMethod == AttachKprobeWithKprobeEvents {
startFunc, fallbackFunc = eventsFunc, pmuFunc
}
var startErr, fallbackErr error
var tl *tracefsLink
if tl, startErr = startFunc(); startErr != nil {
if tl, fallbackErr = fallbackFunc(); fallbackErr != nil {
return errors.Join(startErr, fallbackErr)
}
}
if err := attachPerfEvent(tl.perfEventLink, p.program); err != nil {
_ = tl.Close()
return fmt.Errorf("attach %s: %w", p.ProbeIdentificationPair, err)
}
p.progLink = tl
return nil
}
// attachWithKprobeEvents attaches the kprobe using the kprobes_events ABI
func (p *Probe) attachWithKprobeEvents() (*tracefsLink, error) {
if p.kprobeHookPointNotExist {
return nil, ErrKProbeHookPointNotExist
}
args := traceFsEventArgs{
Type: kprobe,
ReturnProbe: p.isReturnProbe,
Symbol: p.HookFuncName,
UID: p.UID,
MaxActive: p.KProbeMaxActive,
AttachingPID: p.attachPID,
}
var kprobeID int
var eventName string
kprobeID, eventName, err := registerTraceFSEvent(args)
if errors.Is(err, ErrProbeIDNotExist) {
// The probe might have been loaded under a kernel generated event name. Clean up just in case.
_ = unregisterTraceFSEvent(kprobe.eventsFilename(), getKernelGeneratedEventName(p.prefix(), p.HookFuncName))
// fallback without KProbeMaxActive
args.MaxActive = 0
kprobeID, eventName, err = registerTraceFSEvent(args)
}
if err != nil {
if errors.Is(err, os.ErrNotExist) {
p.kprobeHookPointNotExist = true
}
return nil, fmt.Errorf("couldn't enable kprobe %s: %w", p.ProbeIdentificationPair, err)
}
// create perf event fd
pfd, err := perfEventOpenTracingEvent(kprobeID, -1)
if err != nil {
return nil, fmt.Errorf("couldn't open perf event fd for %s: %w", p.ProbeIdentificationPair, err)
}
return &tracefsLink{perfEventLink: newPerfEventLink(pfd), Type: kprobe, EventName: eventName}, nil
}