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
);