1 /* SPDX-License-Identifier: GPL-2.0-only */
3 * Common arm64 stack unwinder code.
5 * See: arch/arm64/kernel/stacktrace.c for the reference implementation.
7 * Copyright (C) 2012 ARM Ltd.
9 #ifndef __ASM_STACKTRACE_COMMON_H
10 #define __ASM_STACKTRACE_COMMON_H
12 #include <linux/types.h>
20 * struct unwind_state - state used for robust unwinding.
22 * @fp: The fp value in the frame record (or the real fp)
23 * @pc: The lr value in the frame record (or the real lr)
25 * @stack: The stack currently being unwound.
26 * @stacks: An array of stacks which can be unwound.
27 * @nr_stacks: The number of stacks in @stacks.
33 struct stack_info stack
;
34 struct stack_info
*stacks
;
38 static inline struct stack_info
stackinfo_get_unknown(void)
40 return (struct stack_info
) {
46 static inline bool stackinfo_on_stack(const struct stack_info
*info
,
47 unsigned long sp
, unsigned long size
)
52 if (sp
< info
->low
|| sp
+ size
< sp
|| sp
+ size
> info
->high
)
58 static inline void unwind_init_common(struct unwind_state
*state
)
60 state
->stack
= stackinfo_get_unknown();
64 * unwind_find_stack() - Find the accessible stack which entirely contains an
67 * @state: the current unwind state.
68 * @sp: the base address of the object.
69 * @size: the size of the object.
71 * Return: a pointer to the relevant stack_info if found; NULL otherwise.
73 static struct stack_info
*unwind_find_stack(struct unwind_state
*state
,
77 struct stack_info
*info
= &state
->stack
;
79 if (stackinfo_on_stack(info
, sp
, size
))
82 for (int i
= 0; i
< state
->nr_stacks
; i
++) {
83 info
= &state
->stacks
[i
];
84 if (stackinfo_on_stack(info
, sp
, size
))
92 * unwind_consume_stack() - Update stack boundaries so that future unwind steps
93 * cannot consume this object again.
95 * @state: the current unwind state.
96 * @info: the stack_info of the stack containing the object.
97 * @sp: the base address of the object.
98 * @size: the size of the object.
100 * Return: 0 upon success, an error code otherwise.
102 static inline void unwind_consume_stack(struct unwind_state
*state
,
103 struct stack_info
*info
,
107 struct stack_info tmp
;
110 * Stack transitions are strictly one-way, and once we've
111 * transitioned from one stack to another, it's never valid to
112 * unwind back to the old stack.
114 * Destroy the old stack info so that it cannot be found upon a
115 * subsequent transition. If the stack has not changed, we'll
116 * immediately restore the current stack info.
118 * Note that stacks can nest in several valid orders, e.g.
120 * TASK -> IRQ -> OVERFLOW -> SDEI_NORMAL
121 * TASK -> SDEI_NORMAL -> SDEI_CRITICAL -> OVERFLOW
124 * ... so we do not check the specific order of stack
128 *info
= stackinfo_get_unknown();
132 * Future unwind steps can only consume stack above this frame record.
133 * Update the current stack to start immediately above it.
135 state
->stack
.low
= sp
+ size
;
139 * unwind_next_frame_record() - Unwind to the next frame record.
141 * @state: the current unwind state.
143 * Return: 0 upon success, an error code otherwise.
146 unwind_next_frame_record(struct unwind_state
*state
)
148 struct stack_info
*info
;
149 struct frame_record
*record
;
150 unsigned long fp
= state
->fp
;
155 info
= unwind_find_stack(state
, fp
, sizeof(*record
));
159 unwind_consume_stack(state
, info
, fp
, sizeof(*record
));
162 * Record this frame record's values.
164 record
= (struct frame_record
*)fp
;
165 state
->fp
= READ_ONCE(record
->fp
);
166 state
->pc
= READ_ONCE(record
->lr
);
171 #endif /* __ASM_STACKTRACE_COMMON_H */