diff options
Diffstat (limited to 'fs/binfmt_elf_fdpic.c')
-rw-r--r-- | fs/binfmt_elf_fdpic.c | 205 |
1 files changed, 90 insertions, 115 deletions
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index cf306e0798fd..50f845702b92 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -35,6 +35,7 @@ #include <linux/elfcore.h> #include <linux/coredump.h> #include <linux/dax.h> +#include <linux/regset.h> #include <linux/uaccess.h> #include <asm/param.h> @@ -1188,6 +1189,32 @@ static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *params, */ #ifdef CONFIG_ELF_CORE +struct elf_prstatus_fdpic +{ + struct elf_siginfo pr_info; /* Info associated with signal */ + short pr_cursig; /* Current signal */ + unsigned long pr_sigpend; /* Set of pending signals */ + unsigned long pr_sighold; /* Set of held signals */ + pid_t pr_pid; + pid_t pr_ppid; + pid_t pr_pgrp; + pid_t pr_sid; + struct __kernel_old_timeval pr_utime; /* User time */ + struct __kernel_old_timeval pr_stime; /* System time */ + struct __kernel_old_timeval pr_cutime; /* Cumulative user time */ + struct __kernel_old_timeval pr_cstime; /* Cumulative system time */ + elf_gregset_t pr_reg; /* GP registers */ + /* When using FDPIC, the loadmap addresses need to be communicated + * to GDB in order for GDB to do the necessary relocations. The + * fields (below) used to communicate this information are placed + * immediately after ``pr_reg'', so that the loadmap addresses may + * be viewed as part of the register set if so desired. + */ + unsigned long pr_exec_fdpic_loadmap; + unsigned long pr_interp_fdpic_loadmap; + int pr_fpvalid; /* True if math co-processor being used. */ +}; + /* * Decide whether a segment is worth dumping; default is yes to be * sure (missing info is worse than too much; etc). @@ -1344,7 +1371,7 @@ static inline void fill_note(struct memelfnote *note, const char *name, int type * fill up all the fields in prstatus from the given task struct, except * registers which need to be filled up separately. */ -static void fill_prstatus(struct elf_prstatus *prstatus, +static void fill_prstatus(struct elf_prstatus_fdpic *prstatus, struct task_struct *p, long signr) { prstatus->pr_info.si_signo = prstatus->pr_cursig = signr; @@ -1426,14 +1453,10 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p, /* 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 */ + struct elf_thread_status *next; + struct elf_prstatus_fdpic prstatus; /* NT_PRSTATUS */ elf_fpregset_t fpu; /* NT_PRFPREG */ - struct task_struct *thread; -#ifdef ELF_CORE_COPY_XFPREGS - elf_fpxregset_t xfpu; /* ELF_CORE_XFPREG_TYPE */ -#endif - struct memelfnote notes[3]; + struct memelfnote notes[2]; int num_notes; }; @@ -1442,38 +1465,44 @@ struct elf_thread_status * we need to keep a linked list of every thread's 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) +static struct elf_thread_status *elf_dump_thread_status(long signr, struct task_struct *p, int *sz) { - struct task_struct *p = t->thread; - int sz = 0; + const struct user_regset_view *view = task_user_regset_view(p); + struct elf_thread_status *t; + int i, ret; - t->num_notes = 0; + t = kzalloc(sizeof(struct elf_thread_status), GFP_KERNEL); + if (!t) + return t; fill_prstatus(&t->prstatus, p, signr); - elf_core_copy_task_regs(p, &t->prstatus.pr_reg); + regset_get(p, &view->regsets[0], + sizeof(t->prstatus.pr_reg), &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]); + *sz += notesize(&t->notes[0]); + + for (i = 1; i < view->n; ++i) { + const struct user_regset *regset = &view->regsets[i]; + if (regset->core_note_type != NT_PRFPREG) + continue; + if (regset->active && regset->active(p, regset) <= 0) + continue; + ret = regset_get(p, regset, sizeof(t->fpu), &t->fpu); + if (ret >= 0) + t->prstatus.pr_fpvalid = 1; + break; + } - t->prstatus.pr_fpvalid = elf_core_copy_task_fpregs(p, NULL, &t->fpu); if (t->prstatus.pr_fpvalid) { fill_note(&t->notes[1], "CORE", NT_PRFPREG, sizeof(t->fpu), &t->fpu); t->num_notes++; - sz += notesize(&t->notes[1]); + *sz += notesize(&t->notes[1]); } - -#ifdef ELF_CORE_COPY_XFPREGS - if (elf_core_copy_task_xfpregs(p, &t->xfpu)) { - fill_note(&t->notes[2], "LINUX", ELF_CORE_XFPREG_TYPE, - sizeof(t->xfpu), &t->xfpu); - t->num_notes++; - sz += notesize(&t->notes[2]); - } -#endif - return sz; + return t; } static void fill_extnum_info(struct elfhdr *elf, struct elf_shdr *shdr4extnum, @@ -1552,23 +1581,15 @@ static size_t elf_core_vma_data_size(unsigned long mm_flags) */ static int elf_fdpic_core_dump(struct coredump_params *cprm) { -#define NUM_NOTES 6 int has_dumped = 0; int segs; int i; struct vm_area_struct *vma; struct elfhdr *elf = NULL; loff_t offset = 0, dataoff; - int numnote; - struct memelfnote *notes = NULL; - struct elf_prstatus *prstatus = NULL; /* NT_PRSTATUS */ + struct memelfnote psinfo_note, auxv_note; struct elf_prpsinfo *psinfo = NULL; /* NT_PRPSINFO */ - LIST_HEAD(thread_list); - struct list_head *t; - elf_fpregset_t *fpu = NULL; -#ifdef ELF_CORE_COPY_XFPREGS - elf_fpxregset_t *xfpu = NULL; -#endif + struct elf_thread_status *thread_list = NULL; int thread_status_size = 0; elf_addr_t *auxv; struct elf_phdr *phdr4note = NULL; @@ -1594,47 +1615,28 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) elf = kmalloc(sizeof(*elf), GFP_KERNEL); if (!elf) goto end_coredump; - prstatus = kzalloc(sizeof(*prstatus), GFP_KERNEL); - if (!prstatus) - goto end_coredump; psinfo = kmalloc(sizeof(*psinfo), GFP_KERNEL); if (!psinfo) goto end_coredump; - notes = kmalloc_array(NUM_NOTES, sizeof(struct memelfnote), - GFP_KERNEL); - if (!notes) - goto end_coredump; - fpu = kmalloc(sizeof(*fpu), GFP_KERNEL); - if (!fpu) - goto end_coredump; -#ifdef ELF_CORE_COPY_XFPREGS - xfpu = kmalloc(sizeof(*xfpu), GFP_KERNEL); - if (!xfpu) - goto end_coredump; -#endif for (ct = current->mm->core_state->dumper.next; ct; ct = ct->next) { - tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); + tmp = elf_dump_thread_status(cprm->siginfo->si_signo, + ct->task, &thread_status_size); if (!tmp) goto end_coredump; - tmp->thread = ct->task; - list_add(&tmp->list, &thread_list); - } - - list_for_each(t, &thread_list) { - struct elf_thread_status *tmp; - int sz; - - tmp = list_entry(t, struct elf_thread_status, list); - sz = elf_dump_thread_status(cprm->siginfo->si_signo, tmp); - thread_status_size += sz; + tmp->next = thread_list; + thread_list = tmp; } /* now collect the dump for the current */ - fill_prstatus(prstatus, current, cprm->siginfo->si_signo); - elf_core_copy_regs(&prstatus->pr_reg, cprm->regs); + tmp = elf_dump_thread_status(cprm->siginfo->si_signo, + current, &thread_status_size); + if (!tmp) + goto end_coredump; + tmp->next = thread_list; + thread_list = tmp; segs = current->mm->map_count; segs += elf_core_extra_phdrs(); @@ -1656,51 +1658,28 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) * with info from their /proc. */ - fill_note(notes + 0, "CORE", NT_PRSTATUS, sizeof(*prstatus), prstatus); fill_psinfo(psinfo, current->group_leader, current->mm); - fill_note(notes + 1, "CORE", NT_PRPSINFO, sizeof(*psinfo), psinfo); - - numnote = 2; + fill_note(&psinfo_note, "CORE", NT_PRPSINFO, sizeof(*psinfo), psinfo); + thread_status_size += notesize(&psinfo_note); auxv = (elf_addr_t *) current->mm->saved_auxv; - i = 0; do i += 2; while (auxv[i - 2] != AT_NULL); - fill_note(¬es[numnote++], "CORE", NT_AUXV, - i * sizeof(elf_addr_t), auxv); - - /* Try to dump the FPU. */ - if ((prstatus->pr_fpvalid = - elf_core_copy_task_fpregs(current, cprm->regs, fpu))) - fill_note(notes + numnote++, - "CORE", NT_PRFPREG, sizeof(*fpu), fpu); -#ifdef ELF_CORE_COPY_XFPREGS - if (elf_core_copy_task_xfpregs(current, xfpu)) - fill_note(notes + numnote++, - "LINUX", ELF_CORE_XFPREG_TYPE, sizeof(*xfpu), xfpu); -#endif + fill_note(&auxv_note, "CORE", NT_AUXV, i * sizeof(elf_addr_t), auxv); + thread_status_size += notesize(&auxv_note); - offset += sizeof(*elf); /* Elf header */ + offset = sizeof(*elf); /* Elf header */ offset += segs * sizeof(struct elf_phdr); /* Program headers */ /* Write notes phdr entry */ - { - int sz = 0; - - for (i = 0; i < numnote; i++) - sz += notesize(notes + i); - - sz += thread_status_size; + phdr4note = kmalloc(sizeof(*phdr4note), GFP_KERNEL); + if (!phdr4note) + goto end_coredump; - phdr4note = kmalloc(sizeof(*phdr4note), GFP_KERNEL); - if (!phdr4note) - goto end_coredump; - - fill_elf_note_phdr(phdr4note, sz, offset); - offset += sz; - } + fill_elf_note_phdr(phdr4note, thread_status_size, offset); + offset += thread_status_size; /* Page-align dumped data */ dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); @@ -1753,15 +1732,18 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) goto end_coredump; /* write out the notes section */ - for (i = 0; i < numnote; i++) - if (!writenote(notes + i, cprm)) + if (!writenote(thread_list->notes, cprm)) + goto end_coredump; + if (!writenote(&psinfo_note, cprm)) + goto end_coredump; + if (!writenote(&auxv_note, cprm)) + goto end_coredump; + for (i = 1; i < thread_list->num_notes; i++) + if (!writenote(thread_list->notes + i, cprm)) goto end_coredump; /* write out the thread status notes section */ - list_for_each(t, &thread_list) { - struct elf_thread_status *tmp = - list_entry(t, struct elf_thread_status, list); - + for (tmp = thread_list->next; tmp; tmp = tmp->next) { for (i = 0; i < tmp->num_notes; i++) if (!writenote(&tmp->notes[i], cprm)) goto end_coredump; @@ -1789,23 +1771,16 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) } end_coredump: - while (!list_empty(&thread_list)) { - struct list_head *tmp = thread_list.next; - list_del(tmp); - kfree(list_entry(tmp, struct elf_thread_status, list)); + while (thread_list) { + tmp = thread_list; + thread_list = thread_list->next; + kfree(tmp); } kfree(phdr4note); kfree(elf); - kfree(prstatus); kfree(psinfo); - kfree(notes); - kfree(fpu); kfree(shdr4extnum); -#ifdef ELF_CORE_COPY_XFPREGS - kfree(xfpu); -#endif return has_dumped; -#undef NUM_NOTES } #endif /* CONFIG_ELF_CORE */ |