Skip to content

Commit c3056a7

Browse files
committed
Merge tag 'x86-fpu-2024-09-17' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 fpu updates from Thomas Gleixner: "Provide FPU buffer layout in core dumps: Debuggers have guess the FPU buffer layout in core dumps, which is error prone. This is because AMD and Intel layouts differ. To avoid buggy heuristics add a ELF section which describes the buffer layout which can be retrieved by tools" * tag 'x86-fpu-2024-09-17' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/elf: Add a new FPU buffer layout info to x86 core files
2 parents dea435d + ba38677 commit c3056a7

File tree

5 files changed

+109
-2
lines changed

5 files changed

+109
-2
lines changed

arch/x86/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ config X86
107107
select ARCH_HAS_DEBUG_WX
108108
select ARCH_HAS_ZONE_DMA_SET if EXPERT
109109
select ARCH_HAVE_NMI_SAFE_CMPXCHG
110+
select ARCH_HAVE_EXTRA_ELF_NOTES
110111
select ARCH_MHP_MEMMAP_ON_MEMORY_ENABLE
111112
select ARCH_MIGHT_HAVE_ACPI_PDC if ACPI
112113
select ARCH_MIGHT_HAVE_PC_PARPORT

arch/x86/include/uapi/asm/elf.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
2+
#ifndef _UAPI_ASM_X86_ELF_H
3+
#define _UAPI_ASM_X86_ELF_H
4+
5+
#include <linux/types.h>
6+
7+
struct x86_xfeat_component {
8+
__u32 type;
9+
__u32 size;
10+
__u32 offset;
11+
__u32 flags;
12+
} __packed;
13+
14+
_Static_assert(sizeof(struct x86_xfeat_component) % 4 == 0, "x86_xfeat_component is not aligned");
15+
16+
#endif /* _UAPI_ASM_X86_ELF_H */

arch/x86/kernel/fpu/xstate.c

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <linux/seq_file.h>
1414
#include <linux/proc_fs.h>
1515
#include <linux/vmalloc.h>
16+
#include <linux/coredump.h>
1617

1718
#include <asm/fpu/api.h>
1819
#include <asm/fpu/regset.h>
@@ -23,6 +24,8 @@
2324
#include <asm/prctl.h>
2425
#include <asm/elf.h>
2526

27+
#include <uapi/asm/elf.h>
28+
2629
#include "context.h"
2730
#include "internal.h"
2831
#include "legacy.h"
@@ -1841,3 +1844,89 @@ int proc_pid_arch_status(struct seq_file *m, struct pid_namespace *ns,
18411844
return 0;
18421845
}
18431846
#endif /* CONFIG_PROC_PID_ARCH_STATUS */
1847+
1848+
#ifdef CONFIG_COREDUMP
1849+
static const char owner_name[] = "LINUX";
1850+
1851+
/*
1852+
* Dump type, size, offset and flag values for every xfeature that is present.
1853+
*/
1854+
static int dump_xsave_layout_desc(struct coredump_params *cprm)
1855+
{
1856+
int num_records = 0;
1857+
int i;
1858+
1859+
for_each_extended_xfeature(i, fpu_user_cfg.max_features) {
1860+
struct x86_xfeat_component xc = {
1861+
.type = i,
1862+
.size = xstate_sizes[i],
1863+
.offset = xstate_offsets[i],
1864+
/* reserved for future use */
1865+
.flags = 0,
1866+
};
1867+
1868+
if (!dump_emit(cprm, &xc, sizeof(xc)))
1869+
return 0;
1870+
1871+
num_records++;
1872+
}
1873+
return num_records;
1874+
}
1875+
1876+
static u32 get_xsave_desc_size(void)
1877+
{
1878+
u32 cnt = 0;
1879+
u32 i;
1880+
1881+
for_each_extended_xfeature(i, fpu_user_cfg.max_features)
1882+
cnt++;
1883+
1884+
return cnt * (sizeof(struct x86_xfeat_component));
1885+
}
1886+
1887+
int elf_coredump_extra_notes_write(struct coredump_params *cprm)
1888+
{
1889+
int num_records = 0;
1890+
struct elf_note en;
1891+
1892+
if (!fpu_user_cfg.max_features)
1893+
return 0;
1894+
1895+
en.n_namesz = sizeof(owner_name);
1896+
en.n_descsz = get_xsave_desc_size();
1897+
en.n_type = NT_X86_XSAVE_LAYOUT;
1898+
1899+
if (!dump_emit(cprm, &en, sizeof(en)))
1900+
return 1;
1901+
if (!dump_emit(cprm, owner_name, en.n_namesz))
1902+
return 1;
1903+
if (!dump_align(cprm, 4))
1904+
return 1;
1905+
1906+
num_records = dump_xsave_layout_desc(cprm);
1907+
if (!num_records)
1908+
return 1;
1909+
1910+
/* Total size should be equal to the number of records */
1911+
if ((sizeof(struct x86_xfeat_component) * num_records) != en.n_descsz)
1912+
return 1;
1913+
1914+
return 0;
1915+
}
1916+
1917+
int elf_coredump_extra_notes_size(void)
1918+
{
1919+
int size;
1920+
1921+
if (!fpu_user_cfg.max_features)
1922+
return 0;
1923+
1924+
/* .note header */
1925+
size = sizeof(struct elf_note);
1926+
/* Name plus alignment to 4 bytes */
1927+
size += roundup(sizeof(owner_name), 4);
1928+
size += get_xsave_desc_size();
1929+
1930+
return size;
1931+
}
1932+
#endif /* CONFIG_COREDUMP */

fs/binfmt_elf.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2039,7 +2039,7 @@ static int elf_core_dump(struct coredump_params *cprm)
20392039
{
20402040
size_t sz = info.size;
20412041

2042-
/* For cell spufs */
2042+
/* For cell spufs and x86 xstate */
20432043
sz += elf_coredump_extra_notes_size();
20442044

20452045
phdr4note = kmalloc(sizeof(*phdr4note), GFP_KERNEL);
@@ -2103,7 +2103,7 @@ static int elf_core_dump(struct coredump_params *cprm)
21032103
if (!write_note_info(&info, cprm))
21042104
goto end_coredump;
21052105

2106-
/* For cell spufs */
2106+
/* For cell spufs and x86 xstate */
21072107
if (elf_coredump_extra_notes_write(cprm))
21082108
goto end_coredump;
21092109

include/uapi/linux/elf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,7 @@ typedef struct elf64_shdr {
411411
#define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */
412412
/* Old binutils treats 0x203 as a CET state */
413413
#define NT_X86_SHSTK 0x204 /* x86 SHSTK state */
414+
#define NT_X86_XSAVE_LAYOUT 0x205 /* XSAVE layout description */
414415
#define NT_S390_HIGH_GPRS 0x300 /* s390 upper register halves */
415416
#define NT_S390_TIMER 0x301 /* s390 timer register */
416417
#define NT_S390_TODCMP 0x302 /* s390 TOD clock comparator register */

0 commit comments

Comments
 (0)