Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys Instead of generating all the 'note' sections twice (and...



details:   https://anonhg.NetBSD.org/src/rev/5d737fdd7f74
branches:  trunk
changeset: 792445:5d737fdd7f74
user:      dsl <dsl%NetBSD.org@localhost>
date:      Fri Jan 03 20:52:47 2014 +0000

description:
Instead of generating all the 'note' sections twice (and hoping that the
  'fast path' size on the first path matches the actual size on the second)
  save all the notes (mostly the cpu registers for all the LWPs) in
  malloced memory on the first pass.
Sanity check that the number of memory segments matches written matches
  the count obtained earlier. If gcore() is used they could differ.
  (Not sure that returning ENOMEM is ideal, but it is better than a crash.)

diffstat:

 sys/kern/core_elf32.c |  334 ++++++++++++++++++++++++++-----------------------
 sys/kern/kern_core.c  |   13 +-
 sys/sys/exec.h        |    3 +-
 sys/sys/exec_elf.h    |   11 +-
 4 files changed, 193 insertions(+), 168 deletions(-)

diffs (truncated from 612 to 300 lines):

diff -r a43b31378e89 -r 5d737fdd7f74 sys/kern/core_elf32.c
--- a/sys/kern/core_elf32.c     Fri Jan 03 20:26:45 2014 +0000
+++ b/sys/kern/core_elf32.c     Fri Jan 03 20:52:47 2014 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: core_elf32.c,v 1.38 2014/01/03 15:15:02 dsl Exp $      */
+/*     $NetBSD: core_elf32.c,v 1.39 2014/01/03 20:52:47 dsl Exp $      */
 
 /*
  * Copyright (c) 2001 Wasabi Systems, Inc.
@@ -40,7 +40,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(1, "$NetBSD: core_elf32.c,v 1.38 2014/01/03 15:15:02 dsl Exp $");
+__KERNEL_RCSID(1, "$NetBSD: core_elf32.c,v 1.39 2014/01/03 20:52:47 dsl Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_coredump.h"
@@ -69,18 +69,33 @@
 struct writesegs_state {
        Elf_Phdr *psections;
        off_t   secoff;
+       size_t  npsections;
+};
+
+/*
+ * We need to know how big the 'notes' are before we write the main header.
+ * To avoid problems with double-processing we save the data.
+ */
+struct note_buf {
+       struct note_buf  *nb_next;
+       unsigned char    nb_data[4096 - sizeof (void *)];
+};
+
+struct note_state {
+       struct note_buf  *ns_first;
+       struct note_buf  *ns_last;
+       unsigned int     ns_count;       /* Of full buffers */
+       unsigned int     ns_offset;      /* Write point in last buffer */
 };
 
 static int     ELFNAMEEND(coredump_getseghdrs)(struct proc *,
                    struct uvm_coredump_state *);
 
-static int     ELFNAMEEND(coredump_notes)(struct proc *, struct lwp *,
-                   struct coredump_iostate *, size_t *);
-static int     ELFNAMEEND(coredump_note)(struct proc *, struct lwp *,
-                   struct coredump_iostate *, size_t *);
+static int     ELFNAMEEND(coredump_notes)(struct lwp *, struct note_state *);
+static int     ELFNAMEEND(coredump_note)(struct lwp *, struct note_state *);
 
+/* The 'note' section names and data are always 4-byte aligned. */
 #define        ELFROUNDSIZE    4       /* XXX Should it be sizeof(Elf_Word)? */
-#define        elfround(x)     roundup((x), ELFROUNDSIZE)
 
 #define elf_process_read_regs  CONCAT(process_read_regs, ELFSIZE)
 #ifdef __HAVE_PROCESS_XFPREGS
@@ -94,18 +109,31 @@
 int
 ELFNAMEEND(coredump)(struct lwp *l, struct coredump_iostate *cookie)
 {
-       struct proc *p;
        Elf_Ehdr ehdr;
-       Elf_Phdr phdr, *psections;
+       Elf_Phdr *psections;
        size_t psectionssize;
        int npsections;
        struct writesegs_state ws;
-       off_t notestart, secstart, offset;
+       off_t notestart;
        size_t notesize;
        int error, i;
 
+       struct note_state ns;
+       struct note_buf *nb;
+
        psections = NULL;
-       p = l->l_proc;
+
+       /* Get all of the notes (mostly all the registers). */
+       ns.ns_first = kmem_alloc(sizeof *ns.ns_first, KM_SLEEP);
+       ns.ns_last = ns.ns_first;
+       ns.ns_count = 0;
+       ns.ns_offset = 0;
+       error = ELFNAMEEND(coredump_notes)(l, &ns);
+       ns.ns_last->nb_next = NULL;
+       if (error)
+               goto out;
+       notesize = ns.ns_count * sizeof nb->nb_data + ns.ns_offset;
+
        /*
         * We have to make a total of 3 passes across the map:
         *
@@ -118,15 +146,11 @@
         */
 
        /* Pass 1: count the entries. */
-       npsections = uvm_coredump_count_segs(p);
-       /* Count the PT_NOTE section. */
+       npsections = uvm_coredump_count_segs(l->l_proc);
+       /* Allow for the PT_NOTE section. */
        npsections++;
 
-       /* Get the size of the notes (mostly all the registers). */
-       error = ELFNAMEEND(coredump_notes)(p, l, NULL, &notesize);
-       if (error)
-               goto out;
-
+       /* Build the main elf header */
        memset(&ehdr.e_ident[EI_PAD], 0, sizeof(ehdr.e_ident) - EI_PAD);
        memcpy(ehdr.e_ident, ELFMAG, SELFMAG);
 #if ELFSIZE == 32
@@ -164,20 +188,24 @@
        if (error)
                goto out;
 
-       offset = sizeof(ehdr);
+       psectionssize = npsections * sizeof(*psections);
+       notestart = sizeof(ehdr) + psectionssize;
 
-       notestart = offset + sizeof(phdr) * npsections;
-       secstart = notestart + notesize;
-
-       psectionssize = npsections * sizeof(Elf_Phdr);
        psections = kmem_zalloc(psectionssize, KM_SLEEP);
 
        /* Pass 2: now find the P-section headers. */
-       ws.secoff = secstart;
+       ws.secoff = notestart + notesize;
        ws.psections = psections;
-       error = uvm_coredump_walkmap(p, ELFNAMEEND(coredump_getseghdrs), &ws);
+       ws.npsections = npsections - 1;
+       error = uvm_coredump_walkmap(l->l_proc, ELFNAMEEND(coredump_getseghdrs),
+           &ws);
        if (error)
                goto out;
+       if (ws.npsections != 0) {
+               /* A section went away */
+               error = ENOMEM;
+               goto out;
+       }
 
        /* Add the PT_NOTE header after the P-section headers. */
        ws.psections->p_type = PT_NOTE;
@@ -189,40 +217,35 @@
        ws.psections->p_flags = PF_R;
        ws.psections->p_align = ELFROUNDSIZE;
 
-       /* Write the P-section headers followed by the PT_NOTR header */
-       error = coredump_write(cookie, UIO_SYSSPACE, psections,
-           npsections * sizeof(Elf_Phdr));
+       /* Write the P-section headers followed by the PT_NOTE header */
+       error = coredump_write(cookie, UIO_SYSSPACE, psections, psectionssize);
        if (error)
                goto out;
 
 #ifdef DIAGNOSTIC
-       offset += npsections * sizeof(Elf_Phdr);
-       if (offset != notestart)
+       if (coredump_offset(cookie) != notestart)
                panic("coredump: offset %lld != notestart %lld",
-                   (long long) offset, (long long) notestart);
+                   (long long) coredump_offset(cookie),
+                   (long long) notestart);
 #endif
 
        /* Write out the notes. */
-       error = ELFNAMEEND(coredump_notes)(p, l, cookie, &notesize);
-       if (error)
-               goto out;
+       for (nb = ns.ns_first; nb != NULL; nb = nb->nb_next) {
+               error = coredump_write(cookie, UIO_SYSSPACE, nb->nb_data,
+                   nb->nb_next == NULL ? ns.ns_offset : sizeof nb->nb_data);
+               if (error)
+                       goto out;
+       }
 
-#ifdef DIAGNOSTIC
-       offset += notesize;
-       if (offset != secstart)
-               panic("coredump: offset %lld != secstart %lld",
-                   (long long) offset, (long long) secstart);
-#endif
-
-       /* Pass 3: finally, write the sections themselves. */
+       /* Finally, write the sections themselves. */
        for (i = 0; i < npsections - 1; i++) {
                if (psections[i].p_filesz == 0)
                        continue;
 
 #ifdef DIAGNOSTIC
-               if (offset != psections[i].p_offset)
+               if (coredump_offset(cookie) != psections[i].p_offset)
                        panic("coredump: offset %lld != p_offset[%d] %lld",
-                           (long long) offset, i,
+                           (long long) coredump_offset(cookie), i,
                            (long long) psections[i].p_filesz);
 #endif
 
@@ -231,15 +254,13 @@
                    psections[i].p_filesz);
                if (error)
                        goto out;
-
-#ifdef DIAGNOSTIC
-               offset += psections[i].p_filesz;
-#endif
        }
 
   out:
        if (psections)
                kmem_free(psections, psectionssize);
