Blame view

kernel/trace/trace_syscalls.c 16.6 KB
47788c58e   Frederic Weisbecker   tracing/syscalls:...
1
  #include <trace/syscall.h>
1c569f026   Josh Stone   tracing: Create g...
2
  #include <trace/events/syscalls.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
3
  #include <linux/slab.h>
ee08c6ecc   Frederic Weisbecker   tracing/ftrace: s...
4
  #include <linux/kernel.h>
56d82e000   Paul Gortmaker   kernel: Add <linu...
5
  #include <linux/module.h>	/* for MODULE_NAME_LEN via KSYM_SYMBOL_LEN */
fb34a08c3   Jason Baron   tracing: Add trac...
6
  #include <linux/ftrace.h>
cdd6c482c   Ingo Molnar   perf: Do the big ...
7
  #include <linux/perf_event.h>
ee08c6ecc   Frederic Weisbecker   tracing/ftrace: s...
8
9
10
11
  #include <asm/syscall.h>
  
  #include "trace_output.h"
  #include "trace.h"
5be71b61f   Frederic Weisbecker   tracing/syscalls:...
12
  static DEFINE_MUTEX(syscall_trace_lock);
fb34a08c3   Jason Baron   tracing: Add trac...
13
14
  static int sys_refcount_enter;
  static int sys_refcount_exit;
57421dbbd   Jason Baron   tracing: Convert ...
15
16
  static DECLARE_BITMAP(enabled_enter_syscalls, NR_syscalls);
  static DECLARE_BITMAP(enabled_exit_syscalls, NR_syscalls);
ee08c6ecc   Frederic Weisbecker   tracing/ftrace: s...
17

2239291ae   Steven Rostedt   tracing: Remove p...
18
19
20
21
  static int syscall_enter_register(struct ftrace_event_call *event,
  				 enum trace_reg type);
  static int syscall_exit_register(struct ftrace_event_call *event,
  				 enum trace_reg type);
2e33af029   Steven Rostedt   tracing: Move fie...
22
23
24
25
26
27
28
29
30
31
  static int syscall_enter_define_fields(struct ftrace_event_call *call);
  static int syscall_exit_define_fields(struct ftrace_event_call *call);
  
  static struct list_head *
  syscall_get_enter_fields(struct ftrace_event_call *call)
  {
  	struct syscall_metadata *entry = call->data;
  
  	return &entry->enter_fields;
  }
80decc70a   Steven Rostedt   tracing: Move pri...
32
  struct trace_event_functions enter_syscall_print_funcs = {
7f85803a2   Lai Jiangshan   tracing: Remove s...
33
  	.trace		= print_syscall_enter,
80decc70a   Steven Rostedt   tracing: Move pri...
34
35
36
  };
  
  struct trace_event_functions exit_syscall_print_funcs = {
7f85803a2   Lai Jiangshan   tracing: Remove s...
37
  	.trace		= print_syscall_exit,
80decc70a   Steven Rostedt   tracing: Move pri...
38
  };
2239291ae   Steven Rostedt   tracing: Remove p...
39
  struct ftrace_event_class event_class_syscall_enter = {
7f85803a2   Lai Jiangshan   tracing: Remove s...
40
41
42
43
44
  	.system		= "syscalls",
  	.reg		= syscall_enter_register,
  	.define_fields	= syscall_enter_define_fields,
  	.get_fields	= syscall_get_enter_fields,
  	.raw_init	= init_syscall_trace,
2239291ae   Steven Rostedt   tracing: Remove p...
45
46
47
  };
  
  struct ftrace_event_class event_class_syscall_exit = {
7f85803a2   Lai Jiangshan   tracing: Remove s...
48
49
50
51
52
  	.system		= "syscalls",
  	.reg		= syscall_exit_register,
  	.define_fields	= syscall_exit_define_fields,
  	.fields		= LIST_HEAD_INIT(event_class_syscall_exit.fields),
  	.raw_init	= init_syscall_trace,
8f0820183   Steven Rostedt   tracing: Create c...
53
  };
3d56e331b   Steven Rostedt   tracing: Replace ...
54
55
  extern struct syscall_metadata *__start_syscalls_metadata[];
  extern struct syscall_metadata *__stop_syscalls_metadata[];
c44fc7708   Frederic Weisbecker   tracing: Move sys...
56
57
  
  static struct syscall_metadata **syscalls_metadata;
b2d554968   Ian Munsie   tracing/syscalls:...
58
59
60
61
62
63
64
65
66
67
68
69
  #ifndef ARCH_HAS_SYSCALL_MATCH_SYM_NAME
  static inline bool arch_syscall_match_sym_name(const char *sym, const char *name)
  {
  	/*
  	 * Only compare after the "sys" prefix. Archs that use
  	 * syscall wrappers may have syscalls symbols aliases prefixed
  	 * with "SyS" instead of "sys", leading to an unwanted
  	 * mismatch.
  	 */
  	return !strcmp(sym + 3, name + 3);
  }
  #endif
3d56e331b   Steven Rostedt   tracing: Replace ...
70
71
  static __init struct syscall_metadata *
  find_syscall_meta(unsigned long syscall)
