Skip to content

Commit

Permalink
arm64: pass a task parameter to unwind_frame()
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
AKASHI Takahiro authored and Will Deacon committed Dec 21, 2015
1 parent 79fdee9 commit fe13f95
Show file tree
Hide file tree
Showing 7 changed files with 13 additions and 11 deletions.
6 changes: 4 additions & 2 deletions arch/arm64/include/asm/stacktrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
2 changes: 1 addition & 1 deletion arch/arm64/kernel/perf_callchain.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion arch/arm64/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion arch/arm64/kernel/return_address.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
8 changes: 4 additions & 4 deletions arch/arm64/kernel/stacktrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -99,15 +99,15 @@ 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) {
int ret;

if (fn(frame, data))
break;
ret = unwind_frame(frame);
ret = unwind_frame(tsk, frame);
if (ret < 0)
break;
}
Expand Down Expand Up @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion arch/arm64/kernel/time.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
2 changes: 1 addition & 1 deletion arch/arm64/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit fe13f95

Please sign in to comment.