All of lore.kernel.org
 help / color / mirror / Atom feed
From: Janani Venkataraman <jananive@in.ibm.com>
To: linux-kernel@vger.kernel.org
Cc: amwang@redhat.com, rdunlap@xenotime.net, andi@firstfloor.org,
	aravinda@linux.vnet.ibm.com, hch@lst.de, mhiramat@redhat.com,
	jeremy.fitzhardinge@citrix.com, xemul@parallels.com,
	suzuki@linux.vnet.ibm.com, kosaki.motohiro@jp.fujitsu.com,
	adobriyan@gmail.com, tarundsk@linux.vnet.ibm.com,
	vapier@gentoo.org, roland@hack.frob.com, tj@kernel.org,
	ananth@linux.vnet.ibm.com, gorcunov@openvz.org,
	avagin@openvz.org, oleg@redhat.com, eparis@redhat.com,
	d.hatayama@jp.fujitsu.com, james.hogan@imgtec.com,
	akpm@linux-foundation.org, torvalds@linux-foundation.org
Subject: [PATCH 14/19] Create ELF Core notes Data
Date: Fri, 04 Oct 2013 16:02:21 +0530	[thread overview]
Message-ID: <20131004103221.1612.11297.stgit@f19-x64> (raw)
In-Reply-To: <20131004102532.1612.24185.stgit@f19-x64>

From:Suzuki K. Poulose <suzuki@in.ibm.com>

Collect the PT_NOTE information for the core.

There are two "process wide" notes. NT_PRPSINFO and NT_AUXV. These are captured
in the core_proc structure.

Each thread gets a NT_PRSTATUS note, which will contain the GPR contents. A
thread may have additional notes depending on the other register sets used by it.
Uses struct elf_thread_core_info to capture the thread specific information.

fill_thread_core_info() fills in the notes for a thread.

Signed-off-by: Suzuki K. Poulose <suzuki@in.ibm.com>
Signed-off-by: Ananth N. Mavinakayanahalli <ananth@in.ibm.com>
---
 fs/proc/gencore-elf.c |  180 ++++++++++++++++++++++++++++++++++++++++++++++++-
 fs/proc/gencore.c     |   56 +++++++++++++++
 fs/proc/gencore.h     |   28 ++++++++
 3 files changed, 260 insertions(+), 4 deletions(-)

diff --git a/fs/proc/gencore-elf.c b/fs/proc/gencore-elf.c
index 0a245f0..6e97f6a 100644
--- a/fs/proc/gencore-elf.c
+++ b/fs/proc/gencore-elf.c
@@ -34,6 +34,157 @@
 
 #include "gencore.h"
 