c44fc7708   Frederic Weisbecker   tracing: Move sys...
72
  {
3d56e331b   Steven Rostedt   tracing: Replace ...
73
74
  	struct syscall_metadata **start;
  	struct syscall_metadata **stop;
c44fc7708   Frederic Weisbecker   tracing: Move sys...
75
  	char str[KSYM_SYMBOL_LEN];
3d56e331b   Steven Rostedt   tracing: Replace ...
76
77
  	start = __start_syscalls_metadata;
  	stop = __stop_syscalls_metadata;
c44fc7708   Frederic Weisbecker   tracing: Move sys...
78
  	kallsyms_lookup(syscall, NULL, NULL, NULL, str);
ae07f551c   Ian Munsie   tracing/syscalls:...
79
80
  	if (arch_syscall_match_sym_name(str, "sys_ni_syscall"))
  		return NULL;
c44fc7708   Frederic Weisbecker   tracing: Move sys...
81
  	for ( ; start < stop; start++) {
b2d554968   Ian Munsie   tracing/syscalls:...
82
  		if ((*start)->name && arch_syscall_match_sym_name(str, (*start)->name))
3d56e331b   Steven Rostedt   tracing: Replace ...
83
  			return *start;
c44fc7708   Frederic Weisbecker   tracing: Move sys...
84
85
86
87
88
89
90
91
92
93
94
  	}
  	return NULL;
  }
  
  static struct syscall_metadata *syscall_nr_to_meta(int nr)
  {
  	if (!syscalls_metadata || nr >= NR_syscalls || nr < 0)
  		return NULL;
  
  	return syscalls_metadata[nr];
  }
bed1ffca0   Frederic Weisbecker   tracing/syscalls:...
95
  enum print_line_t
a9a577638   Steven Rostedt   tracing: Allow ev...
96
97
  print_syscall_enter(struct trace_iterator *iter, int flags,
  		    struct trace_event *event)
