1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * arch/sh/kernel/return_address.c |
4 | * |
5 | * Copyright (C) 2009 Matt Fleming |
6 | * Copyright (C) 2009 Paul Mundt |
7 | */ |
8 | #include <linux/kernel.h> |
9 | #include <linux/module.h> |
10 | #include <asm/dwarf.h> |
11 | |
12 | #ifdef CONFIG_DWARF_UNWINDER |
13 | |
14 | void *return_address(unsigned int depth) |
15 | { |
16 | struct dwarf_frame *frame; |
17 | unsigned long ra; |
18 | int i; |
19 | |
20 | for (i = 0, frame = NULL, ra = 0; i <= depth; i++) { |
21 | struct dwarf_frame *tmp; |
22 | |
23 | tmp = dwarf_unwind_stack(ra, frame); |
24 | if (!tmp) |
25 | return NULL; |
26 | |
27 | if (frame) |
28 | dwarf_free_frame(frame); |
29 | |
30 | frame = tmp; |
31 | |
32 | if (!frame || !frame->return_addr) |
33 | break; |
34 | |
35 | ra = frame->return_addr; |
36 | } |
37 | |
38 | /* Failed to unwind the stack to the specified depth. */ |
39 | WARN_ON(i != depth + 1); |
40 | |
41 | if (frame) |
42 | dwarf_free_frame(frame); |
43 | |
44 | return (void *)ra; |
45 | } |
46 | |
47 | #else |
48 | |
49 | void *return_address(unsigned int depth) |
50 | { |
51 | return NULL; |
52 | } |
53 | |
54 | #endif |
55 | |
56 | EXPORT_SYMBOL_GPL(return_address); |
57 | |