Cleanup: move to kernel style SPDX license identifiers
[deliverable/lttng-modules.git] / probes / lttng-ftrace.c
... / ...
CommitLineData
1/* SPDX-License-Identifier: (GPL-2.0 or LGPL-2.1)
2 *
3 * probes/lttng-ftrace.c
4 *
5 * LTTng function tracer integration module.
6 *
7 * Copyright (C) 2009-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
8 */
9
10/*
11 * Ftrace function tracer does not seem to provide synchronization between probe
12 * teardown and callback execution. Therefore, we make this module permanently
13 * loaded (unloadable).
14 *
15 * TODO: Move to register_ftrace_function() (which is exported for
16 * modules) for Linux >= 3.0. It is faster (only enables the selected
17 * functions), and will stay there.
18 */
19
20#include <linux/module.h>
21#include <linux/ftrace.h>
22#include <linux/slab.h>
23#include <lttng-events.h>
24#include <wrapper/ringbuffer/frontend_types.h>
25#include <wrapper/ftrace.h>
26#include <wrapper/vmalloc.h>
27#include <lttng-tracer.h>
28
29#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0))
30static
31void lttng_ftrace_handler(unsigned long ip, unsigned long parent_ip,
32 struct trace_array *tr, struct ftrace_probe_ops *ops,
33 void *data)
34{
35 struct lttng_event *event = data;
36 struct lttng_probe_ctx lttng_probe_ctx = {
37 .event = event,
38 .interruptible = !irqs_disabled(),
39 };
40 struct lttng_channel *chan = event->chan;
41 struct lib_ring_buffer_ctx ctx;
42 struct {
43 unsigned long ip;
44 unsigned long parent_ip;
45 } payload;
46 int ret;
47
48 if (unlikely(!READ_ONCE(chan->session->active)))
49 return;
50 if (unlikely(!READ_ONCE(chan->enabled)))
51 return;
52 if (unlikely(!READ_ONCE(event->enabled)))
53 return;
54
55 lib_ring_buffer_ctx_init(&ctx, chan->chan, &lttng_probe_ctx,
56 sizeof(payload), lttng_alignof(payload), -1);
57 ret = chan->ops->event_reserve(&ctx, event->id);
58 if (ret < 0)
59 return;
60 payload.ip = ip;
61 payload.parent_ip = parent_ip;
62 lib_ring_buffer_align_ctx(&ctx, lttng_alignof(payload));
63 chan->ops->event_write(&ctx, &payload, sizeof(payload));
64 chan->ops->event_commit(&ctx);
65 return;
66}
67#else
68static
69void lttng_ftrace_handler(unsigned long ip, unsigned long parent_ip, void **data)
70{
71 struct lttng_event *event = *data;
72 struct lttng_probe_ctx lttng_probe_ctx = {
73 .event = event,
74 .interruptible = !irqs_disabled(),
75 };
76 struct lttng_channel *chan = event->chan;
77 struct lib_ring_buffer_ctx ctx;
78 struct {
79 unsigned long ip;
80 unsigned long parent_ip;
81 } payload;
82 int ret;
83
84 if (unlikely(!READ_ONCE(chan->session->active)))
85 return;
86 if (unlikely(!READ_ONCE(chan->enabled)))
87 return;
88 if (unlikely(!READ_ONCE(event->enabled)))
89 return;
90
91 lib_ring_buffer_ctx_init(&ctx, chan->chan, &lttng_probe_ctx,
92 sizeof(payload), lttng_alignof(payload), -1);
93 ret = chan->ops->event_reserve(&ctx, event->id);
94 if (ret < 0)
95 return;
96 payload.ip = ip;
97 payload.parent_ip = parent_ip;
98 lib_ring_buffer_align_ctx(&ctx, lttng_alignof(payload));
99 chan->ops->event_write(&ctx, &payload, sizeof(payload));
100 chan->ops->event_commit(&ctx);
101 return;
102}
103#endif
104
105/*
106 * Create event description
107 */
108static
109int lttng_create_ftrace_event(const char *name, struct lttng_event *event)
110{
111 struct lttng_event_field *fields;
112 struct lttng_event_desc *desc;
113 int ret;
114
115 desc = kzalloc(sizeof(*event->desc), GFP_KERNEL);
116 if (!desc)
117 return -ENOMEM;
118 desc->name = kstrdup(name, GFP_KERNEL);
119 if (!desc->name) {
120 ret = -ENOMEM;
121 goto error_str;
122 }
123 desc->nr_fields = 2;
124 desc->fields = fields =
125 kzalloc(2 * sizeof(struct lttng_event_field), GFP_KERNEL);
126 if (!desc->fields) {
127 ret = -ENOMEM;
128 goto error_fields;
129 }
130 fields[0].name = "ip";
131 fields[0].type.atype = atype_integer;
132 fields[0].type.u.basic.integer.size = sizeof(unsigned long) * CHAR_BIT;
133 fields[0].type.u.basic.integer.alignment = lttng_alignof(unsigned long) * CHAR_BIT;
134 fields[0].type.u.basic.integer.signedness = lttng_is_signed_type(unsigned long);
135 fields[0].type.u.basic.integer.reverse_byte_order = 0;
136 fields[0].type.u.basic.integer.base = 16;
137 fields[0].type.u.basic.integer.encoding = lttng_encode_none;
138
139 fields[1].name = "parent_ip";
140 fields[1].type.atype = atype_integer;
141 fields[1].type.u.basic.integer.size = sizeof(unsigned long) * CHAR_BIT;
142 fields[1].type.u.basic.integer.alignment = lttng_alignof(unsigned long) * CHAR_BIT;
143 fields[1].type.u.basic.integer.signedness = lttng_is_signed_type(unsigned long);
144 fields[1].type.u.basic.integer.reverse_byte_order = 0;
145 fields[1].type.u.basic.integer.base = 16;
146 fields[1].type.u.basic.integer.encoding = lttng_encode_none;
147
148 desc->owner = THIS_MODULE;
149 event->desc = desc;
150
151 return 0;
152
153error_fields:
154 kfree(desc->name);
155error_str:
156 kfree(desc);
157 return ret;
158}
159
160static
161struct ftrace_probe_ops lttng_ftrace_ops = {
162 .func = lttng_ftrace_handler,
163};
164
165int lttng_ftrace_register(const char *name,
166 const char *symbol_name,
167 struct lttng_event *event)
168{
169 int ret;
170
171 ret = lttng_create_ftrace_event(name, event);
172 if (ret)
173 goto error;
174
175 event->u.ftrace.symbol_name = kstrdup(symbol_name, GFP_KERNEL);
176 if (!event->u.ftrace.symbol_name)
177 goto name_error;
178
179 /* Ensure the memory we just allocated don't trigger page faults */
180 wrapper_vmalloc_sync_all();
181
182 ret = wrapper_register_ftrace_function_probe(event->u.ftrace.symbol_name,
183 &lttng_ftrace_ops, event);
184 if (ret < 0)
185 goto register_error;
186 return 0;
187
188register_error:
189 kfree(event->u.ftrace.symbol_name);
190name_error:
191 kfree(event->desc->name);
192 kfree(event->desc);
193error:
194 return ret;
195}
196EXPORT_SYMBOL_GPL(lttng_ftrace_register);
197
198void lttng_ftrace_unregister(struct lttng_event *event)
199{
200 wrapper_unregister_ftrace_function_probe(event->u.ftrace.symbol_name,
201 &lttng_ftrace_ops, event);
202}
203EXPORT_SYMBOL_GPL(lttng_ftrace_unregister);
204
205void lttng_ftrace_destroy_private(struct lttng_event *event)
206{
207 kfree(event->u.ftrace.symbol_name);
208 kfree(event->desc->fields);
209 kfree(event->desc->name);
210 kfree(event->desc);
211}
212EXPORT_SYMBOL_GPL(lttng_ftrace_destroy_private);
213
214int lttng_ftrace_init(void)
215{
216 wrapper_vmalloc_sync_all();
217 return 0;
218}
219module_init(lttng_ftrace_init)
220
221/*
222 * Ftrace takes care of waiting for a grace period (RCU sched) at probe
223 * unregistration, and disables preemption around probe call.
224 */
225void lttng_ftrace_exit(void)
226{
227}
228module_exit(lttng_ftrace_exit)
229
230MODULE_LICENSE("GPL and additional rights");
231MODULE_AUTHOR("Mathieu Desnoyers <mathieu.desnoyers@efficios.com>");
232MODULE_DESCRIPTION("LTTng ftrace probes");
233MODULE_VERSION(__stringify(LTTNG_MODULES_MAJOR_VERSION) "."
234 __stringify(LTTNG_MODULES_MINOR_VERSION) "."
235 __stringify(LTTNG_MODULES_PATCHLEVEL_VERSION)
236 LTTNG_MODULES_EXTRAVERSION);
This page took 0.027232 seconds and 5 git commands to generate.