tracing / arch: Remove direct use of curr_ret_stack
Subsystems (10)
Steven Rostedt
maintainercover tracing / arch: Remove direct use of curr_ret_stack
Folks, I'm working on rewriting the function graph tracer. In order to do so, some changes need to be done that affect architecture specific code. I'm only able to compile test these changes. I would like to have folks check out my repo and give them a test.
The shadow stack of ret_stack is going to be modified to allow multiple users of function graph tracer. It can no longer be referenced directly as an array. A new utility "ftrace_graph_ret_stack()" is available to get the ret_stack entry of a given frame of the shadow stack that architectures can now use. This series converts all users to use the new interface.
git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace.git
ftrace/core
Head SHA1: 51584396cff54aaf57ed0bd353767d71429f77b4
Steven Rostedt (VMware) (6):
fgraph: Add comment to describe ftrace_graph_get_ret_stack x86/ftrace: Do not call function graph from dynamic trampolines powerpc/frace: Use ftrace_graph_get_ret_stack() instead of curr_ret_stack
sparc64: Use ftrace_graph_get_ret_stack() instead of curr_ret_stack
sh: ftrace: Use ftrace_graph_get_ret_stack() instead of curr_ret_stack
arm64: Use ftrace_graph_get_ret_stack() instead of curr_ret_stack
----
arch/arm64/kernel/perf_callchain.c | 2 +- arch/arm64/kernel/process.c | 2 +- arch/arm64/kernel/return_address.c | 2 +- arch/arm64/kernel/stacktrace.c | 12 +++++++----- arch/arm64/kernel/time.c | 2 +- arch/arm64/kernel/traps.c | 2 +- arch/powerpc/kernel/process.c | 13 +++++++++---- arch/sh/kernel/dumpstack.c | 11 +++++++---- arch/sh/kernel/dwarf.c | 9 +++++---- arch/sparc/kernel/perf_event.c | 8 +++++--- arch/sparc/kernel/stacktrace.c | 8 +++++--- arch/sparc/kernel/traps_64.c | 7 ++++--- arch/x86/kernel/ftrace.c | 40 +++++++++++++++++++++----------------- arch/x86/kernel/ftrace_64.S | 8 ++++---- kernel/trace/fgraph.c | 11 +++++++++++ 15 files changed, 84 insertions(+), 53 deletions(-)
Steven Rostedt
maintainerPATCH 1/6 fgraph: Add comment to describe ftrace_graph_get_ret_stack
From: "Steven Rostedt (VMware)" <[email protected]>
The ret_stack should not be accessed directly via the curr_ret_stack variable on the task_struct. This is because the ret_stack is going to be converted into a series of longs and not an array of ret_stack structures. The way that a ret_stack should be retrieved is via the ftrace_graph_get_ret_stack structure, but it needs to be documented on how to use it.
--- kernel/trace/fgraph.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
kernel/trace/fgraph.c +11 -0
@@ -232,6 +232,17 @@ unsigned long ftrace_return_to_handler(unsigned long frame_pointer)return ret; } +/** +* ftrace_graph_get_ret_stack - return the entry of the shadow stack +* @task: The task to read the shadow stack from +* @idx: Index down the shadow stack +* +* Return the ret_struct on the shadow stack of the @task at the +* call graph at @idx starting with zero. If @idx is zero, it +* will return the last saved ret_stack entry. If it is greater than +* zero, it will return the corresponding ret_stack for the depth +* of saved return addresses. +*/ struct ftrace_ret_stack *ftrace_graph_get_ret_stack (struct task_struct *task,int idx) {
Signature · 1 line
2.19.1
Steven Rostedt
maintainerPATCH 2/6 x86/ftrace: Do not call function graph from dynamic trampolines
In reply to Steven RostedtFrom: "Steven Rostedt (VMware)" <[email protected]>
Since commit 79922b8009c07 ("ftrace: Optimize function graph to be called directly"), dynamic trampolines should not be calling the function graph tracer at the end. If they do, it could cause the function graph tracer to trace functions that it filtered out.
Right now it does not cause a problem because there's a test to check if the function graph tracer is attached to the same function as the function tracer, which for now is true. But the function graph tracer is undergoing changes that can make this no longer true which will cause the function graph tracer to trace other functions.
For example:
# cd /sys/kernel/tracing/ # echo do_IRQ > set_ftrace_filter # mkdir instances/foo # echo ip_rcv > instances/foo/set_ftrace_filter # echo function_graph > current_tracer # echo function > instances/foo/current_tracer
Would cause the function graph tracer to trace both do_IRQ and ip_rcv, if the current tests change.
As the current tests prevent this from being a problem, this code does not need to be backported. But it does make the code cleaner.
--- arch/x86/kernel/ftrace.c | 40 ++++++++++++++++++++----------------- arch/x86/kernel/ftrace_64.S | 8 ++++---- 2 files changed, 26 insertions(+), 22 deletions(-)
arch/x86/kernel/ftrace.c +22 -18
@@ -733,6 +733,8 @@ union ftrace_op_code_union { } __attribute__((packed)); }; +#define RET_SIZE 1 +static unsigned long create_trampoline (struct ftrace_ops *ops,unsigned int *tramp_size) {
@@ -742,9 +744,10 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size)unsigned long op_offset;unsigned long offset;unsigned long size; -unsigned long ip; +unsigned long retq;unsigned long *ptr;void *trampoline; +void *ip;/* 48 8b 15 <offset> is movq <offset>(%rip), %rdx */ unsigned const char op_ref[] = {0x48 ,0x8b ,0x15 };union ftrace_op_code_union op_ptr;
@@ -764,27 +767,27 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size)/* * Allocate enough size to store the ftrace_caller code, -* the jmp to ftrace_epilogue, as well as the address of -* the ftrace_ops this trampoline is used for. +* the iret , as well as the address of the ftrace_ops this +* trampoline is used for. */ - trampoline =alloc_tramp (size +MCOUNT_INSN_SIZE +sizeof (void *)); + trampoline =alloc_tramp (size +RET_SIZE +sizeof (void *));if (!trampoline)return 0 ; - *tramp_size = size +MCOUNT_INSN_SIZE +sizeof (void *); + *tramp_size = size +RET_SIZE +sizeof (void *);/* Copy ftrace_caller onto the trampoline memory */ ret =probe_kernel_read (trampoline, (void *)start_offset, size); -if (WARN_ON (ret <0 )) { -tramp_free (trampoline, *tramp_size); -return 0 ; - } +if (WARN_ON (ret <0 )) + goto fail; - ip = (unsigned long )trampoline + size; + ip = trampoline + size; -/* The trampoline ends with a jmp to ftrace_epilogue */ - jmp =ftrace_jmp_replace (ip, (unsigned long )ftrace_epilogue); -memcpy (trampoline + size, jmp,MCOUNT_INSN_SIZE ); +/* The trampoline ends with ret(q) */ + retq = (unsigned long )ftrace_stub; + ret =probe_kernel_read (ip, (void *)retq,RET_SIZE ); +if (WARN_ON (ret <0 )) + goto fail;/* * The address of the ftrace_ops that is used for this trampoline
@@ -794,17 +797,15 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size)* the global function_trace_op variable. */ - ptr = (unsigned long *)(trampoline + size +MCOUNT_INSN_SIZE ); + ptr = (unsigned long *)(trampoline + size +RET_SIZE ); *ptr = (unsigned long )ops; op_offset -= start_offset;memcpy (&op_ptr, trampoline + op_offset,OP_REF_SIZE );/* Are we pointing to the reference? */ -if (WARN_ON (memcmp (op_ptr.op, op_ref,3 ) !=0 )) { -tramp_free (trampoline, *tramp_size); -return 0 ; - } +if (WARN_ON (memcmp (op_ptr.op, op_ref,3 ) !=0 )) + goto fail;/* Load the contents of ptr into the callback parameter */ offset = (unsigned long )ptr;
@@ -819,6 +820,9 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size) ops->flags |=FTRACE_OPS_FL_ALLOC_TRAMP ;return (unsigned long )trampoline; +fail: +tramp_free (trampoline, *tramp_size); +return 0 ; }static unsigned long calc_trampoline_call_offset (bool save_regs)
arch/x86/kernel/ftrace_64.S +4 -4
@@ -171,9 +171,6 @@ GLOBAL(ftrace_call) restore_mcount_regs /* - * The copied trampoline must call ftrace_epilogue as it - * still may need to call the function graph tracer. - * * The code up to this label is copied into trampolines so * think twice before adding any new code or changing the * layout here.
@@ -185,7 +182,10 @@ GLOBAL(ftrace_graph_call) jmp ftrace_stub #endif -/* This is weak to keep gas from relaxing the jumps */ +/* + * This is weak to keep gas from relaxing the jumps. + * It is also used to copy the retq for trampolines. + */ WEAK(ftrace_stub) retq ENDPROC(ftrace_caller)
Signature · 1 line
2.19.1
Steven Rostedt
maintainerPATCH 3/6 powerpc/frace: Use ftrace_graph_get_ret_stack() instead of curr_ret_stack
In reply to Steven RostedtFrom: "Steven Rostedt (VMware)" <[email protected]>
[
Folks, I'm working on rewriting the function graph tracer. In order to do so, some changes need to be done that affect architecture specific code. I'm only able to compile test these changes. I would like to have folks check out my repo and give them a test.
git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace.git
ftrace/core
Head SHA1: 51584396cff54aaf57ed0bd353767d71429f77b4
]
The structure of the ret_stack array on the task struct is going to change, and accessing it directly via the curr_ret_stack index will no longer give the ret_stack entry that holds the return address. To access that, architectures must now use ftrace_graph_get_ret_stack() to get the associated ret_stack that matches the saved return address.
--- arch/powerpc/kernel/process.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
arch/powerpc/kernel/process.c +9 -4
@@ -2061,9 +2061,10 @@ void show_stack(struct task_struct *tsk, unsigned long *stack)int count =0 ;int firstframe =1 ;#ifdef CONFIG_FUNCTION_GRAPH_TRACER -int curr_frame = current->curr_ret_stack; +struct ftrace_ret_stack *ret_stack;extern void return_to_handler (void );unsigned long rth = (unsigned long )return_to_handler; +int curr_frame =0 ;#endif sp = (unsigned long ) stack;
@@ -2089,9 +2090,13 @@ void show_stack(struct task_struct *tsk, unsigned long *stack)printk ("[" REG "] [" REG "] %pS" , sp, ip, (void *)ip);#ifdef CONFIG_FUNCTION_GRAPH_TRACER if ((ip == rth) && curr_frame >=0 ) { -pr_cont (" (%pS)" , - (void *)current->ret_stack[curr_frame].ret); - curr_frame--; + ret_stack =ftrace_graph_get_ret_stack (current, + curr_frame++); +if (ret_stack) +pr_cont (" (%pS)" , + (void *)ret_stack->ret); +else + curr_frame =-1 ; }#endif if (firstframe)
Signature · 1 line
2.19.1
Steven Rostedt
maintainerPATCH 4/6 sparc64: Use ftrace_graph_get_ret_stack() instead of curr_ret_stack
In reply to Steven RostedtFrom: "Steven Rostedt (VMware)" <[email protected]>
[
Folks, I'm working on rewriting the function graph tracer. In order to do so, some changes need to be done that affect architecture specific code. I'm only able to compile test these changes. I would like to have folks check out my repo and give them a test.
git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace.git
ftrace/core
Head SHA1: 51584396cff54aaf57ed0bd353767d71429f77b4
]
The structure of the ret_stack array on the task struct is going to change, and accessing it directly via the curr_ret_stack index will no longer give the ret_stack entry that holds the return address. To access that, architectures must now use ftrace_graph_get_ret_stack() to get the associated ret_stack that matches the saved return address.
--- arch/sparc/kernel/perf_event.c | 8 +++++--- arch/sparc/kernel/stacktrace.c | 8 +++++--- arch/sparc/kernel/traps_64.c | 7 ++++--- 3 files changed, 14 insertions(+), 9 deletions(-)
arch/sparc/kernel/perf_event.c +5 -3
@@ -1767,9 +1767,11 @@ void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry,perf_callchain_store (entry, pc);#ifdef CONFIG_FUNCTION_GRAPH_TRACER if ((pc +8UL ) == (unsigned long ) &return_to_handler) { -int index = current->curr_ret_stack; -if (current->ret_stack && index >= graph) { - pc = current->ret_stack[index - graph].ret; +struct ftrace_ret_stack *ret_stack; + ret_stack =ftrace_graph_get_ret_stack (current, + graph); +if (ret_stack) { + pc = ret_stack->ret;perf_callchain_store (entry, pc); graph++; }
arch/sparc/kernel/stacktrace.c +5 -3
@@ -57,9 +57,11 @@ static void __save_stack_trace(struct thread_info *tp, trace->entries[trace->nr_entries++] = pc;#ifdef CONFIG_FUNCTION_GRAPH_TRACER if ((pc +8UL ) == (unsigned long ) &return_to_handler) { -int index = t->curr_ret_stack; -if (t->ret_stack && index >= graph) { - pc = t->ret_stack[index - graph].ret; +struct ftrace_ret_stack *ret_stack; + ret_stack =ftrace_graph_get_ret_stack (t, + graph); +if (ret_stack) { + pc = ret_stack->ret;if (trace->nr_entries < trace->max_entries) trace->entries[trace->nr_entries++] = pc;
arch/sparc/kernel/traps_64.c +4 -3
@@ -2502,9 +2502,10 @@ void show_stack(struct task_struct *tsk, unsigned long *_ksp)printk (" [%016lx] %pS\n" , pc, (void *) pc);#ifdef CONFIG_FUNCTION_GRAPH_TRACER if ((pc +8UL ) == (unsigned long ) &return_to_handler) { -int index = tsk->curr_ret_stack; -if (tsk->ret_stack && index >= graph) { - pc = tsk->ret_stack[index - graph].ret; +struct ftrace_ret_stack *ret_stack; + ret_stack =ftrace_graph_get_ret_stack (tsk, graph); +if (ret_stack) { + pc = ret_stack->ret;printk (" [%016lx] %pS\n" , pc, (void *) pc); graph++; }
Signature · 1 line
2.19.1
Steven Rostedt
maintainerPATCH 5/6 sh: ftrace: Use ftrace_graph_get_ret_stack() instead of curr_ret_stack
In reply to Steven RostedtFrom: "Steven Rostedt (VMware)" <[email protected]>
[
Folks, I'm working on rewriting the function graph tracer. In order to do so, some changes need to be done that affect architecture specific code. I'm only able to compile test these changes. I would like to have folks check out my repo and give them a test.
git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace.git
ftrace/core
Head SHA1: 51584396cff54aaf57ed0bd353767d71429f77b4
]
The structure of the ret_stack array on the task struct is going to change, and accessing it directly via the curr_ret_stack index will no longer give the ret_stack entry that holds the return address. To access that, architectures must now use ftrace_graph_get_ret_stack() to get the associated ret_stack that matches the saved return address.
--- arch/sh/kernel/dumpstack.c | 11 +++++++---- arch/sh/kernel/dwarf.c | 9 +++++---- 2 files changed, 12 insertions(+), 8 deletions(-)
arch/sh/kernel/dumpstack.c +7 -4
@@ -59,17 +59,20 @@ print_ftrace_graph_addr(unsigned long addr, void *data, struct thread_info *tinfo, int *graph) { struct task_struct *task = tinfo->task; +struct ftrace_ret_stack *ret_stack;unsigned long ret_addr; -int index = task->curr_ret_stack;if (addr != (unsigned long )return_to_handler)return ; -if (!task->ret_stack || index < *graph) +if (!task->ret_stack)return ; - index -= *graph; - ret_addr = task->ret_stack[index].ret; + ret_stack =ftrace_graph_get_ret_stack (task, *graph); +if (!ret_stack) +return ; + + ret_addr = ret_stack->ret; ops->address (data, ret_addr,1 );
arch/sh/kernel/dwarf.c +5 -4
@@ -608,17 +608,18 @@ struct dwarf_frame *dwarf_unwind_stack(unsigned long pc,* expected to find the real return address. */ if (pc == (unsigned long )&return_to_handler) { -int index = current->curr_ret_stack; +struct ftrace_ret_stack *ret_stack; + ret_stack =ftrace_graph_get_ret_stack (current,0 ); +if (ret_stack) + pc = ret_stack->ret;/* * We currently have no way of tracking how many * return_to_handler()'s we've seen. If there is more * than one patched return address on our stack, * complain loudly. */ -WARN_ON (index >0 ); - - pc = current->ret_stack[index].ret; + WARN_ON(ftrace_graph_get_ret_stack(current, 1); }#endif
Signature · 1 line
2.19.1
Steven Rostedt
maintainerPATCH 6/6 arm64: Use ftrace_graph_get_ret_stack() instead of curr_ret_stack
In reply to Steven RostedtFrom: "Steven Rostedt (VMware)" <[email protected]>
[
Folks, I'm working on rewriting the function graph tracer. In order to do so, some changes need to be done that affect architecture specific code. I'm only able to compile test these changes. I would like to have folks check out my repo and give them a test.
git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace.git
ftrace/core
Head SHA1: 51584396cff54aaf57ed0bd353767d71429f77b4
]
The structure of the ret_stack array on the task struct is going to change, and accessing it directly via the curr_ret_stack index will no longer give the ret_stack entry that holds the return address. To access that, architectures must now use ftrace_graph_get_ret_stack() to get the associated ret_stack that matches the saved return address.
--- arch/arm64/kernel/perf_callchain.c | 2 +- arch/arm64/kernel/process.c | 2 +- arch/arm64/kernel/return_address.c | 2 +- arch/arm64/kernel/stacktrace.c | 12 +++++++----- arch/arm64/kernel/time.c | 2 +- arch/arm64/kernel/traps.c | 2 +- 6 files changed, 12 insertions(+), 10 deletions(-)
arch/arm64/kernel/perf_callchain.c +1 -1
@@ -164,7 +164,7 @@ void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, frame.fp = regs->regs[29 ]; frame.pc = regs->pc;#ifdef CONFIG_FUNCTION_GRAPH_TRACER - frame.graph = current->curr_ret_stack; + frame.graph =0 ;#endif walk_stackframe (current, &frame, callchain_trace, entry);
arch/arm64/kernel/process.c +1 -1
@@ -459,7 +459,7 @@ unsigned long get_wchan(struct task_struct *p) frame.fp =thread_saved_fp (p); frame.pc =thread_saved_pc (p);#ifdef CONFIG_FUNCTION_GRAPH_TRACER - frame.graph = p->curr_ret_stack; + frame.graph =0 ;#endif do { if (unwind_frame(p, &frame))
arch/arm64/kernel/return_address.c +1 -1
@@ -44,7 +44,7 @@ void *return_address(unsigned int level) frame.fp = (unsigned long )__builtin_frame_address (0 ); frame.pc = (unsigned long )return_address;/* dummy */ #ifdef CONFIG_FUNCTION_GRAPH_TRACER - frame.graph = current->curr_ret_stack; + frame.graph =0 ;#endif walk_stackframe (current, &frame, save_return_addr, &data);
arch/arm64/kernel/stacktrace.c +7 -5
@@ -59,15 +59,17 @@ int notrace unwind_frame(struct task_struct *tsk, struct stackframe *frame)#ifdef CONFIG_FUNCTION_GRAPH_TRACER if (tsk->ret_stack && (frame->pc == (unsigned long )return_to_handler)) { -if (WARN_ON_ONCE (frame->graph ==-1 )) -return -EINVAL ; +struct ftrace_ret_stack *ret_stack;/* * This is a case where function graph tracer has * modified a return address (LR) in a stack frame * to hook a function return. * So replace it to an original value. */ - frame->pc = tsk->ret_stack[frame->graph--].ret; + ret_stack =ftrace_graph_get_ret_stack (tsk, frame->graph++); +if (WARN_ON_ONCE (!ret_stack)) +return -EINVAL ; + frame->pc = ret_stack->ret; }#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
@@ -134,7 +136,7 @@ void save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace) frame.fp = regs->regs[29 ]; frame.pc = regs->pc;#ifdef CONFIG_FUNCTION_GRAPH_TRACER - frame.graph = current->curr_ret_stack; + frame.graph =0 ;#endif walk_stackframe (current, &frame, save_trace, &data);
@@ -165,7 +167,7 @@ static noinline void __save_stack_trace(struct task_struct *tsk, frame.pc = (unsigned long )__save_stack_trace; }#ifdef CONFIG_FUNCTION_GRAPH_TRACER - frame.graph = tsk->curr_ret_stack; + frame.graph =0 ;#endif walk_stackframe (tsk, &frame, save_trace, &data);
arch/arm64/kernel/time.c +1 -1
@@ -52,7 +52,7 @@ unsigned long profile_pc(struct pt_regs *regs) frame.fp = regs->regs[29 ]; frame.pc = regs->pc;#ifdef CONFIG_FUNCTION_GRAPH_TRACER - frame.graph = current->curr_ret_stack; + frame.graph =0 ;#endif do { int ret = unwind_frame(NULL, &frame);
arch/arm64/kernel/traps.c +1 -1
@@ -122,7 +122,7 @@ void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk) frame.pc =thread_saved_pc (tsk); }#ifdef CONFIG_FUNCTION_GRAPH_TRACER - frame.graph = tsk->curr_ret_stack; + frame.graph =0 ;#endif skip = !!regs;
Signature · 1 line
2.19.1
Re: [PATCH 6/6] arm64: Use ftrace_graph_get_ret_stack() instead of curr_ret_stack
Hi Steven,
Quoted 11 lines · Steven Rostedt
From: "Steven Rostedt (VMware)" <[email protected]>
[
Folks, I'm working on rewriting the function graph tracer. In order to do so, some changes need to be done that affect architecture specific code. I'm only able to compile test these changes. I would like to have folks check out my repo and give them a test.
git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace.git
ftrace/core
Quoted 8 lines
Head SHA1:
51584396cff54aaf57ed0bd353767d71429f77b4
]The structure of the
ret_stackarray on the task struct is going to change, and accessing it directly via thecurr_ret_stackindex will no longer give theret_stackentry that holds the return address. To access that, architectures must now useftrace_graph_get_ret_stack()to get the associatedret_stackthat matches the saved return address.
I gave this branch a spin, but I hit the WARN_ON() fairly easily:
root@debian-guest:~# echo function_graph > /sys/kernel/debug/tracing/current_tracer root@debian-guest:~# ps [ 27.744824] WARNING: CPU: 0 PID: 2457 at arch/arm64/kernel/stacktrace.c:70 unwind_frame+0x78/0x128 [ 27.745174] Modules linked in: [ 27.745375] CPU: 0 PID: 2457 Comm: ps Not tainted 4.20.0-rc3-00038-g51584396cff5 #10814 [ 27.745697] Hardware name: linux,dummy-virt (DT) [ 27.745918] pstate: 80400005 (Nzcv daif +PAN -UAO) [ 27.746151] pc : unwind_frame+0x78/0x128 [ 27.746337] lr : unwind_frame+0x114/0x128 [ 27.746511] sp : ffff00000c893a80 [ 27.746685] x29: ffff00000c893a80 x28: 0000000000000000 [ 27.746914] x27: ffffffffffffffff x26: 0000000000000001 [ 27.747150] x25: 0000000000000049 x24: ffff000009662940 [ 27.747375] x23: 0000000000000001 x22: ffff0000096496c8 [ 27.747622] x21: ffff0000096496c8 x20: 000000000000000f [ 27.747851] x19: ffff00000c893ad0 x18: 0000000000000000 [ 27.748078] x17: 0000000000000000 x16: 0000000000000000 [ 27.748337] x15: 0000000000000000 x14: 0000000000000000 [ 27.748563] x13: ffff80000a6b2500 x12: 0000000000300000 [ 27.748790] x11: 0000000000281bad x10: 0000000000000528 [ 27.749322] x9 : ffff80000c808400 x8 : 0000000000000030 [ 27.749557] x7 : ffff80000a503520 x6 : 0000000000000528 [ 27.749790] x5 : 0000000000019a3b x4 : ffff80000a6b2580 [ 27.750010] x3 : ffff80000c1a0d80 x2 : 0000000000000001 [ 27.750236] x1 : 000000000000000a x0 : 0000000000000000 [ 27.750460] Call trace: [ 27.750587] unwind_frame+0x78/0x128 [ 27.750761] get_wchan+0xa4/0x110 [ 27.750926] do_task_stat+0x8d4/0x9e8 [ 27.751097] proc_tgid_stat+0x40/0x50 [ 27.751271] proc_single_show+0x5c/0xb8 [ 27.751448] seq_read+0x138/0x450 [ 27.751614] __vfs_read+0x60/0x170 [ 27.751782] vfs_read+0x94/0x150 [ 27.751948] ksys_read+0x6c/0xd0 [ 27.752129] __arm64_sys_read+0x24/0x30 [ 27.752309] el0_svc_common+0x94/0xe8 [ 27.752479] el0_svc_handler+0x38/0x78 [ 27.752642] el0_svc+0x8/0xc [ 27.752804] ---[ end trace fdae6e80cafbfff9 ]--- PID TTY TIME CMD 2401 hvc0 00:00:00 login 2451 hvc0 00:00:00 bash 2457 hvc0 00:00:00 ps
This is single cpu kvm guest, with arm64's defconfig and:
| CONFIG_GENERIC_TRACER=y | CONFIG_FUNCTION_TRACER=y | CONFIG_FUNCTION_GRAPH_TRACER=y
This doesn't happen with the same configuration on v4.20-rc4.
Quoted 14 lines
arch/arm64/kernel/stacktrace.c +1
-2@@ -59,15 +59,17 @@ int notrace unwind_frame(struct task_struct *tsk, struct stackframe *frame)#ifdef CONFIG_FUNCTION_GRAPH_TRACER if (tsk->ret_stack && (frame->pc == (unsigned long )return_to_handler)) { -if (WARN_ON_ONCE (frame->graph ==-1 )) -return -EINVAL ; +struct ftrace_ret_stack *ret_stack;/* * This is a case where function graph tracer has * modified a return address (LR) in a stack frame
arch/arm64/kernel/stacktrace.c int notrace unwind_frame(struct task_struct *tsk, struct stackframe *frame) · line 74
Quoted 10 lines
arch/arm64/kernel/stacktrace.c +4
-1* to hook a function return. * So replace it to an original value. */ - frame->pc = tsk->ret_stack[frame->graph--].ret; + ret_stack =ftrace_graph_get_ret_stack (tsk, frame->graph++); +if (WARN_ON_ONCE (!ret_stack)) +return -EINVAL ; + frame->pc = ret_stack->ret; }#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
Thanks,
James
Steven Rostedt
maintainerRe: [PATCH 6/6] arm64: Use ftrace_graph_get_ret_stack() instead of curr_ret_stack
Quoted 4 lines · On Thu, 13 Dec 2018 17:09:35 +0000 James Morse <[email protected]> wrote:
Hi Steven,
I gave this branch a spin, but I hit the
WARN_ON()fairly easily:
Thanks for testing!
Can you see if this patch fixes it for you?
-- Steve
kernel/trace/fgraph.c +2 -2
@@ -246,10 +246,10 @@ unsigned long ftrace_return_to_handler(unsigned long frame_pointer)struct ftrace_ret_stack *ftrace_graph_get_ret_stack (struct task_struct *task,int idx) { - idx = current->curr_ret_stack - idx; + idx = task->curr_ret_stack - idx;if (idx >=0 && idx <= task->curr_ret_stack) -return ¤t->ret_stack[idx]; +return &task->ret_stack[idx];return NULL ; }
James Morse
Tested-byRe: [PATCH 6/6] arm64: Use ftrace_graph_get_ret_stack() instead of curr_ret_stack
Hi Steve,
Quoted 16 lines · Steven Rostedt
Quoted 1 line · On Thu, 13 Dec 2018 17:09:35 +0000 James Morse <[email protected]> wrote:
I gave this branch a spin, but I hit the
WARN_ON()fairly easily:Thanks for testing!
Can you see if this patch fixes it for you?
kernel/trace/fgraph.c +0
-0@@ -246,10 +246,10 @@ unsigned long ftrace_return_to_handler(unsigned long frame_pointer)struct ftrace_ret_stack *ftrace_graph_get_ret_stack (struct task_struct *task,int idx)
kernel/trace/fgraph.c unsigned long ftrace_return_to_handler(unsigned long frame_pointer) · line 255
Quoted 10 lines
kernel/trace/fgraph.c +2
-2{ - idx = current->curr_ret_stack - idx; + idx = task->curr_ret_stack - idx;if (idx >=0 && idx <= task->curr_ret_stack) -return ¤t->ret_stack[idx]; +return &task->ret_stack[idx];return NULL ; }
Heh, yes that fixes it:
Thanks,
James