diff options
Diffstat (limited to 'arch/parisc/kernel/unwind.c')
-rw-r--r-- | arch/parisc/kernel/unwind.c | 27 |
1 files changed, 27 insertions, 0 deletions
diff --git a/arch/parisc/kernel/unwind.c b/arch/parisc/kernel/unwind.c index a36799e85693..f03f6fb0ec83 100644 --- a/arch/parisc/kernel/unwind.c +++ b/arch/parisc/kernel/unwind.c | |||
@@ -417,3 +417,30 @@ int unwind_to_user(struct unwind_frame_info *info) | |||
417 | 417 | ||
418 | return ret; | 418 | return ret; |
419 | } | 419 | } |
420 | |||
421 | unsigned long return_address(unsigned int level) | ||
422 | { | ||
423 | struct unwind_frame_info info; | ||
424 | struct pt_regs r; | ||
425 | unsigned long sp; | ||
426 | |||
427 | /* initialize unwind info */ | ||
428 | asm volatile ("copy %%r30, %0" : "=r"(sp)); | ||
429 | memset(&r, 0, sizeof(struct pt_regs)); | ||
430 | r.iaoq[0] = (unsigned long) current_text_addr(); | ||
431 | r.gr[2] = (unsigned long) __builtin_return_address(0); | ||
432 | r.gr[30] = sp; | ||
433 | unwind_frame_init(&info, current, &r); | ||
434 | |||
435 | /* unwind stack */ | ||
436 | ++level; | ||
437 | do { | ||
438 | if (unwind_once(&info) < 0 || info.ip == 0) | ||
439 | return 0; | ||
440 | if (!__kernel_text_address(info.ip)) { | ||
441 | return 0; | ||
442 | } | ||
443 | } while (info.ip && level--); | ||
444 | |||
445 | return info.ip; | ||
446 | } | ||