lkml.org 
[lkml]   [2020]   [Jun]   [10]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Subject[PATCH] mips/ftrace: Fix stack backtrace in unwind_stack_by_address()
Date
Calling the unwind_stack_by_address() function for stack backtrace
will fail, when we use "echo function: stacktrace > set_ftrace_filter".

The stack backtrace as follows:
<...>-3102 [001] ...2 63.557737: <stack trace>
=> 0
=> 0
=> 0
=> 0
=> 0
=> 0
=> 0
=> 0
=>
<idle>-0 [000] .N.2 63.558793: <stack trace>

The reason is that when performing stack backtrace, the "ftrace_call"
and "ftrace_graph_call" global symbols in ftrace_caller() are
treated as functions.

If CONFIG_FUNCTION_GRAPH_TRACER is defined, the value in the "ra"
register is the address of ftrace_graph_call when the stack
backtrace back to ftrace_caller(). ”ftrace_graph_call“ is a global
symbol, and the value of "ofs" is set to zero when the
kallsyms_lookup_size_offset() is called. Otherwise, the value
in the "ra" register is the address of ftrace_call+8. "ftrace_call"
is the global symbol, and return one when the get_frame_info() is called.

Signed-off-by: YuanJunQing <yuanjunqing66@163.com>
---
arch/mips/kernel/process.c | 20 ++++++++++++++++++--
1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index b2a797557825..ac4fe79bc5bc 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -53,6 +53,8 @@
#include <asm/inst.h>
#include <asm/stacktrace.h>
#include <asm/irq_regs.h>
+#include <linux/ftrace.h>
+#include <generated/asm-offsets.h>

#ifdef CONFIG_HOTPLUG_CPU
void arch_cpu_idle_dead(void)
@@ -569,6 +571,13 @@ unsigned long notrace unwind_stack_by_address(unsigned long stack_page,
* Return ra if an exception occurred at the first instruction
*/
if (unlikely(ofs == 0)) {
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ extern void ftrace_graph_call(void);
+ if ((pc == (unsigned long)ftrace_graph_call)) {
+ pc = ((unsigned long *)(*sp))[PT_R31/sizeof(long)];
+ *sp += PT_SIZE;
+ } else
+#endif
pc = *ra;
*ra = 0;
return pc;
@@ -583,16 +592,23 @@ unsigned long notrace unwind_stack_by_address(unsigned long stack_page,
if (*sp < low || *sp + info.frame_size > high)
return 0;

- if (leaf)
+ if (leaf) {
/*
* For some extreme cases, get_frame_info() can
* consider wrongly a nested function as a leaf
* one. In that cases avoid to return always the
* same value.
*/
+#ifdef CONFIG_DYNAMIC_FTRACE
+ if (info.func == (void *)ftrace_call) {
+ pc = ((unsigned long *)(*sp))[PT_R31/sizeof(long)];
+ info.frame_size = PT_SIZE;
+ } else
+#endif
pc = pc != *ra ? *ra : 0;
- else
+ } else {
pc = ((unsigned long *)(*sp))[info.pc_offset];
+ }

*sp += info.frame_size;
*ra = 0;
--
2.17.1
\
 
 \ /
  Last update: 2020-06-10 14:14    [W:0.200 / U:0.308 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site