Fix: generate header missing echo -e for escape chars
[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 31#ifndef CONFIG_COMPAT
bfa949bf
MD
32# ifndef is_compat_task
33# define is_compat_task() (0)
34# endif
6333ace3
MD
35#endif
36
a93244f8 37static
2faf7d1b 38void syscall_entry_probe(void *__data, struct pt_regs *regs, long id);
259b6cb3 39
f7bdf4db
MD
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
259b6cb3
MD
47/*
48 * Create LTTng tracepoint probes.
49 */
50#define LTTNG_PACKAGE_BUILD
51#define CREATE_TRACE_POINTS
2f804c0a
MD
52#define TP_MODULE_OVERRIDE
53#define TRACE_INCLUDE_PATH ../instrumentation/syscalls/headers
259b6cb3 54
a93244f8
MD
55#define PARAMS(args...) args
56
259b6cb3 57/* Hijack probe callback for system calls */
a93244f8 58#undef TP_PROBE_CB
259b6cb3 59#define TP_PROBE_CB(_template) &syscall_entry_probe
a93244f8
MD
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
177b3692 70#include "instrumentation/syscalls/headers/syscalls_integers.h"
a93244f8
MD
71#undef TRACE_SYSTEM
72#define TRACE_SYSTEM syscalls_pointers
177b3692 73#include "instrumentation/syscalls/headers/syscalls_pointers.h"
a93244f8
MD
74#undef TRACE_SYSTEM
75#undef SC_TRACE_EVENT
76#undef SC_DECLARE_EVENT_CLASS_NOARGS
77#undef SC_DEFINE_EVENT_NOARGS
2f804c0a 78
a93244f8 79#define TRACE_SYSTEM syscalls_unknown
63728b02 80#include "instrumentation/syscalls/headers/syscalls_unknown.h"
a93244f8
MD
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
259b6cb3
MD
109
110#undef TP_MODULE_OVERRIDE
259b6cb3
MD
111#undef LTTNG_PACKAGE_BUILD
112#undef CREATE_TRACE_POINTS
113
a93244f8
MD
114struct 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
259b6cb3 123#undef TRACE_SYSCALL_TABLE
f7bdf4db 124#define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
259b6cb3 125 [ _nr ] = { \
f7bdf4db 126 .func = __event_probe__##_template, \
259b6cb3 127 .nrargs = (_nrargs), \
f7bdf4db
MD
128 .fields = __event_fields___##_template, \
129 .desc = &__event_desc___##_name, \
259b6cb3
MD
130 },
131
49c50022 132static const struct trace_syscall_entry sc_table[] = {
177b3692
MD
133#include "instrumentation/syscalls/headers/syscalls_integers.h"
134#include "instrumentation/syscalls/headers/syscalls_pointers.h"
259b6cb3
MD
135};
136
a93244f8
MD
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 */
147const 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};
259b6cb3 151
a93244f8 152#undef CREATE_SYSCALL_TABLE
2faf7d1b 153
a90917c3 154static void syscall_entry_unknown(struct lttng_event *event,
f405cfce
MD
155 struct pt_regs *regs, unsigned int id)
156{
157 unsigned long args[UNKNOWN_SYSCALL_NRARGS];
f405cfce 158
f405cfce 159 syscall_get_arguments(current, regs, 0, UNKNOWN_SYSCALL_NRARGS, args);
a93244f8
MD
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);
f405cfce
MD
164}
165
2faf7d1b 166void syscall_entry_probe(void *__data, struct pt_regs *regs, long id)
259b6cb3 167{
a90917c3
MD
168 struct lttng_channel *chan = __data;
169 struct lttng_event *event, *unknown_event;
49c50022
MD
170 const struct trace_syscall_entry *table, *entry;
171 size_t table_len;
259b6cb3 172
b76dc1a0 173 if (unlikely(is_compat_task())) {
49c50022 174 table = compat_sc_table;
a93244f8 175 table_len = ARRAY_SIZE(compat_sc_table);
49c50022
MD
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;
b76dc1a0 181 }
49c50022
MD
182 if (unlikely(id >= table_len)) {
183 syscall_entry_unknown(unknown_event, regs, id);
259b6cb3 184 return;
f405cfce 185 }
49c50022
MD
186 if (unlikely(is_compat_task()))
187 event = chan->compat_sc_table[id];
188 else
189 event = chan->sc_table[id];
f405cfce 190 if (unlikely(!event)) {
49c50022 191 syscall_entry_unknown(unknown_event, regs, id);
f405cfce
MD
192 return;
193 }
49c50022 194 entry = &table[id];
f405cfce 195 WARN_ON_ONCE(!entry);
259b6cb3
MD
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
2a0c4816 285/* noinline to diminish caller stack size */
49c50022
MD
286static
287int fill_table(const struct trace_syscall_entry *table, size_t table_len,
a90917c3 288 struct lttng_event **chan_table, struct lttng_channel *chan, void *filter)
259b6cb3 289{
2a0c4816 290 const struct lttng_event_desc *desc;
259b6cb3 291 unsigned int i;
49c50022
MD
292
293 /* Allocate events for each syscall, insert into table */
294 for (i = 0; i < table_len; i++) {
295 struct lttng_kernel_event ev;
2a0c4816 296 desc = table[i].desc;
49c50022
MD
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));
f8695253
MD
309 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
310 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
49c50022 311 ev.instrumentation = LTTNG_KERNEL_NOOP;
a90917c3 312 chan_table[i] = lttng_event_create(chan, &ev, filter,
49c50022
MD
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
a90917c3 327int lttng_syscalls_register(struct lttng_channel *chan, void *filter)
49c50022 328{
2a0c4816 329 struct lttng_kernel_event ev;
259b6cb3
MD
330 int ret;
331
332 wrapper_vmalloc_sync_all();
259b6cb3
MD
333
334 if (!chan->sc_table) {
335 /* create syscall table mapping syscall to events */
a90917c3 336 chan->sc_table = kzalloc(sizeof(struct lttng_event *)
259b6cb3
MD
337 * ARRAY_SIZE(sc_table), GFP_KERNEL);
338 if (!chan->sc_table)
339 return -ENOMEM;
340 }
341
49c50022
MD
342#ifdef CONFIG_COMPAT
343 if (!chan->compat_sc_table) {
344 /* create syscall table mapping compat syscall to events */
a90917c3 345 chan->compat_sc_table = kzalloc(sizeof(struct lttng_event *)
a93244f8 346 * ARRAY_SIZE(compat_sc_table), GFP_KERNEL);
49c50022
MD
347 if (!chan->compat_sc_table)
348 return -ENOMEM;
349 }
350#endif
f405cfce 351 if (!chan->sc_unknown) {
f405cfce
MD
352 const struct lttng_event_desc *desc =
353 &__event_desc___sys_unknown;
2f804c0a 354
f405cfce 355 memset(&ev, 0, sizeof(ev));
f8695253
MD
356 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
357 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
f405cfce 358 ev.instrumentation = LTTNG_KERNEL_NOOP;
a90917c3 359 chan->sc_unknown = lttng_event_create(chan, &ev, filter,
f405cfce
MD
360 desc);
361 if (!chan->sc_unknown) {
362 return -EINVAL;
363 }
364 }
365
b76dc1a0 366 if (!chan->sc_compat_unknown) {
b76dc1a0
MD
367 const struct lttng_event_desc *desc =
368 &__event_desc___compat_sys_unknown;
369
370 memset(&ev, 0, sizeof(ev));
f8695253
MD
371 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
372 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
b76dc1a0 373 ev.instrumentation = LTTNG_KERNEL_NOOP;
a90917c3 374 chan->sc_compat_unknown = lttng_event_create(chan, &ev, filter,
b76dc1a0
MD
375 desc);
376 if (!chan->sc_compat_unknown) {
377 return -EINVAL;
378 }
379 }
380
2f804c0a 381 if (!chan->sc_exit) {
2f804c0a
MD
382 const struct lttng_event_desc *desc =
383 &__event_desc___exit_syscall;
384
385 memset(&ev, 0, sizeof(ev));
f8695253
MD
386 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
387 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
2f804c0a 388 ev.instrumentation = LTTNG_KERNEL_NOOP;
a90917c3 389 chan->sc_exit = lttng_event_create(chan, &ev, filter,
2f804c0a
MD
390 desc);
391 if (!chan->sc_exit) {
392 return -EINVAL;
393 }
394 }
395
49c50022
MD
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
a93244f8 401 ret = fill_table(compat_sc_table, ARRAY_SIZE(compat_sc_table),
49c50022
MD
402 chan->compat_sc_table, chan, filter);
403 if (ret)
404 return ret;
405#endif
259b6cb3
MD
406 ret = tracepoint_probe_register("sys_enter",
407 (void *) syscall_entry_probe, chan);
63728b02
MD
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",
2c01ec07 415 (void *) __event_probe__exit_syscall,
2f804c0a 416 chan->sc_exit);
63728b02
MD
417 if (ret) {
418 WARN_ON_ONCE(tracepoint_probe_unregister("sys_enter",
419 (void *) syscall_entry_probe, chan));
420 }
259b6cb3
MD
421 return ret;
422}
423
424/*
425 * Only called at session destruction.
426 */
a90917c3 427int lttng_syscalls_unregister(struct lttng_channel *chan)
259b6cb3
MD
428{
429 int ret;
430
431 if (!chan->sc_table)
432 return 0;
63728b02 433 ret = tracepoint_probe_unregister("sys_exit",
2c01ec07 434 (void *) __event_probe__exit_syscall,
2f804c0a 435 chan->sc_exit);
63728b02
MD
436 if (ret)
437 return ret;
259b6cb3
MD
438 ret = tracepoint_probe_unregister("sys_enter",
439 (void *) syscall_entry_probe, chan);
440 if (ret)
441 return ret;
a90917c3 442 /* lttng_event destroy will be performed by lttng_session_destroy() */
259b6cb3 443 kfree(chan->sc_table);
49c50022
MD
444#ifdef CONFIG_COMPAT
445 kfree(chan->compat_sc_table);
446#endif
259b6cb3
MD
447 return 0;
448}
This page took 0.043719 seconds and 4 git commands to generate.