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