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