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