]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - arch/x86/include/asm/unwind.h
x86/dumpstack: Fix partial register dumps
[mirror_ubuntu-artful-kernel.git] / arch / x86 / include / asm / unwind.h
1 #ifndef _ASM_X86_UNWIND_H
2 #define _ASM_X86_UNWIND_H
3
4 #include <linux/sched.h>
5 #include <linux/ftrace.h>
6 #include <asm/ptrace.h>
7 #include <asm/stacktrace.h>
8
9 #define IRET_FRAME_OFFSET (offsetof(struct pt_regs, ip))
10 #define IRET_FRAME_SIZE (sizeof(struct pt_regs) - IRET_FRAME_OFFSET)
11
12 struct unwind_state {
13 struct stack_info stack_info;
14 unsigned long stack_mask;
15 struct task_struct *task;
16 int graph_idx;
17 bool error;
18 #if defined(CONFIG_UNWINDER_ORC)
19 bool signal, full_regs;
20 unsigned long sp, bp, ip;
21 struct pt_regs *regs;
22 #elif defined(CONFIG_UNWINDER_FRAME_POINTER)
23 bool got_irq;
24 unsigned long *bp, *orig_sp, ip;
25 struct pt_regs *regs;
26 #else
27 unsigned long *sp;
28 #endif
29 };
30
31 void __unwind_start(struct unwind_state *state, struct task_struct *task,
32 struct pt_regs *regs, unsigned long *first_frame);
33 bool unwind_next_frame(struct unwind_state *state);
34 unsigned long unwind_get_return_address(struct unwind_state *state);
35 unsigned long *unwind_get_return_address_ptr(struct unwind_state *state);
36
37 static inline bool unwind_done(struct unwind_state *state)
38 {
39 return state->stack_info.type == STACK_TYPE_UNKNOWN;
40 }
41
42 static inline bool unwind_error(struct unwind_state *state)
43 {
44 return state->error;
45 }
46
47 static inline
48 void unwind_start(struct unwind_state *state, struct task_struct *task,
49 struct pt_regs *regs, unsigned long *first_frame)
50 {
51 first_frame = first_frame ? : get_stack_pointer(task, regs);
52
53 __unwind_start(state, task, regs, first_frame);
54 }
55
56 #if defined(CONFIG_UNWINDER_ORC) || defined(CONFIG_UNWINDER_FRAME_POINTER)
57 /*
58 * If 'partial' returns true, only the iret frame registers are valid.
59 */
60 static inline struct pt_regs *unwind_get_entry_regs(struct unwind_state *state,
61 bool *partial)
62 {
63 if (unwind_done(state))
64 return NULL;
65
66 if (partial) {
67 #ifdef CONFIG_UNWINDER_ORC
68 *partial = !state->full_regs;
69 #else
70 *partial = false;
71 #endif
72 }
73
74 return state->regs;
75 }
76 #else
77 static inline struct pt_regs *unwind_get_entry_regs(struct unwind_state *state,
78 bool *partial)
79 {
80 return NULL;
81 }
82 #endif
83
84 #ifdef CONFIG_UNWINDER_ORC
85 void unwind_init(void);
86 void unwind_module_init(struct module *mod, void *orc_ip, size_t orc_ip_size,
87 void *orc, size_t orc_size);
88 #else
89 static inline void unwind_init(void) {}
90 static inline
91 void unwind_module_init(struct module *mod, void *orc_ip, size_t orc_ip_size,
92 void *orc, size_t orc_size) {}
93 #endif
94
95 /*
96 * This disables KASAN checking when reading a value from another task's stack,
97 * since the other task could be running on another CPU and could have poisoned
98 * the stack in the meantime.
99 */
100 #define READ_ONCE_TASK_STACK(task, x) \
101 ({ \
102 unsigned long val; \
103 if (task == current) \
104 val = READ_ONCE(x); \
105 else \
106 val = READ_ONCE_NOCHECK(x); \
107 val; \
108 })
109
110 static inline bool task_on_another_cpu(struct task_struct *task)
111 {
112 #ifdef CONFIG_SMP
113 return task != current && task->on_cpu;
114 #else
115 return false;
116 #endif
117 }
118
119 #endif /* _ASM_X86_UNWIND_H */