Refactoring: type description structures
[lttng-modules.git] / src / probes / lttng-kretprobes.c
CommitLineData
b7cdc182 1/* SPDX-License-Identifier: (GPL-2.0-only or LGPL-2.1-only)
9f36eaed
MJ
2 *
3 * probes/lttng-kretprobes.c
7371f44c
MD
4 *
5 * LTTng kretprobes integration module.
6 *
886d51a3 7 * Copyright (C) 2009-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
7371f44c
MD
8 */
9
10#include <linux/module.h>
08726907 11#include <wrapper/kprobes.h>
7371f44c
MD
12#include <linux/slab.h>
13#include <linux/kref.h>
2df37e95 14#include <lttng/events.h>
24591303 15#include <ringbuffer/frontend_types.h>
156a3977
MD
16#include <wrapper/vmalloc.h>
17#include <wrapper/irqflags.h>
2df37e95 18#include <lttng/tracer.h>
caa068b5 19#include <blacklist/kprobes.h>
7371f44c
MD
20
21enum lttng_kretprobe_type {
1b6cc48a
MD
22 EVENT_ENTRY = 0,
23 EVENT_EXIT = 1,
7371f44c
MD
24};
25
26struct lttng_krp {
27 struct kretprobe krp;
1b6cc48a 28 struct lttng_event *event[2]; /* ENTRY and EXIT */
7371f44c
MD
29 struct kref kref_register;
30 struct kref kref_alloc;
31};
32
33static
34int _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 =
08726907 39 container_of(lttng_get_kretprobe(krpi), struct lttng_krp, krp);
a90917c3 40 struct lttng_event *event =
7371f44c 41 lttng_krp->event[type];
79150a49
JD
42 struct lttng_probe_ctx lttng_probe_ctx = {
43 .event = event,
ccecf3fb 44 .interruptible = !lttng_regs_irqs_disabled(regs),
79150a49 45 };
a90917c3 46 struct lttng_channel *chan = event->chan;
7371f44c
MD
47 struct lib_ring_buffer_ctx ctx;
48 int ret;
49 struct {
50 unsigned long ip;
51 unsigned long parent_ip;
52 } payload;
53
585e5dcc 54 if (unlikely(!LTTNG_READ_ONCE(chan->session->active)))
7371f44c 55 return 0;
585e5dcc 56 if (unlikely(!LTTNG_READ_ONCE(chan->enabled)))
7371f44c 57 return 0;
585e5dcc 58 if (unlikely(!LTTNG_READ_ONCE(event->enabled)))
7371f44c
MD
59 return 0;
60
08726907 61 payload.ip = (unsigned long) lttng_get_kretprobe(krpi)->kp.addr;
7371f44c
MD
62 payload.parent_ip = (unsigned long) krpi->ret_addr;
63
79150a49 64 lib_ring_buffer_ctx_init(&ctx, chan->chan, &lttng_probe_ctx, sizeof(payload),
a90917c3 65 lttng_alignof(payload), -1);
7371f44c
MD
66 ret = chan->ops->event_reserve(&ctx, event->id);
67 if (ret < 0)
68 return 0;
a90917c3 69 lib_ring_buffer_align_ctx(&ctx, lttng_alignof(payload));
7371f44c
MD
70 chan->ops->event_write(&ctx, &payload, sizeof(payload));
71 chan->ops->event_commit(&ctx);
72 return 0;
73}
74
75static
76int 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
82static
1b6cc48a
MD
83int lttng_kretprobes_handler_exit(struct kretprobe_instance *krpi,
84 struct pt_regs *regs)
7371f44c 85{
1b6cc48a 86 return _lttng_kretprobes_handler(krpi, regs, EVENT_EXIT);
7371f44c
MD
87}
88
437d5aa5
MD
89static const struct lttng_kernel_type_common *event_type =
90 lttng_kernel_static_type_integer_from_type(unsigned long, __BYTE_ORDER, 16);
91
7371f44c
MD
92/*
93 * Create event description
94 */
95static
a90917c3 96int lttng_create_kprobe_event(const char *name, struct lttng_event *event,
7371f44c
MD
97 enum lttng_kretprobe_type type)
98{
437d5aa5
MD
99 const struct lttng_kernel_event_field **fieldp_array;
100 struct lttng_kernel_event_field *field;
101 struct lttng_kernel_event_desc *desc;
7371f44c
MD
102 char *alloc_name;
103 size_t name_len;
104 const char *suffix = NULL;
437d5aa5 105 int ret;
7371f44c 106
437d5aa5 107 desc = kzalloc(sizeof(*desc), GFP_KERNEL);
7371f44c
MD
108 if (!desc)
109 return -ENOMEM;
110 name_len = strlen(name);
111 switch (type) {
112 case EVENT_ENTRY:
113 suffix = "_entry";
114 break;
1b6cc48a
MD
115 case EVENT_EXIT:
116 suffix = "_exit";
7371f44c
MD
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);
437d5aa5 127 desc->event_name = alloc_name;
7371f44c 128 desc->nr_fields = 2;
437d5aa5
MD
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) {
7371f44c 138 ret = -ENOMEM;
437d5aa5 139 goto error_field0;
7371f44c 140 }
437d5aa5
MD
141 field->name = "ip";
142 field->type = event_type;
143 desc->fields[0] = field;
7371f44c 144
437d5aa5
MD
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;
7371f44c
MD
153
154 desc->owner = THIS_MODULE;
155 event->desc = desc;
156
157 return 0;
158
437d5aa5
MD
159error_field1:
160 kfree(desc->fields[0]);
161error_field0:
162 kfree(fieldp_array);
163error_fieldp_array:
164 kfree(desc->event_name);
7371f44c
MD
165error_str:
166 kfree(desc);
167 return ret;
168}
169
170int lttng_kretprobes_register(const char *name,
171 const char *symbol_name,
172 uint64_t offset,
173 uint64_t addr,
a90917c3 174 struct lttng_event *event_entry,
1b6cc48a 175 struct lttng_event *event_exit)
7371f44c
MD
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;
1b6cc48a 187 ret = lttng_create_kprobe_event(name, event_exit, EVENT_EXIT);
7371f44c 188 if (ret)
1b6cc48a 189 goto event_exit_error;
7371f44c
MD
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;
1b6cc48a 194 lttng_krp->krp.handler = lttng_kretprobes_handler_exit;
7371f44c
MD
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;
1b6cc48a 207 event_exit->u.kretprobe.symbol_name =
7371f44c
MD
208 alloc_symbol;
209 }
210 lttng_krp->krp.kp.offset = offset;
b2c4e8fb 211 lttng_krp->krp.kp.addr = (void *) (unsigned long) addr;
7371f44c
MD
212
213 /* Allow probe handler to find event structures */
214 lttng_krp->event[EVENT_ENTRY] = event_entry;
1b6cc48a 215 lttng_krp->event[EVENT_EXIT] = event_exit;
7371f44c 216 event_entry->u.kretprobe.lttng_krp = lttng_krp;
1b6cc48a 217 event_exit->u.kretprobe.lttng_krp = lttng_krp;
7371f44c
MD
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);
9c1f4643 224 kref_get(&lttng_krp->kref_alloc); /* inc refcount to 2, no overflow. */
7371f44c 225 kref_init(&lttng_krp->kref_register);
9c1f4643 226 kref_get(&lttng_krp->kref_register); /* inc refcount to 2, no overflow. */
7371f44c
MD
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 */
263b6c88 233 wrapper_vmalloc_sync_mappings();
7371f44c
MD
234
235 ret = register_kretprobe(&lttng_krp->krp);
236 if (ret)
237 goto register_error;
238 return 0;
239
240register_error:
241 kfree(lttng_krp->krp.kp.symbol_name);
242name_error:
243 kfree(lttng_krp);
244krp_error:
437d5aa5
MD
245 kfree(event_exit->desc->fields[0]);
246 kfree(event_exit->desc->fields[1]);
1b6cc48a 247 kfree(event_exit->desc->fields);
437d5aa5 248 kfree(event_exit->desc->event_name);
1b6cc48a
MD
249 kfree(event_exit->desc);
250event_exit_error:
437d5aa5
MD
251 kfree(event_entry->desc->fields[0]);
252 kfree(event_entry->desc->fields[1]);
7371f44c 253 kfree(event_entry->desc->fields);
437d5aa5 254 kfree(event_entry->desc->event_name);
7371f44c
MD
255 kfree(event_entry->desc);
256error:
257 return ret;
258}
259EXPORT_SYMBOL_GPL(lttng_kretprobes_register);
260
261static
262void _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
a90917c3 269void lttng_kretprobes_unregister(struct lttng_event *event)
7371f44c
MD
270{
271 kref_put(&event->u.kretprobe.lttng_krp->kref_register,
272 _lttng_kretprobes_unregister_release);
273}
274EXPORT_SYMBOL_GPL(lttng_kretprobes_unregister);
275
276static
277void _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
a90917c3 284void lttng_kretprobes_destroy_private(struct lttng_event *event)
7371f44c 285{
437d5aa5
MD
286 kfree(event->desc->fields[0]);
287 kfree(event->desc->fields[1]);
7371f44c 288 kfree(event->desc->fields);
437d5aa5 289 kfree(event->desc->event_name);
7371f44c
MD
290 kfree(event->desc);
291 kref_put(&event->u.kretprobe.lttng_krp->kref_alloc,
292 _lttng_kretprobes_release);
293}
294EXPORT_SYMBOL_GPL(lttng_kretprobes_destroy_private);
295
a0493bef
MD
296int lttng_kretprobes_event_enable_state(struct lttng_event *event,
297 int enable)
298{
1b6cc48a 299 struct lttng_event *event_exit;
a0493bef
MD
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;
1b6cc48a 309 event_exit = lttng_krp->event[EVENT_EXIT];
a8f2d0c7 310 WRITE_ONCE(event->enabled, enable);
1b6cc48a 311 WRITE_ONCE(event_exit->enabled, enable);
a0493bef
MD
312 return 0;
313}
314EXPORT_SYMBOL_GPL(lttng_kretprobes_event_enable_state);
315
7371f44c 316MODULE_LICENSE("GPL and additional rights");
1c124020
MJ
317MODULE_AUTHOR("Mathieu Desnoyers <mathieu.desnoyers@efficios.com>");
318MODULE_DESCRIPTION("LTTng kretprobes probes");
13ab8b0a
MD
319MODULE_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.061018 seconds and 4 git commands to generate.