提交 fe13f95b 编写于 作者: A AKASHI Takahiro 提交者: Will Deacon

arm64: pass a task parameter to unwind_frame()

Function graph tracer modifies a return address (LR) in a stack frame
to hook a function's return. This will result in many useless entries
(return_to_handler) showing up in a call stack list.
We will fix this problem in a later patch ("arm64: ftrace: fix a stack
tracer's output under function graph tracer"). But since real return
addresses are saved in ret_stack[] array in struct task_struct,
unwind functions need to be notified of, in addition to a stack pointer
address, which task is being traced in order to find out real return
addresses.

This patch extends unwind functions' interfaces by adding an extra
argument of a pointer to task_struct.
Signed-off-by: NAKASHI Takahiro <takahiro.akashi@linaro.org>
Signed-off-by: NWill Deacon <will.deacon@arm.com>
上级 79fdee9b
...@@ -16,14 +16,16 @@ ...@@ -16,14 +16,16 @@
#ifndef __ASM_STACKTRACE_H #ifndef __ASM_STACKTRACE_H
#define __ASM_STACKTRACE_H #define __ASM_STACKTRACE_H
struct task_struct;
struct stackframe { struct stackframe {
unsigned long fp; unsigned long fp;
unsigned long sp; unsigned long sp;
unsigned long pc; unsigned long pc;
}; };
extern int unwind_frame(struct stackframe *frame); extern int unwind_frame(struct task_struct *tsk, struct stackframe *frame);
extern void walk_stackframe(struct stackframe *frame, extern void walk_stackframe(struct task_struct *tsk, struct stackframe *frame,
int (*fn)(struct stackframe *, void *), void *data); int (*fn)(struct stackframe *, void *), void *data);
#endif /* __ASM_STACKTRACE_H */ #endif /* __ASM_STACKTRACE_H */
...@@ -165,7 +165,7 @@ void perf_callchain_kernel(struct perf_callchain_entry *entry, ...@@ -165,7 +165,7 @@ void perf_callchain_kernel(struct perf_callchain_entry *entry,
frame.sp = regs->sp; frame.sp = regs->sp;
frame.pc = regs->pc; frame.pc = regs->pc;
walk_stackframe(&frame, callchain_trace, entry); walk_stackframe(current, &frame, callchain_trace, entry);
} }
unsigned long perf_instruction_pointer(struct pt_regs *regs) unsigned long perf_instruction_pointer(struct pt_regs *regs)
......
...@@ -348,7 +348,7 @@ unsigned long get_wchan(struct task_struct *p) ...@@ -348,7 +348,7 @@ unsigned long get_wchan(struct task_struct *p)
do { do {
if (frame.sp < stack_page || if (frame.sp < stack_page ||
frame.sp >= stack_page + THREAD_SIZE || frame.sp >= stack_page + THREAD_SIZE ||
unwind_frame(&frame)) unwind_frame(p, &frame))
return 0; return 0;
if (!in_sched_functions(frame.pc)) if (!in_sched_functions(frame.pc))
return frame.pc; return frame.pc;
......
...@@ -44,7 +44,7 @@ void *return_address(unsigned int level) ...@@ -44,7 +44,7 @@ void *return_address(unsigned int level)
frame.sp = current_stack_pointer; frame.sp = current_stack_pointer;
frame.pc = (unsigned long)return_address; /* dummy */ frame.pc = (unsigned long)return_address; /* dummy */
walk_stackframe(&frame, save_return_addr, &data); walk_stackframe(current, &frame, save_return_addr, &data);
if (!data.level) if (!data.level)
return data.addr; return data.addr;
......
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
* ldp x29, x30, [sp] * ldp x29, x30, [sp]
* add sp, sp, #0x10 * add sp, sp, #0x10
*/ */
int notrace unwind_frame(struct stackframe *frame) int notrace unwind_frame(struct task_struct *tsk, struct stackframe *frame)
{ {
unsigned long high, low; unsigned long high, low;
unsigned long fp = frame->fp; unsigned long fp = frame->fp;
...@@ -99,7 +99,7 @@ int notrace unwind_frame(struct stackframe *frame) ...@@ -99,7 +99,7 @@ int notrace unwind_frame(struct stackframe *frame)
return 0; return 0;
} }
void notrace walk_stackframe(struct stackframe *frame, void notrace walk_stackframe(struct task_struct *tsk, struct stackframe *frame,
int (*fn)(struct stackframe *, void *), void *data) int (*fn)(struct stackframe *, void *), void *data)
{ {
while (1) { while (1) {
...@@ -107,7 +107,7 @@ void notrace walk_stackframe(struct stackframe *frame, ...@@ -107,7 +107,7 @@ void notrace walk_stackframe(struct stackframe *frame,
if (fn(frame, data)) if (fn(frame, data))
break; break;
ret = unwind_frame(frame); ret = unwind_frame(tsk, frame);
if (ret < 0) if (ret < 0)
break; break;
} }
...@@ -159,7 +159,7 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) ...@@ -159,7 +159,7 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
frame.pc = (unsigned long)save_stack_trace_tsk; frame.pc = (unsigned long)save_stack_trace_tsk;
} }
walk_stackframe(&frame, save_trace, &data); walk_stackframe(tsk, &frame, save_trace, &data);
if (trace->nr_entries < trace->max_entries) if (trace->nr_entries < trace->max_entries)
trace->entries[trace->nr_entries++] = ULONG_MAX; trace->entries[trace->nr_entries++] = ULONG_MAX;
} }
......
...@@ -53,7 +53,7 @@ unsigned long profile_pc(struct pt_regs *regs) ...@@ -53,7 +53,7 @@ unsigned long profile_pc(struct pt_regs *regs)
frame.sp = regs->sp; frame.sp = regs->sp;
frame.pc = regs->pc; frame.pc = regs->pc;
do { do {
int ret = unwind_frame(&frame); int ret = unwind_frame(NULL, &frame);
if (ret < 0) if (ret < 0)
return 0; return 0;
} while (in_lock_functions(frame.pc)); } while (in_lock_functions(frame.pc));
......
...@@ -177,7 +177,7 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk) ...@@ -177,7 +177,7 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
int ret; int ret;
dump_backtrace_entry(where); dump_backtrace_entry(where);
ret = unwind_frame(&frame); ret = unwind_frame(tsk, &frame);
if (ret < 0) if (ret < 0)
break; break;
stack = frame.sp; stack = frame.sp;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册