Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit caf4b323 authored by Frederic Weisbecker's avatar Frederic Weisbecker Committed by Ingo Molnar
Browse files

tracing, x86: add low level support for ftrace return tracing



Impact: add infrastructure for function-return tracing

Add low level support for ftrace return tracing.

This plug-in stores return addresses on the thread_info structure of
the current task.

The index of the current return address is initialized when the task
is the first one (init) and when a process forks (the child). It is
not needed when a task does a sys_execve because after this syscall,
it still needs to return on the kernel functions it called.

Note that the code of return_to_handler has been suggested by Steven
Rostedt as almost all of the ideas of improvements in this V3.

For purpose of security, arch/x86/kernel/process_32.c is not traced
because __switch_to() changes the current task during its execution.
That could cause inconsistency in the stored return address of this
function even if I didn't have any crash after testing with tracing on
this function enabled.

Signed-off-by: default avatarFrederic Weisbecker <fweisbec@gmail.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent d844222a
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@ config 64BIT

config X86_32
	def_bool !64BIT
	select HAVE_FUNCTION_RET_TRACER

config X86_64
	def_bool 64BIT
+26 −0
Original line number Diff line number Diff line
@@ -20,4 +20,30 @@ static inline unsigned long ftrace_call_adjust(unsigned long addr)
#endif /* __ASSEMBLY__ */
#endif /* CONFIG_FUNCTION_TRACER */

#ifdef CONFIG_FUNCTION_RET_TRACER
#define FTRACE_RET_STACK_SIZE 20

#ifndef __ASSEMBLY__

/*
 * Stack of return addresses for functions
 * of a thread.
 * Used in struct thread_info
 */
struct ftrace_ret_stack {
	unsigned long ret;
	unsigned long func;
	unsigned long long calltime;
};

/*
 * Primary handler of a function return.
 * It relays on ftrace_return_to_handler.
 * Defined in entry32.S
 */
extern void return_to_handler(void);

#endif /* __ASSEMBLY__ */
#endif /* CONFIG_FUNCTION_RET_TRACER */

#endif /* _ASM_X86_FTRACE_H */
+24 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
struct task_struct;
struct exec_domain;
#include <asm/processor.h>
#include <asm/ftrace.h>

struct thread_info {
	struct task_struct	*task;		/* main task structure */
@@ -38,8 +39,30 @@ struct thread_info {
						*/
	__u8			supervisor_stack[0];
#endif

#ifdef CONFIG_FUNCTION_RET_TRACER
	/* Index of current stored adress in ret_stack */
	int		curr_ret_stack;
	/* Stack of return addresses for return function tracing */
	struct ftrace_ret_stack	ret_stack[FTRACE_RET_STACK_SIZE];
#endif
};

#ifdef CONFIG_FUNCTION_RET_TRACER
#define INIT_THREAD_INFO(tsk)			\
{						\
	.task		= &tsk,			\
	.exec_domain	= &default_exec_domain,	\
	.flags		= 0,			\
	.cpu		= 0,			\
	.preempt_count	= 1,			\
	.addr_limit	= KERNEL_DS,		\
	.restart_block = {			\
		.fn = do_no_restart_syscall,	\
	},					\
	.curr_ret_stack = -1,\
}
#else
#define INIT_THREAD_INFO(tsk)			\
{						\
	.task		= &tsk,			\
@@ -52,6 +75,7 @@ struct thread_info {
		.fn = do_no_restart_syscall,	\
	},					\
}
#endif

#define init_thread_info	(init_thread_union.thread_info)
#define init_stack		(init_thread_union.stack)
+6 −0
Original line number Diff line number Diff line
@@ -14,6 +14,11 @@ CFLAGS_REMOVE_paravirt-spinlocks.o = -pg
CFLAGS_REMOVE_ftrace.o = -pg
endif

ifdef CONFIG_FUNCTION_RET_TRACER
# Don't trace __switch_to() but let it for function tracer
CFLAGS_REMOVE_process_32.o = -pg
endif

#
# vsyscalls (which work on the user stack) should have
# no stack-protector checks:
@@ -65,6 +70,7 @@ obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o
obj-$(CONFIG_X86_IO_APIC)	+= io_apic.o
obj-$(CONFIG_X86_REBOOTFIXUPS)	+= reboot_fixups_32.o
obj-$(CONFIG_DYNAMIC_FTRACE)	+= ftrace.o
obj-$(CONFIG_FUNCTION_RET_TRACER)	+= ftrace.o
obj-$(CONFIG_KEXEC)		+= machine_kexec_$(BITS).o
obj-$(CONFIG_KEXEC)		+= relocate_kernel_$(BITS).o crash.o
obj-$(CONFIG_CRASH_DUMP)	+= crash_dump_$(BITS).o
+33 −0
Original line number Diff line number Diff line
@@ -1188,6 +1188,10 @@ ENTRY(mcount)

	cmpl $ftrace_stub, ftrace_trace_function
	jnz trace
#ifdef CONFIG_FUNCTION_RET_TRACER
	cmpl $ftrace_stub, ftrace_function_return
	jnz trace_return
#endif
.globl ftrace_stub
ftrace_stub:
	ret
@@ -1206,8 +1210,37 @@ trace:
	popl %edx
	popl %ecx
	popl %eax
	jmp ftrace_stub

#ifdef CONFIG_FUNCTION_RET_TRACER
trace_return:
	pushl %eax
	pushl %ecx
	pushl %edx
	movl 0xc(%esp), %eax
	pushl %eax
	lea 0x4(%ebp), %eax
	pushl %eax
	call prepare_ftrace_return
	addl $8, %esp
	popl %edx
	popl %ecx
	popl %eax
	jmp ftrace_stub

.globl return_to_handler
return_to_handler:
	pushl $0
	pushl %eax
	pushl %ecx
	pushl %edx
	call ftrace_return_to_handler
	movl %eax, 0xc(%esp)
	popl %edx
	popl %ecx
	popl %eax
	ret
#endif /* CONFIG_FUNCTION_RET_TRACER */
END(mcount)
#endif /* CONFIG_DYNAMIC_FTRACE */
#endif /* CONFIG_FUNCTION_TRACER */
Loading