aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm64/kernel/traps.c
diff options
context:
space:
mode:
authorAKASHI Takahiro <takahiro.akashi@linaro.org>2015-12-15 03:33:41 -0500
committerWill Deacon <will.deacon@arm.com>2015-12-21 12:26:02 -0500
commit20380bb390a443b2c5c8800cec59743faf8151b4 (patch)
tree3f9d14ec8f265c8969f322a8cd239f3e946e18bb /arch/arm64/kernel/traps.c
parentfe13f95b720075327a761fe6ddb45b0c90cab504 (diff)
arm64: ftrace: fix a stack tracer's output under function graph tracer
Function graph tracer modifies a return address (LR) in a stack frame to hook a function return. This will result in many useless entries (return_to_handler) showing up in a) a stack tracer's output b) perf call graph (with perf record -g) c) dump_backtrace (at panic et al.) For example, in case of a), $ echo function_graph > /sys/kernel/debug/tracing/current_tracer $ echo 1 > /proc/sys/kernel/stack_trace_enabled $ cat /sys/kernel/debug/tracing/stack_trace Depth Size Location (54 entries) ----- ---- -------- 0) 4504 16 gic_raise_softirq+0x28/0x150 1) 4488 80 smp_cross_call+0x38/0xb8 2) 4408 48 return_to_handler+0x0/0x40 3) 4360 32 return_to_handler+0x0/0x40 ... In case of b), $ echo function_graph > /sys/kernel/debug/tracing/current_tracer $ perf record -e mem:XXX:x -ag -- sleep 10 $ perf report ... | | |--0.22%-- 0x550f8 | | | 0x10888 | | | el0_svc_naked | | | sys_openat | | | return_to_handler | | | return_to_handler ... In case of c), $ echo function_graph > /sys/kernel/debug/tracing/current_tracer $ echo c > /proc/sysrq-trigger ... Call trace: [<ffffffc00044d3ac>] sysrq_handle_crash+0x24/0x30 [<ffffffc000092250>] return_to_handler+0x0/0x40 [<ffffffc000092250>] return_to_handler+0x0/0x40 ... This patch replaces such entries with real addresses preserved in current->ret_stack[] at unwind_frame(). This way, we can cover all the cases. Reviewed-by: Jungseok Lee <jungseoklee85@gmail.com> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org> [will: fixed minor context changes conflicting with irq stack bits] Signed-off-by: Will Deacon <will.deacon@arm.com>
Diffstat (limited to 'arch/arm64/kernel/traps.c')
-rw-r--r--arch/arm64/kernel/traps.c26
1 files changed, 20 insertions, 6 deletions
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index 937008523fa5..bdc293f6adc4 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -147,17 +147,14 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
147{ 147{
148 struct stackframe frame; 148 struct stackframe frame;
149 unsigned long irq_stack_ptr = IRQ_STACK_PTR(smp_processor_id()); 149 unsigned long irq_stack_ptr = IRQ_STACK_PTR(smp_processor_id());
150 int skip;
150 151
151 pr_debug("%s(regs = %p tsk = %p)\n", __func__, regs, tsk); 152 pr_debug("%s(regs = %p tsk = %p)\n", __func__, regs, tsk);
152 153
153 if (!tsk) 154 if (!tsk)
154 tsk = current; 155 tsk = current;
155 156
156 if (regs) { 157 if (tsk == current) {
157 frame.fp = regs->regs[29];
158 frame.sp = regs->sp;
159 frame.pc = regs->pc;
160 } else if (tsk == current) {
161 frame.fp = (unsigned long)__builtin_frame_address(0); 158 frame.fp = (unsigned long)__builtin_frame_address(0);
162 frame.sp = current_stack_pointer; 159 frame.sp = current_stack_pointer;
163 frame.pc = (unsigned long)dump_backtrace; 160 frame.pc = (unsigned long)dump_backtrace;
@@ -169,14 +166,31 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
169 frame.sp = thread_saved_sp(tsk); 166 frame.sp = thread_saved_sp(tsk);
170 frame.pc = thread_saved_pc(tsk); 167 frame.pc = thread_saved_pc(tsk);
171 } 168 }
169#ifdef CONFIG_FUNCTION_GRAPH_TRACER
170 frame.graph = tsk->curr_ret_stack;
171#endif
172 172
173 skip = !!regs;
173 pr_emerg("Call trace:\n"); 174 pr_emerg("Call trace:\n");
174 while (1) { 175 while (1) {
175 unsigned long where = frame.pc; 176 unsigned long where = frame.pc;
176 unsigned long stack; 177 unsigned long stack;
177 int ret; 178 int ret;
178 179
179 dump_backtrace_entry(where); 180 /* skip until specified stack frame */
181 if (!skip) {
182 dump_backtrace_entry(where);
183 } else if (frame.fp == regs->regs[29]) {
184 skip = 0;
185 /*
186 * Mostly, this is the case where this function is
187 * called in panic/abort. As exception handler's
188 * stack frame does not contain the corresponding pc
189 * at which an exception has taken place, use regs->pc
190 * instead.
191 */
192 dump_backtrace_entry(regs->pc);
193 }
180 ret = unwind_frame(tsk, &frame); 194 ret = unwind_frame(tsk, &frame);
181 if (ret < 0) 195 if (ret < 0)
182 break; 196 break;