LoongArch: Get frame info in unwind_start() when regs is not available

[ Upstream commit 429a9671f235c94fc4b5d6687308714b74adc820 ]

At unwind_start(), it is better to get its frame info here rather than
get them outside, even we don't have 'regs'. In this way we can simply
use unwind_{start, next_frame, done} outside.

Signed-off-by: Jinyang He <hejinyang@loongson.cn>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Jinyang He 2023-01-17 11:42:16 +08:00 committed by Greg Kroah-Hartman
parent a4a1af9fa0
commit efc1058831
3 changed files with 22 additions and 12 deletions

View File

@ -185,20 +185,14 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
unsigned long __get_wchan(struct task_struct *task)
{
unsigned long pc;
unsigned long pc = 0;
struct unwind_state state;
if (!try_get_task_stack(task))
return 0;
unwind_start(&state, task, NULL);
state.sp = thread_saved_fp(task);
get_stack_info(state.sp, state.task, &state.stack_info);
state.pc = thread_saved_ra(task);
#ifdef CONFIG_UNWINDER_PROLOGUE
state.type = UNWINDER_PROLOGUE;
#endif
for (; !unwind_done(&state); unwind_next_frame(&state)) {
for (unwind_start(&state, task, NULL);
!unwind_done(&state); unwind_next_frame(&state)) {
pc = unwind_get_return_address(&state);
if (!pc)
break;

View File

@ -25,6 +25,12 @@ void unwind_start(struct unwind_state *state, struct task_struct *task,
if (regs) {
state->sp = regs->regs[3];
state->pc = regs->csr_era;
} else if (task && task != current) {
state->sp = thread_saved_fp(task);
state->pc = thread_saved_ra(task);
} else {
state->sp = (unsigned long)__builtin_frame_address(0);
state->pc = (unsigned long)__builtin_return_address(0);
}
state->task = task;

View File

@ -111,12 +111,22 @@ void unwind_start(struct unwind_state *state, struct task_struct *task,
struct pt_regs *regs)
{
memset(state, 0, sizeof(*state));
state->type = UNWINDER_PROLOGUE;
if (regs && __kernel_text_address(regs->csr_era)) {
state->pc = regs->csr_era;
if (regs) {
state->sp = regs->regs[3];
state->pc = regs->csr_era;
state->ra = regs->regs[1];
state->type = UNWINDER_PROLOGUE;
if (!__kernel_text_address(state->pc))
state->type = UNWINDER_GUESS;
} else if (task && task != current) {
state->sp = thread_saved_fp(task);
state->pc = thread_saved_ra(task);
state->ra = 0;
} else {
state->sp = (unsigned long)__builtin_frame_address(0);
state->pc = (unsigned long)__builtin_return_address(0);
state->ra = 0;
}
state->task = task;