LoongArch: Get frame info in unwind_start() when regs is not available
authorJinyang He <hejinyang@loongson.cn>
Tue, 17 Jan 2023 03:42:16 +0000 (11:42 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 6 Feb 2023 07:06:32 +0000 (08:06 +0100)
[ 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>
arch/loongarch/kernel/process.c
arch/loongarch/kernel/unwind_guess.c
arch/loongarch/kernel/unwind_prologue.c

index ddb8ba4..90a5de7 100644 (file)
@@ -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;
index 5afa606..0c20e51 100644 (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;
index 4571c3c..1c5b657 100644 (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;