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    [W:0.084 / U:0.180 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site