Refactoring: type description structures
[lttng-modules.git] / src / probes / lttng-kretprobes.c
1 /* SPDX-License-Identifier: (GPL-2.0-only or LGPL-2.1-only)
2 *
3 * probes/lttng-kretprobes.c
4 *
5 * LTTng kretprobes integration module.
6 *
7 * Copyright (C) 2009-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
8 */
9
10 #include <linux/module.h>
11 #include <wrapper/kprobes.h>
12 #include <linux/slab.h>
13 #include <linux/kref.h>
14 #include <lttng/events.h>
15 #include <ringbuffer/frontend_types.h>
16 #include <wrapper/vmalloc.h>
17 #include <wrapper/irqflags.h>
18 #include <lttng/tracer.h>
19 #include <blacklist/kprobes.h>
20
21 enum lttng_kretprobe_type {
22 EVENT_ENTRY = 0,
23 EVENT_EXIT = 1,
24 };
25
26 struct lttng_krp {
27 struct kretprobe krp;
28 struct lttng_event *event[2]; /* ENTRY and EXIT */
29 struct kref kref_register;
30 struct kref kref_alloc;
31 };
32
33 static
34 int _lttng_kretprobes_handler(struct kretprobe_instance *krpi,
35 struct pt_regs *regs,
36 enum lttng_kretprobe_type type)
37 {
38 struct lttng_krp *lttng_krp =
39 container_of(lttng_get_kretprobe(krpi), struct lttng_krp, krp);
40 struct lttng_event *event =
41 lttng_krp->event[type];
42 struct lttng_probe_ctx lttng_probe_ctx = {
43 .event = event,
44 .interruptible = !lttng_regs_irqs_disabled(regs),
45 };
46 struct lttng_channel *chan = event->chan;
47 struct lib_ring_buffer_ctx ctx;
48 int ret;
49 struct {
50 unsigned long ip;
51 unsigned long parent_ip;
52 } payload;
53
54 if (unlikely(!LTTNG_READ_ONCE(chan->session->active)))
55 return 0;
56 if (unlikely(!LTTNG_READ_ONCE(chan->enabled)))
57 return 0;
58 if (unlikely(!LTTNG_READ_ONCE(event->enabled)))
59 return 0;
60
61 payload.ip = (unsigned long) lttng_get_kretprobe(krpi)->kp.addr;
62 payload.parent_ip = (unsigned long) krpi->ret_addr;
63
64 lib_ring_buffer_ctx_init(&ctx, chan->chan, &lttng_probe_ctx, sizeof(payload),
65 lttng_alignof(payload), -1);
66 ret = chan->ops->event_reserve(&ctx, event->id);
67 if (ret < 0)
68 return 0;
69 lib_ring_buffer_align_ctx(&ctx, lttng_alignof(payload));
70 chan->ops->event_write(&ctx, &payload, sizeof(payload));
71 chan->ops->event_commit(&ctx);
72 return 0;
73 }
74
75 static
76 int lttng_kretprobes_handler_entry(struct kretprobe_instance *krpi,
77 struct pt_regs *regs)
78 {
79 return _lttng_kretprobes_handler(krpi, regs, EVENT_ENTRY);
80 }
81
82 static
83 int lttng_kretprobes_handler_exit(struct kretprobe_instance *krpi,
84 struct pt_regs *regs)
85 {
86 return _lttng_kretprobes_handler(krpi, regs, EVENT_EXIT);
87 }
88
89 static const struct lttng_kernel_type_common *event_type =
90 lttng_kernel_static_type_integer_from_type(unsigned long, __BYTE_ORDER, 16);
91
92 /*
93 * Create event description
94 */
95 static
96 int lttng_create_kprobe_event(const char *name, struct lttng_event *event,
97 enum lttng_kretprobe_type type)
98 {
99 const struct lttng_kernel_event_field **fieldp_array;
100 struct lttng_kernel_event_field *field;
101 struct lttng_kernel_event_desc *desc;
102 char *alloc_name;
103 size_t name_len;
104 const char *suffix = NULL;
105 int ret;
106
107 desc = kzalloc(sizeof(*desc), GFP_KERNEL);
108 if (!desc)
109 return -ENOMEM;
110 name_len = strlen(name);
111 switch (type) {
112 case EVENT_ENTRY:
113 suffix = "_entry";
114 break;
115 case EVENT_EXIT:
116 suffix = "_exit";
117 break;
118 }
119 name_len += strlen(suffix);
120 alloc_name = kmalloc(name_len + 1, GFP_KERNEL);
121 if (!alloc_name) {
122 ret = -ENOMEM;
123 goto error_str;
124 }
125 strcpy(alloc_name, name);
126 strcat(alloc_name, suffix);
127 desc->event_name = alloc_name;
128 desc->nr_fields = 2;
129 fieldp_array = kzalloc(desc->nr_fields * sizeof(struct lttng_kernel_event_field *), GFP_KERNEL);
130 if (!fieldp_array) {
131 ret = -ENOMEM;
132 goto error_fieldp_array;
133 }
134 desc->fields = fieldp_array;
135
136 field = kzalloc(sizeof(struct lttng_kernel_event_field), GFP_KERNEL);
137 if (!field) {
138 ret = -ENOMEM;
139 goto error_field0;
140 }
141 field->name = "ip";
142 field->type = event_type;
143 desc->fields[0] = field;
144
145 field = kzalloc(sizeof(struct lttng_kernel_event_field), GFP_KERNEL);
146 if (!field) {
147 ret = -ENOMEM;
148 goto error_field1;
149 }
150 field->name = "parent_ip";
151 field->type = event_type;
152 desc->fields[1] = field;
153
154 desc->owner = THIS_MODULE;
155 event->desc = desc;
156
157 return 0;
158
159 error_field1:
160 kfree(desc->fields[0]);
161 error_field0:
162 kfree(fieldp_array);
163 error_fieldp_array:
164 kfree(desc->event_name);
165 error_str:
166 kfree(desc);
167 return ret;
168 }
169
170 int lttng_kretprobes_register(const char *name,
171 const char *symbol_name,
172 uint64_t offset,
173 uint64_t addr,
174 struct lttng_event *event_entry,
175 struct lttng_event *event_exit)
176 {
177 int ret;
178 struct lttng_krp *lttng_krp;
179
180 /* Kprobes expects a NULL symbol name if unused */
181 if (symbol_name[0] == '\0')
182 symbol_name = NULL;
183
184 ret = lttng_create_kprobe_event(name, event_entry, EVENT_ENTRY);
185 if (ret)
186 goto error;
187 ret = lttng_create_kprobe_event(name, event_exit, EVENT_EXIT);
188 if (ret)
189 goto event_exit_error;
190 lttng_krp = kzalloc(sizeof(*lttng_krp), GFP_KERNEL);
191 if (!lttng_krp)
192 goto krp_error;
193 lttng_krp->krp.entry_handler = lttng_kretprobes_handler_entry;
194 lttng_krp->krp.handler = lttng_kretprobes_handler_exit;
195 if (symbol_name) {
196 char *alloc_symbol;
197
198 alloc_symbol = kstrdup(symbol_name, GFP_KERNEL);
199 if (!alloc_symbol) {
200 ret = -ENOMEM;
201 goto name_error;
202 }
203 lttng_krp->krp.kp.symbol_name =
204 alloc_symbol;
205 event_entry->u.kretprobe.symbol_name =
206 alloc_symbol;
207 event_exit->u.kretprobe.symbol_name =
208 alloc_symbol;
209 }
210 lttng_krp->krp.kp.offset = offset;
211 lttng_krp->krp.kp.addr = (void *) (unsigned long) addr;
212
213 /* Allow probe handler to find event structures */
214 lttng_krp->event[EVENT_ENTRY] = event_entry;
215 lttng_krp->event[EVENT_EXIT] = event_exit;
216 event_entry->u.kretprobe.lttng_krp = lttng_krp;
217 event_exit->u.kretprobe.lttng_krp = lttng_krp;
218
219 /*
220 * Both events must be unregistered before the kretprobe is
221 * unregistered. Same for memory allocation.
222 */
223 kref_init(&lttng_krp->kref_alloc);
224 kref_get(&lttng_krp->kref_alloc); /* inc refcount to 2, no overflow. */
225 kref_init(&lttng_krp->kref_register);
226 kref_get(&lttng_krp->kref_register); /* inc refcount to 2, no overflow. */
227
228 /*
229 * Ensure the memory we just allocated don't trigger page faults.
230 * Well.. kprobes itself puts the page fault handler on the blacklist,
231 * but we can never be too careful.
232 */
233 wrapper_vmalloc_sync_mappings();
234
235 ret = register_kretprobe(&lttng_krp->krp);
236 if (ret)
237 goto register_error;
238 return 0;
239
240 register_error:
241 kfree(lttng_krp->krp.kp.symbol_name);
242 name_error:
243 kfree(lttng_krp);
244 krp_error:
245 kfree(event_exit->desc->fields[0]);
246 kfree(event_exit->desc->fields[1]);
247 kfree(event_exit->desc->fields);
248 kfree(event_exit->desc->event_name);
249 kfree(event_exit->desc);
250 event_exit_error:
251 kfree(event_entry->desc->fields[0]);
252 kfree(event_entry->desc->fields[1]);
253 kfree(event_entry->desc->fields);
254 kfree(event_entry->desc->event_name);
255 kfree(event_entry->desc);
256 error:
257 return ret;
258 }
259 EXPORT_SYMBOL_GPL(lttng_kretprobes_register);
260
261 static
262 void _lttng_kretprobes_unregister_release(struct kref *kref)
263 {
264 struct lttng_krp *lttng_krp =
265 container_of(kref, struct lttng_krp, kref_register);
266 unregister_kretprobe(&lttng_krp->krp);
267 }
268
269 void lttng_kretprobes_unregister(struct lttng_event *event)
270 {
271 kref_put(&event->u.kretprobe.lttng_krp->kref_register,
272 _lttng_kretprobes_unregister_release);
273 }
274 EXPORT_SYMBOL_GPL(lttng_kretprobes_unregister);
275
276 static
277 void _lttng_kretprobes_release(struct kref *kref)
278 {
279 struct lttng_krp *lttng_krp =
280 container_of(kref, struct lttng_krp, kref_alloc);
281 kfree(lttng_krp->krp.kp.symbol_name);
282 }
283
284 void lttng_kretprobes_destroy_private(struct lttng_event *event)
285 {
286 kfree(event->desc->fields[0]);
287 kfree(event->desc->fields[1]);
288 kfree(event->desc->fields);
289 kfree(event->desc->event_name);
290 kfree(event->desc);
291 kref_put(&event->u.kretprobe.lttng_krp->kref_alloc,
292 _lttng_kretprobes_release);
293 }
294 EXPORT_SYMBOL_GPL(lttng_kretprobes_destroy_private);
295
296 int lttng_kretprobes_event_enable_state(struct lttng_event *event,
297 int enable)
298 {
299 struct lttng_event *event_exit;
300 struct lttng_krp *lttng_krp;
301
302 if (event->instrumentation != LTTNG_KERNEL_KRETPROBE) {
303 return -EINVAL;
304 }
305 if (event->enabled == enable) {
306 return -EBUSY;
307 }
308 lttng_krp = event->u.kretprobe.lttng_krp;
309 event_exit = lttng_krp->event[EVENT_EXIT];
310 WRITE_ONCE(event->enabled, enable);
311 WRITE_ONCE(event_exit->enabled, enable);
312 return 0;
313 }
314 EXPORT_SYMBOL_GPL(lttng_kretprobes_event_enable_state);
315
316 MODULE_LICENSE("GPL and additional rights");
317 MODULE_AUTHOR("Mathieu Desnoyers <mathieu.desnoyers@efficios.com>");
318 MODULE_DESCRIPTION("LTTng kretprobes probes");
319 MODULE_VERSION(__stringify(LTTNG_MODULES_MAJOR_VERSION) "."
320 __stringify(LTTNG_MODULES_MINOR_VERSION) "."
321 __stringify(LTTNG_MODULES_PATCHLEVEL_VERSION)
322 LTTNG_MODULES_EXTRAVERSION);
This page took 0.034905 seconds and 4 git commands to generate.