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