bed1ffca0   Frederic Weisbecker   tracing/syscalls:...
98
99
100
101
102
103
  {
  	struct trace_seq *s = &iter->seq;
  	struct trace_entry *ent = iter->ent;
  	struct syscall_trace_enter *trace;
  	struct syscall_metadata *entry;
  	int i, ret, syscall;
64c12e044   Jason Baron   tracing: Add indi...
104
  	trace = (typeof(trace))ent;
bed1ffca0   Frederic Weisbecker   tracing/syscalls:...
105
  	syscall = trace->nr;
bed1ffca0   Frederic Weisbecker   tracing/syscalls:...
106
  	entry = syscall_nr_to_meta(syscall);
64c12e044   Jason Baron   tracing: Add indi...
107

bed1ffca0   Frederic Weisbecker   tracing/syscalls:...
108
109
  	if (!entry)
  		goto end;
32c0edaea   Steven Rostedt   tracing: Remove d...
110
  	if (entry->enter_event->event.type != ent->type) {
64c12e044   Jason Baron   tracing: Add indi...
111
112
113
  		WARN_ON_ONCE(1);
  		goto end;
  	}
bed1ffca0   Frederic Weisbecker   tracing/syscalls:...
114
115
116
117
118
119
  	ret = trace_seq_printf(s, "%s(", entry->name);
  	if (!ret)
  		return TRACE_TYPE_PARTIAL_LINE;
  
  	for (i = 0; i < entry->nb_args; i++) {
  		/* parameter types */
ba8b3a40b   Li Zefan   tracing/syscalls:...
120
  		if (trace_flags & TRACE_ITER_VERBOSE) {
bed1ffca0   Frederic Weisbecker   tracing/syscalls:...
121
122
123
124
125
  			ret = trace_seq_printf(s, "%s ", entry->types[i]);
  			if (!ret)
  				return TRACE_TYPE_PARTIAL_LINE;
  		}
  		/* parameter values */
4539f0770   Li Zefan   tracing/syscalls:...
126
  		ret = trace_seq_printf(s, "%s: %lx%s", entry->args[i],
bed1ffca0   Frederic Weisbecker   tracing/syscalls:...
127
  				       trace->args[i],
4539f0770   Li Zefan   tracing/syscalls:...
128
  				       i == entry->nb_args - 1 ? "" : ", ");
bed1ffca0   Frederic Weisbecker   tracing/syscalls:...
129
130
131
  		if (!ret)
  			return TRACE_TYPE_PARTIAL_LINE;
  	}
4539f0770   Li Zefan   tracing/syscalls:...
132
133
134
  	ret = trace_seq_putc(s, ')');
  	if (!ret)
  		return TRACE_TYPE_PARTIAL_LINE;
bed1ffca0   Frederic Weisbecker   tracing/syscalls:...
135
  end:
4539f0770   Li Zefan   tracing/syscalls:...
136
137
138
139
  	ret =  trace_seq_putc(s, '
  ');
  	if (!ret)
  		return TRACE_TYPE_PARTIAL_LINE;
bed1ffca0   Frederic Weisbecker   tracing/syscalls:...
140
141
142
143
  	return TRACE_TYPE_HANDLED;
  }
  
  enum print_line_t
a9a577638   Steven Rostedt   tracing: Allow ev...
144
145
  print_syscall_exit(struct trace_iterator *iter, int flags,
  		   struct trace_event *event)
bed1ffca0   Frederic Weisbecker   tracing/syscalls:...
146
147
148
149
150
151
152
  {
  	struct trace_seq *s = &iter->seq;
  	struct trace_entry *ent = iter->ent;
  	struct syscall_trace_exit *trace;
  	int syscall;
  	struct syscall_metadata *entry;
  	int ret;
64c12e044   Jason Baron   tracing: Add indi...
153
  	trace = (typeof(trace))ent;
bed1ffca0   Frederic Weisbecker   tracing/syscalls:...
154
  	syscall = trace->nr;
bed1ffca0   Frederic Weisbecker   tracing/syscalls:...
155
  	entry = syscall_nr_to_meta(syscall);
64c12e044   Jason Baron   tracing: Add indi...
156

bed1ffca0   Frederic Weisbecker   tracing/syscalls:...
157
158
159
160
161
  	if (!entry) {
  		trace_seq_printf(s, "
  ");
  		return TRACE_TYPE_HANDLED;
  	}
32c0edaea   Steven Rostedt   tracing: Remove d...
162
  	if (entry->exit_event->event.type != ent->type) {
64c12e044   Jason Baron   tracing: Add indi...
163
164
165
  		WARN_ON_ONCE(1);
  		return TRACE_TYPE_UNHANDLED;
  	}
bed1ffca0   Frederic Weisbecker   tracing/syscalls:...
166
167
168
169
170
171
172
173
  	ret = trace_seq_printf(s, "%s -> 0x%lx
  ", entry->name,
  				trace->ret);
  	if (!ret)
  		return TRACE_TYPE_PARTIAL_LINE;
  
  	return TRACE_TYPE_HANDLED;
  }
e6971969c   Li Zefan   tracing/syscalls:...
174
175
176
177
178
  extern char *__bad_type_size(void);
  
  #define SYSCALL_FIELD(type, name)					\
  	sizeof(type) != sizeof(trace.name) ?				\
  		__bad_type_size() :					\
26a50744b   Tom Zanussi   tracing/events: A...
179
180
  		#type, #name, offsetof(typeof(trace), name),		\
  		sizeof(trace.name), is_signed_type(type)
e6971969c   Li Zefan   tracing/syscalls:...
181

50307a45f   Lai Jiangshan   tracing/syscalls:...
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
  static
  int  __set_enter_print_fmt(struct syscall_metadata *entry, char *buf, int len)
  {
  	int i;
  	int pos = 0;
  
  	/* When len=0, we just calculate the needed length */
  #define LEN_OR_ZERO (len ? len - pos : 0)
  
  	pos += snprintf(buf + pos, LEN_OR_ZERO, "\"");
  	for (i = 0; i < entry->nb_args; i++) {
  		pos += snprintf(buf + pos, LEN_OR_ZERO, "%s: 0x%%0%zulx%s",
  				entry->args[i], sizeof(unsigned long),
  				i == entry->nb_args - 1 ? "" : ", ");
  	}
  	pos += snprintf(buf + pos, LEN_OR_ZERO, "\"");
  
  	for (i = 0; i < entry->nb_args; i++) {
  		pos += snprintf(buf + pos, LEN_OR_ZERO,
  				", ((unsigned long)(REC->%s))", entry->args[i]);
  	}
  
  #undef LEN_OR_ZERO
  
  	/* return the length of print_fmt */
  	return pos;
  }
  
  static int set_syscall_print_fmt(struct ftrace_event_call *call)
  {
  	char *print_fmt;
  	int len;
  	struct syscall_metadata *entry = call->data;
  
  	if (entry->enter_event != call) {
  		call->print_fmt = "\"0x%lx\", REC->ret";
  		return 0;
  	}
  
  	/* First: called with 0 length to calculate the needed length */
  	len = __set_enter_print_fmt(entry, NULL, 0);
  
  	print_fmt = kmalloc(len + 1, GFP_KERNEL);
  	if (!print_fmt)
  		return -ENOMEM;
  
  	/* Second: actually write the @print_fmt */
  	__set_enter_print_fmt(entry, print_fmt, len + 1);
  	call->print_fmt = print_fmt;
  
  	return 0;
  }
  
  static void free_syscall_print_fmt(struct ftrace_event_call *call)
  {
  	struct syscall_metadata *entry = call->data;
  
  	if (entry->enter_event == call)
  		kfree(call->print_fmt);
  }
2e33af029   Steven Rostedt   tracing: Move fie...
242
  static int syscall_enter_define_fields(struct ftrace_event_call *call)
540b7b8d6   Li Zefan   tracing/syscalls:...
243
244
  {
  	struct syscall_trace_enter trace;
31c16b133   Lai Jiangshan   trace_syscalls: S...
245
  	struct syscall_metadata *meta = call->data;
540b7b8d6   Li Zefan   tracing/syscalls:...
246
  	int ret;
540b7b8d6   Li Zefan   tracing/syscalls:...
247
248
  	int i;
  	int offset = offsetof(typeof(trace), args);
0f1ef51d2   Lai Jiangshan   trace_syscalls: A...
249
250
251
  	ret = trace_define_field(call, SYSCALL_FIELD(int, nr), FILTER_OTHER);
  	if (ret)
  		return ret;
540b7b8d6   Li Zefan   tracing/syscalls:...
252
  	for (i = 0; i < meta->nb_args; i++) {
aeaeae118   Frederic Weisbecker   tracing: Restore ...
253
254
  		ret = trace_define_field(call, meta->types[i],
  					 meta->args[i], offset,
43b51ead3   Li Zefan   tracing/filters: ...
255
256
  					 sizeof(unsigned long), 0,
  					 FILTER_OTHER);
540b7b8d6   Li Zefan   tracing/syscalls:...
257
258
259
260
261
  		offset += sizeof(unsigned long);
  	}
  
  	return ret;
  }
2e33af029   Steven Rostedt   tracing: Move fie...
262
  static int syscall_exit_define_fields(struct ftrace_event_call *call)
540b7b8d6   Li Zefan   tracing/syscalls:...
263
264
265
  {
  	struct syscall_trace_exit trace;
  	int ret;
0f1ef51d2   Lai Jiangshan   trace_syscalls: A...
266
267
268
  	ret = trace_define_field(call, SYSCALL_FIELD(int, nr), FILTER_OTHER);
  	if (ret)
  		return ret;
26a50744b   Tom Zanussi   tracing/events: A...
269
  	ret = trace_define_field(call, SYSCALL_FIELD(long, ret),
43b51ead3   Li Zefan   tracing/filters: ...
270
  				 FILTER_OTHER);
540b7b8d6   Li Zefan   tracing/syscalls:...
271
272
273
  
  	return ret;
  }
38516ab59   Steven Rostedt   tracing: Let trac...
274
  void ftrace_syscall_enter(void *ignore, struct pt_regs *regs, long id)
ee08c6ecc   Frederic Weisbecker   tracing/ftrace: s...
275
  {
bed1ffca0   Frederic Weisbecker   tracing/syscalls:...
276
277
278
  	struct syscall_trace_enter *entry;
  	struct syscall_metadata *sys_data;
  	struct ring_buffer_event *event;
e77405ad8   Steven Rostedt   tracing: pass aro...
279
  	struct ring_buffer *buffer;
bed1ffca0   Frederic Weisbecker   tracing/syscalls:...
280
  	int size;
ee08c6ecc   Frederic Weisbecker   tracing/ftrace: s...
281
282
283
  	int syscall_nr;
  
  	syscall_nr = syscall_get_nr(current, regs);
cd0980fc8   Hendrik Brueckner   tracing: Check in...
284
285
  	if (syscall_nr < 0)
  		return;
fb34a08c3   Jason Baron   tracing: Add trac...
286
287
  	if (!test_bit(syscall_nr, enabled_enter_syscalls))
  		return;
ee08c6ecc   Frederic Weisbecker   tracing/ftrace: s...
288

bed1ffca0   Frederic Weisbecker   tracing/syscalls:...
289
290
291
292
293
  	sys_data = syscall_nr_to_meta(syscall_nr);
  	if (!sys_data)
  		return;
  
  	size = sizeof(*entry) + sizeof(unsigned long) * sys_data->nb_args;
fcc19438d   Lai Jiangshan   trace_syscalls: R...
294
  	event = trace_current_buffer_lock_reserve(&buffer,
32c0edaea   Steven Rostedt   tracing: Remove d...
295
  			sys_data->enter_event->event.type, size, 0, 0);
bed1ffca0   Frederic Weisbecker   tracing/syscalls:...
296
297
298
299
300
301
  	if (!event)
  		return;
  
  	entry = ring_buffer_event_data(event);
  	entry->nr = syscall_nr;
  	syscall_get_arguments(current, regs, 0, sys_data->nb_args, entry->args);
e77405ad8   Steven Rostedt   tracing: pass aro...
302
303
304
  	if (!filter_current_check_discard(buffer, sys_data->enter_event,
  					  entry, event))
  		trace_current_buffer_unlock_commit(buffer, event, 0, 0);
ee08c6ecc   Frederic Weisbecker   tracing/ftrace: s...
305
  }
38516ab59   Steven Rostedt   tracing: Let trac...
306
  void ftrace_syscall_exit(void *ignore, struct pt_regs *regs, long ret)
ee08c6ecc   Frederic Weisbecker   tracing/ftrace: s...
307
  {
bed1ffca0   Frederic Weisbecker   tracing/syscalls:...
308
309
310
  	struct syscall_trace_exit *entry;
  	struct syscall_metadata *sys_data;
  	struct ring_buffer_event *event;
e77405ad8   Steven Rostedt   tracing: pass aro...
311
  	struct ring_buffer *buffer;
ee08c6ecc   Frederic Weisbecker   tracing/ftrace: s...
312
313
314
  	int syscall_nr;
  
  	syscall_nr = syscall_get_nr(current, regs);
cd0980fc8   Hendrik Brueckner   tracing: Check in...
315
316
  	if (syscall_nr < 0)
  		return;
fb34a08c3   Jason Baron   tracing: Add trac...
317
318
  	if (!test_bit(syscall_nr, enabled_exit_syscalls))
  		return;
ee08c6ecc   Frederic Weisbecker   tracing/ftrace: s...
319

bed1ffca0   Frederic Weisbecker   tracing/syscalls:...
320
321
322
  	sys_data = syscall_nr_to_meta(syscall_nr);
  	if (!sys_data)
  		return;
fcc19438d   Lai Jiangshan   trace_syscalls: R...
323
  	event = trace_current_buffer_lock_reserve(&buffer,
32c0edaea   Steven Rostedt   tracing: Remove d...
324
  			sys_data->exit_event->event.type, sizeof(*entry), 0, 0);
bed1ffca0   Frederic Weisbecker   tracing/syscalls:...
325
326
327
328
329
330
  	if (!event)
  		return;
  
  	entry = ring_buffer_event_data(event);
  	entry->nr = syscall_nr;
  	entry->ret = syscall_get_return_value(current, regs);
e77405ad8   Steven Rostedt   tracing: pass aro...
331
332
333
  	if (!filter_current_check_discard(buffer, sys_data->exit_event,
  					  entry, event))
  		trace_current_buffer_unlock_commit(buffer, event, 0, 0);
ee08c6ecc   Frederic Weisbecker   tracing/ftrace: s...
334
  }
bd1a5c849   Masami Hiramatsu   tracing: Ftrace d...
335
  int reg_event_syscall_enter(struct ftrace_event_call *call)
ee08c6ecc   Frederic Weisbecker   tracing/ftrace: s...
336
  {
fb34a08c3   Jason Baron   tracing: Add trac...
337
338
  	int ret = 0;
  	int num;
fb34a08c3   Jason Baron   tracing: Add trac...
339

c252f6579   Lai Jiangshan   trace_syscalls: A...
340
  	num = ((struct syscall_metadata *)call->data)->syscall_nr;
3773b389b   Ian Munsie   tracing/syscalls:...
341
  	if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls))
fb34a08c3   Jason Baron   tracing: Add trac...
342
343
344
  		return -ENOSYS;
  	mutex_lock(&syscall_trace_lock);
  	if (!sys_refcount_enter)
38516ab59   Steven Rostedt   tracing: Let trac...
345
  		ret = register_trace_sys_enter(ftrace_syscall_enter, NULL);
3b8e42738   Li Zefan   tracing: Move a p...
346
  	if (!ret) {
fb34a08c3   Jason Baron   tracing: Add trac...
347
348
349
350
351
  		set_bit(num, enabled_enter_syscalls);
  		sys_refcount_enter++;
  	}
  	mutex_unlock(&syscall_trace_lock);
  	return ret;
ee08c6ecc   Frederic Weisbecker   tracing/ftrace: s...
352
  }
