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