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