2022-10-29 23:20:25

by Al Viro

[permalink] [raw]
Subject: [RFC][PATCHSET] coredump unification for regset and non-regset architectures

Resurrecting an old work - elf coredumps mess reduction.
Back in 2008 some of the architectures have switched to use of
regsets for elf coredumps. Unfortunately, back then the helpers
used by other architectures used to be shared with a.out coredump
support, which made their calling conventions, etc. hard to
modify. As the result, Roland went for duplicating quite a bit
of coredump-generating logics, with ifdef selecting the right
variant.

Since then the copies had drifted apart - changes made
to one of them and applicable to both had not been propagated,
etc. Many (but not all) architectures have switched to regset
variant. And a.out coredump support had been removed, which
made it easier to modify the primitives on non-regset architectures.

Series below attempts to make use of that; it had been
started about 4 years ago, but got stalled several times.

Review and testing would be very appreciated. Individual
patches - in followups. Alternatively, it can be found in
git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs.gitd #work.elfcore.

Al Viro (10):
kill signal_pt_regs()
kill coredump_params->regs
kill extern of vsyscall32_sysctl
[elf][regset] clean fill_note_info() a bit
[elf][regset] simplify thread list handling in fill_note_info()
elf_core_copy_task_regs(): task_pt_regs is defined everywhere
[elf][non-regset] uninline elf_core_copy_task_fpregs() (and lose pt_regs argument)
[elf][non-regset] use elf_core_copy_task_regs() for dumper as well
[elf] unify regset and non-regset cases
[elf] get rid of get_note_info_size()

arch/alpha/include/asm/elf.h | 6 -
arch/alpha/include/asm/ptrace.h | 1 -
arch/alpha/kernel/process.c | 8 +-
arch/csky/kernel/process.c | 3 +-
arch/m68k/kernel/process.c | 3 +-
arch/microblaze/kernel/process.c | 2 +-
arch/um/kernel/process.c | 2 +-
arch/x86/include/asm/elf.h | 1 -
arch/x86/um/asm/elf.h | 4 -
fs/binfmt_elf.c | 271 ++++++++-------------------------------
fs/coredump.c | 1 -
include/linux/coredump.h | 1 -
include/linux/elfcore.h | 13 +-
include/linux/ptrace.h | 9 --
kernel/signal.c | 2 +-
15 files changed, 61 insertions(+), 266 deletions(-)


2022-10-29 23:20:35

by Al Viro

[permalink] [raw]
Subject: [PATCH 01/10] kill signal_pt_regs()

Once upon at it was used on hot paths, but that had not been
true since 2013. IOW, there's no point for arch-optimized
equivalent of task_pt_regs(current) - remaining two users are
not worth bothering with.

Signed-off-by: Al Viro <[email protected]>
---
arch/alpha/include/asm/ptrace.h | 1 -
fs/coredump.c | 2 +-
include/linux/ptrace.h | 9 ---------
kernel/signal.c | 2 +-
4 files changed, 2 insertions(+), 12 deletions(-)

diff --git a/arch/alpha/include/asm/ptrace.h b/arch/alpha/include/asm/ptrace.h
index df5f317ab3fc..3557ce64ed21 100644
--- a/arch/alpha/include/asm/ptrace.h
+++ b/arch/alpha/include/asm/ptrace.h
@@ -16,7 +16,6 @@

#define current_pt_regs() \
((struct pt_regs *) ((char *)current_thread_info() + 2*PAGE_SIZE) - 1)
-#define signal_pt_regs current_pt_regs

#define force_successful_syscall_return() (current_pt_regs()->r0 = 0)

