xref: /linux/arch/parisc/kernel/unwind.c (revision f8343685643f2901fe11aa9d0358cafbeaf7b4c3)
1 /*
2  * Kernel unwinding support
3  *
4  * (c) 2002-2004 Randolph Chung <tausq@debian.org>
5  *
6  * Derived partially from the IA64 implementation. The PA-RISC
7  * Runtime Architecture Document is also a useful reference to
8  * understand what is happening here
9  */
10 
11 #include <linux/kernel.h>
12 #include <linux/init.h>
13 #include <linux/sched.h>
14 #include <linux/slab.h>
15 #include <linux/kallsyms.h>
16 
17 #include <asm/uaccess.h>
18 #include <asm/assembly.h>
19 
20 #include <asm/unwind.h>
21 
22 /* #define DEBUG 1 */
23 #ifdef DEBUG
24 #define dbg(x...) printk(x)
25 #else
26 #define dbg(x...)
27 #endif
28 
29 extern struct unwind_table_entry __start___unwind[];
30 extern struct unwind_table_entry __stop___unwind[];
31 
32 static spinlock_t unwind_lock;
33 /*
34  * the kernel unwind block is not dynamically allocated so that
35  * we can call unwind_init as early in the bootup process as
36  * possible (before the slab allocator is initialized)
37  */
38 static struct unwind_table kernel_unwind_table __read_mostly;
39 static LIST_HEAD(unwind_tables);
40 
41 static inline const struct unwind_table_entry *
42 find_unwind_entry_in_table(const struct unwind_table *table, unsigned long addr)
43 {
44 	const struct unwind_table_entry *e = NULL;
45 	unsigned long lo, hi, mid;
46 
47 	lo = 0;
48 	hi = table->length - 1;
49 
50 	while (lo <= hi) {
51 		mid = (hi - lo) / 2 + lo;
52 		e = &table->table[mid];
53 		if (addr < e->region_start)
54 			hi = mid - 1;
55 		else if (addr > e->region_end)
56 			lo = mid + 1;
57 		else
58 			return e;
59 	}
60 
61 	return NULL;
62 }
63 
64 static const struct unwind_table_entry *
65 find_unwind_entry(unsigned long addr)
66 {
67 	struct unwind_table *table;
68 	const struct unwind_table_entry *e = NULL;
69 
70 	if (addr >= kernel_unwind_table.start &&
71 	    addr <= kernel_unwind_table.end)
72 		e = find_unwind_entry_in_table(&kernel_unwind_table, addr);
73 	else
74 		list_for_each_entry(table, &unwind_tables, list) {
75 			if (addr >= table->start &&
76 			    addr <= table->end)
77 				e = find_unwind_entry_in_table(table, addr);
78 			if (e)
79 				break;
80 		}
81 
82 	return e;
83 }
84 
85 static void
86 unwind_table_init(struct unwind_table *table, const char *name,
87 		  unsigned long base_addr, unsigned long gp,
88 		  void *table_start, void *table_end)
89 {
90 	struct unwind_table_entry *start = table_start;
91 	struct unwind_table_entry *end =
92 		(struct unwind_table_entry *)table_end - 1;
93 
94 	table->name = name;
95 	table->base_addr = base_addr;
96 	table->gp = gp;
97 	table->start = base_addr + start->region_start;
98 	table->end = base_addr + end->region_end;
99 	table->table = (struct unwind_table_entry *)table_start;
100 	table->length = end - start + 1;
101 	INIT_LIST_HEAD(&table->list);
102 
103 	for (; start <= end; start++) {
104 		if (start < end &&
105 		    start->region_end > (start+1)->region_start) {
106 			printk("WARNING: Out of order unwind entry! %p and %p\n", start, start+1);
107 		}
108 
109 		start->region_start += base_addr;
110 		start->region_end += base_addr;
111 	}
112 }
113 
114 static void
115 unwind_table_sort(struct unwind_table_entry *start,
116 		  struct unwind_table_entry *finish)
117 {
118 	struct unwind_table_entry el, *p, *q;
119 
120 	for (p = start + 1; p < finish; ++p) {
121 		if (p[0].region_start < p[-1].region_start) {
122 			el = *p;
123 			q = p;
124 			do {
125 				q[0] = q[-1];
126 				--q;
127 			} while (q > start &&
128 				 el.region_start < q[-1].region_start);
129 			*q = el;
130 		}
131 	}
132 }
133 
134 struct unwind_table *
135 unwind_table_add(const char *name, unsigned long base_addr,
136 		 unsigned long gp,
137                  void *start, void *end)
138 {
139 	struct unwind_table *table;
140 	unsigned long flags;
141 	struct unwind_table_entry *s = (struct unwind_table_entry *)start;
142 	struct unwind_table_entry *e = (struct unwind_table_entry *)end;
143 
144 	unwind_table_sort(s, e);
145 
146 	table = kmalloc(sizeof(struct unwind_table), GFP_USER);
147 	if (table == NULL)
148 		return NULL;
149 	unwind_table_init(table, name, base_addr, gp, start, end);
150 	spin_lock_irqsave(&unwind_lock, flags);
151 	list_add_tail(&table->list, &unwind_tables);
152 	spin_unlock_irqrestore(&unwind_lock, flags);
153 
154 	return table;
155 }
156 
157 void unwind_table_remove(struct unwind_table *table)
158 {
159 	unsigned long flags;
160 
161 	spin_lock_irqsave(&unwind_lock, flags);
162 	list_del(&table->list);
163 	spin_unlock_irqrestore(&unwind_lock, flags);
164 
165 	kfree(table);
166 }
167 
168 /* Called from setup_arch to import the kernel unwind info */
169 static int unwind_init(void)
170 {
171 	long start, stop;
172 	register unsigned long gp __asm__ ("r27");
173 
174 	start = (long)&__start___unwind[0];
175 	stop = (long)&__stop___unwind[0];
176 
177 	spin_lock_init(&unwind_lock);
178 
179 	printk("unwind_init: start = 0x%lx, end = 0x%lx, entries = %lu\n",
180 	    start, stop,
181 	    (stop - start) / sizeof(struct unwind_table_entry));
182 
183 	unwind_table_init(&kernel_unwind_table, "kernel", KERNEL_START,
184 			  gp,
185 			  &__start___unwind[0], &__stop___unwind[0]);
186 #if 0
187 	{
188 		int i;
189 		for (i = 0; i < 10; i++)
190 		{
191 			printk("region 0x%x-0x%x\n",
192 				__start___unwind[i].region_start,
193 				__start___unwind[i].region_end);
194 		}
195 	}
196 #endif
197 	return 0;
198 }
199 
200 static void unwind_frame_regs(struct unwind_frame_info *info)
201 {
202 	const struct unwind_table_entry *e;
203 	unsigned long npc;
204 	unsigned int insn;
205 	long frame_size = 0;
206 	int looking_for_rp, rpoffset = 0;
207 
208 	e = find_unwind_entry(info->ip);
209 	if (e == NULL) {
210 		unsigned long sp;
211 		extern char _stext[], _etext[];
212 
213 		dbg("Cannot find unwind entry for 0x%lx; forced unwinding\n", info->ip);
214 
215 #ifdef CONFIG_KALLSYMS
216 		/* Handle some frequent special cases.... */
217 		{
218 			char symname[KSYM_NAME_LEN+1];
219 
220 			kallsyms_lookup(info->ip, NULL, NULL, NULL, symname);
221 
222 			dbg("info->ip = 0x%lx, name = %s\n", info->ip, symname);
223 
224 			if (strcmp(symname, "_switch_to_ret") == 0) {
225 				info->prev_sp = info->sp - CALLEE_SAVE_FRAME_SIZE;
226 				info->prev_ip = *(unsigned long *)(info->prev_sp - RP_OFFSET);
227 				dbg("_switch_to_ret @ %lx - setting "
228 				    "prev_sp=%lx prev_ip=%lx\n",
229 				    info->ip, info->prev_sp,
230 				    info->prev_ip);
231 				return;
232 			} else if (strcmp(symname, "ret_from_kernel_thread") == 0 ||
233 				   strcmp(symname, "syscall_exit") == 0) {
234 				info->prev_ip = info->prev_sp = 0;
235 				return;
236 			}
237 		}
238 #endif
239 
240 		/* Since we are doing the unwinding blind, we don't know if
241 		   we are adjusting the stack correctly or extracting the rp
242 		   correctly. The rp is checked to see if it belongs to the
243 		   kernel text section, if not we assume we don't have a
244 		   correct stack frame and we continue to unwind the stack.
245 		   This is not quite correct, and will fail for loadable
246 		   modules. */
247 		sp = info->sp & ~63;
248 		do {
249 			unsigned long tmp;
250 
251 			info->prev_sp = sp - 64;
252 			info->prev_ip = 0;
253 			if (get_user(tmp, (unsigned long *)(info->prev_sp - RP_OFFSET)))
254 				break;
255 			info->prev_ip = tmp;
256 			sp = info->prev_sp;
257 		} while (info->prev_ip < (unsigned long)_stext ||
258 			 info->prev_ip > (unsigned long)_etext);
259 
260 		info->rp = 0;
261 
262 		dbg("analyzing func @ %lx with no unwind info, setting "
263 		    "prev_sp=%lx prev_ip=%lx\n", info->ip,
264 		    info->prev_sp, info->prev_ip);
265 	} else {
266 		dbg("e->start = 0x%x, e->end = 0x%x, Save_SP = %d, "
267 		    "Save_RP = %d, Millicode = %d size = %u\n",
268 		    e->region_start, e->region_end, e->Save_SP, e->Save_RP,
269 		    e->Millicode, e->Total_frame_size);
270 
271 		looking_for_rp = e->Save_RP;
272 
273 		for (npc = e->region_start;
274 		     (frame_size < (e->Total_frame_size << 3) ||
275 		      looking_for_rp) &&
276 		     npc < info->ip;
277 		     npc += 4) {
278 
279 			insn = *(unsigned int *)npc;
280 
281 			if ((insn & 0xffffc000) == 0x37de0000 ||
282 			    (insn & 0xffe00000) == 0x6fc00000) {
283 				/* ldo X(sp), sp, or stwm X,D(sp) */
284 				frame_size += (insn & 0x1 ? -1 << 13 : 0) |
285 					((insn & 0x3fff) >> 1);
286 				dbg("analyzing func @ %lx, insn=%08x @ "
287 				    "%lx, frame_size = %ld\n", info->ip,
288 				    insn, npc, frame_size);
289 			} else if ((insn & 0xffe00008) == 0x73c00008) {
290 				/* std,ma X,D(sp) */
291 				frame_size += (insn & 0x1 ? -1 << 13 : 0) |
292 					(((insn >> 4) & 0x3ff) << 3);
293 				dbg("analyzing func @ %lx, insn=%08x @ "
294 				    "%lx, frame_size = %ld\n", info->ip,
295 				    insn, npc, frame_size);
296 			} else if (insn == 0x6bc23fd9) {
297 				/* stw rp,-20(sp) */
298 				rpoffset = 20;
299 				looking_for_rp = 0;
300 				dbg("analyzing func @ %lx, insn=stw rp,"
301 				    "-20(sp) @ %lx\n", info->ip, npc);
302 			} else if (insn == 0x0fc212c1) {
303 				/* std rp,-16(sr0,sp) */
304 				rpoffset = 16;
305 				looking_for_rp = 0;
306 				dbg("analyzing func @ %lx, insn=std rp,"
307 				    "-16(sp) @ %lx\n", info->ip, npc);
308 			}
309 		}
310 
311 		info->prev_sp = info->sp - frame_size;
312 		if (e->Millicode)
313 			info->rp = info->r31;
314 		else if (rpoffset)
315 			info->rp = *(unsigned long *)(info->prev_sp - rpoffset);
316 		info->prev_ip = info->rp;
317 		info->rp = 0;
318 
319 		dbg("analyzing func @ %lx, setting prev_sp=%lx "
320 		    "prev_ip=%lx npc=%lx\n", info->ip, info->prev_sp,
321 		    info->prev_ip, npc);
322 	}
323 }
324 
325 void unwind_frame_init(struct unwind_frame_info *info, struct task_struct *t,
326 		       struct pt_regs *regs)
327 {
328 	memset(info, 0, sizeof(struct unwind_frame_info));
329 	info->t = t;
330 	info->sp = regs->gr[30];
331 	info->ip = regs->iaoq[0];
332 	info->rp = regs->gr[2];
333 	info->r31 = regs->gr[31];
334 
335 	dbg("(%d) Start unwind from sp=%08lx ip=%08lx\n",
336 	    t ? (int)t->pid : -1, info->sp, info->ip);
337 }
338 
339 void unwind_frame_init_from_blocked_task(struct unwind_frame_info *info, struct task_struct *t)
340 {
341 	struct pt_regs *r = &t->thread.regs;
342 	struct pt_regs *r2;
343 
344 	r2 = kmalloc(sizeof(struct pt_regs), GFP_KERNEL);
345 	if (!r2)
346 		return;
347 	*r2 = *r;
348 	r2->gr[30] = r->ksp;
349 	r2->iaoq[0] = r->kpc;
350 	unwind_frame_init(info, t, r2);
351 	kfree(r2);
352 }
353 
354 void unwind_frame_init_running(struct unwind_frame_info *info, struct pt_regs *regs)
355 {
356 	unwind_frame_init(info, current, regs);
357 }
358 
359 int unwind_once(struct unwind_frame_info *next_frame)
360 {
361 	unwind_frame_regs(next_frame);
362 
363 	if (next_frame->prev_sp == 0 ||
364 	    next_frame->prev_ip == 0)
365 		return -1;
366 
367 	next_frame->sp = next_frame->prev_sp;
368 	next_frame->ip = next_frame->prev_ip;
369 	next_frame->prev_sp = 0;
370 	next_frame->prev_ip = 0;
371 
372 	dbg("(%d) Continue unwind to sp=%08lx ip=%08lx\n",
373 	    next_frame->t ? (int)next_frame->t->pid : -1,
374 	    next_frame->sp, next_frame->ip);
375 
376 	return 0;
377 }
378 
379 int unwind_to_user(struct unwind_frame_info *info)
380 {
381 	int ret;
382 
383 	do {
384 		ret = unwind_once(info);
385 	} while (!ret && !(info->ip & 3));
386 
387 	return ret;
388 }
389 
390 module_init(unwind_init);
391