trace_syscalls.c 17 KB
Newer Older
1
#include <trace/syscall.h>
2
#include <trace/events/syscalls.h>
3
#include <linux/slab.h>
4
#include <linux/kernel.h>
5
#include <linux/module.h>	/* for MODULE_NAME_LEN via KSYM_SYMBOL_LEN */
6
#include <linux/ftrace.h>
7
#include <linux/perf_event.h>
8
9
10
11
12
#include <asm/syscall.h>

#include "trace_output.h"
#include "trace.h"

13
static DEFINE_MUTEX(syscall_trace_lock);
14
15
static int sys_refcount_enter;
static int sys_refcount_exit;
16
17
static DECLARE_BITMAP(enabled_enter_syscalls, NR_syscalls);
static DECLARE_BITMAP(enabled_exit_syscalls, NR_syscalls);
18

19
static int syscall_enter_register(struct ftrace_event_call *event,
20
				 enum trace_reg type, void *data);
21
static int syscall_exit_register(struct ftrace_event_call *event,
22
				 enum trace_reg type, void *data);
23

24
25
26
27
28
29
30
31
32
33
34
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;
}

35
struct trace_event_functions enter_syscall_print_funcs = {
36
	.trace		= print_syscall_enter,
37
38
39
};

struct trace_event_functions exit_syscall_print_funcs = {
40
	.trace		= print_syscall_exit,
41
42
};

43
struct ftrace_event_class event_class_syscall_enter = {
44
45
46
47
48
	.system		= "syscalls",
	.reg		= syscall_enter_register,
	.define_fields	= syscall_enter_define_fields,
	.get_fields	= syscall_get_enter_fields,
	.raw_init	= init_syscall_trace,
49
50
51
};

struct ftrace_event_class event_class_syscall_exit = {
52
53
54
55
56
	.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,
57
58
};

59
60
extern struct syscall_metadata *__start_syscalls_metadata[];
extern struct syscall_metadata *__stop_syscalls_metadata[];
61
62
63

static struct syscall_metadata **syscalls_metadata;

64
65
66
67
68
69
70
71
72
73
74
75
76
#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

77
78
static __init struct syscall_metadata *
find_syscall_meta(unsigned long syscall)
79
{
80
81
	struct syscall_metadata **start;
	struct syscall_metadata **stop;
82
83
84
	char str[KSYM_SYMBOL_LEN];


85
86
	start = __start_syscalls_metadata;
	stop = __stop_syscalls_metadata;
87
88
	kallsyms_lookup(syscall, NULL, NULL, NULL, str);

89
90
91
	if (arch_syscall_match_sym_name(str, "sys_ni_syscall"))
		return NULL;

92
	for ( ; start < stop; start++) {
93
		if ((*start)->name && arch_syscall_match_sym_name(str, (*start)->name))
94
			return *start;
95
96
97
98
99
100
101
102
103
104
105
106
	}
	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];
}

107
enum print_line_t
108
109
print_syscall_enter(struct trace_iterator *iter, int flags,
		    struct trace_event *event)
110
111
112
113
114
115
116
{
	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;

117
	trace = (typeof(trace))ent;
118
119
	syscall = trace->nr;
	entry = syscall_nr_to_meta(syscall);
120

121
122
123
	if (!entry)
		goto end;

124
	if (entry->enter_event->event.type != ent->type) {
125
126
127
128
		WARN_ON_ONCE(1);
		goto end;
	}

129
130
131
132
133
134
	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 */
135
		if (trace_flags & TRACE_ITER_VERBOSE) {
136
137
138
139
140
			ret = trace_seq_printf(s, "%s ", entry->types[i]);
			if (!ret)
				return TRACE_TYPE_PARTIAL_LINE;
		}
		/* parameter values */
141
		ret = trace_seq_printf(s, "%s: %lx%s", entry->args[i],
142
				       trace->args[i],
143
				       i == entry->nb_args - 1 ? "" : ", ");
144
145
146
147
		if (!ret)
			return TRACE_TYPE_PARTIAL_LINE;
	}

