Linux Audio

Check our new training course

Loading...
v5.9
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Kernel unwinding support
  4 *
  5 * (c) 2002-2004 Randolph Chung <tausq@debian.org>
  6 *
  7 * Derived partially from the IA64 implementation. The PA-RISC
  8 * Runtime Architecture Document is also a useful reference to
  9 * understand what is happening here
 10 */
 11
 12#include <linux/kernel.h>
 13#include <linux/init.h>
 14#include <linux/sched.h>
 15#include <linux/slab.h>
 
 16#include <linux/sort.h>
 17
 18#include <linux/uaccess.h>
 19#include <asm/assembly.h>
 20#include <asm/asm-offsets.h>
 21#include <asm/ptrace.h>
 22
 23#include <asm/unwind.h>
 24
 25/* #define DEBUG 1 */
 26#ifdef DEBUG
 27#define dbg(x...) pr_debug(x)
 28#else
 29#define dbg(x...)
 30#endif
 31
 32#define KERNEL_START (KERNEL_BINARY_TEXT_START)
 33
 34extern struct unwind_table_entry __start___unwind[];
 35extern struct unwind_table_entry __stop___unwind[];
 36
 37static DEFINE_SPINLOCK(unwind_lock);
 38/*
 39 * the kernel unwind block is not dynamically allocated so that
 40 * we can call unwind_init as early in the bootup process as 
 41 * possible (before the slab allocator is initialized)
 42 */
 43static struct unwind_table kernel_unwind_table __ro_after_init;
 44static LIST_HEAD(unwind_tables);
 45
 46static inline const struct unwind_table_entry *
 47find_unwind_entry_in_table(const struct unwind_table *table, unsigned long addr)
 48{
 49	const struct unwind_table_entry *e = NULL;
 50	unsigned long lo, hi, mid;
 51
 52	lo = 0; 
 53	hi = table->length - 1; 
 54	
 55	while (lo <= hi) {
 56		mid = (hi - lo) / 2 + lo;
 57		e = &table->table[mid];
 58		if (addr < e->region_start)
 59			hi = mid - 1;
 60		else if (addr > e->region_end)
 61			lo = mid + 1;
 62		else
 63			return e;
 64	}
 65
 66	return NULL;
 67}
 68
 69static const struct unwind_table_entry *
 70find_unwind_entry(unsigned long addr)
 71{
 72	struct unwind_table *table;
 73	const struct unwind_table_entry *e = NULL;
 74
 75	if (addr >= kernel_unwind_table.start && 
 76	    addr <= kernel_unwind_table.end)
 77		e = find_unwind_entry_in_table(&kernel_unwind_table, addr);
 78	else {
 79		unsigned long flags;
 80
 81		spin_lock_irqsave(&unwind_lock, flags);
 82		list_for_each_entry(table, &unwind_tables, list) {
 83			if (addr >= table->start && 
 84			    addr <= table->end)
 85				e = find_unwind_entry_in_table(table, addr);
 86			if (e) {
 87				/* Move-to-front to exploit common traces */
 88				list_move(&table->list, &unwind_tables);
 89				break;
 90			}
 91		}
 92		spin_unlock_irqrestore(&unwind_lock, flags);
 93	}
 94
 95	return e;
 96}
 97
 98static void
 99unwind_table_init(struct unwind_table *table, const char *name,
100		  unsigned long base_addr, unsigned long gp,
101		  void *table_start, void *table_end)
102{
103	struct unwind_table_entry *start = table_start;
104	struct unwind_table_entry *end = 
105		(struct unwind_table_entry *)table_end - 1;
106
107	table->name = name;
108	table->base_addr = base_addr;
109	table->gp = gp;
110	table->start = base_addr + start->region_start;
111	table->end = base_addr + end->region_end;
112	table->table = (struct unwind_table_entry *)table_start;
113	table->length = end - start + 1;
114	INIT_LIST_HEAD(&table->list);
115
116	for (; start <= end; start++) {
117		if (start < end && 
118		    start->region_end > (start+1)->region_start) {
119			pr_warn("Out of order unwind entry! %px and %px\n",
120				start, start+1);
121		}
122
123		start->region_start += base_addr;
124		start->region_end += base_addr;
125	}
126}
127
128static int cmp_unwind_table_entry(const void *a, const void *b)
129{
130	return ((const struct unwind_table_entry *)a)->region_start
131	     - ((const struct unwind_table_entry *)b)->region_start;
132}
133
134static void
135unwind_table_sort(struct unwind_table_entry *start,
136		  struct unwind_table_entry *finish)
137{
138	sort(start, finish - start, sizeof(struct unwind_table_entry),
139	     cmp_unwind_table_entry, NULL);
140}
141
142struct unwind_table *
143unwind_table_add(const char *name, unsigned long base_addr, 
144		 unsigned long gp,
145                 void *start, void *end)
146{
147	struct unwind_table *table;
148	unsigned long flags;
149	struct unwind_table_entry *s = (struct unwind_table_entry *)start;
150	struct unwind_table_entry *e = (struct unwind_table_entry *)end;
151
152	unwind_table_sort(s, e);
153
154	table = kmalloc(sizeof(struct unwind_table), GFP_USER);
155	if (table == NULL)
156		return NULL;
157	unwind_table_init(table, name, base_addr, gp, start, end);
158	spin_lock_irqsave(&unwind_lock, flags);
159	list_add_tail(&table->list, &unwind_tables);
160	spin_unlock_irqrestore(&unwind_lock, flags);
161
162	return table;
163}
164
165void unwind_table_remove(struct unwind_table *table)
166{
167	unsigned long flags;
168
169	spin_lock_irqsave(&unwind_lock, flags);
170	list_del(&table->list);
171	spin_unlock_irqrestore(&unwind_lock, flags);
172
173	kfree(table);
174}
175
176/* Called from setup_arch to import the kernel unwind info */
177int __init unwind_init(void)
178{
179	long start, stop;
180	register unsigned long gp __asm__ ("r27");
181
182	start = (long)&__start___unwind[0];
183	stop = (long)&__stop___unwind[0];
184
185	dbg("unwind_init: start = 0x%lx, end = 0x%lx, entries = %lu\n",
 
 
186	    start, stop,
187	    (stop - start) / sizeof(struct unwind_table_entry));
188
189	unwind_table_init(&kernel_unwind_table, "kernel", KERNEL_START,
190			  gp, 
191			  &__start___unwind[0], &__stop___unwind[0]);
192#if 0
193	{
194		int i;
195		for (i = 0; i < 10; i++)
196		{
197			printk("region 0x%x-0x%x\n", 
198				__start___unwind[i].region_start, 
199				__start___unwind[i].region_end);
200		}
201	}
202#endif
203	return 0;
204}
205
 
 
 
 
 
 
206static int unwind_special(struct unwind_frame_info *info, unsigned long pc, int frame_size)
207{
208	/*
209	 * We have to use void * instead of a function pointer, because
210	 * function pointers aren't a pointer to the function on 64-bit.
211	 * Make them const so the compiler knows they live in .text
212	 * Note: We could use dereference_kernel_function_descriptor()
213	 * instead but we want to keep it simple here.
214	 */
215	extern void * const handle_interruption;
216	extern void * const ret_from_kernel_thread;
217	extern void * const syscall_exit;
218	extern void * const intr_return;
219	extern void * const _switch_to_ret;
220#ifdef CONFIG_IRQSTACKS
221	extern void * const _call_on_stack;
222#endif /* CONFIG_IRQSTACKS */
223
224	if (pc == (unsigned long) &handle_interruption) {
225		struct pt_regs *regs = (struct pt_regs *)(info->sp - frame_size - PT_SZ_ALGN);
226		dbg("Unwinding through handle_interruption()\n");
227		info->prev_sp = regs->gr[30];
228		info->prev_ip = regs->iaoq[0];
229		return 1;
230	}
231
232	if (pc == (unsigned long) &ret_from_kernel_thread ||
233	    pc == (unsigned long) &syscall_exit) {
234		info->prev_sp = info->prev_ip = 0;
235		return 1;
236	}
237
238	if (pc == (unsigned long) &intr_return) {
239		struct pt_regs *regs;
240
241		dbg("Found intr_return()\n");
242		regs = (struct pt_regs *)(info->sp - PT_SZ_ALGN);
243		info->prev_sp = regs->gr[30];
244		info->prev_ip = regs->iaoq[0];
245		info->rp = regs->gr[2];
246		return 1;
247	}
248
249	if (pc == (unsigned long) &_switch_to_ret) {
250		info->prev_sp = info->sp - CALLEE_SAVE_FRAME_SIZE;
251		info->prev_ip = *(unsigned long *)(info->prev_sp - RP_OFFSET);
252		return 1;
253	}
254
255#ifdef CONFIG_IRQSTACKS
256	if (pc == (unsigned long) &_call_on_stack) {
257		info->prev_sp = *(unsigned long *)(info->sp - FRAME_SIZE - REG_SZ);
258		info->prev_ip = *(unsigned long *)(info->sp - FRAME_SIZE - RP_OFFSET);
259		return 1;
260	}
261#endif
262
263	return 0;
264}
265
266static void unwind_frame_regs(struct unwind_frame_info *info)
267{
268	const struct unwind_table_entry *e;
269	unsigned long npc;
270	unsigned int insn;
271	long frame_size = 0;
272	int looking_for_rp, rpoffset = 0;
273
274	e = find_unwind_entry(info->ip);
275	if (e == NULL) {
276		unsigned long sp;
277
278		dbg("Cannot find unwind entry for %pS; forced unwinding\n",
279			(void *) info->ip);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
280
281		/* Since we are doing the unwinding blind, we don't know if
282		   we are adjusting the stack correctly or extracting the rp
283		   correctly. The rp is checked to see if it belongs to the
284		   kernel text section, if not we assume we don't have a 
285		   correct stack frame and we continue to unwind the stack.
286		   This is not quite correct, and will fail for loadable
287		   modules. */
288		sp = info->sp & ~63;
289		do {
290			unsigned long tmp;
291
292			info->prev_sp = sp - 64;
293			info->prev_ip = 0;
294
295			/* The stack is at the end inside the thread_union
296			 * struct. If we reach data, we have reached the
297			 * beginning of the stack and should stop unwinding. */
298			if (info->prev_sp >= (unsigned long) task_thread_info(info->t) &&
299			    info->prev_sp < ((unsigned long) task_thread_info(info->t)
300						+ THREAD_SZ_ALGN)) {
301				info->prev_sp = 0;
302				break;
303			}
304
305			if (get_user(tmp, (unsigned long *)(info->prev_sp - RP_OFFSET))) 
306				break;
307			info->prev_ip = tmp;
308			sp = info->prev_sp;
309		} while (!kernel_text_address(info->prev_ip));
310
311		info->rp = 0;
312
313		dbg("analyzing func @ %lx with no unwind info, setting "
314		    "prev_sp=%lx prev_ip=%lx\n", info->ip, 
315		    info->prev_sp, info->prev_ip);
316	} else {
317		dbg("e->start = 0x%x, e->end = 0x%x, Save_SP = %d, "
318		    "Save_RP = %d, Millicode = %d size = %u\n", 
319		    e->region_start, e->region_end, e->Save_SP, e->Save_RP, 
320		    e->Millicode, e->Total_frame_size);
321
322		looking_for_rp = e->Save_RP;
323
324		for (npc = e->region_start; 
325		     (frame_size < (e->Total_frame_size << 3) || 
326		      looking_for_rp) && 
327		     npc < info->ip; 
328		     npc += 4) {
329
330			insn = *(unsigned int *)npc;
331
332			if ((insn & 0xffffc001) == 0x37de0000 ||
333			    (insn & 0xffe00001) == 0x6fc00000) {
334				/* ldo X(sp), sp, or stwm X,D(sp) */
335				frame_size += (insn & 0x3fff) >> 1;
336				dbg("analyzing func @ %lx, insn=%08x @ "
337				    "%lx, frame_size = %ld\n", info->ip,
338				    insn, npc, frame_size);
339			} else if ((insn & 0xffe00009) == 0x73c00008) {
340				/* std,ma X,D(sp) */
341				frame_size += ((insn >> 4) & 0x3ff) << 3;
342				dbg("analyzing func @ %lx, insn=%08x @ "
343				    "%lx, frame_size = %ld\n", info->ip,
344				    insn, npc, frame_size);
345			} else if (insn == 0x6bc23fd9) { 
346				/* stw rp,-20(sp) */
347				rpoffset = 20;
348				looking_for_rp = 0;
349				dbg("analyzing func @ %lx, insn=stw rp,"
350				    "-20(sp) @ %lx\n", info->ip, npc);
351			} else if (insn == 0x0fc212c1) {
352				/* std rp,-16(sr0,sp) */
353				rpoffset = 16;
354				looking_for_rp = 0;
355				dbg("analyzing func @ %lx, insn=std rp,"
356				    "-16(sp) @ %lx\n", info->ip, npc);
357			}
358		}
359
360		if (frame_size > e->Total_frame_size << 3)
361			frame_size = e->Total_frame_size << 3;
362
363		if (!unwind_special(info, e->region_start, frame_size)) {
364			info->prev_sp = info->sp - frame_size;
365			if (e->Millicode)
366				info->rp = info->r31;
367			else if (rpoffset)
368				info->rp = *(unsigned long *)(info->prev_sp - rpoffset);
369			info->prev_ip = info->rp;
370			info->rp = 0;
371		}
372
373		dbg("analyzing func @ %lx, setting prev_sp=%lx "
374		    "prev_ip=%lx npc=%lx\n", info->ip, info->prev_sp, 
375		    info->prev_ip, npc);
376	}
377}
378
379void unwind_frame_init(struct unwind_frame_info *info, struct task_struct *t, 
380		       struct pt_regs *regs)
381{
382	memset(info, 0, sizeof(struct unwind_frame_info));
383	info->t = t;
384	info->sp = regs->gr[30];
385	info->ip = regs->iaoq[0];
386	info->rp = regs->gr[2];
387	info->r31 = regs->gr[31];
388
389	dbg("(%d) Start unwind from sp=%08lx ip=%08lx\n", 
390	    t ? (int)t->pid : -1, info->sp, info->ip);
391}
392
393void unwind_frame_init_from_blocked_task(struct unwind_frame_info *info, struct task_struct *t)
394{
395	struct pt_regs *r = &t->thread.regs;
396	struct pt_regs *r2;
397
398	r2 = kmalloc(sizeof(struct pt_regs), GFP_ATOMIC);
399	if (!r2)
400		return;
401	*r2 = *r;
402	r2->gr[30] = r->ksp;
403	r2->iaoq[0] = r->kpc;
404	unwind_frame_init(info, t, r2);
405	kfree(r2);
406}
407
408#define get_parisc_stackpointer() ({ \
409	unsigned long sp; \
410	__asm__("copy %%r30, %0" : "=r"(sp)); \
411	(sp); \
412})
413
414void unwind_frame_init_task(struct unwind_frame_info *info,
415	struct task_struct *task, struct pt_regs *regs)
416{
417	task = task ? task : current;
418
419	if (task == current) {
420		struct pt_regs r;
421
422		if (!regs) {
423			memset(&r, 0, sizeof(r));
424			r.iaoq[0] =  _THIS_IP_;
425			r.gr[2] = _RET_IP_;
426			r.gr[30] = get_parisc_stackpointer();
427			regs = &r;
428		}
429		unwind_frame_init(info, task, regs);
430	} else {
431		unwind_frame_init_from_blocked_task(info, task);
432	}
433}
434
435int unwind_once(struct unwind_frame_info *next_frame)
436{
437	unwind_frame_regs(next_frame);
438
439	if (next_frame->prev_sp == 0 ||
440	    next_frame->prev_ip == 0)
441		return -1;
442
443	next_frame->sp = next_frame->prev_sp;
444	next_frame->ip = next_frame->prev_ip;
445	next_frame->prev_sp = 0;
446	next_frame->prev_ip = 0;
447
448	dbg("(%d) Continue unwind to sp=%08lx ip=%08lx\n", 
449	    next_frame->t ? (int)next_frame->t->pid : -1, 
450	    next_frame->sp, next_frame->ip);
451
452	return 0;
453}
454
455int unwind_to_user(struct unwind_frame_info *info)
456{
457	int ret;
458	
459	do {
460		ret = unwind_once(info);
461	} while (!ret && !(info->ip & 3));
462
463	return ret;
464}
465
466unsigned long return_address(unsigned int level)
467{
468	struct unwind_frame_info info;
 
 
469
470	/* initialize unwind info */
471	unwind_frame_init_task(&info, current, NULL);
 
 
 
 
 
472
473	/* unwind stack */
474	level += 2;
475	do {
476		if (unwind_once(&info) < 0 || info.ip == 0)
477			return 0;
478		if (!kernel_text_address(info.ip))
479			return 0;
480	} while (info.ip && level--);
481
482	return info.ip;
483}
v4.10.11
 
  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#include <linux/sort.h>
 17
 18#include <linux/uaccess.h>
 19#include <asm/assembly.h>
 20#include <asm/asm-offsets.h>
 21#include <asm/ptrace.h>
 22
 23#include <asm/unwind.h>
 24
 25/* #define DEBUG 1 */
 26#ifdef DEBUG
 27#define dbg(x...) printk(x)
 28#else
 29#define dbg(x...)
 30#endif
 31
 32#define KERNEL_START (KERNEL_BINARY_TEXT_START)
 33
 34extern struct unwind_table_entry __start___unwind[];
 35extern struct unwind_table_entry __stop___unwind[];
 36
 37static spinlock_t unwind_lock;
 38/*
 39 * the kernel unwind block is not dynamically allocated so that
 40 * we can call unwind_init as early in the bootup process as 
 41 * possible (before the slab allocator is initialized)
 42 */
 43static struct unwind_table kernel_unwind_table __read_mostly;
 44static LIST_HEAD(unwind_tables);
 45
 46static inline const struct unwind_table_entry *
 47find_unwind_entry_in_table(const struct unwind_table *table, unsigned long addr)
 48{
 49	const struct unwind_table_entry *e = NULL;
 50	unsigned long lo, hi, mid;
 51
 52	lo = 0; 
 53	hi = table->length - 1; 
 54	
 55	while (lo <= hi) {
 56		mid = (hi - lo) / 2 + lo;
 57		e = &table->table[mid];
 58		if (addr < e->region_start)
 59			hi = mid - 1;
 60		else if (addr > e->region_end)
 61			lo = mid + 1;
 62		else
 63			return e;
 64	}
 65
 66	return NULL;
 67}
 68
 69static const struct unwind_table_entry *
 70find_unwind_entry(unsigned long addr)
 71{
 72	struct unwind_table *table;
 73	const struct unwind_table_entry *e = NULL;
 74
 75	if (addr >= kernel_unwind_table.start && 
 76	    addr <= kernel_unwind_table.end)
 77		e = find_unwind_entry_in_table(&kernel_unwind_table, addr);
 78	else {
 79		unsigned long flags;
 80
 81		spin_lock_irqsave(&unwind_lock, flags);
 82		list_for_each_entry(table, &unwind_tables, list) {
 83			if (addr >= table->start && 
 84			    addr <= table->end)
 85				e = find_unwind_entry_in_table(table, addr);
 86			if (e) {
 87				/* Move-to-front to exploit common traces */
 88				list_move(&table->list, &unwind_tables);
 89				break;
 90			}
 91		}
 92		spin_unlock_irqrestore(&unwind_lock, flags);
 93	}
 94
 95	return e;
 96}
 97
 98static void
 99unwind_table_init(struct unwind_table *table, const char *name,
100		  unsigned long base_addr, unsigned long gp,
101		  void *table_start, void *table_end)
102{
103	struct unwind_table_entry *start = table_start;
104	struct unwind_table_entry *end = 
105		(struct unwind_table_entry *)table_end - 1;
106
107	table->name = name;
108	table->base_addr = base_addr;
109	table->gp = gp;
110	table->start = base_addr + start->region_start;
111	table->end = base_addr + end->region_end;
112	table->table = (struct unwind_table_entry *)table_start;
113	table->length = end - start + 1;
114	INIT_LIST_HEAD(&table->list);
115
116	for (; start <= end; start++) {
117		if (start < end && 
118		    start->region_end > (start+1)->region_start) {
119			printk("WARNING: Out of order unwind entry! %p and %p\n", start, start+1);
 
120		}
121
122		start->region_start += base_addr;
123		start->region_end += base_addr;
124	}
125}
126
127static int cmp_unwind_table_entry(const void *a, const void *b)
128{
129	return ((const struct unwind_table_entry *)a)->region_start
130	     - ((const struct unwind_table_entry *)b)->region_start;
131}
132
133static void
134unwind_table_sort(struct unwind_table_entry *start,
135		  struct unwind_table_entry *finish)
136{
137	sort(start, finish - start, sizeof(struct unwind_table_entry),
138	     cmp_unwind_table_entry, NULL);
139}
140
141struct unwind_table *
142unwind_table_add(const char *name, unsigned long base_addr, 
143		 unsigned long gp,
144                 void *start, void *end)
145{
146	struct unwind_table *table;
147	unsigned long flags;
148	struct unwind_table_entry *s = (struct unwind_table_entry *)start;
149	struct unwind_table_entry *e = (struct unwind_table_entry *)end;
150
151	unwind_table_sort(s, e);
152
153	table = kmalloc(sizeof(struct unwind_table), GFP_USER);
154	if (table == NULL)
155		return NULL;
156	unwind_table_init(table, name, base_addr, gp, start, end);
157	spin_lock_irqsave(&unwind_lock, flags);
158	list_add_tail(&table->list, &unwind_tables);
159	spin_unlock_irqrestore(&unwind_lock, flags);
160
161	return table;
162}
163
164void unwind_table_remove(struct unwind_table *table)
165{
166	unsigned long flags;
167
168	spin_lock_irqsave(&unwind_lock, flags);
169	list_del(&table->list);
170	spin_unlock_irqrestore(&unwind_lock, flags);
171
172	kfree(table);
173}
174
175/* Called from setup_arch to import the kernel unwind info */
176int __init unwind_init(void)
177{
178	long start, stop;
179	register unsigned long gp __asm__ ("r27");
180
181	start = (long)&__start___unwind[0];
182	stop = (long)&__stop___unwind[0];
183
184	spin_lock_init(&unwind_lock);
185
186	printk("unwind_init: start = 0x%lx, end = 0x%lx, entries = %lu\n", 
187	    start, stop,
188	    (stop - start) / sizeof(struct unwind_table_entry));
189
190	unwind_table_init(&kernel_unwind_table, "kernel", KERNEL_START,
191			  gp, 
192			  &__start___unwind[0], &__stop___unwind[0]);
193#if 0
194	{
195		int i;
196		for (i = 0; i < 10; i++)
197		{
198			printk("region 0x%x-0x%x\n", 
199				__start___unwind[i].region_start, 
200				__start___unwind[i].region_end);
201		}
202	}
203#endif
204	return 0;
205}
206
207#ifdef CONFIG_64BIT
208#define get_func_addr(fptr) fptr[2]
209#else
210#define get_func_addr(fptr) fptr[0]
211#endif
212
213static int unwind_special(struct unwind_frame_info *info, unsigned long pc, int frame_size)
214{
215	extern void handle_interruption(int, struct pt_regs *);
216	static unsigned long *hi = (unsigned long *)&handle_interruption;
 
 
 
 
 
 
 
 
 
 
 
 
 
217
218	if (pc == get_func_addr(hi)) {
219		struct pt_regs *regs = (struct pt_regs *)(info->sp - frame_size - PT_SZ_ALGN);
220		dbg("Unwinding through handle_interruption()\n");
221		info->prev_sp = regs->gr[30];
222		info->prev_ip = regs->iaoq[0];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
223
 
 
 
224		return 1;
225	}
226
 
 
 
 
 
 
 
 
227	return 0;
228}
229
230static void unwind_frame_regs(struct unwind_frame_info *info)
231{
232	const struct unwind_table_entry *e;
233	unsigned long npc;
234	unsigned int insn;
235	long frame_size = 0;
236	int looking_for_rp, rpoffset = 0;
237
238	e = find_unwind_entry(info->ip);
239	if (e == NULL) {
240		unsigned long sp;
241
242		dbg("Cannot find unwind entry for 0x%lx; forced unwinding\n", info->ip);
243
244#ifdef CONFIG_KALLSYMS
245		/* Handle some frequent special cases.... */
246		{
247			char symname[KSYM_NAME_LEN];
248			char *modname;
249
250			kallsyms_lookup(info->ip, NULL, NULL, &modname,
251				symname);
252
253			dbg("info->ip = 0x%lx, name = %s\n", info->ip, symname);
254
255			if (strcmp(symname, "_switch_to_ret") == 0) {
256				info->prev_sp = info->sp - CALLEE_SAVE_FRAME_SIZE;
257				info->prev_ip = *(unsigned long *)(info->prev_sp - RP_OFFSET);
258				dbg("_switch_to_ret @ %lx - setting "
259				    "prev_sp=%lx prev_ip=%lx\n", 
260				    info->ip, info->prev_sp, 
261				    info->prev_ip);
262				return;
263			} else if (strcmp(symname, "ret_from_kernel_thread") == 0 ||
264				   strcmp(symname, "syscall_exit") == 0) {
265				info->prev_ip = info->prev_sp = 0;
266				return;
267			}
268		}
269#endif
270
271		/* Since we are doing the unwinding blind, we don't know if
272		   we are adjusting the stack correctly or extracting the rp
273		   correctly. The rp is checked to see if it belongs to the
274		   kernel text section, if not we assume we don't have a 
275		   correct stack frame and we continue to unwind the stack.
276		   This is not quite correct, and will fail for loadable
277		   modules. */
278		sp = info->sp & ~63;
279		do {
280			unsigned long tmp;
281
282			info->prev_sp = sp - 64;
283			info->prev_ip = 0;
 
 
 
 
 
 
 
 
 
 
 
284			if (get_user(tmp, (unsigned long *)(info->prev_sp - RP_OFFSET))) 
285				break;
286			info->prev_ip = tmp;
287			sp = info->prev_sp;
288		} while (!kernel_text_address(info->prev_ip));
289
290		info->rp = 0;
291
292		dbg("analyzing func @ %lx with no unwind info, setting "
293		    "prev_sp=%lx prev_ip=%lx\n", info->ip, 
294		    info->prev_sp, info->prev_ip);
295	} else {
296		dbg("e->start = 0x%x, e->end = 0x%x, Save_SP = %d, "
297		    "Save_RP = %d, Millicode = %d size = %u\n", 
298		    e->region_start, e->region_end, e->Save_SP, e->Save_RP, 
299		    e->Millicode, e->Total_frame_size);
300
301		looking_for_rp = e->Save_RP;
302
303		for (npc = e->region_start; 
304		     (frame_size < (e->Total_frame_size << 3) || 
305		      looking_for_rp) && 
306		     npc < info->ip; 
307		     npc += 4) {
308
309			insn = *(unsigned int *)npc;
310
311			if ((insn & 0xffffc001) == 0x37de0000 ||
312			    (insn & 0xffe00001) == 0x6fc00000) {
313				/* ldo X(sp), sp, or stwm X,D(sp) */
314				frame_size += (insn & 0x3fff) >> 1;
315				dbg("analyzing func @ %lx, insn=%08x @ "
316				    "%lx, frame_size = %ld\n", info->ip,
317				    insn, npc, frame_size);
318			} else if ((insn & 0xffe00009) == 0x73c00008) {
319				/* std,ma X,D(sp) */
320				frame_size += ((insn >> 4) & 0x3ff) << 3;
321				dbg("analyzing func @ %lx, insn=%08x @ "
322				    "%lx, frame_size = %ld\n", info->ip,
323				    insn, npc, frame_size);
324			} else if (insn == 0x6bc23fd9) { 
325				/* stw rp,-20(sp) */
326				rpoffset = 20;
327				looking_for_rp = 0;
328				dbg("analyzing func @ %lx, insn=stw rp,"
329				    "-20(sp) @ %lx\n", info->ip, npc);
330			} else if (insn == 0x0fc212c1) {
331				/* std rp,-16(sr0,sp) */
332				rpoffset = 16;
333				looking_for_rp = 0;
334				dbg("analyzing func @ %lx, insn=std rp,"
335				    "-16(sp) @ %lx\n", info->ip, npc);
336			}
337		}
338
339		if (frame_size > e->Total_frame_size << 3)
340			frame_size = e->Total_frame_size << 3;
341
342		if (!unwind_special(info, e->region_start, frame_size)) {
343			info->prev_sp = info->sp - frame_size;
344			if (e->Millicode)
345				info->rp = info->r31;
346			else if (rpoffset)
347				info->rp = *(unsigned long *)(info->prev_sp - rpoffset);
348			info->prev_ip = info->rp;
349			info->rp = 0;
350		}
351
352		dbg("analyzing func @ %lx, setting prev_sp=%lx "
353		    "prev_ip=%lx npc=%lx\n", info->ip, info->prev_sp, 
354		    info->prev_ip, npc);
355	}
356}
357
358void unwind_frame_init(struct unwind_frame_info *info, struct task_struct *t, 
359		       struct pt_regs *regs)
360{
361	memset(info, 0, sizeof(struct unwind_frame_info));
362	info->t = t;
363	info->sp = regs->gr[30];
364	info->ip = regs->iaoq[0];
365	info->rp = regs->gr[2];
366	info->r31 = regs->gr[31];
367
368	dbg("(%d) Start unwind from sp=%08lx ip=%08lx\n", 
369	    t ? (int)t->pid : -1, info->sp, info->ip);
370}
371
372void unwind_frame_init_from_blocked_task(struct unwind_frame_info *info, struct task_struct *t)
373{
374	struct pt_regs *r = &t->thread.regs;
375	struct pt_regs *r2;
376
377	r2 = kmalloc(sizeof(struct pt_regs), GFP_ATOMIC);
378	if (!r2)
379		return;
380	*r2 = *r;
381	r2->gr[30] = r->ksp;
382	r2->iaoq[0] = r->kpc;
383	unwind_frame_init(info, t, r2);
384	kfree(r2);
385}
386
387void unwind_frame_init_running(struct unwind_frame_info *info, struct pt_regs *regs)
388{
389	unwind_frame_init(info, current, regs);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
390}
391
392int unwind_once(struct unwind_frame_info *next_frame)
393{
394	unwind_frame_regs(next_frame);
395
396	if (next_frame->prev_sp == 0 ||
397	    next_frame->prev_ip == 0)
398		return -1;
399
400	next_frame->sp = next_frame->prev_sp;
401	next_frame->ip = next_frame->prev_ip;
402	next_frame->prev_sp = 0;
403	next_frame->prev_ip = 0;
404
405	dbg("(%d) Continue unwind to sp=%08lx ip=%08lx\n", 
406	    next_frame->t ? (int)next_frame->t->pid : -1, 
407	    next_frame->sp, next_frame->ip);
408
409	return 0;
410}
411
412int unwind_to_user(struct unwind_frame_info *info)
413{
414	int ret;
415	
416	do {
417		ret = unwind_once(info);
418	} while (!ret && !(info->ip & 3));
419
420	return ret;
421}
422
423unsigned long return_address(unsigned int level)
424{
425	struct unwind_frame_info info;
426	struct pt_regs r;
427	unsigned long sp;
428
429	/* initialize unwind info */
430	asm volatile ("copy %%r30, %0" : "=r"(sp));
431	memset(&r, 0, sizeof(struct pt_regs));
432	r.iaoq[0] = (unsigned long) current_text_addr();
433	r.gr[2] = (unsigned long) __builtin_return_address(0);
434	r.gr[30] = sp;
435	unwind_frame_init(&info, current, &r);
436
437	/* unwind stack */
438	++level;
439	do {
440		if (unwind_once(&info) < 0 || info.ip == 0)
441			return 0;
442		if (!kernel_text_address(info.ip))
443			return 0;
444	} while (info.ip && level--);
445
446	return info.ip;
447}