Fix unknown syscall support
[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
f405cfce
MD
74static void syscall_entry_unknown(struct ltt_channel *chan,
75 struct pt_regs *regs, unsigned int id)
76{
77 unsigned long args[UNKNOWN_SYSCALL_NRARGS];
78 struct ltt_event *event;
79
80 event = chan->sc_unknown;
81 syscall_get_arguments(current, regs, 0, UNKNOWN_SYSCALL_NRARGS, args);
82 __event_probe__sys_unknown(event, id, args);
83}
84
259b6cb3
MD
85static void syscall_entry_probe(void *__data, struct pt_regs *regs, long id)
86{
87 struct trace_syscall_entry *entry;
88 struct ltt_channel *chan = __data;
89 struct ltt_event *event;
90
f405cfce
MD
91 if (unlikely(id >= ARRAY_SIZE(sc_table))) {
92 syscall_entry_unknown(chan, regs, id);
259b6cb3 93 return;
f405cfce 94 }
259b6cb3 95 event = chan->sc_table[id];
f405cfce
MD
96 if (unlikely(!event)) {
97 syscall_entry_unknown(chan, regs, id);
98 return;
99 }
100 entry = &sc_table[id];
101 WARN_ON_ONCE(!entry);
259b6cb3
MD
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
259b6cb3
MD
191int lttng_syscalls_register(struct ltt_channel *chan, void *filter)
192{
193 unsigned int i;
194 int ret;
195
196 wrapper_vmalloc_sync_all();
259b6cb3
MD
197
198 if (!chan->sc_table) {
199 /* create syscall table mapping syscall to events */
200 chan->sc_table = kzalloc(sizeof(struct ltt_event *)
201 * ARRAY_SIZE(sc_table), GFP_KERNEL);
202 if (!chan->sc_table)
203 return -ENOMEM;
204 }
205
f405cfce
MD
206 if (!chan->sc_unknown) {
207 struct lttng_kernel_event ev;
208
209 const struct lttng_event_desc *desc =
210 &__event_desc___sys_unknown;
211 memset(&ev, 0, sizeof(ev));
212 strncpy(ev.name, desc->name, LTTNG_SYM_NAME_LEN);
213 ev.name[LTTNG_SYM_NAME_LEN - 1] = '\0';
214 ev.instrumentation = LTTNG_KERNEL_NOOP;
215 chan->sc_unknown = ltt_event_create(chan, &ev, filter,
216 desc);
217 if (!chan->sc_unknown) {
218 return -EINVAL;
219 }
220 }
221
259b6cb3
MD
222 /* Allocate events for each syscall, insert into table */
223 for (i = 0; i < ARRAY_SIZE(sc_table); i++) {
224 struct lttng_kernel_event ev;
225 const struct lttng_event_desc *desc = sc_table[i].desc;
226
f405cfce
MD
227 if (!desc) {
228 /* Unknown syscall */
229 continue;
230 }
259b6cb3
MD
231 /*
232 * Skip those already populated by previous failed
233 * register for this channel.
234 */
235 if (chan->sc_table[i])
236 continue;
237 memset(&ev, 0, sizeof(ev));
238 strncpy(ev.name, desc->name, LTTNG_SYM_NAME_LEN);
239 ev.name[LTTNG_SYM_NAME_LEN - 1] = '\0';
240 ev.instrumentation = LTTNG_KERNEL_NOOP;
241 chan->sc_table[i] = ltt_event_create(chan, &ev, filter,
242 desc);
243 if (!chan->sc_table[i]) {
244 /*
245 * If something goes wrong in event registration
246 * after the first one, we have no choice but to
247 * leave the previous events in there, until
248 * deleted by session teardown.
249 */
250 return -EINVAL;
251 }
252 }
253 ret = tracepoint_probe_register("sys_enter",
254 (void *) syscall_entry_probe, chan);
63728b02
MD
255 if (ret)
256 return ret;
257 /*
258 * We change the name of sys_exit tracepoint due to namespace
259 * conflict with sys_exit syscall entry.
260 */
261 ret = tracepoint_probe_register("sys_exit",
262 (void *) __event_probe__exit_syscall, chan);
263 if (ret) {
264 WARN_ON_ONCE(tracepoint_probe_unregister("sys_enter",
265 (void *) syscall_entry_probe, chan));
266 }
259b6cb3
MD
267 return ret;
268}
269
270/*
271 * Only called at session destruction.
272 */
273int lttng_syscalls_unregister(struct ltt_channel *chan)
274{
275 int ret;
276
277 if (!chan->sc_table)
278 return 0;
63728b02
MD
279 ret = tracepoint_probe_unregister("sys_exit",
280 (void *) __event_probe__exit_syscall, chan);
281 if (ret)
282 return ret;
259b6cb3
MD
283 ret = tracepoint_probe_unregister("sys_enter",
284 (void *) syscall_entry_probe, chan);
285 if (ret)
286 return ret;
287 /* ltt_event destroy will be performed by ltt_session_destroy() */
288 kfree(chan->sc_table);
289 return 0;
290}
This page took 0.044611 seconds and 4 git commands to generate.