xref: /openbmc/linux/arch/parisc/kernel/unwind.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
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/config.h>
12 #include <linux/kernel.h>
13 #include <linux/init.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;
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 			char *modname;
220 			unsigned long symsize, offset;
221 
222 			kallsyms_lookup(info->ip, &symsize, &offset,
223 					&modname, symname);
224 
225 			dbg("info->ip = 0x%lx, name = %s\n", info->ip, symname);
226 
227 			if (strcmp(symname, "_switch_to_ret") == 0) {
228 				info->prev_sp = info->sp - CALLEE_SAVE_FRAME_SIZE;
229 				info->prev_ip = *(unsigned long *)(info->prev_sp - RP_OFFSET);
230 				dbg("_switch_to_ret @ %lx - setting "
231 				    "prev_sp=%lx prev_ip=%lx\n",
232 				    info->ip, info->prev_sp,
233 				    info->prev_ip);
234 				return;
235 			} else if (strcmp(symname, "ret_from_kernel_thread") == 0 ||
236 				   strcmp(symname, "syscall_exit") == 0) {
237 				info->prev_ip = info->prev_sp = 0;
238 				return;
239 			}
240 		}
241 #endif
242 
243 		/* Since we are doing the unwinding blind, we don't know if
244 		   we are adjusting the stack correctly or extracting the rp
245 		   correctly. The rp is checked to see if it belongs to the
246 		   kernel text section, if not we assume we don't have a
247 		   correct stack frame and we continue to unwind the stack.
248 		   This is not quite correct, and will fail for loadable
249 		   modules. */
250 		sp = info->sp & ~63;
251 		do {
252 			unsigned long tmp;
253 
254 			info->prev_sp = sp - 64;
255 			info->prev_ip = 0;
256 			if (get_user(tmp, (unsigned long *)(info->prev_sp - RP_OFFSET)))
257 				break;
258 			info->prev_ip = tmp;
259 			sp = info->prev_sp;
260 		} while (info->prev_ip < (unsigned long)_stext ||
261 			 info->prev_ip > (unsigned long)_etext);
262 
263 		info->rp = 0;
264 
265 		dbg("analyzing func @ %lx with no unwind info, setting "
266 		    "prev_sp=%lx prev_ip=%lx\n", info->ip,
267 		    info->prev_sp, info->prev_ip);
268 	} else {
269 		dbg("e->start = 0x%x, e->end = 0x%x, Save_SP = %d, "
270 		    "Save_RP = %d, Millicode = %d size = %u\n",
271 		    e->region_start, e->region_end, e->Save_SP, e->Save_RP,
272 		    e->Millicode, e->Total_frame_size);
273 
274 		looking_for_rp = e->Save_RP;
275 
276 		for (npc = e->region_start;
277 		     (frame_size < (e->Total_frame_size << 3) ||
278 		      looking_for_rp) &&
279 		     npc < info->ip;
280 		     npc += 4) {
281 
282 			insn = *(unsigned int *)npc;
283 
284 			if ((insn & 0xffffc000) == 0x37de0000 ||
285 			    (insn & 0xffe00000) == 0x6fc00000) {
286 				/* ldo X(sp), sp, or stwm X,D(sp) */
287 				frame_size += (insn & 0x1 ? -1 << 13 : 0) |
288 					((insn & 0x3fff) >> 1);
289 				dbg("analyzing func @ %lx, insn=%08x @ "
290 				    "%lx, frame_size = %ld\n", info->ip,
291 				    insn, npc, frame_size);
292 			} else if ((insn & 0xffe00008) == 0x73c00008) {
293 				/* std,ma X,D(sp) */
294 				frame_size += (insn & 0x1 ? -1 << 13 : 0) |
295 					(((insn >> 4) & 0x3ff) << 3);
296 				dbg("analyzing func @ %lx, insn=%08x @ "
297 				    "%lx, frame_size = %ld\n", info->ip,
298 				    insn, npc, frame_size);
299 			} else if (insn == 0x6bc23fd9) {
300 				/* stw rp,-20(sp) */
301 				rpoffset = 20;
302 				looking_for_rp = 0;
303 				dbg("analyzing func @ %lx, insn=stw rp,"
304 				    "-20(sp) @ %lx\n", info->ip, npc);
305 			} else if (insn == 0x0fc212c1) {
306 				/* std rp,-16(sr0,sp) */
307 				rpoffset = 16;
308 				looking_for_rp = 0;
309 				dbg("analyzing func @ %lx, insn=std rp,"
310 				    "-16(sp) @ %lx\n", info->ip, npc);
311 			}
312 		}
313 
314 		info->prev_sp = info->sp - frame_size;
315 		if (e->Millicode)
316 			info->rp = info->r31;
317 		else if (rpoffset)
318 			info->rp = *(unsigned long *)(info->prev_sp - rpoffset);
319 		info->prev_ip = info->rp;
320 		info->rp = 0;
321 
322 		dbg("analyzing func @ %lx, setting prev_sp=%lx "
323 		    "prev_ip=%lx npc=%lx\n", info->ip, info->prev_sp,
324 		    info->prev_ip, npc);
325 	}
326 }
327 
328 void unwind_frame_init(struct unwind_frame_info *info, struct task_struct *t,
329 		       struct pt_regs *regs)
330 {
331 	memset(info, 0, sizeof(struct unwind_frame_info));
332 	info->t = t;
333 	info->sp = regs->gr[30];
334 	info->ip = regs->iaoq[0];
335 	info->rp = regs->gr[2];
336 	info->r31 = regs->gr[31];
337 
338 	dbg("(%d) Start unwind from sp=%08lx ip=%08lx\n",
339 	    t ? (int)t->pid : -1, info->sp, info->ip);
340 }
341 
342 void unwind_frame_init_from_blocked_task(struct unwind_frame_info *info, struct task_struct *t)
343 {
344 	struct pt_regs *r = &t->thread.regs;
345 	struct pt_regs *r2;
346 
347 	r2 = (struct pt_regs *)kmalloc(sizeof(struct pt_regs), GFP_KERNEL);
348 	if (!r2)
349 		return;
350 	*r2 = *r;
351 	r2->gr[30] = r->ksp;
352 	r2->iaoq[0] = r->kpc;
353 	unwind_frame_init(info, t, r2);
354 	kfree(r2);
355 }
356 
357 void unwind_frame_init_running(struct unwind_frame_info *info, struct pt_regs *regs)
358 {
359 	unwind_frame_init(info, current, regs);
360 }
361 
362 int unwind_once(struct unwind_frame_info *next_frame)
363 {
364 	unwind_frame_regs(next_frame);
365 
366 	if (next_frame->prev_sp == 0 ||
367 	    next_frame->prev_ip == 0)
368 		return -1;
369 
370 	next_frame->sp = next_frame->prev_sp;
371 	next_frame->ip = next_frame->prev_ip;
372 	next_frame->prev_sp = 0;
373 	next_frame->prev_ip = 0;
374 
375 	dbg("(%d) Continue unwind to sp=%08lx ip=%08lx\n",
376 	    next_frame->t ? (int)next_frame->t->pid : -1,
377 	    next_frame->sp, next_frame->ip);
378 
379 	return 0;
380 }
381 
382 int unwind_to_user(struct unwind_frame_info *info)
383 {
384 	int ret;
385 
386 	do {
387 		ret = unwind_once(info);
388 	} while (!ret && !(info->ip & 3));
389 
390 	return ret;
391 }
392 
393 module_init(unwind_init);
394