elfcore.c revision 102951
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 */ 2640525Sjdp 2793215Scharnier#include <sys/cdefs.h> 2893215Scharnier__FBSDID("$FreeBSD: head/usr.bin/gcore/elfcore.c 102951 2002-09-05 07:43:34Z iedowse $"); 2993215Scharnier 3040525Sjdp#include <sys/param.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> 40102951Siedowse#include <stdint.h> 4140525Sjdp#include <stdio.h> 4240525Sjdp#include <stdlib.h> 4340525Sjdp#include <string.h> 4440525Sjdp#include <unistd.h> 4540525Sjdp 4640525Sjdp#include "extern.h" 4740525Sjdp 4840525Sjdp/* 4940525Sjdp * Code for generating ELF core dumps. 5040525Sjdp */ 5140525Sjdp 5240525Sjdptypedef void (*segment_callback)(vm_map_entry_t, void *); 5340525Sjdp 5440525Sjdp/* Closure for cb_put_phdr(). */ 5540525Sjdpstruct phdr_closure { 5640525Sjdp Elf_Phdr *phdr; /* Program header to fill in */ 5740525Sjdp Elf_Off offset; /* Offset of segment in core file */ 5840525Sjdp}; 5940525Sjdp 6040525Sjdp/* Closure for cb_size_segment(). */ 6140525Sjdpstruct sseg_closure { 6240525Sjdp int count; /* Count of writable segments. */ 6340525Sjdp size_t size; /* Total size of all writable segments. */ 6440525Sjdp}; 6540525Sjdp 6640525Sjdpstatic void cb_put_phdr(vm_map_entry_t, void *); 6740525Sjdpstatic void cb_size_segment(vm_map_entry_t, void *); 6840525Sjdpstatic void each_writable_segment(vm_map_entry_t, segment_callback, 6940525Sjdp void *closure); 7040525Sjdpstatic void elf_corehdr(int fd, pid_t, vm_map_entry_t, int numsegs, 7140525Sjdp void *hdr, size_t hdrsize); 7240525Sjdpstatic void elf_puthdr(vm_map_entry_t, void *, size_t *, 7340525Sjdp const prstatus_t *, const prfpregset_t *, const prpsinfo_t *, int numsegs); 7440525Sjdpstatic void elf_putnote(void *dst, size_t *off, const char *name, int type, 7540525Sjdp const void *desc, size_t descsz); 7640525Sjdpstatic void freemap(vm_map_entry_t); 7740525Sjdpstatic void readhdrinfo(pid_t, prstatus_t *, prfpregset_t *, prpsinfo_t *); 7840525Sjdpstatic vm_map_entry_t readmap(pid_t); 7940525Sjdp 8040525Sjdp/* 8140525Sjdp * Write an ELF coredump for the given pid to the given fd. 8240525Sjdp */ 8340525Sjdpvoid 8440525Sjdpelf_coredump(int fd, pid_t pid) 8540525Sjdp{ 8640525Sjdp vm_map_entry_t map; 8740525Sjdp struct sseg_closure seginfo; 8840525Sjdp void *hdr; 8940525Sjdp size_t hdrsize; 9040525Sjdp char memname[64]; 9140525Sjdp int memfd; 9240525Sjdp Elf_Phdr *php; 9340525Sjdp int i; 9440525Sjdp 9540525Sjdp /* Get the program's memory map. */ 9640525Sjdp map = readmap(pid); 9740525Sjdp 9840525Sjdp /* Size the program segments. */ 9940525Sjdp seginfo.count = 0; 10040525Sjdp seginfo.size = 0; 10140525Sjdp each_writable_segment(map, cb_size_segment, &seginfo); 10240525Sjdp 10340525Sjdp /* 10440525Sjdp * Calculate the size of the core file header area by making 10540525Sjdp * a dry run of generating it. Nothing is written, but the 10640525Sjdp * size is calculated. 10740525Sjdp */ 10840525Sjdp hdrsize = 0; 10940525Sjdp elf_puthdr(map, (void *)NULL, &hdrsize, 11040525Sjdp (const prstatus_t *)NULL, (const prfpregset_t *)NULL, 11140525Sjdp (const prpsinfo_t *)NULL, seginfo.count); 11240525Sjdp 11340525Sjdp /* 11440525Sjdp * Allocate memory for building the header, fill it up, 11540525Sjdp * and write it out. 11640525Sjdp */ 11740525Sjdp hdr = malloc(hdrsize); 11840525Sjdp if ((hdr = malloc(hdrsize)) == NULL) 11940525Sjdp errx(1, "out of memory"); 12040525Sjdp elf_corehdr(fd, pid, map, seginfo.count, hdr, hdrsize); 12140525Sjdp 12240525Sjdp /* Write the contents of all of the writable segments. */ 12340525Sjdp snprintf(memname, sizeof memname, "/proc/%d/mem", pid); 12440525Sjdp if ((memfd = open(memname, O_RDONLY)) == -1) 12540525Sjdp err(1, "cannot open %s", memname); 12640525Sjdp 12740525Sjdp php = (Elf_Phdr *)((char *)hdr + sizeof(Elf_Ehdr)) + 1; 12840525Sjdp for (i = 0; i < seginfo.count; i++) { 129102944Sdwmalone uintmax_t nleft = php->p_filesz; 13040525Sjdp 13140525Sjdp lseek(memfd, (off_t)php->p_vaddr, SEEK_SET); 13240525Sjdp while (nleft > 0) { 13340525Sjdp char buf[8*1024]; 134102944Sdwmalone size_t nwant; 135102944Sdwmalone ssize_t ngot; 13640525Sjdp 137102944Sdwmalone if (nleft > sizeof(buf)) 13840525Sjdp nwant = sizeof buf; 139102944Sdwmalone else 140102944Sdwmalone nwant = nleft; 14140525Sjdp ngot = read(memfd, buf, nwant); 14240525Sjdp if (ngot == -1) 14340525Sjdp err(1, "read from %s", memname); 144102944Sdwmalone if ((size_t)ngot < nwant) 14540525Sjdp errx(1, "short read from %s:" 14693215Scharnier " wanted %d, got %d", memname, 14740803Sjdp nwant, ngot); 14840525Sjdp ngot = write(fd, buf, nwant); 14940525Sjdp if (ngot == -1) 15040525Sjdp err(1, "write of segment %d failed", i); 151102944Sdwmalone if ((size_t)ngot != nwant) 15240525Sjdp errx(1, "short write"); 15340525Sjdp nleft -= nwant; 15440525Sjdp } 15540525Sjdp php++; 15640525Sjdp } 15740525Sjdp close(memfd); 15840525Sjdp free(hdr); 15940525Sjdp freemap(map); 16040525Sjdp} 16140525Sjdp 16240525Sjdp/* 16340525Sjdp * A callback for each_writable_segment() to write out the segment's 16440525Sjdp * program header entry. 16540525Sjdp */ 16640525Sjdpstatic void 16740525Sjdpcb_put_phdr(vm_map_entry_t entry, void *closure) 16840525Sjdp{ 16940525Sjdp struct phdr_closure *phc = (struct phdr_closure *)closure; 17040525Sjdp Elf_Phdr *phdr = phc->phdr; 17140525Sjdp 17240525Sjdp phc->offset = round_page(phc->offset); 17340525Sjdp 17440525Sjdp phdr->p_type = PT_LOAD; 17540525Sjdp phdr->p_offset = phc->offset; 17640525Sjdp phdr->p_vaddr = entry->start; 17740525Sjdp phdr->p_paddr = 0; 17840525Sjdp phdr->p_filesz = phdr->p_memsz = entry->end - entry->start; 17940525Sjdp phdr->p_align = PAGE_SIZE; 18040525Sjdp phdr->p_flags = 0; 18140525Sjdp if (entry->protection & VM_PROT_READ) 18240525Sjdp phdr->p_flags |= PF_R; 18340525Sjdp if (entry->protection & VM_PROT_WRITE) 18440525Sjdp phdr->p_flags |= PF_W; 18540525Sjdp if (entry->protection & VM_PROT_EXECUTE) 18640525Sjdp phdr->p_flags |= PF_X; 18740525Sjdp 18840525Sjdp phc->offset += phdr->p_filesz; 18940525Sjdp phc->phdr++; 19040525Sjdp} 19140525Sjdp 19240525Sjdp/* 19340525Sjdp * A callback for each_writable_segment() to gather information about 19440525Sjdp * the number of segments and their total size. 19540525Sjdp */ 19640525Sjdpstatic void 19740525Sjdpcb_size_segment(vm_map_entry_t entry, void *closure) 19840525Sjdp{ 19940525Sjdp struct sseg_closure *ssc = (struct sseg_closure *)closure; 20040525Sjdp 20140525Sjdp ssc->count++; 20240525Sjdp ssc->size += entry->end - entry->start; 20340525Sjdp} 20440525Sjdp 20540525Sjdp/* 20640525Sjdp * For each segment in the given memory map, call the given function 20740525Sjdp * with a pointer to the map entry and some arbitrary caller-supplied 20840525Sjdp * data. 20940525Sjdp */ 21040525Sjdpstatic void 21140525Sjdpeach_writable_segment(vm_map_entry_t map, segment_callback func, void *closure) 21240525Sjdp{ 21340525Sjdp vm_map_entry_t entry; 21440525Sjdp 21540525Sjdp for (entry = map; entry != NULL; entry = entry->next) 21640525Sjdp (*func)(entry, closure); 21740525Sjdp} 21840525Sjdp 21940525Sjdp/* 22040525Sjdp * Write the core file header to the file, including padding up to 22140525Sjdp * the page boundary. 22240525Sjdp */ 22340525Sjdpstatic void 22440525Sjdpelf_corehdr(int fd, pid_t pid, vm_map_entry_t map, int numsegs, void *hdr, 22540525Sjdp size_t hdrsize) 22640525Sjdp{ 22740525Sjdp size_t off; 22840525Sjdp prstatus_t status; 22940525Sjdp prfpregset_t fpregset; 23040525Sjdp prpsinfo_t psinfo; 23140525Sjdp 23240525Sjdp /* Gather the information for the header. */ 23340525Sjdp readhdrinfo(pid, &status, &fpregset, &psinfo); 23440525Sjdp 23540525Sjdp /* Fill in the header. */ 23640525Sjdp memset(hdr, 0, hdrsize); 23740525Sjdp off = 0; 23840525Sjdp elf_puthdr(map, hdr, &off, &status, &fpregset, &psinfo, numsegs); 23940525Sjdp 24040525Sjdp /* Write it to the core file. */ 24140525Sjdp if (write(fd, hdr, hdrsize) == -1) 24240525Sjdp err(1, "write"); 24340525Sjdp} 24440525Sjdp 24540525Sjdp/* 24640525Sjdp * Generate the ELF coredump header into the buffer at "dst". "dst" may 24740525Sjdp * be NULL, in which case the header is sized but not actually generated. 24840525Sjdp */ 24940525Sjdpstatic void 25040525Sjdpelf_puthdr(vm_map_entry_t map, void *dst, size_t *off, const prstatus_t *status, 25140525Sjdp const prfpregset_t *fpregset, const prpsinfo_t *psinfo, int numsegs) 25240525Sjdp{ 25340525Sjdp size_t ehoff; 25440525Sjdp size_t phoff; 25540525Sjdp size_t noteoff; 25640525Sjdp size_t notesz; 25740525Sjdp 25840525Sjdp ehoff = *off; 25940525Sjdp *off += sizeof(Elf_Ehdr); 26040525Sjdp 26140525Sjdp phoff = *off; 26240525Sjdp *off += (numsegs + 1) * sizeof(Elf_Phdr); 26340525Sjdp 26440525Sjdp noteoff = *off; 26540525Sjdp elf_putnote(dst, off, "FreeBSD", NT_PRSTATUS, status, 26640525Sjdp sizeof *status); 26740525Sjdp elf_putnote(dst, off, "FreeBSD", NT_FPREGSET, fpregset, 26840525Sjdp sizeof *fpregset); 26940525Sjdp elf_putnote(dst, off, "FreeBSD", NT_PRPSINFO, psinfo, 27040525Sjdp sizeof *psinfo); 27140525Sjdp notesz = *off - noteoff; 27240525Sjdp 27340525Sjdp /* Align up to a page boundary for the program segments. */ 27440525Sjdp *off = round_page(*off); 27540525Sjdp 27640525Sjdp if (dst != NULL) { 27740525Sjdp Elf_Ehdr *ehdr; 27840525Sjdp Elf_Phdr *phdr; 27940525Sjdp struct phdr_closure phc; 28040525Sjdp 28140525Sjdp /* 28240525Sjdp * Fill in the ELF header. 28340525Sjdp */ 28440525Sjdp ehdr = (Elf_Ehdr *)((char *)dst + ehoff); 28540525Sjdp ehdr->e_ident[EI_MAG0] = ELFMAG0; 28640525Sjdp ehdr->e_ident[EI_MAG1] = ELFMAG1; 28740525Sjdp ehdr->e_ident[EI_MAG2] = ELFMAG2; 28840525Sjdp ehdr->e_ident[EI_MAG3] = ELFMAG3; 28940525Sjdp ehdr->e_ident[EI_CLASS] = ELF_CLASS; 29040525Sjdp ehdr->e_ident[EI_DATA] = ELF_DATA; 29140525Sjdp ehdr->e_ident[EI_VERSION] = EV_CURRENT; 29259342Sobrien ehdr->e_ident[EI_OSABI] = ELFOSABI_FREEBSD; 29359342Sobrien ehdr->e_ident[EI_ABIVERSION] = 0; 29440525Sjdp ehdr->e_ident[EI_PAD] = 0; 29540525Sjdp ehdr->e_type = ET_CORE; 29640525Sjdp ehdr->e_machine = ELF_ARCH; 29740525Sjdp ehdr->e_version = EV_CURRENT; 29840525Sjdp ehdr->e_entry = 0; 29940525Sjdp ehdr->e_phoff = phoff; 30040525Sjdp ehdr->e_flags = 0; 30140525Sjdp ehdr->e_ehsize = sizeof(Elf_Ehdr); 30240525Sjdp ehdr->e_phentsize = sizeof(Elf_Phdr); 30340525Sjdp ehdr->e_phnum = numsegs + 1; 30440525Sjdp ehdr->e_shentsize = sizeof(Elf_Shdr); 30540525Sjdp ehdr->e_shnum = 0; 30640525Sjdp ehdr->e_shstrndx = SHN_UNDEF; 30740525Sjdp 30840525Sjdp /* 30940525Sjdp * Fill in the program header entries. 31040525Sjdp */ 31140525Sjdp phdr = (Elf_Phdr *)((char *)dst + phoff); 31240525Sjdp 31393215Scharnier /* The note segment. */ 31440525Sjdp phdr->p_type = PT_NOTE; 31540525Sjdp phdr->p_offset = noteoff; 31640525Sjdp phdr->p_vaddr = 0; 31740525Sjdp phdr->p_paddr = 0; 31840525Sjdp phdr->p_filesz = notesz; 31940525Sjdp phdr->p_memsz = 0; 32040525Sjdp phdr->p_flags = 0; 32140525Sjdp phdr->p_align = 0; 32240525Sjdp phdr++; 32340525Sjdp 32440525Sjdp /* All the writable segments from the program. */ 32540525Sjdp phc.phdr = phdr; 32640525Sjdp phc.offset = *off; 32740525Sjdp each_writable_segment(map, cb_put_phdr, &phc); 32840525Sjdp } 32940525Sjdp} 33040525Sjdp 33140525Sjdp/* 33240525Sjdp * Emit one note section to "dst", or just size it if "dst" is NULL. 33340525Sjdp */ 33440525Sjdpstatic void 33540525Sjdpelf_putnote(void *dst, size_t *off, const char *name, int type, 33640525Sjdp const void *desc, size_t descsz) 33740525Sjdp{ 33840525Sjdp Elf_Note note; 33940525Sjdp 34040525Sjdp note.n_namesz = strlen(name) + 1; 34140525Sjdp note.n_descsz = descsz; 34240525Sjdp note.n_type = type; 34340525Sjdp if (dst != NULL) 34440525Sjdp bcopy(¬e, (char *)dst + *off, sizeof note); 34540525Sjdp *off += sizeof note; 34640525Sjdp if (dst != NULL) 34740525Sjdp bcopy(name, (char *)dst + *off, note.n_namesz); 34840525Sjdp *off += roundup2(note.n_namesz, sizeof(Elf_Size)); 34940525Sjdp if (dst != NULL) 35040525Sjdp bcopy(desc, (char *)dst + *off, note.n_descsz); 35140525Sjdp *off += roundup2(note.n_descsz, sizeof(Elf_Size)); 35240525Sjdp} 35340525Sjdp 35440525Sjdp/* 35540525Sjdp * Free the memory map. 35640525Sjdp */ 35740525Sjdpstatic void 35840525Sjdpfreemap(vm_map_entry_t map) 35940525Sjdp{ 36040525Sjdp while (map != NULL) { 36140525Sjdp vm_map_entry_t next = map->next; 36240525Sjdp free(map); 36340525Sjdp map = next; 36440525Sjdp } 36540525Sjdp} 36640525Sjdp 36740525Sjdp/* 36840525Sjdp * Read the process information necessary to fill in the core file's header. 36940525Sjdp */ 37040525Sjdpstatic void 37140525Sjdpreadhdrinfo(pid_t pid, prstatus_t *status, prfpregset_t *fpregset, 37240525Sjdp prpsinfo_t *psinfo) 37340525Sjdp{ 37440525Sjdp char name[64]; 37540525Sjdp char line[256]; 37640525Sjdp int fd; 37740525Sjdp int i; 37840525Sjdp int n; 37940525Sjdp 38040525Sjdp memset(status, 0, sizeof *status); 38140525Sjdp status->pr_version = PRSTATUS_VERSION; 38240525Sjdp status->pr_statussz = sizeof(prstatus_t); 38340525Sjdp status->pr_gregsetsz = sizeof(gregset_t); 38440525Sjdp status->pr_fpregsetsz = sizeof(fpregset_t); 38540525Sjdp status->pr_osreldate = __FreeBSD_version; 38640525Sjdp status->pr_pid = pid; 38740525Sjdp 38840525Sjdp memset(fpregset, 0, sizeof *fpregset); 38940525Sjdp 39040525Sjdp memset(psinfo, 0, sizeof *psinfo); 39140525Sjdp psinfo->pr_version = PRPSINFO_VERSION; 39240525Sjdp psinfo->pr_psinfosz = sizeof(prpsinfo_t); 39340525Sjdp 39440525Sjdp /* Read the general registers. */ 39540525Sjdp snprintf(name, sizeof name, "/proc/%d/regs", pid); 39640525Sjdp if ((fd = open(name, O_RDONLY)) == -1) 39740525Sjdp err(1, "cannot open %s", name); 39840525Sjdp if ((n = read(fd, &status->pr_reg, sizeof status->pr_reg)) == -1) 39940525Sjdp err(1, "read error from %s", name); 400102944Sdwmalone if ((size_t)n < sizeof(status->pr_reg)) 40140525Sjdp errx(1, "short read from %s: wanted %u, got %d", name, 40240525Sjdp sizeof status->pr_reg, n); 40340525Sjdp close(fd); 40440525Sjdp 40540525Sjdp /* Read the floating point registers. */ 40640525Sjdp snprintf(name, sizeof name, "/proc/%d/fpregs", pid); 40740525Sjdp if ((fd = open(name, O_RDONLY)) == -1) 40840525Sjdp err(1, "cannot open %s", name); 40940525Sjdp if ((n = read(fd, fpregset, sizeof *fpregset)) == -1) 41040525Sjdp err(1, "read error from %s", name); 411102944Sdwmalone if ((size_t)n < sizeof(*fpregset)) 41240525Sjdp errx(1, "short read from %s: wanted %u, got %d", name, 41340525Sjdp sizeof *fpregset, n); 41440525Sjdp close(fd); 41540525Sjdp 41640525Sjdp /* Read and parse the process status. */ 41740525Sjdp snprintf(name, sizeof name, "/proc/%d/status", pid); 41840525Sjdp if ((fd = open(name, O_RDONLY)) == -1) 41940525Sjdp err(1, "cannot open %s", name); 42040525Sjdp if ((n = read(fd, line, sizeof line - 1)) == -1) 42140525Sjdp err(1, "read error from %s", name); 42240525Sjdp if (n > MAXCOMLEN) 42340525Sjdp n = MAXCOMLEN; 42440525Sjdp for (i = 0; i < n && line[i] != ' '; i++) 42540525Sjdp psinfo->pr_fname[i] = line[i]; 42640525Sjdp strncpy(psinfo->pr_psargs, psinfo->pr_fname, PRARGSZ); 42740525Sjdp close(fd); 42840525Sjdp} 42940525Sjdp 43040525Sjdp/* 43140525Sjdp * Read the process's memory map using procfs, and return a list of 43240525Sjdp * VM map entries. Only the non-device read/writable segments are 43340525Sjdp * returned. The map entries in the list aren't fully filled in; only 43440525Sjdp * the items we need are present. 43540525Sjdp */ 43640525Sjdpstatic vm_map_entry_t 43740525Sjdpreadmap(pid_t pid) 43840525Sjdp{ 43940525Sjdp char mapname[64]; 44040525Sjdp int mapfd; 44140525Sjdp ssize_t mapsize; 44240525Sjdp size_t bufsize; 44340525Sjdp char *mapbuf; 44440525Sjdp int pos; 44540525Sjdp vm_map_entry_t map; 44640525Sjdp vm_map_entry_t *linkp; 44740525Sjdp 44840525Sjdp snprintf(mapname, sizeof mapname, "/proc/%d/map", pid); 44940525Sjdp if ((mapfd = open(mapname, O_RDONLY)) == -1) 45040525Sjdp err(1, "cannot open %s", mapname); 45140525Sjdp 45240525Sjdp /* 45340525Sjdp * Procfs requires (for consistency) that the entire memory map 45493215Scharnier * be read with a single read() call. Start with a reasonably sized 45540525Sjdp * buffer, and double it until it is big enough. 45640525Sjdp */ 45740525Sjdp bufsize = 8 * 1024; 45840525Sjdp mapbuf = NULL; 45940525Sjdp for ( ; ; ) { 46077861Sjlemon if ((mapbuf = realloc(mapbuf, bufsize + 1)) == NULL) 46140525Sjdp errx(1, "out of memory"); 46240525Sjdp mapsize = read(mapfd, mapbuf, bufsize); 46340525Sjdp if (mapsize != -1 || errno != EFBIG) 46440525Sjdp break; 46540525Sjdp bufsize *= 2; 46640525Sjdp /* This lseek shouldn't be necessary, but it is. */ 46740525Sjdp lseek(mapfd, (off_t)0, SEEK_SET); 46840525Sjdp } 46940525Sjdp if (mapsize == -1) 47040525Sjdp err(1, "read error from %s", mapname); 47140525Sjdp if (mapsize == 0) 47240525Sjdp errx(1, "empty map file %s", mapname); 47377861Sjlemon mapbuf[mapsize] = 0; 47440525Sjdp close(mapfd); 47540525Sjdp 47640525Sjdp pos = 0; 47740525Sjdp map = NULL; 47840525Sjdp linkp = ↦ 47940525Sjdp while (pos < mapsize) { 48040525Sjdp vm_map_entry_t ent; 48140525Sjdp vm_offset_t start; 48240525Sjdp vm_offset_t end; 48340525Sjdp char prot[4]; 48440525Sjdp char type[16]; 48540525Sjdp int n; 48640525Sjdp int len; 48740525Sjdp 48840525Sjdp len = 0; 48948860Sjdp n = sscanf(mapbuf + pos, "%x %x %*d %*d %*x %3[-rwx]" 49040525Sjdp " %*d %*d %*x %*s %*s %16s%*[\n]%n", 49140525Sjdp &start, &end, prot, type, &len); 49240525Sjdp if (n != 4) 49340525Sjdp errx(1, "ill-formed line in %s", mapname); 49440525Sjdp pos += len; 49540525Sjdp 49640525Sjdp /* Ignore segments of the wrong kind, and unwritable ones */ 49740525Sjdp if (strncmp(prot, "rw", 2) != 0 || 49840525Sjdp (strcmp(type, "default") != 0 && 49940525Sjdp strcmp(type, "vnode") != 0 && 50040525Sjdp strcmp(type, "swap") != 0)) 50140525Sjdp continue; 50240525Sjdp 50340525Sjdp if ((ent = (vm_map_entry_t)calloc(1, sizeof *ent)) == NULL) 50440525Sjdp errx(1, "out of memory"); 50540525Sjdp ent->start = start; 50640525Sjdp ent->end = end; 50740525Sjdp ent->protection = VM_PROT_READ | VM_PROT_WRITE; 50840525Sjdp if (prot[2] == 'x') 50940525Sjdp ent->protection |= VM_PROT_EXECUTE; 51040525Sjdp 51140525Sjdp *linkp = ent; 51240525Sjdp linkp = &ent->next; 51340525Sjdp } 51440525Sjdp free(mapbuf); 51540525Sjdp return map; 51640525Sjdp} 517