xref: /kernel/linux/linux-5.10/arch/x86/kernel/ptrace.c (revision 8c2ecf20)
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 &regs->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 &regs->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