#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/sched/task_stack.h>
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/ptrace.h>
#include <linux/user.h>
#include <linux/elf.h>
#include <linux/security.h>
#include <linux/audit.h>
#include <linux/seccomp.h>
#include <linux/signal.h>
#include <linux/perf_event.h>
#include <linux/hw_breakpoint.h>
#include <linux/rcupdate.h>
#include <linux/export.h>
#include <linux/context_tracking.h>
#include <linux/nospec.h>
#include <linux/uaccess.h>
#include <asm/processor.h>
#include <asm/fpu/signal.h>
#include <asm/fpu/regset.h>
#include <asm/fpu/xstate.h>
#include <asm/debugreg.h>
#include <asm/ldt.h>
#include <asm/desc.h>
#include <asm/prctl.h>
#include <asm/proto.h>
#include <asm/hw_breakpoint.h>
#include <asm/traps.h>
#include <asm/syscall.h>
#include <asm/fsgsbase.h>
#include <asm/io_bitmap.h>
#include "tls.h"
enum x86_regset_32 { … };
enum x86_regset_64 { … };
#define REGSET_GENERAL …
#define REGSET_FP …
struct pt_regs_offset { … };
#define REG_OFFSET_NAME(r) …
#define REG_OFFSET_END …
static const struct pt_regs_offset regoffset_table[] = …;
int regs_query_register_offset(const char *name)
{ … }
const char *regs_query_register_name(unsigned int offset)
{ … }
#define FLAG_MASK_32 …
static inline bool invalid_selector(u16 value)
{ … }
#ifdef CONFIG_X86_32
#define FLAG_MASK …
static unsigned long *pt_regs_access(struct pt_regs *regs, unsigned long regno)
{
BUILD_BUG_ON(offsetof(struct pt_regs, bx) != 0);
return ®s->bx + (regno >> 2);
}
static u16 get_segment_reg(struct task_struct *task, unsigned long offset)
{
unsigned int retval;
if (offset != offsetof(struct user_regs_struct, gs))
retval = *pt_regs_access(task_pt_regs(task), offset);
else {
if (task == current)
savesegment(gs, retval);
else
retval = task->thread.gs;
}
return retval;
}
static int set_segment_reg(struct task_struct *task,
unsigned long offset, u16 value)
{
if (WARN_ON_ONCE(task == current))
return -EIO;
if (invalid_selector(value))
return -EIO;
switch (offset) {
case offsetof(struct user_regs_struct, cs):
case offsetof(struct user_regs_struct, ss):
if (unlikely(value == 0))
return -EIO;
fallthrough;
default:
*pt_regs_access(task_pt_regs(task), offset) = value;
break;
case offsetof(struct user_regs_struct, gs):
task->thread.gs = value;
}
return 0;
}
#else
#define FLAG_MASK …
static unsigned long *pt_regs_access(struct pt_regs *regs, unsigned long offset)
{ … }
static u16 get_segment_reg(struct task_struct *task, unsigned long offset)
{ … }
static int set_segment_reg(struct task_struct *task,
unsigned long offset, u16 value)
{ … }
#endif
static unsigned long get_flags(struct task_struct *task)
{ … }
static int set_flags(struct task_struct *task, unsigned long value)
{ … }
static int putreg(struct task_struct *child,
unsigned long offset, unsigned long value)
{ … }
static unsigned long getreg(struct task_struct *task, unsigned long offset)
{ … }
static int genregs_get(struct task_struct *target,
const struct user_regset *regset,
struct membuf to)
{ … }
static int genregs_set(struct task_struct *target,
const struct user_regset *regset,
unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf)
{ … }
static void ptrace_triggered(struct perf_event *bp,
struct perf_sample_data *data,
struct pt_regs *regs)
{ … }
static unsigned long ptrace_get_dr7(struct perf_event *bp[])
{ … }
static int ptrace_fill_bp_fields(struct perf_event_attr *attr,
int len, int type, bool disabled)
{ … }
static struct perf_event *
ptrace_register_breakpoint(struct task_struct *tsk, int len, int type,
unsigned long addr, bool disabled)
{ … }
static int ptrace_modify_breakpoint(struct perf_event *bp, int len, int type,
int disabled)
{ … }
static int ptrace_write_dr7(struct task_struct *tsk, unsigned long data)
{ … }
static unsigned long ptrace_get_debugreg(struct task_struct *tsk, int n)
{ … }
static int ptrace_set_breakpoint_addr(struct task_struct *tsk, int nr,
unsigned long addr)
{ … }
static int ptrace_set_debugreg(struct task_struct *tsk, int n,
unsigned long val)
{ … }
static int ioperm_active(struct task_struct *target,
const struct user_regset *regset)
{ … }
static int ioperm_get(struct task_struct *target,
const struct user_regset *regset,
struct membuf to)
{ … }
void ptrace_disable(struct task_struct *child)
{ … }
#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
static const struct user_regset_view user_x86_32_view;
#endif
#ifdef CONFIG_X86_64
static const struct user_regset_view user_x86_64_view;
#endif
long arch_ptrace(struct task_struct *child, long request,
unsigned long addr, unsigned long data)
{ … }
#ifdef CONFIG_IA32_EMULATION
#include <linux/compat.h>
#include <linux/syscalls.h>
#include <asm/ia32.h>
#include <asm/user32.h>
#define R32 …
#define SEG32 …
static int putreg32(struct task_struct *child, unsigned regno, u32 value)
{ … }
#undef R32
#undef SEG32
#define R32 …
#define SEG32 …
static int getreg32(struct task_struct *child, unsigned regno, u32 *val)
{ … }
#undef R32
#undef SEG32
static int genregs32_get(struct task_struct *target,
const struct user_regset *regset,
struct membuf to)
{ … }
static int genregs32_set(struct task_struct *target,
const struct user_regset *regset,
unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf)
{ … }
static long ia32_arch_ptrace(struct task_struct *child, compat_long_t request,
compat_ulong_t caddr, compat_ulong_t cdata)
{ … }
#endif
#ifdef CONFIG_X86_X32_ABI
static long x32_arch_ptrace(struct task_struct *child,
compat_long_t request, compat_ulong_t caddr,
compat_ulong_t cdata)
{ … }
#endif
#ifdef CONFIG_COMPAT
long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
compat_ulong_t caddr, compat_ulong_t cdata)
{ … }
#endif
#ifdef CONFIG_X86_64
static struct user_regset x86_64_regsets[] __ro_after_init = …;
static const struct user_regset_view user_x86_64_view = …;
#else
#define user_regs_struct32 …
#define genregs32_get …
#define genregs32_set …
#endif
#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
static struct user_regset x86_32_regsets[] __ro_after_init = …;
static const struct user_regset_view user_x86_32_view = …;
#endif
u64 xstate_fx_sw_bytes[USER_XSTATE_FX_SW_WORDS];
void __init update_regset_xstate_info(unsigned int size, u64 xstate_mask)
{ … }
const struct user_regset_view *task_user_regset_view(struct task_struct *task)
{ … }
void send_sigtrap(struct pt_regs *regs, int error_code, int si_code)
{ … }
void user_single_step_report(struct pt_regs *regs)
{ … }