^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /* SPDX-License-Identifier: GPL-2.0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) #ifndef _ASM_S390_UNWIND_H
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #define _ASM_S390_UNWIND_H
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/ftrace.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <asm/ptrace.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <asm/stacktrace.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * To use the stack unwinder it has to be initialized with unwind_start.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * There four combinations for task and regs:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * 1) task==NULL, regs==NULL: the unwind starts for the task that is currently
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * running, sp/ip picked up from the CPU registers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * 2) task==NULL, regs!=NULL: the unwind starts from the sp/ip found in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * the struct pt_regs of an interrupt frame for the current task
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * 3) task!=NULL, regs==NULL: the unwind starts for an inactive task with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * the sp picked up from task->thread.ksp and the ip picked up from the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * return address stored by __switch_to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * 4) task!=NULL, regs!=NULL: the sp/ip are picked up from the interrupt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * frame 'regs' of a inactive task
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * If 'first_frame' is not zero unwind_start skips unwind frames until it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * reaches the specified stack pointer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * The end of the unwinding is indicated with unwind_done, this can be true
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * right after unwind_start, e.g. with first_frame!=0 that can not be found.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * unwind_next_frame skips to the next frame.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * Once the unwind is completed unwind_error() can be used to check if there
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * has been a situation where the unwinder could not correctly understand
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * the tasks call chain.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) struct unwind_state {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) struct stack_info stack_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) unsigned long stack_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) struct task_struct *task;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) struct pt_regs *regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) unsigned long sp, ip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) int graph_idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) bool reliable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) bool error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) void __unwind_start(struct unwind_state *state, struct task_struct *task,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) struct pt_regs *regs, unsigned long first_frame);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) bool unwind_next_frame(struct unwind_state *state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) unsigned long unwind_get_return_address(struct unwind_state *state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static inline bool unwind_done(struct unwind_state *state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) return state->stack_info.type == STACK_TYPE_UNKNOWN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) static inline bool unwind_error(struct unwind_state *state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) return state->error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) static inline void unwind_start(struct unwind_state *state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) struct task_struct *task,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) struct pt_regs *regs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) unsigned long first_frame)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) task = task ?: current;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) first_frame = first_frame ?: get_stack_pointer(task, regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) __unwind_start(state, task, regs, first_frame);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) static inline struct pt_regs *unwind_get_entry_regs(struct unwind_state *state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) return unwind_done(state) ? NULL : state->regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) #define unwind_for_each_frame(state, task, regs, first_frame) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) for (unwind_start(state, task, regs, first_frame); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) !unwind_done(state); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) unwind_next_frame(state))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) static inline void unwind_init(void) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) static inline void unwind_module_init(struct module *mod, void *orc_ip,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) size_t orc_ip_size, void *orc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) size_t orc_size) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) #endif /* _ASM_S390_UNWIND_H */