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