lkml.org 
[lkml]   [2002]   [Dec]   [16]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
SubjectRe: Multithreaded coredump patch where?
Date
I haven't rebased the patches I posted back in June for a while now.

Attached is the patch I posted for the 2.4.18 vanilla kernel. Its a bit
controversial, but it seems to work for a number of folks. Let me know if
you have any troubles re-basing it.

I don't know if there is any plan to back port Ingo's version of this feature
to 2.4.x

--mgross



On Monday 16 December 2002 09:28 am, Roberto Fichera wrote:
> Does anyone point me where can I download a stable
> multithread coredump patch for the 2.4.19/20 kernel ?
>
> Thanks in advance,
>
> Roberto Fichera.
>
>
> ______________________________________
> E-mail protetta dal servizio antivirus di IsolaWeb Agency & ISP
> http://wwww.isolaweb.it
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
diff -urN -X dontdiff linux-2.4.18/arch/i386/kernel/i387.c linux2418.tcore/arch/i386/kernel/i387.c
--- linux-2.4.18/arch/i386/kernel/i387.c Fri Feb 23 13:09:08 2001
+++ linux2418.tcore/arch/i386/kernel/i387.c Thu Jun 13 10:00:48 2002
@@ -520,3 +520,44 @@

return fpvalid;
}
+
+int dump_task_fpu( struct task_struct *tsk, struct user_i387_struct *fpu )
+{
+ int fpvalid;
+
+ fpvalid = tsk->used_math;
+ if ( fpvalid ) {
+ if (tsk == current) unlazy_fpu( tsk );
+ if ( cpu_has_fxsr ) {
+ copy_fpu_fxsave( tsk, fpu );
+ } else {
+ copy_fpu_fsave( tsk, fpu );
+ }
+ }
+
+ return fpvalid;
+}
+
+int dump_task_extended_fpu( struct task_struct *tsk, struct user_fxsr_struct *fpu )
+{
+ int fpvalid;
+
+ fpvalid = tsk->used_math && cpu_has_fxsr;
+ if ( fpvalid ) {
+ if (tsk == current) unlazy_fpu( tsk );
+ memcpy( fpu, &tsk->thread.i387.fxsave,
+ sizeof(struct user_fxsr_struct) );
+ }
+
+ return fpvalid;
+}
+
+
+#ifdef CONFIG_SMP
+void dump_smp_unlazy_fpu(void)
+{
+ unlazy_fpu(current);
+ return;
+}
+#endif
+
diff -urN -X dontdiff linux-2.4.18/arch/i386/kernel/process.c linux2418.tcore/arch/i386/kernel/process.c
--- linux-2.4.18/arch/i386/kernel/process.c Mon Feb 25 14:37:53 2002
+++ linux2418.tcore/arch/i386/kernel/process.c Thu Jun 13 10:00:48 2002
@@ -644,6 +644,24 @@

dump->u_fpvalid = dump_fpu (regs, &dump->i387);
}
+/*
+ * Capture the user space registers if the task is not running (in user space)
+ */
+#include <linux/elfcore.h>
+int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs)
+{
+ struct pt_regs ptregs;
+
+ ptregs = *(struct pt_regs *)((unsigned long)tsk + THREAD_SIZE - sizeof(struct pt_regs));
+ ptregs.xcs &= 0xffff;
+ ptregs.xds &= 0xffff;
+ ptregs.xes &= 0xffff;
+ ptregs.xss &= 0xffff;
+
+ elf_core_copy_regs(regs, &ptregs);
+
+ return 1;
+}

