summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--contrib/binutils/binutils/readelf.c2
-rw-r--r--contrib/binutils/include/elf/common.h1
-rw-r--r--sys/amd64/amd64/elf_machdep.c22
-rw-r--r--sys/amd64/amd64/fpu.c7
-rw-r--r--sys/amd64/amd64/ptrace_machdep.c58
-rw-r--r--sys/compat/ia32/ia32_sysvec.c20
-rw-r--r--sys/i386/i386/elf_machdep.c22
-rw-r--r--sys/i386/i386/ptrace_machdep.c38
-rw-r--r--sys/i386/isa/npx.c7
-rw-r--r--sys/kern/imgact_elf.c49
-rw-r--r--sys/sys/elf_common.h1
-rw-r--r--sys/sys/imgact_elf.h1
-rw-r--r--sys/x86/include/fpu.h17
-rw-r--r--sys/x86/include/ptrace.h17
-rw-r--r--usr.bin/gcore/elfcore.c35
15 files changed, 259 insertions, 38 deletions
diff --git a/contrib/binutils/binutils/readelf.c b/contrib/binutils/binutils/readelf.c
index aafd8d4..09f4062 100644
--- a/contrib/binutils/binutils/readelf.c
+++ b/contrib/binutils/binutils/readelf.c
@@ -9159,6 +9159,8 @@ get_freebsd_note_type (unsigned e_type)
return _("NT_PROCSTAT_PSSTRINGS (ps_strings data)");
case NT_PROCSTAT_AUXV:
return _("NT_PROCSTAT_AUXV (auxv data)");
+ case NT_X86_XSTATE:
+ return _("NT_X86_XSTATE (x86 XSAVE extended state)");
default:
return get_note_type(e_type);
}
diff --git a/contrib/binutils/include/elf/common.h b/contrib/binutils/include/elf/common.h
index d4d9d7b..157922a 100644
--- a/contrib/binutils/include/elf/common.h
+++ b/contrib/binutils/include/elf/common.h
@@ -414,6 +414,7 @@
#define NT_PROCSTAT_OSREL 14
#define NT_PROCSTAT_PSSTRINGS 15
#define NT_PROCSTAT_AUXV 16
+#define NT_X86_XSTATE 0x202
/* Note segments for core files on NetBSD systems. Note name
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);
diff --git a/sys/compat/ia32/ia32_sysvec.c b/sys/compat/ia32/ia32_sysvec.c
index 770bbbf..6dd02af 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 034b4c4..cd701aa 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,12 +135,27 @@ 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
elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
diff --git a/sys/i386/i386/ptrace_machdep.c b/sys/i386/i386/ptrace_machdep.c
index 870d69b..5cfeb4c 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 0034f2d..8cc8118 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 e3494f6..0bdd6ed 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, &note, 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 3f6eebb..2a29dd4 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 712a55e..e8d5567 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 73af34c..0430108 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 16a04d1..16f9c62 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
diff --git a/usr.bin/gcore/elfcore.c b/usr.bin/gcore/elfcore.c
index 037854c..fb3bf50 100644
--- a/usr.bin/gcore/elfcore.c
+++ b/usr.bin/gcore/elfcore.c
@@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$");
#include <err.h>
#include <errno.h>
#include <fcntl.h>
+#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -101,6 +102,9 @@ static void *elf_note_fpregset(void *, size_t *);
static void *elf_note_prpsinfo(void *, size_t *);
static void *elf_note_prstatus(void *, size_t *);
static void *elf_note_thrmisc(void *, size_t *);
+#if defined(__i386__) || defined(__amd64__)
+static void *elf_note_x86_xstate(void *, size_t *);
+#endif
static void *elf_note_procstat_auxv(void *, size_t *);
static void *elf_note_procstat_files(void *, size_t *);
static void *elf_note_procstat_groups(void *, size_t *);
@@ -341,6 +345,9 @@ elf_putnotes(pid_t pid, struct sbuf *sb, size_t *sizep)
elf_putnote(NT_PRSTATUS, elf_note_prstatus, tids + i, sb);
elf_putnote(NT_FPREGSET, elf_note_fpregset, tids + i, sb);
elf_putnote(NT_THRMISC, elf_note_thrmisc, tids + i, sb);
+#if defined(__i386__) || defined(__amd64__)
+ elf_putnote(NT_X86_XSTATE, elf_note_x86_xstate, tids + i, sb);
+#endif
}
#ifndef ELFCORE_COMPAT_32
@@ -615,6 +622,34 @@ elf_note_thrmisc(void *arg, size_t *sizep)
return (thrmisc);
}
+#if defined(__i386__) || defined(__amd64__)
+static void *
+elf_note_x86_xstate(void *arg, size_t *sizep)
+{
+ lwpid_t tid;
+ char *xstate;
+ static bool xsave_checked = false;
+ static struct ptrace_xstate_info info;
+
+ tid = *(lwpid_t *)arg;
+ if (!xsave_checked) {
+ if (ptrace(PT_GETXSTATE_INFO, tid, (void *)&info,
+ sizeof(info)) != 0)
+ info.xsave_len = 0;
+ xsave_checked = true;
+ }
+ if (info.xsave_len == 0) {
+ *sizep = 0;
+ return (NULL);
+ }
+ xstate = calloc(1, info.xsave_len);
+ ptrace(PT_GETXSTATE, tid, xstate, 0);
+ *(uint64_t *)(xstate + X86_XSTATE_XCR0_OFFSET) = info.xsave_mask;
+ *sizep = info.xsave_len;
+ return (xstate);
+}
+#endif
+
static void *
procstat_sysctl(void *arg, int what, size_t structsz, size_t *sizep)
{
OpenPOWER on IntegriCloud