+static int notesize(struct memelfnote *men)
+{
+	int size = sizeof(struct elf_note);
+
+	size += roundup(strlen(men->name) + 1, 4);
+	size += roundup(men->datasz, 4);
+
+	return size;
+}
+
+/* Store the note in the header buffer */
+static char *storenote(struct memelfnote *men, char *bufp)
+{
+	struct elf_note *en = (struct elf_note *)bufp;
+
+	en->n_namesz = strlen(men->name) + 1;
+	en->n_descsz = men->datasz;
+	en->n_type = men->type;
+	bufp = (char *) (en + 1);
+
+	memcpy(bufp, men->name, en->n_namesz);
+	bufp = (char *) roundup((unsigned long)bufp + en->n_namesz, 4);
+
+	memcpy(bufp, men->data, men->datasz);
+	bufp = (char *) roundup((unsigned long)bufp + men->datasz, 4);
+
+	return bufp;
+}
+
+#ifdef CORE_DUMP_USE_REGSET
+static void do_thread_regset_writeback(struct task_struct *task,
+				const struct user_regset *regset)
+{
+	if (regset->writeback)
+		regset->writeback(task, regset, 1);
+}
+
+static int fill_thread_core_info(struct elf_thread_core_info *tinfo,
+					struct core_proc *cp)
+{
+	unsigned int i;
+	const struct user_regset_view *view = task_user_regset_view(tinfo->task);
+
+	fill_prstatus(&tinfo->prstatus, tinfo->task, 0);
+
+	do_thread_regset_writeback(tinfo->task, &view->regsets[0]);
+	(void) view->regsets[0].get(tinfo->task, &view->regsets[0],
+				0, sizeof(tinfo->prstatus.pr_reg),
+				&tinfo->prstatus.pr_reg, NULL);
+	fill_note(&tinfo->notes[0], "CORE", NT_PRSTATUS,
+			sizeof(tinfo->prstatus), &tinfo->prstatus);
+	cp->notes_size += notesize(&tinfo->notes[0]);
+	tinfo->num_notes = view->n;
+
+	for (i = 1; i < view->n; i++) {
+		const struct user_regset *regset = &view->regsets[i];
+
+		do_thread_regset_writeback(tinfo->task, regset);
+		if (regset->core_note_type &&
+			(!regset->active || regset->active(tinfo->task, regset))) {
+			int ret;
+			size_t size = regset->n * regset->size;
+			void *data = kzalloc(size, GFP_KERNEL);
+			if (!unlikely(data))
+				return 0;
+			ret = regset->get(tinfo->task, regset,
+					0, size, data, NULL);
+			if (unlikely(ret))
+				kfree(data);
+			else {
+				if (regset->core_note_type != NT_PRFPREG)
+					fill_note(&tinfo->notes[i], "LINUX",
+						regset->core_note_type,
+						size, data);
+				else {
+					tinfo->prstatus.pr_fpvalid = 1;
+					fill_note(&tinfo->notes[i], "CORE",
+						NT_PRFPREG, size, data);
+				}
+				cp->notes_size += notesize(&tinfo->notes[i]);
+			}
+		}
+	}
+	return 1;
+}
+#else
+static int fill_thread_core_info(struct elf_thread_core_info *tinfo,
+					struct core_proc *cp)
+{
+	elf_fpregset_t fpu, *pfpu;
+#ifdef ELF_CORE_COPY_XFPREGS
+	elf_fpxregset_t xfpu, *pxfpu;
+#endif
+
+	fill_prstatus(&tinfo->prstatus, t->task, 0);
+	elf_core_copy_task_regs(t->task, &tinfo->prstatus.pr_reg);
+	fill_note(&tinfo->notes[0], "CORE", NT_PRSTATUS,
+			sizeof(t->prstatus), &t->prstatus);
+	cp->notes_size += notesize(&tinfo->notes[0]);
+	tinfo->num_notes = 1;
+
+	if (tinfo->prstatus.pr_fpvalid = elf_core_copy_task_fpregs(tinfo->task,
+							NULL, &fpu)) {
+		pfpu = kzalloc(sizeof(*pfpu), GFP_KERNEL);
+		if (pfpu == NULL)
+			return 0;
+		memcpy(pfpu, &fpu, sizeof(fpu));
+		fill_note(&tinfo->notes[tinfo->num_notes], "CORE", NT_PRFPREG,
+				sizeof(*pfpu), pfpu);
+		cp->notes_size += notesize(&tinfo->notes[tinfo->num_notes]);
+		tinfo->num_notes++;
+	}
+#ifdef ELF_CORE_COPY_XFPREGS
+	if (elf_core_copy_task_xfpregs(tinfo->task, &xfpu)) {
+		pxfpu = kzalloc(sizeof(*pxfpu), GFP_KERNEL);
+		if (!pxfpu)
+			return 0;
+		memcpy(pxfpu, &xfpu, sizeof(xfpu));
+		fill_note(&tinfo->notes[tinfo->num_notes], "LINUX",
+			ELF_CORE_XFPREG_TYPE, sizeof(*pxfpu), pxfpu);
+		cp->notes_size += notesize(&tinfo->notes[tinfo->num_notes]);
+		tinfo->num_notes++;
+	}
+#endif
+	return 1;
+}
+#endif
+
+/* Returns 0 on error, 1 on success */
+static int collect_notes(struct core_proc *cp)
+{
+	struct elf_thread_core_info *tinfo;
+
+	/* Fill the 2 process wide notes */
+	fill_psinfo(&cp->prpsinfo, cp->task, cp->task->mm);
+	fill_note(&cp->psinfo, "CORE", NT_PRPSINFO,
+			sizeof(struct elf_prpsinfo), &cp->prpsinfo);
+	cp->notes_size += notesize(&cp->psinfo);
+
+	fill_auxv_note(&cp->auxv, cp->task->mm);
+	cp->notes_size += notesize(&cp->auxv);
+
+	tinfo = cp->tinfo;
+	while (tinfo != NULL) {
+		if (!fill_thread_core_info(tinfo, cp))
+			return 0;
+		tinfo = tinfo->next;
+	}
+	return 1;
+}
+
 static void get_elfhdr_size(struct core_proc *cp)
 {
 	struct vm_area_struct *gate_vma;
@@ -51,7 +202,7 @@ static void get_elfhdr_size(struct core_proc *cp)
 
 	cp->nphdrs = segs;
 	cp->elf_buflen = sizeof(struct elfhdr) +
-			(cp->nphdrs * sizeof(struct elf_phdr));
+			(cp->nphdrs * sizeof(struct elf_phdr)) + cp->notes_size;
 	cp->elf_buflen = roundup(cp->elf_buflen, ELF_EXEC_PAGESIZE);
 
 	return;
@@ -66,11 +217,13 @@ static int create_elf_header(struct core_proc *cp)
 	struct elfhdr *elf = (struct elfhdr *)cp->elf_buf;
 	struct elf_phdr *note;
 	struct vm_area_struct *vma, *gate_vma = get_gate_vma(cp->task->mm);
+	struct elf_thread_core_info *tinfo;
 	char *bufp;
 	off_t dataoff, offset;
 	short e_phnum = (cp->nphdrs > PN_XNUM ? PN_XNUM : cp->nphdrs);
 	size_t exphdrs_sz = 0;
 	unsigned long limit = elf_core_extra_phdrs() * sizeof(struct elf_phdr);
+	int first = 1;
 
 #ifdef CORE_DUMP_USE_REGSET
 	const struct user_regset_view *view = task_user_regset_view(cp->task);
@@ -91,7 +244,7 @@ static int create_elf_header(struct core_proc *cp)
 	note->p_offset = dataoff;
 	note->p_vaddr = 0;
 	note->p_paddr = 0;
-	/* TODO: Needs to be populated with the size of the notes section */
+	note->p_filesz = cp->notes_size;
 	note->p_memsz = 0;
 	note->p_flags = 0;
 	note->p_align = 0;
@@ -138,6 +291,22 @@ static int create_elf_header(struct core_proc *cp)
 						dataoff, cp->nphdrs);
 		dataoff += sizeof(struct elf_shdr);
 	}