/*
* This special macro can be used to load a debugging register
diff -urN -X dontdiff linux-2.4.18/arch/ia64/kernel/process.c linux2418.tcore/arch/ia64/kernel/process.c
--- linux-2.4.18/arch/ia64/kernel/process.c Fri Nov 9 17:26:17 2001
+++ linux2418.tcore/arch/ia64/kernel/process.c Thu Jun 13 10:00:48 2002
@@ -298,6 +298,31 @@
void
do_copy_regs (struct unw_frame_info *info, void *arg)
{
+ do_copy_task_regs(current, info, arg);
+}
+
+void
+do_dump_fpu (struct unw_frame_info *info, void *arg)
+{
+ do_dump_task_fpu(current, info, arg);
+}
+
+void
+ia64_elf_core_copy_regs (struct pt_regs *pt, elf_gregset_t dst)
+{
+ unw_init_running(do_copy_regs, dst);
+}
+
+int
+dump_fpu (struct pt_regs *pt, elf_fpregset_t dst)
+{
+ unw_init_running(do_dump_fpu, dst);
+ return 1; /* f0-f31 are always valid so we always return 1 */
+}
+
+static void
+do_copy_task_regs (struct task_struct *task, struct unw_frame_info *info, void *arg)
+{
unsigned long mask, sp, nat_bits = 0, ip, ar_rnat, urbs_end, cfm;
elf_greg_t *dst = arg;
struct pt_regs *pt;
@@ -312,12 +337,12 @@
unw_get_sp(info, &sp);
pt = (struct pt_regs *) (sp + 16);

- urbs_end = ia64_get_user_rbs_end(current, pt, &cfm);
+ urbs_end = ia64_get_user_rbs_end(task, pt, &cfm);

- if (ia64_sync_user_rbs(current, info->sw, pt->ar_bspstore, urbs_end) < 0)
+ if (ia64_sync_user_rbs(task, info->sw, pt->ar_bspstore, urbs_end) < 0)
return;

- ia64_peek(current, info->sw, urbs_end, (long) ia64_rse_rnat_addr((long *) urbs_end),
+ ia64_peek(task, info->sw, urbs_end, (long) ia64_rse_rnat_addr((long *) urbs_end),
&ar_rnat);

/*
@@ -366,7 +391,7 @@
}

void
-do_dump_fpu (struct unw_frame_info *info, void *arg)
+do_dump_task_fpu (struct task_struct *task, struct unw_frame_info *info, void *arg)
{
elf_fpreg_t *dst = arg;
int i;
@@ -381,22 +406,41 @@
for (i = 2; i < 32; ++i)
unw_get_fr(info, i, dst + i);

- ia64_flush_fph(current);
- if ((current->thread.flags & IA64_THREAD_FPH_VALID) != 0)
- memcpy(dst + 32, current->thread.fph, 96*16);
+ ia64_flush_fph(task);
+ if ((task->thread.flags & IA64_THREAD_FPH_VALID) != 0)
+ memcpy(dst + 32, task->thread.fph, 96*16);
}

-void
-ia64_elf_core_copy_regs (struct pt_regs *pt, elf_gregset_t dst)
+int dump_task_regs(struct task_struct *task, elf_gregset_t *regs)
{
- unw_init_running(do_copy_regs, dst);
+ struct unw_frame_info tcore_info;
+
+ if(current == task) {
+ unw_init_running(do_copy_regs, regs);
+ }
+ else {
+ memset(&tcore_info, 0, sizeof(tcore_info));
+ unw_init_from_blocked_task(&tcore_info, task);
+ do_copy_task_regs(task, &tcore_info, regs);
+ }
+
+ return 1;
}

-int
-dump_fpu (struct pt_regs *pt, elf_fpregset_t dst)
+int dump_task_fpu (struct task_struct *task, elf_fpregset_t *dst)
{
- unw_init_running(do_dump_fpu, dst);
- return 1; /* f0-f31 are always valid so we always return 1 */
+ struct unw_frame_info tcore_info;
+
+ if(current == task) {
+ unw_init_running(do_dump_fpu, dst);
+ }
+ else {
+ memset(&tcore_info, 0, sizeof(tcore_info));
+ unw_init_from_blocked_task(&tcore_info, task);
+ do_dump_task_fpu(task, &tcore_info, dst);
+ }
+
+ return 1;
}

asmlinkage long
Binary files linux-2.4.18/core and linux2418.tcore/core differ
diff -urN -X dontdiff linux-2.4.18/fs/binfmt_elf.c linux2418.tcore/fs/binfmt_elf.c
--- linux-2.4.18/fs/binfmt_elf.c Mon Feb 25 14:38:08 2002
+++ linux2418.tcore/fs/binfmt_elf.c Tue Jun 18 10:00:13 2002
@@ -30,6 +30,7 @@
#include <linux/elfcore.h>
#include <linux/init.h>
#include <linux/highuid.h>
+#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/compiler.h>
#include <linux/highmem.h>
@@ -952,7 +953,7 @@
/* #define DEBUG */

#ifdef DEBUG
-static void dump_regs(const char *str, elf_greg_t *r)
+static void dump_regs(const char *str, elf_gregset_t *r)
{
int i;
static const char *regs[] = { "ebx", "ecx", "edx", "esi", "edi", "ebp",
@@ -1000,6 +1001,156 @@
#define DUMP_SEEK(off) \
if (!dump_seek(file, (off))) \
goto end_coredump;
+
+static inline void fill_elf_header(struct elfhdr *elf, int segs)
+{
+ memcpy(elf->e_ident, ELFMAG, SELFMAG);
+ elf->e_ident[EI_CLASS] = ELF_CLASS;
+ elf->e_ident[EI_DATA] = ELF_DATA;
+ elf->e_ident[EI_VERSION] = EV_CURRENT;
+ memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
+
+ elf->e_type = ET_CORE;
+ elf->e_machine = ELF_ARCH;
+ elf->e_version = EV_CURRENT;
+ elf->e_entry = 0;
+ elf->e_phoff = sizeof(struct elfhdr);
+ elf->e_shoff = 0;
+ elf->e_flags = 0;
+ elf->e_ehsize = sizeof(struct elfhdr);
+ elf->e_phentsize = sizeof(struct elf_phdr);
+ elf->e_phnum = segs;
+ elf->e_shentsize = 0;
+ elf->e_shnum = 0;
+ elf->e_shstrndx = 0;
+ return;
+}
+
+static inline void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, off_t offset)
+{
+ phdr->p_type = PT_NOTE;
+ phdr->p_offset = offset;
+ phdr->p_vaddr = 0;
+ phdr->p_paddr = 0;
+ phdr->p_filesz = sz;
+ phdr->p_memsz = 0;
+ phdr->p_flags = 0;
+ phdr->p_align = 0;
+ return;
+}
+
+static inline void fill_note(struct memelfnote *note, const char *name, int type,
+ unsigned int sz, void *data)
+{
+ note->name = name;
+ note->type = type;
+ note->datasz = sz;
+ note->data = data;
+ return;
+}
+
+/*
+ * fill up all the fields in prstatus from the given task struct, except registers
+ * which need to be filled up seperately.
+ */
+static inline void fill_prstatus(struct elf_prstatus *prstatus, struct task_struct *p, long signr)
+{
+ prstatus->pr_info.si_signo = prstatus->pr_cursig = signr;
+ prstatus->pr_sigpend = p->pending.signal.sig[0];
+ prstatus->pr_sighold = p->blocked.sig[0];
+ prstatus->pr_pid = p->pid;
+ prstatus->pr_ppid = p->p_pptr->pid;
+ prstatus->pr_pgrp = p->pgrp;
+ prstatus->pr_sid = p->session;
+ prstatus->pr_utime.tv_sec = CT_TO_SECS(p->times.tms_utime);
+ prstatus->pr_utime.tv_usec = CT_TO_USECS(p->times.tms_utime);
+ prstatus->pr_stime.tv_sec = CT_TO_SECS(p->times.tms_stime);
+ prstatus->pr_stime.tv_usec = CT_TO_USECS(p->times.tms_stime);
+ prstatus->pr_cutime.tv_sec = CT_TO_SECS(p->times.tms_cutime);
+ prstatus->pr_cutime.tv_usec = CT_TO_USECS(p->times.tms_cutime);
+ prstatus->pr_cstime.tv_sec = CT_TO_SECS(p->times.tms_cstime);
+ prstatus->pr_cstime.tv_usec = CT_TO_USECS(p->times.tms_cstime);
+ return;
+}
+
+static inline void fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p)
+{
+ int i;
+
+ psinfo->pr_pid = p->pid;
+ psinfo->pr_ppid = p->p_pptr->pid;
+ psinfo->pr_pgrp = p->pgrp;
+ psinfo->pr_sid = p->session;
+
+ i = p->state ? ffz(~p->state) + 1 : 0;
+ psinfo->pr_state = i;
+ psinfo->pr_sname = (i < 0 || i > 5) ? '.' : "RSDZTD"[i];
+ psinfo->pr_zomb = psinfo->pr_sname == 'Z';
+ psinfo->pr_nice = p->nice;
+ psinfo->pr_flag = p->flags;
+ psinfo->pr_uid = NEW_TO_OLD_UID(p->uid);
+ psinfo->pr_gid = NEW_TO_OLD_GID(p->gid);
+ strncpy(psinfo->pr_fname, p->comm, sizeof(psinfo->pr_fname));
+ return;
+}
+
+/* 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 */
+#ifdef ELF_CORE_COPY_XFPREGS
+ elf_fpxregset_t xfpu; /* NT_PRXFPREG */
+#endif
+ 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 task_struct * p, struct list_head * thread_list)
+{
+
+ struct elf_thread_status *t;
+ int sz = 0;
+
+ t = kmalloc(sizeof(*t), GFP_KERNEL);
+ if (!t) {
+ printk(KERN_WARNING "Cannot allocate memory for thread status.\n");
+ return 0;
+ }
+
+ INIT_LIST_HEAD(&t->list);
+ t->num_notes = 0;
+
+ fill_prstatus(&t->prstatus, 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, &t->fpu))) {
+ fill_note(&t->notes[1], "CORE", NT_PRFPREG, sizeof(t->fpu), &(t->fpu));
+ 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", NT_PRXFPREG, sizeof(t->xfpu), &(t->xfpu));
+ t->num_notes++;
+ sz += notesize(&t->notes[2]);
+ }
+#endif
+ list_add(&t->list, thread_list);
+ return sz;
+}
+
/*
* Actual dumper
*
@@ -1018,12 +1169,23 @@
struct elfhdr elf;
off_t offset = 0, dataoff;
unsigned long limit = current->rlim[RLIMIT_CORE].rlim_cur;
- int numnote = 4;
- struct memelfnote notes[4];
+ int numnote = 5;
+ struct memelfnote notes[5];
struct elf_prstatus prstatus; /* NT_PRSTATUS */
- elf_fpregset_t fpu; /* NT_PRFPREG */
struct elf_prpsinfo psinfo; /* NT_PRPSINFO */
+ struct task_struct *p;
+ LIST_HEAD(thread_list);
+ struct list_head *t;
+ elf_fpregset_t fpu;
+#ifdef ELF_CORE_COPY_XFPREGS
+ elf_fpxregset_t xfpu;
+#endif
+ int thread_status_size = 0;
+

