elfcore.c revision 40803
14374Slars/*-
24374Slars * Copyright (c) 1998 John D. Polstra
34374Slars * All rights reserved.
44374Slars *
511990Speter * Redistribution and use in source and binary forms, with or without
611990Speter * modification, are permitted provided that the following conditions
711990Speter * are met:
834766Speter * 1. Redistributions of source code must retain the above copyright
911990Speter *    notice, this list of conditions and the following disclaimer.
1011990Speter * 2. Redistributions in binary form must reproduce the above copyright
1111990Speter *    notice, this list of conditions and the following disclaimer in the
1211990Speter *    documentation and/or other materials provided with the distribution.
1311990Speter *
144374Slars * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
154374Slars * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1628597Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1734766Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1834766Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1934766Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2034766Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
214374Slars * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2228597Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2328597Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2428597Speter * SUCH DAMAGE.
2528597Speter *
264374Slars *	$Id: elfcore.c,v 1.1 1998/10/19 19:42:18 jdp Exp $
2728597Speter */
2828597Speter
2928597Speter#include <sys/param.h>
3028597Speter#include <sys/lock.h>
3128597Speter#include <sys/procfs.h>
3228597Speter#include <vm/vm_param.h>
3328597Speter#include <vm/vm.h>
3428597Speter#include <vm/pmap.h>
3528597Speter#include <vm/vm_map.h>
3628597Speter#include <vm/vm_prot.h>
3728597Speter#include <elf.h>
3828597Speter#include <err.h>
3928597Speter#include <errno.h>
4028597Speter#include <fcntl.h>
4128597Speter#include <stdio.h>
4228597Speter#include <stdlib.h>
4328597Speter#include <string.h>
4428597Speter#include <unistd.h>
4528597Speter
4628597Speter#include "extern.h"
4728597Speter
4828597Speter/*
4928597Speter * Code for generating ELF core dumps.
5028597Speter */
5128597Speter
5211990Spetertypedef void (*segment_callback)(vm_map_entry_t, void *);
5311990Speter
5411990Speter/* Closure for cb_put_phdr(). */
5534766Speterstruct phdr_closure {
5634766Speter	Elf_Phdr *phdr;		/* Program header to fill in */
5734766Speter	Elf_Off offset;		/* Offset of segment in core file */
5828597Speter};
5934766Speter
6028597Speter/* Closure for cb_size_segment(). */
6128597Speterstruct sseg_closure {
6228597Speter	int count;		/* Count of writable segments. */
6328597Speter	size_t size;		/* Total size of all writable segments. */
6428597Speter};
6528597Speter
6628597Speterstatic void cb_put_phdr(vm_map_entry_t, void *);
6728597Speterstatic void cb_size_segment(vm_map_entry_t, void *);
6828597Speterstatic void each_writable_segment(vm_map_entry_t, segment_callback,
694374Slars    void *closure);
704374Slarsstatic void elf_corehdr(int fd, pid_t, vm_map_entry_t, int numsegs,
714374Slars    void *hdr, size_t hdrsize);
724374Slarsstatic void elf_puthdr(vm_map_entry_t, void *, size_t *,
734374Slars    const prstatus_t *, const prfpregset_t *, const prpsinfo_t *, int numsegs);
744374Slarsstatic void elf_putnote(void *dst, size_t *off, const char *name, int type,
754374Slars    const void *desc, size_t descsz);
7611990Speterstatic void freemap(vm_map_entry_t);
7728597Speterstatic void readhdrinfo(pid_t, prstatus_t *, prfpregset_t *, prpsinfo_t *);
784374Slarsstatic vm_map_entry_t readmap(pid_t);
794374Slars
8028597Speter/*
8141568Sarchie * Write an ELF coredump for the given pid to the given fd.
8250477Speter */
8328597Spetervoid
844374Slarself_coredump(int fd, pid_t pid)
854374Slars{
8628597Speter	vm_map_entry_t map;
8711990Speter	struct sseg_closure seginfo;
884374Slars	void *hdr;
894374Slars	size_t hdrsize;
904374Slars	char memname[64];
914374Slars	int memfd;
924374Slars	Elf_Phdr *php;
9328597Speter	int i;
944374Slars
954374Slars	/* Get the program's memory map. */
964374Slars	map = readmap(pid);
974374Slars
984374Slars	/* Size the program segments. */
994374Slars	seginfo.count = 0;
1004374Slars	seginfo.size = 0;
1014374Slars	each_writable_segment(map, cb_size_segment, &seginfo);
1024374Slars
1034374Slars	/*
1044374Slars	 * Calculate the size of the core file header area by making
1054374Slars	 * a dry run of generating it.  Nothing is written, but the
1064374Slars	 * size is calculated.
1074374Slars	 */
1084374Slars	hdrsize = 0;
1094374Slars	elf_puthdr(map, (void *)NULL, &hdrsize,
1104374Slars	    (const prstatus_t *)NULL, (const prfpregset_t *)NULL,
1114374Slars	    (const prpsinfo_t *)NULL, seginfo.count);
1124374Slars
1134374Slars	/*
1144374Slars	 * Allocate memory for building the header, fill it up,
1154374Slars	 * and write it out.
11634766Speter	 */
1174374Slars	hdr = malloc(hdrsize);
11811990Speter	if ((hdr = malloc(hdrsize)) == NULL)
11911990Speter		errx(1, "out of memory");
12011990Speter	elf_corehdr(fd, pid, map, seginfo.count, hdr, hdrsize);
12111990Speter
12234766Speter	/* Write the contents of all of the writable segments. */
12334766Speter	snprintf(memname, sizeof memname, "/proc/%d/mem", pid);
12434766Speter	if ((memfd = open(memname, O_RDONLY)) == -1)
12534766Speter		err(1, "cannot open %s", memname);
12634766Speter
12734766Speter	php = (Elf_Phdr *)((char *)hdr + sizeof(Elf_Ehdr)) + 1;
12834766Speter	for (i = 0;  i < seginfo.count;  i++) {
12934766Speter		int nleft = php->p_filesz;
1304374Slars
1314374Slars		lseek(memfd, (off_t)php->p_vaddr, SEEK_SET);
1324374Slars		while (nleft > 0) {
1334374Slars			char buf[8*1024];
1344374Slars			int nwant;
1354374Slars			int ngot;
1364374Slars
1374374Slars			nwant = nleft;
1384374Slars			if (nwant > sizeof buf)
1394374Slars				nwant = sizeof buf;
1404374Slars			ngot = read(memfd, buf, nwant);
1414374Slars			if (ngot == -1)
1424374Slars				err(1, "read from %s", memname);
14311990Speter			if (ngot < nwant)
1444374Slars				errx(1, "short read from %s:"
1454374Slars				    " wanted %d, got %d\n", memname,
14628597Speter				    nwant, ngot);
14711990Speter			ngot = write(fd, buf, nwant);
14834766Speter			if (ngot == -1)
14934766Speter				err(1, "write of segment %d failed", i);
15028597Speter			if (ngot != nwant)
15111990Speter				errx(1, "short write");
15211990Speter			nleft -= nwant;
15311990Speter		}
15411990Speter		php++;
15511990Speter	}
15611990Speter	close(memfd);
15734766Speter	free(hdr);
15834766Speter	freemap(map);
15911990Speter}
1604374Slars
1614374Slars/*
16211990Speter * A callback for each_writable_segment() to write out the segment's
1634374Slars * program header entry.
16411990Speter */
16511990Speterstatic void
16611990Spetercb_put_phdr(vm_map_entry_t entry, void *closure)
1674374Slars{
1684374Slars	struct phdr_closure *phc = (struct phdr_closure *)closure;
16911990Speter	Elf_Phdr *phdr = phc->phdr;
1704374Slars
17111990Speter	phc->offset = round_page(phc->offset);
17211990Speter
17311990Speter	phdr->p_type = PT_LOAD;
1744374Slars	phdr->p_offset = phc->offset;
1754374Slars	phdr->p_vaddr = entry->start;
1764374Slars	phdr->p_paddr = 0;
1774374Slars	phdr->p_filesz = phdr->p_memsz = entry->end - entry->start;
1784374Slars	phdr->p_align = PAGE_SIZE;
17928597Speter	phdr->p_flags = 0;
18028597Speter	if (entry->protection & VM_PROT_READ)
1814374Slars		phdr->p_flags |= PF_R;
18211990Speter	if (entry->protection & VM_PROT_WRITE)
18311990Speter		phdr->p_flags |= PF_W;
18411990Speter	if (entry->protection & VM_PROT_EXECUTE)
18528597Speter		phdr->p_flags |= PF_X;
18611990Speter
18728597Speter	phc->offset += phdr->p_filesz;
18828597Speter	phc->phdr++;
18992920Simp}
19092920Simp
19192920Simp/*
19292920Simp * A callback for each_writable_segment() to gather information about
19392920Simp * the number of segments and their total size.
19492920Simp */
19592920Simpstatic void
19692920Simpcb_size_segment(vm_map_entry_t entry, void *closure)
19792920Simp{
19892920Simp	struct sseg_closure *ssc = (struct sseg_closure *)closure;
19992920Simp
20092920Simp	ssc->count++;
20192920Simp	ssc->size += entry->end - entry->start;
20292920Simp}
20392920Simp
20492920Simp/*
20592920Simp * For each segment in the given memory map, call the given function
20692920Simp * with a pointer to the map entry and some arbitrary caller-supplied
20792920Simp * data.
20892920Simp */
20992920Simpstatic void
21092920Simpeach_writable_segment(vm_map_entry_t map, segment_callback func, void *closure)
21192920Simp{
21292920Simp	vm_map_entry_t entry;
21392920Simp
21492920Simp	for (entry = map;  entry != NULL;  entry = entry->next)
21592920Simp		(*func)(entry, closure);
21692920Simp}
21792920Simp
21892920Simp/*
2194374Slars * Write the core file header to the file, including padding up to
22092920Simp * the page boundary.
22128597Speter */
2224374Slarsstatic void
2234374Slarself_corehdr(int fd, pid_t pid, vm_map_entry_t map, int numsegs, void *hdr,
2244374Slars    size_t hdrsize)
22534766Speter{
2264374Slars	size_t off;
2274374Slars	prstatus_t status;
22834766Speter	prfpregset_t fpregset;
22934766Speter	prpsinfo_t psinfo;
2304374Slars
2314374Slars	/* Gather the information for the header. */
23234766Speter	readhdrinfo(pid, &status, &fpregset, &psinfo);
2334374Slars
2344374Slars	/* Fill in the header. */
2354374Slars	memset(hdr, 0, hdrsize);
23634766Speter	off = 0;
2374374Slars	elf_puthdr(map, hdr, &off, &status, &fpregset, &psinfo, numsegs);
23834766Speter
2394374Slars	/* Write it to the core file. */
2404374Slars	if (write(fd, hdr, hdrsize) == -1)
24134766Speter		err(1, "write");
24234766Speter}
2434374Slars
2444374Slars/*
2454374Slars * Generate the ELF coredump header into the buffer at "dst".  "dst" may
2464374Slars * be NULL, in which case the header is sized but not actually generated.
2474374Slars */
2484374Slarsstatic void
24934766Speterelf_puthdr(vm_map_entry_t map, void *dst, size_t *off, const prstatus_t *status,
25034766Speter    const prfpregset_t *fpregset, const prpsinfo_t *psinfo, int numsegs)
25134766Speter{
2524374Slars	size_t ehoff;
2534374Slars	size_t phoff;
2544374Slars	size_t noteoff;
25511990Speter	size_t notesz;
2564374Slars
25734766Speter	ehoff = *off;
25834766Speter	*off += sizeof(Elf_Ehdr);
25934766Speter
26034766Speter	phoff = *off;
26134766Speter	*off += (numsegs + 1) * sizeof(Elf_Phdr);
26228597Speter
26334766Speter	noteoff = *off;
26434766Speter	elf_putnote(dst, off, "FreeBSD", NT_PRSTATUS, status,
26534766Speter	    sizeof *status);
2664374Slars	elf_putnote(dst, off, "FreeBSD", NT_FPREGSET, fpregset,
26734766Speter	    sizeof *fpregset);
26834766Speter	elf_putnote(dst, off, "FreeBSD", NT_PRPSINFO, psinfo,
26934766Speter	    sizeof *psinfo);
27028597Speter	notesz = *off - noteoff;
27134766Speter
27234766Speter	/* Align up to a page boundary for the program segments. */
27334766Speter	*off = round_page(*off);
27434766Speter
27534766Speter	if (dst != NULL) {
27634766Speter		Elf_Ehdr *ehdr;
27734766Speter		Elf_Phdr *phdr;
27834766Speter		struct phdr_closure phc;
27934766Speter
28034766Speter		/*
2814374Slars		 * Fill in the ELF header.
28234766Speter		 */
28334766Speter		ehdr = (Elf_Ehdr *)((char *)dst + ehoff);
28434766Speter		ehdr->e_ident[EI_MAG0] = ELFMAG0;
2854374Slars		ehdr->e_ident[EI_MAG1] = ELFMAG1;
28634766Speter		ehdr->e_ident[EI_MAG2] = ELFMAG2;
28734766Speter		ehdr->e_ident[EI_MAG3] = ELFMAG3;
28834766Speter		ehdr->e_ident[EI_CLASS] = ELF_CLASS;
28934766Speter		ehdr->e_ident[EI_DATA] = ELF_DATA;
29034766Speter		ehdr->e_ident[EI_VERSION] = EV_CURRENT;
29134766Speter		ehdr->e_ident[EI_PAD] = 0;
2924374Slars		strncpy(ehdr->e_ident + EI_BRAND, "FreeBSD",
29334766Speter		    EI_NIDENT - EI_BRAND);
29434766Speter		ehdr->e_type = ET_CORE;
29534766Speter		ehdr->e_machine = ELF_ARCH;
29634766Speter		ehdr->e_version = EV_CURRENT;
29734766Speter		ehdr->e_entry = 0;
29834766Speter		ehdr->e_phoff = phoff;
29934766Speter		ehdr->e_flags = 0;
30034766Speter		ehdr->e_ehsize = sizeof(Elf_Ehdr);
30134766Speter		ehdr->e_phentsize = sizeof(Elf_Phdr);
30234766Speter		ehdr->e_phnum = numsegs + 1;
30334766Speter		ehdr->e_shentsize = sizeof(Elf_Shdr);
30434766Speter		ehdr->e_shnum = 0;
30534766Speter		ehdr->e_shstrndx = SHN_UNDEF;
30634766Speter
30734766Speter		/*
3084374Slars		 * Fill in the program header entries.
30934766Speter		 */
31034766Speter		phdr = (Elf_Phdr *)((char *)dst + phoff);
31134766Speter
31234766Speter		/* The note segement. */
3134374Slars		phdr->p_type = PT_NOTE;
31434766Speter		phdr->p_offset = noteoff;
31534766Speter		phdr->p_vaddr = 0;
31634766Speter		phdr->p_paddr = 0;
31734766Speter		phdr->p_filesz = notesz;
31834766Speter		phdr->p_memsz = 0;
31934766Speter		phdr->p_flags = 0;
32034766Speter		phdr->p_align = 0;
32134766Speter		phdr++;
32234766Speter
32334766Speter		/* All the writable segments from the program. */
32434766Speter		phc.phdr = phdr;
32534766Speter		phc.offset = *off;
32634766Speter		each_writable_segment(map, cb_put_phdr, &phc);
32734766Speter	}
32811990Speter}
32911990Speter
33011990Speter/*
33111990Speter * Emit one note section to "dst", or just size it if "dst" is NULL.
33211990Speter */
3334374Slarsstatic void
33434766Speterelf_putnote(void *dst, size_t *off, const char *name, int type,
3354374Slars    const void *desc, size_t descsz)
33634766Speter{
3374374Slars	Elf_Note note;
33834766Speter
3394374Slars	note.n_namesz = strlen(name) + 1;
34034766Speter	note.n_descsz = descsz;
34134766Speter	note.n_type = type;
34234766Speter	if (dst != NULL)
34334766Speter		bcopy(&note, (char *)dst + *off, sizeof note);
3444374Slars	*off += sizeof note;
34534766Speter	if (dst != NULL)
3464374Slars		bcopy(name, (char *)dst + *off, note.n_namesz);
3474374Slars	*off += roundup2(note.n_namesz, sizeof(Elf_Size));
34811990Speter	if (dst != NULL)
34934766Speter		bcopy(desc, (char *)dst + *off, note.n_descsz);
3504374Slars	*off += roundup2(note.n_descsz, sizeof(Elf_Size));
3514374Slars}
3524374Slars
3534374Slars/*
3544374Slars * Free the memory map.
35534766Speter */
35634766Speterstatic void
3574374Slarsfreemap(vm_map_entry_t map)
3584374Slars{
35928597Speter	while (map != NULL) {
3604374Slars		vm_map_entry_t next = map->next;
3614374Slars		free(map);
36234766Speter		map = next;
3634374Slars	}
3644374Slars}
36528597Speter
36634766Speter/*
3674374Slars * Read the process information necessary to fill in the core file's header.
3684374Slars */
3694374Slarsstatic void
3704374Slarsreadhdrinfo(pid_t pid, prstatus_t *status, prfpregset_t *fpregset,
3714374Slars    prpsinfo_t *psinfo)
3724374Slars{
3734374Slars	char name[64];
37434766Speter	char line[256];
37532069Salex	int fd;
3764374Slars	int i;
3774374Slars	int n;
3784374Slars
3794374Slars	memset(status, 0, sizeof *status);
38011990Speter	status->pr_version = PRSTATUS_VERSION;
38111990Speter	status->pr_statussz = sizeof(prstatus_t);
38234766Speter	status->pr_gregsetsz = sizeof(gregset_t);
3834374Slars	status->pr_fpregsetsz = sizeof(fpregset_t);
3844374Slars	status->pr_osreldate = __FreeBSD_version;
3854374Slars	status->pr_pid = pid;
3864374Slars
38734766Speter	memset(fpregset, 0, sizeof *fpregset);
3884374Slars
3894374Slars	memset(psinfo, 0, sizeof *psinfo);
3904374Slars	psinfo->pr_version = PRPSINFO_VERSION;
3914374Slars	psinfo->pr_psinfosz = sizeof(prpsinfo_t);
3924374Slars
3934374Slars	/* Read the general registers. */
39428597Speter	snprintf(name, sizeof name, "/proc/%d/regs", pid);
39528597Speter	if ((fd = open(name, O_RDONLY)) == -1)
39628597Speter		err(1, "cannot open %s", name);
39734766Speter	if ((n = read(fd, &status->pr_reg, sizeof status->pr_reg)) == -1)
39834766Speter		err(1, "read error from %s", name);
39928597Speter	if (n < sizeof status->pr_reg)
40034766Speter		errx(1, "short read from %s: wanted %u, got %d", name,
40134766Speter		    sizeof status->pr_reg, n);
4024374Slars	close(fd);
4034374Slars
40434766Speter	/* Read the floating point registers. */
4054374Slars	snprintf(name, sizeof name, "/proc/%d/fpregs", pid);
40634766Speter	if ((fd = open(name, O_RDONLY)) == -1)
4074374Slars		err(1, "cannot open %s", name);
4084374Slars	if ((n = read(fd, fpregset, sizeof *fpregset)) == -1)
40934766Speter		err(1, "read error from %s", name);
4104374Slars	if (n < sizeof *fpregset)
41134766Speter		errx(1, "short read from %s: wanted %u, got %d", name,
41234766Speter		    sizeof *fpregset, n);
41334766Speter	close(fd);
4144374Slars
4154374Slars	/* Read and parse the process status. */
4164374Slars	snprintf(name, sizeof name, "/proc/%d/status", pid);
4174374Slars	if ((fd = open(name, O_RDONLY)) == -1)
41834766Speter		err(1, "cannot open %s", name);
41934766Speter	if ((n = read(fd, line, sizeof line - 1)) == -1)
4204374Slars		err(1, "read error from %s", name);
4214374Slars	if (n > MAXCOMLEN)
4224374Slars		n = MAXCOMLEN;
42334766Speter	for (i = 0;  i < n && line[i] != ' ';  i++)
4244374Slars		psinfo->pr_fname[i] = line[i];
4254374Slars	strncpy(psinfo->pr_psargs, psinfo->pr_fname, PRARGSZ);
4264374Slars	close(fd);
4274374Slars}
4284374Slars
4294374Slars/*
4304374Slars * Read the process's memory map using procfs, and return a list of
4314374Slars * VM map entries.  Only the non-device read/writable segments are
4324374Slars * returned.  The map entries in the list aren't fully filled in; only
4334374Slars * the items we need are present.
43434766Speter */
4354374Slarsstatic vm_map_entry_t
43634766Speterreadmap(pid_t pid)
4374374Slars{
4384374Slars	char mapname[64];
4394374Slars	int mapfd;
4404374Slars	ssize_t mapsize;
44126880Scharnier	size_t bufsize;
44226880Scharnier	char *mapbuf;
44334766Speter	int pos;
44434766Speter	vm_map_entry_t map;
44534766Speter	vm_map_entry_t *linkp;
44634766Speter
4474374Slars	snprintf(mapname, sizeof mapname, "/proc/%d/map", pid);
44834766Speter	if ((mapfd = open(mapname, O_RDONLY)) == -1)
4494374Slars		err(1, "cannot open %s", mapname);
45034766Speter
4514374Slars	/*
45234766Speter	 * Procfs requires (for consistency) that the entire memory map
45334766Speter	 * be read with a single read() call.  Start with a reasonbly sized
45434766Speter	 * buffer, and double it until it is big enough.
45592920Simp	 */
45628597Speter	bufsize = 8 * 1024;
45734766Speter	mapbuf = NULL;
4584374Slars	for ( ; ; ) {
45934766Speter		if ((mapbuf = realloc(mapbuf, bufsize)) == NULL)
46034766Speter			errx(1, "out of memory");
46134766Speter		mapsize = read(mapfd, mapbuf, bufsize);
46228597Speter		if (mapsize != -1 || errno != EFBIG)
46334766Speter			break;
46434766Speter		bufsize *= 2;
46528597Speter		/* This lseek shouldn't be necessary, but it is. */
4664374Slars		lseek(mapfd, (off_t)0, SEEK_SET);
4674374Slars	}
4684374Slars	if (mapsize == -1)
4694374Slars		err(1, "read error from %s", mapname);
4704374Slars	if (mapsize == 0)
47192920Simp		errx(1, "empty map file %s", mapname);
47234766Speter	close(mapfd);
47334766Speter
4744374Slars	pos = 0;
47534766Speter	map = NULL;
47634766Speter	linkp = &map;
47734766Speter	while (pos < mapsize) {
47834766Speter		vm_map_entry_t ent;
47934766Speter		vm_offset_t start;
48034766Speter		vm_offset_t end;
48134766Speter		char prot[4];
48234766Speter		char type[16];
4834374Slars		int n;
4844374Slars		int len;
4854374Slars
4864374Slars		len = 0;
4874374Slars		n = sscanf(mapbuf + pos, "%x %x %*d %*d %*d %3[-rwx]"
48834766Speter		    " %*d %*d %*x %*s %*s %16s%*[\n]%n",
4894374Slars		    &start, &end, prot, type, &len);
4904374Slars		if (n != 4)
4914374Slars			errx(1, "ill-formed line in %s", mapname);
4924374Slars		pos += len;
4934374Slars
4944374Slars		/* Ignore segments of the wrong kind, and unwritable ones */
4954374Slars		if (strncmp(prot, "rw", 2) != 0 ||
49634766Speter		    (strcmp(type, "default") != 0 &&
4974374Slars		    strcmp(type, "vnode") != 0 &&
49834766Speter		    strcmp(type, "swap") != 0))
49934766Speter			continue;
50034766Speter
5014374Slars		if ((ent = (vm_map_entry_t)calloc(1, sizeof *ent)) == NULL)
50234766Speter			errx(1, "out of memory");
50334766Speter		ent->start = start;
5044374Slars		ent->end = end;
5054374Slars		ent->protection = VM_PROT_READ | VM_PROT_WRITE;
50634766Speter		if (prot[2] == 'x')
5074374Slars		    ent->protection |= VM_PROT_EXECUTE;
5084374Slars
5094374Slars		*linkp = ent;
51034766Speter		linkp = &ent->next;
5114374Slars	}
51234766Speter	free(mapbuf);
51334766Speter	return map;
51434766Speter}
51534766Speter