elfcore.c revision 76224
140525Sjdp/*- 240525Sjdp * Copyright (c) 1998 John D. Polstra 340525Sjdp * All rights reserved. 440525Sjdp * 540525Sjdp * Redistribution and use in source and binary forms, with or without 640525Sjdp * modification, are permitted provided that the following conditions 740525Sjdp * are met: 840525Sjdp * 1. Redistributions of source code must retain the above copyright 940525Sjdp * notice, this list of conditions and the following disclaimer. 1040525Sjdp * 2. Redistributions in binary form must reproduce the above copyright 1140525Sjdp * notice, this list of conditions and the following disclaimer in the 1240525Sjdp * documentation and/or other materials provided with the distribution. 1340525Sjdp * 1440525Sjdp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1540525Sjdp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1640525Sjdp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1740525Sjdp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1840525Sjdp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1940525Sjdp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2040525Sjdp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2140525Sjdp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2240525Sjdp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2340525Sjdp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2440525Sjdp * SUCH DAMAGE. 2540525Sjdp * 2650477Speter * $FreeBSD: head/usr.bin/gcore/elfcore.c 76224 2001-05-02 23:56:21Z obrien $ 2740525Sjdp */ 2840525Sjdp 2940525Sjdp#include <sys/param.h> 3040525Sjdp#include <sys/lock.h> 3140525Sjdp#include <sys/procfs.h> 3276224Sobrien#include <machine/elf.h> 3340525Sjdp#include <vm/vm_param.h> 3440525Sjdp#include <vm/vm.h> 3540525Sjdp#include <vm/pmap.h> 3640525Sjdp#include <vm/vm_map.h> 3740525Sjdp#include <err.h> 3840525Sjdp#include <errno.h> 3940525Sjdp#include <fcntl.h> 4040525Sjdp#include <stdio.h> 4140525Sjdp#include <stdlib.h> 4240525Sjdp#include <string.h> 4340525Sjdp#include <unistd.h> 4440525Sjdp 4540525Sjdp#include "extern.h" 4640525Sjdp 4740525Sjdp/* 4840525Sjdp * Code for generating ELF core dumps. 4940525Sjdp */ 5040525Sjdp 5140525Sjdptypedef void (*segment_callback)(vm_map_entry_t, void *); 5240525Sjdp 5340525Sjdp/* Closure for cb_put_phdr(). */ 5440525Sjdpstruct phdr_closure { 5540525Sjdp Elf_Phdr *phdr; /* Program header to fill in */ 5640525Sjdp Elf_Off offset; /* Offset of segment in core file */ 5740525Sjdp}; 5840525Sjdp 5940525Sjdp/* Closure for cb_size_segment(). */ 6040525Sjdpstruct sseg_closure { 6140525Sjdp int count; /* Count of writable segments. */ 6240525Sjdp size_t size; /* Total size of all writable segments. */ 6340525Sjdp}; 6440525Sjdp 6540525Sjdpstatic void cb_put_phdr(vm_map_entry_t, void *); 6640525Sjdpstatic void cb_size_segment(vm_map_entry_t, void *); 6740525Sjdpstatic void each_writable_segment(vm_map_entry_t, segment_callback, 6840525Sjdp void *closure); 6940525Sjdpstatic void elf_corehdr(int fd, pid_t, vm_map_entry_t, int numsegs, 7040525Sjdp void *hdr, size_t hdrsize); 7140525Sjdpstatic void elf_puthdr(vm_map_entry_t, void *, size_t *, 7240525Sjdp const prstatus_t *, const prfpregset_t *, const prpsinfo_t *, int numsegs); 7340525Sjdpstatic void elf_putnote(void *dst, size_t *off, const char *name, int type, 7440525Sjdp const void *desc, size_t descsz); 7540525Sjdpstatic void freemap(vm_map_entry_t); 7640525Sjdpstatic void readhdrinfo(pid_t, prstatus_t *, prfpregset_t *, prpsinfo_t *); 7740525Sjdpstatic vm_map_entry_t readmap(pid_t); 7840525Sjdp 7940525Sjdp/* 8040525Sjdp * Write an ELF coredump for the given pid to the given fd. 8140525Sjdp */ 8240525Sjdpvoid 8340525Sjdpelf_coredump(int fd, pid_t pid) 8440525Sjdp{ 8540525Sjdp vm_map_entry_t map; 8640525Sjdp struct sseg_closure seginfo; 8740525Sjdp void *hdr; 8840525Sjdp size_t hdrsize; 8940525Sjdp char memname[64]; 9040525Sjdp int memfd; 9140525Sjdp Elf_Phdr *php; 9240525Sjdp int i; 9340525Sjdp 9440525Sjdp /* Get the program's memory map. */ 9540525Sjdp map = readmap(pid); 9640525Sjdp 9740525Sjdp /* Size the program segments. */ 9840525Sjdp seginfo.count = 0; 9940525Sjdp seginfo.size = 0; 10040525Sjdp each_writable_segment(map, cb_size_segment, &seginfo); 10140525Sjdp 10240525Sjdp /* 10340525Sjdp * Calculate the size of the core file header area by making 10440525Sjdp * a dry run of generating it. Nothing is written, but the 10540525Sjdp * size is calculated. 10640525Sjdp */ 10740525Sjdp hdrsize = 0; 10840525Sjdp elf_puthdr(map, (void *)NULL, &hdrsize, 10940525Sjdp (const prstatus_t *)NULL, (const prfpregset_t *)NULL, 11040525Sjdp (const prpsinfo_t *)NULL, seginfo.count); 11140525Sjdp 11240525Sjdp /* 11340525Sjdp * Allocate memory for building the header, fill it up, 11440525Sjdp * and write it out. 11540525Sjdp */ 11640525Sjdp hdr = malloc(hdrsize); 11740525Sjdp if ((hdr = malloc(hdrsize)) == NULL) 11840525Sjdp errx(1, "out of memory"); 11940525Sjdp elf_corehdr(fd, pid, map, seginfo.count, hdr, hdrsize); 12040525Sjdp 12140525Sjdp /* Write the contents of all of the writable segments. */ 12240525Sjdp snprintf(memname, sizeof memname, "/proc/%d/mem", pid); 12340525Sjdp if ((memfd = open(memname, O_RDONLY)) == -1) 12440525Sjdp err(1, "cannot open %s", memname); 12540525Sjdp 12640525Sjdp php = (Elf_Phdr *)((char *)hdr + sizeof(Elf_Ehdr)) + 1; 12740525Sjdp for (i = 0; i < seginfo.count; i++) { 12840525Sjdp int nleft = php->p_filesz; 12940525Sjdp 13040525Sjdp lseek(memfd, (off_t)php->p_vaddr, SEEK_SET); 13140525Sjdp while (nleft > 0) { 13240525Sjdp char buf[8*1024]; 13340525Sjdp int nwant; 13440525Sjdp int ngot; 13540525Sjdp 13640525Sjdp nwant = nleft; 13740525Sjdp if (nwant > sizeof buf) 13840525Sjdp nwant = sizeof buf; 13940525Sjdp ngot = read(memfd, buf, nwant); 14040525Sjdp if (ngot == -1) 14140525Sjdp err(1, "read from %s", memname); 14240525Sjdp if (ngot < nwant) 14340525Sjdp errx(1, "short read from %s:" 14440803Sjdp " wanted %d, got %d\n", memname, 14540803Sjdp nwant, ngot); 14640525Sjdp ngot = write(fd, buf, nwant); 14740525Sjdp if (ngot == -1) 14840525Sjdp err(1, "write of segment %d failed", i); 14940525Sjdp if (ngot != nwant) 15040525Sjdp errx(1, "short write"); 15140525Sjdp nleft -= nwant; 15240525Sjdp } 15340525Sjdp php++; 15440525Sjdp } 15540525Sjdp close(memfd); 15640525Sjdp free(hdr); 15740525Sjdp freemap(map); 15840525Sjdp} 15940525Sjdp 16040525Sjdp/* 16140525Sjdp * A callback for each_writable_segment() to write out the segment's 16240525Sjdp * program header entry. 16340525Sjdp */ 16440525Sjdpstatic void 16540525Sjdpcb_put_phdr(vm_map_entry_t entry, void *closure) 16640525Sjdp{ 16740525Sjdp struct phdr_closure *phc = (struct phdr_closure *)closure; 16840525Sjdp Elf_Phdr *phdr = phc->phdr; 16940525Sjdp 17040525Sjdp phc->offset = round_page(phc->offset); 17140525Sjdp 17240525Sjdp phdr->p_type = PT_LOAD; 17340525Sjdp phdr->p_offset = phc->offset; 17440525Sjdp phdr->p_vaddr = entry->start; 17540525Sjdp phdr->p_paddr = 0; 17640525Sjdp phdr->p_filesz = phdr->p_memsz = entry->end - entry->start; 17740525Sjdp phdr->p_align = PAGE_SIZE; 17840525Sjdp phdr->p_flags = 0; 17940525Sjdp if (entry->protection & VM_PROT_READ) 18040525Sjdp phdr->p_flags |= PF_R; 18140525Sjdp if (entry->protection & VM_PROT_WRITE) 18240525Sjdp phdr->p_flags |= PF_W; 18340525Sjdp if (entry->protection & VM_PROT_EXECUTE) 18440525Sjdp phdr->p_flags |= PF_X; 18540525Sjdp 18640525Sjdp phc->offset += phdr->p_filesz; 18740525Sjdp phc->phdr++; 18840525Sjdp} 18940525Sjdp 19040525Sjdp/* 19140525Sjdp * A callback for each_writable_segment() to gather information about 19240525Sjdp * the number of segments and their total size. 19340525Sjdp */ 19440525Sjdpstatic void 19540525Sjdpcb_size_segment(vm_map_entry_t entry, void *closure) 19640525Sjdp{ 19740525Sjdp struct sseg_closure *ssc = (struct sseg_closure *)closure; 19840525Sjdp 19940525Sjdp ssc->count++; 20040525Sjdp ssc->size += entry->end - entry->start; 20140525Sjdp} 20240525Sjdp 20340525Sjdp/* 20440525Sjdp * For each segment in the given memory map, call the given function 20540525Sjdp * with a pointer to the map entry and some arbitrary caller-supplied 20640525Sjdp * data. 20740525Sjdp */ 20840525Sjdpstatic void 20940525Sjdpeach_writable_segment(vm_map_entry_t map, segment_callback func, void *closure) 21040525Sjdp{ 21140525Sjdp vm_map_entry_t entry; 21240525Sjdp 21340525Sjdp for (entry = map; entry != NULL; entry = entry->next) 21440525Sjdp (*func)(entry, closure); 21540525Sjdp} 21640525Sjdp 21740525Sjdp/* 21840525Sjdp * Write the core file header to the file, including padding up to 21940525Sjdp * the page boundary. 22040525Sjdp */ 22140525Sjdpstatic void 22240525Sjdpelf_corehdr(int fd, pid_t pid, vm_map_entry_t map, int numsegs, void *hdr, 22340525Sjdp size_t hdrsize) 22440525Sjdp{ 22540525Sjdp size_t off; 22640525Sjdp prstatus_t status; 22740525Sjdp prfpregset_t fpregset; 22840525Sjdp prpsinfo_t psinfo; 22940525Sjdp 23040525Sjdp /* Gather the information for the header. */ 23140525Sjdp readhdrinfo(pid, &status, &fpregset, &psinfo); 23240525Sjdp 23340525Sjdp /* Fill in the header. */ 23440525Sjdp memset(hdr, 0, hdrsize); 23540525Sjdp off = 0; 23640525Sjdp elf_puthdr(map, hdr, &off, &status, &fpregset, &psinfo, numsegs); 23740525Sjdp 23840525Sjdp /* Write it to the core file. */ 23940525Sjdp if (write(fd, hdr, hdrsize) == -1) 24040525Sjdp err(1, "write"); 24140525Sjdp} 24240525Sjdp 24340525Sjdp/* 24440525Sjdp * Generate the ELF coredump header into the buffer at "dst". "dst" may 24540525Sjdp * be NULL, in which case the header is sized but not actually generated. 24640525Sjdp */ 24740525Sjdpstatic void 24840525Sjdpelf_puthdr(vm_map_entry_t map, void *dst, size_t *off, const prstatus_t *status, 24940525Sjdp const prfpregset_t *fpregset, const prpsinfo_t *psinfo, int numsegs) 25040525Sjdp{ 25140525Sjdp size_t ehoff; 25240525Sjdp size_t phoff; 25340525Sjdp size_t noteoff; 25440525Sjdp size_t notesz; 25540525Sjdp 25640525Sjdp ehoff = *off; 25740525Sjdp *off += sizeof(Elf_Ehdr); 25840525Sjdp 25940525Sjdp phoff = *off; 26040525Sjdp *off += (numsegs + 1) * sizeof(Elf_Phdr); 26140525Sjdp 26240525Sjdp noteoff = *off; 26340525Sjdp elf_putnote(dst, off, "FreeBSD", NT_PRSTATUS, status, 26440525Sjdp sizeof *status); 26540525Sjdp elf_putnote(dst, off, "FreeBSD", NT_FPREGSET, fpregset, 26640525Sjdp sizeof *fpregset); 26740525Sjdp elf_putnote(dst, off, "FreeBSD", NT_PRPSINFO, psinfo, 26840525Sjdp sizeof *psinfo); 26940525Sjdp notesz = *off - noteoff; 27040525Sjdp 27140525Sjdp /* Align up to a page boundary for the program segments. */ 27240525Sjdp *off = round_page(*off); 27340525Sjdp 27440525Sjdp if (dst != NULL) { 27540525Sjdp Elf_Ehdr *ehdr; 27640525Sjdp Elf_Phdr *phdr; 27740525Sjdp struct phdr_closure phc; 27840525Sjdp 27940525Sjdp /* 28040525Sjdp * Fill in the ELF header. 28140525Sjdp */ 28240525Sjdp ehdr = (Elf_Ehdr *)((char *)dst + ehoff); 28340525Sjdp ehdr->e_ident[EI_MAG0] = ELFMAG0; 28440525Sjdp ehdr->e_ident[EI_MAG1] = ELFMAG1; 28540525Sjdp ehdr->e_ident[EI_MAG2] = ELFMAG2; 28640525Sjdp ehdr->e_ident[EI_MAG3] = ELFMAG3; 28740525Sjdp ehdr->e_ident[EI_CLASS] = ELF_CLASS; 28840525Sjdp ehdr->e_ident[EI_DATA] = ELF_DATA; 28940525Sjdp ehdr->e_ident[EI_VERSION] = EV_CURRENT; 29059342Sobrien ehdr->e_ident[EI_OSABI] = ELFOSABI_FREEBSD; 29159342Sobrien ehdr->e_ident[EI_ABIVERSION] = 0; 29240525Sjdp ehdr->e_ident[EI_PAD] = 0; 29340525Sjdp ehdr->e_type = ET_CORE; 29440525Sjdp ehdr->e_machine = ELF_ARCH; 29540525Sjdp ehdr->e_version = EV_CURRENT; 29640525Sjdp ehdr->e_entry = 0; 29740525Sjdp ehdr->e_phoff = phoff; 29840525Sjdp ehdr->e_flags = 0; 29940525Sjdp ehdr->e_ehsize = sizeof(Elf_Ehdr); 30040525Sjdp ehdr->e_phentsize = sizeof(Elf_Phdr); 30140525Sjdp ehdr->e_phnum = numsegs + 1; 30240525Sjdp ehdr->e_shentsize = sizeof(Elf_Shdr); 30340525Sjdp ehdr->e_shnum = 0; 30440525Sjdp ehdr->e_shstrndx = SHN_UNDEF; 30540525Sjdp 30640525Sjdp /* 30740525Sjdp * Fill in the program header entries. 30840525Sjdp */ 30940525Sjdp phdr = (Elf_Phdr *)((char *)dst + phoff); 31040525Sjdp 31140525Sjdp /* The note segement. */ 31240525Sjdp phdr->p_type = PT_NOTE; 31340525Sjdp phdr->p_offset = noteoff; 31440525Sjdp phdr->p_vaddr = 0; 31540525Sjdp phdr->p_paddr = 0; 31640525Sjdp phdr->p_filesz = notesz; 31740525Sjdp phdr->p_memsz = 0; 31840525Sjdp phdr->p_flags = 0; 31940525Sjdp phdr->p_align = 0; 32040525Sjdp phdr++; 32140525Sjdp 32240525Sjdp /* All the writable segments from the program. */ 32340525Sjdp phc.phdr = phdr; 32440525Sjdp phc.offset = *off; 32540525Sjdp each_writable_segment(map, cb_put_phdr, &phc); 32640525Sjdp } 32740525Sjdp} 32840525Sjdp 32940525Sjdp/* 33040525Sjdp * Emit one note section to "dst", or just size it if "dst" is NULL. 33140525Sjdp */ 33240525Sjdpstatic void 33340525Sjdpelf_putnote(void *dst, size_t *off, const char *name, int type, 33440525Sjdp const void *desc, size_t descsz) 33540525Sjdp{ 33640525Sjdp Elf_Note note; 33740525Sjdp 33840525Sjdp note.n_namesz = strlen(name) + 1; 33940525Sjdp note.n_descsz = descsz; 34040525Sjdp note.n_type = type; 34140525Sjdp if (dst != NULL) 34240525Sjdp bcopy(¬e, (char *)dst + *off, sizeof note); 34340525Sjdp *off += sizeof note; 34440525Sjdp if (dst != NULL) 34540525Sjdp bcopy(name, (char *)dst + *off, note.n_namesz); 34640525Sjdp *off += roundup2(note.n_namesz, sizeof(Elf_Size)); 34740525Sjdp if (dst != NULL) 34840525Sjdp bcopy(desc, (char *)dst + *off, note.n_descsz); 34940525Sjdp *off += roundup2(note.n_descsz, sizeof(Elf_Size)); 35040525Sjdp} 35140525Sjdp 35240525Sjdp/* 35340525Sjdp * Free the memory map. 35440525Sjdp */ 35540525Sjdpstatic void 35640525Sjdpfreemap(vm_map_entry_t map) 35740525Sjdp{ 35840525Sjdp while (map != NULL) { 35940525Sjdp vm_map_entry_t next = map->next; 36040525Sjdp free(map); 36140525Sjdp map = next; 36240525Sjdp } 36340525Sjdp} 36440525Sjdp 36540525Sjdp/* 36640525Sjdp * Read the process information necessary to fill in the core file's header. 36740525Sjdp */ 36840525Sjdpstatic void 36940525Sjdpreadhdrinfo(pid_t pid, prstatus_t *status, prfpregset_t *fpregset, 37040525Sjdp prpsinfo_t *psinfo) 37140525Sjdp{ 37240525Sjdp char name[64]; 37340525Sjdp char line[256]; 37440525Sjdp int fd; 37540525Sjdp int i; 37640525Sjdp int n; 37740525Sjdp 37840525Sjdp memset(status, 0, sizeof *status); 37940525Sjdp status->pr_version = PRSTATUS_VERSION; 38040525Sjdp status->pr_statussz = sizeof(prstatus_t); 38140525Sjdp status->pr_gregsetsz = sizeof(gregset_t); 38240525Sjdp status->pr_fpregsetsz = sizeof(fpregset_t); 38340525Sjdp status->pr_osreldate = __FreeBSD_version; 38440525Sjdp status->pr_pid = pid; 38540525Sjdp 38640525Sjdp memset(fpregset, 0, sizeof *fpregset); 38740525Sjdp 38840525Sjdp memset(psinfo, 0, sizeof *psinfo); 38940525Sjdp psinfo->pr_version = PRPSINFO_VERSION; 39040525Sjdp psinfo->pr_psinfosz = sizeof(prpsinfo_t); 39140525Sjdp 39240525Sjdp /* Read the general registers. */ 39340525Sjdp snprintf(name, sizeof name, "/proc/%d/regs", pid); 39440525Sjdp if ((fd = open(name, O_RDONLY)) == -1) 39540525Sjdp err(1, "cannot open %s", name); 39640525Sjdp if ((n = read(fd, &status->pr_reg, sizeof status->pr_reg)) == -1) 39740525Sjdp err(1, "read error from %s", name); 39840525Sjdp if (n < sizeof status->pr_reg) 39940525Sjdp errx(1, "short read from %s: wanted %u, got %d", name, 40040525Sjdp sizeof status->pr_reg, n); 40140525Sjdp close(fd); 40240525Sjdp 40340525Sjdp /* Read the floating point registers. */ 40440525Sjdp snprintf(name, sizeof name, "/proc/%d/fpregs", pid); 40540525Sjdp if ((fd = open(name, O_RDONLY)) == -1) 40640525Sjdp err(1, "cannot open %s", name); 40740525Sjdp if ((n = read(fd, fpregset, sizeof *fpregset)) == -1) 40840525Sjdp err(1, "read error from %s", name); 40940525Sjdp if (n < sizeof *fpregset) 41040525Sjdp errx(1, "short read from %s: wanted %u, got %d", name, 41140525Sjdp sizeof *fpregset, n); 41240525Sjdp close(fd); 41340525Sjdp 41440525Sjdp /* Read and parse the process status. */ 41540525Sjdp snprintf(name, sizeof name, "/proc/%d/status", pid); 41640525Sjdp if ((fd = open(name, O_RDONLY)) == -1) 41740525Sjdp err(1, "cannot open %s", name); 41840525Sjdp if ((n = read(fd, line, sizeof line - 1)) == -1) 41940525Sjdp err(1, "read error from %s", name); 42040525Sjdp if (n > MAXCOMLEN) 42140525Sjdp n = MAXCOMLEN; 42240525Sjdp for (i = 0; i < n && line[i] != ' '; i++) 42340525Sjdp psinfo->pr_fname[i] = line[i]; 42440525Sjdp strncpy(psinfo->pr_psargs, psinfo->pr_fname, PRARGSZ); 42540525Sjdp close(fd); 42640525Sjdp} 42740525Sjdp 42840525Sjdp/* 42940525Sjdp * Read the process's memory map using procfs, and return a list of 43040525Sjdp * VM map entries. Only the non-device read/writable segments are 43140525Sjdp * returned. The map entries in the list aren't fully filled in; only 43240525Sjdp * the items we need are present. 43340525Sjdp */ 43440525Sjdpstatic vm_map_entry_t 43540525Sjdpreadmap(pid_t pid) 43640525Sjdp{ 43740525Sjdp char mapname[64]; 43840525Sjdp int mapfd; 43940525Sjdp ssize_t mapsize; 44040525Sjdp size_t bufsize; 44140525Sjdp char *mapbuf; 44240525Sjdp int pos; 44340525Sjdp vm_map_entry_t map; 44440525Sjdp vm_map_entry_t *linkp; 44540525Sjdp 44640525Sjdp snprintf(mapname, sizeof mapname, "/proc/%d/map", pid); 44740525Sjdp if ((mapfd = open(mapname, O_RDONLY)) == -1) 44840525Sjdp err(1, "cannot open %s", mapname); 44940525Sjdp 45040525Sjdp /* 45140525Sjdp * Procfs requires (for consistency) that the entire memory map 45240525Sjdp * be read with a single read() call. Start with a reasonbly sized 45340525Sjdp * buffer, and double it until it is big enough. 45440525Sjdp */ 45540525Sjdp bufsize = 8 * 1024; 45640525Sjdp mapbuf = NULL; 45740525Sjdp for ( ; ; ) { 45840525Sjdp if ((mapbuf = realloc(mapbuf, bufsize)) == NULL) 45940525Sjdp errx(1, "out of memory"); 46040525Sjdp mapsize = read(mapfd, mapbuf, bufsize); 46140525Sjdp if (mapsize != -1 || errno != EFBIG) 46240525Sjdp break; 46340525Sjdp bufsize *= 2; 46440525Sjdp /* This lseek shouldn't be necessary, but it is. */ 46540525Sjdp lseek(mapfd, (off_t)0, SEEK_SET); 46640525Sjdp } 46740525Sjdp if (mapsize == -1) 46840525Sjdp err(1, "read error from %s", mapname); 46940525Sjdp if (mapsize == 0) 47040525Sjdp errx(1, "empty map file %s", mapname); 47140525Sjdp close(mapfd); 47240525Sjdp 47340525Sjdp pos = 0; 47440525Sjdp map = NULL; 47540525Sjdp linkp = ↦ 47640525Sjdp while (pos < mapsize) { 47740525Sjdp vm_map_entry_t ent; 47840525Sjdp vm_offset_t start; 47940525Sjdp vm_offset_t end; 48040525Sjdp char prot[4]; 48140525Sjdp char type[16]; 48240525Sjdp int n; 48340525Sjdp int len; 48440525Sjdp 48540525Sjdp len = 0; 48648860Sjdp n = sscanf(mapbuf + pos, "%x %x %*d %*d %*x %3[-rwx]" 48740525Sjdp " %*d %*d %*x %*s %*s %16s%*[\n]%n", 48840525Sjdp &start, &end, prot, type, &len); 48940525Sjdp if (n != 4) 49040525Sjdp errx(1, "ill-formed line in %s", mapname); 49140525Sjdp pos += len; 49240525Sjdp 49340525Sjdp /* Ignore segments of the wrong kind, and unwritable ones */ 49440525Sjdp if (strncmp(prot, "rw", 2) != 0 || 49540525Sjdp (strcmp(type, "default") != 0 && 49640525Sjdp strcmp(type, "vnode") != 0 && 49740525Sjdp strcmp(type, "swap") != 0)) 49840525Sjdp continue; 49940525Sjdp 50040525Sjdp if ((ent = (vm_map_entry_t)calloc(1, sizeof *ent)) == NULL) 50140525Sjdp errx(1, "out of memory"); 50240525Sjdp ent->start = start; 50340525Sjdp ent->end = end; 50440525Sjdp ent->protection = VM_PROT_READ | VM_PROT_WRITE; 50540525Sjdp if (prot[2] == 'x') 50640525Sjdp ent->protection |= VM_PROT_EXECUTE; 50740525Sjdp 50840525Sjdp *linkp = ent; 50940525Sjdp linkp = &ent->next; 51040525Sjdp } 51140525Sjdp free(mapbuf); 51240525Sjdp return map; 51340525Sjdp} 514