kretprobes: rename "return" to "exit"
[lttng-modules.git] / src / probes / lttng-kprobes.c
... / ...
CommitLineData
1/* SPDX-License-Identifier: (GPL-2.0-only or LGPL-2.1-only)
2 *
3 * probes/lttng-kprobes.c
4 *
5 * LTTng kprobes integration module.
6 *
7 * Copyright (C) 2009-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
8 */
9
10#include <linux/module.h>
11#include <linux/kprobes.h>
12#include <linux/slab.h>
13#include <lttng/events.h>
14#include <ringbuffer/frontend_types.h>
15#include <wrapper/vmalloc.h>
16#include <wrapper/irqflags.h>
17#include <lttng/tracer.h>
18#include <blacklist/kprobes.h>
19
20static
21int lttng_kprobes_event_handler_pre(struct kprobe *p, struct pt_regs *regs)
22{
23 struct lttng_event *event =
24 container_of(p, struct lttng_event, u.kprobe.kp);
25 struct lttng_probe_ctx lttng_probe_ctx = {
26 .event = event,
27 .interruptible = !lttng_regs_irqs_disabled(regs),
28 };
29 struct lttng_channel *chan = event->chan;
30 struct lib_ring_buffer_ctx ctx;
31 int ret;
32 unsigned long data = (unsigned long) p->addr;
33
34 if (unlikely(!LTTNG_READ_ONCE(chan->session->active)))
35 return 0;
36 if (unlikely(!LTTNG_READ_ONCE(chan->enabled)))
37 return 0;
38 if (unlikely(!LTTNG_READ_ONCE(event->enabled)))
39 return 0;
40
41 lib_ring_buffer_ctx_init(&ctx, chan->chan, &lttng_probe_ctx, sizeof(data),
42 lttng_alignof(data), -1);
43 ret = chan->ops->event_reserve(&ctx, event->id);
44 if (ret < 0)
45 return 0;
46 lib_ring_buffer_align_ctx(&ctx, lttng_alignof(data));
47 chan->ops->event_write(&ctx, &data, sizeof(data));
48 chan->ops->event_commit(&ctx);
49 return 0;
50}
51
52static
53int lttng_kprobes_event_notifier_handler_pre(struct kprobe *p, struct pt_regs *regs)
54{
55 struct lttng_event_notifier *event_notifier =
56 container_of(p, struct lttng_event_notifier, u.kprobe.kp);
57 struct lttng_kernel_notifier_ctx notif_ctx;
58
59 if (unlikely(!READ_ONCE(event_notifier->enabled)))
60 return 0;
61
62 notif_ctx.eval_capture = LTTNG_READ_ONCE(event_notifier->eval_capture);
63 event_notifier->send_notification(event_notifier, NULL, NULL, &notif_ctx);
64
65 return 0;
66}
67
68/*
69 * Create event description
70 */
71static
72int lttng_create_kprobe_event(const char *name, struct lttng_event *event)
73{
74 struct lttng_event_field *field;
75 struct lttng_event_desc *desc;
76 int ret;
77
78 desc = kzalloc(sizeof(*event->desc), GFP_KERNEL);
79 if (!desc)
80 return -ENOMEM;
81 desc->name = kstrdup(name, GFP_KERNEL);
82 if (!desc->name) {
83 ret = -ENOMEM;
84 goto error_str;
85 }
86 desc->nr_fields = 1;
87 desc->fields = field =
88 kzalloc(1 * sizeof(struct lttng_event_field), GFP_KERNEL);
89 if (!field) {
90 ret = -ENOMEM;
91 goto error_field;
92 }
93 field->name = "ip";
94 field->type.atype = atype_integer;
95 field->type.u.integer.size = sizeof(unsigned long) * CHAR_BIT;
96 field->type.u.integer.alignment = lttng_alignof(unsigned long) * CHAR_BIT;
97 field->type.u.integer.signedness = lttng_is_signed_type(unsigned long);
98 field->type.u.integer.reverse_byte_order = 0;
99 field->type.u.integer.base = 16;
100 field->type.u.integer.encoding = lttng_encode_none;
101 desc->owner = THIS_MODULE;
102 event->desc = desc;
103
104 return 0;
105
106error_field:
107 kfree(desc->name);
108error_str:
109 kfree(desc);
110 return ret;
111}
112
113/*
114 * Create event_notifier description
115 */
116static
117int lttng_create_kprobe_event_notifier(const char *name, struct lttng_event_notifier *event_notifier)
118{
119 struct lttng_event_desc *desc;
120 int ret;
121
122 desc = kzalloc(sizeof(*event_notifier->desc), GFP_KERNEL);
123 if (!desc)
124 return -ENOMEM;
125 desc->name = kstrdup(name, GFP_KERNEL);
126 if (!desc->name) {
127 ret = -ENOMEM;
128 goto error_str;
129 }
130 desc->nr_fields = 0;
131
132 desc->owner = THIS_MODULE;
133 event_notifier->desc = desc;
134
135 return 0;
136
137error_str:
138 kfree(desc);
139 return ret;
140}
141
142static
143int _lttng_kprobes_register(const char *symbol_name,
144 uint64_t offset,
145 uint64_t addr,
146 struct lttng_kprobe *lttng_kp,
147 kprobe_pre_handler_t pre_handler)
148{
149 int ret;
150
151 /* Kprobes expects a NULL symbol name if unused */
152 if (symbol_name[0] == '\0')
153 symbol_name = NULL;
154
155 memset(&lttng_kp->kp, 0, sizeof(lttng_kp->kp));
156 lttng_kp->kp.pre_handler = pre_handler;
157
158 if (symbol_name) {
159 lttng_kp->symbol_name =
160 kzalloc(LTTNG_KERNEL_SYM_NAME_LEN * sizeof(char),
161 GFP_KERNEL);
162 if (!lttng_kp->symbol_name) {
163 ret = -ENOMEM;
164 goto name_error;
165 }
166 memcpy(lttng_kp->symbol_name, symbol_name,
167 LTTNG_KERNEL_SYM_NAME_LEN * sizeof(char));
168 lttng_kp->kp.symbol_name = lttng_kp->symbol_name;
169 }
170
171 lttng_kp->kp.offset = offset;
172 lttng_kp->kp.addr = (void *) (unsigned long) addr;
173
174 /*
175 * Ensure the memory we just allocated don't event_notifier page faults.
176 * Well.. kprobes itself puts the page fault handler on the blacklist,
177 * but we can never be too careful.
178 */
179 wrapper_vmalloc_sync_mappings();
180
181 ret = register_kprobe(&lttng_kp->kp);
182 if (ret)
183 goto register_error;
184
185 return 0;
186
187register_error:
188 kfree(lttng_kp->symbol_name);
189name_error:
190 return ret;
191}
192
193int lttng_kprobes_register_event(const char *name,
194 const char *symbol_name,
195 uint64_t offset,
196 uint64_t addr,
197 struct lttng_event *event)
198{
199 int ret;
200
201 ret = lttng_create_kprobe_event(name, event);
202 if (ret)
203 goto error;
204
205 ret = _lttng_kprobes_register(symbol_name, offset, addr,
206 &event->u.kprobe, lttng_kprobes_event_handler_pre);
207 if (ret)
208 goto register_error;
209
210 return 0;
211
212register_error:
213 kfree(event->desc->fields);
214 kfree(event->desc->name);
215 kfree(event->desc);
216error:
217 return ret;
218}
219EXPORT_SYMBOL_GPL(lttng_kprobes_register_event);
220
221int lttng_kprobes_register_event_notifier(const char *symbol_name,
222 uint64_t offset,
223 uint64_t addr,
224 struct lttng_event_notifier *event_notifier)
225{
226 int ret;
227 ret = lttng_create_kprobe_event_notifier(symbol_name, event_notifier);
228 if (ret)
229 goto error;
230
231 ret = _lttng_kprobes_register(symbol_name, offset, addr,
232 &event_notifier->u.kprobe, lttng_kprobes_event_notifier_handler_pre);
233 if (ret)
234 goto register_error;
235
236 return 0;
237
238register_error:
239 kfree(event_notifier->desc->name);
240 kfree(event_notifier->desc);
241error:
242 return ret;
243}
244EXPORT_SYMBOL_GPL(lttng_kprobes_register_event_notifier);
245
246void lttng_kprobes_unregister_event(struct lttng_event *event)
247{
248 unregister_kprobe(&event->u.kprobe.kp);
249}
250EXPORT_SYMBOL_GPL(lttng_kprobes_unregister_event);
251
252void lttng_kprobes_unregister_event_notifier(struct lttng_event_notifier *event_notifier)
253{
254 unregister_kprobe(&event_notifier->u.kprobe.kp);
255}
256EXPORT_SYMBOL_GPL(lttng_kprobes_unregister_event_notifier);
257
258void lttng_kprobes_destroy_event_private(struct lttng_event *event)
259{
260 kfree(event->u.kprobe.symbol_name);
261 kfree(event->desc->fields);
262 kfree(event->desc->name);
263 kfree(event->desc);
264}
265EXPORT_SYMBOL_GPL(lttng_kprobes_destroy_event_private);
266
267void lttng_kprobes_destroy_event_notifier_private(struct lttng_event_notifier *event_notifier)
268{
269 kfree(event_notifier->u.kprobe.symbol_name);
270 kfree(event_notifier->desc->name);
271 kfree(event_notifier->desc);
272}
273EXPORT_SYMBOL_GPL(lttng_kprobes_destroy_event_notifier_private);
274
275MODULE_LICENSE("GPL and additional rights");
276MODULE_AUTHOR("Mathieu Desnoyers <mathieu.desnoyers@efficios.com>");
277MODULE_DESCRIPTION("LTTng kprobes probes");
278MODULE_VERSION(__stringify(LTTNG_MODULES_MAJOR_VERSION) "."
279 __stringify(LTTNG_MODULES_MINOR_VERSION) "."
280 __stringify(LTTNG_MODULES_PATCHLEVEL_VERSION)
281 LTTNG_MODULES_EXTRAVERSION);
This page took 0.022457 seconds and 4 git commands to generate.