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