diff options
Diffstat (limited to 'kernel/trace/trace_syscalls.c')
| -rw-r--r-- | kernel/trace/trace_syscalls.c | 86 | 
1 files changed, 86 insertions, 0 deletions
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index 527e17eae57..ddee9c59373 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c @@ -14,6 +14,69 @@ static int sys_refcount_exit;  static DECLARE_BITMAP(enabled_enter_syscalls, NR_syscalls);  static DECLARE_BITMAP(enabled_exit_syscalls, NR_syscalls); +extern unsigned long __start_syscalls_metadata[]; +extern unsigned long __stop_syscalls_metadata[]; + +static struct syscall_metadata **syscalls_metadata; + +static struct syscall_metadata *find_syscall_meta(unsigned long syscall) +{ +	struct syscall_metadata *start; +	struct syscall_metadata *stop; +	char str[KSYM_SYMBOL_LEN]; + + +	start = (struct syscall_metadata *)__start_syscalls_metadata; +	stop = (struct syscall_metadata *)__stop_syscalls_metadata; +	kallsyms_lookup(syscall, NULL, NULL, NULL, str); + +	for ( ; start < stop; start++) { +		/* +		 * 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. +		 */ +		if (start->name && !strcmp(start->name + 3, str + 3)) +			return start; +	} +	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]; +} + +int syscall_name_to_nr(char *name) +{ +	int i; + +	if (!syscalls_metadata) +		return -1; + +	for (i = 0; i < NR_syscalls; i++) { +		if (syscalls_metadata[i]) { +			if (!strcmp(syscalls_metadata[i]->name, name)) +				return i; +		} +	} +	return -1; +} + +void set_syscall_enter_id(int num, int id) +{ +	syscalls_metadata[num]->enter_id = id; +} + +void set_syscall_exit_id(int num, int id) +{ +	syscalls_metadata[num]->exit_id = id; +} +  enum print_line_t  print_syscall_enter(struct trace_iterator *iter, int flags)  { @@ -375,6 +438,29 @@ struct trace_event event_syscall_exit = {  	.trace			= print_syscall_exit,  }; +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); +		syscalls_metadata[i] = meta; +	} + +	return 0; +} +core_initcall(init_ftrace_syscalls); +  #ifdef CONFIG_EVENT_PROFILE  static DECLARE_BITMAP(enabled_prof_enter_syscalls, NR_syscalls);  |