Refactoring: type description structures
[lttng-modules.git] / src / probes / lttng-uprobes.c
1 /* SPDX-License-Identifier: (GPL-2.0-only OR LGPL-2.1-only)
2 *
3 * probes/lttng-uprobes.c
4 *
5 * LTTng uprobes integration module.
6 *
7 * Copyright (C) 2013 Yannick Brosseau <yannick.brosseau@gmail.com>
8 * Copyright (C) 2009-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
9 *
10 */
11
12 #include <wrapper/fdtable.h>
13 #include <linux/list.h>
14 #include <linux/module.h>
15 #include <linux/namei.h>
16 #include <linux/slab.h>
17 #include <linux/uaccess.h>
18 #include <lttng/events.h>
19 #include <lttng/tracer.h>
20 #include <wrapper/irqflags.h>
21 #include <ringbuffer/frontend_types.h>
22 #include <wrapper/uprobes.h>
23 #include <wrapper/vmalloc.h>
24
25 static
26 int lttng_uprobes_event_handler_pre(struct uprobe_consumer *uc, struct pt_regs *regs)
27 {
28 struct lttng_uprobe_handler *uprobe_handler =
29 container_of(uc, struct lttng_uprobe_handler, up_consumer);
30 struct lttng_event *event = uprobe_handler->u.event;
31 struct lttng_probe_ctx lttng_probe_ctx = {
32 .event = event,
33 .interruptible = !lttng_regs_irqs_disabled(regs),
34 };
35 struct lttng_channel *chan = event->chan;
36 struct lib_ring_buffer_ctx ctx;
37 int ret;
38
39 struct {
40 unsigned long ip;
41 } payload;
42
43 if (unlikely(!LTTNG_READ_ONCE(chan->session->active)))
44 return 0;
45 if (unlikely(!LTTNG_READ_ONCE(chan->enabled)))
46 return 0;
47 if (unlikely(!LTTNG_READ_ONCE(event->enabled)))
48 return 0;
49
50 lib_ring_buffer_ctx_init(&ctx, chan->chan, &lttng_probe_ctx,
51 sizeof(payload), lttng_alignof(payload), -1);
52
53 ret = chan->ops->event_reserve(&ctx, event->id);
54 if (ret < 0)
55 return 0;
56
57 /* Event payload. */
58 payload.ip = (unsigned long)instruction_pointer(regs);
59
60 lib_ring_buffer_align_ctx(&ctx, lttng_alignof(payload));
61 chan->ops->event_write(&ctx, &payload, sizeof(payload));
62 chan->ops->event_commit(&ctx);
63 return 0;
64 }
65
66 static
67 int lttng_uprobes_event_notifier_handler_pre(struct uprobe_consumer *uc, struct pt_regs *regs)
68 {
69 struct lttng_uprobe_handler *uprobe_handler =
70 container_of(uc, struct lttng_uprobe_handler, up_consumer);
71 struct lttng_event_notifier *event_notifier = uprobe_handler->u.event_notifier;
72 struct lttng_kernel_notifier_ctx notif_ctx;
73
74 if (unlikely(!READ_ONCE(event_notifier->enabled)))
75 return 0;
76
77 notif_ctx.eval_capture = LTTNG_READ_ONCE(event_notifier->eval_capture);
78 event_notifier->send_notification(event_notifier, NULL, NULL, &notif_ctx);
79 return 0;
80 }
81
82 static const struct lttng_kernel_type_common *event_type =
83 lttng_kernel_static_type_integer_from_type(unsigned long, __BYTE_ORDER, 16);
84
85 /*
86 * Create event description.
87 */
88 static
89 int lttng_create_uprobe_event(const char *name, struct lttng_event *event)
90 {
91 const struct lttng_kernel_event_field **fieldp_array;
92 struct lttng_kernel_event_field *field;
93 struct lttng_kernel_event_desc *desc;
94 int ret;
95
96 desc = kzalloc(sizeof(*desc), GFP_KERNEL);
97 if (!desc)
98 return -ENOMEM;
99 desc->event_name = kstrdup(name, GFP_KERNEL);
100 if (!desc->event_name) {
101 ret = -ENOMEM;
102 goto error_str;
103 }
104 desc->nr_fields = 1;
105 fieldp_array = kzalloc(1 * sizeof(struct lttng_kernel_event_field *), GFP_KERNEL);
106 if (!fieldp_array) {
107 ret = -ENOMEM;
108 goto error_fieldp_array;
109 }
110 desc->fields = fieldp_array;
111 desc->fields[0] = field =
112 kzalloc(sizeof(struct lttng_kernel_event_field), GFP_KERNEL);
113 if (!field) {
114 ret = -ENOMEM;
115 goto error_field;
116 }
117 field->name = "ip";
118 field->type = event_type;
119 desc->owner = THIS_MODULE;
120 event->desc = desc;
121
122 return 0;
123
124 error_field:
125 kfree(fieldp_array);
126 error_fieldp_array:
127 kfree(desc->event_name);
128 error_str:
129 kfree(desc);
130 return ret;
131 }
132
133 /*
134 * Create event_notifier description.
135 */
136 static
137 int lttng_create_uprobe_event_notifier(const char *name, struct lttng_event_notifier *event_notifier)
138 {
139 struct lttng_kernel_event_desc *desc;
140 int ret;
141
142 desc = kzalloc(sizeof(*desc), GFP_KERNEL);
143 if (!desc)
144 return -ENOMEM;
145 desc->event_name = kstrdup(name, GFP_KERNEL);
146 if (!desc->event_name) {
147 ret = -ENOMEM;
148 goto error_str;
149 }
150
151 desc->nr_fields = 0;
152
153 desc->owner = THIS_MODULE;
154 event_notifier->desc = desc;
155
156 return 0;
157
158 error_str:
159 kfree(desc);
160 return ret;
161 }
162
163 /*
164 * Returns the inode struct from the current task and an fd. The inode is
165 * grabbed by this function and must be put once we are done with it using
166 * iput().
167 */
168 static struct inode *get_inode_from_fd(int fd)
169 {
170 struct file *file;
171 struct inode *inode;
172
173 rcu_read_lock();
174 /*
175 * Returns the file backing the given fd. Needs to be done inside an RCU
176 * critical section.
177 */
178 file = lttng_lookup_fd_rcu(fd);
179 if (file == NULL) {
180 printk(KERN_WARNING "LTTng: Cannot access file backing the fd(%d)\n", fd);
181 inode = NULL;
182 goto error;
183 }
184
185 /* Grab a reference on the inode. */
186 inode = igrab(file->f_path.dentry->d_inode);
187 if (inode == NULL)
188 printk(KERN_WARNING "LTTng: Cannot grab a reference on the inode.\n");
189 error:
190 rcu_read_unlock();
191 return inode;
192 }
193
194
195 static
196 int lttng_uprobes_add_callsite(struct lttng_uprobe *uprobe,
197 struct lttng_kernel_event_callsite __user *callsite,
198 int (*handler)(struct uprobe_consumer *self, struct pt_regs *regs),
199 void *priv_data)
200 {
201 int ret = 0;
202 struct lttng_uprobe_handler *uprobe_handler;
203
204 if (!priv_data) {
205 ret = -EINVAL;
206 goto end;
207 }
208
209 uprobe_handler = kzalloc(sizeof(struct lttng_uprobe_handler), GFP_KERNEL);
210 if (!uprobe_handler) {
211 printk(KERN_WARNING "LTTng: Error allocating uprobe_handler");
212 ret = -ENOMEM;
213 goto end;
214 }
215
216 /* Ensure the memory we just allocated don't notify page faults. */
217 wrapper_vmalloc_sync_mappings();
218
219 uprobe_handler->u.event = priv_data;
220 uprobe_handler->up_consumer.handler = handler;
221
222 ret = copy_from_user(&uprobe_handler->offset, &callsite->u.uprobe.offset, sizeof(uint64_t));
223 if (ret) {
224 goto register_error;
225 }
226
227 ret = wrapper_uprobe_register(uprobe->inode,
228 uprobe_handler->offset, &uprobe_handler->up_consumer);
229 if (ret) {
230 printk(KERN_WARNING "LTTng: Error registering probe on inode %lu "
231 "and offset 0x%llx\n", uprobe->inode->i_ino,
232 uprobe_handler->offset);
233 ret = -1;
234 goto register_error;
235 }
236
237 list_add(&uprobe_handler->node, &uprobe->head);
238
239 return ret;
240
241 register_error:
242 kfree(uprobe_handler);
243 end:
244 return ret;
245 }
246
247 int lttng_uprobes_event_add_callsite(struct lttng_event *event,
248 struct lttng_kernel_event_callsite __user *callsite)
249 {
250 return lttng_uprobes_add_callsite(&event->u.uprobe, callsite,
251 lttng_uprobes_event_handler_pre, event);
252 }
253 EXPORT_SYMBOL_GPL(lttng_uprobes_event_add_callsite);
254
255 int lttng_uprobes_event_notifier_add_callsite(struct lttng_event_notifier *event_notifier,
256 struct lttng_kernel_event_callsite __user *callsite)
257 {
258 return lttng_uprobes_add_callsite(&event_notifier->u.uprobe, callsite,
259 lttng_uprobes_event_notifier_handler_pre, event_notifier);
260 }
261 EXPORT_SYMBOL_GPL(lttng_uprobes_event_notifier_add_callsite);
262
263 static
264 int lttng_uprobes_register(struct lttng_uprobe *uprobe, int fd)
265 {
266 int ret = 0;
267 struct inode *inode;
268
269 inode = get_inode_from_fd(fd);
270 if (!inode) {
271 printk(KERN_WARNING "LTTng: Cannot get inode from fd\n");
272 ret = -EBADF;
273 goto inode_error;
274 }
275 uprobe->inode = inode;
276 INIT_LIST_HEAD(&uprobe->head);
277
278 inode_error:
279 return ret;
280 }
281
282 int lttng_uprobes_register_event(const char *name, int fd, struct lttng_event *event)
283 {
284 int ret = 0;
285
286 ret = lttng_create_uprobe_event(name, event);
287 if (ret)
288 goto error;
289
290 ret = lttng_uprobes_register(&event->u.uprobe, fd);
291 if (ret)
292 goto register_error;
293
294 return 0;
295
296 register_error:
297 kfree(event->desc->event_name);
298 kfree(event->desc);
299 error:
300 return ret;
301 }
302 EXPORT_SYMBOL_GPL(lttng_uprobes_register_event);
303
304 int lttng_uprobes_register_event_notifier(const char *name, int fd,
305 struct lttng_event_notifier *event_notifier)
306 {
307 int ret = 0;
308
309 ret = lttng_create_uprobe_event_notifier(name, event_notifier);
310 if (ret)
311 goto error;
312
313 ret = lttng_uprobes_register(&event_notifier->u.uprobe, fd);
314 if (ret)
315 goto register_error;
316
317 return 0;
318
319 register_error:
320 kfree(event_notifier->desc->event_name);
321 kfree(event_notifier->desc);
322 error:
323 return ret;
324 }
325 EXPORT_SYMBOL_GPL(lttng_uprobes_register_event_notifier);
326
327 static
328 void lttng_uprobes_unregister(struct inode *inode, struct list_head *head)
329 {
330 struct lttng_uprobe_handler *iter, *tmp;
331
332 /*
333 * Iterate over the list of handler, remove each handler from the list
334 * and free the struct.
335 */
336 list_for_each_entry_safe(iter, tmp, head, node) {
337 wrapper_uprobe_unregister(inode, iter->offset, &iter->up_consumer);
338 list_del(&iter->node);
339 kfree(iter);
340 }
341
342 }
343
344 void lttng_uprobes_unregister_event(struct lttng_event *event)
345 {
346 lttng_uprobes_unregister(event->u.uprobe.inode, &event->u.uprobe.head);
347 }
348 EXPORT_SYMBOL_GPL(lttng_uprobes_unregister_event);
349
350 void lttng_uprobes_unregister_event_notifier(struct lttng_event_notifier *event_notifier)
351 {
352 lttng_uprobes_unregister(event_notifier->u.uprobe.inode, &event_notifier->u.uprobe.head);
353 }
354 EXPORT_SYMBOL_GPL(lttng_uprobes_unregister_event_notifier);
355
356 void lttng_uprobes_destroy_event_private(struct lttng_event *event)
357 {
358 iput(event->u.uprobe.inode);
359 kfree(event->desc->fields[0]);
360 kfree(event->desc->fields);
361 kfree(event->desc->event_name);
362 kfree(event->desc);
363 }
364 EXPORT_SYMBOL_GPL(lttng_uprobes_destroy_event_private);
365
366 void lttng_uprobes_destroy_event_notifier_private(struct lttng_event_notifier *event_notifier)
367 {
368 iput(event_notifier->u.uprobe.inode);
369 kfree(event_notifier->desc->event_name);
370 kfree(event_notifier->desc);
371 }
372 EXPORT_SYMBOL_GPL(lttng_uprobes_destroy_event_notifier_private);
373
374 MODULE_LICENSE("GPL and additional rights");
375 MODULE_AUTHOR("Yannick Brosseau");
376 MODULE_DESCRIPTION("Linux Trace Toolkit Uprobes Support");
This page took 0.036128 seconds and 4 git commands to generate.