-
Notifications
You must be signed in to change notification settings - Fork 2
/
probe.go
184 lines (152 loc) · 5.01 KB
/
probe.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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package tkbtf
import (
"fmt"
"github.com/cilium/ebpf/btf"
"strings"
)
// ProbeType highlights the type of the Probe.
// (https://docs.kernel.org/trace/kprobetrace.html#synopsis-of-kprobe-events)
type ProbeType uint32
const (
// ProbeTypeKProbe captures a KProbe.
ProbeTypeKProbe ProbeType = iota
// ProbeTypeKRetProbe captures a KRetProbe.
ProbeTypeKRetProbe
)
type Probe struct {
ref string
symbolName string
probeType ProbeType
duplicateFetchArgs bool
fetchArgOrderName []string
fetchArgs map[string]*fetchArg
tracingEventProbe string
tracingEventFilter string
}
// NewKProbe creates and returns new Probe of type ProbeTypeKProbe.
func NewKProbe() *Probe {
return &Probe{
probeType: ProbeTypeKProbe,
fetchArgs: make(map[string]*fetchArg),
}
}
// NewKRetProbe creates and returns new Probe of type ProbeTypeKRetProbe.
func NewKRetProbe() *Probe {
return &Probe{
probeType: ProbeTypeKRetProbe,
fetchArgs: make(map[string]*fetchArg),
}
}
// AddFetchArgs attaches the given fetchArgs to the Probe.
func (p *Probe) AddFetchArgs(args ...*fetchArg) *Probe {
// Iterate over the given fetchArgs
for _, a := range args {
// Check if the fetchArg already exists in the fetchArgs map
if _, exists := p.fetchArgs[a.name]; !exists {
// If it doesn't exist, add the fetchArg name to the fetchArgOrderName slice
p.fetchArgOrderName = append(p.fetchArgOrderName, a.name)
} else {
p.duplicateFetchArgs = true
}
// Add the fetchArg to the fetchArgs map
p.fetchArgs[a.name] = a
}
return p
}
// SetRef sets the reference name of the probe. This is useful when multiple probes are attached to the same symbol
// and an extra factor of distinguishing them is required.
func (p *Probe) SetRef(ref string) *Probe {
p.ref = ref
return p
}
// SetFilter sets a tracing event filter to the probe.
// It takes a filter string as input and returns a pointer to the probe.
// Note that this doesn't validate the supplied filter string and it up
// to the caller to check its validity.
func (p *Probe) SetFilter(filter string) *Probe {
p.tracingEventFilter = filter
return p
}
// GetSymbolName returns the symbol name of the Probe.
func (p *Probe) GetSymbolName() string {
return p.symbolName
}
// GetTracingEventProbe returns the tracing event probe string for the Probe.
func (p *Probe) GetTracingEventProbe() string {
return p.tracingEventProbe
}
// GetTracingEventFilter returns the tracing event filter of the Probe.
// It returns an empty string if no filter is set.
func (p *Probe) GetTracingEventFilter() string {
return p.tracingEventFilter
}
// GetType returns the ProbeType.
func (p *Probe) GetType() ProbeType {
return p.probeType
}
// GetID returns the ID of the Probe. The ID is the result of combining the probe
// type and the symbol name or the reference name if it is set.
func (p *Probe) GetID() string {
var id strings.Builder
switch p.probeType {
case ProbeTypeKProbe:
id.WriteString("kprobe_")
case ProbeTypeKRetProbe:
id.WriteString("kretprobe_")
}
switch {
case p.ref == "":
id.WriteString(p.symbolName)
default:
id.WriteString(p.ref)
}
return id.String()
}
// build updates the Probe with the provided symbol name and builds one by one the attached fetchArgs, respecting
// the order they were attached. It returns any error encountered during the build process.
func (p *Probe) build(symbolName string, spec btfSpec, funcType *btf.Func, regs registersResolver) error {
var probeTracing strings.Builder
if p.duplicateFetchArgs {
return ErrDuplicateFetchArgs
}
p.symbolName = symbolName
p.tracingEventProbe = ""
// Iterate over the fetch args with the order they were added
for _, argName := range p.fetchArgOrderName {
arg, ok := p.fetchArgs[argName]
if !ok {
continue
}
// Build the fetch argument
fetchArgTracingStr, err := arg.build(spec, p.probeType, funcType, regs)
if err != nil {
return err
}
if fetchArgTracingStr == "" {
return fmt.Errorf("fetch arg %s returned empty tracing event probe string", argName)
}
// string builder is not empty (contains already a fetch arg) thus add space separator
if probeTracing.Len() > 0 {
probeTracing.WriteString(" ")
}
probeTracing.WriteString(fetchArgTracingStr)
}
p.tracingEventProbe = probeTracing.String()
return nil
}