148
149
150
151
	ret = trace_seq_putc(s, ')');
	if (!ret)
		return TRACE_TYPE_PARTIAL_LINE;

152
end:
153
154
155
156
	ret =  trace_seq_putc(s, '\n');
	if (!ret)
		return TRACE_TYPE_PARTIAL_LINE;

157
158
159
160
	return TRACE_TYPE_HANDLED;
}

enum print_line_t
161
162
print_syscall_exit(struct trace_iterator *iter, int flags,
		   struct trace_event *event)
163
164
165
166
167
168
169
170
{
	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;

171
	trace = (typeof(trace))ent;
172
173
	syscall = trace->nr;
	entry = syscall_nr_to_meta(syscall);
174

175
176
177
178
179
	if (!entry) {
		trace_seq_printf(s, "\n");
		return TRACE_TYPE_HANDLED;
	}

180
	if (entry->exit_event->event.type != ent->type) {
181
182
183
184
		WARN_ON_ONCE(1);
		return TRACE_TYPE_UNHANDLED;
	}

185
186
187
188
189
190
191
192
	ret = trace_seq_printf(s, "%s -> 0x%lx\n", entry->name,
				trace->ret);
	if (!ret)
		return TRACE_TYPE_PARTIAL_LINE;

	return TRACE_TYPE_HANDLED;
}

193
194
195
196
197
extern char *__bad_type_size(void);

#define SYSCALL_FIELD(type, name)					\
	sizeof(type) != sizeof(trace.name) ?				\
		__bad_type_size() :					\
198
199
		#type, #name, offsetof(typeof(trace), name),		\
		sizeof(trace.name), is_signed_type(type)
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
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
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);
}

262
static int syscall_enter_define_fields(struct ftrace_event_call *call)
263
264
{
	struct syscall_trace_enter trace;
265
	struct syscall_metadata *meta = call->data;
266
267
268
269
	int ret;
	int i;
	int offset = offsetof(typeof(trace), args);

270
271
272
273
	ret = trace_define_field(call, SYSCALL_FIELD(int, nr), FILTER_OTHER);
	if (ret)
		return ret;

274
	for (i = 0; i < meta->nb_args; i++) {
275
276
		ret = trace_define_field(call, meta->types[i],
					 meta->args[i], offset,
277
278
					 sizeof(unsigned long), 0,
					 FILTER_OTHER);
279
280
281
282
283
284
		offset += sizeof(unsigned long);
	}

	return ret;
}

285
static int syscall_exit_define_fields(struct ftrace_event_call *call)
286
287
288
289
{
	struct syscall_trace_exit trace;
	int ret;

290
291
292
293
	ret = trace_define_field(call, SYSCALL_FIELD(int, nr), FILTER_OTHER);
	if (ret)
		return ret;

294
	ret = trace_define_field(call, SYSCALL_FIELD(long, ret),
295
				 FILTER_OTHER);
296
297
298
299

	return ret;
}

300
void ftrace_syscall_enter(void *ignore, struct pt_regs *regs, long id)
301
{
302
303
304
	struct syscall_trace_enter *entry;
	struct syscall_metadata *sys_data;
	struct ring_buffer_event *event;
305
	struct ring_buffer *buffer;
306
	int size;
307
308
309
	int syscall_nr;

	syscall_nr = syscall_get_nr(current, regs);
310
311
	if (syscall_nr < 0)
		return;
312
313
	if (!test_bit(syscall_nr, enabled_enter_syscalls))
		return;
314

315
316
317
318
319
320
	sys_data = syscall_nr_to_meta(syscall_nr);
	if (!sys_data)
		return;

	size = sizeof(*entry) + sizeof(unsigned long) * sys_data->nb_args;

321
	event = trace_current_buffer_lock_reserve(&buffer,
322
			sys_data->enter_event->event.type, size, 0, 0);
323
324
325
326
327
328
329
	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);

