Blame view

kernel/trace/trace_syscalls.c 16.5 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>
fb34a08c3   Jason Baron   tracing: Add trac...
5
  #include <linux/ftrace.h>
cdd6c482c   Ingo Molnar   perf: Do the big ...
6
  #include <linux/perf_event.h>
ee08c6ecc   Frederic Weisbecker   tracing/ftrace: s...
7
8
9
10
  #include <asm/syscall.h>
  
  #include "trace_output.h"
  #include "trace.h"
5be71b61f   Frederic Weisbecker   tracing/syscalls:...
11
  static DEFINE_MUTEX(syscall_trace_lock);
fb34a08c3   Jason Baron   tracing: Add trac...
12
13
  static int sys_refcount_enter;
  static int sys_refcount_exit;
57421dbbd   Jason Baron   tracing: Convert ...
14
15
  static DECLARE_BITMAP(enabled_enter_syscalls, NR_syscalls);
  static DECLARE_BITMAP(enabled_exit_syscalls, NR_syscalls);
ee08c6ecc   Frederic Weisbecker   tracing/ftrace: s...
16

2239291ae   Steven Rostedt   tracing: Remove p...
17
18
19
20
  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...
21
22
23
24
25
26
27
28
29
30
  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...
31
  struct trace_event_functions enter_syscall_print_funcs = {
7f85803a2   Lai Jiangshan   tracing: Remove s...
32
  	.trace		= print_syscall_enter,
80decc70a   Steven Rostedt   tracing: Move pri...
33
34
35
  };
  
  struct trace_event_functions exit_syscall_print_funcs = {
7f85803a2   Lai Jiangshan   tracing: Remove s...
36
  	.trace		= print_syscall_exit,
80decc70a   Steven Rostedt   tracing: Move pri...
37
  };
2239291ae   Steven Rostedt   tracing: Remove p...
38
  struct ftrace_event_class event_class_syscall_enter = {
7f85803a2   Lai Jiangshan   tracing: Remove s...
39
40
41
42
43
  	.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...
44
45
46
  };
  
  struct ftrace_event_class event_class_syscall_exit = {
7f85803a2   Lai Jiangshan   tracing: Remove s...
47
48
49
50
51
  	.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...
52
  };
3d56e331b   Steven Rostedt   tracing: Replace ...
53
54
  extern struct syscall_metadata *__start_syscalls_metadata[];
  extern struct syscall_metadata *__stop_syscalls_metadata[];
c44fc7708   Frederic Weisbecker   tracing: Move sys...
55
56
  
  static struct syscall_metadata **syscalls_metadata;
b2d554968   Ian Munsie   tracing/syscalls:...
57
58
59
60
61
62
63
64
65
66
67
68
  #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 ...
69
70
  static __init struct syscall_metadata *
  find_syscall_meta(unsigned long syscall)
