bb7217b46c8a01d148a1137e693c219d73495c54
[lttng-modules.git] / probes / lttng-probe-syscalls.c
1 /*
2 * probes/lttng-probe-sched.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 "../ltt-events.h"
13
14 #ifndef SYSCALL_DETAIL
15
16 /*
17 * Create the tracepoint static inlines from the kernel to validate that our
18 * trace event macros match the kernel we run on.
19 */
20 #include <trace/events/syscalls.h>
21
22 /*
23 * Create LTTng tracepoint probes.
24 */
25 #define LTTNG_PACKAGE_BUILD
26 #define CREATE_TRACE_POINTS
27 #define TRACE_INCLUDE_PATH ../instrumentation/events/lttng-module
28
29 #include "../instrumentation/events/lttng-module/syscalls.h"
30
31 #else /* SYSCALL_DETAIL */
32
33 #include <linux/slab.h>
34 #include <asm/ptrace.h>
35 #include <asm/syscall.h>
36
37 static void syscall_entry_probe(void *__data, struct pt_regs *regs, long id);
38 static int lttng_syscalls_register_probe(struct lttng_probe_desc *desc);
39 static void lttng_syscalls_unregister_probe(struct lttng_probe_desc *desc);
40
41 static struct lttng_probe_desc *syscall_probe_desc;
42
43 /*
44 * Create LTTng tracepoint probes.
45 */
46 #define LTTNG_PACKAGE_BUILD
47 #define CREATE_TRACE_POINTS
48
49 /* Hijack probe callback for system calls */
50 #define TP_PROBE_CB(_template) &syscall_entry_probe
51 #define TP_REGISTER_OVERRIDE lttng_syscalls_register_probe
52 #define TP_UNREGISTER_OVERRIDE lttng_syscalls_unregister_probe
53
54 #define TRACE_INCLUDE_PATH ../instrumentation/syscalls/headers
55
56 #include "../instrumentation/syscalls/headers/syscalls.h"
57
58 #undef TP_UNREGISTER_OVERRIDE
59 #undef TP_REGISTER_OVERRIDE
60 #undef TP_PROBE_CB
61 #undef LTTNG_PACKAGE_BUILD
62 #undef CREATE_TRACE_POINTS
63
64 struct trace_syscall_entry {
65 void *func;
66 const struct lttng_event_desc *desc; /* Set dynamically */
67 const struct lttng_event_field *fields;
68 unsigned int nrargs;
69 };
70
71 static int sc_table_desc_filled;
72
73 #define CREATE_SYSCALL_TABLE
74
75 #undef TRACE_SYSCALL_TABLE
76 #define TRACE_SYSCALL_TABLE(_name, _nr, _nrargs) \
77 [ _nr ] = { \
78 .func = __event_probe__##_name, \
79 .nrargs = (_nrargs), \
80 .fields = __event_fields___##_name, \
81 },
82
83 static struct trace_syscall_entry sc_table[] = {
84 #include "../instrumentation/syscalls/headers/syscalls.h"
85 };
86
87 #undef CREATE_SYSCALL_TABLE
88
89 static void syscall_entry_probe(void *__data, struct pt_regs *regs, long id)
90 {
91 struct trace_syscall_entry *entry;
92 struct ltt_channel *chan = __data;
93 struct ltt_event *event;
94
95 if (unlikely(id >= ARRAY_SIZE(sc_table)))
96 return;
97 entry = &sc_table[id];
98 if (unlikely(!entry->func))
99 return;
100 event = chan->sc_table[id];
101 WARN_ON_ONCE(!event);
102
103 switch (entry->nrargs) {
104 case 0:
105 {
106 void (*fptr)(void *__data) = entry->func;
107
108 fptr(event);
109 break;
110 }
111 case 1:
112 {
113 void (*fptr)(void *__data, unsigned long arg0) = entry->func;
114 unsigned long args[1];
115
116 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
117 fptr(event, args[0]);
118 break;
119 }
120 case 2:
121 {
122 void (*fptr)(void *__data,
123 unsigned long arg0,
124 unsigned long arg1) = entry->func;
125 unsigned long args[2];
126
127 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
128 fptr(event, args[0], args[1]);
129 break;
130 }
131 case 3:
132 {
133 void (*fptr)(void *__data,
134 unsigned long arg0,
135 unsigned long arg1,
136 unsigned long arg2) = entry->func;
137 unsigned long args[3];
138
139 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
140 fptr(event, args[0], args[1], args[2]);
141 break;
142 }
143 case 4:
144 {
145 void (*fptr)(void *__data,
146 unsigned long arg0,
147 unsigned long arg1,
148 unsigned long arg2,
149 unsigned long arg3) = entry->func;
150 unsigned long args[4];
151
152 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
153 fptr(event, args[0], args[1], args[2], args[3]);
154 break;
155 }
156 case 5:
157 {
158 void (*fptr)(void *__data,
159 unsigned long arg0,
160 unsigned long arg1,
161 unsigned long arg2,
162 unsigned long arg3,
163 unsigned long arg4) = entry->func;
164 unsigned long args[5];
165
166 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
167 fptr(event, args[0], args[1], args[2], args[3], args[4]);
168 break;
169 }
170 case 6:
171 {
172 void (*fptr)(void *__data,
173 unsigned long arg0,
174 unsigned long arg1,
175 unsigned long arg2,
176 unsigned long arg3,
177 unsigned long arg4,
178 unsigned long arg5) = entry->func;
179 unsigned long args[6];
180
181 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
182 fptr(event, args[0], args[1], args[2],
183 args[3], args[4], args[5]);
184 break;
185 }
186 default:
187 break;
188 }
189 }
190
191 static const struct lttng_event_desc *find_syscall_desc(unsigned int id)
192 {
193 unsigned int i;
194
195 for (i = 0; i < syscall_probe_desc->nr_events; i++) {
196 if (syscall_probe_desc->event_desc[i].fields
197 == sc_table[id].fields)
198 return &syscall_probe_desc->event_desc[i];
199 }
200 WARN_ON_ONCE(1);
201 return NULL;
202 }
203
204 static void fill_sc_table_desc(void)
205 {
206 unsigned int i;
207
208 if (sc_table_desc_filled)
209 return;
210 /*
211 * This is O(n^2), but rare. Eventually get the TRACE_EVENT code
212 * to emit per-event symbols to skip this.
213 */
214 for (i = 0; i < ARRAY_SIZE(sc_table); i++) {
215 const struct lttng_event_desc **desc = &sc_table[i].desc;
216
217 if (!sc_table[i].func)
218 continue;
219 (*desc) = find_syscall_desc(i);
220 }
221 sc_table_desc_filled = 1;
222 }
223
224
225 int lttng_syscalls_register(struct ltt_channel *chan, void *filter)
226 {
227 unsigned int i;
228 int ret;
229
230 fill_sc_table_desc();
231
232 if (!chan->sc_table) {
233 /* create syscall table mapping syscall to events */
234 chan->sc_table = kzalloc(sizeof(struct ltt_event *)
235 * ARRAY_SIZE(sc_table), GFP_KERNEL);
236 if (!chan->sc_table)
237 return -ENOMEM;
238 }
239
240 /* Allocate events for each syscall, insert into table */
241 for (i = 0; i < ARRAY_SIZE(sc_table); i++) {
242 struct lttng_kernel_event ev;
243 const struct lttng_event_desc *desc = sc_table[i].desc;
244
245 /*
246 * Skip those already populated by previous failed
247 * register for this channel.
248 */
249 if (chan->sc_table[i])
250 continue;
251 memset(&ev, 0, sizeof(ev));
252 strncpy(ev.name, desc->name, LTTNG_SYM_NAME_LEN);
253 ev.name[LTTNG_SYM_NAME_LEN - 1] = '\0';
254 ev.instrumentation = LTTNG_KERNEL_NOOP;
255 chan->sc_table[i] = ltt_event_create(chan, &ev, filter);
256 if (!chan->sc_table[i]) {
257 /*
258 * If something goes wrong in event registration
259 * after the first one, we have no choice but to
260 * leave the previous events in there, until
261 * deleted by session teardown.
262 */
263 return -EINVAL;
264 }
265 }
266 ret = tracepoint_probe_register("syscall_entry",
267 (void *) syscall_entry_probe, chan);
268 return ret;
269 }
270
271 /*
272 * Only called at session destruction.
273 */
274 int lttng_syscalls_unregister(struct ltt_channel *chan)
275 {
276 int ret;
277
278 if (!chan->sc_table)
279 return 0;
280 ret = tracepoint_probe_unregister("syscall_entry",
281 (void *) syscall_entry_probe, chan);
282 if (ret)
283 return ret;
284 /* ltt_event destroy will be performed by ltt_session_destroy() */
285 kfree(chan->sc_table);
286 return 0;
287 }
288
289 static int lttng_syscalls_register_probe(struct lttng_probe_desc *desc)
290 {
291 WARN_ON_ONCE(syscall_probe_desc);
292 syscall_probe_desc = desc;
293 return 0;
294 }
295
296 static void lttng_syscalls_unregister_probe(struct lttng_probe_desc *desc)
297 {
298 WARN_ON_ONCE(!syscall_probe_desc);
299 syscall_probe_desc = NULL;
300 }
301
302 #endif /* SYSCALL_DETAIL */
303
304 MODULE_LICENSE("GPL and additional rights");
305 MODULE_AUTHOR("Mathieu Desnoyers <mathieu.desnoyers@efficios.com>");
306 MODULE_DESCRIPTION("LTTng sched probes");
This page took 0.035157 seconds and 3 git commands to generate.