um: switch to regset API and depend on XSTATE
Subsystems (4)
PATCH 1/1 um: switch to regset API and depend on XSTATE
From: Benjamin Berg <[email protected]>
The PTRACE_GETREGSET API has now existed since Linux 2.6.33. The XSAVE CPU feature should also be sufficiently common to be able to rely on it.
With this, define our internal FP state to be the hosts XSAVE data. Add discovery for the hosts XSAVE size and place the FP registers at the end of task_struct so that we can adjust the size at runtime.
Next we can implement the regset API on top and update the signal handling as well as ptrace APIs to use them. Also switch coredump creation to use the regset API and finally set HAVE_ARCH_TRACEHOOK.
This considerably improves the signal frames. Previously they might not have contained all the registers (i386) and also did not have the sizes and magic values set to the correct values to permit userspace to decode the frame.
As a side effect, this will permit UML to run on hosts with newer CPU extensions (such as AMX) that need even more register state.
---
v1:
* Use a fixed mmap'ed buffer for size discovery
* Add forgotten enum definition for signal.c
* Fix FPX register size using sizeof()
* Also set magic1 and xstate_size to the expected values
--- arch/um/Kconfig | 2 + arch/um/include/asm/processor-generic.h | 4 +- arch/um/kernel/process.c | 15 -- arch/um/kernel/um_arch.c | 2 + arch/um/os-Linux/registers.c | 9 +- arch/x86/um/Makefile | 2 +- arch/x86/um/asm/elf.h | 2 + arch/x86/um/asm/ptrace.h | 10 + arch/x86/um/os-Linux/registers.c | 145 +++-------- arch/x86/um/ptrace.c | 267 ++++++++++++++++++++ arch/x86/um/ptrace_32.c | 88 ++----- arch/x86/um/ptrace_64.c | 37 +-- arch/x86/um/shared/sysdep/ptrace.h | 8 +- arch/x86/um/shared/sysdep/ptrace_32.h | 4 - arch/x86/um/shared/sysdep/ptrace_64.h | 4 - arch/x86/um/shared/sysdep/ptrace_user.h | 6 - arch/x86/um/signal.c | 322 ++++++++---------------- arch/x86/um/user-offsets.c | 9 +- 18 files changed, 464 insertions(+), 472 deletions(-) create mode 100644 arch/x86/um/ptrace.c
arch/um/Kconfig +2 -0
@@ -5,6 +5,7 @@ menu "UML-specific options" config UML bool default y + select ARCH_WANTS_DYNAMIC_TASK_STRUCT select ARCH_HAS_CPU_FINALIZE_INIT select ARCH_HAS_FORTIFY_SOURCE select ARCH_HAS_GCOV_PROFILE_ALL
@@ -32,6 +33,7 @@ config UML select HAVE_ARCH_VMAP_STACK select HAVE_RUST select ARCH_HAS_UBSAN + select HAVE_ARCH_TRACEHOOK config MMU bool
arch/um/include/asm/processor-generic.h +3 -1
@@ -20,7 +20,6 @@ struct task_struct;struct mm_struct ;struct thread_struct { -struct pt_regs regs;struct pt_regs *segv_regs;void *fault_addr;jmp_buf *fault_catcher;
@@ -33,6 +32,9 @@ struct thread_struct {void *arg; } thread; } request; + +/* Contains variable sized FP registers */ +struct pt_regs regs; };#define INIT_THREAD \
arch/um/kernel/process.c +0 -15
@@ -287,18 +287,3 @@ unsigned long __get_wchan(struct task_struct *p)return 0 ; } - -int elf_core_copy_task_fpregs (struct task_struct *t,elf_fpregset_t *fpu) -{ -#ifdef CONFIG_X86_32 -extern int have_fpx_regs; - -/* FIXME: A plain copy does not work on i386 with have_fpx_regs */ -if (have_fpx_regs) -return 0 ; -#endif -memcpy (fpu, &t->thread.regs.regs.fp,sizeof (*fpu)); - -return 1 ; -} -
arch/um/kernel/um_arch.c +2 -0
@@ -418,6 +418,8 @@ int __init linux_main(int argc, char **argv, char **envp)os_info ("Kernel virtual memory size shrunk to %lu bytes\n" , virtmem_size); + arch_task_struct_size =sizeof (struct task_struct ) + host_fp_size; +os_flush_stdout ();return start_uml ();
arch/um/os-Linux/registers.c +7 -2
@@ -10,11 +10,12 @@#include <sysdep/ptrace.h> #include <sysdep/ptrace_user.h> #include <registers.h> +#include <stdlib.h> /* This is set once at boot time and not changed thereafter */ static unsigned long exec_regs[MAX_REG_NR ]; -static unsigned long exec_fp_regs[FP_SIZE ]; +static unsigned long *exec_fp_regs;int init_pid_registers (int pid) {
@@ -24,7 +25,11 @@ int init_pid_registers(int pid)if (err <0 )return -errno; -arch_init_registers (pid); + err =arch_init_registers (pid); +if (err <0 ) +return err; + + exec_fp_regs =malloc (host_fp_size);get_fp_registers (pid, exec_fp_regs);return 0 ; }
arch/x86/um/Makefile +1 -1
@@ -10,7 +10,7 @@ else endif obj-y = bugs_$(BITS).o delay.o fault.o \ - ptrace_$(BITS).o ptrace_user.o setjmp_$(BITS).o signal.o \ + ptrace.o ptrace_$(BITS).o ptrace_user.o setjmp_$(BITS).o signal.o \ stub_segv.o \ sys_call_table_$(BITS).o sysrq_$(BITS).o tls_$(BITS).o \ mem_$(BITS).o subarch.o os-Linux/
arch/x86/um/asm/elf.h +2 -0
@@ -8,6 +8,8 @@#include <asm/user.h> #include <skas.h> +#define CORE_DUMP_USE_REGSET +#ifdef CONFIG_X86_32 #define R_386_NONE 0
arch/x86/um/asm/ptrace.h +10 -0
@@ -2,6 +2,16 @@#ifndef __UM_X86_PTRACE_H#define __UM_X86_PTRACE_H +/* This is here because signal.c needs the REGSET_FP_LEGACY definition */ +enum { +REGSET_GENERAL , +#ifdef CONFIG_X86_32 +REGSET_FP_LEGACY , +#endif +REGSET_FP , +REGSET_XSTATE , +}; +#include <linux/compiler.h> #ifndef CONFIG_X86_32 #define __FRAME_OFFSETS/* Needed to get the R* macros */
arch/x86/um/os-Linux/registers.c +35 -110
168 lines not on this page · raw message
arch/x86/um/ptrace.c new file +267 -0
267 lines not on this page · raw message
arch/x86/um/ptrace_32.c +17 -71
109 lines not on this page · raw message
arch/x86/um/ptrace_64.c +9 -28
@@ -8,6 +8,7 @@#include <linux/mm.h> #include <linux/sched.h> #include <linux/errno.h> +#include <linux/regset.h> #define __FRAME_OFFSETS#include <asm/ptrace.h> #include <linux/uaccess.h>
@@ -188,30 +189,6 @@ int peek_user(struct task_struct *child, long addr, long data)return put_user (tmp, (unsigned long *) data); } -static int get_fpregs (struct user_i387_struct __user *buf,struct task_struct *child) -{ -int n; - - n =copy_to_user (buf, &child->thread.regs.regs.fp, -sizeof (struct user_i387_struct )); -if (n >0 ) -return -EFAULT ; - -return n; -} - -static int set_fpregs (struct user_i387_struct __user *buf,struct task_struct *child) -{ -int n; - - n =copy_from_user (&child->thread.regs.regs.fp, buf, -sizeof (struct user_i387_struct )); -if (n >0 ) -return -EFAULT ; - -return 0 ; -} -long subarch_ptrace (struct task_struct *child,long request,unsigned long addr,unsigned long data) {
@@ -220,11 +197,15 @@ long subarch_ptrace(struct task_struct *child, long request,switch (request) {case PTRACE_GETFPREGS :/* Get the child FPU state. */ - ret =get_fpregs (datap, child); -break ; +return copy_regset_to_user (child,task_user_regset_view (child), +REGSET_FP , +0 ,sizeof (struct user_i387_struct ), + datap);case PTRACE_SETFPREGS :/* Set the child FPU state. */ - ret =set_fpregs (datap, child); -break ; +return copy_regset_from_user (child,task_user_regset_view (child), +REGSET_FP , +0 ,sizeof (struct user_i387_struct ), + datap);case PTRACE_ARCH_PRCTL :/* XXX Calls ptrace on the host - needs some SMP thinking */ ret =arch_prctl (child, data, (void __user *) addr);
arch/x86/um/shared/sysdep/ptrace.h +7 -1
@@ -56,12 +56,16 @@ struct syscall_args {UPT_SYSCALL_ARG5 (r), \ UPT_SYSCALL_ARG6(r) } } ) +extern unsigned long host_fp_size; +struct uml_pt_regs {unsigned long gp[MAX_REG_NR ]; -unsigned long fp[MAX_FP_NR ];struct faultinfo faultinfo;long syscall;int is_user; + +/* Dynamically sized FP registers (holds an XSTATE) */ +unsigned long fp[]; };#define EMPTY_UML_PT_REGS { }
@@ -72,4 +76,6 @@ struct uml_pt_regs {extern int user_context (unsigned long sp); +extern int arch_init_registers (int pid); +#endif /* __SYSDEP_X86_PTRACE_H */
arch/x86/um/shared/sysdep/ptrace_32.h +0 -4
@@ -6,8 +6,6 @@#ifndef __SYSDEP_I386_PTRACE_H#define __SYSDEP_I386_PTRACE_H -#define MAX_FP_NR HOST_FPX_SIZE -#define UPT_SYSCALL_ARG1 (r) UPT_BX(r)#define UPT_SYSCALL_ARG2 (r) UPT_CX(r)#define UPT_SYSCALL_ARG3 (r) UPT_DX(r)
@@ -15,6 +13,4 @@#define UPT_SYSCALL_ARG5 (r) UPT_DI(r)#define UPT_SYSCALL_ARG6 (r) UPT_BP(r) -extern void arch_init_registers (int pid); -#endif
arch/x86/um/shared/sysdep/ptrace_64.h +0 -4
@@ -8,8 +8,6 @@#ifndef __SYSDEP_X86_64_PTRACE_H#define __SYSDEP_X86_64_PTRACE_H -#define MAX_FP_NR HOST_FP_SIZE -#define REGS_R8 (r) ((r)[HOST_R8])#define REGS_R9 (r) ((r)[HOST_R9])#define REGS_R10 (r) ((r)[HOST_R10])
@@ -57,6 +55,4 @@#define UPT_SYSCALL_ARG5 (r) UPT_R8(r)#define UPT_SYSCALL_ARG6 (r) UPT_R9(r) -extern void arch_init_registers (int pid); -#endif
arch/x86/um/shared/sysdep/ptrace_user.h +0 -6
@@ -11,12 +11,6 @@#define REGS_IP_INDEX HOST_IP#define REGS_SP_INDEX HOST_SP -#ifdef __i386__ -#define FP_SIZE ((HOST_FPX_SIZE > HOST_FP_SIZE) ? HOST_FPX_SIZE : HOST_FP_SIZE) -#else -#define FP_SIZE HOST_FP_SIZE -#endif -/* * glibc before 2.27 does not include PTRACE_SYSEMU_SINGLESTEP in its enum, * ensure we have a definition by (re-)defining it here.
arch/x86/um/signal.c +101 -221
429 lines not on this page · raw message
arch/x86/um/user-offsets.c +1 -8
@@ -19,10 +19,8 @@ void foo(void);void foo (void ) { -#ifdef __i386__ -DEFINE_LONGS (HOST_FP_SIZE ,sizeof (struct user_fpregs_struct )); -DEFINE_LONGS (HOST_FPX_SIZE ,sizeof (struct user_fpxregs_struct )); +#ifdef __i386__DEFINE (HOST_IP ,EIP );DEFINE (HOST_SP ,UESP );DEFINE (HOST_EFLAGS ,EFL );
@@ -41,11 +39,6 @@ void foo(void)DEFINE (HOST_GS ,GS );DEFINE (HOST_ORIG_AX ,ORIG_EAX );#else -#ifdef FP_XSTATE_MAGIC1 -DEFINE_LONGS (HOST_FP_SIZE ,2696 ); -#else -DEFINE (HOST_FP_SIZE ,sizeof (struct _fpstate ) /sizeof (unsigned long )); -#endif DEFINE_LONGS (HOST_BX ,RBX );DEFINE_LONGS (HOST_CX ,RCX );DEFINE_LONGS (HOST_DI ,RDI );
Signature · 1 line
2.46.2