c44fc7708   Frederic Weisbecker   tracing: Move sys...
71
  {
3d56e331b   Steven Rostedt   tracing: Replace ...
72
73
  	struct syscall_metadata **start;
  	struct syscall_metadata **stop;
c44fc7708   Frederic Weisbecker   tracing: Move sys...
74
  	char str[KSYM_SYMBOL_LEN];
3d56e331b   Steven Rostedt   tracing: Replace ...
75
76
  	start = __start_syscalls_metadata;
  	stop = __stop_syscalls_metadata;
c44fc7708   Frederic Weisbecker   tracing: Move sys...
77
  	kallsyms_lookup(syscall, NULL, NULL, NULL, str);
ae07f551c   Ian Munsie   tracing/syscalls:...
78
79
  	if (arch_syscall_match_sym_name(str, "sys_ni_syscall"))
  		return NULL;
c44fc7708   Frederic Weisbecker   tracing: Move sys...
80
  	for ( ; start < stop; start++) {
b2d554968   Ian Munsie   tracing/syscalls:...
81
  		if ((*start)->name && arch_syscall_match_sym_name(str, (*start)->name))
3d56e331b   Steven Rostedt   tracing: Replace ...
82
  			return *start;
c44fc7708   Frederic Weisbecker   tracing: Move sys...
83
84
85
86
87
88
89
90
91
92
93
  	}
  	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:...
94
  enum print_line_t
a9a577638   Steven Rostedt   tracing: Allow ev...
95
96
  print_syscall_enter(struct trace_iterator *iter, int flags,
  		    struct trace_event *event)
bed1ffca0   Frederic Weisbecker   tracing/syscalls:...
97
98
99
100
101
102
  {
  	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...
103
  	trace = (typeof(trace))ent;
bed1ffca0   Frederic Weisbecker   tracing/syscalls:...
104
  	syscall = trace->nr;
bed1ffca0   Frederic Weisbecker   tracing/syscalls:...
105
  	entry = syscall_nr_to_meta(syscall);
64c12e044   Jason Baron   tracing: Add indi...
106

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

bed1ffca0   Frederic Weisbecker   tracing/syscalls:...
156
157
158
159
160
  	if (!entry) {
  		trace_seq_printf(s, "
  ");
  		return TRACE_TYPE_HANDLED;
  	}
32c0edaea   Steven Rostedt   tracing: Remove d...
161
  	if (entry->exit_event->event.type != ent->type) {
64c12e044   Jason Baron   tracing: Add indi...
162
163
164
  		WARN_ON_ONCE(1);
  		return TRACE_TYPE_UNHANDLED;
  	}
bed1ffca0   Frederic Weisbecker   tracing/syscalls:...
165
166
167
168
169
170
171
172
  	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:...
173
174
175
176
177
  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...
178
179
  		#type, #name, offsetof(typeof(trace), name),		\
  		sizeof(trace.name), is_signed_type(type)
e6971969c   Li Zefan   tracing/syscalls:...
180

50307a45f   Lai Jiangshan   tracing/syscalls:...
181
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
  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...
241
  static int syscall_enter_define_fields(struct ftrace_event_call *call)
540b7b8d6   Li Zefan   tracing/syscalls:...
242
243
  {
  	struct syscall_trace_enter trace;
31c16b133   Lai Jiangshan   trace_syscalls: S...
244
  	struct syscall_metadata *meta = call->data;
540b7b8d6   Li Zefan   tracing/syscalls:...
245
  	int ret;
540b7b8d6   Li Zefan   tracing/syscalls:...
246
247
  	int i;
  	int offset = offsetof(typeof(trace), args);
0f1ef51d2   Lai Jiangshan   trace_syscalls: A...
248
249
250
  	ret = trace_define_field(call, SYSCALL_FIELD(int, nr), FILTER_OTHER);
  	if (ret)
  		return ret;
540b7b8d6   Li Zefan   tracing/syscalls:...
251
  	for (i = 0; i < meta->nb_args; i++) {
aeaeae118   Frederic Weisbecker   tracing: Restore ...
252
253
  		ret = trace_define_field(call, meta->types[i],
  					 meta->args[i], offset,
43b51ead3   Li Zefan   tracing/filters: ...
254
255
  					 sizeof(unsigned long), 0,
  					 FILTER_OTHER);
540b7b8d6   Li Zefan   tracing/syscalls:...
256
257
258
259
260
  		offset += sizeof(unsigned long);
  	}
  
  	return ret;
  }
2e33af029   Steven Rostedt   tracing: Move fie...
261
  static int syscall_exit_define_fields(struct ftrace_event_call *call)
540b7b8d6   Li Zefan   tracing/syscalls:...
262
263
264
  {
  	struct syscall_trace_exit trace;
  	int ret;
0f1ef51d2   Lai Jiangshan   trace_syscalls: A...
265
266
267
  	ret = trace_define_field(call, SYSCALL_FIELD(int, nr), FILTER_OTHER);
  	if (ret)
  		return ret;
26a50744b   Tom Zanussi   tracing/events: A...
268
  	ret = trace_define_field(call, SYSCALL_FIELD(long, ret),
43b51ead3   Li Zefan   tracing/filters: ...
269
  				 FILTER_OTHER);
540b7b8d6   Li Zefan   tracing/syscalls:...
270
271
272
  
  	return ret;
  }
38516ab59   Steven Rostedt   tracing: Let trac...
273
  void ftrace_syscall_enter(void *ignore, struct pt_regs *regs, long id)
ee08c6ecc   Frederic Weisbecker   tracing/ftrace: s...
274
  {
bed1ffca0   Frederic Weisbecker   tracing/syscalls:...
275
276
277
  	struct syscall_trace_enter *entry;
  	struct syscall_metadata *sys_data;
  	struct ring_buffer_event *event;
e77405ad8   Steven Rostedt   tracing: pass aro...
278
  	struct ring_buffer *buffer;
bed1ffca0   Frederic Weisbecker   tracing/syscalls:...
279
  	int size;
ee08c6ecc   Frederic Weisbecker   tracing/ftrace: s...
280
281
282
  	int syscall_nr;
  
  	syscall_nr = syscall_get_nr(current, regs);
cd0980fc8   Hendrik Brueckner   tracing: Check in...
283
284
  	if (syscall_nr < 0)
  		return;
fb34a08c3   Jason Baron   tracing: Add trac...
285
286
  	if (!test_bit(syscall_nr, enabled_enter_syscalls))
  		return;
ee08c6ecc   Frederic Weisbecker   tracing/ftrace: s...
287

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

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

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

c252f6579   Lai Jiangshan   trace_syscalls: A...
356
  	num = ((struct syscall_metadata *)call->data)->syscall_nr;
3773b389b   Ian Munsie   tracing/syscalls:...
357
  	if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls))
fb34a08c3   Jason Baron   tracing: Add trac...
358
359
360
361
362
  		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...
363
  		unregister_trace_sys_enter(ftrace_syscall_enter, NULL);
fb34a08c3   Jason Baron   tracing: Add trac...
364
365
  	mutex_unlock(&syscall_trace_lock);
  }
ee08c6ecc   Frederic Weisbecker   tracing/ftrace: s...
366

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

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

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

c252f6579   Lai Jiangshan   trace_syscalls: A...
390
  	num = ((struct syscall_metadata *)call->data)->syscall_nr;
3773b389b   Ian Munsie   tracing/syscalls:...
391
  	if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls))
fb34a08c3   Jason Baron   tracing: Add trac...
392
393
394
395
396
  		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...
397
  		unregister_trace_sys_exit(ftrace_syscall_exit, NULL);
fb34a08c3   Jason Baron   tracing: Add trac...
398
  	mutex_unlock(&syscall_trace_lock);
ee08c6ecc   Frederic Weisbecker   tracing/ftrace: s...
399
  }
fb34a08c3   Jason Baron   tracing: Add trac...
400

a1301da09   Lai Jiangshan   trace_syscalls: R...
401
402
403
  int init_syscall_trace(struct ftrace_event_call *call)
  {
  	int id;
ba976970c   Ian Munsie   tracing/syscalls:...
404
405
406
407
408
409
410
411
412
  	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...
413

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

97d5a2200   Frederic Weisbecker   perf: Drop the ob...
457
458
459
460
  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...
461

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

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

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

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

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

2239291ae   Steven Rostedt   tracing: Remove p...
598
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
  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;
  }