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

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

tracing/function-graph-tracer: support for x86-64



Impact: extend and enable the function graph tracer to 64-bit x86

This patch implements the support for function graph tracer under x86-64.
Both static and dynamic tracing are supported.

This causes some small CPP conditional asm on arch/x86/kernel/ftrace.c I
wanted to use probe_kernel_read/write to make the return address
saving/patching code more generic but it causes tracing recursion.

That would be perhaps useful to implement a notrace version of these
function for other archs ports.

Note that arch/x86/process_64.c is not traced, as in X86-32. I first
thought __switch_to() was responsible of crashes during tracing because I
believed current task were changed inside but that's actually not the
case (actually yes, but not the "current" pointer).

So I will have to investigate to find the functions that harm here, to
enable tracing of the other functions inside (but there is no issue at
this time, while process_64.c stays out of -pg flags).

A little possible race condition is fixed inside this patch too. When the
tracer allocate a return stack dynamically, the current depth is not
initialized before but after. An interrupt could occur at this time and,
after seeing that the return stack is allocated, the tracer could try to
trace it with a random uninitialized depth. It's a prevention, even if I
hadn't problems with it.

Signed-off-by: default avatarFrederic Weisbecker <fweisbec@gmail.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Tim Bird <tim.bird@am.sony.com>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent 222658e0
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -29,7 +29,7 @@ config X86
	select HAVE_FTRACE_MCOUNT_RECORD
	select HAVE_FTRACE_MCOUNT_RECORD
	select HAVE_DYNAMIC_FTRACE
	select HAVE_DYNAMIC_FTRACE
	select HAVE_FUNCTION_TRACER
	select HAVE_FUNCTION_TRACER
	select HAVE_FUNCTION_GRAPH_TRACER if X86_32
	select HAVE_FUNCTION_GRAPH_TRACER
	select HAVE_FUNCTION_TRACE_MCOUNT_TEST
	select HAVE_FUNCTION_TRACE_MCOUNT_TEST
	select HAVE_KVM if ((X86_32 && !X86_VOYAGER && !X86_VISWS && !X86_NUMAQ) || X86_64)
	select HAVE_KVM if ((X86_32 && !X86_VOYAGER && !X86_VISWS && !X86_NUMAQ) || X86_64)
	select HAVE_ARCH_KGDB if !X86_VOYAGER
	select HAVE_ARCH_KGDB if !X86_VOYAGER
+1 −0
Original line number Original line Diff line number Diff line
@@ -17,6 +17,7 @@ endif
ifdef CONFIG_FUNCTION_GRAPH_TRACER
ifdef CONFIG_FUNCTION_GRAPH_TRACER
# Don't trace __switch_to() but let it for function tracer
# Don't trace __switch_to() but let it for function tracer
CFLAGS_REMOVE_process_32.o = -pg
CFLAGS_REMOVE_process_32.o = -pg
CFLAGS_REMOVE_process_64.o = -pg
endif
endif


#
#
+74 −0
Original line number Original line Diff line number Diff line
@@ -98,6 +98,12 @@ ftrace_call:
	movq (%rsp), %rax
	movq (%rsp), %rax
	addq $0x38, %rsp
	addq $0x38, %rsp


#ifdef CONFIG_FUNCTION_GRAPH_TRACER
.globl ftrace_graph_call
ftrace_graph_call:
	jmp ftrace_stub
#endif

.globl ftrace_stub
.globl ftrace_stub
ftrace_stub:
ftrace_stub:
	retq
	retq
@@ -110,6 +116,12 @@ ENTRY(mcount)


	cmpq $ftrace_stub, ftrace_trace_function
	cmpq $ftrace_stub, ftrace_trace_function
	jnz trace
	jnz trace

#ifdef CONFIG_FUNCTION_GRAPH_TRACER
	cmpq $ftrace_stub, ftrace_graph_return
	jnz ftrace_graph_caller
#endif

.globl ftrace_stub
.globl ftrace_stub
ftrace_stub:
ftrace_stub:
	retq
	retq
@@ -145,6 +157,68 @@ END(mcount)
#endif /* CONFIG_DYNAMIC_FTRACE */
#endif /* CONFIG_DYNAMIC_FTRACE */
#endif /* CONFIG_FUNCTION_TRACER */
#endif /* CONFIG_FUNCTION_TRACER */


