Commit 5d2c56ec authored by Al Viro's avatar Al Viro
Browse files

Merge branch 'work.fdpic' into regset.followup

parents ce327e1c 1697a322
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -179,8 +179,6 @@ extern void ia64_init_addr_space (void);
#define ELF_AR_SSD_OFFSET  (56 * sizeof(elf_greg_t))
#define ELF_AR_END_OFFSET  (57 * sizeof(elf_greg_t))

typedef unsigned long elf_fpxregset_t;

typedef unsigned long elf_greg_t;
typedef elf_greg_t elf_gregset_t[ELF_NGREG];

+0 −2
Original line number Diff line number Diff line
@@ -53,8 +53,6 @@ static inline void ppc_elf_core_copy_regs(elf_gregset_t elf_regs,
}
#define ELF_CORE_COPY_REGS(gregs, regs) ppc_elf_core_copy_regs(gregs, regs);

typedef elf_vrregset_t elf_fpxregset_t;

/* ELF_HWCAP yields a mask that user programs can use to figure out what
   instruction set this cpu supports.  This could be done in userspace,
   but it's not easy, and we've already done it here.  */
+0 −2
Original line number Diff line number Diff line
@@ -21,8 +21,6 @@ typedef struct user_i387_struct elf_fpregset_t;

#ifdef __i386__

typedef struct user_fxsr_struct elf_fpxregset_t;

#define R_386_NONE	0
#define R_386_32	1
#define R_386_PC32	2
+0 −30
Original line number Diff line number Diff line
@@ -2038,9 +2038,6 @@ struct elf_thread_status
	struct elf_prstatus 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];
	int num_notes;
};
@@ -2071,15 +2068,6 @@ static int elf_dump_thread_status(long signr, struct elf_thread_status *t)
		t->num_notes++;
		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;
}

@@ -2090,9 +2078,6 @@ struct elf_note_info {
	struct elf_prpsinfo *psinfo;	/* NT_PRPSINFO */
	struct list_head thread_list;
	elf_fpregset_t *fpu;
#ifdef ELF_CORE_COPY_XFPREGS
	elf_fpxregset_t *xfpu;
#endif
	user_siginfo_t csigdata;
	int thread_status_size;
	int numnote;
@@ -2116,11 +2101,6 @@ static int elf_note_info_init(struct elf_note_info *info)
	info->fpu = kmalloc(sizeof(*info->fpu), GFP_KERNEL);
	if (!info->fpu)
		return 0;
#ifdef ELF_CORE_COPY_XFPREGS
	info->xfpu = kmalloc(sizeof(*info->xfpu), GFP_KERNEL);
	if (!info->xfpu)
		return 0;
#endif
	return 1;
}

@@ -2184,13 +2164,6 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
	if (info->prstatus->pr_fpvalid)
		fill_note(info->notes + info->numnote++,
			  "CORE", NT_PRFPREG, sizeof(*info->fpu), info->fpu);
#ifdef ELF_CORE_COPY_XFPREGS
	if (elf_core_copy_task_xfpregs(current, info->xfpu))
		fill_note(info->notes + info->numnote++,
			  "LINUX", ELF_CORE_XFPREG_TYPE,
			  sizeof(*info->xfpu), info->xfpu);
#endif

	return 1;
}

@@ -2243,9 +2216,6 @@ static void free_note_info(struct elf_note_info *info)
	kfree(info->psinfo);
	kfree(info->notes);
	kfree(info->fpu);
#ifdef ELF_CORE_COPY_XFPREGS
	kfree(info->xfpu);
#endif
}

#endif
+90 −115
Original line number Diff line number Diff line
@@ -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>
@@ -1189,6 +1190,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).
@@ -1345,7 +1372,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;
@@ -1427,14 +1454,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;
};

@@ -1443,38 +1466,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,
@@ -1553,23 +1582,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;
@@ -1595,47 +1616,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();
@@ -1657,51 +1659,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(&notes[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;

		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);
@@ -1754,15 +1733,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;
@@ -1790,23 +1772,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 */
Loading