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