+       for (; (nb = ns.ns_first) != NULL; ns.ns_first = nb->nb_next)
+               kmem_free(nb, sizeof *nb);
        return (error);
 }
 
@@ -252,6 +273,11 @@
        vaddr_t end;
        int error;
 
+       /* Don't overrun if there are more sections */
+       if (ws->npsections == 0)
+               return ENOMEM;
+       ws->npsections--;
+
        size = us->end - us->start;
        realsize = us->realend - us->start;
        end = us->realend;
@@ -299,74 +325,65 @@
 }
 
 static int
-ELFNAMEEND(coredump_notes)(struct proc *p, struct lwp *l,
-    struct coredump_iostate *iocookie, size_t *sizep)
+ELFNAMEEND(coredump_notes)(struct lwp *l, struct note_state *ns)
 {
+       struct proc *p;
        struct netbsd_elfcore_procinfo cpi;
        Elf_Nhdr nhdr;
-       size_t size, notesize;
        int error;
        struct lwp *l0;
        sigset_t ss1, ss2;
 
-       size = 0;
+       p = l->l_proc;
 
        /* First, write an elfcore_procinfo. */
-       notesize = sizeof(nhdr) + elfround(sizeof(ELF_NOTE_NETBSD_CORE_NAME)) +
-           elfround(sizeof(cpi));
-       if (iocookie) {
-               cpi.cpi_version = NETBSD_ELFCORE_PROCINFO_VERSION;
-               cpi.cpi_cpisize = sizeof(cpi);
-               cpi.cpi_signo = p->p_sigctx.ps_signo;
-               cpi.cpi_sigcode = p->p_sigctx.ps_code;
-               cpi.cpi_siglwp = p->p_sigctx.ps_lwp;
+       cpi.cpi_version = NETBSD_ELFCORE_PROCINFO_VERSION;
+       cpi.cpi_cpisize = sizeof(cpi);
+       cpi.cpi_signo = p->p_sigctx.ps_signo;
+       cpi.cpi_sigcode = p->p_sigctx.ps_code;
+       cpi.cpi_siglwp = p->p_sigctx.ps_lwp;
 
-               /*
-                * XXX This should be per-LWP.
-                */
-               ss1 = p->p_sigpend.sp_set;
-               sigemptyset(&ss2);
-               LIST_FOREACH(l0, &p->p_lwps, l_sibling) {
-                       sigplusset(&l0->l_sigpend.sp_set, &ss1);
-                       sigplusset(&l0->l_sigmask, &ss2);
-               }
-               memcpy(&cpi.cpi_sigpend, &ss1, sizeof(cpi.cpi_sigpend));
-               memcpy(&cpi.cpi_sigmask, &ss2, sizeof(cpi.cpi_sigmask));
-               memcpy(&cpi.cpi_sigignore, &p->p_sigctx.ps_sigignore,
-                   sizeof(cpi.cpi_sigignore));
-               memcpy(&cpi.cpi_sigcatch, &p->p_sigctx.ps_sigcatch,
-                   sizeof(cpi.cpi_sigcatch));
+       /*
+        * XXX This should be per-LWP.
+        */
+       ss1 = p->p_sigpend.sp_set;
+       sigemptyset(&ss2);
+       LIST_FOREACH(l0, &p->p_lwps, l_sibling) {
+               sigplusset(&l0->l_sigpend.sp_set, &ss1);
+               sigplusset(&l0->l_sigmask, &ss2);
+       }
+       memcpy(&cpi.cpi_sigpend, &ss1, sizeof(cpi.cpi_sigpend));
+       memcpy(&cpi.cpi_sigmask, &ss2, sizeof(cpi.cpi_sigmask));
+       memcpy(&cpi.cpi_sigignore, &p->p_sigctx.ps_sigignore,
+           sizeof(cpi.cpi_sigignore));
+       memcpy(&cpi.cpi_sigcatch, &p->p_sigctx.ps_sigcatch,
+           sizeof(cpi.cpi_sigcatch));
 
-               cpi.cpi_pid = p->p_pid;
-               mutex_enter(proc_lock);
-               cpi.cpi_ppid = p->p_pptr->p_pid;
-               cpi.cpi_pgrp = p->p_pgid;
-               cpi.cpi_sid = p->p_session->s_sid;
-               mutex_exit(proc_lock);



Home | Main Index | Thread Index | Old Index