diff --git a/fs/coredump.c b/fs/coredump.c
index 7bad7785e8e6..b4ec1bf889f9 100644
--- a/fs/coredump.c
+++ b/fs/coredump.c
@@ -525,7 +525,7 @@ void do_coredump(const kernel_siginfo_t *siginfo)
static atomic_t core_dump_count = ATOMIC_INIT(0);
struct coredump_params cprm = {
.siginfo = siginfo,
- .regs = signal_pt_regs(),
+ .regs = task_pt_regs(current),
.limit = rlimit(RLIMIT_CORE),
/*
* We must use the same mm->flags while dumping core to avoid
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
index c952c5ba8fab..eaaef3ffec22 100644
--- a/include/linux/ptrace.h
+++ b/include/linux/ptrace.h
@@ -389,15 +389,6 @@ static inline void user_single_step_report(struct pt_regs *regs)
#define current_pt_regs() task_pt_regs(current)
#endif

-/*
- * unlike current_pt_regs(), this one is equal to task_pt_regs(current)
- * on *all* architectures; the only reason to have a per-arch definition
- * is optimisation.
- */
-#ifndef signal_pt_regs
-#define signal_pt_regs() task_pt_regs(current)
-#endif
-
#ifndef current_user_stack_pointer
#define current_user_stack_pointer() user_stack_pointer(current_pt_regs())
#endif
diff --git a/kernel/signal.c b/kernel/signal.c
index d140672185a4..848d5c282d35 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1255,7 +1255,7 @@ int send_signal_locked(int sig, struct kernel_siginfo *info,

static void print_fatal_signal(int signr)
{
- struct pt_regs *regs = signal_pt_regs();
+ struct pt_regs *regs = task_pt_regs(current);
pr_info("potentially unexpected fatal signal %d.\n", signr);

#if defined(__i386__) && !defined(__arch_um__)
--
2.30.2


2022-10-29 23:21:08

by Al Viro

[permalink] [raw]
Subject: [PATCH 03/10] kill extern of vsyscall32_sysctl

it's been dead for years.

Signed-off-by: Al Viro <[email protected]>
---
arch/x86/include/asm/elf.h | 1 -
1 file changed, 1 deletion(-)

diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h
index cb0ff1055ab1..289aa3ca4a05 100644
--- a/arch/x86/include/asm/elf.h
+++ b/arch/x86/include/asm/elf.h
@@ -226,7 +226,6 @@ do { \
/* I'm not sure if we can use '-' here */
#define ELF_PLATFORM ("x86_64")
extern void set_personality_64bit(void);
-extern unsigned int sysctl_vsyscall32;
extern int force_personality32;

#endif /* !CONFIG_X86_32 */
--
2.30.2


2022-10-29 23:34:04

by Al Viro

[permalink] [raw]
Subject: [PATCH 06/10] elf_core_copy_task_regs(): task_pt_regs is defined everywhere

Had been since 2011 for all live architectures, ever since 2013
for all architectures, period.

Signed-off-by: Al Viro <[email protected]>
---
include/linux/elfcore.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/linux/elfcore.h b/include/linux/elfcore.h
index 346a8b56cdc8..fcf58e16d1e3 100644
--- a/include/linux/elfcore.h
+++ b/include/linux/elfcore.h
@@ -88,7 +88,7 @@ static inline int elf_core_copy_task_regs(struct task_struct *t, elf_gregset_t*
{
#if defined (ELF_CORE_COPY_TASK_REGS)
return ELF_CORE_COPY_TASK_REGS(t, elfregs);
-#elif defined (task_pt_regs)
+#else
elf_core_copy_regs(elfregs, task_pt_regs(t));
#endif
return 0;
--
2.30.2


2022-10-29 23:38:32

by Al Viro

[permalink] [raw]
Subject: [PATCH 05/10] [elf][regset] simplify thread list handling in fill_note_info()

fill_note_info() iterates through the list of threads collected in
mm->core_state->dumper, allocating a struct elf_thread_core_info
instance for each and linking those into a list.

We need the entry corresponding to current to be first in the
resulting list, so the logics for list insertion is
if it's for current or list is empty
insert in the head
else
insert after the first element

However, in mm->core_state->dumper the entry for current is guaranteed
to be the first one. Which means that both parts of condition will
be true on the first iteration and neither will be true on all subsequent
ones.

Taking the first iteration out of the loop simplifies things nicely...

Signed-off-by: Al Viro <[email protected]>
---
fs/binfmt_elf.c | 22 ++++++++++------------
1 file changed, 10 insertions(+), 12 deletions(-)

diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 4190dafd2ec4..e990075fb43d 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -1866,7 +1866,14 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
/*
* Allocate a structure for each thread.
*/
- for (ct = &dump_task->signal->core_state->dumper; ct; ct = ct->next) {
+ info->thread = kzalloc(offsetof(struct elf_thread_core_info,
+ notes[info->thread_notes]),
+ GFP_KERNEL);
+ if (unlikely(!info->thread))
+ return 0;
+
+ info->thread->task = dump_task;
+ for (ct = dump_task->signal->core_state->dumper.next; ct; ct = ct->next) {
t = kzalloc(offsetof(struct elf_thread_core_info,
notes[info->thread_notes]),
GFP_KERNEL);
@@ -1874,17 +1881,8 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
return 0;

t->task = ct->task;
- if (ct->task == dump_task || !info->thread) {
- t->next = info->thread;
- info->thread = t;
- } else {
- /*
- * Make sure to keep the original task at
- * the head of the list.
- */
- t->next = info->thread->next;
- info->thread->next = t;
- }
+ t->next = info->thread->next;
+ info->thread->next = t;
}

/*
--
2.30.2


2022-10-30 00:04:58

by Al Viro

[permalink] [raw]
Subject: [PATCH 04/10] [elf][regset] clean fill_note_info() a bit

*info is already initialized...

Signed-off-by: Al Viro <[email protected]>
---
fs/binfmt_elf.c | 11 ++---------
1 file changed, 2 insertions(+), 9 deletions(-)

diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 002fd713ac11..4190dafd2ec4 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -1833,24 +1833,17 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
struct elf_thread_core_info *t;
struct elf_prpsinfo *psinfo;
struct core_thread *ct;
- unsigned int i;
-
- info->size = 0;
- info->thread = NULL;

psinfo = kmalloc(sizeof(*psinfo), GFP_KERNEL);
- if (psinfo == NULL) {
- info->psinfo.data = NULL; /* So we don't free this wrongly */
+ if (!psinfo)
return 0;
- }
-
fill_note(&info->psinfo, "CORE", NT_PRPSINFO, sizeof(*psinfo), psinfo);

/*
* Figure out how many notes we're going to need for each thread.
*/
info->thread_notes = 0;
- for (i = 0; i < view->n; ++i)
+ for (int i = 0; i < view->n; ++i)
if (view->regsets[i].core_note_type != 0)
++info->thread_notes;

--
2.30.2


2022-10-30 00:19:36

by Al Viro

[permalink] [raw]
Subject: [PATCH 10/10] [elf] get rid of get_note_info_size()

it's trivial now...

Signed-off-by: Al Viro <[email protected]>
---
fs/binfmt_elf.c | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 3758a617c9d8..65d2d2ba4d9e 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -1946,11 +1946,6 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
return 1;
}

-static size_t get_note_info_size(struct elf_note_info *info)
-{
- return info->size;
-}
-
/*
* Write all the notes for each thread. When writing the first thread, the
* process-wide notes are interleaved after the first thread-specific note.
@@ -2068,7 +2063,7 @@ static int elf_core_dump(struct coredump_params *cprm)

/* Write notes phdr entry */
{
- size_t sz = get_note_info_size(&info);
+ size_t sz = info.size;

/* For cell spufs */
sz += elf_coredump_extra_notes_size();
--
2.30.2


2022-10-30 00:19:36

by Al Viro

[permalink] [raw]
Subject: [PATCH 08/10] [elf][non-regset] use elf_core_copy_task_regs() for dumper as well

elf_core_copy_regs() is equivalent to elf_core_copy_task_regs() of
current on all architectures.

Signed-off-by: Al Viro <[email protected]>
---
fs/binfmt_elf.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index c3c5bd48361e..cb95e842c50f 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -2072,7 +2072,7 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
/* now collect the dump for the current */
memset(info->prstatus, 0, sizeof(*info->prstatus));
fill_prstatus(&info->prstatus->common, current, cprm->siginfo->si_signo);
- elf_core_copy_regs(&info->prstatus->pr_reg, task_pt_regs(current));
+ elf_core_copy_task_regs(current, &info->prstatus->pr_reg);

/* Set up header */
fill_elf_header(elf, phdrs, ELF_ARCH, ELF_CORE_EFLAGS);
--
2.30.2


2022-10-30 00:19:36

by Al Viro

[permalink] [raw]
Subject: [PATCH 07/10] [elf][non-regset] uninline elf_core_copy_task_fpregs() (and lose pt_regs argument)

Don't bother with pointless macros - we are not sharing it with aout coredumps
anymore. Just convert the underlying functions to the same arguments (nobody
uses regs, actually) and call them elf_core_copy_task_fpregs(). And unexport
the entire bunch, while we are at it.

Signed-off-by: Al Viro <[email protected]>
---
arch/alpha/include/asm/elf.h | 6 ------
arch/alpha/kernel/process.c | 8 +++-----
arch/csky/kernel/process.c | 3 +--
arch/m68k/kernel/process.c | 3 +--
arch/microblaze/kernel/process.c | 2 +-
arch/um/kernel/process.c | 2 +-
arch/x86/um/asm/elf.h | 4 ----
fs/binfmt_elf.c | 5 ++---
include/linux/elfcore.h | 11 +----------
9 files changed, 10 insertions(+), 34 deletions(-)

diff --git a/arch/alpha/include/asm/elf.h b/arch/alpha/include/asm/elf.h
index 8049997fa372..e6da23f1da83 100644
--- a/arch/alpha/include/asm/elf.h
+++ b/arch/alpha/include/asm/elf.h
@@ -120,12 +120,6 @@ extern int dump_elf_task(elf_greg_t *dest, struct task_struct *task);
#define ELF_CORE_COPY_TASK_REGS(TASK, DEST) \
dump_elf_task(*(DEST), TASK)

-/* Similar, but for the FP registers. */
-
-extern int dump_elf_task_fp(elf_fpreg_t *dest, struct task_struct *task);
-#define ELF_CORE_COPY_FPREGS(TASK, DEST) \
- dump_elf_task_fp(*(DEST), TASK)
-
/* This yields a mask that user programs can use to figure out what
instruction set this CPU supports. This is trivial on Alpha,
but not so on other machines. */
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index dbf1bc5e2ad2..65fdae9e48f3 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -333,14 +333,12 @@ dump_elf_task(elf_greg_t *dest, struct task_struct *task)
}
EXPORT_SYMBOL(dump_elf_task);

-int
-dump_elf_task_fp(elf_fpreg_t *dest, struct task_struct *task)
+int elf_core_copy_task_fpregs(struct task_struct *t, elf_fpregset_t *fpu)
{
- struct switch_stack *sw = (struct switch_stack *)task_pt_regs(task) - 1;
- memcpy(dest, sw->fp, 32 * 8);
+ struct switch_stack *sw = (struct switch_stack *)task_pt_regs(t) - 1;
+ memcpy(fpu, sw->fp, 32 * 8);
return 1;
}
-EXPORT_SYMBOL(dump_elf_task_fp);

/*
* Return saved PC of a blocked thread. This assumes the frame
diff --git a/arch/csky/kernel/process.c b/arch/csky/kernel/process.c
index eedddb155669..99767587db17 100644
--- a/arch/csky/kernel/process.c
+++ b/arch/csky/kernel/process.c
@@ -69,12 +69,11 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
}

/* Fill in the fpu structure for a core dump. */
-int dump_fpu(struct pt_regs *regs, struct user_fp *fpu)
+int elf_core_copy_task_fpregs(struct task_struct *t, elf_fpregset_t *fpu)
{
memcpy(fpu, &current->thread.user_fp, sizeof(*fpu));
return 1;
}
-EXPORT_SYMBOL(dump_fpu);

int dump_task_regs(struct task_struct *tsk, elf_gregset_t *pr_regs)
{
diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
index 2cb4a61bcfac..38ea940bccea 100644
--- a/arch/m68k/kernel/process.c
+++ b/arch/m68k/kernel/process.c
@@ -213,7 +213,7 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
}

/* Fill in the fpu structure for a core dump. */
-int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu)
+int elf_core_copy_task_fpregs(struct task_struct *t, elf_fpregset_t *fpu)
{
if (FPU_IS_EMU) {
int i;
@@ -262,7 +262,6 @@ int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu)

return 1;
}
-EXPORT_SYMBOL(dump_fpu);

unsigned long __get_wchan(struct task_struct *p)
{
diff --git a/arch/microblaze/kernel/process.c b/arch/microblaze/kernel/process.c
index 3c6241bcaea8..1f802aab2b96 100644
--- a/arch/microblaze/kernel/process.c
+++ b/arch/microblaze/kernel/process.c
@@ -133,7 +133,7 @@ void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long usp)
/*
* Set up a thread for executing a new program
*/
-int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs)
+int elf_core_copy_task_fpregs(struct task_struct *t, elf_fpregset_t *fpu)
{
return 0; /* MicroBlaze has no separate FPU registers */
}
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c
index 010bc422a09d..8058f2ccca67 100644
--- a/arch/um/kernel/process.c
+++ b/arch/um/kernel/process.c
@@ -393,7 +393,7 @@ unsigned long __get_wchan(struct task_struct *p)
return 0;
}

-int elf_core_copy_fpregs(struct task_struct *t, elf_fpregset_t *fpu)
+int elf_core_copy_task_fpregs(struct task_struct *t, elf_fpregset_t *fpu)
{
int cpu = current_thread_info()->cpu;

diff --git a/arch/x86/um/asm/elf.h b/arch/x86/um/asm/elf.h
index dcaf3b38a9e0..6523eb7c3bd1 100644
--- a/arch/x86/um/asm/elf.h
+++ b/arch/x86/um/asm/elf.h
@@ -201,10 +201,6 @@ typedef struct user_i387_struct elf_fpregset_t;

struct task_struct;

-extern int elf_core_copy_fpregs(struct task_struct *t, elf_fpregset_t *fpu);
-
-#define ELF_CORE_COPY_FPREGS(t, fpu) elf_core_copy_fpregs(t, fpu)
-
#define ELF_EXEC_PAGESIZE 4096

#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2)
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index e990075fb43d..c3c5bd48361e 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -2001,8 +2001,7 @@ static int elf_dump_thread_status(long signr, struct elf_thread_status *t)
t->num_notes++;
sz += notesize(&t->notes[0]);

- if ((t->prstatus.pr_fpvalid = elf_core_copy_task_fpregs(p, NULL,
- &t->fpu))) {
+ if ((t->prstatus.pr_fpvalid = elf_core_copy_task_fpregs(p, &t->fpu))) {
fill_note(&t->notes[1], "CORE", NT_PRFPREG, sizeof(t->fpu),
&(t->fpu));
t->num_notes++;
@@ -2100,7 +2099,7 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,

/* Try to dump the FPU. */
info->prstatus->pr_fpvalid =
- elf_core_copy_task_fpregs(current, task_pt_regs(current), info->fpu);
+ elf_core_copy_task_fpregs(current, info->fpu);
if (info->prstatus->pr_fpvalid)
fill_note(info->notes + info->numnote++,
"CORE", NT_PRFPREG, sizeof(*info->fpu), info->fpu);
diff --git a/include/linux/elfcore.h b/include/linux/elfcore.h
index fcf58e16d1e3..9ec81290e3c8 100644
--- a/include/linux/elfcore.h
+++ b/include/linux/elfcore.h
@@ -94,16 +94,7 @@ static inline int elf_core_copy_task_regs(struct task_struct *t, elf_gregset_t*
return 0;
}

-extern int dump_fpu (struct pt_regs *, elf_fpregset_t *);
-
-static inline int elf_core_copy_task_fpregs(struct task_struct *t, struct pt_regs *regs, elf_fpregset_t *fpu)
-{
-#ifdef ELF_CORE_COPY_FPREGS
- return ELF_CORE_COPY_FPREGS(t, fpu);
-#else
- return dump_fpu(regs, fpu);
-#endif
-}
+int elf_core_copy_task_fpregs(struct task_struct *t, elf_fpregset_t *fpu);

#ifdef CONFIG_ARCH_BINFMT_ELF_EXTRA_PHDRS
/*
--
2.30.2


2022-10-30 00:19:44

by Al Viro

[permalink] [raw]
Subject: [PATCH 09/10] [elf] unify regset and non-regset cases

The only real difference is in filling per-thread notes - getting
the values of registers. And this is the only part that is worth
an ifdef - we don't need to duplicate the logics regarding gathering
threads, filling other notes, etc.

It would've been hard to do back when regset-based variant had been
introduced, mostly due to sharing bits and pieces of helpers with
aout coredumps. As the result, too much had been duplicated and
the copies had drifted away since then. Now it can be done cleanly...

Signed-off-by: Al Viro <[email protected]>
---
fs/binfmt_elf.c | 230 ++++++++----------------------------------------
1 file changed, 38 insertions(+), 192 deletions(-)

diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index cb95e842c50f..3758a617c9d8 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -1723,7 +1723,6 @@ static int fill_files_note(struct memelfnote *note, struct coredump_params *cprm
return 0;
}

-#ifdef CORE_DUMP_USE_REGSET
#include <linux/regset.h>

struct elf_thread_core_info {
@@ -1744,6 +1743,7 @@ struct elf_note_info {
int thread_notes;
};

+#ifdef CORE_DUMP_USE_REGSET
/*
* When a regset has a writeback hook, we call it on each thread before
* dumping user memory. On register window machines, this makes sure the
@@ -1823,13 +1823,41 @@ static int fill_thread_core_info(struct elf_thread_core_info *t,

return 1;
}
+#else
+static int fill_thread_core_info(struct elf_thread_core_info *t,
+ const struct user_regset_view *view,
+ long signr, struct elf_note_info *info)
+{
+ struct task_struct *p = t->task;
+ elf_fpregset_t *fpu;
+
+ fill_prstatus(&t->prstatus.common, p, signr);
+ elf_core_copy_task_regs(p, &t->prstatus.pr_reg);
+
+ fill_note(&t->notes[0], "CORE", NT_PRSTATUS, sizeof(t->prstatus),
+ &(t->prstatus));
+ info->size += notesize(&t->notes[0]);
+
+ fpu = kzalloc(sizeof(elf_fpregset_t), GFP_KERNEL);
+ if (!fpu || !elf_core_copy_task_fpregs(p, fpu)) {
+ kfree(fpu);
+ return 1;
+ }
+
+ t->prstatus.pr_fpvalid = 1;
+ fill_note(&t->notes[1], "CORE", NT_PRFPREG, sizeof(*fpu), fpu);
+ info->size += notesize(&t->notes[1]);
+
+ return 1;
+}
+#endif

static int fill_note_info(struct elfhdr *elf, int phdrs,
struct elf_note_info *info,
struct coredump_params *cprm)
{
struct task_struct *dump_task = current;
- const struct user_regset_view *view = task_user_regset_view(dump_task);
+ const struct user_regset_view *view;
struct elf_thread_core_info *t;
struct elf_prpsinfo *psinfo;
struct core_thread *ct;
@@ -1839,6 +1867,9 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
return 0;
fill_note(&info->psinfo, "CORE", NT_PRPSINFO, sizeof(*psinfo), psinfo);

+#ifdef CORE_DUMP_USE_REGSET
+ view = task_user_regset_view(dump_task);
+
/*
* Figure out how many notes we're going to need for each thread.
*/
@@ -1862,6 +1893,11 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
*/
fill_elf_header(elf, phdrs,
view->e_machine, view->e_flags);
+#else
+ view = NULL;
+ info->thread_notes = 2;
+ fill_elf_header(elf, phdrs, ELF_ARCH, ELF_CORE_EFLAGS);
+#endif

/*
* Allocate a structure for each thread.
@@ -1969,196 +2005,6 @@ static void free_note_info(struct elf_note_info *info)
kvfree(info->files.data);
}

-#else
-
-/* Here is the structure in which status of each thread is captured. */
-struct elf_thread_status
-{
- struct list_head list;
- struct elf_prstatus prstatus; /* NT_PRSTATUS */
- elf_fpregset_t fpu; /* NT_PRFPREG */
- struct task_struct *thread;
- struct memelfnote notes[3];
- int num_notes;
-};
-
-/*
- * In order to add the specific thread information for the elf file format,
- * we need to keep a linked list of every threads pr_status and then create
- * a single section for them in the final core file.
- */
-static int elf_dump_thread_status(long signr, struct elf_thread_status *t)
-{
- int sz = 0;
- struct task_struct *p = t->thread;
- t->num_notes = 0;
-
- fill_prstatus(&t->prstatus.common, p, signr);
- elf_core_copy_task_regs(p, &t->prstatus.pr_reg);
-
- fill_note(&t->notes[0], "CORE", NT_PRSTATUS, sizeof(t->prstatus),
- &(t->prstatus));
- t->num_notes++;
- sz += notesize(&t->notes[0]);
-
- if ((t->prstatus.pr_fpvalid = elf_core_copy_task_fpregs(p, &t->fpu))) {
- fill_note(&t->notes[1], "CORE", NT_PRFPREG, sizeof(t->fpu),
- &(t->fpu));
- t->num_notes++;
- sz += notesize(&t->notes[1]);
- }
- return sz;
-}
-
-struct elf_note_info {
- struct memelfnote *notes;
- struct memelfnote *notes_files;
- struct elf_prstatus *prstatus; /* NT_PRSTATUS */
- struct elf_prpsinfo *psinfo; /* NT_PRPSINFO */
- struct list_head thread_list;
- elf_fpregset_t *fpu;
- user_siginfo_t csigdata;
- int thread_status_size;
- int numnote;
-};
-
-static int elf_note_info_init(struct elf_note_info *info)
-{
- memset(info, 0, sizeof(*info));
- INIT_LIST_HEAD(&info->thread_list);
-
- /* Allocate space for ELF notes */
- info->notes = kmalloc_array(8, sizeof(struct memelfnote), GFP_KERNEL);
- if (!info->notes)
- return 0;
- info->psinfo = kmalloc(sizeof(*info->psinfo), GFP_KERNEL);
- if (!info->psinfo)
- return 0;
- info->prstatus = kmalloc(sizeof(*info->prstatus), GFP_KERNEL);
- if (!info->prstatus)
- return 0;
- info->fpu = kmalloc(sizeof(*info->fpu), GFP_KERNEL);
- if (!info->fpu)
- return 0;
- return 1;
-}
-
-static int fill_note_info(struct elfhdr *elf, int phdrs,
- struct elf_note_info *info,
- struct coredump_params *cprm)
-{
- struct core_thread *ct;
- struct elf_thread_status *ets;
-
- if (!elf_note_info_init(info))
- return 0;
-
- for (ct = current->signal->core_state->dumper.next;
- ct; ct = ct->next) {
- ets = kzalloc(sizeof(*ets), GFP_KERNEL);
- if (!ets)
- return 0;
-
- ets->thread = ct->task;
- list_add(&ets->list, &info->thread_list);
- }
-
- list_for_each_entry(ets, &info->thread_list, list) {
- int sz;
-
- sz = elf_dump_thread_status(cprm->siginfo->si_signo, ets);
- info->thread_status_size += sz;
- }
- /* now collect the dump for the current */
- memset(info->prstatus, 0, sizeof(*info->prstatus));
- fill_prstatus(&info->prstatus->common, current, cprm->siginfo->si_signo);
- elf_core_copy_task_regs(current, &info->prstatus->pr_reg);
-
- /* Set up header */
- fill_elf_header(elf, phdrs, ELF_ARCH, ELF_CORE_EFLAGS);
-
- /*
- * Set up the notes in similar form to SVR4 core dumps made
- * with info from their /proc.
- */
-
- fill_note(info->notes + 0, "CORE", NT_PRSTATUS,
- sizeof(*info->prstatus), info->prstatus);
- fill_psinfo(info->psinfo, current->group_leader, current->mm);
- fill_note(info->notes + 1, "CORE", NT_PRPSINFO,
- sizeof(*info->psinfo), info->psinfo);
-
- fill_siginfo_note(info->notes + 2, &info->csigdata, cprm->siginfo);
- fill_auxv_note(info->notes + 3, current->mm);
- info->numnote = 4;
-
- if (fill_files_note(info->notes + info->numnote, cprm) == 0) {
- info->notes_files = info->notes + info->numnote;
- info->numnote++;
- }
-
- /* Try to dump the FPU. */
- info->prstatus->pr_fpvalid =
- elf_core_copy_task_fpregs(current, info->fpu);
- if (info->prstatus->pr_fpvalid)
- fill_note(info->notes + info->numnote++,
- "CORE", NT_PRFPREG, sizeof(*info->fpu), info->fpu);
- return 1;
-}
-
-static size_t get_note_info_size(struct elf_note_info *info)
-{
- int sz = 0;
- int i;
-
- for (i = 0; i < info->numnote; i++)
- sz += notesize(info->notes + i);
-
- sz += info->thread_status_size;
-
- return sz;
-}
-
-static int write_note_info(struct elf_note_info *info,
- struct coredump_params *cprm)
-{
- struct elf_thread_status *ets;
- int i;
-
- for (i = 0; i < info->numnote; i++)
- if (!writenote(info->notes + i, cprm))
- return 0;
-
- /* write out the thread status notes section */
- list_for_each_entry(ets, &info->thread_list, list) {
- for (i = 0; i < ets->num_notes; i++)
- if (!writenote(&ets->notes[i], cprm))
- return 0;
- }
-
- return 1;
-}
-
-static void free_note_info(struct elf_note_info *info)
-{
- while (!list_empty(&info->thread_list)) {
- struct list_head *tmp = info->thread_list.next;
- list_del(tmp);
- kfree(list_entry(tmp, struct elf_thread_status, list));
- }
-
- /* Free data possibly allocated by fill_files_note(): */
- if (info->notes_files)
- kvfree(info->notes_files->data);
-
- kfree(info->prstatus);
- kfree(info->psinfo);
- kfree(info->notes);
- kfree(info->fpu);
-}
-
-#endif
-
static void fill_extnum_info(struct elfhdr *elf, struct elf_shdr *shdr4extnum,
elf_addr_t e_shoff, int segs)
{
--
2.30.2


2022-10-30 00:19:45

by Al Viro

[permalink] [raw]
Subject: [PATCH 02/10] kill coredump_params->regs

it's always task_pt_regs(current)

Signed-off-by: Al Viro <[email protected]>
---
fs/binfmt_elf.c | 4 ++--
fs/coredump.c | 1 -
include/linux/coredump.h | 1 -
3 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 63c7ebb0da89..002fd713ac11 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -2082,7 +2082,7 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
/* now collect the dump for the current */
memset(info->prstatus, 0, sizeof(*info->prstatus));
fill_prstatus(&info->prstatus->common, current, cprm->siginfo->si_signo);
- elf_core_copy_regs(&info->prstatus->pr_reg, cprm->regs);
+ elf_core_copy_regs(&info->prstatus->pr_reg, task_pt_regs(current));

/* Set up header */
fill_elf_header(elf, phdrs, ELF_ARCH, ELF_CORE_EFLAGS);
@@ -2109,7 +2109,7 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,

/* Try to dump the FPU. */
info->prstatus->pr_fpvalid =
- elf_core_copy_task_fpregs(current, cprm->regs, info->fpu);
+ elf_core_copy_task_fpregs(current, task_pt_regs(current), info->fpu);
if (info->prstatus->pr_fpvalid)
fill_note(info->notes + info->numnote++,
"CORE", NT_PRFPREG, sizeof(*info->fpu), info->fpu);
diff --git a/fs/coredump.c b/fs/coredump.c
index b4ec1bf889f9..1a474de1e52b 100644
--- a/fs/coredump.c
+++ b/fs/coredump.c
@@ -525,7 +525,6 @@ void do_coredump(const kernel_siginfo_t *siginfo)
static atomic_t core_dump_count = ATOMIC_INIT(0);
struct coredump_params cprm = {
.siginfo = siginfo,
- .regs = task_pt_regs(current),
.limit = rlimit(RLIMIT_CORE),
/*
* We must use the same mm->flags while dumping core to avoid
diff --git a/include/linux/coredump.h b/include/linux/coredump.h
index 08a1d3e7e46d..a0655d7c149c 100644
--- a/include/linux/coredump.h
+++ b/include/linux/coredump.h
@@ -18,7 +18,6 @@ struct core_vma_metadata {

struct coredump_params {
const kernel_siginfo_t *siginfo;
- struct pt_regs *regs;
struct file *file;
unsigned long limit;
unsigned long mm_flags;
--
2.30.2


2022-11-08 09:59:37

by Geert Uytterhoeven

[permalink] [raw]
Subject: Re: [PATCH 07/10] [elf][non-regset] uninline elf_core_copy_task_fpregs() (and lose pt_regs argument)

On Sun, Oct 30, 2022 at 1:20 AM Al Viro <[email protected]> wrote:
> Don't bother with pointless macros - we are not sharing it with aout coredumps
> anymore. Just convert the underlying functions to the same arguments (nobody
> uses regs, actually) and call them elf_core_copy_task_fpregs(). And unexport
> the entire bunch, while we are at it.
>
> Signed-off-by: Al Viro <[email protected]>

> arch/m68k/kernel/process.c | 3 +--

Acked-by: Geert Uytterhoeven <[email protected]> # m68k

Gr{oetje,eeting}s,

Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds