1*49232773SQing Zhang // SPDX-License-Identifier: GPL-2.0 2*49232773SQing Zhang /* 3*49232773SQing Zhang * Copyright (C) 2022 Loongson Technology Corporation Limited 4*49232773SQing Zhang */ 5*49232773SQing Zhang #include <linux/kernel.h> 6*49232773SQing Zhang 7*49232773SQing Zhang #include <asm/unwind.h> 8*49232773SQing Zhang 9*49232773SQing Zhang unsigned long unwind_get_return_address(struct unwind_state *state) 10*49232773SQing Zhang { 11*49232773SQing Zhang if (unwind_done(state)) 12*49232773SQing Zhang return 0; 13*49232773SQing Zhang else if (state->first) 14*49232773SQing Zhang return state->pc; 15*49232773SQing Zhang 16*49232773SQing Zhang return *(unsigned long *)(state->sp); 17*49232773SQing Zhang } 18*49232773SQing Zhang EXPORT_SYMBOL_GPL(unwind_get_return_address); 19*49232773SQing Zhang 20*49232773SQing Zhang void unwind_start(struct unwind_state *state, struct task_struct *task, 21*49232773SQing Zhang struct pt_regs *regs) 22*49232773SQing Zhang { 23*49232773SQing Zhang memset(state, 0, sizeof(*state)); 24*49232773SQing Zhang 25*49232773SQing Zhang if (regs) { 26*49232773SQing Zhang state->sp = regs->regs[3]; 27*49232773SQing Zhang state->pc = regs->csr_era; 28*49232773SQing Zhang } 29*49232773SQing Zhang 30*49232773SQing Zhang state->task = task; 31*49232773SQing Zhang state->first = true; 32*49232773SQing Zhang 33*49232773SQing Zhang get_stack_info(state->sp, state->task, &state->stack_info); 34*49232773SQing Zhang 35*49232773SQing Zhang if (!unwind_done(state) && !__kernel_text_address(state->pc)) 36*49232773SQing Zhang unwind_next_frame(state); 37*49232773SQing Zhang } 38*49232773SQing Zhang EXPORT_SYMBOL_GPL(unwind_start); 39*49232773SQing Zhang 40*49232773SQing Zhang bool unwind_next_frame(struct unwind_state *state) 41*49232773SQing Zhang { 42*49232773SQing Zhang struct stack_info *info = &state->stack_info; 43*49232773SQing Zhang unsigned long addr; 44*49232773SQing Zhang 45*49232773SQing Zhang if (unwind_done(state)) 46*49232773SQing Zhang return false; 47*49232773SQing Zhang 48*49232773SQing Zhang if (state->first) 49*49232773SQing Zhang state->first = false; 50*49232773SQing Zhang 51*49232773SQing Zhang do { 52*49232773SQing Zhang for (state->sp += sizeof(unsigned long); 53*49232773SQing Zhang state->sp < info->end; 54*49232773SQing Zhang state->sp += sizeof(unsigned long)) { 55*49232773SQing Zhang addr = *(unsigned long *)(state->sp); 56*49232773SQing Zhang 57*49232773SQing Zhang if (__kernel_text_address(addr)) 58*49232773SQing Zhang return true; 59*49232773SQing Zhang } 60*49232773SQing Zhang 61*49232773SQing Zhang state->sp = info->next_sp; 62*49232773SQing Zhang 63*49232773SQing Zhang } while (!get_stack_info(state->sp, state->task, info)); 64*49232773SQing Zhang 65*49232773SQing Zhang return false; 66*49232773SQing Zhang } 67*49232773SQing Zhang EXPORT_SYMBOL_GPL(unwind_next_frame); 68