diff options
| author | John Baldwin <jhb@FreeBSD.org> | 2014-11-21 20:53:17 +0000 |
|---|---|---|
| committer | John Baldwin <jhb@FreeBSD.org> | 2014-11-21 20:53:17 +0000 |
| commit | 180e57e5c7b6bd5a0fd0bc523c4dcd7cff363fd6 (patch) | |
| tree | 99aebdaca5d14d076e3c8d62e9c14bad62a4c56c /sys | |
| parent | 1e7bf26b33f52bf151947f85383d7042bf7e1e3c (diff) | |
Notes
Diffstat (limited to 'sys')
| -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 | ||||
| -rw-r--r-- | sys/compat/ia32/ia32_sysvec.c | 20 | ||||
| -rw-r--r-- | sys/i386/i386/elf_machdep.c | 22 | ||||
| -rw-r--r-- | sys/i386/i386/ptrace_machdep.c | 38 | ||||
| -rw-r--r-- | sys/i386/isa/npx.c | 7 | ||||
| -rw-r--r-- | sys/kern/imgact_elf.c | 49 | ||||
| -rw-r--r-- | sys/sys/elf_common.h | 1 | ||||
| -rw-r--r-- | sys/sys/imgact_elf.h | 1 | ||||
| -rw-r--r-- | sys/x86/include/fpu.h | 17 | ||||
| -rw-r--r-- | sys/x86/include/ptrace.h | 17 |
12 files changed, 221 insertions, 38 deletions
diff --git a/sys/amd64/amd64/elf_machdep.c b/sys/amd64/amd64/elf_machdep.c index fdc4d56308dd..23fa39b4fd1e 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,11 +134,26 @@ 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 diff --git a/sys/amd64/amd64/fpu.c b/sys/amd64/amd64/fpu.c index b0f25ba244c8..f30c07370374 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 9fa1917d8bd4..c96fe263db92 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); diff --git a/sys/compat/ia32/ia32_sysvec.c b/sys/compat/ia32/ia32_sysvec.c index 770bbbf9e462..6dd02aff96a5 100644 --- a/sys/compat/ia32/ia32_sysvec.c +++ b/sys/compat/ia32/ia32_sysvec.c @@ -187,9 +187,25 @@ SYSINIT(kia32, SI_SUB_EXEC, SI_ORDER_ANY, &kia32_brand_info); void -elf32_dump_thread(struct thread *td __unused, void *dst __unused, - size_t *off __unused) +elf32_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 += elf32_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 += elf32_populate_note(NT_X86_XSTATE, NULL, NULL, + cpu_max_ext_state_size, NULL); + } + *off = len; } void diff --git a/sys/i386/i386/elf_machdep.c b/sys/i386/i386/elf_machdep.c index 034b4c47d877..cd701aa3dd7c 100644 --- a/sys/i386/i386/elf_machdep.c +++ b/sys/i386/i386/elf_machdep.c @@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$"); #include <machine/elf.h> #include <machine/md_var.h> +#include <machine/npx.h> struct sysentvec elf32_freebsd_sysvec = { .sv_size = SYS_MAXSYSCALL, @@ -134,11 +135,26 @@ SYSINIT(kelf32, SI_SUB_EXEC, SI_ORDER_ANY, void -elf32_dump_thread(struct thread *td __unused, void *dst __unused, - size_t *off __unused) +elf32_dump_thread(struct thread *td, void *dst, size_t *off) { -} + void *buf; + size_t len; + len = 0; + if (use_xsave) { + if (dst != NULL) { + npxgetregs(td); + len += elf32_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 += elf32_populate_note(NT_X86_XSTATE, NULL, NULL, + cpu_max_ext_state_size, NULL); + } + *off = len; +} /* Process one elf relocation with addend. */ static int diff --git a/sys/i386/i386/ptrace_machdep.c b/sys/i386/i386/ptrace_machdep.c index 870d69b52a56..5cfeb4c299c7 100644 --- a/sys/i386/i386/ptrace_machdep.c +++ b/sys/i386/i386/ptrace_machdep.c @@ -46,6 +46,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; @@ -53,14 +54,14 @@ cpu_ptrace_xstate(struct thread *td, int req, void *addr, int data) return (EOPNOTSUPP); switch (req) { - case PT_GETXSTATE: + case PT_GETXSTATE_OLD: npxgetregs(td); savefpu = (char *)(get_pcb_user_save_td(td) + 1); error = copyout(savefpu, addr, cpu_max_ext_state_size - sizeof(union savefpu)); break; - case PT_SETXSTATE: + case PT_SETXSTATE_OLD: if (data > cpu_max_ext_state_size - sizeof(union savefpu)) { error = EINVAL; break; @@ -74,6 +75,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: + npxgetregs(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 = npxsetregs(td, (union savefpu *)savefpu, + savefpu + sizeof(union savefpu), data - + sizeof(union savefpu)); + free(savefpu, M_TEMP); + break; + default: error = EINVAL; break; @@ -106,6 +137,9 @@ cpu_ptrace(struct thread *td, int req, void *addr, int data) fpstate->sv_env.en_mxcsr &= cpu_mxcsr_mask; break; + 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); diff --git a/sys/i386/isa/npx.c b/sys/i386/isa/npx.c index 0034f2d674dd..8cc81185394b 100644 --- a/sys/i386/isa/npx.c +++ b/sys/i386/isa/npx.c @@ -201,6 +201,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 savexmm, sv_pad) && + X86_XSTATE_XCR0_OFFSET + sizeof(uint64_t) <= sizeof(struct savexmm)); + static void fpu_clean_state(void); #endif diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c index e3494f69d07b..0bdd6edee8c5 100644 --- a/sys/kern/imgact_elf.c +++ b/sys/kern/imgact_elf.c @@ -1587,7 +1587,50 @@ register_note(struct note_info_list *list, int type, outfunc_t out, void *arg) return (size); notesize = sizeof(Elf_Note) + /* note header */ - roundup2(8, ELF_NOTE_ROUNDSIZE) + /* note name ("FreeBSD") */ + roundup2(sizeof(FREEBSD_ABI_VENDOR), ELF_NOTE_ROUNDSIZE) + + /* note name */ + roundup2(size, ELF_NOTE_ROUNDSIZE); /* note description */ + + return (notesize); +} + +static size_t +append_note_data(const void *src, void *dst, size_t len) +{ + size_t padded_len; + + padded_len = roundup2(len, ELF_NOTE_ROUNDSIZE); + if (dst != NULL) { + bcopy(src, dst, len); + bzero((char *)dst + len, padded_len - len); + } + return (padded_len); +} + +size_t +__elfN(populate_note)(int type, void *src, void *dst, size_t size, void **descp) +{ + Elf_Note *note; + char *buf; + size_t notesize; + + buf = dst; + if (buf != NULL) { + note = (Elf_Note *)buf; + note->n_namesz = sizeof(FREEBSD_ABI_VENDOR); + note->n_descsz = size; + note->n_type = type; + buf += sizeof(*note); + buf += append_note_data(FREEBSD_ABI_VENDOR, buf, + sizeof(FREEBSD_ABI_VENDOR)); + append_note_data(src, buf, size); + if (descp != NULL) + *descp = buf; + } + + notesize = sizeof(Elf_Note) + /* note header */ + roundup2(sizeof(FREEBSD_ABI_VENDOR), ELF_NOTE_ROUNDSIZE) + + /* note name */ roundup2(size, ELF_NOTE_ROUNDSIZE); /* note description */ return (notesize); @@ -1604,13 +1647,13 @@ __elfN(putnote)(struct note_info *ninfo, struct sbuf *sb) return; } - note.n_namesz = 8; /* strlen("FreeBSD") + 1 */ + note.n_namesz = sizeof(FREEBSD_ABI_VENDOR); note.n_descsz = ninfo->outsize; note.n_type = ninfo->type; sbuf_bcat(sb, ¬e, sizeof(note)); sbuf_start_section(sb, &old_len); - sbuf_bcat(sb, "FreeBSD", note.n_namesz); + sbuf_bcat(sb, FREEBSD_ABI_VENDOR, sizeof(FREEBSD_ABI_VENDOR)); sbuf_end_section(sb, old_len, ELF_NOTE_ROUNDSIZE, 0); if (note.n_descsz == 0) return; diff --git a/sys/sys/elf_common.h b/sys/sys/elf_common.h index 3f6eebbd6856..2a29dd42df03 100644 --- a/sys/sys/elf_common.h +++ b/sys/sys/elf_common.h @@ -508,6 +508,7 @@ typedef struct { #define NT_PROCSTAT_OSREL 14 /* Procstat osreldate data. */ #define NT_PROCSTAT_PSSTRINGS 15 /* Procstat ps_strings data. */ #define NT_PROCSTAT_AUXV 16 /* Procstat auxv data. */ +#define NT_X86_XSTATE 0x202 /* x86 XSAVE extended state. */ /* Symbol Binding - ELFNN_ST_BIND - st_info */ #define STB_LOCAL 0 /* Local symbol */ diff --git a/sys/sys/imgact_elf.h b/sys/sys/imgact_elf.h index 712a55e1bac4..e8d5567cc273 100644 --- a/sys/sys/imgact_elf.h +++ b/sys/sys/imgact_elf.h @@ -90,6 +90,7 @@ int __elfN(insert_brand_entry)(Elf_Brandinfo *entry); int __elfN(remove_brand_entry)(Elf_Brandinfo *entry); int __elfN(freebsd_fixup)(register_t **, struct image_params *); int __elfN(coredump)(struct thread *, struct vnode *, off_t, int); +size_t __elfN(populate_note)(int, void *, void *, size_t, void **); /* Machine specific function to dump per-thread information. */ void __elfN(dump_thread)(struct thread *, void *, size_t *); diff --git a/sys/x86/include/fpu.h b/sys/x86/include/fpu.h index 73af34c4fd20..0430108ec08e 100644 --- a/sys/x86/include/fpu.h +++ b/sys/x86/include/fpu.h @@ -63,15 +63,7 @@ struct save87 { struct env87 sv_env; /* floating point control/status */ struct fpacc87 sv_ac[8]; /* accumulator contents, 0-7 */ uint8_t sv_pad0[4]; /* saved status word (now unused) */ - /* - * Bogus padding for emulators. Emulators should use their own - * struct and arrange to store into this struct (ending here) - * before it is inspected for ptracing or for core dumps. Some - * emulators overwrite the whole struct. We have no good way of - * knowing how much padding to leave. Leave just enough for the - * GPL emulator's i387_union (176 bytes total). - */ - uint8_t sv_pad[64]; /* padding; used by emulators */ + uint8_t sv_pad[64]; }; /* Contents of each SSE extended accumulator. */ @@ -215,4 +207,11 @@ struct savefpu_ymm { #define __INITIAL_MXCSR__ 0x1F80 #define __INITIAL_MXCSR_MASK__ 0xFFBF +/* + * The current value of %xcr0 is saved in the sv_pad[] field of the FPU + * state in the NT_X86_XSTATE note in core dumps. This offset is chosen + * to match the offset used by NT_X86_XSTATE in other systems. + */ +#define X86_XSTATE_XCR0_OFFSET 464 + #endif /* !_X86_FPU_H_ */ diff --git a/sys/x86/include/ptrace.h b/sys/x86/include/ptrace.h index 16a04d1e9f6e..16f9c62bb213 100644 --- a/sys/x86/include/ptrace.h +++ b/sys/x86/include/ptrace.h @@ -37,14 +37,25 @@ /* * On amd64 (PT_FIRSTMACH + 0) and (PT_FIRSTMACH + 1) are old values for - * PT_GETXSTATE and PT_SETXSTATE. They should not be (re)used. + * PT_GETXSTATE_OLD and PT_SETXSTATE_OLD. They should not be (re)used. */ #ifdef __i386__ #define PT_GETXMMREGS (PT_FIRSTMACH + 0) #define PT_SETXMMREGS (PT_FIRSTMACH + 1) #endif -#define PT_GETXSTATE (PT_FIRSTMACH + 2) -#define PT_SETXSTATE (PT_FIRSTMACH + 3) +#ifdef _KERNEL +#define PT_GETXSTATE_OLD (PT_FIRSTMACH + 2) +#define PT_SETXSTATE_OLD (PT_FIRSTMACH + 3) +#endif +#define PT_GETXSTATE_INFO (PT_FIRSTMACH + 4) +#define PT_GETXSTATE (PT_FIRSTMACH + 5) +#define PT_SETXSTATE (PT_FIRSTMACH + 6) + +/* Argument structure for PT_GETXSTATE_INFO. */ +struct ptrace_xstate_info { + uint64_t xsave_mask; + uint32_t xsave_len; +}; #endif |
