diff options
author | Jeremy Jones <jeremy@delphix.com> | 2013-08-21 15:45:46 -0800 |
---|---|---|
committer | Christopher Siden <chris.siden@delphix.com> | 2013-08-21 16:45:46 -0700 |
commit | 2a12f85ad140e332791b4bad1208a734c3f26bf3 (patch) | |
tree | f4360a28249f0409ce5037f493a18f60e6219ea2 /usr/src/lib/libproc/common | |
parent | 840b2722e5294ae44aa3af6189002f521d7c50e0 (diff) | |
download | illumos-joyent-2a12f85ad140e332791b4bad1208a734c3f26bf3.tar.gz |
3946 ::gcore
Reviewed by: Adam Leventhal <ahl@delphix.com>
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Approved by: Robert Mustacchi <rm@joyent.com>
Diffstat (limited to 'usr/src/lib/libproc/common')
-rw-r--r-- | usr/src/lib/libproc/common/Pcontrol.c | 459 | ||||
-rw-r--r-- | usr/src/lib/libproc/common/Pcontrol.h | 14 | ||||
-rw-r--r-- | usr/src/lib/libproc/common/Pcore.c | 311 | ||||
-rw-r--r-- | usr/src/lib/libproc/common/Pexecname.c | 66 | ||||
-rw-r--r-- | usr/src/lib/libproc/common/Pgcore.c | 5 | ||||
-rw-r--r-- | usr/src/lib/libproc/common/Pidle.c | 57 | ||||
-rw-r--r-- | usr/src/lib/libproc/common/Plwpregs.c | 8 | ||||
-rw-r--r-- | usr/src/lib/libproc/common/Pservice.c | 9 | ||||
-rw-r--r-- | usr/src/lib/libproc/common/Psymtab.c | 105 | ||||
-rw-r--r-- | usr/src/lib/libproc/common/Putil.c | 98 | ||||
-rw-r--r-- | usr/src/lib/libproc/common/Putil.h | 7 | ||||
-rw-r--r-- | usr/src/lib/libproc/common/Pzone.c | 19 | ||||
-rw-r--r-- | usr/src/lib/libproc/common/libproc.h | 54 | ||||
-rw-r--r-- | usr/src/lib/libproc/common/llib-lproc | 5 | ||||
-rw-r--r-- | usr/src/lib/libproc/common/mapfile-vers | 2 |
15 files changed, 834 insertions, 385 deletions
diff --git a/usr/src/lib/libproc/common/Pcontrol.c b/usr/src/lib/libproc/common/Pcontrol.c index 1e7ce1556e..751c0c3f8a 100644 --- a/usr/src/lib/libproc/common/Pcontrol.c +++ b/usr/src/lib/libproc/common/Pcontrol.c @@ -25,6 +25,7 @@ * * 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> @@ -41,6 +42,7 @@ #include <limits.h> #include <signal.h> #include <atomic.h> +#include <zone.h> #include <sys/types.h> #include <sys/uio.h> #include <sys/stat.h> @@ -50,6 +52,7 @@ #include <sys/fault.h> #include <sys/syscall.h> #include <sys/sysmacros.h> +#include <sys/systeminfo.h> #include "libproc.h" #include "Pcontrol.h" @@ -71,25 +74,261 @@ char procfs_path[PATH_MAX] = "/proc"; 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 *); /* - * Read/write interface for live processes: just pread/pwrite the - * /proc/<pid>/as file: + * Ops vector functions for live processes. */ +/*ARGSUSED*/ static ssize_t -Pread_live(struct ps_prochandle *P, void *buf, size_t n, uintptr_t addr) +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) +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)); } -static const ps_rwops_t P_live_ops = { Pread_live, Pwrite_live }; +/*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. @@ -249,7 +488,7 @@ Pxcreate(const char *file, /* executable file name */ P->statfd = -1; P->agentctlfd = -1; P->agentstatfd = -1; - P->ops = &P_live_ops; + Pinit_ops(&P->ops, &P_live_ops); Pinitsym(P); /* @@ -552,7 +791,7 @@ again: /* Come back here if we lose it in the Window of Vulnerability */ P->statfd = -1; P->agentctlfd = -1; P->agentstatfd = -1; - P->ops = &P_live_ops; + Pinit_ops(&P->ops, &P_live_ops); Pinitsym(P); /* @@ -933,45 +1172,6 @@ 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; @@ -1008,6 +1208,7 @@ Pfree(struct ps_prochandle *P) 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)); @@ -1059,15 +1260,7 @@ Pctlfd(struct ps_prochandle *P) 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 (P->ops.pop_psinfo(P, &P->psinfo, P->data)); } /* @@ -1081,6 +1274,12 @@ 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 @@ -1090,32 +1289,22 @@ Pstatus(struct ps_prochandle *P) 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 (P->ops.pop_cred(P, pcrp, ngroups, P->data)); +} - return (0); - } +static prheader_t * +Plstatus(struct ps_prochandle *P) +{ + return (P->ops.pop_lstatus(P, P->data)); +} - errno = ENODATA; - return (-1); +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. @@ -1126,55 +1315,18 @@ Pcred(struct ps_prochandle *P, prcred_t *pcrp, int ngroups) 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); + return (P->ops.pop_ldt(P, pldt, nldt, P->data)); - (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. + * Return a malloced process privilege structure in *pprv. */ -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 +Ppriv(struct ps_prochandle *P, prpriv_t **pprv) +{ + return (P->ops.pop_priv(P, pprv, P->data)); } int @@ -1214,11 +1366,13 @@ Psetpriv(struct ps_prochandle *P, prpriv_t *pprv) void * Pprivinfo(struct ps_prochandle *P) { + core_info_t *core = P->data; + /* Use default from libc */ if (P->state != PS_DEAD) return (NULL); - return (P->core->core_privinfo); + return (core->core_privinfo); } /* @@ -1978,12 +2132,12 @@ Pread(struct ps_prochandle *P, size_t nbyte, /* number of bytes to read */ uintptr_t address) /* address in process */ { - return (P->ops->p_pread(P, buf, nbyte, address)); + return (P->ops.pop_pread(P, buf, nbyte, address, P->data)); } ssize_t Pread_string(struct ps_prochandle *P, - char *buf, /* caller's buffer */ + char *buf, /* caller's buffer */ size_t size, /* upper limit on bytes to read */ uintptr_t addr) /* address in process */ { @@ -2003,7 +2157,8 @@ Pread_string(struct ps_prochandle *P, string[STRSZ] = '\0'; for (nbyte = STRSZ; nbyte == STRSZ && leng < size; addr += STRSZ) { - if ((nbyte = P->ops->p_pread(P, string, STRSZ, addr)) <= 0) { + if ((nbyte = P->ops.pop_pread(P, string, STRSZ, addr, + P->data)) <= 0) { buf[leng] = '\0'; return (leng ? leng : -1); } @@ -2024,7 +2179,7 @@ Pwrite(struct ps_prochandle *P, size_t nbyte, /* number of bytes to write */ uintptr_t address) /* address in process */ { - return (P->ops->p_pwrite(P, buf, nbyte, address)); + return (P->ops.pop_pwrite(P, buf, nbyte, address, P->data)); } int @@ -2765,10 +2920,11 @@ Plwp_iter(struct ps_prochandle *P, proc_lwp_f *func, void *cd) * 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); + core_info_t *core = P->data; + lwp_info_t *lwp = list_prev(&core->core_lwp_head); uint_t i; - for (i = 0; i < P->core->core_nlwp; i++, lwp = list_prev(lwp)) { + 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; @@ -2781,7 +2937,7 @@ Plwp_iter(struct ps_prochandle *P, proc_lwp_f *func, void *cd) * 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) + if ((Lhp = Plstatus(P)) == NULL) return (-1); for (nlwp = Lhp->pr_nent, Lsp = (lwpstatus_t *)(uintptr_t)(Lhp + 1); @@ -2836,10 +2992,11 @@ retry: * 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); + core_info_t *core = P->data; + lwp_info_t *lwp = list_prev(&core->core_lwp_head); uint_t i; - for (i = 0; i < P->core->core_nlwp; i++, lwp = list_prev(lwp)) { + 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) @@ -2850,13 +3007,12 @@ retry: } /* - * 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. + * For all other cases retrieve the array of lwpstatus_t's and + * lwpsinfo_t's. */ - if ((Lhp = read_lfile(P, "lstatus")) == NULL) + if ((Lhp = Plstatus(P)) == NULL) return (-1); - if ((Lphp = read_lfile(P, "lpsinfo")) == NULL) { + if ((Lphp = Plpsinfo(P)) == NULL) { free(Lhp); return (-1); } @@ -2920,8 +3076,10 @@ retry: core_content_t Pcontent(struct ps_prochandle *P) { + core_info_t *core = P->data; + if (P->state == PS_DEAD) - return (P->core->core_content); + return (core->core_content); if (P->state == PS_IDLE) return (CC_CONTENT_TEXT | CC_CONTENT_DATA | CC_CONTENT_CTF); @@ -3728,3 +3886,32 @@ Psort_mappings(struct ps_prochandle *P) 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); +} diff --git a/usr/src/lib/libproc/common/Pcontrol.h b/usr/src/lib/libproc/common/Pcontrol.h index 4bb7e0ca3c..3e72a32804 100644 --- a/usr/src/lib/libproc/common/Pcontrol.h +++ b/usr/src/lib/libproc/common/Pcontrol.h @@ -25,6 +25,7 @@ /* * Copyright 2012 DEY Storage Systems, Inc. All rights reserved. * Copyright (c) 2013, Joyent, Inc. All rights reserved. + * Copyright (c) 2013 by Delphix. All rights reserved. */ #ifndef _PCONTROL_H @@ -43,6 +44,7 @@ #include <libproc.h> #include <libctf.h> #include <limits.h> +#include <libproc.h> #ifdef __cplusplus extern "C" { @@ -190,13 +192,6 @@ typedef struct elf_file { /* convenience for managing ELF files */ int e_fd; /* file descriptor */ } elf_file_t; -typedef struct ps_rwops { /* ops vector for Pread() and Pwrite() */ - ssize_t (*p_pread)(struct ps_prochandle *, - void *, size_t, uintptr_t); - ssize_t (*p_pwrite)(struct ps_prochandle *, - const void *, size_t, uintptr_t); -} ps_rwops_t; - #define HASHSIZE 1024 /* hash table size, power of 2 */ struct ps_prochandle { @@ -227,8 +222,7 @@ struct ps_prochandle { rd_agent_t *rap; /* cookie for rtld_db */ map_info_t *map_exec; /* the mapping for the executable file */ map_info_t *map_ldso; /* the mapping for ld.so.1 */ - const ps_rwops_t *ops; /* pointer to ops-vector for read and write */ - core_info_t *core; /* information specific to core (if PS_DEAD) */ + ps_ops_t ops; /* ops-vector */ uintptr_t *ucaddrs; /* ucontext-list addresses */ uint_t ucnelems; /* number of elements in the ucaddrs list */ char *zoneroot; /* cached path to zone root */ @@ -237,6 +231,7 @@ struct ps_prochandle { uintptr_t map_missing; /* first missing mapping in core due to sig */ siginfo_t killinfo; /* signal that interrupted core dump */ psinfo_t spymaster; /* agent LWP's spymaster, if any */ + void *data; /* private data */ }; /* flags */ @@ -247,6 +242,7 @@ struct ps_prochandle { #define SETEXIT 0x10 /* set sysexit trace mask before continuing */ #define SETHOLD 0x20 /* set signal hold mask before continuing */ #define SETREGS 0x40 /* set registers before continuing */ +#define INCORE 0x80 /* use in-core data to build symbol tables */ struct ps_lwphandle { struct ps_prochandle *lwp_proc; /* process to which this lwp belongs */ diff --git a/usr/src/lib/libproc/common/Pcore.c b/usr/src/lib/libproc/common/Pcore.c index e16e019ab9..596c45861a 100644 --- a/usr/src/lib/libproc/common/Pcore.c +++ b/usr/src/lib/libproc/common/Pcore.c @@ -25,6 +25,7 @@ /* * Copyright 2012 DEY Storage Systems, Inc. All rights reserved. * Copyright (c) 2013, Joyent, Inc. All rights reserved. + * Copyright (c) 2013 by Delphix. All rights reserved. */ #include <sys/types.h> @@ -111,20 +112,202 @@ core_rw(struct ps_prochandle *P, void *buf, size_t n, uintptr_t addr, return (n - resid); } +/*ARGSUSED*/ static ssize_t -Pread_core(struct ps_prochandle *P, void *buf, size_t n, uintptr_t addr) +Pread_core(struct ps_prochandle *P, void *buf, size_t n, uintptr_t addr, + void *data) { return (core_rw(P, buf, n, addr, pread64)); } +/*ARGSUSED*/ static ssize_t -Pwrite_core(struct ps_prochandle *P, const void *buf, size_t n, uintptr_t addr) +Pwrite_core(struct ps_prochandle *P, const void *buf, size_t n, uintptr_t addr, + void *data) { return (core_rw(P, (void *)buf, n, addr, (ssize_t (*)(int, void *, size_t, off64_t)) pwrite64)); } -static const ps_rwops_t P_core_ops = { Pread_core, Pwrite_core }; +/*ARGSUSED*/ +static int +Pcred_core(struct ps_prochandle *P, prcred_t *pcrp, int ngroups, void *data) +{ + core_info_t *core = data; + + if (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, core->core_cred->pr_ngroups); + + (void) memcpy(pcrp, core->core_cred, + sizeof (prcred_t) + (ngroups - 1) * sizeof (gid_t)); + + return (0); + } + + errno = ENODATA; + return (-1); +} + +/*ARGSUSED*/ +static int +Ppriv_core(struct ps_prochandle *P, prpriv_t **pprv, void *data) +{ + core_info_t *core = data; + + if (core->core_priv == NULL) { + errno = ENODATA; + return (-1); + } + + *pprv = malloc(core->core_priv_size); + if (*pprv == NULL) { + return (-1); + } + + (void) memcpy(*pprv, core->core_priv, core->core_priv_size); + return (0); +} + +/*ARGSUSED*/ +static const psinfo_t * +Ppsinfo_core(struct ps_prochandle *P, psinfo_t *psinfo, void *data) +{ + return (&P->psinfo); +} + +/*ARGSUSED*/ +static void +Pfini_core(struct ps_prochandle *P, void *data) +{ + core_info_t *core = data; + + if (core != NULL) { + extern void __priv_free_info(void *); + lwp_info_t *nlwp, *lwp = list_next(&core->core_lwp_head); + int i; + + for (i = 0; i < 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 (core->core_platform != NULL) + free(core->core_platform); + if (core->core_uts != NULL) + free(core->core_uts); + if (core->core_cred != NULL) + free(core->core_cred); + if (core->core_priv != NULL) + free(core->core_priv); + if (core->core_privinfo != NULL) + __priv_free_info(core->core_privinfo); + if (core->core_ppii != NULL) + free(core->core_ppii); + if (core->core_zonename != NULL) + free(core->core_zonename); +#if defined(__i386) || defined(__amd64) + if (core->core_ldt != NULL) + free(core->core_ldt); +#endif + + free(core); + } +} + +/*ARGSUSED*/ +static char * +Pplatform_core(struct ps_prochandle *P, char *s, size_t n, void *data) +{ + core_info_t *core = data; + + if (core->core_platform == NULL) { + errno = ENODATA; + return (NULL); + } + (void) strncpy(s, core->core_platform, n - 1); + s[n - 1] = '\0'; + return (s); +} + +/*ARGSUSED*/ +static int +Puname_core(struct ps_prochandle *P, struct utsname *u, void *data) +{ + core_info_t *core = data; + + if (core->core_uts == NULL) { + errno = ENODATA; + return (-1); + } + (void) memcpy(u, core->core_uts, sizeof (struct utsname)); + return (0); +} + +/*ARGSUSED*/ +static char * +Pzonename_core(struct ps_prochandle *P, char *s, size_t n, void *data) +{ + core_info_t *core = data; + + if (core->core_zonename == NULL) { + errno = ENODATA; + return (NULL); + } + (void) strlcpy(s, core->core_zonename, n); + return (s); +} + +#if defined(__i386) || defined(__amd64) +/*ARGSUSED*/ +static int +Pldt_core(struct ps_prochandle *P, struct ssd *pldt, int nldt, void *data) +{ + core_info_t *core = data; + + if (pldt == NULL || nldt == 0) + return (core->core_nldt); + + if (core->core_ldt != NULL) { + nldt = MIN(nldt, core->core_nldt); + + (void) memcpy(pldt, core->core_ldt, + nldt * sizeof (struct ssd)); + + return (nldt); + } + + errno = ENODATA; + return (-1); +} +#endif + +static const ps_ops_t P_core_ops = { + .pop_pread = Pread_core, + .pop_pwrite = Pwrite_core, + .pop_cred = Pcred_core, + .pop_priv = Ppriv_core, + .pop_psinfo = Ppsinfo_core, + .pop_fini = Pfini_core, + .pop_platform = Pplatform_core, + .pop_uname = Puname_core, + .pop_zonename = Pzonename_core, +#if defined(__i386) || defined(__amd64) + .pop_ldt = Pldt_core +#endif +}; /* * Return the lwp_info_t for the given lwpid. If no such lwpid has been @@ -134,13 +317,14 @@ static const ps_rwops_t P_core_ops = { Pread_core, Pwrite_core }; static lwp_info_t * lwpid2info(struct ps_prochandle *P, lwpid_t id) { - lwp_info_t *lwp = list_next(&P->core->core_lwp_head); + core_info_t *core = P->data; + lwp_info_t *lwp = list_next(&core->core_lwp_head); lwp_info_t *next; uint_t i; - for (i = 0; i < P->core->core_nlwp; i++, lwp = list_next(lwp)) { + for (i = 0; i < core->core_nlwp; i++, lwp = list_next(lwp)) { if (lwp->lwp_id == id) { - P->core->core_lwp = lwp; + core->core_lwp = lwp; return (lwp); } if (lwp->lwp_id < id) { @@ -155,8 +339,8 @@ lwpid2info(struct ps_prochandle *P, lwpid_t id) list_link(lwp, next); lwp->lwp_id = id; - P->core->core_lwp = lwp; - P->core->core_nlwp++; + core->core_lwp = lwp; + core->core_nlwp++; return (lwp); } @@ -175,7 +359,9 @@ static int note_pstatus(struct ps_prochandle *P, size_t nbytes) { #ifdef _LP64 - if (P->core->core_dmodel == PR_MODEL_ILP32) { + core_info_t *core = P->data; + + if (core->core_dmodel == PR_MODEL_ILP32) { pstatus32_t ps32; if (nbytes < sizeof (pstatus32_t) || @@ -207,7 +393,9 @@ note_lwpstatus(struct ps_prochandle *P, size_t nbytes) lwpstatus_t lps; #ifdef _LP64 - if (P->core->core_dmodel == PR_MODEL_ILP32) { + core_info_t *core = P->data; + + if (core->core_dmodel == PR_MODEL_ILP32) { lwpstatus32_t l32; if (nbytes < sizeof (lwpstatus32_t) || @@ -246,7 +434,9 @@ static int note_psinfo(struct ps_prochandle *P, size_t nbytes) { #ifdef _LP64 - if (P->core->core_dmodel == PR_MODEL_ILP32) { + core_info_t *core = P->data; + + if (core->core_dmodel == PR_MODEL_ILP32) { psinfo32_t ps32; if (nbytes < sizeof (psinfo32_t) || @@ -278,7 +468,9 @@ note_lwpsinfo(struct ps_prochandle *P, size_t nbytes) lwpsinfo_t lps; #ifdef _LP64 - if (P->core->core_dmodel == PR_MODEL_ILP32) { + core_info_t *core = P->data; + + if (core->core_dmodel == PR_MODEL_ILP32) { lwpsinfo32_t l32; if (nbytes < sizeof (lwpsinfo32_t) || @@ -328,9 +520,10 @@ note_fdinfo(struct ps_prochandle *P, size_t nbytes) static int note_platform(struct ps_prochandle *P, size_t nbytes) { + core_info_t *core = P->data; char *plat; - if (P->core->core_platform != NULL) + if (core->core_platform != NULL) return (0); /* Already seen */ if (nbytes != 0 && ((plat = malloc(nbytes + 1)) != NULL)) { @@ -340,7 +533,7 @@ note_platform(struct ps_prochandle *P, size_t nbytes) return (-1); } plat[nbytes - 1] = '\0'; - P->core->core_platform = plat; + core->core_platform = plat; } return (0); @@ -349,10 +542,11 @@ note_platform(struct ps_prochandle *P, size_t nbytes) static int note_utsname(struct ps_prochandle *P, size_t nbytes) { + core_info_t *core = P->data; size_t ubytes = sizeof (struct utsname); struct utsname *utsp; - if (P->core->core_uts != NULL || nbytes < ubytes) + if (core->core_uts != NULL || nbytes < ubytes) return (0); /* Already seen or bad size */ if ((utsp = malloc(ubytes)) == NULL) @@ -372,22 +566,23 @@ note_utsname(struct ps_prochandle *P, size_t nbytes) dprintf("uts.machine = \"%s\"\n", utsp->machine); } - P->core->core_uts = utsp; + core->core_uts = utsp; return (0); } static int note_content(struct ps_prochandle *P, size_t nbytes) { + core_info_t *core = P->data; core_content_t content; - if (sizeof (P->core->core_content) != nbytes) + if (sizeof (core->core_content) != nbytes) return (-1); if (read(P->asfd, &content, sizeof (content)) != sizeof (content)) return (-1); - P->core->core_content = content; + core->core_content = content; dprintf("core content = %llx\n", content); @@ -397,6 +592,7 @@ note_content(struct ps_prochandle *P, size_t nbytes) static int note_cred(struct ps_prochandle *P, size_t nbytes) { + core_info_t *core = P->data; prcred_t *pcrp; int ngroups; const size_t min_size = sizeof (prcred_t) - sizeof (gid_t); @@ -407,7 +603,7 @@ note_cred(struct ps_prochandle *P, size_t nbytes) * no group memberships. This allows for more flexibility when it * comes to slightly malformed -- but still valid -- notes. */ - if (P->core->core_cred != NULL || nbytes < min_size) + if (core->core_cred != NULL || nbytes < min_size) return (0); /* Already seen or bad size */ ngroups = (nbytes - min_size) / sizeof (gid_t); @@ -428,7 +624,7 @@ note_cred(struct ps_prochandle *P, size_t nbytes) pcrp->pr_ngroups = ngroups; } - P->core->core_cred = pcrp; + core->core_cred = pcrp; return (0); } @@ -436,10 +632,11 @@ note_cred(struct ps_prochandle *P, size_t nbytes) static int note_ldt(struct ps_prochandle *P, size_t nbytes) { + core_info_t *core = P->data; struct ssd *pldt; uint_t nldt; - if (P->core->core_ldt != NULL || nbytes < sizeof (struct ssd)) + if (core->core_ldt != NULL || nbytes < sizeof (struct ssd)) return (0); /* Already seen or bad size */ nldt = nbytes / sizeof (struct ssd); @@ -454,8 +651,8 @@ note_ldt(struct ps_prochandle *P, size_t nbytes) return (-1); } - P->core->core_ldt = pldt; - P->core->core_nldt = nldt; + core->core_ldt = pldt; + core->core_nldt = nldt; return (0); } #endif /* __i386 */ @@ -463,9 +660,10 @@ note_ldt(struct ps_prochandle *P, size_t nbytes) static int note_priv(struct ps_prochandle *P, size_t nbytes) { + core_info_t *core = P->data; prpriv_t *pprvp; - if (P->core->core_priv != NULL || nbytes < sizeof (prpriv_t)) + if (core->core_priv != NULL || nbytes < sizeof (prpriv_t)) return (0); /* Already seen or bad size */ if ((pprvp = malloc(nbytes)) == NULL) @@ -477,18 +675,19 @@ note_priv(struct ps_prochandle *P, size_t nbytes) return (-1); } - P->core->core_priv = pprvp; - P->core->core_priv_size = nbytes; + core->core_priv = pprvp; + core->core_priv_size = nbytes; return (0); } static int note_priv_info(struct ps_prochandle *P, size_t nbytes) { + core_info_t *core = P->data; extern void *__priv_parse_info(); priv_impl_info_t *ppii; - if (P->core->core_privinfo != NULL || + if (core->core_privinfo != NULL || nbytes < sizeof (priv_impl_info_t)) return (0); /* Already seen or bad size */ @@ -502,17 +701,18 @@ note_priv_info(struct ps_prochandle *P, size_t nbytes) return (-1); } - P->core->core_privinfo = __priv_parse_info(ppii); - P->core->core_ppii = ppii; + core->core_privinfo = __priv_parse_info(ppii); + core->core_ppii = ppii; return (0); } static int note_zonename(struct ps_prochandle *P, size_t nbytes) { + core_info_t *core = P->data; char *zonename; - if (P->core->core_zonename != NULL) + if (core->core_zonename != NULL) return (0); /* Already seen */ if (nbytes != 0) { @@ -524,7 +724,7 @@ note_zonename(struct ps_prochandle *P, size_t nbytes) return (-1); } zonename[nbytes - 1] = '\0'; - P->core->core_zonename = zonename; + core->core_zonename = zonename; } return (0); @@ -536,7 +736,9 @@ note_auxv(struct ps_prochandle *P, size_t nbytes) size_t n, i; #ifdef _LP64 - if (P->core->core_dmodel == PR_MODEL_ILP32) { + core_info_t *core = P->data; + + if (core->core_dmodel == PR_MODEL_ILP32) { auxv32_t *a32; n = nbytes / sizeof (auxv32_t); @@ -594,7 +796,8 @@ note_auxv(struct ps_prochandle *P, size_t nbytes) static int note_xreg(struct ps_prochandle *P, size_t nbytes) { - lwp_info_t *lwp = P->core->core_lwp; + core_info_t *core = P->data; + lwp_info_t *lwp = core->core_lwp; size_t xbytes = sizeof (prxregset_t); prxregset_t *xregs; @@ -617,7 +820,8 @@ note_xreg(struct ps_prochandle *P, size_t nbytes) static int note_gwindows(struct ps_prochandle *P, size_t nbytes) { - lwp_info_t *lwp = P->core->core_lwp; + core_info_t *core = P->data; + lwp_info_t *lwp = core->core_lwp; if (lwp == NULL || lwp->lwp_gwins != NULL || nbytes == 0) return (0); /* No lwp yet or already seen or no data */ @@ -632,7 +836,7 @@ note_gwindows(struct ps_prochandle *P, size_t nbytes) * fails since we have to zero out gwindows first anyway. */ #ifdef _LP64 - if (P->core->core_dmodel == PR_MODEL_ILP32) { + if (core->core_dmodel == PR_MODEL_ILP32) { gwindows32_t g32; (void) memset(&g32, 0, sizeof (g32)); @@ -654,7 +858,8 @@ note_gwindows(struct ps_prochandle *P, size_t nbytes) static int note_asrs(struct ps_prochandle *P, size_t nbytes) { - lwp_info_t *lwp = P->core->core_lwp; + core_info_t *core = P->data; + lwp_info_t *lwp = core->core_lwp; int64_t *asrs; if (lwp == NULL || lwp->lwp_asrs != NULL || nbytes < sizeof (asrset_t)) @@ -679,7 +884,9 @@ static int note_spymaster(struct ps_prochandle *P, size_t nbytes) { #ifdef _LP64 - if (P->core->core_dmodel == PR_MODEL_ILP32) { + core_info_t *core = P->data; + + if (core->core_dmodel == PR_MODEL_ILP32) { psinfo32_t ps32; if (nbytes < sizeof (psinfo32_t) || @@ -830,6 +1037,7 @@ core_report_mapping(struct ps_prochandle *P, GElf_Phdr *php) static int core_add_mapping(struct ps_prochandle *P, GElf_Phdr *php) { + core_info_t *core = P->data; prmap_t pmap; dprintf("mapping base %llx filesz %llu memsz %llu offset %llu\n", @@ -845,7 +1053,7 @@ core_add_mapping(struct ps_prochandle *P, GElf_Phdr *php) */ if (php->p_flags & PF_SUNW_FAILURE) { core_report_mapping(P, php); - } else if (php->p_filesz != 0 && php->p_offset >= P->core->core_size) { + } else if (php->p_filesz != 0 && php->p_offset >= core->core_size) { Perror_printf(P, "core file may be corrupt -- data for mapping " "at %p is missing\n", (void *)(uintptr_t)php->p_vaddr); dprintf("core file may be corrupt -- data for mapping " @@ -1481,6 +1689,7 @@ core_find_data(struct ps_prochandle *P, Elf *elf, rd_loadobj_t *rlp) static int core_iter_mapping(const rd_loadobj_t *rlp, struct ps_prochandle *P) { + core_info_t *core = P->data; char lname[PATH_MAX], buf[PATH_MAX]; file_info_t *fp; map_info_t *mp; @@ -1508,7 +1717,7 @@ core_iter_mapping(const rd_loadobj_t *rlp, struct ps_prochandle *P) */ if ((fp = mp->map_file) == NULL && (fp = file_info_new(P, mp)) == NULL) { - P->core->core_errno = errno; + core->core_errno = errno; dprintf("failed to malloc mapping data\n"); return (0); /* Abort */ } @@ -1516,7 +1725,7 @@ core_iter_mapping(const rd_loadobj_t *rlp, struct ps_prochandle *P) /* Create a local copy of the load object representation */ if ((fp->file_lo = calloc(1, sizeof (rd_loadobj_t))) == NULL) { - P->core->core_errno = errno; + core->core_errno = errno; dprintf("failed to malloc mapping data\n"); return (0); /* Abort */ } @@ -1783,6 +1992,7 @@ struct ps_prochandle * Pfgrab_core(int core_fd, const char *aout_path, int *perr) { struct ps_prochandle *P; + core_info_t *core_info; map_info_t *stk_mp, *brk_mp; const char *execname; char *interp; @@ -1848,7 +2058,7 @@ Pfgrab_core(int core_fd, const char *aout_path, int *perr) P->agentstatfd = -1; P->zoneroot = NULL; P->info_valid = 1; - P->ops = &P_core_ops; + Pinit_ops(&P->ops, &P_core_ops); Pinitsym(P); @@ -1867,28 +2077,29 @@ Pfgrab_core(int core_fd, const char *aout_path, int *perr) * Allocate and initialize a core_info_t to hang off the ps_prochandle * structure. We keep all core-specific information in this structure. */ - if ((P->core = calloc(1, sizeof (core_info_t))) == NULL) { + if ((core_info = calloc(1, sizeof (core_info_t))) == NULL) { *perr = G_STRANGE; goto err; } - list_link(&P->core->core_lwp_head, NULL); - P->core->core_size = stbuf.st_size; + P->data = core_info; + list_link(&core_info->core_lwp_head, NULL); + core_info->core_size = stbuf.st_size; /* * In the days before adjustable core file content, this was the * default core file content. For new core files, this value will * be overwritten by the NT_CONTENT note section. */ - P->core->core_content = CC_CONTENT_STACK | CC_CONTENT_HEAP | + core_info->core_content = CC_CONTENT_STACK | CC_CONTENT_HEAP | CC_CONTENT_DATA | CC_CONTENT_RODATA | CC_CONTENT_ANON | CC_CONTENT_SHANON; switch (core.e_hdr.e_ident[EI_CLASS]) { case ELFCLASS32: - P->core->core_dmodel = PR_MODEL_ILP32; + core_info->core_dmodel = PR_MODEL_ILP32; break; case ELFCLASS64: - P->core->core_dmodel = PR_MODEL_LP64; + core_info->core_dmodel = PR_MODEL_LP64; break; default: *perr = G_FORMAT; @@ -2114,7 +2325,7 @@ Pfgrab_core(int core_fd, const char *aout_path, int *perr) interp = dp->d_buf; } else if (base_addr != (uintptr_t)-1L) { - if (P->core->core_dmodel == PR_MODEL_LP64) + if (core_info->core_dmodel == PR_MODEL_LP64) interp = "/usr/lib/64/ld.so.1"; else interp = "/usr/lib/ld.so.1"; @@ -2229,8 +2440,8 @@ Pfgrab_core(int core_fd, const char *aout_path, int *perr) (void) rd_loadobj_iter(P->rap, (rl_iter_f *) core_iter_mapping, P); - if (P->core->core_errno != 0) { - errno = P->core->core_errno; + if (core_info->core_errno != 0) { + errno = core_info->core_errno; *perr = G_STRANGE; goto err; } diff --git a/usr/src/lib/libproc/common/Pexecname.c b/usr/src/lib/libproc/common/Pexecname.c index 82b4219560..8af0416e10 100644 --- a/usr/src/lib/libproc/common/Pexecname.c +++ b/usr/src/lib/libproc/common/Pexecname.c @@ -22,6 +22,9 @@ * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ +/* + * Copyright (c) 2013 by Delphix. All rights reserved. + */ #define __EXTENSIONS__ #include <string.h> @@ -236,23 +239,7 @@ found: } /* - * 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, struct stat64 *stp) -{ - 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); -} - -/* - * Return the full pathname for the executable file. If the process handle is - * a core file, we've already tried our best to get the executable name. - * Otherwise, we make an attempt using Pfindexec(). + * Return the full pathname for the executable file. */ char * Pexecname(struct ps_prochandle *P, char *buf, size_t buflen) @@ -262,48 +249,5 @@ Pexecname(struct ps_prochandle *P, char *buf, size_t buflen) return (buf); } - if (P->state != PS_DEAD && P->state != PS_IDLE) { - 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, - (int (*)(const char *, void *))stat_exec, &st); - } - - return (NULL); + return (P->ops.pop_execname(P, buf, buflen, P->data)); } diff --git a/usr/src/lib/libproc/common/Pgcore.c b/usr/src/lib/libproc/common/Pgcore.c index 2b5ec7c9bd..bf530be90c 100644 --- a/usr/src/lib/libproc/common/Pgcore.c +++ b/usr/src/lib/libproc/common/Pgcore.c @@ -26,6 +26,7 @@ /* * Copyright 2012 DEY Storage Systems, Inc. All rights reserved. * Copyright (c) 2013, Joyent, Inc. All rights reserved. + * Copyright (c) 2013 by Delphix. All rights reserved. */ #define _STRUCTURED_PROC 1 @@ -1357,11 +1358,11 @@ Pfgcore(struct ps_prochandle *P, int fd, core_content_t content) } { - prpriv_t *ppriv; + prpriv_t *ppriv = NULL; const priv_impl_info_t *pinfo; size_t pprivsz, pinfosz; - if ((ppriv = proc_get_priv(P->pid)) == NULL) + if (Ppriv(P, &ppriv) == -1) goto err; pprivsz = PRIV_PRPRIV_SIZE(ppriv); diff --git a/usr/src/lib/libproc/common/Pidle.c b/usr/src/lib/libproc/common/Pidle.c index 938510abeb..3191f4fa7e 100644 --- a/usr/src/lib/libproc/common/Pidle.c +++ b/usr/src/lib/libproc/common/Pidle.c @@ -22,6 +22,9 @@ * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ +/* + * Copyright (c) 2013 by Delphix. All rights reserved. + */ #include <stdlib.h> #include <libelf.h> @@ -34,8 +37,10 @@ #include "libproc.h" #include "Pcontrol.h" +/*ARGSUSED*/ static ssize_t -Pread_idle(struct ps_prochandle *P, void *buf, size_t n, uintptr_t addr) +Pread_idle(struct ps_prochandle *P, void *buf, size_t n, uintptr_t addr, + void *data) { size_t resid = n; @@ -65,15 +70,55 @@ Pread_idle(struct ps_prochandle *P, void *buf, size_t n, uintptr_t addr) /*ARGSUSED*/ static ssize_t -Pwrite_idle(struct ps_prochandle *P, const void *buf, size_t n, uintptr_t addr) +Pwrite_idle(struct ps_prochandle *P, const void *buf, size_t n, uintptr_t addr, + void *data) { errno = EIO; return (-1); } -static const ps_rwops_t P_idle_ops = { - Pread_idle, - Pwrite_idle +/*ARGSUSED*/ +static int +Ppriv_idle(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); +} + +/* Default operations for the idl ops vector. */ +static void * +Pidle_voidp() +{ + errno = ENODATA; + return (NULL); +} + +static int +Pidle_int() +{ + errno = ENODATA; + return (-1); +} + +static const ps_ops_t P_idle_ops = { + .pop_pread = Pread_idle, + .pop_pwrite = Pwrite_idle, + .pop_cred = (pop_cred_t)Pidle_int, + .pop_priv = Ppriv_idle, + .pop_psinfo = (pop_psinfo_t)Pidle_voidp, + .pop_platform = (pop_platform_t)Pidle_voidp, + .pop_uname = (pop_uname_t)Pidle_int, + .pop_zonename = (pop_zonename_t)Pidle_voidp, +#if defined(__i386) || defined(__amd64) + .pop_ldt = (pop_ldt_t)Pidle_int +#endif }; static int @@ -143,7 +188,7 @@ Pgrab_file(const char *fname, int *perr) P->agentctlfd = -1; P->agentstatfd = -1; P->info_valid = -1; - P->ops = &P_idle_ops; + Pinit_ops(&P->ops, &P_idle_ops); Pinitsym(P); if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { diff --git a/usr/src/lib/libproc/common/Plwpregs.c b/usr/src/lib/libproc/common/Plwpregs.c index 7549bc142d..c2b150000f 100644 --- a/usr/src/lib/libproc/common/Plwpregs.c +++ b/usr/src/lib/libproc/common/Plwpregs.c @@ -25,6 +25,7 @@ /* * Copyright (c) 2013, Joyent, Inc. All rights reserved. + * Copyright (c) 2013 by Delphix. All rights reserved. */ #include <sys/types.h> @@ -50,10 +51,11 @@ static lwp_info_t * getlwpcore(struct ps_prochandle *P, lwpid_t lwpid) { - lwp_info_t *lwp = list_next(&P->core->core_lwp_head); + core_info_t *core = P->data; + lwp_info_t *lwp = list_next(&core->core_lwp_head); uint_t i; - for (i = 0; i < P->core->core_nlwp; i++, lwp = list_next(lwp)) { + for (i = 0; i < core->core_nlwp; i++, lwp = list_next(lwp)) { if (lwp->lwp_id == lwpid) return (lwp); } @@ -118,7 +120,7 @@ getlwpstatus(struct ps_prochandle *P, lwpid_t lwpid, lwpstatus_t *lps) * If this is a core file, we need to iterate through our list of * cached lwp information and then copy out the status. */ - if (P->core != NULL && (lwp = getlwpcore(P, lwpid)) != NULL) { + if (P->data != NULL && (lwp = getlwpcore(P, lwpid)) != NULL) { (void) memcpy(lps, &lwp->lwp_status, sizeof (lwpstatus_t)); return (0); } diff --git a/usr/src/lib/libproc/common/Pservice.c b/usr/src/lib/libproc/common/Pservice.c index cd43947171..62c88d3ec8 100644 --- a/usr/src/lib/libproc/common/Pservice.c +++ b/usr/src/lib/libproc/common/Pservice.c @@ -22,8 +22,9 @@ * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ - -#pragma ident "%Z%%M% %I% %E% SMI" +/* + * Copyright (c) 2013 by Delphix. All rights reserved. + */ #include <stdarg.h> #include <string.h> @@ -56,7 +57,7 @@ ps_pdmodel(struct ps_prochandle *P, int *modelp) ps_err_e ps_pread(struct ps_prochandle *P, psaddr_t addr, void *buf, size_t size) { - if (P->ops->p_pread(P, buf, size, addr) != size) + if (P->ops.pop_pread(P, buf, size, addr, P->data) != size) return (PS_BADADDR); return (PS_OK); } @@ -64,7 +65,7 @@ ps_pread(struct ps_prochandle *P, psaddr_t addr, void *buf, size_t size) ps_err_e ps_pwrite(struct ps_prochandle *P, psaddr_t addr, const void *buf, size_t size) { - if (P->ops->p_pwrite(P, buf, size, addr) != size) + if (P->ops.pop_pwrite(P, buf, size, addr, P->data) != size) return (PS_BADADDR); return (PS_OK); } diff --git a/usr/src/lib/libproc/common/Psymtab.c b/usr/src/lib/libproc/common/Psymtab.c index 7c8166d5c3..62354f9a7b 100644 --- a/usr/src/lib/libproc/common/Psymtab.c +++ b/usr/src/lib/libproc/common/Psymtab.c @@ -22,6 +22,7 @@ /* * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013, Joyent, Inc. All rights reserved. + * Copyright (c) 2013 by Delphix. All rights reserved. */ #include <assert.h> @@ -41,7 +42,6 @@ #include <libgen.h> #include <sys/types.h> #include <sys/stat.h> -#include <sys/systeminfo.h> #include <sys/sysmacros.h> #include "libproc.h" @@ -434,6 +434,12 @@ load_static_maps(struct ps_prochandle *P) map_set(P, mptr, "ld.so.1"); } +int +Preadmaps(struct ps_prochandle *P, prmap_t **Pmapp, ssize_t *nmapp) +{ + return (P->ops.pop_read_maps(P, Pmapp, nmapp, P->data)); +} + /* * Go through all the address space mappings, validating or updating * the information already gathered, or gathering new information. @@ -444,9 +450,6 @@ load_static_maps(struct ps_prochandle *P) void Pupdate_maps(struct ps_prochandle *P) { - char mapfile[PATH_MAX]; - int mapfd; - struct stat statb; prmap_t *Pmap = NULL; prmap_t *pmap; ssize_t nmap; @@ -460,22 +463,8 @@ Pupdate_maps(struct ps_prochandle *P) Preadauxvec(P); - (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 */ + if (Preadmaps(P, &Pmap, &nmap) != 0) return; - } - (void) close(mapfd); if ((newmap = calloc(1, nmap * sizeof (map_info_t))) == NULL) return; @@ -848,51 +837,16 @@ Pname_to_ctf(struct ps_prochandle *P, const char *name) return (Plmid_to_ctf(P, PR_LMID_EVERY, name)); } -/* - * If we're not a core file, re-read the /proc/<pid>/auxv file and store - * its contents in P->auxv. In the case of a core file, we either - * initialized P->auxv in Pcore() from the NT_AUXV, or we don't have an - * auxv because the note was missing. - */ void Preadauxvec(struct ps_prochandle *P) { - char auxfile[64]; - struct stat statb; - ssize_t naux; - int fd; - - if (P->state == PS_DEAD) - return; /* Already read during Pgrab_core() */ - if (P->state == PS_IDLE) - return; /* No aux vec for Pgrab_file() */ - if (P->auxv != NULL) { free(P->auxv); P->auxv = NULL; P->nauxv = 0; } - (void) snprintf(auxfile, sizeof (auxfile), "%s/%d/auxv", - procfs_path, (int)P->pid); - if ((fd = open(auxfile, O_RDONLY)) < 0) - return; - - if (fstat(fd, &statb) == 0 && - statb.st_size >= sizeof (auxv_t) && - (P->auxv = malloc(statb.st_size + sizeof (auxv_t))) != NULL) { - if ((naux = read(fd, P->auxv, statb.st_size)) < 0 || - (naux /= sizeof (auxv_t)) < 1) { - free(P->auxv); - P->auxv = NULL; - } else { - P->auxv[naux].a_type = AT_NULL; - P->auxv[naux].a_un.a_val = 0L; - P->nauxv = (int)naux; - } - } - - (void) close(fd); + P->ops.pop_read_aux(P, &P->auxv, &P->nauxv, P->data); } /* @@ -1683,7 +1637,7 @@ Pbuild_file_symtab(struct ps_prochandle *P, file_info_t *fptr) * the in-core elf image. */ - if (_libproc_incore_elf) { + if (_libproc_incore_elf || (P->flags & INCORE)) { dprintf("Pbuild_file_symtab: using in-core data for: %s\n", fptr->file_pname); @@ -2969,52 +2923,21 @@ Psymbol_iter_by_name(struct ps_prochandle *P, } /* - * Get the platform string from the core file if we have it; - * just perform the system call for the caller if this is a live process. + * Get the platform string. */ char * Pplatform(struct ps_prochandle *P, char *s, size_t n) { - if (P->state == PS_IDLE) { - errno = ENODATA; - return (NULL); - } - - if (P->state == PS_DEAD) { - if (P->core->core_platform == NULL) { - errno = ENODATA; - return (NULL); - } - (void) strncpy(s, P->core->core_platform, n - 1); - s[n - 1] = '\0'; - - } else if (sysinfo(SI_PLATFORM, s, n) == -1) - return (NULL); - - return (s); + return (P->ops.pop_platform(P, s, n, P->data)); } /* - * Get the uname(2) information from the core file if we have it; - * just perform the system call for the caller if this is a live process. + * Get the uname(2) information. */ int Puname(struct ps_prochandle *P, struct utsname *u) { - if (P->state == PS_IDLE) { - errno = ENODATA; - return (-1); - } - - if (P->state == PS_DEAD) { - if (P->core->core_uts == NULL) { - errno = ENODATA; - return (-1); - } - (void) memcpy(u, P->core->core_uts, sizeof (struct utsname)); - return (0); - } - return (uname(u)); + return (P->ops.pop_uname(P, u, P->data)); } /* diff --git a/usr/src/lib/libproc/common/Putil.c b/usr/src/lib/libproc/common/Putil.c index 791ec668cb..f6f2aa862e 100644 --- a/usr/src/lib/libproc/common/Putil.c +++ b/usr/src/lib/libproc/common/Putil.c @@ -23,8 +23,9 @@ * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ - -#pragma ident "%Z%%M% %I% %E% SMI" +/* + * Copyright (c) 2013 by Delphix. All rights reserved. + */ #include <limits.h> #include <string.h> @@ -150,3 +151,96 @@ Perror_printf(struct ps_prochandle *P, const char *format, ...) { /* nothing to do here */ } + +/* + * Default operations. + */ +static ssize_t +Pdefault_ssizet() +{ + return (-1); +} + +static int +Pdefault_int() +{ + return (-1); +} + +static void +Pdefault_void() +{ +} + +static void * +Pdefault_voidp() +{ + return (NULL); +} + +static const ps_ops_t P_default_ops = { + .pop_pread = (pop_pread_t)Pdefault_ssizet, + .pop_pwrite = (pop_pwrite_t)Pdefault_ssizet, + .pop_read_maps = (pop_read_maps_t)Pdefault_int, + .pop_read_aux = (pop_read_aux_t)Pdefault_void, + .pop_cred = (pop_cred_t)Pdefault_int, + .pop_priv = (pop_priv_t)Pdefault_int, + .pop_psinfo = (pop_psinfo_t)Pdefault_voidp, + .pop_status = (pop_status_t)Pdefault_void, + .pop_lstatus = (pop_lstatus_t)Pdefault_voidp, + .pop_lpsinfo = (pop_lpsinfo_t)Pdefault_voidp, + .pop_fini = (pop_fini_t)Pdefault_void, + .pop_platform = (pop_platform_t)Pdefault_voidp, + .pop_uname = (pop_uname_t)Pdefault_int, + .pop_zonename = (pop_zonename_t)Pdefault_voidp, + .pop_execname = (pop_execname_t)Pdefault_voidp, +#if defined(__i386) || defined(__amd64) + .pop_ldt = (pop_ldt_t)Pdefault_int +#endif +}; + +/* + * Initialize the destination ops vector with functions from the source. + * Functions which are NULL in the source ops vector are set to corresponding + * default function in the destination vector. + */ +void +Pinit_ops(ps_ops_t *dst, const ps_ops_t *src) +{ + *dst = P_default_ops; + + if (src->pop_pread != NULL) + dst->pop_pread = src->pop_pread; + if (src->pop_pwrite != NULL) + dst->pop_pwrite = src->pop_pwrite; + if (src->pop_read_maps != NULL) + dst->pop_read_maps = src->pop_read_maps; + if (src->pop_read_aux != NULL) + dst->pop_read_aux = src->pop_read_aux; + if (src->pop_cred != NULL) + dst->pop_cred = src->pop_cred; + if (src->pop_priv != NULL) + dst->pop_priv = src->pop_priv; + if (src->pop_psinfo != NULL) + dst->pop_psinfo = src->pop_psinfo; + if (src->pop_status != NULL) + dst->pop_status = src->pop_status; + if (src->pop_lstatus != NULL) + dst->pop_lstatus = src->pop_lstatus; + if (src->pop_lpsinfo != NULL) + dst->pop_lpsinfo = src->pop_lpsinfo; + if (src->pop_fini != NULL) + dst->pop_fini = src->pop_fini; + if (src->pop_platform != NULL) + dst->pop_platform = src->pop_platform; + if (src->pop_uname != NULL) + dst->pop_uname = src->pop_uname; + if (src->pop_zonename != NULL) + dst->pop_zonename = src->pop_zonename; + if (src->pop_execname != NULL) + dst->pop_execname = src->pop_execname; +#if defined(__i386) || defined(__amd64) + if (src->pop_ldt != NULL) + dst->pop_ldt = src->pop_ldt; +#endif +} diff --git a/usr/src/lib/libproc/common/Putil.h b/usr/src/lib/libproc/common/Putil.h index 55ea45dba2..57814a9a7f 100644 --- a/usr/src/lib/libproc/common/Putil.h +++ b/usr/src/lib/libproc/common/Putil.h @@ -23,12 +23,13 @@ * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ +/* + * Copyright (c) 2013 by Delphix. All rights reserved. + */ #ifndef _PUTIL_H #define _PUTIL_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -64,6 +65,8 @@ extern int prset_ismember(void *, size_t, uint_t); */ extern void dprintf(const char *, ...); +extern void Pinit_ops(ps_ops_t *, const ps_ops_t *); + #ifdef __cplusplus } #endif diff --git a/usr/src/lib/libproc/common/Pzone.c b/usr/src/lib/libproc/common/Pzone.c index 68efea7a72..67a8c0b3c9 100644 --- a/usr/src/lib/libproc/common/Pzone.c +++ b/usr/src/lib/libproc/common/Pzone.c @@ -25,6 +25,7 @@ */ /* * Copyright (c) 2013, Joyent, Inc. All rights reserved. + * Copyright (c) 2013 by Delphix. All rights reserved. */ #include <assert.h> @@ -231,23 +232,7 @@ Pbrandname(struct ps_prochandle *P, char *buf, size_t buflen) char * Pzonename(struct ps_prochandle *P, char *s, size_t n) { - if (P->state == PS_IDLE) { - errno = ENODATA; - return (NULL); - } - - if (P->state == PS_DEAD) { - if (P->core->core_zonename == NULL) { - errno = ENODATA; - return (NULL); - } - (void) strlcpy(s, P->core->core_zonename, n); - } else { - if (getzonenamebyid(P->status.pr_zoneid, s, n) < 0) - return (NULL); - s[n - 1] = '\0'; - } - return (s); + return (P->ops.pop_zonename(P, s, n, P->data)); } char * diff --git a/usr/src/lib/libproc/common/libproc.h b/usr/src/lib/libproc/common/libproc.h index 7cfc80cd7a..01970f439e 100644 --- a/usr/src/lib/libproc/common/libproc.h +++ b/usr/src/lib/libproc/common/libproc.h @@ -26,6 +26,7 @@ * Portions Copyright 2007 Chad Mynhier * Copyright 2012 DEY Storage Systems, Inc. All rights reserved. * Copyright (c) 2013, Joyent, Inc. All rights reserved. + * Copyright (c) 2013 by Delphix. All rights reserved. */ /* @@ -127,6 +128,7 @@ extern int _libproc_incore_elf; /* only use in-core elf data */ #define PGRAB_FORCE 0x02 /* Open the process w/o O_EXCL */ #define PGRAB_RDONLY 0x04 /* Open the process or core w/ O_RDONLY */ #define PGRAB_NOSTOP 0x08 /* Open the process but do not stop it */ +#define PGRAB_INCORE 0x10 /* Use in-core data to build symbol tables */ /* Error codes from Pcreate() */ #define C_STRANGE -1 /* Unanticipated error, errno is meaningful */ @@ -188,6 +190,55 @@ typedef struct { /* argument descriptor for system call (Psyscall) */ #define MAXARGL (4*1024) /* + * Ops vector definition for the Pgrab_ops(). + */ +typedef ssize_t (*pop_pread_t)(struct ps_prochandle *, void *, size_t, + uintptr_t, void *); +typedef ssize_t (*pop_pwrite_t)(struct ps_prochandle *, const void *, size_t, + uintptr_t, void *); +typedef int (*pop_read_maps_t)(struct ps_prochandle *, prmap_t **, ssize_t *, + void *); +typedef void (*pop_read_aux_t)(struct ps_prochandle *, auxv_t **, int *, + void *); +typedef int (*pop_cred_t)(struct ps_prochandle *, prcred_t *, int, + void *); +typedef int (*pop_priv_t)(struct ps_prochandle *, prpriv_t **, void *); +typedef const psinfo_t *(*pop_psinfo_t)(struct ps_prochandle *, psinfo_t *, + void *); +typedef void (*pop_status_t)(struct ps_prochandle *, pstatus_t *, void *); +typedef prheader_t *(*pop_lstatus_t)(struct ps_prochandle *, void *); +typedef prheader_t *(*pop_lpsinfo_t)(struct ps_prochandle *, void *); +typedef void (*pop_fini_t)(struct ps_prochandle *, void *); +typedef char *(*pop_platform_t)(struct ps_prochandle *, char *, size_t, void *); +typedef int (*pop_uname_t)(struct ps_prochandle *, struct utsname *, void *); +typedef char *(*pop_zonename_t)(struct ps_prochandle *, char *, size_t, void *); +typedef char *(*pop_execname_t)(struct ps_prochandle *, char *, size_t, void *); +#if defined(__i386) || defined(__amd64) +typedef int (*pop_ldt_t)(struct ps_prochandle *, struct ssd *, int, void *); +#endif + +typedef struct ps_ops { + pop_pread_t pop_pread; + pop_pwrite_t pop_pwrite; + pop_read_maps_t pop_read_maps; + pop_read_aux_t pop_read_aux; + pop_cred_t pop_cred; + pop_priv_t pop_priv; + pop_psinfo_t pop_psinfo; + pop_status_t pop_status; + pop_lstatus_t pop_lstatus; + pop_lpsinfo_t pop_lpsinfo; + pop_fini_t pop_fini; + pop_platform_t pop_platform; + pop_uname_t pop_uname; + pop_zonename_t pop_zonename; + pop_execname_t pop_execname; +#if defined(__i386) || defined(__amd64) + pop_ldt_t pop_ldt; +#endif +} ps_ops_t; + +/* * Function prototypes for routines in the process control package. */ extern struct ps_prochandle *Pcreate(const char *, char *const *, @@ -201,6 +252,7 @@ extern struct ps_prochandle *Pgrab(pid_t, int, int *); extern struct ps_prochandle *Pgrab_core(const char *, const char *, int, int *); extern struct ps_prochandle *Pfgrab_core(int, const char *, int *); extern struct ps_prochandle *Pgrab_file(const char *, int *); +extern struct ps_prochandle *Pgrab_ops(pid_t, void *, const ps_ops_t *, int); extern const char *Pgrab_error(int); extern int Preopen(struct ps_prochandle *); @@ -221,7 +273,7 @@ extern const psinfo_t *Ppsinfo(struct ps_prochandle *); extern const pstatus_t *Pstatus(struct ps_prochandle *); extern int Pcred(struct ps_prochandle *, prcred_t *, int); extern int Psetcred(struct ps_prochandle *, const prcred_t *); -extern ssize_t Ppriv(struct ps_prochandle *, prpriv_t *, size_t); +extern int Ppriv(struct ps_prochandle *, prpriv_t **); extern int Psetpriv(struct ps_prochandle *, prpriv_t *); extern void *Pprivinfo(struct ps_prochandle *); extern int Psetzoneid(struct ps_prochandle *, zoneid_t); diff --git a/usr/src/lib/libproc/common/llib-lproc b/usr/src/lib/libproc/common/llib-lproc index 9626e80024..35907f04d0 100644 --- a/usr/src/lib/libproc/common/llib-lproc +++ b/usr/src/lib/libproc/common/llib-lproc @@ -25,6 +25,9 @@ * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ +/* + * Copyright (c) 2013 by Delphix. All rights reserved. + */ #include "libproc.h" /* @@ -46,7 +49,7 @@ int Pctlfd(struct ps_prochandle *Pr); const psinfo_t *Ppsinfo(struct ps_prochandle *Pr); const pstatus_t *Pstatus(struct ps_prochandle *Pr); int Pcred(struct ps_prochandle *Pr, prcred_t *pcrp, int ngroups); -ssize_t Ppriv(struct ps_prochandle *Pr, prpriv_t *pprivp, size_t); +int Ppriv(struct ps_prochandle *Pr, prpriv_t **pprivp); void Psync(struct ps_prochandle *Pr); int Pcreate_agent(struct ps_prochandle *Pr); void Pdestroy_agent(struct ps_prochandle *Pr); diff --git a/usr/src/lib/libproc/common/mapfile-vers b/usr/src/lib/libproc/common/mapfile-vers index eb91461d98..666d63fbf0 100644 --- a/usr/src/lib/libproc/common/mapfile-vers +++ b/usr/src/lib/libproc/common/mapfile-vers @@ -22,6 +22,7 @@ # Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. # Copyright 2012 DEY Storage Systems, Inc. All rights reserved. # Copyright (c) 2013, Joyent, Inc. All rights reserved. +# Copyright (c) 2013 by Delphix. All rights reserved. # # @@ -123,6 +124,7 @@ SYMBOL_VERSION SUNWprivate_1.1 { Pgrab_core; Pgrab_error; Pgrab_file; + Pgrab_ops; Pisprocdir; Pissyscall_prev; Plmid; |