1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2022 Loongson Technology Corporation Limited
5 #include <linux/cpumask.h>
6 #include <linux/ftrace.h>
7 #include <linux/kallsyms.h>
10 #include <asm/loongson.h>
11 #include <asm/ptrace.h>
12 #include <asm/setup.h>
13 #include <asm/unwind.h>
15 extern const int unwind_hint_ade;
16 extern const int unwind_hint_ale;
17 extern const int unwind_hint_bp;
18 extern const int unwind_hint_fpe;
19 extern const int unwind_hint_fpu;
20 extern const int unwind_hint_lsx;
21 extern const int unwind_hint_lasx;
22 extern const int unwind_hint_lbt;
23 extern const int unwind_hint_ri;
24 extern const int unwind_hint_watch;
25 extern unsigned long eentry;
27 extern unsigned long pcpu_handlers[NR_CPUS];
30 static inline bool scan_handlers(unsigned long entry_offset)
34 if (entry_offset >= EXCCODE_INT_START * VECSIZE)
37 idx = entry_offset / VECSIZE;
38 offset = entry_offset % VECSIZE;
41 return offset == unwind_hint_ade;
43 return offset == unwind_hint_ale;
45 return offset == unwind_hint_bp;
47 return offset == unwind_hint_fpe;
49 return offset == unwind_hint_fpu;
51 return offset == unwind_hint_lsx;
53 return offset == unwind_hint_lasx;
55 return offset == unwind_hint_lbt;
57 return offset == unwind_hint_ri;
59 return offset == unwind_hint_watch;
65 static inline bool fix_exception(unsigned long pc)
70 for_each_possible_cpu(cpu) {
71 if (!pcpu_handlers[cpu])
73 if (scan_handlers(pc - pcpu_handlers[cpu]))
77 return scan_handlers(pc - eentry);
81 * As we meet ftrace_regs_entry, reset first flag like first doing
82 * tracing. Prologue analysis will stop soon because PC is at entry.
84 static inline bool fix_ftrace(unsigned long pc)
86 #ifdef CONFIG_DYNAMIC_FTRACE
87 return pc == (unsigned long)ftrace_call + LOONGARCH_INSN_SIZE;
93 static inline bool unwind_state_fixup(struct unwind_state *state)
95 if (!fix_exception(state->pc) && !fix_ftrace(state->pc))
103 * LoongArch function prologue is like follows,
104 * [instructions not use stack var]
105 * addi.d sp, sp, -imm
106 * st.d xx, sp, offset <- save callee saved regs and
107 * st.d yy, sp, offset save ra if function is nest.
108 * [others instructions]
110 static bool unwind_by_prologue(struct unwind_state *state)
113 unsigned long frame_size = 0;
114 unsigned long size, offset, pc;
115 struct pt_regs *regs;
116 struct stack_info *info = &state->stack_info;
117 union loongarch_instruction *ip, *ip_end;
119 if (state->sp >= info->end || state->sp < info->begin)
123 regs = (struct pt_regs *)state->sp;
125 state->reset = false;
126 state->pc = regs->csr_era;
127 state->ra = regs->regs[1];
128 state->sp = regs->regs[3];
133 * When first is not set, the PC is a return address in the previous frame.
134 * We need to adjust its value in case overflow to the next symbol.
136 pc = state->pc - (state->first ? 0 : LOONGARCH_INSN_SIZE);
137 if (!kallsyms_lookup_size_offset(pc, &size, &offset))
140 ip = (union loongarch_instruction *)(pc - offset);
141 ip_end = (union loongarch_instruction *)pc;
143 while (ip < ip_end) {
144 if (is_stack_alloc_ins(ip)) {
145 frame_size = (1 << 12) - ip->reg2i12_format.immediate;
153 * Can't find stack alloc action, PC may be in a leaf function. Only the
154 * first being true is reasonable, otherwise indicate analysis is broken.
163 while (ip < ip_end) {
164 if (is_ra_save_ins(ip)) {
165 frame_ra = ip->reg2i12_format.immediate;
168 if (is_branch_ins(ip))
173 /* Can't find save $ra action, PC may be in a leaf function, too. */
176 state->sp = state->sp + frame_size;
182 state->pc = *(unsigned long *)(state->sp + frame_ra);
183 state->sp = state->sp + frame_size;
187 state->pc = state->ra;
190 state->first = false;
191 return unwind_state_fixup(state) || __kernel_text_address(state->pc);
194 static bool next_frame(struct unwind_state *state)
197 struct pt_regs *regs;
198 struct stack_info *info = &state->stack_info;
200 if (unwind_done(state))
204 if (unwind_by_prologue(state)) {
205 state->pc = unwind_graph_addr(state, state->pc, state->sp);
209 if (info->type == STACK_TYPE_IRQ && info->end == state->sp) {
210 regs = (struct pt_regs *)info->next_sp;
213 if (user_mode(regs) || !__kernel_text_address(pc))
218 state->ra = regs->regs[1];
219 state->sp = regs->regs[3];
220 get_stack_info(state->sp, state->task, info);
225 state->sp = info->next_sp;
227 } while (!get_stack_info(state->sp, state->task, info));
230 state->stack_info.type = STACK_TYPE_UNKNOWN;
234 unsigned long unwind_get_return_address(struct unwind_state *state)
236 return __unwind_get_return_address(state);
238 EXPORT_SYMBOL_GPL(unwind_get_return_address);
240 void unwind_start(struct unwind_state *state, struct task_struct *task,
241 struct pt_regs *regs)
243 __unwind_start(state, task, regs);
244 state->type = UNWINDER_PROLOGUE;
248 * The current PC is not kernel text address, we cannot find its
249 * relative symbol. Thus, prologue analysis will be broken. Luckily,
250 * we can use the default_next_frame().
252 if (!__kernel_text_address(state->pc)) {
253 state->type = UNWINDER_GUESS;
254 if (!unwind_done(state))
255 unwind_next_frame(state);
258 EXPORT_SYMBOL_GPL(unwind_start);
260 bool unwind_next_frame(struct unwind_state *state)
262 return state->type == UNWINDER_PROLOGUE ?
263 next_frame(state) : default_next_frame(state);
265 EXPORT_SYMBOL_GPL(unwind_next_frame);