1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2022 Loongson Technology Corporation Limited 4 */ 5 #include <linux/ftrace.h> 6 #include <linux/kallsyms.h> 7 8 #include <asm/inst.h> 9 #include <asm/ptrace.h> 10 #include <asm/unwind.h> 11 12 static inline void unwind_state_fixup(struct unwind_state *state) 13 { 14 #ifdef CONFIG_DYNAMIC_FTRACE 15 static unsigned long ftrace = (unsigned long)ftrace_call + 4; 16 17 if (state->pc == ftrace) 18 state->is_ftrace = true; 19 #endif 20 } 21 22 unsigned long unwind_get_return_address(struct unwind_state *state) 23 { 24 25 if (unwind_done(state)) 26 return 0; 27 else if (state->type) 28 return state->pc; 29 else if (state->first) 30 return state->pc; 31 32 return *(unsigned long *)(state->sp); 33 34 } 35 EXPORT_SYMBOL_GPL(unwind_get_return_address); 36 37 static bool unwind_by_guess(struct unwind_state *state) 38 { 39 struct stack_info *info = &state->stack_info; 40 unsigned long addr; 41 42 for (state->sp += sizeof(unsigned long); 43 state->sp < info->end; 44 state->sp += sizeof(unsigned long)) { 45 addr = *(unsigned long *)(state->sp); 46 state->pc = ftrace_graph_ret_addr(state->task, &state->graph_idx, 47 addr, (unsigned long *)(state->sp - GRAPH_FAKE_OFFSET)); 48 if (__kernel_text_address(addr)) 49 return true; 50 } 51 52 return false; 53 } 54 55 static bool unwind_by_prologue(struct unwind_state *state) 56 { 57 long frame_ra = -1; 58 unsigned long frame_size = 0; 59 unsigned long size, offset, pc = state->pc; 60 struct pt_regs *regs; 61 struct stack_info *info = &state->stack_info; 62 union loongarch_instruction *ip, *ip_end; 63 64 if (state->sp >= info->end || state->sp < info->begin) 65 return false; 66 67 if (state->is_ftrace) { 68 /* 69 * As we meet ftrace_regs_entry, reset first flag like first doing 70 * tracing. Prologue analysis will stop soon because PC is at entry. 71 */ 72 regs = (struct pt_regs *)state->sp; 73 state->first = true; 74 state->is_ftrace = false; 75 state->pc = regs->csr_era; 76 state->ra = regs->regs[1]; 77 state->sp = regs->regs[3]; 78 return true; 79 } 80 81 if (!kallsyms_lookup_size_offset(pc, &size, &offset)) 82 return false; 83 84 ip = (union loongarch_instruction *)(pc - offset); 85 ip_end = (union loongarch_instruction *)pc; 86 87 while (ip < ip_end) { 88 if (is_stack_alloc_ins(ip)) { 89 frame_size = (1 << 12) - ip->reg2i12_format.immediate; 90 ip++; 91 break; 92 } 93 ip++; 94 } 95 96 if (!frame_size) { 97 if (state->first) 98 goto first; 99 100 return false; 101 } 102 103 while (ip < ip_end) { 104 if (is_ra_save_ins(ip)) { 105 frame_ra = ip->reg2i12_format.immediate; 106 break; 107 } 108 if (is_branch_ins(ip)) 109 break; 110 ip++; 111 } 112 113 if (frame_ra < 0) { 114 if (state->first) { 115 state->sp = state->sp + frame_size; 116 goto first; 117 } 118 return false; 119 } 120 121 if (state->first) 122 state->first = false; 123 124 state->pc = *(unsigned long *)(state->sp + frame_ra); 125 state->sp = state->sp + frame_size; 126 goto out; 127 128 first: 129 state->first = false; 130 if (state->pc == state->ra) 131 return false; 132 133 state->pc = state->ra; 134 135 out: 136 unwind_state_fixup(state); 137 return !!__kernel_text_address(state->pc); 138 } 139 140 void unwind_start(struct unwind_state *state, struct task_struct *task, 141 struct pt_regs *regs) 142 { 143 memset(state, 0, sizeof(*state)); 144 145 if (regs && __kernel_text_address(regs->csr_era)) { 146 state->pc = regs->csr_era; 147 state->sp = regs->regs[3]; 148 state->ra = regs->regs[1]; 149 state->type = UNWINDER_PROLOGUE; 150 } 151 152 state->task = task; 153 state->first = true; 154 155 get_stack_info(state->sp, state->task, &state->stack_info); 156 157 if (!unwind_done(state) && !__kernel_text_address(state->pc)) 158 unwind_next_frame(state); 159 } 160 EXPORT_SYMBOL_GPL(unwind_start); 161 162 bool unwind_next_frame(struct unwind_state *state) 163 { 164 struct stack_info *info = &state->stack_info; 165 struct pt_regs *regs; 166 unsigned long pc; 167 168 if (unwind_done(state)) 169 return false; 170 171 do { 172 switch (state->type) { 173 case UNWINDER_GUESS: 174 state->first = false; 175 if (unwind_by_guess(state)) 176 return true; 177 break; 178 179 case UNWINDER_PROLOGUE: 180 if (unwind_by_prologue(state)) { 181 state->pc = ftrace_graph_ret_addr(state->task, &state->graph_idx, 182 state->pc, (unsigned long *)(state->sp - GRAPH_FAKE_OFFSET)); 183 return true; 184 } 185 186 if (info->type == STACK_TYPE_IRQ && 187 info->end == state->sp) { 188 regs = (struct pt_regs *)info->next_sp; 189 pc = regs->csr_era; 190 191 if (user_mode(regs) || !__kernel_text_address(pc)) 192 return false; 193 194 state->first = true; 195 state->ra = regs->regs[1]; 196 state->sp = regs->regs[3]; 197 state->pc = ftrace_graph_ret_addr(state->task, &state->graph_idx, 198 pc, (unsigned long *)(state->sp - GRAPH_FAKE_OFFSET)); 199 get_stack_info(state->sp, state->task, info); 200 201 return true; 202 } 203 } 204 205 state->sp = info->next_sp; 206 207 } while (!get_stack_info(state->sp, state->task, info)); 208 209 return false; 210 } 211 EXPORT_SYMBOL_GPL(unwind_next_frame); 212