Implement detailed syscall event probe
[lttng-modules.git] / probes / lttng-probe-syscalls.c
CommitLineData
ae3dd5f0
MD
1/*
2 * probes/lttng-probe-sched.c
3 *
4 * Copyright 2010 (c) - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
5 *
6 * LTTng sched probes.
17baffe2
MD
7 *
8 * Dual LGPL v2.1/GPL v2 license.
ae3dd5f0
MD
9 */
10
11#include <linux/module.h>
1ec65de1 12#include "../ltt-events.h"
ae3dd5f0 13
054f2ed3
MD
14#ifndef SYSCALL_DETAIL
15
ae3dd5f0
MD
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 */
705e0807 20#include <trace/events/syscalls.h>
ae3dd5f0
MD
21
22/*
23 * Create LTTng tracepoint probes.
24 */
25#define LTTNG_PACKAGE_BUILD
26#define CREATE_TRACE_POINTS
d5869321 27#define TRACE_INCLUDE_PATH ../instrumentation/events/lttng-module
ae3dd5f0 28
d5869321 29#include "../instrumentation/events/lttng-module/syscalls.h"
ae3dd5f0 30
054f2ed3
MD
31#else /* SYSCALL_DETAIL */
32
1ec65de1
MD
33#include <linux/slab.h>
34#include <asm/ptrace.h>
35#include <asm/syscall.h>
36
37static void syscall_entry_probe(void *__data, struct pt_regs *regs, long id);
38static int lttng_syscalls_register_probe(struct lttng_probe_desc *desc);
39static void lttng_syscalls_unregister_probe(struct lttng_probe_desc *desc);
40
41static struct lttng_probe_desc *syscall_probe_desc;
42
054f2ed3
MD
43/*
44 * Create LTTng tracepoint probes.
45 */
46#define LTTNG_PACKAGE_BUILD
47#define CREATE_TRACE_POINTS
48
1ec65de1
MD
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
054f2ed3 53
1ec65de1 54#define TRACE_INCLUDE_PATH ../instrumentation/syscalls/headers
054f2ed3
MD
55
56#include "../instrumentation/syscalls/headers/syscalls.h"
57
1ec65de1
MD
58#undef TP_UNREGISTER_OVERRIDE
59#undef TP_REGISTER_OVERRIDE
60#undef TP_PROBE_CB
054f2ed3
MD
61#undef LTTNG_PACKAGE_BUILD
62#undef CREATE_TRACE_POINTS
63
64struct trace_syscall_entry {
65 void *func;
1ec65de1
MD
66 const struct lttng_event_desc *desc; /* Set dynamically */
67 const struct lttng_event_field *fields;
054f2ed3
MD
68 unsigned int nrargs;
69};
70
1ec65de1
MD
71static int sc_table_desc_filled;
72
054f2ed3
MD
73#define CREATE_SYSCALL_TABLE
74
75#undef TRACE_SYSCALL_TABLE
1ec65de1
MD
76#define TRACE_SYSCALL_TABLE(_name, _nr, _nrargs) \
77 [ _nr ] = { \
78 .func = __event_probe__##_name, \
79 .nrargs = (_nrargs), \
80 .fields = __event_fields___##_name, \
81 },
054f2ed3
MD
82
83static struct trace_syscall_entry sc_table[] = {
84#include "../instrumentation/syscalls/headers/syscalls.h"
85};
1ec65de1 86
054f2ed3
MD
87#undef CREATE_SYSCALL_TABLE
88
1ec65de1
MD
89static 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
191static 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
204static 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
225int 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 */
274int 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
289static 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
296static 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
054f2ed3
MD
302#endif /* SYSCALL_DETAIL */
303
ae3dd5f0
MD
304MODULE_LICENSE("GPL and additional rights");
305MODULE_AUTHOR("Mathieu Desnoyers <mathieu.desnoyers@efficios.com>");
306MODULE_DESCRIPTION("LTTng sched probes");
This page took 0.034798 seconds and 4 git commands to generate.