/*- * Copyright (c) 1995-1996 Søren Schmidt * Copyright (c) 1996 Peter Wemm * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software withough specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $Id: imgact_elf.c,v 1.33 1998/09/15 22:07:20 jdp Exp $ */ #include "opt_rlimit.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MAX_PHDR 32 /* XXX enough ? */ #if ELF_TARG_CLASS == ELFCLASS32 #define Elf_Ehdr Elf32_Ehdr #define Elf_Phdr Elf32_Phdr #define Elf_Auxargs Elf32_Auxargs #define Elf_Brandinfo Elf32_Brandinfo #else #define Elf_Ehdr Elf64_Ehdr #define Elf_Phdr Elf64_Phdr #define Elf_Auxargs Elf64_Auxargs #define Elf_Brandinfo Elf64_Brandinfo #endif static int elf_check_header __P((const Elf_Ehdr *hdr, int type)); static int elf_freebsd_fixup __P((long **stack_base, struct image_params *imgp)); static int elf_load_file __P((struct proc *p, char *file, u_long *addr, u_long *entry)); static int elf_load_section __P((struct vmspace *vmspace, struct vnode *vp, vm_offset_t offset, caddr_t vmaddr, size_t memsz, size_t filsz, vm_prot_t prot)); static int exec_elf_imgact __P((struct image_params *imgp)); static int elf_trace = 0; SYSCTL_INT(_debug, OID_AUTO, elf_trace, CTLFLAG_RW, &elf_trace, 0, ""); #define UPRINTF if (elf_trace) uprintf static struct sysentvec elf_freebsd_sysvec = { SYS_MAXSYSCALL, sysent, 0, 0, 0, 0, 0, 0, elf_freebsd_fixup, sendsig, sigcode, &szsigcode, 0, "FreeBSD ELF", elf_coredump }; static Elf_Brandinfo freebsd_brand_info = { "FreeBSD", "", "/usr/libexec/ld-elf.so.1", &elf_freebsd_sysvec }; static Elf_Brandinfo *elf_brand_list[MAX_BRANDS] = { &freebsd_brand_info, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; int elf_insert_brand_entry(Elf_Brandinfo *entry) { int i; for (i=1; ie_ident[EI_MAG0] == ELFMAG0 && hdr->e_ident[EI_MAG1] == ELFMAG1 && hdr->e_ident[EI_MAG2] == ELFMAG2 && hdr->e_ident[EI_MAG3] == ELFMAG3)) return ENOEXEC; #ifdef __i386__ if (hdr->e_machine != EM_386 && hdr->e_machine != EM_486) #endif #ifdef __alpha__ if (hdr->e_machine != EM_ALPHA) #endif return ENOEXEC; if (hdr->e_type != type) return ENOEXEC; return 0; } static int elf_load_section(struct vmspace *vmspace, struct vnode *vp, vm_offset_t offset, caddr_t vmaddr, size_t memsz, size_t filsz, vm_prot_t prot) { size_t map_len; vm_offset_t map_addr; int error; unsigned char *data_buf = 0; size_t copy_len; map_addr = trunc_page(vmaddr); if (memsz > filsz) map_len = trunc_page(offset+filsz) - trunc_page(offset); else map_len = round_page(offset+filsz) - trunc_page(offset); if (error = vm_mmap (&vmspace->vm_map, &map_addr, map_len, prot, VM_PROT_ALL, MAP_PRIVATE | MAP_FIXED, (caddr_t)vp, trunc_page(offset))) return error; if (memsz == filsz) return 0; /* * We have to map the remaining bit of the file into the kernel's * memory map, allocate some anonymous memory, and copy that last * bit into it. The remaining space should be .bss... */ copy_len = (offset + filsz) - trunc_page(offset + filsz); map_addr = trunc_page(vmaddr + filsz); map_len = round_page(vmaddr + memsz) - map_addr; if (map_len != 0) { if (error = vm_map_find(&vmspace->vm_map, NULL, 0, &map_addr, map_len, FALSE, VM_PROT_ALL, VM_PROT_ALL,0)) return error; } if (error = vm_mmap(exec_map, (vm_offset_t *)&data_buf, PAGE_SIZE, VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vp, trunc_page(offset + filsz))) return error; error = copyout(data_buf, (caddr_t)map_addr, copy_len); vm_map_remove(exec_map, (vm_offset_t)data_buf, (vm_offset_t)data_buf + PAGE_SIZE); /* * set it to the specified protection */ vm_map_protect(&vmspace->vm_map, map_addr, map_addr + map_len, prot, FALSE); UPRINTF("bss size %d (%x)\n", map_len-copy_len, map_len-copy_len); return error; } static int elf_load_file(struct proc *p, char *file, u_long *addr, u_long *entry) { Elf_Ehdr *hdr = NULL; Elf_Phdr *phdr = NULL; struct nameidata nd; struct vmspace *vmspace = p->p_vmspace; struct vattr attr; struct image_params image_params, *imgp; vm_prot_t prot = 0; unsigned long text_size = 0, data_size = 0; unsigned long text_addr = 0, data_addr = 0; int header_size = 0; int error, i; imgp = &image_params; /* * Initialize part of the common data */ imgp->proc = p; imgp->uap = NULL; imgp->attr = &attr; imgp->firstpage = NULL; imgp->image_header = (char *)kmem_alloc_wait(exec_map, PAGE_SIZE); if (imgp->image_header == NULL) { nd.ni_vp = NULL; error = ENOMEM; goto fail; } NDINIT(&nd, LOOKUP, LOCKLEAF|FOLLOW, UIO_SYSSPACE, file, p); if (error = namei(&nd)) { nd.ni_vp = NULL; goto fail; } imgp->vp = nd.ni_vp; /* * Check permissions, modes, uid, etc on the file, and "open" it. */ error = exec_check_permissions(imgp); if (error) { VOP_UNLOCK(nd.ni_vp, 0, p); goto fail; } error = exec_map_first_page(imgp); VOP_UNLOCK(nd.ni_vp, 0, p); if (error) goto fail; hdr = (Elf_Ehdr *)imgp->image_header; if (error = elf_check_header(hdr, ET_DYN)) goto fail; /* * ouch, need to bounds check in case user gives us a corrupted * file with an insane header size */ if (hdr->e_phnum > MAX_PHDR) { /* XXX: ever more than this? */ error = ENOEXEC; goto fail; } header_size = hdr->e_phentsize * hdr->e_phnum; /* Only support headers that fit within first page for now */ if (header_size + hdr->e_phoff > PAGE_SIZE) { error = ENOEXEC; goto fail; } phdr = (Elf_Phdr *)(imgp->image_header + hdr->e_phoff); for (i = 0; i < hdr->e_phnum; i++) { switch(phdr[i].p_type) { case PT_NULL: /* NULL section */ UPRINTF ("ELF(file) PT_NULL section\n"); break; case PT_LOAD: /* Loadable segment */ { UPRINTF ("ELF(file) PT_LOAD section "); if (phdr[i].p_flags & PF_X) prot |= VM_PROT_EXECUTE; if (phdr[i].p_flags & PF_W) prot |= VM_PROT_WRITE; if (phdr[i].p_flags & PF_R) prot |= VM_PROT_READ; if (error = elf_load_section(vmspace, nd.ni_vp, phdr[i].p_offset, (caddr_t)phdr[i].p_vaddr + (*addr), phdr[i].p_memsz, phdr[i].p_filesz, prot)) goto fail; /* * Is this .text or .data ?? * * We only handle one each of those yet XXX */ if (hdr->e_entry >= phdr[i].p_vaddr && hdr->e_entry <(phdr[i].p_vaddr+phdr[i].p_memsz)) { text_addr = trunc_page(phdr[i].p_vaddr+(*addr)); text_size = round_page(phdr[i].p_memsz + phdr[i].p_vaddr - trunc_page(phdr[i].p_vaddr)); *entry=(unsigned long)hdr->e_entry+(*addr); UPRINTF(".text <%08lx,%08lx> entry=%08lx\n", text_addr, text_size, *entry); } else { data_addr = trunc_page(phdr[i].p_vaddr+(*addr)); data_size = round_page(phdr[i].p_memsz + phdr[i].p_vaddr - trunc_page(phdr[i].p_vaddr)); UPRINTF(".data <%08lx,%08lx>\n", data_addr, data_size); } } break; case PT_DYNAMIC:/* Dynamic link information */ UPRINTF ("ELF(file) PT_DYNAMIC section\n"); break; case PT_INTERP: /* Path to interpreter */ UPRINTF ("ELF(file) PT_INTERP section\n"); break; case PT_NOTE: /* Note section */ UPRINTF ("ELF(file) PT_NOTE section\n"); break; case PT_SHLIB: /* Shared lib section */ UPRINTF ("ELF(file) PT_SHLIB section\n"); break; case PT_PHDR: /* Program header table info */ UPRINTF ("ELF(file) PT_PHDR section\n"); break; default: UPRINTF ("ELF(file) %d section ??\n", phdr[i].p_type ); } } fail: if (imgp->firstpage) exec_unmap_first_page(imgp); if (imgp->image_header) kmem_free_wakeup(exec_map, (vm_offset_t)imgp->image_header, PAGE_SIZE); if (nd.ni_vp) vrele(nd.ni_vp); return error; } static int exec_elf_imgact(struct image_params *imgp) { const Elf_Ehdr *hdr = (const Elf_Ehdr *) imgp->image_header; const Elf_Phdr *phdr, *mapped_phdr = NULL; Elf_Auxargs *elf_auxargs = NULL; struct vmspace *vmspace; vm_prot_t prot = 0; u_long text_size = 0, data_size = 0; u_long text_addr = 0, data_addr = 0; u_long addr, entry = 0, proghdr = 0; int error, i, header_size = 0; const char *interp = NULL; char *brand = NULL; char path[MAXPATHLEN]; /* * Do we have a valid ELF header ? */ if (elf_check_header(hdr, ET_EXEC)) return -1; /* * From here on down, we return an errno, not -1, as we've * detected an ELF file. */ /* * ouch, need to bounds check in case user gives us a corrupted * file with an insane header size */ if (hdr->e_phnum > MAX_PHDR) { /* XXX: ever more than this? */ return ENOEXEC; } header_size = hdr->e_phentsize * hdr->e_phnum; if ((hdr->e_phoff > PAGE_SIZE) || (hdr->e_phoff + header_size) > PAGE_SIZE) { /* Only support headers in first page for now */ return ENOEXEC; } else { phdr = (const Elf_Phdr*) ((const char *)imgp->image_header + hdr->e_phoff); } /* * From this point on, we may have resources that need to be freed. */ if (error = exec_extract_strings(imgp)) goto fail; exec_new_vmspace(imgp); vmspace = imgp->proc->p_vmspace; for (i = 0; i < hdr->e_phnum; i++) { switch(phdr[i].p_type) { case PT_NULL: /* NULL section */ UPRINTF ("ELF PT_NULL section\n"); break; case PT_LOAD: /* Loadable segment */ { UPRINTF ("ELF PT_LOAD section "); if (phdr[i].p_flags & PF_X) prot |= VM_PROT_EXECUTE; if (phdr[i].p_flags & PF_W) prot |= VM_PROT_WRITE; if (phdr[i].p_flags & PF_R) prot |= VM_PROT_READ; if (error = elf_load_section(vmspace, imgp->vp, phdr[i].p_offset, (caddr_t)phdr[i].p_vaddr, phdr[i].p_memsz, phdr[i].p_filesz, prot)) goto fail; /* * Is this .text or .data ?? * * We only handle one each of those yet XXX */ if (hdr->e_entry >= phdr[i].p_vaddr && hdr->e_entry <(phdr[i].p_vaddr+phdr[i].p_memsz)) { text_addr = trunc_page(phdr[i].p_vaddr); text_size = round_page(phdr[i].p_memsz + phdr[i].p_vaddr - text_addr); entry = (u_long)hdr->e_entry; UPRINTF(".text <%08lx,%08lx> entry=%08lx\n", text_addr, text_size, entry); } else { data_addr = trunc_page(phdr[i].p_vaddr); data_size = round_page(phdr[i].p_memsz + phdr[i].p_vaddr - data_addr); UPRINTF(".data <%08lx,%08lx>\n", data_addr, data_size); } } break; case PT_DYNAMIC:/* Dynamic link information */ UPRINTF ("ELF PT_DYNAMIC section ??\n"); break; case PT_INTERP: /* Path to interpreter */ UPRINTF ("ELF PT_INTERP section "); if (phdr[i].p_filesz > MAXPATHLEN || phdr[i].p_offset + phdr[i].p_filesz > PAGE_SIZE) { error = ENOEXEC; goto fail; } interp = imgp->image_header + phdr[i].p_offset; UPRINTF("<%s>\n", interp); break; case PT_NOTE: /* Note section */ UPRINTF ("ELF PT_NOTE section\n"); break; case PT_SHLIB: /* Shared lib section */ UPRINTF ("ELF PT_SHLIB section\n"); break; case PT_PHDR: /* Program header table info */ UPRINTF ("ELF PT_PHDR section <%x>\n", phdr[i].p_vaddr); proghdr = phdr[i].p_vaddr; break; default: UPRINTF ("ELF %d section ??\n", phdr[i].p_type); } } vmspace->vm_tsize = text_size >> PAGE_SHIFT; vmspace->vm_taddr = (caddr_t)(uintptr_t)text_addr; vmspace->vm_dsize = data_size >> PAGE_SHIFT; vmspace->vm_daddr = (caddr_t)(uintptr_t)data_addr; addr = 2L*MAXDSIZ; /* May depend on OS type XXX */ imgp->entry_addr = entry; /* * So which kind (brand) of ELF binary do we have at hand * FreeBSD, Linux, SVR4 or something else ?? * If its has a interpreter section try that first */ if (interp) { for (i=0; iinterp_path)) { imgp->proc->p_sysent = elf_brand_list[i]->sysvec; strcpy(path, elf_brand_list[i]->emul_path); strcat(path, elf_brand_list[i]->interp_path); UPRINTF("interpreter=<%s> %s\n", elf_brand_list[i]->interp_path, elf_brand_list[i]->emul_path); break; } } } } /* * If there is no interpreter, or recognition of it * failed, se if the binary is branded. */ if (!interp || i == MAX_BRANDS) { brand = (char *)&(hdr->e_ident[EI_BRAND]); for (i=0; ibrand)) { imgp->proc->p_sysent = elf_brand_list[i]->sysvec; if (interp) { strcpy(path, elf_brand_list[i]->emul_path); strcat(path, elf_brand_list[i]->interp_path); UPRINTF("interpreter=<%s> %s\n", elf_brand_list[i]->interp_path, elf_brand_list[i]->emul_path); } break; } } } } if (i == MAX_BRANDS) { #ifndef __alpha__ uprintf("ELF binary type not known\n"); error = ENOEXEC; goto fail; #else i = 0; /* assume freebsd */ imgp->proc->p_sysent = elf_brand_list[i]->sysvec; if (interp) { strcpy(path, elf_brand_list[i]->emul_path); strcat(path, elf_brand_list[i]->interp_path); UPRINTF("interpreter=<%s> %s\n", elf_brand_list[i]->interp_path, elf_brand_list[i]->emul_path); } #endif } if (interp) { if (error = elf_load_file(imgp->proc, path, &addr, /* XXX */ &imgp->entry_addr)) { uprintf("ELF interpreter %s not found\n", path); goto fail; } } UPRINTF("Executing %s binary\n", elf_brand_list[i]->brand); /* * Construct auxargs table (used by the fixup routine) */ elf_auxargs = malloc(sizeof(Elf_Auxargs), M_TEMP, M_WAITOK); elf_auxargs->execfd = -1; elf_auxargs->phdr = proghdr; elf_auxargs->phent = hdr->e_phentsize; elf_auxargs->phnum = hdr->e_phnum; elf_auxargs->pagesz = PAGE_SIZE; elf_auxargs->base = addr; elf_auxargs->flags = 0; elf_auxargs->entry = entry; elf_auxargs->trace = elf_trace; imgp->auxargs = elf_auxargs; imgp->interpreted = 0; /* don't allow modifying the file while we run it */ imgp->vp->v_flag |= VTEXT; fail: return error; } static int elf_freebsd_fixup(long **stack_base, struct image_params *imgp) { Elf_Auxargs *args = (Elf_Auxargs *)imgp->auxargs; long *pos; pos = *stack_base + (imgp->argc + imgp->envc + 2); if (args->trace) { AUXARGS_ENTRY(pos, AT_DEBUG, 1); } if (args->execfd != -1) { AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd); } AUXARGS_ENTRY(pos, AT_PHDR, args->phdr); AUXARGS_ENTRY(pos, AT_PHENT, args->phent); AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum); AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz); AUXARGS_ENTRY(pos, AT_FLAGS, args->flags); AUXARGS_ENTRY(pos, AT_ENTRY, args->entry); AUXARGS_ENTRY(pos, AT_BASE, args->base); AUXARGS_ENTRY(pos, AT_NULL, 0); free(imgp->auxargs, M_TEMP); imgp->auxargs = NULL; (*stack_base)--; **stack_base = (long)imgp->argc; return 0; } /* * Code for generating ELF core dumps. */ typedef void (*segment_callback) __P((vm_map_entry_t, void *)); /* Closure for cb_put_phdr(). */ struct phdr_closure { Elf_Phdr *phdr; /* Program header to fill in */ Elf_Off offset; /* Offset of segment in core file */ }; /* Closure for cb_size_segment(). */ struct sseg_closure { int count; /* Count of writable segments. */ size_t size; /* Total size of all writable segments. */ }; static void cb_put_phdr __P((vm_map_entry_t, void *)); static void cb_size_segment __P((vm_map_entry_t, void *)); static void each_writable_segment __P((struct proc *, segment_callback, void *)); static int elf_corehdr __P((struct proc *, struct vnode *, struct ucred *, int, void *, size_t)); static void elf_puthdr __P((struct proc *, void *, size_t *, const prstatus_t *, const prfpregset_t *, const prpsinfo_t *, int)); static void elf_putnote __P((void *, size_t *, const char *, int, const void *, size_t)); extern int osreldate; int elf_coredump(p) register struct proc *p; { register struct vnode *vp; register struct ucred *cred = p->p_cred->pc_ucred; register struct vmspace *vm = p->p_vmspace; struct nameidata nd; struct vattr vattr; int error, error1; char *name; /* name of corefile */ struct sseg_closure seginfo; void *hdr; size_t hdrsize; STOPEVENT(p, S_CORE, 0); if (sugid_coredump == 0 && p->p_flag & P_SUGID) return (EFAULT); /* Size the program segments. */ seginfo.count = 0; seginfo.size = 0; each_writable_segment(p, cb_size_segment, &seginfo); /* * Calculate the size of the core file header area by making * a dry run of generating it. Nothing is written, but the * size is calculated. */ hdrsize = 0; elf_puthdr((struct proc *)NULL, (void *)NULL, &hdrsize, (const prstatus_t *)NULL, (const prfpregset_t *)NULL, (const prpsinfo_t *)NULL, seginfo.count); if (hdrsize + seginfo.size >= p->p_rlimit[RLIMIT_CORE].rlim_cur) return (EFAULT); name = expand_name(p->p_comm, p->p_ucred->cr_uid, p->p_pid); if (name == NULL) return (EFAULT); /* XXX -- not the best error */ NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, name, p); error = vn_open(&nd, O_CREAT | FWRITE, S_IRUSR | S_IWUSR); free(name, M_TEMP); if (error) return (error); vp = nd.ni_vp; /* Don't dump to non-regular files or files with links. */ if (vp->v_type != VREG || VOP_GETATTR(vp, &vattr, cred, p) || vattr.va_nlink != 1) { error = EFAULT; goto out; } VATTR_NULL(&vattr); vattr.va_size = 0; VOP_LEASE(vp, p, cred, LEASE_WRITE); VOP_SETATTR(vp, &vattr, cred, p); p->p_acflag |= ACORE; /* * Allocate memory for building the header, fill it up, * and write it out. */ hdr = malloc(hdrsize, M_TEMP, M_WAITOK); if (hdr == NULL) { error = EINVAL; goto out; } error = elf_corehdr(p, vp, cred, seginfo.count, hdr, hdrsize); /* Write the contents of all of the writable segments. */ if (error == 0) { Elf_Phdr *php; off_t offset; int i; php = (Elf_Phdr *)((char *)hdr + sizeof(Elf_Ehdr)) + 1; offset = hdrsize; for (i = 0; i < seginfo.count; i++) { error = vn_rdwr(UIO_WRITE, vp, (caddr_t)php->p_vaddr, php->p_filesz, offset, UIO_USERSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *)NULL, p); if (error != 0) break; offset += php->p_filesz; php++; } } free(hdr, M_TEMP); out: VOP_UNLOCK(vp, 0, p); error1 = vn_close(vp, FWRITE, cred, p); if (error == 0) error = error1; return (error); } /* * A callback for each_writable_segment() to write out the segment's * program header entry. */ static void cb_put_phdr(entry, closure) vm_map_entry_t entry; void *closure; { struct phdr_closure *phc = (struct phdr_closure *)closure; Elf_Phdr *phdr = phc->phdr; phc->offset = round_page(phc->offset); phdr->p_type = PT_LOAD; phdr->p_offset = phc->offset; phdr->p_vaddr = entry->start; phdr->p_paddr = 0; phdr->p_filesz = phdr->p_memsz = entry->end - entry->start; phdr->p_align = PAGE_SIZE; phdr->p_flags = 0; if (entry->protection & VM_PROT_READ) phdr->p_flags |= PF_R; if (entry->protection & VM_PROT_WRITE) phdr->p_flags |= PF_W; if (entry->protection & VM_PROT_EXECUTE) phdr->p_flags |= PF_X; phc->offset += phdr->p_filesz; phc->phdr++; } /* * A callback for each_writable_segment() to gather information about * the number of segments and their total size. */ static void cb_size_segment(entry, closure) vm_map_entry_t entry; void *closure; { struct sseg_closure *ssc = (struct sseg_closure *)closure; ssc->count++; ssc->size += entry->end - entry->start; } /* * For each writable segment in the process's memory map, call the given * function with a pointer to the map entry and some arbitrary * caller-supplied data. */ static void each_writable_segment(p, func, closure) struct proc *p; segment_callback func; void *closure; { vm_map_t map = &p->p_vmspace->vm_map; vm_map_entry_t entry; for (entry = map->header.next; entry != &map->header; entry = entry->next) { vm_object_t obj; if (entry->eflags & (MAP_ENTRY_IS_A_MAP|MAP_ENTRY_IS_SUB_MAP) || (entry->protection & (VM_PROT_READ|VM_PROT_WRITE)) != (VM_PROT_READ|VM_PROT_WRITE)) continue; if ((obj = entry->object.vm_object) == NULL) continue; /* Find the deepest backing object. */ while (obj->backing_object != NULL) obj = obj->backing_object; /* Ignore memory-mapped devices and such things. */ if (obj->type != OBJT_DEFAULT && obj->type != OBJT_SWAP && obj->type != OBJT_VNODE) continue; (*func)(entry, closure); } } /* * Write the core file header to the file, including padding up to * the page boundary. */ static int elf_corehdr(p, vp, cred, numsegs, hdr, hdrsize) struct proc *p; struct vnode *vp; struct ucred *cred; int numsegs; size_t hdrsize; void *hdr; { struct vmspace *vm = p->p_vmspace; size_t off; prstatus_t status; prfpregset_t fpregset; prpsinfo_t psinfo; /* Gather the information for the header. */ bzero(&status, sizeof status); 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_sigacts->ps_sig; status.pr_pid = p->p_pid; fill_regs(p, &status.pr_reg); fill_fpregs(p, &fpregset); bzero(&psinfo, sizeof psinfo); psinfo.pr_version = PRPSINFO_VERSION; psinfo.pr_psinfosz = sizeof(prpsinfo_t); strncpy(psinfo.pr_fname, p->p_comm, MAXCOMLEN); /* XXX - We don't fill in the command line arguments properly yet. */ strncpy(psinfo.pr_psargs, p->p_comm, PRARGSZ); /* Fill in the header. */ bzero(hdr, hdrsize); off = 0; elf_puthdr(p, hdr, &off, &status, &fpregset, &psinfo, numsegs); /* Write it to the core file. */ return vn_rdwr(UIO_WRITE, vp, hdr, hdrsize, (off_t)0, UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, NULL, p); } static void elf_puthdr(struct proc *p, void *dst, size_t *off, const prstatus_t *status, const prfpregset_t *fpregset, const prpsinfo_t *psinfo, int numsegs) { size_t ehoff; size_t phoff; size_t noteoff; size_t notesz; ehoff = *off; *off += sizeof(Elf_Ehdr); phoff = *off; *off += (numsegs + 1) * sizeof(Elf_Phdr); noteoff = *off; elf_putnote(dst, off, "FreeBSD", NT_PRSTATUS, status, sizeof *status); elf_putnote(dst, off, "FreeBSD", NT_FPREGSET, fpregset, sizeof *fpregset); elf_putnote(dst, off, "FreeBSD", NT_PRPSINFO, psinfo, sizeof *psinfo); notesz = *off - noteoff; /* Align up to a page boundary for the program segments. */ *off = round_page(*off); if (dst != NULL) { Elf_Ehdr *ehdr; Elf_Phdr *phdr; struct phdr_closure phc; /* * Fill in the ELF header. */ ehdr = (Elf_Ehdr *)((char *)dst + ehoff); ehdr->e_ident[EI_MAG0] = ELFMAG0; ehdr->e_ident[EI_MAG1] = ELFMAG1; ehdr->e_ident[EI_MAG2] = ELFMAG2; ehdr->e_ident[EI_MAG3] = ELFMAG3; ehdr->e_ident[EI_CLASS] = ELF_CLASS; ehdr->e_ident[EI_DATA] = ELF_DATA; ehdr->e_ident[EI_VERSION] = EV_CURRENT; ehdr->e_ident[EI_PAD] = 0; strncpy(ehdr->e_ident + EI_BRAND, "FreeBSD", EI_NIDENT - EI_BRAND); ehdr->e_type = ET_CORE; ehdr->e_machine = ELF_ARCH; ehdr->e_version = EV_CURRENT; ehdr->e_entry = 0; ehdr->e_phoff = phoff; ehdr->e_flags = 0; ehdr->e_ehsize = sizeof(Elf_Ehdr); ehdr->e_phentsize = sizeof(Elf_Phdr); ehdr->e_phnum = numsegs + 1; ehdr->e_shentsize = sizeof(Elf_Shdr); ehdr->e_shnum = 0; ehdr->e_shstrndx = SHN_UNDEF; /* * Fill in the program header entries. */ phdr = (Elf_Phdr *)((char *)dst + phoff); /* The note segement. */ phdr->p_type = PT_NOTE; phdr->p_offset = noteoff; phdr->p_vaddr = 0; phdr->p_paddr = 0; phdr->p_filesz = notesz; phdr->p_memsz = 0; phdr->p_flags = 0; phdr->p_align = 0; phdr++; /* All the writable segments from the program. */ phc.phdr = phdr; phc.offset = *off; each_writable_segment(p, cb_put_phdr, &phc); } } static void elf_putnote(void *dst, size_t *off, const char *name, int type, const void *desc, size_t descsz) { Elf_Note note; note.n_namesz = strlen(name) + 1; note.n_descsz = descsz; note.n_type = type; if (dst != NULL) bcopy(¬e, (char *)dst + *off, sizeof note); *off += sizeof note; if (dst != NULL) bcopy(name, (char *)dst + *off, note.n_namesz); *off += roundup2(note.n_namesz, sizeof(Elf_Size)); if (dst != NULL) bcopy(desc, (char *)dst + *off, note.n_descsz); *off += roundup2(note.n_descsz, sizeof(Elf_Size)); } /* * Tell kern_execve.c about it, with a little help from the linker. * Since `const' objects end up in the text segment, TEXT_SET is the * correct directive to use. */ static const struct execsw elf_execsw = {exec_elf_imgact, "ELF"}; TEXT_SET(execsw_set, elf_execsw);