The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/core_elf32.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: core_elf32.c,v 1.32 2008/04/24 15:35:28 ad Exp $       */
    2 
    3 /*
    4  * Copyright (c) 2001 Wasabi Systems, Inc.
    5  * All rights reserved.
    6  *
    7  * Written by Jason R. Thorpe for Wasabi Systems, Inc.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  * 3. All advertising materials mentioning features or use of this software
   18  *    must display the following acknowledgement:
   19  *      This product includes software developed for the NetBSD Project by
   20  *      Wasabi Systems, Inc.
   21  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
   22  *    or promote products derived from this software without specific prior
   23  *    written permission.
   24  *
   25  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
   26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   27  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   28  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
   29  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   33  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   35  * POSSIBILITY OF SUCH DAMAGE.
   36  */
   37 
   38 /*
   39  * core_elf32.c/core_elf64.c: Support for the Elf32/Elf64 core file format.
   40  */
   41 
   42 #include <sys/cdefs.h>
   43 __KERNEL_RCSID(1, "$NetBSD: core_elf32.c,v 1.32 2008/04/24 15:35:28 ad Exp $");
   44 
   45 /* If not included by core_elf64.c, ELFSIZE won't be defined. */
   46 #ifndef ELFSIZE
   47 #define ELFSIZE         32
   48 #endif
   49 
   50 #include <sys/param.h>
   51 #include <sys/systm.h>
   52 #include <sys/proc.h>
   53 #include <sys/vnode.h>
   54 #include <sys/exec.h>
   55 #include <sys/exec_elf.h>
   56 #include <sys/ptrace.h>
   57 #include <sys/malloc.h>
   58 #include <sys/kauth.h>
   59 
   60 #include <machine/reg.h>
   61 
   62 #include <uvm/uvm_extern.h>
   63 
   64 struct countsegs_state {
   65         int     npsections;
   66 };
   67 
   68 static int      ELFNAMEEND(coredump_countsegs)(struct proc *, void *,
   69                     struct uvm_coredump_state *);
   70 
   71 struct writesegs_state {
   72         Elf_Phdr *psections;
   73         off_t   secoff;
   74 };
   75 
   76 static int      ELFNAMEEND(coredump_writeseghdrs)(struct proc *, void *,
   77                     struct uvm_coredump_state *);
   78 
   79 static int      ELFNAMEEND(coredump_notes)(struct proc *, struct lwp *, void *,
   80                     size_t *);
   81 static int      ELFNAMEEND(coredump_note)(struct proc *, struct lwp *, void *,
   82                     size_t *);
   83 
   84 #define ELFROUNDSIZE    4       /* XXX Should it be sizeof(Elf_Word)? */
   85 #define elfround(x)     roundup((x), ELFROUNDSIZE)
   86 
   87 #define elf_process_read_regs   CONCAT(process_read_regs, ELFSIZE)
   88 #define elf_process_read_fpregs CONCAT(process_read_fpregs, ELFSIZE)
   89 #define elf_reg                 CONCAT(process_reg, ELFSIZE)
   90 #define elf_fpreg               CONCAT(process_fpreg, ELFSIZE)
   91 
   92 int
   93 ELFNAMEEND(coredump)(struct lwp *l, void *cookie)
   94 {
   95         struct proc *p;
   96         Elf_Ehdr ehdr;
   97         Elf_Phdr phdr, *psections;
   98         struct countsegs_state cs;
   99         struct writesegs_state ws;
  100         off_t notestart, secstart, offset;
  101         size_t notesize;
  102         int error, i;
  103 
  104         psections = NULL;
  105         p = l->l_proc;
  106         /*
  107          * We have to make a total of 3 passes across the map:
  108          *
  109          *      1. Count the number of map entries (the number of
  110          *         PT_LOAD sections).
  111          *
  112          *      2. Write the P-section headers.
  113          *
  114          *      3. Write the P-sections.
  115          */
  116 
  117         /* Pass 1: count the entries. */
  118         cs.npsections = 0;
  119         error = uvm_coredump_walkmap(p, NULL,
  120             ELFNAMEEND(coredump_countsegs), &cs);
  121         if (error)
  122                 goto out;
  123 
  124         /* Count the PT_NOTE section. */
  125         cs.npsections++;
  126 
  127         /* Get the size of the notes. */
  128         error = ELFNAMEEND(coredump_notes)(p, l, NULL, &notesize);
  129         if (error)
  130                 goto out;
  131 
  132         memset(&ehdr.e_ident[EI_PAD], 0, sizeof(ehdr.e_ident) - EI_PAD);
  133         memcpy(ehdr.e_ident, ELFMAG, SELFMAG);
  134 #if ELFSIZE == 32
  135         ehdr.e_ident[EI_CLASS] = ELFCLASS32;
  136 #elif ELFSIZE == 64
  137         ehdr.e_ident[EI_CLASS] = ELFCLASS64;
  138 #endif
  139         ehdr.e_ident[EI_DATA] = ELFDEFNNAME(MACHDEP_ENDIANNESS);
  140         ehdr.e_ident[EI_VERSION] = EV_CURRENT;
  141         /* XXX Should be the OSABI/ABI version of the executable. */
  142         ehdr.e_ident[EI_OSABI] = ELFOSABI_SYSV;
  143         ehdr.e_ident[EI_ABIVERSION] = 0;
  144 
  145         ehdr.e_type = ET_CORE;
  146         /* XXX This should be the e_machine of the executable. */
  147         ehdr.e_machine = ELFDEFNNAME(MACHDEP_ID);
  148         ehdr.e_version = EV_CURRENT;
  149         ehdr.e_entry = 0;
  150         ehdr.e_phoff = sizeof(ehdr);
  151         ehdr.e_shoff = 0;
  152         ehdr.e_flags = 0;
  153         ehdr.e_ehsize = sizeof(ehdr);
  154         ehdr.e_phentsize = sizeof(Elf_Phdr);
  155         ehdr.e_phnum = cs.npsections;
  156         ehdr.e_shentsize = 0;
  157         ehdr.e_shnum = 0;
  158         ehdr.e_shstrndx = 0;
  159 
  160         /* Write out the ELF header. */
  161         error = coredump_write(cookie, UIO_SYSSPACE, &ehdr, sizeof(ehdr));
  162         if (error)
  163                 goto out;
  164 
  165         offset = sizeof(ehdr);
  166 
  167         notestart = offset + sizeof(phdr) * cs.npsections;
  168         secstart = notestart + notesize;
  169 
  170         psections = malloc(cs.npsections * sizeof(Elf_Phdr),
  171             M_TEMP, M_WAITOK|M_ZERO);
  172 
  173         /* Pass 2: now write the P-section headers. */
  174         ws.secoff = secstart;
  175         ws.psections = psections;
  176         error = uvm_coredump_walkmap(p, cookie,
  177             ELFNAMEEND(coredump_writeseghdrs), &ws);
  178         if (error)
  179                 goto out;
  180 
  181         /* Write out the PT_NOTE header. */
  182         ws.psections->p_type = PT_NOTE;
  183         ws.psections->p_offset = notestart;
  184         ws.psections->p_vaddr = 0;
  185         ws.psections->p_paddr = 0;
  186         ws.psections->p_filesz = notesize;
  187         ws.psections->p_memsz = 0;
  188         ws.psections->p_flags = PF_R;
  189         ws.psections->p_align = ELFROUNDSIZE;
  190 
  191         error = coredump_write(cookie, UIO_SYSSPACE, psections,
  192             cs.npsections * sizeof(Elf_Phdr));
  193         if (error)
  194                 goto out;
  195 
  196 #ifdef DIAGNOSTIC
  197         offset += cs.npsections * sizeof(Elf_Phdr);
  198         if (offset != notestart)
  199                 panic("coredump: offset %lld != notestart %lld",
  200                     (long long) offset, (long long) notestart);
  201 #endif
  202 
  203         /* Write out the notes. */
  204         error = ELFNAMEEND(coredump_notes)(p, l, cookie, &notesize);
  205         if (error)
  206                 goto out;
  207 
  208 #ifdef DIAGNOSTIC
  209         offset += notesize;
  210         if (offset != secstart)
  211                 panic("coredump: offset %lld != secstart %lld",
  212                     (long long) offset, (long long) secstart);
  213 #endif
  214 
  215         /* Pass 3: finally, write the sections themselves. */
  216         for (i = 0; i < cs.npsections - 1; i++) {
  217                 if (psections[i].p_filesz == 0)
  218                         continue;
  219 
  220 #ifdef DIAGNOSTIC
  221                 if (offset != psections[i].p_offset)
  222                         panic("coredump: offset %lld != p_offset[%d] %lld",
  223                             (long long) offset, i,
  224                             (long long) psections[i].p_filesz);
  225 #endif
  226 
  227                 error = coredump_write(cookie, UIO_USERSPACE,
  228                     (void *)(vaddr_t)psections[i].p_vaddr,
  229                     psections[i].p_filesz);
  230                 if (error)
  231                         goto out;
  232 
  233 #ifdef DIAGNOSTIC
  234                 offset += psections[i].p_filesz;
  235 #endif
  236         }
  237 
  238   out:
  239         if (psections)
  240                 free(psections, M_TEMP);
  241         return (error);
  242 }
  243 
  244 static int
  245 ELFNAMEEND(coredump_countsegs)(struct proc *p, void *iocookie,
  246     struct uvm_coredump_state *us)
  247 {
  248         struct countsegs_state *cs = us->cookie;
  249 
  250         cs->npsections++;
  251         return (0);
  252 }
  253 
  254 static int
  255 ELFNAMEEND(coredump_writeseghdrs)(struct proc *p, void *iocookie,
  256     struct uvm_coredump_state *us)
  257 {
  258         struct writesegs_state *ws = us->cookie;
  259         Elf_Phdr phdr;
  260         vsize_t size, realsize;
  261         vaddr_t end;
  262         int error;
  263 
  264         size = us->end - us->start;
  265         realsize = us->realend - us->start;
  266         end = us->realend;
  267 
  268         while (realsize > 0) {
  269                 long buf[1024 / sizeof(long)];
  270                 size_t slen = realsize > sizeof(buf) ? sizeof(buf) : realsize;
  271                 const long *ep;
  272                 int i;
  273 
  274                 end -= slen;
  275                 if ((error = copyin_proc(p, (void *)end, buf, slen)) != 0)
  276                         return error;
  277 
  278                 ep = (const long *) &buf[slen / sizeof(buf[0])];
  279                 for (i = 0, ep--; buf <= ep; ep--, i++) {
  280                         if (*ep)
  281                                 break;
  282                 }
  283                 realsize -= i * sizeof(buf[0]);
  284                 if (i * sizeof(buf[0]) < slen)
  285                         break;
  286         }
  287 
  288         phdr.p_type = PT_LOAD;
  289         phdr.p_offset = ws->secoff;
  290         phdr.p_vaddr = us->start;
  291         phdr.p_paddr = 0;
  292         phdr.p_filesz = realsize;
  293         phdr.p_memsz = size;
  294         phdr.p_flags = 0;
  295         if (us->prot & VM_PROT_READ)
  296                 phdr.p_flags |= PF_R;
  297         if (us->prot & VM_PROT_WRITE)
  298                 phdr.p_flags |= PF_W;
  299         if (us->prot & VM_PROT_EXECUTE)
  300                 phdr.p_flags |= PF_X;
  301         phdr.p_align = PAGE_SIZE;
  302 
  303         ws->secoff += phdr.p_filesz;
  304         *ws->psections++ = phdr;
  305 
  306         return (0);
  307 }
  308 
  309 static int
  310 ELFNAMEEND(coredump_notes)(struct proc *p, struct lwp *l,
  311     void *iocookie, size_t *sizep)
  312 {
  313         struct netbsd_elfcore_procinfo cpi;
  314         Elf_Nhdr nhdr;
  315         size_t size, notesize;
  316         int error;
  317         struct lwp *l0;
  318         sigset_t ss1, ss2;
  319 
  320         size = 0;
  321 
  322         /* First, write an elfcore_procinfo. */
  323         notesize = sizeof(nhdr) + elfround(sizeof(ELF_NOTE_NETBSD_CORE_NAME)) +
  324             elfround(sizeof(cpi));
  325         if (iocookie) {
  326                 cpi.cpi_version = NETBSD_ELFCORE_PROCINFO_VERSION;
  327                 cpi.cpi_cpisize = sizeof(cpi);
  328                 cpi.cpi_signo = p->p_sigctx.ps_signo;
  329                 cpi.cpi_sigcode = p->p_sigctx.ps_code;
  330                 cpi.cpi_siglwp = p->p_sigctx.ps_lwp;
  331 
  332                 /*
  333                  * XXX This should be per-LWP.
  334                  */
  335                 ss1 = p->p_sigpend.sp_set;
  336                 sigemptyset(&ss2);
  337                 LIST_FOREACH(l0, &p->p_lwps, l_sibling) {
  338                         sigplusset(&l0->l_sigpend.sp_set, &ss1);
  339                         sigplusset(&l0->l_sigmask, &ss2);
  340                 }
  341                 memcpy(&cpi.cpi_sigpend, &ss1, sizeof(cpi.cpi_sigpend));
  342                 memcpy(&cpi.cpi_sigmask, &ss2, sizeof(cpi.cpi_sigmask));
  343                 memcpy(&cpi.cpi_sigignore, &p->p_sigctx.ps_sigignore,
  344                     sizeof(cpi.cpi_sigignore));
  345                 memcpy(&cpi.cpi_sigcatch, &p->p_sigctx.ps_sigcatch,
  346                     sizeof(cpi.cpi_sigcatch));
  347 
  348                 cpi.cpi_pid = p->p_pid;
  349                 mutex_enter(proc_lock);
  350                 cpi.cpi_ppid = p->p_pptr->p_pid;
  351                 cpi.cpi_pgrp = p->p_pgid;
  352                 cpi.cpi_sid = p->p_session->s_sid;
  353                 mutex_exit(proc_lock);
  354 
  355                 cpi.cpi_ruid = kauth_cred_getuid(l->l_cred);
  356                 cpi.cpi_euid = kauth_cred_geteuid(l->l_cred);
  357                 cpi.cpi_svuid = kauth_cred_getsvuid(l->l_cred);
  358 
  359                 cpi.cpi_rgid = kauth_cred_getgid(l->l_cred);
  360                 cpi.cpi_egid = kauth_cred_getegid(l->l_cred);
  361                 cpi.cpi_svgid = kauth_cred_getsvgid(l->l_cred);
  362 
  363                 cpi.cpi_nlwps = p->p_nlwps;
  364                 (void)strncpy(cpi.cpi_name, p->p_comm, sizeof(cpi.cpi_name));
  365                 cpi.cpi_name[sizeof(cpi.cpi_name) - 1] = '\0';
  366 
  367                 nhdr.n_namesz = sizeof(ELF_NOTE_NETBSD_CORE_NAME);
  368                 nhdr.n_descsz = sizeof(cpi);
  369                 nhdr.n_type = ELF_NOTE_NETBSD_CORE_PROCINFO;
  370 
  371                 error = ELFNAMEEND(coredump_writenote)(p, iocookie, &nhdr,
  372                     ELF_NOTE_NETBSD_CORE_NAME "\0\0\0", &cpi);
  373                 if (error)
  374                         return (error);
  375         }
  376 
  377         size += notesize;
  378 
  379         /* XXX Add hook for machdep per-proc notes. */
  380 
  381         /*
  382          * Now write the register info for the thread that caused the
  383          * coredump.
  384          */
  385         error = ELFNAMEEND(coredump_note)(p, l, iocookie, &notesize);
  386         if (error)
  387                 return (error);
  388         size += notesize;
  389 
  390         /*
  391          * Now, for each LWP, write the register info and any other
  392          * per-LWP notes.  Since we're dumping core, we don't bother
  393          * locking.
  394          */
  395         LIST_FOREACH(l0, &p->p_lwps, l_sibling) {
  396                 if (l0 == l)            /* we've taken care of this thread */
  397                         continue;
  398                 error = ELFNAMEEND(coredump_note)(p, l0, iocookie, &notesize);
  399                 if (error)
  400                         return (error);
  401                 size += notesize;
  402         }
  403 
  404         *sizep = size;
  405         return (0);
  406 }
  407 
  408 static int
  409 ELFNAMEEND(coredump_note)(struct proc *p, struct lwp *l, void *iocookie,
  410     size_t *sizep)
  411 {
  412         Elf_Nhdr nhdr;
  413         int size, notesize, error;
  414         int namesize;
  415         char name[64+ELFROUNDSIZE];
  416         elf_reg intreg;
  417 #ifdef PT_GETFPREGS
  418         elf_fpreg freg;
  419 #endif
  420 
  421         size = 0;
  422 
  423         snprintf(name, sizeof(name)-ELFROUNDSIZE, "%s@%d",
  424             ELF_NOTE_NETBSD_CORE_NAME, l->l_lid);
  425         namesize = strlen(name) + 1;
  426         memset(name + namesize, 0, elfround(namesize) - namesize);
  427 
  428         notesize = sizeof(nhdr) + elfround(namesize) + elfround(sizeof(intreg));
  429         if (iocookie) {
  430                 uvm_lwp_hold(l);
  431                 error = elf_process_read_regs(l, &intreg);
  432                 uvm_lwp_rele(l);
  433                 if (error)
  434                         return (error);
  435 
  436                 nhdr.n_namesz = namesize;
  437                 nhdr.n_descsz = sizeof(intreg);
  438                 nhdr.n_type = PT_GETREGS;
  439 
  440                 error = ELFNAMEEND(coredump_writenote)(p, iocookie, &nhdr,
  441                     name, &intreg);
  442                 if (error)
  443                         return (error);
  444 
  445         }
  446         size += notesize;
  447 
  448 #ifdef PT_GETFPREGS
  449         notesize = sizeof(nhdr) + elfround(namesize) + elfround(sizeof(freg));
  450         if (iocookie) {
  451                 uvm_lwp_hold(l);
  452                 error = elf_process_read_fpregs(l, &freg);
  453                 uvm_lwp_rele(l);
  454                 if (error)
  455                         return (error);
  456 
  457                 nhdr.n_namesz = namesize;
  458                 nhdr.n_descsz = sizeof(freg);
  459                 nhdr.n_type = PT_GETFPREGS;
  460 
  461                 error = ELFNAMEEND(coredump_writenote)(p, iocookie, &nhdr,
  462                     name, &freg);
  463                 if (error)
  464                         return (error);
  465         }
  466         size += notesize;
  467 #endif
  468         *sizep = size;
  469         /* XXX Add hook for machdep per-LWP notes. */
  470         return (0);
  471 }
  472 
  473 int
  474 ELFNAMEEND(coredump_writenote)(struct proc *p, void *cookie, Elf_Nhdr *nhdr,
  475     const char *name, void *data)
  476 {
  477         int error;
  478 
  479         error = coredump_write(cookie, UIO_SYSSPACE, nhdr, sizeof(*nhdr));
  480         if (error)
  481                 return error;
  482 
  483         error = coredump_write(cookie, UIO_SYSSPACE, name,
  484             elfround(nhdr->n_namesz));
  485         if (error)
  486                 return error;
  487 
  488         return coredump_write(cookie, UIO_SYSSPACE, data, nhdr->n_descsz);
  489 }

Cache object: 749cd63b1fc70e573879c7387d383f71


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.