c4b089c64f7ce20176f4e6a05aae6e7e2f31263d
[lttng-modules.git] / src / probes / lttng-kprobes.c
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
20 static
21 int 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
52 static
53 int 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 */
71 static
72 int 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.type = lttng_kernel_type_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
106 error_field:
107 kfree(desc->name);
108 error_str:
109 kfree(desc);
110 return ret;
111 }
112
113 /*
114 * Create event_notifier description
115 */
116 static
117 int 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
137 error_str:
138 kfree(desc);
139 return ret;
140 }
141
142 static
143 int _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 notify 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
187 register_error:
188 kfree(lttng_kp->symbol_name);
189 name_error:
190 return ret;
191 }
192
193 int 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
212 register_error:
213 kfree(event->desc->fields);
214 kfree(event->desc->name);
215 kfree(event->desc);
216 error:
217 return ret;
218 }
219 EXPORT_SYMBOL_GPL(lttng_kprobes_register_event);
220
221 int 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
238 register_error:
239 kfree(event_notifier->desc->name);
240 kfree(event_notifier->desc);
241 error:
242 return ret;
243 }
244 EXPORT_SYMBOL_GPL(lttng_kprobes_register_event_notifier);
245
246 void lttng_kprobes_unregister_event(struct lttng_event *event)
247 {
248 unregister_kprobe(&event->u.kprobe.kp);
249 }
250 EXPORT_SYMBOL_GPL(lttng_kprobes_unregister_event);
251
252 void lttng_kprobes_unregister_event_notifier(struct lttng_event_notifier *event_notifier)
253 {
254 unregister_kprobe(&event_notifier->u.kprobe.kp);
255 }
256 EXPORT_SYMBOL_GPL(lttng_kprobes_unregister_event_notifier);
257
258 void 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 }
265 EXPORT_SYMBOL_GPL(lttng_kprobes_destroy_event_private);
266
267 void 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 }
273 EXPORT_SYMBOL_GPL(lttng_kprobes_destroy_event_notifier_private);
274
275 MODULE_LICENSE("GPL and additional rights");
276 MODULE_AUTHOR("Mathieu Desnoyers <mathieu.desnoyers@efficios.com>");
277 MODULE_DESCRIPTION("LTTng kprobes probes");
278 MODULE_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.033929 seconds and 3 git commands to generate.