From efc1058831f9cdd72a0af969e75d9ca533b32d62 Mon Sep 17 00:00:00 2001 From: Jinyang He Date: Tue, 17 Jan 2023 11:42:16 +0800 Subject: 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 Signed-off-by: Huacai Chen Signed-off-by: Sasha Levin --- arch/loongarch/kernel/process.c | 12 +++--------- arch/loongarch/kernel/unwind_guess.c | 6 ++++++ arch/loongarch/kernel/unwind_prologue.c | 16 +++++++++++++--- 3 files changed, 22 insertions(+), 12 deletions(-) (limited to 'arch/loongarch') diff --git a/arch/loongarch/kernel/process.c b/arch/loongarch/kernel/process.c index ddb8ba4eb399..90a5de746332 100644 --- a/arch/loongarch/kernel/process.c +++ b/arch/loongarch/kernel/process.c @@ -185,20 +185,14 @@ out: 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; diff --git a/arch/loongarch/kernel/unwind_guess.c b/arch/loongarch/kernel/unwind_guess.c index 5afa6064d73e..0c20e5184de6 100644 --- a/arch/loongarch/kernel/unwind_guess.c +++ b/arch/loongarch/kernel/unwind_guess.c @@ -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; diff --git a/arch/loongarch/kernel/unwind_prologue.c b/arch/loongarch/kernel/unwind_prologue.c index 4571c3c87cd4..1c5b65756144 100644 --- a/arch/loongarch/kernel/unwind_prologue.c +++ b/arch/loongarch/kernel/unwind_prologue.c @@ -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; -- cgit v1.2.3