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

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>
This commit is contained in:
Jinyang He 2023-01-17 11:42:16 +08:00 committed by Huacai Chen
parent e2f2739227
commit 429a9671f2
3 changed files with 22 additions and 12 deletions

View File

@ -191,20 +191,14 @@ out:
unsigned long __get_wchan(struct task_struct *task) unsigned long __get_wchan(struct task_struct *task)
{ {
unsigned long pc; unsigned long pc = 0;
struct unwind_state state; struct unwind_state state;
if (!try_get_task_stack(task)) if (!try_get_task_stack(task))
return 0; return 0;
unwind_start(&state, task, NULL); for (unwind_start(&state, task, NULL);
state.sp = thread_saved_fp(task); !unwind_done(&state); unwind_next_frame(&state)) {
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)) {
pc = unwind_get_return_address(&state); pc = unwind_get_return_address(&state);
if (!pc) if (!pc)
break; break;

View File

@ -26,6 +26,12 @@ void unwind_start(struct unwind_state *state, struct task_struct *task,
if (regs) { if (regs) {
state->sp = regs->regs[3]; state->sp = regs->regs[3];
state->pc = regs->csr_era; 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; state->task = task;

View File

@ -146,12 +146,22 @@ void unwind_start(struct unwind_state *state, struct task_struct *task,
struct pt_regs *regs) struct pt_regs *regs)
{ {
memset(state, 0, sizeof(*state)); memset(state, 0, sizeof(*state));
state->type = UNWINDER_PROLOGUE;
if (regs && __kernel_text_address(regs->csr_era)) { if (regs) {
state->pc = regs->csr_era;
state->sp = regs->regs[3]; state->sp = regs->regs[3];
state->pc = regs->csr_era;
state->ra = regs->regs[1]; 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; state->task = task;