summaryrefslogtreecommitdiffstats
path: root/usr.bin/gcore
diff options
context:
space:
mode:
authorjdp <jdp@FreeBSD.org>1998-10-19 19:42:18 +0000
committerjdp <jdp@FreeBSD.org>1998-10-19 19:42:18 +0000
commitface6e927780c3680f0315b297cc7108445cf37e (patch)
tree44dc625097f6da43bc86458b2977ad587f27f640 /usr.bin/gcore
parent59abe72c15ca058ae7f370015b5804af0d2eab23 (diff)
downloadFreeBSD-src-face6e927780c3680f0315b297cc7108445cf37e.zip
FreeBSD-src-face6e927780c3680f0315b297cc7108445cf37e.tar.gz
Make gcore work for ELF.
Diffstat (limited to 'usr.bin/gcore')
-rw-r--r--usr.bin/gcore/Makefile3
-rw-r--r--usr.bin/gcore/aoutcore.c102
-rw-r--r--usr.bin/gcore/elfcore.c513
-rw-r--r--usr.bin/gcore/extern.h4
-rw-r--r--usr.bin/gcore/gcore.c102
5 files changed, 625 insertions, 99 deletions
diff --git a/usr.bin/gcore/Makefile b/usr.bin/gcore/Makefile
index 664813f..7f6a3ee 100644
--- a/usr.bin/gcore/Makefile
+++ b/usr.bin/gcore/Makefile
@@ -1,7 +1,8 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
PROG= gcore
-SRCS= gcore.c
+SRCS= elfcore.c gcore.c
+CFLAGS+=-Wall
DPADD= ${LIBKVM}
LDADD= -lkvm
diff --git a/usr.bin/gcore/aoutcore.c b/usr.bin/gcore/aoutcore.c
index 8ab7b0b..c191a0a 100644
--- a/usr.bin/gcore/aoutcore.c
+++ b/usr.bin/gcore/aoutcore.c
@@ -42,7 +42,7 @@ static const char copyright[] =
static char sccsid[] = "@(#)gcore.c 8.2 (Berkeley) 9/23/93";
#endif
static const char rcsid[] =
- "$Id: gcore.c,v 1.9 1998/09/14 10:09:30 des Exp $";
+ "$Id: gcore.c,v 1.10 1998/10/14 16:16:50 jdp Exp $";
#endif /* not lint */
/*
@@ -81,7 +81,7 @@ static const char rcsid[] =
void core __P((int, int, struct kinfo_proc *));
void datadump __P((int, int, struct proc *, u_long, int));
-void usage __P((void));
+void usage __P((void)) __dead2;
void userdump __P((int, struct proc *, u_long, int));
kvm_t *kd;
@@ -97,11 +97,12 @@ main(argc, argv)
char *argv[];
{
register struct proc *p;
- struct kinfo_proc *ki;
+ struct kinfo_proc *ki = NULL;
struct exec exec;
int ch, cnt, efd, fd, pid, sflag, uid;
char *binfile, *corefile;
char errbuf[_POSIX2_LINE_MAX], fname[MAXPATHLEN + 1];
+ int is_aout;
sflag = 0;
corefile = NULL;
@@ -137,36 +138,6 @@ main(argc, argv)
usage();
}
- kd = kvm_openfiles(0, 0, 0, O_RDONLY, errbuf);
- if (kd == NULL)
- errx(1, "%s", errbuf);
-
- uid = getuid();
-
- ki = kvm_getprocs(kd, KERN_PROC_PID, pid, &cnt);
- if (ki == NULL || cnt != 1)
- errx(1, "%d: not found", pid);
-
- p = &ki->kp_proc;
- if (ki->kp_eproc.e_pcred.p_ruid != uid && uid != 0)
- errx(1, "%d: not owner", pid);
-
- if (p->p_stat == SZOMB)
- errx(1, "%d: zombie", pid);
-
- if (p->p_flag & P_WEXIT)
- errx(1, "%d: process exiting", pid);
- if (p->p_flag & P_SYSTEM) /* Swapper or pagedaemon. */
- errx(1, "%d: system process", pid);
-
- if (corefile == NULL) {
- (void)snprintf(fname, sizeof(fname), "core.%d", pid);
- corefile = fname;
- }
- fd = open(corefile, O_RDWR|O_CREAT|O_TRUNC, DEFFILEMODE);
- if (fd < 0)
- err(1, "%s", corefile);
-
efd = open(binfile, O_RDONLY, 0);
if (efd < 0)
err(1, "%s", binfile);
@@ -175,28 +146,61 @@ main(argc, argv)
if (cnt != sizeof(exec))
errx(1, "%s exec header: %s",
binfile, cnt > 0 ? strerror(EIO) : strerror(errno));
- if (N_BADMAG(exec)) {
- const Elf_Ehdr *ehdr = (const Elf_Ehdr *)&exec;
-
- if (IS_ELF(*ehdr))
- errx(1, "ELF executables are not supported yet");
+ if (!N_BADMAG(exec)) {
+ is_aout = 1;
+ /*
+ * This legacy a.out support uses the kvm interface instead
+ * of procfs.
+ */
+ kd = kvm_openfiles(0, 0, 0, O_RDONLY, errbuf);
+ if (kd == NULL)
+ errx(1, "%s", errbuf);
+
+ uid = getuid();
+
+ ki = kvm_getprocs(kd, KERN_PROC_PID, pid, &cnt);
+ if (ki == NULL || cnt != 1)
+ errx(1, "%d: not found", pid);
+
+ p = &ki->kp_proc;
+ if (ki->kp_eproc.e_pcred.p_ruid != uid && uid != 0)
+ errx(1, "%d: not owner", pid);
+
+ if (p->p_stat == SZOMB)
+ errx(1, "%d: zombie", pid);
+
+ if (p->p_flag & P_WEXIT)
+ errx(1, "%d: process exiting", pid);
+ if (p->p_flag & P_SYSTEM) /* Swapper or pagedaemon. */
+ errx(1, "%d: system process", pid);
+ if (exec.a_text != ptoa(ki->kp_eproc.e_vm.vm_tsize))
+ errx(1, "The executable %s does not belong to"
+ " process %d!\n"
+ "Text segment size (in bytes): executable %d,"
+ " process %d", binfile, pid, exec.a_text,
+ ptoa(ki->kp_eproc.e_vm.vm_tsize));
+ data_offset = N_DATOFF(exec);
+ } else if (IS_ELF(*(Elf_Ehdr *)&exec)) {
+ is_aout = 0;
+ close(efd);
+ } else
errx(1, "Invalid executable file");
- }
-
- /* check the text segment size of the executable and the process */
- if (exec.a_text != ptoa(ki->kp_eproc.e_vm.vm_tsize))
- errx(1,
- "The executable %s does not belong to process %d!\n"
- "Text segment size (in bytes): executable %d, process %d",
- binfile, pid, exec.a_text,
- ptoa(ki->kp_eproc.e_vm.vm_tsize));
- data_offset = N_DATOFF(exec);
+ if (corefile == NULL) {
+ (void)snprintf(fname, sizeof(fname), "core.%d", pid);
+ corefile = fname;
+ }
+ fd = open(corefile, O_RDWR|O_CREAT|O_TRUNC, DEFFILEMODE);
+ if (fd < 0)
+ err(1, "%s", corefile);
if (sflag && kill(pid, SIGSTOP) < 0)
err(1, "%d: stop signal", pid);
- core(efd, fd, ki);
+ if (is_aout)
+ core(efd, fd, ki);
+ else
+ elf_coredump(fd, pid);
if (sflag && kill(pid, SIGCONT) < 0)
err(1, "%d: continue signal", pid);
diff --git a/usr.bin/gcore/elfcore.c b/usr.bin/gcore/elfcore.c
new file mode 100644
index 0000000..1053841
--- /dev/null
+++ b/usr.bin/gcore/elfcore.c
@@ -0,0 +1,513 @@
+/*-
+ * Copyright (c) 1998 John D. Polstra
+ * 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.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$
+ */
+
+#include <sys/param.h>
+#include <sys/lock.h>
+#include <sys/procfs.h>
+#include <vm/vm_param.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_map.h>
+#include <vm/vm_prot.h>
+#include <elf.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "extern.h"
+
+/*
+ * Code for generating ELF core dumps.
+ */
+
+typedef void (*segment_callback)(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(vm_map_entry_t, void *);
+static void cb_size_segment(vm_map_entry_t, void *);
+static void each_writable_segment(vm_map_entry_t, segment_callback,
+ void *closure);
+static void elf_corehdr(int fd, pid_t, vm_map_entry_t, int numsegs,
+ void *hdr, size_t hdrsize);
+static void elf_puthdr(vm_map_entry_t, void *, size_t *,
+ const prstatus_t *, const prfpregset_t *, const prpsinfo_t *, int numsegs);
+static void elf_putnote(void *dst, size_t *off, const char *name, int type,
+ const void *desc, size_t descsz);
+static void freemap(vm_map_entry_t);
+static void readhdrinfo(pid_t, prstatus_t *, prfpregset_t *, prpsinfo_t *);
+static vm_map_entry_t readmap(pid_t);
+
+/*
+ * Write an ELF coredump for the given pid to the given fd.
+ */
+void
+elf_coredump(int fd, pid_t pid)
+{
+ vm_map_entry_t map;
+ struct sseg_closure seginfo;
+ void *hdr;
+ size_t hdrsize;
+ char memname[64];
+ int memfd;
+ Elf_Phdr *php;
+ int i;
+
+ /* Get the program's memory map. */
+ map = readmap(pid);
+
+ /* Size the program segments. */
+ seginfo.count = 0;
+ seginfo.size = 0;
+ each_writable_segment(map, 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(map, (void *)NULL, &hdrsize,
+ (const prstatus_t *)NULL, (const prfpregset_t *)NULL,
+ (const prpsinfo_t *)NULL, seginfo.count);
+
+ /*
+ * Allocate memory for building the header, fill it up,
+ * and write it out.
+ */
+ hdr = malloc(hdrsize);
+ if ((hdr = malloc(hdrsize)) == NULL)
+ errx(1, "out of memory");
+ elf_corehdr(fd, pid, map, seginfo.count, hdr, hdrsize);
+
+ /* Write the contents of all of the writable segments. */
+ snprintf(memname, sizeof memname, "/proc/%d/mem", pid);
+ if ((memfd = open(memname, O_RDONLY)) == -1)
+ err(1, "cannot open %s", memname);
+
+ php = (Elf_Phdr *)((char *)hdr + sizeof(Elf_Ehdr)) + 1;
+ for (i = 0; i < seginfo.count; i++) {
+ int nleft = php->p_filesz;
+
+ lseek(memfd, (off_t)php->p_vaddr, SEEK_SET);
+ while (nleft > 0) {
+ char buf[8*1024];
+ int nwant;
+ int ngot;
+
+ nwant = nleft;
+ if (nwant > sizeof buf)
+ nwant = sizeof buf;
+ ngot = read(memfd, buf, nwant);
+ if (ngot == -1)
+ err(1, "read from %s", memname);
+ if (ngot < nwant)
+ errx(1, "short read from %s:"
+ " wanted %d, got %d\n", nwant, ngot);
+ ngot = write(fd, buf, nwant);
+ if (ngot == -1)
+ err(1, "write of segment %d failed", i);
+ if (ngot != nwant)
+ errx(1, "short write");
+ nleft -= nwant;
+ }
+ php++;
+ }
+ close(memfd);
+ free(hdr);
+ freemap(map);
+}
+
+/*
+ * A callback for each_writable_segment() to write out the segment's
+ * program header entry.
+ */
+static void
+cb_put_phdr(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(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 segment in the given memory map, call the given function
+ * with a pointer to the map entry and some arbitrary caller-supplied
+ * data.
+ */
+static void
+each_writable_segment(vm_map_entry_t map, segment_callback func, void *closure)
+{
+ vm_map_entry_t entry;
+
+ for (entry = map; entry != NULL; entry = entry->next)
+ (*func)(entry, closure);
+}
+
+/*
+ * Write the core file header to the file, including padding up to
+ * the page boundary.
+ */
+static void
+elf_corehdr(int fd, pid_t pid, vm_map_entry_t map, int numsegs, void *hdr,
+ size_t hdrsize)
+{
+ size_t off;
+ prstatus_t status;
+ prfpregset_t fpregset;
+ prpsinfo_t psinfo;
+
+ /* Gather the information for the header. */
+ readhdrinfo(pid, &status, &fpregset, &psinfo);
+
+ /* Fill in the header. */
+ memset(hdr, 0, hdrsize);
+ off = 0;
+ elf_puthdr(map, hdr, &off, &status, &fpregset, &psinfo, numsegs);
+
+ /* Write it to the core file. */
+ if (write(fd, hdr, hdrsize) == -1)
+ err(1, "write");
+}
+
+/*
+ * Generate the ELF coredump header into the buffer at "dst". "dst" may
+ * be NULL, in which case the header is sized but not actually generated.
+ */
+static void
+elf_puthdr(vm_map_entry_t map, 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(map, cb_put_phdr, &phc);
+ }
+}
+
+/*
+ * Emit one note section to "dst", or just size it if "dst" is NULL.
+ */
+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(&note, (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));
+}
+
+/*
+ * Free the memory map.
+ */
+static void
+freemap(vm_map_entry_t map)
+{
+ while (map != NULL) {
+ vm_map_entry_t next = map->next;
+ free(map);
+ map = next;
+ }
+}
+
+/*
+ * Read the process information necessary to fill in the core file's header.
+ */
+static void
+readhdrinfo(pid_t pid, prstatus_t *status, prfpregset_t *fpregset,
+ prpsinfo_t *psinfo)
+{
+ char name[64];
+ char line[256];
+ int fd;
+ int i;
+ int n;
+
+ memset(status, 0, 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 = __FreeBSD_version;
+ status->pr_pid = pid;
+
+ memset(fpregset, 0, sizeof *fpregset);
+
+ memset(psinfo, 0, sizeof *psinfo);
+ psinfo->pr_version = PRPSINFO_VERSION;
+ psinfo->pr_psinfosz = sizeof(prpsinfo_t);
+
+ /* Read the general registers. */
+ snprintf(name, sizeof name, "/proc/%d/regs", pid);
+ if ((fd = open(name, O_RDONLY)) == -1)
+ err(1, "cannot open %s", name);
+ if ((n = read(fd, &status->pr_reg, sizeof status->pr_reg)) == -1)
+ err(1, "read error from %s", name);
+ if (n < sizeof status->pr_reg)
+ errx(1, "short read from %s: wanted %u, got %d", name,
+ sizeof status->pr_reg, n);
+ close(fd);
+
+ /* Read the floating point registers. */
+ snprintf(name, sizeof name, "/proc/%d/fpregs", pid);
+ if ((fd = open(name, O_RDONLY)) == -1)
+ err(1, "cannot open %s", name);
+ if ((n = read(fd, fpregset, sizeof *fpregset)) == -1)
+ err(1, "read error from %s", name);
+ if (n < sizeof *fpregset)
+ errx(1, "short read from %s: wanted %u, got %d", name,
+ sizeof *fpregset, n);
+ close(fd);
+
+ /* Read and parse the process status. */
+ snprintf(name, sizeof name, "/proc/%d/status", pid);
+ if ((fd = open(name, O_RDONLY)) == -1)
+ err(1, "cannot open %s", name);
+ if ((n = read(fd, line, sizeof line - 1)) == -1)
+ err(1, "read error from %s", name);
+ if (n > MAXCOMLEN)
+ n = MAXCOMLEN;
+ for (i = 0; i < n && line[i] != ' '; i++)
+ psinfo->pr_fname[i] = line[i];
+ strncpy(psinfo->pr_psargs, psinfo->pr_fname, PRARGSZ);
+ close(fd);
+}
+
+/*
+ * Read the process's memory map using procfs, and return a list of
+ * VM map entries. Only the non-device read/writable segments are
+ * returned. The map entries in the list aren't fully filled in; only
+ * the items we need are present.
+ */
+static vm_map_entry_t
+readmap(pid_t pid)
+{
+ char mapname[64];
+ int mapfd;
+ ssize_t mapsize;
+ size_t bufsize;
+ char *mapbuf;
+ int pos;
+ vm_map_entry_t map;
+ vm_map_entry_t *linkp;
+
+ snprintf(mapname, sizeof mapname, "/proc/%d/map", pid);
+ if ((mapfd = open(mapname, O_RDONLY)) == -1)
+ err(1, "cannot open %s", mapname);
+
+ /*
+ * Procfs requires (for consistency) that the entire memory map
+ * be read with a single read() call. Start with a reasonbly sized
+ * buffer, and double it until it is big enough.
+ */
+ bufsize = 8 * 1024;
+ mapbuf = NULL;
+ for ( ; ; ) {
+ if ((mapbuf = realloc(mapbuf, bufsize)) == NULL)
+ errx(1, "out of memory");
+ mapsize = read(mapfd, mapbuf, bufsize);
+ if (mapsize != -1 || errno != EFBIG)
+ break;
+ bufsize *= 2;
+ /* This lseek shouldn't be necessary, but it is. */
+ lseek(mapfd, (off_t)0, SEEK_SET);
+ }
+ if (mapsize == -1)
+ err(1, "read error from %s", mapname);
+ if (mapsize == 0)
+ errx(1, "empty map file %s", mapname);
+ close(mapfd);
+
+ pos = 0;
+ map = NULL;
+ linkp = &map;
+ while (pos < mapsize) {
+ vm_map_entry_t ent;
+ vm_offset_t start;
+ vm_offset_t end;
+ char prot[4];
+ char type[16];
+ int n;
+ int len;
+
+ len = 0;
+ n = sscanf(mapbuf + pos, "%x %x %*d %*d %*d %3[-rwx]"
+ " %*d %*d %*x %*s %*s %16s%*[\n]%n",
+ &start, &end, prot, type, &len);
+ if (n != 4)
+ errx(1, "ill-formed line in %s", mapname);
+ pos += len;
+
+ /* Ignore segments of the wrong kind, and unwritable ones */
+ if (strncmp(prot, "rw", 2) != 0 ||
+ (strcmp(type, "default") != 0 &&
+ strcmp(type, "vnode") != 0 &&
+ strcmp(type, "swap") != 0))
+ continue;
+
+ if ((ent = (vm_map_entry_t)calloc(1, sizeof *ent)) == NULL)
+ errx(1, "out of memory");
+ ent->start = start;
+ ent->end = end;
+ ent->protection = VM_PROT_READ | VM_PROT_WRITE;
+ if (prot[2] == 'x')
+ ent->protection |= VM_PROT_EXECUTE;
+
+ *linkp = ent;
+ linkp = &ent->next;
+ }
+ free(mapbuf);
+ return map;
+}
diff --git a/usr.bin/gcore/extern.h b/usr.bin/gcore/extern.h
index 3dccafe..f157e53 100644
--- a/usr.bin/gcore/extern.h
+++ b/usr.bin/gcore/extern.h
@@ -33,5 +33,9 @@
* @(#)extern.h 8.1 (Berkeley) 6/6/93
*/
+#include <sys/types.h>
+#include <kvm.h>
+
void err __P((int, const char *, ...));
+void elf_coredump __P((int, pid_t));
void md_core __P((kvm_t *, int, struct kinfo_proc *));
diff --git a/usr.bin/gcore/gcore.c b/usr.bin/gcore/gcore.c
index 8ab7b0b..c191a0a 100644
--- a/usr.bin/gcore/gcore.c
+++ b/usr.bin/gcore/gcore.c
@@ -42,7 +42,7 @@ static const char copyright[] =
static char sccsid[] = "@(#)gcore.c 8.2 (Berkeley) 9/23/93";
#endif
static const char rcsid[] =
- "$Id: gcore.c,v 1.9 1998/09/14 10:09:30 des Exp $";
+ "$Id: gcore.c,v 1.10 1998/10/14 16:16:50 jdp Exp $";
#endif /* not lint */
/*
@@ -81,7 +81,7 @@ static const char rcsid[] =
void core __P((int, int, struct kinfo_proc *));
void datadump __P((int, int, struct proc *, u_long, int));
-void usage __P((void));
+void usage __P((void)) __dead2;
void userdump __P((int, struct proc *, u_long, int));
kvm_t *kd;
@@ -97,11 +97,12 @@ main(argc, argv)
char *argv[];
{
register struct proc *p;
- struct kinfo_proc *ki;
+ struct kinfo_proc *ki = NULL;
struct exec exec;
int ch, cnt, efd, fd, pid, sflag, uid;
char *binfile, *corefile;
char errbuf[_POSIX2_LINE_MAX], fname[MAXPATHLEN + 1];
+ int is_aout;
sflag = 0;
corefile = NULL;
@@ -137,36 +138,6 @@ main(argc, argv)
usage();
}
- kd = kvm_openfiles(0, 0, 0, O_RDONLY, errbuf);
- if (kd == NULL)
- errx(1, "%s", errbuf);
-
- uid = getuid();
-
- ki = kvm_getprocs(kd, KERN_PROC_PID, pid, &cnt);
- if (ki == NULL || cnt != 1)
- errx(1, "%d: not found", pid);
-
- p = &ki->kp_proc;
- if (ki->kp_eproc.e_pcred.p_ruid != uid && uid != 0)
- errx(1, "%d: not owner", pid);
-
- if (p->p_stat == SZOMB)
- errx(1, "%d: zombie", pid);
-
- if (p->p_flag & P_WEXIT)
- errx(1, "%d: process exiting", pid);
- if (p->p_flag & P_SYSTEM) /* Swapper or pagedaemon. */
- errx(1, "%d: system process", pid);
-
- if (corefile == NULL) {
- (void)snprintf(fname, sizeof(fname), "core.%d", pid);
- corefile = fname;
- }
- fd = open(corefile, O_RDWR|O_CREAT|O_TRUNC, DEFFILEMODE);
- if (fd < 0)
- err(1, "%s", corefile);
-
efd = open(binfile, O_RDONLY, 0);
if (efd < 0)
err(1, "%s", binfile);
@@ -175,28 +146,61 @@ main(argc, argv)
if (cnt != sizeof(exec))
errx(1, "%s exec header: %s",
binfile, cnt > 0 ? strerror(EIO) : strerror(errno));
- if (N_BADMAG(exec)) {
- const Elf_Ehdr *ehdr = (const Elf_Ehdr *)&exec;
-
- if (IS_ELF(*ehdr))
- errx(1, "ELF executables are not supported yet");
+ if (!N_BADMAG(exec)) {
+ is_aout = 1;
+ /*
+ * This legacy a.out support uses the kvm interface instead
+ * of procfs.
+ */
+ kd = kvm_openfiles(0, 0, 0, O_RDONLY, errbuf);
+ if (kd == NULL)
+ errx(1, "%s", errbuf);
+
+ uid = getuid();
+
+ ki = kvm_getprocs(kd, KERN_PROC_PID, pid, &cnt);
+ if (ki == NULL || cnt != 1)
+ errx(1, "%d: not found", pid);
+
+ p = &ki->kp_proc;
+ if (ki->kp_eproc.e_pcred.p_ruid != uid && uid != 0)
+ errx(1, "%d: not owner", pid);
+
+ if (p->p_stat == SZOMB)
+ errx(1, "%d: zombie", pid);
+
+ if (p->p_flag & P_WEXIT)
+ errx(1, "%d: process exiting", pid);
+ if (p->p_flag & P_SYSTEM) /* Swapper or pagedaemon. */
+ errx(1, "%d: system process", pid);
+ if (exec.a_text != ptoa(ki->kp_eproc.e_vm.vm_tsize))
+ errx(1, "The executable %s does not belong to"
+ " process %d!\n"
+ "Text segment size (in bytes): executable %d,"
+ " process %d", binfile, pid, exec.a_text,
+ ptoa(ki->kp_eproc.e_vm.vm_tsize));
+ data_offset = N_DATOFF(exec);
+ } else if (IS_ELF(*(Elf_Ehdr *)&exec)) {
+ is_aout = 0;
+ close(efd);
+ } else
errx(1, "Invalid executable file");
- }
-
- /* check the text segment size of the executable and the process */
- if (exec.a_text != ptoa(ki->kp_eproc.e_vm.vm_tsize))
- errx(1,
- "The executable %s does not belong to process %d!\n"
- "Text segment size (in bytes): executable %d, process %d",
- binfile, pid, exec.a_text,
- ptoa(ki->kp_eproc.e_vm.vm_tsize));
- data_offset = N_DATOFF(exec);
+ if (corefile == NULL) {
+ (void)snprintf(fname, sizeof(fname), "core.%d", pid);
+ corefile = fname;
+ }
+ fd = open(corefile, O_RDWR|O_CREAT|O_TRUNC, DEFFILEMODE);
+ if (fd < 0)
+ err(1, "%s", corefile);
if (sflag && kill(pid, SIGSTOP) < 0)
err(1, "%d: stop signal", pid);
- core(efd, fd, ki);
+ if (is_aout)
+ core(efd, fd, ki);
+ else
+ elf_coredump(fd, pid);
if (sflag && kill(pid, SIGCONT) < 0)
err(1, "%d: continue signal", pid);
OpenPOWER on IntegriCloud