diff options
Diffstat (limited to 'arch/loongarch')
-rw-r--r-- | arch/loongarch/kernel/process.c | 12 | ||||
-rw-r--r-- | arch/loongarch/kernel/unwind_guess.c | 6 | ||||
-rw-r--r-- | arch/loongarch/kernel/unwind_prologue.c | 16 |
3 files changed, 22 insertions, 12 deletions
diff --git a/arch/loongarch/kernel/process.c b/arch/loongarch/kernel/process.c index c583b1ef1f44..edfd220a3737 100644 --- a/arch/loongarch/kernel/process.c +++ b/arch/loongarch/kernel/process.c @@ -191,20 +191,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 e2d2e4f3001f..9ef5f2a47f88 100644 --- a/arch/loongarch/kernel/unwind_guess.c +++ b/arch/loongarch/kernel/unwind_guess.c @@ -26,6 +26,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 e98b00432c88..613545ce6a97 100644 --- a/arch/loongarch/kernel/unwind_prologue.c +++ b/arch/loongarch/kernel/unwind_prologue.c @@ -146,12 +146,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; |