diff options
Diffstat (limited to 'sys/amd64')
-rw-r--r-- | sys/amd64/amd64/elf_machdep.c | 22 | ||||
-rw-r--r-- | sys/amd64/amd64/fpu.c | 7 | ||||
-rw-r--r-- | sys/amd64/amd64/ptrace_machdep.c | 58 |
3 files changed, 71 insertions, 16 deletions
diff --git a/sys/amd64/amd64/elf_machdep.c b/sys/amd64/amd64/elf_machdep.c index fdc4d56..23fa39b 100644 --- a/sys/amd64/amd64/elf_machdep.c +++ b/sys/amd64/amd64/elf_machdep.c @@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$"); #include <vm/vm_param.h> #include <machine/elf.h> +#include <machine/fpu.h> #include <machine/md_var.h> struct sysentvec elf64_freebsd_sysvec = { @@ -133,12 +134,27 @@ SYSINIT(kelf64, SI_SUB_EXEC, SI_ORDER_ANY, &kfreebsd_brand_info); void -elf64_dump_thread(struct thread *td __unused, void *dst __unused, - size_t *off __unused) +elf64_dump_thread(struct thread *td, void *dst, size_t *off) { + void *buf; + size_t len; + + len = 0; + if (use_xsave) { + if (dst != NULL) { + fpugetregs(td); + len += elf64_populate_note(NT_X86_XSTATE, + get_pcb_user_save_td(td), dst, + cpu_max_ext_state_size, &buf); + *(uint64_t *)((char *)buf + X86_XSTATE_XCR0_OFFSET) = + xsave_mask; + } else + len += elf64_populate_note(NT_X86_XSTATE, NULL, NULL, + cpu_max_ext_state_size, NULL); + } + *off = len; } - /* Process one elf relocation with addend. */ static int elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, diff --git a/sys/amd64/amd64/fpu.c b/sys/amd64/amd64/fpu.c index b0f25ba..f30c073 100644 --- a/sys/amd64/amd64/fpu.c +++ b/sys/amd64/amd64/fpu.c @@ -127,6 +127,13 @@ CTASSERT(sizeof(struct savefpu_ymm) == 832); */ CTASSERT(sizeof(struct pcb) % XSAVE_AREA_ALIGN == 0); +/* + * Ensure the copy of XCR0 saved in a core is contained in the padding + * area. + */ +CTASSERT(X86_XSTATE_XCR0_OFFSET >= offsetof(struct savefpu, sv_pad) && + X86_XSTATE_XCR0_OFFSET + sizeof(uint64_t) <= sizeof(struct savefpu)); + static void fpu_clean_state(void); SYSCTL_INT(_hw, HW_FLOATINGPT, floatingpoint, CTLFLAG_RD, diff --git a/sys/amd64/amd64/ptrace_machdep.c b/sys/amd64/amd64/ptrace_machdep.c index 9fa1917..c96fe26 100644 --- a/sys/amd64/amd64/ptrace_machdep.c +++ b/sys/amd64/amd64/ptrace_machdep.c @@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$"); static int cpu_ptrace_xstate(struct thread *td, int req, void *addr, int data) { + struct ptrace_xstate_info info; char *savefpu; int error; @@ -49,14 +50,14 @@ cpu_ptrace_xstate(struct thread *td, int req, void *addr, int data) return (EOPNOTSUPP); switch (req) { - case PT_GETXSTATE: + case PT_GETXSTATE_OLD: fpugetregs(td); savefpu = (char *)(get_pcb_user_save_td(td) + 1); error = copyout(savefpu, addr, cpu_max_ext_state_size - sizeof(struct savefpu)); break; - case PT_SETXSTATE: + case PT_SETXSTATE_OLD: if (data > cpu_max_ext_state_size - sizeof(struct savefpu)) { error = EINVAL; break; @@ -70,6 +71,36 @@ cpu_ptrace_xstate(struct thread *td, int req, void *addr, int data) free(savefpu, M_TEMP); break; + case PT_GETXSTATE_INFO: + if (data != sizeof(info)) { + error = EINVAL; + break; + } + info.xsave_len = cpu_max_ext_state_size; + info.xsave_mask = xsave_mask; + error = copyout(&info, addr, data); + break; + + case PT_GETXSTATE: + fpugetregs(td); + savefpu = (char *)(get_pcb_user_save_td(td)); + error = copyout(savefpu, addr, cpu_max_ext_state_size); + break; + + case PT_SETXSTATE: + if (data > cpu_max_ext_state_size) { + error = EINVAL; + break; + } + savefpu = malloc(data, M_TEMP, M_WAITOK); + error = copyin(addr, savefpu, data); + if (error == 0) + error = fpusetregs(td, (struct savefpu *)savefpu, + savefpu + sizeof(struct savefpu), data - + sizeof(struct savefpu)); + free(savefpu, M_TEMP); + break; + default: error = EINVAL; break; @@ -81,8 +112,6 @@ cpu_ptrace_xstate(struct thread *td, int req, void *addr, int data) #ifdef COMPAT_FREEBSD32 #define PT_I386_GETXMMREGS (PT_FIRSTMACH + 0) #define PT_I386_SETXMMREGS (PT_FIRSTMACH + 1) -#define PT_I386_GETXSTATE (PT_FIRSTMACH + 2) -#define PT_I386_SETXSTATE (PT_FIRSTMACH + 3) static int cpu32_ptrace(struct thread *td, int req, void *addr, int data) @@ -104,12 +133,12 @@ cpu32_ptrace(struct thread *td, int req, void *addr, int data) fpstate->sv_env.en_mxcsr &= cpu_mxcsr_mask; break; - case PT_I386_GETXSTATE: - error = cpu_ptrace_xstate(td, PT_GETXSTATE, addr, data); - break; - - case PT_I386_SETXSTATE: - error = cpu_ptrace_xstate(td, PT_SETXSTATE, addr, data); + case PT_GETXSTATE_OLD: + case PT_SETXSTATE_OLD: + case PT_GETXSTATE_INFO: + case PT_GETXSTATE: + case PT_SETXSTATE: + error = cpu_ptrace_xstate(td, req, addr, data); break; default: @@ -131,13 +160,16 @@ cpu_ptrace(struct thread *td, int req, void *addr, int data) return (cpu32_ptrace(td, req, addr, data)); #endif - /* Support old values of PT_GETXSTATE and PT_SETXSTATE. */ + /* Support old values of PT_GETXSTATE_OLD and PT_SETXSTATE_OLD. */ if (req == PT_FIRSTMACH + 0) - req = PT_GETXSTATE; + req = PT_GETXSTATE_OLD; if (req == PT_FIRSTMACH + 1) - req = PT_SETXSTATE; + req = PT_SETXSTATE_OLD; switch (req) { + case PT_GETXSTATE_OLD: + case PT_SETXSTATE_OLD: + case PT_GETXSTATE_INFO: case PT_GETXSTATE: case PT_SETXSTATE: error = cpu_ptrace_xstate(td, req, addr, data); |