18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* By Ross Biro 1/23/92 */ 38c2ecf20Sopenharmony_ci/* 48c2ecf20Sopenharmony_ci * Pentium III FXSR, SSE support 58c2ecf20Sopenharmony_ci * Gareth Hughes <gareth@valinux.com>, May 2000 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/kernel.h> 98c2ecf20Sopenharmony_ci#include <linux/sched.h> 108c2ecf20Sopenharmony_ci#include <linux/sched/task_stack.h> 118c2ecf20Sopenharmony_ci#include <linux/mm.h> 128c2ecf20Sopenharmony_ci#include <linux/smp.h> 138c2ecf20Sopenharmony_ci#include <linux/errno.h> 148c2ecf20Sopenharmony_ci#include <linux/slab.h> 158c2ecf20Sopenharmony_ci#include <linux/ptrace.h> 168c2ecf20Sopenharmony_ci#include <linux/tracehook.h> 178c2ecf20Sopenharmony_ci#include <linux/user.h> 188c2ecf20Sopenharmony_ci#include <linux/elf.h> 198c2ecf20Sopenharmony_ci#include <linux/security.h> 208c2ecf20Sopenharmony_ci#include <linux/audit.h> 218c2ecf20Sopenharmony_ci#include <linux/seccomp.h> 228c2ecf20Sopenharmony_ci#include <linux/signal.h> 238c2ecf20Sopenharmony_ci#include <linux/perf_event.h> 248c2ecf20Sopenharmony_ci#include <linux/hw_breakpoint.h> 258c2ecf20Sopenharmony_ci#include <linux/rcupdate.h> 268c2ecf20Sopenharmony_ci#include <linux/export.h> 278c2ecf20Sopenharmony_ci#include <linux/context_tracking.h> 288c2ecf20Sopenharmony_ci#include <linux/nospec.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 318c2ecf20Sopenharmony_ci#include <asm/processor.h> 328c2ecf20Sopenharmony_ci#include <asm/fpu/internal.h> 338c2ecf20Sopenharmony_ci#include <asm/fpu/signal.h> 348c2ecf20Sopenharmony_ci#include <asm/fpu/regset.h> 358c2ecf20Sopenharmony_ci#include <asm/debugreg.h> 368c2ecf20Sopenharmony_ci#include <asm/ldt.h> 378c2ecf20Sopenharmony_ci#include <asm/desc.h> 388c2ecf20Sopenharmony_ci#include <asm/prctl.h> 398c2ecf20Sopenharmony_ci#include <asm/proto.h> 408c2ecf20Sopenharmony_ci#include <asm/hw_breakpoint.h> 418c2ecf20Sopenharmony_ci#include <asm/traps.h> 428c2ecf20Sopenharmony_ci#include <asm/syscall.h> 438c2ecf20Sopenharmony_ci#include <asm/fsgsbase.h> 448c2ecf20Sopenharmony_ci#include <asm/io_bitmap.h> 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#include "tls.h" 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cienum x86_regset { 498c2ecf20Sopenharmony_ci REGSET_GENERAL, 508c2ecf20Sopenharmony_ci REGSET_FP, 518c2ecf20Sopenharmony_ci REGSET_XFP, 528c2ecf20Sopenharmony_ci REGSET_IOPERM64 = REGSET_XFP, 538c2ecf20Sopenharmony_ci REGSET_XSTATE, 548c2ecf20Sopenharmony_ci REGSET_TLS, 558c2ecf20Sopenharmony_ci REGSET_IOPERM32, 568c2ecf20Sopenharmony_ci}; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistruct pt_regs_offset { 598c2ecf20Sopenharmony_ci const char *name; 608c2ecf20Sopenharmony_ci int offset; 618c2ecf20Sopenharmony_ci}; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci#define REG_OFFSET_NAME(r) {.name = #r, .offset = offsetof(struct pt_regs, r)} 648c2ecf20Sopenharmony_ci#define REG_OFFSET_END {.name = NULL, .offset = 0} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic const struct pt_regs_offset regoffset_table[] = { 678c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 688c2ecf20Sopenharmony_ci REG_OFFSET_NAME(r15), 698c2ecf20Sopenharmony_ci REG_OFFSET_NAME(r14), 708c2ecf20Sopenharmony_ci REG_OFFSET_NAME(r13), 718c2ecf20Sopenharmony_ci REG_OFFSET_NAME(r12), 728c2ecf20Sopenharmony_ci REG_OFFSET_NAME(r11), 738c2ecf20Sopenharmony_ci REG_OFFSET_NAME(r10), 748c2ecf20Sopenharmony_ci REG_OFFSET_NAME(r9), 758c2ecf20Sopenharmony_ci REG_OFFSET_NAME(r8), 768c2ecf20Sopenharmony_ci#endif 778c2ecf20Sopenharmony_ci REG_OFFSET_NAME(bx), 788c2ecf20Sopenharmony_ci REG_OFFSET_NAME(cx), 798c2ecf20Sopenharmony_ci REG_OFFSET_NAME(dx), 808c2ecf20Sopenharmony_ci REG_OFFSET_NAME(si), 818c2ecf20Sopenharmony_ci REG_OFFSET_NAME(di), 828c2ecf20Sopenharmony_ci REG_OFFSET_NAME(bp), 838c2ecf20Sopenharmony_ci REG_OFFSET_NAME(ax), 848c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_32 858c2ecf20Sopenharmony_ci REG_OFFSET_NAME(ds), 868c2ecf20Sopenharmony_ci REG_OFFSET_NAME(es), 878c2ecf20Sopenharmony_ci REG_OFFSET_NAME(fs), 888c2ecf20Sopenharmony_ci REG_OFFSET_NAME(gs), 898c2ecf20Sopenharmony_ci#endif 908c2ecf20Sopenharmony_ci REG_OFFSET_NAME(orig_ax), 918c2ecf20Sopenharmony_ci REG_OFFSET_NAME(ip), 928c2ecf20Sopenharmony_ci REG_OFFSET_NAME(cs), 938c2ecf20Sopenharmony_ci REG_OFFSET_NAME(flags), 948c2ecf20Sopenharmony_ci REG_OFFSET_NAME(sp), 958c2ecf20Sopenharmony_ci REG_OFFSET_NAME(ss), 968c2ecf20Sopenharmony_ci REG_OFFSET_END, 978c2ecf20Sopenharmony_ci}; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci/** 1008c2ecf20Sopenharmony_ci * regs_query_register_offset() - query register offset from its name 1018c2ecf20Sopenharmony_ci * @name: the name of a register 1028c2ecf20Sopenharmony_ci * 1038c2ecf20Sopenharmony_ci * regs_query_register_offset() returns the offset of a register in struct 1048c2ecf20Sopenharmony_ci * pt_regs from its name. If the name is invalid, this returns -EINVAL; 1058c2ecf20Sopenharmony_ci */ 1068c2ecf20Sopenharmony_ciint regs_query_register_offset(const char *name) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci const struct pt_regs_offset *roff; 1098c2ecf20Sopenharmony_ci for (roff = regoffset_table; roff->name != NULL; roff++) 1108c2ecf20Sopenharmony_ci if (!strcmp(roff->name, name)) 1118c2ecf20Sopenharmony_ci return roff->offset; 1128c2ecf20Sopenharmony_ci return -EINVAL; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci/** 1168c2ecf20Sopenharmony_ci * regs_query_register_name() - query register name from its offset 1178c2ecf20Sopenharmony_ci * @offset: the offset of a register in struct pt_regs. 1188c2ecf20Sopenharmony_ci * 1198c2ecf20Sopenharmony_ci * regs_query_register_name() returns the name of a register from its 1208c2ecf20Sopenharmony_ci * offset in struct pt_regs. If the @offset is invalid, this returns NULL; 1218c2ecf20Sopenharmony_ci */ 1228c2ecf20Sopenharmony_ciconst char *regs_query_register_name(unsigned int offset) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci const struct pt_regs_offset *roff; 1258c2ecf20Sopenharmony_ci for (roff = regoffset_table; roff->name != NULL; roff++) 1268c2ecf20Sopenharmony_ci if (roff->offset == offset) 1278c2ecf20Sopenharmony_ci return roff->name; 1288c2ecf20Sopenharmony_ci return NULL; 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci/* 1328c2ecf20Sopenharmony_ci * does not yet catch signals sent when the child dies. 1338c2ecf20Sopenharmony_ci * in exit.c or in signal.c. 1348c2ecf20Sopenharmony_ci */ 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci/* 1378c2ecf20Sopenharmony_ci * Determines which flags the user has access to [1 = access, 0 = no access]. 1388c2ecf20Sopenharmony_ci */ 1398c2ecf20Sopenharmony_ci#define FLAG_MASK_32 ((unsigned long) \ 1408c2ecf20Sopenharmony_ci (X86_EFLAGS_CF | X86_EFLAGS_PF | \ 1418c2ecf20Sopenharmony_ci X86_EFLAGS_AF | X86_EFLAGS_ZF | \ 1428c2ecf20Sopenharmony_ci X86_EFLAGS_SF | X86_EFLAGS_TF | \ 1438c2ecf20Sopenharmony_ci X86_EFLAGS_DF | X86_EFLAGS_OF | \ 1448c2ecf20Sopenharmony_ci X86_EFLAGS_RF | X86_EFLAGS_AC)) 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci/* 1478c2ecf20Sopenharmony_ci * Determines whether a value may be installed in a segment register. 1488c2ecf20Sopenharmony_ci */ 1498c2ecf20Sopenharmony_cistatic inline bool invalid_selector(u16 value) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci return unlikely(value != 0 && (value & SEGMENT_RPL_MASK) != USER_RPL); 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_32 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci#define FLAG_MASK FLAG_MASK_32 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic unsigned long *pt_regs_access(struct pt_regs *regs, unsigned long regno) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci BUILD_BUG_ON(offsetof(struct pt_regs, bx) != 0); 1618c2ecf20Sopenharmony_ci return ®s->bx + (regno >> 2); 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic u16 get_segment_reg(struct task_struct *task, unsigned long offset) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci /* 1678c2ecf20Sopenharmony_ci * Returning the value truncates it to 16 bits. 1688c2ecf20Sopenharmony_ci */ 1698c2ecf20Sopenharmony_ci unsigned int retval; 1708c2ecf20Sopenharmony_ci if (offset != offsetof(struct user_regs_struct, gs)) 1718c2ecf20Sopenharmony_ci retval = *pt_regs_access(task_pt_regs(task), offset); 1728c2ecf20Sopenharmony_ci else { 1738c2ecf20Sopenharmony_ci if (task == current) 1748c2ecf20Sopenharmony_ci retval = get_user_gs(task_pt_regs(task)); 1758c2ecf20Sopenharmony_ci else 1768c2ecf20Sopenharmony_ci retval = task_user_gs(task); 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci return retval; 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic int set_segment_reg(struct task_struct *task, 1828c2ecf20Sopenharmony_ci unsigned long offset, u16 value) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(task == current)) 1858c2ecf20Sopenharmony_ci return -EIO; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci /* 1888c2ecf20Sopenharmony_ci * The value argument was already truncated to 16 bits. 1898c2ecf20Sopenharmony_ci */ 1908c2ecf20Sopenharmony_ci if (invalid_selector(value)) 1918c2ecf20Sopenharmony_ci return -EIO; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci /* 1948c2ecf20Sopenharmony_ci * For %cs and %ss we cannot permit a null selector. 1958c2ecf20Sopenharmony_ci * We can permit a bogus selector as long as it has USER_RPL. 1968c2ecf20Sopenharmony_ci * Null selectors are fine for other segment registers, but 1978c2ecf20Sopenharmony_ci * we will never get back to user mode with invalid %cs or %ss 1988c2ecf20Sopenharmony_ci * and will take the trap in iret instead. Much code relies 1998c2ecf20Sopenharmony_ci * on user_mode() to distinguish a user trap frame (which can 2008c2ecf20Sopenharmony_ci * safely use invalid selectors) from a kernel trap frame. 2018c2ecf20Sopenharmony_ci */ 2028c2ecf20Sopenharmony_ci switch (offset) { 2038c2ecf20Sopenharmony_ci case offsetof(struct user_regs_struct, cs): 2048c2ecf20Sopenharmony_ci case offsetof(struct user_regs_struct, ss): 2058c2ecf20Sopenharmony_ci if (unlikely(value == 0)) 2068c2ecf20Sopenharmony_ci return -EIO; 2078c2ecf20Sopenharmony_ci fallthrough; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci default: 2108c2ecf20Sopenharmony_ci *pt_regs_access(task_pt_regs(task), offset) = value; 2118c2ecf20Sopenharmony_ci break; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci case offsetof(struct user_regs_struct, gs): 2148c2ecf20Sopenharmony_ci task_user_gs(task) = value; 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci return 0; 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci#else /* CONFIG_X86_64 */ 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci#define FLAG_MASK (FLAG_MASK_32 | X86_EFLAGS_NT) 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_cistatic unsigned long *pt_regs_access(struct pt_regs *regs, unsigned long offset) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci BUILD_BUG_ON(offsetof(struct pt_regs, r15) != 0); 2278c2ecf20Sopenharmony_ci return ®s->r15 + (offset / sizeof(regs->r15)); 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistatic u16 get_segment_reg(struct task_struct *task, unsigned long offset) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci /* 2338c2ecf20Sopenharmony_ci * Returning the value truncates it to 16 bits. 2348c2ecf20Sopenharmony_ci */ 2358c2ecf20Sopenharmony_ci unsigned int seg; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci switch (offset) { 2388c2ecf20Sopenharmony_ci case offsetof(struct user_regs_struct, fs): 2398c2ecf20Sopenharmony_ci if (task == current) { 2408c2ecf20Sopenharmony_ci /* Older gas can't assemble movq %?s,%r?? */ 2418c2ecf20Sopenharmony_ci asm("movl %%fs,%0" : "=r" (seg)); 2428c2ecf20Sopenharmony_ci return seg; 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci return task->thread.fsindex; 2458c2ecf20Sopenharmony_ci case offsetof(struct user_regs_struct, gs): 2468c2ecf20Sopenharmony_ci if (task == current) { 2478c2ecf20Sopenharmony_ci asm("movl %%gs,%0" : "=r" (seg)); 2488c2ecf20Sopenharmony_ci return seg; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci return task->thread.gsindex; 2518c2ecf20Sopenharmony_ci case offsetof(struct user_regs_struct, ds): 2528c2ecf20Sopenharmony_ci if (task == current) { 2538c2ecf20Sopenharmony_ci asm("movl %%ds,%0" : "=r" (seg)); 2548c2ecf20Sopenharmony_ci return seg; 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci return task->thread.ds; 2578c2ecf20Sopenharmony_ci case offsetof(struct user_regs_struct, es): 2588c2ecf20Sopenharmony_ci if (task == current) { 2598c2ecf20Sopenharmony_ci asm("movl %%es,%0" : "=r" (seg)); 2608c2ecf20Sopenharmony_ci return seg; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci return task->thread.es; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci case offsetof(struct user_regs_struct, cs): 2658c2ecf20Sopenharmony_ci case offsetof(struct user_regs_struct, ss): 2668c2ecf20Sopenharmony_ci break; 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci return *pt_regs_access(task_pt_regs(task), offset); 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic int set_segment_reg(struct task_struct *task, 2728c2ecf20Sopenharmony_ci unsigned long offset, u16 value) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(task == current)) 2758c2ecf20Sopenharmony_ci return -EIO; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci /* 2788c2ecf20Sopenharmony_ci * The value argument was already truncated to 16 bits. 2798c2ecf20Sopenharmony_ci */ 2808c2ecf20Sopenharmony_ci if (invalid_selector(value)) 2818c2ecf20Sopenharmony_ci return -EIO; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci /* 2848c2ecf20Sopenharmony_ci * Writes to FS and GS will change the stored selector. Whether 2858c2ecf20Sopenharmony_ci * this changes the segment base as well depends on whether 2868c2ecf20Sopenharmony_ci * FSGSBASE is enabled. 2878c2ecf20Sopenharmony_ci */ 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci switch (offset) { 2908c2ecf20Sopenharmony_ci case offsetof(struct user_regs_struct,fs): 2918c2ecf20Sopenharmony_ci task->thread.fsindex = value; 2928c2ecf20Sopenharmony_ci break; 2938c2ecf20Sopenharmony_ci case offsetof(struct user_regs_struct,gs): 2948c2ecf20Sopenharmony_ci task->thread.gsindex = value; 2958c2ecf20Sopenharmony_ci break; 2968c2ecf20Sopenharmony_ci case offsetof(struct user_regs_struct,ds): 2978c2ecf20Sopenharmony_ci task->thread.ds = value; 2988c2ecf20Sopenharmony_ci break; 2998c2ecf20Sopenharmony_ci case offsetof(struct user_regs_struct,es): 3008c2ecf20Sopenharmony_ci task->thread.es = value; 3018c2ecf20Sopenharmony_ci break; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci /* 3048c2ecf20Sopenharmony_ci * Can't actually change these in 64-bit mode. 3058c2ecf20Sopenharmony_ci */ 3068c2ecf20Sopenharmony_ci case offsetof(struct user_regs_struct,cs): 3078c2ecf20Sopenharmony_ci if (unlikely(value == 0)) 3088c2ecf20Sopenharmony_ci return -EIO; 3098c2ecf20Sopenharmony_ci task_pt_regs(task)->cs = value; 3108c2ecf20Sopenharmony_ci break; 3118c2ecf20Sopenharmony_ci case offsetof(struct user_regs_struct,ss): 3128c2ecf20Sopenharmony_ci if (unlikely(value == 0)) 3138c2ecf20Sopenharmony_ci return -EIO; 3148c2ecf20Sopenharmony_ci task_pt_regs(task)->ss = value; 3158c2ecf20Sopenharmony_ci break; 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci return 0; 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci#endif /* CONFIG_X86_32 */ 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_cistatic unsigned long get_flags(struct task_struct *task) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci unsigned long retval = task_pt_regs(task)->flags; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci /* 3288c2ecf20Sopenharmony_ci * If the debugger set TF, hide it from the readout. 3298c2ecf20Sopenharmony_ci */ 3308c2ecf20Sopenharmony_ci if (test_tsk_thread_flag(task, TIF_FORCED_TF)) 3318c2ecf20Sopenharmony_ci retval &= ~X86_EFLAGS_TF; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci return retval; 3348c2ecf20Sopenharmony_ci} 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_cistatic int set_flags(struct task_struct *task, unsigned long value) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci struct pt_regs *regs = task_pt_regs(task); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci /* 3418c2ecf20Sopenharmony_ci * If the user value contains TF, mark that 3428c2ecf20Sopenharmony_ci * it was not "us" (the debugger) that set it. 3438c2ecf20Sopenharmony_ci * If not, make sure it stays set if we had. 3448c2ecf20Sopenharmony_ci */ 3458c2ecf20Sopenharmony_ci if (value & X86_EFLAGS_TF) 3468c2ecf20Sopenharmony_ci clear_tsk_thread_flag(task, TIF_FORCED_TF); 3478c2ecf20Sopenharmony_ci else if (test_tsk_thread_flag(task, TIF_FORCED_TF)) 3488c2ecf20Sopenharmony_ci value |= X86_EFLAGS_TF; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci regs->flags = (regs->flags & ~FLAG_MASK) | (value & FLAG_MASK); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci return 0; 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_cistatic int putreg(struct task_struct *child, 3568c2ecf20Sopenharmony_ci unsigned long offset, unsigned long value) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci switch (offset) { 3598c2ecf20Sopenharmony_ci case offsetof(struct user_regs_struct, cs): 3608c2ecf20Sopenharmony_ci case offsetof(struct user_regs_struct, ds): 3618c2ecf20Sopenharmony_ci case offsetof(struct user_regs_struct, es): 3628c2ecf20Sopenharmony_ci case offsetof(struct user_regs_struct, fs): 3638c2ecf20Sopenharmony_ci case offsetof(struct user_regs_struct, gs): 3648c2ecf20Sopenharmony_ci case offsetof(struct user_regs_struct, ss): 3658c2ecf20Sopenharmony_ci return set_segment_reg(child, offset, value); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci case offsetof(struct user_regs_struct, flags): 3688c2ecf20Sopenharmony_ci return set_flags(child, value); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 3718c2ecf20Sopenharmony_ci case offsetof(struct user_regs_struct,fs_base): 3728c2ecf20Sopenharmony_ci if (value >= TASK_SIZE_MAX) 3738c2ecf20Sopenharmony_ci return -EIO; 3748c2ecf20Sopenharmony_ci x86_fsbase_write_task(child, value); 3758c2ecf20Sopenharmony_ci return 0; 3768c2ecf20Sopenharmony_ci case offsetof(struct user_regs_struct,gs_base): 3778c2ecf20Sopenharmony_ci if (value >= TASK_SIZE_MAX) 3788c2ecf20Sopenharmony_ci return -EIO; 3798c2ecf20Sopenharmony_ci x86_gsbase_write_task(child, value); 3808c2ecf20Sopenharmony_ci return 0; 3818c2ecf20Sopenharmony_ci#endif 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci *pt_regs_access(task_pt_regs(child), offset) = value; 3858c2ecf20Sopenharmony_ci return 0; 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_cistatic unsigned long getreg(struct task_struct *task, unsigned long offset) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci switch (offset) { 3918c2ecf20Sopenharmony_ci case offsetof(struct user_regs_struct, cs): 3928c2ecf20Sopenharmony_ci case offsetof(struct user_regs_struct, ds): 3938c2ecf20Sopenharmony_ci case offsetof(struct user_regs_struct, es): 3948c2ecf20Sopenharmony_ci case offsetof(struct user_regs_struct, fs): 3958c2ecf20Sopenharmony_ci case offsetof(struct user_regs_struct, gs): 3968c2ecf20Sopenharmony_ci case offsetof(struct user_regs_struct, ss): 3978c2ecf20Sopenharmony_ci return get_segment_reg(task, offset); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci case offsetof(struct user_regs_struct, flags): 4008c2ecf20Sopenharmony_ci return get_flags(task); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 4038c2ecf20Sopenharmony_ci case offsetof(struct user_regs_struct, fs_base): 4048c2ecf20Sopenharmony_ci return x86_fsbase_read_task(task); 4058c2ecf20Sopenharmony_ci case offsetof(struct user_regs_struct, gs_base): 4068c2ecf20Sopenharmony_ci return x86_gsbase_read_task(task); 4078c2ecf20Sopenharmony_ci#endif 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci return *pt_regs_access(task_pt_regs(task), offset); 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_cistatic int genregs_get(struct task_struct *target, 4148c2ecf20Sopenharmony_ci const struct user_regset *regset, 4158c2ecf20Sopenharmony_ci struct membuf to) 4168c2ecf20Sopenharmony_ci{ 4178c2ecf20Sopenharmony_ci int reg; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci for (reg = 0; to.left; reg++) 4208c2ecf20Sopenharmony_ci membuf_store(&to, getreg(target, reg * sizeof(unsigned long))); 4218c2ecf20Sopenharmony_ci return 0; 4228c2ecf20Sopenharmony_ci} 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_cistatic int genregs_set(struct task_struct *target, 4258c2ecf20Sopenharmony_ci const struct user_regset *regset, 4268c2ecf20Sopenharmony_ci unsigned int pos, unsigned int count, 4278c2ecf20Sopenharmony_ci const void *kbuf, const void __user *ubuf) 4288c2ecf20Sopenharmony_ci{ 4298c2ecf20Sopenharmony_ci int ret = 0; 4308c2ecf20Sopenharmony_ci if (kbuf) { 4318c2ecf20Sopenharmony_ci const unsigned long *k = kbuf; 4328c2ecf20Sopenharmony_ci while (count >= sizeof(*k) && !ret) { 4338c2ecf20Sopenharmony_ci ret = putreg(target, pos, *k++); 4348c2ecf20Sopenharmony_ci count -= sizeof(*k); 4358c2ecf20Sopenharmony_ci pos += sizeof(*k); 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci } else { 4388c2ecf20Sopenharmony_ci const unsigned long __user *u = ubuf; 4398c2ecf20Sopenharmony_ci while (count >= sizeof(*u) && !ret) { 4408c2ecf20Sopenharmony_ci unsigned long word; 4418c2ecf20Sopenharmony_ci ret = __get_user(word, u++); 4428c2ecf20Sopenharmony_ci if (ret) 4438c2ecf20Sopenharmony_ci break; 4448c2ecf20Sopenharmony_ci ret = putreg(target, pos, word); 4458c2ecf20Sopenharmony_ci count -= sizeof(*u); 4468c2ecf20Sopenharmony_ci pos += sizeof(*u); 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci return ret; 4508c2ecf20Sopenharmony_ci} 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_cistatic void ptrace_triggered(struct perf_event *bp, 4538c2ecf20Sopenharmony_ci struct perf_sample_data *data, 4548c2ecf20Sopenharmony_ci struct pt_regs *regs) 4558c2ecf20Sopenharmony_ci{ 4568c2ecf20Sopenharmony_ci int i; 4578c2ecf20Sopenharmony_ci struct thread_struct *thread = &(current->thread); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci /* 4608c2ecf20Sopenharmony_ci * Store in the virtual DR6 register the fact that the breakpoint 4618c2ecf20Sopenharmony_ci * was hit so the thread's debugger will see it. 4628c2ecf20Sopenharmony_ci */ 4638c2ecf20Sopenharmony_ci for (i = 0; i < HBP_NUM; i++) { 4648c2ecf20Sopenharmony_ci if (thread->ptrace_bps[i] == bp) 4658c2ecf20Sopenharmony_ci break; 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci thread->virtual_dr6 |= (DR_TRAP0 << i); 4698c2ecf20Sopenharmony_ci} 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci/* 4728c2ecf20Sopenharmony_ci * Walk through every ptrace breakpoints for this thread and 4738c2ecf20Sopenharmony_ci * build the dr7 value on top of their attributes. 4748c2ecf20Sopenharmony_ci * 4758c2ecf20Sopenharmony_ci */ 4768c2ecf20Sopenharmony_cistatic unsigned long ptrace_get_dr7(struct perf_event *bp[]) 4778c2ecf20Sopenharmony_ci{ 4788c2ecf20Sopenharmony_ci int i; 4798c2ecf20Sopenharmony_ci int dr7 = 0; 4808c2ecf20Sopenharmony_ci struct arch_hw_breakpoint *info; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci for (i = 0; i < HBP_NUM; i++) { 4838c2ecf20Sopenharmony_ci if (bp[i] && !bp[i]->attr.disabled) { 4848c2ecf20Sopenharmony_ci info = counter_arch_bp(bp[i]); 4858c2ecf20Sopenharmony_ci dr7 |= encode_dr7(i, info->len, info->type); 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci } 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci return dr7; 4908c2ecf20Sopenharmony_ci} 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_cistatic int ptrace_fill_bp_fields(struct perf_event_attr *attr, 4938c2ecf20Sopenharmony_ci int len, int type, bool disabled) 4948c2ecf20Sopenharmony_ci{ 4958c2ecf20Sopenharmony_ci int err, bp_len, bp_type; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci err = arch_bp_generic_fields(len, type, &bp_len, &bp_type); 4988c2ecf20Sopenharmony_ci if (!err) { 4998c2ecf20Sopenharmony_ci attr->bp_len = bp_len; 5008c2ecf20Sopenharmony_ci attr->bp_type = bp_type; 5018c2ecf20Sopenharmony_ci attr->disabled = disabled; 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci return err; 5058c2ecf20Sopenharmony_ci} 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_cistatic struct perf_event * 5088c2ecf20Sopenharmony_ciptrace_register_breakpoint(struct task_struct *tsk, int len, int type, 5098c2ecf20Sopenharmony_ci unsigned long addr, bool disabled) 5108c2ecf20Sopenharmony_ci{ 5118c2ecf20Sopenharmony_ci struct perf_event_attr attr; 5128c2ecf20Sopenharmony_ci int err; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci ptrace_breakpoint_init(&attr); 5158c2ecf20Sopenharmony_ci attr.bp_addr = addr; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci err = ptrace_fill_bp_fields(&attr, len, type, disabled); 5188c2ecf20Sopenharmony_ci if (err) 5198c2ecf20Sopenharmony_ci return ERR_PTR(err); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci return register_user_hw_breakpoint(&attr, ptrace_triggered, 5228c2ecf20Sopenharmony_ci NULL, tsk); 5238c2ecf20Sopenharmony_ci} 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_cistatic int ptrace_modify_breakpoint(struct perf_event *bp, int len, int type, 5268c2ecf20Sopenharmony_ci int disabled) 5278c2ecf20Sopenharmony_ci{ 5288c2ecf20Sopenharmony_ci struct perf_event_attr attr = bp->attr; 5298c2ecf20Sopenharmony_ci int err; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci err = ptrace_fill_bp_fields(&attr, len, type, disabled); 5328c2ecf20Sopenharmony_ci if (err) 5338c2ecf20Sopenharmony_ci return err; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci return modify_user_hw_breakpoint(bp, &attr); 5368c2ecf20Sopenharmony_ci} 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci/* 5398c2ecf20Sopenharmony_ci * Handle ptrace writes to debug register 7. 5408c2ecf20Sopenharmony_ci */ 5418c2ecf20Sopenharmony_cistatic int ptrace_write_dr7(struct task_struct *tsk, unsigned long data) 5428c2ecf20Sopenharmony_ci{ 5438c2ecf20Sopenharmony_ci struct thread_struct *thread = &tsk->thread; 5448c2ecf20Sopenharmony_ci unsigned long old_dr7; 5458c2ecf20Sopenharmony_ci bool second_pass = false; 5468c2ecf20Sopenharmony_ci int i, rc, ret = 0; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci data &= ~DR_CONTROL_RESERVED; 5498c2ecf20Sopenharmony_ci old_dr7 = ptrace_get_dr7(thread->ptrace_bps); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_cirestore: 5528c2ecf20Sopenharmony_ci rc = 0; 5538c2ecf20Sopenharmony_ci for (i = 0; i < HBP_NUM; i++) { 5548c2ecf20Sopenharmony_ci unsigned len, type; 5558c2ecf20Sopenharmony_ci bool disabled = !decode_dr7(data, i, &len, &type); 5568c2ecf20Sopenharmony_ci struct perf_event *bp = thread->ptrace_bps[i]; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci if (!bp) { 5598c2ecf20Sopenharmony_ci if (disabled) 5608c2ecf20Sopenharmony_ci continue; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci bp = ptrace_register_breakpoint(tsk, 5638c2ecf20Sopenharmony_ci len, type, 0, disabled); 5648c2ecf20Sopenharmony_ci if (IS_ERR(bp)) { 5658c2ecf20Sopenharmony_ci rc = PTR_ERR(bp); 5668c2ecf20Sopenharmony_ci break; 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci thread->ptrace_bps[i] = bp; 5708c2ecf20Sopenharmony_ci continue; 5718c2ecf20Sopenharmony_ci } 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci rc = ptrace_modify_breakpoint(bp, len, type, disabled); 5748c2ecf20Sopenharmony_ci if (rc) 5758c2ecf20Sopenharmony_ci break; 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci /* Restore if the first pass failed, second_pass shouldn't fail. */ 5798c2ecf20Sopenharmony_ci if (rc && !WARN_ON(second_pass)) { 5808c2ecf20Sopenharmony_ci ret = rc; 5818c2ecf20Sopenharmony_ci data = old_dr7; 5828c2ecf20Sopenharmony_ci second_pass = true; 5838c2ecf20Sopenharmony_ci goto restore; 5848c2ecf20Sopenharmony_ci } 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci return ret; 5878c2ecf20Sopenharmony_ci} 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci/* 5908c2ecf20Sopenharmony_ci * Handle PTRACE_PEEKUSR calls for the debug register area. 5918c2ecf20Sopenharmony_ci */ 5928c2ecf20Sopenharmony_cistatic unsigned long ptrace_get_debugreg(struct task_struct *tsk, int n) 5938c2ecf20Sopenharmony_ci{ 5948c2ecf20Sopenharmony_ci struct thread_struct *thread = &tsk->thread; 5958c2ecf20Sopenharmony_ci unsigned long val = 0; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci if (n < HBP_NUM) { 5988c2ecf20Sopenharmony_ci int index = array_index_nospec(n, HBP_NUM); 5998c2ecf20Sopenharmony_ci struct perf_event *bp = thread->ptrace_bps[index]; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci if (bp) 6028c2ecf20Sopenharmony_ci val = bp->hw.info.address; 6038c2ecf20Sopenharmony_ci } else if (n == 6) { 6048c2ecf20Sopenharmony_ci val = thread->virtual_dr6 ^ DR6_RESERVED; /* Flip back to arch polarity */ 6058c2ecf20Sopenharmony_ci } else if (n == 7) { 6068c2ecf20Sopenharmony_ci val = thread->ptrace_dr7; 6078c2ecf20Sopenharmony_ci } 6088c2ecf20Sopenharmony_ci return val; 6098c2ecf20Sopenharmony_ci} 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_cistatic int ptrace_set_breakpoint_addr(struct task_struct *tsk, int nr, 6128c2ecf20Sopenharmony_ci unsigned long addr) 6138c2ecf20Sopenharmony_ci{ 6148c2ecf20Sopenharmony_ci struct thread_struct *t = &tsk->thread; 6158c2ecf20Sopenharmony_ci struct perf_event *bp = t->ptrace_bps[nr]; 6168c2ecf20Sopenharmony_ci int err = 0; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci if (!bp) { 6198c2ecf20Sopenharmony_ci /* 6208c2ecf20Sopenharmony_ci * Put stub len and type to create an inactive but correct bp. 6218c2ecf20Sopenharmony_ci * 6228c2ecf20Sopenharmony_ci * CHECKME: the previous code returned -EIO if the addr wasn't 6238c2ecf20Sopenharmony_ci * a valid task virtual addr. The new one will return -EINVAL in 6248c2ecf20Sopenharmony_ci * this case. 6258c2ecf20Sopenharmony_ci * -EINVAL may be what we want for in-kernel breakpoints users, 6268c2ecf20Sopenharmony_ci * but -EIO looks better for ptrace, since we refuse a register 6278c2ecf20Sopenharmony_ci * writing for the user. And anyway this is the previous 6288c2ecf20Sopenharmony_ci * behaviour. 6298c2ecf20Sopenharmony_ci */ 6308c2ecf20Sopenharmony_ci bp = ptrace_register_breakpoint(tsk, 6318c2ecf20Sopenharmony_ci X86_BREAKPOINT_LEN_1, X86_BREAKPOINT_WRITE, 6328c2ecf20Sopenharmony_ci addr, true); 6338c2ecf20Sopenharmony_ci if (IS_ERR(bp)) 6348c2ecf20Sopenharmony_ci err = PTR_ERR(bp); 6358c2ecf20Sopenharmony_ci else 6368c2ecf20Sopenharmony_ci t->ptrace_bps[nr] = bp; 6378c2ecf20Sopenharmony_ci } else { 6388c2ecf20Sopenharmony_ci struct perf_event_attr attr = bp->attr; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci attr.bp_addr = addr; 6418c2ecf20Sopenharmony_ci err = modify_user_hw_breakpoint(bp, &attr); 6428c2ecf20Sopenharmony_ci } 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci return err; 6458c2ecf20Sopenharmony_ci} 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci/* 6488c2ecf20Sopenharmony_ci * Handle PTRACE_POKEUSR calls for the debug register area. 6498c2ecf20Sopenharmony_ci */ 6508c2ecf20Sopenharmony_cistatic int ptrace_set_debugreg(struct task_struct *tsk, int n, 6518c2ecf20Sopenharmony_ci unsigned long val) 6528c2ecf20Sopenharmony_ci{ 6538c2ecf20Sopenharmony_ci struct thread_struct *thread = &tsk->thread; 6548c2ecf20Sopenharmony_ci /* There are no DR4 or DR5 registers */ 6558c2ecf20Sopenharmony_ci int rc = -EIO; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci if (n < HBP_NUM) { 6588c2ecf20Sopenharmony_ci rc = ptrace_set_breakpoint_addr(tsk, n, val); 6598c2ecf20Sopenharmony_ci } else if (n == 6) { 6608c2ecf20Sopenharmony_ci thread->virtual_dr6 = val ^ DR6_RESERVED; /* Flip to positive polarity */ 6618c2ecf20Sopenharmony_ci rc = 0; 6628c2ecf20Sopenharmony_ci } else if (n == 7) { 6638c2ecf20Sopenharmony_ci rc = ptrace_write_dr7(tsk, val); 6648c2ecf20Sopenharmony_ci if (!rc) 6658c2ecf20Sopenharmony_ci thread->ptrace_dr7 = val; 6668c2ecf20Sopenharmony_ci } 6678c2ecf20Sopenharmony_ci return rc; 6688c2ecf20Sopenharmony_ci} 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci/* 6718c2ecf20Sopenharmony_ci * These access the current or another (stopped) task's io permission 6728c2ecf20Sopenharmony_ci * bitmap for debugging or core dump. 6738c2ecf20Sopenharmony_ci */ 6748c2ecf20Sopenharmony_cistatic int ioperm_active(struct task_struct *target, 6758c2ecf20Sopenharmony_ci const struct user_regset *regset) 6768c2ecf20Sopenharmony_ci{ 6778c2ecf20Sopenharmony_ci struct io_bitmap *iobm = target->thread.io_bitmap; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci return iobm ? DIV_ROUND_UP(iobm->max, regset->size) : 0; 6808c2ecf20Sopenharmony_ci} 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_cistatic int ioperm_get(struct task_struct *target, 6838c2ecf20Sopenharmony_ci const struct user_regset *regset, 6848c2ecf20Sopenharmony_ci struct membuf to) 6858c2ecf20Sopenharmony_ci{ 6868c2ecf20Sopenharmony_ci struct io_bitmap *iobm = target->thread.io_bitmap; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci if (!iobm) 6898c2ecf20Sopenharmony_ci return -ENXIO; 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci return membuf_write(&to, iobm->bitmap, IO_BITMAP_BYTES); 6928c2ecf20Sopenharmony_ci} 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci/* 6958c2ecf20Sopenharmony_ci * Called by kernel/ptrace.c when detaching.. 6968c2ecf20Sopenharmony_ci * 6978c2ecf20Sopenharmony_ci * Make sure the single step bit is not set. 6988c2ecf20Sopenharmony_ci */ 6998c2ecf20Sopenharmony_civoid ptrace_disable(struct task_struct *child) 7008c2ecf20Sopenharmony_ci{ 7018c2ecf20Sopenharmony_ci user_disable_single_step(child); 7028c2ecf20Sopenharmony_ci} 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION 7058c2ecf20Sopenharmony_cistatic const struct user_regset_view user_x86_32_view; /* Initialized below. */ 7068c2ecf20Sopenharmony_ci#endif 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_cilong arch_ptrace(struct task_struct *child, long request, 7098c2ecf20Sopenharmony_ci unsigned long addr, unsigned long data) 7108c2ecf20Sopenharmony_ci{ 7118c2ecf20Sopenharmony_ci int ret; 7128c2ecf20Sopenharmony_ci unsigned long __user *datap = (unsigned long __user *)data; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci switch (request) { 7158c2ecf20Sopenharmony_ci /* read the word at location addr in the USER area. */ 7168c2ecf20Sopenharmony_ci case PTRACE_PEEKUSR: { 7178c2ecf20Sopenharmony_ci unsigned long tmp; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci ret = -EIO; 7208c2ecf20Sopenharmony_ci if ((addr & (sizeof(data) - 1)) || addr >= sizeof(struct user)) 7218c2ecf20Sopenharmony_ci break; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci tmp = 0; /* Default return condition */ 7248c2ecf20Sopenharmony_ci if (addr < sizeof(struct user_regs_struct)) 7258c2ecf20Sopenharmony_ci tmp = getreg(child, addr); 7268c2ecf20Sopenharmony_ci else if (addr >= offsetof(struct user, u_debugreg[0]) && 7278c2ecf20Sopenharmony_ci addr <= offsetof(struct user, u_debugreg[7])) { 7288c2ecf20Sopenharmony_ci addr -= offsetof(struct user, u_debugreg[0]); 7298c2ecf20Sopenharmony_ci tmp = ptrace_get_debugreg(child, addr / sizeof(data)); 7308c2ecf20Sopenharmony_ci } 7318c2ecf20Sopenharmony_ci ret = put_user(tmp, datap); 7328c2ecf20Sopenharmony_ci break; 7338c2ecf20Sopenharmony_ci } 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ 7368c2ecf20Sopenharmony_ci ret = -EIO; 7378c2ecf20Sopenharmony_ci if ((addr & (sizeof(data) - 1)) || addr >= sizeof(struct user)) 7388c2ecf20Sopenharmony_ci break; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci if (addr < sizeof(struct user_regs_struct)) 7418c2ecf20Sopenharmony_ci ret = putreg(child, addr, data); 7428c2ecf20Sopenharmony_ci else if (addr >= offsetof(struct user, u_debugreg[0]) && 7438c2ecf20Sopenharmony_ci addr <= offsetof(struct user, u_debugreg[7])) { 7448c2ecf20Sopenharmony_ci addr -= offsetof(struct user, u_debugreg[0]); 7458c2ecf20Sopenharmony_ci ret = ptrace_set_debugreg(child, 7468c2ecf20Sopenharmony_ci addr / sizeof(data), data); 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci break; 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci case PTRACE_GETREGS: /* Get all gp regs from the child. */ 7518c2ecf20Sopenharmony_ci return copy_regset_to_user(child, 7528c2ecf20Sopenharmony_ci task_user_regset_view(current), 7538c2ecf20Sopenharmony_ci REGSET_GENERAL, 7548c2ecf20Sopenharmony_ci 0, sizeof(struct user_regs_struct), 7558c2ecf20Sopenharmony_ci datap); 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci case PTRACE_SETREGS: /* Set all gp regs in the child. */ 7588c2ecf20Sopenharmony_ci return copy_regset_from_user(child, 7598c2ecf20Sopenharmony_ci task_user_regset_view(current), 7608c2ecf20Sopenharmony_ci REGSET_GENERAL, 7618c2ecf20Sopenharmony_ci 0, sizeof(struct user_regs_struct), 7628c2ecf20Sopenharmony_ci datap); 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci case PTRACE_GETFPREGS: /* Get the child FPU state. */ 7658c2ecf20Sopenharmony_ci return copy_regset_to_user(child, 7668c2ecf20Sopenharmony_ci task_user_regset_view(current), 7678c2ecf20Sopenharmony_ci REGSET_FP, 7688c2ecf20Sopenharmony_ci 0, sizeof(struct user_i387_struct), 7698c2ecf20Sopenharmony_ci datap); 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci case PTRACE_SETFPREGS: /* Set the child FPU state. */ 7728c2ecf20Sopenharmony_ci return copy_regset_from_user(child, 7738c2ecf20Sopenharmony_ci task_user_regset_view(current), 7748c2ecf20Sopenharmony_ci REGSET_FP, 7758c2ecf20Sopenharmony_ci 0, sizeof(struct user_i387_struct), 7768c2ecf20Sopenharmony_ci datap); 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_32 7798c2ecf20Sopenharmony_ci case PTRACE_GETFPXREGS: /* Get the child extended FPU state. */ 7808c2ecf20Sopenharmony_ci return copy_regset_to_user(child, &user_x86_32_view, 7818c2ecf20Sopenharmony_ci REGSET_XFP, 7828c2ecf20Sopenharmony_ci 0, sizeof(struct user_fxsr_struct), 7838c2ecf20Sopenharmony_ci datap) ? -EIO : 0; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci case PTRACE_SETFPXREGS: /* Set the child extended FPU state. */ 7868c2ecf20Sopenharmony_ci return copy_regset_from_user(child, &user_x86_32_view, 7878c2ecf20Sopenharmony_ci REGSET_XFP, 7888c2ecf20Sopenharmony_ci 0, sizeof(struct user_fxsr_struct), 7898c2ecf20Sopenharmony_ci datap) ? -EIO : 0; 7908c2ecf20Sopenharmony_ci#endif 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION 7938c2ecf20Sopenharmony_ci case PTRACE_GET_THREAD_AREA: 7948c2ecf20Sopenharmony_ci if ((int) addr < 0) 7958c2ecf20Sopenharmony_ci return -EIO; 7968c2ecf20Sopenharmony_ci ret = do_get_thread_area(child, addr, 7978c2ecf20Sopenharmony_ci (struct user_desc __user *)data); 7988c2ecf20Sopenharmony_ci break; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci case PTRACE_SET_THREAD_AREA: 8018c2ecf20Sopenharmony_ci if ((int) addr < 0) 8028c2ecf20Sopenharmony_ci return -EIO; 8038c2ecf20Sopenharmony_ci ret = do_set_thread_area(child, addr, 8048c2ecf20Sopenharmony_ci (struct user_desc __user *)data, 0); 8058c2ecf20Sopenharmony_ci break; 8068c2ecf20Sopenharmony_ci#endif 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 8098c2ecf20Sopenharmony_ci /* normal 64bit interface to access TLS data. 8108c2ecf20Sopenharmony_ci Works just like arch_prctl, except that the arguments 8118c2ecf20Sopenharmony_ci are reversed. */ 8128c2ecf20Sopenharmony_ci case PTRACE_ARCH_PRCTL: 8138c2ecf20Sopenharmony_ci ret = do_arch_prctl_64(child, data, addr); 8148c2ecf20Sopenharmony_ci break; 8158c2ecf20Sopenharmony_ci#endif 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci default: 8188c2ecf20Sopenharmony_ci ret = ptrace_request(child, request, addr, data); 8198c2ecf20Sopenharmony_ci break; 8208c2ecf20Sopenharmony_ci } 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci return ret; 8238c2ecf20Sopenharmony_ci} 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci#ifdef CONFIG_IA32_EMULATION 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci#include <linux/compat.h> 8288c2ecf20Sopenharmony_ci#include <linux/syscalls.h> 8298c2ecf20Sopenharmony_ci#include <asm/ia32.h> 8308c2ecf20Sopenharmony_ci#include <asm/user32.h> 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci#define R32(l,q) \ 8338c2ecf20Sopenharmony_ci case offsetof(struct user32, regs.l): \ 8348c2ecf20Sopenharmony_ci regs->q = value; break 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci#define SEG32(rs) \ 8378c2ecf20Sopenharmony_ci case offsetof(struct user32, regs.rs): \ 8388c2ecf20Sopenharmony_ci return set_segment_reg(child, \ 8398c2ecf20Sopenharmony_ci offsetof(struct user_regs_struct, rs), \ 8408c2ecf20Sopenharmony_ci value); \ 8418c2ecf20Sopenharmony_ci break 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_cistatic int putreg32(struct task_struct *child, unsigned regno, u32 value) 8448c2ecf20Sopenharmony_ci{ 8458c2ecf20Sopenharmony_ci struct pt_regs *regs = task_pt_regs(child); 8468c2ecf20Sopenharmony_ci int ret; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci switch (regno) { 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci SEG32(cs); 8518c2ecf20Sopenharmony_ci SEG32(ds); 8528c2ecf20Sopenharmony_ci SEG32(es); 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci /* 8558c2ecf20Sopenharmony_ci * A 32-bit ptracer on a 64-bit kernel expects that writing 8568c2ecf20Sopenharmony_ci * FS or GS will also update the base. This is needed for 8578c2ecf20Sopenharmony_ci * operations like PTRACE_SETREGS to fully restore a saved 8588c2ecf20Sopenharmony_ci * CPU state. 8598c2ecf20Sopenharmony_ci */ 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci case offsetof(struct user32, regs.fs): 8628c2ecf20Sopenharmony_ci ret = set_segment_reg(child, 8638c2ecf20Sopenharmony_ci offsetof(struct user_regs_struct, fs), 8648c2ecf20Sopenharmony_ci value); 8658c2ecf20Sopenharmony_ci if (ret == 0) 8668c2ecf20Sopenharmony_ci child->thread.fsbase = 8678c2ecf20Sopenharmony_ci x86_fsgsbase_read_task(child, value); 8688c2ecf20Sopenharmony_ci return ret; 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci case offsetof(struct user32, regs.gs): 8718c2ecf20Sopenharmony_ci ret = set_segment_reg(child, 8728c2ecf20Sopenharmony_ci offsetof(struct user_regs_struct, gs), 8738c2ecf20Sopenharmony_ci value); 8748c2ecf20Sopenharmony_ci if (ret == 0) 8758c2ecf20Sopenharmony_ci child->thread.gsbase = 8768c2ecf20Sopenharmony_ci x86_fsgsbase_read_task(child, value); 8778c2ecf20Sopenharmony_ci return ret; 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci SEG32(ss); 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci R32(ebx, bx); 8828c2ecf20Sopenharmony_ci R32(ecx, cx); 8838c2ecf20Sopenharmony_ci R32(edx, dx); 8848c2ecf20Sopenharmony_ci R32(edi, di); 8858c2ecf20Sopenharmony_ci R32(esi, si); 8868c2ecf20Sopenharmony_ci R32(ebp, bp); 8878c2ecf20Sopenharmony_ci R32(eax, ax); 8888c2ecf20Sopenharmony_ci R32(eip, ip); 8898c2ecf20Sopenharmony_ci R32(esp, sp); 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci case offsetof(struct user32, regs.orig_eax): 8928c2ecf20Sopenharmony_ci /* 8938c2ecf20Sopenharmony_ci * Warning: bizarre corner case fixup here. A 32-bit 8948c2ecf20Sopenharmony_ci * debugger setting orig_eax to -1 wants to disable 8958c2ecf20Sopenharmony_ci * syscall restart. Make sure that the syscall 8968c2ecf20Sopenharmony_ci * restart code sign-extends orig_ax. Also make sure 8978c2ecf20Sopenharmony_ci * we interpret the -ERESTART* codes correctly if 8988c2ecf20Sopenharmony_ci * loaded into regs->ax in case the task is not 8998c2ecf20Sopenharmony_ci * actually still sitting at the exit from a 32-bit 9008c2ecf20Sopenharmony_ci * syscall with TS_COMPAT still set. 9018c2ecf20Sopenharmony_ci */ 9028c2ecf20Sopenharmony_ci regs->orig_ax = value; 9038c2ecf20Sopenharmony_ci if (syscall_get_nr(child, regs) >= 0) 9048c2ecf20Sopenharmony_ci child->thread_info.status |= TS_I386_REGS_POKED; 9058c2ecf20Sopenharmony_ci break; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci case offsetof(struct user32, regs.eflags): 9088c2ecf20Sopenharmony_ci return set_flags(child, value); 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci case offsetof(struct user32, u_debugreg[0]) ... 9118c2ecf20Sopenharmony_ci offsetof(struct user32, u_debugreg[7]): 9128c2ecf20Sopenharmony_ci regno -= offsetof(struct user32, u_debugreg[0]); 9138c2ecf20Sopenharmony_ci return ptrace_set_debugreg(child, regno / 4, value); 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci default: 9168c2ecf20Sopenharmony_ci if (regno > sizeof(struct user32) || (regno & 3)) 9178c2ecf20Sopenharmony_ci return -EIO; 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci /* 9208c2ecf20Sopenharmony_ci * Other dummy fields in the virtual user structure 9218c2ecf20Sopenharmony_ci * are ignored 9228c2ecf20Sopenharmony_ci */ 9238c2ecf20Sopenharmony_ci break; 9248c2ecf20Sopenharmony_ci } 9258c2ecf20Sopenharmony_ci return 0; 9268c2ecf20Sopenharmony_ci} 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci#undef R32 9298c2ecf20Sopenharmony_ci#undef SEG32 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci#define R32(l,q) \ 9328c2ecf20Sopenharmony_ci case offsetof(struct user32, regs.l): \ 9338c2ecf20Sopenharmony_ci *val = regs->q; break 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci#define SEG32(rs) \ 9368c2ecf20Sopenharmony_ci case offsetof(struct user32, regs.rs): \ 9378c2ecf20Sopenharmony_ci *val = get_segment_reg(child, \ 9388c2ecf20Sopenharmony_ci offsetof(struct user_regs_struct, rs)); \ 9398c2ecf20Sopenharmony_ci break 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_cistatic int getreg32(struct task_struct *child, unsigned regno, u32 *val) 9428c2ecf20Sopenharmony_ci{ 9438c2ecf20Sopenharmony_ci struct pt_regs *regs = task_pt_regs(child); 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci switch (regno) { 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci SEG32(ds); 9488c2ecf20Sopenharmony_ci SEG32(es); 9498c2ecf20Sopenharmony_ci SEG32(fs); 9508c2ecf20Sopenharmony_ci SEG32(gs); 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci R32(cs, cs); 9538c2ecf20Sopenharmony_ci R32(ss, ss); 9548c2ecf20Sopenharmony_ci R32(ebx, bx); 9558c2ecf20Sopenharmony_ci R32(ecx, cx); 9568c2ecf20Sopenharmony_ci R32(edx, dx); 9578c2ecf20Sopenharmony_ci R32(edi, di); 9588c2ecf20Sopenharmony_ci R32(esi, si); 9598c2ecf20Sopenharmony_ci R32(ebp, bp); 9608c2ecf20Sopenharmony_ci R32(eax, ax); 9618c2ecf20Sopenharmony_ci R32(orig_eax, orig_ax); 9628c2ecf20Sopenharmony_ci R32(eip, ip); 9638c2ecf20Sopenharmony_ci R32(esp, sp); 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci case offsetof(struct user32, regs.eflags): 9668c2ecf20Sopenharmony_ci *val = get_flags(child); 9678c2ecf20Sopenharmony_ci break; 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci case offsetof(struct user32, u_debugreg[0]) ... 9708c2ecf20Sopenharmony_ci offsetof(struct user32, u_debugreg[7]): 9718c2ecf20Sopenharmony_ci regno -= offsetof(struct user32, u_debugreg[0]); 9728c2ecf20Sopenharmony_ci *val = ptrace_get_debugreg(child, regno / 4); 9738c2ecf20Sopenharmony_ci break; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci default: 9768c2ecf20Sopenharmony_ci if (regno > sizeof(struct user32) || (regno & 3)) 9778c2ecf20Sopenharmony_ci return -EIO; 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci /* 9808c2ecf20Sopenharmony_ci * Other dummy fields in the virtual user structure 9818c2ecf20Sopenharmony_ci * are ignored 9828c2ecf20Sopenharmony_ci */ 9838c2ecf20Sopenharmony_ci *val = 0; 9848c2ecf20Sopenharmony_ci break; 9858c2ecf20Sopenharmony_ci } 9868c2ecf20Sopenharmony_ci return 0; 9878c2ecf20Sopenharmony_ci} 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci#undef R32 9908c2ecf20Sopenharmony_ci#undef SEG32 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_cistatic int genregs32_get(struct task_struct *target, 9938c2ecf20Sopenharmony_ci const struct user_regset *regset, 9948c2ecf20Sopenharmony_ci struct membuf to) 9958c2ecf20Sopenharmony_ci{ 9968c2ecf20Sopenharmony_ci int reg; 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci for (reg = 0; to.left; reg++) { 9998c2ecf20Sopenharmony_ci u32 val; 10008c2ecf20Sopenharmony_ci getreg32(target, reg * 4, &val); 10018c2ecf20Sopenharmony_ci membuf_store(&to, val); 10028c2ecf20Sopenharmony_ci } 10038c2ecf20Sopenharmony_ci return 0; 10048c2ecf20Sopenharmony_ci} 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_cistatic int genregs32_set(struct task_struct *target, 10078c2ecf20Sopenharmony_ci const struct user_regset *regset, 10088c2ecf20Sopenharmony_ci unsigned int pos, unsigned int count, 10098c2ecf20Sopenharmony_ci const void *kbuf, const void __user *ubuf) 10108c2ecf20Sopenharmony_ci{ 10118c2ecf20Sopenharmony_ci int ret = 0; 10128c2ecf20Sopenharmony_ci if (kbuf) { 10138c2ecf20Sopenharmony_ci const compat_ulong_t *k = kbuf; 10148c2ecf20Sopenharmony_ci while (count >= sizeof(*k) && !ret) { 10158c2ecf20Sopenharmony_ci ret = putreg32(target, pos, *k++); 10168c2ecf20Sopenharmony_ci count -= sizeof(*k); 10178c2ecf20Sopenharmony_ci pos += sizeof(*k); 10188c2ecf20Sopenharmony_ci } 10198c2ecf20Sopenharmony_ci } else { 10208c2ecf20Sopenharmony_ci const compat_ulong_t __user *u = ubuf; 10218c2ecf20Sopenharmony_ci while (count >= sizeof(*u) && !ret) { 10228c2ecf20Sopenharmony_ci compat_ulong_t word; 10238c2ecf20Sopenharmony_ci ret = __get_user(word, u++); 10248c2ecf20Sopenharmony_ci if (ret) 10258c2ecf20Sopenharmony_ci break; 10268c2ecf20Sopenharmony_ci ret = putreg32(target, pos, word); 10278c2ecf20Sopenharmony_ci count -= sizeof(*u); 10288c2ecf20Sopenharmony_ci pos += sizeof(*u); 10298c2ecf20Sopenharmony_ci } 10308c2ecf20Sopenharmony_ci } 10318c2ecf20Sopenharmony_ci return ret; 10328c2ecf20Sopenharmony_ci} 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_cistatic long ia32_arch_ptrace(struct task_struct *child, compat_long_t request, 10358c2ecf20Sopenharmony_ci compat_ulong_t caddr, compat_ulong_t cdata) 10368c2ecf20Sopenharmony_ci{ 10378c2ecf20Sopenharmony_ci unsigned long addr = caddr; 10388c2ecf20Sopenharmony_ci unsigned long data = cdata; 10398c2ecf20Sopenharmony_ci void __user *datap = compat_ptr(data); 10408c2ecf20Sopenharmony_ci int ret; 10418c2ecf20Sopenharmony_ci __u32 val; 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci switch (request) { 10448c2ecf20Sopenharmony_ci case PTRACE_PEEKUSR: 10458c2ecf20Sopenharmony_ci ret = getreg32(child, addr, &val); 10468c2ecf20Sopenharmony_ci if (ret == 0) 10478c2ecf20Sopenharmony_ci ret = put_user(val, (__u32 __user *)datap); 10488c2ecf20Sopenharmony_ci break; 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci case PTRACE_POKEUSR: 10518c2ecf20Sopenharmony_ci ret = putreg32(child, addr, data); 10528c2ecf20Sopenharmony_ci break; 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci case PTRACE_GETREGS: /* Get all gp regs from the child. */ 10558c2ecf20Sopenharmony_ci return copy_regset_to_user(child, &user_x86_32_view, 10568c2ecf20Sopenharmony_ci REGSET_GENERAL, 10578c2ecf20Sopenharmony_ci 0, sizeof(struct user_regs_struct32), 10588c2ecf20Sopenharmony_ci datap); 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci case PTRACE_SETREGS: /* Set all gp regs in the child. */ 10618c2ecf20Sopenharmony_ci return copy_regset_from_user(child, &user_x86_32_view, 10628c2ecf20Sopenharmony_ci REGSET_GENERAL, 0, 10638c2ecf20Sopenharmony_ci sizeof(struct user_regs_struct32), 10648c2ecf20Sopenharmony_ci datap); 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci case PTRACE_GETFPREGS: /* Get the child FPU state. */ 10678c2ecf20Sopenharmony_ci return copy_regset_to_user(child, &user_x86_32_view, 10688c2ecf20Sopenharmony_ci REGSET_FP, 0, 10698c2ecf20Sopenharmony_ci sizeof(struct user_i387_ia32_struct), 10708c2ecf20Sopenharmony_ci datap); 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci case PTRACE_SETFPREGS: /* Set the child FPU state. */ 10738c2ecf20Sopenharmony_ci return copy_regset_from_user( 10748c2ecf20Sopenharmony_ci child, &user_x86_32_view, REGSET_FP, 10758c2ecf20Sopenharmony_ci 0, sizeof(struct user_i387_ia32_struct), datap); 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci case PTRACE_GETFPXREGS: /* Get the child extended FPU state. */ 10788c2ecf20Sopenharmony_ci return copy_regset_to_user(child, &user_x86_32_view, 10798c2ecf20Sopenharmony_ci REGSET_XFP, 0, 10808c2ecf20Sopenharmony_ci sizeof(struct user32_fxsr_struct), 10818c2ecf20Sopenharmony_ci datap); 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci case PTRACE_SETFPXREGS: /* Set the child extended FPU state. */ 10848c2ecf20Sopenharmony_ci return copy_regset_from_user(child, &user_x86_32_view, 10858c2ecf20Sopenharmony_ci REGSET_XFP, 0, 10868c2ecf20Sopenharmony_ci sizeof(struct user32_fxsr_struct), 10878c2ecf20Sopenharmony_ci datap); 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci case PTRACE_GET_THREAD_AREA: 10908c2ecf20Sopenharmony_ci case PTRACE_SET_THREAD_AREA: 10918c2ecf20Sopenharmony_ci return arch_ptrace(child, request, addr, data); 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci default: 10948c2ecf20Sopenharmony_ci return compat_ptrace_request(child, request, addr, data); 10958c2ecf20Sopenharmony_ci } 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci return ret; 10988c2ecf20Sopenharmony_ci} 10998c2ecf20Sopenharmony_ci#endif /* CONFIG_IA32_EMULATION */ 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_X32_ABI 11028c2ecf20Sopenharmony_cistatic long x32_arch_ptrace(struct task_struct *child, 11038c2ecf20Sopenharmony_ci compat_long_t request, compat_ulong_t caddr, 11048c2ecf20Sopenharmony_ci compat_ulong_t cdata) 11058c2ecf20Sopenharmony_ci{ 11068c2ecf20Sopenharmony_ci unsigned long addr = caddr; 11078c2ecf20Sopenharmony_ci unsigned long data = cdata; 11088c2ecf20Sopenharmony_ci void __user *datap = compat_ptr(data); 11098c2ecf20Sopenharmony_ci int ret; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci switch (request) { 11128c2ecf20Sopenharmony_ci /* Read 32bits at location addr in the USER area. Only allow 11138c2ecf20Sopenharmony_ci to return the lower 32bits of segment and debug registers. */ 11148c2ecf20Sopenharmony_ci case PTRACE_PEEKUSR: { 11158c2ecf20Sopenharmony_ci u32 tmp; 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci ret = -EIO; 11188c2ecf20Sopenharmony_ci if ((addr & (sizeof(data) - 1)) || addr >= sizeof(struct user) || 11198c2ecf20Sopenharmony_ci addr < offsetof(struct user_regs_struct, cs)) 11208c2ecf20Sopenharmony_ci break; 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci tmp = 0; /* Default return condition */ 11238c2ecf20Sopenharmony_ci if (addr < sizeof(struct user_regs_struct)) 11248c2ecf20Sopenharmony_ci tmp = getreg(child, addr); 11258c2ecf20Sopenharmony_ci else if (addr >= offsetof(struct user, u_debugreg[0]) && 11268c2ecf20Sopenharmony_ci addr <= offsetof(struct user, u_debugreg[7])) { 11278c2ecf20Sopenharmony_ci addr -= offsetof(struct user, u_debugreg[0]); 11288c2ecf20Sopenharmony_ci tmp = ptrace_get_debugreg(child, addr / sizeof(data)); 11298c2ecf20Sopenharmony_ci } 11308c2ecf20Sopenharmony_ci ret = put_user(tmp, (__u32 __user *)datap); 11318c2ecf20Sopenharmony_ci break; 11328c2ecf20Sopenharmony_ci } 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci /* Write the word at location addr in the USER area. Only allow 11358c2ecf20Sopenharmony_ci to update segment and debug registers with the upper 32bits 11368c2ecf20Sopenharmony_ci zero-extended. */ 11378c2ecf20Sopenharmony_ci case PTRACE_POKEUSR: 11388c2ecf20Sopenharmony_ci ret = -EIO; 11398c2ecf20Sopenharmony_ci if ((addr & (sizeof(data) - 1)) || addr >= sizeof(struct user) || 11408c2ecf20Sopenharmony_ci addr < offsetof(struct user_regs_struct, cs)) 11418c2ecf20Sopenharmony_ci break; 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci if (addr < sizeof(struct user_regs_struct)) 11448c2ecf20Sopenharmony_ci ret = putreg(child, addr, data); 11458c2ecf20Sopenharmony_ci else if (addr >= offsetof(struct user, u_debugreg[0]) && 11468c2ecf20Sopenharmony_ci addr <= offsetof(struct user, u_debugreg[7])) { 11478c2ecf20Sopenharmony_ci addr -= offsetof(struct user, u_debugreg[0]); 11488c2ecf20Sopenharmony_ci ret = ptrace_set_debugreg(child, 11498c2ecf20Sopenharmony_ci addr / sizeof(data), data); 11508c2ecf20Sopenharmony_ci } 11518c2ecf20Sopenharmony_ci break; 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci case PTRACE_GETREGS: /* Get all gp regs from the child. */ 11548c2ecf20Sopenharmony_ci return copy_regset_to_user(child, 11558c2ecf20Sopenharmony_ci task_user_regset_view(current), 11568c2ecf20Sopenharmony_ci REGSET_GENERAL, 11578c2ecf20Sopenharmony_ci 0, sizeof(struct user_regs_struct), 11588c2ecf20Sopenharmony_ci datap); 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci case PTRACE_SETREGS: /* Set all gp regs in the child. */ 11618c2ecf20Sopenharmony_ci return copy_regset_from_user(child, 11628c2ecf20Sopenharmony_ci task_user_regset_view(current), 11638c2ecf20Sopenharmony_ci REGSET_GENERAL, 11648c2ecf20Sopenharmony_ci 0, sizeof(struct user_regs_struct), 11658c2ecf20Sopenharmony_ci datap); 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci case PTRACE_GETFPREGS: /* Get the child FPU state. */ 11688c2ecf20Sopenharmony_ci return copy_regset_to_user(child, 11698c2ecf20Sopenharmony_ci task_user_regset_view(current), 11708c2ecf20Sopenharmony_ci REGSET_FP, 11718c2ecf20Sopenharmony_ci 0, sizeof(struct user_i387_struct), 11728c2ecf20Sopenharmony_ci datap); 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci case PTRACE_SETFPREGS: /* Set the child FPU state. */ 11758c2ecf20Sopenharmony_ci return copy_regset_from_user(child, 11768c2ecf20Sopenharmony_ci task_user_regset_view(current), 11778c2ecf20Sopenharmony_ci REGSET_FP, 11788c2ecf20Sopenharmony_ci 0, sizeof(struct user_i387_struct), 11798c2ecf20Sopenharmony_ci datap); 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci default: 11828c2ecf20Sopenharmony_ci return compat_ptrace_request(child, request, addr, data); 11838c2ecf20Sopenharmony_ci } 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci return ret; 11868c2ecf20Sopenharmony_ci} 11878c2ecf20Sopenharmony_ci#endif 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 11908c2ecf20Sopenharmony_cilong compat_arch_ptrace(struct task_struct *child, compat_long_t request, 11918c2ecf20Sopenharmony_ci compat_ulong_t caddr, compat_ulong_t cdata) 11928c2ecf20Sopenharmony_ci{ 11938c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_X32_ABI 11948c2ecf20Sopenharmony_ci if (!in_ia32_syscall()) 11958c2ecf20Sopenharmony_ci return x32_arch_ptrace(child, request, caddr, cdata); 11968c2ecf20Sopenharmony_ci#endif 11978c2ecf20Sopenharmony_ci#ifdef CONFIG_IA32_EMULATION 11988c2ecf20Sopenharmony_ci return ia32_arch_ptrace(child, request, caddr, cdata); 11998c2ecf20Sopenharmony_ci#else 12008c2ecf20Sopenharmony_ci return 0; 12018c2ecf20Sopenharmony_ci#endif 12028c2ecf20Sopenharmony_ci} 12038c2ecf20Sopenharmony_ci#endif /* CONFIG_COMPAT */ 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_cistatic struct user_regset x86_64_regsets[] __ro_after_init = { 12088c2ecf20Sopenharmony_ci [REGSET_GENERAL] = { 12098c2ecf20Sopenharmony_ci .core_note_type = NT_PRSTATUS, 12108c2ecf20Sopenharmony_ci .n = sizeof(struct user_regs_struct) / sizeof(long), 12118c2ecf20Sopenharmony_ci .size = sizeof(long), .align = sizeof(long), 12128c2ecf20Sopenharmony_ci .regset_get = genregs_get, .set = genregs_set 12138c2ecf20Sopenharmony_ci }, 12148c2ecf20Sopenharmony_ci [REGSET_FP] = { 12158c2ecf20Sopenharmony_ci .core_note_type = NT_PRFPREG, 12168c2ecf20Sopenharmony_ci .n = sizeof(struct user_i387_struct) / sizeof(long), 12178c2ecf20Sopenharmony_ci .size = sizeof(long), .align = sizeof(long), 12188c2ecf20Sopenharmony_ci .active = regset_xregset_fpregs_active, .regset_get = xfpregs_get, .set = xfpregs_set 12198c2ecf20Sopenharmony_ci }, 12208c2ecf20Sopenharmony_ci [REGSET_XSTATE] = { 12218c2ecf20Sopenharmony_ci .core_note_type = NT_X86_XSTATE, 12228c2ecf20Sopenharmony_ci .size = sizeof(u64), .align = sizeof(u64), 12238c2ecf20Sopenharmony_ci .active = xstateregs_active, .regset_get = xstateregs_get, 12248c2ecf20Sopenharmony_ci .set = xstateregs_set 12258c2ecf20Sopenharmony_ci }, 12268c2ecf20Sopenharmony_ci [REGSET_IOPERM64] = { 12278c2ecf20Sopenharmony_ci .core_note_type = NT_386_IOPERM, 12288c2ecf20Sopenharmony_ci .n = IO_BITMAP_LONGS, 12298c2ecf20Sopenharmony_ci .size = sizeof(long), .align = sizeof(long), 12308c2ecf20Sopenharmony_ci .active = ioperm_active, .regset_get = ioperm_get 12318c2ecf20Sopenharmony_ci }, 12328c2ecf20Sopenharmony_ci}; 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_cistatic const struct user_regset_view user_x86_64_view = { 12358c2ecf20Sopenharmony_ci .name = "x86_64", .e_machine = EM_X86_64, 12368c2ecf20Sopenharmony_ci .regsets = x86_64_regsets, .n = ARRAY_SIZE(x86_64_regsets) 12378c2ecf20Sopenharmony_ci}; 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci#else /* CONFIG_X86_32 */ 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci#define user_regs_struct32 user_regs_struct 12428c2ecf20Sopenharmony_ci#define genregs32_get genregs_get 12438c2ecf20Sopenharmony_ci#define genregs32_set genregs_set 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci#endif /* CONFIG_X86_64 */ 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION 12488c2ecf20Sopenharmony_cistatic struct user_regset x86_32_regsets[] __ro_after_init = { 12498c2ecf20Sopenharmony_ci [REGSET_GENERAL] = { 12508c2ecf20Sopenharmony_ci .core_note_type = NT_PRSTATUS, 12518c2ecf20Sopenharmony_ci .n = sizeof(struct user_regs_struct32) / sizeof(u32), 12528c2ecf20Sopenharmony_ci .size = sizeof(u32), .align = sizeof(u32), 12538c2ecf20Sopenharmony_ci .regset_get = genregs32_get, .set = genregs32_set 12548c2ecf20Sopenharmony_ci }, 12558c2ecf20Sopenharmony_ci [REGSET_FP] = { 12568c2ecf20Sopenharmony_ci .core_note_type = NT_PRFPREG, 12578c2ecf20Sopenharmony_ci .n = sizeof(struct user_i387_ia32_struct) / sizeof(u32), 12588c2ecf20Sopenharmony_ci .size = sizeof(u32), .align = sizeof(u32), 12598c2ecf20Sopenharmony_ci .active = regset_fpregs_active, .regset_get = fpregs_get, .set = fpregs_set 12608c2ecf20Sopenharmony_ci }, 12618c2ecf20Sopenharmony_ci [REGSET_XFP] = { 12628c2ecf20Sopenharmony_ci .core_note_type = NT_PRXFPREG, 12638c2ecf20Sopenharmony_ci .n = sizeof(struct user32_fxsr_struct) / sizeof(u32), 12648c2ecf20Sopenharmony_ci .size = sizeof(u32), .align = sizeof(u32), 12658c2ecf20Sopenharmony_ci .active = regset_xregset_fpregs_active, .regset_get = xfpregs_get, .set = xfpregs_set 12668c2ecf20Sopenharmony_ci }, 12678c2ecf20Sopenharmony_ci [REGSET_XSTATE] = { 12688c2ecf20Sopenharmony_ci .core_note_type = NT_X86_XSTATE, 12698c2ecf20Sopenharmony_ci .size = sizeof(u64), .align = sizeof(u64), 12708c2ecf20Sopenharmony_ci .active = xstateregs_active, .regset_get = xstateregs_get, 12718c2ecf20Sopenharmony_ci .set = xstateregs_set 12728c2ecf20Sopenharmony_ci }, 12738c2ecf20Sopenharmony_ci [REGSET_TLS] = { 12748c2ecf20Sopenharmony_ci .core_note_type = NT_386_TLS, 12758c2ecf20Sopenharmony_ci .n = GDT_ENTRY_TLS_ENTRIES, .bias = GDT_ENTRY_TLS_MIN, 12768c2ecf20Sopenharmony_ci .size = sizeof(struct user_desc), 12778c2ecf20Sopenharmony_ci .align = sizeof(struct user_desc), 12788c2ecf20Sopenharmony_ci .active = regset_tls_active, 12798c2ecf20Sopenharmony_ci .regset_get = regset_tls_get, .set = regset_tls_set 12808c2ecf20Sopenharmony_ci }, 12818c2ecf20Sopenharmony_ci [REGSET_IOPERM32] = { 12828c2ecf20Sopenharmony_ci .core_note_type = NT_386_IOPERM, 12838c2ecf20Sopenharmony_ci .n = IO_BITMAP_BYTES / sizeof(u32), 12848c2ecf20Sopenharmony_ci .size = sizeof(u32), .align = sizeof(u32), 12858c2ecf20Sopenharmony_ci .active = ioperm_active, .regset_get = ioperm_get 12868c2ecf20Sopenharmony_ci }, 12878c2ecf20Sopenharmony_ci}; 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_cistatic const struct user_regset_view user_x86_32_view = { 12908c2ecf20Sopenharmony_ci .name = "i386", .e_machine = EM_386, 12918c2ecf20Sopenharmony_ci .regsets = x86_32_regsets, .n = ARRAY_SIZE(x86_32_regsets) 12928c2ecf20Sopenharmony_ci}; 12938c2ecf20Sopenharmony_ci#endif 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci/* 12968c2ecf20Sopenharmony_ci * This represents bytes 464..511 in the memory layout exported through 12978c2ecf20Sopenharmony_ci * the REGSET_XSTATE interface. 12988c2ecf20Sopenharmony_ci */ 12998c2ecf20Sopenharmony_ciu64 xstate_fx_sw_bytes[USER_XSTATE_FX_SW_WORDS]; 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_civoid __init update_regset_xstate_info(unsigned int size, u64 xstate_mask) 13028c2ecf20Sopenharmony_ci{ 13038c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 13048c2ecf20Sopenharmony_ci x86_64_regsets[REGSET_XSTATE].n = size / sizeof(u64); 13058c2ecf20Sopenharmony_ci#endif 13068c2ecf20Sopenharmony_ci#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION 13078c2ecf20Sopenharmony_ci x86_32_regsets[REGSET_XSTATE].n = size / sizeof(u64); 13088c2ecf20Sopenharmony_ci#endif 13098c2ecf20Sopenharmony_ci xstate_fx_sw_bytes[USER_XSTATE_XCR0_WORD] = xstate_mask; 13108c2ecf20Sopenharmony_ci} 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ciconst struct user_regset_view *task_user_regset_view(struct task_struct *task) 13138c2ecf20Sopenharmony_ci{ 13148c2ecf20Sopenharmony_ci#ifdef CONFIG_IA32_EMULATION 13158c2ecf20Sopenharmony_ci if (!user_64bit_mode(task_pt_regs(task))) 13168c2ecf20Sopenharmony_ci#endif 13178c2ecf20Sopenharmony_ci#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION 13188c2ecf20Sopenharmony_ci return &user_x86_32_view; 13198c2ecf20Sopenharmony_ci#endif 13208c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 13218c2ecf20Sopenharmony_ci return &user_x86_64_view; 13228c2ecf20Sopenharmony_ci#endif 13238c2ecf20Sopenharmony_ci} 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_civoid send_sigtrap(struct pt_regs *regs, int error_code, int si_code) 13268c2ecf20Sopenharmony_ci{ 13278c2ecf20Sopenharmony_ci struct task_struct *tsk = current; 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci tsk->thread.trap_nr = X86_TRAP_DB; 13308c2ecf20Sopenharmony_ci tsk->thread.error_code = error_code; 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci /* Send us the fake SIGTRAP */ 13338c2ecf20Sopenharmony_ci force_sig_fault(SIGTRAP, si_code, 13348c2ecf20Sopenharmony_ci user_mode(regs) ? (void __user *)regs->ip : NULL); 13358c2ecf20Sopenharmony_ci} 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_civoid user_single_step_report(struct pt_regs *regs) 13388c2ecf20Sopenharmony_ci{ 13398c2ecf20Sopenharmony_ci send_sigtrap(regs, 0, TRAP_BRKPT); 13408c2ecf20Sopenharmony_ci} 1341