aboutsummaryrefslogtreecommitdiffstats
path: root/arch/parisc/kernel/unwind.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/parisc/kernel/unwind.c')
-rw-r--r--arch/parisc/kernel/unwind.c50
1 files changed, 36 insertions, 14 deletions
diff --git a/arch/parisc/kernel/unwind.c b/arch/parisc/kernel/unwind.c
index a36799e85693..d58eac1a8288 100644
--- a/arch/parisc/kernel/unwind.c
+++ b/arch/parisc/kernel/unwind.c
@@ -13,6 +13,7 @@
13#include <linux/sched.h> 13#include <linux/sched.h>
14#include <linux/slab.h> 14#include <linux/slab.h>
15#include <linux/kallsyms.h> 15#include <linux/kallsyms.h>
16#include <linux/sort.h>
16 17
17#include <asm/uaccess.h> 18#include <asm/uaccess.h>
18#include <asm/assembly.h> 19#include <asm/assembly.h>
@@ -115,24 +116,18 @@ unwind_table_init(struct unwind_table *table, const char *name,
115 } 116 }
116} 117}
117 118
119static int cmp_unwind_table_entry(const void *a, const void *b)
120{
121 return ((const struct unwind_table_entry *)a)->region_start
122 - ((const struct unwind_table_entry *)b)->region_start;
123}
124
118static void 125static void
119unwind_table_sort(struct unwind_table_entry *start, 126unwind_table_sort(struct unwind_table_entry *start,
120 struct unwind_table_entry *finish) 127 struct unwind_table_entry *finish)
121{ 128{
122 struct unwind_table_entry el, *p, *q; 129 sort(start, finish - start, sizeof(struct unwind_table_entry),
123 130 cmp_unwind_table_entry, NULL);
124 for (p = start + 1; p < finish; ++p) {
125 if (p[0].region_start < p[-1].region_start) {
126 el = *p;
127 q = p;
128 do {
129 q[0] = q[-1];
130 --q;
131 } while (q > start &&
132 el.region_start < q[-1].region_start);
133 *q = el;
134 }
135 }
136} 131}
137 132
138struct unwind_table * 133struct unwind_table *
@@ -417,3 +412,30 @@ int unwind_to_user(struct unwind_frame_info *info)
417 412
418 return ret; 413 return ret;
419} 414}
415
416unsigned long return_address(unsigned int level)
417{
418 struct unwind_frame_info info;
419 struct pt_regs r;
420 unsigned long sp;
421
422 /* initialize unwind info */
423 asm volatile ("copy %%r30, %0" : "=r"(sp));
424 memset(&r, 0, sizeof(struct pt_regs));
425 r.iaoq[0] = (unsigned long) current_text_addr();
426 r.gr[2] = (unsigned long) __builtin_return_address(0);
427 r.gr[30] = sp;
428 unwind_frame_init(&info, current, &r);
429
430 /* unwind stack */
431 ++level;
432 do {
433 if (unwind_once(&info) < 0 || info.ip == 0)
434 return 0;
435 if (!__kernel_text_address(info.ip)) {
436 return 0;
437 }
438 } while (info.ip && level--);
439
440 return info.ip;
441}