+ /* First pause all related threaded processes */
+ tcore_suspend_threads();
+
/* first copy the parameters from user space */
memset(&psinfo, 0, sizeof(psinfo));
{
@@ -1041,51 +1203,50 @@

}

- memset(&prstatus, 0, sizeof(prstatus));
- /*
- * This transfers the registers from regs into the standard
- * coredump arrangement, whatever that is.
- */
-#ifdef ELF_CORE_COPY_REGS
- ELF_CORE_COPY_REGS(prstatus.pr_reg, regs)
-#else
- if (sizeof(elf_gregset_t) != sizeof(struct pt_regs))
- {
- printk("sizeof(elf_gregset_t) (%ld) != sizeof(struct pt_regs) (%ld)\n",
- (long)sizeof(elf_gregset_t), (long)sizeof(struct pt_regs));
+ /* capture the status of all other threads */
+ if (signr) {
+ read_lock(&tasklist_lock);
+ for_each_task(p)
+ if (current->mm == p->mm && current != p) {
+ int sz = elf_dump_thread_status(signr, p, &thread_list);
+ if (!sz) {
+ read_unlock(&tasklist_lock);
+ goto cleanup;
+ }
+ else
+ thread_status_size += sz;
+ }
+ read_unlock(&tasklist_lock);
}
- else
- *(struct pt_regs *)&prstatus.pr_reg = *regs;
-#endif

- /* now stop all vm operations */
- down_write(&current->mm->mmap_sem);
- segs = current->mm->map_count;
+ /* now capture current's thread state */
+ memset(&prstatus, 0, sizeof(prstatus));
+ fill_prstatus(&prstatus, current, signr);
+ elf_core_copy_regs(&prstatus.pr_reg, regs);
+
+ /* We no longer stop all vm operations */
+
+ /* This because those proceses that could possibly
+ * change map_count or the mmap / vma pages are now suspended.
+ *
+ * Only ptrace can touch these memory address, but it cannot change
+ * the map_count or the pages. So no possibility of crashing exists while dumping
+ * the mm->vm_next areas to the core file.
+ *
+ * Grabbing mmap_sem in this function is risky WRT the use of suspend_threads.
+ * Although no locks ups have been induced, if one of the suspended threads was
+ * in line for the current->mmap_sem and if gets it while on the Phantom runque,
+ * then we would dead lock in this function if we continue to attempt to down_write
+ * in this function.
+ */
+ segs = current->mm->map_count;

#ifdef DEBUG
printk("elf_core_dump: %d segs %lu limit\n", segs, limit);
#endif

/* Set up header */
- memcpy(elf.e_ident, ELFMAG, SELFMAG);
- elf.e_ident[EI_CLASS] = ELF_CLASS;
- elf.e_ident[EI_DATA] = ELF_DATA;
- elf.e_ident[EI_VERSION] = EV_CURRENT;
- memset(elf.e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
-
- elf.e_type = ET_CORE;
- elf.e_machine = ELF_ARCH;
- elf.e_version = EV_CURRENT;
- elf.e_entry = 0;
- elf.e_phoff = sizeof(elf);
- elf.e_shoff = 0;
- elf.e_flags = 0;
- elf.e_ehsize = sizeof(elf);
- elf.e_phentsize = sizeof(struct elf_phdr);
- elf.e_phnum = segs+1; /* Include notes */
- elf.e_shentsize = 0;
- elf.e_shnum = 0;
- elf.e_shstrndx = 0;
+ fill_elf_header(&elf, segs+1); /* including notes section*/

fs = get_fs();
set_fs(KERNEL_DS);
@@ -1102,64 +1263,34 @@
* with info from their /proc.
*/

- notes[0].name = "CORE";
- notes[0].type = NT_PRSTATUS;
- notes[0].datasz = sizeof(prstatus);
- notes[0].data = &prstatus;
- prstatus.pr_info.si_signo = prstatus.pr_cursig = signr;
- prstatus.pr_sigpend = current->pending.signal.sig[0];
- prstatus.pr_sighold = current->blocked.sig[0];
- psinfo.pr_pid = prstatus.pr_pid = current->pid;
- psinfo.pr_ppid = prstatus.pr_ppid = current->p_pptr->pid;
- psinfo.pr_pgrp = prstatus.pr_pgrp = current->pgrp;
- psinfo.pr_sid = prstatus.pr_sid = current->session;
- prstatus.pr_utime.tv_sec = CT_TO_SECS(current->times.tms_utime);
- prstatus.pr_utime.tv_usec = CT_TO_USECS(current->times.tms_utime);
- prstatus.pr_stime.tv_sec = CT_TO_SECS(current->times.tms_stime);
- prstatus.pr_stime.tv_usec = CT_TO_USECS(current->times.tms_stime);
- prstatus.pr_cutime.tv_sec = CT_TO_SECS(current->times.tms_cutime);
- prstatus.pr_cutime.tv_usec = CT_TO_USECS(current->times.tms_cutime);
- prstatus.pr_cstime.tv_sec = CT_TO_SECS(current->times.tms_cstime);
- prstatus.pr_cstime.tv_usec = CT_TO_USECS(current->times.tms_cstime);
-
#ifdef DEBUG
dump_regs("Passed in regs", (elf_greg_t *)regs);
dump_regs("prstatus regs", (elf_greg_t *)&prstatus.pr_reg);
#endif

- notes[1].name = "CORE";
- notes[1].type = NT_PRPSINFO;
- notes[1].datasz = sizeof(psinfo);
- notes[1].data = &psinfo;
- i = current->state ? ffz(~current->state) + 1 : 0;
- psinfo.pr_state = i;
- psinfo.pr_sname = (i < 0 || i > 5) ? '.' : "RSDZTD"[i];
- psinfo.pr_zomb = psinfo.pr_sname == 'Z';
- psinfo.pr_nice = current->nice;
- psinfo.pr_flag = current->flags;
- psinfo.pr_uid = NEW_TO_OLD_UID(current->uid);
- psinfo.pr_gid = NEW_TO_OLD_GID(current->gid);
- strncpy(psinfo.pr_fname, current->comm, sizeof(psinfo.pr_fname));
-
- notes[2].name = "CORE";
- notes[2].type = NT_TASKSTRUCT;
- notes[2].datasz = sizeof(*current);
- notes[2].data = current;
-
- /* Try to dump the FPU. */
- prstatus.pr_fpvalid = dump_fpu (regs, &fpu);
- if (!prstatus.pr_fpvalid)
- {
- numnote--;
- }
- else
- {
- notes[3].name = "CORE";
- notes[3].type = NT_PRFPREG;
- notes[3].datasz = sizeof(fpu);
- notes[3].data = &fpu;
- }
+ fill_note(&notes[0], "CORE", NT_PRSTATUS, sizeof(prstatus), &prstatus);

+ fill_psinfo(&psinfo, current);
+ fill_note(&notes[1], "CORE", NT_PRPSINFO, sizeof(psinfo), &psinfo);
+
+ fill_note(&notes[2], "CORE", NT_TASKSTRUCT, sizeof(*current), current);
+
+ /* Try to dump the FPU. */
+ if ((prstatus.pr_fpvalid = elf_core_copy_task_fpregs(current, &fpu))) {
+ fill_note(&notes[3], "CORE", NT_PRFPREG, sizeof(fpu), &fpu);
+ } else {
+ --numnote;
+ }
+#ifdef ELF_CORE_COPY_XFPREGS
+ if (elf_core_copy_task_xfpregs(current, &xfpu)) {
+ fill_note(&notes[4], "LINUX", NT_PRXFPREG, sizeof(xfpu), &xfpu);
+ } else {
+ --numnote;
+ }
+#else
+ numnote --;
+#endif
+
/* Write notes phdr entry */
{
struct elf_phdr phdr;
@@ -1167,17 +1298,11 @@

for(i = 0; i < numnote; i++)
sz += notesize(&notes[i]);
+
+ sz += thread_status_size;

- phdr.p_type = PT_NOTE;
- phdr.p_offset = offset;
- phdr.p_vaddr = 0;
- phdr.p_paddr = 0;
- phdr.p_filesz = sz;
- phdr.p_memsz = 0;
- phdr.p_flags = 0;
- phdr.p_align = 0;
-
- offset += phdr.p_filesz;
+ fill_elf_note_phdr(&phdr, sz, offset);
+ offset += sz;
DUMP_WRITE(&phdr, sizeof(phdr));
}

@@ -1206,10 +1331,19 @@
DUMP_WRITE(&phdr, sizeof(phdr));
}

+ /* write out the notes section */
for(i = 0; i < numnote; i++)
if (!writenote(&notes[i], file))
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 (i = 0; i < tmp->num_notes; i++)
+ if (!writenote(&tmp->notes[i], file))
+ goto end_coredump;
+ }
+
DUMP_SEEK(dataoff);