bd1a5c849   Masami Hiramatsu   tracing: Ftrace d...
353
  void unreg_event_syscall_enter(struct ftrace_event_call *call)
ee08c6ecc   Frederic Weisbecker   tracing/ftrace: s...
354
  {
fb34a08c3   Jason Baron   tracing: Add trac...
355
  	int num;
ee08c6ecc   Frederic Weisbecker   tracing/ftrace: s...
356

c252f6579   Lai Jiangshan   trace_syscalls: A...
357
  	num = ((struct syscall_metadata *)call->data)->syscall_nr;
3773b389b   Ian Munsie   tracing/syscalls:...
358
  	if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls))
fb34a08c3   Jason Baron   tracing: Add trac...
359
360
361
362
363
  		return;
  	mutex_lock(&syscall_trace_lock);
  	sys_refcount_enter--;
  	clear_bit(num, enabled_enter_syscalls);
  	if (!sys_refcount_enter)
38516ab59   Steven Rostedt   tracing: Let trac...
364
  		unregister_trace_sys_enter(ftrace_syscall_enter, NULL);
fb34a08c3   Jason Baron   tracing: Add trac...
365
366
  	mutex_unlock(&syscall_trace_lock);
  }
ee08c6ecc   Frederic Weisbecker   tracing/ftrace: s...
367

