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: AKASHI Takahiro <takahiro.akashi@linaro.org> Signed-off-by: Will Deacon <will.deacon@arm.com>
This commit is contained in:
parent
79fdee9b63
commit
fe13f95b72
|
@ -16,14 +16,16 @@
|
|||
#ifndef __ASM_STACKTRACE_H
|
||||
#define __ASM_STACKTRACE_H
|
||||
|
||||
struct task_struct;
|
||||
|
||||
struct stackframe {
|
||||
unsigned long fp;
|
||||
unsigned long sp;
|
||||
unsigned long pc;
|
||||
};
|
||||
|
||||
extern int unwind_frame(struct stackframe *frame);
|
||||
extern void walk_stackframe(struct stackframe *frame,
|
||||
extern int unwind_frame(struct task_struct *tsk, struct stackframe *frame);
|
||||
extern void walk_stackframe(struct task_struct *tsk, struct stackframe *frame,
|
||||
int (*fn)(struct stackframe *, void *), void *data);
|
||||
|
||||
#endif /* __ASM_STACKTRACE_H */
|
||||
|
|
|
@ -165,7 +165,7 @@ void perf_callchain_kernel(struct perf_callchain_entry *entry,
|
|||
frame.sp = regs->sp;
|
||||
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)
|
||||
|
|
|
@ -348,7 +348,7 @@ unsigned long get_wchan(struct task_struct *p)
|
|||
do {
|
||||
if (frame.sp < stack_page ||
|
||||
frame.sp >= stack_page + THREAD_SIZE ||
|
||||
unwind_frame(&frame))
|
||||
unwind_frame(p, &frame))
|
||||
return 0;
|
||||
if (!in_sched_functions(frame.pc))
|
||||
return frame.pc;
|
||||
|
|
|
@ -44,7 +44,7 @@ void *return_address(unsigned int level)
|
|||
frame.sp = current_stack_pointer;
|
||||
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)
|
||||
return data.addr;
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
* ldp x29, x30, [sp]
|
||||
* 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 fp = frame->fp;
|
||||
|
@ -99,7 +99,7 @@ int notrace unwind_frame(struct stackframe *frame)
|
|||
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)
|
||||
{
|
||||
while (1) {
|
||||
|
@ -107,7 +107,7 @@ void notrace walk_stackframe(struct stackframe *frame,
|
|||
|
||||
if (fn(frame, data))
|
||||
break;
|
||||
ret = unwind_frame(frame);
|
||||
ret = unwind_frame(tsk, frame);
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
walk_stackframe(&frame, save_trace, &data);
|
||||
walk_stackframe(tsk, &frame, save_trace, &data);
|
||||
if (trace->nr_entries < trace->max_entries)
|
||||
trace->entries[trace->nr_entries++] = ULONG_MAX;
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ unsigned long profile_pc(struct pt_regs *regs)
|
|||
frame.sp = regs->sp;
|
||||
frame.pc = regs->pc;
|
||||
do {
|
||||
int ret = unwind_frame(&frame);
|
||||
int ret = unwind_frame(NULL, &frame);
|
||||
if (ret < 0)
|
||||
return 0;
|
||||
} while (in_lock_functions(frame.pc));
|
||||
|
|
|
@ -177,7 +177,7 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
|
|||
int ret;
|
||||
|
||||
dump_backtrace_entry(where);
|
||||
ret = unwind_frame(&frame);
|
||||
ret = unwind_frame(tsk, &frame);
|
||||
if (ret < 0)
|
||||
break;
|
||||
stack = frame.sp;
|
||||
|
|
Loading…
Reference in New Issue