diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-16 10:12:07 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-16 10:12:07 -0800 |
commit | b2adf0cbec4cf0934c63f48f893e0cebde380d0c (patch) | |
tree | f4073c90ec71ebb37a0934dc14b52959ad58bfaa /arch/parisc/kernel/unwind.c | |
parent | a79960e576ebca9dbf24489b562689f2be7e9ff0 (diff) | |
parent | d0608b54740c82b08056b7611e38a3fd73be3564 (diff) |
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/kyle/parisc-2.6
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/kyle/parisc-2.6:
parisc: Fixup last users of irq_chip->typename
parisc: convert /proc/pdc/{lcd,led} to seq_file
parisc: Convert BUG() to use unreachable()
parisc: Replace old style lock init in smp.c
parisc: use sort() instead of home-made implementation (v2)
parisc: add CALLER_ADDR{0-6} macros
parisc: remove unused IRQSTAT_SIRQ_PEND and IRQSTAT_SZ defines
parisc: remove duplicated #include
Diffstat (limited to 'arch/parisc/kernel/unwind.c')
-rw-r--r-- | arch/parisc/kernel/unwind.c | 50 |
1 files changed, 36 insertions, 14 deletions
diff --git a/arch/parisc/kernel/unwind.c b/arch/parisc/kernel/unwind.c index a36799e8569..d58eac1a828 100644 --- a/arch/parisc/kernel/unwind.c +++ b/arch/parisc/kernel/unwind.c @@ -13,6 +13,7 @@ #include <linux/sched.h> #include <linux/slab.h> #include <linux/kallsyms.h> +#include <linux/sort.h> #include <asm/uaccess.h> #include <asm/assembly.h> @@ -115,24 +116,18 @@ unwind_table_init(struct unwind_table *table, const char *name, } } +static int cmp_unwind_table_entry(const void *a, const void *b) +{ + return ((const struct unwind_table_entry *)a)->region_start + - ((const struct unwind_table_entry *)b)->region_start; +} + static void unwind_table_sort(struct unwind_table_entry *start, struct unwind_table_entry *finish) { - struct unwind_table_entry el, *p, *q; - - for (p = start + 1; p < finish; ++p) { - if (p[0].region_start < p[-1].region_start) { - el = *p; - q = p; - do { - q[0] = q[-1]; - --q; - } while (q > start && - el.region_start < q[-1].region_start); - *q = el; - } - } + sort(start, finish - start, sizeof(struct unwind_table_entry), + cmp_unwind_table_entry, NULL); } struct unwind_table * @@ -417,3 +412,30 @@ int unwind_to_user(struct unwind_frame_info *info) return ret; } + +unsigned long return_address(unsigned int level) +{ + struct unwind_frame_info info; + struct pt_regs r; + unsigned long sp; + + /* initialize unwind info */ + asm volatile ("copy %%r30, %0" : "=r"(sp)); + memset(&r, 0, sizeof(struct pt_regs)); + r.iaoq[0] = (unsigned long) current_text_addr(); + r.gr[2] = (unsigned long) __builtin_return_address(0); + r.gr[30] = sp; + unwind_frame_init(&info, current, &r); + + /* unwind stack */ + ++level; + do { + if (unwind_once(&info) < 0 || info.ip == 0) + return 0; + if (!__kernel_text_address(info.ip)) { + return 0; + } + } while (info.ip && level--); + + return info.ip; +} |