4 * Reusable arch specific api for unwinding stacks.
6 * Copyright (C) 2017 Stafford Horne <shorne@gmail.com>
8 * This file is licensed under the terms of the GNU General Public License
9 * version 2. This program is licensed "as is" without any warranty of any
10 * kind, whether express or implied.
13 #include <linux/sched/task_stack.h>
14 #include <linux/kernel.h>
16 #include <asm/unwinder.h>
18 #ifdef CONFIG_FRAME_POINTER
19 struct or1k_frameinfo
{
26 * Verify a frameinfo structure. The return address should be a valid text
27 * address. The frame pointer may be null if its the last frame, otherwise
28 * the frame pointer should point to a location in the stack after the the
29 * top of the next frame up.
31 static inline int or1k_frameinfo_valid(struct or1k_frameinfo
*frameinfo
)
33 return (frameinfo
->fp
== NULL
||
34 (!kstack_end(frameinfo
->fp
) &&
35 frameinfo
->fp
> &frameinfo
->top
)) &&
36 __kernel_text_address(frameinfo
->ra
);
40 * Create a stack trace doing scanning which is frame pointer aware. We can
41 * get reliable stack traces by matching the previously found frame
42 * pointer with the top of the stack address every time we find a valid
45 * Ideally the stack parameter will be passed as FP, but it can not be
46 * guaranteed. Therefore we scan each address looking for the first sign
47 * of a return address.
49 * The OpenRISC stack frame looks something like the following. The
50 * location SP is held in r1 and location FP is held in r2 when frame pointers
53 * SP -> (top of stack)
54 * - (callee saved registers)
56 * FP-8 -> previous FP \
57 * FP-4 -> return address |- or1k_frameinfo
58 * FP -> (previous top of stack) /
60 void unwind_stack(void *data
, unsigned long *stack
,
61 void (*trace
)(void *data
, unsigned long addr
, int reliable
))
63 unsigned long *next_fp
= NULL
;
64 struct or1k_frameinfo
*frameinfo
= NULL
;
67 while (!kstack_end(stack
)) {
68 frameinfo
= container_of(stack
,
69 struct or1k_frameinfo
,
72 if (__kernel_text_address(frameinfo
->ra
)) {
73 if (or1k_frameinfo_valid(frameinfo
) &&
75 next_fp
== &frameinfo
->top
)) {
77 next_fp
= frameinfo
->fp
;
81 trace(data
, frameinfo
->ra
, reliable
);
87 #else /* CONFIG_FRAME_POINTER */
90 * Create a stack trace by doing a simple scan treating all text addresses
91 * as return addresses.
93 void unwind_stack(void *data
, unsigned long *stack
,
94 void (*trace
)(void *data
, unsigned long addr
, int reliable
))
98 while (!kstack_end(stack
)) {
100 if (__kernel_text_address(addr
))
101 trace(data
, addr
, 0);
104 #endif /* CONFIG_FRAME_POINTER */