PERFORCE change 49851 for review

Marcel Moolenaar marcel at FreeBSD.org
Sun Mar 28 14:44:42 PST 2004


http://perforce.freebsd.org/chv.cgi?CH=49851

Change 49851 by marcel at marcel_nfs on 2004/03/28 14:44:06

	Fix coredumps for multi-threaded applications that use 1:1 or
	M:N threading. When multiple kernel threads exist in a process,
	we want to dump the context of each thread so that the debugger
	has a chance to figure out where each of the bound or system
	scoped threads was and libthread_db has a chance to map user
	threads to system threads (if applicable).
	
	This change is dependent on kernel threads having IDs.

Affected files ...

.. //depot/projects/gdb/sys/kern/imgact_elf.c#4 edit

Differences ...

==== //depot/projects/gdb/sys/kern/imgact_elf.c#4 (text+ko) ====

@@ -922,8 +922,7 @@
 static void each_writable_segment(struct proc *, segment_callback, void *);
 static int __elfN(corehdr)(struct thread *, struct vnode *, struct ucred *,
     int, void *, size_t);
-static void __elfN(puthdr)(struct proc *, void *, size_t *,
-    const prstatus_t *, const prfpregset_t *, const prpsinfo_t *, int);
+static void __elfN(puthdr)(struct proc *, void *, size_t *, int);
 static void __elfN(putnote)(void *, size_t *, const char *, int,
     const void *, size_t);
 
@@ -953,9 +952,7 @@
 	 * size is calculated.
 	 */
 	hdrsize = 0;
-	__elfN(puthdr)((struct proc *)NULL, (void *)NULL, &hdrsize,
-	    (const prstatus_t *)NULL, (const prfpregset_t *)NULL,
-	    (const prpsinfo_t *)NULL, seginfo.count);
+	__elfN(puthdr)(p, (void *)NULL, &hdrsize, seginfo.count);
 
 	if (hdrsize + seginfo.size >= limit)
 		return (EFAULT);
