mirror of
https://github.com/tbsdtv/linux_media.git
synced 2025-07-23 12:43:29 +02:00
Merge tag 'pull-elfcore' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull elf coredumping updates from Al Viro: "Unification of regset and non-regset sides of ELF coredump handling. Collecting per-thread register values is the only thing that needs to be ifdefed there..." * tag 'pull-elfcore' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: [elf] get rid of get_note_info_size() [elf] unify regset and non-regset cases [elf][non-regset] use elf_core_copy_task_regs() for dumper as well [elf][non-regset] uninline elf_core_copy_task_fpregs() (and lose pt_regs argument) elf_core_copy_task_regs(): task_pt_regs is defined everywhere [elf][regset] simplify thread list handling in fill_note_info() [elf][regset] clean fill_note_info() a bit kill extern of vsyscall32_sysctl kill coredump_params->regs kill signal_pt_regs()
This commit is contained in:
271
fs/binfmt_elf.c
271
fs/binfmt_elf.c
@@ -1718,7 +1718,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 {
|
||||
@@ -1739,6 +1738,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
|
||||
@@ -1818,34 +1818,58 @@ 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;
|
||||
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);
|
||||
|
||||
#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.
|
||||
*/
|
||||
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;
|
||||
|
||||
@@ -1864,11 +1888,23 @@ 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.
|
||||
*/
|
||||
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);
|
||||
@@ -1876,17 +1912,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;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1914,11 +1941,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.
|
||||
@@ -1973,197 +1995,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, NULL,
|
||||
&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_regs(&info->prstatus->pr_reg, cprm->regs);
|
||||
|
||||
/* 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, cprm->regs, 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)
|
||||
{
|
||||
@@ -2227,7 +2058,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();
|
||||
|
Reference in New Issue
Block a user