330
331
332
	if (!filter_current_check_discard(buffer, sys_data->enter_event,
					  entry, event))
		trace_current_buffer_unlock_commit(buffer, event, 0, 0);
333
334
}

335
void ftrace_syscall_exit(void *ignore, struct pt_regs *regs, long ret)
336
{
337
338
339
	struct syscall_trace_exit *entry;
	struct syscall_metadata *sys_data;
	struct ring_buffer_event *event;
340
	struct ring_buffer *buffer;
341
342
343
	int syscall_nr;

	syscall_nr = syscall_get_nr(current, regs);
344
345
	if (syscall_nr < 0)
		return;
346
347
	if (!test_bit(syscall_nr, enabled_exit_syscalls))
		return;
348

349
350
351
352
	sys_data = syscall_nr_to_meta(syscall_nr);
	if (!sys_data)
		return;

353
	event = trace_current_buffer_lock_reserve(&buffer,
354
			sys_data->exit_event->event.type, sizeof(*entry), 0, 0);
355
356
357
358
359
360
361
	if (!event)
		return;

	entry = ring_buffer_event_data(event);
	entry->nr = syscall_nr;
	entry->ret = syscall_get_return_value(current, regs);

362
363
364
	if (!filter_current_check_discard(buffer, sys_data->exit_event,
					  entry, event))
		trace_current_buffer_unlock_commit(buffer, event, 0, 0);
365
366
}

367
int reg_event_syscall_enter(struct ftrace_event_call *call)
368
{
369
370
371
	int ret = 0;
	int num;

372
	num = ((struct syscall_metadata *)call->data)->syscall_nr;
373
	if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls))
374
375
376
		return -ENOSYS;
	mutex_lock(&syscall_trace_lock);
	if (!sys_refcount_enter)
377
		ret = register_trace_sys_enter(ftrace_syscall_enter, NULL);
378
	if (!ret) {
379
380
381
382
383
		set_bit(num, enabled_enter_syscalls);
		sys_refcount_enter++;
	}
	mutex_unlock(&syscall_trace_lock);
	return ret;
384
385
}

386
void unreg_event_syscall_enter(struct ftrace_event_call *call)
387
{
388
	int num;
389

390
	num = ((struct syscall_metadata *)call->data)->syscall_nr;
391
	if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls))
392
393
394
395
396
		return;
	mutex_lock(&syscall_trace_lock);
	sys_refcount_enter--;
	clear_bit(num, enabled_enter_syscalls);
	if (!sys_refcount_enter)
397
		unregister_trace_sys_enter(ftrace_syscall_enter, NULL);
398
399
	mutex_unlock(&syscall_trace_lock);
}
400

401
int reg_event_syscall_exit(struct ftrace_event_call *call)
402
{
403
404
405
	int ret = 0;
	int num;

406
	num = ((struct syscall_metadata *)call->data)->syscall_nr;
407
	if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls))
408
409
410
		return -ENOSYS;
	mutex_lock(&syscall_trace_lock);
	if (!sys_refcount_exit)
411
		ret = register_trace_sys_exit(ftrace_syscall_exit, NULL);
412
	if (!ret) {
413
414
		set_bit(num, enabled_exit_syscalls);
		sys_refcount_exit++;
415
	}
416
417
418
	mutex_unlock(&syscall_trace_lock);
	return ret;
}
419

420
void unreg_event_syscall_exit(struct ftrace_event_call *call)
421
422
{
	int num;
423

424
	num = ((struct syscall_metadata *)call->data)->syscall_nr;
425
	if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls))
426
427
428
429
430
		return;
	mutex_lock(&syscall_trace_lock);
	sys_refcount_exit--;
	clear_bit(num, enabled_exit_syscalls);
	if (!sys_refcount_exit)
431
		unregister_trace_sys_exit(ftrace_syscall_exit, NULL);
432
	mutex_unlock(&syscall_trace_lock);
433
}
434

435
436
437
int init_syscall_trace(struct ftrace_event_call *call)
{
	int id;
438
439
440
441
442
443
444
445
	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\n",
				((struct syscall_metadata *)call->data)->name);
		return -ENOSYS;
	}
446

447
448
449
	if (set_syscall_print_fmt(call) < 0)
		return -ENOMEM;

450
451
452
	id = trace_event_raw_init(call);

	if (id < 0) {
453
		free_syscall_print_fmt(call);
454
		return id;
455
	}
456
457

	return id;
458
459
}

460
unsigned long __init __weak arch_syscall_addr(int nr)
461
462
463
464
{
	return (unsigned long)sys_call_table[nr];
}

465
466
467
468
469
470
int __init init_ftrace_syscalls(void)
{
	struct syscall_metadata *meta;
	unsigned long addr;
	int i;

471
472
	syscalls_metadata = kcalloc(NR_syscalls, sizeof(*syscalls_metadata),
				    GFP_KERNEL);
473
474
475
476
477
478
479
480
	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);
481
482
483
484
		if (!meta)
			continue;

		meta->syscall_nr = i;
485
486
487
488
489
		syscalls_metadata[i] = meta;
	}

	return 0;
}
490
early_initcall(init_ftrace_syscalls);
491

492
#ifdef CONFIG_PERF_EVENTS
493

494
495
496
497
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;
498

499
static void perf_syscall_enter(void *ignore, struct pt_regs *regs, long id)
500
501
{
	struct syscall_metadata *sys_data;
502
	struct syscall_trace_enter *rec;
503
	struct hlist_head *head;
504
	int syscall_nr;
505
	int rctx;
506
	int size;
507
508

	syscall_nr = syscall_get_nr(current, regs);
509
510
	if (syscall_nr < 0)
		return;
511
	if (!test_bit(syscall_nr, enabled_perf_enter_syscalls))
512
513
514
515
516
517
		return;

	sys_data = syscall_nr_to_meta(syscall_nr);
	if (!sys_data)
		return;

518
519
520
521
522
	/* 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);

523
524
	if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE,
		      "perf buffer not large enough"))
525
526
		return;

527
	rec = (struct syscall_trace_enter *)perf_trace_buf_prepare(size,
528
				sys_data->enter_event->event.type, regs, &rctx);
529
530
	if (!rec)
		return;
531
532
533
534

	rec->nr = syscall_nr;
	syscall_get_arguments(current, regs, 0, sys_data->nb_args,
			       (unsigned long *)&rec->args);
535

536
	head = this_cpu_ptr(sys_data->enter_event->perf_events);
537
	perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, head, NULL);
538
539
}

540
int perf_sysenter_enable(struct ftrace_event_call *call)
541
542
543
544
{
	int ret = 0;
	int num;

545
	num = ((struct syscall_metadata *)call->data)->syscall_nr;
546
547

	mutex_lock(&syscall_trace_lock);
548
	if (!sys_perf_refcount_enter)
549
		ret = register_trace_sys_enter(perf_syscall_enter, NULL);
550
551
552
553
	if (ret) {
		pr_info("event trace: Could not activate"
				"syscall entry trace point");
	} else {
554
555
		set_bit(num, enabled_perf_enter_syscalls);
		sys_perf_refcount_enter++;
556
557
558
559
560
	}
	mutex_unlock(&syscall_trace_lock);
	return ret;
}

561
void perf_sysenter_disable(struct ftrace_event_call *call)
562
563
564
{
	int num;

565
	num = ((struct syscall_metadata *)call->data)->syscall_nr;
566
567

	mutex_lock(&syscall_trace_lock);
568
569
570
	sys_perf_refcount_enter--;
	clear_bit(num, enabled_perf_enter_syscalls);
	if (!sys_perf_refcount_enter)
571
		unregister_trace_sys_enter(perf_syscall_enter, NULL);
572
573
574
	mutex_unlock(&syscall_trace_lock);
}

575
static void perf_syscall_exit(void *ignore, struct pt_regs *regs, long ret)
576
577
{
	struct syscall_metadata *sys_data;
578
	struct syscall_trace_exit *rec;
579
	struct hlist_head *head;
580
	int syscall_nr;
581
	int rctx;
582
	int size;
583
584

	syscall_nr = syscall_get_nr(current, regs);
585
586
	if (syscall_nr < 0)
		return;
587
	if (!test_bit(syscall_nr, enabled_perf_exit_syscalls))
588
589
590
591
592
593
		return;

	sys_data = syscall_nr_to_meta(syscall_nr);
	if (!sys_data)
		return;

594
595
596
	/* We can probably do that at build time */
	size = ALIGN(sizeof(*rec) + sizeof(u32), sizeof(u64));
	size -= sizeof(u32);
597

598
599
600
601
	/*
	 * Impossible, but be paranoid with the future
	 * How to put this check outside runtime?
	 */
602
603
	if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE,
		"exit event has grown above perf buffer size"))
604
605
		return;

606
	rec = (struct syscall_trace_exit *)perf_trace_buf_prepare(size,
607
				sys_data->exit_event->event.type, regs, &rctx);
608
609
	if (!rec)
		return;
610
611
612
613

	rec->nr = syscall_nr;
	rec->ret = syscall_get_return_value(current, regs);

614
	head = this_cpu_ptr(sys_data->exit_event->perf_events);
615
	perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, head, NULL);
616
617
}

618
int perf_sysexit_enable(struct ftrace_event_call *call)
619
620
621
622
{
	int ret = 0;
	int num;

623
	num = ((struct syscall_metadata *)call->data)->syscall_nr;
624
625

	mutex_lock(&syscall_trace_lock);
626
	if (!sys_perf_refcount_exit)
627
		ret = register_trace_sys_exit(perf_syscall_exit, NULL);
628
629
	if (ret) {
		pr_info("event trace: Could not activate"
630
				"syscall exit trace point");
631
	} else {
632
633
		set_bit(num, enabled_perf_exit_syscalls);
		sys_perf_refcount_exit++;
634
635
636
637
638
	}
	mutex_unlock(&syscall_trace_lock);
	return ret;
}

639
void perf_sysexit_disable(struct ftrace_event_call *call)
640
641
642
{
	int num;

643
	num = ((struct syscall_metadata *)call->data)->syscall_nr;
644
645

	mutex_lock(&syscall_trace_lock);
646
647
648
	sys_perf_refcount_exit--;
	clear_bit(num, enabled_perf_exit_syscalls);
	if (!sys_perf_refcount_exit)
649
		unregister_trace_sys_exit(perf_syscall_exit, NULL);
650
651
652
	mutex_unlock(&syscall_trace_lock);
}

653
#endif /* CONFIG_PERF_EVENTS */
654

655
static int syscall_enter_register(struct ftrace_event_call *event,
656
				 enum trace_reg type, void *data)
657
658
659
660
661
662
663
664
665
666
667
668
669
670
{
	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;
671
672
	case TRACE_REG_PERF_OPEN:
	case TRACE_REG_PERF_CLOSE:
673
674
	case TRACE_REG_PERF_ADD:
	case TRACE_REG_PERF_DEL:
675
		return 0;
676
677
678
679
680
681
#endif
	}
	return 0;
}

static int syscall_exit_register(struct ftrace_event_call *event,
682
				 enum trace_reg type, void *data)
683
684
685
686
687
688
689
690
691
692
693
694
695
696
{
	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;
697
698
	case TRACE_REG_PERF_OPEN:
	case TRACE_REG_PERF_CLOSE:
699
700
	case TRACE_REG_PERF_ADD:
	case TRACE_REG_PERF_DEL:
701
		return 0;
702
703
704
705
#endif
	}
	return 0;
}