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