for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
@@ -1253,11 +1387,21 @@
(off_t) file->f_pos, offset);
}

- end_coredump:
+end_coredump:
set_fs(fs);
- up_write(&current->mm->mmap_sem);
+
+cleanup:
+ while(!list_empty(&thread_list)) {
+ struct list_head *tmp = thread_list.next;
+ list_del(tmp);
+ kfree(list_entry(tmp, struct elf_thread_status, list));
+ }
+
+ tcore_resume_threads();
+
return has_dumped;
}
+
#endif /* USE_ELF_CORE_DUMP */

static int __init init_elf_binfmt(void)
diff -urN -X dontdiff linux-2.4.18/include/asm-i386/elf.h linux2418.tcore/include/asm-i386/elf.h
--- linux-2.4.18/include/asm-i386/elf.h Thu Nov 22 14:48:29 2001
+++ linux2418.tcore/include/asm-i386/elf.h Thu Jun 13 11:19:11 2002
@@ -99,6 +99,21 @@

#ifdef __KERNEL__
#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX)
+
+
+extern int dump_task_regs (struct task_struct *, elf_gregset_t *);
+extern int dump_task_fpu (struct task_struct *, elf_fpregset_t *);
+extern int dump_task_extended_fpu (struct task_struct *, struct user_fxsr_struct *);
+
+#define ELF_CORE_COPY_TASK_REGS(tsk, elf_regs) dump_task_regs(tsk, elf_regs)
+#define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs) dump_task_fpu(tsk, elf_fpregs)
+#define ELF_CORE_COPY_XFPREGS(tsk, elf_xfpregs) dump_task_extended_fpu(tsk, elf_xfpregs)
+
+#ifdef CONFIG_SMP
+extern void dump_smp_unlazy_fpu(void);
+#define ELF_CORE_SYNC dump_smp_unlazy_fpu
+#endif
+
#endif

