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;
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 	/*
82 	 * When first is not set, the PC is a return address in the previous frame.
83 	 * We need to adjust its value in case overflow to the next symbol.
84 	 */
85 	pc = state->pc - (state->first ? 0 : LOONGARCH_INSN_SIZE);
86 	if (!kallsyms_lookup_size_offset(pc, &size, &offset))
87 		return false;
88 
89 	ip = (union loongarch_instruction *)(pc - offset);
90 	ip_end = (union loongarch_instruction *)pc;
91 
92 	while (ip < ip_end) {
93 		if (is_stack_alloc_ins(ip)) {
94 			frame_size = (1 << 12) - ip->reg2i12_format.immediate;
95 			ip++;
96 			break;
97 		}
98 		ip++;
99 	}
100 
101 	if (!frame_size) {
102 		if (state->first)
103 			goto first;
104 
105 		return false;
106 	}
107 
108 	while (ip < ip_end) {
109 		if (is_ra_save_ins(ip)) {
110 			frame_ra = ip->reg2i12_format.immediate;
111 			break;
112 		}
113 		if (is_branch_ins(ip))
114 			break;
115 		ip++;
116 	}
117 
118 	if (frame_ra < 0) {
119 		if (state->first) {
120 			state->sp = state->sp + frame_size;
121 			goto first;
122 		}
123 		return false;
124 	}
125 
126 	if (state->first)
127 		state->first = false;
128 
129 	state->pc = *(unsigned long *)(state->sp + frame_ra);
130 	state->sp = state->sp + frame_size;
131 	goto out;
132 
133 first:
134 	state->first = false;
135 	if (state->pc == state->ra)
136 		return false;
137 
138 	state->pc = state->ra;
139 
140 out:
141 	unwind_state_fixup(state);
142 	return !!__kernel_text_address(state->pc);
143 }
144 
145 void unwind_start(struct unwind_state *state, struct task_struct *task,
146 		    struct pt_regs *regs)
147 {
148 	memset(state, 0, sizeof(*state));
149 	state->type = UNWINDER_PROLOGUE;
150 
151 	if (regs) {
152 		state->sp = regs->regs[3];
153 		state->pc = regs->csr_era;
154 		state->ra = regs->regs[1];
155 		if (!__kernel_text_address(state->pc))
156 			state->type = UNWINDER_GUESS;
157 	} else if (task && task != current) {
158 		state->sp = thread_saved_fp(task);
159 		state->pc = thread_saved_ra(task);
160 		state->ra = 0;
161 	} else {
162 		state->sp = (unsigned long)__builtin_frame_address(0);
163 		state->pc = (unsigned long)__builtin_return_address(0);
164 		state->ra = 0;
165 	}
166 
167 	state->task = task;
168 	state->first = true;
169 
170 	get_stack_info(state->sp, state->task, &state->stack_info);
171 
172 	if (!unwind_done(state) && !__kernel_text_address(state->pc))
173 		unwind_next_frame(state);
174 }
175 EXPORT_SYMBOL_GPL(unwind_start);
176 
177 bool unwind_next_frame(struct unwind_state *state)
178 {
179 	struct stack_info *info = &state->stack_info;
180 	struct pt_regs *regs;
181 	unsigned long pc;
182 
183 	if (unwind_done(state))
184 		return false;
185 
186 	do {
187 		switch (state->type) {
188 		case UNWINDER_GUESS:
189 			state->first = false;
190 			if (unwind_by_guess(state))
191 				return true;
192 			break;
193 
194 		case UNWINDER_PROLOGUE:
195 			if (unwind_by_prologue(state)) {
196 				state->pc = ftrace_graph_ret_addr(state->task, &state->graph_idx,
197 						state->pc, (unsigned long *)(state->sp - GRAPH_FAKE_OFFSET));
198 				return true;
199 			}
200 
201 			if (info->type == STACK_TYPE_IRQ &&
202 				info->end == state->sp) {
203 				regs = (struct pt_regs *)info->next_sp;
204 				pc = regs->csr_era;
205 
206 				if (user_mode(regs) || !__kernel_text_address(pc))
207 					return false;
208 
209 				state->first = true;
210 				state->ra = regs->regs[1];
211 				state->sp = regs->regs[3];
212 				state->pc = ftrace_graph_ret_addr(state->task, &state->graph_idx,
213 						pc, (unsigned long *)(state->sp - GRAPH_FAKE_OFFSET));
214 				get_stack_info(state->sp, state->task, info);
215 
216 				return true;
217 			}
218 		}
219 
220 		state->sp = info->next_sp;
221 
222 	} while (!get_stack_info(state->sp, state->task, info));
223 
224 	return false;
225 }
226 EXPORT_SYMBOL_GPL(unwind_next_frame);
227