#ifdef CONFIG_FUNCTION_GRAPH_TRACER
ENTRY(ftrace_graph_caller)
	cmpl $0, function_trace_stop
	jne ftrace_stub

	subq $0x38, %rsp
	movq %rax, (%rsp)
	movq %rcx, 8(%rsp)
	movq %rdx, 16(%rsp)
	movq %rsi, 24(%rsp)
	movq %rdi, 32(%rsp)
	movq %r8, 40(%rsp)
	movq %r9, 48(%rsp)

	leaq 8(%rbp), %rdi
	movq 0x38(%rsp), %rsi

	call	prepare_ftrace_return

	movq 48(%rsp), %r9
	movq 40(%rsp), %r8
	movq 32(%rsp), %rdi
	movq 24(%rsp), %rsi
	movq 16(%rsp), %rdx
	movq 8(%rsp), %rcx
	movq (%rsp), %rax
	addq $0x38, %rsp
	retq
END(ftrace_graph_caller)


.globl return_to_handler
return_to_handler:
	subq  $80, %rsp

	movq %rax, (%rsp)
	movq %rcx, 8(%rsp)
	movq %rdx, 16(%rsp)
	movq %rsi, 24(%rsp)
	movq %rdi, 32(%rsp)
	movq %r8, 40(%rsp)
	movq %r9, 48(%rsp)
	movq %r10, 56(%rsp)
	movq %r11, 64(%rsp)

	call ftrace_return_to_handler

	movq %rax, 72(%rsp)
	movq 64(%rsp), %r11
	movq 56(%rsp), %r10
	movq 48(%rsp), %r9
	movq 40(%rsp), %r8
	movq 32(%rsp), %rdi
	movq 24(%rsp), %rsi
	movq 16(%rsp), %rdx
	movq 8(%rsp), %rcx
	movq (%rsp), %rax
	addq $72, %rsp
	retq
#endif


#ifndef CONFIG_PREEMPT
#ifndef CONFIG_PREEMPT
#define retint_kernel retint_restore_args
#define retint_kernel retint_restore_args
#endif	
#endif	
+10 −1
Original line number Original line Diff line number Diff line
@@ -467,8 +467,13 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
	 * ignore such a protection.
	 * ignore such a protection.
	 */
	 */
	asm volatile(
	asm volatile(
#ifdef CONFIG_X86_64
		"1: movq (%[parent_old]), %[old]\n"
		"2: movq %[return_hooker], (%[parent_replaced])\n"
#else
		"1: movl (%[parent_old]), %[old]\n"
		"1: movl (%[parent_old]), %[old]\n"
		"2: movl %[return_hooker], (%[parent_replaced])\n"
		"2: movl %[return_hooker], (%[parent_replaced])\n"
#endif
		"   movl $0, %[faulted]\n"
		"   movl $0, %[faulted]\n"


		".section .fixup, \"ax\"\n"
		".section .fixup, \"ax\"\n"
@@ -476,8 +481,13 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
		".previous\n"
		".previous\n"


		".section __ex_table, \"a\"\n"
		".section __ex_table, \"a\"\n"
#ifdef CONFIG_X86_64
		"   .quad 1b, 3b\n"
		"   .quad 2b, 3b\n"
#else
		"   .long 1b, 3b\n"
		"   .long 1b, 3b\n"
		"   .long 2b, 3b\n"
		"   .long 2b, 3b\n"
#endif
		".previous\n"
		".previous\n"


		: [parent_replaced] "=r" (parent), [old] "=r" (old),
		: [parent_replaced] "=r" (parent), [old] "=r" (old),
@@ -509,5 +519,4 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
	ftrace_graph_entry(&trace);
	ftrace_graph_entry(&trace);


}
}

#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+3 −1
Original line number Original line Diff line number Diff line
@@ -1673,8 +1673,10 @@ static int alloc_retstack_tasklist(struct ftrace_ret_stack **ret_stack_list)
		}
		}


		if (t->ret_stack == NULL) {
		if (t->ret_stack == NULL) {
			t->ret_stack = ret_stack_list[start++];
			t->curr_ret_stack = -1;
			t->curr_ret_stack = -1;
			/* Make sure IRQs see the -1 first: */
			barrier();
			t->ret_stack = ret_stack_list[start++];
			atomic_set(&t->trace_overrun, 0);
			atomic_set(&t->trace_overrun, 0);
		}
		}
	} while_each_thread(g, t);
	} while_each_thread(g, t);