#endif
diff -urN -X dontdiff linux-2.4.18/include/asm-ia64/elf.h linux2418.tcore/include/asm-ia64/elf.h
--- linux-2.4.18/include/asm-ia64/elf.h Tue Jul 11 18:43:45 2000
+++ linux2418.tcore/include/asm-ia64/elf.h Thu Jun 13 10:00:48 2002
@@ -62,12 +62,16 @@
#define ELF_NGREG 128 /* we really need just 72 but let's leave some headroom... */
#define ELF_NFPREG 128 /* f0 and f1 could be omitted, but so what... */

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

typedef struct ia64_fpreg elf_fpreg_t;
typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];

+
+
struct pt_regs; /* forward declaration... */
extern void ia64_elf_core_copy_regs (struct pt_regs *src, elf_gregset_t dst);
#define ELF_CORE_COPY_REGS(_dest,_regs) ia64_elf_core_copy_regs(_regs, _dest);
@@ -83,6 +87,12 @@

#ifdef __KERNEL__
#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX)
+extern int dump_task_regs(struct task_struct *, elf_gregset_t *);
+extern int dump_task_fpu (struct task_struct *, elf_fpregset_t *);
+
+#define ELF_CORE_COPY_TASK_REGS(tsk, elf_gregs) dump_task_regs(tsk, elf_gregs)
+#define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs) dump_task_fpu(tsk, elf_fpregs)
+
#endif

