xref: /linux/arch/x86/include/asm/unwind.h (revision 00389c58ffe993782a8ba4bb5a34a102b1f6fe24)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef _ASM_X86_UNWIND_H
3 #define _ASM_X86_UNWIND_H
4 
5 #include <linux/sched.h>
6 #include <linux/ftrace.h>
7 #include <linux/kprobes.h>
8 #include <linux/rethook.h>
9 #include <asm/ptrace.h>
10 #include <asm/stacktrace.h>
11 
12 #define IRET_FRAME_OFFSET (offsetof(struct pt_regs, ip))
13 #define IRET_FRAME_SIZE   (sizeof(struct pt_regs) - IRET_FRAME_OFFSET)
14 
15 struct unwind_state {
16 	struct stack_info stack_info;
17 	unsigned long stack_mask;
18 	struct task_struct *task;
19 	int graph_idx;
20 #if defined(CONFIG_KRETPROBES) || defined(CONFIG_RETHOOK)
21 	struct llist_node *kr_cur;
22 #endif
23 	bool error;
24 #if defined(CONFIG_UNWINDER_ORC)
25 	bool signal, full_regs;
26 	unsigned long sp, bp, ip;
27 	struct pt_regs *regs, *prev_regs;
28 #elif defined(CONFIG_UNWINDER_FRAME_POINTER)
29 	bool got_irq;
30 	unsigned long *bp, *orig_sp, ip;
31 	/*
32 	 * If non-NULL: The current frame is incomplete and doesn't contain a
33 	 * valid BP. When looking for the next frame, use this instead of the
34 	 * non-existent saved BP.
35 	 */
36 	unsigned long *next_bp;
37 	struct pt_regs *regs;
38 #else
39 	unsigned long *sp;
40 #endif
41 };
42 
43 void __unwind_start(struct unwind_state *state, struct task_struct *task,
44 		    struct pt_regs *regs, unsigned long *first_frame);
45 bool unwind_next_frame(struct unwind_state *state);
46 unsigned long unwind_get_return_address(struct unwind_state *state);
47 unsigned long *unwind_get_return_address_ptr(struct unwind_state *state);
48 
49 static inline bool unwind_done(struct unwind_state *state)
50 {
51 	return state->stack_info.type == STACK_TYPE_UNKNOWN;
52 }
53 
54 static inline bool unwind_error(struct unwind_state *state)
55 {
56 	return state->error;
57 }
58 
59 static inline
60 void unwind_start(struct unwind_state *state, struct task_struct *task,
61 		  struct pt_regs *regs, unsigned long *first_frame)
62 {
63 	first_frame = first_frame ? : get_stack_pointer(task, regs);
64 
65 	__unwind_start(state, task, regs, first_frame);
66 }
67 
68 #if defined(CONFIG_UNWINDER_ORC) || defined(CONFIG_UNWINDER_FRAME_POINTER)
69 /*
70  * If 'partial' returns true, only the iret frame registers are valid.
71  */
72 static inline struct pt_regs *unwind_get_entry_regs(struct unwind_state *state,
73 						    bool *partial)
74 {
75 	if (unwind_done(state))
76 		return NULL;
77 
78 	if (partial) {
79 #ifdef CONFIG_UNWINDER_ORC
80 		*partial = !state->full_regs;
81 #else
82 		*partial = false;
83 #endif
84 	}
85 
86 	return state->regs;
87 }
88 #else
89 static inline struct pt_regs *unwind_get_entry_regs(struct unwind_state *state,
90 						    bool *partial)
91 {
92 	return NULL;
93 }
94 #endif
95 
96 #ifdef CONFIG_UNWINDER_ORC
97 void unwind_init(void);
98 void unwind_module_init(struct module *mod, void *orc_ip, size_t orc_ip_size,
99 			void *orc, size_t orc_size);
100 #else
101 static inline void unwind_init(void) {}
102 static inline
103 void unwind_module_init(struct module *mod, void *orc_ip, size_t orc_ip_size,
104 			void *orc, size_t orc_size) {}
105 #endif
106 
107 static inline
108 unsigned long unwind_recover_kretprobe(struct unwind_state *state,
109 				       unsigned long addr, unsigned long *addr_p)
110 {
111 #ifdef CONFIG_RETHOOK
112 	if (is_rethook_trampoline(addr))
113 		return rethook_find_ret_addr(state->task, (unsigned long)addr_p,
114 					     &state->kr_cur);
115 #endif
116 #ifdef CONFIG_KRETPROBES
117 	return is_kretprobe_trampoline(addr) ?
118 		kretprobe_find_ret_addr(state->task, addr_p, &state->kr_cur) :
119 		addr;
120 #else
121 	return addr;
122 #endif
123 }
124 
125 /* Recover the return address modified by kretprobe and ftrace_graph. */
126 static inline
127 unsigned long unwind_recover_ret_addr(struct unwind_state *state,
128 				     unsigned long addr, unsigned long *addr_p)
129 {
130 	unsigned long ret;
131 
132 	ret = ftrace_graph_ret_addr(state->task, &state->graph_idx,
133 				    addr, addr_p);
134 	return unwind_recover_kretprobe(state, ret, addr_p);
135 }
136 
137 /*
138  * This disables KASAN checking when reading a value from another task's stack,
139  * since the other task could be running on another CPU and could have poisoned
140  * the stack in the meantime.
141  */
142 #define READ_ONCE_TASK_STACK(task, x)			\
143 ({							\
144 	unsigned long val;				\
145 	if (task == current)				\
146 		val = READ_ONCE(x);			\
147 	else						\
148 		val = READ_ONCE_NOCHECK(x);		\
149 	val;						\
150 })
151 
152 static inline bool task_on_another_cpu(struct task_struct *task)
153 {
154 #ifdef CONFIG_SMP
155 	return task != current && task->on_cpu;
156 #else
157 	return false;
158 #endif
159 }
160 
161 #endif /* _ASM_X86_UNWIND_H */
162