From owner-freebsd-bugs@FreeBSD.ORG Tue Apr 16 19:20:01 2013 Return-Path: Delivered-To: freebsd-bugs@smarthost.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.FreeBSD.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 450A233C for ; Tue, 16 Apr 2013 19:20:01 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:1900:2254:206c::16:87]) by mx1.freebsd.org (Postfix) with ESMTP id 36AA6110C for ; Tue, 16 Apr 2013 19:20:01 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.6/8.14.6) with ESMTP id r3GJK1qE031502 for ; Tue, 16 Apr 2013 19:20:01 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.6/8.14.6/Submit) id r3GJK0V6031501; Tue, 16 Apr 2013 19:20:00 GMT (envelope-from gnats) Date: Tue, 16 Apr 2013 19:20:00 GMT Message-Id: <201304161920.r3GJK0V6031501@freefall.freebsd.org> To: freebsd-bugs@FreeBSD.org Cc: From: dfilter@FreeBSD.ORG (dfilter service) Subject: Re: kern/173723: commit references a PR X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list Reply-To: dfilter service List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 16 Apr 2013 19:20:01 -0000 The following reply was made to PR kern/173723; it has been noted by GNATS. From: dfilter@FreeBSD.ORG (dfilter service) To: bug-followup@FreeBSD.org Cc: Subject: Re: kern/173723: commit references a PR Date: Tue, 16 Apr 2013 19:19:29 +0000 (UTC) Author: trociny Date: Tue Apr 16 19:19:14 2013 New Revision: 249558 URL: http://svnweb.freebsd.org/changeset/base/249558 Log: Add a new set of notes to a process core dump to store procstat data. The notes format is a header of sizeof(int), which stores the size of the corresponding data structure to provide some versioning, and data in the format as it is returned by a related sysctl call. The userland tools (procstat(1)) will be taught to extract this data, providing additional info for postmortem analysis. PR: kern/173723 Suggested by: jhb Discussed with: jhb, kib Reviewed by: jhb (initial version), kib MFC after: 1 month Modified: head/sys/kern/imgact_elf.c head/sys/sys/elf_common.h Modified: head/sys/kern/imgact_elf.c ============================================================================== --- head/sys/kern/imgact_elf.c Tue Apr 16 17:50:20 2013 (r249557) +++ head/sys/kern/imgact_elf.c Tue Apr 16 19:19:14 2013 (r249558) @@ -66,6 +66,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include @@ -1062,12 +1063,22 @@ static void __elfN(puthdr)(struct thread static void __elfN(putnote)(struct note_info *, struct sbuf *); static size_t register_note(struct note_info_list *, int, outfunc_t, void *); static int sbuf_drain_core_output(void *, const char *, int); +static int sbuf_drain_count(void *arg, const char *data, int len); static void __elfN(note_fpregset)(void *, struct sbuf *, size_t *); static void __elfN(note_prpsinfo)(void *, struct sbuf *, size_t *); static void __elfN(note_prstatus)(void *, struct sbuf *, size_t *); static void __elfN(note_threadmd)(void *, struct sbuf *, size_t *); static void __elfN(note_thrmisc)(void *, struct sbuf *, size_t *); +static void __elfN(note_procstat_auxv)(void *, struct sbuf *, size_t *); +static void __elfN(note_procstat_proc)(void *, struct sbuf *, size_t *); +static void __elfN(note_procstat_psstrings)(void *, struct sbuf *, size_t *); +static void note_procstat_files(void *, struct sbuf *, size_t *); +static void note_procstat_groups(void *, struct sbuf *, size_t *); +static void note_procstat_osrel(void *, struct sbuf *, size_t *); +static void note_procstat_rlimit(void *, struct sbuf *, size_t *); +static void note_procstat_umask(void *, struct sbuf *, size_t *); +static void note_procstat_vmmap(void *, struct sbuf *, size_t *); #ifdef COMPRESS_USER_CORES extern int compress_user_cores; @@ -1113,9 +1124,21 @@ static int sbuf_drain_core_output(void *arg, const char *data, int len) { struct sbuf_drain_core_params *p; - int error; + int error, locked; p = (struct sbuf_drain_core_params *)arg; + + /* + * Some kern_proc out routines that print to this sbuf may + * call us with the process lock held. Draining with the + * non-sleepable lock held is unsafe. The lock is needed for + * those routines when dumping a live process. In our case we + * can safely release the lock before draining and acquire + * again after. + */ + locked = PROC_LOCKED(p->td->td_proc); + if (locked) + PROC_UNLOCK(p->td->td_proc); #ifdef COMPRESS_USER_CORES if (p->gzfile != Z_NULL) error = compress_core(p->gzfile, NULL, __DECONST(char *, data), @@ -1126,12 +1149,27 @@ sbuf_drain_core_output(void *arg, const __DECONST(void *, data), len, p->offset, UIO_SYSSPACE, IO_UNIT | IO_DIRECT, p->active_cred, p->file_cred, NULL, p->td); + if (locked) + PROC_LOCK(p->td->td_proc); if (error != 0) return (-error); p->offset += len; return (len); } +/* + * Drain into a counter. + */ +static int +sbuf_drain_count(void *arg, const char *data __unused, int len) +{ + size_t *sizep; + + sizep = (size_t *)arg; + *sizep += len; + return (len); +} + int __elfN(coredump)(struct thread *td, struct vnode *vp, off_t limit, int flags) { @@ -1436,6 +1474,25 @@ __elfN(prepare_notes)(struct thread *td, thr = TAILQ_NEXT(thr, td_plist); } + size += register_note(list, NT_PROCSTAT_PROC, + __elfN(note_procstat_proc), p); + size += register_note(list, NT_PROCSTAT_FILES, + note_procstat_files, p); + size += register_note(list, NT_PROCSTAT_VMMAP, + note_procstat_vmmap, p); + size += register_note(list, NT_PROCSTAT_GROUPS, + note_procstat_groups, p); + size += register_note(list, NT_PROCSTAT_UMASK, + note_procstat_umask, p); + size += register_note(list, NT_PROCSTAT_RLIMIT, + note_procstat_rlimit, p); + size += register_note(list, NT_PROCSTAT_OSREL, + note_procstat_osrel, p); + size += register_note(list, NT_PROCSTAT_PSSTRINGS, + __elfN(note_procstat_psstrings), p); + size += register_note(list, NT_PROCSTAT_AUXV, + __elfN(note_procstat_auxv), p); + *sizep = size; } @@ -1562,6 +1619,9 @@ typedef struct fpreg32 elf_prfpregset_t; typedef struct fpreg32 elf_fpregset_t; typedef struct reg32 elf_gregset_t; typedef struct thrmisc32 elf_thrmisc_t; +#define ELF_KERN_PROC_MASK KERN_PROC_MASK32 +typedef struct kinfo_proc32 elf_kinfo_proc_t; +typedef uint32_t elf_ps_strings_t; #else typedef prstatus_t elf_prstatus_t; typedef prpsinfo_t elf_prpsinfo_t; @@ -1569,6 +1629,9 @@ typedef prfpregset_t elf_prfpregset_t; typedef prfpregset_t elf_fpregset_t; typedef gregset_t elf_gregset_t; typedef thrmisc_t elf_thrmisc_t; +#define ELF_KERN_PROC_MASK 0 +typedef struct kinfo_proc elf_kinfo_proc_t; +typedef vm_offset_t elf_ps_strings_t; #endif static void @@ -1686,6 +1749,221 @@ __elfN(note_threadmd)(void *arg, struct *sizep = size; } +#ifdef KINFO_PROC_SIZE +CTASSERT(sizeof(struct kinfo_proc) == KINFO_PROC_SIZE); +#endif + +static void +__elfN(note_procstat_proc)(void *arg, struct sbuf *sb, size_t *sizep) +{ + struct proc *p; + size_t size; + int structsize; + + p = (struct proc *)arg; + size = sizeof(structsize) + p->p_numthreads * + sizeof(elf_kinfo_proc_t); + + if (sb != NULL) { + KASSERT(*sizep == size, ("invalid size")); + structsize = sizeof(elf_kinfo_proc_t); + sbuf_bcat(sb, &structsize, sizeof(structsize)); + PROC_LOCK(p); + kern_proc_out(p, sb, ELF_KERN_PROC_MASK); + } + *sizep = size; +} + +#ifdef KINFO_FILE_SIZE +CTASSERT(sizeof(struct kinfo_file) == KINFO_FILE_SIZE); +#endif + +static void +note_procstat_files(void *arg, struct sbuf *sb, size_t *sizep) +{ + struct proc *p; + size_t size; + int structsize; + + p = (struct proc *)arg; + if (sb == NULL) { + size = 0; + sb = sbuf_new(NULL, NULL, 128, SBUF_FIXEDLEN); + sbuf_set_drain(sb, sbuf_drain_count, &size); + sbuf_bcat(sb, &structsize, sizeof(structsize)); + PROC_LOCK(p); + kern_proc_filedesc_out(p, sb, -1); + sbuf_finish(sb); + sbuf_delete(sb); + *sizep = size; + } else { + structsize = sizeof(struct kinfo_file); + sbuf_bcat(sb, &structsize, sizeof(structsize)); + PROC_LOCK(p); + kern_proc_filedesc_out(p, sb, -1); + } +} + +#ifdef KINFO_VMENTRY_SIZE +CTASSERT(sizeof(struct kinfo_vmentry) == KINFO_VMENTRY_SIZE); +#endif + +static void +note_procstat_vmmap(void *arg, struct sbuf *sb, size_t *sizep) +{ + struct proc *p; + size_t size; + int structsize; + + p = (struct proc *)arg; + if (sb == NULL) { + size = 0; + sb = sbuf_new(NULL, NULL, 128, SBUF_FIXEDLEN); + sbuf_set_drain(sb, sbuf_drain_count, &size); + sbuf_bcat(sb, &structsize, sizeof(structsize)); + PROC_LOCK(p); + kern_proc_vmmap_out(p, sb); + sbuf_finish(sb); + sbuf_delete(sb); + *sizep = size; + } else { + structsize = sizeof(struct kinfo_vmentry); + sbuf_bcat(sb, &structsize, sizeof(structsize)); + PROC_LOCK(p); + kern_proc_vmmap_out(p, sb); + } +} + +static void +note_procstat_groups(void *arg, struct sbuf *sb, size_t *sizep) +{ + struct proc *p; + size_t size; + int structsize; + + p = (struct proc *)arg; + size = sizeof(structsize) + p->p_ucred->cr_ngroups * sizeof(gid_t); + if (sb != NULL) { + KASSERT(*sizep == size, ("invalid size")); + structsize = sizeof(gid_t); + sbuf_bcat(sb, &structsize, sizeof(structsize)); + sbuf_bcat(sb, p->p_ucred->cr_groups, p->p_ucred->cr_ngroups * + sizeof(gid_t)); + } + *sizep = size; +} + +static void +note_procstat_umask(void *arg, struct sbuf *sb, size_t *sizep) +{ + struct proc *p; + size_t size; + int structsize; + + p = (struct proc *)arg; + size = sizeof(structsize) + sizeof(p->p_fd->fd_cmask); + if (sb != NULL) { + KASSERT(*sizep == size, ("invalid size")); + structsize = sizeof(p->p_fd->fd_cmask); + sbuf_bcat(sb, &structsize, sizeof(structsize)); + sbuf_bcat(sb, &p->p_fd->fd_cmask, sizeof(p->p_fd->fd_cmask)); + } + *sizep = size; +} + +static void +note_procstat_rlimit(void *arg, struct sbuf *sb, size_t *sizep) +{ + struct proc *p; + struct rlimit rlim[RLIM_NLIMITS]; + size_t size; + int structsize, i; + + p = (struct proc *)arg; + size = sizeof(structsize) + sizeof(rlim); + if (sb != NULL) { + KASSERT(*sizep == size, ("invalid size")); + structsize = sizeof(rlim); + sbuf_bcat(sb, &structsize, sizeof(structsize)); + PROC_LOCK(p); + for (i = 0; i < RLIM_NLIMITS; i++) + lim_rlimit(p, i, &rlim[i]); + PROC_UNLOCK(p); + sbuf_bcat(sb, rlim, sizeof(rlim)); + } + *sizep = size; +} + +static void +note_procstat_osrel(void *arg, struct sbuf *sb, size_t *sizep) +{ + struct proc *p; + size_t size; + int structsize; + + p = (struct proc *)arg; + size = sizeof(structsize) + sizeof(p->p_osrel); + if (sb != NULL) { + KASSERT(*sizep == size, ("invalid size")); + structsize = sizeof(p->p_osrel); + sbuf_bcat(sb, &structsize, sizeof(structsize)); + sbuf_bcat(sb, &p->p_osrel, sizeof(p->p_osrel)); + } + *sizep = size; +} + +static void +__elfN(note_procstat_psstrings)(void *arg, struct sbuf *sb, size_t *sizep) +{ + struct proc *p; + elf_ps_strings_t ps_strings; + size_t size; + int structsize; + + p = (struct proc *)arg; + size = sizeof(structsize) + sizeof(ps_strings); + if (sb != NULL) { + KASSERT(*sizep == size, ("invalid size")); + structsize = sizeof(ps_strings); +#if defined(COMPAT_FREEBSD32) && __ELF_WORD_SIZE == 32 + ps_strings = PTROUT(p->p_sysent->sv_psstrings); +#else + ps_strings = p->p_sysent->sv_psstrings; +#endif + sbuf_bcat(sb, &structsize, sizeof(structsize)); + sbuf_bcat(sb, &ps_strings, sizeof(ps_strings)); + } + *sizep = size; +} + +static void +__elfN(note_procstat_auxv)(void *arg, struct sbuf *sb, size_t *sizep) +{ + struct proc *p; + size_t size; + int structsize; + + p = (struct proc *)arg; + if (sb == NULL) { + size = 0; + sb = sbuf_new(NULL, NULL, 128, SBUF_FIXEDLEN); + sbuf_set_drain(sb, sbuf_drain_count, &size); + sbuf_bcat(sb, &structsize, sizeof(structsize)); + PHOLD(p); + proc_getauxv(curthread, p, sb); + PRELE(p); + sbuf_finish(sb); + sbuf_delete(sb); + *sizep = size; + } else { + structsize = sizeof(Elf_Auxinfo); + sbuf_bcat(sb, &structsize, sizeof(structsize)); + PHOLD(p); + proc_getauxv(curthread, p, sb); + PRELE(p); + } +} + static boolean_t __elfN(parse_notes)(struct image_params *imgp, Elf_Brandnote *checknote, int32_t *osrel, const Elf_Phdr *pnote) Modified: head/sys/sys/elf_common.h ============================================================================== --- head/sys/sys/elf_common.h Tue Apr 16 17:50:20 2013 (r249557) +++ head/sys/sys/elf_common.h Tue Apr 16 19:19:14 2013 (r249558) @@ -487,6 +487,15 @@ typedef struct { #define NT_FPREGSET 2 /* Floating point registers. */ #define NT_PRPSINFO 3 /* Process state info. */ #define NT_THRMISC 7 /* Thread miscellaneous info. */ +#define NT_PROCSTAT_PROC 8 /* Procstat proc data. */ +#define NT_PROCSTAT_FILES 9 /* Procstat files data. */ +#define NT_PROCSTAT_VMMAP 10 /* Procstat vmmap data. */ +#define NT_PROCSTAT_GROUPS 11 /* Procstat groups data. */ +#define NT_PROCSTAT_UMASK 12 /* Procstat umask data. */ +#define NT_PROCSTAT_RLIMIT 13 /* Procstat rlimit data. */ +#define NT_PROCSTAT_OSREL 14 /* Procstat osreldate data. */ +#define NT_PROCSTAT_PSSTRINGS 15 /* Procstat ps_strings data. */ +#define NT_PROCSTAT_AUXV 16 /* Procstat auxv data. */ /* Symbol Binding - ELFNN_ST_BIND - st_info */ #define STB_LOCAL 0 /* Local symbol */ _______________________________________________ svn-src-all@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"