bd1a5c849   Masami Hiramatsu   tracing: Ftrace d...
368
  int reg_event_syscall_exit(struct ftrace_event_call *call)
ee08c6ecc   Frederic Weisbecker   tracing/ftrace: s...
369
  {
fb34a08c3   Jason Baron   tracing: Add trac...
370
371
  	int ret = 0;
  	int num;
fb34a08c3   Jason Baron   tracing: Add trac...
372

c252f6579   Lai Jiangshan   trace_syscalls: A...
373
  	num = ((struct syscall_metadata *)call->data)->syscall_nr;
3773b389b   Ian Munsie   tracing/syscalls:...
374
  	if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls))
fb34a08c3   Jason Baron   tracing: Add trac...
375
376
377
  		return -ENOSYS;
  	mutex_lock(&syscall_trace_lock);
  	if (!sys_refcount_exit)
38516ab59   Steven Rostedt   tracing: Let trac...
378
  		ret = register_trace_sys_exit(ftrace_syscall_exit, NULL);
3b8e42738   Li Zefan   tracing: Move a p...
379
  	if (!ret) {
fb34a08c3   Jason Baron   tracing: Add trac...
380
381
  		set_bit(num, enabled_exit_syscalls);
  		sys_refcount_exit++;
ee08c6ecc   Frederic Weisbecker   tracing/ftrace: s...
382
  	}
fb34a08c3   Jason Baron   tracing: Add trac...
383
384
385
  	mutex_unlock(&syscall_trace_lock);
  	return ret;
  }
ee08c6ecc   Frederic Weisbecker   tracing/ftrace: s...
386

bd1a5c849   Masami Hiramatsu   tracing: Ftrace d...
387
  void unreg_event_syscall_exit(struct ftrace_event_call *call)
fb34a08c3   Jason Baron   tracing: Add trac...
388
389
  {
  	int num;
ee08c6ecc   Frederic Weisbecker   tracing/ftrace: s...
390

c252f6579   Lai Jiangshan   trace_syscalls: A...
391
  	num = ((struct syscall_metadata *)call->data)->syscall_nr;
3773b389b   Ian Munsie   tracing/syscalls:...
392
  	if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls))
fb34a08c3   Jason Baron   tracing: Add trac...
393
394
395
396
397
  		return;
  	mutex_lock(&syscall_trace_lock);
  	sys_refcount_exit--;
  	clear_bit(num, enabled_exit_syscalls);
  	if (!sys_refcount_exit)
38516ab59   Steven Rostedt   tracing: Let trac...
398
  		unregister_trace_sys_exit(ftrace_syscall_exit, NULL);
