trace event: introduce TP_MODULE_NOAUTOLOAD and TP_MODULE_NOINIT
[lttng-modules.git] / lttng-syscalls.c
1 /*
2 * lttng-syscalls.c
3 *
4 * LTTng syscall probes.
5 *
6 * Copyright (C) 2010-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; only
11 * version 2.1 of the License.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #include <linux/module.h>
24 #include <linux/slab.h>
25 #include <linux/compat.h>
26 #include <asm/ptrace.h>
27 #include <asm/syscall.h>
28
29 #include "lttng-events.h"
30
31 #ifndef CONFIG_COMPAT
32 # ifndef is_compat_task
33 # define is_compat_task() (0)
34 # endif
35 #endif
36
37 static
38 void syscall_entry_probe(void *__data, struct pt_regs *regs, long id);
39
40 /*
41 * Take care of NOARGS not supported by mainline.
42 */
43 #define DECLARE_EVENT_CLASS_NOARGS(name, tstruct, assign, print)
44 #define DEFINE_EVENT_NOARGS(template, name)
45 #define TRACE_EVENT_NOARGS(name, struct, assign, print)
46
47 /*
48 * Create LTTng tracepoint probes.
49 */
50 #define LTTNG_PACKAGE_BUILD
51 #define CREATE_TRACE_POINTS
52 #define TP_MODULE_NOINIT
53 #define TRACE_INCLUDE_PATH ../instrumentation/syscalls/headers
54
55 #define PARAMS(args...) args
56
57 /* Hijack probe callback for system calls */
58 #undef TP_PROBE_CB
59 #define TP_PROBE_CB(_template) &syscall_entry_probe
60 #define SC_TRACE_EVENT(_name, _proto, _args, _struct, _assign, _printk) \
61 TRACE_EVENT(_name, PARAMS(_proto), PARAMS(_args),\
62 PARAMS(_struct), PARAMS(_assign), PARAMS(_printk))
63 #define SC_DECLARE_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \
64 DECLARE_EVENT_CLASS_NOARGS(_name, PARAMS(_struct), PARAMS(_assign),\
65 PARAMS(_printk))
66 #define SC_DEFINE_EVENT_NOARGS(_template, _name) \
67 DEFINE_EVENT_NOARGS(_template, _name)
68 #undef TRACE_SYSTEM
69 #define TRACE_SYSTEM syscalls_integers
70 #include "instrumentation/syscalls/headers/syscalls_integers.h"
71 #undef TRACE_SYSTEM
72 #define TRACE_SYSTEM syscalls_pointers
73 #include "instrumentation/syscalls/headers/syscalls_pointers.h"
74 #undef TRACE_SYSTEM
75 #undef SC_TRACE_EVENT
76 #undef SC_DECLARE_EVENT_CLASS_NOARGS
77 #undef SC_DEFINE_EVENT_NOARGS
78
79 #define TRACE_SYSTEM syscalls_unknown
80 #include "instrumentation/syscalls/headers/syscalls_unknown.h"
81 #undef TRACE_SYSTEM
82
83 /* For compat syscalls */
84 #undef _TRACE_SYSCALLS_integers_H
85 #undef _TRACE_SYSCALLS_pointers_H
86
87 /* Hijack probe callback for system calls */
88 #undef TP_PROBE_CB
89 #define TP_PROBE_CB(_template) &syscall_entry_probe
90 #define SC_TRACE_EVENT(_name, _proto, _args, _struct, _assign, _printk) \
91 TRACE_EVENT(compat_##_name, PARAMS(_proto), PARAMS(_args), \
92 PARAMS(_struct), PARAMS(_assign), \
93 PARAMS(_printk))
94 #define SC_DECLARE_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \
95 DECLARE_EVENT_CLASS_NOARGS(compat_##_name, PARAMS(_struct), \
96 PARAMS(_assign), PARAMS(_printk))
97 #define SC_DEFINE_EVENT_NOARGS(_template, _name) \
98 DEFINE_EVENT_NOARGS(compat_##_template, compat_##_name)
99 #define TRACE_SYSTEM compat_syscalls_integers
100 #include "instrumentation/syscalls/headers/compat_syscalls_integers.h"
101 #undef TRACE_SYSTEM
102 #define TRACE_SYSTEM compat_syscalls_pointers
103 #include "instrumentation/syscalls/headers/compat_syscalls_pointers.h"
104 #undef TRACE_SYSTEM
105 #undef SC_TRACE_EVENT
106 #undef SC_DECLARE_EVENT_CLASS_NOARGS
107 #undef SC_DEFINE_EVENT_NOARGS
108 #undef TP_PROBE_CB
109
110 #undef TP_MODULE_NOINIT
111 #undef LTTNG_PACKAGE_BUILD
112 #undef CREATE_TRACE_POINTS
113
114 struct trace_syscall_entry {
115 void *func;
116 const struct lttng_event_desc *desc;
117 const struct lttng_event_field *fields;
118 unsigned int nrargs;
119 };
120
121 #define CREATE_SYSCALL_TABLE
122
123 #undef TRACE_SYSCALL_TABLE
124 #define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
125 [ _nr ] = { \
126 .func = __event_probe__##_template, \
127 .nrargs = (_nrargs), \
128 .fields = __event_fields___##_template, \
129 .desc = &__event_desc___##_name, \
130 },
131
132 static const struct trace_syscall_entry sc_table[] = {
133 #include "instrumentation/syscalls/headers/syscalls_integers.h"
134 #include "instrumentation/syscalls/headers/syscalls_pointers.h"
135 };
136
137 #undef TRACE_SYSCALL_TABLE
138 #define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
139 [ _nr ] = { \
140 .func = __event_probe__##compat_##_template, \
141 .nrargs = (_nrargs), \
142 .fields = __event_fields___##compat_##_template,\
143 .desc = &__event_desc___##compat_##_name, \
144 },
145
146 /* Create compatibility syscall table */
147 const struct trace_syscall_entry compat_sc_table[] = {
148 #include "instrumentation/syscalls/headers/compat_syscalls_integers.h"
149 #include "instrumentation/syscalls/headers/compat_syscalls_pointers.h"
150 };
151
152 #undef CREATE_SYSCALL_TABLE
153
154 static void syscall_entry_unknown(struct lttng_event *event,
155 struct pt_regs *regs, unsigned int id)
156 {
157 unsigned long args[UNKNOWN_SYSCALL_NRARGS];
158
159 syscall_get_arguments(current, regs, 0, UNKNOWN_SYSCALL_NRARGS, args);
160 if (unlikely(is_compat_task()))
161 __event_probe__compat_sys_unknown(event, id, args);
162 else
163 __event_probe__sys_unknown(event, id, args);
164 }
165
166 void syscall_entry_probe(void *__data, struct pt_regs *regs, long id)
167 {
168 struct lttng_channel *chan = __data;
169 struct lttng_event *event, *unknown_event;
170 const struct trace_syscall_entry *table, *entry;
171 size_t table_len;
172
173 if (unlikely(is_compat_task())) {
174 table = compat_sc_table;
175 table_len = ARRAY_SIZE(compat_sc_table);
176 unknown_event = chan->sc_compat_unknown;
177 } else {
178 table = sc_table;
179 table_len = ARRAY_SIZE(sc_table);
180 unknown_event = chan->sc_unknown;
181 }
182 if (unlikely(id >= table_len)) {
183 syscall_entry_unknown(unknown_event, regs, id);
184 return;
185 }
186 if (unlikely(is_compat_task()))
187 event = chan->compat_sc_table[id];
188 else
189 event = chan->sc_table[id];
190 if (unlikely(!event)) {
191 syscall_entry_unknown(unknown_event, regs, id);
192 return;
193 }
194 entry = &table[id];
195 WARN_ON_ONCE(!entry);
196
197 switch (entry->nrargs) {
198 case 0:
199 {
200 void (*fptr)(void *__data) = entry->func;
201
202 fptr(event);
203 break;
204 }
205 case 1:
206 {
207 void (*fptr)(void *__data, unsigned long arg0) = entry->func;
208 unsigned long args[1];
209
210 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
211 fptr(event, args[0]);
212 break;
213 }
214 case 2:
215 {
216 void (*fptr)(void *__data,
217 unsigned long arg0,
218 unsigned long arg1) = entry->func;
219 unsigned long args[2];
220
221 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
222 fptr(event, args[0], args[1]);
223 break;
224 }
225 case 3:
226 {
227 void (*fptr)(void *__data,
228 unsigned long arg0,
229 unsigned long arg1,
230 unsigned long arg2) = entry->func;
231 unsigned long args[3];
232
233 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
234 fptr(event, args[0], args[1], args[2]);
235 break;
236 }
237 case 4:
238 {
239 void (*fptr)(void *__data,
240 unsigned long arg0,
241 unsigned long arg1,
242 unsigned long arg2,
243 unsigned long arg3) = entry->func;
244 unsigned long args[4];
245
246 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
247 fptr(event, args[0], args[1], args[2], args[3]);
248 break;
249 }
250 case 5:
251 {
252 void (*fptr)(void *__data,
253 unsigned long arg0,
254 unsigned long arg1,
255 unsigned long arg2,
256 unsigned long arg3,
257 unsigned long arg4) = entry->func;
258 unsigned long args[5];
259
260 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
261 fptr(event, args[0], args[1], args[2], args[3], args[4]);
262 break;
263 }
264 case 6:
265 {
266 void (*fptr)(void *__data,
267 unsigned long arg0,
268 unsigned long arg1,
269 unsigned long arg2,
270 unsigned long arg3,
271 unsigned long arg4,
272 unsigned long arg5) = entry->func;
273 unsigned long args[6];
274
275 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
276 fptr(event, args[0], args[1], args[2],
277 args[3], args[4], args[5]);
278 break;
279 }
280 default:
281 break;
282 }
283 }
284
285 /* noinline to diminish caller stack size */
286 static
287 int fill_table(const struct trace_syscall_entry *table, size_t table_len,
288 struct lttng_event **chan_table, struct lttng_channel *chan, void *filter)
289 {
290 const struct lttng_event_desc *desc;
291 unsigned int i;
292
293 /* Allocate events for each syscall, insert into table */
294 for (i = 0; i < table_len; i++) {
295 struct lttng_kernel_event ev;
296 desc = table[i].desc;
297
298 if (!desc) {
299 /* Unknown syscall */
300 continue;
301 }
302 /*
303 * Skip those already populated by previous failed
304 * register for this channel.
305 */
306 if (chan_table[i])
307 continue;
308 memset(&ev, 0, sizeof(ev));
309 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
310 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
311 ev.instrumentation = LTTNG_KERNEL_NOOP;
312 chan_table[i] = lttng_event_create(chan, &ev, filter,
313 desc);
314 if (!chan_table[i]) {
315 /*
316 * If something goes wrong in event registration
317 * after the first one, we have no choice but to
318 * leave the previous events in there, until
319 * deleted by session teardown.
320 */
321 return -EINVAL;
322 }
323 }
324 return 0;
325 }
326
327 int lttng_syscalls_register(struct lttng_channel *chan, void *filter)
328 {
329 struct lttng_kernel_event ev;
330 int ret;
331
332 wrapper_vmalloc_sync_all();
333
334 if (!chan->sc_table) {
335 /* create syscall table mapping syscall to events */
336 chan->sc_table = kzalloc(sizeof(struct lttng_event *)
337 * ARRAY_SIZE(sc_table), GFP_KERNEL);
338 if (!chan->sc_table)
339 return -ENOMEM;
340 }
341
342 #ifdef CONFIG_COMPAT
343 if (!chan->compat_sc_table) {
344 /* create syscall table mapping compat syscall to events */
345 chan->compat_sc_table = kzalloc(sizeof(struct lttng_event *)
346 * ARRAY_SIZE(compat_sc_table), GFP_KERNEL);
347 if (!chan->compat_sc_table)
348 return -ENOMEM;
349 }
350 #endif
351 if (!chan->sc_unknown) {
352 const struct lttng_event_desc *desc =
353 &__event_desc___sys_unknown;
354
355 memset(&ev, 0, sizeof(ev));
356 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
357 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
358 ev.instrumentation = LTTNG_KERNEL_NOOP;
359 chan->sc_unknown = lttng_event_create(chan, &ev, filter,
360 desc);
361 if (!chan->sc_unknown) {
362 return -EINVAL;
363 }
364 }
365
366 if (!chan->sc_compat_unknown) {
367 const struct lttng_event_desc *desc =
368 &__event_desc___compat_sys_unknown;
369
370 memset(&ev, 0, sizeof(ev));
371 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
372 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
373 ev.instrumentation = LTTNG_KERNEL_NOOP;
374 chan->sc_compat_unknown = lttng_event_create(chan, &ev, filter,
375 desc);
376 if (!chan->sc_compat_unknown) {
377 return -EINVAL;
378 }
379 }
380
381 if (!chan->sc_exit) {
382 const struct lttng_event_desc *desc =
383 &__event_desc___exit_syscall;
384
385 memset(&ev, 0, sizeof(ev));
386 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
387 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
388 ev.instrumentation = LTTNG_KERNEL_NOOP;
389 chan->sc_exit = lttng_event_create(chan, &ev, filter,
390 desc);
391 if (!chan->sc_exit) {
392 return -EINVAL;
393 }
394 }
395
396 ret = fill_table(sc_table, ARRAY_SIZE(sc_table),
397 chan->sc_table, chan, filter);
398 if (ret)
399 return ret;
400 #ifdef CONFIG_COMPAT
401 ret = fill_table(compat_sc_table, ARRAY_SIZE(compat_sc_table),
402 chan->compat_sc_table, chan, filter);
403 if (ret)
404 return ret;
405 #endif
406 ret = tracepoint_probe_register("sys_enter",
407 (void *) syscall_entry_probe, chan);
408 if (ret)
409 return ret;
410 /*
411 * We change the name of sys_exit tracepoint due to namespace
412 * conflict with sys_exit syscall entry.
413 */
414 ret = tracepoint_probe_register("sys_exit",
415 (void *) __event_probe__exit_syscall,
416 chan->sc_exit);
417 if (ret) {
418 WARN_ON_ONCE(tracepoint_probe_unregister("sys_enter",
419 (void *) syscall_entry_probe, chan));
420 }
421 return ret;
422 }
423
424 /*
425 * Only called at session destruction.
426 */
427 int lttng_syscalls_unregister(struct lttng_channel *chan)
428 {
429 int ret;
430
431 if (!chan->sc_table)
432 return 0;
433 ret = tracepoint_probe_unregister("sys_exit",
434 (void *) __event_probe__exit_syscall,
435 chan->sc_exit);
436 if (ret)
437 return ret;
438 ret = tracepoint_probe_unregister("sys_enter",
439 (void *) syscall_entry_probe, chan);
440 if (ret)
441 return ret;
442 /* lttng_event destroy will be performed by lttng_session_destroy() */
443 kfree(chan->sc_table);
444 #ifdef CONFIG_COMPAT
445 kfree(chan->compat_sc_table);
446 #endif
447 return 0;
448 }
This page took 0.0458499999999999 seconds and 5 git commands to generate.