Remove unused variable
[lttng-modules.git] / lttng-syscalls.c
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
18 static void syscall_entry_probe(void *__data, struct pt_regs *regs, long id);
19
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
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
38 #include "instrumentation/syscalls/headers/syscalls_integers.h"
39 #include "instrumentation/syscalls/headers/syscalls_pointers.h"
40 #include "instrumentation/syscalls/headers/syscalls_unknown.h"
41
42 #undef TP_MODULE_OVERRIDE
43 #undef TP_PROBE_CB
44 #undef LTTNG_PACKAGE_BUILD
45 #undef CREATE_TRACE_POINTS
46
47 struct trace_syscall_entry {
48 void *func;
49 const struct lttng_event_desc *desc;
50 const struct lttng_event_field *fields;
51 unsigned int nrargs;
52 };
53
54 #define CREATE_SYSCALL_TABLE
55
56 #undef TRACE_SYSCALL_TABLE
57 #define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
58 [ _nr ] = { \
59 .func = __event_probe__##_template, \
60 .nrargs = (_nrargs), \
61 .fields = __event_fields___##_template, \
62 .desc = &__event_desc___##_name, \
63 },
64
65 static struct trace_syscall_entry sc_table[] = {
66 #include "instrumentation/syscalls/headers/syscalls_integers.h"
67 #include "instrumentation/syscalls/headers/syscalls_pointers.h"
68 };
69
70 #undef CREATE_SYSCALL_TABLE
71
72 static void syscall_entry_unknown(struct ltt_channel *chan,
73 struct pt_regs *regs, unsigned int id)
74 {
75 unsigned long args[UNKNOWN_SYSCALL_NRARGS];
76 struct ltt_event *event;
77
78 event = chan->sc_unknown;
79 syscall_get_arguments(current, regs, 0, UNKNOWN_SYSCALL_NRARGS, args);
80 __event_probe__sys_unknown(event, id, args);
81 }
82
83 static void syscall_entry_probe(void *__data, struct pt_regs *regs, long id)
84 {
85 struct trace_syscall_entry *entry;
86 struct ltt_channel *chan = __data;
87 struct ltt_event *event;
88
89 if (unlikely(id >= ARRAY_SIZE(sc_table))) {
90 syscall_entry_unknown(chan, regs, id);
91 return;
92 }
93 event = chan->sc_table[id];
94 if (unlikely(!event)) {
95 syscall_entry_unknown(chan, regs, id);
96 return;
97 }
98 entry = &sc_table[id];
99 WARN_ON_ONCE(!entry);
100
101 switch (entry->nrargs) {
102 case 0:
103 {
104 void (*fptr)(void *__data) = entry->func;
105
106 fptr(event);
107 break;
108 }
109 case 1:
110 {
111 void (*fptr)(void *__data, unsigned long arg0) = entry->func;
112 unsigned long args[1];
113
114 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
115 fptr(event, args[0]);
116 break;
117 }
118 case 2:
119 {
120 void (*fptr)(void *__data,
121 unsigned long arg0,
122 unsigned long arg1) = entry->func;
123 unsigned long args[2];
124
125 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
126 fptr(event, args[0], args[1]);
127 break;
128 }
129 case 3:
130 {
131 void (*fptr)(void *__data,
132 unsigned long arg0,
133 unsigned long arg1,
134 unsigned long arg2) = entry->func;
135 unsigned long args[3];
136
137 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
138 fptr(event, args[0], args[1], args[2]);
139 break;
140 }
141 case 4:
142 {
143 void (*fptr)(void *__data,
144 unsigned long arg0,
145 unsigned long arg1,
146 unsigned long arg2,
147 unsigned long arg3) = entry->func;
148 unsigned long args[4];
149
150 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
151 fptr(event, args[0], args[1], args[2], args[3]);
152 break;
153 }
154 case 5:
155 {
156 void (*fptr)(void *__data,
157 unsigned long arg0,
158 unsigned long arg1,
159 unsigned long arg2,
160 unsigned long arg3,
161 unsigned long arg4) = entry->func;
162 unsigned long args[5];
163
164 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
165 fptr(event, args[0], args[1], args[2], args[3], args[4]);
166 break;
167 }
168 case 6:
169 {
170 void (*fptr)(void *__data,
171 unsigned long arg0,
172 unsigned long arg1,
173 unsigned long arg2,
174 unsigned long arg3,
175 unsigned long arg4,
176 unsigned long arg5) = entry->func;
177 unsigned long args[6];
178
179 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
180 fptr(event, args[0], args[1], args[2],
181 args[3], args[4], args[5]);
182 break;
183 }
184 default:
185 break;
186 }
187 }
188
189 int lttng_syscalls_register(struct ltt_channel *chan, void *filter)
190 {
191 unsigned int i;
192 int ret;
193
194 wrapper_vmalloc_sync_all();
195
196 if (!chan->sc_table) {
197 /* create syscall table mapping syscall to events */
198 chan->sc_table = kzalloc(sizeof(struct ltt_event *)
199 * ARRAY_SIZE(sc_table), GFP_KERNEL);
200 if (!chan->sc_table)
201 return -ENOMEM;
202 }
203
204 if (!chan->sc_unknown) {
205 struct lttng_kernel_event ev;
206
207 const struct lttng_event_desc *desc =
208 &__event_desc___sys_unknown;
209 memset(&ev, 0, sizeof(ev));
210 strncpy(ev.name, desc->name, LTTNG_SYM_NAME_LEN);
211 ev.name[LTTNG_SYM_NAME_LEN - 1] = '\0';
212 ev.instrumentation = LTTNG_KERNEL_NOOP;
213 chan->sc_unknown = ltt_event_create(chan, &ev, filter,
214 desc);
215 if (!chan->sc_unknown) {
216 return -EINVAL;
217 }
218 }
219
220 /* Allocate events for each syscall, insert into table */
221 for (i = 0; i < ARRAY_SIZE(sc_table); i++) {
222 struct lttng_kernel_event ev;
223 const struct lttng_event_desc *desc = sc_table[i].desc;
224
225 if (!desc) {
226 /* Unknown syscall */
227 continue;
228 }
229 /*
230 * Skip those already populated by previous failed
231 * register for this channel.
232 */
233 if (chan->sc_table[i])
234 continue;
235 memset(&ev, 0, sizeof(ev));
236 strncpy(ev.name, desc->name, LTTNG_SYM_NAME_LEN);
237 ev.name[LTTNG_SYM_NAME_LEN - 1] = '\0';
238 ev.instrumentation = LTTNG_KERNEL_NOOP;
239 chan->sc_table[i] = ltt_event_create(chan, &ev, filter,
240 desc);
241 if (!chan->sc_table[i]) {
242 /*
243 * If something goes wrong in event registration
244 * after the first one, we have no choice but to
245 * leave the previous events in there, until
246 * deleted by session teardown.
247 */
248 return -EINVAL;
249 }
250 }
251 ret = tracepoint_probe_register("sys_enter",
252 (void *) syscall_entry_probe, chan);
253 if (ret)
254 return ret;
255 /*
256 * We change the name of sys_exit tracepoint due to namespace
257 * conflict with sys_exit syscall entry.
258 */
259 ret = tracepoint_probe_register("sys_exit",
260 (void *) __event_probe__exit_syscall, chan);
261 if (ret) {
262 WARN_ON_ONCE(tracepoint_probe_unregister("sys_enter",
263 (void *) syscall_entry_probe, chan));
264 }
265 return ret;
266 }
267
268 /*
269 * Only called at session destruction.
270 */
271 int lttng_syscalls_unregister(struct ltt_channel *chan)
272 {
273 int ret;
274
275 if (!chan->sc_table)
276 return 0;
277 ret = tracepoint_probe_unregister("sys_exit",
278 (void *) __event_probe__exit_syscall, chan);
279 if (ret)
280 return ret;
281 ret = tracepoint_probe_unregister("sys_enter",
282 (void *) syscall_entry_probe, chan);
283 if (ret)
284 return ret;
285 /* ltt_event destroy will be performed by ltt_session_destroy() */
286 kfree(chan->sc_table);
287 return 0;
288 }
This page took 0.035395 seconds and 5 git commands to generate.