Linux Audio

Check our new training course

Loading...
v4.6
  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 <asm/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		list_for_each_entry(table, &unwind_tables, list) {
 80			if (addr >= table->start && 
 81			    addr <= table->end)
 82				e = find_unwind_entry_in_table(table, addr);
 83			if (e) {
 84				/* Move-to-front to exploit common traces */
 85				list_move(&table->list, &unwind_tables);
 86				break;
 87			}
 88		}
 
 
 89
 90	return e;
 91}
 92
 93static void
 94unwind_table_init(struct unwind_table *table, const char *name,
 95		  unsigned long base_addr, unsigned long gp,
 96		  void *table_start, void *table_end)
 97{
 98	struct unwind_table_entry *start = table_start;
 99	struct unwind_table_entry *end = 
100		(struct unwind_table_entry *)table_end - 1;
101
102	table->name = name;
103	table->base_addr = base_addr;
104	table->gp = gp;
105	table->start = base_addr + start->region_start;
106	table->end = base_addr + end->region_end;
107	table->table = (struct unwind_table_entry *)table_start;
108	table->length = end - start + 1;
109	INIT_LIST_HEAD(&table->list);
110
111	for (; start <= end; start++) {
112		if (start < end && 
113		    start->region_end > (start+1)->region_start) {
114			printk("WARNING: Out of order unwind entry! %p and %p\n", start, start+1);
115		}
116
117		start->region_start += base_addr;
118		start->region_end += base_addr;
119	}
120}
121
122static int cmp_unwind_table_entry(const void *a, const void *b)
123{
124	return ((const struct unwind_table_entry *)a)->region_start
125	     - ((const struct unwind_table_entry *)b)->region_start;
126}
127
128static void
129unwind_table_sort(struct unwind_table_entry *start,
130		  struct unwind_table_entry *finish)
131{
132	sort(start, finish - start, sizeof(struct unwind_table_entry),
133	     cmp_unwind_table_entry, NULL);
134}
135
136struct unwind_table *
137unwind_table_add(const char *name, unsigned long base_addr, 
138		 unsigned long gp,
139                 void *start, void *end)
140{
141	struct unwind_table *table;
142	unsigned long flags;
143	struct unwind_table_entry *s = (struct unwind_table_entry *)start;
144	struct unwind_table_entry *e = (struct unwind_table_entry *)end;
145
146	unwind_table_sort(s, e);
147
148	table = kmalloc(sizeof(struct unwind_table), GFP_USER);
149	if (table == NULL)
150		return NULL;
151	unwind_table_init(table, name, base_addr, gp, start, end);
152	spin_lock_irqsave(&unwind_lock, flags);
153	list_add_tail(&table->list, &unwind_tables);
154	spin_unlock_irqrestore(&unwind_lock, flags);
155
156	return table;
157}
158
159void unwind_table_remove(struct unwind_table *table)
160{
161	unsigned long flags;
162
163	spin_lock_irqsave(&unwind_lock, flags);
164	list_del(&table->list);
165	spin_unlock_irqrestore(&unwind_lock, flags);
166
167	kfree(table);
168}
169
170/* Called from setup_arch to import the kernel unwind info */
171int __init unwind_init(void)
172{
173	long start, stop;
174	register unsigned long gp __asm__ ("r27");
175
176	start = (long)&__start___unwind[0];
177	stop = (long)&__stop___unwind[0];
178
179	spin_lock_init(&unwind_lock);
180
181	printk("unwind_init: start = 0x%lx, end = 0x%lx, entries = %lu\n", 
182	    start, stop,
183	    (stop - start) / sizeof(struct unwind_table_entry));
184
185	unwind_table_init(&kernel_unwind_table, "kernel", KERNEL_START,
186			  gp, 
187			  &__start___unwind[0], &__stop___unwind[0]);
188#if 0
189	{
190		int i;
191		for (i = 0; i < 10; i++)
192		{
193			printk("region 0x%x-0x%x\n", 
194				__start___unwind[i].region_start, 
195				__start___unwind[i].region_end);
196		}
197	}
198#endif
199	return 0;
200}
201
202#ifdef CONFIG_64BIT
203#define get_func_addr(fptr) fptr[2]
204#else
205#define get_func_addr(fptr) fptr[0]
206#endif
207
208static int unwind_special(struct unwind_frame_info *info, unsigned long pc, int frame_size)
209{
210	extern void handle_interruption(int, struct pt_regs *);
211	static unsigned long *hi = (unsigned long *)&handle_interruption;
212
213	if (pc == get_func_addr(hi)) {
214		struct pt_regs *regs = (struct pt_regs *)(info->sp - frame_size - PT_SZ_ALGN);
215		dbg("Unwinding through handle_interruption()\n");
216		info->prev_sp = regs->gr[30];
217		info->prev_ip = regs->iaoq[0];
218
219		return 1;
220	}
221
222	return 0;
223}
224
225static void unwind_frame_regs(struct unwind_frame_info *info)
226{
227	const struct unwind_table_entry *e;
228	unsigned long npc;
229	unsigned int insn;
230	long frame_size = 0;
231	int looking_for_rp, rpoffset = 0;
232
233	e = find_unwind_entry(info->ip);
234	if (e == NULL) {
235		unsigned long sp;
236
237		dbg("Cannot find unwind entry for 0x%lx; forced unwinding\n", info->ip);
238
239#ifdef CONFIG_KALLSYMS
240		/* Handle some frequent special cases.... */
241		{
242			char symname[KSYM_NAME_LEN];
243			char *modname;
244
245			kallsyms_lookup(info->ip, NULL, NULL, &modname,
246				symname);
247
248			dbg("info->ip = 0x%lx, name = %s\n", info->ip, symname);
249
250			if (strcmp(symname, "_switch_to_ret") == 0) {
251				info->prev_sp = info->sp - CALLEE_SAVE_FRAME_SIZE;
252				info->prev_ip = *(unsigned long *)(info->prev_sp - RP_OFFSET);
253				dbg("_switch_to_ret @ %lx - setting "
254				    "prev_sp=%lx prev_ip=%lx\n", 
255				    info->ip, info->prev_sp, 
256				    info->prev_ip);
257				return;
258			} else if (strcmp(symname, "ret_from_kernel_thread") == 0 ||
259				   strcmp(symname, "syscall_exit") == 0) {
260				info->prev_ip = info->prev_sp = 0;
261				return;
262			}
263		}
264#endif
265
266		/* Since we are doing the unwinding blind, we don't know if
267		   we are adjusting the stack correctly or extracting the rp
268		   correctly. The rp is checked to see if it belongs to the
269		   kernel text section, if not we assume we don't have a 
270		   correct stack frame and we continue to unwind the stack.
271		   This is not quite correct, and will fail for loadable
272		   modules. */
273		sp = info->sp & ~63;
274		do {
275			unsigned long tmp;
276
277			info->prev_sp = sp - 64;
278			info->prev_ip = 0;
279			if (get_user(tmp, (unsigned long *)(info->prev_sp - RP_OFFSET))) 
280				break;
281			info->prev_ip = tmp;
282			sp = info->prev_sp;
283		} while (!kernel_text_address(info->prev_ip));
284
285		info->rp = 0;
286
287		dbg("analyzing func @ %lx with no unwind info, setting "
288		    "prev_sp=%lx prev_ip=%lx\n", info->ip, 
289		    info->prev_sp, info->prev_ip);
290	} else {
291		dbg("e->start = 0x%x, e->end = 0x%x, Save_SP = %d, "
292		    "Save_RP = %d, Millicode = %d size = %u\n", 
293		    e->region_start, e->region_end, e->Save_SP, e->Save_RP, 
294		    e->Millicode, e->Total_frame_size);
295
296		looking_for_rp = e->Save_RP;
297
298		for (npc = e->region_start; 
299		     (frame_size < (e->Total_frame_size << 3) || 
300		      looking_for_rp) && 
301		     npc < info->ip; 
302		     npc += 4) {
303
304			insn = *(unsigned int *)npc;
305
306			if ((insn & 0xffffc000) == 0x37de0000 ||
307			    (insn & 0xffe00000) == 0x6fc00000) {
308				/* ldo X(sp), sp, or stwm X,D(sp) */
309				frame_size += (insn & 0x1 ? -1 << 13 : 0) | 
310					((insn & 0x3fff) >> 1);
311				dbg("analyzing func @ %lx, insn=%08x @ "
312				    "%lx, frame_size = %ld\n", info->ip,
313				    insn, npc, frame_size);
314			} else if ((insn & 0xffe00008) == 0x73c00008) {
315				/* std,ma X,D(sp) */
316				frame_size += (insn & 0x1 ? -1 << 13 : 0) | 
317					(((insn >> 4) & 0x3ff) << 3);
318				dbg("analyzing func @ %lx, insn=%08x @ "
319				    "%lx, frame_size = %ld\n", info->ip,
320				    insn, npc, frame_size);
321			} else if (insn == 0x6bc23fd9) { 
322				/* stw rp,-20(sp) */
323				rpoffset = 20;
324				looking_for_rp = 0;
325				dbg("analyzing func @ %lx, insn=stw rp,"
326				    "-20(sp) @ %lx\n", info->ip, npc);
327			} else if (insn == 0x0fc212c1) {
328				/* std rp,-16(sr0,sp) */
329				rpoffset = 16;
330				looking_for_rp = 0;
331				dbg("analyzing func @ %lx, insn=std rp,"
332				    "-16(sp) @ %lx\n", info->ip, npc);
333			}
334		}
 
 
 
335
336		if (!unwind_special(info, e->region_start, frame_size)) {
337			info->prev_sp = info->sp - frame_size;
338			if (e->Millicode)
339				info->rp = info->r31;
340			else if (rpoffset)
341				info->rp = *(unsigned long *)(info->prev_sp - rpoffset);
342			info->prev_ip = info->rp;
343			info->rp = 0;
344		}
345
346		dbg("analyzing func @ %lx, setting prev_sp=%lx "
347		    "prev_ip=%lx npc=%lx\n", info->ip, info->prev_sp, 
348		    info->prev_ip, npc);
349	}
350}
351
352void unwind_frame_init(struct unwind_frame_info *info, struct task_struct *t, 
353		       struct pt_regs *regs)
354{
355	memset(info, 0, sizeof(struct unwind_frame_info));
356	info->t = t;
357	info->sp = regs->gr[30];
358	info->ip = regs->iaoq[0];
359	info->rp = regs->gr[2];
360	info->r31 = regs->gr[31];
361
362	dbg("(%d) Start unwind from sp=%08lx ip=%08lx\n", 
363	    t ? (int)t->pid : -1, info->sp, info->ip);
364}
365
366void unwind_frame_init_from_blocked_task(struct unwind_frame_info *info, struct task_struct *t)
367{
368	struct pt_regs *r = &t->thread.regs;
369	struct pt_regs *r2;
370
371	r2 = kmalloc(sizeof(struct pt_regs), GFP_ATOMIC);
372	if (!r2)
373		return;
374	*r2 = *r;
375	r2->gr[30] = r->ksp;
376	r2->iaoq[0] = r->kpc;
377	unwind_frame_init(info, t, r2);
378	kfree(r2);
379}
380
381void unwind_frame_init_running(struct unwind_frame_info *info, struct pt_regs *regs)
382{
383	unwind_frame_init(info, current, regs);
384}
385
386int unwind_once(struct unwind_frame_info *next_frame)
387{
388	unwind_frame_regs(next_frame);
389
390	if (next_frame->prev_sp == 0 ||
391	    next_frame->prev_ip == 0)
392		return -1;
393
394	next_frame->sp = next_frame->prev_sp;
395	next_frame->ip = next_frame->prev_ip;
396	next_frame->prev_sp = 0;
397	next_frame->prev_ip = 0;
398
399	dbg("(%d) Continue unwind to sp=%08lx ip=%08lx\n", 
400	    next_frame->t ? (int)next_frame->t->pid : -1, 
401	    next_frame->sp, next_frame->ip);
402
403	return 0;
404}
405
406int unwind_to_user(struct unwind_frame_info *info)
407{
408	int ret;
409	
410	do {
411		ret = unwind_once(info);
412	} while (!ret && !(info->ip & 3));
413
414	return ret;
415}
416
417unsigned long return_address(unsigned int level)
418{
419	struct unwind_frame_info info;
420	struct pt_regs r;
421	unsigned long sp;
422
423	/* initialize unwind info */
424	asm volatile ("copy %%r30, %0" : "=r"(sp));
425	memset(&r, 0, sizeof(struct pt_regs));
426	r.iaoq[0] = (unsigned long) current_text_addr();
427	r.gr[2] = (unsigned long) __builtin_return_address(0);
428	r.gr[30] = sp;
429	unwind_frame_init(&info, current, &r);
430
431	/* unwind stack */
432	++level;
433	do {
434		if (unwind_once(&info) < 0 || info.ip == 0)
435			return 0;
436		if (!kernel_text_address(info.ip))
437			return 0;
438	} while (info.ip && level--);
439
440	return info.ip;
441}
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}