Print this page
3946 ::gcore
Reviewed by: Adam Leventhal <ahl@delphix.com>
Reviewed by: Matthew Ahrens <mahrens@delphix.com>

*** 23,32 **** --- 23,33 ---- * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Portions Copyright 2007 Chad Mynhier * Copyright 2012 DEY Storage Systems, Inc. All rights reserved. + * Copyright (c) 2013 by Delphix. All rights reserved. */ #include <assert.h> #include <stdio.h> #include <stdlib.h>
*** 39,57 **** --- 40,60 ---- #include <errno.h> #include <dirent.h> #include <limits.h> #include <signal.h> #include <atomic.h> + #include <zone.h> #include <sys/types.h> #include <sys/uio.h> #include <sys/stat.h> #include <sys/resource.h> #include <sys/param.h> #include <sys/stack.h> #include <sys/fault.h> #include <sys/syscall.h> #include <sys/sysmacros.h> + #include <sys/systeminfo.h> #include "libproc.h" #include "Pcontrol.h" #include "Putil.h" #include "P32ton.h"
*** 69,99 **** * Function prototypes for static routines in this module. */ static void deadcheck(struct ps_prochandle *); static void restore_tracing_flags(struct ps_prochandle *); static void Lfree_internal(struct ps_prochandle *, struct ps_lwphandle *); /* ! * Read/write interface for live processes: just pread/pwrite the ! * /proc/<pid>/as file: */ static ssize_t ! Pread_live(struct ps_prochandle *P, void *buf, size_t n, uintptr_t addr) { return (pread(P->asfd, buf, n, (off_t)addr)); } static ssize_t ! Pwrite_live(struct ps_prochandle *P, const void *buf, size_t n, uintptr_t addr) { return (pwrite(P->asfd, buf, n, (off_t)addr)); } ! static const ps_rwops_t P_live_ops = { Pread_live, Pwrite_live }; /* * This is the library's .init handler. */ #pragma init(_libproc_init) void _libproc_init(void) --- 72,338 ---- * Function prototypes for static routines in this module. */ static void deadcheck(struct ps_prochandle *); static void restore_tracing_flags(struct ps_prochandle *); static void Lfree_internal(struct ps_prochandle *, struct ps_lwphandle *); + static prheader_t *read_lfile(struct ps_prochandle *, const char *); /* ! * Ops vector functions for live processes. */ + /*ARGSUSED*/ static ssize_t ! Pread_live(struct ps_prochandle *P, void *buf, size_t n, uintptr_t addr, ! void *data) { return (pread(P->asfd, buf, n, (off_t)addr)); } + /*ARGSUSED*/ static ssize_t ! Pwrite_live(struct ps_prochandle *P, const void *buf, size_t n, uintptr_t addr, ! void *data) { return (pwrite(P->asfd, buf, n, (off_t)addr)); } ! /*ARGSUSED*/ ! static int ! Pread_maps_live(struct ps_prochandle *P, prmap_t **Pmapp, ssize_t *nmapp, ! void *data) ! { ! char mapfile[PATH_MAX]; ! int mapfd; ! struct stat statb; ! ssize_t nmap; ! prmap_t *Pmap = NULL; + (void) snprintf(mapfile, sizeof (mapfile), "%s/%d/map", + procfs_path, (int)P->pid); + if ((mapfd = open(mapfile, O_RDONLY)) < 0 || + fstat(mapfd, &statb) != 0 || + statb.st_size < sizeof (prmap_t) || + (Pmap = malloc(statb.st_size)) == NULL || + (nmap = pread(mapfd, Pmap, statb.st_size, 0L)) <= 0 || + (nmap /= sizeof (prmap_t)) == 0) { + if (Pmap != NULL) + free(Pmap); + if (mapfd >= 0) + (void) close(mapfd); + Preset_maps(P); /* utter failure; destroy tables */ + return (-1); + } + (void) close(mapfd); + + *Pmapp = Pmap; + *nmapp = nmap; + + return (0); + } + + /*ARGSUSED*/ + static void + Pread_aux_live(struct ps_prochandle *P, auxv_t **auxvp, int *nauxp, void *data) + { + char auxfile[64]; + int fd; + struct stat statb; + auxv_t *auxv; + ssize_t naux; + + (void) snprintf(auxfile, sizeof (auxfile), "%s/%d/auxv", + procfs_path, (int)P->pid); + if ((fd = open(auxfile, O_RDONLY)) < 0) { + dprintf("%s: failed to open %s: %s\n", + __func__, auxfile, strerror(errno)); + return; + } + + if (fstat(fd, &statb) == 0 && + statb.st_size >= sizeof (auxv_t) && + (auxv = malloc(statb.st_size + sizeof (auxv_t))) != NULL) { + if ((naux = read(fd, auxv, statb.st_size)) < 0 || + (naux /= sizeof (auxv_t)) < 1) { + dprintf("%s: read failed: %s\n", + __func__, strerror(errno)); + free(auxv); + } else { + auxv[naux].a_type = AT_NULL; + auxv[naux].a_un.a_val = 0L; + + *auxvp = auxv; + *nauxp = (int)naux; + } + } + + (void) close(fd); + } + + /*ARGSUSED*/ + static int + Pcred_live(struct ps_prochandle *P, prcred_t *pcrp, int ngroups, void *data) + { + return (proc_get_cred(P->pid, pcrp, ngroups)); + } + + /*ARGSUSED*/ + static int + Ppriv_live(struct ps_prochandle *P, prpriv_t **pprv, void *data) + { + prpriv_t *pp; + + pp = proc_get_priv(P->pid); + if (pp == NULL) { + return (-1); + } + + *pprv = pp; + return (0); + } + + /*ARGSUSED*/ + static const psinfo_t * + Ppsinfo_live(struct ps_prochandle *P, psinfo_t *psinfo, void *data) + { + if (proc_get_psinfo(P->pid, psinfo) == -1) + return (NULL); + + return (psinfo); + } + + /*ARGSUSED*/ + static prheader_t * + Plstatus_live(struct ps_prochandle *P, void *data) + { + return (read_lfile(P, "lstatus")); + } + + /*ARGSUSED*/ + static prheader_t * + Plpsinfo_live(struct ps_prochandle *P, void *data) + { + return (read_lfile(P, "lpsinfo")); + } + + /*ARGSUSED*/ + static char * + Pplatform_live(struct ps_prochandle *P, char *s, size_t n, void *data) + { + if (sysinfo(SI_PLATFORM, s, n) == -1) + return (NULL); + return (s); + } + + /*ARGSUSED*/ + static int + Puname_live(struct ps_prochandle *P, struct utsname *u, void *data) + { + return (uname(u)); + } + + /*ARGSUSED*/ + static char * + Pzonename_live(struct ps_prochandle *P, char *s, size_t n, void *data) + { + if (getzonenamebyid(P->status.pr_zoneid, s, n) < 0) + return (NULL); + s[n - 1] = '\0'; + return (s); + } + /* + * Callback function for Pfindexec(). We return a match if we can stat the + * suggested pathname and confirm its device and inode number match our + * previous information about the /proc/<pid>/object/a.out file. + */ + static int + stat_exec(const char *path, void *arg) + { + struct stat64 *stp = arg; + struct stat64 st; + + return (stat64(path, &st) == 0 && S_ISREG(st.st_mode) && + stp->st_dev == st.st_dev && stp->st_ino == st.st_ino); + } + + /*ARGSUSED*/ + static char * + Pexecname_live(struct ps_prochandle *P, char *buf, size_t buflen, void *data) + { + char exec_name[PATH_MAX]; + char cwd[PATH_MAX]; + char proc_cwd[64]; + struct stat64 st; + int ret; + + /* + * Try to get the path information first. + */ + (void) snprintf(exec_name, sizeof (exec_name), + "%s/%d/path/a.out", procfs_path, (int)P->pid); + if ((ret = readlink(exec_name, buf, buflen - 1)) > 0) { + buf[ret] = '\0'; + (void) Pfindobj(P, buf, buf, buflen); + return (buf); + } + + /* + * Stat the executable file so we can compare Pfindexec's + * suggestions to the actual device and inode number. + */ + (void) snprintf(exec_name, sizeof (exec_name), + "%s/%d/object/a.out", procfs_path, (int)P->pid); + + if (stat64(exec_name, &st) != 0 || !S_ISREG(st.st_mode)) + return (NULL); + + /* + * Attempt to figure out the current working directory of the + * target process. This only works if the target process has + * not changed its current directory since it was exec'd. + */ + (void) snprintf(proc_cwd, sizeof (proc_cwd), + "%s/%d/path/cwd", procfs_path, (int)P->pid); + + if ((ret = readlink(proc_cwd, cwd, PATH_MAX - 1)) > 0) + cwd[ret] = '\0'; + + (void) Pfindexec(P, ret > 0 ? cwd : NULL, stat_exec, &st); + + return (NULL); + } + + #if defined(__i386) || defined(__amd64) + /*ARGSUSED*/ + static int + Pldt_live(struct ps_prochandle *P, struct ssd *pldt, int nldt, void *data) + { + return (proc_get_ldt(P->pid, pldt, nldt)); + } + #endif + + static const ps_ops_t P_live_ops = { + .pop_pread = Pread_live, + .pop_pwrite = Pwrite_live, + .pop_read_maps = Pread_maps_live, + .pop_read_aux = Pread_aux_live, + .pop_cred = Pcred_live, + .pop_priv = Ppriv_live, + .pop_psinfo = Ppsinfo_live, + .pop_lstatus = Plstatus_live, + .pop_lpsinfo = Plpsinfo_live, + .pop_platform = Pplatform_live, + .pop_uname = Puname_live, + .pop_zonename = Pzonename_live, + .pop_execname = Pexecname_live, + #if defined(__i386) || defined(__amd64) + .pop_ldt = Pldt_live + #endif + }; + + /* * This is the library's .init handler. */ #pragma init(_libproc_init) void _libproc_init(void)
*** 247,257 **** P->asfd = -1; P->ctlfd = -1; P->statfd = -1; P->agentctlfd = -1; P->agentstatfd = -1; ! P->ops = &P_live_ops; Pinitsym(P); /* * Open the /proc/pid files. */ --- 486,496 ---- P->asfd = -1; P->ctlfd = -1; P->statfd = -1; P->agentctlfd = -1; P->agentstatfd = -1; ! Pinit_ops(&P->ops, &P_live_ops); Pinitsym(P); /* * Open the /proc/pid files. */
*** 550,560 **** P->ctlfd = -1; P->asfd = -1; P->statfd = -1; P->agentctlfd = -1; P->agentstatfd = -1; ! P->ops = &P_live_ops; Pinitsym(P); /* * Open the /proc/pid files */ --- 789,799 ---- P->ctlfd = -1; P->asfd = -1; P->statfd = -1; P->agentctlfd = -1; P->agentstatfd = -1; ! Pinit_ops(&P->ops, &P_live_ops); Pinitsym(P); /* * Open the /proc/pid files */
*** 931,979 **** void Pfree(struct ps_prochandle *P) { uint_t i; - if (P->core != NULL) { - extern void __priv_free_info(void *); - lwp_info_t *nlwp, *lwp = list_next(&P->core->core_lwp_head); - - for (i = 0; i < P->core->core_nlwp; i++, lwp = nlwp) { - nlwp = list_next(lwp); - #ifdef __sparc - if (lwp->lwp_gwins != NULL) - free(lwp->lwp_gwins); - if (lwp->lwp_xregs != NULL) - free(lwp->lwp_xregs); - if (lwp->lwp_asrs != NULL) - free(lwp->lwp_asrs); - #endif - free(lwp); - } - - if (P->core->core_platform != NULL) - free(P->core->core_platform); - if (P->core->core_uts != NULL) - free(P->core->core_uts); - if (P->core->core_cred != NULL) - free(P->core->core_cred); - if (P->core->core_priv != NULL) - free(P->core->core_priv); - if (P->core->core_privinfo != NULL) - __priv_free_info(P->core->core_privinfo); - if (P->core->core_ppii != NULL) - free(P->core->core_ppii); - if (P->core->core_zonename != NULL) - free(P->core->core_zonename); - #if defined(__i386) || defined(__amd64) - if (P->core->core_ldt != NULL) - free(P->core->core_ldt); - #endif - - free(P->core); - } - if (P->ucaddrs != NULL) { free(P->ucaddrs); P->ucaddrs = NULL; P->ucnelems = 0; } --- 1170,1179 ----
*** 1006,1015 **** --- 1206,1216 ---- if (P->asfd >= 0) (void) close(P->asfd); if (P->statfd >= 0) (void) close(P->statfd); Preset_maps(P); + P->ops.pop_fini(P, P->data); /* clear out the structure as a precaution against reuse */ (void) memset(P, 0, sizeof (*P)); P->ctlfd = -1; P->asfd = -1;
*** 1057,1075 **** * It will become invalid on Prelease(). */ const psinfo_t * Ppsinfo(struct ps_prochandle *P) { ! if (P->state == PS_IDLE) { ! errno = ENODATA; ! return (NULL); ! } ! ! if (P->state != PS_DEAD && proc_get_psinfo(P->pid, &P->psinfo) == -1) ! return (NULL); ! ! return (&P->psinfo); } /* * Return a pointer to the process status structure. * Clients should not hold on to this pointer indefinitely. --- 1258,1268 ---- * It will become invalid on Prelease(). */ const psinfo_t * Ppsinfo(struct ps_prochandle *P) { ! return (P->ops.pop_psinfo(P, &P->psinfo, P->data)); } /* * Return a pointer to the process status structure. * Clients should not hold on to this pointer indefinitely.
*** 1079,1123 **** Pstatus(struct ps_prochandle *P) { return (&P->status); } /* * Fill in a pointer to a process credentials structure. The ngroups parameter * is the number of supplementary group entries allocated in the caller's cred * structure. It should equal zero or one unless extra space has been * allocated for the group list by the caller. */ int Pcred(struct ps_prochandle *P, prcred_t *pcrp, int ngroups) { ! if (P->state == PS_IDLE) { ! errno = ENODATA; ! return (-1); ! } ! if (P->state != PS_DEAD) ! return (proc_get_cred(P->pid, pcrp, ngroups)); ! if (P->core->core_cred != NULL) { ! /* ! * Avoid returning more supplementary group data than the ! * caller has allocated in their buffer. We expect them to ! * check pr_ngroups afterward and potentially call us again. ! */ ! ngroups = MIN(ngroups, P->core->core_cred->pr_ngroups); ! ! (void) memcpy(pcrp, P->core->core_cred, ! sizeof (prcred_t) + (ngroups - 1) * sizeof (gid_t)); ! ! return (0); ! } ! ! errno = ENODATA; ! return (-1); } #if defined(__i386) || defined(__amd64) /* * Fill in a pointer to a process LDT structure. * The caller provides a buffer of size 'nldt * sizeof (struct ssd)'; * If pldt == NULL or nldt == 0, we return the number of existing LDT entries. --- 1272,1312 ---- Pstatus(struct ps_prochandle *P) { return (&P->status); } + static void + Pread_status(struct ps_prochandle *P) + { + P->ops.pop_status(P, &P->status, P->data); + } + /* * Fill in a pointer to a process credentials structure. The ngroups parameter * is the number of supplementary group entries allocated in the caller's cred * structure. It should equal zero or one unless extra space has been * allocated for the group list by the caller. */ int Pcred(struct ps_prochandle *P, prcred_t *pcrp, int ngroups) { ! return (P->ops.pop_cred(P, pcrp, ngroups, P->data)); ! } ! static prheader_t * ! Plstatus(struct ps_prochandle *P) ! { ! return (P->ops.pop_lstatus(P, P->data)); ! } ! static prheader_t * ! Plpsinfo(struct ps_prochandle *P) ! { ! return (P->ops.pop_lpsinfo(P, P->data)); } + #if defined(__i386) || defined(__amd64) /* * Fill in a pointer to a process LDT structure. * The caller provides a buffer of size 'nldt * sizeof (struct ssd)'; * If pldt == NULL or nldt == 0, we return the number of existing LDT entries.
*** 1124,1182 **** * Otherwise we return the actual number of LDT entries fetched (<= nldt). */ int Pldt(struct ps_prochandle *P, struct ssd *pldt, int nldt) { ! if (P->state == PS_IDLE) { ! errno = ENODATA; ! return (-1); ! } - if (P->state != PS_DEAD) - return (proc_get_ldt(P->pid, pldt, nldt)); - - if (pldt == NULL || nldt == 0) - return (P->core->core_nldt); - - if (P->core->core_ldt != NULL) { - nldt = MIN(nldt, P->core->core_nldt); - - (void) memcpy(pldt, P->core->core_ldt, - nldt * sizeof (struct ssd)); - - return (nldt); - } - - errno = ENODATA; - return (-1); } #endif /* __i386 */ /* ! * Fill in a pointer to a process privilege structure. */ ! ssize_t ! Ppriv(struct ps_prochandle *P, prpriv_t *pprv, size_t size) { ! if (P->state != PS_DEAD) { ! prpriv_t *pp = proc_get_priv(P->pid); ! if (pp != NULL) { ! size = MIN(size, PRIV_PRPRIV_SIZE(pp)); ! (void) memcpy(pprv, pp, size); ! free(pp); ! return (size); ! } ! return (-1); ! } ! ! if (P->core->core_priv != NULL) { ! size = MIN(P->core->core_priv_size, size); ! (void) memcpy(pprv, P->core->core_priv, size); ! return (size); ! } ! errno = ENODATA; ! return (-1); } int Psetpriv(struct ps_prochandle *P, prpriv_t *pprv) { --- 1313,1334 ---- * Otherwise we return the actual number of LDT entries fetched (<= nldt). */ int Pldt(struct ps_prochandle *P, struct ssd *pldt, int nldt) { ! return (P->ops.pop_ldt(P, pldt, nldt, P->data)); } #endif /* __i386 */ /* ! * Return a malloced process privilege structure in *pprv. */ ! int ! Ppriv(struct ps_prochandle *P, prpriv_t **pprv) { ! return (P->ops.pop_priv(P, pprv, P->data)); } int Psetpriv(struct ps_prochandle *P, prpriv_t *pprv) {
*** 1212,1226 **** } void * Pprivinfo(struct ps_prochandle *P) { /* Use default from libc */ if (P->state != PS_DEAD) return (NULL); ! return (P->core->core_privinfo); } /* * Ensure that all cached state is written to the process. * The cached state is the LWP's signal mask and registers --- 1364,1380 ---- } void * Pprivinfo(struct ps_prochandle *P) { + core_info_t *core = P->data; + /* Use default from libc */ if (P->state != PS_DEAD) return (NULL); ! return (core->core_privinfo); } /* * Ensure that all cached state is written to the process. * The cached state is the LWP's signal mask and registers
*** 1976,1986 **** Pread(struct ps_prochandle *P, void *buf, /* caller's buffer */ size_t nbyte, /* number of bytes to read */ uintptr_t address) /* address in process */ { ! return (P->ops->p_pread(P, buf, nbyte, address)); } ssize_t Pread_string(struct ps_prochandle *P, char *buf, /* caller's buffer */ --- 2130,2140 ---- Pread(struct ps_prochandle *P, void *buf, /* caller's buffer */ size_t nbyte, /* number of bytes to read */ uintptr_t address) /* address in process */ { ! return (P->ops.pop_pread(P, buf, nbyte, address, P->data)); } ssize_t Pread_string(struct ps_prochandle *P, char *buf, /* caller's buffer */
*** 2001,2011 **** *buf = '\0'; string[STRSZ] = '\0'; for (nbyte = STRSZ; nbyte == STRSZ && leng < size; addr += STRSZ) { ! if ((nbyte = P->ops->p_pread(P, string, STRSZ, addr)) <= 0) { buf[leng] = '\0'; return (leng ? leng : -1); } if ((nbyte = strlen(string)) > 0) { if (leng + nbyte > size) --- 2155,2166 ---- *buf = '\0'; string[STRSZ] = '\0'; for (nbyte = STRSZ; nbyte == STRSZ && leng < size; addr += STRSZ) { ! if ((nbyte = P->ops.pop_pread(P, string, STRSZ, addr, ! P->data)) <= 0) { buf[leng] = '\0'; return (leng ? leng : -1); } if ((nbyte = strlen(string)) > 0) { if (leng + nbyte > size)
*** 2022,2032 **** Pwrite(struct ps_prochandle *P, const void *buf, /* caller's buffer */ size_t nbyte, /* number of bytes to write */ uintptr_t address) /* address in process */ { ! return (P->ops->p_pwrite(P, buf, nbyte, address)); } int Pclearsig(struct ps_prochandle *P) { --- 2177,2187 ---- Pwrite(struct ps_prochandle *P, const void *buf, /* caller's buffer */ size_t nbyte, /* number of bytes to write */ uintptr_t address) /* address in process */ { ! return (P->ops.pop_pwrite(P, buf, nbyte, address, P->data)); } int Pclearsig(struct ps_prochandle *P) {
*** 2763,2776 **** /* * For the core file multi-LWP case, we just iterate through the * list of LWP structs we read in from the core file. */ if (P->state == PS_DEAD) { ! lwp_info_t *lwp = list_prev(&P->core->core_lwp_head); uint_t i; ! for (i = 0; i < P->core->core_nlwp; i++, lwp = list_prev(lwp)) { if (lwp->lwp_psinfo.pr_sname != 'Z' && (rv = func(cd, &lwp->lwp_status)) != 0) break; } --- 2918,2932 ---- /* * For the core file multi-LWP case, we just iterate through the * list of LWP structs we read in from the core file. */ if (P->state == PS_DEAD) { ! core_info_t *core = P->data; ! lwp_info_t *lwp = list_prev(&core->core_lwp_head); uint_t i; ! for (i = 0; i < core->core_nlwp; i++, lwp = list_prev(lwp)) { if (lwp->lwp_psinfo.pr_sname != 'Z' && (rv = func(cd, &lwp->lwp_status)) != 0) break; }
*** 2779,2789 **** /* * For the live process multi-LWP case, we have to work a little * harder: the /proc/pid/lstatus file has the array of LWP structs. */ ! if ((Lhp = read_lfile(P, "lstatus")) == NULL) return (-1); for (nlwp = Lhp->pr_nent, Lsp = (lwpstatus_t *)(uintptr_t)(Lhp + 1); nlwp > 0; nlwp--, Lsp = (lwpstatus_t *)((uintptr_t)Lsp + Lhp->pr_entsize)) { --- 2935,2945 ---- /* * For the live process multi-LWP case, we have to work a little * harder: the /proc/pid/lstatus file has the array of LWP structs. */ ! if ((Lhp = Plstatus(P)) == NULL) return (-1); for (nlwp = Lhp->pr_nent, Lsp = (lwpstatus_t *)(uintptr_t)(Lhp + 1); nlwp > 0; nlwp--, Lsp = (lwpstatus_t *)((uintptr_t)Lsp + Lhp->pr_entsize)) {
*** 2834,2847 **** /* * For the core file multi-LWP case, we just iterate through the * list of LWP structs we read in from the core file. */ if (P->state == PS_DEAD) { ! lwp_info_t *lwp = list_prev(&P->core->core_lwp_head); uint_t i; ! for (i = 0; i < P->core->core_nlwp; i++, lwp = list_prev(lwp)) { sp = (lwp->lwp_psinfo.pr_sname == 'Z')? NULL : &lwp->lwp_status; if ((rv = func(cd, sp, &lwp->lwp_psinfo)) != 0) break; } --- 2990,3004 ---- /* * For the core file multi-LWP case, we just iterate through the * list of LWP structs we read in from the core file. */ if (P->state == PS_DEAD) { ! core_info_t *core = P->data; ! lwp_info_t *lwp = list_prev(&core->core_lwp_head); uint_t i; ! for (i = 0; i < core->core_nlwp; i++, lwp = list_prev(lwp)) { sp = (lwp->lwp_psinfo.pr_sname == 'Z')? NULL : &lwp->lwp_status; if ((rv = func(cd, sp, &lwp->lwp_psinfo)) != 0) break; }
*** 2848,2864 **** return (rv); } /* ! * For the live process multi-LWP case, we have to work a little ! * harder: the /proc/pid/lstatus file has the array of lwpstatus_t's ! * and the /proc/pid/lpsinfo file has the array of lwpsinfo_t's. */ ! if ((Lhp = read_lfile(P, "lstatus")) == NULL) return (-1); ! if ((Lphp = read_lfile(P, "lpsinfo")) == NULL) { free(Lhp); return (-1); } /* --- 3005,3020 ---- return (rv); } /* ! * For all other cases retrieve the array of lwpstatus_t's and ! * lwpsinfo_t's. */ ! if ((Lhp = Plstatus(P)) == NULL) return (-1); ! if ((Lphp = Plpsinfo(P)) == NULL) { free(Lhp); return (-1); } /*
*** 2918,2929 **** } core_content_t Pcontent(struct ps_prochandle *P) { if (P->state == PS_DEAD) ! return (P->core->core_content); if (P->state == PS_IDLE) return (CC_CONTENT_TEXT | CC_CONTENT_DATA | CC_CONTENT_CTF); return (CC_CONTENT_ALL); } --- 3074,3087 ---- } core_content_t Pcontent(struct ps_prochandle *P) { + core_info_t *core = P->data; + if (P->state == PS_DEAD) ! return (core->core_content); if (P->state == PS_IDLE) return (CC_CONTENT_TEXT | CC_CONTENT_DATA | CC_CONTENT_CTF); return (CC_CONTENT_ALL); }
*** 3725,3730 **** --- 3883,3917 ---- mp = &P->mappings[i]; if (mp->map_relocate) mp->map_file->file_map = mp; mp->map_relocate = 0; } + } + + struct ps_prochandle * + Pgrab_ops(pid_t pid, void *data, const ps_ops_t *ops, int flags) + { + struct ps_prochandle *P; + + if ((P = calloc(1, sizeof (*P))) == NULL) { + return (NULL); + } + + Pinit_ops(&P->ops, ops); + (void) mutex_init(&P->proc_lock, USYNC_THREAD, NULL); + P->pid = pid; + P->state = PS_STOP; + P->asfd = -1; + P->ctlfd = -1; + P->statfd = -1; + P->agentctlfd = -1; + P->agentstatfd = -1; + Pinitsym(P); + P->data = data; + Pread_status(P); + + if (flags & PGRAB_INCORE) { + P->flags |= INCORE; + } + + return (P); }