Line data Source code
1 : /* SPDX-License-Identifier: GPL-2.0 */
2 : #ifndef _ASM_X86_PTRACE_H
3 : #define _ASM_X86_PTRACE_H
4 :
5 : #include <asm/segment.h>
6 : #include <asm/page_types.h>
7 : #include <uapi/asm/ptrace.h>
8 :
9 : #ifndef __ASSEMBLY__
10 : #ifdef __i386__
11 :
12 : struct pt_regs {
13 : /*
14 : * NB: 32-bit x86 CPUs are inconsistent as what happens in the
15 : * following cases (where %seg represents a segment register):
16 : *
17 : * - pushl %seg: some do a 16-bit write and leave the high
18 : * bits alone
19 : * - movl %seg, [mem]: some do a 16-bit write despite the movl
20 : * - IDT entry: some (e.g. 486) will leave the high bits of CS
21 : * and (if applicable) SS undefined.
22 : *
23 : * Fortunately, x86-32 doesn't read the high bits on POP or IRET,
24 : * so we can just treat all of the segment registers as 16-bit
25 : * values.
26 : */
27 : unsigned long bx;
28 : unsigned long cx;
29 : unsigned long dx;
30 : unsigned long si;
31 : unsigned long di;
32 : unsigned long bp;
33 : unsigned long ax;
34 : unsigned short ds;
35 : unsigned short __dsh;
36 : unsigned short es;
37 : unsigned short __esh;
38 : unsigned short fs;
39 : unsigned short __fsh;
40 : /* On interrupt, gs and __gsh store the vector number. */
41 : unsigned short gs;
42 : unsigned short __gsh;
43 : /* On interrupt, this is the error code. */
44 : unsigned long orig_ax;
45 : unsigned long ip;
46 : unsigned short cs;
47 : unsigned short __csh;
48 : unsigned long flags;
49 : unsigned long sp;
50 : unsigned short ss;
51 : unsigned short __ssh;
52 : };
53 :
54 : #else /* __i386__ */
55 :
56 : struct pt_regs {
57 : /*
58 : * C ABI says these regs are callee-preserved. They aren't saved on kernel entry
59 : * unless syscall needs a complete, fully filled "struct pt_regs".
60 : */
61 : unsigned long r15;
62 : unsigned long r14;
63 : unsigned long r13;
64 : unsigned long r12;
65 : unsigned long bp;
66 : unsigned long bx;
67 : /* These regs are callee-clobbered. Always saved on kernel entry. */
68 : unsigned long r11;
69 : unsigned long r10;
70 : unsigned long r9;
71 : unsigned long r8;
72 : unsigned long ax;
73 : unsigned long cx;
74 : unsigned long dx;
75 : unsigned long si;
76 : unsigned long di;
77 : /*
78 : * On syscall entry, this is syscall#. On CPU exception, this is error code.
79 : * On hw interrupt, it's IRQ number:
80 : */
81 : unsigned long orig_ax;
82 : /* Return frame for iretq */
83 : unsigned long ip;
84 : unsigned long cs;
85 : unsigned long flags;
86 : unsigned long sp;
87 : unsigned long ss;
88 : /* top of stack page */
89 : };
90 :
91 : #endif /* !__i386__ */
92 :
93 : #ifdef CONFIG_PARAVIRT
94 : #include <asm/paravirt_types.h>
95 : #endif
96 :
97 : #include <asm/proto.h>
98 :
99 : struct cpuinfo_x86;
100 : struct task_struct;
101 :
102 : extern unsigned long profile_pc(struct pt_regs *regs);
103 :
104 : extern unsigned long
105 : convert_ip_to_linear(struct task_struct *child, struct pt_regs *regs);
106 : extern void send_sigtrap(struct pt_regs *regs, int error_code, int si_code);
107 :
108 :
109 : static inline unsigned long regs_return_value(struct pt_regs *regs)
110 : {
111 : return regs->ax;
112 : }
113 :
114 : static inline void regs_set_return_value(struct pt_regs *regs, unsigned long rc)
115 : {
116 : regs->ax = rc;
117 : }
118 :
119 : /*
120 : * user_mode(regs) determines whether a register set came from user
121 : * mode. On x86_32, this is true if V8086 mode was enabled OR if the
122 : * register set was from protected mode with RPL-3 CS value. This
123 : * tricky test checks that with one comparison.
124 : *
125 : * On x86_64, vm86 mode is mercifully nonexistent, and we don't need
126 : * the extra check.
127 : */
128 2087162 : static __always_inline int user_mode(struct pt_regs *regs)
129 : {
130 : #ifdef CONFIG_X86_32
131 : return ((regs->cs & SEGMENT_RPL_MASK) | (regs->flags & X86_VM_MASK)) >= USER_RPL;
132 : #else
133 2087162 : return !!(regs->cs & 3);
134 : #endif
135 : }
136 :
137 1269 : static inline int v8086_mode(struct pt_regs *regs)
138 : {
139 : #ifdef CONFIG_X86_32
140 : return (regs->flags & X86_VM_MASK);
141 : #else
142 1265 : return 0; /* No V86 mode support in long mode */
143 : #endif
144 : }
145 :
146 1265 : static inline bool user_64bit_mode(struct pt_regs *regs)
147 : {
148 : #ifdef CONFIG_X86_64
149 : #ifndef CONFIG_PARAVIRT_XXL
150 : /*
151 : * On non-paravirt systems, this is the only long mode CPL 3
152 : * selector. We do not allow long mode selectors in the LDT.
153 : */
154 1265 : return regs->cs == __USER_CS;
155 : #else
156 : /* Headers are too twisted for this to go in paravirt.h. */
157 : return regs->cs == __USER_CS || regs->cs == pv_info.extra_user_64bit_cs;
158 : #endif
159 : #else /* !CONFIG_X86_64 */
160 : return false;
161 : #endif
162 : }
163 :
164 : /*
165 : * Determine whether the register set came from any context that is running in
166 : * 64-bit mode.
167 : */
168 0 : static inline bool any_64bit_mode(struct pt_regs *regs)
169 : {
170 : #ifdef CONFIG_X86_64
171 0 : return !user_mode(regs) || user_64bit_mode(regs);
172 : #else
173 : return false;
174 : #endif
175 : }
176 :
177 : #ifdef CONFIG_X86_64
178 : #define current_user_stack_pointer() current_pt_regs()->sp
179 : #define compat_user_stack_pointer() current_pt_regs()->sp
180 :
181 : static inline bool ip_within_syscall_gap(struct pt_regs *regs)
182 : {
183 : bool ret = (regs->ip >= (unsigned long)entry_SYSCALL_64 &&
184 : regs->ip < (unsigned long)entry_SYSCALL_64_safe_stack);
185 :
186 : #ifdef CONFIG_IA32_EMULATION
187 : ret = ret || (regs->ip >= (unsigned long)entry_SYSCALL_compat &&
188 : regs->ip < (unsigned long)entry_SYSCALL_compat_safe_stack);
189 : #endif
190 :
191 : return ret;
192 : }
193 : #endif
194 :
195 : static inline unsigned long kernel_stack_pointer(struct pt_regs *regs)
196 : {
197 : return regs->sp;
198 : }
199 :
200 3657 : static inline unsigned long instruction_pointer(struct pt_regs *regs)
201 : {
202 3657 : return regs->ip;
203 : }
204 :
205 : static inline void instruction_pointer_set(struct pt_regs *regs,
206 : unsigned long val)
207 : {
208 : regs->ip = val;
209 : }
210 :
211 : static inline unsigned long frame_pointer(struct pt_regs *regs)
212 : {
213 : return regs->bp;
214 : }
215 :
216 0 : static inline unsigned long user_stack_pointer(struct pt_regs *regs)
217 : {
218 0 : return regs->sp;
219 : }
220 :
221 : static inline void user_stack_pointer_set(struct pt_regs *regs,
222 : unsigned long val)
223 : {
224 : regs->sp = val;
225 : }
226 :
227 45681 : static __always_inline bool regs_irqs_disabled(struct pt_regs *regs)
228 : {
229 45681 : return !(regs->flags & X86_EFLAGS_IF);
230 : }
231 :
232 : /* Query offset/name of register from its name/offset */
233 : extern int regs_query_register_offset(const char *name);
234 : extern const char *regs_query_register_name(unsigned int offset);
235 : #define MAX_REG_OFFSET (offsetof(struct pt_regs, ss))
236 :
237 : /**
238 : * regs_get_register() - get register value from its offset
239 : * @regs: pt_regs from which register value is gotten.
240 : * @offset: offset number of the register.
241 : *
242 : * regs_get_register returns the value of a register. The @offset is the
243 : * offset of the register in struct pt_regs address which specified by @regs.
244 : * If @offset is bigger than MAX_REG_OFFSET, this returns 0.
245 : */
246 0 : static inline unsigned long regs_get_register(struct pt_regs *regs,
247 : unsigned int offset)
248 : {
249 0 : if (unlikely(offset > MAX_REG_OFFSET))
250 : return 0;
251 : #ifdef CONFIG_X86_32
252 : /* The selector fields are 16-bit. */
253 : if (offset == offsetof(struct pt_regs, cs) ||
254 : offset == offsetof(struct pt_regs, ss) ||
255 : offset == offsetof(struct pt_regs, ds) ||
256 : offset == offsetof(struct pt_regs, es) ||
257 : offset == offsetof(struct pt_regs, fs) ||
258 : offset == offsetof(struct pt_regs, gs)) {
259 : return *(u16 *)((unsigned long)regs + offset);
260 :
261 : }
262 : #endif
263 0 : return *(unsigned long *)((unsigned long)regs + offset);
264 : }
265 :
266 : /**
267 : * regs_within_kernel_stack() - check the address in the stack
268 : * @regs: pt_regs which contains kernel stack pointer.
269 : * @addr: address which is checked.
270 : *
271 : * regs_within_kernel_stack() checks @addr is within the kernel stack page(s).
272 : * If @addr is within the kernel stack, it returns true. If not, returns false.
273 : */
274 : static inline int regs_within_kernel_stack(struct pt_regs *regs,
275 : unsigned long addr)
276 : {
277 : return ((addr & ~(THREAD_SIZE - 1)) == (regs->sp & ~(THREAD_SIZE - 1)));
278 : }
279 :
280 : /**
281 : * regs_get_kernel_stack_nth_addr() - get the address of the Nth entry on stack
282 : * @regs: pt_regs which contains kernel stack pointer.
283 : * @n: stack entry number.
284 : *
285 : * regs_get_kernel_stack_nth() returns the address of the @n th entry of the
286 : * kernel stack which is specified by @regs. If the @n th entry is NOT in
287 : * the kernel stack, this returns NULL.
288 : */
289 : static inline unsigned long *regs_get_kernel_stack_nth_addr(struct pt_regs *regs, unsigned int n)
290 : {
291 : unsigned long *addr = (unsigned long *)regs->sp;
292 :
293 : addr += n;
294 : if (regs_within_kernel_stack(regs, (unsigned long)addr))
295 : return addr;
296 : else
297 : return NULL;
298 : }
299 :
300 : /* To avoid include hell, we can't include uaccess.h */
301 : extern long copy_from_kernel_nofault(void *dst, const void *src, size_t size);
302 :
303 : /**
304 : * regs_get_kernel_stack_nth() - get Nth entry of the stack
305 : * @regs: pt_regs which contains kernel stack pointer.
306 : * @n: stack entry number.
307 : *
308 : * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which
309 : * is specified by @regs. If the @n th entry is NOT in the kernel stack
310 : * this returns 0.
311 : */
312 : static inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
313 : unsigned int n)
314 : {
315 : unsigned long *addr;
316 : unsigned long val;
317 : long ret;
318 :
319 : addr = regs_get_kernel_stack_nth_addr(regs, n);
320 : if (addr) {
321 : ret = copy_from_kernel_nofault(&val, addr, sizeof(val));
322 : if (!ret)
323 : return val;
324 : }
325 : return 0;
326 : }
327 :
328 : /**
329 : * regs_get_kernel_argument() - get Nth function argument in kernel
330 : * @regs: pt_regs of that context
331 : * @n: function argument number (start from 0)
332 : *
333 : * regs_get_argument() returns @n th argument of the function call.
334 : * Note that this chooses most probably assignment, in some case
335 : * it can be incorrect.
336 : * This is expected to be called from kprobes or ftrace with regs
337 : * where the top of stack is the return address.
338 : */
339 : static inline unsigned long regs_get_kernel_argument(struct pt_regs *regs,
340 : unsigned int n)
341 : {
342 : static const unsigned int argument_offs[] = {
343 : #ifdef __i386__
344 : offsetof(struct pt_regs, ax),
345 : offsetof(struct pt_regs, dx),
346 : offsetof(struct pt_regs, cx),
347 : #define NR_REG_ARGUMENTS 3
348 : #else
349 : offsetof(struct pt_regs, di),
350 : offsetof(struct pt_regs, si),
351 : offsetof(struct pt_regs, dx),
352 : offsetof(struct pt_regs, cx),
353 : offsetof(struct pt_regs, r8),
354 : offsetof(struct pt_regs, r9),
355 : #define NR_REG_ARGUMENTS 6
356 : #endif
357 : };
358 :
359 : if (n >= NR_REG_ARGUMENTS) {
360 : n -= NR_REG_ARGUMENTS - 1;
361 : return regs_get_kernel_stack_nth(regs, n);
362 : } else
363 : return regs_get_register(regs, argument_offs[n]);
364 : }
365 :
366 : #define arch_has_single_step() (1)
367 : #ifdef CONFIG_X86_DEBUGCTLMSR
368 : #define arch_has_block_step() (1)
369 : #else
370 : #define arch_has_block_step() (boot_cpu_data.x86 >= 6)
371 : #endif
372 :
373 : #define ARCH_HAS_USER_SINGLE_STEP_REPORT
374 :
375 : struct user_desc;
376 : extern int do_get_thread_area(struct task_struct *p, int idx,
377 : struct user_desc __user *info);
378 : extern int do_set_thread_area(struct task_struct *p, int idx,
379 : struct user_desc __user *info, int can_allocate);
380 :
381 : #ifdef CONFIG_X86_64
382 : # define do_set_thread_area_64(p, s, t) do_arch_prctl_64(p, s, t)
383 : #else
384 : # define do_set_thread_area_64(p, s, t) (0)
385 : #endif
386 :
387 : #endif /* !__ASSEMBLY__ */
388 : #endif /* _ASM_X86_PTRACE_H */
|