fb34a08c3   Jason Baron   tracing: Add trac...
399
  	mutex_unlock(&syscall_trace_lock);
ee08c6ecc   Frederic Weisbecker   tracing/ftrace: s...
400
  }
fb34a08c3   Jason Baron   tracing: Add trac...
401

a1301da09   Lai Jiangshan   trace_syscalls: R...
402
403
404
  int init_syscall_trace(struct ftrace_event_call *call)
  {
  	int id;
ba976970c   Ian Munsie   tracing/syscalls:...
405
406
407
408
409
410
411
412
413
  	int num;
  
  	num = ((struct syscall_metadata *)call->data)->syscall_nr;
  	if (num < 0 || num >= NR_syscalls) {
  		pr_debug("syscall %s metadata not mapped, disabling ftrace event
  ",
  				((struct syscall_metadata *)call->data)->name);
  		return -ENOSYS;
  	}
a1301da09   Lai Jiangshan   trace_syscalls: R...
414

50307a45f   Lai Jiangshan   tracing/syscalls:...
415
416
  	if (set_syscall_print_fmt(call) < 0)
  		return -ENOMEM;
c7ef3a900   Steven Rostedt   tracing: Have sys...
417
418
419
  	id = trace_event_raw_init(call);
  
  	if (id < 0) {
50307a45f   Lai Jiangshan   tracing/syscalls:...
420
  		free_syscall_print_fmt(call);
c7ef3a900   Steven Rostedt   tracing: Have sys...
421
  		return id;
50307a45f   Lai Jiangshan   tracing/syscalls:...
422
  	}
c7ef3a900   Steven Rostedt   tracing: Have sys...
423
424
  
  	return id;
a1301da09   Lai Jiangshan   trace_syscalls: R...
425
  }
c763ba06b   Ian Munsie   tracing/syscalls:...
426
  unsigned long __init __weak arch_syscall_addr(int nr)
e7b8e675d   Mike Frysinger   tracing: Unify ar...
427
428
429
  {
  	return (unsigned long)sys_call_table[nr];
  }
c44fc7708   Frederic Weisbecker   tracing: Move sys...
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
  int __init init_ftrace_syscalls(void)
  {
  	struct syscall_metadata *meta;
  	unsigned long addr;
  	int i;
  
  	syscalls_metadata = kzalloc(sizeof(*syscalls_metadata) *
  					NR_syscalls, GFP_KERNEL);
  	if (!syscalls_metadata) {
  		WARN_ON(1);
  		return -ENOMEM;
  	}
  
  	for (i = 0; i < NR_syscalls; i++) {
  		addr = arch_syscall_addr(i);
  		meta = find_syscall_meta(addr);
c252f6579   Lai Jiangshan   trace_syscalls: A...
446
447
448
449
  		if (!meta)
  			continue;
  
  		meta->syscall_nr = i;
c44fc7708   Frederic Weisbecker   tracing: Move sys...
450
451
452
453
454
455
  		syscalls_metadata[i] = meta;
  	}
  
  	return 0;
  }
  core_initcall(init_ftrace_syscalls);
07b139c8c   Li Zefan   perf events: Remo...
456
  #ifdef CONFIG_PERF_EVENTS
19007a67a   Frederic Weisbecker   tracing: Support ...
457

97d5a2200   Frederic Weisbecker   perf: Drop the ob...
458
459
460
461
  static DECLARE_BITMAP(enabled_perf_enter_syscalls, NR_syscalls);
  static DECLARE_BITMAP(enabled_perf_exit_syscalls, NR_syscalls);
  static int sys_perf_refcount_enter;
  static int sys_perf_refcount_exit;
f4b5ffccc   Jason Baron   tracing: Add perf...
462

38516ab59   Steven Rostedt   tracing: Let trac...
463
  static void perf_syscall_enter(void *ignore, struct pt_regs *regs, long id)
f4b5ffccc   Jason Baron   tracing: Add perf...
464
465
  {
  	struct syscall_metadata *sys_data;
20ab4425a   Frederic Weisbecker   tracing: Allocate...
466
  	struct syscall_trace_enter *rec;
1c024eca5   Peter Zijlstra   perf, trace: Opti...
467
  	struct hlist_head *head;
f4b5ffccc   Jason Baron   tracing: Add perf...
468
  	int syscall_nr;
4ed7c92d6   Peter Zijlstra   perf_events: Undo...
469
  	int rctx;
19007a67a   Frederic Weisbecker   tracing: Support ...
470
  	int size;
f4b5ffccc   Jason Baron   tracing: Add perf...
471
472
  
  	syscall_nr = syscall_get_nr(current, regs);
97d5a2200   Frederic Weisbecker   perf: Drop the ob...
473
  	if (!test_bit(syscall_nr, enabled_perf_enter_syscalls))
f4b5ffccc   Jason Baron   tracing: Add perf...
474
475
476
477
478
  		return;
  
  	sys_data = syscall_nr_to_meta(syscall_nr);
  	if (!sys_data)
  		return;
19007a67a   Frederic Weisbecker   tracing: Support ...
479
480
481
482
  	/* get the size after alignment with the u32 buffer size field */
  	size = sizeof(unsigned long) * sys_data->nb_args + sizeof(*rec);
  	size = ALIGN(size + sizeof(u32), sizeof(u64));
  	size -= sizeof(u32);
97d5a2200   Frederic Weisbecker   perf: Drop the ob...
483
484
  	if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE,
  		      "perf buffer not large enough"))