+	/* Store the notes */
+	tinfo = cp->tinfo;
+	do {
+		int i;
+
+		bufp = storenote(&tinfo->notes[0], bufp);
+		if (first) {
+			bufp = storenote(&cp->psinfo, bufp);
+			bufp = storenote(&cp->auxv, bufp);
+		}
+		for (i = 1; i < tinfo->num_notes; i++)
+			if (tinfo->notes[i].data != NULL)
+				bufp = storenote(&tinfo->notes[i], bufp);
+		first = 0;
+		tinfo = tinfo->next;
+	} while (tinfo != NULL);
 
 	return 0;
 }
@@ -147,6 +316,13 @@ ssize_t elf_read_gencore(struct core_proc *cp, char __user *buffer,
 {
 	ssize_t ret = 0;
 
+	if (!cp->notes_size) {
+		if (!collect_notes(cp)) {
+			ret = -ENOMEM;
+			goto out;
+		}
+	}
+
 	if (!cp->elf_buf) {
 		get_elfhdr_size(cp);
 
diff --git a/fs/proc/gencore.c b/fs/proc/gencore.c
index d741f18..463bedd 100644
--- a/fs/proc/gencore.c
+++ b/fs/proc/gencore.c
@@ -29,7 +29,7 @@
 #include <linux/slab.h>
 #include "internal.h"
 #include "gencore.h"
-
+#include <linux/sched.h>
 static LIST_HEAD(core_list);
 static DEFINE_MUTEX(core_mutex);
 
@@ -69,6 +69,39 @@ out:
 	return ret;
 }
 
+static void free_notes_data(struct elf_thread_core_info *tinfo)
+{
+	int i;
+
+	for (i = 1; i < tinfo->num_notes; i++)
+		if (tinfo->notes[i].data) {
+			kfree(tinfo->notes[i].data);
+			tinfo->notes[i].data = NULL;
+		}
+}
+
+static void cleanup_cp(struct core_proc *cp)
+{
+	struct elf_thread_core_info *tmp, *tinfo = cp->tinfo;
+
+	mutex_lock(&core_mutex);
+	list_del(&cp->list);
+	mutex_unlock(&core_mutex);
+
+	if (tinfo) {
+		do {
+			tmp = tinfo;
+			tinfo = tinfo->next;
+			free_notes_data(tmp);
+			kfree(tmp);
+		} while (tinfo != NULL);
+	}
+	if (cp->shdr)
+		kfree(cp->shdr);
+	kfree(cp->elf_buf);
+	kfree(cp);
+}
+
 static void gencore_work(struct callback_head *open_work)
 {
 	/* TODO A method to know when all the threads have reached here */ 
@@ -143,7 +176,8 @@ static int open_gencore(struct inode *inode, struct file *filp)
 	struct task_struct *task = get_proc_task(inode);
 	struct core_proc *cp;
 	struct task_struct *t;
-	int elf_class;
+	struct elf_thread_core_info *tinfo = NULL;
+	int elf_class, max_regset, i;
 	int ret = 0;
 	if (!task)
 		return -ENOENT;
@@ -171,12 +205,30 @@ static int open_gencore(struct inode *inode, struct file *filp)
 	mutex_lock(&core_mutex);
 	list_add(&cp->list, &core_list);
 	mutex_unlock(&core_mutex);
+	max_regset = get_max_regsets(task);
+
+	for (i = 0; i < get_nr_threads(task); i++) {
+		tinfo = kzalloc(offsetof(struct elf_thread_core_info,
+					notes[max_regset]), GFP_KERNEL);
+		if (unlikely(!tinfo)) {
+			cleanup_cp(cp);
+			ret = -ENOMEM;
+			goto out;
+		}
+		tinfo->next = cp->tinfo;
+		cp->tinfo = tinfo;
+	}
+
 	init_completion(&cp->hold);
 	/* Adding the work for all the threads except current */
 	t = cp->task;
 	init_task_work(&cp->twork, gencore_work);
 	read_lock(&tasklist_lock);
 	do {
+		if (tinfo) {
+			tinfo->task = t;
+			tinfo = tinfo->next;
+		}
 		if (t != current)
 			task_work_add(t, &cp->twork, true);
 	} while_each_thread(cp->task, t);
diff --git a/fs/proc/gencore.h b/fs/proc/gencore.h
index 6c1d57c..e508417 100644
--- a/fs/proc/gencore.h
+++ b/fs/proc/gencore.h
@@ -5,6 +5,16 @@
 #include <linux/list.h>
 #include <linux/sched.h>
 #include <linux/completion.h>
+#include <linux/elfcore.h>
+#include <linux/elfcore-internal.h>
+
+struct elf_thread_core_info {
+	unsigned short num_notes;       /* Number of notes for this thread */
+	struct elf_thread_core_info *next;
+	struct task_struct *task;
+	struct elf_prstatus prstatus;
+	struct memelfnote notes[0];
+};
 
 struct core_proc {
 	struct list_head list;
@@ -13,10 +23,28 @@ struct core_proc {
 	struct callback_head twork;
 	void *shdr;             /* elf_shdr, in case nphdrs > PN_XNUM */
 	char *elf_buf;          /* buffer for elf_hdr + phdrs + notes */
+	struct elf_thread_core_info *tinfo; 
+	struct memelfnote psinfo; 
+	struct memelfnote auxv;
+	struct elf_prpsinfo prpsinfo;
 	size_t elf_buflen;      /* size of elf_buf */
 	size_t nphdrs;          /* number of phdrs */
+	size_t notes_size;
 };
 
+#ifdef CORE_DUMP_USE_REGSET
+#include <linux/regset.h>
+
+static inline int  get_max_regsets(struct task_struct *task)
+{  
+	const struct user_regset_view *view = task_user_regset_view(task);
+	return view->n;
+}
+
+#else
+#define get_max_regsets(task)  3 /* GPR, FP, XFP? */
+#endif
+
 extern ssize_t elf_read_gencore(struct core_proc *cp, char __user *buffer,
 					size_t buflen, loff_t *foffset);
 


  parent reply	other threads:[~2013-10-04 10:32 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-10-04 10:30 [RFC] [PATCH 00/19] Non disruptive application core dump infrastructure using task_work_add() Janani Venkataraman
2013-10-04 10:30 ` [PATCH 01/19] Create elfcore-common.c for ELF class independent core generation helpers Janani Venkataraman
2013-10-04 10:30 ` [PATCH 02/19] Make vma_dump_size() generic Janani Venkataraman
2013-10-08  0:23   ` Ryan Mallon
2013-10-08  3:52     ` Janani Venkataraman1
2013-10-04 10:31 ` [PATCH 03/19] Make fill_psinfo generic Janani Venkataraman
2013-10-04 10:31 ` [PATCH 04/19] Rename compat versions of the reusable core generation routines Janani Venkataraman
2013-10-04 10:31 ` [PATCH 05/19] Export the reusable ELF " Janani Venkataraman
2013-10-04 10:31 ` [PATCH 06/19] Define API for reading arch specif Program Headers for Core Janani Venkataraman
2013-10-04 10:31 ` [PATCH 07/19] ia64 impelementation for elf_core_copy_extra_phdrs() Janani Venkataraman
2013-10-04 10:31 ` [PATCH 08/19] elf_core_copy_extra_phdrs() for UML Janani Venkataraman
2013-10-04 10:31 ` [PATCH 09/19] Create /proc/pid/core entry Janani Venkataraman
2013-10-04 10:31 ` [PATCH 10/19] Track the core generation requests Janani Venkataraman
2013-10-04 10:31 ` [PATCH 11/19] Check if the process is an ELF executable Janani Venkataraman
2013-10-04 10:32 ` [PATCH 12/19] Hold the threads using task_work_add Janani Venkataraman
2013-10-04 10:32 ` [PATCH 13/19] Create ELF Header Janani Venkataraman
2013-10-04 10:32 ` Janani Venkataraman [this message]
2013-10-04 10:32 ` [PATCH 15/19] Calculate the size of the core file Janani Venkataraman
2013-10-04 10:32 ` [PATCH 16/19] Generate the data sections for ELF Core Janani Venkataraman
2013-10-04 10:32 ` [PATCH 17/19] Identify the ELF class of the process Janani Venkataraman
2013-10-04 10:33 ` [PATCH 18/19] Adding support for compat ELF class data structures Janani Venkataraman
2013-10-04 10:33 ` [PATCH 19/19] Compat ELF class core generation support Janani Venkataraman
2013-10-04 10:38 ` [RFC] [PATCH 00/19] Non disruptive application core dump infrastructure using task_work_add() Pavel Emelyanov
2013-10-07 18:57   ` Tejun Heo
2013-10-08 10:14     ` Janani Venkataraman1
2013-10-08 10:12   ` Janani Venkataraman1
2013-10-09  8:57     ` Pavel Emelyanov
2013-10-04 13:44 ` Andi Kleen
2013-10-07  6:07   ` Suzuki K. Poulose
2013-10-07 13:58     ` Oleg Nesterov
2013-10-07 18:10     ` Andi Kleen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20131004103221.1612.11297.stgit@f19-x64 \
    --to=jananive@in.ibm.com \
    --cc=adobriyan@gmail.com \
    --cc=akpm@linux-foundation.org \
    --cc=amwang@redhat.com \
    --cc=ananth@linux.vnet.ibm.com \
    --cc=andi@firstfloor.org \
    --cc=aravinda@linux.vnet.ibm.com \
    --cc=avagin@openvz.org \
    --cc=d.hatayama@jp.fujitsu.com \
    --cc=eparis@redhat.com \
    --cc=gorcunov@openvz.org \
    --cc=hch@lst.de \
    --cc=james.hogan@imgtec.com \
    --cc=jeremy.fitzhardinge@citrix.com \
    --cc=kosaki.motohiro@jp.fujitsu.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mhiramat@redhat.com \
    --cc=oleg@redhat.com \
    --cc=rdunlap@xenotime.net \
    --cc=roland@hack.frob.com \
    --cc=suzuki@linux.vnet.ibm.com \
    --cc=tarundsk@linux.vnet.ibm.com \
    --cc=tj@kernel.org \
    --cc=torvalds@linux-foundation.org \
    --cc=vapier@gentoo.org \
    --cc=xemul@parallels.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.