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