20ab4425a   Frederic Weisbecker   tracing: Allocate...
485
  		return;
97d5a2200   Frederic Weisbecker   perf: Drop the ob...
486
  	rec = (struct syscall_trace_enter *)perf_trace_buf_prepare(size,
ff5f149b6   Steven Rostedt   Merge branch 'per...
487
  				sys_data->enter_event->event.type, regs, &rctx);
430ad5a60   Xiao Guangrong   perf: Factorize t...
488
489
  	if (!rec)
  		return;
20ab4425a   Frederic Weisbecker   tracing: Allocate...
490

20ab4425a   Frederic Weisbecker   tracing: Allocate...
491
492
493
  	rec->nr = syscall_nr;
  	syscall_get_arguments(current, regs, 0, sys_data->nb_args,
  			       (unsigned long *)&rec->args);
1c024eca5   Peter Zijlstra   perf, trace: Opti...
494

3771f0771   Peter Zijlstra   perf_events, trac...
495
  	head = this_cpu_ptr(sys_data->enter_event->perf_events);
1c024eca5   Peter Zijlstra   perf, trace: Opti...
496
  	perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, head);
f4b5ffccc   Jason Baron   tracing: Add perf...
497
  }
97d5a2200   Frederic Weisbecker   perf: Drop the ob...
498
  int perf_sysenter_enable(struct ftrace_event_call *call)
f4b5ffccc   Jason Baron   tracing: Add perf...
499
500
501
  {
  	int ret = 0;
  	int num;
3bbe84e9d   Lai Jiangshan   trace_syscalls: S...
502
  	num = ((struct syscall_metadata *)call->data)->syscall_nr;
f4b5ffccc   Jason Baron   tracing: Add perf...
503
504
  
  	mutex_lock(&syscall_trace_lock);
97d5a2200   Frederic Weisbecker   perf: Drop the ob...
505
  	if (!sys_perf_refcount_enter)
38516ab59   Steven Rostedt   tracing: Let trac...
506
  		ret = register_trace_sys_enter(perf_syscall_enter, NULL);
f4b5ffccc   Jason Baron   tracing: Add perf...
507
508
509
510
  	if (ret) {
  		pr_info("event trace: Could not activate"
  				"syscall entry trace point");
  	} else {
97d5a2200   Frederic Weisbecker   perf: Drop the ob...
511
512
  		set_bit(num, enabled_perf_enter_syscalls);
  		sys_perf_refcount_enter++;
f4b5ffccc   Jason Baron   tracing: Add perf...
513
514
515
516
  	}
  	mutex_unlock(&syscall_trace_lock);
  	return ret;
  }
97d5a2200   Frederic Weisbecker   perf: Drop the ob...
517
  void perf_sysenter_disable(struct ftrace_event_call *call)
f4b5ffccc   Jason Baron   tracing: Add perf...
518
519
  {
  	int num;
3bbe84e9d   Lai Jiangshan   trace_syscalls: S...
520
  	num = ((struct syscall_metadata *)call->data)->syscall_nr;
f4b5ffccc   Jason Baron   tracing: Add perf...
521
522
  
  	mutex_lock(&syscall_trace_lock);
97d5a2200   Frederic Weisbecker   perf: Drop the ob...
523
524
525
  	sys_perf_refcount_enter--;
  	clear_bit(num, enabled_perf_enter_syscalls);
  	if (!sys_perf_refcount_enter)
38516ab59   Steven Rostedt   tracing: Let trac...
526
  		unregister_trace_sys_enter(perf_syscall_enter, NULL);
f4b5ffccc   Jason Baron   tracing: Add perf...
527
528
  	mutex_unlock(&syscall_trace_lock);
  }
38516ab59   Steven Rostedt   tracing: Let trac...
529
  static void perf_syscall_exit(void *ignore, struct pt_regs *regs, long ret)
f4b5ffccc   Jason Baron   tracing: Add perf...
530
531
  {
  	struct syscall_metadata *sys_data;
20ab4425a   Frederic Weisbecker   tracing: Allocate...
532
  	struct syscall_trace_exit *rec;
1c024eca5   Peter Zijlstra   perf, trace: Opti...
533
  	struct hlist_head *head;
f4b5ffccc   Jason Baron   tracing: Add perf...
534
  	int syscall_nr;
4ed7c92d6   Peter Zijlstra   perf_events: Undo...
535
  	int rctx;
20ab4425a   Frederic Weisbecker   tracing: Allocate...
536
  	int size;
f4b5ffccc   Jason Baron   tracing: Add perf...
537
538
  
  	syscall_nr = syscall_get_nr(current, regs);
97d5a2200   Frederic Weisbecker   perf: Drop the ob...
539
  	if (!test_bit(syscall_nr, enabled_perf_exit_syscalls))
f4b5ffccc   Jason Baron   tracing: Add perf...
540
541
542
543
544
  		return;
  
  	sys_data = syscall_nr_to_meta(syscall_nr);
  	if (!sys_data)
  		return;
20ab4425a   Frederic Weisbecker   tracing: Allocate...
545
546
547
  	/* We can probably do that at build time */
  	size = ALIGN(sizeof(*rec) + sizeof(u32), sizeof(u64));
  	size -= sizeof(u32);
19007a67a   Frederic Weisbecker   tracing: Support ...
548

20ab4425a   Frederic Weisbecker   tracing: Allocate...
549
550
551
552
  	/*
  	 * Impossible, but be paranoid with the future
  	 * How to put this check outside runtime?
  	 */
97d5a2200   Frederic Weisbecker   perf: Drop the ob...
553
554
  	if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE,
  		"exit event has grown above perf buffer size"))
