Only enable detailed syscalls for x86_64 for now
[lttng-modules.git] / lttng-syscalls.c
CommitLineData
259b6cb3
MD
1/*
2 * lttng-syscalls.c
3 *
4 * Copyright 2010 (c) - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
5 *
6 * LTTng sched probes.
7 *
8 * Dual LGPL v2.1/GPL v2 license.
9 */
10
11#include <linux/module.h>
12#include <linux/slab.h>
13#include <asm/ptrace.h>
14#include <asm/syscall.h>
15
16#include "ltt-events.h"
17
18static void syscall_entry_probe(void *__data, struct pt_regs *regs, long id);
19
f7bdf4db
MD
20/*
21 * Take care of NOARGS not supported by mainline.
22 */
23#define DECLARE_EVENT_CLASS_NOARGS(name, tstruct, assign, print)
24#define DEFINE_EVENT_NOARGS(template, name)
25#define TRACE_EVENT_NOARGS(name, struct, assign, print)
26
259b6cb3
MD
27/*
28 * Create LTTng tracepoint probes.
29 */
30#define LTTNG_PACKAGE_BUILD
31#define CREATE_TRACE_POINTS
32
33/* Hijack probe callback for system calls */
34#define TP_PROBE_CB(_template) &syscall_entry_probe
35#define TP_MODULE_OVERRIDE
36
37#define TRACE_INCLUDE_PATH ../instrumentation/syscalls/headers
177b3692
MD
38#include "instrumentation/syscalls/headers/syscalls_integers.h"
39#include "instrumentation/syscalls/headers/syscalls_pointers.h"
63728b02 40#include "instrumentation/syscalls/headers/syscalls_unknown.h"
259b6cb3
MD
41
42#undef TP_MODULE_OVERRIDE
43#undef TP_PROBE_CB
44#undef LTTNG_PACKAGE_BUILD
45#undef CREATE_TRACE_POINTS
46
47struct trace_syscall_entry {
48 void *func;
f7bdf4db 49 const struct lttng_event_desc *desc;
259b6cb3
MD
50 const struct lttng_event_field *fields;
51 unsigned int nrargs;
52};
53
259b6cb3
MD
54#define CREATE_SYSCALL_TABLE
55
56#undef TRACE_SYSCALL_TABLE
f7bdf4db 57#define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
259b6cb3 58 [ _nr ] = { \
f7bdf4db 59 .func = __event_probe__##_template, \
259b6cb3 60 .nrargs = (_nrargs), \
f7bdf4db
MD
61 .fields = __event_fields___##_template, \
62 .desc = &__event_desc___##_name, \
259b6cb3
MD
63 },
64
65static struct trace_syscall_entry sc_table[] = {
177b3692
MD
66#include "instrumentation/syscalls/headers/syscalls_integers.h"
67#include "instrumentation/syscalls/headers/syscalls_pointers.h"
259b6cb3
MD
68};
69
63728b02
MD
70static int sc_table_filled;
71
259b6cb3
MD
72#undef CREATE_SYSCALL_TABLE
73
74static void syscall_entry_probe(void *__data, struct pt_regs *regs, long id)
75{
76 struct trace_syscall_entry *entry;
77 struct ltt_channel *chan = __data;
78 struct ltt_event *event;
79
80 if (unlikely(id >= ARRAY_SIZE(sc_table)))
81 return;
82 entry = &sc_table[id];
83 if (unlikely(!entry->func))
84 return;
85 event = chan->sc_table[id];
86 WARN_ON_ONCE(!event);
87
88 switch (entry->nrargs) {
89 case 0:
90 {
91 void (*fptr)(void *__data) = entry->func;
92
93 fptr(event);
94 break;
95 }
96 case 1:
97 {
98 void (*fptr)(void *__data, unsigned long arg0) = entry->func;
99 unsigned long args[1];
100
101 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
102 fptr(event, args[0]);
103 break;
104 }
105 case 2:
106 {
107 void (*fptr)(void *__data,
108 unsigned long arg0,
109 unsigned long arg1) = entry->func;
110 unsigned long args[2];
111
112 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
113 fptr(event, args[0], args[1]);
114 break;
115 }
116 case 3:
117 {
118 void (*fptr)(void *__data,
119 unsigned long arg0,
120 unsigned long arg1,
121 unsigned long arg2) = entry->func;
122 unsigned long args[3];
123
124 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
125 fptr(event, args[0], args[1], args[2]);
126 break;
127 }
128 case 4:
129 {
130 void (*fptr)(void *__data,
131 unsigned long arg0,
132 unsigned long arg1,
133 unsigned long arg2,
134 unsigned long arg3) = entry->func;
135 unsigned long args[4];
136
137 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
138 fptr(event, args[0], args[1], args[2], args[3]);
139 break;
140 }
141 case 5:
142 {
143 void (*fptr)(void *__data,
144 unsigned long arg0,
145 unsigned long arg1,
146 unsigned long arg2,
147 unsigned long arg3,
148 unsigned long arg4) = entry->func;
149 unsigned long args[5];
150
151 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
152 fptr(event, args[0], args[1], args[2], args[3], args[4]);
153 break;
154 }
155 case 6:
156 {
157 void (*fptr)(void *__data,
158 unsigned long arg0,
159 unsigned long arg1,
160 unsigned long arg2,
161 unsigned long arg3,
162 unsigned long arg4,
163 unsigned long arg5) = entry->func;
164 unsigned long args[6];
165
166 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
167 fptr(event, args[0], args[1], args[2],
168 args[3], args[4], args[5]);
169 break;
170 }
171 default:
172 break;
173 }
174}
175
63728b02
MD
176static void fill_sc_table(void)
177{
178 int i;
179
180 if (sc_table_filled) {
181 smp_rmb(); /* read flag before table */
182 return;
183 }
184
185 for (i = 0; i < ARRAY_SIZE(sc_table); i++) {
186 if (sc_table[i].func)
187 continue;
188 sc_table[i].func = __event_probe__sys_unknown;
189 sc_table[i].nrargs = UNKNOWN_SYSCALL_NRARGS;
190 sc_table[i].fields = __event_fields___sys_unknown;
191 sc_table[i].desc = &__event_desc___sys_unknown;
192 }
193 smp_wmb(); /* Fill sc table before set flag to 1 */
194 sc_table_filled = 1;
195}
196
259b6cb3
MD
197int lttng_syscalls_register(struct ltt_channel *chan, void *filter)
198{
199 unsigned int i;
200 int ret;
201
202 wrapper_vmalloc_sync_all();
259b6cb3 203
63728b02
MD
204 fill_sc_table();
205
259b6cb3
MD
206 if (!chan->sc_table) {
207 /* create syscall table mapping syscall to events */
208 chan->sc_table = kzalloc(sizeof(struct ltt_event *)
209 * ARRAY_SIZE(sc_table), GFP_KERNEL);
210 if (!chan->sc_table)
211 return -ENOMEM;
212 }
213
214 /* Allocate events for each syscall, insert into table */
215 for (i = 0; i < ARRAY_SIZE(sc_table); i++) {
216 struct lttng_kernel_event ev;
217 const struct lttng_event_desc *desc = sc_table[i].desc;
218
63728b02 219 WARN_ON_ONCE(!desc);
259b6cb3
MD
220 /*
221 * Skip those already populated by previous failed
222 * register for this channel.
223 */
224 if (chan->sc_table[i])
225 continue;
226 memset(&ev, 0, sizeof(ev));
227 strncpy(ev.name, desc->name, LTTNG_SYM_NAME_LEN);
228 ev.name[LTTNG_SYM_NAME_LEN - 1] = '\0';
229 ev.instrumentation = LTTNG_KERNEL_NOOP;
230 chan->sc_table[i] = ltt_event_create(chan, &ev, filter,
231 desc);
232 if (!chan->sc_table[i]) {
233 /*
234 * If something goes wrong in event registration
235 * after the first one, we have no choice but to
236 * leave the previous events in there, until
237 * deleted by session teardown.
238 */
239 return -EINVAL;
240 }
241 }
242 ret = tracepoint_probe_register("sys_enter",
243 (void *) syscall_entry_probe, chan);
63728b02
MD
244 if (ret)
245 return ret;
246 /*
247 * We change the name of sys_exit tracepoint due to namespace
248 * conflict with sys_exit syscall entry.
249 */
250 ret = tracepoint_probe_register("sys_exit",
251 (void *) __event_probe__exit_syscall, chan);
252 if (ret) {
253 WARN_ON_ONCE(tracepoint_probe_unregister("sys_enter",
254 (void *) syscall_entry_probe, chan));
255 }
259b6cb3
MD
256 return ret;
257}
258
259/*
260 * Only called at session destruction.
261 */
262int lttng_syscalls_unregister(struct ltt_channel *chan)
263{
264 int ret;
265
266 if (!chan->sc_table)
267 return 0;
63728b02
MD
268 ret = tracepoint_probe_unregister("sys_exit",
269 (void *) __event_probe__exit_syscall, chan);
270 if (ret)
271 return ret;
259b6cb3
MD
272 ret = tracepoint_probe_unregister("sys_enter",
273 (void *) syscall_entry_probe, chan);
274 if (ret)
275 return ret;
276 /* ltt_event destroy will be performed by ltt_session_destroy() */
277 kfree(chan->sc_table);
278 return 0;
279}
This page took 0.036646 seconds and 4 git commands to generate.