1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2022 Loongson Technology Corporation Limited 4 */ 5 #include <linux/cpumask.h> 6 #include <linux/export.h> 7 #include <linux/ftrace.h> 8 #include <linux/kallsyms.h> 9 10 #include <asm/inst.h> 11 #include <asm/loongson.h> 12 #include <asm/ptrace.h> 13 #include <asm/setup.h> 14 #include <asm/unwind.h> 15 16 extern const int unwind_hint_ade; 17 extern const int unwind_hint_ale; 18 extern const int unwind_hint_bp; 19 extern const int unwind_hint_fpe; 20 extern const int unwind_hint_fpu; 21 extern const int unwind_hint_lsx; 22 extern const int unwind_hint_lasx; 23 extern const int unwind_hint_lbt; 24 extern const int unwind_hint_ri; 25 extern const int unwind_hint_watch; 26 extern unsigned long eentry; 27 #ifdef CONFIG_NUMA 28 extern unsigned long pcpu_handlers[NR_CPUS]; 29 #endif 30 31 static inline bool scan_handlers(unsigned long entry_offset) 32 { 33 int idx, offset; 34 35 if (entry_offset >= EXCCODE_INT_START * VECSIZE) 36 return false; 37 38 idx = entry_offset / VECSIZE; 39 offset = entry_offset % VECSIZE; 40 switch (idx) { 41 case EXCCODE_ADE: 42 return offset == unwind_hint_ade; 43 case EXCCODE_ALE: 44 return offset == unwind_hint_ale; 45 case EXCCODE_BP: 46 return offset == unwind_hint_bp; 47 case EXCCODE_FPE: 48 return offset == unwind_hint_fpe; 49 case EXCCODE_FPDIS: 50 return offset == unwind_hint_fpu; 51 case EXCCODE_LSXDIS: 52 return offset == unwind_hint_lsx; 53 case EXCCODE_LASXDIS: 54 return offset == unwind_hint_lasx; 55 case EXCCODE_BTDIS: 56 return offset == unwind_hint_lbt; 57 case EXCCODE_INE: 58 return offset == unwind_hint_ri; 59 case EXCCODE_WATCH: 60 return offset == unwind_hint_watch; 61 default: 62 return false; 63 } 64 } 65 66 static inline bool fix_exception(unsigned long pc) 67 { 68 #ifdef CONFIG_NUMA 69 int cpu; 70 71 for_each_possible_cpu(cpu) { 72 if (!pcpu_handlers[cpu]) 73 continue; 74 if (scan_handlers(pc - pcpu_handlers[cpu])) 75 return true; 76 } 77 #endif 78 return scan_handlers(pc - eentry); 79 } 80 81 /* 82 * As we meet ftrace_regs_entry, reset first flag like first doing 83 * tracing. Prologue analysis will stop soon because PC is at entry. 84 */ 85 static inline bool fix_ftrace(unsigned long pc) 86 { 87 #ifdef CONFIG_DYNAMIC_FTRACE 88 return pc == (unsigned long)ftrace_call + LOONGARCH_INSN_SIZE; 89 #else 90 return false; 91 #endif 92 } 93 94 static inline bool unwind_state_fixup(struct unwind_state *state) 95 { 96 if (!fix_exception(state->pc) && !fix_ftrace(state->pc)) 97 return false; 98 99 state->reset = true; 100 return true; 101 } 102 103 /* 104 * LoongArch function prologue is like follows, 105 * [instructions not use stack var] 106 * addi.d sp, sp, -imm 107 * st.d xx, sp, offset <- save callee saved regs and 108 * st.d yy, sp, offset save ra if function is nest. 109 * [others instructions] 110 */ 111 static bool unwind_by_prologue(struct unwind_state *state) 112 { 113 long frame_ra = -1; 114 unsigned long frame_size = 0; 115 unsigned long size, offset, pc; 116 struct pt_regs *regs; 117 struct stack_info *info = &state->stack_info; 118 union loongarch_instruction *ip, *ip_end; 119 120 if (state->sp >= info->end || state->sp < info->begin) 121 return false; 122 123 if (state->reset) { 124 regs = (struct pt_regs *)state->sp; 125 state->first = true; 126 state->reset = false; 127 state->pc = regs->csr_era; 128 state->ra = regs->regs[1]; 129 state->sp = regs->regs[3]; 130 return true; 131 } 132 133 /* 134 * When first is not set, the PC is a return address in the previous frame. 135 * We need to adjust its value in case overflow to the next symbol. 136 */ 137 pc = state->pc - (state->first ? 0 : LOONGARCH_INSN_SIZE); 138 if (!kallsyms_lookup_size_offset(pc, &size, &offset)) 139 return false; 140 141 ip = (union loongarch_instruction *)(pc - offset); 142 ip_end = (union loongarch_instruction *)pc; 143 144 while (ip < ip_end) { 145 if (is_stack_alloc_ins(ip)) { 146 frame_size = (1 << 12) - ip->reg2i12_format.immediate; 147 ip++; 148 break; 149 } 150 ip++; 151 } 152 153 /* 154 * Can't find stack alloc action, PC may be in a leaf function. Only the 155 * first being true is reasonable, otherwise indicate analysis is broken. 156 */ 157 if (!frame_size) { 158 if (state->first) 159 goto first; 160 161 return false; 162 } 163 164 while (ip < ip_end) { 165 if (is_ra_save_ins(ip)) { 166 frame_ra = ip->reg2i12_format.immediate; 167 break; 168 } 169 if (is_branch_ins(ip)) 170 break; 171 ip++; 172 } 173 174 /* Can't find save $ra action, PC may be in a leaf function, too. */ 175 if (frame_ra < 0) { 176 if (state->first) { 177 state->sp = state->sp + frame_size; 178 goto first; 179 } 180 return false; 181 } 182 183 state->pc = *(unsigned long *)(state->sp + frame_ra); 184 state->sp = state->sp + frame_size; 185 goto out; 186 187 first: 188 state->pc = state->ra; 189 190 out: 191 state->first = false; 192 return unwind_state_fixup(state) || __kernel_text_address(state->pc); 193 } 194 195 static bool next_frame(struct unwind_state *state) 196 { 197 unsigned long pc; 198 struct pt_regs *regs; 199 struct stack_info *info = &state->stack_info; 200 201 if (unwind_done(state)) 202 return false; 203 204 do { 205 if (unwind_by_prologue(state)) { 206 state->pc = unwind_graph_addr(state, state->pc, state->sp); 207 return true; 208 } 209 210 if (info->type == STACK_TYPE_IRQ && info->end == state->sp) { 211 regs = (struct pt_regs *)info->next_sp; 212 pc = regs->csr_era; 213 214 if (user_mode(regs) || !__kernel_text_address(pc)) 215 goto out; 216 217 state->first = true; 218 state->pc = pc; 219 state->ra = regs->regs[1]; 220 state->sp = regs->regs[3]; 221 get_stack_info(state->sp, state->task, info); 222 223 return true; 224 } 225 226 state->sp = info->next_sp; 227 228 } while (!get_stack_info(state->sp, state->task, info)); 229 230 out: 231 state->stack_info.type = STACK_TYPE_UNKNOWN; 232 return false; 233 } 234 235 unsigned long unwind_get_return_address(struct unwind_state *state) 236 { 237 return __unwind_get_return_address(state); 238 } 239 EXPORT_SYMBOL_GPL(unwind_get_return_address); 240 241 void unwind_start(struct unwind_state *state, struct task_struct *task, 242 struct pt_regs *regs) 243 { 244 __unwind_start(state, task, regs); 245 state->type = UNWINDER_PROLOGUE; 246 state->first = true; 247 248 /* 249 * The current PC is not kernel text address, we cannot find its 250 * relative symbol. Thus, prologue analysis will be broken. Luckily, 251 * we can use the default_next_frame(). 252 */ 253 if (!__kernel_text_address(state->pc)) { 254 state->type = UNWINDER_GUESS; 255 if (!unwind_done(state)) 256 unwind_next_frame(state); 257 } 258 } 259 EXPORT_SYMBOL_GPL(unwind_start); 260 261 bool unwind_next_frame(struct unwind_state *state) 262 { 263 return state->type == UNWINDER_PROLOGUE ? 264 next_frame(state) : default_next_frame(state); 265 } 266 EXPORT_SYMBOL_GPL(unwind_next_frame); 267