20ab4425a   Frederic Weisbecker   tracing: Allocate...
555
  		return;
97d5a2200   Frederic Weisbecker   perf: Drop the ob...
556
  	rec = (struct syscall_trace_exit *)perf_trace_buf_prepare(size,
ff5f149b6   Steven Rostedt   Merge branch 'per...
557
  				sys_data->exit_event->event.type, regs, &rctx);
430ad5a60   Xiao Guangrong   perf: Factorize t...
558
559
  	if (!rec)
  		return;
20ab4425a   Frederic Weisbecker   tracing: Allocate...
560

20ab4425a   Frederic Weisbecker   tracing: Allocate...
561
562
  	rec->nr = syscall_nr;
  	rec->ret = syscall_get_return_value(current, regs);
3771f0771   Peter Zijlstra   perf_events, trac...
563
  	head = this_cpu_ptr(sys_data->exit_event->perf_events);
1c024eca5   Peter Zijlstra   perf, trace: Opti...
564
  	perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, head);
f4b5ffccc   Jason Baron   tracing: Add perf...
565
  }
97d5a2200   Frederic Weisbecker   perf: Drop the ob...
566
  int perf_sysexit_enable(struct ftrace_event_call *call)
f4b5ffccc   Jason Baron   tracing: Add perf...
567
568
569
  {
  	int ret = 0;
  	int num;
3bbe84e9d   Lai Jiangshan   trace_syscalls: S...
570
  	num = ((struct syscall_metadata *)call->data)->syscall_nr;
f4b5ffccc   Jason Baron   tracing: Add perf...
571
572
  
  	mutex_lock(&syscall_trace_lock);
97d5a2200   Frederic Weisbecker   perf: Drop the ob...
573
  	if (!sys_perf_refcount_exit)
38516ab59   Steven Rostedt   tracing: Let trac...
574
  		ret = register_trace_sys_exit(perf_syscall_exit, NULL);
f4b5ffccc   Jason Baron   tracing: Add perf...
575
576
  	if (ret) {
  		pr_info("event trace: Could not activate"
6574658b3   Wenji Huang   tracing: Fix typo...
577
  				"syscall exit trace point");
f4b5ffccc   Jason Baron   tracing: Add perf...
578
  	} else {
97d5a2200   Frederic Weisbecker   perf: Drop the ob...
579
580
  		set_bit(num, enabled_perf_exit_syscalls);
  		sys_perf_refcount_exit++;
f4b5ffccc   Jason Baron   tracing: Add perf...
581
582
583
584
  	}
  	mutex_unlock(&syscall_trace_lock);
  	return ret;
  }
97d5a2200   Frederic Weisbecker   perf: Drop the ob...
585
  void perf_sysexit_disable(struct ftrace_event_call *call)
f4b5ffccc   Jason Baron   tracing: Add perf...
586
587
  {
  	int num;
3bbe84e9d   Lai Jiangshan   trace_syscalls: S...
588
  	num = ((struct syscall_metadata *)call->data)->syscall_nr;
f4b5ffccc   Jason Baron   tracing: Add perf...
589
590
  
  	mutex_lock(&syscall_trace_lock);
97d5a2200   Frederic Weisbecker   perf: Drop the ob...
591
592
593
  	sys_perf_refcount_exit--;
  	clear_bit(num, enabled_perf_exit_syscalls);
  	if (!sys_perf_refcount_exit)
38516ab59   Steven Rostedt   tracing: Let trac...
594
  		unregister_trace_sys_exit(perf_syscall_exit, NULL);
f4b5ffccc   Jason Baron   tracing: Add perf...
595
596
  	mutex_unlock(&syscall_trace_lock);
  }
07b139c8c   Li Zefan   perf events: Remo...
597
  #endif /* CONFIG_PERF_EVENTS */
f4b5ffccc   Jason Baron   tracing: Add perf...
598

2239291ae   Steven Rostedt   tracing: Remove p...
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
  static int syscall_enter_register(struct ftrace_event_call *event,
  				 enum trace_reg type)
  {
  	switch (type) {
  	case TRACE_REG_REGISTER:
  		return reg_event_syscall_enter(event);
  	case TRACE_REG_UNREGISTER:
  		unreg_event_syscall_enter(event);
  		return 0;
  
  #ifdef CONFIG_PERF_EVENTS
  	case TRACE_REG_PERF_REGISTER:
  		return perf_sysenter_enable(event);
  	case TRACE_REG_PERF_UNREGISTER:
  		perf_sysenter_disable(event);
  		return 0;
  #endif
  	}
  	return 0;
  }
  
  static int syscall_exit_register(struct ftrace_event_call *event,
  				 enum trace_reg type)
  {
  	switch (type) {
  	case TRACE_REG_REGISTER:
  		return reg_event_syscall_exit(event);
  	case TRACE_REG_UNREGISTER:
  		unreg_event_syscall_exit(event);
  		return 0;
  
  #ifdef CONFIG_PERF_EVENTS
  	case TRACE_REG_PERF_REGISTER:
  		return perf_sysexit_enable(event);
  	case TRACE_REG_PERF_UNREGISTER:
  		perf_sysexit_disable(event);
  		return 0;
  #endif
  	}
  	return 0;
  }