190075Sobrien/* SPDX-License-Identifier: GPL-2.0 */
2132718Skan#ifndef _ASM_S390_UNWIND_H
3169689Skan#define _ASM_S390_UNWIND_H
418334Speter
518334Speter#include <linux/sched.h>
690075Sobrien#include <linux/ftrace.h>
718334Speter#include <linux/rethook.h>
890075Sobrien#include <linux/llist.h>
990075Sobrien#include <asm/ptrace.h>
1090075Sobrien#include <asm/stacktrace.h>
1190075Sobrien
1218334Speter/*
1390075Sobrien * To use the stack unwinder it has to be initialized with unwind_start.
1490075Sobrien * There four combinations for task and regs:
1590075Sobrien * 1) task==NULL, regs==NULL: the unwind starts for the task that is currently
1690075Sobrien *    running, sp/ip picked up from the CPU registers
1718334Speter * 2) task==NULL, regs!=NULL: the unwind starts from the sp/ip found in
1818334Speter *    the struct pt_regs of an interrupt frame for the current task
1990075Sobrien * 3) task!=NULL, regs==NULL: the unwind starts for an inactive task with
20169689Skan *    the sp picked up from task->thread.ksp and the ip picked up from the
21169689Skan *    return address stored by __switch_to
2218334Speter * 4) task!=NULL, regs!=NULL: the sp/ip are picked up from the interrupt
2350397Sobrien *    frame 'regs' of a inactive task
2450397Sobrien * If 'first_frame' is not zero unwind_start skips unwind frames until it
25132718Skan * reaches the specified stack pointer.
26132718Skan * The end of the unwinding is indicated with unwind_done, this can be true
2718334Speter * right after unwind_start, e.g. with first_frame!=0 that can not be found.
2818334Speter * unwind_next_frame skips to the next frame.
2918334Speter * Once the unwind is completed unwind_error() can be used to check if there
3090075Sobrien * has been a situation where the unwinder could not correctly understand
3150397Sobrien * the tasks call chain.
3218334Speter */
3390075Sobrien
3418334Speterstruct unwind_state {
3518334Speter	struct stack_info stack_info;
3618334Speter	unsigned long stack_mask;
3750397Sobrien	struct task_struct *task;
3818334Speter	struct pt_regs *regs;
3918334Speter	unsigned long sp, ip;
4050397Sobrien	int graph_idx;
4118334Speter	struct llist_node *kr_cur;
4250397Sobrien	bool reliable;
4352284Sobrien	bool error;
4490075Sobrien};
4590075Sobrien
4690075Sobrien/* Recover the return address modified by rethook and ftrace_graph. */
47117395Skanstatic inline unsigned long unwind_recover_ret_addr(struct unwind_state *state,
48169689Skan						    unsigned long ip)
4918334Speter{
50169689Skan	ip = ftrace_graph_ret_addr(state->task, &state->graph_idx, ip, (void *)state->sp);
5118334Speter#ifdef CONFIG_RETHOOK
5218334Speter	if (is_rethook_trampoline(ip))
5318334Speter		ip = rethook_find_ret_addr(state->task, state->sp, &state->kr_cur);
54169689Skan#endif
55117395Skan	return ip;
5690075Sobrien}
5790075Sobrien
5890075Sobrienvoid __unwind_start(struct unwind_state *state, struct task_struct *task,
59117395Skan		    struct pt_regs *regs, unsigned long first_frame);
6090075Sobrienbool unwind_next_frame(struct unwind_state *state);
6190075Sobrienunsigned long unwind_get_return_address(struct unwind_state *state);
62117395Skan
6390075Sobrienstatic inline bool unwind_done(struct unwind_state *state)
6452284Sobrien{
65132718Skan	return state->stack_info.type == STACK_TYPE_UNKNOWN;
66132718Skan}
6718334Speter
6850397Sobrienstatic inline bool unwind_error(struct unwind_state *state)
6990075Sobrien{
7090075Sobrien	return state->error;
7190075Sobrien}
72132718Skan
7390075Sobrienstatic __always_inline void unwind_start(struct unwind_state *state,
74117395Skan					 struct task_struct *task,
7590075Sobrien					 struct pt_regs *regs,
76117395Skan					 unsigned long first_frame)
7790075Sobrien{
78117395Skan	task = task ?: current;
7990075Sobrien	first_frame = first_frame ?: get_stack_pointer(task, regs);
80117395Skan	__unwind_start(state, task, regs, first_frame);
81117395Skan}
82117395Skan
83117395Skanstatic inline struct pt_regs *unwind_get_entry_regs(struct unwind_state *state)
84117395Skan{
85169689Skan	return unwind_done(state) ? NULL : state->regs;
8690075Sobrien}
8790075Sobrien
8890075Sobrien#define unwind_for_each_frame(state, task, regs, first_frame)	\
89117395Skan	for (unwind_start(state, task, regs, first_frame);	\
9090075Sobrien	     !unwind_done(state);				\
9118334Speter	     unwind_next_frame(state))
9218334Speter
9318334Speterstatic inline void unwind_init(void) {}
9418334Speterstatic inline void unwind_module_init(struct module *mod, void *orc_ip,
9518334Speter				      size_t orc_ip_size, void *orc,
9618334Speter				      size_t orc_size) {}
9718334Speter
9818334Speter#endif /* _ASM_S390_UNWIND_H */
9918334Speter