#endif /* _ASM_IA64_ELF_H */
diff -urN -X dontdiff linux-2.4.18/include/linux/elf.h linux2418.tcore/include/linux/elf.h
--- linux-2.4.18/include/linux/elf.h Thu Nov 22 14:48:29 2001
+++ linux2418.tcore/include/linux/elf.h Thu Jun 13 11:20:43 2002
@@ -576,6 +576,9 @@
#define NT_PRPSINFO 3
#define NT_TASKSTRUCT 4
#define NT_PRFPXREG 20
+#define NT_PRXFPREG 0x46e62b7f /* note name must be "LINUX" as per GDB */
+ /* from gdb5.1/include/elf/common.h */
+

/* Note header in a PT_NOTE section */
typedef struct elf32_note {
@@ -606,6 +609,5 @@
#define elf_note elf64_note

#endif
-

#endif /* _LINUX_ELF_H */
diff -urN -X dontdiff linux-2.4.18/include/linux/elfcore.h linux2418.tcore/include/linux/elfcore.h
--- linux-2.4.18/include/linux/elfcore.h Thu Nov 22 14:49:02 2001
+++ linux2418.tcore/include/linux/elfcore.h Thu Jun 13 11:19:11 2002
@@ -86,4 +86,66 @@
#define PRARGSZ ELF_PRARGSZ
#endif

+#ifdef __KERNEL__
+static inline void elf_core_copy_regs(elf_gregset_t *elfregs, struct pt_regs *regs)
+{
+#ifdef ELF_CORE_COPY_REGS
+ ELF_CORE_COPY_REGS((*elfregs), regs)
+#else
+ if (sizeof(elf_gregset_t) != sizeof(struct pt_regs)) {
+ printk("sizeof(elf_gregset_t) (%ld) != sizeof(struct pt_regs) (%ld)\n",
+ (long)sizeof(elf_gregset_t), (long)sizeof(struct pt_regs));
+ } else
+ *(struct pt_regs *)elfregs = *regs;
+#endif
+}
+
+static inline int elf_core_copy_task_regs(struct task_struct *t, elf_gregset_t* elfregs)
+{
+#ifdef ELF_CORE_COPY_TASK_REGS
+
+ return ELF_CORE_COPY_TASK_REGS(t, elfregs);
+#endif
+ return 0;
+}
+
+extern int dump_fpu (struct pt_regs *, elf_fpregset_t *);
+
+static inline int elf_core_copy_task_fpregs(struct task_struct *t, elf_fpregset_t *fpu)
+{
+#ifdef ELF_CORE_COPY_FPREGS
+ return ELF_CORE_COPY_FPREGS(t, fpu);
+#else
+ return dump_fpu(NULL, fpu);
+#endif
+}
+
+#ifdef ELF_CORE_COPY_XFPREGS
+static inline int elf_core_copy_task_xfpregs(struct task_struct *t, elf_fpxregset_t *xfpu)
+{
+ return ELF_CORE_COPY_XFPREGS(t, xfpu);
+}
+#endif
+
+#ifdef CONFIG_SMP
+/*
+ * trivial function used for SMP CPU synchronization.
+ * It doesn't do anything.
+ */
+static void tcore_do_nothing(void *var)
+{
+
+#ifdef ELF_CORE_SYNC
+ ELF_CORE_SYNC();
+#endif
+
+ return;
+}
+
+#endif
+
+
+#endif /* __KERNEL__ */
+
+
#endif /* _LINUX_ELFCORE_H */
diff -urN -X dontdiff linux-2.4.18/include/linux/sched.h linux2418.tcore/include/linux/sched.h
--- linux-2.4.18/include/linux/sched.h Fri Dec 21 12:42:03 2001
+++ linux2418.tcore/include/linux/sched.h Thu Jun 13 11:19:11 2002
@@ -132,6 +132,14 @@

#include <linux/spinlock.h>

+
+/* functions for pausing and resumming functions
+ * common mm's without using signals. These are used
+ * by the multithreaded elf core dump code in binfmt_elf.c*/
+extern void tcore_suspend_threads( void );
+extern void tcore_resume_threads( void );
+
+
/*
* This serializes "schedule()" and also protects
* the run-queue from deletions/modifications (but
diff -urN -X dontdiff linux-2.4.18/kernel/sched.c linux2418.tcore/kernel/sched.c
--- linux-2.4.18/kernel/sched.c Fri Dec 21 12:42:04 2001
+++ linux2418.tcore/kernel/sched.c Thu Jun 13 10:00:48 2002
@@ -33,6 +33,8 @@
#include <asm/uaccess.h>
#include <asm/mmu_context.h>

+#include <linux/elfcore.h>
+
extern void timer_bh(void);
extern void tqueue_bh(void);
extern void immediate_bh(void);
@@ -121,7 +123,7 @@
#else

#define idle_task(cpu) (&init_task)
-#define can_schedule(p,cpu) (1)
+#define can_schedule(p,cpu) ((p)->cpus_allowed & (1 << cpu))

#endif

@@ -851,6 +853,108 @@
}

void scheduling_functions_end_here(void) { }
+
+/*
+ * needed for accurate core dumps of multi-threaded applications.
+ * see binfmt_elf.c for more information.
+ */
+static void reschedule_other_cpus(void)
+{
+#ifdef CONFIG_SMP
+ int i, cpu;
+ struct task_struct *p;
+
+ for(i=0; i< smp_num_cpus; i++) {
+ cpu = cpu_logical_map(i);
+ p = cpu_curr(cpu);
+ if (p->processor != smp_processor_id()) {
+ p->need_resched = 1;
+ smp_send_reschedule(p->processor);
+ }
+ }
+#endif
+ return;
+}
+
+/* functions for pausing and resumming functions with out using signals */
+void tcore_suspend_threads(void)
+{
+ struct task_struct *p;
+
+//
+// grab all the rq_locks.
+// current is the process dumping core
+//
+
+ down_write(&current->mm->mmap_sem);
+ // avoid potential race on >2 way SMP if 3 or more thread procs
+ // dump core at the same time.
+
+
+ /*
+ * brute force method uses the runqueue_lock contention. Grab this lock, and
+ * force a schedule call on all the other CPU's to get them spinning.
+ * spin_lock_prefetch(&runqueue_lock) <-- is this needed?
+ */
+ read_lock(&tasklist_lock);
+ spin_lock_irq(&runqueue_lock);
+
+ task_lock(current);
+ current->cpus_allowed = 1UL << current->processor;
+ // prevent migraion of dumping process making life complicated.
+ task_unlock(current);
+
+ reschedule_other_cpus();
+ // this is an optional IPI, but it makes for the most accurate core files possible.
+
+ for_each_task(p)
+ if (current->mm == p->mm && current != p) {
+ task_lock(p);
+ p->cpus_allowed = 0UL;
+ task_unlock(p);
+ /*
+ * forces yeild and keeps waking process from getting scheduled
+ * in. This will result in these processes getting swapped out and
+ * not swapped in by the scheduler if they have been sleeping.
+ */
+ }
+
+ spin_unlock_irq(&runqueue_lock);
+
+ /* let them all run again.. */
+ read_unlock(&tasklist_lock);
+
+ up_write(&current->mm->mmap_sem);
+
+#ifdef CONFIG_SMP
+ /*
+ * now we syncronize on all the CPU's to make sure
+ * none of the other thread processes are running in
+ * and any lazy fpu register data has been captured
+ * from user space before we proceed.
+ */
+ smp_call_function(tcore_do_nothing, NULL, 1,1);
+#endif
+
+return;
+}
+
+void tcore_resume_threads(void)
+{
+ struct task_struct *p;
+
+ read_lock(&tasklist_lock);
+ for_each_task(p)
+ if (current->mm == p->mm && current != p){
+ task_lock(p);
+ p->cpus_allowed = 1UL << current->processor;
+ task_unlock(p);
+ }
+ read_unlock(&tasklist_lock);
+
+ return;
+}
+

#ifndef __alpha__
\
 
 \ /
  Last update: 2005-03-22 13:31    [from the cache]
©2003-2011 Jasper Spaans