From owner-svn-src-stable-7@FreeBSD.ORG Tue Dec 28 18:37:10 2010 Return-Path: Delivered-To: svn-src-stable-7@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id B962E106564A; Tue, 28 Dec 2010 18:37:10 +0000 (UTC) (envelope-from jhb@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id A7B388FC18; Tue, 28 Dec 2010 18:37:10 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id oBSIbAxY073432; Tue, 28 Dec 2010 18:37:10 GMT (envelope-from jhb@svn.freebsd.org) Received: (from jhb@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id oBSIbALd073429; Tue, 28 Dec 2010 18:37:10 GMT (envelope-from jhb@svn.freebsd.org) Message-Id: <201012281837.oBSIbALd073429@svn.freebsd.org> From: John Baldwin Date: Tue, 28 Dec 2010 18:37:10 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org X-SVN-Group: stable-7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r216767 - in stable/7/sys: kern sys X-BeenThere: svn-src-stable-7@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for only the 7-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 28 Dec 2010 18:37:10 -0000 Author: jhb Date: Tue Dec 28 18:37:10 2010 New Revision: 216767 URL: http://svn.freebsd.org/changeset/base/216767 Log: MFC 208587: Add support for reporting the NOCOREDUMP flag from sysctl_kern_proc_vmmap(). Modified: stable/7/sys/kern/kern_proc.c stable/7/sys/sys/user.h Directory Properties: stable/7/sys/ (props changed) stable/7/sys/cddl/contrib/opensolaris/ (props changed) stable/7/sys/contrib/dev/acpica/ (props changed) stable/7/sys/contrib/pf/ (props changed) Modified: stable/7/sys/kern/kern_proc.c ============================================================================== --- stable/7/sys/kern/kern_proc.c Tue Dec 28 17:45:43 2010 (r216766) +++ stable/7/sys/kern/kern_proc.c Tue Dec 28 18:37:10 2010 (r216767) @@ -1456,6 +1456,8 @@ sysctl_kern_proc_ovmmap(SYSCTL_HANDLER_A kve->kve_flags |= KVME_FLAG_COW; if (entry->eflags & MAP_ENTRY_NEEDS_COPY) kve->kve_flags |= KVME_FLAG_NEEDS_COPY; + if (entry->eflags & MAP_ENTRY_NOCOREDUMP) + kve->kve_flags |= KVME_FLAG_NOCOREDUMP; last_timestamp = map->timestamp; vm_map_unlock_read(map); @@ -1630,6 +1632,8 @@ sysctl_kern_proc_vmmap(SYSCTL_HANDLER_AR kve->kve_flags |= KVME_FLAG_COW; if (entry->eflags & MAP_ENTRY_NEEDS_COPY) kve->kve_flags |= KVME_FLAG_NEEDS_COPY; + if (entry->eflags & MAP_ENTRY_NOCOREDUMP) + kve->kve_flags |= KVME_FLAG_NOCOREDUMP; last_timestamp = map->timestamp; vm_map_unlock_read(map); Modified: stable/7/sys/sys/user.h ============================================================================== --- stable/7/sys/sys/user.h Tue Dec 28 17:45:43 2010 (r216766) +++ stable/7/sys/sys/user.h Tue Dec 28 18:37:10 2010 (r216767) @@ -343,6 +343,7 @@ struct kinfo_file { #define KVME_FLAG_COW 0x00000001 #define KVME_FLAG_NEEDS_COPY 0x00000002 +#define KVME_FLAG_NOCOREDUMP 0x00000004 #if defined(__amd64__) #define KINFO_OVMENTRY_SIZE 1168 From owner-svn-src-stable-7@FreeBSD.ORG Tue Dec 28 19:26:58 2010 Return-Path: Delivered-To: svn-src-stable-7@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id F24B31065672; Tue, 28 Dec 2010 19:26:57 +0000 (UTC) (envelope-from jhb@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id DEF218FC1C; Tue, 28 Dec 2010 19:26:57 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id oBSJQvgY074780; Tue, 28 Dec 2010 19:26:57 GMT (envelope-from jhb@svn.freebsd.org) Received: (from jhb@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id oBSJQvJJ074774; Tue, 28 Dec 2010 19:26:57 GMT (envelope-from jhb@svn.freebsd.org) Message-Id: <201012281926.oBSJQvJJ074774@svn.freebsd.org> From: John Baldwin Date: Tue, 28 Dec 2010 19:26:57 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org X-SVN-Group: stable-7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r216771 - stable/7/usr.bin/gcore X-BeenThere: svn-src-stable-7@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for only the 7-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 28 Dec 2010 19:26:58 -0000 Author: jhb Date: Tue Dec 28 19:26:57 2010 New Revision: 216771 URL: http://svn.freebsd.org/changeset/base/216771 Log: MFC 199805,203532,204329,210063,210065: - Change gcore in order to get rid of the procfs accesses and use FreeBSD's specific sysctls and ptrace interfaces. This change switches a bit gcore POLA that is summarized here: - now gcore can recognize threads within the process and handle dumps on thread-scope - the process to be analyzed will be stopped during its gcore run - gcore may not work with processes which are actively being analyzed by gdb or truss - the ptrace interface may cause syscalls to return EINTR, thus interferring with signals handling within the process - Fix gcore so that it can have the '-s' flag without hanging. - Fix the way the segments are included in the gcore outputs (with the default invokation): - Right now if segments are not writable are not included. Remove this. - Right now if a segment is mapped with NOCORE the check is not honoured. Change this by checking the newly added flag, from libutil, KVME_FLAG_NOCOREDUMP. Besides that, add a new flag (-f) that forces a 'full' dump of all the segments excluding just the malformed ones. This might be used very carefully as, among the reported segments, there could be memory mapped areas that could be vital to program execution. Modified: stable/7/usr.bin/gcore/Makefile stable/7/usr.bin/gcore/elfcore.c stable/7/usr.bin/gcore/extern.h stable/7/usr.bin/gcore/gcore.1 stable/7/usr.bin/gcore/gcore.c Directory Properties: stable/7/usr.bin/gcore/ (props changed) Modified: stable/7/usr.bin/gcore/Makefile ============================================================================== --- stable/7/usr.bin/gcore/Makefile Tue Dec 28 19:22:53 2010 (r216770) +++ stable/7/usr.bin/gcore/Makefile Tue Dec 28 19:26:57 2010 (r216771) @@ -3,5 +3,7 @@ PROG= gcore SRCS= elfcore.c gcore.c +DPADD= ${LIBUTIL} +LDADD= -lutil .include Modified: stable/7/usr.bin/gcore/elfcore.c ============================================================================== --- stable/7/usr.bin/gcore/elfcore.c Tue Dec 28 19:22:53 2010 (r216770) +++ stable/7/usr.bin/gcore/elfcore.c Tue Dec 28 19:26:57 2010 (r216771) @@ -1,4 +1,5 @@ /*- + * Copyright (c) 2007 Sandvine Incorporated * Copyright (c) 1998 John D. Polstra * All rights reserved. * @@ -29,8 +30,12 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include +#include +#include +#include #include #include #include @@ -44,6 +49,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include "extern.h" @@ -69,16 +75,15 @@ static void cb_put_phdr(vm_map_entry_t, 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_detach(void); /* atexit() handler. */ +static void elf_puthdr(pid_t, vm_map_entry_t, void *, size_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); +static pid_t g_pid; /* Pid being dumped, global for elf_detach */ + static int elf_ident(int efd, pid_t pid __unused, char *binfile __unused) { @@ -93,6 +98,14 @@ elf_ident(int efd, pid_t pid __unused, c return (0); } +static void +elf_detach(void) +{ + + if (g_pid != 0) + ptrace(PT_DETACH, g_pid, (caddr_t)1, 0); +} + /* * Write an ELF coredump for the given pid to the given fd. */ @@ -103,11 +116,20 @@ elf_coredump(int efd __unused, int fd, p struct sseg_closure seginfo; void *hdr; size_t hdrsize; - char memname[64]; - int memfd; Elf_Phdr *php; int i; + /* Attach to process to dump. */ + g_pid = pid; + if (atexit(elf_detach) != 0) + err(1, "atexit"); + errno = 0; + ptrace(PT_ATTACH, pid, NULL, 0); + if (errno) + err(1, "PT_ATTACH"); + if (waitpid(pid, NULL, 0) == -1) + err(1, "waitpid"); + /* Get the program's memory map. */ map = readmap(pid); @@ -122,28 +144,31 @@ elf_coredump(int efd __unused, int fd, p * 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); + elf_puthdr(pid, map, NULL, &hdrsize, seginfo.count); /* * Allocate memory for building the header, fill it up, * and write it out. */ - if ((hdr = malloc(hdrsize)) == NULL) + if ((hdr = calloc(1, 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); + /* Fill in the header. */ + hdrsize = 0; + elf_puthdr(pid, map, hdr, &hdrsize, seginfo.count); + + /* Write it to the core file. */ + if (write(fd, hdr, hdrsize) == -1) + err(1, "write"); + /* Write the contents of all of the writable segments. */ php = (Elf_Phdr *)((char *)hdr + sizeof(Elf_Ehdr)) + 1; for (i = 0; i < seginfo.count; i++) { + struct ptrace_io_desc iorequest; uintmax_t nleft = php->p_filesz; - lseek(memfd, (off_t)php->p_vaddr, SEEK_SET); + iorequest.piod_op = PIOD_READ_D; + iorequest.piod_offs = (caddr_t)php->p_vaddr; while (nleft > 0) { char buf[8*1024]; size_t nwant; @@ -153,12 +178,12 @@ elf_coredump(int efd __unused, int fd, p nwant = sizeof buf; else nwant = nleft; - ngot = read(memfd, buf, nwant); - if (ngot == -1) - err(1, "read from %s", memname); + iorequest.piod_addr = buf; + iorequest.piod_len = nwant; + ptrace(PT_IO, pid, (caddr_t)&iorequest, 0); + ngot = iorequest.piod_len; if ((size_t)ngot < nwant) - errx(1, "short read from %s:" - " wanted %zu, got %zd", memname, + errx(1, "short read wanted %d, got %d", nwant, ngot); ngot = write(fd, buf, nwant); if (ngot == -1) @@ -166,10 +191,10 @@ elf_coredump(int efd __unused, int fd, p if ((size_t)ngot != nwant) errx(1, "short write"); nleft -= nwant; + iorequest.piod_offs += ngot; } php++; } - close(memfd); free(hdr); freemap(map); } @@ -231,30 +256,25 @@ each_writable_segment(vm_map_entry_t map (*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) +elf_getstatus(pid_t pid, prpsinfo_t *psinfo) { - 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"); + struct kinfo_proc kobj; + int name[4]; + size_t len; + + name[0] = CTL_KERN; + name[1] = KERN_PROC; + name[2] = KERN_PROC_PID; + name[3] = pid; + + len = sizeof(kobj); + if (sysctl(name, 4, &kobj, &len, NULL, 0) == -1) + err(1, "error accessing kern.proc.pid.%u sysctl", pid); + if (kobj.ki_pid != pid) + err(1, "error accessing kern.proc.pid.%u sysctl datas", pid); + strncpy(psinfo->pr_fname, kobj.ki_comm, MAXCOMLEN); + strncpy(psinfo->pr_psargs, psinfo->pr_fname, PRARGSZ); } /* @@ -262,13 +282,24 @@ elf_corehdr(int fd, pid_t pid, vm_map_en * 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) +elf_puthdr(pid_t pid, vm_map_entry_t map, void *dst, size_t *off, int numsegs) { + struct { + prstatus_t status; + prfpregset_t fpregset; + prpsinfo_t psinfo; + } *tempdata; size_t ehoff; size_t phoff; size_t noteoff; size_t notesz; + size_t threads; + lwpid_t *tids; + int i; + + prstatus_t *status; + prfpregset_t *fpregset; + prpsinfo_t *psinfo; ehoff = *off; *off += sizeof(Elf_Ehdr); @@ -277,14 +308,68 @@ elf_puthdr(vm_map_entry_t map, void *dst *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); + + if (dst != NULL) { + if ((tempdata = calloc(1, sizeof(*tempdata))) == NULL) + errx(1, "out of memory"); + status = &tempdata->status; + fpregset = &tempdata->fpregset; + psinfo = &tempdata->psinfo; + } else { + tempdata = NULL; + status = NULL; + fpregset = NULL; + psinfo = NULL; + } + + errno = 0; + threads = ptrace(PT_GETNUMLWPS, pid, NULL, 0); + if (errno) + err(1, "PT_GETNUMLWPS"); + + if (dst != NULL) { + psinfo->pr_version = PRPSINFO_VERSION; + psinfo->pr_psinfosz = sizeof(prpsinfo_t); + elf_getstatus(pid, psinfo); + + } elf_putnote(dst, off, "FreeBSD", NT_PRPSINFO, psinfo, sizeof *psinfo); + + if (dst != NULL) { + tids = malloc(threads * sizeof(*tids)); + if (tids == NULL) + errx(1, "out of memory"); + errno = 0; + ptrace(PT_GETLWPLIST, pid, (void *)tids, threads); + if (errno) + err(1, "PT_GETLWPLIST"); + } + for (i = 0; i < threads; ++i) { + if (dst != NULL) { + 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 = tids[i]; + + ptrace(PT_GETREGS, tids[i], (void *)&status->pr_reg, 0); + ptrace(PT_GETFPREGS, tids[i], (void *)fpregset, 0); + } + elf_putnote(dst, off, "FreeBSD", NT_PRSTATUS, status, + sizeof *status); + elf_putnote(dst, off, "FreeBSD", NT_FPREGSET, fpregset, + sizeof *fpregset); + } + notesz = *off - noteoff; + if (dst != NULL) { + free(tids); + free(tempdata); + } + /* Align up to a page boundary for the program segments. */ *off = round_page(*off); @@ -381,70 +466,7 @@ freemap(vm_map_entry_t map) } /* - * 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 ((size_t)n < sizeof(status->pr_reg)) - errx(1, "short read from %s: wanted %zu, 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 ((size_t)n < sizeof(*fpregset)) - errx(1, "short read from %s: wanted %zu, 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 + * Read the process's memory map using kinfo_getvmmap(), 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. @@ -452,83 +474,49 @@ readhdrinfo(pid_t pid, prstatus_t *statu 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); + vm_map_entry_t ent, *linkp, map; + struct kinfo_vmentry *vmentl, *kve; + int i, nitems; + + vmentl = kinfo_getvmmap(pid, &nitems); + if (vmentl == NULL) + err(1, "cannot retrieve mappings for %u process", pid); - /* - * Procfs requires (for consistency) that the entire memory map - * be read with a single read() call. Start with a reasonably sized - * buffer, and double it until it is big enough. - */ - bufsize = 8 * 1024; - mapbuf = NULL; - for ( ; ; ) { - if ((mapbuf = realloc(mapbuf, bufsize + 1)) == 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); - mapbuf[mapsize] = 0; - close(mapfd); - - pos = 0; map = NULL; linkp = ↦ - while (pos < mapsize) { - vm_map_entry_t ent; - u_long start; - u_long end; - char prot[4]; - char type[16]; - int n; - int len; - - len = 0; - n = sscanf(mapbuf + pos, "%lx %lx %*d %*d %*x %3[-rwx]" - " %*d %*d %*x %*s %*s %16s %*s%*[\n]%n", - &start, &end, prot, type, &len); - if (n != 4 || len == 0) - errx(1, "ill-formed line in %s starting at character %d", mapname, pos + 1); - 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)) + for (i = 0; i < nitems; i++) { + kve = &vmentl[i]; + + /* + * Ignore 'malformed' segments or ones representing memory + * mapping with MAP_NOCORE on. + * If the 'full' support is disabled, just dump the most + * meaningful data segments. + */ + if ((kve->kve_protection & KVME_PROT_READ) == 0 || + (kve->kve_flags & KVME_FLAG_NOCOREDUMP) != 0 || + kve->kve_type == KVME_TYPE_DEAD || + kve->kve_type == KVME_TYPE_UNKNOWN || + ((pflags & PFLAGS_FULL) == 0 && + kve->kve_type != KVME_TYPE_DEFAULT && + kve->kve_type != KVME_TYPE_VNODE && + kve->kve_type != KVME_TYPE_SWAP)) continue; - if ((ent = (vm_map_entry_t)calloc(1, sizeof *ent)) == NULL) + ent = calloc(1, sizeof(*ent)); + if (ent == NULL) errx(1, "out of memory"); - ent->start = start; - ent->end = end; + ent->start = (vm_offset_t)kve->kve_start; + ent->end = (vm_offset_t)kve->kve_end; ent->protection = VM_PROT_READ | VM_PROT_WRITE; - if (prot[2] == 'x') - ent->protection |= VM_PROT_EXECUTE; + if ((kve->kve_protection & KVME_PROT_EXEC) != 0) + ent->protection |= VM_PROT_EXECUTE; *linkp = ent; linkp = &ent->next; } - free(mapbuf); - return map; + free(vmentl); + return (map); } struct dumpers elfdump = { elf_ident, elf_coredump }; Modified: stable/7/usr.bin/gcore/extern.h ============================================================================== --- stable/7/usr.bin/gcore/extern.h Tue Dec 28 19:22:53 2010 (r216770) +++ stable/7/usr.bin/gcore/extern.h Tue Dec 28 19:26:57 2010 (r216771) @@ -34,7 +34,11 @@ * $FreeBSD$ */ +#define PFLAGS_FULL 0x01 +#define PFLAGS_RESUME 0x02 + struct dumpers { int (*ident)(int efd, pid_t pid, char *binfile); void (*dump)(int efd, int fd, pid_t pid); }; +extern int pflags; Modified: stable/7/usr.bin/gcore/gcore.1 ============================================================================== --- stable/7/usr.bin/gcore/gcore.1 Tue Dec 28 19:22:53 2010 (r216770) +++ stable/7/usr.bin/gcore/gcore.1 Tue Dec 28 19:26:57 2010 (r216771) @@ -32,7 +32,7 @@ .\" @(#)gcore.1 8.2 (Berkeley) 4/18/94 .\" $FreeBSD$ .\" -.Dd April 18, 1994 +.Dd July 14, 2010 .Dt GCORE 1 .Os .Sh NAME @@ -40,6 +40,7 @@ .Nd get core images of running process .Sh SYNOPSIS .Nm +.Op Fl f .Op Fl s .Op Fl c Ar core .Op Ar executable @@ -55,17 +56,19 @@ By default, the core is written to the f The process identifier, .Ar pid , must be given on the command line. -If no executable image is -specified, -.Nm -will use -.Dq Pa /proc//file . .Pp The following options are available: .Bl -tag -width indent .It Fl c Write the core file to the specified file instead of .Dq Pa core. . +.It Fl f +Dumps all the available segments, excluding only the malformed ones and +un-dumpable ones. Unlike the default invocation, it also dumps +device- and sglist-mapped areas that may invalidate the state of +some transactions. This flag must be used very carefully, when the +behavior of the application is fully understood and the fallouts can +be easily controlled. .It Fl s Stop the process while gathering the core image, and resume it when done. @@ -80,8 +83,6 @@ The same effect can be achieved manually .Bl -tag -width /var/log/messages -compact .It Pa core. the core image -.It Pa /proc//file -the executable image .El .Sh HISTORY A @@ -89,12 +90,15 @@ A utility appeared in .Bx 4.2 . .Sh BUGS -Context switches or paging activity that occur while -.Nm -is running may cause the program to become confused. -For best results, use -.Fl s -to temporarily stop the target process. +Because of the +.Xr ptrace 2 +usage +.Nm +may not work with processes which are actively investigated with +.Xr truss 1 +or +.Xr gdb 1 . +Additionally, interruptable sleeps may exit with EINTR. .Pp The .Nm Modified: stable/7/usr.bin/gcore/gcore.c ============================================================================== --- stable/7/usr.bin/gcore/gcore.c Tue Dec 28 19:22:53 2010 (r216770) +++ stable/7/usr.bin/gcore/gcore.c Tue Dec 28 19:26:57 2010 (r216771) @@ -61,19 +61,19 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include -#include #include #include #include #include #include "extern.h" +int pflags; static void killed(int); -static void restart_target(void); static void usage(void) __dead2; static pid_t pid; @@ -83,20 +83,24 @@ SET_DECLARE(dumpset, struct dumpers); int main(int argc, char *argv[]) { - int ch, efd, fd, sflag; + int ch, efd, fd, name[4]; char *binfile, *corefile; - char fname[MAXPATHLEN]; + char passpath[MAXPATHLEN], fname[MAXPATHLEN]; struct dumpers **d, *dumper; + size_t len; - sflag = 0; + pflags = 0; corefile = NULL; - while ((ch = getopt(argc, argv, "c:s")) != -1) { + while ((ch = getopt(argc, argv, "c:fs")) != -1) { switch (ch) { case 'c': corefile = optarg; break; + case 'f': + pflags |= PFLAGS_FULL; + break; case 's': - sflag = 1; + pflags |= PFLAGS_RESUME; break; default: usage(); @@ -109,9 +113,14 @@ main(int argc, char *argv[]) switch (argc) { case 1: pid = atoi(argv[0]); - asprintf(&binfile, "/proc/%d/file", pid); - if (binfile == NULL) - errx(1, "allocation failure"); + name[0] = CTL_KERN; + name[1] = KERN_PROC; + name[2] = KERN_PROC_PATHNAME; + name[3] = pid; + len = sizeof(passpath); + if (sysctl(name, 4, passpath, &len, NULL, 0) == -1) + errx(1, "kern.proc.pathname failure"); + binfile = passpath; break; case 2: pid = atoi(argv[1]); @@ -141,36 +150,28 @@ main(int argc, char *argv[]) fd = open(corefile, O_RDWR|O_CREAT|O_TRUNC, DEFFILEMODE); if (fd < 0) err(1, "%s", corefile); - if (sflag) { - signal(SIGHUP, killed); - signal(SIGINT, killed); - signal(SIGTERM, killed); - if (kill(pid, SIGSTOP) == -1) - err(1, "%d: stop signal", pid); - atexit(restart_target); - } + /* + * The semantics of the 's' flag is to stop the target process. + * Previous versions of gcore would manage this by trapping SIGHUP, + * SIGINT and SIGTERM (to be passed to the target pid), and then + * signal the child to stop. + * + * However, this messes up if the selected dumper uses ptrace calls + * that leave the child already stopped. The waitpid call in elfcore + * never returns. + * + * The best thing to do here is to externalize the 's' flag and let + * each dumper dispose of what that means, if anything. For the elfcore + * dumper, the 's' flag is a no-op since the ptrace attach stops the + * process in question already. + */ + dumper->dump(efd, fd, pid); (void)close(fd); (void)close(efd); exit(0); } -static void -killed(int sig) -{ - - restart_target(); - signal(sig, SIG_DFL); - kill(getpid(), sig); -} - -static void -restart_target(void) -{ - - kill(pid, SIGCONT); -} - void usage(void) { From owner-svn-src-stable-7@FreeBSD.ORG Fri Dec 31 18:16:44 2010 Return-Path: Delivered-To: svn-src-stable-7@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 5E84B1065670; Fri, 31 Dec 2010 18:16:44 +0000 (UTC) (envelope-from bz@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 4D4328FC16; Fri, 31 Dec 2010 18:16:44 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id oBVIGivw084554; Fri, 31 Dec 2010 18:16:44 GMT (envelope-from bz@svn.freebsd.org) Received: (from bz@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id oBVIGi3a084551; Fri, 31 Dec 2010 18:16:44 GMT (envelope-from bz@svn.freebsd.org) Message-Id: <201012311816.oBVIGi3a084551@svn.freebsd.org> From: "Bjoern A. Zeeb" Date: Fri, 31 Dec 2010 18:16:44 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org X-SVN-Group: stable-7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r216850 - in stable/7: . sys/sys X-BeenThere: svn-src-stable-7@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for only the 7-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 31 Dec 2010 18:16:44 -0000 Author: bz Date: Fri Dec 31 18:16:44 2010 New Revision: 216850 URL: http://svn.freebsd.org/changeset/base/216850 Log: MFC r216848: Happy New Year 2011. Approved by: core (kib) Modified: stable/7/COPYRIGHT (contents, props changed) stable/7/sys/sys/copyright.h Directory Properties: stable/7/sys/ (props changed) stable/7/sys/cddl/contrib/opensolaris/ (props changed) stable/7/sys/contrib/dev/acpica/ (props changed) stable/7/sys/contrib/pf/ (props changed) Modified: stable/7/COPYRIGHT ============================================================================== --- stable/7/COPYRIGHT Fri Dec 31 18:16:15 2010 (r216849) +++ stable/7/COPYRIGHT Fri Dec 31 18:16:44 2010 (r216850) @@ -4,7 +4,7 @@ The compilation of software known as FreeBSD is distributed under the following terms: -Copyright (c) 1992-2010 The FreeBSD Project. All rights reserved. +Copyright (c) 1992-2011 The FreeBSD Project. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions Modified: stable/7/sys/sys/copyright.h ============================================================================== --- stable/7/sys/sys/copyright.h Fri Dec 31 18:16:15 2010 (r216849) +++ stable/7/sys/sys/copyright.h Fri Dec 31 18:16:44 2010 (r216850) @@ -1,5 +1,5 @@ /*- - * Copyright (C) 1992-2010 The FreeBSD Project. All rights reserved. + * Copyright (C) 1992-2011 The FreeBSD Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,7 +30,7 @@ /* FreeBSD */ #define COPYRIGHT_FreeBSD \ - "Copyright (c) 1992-2010 The FreeBSD Project.\n" + "Copyright (c) 1992-2011 The FreeBSD Project.\n" /* Foundation */ #define TRADEMARK_Foundation \