Preserve the original ELF e_flags from the executable in the core dump header instead of relying on compile-time defaults (ELF_CORE_EFLAGS or value from the regset view). This ensures that ABI-specific flags in the dump file match the actual binary being executed. Save the e_flags field during ELF binary loading (in load_elf_binary()) into the mm_struct, and later retrieve it during core dump generation (in fill_note_info()). Use this saved value to populate the e_flags in the core dump ELF header. Add a new Kconfig option, CONFIG_CORE_DUMP_USE_PROCESS_EFLAGS, to guard this behavior. Although motivated by a RISC-V use case, the mechanism is generic and can be applied to all architectures. This change is needed to resolve a debugging issue encountered when analyzing core dumps with GDB for RISC-V systems. GDB inspects the e_flags field to determine whether optional register sets such as the floating-point unit are supported. Without correct flags, GDB may warn and ignore valid register data: warning: Unexpected size of section '.reg2/213' in core file. As a result, floating-point registers are not accessible in the debugger, even though they were dumped. Preserving the original e_flags enables GDB and other tools to properly interpret the dump contents. Signed-off-by: Svetlana Parfenova <svetlana.parfenova@xxxxxxxxxxxxx> --- fs/Kconfig.binfmt | 9 +++++++++ fs/binfmt_elf.c | 26 ++++++++++++++++++++------ include/linux/mm_types.h | 5 +++++ 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt index bd2f530e5740..45bed2041542 100644 --- a/fs/Kconfig.binfmt +++ b/fs/Kconfig.binfmt @@ -184,4 +184,13 @@ config EXEC_KUNIT_TEST This builds the exec KUnit tests, which tests boundary conditions of various aspects of the exec internals. +config CORE_DUMP_USE_PROCESS_EFLAGS + bool "Preserve ELF e_flags from executable in core dumps" + depends on BINFMT_ELF && ELF_CORE && RISCV + default n + help + Save the ELF e_flags from the process executable at load time + and use it in the core dump header. This ensures the dump reflects + the original binary ABI. + endmenu diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 4c1ea6b52a53..baf749e431a1 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -1297,6 +1297,11 @@ static int load_elf_binary(struct linux_binprm *bprm) mm->end_data = end_data; mm->start_stack = bprm->p; +#ifdef CONFIG_CORE_DUMP_USE_PROCESS_EFLAGS + /* stash e_flags for use in core dumps */ + mm->saved_e_flags = elf_ex->e_flags; +#endif + /** * DOC: "brk" handling * @@ -1870,6 +1875,8 @@ static int fill_note_info(struct elfhdr *elf, int phdrs, struct elf_thread_core_info *t; struct elf_prpsinfo *psinfo; struct core_thread *ct; + u16 machine; + u32 flags; psinfo = kmalloc(sizeof(*psinfo), GFP_KERNEL); if (!psinfo) @@ -1897,17 +1904,24 @@ static int fill_note_info(struct elfhdr *elf, int phdrs, return 0; } - /* - * Initialize the ELF file header. - */ - fill_elf_header(elf, phdrs, - view->e_machine, view->e_flags); + machine = view->e_machine; + flags = view->e_flags; #else view = NULL; info->thread_notes = 2; - fill_elf_header(elf, phdrs, ELF_ARCH, ELF_CORE_EFLAGS); + machine = ELF_ARCH; + flags = ELF_CORE_EFLAGS; #endif +#ifdef CONFIG_CORE_DUMP_USE_PROCESS_EFLAGS + flags = dump_task->mm->saved_e_flags; +#endif + + /* + * Initialize the ELF file header. + */ + fill_elf_header(elf, phdrs, machine, flags); + /* * Allocate a structure for each thread. */ diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index 56d07edd01f9..5487d6ba6fcb 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -1059,6 +1059,11 @@ struct mm_struct { unsigned long saved_auxv[AT_VECTOR_SIZE]; /* for /proc/PID/auxv */ +#ifdef CONFIG_CORE_DUMP_USE_PROCESS_EFLAGS + /* the ABI-related flags from the ELF header. Used for core dump */ + unsigned long saved_e_flags; +#endif + struct percpu_counter rss_stat[NR_MM_COUNTERS]; struct linux_binfmt *binfmt; -- 2.39.5