@@ -1115,48 +1112,14 @@
 	size_t hdrsize;
 	void *hdr;
 {
-	struct {
-		prstatus_t status;
-		prfpregset_t fpregset;
-		prpsinfo_t psinfo;
-	} *tempdata;
 	struct proc *p = td->td_proc;
 	size_t off;
-	prstatus_t *status;
-	prfpregset_t *fpregset;
-	prpsinfo_t *psinfo;
-
-	tempdata = malloc(sizeof(*tempdata), M_TEMP, M_ZERO | M_WAITOK);
-	status = &tempdata->status;
-	fpregset = &tempdata->fpregset;
-	psinfo = &tempdata->psinfo;
-
-	/* Gather the information for the header. */
-	status->pr_version = PRSTATUS_VERSION;
-	status->pr_statussz = sizeof(prstatus_t);
-	status->pr_gregsetsz = sizeof(gregset_t);
-	status->pr_fpregsetsz = sizeof(fpregset_t);
-	status->pr_osreldate = osreldate;
-	status->pr_cursig = p->p_sig;
-	status->pr_pid = p->p_pid;
-	fill_regs(td, &status->pr_reg);
 
-	fill_fpregs(td, fpregset);
-
-	psinfo->pr_version = PRPSINFO_VERSION;
-	psinfo->pr_psinfosz = sizeof(prpsinfo_t);
-	strlcpy(psinfo->pr_fname, p->p_comm, sizeof(psinfo->pr_fname));
-
-	/* XXX - We don't fill in the command line arguments properly yet. */
-	strlcpy(psinfo->pr_psargs, p->p_comm, sizeof(psinfo->pr_psargs));
-
 	/* Fill in the header. */
 	bzero(hdr, hdrsize);
 	off = 0;
-	__elfN(puthdr)(p, hdr, &off, status, fpregset, psinfo, numsegs);
+	__elfN(puthdr)(p, hdr, &off, numsegs);
 
-	free(tempdata, M_TEMP);
-
 	/* Write it to the core file. */
 	return (vn_rdwr_inchunks(UIO_WRITE, vp, hdr, hdrsize, (off_t)0,
 	    UIO_SYSSPACE, IO_UNIT | IO_DIRECT, cred, NOCRED, NULL,
@@ -1164,13 +1127,18 @@
 }
 
 static void
-__elfN(puthdr)(struct proc *p, void *dst, size_t *off, const prstatus_t *status,
-    const prfpregset_t *fpregset, const prpsinfo_t *psinfo, int numsegs)
+__elfN(puthdr)(struct proc *p, void *dst, size_t *off, int numsegs)
 {
-	size_t ehoff;
-	size_t phoff;
-	size_t noteoff;
-	size_t notesz;
+	struct {
+		prstatus_t status;
+		prfpregset_t fpregset;
+		prpsinfo_t psinfo;
+	} *tempdata;
+	prstatus_t *status;
+	prfpregset_t *fpregset;
+	prpsinfo_t *psinfo;
+	struct thread *thr;
+	size_t ehoff, noteoff, notesz, phoff;
 
 	ehoff = *off;
 	*off += sizeof(Elf_Ehdr);
@@ -1179,14 +1147,64 @@
 	*off += (numsegs + 1) * sizeof(Elf_Phdr);
 
 	noteoff = *off;
-	__elfN(putnote)(dst, off, "FreeBSD", NT_PRSTATUS, status,
-	    sizeof *status);
-	__elfN(putnote)(dst, off, "FreeBSD", NT_FPREGSET, fpregset,
-	    sizeof *fpregset);
+	/*
+	 * Don't allocate space for the notes if we're just calculating
+	 * the size of the header. We also don't collect the data.
+	 */
+	if (dst != NULL) {
+		tempdata = malloc(sizeof(*tempdata), M_TEMP, M_ZERO|M_WAITOK);
+		status = &tempdata->status;
+		fpregset = &tempdata->fpregset;
+		psinfo = &tempdata->psinfo;
+	} else {
+		tempdata = NULL;
+		status = NULL;
+		fpregset = NULL;
+		psinfo = NULL;
+	}
+
+	if (dst != NULL) {
+		psinfo->pr_version = PRPSINFO_VERSION;
+		psinfo->pr_psinfosz = sizeof(prpsinfo_t);
+		strlcpy(psinfo->pr_fname, p->p_comm, sizeof(psinfo->pr_fname));
+		/*
+		 * XXX - We don't fill in the command line arguments properly
+		 * yet.
+		 */
+		strlcpy(psinfo->pr_psargs, p->p_comm,
+		    sizeof(psinfo->pr_psargs));
+	}
 	__elfN(putnote)(dst, off, "FreeBSD", NT_PRPSINFO, psinfo,
 	    sizeof *psinfo);
+
+	thr = TAILQ_FIRST(&p->p_threads);
+	while (thr != NULL) {
+		if (dst != NULL) {
+			status->pr_version = PRSTATUS_VERSION;
+			status->pr_statussz = sizeof(prstatus_t);
+			status->pr_gregsetsz = sizeof(gregset_t);
+			status->pr_fpregsetsz = sizeof(fpregset_t);
+			status->pr_osreldate = osreldate;
+			status->pr_cursig = p->p_sig;
+			status->pr_pid = thr->td_tid;
+			fill_regs(thr, &status->pr_reg);
+			fill_fpregs(thr, fpregset);
+		}
+		__elfN(putnote)(dst, off, "FreeBSD", NT_PRSTATUS, status,
+		    sizeof *status);
+		__elfN(putnote)(dst, off, "FreeBSD", NT_FPREGSET, fpregset,
+		    sizeof *fpregset);
+		/*
+		 * XXX allow for MD specific notes.
+		 */
+		thr = TAILQ_NEXT(thr, td_plist);
+	}
+
 	notesz = *off - noteoff;
 
+	if (dst != NULL)
+		free(tempdata, M_TEMP);
+
 	/* Align up to a page boundary for the program segments. */
 	*off = round_page(*off);
 


More information about the p4-projects mailing list