summaryrefslogtreecommitdiff
path: root/usr/src/lib/libproc/common
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/lib/libproc/common
downloadillumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/lib/libproc/common')
-rw-r--r--usr/src/lib/libproc/common/P32ton.c819
-rw-r--r--usr/src/lib/libproc/common/P32ton.h86
-rw-r--r--usr/src/lib/libproc/common/Pcontrol.c3693
-rw-r--r--usr/src/lib/libproc/common/Pcontrol.h250
-rw-r--r--usr/src/lib/libproc/common/Pcore.c2003
-rw-r--r--usr/src/lib/libproc/common/Pexecname.c286
-rw-r--r--usr/src/lib/libproc/common/Pgcore.c1534
-rw-r--r--usr/src/lib/libproc/common/Pidle.c259
-rw-r--r--usr/src/lib/libproc/common/Pisadep.h101
-rw-r--r--usr/src/lib/libproc/common/Pisprocdir.c62
-rw-r--r--usr/src/lib/libproc/common/Plwpregs.c500
-rw-r--r--usr/src/lib/libproc/common/Pscantext.c183
-rw-r--r--usr/src/lib/libproc/common/Pservice.c372
-rw-r--r--usr/src/lib/libproc/common/Pstack.c288
-rw-r--r--usr/src/lib/libproc/common/Pstack.h61
-rw-r--r--usr/src/lib/libproc/common/Psymtab.c3434
-rw-r--r--usr/src/lib/libproc/common/Psyscall.c555
-rw-r--r--usr/src/lib/libproc/common/Putil.c152
-rw-r--r--usr/src/lib/libproc/common/Putil.h71
-rw-r--r--usr/src/lib/libproc/common/libproc.h704
-rw-r--r--usr/src/lib/libproc/common/llib-lproc381
-rw-r--r--usr/src/lib/libproc/common/pr_door.c98
-rw-r--r--usr/src/lib/libproc/common/pr_exit.c110
-rw-r--r--usr/src/lib/libproc/common/pr_fcntl.c140
-rw-r--r--usr/src/lib/libproc/common/pr_getitimer.c172
-rw-r--r--usr/src/lib/libproc/common/pr_getrctl.c199
-rw-r--r--usr/src/lib/libproc/common/pr_getrlimit.c227
-rw-r--r--usr/src/lib/libproc/common/pr_getsockname.c169
-rw-r--r--usr/src/lib/libproc/common/pr_ioctl.c84
-rw-r--r--usr/src/lib/libproc/common/pr_lseek.c187
-rw-r--r--usr/src/lib/libproc/common/pr_memcntl.c116
-rw-r--r--usr/src/lib/libproc/common/pr_meminfo.c188
-rw-r--r--usr/src/lib/libproc/common/pr_mmap.c145
-rw-r--r--usr/src/lib/libproc/common/pr_open.c183
-rw-r--r--usr/src/lib/libproc/common/pr_pbind.c155
-rw-r--r--usr/src/lib/libproc/common/pr_rename.c137
-rw-r--r--usr/src/lib/libproc/common/pr_sigaction.c126
-rw-r--r--usr/src/lib/libproc/common/pr_stat.c500
-rw-r--r--usr/src/lib/libproc/common/pr_statvfs.c165
-rw-r--r--usr/src/lib/libproc/common/pr_tasksys.c170
-rw-r--r--usr/src/lib/libproc/common/pr_waitid.c108
-rw-r--r--usr/src/lib/libproc/common/proc_arg.c509
-rw-r--r--usr/src/lib/libproc/common/proc_get_info.c183
-rw-r--r--usr/src/lib/libproc/common/proc_names.c711
-rw-r--r--usr/src/lib/libproc/common/proc_set.c86
-rw-r--r--usr/src/lib/libproc/common/proc_stdio.c171
46 files changed, 20833 insertions, 0 deletions
diff --git a/usr/src/lib/libproc/common/P32ton.c b/usr/src/lib/libproc/common/P32ton.c
new file mode 100644
index 0000000000..90cdb41a41
--- /dev/null
+++ b/usr/src/lib/libproc/common/P32ton.c
@@ -0,0 +1,819 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/mkdev.h>
+#include <sys/regset.h>
+#include <string.h>
+
+#if defined(__amd64)
+#include <sys/fp.h>
+#include <ieeefp.h>
+#endif
+
+#include "P32ton.h"
+
+dev_t
+prexpldev(dev32_t d)
+{
+ if (d != (dev32_t)-1L)
+ return (makedev((d >> NBITSMINOR32) & MAXMAJ32, d & MAXMIN32));
+
+ return ((dev_t)PRNODEV);
+}
+
+
+dev32_t
+prcmpldev(dev_t d)
+{
+#ifdef _LP64
+ if (d == PRNODEV) {
+ return (PRNODEV32);
+ } else {
+ major_t maj = major(d);
+ minor_t min = minor(d);
+
+ if (maj == (major_t)PRNODEV || min == (minor_t)PRNODEV)
+ return (PRNODEV32);
+
+ return ((dev32_t)((maj << NBITSMINOR32) | min));
+ }
+#else
+ return ((dev32_t)d);
+#endif
+}
+
+#ifdef _LP64
+
+void
+timestruc_32_to_n(const timestruc32_t *src, timestruc_t *dst)
+{
+ dst->tv_sec = (time_t)(uint32_t)src->tv_sec;
+ dst->tv_nsec = (long)(uint32_t)src->tv_nsec;
+}
+
+void
+stack_32_to_n(const stack32_t *src, stack_t *dst)
+{
+ dst->ss_sp = (caddr_t)(uintptr_t)src->ss_sp;
+ dst->ss_size = src->ss_size;
+ dst->ss_flags = src->ss_flags;
+}
+
+void
+sigaction_32_to_n(const struct sigaction32 *src, struct sigaction *dst)
+{
+ (void) memset(dst, 0, sizeof (struct sigaction));
+ dst->sa_flags = src->sa_flags;
+ dst->sa_handler = (void (*)())(uintptr_t)src->sa_handler;
+ (void) memcpy(&dst->sa_mask, &src->sa_mask, sizeof (dst->sa_mask));
+}
+
+void
+siginfo_32_to_n(const siginfo32_t *src, siginfo_t *dst)
+{
+ (void) memset(dst, 0, sizeof (siginfo_t));
+
+ /*
+ * The absolute minimum content is si_signo and si_code.
+ */
+ dst->si_signo = src->si_signo;
+ if ((dst->si_code = src->si_code) == SI_NOINFO)
+ return;
+
+ /*
+ * A siginfo generated by user level is structured
+ * differently from one generated by the kernel.
+ */
+ if (SI_FROMUSER(src)) {
+ dst->si_pid = src->si_pid;
+ dst->si_ctid = src->si_ctid;
+ dst->si_zoneid = src->si_zoneid;
+ dst->si_uid = src->si_uid;
+ if (SI_CANQUEUE(src->si_code)) {
+ dst->si_value.sival_int =
+ (long)(uint32_t)src->si_value.sival_int;
+ }
+ return;
+ }
+
+ dst->si_errno = src->si_errno;
+
+ switch (src->si_signo) {
+ default:
+ dst->si_pid = src->si_pid;
+ dst->si_ctid = src->si_ctid;
+ dst->si_zoneid = src->si_zoneid;
+ dst->si_uid = src->si_uid;
+ dst->si_value.sival_int =
+ (long)(uint32_t)src->si_value.sival_int;
+ break;
+ case SIGCLD:
+ dst->si_pid = src->si_pid;
+ dst->si_ctid = src->si_ctid;
+ dst->si_zoneid = src->si_zoneid;
+ dst->si_status = src->si_status;
+ dst->si_stime = src->si_stime;
+ dst->si_utime = src->si_utime;
+ break;
+ case SIGSEGV:
+ case SIGBUS:
+ case SIGILL:
+ case SIGTRAP:
+ case SIGFPE:
+ case SIGEMT:
+ dst->si_addr = (void *)(uintptr_t)src->si_addr;
+ dst->si_trapno = src->si_trapno;
+ dst->si_pc = (void *)(uintptr_t)src->si_pc;
+ break;
+ case SIGPOLL:
+ case SIGXFSZ:
+ dst->si_fd = src->si_fd;
+ dst->si_band = src->si_band;
+ break;
+ case SIGPROF:
+ dst->si_faddr = (void *)(uintptr_t)src->si_faddr;
+ dst->si_tstamp.tv_sec = src->si_tstamp.tv_sec;
+ dst->si_tstamp.tv_nsec = src->si_tstamp.tv_nsec;
+ dst->si_syscall = src->si_syscall;
+ dst->si_nsysarg = src->si_nsysarg;
+ dst->si_fault = src->si_fault;
+ break;
+ }
+}
+
+void
+auxv_32_to_n(const auxv32_t *src, auxv_t *dst)
+{
+ /*
+ * This is a little sketchy: we have three types of values stored
+ * in an auxv (long, void *, and void (*)()) so the only sign-extension
+ * issue is with the long. We could case on all possible AT_* types,
+ * but this seems silly since currently none of the types which use
+ * a_un.a_val actually use negative numbers as a value. For this
+ * reason, it seems simpler to just do an unsigned expansion for now.
+ */
+ dst->a_type = src->a_type;
+ dst->a_un.a_ptr = (void *)(uintptr_t)src->a_un.a_ptr;
+}
+
+#if defined(__sparc)
+void
+rwindow_32_to_n(const struct rwindow32 *src, struct rwindow *dst)
+{
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ dst->rw_local[i] = (uint64_t)(uint32_t)src->rw_local[i];
+ dst->rw_in[i] = (uint64_t)(uint32_t)src->rw_in[i];
+ }
+}
+
+void
+gwindows_32_to_n(const gwindows32_t *src, gwindows_t *dst)
+{
+ int i;
+
+ (void) memset(dst, 0, sizeof (gwindows_t));
+ dst->wbcnt = src->wbcnt;
+
+ for (i = 0; i < src->wbcnt; i++) {
+ if (src->spbuf[i] != 0) {
+ rwindow_32_to_n(&src->wbuf[i], &dst->wbuf[i]);
+ dst->spbuf[i] = (greg_t *)src->spbuf[i];
+ }
+ }
+}
+#endif /* __sparc */
+
+void
+prgregset_32_to_n(const prgreg32_t *src, prgreg_t *dst)
+{
+#ifdef __amd64
+ (void) memset(dst, 0, NPRGREG * sizeof (prgreg_t));
+ dst[REG_GS] = (uint32_t)src[GS];
+ dst[REG_FS] = (uint32_t)src[FS];
+ dst[REG_DS] = (uint32_t)src[DS];
+ dst[REG_ES] = (uint32_t)src[ES];
+ dst[REG_RDI] = (uint32_t)src[EDI];
+ dst[REG_RSI] = (uint32_t)src[ESI];
+ dst[REG_RBP] = (uint32_t)src[EBP];
+ dst[REG_RBX] = (uint32_t)src[EBX];
+ dst[REG_RDX] = (uint32_t)src[EDX];
+ dst[REG_RCX] = (uint32_t)src[ECX];
+ dst[REG_RAX] = (uint32_t)src[EAX];
+ dst[REG_TRAPNO] = (uint32_t)src[TRAPNO];
+ dst[REG_ERR] = (uint32_t)src[ERR];
+ dst[REG_RIP] = (uint32_t)src[EIP];
+ dst[REG_CS] = (uint32_t)src[CS];
+ dst[REG_RFL] = (uint32_t)src[EFL];
+ dst[REG_RSP] = (uint32_t)src[UESP];
+ dst[REG_SS] = (uint32_t)src[SS];
+#else
+ int i;
+
+ for (i = 0; i < NPRGREG; i++)
+ dst[i] = (prgreg_t)(uint32_t)src[i];
+#endif
+}
+
+void
+prfpregset_32_to_n(const prfpregset32_t *src, prfpregset_t *dst)
+{
+#if defined(__sparc)
+ int i;
+
+ (void) memset(dst, 0, sizeof (prfpregset_t));
+
+ for (i = 0; i < 32; i++)
+ dst->pr_fr.pr_regs[i] = src->pr_fr.pr_regs[i];
+
+ /*
+ * We deliberately do not convert pr_qcnt or pr_q because it is a long-
+ * standing /proc bug that this information is not exported, and another
+ * bug further caused these values to be returned as uninitialized data
+ * when the 64-bit kernel exported them for a 32-bit process with en=0.
+ */
+ dst->pr_filler = src->pr_filler;
+ dst->pr_fsr = src->pr_fsr;
+ dst->pr_q_entrysize = src->pr_q_entrysize;
+ dst->pr_en = src->pr_en;
+
+#elif defined(__amd64)
+
+ struct _fpstate32 *src32 = (struct _fpstate32 *)src;
+ struct fpchip_state *dst64 = (struct fpchip_state *)dst;
+ int i;
+
+ (void) memcpy(dst64->st, src32->_st, sizeof (src32->_st));
+ (void) memcpy(dst64->xmm, src32->xmm, sizeof (src32->xmm));
+ (void) memset((caddr_t)dst64->xmm + sizeof (src32->xmm), 0,
+ sizeof (dst64->xmm) - sizeof (src32->xmm));
+ dst64->cw = (uint16_t)src32->cw;
+ dst64->sw = (uint16_t)src32->sw;
+ dst64->fop = 0;
+ dst64->rip = src32->ipoff;
+ dst64->rdp = src32->dataoff;
+ dst64->mxcsr = src32->mxcsr;
+ dst64->mxcsr_mask = 0;
+ dst64->status = src32->status;
+ dst64->xstatus = src32->xstatus;
+
+ /*
+ * Converting from the tag field to the compressed fctw is easy.
+ * If the two tag bits are 3, then the register is empty and we
+ * clear the bit in fctw. Otherwise we set the bit.
+ */
+
+ dst64->fctw = 0;
+ for (i = 0; i < 8; i++)
+ if (((src32->tag >> (i * 2)) & 3) != 3)
+ dst64->fctw |= 1 << i;
+#else
+#error "unrecognized ISA"
+#endif
+}
+
+void
+lwpstatus_32_to_n(const lwpstatus32_t *src, lwpstatus_t *dst)
+{
+ int i;
+
+ dst->pr_flags = src->pr_flags;
+ dst->pr_lwpid = src->pr_lwpid;
+ dst->pr_why = src->pr_why;
+ dst->pr_what = src->pr_what;
+ dst->pr_cursig = src->pr_cursig;
+
+ siginfo_32_to_n(&src->pr_info, &dst->pr_info);
+
+ dst->pr_lwppend = src->pr_lwppend;
+ dst->pr_lwphold = src->pr_lwphold;
+
+ sigaction_32_to_n(&src->pr_action, &dst->pr_action);
+ stack_32_to_n(&src->pr_altstack, &dst->pr_altstack);
+
+ dst->pr_oldcontext = src->pr_oldcontext;
+ dst->pr_syscall = src->pr_syscall;
+ dst->pr_nsysarg = src->pr_nsysarg;
+ dst->pr_errno = src->pr_errno;
+
+ for (i = 0; i < PRSYSARGS; i++)
+ dst->pr_sysarg[i] = (long)(uint32_t)src->pr_sysarg[i];
+
+ dst->pr_rval1 = (long)(uint32_t)src->pr_rval1;
+ dst->pr_rval2 = (long)(uint32_t)src->pr_rval2;
+
+ (void) memcpy(&dst->pr_clname[0], &src->pr_clname[0], PRCLSZ);
+ timestruc_32_to_n(&src->pr_tstamp, &dst->pr_tstamp);
+
+ dst->pr_ustack = src->pr_ustack;
+ dst->pr_instr = src->pr_instr;
+
+ prgregset_32_to_n(src->pr_reg, dst->pr_reg);
+ prfpregset_32_to_n(&src->pr_fpreg, &dst->pr_fpreg);
+}
+
+void
+pstatus_32_to_n(const pstatus32_t *src, pstatus_t *dst)
+{
+ dst->pr_flags = src->pr_flags;
+ dst->pr_nlwp = src->pr_nlwp;
+ dst->pr_nzomb = src->pr_nzomb;
+ dst->pr_pid = src->pr_pid;
+ dst->pr_ppid = src->pr_ppid;
+ dst->pr_pgid = src->pr_pgid;
+ dst->pr_sid = src->pr_sid;
+ dst->pr_taskid = src->pr_taskid;
+ dst->pr_projid = src->pr_projid;
+ dst->pr_zoneid = src->pr_zoneid;
+ dst->pr_aslwpid = src->pr_aslwpid;
+ dst->pr_agentid = src->pr_agentid;
+ dst->pr_sigpend = src->pr_sigpend;
+ dst->pr_brkbase = src->pr_brkbase;
+ dst->pr_brksize = src->pr_brksize;
+ dst->pr_stkbase = src->pr_stkbase;
+ dst->pr_stksize = src->pr_stksize;
+
+ timestruc_32_to_n(&src->pr_utime, &dst->pr_utime);
+ timestruc_32_to_n(&src->pr_stime, &dst->pr_stime);
+ timestruc_32_to_n(&src->pr_cutime, &dst->pr_cutime);
+ timestruc_32_to_n(&src->pr_cstime, &dst->pr_cstime);
+
+ dst->pr_sigtrace = src->pr_sigtrace;
+ dst->pr_flttrace = src->pr_flttrace;
+ dst->pr_sysentry = src->pr_sysentry;
+ dst->pr_sysexit = src->pr_sysexit;
+ dst->pr_dmodel = src->pr_dmodel;
+
+ lwpstatus_32_to_n(&src->pr_lwp, &dst->pr_lwp);
+}
+
+void
+lwpsinfo_32_to_n(const lwpsinfo32_t *src, lwpsinfo_t *dst)
+{
+ dst->pr_flag = src->pr_flag;
+ dst->pr_lwpid = src->pr_lwpid;
+ dst->pr_addr = src->pr_addr;
+ dst->pr_wchan = src->pr_wchan;
+ dst->pr_stype = src->pr_stype;
+ dst->pr_state = src->pr_state;
+ dst->pr_sname = src->pr_sname;
+ dst->pr_nice = src->pr_nice;
+ dst->pr_syscall = src->pr_syscall;
+ dst->pr_oldpri = src->pr_oldpri;
+ dst->pr_cpu = src->pr_cpu;
+ dst->pr_pri = src->pr_pri;
+ dst->pr_pctcpu = src->pr_pctcpu;
+
+ timestruc_32_to_n(&src->pr_start, &dst->pr_start);
+ timestruc_32_to_n(&src->pr_time, &dst->pr_time);
+
+ (void) memcpy(&dst->pr_clname[0], &src->pr_clname[0], PRCLSZ);
+ (void) memcpy(&dst->pr_name[0], &src->pr_name[0], PRFNSZ);
+
+ dst->pr_onpro = src->pr_onpro;
+ dst->pr_bindpro = src->pr_bindpro;
+ dst->pr_bindpset = src->pr_bindpset;
+}
+
+void
+psinfo_32_to_n(const psinfo32_t *src, psinfo_t *dst)
+{
+ dst->pr_flag = src->pr_flag;
+ dst->pr_nlwp = src->pr_nlwp;
+ dst->pr_nzomb = src->pr_nzomb;
+ dst->pr_pid = src->pr_pid;
+ dst->pr_pgid = src->pr_pgid;
+ dst->pr_sid = src->pr_sid;
+ dst->pr_taskid = src->pr_taskid;
+ dst->pr_projid = src->pr_projid;
+ dst->pr_zoneid = src->pr_zoneid;
+ dst->pr_uid = src->pr_uid;
+ dst->pr_euid = src->pr_euid;
+ dst->pr_gid = src->pr_gid;
+ dst->pr_egid = src->pr_egid;
+ dst->pr_addr = src->pr_addr;
+ dst->pr_size = src->pr_size;
+ dst->pr_rssize = src->pr_rssize;
+
+ dst->pr_ttydev = prexpldev(src->pr_ttydev);
+
+ dst->pr_pctcpu = src->pr_pctcpu;
+ dst->pr_pctmem = src->pr_pctmem;
+
+ timestruc_32_to_n(&src->pr_start, &dst->pr_start);
+ timestruc_32_to_n(&src->pr_time, &dst->pr_time);
+ timestruc_32_to_n(&src->pr_ctime, &dst->pr_ctime);
+
+ (void) memcpy(&dst->pr_fname[0], &src->pr_fname[0], PRFNSZ);
+ (void) memcpy(&dst->pr_psargs[0], &src->pr_psargs[0], PRARGSZ);
+
+ dst->pr_wstat = src->pr_wstat;
+ dst->pr_argc = src->pr_argc;
+ dst->pr_argv = src->pr_argv;
+ dst->pr_envp = src->pr_envp;
+ dst->pr_dmodel = src->pr_dmodel;
+
+ lwpsinfo_32_to_n(&src->pr_lwp, &dst->pr_lwp);
+}
+
+void
+timestruc_n_to_32(const timestruc_t *src, timestruc32_t *dst)
+{
+ dst->tv_sec = (time32_t)src->tv_sec;
+ dst->tv_nsec = (int32_t)src->tv_nsec;
+}
+
+void
+stack_n_to_32(const stack_t *src, stack32_t *dst)
+{
+ dst->ss_sp = (caddr32_t)(uintptr_t)src->ss_sp;
+ dst->ss_size = src->ss_size;
+ dst->ss_flags = src->ss_flags;
+}
+
+void
+sigaction_n_to_32(const struct sigaction *src, struct sigaction32 *dst)
+{
+ (void) memset(dst, 0, sizeof (struct sigaction32));
+ dst->sa_flags = src->sa_flags;
+ dst->sa_handler = (caddr32_t)(uintptr_t)src->sa_handler;
+ (void) memcpy(&dst->sa_mask, &src->sa_mask, sizeof (dst->sa_mask));
+}
+
+void
+siginfo_n_to_32(const siginfo_t *src, siginfo32_t *dst)
+{
+ (void) memset(dst, 0, sizeof (siginfo32_t));
+
+ /*
+ * The absolute minimum content is si_signo and si_code.
+ */
+ dst->si_signo = src->si_signo;
+ if ((dst->si_code = src->si_code) == SI_NOINFO)
+ return;
+
+ /*
+ * A siginfo generated by user level is structured
+ * differently from one generated by the kernel.
+ */
+ if (SI_FROMUSER(src)) {
+ dst->si_pid = src->si_pid;
+ dst->si_ctid = src->si_ctid;
+ dst->si_zoneid = src->si_zoneid;
+ dst->si_uid = src->si_uid;
+ if (SI_CANQUEUE(src->si_code)) {
+ dst->si_value.sival_int =
+ (int32_t)src->si_value.sival_int;
+ }
+ return;
+ }
+
+ dst->si_errno = src->si_errno;
+
+ switch (src->si_signo) {
+ default:
+ dst->si_pid = src->si_pid;
+ dst->si_ctid = src->si_ctid;
+ dst->si_zoneid = src->si_zoneid;
+ dst->si_uid = src->si_uid;
+ dst->si_value.sival_int =
+ (int32_t)src->si_value.sival_int;
+ break;
+ case SIGCLD:
+ dst->si_pid = src->si_pid;
+ dst->si_ctid = src->si_ctid;
+ dst->si_zoneid = src->si_zoneid;
+ dst->si_status = src->si_status;
+ dst->si_stime = src->si_stime;
+ dst->si_utime = src->si_utime;
+ break;
+ case SIGSEGV:
+ case SIGBUS:
+ case SIGILL:
+ case SIGTRAP:
+ case SIGFPE:
+ case SIGEMT:
+ dst->si_addr = (caddr32_t)(uintptr_t)src->si_addr;
+ dst->si_trapno = src->si_trapno;
+ dst->si_pc = (caddr32_t)(uintptr_t)src->si_pc;
+ break;
+ case SIGPOLL:
+ case SIGXFSZ:
+ dst->si_fd = src->si_fd;
+ dst->si_band = src->si_band;
+ break;
+ case SIGPROF:
+ dst->si_faddr = (caddr32_t)(uintptr_t)src->si_faddr;
+ dst->si_tstamp.tv_sec = src->si_tstamp.tv_sec;
+ dst->si_tstamp.tv_nsec = src->si_tstamp.tv_nsec;
+ dst->si_syscall = src->si_syscall;
+ dst->si_nsysarg = src->si_nsysarg;
+ dst->si_fault = src->si_fault;
+ break;
+ }
+}
+
+void
+auxv_n_to_32(const auxv_t *src, auxv32_t *dst)
+{
+ dst->a_type = src->a_type;
+ dst->a_un.a_ptr = (caddr32_t)(uintptr_t)src->a_un.a_ptr;
+}
+
+void
+prgregset_n_to_32(const prgreg_t *src, prgreg32_t *dst)
+{
+#ifdef __amd64
+ (void) memset(dst, 0, NPRGREG32 * sizeof (prgreg32_t));
+ dst[GS] = src[REG_GS];
+ dst[FS] = src[REG_FS];
+ dst[DS] = src[REG_DS];
+ dst[ES] = src[REG_ES];
+ dst[EDI] = src[REG_RDI];
+ dst[ESI] = src[REG_RSI];
+ dst[EBP] = src[REG_RBP];
+ dst[EBX] = src[REG_RBX];
+ dst[EDX] = src[REG_RDX];
+ dst[ECX] = src[REG_RCX];
+ dst[EAX] = src[REG_RAX];
+ dst[TRAPNO] = src[REG_TRAPNO];
+ dst[ERR] = src[REG_ERR];
+ dst[EIP] = src[REG_RIP];
+ dst[CS] = src[REG_CS];
+ dst[EFL] = src[REG_RFL];
+ dst[UESP] = src[REG_RSP];
+ dst[SS] = src[REG_SS];
+#else
+ int i;
+
+ for (i = 0; i < NPRGREG; i++)
+ dst[i] = (prgreg32_t)src[i];
+#endif
+}
+
+void
+prfpregset_n_to_32(const prfpregset_t *src, prfpregset32_t *dst)
+{
+#if defined(__sparc)
+ int i;
+
+ (void) memset(dst, 0, sizeof (prfpregset32_t));
+
+ for (i = 0; i < 32; i++)
+ dst->pr_fr.pr_regs[i] = src->pr_fr.pr_regs[i];
+
+ dst->pr_filler = src->pr_filler;
+ dst->pr_fsr = src->pr_fsr;
+ dst->pr_q_entrysize = src->pr_q_entrysize;
+ dst->pr_en = src->pr_en;
+
+#elif defined(__amd64)
+
+ struct _fpstate32 *dst32 = (struct _fpstate32 *)dst;
+ struct fpchip_state *src64 = (struct fpchip_state *)src;
+ uint32_t top;
+ int i;
+
+ (void) memcpy(dst32->_st, src64->st, sizeof (dst32->_st));
+ (void) memcpy(dst32->xmm, src64->xmm, sizeof (dst32->xmm));
+ dst32->cw = src64->cw;
+ dst32->sw = src64->sw;
+ dst32->ipoff = (unsigned int)src64->rip;
+ dst32->cssel = 0;
+ dst32->dataoff = (unsigned int)src64->rdp;
+ dst32->datasel = 0;
+ dst32->status = src64->status;
+ dst32->mxcsr = src64->mxcsr;
+ dst32->xstatus = src64->xstatus;
+
+ /*
+ * AMD64 stores the tag in a compressed form. It is
+ * necessary to extract the original 2-bit tag value.
+ * See AMD64 Architecture Programmer's Manual Volume 2:
+ * System Programming, Chapter 11.
+ */
+
+ top = (src64->sw & FPS_TOP) >> 11;
+ dst32->tag = 0;
+ for (i = 0; i < 8; i++) {
+ /*
+ * Recall that we need to use the current TOP-of-stack value to
+ * associate the _st[] index back to a physical register number,
+ * since tag word indices are physical register numbers. Then
+ * to get the tag value, we shift over two bits for each tag
+ * index, and then grab the bottom two bits.
+ */
+ uint_t tag_index = (i + top) & 7;
+ uint_t tag_fctw = (src64->fctw >> tag_index) & 1;
+ uint_t tag_value;
+ uint_t exp;
+
+ /*
+ * Union for overlaying _fpreg structure on to quad-precision
+ * floating-point value (long double).
+ */
+ union {
+ struct _fpreg reg;
+ long double ld;
+ } fpru;
+
+ fpru.ld = src64->st[i].__fpr_pad._q;
+ exp = fpru.reg.exponent & 0x7fff;
+
+ if (tag_fctw == 0) {
+ tag_value = 3; /* empty */
+ } else if (exp == 0) {
+ if (fpru.reg.significand[0] == 0 &&
+ fpru.reg.significand[1] == 0 &&
+ fpru.reg.significand[2] == 0 &&
+ fpru.reg.significand[3] == 0)
+ tag_value = 1; /* zero */
+ else
+ tag_value = 2; /* special: denormal */
+ } else if (exp == 0x7fff) {
+ tag_value = 2; /* special: infinity or NaN */
+ } else if (fpru.reg.significand[3] & 0x8000) {
+ tag_value = 0; /* valid */
+ } else {
+ tag_value = 2; /* special: unnormal */
+ }
+ dst32->tag |= tag_value << (tag_index * 2);
+ }
+#else
+#error "unrecognized ISA"
+#endif
+}
+
+void
+lwpstatus_n_to_32(const lwpstatus_t *src, lwpstatus32_t *dst)
+{
+ int i;
+
+ dst->pr_flags = src->pr_flags;
+ dst->pr_lwpid = src->pr_lwpid;
+ dst->pr_why = src->pr_why;
+ dst->pr_what = src->pr_what;
+ dst->pr_cursig = src->pr_cursig;
+
+ siginfo_n_to_32(&src->pr_info, &dst->pr_info);
+
+ dst->pr_lwppend = src->pr_lwppend;
+ dst->pr_lwphold = src->pr_lwphold;
+
+ sigaction_n_to_32(&src->pr_action, &dst->pr_action);
+ stack_n_to_32(&src->pr_altstack, &dst->pr_altstack);
+
+ dst->pr_oldcontext = (caddr32_t)src->pr_oldcontext;
+ dst->pr_syscall = src->pr_syscall;
+ dst->pr_nsysarg = src->pr_nsysarg;
+ dst->pr_errno = src->pr_errno;
+
+ for (i = 0; i < PRSYSARGS; i++)
+ dst->pr_sysarg[i] = (int32_t)src->pr_sysarg[i];
+
+ dst->pr_rval1 = (int32_t)src->pr_rval1;
+ dst->pr_rval2 = (int32_t)src->pr_rval2;
+
+ (void) memcpy(&dst->pr_clname[0], &src->pr_clname[0], PRCLSZ);
+ timestruc_n_to_32(&src->pr_tstamp, &dst->pr_tstamp);
+
+ dst->pr_ustack = (caddr32_t)src->pr_ustack;
+ dst->pr_instr = src->pr_instr;
+
+ prgregset_n_to_32(src->pr_reg, dst->pr_reg);
+ prfpregset_n_to_32(&src->pr_fpreg, &dst->pr_fpreg);
+}
+
+void
+pstatus_n_to_32(const pstatus_t *src, pstatus32_t *dst)
+{
+ dst->pr_flags = src->pr_flags;
+ dst->pr_nlwp = src->pr_nlwp;
+ dst->pr_nzomb = src->pr_nzomb;
+ dst->pr_pid = (pid32_t)src->pr_pid;
+ dst->pr_ppid = (pid32_t)src->pr_ppid;
+ dst->pr_pgid = (pid32_t)src->pr_pgid;
+ dst->pr_sid = (pid32_t)src->pr_sid;
+ dst->pr_taskid = (id32_t)src->pr_taskid;
+ dst->pr_projid = (id32_t)src->pr_projid;
+ dst->pr_zoneid = (id32_t)src->pr_zoneid;
+ dst->pr_aslwpid = (id32_t)src->pr_aslwpid;
+ dst->pr_agentid = (id32_t)src->pr_agentid;
+ dst->pr_sigpend = src->pr_sigpend;
+ dst->pr_brkbase = (caddr32_t)src->pr_brkbase;
+ dst->pr_brksize = (size32_t)src->pr_brksize;
+ dst->pr_stkbase = (caddr32_t)src->pr_stkbase;
+ dst->pr_stksize = (size32_t)src->pr_stksize;
+
+ timestruc_n_to_32(&src->pr_utime, &dst->pr_utime);
+ timestruc_n_to_32(&src->pr_stime, &dst->pr_stime);
+ timestruc_n_to_32(&src->pr_cutime, &dst->pr_cutime);
+ timestruc_n_to_32(&src->pr_cstime, &dst->pr_cstime);
+
+ dst->pr_sigtrace = src->pr_sigtrace;
+ dst->pr_flttrace = src->pr_flttrace;
+ dst->pr_sysentry = src->pr_sysentry;
+ dst->pr_sysexit = src->pr_sysexit;
+ dst->pr_dmodel = src->pr_dmodel;
+
+ lwpstatus_n_to_32(&src->pr_lwp, &dst->pr_lwp);
+}
+
+void
+lwpsinfo_n_to_32(const lwpsinfo_t *src, lwpsinfo32_t *dst)
+{
+ dst->pr_flag = src->pr_flag;
+ dst->pr_lwpid = (id32_t)src->pr_lwpid;
+ dst->pr_addr = (caddr32_t)src->pr_addr;
+ dst->pr_wchan = (caddr32_t)src->pr_wchan;
+ dst->pr_stype = src->pr_stype;
+ dst->pr_state = src->pr_state;
+ dst->pr_sname = src->pr_sname;
+ dst->pr_nice = src->pr_nice;
+ dst->pr_syscall = src->pr_syscall;
+ dst->pr_oldpri = src->pr_oldpri;
+ dst->pr_cpu = src->pr_cpu;
+ dst->pr_pri = src->pr_pri;
+ dst->pr_pctcpu = src->pr_pctcpu;
+
+ timestruc_n_to_32(&src->pr_start, &dst->pr_start);
+ timestruc_n_to_32(&src->pr_time, &dst->pr_time);
+
+ (void) memcpy(&dst->pr_clname[0], &src->pr_clname[0], PRCLSZ);
+ (void) memcpy(&dst->pr_name[0], &src->pr_name[0], PRFNSZ);
+
+ dst->pr_onpro = src->pr_onpro;
+ dst->pr_bindpro = src->pr_bindpro;
+ dst->pr_bindpset = src->pr_bindpset;
+}
+
+void
+psinfo_n_to_32(const psinfo_t *src, psinfo32_t *dst)
+{
+ dst->pr_flag = src->pr_flag;
+ dst->pr_nlwp = src->pr_nlwp;
+ dst->pr_nzomb = src->pr_nzomb;
+ dst->pr_pid = (pid32_t)src->pr_pid;
+ dst->pr_pgid = (pid32_t)src->pr_pgid;
+ dst->pr_sid = (pid32_t)src->pr_sid;
+ dst->pr_taskid = (id32_t)src->pr_taskid;
+ dst->pr_projid = (id32_t)src->pr_projid;
+ dst->pr_zoneid = (id32_t)src->pr_zoneid;
+ dst->pr_uid = (uid32_t)src->pr_uid;
+ dst->pr_euid = (uid32_t)src->pr_euid;
+ dst->pr_gid = (gid32_t)src->pr_gid;
+ dst->pr_egid = (gid32_t)src->pr_egid;
+ dst->pr_addr = (caddr32_t)src->pr_addr;
+ dst->pr_size = (size32_t)src->pr_size;
+ dst->pr_rssize = (size32_t)src->pr_rssize;
+
+ dst->pr_ttydev = prcmpldev(src->pr_ttydev);
+
+ dst->pr_pctcpu = src->pr_pctcpu;
+ dst->pr_pctmem = src->pr_pctmem;
+
+ timestruc_n_to_32(&src->pr_start, &dst->pr_start);
+ timestruc_n_to_32(&src->pr_time, &dst->pr_time);
+ timestruc_n_to_32(&src->pr_ctime, &dst->pr_ctime);
+
+ (void) memcpy(&dst->pr_fname[0], &src->pr_fname[0], PRFNSZ);
+ (void) memcpy(&dst->pr_psargs[0], &src->pr_psargs[0], PRARGSZ);
+
+ dst->pr_wstat = src->pr_wstat;
+ dst->pr_argc = src->pr_argc;
+ dst->pr_argv = (caddr32_t)src->pr_argv;
+ dst->pr_envp = (caddr32_t)src->pr_envp;
+ dst->pr_dmodel = src->pr_dmodel;
+
+ lwpsinfo_n_to_32(&src->pr_lwp, &dst->pr_lwp);
+}
+
+
+#endif /* _LP64 */
diff --git a/usr/src/lib/libproc/common/P32ton.h b/usr/src/lib/libproc/common/P32ton.h
new file mode 100644
index 0000000000..95b6d06fae
--- /dev/null
+++ b/usr/src/lib/libproc/common/P32ton.h
@@ -0,0 +1,86 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _P32TON_H
+#define _P32TON_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/types32.h>
+#include <sys/time_impl.h>
+#include <sys/regset.h>
+#include <sys/signal.h>
+#include <sys/auxv.h>
+#include <procfs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern dev_t prexpldev(dev32_t);
+extern dev32_t prcmpldev(dev_t);
+
+#ifdef _LP64
+
+extern void timestruc_32_to_n(const timestruc32_t *, timestruc_t *);
+extern void stack_32_to_n(const stack32_t *, stack_t *);
+extern void sigaction_32_to_n(const struct sigaction32 *, struct sigaction *);
+extern void siginfo_32_to_n(const siginfo32_t *, siginfo_t *);
+extern void auxv_32_to_n(const auxv32_t *, auxv_t *);
+
+#if defined(__sparc)
+extern void rwindow_32_to_n(const struct rwindow32 *, struct rwindow *);
+extern void gwindows_32_to_n(const gwindows32_t *, gwindows_t *);
+#endif
+
+extern void prgregset_32_to_n(const prgreg32_t *, prgreg_t *);
+extern void prfpregset_32_to_n(const prfpregset32_t *, prfpregset_t *);
+extern void lwpstatus_32_to_n(const lwpstatus32_t *, lwpstatus_t *);
+extern void pstatus_32_to_n(const pstatus32_t *, pstatus_t *);
+extern void lwpsinfo_32_to_n(const lwpsinfo32_t *, lwpsinfo_t *);
+extern void psinfo_32_to_n(const psinfo32_t *, psinfo_t *);
+
+extern void timestruc_n_to_32(const timestruc_t *, timestruc32_t *);
+extern void stack_n_to_32(const stack_t *, stack32_t *);
+extern void sigaction_n_to_32(const struct sigaction *, struct sigaction32 *);
+extern void siginfo_n_to_32(const siginfo_t *, siginfo32_t *);
+extern void auxv_n_to_32(const auxv_t *, auxv32_t *);
+
+extern void prgregset_n_to_32(const prgreg_t *, prgreg32_t *);
+extern void prfpregset_n_to_32(const prfpregset_t *, prfpregset32_t *);
+extern void lwpstatus_n_to_32(const lwpstatus_t *, lwpstatus32_t *);
+extern void pstatus_n_to_32(const pstatus_t *, pstatus32_t *);
+extern void lwpsinfo_n_to_32(const lwpsinfo_t *, lwpsinfo32_t *);
+extern void psinfo_n_to_32(const psinfo_t *, psinfo32_t *);
+
+#endif /* _LP64 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _P32TON_H */
diff --git a/usr/src/lib/libproc/common/Pcontrol.c b/usr/src/lib/libproc/common/Pcontrol.c
new file mode 100644
index 0000000000..a0db30858b
--- /dev/null
+++ b/usr/src/lib/libproc/common/Pcontrol.c
@@ -0,0 +1,3693 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <string.h>
+#include <memory.h>
+#include <errno.h>
+#include <dirent.h>
+#include <limits.h>
+#include <signal.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 "libproc.h"
+#include "Pcontrol.h"
+#include "Putil.h"
+#include "P32ton.h"
+
+int _libproc_debug; /* set non-zero to enable debugging printfs */
+sigset_t blockable_sigs; /* signals to block when we need to be safe */
+static int minfd; /* minimum file descriptor returned by dupfd(fd, 0) */
+
+/*
+ * 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)
+{
+ _libproc_debug = getenv("LIBPROC_DEBUG") != NULL;
+
+ (void) sigfillset(&blockable_sigs);
+ (void) sigdelset(&blockable_sigs, SIGKILL);
+ (void) sigdelset(&blockable_sigs, SIGSTOP);
+}
+
+/*
+ * Call set_minfd() once before calling dupfd() several times.
+ * We assume that the application will not reduce its current file
+ * descriptor limit lower than 512 once it has set at least that value.
+ */
+int
+set_minfd(void)
+{
+ static mutex_t minfd_lock = DEFAULTMUTEX;
+ struct rlimit rlim;
+ int fd;
+
+ if ((fd = minfd) < 256) {
+ (void) mutex_lock(&minfd_lock);
+ if ((fd = minfd) < 256) {
+ if (getrlimit(RLIMIT_NOFILE, &rlim) != 0)
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ if (rlim.rlim_cur >= 512)
+ fd = 256;
+ else if ((fd = rlim.rlim_cur / 2) < 3)
+ fd = 3;
+ minfd = fd;
+ }
+ (void) mutex_unlock(&minfd_lock);
+ }
+ return (fd);
+}
+
+int
+dupfd(int fd, int dfd)
+{
+ int mfd;
+
+ /*
+ * Make fd be greater than 255 (the 32-bit stdio limit),
+ * or at least make it greater than 2 so that the
+ * program will work when spawned by init(1m).
+ * Also, if dfd is non-zero, dup the fd to be dfd.
+ */
+ if ((mfd = minfd) == 0)
+ mfd = set_minfd();
+ if (dfd > 0 || (0 <= fd && fd < mfd)) {
+ if (dfd <= 0)
+ dfd = mfd;
+ dfd = fcntl(fd, F_DUPFD, dfd);
+ (void) close(fd);
+ fd = dfd;
+ }
+ /*
+ * Mark it close-on-exec so any created process doesn't inherit it.
+ */
+ if (fd >= 0)
+ (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
+ return (fd);
+}
+
+/*
+ * Create a new controlled process.
+ * Leave it stopped on successful exit from exec() or execve().
+ * Return an opaque pointer to its process control structure.
+ * Return NULL if process cannot be created (fork()/exec() not successful).
+ */
+struct ps_prochandle *
+Pxcreate(const char *file, /* executable file name */
+ char *const *argv, /* argument vector */
+ char *const *envp, /* environment */
+ int *perr, /* pointer to error return code */
+ char *path, /* if non-null, holds exec path name on return */
+ size_t len) /* size of the path buffer */
+{
+ char execpath[PATH_MAX];
+ char procname[100];
+ struct ps_prochandle *P;
+ pid_t pid;
+ int fd;
+ char *fname;
+ int rc;
+ int lasterrno = 0;
+
+ if (len == 0) /* zero length, no path */
+ path = NULL;
+ if (path != NULL)
+ *path = '\0';
+
+ if ((P = malloc(sizeof (struct ps_prochandle))) == NULL) {
+ *perr = C_STRANGE;
+ return (NULL);
+ }
+
+ if ((pid = fork1()) == -1) {
+ free(P);
+ *perr = C_FORK;
+ return (NULL);
+ }
+
+ if (pid == 0) { /* child process */
+ id_t id;
+ extern char **environ;
+
+ /*
+ * If running setuid or setgid, reset credentials to normal.
+ */
+ if ((id = getgid()) != getegid())
+ (void) setgid(id);
+ if ((id = getuid()) != geteuid())
+ (void) setuid(id);
+
+ Pcreate_callback(P); /* execute callback (see below) */
+ (void) pause(); /* wait for PRSABORT from parent */
+
+ /*
+ * This is ugly. There is no execvep() function that takes a
+ * path and an environment. We cheat here by replacing the
+ * global 'environ' variable right before we call this.
+ */
+ if (envp)
+ environ = (char **)envp;
+
+ (void) execvp(file, argv); /* execute the program */
+ _exit(127);
+ }
+
+ /*
+ * Initialize the process structure.
+ */
+ (void) memset(P, 0, sizeof (*P));
+ (void) mutex_init(&P->proc_lock, USYNC_THREAD, NULL);
+ P->flags |= CREATED;
+ P->state = PS_RUN;
+ P->pid = pid;
+ 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.
+ */
+ (void) sprintf(procname, "/proc/%d/", (int)pid);
+ fname = procname + strlen(procname);
+ (void) set_minfd();
+
+ /*
+ * Exclusive write open advises others not to interfere.
+ * There is no reason for any of these open()s to fail.
+ */
+ (void) strcpy(fname, "as");
+ if ((fd = open(procname, (O_RDWR|O_EXCL))) < 0 ||
+ (fd = dupfd(fd, 0)) < 0) {
+ dprintf("Pcreate: failed to open %s: %s\n",
+ procname, strerror(errno));
+ rc = C_STRANGE;
+ goto bad;
+ }
+ P->asfd = fd;
+
+ (void) strcpy(fname, "status");
+ if ((fd = open(procname, O_RDONLY)) < 0 ||
+ (fd = dupfd(fd, 0)) < 0) {
+ dprintf("Pcreate: failed to open %s: %s\n",
+ procname, strerror(errno));
+ rc = C_STRANGE;
+ goto bad;
+ }
+ P->statfd = fd;
+
+ (void) strcpy(fname, "ctl");
+ if ((fd = open(procname, O_WRONLY)) < 0 ||
+ (fd = dupfd(fd, 0)) < 0) {
+ dprintf("Pcreate: failed to open %s: %s\n",
+ procname, strerror(errno));
+ rc = C_STRANGE;
+ goto bad;
+ }
+ P->ctlfd = fd;
+
+ (void) Pstop(P, 0); /* stop the controlled process */
+
+ /*
+ * Wait for process to sleep in pause().
+ * If the process has already called pause(), then it should be
+ * stopped (PR_REQUESTED) while asleep in pause and we are done.
+ * Else we set up to catch entry/exit to pause() and set the process
+ * running again, expecting it to stop when it reaches pause().
+ * There is no reason for this to fail other than an interrupt.
+ */
+ (void) Psysentry(P, SYS_pause, 1);
+ (void) Psysexit(P, SYS_pause, 1);
+ for (;;) {
+ if (P->state == PS_STOP &&
+ P->status.pr_lwp.pr_syscall == SYS_pause &&
+ (P->status.pr_lwp.pr_why == PR_REQUESTED ||
+ P->status.pr_lwp.pr_why == PR_SYSENTRY ||
+ P->status.pr_lwp.pr_why == PR_SYSEXIT))
+ break;
+
+ if (P->state != PS_STOP || /* interrupt or process died */
+ Psetrun(P, 0, 0) != 0) { /* can't restart */
+ if (errno == EINTR || errno == ERESTART)
+ rc = C_INTR;
+ else {
+ dprintf("Pcreate: Psetrun failed: %s\n",
+ strerror(errno));
+ rc = C_STRANGE;
+ }
+ goto bad;
+ }
+
+ (void) Pwait(P, 0);
+ }
+ (void) Psysentry(P, SYS_pause, 0);
+ (void) Psysexit(P, SYS_pause, 0);
+
+ /*
+ * Kick the process off the pause() and catch
+ * it again on entry to exec() or exit().
+ */
+ (void) Psysentry(P, SYS_exit, 1);
+ (void) Psysentry(P, SYS_exec, 1);
+ (void) Psysentry(P, SYS_execve, 1);
+ if (Psetrun(P, 0, PRSABORT) == -1) {
+ dprintf("Pcreate: Psetrun failed: %s\n", strerror(errno));
+ rc = C_STRANGE;
+ goto bad;
+ }
+ (void) Pwait(P, 0);
+ if (P->state != PS_STOP) {
+ dprintf("Pcreate: Pwait failed: %s\n", strerror(errno));
+ rc = C_STRANGE;
+ goto bad;
+ }
+
+ /*
+ * Move the process through instances of failed exec()s
+ * to reach the point of stopped on successful exec().
+ */
+ (void) Psysexit(P, SYS_exec, TRUE);
+ (void) Psysexit(P, SYS_execve, TRUE);
+
+ while (P->state == PS_STOP &&
+ P->status.pr_lwp.pr_why == PR_SYSENTRY &&
+ (P->status.pr_lwp.pr_what == SYS_execve ||
+ P->status.pr_lwp.pr_what == SYS_exec)) {
+ /*
+ * Fetch the exec path name now, before we complete
+ * the exec(). We may lose the process and be unable
+ * to get the information later.
+ */
+ (void) Pread_string(P, execpath, sizeof (execpath),
+ (off_t)P->status.pr_lwp.pr_sysarg[0]);
+ if (path != NULL)
+ (void) strncpy(path, execpath, len);
+ /*
+ * Set the process running and wait for
+ * it to stop on exit from the exec().
+ */
+ (void) Psetrun(P, 0, 0);
+ (void) Pwait(P, 0);
+
+ if (P->state == PS_LOST && /* we lost control */
+ Preopen(P) != 0) { /* and we can't get it back */
+ rc = C_PERM;
+ goto bad;
+ }
+
+ /*
+ * If the exec() failed, continue the loop, expecting
+ * there to be more attempts to exec(), based on PATH.
+ */
+ if (P->state == PS_STOP &&
+ P->status.pr_lwp.pr_why == PR_SYSEXIT &&
+ (P->status.pr_lwp.pr_what == SYS_execve ||
+ P->status.pr_lwp.pr_what == SYS_exec) &&
+ (lasterrno = P->status.pr_lwp.pr_errno) != 0) {
+ /*
+ * The exec() failed. Set the process running and
+ * wait for it to stop on entry to the next exec().
+ */
+ (void) Psetrun(P, 0, 0);
+ (void) Pwait(P, 0);
+
+ continue;
+ }
+ break;
+ }
+
+ if (P->state == PS_STOP &&
+ P->status.pr_lwp.pr_why == PR_SYSEXIT &&
+ (P->status.pr_lwp.pr_what == SYS_execve ||
+ P->status.pr_lwp.pr_what == SYS_exec) &&
+ P->status.pr_lwp.pr_errno == 0) {
+ /*
+ * The process is stopped on successful exec() or execve().
+ * Turn off all tracing flags and return success.
+ */
+ restore_tracing_flags(P);
+#ifndef _LP64
+ /* We must be a 64-bit process to deal with a 64-bit process */
+ if (P->status.pr_dmodel == PR_MODEL_LP64) {
+ rc = C_LP64;
+ goto bad;
+ }
+#endif
+ /*
+ * Set run-on-last-close so the controlled process
+ * runs even if we die on a signal.
+ */
+ (void) Psetflags(P, PR_RLC);
+ *perr = 0;
+ return (P);
+ }
+
+ rc = lasterrno == ENOENT ? C_NOENT : C_NOEXEC;
+
+bad:
+ (void) kill(pid, SIGKILL);
+ if (path != NULL && rc != C_PERM && rc != C_LP64)
+ *path = '\0';
+ Pfree(P);
+ *perr = rc;
+ return (NULL);
+}
+
+struct ps_prochandle *
+Pcreate(
+ const char *file, /* executable file name */
+ char *const *argv, /* argument vector */
+ int *perr, /* pointer to error return code */
+ char *path, /* if non-null, holds exec path name on return */
+ size_t len) /* size of the path buffer */
+{
+ return (Pxcreate(file, argv, NULL, perr, path, len));
+}
+
+/*
+ * Return a printable string corresponding to a Pcreate() error return.
+ */
+const char *
+Pcreate_error(int error)
+{
+ const char *str;
+
+ switch (error) {
+ case C_FORK:
+ str = "cannot fork";
+ break;
+ case C_PERM:
+ str = "file is set-id or unreadable";
+ break;
+ case C_NOEXEC:
+ str = "cannot execute file";
+ break;
+ case C_INTR:
+ str = "operation interrupted";
+ break;
+ case C_LP64:
+ str = "program is _LP64, self is not";
+ break;
+ case C_STRANGE:
+ str = "unanticipated system error";
+ break;
+ case C_NOENT:
+ str = "cannot find executable file";
+ break;
+ default:
+ str = "unknown error";
+ break;
+ }
+
+ return (str);
+}
+
+/*
+ * Callback to execute in each child process created with Pcreate() after fork
+ * but before it execs the new process image. By default, we do nothing, but
+ * by calling this function we allow the client program to define its own
+ * version of the function which will interpose on our empty default. This
+ * may be useful for clients that need to modify signal dispositions, terminal
+ * attributes, or process group and session properties for each new victim.
+ */
+/*ARGSUSED*/
+void
+Pcreate_callback(struct ps_prochandle *P)
+{
+ /* nothing to do here */
+}
+
+/*
+ * Grab an existing process.
+ * Return an opaque pointer to its process control structure.
+ *
+ * pid: UNIX process ID.
+ * flags:
+ * PGRAB_RETAIN Retain tracing flags (default clears all tracing flags).
+ * PGRAB_FORCE Grab regardless of whether process is already traced.
+ * PGRAB_RDONLY Open the address space file O_RDONLY instead of O_RDWR,
+ * and do not open the process control file.
+ * PGRAB_NOSTOP Open the process but do not force it to stop.
+ * perr: pointer to error return code.
+ */
+struct ps_prochandle *
+Pgrab(pid_t pid, int flags, int *perr)
+{
+ struct ps_prochandle *P;
+ int fd, omode;
+ char procname[100];
+ char *fname;
+ int rc = 0;
+
+ /*
+ * PGRAB_RDONLY means that we do not open the /proc/<pid>/control file,
+ * and so it implies RETAIN and NOSTOP since both require control.
+ */
+ if (flags & PGRAB_RDONLY)
+ flags |= PGRAB_RETAIN | PGRAB_NOSTOP;
+
+ if ((P = malloc(sizeof (struct ps_prochandle))) == NULL) {
+ *perr = G_STRANGE;
+ return (NULL);
+ }
+
+ P->asfd = -1;
+ P->ctlfd = -1;
+ P->statfd = -1;
+
+again: /* Come back here if we lose it in the Window of Vulnerability */
+ if (P->ctlfd >= 0)
+ (void) close(P->ctlfd);
+ if (P->asfd >= 0)
+ (void) close(P->asfd);
+ if (P->statfd >= 0)
+ (void) close(P->statfd);
+ (void) memset(P, 0, sizeof (*P));
+ (void) mutex_init(&P->proc_lock, USYNC_THREAD, NULL);
+ 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
+ */
+ (void) sprintf(procname, "/proc/%d/", (int)pid);
+ fname = procname + strlen(procname);
+ (void) set_minfd();
+
+ /*
+ * Request exclusive open to avoid grabbing someone else's
+ * process and to prevent others from interfering afterwards.
+ * If this fails and the 'PGRAB_FORCE' flag is set, attempt to
+ * open non-exclusively.
+ */
+ (void) strcpy(fname, "as");
+ omode = (flags & PGRAB_RDONLY) ? O_RDONLY : O_RDWR;
+
+ if (((fd = open(procname, omode | O_EXCL)) < 0 &&
+ (fd = ((flags & PGRAB_FORCE)? open(procname, omode) : -1)) < 0) ||
+ (fd = dupfd(fd, 0)) < 0) {
+ switch (errno) {
+ case ENOENT:
+ rc = G_NOPROC;
+ break;
+ case EACCES:
+ case EPERM:
+ rc = G_PERM;
+ break;
+ case EBUSY:
+ if (!(flags & PGRAB_FORCE) || geteuid() != 0) {
+ rc = G_BUSY;
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ dprintf("Pgrab: failed to open %s: %s\n",
+ procname, strerror(errno));
+ rc = G_STRANGE;
+ break;
+ }
+ goto err;
+ }
+ P->asfd = fd;
+
+ (void) strcpy(fname, "status");
+ if ((fd = open(procname, O_RDONLY)) < 0 ||
+ (fd = dupfd(fd, 0)) < 0) {
+ switch (errno) {
+ case ENOENT:
+ rc = G_NOPROC;
+ break;
+ default:
+ dprintf("Pgrab: failed to open %s: %s\n",
+ procname, strerror(errno));
+ rc = G_STRANGE;
+ break;
+ }
+ goto err;
+ }
+ P->statfd = fd;
+
+ if (!(flags & PGRAB_RDONLY)) {
+ (void) strcpy(fname, "ctl");
+ if ((fd = open(procname, O_WRONLY)) < 0 ||
+ (fd = dupfd(fd, 0)) < 0) {
+ switch (errno) {
+ case ENOENT:
+ rc = G_NOPROC;
+ break;
+ default:
+ dprintf("Pgrab: failed to open %s: %s\n",
+ procname, strerror(errno));
+ rc = G_STRANGE;
+ break;
+ }
+ goto err;
+ }
+ P->ctlfd = fd;
+ }
+
+ P->state = PS_RUN;
+ P->pid = pid;
+
+ /*
+ * We are now in the Window of Vulnerability (WoV). The process may
+ * exec() a setuid/setgid or unreadable object file between the open()
+ * and the PCSTOP. We will get EAGAIN in this case and must start over.
+ * As Pstopstatus will trigger the first read() from a /proc file,
+ * we also need to handle EOVERFLOW here when 32-bit as an indicator
+ * that this process is 64-bit. Finally, if the process has become
+ * a zombie (PS_UNDEAD) while we were trying to grab it, just remain
+ * silent about this and pretend there was no process.
+ */
+ if (Pstopstatus(P, PCNULL, 0) != 0) {
+#ifndef _LP64
+ if (errno == EOVERFLOW) {
+ rc = G_LP64;
+ goto err;
+ }
+#endif
+ if (P->state == PS_LOST) { /* WoV */
+ (void) mutex_destroy(&P->proc_lock);
+ goto again;
+ }
+
+ if (P->state == PS_UNDEAD)
+ rc = G_NOPROC;
+ else
+ rc = G_STRANGE;
+
+ goto err;
+ }
+
+ /*
+ * If the process is a system process, we can't control it even as root
+ */
+ if (P->status.pr_flags & PR_ISSYS) {
+ rc = G_SYS;
+ goto err;
+ }
+#ifndef _LP64
+ /*
+ * We must be a 64-bit process to deal with a 64-bit process
+ */
+ if (P->status.pr_dmodel == PR_MODEL_LP64) {
+ rc = G_LP64;
+ goto err;
+ }
+#endif
+
+ /*
+ * Remember the status for use by Prelease().
+ */
+ P->orig_status = P->status; /* structure copy */
+
+ /*
+ * Before stopping the process, make sure we are not grabbing ourselves.
+ * If we are, make sure we are doing it PGRAB_RDONLY.
+ */
+ if (pid == getpid()) {
+ /*
+ * Verify that the process is really ourself:
+ * Set a magic number, read it through the
+ * /proc file and see if the results match.
+ */
+ uint32_t magic1 = 0;
+ uint32_t magic2 = 2;
+
+ errno = 0;
+
+ if (Pread(P, &magic2, sizeof (magic2), (uintptr_t)&magic1)
+ == sizeof (magic2) &&
+ magic2 == 0 &&
+ (magic1 = 0xfeedbeef) &&
+ Pread(P, &magic2, sizeof (magic2), (uintptr_t)&magic1)
+ == sizeof (magic2) &&
+ magic2 == 0xfeedbeef &&
+ !(flags & PGRAB_RDONLY)) {
+ rc = G_SELF;
+ goto err;
+ }
+ }
+
+ /*
+ * If the process is already stopped or has been directed
+ * to stop via /proc, do not set run-on-last-close.
+ */
+ if (!(P->status.pr_lwp.pr_flags & (PR_ISTOP|PR_DSTOP)) &&
+ !(flags & PGRAB_RDONLY)) {
+ /*
+ * Mark the process run-on-last-close so
+ * it runs even if we die from SIGKILL.
+ */
+ if (Psetflags(P, PR_RLC) != 0) {
+ if (errno == EAGAIN) { /* WoV */
+ (void) mutex_destroy(&P->proc_lock);
+ goto again;
+ }
+ if (errno == ENOENT) /* No complaint about zombies */
+ rc = G_ZOMB;
+ else {
+ dprintf("Pgrab: failed to set RLC\n");
+ rc = G_STRANGE;
+ }
+ goto err;
+ }
+ }
+
+ /*
+ * If a stop directive is pending and the process has not yet stopped,
+ * then synchronously wait for the stop directive to take effect.
+ * Limit the time spent waiting for the process to stop by iterating
+ * at most 10 times. The time-out of 20 ms corresponds to the time
+ * between sending the stop directive and the process actually stopped
+ * as measured by DTrace on a slow, busy system. If the process doesn't
+ * stop voluntarily, clear the PR_DSTOP flag so that the code below
+ * forces the process to stop.
+ */
+ if (!(flags & PGRAB_RDONLY)) {
+ int niter = 0;
+ while ((P->status.pr_lwp.pr_flags & (PR_STOPPED|PR_DSTOP)) ==
+ PR_DSTOP && niter < 10 &&
+ Pstopstatus(P, PCTWSTOP, 20) != 0) {
+ niter++;
+ if (flags & PGRAB_NOSTOP)
+ break;
+ }
+ if (niter == 10 && !(flags & PGRAB_NOSTOP)) {
+ /* Try it harder down below */
+ P->status.pr_lwp.pr_flags &= ~PR_DSTOP;
+ }
+ }
+
+ /*
+ * If the process is not already stopped or directed to stop
+ * and PGRAB_NOSTOP was not specified, stop the process now.
+ */
+ if (!(P->status.pr_lwp.pr_flags & (PR_ISTOP|PR_DSTOP)) &&
+ !(flags & PGRAB_NOSTOP)) {
+ /*
+ * Stop the process, get its status and signal/syscall masks.
+ */
+ if (((P->status.pr_lwp.pr_flags & PR_STOPPED) &&
+ Pstopstatus(P, PCDSTOP, 0) != 0) ||
+ Pstopstatus(P, PCSTOP, 2000) != 0) {
+#ifndef _LP64
+ if (errno == EOVERFLOW) {
+ rc = G_LP64;
+ goto err;
+ }
+#endif
+ if (P->state == PS_LOST) { /* WoV */
+ (void) mutex_destroy(&P->proc_lock);
+ goto again;
+ }
+ if ((errno != EINTR && errno != ERESTART) ||
+ (P->state != PS_STOP &&
+ !(P->status.pr_flags & PR_DSTOP))) {
+ if (P->state != PS_RUN && errno != ENOENT) {
+ dprintf("Pgrab: failed to PCSTOP\n");
+ rc = G_STRANGE;
+ } else {
+ rc = G_ZOMB;
+ }
+ goto err;
+ }
+ }
+
+ /*
+ * Process should now either be stopped via /proc or there
+ * should be an outstanding stop directive.
+ */
+ if (!(P->status.pr_flags & (PR_ISTOP|PR_DSTOP))) {
+ dprintf("Pgrab: process is not stopped\n");
+ rc = G_STRANGE;
+ goto err;
+ }
+#ifndef _LP64
+ /*
+ * Test this again now because the 32-bit victim process may
+ * have exec'd a 64-bit process in the meantime.
+ */
+ if (P->status.pr_dmodel == PR_MODEL_LP64) {
+ rc = G_LP64;
+ goto err;
+ }
+#endif
+ }
+
+ /*
+ * Cancel all tracing flags unless the PGRAB_RETAIN flag is set.
+ */
+ if (!(flags & PGRAB_RETAIN)) {
+ (void) Psysentry(P, 0, FALSE);
+ (void) Psysexit(P, 0, FALSE);
+ (void) Psignal(P, 0, FALSE);
+ (void) Pfault(P, 0, FALSE);
+ Psync(P);
+ }
+
+ *perr = 0;
+ return (P);
+
+err:
+ Pfree(P);
+ *perr = rc;
+ return (NULL);
+}
+
+/*
+ * Return a printable string corresponding to a Pgrab() error return.
+ */
+const char *
+Pgrab_error(int error)
+{
+ const char *str;
+
+ switch (error) {
+ case G_NOPROC:
+ str = "no such process";
+ break;
+ case G_NOCORE:
+ str = "no such core file";
+ break;
+ case G_NOPROCORCORE:
+ str = "no such process or core file";
+ break;
+ case G_NOEXEC:
+ str = "cannot find executable file";
+ break;
+ case G_ZOMB:
+ str = "zombie process";
+ break;
+ case G_PERM:
+ str = "permission denied";
+ break;
+ case G_BUSY:
+ str = "process is traced";
+ break;
+ case G_SYS:
+ str = "system process";
+ break;
+ case G_SELF:
+ str = "attempt to grab self";
+ break;
+ case G_INTR:
+ str = "operation interrupted";
+ break;
+ case G_LP64:
+ str = "program is _LP64, self is not";
+ break;
+ case G_FORMAT:
+ str = "file is not an ELF core file";
+ break;
+ case G_ELF:
+ str = "libelf error";
+ break;
+ case G_NOTE:
+ str = "core file is corrupt or missing required data";
+ break;
+ case G_STRANGE:
+ str = "unanticipated system error";
+ break;
+ case G_ISAINVAL:
+ str = "wrong ELF machine type";
+ break;
+ case G_BADLWPS:
+ str = "bad lwp specification";
+ break;
+ default:
+ str = "unknown error";
+ break;
+ }
+
+ return (str);
+}
+
+/*
+ * Free a process control structure.
+ * Close the file descriptors but don't do the Prelease logic.
+ */
+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;
+ }
+
+ (void) mutex_lock(&P->proc_lock);
+ if (P->hashtab != NULL) {
+ struct ps_lwphandle *L;
+ for (i = 0; i < HASHSIZE; i++) {
+ while ((L = P->hashtab[i]) != NULL)
+ Lfree_internal(P, L);
+ }
+ free(P->hashtab);
+ }
+ (void) mutex_unlock(&P->proc_lock);
+ (void) mutex_destroy(&P->proc_lock);
+
+ if (P->agentctlfd >= 0)
+ (void) close(P->agentctlfd);
+ if (P->agentstatfd >= 0)
+ (void) close(P->agentstatfd);
+ if (P->ctlfd >= 0)
+ (void) close(P->ctlfd);
+ if (P->asfd >= 0)
+ (void) close(P->asfd);
+ if (P->statfd >= 0)
+ (void) close(P->statfd);
+ Preset_maps(P);
+
+ /* clear out the structure as a precaution against reuse */
+ (void) memset(P, 0, sizeof (*P));
+ P->ctlfd = -1;
+ P->asfd = -1;
+ P->statfd = -1;
+ P->agentctlfd = -1;
+ P->agentstatfd = -1;
+
+ free(P);
+}
+
+/*
+ * Return the state of the process, one of the PS_* values.
+ */
+int
+Pstate(struct ps_prochandle *P)
+{
+ return (P->state);
+}
+
+/*
+ * Return the open address space file descriptor for the process.
+ * Clients must not close this file descriptor, not use it
+ * after the process is freed.
+ */
+int
+Pasfd(struct ps_prochandle *P)
+{
+ return (P->asfd);
+}
+
+/*
+ * Return the open control file descriptor for the process.
+ * Clients must not close this file descriptor, not use it
+ * after the process is freed.
+ */
+int
+Pctlfd(struct ps_prochandle *P)
+{
+ return (P->ctlfd);
+}
+
+/*
+ * Return a pointer to the process psinfo structure.
+ * Clients should not hold on to this pointer indefinitely.
+ * 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.
+ * It will become invalid on Prelease().
+ */
+const pstatus_t *
+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.
+ * 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)
+{
+ int rc;
+ long *ctl;
+ size_t sz;
+
+ if (P->state == PS_DEAD) {
+ errno = EBADF;
+ return (-1);
+ }
+
+ sz = PRIV_PRPRIV_SIZE(pprv) + sizeof (long);
+
+ sz = ((sz - 1) / sizeof (long) + 1) * sizeof (long);
+
+ ctl = malloc(sz);
+ if (ctl == NULL)
+ return (-1);
+
+ ctl[0] = PCSPRIV;
+
+ (void) memcpy(&ctl[1], pprv, PRIV_PRPRIV_SIZE(pprv));
+
+ if (write(P->ctlfd, ctl, sz) != sz)
+ rc = -1;
+ else
+ rc = 0;
+
+ free(ctl);
+
+ return (rc);
+}
+
+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
+ * and the process's tracing flags.
+ */
+void
+Psync(struct ps_prochandle *P)
+{
+ int ctlfd = (P->agentctlfd >= 0)? P->agentctlfd : P->ctlfd;
+ long cmd[6];
+ iovec_t iov[12];
+ int n = 0;
+
+ if (P->flags & SETHOLD) {
+ cmd[0] = PCSHOLD;
+ iov[n].iov_base = (caddr_t)&cmd[0];
+ iov[n++].iov_len = sizeof (long);
+ iov[n].iov_base = (caddr_t)&P->status.pr_lwp.pr_lwphold;
+ iov[n++].iov_len = sizeof (P->status.pr_lwp.pr_lwphold);
+ }
+ if (P->flags & SETREGS) {
+ cmd[1] = PCSREG;
+#ifdef __i386
+ /* XX64 we should probably restore REG_GS after this */
+ if (ctlfd == P->agentctlfd)
+ P->status.pr_lwp.pr_reg[GS] = 0;
+#elif defined(__amd64)
+ /* XX64 */
+#endif
+ iov[n].iov_base = (caddr_t)&cmd[1];
+ iov[n++].iov_len = sizeof (long);
+ iov[n].iov_base = (caddr_t)&P->status.pr_lwp.pr_reg[0];
+ iov[n++].iov_len = sizeof (P->status.pr_lwp.pr_reg);
+ }
+ if (P->flags & SETSIG) {
+ cmd[2] = PCSTRACE;
+ iov[n].iov_base = (caddr_t)&cmd[2];
+ iov[n++].iov_len = sizeof (long);
+ iov[n].iov_base = (caddr_t)&P->status.pr_sigtrace;
+ iov[n++].iov_len = sizeof (P->status.pr_sigtrace);
+ }
+ if (P->flags & SETFAULT) {
+ cmd[3] = PCSFAULT;
+ iov[n].iov_base = (caddr_t)&cmd[3];
+ iov[n++].iov_len = sizeof (long);
+ iov[n].iov_base = (caddr_t)&P->status.pr_flttrace;
+ iov[n++].iov_len = sizeof (P->status.pr_flttrace);
+ }
+ if (P->flags & SETENTRY) {
+ cmd[4] = PCSENTRY;
+ iov[n].iov_base = (caddr_t)&cmd[4];
+ iov[n++].iov_len = sizeof (long);
+ iov[n].iov_base = (caddr_t)&P->status.pr_sysentry;
+ iov[n++].iov_len = sizeof (P->status.pr_sysentry);
+ }
+ if (P->flags & SETEXIT) {
+ cmd[5] = PCSEXIT;
+ iov[n].iov_base = (caddr_t)&cmd[5];
+ iov[n++].iov_len = sizeof (long);
+ iov[n].iov_base = (caddr_t)&P->status.pr_sysexit;
+ iov[n++].iov_len = sizeof (P->status.pr_sysexit);
+ }
+
+ if (n == 0 || writev(ctlfd, iov, n) < 0)
+ return; /* nothing to do or write failed */
+
+ P->flags &= ~(SETSIG|SETFAULT|SETENTRY|SETEXIT|SETHOLD|SETREGS);
+}
+
+/*
+ * Reopen the /proc file (after PS_LOST).
+ */
+int
+Preopen(struct ps_prochandle *P)
+{
+ int fd;
+ char procname[100];
+ char *fname;
+
+ if (P->state == PS_DEAD || P->state == PS_IDLE)
+ return (0);
+
+ if (P->agentcnt > 0) {
+ P->agentcnt = 1;
+ Pdestroy_agent(P);
+ }
+
+ (void) sprintf(procname, "/proc/%d/", (int)P->pid);
+ fname = procname + strlen(procname);
+
+ (void) strcpy(fname, "as");
+ if ((fd = open(procname, O_RDWR)) < 0 ||
+ close(P->asfd) < 0 ||
+ (fd = dupfd(fd, P->asfd)) != P->asfd) {
+ dprintf("Preopen: failed to open %s: %s\n",
+ procname, strerror(errno));
+ if (fd >= 0)
+ (void) close(fd);
+ return (-1);
+ }
+ P->asfd = fd;
+
+ (void) strcpy(fname, "status");
+ if ((fd = open(procname, O_RDONLY)) < 0 ||
+ close(P->statfd) < 0 ||
+ (fd = dupfd(fd, P->statfd)) != P->statfd) {
+ dprintf("Preopen: failed to open %s: %s\n",
+ procname, strerror(errno));
+ if (fd >= 0)
+ (void) close(fd);
+ return (-1);
+ }
+ P->statfd = fd;
+
+ (void) strcpy(fname, "ctl");
+ if ((fd = open(procname, O_WRONLY)) < 0 ||
+ close(P->ctlfd) < 0 ||
+ (fd = dupfd(fd, P->ctlfd)) != P->ctlfd) {
+ dprintf("Preopen: failed to open %s: %s\n",
+ procname, strerror(errno));
+ if (fd >= 0)
+ (void) close(fd);
+ return (-1);
+ }
+ P->ctlfd = fd;
+
+ /*
+ * Set the state to PS_RUN and wait for the process to stop so that
+ * we re-read the status from the new P->statfd. If this fails, Pwait
+ * will reset the state to PS_LOST and we fail the reopen. Before
+ * returning, we also forge a bit of P->status to allow the debugger to
+ * see that we are PS_LOST following a successful exec.
+ */
+ P->state = PS_RUN;
+ if (Pwait(P, 0) == -1) {
+#ifdef _ILP32
+ if (errno == EOVERFLOW)
+ P->status.pr_dmodel = PR_MODEL_LP64;
+#endif
+ P->status.pr_lwp.pr_why = PR_SYSEXIT;
+ P->status.pr_lwp.pr_what = SYS_execve;
+ P->status.pr_lwp.pr_errno = 0;
+ return (-1);
+ }
+
+ /*
+ * The process should be stopped on exec (REQUESTED)
+ * or else should be stopped on exit from exec() (SYSEXIT)
+ */
+ if (P->state == PS_STOP &&
+ (P->status.pr_lwp.pr_why == PR_REQUESTED ||
+ (P->status.pr_lwp.pr_why == PR_SYSEXIT &&
+ (P->status.pr_lwp.pr_what == SYS_exec ||
+ P->status.pr_lwp.pr_what == SYS_execve)))) {
+ /* fake up stop-on-exit-from-execve */
+ if (P->status.pr_lwp.pr_why == PR_REQUESTED) {
+ P->status.pr_lwp.pr_why = PR_SYSEXIT;
+ P->status.pr_lwp.pr_what = SYS_execve;
+ P->status.pr_lwp.pr_errno = 0;
+ }
+ } else {
+ dprintf("Preopen: expected REQUESTED or "
+ "SYSEXIT(SYS_execve) stop\n");
+ }
+
+ return (0);
+}
+
+/*
+ * Define all settable flags other than the microstate accounting flags.
+ */
+#define ALL_SETTABLE_FLAGS (PR_FORK|PR_RLC|PR_KLC|PR_ASYNC|PR_BPTADJ|PR_PTRACE)
+
+/*
+ * Restore /proc tracing flags to their original values
+ * in preparation for releasing the process.
+ * Also called by Pcreate() to clear all tracing flags.
+ */
+static void
+restore_tracing_flags(struct ps_prochandle *P)
+{
+ long flags;
+ long cmd[4];
+ iovec_t iov[8];
+
+ if (P->flags & CREATED) {
+ /* we created this process; clear all tracing flags */
+ premptyset(&P->status.pr_sigtrace);
+ premptyset(&P->status.pr_flttrace);
+ premptyset(&P->status.pr_sysentry);
+ premptyset(&P->status.pr_sysexit);
+ if ((P->status.pr_flags & ALL_SETTABLE_FLAGS) != 0)
+ (void) Punsetflags(P, ALL_SETTABLE_FLAGS);
+ } else {
+ /* we grabbed the process; restore its tracing flags */
+ P->status.pr_sigtrace = P->orig_status.pr_sigtrace;
+ P->status.pr_flttrace = P->orig_status.pr_flttrace;
+ P->status.pr_sysentry = P->orig_status.pr_sysentry;
+ P->status.pr_sysexit = P->orig_status.pr_sysexit;
+ if ((P->status.pr_flags & ALL_SETTABLE_FLAGS) !=
+ (flags = (P->orig_status.pr_flags & ALL_SETTABLE_FLAGS))) {
+ (void) Punsetflags(P, ALL_SETTABLE_FLAGS);
+ if (flags)
+ (void) Psetflags(P, flags);
+ }
+ }
+
+ cmd[0] = PCSTRACE;
+ iov[0].iov_base = (caddr_t)&cmd[0];
+ iov[0].iov_len = sizeof (long);
+ iov[1].iov_base = (caddr_t)&P->status.pr_sigtrace;
+ iov[1].iov_len = sizeof (P->status.pr_sigtrace);
+
+ cmd[1] = PCSFAULT;
+ iov[2].iov_base = (caddr_t)&cmd[1];
+ iov[2].iov_len = sizeof (long);
+ iov[3].iov_base = (caddr_t)&P->status.pr_flttrace;
+ iov[3].iov_len = sizeof (P->status.pr_flttrace);
+
+ cmd[2] = PCSENTRY;
+ iov[4].iov_base = (caddr_t)&cmd[2];
+ iov[4].iov_len = sizeof (long);
+ iov[5].iov_base = (caddr_t)&P->status.pr_sysentry;
+ iov[5].iov_len = sizeof (P->status.pr_sysentry);
+
+ cmd[3] = PCSEXIT;
+ iov[6].iov_base = (caddr_t)&cmd[3];
+ iov[6].iov_len = sizeof (long);
+ iov[7].iov_base = (caddr_t)&P->status.pr_sysexit;
+ iov[7].iov_len = sizeof (P->status.pr_sysexit);
+
+ (void) writev(P->ctlfd, iov, 8);
+
+ P->flags &= ~(SETSIG|SETFAULT|SETENTRY|SETEXIT);
+}
+
+/*
+ * Release the process. Frees the process control structure.
+ * flags:
+ * PRELEASE_CLEAR Clear all tracing flags.
+ * PRELEASE_RETAIN Retain current tracing flags.
+ * PRELEASE_HANG Leave the process stopped and abandoned.
+ * PRELEASE_KILL Terminate the process with SIGKILL.
+ */
+void
+Prelease(struct ps_prochandle *P, int flags)
+{
+ if (P->state == PS_DEAD) {
+ dprintf("Prelease: releasing handle %p PS_DEAD of pid %d\n",
+ (void *)P, (int)P->pid);
+ Pfree(P);
+ return;
+ }
+
+ if (P->state == PS_IDLE) {
+ file_info_t *fptr = list_next(&P->file_head);
+ dprintf("Prelease: releasing handle %p PS_IDLE of file %s\n",
+ (void *)P, fptr->file_pname);
+ Pfree(P);
+ return;
+ }
+
+ dprintf("Prelease: releasing handle %p pid %d\n",
+ (void *)P, (int)P->pid);
+
+ if (P->ctlfd == -1) {
+ Pfree(P);
+ return;
+ }
+
+ if (P->agentcnt > 0) {
+ P->agentcnt = 1;
+ Pdestroy_agent(P);
+ }
+
+ /*
+ * Attempt to stop the process.
+ */
+ P->state = PS_RUN;
+ (void) Pstop(P, 1000);
+
+ if (flags & PRELEASE_KILL) {
+ if (P->state == PS_STOP)
+ (void) Psetrun(P, SIGKILL, 0);
+ (void) kill(P->pid, SIGKILL);
+ Pfree(P);
+ return;
+ }
+
+ /*
+ * If we lost control, all we can do now is close the files.
+ * In this case, the last close sets the process running.
+ */
+ if (P->state != PS_STOP &&
+ (P->status.pr_lwp.pr_flags & (PR_ISTOP|PR_DSTOP)) == 0) {
+ Pfree(P);
+ return;
+ }
+
+ /*
+ * We didn't lose control; we do more.
+ */
+ Psync(P);
+
+ if (flags & PRELEASE_CLEAR)
+ P->flags |= CREATED;
+
+ if (!(flags & PRELEASE_RETAIN))
+ restore_tracing_flags(P);
+
+ if (flags & PRELEASE_HANG) {
+ /* Leave the process stopped and abandoned */
+ (void) Punsetflags(P, PR_RLC|PR_KLC);
+ Pfree(P);
+ return;
+ }
+
+ /*
+ * Set the process running if we created it or if it was
+ * not originally stopped or directed to stop via /proc
+ * or if we were given the PRELEASE_CLEAR flag.
+ */
+ if ((P->flags & CREATED) ||
+ (P->orig_status.pr_lwp.pr_flags & (PR_ISTOP|PR_DSTOP)) == 0) {
+ (void) Psetflags(P, PR_RLC);
+ /*
+ * We do this repeatedly because the process may have
+ * more than one LWP stopped on an event of interest.
+ * This makes sure all of them are set running.
+ */
+ do {
+ if (Psetrun(P, 0, 0) == -1 && errno == EBUSY)
+ break; /* Agent LWP may be stuck */
+ } while (Pstopstatus(P, PCNULL, 0) == 0 &&
+ P->status.pr_lwp.pr_flags & (PR_ISTOP|PR_DSTOP));
+
+ if (P->status.pr_lwp.pr_flags & (PR_ISTOP|PR_DSTOP))
+ dprintf("Prelease: failed to set process running\n");
+ }
+
+ Pfree(P);
+}
+
+/* debugging */
+void
+prldump(const char *caller, lwpstatus_t *lsp)
+{
+ char name[32];
+ uint32_t bits;
+
+ switch (lsp->pr_why) {
+ case PR_REQUESTED:
+ dprintf("%s: REQUESTED\n", caller);
+ break;
+ case PR_SIGNALLED:
+ dprintf("%s: SIGNALLED %s\n", caller,
+ proc_signame(lsp->pr_what, name, sizeof (name)));
+ break;
+ case PR_FAULTED:
+ dprintf("%s: FAULTED %s\n", caller,
+ proc_fltname(lsp->pr_what, name, sizeof (name)));
+ break;
+ case PR_SYSENTRY:
+ dprintf("%s: SYSENTRY %s\n", caller,
+ proc_sysname(lsp->pr_what, name, sizeof (name)));
+ break;
+ case PR_SYSEXIT:
+ dprintf("%s: SYSEXIT %s\n", caller,
+ proc_sysname(lsp->pr_what, name, sizeof (name)));
+ break;
+ case PR_JOBCONTROL:
+ dprintf("%s: JOBCONTROL %s\n", caller,
+ proc_signame(lsp->pr_what, name, sizeof (name)));
+ break;
+ case PR_SUSPENDED:
+ dprintf("%s: SUSPENDED\n", caller);
+ break;
+ default:
+ dprintf("%s: Unknown\n", caller);
+ break;
+ }
+
+ if (lsp->pr_cursig)
+ dprintf("%s: p_cursig = %d\n", caller, lsp->pr_cursig);
+
+ bits = *((uint32_t *)&lsp->pr_lwppend);
+ if (bits)
+ dprintf("%s: pr_lwppend = 0x%.8X\n", caller, bits);
+}
+
+/* debugging */
+static void
+prdump(struct ps_prochandle *P)
+{
+ uint32_t bits;
+
+ prldump("Pstopstatus", &P->status.pr_lwp);
+
+ bits = *((uint32_t *)&P->status.pr_sigpend);
+ if (bits)
+ dprintf("Pstopstatus: pr_sigpend = 0x%.8X\n", bits);
+}
+
+/*
+ * Wait for the specified process to stop or terminate.
+ * Or, just get the current status (PCNULL).
+ * Or, direct it to stop and get the current status (PCDSTOP).
+ * If the agent LWP exists, do these things to the agent,
+ * else do these things to the process as a whole.
+ */
+int
+Pstopstatus(struct ps_prochandle *P,
+ long request, /* PCNULL, PCDSTOP, PCSTOP, PCWSTOP */
+ uint_t msec) /* if non-zero, timeout in milliseconds */
+{
+ int ctlfd = (P->agentctlfd >= 0)? P->agentctlfd : P->ctlfd;
+ long ctl[3];
+ ssize_t rc;
+ int err;
+ int old_state = P->state;
+
+ switch (P->state) {
+ case PS_RUN:
+ break;
+ case PS_STOP:
+ if (request != PCNULL && request != PCDSTOP)
+ return (0);
+ break;
+ case PS_LOST:
+ if (request != PCNULL) {
+ errno = EAGAIN;
+ return (-1);
+ }
+ break;
+ case PS_UNDEAD:
+ case PS_DEAD:
+ case PS_IDLE:
+ if (request != PCNULL) {
+ errno = ENOENT;
+ return (-1);
+ }
+ break;
+ default: /* corrupted state */
+ dprintf("Pstopstatus: corrupted state: %d\n", P->state);
+ errno = EINVAL;
+ return (-1);
+ }
+
+ ctl[0] = PCDSTOP;
+ ctl[1] = PCTWSTOP;
+ ctl[2] = (long)msec;
+ rc = 0;
+ switch (request) {
+ case PCSTOP:
+ rc = write(ctlfd, &ctl[0], 3*sizeof (long));
+ break;
+ case PCWSTOP:
+ rc = write(ctlfd, &ctl[1], 2*sizeof (long));
+ break;
+ case PCDSTOP:
+ rc = write(ctlfd, &ctl[0], 1*sizeof (long));
+ break;
+ case PCNULL:
+ if (P->state == PS_DEAD || P->state == PS_IDLE)
+ return (0);
+ break;
+ default: /* programming error */
+ errno = EINVAL;
+ return (-1);
+ }
+ err = (rc < 0)? errno : 0;
+ Psync(P);
+
+ if (P->agentstatfd < 0) {
+ if (pread(P->statfd, &P->status,
+ sizeof (P->status), (off_t)0) < 0)
+ err = errno;
+ } else {
+ if (pread(P->agentstatfd, &P->status.pr_lwp,
+ sizeof (P->status.pr_lwp), (off_t)0) < 0)
+ err = errno;
+ P->status.pr_flags = P->status.pr_lwp.pr_flags;
+ }
+
+ if (err) {
+ switch (err) {
+ case EINTR: /* user typed ctl-C */
+ case ERESTART:
+ dprintf("Pstopstatus: EINTR\n");
+ break;
+ case EAGAIN: /* we lost control of the the process */
+ case EOVERFLOW:
+ dprintf("Pstopstatus: PS_LOST, errno=%d\n", err);
+ P->state = PS_LOST;
+ break;
+ default: /* check for dead process */
+ if (_libproc_debug) {
+ const char *errstr;
+
+ switch (request) {
+ case PCNULL:
+ errstr = "Pstopstatus PCNULL"; break;
+ case PCSTOP:
+ errstr = "Pstopstatus PCSTOP"; break;
+ case PCDSTOP:
+ errstr = "Pstopstatus PCDSTOP"; break;
+ case PCWSTOP:
+ errstr = "Pstopstatus PCWSTOP"; break;
+ default:
+ errstr = "Pstopstatus PC???"; break;
+ }
+ dprintf("%s: %s\n", errstr, strerror(err));
+ }
+ deadcheck(P);
+ break;
+ }
+ if (err != EINTR && err != ERESTART) {
+ errno = err;
+ return (-1);
+ }
+ }
+
+ if (!(P->status.pr_flags & PR_STOPPED)) {
+ P->state = PS_RUN;
+ if (request == PCNULL || request == PCDSTOP || msec != 0)
+ return (0);
+ dprintf("Pstopstatus: process is not stopped\n");
+ errno = EPROTO;
+ return (-1);
+ }
+
+ P->state = PS_STOP;
+
+ if (_libproc_debug) /* debugging */
+ prdump(P);
+
+ /*
+ * If the process was already stopped coming into Pstopstatus(),
+ * then don't use its PC to set P->sysaddr since it may have been
+ * changed since the time the process originally stopped.
+ */
+ if (old_state == PS_STOP)
+ return (0);
+
+ switch (P->status.pr_lwp.pr_why) {
+ case PR_SYSENTRY:
+ case PR_SYSEXIT:
+ if (Pissyscall_prev(P, P->status.pr_lwp.pr_reg[R_PC],
+ &P->sysaddr) == 0)
+ P->sysaddr = P->status.pr_lwp.pr_reg[R_PC];
+ break;
+ case PR_REQUESTED:
+ case PR_SIGNALLED:
+ case PR_FAULTED:
+ case PR_JOBCONTROL:
+ case PR_SUSPENDED:
+ break;
+ default:
+ errno = EPROTO;
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * Wait for the process to stop for any reason.
+ */
+int
+Pwait(struct ps_prochandle *P, uint_t msec)
+{
+ return (Pstopstatus(P, PCWSTOP, msec));
+}
+
+/*
+ * Direct the process to stop; wait for it to stop.
+ */
+int
+Pstop(struct ps_prochandle *P, uint_t msec)
+{
+ return (Pstopstatus(P, PCSTOP, msec));
+}
+
+/*
+ * Direct the process to stop; don't wait.
+ */
+int
+Pdstop(struct ps_prochandle *P)
+{
+ return (Pstopstatus(P, PCDSTOP, 0));
+}
+
+static void
+deadcheck(struct ps_prochandle *P)
+{
+ int fd;
+ void *buf;
+ size_t size;
+
+ if (P->statfd < 0)
+ P->state = PS_UNDEAD;
+ else {
+ if (P->agentstatfd < 0) {
+ fd = P->statfd;
+ buf = &P->status;
+ size = sizeof (P->status);
+ } else {
+ fd = P->agentstatfd;
+ buf = &P->status.pr_lwp;
+ size = sizeof (P->status.pr_lwp);
+ }
+ while (pread(fd, buf, size, (off_t)0) != size) {
+ switch (errno) {
+ default:
+ P->state = PS_UNDEAD;
+ break;
+ case EINTR:
+ case ERESTART:
+ continue;
+ case EAGAIN:
+ P->state = PS_LOST;
+ break;
+ }
+ break;
+ }
+ P->status.pr_flags = P->status.pr_lwp.pr_flags;
+ }
+}
+
+/*
+ * Get the value of one register from stopped process.
+ */
+int
+Pgetareg(struct ps_prochandle *P, int regno, prgreg_t *preg)
+{
+ if (regno < 0 || regno >= NPRGREG) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (P->state == PS_IDLE) {
+ errno = ENODATA;
+ return (-1);
+ }
+
+ if (P->state != PS_STOP && P->state != PS_DEAD) {
+ errno = EBUSY;
+ return (-1);
+ }
+
+ *preg = P->status.pr_lwp.pr_reg[regno];
+ return (0);
+}
+
+/*
+ * Put value of one register into stopped process.
+ */
+int
+Pputareg(struct ps_prochandle *P, int regno, prgreg_t reg)
+{
+ if (regno < 0 || regno >= NPRGREG) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (P->state != PS_STOP) {
+ errno = EBUSY;
+ return (-1);
+ }
+
+ P->status.pr_lwp.pr_reg[regno] = reg;
+ P->flags |= SETREGS; /* set registers before continuing */
+ return (0);
+}
+
+int
+Psetrun(struct ps_prochandle *P,
+ int sig, /* signal to pass to process */
+ int flags) /* PRSTEP|PRSABORT|PRSTOP|PRCSIG|PRCFAULT */
+{
+ int ctlfd = (P->agentctlfd >= 0) ? P->agentctlfd : P->ctlfd;
+ int sbits = (PR_DSTOP | PR_ISTOP | PR_ASLEEP);
+
+ long ctl[1 + /* PCCFAULT */
+ 1 + sizeof (siginfo_t)/sizeof (long) + /* PCSSIG/PCCSIG */
+ 2 ]; /* PCRUN */
+
+ long *ctlp = ctl;
+ size_t size;
+
+ if (P->state != PS_STOP && (P->status.pr_lwp.pr_flags & sbits) == 0) {
+ errno = EBUSY;
+ return (-1);
+ }
+
+ Psync(P); /* flush tracing flags and registers */
+
+ if (flags & PRCFAULT) { /* clear current fault */
+ *ctlp++ = PCCFAULT;
+ flags &= ~PRCFAULT;
+ }
+
+ if (flags & PRCSIG) { /* clear current signal */
+ *ctlp++ = PCCSIG;
+ flags &= ~PRCSIG;
+ } else if (sig && sig != P->status.pr_lwp.pr_cursig) {
+ /* make current signal */
+ siginfo_t *infop;
+
+ *ctlp++ = PCSSIG;
+ infop = (siginfo_t *)ctlp;
+ (void) memset(infop, 0, sizeof (*infop));
+ infop->si_signo = sig;
+ ctlp += sizeof (siginfo_t) / sizeof (long);
+ }
+
+ *ctlp++ = PCRUN;
+ *ctlp++ = flags;
+ size = (char *)ctlp - (char *)ctl;
+
+ P->info_valid = 0; /* will need to update map and file info */
+
+ /*
+ * If we've cached ucontext-list information while we were stopped,
+ * free it now.
+ */
+ if (P->ucaddrs != NULL) {
+ free(P->ucaddrs);
+ P->ucaddrs = NULL;
+ P->ucnelems = 0;
+ }
+
+ if (write(ctlfd, ctl, size) != size) {
+ /* If it is dead or lost, return the real status, not PS_RUN */
+ if (errno == ENOENT || errno == EAGAIN) {
+ (void) Pstopstatus(P, PCNULL, 0);
+ return (0);
+ }
+ /* If it is not in a jobcontrol stop, issue an error message */
+ if (errno != EBUSY ||
+ P->status.pr_lwp.pr_why != PR_JOBCONTROL) {
+ dprintf("Psetrun: %s\n", strerror(errno));
+ return (-1);
+ }
+ /* Otherwise pretend that the job-stopped process is running */
+ }
+
+ P->state = PS_RUN;
+ return (0);
+}
+
+ssize_t
+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 */
+ size_t size, /* upper limit on bytes to read */
+ uintptr_t addr) /* address in process */
+{
+ enum { STRSZ = 40 };
+ char string[STRSZ + 1];
+ ssize_t leng = 0;
+ int nbyte;
+
+ if (size < 2) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ size--; /* ensure trailing null fits in buffer */
+
+ *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)
+ nbyte = size - leng;
+ (void) strncpy(buf + leng, string, nbyte);
+ leng += nbyte;
+ }
+ }
+ buf[leng] = '\0';
+ return (leng);
+}
+
+ssize_t
+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)
+{
+ int ctlfd = (P->agentctlfd >= 0)? P->agentctlfd : P->ctlfd;
+ long ctl = PCCSIG;
+
+ if (write(ctlfd, &ctl, sizeof (ctl)) != sizeof (ctl))
+ return (-1);
+ P->status.pr_lwp.pr_cursig = 0;
+ return (0);
+}
+
+int
+Pclearfault(struct ps_prochandle *P)
+{
+ int ctlfd = (P->agentctlfd >= 0)? P->agentctlfd : P->ctlfd;
+ long ctl = PCCFAULT;
+
+ if (write(ctlfd, &ctl, sizeof (ctl)) != sizeof (ctl))
+ return (-1);
+ return (0);
+}
+
+/*
+ * Set a breakpoint trap, return original instruction.
+ */
+int
+Psetbkpt(struct ps_prochandle *P, uintptr_t address, ulong_t *saved)
+{
+ long ctl[1 + sizeof (priovec_t) / sizeof (long) + /* PCREAD */
+ 1 + sizeof (priovec_t) / sizeof (long)]; /* PCWRITE */
+ long *ctlp = ctl;
+ size_t size;
+ priovec_t *iovp;
+ instr_t bpt = BPT;
+ instr_t old;
+
+ if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
+ P->state == PS_IDLE) {
+ errno = ENOENT;
+ return (-1);
+ }
+
+ /* fetch the old instruction */
+ *ctlp++ = PCREAD;
+ iovp = (priovec_t *)ctlp;
+ iovp->pio_base = &old;
+ iovp->pio_len = sizeof (old);
+ iovp->pio_offset = address;
+ ctlp += sizeof (priovec_t) / sizeof (long);
+
+ /* write the BPT instruction */
+ *ctlp++ = PCWRITE;
+ iovp = (priovec_t *)ctlp;
+ iovp->pio_base = &bpt;
+ iovp->pio_len = sizeof (bpt);
+ iovp->pio_offset = address;
+ ctlp += sizeof (priovec_t) / sizeof (long);
+
+ size = (char *)ctlp - (char *)ctl;
+ if (write(P->ctlfd, ctl, size) != size)
+ return (-1);
+
+ /*
+ * Fail if there was already a breakpoint there from another debugger
+ * or DTrace's user-level tracing on x86.
+ */
+ if (old == BPT)
+ return (EBUSY);
+
+ *saved = (ulong_t)old;
+ return (0);
+}
+
+/*
+ * Restore original instruction where a breakpoint was set.
+ */
+int
+Pdelbkpt(struct ps_prochandle *P, uintptr_t address, ulong_t saved)
+{
+ instr_t old = (instr_t)saved;
+ instr_t cur;
+
+ if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
+ P->state == PS_IDLE) {
+ errno = ENOENT;
+ return (-1);
+ }
+
+ /*
+ * If the breakpoint instruction we had placed has been overwritten
+ * with a new instruction, then don't try to replace it with the
+ * old instruction. Doing do can cause problems with self-modifying
+ * code -- PLTs for example. If the Pread() fails, we assume that we
+ * should proceed though most likely the Pwrite() will also fail.
+ */
+ if (Pread(P, &cur, sizeof (cur), address) == sizeof (cur) &&
+ cur != BPT)
+ return (0);
+
+ if (Pwrite(P, &old, sizeof (old), address) != sizeof (old))
+ return (-1);
+
+ return (0);
+}
+
+/*
+ * Common code for Pxecbkpt() and Lxecbkpt().
+ * Develop the array of requests that will do the job, then
+ * write them to the specified control file descriptor.
+ * Return the non-zero errno if the write fails.
+ */
+static int
+execute_bkpt(
+ int ctlfd, /* process or LWP control file descriptor */
+ const fltset_t *faultset, /* current set of traced faults */
+ const sigset_t *sigmask, /* current signal mask */
+ uintptr_t address, /* address of breakpint */
+ ulong_t saved) /* the saved instruction */
+{
+ long ctl[
+ 1 + sizeof (sigset_t) / sizeof (long) + /* PCSHOLD */
+ 1 + sizeof (fltset_t) / sizeof (long) + /* PCSFAULT */
+ 1 + sizeof (priovec_t) / sizeof (long) + /* PCWRITE */
+ 2 + /* PCRUN */
+ 1 + /* PCWSTOP */
+ 1 + /* PCCFAULT */
+ 1 + sizeof (priovec_t) / sizeof (long) + /* PCWRITE */
+ 1 + sizeof (fltset_t) / sizeof (long) + /* PCSFAULT */
+ 1 + sizeof (sigset_t) / sizeof (long)]; /* PCSHOLD */
+ long *ctlp = ctl;
+ sigset_t unblock;
+ size_t size;
+ ssize_t ssize;
+ priovec_t *iovp;
+ sigset_t *holdp;
+ fltset_t *faultp;
+ instr_t old = (instr_t)saved;
+ instr_t bpt = BPT;
+ int error = 0;
+
+ /* block our signals for the duration */
+ (void) sigprocmask(SIG_BLOCK, &blockable_sigs, &unblock);
+
+ /* hold posted signals */
+ *ctlp++ = PCSHOLD;
+ holdp = (sigset_t *)ctlp;
+ prfillset(holdp);
+ prdelset(holdp, SIGKILL);
+ prdelset(holdp, SIGSTOP);
+ ctlp += sizeof (sigset_t) / sizeof (long);
+
+ /* force tracing of FLTTRACE */
+ if (!(prismember(faultset, FLTTRACE))) {
+ *ctlp++ = PCSFAULT;
+ faultp = (fltset_t *)ctlp;
+ *faultp = *faultset;
+ praddset(faultp, FLTTRACE);
+ ctlp += sizeof (fltset_t) / sizeof (long);
+ }
+
+ /* restore the old instruction */
+ *ctlp++ = PCWRITE;
+ iovp = (priovec_t *)ctlp;
+ iovp->pio_base = &old;
+ iovp->pio_len = sizeof (old);
+ iovp->pio_offset = address;
+ ctlp += sizeof (priovec_t) / sizeof (long);
+
+ /* clear current signal and fault; set running w/ single-step */
+ *ctlp++ = PCRUN;
+ *ctlp++ = PRCSIG | PRCFAULT | PRSTEP;
+
+ /* wait for stop, cancel the fault */
+ *ctlp++ = PCWSTOP;
+ *ctlp++ = PCCFAULT;
+
+ /* restore the breakpoint trap */
+ *ctlp++ = PCWRITE;
+ iovp = (priovec_t *)ctlp;
+ iovp->pio_base = &bpt;
+ iovp->pio_len = sizeof (bpt);
+ iovp->pio_offset = address;
+ ctlp += sizeof (priovec_t) / sizeof (long);
+
+ /* restore fault tracing set */
+ if (!(prismember(faultset, FLTTRACE))) {
+ *ctlp++ = PCSFAULT;
+ *(fltset_t *)ctlp = *faultset;
+ ctlp += sizeof (fltset_t) / sizeof (long);
+ }
+
+ /* restore the hold mask */
+ *ctlp++ = PCSHOLD;
+ *(sigset_t *)ctlp = *sigmask;
+ ctlp += sizeof (sigset_t) / sizeof (long);
+
+ size = (char *)ctlp - (char *)ctl;
+ if ((ssize = write(ctlfd, ctl, size)) != size)
+ error = (ssize == -1)? errno : EINTR;
+ (void) sigprocmask(SIG_SETMASK, &unblock, NULL);
+ return (error);
+}
+
+/*
+ * Step over a breakpoint, i.e., execute the instruction that
+ * really belongs at the breakpoint location (the current %pc)
+ * and leave the process stopped at the next instruction.
+ */
+int
+Pxecbkpt(struct ps_prochandle *P, ulong_t saved)
+{
+ int ctlfd = (P->agentctlfd >= 0)? P->agentctlfd : P->ctlfd;
+ int rv, error;
+
+ if (P->state != PS_STOP) {
+ errno = EBUSY;
+ return (-1);
+ }
+
+ Psync(P);
+
+ error = execute_bkpt(ctlfd,
+ &P->status.pr_flttrace, &P->status.pr_lwp.pr_lwphold,
+ P->status.pr_lwp.pr_reg[R_PC], saved);
+ rv = Pstopstatus(P, PCNULL, 0);
+
+ if (error != 0) {
+ if (P->status.pr_lwp.pr_why == PR_JOBCONTROL &&
+ error == EBUSY) { /* jobcontrol stop -- back off */
+ P->state = PS_RUN;
+ return (0);
+ }
+ if (error == ENOENT)
+ return (0);
+ errno = error;
+ return (-1);
+ }
+
+ return (rv);
+}
+
+/*
+ * Install the watchpoint described by wp.
+ */
+int
+Psetwapt(struct ps_prochandle *P, const prwatch_t *wp)
+{
+ long ctl[1 + sizeof (prwatch_t) / sizeof (long)];
+ prwatch_t *cwp = (prwatch_t *)&ctl[1];
+
+ if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
+ P->state == PS_IDLE) {
+ errno = ENOENT;
+ return (-1);
+ }
+
+ ctl[0] = PCWATCH;
+ cwp->pr_vaddr = wp->pr_vaddr;
+ cwp->pr_size = wp->pr_size;
+ cwp->pr_wflags = wp->pr_wflags;
+
+ if (write(P->ctlfd, ctl, sizeof (ctl)) != sizeof (ctl))
+ return (-1);
+
+ return (0);
+}
+
+/*
+ * Remove the watchpoint described by wp.
+ */
+int
+Pdelwapt(struct ps_prochandle *P, const prwatch_t *wp)
+{
+ long ctl[1 + sizeof (prwatch_t) / sizeof (long)];
+ prwatch_t *cwp = (prwatch_t *)&ctl[1];
+
+ if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
+ P->state == PS_IDLE) {
+ errno = ENOENT;
+ return (-1);
+ }
+
+ ctl[0] = PCWATCH;
+ cwp->pr_vaddr = wp->pr_vaddr;
+ cwp->pr_size = wp->pr_size;
+ cwp->pr_wflags = 0;
+
+ if (write(P->ctlfd, ctl, sizeof (ctl)) != sizeof (ctl))
+ return (-1);
+
+ return (0);
+}
+
+/*
+ * Common code for Pxecwapt() and Lxecwapt(). Develop the array of requests
+ * that will do the job, then write them to the specified control file
+ * descriptor. Return the non-zero errno if the write fails.
+ */
+static int
+execute_wapt(
+ int ctlfd, /* process or LWP control file descriptor */
+ const fltset_t *faultset, /* current set of traced faults */
+ const sigset_t *sigmask, /* current signal mask */
+ const prwatch_t *wp) /* watchpoint descriptor */
+{
+ long ctl[
+ 1 + sizeof (sigset_t) / sizeof (long) + /* PCSHOLD */
+ 1 + sizeof (fltset_t) / sizeof (long) + /* PCSFAULT */
+ 1 + sizeof (prwatch_t) / sizeof (long) + /* PCWATCH */
+ 2 + /* PCRUN */
+ 1 + /* PCWSTOP */
+ 1 + /* PCCFAULT */
+ 1 + sizeof (prwatch_t) / sizeof (long) + /* PCWATCH */
+ 1 + sizeof (fltset_t) / sizeof (long) + /* PCSFAULT */
+ 1 + sizeof (sigset_t) / sizeof (long)]; /* PCSHOLD */
+
+ long *ctlp = ctl;
+ int error = 0;
+
+ sigset_t unblock;
+ sigset_t *holdp;
+ fltset_t *faultp;
+ prwatch_t *prw;
+ ssize_t ssize;
+ size_t size;
+
+ (void) sigprocmask(SIG_BLOCK, &blockable_sigs, &unblock);
+
+ /*
+ * Hold all posted signals in the victim process prior to stepping.
+ */
+ *ctlp++ = PCSHOLD;
+ holdp = (sigset_t *)ctlp;
+ prfillset(holdp);
+ prdelset(holdp, SIGKILL);
+ prdelset(holdp, SIGSTOP);
+ ctlp += sizeof (sigset_t) / sizeof (long);
+
+ /*
+ * Force tracing of FLTTRACE since we need to single step.
+ */
+ if (!(prismember(faultset, FLTTRACE))) {
+ *ctlp++ = PCSFAULT;
+ faultp = (fltset_t *)ctlp;
+ *faultp = *faultset;
+ praddset(faultp, FLTTRACE);
+ ctlp += sizeof (fltset_t) / sizeof (long);
+ }
+
+ /*
+ * Clear only the current watchpoint by setting pr_wflags to zero.
+ */
+ *ctlp++ = PCWATCH;
+ prw = (prwatch_t *)ctlp;
+ prw->pr_vaddr = wp->pr_vaddr;
+ prw->pr_size = wp->pr_size;
+ prw->pr_wflags = 0;
+ ctlp += sizeof (prwatch_t) / sizeof (long);
+
+ /*
+ * Clear the current signal and fault; set running with single-step.
+ * Then wait for the victim to stop and cancel the FLTTRACE.
+ */
+ *ctlp++ = PCRUN;
+ *ctlp++ = PRCSIG | PRCFAULT | PRSTEP;
+ *ctlp++ = PCWSTOP;
+ *ctlp++ = PCCFAULT;
+
+ /*
+ * Restore the current watchpoint.
+ */
+ *ctlp++ = PCWATCH;
+ (void) memcpy(ctlp, wp, sizeof (prwatch_t));
+ ctlp += sizeof (prwatch_t) / sizeof (long);
+
+ /*
+ * Restore fault tracing set if we modified it.
+ */
+ if (!(prismember(faultset, FLTTRACE))) {
+ *ctlp++ = PCSFAULT;
+ *(fltset_t *)ctlp = *faultset;
+ ctlp += sizeof (fltset_t) / sizeof (long);
+ }
+
+ /*
+ * Restore the hold mask to the current hold mask (i.e. the one
+ * before we executed any of the previous operations).
+ */
+ *ctlp++ = PCSHOLD;
+ *(sigset_t *)ctlp = *sigmask;
+ ctlp += sizeof (sigset_t) / sizeof (long);
+
+ size = (char *)ctlp - (char *)ctl;
+ if ((ssize = write(ctlfd, ctl, size)) != size)
+ error = (ssize == -1)? errno : EINTR;
+ (void) sigprocmask(SIG_SETMASK, &unblock, NULL);
+ return (error);
+}
+
+/*
+ * Step over a watchpoint, i.e., execute the instruction that was stopped by
+ * the watchpoint, and then leave the LWP stopped at the next instruction.
+ */
+int
+Pxecwapt(struct ps_prochandle *P, const prwatch_t *wp)
+{
+ int ctlfd = (P->agentctlfd >= 0)? P->agentctlfd : P->ctlfd;
+ int rv, error;
+
+ if (P->state != PS_STOP) {
+ errno = EBUSY;
+ return (-1);
+ }
+
+ Psync(P);
+ error = execute_wapt(ctlfd,
+ &P->status.pr_flttrace, &P->status.pr_lwp.pr_lwphold, wp);
+ rv = Pstopstatus(P, PCNULL, 0);
+
+ if (error != 0) {
+ if (P->status.pr_lwp.pr_why == PR_JOBCONTROL &&
+ error == EBUSY) { /* jobcontrol stop -- back off */
+ P->state = PS_RUN;
+ return (0);
+ }
+ if (error == ENOENT)
+ return (0);
+ errno = error;
+ return (-1);
+ }
+
+ return (rv);
+}
+
+int
+Psetflags(struct ps_prochandle *P, long flags)
+{
+ int rc;
+ long ctl[2];
+
+ ctl[0] = PCSET;
+ ctl[1] = flags;
+
+ if (write(P->ctlfd, ctl, 2*sizeof (long)) != 2*sizeof (long)) {
+ rc = -1;
+ } else {
+ P->status.pr_flags |= flags;
+ P->status.pr_lwp.pr_flags |= flags;
+ rc = 0;
+ }
+
+ return (rc);
+}
+
+int
+Punsetflags(struct ps_prochandle *P, long flags)
+{
+ int rc;
+ long ctl[2];
+
+ ctl[0] = PCUNSET;
+ ctl[1] = flags;
+
+ if (write(P->ctlfd, ctl, 2*sizeof (long)) != 2*sizeof (long)) {
+ rc = -1;
+ } else {
+ P->status.pr_flags &= ~flags;
+ P->status.pr_lwp.pr_flags &= ~flags;
+ rc = 0;
+ }
+
+ return (rc);
+}
+
+/*
+ * Common function to allow clients to manipulate the action to be taken
+ * on receipt of a signal, receipt of machine fault, entry to a system call,
+ * or exit from a system call. We make use of our private prset_* functions
+ * in order to make this code be common. The 'which' parameter identifies
+ * the code for the event of interest (0 means change the entire set), and
+ * the 'stop' parameter is a boolean indicating whether the process should
+ * stop when the event of interest occurs. The previous value is returned
+ * to the caller; -1 is returned if an error occurred.
+ */
+static int
+Psetaction(struct ps_prochandle *P, void *sp, size_t size,
+ uint_t flag, int max, int which, int stop)
+{
+ int oldval;
+
+ if (which < 0 || which > max) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
+ P->state == PS_IDLE) {
+ errno = ENOENT;
+ return (-1);
+ }
+
+ oldval = prset_ismember(sp, size, which) ? TRUE : FALSE;
+
+ if (stop) {
+ if (which == 0) {
+ prset_fill(sp, size);
+ P->flags |= flag;
+ } else if (!oldval) {
+ prset_add(sp, size, which);
+ P->flags |= flag;
+ }
+ } else {
+ if (which == 0) {
+ prset_empty(sp, size);
+ P->flags |= flag;
+ } else if (oldval) {
+ prset_del(sp, size, which);
+ P->flags |= flag;
+ }
+ }
+
+ if (P->state == PS_RUN)
+ Psync(P);
+
+ return (oldval);
+}
+
+/*
+ * Set action on specified signal.
+ */
+int
+Psignal(struct ps_prochandle *P, int which, int stop)
+{
+ int oldval;
+
+ if (which == SIGKILL && stop != 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ oldval = Psetaction(P, &P->status.pr_sigtrace, sizeof (sigset_t),
+ SETSIG, PRMAXSIG, which, stop);
+
+ if (oldval != -1 && which == 0 && stop != 0)
+ prdelset(&P->status.pr_sigtrace, SIGKILL);
+
+ return (oldval);
+}
+
+/*
+ * Set all signal tracing flags.
+ */
+void
+Psetsignal(struct ps_prochandle *P, const sigset_t *set)
+{
+ if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
+ P->state == PS_IDLE)
+ return;
+
+ P->status.pr_sigtrace = *set;
+ P->flags |= SETSIG;
+
+ if (P->state == PS_RUN)
+ Psync(P);
+}
+
+/*
+ * Set action on specified fault.
+ */
+int
+Pfault(struct ps_prochandle *P, int which, int stop)
+{
+ return (Psetaction(P, &P->status.pr_flttrace, sizeof (fltset_t),
+ SETFAULT, PRMAXFAULT, which, stop));
+}
+
+/*
+ * Set all machine fault tracing flags.
+ */
+void
+Psetfault(struct ps_prochandle *P, const fltset_t *set)
+{
+ if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
+ P->state == PS_IDLE)
+ return;
+
+ P->status.pr_flttrace = *set;
+ P->flags |= SETFAULT;
+
+ if (P->state == PS_RUN)
+ Psync(P);
+}
+
+/*
+ * Set action on specified system call entry.
+ */
+int
+Psysentry(struct ps_prochandle *P, int which, int stop)
+{
+ return (Psetaction(P, &P->status.pr_sysentry, sizeof (sysset_t),
+ SETENTRY, PRMAXSYS, which, stop));
+}
+
+/*
+ * Set all system call entry tracing flags.
+ */
+void
+Psetsysentry(struct ps_prochandle *P, const sysset_t *set)
+{
+ if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
+ P->state == PS_IDLE)
+ return;
+
+ P->status.pr_sysentry = *set;
+ P->flags |= SETENTRY;
+
+ if (P->state == PS_RUN)
+ Psync(P);
+}
+
+/*
+ * Set action on specified system call exit.
+ */
+int
+Psysexit(struct ps_prochandle *P, int which, int stop)
+{
+ return (Psetaction(P, &P->status.pr_sysexit, sizeof (sysset_t),
+ SETEXIT, PRMAXSYS, which, stop));
+}
+
+/*
+ * Set all system call exit tracing flags.
+ */
+void
+Psetsysexit(struct ps_prochandle *P, const sysset_t *set)
+{
+ if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
+ P->state == PS_IDLE)
+ return;
+
+ P->status.pr_sysexit = *set;
+ P->flags |= SETEXIT;
+
+ if (P->state == PS_RUN)
+ Psync(P);
+}
+
+/*
+ * Utility function to read the contents of a file that contains a
+ * prheader_t at the start (/proc/pid/lstatus or /proc/pid/lpsinfo).
+ * Returns a malloc()d buffer or NULL on failure.
+ */
+static prheader_t *
+read_lfile(struct ps_prochandle *P, const char *lname)
+{
+ prheader_t *Lhp;
+ char lpath[64];
+ struct stat64 statb;
+ int fd;
+ size_t size;
+ ssize_t rval;
+
+ (void) snprintf(lpath, sizeof (lpath), "/proc/%d/%s",
+ (int)P->status.pr_pid, lname);
+ if ((fd = open(lpath, O_RDONLY)) < 0 || fstat64(fd, &statb) != 0) {
+ if (fd >= 0)
+ (void) close(fd);
+ return (NULL);
+ }
+
+ /*
+ * 'size' is just the initial guess at the buffer size.
+ * It will have to grow if the number of lwps increases
+ * while we are looking at the process.
+ * 'size' must be larger than the actual file size.
+ */
+ size = statb.st_size + 32;
+
+ for (;;) {
+ if ((Lhp = malloc(size)) == NULL)
+ break;
+ if ((rval = pread(fd, Lhp, size, 0)) < 0 ||
+ rval <= sizeof (prheader_t)) {
+ free(Lhp);
+ Lhp = NULL;
+ break;
+ }
+ if (rval < size)
+ break;
+ /* need a bigger buffer */
+ free(Lhp);
+ size *= 2;
+ }
+
+ (void) close(fd);
+ return (Lhp);
+}
+
+/*
+ * LWP iteration interface.
+ */
+int
+Plwp_iter(struct ps_prochandle *P, proc_lwp_f *func, void *cd)
+{
+ prheader_t *Lhp;
+ lwpstatus_t *Lsp;
+ long nlwp;
+ int rv;
+
+ switch (P->state) {
+ case PS_RUN:
+ (void) Pstopstatus(P, PCNULL, 0);
+ break;
+
+ case PS_STOP:
+ Psync(P);
+ break;
+
+ case PS_IDLE:
+ errno = ENODATA;
+ return (-1);
+ }
+
+ /*
+ * For either live processes or cores, the single LWP case is easy:
+ * the pstatus_t contains the lwpstatus_t for the only LWP.
+ */
+ if (P->status.pr_nlwp <= 1)
+ return (func(cd, &P->status.pr_lwp));
+
+ /*
+ * 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;
+ }
+
+ 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 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)) {
+ if ((rv = func(cd, Lsp)) != 0)
+ break;
+ }
+
+ free(Lhp);
+ return (rv);
+}
+
+/*
+ * Extended LWP iteration interface.
+ * Iterate over all LWPs, active and zombie.
+ */
+int
+Plwp_iter_all(struct ps_prochandle *P, proc_lwp_all_f *func, void *cd)
+{
+ prheader_t *Lhp = NULL;
+ lwpstatus_t *Lsp;
+ lwpstatus_t *sp;
+ prheader_t *Lphp = NULL;
+ lwpsinfo_t *Lpsp;
+ long nstat;
+ long ninfo;
+ int rv;
+
+retry:
+ if (Lhp != NULL)
+ free(Lhp);
+ if (Lphp != NULL)
+ free(Lphp);
+ if (P->state == PS_RUN)
+ (void) Pstopstatus(P, PCNULL, 0);
+ (void) Ppsinfo(P);
+
+ if (P->state == PS_STOP)
+ Psync(P);
+
+ /*
+ * For either live processes or cores, the single LWP case is easy:
+ * the pstatus_t contains the lwpstatus_t for the only LWP and
+ * the psinfo_t contains the lwpsinfo_t for the only LWP.
+ */
+ if (P->status.pr_nlwp + P->status.pr_nzomb <= 1)
+ return (func(cd, &P->status.pr_lwp, &P->psinfo.pr_lwp));
+
+ /*
+ * 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;
+ }
+
+ 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);
+ }
+
+ /*
+ * If we are looking at a running process, or one we do not control,
+ * the active and zombie lwps in the process may have changed since
+ * we read the process status structure. If so, just start over.
+ */
+ if (Lhp->pr_nent != P->status.pr_nlwp ||
+ Lphp->pr_nent != P->status.pr_nlwp + P->status.pr_nzomb)
+ goto retry;
+
+ /*
+ * To be perfectly safe, prescan the two arrays, checking consistency.
+ * We rely on /proc giving us lwpstatus_t's and lwpsinfo_t's in the
+ * same order (the lwp directory order) in their respective files.
+ * We also rely on there being (possibly) more lwpsinfo_t's than
+ * lwpstatus_t's (the extra lwpsinfo_t's are for zombie lwps).
+ */
+ Lsp = (lwpstatus_t *)(uintptr_t)(Lhp + 1);
+ Lpsp = (lwpsinfo_t *)(uintptr_t)(Lphp + 1);
+ nstat = Lhp->pr_nent;
+ for (ninfo = Lphp->pr_nent; ninfo != 0; ninfo--) {
+ if (Lpsp->pr_sname != 'Z') {
+ /*
+ * Not a zombie lwp; check for matching lwpids.
+ */
+ if (nstat == 0 || Lsp->pr_lwpid != Lpsp->pr_lwpid)
+ goto retry;
+ Lsp = (lwpstatus_t *)((uintptr_t)Lsp + Lhp->pr_entsize);
+ nstat--;
+ }
+ Lpsp = (lwpsinfo_t *)((uintptr_t)Lpsp + Lphp->pr_entsize);
+ }
+ if (nstat != 0)
+ goto retry;
+
+ /*
+ * Rescan, this time for real.
+ */
+ Lsp = (lwpstatus_t *)(uintptr_t)(Lhp + 1);
+ Lpsp = (lwpsinfo_t *)(uintptr_t)(Lphp + 1);
+ for (ninfo = Lphp->pr_nent; ninfo != 0; ninfo--) {
+ if (Lpsp->pr_sname != 'Z') {
+ sp = Lsp;
+ Lsp = (lwpstatus_t *)((uintptr_t)Lsp + Lhp->pr_entsize);
+ } else {
+ sp = NULL;
+ }
+ if ((rv = func(cd, sp, Lpsp)) != 0)
+ break;
+ Lpsp = (lwpsinfo_t *)((uintptr_t)Lpsp + Lphp->pr_entsize);
+ }
+
+ free(Lhp);
+ free(Lphp);
+ return (rv);
+}
+
+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);
+}
+
+/*
+ * =================================================================
+ * The remainder of the functions in this file are for the
+ * control of individual LWPs in the controlled process.
+ * =================================================================
+ */
+
+/*
+ * Find an entry in the process hash table for the specified lwpid.
+ * The entry will either point to an existing struct ps_lwphandle
+ * or it will point to an empty slot for a new struct ps_lwphandle.
+ */
+static struct ps_lwphandle **
+Lfind(struct ps_prochandle *P, lwpid_t lwpid)
+{
+ struct ps_lwphandle **Lp;
+ struct ps_lwphandle *L;
+
+ for (Lp = &P->hashtab[lwpid % (HASHSIZE - 1)];
+ (L = *Lp) != NULL; Lp = &L->lwp_hash)
+ if (L->lwp_id == lwpid)
+ break;
+ return (Lp);
+}
+
+/*
+ * Grab an LWP contained within the controlled process.
+ * Return an opaque pointer to its LWP control structure.
+ * perr: pointer to error return code.
+ */
+struct ps_lwphandle *
+Lgrab(struct ps_prochandle *P, lwpid_t lwpid, int *perr)
+{
+ struct ps_lwphandle **Lp;
+ struct ps_lwphandle *L;
+ int fd;
+ char procname[100];
+ char *fname;
+ int rc = 0;
+
+ (void) mutex_lock(&P->proc_lock);
+
+ if (P->state == PS_UNDEAD || P->state == PS_IDLE)
+ rc = G_NOPROC;
+ else if (P->hashtab == NULL &&
+ (P->hashtab = calloc(HASHSIZE, sizeof (struct ps_lwphandle *)))
+ == NULL)
+ rc = G_STRANGE;
+ else if (*(Lp = Lfind(P, lwpid)) != NULL)
+ rc = G_BUSY;
+ else if ((L = malloc(sizeof (struct ps_lwphandle))) == NULL)
+ rc = G_STRANGE;
+ if (rc) {
+ *perr = rc;
+ (void) mutex_unlock(&P->proc_lock);
+ return (NULL);
+ }
+
+ (void) memset(L, 0, sizeof (*L));
+ L->lwp_ctlfd = -1;
+ L->lwp_statfd = -1;
+ L->lwp_proc = P;
+ L->lwp_id = lwpid;
+ *Lp = L; /* insert into the hash table */
+
+ if (P->state == PS_DEAD) { /* core file */
+ if (getlwpstatus(P, lwpid, &L->lwp_status) == -1) {
+ rc = G_NOPROC;
+ goto err;
+ }
+ L->lwp_state = PS_DEAD;
+ *perr = 0;
+ (void) mutex_unlock(&P->proc_lock);
+ return (L);
+ }
+
+ /*
+ * Open the /proc/<pid>/lwp/<lwpid> files
+ */
+ (void) sprintf(procname, "/proc/%d/lwp/%d/", (int)P->pid, (int)lwpid);
+ fname = procname + strlen(procname);
+ (void) set_minfd();
+
+ (void) strcpy(fname, "lwpstatus");
+ if ((fd = open(procname, O_RDONLY)) < 0 ||
+ (fd = dupfd(fd, 0)) < 0) {
+ switch (errno) {
+ case ENOENT:
+ rc = G_NOPROC;
+ break;
+ default:
+ dprintf("Lgrab: failed to open %s: %s\n",
+ procname, strerror(errno));
+ rc = G_STRANGE;
+ break;
+ }
+ goto err;
+ }
+ L->lwp_statfd = fd;
+
+ if (pread(fd, &L->lwp_status, sizeof (L->lwp_status), (off_t)0) < 0) {
+ switch (errno) {
+ case ENOENT:
+ rc = G_NOPROC;
+ break;
+ default:
+ dprintf("Lgrab: failed to read %s: %s\n",
+ procname, strerror(errno));
+ rc = G_STRANGE;
+ break;
+ }
+ goto err;
+ }
+
+ (void) strcpy(fname, "lwpctl");
+ if ((fd = open(procname, O_WRONLY)) < 0 ||
+ (fd = dupfd(fd, 0)) < 0) {
+ switch (errno) {
+ case ENOENT:
+ rc = G_NOPROC;
+ break;
+ default:
+ dprintf("Lgrab: failed to open %s: %s\n",
+ procname, strerror(errno));
+ rc = G_STRANGE;
+ break;
+ }
+ goto err;
+ }
+ L->lwp_ctlfd = fd;
+
+ L->lwp_state =
+ ((L->lwp_status.pr_flags & (PR_STOPPED|PR_ISTOP))
+ == (PR_STOPPED|PR_ISTOP))?
+ PS_STOP : PS_RUN;
+
+ *perr = 0;
+ (void) mutex_unlock(&P->proc_lock);
+ return (L);
+
+err:
+ Lfree_internal(P, L);
+ *perr = rc;
+ (void) mutex_unlock(&P->proc_lock);
+ return (NULL);
+}
+
+/*
+ * Return a printable string corresponding to an Lgrab() error return.
+ */
+const char *
+Lgrab_error(int error)
+{
+ const char *str;
+
+ switch (error) {
+ case G_NOPROC:
+ str = "no such LWP";
+ break;
+ case G_BUSY:
+ str = "LWP already grabbed";
+ break;
+ case G_STRANGE:
+ str = "unanticipated system error";
+ break;
+ default:
+ str = "unknown error";
+ break;
+ }
+
+ return (str);
+}
+
+/*
+ * Free an LWP control structure.
+ */
+void
+Lfree(struct ps_lwphandle *L)
+{
+ struct ps_prochandle *P = L->lwp_proc;
+
+ (void) mutex_lock(&P->proc_lock);
+ Lfree_internal(P, L);
+ (void) mutex_unlock(&P->proc_lock);
+}
+
+static void
+Lfree_internal(struct ps_prochandle *P, struct ps_lwphandle *L)
+{
+ *Lfind(P, L->lwp_id) = L->lwp_hash; /* delete from hash table */
+ if (L->lwp_ctlfd >= 0)
+ (void) close(L->lwp_ctlfd);
+ if (L->lwp_statfd >= 0)
+ (void) close(L->lwp_statfd);
+
+ /* clear out the structure as a precaution against reuse */
+ (void) memset(L, 0, sizeof (*L));
+ L->lwp_ctlfd = -1;
+ L->lwp_statfd = -1;
+
+ free(L);
+}
+
+/*
+ * Return the state of the process, one of the PS_* values.
+ */
+int
+Lstate(struct ps_lwphandle *L)
+{
+ return (L->lwp_state);
+}
+
+/*
+ * Return the open control file descriptor for the LWP.
+ * Clients must not close this file descriptor, nor use it
+ * after the LWP is freed.
+ */
+int
+Lctlfd(struct ps_lwphandle *L)
+{
+ return (L->lwp_ctlfd);
+}
+
+/*
+ * Return a pointer to the LWP lwpsinfo structure.
+ * Clients should not hold on to this pointer indefinitely.
+ * It will become invalid on Lfree().
+ */
+const lwpsinfo_t *
+Lpsinfo(struct ps_lwphandle *L)
+{
+ if (Plwp_getpsinfo(L->lwp_proc, L->lwp_id, &L->lwp_psinfo) == -1)
+ return (NULL);
+
+ return (&L->lwp_psinfo);
+}
+
+/*
+ * Return a pointer to the LWP status structure.
+ * Clients should not hold on to this pointer indefinitely.
+ * It will become invalid on Lfree().
+ */
+const lwpstatus_t *
+Lstatus(struct ps_lwphandle *L)
+{
+ return (&L->lwp_status);
+}
+
+/*
+ * Given an LWP handle, return the process handle.
+ */
+struct ps_prochandle *
+Lprochandle(struct ps_lwphandle *L)
+{
+ return (L->lwp_proc);
+}
+
+/*
+ * Ensure that all cached state is written to the LWP.
+ * The cached state is the LWP's signal mask and registers.
+ */
+void
+Lsync(struct ps_lwphandle *L)
+{
+ int ctlfd = L->lwp_ctlfd;
+ long cmd[2];
+ iovec_t iov[4];
+ int n = 0;
+
+ if (L->lwp_flags & SETHOLD) {
+ cmd[0] = PCSHOLD;
+ iov[n].iov_base = (caddr_t)&cmd[0];
+ iov[n++].iov_len = sizeof (long);
+ iov[n].iov_base = (caddr_t)&L->lwp_status.pr_lwphold;
+ iov[n++].iov_len = sizeof (L->lwp_status.pr_lwphold);
+ }
+ if (L->lwp_flags & SETREGS) {
+ cmd[1] = PCSREG;
+ iov[n].iov_base = (caddr_t)&cmd[1];
+ iov[n++].iov_len = sizeof (long);
+ iov[n].iov_base = (caddr_t)&L->lwp_status.pr_reg[0];
+ iov[n++].iov_len = sizeof (L->lwp_status.pr_reg);
+ }
+
+ if (n == 0 || writev(ctlfd, iov, n) < 0)
+ return; /* nothing to do or write failed */
+
+ L->lwp_flags &= ~(SETHOLD|SETREGS);
+}
+
+/*
+ * Wait for the specified LWP to stop or terminate.
+ * Or, just get the current status (PCNULL).
+ * Or, direct it to stop and get the current status (PCDSTOP).
+ */
+static int
+Lstopstatus(struct ps_lwphandle *L,
+ long request, /* PCNULL, PCDSTOP, PCSTOP, PCWSTOP */
+ uint_t msec) /* if non-zero, timeout in milliseconds */
+{
+ int ctlfd = L->lwp_ctlfd;
+ long ctl[3];
+ ssize_t rc;
+ int err;
+
+ switch (L->lwp_state) {
+ case PS_RUN:
+ break;
+ case PS_STOP:
+ if (request != PCNULL && request != PCDSTOP)
+ return (0);
+ break;
+ case PS_LOST:
+ if (request != PCNULL) {
+ errno = EAGAIN;
+ return (-1);
+ }
+ break;
+ case PS_UNDEAD:
+ case PS_DEAD:
+ if (request != PCNULL) {
+ errno = ENOENT;
+ return (-1);
+ }
+ break;
+ default: /* corrupted state */
+ dprintf("Lstopstatus: corrupted state: %d\n", L->lwp_state);
+ errno = EINVAL;
+ return (-1);
+ }
+
+ ctl[0] = PCDSTOP;
+ ctl[1] = PCTWSTOP;
+ ctl[2] = (long)msec;
+ rc = 0;
+ switch (request) {
+ case PCSTOP:
+ rc = write(ctlfd, &ctl[0], 3*sizeof (long));
+ break;
+ case PCWSTOP:
+ rc = write(ctlfd, &ctl[1], 2*sizeof (long));
+ break;
+ case PCDSTOP:
+ rc = write(ctlfd, &ctl[0], 1*sizeof (long));
+ break;
+ case PCNULL:
+ if (L->lwp_state == PS_DEAD)
+ return (0); /* Nothing else to do for cores */
+ break;
+ default: /* programming error */
+ errno = EINVAL;
+ return (-1);
+ }
+ err = (rc < 0)? errno : 0;
+ Lsync(L);
+
+ if (pread(L->lwp_statfd, &L->lwp_status,
+ sizeof (L->lwp_status), (off_t)0) < 0)
+ err = errno;
+
+ if (err) {
+ switch (err) {
+ case EINTR: /* user typed ctl-C */
+ case ERESTART:
+ dprintf("Lstopstatus: EINTR\n");
+ break;
+ case EAGAIN: /* we lost control of the the process */
+ dprintf("Lstopstatus: EAGAIN\n");
+ L->lwp_state = PS_LOST;
+ errno = err;
+ return (-1);
+ default:
+ if (_libproc_debug) {
+ const char *errstr;
+
+ switch (request) {
+ case PCNULL:
+ errstr = "Lstopstatus PCNULL"; break;
+ case PCSTOP:
+ errstr = "Lstopstatus PCSTOP"; break;
+ case PCDSTOP:
+ errstr = "Lstopstatus PCDSTOP"; break;
+ case PCWSTOP:
+ errstr = "Lstopstatus PCWSTOP"; break;
+ default:
+ errstr = "Lstopstatus PC???"; break;
+ }
+ dprintf("%s: %s\n", errstr, strerror(err));
+ }
+ L->lwp_state = PS_UNDEAD;
+ errno = err;
+ return (-1);
+ }
+ }
+
+ if ((L->lwp_status.pr_flags & (PR_STOPPED|PR_ISTOP))
+ != (PR_STOPPED|PR_ISTOP)) {
+ L->lwp_state = PS_RUN;
+ if (request == PCNULL || request == PCDSTOP || msec != 0)
+ return (0);
+ dprintf("Lstopstatus: LWP is not stopped\n");
+ errno = EPROTO;
+ return (-1);
+ }
+
+ L->lwp_state = PS_STOP;
+
+ if (_libproc_debug) /* debugging */
+ prldump("Lstopstatus", &L->lwp_status);
+
+ switch (L->lwp_status.pr_why) {
+ case PR_SYSENTRY:
+ case PR_SYSEXIT:
+ case PR_REQUESTED:
+ case PR_SIGNALLED:
+ case PR_FAULTED:
+ case PR_JOBCONTROL:
+ case PR_SUSPENDED:
+ break;
+ default:
+ errno = EPROTO;
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * Wait for the LWP to stop for any reason.
+ */
+int
+Lwait(struct ps_lwphandle *L, uint_t msec)
+{
+ return (Lstopstatus(L, PCWSTOP, msec));
+}
+
+/*
+ * Direct the LWP to stop; wait for it to stop.
+ */
+int
+Lstop(struct ps_lwphandle *L, uint_t msec)
+{
+ return (Lstopstatus(L, PCSTOP, msec));
+}
+
+/*
+ * Direct the LWP to stop; don't wait.
+ */
+int
+Ldstop(struct ps_lwphandle *L)
+{
+ return (Lstopstatus(L, PCDSTOP, 0));
+}
+
+/*
+ * Get the value of one register from stopped LWP.
+ */
+int
+Lgetareg(struct ps_lwphandle *L, int regno, prgreg_t *preg)
+{
+ if (regno < 0 || regno >= NPRGREG) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (L->lwp_state != PS_STOP) {
+ errno = EBUSY;
+ return (-1);
+ }
+
+ *preg = L->lwp_status.pr_reg[regno];
+ return (0);
+}
+
+/*
+ * Put value of one register into stopped LWP.
+ */
+int
+Lputareg(struct ps_lwphandle *L, int regno, prgreg_t reg)
+{
+ if (regno < 0 || regno >= NPRGREG) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (L->lwp_state != PS_STOP) {
+ errno = EBUSY;
+ return (-1);
+ }
+
+ L->lwp_status.pr_reg[regno] = reg;
+ L->lwp_flags |= SETREGS; /* set registers before continuing */
+ return (0);
+}
+
+int
+Lsetrun(struct ps_lwphandle *L,
+ int sig, /* signal to pass to LWP */
+ int flags) /* PRSTEP|PRSABORT|PRSTOP|PRCSIG|PRCFAULT */
+{
+ int ctlfd = L->lwp_ctlfd;
+ int sbits = (PR_DSTOP | PR_ISTOP | PR_ASLEEP);
+
+ long ctl[1 + /* PCCFAULT */
+ 1 + sizeof (siginfo_t)/sizeof (long) + /* PCSSIG/PCCSIG */
+ 2 ]; /* PCRUN */
+
+ long *ctlp = ctl;
+ size_t size;
+
+ if (L->lwp_state != PS_STOP &&
+ (L->lwp_status.pr_flags & sbits) == 0) {
+ errno = EBUSY;
+ return (-1);
+ }
+
+ Lsync(L); /* flush registers */
+
+ if (flags & PRCFAULT) { /* clear current fault */
+ *ctlp++ = PCCFAULT;
+ flags &= ~PRCFAULT;
+ }
+
+ if (flags & PRCSIG) { /* clear current signal */
+ *ctlp++ = PCCSIG;
+ flags &= ~PRCSIG;
+ } else if (sig && sig != L->lwp_status.pr_cursig) {
+ /* make current signal */
+ siginfo_t *infop;
+
+ *ctlp++ = PCSSIG;
+ infop = (siginfo_t *)ctlp;
+ (void) memset(infop, 0, sizeof (*infop));
+ infop->si_signo = sig;
+ ctlp += sizeof (siginfo_t) / sizeof (long);
+ }
+
+ *ctlp++ = PCRUN;
+ *ctlp++ = flags;
+ size = (char *)ctlp - (char *)ctl;
+
+ L->lwp_proc->info_valid = 0; /* will need to update map and file info */
+ L->lwp_proc->state = PS_RUN;
+ L->lwp_state = PS_RUN;
+
+ if (write(ctlfd, ctl, size) != size) {
+ /* Pretend that a job-stopped LWP is running */
+ if (errno != EBUSY || L->lwp_status.pr_why != PR_JOBCONTROL)
+ return (Lstopstatus(L, PCNULL, 0));
+ }
+
+ return (0);
+}
+
+int
+Lclearsig(struct ps_lwphandle *L)
+{
+ int ctlfd = L->lwp_ctlfd;
+ long ctl = PCCSIG;
+
+ if (write(ctlfd, &ctl, sizeof (ctl)) != sizeof (ctl))
+ return (-1);
+ L->lwp_status.pr_cursig = 0;
+ return (0);
+}
+
+int
+Lclearfault(struct ps_lwphandle *L)
+{
+ int ctlfd = L->lwp_ctlfd;
+ long ctl = PCCFAULT;
+
+ if (write(ctlfd, &ctl, sizeof (ctl)) != sizeof (ctl))
+ return (-1);
+ return (0);
+}
+
+/*
+ * Step over a breakpoint, i.e., execute the instruction that
+ * really belongs at the breakpoint location (the current %pc)
+ * and leave the LWP stopped at the next instruction.
+ */
+int
+Lxecbkpt(struct ps_lwphandle *L, ulong_t saved)
+{
+ struct ps_prochandle *P = L->lwp_proc;
+ int rv, error;
+
+ if (L->lwp_state != PS_STOP) {
+ errno = EBUSY;
+ return (-1);
+ }
+
+ Lsync(L);
+ error = execute_bkpt(L->lwp_ctlfd,
+ &P->status.pr_flttrace, &L->lwp_status.pr_lwphold,
+ L->lwp_status.pr_reg[R_PC], saved);
+ rv = Lstopstatus(L, PCNULL, 0);
+
+ if (error != 0) {
+ if (L->lwp_status.pr_why == PR_JOBCONTROL &&
+ error == EBUSY) { /* jobcontrol stop -- back off */
+ L->lwp_state = PS_RUN;
+ return (0);
+ }
+ if (error == ENOENT)
+ return (0);
+ errno = error;
+ return (-1);
+ }
+
+ return (rv);
+}
+
+/*
+ * Step over a watchpoint, i.e., execute the instruction that was stopped by
+ * the watchpoint, and then leave the LWP stopped at the next instruction.
+ */
+int
+Lxecwapt(struct ps_lwphandle *L, const prwatch_t *wp)
+{
+ struct ps_prochandle *P = L->lwp_proc;
+ int rv, error;
+
+ if (L->lwp_state != PS_STOP) {
+ errno = EBUSY;
+ return (-1);
+ }
+
+ Lsync(L);
+ error = execute_wapt(L->lwp_ctlfd,
+ &P->status.pr_flttrace, &L->lwp_status.pr_lwphold, wp);
+ rv = Lstopstatus(L, PCNULL, 0);
+
+ if (error != 0) {
+ if (L->lwp_status.pr_why == PR_JOBCONTROL &&
+ error == EBUSY) { /* jobcontrol stop -- back off */
+ L->lwp_state = PS_RUN;
+ return (0);
+ }
+ if (error == ENOENT)
+ return (0);
+ errno = error;
+ return (-1);
+ }
+
+ return (rv);
+}
+
+int
+Lstack(struct ps_lwphandle *L, stack_t *stkp)
+{
+ struct ps_prochandle *P = L->lwp_proc;
+ uintptr_t addr = L->lwp_status.pr_ustack;
+
+ if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
+ if (Pread(P, stkp, sizeof (*stkp), addr) != sizeof (*stkp))
+ return (-1);
+#ifdef _LP64
+ } else {
+ stack32_t stk32;
+
+ if (Pread(P, &stk32, sizeof (stk32), addr) != sizeof (stk32))
+ return (-1);
+
+ stack_32_to_n(&stk32, stkp);
+#endif
+ }
+
+ return (0);
+}
+
+int
+Lmain_stack(struct ps_lwphandle *L, stack_t *stkp)
+{
+ struct ps_prochandle *P = L->lwp_proc;
+
+ if (Lstack(L, stkp) != 0)
+ return (-1);
+
+ /*
+ * If the SS_ONSTACK flag is set then this LWP is operating on the
+ * alternate signal stack. We can recover the original stack from
+ * pr_oldcontext.
+ */
+ if (!(stkp->ss_flags & SS_ONSTACK))
+ return (0);
+
+ if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
+ ucontext_t *ctxp = (void *)L->lwp_status.pr_oldcontext;
+
+ if (Pread(P, stkp, sizeof (*stkp),
+ (uintptr_t)&ctxp->uc_stack) != sizeof (*stkp))
+ return (-1);
+#ifdef _LP64
+ } else {
+ ucontext32_t *ctxp = (void *)L->lwp_status.pr_oldcontext;
+ stack32_t stk32;
+
+ if (Pread(P, &stk32, sizeof (stk32),
+ (uintptr_t)&ctxp->uc_stack) != sizeof (stk32))
+ return (-1);
+
+ stack_32_to_n(&stk32, stkp);
+#endif
+ }
+
+ return (0);
+}
+
+int
+Lalt_stack(struct ps_lwphandle *L, stack_t *stkp)
+{
+ if (L->lwp_status.pr_altstack.ss_flags & SS_DISABLE) {
+ errno = ENODATA;
+ return (-1);
+ }
+
+ *stkp = L->lwp_status.pr_altstack;
+
+ return (0);
+}
+
+/*
+ * Add a mapping to the given proc handle. Resizes the array as appropriate and
+ * manages reference counts on the given file_info_t.
+ *
+ * The 'map_relocate' member is used to tell Psort_mappings() that the
+ * associated file_map pointer needs to be relocated after the mappings have
+ * been sorted. It is only set for the first mapping, and has no meaning
+ * outside these two functions.
+ */
+int
+Padd_mapping(struct ps_prochandle *P, off64_t off, file_info_t *fp,
+ prmap_t *pmap)
+{
+ map_info_t *mp;
+
+ if (P->map_count == P->map_alloc) {
+ size_t next = P->map_alloc ? P->map_alloc * 2 : 16;
+
+ if ((P->mappings = realloc(P->mappings,
+ next * sizeof (map_info_t))) == NULL)
+ return (-1);
+
+ P->map_alloc = next;
+ }
+
+ mp = &P->mappings[P->map_count++];
+
+ mp->map_offset = off;
+ mp->map_pmap = *pmap;
+ mp->map_relocate = 0;
+ if ((mp->map_file = fp) != NULL) {
+ if (fp->file_map == NULL) {
+ fp->file_map = mp;
+ mp->map_relocate = 1;
+ }
+ fp->file_ref++;
+ }
+
+ return (0);
+}
+
+static int
+map_sort(const void *a, const void *b)
+{
+ const map_info_t *ap = a, *bp = b;
+
+ if (ap->map_pmap.pr_vaddr < bp->map_pmap.pr_vaddr)
+ return (-1);
+ else if (ap->map_pmap.pr_vaddr > bp->map_pmap.pr_vaddr)
+ return (1);
+ else
+ return (0);
+}
+
+/*
+ * Sort the current set of mappings. Should be called during target
+ * initialization after all calls to Padd_mapping() have been made.
+ */
+void
+Psort_mappings(struct ps_prochandle *P)
+{
+ int i;
+ map_info_t *mp;
+
+ qsort(P->mappings, P->map_count, sizeof (map_info_t), map_sort);
+
+ /*
+ * Update all the file_map pointers to refer to the new locations.
+ */
+ for (i = 0; i < P->map_count; i++) {
+ mp = &P->mappings[i];
+ if (mp->map_relocate)
+ mp->map_file->file_map = mp;
+ mp->map_relocate = 0;
+ }
+}
diff --git a/usr/src/lib/libproc/common/Pcontrol.h b/usr/src/lib/libproc/common/Pcontrol.h
new file mode 100644
index 0000000000..5d3797d16f
--- /dev/null
+++ b/usr/src/lib/libproc/common/Pcontrol.h
@@ -0,0 +1,250 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _PCONTROL_H
+#define _PCONTROL_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Implemention-specific include file for libproc process management.
+ * This is not to be seen by the clients of libproc.
+ */
+
+#include <stdio.h>
+#include <gelf.h>
+#include <synch.h>
+#include <procfs.h>
+#include <rtld_db.h>
+#include <libproc.h>
+#include <libctf.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "Putil.h"
+
+/*
+ * Definitions of the process control structures, internal to libproc.
+ * These may change without affecting clients of libproc.
+ */
+
+typedef struct { /* symbol table */
+ Elf_Data *sym_data; /* start of table */
+ size_t sym_symn; /* number of entries */
+ char *sym_strs; /* ptr to strings */
+ size_t sym_strsz; /* size of string table */
+ GElf_Shdr sym_hdr; /* symbol table section header */
+ GElf_Shdr sym_strhdr; /* string table section header */
+ Elf *sym_elf; /* faked-up elf handle from core file */
+ void *sym_elfmem; /* data for faked-up elf handle */
+ uint_t *sym_byname; /* symbols sorted by name */
+ uint_t *sym_byaddr; /* symbols sorted by addr */
+ size_t sym_count; /* number of symbols in each sorted list */
+} sym_tbl_t;
+
+typedef struct file_info { /* symbol information for a mapped file */
+ list_t file_list; /* linked list */
+ char file_pname[PRMAPSZ]; /* name from prmap_t */
+ struct map_info *file_map; /* primary (text) mapping */
+ int file_ref; /* references from map_info_t structures */
+ int file_fd; /* file descriptor for the mapped file */
+ int file_init; /* 0: initialization yet to be performed */
+ GElf_Half file_etype; /* ELF e_type from ehdr */
+ GElf_Half file_class; /* ELF e_ident[EI_CLASS] from ehdr */
+ rd_loadobj_t *file_lo; /* load object structure from rtld_db */
+ char *file_lname; /* load object name from rtld_db */
+ char *file_lbase; /* pointer to basename of file_lname */
+ Elf *file_elf; /* elf handle so we can close */
+ void *file_elfmem; /* data for faked-up elf handle */
+ sym_tbl_t file_symtab; /* symbol table */
+ sym_tbl_t file_dynsym; /* dynamic symbol table */
+ uintptr_t file_dyn_base; /* load address for ET_DYN files */
+ uintptr_t file_plt_base; /* base address for PLT */
+ size_t file_plt_size; /* size of PLT region */
+ uintptr_t file_jmp_rel; /* base address of PLT relocations */
+ uintptr_t file_ctf_off; /* offset of CTF data in object file */
+ size_t file_ctf_size; /* size of CTF data in object file */
+ int file_ctf_dyn; /* does the CTF data reference the dynsym */
+ void *file_ctf_buf; /* CTF data for this file */
+ ctf_file_t *file_ctfp; /* CTF container for this file */
+} file_info_t;
+
+typedef struct map_info { /* description of an address space mapping */
+ prmap_t map_pmap; /* /proc description of this mapping */
+ file_info_t *map_file; /* pointer into list of mapped files */
+ off64_t map_offset; /* offset into core file (if core) */
+ int map_relocate; /* associated file_map needs to be relocated */
+} map_info_t;
+
+typedef struct lwp_info { /* per-lwp information from core file */
+ list_t lwp_list; /* linked list */
+ lwpid_t lwp_id; /* lwp identifier */
+ lwpsinfo_t lwp_psinfo; /* /proc/<pid>/lwp/<lwpid>/lwpsinfo data */
+ lwpstatus_t lwp_status; /* /proc/<pid>/lwp/<lwpid>/lwpstatus data */
+#if defined(sparc) || defined(__sparc)
+ gwindows_t *lwp_gwins; /* /proc/<pid>/lwp/<lwpid>/gwindows data */
+ prxregset_t *lwp_xregs; /* /proc/<pid>/lwp/<lwpid>/xregs data */
+ int64_t *lwp_asrs; /* /proc/<pid>/lwp/<lwpid>/asrs data */
+#endif
+} lwp_info_t;
+
+typedef struct core_info { /* information specific to core files */
+ char core_dmodel; /* data model for core file */
+ int core_errno; /* error during initialization if != 0 */
+ list_t core_lwp_head; /* head of list of lwp info */
+ lwp_info_t *core_lwp; /* current lwp information */
+ uint_t core_nlwp; /* number of lwp's in list */
+ off64_t core_size; /* size of core file in bytes */
+ char *core_platform; /* platform string from core file */
+ struct utsname *core_uts; /* uname(2) data from core file */
+ prcred_t *core_cred; /* process credential from core file */
+ core_content_t core_content; /* content dumped to core file */
+ prpriv_t *core_priv; /* process privileges from core file */
+ size_t core_priv_size; /* size of the privileges */
+ void *core_privinfo; /* system privileges info from core file */
+ priv_impl_info_t *core_ppii; /* NOTE entry for core_privinfo */
+ char *core_zonename; /* zone name from core file */
+#if defined(__i386) || defined(__amd64)
+ struct ssd *core_ldt; /* LDT entries from core file */
+ uint_t core_nldt; /* number of LDT entries in core file */
+#endif
+} core_info_t;
+
+typedef struct elf_file { /* convenience for managing ELF files */
+ GElf_Ehdr e_hdr; /* ELF file header information */
+ Elf *e_elf; /* ELF library handle */
+ 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 {
+ struct ps_lwphandle **hashtab; /* hash table for LWPs (Lgrab()) */
+ mutex_t proc_lock; /* protects hash table; serializes Lgrab() */
+ pstatus_t orig_status; /* remembered status on Pgrab() */
+ pstatus_t status; /* status when stopped */
+ psinfo_t psinfo; /* psinfo_t from last Ppsinfo() request */
+ uintptr_t sysaddr; /* address of most recent syscall instruction */
+ pid_t pid; /* process-ID */
+ int state; /* state of the process, see "libproc.h" */
+ uint_t flags; /* see defines below */
+ uint_t agentcnt; /* Pcreate_agent()/Pdestroy_agent() ref count */
+ int asfd; /* /proc/<pid>/as filedescriptor */
+ int ctlfd; /* /proc/<pid>/ctl filedescriptor */
+ int statfd; /* /proc/<pid>/status filedescriptor */
+ int agentctlfd; /* /proc/<pid>/lwp/agent/ctl */
+ int agentstatfd; /* /proc/<pid>/lwp/agent/status */
+ int info_valid; /* if zero, map and file info need updating */
+ map_info_t *mappings; /* cached process mappings */
+ size_t map_count; /* number of mappings */
+ size_t map_alloc; /* number of mappings allocated */
+ uint_t num_files; /* number of file elements in file_info */
+ list_t file_head; /* head of mapped files w/ symbol table info */
+ char *execname; /* name of the executable file */
+ auxv_t *auxv; /* the process's aux vector */
+ int nauxv; /* number of aux vector entries */
+ 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) */
+ uintptr_t *ucaddrs; /* ucontext-list addresses */
+ uint_t ucnelems; /* number of elements in the ucaddrs list */
+};
+
+/* flags */
+#define CREATED 0x01 /* process was created by Pcreate() */
+#define SETSIG 0x02 /* set signal trace mask before continuing */
+#define SETFAULT 0x04 /* set fault trace mask before continuing */
+#define SETENTRY 0x08 /* set sysentry trace mask before continuing */
+#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 */
+
+struct ps_lwphandle {
+ struct ps_prochandle *lwp_proc; /* process to which this lwp belongs */
+ struct ps_lwphandle *lwp_hash; /* hash table linked list */
+ lwpstatus_t lwp_status; /* status when stopped */
+ lwpsinfo_t lwp_psinfo; /* lwpsinfo_t from last Lpsinfo() */
+ lwpid_t lwp_id; /* lwp identifier */
+ int lwp_state; /* state of the lwp, see "libproc.h" */
+ uint_t lwp_flags; /* SETHOLD and/or SETREGS */
+ int lwp_ctlfd; /* /proc/<pid>/lwp/<lwpid>/lwpctl */
+ int lwp_statfd; /* /proc/<pid>/lwp/<lwpid>/lwpstatus */
+};
+
+/*
+ * Implementation functions in the process control library.
+ * These are not exported to clients of the library.
+ */
+extern void prldump(const char *, lwpstatus_t *);
+extern int dupfd(int, int);
+extern int set_minfd(void);
+extern int Pscantext(struct ps_prochandle *);
+extern void Pinitsym(struct ps_prochandle *);
+extern void Preadauxvec(struct ps_prochandle *);
+extern void optimize_symtab(sym_tbl_t *);
+extern void Pbuild_file_symtab(struct ps_prochandle *, file_info_t *);
+extern ctf_file_t *Pbuild_file_ctf(struct ps_prochandle *, file_info_t *);
+extern map_info_t *Paddr2mptr(struct ps_prochandle *, uintptr_t);
+extern char *Pfindexec(struct ps_prochandle *, const char *,
+ int (*)(const char *, void *), void *);
+extern int getlwpstatus(struct ps_prochandle *, lwpid_t, lwpstatus_t *);
+int Pstopstatus(struct ps_prochandle *, long, uint32_t);
+
+extern int Padd_mapping(struct ps_prochandle *, off64_t, file_info_t *,
+ prmap_t *);
+extern void Psort_mappings(struct ps_prochandle *);
+
+/*
+ * Architecture-dependent definition of the breakpoint instruction.
+ */
+#if defined(sparc) || defined(__sparc)
+#define BPT ((instr_t)0x91d02001)
+#elif defined(__i386) || defined(__amd64)
+#define BPT ((instr_t)0xcc)
+#endif
+
+/*
+ * Simple convenience.
+ */
+#define TRUE 1
+#define FALSE 0
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PCONTROL_H */
diff --git a/usr/src/lib/libproc/common/Pcore.c b/usr/src/lib/libproc/common/Pcore.c
new file mode 100644
index 0000000000..99feb87ac4
--- /dev/null
+++ b/usr/src/lib/libproc/common/Pcore.c
@@ -0,0 +1,2003 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <sys/sysmacros.h>
+
+#include <alloca.h>
+#include <rtld_db.h>
+#include <libgen.h>
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <gelf.h>
+#include <stddef.h>
+
+#include "Pcontrol.h"
+#include "P32ton.h"
+#include "Putil.h"
+
+/*
+ * Pcore.c - Code to initialize a ps_prochandle from a core dump. We
+ * allocate an additional structure to hold information from the core
+ * file, and attach this to the standard ps_prochandle in place of the
+ * ability to examine /proc/<pid>/ files.
+ */
+
+/*
+ * Basic i/o function for reading and writing from the process address space
+ * stored in the core file and associated shared libraries. We compute the
+ * appropriate fd and offsets, and let the provided prw function do the rest.
+ */
+static ssize_t
+core_rw(struct ps_prochandle *P, void *buf, size_t n, uintptr_t addr,
+ ssize_t (*prw)(int, void *, size_t, off64_t))
+{
+ ssize_t resid = n;
+
+ while (resid != 0) {
+ map_info_t *mp = Paddr2mptr(P, addr);
+
+ uintptr_t mapoff;
+ ssize_t len;
+ off64_t off;
+ int fd;
+
+ if (mp == NULL)
+ break; /* No mapping for this address */
+
+ if (mp->map_pmap.pr_mflags & MA_RESERVED1) {
+ if (mp->map_file == NULL || mp->map_file->file_fd < 0)
+ break; /* No file or file not open */
+
+ fd = mp->map_file->file_fd;
+ } else
+ fd = P->asfd;
+
+ mapoff = addr - mp->map_pmap.pr_vaddr;
+ len = MIN(resid, mp->map_pmap.pr_size - mapoff);
+ off = mp->map_offset + mapoff;
+
+ if ((len = prw(fd, buf, len, off)) <= 0)
+ break;
+
+ resid -= len;
+ addr += len;
+ buf = (char *)buf + len;
+ }
+
+ /*
+ * Important: Be consistent with the behavior of i/o on the as file:
+ * writing to an invalid address yields EIO; reading from an invalid
+ * address falls through to returning success and zero bytes.
+ */
+ if (resid == n && n != 0 && prw != pread64) {
+ errno = EIO;
+ return (-1);
+ }
+
+ return (n - resid);
+}
+
+static ssize_t
+Pread_core(struct ps_prochandle *P, void *buf, size_t n, uintptr_t addr)
+{
+ return (core_rw(P, buf, n, addr, pread64));
+}
+
+static ssize_t
+Pwrite_core(struct ps_prochandle *P, const void *buf, size_t n, uintptr_t addr)
+{
+ 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 };
+
+/*
+ * Return the lwp_info_t for the given lwpid. If no such lwpid has been
+ * encountered yet, allocate a new structure and return a pointer to it.
+ * Create a list of lwp_info_t structures sorted in decreasing lwp_id order.
+ */
+static lwp_info_t *
+lwpid2info(struct ps_prochandle *P, lwpid_t id)
+{
+ lwp_info_t *lwp = list_next(&P->core->core_lwp_head);
+ lwp_info_t *next;
+ uint_t i;
+
+ for (i = 0; i < P->core->core_nlwp; i++, lwp = list_next(lwp)) {
+ if (lwp->lwp_id == id) {
+ P->core->core_lwp = lwp;
+ return (lwp);
+ }
+ if (lwp->lwp_id < id) {
+ break;
+ }
+ }
+
+ next = lwp;
+ if ((lwp = calloc(1, sizeof (lwp_info_t))) == NULL)
+ return (NULL);
+
+ list_link(lwp, next);
+ lwp->lwp_id = id;
+
+ P->core->core_lwp = lwp;
+ P->core->core_nlwp++;
+
+ return (lwp);
+}
+
+/*
+ * The core file itself contains a series of NOTE segments containing saved
+ * structures from /proc at the time the process died. For each note we
+ * comprehend, we define a function to read it in from the core file,
+ * convert it to our native data model if necessary, and store it inside
+ * the ps_prochandle. Each function is invoked by Pfgrab_core() with the
+ * seek pointer on P->asfd positioned appropriately. We populate a table
+ * of pointers to these note functions below.
+ */
+
+static int
+note_pstatus(struct ps_prochandle *P, size_t nbytes)
+{
+#ifdef _LP64
+ if (P->core->core_dmodel == PR_MODEL_ILP32) {
+ pstatus32_t ps32;
+
+ if (nbytes < sizeof (pstatus32_t) ||
+ read(P->asfd, &ps32, sizeof (ps32)) != sizeof (ps32))
+ goto err;
+
+ pstatus_32_to_n(&ps32, &P->status);
+
+ } else
+#endif
+ if (nbytes < sizeof (pstatus_t) ||
+ read(P->asfd, &P->status, sizeof (pstatus_t)) != sizeof (pstatus_t))
+ goto err;
+
+ P->orig_status = P->status;
+ P->pid = P->status.pr_pid;
+
+ return (0);
+
+err:
+ dprintf("Pgrab_core: failed to read NT_PSTATUS\n");
+ return (-1);
+}
+
+static int
+note_lwpstatus(struct ps_prochandle *P, size_t nbytes)
+{
+ lwp_info_t *lwp;
+ lwpstatus_t lps;
+
+#ifdef _LP64
+ if (P->core->core_dmodel == PR_MODEL_ILP32) {
+ lwpstatus32_t l32;
+
+ if (nbytes < sizeof (lwpstatus32_t) ||
+ read(P->asfd, &l32, sizeof (l32)) != sizeof (l32))
+ goto err;
+
+ lwpstatus_32_to_n(&l32, &lps);
+ } else
+#endif
+ if (nbytes < sizeof (lwpstatus_t) ||
+ read(P->asfd, &lps, sizeof (lps)) != sizeof (lps))
+ goto err;
+
+ if ((lwp = lwpid2info(P, lps.pr_lwpid)) == NULL) {
+ dprintf("Pgrab_core: failed to add NT_LWPSTATUS\n");
+ return (-1);
+ }
+
+ /*
+ * Erase a useless and confusing artifact of the kernel implementation:
+ * the lwps which did *not* create the core will show SIGKILL. We can
+ * be assured this is bogus because SIGKILL can't produce core files.
+ */
+ if (lps.pr_cursig == SIGKILL)
+ lps.pr_cursig = 0;
+
+ (void) memcpy(&lwp->lwp_status, &lps, sizeof (lps));
+ return (0);
+
+err:
+ dprintf("Pgrab_core: failed to read NT_LWPSTATUS\n");
+ return (-1);
+}
+
+static int
+note_psinfo(struct ps_prochandle *P, size_t nbytes)
+{
+#ifdef _LP64
+ if (P->core->core_dmodel == PR_MODEL_ILP32) {
+ psinfo32_t ps32;
+
+ if (nbytes < sizeof (psinfo32_t) ||
+ read(P->asfd, &ps32, sizeof (ps32)) != sizeof (ps32))
+ goto err;
+
+ psinfo_32_to_n(&ps32, &P->psinfo);
+ } else
+#endif
+ if (nbytes < sizeof (psinfo_t) ||
+ read(P->asfd, &P->psinfo, sizeof (psinfo_t)) != sizeof (psinfo_t))
+ goto err;
+
+ dprintf("pr_fname = <%s>\n", P->psinfo.pr_fname);
+ dprintf("pr_psargs = <%s>\n", P->psinfo.pr_psargs);
+ dprintf("pr_wstat = 0x%x\n", P->psinfo.pr_wstat);
+
+ return (0);
+
+err:
+ dprintf("Pgrab_core: failed to read NT_PSINFO\n");
+ return (-1);
+}
+
+static int
+note_lwpsinfo(struct ps_prochandle *P, size_t nbytes)
+{
+ lwp_info_t *lwp;
+ lwpsinfo_t lps;
+
+#ifdef _LP64
+ if (P->core->core_dmodel == PR_MODEL_ILP32) {
+ lwpsinfo32_t l32;
+
+ if (nbytes < sizeof (lwpsinfo32_t) ||
+ read(P->asfd, &l32, sizeof (l32)) != sizeof (l32))
+ goto err;
+
+ lwpsinfo_32_to_n(&l32, &lps);
+ } else
+#endif
+ if (nbytes < sizeof (lwpsinfo_t) ||
+ read(P->asfd, &lps, sizeof (lps)) != sizeof (lps))
+ goto err;
+
+ if ((lwp = lwpid2info(P, lps.pr_lwpid)) == NULL) {
+ dprintf("Pgrab_core: failed to add NT_LWPSINFO\n");
+ return (-1);
+ }
+
+ (void) memcpy(&lwp->lwp_psinfo, &lps, sizeof (lps));
+ return (0);
+
+err:
+ dprintf("Pgrab_core: failed to read NT_LWPSINFO\n");
+ return (-1);
+}
+
+static int
+note_platform(struct ps_prochandle *P, size_t nbytes)
+{
+ char *plat;
+
+ if (P->core->core_platform != NULL)
+ return (0); /* Already seen */
+
+ if (nbytes != 0 && ((plat = malloc(nbytes + 1)) != NULL)) {
+ if (read(P->asfd, plat, nbytes) != nbytes) {
+ dprintf("Pgrab_core: failed to read NT_PLATFORM\n");
+ free(plat);
+ return (-1);
+ }
+ plat[nbytes - 1] = '\0';
+ P->core->core_platform = plat;
+ }
+
+ return (0);
+}
+
+static int
+note_utsname(struct ps_prochandle *P, size_t nbytes)
+{
+ size_t ubytes = sizeof (struct utsname);
+ struct utsname *utsp;
+
+ if (P->core->core_uts != NULL || nbytes < ubytes)
+ return (0); /* Already seen or bad size */
+
+ if ((utsp = malloc(ubytes)) == NULL)
+ return (-1);
+
+ if (read(P->asfd, utsp, ubytes) != ubytes) {
+ dprintf("Pgrab_core: failed to read NT_UTSNAME\n");
+ free(utsp);
+ return (-1);
+ }
+
+ if (_libproc_debug) {
+ dprintf("uts.sysname = \"%s\"\n", utsp->sysname);
+ dprintf("uts.nodename = \"%s\"\n", utsp->nodename);
+ dprintf("uts.release = \"%s\"\n", utsp->release);
+ dprintf("uts.version = \"%s\"\n", utsp->version);
+ dprintf("uts.machine = \"%s\"\n", utsp->machine);
+ }
+
+ P->core->core_uts = utsp;
+ return (0);
+}
+
+static int
+note_content(struct ps_prochandle *P, size_t nbytes)
+{
+ core_content_t content;
+
+ if (sizeof (P->core->core_content) != nbytes)
+ return (-1);
+
+ if (read(P->asfd, &content, sizeof (content)) != sizeof (content))
+ return (-1);
+
+ P->core->core_content = content;
+
+ dprintf("core content = %llx\n", content);
+
+ return (0);
+}
+
+static int
+note_cred(struct ps_prochandle *P, size_t nbytes)
+{
+ prcred_t *pcrp;
+ int ngroups;
+ const size_t min_size = sizeof (prcred_t) - sizeof (gid_t);
+
+ /*
+ * We allow for prcred_t notes that are actually smaller than a
+ * prcred_t since the last member isn't essential if there are
+ * 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)
+ return (0); /* Already seen or bad size */
+
+ ngroups = (nbytes - min_size) / sizeof (gid_t);
+ nbytes = sizeof (prcred_t) + (ngroups - 1) * sizeof (gid_t);
+
+ if ((pcrp = malloc(nbytes)) == NULL)
+ return (-1);
+
+ if (read(P->asfd, pcrp, nbytes) != nbytes) {
+ dprintf("Pgrab_core: failed to read NT_PRCRED\n");
+ free(pcrp);
+ return (-1);
+ }
+
+ if (pcrp->pr_ngroups > ngroups) {
+ dprintf("pr_ngroups = %d; resetting to %d based on note size\n",
+ pcrp->pr_ngroups, ngroups);
+ pcrp->pr_ngroups = ngroups;
+ }
+
+ P->core->core_cred = pcrp;
+ return (0);
+}
+
+#if defined(__i386) || defined(__amd64)
+static int
+note_ldt(struct ps_prochandle *P, size_t nbytes)
+{
+ struct ssd *pldt;
+ uint_t nldt;
+
+ if (P->core->core_ldt != NULL || nbytes < sizeof (struct ssd))
+ return (0); /* Already seen or bad size */
+
+ nldt = nbytes / sizeof (struct ssd);
+ nbytes = nldt * sizeof (struct ssd);
+
+ if ((pldt = malloc(nbytes)) == NULL)
+ return (-1);
+
+ if (read(P->asfd, pldt, nbytes) != nbytes) {
+ dprintf("Pgrab_core: failed to read NT_LDT\n");
+ free(pldt);
+ return (-1);
+ }
+
+ P->core->core_ldt = pldt;
+ P->core->core_nldt = nldt;
+ return (0);
+}
+#endif /* __i386 */
+
+static int
+note_priv(struct ps_prochandle *P, size_t nbytes)
+{
+ prpriv_t *pprvp;
+
+ if (P->core->core_priv != NULL || nbytes < sizeof (prpriv_t))
+ return (0); /* Already seen or bad size */
+
+ if ((pprvp = malloc(nbytes)) == NULL)
+ return (-1);
+
+ if (read(P->asfd, pprvp, nbytes) != nbytes) {
+ dprintf("Pgrab_core: failed to read NT_PRPRIV\n");
+ free(pprvp);
+ return (-1);
+ }
+
+ P->core->core_priv = pprvp;
+ P->core->core_priv_size = nbytes;
+ return (0);
+}
+
+static int
+note_priv_info(struct ps_prochandle *P, size_t nbytes)
+{
+ extern void *__priv_parse_info();
+ priv_impl_info_t *ppii;
+
+ if (P->core->core_privinfo != NULL ||
+ nbytes < sizeof (priv_impl_info_t))
+ return (0); /* Already seen or bad size */
+
+ if ((ppii = malloc(nbytes)) == NULL)
+ return (-1);
+
+ if (read(P->asfd, ppii, nbytes) != nbytes ||
+ PRIV_IMPL_INFO_SIZE(ppii) != nbytes) {
+ dprintf("Pgrab_core: failed to read NT_PRPRIVINFO\n");
+ free(ppii);
+ return (-1);
+ }
+
+ P->core->core_privinfo = __priv_parse_info(ppii);
+ P->core->core_ppii = ppii;
+ return (0);
+}
+
+static int
+note_zonename(struct ps_prochandle *P, size_t nbytes)
+{
+ char *zonename;
+
+ if (P->core->core_zonename != NULL)
+ return (0); /* Already seen */
+
+ if (nbytes != 0) {
+ if ((zonename = malloc(nbytes)) == NULL)
+ return (-1);
+ if (read(P->asfd, zonename, nbytes) != nbytes) {
+ dprintf("Pgrab_core: failed to read NT_ZONENAME\n");
+ free(zonename);
+ return (-1);
+ }
+ zonename[nbytes - 1] = '\0';
+ P->core->core_zonename = zonename;
+ }
+
+ return (0);
+}
+
+static int
+note_auxv(struct ps_prochandle *P, size_t nbytes)
+{
+ size_t n, i;
+
+#ifdef _LP64
+ if (P->core->core_dmodel == PR_MODEL_ILP32) {
+ auxv32_t *a32;
+
+ n = nbytes / sizeof (auxv32_t);
+ nbytes = n * sizeof (auxv32_t);
+ a32 = alloca(nbytes);
+
+ if (read(P->asfd, a32, nbytes) != nbytes) {
+ dprintf("Pgrab_core: failed to read NT_AUXV\n");
+ return (-1);
+ }
+
+ if ((P->auxv = malloc(sizeof (auxv_t) * (n + 1))) == NULL)
+ return (-1);
+
+ for (i = 0; i < n; i++)
+ auxv_32_to_n(&a32[i], &P->auxv[i]);
+
+ } else {
+#endif
+ n = nbytes / sizeof (auxv_t);
+ nbytes = n * sizeof (auxv_t);
+
+ if ((P->auxv = malloc(nbytes + sizeof (auxv_t))) == NULL)
+ return (-1);
+
+ if (read(P->asfd, P->auxv, nbytes) != nbytes) {
+ free(P->auxv);
+ P->auxv = NULL;
+ return (-1);
+ }
+#ifdef _LP64
+ }
+#endif
+
+ if (_libproc_debug) {
+ for (i = 0; i < n; i++) {
+ dprintf("P->auxv[%lu] = ( %d, 0x%lx )\n", (ulong_t)i,
+ P->auxv[i].a_type, P->auxv[i].a_un.a_val);
+ }
+ }
+
+ /*
+ * Defensive coding for loops which depend upon the auxv array being
+ * terminated by an AT_NULL element; in each case, we've allocated
+ * P->auxv to have an additional element which we force to be AT_NULL.
+ */
+ P->auxv[n].a_type = AT_NULL;
+ P->auxv[n].a_un.a_val = 0L;
+ P->nauxv = (int)n;
+
+ return (0);
+}
+
+#ifdef __sparc
+static int
+note_xreg(struct ps_prochandle *P, size_t nbytes)
+{
+ lwp_info_t *lwp = P->core->core_lwp;
+ size_t xbytes = sizeof (prxregset_t);
+ prxregset_t *xregs;
+
+ if (lwp == NULL || lwp->lwp_xregs != NULL || nbytes < xbytes)
+ return (0); /* No lwp yet, already seen, or bad size */
+
+ if ((xregs = malloc(xbytes)) == NULL)
+ return (-1);
+
+ if (read(P->asfd, xregs, xbytes) != xbytes) {
+ dprintf("Pgrab_core: failed to read NT_PRXREG\n");
+ free(xregs);
+ return (-1);
+ }
+
+ lwp->lwp_xregs = xregs;
+ return (0);
+}
+
+static int
+note_gwindows(struct ps_prochandle *P, size_t nbytes)
+{
+ lwp_info_t *lwp = P->core->core_lwp;
+
+ if (lwp == NULL || lwp->lwp_gwins != NULL || nbytes == 0)
+ return (0); /* No lwp yet or already seen or no data */
+
+ if ((lwp->lwp_gwins = malloc(sizeof (gwindows_t))) == NULL)
+ return (-1);
+
+ /*
+ * Since the amount of gwindows data varies with how many windows were
+ * actually saved, we just read up to the minimum of the note size
+ * and the size of the gwindows_t type. It doesn't matter if the read
+ * fails since we have to zero out gwindows first anyway.
+ */
+#ifdef _LP64
+ if (P->core->core_dmodel == PR_MODEL_ILP32) {
+ gwindows32_t g32;
+
+ (void) memset(&g32, 0, sizeof (g32));
+ (void) read(P->asfd, &g32, MIN(nbytes, sizeof (g32)));
+ gwindows_32_to_n(&g32, lwp->lwp_gwins);
+
+ } else {
+#endif
+ (void) memset(lwp->lwp_gwins, 0, sizeof (gwindows_t));
+ (void) read(P->asfd, lwp->lwp_gwins,
+ MIN(nbytes, sizeof (gwindows_t)));
+#ifdef _LP64
+ }
+#endif
+ return (0);
+}
+
+#ifdef __sparcv9
+static int
+note_asrs(struct ps_prochandle *P, size_t nbytes)
+{
+ lwp_info_t *lwp = P->core->core_lwp;
+ int64_t *asrs;
+
+ if (lwp == NULL || lwp->lwp_asrs != NULL || nbytes < sizeof (asrset_t))
+ return (0); /* No lwp yet, already seen, or bad size */
+
+ if ((asrs = malloc(sizeof (asrset_t))) == NULL)
+ return (-1);
+
+ if (read(P->asfd, asrs, sizeof (asrset_t)) != sizeof (asrset_t)) {
+ dprintf("Pgrab_core: failed to read NT_ASRS\n");
+ free(asrs);
+ return (-1);
+ }
+
+ lwp->lwp_asrs = asrs;
+ return (0);
+}
+#endif /* __sparcv9 */
+#endif /* __sparc */
+
+/*ARGSUSED*/
+static int
+note_notsup(struct ps_prochandle *P, size_t nbytes)
+{
+ dprintf("skipping unsupported note type\n");
+ return (0);
+}
+
+/*
+ * Populate a table of function pointers indexed by Note type with our
+ * functions to process each type of core file note:
+ */
+static int (*nhdlrs[])(struct ps_prochandle *, size_t) = {
+ note_notsup, /* 0 unassigned */
+ note_notsup, /* 1 NT_PRSTATUS (old) */
+ note_notsup, /* 2 NT_PRFPREG (old) */
+ note_notsup, /* 3 NT_PRPSINFO (old) */
+#ifdef __sparc
+ note_xreg, /* 4 NT_PRXREG */
+#else
+ note_notsup, /* 4 NT_PRXREG */
+#endif
+ note_platform, /* 5 NT_PLATFORM */
+ note_auxv, /* 6 NT_AUXV */
+#ifdef __sparc
+ note_gwindows, /* 7 NT_GWINDOWS */
+#ifdef __sparcv9
+ note_asrs, /* 8 NT_ASRS */
+#else
+ note_notsup, /* 8 NT_ASRS */
+#endif
+#else
+ note_notsup, /* 7 NT_GWINDOWS */
+ note_notsup, /* 8 NT_ASRS */
+#endif
+#if defined(__i386) || defined(__amd64)
+ note_ldt, /* 9 NT_LDT */
+#else
+ note_notsup, /* 9 NT_LDT */
+#endif
+ note_pstatus, /* 10 NT_PSTATUS */
+ note_notsup, /* 11 unassigned */
+ note_notsup, /* 12 unassigned */
+ note_psinfo, /* 13 NT_PSINFO */
+ note_cred, /* 14 NT_PRCRED */
+ note_utsname, /* 15 NT_UTSNAME */
+ note_lwpstatus, /* 16 NT_LWPSTATUS */
+ note_lwpsinfo, /* 17 NT_LWPSINFO */
+ note_priv, /* 18 NT_PRPRIV */
+ note_priv_info, /* 19 NT_PRPRIVINFO */
+ note_content, /* 20 NT_CONTENT */
+ note_zonename, /* 21 NT_ZONENAME */
+};
+
+/*
+ * Add information on the address space mapping described by the given
+ * PT_LOAD program header. We fill in more information on the mapping later.
+ */
+static int
+core_add_mapping(struct ps_prochandle *P, GElf_Phdr *php)
+{
+ int err = 0;
+ prmap_t pmap;
+
+ dprintf("mapping base %llx filesz %llu memsz %llu offset %llu\n",
+ (u_longlong_t)php->p_vaddr, (u_longlong_t)php->p_filesz,
+ (u_longlong_t)php->p_memsz, (u_longlong_t)php->p_offset);
+
+ pmap.pr_vaddr = (uintptr_t)php->p_vaddr;
+ pmap.pr_size = php->p_memsz;
+
+ /*
+ * If Pgcore() or elfcore() fail to write a mapping, they will set
+ * PF_SUNW_FAILURE in the Phdr and try to stash away the errno for us.
+ */
+ if (php->p_flags & PF_SUNW_FAILURE) {
+ (void) pread64(P->asfd, &err,
+ sizeof (err), (off64_t)php->p_offset);
+
+ Perror_printf(P, "core file data for mapping at %p not saved: "
+ "%s\n", (void *)(uintptr_t)php->p_vaddr, strerror(err));
+ dprintf("core file data for mapping at %p not saved: %s\n",
+ (void *)(uintptr_t)php->p_vaddr, strerror(err));
+
+ } else if (php->p_filesz != 0 && php->p_offset >= P->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 "
+ "at %p is missing\n", (void *)(uintptr_t)php->p_vaddr);
+ }
+
+ /*
+ * The mapping name and offset will hopefully be filled in
+ * by the librtld_db agent. Unfortunately, if it isn't a
+ * shared library mapping, this information is gone forever.
+ */
+ pmap.pr_mapname[0] = '\0';
+ pmap.pr_offset = 0;
+
+ pmap.pr_mflags = 0;
+ if (php->p_flags & PF_R)
+ pmap.pr_mflags |= MA_READ;
+ if (php->p_flags & PF_W)
+ pmap.pr_mflags |= MA_WRITE;
+ if (php->p_flags & PF_X)
+ pmap.pr_mflags |= MA_EXEC;
+
+ if (php->p_filesz == 0)
+ pmap.pr_mflags |= MA_RESERVED1;
+
+ /*
+ * At the time of adding this mapping, we just zero the pagesize.
+ * Once we've processed more of the core file, we'll have the
+ * pagesize from the auxv's AT_PAGESZ element and we can fill this in.
+ */
+ pmap.pr_pagesize = 0;
+
+ /*
+ * Unfortunately whether or not the mapping was a System V
+ * shared memory segment is lost. We use -1 to mark it as not shm.
+ */
+ pmap.pr_shmid = -1;
+
+ return (Padd_mapping(P, php->p_offset, NULL, &pmap));
+}
+
+/*
+ * Given a virtual address, name the mapping at that address using the
+ * specified name, and return the map_info_t pointer.
+ */
+static map_info_t *
+core_name_mapping(struct ps_prochandle *P, uintptr_t addr, const char *name)
+{
+ map_info_t *mp = Paddr2mptr(P, addr);
+
+ if (mp != NULL) {
+ (void) strncpy(mp->map_pmap.pr_mapname, name, PRMAPSZ);
+ mp->map_pmap.pr_mapname[PRMAPSZ - 1] = '\0';
+ }
+
+ return (mp);
+}
+
+/*
+ * libproc uses libelf for all of its symbol table manipulation. This function
+ * takes a symbol table and string table from a core file and places them
+ * in a memory backed elf file.
+ */
+static void
+fake_up_symtab(struct ps_prochandle *P, GElf_Ehdr *ehdr,
+ GElf_Shdr *symtab, GElf_Shdr *strtab)
+{
+ size_t size;
+ off64_t off, base;
+ map_info_t *mp;
+ file_info_t *fp;
+ Elf_Scn *scn;
+ Elf_Data *data;
+
+ if (symtab->sh_addr == 0 ||
+ (mp = Paddr2mptr(P, symtab->sh_addr)) == NULL ||
+ (fp = mp->map_file) == NULL ||
+ fp->file_symtab.sym_data != NULL)
+ return;
+
+ if (P->status.pr_dmodel == PR_MODEL_ILP32) {
+ struct {
+ Elf32_Ehdr ehdr;
+ Elf32_Shdr shdr[3];
+ char data[1];
+ } *b;
+
+ base = sizeof (b->ehdr) + sizeof (b->shdr);
+ size = base + symtab->sh_size + strtab->sh_size;
+
+ if ((b = calloc(1, size)) == NULL)
+ return;
+
+ (void) memcpy(&b->ehdr, ehdr, offsetof(GElf_Ehdr, e_entry));
+ b->ehdr.e_ehsize = sizeof (b->ehdr);
+ b->ehdr.e_shoff = sizeof (b->ehdr);
+ b->ehdr.e_shentsize = sizeof (b->shdr[0]);
+ b->ehdr.e_shnum = 3;
+ off = 0;
+
+ b->shdr[1].sh_size = symtab->sh_size;
+ b->shdr[1].sh_type = SHT_SYMTAB;
+ b->shdr[1].sh_offset = off + base;
+ b->shdr[1].sh_entsize = sizeof (Elf32_Sym);
+ b->shdr[1].sh_link = 2;
+ b->shdr[1].sh_info = symtab->sh_info;
+ b->shdr[1].sh_addralign = symtab->sh_addralign;
+
+ if (pread64(P->asfd, &b->data[off], b->shdr[1].sh_size,
+ symtab->sh_offset) != b->shdr[1].sh_size) {
+ free(b);
+ return;
+ }
+
+ off += b->shdr[1].sh_size;
+
+ b->shdr[2].sh_flags = SHF_STRINGS;
+ b->shdr[2].sh_size = strtab->sh_size;
+ b->shdr[2].sh_type = SHT_STRTAB;
+ b->shdr[2].sh_offset = off + base;
+ b->shdr[2].sh_info = strtab->sh_info;
+ b->shdr[2].sh_addralign = 1;
+
+ if (pread64(P->asfd, &b->data[off], b->shdr[2].sh_size,
+ strtab->sh_offset) != b->shdr[2].sh_size) {
+ free(b);
+ return;
+ }
+
+ off += b->shdr[2].sh_size;
+
+ fp->file_symtab.sym_elf = elf_memory((char *)b, size);
+ if (fp->file_symtab.sym_elf == NULL) {
+ free(b);
+ return;
+ }
+
+ fp->file_symtab.sym_elfmem = b;
+#ifdef _LP64
+ } else {
+ struct {
+ Elf64_Ehdr ehdr;
+ Elf64_Shdr shdr[3];
+ char data[1];
+ } *b;
+
+ base = sizeof (b->ehdr) + sizeof (b->shdr);
+ size = base + symtab->sh_size + strtab->sh_size;
+
+ if ((b = calloc(1, size)) == NULL)
+ return;
+
+ (void) memcpy(&b->ehdr, ehdr, offsetof(GElf_Ehdr, e_entry));
+ b->ehdr.e_ehsize = sizeof (b->ehdr);
+ b->ehdr.e_shoff = sizeof (b->ehdr);
+ b->ehdr.e_shentsize = sizeof (b->shdr[0]);
+ b->ehdr.e_shnum = 3;
+ off = 0;
+
+ b->shdr[1].sh_size = symtab->sh_size;
+ b->shdr[1].sh_type = SHT_SYMTAB;
+ b->shdr[1].sh_offset = off + base;
+ b->shdr[1].sh_entsize = sizeof (Elf64_Sym);
+ b->shdr[1].sh_link = 2;
+ b->shdr[1].sh_info = symtab->sh_info;
+ b->shdr[1].sh_addralign = symtab->sh_addralign;
+
+ if (pread64(P->asfd, &b->data[off], b->shdr[1].sh_size,
+ symtab->sh_offset) != b->shdr[1].sh_size) {
+ free(b);
+ return;
+ }
+
+ off += b->shdr[1].sh_size;
+
+ b->shdr[2].sh_flags = SHF_STRINGS;
+ b->shdr[2].sh_size = strtab->sh_size;
+ b->shdr[2].sh_type = SHT_STRTAB;
+ b->shdr[2].sh_offset = off + base;
+ b->shdr[2].sh_info = strtab->sh_info;
+ b->shdr[2].sh_addralign = 1;
+
+ if (pread64(P->asfd, &b->data[off], b->shdr[2].sh_size,
+ strtab->sh_offset) != b->shdr[2].sh_size) {
+ free(b);
+ return;
+ }
+
+ off += b->shdr[2].sh_size;
+
+ fp->file_symtab.sym_elf = elf_memory((char *)b, size);
+ if (fp->file_symtab.sym_elf == NULL) {
+ free(b);
+ return;
+ }
+
+ fp->file_symtab.sym_elfmem = b;
+#endif
+ }
+
+ if ((scn = elf_getscn(fp->file_symtab.sym_elf, 1)) == NULL ||
+ (fp->file_symtab.sym_data = elf_getdata(scn, NULL)) == NULL ||
+ (scn = elf_getscn(fp->file_symtab.sym_elf, 2)) == NULL ||
+ (data = elf_getdata(scn, NULL)) == NULL)
+ goto err;
+
+ fp->file_symtab.sym_strs = data->d_buf;
+ fp->file_symtab.sym_strsz = data->d_size;
+ fp->file_symtab.sym_symn = symtab->sh_size / symtab->sh_entsize;
+ fp->file_symtab.sym_hdr = *symtab;
+ fp->file_symtab.sym_strhdr = *strtab;
+
+ optimize_symtab(&fp->file_symtab);
+
+ return;
+err:
+ (void) elf_end(fp->file_symtab.sym_elf);
+ free(fp->file_symtab.sym_elfmem);
+ fp->file_symtab.sym_elf = NULL;
+ fp->file_symtab.sym_elfmem = NULL;
+}
+
+static void
+core_ehdr_to_gelf(const Elf32_Ehdr *src, GElf_Ehdr *dst)
+{
+ (void) memcpy(dst->e_ident, src->e_ident, EI_NIDENT);
+ dst->e_type = src->e_type;
+ dst->e_machine = src->e_machine;
+ dst->e_version = src->e_version;
+ dst->e_entry = (Elf64_Addr)src->e_entry;
+ dst->e_phoff = (Elf64_Off)src->e_phoff;
+ dst->e_shoff = (Elf64_Off)src->e_shoff;
+ dst->e_flags = src->e_flags;
+ dst->e_ehsize = src->e_ehsize;
+ dst->e_phentsize = src->e_phentsize;
+ dst->e_phnum = src->e_phnum;
+ dst->e_shentsize = src->e_shentsize;
+ dst->e_shnum = src->e_shnum;
+ dst->e_shstrndx = src->e_shstrndx;
+}
+
+static void
+core_phdr_to_gelf(const Elf32_Phdr *src, GElf_Phdr *dst)
+{
+ dst->p_type = src->p_type;
+ dst->p_flags = src->p_flags;
+ dst->p_offset = (Elf64_Off)src->p_offset;
+ dst->p_vaddr = (Elf64_Addr)src->p_vaddr;
+ dst->p_paddr = (Elf64_Addr)src->p_paddr;
+ dst->p_filesz = (Elf64_Xword)src->p_filesz;
+ dst->p_memsz = (Elf64_Xword)src->p_memsz;
+ dst->p_align = (Elf64_Xword)src->p_align;
+}
+
+static void
+core_shdr_to_gelf(const Elf32_Shdr *src, GElf_Shdr *dst)
+{
+ dst->sh_name = src->sh_name;
+ dst->sh_type = src->sh_type;
+ dst->sh_flags = (Elf64_Xword)src->sh_flags;
+ dst->sh_addr = (Elf64_Addr)src->sh_addr;
+ dst->sh_offset = (Elf64_Off)src->sh_offset;
+ dst->sh_size = (Elf64_Xword)src->sh_size;
+ dst->sh_link = src->sh_link;
+ dst->sh_info = src->sh_info;
+ dst->sh_addralign = (Elf64_Xword)src->sh_addralign;
+ dst->sh_entsize = (Elf64_Xword)src->sh_entsize;
+}
+
+/*
+ * Perform elf_begin on efp->e_fd and verify the ELF file's type and class.
+ */
+static int
+core_elf_fdopen(elf_file_t *efp, GElf_Half type, int *perr)
+{
+#ifdef _BIG_ENDIAN
+ uchar_t order = ELFDATA2MSB;
+#else
+ uchar_t order = ELFDATA2LSB;
+#endif
+ Elf32_Ehdr e32;
+ int is_noelf = -1;
+ int isa_err = 0;
+
+ /*
+ * Because 32-bit libelf cannot deal with large files, we need to read,
+ * check, and convert the file header manually in case type == ET_CORE.
+ */
+ if (pread64(efp->e_fd, &e32, sizeof (e32), 0) != sizeof (e32)) {
+ if (perr != NULL)
+ *perr = G_FORMAT;
+ goto err;
+ }
+ if ((is_noelf = memcmp(&e32.e_ident[EI_MAG0], ELFMAG, SELFMAG)) != 0 ||
+ e32.e_type != type || (isa_err = (e32.e_ident[EI_DATA] != order)) ||
+ e32.e_version != EV_CURRENT) {
+ if (perr != NULL) {
+ if (is_noelf == 0 && isa_err) {
+ *perr = G_ISAINVAL;
+ } else {
+ *perr = G_FORMAT;
+ }
+ }
+ goto err;
+ }
+
+ /*
+ * If the file is 64-bit and we are 32-bit, fail with G_LP64. If the
+ * file is 64-bit and we are 64-bit, re-read the header as a Elf64_Ehdr.
+ * Otherwise, the file is 32-bit, so convert e32 to a GElf_Ehdr.
+ */
+ if (e32.e_ident[EI_CLASS] == ELFCLASS64) {
+#ifdef _LP64
+ if (pread64(efp->e_fd, &efp->e_hdr,
+ sizeof (GElf_Ehdr), 0) != sizeof (GElf_Ehdr)) {
+ if (perr != NULL)
+ *perr = G_FORMAT;
+ goto err;
+ }
+#else /* _LP64 */
+ if (perr != NULL)
+ *perr = G_LP64;
+ goto err;
+#endif /* _LP64 */
+ } else
+ core_ehdr_to_gelf(&e32, &efp->e_hdr);
+
+ /*
+ * The libelf implementation was never ported to be large-file aware.
+ * This is typically not a problem for your average executable or
+ * shared library, but a large 32-bit core file can exceed 2GB in size.
+ * So if type is ET_CORE, we don't bother doing elf_begin; the code
+ * in Pfgrab_core() below will do its own i/o and struct conversion.
+ */
+
+ if (type == ET_CORE) {
+ efp->e_elf = NULL;
+ return (0);
+ }
+
+ if ((efp->e_elf = elf_begin(efp->e_fd, ELF_C_READ, NULL)) == NULL) {
+ if (perr != NULL)
+ *perr = G_ELF;
+ goto err;
+ }
+
+ return (0);
+
+err:
+ efp->e_elf = NULL;
+ return (-1);
+}
+
+/*
+ * Open the specified file and then do a core_elf_fdopen on it.
+ */
+static int
+core_elf_open(elf_file_t *efp, const char *path, GElf_Half type, int *perr)
+{
+ (void) memset(efp, 0, sizeof (elf_file_t));
+
+ if ((efp->e_fd = open64(path, O_RDONLY)) >= 0) {
+ if (core_elf_fdopen(efp, type, perr) == 0)
+ return (0);
+
+ (void) close(efp->e_fd);
+ efp->e_fd = -1;
+ }
+
+ return (-1);
+}
+
+/*
+ * Close the ELF handle and file descriptor.
+ */
+static void
+core_elf_close(elf_file_t *efp)
+{
+ if (efp->e_elf != NULL) {
+ (void) elf_end(efp->e_elf);
+ efp->e_elf = NULL;
+ }
+
+ if (efp->e_fd != -1) {
+ (void) close(efp->e_fd);
+ efp->e_fd = -1;
+ }
+}
+
+/*
+ * Given an ELF file for a statically linked executable, locate the likely
+ * primary text section and fill in rl_base with its virtual address.
+ */
+static map_info_t *
+core_find_text(struct ps_prochandle *P, Elf *elf, rd_loadobj_t *rlp)
+{
+ GElf_Ehdr ehdr;
+ GElf_Phdr phdr;
+ uint_t i;
+
+ if (gelf_getehdr(elf, &ehdr) != NULL) {
+ for (i = 0; i < ehdr.e_phnum; i++) {
+ if (gelf_getphdr(elf, i, &phdr) != NULL &&
+ phdr.p_type == PT_LOAD && (phdr.p_flags & PF_X)) {
+ rlp->rl_base = phdr.p_vaddr;
+ return (Paddr2mptr(P, rlp->rl_base));
+ }
+ }
+ }
+
+ return (NULL);
+}
+
+/*
+ * Given an ELF file and the librtld_db structure corresponding to its primary
+ * text mapping, deduce where its data segment was loaded and fill in
+ * rl_data_base and prmap_t.pr_offset accordingly.
+ */
+static map_info_t *
+core_find_data(struct ps_prochandle *P, Elf *elf, rd_loadobj_t *rlp)
+{
+ GElf_Ehdr ehdr;
+ GElf_Phdr phdr;
+
+ map_info_t *mp;
+ uint_t i, pagemask;
+
+ rlp->rl_data_base = NULL;
+
+ /*
+ * Find the first loadable, writeable Phdr and compute rl_data_base
+ * as the virtual address at which is was loaded.
+ */
+ if (gelf_getehdr(elf, &ehdr) != NULL) {
+ for (i = 0; i < ehdr.e_phnum; i++) {
+ if (gelf_getphdr(elf, i, &phdr) != NULL &&
+ phdr.p_type == PT_LOAD && (phdr.p_flags & PF_W)) {
+
+ rlp->rl_data_base = phdr.p_vaddr;
+ if (ehdr.e_type == ET_DYN)
+ rlp->rl_data_base += rlp->rl_base;
+ break;
+ }
+ }
+ }
+
+ /*
+ * If we didn't find an appropriate phdr or if the address we
+ * computed has no mapping, return NULL.
+ */
+ if (rlp->rl_data_base == NULL ||
+ (mp = Paddr2mptr(P, rlp->rl_data_base)) == NULL)
+ return (NULL);
+
+ /*
+ * It wouldn't be procfs-related code if we didn't make use of
+ * unclean knowledge of segvn, even in userland ... the prmap_t's
+ * pr_offset field will be the segvn offset from mmap(2)ing the
+ * data section, which will be the file offset & PAGEMASK.
+ */
+ pagemask = ~(mp->map_pmap.pr_pagesize - 1);
+ mp->map_pmap.pr_offset = phdr.p_offset & pagemask;
+
+ return (mp);
+}
+
+/*
+ * Librtld_db agent callback for iterating over load object mappings.
+ * For each load object, we allocate a new file_info_t, perform naming,
+ * and attempt to construct a symbol table for the load object.
+ */
+static int
+core_iter_mapping(const rd_loadobj_t *rlp, struct ps_prochandle *P)
+{
+ char lname[PATH_MAX];
+ file_info_t *fp;
+ map_info_t *mp;
+
+ if (Pread_string(P, lname, PATH_MAX, (off_t)rlp->rl_nameaddr) <= 0) {
+ dprintf("failed to read name %p\n", (void *)rlp->rl_nameaddr);
+ return (1); /* Keep going; forget this if we can't get a name */
+ }
+
+ dprintf("rd_loadobj name = \"%s\" rl_base = %p\n",
+ lname, (void *)rlp->rl_base);
+
+ if ((mp = Paddr2mptr(P, rlp->rl_base)) == NULL) {
+ dprintf("no mapping for %p\n", (void *)rlp->rl_base);
+ return (1); /* No mapping; advance to next mapping */
+ }
+
+ if ((fp = mp->map_file) == NULL) {
+ if ((fp = malloc(sizeof (file_info_t))) == NULL) {
+ P->core->core_errno = errno;
+ dprintf("failed to malloc mapping data\n");
+ return (0); /* Abort */
+ }
+
+ (void) memset(fp, 0, sizeof (file_info_t));
+
+ list_link(fp, &P->file_head);
+ mp->map_file = fp;
+ P->num_files++;
+
+ fp->file_ref = 1;
+ fp->file_fd = -1;
+ }
+
+ if ((fp->file_lo = malloc(sizeof (rd_loadobj_t))) == NULL) {
+ P->core->core_errno = errno;
+ dprintf("failed to malloc mapping data\n");
+ return (0); /* Abort */
+ }
+
+ *fp->file_lo = *rlp;
+
+ if (fp->file_lname == NULL &&
+ strcmp(mp->map_pmap.pr_mapname, "a.out") == 0) {
+ /*
+ * Naming dance part 1: if the file_info_t is unnamed and
+ * it represents the main executable, name it after the
+ * execname.
+ */
+ fp->file_lname = P->execname ?
+ strdup(P->execname) : strdup("a.out");
+ }
+
+ if (lname[0] != '\0') {
+ /*
+ * Naming dance part 2: if we got a name from librtld_db, then
+ * copy this name to the prmap_t if it is unnamed. If the
+ * file_info_t is unnamed, name it after the lname.
+ */
+ if (mp->map_pmap.pr_mapname[0] == '\0') {
+ (void) strncpy(mp->map_pmap.pr_mapname, lname, PRMAPSZ);
+ mp->map_pmap.pr_mapname[PRMAPSZ - 1] = '\0';
+ }
+
+ if (fp->file_lname == NULL)
+ fp->file_lname = strdup(lname);
+
+ } else if (fp->file_lname == NULL &&
+ mp->map_pmap.pr_mapname[0] != '\0') {
+ /*
+ * Naming dance part 3: if the mapping is named and the
+ * file_info_t is not, name the file after the mapping.
+ */
+ fp->file_lname = strdup(mp->map_pmap.pr_mapname);
+ }
+
+ if (fp->file_lname != NULL)
+ fp->file_lbase = basename(fp->file_lname);
+
+ /*
+ * Associate the file and the mapping, and attempt to build
+ * a symbol table for this file.
+ */
+ (void) strcpy(fp->file_pname, mp->map_pmap.pr_mapname);
+ fp->file_map = mp;
+
+ Pbuild_file_symtab(P, fp);
+
+ if (fp->file_elf == NULL)
+ return (1); /* No symbol table; advance to next mapping */
+
+ /*
+ * Locate the start of a data segment associated with this file,
+ * name it after the file, and establish the mp->map_file link:
+ */
+ if ((mp = core_find_data(P, fp->file_elf, fp->file_lo)) != NULL) {
+ dprintf("found data for %s at %p (pr_offset 0x%llx)\n",
+ fp->file_pname, (void *)fp->file_lo->rl_data_base,
+ mp->map_pmap.pr_offset);
+
+ for (; mp < P->mappings + P->map_count; mp++) {
+ if (mp->map_pmap.pr_vaddr > fp->file_lo->rl_bend)
+ break;
+ if (mp->map_file == NULL) {
+ mp->map_file = fp;
+ fp->file_ref++;
+ }
+
+ if (!(mp->map_pmap.pr_mflags & MA_BREAK))
+ (void) strcpy(mp->map_pmap.pr_mapname,
+ fp->file_pname);
+ }
+ }
+
+ return (1); /* Advance to next mapping */
+}
+
+/*
+ * Callback function for Pfindexec(). In order to confirm a given pathname,
+ * we verify that we can open it as an ELF file of type ET_EXEC.
+ */
+static int
+core_exec_open(const char *path, void *efp)
+{
+ return (core_elf_open(efp, path, ET_EXEC, NULL) == 0);
+}
+
+/*
+ * Attempt to load any section headers found in the core file. If present,
+ * this will refer to non-loadable data added to the core file by the kernel
+ * based on coreadm(1M) settings, including CTF data and the symbol table.
+ */
+static void
+core_load_shdrs(struct ps_prochandle *P, elf_file_t *efp)
+{
+ GElf_Shdr *shp, *shdrs = NULL;
+ char *shstrtab = NULL;
+ ulong_t shstrtabsz;
+ const char *name;
+ map_info_t *mp;
+
+ size_t nbytes;
+ void *buf;
+ int i;
+
+ if (efp->e_hdr.e_shstrndx >= efp->e_hdr.e_shnum) {
+ dprintf("corrupt shstrndx (%u) exceeds shnum (%u)\n",
+ (uint_t)efp->e_hdr.e_shstrndx, (uint_t)efp->e_hdr.e_shnum);
+ return;
+ }
+
+ /*
+ * Read the section header table from the core file and then iterate
+ * over the section headers, converting each to a GElf_Shdr.
+ */
+ shdrs = malloc(efp->e_hdr.e_shnum * sizeof (GElf_Shdr));
+ nbytes = efp->e_hdr.e_shnum * efp->e_hdr.e_shentsize;
+ buf = malloc(nbytes);
+
+ if (shdrs == NULL || buf == NULL) {
+ dprintf("failed to malloc %u section headers: %s\n",
+ (uint_t)efp->e_hdr.e_shnum, strerror(errno));
+ free(buf);
+ goto out;
+ }
+
+ if (pread64(efp->e_fd, buf, nbytes, efp->e_hdr.e_shoff) != nbytes) {
+ dprintf("failed to read section headers at off %lld: %s\n",
+ (longlong_t)efp->e_hdr.e_shoff, strerror(errno));
+ free(buf);
+ goto out;
+ }
+
+ for (i = 0; i < efp->e_hdr.e_shnum; i++) {
+ void *p = (uchar_t *)buf + efp->e_hdr.e_shentsize * i;
+
+ if (efp->e_hdr.e_ident[EI_CLASS] == ELFCLASS32)
+ core_shdr_to_gelf(p, &shdrs[i]);
+ else
+ (void) memcpy(&shdrs[i], p, sizeof (GElf_Shdr));
+ }
+
+ free(buf);
+ buf = NULL;
+
+ /*
+ * Read the .shstrtab section from the core file, terminating it with
+ * an extra \0 so that a corrupt section will not cause us to die.
+ */
+ shp = &shdrs[efp->e_hdr.e_shstrndx];
+ shstrtabsz = shp->sh_size;
+
+ if ((shstrtab = malloc(shstrtabsz + 1)) == NULL) {
+ dprintf("failed to allocate %lu bytes for shstrtab\n",
+ (ulong_t)shstrtabsz);
+ goto out;
+ }
+
+ if (pread64(efp->e_fd, shstrtab, shstrtabsz,
+ shp->sh_offset) != shstrtabsz) {
+ dprintf("failed to read %lu bytes of shstrs at off %lld: %s\n",
+ shstrtabsz, (longlong_t)shp->sh_offset, strerror(errno));
+ goto out;
+ }
+
+ shstrtab[shstrtabsz] = '\0';
+
+ /*
+ * Now iterate over each section in the section header table, locating
+ * sections of interest and initializing more of the ps_prochandle.
+ */
+ for (i = 0; i < efp->e_hdr.e_shnum; i++) {
+ shp = &shdrs[i];
+ name = shstrtab + shp->sh_name;
+
+ if (shp->sh_name >= shstrtabsz) {
+ dprintf("skipping section [%d]: corrupt sh_name\n", i);
+ continue;
+ }
+
+ if (shp->sh_link >= efp->e_hdr.e_shnum) {
+ dprintf("skipping section [%d]: corrupt sh_link\n", i);
+ continue;
+ }
+
+ dprintf("found section header %s (sh_addr 0x%llx)\n",
+ name, (u_longlong_t)shp->sh_addr);
+
+ if (strcmp(name, ".SUNW_ctf") == 0) {
+ if ((mp = Paddr2mptr(P, shp->sh_addr)) == NULL) {
+ dprintf("no map at addr 0x%llx for %s [%d]\n",
+ (u_longlong_t)shp->sh_addr, name, i);
+ continue;
+ }
+
+ if (mp->map_file == NULL ||
+ mp->map_file->file_ctf_buf != NULL) {
+ dprintf("no mapping file or duplicate buffer "
+ "for %s [%d]\n", name, i);
+ continue;
+ }
+
+ if ((buf = malloc(shp->sh_size)) == NULL ||
+ pread64(efp->e_fd, buf, shp->sh_size,
+ shp->sh_offset) != shp->sh_size) {
+ dprintf("skipping section %s [%d]: %s\n",
+ name, i, strerror(errno));
+ free(buf);
+ continue;
+ }
+
+ mp->map_file->file_ctf_size = shp->sh_size;
+ mp->map_file->file_ctf_buf = buf;
+
+ if (shdrs[shp->sh_link].sh_type == SHT_DYNSYM)
+ mp->map_file->file_ctf_dyn = 1;
+
+ } else if (strcmp(name, ".symtab") == 0) {
+ fake_up_symtab(P, &efp->e_hdr,
+ shp, &shdrs[shp->sh_link]);
+ }
+ }
+out:
+ free(shstrtab);
+ free(shdrs);
+}
+
+/*
+ * Main engine for core file initialization: given an fd for the core file
+ * and an optional pathname, construct the ps_prochandle. The aout_path can
+ * either be a suggested executable pathname, or a suggested directory to
+ * use as a possible current working directory.
+ */
+struct ps_prochandle *
+Pfgrab_core(int core_fd, const char *aout_path, int *perr)
+{
+ struct ps_prochandle *P;
+ map_info_t *stk_mp, *brk_mp;
+ const char *execname;
+ char *interp;
+ int i, notes, pagesize;
+ uintptr_t addr, base_addr;
+ struct stat64 stbuf;
+ void *phbuf, *php;
+ size_t nbytes;
+
+ elf_file_t aout;
+ elf_file_t core;
+
+ Elf_Scn *scn, *intp_scn = NULL;
+ Elf_Data *dp;
+
+ GElf_Phdr phdr, note_phdr;
+ GElf_Shdr shdr;
+ GElf_Xword nleft;
+
+ if (elf_version(EV_CURRENT) == EV_NONE) {
+ dprintf("libproc ELF version is more recent than libelf\n");
+ *perr = G_ELF;
+ return (NULL);
+ }
+
+ aout.e_elf = NULL;
+ aout.e_fd = -1;
+
+ core.e_elf = NULL;
+ core.e_fd = core_fd;
+
+ /*
+ * Allocate and initialize a ps_prochandle structure for the core.
+ * There are several key pieces of initialization here:
+ *
+ * 1. The PS_DEAD state flag marks this prochandle as a core file.
+ * PS_DEAD also thus prevents all operations which require state
+ * to be PS_STOP from operating on this handle.
+ *
+ * 2. We keep the core file fd in P->asfd since the core file contains
+ * the remnants of the process address space.
+ *
+ * 3. We set the P->info_valid bit because all information about the
+ * core is determined by the end of this function; there is no need
+ * for proc_update_maps() to reload mappings at any later point.
+ *
+ * 4. The read/write ops vector uses our core_rw() function defined
+ * above to handle i/o requests.
+ */
+ if ((P = malloc(sizeof (struct ps_prochandle))) == NULL) {
+ *perr = G_STRANGE;
+ return (NULL);
+ }
+
+ (void) memset(P, 0, sizeof (struct ps_prochandle));
+ (void) mutex_init(&P->proc_lock, USYNC_THREAD, NULL);
+ P->state = PS_DEAD;
+ P->pid = (pid_t)-1;
+ P->asfd = core.e_fd;
+ P->ctlfd = -1;
+ P->statfd = -1;
+ P->agentctlfd = -1;
+ P->agentstatfd = -1;
+ P->info_valid = 1;
+ P->ops = &P_core_ops;
+
+ Pinitsym(P);
+
+ /*
+ * Fstat and open the core file and make sure it is a valid ELF core.
+ */
+ if (fstat64(P->asfd, &stbuf) == -1) {
+ *perr = G_STRANGE;
+ goto err;
+ }
+
+ if (core_elf_fdopen(&core, ET_CORE, perr) == -1)
+ goto err;
+
+ /*
+ * 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 = malloc(sizeof (core_info_t))) == NULL) {
+ *perr = G_STRANGE;
+ goto err;
+ }
+
+ list_link(&P->core->core_lwp_head, NULL);
+ P->core->core_errno = 0;
+ P->core->core_lwp = NULL;
+ P->core->core_nlwp = 0;
+ P->core->core_size = stbuf.st_size;
+ P->core->core_platform = NULL;
+ P->core->core_uts = NULL;
+ P->core->core_cred = NULL;
+ /*
+ * 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 |
+ CC_CONTENT_DATA | CC_CONTENT_RODATA | CC_CONTENT_ANON |
+ CC_CONTENT_SHANON;
+ P->core->core_priv = NULL;
+ P->core->core_priv_size = 0;
+ P->core->core_privinfo = NULL;
+ P->core->core_zonename = NULL;
+ P->core->core_ppii = NULL;
+
+#if defined(__i386) || defined(__amd64)
+ P->core->core_ldt = NULL;
+ P->core->core_nldt = 0;
+#endif
+
+ switch (core.e_hdr.e_ident[EI_CLASS]) {
+ case ELFCLASS32:
+ P->core->core_dmodel = PR_MODEL_ILP32;
+ break;
+ case ELFCLASS64:
+ P->core->core_dmodel = PR_MODEL_LP64;
+ break;
+ default:
+ *perr = G_FORMAT;
+ goto err;
+ }
+
+ /*
+ * Because the core file may be a large file, we can't use libelf to
+ * read the Phdrs. We use e_phnum and e_phentsize to simplify things.
+ */
+ nbytes = core.e_hdr.e_phnum * core.e_hdr.e_phentsize;
+
+ if ((phbuf = malloc(nbytes)) == NULL) {
+ *perr = G_STRANGE;
+ goto err;
+ }
+
+ if (pread64(core_fd, phbuf, nbytes, core.e_hdr.e_phoff) != nbytes) {
+ *perr = G_STRANGE;
+ free(phbuf);
+ goto err;
+ }
+
+ /*
+ * Iterate through the program headers in the core file.
+ * We're interested in two types of Phdrs: PT_NOTE (which
+ * contains a set of saved /proc structures), and PT_LOAD (which
+ * represents a memory mapping from the process's address space).
+ * In the case of PT_NOTE, we're interested in the last PT_NOTE
+ * in the core file; currently the first PT_NOTE (if present)
+ * contains /proc structs in the pre-2.6 unstructured /proc format.
+ */
+ for (php = phbuf, notes = 0, i = 0; i < core.e_hdr.e_phnum; i++) {
+ if (core.e_hdr.e_ident[EI_CLASS] == ELFCLASS64)
+ (void) memcpy(&phdr, php, sizeof (GElf_Phdr));
+ else
+ core_phdr_to_gelf(php, &phdr);
+
+ switch (phdr.p_type) {
+ case PT_NOTE:
+ note_phdr = phdr;
+ notes++;
+ break;
+
+ case PT_LOAD:
+ if (core_add_mapping(P, &phdr) == -1) {
+ *perr = G_STRANGE;
+ free(phbuf);
+ goto err;
+ }
+ break;
+ }
+
+ php = (char *)php + core.e_hdr.e_phentsize;
+ }
+
+ free(phbuf);
+
+ Psort_mappings(P);
+
+ /*
+ * If we couldn't find anything of type PT_NOTE, or only one PT_NOTE
+ * was present, abort. The core file is either corrupt or too old.
+ */
+ if (notes == 0 || notes == 1) {
+ *perr = G_NOTE;
+ goto err;
+ }
+
+ /*
+ * Advance the seek pointer to the start of the PT_NOTE data
+ */
+ if (lseek64(P->asfd, note_phdr.p_offset, SEEK_SET) == (off64_t)-1) {
+ dprintf("Pgrab_core: failed to lseek to PT_NOTE data\n");
+ *perr = G_STRANGE;
+ goto err;
+ }
+
+ /*
+ * Now process the PT_NOTE structures. Each one is preceded by
+ * an Elf{32/64}_Nhdr structure describing its type and size.
+ *
+ * +--------+
+ * | header |
+ * +--------+
+ * | name |
+ * | ... |
+ * +--------+
+ * | desc |
+ * | ... |
+ * +--------+
+ */
+ for (nleft = note_phdr.p_filesz; nleft > 0; ) {
+ Elf64_Nhdr nhdr;
+ off64_t off, namesz;
+
+ /*
+ * Although <sys/elf.h> defines both Elf32_Nhdr and Elf64_Nhdr
+ * as different types, they are both of the same content and
+ * size, so we don't need to worry about 32/64 conversion here.
+ */
+ if (read(P->asfd, &nhdr, sizeof (nhdr)) != sizeof (nhdr)) {
+ dprintf("Pgrab_core: failed to read ELF note header\n");
+ *perr = G_NOTE;
+ goto err;
+ }
+
+ /*
+ * According to the System V ABI, the amount of padding
+ * following the name field should align the description
+ * field on a 4 byte boundary for 32-bit binaries or on an 8
+ * byte boundary for 64-bit binaries. However, this change
+ * was not made correctly during the 64-bit port so all
+ * descriptions can assume only 4-byte alignment. We ignore
+ * the name field and the padding to 4-byte alignment.
+ */
+ namesz = P2ROUNDUP((off64_t)nhdr.n_namesz, (off64_t)4);
+ if (lseek64(P->asfd, namesz, SEEK_CUR) == (off64_t)-1) {
+ dprintf("failed to seek past name and padding\n");
+ *perr = G_STRANGE;
+ goto err;
+ }
+
+ dprintf("Note hdr n_type=%u n_namesz=%u n_descsz=%u\n",
+ nhdr.n_type, nhdr.n_namesz, nhdr.n_descsz);
+
+ off = lseek64(P->asfd, (off64_t)0L, SEEK_CUR);
+
+ /*
+ * Invoke the note handler function from our table
+ */
+ if (nhdr.n_type < sizeof (nhdlrs) / sizeof (nhdlrs[0])) {
+ if (nhdlrs[nhdr.n_type](P, nhdr.n_descsz) < 0) {
+ *perr = G_NOTE;
+ goto err;
+ }
+ } else
+ (void) note_notsup(P, nhdr.n_descsz);
+
+ /*
+ * Seek past the current note data to the next Elf_Nhdr
+ */
+ if (lseek64(P->asfd, off + nhdr.n_descsz,
+ SEEK_SET) == (off64_t)-1) {
+ dprintf("Pgrab_core: failed to seek to next nhdr\n");
+ *perr = G_STRANGE;
+ goto err;
+ }
+
+ /*
+ * Subtract the size of the header and its data from what
+ * we have left to process.
+ */
+ nleft -= sizeof (nhdr) + namesz + nhdr.n_descsz;
+ }
+
+ if (nleft != 0) {
+ dprintf("Pgrab_core: note section malformed\n");
+ *perr = G_STRANGE;
+ goto err;
+ }
+
+ if ((pagesize = Pgetauxval(P, AT_PAGESZ)) == -1) {
+ pagesize = getpagesize();
+ dprintf("AT_PAGESZ missing; defaulting to %d\n", pagesize);
+ }
+
+ /*
+ * Locate and label the mappings corresponding to the end of the
+ * heap (MA_BREAK) and the base of the stack (MA_STACK).
+ */
+ if ((P->status.pr_brkbase != 0 || P->status.pr_brksize != 0) &&
+ (brk_mp = Paddr2mptr(P, P->status.pr_brkbase +
+ P->status.pr_brksize - 1)) != NULL)
+ brk_mp->map_pmap.pr_mflags |= MA_BREAK;
+ else
+ brk_mp = NULL;
+
+ if ((stk_mp = Paddr2mptr(P, P->status.pr_stkbase)) != NULL)
+ stk_mp->map_pmap.pr_mflags |= MA_STACK;
+
+ /*
+ * At this point, we have enough information to look for the
+ * executable and open it: we have access to the auxv, a psinfo_t,
+ * and the ability to read from mappings provided by the core file.
+ */
+ (void) Pfindexec(P, aout_path, core_exec_open, &aout);
+ dprintf("P->execname = \"%s\"\n", P->execname ? P->execname : "NULL");
+ execname = P->execname ? P->execname : "a.out";
+
+ /*
+ * Iterate through the sections, looking for the .dynamic and .interp
+ * sections. If we encounter them, remember their section pointers.
+ */
+ for (scn = NULL; (scn = elf_nextscn(aout.e_elf, scn)) != NULL; ) {
+ char *sname;
+
+ if ((gelf_getshdr(scn, &shdr) == NULL) ||
+ (sname = elf_strptr(aout.e_elf, aout.e_hdr.e_shstrndx,
+ (size_t)shdr.sh_name)) == NULL)
+ continue;
+
+ if (strcmp(sname, ".interp") == 0)
+ intp_scn = scn;
+ }
+
+ /*
+ * Get the AT_BASE auxv element. If this is missing (-1), then
+ * we assume this is a statically-linked executable.
+ */
+ base_addr = Pgetauxval(P, AT_BASE);
+
+ /*
+ * In order to get librtld_db initialized, we'll need to identify
+ * and name the mapping corresponding to the run-time linker. The
+ * AT_BASE auxv element tells us the address where it was mapped,
+ * and the .interp section of the executable tells us its path.
+ * If for some reason that doesn't pan out, just use ld.so.1.
+ */
+ if (intp_scn != NULL && (dp = elf_getdata(intp_scn, NULL)) != NULL &&
+ dp->d_size != 0) {
+ dprintf(".interp = <%s>\n", (char *)dp->d_buf);
+ interp = dp->d_buf;
+
+ } else if (base_addr != (uintptr_t)-1L) {
+ if (P->core->core_dmodel == PR_MODEL_LP64)
+ interp = "/usr/lib/64/ld.so.1";
+ else
+ interp = "/usr/lib/ld.so.1";
+
+ dprintf(".interp section is missing or could not be read; "
+ "defaulting to %s\n", interp);
+ } else
+ dprintf("detected statically linked executable\n");
+
+ /*
+ * If we have an AT_BASE element, name the mapping at that address
+ * using the interpreter pathname. Name the corresponding data
+ * mapping after the interpreter as well.
+ */
+ if (base_addr != (uintptr_t)-1L) {
+ elf_file_t intf;
+
+ P->map_ldso = core_name_mapping(P, base_addr, interp);
+
+ if (core_elf_open(&intf, interp, ET_DYN, NULL) == 0) {
+ rd_loadobj_t rl;
+ map_info_t *dmp;
+
+ rl.rl_base = base_addr;
+ dmp = core_find_data(P, intf.e_elf, &rl);
+
+ if (dmp != NULL) {
+ dprintf("renamed data at %p to %s\n",
+ (void *)rl.rl_data_base, interp);
+ (void) strncpy(dmp->map_pmap.pr_mapname,
+ interp, PRMAPSZ);
+ dmp->map_pmap.pr_mapname[PRMAPSZ - 1] = '\0';
+ }
+ }
+
+ core_elf_close(&intf);
+ }
+
+ /*
+ * If we have an AT_ENTRY element, name the mapping at that address
+ * using the special name "a.out" just like /proc does.
+ */
+ if ((addr = Pgetauxval(P, AT_ENTRY)) != (uintptr_t)-1L)
+ P->map_exec = core_name_mapping(P, addr, "a.out");
+
+ /*
+ * If we're a statically linked executable, then just locate the
+ * executable's text and data and name them after the executable.
+ */
+ if (base_addr == (uintptr_t)-1L) {
+ map_info_t *tmp, *dmp;
+ file_info_t *fp;
+ rd_loadobj_t rl;
+
+ if ((tmp = core_find_text(P, aout.e_elf, &rl)) != NULL &&
+ (dmp = core_find_data(P, aout.e_elf, &rl)) != NULL) {
+ (void) strncpy(tmp->map_pmap.pr_mapname,
+ execname, PRMAPSZ);
+ tmp->map_pmap.pr_mapname[PRMAPSZ - 1] = '\0';
+ (void) strncpy(dmp->map_pmap.pr_mapname,
+ execname, PRMAPSZ);
+ dmp->map_pmap.pr_mapname[PRMAPSZ - 1] = '\0';
+ }
+
+ if ((P->map_exec = tmp) != NULL &&
+ (fp = malloc(sizeof (file_info_t))) != NULL) {
+
+ (void) memset(fp, 0, sizeof (file_info_t));
+
+ list_link(fp, &P->file_head);
+ tmp->map_file = fp;
+ P->num_files++;
+
+ fp->file_ref = 1;
+ fp->file_fd = -1;
+
+ fp->file_lo = malloc(sizeof (rd_loadobj_t));
+ fp->file_lname = strdup(execname);
+
+ if (fp->file_lo)
+ *fp->file_lo = rl;
+ if (fp->file_lname)
+ fp->file_lbase = basename(fp->file_lname);
+
+ (void) strcpy(fp->file_pname,
+ P->mappings[0].map_pmap.pr_mapname);
+ fp->file_map = tmp;
+
+ Pbuild_file_symtab(P, fp);
+
+ if (dmp != NULL) {
+ dmp->map_file = fp;
+ fp->file_ref++;
+ }
+ }
+ }
+
+ core_elf_close(&aout);
+
+ /*
+ * We now have enough information to initialize librtld_db.
+ * After it warms up, we can iterate through the load object chain
+ * in the core, which will allow us to construct the file info
+ * we need to provide symbol information for the other shared
+ * libraries, and also to fill in the missing mapping names.
+ */
+ rd_log(_libproc_debug);
+
+ if ((P->rap = rd_new(P)) != NULL) {
+ (void) rd_loadobj_iter(P->rap, (rl_iter_f *)
+ core_iter_mapping, P);
+
+ if (P->core->core_errno != 0) {
+ errno = P->core->core_errno;
+ *perr = G_STRANGE;
+ goto err;
+ }
+ } else
+ dprintf("failed to initialize rtld_db agent\n");
+
+ /*
+ * If there are sections, load them and process the data from any
+ * sections that we can use to annotate the file_info_t's.
+ */
+ core_load_shdrs(P, &core);
+
+ /*
+ * If we previously located a stack or break mapping, and they are
+ * still anonymous, we now assume that they were MAP_ANON mappings.
+ * If brk_mp turns out to now have a name, then the heap is still
+ * sitting at the end of the executable's data+bss mapping: remove
+ * the previous MA_BREAK setting to be consistent with /proc.
+ */
+ if (stk_mp != NULL && stk_mp->map_pmap.pr_mapname[0] == '\0')
+ stk_mp->map_pmap.pr_mflags |= MA_ANON;
+ if (brk_mp != NULL && brk_mp->map_pmap.pr_mapname[0] == '\0')
+ brk_mp->map_pmap.pr_mflags |= MA_ANON;
+ else if (brk_mp != NULL)
+ brk_mp->map_pmap.pr_mflags &= ~MA_BREAK;
+
+ *perr = 0;
+ return (P);
+
+err:
+ Pfree(P);
+ core_elf_close(&aout);
+ return (NULL);
+}
+
+/*
+ * Grab a core file using a pathname. We just open it and call Pfgrab_core().
+ */
+struct ps_prochandle *
+Pgrab_core(const char *core, const char *aout, int gflag, int *perr)
+{
+ int fd, oflag = (gflag & PGRAB_RDONLY) ? O_RDONLY : O_RDWR;
+
+ if ((fd = open64(core, oflag)) >= 0)
+ return (Pfgrab_core(fd, aout, perr));
+
+ if (errno != ENOENT)
+ *perr = G_STRANGE;
+ else
+ *perr = G_NOCORE;
+
+ return (NULL);
+}
diff --git a/usr/src/lib/libproc/common/Pexecname.c b/usr/src/lib/libproc/common/Pexecname.c
new file mode 100644
index 0000000000..3c4fee08d1
--- /dev/null
+++ b/usr/src/lib/libproc/common/Pexecname.c
@@ -0,0 +1,286 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#define __EXTENSIONS__
+#include <string.h>
+#undef __EXTENSIONS__
+
+#include <libgen.h>
+#include <limits.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "Pcontrol.h"
+
+/*
+ * Pexecname.c - Way too much code to attempt to derive the full pathname of
+ * the executable file from a process handle, be it dead or alive.
+ */
+
+/*
+ * Once we've computed a cwd and a relative path, we use try_exec() to
+ * form an absolute path, call resolvepath() on it, and then let the
+ * caller's function do the final confirmation.
+ */
+static int
+try_exec(const char *cwd, const char *path, char *buf,
+ int (*isexec)(const char *, void *), void *isdata)
+{
+ int i;
+
+ if (path[0] != '/')
+ (void) snprintf(buf, PATH_MAX, "%s/%s", cwd, path);
+ else
+ (void) strcpy(buf, path);
+
+ dprintf("try_exec \"%s\"\n", buf);
+
+ if ((i = resolvepath(buf, buf, PATH_MAX)) > 0) {
+ buf[i] = '\0';
+ return (isexec(buf, isdata));
+ }
+
+ return (0); /* resolvepath failed */
+}
+
+/*
+ * The Pfindexec function contains the logic for the executable name dance.
+ * The caller provides a possible executable name or likely directory (the
+ * aout parameter), and a function which is responsible for doing any
+ * final confirmation on the executable pathname once a possible full
+ * pathname has been chosen.
+ */
+char *
+Pfindexec(struct ps_prochandle *P, const char *aout,
+ int (*isexec)(const char *, void *), void *isdata)
+{
+ char cwd[PATH_MAX * 2];
+ char path[PATH_MAX];
+ char buf[PATH_MAX];
+ struct stat st;
+ uintptr_t addr;
+ char *p, *q;
+
+ if (P->execname)
+ return (P->execname); /* Already found */
+
+ errno = 0; /* Set to zero so we can tell if stat() failed */
+
+ /*
+ * First try: use the provided default value, if it is not a directory.
+ * If the aout parameter turns out to be a directory, this is
+ * interpreted as the directory to use as an alternate cwd for
+ * our subsequent attempts to locate the executable.
+ */
+ if (aout != NULL && stat(aout, &st) == 0 && !S_ISDIR(st.st_mode)) {
+ if (try_exec(".", aout, buf, isexec, isdata))
+ goto found;
+ else
+ aout = ".";
+
+ } else if (aout == NULL || errno != 0)
+ aout = ".";
+
+ /*
+ * At this point 'aout' is either "." or an alternate cwd. We use
+ * realpath(3c) to turn this into a full pathname free of ".", "..",
+ * and symlinks. If this fails for some reason, fall back to "."
+ */
+ if (realpath(aout, cwd) == NULL)
+ (void) strcpy(cwd, ".");
+
+ /*
+ * Second try: read the string pointed to by the AT_SUN_EXECNAME
+ * auxv element, saved when the program was exec'd. If the full
+ * pathname try_exec() forms fails, try again using just the
+ * basename appended to our cwd.
+ */
+ if ((addr = Pgetauxval(P, AT_SUN_EXECNAME)) != (uintptr_t)-1L &&
+ Pread_string(P, path, sizeof (path), (off_t)addr) > 0) {
+
+ if (try_exec(cwd, path, buf, isexec, isdata))
+ goto found;
+
+ if (strchr(path, '/') != NULL && basename(path) != NULL &&
+ try_exec(cwd, path, buf, isexec, isdata))
+ goto found;
+ }
+
+ /*
+ * Third try: try using the first whitespace-separated token
+ * saved in the psinfo_t's pr_psargs (the initial value of argv[0]).
+ */
+ if (Ppsinfo(P) != NULL) {
+ (void) strncpy(path, P->psinfo.pr_psargs, PRARGSZ);
+ path[PRARGSZ] = '\0';
+
+ if ((p = strchr(path, ' ')) != NULL)
+ *p = '\0';
+
+ if (try_exec(cwd, path, buf, isexec, isdata))
+ goto found;
+
+ if (strchr(path, '/') != NULL && basename(path) != NULL &&
+ try_exec(cwd, path, buf, isexec, isdata))
+ goto found;
+ }
+
+ /*
+ * Fourth try: read the string pointed to by argv[0] out of the
+ * stack in the process's address space.
+ */
+ if (P->psinfo.pr_argv != NULL &&
+ Pread(P, &addr, sizeof (addr), P->psinfo.pr_argv) != -1 &&
+ Pread_string(P, path, sizeof (path), (off_t)addr) > 0) {
+
+ if (try_exec(cwd, path, buf, isexec, isdata))
+ goto found;
+
+ if (strchr(path, '/') != NULL && basename(path) != NULL &&
+ try_exec(cwd, path, buf, isexec, isdata))
+ goto found;
+ }
+
+ /*
+ * Fifth try: read the process's $PATH environment variable and
+ * search each directory named there for the name matching pr_fname.
+ */
+ if (Pgetenv(P, "PATH", cwd, sizeof (cwd)) != NULL) {
+ /*
+ * If the name from pr_psargs contains pr_fname as its
+ * leading string, then accept the name from pr_psargs
+ * because more bytes are saved there. Otherwise use
+ * pr_fname because this gives us new information.
+ */
+ (void) strncpy(path, P->psinfo.pr_psargs, PRARGSZ);
+ path[PRARGSZ] = '\0';
+
+ if ((p = strchr(path, ' ')) != NULL)
+ *p = '\0';
+
+ if (strchr(path, '/') != NULL || strncmp(path,
+ P->psinfo.pr_fname, strlen(P->psinfo.pr_fname)) != 0)
+ (void) strcpy(path, P->psinfo.pr_fname);
+
+ /*
+ * Now iterate over the $PATH elements, trying to form
+ * an executable pathname with each one.
+ */
+ for (p = strtok_r(cwd, ":", &q); p != NULL;
+ p = strtok_r(NULL, ":", &q)) {
+
+ if (*p != '/')
+ continue; /* Ignore anything relative */
+
+ if (try_exec(p, path, buf, isexec, isdata))
+ goto found;
+ }
+ }
+
+ errno = ENOENT;
+ return (NULL);
+
+found:
+ if ((P->execname = strdup(buf)) == NULL)
+ dprintf("failed to malloc; executable name is \"%s\"", buf);
+
+ return (P->execname);
+}
+
+/*
+ * 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().
+ */
+char *
+Pexecname(struct ps_prochandle *P, char *buf, size_t buflen)
+{
+ if (P->execname == NULL && 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),
+ "/proc/%d/path/a.out", (int)P->pid);
+ if ((ret = readlink(exec_name, buf, buflen - 1)) > 0) {
+ buf[ret] = '\0';
+ 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),
+ "/proc/%d/object/a.out", (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),
+ "/proc/%d/path/cwd", (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);
+ }
+
+ if (P->execname != NULL) {
+ (void) strncpy(buf, P->execname, buflen);
+ return (buf);
+ }
+
+ return (NULL);
+}
diff --git a/usr/src/lib/libproc/common/Pgcore.c b/usr/src/lib/libproc/common/Pgcore.c
new file mode 100644
index 0000000000..9147bcb201
--- /dev/null
+++ b/usr/src/lib/libproc/common/Pgcore.c
@@ -0,0 +1,1534 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+#include <procfs.h>
+#include <priv.h>
+#include <sys/elf.h>
+#include <sys/machelf.h>
+#include <sys/sysmacros.h>
+#include <sys/systeminfo.h>
+#include <sys/proc.h>
+#include <sys/utsname.h>
+
+#include <sys/old_procfs.h>
+
+#include "Pcontrol.h"
+#include "P32ton.h"
+
+typedef enum {
+ STR_CTF,
+ STR_SYMTAB,
+ STR_DYNSYM,
+ STR_STRTAB,
+ STR_DYNSTR,
+ STR_SHSTRTAB,
+ STR_NUM
+} shstrtype_t;
+
+static const char *shstrtab_data[] = {
+ ".SUNW_ctf",
+ ".symtab",
+ ".dynsym",
+ ".strtab",
+ ".dynstr",
+ ".shstrtab"
+};
+
+typedef struct shstrtab {
+ int sst_ndx[STR_NUM];
+ int sst_cur;
+} shstrtab_t;
+
+typedef struct {
+ struct ps_prochandle *P;
+ int pgc_fd;
+ off64_t *pgc_poff;
+ off64_t *pgc_soff;
+ off64_t *pgc_doff;
+ core_content_t pgc_content;
+ void *pgc_chunk;
+ size_t pgc_chunksz;
+
+ shstrtab_t pgc_shstrtab;
+} pgcore_t;
+
+static void
+shstrtab_init(shstrtab_t *s)
+{
+ bzero(&s->sst_ndx, sizeof (s->sst_ndx));
+ s->sst_cur = 1;
+}
+
+static int
+shstrtab_ndx(shstrtab_t *s, shstrtype_t type)
+{
+ int ret;
+
+ if ((ret = s->sst_ndx[type]) != 0)
+ return (ret);
+
+ ret = s->sst_ndx[type] = s->sst_cur;
+ s->sst_cur += strlen(shstrtab_data[type]) + 1;
+
+ return (ret);
+}
+
+static size_t
+shstrtab_size(const shstrtab_t *s)
+{
+ return (s->sst_cur);
+}
+
+int
+Pgcore(struct ps_prochandle *P, const char *fname, core_content_t content)
+{
+ int fd;
+ int err;
+
+ if ((fd = creat64(fname, 0666)) < 0)
+ return (-1);
+
+ if ((err = Pfgcore(P, fd, content)) != 0) {
+ (void) close(fd);
+ (void) unlink(fname);
+ return (err);
+ }
+
+ return (close(fd));
+}
+
+/*
+ * Since we don't want to use the old-school procfs interfaces, we use the
+ * new-style data structures we already have to construct the old-style
+ * data structures. We include these data structures in core files for
+ * backward compatability.
+ */
+
+static void
+mkprstatus(struct ps_prochandle *P, const lwpstatus_t *lsp,
+ const lwpsinfo_t *lip, prstatus_t *psp)
+{
+ bzero(psp, sizeof (*psp));
+
+ if (lsp->pr_flags & PR_STOPPED)
+ psp->pr_flags = 0x0001;
+ if (lsp->pr_flags & PR_ISTOP)
+ psp->pr_flags = 0x0002;
+ if (lsp->pr_flags & PR_DSTOP)
+ psp->pr_flags = 0x0004;
+ if (lsp->pr_flags & PR_ASLEEP)
+ psp->pr_flags = 0x0008;
+ if (lsp->pr_flags & PR_FORK)
+ psp->pr_flags = 0x0010;
+ if (lsp->pr_flags & PR_RLC)
+ psp->pr_flags = 0x0020;
+ /*
+ * Note that PR_PTRACE (0x0040) from <sys/old_procfs.h> is never set;
+ * PR_PCOMPAT corresponds to PR_PTRACE in the newer <sys/procfs.h>.
+ */
+ if (lsp->pr_flags & PR_PCINVAL)
+ psp->pr_flags = 0x0080;
+ if (lsp->pr_flags & PR_ISSYS)
+ psp->pr_flags = 0x0100;
+ if (lsp->pr_flags & PR_STEP)
+ psp->pr_flags = 0x0200;
+ if (lsp->pr_flags & PR_KLC)
+ psp->pr_flags = 0x0400;
+ if (lsp->pr_flags & PR_ASYNC)
+ psp->pr_flags = 0x0800;
+ if (lsp->pr_flags & PR_PTRACE)
+ psp->pr_flags = 0x1000;
+ if (lsp->pr_flags & PR_MSACCT)
+ psp->pr_flags = 0x2000;
+ if (lsp->pr_flags & PR_BPTADJ)
+ psp->pr_flags = 0x4000;
+ if (lsp->pr_flags & PR_ASLWP)
+ psp->pr_flags = 0x8000;
+
+ psp->pr_why = lsp->pr_why;
+ psp->pr_what = lsp->pr_what;
+ psp->pr_info = lsp->pr_info;
+ psp->pr_cursig = lsp->pr_cursig;
+ psp->pr_nlwp = P->status.pr_nlwp;
+ psp->pr_sigpend = P->status.pr_sigpend;
+ psp->pr_sighold = lsp->pr_lwphold;
+ psp->pr_altstack = lsp->pr_altstack;
+ psp->pr_action = lsp->pr_action;
+ psp->pr_pid = P->status.pr_pid;
+ psp->pr_ppid = P->status.pr_ppid;
+ psp->pr_pgrp = P->status.pr_pgid;
+ psp->pr_sid = P->status.pr_sid;
+ psp->pr_utime = P->status.pr_utime;
+ psp->pr_stime = P->status.pr_stime;
+ psp->pr_cutime = P->status.pr_cutime;
+ psp->pr_cstime = P->status.pr_cstime;
+ (void) strncpy(psp->pr_clname, lsp->pr_clname, sizeof (psp->pr_clname));
+ psp->pr_syscall = lsp->pr_syscall;
+ psp->pr_nsysarg = lsp->pr_nsysarg;
+ bcopy(lsp->pr_sysarg, psp->pr_sysarg, sizeof (psp->pr_sysarg));
+ psp->pr_who = lsp->pr_lwpid;
+ psp->pr_lwppend = lsp->pr_lwppend;
+ psp->pr_oldcontext = (ucontext_t *)lsp->pr_oldcontext;
+ psp->pr_brkbase = (caddr_t)P->status.pr_brkbase;
+ psp->pr_brksize = P->status.pr_brksize;
+ psp->pr_stkbase = (caddr_t)P->status.pr_stkbase;
+ psp->pr_stksize = P->status.pr_stksize;
+ psp->pr_processor = (short)lip->pr_onpro;
+ psp->pr_bind = (short)lip->pr_bindpro;
+ psp->pr_instr = lsp->pr_instr;
+ bcopy(lsp->pr_reg, psp->pr_reg, sizeof (psp->pr_sysarg));
+}
+
+static void
+mkprpsinfo(struct ps_prochandle *P, prpsinfo_t *psp)
+{
+ bzero(psp, sizeof (*psp));
+ psp->pr_state = P->psinfo.pr_lwp.pr_state;
+ psp->pr_sname = P->psinfo.pr_lwp.pr_sname;
+ psp->pr_zomb = (psp->pr_state == SZOMB);
+ psp->pr_nice = P->psinfo.pr_lwp.pr_nice;
+ psp->pr_flag = P->psinfo.pr_lwp.pr_flag;
+ psp->pr_uid = P->psinfo.pr_uid;
+ psp->pr_gid = P->psinfo.pr_gid;
+ psp->pr_pid = P->psinfo.pr_pid;
+ psp->pr_ppid = P->psinfo.pr_ppid;
+ psp->pr_pgrp = P->psinfo.pr_pgid;
+ psp->pr_sid = P->psinfo.pr_sid;
+ psp->pr_addr = (caddr_t)P->psinfo.pr_addr;
+ psp->pr_size = P->psinfo.pr_size;
+ psp->pr_rssize = P->psinfo.pr_rssize;
+ psp->pr_wchan = (caddr_t)P->psinfo.pr_lwp.pr_wchan;
+ psp->pr_start = P->psinfo.pr_start;
+ psp->pr_time = P->psinfo.pr_time;
+ psp->pr_pri = P->psinfo.pr_lwp.pr_pri;
+ psp->pr_oldpri = P->psinfo.pr_lwp.pr_oldpri;
+ psp->pr_cpu = P->psinfo.pr_lwp.pr_cpu;
+ psp->pr_ottydev = cmpdev(P->psinfo.pr_ttydev);
+ psp->pr_lttydev = P->psinfo.pr_ttydev;
+ (void) strncpy(psp->pr_clname, P->psinfo.pr_lwp.pr_clname,
+ sizeof (psp->pr_clname));
+ (void) strncpy(psp->pr_fname, P->psinfo.pr_fname,
+ sizeof (psp->pr_fname));
+ bcopy(&P->psinfo.pr_psargs, &psp->pr_psargs,
+ sizeof (psp->pr_psargs));
+ psp->pr_syscall = P->psinfo.pr_lwp.pr_syscall;
+ psp->pr_ctime = P->psinfo.pr_ctime;
+ psp->pr_bysize = psp->pr_size * PAGESIZE;
+ psp->pr_byrssize = psp->pr_rssize * PAGESIZE;
+ psp->pr_argc = P->psinfo.pr_argc;
+ psp->pr_argv = (char **)P->psinfo.pr_argv;
+ psp->pr_envp = (char **)P->psinfo.pr_envp;
+ psp->pr_wstat = P->psinfo.pr_wstat;
+ psp->pr_pctcpu = P->psinfo.pr_pctcpu;
+ psp->pr_pctmem = P->psinfo.pr_pctmem;
+ psp->pr_euid = P->psinfo.pr_euid;
+ psp->pr_egid = P->psinfo.pr_egid;
+ psp->pr_aslwpid = 0;
+ psp->pr_dmodel = P->psinfo.pr_dmodel;
+}
+
+#ifdef _LP64
+
+static void
+mkprstatus32(struct ps_prochandle *P, const lwpstatus_t *lsp,
+ const lwpsinfo_t *lip, prstatus32_t *psp)
+{
+ bzero(psp, sizeof (*psp));
+
+ if (lsp->pr_flags & PR_STOPPED)
+ psp->pr_flags = 0x0001;
+ if (lsp->pr_flags & PR_ISTOP)
+ psp->pr_flags = 0x0002;
+ if (lsp->pr_flags & PR_DSTOP)
+ psp->pr_flags = 0x0004;
+ if (lsp->pr_flags & PR_ASLEEP)
+ psp->pr_flags = 0x0008;
+ if (lsp->pr_flags & PR_FORK)
+ psp->pr_flags = 0x0010;
+ if (lsp->pr_flags & PR_RLC)
+ psp->pr_flags = 0x0020;
+ /*
+ * Note that PR_PTRACE (0x0040) from <sys/old_procfs.h> is never set;
+ * PR_PCOMPAT corresponds to PR_PTRACE in the newer <sys/procfs.h>.
+ */
+ if (lsp->pr_flags & PR_PCINVAL)
+ psp->pr_flags = 0x0080;
+ if (lsp->pr_flags & PR_ISSYS)
+ psp->pr_flags = 0x0100;
+ if (lsp->pr_flags & PR_STEP)
+ psp->pr_flags = 0x0200;
+ if (lsp->pr_flags & PR_KLC)
+ psp->pr_flags = 0x0400;
+ if (lsp->pr_flags & PR_ASYNC)
+ psp->pr_flags = 0x0800;
+ if (lsp->pr_flags & PR_PTRACE)
+ psp->pr_flags = 0x1000;
+ if (lsp->pr_flags & PR_MSACCT)
+ psp->pr_flags = 0x2000;
+ if (lsp->pr_flags & PR_BPTADJ)
+ psp->pr_flags = 0x4000;
+ if (lsp->pr_flags & PR_ASLWP)
+ psp->pr_flags = 0x8000;
+
+ psp->pr_why = lsp->pr_why;
+ psp->pr_what = lsp->pr_what;
+ siginfo_n_to_32(&lsp->pr_info, &psp->pr_info);
+ psp->pr_cursig = lsp->pr_cursig;
+ psp->pr_nlwp = P->status.pr_nlwp;
+ psp->pr_sigpend = P->status.pr_sigpend;
+ psp->pr_sighold = lsp->pr_lwphold;
+ stack_n_to_32(&lsp->pr_altstack, &psp->pr_altstack);
+ sigaction_n_to_32(&lsp->pr_action, &psp->pr_action);
+ psp->pr_pid = P->status.pr_pid;
+ psp->pr_ppid = P->status.pr_ppid;
+ psp->pr_pgrp = P->status.pr_pgid;
+ psp->pr_sid = P->status.pr_sid;
+ timestruc_n_to_32(&P->status.pr_utime, &psp->pr_utime);
+ timestruc_n_to_32(&P->status.pr_stime, &psp->pr_stime);
+ timestruc_n_to_32(&P->status.pr_cutime, &psp->pr_cutime);
+ timestruc_n_to_32(&P->status.pr_cstime, &psp->pr_cstime);
+ (void) strncpy(psp->pr_clname, lsp->pr_clname, sizeof (psp->pr_clname));
+ psp->pr_syscall = lsp->pr_syscall;
+ psp->pr_nsysarg = lsp->pr_nsysarg;
+ bcopy(lsp->pr_sysarg, psp->pr_sysarg,
+ sizeof (psp->pr_sysarg)); psp->pr_who = lsp->pr_lwpid;
+ psp->pr_lwppend = lsp->pr_lwppend;
+ psp->pr_oldcontext = (caddr32_t)lsp->pr_oldcontext;
+ psp->pr_brkbase = (caddr32_t)P->status.pr_brkbase;
+ psp->pr_brksize = P->status.pr_brksize;
+ psp->pr_stkbase = (caddr32_t)P->status.pr_stkbase;
+ psp->pr_stksize = P->status.pr_stksize;
+ psp->pr_processor = (short)lip->pr_onpro;
+ psp->pr_bind = (short)lip->pr_bindpro;
+ psp->pr_instr = lsp->pr_instr;
+ bcopy(lsp->pr_reg, psp->pr_reg, sizeof (psp->pr_sysarg));
+}
+
+static void
+mkprpsinfo32(struct ps_prochandle *P, prpsinfo32_t *psp)
+{
+ bzero(psp, sizeof (*psp));
+ psp->pr_state = P->psinfo.pr_lwp.pr_state;
+ psp->pr_sname = P->psinfo.pr_lwp.pr_sname;
+ psp->pr_zomb = (psp->pr_state == SZOMB);
+ psp->pr_nice = P->psinfo.pr_lwp.pr_nice;
+ psp->pr_flag = P->psinfo.pr_lwp.pr_flag;
+ psp->pr_uid = P->psinfo.pr_uid;
+ psp->pr_gid = P->psinfo.pr_gid;
+ psp->pr_pid = P->psinfo.pr_pid;
+ psp->pr_ppid = P->psinfo.pr_ppid;
+ psp->pr_pgrp = P->psinfo.pr_pgid;
+ psp->pr_sid = P->psinfo.pr_sid;
+ psp->pr_addr = (caddr32_t)P->psinfo.pr_addr;
+ psp->pr_size = P->psinfo.pr_size;
+ psp->pr_rssize = P->psinfo.pr_rssize;
+ psp->pr_wchan = (caddr32_t)P->psinfo.pr_lwp.pr_wchan;
+ timestruc_n_to_32(&P->psinfo.pr_start, &psp->pr_start);
+ timestruc_n_to_32(&P->psinfo.pr_time, &psp->pr_time);
+ psp->pr_pri = P->psinfo.pr_lwp.pr_pri;
+ psp->pr_oldpri = P->psinfo.pr_lwp.pr_oldpri;
+ psp->pr_cpu = P->psinfo.pr_lwp.pr_cpu;
+ psp->pr_ottydev = cmpdev(P->psinfo.pr_ttydev);
+ psp->pr_lttydev = prcmpldev(P->psinfo.pr_ttydev);
+ (void) strncpy(psp->pr_clname, P->psinfo.pr_lwp.pr_clname,
+ sizeof (psp->pr_clname));
+ (void) strncpy(psp->pr_fname, P->psinfo.pr_fname,
+ sizeof (psp->pr_fname));
+ bcopy(&P->psinfo.pr_psargs, &psp->pr_psargs,
+ sizeof (psp->pr_psargs));
+ psp->pr_syscall = P->psinfo.pr_lwp.pr_syscall;
+ timestruc_n_to_32(&P->psinfo.pr_ctime, &psp->pr_ctime);
+ psp->pr_bysize = psp->pr_size * PAGESIZE;
+ psp->pr_byrssize = psp->pr_rssize * PAGESIZE;
+ psp->pr_argc = P->psinfo.pr_argc;
+ psp->pr_argv = (caddr32_t)P->psinfo.pr_argv;
+ psp->pr_envp = (caddr32_t)P->psinfo.pr_envp;
+ psp->pr_wstat = P->psinfo.pr_wstat;
+ psp->pr_pctcpu = P->psinfo.pr_pctcpu;
+ psp->pr_pctmem = P->psinfo.pr_pctmem;
+ psp->pr_euid = P->psinfo.pr_euid;
+ psp->pr_egid = P->psinfo.pr_egid;
+ psp->pr_aslwpid = 0;
+ psp->pr_dmodel = P->psinfo.pr_dmodel;
+}
+
+#endif /* _LP64 */
+
+static int
+write_note(int fd, uint_t type, const void *desc, size_t descsz, off64_t *offp)
+{
+ /*
+ * Note headers are the same regardless of the data model of the
+ * ELF file; we arbitrarily use Elf64_Nhdr here.
+ */
+ struct {
+ Elf64_Nhdr nhdr;
+ char name[8];
+ } n;
+
+ bzero(&n, sizeof (n));
+ bcopy("CORE", n.name, 4);
+ n.nhdr.n_type = type;
+ n.nhdr.n_namesz = 5;
+ n.nhdr.n_descsz = roundup(descsz, 4);
+
+ if (pwrite64(fd, &n, sizeof (n), *offp) != sizeof (n))
+ return (-1);
+
+ *offp += sizeof (n);
+
+ if (pwrite64(fd, desc, n.nhdr.n_descsz, *offp) != n.nhdr.n_descsz)
+ return (-1);
+
+ *offp += n.nhdr.n_descsz;
+
+ return (0);
+}
+
+static int
+old_per_lwp(void *data, const lwpstatus_t *lsp, const lwpsinfo_t *lip)
+{
+ pgcore_t *pgc = data;
+ struct ps_prochandle *P = pgc->P;
+
+ /*
+ * Legacy core files don't contain information about zombie LWPs.
+ * We use Plwp_iter_all() so that we get the lwpsinfo_t structure
+ * more cheaply.
+ */
+ if (lsp == NULL)
+ return (0);
+
+ if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
+ prstatus_t prstatus;
+ mkprstatus(P, lsp, lip, &prstatus);
+ if (write_note(pgc->pgc_fd, NT_PRSTATUS, &prstatus,
+ sizeof (prstatus_t), pgc->pgc_doff) != 0)
+ return (0);
+ if (write_note(pgc->pgc_fd, NT_PRFPREG, &lsp->pr_fpreg,
+ sizeof (prfpregset_t), pgc->pgc_doff) != 0)
+ return (1);
+#ifdef _LP64
+ } else {
+ prstatus32_t pr32;
+ prfpregset32_t pf32;
+ mkprstatus32(P, lsp, lip, &pr32);
+ if (write_note(pgc->pgc_fd, NT_PRSTATUS, &pr32,
+ sizeof (prstatus32_t), pgc->pgc_doff) != 0)
+ return (1);
+ prfpregset_n_to_32(&lsp->pr_fpreg, &pf32);
+ if (write_note(pgc->pgc_fd, NT_PRFPREG, &pf32,
+ sizeof (prfpregset32_t), pgc->pgc_doff) != 0)
+ return (1);
+#endif /* _LP64 */
+ }
+
+#ifdef sparc
+ {
+ prxregset_t xregs;
+ if (Plwp_getxregs(P, lsp->pr_lwpid, &xregs) == 0 &&
+ write_note(pgc->pgc_fd, NT_PRXREG, &xregs,
+ sizeof (prxregset_t), pgc->pgc_doff) != 0)
+ return (1);
+ }
+#endif /* sparc */
+
+ return (0);
+}
+
+static int
+new_per_lwp(void *data, const lwpstatus_t *lsp, const lwpsinfo_t *lip)
+{
+ pgcore_t *pgc = data;
+ struct ps_prochandle *P = pgc->P;
+
+ /*
+ * If lsp is NULL this indicates that this is a zombie LWP in
+ * which case we dump only the lwpsinfo_t structure and none of
+ * the other ancillary LWP state data.
+ */
+ if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
+ if (write_note(pgc->pgc_fd, NT_LWPSINFO, lip,
+ sizeof (lwpsinfo_t), pgc->pgc_doff) != 0)
+ return (1);
+ if (lsp == NULL)
+ return (0);
+ if (write_note(pgc->pgc_fd, NT_LWPSTATUS, lsp,
+ sizeof (lwpstatus_t), pgc->pgc_doff) != 0)
+ return (1);
+#ifdef _LP64
+ } else {
+ lwpsinfo32_t li32;
+ lwpstatus32_t ls32;
+ lwpsinfo_n_to_32(lip, &li32);
+ if (write_note(pgc->pgc_fd, NT_LWPSINFO, &li32,
+ sizeof (lwpsinfo32_t), pgc->pgc_doff) != 0)
+ return (1);
+ if (lsp == NULL)
+ return (0);
+ lwpstatus_n_to_32(lsp, &ls32);
+ if (write_note(pgc->pgc_fd, NT_LWPSTATUS, &ls32,
+ sizeof (lwpstatus32_t), pgc->pgc_doff) != 0)
+ return (1);
+#endif /* _LP64 */
+ }
+
+#ifdef sparc
+ {
+ prxregset_t xregs;
+ gwindows_t gwins;
+ size_t size;
+
+ if (Plwp_getxregs(P, lsp->pr_lwpid, &xregs) == 0) {
+ if (write_note(pgc->pgc_fd, NT_PRXREG, &xregs,
+ sizeof (prxregset_t), pgc->pgc_doff) != 0)
+ return (1);
+ }
+
+ if (Plwp_getgwindows(P, lsp->pr_lwpid, &gwins) == 0 &&
+ gwins.wbcnt > 0) {
+ size = sizeof (gwins) - sizeof (gwins.wbuf) +
+ gwins.wbcnt * sizeof (gwins.wbuf[0]);
+
+ if (write_note(pgc->pgc_fd, NT_GWINDOWS, &gwins, size,
+ pgc->pgc_doff) != 0)
+ return (1);
+ }
+
+ }
+#ifdef __sparcv9
+ if (P->status.pr_dmodel == PR_MODEL_LP64) {
+ asrset_t asrs;
+ if (Plwp_getasrs(P, lsp->pr_lwpid, asrs) == 0) {
+ if (write_note(pgc->pgc_fd, NT_ASRS, &asrs,
+ sizeof (asrset_t), pgc->pgc_doff) != 0)
+ return (1);
+ }
+ }
+#endif /* __sparcv9 */
+#endif /* sparc */
+
+ return (0);
+}
+
+static uint_t
+count_sections(pgcore_t *pgc)
+{
+ struct ps_prochandle *P = pgc->P;
+ file_info_t *fptr;
+ uint_t cnt;
+ uint_t nshdrs = 0;
+
+ if (!(pgc->pgc_content & (CC_CONTENT_CTF | CC_CONTENT_SYMTAB)))
+ return (0);
+
+ fptr = list_next(&P->file_head);
+ for (cnt = P->num_files; cnt > 0; cnt--, fptr = list_next(fptr)) {
+ int hit_symtab = 0;
+
+ Pbuild_file_symtab(P, fptr);
+
+ if ((pgc->pgc_content & CC_CONTENT_CTF) &&
+ Pbuild_file_ctf(P, fptr) != NULL) {
+ sym_tbl_t *sym;
+
+ nshdrs++;
+
+ if (fptr->file_ctf_dyn) {
+ sym = &fptr->file_dynsym;
+ } else {
+ sym = &fptr->file_symtab;
+ hit_symtab = 1;
+ }
+
+ if (sym->sym_data != NULL && sym->sym_symn != 0 &&
+ sym->sym_strs != NULL)
+ nshdrs += 2;
+ }
+
+ if ((pgc->pgc_content & CC_CONTENT_SYMTAB) && !hit_symtab &&
+ fptr->file_symtab.sym_data != NULL &&
+ fptr->file_symtab.sym_symn != 0 &&
+ fptr->file_symtab.sym_strs != NULL) {
+ nshdrs += 2;
+ }
+ }
+
+ return (nshdrs == 0 ? 0 : nshdrs + 2);
+}
+
+static int
+write_shdr(pgcore_t *pgc, shstrtype_t name, uint_t type, ulong_t flags,
+ uintptr_t addr, ulong_t offset, size_t size, uint_t link, uint_t info,
+ uintptr_t addralign, uintptr_t entsize)
+{
+ if (pgc->P->status.pr_dmodel == PR_MODEL_ILP32) {
+ Elf32_Shdr shdr;
+
+ bzero(&shdr, sizeof (shdr));
+ shdr.sh_name = shstrtab_ndx(&pgc->pgc_shstrtab, name);
+ shdr.sh_type = type;
+ shdr.sh_flags = flags;
+ shdr.sh_addr = (Elf32_Addr)addr;
+ shdr.sh_offset = offset;
+ shdr.sh_size = size;
+ shdr.sh_link = link;
+ shdr.sh_info = info;
+ shdr.sh_addralign = addralign;
+ shdr.sh_entsize = entsize;
+
+ if (pwrite64(pgc->pgc_fd, &shdr, sizeof (shdr),
+ *pgc->pgc_soff) != sizeof (shdr))
+ return (-1);
+
+ *pgc->pgc_soff += sizeof (shdr);
+#ifdef _LP64
+ } else {
+ Elf64_Shdr shdr;
+
+ bzero(&shdr, sizeof (shdr));
+ shdr.sh_name = shstrtab_ndx(&pgc->pgc_shstrtab, name);
+ shdr.sh_type = type;
+ shdr.sh_flags = flags;
+ shdr.sh_addr = addr;
+ shdr.sh_offset = offset;
+ shdr.sh_size = size;
+ shdr.sh_link = link;
+ shdr.sh_info = info;
+ shdr.sh_addralign = addralign;
+ shdr.sh_entsize = entsize;
+
+ if (pwrite64(pgc->pgc_fd, &shdr, sizeof (shdr),
+ *pgc->pgc_soff) != sizeof (shdr))
+ return (-1);
+
+ *pgc->pgc_soff += sizeof (shdr);
+#endif /* _LP64 */
+ }
+
+ return (0);
+}
+
+static int
+dump_symtab(pgcore_t *pgc, file_info_t *fptr, uint_t index, int dynsym)
+{
+ sym_tbl_t *sym = dynsym ? &fptr->file_dynsym : &fptr->file_symtab;
+ shstrtype_t symname = dynsym ? STR_DYNSYM : STR_SYMTAB;
+ shstrtype_t strname = dynsym ? STR_DYNSTR : STR_STRTAB;
+ uint_t symtype = dynsym ? SHT_DYNSYM : SHT_SYMTAB;
+ size_t size;
+ uintptr_t addr = fptr->file_map->map_pmap.pr_vaddr;
+
+ if (sym->sym_data == NULL || sym->sym_symn == 0 ||
+ sym->sym_strs == NULL)
+ return (0);
+
+ size = sym->sym_hdr.sh_size;
+ if (pwrite64(pgc->pgc_fd, sym->sym_data->d_buf, size,
+ *pgc->pgc_doff) != size)
+ return (-1);
+
+ if (write_shdr(pgc, symname, symtype, 0, addr, *pgc->pgc_doff, size,
+ index + 1, sym->sym_hdr.sh_info, sym->sym_hdr.sh_addralign,
+ sym->sym_hdr.sh_entsize) != 0)
+ return (-1);
+
+ *pgc->pgc_doff += roundup(size, 8);
+
+ size = sym->sym_strhdr.sh_size;
+ if (pwrite64(pgc->pgc_fd, sym->sym_strs, size, *pgc->pgc_doff) != size)
+ return (-1);
+
+ if (write_shdr(pgc, strname, SHT_STRTAB, SHF_STRINGS, addr,
+ *pgc->pgc_doff, size, 0, 0, 1, 0) != 0)
+ return (-1);
+
+ *pgc->pgc_doff += roundup(size, 8);
+
+ return (0);
+}
+
+static int
+dump_sections(pgcore_t *pgc)
+{
+ struct ps_prochandle *P = pgc->P;
+ file_info_t *fptr;
+ uint_t cnt;
+ uint_t index = 1;
+
+ if (!(pgc->pgc_content & (CC_CONTENT_CTF | CC_CONTENT_SYMTAB)))
+ return (0);
+
+ fptr = list_next(&P->file_head);
+ for (cnt = P->num_files; cnt > 0; cnt--, fptr = list_next(fptr)) {
+ int hit_symtab = 0;
+
+ Pbuild_file_symtab(P, fptr);
+
+ if ((pgc->pgc_content & CC_CONTENT_CTF) &&
+ Pbuild_file_ctf(P, fptr) != NULL) {
+ sym_tbl_t *sym;
+ uint_t dynsym;
+ uint_t symindex = 0;
+
+ /*
+ * Write the symtab out first so we can correctly
+ * set the sh_link field in the CTF section header.
+ * symindex will be 0 if there is no corresponding
+ * symbol table section.
+ */
+ if (fptr->file_ctf_dyn) {
+ sym = &fptr->file_dynsym;
+ dynsym = 1;
+ } else {
+ sym = &fptr->file_symtab;
+ dynsym = 0;
+ hit_symtab = 1;
+ }
+
+ if (sym->sym_data != NULL && sym->sym_symn != 0 &&
+ sym->sym_strs != NULL) {
+ symindex = index;
+ if (dump_symtab(pgc, fptr, index, dynsym) != 0)
+ return (-1);
+ index += 2;
+ }
+
+ /*
+ * Write the CTF data that we've read out of the
+ * file itself into the core file.
+ */
+ if (pwrite64(pgc->pgc_fd, fptr->file_ctf_buf,
+ fptr->file_ctf_size, *pgc->pgc_doff) !=
+ fptr->file_ctf_size)
+ return (-1);
+
+ if (write_shdr(pgc, STR_CTF, SHT_PROGBITS, 0,
+ fptr->file_map->map_pmap.pr_vaddr, *pgc->pgc_doff,
+ fptr->file_ctf_size, symindex, 0, 4, 0) != 0)
+ return (-1);
+
+ index++;
+ *pgc->pgc_doff += roundup(fptr->file_ctf_size, 8);
+ }
+
+ if ((pgc->pgc_content & CC_CONTENT_SYMTAB) && !hit_symtab &&
+ fptr->file_symtab.sym_data != NULL &&
+ fptr->file_symtab.sym_symn != 0 &&
+ fptr->file_symtab.sym_strs != NULL) {
+ if (dump_symtab(pgc, fptr, index, 0) != 0)
+ return (-1);
+ index += 2;
+ }
+ }
+
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+dump_map(void *data, const prmap_t *pmp, const char *name)
+{
+ pgcore_t *pgc = data;
+ struct ps_prochandle *P = pgc->P;
+#ifdef _LP64
+ Elf64_Phdr phdr;
+#else
+ Elf32_Phdr phdr;
+#endif
+ size_t n;
+
+ bzero(&phdr, sizeof (phdr));
+ phdr.p_type = PT_LOAD;
+ phdr.p_vaddr = pmp->pr_vaddr;
+ phdr.p_memsz = pmp->pr_size;
+ if (pmp->pr_mflags & MA_READ)
+ phdr.p_flags |= PF_R;
+ if (pmp->pr_mflags & MA_WRITE)
+ phdr.p_flags |= PF_W;
+ if (pmp->pr_mflags & MA_EXEC)
+ phdr.p_flags |= PF_X;
+
+ if (pmp->pr_vaddr + pmp->pr_size > P->status.pr_stkbase &&
+ pmp->pr_vaddr < P->status.pr_stkbase + P->status.pr_stksize) {
+ if (!(pgc->pgc_content & CC_CONTENT_STACK))
+ goto exclude;
+
+ } else if ((pmp->pr_mflags & MA_ANON) &&
+ pmp->pr_vaddr + pmp->pr_size > P->status.pr_brkbase &&
+ pmp->pr_vaddr < P->status.pr_brkbase + P->status.pr_brksize) {
+ if (!(pgc->pgc_content & CC_CONTENT_HEAP))
+ goto exclude;
+
+ } else if (pmp->pr_mflags & MA_ISM) {
+ if (pmp->pr_mflags & MA_NORESERVE) {
+ if (!(pgc->pgc_content & CC_CONTENT_DISM))
+ goto exclude;
+ } else {
+ if (!(pgc->pgc_content & CC_CONTENT_ISM))
+ goto exclude;
+ }
+
+ } else if (pmp->pr_mflags & MA_SHM) {
+ if (!(pgc->pgc_content & CC_CONTENT_SHM))
+ goto exclude;
+
+ } else if (pmp->pr_mflags & MA_SHARED) {
+ if (pmp->pr_mflags & MA_ANON) {
+ if (!(pgc->pgc_content & CC_CONTENT_SHANON))
+ goto exclude;
+ } else {
+ if (!(pgc->pgc_content & CC_CONTENT_SHFILE))
+ goto exclude;
+ }
+
+ } else if (pmp->pr_mflags & MA_ANON) {
+ if (!(pgc->pgc_content & CC_CONTENT_ANON))
+ goto exclude;
+
+ } else if (phdr.p_flags == (PF_R | PF_X)) {
+ if (!(pgc->pgc_content & CC_CONTENT_TEXT))
+ goto exclude;
+
+ } else if (phdr.p_flags == PF_R) {
+ if (!(pgc->pgc_content & CC_CONTENT_RODATA))
+ goto exclude;
+
+ } else {
+ if (!(pgc->pgc_content & CC_CONTENT_DATA))
+ goto exclude;
+ }
+
+ n = 0;
+ while (n < pmp->pr_size) {
+ size_t csz = MIN(pmp->pr_size - n, pgc->pgc_chunksz);
+
+ /*
+ * If we can't read out part of the victim's address
+ * space for some reason ignore that failure and try to
+ * emit a partial core file without that mapping's data.
+ * As in the kernel, we mark these failures with the
+ * PF_SUNW_FAILURE flag and store the errno where the
+ * mapping would have been.
+ */
+ if (Pread(P, pgc->pgc_chunk, csz, pmp->pr_vaddr + n) != csz ||
+ pwrite64(pgc->pgc_fd, pgc->pgc_chunk, csz,
+ *pgc->pgc_doff + n) != csz) {
+ int err = errno;
+ (void) pwrite64(pgc->pgc_fd, &err, sizeof (err),
+ *pgc->pgc_doff);
+ *pgc->pgc_doff += roundup(sizeof (err), 8);
+
+ phdr.p_flags |= PF_SUNW_FAILURE;
+ (void) ftruncate64(pgc->pgc_fd, *pgc->pgc_doff);
+ goto exclude;
+ }
+
+ n += csz;
+ }
+
+ phdr.p_offset = *pgc->pgc_doff;
+ phdr.p_filesz = pmp->pr_size;
+ *pgc->pgc_doff += roundup(phdr.p_filesz, 8);
+
+exclude:
+ if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
+ if (pwrite64(pgc->pgc_fd, &phdr, sizeof (phdr),
+ *pgc->pgc_poff) != sizeof (phdr))
+ return (1);
+
+ *pgc->pgc_poff += sizeof (phdr);
+#ifdef _LP64
+ } else {
+ Elf32_Phdr phdr32;
+
+ bzero(&phdr32, sizeof (phdr32));
+ phdr32.p_type = phdr.p_type;
+ phdr32.p_vaddr = (Elf32_Addr)phdr.p_vaddr;
+ phdr32.p_memsz = (Elf32_Word)phdr.p_memsz;
+ phdr32.p_flags = phdr.p_flags;
+ phdr32.p_offset = (Elf32_Off)phdr.p_offset;
+ phdr32.p_filesz = (Elf32_Word)phdr.p_filesz;
+
+ if (pwrite64(pgc->pgc_fd, &phdr32, sizeof (phdr32),
+ *pgc->pgc_poff) != sizeof (phdr32))
+ return (1);
+
+ *pgc->pgc_poff += sizeof (phdr32);
+#endif /* _LP64 */
+ }
+
+ return (0);
+}
+
+int
+write_shstrtab(struct ps_prochandle *P, pgcore_t *pgc)
+{
+ off64_t off = *pgc->pgc_doff;
+ size_t size = 0;
+ shstrtab_t *s = &pgc->pgc_shstrtab;
+ int i, ndx;
+
+ if (shstrtab_size(s) == 1)
+ return (0);
+
+ /*
+ * Preemptively stick the name of the shstrtab in the string table.
+ */
+ (void) shstrtab_ndx(&pgc->pgc_shstrtab, STR_SHSTRTAB);
+ size = shstrtab_size(s);
+
+ if (pwrite64(pgc->pgc_fd, "", 1, off) != 1)
+ return (1);
+
+ /*
+ * Dump all the strings that we used being sure we include the
+ * terminating null character.
+ */
+ for (i = 0; i < STR_NUM; i++) {
+ if ((ndx = s->sst_ndx[i]) != 0) {
+ const char *str = shstrtab_data[i];
+ size_t len = strlen(str) + 1;
+ if (pwrite64(pgc->pgc_fd, str, len, off + ndx) != len)
+ return (1);
+ }
+ }
+
+ if (P->status.pr_dmodel == PR_MODEL_ILP32) {
+ Elf32_Shdr shdr;
+
+ bzero(&shdr, sizeof (shdr));
+ shdr.sh_name = shstrtab_ndx(&pgc->pgc_shstrtab, STR_SHSTRTAB);
+ shdr.sh_size = size;
+ shdr.sh_offset = *pgc->pgc_doff;
+ shdr.sh_addralign = 1;
+ shdr.sh_flags = SHF_STRINGS;
+ shdr.sh_type = SHT_STRTAB;
+
+ if (pwrite64(pgc->pgc_fd, &shdr, sizeof (shdr),
+ *pgc->pgc_soff) != sizeof (shdr))
+ return (1);
+
+ *pgc->pgc_soff += sizeof (shdr);
+#ifdef _LP64
+ } else {
+ Elf64_Shdr shdr;
+
+ bzero(&shdr, sizeof (shdr));
+ shdr.sh_name = shstrtab_ndx(&pgc->pgc_shstrtab, STR_SHSTRTAB);
+ shdr.sh_size = size;
+ shdr.sh_offset = *pgc->pgc_doff;
+ shdr.sh_addralign = 1;
+ shdr.sh_flags = SHF_STRINGS;
+ shdr.sh_type = SHT_STRTAB;
+
+ if (pwrite64(pgc->pgc_fd, &shdr, sizeof (shdr),
+ *pgc->pgc_soff) != sizeof (shdr))
+ return (1);
+
+ *pgc->pgc_soff += sizeof (shdr);
+#endif /* _LP64 */
+ }
+
+ *pgc->pgc_doff += roundup(size, 8);
+
+ return (0);
+}
+
+/*
+ * Don't explicity stop the process; that's up to the consumer.
+ */
+int
+Pfgcore(struct ps_prochandle *P, int fd, core_content_t content)
+{
+ char plat[SYS_NMLN];
+ char zonename[ZONENAME_MAX];
+ int platlen = -1;
+ pgcore_t pgc;
+ off64_t poff, soff, doff, boff;
+ struct utsname uts;
+ uint_t nphdrs, nshdrs;
+
+ if (ftruncate64(fd, 0) != 0)
+ return (-1);
+
+ if (content == CC_CONTENT_INVALID) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ /*
+ * Cache the mappings and other useful data.
+ */
+ (void) Prd_agent(P);
+ (void) Ppsinfo(P);
+
+ pgc.P = P;
+ pgc.pgc_fd = fd;
+ pgc.pgc_poff = &poff;
+ pgc.pgc_soff = &soff;
+ pgc.pgc_doff = &doff;
+ pgc.pgc_content = content;
+ pgc.pgc_chunksz = PAGESIZE;
+ if ((pgc.pgc_chunk = malloc(pgc.pgc_chunksz)) == NULL)
+ return (-1);
+
+ shstrtab_init(&pgc.pgc_shstrtab);
+
+ /*
+ * There are two PT_NOTE program headers for ancillary data, and
+ * one for each mapping.
+ */
+ nphdrs = 2 + P->map_count;
+ nshdrs = count_sections(&pgc);
+
+ (void) Pplatform(P, plat, sizeof (plat));
+ platlen = strlen(plat) + 1;
+ Preadauxvec(P);
+ (void) Puname(P, &uts);
+ if (Pzonename(P, zonename, sizeof (zonename)) == NULL)
+ zonename[0] = '\0';
+
+ /*
+ * Set up the ELF header.
+ */
+ if (P->status.pr_dmodel == PR_MODEL_ILP32) {
+ Elf32_Ehdr ehdr;
+
+ bzero(&ehdr, sizeof (ehdr));
+ ehdr.e_ident[EI_MAG0] = ELFMAG0;
+ ehdr.e_ident[EI_MAG1] = ELFMAG1;
+ ehdr.e_ident[EI_MAG2] = ELFMAG2;
+ ehdr.e_ident[EI_MAG3] = ELFMAG3;
+ ehdr.e_type = ET_CORE;
+
+ ehdr.e_ident[EI_CLASS] = ELFCLASS32;
+#if defined(__sparc)
+ ehdr.e_machine = EM_SPARC;
+ ehdr.e_ident[EI_DATA] = ELFDATA2MSB;
+#elif defined(__i386) || defined(__amd64)
+ ehdr.e_machine = EM_386;
+ ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
+#else
+#error "unknown machine type"
+#endif
+ ehdr.e_ident[EI_VERSION] = EV_CURRENT;
+
+ ehdr.e_version = EV_CURRENT;
+ ehdr.e_ehsize = sizeof (ehdr);
+ ehdr.e_phentsize = sizeof (Elf32_Phdr);
+ ehdr.e_phnum = (unsigned short)nphdrs;
+ ehdr.e_phoff = ehdr.e_ehsize;
+
+ if (nshdrs != 0) {
+ ehdr.e_shentsize = sizeof (Elf32_Shdr);
+ ehdr.e_shnum = (unsigned short)nshdrs;
+ ehdr.e_shoff = ehdr.e_phoff +
+ ehdr.e_phentsize * ehdr.e_phnum;
+ ehdr.e_shstrndx = nshdrs - 1;
+ }
+
+ if (pwrite64(fd, &ehdr, sizeof (ehdr), 0) != sizeof (ehdr))
+ goto err;
+
+ poff = ehdr.e_phoff;
+ soff = ehdr.e_shoff + ehdr.e_shentsize;
+ doff = boff = ehdr.e_ehsize +
+ ehdr.e_phentsize * ehdr.e_phnum +
+ ehdr.e_shentsize * ehdr.e_shnum;
+
+#ifdef _LP64
+ } else {
+ Elf64_Ehdr ehdr;
+
+ bzero(&ehdr, sizeof (ehdr));
+ ehdr.e_ident[EI_MAG0] = ELFMAG0;
+ ehdr.e_ident[EI_MAG1] = ELFMAG1;
+ ehdr.e_ident[EI_MAG2] = ELFMAG2;
+ ehdr.e_ident[EI_MAG3] = ELFMAG3;
+ ehdr.e_type = ET_CORE;
+
+ ehdr.e_ident[EI_CLASS] = ELFCLASS64;
+#if defined(__sparc)
+ ehdr.e_machine = EM_SPARCV9;
+ ehdr.e_ident[EI_DATA] = ELFDATA2MSB;
+#elif defined(__i386) || defined(__amd64)
+ ehdr.e_machine = EM_AMD64;
+ ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
+#else
+#error "unknown machine type"
+#endif
+ ehdr.e_ident[EI_VERSION] = EV_CURRENT;
+
+ ehdr.e_version = EV_CURRENT;
+ ehdr.e_ehsize = sizeof (ehdr);
+ ehdr.e_phentsize = sizeof (Elf64_Phdr);
+ ehdr.e_phnum = (unsigned short)nphdrs;
+ ehdr.e_phoff = ehdr.e_ehsize;
+
+ if (nshdrs != 0) {
+ ehdr.e_shentsize = sizeof (Elf64_Shdr);
+ ehdr.e_shnum = (unsigned short)nshdrs;
+ ehdr.e_shoff = ehdr.e_phoff +
+ ehdr.e_phentsize * ehdr.e_phnum;
+ ehdr.e_shstrndx = nshdrs - 1;
+ }
+
+ if (pwrite64(fd, &ehdr, sizeof (ehdr), 0) != sizeof (ehdr))
+ goto err;
+
+ poff = ehdr.e_phoff;
+ soff = ehdr.e_shoff + ehdr.e_shentsize;
+ doff = boff = sizeof (ehdr) +
+ ehdr.e_phentsize * ehdr.e_phnum +
+ ehdr.e_shentsize * ehdr.e_shnum;
+
+#endif /* _LP64 */
+ }
+
+ /*
+ * Construct the old-style note header and section.
+ */
+
+ if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
+ prpsinfo_t prpsinfo;
+
+ mkprpsinfo(P, &prpsinfo);
+ if (write_note(fd, NT_PRPSINFO, &prpsinfo, sizeof (prpsinfo_t),
+ &doff) != 0) {
+ goto err;
+ }
+ if (write_note(fd, NT_AUXV, P->auxv,
+ P->nauxv * sizeof (P->auxv[0]), &doff) != 0) {
+ goto err;
+ }
+#ifdef _LP64
+ } else {
+ prpsinfo32_t pi32;
+ auxv32_t *av32;
+ size_t size = sizeof (auxv32_t) * P->nauxv;
+ int i;
+
+ mkprpsinfo32(P, &pi32);
+ if (write_note(fd, NT_PRPSINFO, &pi32, sizeof (prpsinfo32_t),
+ &doff) != 0) {
+ goto err;
+ }
+
+ if ((av32 = malloc(size)) == NULL)
+ goto err;
+
+ for (i = 0; i < P->nauxv; i++) {
+ auxv_n_to_32(&P->auxv[i], &av32[i]);
+ }
+
+ if (write_note(fd, NT_AUXV, av32, size, &doff) != 0) {
+ free(av32);
+ goto err;
+ }
+
+ free(av32);
+#endif /* _LP64 */
+ }
+
+ if (write_note(fd, NT_PLATFORM, plat, platlen, &doff) != 0)
+ goto err;
+
+ if (Plwp_iter_all(P, old_per_lwp, &pgc) != 0)
+ goto err;
+
+ if (P->status.pr_dmodel == PR_MODEL_ILP32) {
+ Elf32_Phdr phdr;
+
+ bzero(&phdr, sizeof (phdr));
+ phdr.p_type = PT_NOTE;
+ phdr.p_flags = PF_R;
+ phdr.p_offset = (Elf32_Off)boff;
+ phdr.p_filesz = doff - boff;
+ boff = doff;
+
+ if (pwrite64(fd, &phdr, sizeof (phdr), poff) != sizeof (phdr))
+ goto err;
+ poff += sizeof (phdr);
+#ifdef _LP64
+ } else {
+ Elf64_Phdr phdr;
+
+ bzero(&phdr, sizeof (phdr));
+ phdr.p_type = PT_NOTE;
+ phdr.p_flags = PF_R;
+ phdr.p_offset = boff;
+ phdr.p_filesz = doff - boff;
+ boff = doff;
+
+ if (pwrite64(fd, &phdr, sizeof (phdr), poff) != sizeof (phdr))
+ goto err;
+ poff += sizeof (phdr);
+#endif /* _LP64 */
+ }
+
+ /*
+ * Construct the new-style note header and section.
+ */
+
+ if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
+ if (write_note(fd, NT_PSINFO, &P->psinfo, sizeof (psinfo_t),
+ &doff) != 0) {
+ goto err;
+ }
+ if (write_note(fd, NT_PSTATUS, &P->status, sizeof (pstatus_t),
+ &doff) != 0) {
+ goto err;
+ }
+ if (write_note(fd, NT_AUXV, P->auxv,
+ P->nauxv * sizeof (P->auxv[0]), &doff) != 0) {
+ goto err;
+ }
+#ifdef _LP64
+ } else {
+ psinfo32_t pi32;
+ pstatus32_t ps32;
+ auxv32_t *av32;
+ size_t size = sizeof (auxv32_t) * P->nauxv;
+ int i;
+
+ psinfo_n_to_32(&P->psinfo, &pi32);
+ if (write_note(fd, NT_PSINFO, &pi32, sizeof (psinfo32_t),
+ &doff) != 0) {
+ goto err;
+ }
+ pstatus_n_to_32(&P->status, &ps32);
+ if (write_note(fd, NT_PSTATUS, &ps32, sizeof (pstatus32_t),
+ &doff) != 0) {
+ goto err;
+ }
+ if ((av32 = malloc(size)) == NULL)
+ goto err;
+
+ for (i = 0; i < P->nauxv; i++) {
+ auxv_n_to_32(&P->auxv[i], &av32[i]);
+ }
+
+ if (write_note(fd, NT_AUXV, av32, size, &doff) != 0) {
+ free(av32);
+ goto err;
+ }
+
+ free(av32);
+#endif /* _LP64 */
+ }
+
+ if (write_note(fd, NT_PLATFORM, plat, platlen, &doff) != 0 ||
+ write_note(fd, NT_UTSNAME, &uts, sizeof (uts), &doff) != 0 ||
+ write_note(fd, NT_CONTENT, &content, sizeof (content), &doff) != 0)
+ goto err;
+
+ {
+ prcred_t cred, *cp;
+ size_t size = sizeof (prcred_t);
+
+ if (Pcred(P, &cred, 0) != 0)
+ goto err;
+
+ if (cred.pr_ngroups > 0)
+ size += sizeof (gid_t) * (cred.pr_ngroups - 1);
+ if ((cp = malloc(size)) == NULL)
+ goto err;
+
+ if (Pcred(P, cp, cred.pr_ngroups) != 0 ||
+ write_note(fd, NT_PRCRED, cp, size, &doff) != 0) {
+ free(cp);
+ goto err;
+ }
+
+ free(cp);
+ }
+
+ {
+ prpriv_t *ppriv;
+ const priv_impl_info_t *pinfo;
+ size_t pprivsz, pinfosz;
+
+ if ((ppriv = proc_get_priv(P->pid)) == NULL)
+ goto err;
+ pprivsz = PRIV_PRPRIV_SIZE(ppriv);
+
+ if (write_note(fd, NT_PRPRIV, ppriv, pprivsz, &doff) != 0) {
+ free(ppriv);
+ goto err;
+ }
+ free(ppriv);
+
+ if ((pinfo = getprivimplinfo()) == NULL)
+ goto err;
+ pinfosz = PRIV_IMPL_INFO_SIZE(pinfo);
+
+ if (write_note(fd, NT_PRPRIVINFO, pinfo, pinfosz, &doff) != 0)
+ goto err;
+ }
+
+ if (write_note(fd, NT_ZONENAME, zonename, strlen(zonename) + 1,
+ &doff) != 0)
+ goto err;
+
+#if defined(__i386) || defined(__amd64)
+ /* CSTYLED */
+ {
+ struct ssd *ldtp;
+ size_t size;
+ int nldt;
+
+ nldt = Pldt(P, NULL, 0);
+ size = sizeof (struct ssd) * nldt;
+ if ((ldtp = malloc(size)) == NULL)
+ goto err;
+
+ if (Pldt(P, ldtp, nldt) == -1 ||
+ write_note(fd, NT_LDT, ldtp, size, &doff) != 0) {
+ free(ldtp);
+ goto err;
+ }
+
+ free(ldtp);
+ }
+#endif /* __i386 || __amd64 */
+
+ if (Plwp_iter_all(P, new_per_lwp, &pgc) != 0)
+ goto err;
+
+ if (P->status.pr_dmodel == PR_MODEL_ILP32) {
+ Elf32_Phdr phdr;
+
+ bzero(&phdr, sizeof (phdr));
+ phdr.p_type = PT_NOTE;
+ phdr.p_flags = PF_R;
+ phdr.p_offset = (Elf32_Off)boff;
+ phdr.p_filesz = doff - boff;
+ boff = doff;
+
+ if (pwrite64(fd, &phdr, sizeof (phdr), poff) != sizeof (phdr))
+ goto err;
+ poff += sizeof (phdr);
+#ifdef _LP64
+ } else {
+ Elf64_Phdr phdr;
+
+ bzero(&phdr, sizeof (phdr));
+ phdr.p_type = PT_NOTE;
+ phdr.p_flags = PF_R;
+ phdr.p_offset = boff;
+ phdr.p_filesz = doff - boff;
+ boff = doff;
+
+ if (pwrite64(fd, &phdr, sizeof (phdr), poff) != sizeof (phdr))
+ goto err;
+ poff += sizeof (phdr);
+#endif /* _LP64 */
+ }
+
+ /*
+ * Construct the headers for each mapping and write out its data
+ * if the content parameter indicates that it should be present
+ * in the core file.
+ */
+ if (Pmapping_iter(P, dump_map, &pgc) != 0)
+ goto err;
+
+ if (dump_sections(&pgc) != 0)
+ goto err;
+
+ if (write_shstrtab(P, &pgc) != 0)
+ goto err;
+
+ free(pgc.pgc_chunk);
+
+ return (0);
+
+err:
+ /*
+ * Wipe out anything we may have written if there was an error.
+ */
+ (void) ftruncate64(fd, 0);
+ free(pgc.pgc_chunk);
+ return (-1);
+}
+
+static const char *content_str[] = {
+ "stack", /* CC_CONTENT_STACK */
+ "heap", /* CC_CONTENT_HEAP */
+ "shfile", /* CC_CONTENT_SHFILE */
+ "shanon", /* CC_CONTENT_SHANON */
+ "text", /* CC_CONTENT_TEXT */
+ "data", /* CC_CONTENT_DATA */
+ "rodata", /* CC_CONTENT_RODATA */
+ "anon", /* CC_CONTENT_ANON */
+ "shm", /* CC_CONTENT_SHM */
+ "ism", /* CC_CONTENT_ISM */
+ "dism", /* CC_CONTENT_DISM */
+ "ctf", /* CC_CONTENT_CTF */
+ "symtab", /* CC_CONTENT_SYMTAB */
+};
+
+static uint_t ncontent_str = sizeof (content_str) / sizeof (content_str[0]);
+
+#define STREQ(a, b, n) (strlen(b) == (n) && strncmp(a, b, n) == 0)
+
+int
+proc_str2content(const char *str, core_content_t *cp)
+{
+ const char *cur = str;
+ int add = 1;
+ core_content_t mask, content = 0;
+
+ for (;;) {
+ for (cur = str; isalpha(*cur); cur++)
+ continue;
+
+ if (STREQ(str, "default", cur - str)) {
+ mask = CC_CONTENT_DEFAULT;
+ } else if (STREQ(str, "all", cur - str)) {
+ mask = CC_CONTENT_ALL;
+ } else if (STREQ(str, "none", cur - str)) {
+ mask = 0;
+ } else {
+ int i = 0;
+
+ while (!STREQ(str, content_str[i], cur - str)) {
+ i++;
+
+ if (i >= ncontent_str)
+ return (-1);
+ }
+
+ mask = (core_content_t)1 << i;
+ }
+
+ if (add)
+ content |= mask;
+ else
+ content &= ~mask;
+
+ switch (*cur) {
+ case '\0':
+ *cp = content;
+ return (0);
+ case '+':
+ add = 1;
+ break;
+ case '-':
+ add = 0;
+ break;
+ default:
+ return (-1);
+ }
+
+ str = cur + 1;
+ }
+}
+
+static int
+popc(core_content_t x)
+{
+ int i;
+
+ for (i = 0; x != 0; i++)
+ x &= x - 1;
+
+ return (i);
+}
+
+int
+proc_content2str(core_content_t content, char *buf, size_t size)
+{
+ int nonecnt, defcnt, allcnt;
+ core_content_t mask, bit;
+ int first;
+ uint_t index;
+ size_t n, tot = 0;
+
+ if (content == 0)
+ return ((int)strlcpy(buf, "none", size));
+
+ if (content & ~CC_CONTENT_ALL)
+ return ((int)strlcpy(buf, "<invalid>", size));
+
+ nonecnt = popc(content);
+ defcnt = 1 + popc(content ^ CC_CONTENT_DEFAULT);
+ allcnt = 1 + popc(content ^ CC_CONTENT_ALL);
+
+ if (defcnt <= nonecnt && defcnt <= allcnt) {
+ mask = content ^ CC_CONTENT_DEFAULT;
+ first = 0;
+ tot += (n = strlcpy(buf, "default", size));
+ if (n > size)
+ n = size;
+ buf += n;
+ size -= n;
+ } else if (allcnt < nonecnt) {
+ mask = content ^ CC_CONTENT_ALL;
+ first = 0;
+ tot += (n = strlcpy(buf, "all", size));
+ if (n > size)
+ n = size;
+ buf += n;
+ size -= n;
+ } else {
+ mask = content;
+ first = 1;
+ }
+
+ while (mask != 0) {
+ bit = mask ^ (mask & (mask - 1));
+
+ if (!first) {
+ if (size > 1) {
+ *buf = (bit & content) ? '+' : '-';
+ buf++;
+ size--;
+ }
+
+ tot++;
+ }
+ index = popc(bit - 1);
+ tot += (n = strlcpy(buf, content_str[index], size));
+ if (n > size)
+ n = size;
+ buf += n;
+ size -= n;
+
+ mask ^= bit;
+ first = 0;
+ }
+
+ return ((int)tot);
+}
diff --git a/usr/src/lib/libproc/common/Pidle.c b/usr/src/lib/libproc/common/Pidle.c
new file mode 100644
index 0000000000..bf05e6a2e9
--- /dev/null
+++ b/usr/src/lib/libproc/common/Pidle.c
@@ -0,0 +1,259 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <libelf.h>
+#include <libgen.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+#include <sys/sysmacros.h>
+
+#include "Pcontrol.h"
+
+static ssize_t
+Pread_idle(struct ps_prochandle *P, void *buf, size_t n, uintptr_t addr)
+{
+ size_t resid = n;
+
+ while (resid > 0) {
+ map_info_t *mp;
+ uintptr_t mapoff;
+ ssize_t len;
+ off64_t off;
+
+ if ((mp = Paddr2mptr(P, addr)) == NULL)
+ break;
+
+ mapoff = addr - mp->map_pmap.pr_vaddr;
+ len = MIN(resid, mp->map_pmap.pr_size - mapoff);
+ off = mp->map_offset + mapoff;
+
+ if ((len = pread64(P->asfd, buf, len, off)) <= 0)
+ break;
+
+ resid -= len;
+ addr += len;
+ buf = (char *)buf + len;
+ }
+
+ return (n - resid);
+}
+
+/*ARGSUSED*/
+static ssize_t
+Pwrite_idle(struct ps_prochandle *P, const void *buf, size_t n, uintptr_t addr)
+{
+ errno = EIO;
+ return (-1);
+}
+
+static const ps_rwops_t P_idle_ops = {
+ Pread_idle,
+ Pwrite_idle
+};
+
+static int
+idle_add_mapping(struct ps_prochandle *P, GElf_Phdr *php, file_info_t *fp)
+{
+ prmap_t pmap;
+
+ dprintf("mapping base %llx filesz %llu memsz %llu offset %llu\n",
+ (u_longlong_t)php->p_vaddr, (u_longlong_t)php->p_filesz,
+ (u_longlong_t)php->p_memsz, (u_longlong_t)php->p_offset);
+
+ pmap.pr_vaddr = (uintptr_t)php->p_vaddr;
+ pmap.pr_size = php->p_filesz;
+ (void) strncpy(pmap.pr_mapname, fp->file_pname,
+ sizeof (pmap.pr_mapname));
+ pmap.pr_offset = php->p_offset;
+
+ pmap.pr_mflags = 0;
+ if (php->p_flags & PF_R)
+ pmap.pr_mflags |= MA_READ;
+ if (php->p_flags & PF_W)
+ pmap.pr_mflags |= MA_WRITE;
+ if (php->p_flags & PF_X)
+ pmap.pr_mflags |= MA_EXEC;
+
+ pmap.pr_pagesize = 0;
+ pmap.pr_shmid = -1;
+
+ return (Padd_mapping(P, php->p_offset, fp, &pmap));
+}
+
+struct ps_prochandle *
+Pgrab_file(const char *fname, int *perr)
+{
+ struct ps_prochandle *P = NULL;
+ GElf_Ehdr ehdr;
+ Elf *elf = NULL;
+ file_info_t *fp = NULL;
+ int fd;
+ int i;
+
+ if ((fd = open64(fname, O_RDONLY)) < 0) {
+ dprintf("couldn't open file");
+ *perr = (errno == ENOENT) ? G_NOEXEC : G_STRANGE;
+ return (NULL);
+ }
+
+ if (elf_version(EV_CURRENT) == EV_NONE) {
+ dprintf("libproc ELF version is more recent than libelf");
+ *perr = G_ELF;
+ goto err;
+ }
+
+ if ((P = calloc(1, sizeof (struct ps_prochandle))) == NULL) {
+ *perr = G_STRANGE;
+ goto err;
+ }
+
+ (void) mutex_init(&P->proc_lock, USYNC_THREAD, NULL);
+ P->state = PS_IDLE;
+ P->pid = (pid_t)-1;
+ P->asfd = fd;
+ P->ctlfd = -1;
+ P->statfd = -1;
+ P->agentctlfd = -1;
+ P->agentstatfd = -1;
+ P->info_valid = -1;
+ P->ops = &P_idle_ops;
+ Pinitsym(P);
+
+ if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
+ *perr = G_ELF;
+ return (NULL);
+ }
+
+ /*
+ * Construct a file_info_t that corresponds to this file.
+ */
+ if ((fp = calloc(1, sizeof (file_info_t))) == NULL) {
+ *perr = G_STRANGE;
+ goto err;
+ }
+
+ if ((fp->file_lo = calloc(1, sizeof (rd_loadobj_t))) == NULL) {
+ *perr = G_STRANGE;
+ goto err;
+ }
+
+ if (*fname == '/') {
+ (void) strncpy(fp->file_pname, fname, sizeof (fp->file_pname));
+ } else {
+ size_t sz;
+
+ if (getcwd(fp->file_pname, sizeof (fp->file_pname) - 1) ==
+ NULL) {
+ *perr = G_STRANGE;
+ goto err;
+ }
+
+ sz = strlen(fp->file_pname);
+ (void) snprintf(&fp->file_pname[sz],
+ sizeof (fp->file_pname) - sz, "/%s", fname);
+ }
+
+ fp->file_fd = fd;
+ fp->file_lo->rl_lmident = LM_ID_BASE;
+ fp->file_lname = strdup(fp->file_pname);
+ fp->file_lbase = basename(fp->file_lname);
+
+ P->execname = strdup(fp->file_pname);
+
+ P->num_files++;
+ list_link(fp, &P->file_head);
+
+ if (gelf_getehdr(elf, &ehdr) == NULL) {
+ *perr = G_STRANGE;
+ goto err;
+ }
+
+ dprintf("Pgrab_file: ehdr.e_phnum = %d\n", ehdr.e_phnum);
+
+ /*
+ * Sift through the program headers making the relevant maps.
+ */
+ for (i = 0; i < ehdr.e_phnum; i++) {
+ GElf_Phdr phdr, *php;
+
+ if ((php = gelf_getphdr(elf, i, &phdr)) == NULL) {
+ *perr = G_STRANGE;
+ goto err;
+ }
+
+ if (php->p_type != PT_LOAD)
+ continue;
+
+ if (idle_add_mapping(P, php, fp) != 0) {
+ *perr = G_STRANGE;
+ goto err;
+ }
+ }
+ Psort_mappings(P);
+
+ (void) elf_end(elf);
+
+ P->map_exec = fp->file_map;
+
+ P->status.pr_flags = PR_STOPPED;
+ P->status.pr_nlwp = 0;
+ P->status.pr_pid = (pid_t)-1;
+ P->status.pr_ppid = (pid_t)-1;
+ P->status.pr_pgid = (pid_t)-1;
+ P->status.pr_sid = (pid_t)-1;
+ P->status.pr_taskid = (taskid_t)-1;
+ P->status.pr_projid = (projid_t)-1;
+ switch (ehdr.e_ident[EI_CLASS]) {
+ case ELFCLASS32:
+ P->status.pr_dmodel = PR_MODEL_ILP32;
+ break;
+ case ELFCLASS64:
+ P->status.pr_dmodel = PR_MODEL_LP64;
+ break;
+ default:
+ *perr = G_FORMAT;
+ goto err;
+ }
+
+ /*
+ * The file and map lists are complete, and will never need to be
+ * adjusted.
+ */
+ P->info_valid = 1;
+
+ return (P);
+err:
+ (void) close(fd);
+ if (P != NULL)
+ Pfree(P);
+ if (elf != NULL)
+ (void) elf_end(elf);
+ return (NULL);
+}
diff --git a/usr/src/lib/libproc/common/Pisadep.h b/usr/src/lib/libproc/common/Pisadep.h
new file mode 100644
index 0000000000..1d7e785ae3
--- /dev/null
+++ b/usr/src/lib/libproc/common/Pisadep.h
@@ -0,0 +1,101 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _PISADEP_H
+#define _PISADEP_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Internal ISA-dependent functions.
+ *
+ * Note that some ISA-dependent functions are exposed to applications, and found
+ * in libproc.h:
+ *
+ * Ppltdest()
+ * Pissyscall_prev()
+ * Pstack_iter()
+ */
+
+/*
+ * ISA dependent function to determine if the instruction at the given address
+ * is a syscall instruction. On x86, we have multiple system call instructions.
+ * this function returns 1 if there is a system call at the given address, 2 if
+ * there is a less preferred system call, and 0 if there is no system call
+ * there.
+ */
+extern int Pissyscall(struct ps_prochandle *, uintptr_t);
+/*
+ * Works the same way as Pissyscall(), except operates on an in-memory buffer.
+ */
+extern int Pissyscall_text(struct ps_prochandle *, const void *buf,
+ size_t buflen);
+
+#if defined(__amd64)
+/* amd64 stack doubleword aligned, unaligned in 32-bit mode */
+#define PSTACK_ALIGN32(sp) ((sp) & ~(2 * sizeof (int64_t) - 1))
+#define PSTACK_ALIGN64(sp) (sp)
+#elif defined(__i386)
+/* i386 stack is unaligned */
+#define PSTACK_ALIGN32(sp) (sp)
+#define PSTACK_ALIGN64(sp) ALIGN32(sp)
+#elif defined(__sparc)
+/* sparc stack is doubleword aligned for 64-bit values */
+#define PSTACK_ALIGN32(sp) ((sp) & ~(2 * sizeof (int32_t) - 1))
+#define PSTACK_ALIGN64(sp) ((sp) & ~(2 * sizeof (int64_t) - 1))
+#else
+#error Unknown ISA
+#endif
+
+/*
+ * Given an argument count, stack pointer, and syscall index, sets up the stack
+ * and appropriate registers. The stack pointer should be the top of the stack
+ * area, after any space reserved for arguments passed by reference. Returns a
+ * pointer which is later passed to Psyscall_copyargs().
+ */
+extern uintptr_t Psyscall_setup(struct ps_prochandle *, int, int, uintptr_t);
+
+/*
+ * Copies all arguments out to the stack once we're stopped before the syscall.
+ */
+extern int Psyscall_copyinargs(struct ps_prochandle *, int, argdes_t *,
+ uintptr_t);
+
+/*
+ * Copies out arguments to their original values.
+ */
+extern int Psyscall_copyoutargs(struct ps_prochandle *, int, argdes_t *,
+ uintptr_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PISADEP_H */
diff --git a/usr/src/lib/libproc/common/Pisprocdir.c b/usr/src/lib/libproc/common/Pisprocdir.c
new file mode 100644
index 0000000000..b617b2edda
--- /dev/null
+++ b/usr/src/lib/libproc/common/Pisprocdir.c
@@ -0,0 +1,62 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1997-2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <string.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "Pcontrol.h"
+
+/*
+ * Return TRUE iff dir is the /proc directory.
+ */
+int
+Pisprocdir(struct ps_prochandle *Pr, const char *dir)
+{
+ char path[PATH_MAX];
+ struct stat statb;
+ struct statvfs statvfsb;
+
+ if (*dir == '/')
+ (void) snprintf(path, sizeof (path), "/proc/%d/root%s",
+ (int)Pr->pid, dir);
+ else
+ (void) snprintf(path, sizeof (path), "/proc/%d/cwd/%s",
+ (int)Pr->pid, dir);
+
+ /*
+ * We can't compare the statb.st_fstype string to "proc" because
+ * a loop-back mount of /proc would show "lofs" instead of "proc".
+ * Instead we use the statvfs() f_basetype string.
+ */
+ return (stat(path, &statb) == 0 &&
+ statvfs(path, &statvfsb) == 0 &&
+ (statb.st_mode & S_IFMT) == S_IFDIR &&
+ statb.st_ino == 2 &&
+ strcmp(statvfsb.f_basetype, "proc") == 0);
+}
diff --git a/usr/src/lib/libproc/common/Plwpregs.c b/usr/src/lib/libproc/common/Plwpregs.c
new file mode 100644
index 0000000000..bb16b50370
--- /dev/null
+++ b/usr/src/lib/libproc/common/Plwpregs.c
@@ -0,0 +1,500 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "Pcontrol.h"
+#include "P32ton.h"
+
+/*
+ * This file implements the routines to read and write per-lwp register
+ * information from either a live process or core file opened with libproc.
+ * We build up a few common routines for reading and writing register
+ * information, and then the public functions are all trivial calls to these.
+ */
+
+/*
+ * Utility function to return a pointer to the structure of cached information
+ * about an lwp in the core file, given its lwpid.
+ */
+static lwp_info_t *
+getlwpcore(struct ps_prochandle *P, lwpid_t lwpid)
+{
+ lwp_info_t *lwp = list_next(&P->core->core_lwp_head);
+ uint_t i;
+
+ for (i = 0; i < P->core->core_nlwp; i++, lwp = list_next(lwp)) {
+ if (lwp->lwp_id == lwpid)
+ return (lwp);
+ }
+
+ errno = EINVAL;
+ return (NULL);
+}
+
+/*
+ * Utility function to open and read the contents of a per-lwp /proc file.
+ * This function is used to slurp in lwpstatus, xregs, and asrs.
+ */
+static int
+getlwpfile(struct ps_prochandle *P, lwpid_t lwpid,
+ const char *fbase, void *rp, size_t n)
+{
+ char fname[64];
+ int fd;
+
+ (void) snprintf(fname, sizeof (fname), "/proc/%d/lwp/%d/%s",
+ (int)P->status.pr_pid, (int)lwpid, fbase);
+
+ if ((fd = open(fname, O_RDONLY)) >= 0) {
+ if (read(fd, rp, n) > 0) {
+ (void) close(fd);
+ return (0);
+ }
+ (void) close(fd);
+ }
+ return (-1);
+}
+
+/*
+ * Get the lwpstatus_t for an lwp from either the live process or our
+ * cached information from the core file. This is used to get the
+ * general-purpose registers or floating point registers.
+ */
+int
+getlwpstatus(struct ps_prochandle *P, lwpid_t lwpid, lwpstatus_t *lps)
+{
+ lwp_info_t *lwp;
+
+ /*
+ * For both live processes and cores, our job is easy if the lwpid
+ * matches that of the representative lwp:
+ */
+ if (P->status.pr_lwp.pr_lwpid == lwpid) {
+ (void) memcpy(lps, &P->status.pr_lwp, sizeof (lwpstatus_t));
+ return (0);
+ }
+
+ /*
+ * If this is a live process, then just read the information out
+ * of the per-lwp status file:
+ */
+ if (P->state != PS_DEAD) {
+ return (getlwpfile(P, lwpid, "lwpstatus",
+ lps, sizeof (lwpstatus_t)));
+ }
+
+ /*
+ * 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) {
+ (void) memcpy(lps, &lwp->lwp_status, sizeof (lwpstatus_t));
+ return (0);
+ }
+
+ return (-1);
+}
+
+/*
+ * Utility function to modify lwp registers. This is done using either the
+ * process control file or per-lwp control file as necessary.
+ */
+static int
+setlwpregs(struct ps_prochandle *P, lwpid_t lwpid, long cmd,
+ const void *rp, size_t n)
+{
+ iovec_t iov[2];
+ char fname[64];
+ int fd;
+
+ if (P->state != PS_STOP) {
+ errno = EBUSY;
+ return (-1);
+ }
+
+ iov[0].iov_base = (caddr_t)&cmd;
+ iov[0].iov_len = sizeof (long);
+ iov[1].iov_base = (caddr_t)rp;
+ iov[1].iov_len = n;
+
+ /*
+ * Writing the process control file writes the representative lwp.
+ * Psync before we write to make sure we are consistent with the
+ * primary interfaces. Similarly, make sure to update P->status
+ * afterward if we are modifying one of its register sets.
+ */
+ if (P->status.pr_lwp.pr_lwpid == lwpid) {
+ Psync(P);
+
+ if (writev(P->ctlfd, iov, 2) == -1)
+ return (-1);
+
+ if (cmd == PCSREG)
+ (void) memcpy(P->status.pr_lwp.pr_reg, rp, n);
+ else if (cmd == PCSFPREG)
+ (void) memcpy(&P->status.pr_lwp.pr_fpreg, rp, n);
+
+ return (0);
+ }
+
+ /*
+ * If the lwp we want is not the representative lwp, we need to
+ * open the ctl file for that specific lwp.
+ */
+ (void) snprintf(fname, sizeof (fname), "/proc/%d/lwp/%d/lwpctl",
+ (int)P->status.pr_pid, (int)lwpid);
+
+ if ((fd = open(fname, O_WRONLY)) >= 0) {
+ if (writev(fd, iov, 2) > 0) {
+ (void) close(fd);
+ return (0);
+ }
+ (void) close(fd);
+ }
+ return (-1);
+}
+
+int
+Plwp_getregs(struct ps_prochandle *P, lwpid_t lwpid, prgregset_t gregs)
+{
+ lwpstatus_t lps;
+
+ if (getlwpstatus(P, lwpid, &lps) == -1)
+ return (-1);
+
+ (void) memcpy(gregs, lps.pr_reg, sizeof (prgregset_t));
+ return (0);
+}
+
+int
+Plwp_setregs(struct ps_prochandle *P, lwpid_t lwpid, const prgregset_t gregs)
+{
+ return (setlwpregs(P, lwpid, PCSREG, gregs, sizeof (prgregset_t)));
+}
+
+int
+Plwp_getfpregs(struct ps_prochandle *P, lwpid_t lwpid, prfpregset_t *fpregs)
+{
+ lwpstatus_t lps;
+
+ if (getlwpstatus(P, lwpid, &lps) == -1)
+ return (-1);
+
+ (void) memcpy(fpregs, &lps.pr_fpreg, sizeof (prfpregset_t));
+ return (0);
+}
+
+int Plwp_setfpregs(struct ps_prochandle *P, lwpid_t lwpid,
+ const prfpregset_t *fpregs)
+{
+ return (setlwpregs(P, lwpid, PCSFPREG, fpregs, sizeof (prfpregset_t)));
+}
+
+#if defined(sparc) || defined(__sparc)
+int
+Plwp_getxregs(struct ps_prochandle *P, lwpid_t lwpid, prxregset_t *xregs)
+{
+ lwp_info_t *lwp;
+
+ if (P->state == PS_IDLE) {
+ errno = ENODATA;
+ return (-1);
+ }
+
+ if (P->state != PS_DEAD) {
+ if (P->state != PS_STOP) {
+ errno = EBUSY;
+ return (-1);
+ }
+
+ return (getlwpfile(P, lwpid, "xregs",
+ xregs, sizeof (prxregset_t)));
+ }
+
+ if ((lwp = getlwpcore(P, lwpid)) != NULL && lwp->lwp_xregs != NULL) {
+ (void) memcpy(xregs, lwp->lwp_xregs, sizeof (prxregset_t));
+ return (0);
+ }
+
+ if (lwp != NULL)
+ errno = ENODATA;
+ return (-1);
+}
+
+int
+Plwp_setxregs(struct ps_prochandle *P, lwpid_t lwpid, const prxregset_t *xregs)
+{
+ return (setlwpregs(P, lwpid, PCSXREG, xregs, sizeof (prxregset_t)));
+}
+
+int
+Plwp_getgwindows(struct ps_prochandle *P, lwpid_t lwpid, gwindows_t *gwins)
+{
+ lwp_info_t *lwp;
+
+ if (P->state == PS_IDLE) {
+ errno = ENODATA;
+ return (-1);
+ }
+
+ if (P->state != PS_DEAD) {
+ if (P->state != PS_STOP) {
+ errno = EBUSY;
+ return (-1);
+ }
+
+ return (getlwpfile(P, lwpid, "gwindows",
+ gwins, sizeof (gwindows_t)));
+ }
+
+ if ((lwp = getlwpcore(P, lwpid)) != NULL && lwp->lwp_gwins != NULL) {
+ *gwins = *lwp->lwp_gwins;
+ return (0);
+ }
+
+ if (lwp != NULL)
+ errno = ENODATA;
+ return (-1);
+}
+
+#if defined(__sparcv9)
+int
+Plwp_getasrs(struct ps_prochandle *P, lwpid_t lwpid, asrset_t asrs)
+{
+ lwp_info_t *lwp;
+
+ if (P->state == PS_IDLE) {
+ errno = ENODATA;
+ return (-1);
+ }
+
+ if (P->state != PS_DEAD) {
+ if (P->state != PS_STOP) {
+ errno = EBUSY;
+ return (-1);
+ }
+
+ return (getlwpfile(P, lwpid, "asrs", asrs, sizeof (asrset_t)));
+ }
+
+ if ((lwp = getlwpcore(P, lwpid)) != NULL && lwp->lwp_asrs != NULL) {
+ (void) memcpy(asrs, lwp->lwp_asrs, sizeof (asrset_t));
+ return (0);
+ }
+
+ if (lwp != NULL)
+ errno = ENODATA;
+ return (-1);
+
+}
+
+int
+Plwp_setasrs(struct ps_prochandle *P, lwpid_t lwpid, const asrset_t asrs)
+{
+ return (setlwpregs(P, lwpid, PCSASRS, asrs, sizeof (asrset_t)));
+}
+#endif /* __sparcv9 */
+#endif /* __sparc */
+
+int
+Plwp_getpsinfo(struct ps_prochandle *P, lwpid_t lwpid, lwpsinfo_t *lps)
+{
+ lwp_info_t *lwp;
+
+ if (P->state == PS_IDLE) {
+ errno = ENODATA;
+ return (-1);
+ }
+
+ if (P->state != PS_DEAD) {
+ return (getlwpfile(P, lwpid, "lwpsinfo",
+ lps, sizeof (lwpsinfo_t)));
+ }
+
+ if ((lwp = getlwpcore(P, lwpid)) != NULL) {
+ (void) memcpy(lps, &lwp->lwp_psinfo, sizeof (lwpsinfo_t));
+ return (0);
+ }
+
+ return (-1);
+}
+
+int
+Plwp_stack(struct ps_prochandle *P, lwpid_t lwpid, stack_t *stkp)
+{
+ uintptr_t addr;
+
+ if (P->state == PS_IDLE) {
+ errno = ENODATA;
+ return (-1);
+ }
+
+ if (P->state != PS_DEAD) {
+ lwpstatus_t ls;
+ if (getlwpfile(P, lwpid, "lwpstatus", &ls, sizeof (ls)) != 0)
+ return (-1);
+ addr = ls.pr_ustack;
+ } else {
+ lwp_info_t *lwp;
+ if ((lwp = getlwpcore(P, lwpid)) == NULL)
+ return (-1);
+ addr = lwp->lwp_status.pr_ustack;
+ }
+
+
+ if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
+ if (Pread(P, stkp, sizeof (*stkp), addr) != sizeof (*stkp))
+ return (-1);
+#ifdef _LP64
+ } else {
+ stack32_t stk32;
+
+ if (Pread(P, &stk32, sizeof (stk32), addr) != sizeof (stk32))
+ return (-1);
+
+ stack_32_to_n(&stk32, stkp);
+#endif
+ }
+
+ return (0);
+}
+
+int
+Plwp_main_stack(struct ps_prochandle *P, lwpid_t lwpid, stack_t *stkp)
+{
+ uintptr_t addr;
+ lwpstatus_t ls;
+
+ if (P->state == PS_IDLE) {
+ errno = ENODATA;
+ return (-1);
+ }
+
+ if (P->state != PS_DEAD) {
+ if (getlwpfile(P, lwpid, "lwpstatus", &ls, sizeof (ls)) != 0)
+ return (-1);
+ } else {
+ lwp_info_t *lwp;
+ if ((lwp = getlwpcore(P, lwpid)) == NULL)
+ return (-1);
+ ls = lwp->lwp_status;
+ }
+
+ addr = ls.pr_ustack;
+
+ /*
+ * Read out the current stack; if the SS_ONSTACK flag is set then
+ * this LWP is operating on the alternate signal stack. We can
+ * recover the original stack from pr_oldcontext.
+ */
+ if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
+ if (Pread(P, stkp, sizeof (*stkp), addr) != sizeof (*stkp))
+ return (-1);
+
+ if (stkp->ss_flags & SS_ONSTACK)
+ goto on_altstack;
+#ifdef _LP64
+ } else {
+ stack32_t stk32;
+
+ if (Pread(P, &stk32, sizeof (stk32), addr) != sizeof (stk32))
+ return (-1);
+
+ if (stk32.ss_flags & SS_ONSTACK)
+ goto on_altstack;
+
+ stack_32_to_n(&stk32, stkp);
+#endif
+ }
+
+ return (0);
+
+on_altstack:
+
+ if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
+ ucontext_t *ctxp = (void *)ls.pr_oldcontext;
+
+ if (Pread(P, stkp, sizeof (*stkp),
+ (uintptr_t)&ctxp->uc_stack) != sizeof (*stkp))
+ return (-1);
+#ifdef _LP64
+ } else {
+ ucontext32_t *ctxp = (void *)ls.pr_oldcontext;
+ stack32_t stk32;
+
+ if (Pread(P, &stk32, sizeof (stk32),
+ (uintptr_t)&ctxp->uc_stack) != sizeof (stk32))
+ return (-1);
+
+ stack_32_to_n(&stk32, stkp);
+#endif
+ }
+
+ return (0);
+}
+
+int
+Plwp_alt_stack(struct ps_prochandle *P, lwpid_t lwpid, stack_t *stkp)
+{
+ if (P->state == PS_IDLE) {
+ errno = ENODATA;
+ return (-1);
+ }
+
+ if (P->state != PS_DEAD) {
+ lwpstatus_t ls;
+
+ if (getlwpfile(P, lwpid, "lwpstatus", &ls, sizeof (ls)) != 0)
+ return (-1);
+
+ if (ls.pr_altstack.ss_flags & SS_DISABLE) {
+ errno = ENODATA;
+ return (-1);
+ }
+
+ *stkp = ls.pr_altstack;
+ } else {
+ lwp_info_t *lwp;
+
+ if ((lwp = getlwpcore(P, lwpid)) == NULL)
+ return (-1);
+
+ if (lwp->lwp_status.pr_altstack.ss_flags & SS_DISABLE) {
+ errno = ENODATA;
+ return (-1);
+ }
+
+ *stkp = lwp->lwp_status.pr_altstack;
+ }
+
+ return (0);
+}
diff --git a/usr/src/lib/libproc/common/Pscantext.c b/usr/src/lib/libproc/common/Pscantext.c
new file mode 100644
index 0000000000..d4cb853254
--- /dev/null
+++ b/usr/src/lib/libproc/common/Pscantext.c
@@ -0,0 +1,183 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include "libproc.h"
+#include "Pcontrol.h"
+#include "Pisadep.h"
+#include "Putil.h"
+
+#define BLKSIZE (8 * 1024)
+
+/*
+ * Look for a SYSCALL instruction in the process's address space.
+ */
+int
+Pscantext(struct ps_prochandle *P)
+{
+ char mapfile[100];
+ int mapfd;
+ off_t offset; /* offset in text section */
+ off_t endoff; /* ending offset in text section */
+ uintptr_t sysaddr; /* address of SYSCALL instruction */
+ int syspri; /* priority of SYSCALL instruction */
+ int nbytes; /* number of bytes in buffer */
+ int n2bytes; /* number of bytes in second buffer */
+ int nmappings; /* current number of mappings */
+ prmap_t *pdp; /* pointer to map descriptor */
+ prmap_t *prbuf; /* buffer for map descriptors */
+ unsigned nmap; /* number of map descriptors */
+ uint32_t buf[2 * BLKSIZE / sizeof (uint32_t)]; /* text buffer */
+ uchar_t *p;
+
+ /* try the most recently-seen syscall address */
+ syspri = 0;
+ sysaddr = 0;
+ if (P->sysaddr != 0 &&
+ (syspri = Pissyscall(P, P->sysaddr)))
+ sysaddr = P->sysaddr;
+
+ /* try the previous instruction */
+ if (sysaddr == 0 || syspri != 1)
+ syspri = Pissyscall_prev(P, P->status.pr_lwp.pr_reg[R_PC],
+ &sysaddr);
+
+ if (sysaddr != 0 && syspri == 1) {
+ P->sysaddr = sysaddr;
+ return (0);
+ }
+
+ /* open the /proc/<pid>/map file */
+ (void) sprintf(mapfile, "/proc/%d/map", (int)P->pid);
+ if ((mapfd = open(mapfile, O_RDONLY)) < 0) {
+ dprintf("failed to open %s: %s\n", mapfile, strerror(errno));
+ return (-1);
+ }
+
+ /* allocate a plausible initial buffer size */
+ nmap = 50;
+
+ /* read all the map structures, allocating more space as needed */
+ for (;;) {
+ prbuf = malloc(nmap * sizeof (prmap_t));
+ if (prbuf == NULL) {
+ dprintf("Pscantext: failed to allocate buffer\n");
+ (void) close(mapfd);
+ return (-1);
+ }
+ nmappings = pread(mapfd, prbuf, nmap * sizeof (prmap_t), 0L);
+ if (nmappings < 0) {
+ dprintf("Pscantext: failed to read map file: %s\n",
+ strerror(errno));
+ free(prbuf);
+ (void) close(mapfd);
+ return (-1);
+ }
+ nmappings /= sizeof (prmap_t);
+ if (nmappings < nmap) /* we read them all */
+ break;
+ /* allocate a bigger buffer */
+ free(prbuf);
+ nmap *= 2;
+ }
+ (void) close(mapfd);
+
+ /*
+ * Scan each executable mapping looking for a syscall instruction.
+ * In dynamically linked executables, syscall instructions are
+ * typically only found in shared libraries. Because shared libraries
+ * are most often mapped at the top of the address space, we minimize
+ * our expected search time by starting at the last mapping and working
+ * our way down to the first mapping.
+ */
+ for (pdp = &prbuf[nmappings - 1]; sysaddr == 0 && syspri != 1 &&
+ pdp >= prbuf; pdp--) {
+
+ offset = (off_t)pdp->pr_vaddr; /* beginning of text */
+ endoff = offset + pdp->pr_size;
+
+ /* avoid non-EXEC mappings; avoid the stack and heap */
+ if ((pdp->pr_mflags&MA_EXEC) == 0 ||
+ (endoff > P->status.pr_stkbase &&
+ offset < P->status.pr_stkbase + P->status.pr_stksize) ||
+ (endoff > P->status.pr_brkbase &&
+ offset < P->status.pr_brkbase + P->status.pr_brksize))
+ continue;
+
+ (void) lseek(P->asfd, (off_t)offset, 0);
+
+ if ((nbytes = read(P->asfd, buf, 2*BLKSIZE)) <= 0)
+ continue;
+
+ if (nbytes < BLKSIZE)
+ n2bytes = 0;
+ else {
+ n2bytes = nbytes - BLKSIZE;
+ nbytes = BLKSIZE;
+ }
+
+ p = (uchar_t *)buf;
+
+ /* search text for a SYSCALL instruction */
+ while (sysaddr == 0 && syspri != 1 && offset < endoff) {
+ if (nbytes <= 0) { /* shift buffers */
+ if ((nbytes = n2bytes) <= 0)
+ break;
+ (void) memcpy(buf,
+ &buf[BLKSIZE / sizeof (buf[0])],
+ nbytes);
+ n2bytes = 0;
+ p = (uchar_t *)buf;
+ if (nbytes == BLKSIZE &&
+ offset + BLKSIZE < endoff)
+ n2bytes = read(P->asfd,
+ &buf[BLKSIZE / sizeof (buf[0])],
+ BLKSIZE);
+ }
+
+ if (syspri = Pissyscall_text(P, p, nbytes))
+ sysaddr = offset;
+
+ p += sizeof (instr_t);
+ offset += sizeof (instr_t);
+ nbytes -= sizeof (instr_t);
+ }
+ }
+
+ if ((P->sysaddr = sysaddr) != 0)
+ return (0);
+ else
+ return (-1);
+}
diff --git a/usr/src/lib/libproc/common/Pservice.c b/usr/src/lib/libproc/common/Pservice.c
new file mode 100644
index 0000000000..6850696af4
--- /dev/null
+++ b/usr/src/lib/libproc/common/Pservice.c
@@ -0,0 +1,372 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdarg.h>
+#include <string.h>
+#include "Pcontrol.h"
+
+/*
+ * This file implements the process services declared in <proc_service.h>.
+ * This enables libproc to be used in conjunction with libc_db and
+ * librtld_db. As most of these facilities are already provided by
+ * (more elegant) interfaces in <libproc.h>, we can just call those.
+ *
+ * NOTE: We explicitly do *not* implement the functions ps_kill() and
+ * ps_lrolltoaddr() in this library. The very existence of these functions
+ * causes libc_db to create an "agent thread" in the target process.
+ * The only way to turn off this behavior is to omit these functions.
+ */
+
+#pragma weak ps_pdread = ps_pread
+#pragma weak ps_ptread = ps_pread
+#pragma weak ps_pdwrite = ps_pwrite
+#pragma weak ps_ptwrite = ps_pwrite
+
+ps_err_e
+ps_pdmodel(struct ps_prochandle *P, int *modelp)
+{
+ *modelp = P->status.pr_dmodel;
+ return (PS_OK);
+}
+
+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)
+ return (PS_BADADDR);
+ return (PS_OK);
+}
+
+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)
+ return (PS_BADADDR);
+ return (PS_OK);
+}
+
+/*
+ * libc_db calls matched pairs of ps_pstop()/ps_pcontinue()
+ * in the belief that the client may have left the process
+ * running while calling in to the libc_db interfaces.
+ *
+ * We interpret the meaning of these functions to be an inquiry
+ * as to whether the process is stopped, not an action to be
+ * performed to make it stopped. For similar reasons, we also
+ * return PS_OK for core files in order to allow libc_db to
+ * operate on these as well.
+ */
+ps_err_e
+ps_pstop(struct ps_prochandle *P)
+{
+ if (P->state != PS_STOP && P->state != PS_DEAD)
+ return (PS_ERR);
+ return (PS_OK);
+}
+
+ps_err_e
+ps_pcontinue(struct ps_prochandle *P)
+{
+ if (P->state != PS_STOP && P->state != PS_DEAD)
+ return (PS_ERR);
+ return (PS_OK);
+}
+
+/*
+ * ps_lstop() and ps_lcontinue() are not called by any code in libc_db
+ * or librtld_db. We make them behave like ps_pstop() and ps_pcontinue().
+ */
+/* ARGSUSED1 */
+ps_err_e
+ps_lstop(struct ps_prochandle *P, lwpid_t lwpid)
+{
+ if (P->state != PS_STOP && P->state != PS_DEAD)
+ return (PS_ERR);
+ return (PS_OK);
+}
+
+/* ARGSUSED1 */
+ps_err_e
+ps_lcontinue(struct ps_prochandle *P, lwpid_t lwpid)
+{
+ if (P->state != PS_STOP && P->state != PS_DEAD)
+ return (PS_ERR);
+ return (PS_OK);
+}
+
+ps_err_e
+ps_lgetregs(struct ps_prochandle *P, lwpid_t lwpid, prgregset_t regs)
+{
+ if (P->state != PS_STOP && P->state != PS_DEAD)
+ return (PS_ERR);
+
+ if (Plwp_getregs(P, lwpid, regs) == 0)
+ return (PS_OK);
+
+ return (PS_BADLID);
+}
+
+ps_err_e
+ps_lsetregs(struct ps_prochandle *P, lwpid_t lwpid, const prgregset_t regs)
+{
+ if (P->state != PS_STOP)
+ return (PS_ERR);
+
+ if (Plwp_setregs(P, lwpid, regs) == 0)
+ return (PS_OK);
+
+ return (PS_BADLID);
+}
+
+ps_err_e
+ps_lgetfpregs(struct ps_prochandle *P, lwpid_t lwpid, prfpregset_t *regs)
+{
+ if (P->state != PS_STOP && P->state != PS_DEAD)
+ return (PS_ERR);
+
+ if (Plwp_getfpregs(P, lwpid, regs) == 0)
+ return (PS_OK);
+
+ return (PS_BADLID);
+}
+
+ps_err_e
+ps_lsetfpregs(struct ps_prochandle *P, lwpid_t lwpid, const prfpregset_t *regs)
+{
+ if (P->state != PS_STOP)
+ return (PS_ERR);
+
+ if (Plwp_setfpregs(P, lwpid, regs) == 0)
+ return (PS_OK);
+
+ return (PS_BADLID);
+}
+
+#if defined(sparc) || defined(__sparc)
+
+ps_err_e
+ps_lgetxregsize(struct ps_prochandle *P, lwpid_t lwpid, int *xrsize)
+{
+ char fname[64];
+ struct stat statb;
+
+ if (P->state == PS_DEAD) {
+ lwp_info_t *lwp = list_next(&P->core->core_lwp_head);
+ uint_t i;
+
+ for (i = 0; i < P->core->core_nlwp; i++, lwp = list_next(lwp)) {
+ if (lwp->lwp_id == lwpid) {
+ if (lwp->lwp_xregs != NULL)
+ *xrsize = sizeof (prxregset_t);
+ else
+ *xrsize = 0;
+ return (PS_OK);
+ }
+ }
+
+ return (PS_BADLID);
+ }
+
+ (void) snprintf(fname, sizeof (fname), "/proc/%d/lwp/%d/xregs",
+ (int)P->status.pr_pid, (int)lwpid);
+
+ if (stat(fname, &statb) != 0)
+ return (PS_BADLID);
+
+ *xrsize = (int)statb.st_size;
+ return (PS_OK);
+}
+
+ps_err_e
+ps_lgetxregs(struct ps_prochandle *P, lwpid_t lwpid, caddr_t xregs)
+{
+ if (P->state != PS_STOP && P->state != PS_DEAD)
+ return (PS_ERR);
+
+ /* LINTED - alignment */
+ if (Plwp_getxregs(P, lwpid, (prxregset_t *)xregs) == 0)
+ return (PS_OK);
+
+ return (PS_BADLID);
+}
+
+ps_err_e
+ps_lsetxregs(struct ps_prochandle *P, lwpid_t lwpid, caddr_t xregs)
+{
+ if (P->state != PS_STOP)
+ return (PS_ERR);
+
+ /* LINTED - alignment */
+ if (Plwp_setxregs(P, lwpid, (prxregset_t *)xregs) == 0)
+ return (PS_OK);
+
+ return (PS_BADLID);
+}
+
+#endif /* sparc */
+
+#if defined(__i386) || defined(__amd64)
+
+ps_err_e
+ps_lgetLDT(struct ps_prochandle *P, lwpid_t lwpid, struct ssd *ldt)
+{
+#if defined(__amd64) && defined(_LP64)
+ if (P->status.pr_dmodel != PR_MODEL_NATIVE) {
+#endif
+ prgregset_t regs;
+ struct ssd *ldtarray;
+ ps_err_e error;
+ uint_t gs;
+ int nldt;
+ int i;
+
+ if (P->state != PS_STOP && P->state != PS_DEAD)
+ return (PS_ERR);
+
+ /*
+ * We need to get the ldt entry that matches the
+ * value in the lwp's GS register.
+ */
+ if ((error = ps_lgetregs(P, lwpid, regs)) != PS_OK)
+ return (error);
+
+ gs = regs[GS];
+
+ if ((nldt = Pldt(P, NULL, 0)) <= 0 ||
+ (ldtarray = malloc(nldt * sizeof (struct ssd))) == NULL)
+ return (PS_ERR);
+ if ((nldt = Pldt(P, ldtarray, nldt)) <= 0) {
+ free(ldtarray);
+ return (PS_ERR);
+ }
+
+ for (i = 0; i < nldt; i++) {
+ if (gs == ldtarray[i].sel) {
+ *ldt = ldtarray[i];
+ break;
+ }
+ }
+ free(ldtarray);
+
+ if (i < nldt)
+ return (PS_OK);
+#if defined(__amd64) && defined(_LP64)
+ }
+#endif
+
+ return (PS_ERR);
+}
+
+#endif /* __i386 || __amd64 */
+
+/*
+ * Libthread_db doesn't use this function currently, but librtld_db uses
+ * it for its debugging output. We turn this on via rd_log if our debugging
+ * switch is on, and then echo the messages sent to ps_plog to stderr.
+ */
+void
+ps_plog(const char *fmt, ...)
+{
+ va_list ap;
+
+ if (_libproc_debug && fmt != NULL && *fmt != '\0') {
+ va_start(ap, fmt);
+ (void) vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ if (fmt[strlen(fmt) - 1] != '\n')
+ (void) fputc('\n', stderr);
+ }
+}
+
+/*
+ * Store a pointer to our internal copy of the aux vector at the address
+ * specified by the caller. It should not hold on to this data for too long.
+ */
+ps_err_e
+ps_pauxv(struct ps_prochandle *P, const auxv_t **aux)
+{
+ if (P->auxv == NULL)
+ Preadauxvec(P);
+
+ if (P->auxv == NULL)
+ return (PS_ERR);
+
+ *aux = (const auxv_t *)P->auxv;
+ return (PS_OK);
+}
+
+/*
+ * Search for a symbol by name and return the corresponding address.
+ */
+ps_err_e
+ps_pglobal_lookup(struct ps_prochandle *P, const char *object_name,
+ const char *sym_name, psaddr_t *sym_addr)
+{
+ GElf_Sym sym;
+
+ if (Plookup_by_name(P, object_name, sym_name, &sym) == 0) {
+ dprintf("pglobal_lookup <%s> -> %p\n",
+ sym_name, (void *)(uintptr_t)sym.st_value);
+ *sym_addr = (psaddr_t)sym.st_value;
+ return (PS_OK);
+ }
+
+ return (PS_NOSYM);
+}
+
+/*
+ * Search for a symbol by name and return the corresponding symbol
+ * information. If we're compiled _LP64, we just call Plookup_by_name
+ * and return because ps_sym_t is defined to be an Elf64_Sym, which
+ * is the same as a GElf_Sym. In the _ILP32 case, we have to convert
+ * Plookup_by_name's result back to a ps_sym_t (which is an Elf32_Sym).
+ */
+ps_err_e
+ps_pglobal_sym(struct ps_prochandle *P, const char *object_name,
+ const char *sym_name, ps_sym_t *symp)
+{
+#if defined(_ILP32)
+ GElf_Sym sym;
+
+ if (Plookup_by_name(P, object_name, sym_name, &sym) == 0) {
+ symp->st_name = (Elf32_Word)sym.st_name;
+ symp->st_value = (Elf32_Addr)sym.st_value;
+ symp->st_size = (Elf32_Word)sym.st_size;
+ symp->st_info = ELF32_ST_INFO(
+ GELF_ST_BIND(sym.st_info), GELF_ST_TYPE(sym.st_info));
+ symp->st_other = sym.st_other;
+ symp->st_shndx = sym.st_shndx;
+ return (PS_OK);
+ }
+
+#elif defined(_LP64)
+ if (Plookup_by_name(P, object_name, sym_name, symp) == 0)
+ return (PS_OK);
+#endif
+ return (PS_NOSYM);
+}
diff --git a/usr/src/lib/libproc/common/Pstack.c b/usr/src/lib/libproc/common/Pstack.c
new file mode 100644
index 0000000000..f0f8b5ce8d
--- /dev/null
+++ b/usr/src/lib/libproc/common/Pstack.c
@@ -0,0 +1,288 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Pstack.c
+ *
+ * Common helper functions for stack walking. The ISA-specific code is found in
+ * Pstack_iter() in Pisadep.c.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include "libproc.h"
+#include "Pcontrol.h"
+#include "P32ton.h"
+#include "Pstack.h"
+
+/*
+ * Utility function to prevent stack loops from running on forever by
+ * detecting when there is a stack loop (the %fp has been seen before).
+ */
+int
+stack_loop(prgreg_t fp, prgreg_t **prevfpp, int *nfpp, uint_t *pfpsizep)
+{
+ prgreg_t *prevfp = *prevfpp;
+ uint_t pfpsize = *pfpsizep;
+ int nfp = *nfpp;
+ int i;
+
+ for (i = 0; i < nfp; i++) {
+ if (fp == prevfp[i])
+ return (1); /* stack loop detected */
+ }
+
+ if (nfp == pfpsize) {
+ pfpsize = pfpsize ? pfpsize * 2 : 16;
+ prevfp = realloc(prevfp, pfpsize * sizeof (prgreg_t));
+ /*
+ * Just assume there is no loop in the face of allocation
+ * failure; the caller still has the original prevfp pointer.
+ */
+ if (prevfp == NULL)
+ return (0);
+ }
+
+ prevfp[nfp++] = fp;
+ *prevfpp = prevfp;
+ *pfpsizep = pfpsize;
+ *nfpp = nfp;
+
+ return (0);
+}
+
+/*
+ * Signal Frame Detection
+ *
+ * In order to facilitate detection and processing of signal handler frames
+ * during a stack backtrace, we define a set of utility routines to operate on
+ * a uclist (ucontext address list), and then use these routines in the various
+ * implementations of Pstack_iter below. Certain source-level debuggers and
+ * virtual machines that shall remain nameless believe that in order to detect
+ * signal handler frames, one must hard-code checks for symbol names defined
+ * in libc and libthread and knowledge of their implementation. We make no
+ * such assumptions, allowing us to operate on programs that manipulate their
+ * underlying kernel signal handlers (i.e. use __sigaction) and to not require
+ * changes in the face of future library modifications.
+ *
+ * A signal handler frame is essentially a set of data pushed on to the user
+ * stack by the kernel prior to returning to the user program in one of the
+ * pre-defined signal handlers. The signal handler itself receives the signal
+ * number, an optional pointer to a siginfo_t, and a pointer to the interrupted
+ * ucontext as arguments. When performing a stack backtrace, we would like to
+ * detect these frames so that we can correctly return the interrupted program
+ * counter and frame pointer as a separate frame. When a signal handler frame
+ * is constructed on the stack by the kernel, the signalled LWP has its
+ * lwp_oldcontext member (exported through /proc as lwpstatus.pr_oldcontext)
+ * set to the user address at which the ucontext_t was placed on the LWP's
+ * stack. The ucontext_t's uc_link member is set to the previous value of
+ * lwp_oldcontext. Thus when signal handlers are active, pr_oldcontext will
+ * point to the first element of a linked list of ucontext_t addresses.
+ *
+ * The stack layout for a signal handler frame is as follows:
+ *
+ * SPARC v7/v9: Intel ia32:
+ * +--------------+ - high +--------------+ -
+ * | struct fq | ^ addrs | siginfo_t | optional
+ * +--------------+ | ^ +--------------+ -
+ * | gwindows_t | | | ucontext_t | ^
+ * +--------------+ optional +--------------+ |
+ * | siginfo_t | | ucontext_t * | |
+ * +--------------+ | | +--------------+
+ * | xregs data | v v | siginfo_t * | mandatory
+ * +--------------+ - low +--------------+
+ * | ucontext_t | ^ addrs | int (signo) | |
+ * +--------------+ mandatory +--------------+ |
+ * | struct frame | v | struct frame | v
+ * +--------------+ - <- %sp on resume +--------------+ - <- %esp on resume
+ *
+ * amd64 (64-bit):
+ * +--------------+ -
+ * | siginfo_t | optional
+ * +--------------+ -
+ * | ucontext_t | ^
+ * +--------------+ |
+ * | siginfo_t * |
+ * +--------------+ mandatory
+ * | int (signo) |
+ * +--------------+ |
+ * | struct frame | v
+ * +--------------+ - <- %rsp on resume
+ *
+ * The bottom-most struct frame is actually constructed by the kernel by
+ * copying the previous stack frame, allowing naive backtrace code to simply
+ * skip over the interrupted frame. The copied frame is never really used,
+ * since it is presumed the libc or libthread signal handler wrapper function
+ * will explicitly setcontext(2) to the interrupted context if the user
+ * program's handler returns. If we detect a signal handler frame, we simply
+ * read the interrupted context structure from the stack, use its embedded
+ * gregs to construct the register set for the interrupted frame, and then
+ * continue our backtrace. Detecting the frame itself is easy according to
+ * the diagram ("oldcontext" represents any element in the uc_link chain):
+ *
+ * On SPARC v7 or v9:
+ * %fp + sizeof (struct frame) == oldcontext
+ *
+ * On Intel ia32:
+ * %ebp + sizeof (struct frame) + (3 * regsize) == oldcontext
+ *
+ * On amd64:
+ * %rbp + sizeof (struct frame) + (2 * regsize) == oldcontext
+ *
+ * A final complication is that we want libproc to support backtraces from
+ * arbitrary addresses without the caller passing in an LWP id. To do this,
+ * we must first determine all the known oldcontexts by iterating over all
+ * LWPs and following their pr_oldcontext pointers. We optimize our search
+ * by discarding NULL pointers and pointers whose value is less than that
+ * of the initial stack pointer (since stacks grow down from high memory),
+ * and then sort the resulting list by virtual address so we can binary search.
+ */
+
+int
+load_uclist(uclist_t *ucl, const lwpstatus_t *psp)
+{
+ struct ps_prochandle *P = ucl->uc_proc;
+ uintptr_t addr = psp->pr_oldcontext;
+
+ uintptr_t *new_addrs;
+ uint_t new_size, i;
+ ucontext_t uc;
+
+ if (addr == NULL)
+ return (0);
+
+ for (;;) {
+ if (ucl->uc_nelems == ucl->uc_size) {
+ new_size = ucl->uc_size ? ucl->uc_size * 2 : 16;
+ new_addrs = realloc(ucl->uc_addrs,
+ new_size * sizeof (uintptr_t));
+
+ if (new_addrs != NULL) {
+ ucl->uc_addrs = new_addrs;
+ ucl->uc_size = new_size;
+ } else
+ break; /* abort if allocation failure */
+ }
+#ifdef _LP64
+ if (P->status.pr_dmodel == PR_MODEL_ILP32) {
+ ucontext32_t u32;
+
+ if (Pread(P, &u32, sizeof (u32), addr) != sizeof (u32))
+ break; /* abort if we fail to read ucontext */
+ uc.uc_link = (ucontext_t *)(uintptr_t)u32.uc_link;
+ } else
+#endif
+ if (Pread(P, &uc, sizeof (uc), addr) != sizeof (uc))
+ break; /* abort if we fail to read ucontext */
+
+ dprintf("detected lwp %d signal context at %p\n",
+ (int)psp->pr_lwpid, (void *)addr);
+ ucl->uc_addrs[ucl->uc_nelems++] = addr;
+
+ addr = (uintptr_t)uc.uc_link;
+
+ /*
+ * Abort if we find a NULL uc_link pointer or a duplicate
+ * entry which could indicate a cycle or a very peculiar
+ * interference pattern between threads.
+ */
+ if (addr == NULL)
+ break;
+
+ for (i = 0; i < ucl->uc_nelems - 1; i++) {
+ if (ucl->uc_addrs[i] == addr)
+ return (0);
+ }
+ }
+
+ return (0);
+}
+
+int
+sort_uclist(const void *lhp, const void *rhp)
+{
+ uintptr_t lhs = *((const uintptr_t *)lhp);
+ uintptr_t rhs = *((const uintptr_t *)rhp);
+
+ if (lhs < rhs)
+ return (-1);
+ if (lhs > rhs)
+ return (+1);
+ return (0);
+}
+
+void
+init_uclist(uclist_t *ucl, struct ps_prochandle *P)
+{
+ if ((P->state == PS_STOP || P->state == PS_DEAD) &&
+ P->ucaddrs != NULL) {
+ ucl->uc_proc = P;
+ ucl->uc_addrs = P->ucaddrs;
+ ucl->uc_nelems = P->ucnelems;
+ ucl->uc_size = P->ucnelems;
+ ucl->uc_cached = 1;
+ return;
+ }
+
+ ucl->uc_proc = P;
+ ucl->uc_addrs = NULL;
+ ucl->uc_nelems = 0;
+ ucl->uc_size = 0;
+
+ (void) Plwp_iter(P, (proc_lwp_f *)load_uclist, ucl);
+ qsort(ucl->uc_addrs, ucl->uc_nelems, sizeof (uintptr_t), sort_uclist);
+
+ if (P->state == PS_STOP || P->state == PS_DEAD) {
+ P->ucaddrs = ucl->uc_addrs;
+ P->ucnelems = ucl->uc_nelems;
+ ucl->uc_cached = 1;
+ } else {
+ ucl->uc_cached = 0;
+ }
+}
+
+void
+free_uclist(uclist_t *ucl)
+{
+ if (!ucl->uc_cached && ucl->uc_addrs != NULL)
+ free(ucl->uc_addrs);
+}
+
+int
+find_uclink(uclist_t *ucl, uintptr_t addr)
+{
+ if (ucl->uc_nelems != 0) {
+ return (bsearch(&addr, ucl->uc_addrs, ucl->uc_nelems,
+ sizeof (uintptr_t), sort_uclist) != NULL);
+ }
+
+ return (0);
+}
diff --git a/usr/src/lib/libproc/common/Pstack.h b/usr/src/lib/libproc/common/Pstack.h
new file mode 100644
index 0000000000..31bdac9c62
--- /dev/null
+++ b/usr/src/lib/libproc/common/Pstack.h
@@ -0,0 +1,61 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _PSTACK_H
+#define _PSTACK_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Support functions for ISA-dependent Pstack_iter().
+ */
+int stack_loop(prgreg_t fp, prgreg_t **prevfpp, int *nfpp, uint_t *pfpsizep);
+
+typedef struct {
+ struct ps_prochandle *uc_proc; /* libproc handle */
+ uintptr_t *uc_addrs; /* array of stack addresses */
+ uint_t uc_nelems; /* number of valid elements */
+ uint_t uc_size; /* actual size of array */
+ uint_t uc_cached; /* is cached in the ps_prochandle */
+} uclist_t;
+
+int load_uclist(uclist_t *ucl, const lwpstatus_t *psp);
+int sort_uclist(const void *lhp, const void *rhp);
+void init_uclist(uclist_t *ucl, struct ps_prochandle *P);
+void free_uclist(uclist_t *ucl);
+int find_uclink(uclist_t *ucl, uintptr_t addr);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PSTACK_H */
diff --git a/usr/src/lib/libproc/common/Psymtab.c b/usr/src/lib/libproc/common/Psymtab.c
new file mode 100644
index 0000000000..05dd4d570c
--- /dev/null
+++ b/usr/src/lib/libproc/common/Psymtab.c
@@ -0,0 +1,3434 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <string.h>
+#include <strings.h>
+#include <memory.h>
+#include <errno.h>
+#include <dirent.h>
+#include <signal.h>
+#include <limits.h>
+#include <libgen.h>
+#include <zone.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/systeminfo.h>
+#include <sys/sysmacros.h>
+
+#include "libproc.h"
+#include "Pcontrol.h"
+#include "Putil.h"
+
+static file_info_t *build_map_symtab(struct ps_prochandle *, map_info_t *);
+static map_info_t *exec_map(struct ps_prochandle *);
+static map_info_t *object_to_map(struct ps_prochandle *, Lmid_t, const char *);
+static map_info_t *object_name_to_map(struct ps_prochandle *,
+ Lmid_t, const char *);
+static GElf_Sym *sym_by_name(sym_tbl_t *, const char *, GElf_Sym *, uint_t *);
+static int read_ehdr32(struct ps_prochandle *, Elf32_Ehdr *, uintptr_t);
+#ifdef _LP64
+static int read_ehdr64(struct ps_prochandle *, Elf64_Ehdr *, uintptr_t);
+#endif
+
+#define DATA_TYPES \
+ ((1 << STT_OBJECT) | (1 << STT_FUNC) | \
+ (1 << STT_COMMON) | (1 << STT_TLS))
+#define IS_DATA_TYPE(tp) (((1 << (tp)) & DATA_TYPES) != 0)
+
+#define MA_RWX (MA_READ | MA_WRITE | MA_EXEC)
+
+typedef enum {
+ PRO_NATURAL,
+ PRO_BYADDR,
+ PRO_BYNAME
+} pr_order_t;
+
+static int
+addr_cmp(const void *aa, const void *bb)
+{
+ uintptr_t a = *((uintptr_t *)aa);
+ uintptr_t b = *((uintptr_t *)bb);
+
+ if (a > b)
+ return (1);
+ if (a < b)
+ return (-1);
+ return (0);
+}
+
+/*
+ * Allocation function for a new file_info_t
+ */
+static file_info_t *
+file_info_new(struct ps_prochandle *P, map_info_t *mptr)
+{
+ file_info_t *fptr;
+ map_info_t *mp;
+ uintptr_t a, addr, *addrs, last = 0;
+ uint_t i, j, naddrs = 0, unordered = 0;
+
+ if ((fptr = calloc(1, sizeof (file_info_t))) == NULL)
+ return (NULL);
+
+ list_link(fptr, &P->file_head);
+ (void) strcpy(fptr->file_pname, mptr->map_pmap.pr_mapname);
+ mptr->map_file = fptr;
+ fptr->file_ref = 1;
+ fptr->file_fd = -1;
+ P->num_files++;
+
+ /*
+ * To figure out which map_info_t instances correspond to the mappings
+ * for this load object, we look at the in-memory ELF image in the
+ * base mapping (usually the program text). We examine the program
+ * headers to find the addresses at the beginning and end of each
+ * section and store them in a list which we then sort. Finally, we
+ * walk down the list of addresses and the list of map_info_t
+ * instances in lock step to correctly find the mappings that
+ * correspond to this load object.
+ */
+ if (P->status.pr_dmodel == PR_MODEL_ILP32) {
+ Elf32_Ehdr ehdr;
+ Elf32_Phdr phdr;
+
+ if (read_ehdr32(P, &ehdr, mptr->map_pmap.pr_vaddr) != 0)
+ return (fptr);
+
+ addrs = malloc(sizeof (uintptr_t) * ehdr.e_phnum * 2);
+ a = mptr->map_pmap.pr_vaddr + ehdr.e_phoff;
+ for (i = 0; i < ehdr.e_phnum; i++, a += ehdr.e_phentsize) {
+ if (Pread(P, &phdr, sizeof (phdr), a) != sizeof (phdr))
+ goto out;
+ if (phdr.p_type != PT_LOAD || phdr.p_memsz == 0)
+ continue;
+
+ addr = phdr.p_vaddr;
+ if (ehdr.e_type == ET_DYN)
+ addr += mptr->map_pmap.pr_vaddr;
+ if (last > addr)
+ unordered = 1;
+ addrs[naddrs++] = addr;
+ addrs[naddrs++] = last = addr + phdr.p_memsz - 1;
+ }
+#ifdef _LP64
+ } else {
+ Elf64_Ehdr ehdr;
+ Elf64_Phdr phdr;
+
+ if (read_ehdr64(P, &ehdr, mptr->map_pmap.pr_vaddr) != 0)
+ return (fptr);
+
+ addrs = malloc(sizeof (uintptr_t) * ehdr.e_phnum * 2);
+ a = mptr->map_pmap.pr_vaddr + ehdr.e_phoff;
+ for (i = 0; i < ehdr.e_phnum; i++, a += ehdr.e_phentsize) {
+ if (Pread(P, &phdr, sizeof (phdr), a) != sizeof (phdr))
+ goto out;
+ if (phdr.p_type != PT_LOAD || phdr.p_memsz == 0)
+ continue;
+
+ addr = phdr.p_vaddr;
+ if (ehdr.e_type == ET_DYN)
+ addr += mptr->map_pmap.pr_vaddr;
+ if (last > addr)
+ unordered = 1;
+ addrs[naddrs++] = addr;
+ addrs[naddrs++] = last = addr + phdr.p_memsz - 1;
+ }
+#endif
+ }
+
+ if (unordered)
+ qsort(addrs, naddrs, sizeof (uintptr_t), addr_cmp);
+
+
+ i = j = 0;
+ mp = P->mappings;
+ while (j < P->map_count && i < naddrs) {
+ addr = addrs[i];
+ if (addr >= mp->map_pmap.pr_vaddr &&
+ addr < mp->map_pmap.pr_vaddr + mp->map_pmap.pr_size &&
+ mp->map_file == NULL) {
+ mp->map_file = fptr;
+ fptr->file_ref++;
+ }
+
+ if (addr < mp->map_pmap.pr_vaddr + mp->map_pmap.pr_size) {
+ i++;
+ } else {
+ mp++;
+ j++;
+ }
+ }
+
+out:
+ free(addrs);
+ return (fptr);
+}
+
+/*
+ * Deallocation function for a file_info_t
+ */
+static void
+file_info_free(struct ps_prochandle *P, file_info_t *fptr)
+{
+ if (--fptr->file_ref == 0) {
+ list_unlink(fptr);
+ if (fptr->file_symtab.sym_elf) {
+ (void) elf_end(fptr->file_symtab.sym_elf);
+ free(fptr->file_symtab.sym_elfmem);
+ }
+ if (fptr->file_symtab.sym_byname)
+ free(fptr->file_symtab.sym_byname);
+ if (fptr->file_symtab.sym_byaddr)
+ free(fptr->file_symtab.sym_byaddr);
+
+ if (fptr->file_dynsym.sym_elf) {
+ (void) elf_end(fptr->file_dynsym.sym_elf);
+ free(fptr->file_dynsym.sym_elfmem);
+ }
+ if (fptr->file_dynsym.sym_byname)
+ free(fptr->file_dynsym.sym_byname);
+ if (fptr->file_dynsym.sym_byaddr)
+ free(fptr->file_dynsym.sym_byaddr);
+
+ if (fptr->file_lo)
+ free(fptr->file_lo);
+ if (fptr->file_lname)
+ free(fptr->file_lname);
+ if (fptr->file_elf)
+ (void) elf_end(fptr->file_elf);
+ if (fptr->file_elfmem != NULL)
+ free(fptr->file_elfmem);
+ if (fptr->file_fd >= 0)
+ (void) close(fptr->file_fd);
+ if (fptr->file_ctfp) {
+ ctf_close(fptr->file_ctfp);
+ free(fptr->file_ctf_buf);
+ }
+ free(fptr);
+ P->num_files--;
+ }
+}
+
+/*
+ * Deallocation function for a map_info_t
+ */
+static void
+map_info_free(struct ps_prochandle *P, map_info_t *mptr)
+{
+ file_info_t *fptr;
+
+ if ((fptr = mptr->map_file) != NULL) {
+ if (fptr->file_map == mptr)
+ fptr->file_map = NULL;
+ file_info_free(P, fptr);
+ }
+ if (P->execname && mptr == P->map_exec) {
+ free(P->execname);
+ P->execname = NULL;
+ }
+ if (P->auxv && (mptr == P->map_exec || mptr == P->map_ldso)) {
+ free(P->auxv);
+ P->auxv = NULL;
+ P->nauxv = 0;
+ }
+ if (mptr == P->map_exec)
+ P->map_exec = NULL;
+ if (mptr == P->map_ldso)
+ P->map_ldso = NULL;
+}
+
+/*
+ * Call-back function for librtld_db to iterate through all of its shared
+ * libraries. We use this to get the load object names for the mappings.
+ */
+static int
+map_iter(const rd_loadobj_t *lop, void *cd)
+{
+ char buf[PATH_MAX];
+ struct ps_prochandle *P = cd;
+ map_info_t *mptr;
+ file_info_t *fptr;
+
+ dprintf("encountered rd object at %p\n", (void *)lop->rl_base);
+
+ if ((mptr = Paddr2mptr(P, lop->rl_base)) == NULL)
+ return (1); /* Base address does not match any mapping */
+
+ if ((fptr = mptr->map_file) == NULL &&
+ (fptr = file_info_new(P, mptr)) == NULL)
+ return (1); /* Failed to allocate a new file_info_t */
+
+ if ((fptr->file_lo == NULL) &&
+ (fptr->file_lo = malloc(sizeof (rd_loadobj_t))) == NULL) {
+ file_info_free(P, fptr);
+ return (1); /* Failed to allocate rd_loadobj_t */
+ }
+
+ fptr->file_map = mptr;
+ *fptr->file_lo = *lop;
+
+ fptr->file_lo->rl_plt_base = fptr->file_plt_base;
+ fptr->file_lo->rl_plt_size = fptr->file_plt_size;
+
+ if (fptr->file_lname) {
+ free(fptr->file_lname);
+ fptr->file_lname = NULL;
+ }
+
+ if (Pread_string(P, buf, sizeof (buf), lop->rl_nameaddr) > 0) {
+ if ((fptr->file_lname = strdup(buf)) != NULL)
+ fptr->file_lbase = basename(fptr->file_lname);
+ }
+
+ dprintf("loaded rd object %s lmid %lx\n",
+ fptr->file_lname ? fptr->file_lname : "<NULL>", lop->rl_lmident);
+ return (1);
+}
+
+static void
+map_set(struct ps_prochandle *P, map_info_t *mptr, const char *lname)
+{
+ file_info_t *fptr;
+
+ if ((fptr = mptr->map_file) == NULL &&
+ (fptr = file_info_new(P, mptr)) == NULL)
+ return; /* Failed to allocate a new file_info_t */
+
+ fptr->file_map = mptr;
+
+ if ((fptr->file_lo == NULL) &&
+ (fptr->file_lo = malloc(sizeof (rd_loadobj_t))) == NULL) {
+ file_info_free(P, fptr);
+ return; /* Failed to allocate rd_loadobj_t */
+ }
+
+ (void) memset(fptr->file_lo, 0, sizeof (rd_loadobj_t));
+ fptr->file_lo->rl_base = mptr->map_pmap.pr_vaddr;
+ fptr->file_lo->rl_bend =
+ mptr->map_pmap.pr_vaddr + mptr->map_pmap.pr_size;
+
+ fptr->file_lo->rl_plt_base = fptr->file_plt_base;
+ fptr->file_lo->rl_plt_size = fptr->file_plt_size;
+
+ if (fptr->file_lname) {
+ free(fptr->file_lname);
+ fptr->file_lname = NULL;
+ }
+
+ if ((fptr->file_lname = strdup(lname)) != NULL)
+ fptr->file_lbase = basename(fptr->file_lname);
+}
+
+static void
+load_static_maps(struct ps_prochandle *P)
+{
+ map_info_t *mptr;
+
+ /*
+ * Construct the map for the a.out.
+ */
+ if ((mptr = object_name_to_map(P, PR_LMID_EVERY, PR_OBJ_EXEC)) != NULL)
+ map_set(P, mptr, "a.out");
+
+ /*
+ * If the dynamic linker exists for this process,
+ * construct the map for it.
+ */
+ if (Pgetauxval(P, AT_BASE) != -1L &&
+ (mptr = object_name_to_map(P, PR_LMID_EVERY, PR_OBJ_LDSO)) != NULL)
+ map_set(P, mptr, "ld.so.1");
+}
+
+/*
+ * Go through all the address space mappings, validating or updating
+ * the information already gathered, or gathering new information.
+ *
+ * This function is only called when we suspect that the mappings have changed
+ * because this is the first time we're calling it or because of rtld activity.
+ */
+void
+Pupdate_maps(struct ps_prochandle *P)
+{
+ char mapfile[64];
+ int mapfd;
+ struct stat statb;
+ prmap_t *Pmap = NULL;
+ prmap_t *pmap;
+ ssize_t nmap;
+ int i;
+ uint_t oldmapcount;
+ map_info_t *newmap, *newp;
+ map_info_t *mptr;
+
+ if (P->info_valid)
+ return;
+
+ Preadauxvec(P);
+
+ (void) sprintf(mapfile, "/proc/%d/map", (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;
+ }
+ (void) close(mapfd);
+
+ if ((newmap = calloc(1, nmap * sizeof (map_info_t))) == NULL)
+ return;
+
+ /*
+ * We try to merge any file information we may have for existing
+ * mappings, to avoid having to rebuild the file info.
+ */
+ mptr = P->mappings;
+ pmap = Pmap;
+ newp = newmap;
+ oldmapcount = P->map_count;
+ for (i = 0; i < nmap; i++, pmap++, newp++) {
+
+ if (oldmapcount == 0) {
+ /*
+ * We've exhausted all the old mappings. Every new
+ * mapping should be added.
+ */
+ newp->map_pmap = *pmap;
+
+ } else if (pmap->pr_vaddr == mptr->map_pmap.pr_vaddr &&
+ pmap->pr_size == mptr->map_pmap.pr_size &&
+ pmap->pr_offset == mptr->map_pmap.pr_offset &&
+ (pmap->pr_mflags & ~(MA_BREAK | MA_STACK)) ==
+ (mptr->map_pmap.pr_mflags & ~(MA_BREAK | MA_STACK)) &&
+ pmap->pr_pagesize == mptr->map_pmap.pr_pagesize &&
+ pmap->pr_shmid == mptr->map_pmap.pr_shmid &&
+ strcmp(pmap->pr_mapname, mptr->map_pmap.pr_mapname) == 0) {
+
+ /*
+ * This mapping matches exactly. Copy over the old
+ * mapping, taking care to get the latest flags.
+ * Make sure the associated file_info_t is updated
+ * appropriately.
+ */
+ *newp = *mptr;
+ if (P->map_exec == mptr)
+ P->map_exec = newp;
+ if (P->map_ldso == mptr)
+ P->map_ldso = newp;
+ newp->map_pmap.pr_mflags = pmap->pr_mflags;
+ if (mptr->map_file != NULL &&
+ mptr->map_file->file_map == mptr)
+ mptr->map_file->file_map = newp;
+ oldmapcount--;
+ mptr++;
+
+ } else if (pmap->pr_vaddr + pmap->pr_size >
+ mptr->map_pmap.pr_vaddr) {
+
+ /*
+ * The old mapping doesn't exist any more, remove it
+ * from the list.
+ */
+ map_info_free(P, mptr);
+ oldmapcount--;
+ i--;
+ newp--;
+ pmap--;
+ mptr++;
+
+ } else {
+
+ /*
+ * This is a new mapping, add it directly.
+ */
+ newp->map_pmap = *pmap;
+ }
+ }
+
+ /*
+ * Free any old maps
+ */
+ while (oldmapcount) {
+ map_info_free(P, mptr);
+ oldmapcount--;
+ mptr++;
+ }
+
+ free(Pmap);
+ if (P->mappings != NULL)
+ free(P->mappings);
+ P->mappings = newmap;
+ P->map_count = P->map_alloc = nmap;
+ P->info_valid = 1;
+
+ /*
+ * Consult librtld_db to get the load object
+ * names for all of the shared libraries.
+ */
+ if (P->rap != NULL)
+ (void) rd_loadobj_iter(P->rap, map_iter, P);
+}
+
+/*
+ * Update all of the mappings and rtld_db as if by Pupdate_maps(), and then
+ * forcibly cache all of the symbol tables associated with all object files.
+ */
+void
+Pupdate_syms(struct ps_prochandle *P)
+{
+ file_info_t *fptr = list_next(&P->file_head);
+ int i;
+
+ Pupdate_maps(P);
+
+ for (i = 0; i < P->num_files; i++, fptr = list_next(fptr)) {
+ Pbuild_file_symtab(P, fptr);
+ (void) Pbuild_file_ctf(P, fptr);
+ }
+}
+
+/*
+ * Return the librtld_db agent handle for the victim process.
+ * The handle will become invalid at the next successful exec() and the
+ * client (caller of proc_rd_agent()) must not use it beyond that point.
+ * If the process is already dead, we've already tried our best to
+ * create the agent during core file initialization.
+ */
+rd_agent_t *
+Prd_agent(struct ps_prochandle *P)
+{
+ if (P->rap == NULL && P->state != PS_DEAD && P->state != PS_IDLE) {
+ Pupdate_maps(P);
+ if (P->num_files == 0)
+ load_static_maps(P);
+ rd_log(_libproc_debug);
+ if ((P->rap = rd_new(P)) != NULL)
+ (void) rd_loadobj_iter(P->rap, map_iter, P);
+ }
+ return (P->rap);
+}
+
+/*
+ * Return the prmap_t structure containing 'addr', but only if it
+ * is in the dynamic linker's link map and is the text section.
+ */
+const prmap_t *
+Paddr_to_text_map(struct ps_prochandle *P, uintptr_t addr)
+{
+ map_info_t *mptr;
+
+ if (!P->info_valid)
+ Pupdate_maps(P);
+
+ if ((mptr = Paddr2mptr(P, addr)) != NULL) {
+ file_info_t *fptr = build_map_symtab(P, mptr);
+ const prmap_t *pmp = &mptr->map_pmap;
+
+ if (fptr != NULL && fptr->file_lo != NULL &&
+ fptr->file_lo->rl_base >= pmp->pr_vaddr &&
+ fptr->file_lo->rl_base < pmp->pr_vaddr + pmp->pr_size)
+ return (pmp);
+ }
+
+ return (NULL);
+}
+
+/*
+ * Return the prmap_t structure containing 'addr' (no restrictions on
+ * the type of mapping).
+ */
+const prmap_t *
+Paddr_to_map(struct ps_prochandle *P, uintptr_t addr)
+{
+ map_info_t *mptr;
+
+ if (!P->info_valid)
+ Pupdate_maps(P);
+
+ if ((mptr = Paddr2mptr(P, addr)) != NULL)
+ return (&mptr->map_pmap);
+
+ return (NULL);
+}
+
+/*
+ * Convert a full or partial load object name to the prmap_t for its
+ * corresponding primary text mapping.
+ */
+const prmap_t *
+Plmid_to_map(struct ps_prochandle *P, Lmid_t lmid, const char *name)
+{
+ map_info_t *mptr;
+
+ if (name == PR_OBJ_EVERY)
+ return (NULL); /* A reasonable mistake */
+
+ if ((mptr = object_name_to_map(P, lmid, name)) != NULL)
+ return (&mptr->map_pmap);
+
+ return (NULL);
+}
+
+const prmap_t *
+Pname_to_map(struct ps_prochandle *P, const char *name)
+{
+ return (Plmid_to_map(P, PR_LMID_EVERY, name));
+}
+
+const rd_loadobj_t *
+Paddr_to_loadobj(struct ps_prochandle *P, uintptr_t addr)
+{
+ map_info_t *mptr;
+
+ if (!P->info_valid)
+ Pupdate_maps(P);
+
+ if ((mptr = Paddr2mptr(P, addr)) == NULL)
+ return (NULL);
+
+ /*
+ * By building the symbol table, we implicitly bring the PLT
+ * information up to date in the load object.
+ */
+ (void) build_map_symtab(P, mptr);
+
+ return (mptr->map_file->file_lo);
+}
+
+const rd_loadobj_t *
+Plmid_to_loadobj(struct ps_prochandle *P, Lmid_t lmid, const char *name)
+{
+ map_info_t *mptr;
+
+ if (name == PR_OBJ_EVERY)
+ return (NULL);
+
+ if ((mptr = object_name_to_map(P, lmid, name)) == NULL)
+ return (NULL);
+
+ /*
+ * By building the symbol table, we implicitly bring the PLT
+ * information up to date in the load object.
+ */
+ (void) build_map_symtab(P, mptr);
+
+ return (mptr->map_file->file_lo);
+}
+
+const rd_loadobj_t *
+Pname_to_loadobj(struct ps_prochandle *P, const char *name)
+{
+ return (Plmid_to_loadobj(P, PR_LMID_EVERY, name));
+}
+
+ctf_file_t *
+Pbuild_file_ctf(struct ps_prochandle *P, file_info_t *fptr)
+{
+ ctf_sect_t ctdata, symtab, strtab;
+ sym_tbl_t *symp;
+ int err;
+
+ if (fptr->file_ctfp != NULL)
+ return (fptr->file_ctfp);
+
+ Pbuild_file_symtab(P, fptr);
+
+ if (fptr->file_ctf_size == 0)
+ return (NULL);
+
+ symp = fptr->file_ctf_dyn ? &fptr->file_dynsym : &fptr->file_symtab;
+ if (symp->sym_data == NULL)
+ return (NULL);
+
+ /*
+ * The buffer may alread be allocated if this is a core file that
+ * contained CTF data for this file.
+ */
+ if (fptr->file_ctf_buf == NULL) {
+ fptr->file_ctf_buf = malloc(fptr->file_ctf_size);
+ if (fptr->file_ctf_buf == NULL) {
+ dprintf("failed to allocate ctf buffer\n");
+ return (NULL);
+ }
+
+ if (pread(fptr->file_fd, fptr->file_ctf_buf,
+ fptr->file_ctf_size, fptr->file_ctf_off) !=
+ fptr->file_ctf_size) {
+ free(fptr->file_ctf_buf);
+ fptr->file_ctf_buf = NULL;
+ dprintf("failed to read ctf data\n");
+ return (NULL);
+ }
+ }
+
+ ctdata.cts_name = ".SUNW_ctf";
+ ctdata.cts_type = SHT_PROGBITS;
+ ctdata.cts_flags = 0;
+ ctdata.cts_data = fptr->file_ctf_buf;
+ ctdata.cts_size = fptr->file_ctf_size;
+ ctdata.cts_entsize = 1;
+ ctdata.cts_offset = 0;
+
+ symtab.cts_name = fptr->file_ctf_dyn ? ".dynsym" : ".symtab";
+ symtab.cts_type = symp->sym_hdr.sh_type;
+ symtab.cts_flags = symp->sym_hdr.sh_flags;
+ symtab.cts_data = symp->sym_data->d_buf;
+ symtab.cts_size = symp->sym_hdr.sh_size;
+ symtab.cts_entsize = symp->sym_hdr.sh_entsize;
+ symtab.cts_offset = symp->sym_hdr.sh_offset;
+
+ strtab.cts_name = fptr->file_ctf_dyn ? ".dynstr" : ".strtab";
+ strtab.cts_type = symp->sym_strhdr.sh_type;
+ strtab.cts_flags = symp->sym_strhdr.sh_flags;
+ strtab.cts_data = symp->sym_strs;
+ strtab.cts_size = symp->sym_strhdr.sh_size;
+ strtab.cts_entsize = symp->sym_strhdr.sh_entsize;
+ strtab.cts_offset = symp->sym_strhdr.sh_offset;
+
+ fptr->file_ctfp = ctf_bufopen(&ctdata, &symtab, &strtab, &err);
+ if (fptr->file_ctfp == NULL) {
+ free(fptr->file_ctf_buf);
+ fptr->file_ctf_buf = NULL;
+ return (NULL);
+ }
+
+ dprintf("loaded %lu bytes of CTF data for %s\n",
+ (ulong_t)fptr->file_ctf_size, fptr->file_pname);
+
+ return (fptr->file_ctfp);
+}
+
+ctf_file_t *
+Paddr_to_ctf(struct ps_prochandle *P, uintptr_t addr)
+{
+ map_info_t *mptr;
+ file_info_t *fptr;
+
+ if (!P->info_valid)
+ Pupdate_maps(P);
+
+ if ((mptr = Paddr2mptr(P, addr)) == NULL ||
+ (fptr = mptr->map_file) == NULL)
+ return (NULL);
+
+ return (Pbuild_file_ctf(P, fptr));
+}
+
+ctf_file_t *
+Plmid_to_ctf(struct ps_prochandle *P, Lmid_t lmid, const char *name)
+{
+ map_info_t *mptr;
+ file_info_t *fptr;
+
+ if (name == PR_OBJ_EVERY)
+ return (NULL);
+
+ if ((mptr = object_name_to_map(P, lmid, name)) == NULL ||
+ (fptr = mptr->map_file) == NULL)
+ return (NULL);
+
+ return (Pbuild_file_ctf(P, fptr));
+}
+
+ctf_file_t *
+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) sprintf(auxfile, "/proc/%d/auxv", (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);
+}
+
+/*
+ * Return a requested element from the process's aux vector.
+ * Return -1 on failure (this is adequate for our purposes).
+ */
+long
+Pgetauxval(struct ps_prochandle *P, int type)
+{
+ auxv_t *auxv;
+
+ if (P->auxv == NULL)
+ Preadauxvec(P);
+
+ if (P->auxv == NULL)
+ return (-1);
+
+ for (auxv = P->auxv; auxv->a_type != AT_NULL; auxv++) {
+ if (auxv->a_type == type)
+ return (auxv->a_un.a_val);
+ }
+
+ return (-1);
+}
+
+/*
+ * Return a pointer to our internal copy of the process's aux vector.
+ * The caller should not hold on to this pointer across any libproc calls.
+ */
+const auxv_t *
+Pgetauxvec(struct ps_prochandle *P)
+{
+ static const auxv_t empty = { AT_NULL, 0L };
+
+ if (P->auxv == NULL)
+ Preadauxvec(P);
+
+ if (P->auxv == NULL)
+ return (&empty);
+
+ return (P->auxv);
+}
+
+/*
+ * Find or build the symbol table for the given mapping.
+ */
+static file_info_t *
+build_map_symtab(struct ps_prochandle *P, map_info_t *mptr)
+{
+ prmap_t *pmap = &mptr->map_pmap;
+ file_info_t *fptr;
+ rd_loadobj_t *lop;
+ uint_t i;
+
+ if ((fptr = mptr->map_file) != NULL) {
+ Pbuild_file_symtab(P, fptr);
+ return (fptr);
+ }
+
+ if (pmap->pr_mapname[0] == '\0')
+ return (NULL);
+
+ /*
+ * Attempt to find a matching file.
+ * (A file can be mapped at several different addresses.)
+ */
+ for (i = 0, fptr = list_next(&P->file_head); i < P->num_files;
+ i++, fptr = list_next(fptr)) {
+ if (strcmp(fptr->file_pname, pmap->pr_mapname) == 0 &&
+ (lop = fptr->file_lo) != NULL &&
+ ((pmap->pr_vaddr <= lop->rl_base &&
+ lop->rl_base < pmap->pr_vaddr + pmap->pr_size) ||
+ (pmap->pr_vaddr <= lop->rl_data_base &&
+ lop->rl_data_base < pmap->pr_vaddr + pmap->pr_size))) {
+ mptr->map_file = fptr;
+ fptr->file_ref++;
+ Pbuild_file_symtab(P, fptr);
+ return (fptr);
+ }
+ }
+
+ /*
+ * If we need to create a new file_info structure, iterate
+ * through the load objects in order to attempt to connect
+ * this new file with its primary text mapping. We again
+ * need to handle ld.so as a special case because we need
+ * to be able to bootstrap librtld_db.
+ */
+ if ((fptr = file_info_new(P, mptr)) == NULL)
+ return (NULL);
+
+ if (P->map_ldso != mptr) {
+ if (P->rap != NULL)
+ (void) rd_loadobj_iter(P->rap, map_iter, P);
+ else
+ (void) Prd_agent(P);
+ } else {
+ fptr->file_map = mptr;
+ }
+
+ /*
+ * If librtld_db wasn't able to help us connect the file to a primary
+ * text mapping, set file_map to the current mapping because we require
+ * fptr->file_map to be set in Pbuild_file_symtab. librtld_db may be
+ * unaware of what's going on in the rare case that a legitimate ELF
+ * file has been mmap(2)ed into the process address space *without*
+ * the use of dlopen(3x). Why would this happen? See pwdx ... :)
+ */
+ if (fptr->file_map == NULL)
+ fptr->file_map = mptr;
+
+ Pbuild_file_symtab(P, fptr);
+
+ return (fptr);
+}
+
+static int
+read_ehdr32(struct ps_prochandle *P, Elf32_Ehdr *ehdr, uintptr_t addr)
+{
+ if (Pread(P, ehdr, sizeof (*ehdr), addr) != sizeof (*ehdr))
+ return (-1);
+
+ if (ehdr->e_ident[EI_MAG0] != ELFMAG0 ||
+ ehdr->e_ident[EI_MAG1] != ELFMAG1 ||
+ ehdr->e_ident[EI_MAG2] != ELFMAG2 ||
+ ehdr->e_ident[EI_MAG3] != ELFMAG3 ||
+ ehdr->e_ident[EI_CLASS] != ELFCLASS32 ||
+#ifdef _BIG_ENDIAN
+ ehdr->e_ident[EI_DATA] != ELFDATA2MSB ||
+#else
+ ehdr->e_ident[EI_DATA] != ELFDATA2LSB ||
+#endif
+ ehdr->e_ident[EI_VERSION] != EV_CURRENT)
+ return (-1);
+
+ return (0);
+}
+
+static int
+read_dynamic_phdr32(struct ps_prochandle *P, const Elf32_Ehdr *ehdr,
+ Elf32_Phdr *phdr, uintptr_t addr)
+{
+ uint_t i;
+
+ for (i = 0; i < ehdr->e_phnum; i++) {
+ uintptr_t a = addr + ehdr->e_phoff + i * ehdr->e_phentsize;
+ if (Pread(P, phdr, sizeof (*phdr), a) != sizeof (*phdr))
+ return (-1);
+
+ if (phdr->p_type == PT_DYNAMIC)
+ return (0);
+ }
+
+ return (-1);
+}
+
+#ifdef _LP64
+static int
+read_ehdr64(struct ps_prochandle *P, Elf64_Ehdr *ehdr, uintptr_t addr)
+{
+ if (Pread(P, ehdr, sizeof (Elf64_Ehdr), addr) != sizeof (Elf64_Ehdr))
+ return (-1);
+
+ if (ehdr->e_ident[EI_MAG0] != ELFMAG0 ||
+ ehdr->e_ident[EI_MAG1] != ELFMAG1 ||
+ ehdr->e_ident[EI_MAG2] != ELFMAG2 ||
+ ehdr->e_ident[EI_MAG3] != ELFMAG3 ||
+ ehdr->e_ident[EI_CLASS] != ELFCLASS64 ||
+#ifdef _BIG_ENDIAN
+ ehdr->e_ident[EI_DATA] != ELFDATA2MSB ||
+#else
+ ehdr->e_ident[EI_DATA] != ELFDATA2LSB ||
+#endif
+ ehdr->e_ident[EI_VERSION] != EV_CURRENT)
+ return (-1);
+
+ return (0);
+}
+
+static int
+read_dynamic_phdr64(struct ps_prochandle *P, const Elf64_Ehdr *ehdr,
+ Elf64_Phdr *phdr, uintptr_t addr)
+{
+ uint_t i;
+
+ for (i = 0; i < ehdr->e_phnum; i++) {
+ uintptr_t a = addr + ehdr->e_phoff + i * ehdr->e_phentsize;
+ if (Pread(P, phdr, sizeof (*phdr), a) != sizeof (*phdr))
+ return (-1);
+
+ if (phdr->p_type == PT_DYNAMIC)
+ return (0);
+ }
+
+ return (-1);
+}
+#endif /* _LP64 */
+
+/*
+ * The text segment for each load object contains the elf header and
+ * program headers. We can use this information to determine if the
+ * file that corresponds to the load object is the same file that
+ * was loaded into the process's address space. There can be a discrepency
+ * if a file is recompiled after the process is started or if the target
+ * represents a core file from a differently configured system -- two
+ * common examples. The DT_CHECKSUM entry in the dynamic section
+ * provides an easy method of comparison. It is important to note that
+ * the dynamic section usually lives in the data segment, but the meta
+ * data we use to find the dynamic section lives in the text segment so
+ * if either of those segments is absent we can't proceed.
+ *
+ * We're looking through the elf file for several items: the symbol tables
+ * (both dynsym and symtab), the procedure linkage table (PLT) base,
+ * size, and relocation base, and the CTF information. Most of this can
+ * be recovered from the loaded image of the file itself, the exceptions
+ * being the symtab and CTF data.
+ *
+ * First we try to open the file that we think corresponds to the load
+ * object, if the DT_CHECKSUM values match, we're all set, and can simply
+ * recover all the information we need from the file. If the values of
+ * DT_CHECKSUM don't match, or if we can't access the file for whatever
+ * reasaon, we fake up a elf file to use in its stead. If we can't read
+ * the elf data in the process's address space, we fall back to using
+ * the file even though it may give inaccurate information.
+ *
+ * The elf file that we fake up has to consist of sections for the
+ * dynsym, the PLT and the dynamic section. Note that in the case of a
+ * core file, we'll get the CTF data in the file_info_t later on from
+ * a section embedded the core file (if it's present).
+ *
+ * file_differs() conservatively looks for mismatched files, identifying
+ * a match when there is any ambiguity (since that's the legacy behavior).
+ */
+static int
+file_differs(struct ps_prochandle *P, Elf *elf, file_info_t *fptr)
+{
+ Elf_Scn *scn;
+ GElf_Shdr shdr;
+ GElf_Dyn dyn;
+ Elf_Data *data;
+ uint_t i, ndyn;
+ GElf_Xword cksum;
+ uintptr_t addr;
+
+ if (fptr->file_map == NULL)
+ return (0);
+
+ if ((Pcontent(P) & (CC_CONTENT_TEXT | CC_CONTENT_DATA)) !=
+ (CC_CONTENT_TEXT | CC_CONTENT_DATA))
+ return (0);
+
+ /*
+ * First, we find the checksum value in the elf file.
+ */
+ scn = NULL;
+ while ((scn = elf_nextscn(elf, scn)) != NULL) {
+ if (gelf_getshdr(scn, &shdr) != NULL &&
+ shdr.sh_type == SHT_DYNAMIC)
+ goto found_shdr;
+ }
+ return (0);
+
+found_shdr:
+ if ((data = elf_getdata(scn, NULL)) == NULL)
+ return (0);
+
+ if (P->status.pr_dmodel == PR_MODEL_ILP32)
+ ndyn = shdr.sh_size / sizeof (Elf32_Dyn);
+#ifdef _LP64
+ else if (P->status.pr_dmodel == PR_MODEL_LP64)
+ ndyn = shdr.sh_size / sizeof (Elf64_Dyn);
+#endif
+ else
+ return (0);
+
+ for (i = 0; i < ndyn; i++) {
+ if (gelf_getdyn(data, i, &dyn) != NULL &&
+ dyn.d_tag == DT_CHECKSUM)
+ goto found_cksum;
+ }
+ return (0);
+
+found_cksum:
+ cksum = dyn.d_un.d_val;
+ dprintf("elf cksum value is %llx\n", (u_longlong_t)cksum);
+
+ /*
+ * Get the base of the text mapping that corresponds to this file.
+ */
+ addr = fptr->file_map->map_pmap.pr_vaddr;
+
+ if (P->status.pr_dmodel == PR_MODEL_ILP32) {
+ Elf32_Ehdr ehdr;
+ Elf32_Phdr phdr;
+ Elf32_Dyn dync, *dynp;
+ uint_t i;
+
+ if (read_ehdr32(P, &ehdr, addr) != 0 ||
+ read_dynamic_phdr32(P, &ehdr, &phdr, addr) != 0)
+ return (0);
+
+ if (ehdr.e_type == ET_DYN)
+ phdr.p_vaddr += addr;
+ if ((dynp = malloc(phdr.p_filesz)) == NULL)
+ return (0);
+ dync.d_tag = DT_NULL;
+ if (Pread(P, dynp, phdr.p_filesz, phdr.p_vaddr) !=
+ phdr.p_filesz) {
+ free(dynp);
+ return (0);
+ }
+
+ for (i = 0; i < phdr.p_filesz / sizeof (Elf32_Dyn); i++) {
+ if (dynp[i].d_tag == DT_CHECKSUM)
+ dync = dynp[i];
+ }
+
+ free(dynp);
+
+ if (dync.d_tag != DT_CHECKSUM)
+ return (0);
+
+ dprintf("image cksum value is %llx\n",
+ (u_longlong_t)dync.d_un.d_val);
+ return (dync.d_un.d_val != cksum);
+#ifdef _LP64
+ } else if (P->status.pr_dmodel == PR_MODEL_LP64) {
+ Elf64_Ehdr ehdr;
+ Elf64_Phdr phdr;
+ Elf64_Dyn dync, *dynp;
+ uint_t i;
+
+ if (read_ehdr64(P, &ehdr, addr) != 0 ||
+ read_dynamic_phdr64(P, &ehdr, &phdr, addr) != 0)
+ return (0);
+
+ if (ehdr.e_type == ET_DYN)
+ phdr.p_vaddr += addr;
+ if ((dynp = malloc(phdr.p_filesz)) == NULL)
+ return (0);
+ dync.d_tag = DT_NULL;
+ if (Pread(P, dynp, phdr.p_filesz, phdr.p_vaddr) !=
+ phdr.p_filesz) {
+ free(dynp);
+ return (0);
+ }
+
+ for (i = 0; i < phdr.p_filesz / sizeof (Elf64_Dyn); i++) {
+ if (dynp[i].d_tag == DT_CHECKSUM)
+ dync = dynp[i];
+ }
+
+ free(dynp);
+
+ if (dync.d_tag != DT_CHECKSUM)
+ return (0);
+
+ dprintf("image cksum value is %llx\n",
+ (u_longlong_t)dync.d_un.d_val);
+ return (dync.d_un.d_val != cksum);
+#endif /* _LP64 */
+ }
+
+ return (0);
+}
+
+static Elf *
+fake_elf(struct ps_prochandle *P, file_info_t *fptr)
+{
+ enum {
+ DI_PLTGOT = 0,
+ DI_JMPREL,
+ DI_PLTRELSZ,
+ DI_PLTREL,
+ DI_SYMTAB,
+ DI_HASH,
+ DI_SYMENT,
+ DI_STRTAB,
+ DI_STRSZ,
+ DI_NENT
+ };
+ uintptr_t addr;
+ size_t size = 0;
+ caddr_t elfdata = NULL;
+ Elf *elf;
+ Elf32_Word nchain;
+ static char shstr[] = ".shstrtab\0.dynsym\0.dynstr\0.dynamic\0.plt";
+
+ if (fptr->file_map == NULL)
+ return (NULL);
+
+ if ((Pcontent(P) & (CC_CONTENT_TEXT | CC_CONTENT_DATA)) !=
+ (CC_CONTENT_TEXT | CC_CONTENT_DATA))
+ return (NULL);
+
+ addr = fptr->file_map->map_pmap.pr_vaddr;
+
+ /*
+ * We're building a in memory elf file that will let us use libelf
+ * for most of the work we need to later (e.g. symbol table lookups).
+ * We need sections for the dynsym, dynstr, and plt, and we need
+ * the program headers from the text section. The former is used in
+ * Pbuild_file_symtab(); the latter is used in several functions in
+ * Pcore.c to reconstruct the origin of each mapping from the load
+ * object that spawned it.
+ *
+ * Here are some useful pieces of elf trivia that will help
+ * to elucidate this code.
+ *
+ * All the information we need about the dynstr can be found in these
+ * two entries in the dynamic section:
+ *
+ * DT_STRTAB base of dynstr
+ * DT_STRSZ size of dynstr
+ *
+ * So deciphering the dynstr is pretty straightforward.
+ *
+ * The dynsym is a little trickier.
+ *
+ * DT_SYMTAB base of dynsym
+ * DT_SYMENT size of a dynstr entry (Elf{32,64}_Sym)
+ * DT_HASH base of hash table for dynamic lookups
+ *
+ * The DT_SYMTAB entry gives us any easy way of getting to the base
+ * of the dynsym, but getting the size involves rooting around in the
+ * dynamic lookup hash table. Here's the layout of the hash table:
+ *
+ * +-------------------+
+ * | nbucket | All values are of type
+ * +-------------------+ Elf32_Word
+ * | nchain |
+ * +-------------------+
+ * | bucket[0] |
+ * | . . . |
+ * | bucket[nbucket-1] |
+ * +-------------------+
+ * | chain[0] |
+ * | . . . |
+ * | chain[nchain-1] |
+ * +-------------------+
+ * (figure 5-12 from the SYS V Generic ABI)
+ *
+ * Symbols names are hashed into a particular bucket which contains
+ * an index into the symbol table. Each entry in the symbol table
+ * has a corresponding entry in the chain table which tells the
+ * consumer where the next entry in the hash chain is. We can use
+ * the nchain field to find out the size of the dynsym.
+ *
+ * We can figure out the size of the .plt section, but it takes some
+ * doing. We need to use the following information:
+ *
+ * DT_PLTGOT base of the PLT
+ * DT_JMPREL base of the PLT's relocation section
+ * DT_PLTRELSZ size of the PLT's relocation section
+ * DT_PLTREL type of the PLT's relocation section
+ *
+ * We can use the relocation section to figure out the address of the
+ * last entry and subtract off the value of DT_PLTGOT to calculate
+ * the size of the PLT.
+ *
+ * For more information, check out the System V Generic ABI.
+ */
+
+ if (P->status.pr_dmodel == PR_MODEL_ILP32) {
+ Elf32_Ehdr ehdr, *ep;
+ Elf32_Phdr phdr;
+ Elf32_Shdr *sp;
+ Elf32_Dyn *dp;
+ Elf32_Dyn *d[DI_NENT] = { 0 };
+ uint_t i, dcount = 0;
+ uint32_t off;
+ size_t pltsz = 0, pltentsz;
+
+ if (read_ehdr32(P, &ehdr, addr) != 0 ||
+ read_dynamic_phdr32(P, &ehdr, &phdr, addr) != 0)
+ return (NULL);
+
+ if (ehdr.e_type == ET_DYN)
+ phdr.p_vaddr += addr;
+
+ if ((dp = malloc(phdr.p_filesz)) == NULL)
+ return (NULL);
+
+ if (Pread(P, dp, phdr.p_filesz, phdr.p_vaddr) !=
+ phdr.p_filesz) {
+ free(dp);
+ return (NULL);
+ }
+
+ for (i = 0; i < phdr.p_filesz / sizeof (Elf32_Dyn); i++) {
+ switch (dp[i].d_tag) {
+ /*
+ * For the .plt section.
+ */
+ case DT_PLTGOT:
+ d[DI_PLTGOT] = &dp[i];
+ continue;
+ case DT_JMPREL:
+ d[DI_JMPREL] = &dp[i];
+ continue;
+ case DT_PLTRELSZ:
+ d[DI_PLTRELSZ] = &dp[i];
+ continue;
+ case DT_PLTREL:
+ d[DI_PLTREL] = &dp[i];
+ continue;
+ default:
+ continue;
+
+ /*
+ * For the .dynsym section.
+ */
+ case DT_SYMTAB:
+ d[DI_SYMTAB] = &dp[i];
+ break;
+ case DT_HASH:
+ d[DI_HASH] = &dp[i];
+ break;
+ case DT_SYMENT:
+ d[DI_SYMENT] = &dp[i];
+ break;
+
+ /*
+ * For the .dynstr section.
+ */
+ case DT_STRTAB:
+ d[DI_STRTAB] = &dp[i];
+ break;
+ case DT_STRSZ:
+ d[DI_STRSZ] = &dp[i];
+ break;
+ }
+
+ dcount++;
+ }
+
+ /*
+ * We need all of those dynamic entries in order to put
+ * together a complete set of elf sections, but we'll
+ * let the PLT section slide if need be. The dynsym- and
+ * dynstr-related dynamic entries are mandatory in both
+ * executables and shared objects so if one of those is
+ * missing, we're in some trouble and should abort.
+ */
+ if (dcount + 4 != DI_NENT) {
+ dprintf("text section missing required dynamic "
+ "entries\n");
+ return (NULL);
+ }
+
+ if (ehdr.e_type == ET_DYN) {
+ if (d[DI_PLTGOT] != NULL)
+ d[DI_PLTGOT]->d_un.d_ptr += addr;
+ if (d[DI_JMPREL] != NULL)
+ d[DI_JMPREL]->d_un.d_ptr += addr;
+ d[DI_SYMTAB]->d_un.d_ptr += addr;
+ d[DI_HASH]->d_un.d_ptr += addr;
+ d[DI_STRTAB]->d_un.d_ptr += addr;
+ }
+
+ /* elf header */
+ size = sizeof (Elf32_Ehdr);
+
+ /* program headers from in-core elf fragment */
+ size += ehdr.e_phnum * ehdr.e_phentsize;
+
+ /* unused shdr, and .shstrtab section */
+ size += sizeof (Elf32_Shdr);
+ size += sizeof (Elf32_Shdr);
+ size += roundup(sizeof (shstr), 4);
+
+ /* .dynsym section */
+ size += sizeof (Elf32_Shdr);
+ if (Pread(P, &nchain, sizeof (nchain),
+ d[DI_HASH]->d_un.d_ptr + 4) != sizeof (nchain))
+ goto bad32;
+ size += sizeof (Elf32_Sym) * nchain;
+
+ /* .dynstr section */
+ size += sizeof (Elf32_Shdr);
+ size += roundup(d[DI_STRSZ]->d_un.d_val, 4);
+
+ /* .dynamic section */
+ size += sizeof (Elf32_Shdr);
+ size += roundup(phdr.p_filesz, 4);
+
+ /* .plt section */
+ if (d[DI_PLTGOT] != NULL && d[DI_JMPREL] != NULL &&
+ d[DI_PLTRELSZ] != NULL && d[DI_PLTREL] != NULL) {
+ uintptr_t penult, ult;
+ uintptr_t jmprel = d[DI_JMPREL]->d_un.d_ptr;
+ size_t pltrelsz = d[DI_PLTRELSZ]->d_un.d_val;
+
+ if (d[DI_PLTREL]->d_un.d_val == DT_RELA) {
+ uint_t ndx = pltrelsz / sizeof (Elf32_Rela) - 2;
+ Elf32_Rela r[2];
+
+ if (Pread(P, r, sizeof (r), jmprel +
+ sizeof (r[0]) * ndx) != sizeof (r))
+ goto bad32;
+
+ penult = r[0].r_offset;
+ ult = r[1].r_offset;
+
+ } else if (d[DI_PLTREL]->d_un.d_val == DT_REL) {
+ uint_t ndx = pltrelsz / sizeof (Elf32_Rel) - 2;
+ Elf32_Rel r[2];
+
+ if (Pread(P, r, sizeof (r), jmprel +
+ sizeof (r[0]) * ndx) != sizeof (r))
+ goto bad32;
+
+ penult = r[0].r_offset;
+ ult = r[1].r_offset;
+ } else {
+ goto bad32;
+ }
+
+ pltentsz = ult - penult;
+
+ if (ehdr.e_type == ET_DYN)
+ ult += addr;
+
+ pltsz = ult - d[DI_PLTGOT]->d_un.d_ptr + pltentsz;
+
+ size += sizeof (Elf32_Shdr);
+ size += roundup(pltsz, 4);
+ }
+
+ if ((elfdata = calloc(1, size)) == NULL)
+ goto bad32;
+
+ /* LINTED - alignment */
+ ep = (Elf32_Ehdr *)elfdata;
+ (void) memcpy(ep, &ehdr, offsetof(Elf32_Ehdr, e_phoff));
+
+ ep->e_ehsize = sizeof (Elf32_Ehdr);
+ ep->e_phoff = sizeof (Elf32_Ehdr);
+ ep->e_phentsize = ehdr.e_phentsize;
+ ep->e_phnum = ehdr.e_phnum;
+ ep->e_shoff = ep->e_phoff + ep->e_phnum * ep->e_phentsize;
+ ep->e_shentsize = sizeof (Elf32_Shdr);
+ ep->e_shnum = (pltsz == 0) ? 5 : 6;
+ ep->e_shstrndx = 1;
+
+ /* LINTED - alignment */
+ sp = (Elf32_Shdr *)(elfdata + ep->e_shoff);
+ off = ep->e_shoff + ep->e_shentsize * ep->e_shnum;
+
+ /*
+ * Copying the program headers directly from the process's
+ * address space is a little suspect, but since we only
+ * use them for their address and size values, this is fine.
+ */
+ if (Pread(P, &elfdata[ep->e_phoff],
+ ep->e_phnum * ep->e_phentsize, addr + ehdr.e_phoff) !=
+ ep->e_phnum * ep->e_phentsize) {
+ free(elfdata);
+ goto bad32;
+ }
+
+ /*
+ * The first elf section is always skipped.
+ */
+ sp++;
+
+ /*
+ * Section Header[1] sh_name: .shstrtab
+ */
+ sp->sh_name = 0;
+ sp->sh_type = SHT_STRTAB;
+ sp->sh_flags = SHF_STRINGS;
+ sp->sh_addr = 0;
+ sp->sh_offset = off;
+ sp->sh_size = sizeof (shstr);
+ sp->sh_link = 0;
+ sp->sh_info = 0;
+ sp->sh_addralign = 1;
+ sp->sh_entsize = 0;
+
+ (void) memcpy(&elfdata[off], shstr, sizeof (shstr));
+ off += roundup(sp->sh_size, 4);
+ sp++;
+
+ /*
+ * Section Header[2] sh_name: .dynsym
+ */
+ sp->sh_name = 10;
+ sp->sh_type = SHT_DYNSYM;
+ sp->sh_flags = SHF_ALLOC;
+ sp->sh_addr = d[DI_SYMTAB]->d_un.d_ptr;
+ if (ehdr.e_type == ET_DYN)
+ sp->sh_addr -= addr;
+ sp->sh_offset = off;
+ sp->sh_size = nchain * sizeof (Elf32_Sym);
+ sp->sh_link = 3;
+ sp->sh_info = 1;
+ sp->sh_addralign = 4;
+ sp->sh_entsize = sizeof (Elf32_Sym);
+
+ if (Pread(P, &elfdata[off], sp->sh_size,
+ d[DI_SYMTAB]->d_un.d_ptr) != sp->sh_size) {
+ free(elfdata);
+ goto bad32;
+ }
+
+ off += roundup(sp->sh_size, 4);
+ sp++;
+
+ /*
+ * Section Header[3] sh_name: .dynstr
+ */
+ sp->sh_name = 18;
+ sp->sh_type = SHT_STRTAB;
+ sp->sh_flags = SHF_ALLOC | SHF_STRINGS;
+ sp->sh_addr = d[DI_STRTAB]->d_un.d_ptr;
+ if (ehdr.e_type == ET_DYN)
+ sp->sh_addr -= addr;
+ sp->sh_offset = off;
+ sp->sh_size = d[DI_STRSZ]->d_un.d_val;
+ sp->sh_link = 0;
+ sp->sh_info = 0;
+ sp->sh_addralign = 1;
+ sp->sh_entsize = 0;
+
+ if (Pread(P, &elfdata[off], sp->sh_size,
+ d[DI_STRTAB]->d_un.d_ptr) != sp->sh_size) {
+ free(elfdata);
+ goto bad32;
+ }
+ off += roundup(sp->sh_size, 4);
+ sp++;
+
+ /*
+ * Section Header[4] sh_name: .dynamic
+ */
+ sp->sh_name = 26;
+ sp->sh_type = SHT_DYNAMIC;
+ sp->sh_flags = SHF_WRITE | SHF_ALLOC;
+ sp->sh_addr = phdr.p_vaddr;
+ if (ehdr.e_type == ET_DYN)
+ sp->sh_addr -= addr;
+ sp->sh_offset = off;
+ sp->sh_size = phdr.p_filesz;
+ sp->sh_link = 3;
+ sp->sh_info = 0;
+ sp->sh_addralign = 4;
+ sp->sh_entsize = sizeof (Elf32_Dyn);
+
+ (void) memcpy(&elfdata[off], dp, sp->sh_size);
+ off += roundup(sp->sh_size, 4);
+ sp++;
+
+ /*
+ * Section Header[5] sh_name: .plt
+ */
+ if (pltsz != 0) {
+ sp->sh_name = 35;
+ sp->sh_type = SHT_PROGBITS;
+ sp->sh_flags = SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR;
+ sp->sh_addr = d[DI_PLTGOT]->d_un.d_ptr;
+ if (ehdr.e_type == ET_DYN)
+ sp->sh_addr -= addr;
+ sp->sh_offset = off;
+ sp->sh_size = pltsz;
+ sp->sh_link = 0;
+ sp->sh_info = 0;
+ sp->sh_addralign = 4;
+ sp->sh_entsize = pltentsz;
+
+ if (Pread(P, &elfdata[off], sp->sh_size,
+ d[DI_PLTGOT]->d_un.d_ptr) != sp->sh_size) {
+ free(elfdata);
+ goto bad32;
+ }
+ off += roundup(sp->sh_size, 4);
+ sp++;
+ }
+
+ free(dp);
+ goto good;
+
+bad32:
+ free(dp);
+ return (NULL);
+#ifdef _LP64
+ } else if (P->status.pr_dmodel == PR_MODEL_LP64) {
+ Elf64_Ehdr ehdr, *ep;
+ Elf64_Phdr phdr;
+ Elf64_Shdr *sp;
+ Elf64_Dyn *dp;
+ Elf64_Dyn *d[DI_NENT] = { 0 };
+ uint_t i, dcount = 0;
+ uint64_t off;
+ size_t pltsz = 0, pltentsz;
+
+ if (read_ehdr64(P, &ehdr, addr) != 0 ||
+ read_dynamic_phdr64(P, &ehdr, &phdr, addr) != 0)
+ return (NULL);
+
+ if (ehdr.e_type == ET_DYN)
+ phdr.p_vaddr += addr;
+
+ if ((dp = malloc(phdr.p_filesz)) == NULL)
+ return (NULL);
+
+ if (Pread(P, dp, phdr.p_filesz, phdr.p_vaddr) !=
+ phdr.p_filesz) {
+ free(dp);
+ return (NULL);
+ }
+
+ for (i = 0; i < phdr.p_filesz / sizeof (Elf64_Dyn); i++) {
+ switch (dp[i].d_tag) {
+ /*
+ * For the .plt section.
+ */
+ case DT_PLTGOT:
+ d[DI_PLTGOT] = &dp[i];
+ continue;
+ case DT_JMPREL:
+ d[DI_JMPREL] = &dp[i];
+ continue;
+ case DT_PLTRELSZ:
+ d[DI_PLTRELSZ] = &dp[i];
+ continue;
+ case DT_PLTREL:
+ d[DI_PLTREL] = &dp[i];
+ continue;
+ default:
+ continue;
+
+ /*
+ * For the .dynsym section.
+ */
+ case DT_SYMTAB:
+ d[DI_SYMTAB] = &dp[i];
+ break;
+ case DT_HASH:
+ d[DI_HASH] = &dp[i];
+ break;
+ case DT_SYMENT:
+ d[DI_SYMENT] = &dp[i];
+ break;
+
+ /*
+ * For the .dynstr section.
+ */
+ case DT_STRTAB:
+ d[DI_STRTAB] = &dp[i];
+ break;
+ case DT_STRSZ:
+ d[DI_STRSZ] = &dp[i];
+ break;
+ }
+
+ dcount++;
+ }
+
+ /*
+ * We need all of those dynamic entries in order to put
+ * together a complete set of elf sections, but we'll
+ * let the PLT section slide if need be. The dynsym- and
+ * dynstr-related dynamic entries are mandatory in both
+ * executables and shared objects so if one of those is
+ * missing, we're in some trouble and should abort.
+ */
+ if (dcount + 4 != DI_NENT) {
+ dprintf("text section missing required dynamic "
+ "entries\n");
+ return (NULL);
+ }
+
+ if (ehdr.e_type == ET_DYN) {
+ if (d[DI_PLTGOT] != NULL)
+ d[DI_PLTGOT]->d_un.d_ptr += addr;
+ if (d[DI_JMPREL] != NULL)
+ d[DI_JMPREL]->d_un.d_ptr += addr;
+ d[DI_SYMTAB]->d_un.d_ptr += addr;
+ d[DI_HASH]->d_un.d_ptr += addr;
+ d[DI_STRTAB]->d_un.d_ptr += addr;
+ }
+
+ /* elf header */
+ size = sizeof (Elf64_Ehdr);
+
+ /* program headers from in-core elf fragment */
+ size += ehdr.e_phnum * ehdr.e_phentsize;
+
+ /* unused shdr, and .shstrtab section */
+ size += sizeof (Elf64_Shdr);
+ size += sizeof (Elf64_Shdr);
+ size += roundup(sizeof (shstr), 8);
+
+ /* .dynsym section */
+ size += sizeof (Elf64_Shdr);
+ if (Pread(P, &nchain, sizeof (nchain),
+ d[DI_HASH]->d_un.d_ptr + 4) != sizeof (nchain))
+ goto bad64;
+ size += sizeof (Elf64_Sym) * nchain;
+
+ /* .dynstr section */
+ size += sizeof (Elf64_Shdr);
+ size += roundup(d[DI_STRSZ]->d_un.d_val, 8);
+
+ /* .dynamic section */
+ size += sizeof (Elf64_Shdr);
+ size += roundup(phdr.p_filesz, 8);
+
+ /* .plt section */
+ if (d[DI_PLTGOT] != NULL && d[DI_JMPREL] != NULL &&
+ d[DI_PLTRELSZ] != NULL && d[DI_PLTREL] != NULL) {
+ uintptr_t penult, ult;
+ uintptr_t jmprel = d[DI_JMPREL]->d_un.d_ptr;
+ size_t pltrelsz = d[DI_PLTRELSZ]->d_un.d_val;
+
+ if (d[DI_PLTREL]->d_un.d_val == DT_RELA) {
+ uint_t ndx = pltrelsz / sizeof (Elf64_Rela) - 2;
+ Elf64_Rela r[2];
+
+ if (Pread(P, r, sizeof (r), jmprel +
+ sizeof (r[0]) * ndx) != sizeof (r))
+ goto bad64;
+
+ penult = r[0].r_offset;
+ ult = r[1].r_offset;
+
+ } else if (d[DI_PLTREL]->d_un.d_val == DT_REL) {
+ uint_t ndx = pltrelsz / sizeof (Elf64_Rel) - 2;
+ Elf64_Rel r[2];
+
+ if (Pread(P, r, sizeof (r), jmprel +
+ sizeof (r[0]) * ndx) != sizeof (r))
+ goto bad64;
+
+ penult = r[0].r_offset;
+ ult = r[1].r_offset;
+ } else {
+ goto bad64;
+ }
+
+ pltentsz = ult - penult;
+
+ if (ehdr.e_type == ET_DYN)
+ ult += addr;
+
+ pltsz = ult - d[DI_PLTGOT]->d_un.d_ptr + pltentsz;
+
+ size += sizeof (Elf64_Shdr);
+ size += roundup(pltsz, 8);
+ }
+
+ if ((elfdata = calloc(1, size)) == NULL)
+ goto bad64;
+
+ /* LINTED - alignment */
+ ep = (Elf64_Ehdr *)elfdata;
+ (void) memcpy(ep, &ehdr, offsetof(Elf64_Ehdr, e_phoff));
+
+ ep->e_ehsize = sizeof (Elf64_Ehdr);
+ ep->e_phoff = sizeof (Elf64_Ehdr);
+ ep->e_phentsize = ehdr.e_phentsize;
+ ep->e_phnum = ehdr.e_phnum;
+ ep->e_shoff = ep->e_phoff + ep->e_phnum * ep->e_phentsize;
+ ep->e_shentsize = sizeof (Elf64_Shdr);
+ ep->e_shnum = (pltsz == 0) ? 5 : 6;
+ ep->e_shstrndx = 1;
+
+ /* LINTED - alignment */
+ sp = (Elf64_Shdr *)(elfdata + ep->e_shoff);
+ off = ep->e_shoff + ep->e_shentsize * ep->e_shnum;
+
+ /*
+ * Copying the program headers directly from the process's
+ * address space is a little suspect, but since we only
+ * use them for their address and size values, this is fine.
+ */
+ if (Pread(P, &elfdata[ep->e_phoff],
+ ep->e_phnum * ep->e_phentsize, addr + ehdr.e_phoff) !=
+ ep->e_phnum * ep->e_phentsize) {
+ free(elfdata);
+ goto bad64;
+ }
+
+ /*
+ * The first elf section is always skipped.
+ */
+ sp++;
+
+ /*
+ * Section Header[1] sh_name: .shstrtab
+ */
+ sp->sh_name = 0;
+ sp->sh_type = SHT_STRTAB;
+ sp->sh_flags = SHF_STRINGS;
+ sp->sh_addr = 0;
+ sp->sh_offset = off;
+ sp->sh_size = sizeof (shstr);
+ sp->sh_link = 0;
+ sp->sh_info = 0;
+ sp->sh_addralign = 1;
+ sp->sh_entsize = 0;
+
+ (void) memcpy(&elfdata[off], shstr, sizeof (shstr));
+ off += roundup(sp->sh_size, 8);
+ sp++;
+
+ /*
+ * Section Header[2] sh_name: .dynsym
+ */
+ sp->sh_name = 10;
+ sp->sh_type = SHT_DYNSYM;
+ sp->sh_flags = SHF_ALLOC;
+ sp->sh_addr = d[DI_SYMTAB]->d_un.d_ptr;
+ if (ehdr.e_type == ET_DYN)
+ sp->sh_addr -= addr;
+ sp->sh_offset = off;
+ sp->sh_size = nchain * sizeof (Elf64_Sym);
+ sp->sh_link = 3;
+ sp->sh_info = 1;
+ sp->sh_addralign = 8;
+ sp->sh_entsize = sizeof (Elf64_Sym);
+
+ if (Pread(P, &elfdata[off], sp->sh_size,
+ d[DI_SYMTAB]->d_un.d_ptr) != sp->sh_size) {
+ free(elfdata);
+ goto bad64;
+ }
+
+ off += roundup(sp->sh_size, 8);
+ sp++;
+
+ /*
+ * Section Header[3] sh_name: .dynstr
+ */
+ sp->sh_name = 18;
+ sp->sh_type = SHT_STRTAB;
+ sp->sh_flags = SHF_ALLOC | SHF_STRINGS;
+ sp->sh_addr = d[DI_STRTAB]->d_un.d_ptr;
+ if (ehdr.e_type == ET_DYN)
+ sp->sh_addr -= addr;
+ sp->sh_offset = off;
+ sp->sh_size = d[DI_STRSZ]->d_un.d_val;
+ sp->sh_link = 0;
+ sp->sh_info = 0;
+ sp->sh_addralign = 1;
+ sp->sh_entsize = 0;
+
+ if (Pread(P, &elfdata[off], sp->sh_size,
+ d[DI_STRTAB]->d_un.d_ptr) != sp->sh_size) {
+ free(elfdata);
+ goto bad64;
+ }
+ off += roundup(sp->sh_size, 8);
+ sp++;
+
+ /*
+ * Section Header[4] sh_name: .dynamic
+ */
+ sp->sh_name = 26;
+ sp->sh_type = SHT_DYNAMIC;
+ sp->sh_flags = SHF_WRITE | SHF_ALLOC;
+ sp->sh_addr = phdr.p_vaddr;
+ if (ehdr.e_type == ET_DYN)
+ sp->sh_addr -= addr;
+ sp->sh_offset = off;
+ sp->sh_size = phdr.p_filesz;
+ sp->sh_link = 3;
+ sp->sh_info = 0;
+ sp->sh_addralign = 8;
+ sp->sh_entsize = sizeof (Elf64_Dyn);
+
+ (void) memcpy(&elfdata[off], dp, sp->sh_size);
+ off += roundup(sp->sh_size, 8);
+ sp++;
+
+ /*
+ * Section Header[5] sh_name: .plt
+ */
+ if (pltsz != 0) {
+ sp->sh_name = 35;
+ sp->sh_type = SHT_PROGBITS;
+ sp->sh_flags = SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR;
+ sp->sh_addr = d[DI_PLTGOT]->d_un.d_ptr;
+ if (ehdr.e_type == ET_DYN)
+ sp->sh_addr -= addr;
+ sp->sh_offset = off;
+ sp->sh_size = pltsz;
+ sp->sh_link = 0;
+ sp->sh_info = 0;
+ sp->sh_addralign = 8;
+ sp->sh_entsize = pltentsz;
+
+ if (Pread(P, &elfdata[off], sp->sh_size,
+ d[DI_PLTGOT]->d_un.d_ptr) != sp->sh_size) {
+ free(elfdata);
+ goto bad64;
+ }
+ off += roundup(sp->sh_size, 8);
+ sp++;
+ }
+
+ free(dp);
+ goto good;
+
+bad64:
+ free(dp);
+ return (NULL);
+#endif /* _LP64 */
+ }
+good:
+ if ((elf = elf_memory(elfdata, size)) == NULL) {
+ free(elfdata);
+ return (NULL);
+ }
+
+ fptr->file_elfmem = elfdata;
+
+ return (elf);
+}
+
+/*
+ * We wouldn't need these if qsort(3C) took an argument for the callback...
+ */
+static mutex_t sort_mtx = DEFAULTMUTEX;
+static char *sort_strs;
+static GElf_Sym *sort_syms;
+
+int
+byaddr_cmp_common(GElf_Sym *a, char *aname, GElf_Sym *b, char *bname)
+{
+ if (a->st_value < b->st_value)
+ return (-1);
+ if (a->st_value > b->st_value)
+ return (1);
+
+ /*
+ * Prefer the function to the non-function.
+ */
+ if (GELF_ST_TYPE(a->st_info) != GELF_ST_TYPE(b->st_info)) {
+ if (GELF_ST_TYPE(a->st_info) == STT_FUNC)
+ return (-1);
+ if (GELF_ST_TYPE(b->st_info) == STT_FUNC)
+ return (1);
+ }
+
+ /*
+ * Prefer the weak or strong global symbol to the local symbol.
+ */
+ if (GELF_ST_BIND(a->st_info) != GELF_ST_BIND(b->st_info)) {
+ if (GELF_ST_BIND(b->st_info) == STB_LOCAL)
+ return (-1);
+ if (GELF_ST_BIND(a->st_info) == STB_LOCAL)
+ return (1);
+ }
+
+ /*
+ * Prefer the name with fewer leading underscores in the name.
+ */
+ while (*aname == '_' && *bname == '_') {
+ aname++;
+ bname++;
+ }
+
+ if (*bname == '_')
+ return (-1);
+ if (*aname == '_')
+ return (1);
+
+ /*
+ * Prefer the symbol with the smaller size.
+ */
+ if (a->st_size < b->st_size)
+ return (-1);
+ if (a->st_size > b->st_size)
+ return (1);
+
+ /*
+ * All other factors being equal, fall back to lexicographic order.
+ */
+ return (strcmp(aname, bname));
+}
+
+static int
+byaddr_cmp(const void *aa, const void *bb)
+{
+ GElf_Sym *a = &sort_syms[*(uint_t *)aa];
+ GElf_Sym *b = &sort_syms[*(uint_t *)bb];
+ char *aname = sort_strs + a->st_name;
+ char *bname = sort_strs + b->st_name;
+
+ return (byaddr_cmp_common(a, aname, b, bname));
+}
+
+static int
+byname_cmp(const void *aa, const void *bb)
+{
+ GElf_Sym *a = &sort_syms[*(uint_t *)aa];
+ GElf_Sym *b = &sort_syms[*(uint_t *)bb];
+ char *aname = sort_strs + a->st_name;
+ char *bname = sort_strs + b->st_name;
+
+ return (strcmp(aname, bname));
+}
+
+void
+optimize_symtab(sym_tbl_t *symtab)
+{
+ GElf_Sym *symp, *syms;
+ uint_t i, *indexa, *indexb;
+ Elf_Data *data;
+ size_t symn, strsz, count;
+
+ if (symtab == NULL || symtab->sym_data == NULL ||
+ symtab->sym_byaddr != NULL)
+ return;
+
+ data = symtab->sym_data;
+ symn = symtab->sym_symn;
+ strsz = symtab->sym_strsz;
+
+ symp = syms = malloc(sizeof (GElf_Sym) * symn);
+
+ /*
+ * First record all the symbols into a table and count up the ones
+ * that we're interested in. We mark symbols as invalid by setting
+ * the st_name to an illegal value.
+ */
+ for (i = 0, count = 0; i < symn; i++, symp++) {
+ if (gelf_getsym(data, i, symp) != NULL &&
+ symp->st_name < strsz &&
+ IS_DATA_TYPE(GELF_ST_TYPE(symp->st_info)))
+ count++;
+ else
+ symp->st_name = strsz;
+ }
+
+ /*
+ * Allocate sufficient space for both tables and populate them
+ * with the same symbols we just counted.
+ */
+ symtab->sym_count = count;
+ indexa = symtab->sym_byaddr = calloc(sizeof (uint_t), count);
+ indexb = symtab->sym_byname = calloc(sizeof (uint_t), count);
+
+ for (i = 0, symp = syms; i < symn; i++, symp++) {
+ if (symp->st_name < strsz)
+ *indexa++ = *indexb++ = i;
+ }
+
+ /*
+ * Sort the two tables according to the appropriate criteria.
+ */
+ (void) mutex_lock(&sort_mtx);
+ sort_strs = symtab->sym_strs;
+ sort_syms = syms;
+
+ qsort(symtab->sym_byaddr, count, sizeof (uint_t), byaddr_cmp);
+ qsort(symtab->sym_byname, count, sizeof (uint_t), byname_cmp);
+
+ sort_strs = NULL;
+ sort_syms = NULL;
+ (void) mutex_unlock(&sort_mtx);
+
+ free(syms);
+}
+
+/*
+ * Build the symbol table for the given mapped file.
+ */
+void
+Pbuild_file_symtab(struct ps_prochandle *P, file_info_t *fptr)
+{
+ char objectfile[PATH_MAX];
+ uint_t i;
+
+ GElf_Ehdr ehdr;
+ GElf_Sym s;
+
+ Elf_Data *shdata;
+ Elf_Scn *scn;
+ Elf *elf;
+
+ struct {
+ GElf_Shdr c_shdr;
+ Elf_Data *c_data;
+ const char *c_name;
+ } *cp, *cache = NULL, *dyn = NULL, *plt = NULL, *ctf = NULL;
+
+ if (fptr->file_init)
+ return; /* We've already processed this file */
+
+ /*
+ * Mark the file_info struct as having the symbol table initialized
+ * even if we fail below. We tried once; we don't try again.
+ */
+ fptr->file_init = 1;
+
+ if (elf_version(EV_CURRENT) == EV_NONE) {
+ dprintf("libproc ELF version is more recent than libelf\n");
+ return;
+ }
+
+ if (P->state == PS_DEAD || P->state == PS_IDLE) {
+ /*
+ * If we're a not live, we can't open files from the /proc
+ * object directory; we have only the mapping and file names
+ * to guide us. We prefer the file_lname, but need to handle
+ * the case of it being NULL in order to bootstrap: we first
+ * come here during rd_new() when the only information we have
+ * is interpreter name associated with the AT_BASE mapping.
+ */
+ (void) snprintf(objectfile, sizeof (objectfile), "%s",
+ fptr->file_lname ? fptr->file_lname : fptr->file_pname);
+ } else {
+ (void) snprintf(objectfile, sizeof (objectfile),
+ "/proc/%d/object/%s", (int)P->pid, fptr->file_pname);
+ }
+
+ /*
+ * Open the object file, create the elf file, and then get the elf
+ * header and .shstrtab data buffer so we can process sections by
+ * name. If anything goes wrong try to fake up an elf file from
+ * the in-core elf image.
+ */
+ if ((fptr->file_fd = open(objectfile, O_RDONLY)) < 0) {
+ dprintf("Pbuild_file_symtab: failed to open %s: %s\n",
+ objectfile, strerror(errno));
+
+ if ((elf = fake_elf(P, fptr)) == NULL ||
+ elf_kind(elf) != ELF_K_ELF ||
+ gelf_getehdr(elf, &ehdr) == NULL ||
+ (scn = elf_getscn(elf, ehdr.e_shstrndx)) == NULL ||
+ (shdata = elf_getdata(scn, NULL)) == NULL) {
+ dprintf("failed to fake up ELF file\n");
+ return;
+ }
+
+ } else if ((elf = elf_begin(fptr->file_fd, ELF_C_READ, NULL)) == NULL ||
+ elf_kind(elf) != ELF_K_ELF ||
+ gelf_getehdr(elf, &ehdr) == NULL ||
+ (scn = elf_getscn(elf, ehdr.e_shstrndx)) == NULL ||
+ (shdata = elf_getdata(scn, NULL)) == NULL) {
+ dprintf("failed to process ELF file %s: %s\n",
+ objectfile, elf_errmsg(elf_errno()));
+
+ if ((elf = fake_elf(P, fptr)) == NULL ||
+ elf_kind(elf) != ELF_K_ELF ||
+ gelf_getehdr(elf, &ehdr) == NULL ||
+ (scn = elf_getscn(elf, ehdr.e_shstrndx)) == NULL ||
+ (shdata = elf_getdata(scn, NULL)) == NULL) {
+ dprintf("failed to fake up ELF file\n");
+ goto bad;
+ }
+
+ } else if (file_differs(P, elf, fptr)) {
+ Elf *newelf;
+
+ /*
+ * Before we get too excited about this elf file, we'll check
+ * its checksum value against the value we have in memory. If
+ * they don't agree, we try to fake up a new elf file and
+ * proceed with that instead.
+ */
+
+ dprintf("ELF file %s (%lx) doesn't match in-core image\n",
+ fptr->file_pname,
+ (ulong_t)fptr->file_map->map_pmap.pr_vaddr);
+
+ if ((newelf = fake_elf(P, fptr)) == NULL ||
+ elf_kind(newelf) != ELF_K_ELF ||
+ gelf_getehdr(newelf, &ehdr) == NULL ||
+ (scn = elf_getscn(newelf, ehdr.e_shstrndx)) == NULL ||
+ (shdata = elf_getdata(scn, NULL)) == NULL) {
+ dprintf("failed to fake up ELF file\n");
+ } else {
+ (void) elf_end(elf);
+ elf = newelf;
+
+ dprintf("switched to faked up ELF file\n");
+ }
+ }
+
+ if ((cache = malloc(ehdr.e_shnum * sizeof (*cache))) == NULL) {
+ dprintf("failed to malloc section cache for %s\n", objectfile);
+ goto bad;
+ }
+
+ dprintf("processing ELF file %s\n", objectfile);
+ fptr->file_class = ehdr.e_ident[EI_CLASS];
+ fptr->file_etype = ehdr.e_type;
+ fptr->file_elf = elf;
+
+ /*
+ * Iterate through each section, caching its section header, data
+ * pointer, and name. We use this for handling sh_link values below.
+ */
+ for (cp = cache + 1, scn = NULL; scn = elf_nextscn(elf, scn); cp++) {
+ if (gelf_getshdr(scn, &cp->c_shdr) == NULL)
+ goto bad; /* Failed to get section header */
+
+ if ((cp->c_data = elf_getdata(scn, NULL)) == NULL)
+ goto bad; /* Failed to get section data */
+
+ if (cp->c_shdr.sh_name >= shdata->d_size)
+ goto bad; /* Corrupt section name */
+
+ cp->c_name = (const char *)shdata->d_buf + cp->c_shdr.sh_name;
+ }
+
+ /*
+ * Now iterate through the section cache in order to locate info
+ * for the .symtab, .dynsym, .dynamic, .plt, and .SUNW_ctf sections:
+ */
+ for (i = 1, cp = cache + 1; i < ehdr.e_shnum; i++, cp++) {
+ GElf_Shdr *shp = &cp->c_shdr;
+
+ if (shp->sh_type == SHT_SYMTAB || shp->sh_type == SHT_DYNSYM) {
+ sym_tbl_t *symp = shp->sh_type == SHT_SYMTAB ?
+ &fptr->file_symtab : &fptr->file_dynsym;
+
+ /*
+ * It's possible that the we already got the symbol
+ * table from the core file itself. Either the file
+ * differs in which case our faked up elf file will
+ * only contain the dynsym (not the symtab) or the
+ * file matches in which case we'll just be replacing
+ * the symbol table we pulled out of the core file
+ * with an equivalent one. In either case, this
+ * check isn't essential, but it's a good idea.
+ */
+ if (symp->sym_data == NULL) {
+ symp->sym_data = cp->c_data;
+ symp->sym_symn = shp->sh_size / shp->sh_entsize;
+ symp->sym_strs =
+ cache[shp->sh_link].c_data->d_buf;
+ symp->sym_strsz =
+ cache[shp->sh_link].c_data->d_size;
+ symp->sym_hdr = cp->c_shdr;
+ symp->sym_strhdr = cache[shp->sh_link].c_shdr;
+ }
+
+ } else if (shp->sh_type == SHT_DYNAMIC) {
+ dyn = cp;
+
+ } else if (strcmp(cp->c_name, ".plt") == 0) {
+ plt = cp;
+
+ } else if (strcmp(cp->c_name, ".SUNW_ctf") == 0) {
+ /*
+ * Skip over bogus CTF sections so they don't come back
+ * to haunt us later.
+ */
+ if (shp->sh_link == 0 ||
+ shp->sh_link > ehdr.e_shnum ||
+ (cache[shp->sh_link].c_shdr.sh_type != SHT_DYNSYM &&
+ cache[shp->sh_link].c_shdr.sh_type != SHT_SYMTAB)) {
+ dprintf("Bad sh_link %d for "
+ "CTF\n", shp->sh_link);
+ continue;
+ }
+ ctf = cp;
+ }
+ }
+
+ /*
+ * At this point, we've found all the symbol tables we're ever going
+ * to find: the ones in the loop above and possibly the symtab that
+ * was included in the core file. Before we perform any lookups, we
+ * create sorted versions to optimize for lookups.
+ */
+ optimize_symtab(&fptr->file_symtab);
+ optimize_symtab(&fptr->file_dynsym);
+
+ /*
+ * Fill in the base address of the text mapping for shared libraries.
+ * This allows us to translate symbols before librtld_db is ready.
+ */
+ if (fptr->file_etype == ET_DYN) {
+ fptr->file_dyn_base = fptr->file_map->map_pmap.pr_vaddr -
+ fptr->file_map->map_pmap.pr_offset;
+ dprintf("setting file_dyn_base for %s to %p\n",
+ objectfile, (void *)fptr->file_dyn_base);
+ }
+
+ /*
+ * Record the CTF section information in the file info structure.
+ */
+ if (ctf != NULL) {
+ fptr->file_ctf_off = ctf->c_shdr.sh_offset;
+ fptr->file_ctf_size = ctf->c_shdr.sh_size;
+ if (ctf->c_shdr.sh_link != 0 &&
+ cache[ctf->c_shdr.sh_link].c_shdr.sh_type == SHT_DYNSYM)
+ fptr->file_ctf_dyn = 1;
+ }
+
+ if (fptr->file_lo == NULL)
+ goto done; /* Nothing else to do if no load object info */
+
+ /*
+ * If the object is a shared library and we have a different rl_base
+ * value, reset file_dyn_base according to librtld_db's information.
+ */
+ if (fptr->file_etype == ET_DYN &&
+ fptr->file_lo->rl_base != fptr->file_dyn_base) {
+ dprintf("resetting file_dyn_base for %s to %p\n",
+ objectfile, (void *)fptr->file_lo->rl_base);
+ fptr->file_dyn_base = fptr->file_lo->rl_base;
+ }
+
+ /*
+ * Fill in the PLT information for this file if a PLT symbol is found.
+ */
+ if (sym_by_name(&fptr->file_dynsym, "_PROCEDURE_LINKAGE_TABLE_", &s,
+ NULL) != NULL) {
+ fptr->file_plt_base = s.st_value + fptr->file_dyn_base;
+ fptr->file_plt_size = (plt != NULL) ? plt->c_shdr.sh_size : 0;
+
+ /*
+ * Bring the load object up to date; it is the only way the
+ * user has to access the PLT data. The PLT information in the
+ * rd_loadobj_t is not set in the call to map_iter() (the
+ * callback for rd_loadobj_iter) where we set file_lo.
+ */
+ fptr->file_lo->rl_plt_base = fptr->file_plt_base;
+ fptr->file_lo->rl_plt_size = fptr->file_plt_size;
+
+ dprintf("PLT found at %p, size = %lu\n",
+ (void *)fptr->file_plt_base, (ulong_t)fptr->file_plt_size);
+ }
+
+ /*
+ * Fill in the PLT information.
+ */
+ if (dyn != NULL) {
+ uintptr_t dynaddr = dyn->c_shdr.sh_addr + fptr->file_dyn_base;
+ size_t ndyn = dyn->c_shdr.sh_size / dyn->c_shdr.sh_entsize;
+ GElf_Dyn d;
+
+ for (i = 0; i < ndyn; i++) {
+ if (gelf_getdyn(dyn->c_data, i, &d) != NULL &&
+ d.d_tag == DT_JMPREL) {
+ fptr->file_jmp_rel =
+ d.d_un.d_ptr + fptr->file_dyn_base;
+ break;
+ }
+ }
+
+ dprintf("_DYNAMIC found at %p, %lu entries, DT_JMPREL = %p\n",
+ (void *)dynaddr, (ulong_t)ndyn, (void *)fptr->file_jmp_rel);
+ }
+
+done:
+ free(cache);
+ return;
+
+bad:
+ if (cache != NULL)
+ free(cache);
+
+ (void) elf_end(elf);
+ fptr->file_elf = NULL;
+ if (fptr->file_elfmem != NULL) {
+ free(fptr->file_elfmem);
+ fptr->file_elfmem = NULL;
+ }
+ (void) close(fptr->file_fd);
+ fptr->file_fd = -1;
+}
+
+/*
+ * Given a process virtual address, return the map_info_t containing it.
+ * If none found, return NULL.
+ */
+map_info_t *
+Paddr2mptr(struct ps_prochandle *P, uintptr_t addr)
+{
+ int lo = 0;
+ int hi = P->map_count - 1;
+ int mid;
+ map_info_t *mp;
+
+ while (lo <= hi) {
+
+ mid = (lo + hi) / 2;
+ mp = &P->mappings[mid];
+
+ /* check that addr is in [vaddr, vaddr + size) */
+ if ((addr - mp->map_pmap.pr_vaddr) < mp->map_pmap.pr_size)
+ return (mp);
+
+ if (addr < mp->map_pmap.pr_vaddr)
+ hi = mid - 1;
+ else
+ lo = mid + 1;
+ }
+
+ return (NULL);
+}
+
+/*
+ * Return the map_info_t for the executable file.
+ * If not found, return NULL.
+ */
+static map_info_t *
+exec_map(struct ps_prochandle *P)
+{
+ uint_t i;
+ map_info_t *mptr;
+ map_info_t *mold = NULL;
+ file_info_t *fptr;
+ uintptr_t base;
+
+ for (i = 0, mptr = P->mappings; i < P->map_count; i++, mptr++) {
+ if (mptr->map_pmap.pr_mapname[0] == '\0')
+ continue;
+ if (strcmp(mptr->map_pmap.pr_mapname, "a.out") == 0) {
+ if ((fptr = mptr->map_file) != NULL &&
+ fptr->file_lo != NULL) {
+ base = fptr->file_lo->rl_base;
+ if (base >= mptr->map_pmap.pr_vaddr &&
+ base < mptr->map_pmap.pr_vaddr +
+ mptr->map_pmap.pr_size) /* text space */
+ return (mptr);
+ mold = mptr; /* must be the data */
+ continue;
+ }
+ /* This is a poor way to test for text space */
+ if (!(mptr->map_pmap.pr_mflags & MA_EXEC) ||
+ (mptr->map_pmap.pr_mflags & MA_WRITE)) {
+ mold = mptr;
+ continue;
+ }
+ return (mptr);
+ }
+ }
+
+ return (mold);
+}
+
+/*
+ * Given a shared object name, return the map_info_t for it. If no matching
+ * object is found, return NULL. Normally, the link maps contain the full
+ * object pathname, e.g. /usr/lib/libc.so.1. We allow the object name to
+ * take one of the following forms:
+ *
+ * 1. An exact match (i.e. a full pathname): "/usr/lib/libc.so.1"
+ * 2. An exact basename match: "libc.so.1"
+ * 3. An initial basename match up to a '.' suffix: "libc.so" or "libc"
+ * 4. The literal string "a.out" is an alias for the executable mapping
+ *
+ * The third case is a convenience for callers and may not be necessary.
+ *
+ * As the exact same object name may be loaded on different link maps (see
+ * dlmopen(3DL)), we also allow the caller to resolve the object name by
+ * specifying a particular link map id. If lmid is PR_LMID_EVERY, the
+ * first matching name will be returned, regardless of the link map id.
+ */
+static map_info_t *
+object_to_map(struct ps_prochandle *P, Lmid_t lmid, const char *objname)
+{
+ map_info_t *mp;
+ file_info_t *fp;
+ size_t objlen;
+ uint_t i;
+
+ /*
+ * First pass: look for exact matches of the entire pathname or
+ * basename (cases 1 and 2 above):
+ */
+ for (i = 0, mp = P->mappings; i < P->map_count; i++, mp++) {
+
+ if (mp->map_pmap.pr_mapname[0] == '\0' ||
+ (fp = mp->map_file) == NULL || fp->file_lname == NULL)
+ continue;
+
+ if (lmid != PR_LMID_EVERY &&
+ (fp->file_lo == NULL || lmid != fp->file_lo->rl_lmident))
+ continue;
+
+ /*
+ * If we match, return the primary text mapping; otherwise
+ * just return the mapping we matched.
+ */
+ if (strcmp(fp->file_lname, objname) == 0 ||
+ strcmp(fp->file_lbase, objname) == 0)
+ return (fp->file_map ? fp->file_map : mp);
+ }
+
+ objlen = strlen(objname);
+
+ /*
+ * Second pass: look for partial matches (case 3 above):
+ */
+ for (i = 0, mp = P->mappings; i < P->map_count; i++, mp++) {
+
+ if (mp->map_pmap.pr_mapname[0] == '\0' ||
+ (fp = mp->map_file) == NULL || fp->file_lname == NULL)
+ continue;
+
+ if (lmid != PR_LMID_EVERY &&
+ (fp->file_lo == NULL || lmid != fp->file_lo->rl_lmident))
+ continue;
+
+ /*
+ * If we match, return the primary text mapping; otherwise
+ * just return the mapping we matched.
+ */
+ if (strncmp(fp->file_lbase, objname, objlen) == 0 &&
+ fp->file_lbase[objlen] == '.')
+ return (fp->file_map ? fp->file_map : mp);
+ }
+
+ /*
+ * One last check: we allow "a.out" to always alias the executable,
+ * assuming this name was not in use for something else.
+ */
+ if ((lmid == PR_LMID_EVERY || lmid == LM_ID_BASE) &&
+ (strcmp(objname, "a.out") == 0))
+ return (P->map_exec);
+
+ return (NULL);
+}
+
+static map_info_t *
+object_name_to_map(struct ps_prochandle *P, Lmid_t lmid, const char *name)
+{
+ map_info_t *mptr;
+
+ if (!P->info_valid)
+ Pupdate_maps(P);
+
+ if (P->map_exec == NULL && ((mptr = Paddr2mptr(P,
+ Pgetauxval(P, AT_ENTRY))) != NULL || (mptr = exec_map(P)) != NULL))
+ P->map_exec = mptr;
+
+ if (P->map_ldso == NULL && (mptr = Paddr2mptr(P,
+ Pgetauxval(P, AT_BASE))) != NULL)
+ P->map_ldso = mptr;
+
+ if (name == PR_OBJ_EXEC)
+ mptr = P->map_exec;
+ else if (name == PR_OBJ_LDSO)
+ mptr = P->map_ldso;
+ else if (Prd_agent(P) != NULL || P->state == PS_IDLE)
+ mptr = object_to_map(P, lmid, name);
+ else
+ mptr = NULL;
+
+ return (mptr);
+}
+
+/*
+ * When two symbols are found by address, decide which one is to be preferred.
+ */
+static GElf_Sym *
+sym_prefer(GElf_Sym *sym1, char *name1, GElf_Sym *sym2, char *name2)
+{
+ /*
+ * Prefer the non-NULL symbol.
+ */
+ if (sym1 == NULL)
+ return (sym2);
+ if (sym2 == NULL)
+ return (sym1);
+
+ /*
+ * Defer to the sort ordering...
+ */
+ return (byaddr_cmp_common(sym1, name1, sym2, name2) <= 0 ? sym1 : sym2);
+}
+
+/*
+ * Look up a symbol by address in the specified symbol table.
+ * Adjustment to 'addr' must already have been made for the
+ * offset of the symbol if this is a dynamic library symbol table.
+ */
+static GElf_Sym *
+sym_by_addr(sym_tbl_t *symtab, GElf_Addr addr, GElf_Sym *symp, uint_t *idp)
+{
+ Elf_Data *data = symtab->sym_data;
+ GElf_Sym sym, osym;
+ uint_t i, oid, *byaddr = symtab->sym_byaddr;
+ int min, max, mid, omid, found = 0;
+
+ if (data == NULL)
+ return (NULL);
+
+ min = 0;
+ max = symtab->sym_count - 1;
+ osym.st_value = 0;
+
+ /*
+ * We can't return when we've found a match, we have to continue
+ * searching for the closest matching symbol.
+ */
+ while (min <= max) {
+ mid = (max + min) / 2;
+
+ i = byaddr[mid];
+ (void) gelf_getsym(data, i, &sym);
+
+ if (addr >= sym.st_value &&
+ addr < sym.st_value + sym.st_size &&
+ (!found || sym.st_value > osym.st_value)) {
+ osym = sym;
+ omid = mid;
+ oid = i;
+ found = 1;
+ }
+
+ if (addr < sym.st_value)
+ max = mid - 1;
+ else
+ min = mid + 1;
+ }
+
+ if (!found)
+ return (NULL);
+
+ /*
+ * There may be many symbols with identical values so we walk
+ * backward in the byaddr table to find the best match.
+ */
+ do {
+ sym = osym;
+ i = oid;
+
+ if (omid == 0)
+ break;
+
+ oid = byaddr[--omid];
+ (void) gelf_getsym(data, oid, &osym);
+ } while (addr >= osym.st_value &&
+ addr < sym.st_value + osym.st_size &&
+ osym.st_value == sym.st_value);
+
+ *symp = sym;
+ if (idp != NULL)
+ *idp = i;
+ return (symp);
+}
+
+/*
+ * Look up a symbol by name in the specified symbol table.
+ */
+static GElf_Sym *
+sym_by_name(sym_tbl_t *symtab, const char *name, GElf_Sym *symp, uint_t *idp)
+{
+ Elf_Data *data = symtab->sym_data;
+ char *strs = symtab->sym_strs;
+ uint_t i, *byname = symtab->sym_byname;
+ int min, mid, max, cmp;
+
+ if (data == NULL || strs == NULL)
+ return (NULL);
+
+ min = 0;
+ max = symtab->sym_count - 1;
+
+ while (min <= max) {
+ mid = (max + min) / 2;
+
+ i = byname[mid];
+ (void) gelf_getsym(data, i, symp);
+
+ if ((cmp = strcmp(name, strs + symp->st_name)) == 0) {
+ if (idp != NULL)
+ *idp = i;
+ return (symp);
+ }
+
+ if (cmp < 0)
+ max = mid - 1;
+ else
+ min = mid + 1;
+ }
+
+ return (NULL);
+}
+
+/*
+ * Search the process symbol tables looking for a symbol whose
+ * value to value+size contain the address specified by addr.
+ * Return values are:
+ * sym_name_buffer containing the symbol name
+ * GElf_Sym symbol table entry
+ * prsyminfo_t ancillary symbol information
+ * Returns 0 on success, -1 on failure.
+ */
+int
+Pxlookup_by_addr(
+ struct ps_prochandle *P,
+ uintptr_t addr, /* process address being sought */
+ char *sym_name_buffer, /* buffer for the symbol name */
+ size_t bufsize, /* size of sym_name_buffer */
+ GElf_Sym *symbolp, /* returned symbol table entry */
+ prsyminfo_t *sip) /* returned symbol info */
+{
+ GElf_Sym *symp;
+ char *name;
+ GElf_Sym sym1, *sym1p = NULL;
+ GElf_Sym sym2, *sym2p = NULL;
+ char *name1 = NULL;
+ char *name2 = NULL;
+ uint_t i1;
+ uint_t i2;
+ map_info_t *mptr;
+ file_info_t *fptr;
+
+ (void) Prd_agent(P);
+
+ if ((mptr = Paddr2mptr(P, addr)) == NULL || /* no such address */
+ (fptr = build_map_symtab(P, mptr)) == NULL || /* no mapped file */
+ fptr->file_elf == NULL) /* not an ELF file */
+ return (-1);
+
+ /*
+ * Adjust the address by the load object base address in
+ * case the address turns out to be in a shared library.
+ */
+ addr -= fptr->file_dyn_base;
+
+ /*
+ * Search both symbol tables, symtab first, then dynsym.
+ */
+ if ((sym1p = sym_by_addr(&fptr->file_symtab, addr, &sym1, &i1)) != NULL)
+ name1 = fptr->file_symtab.sym_strs + sym1.st_name;
+ if ((sym2p = sym_by_addr(&fptr->file_dynsym, addr, &sym2, &i2)) != NULL)
+ name2 = fptr->file_dynsym.sym_strs + sym2.st_name;
+
+ if ((symp = sym_prefer(sym1p, name1, sym2p, name2)) == NULL)
+ return (-1);
+
+ name = (symp == sym1p) ? name1 : name2;
+ if (bufsize > 0) {
+ (void) strncpy(sym_name_buffer, name, bufsize);
+ sym_name_buffer[bufsize - 1] = '\0';
+ }
+
+ *symbolp = *symp;
+ if (sip != NULL) {
+ sip->prs_name = bufsize == 0 ? NULL : sym_name_buffer;
+ sip->prs_object = fptr->file_lbase;
+ sip->prs_id = (symp == sym1p) ? i1 : i2;
+ sip->prs_table = (symp == sym1p) ? PR_SYMTAB : PR_DYNSYM;
+ sip->prs_lmid = (fptr->file_lo == NULL) ? LM_ID_BASE :
+ fptr->file_lo->rl_lmident;
+ }
+
+ if (GELF_ST_TYPE(symbolp->st_info) != STT_TLS)
+ symbolp->st_value += fptr->file_dyn_base;
+
+ return (0);
+}
+
+int
+Plookup_by_addr(struct ps_prochandle *P, uintptr_t addr, char *buf, size_t size,
+ GElf_Sym *symp)
+{
+ return (Pxlookup_by_addr(P, addr, buf, size, symp, NULL));
+}
+
+/*
+ * Search the process symbol tables looking for a symbol whose name matches the
+ * specified name and whose object and link map optionally match the specified
+ * parameters. On success, the function returns 0 and fills in the GElf_Sym
+ * symbol table entry. On failure, -1 is returned.
+ */
+int
+Pxlookup_by_name(
+ struct ps_prochandle *P,
+ Lmid_t lmid, /* link map to match, or -1 for any */
+ const char *oname, /* load object name */
+ const char *sname, /* symbol name */
+ GElf_Sym *symp, /* returned symbol table entry */
+ prsyminfo_t *sip) /* returned symbol info */
+{
+ map_info_t *mptr;
+ file_info_t *fptr;
+ int cnt;
+
+ GElf_Sym sym;
+ prsyminfo_t si;
+ int rv = -1;
+ uint_t id;
+
+ if (oname == PR_OBJ_EVERY) {
+ /* create all the file_info_t's for all the mappings */
+ (void) Prd_agent(P);
+ cnt = P->num_files;
+ fptr = list_next(&P->file_head);
+ } else {
+ cnt = 1;
+ if ((mptr = object_name_to_map(P, lmid, oname)) == NULL ||
+ (fptr = build_map_symtab(P, mptr)) == NULL)
+ return (-1);
+ }
+
+ /*
+ * Iterate through the loaded object files and look for the symbol
+ * name in the .symtab and .dynsym of each. If we encounter a match
+ * with SHN_UNDEF, keep looking in hopes of finding a better match.
+ * This means that a name such as "puts" will match the puts function
+ * in libc instead of matching the puts PLT entry in the a.out file.
+ */
+ for (; cnt > 0; cnt--, fptr = list_next(fptr)) {
+ Pbuild_file_symtab(P, fptr);
+
+ if (fptr->file_elf == NULL)
+ continue;
+
+ if (lmid != PR_LMID_EVERY && fptr->file_lo != NULL &&
+ lmid != fptr->file_lo->rl_lmident)
+ continue;
+
+ if (fptr->file_symtab.sym_data != NULL &&
+ sym_by_name(&fptr->file_symtab, sname, symp, &id)) {
+ if (sip != NULL) {
+ sip->prs_id = id;
+ sip->prs_table = PR_SYMTAB;
+ sip->prs_object = oname;
+ sip->prs_name = sname;
+ sip->prs_lmid = fptr->file_lo == NULL ?
+ LM_ID_BASE : fptr->file_lo->rl_lmident;
+ }
+ } else if (fptr->file_dynsym.sym_data != NULL &&
+ sym_by_name(&fptr->file_dynsym, sname, symp, &id)) {
+ if (sip != NULL) {
+ sip->prs_id = id;
+ sip->prs_table = PR_DYNSYM;
+ sip->prs_object = oname;
+ sip->prs_name = sname;
+ sip->prs_lmid = fptr->file_lo == NULL ?
+ LM_ID_BASE : fptr->file_lo->rl_lmident;
+ }
+ } else {
+ continue;
+ }
+
+ if (GELF_ST_TYPE(symp->st_info) != STT_TLS)
+ symp->st_value += fptr->file_dyn_base;
+
+ if (symp->st_shndx != SHN_UNDEF)
+ return (0);
+
+ if (rv != 0) {
+ if (sip != NULL)
+ si = *sip;
+ sym = *symp;
+ rv = 0;
+ }
+ }
+
+ if (rv == 0) {
+ if (sip != NULL)
+ *sip = si;
+ *symp = sym;
+ }
+
+ return (rv);
+}
+
+/*
+ * Search the process symbol tables looking for a symbol whose name matches the
+ * specified name, but without any restriction on the link map id.
+ */
+int
+Plookup_by_name(struct ps_prochandle *P, const char *object,
+ const char *symbol, GElf_Sym *symp)
+{
+ return (Pxlookup_by_name(P, PR_LMID_EVERY, object, symbol, symp, NULL));
+}
+
+/*
+ * Iterate over the process's address space mappings.
+ */
+int
+Pmapping_iter(struct ps_prochandle *P, proc_map_f *func, void *cd)
+{
+ map_info_t *mptr;
+ file_info_t *fptr;
+ char *object_name;
+ int rc = 0;
+ int i;
+
+ /* create all the file_info_t's for all the mappings */
+ (void) Prd_agent(P);
+
+ for (i = 0, mptr = P->mappings; i < P->map_count; i++, mptr++) {
+ if ((fptr = mptr->map_file) == NULL)
+ object_name = NULL;
+ else
+ object_name = fptr->file_lname;
+ if ((rc = func(cd, &mptr->map_pmap, object_name)) != 0)
+ return (rc);
+ }
+ return (0);
+}
+
+/*
+ * Iterate over the process's mapped objects.
+ */
+int
+Pobject_iter(struct ps_prochandle *P, proc_map_f *func, void *cd)
+{
+ map_info_t *mptr;
+ file_info_t *fptr;
+ uint_t cnt;
+ int rc = 0;
+
+ (void) Prd_agent(P); /* create file_info_t's for all the mappings */
+ Pupdate_maps(P);
+
+ for (cnt = P->num_files, fptr = list_next(&P->file_head);
+ cnt; cnt--, fptr = list_next(fptr)) {
+
+ const char *lname = fptr->file_lname ? fptr->file_lname : "";
+
+ if ((mptr = fptr->file_map) == NULL)
+ continue;
+
+ if ((rc = func(cd, &mptr->map_pmap, lname)) != 0)
+ return (rc);
+ }
+ return (0);
+}
+
+/*
+ * Given a virtual address, return the name of the underlying
+ * mapped object (file), as provided by the dynamic linker.
+ * Return NULL on failure (no underlying shared library).
+ */
+char *
+Pobjname(struct ps_prochandle *P, uintptr_t addr,
+ char *buffer, size_t bufsize)
+{
+ map_info_t *mptr;
+ file_info_t *fptr;
+
+ /* create all the file_info_t's for all the mappings */
+ (void) Prd_agent(P);
+
+ if ((mptr = Paddr2mptr(P, addr)) != NULL &&
+ (fptr = mptr->map_file) != NULL &&
+ fptr->file_lname != NULL) {
+ (void) strncpy(buffer, fptr->file_lname, bufsize);
+ if (strlen(fptr->file_lname) >= bufsize)
+ buffer[bufsize-1] = '\0';
+ return (buffer);
+ }
+ return (NULL);
+}
+
+/*
+ * Given a virtual address, return the link map id of the underlying mapped
+ * object (file), as provided by the dynamic linker. Return -1 on failure.
+ */
+int
+Plmid(struct ps_prochandle *P, uintptr_t addr, Lmid_t *lmidp)
+{
+ map_info_t *mptr;
+ file_info_t *fptr;
+
+ /* create all the file_info_t's for all the mappings */
+ (void) Prd_agent(P);
+
+ if ((mptr = Paddr2mptr(P, addr)) != NULL &&
+ (fptr = mptr->map_file) != NULL && fptr->file_lo != NULL) {
+ *lmidp = fptr->file_lo->rl_lmident;
+ return (0);
+ }
+
+ return (-1);
+}
+
+/*
+ * Given an object name and optional lmid, iterate over the object's symbols.
+ * If which == PR_SYMTAB, search the normal symbol table.
+ * If which == PR_DYNSYM, search the dynamic symbol table.
+ */
+static int
+Psymbol_iter_com(struct ps_prochandle *P, Lmid_t lmid, const char *object_name,
+ int which, int mask, pr_order_t order, proc_xsym_f *func, void *cd)
+{
+ GElf_Sym sym;
+ map_info_t *mptr;
+ file_info_t *fptr;
+ sym_tbl_t *symtab;
+ Elf_Data *data;
+ size_t symn;
+ const char *strs;
+ size_t strsz;
+ prsyminfo_t si;
+ int rv;
+ uint_t *map, i, count, ndx;
+
+ if ((mptr = object_name_to_map(P, lmid, object_name)) == NULL)
+ return (-1);
+
+ if ((fptr = build_map_symtab(P, mptr)) == NULL || /* no mapped file */
+ fptr->file_elf == NULL) /* not an ELF file */
+ return (-1);
+
+ /*
+ * Search the specified symbol table.
+ */
+ switch (which) {
+ case PR_SYMTAB:
+ symtab = &fptr->file_symtab;
+ si.prs_table = PR_SYMTAB;
+ break;
+ case PR_DYNSYM:
+ symtab = &fptr->file_dynsym;
+ si.prs_table = PR_DYNSYM;
+ break;
+ default:
+ return (-1);
+ }
+
+ si.prs_object = object_name;
+ si.prs_lmid = fptr->file_lo == NULL ?
+ LM_ID_BASE : fptr->file_lo->rl_lmident;
+
+ data = symtab->sym_data;
+ symn = symtab->sym_symn;
+ strs = symtab->sym_strs;
+ strsz = symtab->sym_strsz;
+
+ if (data == NULL || strs == NULL)
+ return (-1);
+
+ switch (order) {
+ case PRO_NATURAL:
+ map = NULL;
+ count = symn;
+ break;
+ case PRO_BYNAME:
+ map = symtab->sym_byname;
+ count = symtab->sym_count;
+ break;
+ case PRO_BYADDR:
+ map = symtab->sym_byaddr;
+ count = symtab->sym_count;
+ break;
+ default:
+ return (-1);
+ }
+
+ rv = 0;
+
+ for (i = 0; i < count; i++) {
+ ndx = map == NULL ? i : map[i];
+ if (gelf_getsym(data, ndx, &sym) != NULL) {
+ uint_t s_bind, s_type, type;
+
+ if (sym.st_name >= strsz) /* invalid st_name */
+ continue;
+
+ s_bind = GELF_ST_BIND(sym.st_info);
+ s_type = GELF_ST_TYPE(sym.st_info);
+
+ /*
+ * In case you haven't already guessed, this relies on
+ * the bitmask used in <libproc.h> for encoding symbol
+ * type and binding matching the order of STB and STT
+ * constants in <sys/elf.h>. ELF can't change without
+ * breaking binary compatibility, so I think this is
+ * reasonably fair game.
+ */
+ if (s_bind < STB_NUM && s_type < STT_NUM) {
+ type = (1 << (s_type + 8)) | (1 << s_bind);
+ if ((type & ~mask) != 0)
+ continue;
+ } else
+ continue; /* Invalid type or binding */
+
+ if (GELF_ST_TYPE(sym.st_info) != STT_TLS)
+ sym.st_value += fptr->file_dyn_base;
+
+ si.prs_name = strs + sym.st_name;
+ si.prs_id = ndx;
+ if ((rv = func(cd, &sym, strs + sym.st_name, &si)) != 0)
+ break;
+ }
+ }
+
+ return (rv);
+}
+
+int
+Pxsymbol_iter(struct ps_prochandle *P, Lmid_t lmid, const char *object_name,
+ int which, int mask, proc_xsym_f *func, void *cd)
+{
+ return (Psymbol_iter_com(P, lmid, object_name, which, mask,
+ PRO_NATURAL, func, cd));
+}
+
+int
+Psymbol_iter_by_lmid(struct ps_prochandle *P, Lmid_t lmid,
+ const char *object_name, int which, int mask, proc_sym_f *func, void *cd)
+{
+ return (Psymbol_iter_com(P, lmid, object_name, which, mask,
+ PRO_NATURAL, (proc_xsym_f *)func, cd));
+}
+
+int
+Psymbol_iter(struct ps_prochandle *P,
+ const char *object_name, int which, int mask, proc_sym_f *func, void *cd)
+{
+ return (Psymbol_iter_com(P, PR_LMID_EVERY, object_name, which, mask,
+ PRO_NATURAL, (proc_xsym_f *)func, cd));
+}
+
+int
+Psymbol_iter_by_addr(struct ps_prochandle *P,
+ const char *object_name, int which, int mask, proc_sym_f *func, void *cd)
+{
+ return (Psymbol_iter_com(P, PR_LMID_EVERY, object_name, which, mask,
+ PRO_BYADDR, (proc_xsym_f *)func, cd));
+}
+
+int
+Psymbol_iter_by_name(struct ps_prochandle *P,
+ const char *object_name, int which, int mask, proc_sym_f *func, void *cd)
+{
+ return (Psymbol_iter_com(P, PR_LMID_EVERY, object_name, which, mask,
+ PRO_BYNAME, (proc_xsym_f *)func, cd));
+}
+
+/*
+ * 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.
+ */
+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);
+}
+
+/*
+ * 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.
+ */
+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));
+}
+
+/*
+ * Get the zone name from the core file if we have it; look up the
+ * name based on the zone id if this is a live process.
+ */
+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);
+}
+
+/*
+ * Called from Pcreate(), Pgrab(), and Pfgrab_core() to initialize
+ * the symbol table heads in the new ps_prochandle.
+ */
+void
+Pinitsym(struct ps_prochandle *P)
+{
+ P->num_files = 0;
+ list_link(&P->file_head, NULL);
+}
+
+/*
+ * Called from Prelease() to destroy the symbol tables.
+ * Must be called by the client after an exec() in the victim process.
+ */
+void
+Preset_maps(struct ps_prochandle *P)
+{
+ int i;
+
+ if (P->rap != NULL) {
+ rd_delete(P->rap);
+ P->rap = NULL;
+ }
+
+ if (P->execname != NULL) {
+ free(P->execname);
+ P->execname = NULL;
+ }
+
+ if (P->auxv != NULL) {
+ free(P->auxv);
+ P->auxv = NULL;
+ P->nauxv = 0;
+ }
+
+ for (i = 0; i < P->map_count; i++)
+ map_info_free(P, &P->mappings[i]);
+
+ if (P->mappings != NULL) {
+ free(P->mappings);
+ P->mappings = NULL;
+ }
+ P->map_count = P->map_alloc = 0;
+
+ P->info_valid = 0;
+}
+
+typedef struct getenv_data {
+ char *buf;
+ size_t bufsize;
+ const char *search;
+ size_t searchlen;
+} getenv_data_t;
+
+/*ARGSUSED*/
+static int
+getenv_func(void *data, struct ps_prochandle *P, uintptr_t addr,
+ const char *nameval)
+{
+ getenv_data_t *d = data;
+ size_t len;
+
+ if (nameval == NULL)
+ return (0);
+
+ if (d->searchlen < strlen(nameval) &&
+ strncmp(nameval, d->search, d->searchlen) == 0 &&
+ nameval[d->searchlen] == '=') {
+ len = MIN(strlen(nameval), d->bufsize - 1);
+ (void) strncpy(d->buf, nameval, len);
+ d->buf[len] = '\0';
+ return (1);
+ }
+
+ return (0);
+}
+
+char *
+Pgetenv(struct ps_prochandle *P, const char *name, char *buf, size_t buflen)
+{
+ getenv_data_t d;
+
+ d.buf = buf;
+ d.bufsize = buflen;
+ d.search = name;
+ d.searchlen = strlen(name);
+
+ if (Penv_iter(P, getenv_func, &d) == 1) {
+ char *equals = strchr(d.buf, '=');
+
+ if (equals != NULL) {
+ (void) memmove(d.buf, equals + 1,
+ d.buf + buflen - equals - 1);
+ d.buf[d.buf + buflen - equals] = '\0';
+
+ return (buf);
+ }
+ }
+
+ return (NULL);
+}
+
+/* number of argument or environment pointers to read all at once */
+#define NARG 100
+
+int
+Penv_iter(struct ps_prochandle *P, proc_env_f *func, void *data)
+{
+ const psinfo_t *psp;
+ uintptr_t envpoff;
+ GElf_Sym sym;
+ int ret;
+ char *buf, *nameval;
+ size_t buflen;
+
+ int nenv = NARG;
+ long envp[NARG];
+
+ /*
+ * Attempt to find the "_environ" variable in the process.
+ * Failing that, use the original value provided by Ppsinfo().
+ */
+ if ((psp = Ppsinfo(P)) == NULL)
+ return (-1);
+
+ envpoff = psp->pr_envp; /* Default if no _environ found */
+
+ if (Plookup_by_name(P, PR_OBJ_EXEC, "_environ", &sym) == 0) {
+ if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
+ if (Pread(P, &envpoff, sizeof (envpoff),
+ sym.st_value) != sizeof (envpoff))
+ envpoff = psp->pr_envp;
+ } else if (P->status.pr_dmodel == PR_MODEL_ILP32) {
+ uint32_t envpoff32;
+
+ if (Pread(P, &envpoff32, sizeof (envpoff32),
+ sym.st_value) != sizeof (envpoff32))
+ envpoff = psp->pr_envp;
+ else
+ envpoff = envpoff32;
+ }
+ }
+
+ buflen = 128;
+ buf = malloc(buflen);
+
+ ret = 0;
+ for (;;) {
+ uintptr_t envoff;
+
+ if (nenv == NARG) {
+ (void) memset(envp, 0, sizeof (envp));
+ if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
+ if (Pread(P, envp,
+ sizeof (envp), envpoff) <= 0) {
+ ret = -1;
+ break;
+ }
+ } else if (P->status.pr_dmodel == PR_MODEL_ILP32) {
+ uint32_t e32[NARG];
+ int i;
+
+ (void) memset(e32, 0, sizeof (e32));
+ if (Pread(P, e32, sizeof (e32), envpoff) <= 0) {
+ ret = -1;
+ break;
+ }
+ for (i = 0; i < NARG; i++)
+ envp[i] = e32[i];
+ }
+ nenv = 0;
+ }
+
+ if ((envoff = envp[nenv++]) == NULL)
+ break;
+
+ /*
+ * Attempt to read the string from the process.
+ */
+again:
+ ret = Pread_string(P, buf, buflen, envoff);
+
+ if (ret <= 0) {
+ nameval = NULL;
+ } else if (ret == buflen - 1) {
+ free(buf);
+ /*
+ * Bail if we have a corrupted environment
+ */
+ if (buflen >= ARG_MAX)
+ return (-1);
+ buflen *= 2;
+ buf = malloc(buflen);
+ goto again;
+ } else {
+ nameval = buf;
+ }
+
+ if ((ret = func(data, P, envoff, nameval)) != 0)
+ break;
+
+ envpoff += (P->status.pr_dmodel == PR_MODEL_LP64)? 8 : 4;
+ }
+
+ free(buf);
+
+ return (ret);
+}
diff --git a/usr/src/lib/libproc/common/Psyscall.c b/usr/src/lib/libproc/common/Psyscall.c
new file mode 100644
index 0000000000..c34a17a04c
--- /dev/null
+++ b/usr/src/lib/libproc/common/Psyscall.c
@@ -0,0 +1,555 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <string.h>
+#include <memory.h>
+#include <errno.h>
+#include <dirent.h>
+#include <limits.h>
+#include <signal.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 "libproc.h"
+#include "Pcontrol.h"
+#include "Putil.h"
+#include "P32ton.h"
+#include "Pisadep.h"
+
+extern sigset_t blockable_sigs;
+
+static void
+Pabort_agent(struct ps_prochandle *P)
+{
+ int sysnum = P->status.pr_lwp.pr_syscall;
+ int stop;
+
+ dprintf("agent LWP is asleep in syscall %d\n", sysnum);
+ (void) Pstop(P, 0);
+ stop = Psysexit(P, sysnum, TRUE);
+
+ if (Psetrun(P, 0, PRSABORT) == 0) {
+ while (Pwait(P, 0) == -1 && errno == EINTR)
+ continue;
+ (void) Psysexit(P, sysnum, stop);
+ dprintf("agent LWP system call aborted\n");
+ }
+}
+
+/*
+ * Create the /proc agent LWP for further operations.
+ */
+int
+Pcreate_agent(struct ps_prochandle *P)
+{
+ int fd;
+ char pathname[100];
+ char *fname;
+ struct {
+ long cmd;
+ prgregset_t regs;
+ } cmd;
+
+ /*
+ * If not first reference, we already have the /proc agent LWP active.
+ */
+ if (P->agentcnt > 0) {
+ P->agentcnt++;
+ return (0);
+ }
+
+ /*
+ * The agent is not available for use as a mortician or as an
+ * obstetrician.
+ */
+ if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
+ P->state == PS_IDLE) {
+ errno = ENOENT;
+ return (-1);
+ }
+
+ /*
+ * Create the special /proc agent LWP if it doesn't already exist.
+ * Give it the registers of the representative LWP.
+ */
+ (void) Pstop(P, 0);
+ Psync(P);
+ if (!(P->status.pr_lwp.pr_flags & PR_AGENT)) {
+ cmd.cmd = PCAGENT;
+ (void) memcpy(&cmd.regs, &P->status.pr_lwp.pr_reg[0],
+ sizeof (P->status.pr_lwp.pr_reg));
+ if (write(P->ctlfd, &cmd, sizeof (cmd)) != sizeof (cmd))
+ goto bad;
+ }
+
+ /* refresh the process status */
+ (void) Pstopstatus(P, PCNULL, 0);
+
+ /* open the agent LWP files */
+ (void) sprintf(pathname, "/proc/%d/lwp/agent/", (int)P->pid);
+ fname = pathname + strlen(pathname);
+ (void) set_minfd();
+
+ /*
+ * It is difficult to know how to recover from the two errors
+ * that follow. The agent LWP exists and we need to kill it,
+ * but we can't because we need it active in order to kill it.
+ * We just hope that these failures never occur.
+ */
+ (void) strcpy(fname, "lwpstatus");
+ if ((fd = open(pathname, O_RDONLY)) < 0 ||
+ (fd = dupfd(fd, 0)) < 0)
+ goto bad;
+ P->agentstatfd = fd;
+
+ (void) strcpy(fname, "lwpctl");
+ if ((fd = open(pathname, O_WRONLY)) < 0 ||
+ (fd = dupfd(fd, 0)) < 0)
+ goto bad;
+ P->agentctlfd = fd;
+
+ /*
+ * If the agent is currently asleep in a system call, attempt
+ * to abort the system call so it's ready to serve.
+ */
+ if (P->status.pr_lwp.pr_flags & PR_ASLEEP) {
+ dprintf("Pcreate_agent: aborting agent syscall\n");
+ Pabort_agent(P);
+ }
+
+ /* get the agent LWP status */
+ P->agentcnt++;
+ if (Pstopstatus(P, PCNULL, 0) != 0) {
+ Pdestroy_agent(P);
+ return (-1);
+ }
+
+ return (0);
+
+bad:
+ if (P->agentstatfd >= 0)
+ (void) close(P->agentstatfd);
+ if (P->agentctlfd >= 0)
+ (void) close(P->agentctlfd);
+ P->agentstatfd = -1;
+ P->agentctlfd = -1;
+ /* refresh the process status */
+ (void) Pstopstatus(P, PCNULL, 0);
+ return (-1);
+}
+
+/*
+ * Decrement the /proc agent agent reference count.
+ * On last reference, destroy the agent.
+ */
+void
+Pdestroy_agent(struct ps_prochandle *P)
+{
+ if (P->agentcnt > 1)
+ P->agentcnt--;
+ else {
+ int flags;
+
+ Psync(P); /* Flush out any pending changes */
+
+ (void) Pstopstatus(P, PCNULL, 0);
+ flags = P->status.pr_lwp.pr_flags;
+
+ /*
+ * If the agent is currently asleep in a system call, attempt
+ * to abort the system call so we can terminate the agent.
+ */
+ if ((flags & (PR_AGENT|PR_ASLEEP)) == (PR_AGENT|PR_ASLEEP)) {
+ dprintf("Pdestroy_agent: aborting agent syscall\n");
+ Pabort_agent(P);
+ }
+
+ /*
+ * The agent itself is destroyed by forcing it to execute
+ * the _lwp_exit(2) system call. Close our agent descriptors
+ * regardless of whether this is successful.
+ */
+ (void) pr_lwp_exit(P);
+ (void) close(P->agentctlfd);
+ (void) close(P->agentstatfd);
+ P->agentctlfd = -1;
+ P->agentstatfd = -1;
+ P->agentcnt = 0;
+
+ /*
+ * Now that (hopefully) the agent has exited, refresh the
+ * status: the representative LWP is no longer the agent.
+ */
+ (void) Pstopstatus(P, PCNULL, 0);
+ }
+}
+
+/*
+ * Execute the syscall instruction.
+ */
+static int
+execute(struct ps_prochandle *P, int sysindex)
+{
+ int ctlfd = (P->agentctlfd >= 0)? P->agentctlfd : P->ctlfd;
+ int washeld = FALSE;
+ sigset_t hold; /* mask of held signals */
+ int cursig;
+ struct {
+ long cmd;
+ siginfo_t siginfo;
+ } ctl;
+ int sentry; /* old value of stop-on-syscall-entry */
+
+ sentry = Psysentry(P, sysindex, TRUE); /* set stop-on-syscall-entry */
+
+ /*
+ * If not already blocked, block all signals now.
+ */
+ if (memcmp(&P->status.pr_lwp.pr_lwphold, &blockable_sigs,
+ sizeof (sigset_t)) != 0) {
+ hold = P->status.pr_lwp.pr_lwphold;
+ P->status.pr_lwp.pr_lwphold = blockable_sigs;
+ P->flags |= SETHOLD;
+ washeld = TRUE;
+ }
+
+ /*
+ * If there is a current signal, remember it and cancel it.
+ */
+ if ((cursig = P->status.pr_lwp.pr_cursig) != 0) {
+ ctl.cmd = PCSSIG;
+ ctl.siginfo = P->status.pr_lwp.pr_info;
+ }
+
+ if (Psetrun(P, 0, PRCSIG | PRCFAULT) == -1)
+ goto bad;
+
+ while (P->state == PS_RUN) {
+ (void) Pwait(P, 0);
+ }
+ if (P->state != PS_STOP)
+ goto bad;
+
+ if (cursig) /* restore cursig */
+ (void) write(ctlfd, &ctl, sizeof (ctl));
+ if (washeld) { /* restore the signal mask if we set it */
+ P->status.pr_lwp.pr_lwphold = hold;
+ P->flags |= SETHOLD;
+ }
+
+ (void) Psysentry(P, sysindex, sentry); /* restore sysentry stop */
+
+ if (P->status.pr_lwp.pr_why == PR_SYSENTRY &&
+ P->status.pr_lwp.pr_what == sysindex)
+ return (0);
+bad:
+ return (-1);
+}
+
+
+/*
+ * Perform system call in controlled process.
+ */
+int
+Psyscall(struct ps_prochandle *P,
+ sysret_t *rval, /* syscall return values */
+ int sysindex, /* system call index */
+ uint_t nargs, /* number of arguments to system call */
+ argdes_t *argp) /* argument descriptor array */
+{
+ int agent_created = FALSE;
+ pstatus_t save_pstatus;
+ argdes_t *adp; /* pointer to argument descriptor */
+ int i; /* general index value */
+ int model; /* data model */
+ int error = 0; /* syscall errno */
+ int Perr = 0; /* local error number */
+ int sexit; /* old value of stop-on-syscall-exit */
+ prgreg_t sp; /* adjusted stack pointer */
+ prgreg_t ap; /* adjusted argument pointer */
+ sigset_t unblock;
+
+ (void) sigprocmask(SIG_BLOCK, &blockable_sigs, &unblock);
+
+ rval->sys_rval1 = 0; /* initialize return values */
+ rval->sys_rval2 = 0;
+
+ if (sysindex <= 0 || sysindex > PRMAXSYS || nargs > MAXARGS)
+ goto bad1; /* programming error */
+
+ if (P->state == PS_DEAD || P->state == PS_UNDEAD || P->state == PS_IDLE)
+ goto bad1; /* dead processes can't perform system calls */
+
+ model = P->status.pr_dmodel;
+#ifndef _LP64
+ /* We must be a 64-bit process to deal with a 64-bit process */
+ if (model == PR_MODEL_LP64)
+ goto bad9;
+#endif
+
+ /*
+ * Create the /proc agent LWP in the process to do all the work.
+ * (It may already exist; nested create/destroy is permitted
+ * by virtue of the reference count.)
+ */
+ if (Pcreate_agent(P) != 0)
+ goto bad8;
+
+ /*
+ * Save agent's status to restore on exit.
+ */
+ agent_created = TRUE;
+ save_pstatus = P->status;
+
+ if (P->state != PS_STOP || /* check state of LWP */
+ (P->status.pr_flags & PR_ASLEEP))
+ goto bad2;
+
+ if (Pscantext(P)) /* bad text ? */
+ goto bad3;
+
+ /*
+ * Validate arguments and compute the stack frame parameters.
+ * Begin with the current stack pointer.
+ */
+#ifdef _LP64
+ if (model == PR_MODEL_LP64) {
+ sp = P->status.pr_lwp.pr_reg[R_SP] + STACK_BIAS;
+ sp = PSTACK_ALIGN64(sp);
+ } else {
+#endif
+ sp = (uint32_t)P->status.pr_lwp.pr_reg[R_SP];
+ sp = PSTACK_ALIGN32(sp);
+#ifdef _LP64
+ }
+#endif
+
+ /*
+ * For each AT_BYREF argument, compute the necessary
+ * stack space and the object's stack address.
+ */
+ for (i = 0, adp = argp; i < nargs; i++, adp++) {
+ rval->sys_rval1 = i; /* in case of error */
+ switch (adp->arg_type) {
+ default: /* programming error */
+ goto bad4;
+ case AT_BYVAL: /* simple argument */
+ break;
+ case AT_BYREF: /* must allocate space */
+ switch (adp->arg_inout) {
+ case AI_INPUT:
+ case AI_OUTPUT:
+ case AI_INOUT:
+ if (adp->arg_object == NULL)
+ goto bad5; /* programming error */
+ break;
+ default: /* programming error */
+ goto bad6;
+ }
+ /* allocate stack space for BYREF argument */
+ if (adp->arg_size == 0 || adp->arg_size > MAXARGL)
+ goto bad7; /* programming error */
+#ifdef _LP64
+ if (model == PR_MODEL_LP64)
+ sp = PSTACK_ALIGN64(sp - adp->arg_size);
+ else
+#endif
+ sp = PSTACK_ALIGN32(sp - adp->arg_size);
+ adp->arg_value = sp; /* stack address for object */
+ break;
+ }
+ }
+ rval->sys_rval1 = 0; /* in case of error */
+ /*
+ * Point of no return.
+ * Perform the system call entry, adjusting %sp.
+ * This moves the LWP to the stopped-on-syscall-entry state
+ * just before the arguments to the system call are fetched.
+ */
+ ap = Psyscall_setup(P, nargs, sysindex, sp);
+ P->flags |= SETREGS; /* set registers before continuing */
+ dprintf("Psyscall(): execute(sysindex = %d)\n", sysindex);
+
+ /*
+ * Execute the syscall instruction and stop on syscall entry.
+ */
+ if (execute(P, sysindex) != 0 ||
+ (!Pissyscall(P, P->status.pr_lwp.pr_reg[R_PC]) &&
+ !Pissyscall_prev(P, P->status.pr_lwp.pr_reg[R_PC], NULL)))
+ goto bad10;
+
+ dprintf("Psyscall(): copying arguments\n");
+
+ /*
+ * The LWP is stopped at syscall entry.
+ * Copy objects to stack frame for each argument.
+ */
+ for (i = 0, adp = argp; i < nargs; i++, adp++) {
+ rval->sys_rval1 = i; /* in case of error */
+ if (adp->arg_type != AT_BYVAL &&
+ adp->arg_inout != AI_OUTPUT) {
+ /* copy input byref parameter to process */
+ if (Pwrite(P, adp->arg_object, adp->arg_size,
+ (uintptr_t)adp->arg_value) != adp->arg_size)
+ goto bad17;
+ }
+ }
+ rval->sys_rval1 = 0; /* in case of error */
+ if (Psyscall_copyinargs(P, nargs, argp, ap) != 0)
+ goto bad18;
+
+ /*
+ * Complete the system call.
+ * This moves the LWP to the stopped-on-syscall-exit state.
+ */
+ dprintf("Psyscall(): set running at sysentry\n");
+
+ sexit = Psysexit(P, sysindex, TRUE); /* catch this syscall exit */
+ do {
+ if (Psetrun(P, 0, 0) == -1)
+ goto bad21;
+ while (P->state == PS_RUN)
+ (void) Pwait(P, 0);
+ } while (P->state == PS_STOP && P->status.pr_lwp.pr_why != PR_SYSEXIT);
+ (void) Psysexit(P, sysindex, sexit); /* restore original setting */
+
+ /*
+ * If the system call was _lwp_exit(), we expect that our last call
+ * to Pwait() will yield ENOENT because the LWP no longer exists.
+ */
+ if (sysindex == SYS_lwp_exit && errno == ENOENT) {
+ dprintf("Psyscall(): _lwp_exit successful\n");
+ rval->sys_rval1 = rval->sys_rval2 = 0;
+ goto out;
+ }
+
+ if (P->state != PS_STOP || P->status.pr_lwp.pr_why != PR_SYSEXIT)
+ goto bad22;
+
+ if (P->status.pr_lwp.pr_what != sysindex)
+ goto bad23;
+
+ if (!Pissyscall_prev(P, P->status.pr_lwp.pr_reg[R_PC], NULL)) {
+ dprintf("Pissyscall_prev() failed\n");
+ goto bad24;
+ }
+
+ dprintf("Psyscall(): caught at sysexit\n");
+
+ /*
+ * For each argument.
+ */
+ for (i = 0, adp = argp; i < nargs; i++, adp++) {
+ rval->sys_rval1 = i; /* in case of error */
+ if (adp->arg_type != AT_BYVAL &&
+ adp->arg_inout != AI_INPUT) {
+ /* copy output byref parameter from process */
+ if (Pread(P, adp->arg_object, adp->arg_size,
+ (uintptr_t)adp->arg_value) != adp->arg_size)
+ goto bad25;
+ }
+ }
+
+ if (Psyscall_copyoutargs(P, nargs, argp, ap) != 0)
+ goto bad26;
+
+ /*
+ * Get the return values from the syscall.
+ */
+ if (P->status.pr_lwp.pr_errno) { /* error return */
+ error = P->status.pr_lwp.pr_errno;
+ rval->sys_rval1 = -1L;
+ rval->sys_rval2 = -1L;
+ dprintf("Psyscall(%d) fails with errno %d\n",
+ sysindex, error);
+ } else { /* normal return */
+ rval->sys_rval1 = P->status.pr_lwp.pr_rval1;
+ rval->sys_rval2 = P->status.pr_lwp.pr_rval2;
+ dprintf("Psyscall(%d) returns 0x%lx 0x%lx\n", sysindex,
+ P->status.pr_lwp.pr_rval1, P->status.pr_lwp.pr_rval2);
+ }
+
+ goto out;
+
+bad26: Perr++;
+bad25: Perr++;
+bad24: Perr++;
+bad23: Perr++;
+bad22: Perr++;
+bad21: Perr++;
+ Perr++;
+ Perr++;
+bad18: Perr++;
+bad17: Perr++;
+ Perr++;
+ Perr++;
+ Perr++;
+ Perr++;
+ Perr++;
+ Perr++;
+bad10: Perr++;
+bad9: Perr++;
+bad8: Perr++;
+bad7: Perr++;
+bad6: Perr++;
+bad5: Perr++;
+bad4: Perr++;
+bad3: Perr++;
+bad2: Perr++;
+bad1: Perr++;
+ error = -1;
+ dprintf("Psyscall(%d) fails with local error %d\n", sysindex, Perr);
+
+out:
+ /*
+ * Destroy the /proc agent LWP now (or just bump down the ref count).
+ */
+ if (agent_created) {
+ if (P->state != PS_UNDEAD) {
+ P->status = save_pstatus;
+ P->flags |= SETREGS;
+ Psync(P);
+ }
+ Pdestroy_agent(P);
+ }
+
+ (void) sigprocmask(SIG_SETMASK, &unblock, NULL);
+ return (error);
+}
diff --git a/usr/src/lib/libproc/common/Putil.c b/usr/src/lib/libproc/common/Putil.c
new file mode 100644
index 0000000000..7e06c14f67
--- /dev/null
+++ b/usr/src/lib/libproc/common/Putil.c
@@ -0,0 +1,152 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1998-2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <limits.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include "Pcontrol.h"
+#include "Putil.h"
+
+/*
+ * Place the new element on the list prior to the existing element.
+ */
+void
+list_link(void *new, void *existing)
+{
+ list_t *p = new;
+ list_t *q = existing;
+
+ if (q) {
+ p->list_forw = q;
+ p->list_back = q->list_back;
+ q->list_back->list_forw = p;
+ q->list_back = p;
+ } else {
+ p->list_forw = p->list_back = p;
+ }
+}
+
+/*
+ * Unchain the specified element from a list.
+ */
+void
+list_unlink(void *old)
+{
+ list_t *p = old;
+
+ if (p->list_forw != p) {
+ p->list_back->list_forw = p->list_forw;
+ p->list_forw->list_back = p->list_back;
+ }
+ p->list_forw = p->list_back = p;
+}
+
+/*
+ * Routines to manipulate sigset_t, fltset_t, or sysset_t. These routines
+ * are provided as equivalents for the <sys/procfs.h> macros prfillset,
+ * premptyset, praddset, and prdelset. These functions are preferable
+ * because they are not macros which rely on using sizeof (*sp), and thus
+ * can be used to create common code to manipulate event sets. The set
+ * size must be passed explicitly, e.g. : prset_fill(&set, sizeof (set));
+ */
+void
+prset_fill(void *sp, size_t size)
+{
+ size_t i = size / sizeof (uint32_t);
+
+ while (i != 0)
+ ((uint32_t *)sp)[--i] = (uint32_t)0xFFFFFFFF;
+}
+
+void
+prset_empty(void *sp, size_t size)
+{
+ size_t i = size / sizeof (uint32_t);
+
+ while (i != 0)
+ ((uint32_t *)sp)[--i] = (uint32_t)0;
+}
+
+void
+prset_add(void *sp, size_t size, uint_t flag)
+{
+ if (flag - 1 < 32 * size / sizeof (uint32_t))
+ ((uint32_t *)sp)[(flag - 1) / 32] |= 1U << ((flag - 1) % 32);
+}
+
+void
+prset_del(void *sp, size_t size, uint_t flag)
+{
+ if (flag - 1 < 32 * size / sizeof (uint32_t))
+ ((uint32_t *)sp)[(flag - 1) / 32] &= ~(1U << ((flag - 1) % 32));
+}
+
+int
+prset_ismember(void *sp, size_t size, uint_t flag)
+{
+ return ((flag - 1 < 32 * size / sizeof (uint32_t)) &&
+ (((uint32_t *)sp)[(flag - 1) / 32] & (1U << ((flag - 1) % 32))));
+}
+
+/*
+ * If _libproc_debug is set, printf the debug message to stderr
+ * with an appropriate prefix.
+ */
+/*PRINTFLIKE1*/
+void
+dprintf(const char *format, ...)
+{
+ if (_libproc_debug) {
+ va_list alist;
+
+ va_start(alist, format);
+ (void) fputs("libproc DEBUG: ", stderr);
+ (void) vfprintf(stderr, format, alist);
+ va_end(alist);
+ }
+}
+
+/*
+ * Printf-style error reporting function. This is used to supplement the error
+ * return codes from various libproc functions with additional text. Since we
+ * are a library, and should not be spewing messages to stderr, we provide a
+ * default version of this function that does nothing, but by calling this
+ * function we allow the client program to define its own version of the
+ * function that will interpose on our empty default. This may be useful for
+ * clients that wish to display such messages to the user.
+ */
+/*ARGSUSED*/
+/*PRINTFLIKE2*/
+void
+Perror_printf(struct ps_prochandle *P, const char *format, ...)
+{
+ /* nothing to do here */
+}
diff --git a/usr/src/lib/libproc/common/Putil.h b/usr/src/lib/libproc/common/Putil.h
new file mode 100644
index 0000000000..328440fc81
--- /dev/null
+++ b/usr/src/lib/libproc/common/Putil.h
@@ -0,0 +1,71 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _PUTIL_H
+#define _PUTIL_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Circular doubly-linked list:
+ */
+typedef struct P_list {
+ struct P_list *list_forw;
+ struct P_list *list_back;
+} list_t;
+
+/*
+ * Routines to manipulate linked lists:
+ */
+extern void list_link(void *, void *);
+extern void list_unlink(void *);
+
+#define list_next(elem) (void *)(((list_t *)(elem))->list_forw)
+#define list_prev(elem) (void *)(((list_t *)(elem))->list_back)
+
+/*
+ * Routines to manipulate sigset_t, fltset_t, or sysset_t.
+ */
+extern void prset_fill(void *, size_t);
+extern void prset_empty(void *, size_t);
+extern void prset_add(void *, size_t, uint_t);
+extern void prset_del(void *, size_t, uint_t);
+extern int prset_ismember(void *, size_t, uint_t);
+
+/*
+ * Routine to print debug messages:
+ */
+extern void dprintf(const char *, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PUTIL_H */
diff --git a/usr/src/lib/libproc/common/libproc.h b/usr/src/lib/libproc/common/libproc.h
new file mode 100644
index 0000000000..b2f37f45d7
--- /dev/null
+++ b/usr/src/lib/libproc/common/libproc.h
@@ -0,0 +1,704 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Interfaces available from the process control library, libproc.
+ *
+ * libproc provides process control functions for the /proc tools
+ * (commands in /usr/proc/bin), /usr/bin/truss, and /usr/bin/gcore.
+ * libproc is a private support library for these commands only.
+ * It is _not_ a public interface, although it might become one
+ * in the fullness of time, when the interfaces settle down.
+ *
+ * In the meantime, be aware that any program linked with libproc in this
+ * release of Solaris is almost guaranteed to break in the next release.
+ *
+ * In short, do not use this header file or libproc for any purpose.
+ */
+
+#ifndef _LIBPROC_H
+#define _LIBPROC_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <nlist.h>
+#include <door.h>
+#include <gelf.h>
+#include <proc_service.h>
+#include <rtld_db.h>
+#include <procfs.h>
+#include <rctl.h>
+#include <libctf.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <sys/auxv.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/utsname.h>
+#include <sys/corectl.h>
+#if defined(__i386) || defined(__amd64)
+#include <sys/sysi86.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Opaque structure tag reference to a process control structure.
+ * Clients of libproc cannot look inside the process control structure.
+ * The implementation of struct ps_prochandle can change w/o affecting clients.
+ */
+struct ps_prochandle;
+
+/*
+ * Opaque structure tag reference to an lwp control structure.
+ */
+struct ps_lwphandle;
+
+extern int _libproc_debug; /* set non-zero to enable debugging fprintfs */
+
+#if defined(__sparc)
+#define R_RVAL1 R_O0 /* register holding a function return value */
+#define R_RVAL2 R_O1 /* 32 more bits for a 64-bit return value */
+#endif /* __sparc */
+
+#if defined(__amd64)
+#define R_PC REG_RIP
+#define R_SP REG_RSP
+#define R_RVAL1 REG_RAX /* register holding a function return value */
+#define R_RVAL2 REG_RDX /* 32 more bits for a 64-bit return value */
+#elif defined(__i386)
+#define R_PC EIP
+#define R_SP UESP
+#define R_RVAL1 EAX /* register holding a function return value */
+#define R_RVAL2 EDX /* 32 more bits for a 64-bit return value */
+#endif /* __amd64 || __i386 */
+
+#define R_RVAL R_RVAL1 /* simple function return value register */
+
+/* maximum sizes of things */
+#define PRMAXSIG (32 * sizeof (sigset_t) / sizeof (uint32_t))
+#define PRMAXFAULT (32 * sizeof (fltset_t) / sizeof (uint32_t))
+#define PRMAXSYS (32 * sizeof (sysset_t) / sizeof (uint32_t))
+
+/* State values returned by Pstate() */
+#define PS_RUN 1 /* process is running */
+#define PS_STOP 2 /* process is stopped */
+#define PS_LOST 3 /* process is lost to control (EAGAIN) */
+#define PS_UNDEAD 4 /* process is terminated (zombie) */
+#define PS_DEAD 5 /* process is terminated (core file) */
+#define PS_IDLE 6 /* process has not been run */
+
+/* Flags accepted by Pgrab() */
+#define PGRAB_RETAIN 0x01 /* Retain tracing flags, else clear flags */
+#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 */
+
+/* Error codes from Pcreate() */
+#define C_STRANGE -1 /* Unanticipated error, errno is meaningful */
+#define C_FORK 1 /* Unable to fork */
+#define C_PERM 2 /* No permission (file set-id or unreadable) */
+#define C_NOEXEC 3 /* Cannot execute file */
+#define C_INTR 4 /* Interrupt received while creating */
+#define C_LP64 5 /* Program is _LP64, self is _ILP32 */
+#define C_NOENT 6 /* Cannot find executable file */
+
+/* Error codes from Pgrab(), Pfgrab_core(), and Pgrab_core() */
+#define G_STRANGE -1 /* Unanticipated error, errno is meaningful */
+#define G_NOPROC 1 /* No such process */
+#define G_NOCORE 2 /* No such core file */
+#define G_NOPROCORCORE 3 /* No such proc or core (for proc_arg_grab) */
+#define G_NOEXEC 4 /* Cannot locate executable file */
+#define G_ZOMB 5 /* Zombie process */
+#define G_PERM 6 /* No permission */
+#define G_BUSY 7 /* Another process has control */
+#define G_SYS 8 /* System process */
+#define G_SELF 9 /* Process is self */
+#define G_INTR 10 /* Interrupt received while grabbing */
+#define G_LP64 11 /* Process is _LP64, self is ILP32 */
+#define G_FORMAT 12 /* File is not an ELF format core file */
+#define G_ELF 13 /* Libelf error, elf_errno() is meaningful */
+#define G_NOTE 14 /* Required PT_NOTE Phdr not present in core */
+#define G_ISAINVAL 15 /* Wrong ELF machine type */
+#define G_BADLWPS 16 /* Bad '/lwps' specification */
+
+
+/* Flags accepted by Prelease */
+#define PRELEASE_CLEAR 0x10 /* Clear all tracing flags */
+#define PRELEASE_RETAIN 0x20 /* Retain final tracing flags */
+#define PRELEASE_HANG 0x40 /* Leave the process stopped */
+#define PRELEASE_KILL 0x80 /* Terminate the process */
+
+typedef struct { /* argument descriptor for system call (Psyscall) */
+ long arg_value; /* value of argument given to system call */
+ void *arg_object; /* pointer to object in controlling process */
+ char arg_type; /* AT_BYVAL, AT_BYREF */
+ char arg_inout; /* AI_INPUT, AI_OUTPUT, AI_INOUT */
+ ushort_t arg_size; /* if AT_BYREF, size of object in bytes */
+} argdes_t;
+
+/* values for type */
+#define AT_BYVAL 1
+#define AT_BYREF 2
+
+/* values for inout */
+#define AI_INPUT 1
+#define AI_OUTPUT 2
+#define AI_INOUT 3
+
+/* maximum number of syscall arguments */
+#define MAXARGS 8
+
+/* maximum size in bytes of a BYREF argument */
+#define MAXARGL (4*1024)
+
+/*
+ * Function prototypes for routines in the process control package.
+ */
+extern struct ps_prochandle *Pcreate(const char *, char *const *,
+ int *, char *, size_t);
+extern struct ps_prochandle *Pxcreate(const char *, char *const *,
+ char *const *, int *, char *, size_t);
+
+extern const char *Pcreate_error(int);
+
+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 const char *Pgrab_error(int);
+
+extern int Preopen(struct ps_prochandle *);
+extern void Prelease(struct ps_prochandle *, int);
+extern void Pfree(struct ps_prochandle *);
+
+extern int Pasfd(struct ps_prochandle *);
+extern int Pctlfd(struct ps_prochandle *);
+extern int Pcreate_agent(struct ps_prochandle *);
+extern void Pdestroy_agent(struct ps_prochandle *);
+extern int Pstopstatus(struct ps_prochandle *, long, uint_t);
+extern int Pwait(struct ps_prochandle *, uint_t);
+extern int Pstop(struct ps_prochandle *, uint_t);
+extern int Pdstop(struct ps_prochandle *);
+extern int Pstate(struct ps_prochandle *);
+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 Psetpriv(struct ps_prochandle *, prpriv_t *);
+extern void *Pprivinfo(struct ps_prochandle *);
+extern int Psetzoneid(struct ps_prochandle *, zoneid_t);
+extern int Pgetareg(struct ps_prochandle *, int, prgreg_t *);
+extern int Pputareg(struct ps_prochandle *, int, prgreg_t);
+extern int Psetrun(struct ps_prochandle *, int, int);
+extern ssize_t Pread(struct ps_prochandle *, void *, size_t, uintptr_t);
+extern ssize_t Pread_string(struct ps_prochandle *, char *, size_t, uintptr_t);
+extern ssize_t Pwrite(struct ps_prochandle *, const void *, size_t, uintptr_t);
+extern int Pclearsig(struct ps_prochandle *);
+extern int Pclearfault(struct ps_prochandle *);
+extern int Psetbkpt(struct ps_prochandle *, uintptr_t, ulong_t *);
+extern int Pdelbkpt(struct ps_prochandle *, uintptr_t, ulong_t);
+extern int Pxecbkpt(struct ps_prochandle *, ulong_t);
+extern int Psetwapt(struct ps_prochandle *, const prwatch_t *);
+extern int Pdelwapt(struct ps_prochandle *, const prwatch_t *);
+extern int Pxecwapt(struct ps_prochandle *, const prwatch_t *);
+extern int Psetflags(struct ps_prochandle *, long);
+extern int Punsetflags(struct ps_prochandle *, long);
+extern int Psignal(struct ps_prochandle *, int, int);
+extern int Pfault(struct ps_prochandle *, int, int);
+extern int Psysentry(struct ps_prochandle *, int, int);
+extern int Psysexit(struct ps_prochandle *, int, int);
+extern void Psetsignal(struct ps_prochandle *, const sigset_t *);
+extern void Psetfault(struct ps_prochandle *, const fltset_t *);
+extern void Psetsysentry(struct ps_prochandle *, const sysset_t *);
+extern void Psetsysexit(struct ps_prochandle *, const sysset_t *);
+
+extern void Psync(struct ps_prochandle *);
+extern int Psyscall(struct ps_prochandle *, sysret_t *,
+ int, uint_t, argdes_t *);
+extern int Pisprocdir(struct ps_prochandle *, const char *);
+
+/*
+ * Function prototypes for lwp-specific operations.
+ */
+extern struct ps_lwphandle *Lgrab(struct ps_prochandle *, lwpid_t, int *);
+extern const char *Lgrab_error(int);
+
+extern struct ps_prochandle *Lprochandle(struct ps_lwphandle *);
+extern void Lfree(struct ps_lwphandle *);
+
+extern int Lctlfd(struct ps_lwphandle *);
+extern int Lwait(struct ps_lwphandle *, uint_t);
+extern int Lstop(struct ps_lwphandle *, uint_t);
+extern int Ldstop(struct ps_lwphandle *);
+extern int Lstate(struct ps_lwphandle *);
+extern const lwpsinfo_t *Lpsinfo(struct ps_lwphandle *);
+extern const lwpstatus_t *Lstatus(struct ps_lwphandle *);
+extern int Lgetareg(struct ps_lwphandle *, int, prgreg_t *);
+extern int Lputareg(struct ps_lwphandle *, int, prgreg_t);
+extern int Lsetrun(struct ps_lwphandle *, int, int);
+extern int Lclearsig(struct ps_lwphandle *);
+extern int Lclearfault(struct ps_lwphandle *);
+extern int Lxecbkpt(struct ps_lwphandle *, ulong_t);
+extern int Lxecwapt(struct ps_lwphandle *, const prwatch_t *);
+extern void Lsync(struct ps_lwphandle *);
+
+extern int Lstack(struct ps_lwphandle *, stack_t *);
+extern int Lmain_stack(struct ps_lwphandle *, stack_t *);
+extern int Lalt_stack(struct ps_lwphandle *, stack_t *);
+
+/*
+ * Function prototypes for system calls forced on the victim process.
+ */
+extern int pr_open(struct ps_prochandle *, const char *, int, mode_t);
+extern int pr_creat(struct ps_prochandle *, const char *, mode_t);
+extern int pr_close(struct ps_prochandle *, int);
+extern int pr_access(struct ps_prochandle *, const char *, int);
+extern int pr_door_info(struct ps_prochandle *, int, struct door_info *);
+extern void *pr_mmap(struct ps_prochandle *,
+ void *, size_t, int, int, int, off_t);
+extern void *pr_zmap(struct ps_prochandle *,
+ void *, size_t, int, int);
+extern int pr_munmap(struct ps_prochandle *, void *, size_t);
+extern int pr_memcntl(struct ps_prochandle *,
+ caddr_t, size_t, int, caddr_t, int, int);
+extern int pr_meminfo(struct ps_prochandle *, const uint64_t *addrs,
+ int addr_count, const uint_t *info, int info_count,
+ uint64_t *outdata, uint_t *validity);
+extern int pr_sigaction(struct ps_prochandle *,
+ int, const struct sigaction *, struct sigaction *);
+extern int pr_getitimer(struct ps_prochandle *,
+ int, struct itimerval *);
+extern int pr_setitimer(struct ps_prochandle *,
+ int, const struct itimerval *, struct itimerval *);
+extern int pr_ioctl(struct ps_prochandle *, int, int, void *, size_t);
+extern int pr_fcntl(struct ps_prochandle *, int, int, void *);
+extern int pr_stat(struct ps_prochandle *, const char *, struct stat *);
+extern int pr_lstat(struct ps_prochandle *, const char *, struct stat *);
+extern int pr_fstat(struct ps_prochandle *, int, struct stat *);
+extern int pr_stat64(struct ps_prochandle *, const char *,
+ struct stat64 *);
+extern int pr_lstat64(struct ps_prochandle *, const char *,
+ struct stat64 *);
+extern int pr_fstat64(struct ps_prochandle *, int, struct stat64 *);
+extern int pr_statvfs(struct ps_prochandle *, const char *, statvfs_t *);
+extern int pr_fstatvfs(struct ps_prochandle *, int, statvfs_t *);
+extern projid_t pr_getprojid(struct ps_prochandle *Pr);
+extern taskid_t pr_gettaskid(struct ps_prochandle *Pr);
+extern taskid_t pr_settaskid(struct ps_prochandle *Pr, projid_t project,
+ int flags);
+extern zoneid_t pr_getzoneid(struct ps_prochandle *Pr);
+extern int pr_getrctl(struct ps_prochandle *,
+ const char *, rctlblk_t *, rctlblk_t *, int);
+extern int pr_setrctl(struct ps_prochandle *,
+ const char *, rctlblk_t *, rctlblk_t *, int);
+extern int pr_getrlimit(struct ps_prochandle *,
+ int, struct rlimit *);
+extern int pr_setrlimit(struct ps_prochandle *,
+ int, const struct rlimit *);
+#if defined(_LARGEFILE64_SOURCE)
+extern int pr_getrlimit64(struct ps_prochandle *,
+ int, struct rlimit64 *);
+extern int pr_setrlimit64(struct ps_prochandle *,
+ int, const struct rlimit64 *);
+#endif /* _LARGEFILE64_SOURCE */
+extern int pr_lwp_exit(struct ps_prochandle *);
+extern int pr_exit(struct ps_prochandle *, int);
+extern int pr_waitid(struct ps_prochandle *,
+ idtype_t, id_t, siginfo_t *, int);
+extern off_t pr_lseek(struct ps_prochandle *, int, off_t, int);
+extern offset_t pr_llseek(struct ps_prochandle *, int, offset_t, int);
+extern int pr_rename(struct ps_prochandle *, const char *, const char *);
+extern int pr_link(struct ps_prochandle *, const char *, const char *);
+extern int pr_unlink(struct ps_prochandle *, const char *);
+extern int pr_getpeername(struct ps_prochandle *,
+ int, struct sockaddr *, socklen_t *);
+extern int pr_getsockname(struct ps_prochandle *,
+ int, struct sockaddr *, socklen_t *);
+extern int pr_getsockopt(struct ps_prochandle *,
+ int, int, int, void *, int *);
+extern int pr_processor_bind(struct ps_prochandle *,
+ idtype_t, id_t, int, int *);
+extern int pr_pset_bind(struct ps_prochandle *,
+ int, idtype_t, id_t, int *);
+
+/*
+ * Function prototypes for accessing per-LWP register information.
+ */
+extern int Plwp_getregs(struct ps_prochandle *, lwpid_t, prgregset_t);
+extern int Plwp_setregs(struct ps_prochandle *, lwpid_t, const prgregset_t);
+
+extern int Plwp_getfpregs(struct ps_prochandle *, lwpid_t, prfpregset_t *);
+extern int Plwp_setfpregs(struct ps_prochandle *, lwpid_t,
+ const prfpregset_t *);
+
+#if defined(__sparc)
+
+extern int Plwp_getxregs(struct ps_prochandle *, lwpid_t, prxregset_t *);
+extern int Plwp_setxregs(struct ps_prochandle *, lwpid_t, const prxregset_t *);
+
+extern int Plwp_getgwindows(struct ps_prochandle *, lwpid_t, gwindows_t *);
+
+#if defined(__sparcv9)
+extern int Plwp_getasrs(struct ps_prochandle *, lwpid_t, asrset_t);
+extern int Plwp_setasrs(struct ps_prochandle *, lwpid_t, const asrset_t);
+#endif /* __sparcv9 */
+
+#endif /* __sparc */
+
+#if defined(__i386) || defined(__amd64)
+extern int Pldt(struct ps_prochandle *, struct ssd *, int);
+extern int proc_get_ldt(pid_t, struct ssd *, int);
+#endif /* __i386 || __amd64 */
+
+extern int Plwp_getpsinfo(struct ps_prochandle *, lwpid_t, lwpsinfo_t *);
+
+extern int Plwp_stack(struct ps_prochandle *, lwpid_t, stack_t *);
+extern int Plwp_main_stack(struct ps_prochandle *, lwpid_t, stack_t *);
+extern int Plwp_alt_stack(struct ps_prochandle *, lwpid_t, stack_t *);
+
+/*
+ * LWP iteration interface; iterate over all active LWPs.
+ */
+typedef int proc_lwp_f(void *, const lwpstatus_t *);
+extern int Plwp_iter(struct ps_prochandle *, proc_lwp_f *, void *);
+
+/*
+ * LWP iteration interface; iterate over all LWPs, active and zombie.
+ */
+typedef int proc_lwp_all_f(void *, const lwpstatus_t *, const lwpsinfo_t *);
+extern int Plwp_iter_all(struct ps_prochandle *, proc_lwp_all_f *, void *);
+
+/*
+ * Process iteration interface; iterate over all active processes.
+ */
+typedef int proc_walk_f(psinfo_t *, lwpsinfo_t *, void *);
+extern int proc_walk(proc_walk_f *, void *, int);
+
+#define PR_WALK_PROC 0 /* walk processes only */
+#define PR_WALK_LWP 1 /* walk all lwps */
+
+/*
+ * Determine if an lwp is in a set as returned from proc_arg_xgrab().
+ */
+extern int proc_lwp_in_set(const char *, lwpid_t);
+extern int proc_lwp_range_valid(const char *);
+
+/*
+ * Symbol table interfaces.
+ */
+
+/*
+ * Pseudo-names passed to Plookup_by_name() for well-known load objects.
+ * NOTE: It is required that PR_OBJ_EXEC and PR_OBJ_LDSO exactly match
+ * the definitions of PS_OBJ_EXEC and PS_OBJ_LDSO from <proc_service.h>.
+ */
+#define PR_OBJ_EXEC ((const char *)0) /* search the executable file */
+#define PR_OBJ_LDSO ((const char *)1) /* search ld.so.1 */
+#define PR_OBJ_EVERY ((const char *)-1) /* search every load object */
+
+/*
+ * Special Lmid_t passed to Plookup_by_lmid() to search all link maps. The
+ * special values LM_ID_BASE and LM_ID_LDSO from <link.h> may also be used.
+ * If PR_OBJ_EXEC is used as the object name, the lmid must be PR_LMID_EVERY
+ * or LM_ID_BASE in order to return a match. If PR_OBJ_LDSO is used as the
+ * object name, the lmid must be PR_LMID_EVERY or LM_ID_LDSO to return a match.
+ */
+#define PR_LMID_EVERY ((Lmid_t)-1UL) /* search every link map */
+
+/*
+ * 'object_name' is the name of a load object obtained from an
+ * iteration over the process's address space mappings (Pmapping_iter),
+ * or an iteration over the process's mapped objects (Pobject_iter),
+ * or else it is one of the special PR_OBJ_* values above.
+ */
+extern int Plookup_by_name(struct ps_prochandle *,
+ const char *, const char *, GElf_Sym *);
+
+extern int Plookup_by_addr(struct ps_prochandle *,
+ uintptr_t, char *, size_t, GElf_Sym *);
+
+typedef struct prsyminfo {
+ const char *prs_object; /* object name */
+ const char *prs_name; /* symbol name */
+ Lmid_t prs_lmid; /* link map id */
+ uint_t prs_id; /* symbol id */
+ uint_t prs_table; /* symbol table id */
+} prsyminfo_t;
+
+extern int Pxlookup_by_name(struct ps_prochandle *,
+ Lmid_t, const char *, const char *, GElf_Sym *, prsyminfo_t *);
+
+extern int Pxlookup_by_addr(struct ps_prochandle *,
+ uintptr_t, char *, size_t, GElf_Sym *, prsyminfo_t *);
+
+typedef int proc_map_f(void *, const prmap_t *, const char *);
+
+extern int Pmapping_iter(struct ps_prochandle *, proc_map_f *, void *);
+extern int Pobject_iter(struct ps_prochandle *, proc_map_f *, void *);
+
+extern const prmap_t *Paddr_to_map(struct ps_prochandle *, uintptr_t);
+extern const prmap_t *Paddr_to_text_map(struct ps_prochandle *, uintptr_t);
+extern const prmap_t *Pname_to_map(struct ps_prochandle *, const char *);
+extern const prmap_t *Plmid_to_map(struct ps_prochandle *,
+ Lmid_t, const char *);
+
+extern const rd_loadobj_t *Paddr_to_loadobj(struct ps_prochandle *, uintptr_t);
+extern const rd_loadobj_t *Pname_to_loadobj(struct ps_prochandle *,
+ const char *);
+extern const rd_loadobj_t *Plmid_to_loadobj(struct ps_prochandle *,
+ Lmid_t, const char *);
+
+extern ctf_file_t *Paddr_to_ctf(struct ps_prochandle *, uintptr_t);
+extern ctf_file_t *Pname_to_ctf(struct ps_prochandle *, const char *);
+
+extern char *Pplatform(struct ps_prochandle *, char *, size_t);
+extern int Puname(struct ps_prochandle *, struct utsname *);
+extern char *Pzonename(struct ps_prochandle *, char *, size_t);
+
+extern char *Pexecname(struct ps_prochandle *, char *, size_t);
+extern char *Pobjname(struct ps_prochandle *, uintptr_t, char *, size_t);
+extern int Plmid(struct ps_prochandle *, uintptr_t, Lmid_t *);
+
+typedef int proc_env_f(void *, struct ps_prochandle *, uintptr_t, const char *);
+extern int Penv_iter(struct ps_prochandle *, proc_env_f *, void *);
+extern char *Pgetenv(struct ps_prochandle *, const char *, char *, size_t);
+extern long Pgetauxval(struct ps_prochandle *, int);
+extern const auxv_t *Pgetauxvec(struct ps_prochandle *);
+
+/*
+ * Symbol table iteration interface. The special lmid constants LM_ID_BASE,
+ * LM_ID_LDSO, and PR_LMID_EVERY may be used with Psymbol_iter_by_lmid.
+ */
+typedef int proc_sym_f(void *, const GElf_Sym *, const char *);
+typedef int proc_xsym_f(void *, const GElf_Sym *, const char *,
+ const prsyminfo_t *);
+
+extern int Psymbol_iter(struct ps_prochandle *,
+ const char *, int, int, proc_sym_f *, void *);
+extern int Psymbol_iter_by_addr(struct ps_prochandle *,
+ const char *, int, int, proc_sym_f *, void *);
+extern int Psymbol_iter_by_name(struct ps_prochandle *,
+ const char *, int, int, proc_sym_f *, void *);
+
+extern int Psymbol_iter_by_lmid(struct ps_prochandle *,
+ Lmid_t, const char *, int, int, proc_sym_f *, void *);
+
+extern int Pxsymbol_iter(struct ps_prochandle *,
+ Lmid_t, const char *, int, int, proc_xsym_f *, void *);
+
+/*
+ * 'which' selects which symbol table and can be one of the following.
+ */
+#define PR_SYMTAB 1
+#define PR_DYNSYM 2
+/*
+ * 'type' selects the symbols of interest by binding and type. It is a bit-
+ * mask of one or more of the following flags, whose order MUST match the
+ * order of STB and STT constants in <sys/elf.h>.
+ */
+#define BIND_LOCAL 0x0001
+#define BIND_GLOBAL 0x0002
+#define BIND_WEAK 0x0004
+#define BIND_ANY (BIND_LOCAL|BIND_GLOBAL|BIND_WEAK)
+#define TYPE_NOTYPE 0x0100
+#define TYPE_OBJECT 0x0200
+#define TYPE_FUNC 0x0400
+#define TYPE_SECTION 0x0800
+#define TYPE_FILE 0x1000
+#define TYPE_ANY (TYPE_NOTYPE|TYPE_OBJECT|TYPE_FUNC|TYPE_SECTION|TYPE_FILE)
+
+/*
+ * This returns the rtld_db agent handle for the process.
+ * The handle will become invalid at the next successful exec() and
+ * must not be used beyond that point (see Preset_maps(), below).
+ */
+extern rd_agent_t *Prd_agent(struct ps_prochandle *);
+
+/*
+ * This should be called when an RD_DLACTIVITY event with the
+ * RD_CONSISTENT state occurs via librtld_db's event mechanism.
+ * This makes libproc's address space mappings and symbol tables current.
+ * The variant Pupdate_syms() can be used to preload all symbol tables as well.
+ */
+extern void Pupdate_maps(struct ps_prochandle *);
+extern void Pupdate_syms(struct ps_prochandle *);
+
+/*
+ * This must be called after the victim process performs a successful
+ * exec() if any of the symbol table interface functions have been called
+ * prior to that point. This is essential because an exec() invalidates
+ * all previous symbol table and address space mapping information.
+ * It is always safe to call, but if it is called other than after an
+ * exec() by the victim process it just causes unnecessary overhead.
+ *
+ * The rtld_db agent handle obtained from a previous call to Prd_agent() is
+ * made invalid by Preset_maps() and Prd_agent() must be called again to get
+ * the new handle.
+ */
+extern void Preset_maps(struct ps_prochandle *);
+
+/*
+ * Given an address, Ppltdest() determines if this is part of a PLT, and if
+ * so returns a pointer to the symbol name that will be used for resolution.
+ * If the specified address is not part of a PLT, the function returns NULL.
+ */
+extern const char *Ppltdest(struct ps_prochandle *, uintptr_t);
+
+/*
+ * See comments for Pissyscall(), in Pisadep.h
+ */
+extern int Pissyscall_prev(struct ps_prochandle *, uintptr_t, uintptr_t *);
+
+/*
+ * Stack frame iteration interface.
+ */
+typedef int proc_stack_f(void *, prgregset_t, uint_t, const long *);
+
+extern int Pstack_iter(struct ps_prochandle *,
+ const prgregset_t, proc_stack_f *, void *);
+
+/*
+ * The following functions define a set of passive interfaces: libproc provides
+ * default, empty definitions that are called internally. If a client wishes
+ * to override these definitions, it can simply provide its own version with
+ * the same signature that interposes on the libproc definition.
+ *
+ * If the client program wishes to report additional error information, it
+ * can provide its own version of Perror_printf.
+ *
+ * If the client program wishes to receive a callback after Pcreate forks
+ * but before it execs, it can provide its own version of Pcreate_callback.
+ */
+extern void Perror_printf(struct ps_prochandle *P, const char *format, ...);
+extern void Pcreate_callback(struct ps_prochandle *);
+
+/*
+ * Remove unprintable characters from psinfo.pr_psargs and replace with
+ * whitespace characters so it is safe for printing.
+ */
+extern void proc_unctrl_psinfo(psinfo_t *);
+
+/*
+ * Utility functions for processing arguments which should be /proc files,
+ * pids, and/or core files. The returned error code can be passed to
+ * Pgrab_error() in order to convert it to an error string.
+ */
+#define PR_ARG_PIDS 0x1 /* Allow pid and /proc file arguments */
+#define PR_ARG_CORES 0x2 /* Allow core file arguments */
+
+#define PR_ARG_ANY (PR_ARG_PIDS | PR_ARG_CORES)
+
+extern struct ps_prochandle *proc_arg_grab(const char *, int, int, int *);
+extern struct ps_prochandle *proc_arg_xgrab(const char *, const char *, int,
+ int, int *, const char **);
+extern pid_t proc_arg_psinfo(const char *, int, psinfo_t *, int *);
+extern pid_t proc_arg_xpsinfo(const char *, int, psinfo_t *, int *,
+ const char **);
+
+/*
+ * Utility functions for obtaining information via /proc without actually
+ * performing a Pcreate() or Pgrab():
+ */
+extern int proc_get_auxv(pid_t, auxv_t *, int);
+extern int proc_get_cred(pid_t, prcred_t *, int);
+extern prpriv_t *proc_get_priv(pid_t);
+extern int proc_get_psinfo(pid_t, psinfo_t *);
+extern int proc_get_status(pid_t, pstatus_t *);
+
+/*
+ * Utility functions for debugging tools to convert numeric fault,
+ * signal, and system call numbers to symbolic names:
+ */
+#define FLT2STR_MAX 32 /* max. string length of faults (like SIG2STR_MAX) */
+#define SYS2STR_MAX 32 /* max. string length of syscalls (like SIG2STR_MAX) */
+
+extern char *proc_fltname(int, char *, size_t);
+extern char *proc_signame(int, char *, size_t);
+extern char *proc_sysname(int, char *, size_t);
+
+/*
+ * Utility functions for debugging tools to convert fault, signal, and system
+ * call names back to the numeric constants:
+ */
+extern int proc_str2flt(const char *, int *);
+extern int proc_str2sig(const char *, int *);
+extern int proc_str2sys(const char *, int *);
+
+/*
+ * Utility functions for debugging tools to convert a fault, signal or system
+ * call set to a string representation (e.g. "BUS,SEGV" or "open,close,read").
+ */
+#define PRSIGBUFSZ 1024 /* buffer size for proc_sigset2str() */
+
+extern char *proc_fltset2str(const fltset_t *, const char *, int,
+ char *, size_t);
+extern char *proc_sigset2str(const sigset_t *, const char *, int,
+ char *, size_t);
+extern char *proc_sysset2str(const sysset_t *, const char *, int,
+ char *, size_t);
+
+extern int Pgcore(struct ps_prochandle *, const char *, core_content_t);
+extern int Pfgcore(struct ps_prochandle *, int, core_content_t);
+extern core_content_t Pcontent(struct ps_prochandle *);
+
+/*
+ * Utility functions for debugging tools to convert a string representation of
+ * a fault, signal or system call set back to the numeric value of the
+ * corresponding set type.
+ */
+extern char *proc_str2fltset(const char *, const char *, int, fltset_t *);
+extern char *proc_str2sigset(const char *, const char *, int, sigset_t *);
+extern char *proc_str2sysset(const char *, const char *, int, sysset_t *);
+
+/*
+ * Utility functions for converting between strings and core_content_t.
+ */
+#define PRCONTENTBUFSZ 80 /* buffer size for proc_content2str() */
+
+extern int proc_str2content(const char *, core_content_t *);
+extern int proc_content2str(core_content_t, char *, size_t);
+
+/*
+ * Utility functions for buffering output to stdout, stderr while
+ * process is grabbed. Prevents deadlocks due to pfiles `pgrep xterm`
+ * and other varients.
+ */
+extern int proc_initstdio(void);
+extern int proc_flushstdio(void);
+extern int proc_finistdio(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBPROC_H */
diff --git a/usr/src/lib/libproc/common/llib-lproc b/usr/src/lib/libproc/common/llib-lproc
new file mode 100644
index 0000000000..015de9ca0e
--- /dev/null
+++ b/usr/src/lib/libproc/common/llib-lproc
@@ -0,0 +1,381 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "libproc.h"
+
+/*
+ * usr/src/lib/libproc
+ */
+
+/* Pcontrol.c */
+int _libproc_debug;
+struct ps_prochandle *Pcreate(const char *file, char *const *argv,
+ int *perr, char *path, size_t len);
+const char *Pcreate_error(int error);
+void Pcreate_callback(struct ps_prochandle *Pr);
+struct ps_prochandle *Pgrab(pid_t pid, int gflag, int *perr);
+const char *Pgrab_error(int error);
+void Pfree(struct ps_prochandle *Pr);
+int Pstate(struct ps_prochandle *Pr);
+int Pasfd(struct ps_prochandle *Pr);
+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);
+void Psync(struct ps_prochandle *Pr);
+int Pcreate_agent(struct ps_prochandle *Pr);
+void Pdestroy_agent(struct ps_prochandle *Pr);
+int Preopen(struct ps_prochandle *Pr);
+void Prelease(struct ps_prochandle *Pr, int flags);
+int Pstopstatus(struct ps_prochandle *Pr, long cmd, uint_t msec);
+int Pwait(struct ps_prochandle *Pr, uint_t msec);
+int Pstop(struct ps_prochandle *Pr, uint_t msec);
+int Pdstop(struct ps_prochandle *Pr);
+int Pgetareg(struct ps_prochandle *Pr, int regno, prgreg_t *preg);
+int Pputareg(struct ps_prochandle *Pr, int regno, prgreg_t reg);
+int Psetrun(struct ps_prochandle *Pr, int sig, int flags);
+ssize_t Pread(struct ps_prochandle *Pr,
+ void *buf, size_t nbyte, uintptr_t address);
+ssize_t Pread_string(struct ps_prochandle *Pr,
+ char *buf, size_t nbyte, uintptr_t address);
+ssize_t Pwrite(struct ps_prochandle *Pr,
+ const void *buf, size_t nbyte, uintptr_t address);
+int Pclearsig(struct ps_prochandle *Pr);
+int Pclearfault(struct ps_prochandle *Pr);
+int Psetbkpt(struct ps_prochandle *Pr, uintptr_t address, ulong_t *saved);
+int Pdelbkpt(struct ps_prochandle *Pr, uintptr_t address, ulong_t saved);
+int Pxecbkpt(struct ps_prochandle *Pr, ulong_t saved);
+int Psetwapt(struct ps_prochandle *Pr, const prwatch_t *wp);
+int Pdelwapt(struct ps_prochandle *Pr, const prwatch_t *wp);
+int Pxecwapt(struct ps_prochandle *Pr, const prwatch_t *wp);
+int Psetflags(struct ps_prochandle *Pr, long flags);
+int Punsetflags(struct ps_prochandle *Pr, long flags);
+int Psignal(struct ps_prochandle *Pr, int which, int stop);
+void Psetsignal(struct ps_prochandle *Pr, const sigset_t *set);
+int Pfault(struct ps_prochandle *Pr, int which, int stop);
+void Psetfault(struct ps_prochandle *Pr, const fltset_t *set);
+int Psysentry(struct ps_prochandle *Pr, int which, int stop);
+void Psetsysentry(struct ps_prochandle *Pr, const sysset_t *set);
+int Psysexit(struct ps_prochandle *Pr, int which, int stop);
+void Psetsysexit(struct ps_prochandle *Pr, const sysset_t *set);
+int Plwp_iter(struct ps_prochandle *Pr, proc_lwp_f *func, void *cd);
+int Psyscall(struct ps_prochandle *Pr, sysret_t *,
+ int sysindex, uint_t nargs, argdes_t *argp);
+
+struct ps_lwphandle *Lgrab(struct ps_prochandle *P, lwpid_t lwpid, int *perr);
+const char *Lgrab_error(int error);
+struct ps_prochandle *Lprochandle(struct ps_lwphandle *Lwp);
+void Lfree(struct ps_lwphandle *Lwp);
+int Lctlfd(struct ps_lwphandle *Lwp);
+int Lwait(struct ps_lwphandle *Lwp, uint_t msec);
+int Lstop(struct ps_lwphandle *Lwp, uint_t msec);
+int Ldstop(struct ps_lwphandle *Lwp);
+int Lstate(struct ps_lwphandle *Lwp);
+const lwpsinfo_t *Lpsinfo(struct ps_lwphandle *Lwp);
+const lwpstatus_t *Lstatus(struct ps_lwphandle *Lwp);
+int Lgetareg(struct ps_lwphandle *Lwp, int regno, prgreg_t *preg);
+int Lputareg(struct ps_lwphandle *Lwp, int regno, prgreg_t reg);
+int Lsetrun(struct ps_lwphandle *Lwp, int sig, int flags);
+int Lclearsig(struct ps_lwphandle *Lwp);
+int Lclearfault(struct ps_lwphandle *Lwp);
+int Lxecbkpt(struct ps_lwphandle *Lwp, ulong_t saved);
+int Lxecwapt(struct ps_lwphandle *Lwp, const prwatch_t *wp);
+void Lsync(struct ps_lwphandle *Lwp);
+
+/* Plwpregs.c */
+int Plwp_getregs(struct ps_prochandle *Pr, lwpid_t i, prgregset_t gr);
+int Plwp_setregs(struct ps_prochandle *Pr, lwpid_t i, const prgregset_t gr);
+int Plwp_getfpregs(struct ps_prochandle *Pr, lwpid_t i, prfpregset_t *fp);
+int Plwp_setfpregs(struct ps_prochandle *Pr, lwpid_t i, const prfpregset_t *fp);
+#if defined(sparc) || defined(__sparc)
+int Plwp_getxregs(struct ps_prochandle *Pr, lwpid_t i, prxregset_t *xr);
+int Plwp_setxregs(struct ps_prochandle *Pr, lwpid_t i, const prxregset_t *xr);
+#if defined(__sparcv9)
+int Plwp_getasrs(struct ps_prochandle *Pr, lwpid_t i, asrset_t asrs);
+int Plwp_setasrs(struct ps_prochandle *Pr, lwpid_t i, const asrset_t asrs);
+#endif /* __sparcv9 */
+#endif /* __sparc */
+int Plwp_getpsinfo(struct ps_prochandle *Pr, lwpid_t i, lwpsinfo_t *lps);
+
+/* Pcore.c */
+struct ps_prochandle *Pfgrab_core(int fd, const char *aout, int *perr);
+struct ps_prochandle *Pgrab_core(const char *core, const char *aout,
+ int gflag, int *perr);
+
+/* Pisprocdir.c */
+int Pisprocdir(struct ps_prochandle *Pr, const char *dir);
+
+/* Pservice.c */
+ps_err_e ps_pdmodel(struct ps_prochandle *Pr, int *modelp);
+ps_err_e ps_pread(struct ps_prochandle *Pr,
+ psaddr_t addr, void *buf, size_t size);
+ps_err_e ps_pwrite(struct ps_prochandle *Pr,
+ psaddr_t addr, const void *buf, size_t size);
+ps_err_e ps_pdread(struct ps_prochandle *Pr,
+ psaddr_t addr, void *buf, size_t size);
+ps_err_e ps_pdwrite(struct ps_prochandle *Pr,
+ psaddr_t addr, const void *buf, size_t size);
+ps_err_e ps_ptread(struct ps_prochandle *Pr,
+ psaddr_t addr, void *buf, size_t size);
+ps_err_e ps_ptwrite(struct ps_prochandle *Pr,
+ psaddr_t addr, const void *buf, size_t size);
+ps_err_e ps_pstop(struct ps_prochandle *Pr);
+ps_err_e ps_pcontinue(struct ps_prochandle *Pr);
+ps_err_e ps_lstop(struct ps_prochandle *Pr, lwpid_t lwpid);
+ps_err_e ps_lcontinue(struct ps_prochandle *Pr, lwpid_t lwpid);
+ps_err_e ps_lgetregs(struct ps_prochandle *Pr,
+ lwpid_t lwpid, prgregset_t regs);
+ps_err_e ps_lsetregs(struct ps_prochandle *Pr,
+ lwpid_t lwpid, const prgregset_t regs);
+ps_err_e ps_lgetfpregs(struct ps_prochandle *Pr,
+ lwpid_t lwpid, prfpregset_t *regs);
+ps_err_e ps_lsetfpregs(struct ps_prochandle *Pr,
+ lwpid_t lwpid, const prfpregset_t *regs);
+#if defined(sparc) || defined(__sparc)
+ps_err_e ps_lgetxregsize(struct ps_prochandle *Pr,
+ lwpid_t lwpid, int *xrsize);
+ps_err_e ps_lgetxregs(struct ps_prochandle *Pr,
+ lwpid_t lwpid, caddr_t xregs);
+ps_err_e ps_lsetxregs(struct ps_prochandle *Pr,
+ lwpid_t lwpid, caddr_t xregs);
+#endif /* sparc */
+#if defined(__i386) || defined(__amd64)
+ps_err_e ps_lgetLDT(struct ps_prochandle *Pr,
+ lwpid_t lwpid, struct ssd *ldt);
+#endif /* __i386 || __amd6464 */
+void ps_plog(const char *fmt, ...);
+
+/* Psymtab.c */
+void Pupdate_maps(struct ps_prochandle *Pr);
+void Pupdate_syms(struct ps_prochandle *Pr);
+rd_agent_t *Prd_agent(struct ps_prochandle *Pr);
+const prmap_t *Paddr_to_map(struct ps_prochandle *Pr, uintptr_t addr);
+const prmap_t *Paddr_to_text_map(struct ps_prochandle *Pr, uintptr_t addr);
+const prmap_t *Pname_to_map(struct ps_prochandle *Pr, const char *name);
+const prmap_t *Plmid_to_map(struct ps_prochandle *Pr, Lmid_t lmid,
+ const char *name);
+int Plookup_by_addr(struct ps_prochandle *Pr, uintptr_t addr,
+ char *sym_name_buffer, size_t bufsize, GElf_Sym *symbolp);
+int Plookup_by_name(struct ps_prochandle *Pr,
+ const char *object_name, const char *symbol_name,
+ GElf_Sym *sym);
+int Plookup_by_lmid(struct ps_prochandle *Pr,
+ Lmid_t lmid, const char *object_name, const char *symbol_name,
+ GElf_Sym *sym);
+const rd_loadobj_t *Paddr_to_loadobj(struct ps_prochandle *, uintptr_t);
+const rd_loadobj_t *Pname_to_loadobj(struct ps_prochandle *, const char *);
+const rd_loadobj_t *Plmid_to_loadobj(struct ps_prochandle *, Lmid_t,
+ const char *);
+int Pmapping_iter(struct ps_prochandle *Pr, proc_map_f *func, void *cd);
+int Pobject_iter(struct ps_prochandle *Pr, proc_map_f *func, void *cd);
+char *Pobjname(struct ps_prochandle *Pr, uintptr_t addr,
+ char *buffer, size_t bufsize);
+int Plmid(struct ps_prochandle *Pr, uintptr_t addr, Lmid_t *lmidp);
+int Psymbol_iter(struct ps_prochandle *Pr, const char *object_name,
+ int which, int type, proc_sym_f *func, void *cd);
+int Psymbol_iter_by_lmid(struct ps_prochandle *Pr, Lmid_t lmid,
+ const char *object_name, int which, int type,
+ proc_sym_f *func, void *cd);
+char *Pgetenv(struct ps_prochandle *Pr, const char *name,
+ char *buffer, size_t bufsize);
+char *Pplatform(struct ps_prochandle *Pr, char *s, size_t n);
+int Puname(struct ps_prochandle *Pr, struct utsname *u);
+char *Pzonename(struct ps_prochandle *Pr, char *s, size_t n);
+char *Pexecname(struct ps_prochandle *Pr, char *buffer, size_t bufsize);
+void Preset_maps(struct ps_prochandle *Pr);
+
+ps_err_e ps_pglobal_lookup(struct ps_prochandle *Pr,
+ const char *object_name, const char *sym_name,
+ psaddr_t *sym_addr);
+
+ps_err_e ps_pglobal_sym(struct ps_prochandle *Pr,
+ const char *object_name, const char *sym_name,
+ ps_sym_t *symp);
+
+long Pgetauxval(struct ps_prochandle *Pr, int type);
+const auxv_t *Pgetauxvec(struct ps_prochandle *Pr);
+ps_err_e ps_pauxv(struct ps_prochandle *Pr, const auxv_t **aux);
+
+/* Putil.c */
+void Perror_printf(struct ps_prochandle *Pr, const char *format, ...);
+
+/* pr_door.c */
+int pr_door_info(struct ps_prochandle *Pr, int did, door_info_t *di);
+
+/* pr_exit.c */
+int pr_exit(struct ps_prochandle *Pr, int status);
+int pr_lwp_exit(struct ps_prochandle *Pr);
+
+/* pr_fcntl.c */
+int pr_fcntl(struct ps_prochandle *Pr, int fd, int cmd, void *argp);
+
+/* pr_getitimer.c */
+int pr_getitimer(struct ps_prochandle *Pr,
+ int which, struct itimerval *itv);
+int pr_setitimer(struct ps_prochandle *Pr,
+ int which, const struct itimerval *itv, struct itimerval *oitv);
+
+/* pr_getrctl.c */
+int pr_getrctl(struct ps_prochandle *Pr, const char *rname,
+ rctlblk_t *old_blk, rctlblk_t *new_blk, int rflag);
+int pr_setrctl(struct ps_prochandle *Pr, const char *rname,
+ rctlblk_t *old_blk, rctlblk_t *new_blk, int rflag);
+
+/* pr_getrlimit.c */
+int pr_getrlimit(struct ps_prochandle *Pr,
+ int resource, struct rlimit *rlp);
+int pr_setrlimit(struct ps_prochandle *Pr,
+ int resource, const struct rlimit *rlp);
+int pr_getrlimit64(struct ps_prochandle *Pr,
+ int resource, struct rlimit64 *rlp);
+int pr_setrlimit64(struct ps_prochandle *Pr,
+ int resource, const struct rlimit64 *rlp);
+
+/* pr_getsockname.c */
+int pr_getsockname(struct ps_prochandle *Pr,
+ int sock, struct sockaddr *name, socklen_t *namelen);
+int pr_getpeername(struct ps_prochandle *Pr,
+ int sock, struct sockaddr *name, socklen_t *namelen);
+
+/* pr_ioctl.c */
+int pr_ioctl(struct ps_prochandle *Pr,
+ int fd, int code, void *buf, size_t size);
+
+/* pr_lseek.c */
+off_t pr_lseek(struct ps_prochandle *Pr,
+ int filedes, off_t offset, int whence);
+offset_t pr_llseek(struct ps_prochandle *Pr,
+ int filedes, offset_t offset, int whence);
+
+/* pr_memcntl.c */
+int pr_memcntl(struct ps_prochandle *Pr,
+ caddr_t addr, size_t len, int cmd, caddr_t arg, int attr, int mask);
+
+/* pr_mmap.c */
+void *pr_mmap(struct ps_prochandle *Pr,
+ void *addr, size_t len, int prot, int flags, int fd, off_t off);
+int pr_munmap(struct ps_prochandle *Pr,
+ void *addr, size_t len);
+void *pr_zmap(struct ps_prochandle *Pr,
+ void *addr, size_t len, int prot, int flags);
+
+/* pr_open.c */
+int pr_open(struct ps_prochandle *Pr,
+ const char *filename, int flags, mode_t mode);
+int pr_creat(struct ps_prochandle *Pr,
+ const char *filename, mode_t mode);
+int pr_close(struct ps_prochandle *Pr, int fd);
+int pr_access(struct ps_prochandle *Pr, const char *path, int amode);
+
+/* pr_pbind.c */
+int pr_processor_bind(struct ps_prochandle *Pr, idtype_t, id_t, int, int *);
+int pr_pset_bind(struct ps_prochandle *Pr, int, idtype_t, id_t, int *);
+
+/* pr_rename.c */
+int pr_rename(struct ps_prochandle *Pr, const char *old, const char *new);
+int pr_link(struct ps_prochandle *Pr, const char *exist, const char *new);
+int pr_unlink(struct ps_prochandle *Pr, const char *);
+
+/* pr_sigaction.c */
+int pr_sigaction(struct ps_prochandle *Pr,
+ int sig, const struct sigaction *act, struct sigaction *oact);
+
+/* pr_stat.c */
+int pr_stat(struct ps_prochandle *Pr, const char *path, struct stat *buf);
+int pr_lstat(struct ps_prochandle *Pr, const char *path, struct stat *buf);
+int pr_fstat(struct ps_prochandle *Pr, int fd, struct stat *buf);
+int pr_stat64(struct ps_prochandle *Pr, const char *path,
+ struct stat64 *buf);
+int pr_lstat64(struct ps_prochandle *Pr, const char *path,
+ struct stat64 *buf);
+int pr_fstat64(struct ps_prochandle *Pr, int fd, struct stat64 *buf);
+
+/* pr_statvfs.c */
+int pr_statvfs(struct ps_prochandle *Pr, const char *path, statvfs_t *buf);
+int pr_fstatvfs(struct ps_prochandle *Pr, int fd, statvfs_t *buf);
+
+/* pr_tasksys.c */
+projid_t pr_getprojid(struct ps_prochandle *Pr);
+taskid_t pr_gettaskid(struct ps_prochandle *Pr);
+taskid_t pr_settaskid(struct ps_prochandle *Pr, projid_t project, int flags);
+
+/* pr_waitid.c */
+int pr_waitid(struct ps_prochandle *Pr,
+ idtype_t idtype, id_t id, siginfo_t *infop, int options);
+
+/* proc_get_info.c */
+int proc_get_cred(pid_t pid, prcred_t *credp, int ngroups);
+prpriv_t *proc_get_priv(pid_t pid);
+int proc_get_psinfo(pid_t pid, psinfo_t *psp);
+int proc_get_status(pid_t pid, pstatus_t *psp);
+int proc_get_auxv(pid_t pid, auxv_t *pauxv, int naux);
+
+/* proc_names.c */
+char *proc_fltname(int flt, char *buf, size_t bufsz);
+char *proc_signame(int sig, char *buf, size_t bufsz);
+char *proc_sysname(int sys, char *buf, size_t bufsz);
+
+int proc_str2flt(const char *str, int *fltnum);
+int proc_str2sig(const char *str, int *signum);
+int proc_str2sys(const char *str, int *sysnum);
+
+char *proc_fltset2str(const fltset_t *set, const char *delim, int members,
+ char *buf, size_t nbytes);
+char *proc_sigset2str(const sigset_t *set, const char *delim, int members,
+ char *buf, size_t nbytes);
+char *proc_sysset2str(const sysset_t *set, const char *delim, int members,
+ char *buf, size_t nbytes);
+
+char *proc_str2fltset(const char *str, const char *delim, int members,
+ fltset_t *set);
+char *proc_str2sigset(const char *str, const char *delim, int members,
+ sigset_t *set);
+char *proc_str2sysset(const char *str, const char *delim, int members,
+ sysset_t *set);
+
+int proc_walk(proc_walk_f *func, void *arg, int flags);
+
+/* proc_arg.c */
+struct ps_prochandle *proc_arg_grab(const char *arg,
+ int oflag, int gflag, int *perr);
+
+pid_t proc_arg_psinfo(const char *arg, int oflag, psinfo_t *psp, int *perr);
+void proc_unctrl_psinfo(psinfo_t *psp);
+
+/* proc_set.c */
+int Psetcred(struct ps_prochandle *Pr, const prcred_t *pcred);
+
+/* Pstack.c */
+int Pstack_iter(struct ps_prochandle *Pr,
+ const prgregset_t regs, proc_stack_f *func, void *arg);
+
+/* Pisadep.c */
+const char *Ppltdest(struct ps_prochandle *Pr, uintptr_t addr);
diff --git a/usr/src/lib/libproc/common/pr_door.c b/usr/src/lib/libproc/common/pr_door.c
new file mode 100644
index 0000000000..9a294d40f7
--- /dev/null
+++ b/usr/src/lib/libproc/common/pr_door.c
@@ -0,0 +1,98 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <door.h>
+#include "libproc.h"
+
+/*
+ * door() system calls -- executed by subject process
+ */
+
+int
+pr_door_info(struct ps_prochandle *Pr, int did, door_info_t *di)
+{
+ sysret_t rval; /* return value from _door_info() */
+ argdes_t argd[6]; /* arg descriptors for _door_info() */
+ argdes_t *adp = &argd[0]; /* first argument */
+ int error;
+
+ if (Pr == NULL) /* no subject process */
+ return (door_info(did, di));
+
+ adp->arg_value = did;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+ adp++; /* move to door_info_t argument */
+
+ adp->arg_value = 0;
+ adp->arg_object = di;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_OUTPUT;
+ adp->arg_size = sizeof (door_info_t);
+ adp++; /* move to unused argument */
+
+ adp->arg_value = 0;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+ adp++; /* move to unused argument */
+
+ adp->arg_value = 0;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+ adp++; /* move to unused argument */
+
+ adp->arg_value = 0;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+ adp++; /* move to subcode argument */
+
+ adp->arg_value = DOOR_INFO;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ error = Psyscall(Pr, &rval, SYS_door, 6, &argd[0]);
+
+ if (error) {
+ errno = (error < 0)? ENOSYS : error;
+ return (-1);
+ }
+ return (0);
+}
diff --git a/usr/src/lib/libproc/common/pr_exit.c b/usr/src/lib/libproc/common/pr_exit.c
new file mode 100644
index 0000000000..d9fb874cc2
--- /dev/null
+++ b/usr/src/lib/libproc/common/pr_exit.c
@@ -0,0 +1,110 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1997-2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/lwp.h>
+#include "libproc.h"
+
+/*
+ * exit() system call -- executed by subject process.
+ */
+int
+pr_exit(struct ps_prochandle *Pr, int status)
+{
+ sysret_t rval; /* return value from exit() */
+ argdes_t argd[1]; /* arg descriptors for exit() */
+ argdes_t *adp;
+ int error;
+
+ if (Pr == NULL) { /* no subject process */
+ exit(status);
+ return (0); /* not reached */
+ }
+
+ adp = &argd[0]; /* status argument */
+ adp->arg_value = status;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ error = Psyscall(Pr, &rval, SYS_exit, 1, &argd[0]);
+ /* actually -- never returns. Expect ENOENT */
+
+ if (error < 0) {
+ if (errno == ENOENT) /* expected case */
+ error = ENOENT;
+ else
+ error = ENOSYS;
+ }
+
+ if (error == 0) /* can't happen? */
+ return (rval.sys_rval1);
+
+ if (error == ENOENT) /* expected case */
+ return (0);
+
+ errno = error;
+ return (-1);
+}
+
+/*
+ * lwp_exit() system call -- executed by subject lwp.
+ */
+int
+pr_lwp_exit(struct ps_prochandle *Pr)
+{
+ sysret_t rval; /* return value from lwp_exit() */
+ int error;
+
+ if (Pr == NULL) { /* no subject process */
+ (void) syscall(SYS_lwp_exit);
+ return (0); /* not reached */
+ }
+
+ error = Psyscall(Pr, &rval, SYS_lwp_exit, 0, NULL);
+ /* actually -- never returns. Expect ENOENT */
+
+ if (error < 0) {
+ if (errno == ENOENT) /* expected case */
+ error = ENOENT;
+ else
+ error = ENOSYS;
+ }
+
+ if (error == 0) /* can't happen? */
+ return (rval.sys_rval1);
+
+ if (error == ENOENT) /* expected case */
+ return (0);
+
+ errno = error;
+ return (-1);
+}
diff --git a/usr/src/lib/libproc/common/pr_fcntl.c b/usr/src/lib/libproc/common/pr_fcntl.c
new file mode 100644
index 0000000000..c2c34e1d41
--- /dev/null
+++ b/usr/src/lib/libproc/common/pr_fcntl.c
@@ -0,0 +1,140 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1997-2000 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/isa_defs.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include "libproc.h"
+
+/*
+ * fcntl() system call -- executed by subject process.
+ */
+int
+pr_fcntl(struct ps_prochandle *Pr, int fd, int cmd, void *argp)
+{
+ sysret_t rval; /* return value from fcntl() */
+ argdes_t argd[3]; /* arg descriptors for fcntl() */
+ argdes_t *adp;
+ int error;
+
+ if (Pr == NULL) /* no subject process */
+ return (fcntl(fd, cmd, argp));
+
+ adp = &argd[0]; /* file descriptor argument */
+ adp->arg_value = fd;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ adp++; /* cmd argument */
+#ifdef _LP64
+ if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32) {
+ /*
+ * Guilty knowledge of the large file compilation environment
+ */
+ switch (cmd) {
+ case F_GETLK:
+ cmd = 33;
+ break;
+ case F_SETLK:
+ cmd = 34;
+ break;
+ case F_SETLKW:
+ cmd = 35;
+ break;
+ case F_FREESP:
+ cmd = 27;
+ break;
+ }
+ }
+#endif /* _LP64 */
+ adp->arg_value = cmd;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ adp++; /* argp argument */
+ if (argp == NULL) {
+ adp->arg_value = 0;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+ } else {
+ adp->arg_value = 0;
+ adp->arg_object = argp;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_INOUT;
+ switch (cmd) {
+ case F_GETLK:
+ case F_SETLK:
+ case F_SETLKW:
+ case F_ALLOCSP:
+ case F_FREESP:
+ adp->arg_size = sizeof (struct flock);
+ break;
+#ifdef _LP64
+ case 33:
+ case 34:
+ case 35:
+ case 27:
+ adp->arg_size = sizeof (struct flock64_32);
+#else /* _LP64 */
+ case F_GETLK64:
+ case F_SETLK64:
+ case F_SETLKW64:
+ case F_FREESP64:
+ adp->arg_size = sizeof (struct flock64);
+#endif /* _LP64 */
+ break;
+ case F_SHARE:
+ case F_UNSHARE:
+ adp->arg_size = sizeof (struct fshare);
+ break;
+ default:
+ adp->arg_value = (long)argp;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+ break;
+ }
+ }
+
+ error = Psyscall(Pr, &rval, SYS_fcntl, 3, &argd[0]);
+
+ if (error) {
+ errno = (error > 0)? error : ENOSYS;
+ return (-1);
+ }
+ return (rval.sys_rval1);
+}
diff --git a/usr/src/lib/libproc/common/pr_getitimer.c b/usr/src/lib/libproc/common/pr_getitimer.c
new file mode 100644
index 0000000000..80e1fafdd3
--- /dev/null
+++ b/usr/src/lib/libproc/common/pr_getitimer.c
@@ -0,0 +1,172 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1997-2000 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/isa_defs.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include "libproc.h"
+
+/*
+ * getitimer() system call -- executed by victim process.
+ */
+int
+pr_getitimer(struct ps_prochandle *Pr, int which, struct itimerval *itv)
+{
+ sysret_t rval; /* return value from getitimer() */
+ argdes_t argd[2]; /* arg descriptors for getitimer() */
+ argdes_t *adp;
+ int error;
+#ifdef _LP64
+ int victim32 = (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32);
+ struct itimerval32 itimerval32;
+#endif
+
+ if (Pr == NULL) /* no victim process */
+ return (getitimer(which, itv));
+
+ adp = &argd[0]; /* which argument */
+ adp->arg_value = which;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_object = NULL;
+ adp->arg_size = 0;
+
+ adp++; /* itv argument */
+ adp->arg_value = 0;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_OUTPUT;
+#ifdef _LP64
+ if (victim32) {
+ adp->arg_object = &itimerval32;
+ adp->arg_size = sizeof (itimerval32);
+ } else {
+ adp->arg_object = itv;
+ adp->arg_size = sizeof (*itv);
+ }
+#else /* _LP64 */
+ adp->arg_object = itv;
+ adp->arg_size = sizeof (*itv);
+#endif /* _LP64 */
+
+ error = Psyscall(Pr, &rval, SYS_getitimer, 2, &argd[0]);
+
+ if (error) {
+ errno = (error > 0)? error : ENOSYS;
+ return (-1);
+ }
+#ifdef _LP64
+ if (victim32) {
+ ITIMERVAL32_TO_ITIMERVAL(itv, &itimerval32);
+ }
+#endif /* _LP64 */
+ return (rval.sys_rval1);
+}
+
+/*
+ * setitimer() system call -- executed by victim process.
+ */
+int
+pr_setitimer(struct ps_prochandle *Pr,
+ int which, const struct itimerval *itv, struct itimerval *oitv)
+{
+ sysret_t rval; /* return value from setitimer() */
+ argdes_t argd[3]; /* arg descriptors for setitimer() */
+ argdes_t *adp;
+ int error;
+#ifdef _LP64
+ int victim32 = (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32);
+ struct itimerval32 itimerval32;
+ struct itimerval32 oitimerval32;
+#endif /* _LP64 */
+
+ if (Pr == NULL) /* no victim process */
+ return (setitimer(which, (struct itimerval *)itv, oitv));
+
+ adp = &argd[0]; /* which argument */
+ adp->arg_value = which;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_object = NULL;
+ adp->arg_size = 0;
+
+ adp++; /* itv argument */
+ adp->arg_value = 0;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_INPUT;
+#ifdef _LP64
+ if (victim32) {
+ ITIMERVAL_TO_ITIMERVAL32(&itimerval32, itv);
+ adp->arg_object = (void *)&itimerval32;
+ adp->arg_size = sizeof (itimerval32);
+ } else {
+ adp->arg_object = (void *)itv;
+ adp->arg_size = sizeof (*itv);
+ }
+#else /* _LP64 */
+ adp->arg_object = (void *)itv;
+ adp->arg_size = sizeof (*itv);
+#endif /* _LP64 */
+
+ adp++; /* oitv argument */
+ adp->arg_value = 0;
+ if (oitv == NULL) {
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_object = NULL;
+ adp->arg_size = 0;
+ } else {
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_OUTPUT;
+#ifdef _LP64
+ if (victim32) {
+ adp->arg_object = (void *)&oitimerval32;
+ adp->arg_size = sizeof (oitimerval32);
+ } else {
+ adp->arg_object = oitv;
+ adp->arg_size = sizeof (*oitv);
+ }
+#else /* _LP64 */
+ adp->arg_object = oitv;
+ adp->arg_size = sizeof (*oitv);
+#endif /* _LP64 */
+ }
+
+ error = Psyscall(Pr, &rval, SYS_setitimer, 3, &argd[0]);
+
+ if (error) {
+ errno = (error > 0)? error : ENOSYS;
+ return (-1);
+ }
+#ifdef _LP64
+ if (victim32 && oitv != NULL) {
+ ITIMERVAL32_TO_ITIMERVAL(oitv, &oitimerval32);
+ }
+#endif /* _LP64 */
+ return (rval.sys_rval1);
+}
diff --git a/usr/src/lib/libproc/common/pr_getrctl.c b/usr/src/lib/libproc/common/pr_getrctl.c
new file mode 100644
index 0000000000..d54fc228a6
--- /dev/null
+++ b/usr/src/lib/libproc/common/pr_getrctl.c
@@ -0,0 +1,199 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#define _LARGEFILE64_SOURCE
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <strings.h>
+#include "libproc.h"
+
+/*
+ * getrctl() system call -- executed by subject process
+ */
+int
+pr_getrctl(struct ps_prochandle *Pr, const char *rname,
+ rctlblk_t *old_blk, rctlblk_t *new_blk, int rflag)
+{
+ sysret_t rval;
+ argdes_t argd[6];
+ argdes_t *adp;
+ int error;
+
+ if (Pr == NULL) /* no subject process */
+ return (getrctl(rname, old_blk, new_blk, rflag));
+
+ adp = &argd[0];
+ adp->arg_value = 0; /* switch for getrctl in rctlsys */
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ adp++;
+ adp->arg_value = 0;
+ adp->arg_object = (void *)rname;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = strlen(rname) + 1;
+
+ adp++;
+ if (old_blk == NULL) {
+ adp->arg_value = 0;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+ } else {
+ adp->arg_value = 0;
+ adp->arg_object = old_blk;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = rctlblk_size();
+ }
+
+ adp++;
+ if (new_blk == NULL) {
+ adp->arg_value = 0;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_OUTPUT;
+ adp->arg_size = 0;
+ } else {
+ adp->arg_value = 0;
+ adp->arg_object = new_blk;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_INOUT;
+ adp->arg_size = rctlblk_size();
+ }
+
+ adp++;
+ adp->arg_value = 0; /* obufsz isn't used by getrctl() */
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ adp++;
+ adp->arg_value = rflag;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ error = Psyscall(Pr, &rval, SYS_rctlsys, 6, &argd[0]);
+
+ if (error) {
+ errno = (error > 0) ? error : ENOSYS;
+ return (-1);
+ }
+ return (rval.sys_rval1);
+}
+
+/*
+ * setrctl() system call -- executed by subject process
+ */
+int
+pr_setrctl(struct ps_prochandle *Pr, const char *rname,
+ rctlblk_t *old_blk, rctlblk_t *new_blk, int rflag)
+{
+ sysret_t rval;
+ argdes_t argd[6];
+ argdes_t *adp;
+ int error;
+
+ if (Pr == NULL) /* no subject process */
+ return (setrctl(rname, old_blk, new_blk, rflag));
+
+ adp = &argd[0];
+ adp->arg_value = 1; /* switch for setrctl in rctlsys */
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ adp++;
+ adp->arg_value = 0;
+ adp->arg_object = (void *)rname;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = strlen(rname) + 1;
+
+ adp++;
+ if (old_blk == NULL) {
+ adp->arg_value = 0;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+ } else {
+ adp->arg_value = 0;
+ adp->arg_object = old_blk;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = rctlblk_size();
+ }
+
+ adp++;
+ if (new_blk == NULL) {
+ adp->arg_value = 0;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+ } else {
+ adp->arg_value = 0;
+ adp->arg_object = new_blk;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = rctlblk_size();
+ }
+
+ adp++;
+ adp->arg_value = 0; /* obufsz isn't used by setrctl() */
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ adp++;
+ adp->arg_value = rflag;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ error = Psyscall(Pr, &rval, SYS_rctlsys, 6, &argd[0]);
+
+ if (error) {
+ errno = (error > 0) ? error : ENOSYS;
+ return (-1);
+ }
+ return (rval.sys_rval1);
+}
diff --git a/usr/src/lib/libproc/common/pr_getrlimit.c b/usr/src/lib/libproc/common/pr_getrlimit.c
new file mode 100644
index 0000000000..d5ea456cef
--- /dev/null
+++ b/usr/src/lib/libproc/common/pr_getrlimit.c
@@ -0,0 +1,227 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1997-2000 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#define _LARGEFILE64_SOURCE
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/resource.h>
+#include "libproc.h"
+
+/*
+ * getrlimit() system call -- executed by subject process.
+ */
+int
+pr_getrlimit(struct ps_prochandle *Pr,
+ int resource, struct rlimit *rlp)
+{
+ sysret_t rval; /* return value from getrlimit() */
+ argdes_t argd[2]; /* arg descriptors for getrlimit() */
+ argdes_t *adp;
+ int sysnum;
+ int error;
+
+ if (Pr == NULL) /* no subject process */
+ return (getrlimit(resource, rlp));
+
+ adp = &argd[0]; /* resource argument */
+ adp->arg_value = resource;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ adp++; /* rlp argument */
+ adp->arg_value = 0;
+ adp->arg_object = rlp;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_OUTPUT;
+ adp->arg_size = sizeof (*rlp);
+
+#ifdef _LP64
+ if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32)
+ sysnum = SYS_getrlimit64;
+ else
+ sysnum = SYS_getrlimit;
+#else /* _LP64 */
+ sysnum = SYS_getrlimit;
+#endif /* _LP64 */
+
+ error = Psyscall(Pr, &rval, sysnum, 2, &argd[0]);
+
+ if (error) {
+ errno = (error > 0)? error : ENOSYS;
+ return (-1);
+ }
+ return (rval.sys_rval1);
+}
+
+/*
+ * setrlimit() system call -- executed by subject process.
+ */
+int
+pr_setrlimit(struct ps_prochandle *Pr,
+ int resource, const struct rlimit *rlp)
+{
+ sysret_t rval; /* return value from setrlimit() */
+ argdes_t argd[2]; /* arg descriptors for setrlimit() */
+ argdes_t *adp;
+ int sysnum;
+ int error;
+
+ if (Pr == NULL) /* no subject process */
+ return (setrlimit(resource, rlp));
+
+ adp = &argd[0]; /* resource argument */
+ adp->arg_value = resource;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ adp++; /* rlp argument */
+ adp->arg_value = 0;
+ adp->arg_object = (void *)rlp;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = sizeof (*rlp);
+
+#ifdef _LP64
+ if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32)
+ sysnum = SYS_setrlimit64;
+ else
+ sysnum = SYS_setrlimit;
+#else /* _LP64 */
+ sysnum = SYS_setrlimit;
+#endif /* _LP64 */
+
+ error = Psyscall(Pr, &rval, sysnum, 2, &argd[0]);
+
+ if (error) {
+ errno = (error > 0)? error : ENOSYS;
+ return (-1);
+ }
+ return (rval.sys_rval1);
+}
+
+/*
+ * getrlimit64() system call -- executed by subject process.
+ */
+int
+pr_getrlimit64(struct ps_prochandle *Pr,
+ int resource, struct rlimit64 *rlp)
+{
+ sysret_t rval; /* return value from getrlimit() */
+ argdes_t argd[2]; /* arg descriptors for getrlimit() */
+ argdes_t *adp;
+ int sysnum;
+ int error;
+
+ if (Pr == NULL) /* no subject process */
+ return (getrlimit64(resource, rlp));
+
+ adp = &argd[0]; /* resource argument */
+ adp->arg_value = resource;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ adp++; /* rlp argument */
+ adp->arg_value = 0;
+ adp->arg_object = rlp;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_OUTPUT;
+ adp->arg_size = sizeof (*rlp);
+
+#ifdef _LP64
+ if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32)
+ sysnum = SYS_getrlimit64;
+ else
+ sysnum = SYS_getrlimit;
+#else /* _LP64 */
+ sysnum = SYS_getrlimit64;
+#endif /* _LP64 */
+
+ error = Psyscall(Pr, &rval, sysnum, 2, &argd[0]);
+
+ if (error) {
+ errno = (error > 0)? error : ENOSYS;
+ return (-1);
+ }
+ return (rval.sys_rval1);
+}
+
+/*
+ * setrlimit64() system call -- executed by subject process.
+ */
+int
+pr_setrlimit64(struct ps_prochandle *Pr,
+ int resource, const struct rlimit64 *rlp)
+{
+ sysret_t rval; /* return value from setrlimit() */
+ argdes_t argd[2]; /* arg descriptors for setrlimit() */
+ argdes_t *adp;
+ int sysnum;
+ int error;
+
+ if (Pr == NULL) /* no subject process */
+ return (setrlimit64(resource, rlp));
+
+ adp = &argd[0]; /* resource argument */
+ adp->arg_value = resource;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ adp++; /* rlp argument */
+ adp->arg_value = 0;
+ adp->arg_object = (void *)rlp;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = sizeof (*rlp);
+
+#ifdef _LP64
+ if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32)
+ sysnum = SYS_setrlimit64;
+ else
+ sysnum = SYS_setrlimit;
+#else /* _LP64 */
+ sysnum = SYS_setrlimit64;
+#endif /* _LP64 */
+
+ error = Psyscall(Pr, &rval, sysnum, 2, &argd[0]);
+
+ if (error) {
+ errno = (error > 0)? error : ENOSYS;
+ return (-1);
+ }
+ return (rval.sys_rval1);
+}
diff --git a/usr/src/lib/libproc/common/pr_getsockname.c b/usr/src/lib/libproc/common/pr_getsockname.c
new file mode 100644
index 0000000000..ce29c9bdca
--- /dev/null
+++ b/usr/src/lib/libproc/common/pr_getsockname.c
@@ -0,0 +1,169 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1998-2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stream.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include "libproc.h"
+
+static int
+get_sock_peer_name(struct ps_prochandle *Pr,
+ int syscall, int sock, struct sockaddr *name, socklen_t *namelen)
+{
+ sysret_t rval; /* return value from get{sock|peer}name() */
+ argdes_t argd[4]; /* arg descriptors for get{sock|peer}name() */
+ argdes_t *adp;
+ int error;
+
+ adp = &argd[0]; /* sock argument */
+ adp->arg_value = sock;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ adp++; /* name argument */
+ adp->arg_value = 0;
+ adp->arg_object = name;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_OUTPUT;
+ adp->arg_size = *namelen;
+
+ adp++; /* namelen argument */
+ adp->arg_value = 0;
+ adp->arg_object = namelen;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_INOUT;
+ adp->arg_size = sizeof (*namelen);
+
+ adp++; /* version argument */
+ adp->arg_value = SOV_DEFAULT;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ error = Psyscall(Pr, &rval, syscall, 4, &argd[0]);
+
+ if (error) {
+ errno = (error > 0)? error : ENOSYS;
+ return (-1);
+ }
+ return (0);
+}
+
+/* libc system call interface */
+extern int _so_getsockname(int, struct sockaddr *, socklen_t *, int);
+extern int _so_getpeername(int, struct sockaddr *, socklen_t *, int);
+extern int _so_getsockopt(int, int, int, void *, int *);
+
+/*
+ * getsockname() system call -- executed by subject process
+ */
+int
+pr_getsockname(struct ps_prochandle *Pr,
+ int sock, struct sockaddr *name, socklen_t *namelen)
+{
+ if (Pr == NULL) /* no subject process */
+ return (_so_getsockname(sock, name, namelen, SOV_DEFAULT));
+
+ return (get_sock_peer_name(Pr, SYS_getsockname, sock, name, namelen));
+}
+
+/*
+ * getpeername() system call -- executed by subject process
+ */
+int
+pr_getpeername(struct ps_prochandle *Pr,
+ int sock, struct sockaddr *name, socklen_t *namelen)
+{
+ if (Pr == NULL) /* no subject process */
+ return (_so_getpeername(sock, name, namelen, SOV_DEFAULT));
+
+ return (get_sock_peer_name(Pr, SYS_getpeername, sock, name, namelen));
+}
+
+int
+pr_getsockopt(struct ps_prochandle *Pr,
+ int sock, int level, int optname, void *optval, int *optlen)
+{
+ sysret_t rval; /* return value from getsockopt() */
+ argdes_t argd[5]; /* arg descriptors for getsockopt() */
+ argdes_t *adp;
+ int error;
+
+ if (Pr == NULL) /* no subject process */
+ return (_so_getsockopt(sock, level, optname, optval, optlen));
+
+ adp = &argd[0]; /* sock argument */
+ adp->arg_value = sock;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ adp++; /* level argument */
+ adp->arg_value = level;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ adp++; /* optname argument */
+ adp->arg_value = optname;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ adp++; /* optval argument */
+ adp->arg_value = 0;
+ adp->arg_object = optval;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_OUTPUT;
+ adp->arg_size = optlen == NULL ? 0 : *optlen;
+
+ adp++; /* optlen argument */
+ adp->arg_value = 0;
+ adp->arg_object = optlen;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_INOUT;
+ adp->arg_size = sizeof (*optlen);
+
+ error = Psyscall(Pr, &rval, SYS_getsockopt, 5, &argd[0]);
+
+ if (error) {
+ errno = (error > 0)? error : ENOSYS;
+ return (-1);
+ }
+ return (0);
+}
diff --git a/usr/src/lib/libproc/common/pr_ioctl.c b/usr/src/lib/libproc/common/pr_ioctl.c
new file mode 100644
index 0000000000..c33f778031
--- /dev/null
+++ b/usr/src/lib/libproc/common/pr_ioctl.c
@@ -0,0 +1,84 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1997-2000 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include "libproc.h"
+
+/*
+ * ioctl() system call -- executed by subject process.
+ */
+int
+pr_ioctl(struct ps_prochandle *Pr, int fd, int code, void *buf, size_t size)
+{
+ sysret_t rval; /* return value from ioctl() */
+ argdes_t argd[3]; /* arg descriptors for ioctl() */
+ argdes_t *adp = &argd[0]; /* first argument */
+ int error;
+
+ if (Pr == NULL) /* no subject process */
+ return (ioctl(fd, code, buf));
+
+ adp->arg_value = fd;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+ adp++; /* move to code argument */
+
+ adp->arg_value = code;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+ adp++; /* move to buffer argument */
+
+ if (size == 0) {
+ adp->arg_value = (long)buf;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+ } else {
+ adp->arg_value = 0;
+ adp->arg_object = buf;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_INOUT;
+ adp->arg_size = size;
+ }
+
+ error = Psyscall(Pr, &rval, SYS_ioctl, 3, &argd[0]);
+
+ if (error) {
+ errno = (error > 0)? error : ENOSYS;
+ return (-1);
+ }
+ return (rval.sys_rval1);
+}
diff --git a/usr/src/lib/libproc/common/pr_lseek.c b/usr/src/lib/libproc/common/pr_lseek.c
new file mode 100644
index 0000000000..1d46f2db01
--- /dev/null
+++ b/usr/src/lib/libproc/common/pr_lseek.c
@@ -0,0 +1,187 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1998-2000 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include "libproc.h"
+
+typedef union {
+ offset_t full; /* full 64 bit offset value */
+ uint32_t half[2]; /* two 32-bit halves */
+} offsets_t;
+
+/*
+ * lseek() system call -- executed by subject process.
+ */
+off_t
+pr_lseek(struct ps_prochandle *Pr, int filedes, off_t offset, int whence)
+{
+ int syscall; /* SYS_lseek or SYS_llseek */
+ int nargs; /* 3 or 4, depending on syscall */
+ offsets_t off;
+ sysret_t rval; /* return value from lseek() */
+ argdes_t argd[4]; /* arg descriptors for lseek() */
+ argdes_t *adp;
+ int error;
+
+ if (Pr == NULL)
+ return (lseek(filedes, offset, whence));
+
+ adp = &argd[0]; /* filedes argument */
+ adp->arg_value = filedes;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ adp++; /* offset argument */
+ if (Pstatus(Pr)->pr_dmodel == PR_MODEL_NATIVE) {
+ syscall = SYS_lseek;
+ nargs = 3;
+ adp->arg_value = offset;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+ } else {
+ syscall = SYS_llseek;
+ nargs = 4;
+ off.full = offset;
+ adp->arg_value = off.half[0]; /* first 32 bits */
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+ adp++;
+ adp->arg_value = off.half[1]; /* second 32 bits */
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+ }
+
+ adp++; /* whence argument */
+ adp->arg_value = whence;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ error = Psyscall(Pr, &rval, syscall, nargs, &argd[0]);
+
+ if (error) {
+ errno = (error > 0)? error : ENOSYS;
+ return ((off_t)(-1));
+ }
+
+ if (Pstatus(Pr)->pr_dmodel == PR_MODEL_NATIVE)
+ offset = rval.sys_rval1;
+ else {
+ off.half[0] = (uint32_t)rval.sys_rval1;
+ off.half[1] = (uint32_t)rval.sys_rval2;
+ offset = (off_t)off.full;
+ }
+
+ return (offset);
+}
+
+/*
+ * llseek() system call -- executed by subject process.
+ */
+offset_t
+pr_llseek(struct ps_prochandle *Pr, int filedes, offset_t offset, int whence)
+{
+ int syscall; /* SYS_lseek or SYS_llseek */
+ int nargs; /* 3 or 4, depending on syscall */
+ offsets_t off;
+ sysret_t rval; /* return value from llseek() */
+ argdes_t argd[4]; /* arg descriptors for llseek() */
+ argdes_t *adp;
+ int error;
+
+ if (Pr == NULL)
+ return (llseek(filedes, offset, whence));
+
+ adp = &argd[0]; /* filedes argument */
+ adp->arg_value = filedes;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ adp++; /* offset argument */
+ if (Pstatus(Pr)->pr_dmodel == PR_MODEL_LP64) {
+ syscall = SYS_lseek;
+ nargs = 3;
+ adp->arg_value = offset;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+ } else {
+ syscall = SYS_llseek;
+ nargs = 4;
+ off.full = offset;
+ adp->arg_value = off.half[0]; /* first 32 bits */
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+ adp++;
+ adp->arg_value = off.half[1]; /* second 32 bits */
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+ }
+
+ adp++; /* whence argument */
+ adp->arg_value = whence;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ error = Psyscall(Pr, &rval, syscall, nargs, &argd[0]);
+
+ if (error) {
+ errno = (error > 0)? error : ENOSYS;
+ return ((offset_t)(-1));
+ }
+
+ if (Pstatus(Pr)->pr_dmodel == PR_MODEL_LP64)
+ offset = rval.sys_rval1;
+ else {
+ off.half[0] = (uint32_t)rval.sys_rval1;
+ off.half[1] = (uint32_t)rval.sys_rval2;
+ offset = off.full;
+ }
+
+ return (offset);
+}
diff --git a/usr/src/lib/libproc/common/pr_memcntl.c b/usr/src/lib/libproc/common/pr_memcntl.c
new file mode 100644
index 0000000000..0b2a306e75
--- /dev/null
+++ b/usr/src/lib/libproc/common/pr_memcntl.c
@@ -0,0 +1,116 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1998-2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include "libproc.h"
+
+/*
+ * memcntl() system call -- executed by subject process
+ */
+
+int
+pr_memcntl(struct ps_prochandle *Pr,
+ caddr_t addr, size_t len, int cmd, caddr_t arg, int attr, int mask)
+{
+ sysret_t rval; /* return value from memcntl() */
+ argdes_t argd[6]; /* arg descriptors for memcntl() */
+ argdes_t *adp;
+ int error;
+
+ if (Pr == NULL) /* no subject process */
+ return (memcntl(addr, len, cmd, arg, attr, mask));
+
+ adp = &argd[0]; /* addr argument */
+ adp->arg_value = (uintptr_t)addr;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ adp++; /* len argument */
+ adp->arg_value = len;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ adp++; /* cmd argument */
+ adp->arg_value = cmd;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ adp++; /* arg argument */
+ if (cmd == MC_HAT_ADVISE) {
+ adp->arg_value = 0;
+ adp->arg_object = arg;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_INPUT;
+#ifdef _LP64
+ if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32)
+ adp->arg_size = sizeof (struct memcntl_mha32);
+ else
+ adp->arg_size = sizeof (struct memcntl_mha);
+#else
+ adp->arg_size = sizeof (struct memcntl_mha);
+#endif
+ } else {
+ adp->arg_value = (uintptr_t)arg;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+ }
+
+ adp++; /* attr argument */
+ adp->arg_value = attr;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ adp++; /* mask argument */
+ adp->arg_value = mask;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ error = Psyscall(Pr, &rval, SYS_memcntl, 6, &argd[0]);
+
+ if (error) {
+ errno = (error > 0)? error : ENOSYS;
+ return (-1);
+ }
+ return (0);
+}
diff --git a/usr/src/lib/libproc/common/pr_meminfo.c b/usr/src/lib/libproc/common/pr_meminfo.c
new file mode 100644
index 0000000000..475c728267
--- /dev/null
+++ b/usr/src/lib/libproc/common/pr_meminfo.c
@@ -0,0 +1,188 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include "libproc.h"
+#include "Pcontrol.h"
+#include "Putil.h"
+
+
+int
+pr_meminfo(struct ps_prochandle *Pr, const uint64_t *addrs,
+ int addr_count, const uint_t *info, int info_count,
+ uint64_t *outdata, uint_t *validity)
+{
+
+
+ int error;
+ sysret_t rval;
+ argdes_t argd[7];
+ argdes_t *adp = &argd[0];
+ struct meminfo m;
+#ifdef _LP64
+ struct meminfo32 m32;
+ int model;
+#endif
+ int retval = -1;
+ uintptr_t inaddr, infoaddr, outaddr, validityaddr;
+ size_t outarraysize, infoarraysize;
+ size_t inarraysize, validityarraysize;
+ size_t totalsize;
+ char *totalmap = MAP_FAILED;
+
+ inarraysize = addr_count * sizeof (uint64_t);
+ outarraysize = sizeof (uint64_t) * addr_count * info_count;
+ infoarraysize = info_count * sizeof (uint_t);
+ validityarraysize = sizeof (uint_t) * addr_count;
+
+
+ totalsize = inarraysize + outarraysize + infoarraysize +
+ validityarraysize;
+
+ if ((totalmap = pr_zmap(Pr, 0, totalsize, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE)) == MAP_FAILED) {
+ dprintf("pr_meminfo: mmap failed\n");
+ goto out;
+ }
+
+ inaddr = (uintptr_t)totalmap;
+
+ outaddr = inaddr + inarraysize;
+
+ infoaddr = outaddr + outarraysize;
+
+ validityaddr = infoaddr + infoarraysize;
+
+ if (Pwrite(Pr, addrs, inarraysize, inaddr) != inarraysize) {
+ dprintf("pr_meminfo: Pwrite inaddr failed \n");
+ goto out;
+ }
+
+ if (Pwrite(Pr, info, infoarraysize, infoaddr) !=
+ infoarraysize) {
+ dprintf("pr_meminfo: Pwrite info failed \n");
+ goto out;
+ }
+
+#ifdef _LP64
+ model = Pr->status.pr_dmodel;
+ if (model == PR_MODEL_ILP32) {
+ m32.mi_info_count = info_count;
+ m32.mi_inaddr = (caddr32_t)inaddr;
+ m32.mi_outdata = (caddr32_t)outaddr;
+ m32.mi_info_req = (caddr32_t)infoaddr;
+ m32.mi_validity = (caddr32_t)validityaddr;
+ } else
+#endif
+ {
+ m.mi_info_count = info_count;
+ m.mi_inaddr = (uint64_t *)inaddr;
+ m.mi_outdata = (uint64_t *)outaddr;
+ m.mi_info_req = (uint_t *)infoaddr;
+ m.mi_validity = (uint_t *)validityaddr;
+ }
+
+
+ /*
+ * initial command
+ */
+
+ adp->arg_value = MISYS_MEMINFO;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+ adp++;
+
+ /*
+ * length of input address vector
+ */
+
+ adp->arg_value = addr_count;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+ adp++;
+
+ /*
+ * information wanted vector
+ */
+
+ adp->arg_value = 0;
+#ifdef _LP64
+ if (model == PR_MODEL_ILP32) {
+ adp->arg_object = &m32;
+ adp->arg_size = sizeof (struct meminfo32);
+ } else
+#endif
+ {
+ adp->arg_object = &m;
+ adp->arg_size = sizeof (struct meminfo);
+ }
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_INPUT;
+
+
+ error = Psyscall(Pr, &rval, SYS_meminfosys, 3, &argd[0]);
+
+ if (error) {
+ errno = (error > 0) ? error: ENOSYS;
+ goto out;
+ }
+
+ /* syscall was successful, copy out the data */
+
+ if ((Pread(Pr, outdata, outarraysize, outaddr)) != outarraysize) {
+ dprintf("pr_meminfo: Pread of outarray failed\n");
+ goto out;
+ }
+
+ if (Pread(Pr, validity, validityarraysize, validityaddr)
+ != validityarraysize) {
+ dprintf("pr_meminfo: Pread of validity array failed\n");
+ goto out;
+ }
+
+ retval = rval.sys_rval1;
+
+out:
+
+ if (totalmap != MAP_FAILED &&
+ pr_munmap(Pr, totalmap, totalsize) == -1) {
+ dprintf("pr_meminfo: munmap failed\n");
+ retval = -1;
+ }
+
+ return (retval);
+
+}
diff --git a/usr/src/lib/libproc/common/pr_mmap.c b/usr/src/lib/libproc/common/pr_mmap.c
new file mode 100644
index 0000000000..2c30aaf224
--- /dev/null
+++ b/usr/src/lib/libproc/common/pr_mmap.c
@@ -0,0 +1,145 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1997-2000 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include "libproc.h"
+
+/*
+ * mmap() system call -- executed by subject process
+ */
+void *
+pr_mmap(struct ps_prochandle *Pr,
+ void *addr, size_t len, int prot, int flags, int fd, off_t off)
+{
+ sysret_t rval; /* return value from mmap() */
+ argdes_t argd[6]; /* arg descriptors for mmap() */
+ argdes_t *adp;
+ int error;
+
+ if (Pr == NULL) /* no subject process */
+ return (mmap(addr, len, prot, flags, fd, off));
+
+ adp = &argd[0]; /* addr argument */
+ adp->arg_value = (long)addr;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ adp++; /* len argument */
+ adp->arg_value = (long)len;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ adp++; /* prot argument */
+ adp->arg_value = (long)prot;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ adp++; /* flags argument */
+ adp->arg_value = (long)(_MAP_NEW|flags);
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ adp++; /* fd argument */
+ adp->arg_value = (long)fd;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ adp++; /* off argument */
+ adp->arg_value = (long)off;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ error = Psyscall(Pr, &rval, SYS_mmap, 6, &argd[0]);
+
+ if (error) {
+ errno = (error > 0)? error : ENOSYS;
+ return ((void *)(-1));
+ }
+ return ((void *)rval.sys_rval1);
+}
+
+/*
+ * munmap() system call -- executed by subject process
+ */
+int
+pr_munmap(struct ps_prochandle *Pr, void *addr, size_t len)
+{
+ sysret_t rval; /* return value from munmap() */
+ argdes_t argd[2]; /* arg descriptors for munmap() */
+ argdes_t *adp;
+ int error;
+
+ if (Pr == NULL) /* no subject process */
+ return (munmap(addr, len));
+
+ adp = &argd[0]; /* addr argument */
+ adp->arg_value = (long)addr;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ adp++; /* len argument */
+ adp->arg_value = (long)len;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ error = Psyscall(Pr, &rval, SYS_munmap, 2, &argd[0]);
+
+ if (error) {
+ errno = (error > 0)? error : ENOSYS;
+ return (-1);
+ }
+ return (rval.sys_rval1);
+}
+
+/*
+ * zmap() -- convenience function; mmap(MAP_ANON) executed by subject process.
+ */
+void *
+pr_zmap(struct ps_prochandle *Pr, void *addr, size_t len, int prot, int flags)
+{
+ return (pr_mmap(Pr, addr, len, prot, flags | MAP_ANON, -1, (off_t)0));
+}
diff --git a/usr/src/lib/libproc/common/pr_open.c b/usr/src/lib/libproc/common/pr_open.c
new file mode 100644
index 0000000000..5ea4ea1393
--- /dev/null
+++ b/usr/src/lib/libproc/common/pr_open.c
@@ -0,0 +1,183 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1997-2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "libproc.h"
+
+/*
+ * open() system call -- executed by subject process.
+ */
+int
+pr_open(struct ps_prochandle *Pr, const char *filename, int flags, mode_t mode)
+{
+ sysret_t rval; /* return value from open() */
+ argdes_t argd[3]; /* arg descriptors for open() */
+ argdes_t *adp;
+ int error;
+
+ if (Pr == NULL) /* no subject process */
+ return (open(filename, flags, mode));
+
+ adp = &argd[0]; /* filename argument */
+ adp->arg_value = 0;
+ adp->arg_object = (void *)filename;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = strlen(filename)+1;
+
+ adp++; /* flags argument */
+ adp->arg_value = (long)flags;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ adp++; /* mode argument */
+ adp->arg_value = (long)mode;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ error = Psyscall(Pr, &rval, SYS_open, 3, &argd[0]);
+
+ if (error) {
+ errno = (error > 0)? error : ENOSYS;
+ return (-1);
+ }
+ return (rval.sys_rval1);
+}
+
+/*
+ * creat() system call -- executed by subject process.
+ */
+int
+pr_creat(struct ps_prochandle *Pr, const char *filename, mode_t mode)
+{
+ sysret_t rval; /* return value from creat() */
+ argdes_t argd[2]; /* arg descriptors for creat() */
+ argdes_t *adp;
+ int error;
+
+ if (Pr == NULL) /* no subject process */
+ return (creat(filename, mode));
+
+ adp = &argd[0]; /* filename argument */
+ adp->arg_value = 0;
+ adp->arg_object = (void *)filename;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = strlen(filename)+1;
+
+ adp++; /* mode argument */
+ adp->arg_value = (long)mode;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ error = Psyscall(Pr, &rval, SYS_creat, 2, &argd[0]);
+
+ if (error) {
+ errno = (error > 0)? error : ENOSYS;
+ return (-1);
+ }
+ return (rval.sys_rval1);
+}
+
+/*
+ * close() system call -- executed by subject process.
+ */
+int
+pr_close(struct ps_prochandle *Pr, int fd)
+{
+ sysret_t rval; /* return value from close() */
+ argdes_t argd[1]; /* arg descriptors for close() */
+ argdes_t *adp;
+ int error;
+
+ if (Pr == NULL) /* no subject process */
+ return (close(fd));
+
+ adp = &argd[0]; /* fd argument */
+ adp->arg_value = (int)fd;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ error = Psyscall(Pr, &rval, SYS_close, 1, &argd[0]);
+
+ if (error) {
+ errno = (error > 0)? error : ENOSYS;
+ return (-1);
+ }
+ return (rval.sys_rval1);
+}
+
+/*
+ * access() system call -- executed by subject process.
+ */
+int
+pr_access(struct ps_prochandle *Pr, const char *path, int amode)
+{
+ sysret_t rval; /* return from access() */
+ argdes_t argd[2]; /* arg descriptors for access() */
+ argdes_t *adp;
+ int err;
+
+ if (Pr == NULL) /* no subject process */
+ return (access(path, amode));
+
+ adp = &argd[0]; /* path argument */
+ adp->arg_value = 0;
+ adp->arg_object = (void *)path;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = strlen(path) + 1;
+
+ adp++; /* amode argument */
+ adp->arg_value = (long)amode;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ err = Psyscall(Pr, &rval, SYS_access, 2, &argd[0]);
+
+ if (err) {
+ errno = (err > 0) ? err : ENOSYS;
+ return (-1);
+ }
+
+ return (rval.sys_rval1);
+}
diff --git a/usr/src/lib/libproc/common/pr_pbind.c b/usr/src/lib/libproc/common/pr_pbind.c
new file mode 100644
index 0000000000..1a9f6de689
--- /dev/null
+++ b/usr/src/lib/libproc/common/pr_pbind.c
@@ -0,0 +1,155 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/procset.h>
+#include <sys/processor.h>
+#include <sys/pset.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include "libproc.h"
+
+int
+pr_processor_bind(struct ps_prochandle *Pr, idtype_t idtype, id_t id,
+ int processorid, int *obind)
+{
+ sysret_t rval; /* return value */
+ argdes_t argd[4]; /* arg descriptors */
+ argdes_t *adp = &argd[0]; /* first argument */
+ int error;
+
+ if (Pr == NULL) /* no subject process */
+ return (processor_bind(idtype, id, processorid, obind));
+
+ adp->arg_value = idtype; /* idtype */
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+ adp++;
+
+ adp->arg_value = id; /* id */
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+ adp++;
+
+ adp->arg_value = processorid; /* processorid */
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+ adp++;
+
+ if (obind == NULL) {
+ adp->arg_value = 0; /* obind */
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+ } else {
+ adp->arg_value = 0;
+ adp->arg_object = obind;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_INOUT;
+ adp->arg_size = sizeof (int);
+ }
+
+ error = Psyscall(Pr, &rval, SYS_processor_bind, 4, &argd[0]);
+
+ if (error) {
+ errno = (error < 0)? ENOSYS : error;
+ return (-1);
+ }
+ return (rval.sys_rval1);
+}
+
+int
+pr_pset_bind(struct ps_prochandle *Pr, int pset, idtype_t idtype, id_t id,
+ int *opset)
+{
+ sysret_t rval; /* return value */
+ argdes_t argd[5]; /* arg descriptors */
+ argdes_t *adp = &argd[0]; /* first argument */
+ int error;
+
+ if (Pr == NULL) /* no subject process */
+ return (pset_bind(pset, idtype, id, opset));
+
+ adp->arg_value = PSET_BIND; /* PSET_BIND */
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+ adp++;
+
+ adp->arg_value = pset; /* pset */
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+ adp++;
+
+ adp->arg_value = idtype; /* idtype */
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+ adp++;
+
+ adp->arg_value = id; /* id */
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+ adp++;
+
+ if (opset == NULL) {
+ adp->arg_value = 0; /* opset */
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+ } else {
+ adp->arg_value = 0;
+ adp->arg_object = opset;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_INOUT;
+ adp->arg_size = sizeof (int);
+ }
+
+ error = Psyscall(Pr, &rval, SYS_pset, 5, &argd[0]);
+
+ if (error) {
+ errno = (error < 0)? ENOSYS : error;
+ return (-1);
+ }
+ return (rval.sys_rval1);
+}
diff --git a/usr/src/lib/libproc/common/pr_rename.c b/usr/src/lib/libproc/common/pr_rename.c
new file mode 100644
index 0000000000..e6c5074eea
--- /dev/null
+++ b/usr/src/lib/libproc/common/pr_rename.c
@@ -0,0 +1,137 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1998-2000 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include "libproc.h"
+
+/*
+ * rename() system call -- executed by subject process.
+ */
+int
+pr_rename(struct ps_prochandle *Pr, const char *old, const char *new)
+{
+ sysret_t rval;
+ argdes_t argd[2];
+ argdes_t *adp;
+ int error;
+
+ if (Pr == NULL)
+ return (rename(old, new));
+
+ adp = &argd[0]; /* old argument */
+ adp->arg_value = 0;
+ adp->arg_object = (void *)old;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = strlen(old) + 1;
+
+ adp++; /* new argument */
+ adp->arg_value = 0;
+ adp->arg_object = (void *)new;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = strlen(new) + 1;
+
+ error = Psyscall(Pr, &rval, SYS_rename, 2, &argd[0]);
+
+ if (error) {
+ errno = (error > 0) ? error : ENOSYS;
+ return (-1);
+ }
+ return (rval.sys_rval1);
+}
+
+/*
+ * link() system call -- executed by subject process.
+ */
+int
+pr_link(struct ps_prochandle *Pr, const char *existing, const char *new)
+{
+ sysret_t rval;
+ argdes_t argd[2];
+ argdes_t *adp;
+ int error;
+
+ if (Pr == NULL)
+ return (link(existing, new));
+
+ adp = &argd[0]; /* existing argument */
+ adp->arg_value = 0;
+ adp->arg_object = (void *)existing;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = strlen(existing) + 1;
+
+ adp++; /* new argument */
+ adp->arg_value = 0;
+ adp->arg_object = (void *)new;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = strlen(new) + 1;
+
+ error = Psyscall(Pr, &rval, SYS_link, 2, &argd[0]);
+
+ if (error) {
+ errno = (error > 0) ? error : ENOSYS;
+ return (-1);
+ }
+ return (rval.sys_rval1);
+}
+
+/*
+ * unlink() system call -- executed by subject process.
+ */
+int
+pr_unlink(struct ps_prochandle *Pr, const char *path)
+{
+ sysret_t rval;
+ argdes_t argd[1];
+ argdes_t *adp;
+ int error;
+
+ if (Pr == NULL)
+ return (unlink(path));
+
+ adp = &argd[0]; /* path argument */
+ adp->arg_value = 0;
+ adp->arg_object = (void *)path;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = strlen(path) + 1;
+
+ error = Psyscall(Pr, &rval, SYS_unlink, 1, &argd[0]);
+
+ if (error) {
+ errno = (error > 0) ? error : ENOSYS;
+ return (-1);
+ }
+ return (rval.sys_rval1);
+}
diff --git a/usr/src/lib/libproc/common/pr_sigaction.c b/usr/src/lib/libproc/common/pr_sigaction.c
new file mode 100644
index 0000000000..2ac068ecbb
--- /dev/null
+++ b/usr/src/lib/libproc/common/pr_sigaction.c
@@ -0,0 +1,126 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1997-2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/isa_defs.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <memory.h>
+#include <errno.h>
+
+#include "P32ton.h"
+#include "libproc.h"
+
+/*
+ * sigaction() system call -- executed by subject process.
+ */
+int
+pr_sigaction(struct ps_prochandle *Pr,
+ int sig, const struct sigaction *act, struct sigaction *oact)
+{
+ sysret_t rval; /* return value from sigaction() */
+ argdes_t argd[3]; /* arg descriptors for sigaction() */
+ argdes_t *adp;
+ int error;
+#ifdef _LP64
+ struct sigaction32 act32;
+ struct sigaction32 oact32;
+#endif /* _LP64 */
+
+ if (Pr == NULL) /* no subject process */
+ return (sigaction(sig, act, oact));
+
+ adp = &argd[0]; /* sig argument */
+ adp->arg_value = sig;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ adp++; /* act argument */
+ adp->arg_value = 0;
+ if (act == NULL) {
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_object = NULL;
+ adp->arg_size = 0;
+ } else {
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_INPUT;
+#ifdef _LP64
+ if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32) {
+ sigaction_n_to_32(act, &act32);
+ adp->arg_object = &act32;
+ adp->arg_size = sizeof (act32);
+ } else {
+ adp->arg_object = (void *)act;
+ adp->arg_size = sizeof (*act);
+ }
+#else /* _LP64 */
+ adp->arg_object = (void *)act;
+ adp->arg_size = sizeof (*act);
+#endif /* _LP64 */
+ }
+
+ adp++; /* oact argument */
+ adp->arg_value = 0;
+ if (oact == NULL) {
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_object = NULL;
+ adp->arg_size = 0;
+ } else {
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_OUTPUT;
+#ifdef _LP64
+ if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32) {
+ adp->arg_object = &oact32;
+ adp->arg_size = sizeof (oact32);
+ } else {
+ adp->arg_object = oact;
+ adp->arg_size = sizeof (*oact);
+ }
+#else /* _LP64 */
+ adp->arg_object = oact;
+ adp->arg_size = sizeof (*oact);
+#endif /* _LP64 */
+ }
+
+ error = Psyscall(Pr, &rval, SYS_sigaction, 3, &argd[0]);
+
+ if (error) {
+ errno = (error > 0)? error : ENOSYS;
+ return (-1);
+ }
+#ifdef _LP64
+ if (oact != NULL && Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32)
+ sigaction_32_to_n(&oact32, oact);
+#endif /* _LP64 */
+ return (rval.sys_rval1);
+}
diff --git a/usr/src/lib/libproc/common/pr_stat.c b/usr/src/lib/libproc/common/pr_stat.c
new file mode 100644
index 0000000000..cac5bf9c88
--- /dev/null
+++ b/usr/src/lib/libproc/common/pr_stat.c
@@ -0,0 +1,500 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1997-2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/isa_defs.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include "libproc.h"
+
+#ifdef _LP64
+/*
+ * in case of 64-bit *stat() and *stat64 library call and 32-bit subject
+ * process convert 64-bit struct stat/stat64 into 32-bit struct stat64
+ */
+static void
+stat64_32_to_n(struct stat64_32 *src, struct stat *dest)
+{
+ (void) memset(dest, 0, sizeof (*dest));
+ dest->st_dev = DEVEXPL(src->st_dev);
+ dest->st_ino = (ino_t)src->st_ino;
+ dest->st_mode = (mode_t)src->st_mode;
+ dest->st_nlink = (nlink_t)src->st_nlink;
+ dest->st_uid = (uid_t)src->st_uid;
+ dest->st_gid = (gid_t)src->st_gid;
+ dest->st_rdev = DEVEXPL(src->st_rdev);
+ dest->st_size = (off_t)src->st_size;
+ TIMESPEC32_TO_TIMESPEC(&dest->st_atim, &src->st_atim);
+ TIMESPEC32_TO_TIMESPEC(&dest->st_mtim, &src->st_mtim);
+ TIMESPEC32_TO_TIMESPEC(&dest->st_ctim, &src->st_ctim);
+ dest->st_blksize = (blksize_t)src->st_blksize;
+ dest->st_blocks = (blkcnt_t)src->st_blocks;
+ (void) memcpy(dest->st_fstype, src->st_fstype,
+ sizeof (dest->st_fstype));
+}
+#endif /* _LP64 */
+
+/*
+ * stat() system call -- executed by subject process
+ */
+int
+pr_stat(struct ps_prochandle *Pr, const char *path, struct stat *buf)
+{
+ sysret_t rval; /* return value from stat() */
+ argdes_t argd[3]; /* arg descriptors for stat() */
+ argdes_t *adp = &argd[0]; /* first argument */
+ int syscall; /* stat, xstat or stat64 */
+ int nargs = 2; /* number of actual arguments */
+ int error;
+#ifdef _LP64
+ struct stat64_32 statb64_32;
+#endif /* _LP64 */
+
+ if (Pr == NULL) /* no subject process */
+ return (stat(path, buf));
+
+ /*
+ * This is filthy, but /proc reveals everything about the
+ * system call interfaces, despite what the architects of the
+ * header files may desire. We have to know here whether we
+ * are calling stat() or xstat() in the subject.
+ */
+#if defined(_STAT_VER)
+ syscall = SYS_xstat;
+ nargs = 3;
+ adp->arg_value = _STAT_VER;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+ adp++; /* move to pathname argument */
+#else
+ if (Pstatus(Pr)->pr_dmodel != PR_MODEL_NATIVE) {
+ /* 64-bit process controls 32-bit subject process */
+ syscall = SYS_stat64;
+ } else {
+ syscall = SYS_stat;
+ }
+#endif
+
+ adp->arg_value = 0;
+ adp->arg_object = (void *)path;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = strlen(path) + 1;
+ adp++; /* move to buffer argument */
+
+ adp->arg_value = 0;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_OUTPUT;
+#ifdef _LP64
+ if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32) {
+ adp->arg_object = &statb64_32;
+ adp->arg_size = sizeof (statb64_32);
+ } else {
+ adp->arg_object = buf;
+ adp->arg_size = sizeof (*buf);
+ }
+#else /* _LP64 */
+ adp->arg_object = buf;
+ adp->arg_size = sizeof (*buf);
+#endif /* _LP64 */
+
+ error = Psyscall(Pr, &rval, syscall, nargs, &argd[0]);
+
+ if (error) {
+ errno = (error > 0)? error : ENOSYS;
+ return (-1);
+ }
+#ifdef _LP64
+ if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32)
+ stat64_32_to_n(&statb64_32, buf);
+#endif /* _LP64 */
+ return (0);
+}
+
+/*
+ * lstat() system call -- executed by subject process
+ */
+int
+pr_lstat(struct ps_prochandle *Pr, const char *path, struct stat *buf)
+{
+ sysret_t rval; /* return value from lstat() */
+ argdes_t argd[3]; /* arg descriptors for lstat() */
+ argdes_t *adp = &argd[0]; /* first argument */
+ int syscall; /* lstat, lxstat or lstat64 */
+ int nargs = 2; /* number of actual arguments */
+ int error;
+#ifdef _LP64
+ struct stat64_32 statb64_32;
+#endif /* _LP64 */
+
+ if (Pr == NULL) /* no subject process */
+ return (lstat(path, buf));
+
+ /*
+ * This is filthy, but /proc reveals everything about the
+ * system call interfaces, despite what the architects of the
+ * header files may desire. We have to know here whether we
+ * are calling lstat() or lxstat() in the subject.
+ */
+#if defined(_STAT_VER)
+ syscall = SYS_lxstat;
+ nargs = 3;
+ adp->arg_value = _STAT_VER;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+ adp++; /* move to pathname argument */
+#else
+ if (Pstatus(Pr)->pr_dmodel != PR_MODEL_NATIVE) {
+ /* 64-bit process controls 32-bit subject process */
+ syscall = SYS_lstat64;
+ } else {
+ syscall = SYS_lstat;
+ }
+#endif
+
+ adp->arg_value = 0;
+ adp->arg_object = (void *)path;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = strlen(path) + 1;
+ adp++; /* move to buffer argument */
+
+ adp->arg_value = 0;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_OUTPUT;
+#ifdef _LP64
+ if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32) {
+ adp->arg_object = &statb64_32;
+ adp->arg_size = sizeof (statb64_32);
+ } else {
+ adp->arg_object = buf;
+ adp->arg_size = sizeof (*buf);
+ }
+#else /* _LP64 */
+ adp->arg_object = buf;
+ adp->arg_size = sizeof (*buf);
+#endif /* _LP64 */
+
+ error = Psyscall(Pr, &rval, syscall, nargs, &argd[0]);
+
+ if (error) {
+ errno = (error > 0)? error : ENOSYS;
+ return (-1);
+ }
+#ifdef _LP64
+ if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32)
+ stat64_32_to_n(&statb64_32, buf);
+#endif /* _LP64 */
+ return (0);
+}
+
+/*
+ * fstat() system call -- executed by subject process
+ */
+int
+pr_fstat(struct ps_prochandle *Pr, int fd, struct stat *buf)
+{
+ sysret_t rval; /* return value from fstat() */
+ argdes_t argd[3]; /* arg descriptors for fstat() */
+ argdes_t *adp = &argd[0]; /* first argument */
+ int syscall; /* fstat, fxstat or fstat64 */
+ int nargs = 2; /* number of actual arguments */
+ int error;
+#ifdef _LP64
+ struct stat64_32 statb64_32;
+#endif /* _LP64 */
+
+ if (Pr == NULL) /* no subject process */
+ return (fstat(fd, buf));
+
+ /*
+ * This is filthy, but /proc reveals everything about the
+ * system call interfaces, despite what the architects of the
+ * header files may desire. We have to know here whether we
+ * are calling fstat() or fxstat() in the subject.
+ */
+#if defined(_STAT_VER)
+ syscall = SYS_fxstat;
+ nargs = 3;
+ adp->arg_value = _STAT_VER;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+ adp++; /* move to fd argument */
+#else
+ if (Pstatus(Pr)->pr_dmodel != PR_MODEL_NATIVE) {
+ /* 64-bit process controls 32-bit subject process */
+ syscall = SYS_fstat64;
+ } else {
+ syscall = SYS_fstat;
+ }
+#endif
+
+ adp->arg_value = fd;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+ adp++; /* move to buffer argument */
+
+ adp->arg_value = 0;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_OUTPUT;
+#ifdef _LP64
+ if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32) {
+ adp->arg_object = &statb64_32;
+ adp->arg_size = sizeof (statb64_32);
+ } else {
+ adp->arg_object = buf;
+ adp->arg_size = sizeof (*buf);
+ }
+#else /* _LP64 */
+ adp->arg_object = buf;
+ adp->arg_size = sizeof (*buf);
+#endif /* _LP64 */
+
+ error = Psyscall(Pr, &rval, syscall, nargs, &argd[0]);
+
+ if (error) {
+ errno = (error > 0)? error : ENOSYS;
+ return (-1);
+ }
+#ifdef _LP64
+ if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32)
+ stat64_32_to_n(&statb64_32, buf);
+#endif /* _LP64 */
+ return (0);
+}
+
+/*
+ * stat64() system call -- executed by subject process
+ */
+int
+pr_stat64(struct ps_prochandle *Pr, const char *path, struct stat64 *buf)
+{
+ sysret_t rval; /* return value from stat64() */
+ argdes_t argd[2]; /* arg descriptors for stat64() */
+ argdes_t *adp = &argd[0]; /* first argument */
+ int syscall; /* stat or stat64 */
+ int nargs = 2; /* number of actual arguments */
+ int error;
+#ifdef _LP64
+ struct stat64_32 statb64_32;
+#endif /* _LP64 */
+
+ if (Pr == NULL) /* no subject process */
+ return (stat64(path, buf));
+
+ if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32) {
+ /*
+ * 32-bit native and
+ * 64-bit process controls 32-bit subject process
+ */
+ syscall = SYS_stat64;
+ } else {
+ /* 64-bit native */
+ syscall = SYS_stat;
+ }
+
+ adp->arg_value = 0;
+ adp->arg_object = (void *)path;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = strlen(path) + 1;
+ adp++; /* move to buffer argument */
+
+ adp->arg_value = 0;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_OUTPUT;
+#ifdef _LP64
+ if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32) {
+ adp->arg_object = &statb64_32;
+ adp->arg_size = sizeof (statb64_32);
+ } else {
+ adp->arg_object = buf;
+ adp->arg_size = sizeof (*buf);
+ }
+#else /* _LP64 */
+ adp->arg_object = buf;
+ adp->arg_size = sizeof (*buf);
+#endif /* _LP64 */
+
+ error = Psyscall(Pr, &rval, syscall, nargs, &argd[0]);
+
+ if (error) {
+ errno = (error > 0)? error : ENOSYS;
+ return (-1);
+ }
+#ifdef _LP64
+ if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32)
+ stat64_32_to_n(&statb64_32, (struct stat *)buf);
+#endif /* _LP64 */
+ return (0);
+}
+
+/*
+ * lstat64() system call -- executed by subject process
+ */
+int
+pr_lstat64(struct ps_prochandle *Pr, const char *path, struct stat64 *buf)
+{
+ sysret_t rval; /* return value from lstat64() */
+ argdes_t argd[2]; /* arg descriptors for lstat64() */
+ argdes_t *adp = &argd[0]; /* first argument */
+ int syscall; /* lstat or lstat64 */
+ int nargs = 2; /* number of actual arguments */
+ int error;
+#ifdef _LP64
+ struct stat64_32 statb64_32;
+#endif /* _LP64 */
+
+ if (Pr == NULL) /* no subject process */
+ return (lstat64(path, buf));
+
+ if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32) {
+ /*
+ * 32-bit native and
+ * 64-bit process controls 32-bit subject process
+ */
+ syscall = SYS_lstat64;
+ } else {
+ /* 64-bit native */
+ syscall = SYS_lstat;
+ }
+
+ adp->arg_value = 0;
+ adp->arg_object = (void *)path;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = strlen(path) + 1;
+ adp++; /* move to buffer argument */
+
+ adp->arg_value = 0;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_OUTPUT;
+#ifdef _LP64
+ if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32) {
+ adp->arg_object = &statb64_32;
+ adp->arg_size = sizeof (statb64_32);
+ } else {
+ adp->arg_object = buf;
+ adp->arg_size = sizeof (*buf);
+ }
+#else /* _LP64 */
+ adp->arg_object = buf;
+ adp->arg_size = sizeof (*buf);
+#endif /* _LP64 */
+
+ error = Psyscall(Pr, &rval, syscall, nargs, &argd[0]);
+
+ if (error) {
+ errno = (error > 0)? error : ENOSYS;
+ return (-1);
+ }
+#ifdef _LP64
+ if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32)
+ stat64_32_to_n(&statb64_32, (struct stat *)buf);
+#endif /* _LP64 */
+ return (0);
+}
+
+/*
+ * fstat64() system call -- executed by subject process
+ */
+int
+pr_fstat64(struct ps_prochandle *Pr, int fd, struct stat64 *buf)
+{
+ sysret_t rval; /* return value from fstat64() */
+ argdes_t argd[2]; /* arg descriptors for fstat64() */
+ argdes_t *adp = &argd[0]; /* first argument */
+ int syscall; /* fstat or fstat64 */
+ int nargs = 2; /* number of actual arguments */
+ int error;
+#ifdef _LP64
+ struct stat64_32 statb64_32;
+#endif /* _LP64 */
+
+ if (Pr == NULL) /* no subject process */
+ return (fstat64(fd, buf));
+
+ if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32) {
+ /*
+ * 32-bit native and
+ * 64-bit process controls 32-bit subject process
+ */
+ syscall = SYS_fstat64;
+ } else {
+ /* 64-bit native */
+ syscall = SYS_fstat;
+ }
+
+ adp->arg_value = fd;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+ adp++; /* move to buffer argument */
+
+ adp->arg_value = 0;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_OUTPUT;
+#ifdef _LP64
+ if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32) {
+ adp->arg_object = &statb64_32;
+ adp->arg_size = sizeof (statb64_32);
+ } else {
+ adp->arg_object = buf;
+ adp->arg_size = sizeof (*buf);
+ }
+#else /* _LP64 */
+ adp->arg_object = buf;
+ adp->arg_size = sizeof (*buf);
+#endif /* _LP64 */
+
+ error = Psyscall(Pr, &rval, syscall, nargs, &argd[0]);
+
+ if (error) {
+ errno = (error > 0)? error : ENOSYS;
+ return (-1);
+ }
+#ifdef _LP64
+ if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32)
+ stat64_32_to_n(&statb64_32, (struct stat *)buf);
+#endif /* _LP64 */
+ return (0);
+}
diff --git a/usr/src/lib/libproc/common/pr_statvfs.c b/usr/src/lib/libproc/common/pr_statvfs.c
new file mode 100644
index 0000000000..01d8d3ce67
--- /dev/null
+++ b/usr/src/lib/libproc/common/pr_statvfs.c
@@ -0,0 +1,165 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1998-2000 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/isa_defs.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/statvfs.h>
+#include <sys/sysmacros.h>
+#include "libproc.h"
+
+#ifdef _LP64
+static void
+statvfs_32_to_n(statvfs32_t *src, statvfs_t *dest)
+{
+ dest->f_bsize = src->f_bsize;
+ dest->f_frsize = src->f_frsize;
+ dest->f_blocks = src->f_blocks;
+ dest->f_bfree = src->f_bfree;
+ dest->f_bavail = src->f_bavail;
+ dest->f_files = src->f_files;
+ dest->f_ffree = src->f_ffree;
+ dest->f_favail = src->f_favail;
+ dest->f_fsid = src->f_fsid;
+ (void) memcpy(dest->f_basetype, src->f_basetype,
+ sizeof (dest->f_basetype));
+ dest->f_flag = src->f_flag;
+ dest->f_namemax = src->f_namemax;
+ (void) memcpy(dest->f_fstr, src->f_fstr,
+ sizeof (dest->f_fstr));
+}
+#endif /* _LP64 */
+
+/*
+ * statvfs() system call -- executed by subject process
+ */
+int
+pr_statvfs(struct ps_prochandle *Pr, const char *path, statvfs_t *buf)
+{
+ sysret_t rval; /* return value from statvfs() */
+ argdes_t argd[2]; /* arg descriptors for statvfs() */
+ argdes_t *adp = &argd[0]; /* first argument */
+ int error;
+#ifdef _LP64
+ statvfs32_t statvfs32;
+#endif /* _LP64 */
+
+ if (Pr == NULL) /* no subject process */
+ return (statvfs(path, buf));
+
+ adp->arg_value = 0;
+ adp->arg_object = (void *)path;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = strlen(path)+1;
+ adp++; /* move to buffer argument */
+
+ adp->arg_value = 0;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_OUTPUT;
+#ifdef _LP64
+ if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32) {
+ adp->arg_object = &statvfs32;
+ adp->arg_size = sizeof (statvfs32);
+ } else {
+ adp->arg_object = buf;
+ adp->arg_size = sizeof (*buf);
+ }
+#else /* _LP64 */
+ adp->arg_object = buf;
+ adp->arg_size = sizeof (*buf);
+#endif /* _LP64 */
+
+ error = Psyscall(Pr, &rval, SYS_statvfs, 2, &argd[0]);
+
+ if (error) {
+ errno = (error > 0)? error : ENOSYS;
+ return (-1);
+ }
+#ifdef _LP64
+ if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32)
+ statvfs_32_to_n(&statvfs32, buf);
+#endif /* _LP64 */
+ return (0);
+}
+
+/*
+ * fstatvfs() system call -- executed by subject process
+ */
+int
+pr_fstatvfs(struct ps_prochandle *Pr, int fd, statvfs_t *buf)
+{
+ sysret_t rval; /* return value from fstatvfs() */
+ argdes_t argd[2]; /* arg descriptors for fstatvfs() */
+ argdes_t *adp = &argd[0]; /* first argument */
+ int error;
+#ifdef _LP64
+ statvfs32_t statvfs32;
+#endif /* _LP64 */
+
+ if (Pr == NULL) /* no subject process */
+ return (fstatvfs(fd, buf));
+
+ adp->arg_value = fd;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+ adp++; /* move to buffer argument */
+
+ adp->arg_value = 0;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_OUTPUT;
+#ifdef _LP64
+ if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32) {
+ adp->arg_object = &statvfs32;
+ adp->arg_size = sizeof (statvfs32);
+ } else {
+ adp->arg_object = buf;
+ adp->arg_size = sizeof (*buf);
+ }
+#else /* _LP64 */
+ adp->arg_object = buf;
+ adp->arg_size = sizeof (*buf);
+#endif /* _LP64 */
+
+ error = Psyscall(Pr, &rval, SYS_fstatvfs, 2, &argd[0]);
+
+ if (error) {
+ errno = (error > 0)? error : ENOSYS;
+ return (-1);
+ }
+#ifdef _LP64
+ if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32)
+ statvfs_32_to_n(&statvfs32, buf);
+#endif /* _LP64 */
+ return (0);
+}
diff --git a/usr/src/lib/libproc/common/pr_tasksys.c b/usr/src/lib/libproc/common/pr_tasksys.c
new file mode 100644
index 0000000000..7236e75dff
--- /dev/null
+++ b/usr/src/lib/libproc/common/pr_tasksys.c
@@ -0,0 +1,170 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#define _LARGEFILE64_SOURCE
+
+#include <sys/task.h>
+#include <sys/types.h>
+
+#include <zone.h>
+#include <errno.h>
+#include <project.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include "libproc.h"
+
+zoneid_t
+pr_getzoneid(struct ps_prochandle *Pr)
+{
+ sysret_t rval;
+ argdes_t argd[2];
+ argdes_t *adp;
+ int error;
+
+ if (Pr == NULL) /* no subject process */
+ return (getzoneid());
+
+ adp = &argd[0];
+ adp->arg_value = 6; /* switch for zone_lookup in zone */
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ adp = &argd[1];
+ adp->arg_value = 0; /* arguement for zone_lookup in zone */
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ error = Psyscall(Pr, &rval, SYS_zone, 2, &argd[0]);
+
+ if (error) {
+ errno = (error > 0) ? error : ENOSYS;
+ return (-1);
+ }
+ return (rval.sys_rval1);
+}
+
+projid_t
+pr_getprojid(struct ps_prochandle *Pr)
+{
+ sysret_t rval;
+ argdes_t argd[1];
+ argdes_t *adp;
+ int error;
+
+ if (Pr == NULL) /* no subject process */
+ return (getprojid());
+
+ adp = &argd[0];
+ adp->arg_value = 2; /* switch for getprojid in tasksys */
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ error = Psyscall(Pr, &rval, SYS_tasksys, 1, &argd[0]);
+
+ if (error) {
+ errno = (error > 0) ? error : ENOSYS;
+ return (-1);
+ }
+ return (rval.sys_rval1);
+}
+
+taskid_t
+pr_gettaskid(struct ps_prochandle *Pr)
+{
+ sysret_t rval;
+ argdes_t argd[1];
+ argdes_t *adp;
+ int error;
+
+ if (Pr == NULL) /* no subject process */
+ return (gettaskid());
+
+ adp = &argd[0];
+ adp->arg_value = 1; /* switch for gettaskid in tasksys */
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ error = Psyscall(Pr, &rval, SYS_tasksys, 1, &argd[0]);
+
+ if (error) {
+ errno = (error > 0) ? error : ENOSYS;
+ return (-1);
+ }
+ return (rval.sys_rval1);
+}
+
+taskid_t
+pr_settaskid(struct ps_prochandle *Pr, projid_t project, int flags)
+{
+ sysret_t rval;
+ argdes_t argd[3];
+ argdes_t *adp;
+ int error;
+
+ if (Pr == NULL) /* No subject process */
+ return (settaskid(project, flags));
+
+ adp = &argd[0];
+ adp->arg_value = 0; /* switch for settaskid in tasksys */
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ adp++;
+ adp->arg_value = project;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = sizeof (project);
+
+ adp++;
+ adp->arg_value = flags;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ error = Psyscall(Pr, &rval, SYS_tasksys, 3, &argd[0]);
+
+ if (error) {
+ errno = (error > 0) ? error : ENOSYS;
+ return (-1);
+ }
+ return (rval.sys_rval1);
+}
diff --git a/usr/src/lib/libproc/common/pr_waitid.c b/usr/src/lib/libproc/common/pr_waitid.c
new file mode 100644
index 0000000000..fdf57c29b2
--- /dev/null
+++ b/usr/src/lib/libproc/common/pr_waitid.c
@@ -0,0 +1,108 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1998-2000 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/isa_defs.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "P32ton.h"
+#include "libproc.h"
+
+/*
+ * waitid() system call -- executed by subject process
+ */
+int
+pr_waitid(struct ps_prochandle *Pr,
+ idtype_t idtype, id_t id, siginfo_t *infop, int options)
+{
+ sysret_t rval; /* return value from waitid() */
+ argdes_t argd[4]; /* arg descriptors for waitid() */
+ argdes_t *adp;
+ int error;
+#ifdef _LP64
+ siginfo32_t siginfo32;
+#endif /* _LP64 */
+
+ if (Pr == NULL) /* no subject process */
+ return (waitid(idtype, id, infop, options));
+
+ adp = &argd[0]; /* idtype argument */
+ adp->arg_value = idtype;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ adp++; /* id argument */
+ adp->arg_value = id;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ adp++; /* infop argument */
+ adp->arg_value = 0;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_OUTPUT;
+#ifdef _LP64
+ if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32) {
+ adp->arg_object = &siginfo32;
+ adp->arg_size = sizeof (siginfo32);
+ } else {
+ adp->arg_object = infop;
+ adp->arg_size = sizeof (*infop);
+ }
+#else /* _LP64 */
+ adp->arg_object = infop;
+ adp->arg_size = sizeof (*infop);
+#endif /* _LP64 */
+
+ adp++; /* options argument */
+ adp->arg_value = options;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ error = Psyscall(Pr, &rval, SYS_waitsys, 4, &argd[0]);
+
+ if (error) {
+ errno = (error > 0)? error : ENOSYS;
+ return (-1);
+ }
+#ifdef _LP64
+ if (Pstatus(Pr)->pr_dmodel == PR_MODEL_ILP32)
+ siginfo_32_to_n(&siginfo32, infop);
+#endif /* _LP64 */
+ return (0);
+}
diff --git a/usr/src/lib/libproc/common/proc_arg.c b/usr/src/lib/libproc/common/proc_arg.c
new file mode 100644
index 0000000000..2a79b016c2
--- /dev/null
+++ b/usr/src/lib/libproc/common/proc_arg.c
@@ -0,0 +1,509 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <libgen.h>
+#include <limits.h>
+#include <alloca.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+#include <dirent.h>
+
+#include "libproc.h"
+
+static int
+open_psinfo(const char *arg, int *perr)
+{
+ /*
+ * Allocate enough space for "/proc/" + arg + "/psinfo"
+ */
+ char *path = alloca(strlen(arg) + 14);
+
+ struct stat64 st;
+ int fd;
+
+ if (strchr(arg, '/') == NULL) {
+ (void) strcpy(path, "/proc/");
+ (void) strcat(path, arg);
+ } else
+ (void) strcpy(path, arg);
+
+ (void) strcat(path, "/psinfo");
+
+ /*
+ * Attempt to open the psinfo file, and return the fd if we can
+ * confirm this is a regular file provided by /proc.
+ */
+ if ((fd = open64(path, O_RDONLY)) >= 0) {
+ if (fstat64(fd, &st) != 0 || !S_ISREG(st.st_mode) ||
+ strcmp(st.st_fstype, "proc") != 0) {
+ (void) close(fd);
+ fd = -1;
+ }
+ } else if (errno == EACCES || errno == EPERM)
+ *perr = G_PERM;
+
+ return (fd);
+}
+
+static int
+open_core(const char *arg, int *perr)
+{
+#ifdef _BIG_ENDIAN
+ uchar_t order = ELFDATA2MSB;
+#else
+ uchar_t order = ELFDATA2LSB;
+#endif
+ GElf_Ehdr ehdr;
+ int fd;
+ int is_noelf = -1;
+
+ /*
+ * Attempt to open the core file, and return the fd if we can confirm
+ * this is an ELF file of type ET_CORE.
+ */
+ if ((fd = open64(arg, O_RDONLY)) >= 0) {
+ if (read(fd, &ehdr, sizeof (ehdr)) != sizeof (ehdr)) {
+ (void) close(fd);
+ fd = -1;
+ } else if ((is_noelf = memcmp(&ehdr.e_ident[EI_MAG0], ELFMAG,
+ SELFMAG)) != 0 || ehdr.e_type != ET_CORE) {
+ (void) close(fd);
+ fd = -1;
+ if (is_noelf == 0 &&
+ ehdr.e_ident[EI_DATA] != order)
+ *perr = G_ISAINVAL;
+ }
+ } else if (errno == EACCES || errno == EPERM)
+ *perr = G_PERM;
+
+ return (fd);
+}
+
+/*
+ * Make the error message precisely match the type of arguments the caller
+ * wanted to process. This ensures that a tool which only accepts pids does
+ * not produce an error message saying "no such process or core file 'foo'".
+ */
+static int
+open_error(int oflag)
+{
+ if ((oflag & PR_ARG_ANY) == PR_ARG_PIDS)
+ return (G_NOPROC);
+
+ if ((oflag & PR_ARG_ANY) == PR_ARG_CORES)
+ return (G_NOCORE);
+
+ return (G_NOPROCORCORE);
+}
+
+static void *
+proc_grab_common(const char *arg, const char *path, int oflag, int gflag,
+ int *perr, const char **lwps, psinfo_t *psp)
+{
+ psinfo_t psinfo;
+ char *core;
+ int fd;
+ char *slash;
+ struct ps_prochandle *Pr;
+
+ *perr = 0;
+ if (lwps)
+ *lwps = NULL;
+
+ if (lwps != NULL && (slash = strrchr(arg, '/')) != NULL) {
+ /*
+ * Check to see if the user has supplied an lwp range. First,
+ * try to grab it as a pid/lwp combo.
+ */
+ *slash = '\0';
+ if ((oflag & PR_ARG_PIDS) &&
+ (fd = open_psinfo(arg, perr)) != -1) {
+ if (read(fd, &psinfo,
+ sizeof (psinfo_t)) == sizeof (psinfo_t)) {
+ (void) close(fd);
+ *lwps = slash + 1;
+ *slash = '/';
+ if (proc_lwp_range_valid(*lwps) != 0) {
+ *perr = G_BADLWPS;
+ return (NULL);
+ }
+ if (psp) {
+ *psp = psinfo;
+ return (psp);
+ } else {
+ return (Pgrab(psinfo.pr_pid, gflag,
+ perr));
+ }
+ }
+ (void) close(fd);
+ }
+
+ /*
+ * Next, try grabbing it as a corefile.
+ */
+ if ((oflag & PR_ARG_CORES) &&
+ (fd = open_core(arg, perr)) != -1) {
+ *lwps = slash + 1;
+ *slash = '/';
+ if (proc_lwp_range_valid(*lwps) != 0) {
+ *perr = G_BADLWPS;
+ return (NULL);
+ }
+ core = alloca(strlen(arg) + 1);
+ (void) strcpy(core, arg);
+ if ((Pr = Pfgrab_core(fd, path == NULL ?
+ dirname(core) : path, perr)) != NULL) {
+ if (psp) {
+ (void) memcpy(psp, Ppsinfo(Pr),
+ sizeof (psinfo_t));
+ Prelease(Pr, 0);
+ return (psp);
+ } else {
+ return (Pr);
+ }
+ }
+ }
+
+ *slash = '/';
+ }
+
+ if ((oflag & PR_ARG_PIDS) && (fd = open_psinfo(arg, perr)) != -1) {
+ if (read(fd, &psinfo, sizeof (psinfo_t)) == sizeof (psinfo_t)) {
+ (void) close(fd);
+ if (psp) {
+ *psp = psinfo;
+ return (psp);
+ } else {
+ return (Pgrab(psinfo.pr_pid, gflag, perr));
+ }
+ }
+ /*
+ * If the read failed, the process may have gone away;
+ * we continue checking for core files or fail with G_NOPROC
+ */
+ (void) close(fd);
+ }
+
+ if ((oflag & PR_ARG_CORES) && (fd = open_core(arg, perr)) != -1) {
+ core = alloca(strlen(arg) + 1);
+ (void) strcpy(core, arg);
+ if ((Pr = Pfgrab_core(fd, path == NULL ? dirname(core) : path,
+ perr)) != NULL) {
+ if (psp) {
+ (void) memcpy(psp, Ppsinfo(Pr),
+ sizeof (psinfo_t));
+ Prelease(Pr, 0);
+ return (psp);
+ } else {
+ return (Pr);
+ }
+ }
+ }
+
+ /*
+ * We were unable to open the corefile. If we have no meaningful
+ * information, report the (ambiguous) error from open_error().
+ */
+
+ if (*perr == 0)
+ *perr = open_error(oflag);
+
+ return (NULL);
+}
+
+struct ps_prochandle *
+proc_arg_xgrab(const char *arg, const char *path, int oflag, int gflag,
+ int *perr, const char **lwps)
+{
+ return (proc_grab_common(arg, path, oflag, gflag, perr, lwps, NULL));
+}
+
+struct ps_prochandle *
+proc_arg_grab(const char *arg, int oflag, int gflag, int *perr)
+{
+ return (proc_grab_common(arg, NULL, oflag, gflag, perr, NULL, NULL));
+}
+
+pid_t
+proc_arg_psinfo(const char *arg, int oflag, psinfo_t *psp, int *perr)
+{
+ psinfo_t psinfo;
+
+ if (psp == NULL)
+ psp = &psinfo;
+
+ if (proc_grab_common(arg, NULL, oflag, 0, perr, NULL, psp) == NULL)
+ return (-1);
+ else
+ return (psp->pr_pid);
+}
+
+pid_t
+proc_arg_xpsinfo(const char *arg, int oflag, psinfo_t *psp, int *perr,
+ const char **lwps)
+{
+ psinfo_t psinfo;
+
+ if (psp == NULL)
+ psp = &psinfo;
+
+ if (proc_grab_common(arg, NULL, oflag, 0, perr, lwps, psp) == NULL)
+ return (-1);
+ else
+ return (psp->pr_pid);
+}
+
+/*
+ * Convert psinfo_t.pr_psargs string into itself, replacing unprintable
+ * characters with space along the way. Stop on a null character.
+ */
+void
+proc_unctrl_psinfo(psinfo_t *psp)
+{
+ char *s = &psp->pr_psargs[0];
+ size_t n = PRARGSZ;
+ int c;
+
+ while (n-- != 0 && (c = (*s & UCHAR_MAX)) != '\0') {
+ if (!isprint(c))
+ c = ' ';
+ *s++ = (char)c;
+ }
+
+ *s = '\0';
+}
+
+static int
+proc_lwp_get_range(char *range, id_t *low, id_t *high)
+{
+ if (*range == '-')
+ *low = 0;
+ else
+ *low = (id_t)strtol(range, &range, 10);
+
+ if (*range == '\0' || *range == ',') {
+ *high = *low;
+ return (0);
+ }
+ if (*range != '-') {
+ return (-1);
+ }
+ range++;
+
+ if (*range == '\0')
+ *high = INT_MAX;
+ else
+ *high = (id_t)strtol(range, &range, 10);
+
+ if (*range != '\0' && *range != ',') {
+ return (-1);
+ }
+
+ if (*high < *low) {
+ id_t tmp = *high;
+ *high = *low;
+ *low = tmp;
+ }
+
+ return (0);
+}
+
+/*
+ * Determine if the specified lwpid is in the given set of lwpids.
+ * The set can include multiple lwpid ranges separated by commas
+ * and has the following syntax:
+ *
+ * lwp_range[,lwp_range]*
+ *
+ * where lwp_range is specifed as:
+ *
+ * -n lwpid <= n
+ * n-m n <= lwpid <= m
+ * n- lwpid >= n
+ * n lwpid == n
+ */
+int
+proc_lwp_in_set(const char *set, lwpid_t lwpid)
+{
+ id_t low, high;
+ id_t id = (id_t)lwpid;
+ char *comma;
+ char *range = (char *)set;
+
+ /*
+ * A NULL set indicates that all LWPs are valid.
+ */
+ if (set == NULL)
+ return (1);
+
+ while (range != NULL) {
+ comma = strchr(range, ',');
+ if (comma != NULL)
+ *comma = '\0';
+ if (proc_lwp_get_range(range, &low, &high) != 0) {
+ if (comma != NULL)
+ *comma = ',';
+ return (0);
+ }
+ if (comma != NULL) {
+ *comma = ',';
+ range = comma + 1;
+ } else {
+ range = NULL;
+ }
+ if (id >= low && id <= high)
+ return (1);
+ }
+
+ return (0);
+}
+
+int
+proc_lwp_range_valid(const char *set)
+{
+ char *comma;
+ char *range = (char *)set;
+ id_t low, high;
+ int ret;
+
+ if (range == NULL || *range == '\0' || *range == ',')
+ return (-1);
+
+ while (range != NULL) {
+ comma = strchr(range, ',');
+ if (comma != NULL)
+ *comma = '\0';
+ if ((ret = proc_lwp_get_range(range, &low, &high)) != 0) {
+ if (comma != NULL)
+ *comma = ',';
+ return (ret);
+ }
+ if (comma != NULL) {
+ *comma = ',';
+ range = comma + 1;
+ } else {
+ range = NULL;
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * Walk all processes or LWPs in /proc and call func() for each.
+ * Stop calling func() if it returns non 0 value and return it.
+ */
+int
+proc_walk(proc_walk_f *func, void *arg, int flag)
+{
+ DIR *procdir;
+ struct dirent *dirent;
+ char *errptr;
+ char pidstr[80];
+ psinfo_t psinfo;
+ lwpsinfo_t *lwpsinfo;
+ prheader_t prheader;
+ void *buf;
+ char *ptr;
+ int bufsz;
+ id_t pid;
+ int fd, i;
+ int ret = 0;
+
+ if (flag != PR_WALK_PROC && flag != PR_WALK_LWP) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if ((procdir = opendir("/proc")) == NULL)
+ return (-1);
+ while (dirent = readdir(procdir)) {
+ if (dirent->d_name[0] == '.') /* skip . and .. */
+ continue;
+ pid = (id_t)strtol(dirent->d_name, &errptr, 10);
+ if (errptr != NULL && *errptr != '\0')
+ continue;
+ /* PR_WALK_PROC case */
+ (void) snprintf(pidstr, sizeof (pidstr),
+ "/proc/%ld/psinfo", pid);
+ fd = open(pidstr, O_RDONLY);
+ if (fd < 0)
+ continue;
+ if (read(fd, &psinfo, sizeof (psinfo)) != sizeof (psinfo)) {
+ (void) close(fd);
+ continue;
+ }
+ (void) close(fd);
+ if (flag == PR_WALK_PROC) {
+ if ((ret = func(&psinfo, &psinfo.pr_lwp, arg)) != 0)
+ break;
+ continue;
+ }
+ /* PR_WALK_LWP case */
+ (void) snprintf(pidstr, sizeof (pidstr),
+ "/proc/%ld/lpsinfo", pid);
+ fd = open(pidstr, O_RDONLY);
+ if (fd < 0)
+ continue;
+ if (read(fd, &prheader, sizeof (prheader)) !=
+ sizeof (prheader)) {
+ (void) close(fd);
+ continue;
+ }
+ bufsz = prheader.pr_nent * prheader.pr_entsize;
+ if ((buf = malloc(bufsz)) == NULL) {
+ (void) close(fd);
+ ret = -1;
+ break;
+ }
+ ptr = buf;
+ if (pread(fd, buf, bufsz, sizeof (prheader)) != bufsz) {
+ free(buf);
+ (void) close(fd);
+ continue;
+ }
+ (void) close(fd);
+ for (i = 0; i < prheader.pr_nent;
+ i++, ptr += prheader.pr_entsize) {
+ /*LINTED ALIGNMENT*/
+ lwpsinfo = (lwpsinfo_t *)ptr;
+ if ((ret = func(&psinfo, lwpsinfo, arg)) != 0) {
+ free(buf);
+ break;
+ }
+ }
+ free(buf);
+ }
+ (void) closedir(procdir);
+ return (ret);
+}
diff --git a/usr/src/lib/libproc/common/proc_get_info.c b/usr/src/lib/libproc/common/proc_get_info.c
new file mode 100644
index 0000000000..d4426f7cc0
--- /dev/null
+++ b/usr/src/lib/libproc/common/proc_get_info.c
@@ -0,0 +1,183 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include "libproc.h"
+
+/*
+ * These several routines simply get the indicated /proc structures
+ * for a process identified by process ID. They are convenience
+ * functions for one-time operations. They do the mechanics of
+ * open() / read() / close() of the necessary /proc files so the
+ * caller's code can look relatively less cluttered.
+ */
+
+/*
+ * 'ngroups' 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, like this:
+ * credp = malloc(sizeof (prcred_t) + (ngroups - 1) * sizeof (gid_t));
+ */
+int
+proc_get_cred(pid_t pid, prcred_t *credp, int ngroups)
+{
+ char fname[64];
+ int fd;
+ int rv = -1;
+ ssize_t minsize = sizeof (*credp) - sizeof (gid_t);
+ size_t size = minsize + ngroups * sizeof (gid_t);
+
+ (void) snprintf(fname, sizeof (fname), "/proc/%d/cred", (int)pid);
+ if ((fd = open(fname, O_RDONLY)) >= 0) {
+ if (read(fd, credp, size) >= minsize)
+ rv = 0;
+ (void) close(fd);
+ }
+ return (rv);
+}
+
+/*
+ * Malloc and return a properly sized structure.
+ */
+prpriv_t *
+proc_get_priv(pid_t pid)
+{
+ char fname[64];
+ int fd;
+ struct stat statb;
+ prpriv_t *rv = NULL;
+
+ (void) snprintf(fname, sizeof (fname), "/proc/%d/priv", (int)pid);
+ if ((fd = open(fname, O_RDONLY)) >= 0) {
+ if (fstat(fd, &statb) != 0 ||
+ (rv = malloc(statb.st_size)) == NULL ||
+ read(fd, rv, statb.st_size) != statb.st_size) {
+ free(rv);
+ rv = NULL;
+ }
+ (void) close(fd);
+ }
+ return (rv);
+}
+
+#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.
+ * Otherwise we return the actual number of LDT entries fetched (<= nldt).
+ */
+int
+proc_get_ldt(pid_t pid, struct ssd *pldt, int nldt)
+{
+ char fname[64];
+ int fd;
+ struct stat statb;
+ size_t size;
+ ssize_t ssize;
+
+ (void) snprintf(fname, sizeof (fname), "/proc/%d/ldt", (int)pid);
+ if ((fd = open(fname, O_RDONLY)) < 0)
+ return (-1);
+
+ if (pldt == NULL || nldt == 0) {
+ nldt = 0;
+ if (fstat(fd, &statb) == 0)
+ nldt = statb.st_size / sizeof (struct ssd);
+ (void) close(fd);
+ return (nldt);
+ }
+
+ size = nldt * sizeof (struct ssd);
+ if ((ssize = read(fd, pldt, size)) < 0)
+ nldt = -1;
+ else
+ nldt = ssize / sizeof (struct ssd);
+
+ (void) close(fd);
+ return (nldt);
+}
+#endif /* __i386 || __amd64 */
+
+int
+proc_get_psinfo(pid_t pid, psinfo_t *psp)
+{
+ char fname[64];
+ int fd;
+ int rv = -1;
+
+ (void) snprintf(fname, sizeof (fname), "/proc/%d/psinfo", (int)pid);
+ if ((fd = open(fname, O_RDONLY)) >= 0) {
+ if (read(fd, psp, sizeof (*psp)) == sizeof (*psp))
+ rv = 0;
+ (void) close(fd);
+ }
+ return (rv);
+}
+
+int
+proc_get_status(pid_t pid, pstatus_t *psp)
+{
+ char fname[64];
+ int fd;
+ int rv = -1;
+
+ (void) snprintf(fname, sizeof (fname), "/proc/%d/status", (int)pid);
+ if ((fd = open(fname, O_RDONLY)) >= 0) {
+ if (read(fd, psp, sizeof (*psp)) == sizeof (*psp))
+ rv = 0;
+ (void) close(fd);
+ }
+ return (rv);
+}
+
+/*
+ * Get the process's aux vector.
+ * 'naux' is the number of aux entries in the caller's buffer.
+ * We return the number of aux entries actually fetched from
+ * the process (less than or equal to 'naux') or -1 on failure.
+ */
+int
+proc_get_auxv(pid_t pid, auxv_t *pauxv, int naux)
+{
+ char fname[64];
+ int fd;
+ int rv = -1;
+
+ (void) snprintf(fname, sizeof (fname), "/proc/%d/auxv", (int)pid);
+ if ((fd = open(fname, O_RDONLY)) >= 0) {
+ if ((rv = read(fd, pauxv, naux * sizeof (auxv_t))) >= 0)
+ rv /= sizeof (auxv_t);
+ (void) close(fd);
+ }
+ return (rv);
+}
diff --git a/usr/src/lib/libproc/common/proc_names.c b/usr/src/lib/libproc/common/proc_names.c
new file mode 100644
index 0000000000..249b9745a3
--- /dev/null
+++ b/usr/src/lib/libproc/common/proc_names.c
@@ -0,0 +1,711 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#define __EXTENSIONS__
+#include <string.h>
+#undef __EXTENSIONS__
+#include <signal.h>
+#include <alloca.h>
+#include <errno.h>
+#include "libproc.h"
+
+static const char *
+rawfltname(int flt)
+{
+ const char *name;
+
+ switch (flt) {
+ case FLTILL: name = "FLTILL"; break;
+ case FLTPRIV: name = "FLTPRIV"; break;
+ case FLTBPT: name = "FLTBPT"; break;
+ case FLTTRACE: name = "FLTTRACE"; break;
+ case FLTACCESS: name = "FLTACCESS"; break;
+ case FLTBOUNDS: name = "FLTBOUNDS"; break;
+ case FLTIOVF: name = "FLTIOVF"; break;
+ case FLTIZDIV: name = "FLTIZDIV"; break;
+ case FLTFPE: name = "FLTFPE"; break;
+ case FLTSTACK: name = "FLTSTACK"; break;
+ case FLTPAGE: name = "FLTPAGE"; break;
+ case FLTWATCH: name = "FLTWATCH"; break;
+ case FLTCPCOVF: name = "FLTCPCOVF"; break;
+ default: name = NULL; break;
+ }
+
+ return (name);
+}
+
+/*
+ * Return the name of a fault.
+ * Manufacture a name for unknown fault.
+ */
+char *
+proc_fltname(int flt, char *buf, size_t bufsz)
+{
+ const char *name = rawfltname(flt);
+ size_t len;
+
+ if (bufsz == 0) /* force a program failure */
+ return (NULL);
+
+ if (name != NULL) {
+ len = strlen(name);
+ (void) strncpy(buf, name, bufsz);
+ } else {
+ len = snprintf(buf, bufsz, "FLT#%d", flt);
+ }
+
+ if (len >= bufsz) /* ensure null-termination */
+ buf[bufsz-1] = '\0';
+
+ return (buf);
+}
+
+/*
+ * Return the name of a signal.
+ * Manufacture a name for unknown signal.
+ */
+char *
+proc_signame(int sig, char *buf, size_t bufsz)
+{
+ char name[SIG2STR_MAX+4];
+ size_t len;
+
+ if (bufsz == 0) /* force a program failure */
+ return (NULL);
+
+ /* sig2str() omits the leading "SIG" */
+ (void) strcpy(name, "SIG");
+
+ if (sig2str(sig, name+3) == 0) {
+ len = strlen(name);
+ (void) strncpy(buf, name, bufsz);
+ } else {
+ len = snprintf(buf, bufsz, "SIG#%d", sig);
+ }
+
+ if (len >= bufsz) /* ensure null-termination */
+ buf[bufsz-1] = '\0';
+
+ return (buf);
+}
+
+static const char *const systable[] = {
+ NULL, /* 0 */
+ "_exit", /* 1 */
+ "forkall", /* 2 */
+ "read", /* 3 */
+ "write", /* 4 */
+ "open", /* 5 */
+ "close", /* 6 */
+ "wait", /* 7 */
+ "creat", /* 8 */
+ "link", /* 9 */
+ "unlink", /* 10 */
+ "exec", /* 11 */
+ "chdir", /* 12 */
+ "time", /* 13 */
+ "mknod", /* 14 */
+ "chmod", /* 15 */
+ "chown", /* 16 */
+ "brk", /* 17 */
+ "stat", /* 18 */
+ "lseek", /* 19 */
+ "getpid", /* 20 */
+ "mount", /* 21 */
+ "umount", /* 22 */
+ "setuid", /* 23 */
+ "getuid", /* 24 */
+ "stime", /* 25 */
+ "ptrace", /* 26 */
+ "alarm", /* 27 */
+ "fstat", /* 28 */
+ "pause", /* 29 */
+ "utime", /* 30 */
+ "stty", /* 31 */
+ "gtty", /* 32 */
+ "access", /* 33 */
+ "nice", /* 34 */
+ "statfs", /* 35 */
+ "sync", /* 36 */
+ "kill", /* 37 */
+ "fstatfs", /* 38 */
+ "pgrpsys", /* 39 */
+ NULL, /* 40 was xenix */
+ "dup", /* 41 */
+ "pipe", /* 42 */
+ "times", /* 43 */
+ "profil", /* 44 */
+ "plock", /* 45 */
+ "setgid", /* 46 */
+ "getgid", /* 47 */
+ "signal", /* 48 */
+ "msgsys", /* 49 */
+ "sysi86", /* 50 */
+ "acct", /* 51 */
+ "shmsys", /* 52 */
+ "semsys", /* 53 */
+ "ioctl", /* 54 */
+ "uadmin", /* 55 */
+ NULL, /* 56 */
+ "utssys", /* 57 */
+ "fdsync", /* 58 */
+ "execve", /* 59 */
+ "umask", /* 60 */
+ "chroot", /* 61 */
+ "fcntl", /* 62 */
+ "ulimit", /* 63 */
+
+ /* The following 6 entries were reserved for the UNIX PC */
+ NULL, /* 64 */
+ NULL, /* 65 */
+ NULL, /* 66 */
+ NULL, /* 67 */
+ NULL, /* 68 */
+ NULL, /* 69 */
+
+ "tasksys", /* 70 */
+ "acctctl", /* 71 */
+ "exacctsys", /* 72 */
+ "getpagesizes", /* 73 */
+ "rctlsys", /* 74 */
+ "issetugid", /* 75 */
+ "fsat", /* 76 */
+ "lwp_park", /* 77 */
+ "sendfilev", /* 78 */
+ "rmdir", /* 79 */
+ "mkdir", /* 80 */
+ "getdents", /* 81 */
+ "privsys", /* 82 */
+ "ucredsys", /* 83 */
+ "sysfs", /* 84 */
+ "getmsg", /* 85 */
+ "putmsg", /* 86 */
+ "poll", /* 87 */
+ "lstat", /* 88 */
+ "symlink", /* 89 */
+ "readlink", /* 90 */
+ "setgroups", /* 91 */
+ "getgroups", /* 92 */
+ "fchmod", /* 93 */
+ "fchown", /* 94 */
+ "sigprocmask", /* 95 */
+ "sigsuspend", /* 96 */
+ "sigaltstack", /* 97 */
+ "sigaction", /* 98 */
+ "sigpending", /* 99 */
+ "context", /* 100 */
+ "evsys", /* 101 */
+ "evtrapret", /* 102 */
+ "statvfs", /* 103 */
+ "fstatvfs", /* 104 */
+ "getloadavg", /* 105 */
+ "nfssys", /* 106 */
+ "waitid", /* 107 */
+ "sigsendsys", /* 108 */
+ "hrtsys", /* 109 */
+ "acancel", /* 110 */
+ "async", /* 111 */
+ "priocntlsys", /* 112 */
+ "pathconf", /* 113 */
+ "mincore", /* 114 */
+ "mmap", /* 115 */
+ "mprotect", /* 116 */
+ "munmap", /* 117 */
+ "fpathconf", /* 118 */
+ "vfork", /* 119 */
+ "fchdir", /* 120 */
+ "readv", /* 121 */
+ "writev", /* 122 */
+ "xstat", /* 123 */
+ "lxstat", /* 124 */
+ "fxstat", /* 125 */
+ "xmknod", /* 126 */
+ "NULL", /* 127 */
+ "setrlimit", /* 128 */
+ "getrlimit", /* 129 */
+ "lchown", /* 130 */
+ "memcntl", /* 131 */
+ "getpmsg", /* 132 */
+ "putpmsg", /* 133 */
+ "rename", /* 134 */
+ "uname", /* 135 */
+ "setegid", /* 136 */
+ "sysconfig", /* 137 */
+ "adjtime", /* 138 */
+ "systeminfo", /* 139 */
+ NULL, /* 140 */
+ "seteuid", /* 141 */
+ NULL, /* 142 */
+ "fork1", /* 143 */
+ "sigtimedwait", /* 144 */
+ "lwp_info", /* 145 */
+ "yield", /* 146 */
+ "lwp_sema_wait", /* 147 */
+ "lwp_sema_post", /* 148 */
+ "lwp_sema_trywait", /* 149 */
+ "lwp_detatch", /* 150 */
+ "corectl", /* 151 */
+ "modctl", /* 152 */
+ "fchroot", /* 153 */
+ "utimes", /* 154 */
+ "vhangup", /* 155 */
+ "gettimeofday", /* 156 */
+ "getitimer", /* 157 */
+ "setitimer", /* 158 */
+ "lwp_create", /* 159 */
+ "lwp_exit", /* 160 */
+ "lwp_suspend", /* 161 */
+ "lwp_continue", /* 162 */
+ "lwp_kill", /* 163 */
+ "lwp_self", /* 164 */
+ "lwp_sigmask", /* 165 */
+ "lwp_private", /* 166 */
+ "lwp_wait", /* 167 */
+ "lwp_mutex_unlock", /* 168 */
+ "lwp_mutex_lock", /* 169 */
+ "lwp_cond_wait", /* 170 */
+ "lwp_cond_signal", /* 171 */
+ "lwp_cond_broadcast", /* 172 */
+ "pread", /* 173 */
+ "pwrite", /* 174 */
+ "llseek", /* 175 */
+ "inst_sync", /* 176 */
+ NULL, /* 177 */
+ "kaio", /* 178 */
+ "cpc", /* 179 */
+ "lgrpsys", /* 180 */
+ "rusagesys", /* 181 */
+ "portfs", /* 182 */
+ "pollsys", /* 183 */
+ NULL, /* 184 */
+ "acl", /* 185 */
+ "auditsys", /* 186 */
+ "processor_bind", /* 187 */
+ "processor_info", /* 188 */
+ "p_online", /* 189 */
+ "sigqueue", /* 190 */
+ "clock_gettime", /* 191 */
+ "clock_settime", /* 192 */
+ "clock_getres", /* 193 */
+ "timer_create", /* 194 */
+ "timer_delete", /* 195 */
+ "timer_settime", /* 196 */
+ "timer_gettime", /* 197 */
+ "timer_getoverrun", /* 198 */
+ "nanosleep", /* 199 */
+ "facl", /* 200 */
+ "door", /* 201 */
+ "setreuid", /* 202 */
+ "setregid", /* 203 */
+ "install_utrap", /* 204 */
+ "signotify", /* 205 */
+ "schedctl", /* 206 */
+ "pset", /* 207 */
+ "sparc_utrap_install", /* 208 */
+ "resolvepath", /* 209 */
+ "lwp_mutex_timedlock", /* 210 */
+ "lwp_sema_timedwait", /* 211 */
+ "lwp_rwlock_sys", /* 212 */
+ "getdents64", /* 213 */
+ "mmap64", /* 214 */
+ "stat64", /* 215 */
+ "lstat64", /* 216 */
+ "fstat64", /* 217 */
+ "statvfs64", /* 218 */
+ "fstatvfs64", /* 219 */
+ "setrlimit64", /* 220 */
+ "getrlimit64", /* 221 */
+ "pread64", /* 222 */
+ "pwrite64", /* 223 */
+ "creat64", /* 224 */
+ "open64", /* 225 */
+ "rpcmod", /* 226 */
+ "zone", /* 227 */
+ "autofssys", /* 228 */
+ "getcwd", /* 229 */
+ "so_socket", /* 230 */
+ "so_socketpair", /* 231 */
+ "bind", /* 232 */
+ "listen", /* 233 */
+ "accept", /* 234 */
+ "connect", /* 235 */
+ "shutdown", /* 236 */
+ "recv", /* 237 */
+ "recvfrom", /* 238 */
+ "recvmsg", /* 239 */
+ "send", /* 240 */
+ "sendmsg", /* 241 */
+ "sendto", /* 242 */
+ "getpeername", /* 243 */
+ "getsockname", /* 244 */
+ "getsockopt", /* 245 */
+ "setsockopt", /* 246 */
+ "sockconfig", /* 247 */
+ "ntp_gettime", /* 248 */
+ "ntp_adjtime", /* 249 */
+ "lwp_mutex_unlock", /* 250 */
+ "lwp_mutex_trylock", /* 251 */
+ "lwp_mutex_init", /* 252 */
+ "cladm", /* 253 */
+ NULL, /* 254 */
+ "umount2" /* 255 */
+};
+
+/* SYSEND == max syscall number + 1 */
+#define SYSEND (sizeof (systable) / sizeof (systable[0]))
+
+/*
+ * Return the name of a system call.
+ * Manufacture a name for unknown system call.
+ */
+char *
+proc_sysname(int sys, char *buf, size_t bufsz)
+{
+ const char *name;
+ size_t len;
+
+ if (bufsz == 0) /* force a program failure */
+ return (NULL);
+
+ if (sys >= 0 && sys < SYSEND)
+ name = systable[sys];
+ else
+ name = NULL;
+
+ if (name != NULL) {
+ len = strlen(name);
+ (void) strncpy(buf, name, bufsz);
+ } else {
+ len = snprintf(buf, bufsz, "SYS#%d", sys);
+ }
+
+ if (len >= bufsz) /* ensure null-termination */
+ buf[bufsz-1] = '\0';
+
+ return (buf);
+}
+
+/*
+ * Convert a string representation of a fault to the corresponding number.
+ */
+int
+proc_str2flt(const char *str, int *fltnum)
+{
+ char *next;
+ int i;
+
+ i = strtol(str, &next, 0);
+ if (i > 0 && i <= PRMAXFAULT && *next == '\0') {
+ *fltnum = i;
+ return (0);
+ }
+
+ for (i = 1; i <= PRMAXFAULT; i++) {
+ const char *s = rawfltname(i);
+
+ if (s && (strcasecmp(s, str) == 0 ||
+ strcasecmp(s + 3, str) == 0)) {
+ *fltnum = i;
+ return (0);
+ }
+ }
+
+ return (-1);
+}
+
+/*
+ * Convert a string representation of a signal to the signal number. This
+ * functionality is already available in libc, but the interface doesn't
+ * optionally accept a "SIG" prefix. We strip that first, and then call libc.
+ */
+int
+proc_str2sig(const char *str, int *signum)
+{
+ if (strncasecmp(str, "SIG", 3) == 0)
+ str += 3; /* skip prefix */
+
+ return (str2sig(str, signum));
+}
+
+/*
+ * Convert a string representation of a system call to the corresponding number.
+ * We do this by performing a simple linear search of the table above.
+ */
+int
+proc_str2sys(const char *str, int *sysnum)
+{
+ char *next;
+ int i;
+
+ i = strtol(str, &next, 0);
+ if (i > 0 && i <= PRMAXSYS && *next == '\0') {
+ *sysnum = i;
+ return (0);
+ }
+
+ for (i = 1; i < SYSEND; i++) {
+ if (systable[i] != NULL && strcmp(systable[i], str) == 0) {
+ *sysnum = i;
+ return (0);
+ }
+ }
+
+ return (-1);
+}
+
+/*
+ * Convert a fltset_t to a string representation consisting of canonical
+ * machine fault names separated by the given delimeter string. If
+ * m is non-zero (TRUE), set members are printed. If m is zero (FALSE), set
+ * non-members are printed. If the specified buf is too small to hold the
+ * complete formatted set, NULL is returned; otherwise buf is returned.
+ */
+char *
+proc_fltset2str(const fltset_t *set, const char *delim, int m,
+ char *buf, size_t len)
+{
+ char name[FLT2STR_MAX], *p = buf;
+ size_t n;
+ int i;
+
+ if (buf == NULL || len < 1) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ buf[0] = '\0'; /* Set first byte to \0 */
+
+ for (i = 1; i <= PRMAXFAULT; i++) {
+ if ((prismember(set, i) != 0) ^ (m == 0)) {
+ (void) proc_fltname(i, name, sizeof (name));
+
+ if (buf[0] != '\0')
+ n = snprintf(p, len, "%s%s", delim, name);
+ else
+ n = snprintf(p, len, "%s", name);
+
+ if (n != strlen(p)) {
+ errno = ENAMETOOLONG; /* Output was truncated */
+ return (NULL);
+ }
+ len -= n;
+ p += n;
+ }
+ }
+ return (buf);
+}
+
+/*
+ * Convert a sigset_t to a string representation consisting of canonical signal
+ * names (without the SIG prefix). Parameters and return values analogous to
+ * proc_fltset2str().
+ */
+char *
+proc_sigset2str(const sigset_t *set, const char *delim, int m,
+ char *buf, size_t len)
+{
+ char name[SIG2STR_MAX], *p = buf;
+ size_t n;
+ int i;
+
+ if (buf == NULL || len < 1) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ m = (m != 0); /* Make sure m is 0 or 1 */
+ buf[0] = '\0'; /* Set first byte to \0 */
+
+ /*
+ * Unlike proc_fltset2str() and proc_sysset2str(), we don't loop
+ * until i <= NSIG here, because sigismember() rejects i == NSIG.
+ */
+ for (i = 1; i < NSIG; i++) {
+ if (sigismember(set, i) == m) {
+ (void) sig2str(i, name);
+
+ if (buf[0] != '\0')
+ n = snprintf(p, len, "%s%s", delim, name);
+ else
+ n = snprintf(p, len, "%s", name);
+
+ if (n != strlen(p)) {
+ errno = ENAMETOOLONG; /* Output was truncated */
+ return (NULL);
+ }
+
+ len -= n;
+ p += n;
+ }
+ }
+
+ return (buf);
+}
+
+/*
+ * Convert a sysset_t to a string representation consisting of canonical system
+ * call names. Parameters and return values analogous to proc_fltset2str().
+ */
+char *
+proc_sysset2str(const sysset_t *set, const char *delim, int m,
+ char *buf, size_t len)
+{
+ char name[SYS2STR_MAX], *p = buf;
+ size_t n;
+ int i;
+
+ if (buf == NULL || len < 1) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ buf[0] = '\0'; /* Set first byte to \0 */
+
+ for (i = 1; i <= PRMAXSYS; i++) {
+ if ((prismember(set, i) != 0) ^ (m == 0)) {
+ (void) proc_sysname(i, name, sizeof (name));
+
+ if (buf[0] != '\0')
+ n = snprintf(p, len, "%s%s", delim, name);
+ else
+ n = snprintf(p, len, "%s", name);
+
+ if (n != strlen(p)) {
+ errno = ENAMETOOLONG; /* Output was truncated */
+ return (NULL);
+ }
+ len -= n;
+ p += n;
+ }
+ }
+ return (buf);
+}
+
+/*
+ * Convert a string representation of a fault set (names separated by
+ * one or more of the given delimeters) to a fltset_t.
+ * If m is non-zero (TRUE), members of the string representation are set.
+ * If m is zero (FALSE), non-members of the string representation are set.
+ * This function returns NULL for success. Otherwise it returns a pointer
+ * to the token of the string that couldn't be identified as a string
+ * representation of a fault.
+ */
+char *
+proc_str2fltset(const char *s, const char *delim, int m, fltset_t *set)
+{
+ char *p, *q, *t = alloca(strlen(s) + 1);
+ int flt;
+
+ if (m) {
+ premptyset(set);
+ } else {
+ prfillset(set);
+ }
+
+ (void) strcpy(t, s);
+
+ for (p = strtok_r(t, delim, &q); p != NULL;
+ p = strtok_r(NULL, delim, &q)) {
+ if (proc_str2flt(p, &flt) == -1) {
+ errno = EINVAL;
+ return ((char *)s + (p - t));
+ }
+ if (m)
+ praddset(set, flt);
+ else
+ prdelset(set, flt);
+ }
+ return (NULL);
+}
+
+/*
+ * Convert a string representation of a signal set (names with or without the
+ * SIG prefix separated by one or more of the given delimeters) to a sigset_t.
+ * Parameters and return values analogous to proc_str2fltset().
+ */
+char *
+proc_str2sigset(const char *s, const char *delim, int m, sigset_t *set)
+{
+ char *p, *q, *t = alloca(strlen(s) + 1);
+ int sig;
+
+ if (m) {
+ premptyset(set);
+ } else {
+ prfillset(set);
+ }
+
+ (void) strcpy(t, s);
+
+ for (p = strtok_r(t, delim, &q); p != NULL;
+ p = strtok_r(NULL, delim, &q)) {
+ if (proc_str2sig(p, &sig) == -1) {
+ errno = EINVAL;
+ return ((char *)s + (p - t));
+ }
+ if (m)
+ praddset(set, sig);
+ else
+ prdelset(set, sig);
+ }
+ return (NULL);
+}
+
+/*
+ * Convert a string representation of a system call set (names separated by
+ * one or more of the given delimeters) to a sysset_t. Parameters and return
+ * values analogous to proc_str2fltset().
+ */
+char *
+proc_str2sysset(const char *s, const char *delim, int m, sysset_t *set)
+{
+ char *p, *q, *t = alloca(strlen(s) + 1);
+ int sys;
+
+ if (m) {
+ premptyset(set);
+ } else {
+ prfillset(set);
+ }
+
+ (void) strcpy(t, s);
+
+ for (p = strtok_r(t, delim, &q); p != NULL;
+ p = strtok_r(NULL, delim, &q)) {
+ if (proc_str2sys(p, &sys) == -1) {
+ errno = EINVAL;
+ return ((char *)s + (p - t));
+ }
+ if (m)
+ praddset(set, sys);
+ else
+ prdelset(set, sys);
+ }
+ return (NULL);
+}
diff --git a/usr/src/lib/libproc/common/proc_set.c b/usr/src/lib/libproc/common/proc_set.c
new file mode 100644
index 0000000000..bdd7ccb77d
--- /dev/null
+++ b/usr/src/lib/libproc/common/proc_set.c
@@ -0,0 +1,86 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "libproc.h"
+#include <alloca.h>
+#include <string.h>
+
+/*
+ * Convenience wrapper to set the cred attributes of a victim process
+ * to a set of new values. Caller must supply a prochandle and a
+ * fully populated prcred structure.
+ */
+int
+Psetcred(struct ps_prochandle *Pr, const prcred_t *credp)
+{
+ int ngrp;
+ int ctlsize;
+ struct {
+ long cmd;
+ prcred_t cred;
+ } *ctlp;
+
+ if (Pr == NULL || credp == NULL)
+ return (-1);
+
+ ngrp = credp->pr_ngroups;
+ ctlsize = sizeof (prcred_t) + (ngrp - 1) * sizeof (gid_t);
+ ctlp = alloca(ctlsize + sizeof (long));
+
+ ctlp->cmd = PCSCREDX;
+ (void) memcpy(&ctlp->cred, credp, ctlsize);
+
+ if (write(Pctlfd(Pr), ctlp, sizeof (long) + ctlsize) < 0)
+ return (-1);
+
+ return (0);
+}
+
+/*
+ * Convenience wrapper to set the zoneid attribute of a victim process to a new
+ * value (only to and from GLOBAL_ZONEID makes sense). Caller must supply a
+ * prochandle and a valid zoneid.
+ */
+int
+Psetzoneid(struct ps_prochandle *Pr, zoneid_t zoneid)
+{
+ struct {
+ long cmd;
+ long zoneid;
+ } ctl;
+
+ if (Pr == NULL)
+ return (-1);
+
+ ctl.zoneid = zoneid;
+ ctl.cmd = PCSZONE;
+
+ if (write(Pctlfd(Pr), &ctl, sizeof (ctl)) < 0)
+ return (-1);
+ return (0);
+}
diff --git a/usr/src/lib/libproc/common/proc_stdio.c b/usr/src/lib/libproc/common/proc_stdio.c
new file mode 100644
index 0000000000..b8e74bfe5a
--- /dev/null
+++ b/usr/src/lib/libproc/common/proc_stdio.c
@@ -0,0 +1,171 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Utility functions for buffering output to stdout, stderr while
+ * process is grabbed. Prevents infamous deadlocks due to pfiles `pgrep xterm`
+ * and other varients.
+ */
+
+#include "libproc.h"
+#include <stdio.h>
+
+static int cached_stdout_fd = -1;
+static int cached_stderr_fd = -1;
+static int initialized = 0;
+
+static char stdout_name[] = "/tmp/.stdoutXXXXXX";
+static char stderr_name[] = "/tmp/.stderrXXXXXX";
+
+int
+proc_initstdio(void)
+{
+ int fd;
+
+ (void) fflush(stdout);
+ (void) fflush(stderr);
+
+ if ((cached_stdout_fd = dup(1)) < 0) {
+ return (-1);
+ }
+
+ if ((cached_stderr_fd = dup(2)) < 0) {
+ (void) close(cached_stdout_fd);
+ return (-1);
+ }
+
+ if ((fd = mkstemp(stdout_name)) < 0) {
+ (void) close(cached_stdout_fd);
+ (void) close(cached_stderr_fd);
+ return (-1);
+ }
+
+ (void) unlink(stdout_name);
+
+ if (dup2(fd, 1) < 0) {
+ (void) close(fd);
+ (void) close(cached_stdout_fd);
+ (void) close(cached_stderr_fd);
+ return (-1);
+ }
+
+ (void) close(fd);
+
+
+ if ((fd = mkstemp(stderr_name)) < 0) {
+ (void) dup2(cached_stdout_fd, 1);
+ (void) close(cached_stdout_fd);
+ (void) close(cached_stderr_fd);
+ return (-1);
+ }
+
+ (void) unlink(stderr_name);
+
+ if (dup2(fd, 2) < 0) {
+ (void) close(fd);
+ (void) dup2(cached_stdout_fd, 1);
+ (void) close(cached_stdout_fd);
+ (void) dup2(cached_stderr_fd, 2);
+ (void) close(cached_stderr_fd);
+ (void) close(fd);
+ return (-1);
+ }
+
+ (void) close(fd);
+
+ initialized = 1;
+
+ return (0);
+}
+
+static int
+copy_fd(int out, FILE *in, size_t len)
+{
+ char buffer[8192];
+ int rlen, alen;
+ int errors = 0;
+
+ rewind(in);
+ while (len > 0 && !errors) {
+ rlen = (len > sizeof (buffer)) ? sizeof (buffer) : len;
+ alen = read(fileno(in), buffer, rlen);
+ if (alen == rlen) {
+ if (write(out, buffer, alen) < alen)
+ errors++;
+ else
+ len -= alen;
+ }
+ else
+ errors++;
+ }
+ rewind(in);
+ return (errors);
+}
+
+int
+proc_flushstdio(void)
+{
+ size_t len;
+ int errors = 0;
+
+ /*
+ * flush any pending IO
+ */
+
+ if (!initialized)
+ return (-1);
+
+ (void) fflush(stdout);
+ (void) fflush(stderr);
+
+ if ((len = ftell(stdout)) > 0)
+ errors += copy_fd(cached_stdout_fd, stdout, len);
+
+
+ if ((len = ftell(stderr)) > 0)
+ errors += copy_fd(cached_stderr_fd, stderr, len);
+
+ return (errors?-1:0);
+}
+
+int
+proc_finistdio(void)
+{
+ if (!initialized)
+ return (-1);
+
+ if (proc_flushstdio() != 0)
+ return (-1);
+
+ (void) dup2(cached_stdout_fd, 1);
+ (void) close(cached_stdout_fd);
+ (void) dup2(cached_stderr_fd, 2);
+ (void) close(cached_stderr_fd);
+
+ return (0);
+}