xref: /illumos-gate/usr/src/cmd/mdb/common/mdb/mdb_proc.c (revision 7c478bd9)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate  * User Process Target
31*7c478bd9Sstevel@tonic-gate  *
32*7c478bd9Sstevel@tonic-gate  * The user process target is invoked when the -u or -p command-line options
33*7c478bd9Sstevel@tonic-gate  * are used, or when an ELF executable file or ELF core file is specified on
34*7c478bd9Sstevel@tonic-gate  * the command-line.  This target is also selected by default when no target
35*7c478bd9Sstevel@tonic-gate  * options are present.  In this case, it defaults the executable name to
36*7c478bd9Sstevel@tonic-gate  * "a.out".  If no process or core file is currently attached, the target
37*7c478bd9Sstevel@tonic-gate  * functions as a kind of virtual /dev/zero (in accordance with adb(1)
38*7c478bd9Sstevel@tonic-gate  * semantics); reads from the virtual address space return zeroes and writes
39*7c478bd9Sstevel@tonic-gate  * fail silently.  The proc target itself is designed as a wrapper around the
40*7c478bd9Sstevel@tonic-gate  * services provided by libproc.so: t->t_pshandle is set to the struct
41*7c478bd9Sstevel@tonic-gate  * ps_prochandle pointer returned as a handle by libproc.  The target also
42*7c478bd9Sstevel@tonic-gate  * opens the executable file itself using the MDB GElf services, for
43*7c478bd9Sstevel@tonic-gate  * interpreting the .symtab and .dynsym if no libproc handle has been
44*7c478bd9Sstevel@tonic-gate  * initialized, and for handling i/o to and from the object file.  Currently,
45*7c478bd9Sstevel@tonic-gate  * the only ISA-dependent portions of the proc target are the $r and ::fpregs
46*7c478bd9Sstevel@tonic-gate  * dcmds, the callbacks for t_next() and t_step_out(), and the list of named
47*7c478bd9Sstevel@tonic-gate  * registers; these are linked in from the proc_isadep.c file for each ISA and
48*7c478bd9Sstevel@tonic-gate  * called from the common code in this file.
49*7c478bd9Sstevel@tonic-gate  *
50*7c478bd9Sstevel@tonic-gate  * The user process target implements complete user process control using the
51*7c478bd9Sstevel@tonic-gate  * facilities provided by libproc.so.  The MDB execution control model and
52*7c478bd9Sstevel@tonic-gate  * an overview of software event management is described in mdb_target.c.  The
53*7c478bd9Sstevel@tonic-gate  * proc target implements breakpoints by replacing the instruction of interest
54*7c478bd9Sstevel@tonic-gate  * with a trap instruction, and then restoring the original instruction to step
55*7c478bd9Sstevel@tonic-gate  * over the breakpoint.  The idea of replacing program text with instructions
56*7c478bd9Sstevel@tonic-gate  * that transfer control to the debugger dates back as far as 1951 [1].  When
57*7c478bd9Sstevel@tonic-gate  * the target stops, we replace each breakpoint with the original instruction
58*7c478bd9Sstevel@tonic-gate  * as part of the disarm operation.  This means that no special processing is
59*7c478bd9Sstevel@tonic-gate  * required for t_vread() because the instrumented instructions will never be
60*7c478bd9Sstevel@tonic-gate  * seen by the debugger once the target stops.  Some debuggers have improved
61*7c478bd9Sstevel@tonic-gate  * start/stop performance by leaving breakpoint traps in place and then
62*7c478bd9Sstevel@tonic-gate  * handling a read from a breakpoint address as a special case.  Although this
63*7c478bd9Sstevel@tonic-gate  * improves efficiency for a source-level debugger, it runs somewhat contrary
64*7c478bd9Sstevel@tonic-gate  * to the philosophy of the low-level debugger.  Since we remove the
65*7c478bd9Sstevel@tonic-gate  * instructions, users can apply other external debugging tools to the process
66*7c478bd9Sstevel@tonic-gate  * once it has stopped (e.g. the proc(1) tools) and not be misled by MDB
67*7c478bd9Sstevel@tonic-gate  * instrumentation.  The tracing of faults, signals, system calls, and
68*7c478bd9Sstevel@tonic-gate  * watchpoints and general process inspection is implemented directly using
69*7c478bd9Sstevel@tonic-gate  * the mechanisms provided by /proc, as described originally in [2] and [3].
70*7c478bd9Sstevel@tonic-gate  *
71*7c478bd9Sstevel@tonic-gate  * References
72*7c478bd9Sstevel@tonic-gate  *
73*7c478bd9Sstevel@tonic-gate  * [1] S. Gill, "The Diagnosis Of Mistakes In Programmes on the EDSAC",
74*7c478bd9Sstevel@tonic-gate  *     Proceedings of the Royal Society Series A Mathematical and Physical
75*7c478bd9Sstevel@tonic-gate  *     Sciences, Cambridge University Press, 206(1087), May 1951, pp. 538-554.
76*7c478bd9Sstevel@tonic-gate  *
77*7c478bd9Sstevel@tonic-gate  * [2] T.J. Killian, "Processes as Files", Proceedings of the USENIX Association
78*7c478bd9Sstevel@tonic-gate  *     Summer Conference, Salt Lake City, June 1984, pp. 203-207.
79*7c478bd9Sstevel@tonic-gate  *
80*7c478bd9Sstevel@tonic-gate  * [3] Roger Faulkner and Ron Gomes, "The Process File System and Process
81*7c478bd9Sstevel@tonic-gate  *     Model in UNIX System V", Proceedings of the USENIX Association
82*7c478bd9Sstevel@tonic-gate  *     Winter Conference, Dallas, January 1991, pp. 243-252.
83*7c478bd9Sstevel@tonic-gate  */
84*7c478bd9Sstevel@tonic-gate 
85*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_proc.h>
86*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_disasm.h>
87*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_signal.h>
88*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_string.h>
89*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_module.h>
90*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_debug.h>
91*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_conf.h>
92*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_err.h>
93*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_types.h>
94*7c478bd9Sstevel@tonic-gate #include <mdb/mdb.h>
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate #include <sys/utsname.h>
97*7c478bd9Sstevel@tonic-gate #include <sys/wait.h>
98*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
99*7c478bd9Sstevel@tonic-gate #include <termio.h>
100*7c478bd9Sstevel@tonic-gate #include <signal.h>
101*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
102*7c478bd9Sstevel@tonic-gate #include <string.h>
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate #define	PC_FAKE		-1UL			/* illegal pc value unequal 0 */
105*7c478bd9Sstevel@tonic-gate 
106*7c478bd9Sstevel@tonic-gate static const char PT_EXEC_PATH[] = "a.out";	/* Default executable */
107*7c478bd9Sstevel@tonic-gate static const char PT_CORE_PATH[] = "core";	/* Default core file */
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate static const pt_ptl_ops_t proc_lwp_ops;
110*7c478bd9Sstevel@tonic-gate static const pt_ptl_ops_t proc_tdb_ops;
111*7c478bd9Sstevel@tonic-gate static const mdb_se_ops_t proc_brkpt_ops;
112*7c478bd9Sstevel@tonic-gate static const mdb_se_ops_t proc_wapt_ops;
113*7c478bd9Sstevel@tonic-gate 
114*7c478bd9Sstevel@tonic-gate static int pt_setrun(mdb_tgt_t *, mdb_tgt_status_t *, int);
115*7c478bd9Sstevel@tonic-gate static void pt_activate_common(mdb_tgt_t *);
116*7c478bd9Sstevel@tonic-gate static mdb_tgt_vespec_f pt_ignore_sig;
117*7c478bd9Sstevel@tonic-gate static mdb_tgt_se_f pt_fork;
118*7c478bd9Sstevel@tonic-gate static mdb_tgt_se_f pt_exec;
119*7c478bd9Sstevel@tonic-gate 
120*7c478bd9Sstevel@tonic-gate static int pt_lookup_by_name_thr(mdb_tgt_t *, const char *,
121*7c478bd9Sstevel@tonic-gate     const char *, GElf_Sym *, mdb_syminfo_t *, mdb_tgt_tid_t);
122*7c478bd9Sstevel@tonic-gate static int tlsbase(mdb_tgt_t *, mdb_tgt_tid_t, Lmid_t, const char *,
123*7c478bd9Sstevel@tonic-gate     psaddr_t *);
124*7c478bd9Sstevel@tonic-gate 
125*7c478bd9Sstevel@tonic-gate /*
126*7c478bd9Sstevel@tonic-gate  * The Perror_printf() function interposes on the default, empty libproc
127*7c478bd9Sstevel@tonic-gate  * definition.  It will be called to report additional information on complex
128*7c478bd9Sstevel@tonic-gate  * errors, such as a corrupt core file.  We just pass the args to vwarn.
129*7c478bd9Sstevel@tonic-gate  */
130*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
131*7c478bd9Sstevel@tonic-gate void
132*7c478bd9Sstevel@tonic-gate Perror_printf(struct ps_prochandle *P, const char *format, ...)
133*7c478bd9Sstevel@tonic-gate {
134*7c478bd9Sstevel@tonic-gate 	va_list alist;
135*7c478bd9Sstevel@tonic-gate 
136*7c478bd9Sstevel@tonic-gate 	va_start(alist, format);
137*7c478bd9Sstevel@tonic-gate 	vwarn(format, alist);
138*7c478bd9Sstevel@tonic-gate 	va_end(alist);
139*7c478bd9Sstevel@tonic-gate }
140*7c478bd9Sstevel@tonic-gate 
141*7c478bd9Sstevel@tonic-gate /*
142*7c478bd9Sstevel@tonic-gate  * Open the specified i/o backend as the a.out executable file, and attempt to
143*7c478bd9Sstevel@tonic-gate  * load its standard and dynamic symbol tables.  Note that if mdb_gelf_create
144*7c478bd9Sstevel@tonic-gate  * succeeds, io is assigned to p_fio and is automatically held by gelf_create.
145*7c478bd9Sstevel@tonic-gate  */
146*7c478bd9Sstevel@tonic-gate static mdb_gelf_file_t *
147*7c478bd9Sstevel@tonic-gate pt_open_aout(mdb_tgt_t *t, mdb_io_t *io)
148*7c478bd9Sstevel@tonic-gate {
149*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
150*7c478bd9Sstevel@tonic-gate 	GElf_Sym s1, s2;
151*7c478bd9Sstevel@tonic-gate 
152*7c478bd9Sstevel@tonic-gate 	if ((pt->p_file = mdb_gelf_create(io, ET_NONE, GF_FILE)) == NULL)
153*7c478bd9Sstevel@tonic-gate 		return (NULL);
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate 	pt->p_symtab = mdb_gelf_symtab_create_file(pt->p_file,
156*7c478bd9Sstevel@tonic-gate 	    SHT_SYMTAB, MDB_TGT_SYMTAB);
157*7c478bd9Sstevel@tonic-gate 	pt->p_dynsym = mdb_gelf_symtab_create_file(pt->p_file,
158*7c478bd9Sstevel@tonic-gate 	    SHT_DYNSYM, MDB_TGT_DYNSYM);
159*7c478bd9Sstevel@tonic-gate 
160*7c478bd9Sstevel@tonic-gate 	/*
161*7c478bd9Sstevel@tonic-gate 	 * If we've got an _start symbol with a zero size, prime the private
162*7c478bd9Sstevel@tonic-gate 	 * symbol table with a copy of _start with its size set to the distance
163*7c478bd9Sstevel@tonic-gate 	 * between _mcount and _start.  We do this because DevPro has shipped
164*7c478bd9Sstevel@tonic-gate 	 * the Intel crt1.o without proper .size directives for years, which
165*7c478bd9Sstevel@tonic-gate 	 * precludes proper identification of _start in stack traces.
166*7c478bd9Sstevel@tonic-gate 	 */
167*7c478bd9Sstevel@tonic-gate 	if (mdb_gelf_symtab_lookup_by_name(pt->p_dynsym, "_start", &s1,
168*7c478bd9Sstevel@tonic-gate 	    NULL) == 0 && s1.st_size == 0 &&
169*7c478bd9Sstevel@tonic-gate 	    GELF_ST_TYPE(s1.st_info) == STT_FUNC) {
170*7c478bd9Sstevel@tonic-gate 		if (mdb_gelf_symtab_lookup_by_name(pt->p_dynsym, "_mcount",
171*7c478bd9Sstevel@tonic-gate 		    &s2, NULL) == 0 && GELF_ST_TYPE(s2.st_info) == STT_FUNC) {
172*7c478bd9Sstevel@tonic-gate 			s1.st_size = s2.st_value - s1.st_value;
173*7c478bd9Sstevel@tonic-gate 			mdb_gelf_symtab_insert(mdb.m_prsym, "_start", &s1);
174*7c478bd9Sstevel@tonic-gate 		}
175*7c478bd9Sstevel@tonic-gate 	}
176*7c478bd9Sstevel@tonic-gate 
177*7c478bd9Sstevel@tonic-gate 	pt->p_fio = io;
178*7c478bd9Sstevel@tonic-gate 	return (pt->p_file);
179*7c478bd9Sstevel@tonic-gate }
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate /*
182*7c478bd9Sstevel@tonic-gate  * Destroy the symbol tables and GElf file object associated with p_fio.  Note
183*7c478bd9Sstevel@tonic-gate  * that we do not need to explicitly free p_fio: its reference count is
184*7c478bd9Sstevel@tonic-gate  * automatically decremented by mdb_gelf_destroy, which will free it if needed.
185*7c478bd9Sstevel@tonic-gate  */
186*7c478bd9Sstevel@tonic-gate static void
187*7c478bd9Sstevel@tonic-gate pt_close_aout(mdb_tgt_t *t)
188*7c478bd9Sstevel@tonic-gate {
189*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
190*7c478bd9Sstevel@tonic-gate 
191*7c478bd9Sstevel@tonic-gate 	if (pt->p_symtab != NULL) {
192*7c478bd9Sstevel@tonic-gate 		mdb_gelf_symtab_destroy(pt->p_symtab);
193*7c478bd9Sstevel@tonic-gate 		pt->p_symtab = NULL;
194*7c478bd9Sstevel@tonic-gate 	}
195*7c478bd9Sstevel@tonic-gate 
196*7c478bd9Sstevel@tonic-gate 	if (pt->p_dynsym != NULL) {
197*7c478bd9Sstevel@tonic-gate 		mdb_gelf_symtab_destroy(pt->p_dynsym);
198*7c478bd9Sstevel@tonic-gate 		pt->p_dynsym = NULL;
199*7c478bd9Sstevel@tonic-gate 	}
200*7c478bd9Sstevel@tonic-gate 
201*7c478bd9Sstevel@tonic-gate 	if (pt->p_file != NULL) {
202*7c478bd9Sstevel@tonic-gate 		mdb_gelf_destroy(pt->p_file);
203*7c478bd9Sstevel@tonic-gate 		pt->p_file = NULL;
204*7c478bd9Sstevel@tonic-gate 	}
205*7c478bd9Sstevel@tonic-gate 
206*7c478bd9Sstevel@tonic-gate 	mdb_gelf_symtab_delete(mdb.m_prsym, "_start", NULL);
207*7c478bd9Sstevel@tonic-gate 	pt->p_fio = NULL;
208*7c478bd9Sstevel@tonic-gate }
209*7c478bd9Sstevel@tonic-gate 
210*7c478bd9Sstevel@tonic-gate /*
211*7c478bd9Sstevel@tonic-gate  * Pobject_iter callback that we use to search for the presence of libthread in
212*7c478bd9Sstevel@tonic-gate  * order to load the corresponding libthread_db support.  We derive the
213*7c478bd9Sstevel@tonic-gate  * libthread_db path dynamically based on the libthread path.  If libthread is
214*7c478bd9Sstevel@tonic-gate  * found, this function returns 1 (and thus Pobject_iter aborts and returns 1)
215*7c478bd9Sstevel@tonic-gate  * regardless of whether it was successful in loading the libthread_db support.
216*7c478bd9Sstevel@tonic-gate  * If we iterate over all objects and no libthread is found, 0 is returned.
217*7c478bd9Sstevel@tonic-gate  * Since libthread_db support was then merged into libc_db, we load either
218*7c478bd9Sstevel@tonic-gate  * libc_db or libthread_db, depending on which library we see first.
219*7c478bd9Sstevel@tonic-gate  */
220*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
221*7c478bd9Sstevel@tonic-gate static int
222*7c478bd9Sstevel@tonic-gate thr_check(mdb_tgt_t *t, const prmap_t *pmp, const char *name)
223*7c478bd9Sstevel@tonic-gate {
224*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
225*7c478bd9Sstevel@tonic-gate 	const mdb_tdb_ops_t *ops;
226*7c478bd9Sstevel@tonic-gate 	char *p, *q;
227*7c478bd9Sstevel@tonic-gate 
228*7c478bd9Sstevel@tonic-gate 	char path[MAXPATHLEN + 8]; /* +8 for "/64" "_db" and '\0' */
229*7c478bd9Sstevel@tonic-gate 
230*7c478bd9Sstevel@tonic-gate 	const char *const libs[] = { "/libc.so", "/libthread.so" };
231*7c478bd9Sstevel@tonic-gate 	int libn;
232*7c478bd9Sstevel@tonic-gate 
233*7c478bd9Sstevel@tonic-gate 	if (name == NULL)
234*7c478bd9Sstevel@tonic-gate 		return (0); /* no rtld_db object name; keep going */
235*7c478bd9Sstevel@tonic-gate 
236*7c478bd9Sstevel@tonic-gate 	for (libn = 0; libn < sizeof (libs) / sizeof (libs[0]); libn++) {
237*7c478bd9Sstevel@tonic-gate 		if ((p = strstr(name, libs[libn])) != NULL)
238*7c478bd9Sstevel@tonic-gate 			break;
239*7c478bd9Sstevel@tonic-gate 	}
240*7c478bd9Sstevel@tonic-gate 
241*7c478bd9Sstevel@tonic-gate 	if (p == NULL)
242*7c478bd9Sstevel@tonic-gate 		return (0); /* no match; keep going */
243*7c478bd9Sstevel@tonic-gate 
244*7c478bd9Sstevel@tonic-gate 	(void) strncpy(path, name, MAXPATHLEN);
245*7c478bd9Sstevel@tonic-gate 	path[MAXPATHLEN] = '\0';
246*7c478bd9Sstevel@tonic-gate 	q = strstr(path, libs[libn]);
247*7c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL);
248*7c478bd9Sstevel@tonic-gate 
249*7c478bd9Sstevel@tonic-gate 	/*
250*7c478bd9Sstevel@tonic-gate 	 * If the 64-bit debugger is looking at a 32-bit victim, append /64 to
251*7c478bd9Sstevel@tonic-gate 	 * the library directory name so we load the 64-bit version.
252*7c478bd9Sstevel@tonic-gate 	 */
253*7c478bd9Sstevel@tonic-gate 	if (Pstatus(t->t_pshandle)->pr_dmodel != PR_MODEL_NATIVE) {
254*7c478bd9Sstevel@tonic-gate 		(void) strcpy(q, "/64");
255*7c478bd9Sstevel@tonic-gate 		q += 3;
256*7c478bd9Sstevel@tonic-gate 		(void) strcpy(q, p);
257*7c478bd9Sstevel@tonic-gate 	}
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate 	p = strchr(p, '.');
260*7c478bd9Sstevel@tonic-gate 	q = strchr(q, '.');
261*7c478bd9Sstevel@tonic-gate 	(void) strcpy(q, "_db");
262*7c478bd9Sstevel@tonic-gate 	q += 3;
263*7c478bd9Sstevel@tonic-gate 	(void) strcpy(q, p);
264*7c478bd9Sstevel@tonic-gate 
265*7c478bd9Sstevel@tonic-gate 	if ((ops = mdb_tdb_load(path)) == NULL) {
266*7c478bd9Sstevel@tonic-gate 		if (libn != 0 || errno != ENOENT)
267*7c478bd9Sstevel@tonic-gate 			warn("failed to load %s", path);
268*7c478bd9Sstevel@tonic-gate 		goto err;
269*7c478bd9Sstevel@tonic-gate 	}
270*7c478bd9Sstevel@tonic-gate 
271*7c478bd9Sstevel@tonic-gate 	if (ops == pt->p_tdb_ops)
272*7c478bd9Sstevel@tonic-gate 		return (1); /* no changes needed */
273*7c478bd9Sstevel@tonic-gate 
274*7c478bd9Sstevel@tonic-gate 	PTL_DTOR(t);
275*7c478bd9Sstevel@tonic-gate 	pt->p_tdb_ops = ops;
276*7c478bd9Sstevel@tonic-gate 	pt->p_ptl_ops = &proc_tdb_ops;
277*7c478bd9Sstevel@tonic-gate 	pt->p_ptl_hdl = NULL;
278*7c478bd9Sstevel@tonic-gate 
279*7c478bd9Sstevel@tonic-gate 	if (PTL_CTOR(t) == -1) {
280*7c478bd9Sstevel@tonic-gate 		warn("failed to initialize %s", path);
281*7c478bd9Sstevel@tonic-gate 		goto err;
282*7c478bd9Sstevel@tonic-gate 	}
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate 	mdb_dprintf(MDB_DBG_TGT, "loaded %s for debugging %s\n", path, name);
285*7c478bd9Sstevel@tonic-gate 	(void) mdb_tgt_status(t, &t->t_status);
286*7c478bd9Sstevel@tonic-gate 	return (1);
287*7c478bd9Sstevel@tonic-gate err:
288*7c478bd9Sstevel@tonic-gate 	PTL_DTOR(t);
289*7c478bd9Sstevel@tonic-gate 	pt->p_tdb_ops = NULL;
290*7c478bd9Sstevel@tonic-gate 	pt->p_ptl_ops = &proc_lwp_ops;
291*7c478bd9Sstevel@tonic-gate 	pt->p_ptl_hdl = NULL;
292*7c478bd9Sstevel@tonic-gate 
293*7c478bd9Sstevel@tonic-gate 	if (libn != 0 || errno != ENOENT) {
294*7c478bd9Sstevel@tonic-gate 		warn("warning: debugger will only be able to "
295*7c478bd9Sstevel@tonic-gate 		    "examine raw LWPs\n");
296*7c478bd9Sstevel@tonic-gate 	}
297*7c478bd9Sstevel@tonic-gate 
298*7c478bd9Sstevel@tonic-gate 	(void) mdb_tgt_status(t, &t->t_status);
299*7c478bd9Sstevel@tonic-gate 	return (1);
300*7c478bd9Sstevel@tonic-gate }
301*7c478bd9Sstevel@tonic-gate 
302*7c478bd9Sstevel@tonic-gate /*
303*7c478bd9Sstevel@tonic-gate  * Whenever the link map is consistent following an add or delete event, we ask
304*7c478bd9Sstevel@tonic-gate  * libproc to update its mappings, check to see if we need to load libthread_db,
305*7c478bd9Sstevel@tonic-gate  * and then update breakpoints which have been mapped or unmapped.
306*7c478bd9Sstevel@tonic-gate  */
307*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
308*7c478bd9Sstevel@tonic-gate static void
309*7c478bd9Sstevel@tonic-gate pt_rtld_event(mdb_tgt_t *t, int vid, void *private)
310*7c478bd9Sstevel@tonic-gate {
311*7c478bd9Sstevel@tonic-gate 	struct ps_prochandle *P = t->t_pshandle;
312*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
313*7c478bd9Sstevel@tonic-gate 	rd_event_msg_t rdm;
314*7c478bd9Sstevel@tonic-gate 	int docontinue = 1;
315*7c478bd9Sstevel@tonic-gate 
316*7c478bd9Sstevel@tonic-gate 	if (rd_event_getmsg(pt->p_rtld, &rdm) == RD_OK) {
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate 		mdb_dprintf(MDB_DBG_TGT, "rtld event type 0x%x state 0x%x\n",
319*7c478bd9Sstevel@tonic-gate 		    rdm.type, rdm.u.state);
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate 		if (rdm.type == RD_DLACTIVITY && rdm.u.state == RD_CONSISTENT) {
322*7c478bd9Sstevel@tonic-gate 			mdb_sespec_t *sep, *nsep = mdb_list_next(&t->t_active);
323*7c478bd9Sstevel@tonic-gate 			pt_brkpt_t *ptb;
324*7c478bd9Sstevel@tonic-gate 
325*7c478bd9Sstevel@tonic-gate 			Pupdate_maps(P);
326*7c478bd9Sstevel@tonic-gate 
327*7c478bd9Sstevel@tonic-gate 			if (Pobject_iter(P, (proc_map_f *)thr_check, t) == 0 &&
328*7c478bd9Sstevel@tonic-gate 			    pt->p_ptl_ops != &proc_lwp_ops) {
329*7c478bd9Sstevel@tonic-gate 				mdb_dprintf(MDB_DBG_TGT, "unloading thread_db "
330*7c478bd9Sstevel@tonic-gate 				    "support after dlclose\n");
331*7c478bd9Sstevel@tonic-gate 				PTL_DTOR(t);
332*7c478bd9Sstevel@tonic-gate 				pt->p_tdb_ops = NULL;
333*7c478bd9Sstevel@tonic-gate 				pt->p_ptl_ops = &proc_lwp_ops;
334*7c478bd9Sstevel@tonic-gate 				pt->p_ptl_hdl = NULL;
335*7c478bd9Sstevel@tonic-gate 				(void) mdb_tgt_status(t, &t->t_status);
336*7c478bd9Sstevel@tonic-gate 			}
337*7c478bd9Sstevel@tonic-gate 
338*7c478bd9Sstevel@tonic-gate 			for (sep = nsep; sep != NULL; sep = nsep) {
339*7c478bd9Sstevel@tonic-gate 				nsep = mdb_list_next(sep);
340*7c478bd9Sstevel@tonic-gate 				ptb = sep->se_data;
341*7c478bd9Sstevel@tonic-gate 
342*7c478bd9Sstevel@tonic-gate 				if (sep->se_ops == &proc_brkpt_ops &&
343*7c478bd9Sstevel@tonic-gate 				    Paddr_to_map(P, ptb->ptb_addr) == NULL)
344*7c478bd9Sstevel@tonic-gate 					mdb_tgt_sespec_idle_one(t, sep,
345*7c478bd9Sstevel@tonic-gate 					    EMDB_NOMAP);
346*7c478bd9Sstevel@tonic-gate 			}
347*7c478bd9Sstevel@tonic-gate 
348*7c478bd9Sstevel@tonic-gate 			if (!mdb_tgt_sespec_activate_all(t) &&
349*7c478bd9Sstevel@tonic-gate 			    (mdb.m_flags & MDB_FL_BPTNOSYMSTOP) &&
350*7c478bd9Sstevel@tonic-gate 			    pt->p_rtld_finished) {
351*7c478bd9Sstevel@tonic-gate 				/*
352*7c478bd9Sstevel@tonic-gate 				 * We weren't able to activate the breakpoints.
353*7c478bd9Sstevel@tonic-gate 				 * If so requested, we'll return without
354*7c478bd9Sstevel@tonic-gate 				 * calling continue, thus throwing the user into
355*7c478bd9Sstevel@tonic-gate 				 * the debugger.
356*7c478bd9Sstevel@tonic-gate 				 */
357*7c478bd9Sstevel@tonic-gate 				docontinue = 0;
358*7c478bd9Sstevel@tonic-gate 			}
359*7c478bd9Sstevel@tonic-gate 
360*7c478bd9Sstevel@tonic-gate 			if (pt->p_rdstate == PT_RD_ADD)
361*7c478bd9Sstevel@tonic-gate 				pt->p_rdstate = PT_RD_CONSIST;
362*7c478bd9Sstevel@tonic-gate 		}
363*7c478bd9Sstevel@tonic-gate 
364*7c478bd9Sstevel@tonic-gate 		if (rdm.type == RD_PREINIT)
365*7c478bd9Sstevel@tonic-gate 			(void) mdb_tgt_sespec_activate_all(t);
366*7c478bd9Sstevel@tonic-gate 
367*7c478bd9Sstevel@tonic-gate 		if (rdm.type == RD_POSTINIT) {
368*7c478bd9Sstevel@tonic-gate 			pt->p_rtld_finished = TRUE;
369*7c478bd9Sstevel@tonic-gate 			if (!mdb_tgt_sespec_activate_all(t) &&
370*7c478bd9Sstevel@tonic-gate 			    (mdb.m_flags & MDB_FL_BPTNOSYMSTOP)) {
371*7c478bd9Sstevel@tonic-gate 				/*
372*7c478bd9Sstevel@tonic-gate 				 * Now that rtld has been initialized, we
373*7c478bd9Sstevel@tonic-gate 				 * should be able to initialize all deferred
374*7c478bd9Sstevel@tonic-gate 				 * breakpoints.  If we can't, don't let the
375*7c478bd9Sstevel@tonic-gate 				 * target continue.
376*7c478bd9Sstevel@tonic-gate 				 */
377*7c478bd9Sstevel@tonic-gate 				docontinue = 0;
378*7c478bd9Sstevel@tonic-gate 			}
379*7c478bd9Sstevel@tonic-gate 		}
380*7c478bd9Sstevel@tonic-gate 
381*7c478bd9Sstevel@tonic-gate 		if (rdm.type == RD_DLACTIVITY && rdm.u.state == RD_ADD &&
382*7c478bd9Sstevel@tonic-gate 		    pt->p_rtld_finished)
383*7c478bd9Sstevel@tonic-gate 			pt->p_rdstate = MAX(pt->p_rdstate, PT_RD_ADD);
384*7c478bd9Sstevel@tonic-gate 	}
385*7c478bd9Sstevel@tonic-gate 
386*7c478bd9Sstevel@tonic-gate 	if (docontinue)
387*7c478bd9Sstevel@tonic-gate 		(void) mdb_tgt_continue(t, NULL);
388*7c478bd9Sstevel@tonic-gate }
389*7c478bd9Sstevel@tonic-gate 
390*7c478bd9Sstevel@tonic-gate static void
391*7c478bd9Sstevel@tonic-gate pt_post_attach(mdb_tgt_t *t)
392*7c478bd9Sstevel@tonic-gate {
393*7c478bd9Sstevel@tonic-gate 	struct ps_prochandle *P = t->t_pshandle;
394*7c478bd9Sstevel@tonic-gate 	const lwpstatus_t *psp = &Pstatus(P)->pr_lwp;
395*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
396*7c478bd9Sstevel@tonic-gate 	int hflag = MDB_TGT_SPEC_HIDDEN;
397*7c478bd9Sstevel@tonic-gate 
398*7c478bd9Sstevel@tonic-gate 	mdb_dprintf(MDB_DBG_TGT, "attach pr_flags=0x%x pr_why=%d pr_what=%d\n",
399*7c478bd9Sstevel@tonic-gate 	    psp->pr_flags, psp->pr_why, psp->pr_what);
400*7c478bd9Sstevel@tonic-gate 
401*7c478bd9Sstevel@tonic-gate 	/*
402*7c478bd9Sstevel@tonic-gate 	 * When we grab a process, the initial setting of p_rtld_finished
403*7c478bd9Sstevel@tonic-gate 	 * should be false if the process was just created by exec; otherwise
404*7c478bd9Sstevel@tonic-gate 	 * we permit unscoped references to resolve because we do not know how
405*7c478bd9Sstevel@tonic-gate 	 * far the process has proceeded through linker initialization.
406*7c478bd9Sstevel@tonic-gate 	 */
407*7c478bd9Sstevel@tonic-gate 	if ((psp->pr_flags & PR_ISTOP) && psp->pr_why == PR_SYSEXIT &&
408*7c478bd9Sstevel@tonic-gate 	    psp->pr_errno == 0 && (psp->pr_what == SYS_exec ||
409*7c478bd9Sstevel@tonic-gate 	    psp->pr_what == SYS_execve)) {
410*7c478bd9Sstevel@tonic-gate 		if (mdb.m_target == NULL) {
411*7c478bd9Sstevel@tonic-gate 			warn("target performed exec of %s\n",
412*7c478bd9Sstevel@tonic-gate 			    IOP_NAME(pt->p_fio));
413*7c478bd9Sstevel@tonic-gate 		}
414*7c478bd9Sstevel@tonic-gate 		pt->p_rtld_finished = FALSE;
415*7c478bd9Sstevel@tonic-gate 	} else
416*7c478bd9Sstevel@tonic-gate 		pt->p_rtld_finished = TRUE;
417*7c478bd9Sstevel@tonic-gate 
418*7c478bd9Sstevel@tonic-gate 	/*
419*7c478bd9Sstevel@tonic-gate 	 * When we grab a process, if it is stopped by job control and part of
420*7c478bd9Sstevel@tonic-gate 	 * the same session (i.e. same controlling tty), set MDB_FL_JOBCTL so
421*7c478bd9Sstevel@tonic-gate 	 * we will know to bring it to the foreground when we continue it.
422*7c478bd9Sstevel@tonic-gate 	 */
423*7c478bd9Sstevel@tonic-gate 	if (mdb.m_term != NULL && (psp->pr_flags & PR_STOPPED) &&
424*7c478bd9Sstevel@tonic-gate 	    psp->pr_why == PR_JOBCONTROL && getsid(0) == Pstatus(P)->pr_sid)
425*7c478bd9Sstevel@tonic-gate 		mdb.m_flags |= MDB_FL_JOBCTL;
426*7c478bd9Sstevel@tonic-gate 
427*7c478bd9Sstevel@tonic-gate 	/*
428*7c478bd9Sstevel@tonic-gate 	 * When we grab control of a live process, set F_RDWR so that the
429*7c478bd9Sstevel@tonic-gate 	 * target layer permits writes to the target's address space.
430*7c478bd9Sstevel@tonic-gate 	 */
431*7c478bd9Sstevel@tonic-gate 	t->t_flags |= MDB_TGT_F_RDWR;
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate 	(void) Pfault(P, FLTBPT, TRUE);		/* always trace breakpoints */
434*7c478bd9Sstevel@tonic-gate 	(void) Pfault(P, FLTWATCH, TRUE);	/* always trace watchpoints */
435*7c478bd9Sstevel@tonic-gate 	(void) Pfault(P, FLTTRACE, TRUE);	/* always trace single-step */
436*7c478bd9Sstevel@tonic-gate 
437*7c478bd9Sstevel@tonic-gate 	(void) Punsetflags(P, PR_ASYNC);	/* require synchronous mode */
438*7c478bd9Sstevel@tonic-gate 	(void) Psetflags(P, PR_BPTADJ);		/* always adjust eip on x86 */
439*7c478bd9Sstevel@tonic-gate 	(void) Psetflags(P, PR_FORK);		/* inherit tracing on fork */
440*7c478bd9Sstevel@tonic-gate 
441*7c478bd9Sstevel@tonic-gate 	/*
442*7c478bd9Sstevel@tonic-gate 	 * Install event specifiers to track fork and exec activities:
443*7c478bd9Sstevel@tonic-gate 	 */
444*7c478bd9Sstevel@tonic-gate 	(void) mdb_tgt_add_sysexit(t, SYS_forkall, hflag, pt_fork, NULL);
445*7c478bd9Sstevel@tonic-gate 	(void) mdb_tgt_add_sysexit(t, SYS_fork1, hflag, pt_fork, NULL);
446*7c478bd9Sstevel@tonic-gate 	(void) mdb_tgt_add_sysexit(t, SYS_vfork, hflag, pt_fork, NULL);
447*7c478bd9Sstevel@tonic-gate 	(void) mdb_tgt_add_sysexit(t, SYS_exec, hflag, pt_exec, NULL);
448*7c478bd9Sstevel@tonic-gate 	(void) mdb_tgt_add_sysexit(t, SYS_execve, hflag, pt_exec, NULL);
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate 	/*
451*7c478bd9Sstevel@tonic-gate 	 * Attempt to instantiate the librtld_db agent and set breakpoints
452*7c478bd9Sstevel@tonic-gate 	 * to track rtld activity.  We will legitimately fail to instantiate
453*7c478bd9Sstevel@tonic-gate 	 * the rtld_db agent if the target is statically linked.
454*7c478bd9Sstevel@tonic-gate 	 */
455*7c478bd9Sstevel@tonic-gate 	if (pt->p_rtld == NULL && (pt->p_rtld = Prd_agent(P)) != NULL) {
456*7c478bd9Sstevel@tonic-gate 		rd_notify_t rdn;
457*7c478bd9Sstevel@tonic-gate 		rd_err_e err;
458*7c478bd9Sstevel@tonic-gate 
459*7c478bd9Sstevel@tonic-gate 		if ((err = rd_event_enable(pt->p_rtld, TRUE)) != RD_OK) {
460*7c478bd9Sstevel@tonic-gate 			warn("failed to enable rtld_db event tracing: %s\n",
461*7c478bd9Sstevel@tonic-gate 			    rd_errstr(err));
462*7c478bd9Sstevel@tonic-gate 			goto out;
463*7c478bd9Sstevel@tonic-gate 		}
464*7c478bd9Sstevel@tonic-gate 
465*7c478bd9Sstevel@tonic-gate 		if ((err = rd_event_addr(pt->p_rtld, RD_PREINIT,
466*7c478bd9Sstevel@tonic-gate 		    &rdn)) == RD_OK && rdn.type == RD_NOTIFY_BPT) {
467*7c478bd9Sstevel@tonic-gate 			(void) mdb_tgt_add_vbrkpt(t, rdn.u.bptaddr,
468*7c478bd9Sstevel@tonic-gate 			    hflag, pt_rtld_event, NULL);
469*7c478bd9Sstevel@tonic-gate 		} else {
470*7c478bd9Sstevel@tonic-gate 			warn("failed to install rtld_db preinit tracing: %s\n",
471*7c478bd9Sstevel@tonic-gate 			    rd_errstr(err));
472*7c478bd9Sstevel@tonic-gate 		}
473*7c478bd9Sstevel@tonic-gate 
474*7c478bd9Sstevel@tonic-gate 		if ((err = rd_event_addr(pt->p_rtld, RD_POSTINIT,
475*7c478bd9Sstevel@tonic-gate 		    &rdn)) == RD_OK && rdn.type == RD_NOTIFY_BPT) {
476*7c478bd9Sstevel@tonic-gate 			(void) mdb_tgt_add_vbrkpt(t, rdn.u.bptaddr,
477*7c478bd9Sstevel@tonic-gate 			    hflag, pt_rtld_event, NULL);
478*7c478bd9Sstevel@tonic-gate 		} else {
479*7c478bd9Sstevel@tonic-gate 			warn("failed to install rtld_db postinit tracing: %s\n",
480*7c478bd9Sstevel@tonic-gate 			    rd_errstr(err));
481*7c478bd9Sstevel@tonic-gate 		}
482*7c478bd9Sstevel@tonic-gate 
483*7c478bd9Sstevel@tonic-gate 		if ((err = rd_event_addr(pt->p_rtld, RD_DLACTIVITY,
484*7c478bd9Sstevel@tonic-gate 		    &rdn)) == RD_OK && rdn.type == RD_NOTIFY_BPT) {
485*7c478bd9Sstevel@tonic-gate 			(void) mdb_tgt_add_vbrkpt(t, rdn.u.bptaddr,
486*7c478bd9Sstevel@tonic-gate 			    hflag, pt_rtld_event, NULL);
487*7c478bd9Sstevel@tonic-gate 		} else {
488*7c478bd9Sstevel@tonic-gate 			warn("failed to install rtld_db activity tracing: %s\n",
489*7c478bd9Sstevel@tonic-gate 			    rd_errstr(err));
490*7c478bd9Sstevel@tonic-gate 		}
491*7c478bd9Sstevel@tonic-gate 	}
492*7c478bd9Sstevel@tonic-gate out:
493*7c478bd9Sstevel@tonic-gate 	Pupdate_maps(P);
494*7c478bd9Sstevel@tonic-gate 	Psync(P);
495*7c478bd9Sstevel@tonic-gate 
496*7c478bd9Sstevel@tonic-gate 	/*
497*7c478bd9Sstevel@tonic-gate 	 * If librtld_db failed to initialize due to an error or because we are
498*7c478bd9Sstevel@tonic-gate 	 * debugging a statically linked executable, allow unscoped references.
499*7c478bd9Sstevel@tonic-gate 	 */
500*7c478bd9Sstevel@tonic-gate 	if (pt->p_rtld == NULL)
501*7c478bd9Sstevel@tonic-gate 		pt->p_rtld_finished = TRUE;
502*7c478bd9Sstevel@tonic-gate 
503*7c478bd9Sstevel@tonic-gate 	(void) mdb_tgt_sespec_activate_all(t);
504*7c478bd9Sstevel@tonic-gate }
505*7c478bd9Sstevel@tonic-gate 
506*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
507*7c478bd9Sstevel@tonic-gate static int
508*7c478bd9Sstevel@tonic-gate pt_vespec_delete(mdb_tgt_t *t, void *private, int id, void *data)
509*7c478bd9Sstevel@tonic-gate {
510*7c478bd9Sstevel@tonic-gate 	if (id < 0) {
511*7c478bd9Sstevel@tonic-gate 		ASSERT(data == NULL); /* we don't use any ve_data */
512*7c478bd9Sstevel@tonic-gate 		(void) mdb_tgt_vespec_delete(t, id);
513*7c478bd9Sstevel@tonic-gate 	}
514*7c478bd9Sstevel@tonic-gate 	return (0);
515*7c478bd9Sstevel@tonic-gate }
516*7c478bd9Sstevel@tonic-gate 
517*7c478bd9Sstevel@tonic-gate static void
518*7c478bd9Sstevel@tonic-gate pt_pre_detach(mdb_tgt_t *t, int clear_matched)
519*7c478bd9Sstevel@tonic-gate {
520*7c478bd9Sstevel@tonic-gate 	const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp;
521*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
522*7c478bd9Sstevel@tonic-gate 	long cmd = 0;
523*7c478bd9Sstevel@tonic-gate 
524*7c478bd9Sstevel@tonic-gate 	/*
525*7c478bd9Sstevel@tonic-gate 	 * If we are about to release the process and it is stopped on a traced
526*7c478bd9Sstevel@tonic-gate 	 * SIGINT, breakpoint fault, single-step fault, or watchpoint, make
527*7c478bd9Sstevel@tonic-gate 	 * sure to clear this event prior to releasing the process so that it
528*7c478bd9Sstevel@tonic-gate 	 * does not subsequently reissue the fault and die from SIGTRAP.
529*7c478bd9Sstevel@tonic-gate 	 */
530*7c478bd9Sstevel@tonic-gate 	if (psp->pr_flags & PR_ISTOP) {
531*7c478bd9Sstevel@tonic-gate 		if (psp->pr_why == PR_FAULTED && (psp->pr_what == FLTBPT ||
532*7c478bd9Sstevel@tonic-gate 		    psp->pr_what == FLTTRACE || psp->pr_what == FLTWATCH))
533*7c478bd9Sstevel@tonic-gate 			cmd = PCCFAULT;
534*7c478bd9Sstevel@tonic-gate 		else if (psp->pr_why == PR_SIGNALLED && psp->pr_what == SIGINT)
535*7c478bd9Sstevel@tonic-gate 			cmd = PCCSIG;
536*7c478bd9Sstevel@tonic-gate 
537*7c478bd9Sstevel@tonic-gate 		if (cmd != 0)
538*7c478bd9Sstevel@tonic-gate 			(void) write(Pctlfd(t->t_pshandle), &cmd, sizeof (cmd));
539*7c478bd9Sstevel@tonic-gate 	}
540*7c478bd9Sstevel@tonic-gate 
541*7c478bd9Sstevel@tonic-gate 	if (Pstate(t->t_pshandle) == PS_UNDEAD)
542*7c478bd9Sstevel@tonic-gate 		(void) waitpid(Pstatus(t->t_pshandle)->pr_pid, NULL, WNOHANG);
543*7c478bd9Sstevel@tonic-gate 
544*7c478bd9Sstevel@tonic-gate 	(void) mdb_tgt_vespec_iter(t, pt_vespec_delete, NULL);
545*7c478bd9Sstevel@tonic-gate 	mdb_tgt_sespec_idle_all(t, EMDB_NOPROC, clear_matched);
546*7c478bd9Sstevel@tonic-gate 
547*7c478bd9Sstevel@tonic-gate 	if (pt->p_fio != pt->p_aout_fio) {
548*7c478bd9Sstevel@tonic-gate 		pt_close_aout(t);
549*7c478bd9Sstevel@tonic-gate 		(void) pt_open_aout(t, pt->p_aout_fio);
550*7c478bd9Sstevel@tonic-gate 	}
551*7c478bd9Sstevel@tonic-gate 
552*7c478bd9Sstevel@tonic-gate 	PTL_DTOR(t);
553*7c478bd9Sstevel@tonic-gate 	pt->p_tdb_ops = NULL;
554*7c478bd9Sstevel@tonic-gate 	pt->p_ptl_ops = &proc_lwp_ops;
555*7c478bd9Sstevel@tonic-gate 	pt->p_ptl_hdl = NULL;
556*7c478bd9Sstevel@tonic-gate 
557*7c478bd9Sstevel@tonic-gate 	pt->p_rtld = NULL;
558*7c478bd9Sstevel@tonic-gate 	pt->p_signal = 0;
559*7c478bd9Sstevel@tonic-gate 	pt->p_rtld_finished = FALSE;
560*7c478bd9Sstevel@tonic-gate 	pt->p_rdstate = PT_RD_NONE;
561*7c478bd9Sstevel@tonic-gate }
562*7c478bd9Sstevel@tonic-gate 
563*7c478bd9Sstevel@tonic-gate static void
564*7c478bd9Sstevel@tonic-gate pt_release_parents(mdb_tgt_t *t)
565*7c478bd9Sstevel@tonic-gate {
566*7c478bd9Sstevel@tonic-gate 	struct ps_prochandle *P = t->t_pshandle;
567*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
568*7c478bd9Sstevel@tonic-gate 
569*7c478bd9Sstevel@tonic-gate 	mdb_sespec_t *sep;
570*7c478bd9Sstevel@tonic-gate 	pt_vforkp_t *vfp;
571*7c478bd9Sstevel@tonic-gate 
572*7c478bd9Sstevel@tonic-gate 	while ((vfp = mdb_list_next(&pt->p_vforkp)) != NULL) {
573*7c478bd9Sstevel@tonic-gate 		mdb_dprintf(MDB_DBG_TGT, "releasing vfork parent %d\n",
574*7c478bd9Sstevel@tonic-gate 		    (int)Pstatus(vfp->p_pshandle)->pr_pid);
575*7c478bd9Sstevel@tonic-gate 
576*7c478bd9Sstevel@tonic-gate 		/*
577*7c478bd9Sstevel@tonic-gate 		 * To release vfork parents, we must also wipe out any armed
578*7c478bd9Sstevel@tonic-gate 		 * events in the parent by switching t_pshandle and calling
579*7c478bd9Sstevel@tonic-gate 		 * se_disarm().  Do not change states or lose the matched list.
580*7c478bd9Sstevel@tonic-gate 		 */
581*7c478bd9Sstevel@tonic-gate 		t->t_pshandle = vfp->p_pshandle;
582*7c478bd9Sstevel@tonic-gate 
583*7c478bd9Sstevel@tonic-gate 		for (sep = mdb_list_next(&t->t_active); sep != NULL;
584*7c478bd9Sstevel@tonic-gate 		    sep = mdb_list_next(sep)) {
585*7c478bd9Sstevel@tonic-gate 			if (sep->se_state == MDB_TGT_SPEC_ARMED)
586*7c478bd9Sstevel@tonic-gate 				(void) sep->se_ops->se_disarm(t, sep);
587*7c478bd9Sstevel@tonic-gate 		}
588*7c478bd9Sstevel@tonic-gate 
589*7c478bd9Sstevel@tonic-gate 		t->t_pshandle = P;
590*7c478bd9Sstevel@tonic-gate 
591*7c478bd9Sstevel@tonic-gate 		Prelease(vfp->p_pshandle, PRELEASE_CLEAR);
592*7c478bd9Sstevel@tonic-gate 		mdb_list_delete(&pt->p_vforkp, vfp);
593*7c478bd9Sstevel@tonic-gate 		mdb_free(vfp, sizeof (pt_vforkp_t));
594*7c478bd9Sstevel@tonic-gate 	}
595*7c478bd9Sstevel@tonic-gate }
596*7c478bd9Sstevel@tonic-gate 
597*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
598*7c478bd9Sstevel@tonic-gate static void
599*7c478bd9Sstevel@tonic-gate pt_fork(mdb_tgt_t *t, int vid, void *private)
600*7c478bd9Sstevel@tonic-gate {
601*7c478bd9Sstevel@tonic-gate 	struct ps_prochandle *P = t->t_pshandle;
602*7c478bd9Sstevel@tonic-gate 	const lwpstatus_t *psp = &Pstatus(P)->pr_lwp;
603*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
604*7c478bd9Sstevel@tonic-gate 	mdb_sespec_t *sep;
605*7c478bd9Sstevel@tonic-gate 
606*7c478bd9Sstevel@tonic-gate 	int follow_parent = mdb.m_forkmode != MDB_FM_CHILD;
607*7c478bd9Sstevel@tonic-gate 	int is_vfork = psp->pr_what == SYS_vfork;
608*7c478bd9Sstevel@tonic-gate 
609*7c478bd9Sstevel@tonic-gate 	struct ps_prochandle *C;
610*7c478bd9Sstevel@tonic-gate 	const lwpstatus_t *csp;
611*7c478bd9Sstevel@tonic-gate 	char sysname[32];
612*7c478bd9Sstevel@tonic-gate 	int gcode;
613*7c478bd9Sstevel@tonic-gate 	char c;
614*7c478bd9Sstevel@tonic-gate 
615*7c478bd9Sstevel@tonic-gate 	mdb_dprintf(MDB_DBG_TGT, "parent %s: errno=%d rv1=%ld rv2=%ld\n",
616*7c478bd9Sstevel@tonic-gate 	    proc_sysname(psp->pr_what, sysname, sizeof (sysname)),
617*7c478bd9Sstevel@tonic-gate 	    psp->pr_errno, psp->pr_rval1, psp->pr_rval2);
618*7c478bd9Sstevel@tonic-gate 
619*7c478bd9Sstevel@tonic-gate 	if (psp->pr_errno != 0) {
620*7c478bd9Sstevel@tonic-gate 		(void) mdb_tgt_continue(t, NULL);
621*7c478bd9Sstevel@tonic-gate 		return; /* fork failed */
622*7c478bd9Sstevel@tonic-gate 	}
623*7c478bd9Sstevel@tonic-gate 
624*7c478bd9Sstevel@tonic-gate 	/*
625*7c478bd9Sstevel@tonic-gate 	 * If forkmode is ASK and stdout is a terminal, then ask the user to
626*7c478bd9Sstevel@tonic-gate 	 * explicitly set the fork behavior for this particular fork.
627*7c478bd9Sstevel@tonic-gate 	 */
628*7c478bd9Sstevel@tonic-gate 	if (mdb.m_forkmode == MDB_FM_ASK && mdb.m_term != NULL) {
629*7c478bd9Sstevel@tonic-gate 		mdb_iob_printf(mdb.m_err, "%s: %s detected: follow (p)arent "
630*7c478bd9Sstevel@tonic-gate 		    "or (c)hild? ", mdb.m_pname, sysname);
631*7c478bd9Sstevel@tonic-gate 		mdb_iob_flush(mdb.m_err);
632*7c478bd9Sstevel@tonic-gate 
633*7c478bd9Sstevel@tonic-gate 		while (IOP_READ(mdb.m_term, &c, sizeof (c)) == sizeof (c)) {
634*7c478bd9Sstevel@tonic-gate 			if (c == 'P' || c == 'p') {
635*7c478bd9Sstevel@tonic-gate 				mdb_iob_printf(mdb.m_err, "%c\n", c);
636*7c478bd9Sstevel@tonic-gate 				follow_parent = TRUE;
637*7c478bd9Sstevel@tonic-gate 				break;
638*7c478bd9Sstevel@tonic-gate 			} else if (c == 'C' || c == 'c') {
639*7c478bd9Sstevel@tonic-gate 				mdb_iob_printf(mdb.m_err, "%c\n", c);
640*7c478bd9Sstevel@tonic-gate 				follow_parent = FALSE;
641*7c478bd9Sstevel@tonic-gate 				break;
642*7c478bd9Sstevel@tonic-gate 			}
643*7c478bd9Sstevel@tonic-gate 		}
644*7c478bd9Sstevel@tonic-gate 	}
645*7c478bd9Sstevel@tonic-gate 
646*7c478bd9Sstevel@tonic-gate 	/*
647*7c478bd9Sstevel@tonic-gate 	 * The parent is now stopped on exit from its fork call.  We must now
648*7c478bd9Sstevel@tonic-gate 	 * grab the child on its return from fork in order to manipulate it.
649*7c478bd9Sstevel@tonic-gate 	 */
650*7c478bd9Sstevel@tonic-gate 	if ((C = Pgrab(psp->pr_rval1, PGRAB_RETAIN, &gcode)) == NULL) {
651*7c478bd9Sstevel@tonic-gate 		warn("failed to grab forked child process %ld: %s\n",
652*7c478bd9Sstevel@tonic-gate 		    psp->pr_rval1, Pgrab_error(gcode));
653*7c478bd9Sstevel@tonic-gate 		return; /* just stop if we failed to grab the child */
654*7c478bd9Sstevel@tonic-gate 	}
655*7c478bd9Sstevel@tonic-gate 
656*7c478bd9Sstevel@tonic-gate 	/*
657*7c478bd9Sstevel@tonic-gate 	 * We may have grabbed the child and stopped it prematurely before it
658*7c478bd9Sstevel@tonic-gate 	 * stopped on exit from fork.  If so, wait up to 1 sec for it to settle.
659*7c478bd9Sstevel@tonic-gate 	 */
660*7c478bd9Sstevel@tonic-gate 	if (Pstatus(C)->pr_lwp.pr_why != PR_SYSEXIT)
661*7c478bd9Sstevel@tonic-gate 		(void) Pwait(C, MILLISEC);
662*7c478bd9Sstevel@tonic-gate 
663*7c478bd9Sstevel@tonic-gate 	csp = &Pstatus(C)->pr_lwp;
664*7c478bd9Sstevel@tonic-gate 
665*7c478bd9Sstevel@tonic-gate 	if (csp->pr_why != PR_SYSEXIT || (csp->pr_what != SYS_forkall &&
666*7c478bd9Sstevel@tonic-gate 	    csp->pr_what != SYS_fork1 && csp->pr_what != SYS_vfork)) {
667*7c478bd9Sstevel@tonic-gate 		warn("forked child process %ld did not stop on exit from "
668*7c478bd9Sstevel@tonic-gate 		    "fork as expected\n", psp->pr_rval1);
669*7c478bd9Sstevel@tonic-gate 	}
670*7c478bd9Sstevel@tonic-gate 
671*7c478bd9Sstevel@tonic-gate 	warn("target forked child process %ld (debugger following %s)\n",
672*7c478bd9Sstevel@tonic-gate 	    psp->pr_rval1, follow_parent ? "parent" : "child");
673*7c478bd9Sstevel@tonic-gate 
674*7c478bd9Sstevel@tonic-gate 	(void) Punsetflags(C, PR_ASYNC);	/* require synchronous mode */
675*7c478bd9Sstevel@tonic-gate 	(void) Psetflags(C, PR_BPTADJ);		/* always adjust eip on x86 */
676*7c478bd9Sstevel@tonic-gate 	(void) Prd_agent(C);			/* initialize librtld_db */
677*7c478bd9Sstevel@tonic-gate 
678*7c478bd9Sstevel@tonic-gate 	/*
679*7c478bd9Sstevel@tonic-gate 	 * At the time pt_fork() is called, the target event engine has already
680*7c478bd9Sstevel@tonic-gate 	 * disarmed the specifiers on the active list, clearing out events in
681*7c478bd9Sstevel@tonic-gate 	 * the parent process.  However, this means that events that change
682*7c478bd9Sstevel@tonic-gate 	 * the address space (e.g. breakpoints) have not been effectively
683*7c478bd9Sstevel@tonic-gate 	 * disarmed in the child since its address space reflects the state of
684*7c478bd9Sstevel@tonic-gate 	 * the process at the time of fork when events were armed.  We must
685*7c478bd9Sstevel@tonic-gate 	 * therefore handle this as a special case and re-invoke the disarm
686*7c478bd9Sstevel@tonic-gate 	 * callback of each active specifier to clean out the child process.
687*7c478bd9Sstevel@tonic-gate 	 */
688*7c478bd9Sstevel@tonic-gate 	if (!is_vfork) {
689*7c478bd9Sstevel@tonic-gate 		for (t->t_pshandle = C, sep = mdb_list_next(&t->t_active);
690*7c478bd9Sstevel@tonic-gate 		    sep != NULL; sep = mdb_list_next(sep)) {
691*7c478bd9Sstevel@tonic-gate 			if (sep->se_state == MDB_TGT_SPEC_ACTIVE)
692*7c478bd9Sstevel@tonic-gate 				(void) sep->se_ops->se_disarm(t, sep);
693*7c478bd9Sstevel@tonic-gate 		}
694*7c478bd9Sstevel@tonic-gate 
695*7c478bd9Sstevel@tonic-gate 		t->t_pshandle = P; /* restore pshandle to parent */
696*7c478bd9Sstevel@tonic-gate 	}
697*7c478bd9Sstevel@tonic-gate 
698*7c478bd9Sstevel@tonic-gate 	/*
699*7c478bd9Sstevel@tonic-gate 	 * If we're following the parent process, we need to temporarily change
700*7c478bd9Sstevel@tonic-gate 	 * t_pshandle to refer to the child handle C so that we can clear out
701*7c478bd9Sstevel@tonic-gate 	 * all the events in the child prior to releasing it below.  If we are
702*7c478bd9Sstevel@tonic-gate 	 * tracing a vfork, we also need to explicitly wait for the child to
703*7c478bd9Sstevel@tonic-gate 	 * exec, exit, or die before we can reset and continue the parent.  We
704*7c478bd9Sstevel@tonic-gate 	 * avoid having to deal with the vfork child forking again by clearing
705*7c478bd9Sstevel@tonic-gate 	 * PR_FORK and setting PR_RLC; if it does fork it will effectively be
706*7c478bd9Sstevel@tonic-gate 	 * released from our control and we will continue following the parent.
707*7c478bd9Sstevel@tonic-gate 	 */
708*7c478bd9Sstevel@tonic-gate 	if (follow_parent) {
709*7c478bd9Sstevel@tonic-gate 		if (is_vfork) {
710*7c478bd9Sstevel@tonic-gate 			mdb_tgt_status_t status;
711*7c478bd9Sstevel@tonic-gate 
712*7c478bd9Sstevel@tonic-gate 			ASSERT(psp->pr_flags & PR_VFORKP);
713*7c478bd9Sstevel@tonic-gate 			mdb_tgt_sespec_idle_all(t, EBUSY, FALSE);
714*7c478bd9Sstevel@tonic-gate 			t->t_pshandle = C;
715*7c478bd9Sstevel@tonic-gate 
716*7c478bd9Sstevel@tonic-gate 			(void) Psysexit(C, SYS_exec, TRUE);
717*7c478bd9Sstevel@tonic-gate 			(void) Psysexit(C, SYS_execve, TRUE);
718*7c478bd9Sstevel@tonic-gate 
719*7c478bd9Sstevel@tonic-gate 			(void) Punsetflags(C, PR_FORK | PR_KLC);
720*7c478bd9Sstevel@tonic-gate 			(void) Psetflags(C, PR_RLC);
721*7c478bd9Sstevel@tonic-gate 
722*7c478bd9Sstevel@tonic-gate 			do {
723*7c478bd9Sstevel@tonic-gate 				if (pt_setrun(t, &status, 0) == -1 ||
724*7c478bd9Sstevel@tonic-gate 				    status.st_state == MDB_TGT_UNDEAD ||
725*7c478bd9Sstevel@tonic-gate 				    status.st_state == MDB_TGT_LOST)
726*7c478bd9Sstevel@tonic-gate 					break; /* failure or process died */
727*7c478bd9Sstevel@tonic-gate 
728*7c478bd9Sstevel@tonic-gate 			} while (csp->pr_why != PR_SYSEXIT ||
729*7c478bd9Sstevel@tonic-gate 			    csp->pr_errno != 0 || (csp->pr_what != SYS_exec &&
730*7c478bd9Sstevel@tonic-gate 			    csp->pr_what != SYS_execve));
731*7c478bd9Sstevel@tonic-gate 		} else
732*7c478bd9Sstevel@tonic-gate 			t->t_pshandle = C;
733*7c478bd9Sstevel@tonic-gate 	}
734*7c478bd9Sstevel@tonic-gate 
735*7c478bd9Sstevel@tonic-gate 	/*
736*7c478bd9Sstevel@tonic-gate 	 * If we are following the child, destroy any active libthread_db
737*7c478bd9Sstevel@tonic-gate 	 * handle before we release the parent process.
738*7c478bd9Sstevel@tonic-gate 	 */
739*7c478bd9Sstevel@tonic-gate 	if (!follow_parent) {
740*7c478bd9Sstevel@tonic-gate 		PTL_DTOR(t);
741*7c478bd9Sstevel@tonic-gate 		pt->p_tdb_ops = NULL;
742*7c478bd9Sstevel@tonic-gate 		pt->p_ptl_ops = &proc_lwp_ops;
743*7c478bd9Sstevel@tonic-gate 		pt->p_ptl_hdl = NULL;
744*7c478bd9Sstevel@tonic-gate 	}
745*7c478bd9Sstevel@tonic-gate 
746*7c478bd9Sstevel@tonic-gate 	/*
747*7c478bd9Sstevel@tonic-gate 	 * Idle all events to make sure the address space and tracing flags are
748*7c478bd9Sstevel@tonic-gate 	 * restored, and then release the process we are not tracing.  If we
749*7c478bd9Sstevel@tonic-gate 	 * are following the child of a vfork, we push the parent's pshandle
750*7c478bd9Sstevel@tonic-gate 	 * on to a list of vfork parents to be released when we exec or exit.
751*7c478bd9Sstevel@tonic-gate 	 */
752*7c478bd9Sstevel@tonic-gate 	if (is_vfork && !follow_parent) {
753*7c478bd9Sstevel@tonic-gate 		pt_vforkp_t *vfp = mdb_alloc(sizeof (pt_vforkp_t), UM_SLEEP);
754*7c478bd9Sstevel@tonic-gate 
755*7c478bd9Sstevel@tonic-gate 		ASSERT(psp->pr_flags & PR_VFORKP);
756*7c478bd9Sstevel@tonic-gate 		vfp->p_pshandle = P;
757*7c478bd9Sstevel@tonic-gate 		mdb_list_append(&pt->p_vforkp, vfp);
758*7c478bd9Sstevel@tonic-gate 		mdb_tgt_sespec_idle_all(t, EBUSY, FALSE);
759*7c478bd9Sstevel@tonic-gate 
760*7c478bd9Sstevel@tonic-gate 	} else {
761*7c478bd9Sstevel@tonic-gate 		mdb_tgt_sespec_idle_all(t, EBUSY, FALSE);
762*7c478bd9Sstevel@tonic-gate 		Prelease(t->t_pshandle, PRELEASE_CLEAR);
763*7c478bd9Sstevel@tonic-gate 		if (!follow_parent)
764*7c478bd9Sstevel@tonic-gate 			pt_release_parents(t);
765*7c478bd9Sstevel@tonic-gate 	}
766*7c478bd9Sstevel@tonic-gate 
767*7c478bd9Sstevel@tonic-gate 	/*
768*7c478bd9Sstevel@tonic-gate 	 * Now that all the hard stuff is done, switch t_pshandle back to the
769*7c478bd9Sstevel@tonic-gate 	 * process we are following and reset our events to the ACTIVE state.
770*7c478bd9Sstevel@tonic-gate 	 * If we are following the child, reset the libthread_db handle as well
771*7c478bd9Sstevel@tonic-gate 	 * as the rtld agent.
772*7c478bd9Sstevel@tonic-gate 	 */
773*7c478bd9Sstevel@tonic-gate 	if (follow_parent)
774*7c478bd9Sstevel@tonic-gate 		t->t_pshandle = P;
775*7c478bd9Sstevel@tonic-gate 	else {
776*7c478bd9Sstevel@tonic-gate 		t->t_pshandle = C;
777*7c478bd9Sstevel@tonic-gate 		pt->p_rtld = Prd_agent(C);
778*7c478bd9Sstevel@tonic-gate 		(void) Pobject_iter(t->t_pshandle, (proc_map_f *)thr_check, t);
779*7c478bd9Sstevel@tonic-gate 	}
780*7c478bd9Sstevel@tonic-gate 
781*7c478bd9Sstevel@tonic-gate 	(void) mdb_tgt_sespec_activate_all(t);
782*7c478bd9Sstevel@tonic-gate 	(void) mdb_tgt_continue(t, NULL);
783*7c478bd9Sstevel@tonic-gate }
784*7c478bd9Sstevel@tonic-gate 
785*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
786*7c478bd9Sstevel@tonic-gate static void
787*7c478bd9Sstevel@tonic-gate pt_exec(mdb_tgt_t *t, int vid, void *private)
788*7c478bd9Sstevel@tonic-gate {
789*7c478bd9Sstevel@tonic-gate 	struct ps_prochandle *P = t->t_pshandle;
790*7c478bd9Sstevel@tonic-gate 	const pstatus_t *psp = Pstatus(P);
791*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
792*7c478bd9Sstevel@tonic-gate 	int follow_exec = mdb.m_execmode == MDB_EM_FOLLOW;
793*7c478bd9Sstevel@tonic-gate 	pid_t pid = psp->pr_pid;
794*7c478bd9Sstevel@tonic-gate 
795*7c478bd9Sstevel@tonic-gate 	char execname[MAXPATHLEN];
796*7c478bd9Sstevel@tonic-gate 	mdb_sespec_t *sep, *nsep;
797*7c478bd9Sstevel@tonic-gate 	mdb_io_t *io;
798*7c478bd9Sstevel@tonic-gate 	char c;
799*7c478bd9Sstevel@tonic-gate 
800*7c478bd9Sstevel@tonic-gate 	mdb_dprintf(MDB_DBG_TGT, "exit from %s: errno=%d\n", proc_sysname(
801*7c478bd9Sstevel@tonic-gate 	    psp->pr_lwp.pr_what, execname, sizeof (execname)),
802*7c478bd9Sstevel@tonic-gate 	    psp->pr_lwp.pr_errno);
803*7c478bd9Sstevel@tonic-gate 
804*7c478bd9Sstevel@tonic-gate 	if (psp->pr_lwp.pr_errno != 0) {
805*7c478bd9Sstevel@tonic-gate 		(void) mdb_tgt_continue(t, NULL);
806*7c478bd9Sstevel@tonic-gate 		return; /* exec failed */
807*7c478bd9Sstevel@tonic-gate 	}
808*7c478bd9Sstevel@tonic-gate 
809*7c478bd9Sstevel@tonic-gate 	/*
810*7c478bd9Sstevel@tonic-gate 	 * If execmode is ASK and stdout is a terminal, then ask the user to
811*7c478bd9Sstevel@tonic-gate 	 * explicitly set the exec behavior for this particular exec.  If
812*7c478bd9Sstevel@tonic-gate 	 * Pstate() still shows PS_LOST, we are being called from pt_setrun()
813*7c478bd9Sstevel@tonic-gate 	 * directly and therefore we must resume the terminal since it is still
814*7c478bd9Sstevel@tonic-gate 	 * in the suspended state as far as tgt_continue() is concerned.
815*7c478bd9Sstevel@tonic-gate 	 */
816*7c478bd9Sstevel@tonic-gate 	if (mdb.m_execmode == MDB_EM_ASK && mdb.m_term != NULL) {
817*7c478bd9Sstevel@tonic-gate 		if (Pstate(P) == PS_LOST)
818*7c478bd9Sstevel@tonic-gate 			IOP_RESUME(mdb.m_term);
819*7c478bd9Sstevel@tonic-gate 
820*7c478bd9Sstevel@tonic-gate 		mdb_iob_printf(mdb.m_err, "%s: %s detected: (f)ollow new "
821*7c478bd9Sstevel@tonic-gate 		    "program or (s)top? ", mdb.m_pname, execname);
822*7c478bd9Sstevel@tonic-gate 		mdb_iob_flush(mdb.m_err);
823*7c478bd9Sstevel@tonic-gate 
824*7c478bd9Sstevel@tonic-gate 		while (IOP_READ(mdb.m_term, &c, sizeof (c)) == sizeof (c)) {
825*7c478bd9Sstevel@tonic-gate 			if (c == 'F' || c == 'f') {
826*7c478bd9Sstevel@tonic-gate 				mdb_iob_printf(mdb.m_err, "%c\n", c);
827*7c478bd9Sstevel@tonic-gate 				follow_exec = TRUE;
828*7c478bd9Sstevel@tonic-gate 				break;
829*7c478bd9Sstevel@tonic-gate 			} else if (c == 'S' || c == 's') {
830*7c478bd9Sstevel@tonic-gate 				mdb_iob_printf(mdb.m_err, "%c\n", c);
831*7c478bd9Sstevel@tonic-gate 				follow_exec = FALSE;
832*7c478bd9Sstevel@tonic-gate 				break;
833*7c478bd9Sstevel@tonic-gate 			}
834*7c478bd9Sstevel@tonic-gate 		}
835*7c478bd9Sstevel@tonic-gate 
836*7c478bd9Sstevel@tonic-gate 		if (Pstate(P) == PS_LOST)
837*7c478bd9Sstevel@tonic-gate 			IOP_SUSPEND(mdb.m_term);
838*7c478bd9Sstevel@tonic-gate 	}
839*7c478bd9Sstevel@tonic-gate 
840*7c478bd9Sstevel@tonic-gate 	pt_release_parents(t);	/* release any waiting vfork parents */
841*7c478bd9Sstevel@tonic-gate 	pt_pre_detach(t, FALSE); /* remove our breakpoints and idle events */
842*7c478bd9Sstevel@tonic-gate 	Preset_maps(P);		/* libproc must delete mappings and symtabs */
843*7c478bd9Sstevel@tonic-gate 	pt_close_aout(t);	/* free pt symbol tables and GElf file data */
844*7c478bd9Sstevel@tonic-gate 
845*7c478bd9Sstevel@tonic-gate 	/*
846*7c478bd9Sstevel@tonic-gate 	 * If we lost control of the process across the exec and are not able
847*7c478bd9Sstevel@tonic-gate 	 * to reopen it, we have no choice but to clear the matched event list
848*7c478bd9Sstevel@tonic-gate 	 * and wait for the user to quit or otherwise release the process.
849*7c478bd9Sstevel@tonic-gate 	 */
850*7c478bd9Sstevel@tonic-gate 	if (Pstate(P) == PS_LOST && Preopen(P) == -1) {
851*7c478bd9Sstevel@tonic-gate 		int error = errno;
852*7c478bd9Sstevel@tonic-gate 
853*7c478bd9Sstevel@tonic-gate 		warn("lost control of PID %d due to exec of %s executable\n",
854*7c478bd9Sstevel@tonic-gate 		    (int)pid, error == EOVERFLOW ? "64-bit" : "set-id");
855*7c478bd9Sstevel@tonic-gate 
856*7c478bd9Sstevel@tonic-gate 		for (sep = t->t_matched; sep != T_SE_END; sep = nsep) {
857*7c478bd9Sstevel@tonic-gate 			nsep = sep->se_matched;
858*7c478bd9Sstevel@tonic-gate 			sep->se_matched = NULL;
859*7c478bd9Sstevel@tonic-gate 			mdb_tgt_sespec_rele(t, sep);
860*7c478bd9Sstevel@tonic-gate 		}
861*7c478bd9Sstevel@tonic-gate 
862*7c478bd9Sstevel@tonic-gate 		if (error != EOVERFLOW)
863*7c478bd9Sstevel@tonic-gate 			return; /* just stop if we exec'd a set-id executable */
864*7c478bd9Sstevel@tonic-gate 	}
865*7c478bd9Sstevel@tonic-gate 
866*7c478bd9Sstevel@tonic-gate 	if (Pstate(P) != PS_LOST) {
867*7c478bd9Sstevel@tonic-gate 		if (Pexecname(P, execname, sizeof (execname)) == NULL) {
868*7c478bd9Sstevel@tonic-gate 			(void) mdb_iob_snprintf(execname, sizeof (execname),
869*7c478bd9Sstevel@tonic-gate 			    "/proc/%d/object/a.out", (int)pid);
870*7c478bd9Sstevel@tonic-gate 		}
871*7c478bd9Sstevel@tonic-gate 
872*7c478bd9Sstevel@tonic-gate 		if (follow_exec == FALSE || psp->pr_dmodel == PR_MODEL_NATIVE)
873*7c478bd9Sstevel@tonic-gate 			warn("target performed exec of %s\n", execname);
874*7c478bd9Sstevel@tonic-gate 
875*7c478bd9Sstevel@tonic-gate 		io = mdb_fdio_create_path(NULL, execname, pt->p_oflags, 0);
876*7c478bd9Sstevel@tonic-gate 		if (io == NULL) {
877*7c478bd9Sstevel@tonic-gate 			warn("failed to open %s", execname);
878*7c478bd9Sstevel@tonic-gate 			warn("a.out symbol tables will not be available\n");
879*7c478bd9Sstevel@tonic-gate 		} else if (pt_open_aout(t, io) == NULL) {
880*7c478bd9Sstevel@tonic-gate 			(void) mdb_dis_select(pt_disasm(NULL));
881*7c478bd9Sstevel@tonic-gate 			mdb_io_destroy(io);
882*7c478bd9Sstevel@tonic-gate 		} else
883*7c478bd9Sstevel@tonic-gate 			(void) mdb_dis_select(pt_disasm(&pt->p_file->gf_ehdr));
884*7c478bd9Sstevel@tonic-gate 	}
885*7c478bd9Sstevel@tonic-gate 
886*7c478bd9Sstevel@tonic-gate 	/*
887*7c478bd9Sstevel@tonic-gate 	 * We reset our libthread_db state here, but deliberately do NOT call
888*7c478bd9Sstevel@tonic-gate 	 * PTL_DTOR because we do not want to call libthread_db's td_ta_delete.
889*7c478bd9Sstevel@tonic-gate 	 * This interface is hopelessly broken in that it writes to the process
890*7c478bd9Sstevel@tonic-gate 	 * address space (which we do not want it to do after an exec) and it
891*7c478bd9Sstevel@tonic-gate 	 * doesn't bother deallocating any of its storage anyway.
892*7c478bd9Sstevel@tonic-gate 	 */
893*7c478bd9Sstevel@tonic-gate 	pt->p_tdb_ops = NULL;
894*7c478bd9Sstevel@tonic-gate 	pt->p_ptl_ops = &proc_lwp_ops;
895*7c478bd9Sstevel@tonic-gate 	pt->p_ptl_hdl = NULL;
896*7c478bd9Sstevel@tonic-gate 
897*7c478bd9Sstevel@tonic-gate 	if (follow_exec && psp->pr_dmodel != PR_MODEL_NATIVE) {
898*7c478bd9Sstevel@tonic-gate 		const char *argv[3];
899*7c478bd9Sstevel@tonic-gate 		char *state, *env;
900*7c478bd9Sstevel@tonic-gate 		char pidarg[16];
901*7c478bd9Sstevel@tonic-gate 		size_t envlen;
902*7c478bd9Sstevel@tonic-gate 
903*7c478bd9Sstevel@tonic-gate 		if (realpath(getexecname(), execname) == NULL) {
904*7c478bd9Sstevel@tonic-gate 			warn("cannot follow PID %d -- failed to resolve "
905*7c478bd9Sstevel@tonic-gate 			    "debugger pathname for re-exec", (int)pid);
906*7c478bd9Sstevel@tonic-gate 			return;
907*7c478bd9Sstevel@tonic-gate 		}
908*7c478bd9Sstevel@tonic-gate 
909*7c478bd9Sstevel@tonic-gate 		warn("restarting debugger to follow PID %d ...\n", (int)pid);
910*7c478bd9Sstevel@tonic-gate 		mdb_dprintf(MDB_DBG_TGT, "re-exec'ing %s\n", execname);
911*7c478bd9Sstevel@tonic-gate 
912*7c478bd9Sstevel@tonic-gate 		(void) mdb_snprintf(pidarg, sizeof (pidarg), "-p%d", (int)pid);
913*7c478bd9Sstevel@tonic-gate 
914*7c478bd9Sstevel@tonic-gate 		state = mdb_get_config();
915*7c478bd9Sstevel@tonic-gate 		envlen = strlen(MDB_CONFIG_ENV_VAR) + 1 + strlen(state) + 1;
916*7c478bd9Sstevel@tonic-gate 		env = mdb_alloc(envlen, UM_SLEEP);
917*7c478bd9Sstevel@tonic-gate 		snprintf(env, envlen, "%s=%s", MDB_CONFIG_ENV_VAR, state);
918*7c478bd9Sstevel@tonic-gate 
919*7c478bd9Sstevel@tonic-gate 		(void) putenv(env);
920*7c478bd9Sstevel@tonic-gate 
921*7c478bd9Sstevel@tonic-gate 		argv[0] = mdb.m_pname;
922*7c478bd9Sstevel@tonic-gate 		argv[1] = pidarg;
923*7c478bd9Sstevel@tonic-gate 		argv[2] = NULL;
924*7c478bd9Sstevel@tonic-gate 
925*7c478bd9Sstevel@tonic-gate 		if (mdb.m_term != NULL)
926*7c478bd9Sstevel@tonic-gate 			IOP_SUSPEND(mdb.m_term);
927*7c478bd9Sstevel@tonic-gate 
928*7c478bd9Sstevel@tonic-gate 		Prelease(P, PRELEASE_CLEAR | PRELEASE_HANG);
929*7c478bd9Sstevel@tonic-gate 		(void) execv(execname, (char *const *)argv);
930*7c478bd9Sstevel@tonic-gate 		warn("failed to re-exec debugger");
931*7c478bd9Sstevel@tonic-gate 
932*7c478bd9Sstevel@tonic-gate 		if (mdb.m_term != NULL)
933*7c478bd9Sstevel@tonic-gate 			IOP_RESUME(mdb.m_term);
934*7c478bd9Sstevel@tonic-gate 
935*7c478bd9Sstevel@tonic-gate 		t->t_pshandle = pt->p_idlehandle;
936*7c478bd9Sstevel@tonic-gate 		return;
937*7c478bd9Sstevel@tonic-gate 	}
938*7c478bd9Sstevel@tonic-gate 
939*7c478bd9Sstevel@tonic-gate 	pt_post_attach(t);	/* install tracing flags and activate events */
940*7c478bd9Sstevel@tonic-gate 	pt_activate_common(t);	/* initialize librtld_db and libthread_db */
941*7c478bd9Sstevel@tonic-gate 
942*7c478bd9Sstevel@tonic-gate 	if (psp->pr_dmodel != PR_MODEL_NATIVE && mdb.m_term != NULL) {
943*7c478bd9Sstevel@tonic-gate 		warn("loadable dcmds will not operate on non-native %d-bit "
944*7c478bd9Sstevel@tonic-gate 		    "data model\n", psp->pr_dmodel == PR_MODEL_ILP32 ? 32 : 64);
945*7c478bd9Sstevel@tonic-gate 		warn("use ::release -a and then run mdb -p %d to restart "
946*7c478bd9Sstevel@tonic-gate 		    "debugger\n", (int)pid);
947*7c478bd9Sstevel@tonic-gate 	}
948*7c478bd9Sstevel@tonic-gate 
949*7c478bd9Sstevel@tonic-gate 	if (follow_exec)
950*7c478bd9Sstevel@tonic-gate 		(void) mdb_tgt_continue(t, NULL);
951*7c478bd9Sstevel@tonic-gate }
952*7c478bd9Sstevel@tonic-gate 
953*7c478bd9Sstevel@tonic-gate static int
954*7c478bd9Sstevel@tonic-gate pt_setflags(mdb_tgt_t *t, int flags)
955*7c478bd9Sstevel@tonic-gate {
956*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
957*7c478bd9Sstevel@tonic-gate 
958*7c478bd9Sstevel@tonic-gate 	if ((flags ^ t->t_flags) & MDB_TGT_F_RDWR) {
959*7c478bd9Sstevel@tonic-gate 		int mode = (flags & MDB_TGT_F_RDWR) ? O_RDWR : O_RDONLY;
960*7c478bd9Sstevel@tonic-gate 		mdb_io_t *io;
961*7c478bd9Sstevel@tonic-gate 
962*7c478bd9Sstevel@tonic-gate 		if (pt->p_fio == NULL)
963*7c478bd9Sstevel@tonic-gate 			return (set_errno(EMDB_NOEXEC));
964*7c478bd9Sstevel@tonic-gate 
965*7c478bd9Sstevel@tonic-gate 		io = mdb_fdio_create_path(NULL, IOP_NAME(pt->p_fio), mode, 0);
966*7c478bd9Sstevel@tonic-gate 
967*7c478bd9Sstevel@tonic-gate 		if (io == NULL)
968*7c478bd9Sstevel@tonic-gate 			return (-1); /* errno is set for us */
969*7c478bd9Sstevel@tonic-gate 
970*7c478bd9Sstevel@tonic-gate 		t->t_flags = (t->t_flags & ~MDB_TGT_F_RDWR) |
971*7c478bd9Sstevel@tonic-gate 		    (flags & MDB_TGT_F_RDWR);
972*7c478bd9Sstevel@tonic-gate 
973*7c478bd9Sstevel@tonic-gate 		pt->p_fio = mdb_io_hold(io);
974*7c478bd9Sstevel@tonic-gate 		mdb_io_rele(pt->p_file->gf_io);
975*7c478bd9Sstevel@tonic-gate 		pt->p_file->gf_io = pt->p_fio;
976*7c478bd9Sstevel@tonic-gate 	}
977*7c478bd9Sstevel@tonic-gate 
978*7c478bd9Sstevel@tonic-gate 	if (flags & MDB_TGT_F_FORCE) {
979*7c478bd9Sstevel@tonic-gate 		t->t_flags |= MDB_TGT_F_FORCE;
980*7c478bd9Sstevel@tonic-gate 		pt->p_gflags |= PGRAB_FORCE;
981*7c478bd9Sstevel@tonic-gate 	}
982*7c478bd9Sstevel@tonic-gate 
983*7c478bd9Sstevel@tonic-gate 	return (0);
984*7c478bd9Sstevel@tonic-gate }
985*7c478bd9Sstevel@tonic-gate 
986*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
987*7c478bd9Sstevel@tonic-gate static int
988*7c478bd9Sstevel@tonic-gate pt_frame(void *arglim, uintptr_t pc, uint_t argc, const long *argv,
989*7c478bd9Sstevel@tonic-gate     const mdb_tgt_gregset_t *gregs)
990*7c478bd9Sstevel@tonic-gate {
991*7c478bd9Sstevel@tonic-gate 	argc = MIN(argc, (uint_t)(uintptr_t)arglim);
992*7c478bd9Sstevel@tonic-gate 	mdb_printf("%a(", pc);
993*7c478bd9Sstevel@tonic-gate 
994*7c478bd9Sstevel@tonic-gate 	if (argc != 0) {
995*7c478bd9Sstevel@tonic-gate 		mdb_printf("%lr", *argv++);
996*7c478bd9Sstevel@tonic-gate 		for (argc--; argc != 0; argc--)
997*7c478bd9Sstevel@tonic-gate 			mdb_printf(", %lr", *argv++);
998*7c478bd9Sstevel@tonic-gate 	}
999*7c478bd9Sstevel@tonic-gate 
1000*7c478bd9Sstevel@tonic-gate 	mdb_printf(")\n");
1001*7c478bd9Sstevel@tonic-gate 	return (0);
1002*7c478bd9Sstevel@tonic-gate }
1003*7c478bd9Sstevel@tonic-gate 
1004*7c478bd9Sstevel@tonic-gate static int
1005*7c478bd9Sstevel@tonic-gate pt_framev(void *arglim, uintptr_t pc, uint_t argc, const long *argv,
1006*7c478bd9Sstevel@tonic-gate     const mdb_tgt_gregset_t *gregs)
1007*7c478bd9Sstevel@tonic-gate {
1008*7c478bd9Sstevel@tonic-gate 	argc = MIN(argc, (uint_t)(uintptr_t)arglim);
1009*7c478bd9Sstevel@tonic-gate #if defined(__i386) || defined(__amd64)
1010*7c478bd9Sstevel@tonic-gate 	mdb_printf("%0?lr %a(", gregs->gregs[R_FP], pc);
1011*7c478bd9Sstevel@tonic-gate #else
1012*7c478bd9Sstevel@tonic-gate 	mdb_printf("%0?lr %a(", gregs->gregs[R_SP], pc);
1013*7c478bd9Sstevel@tonic-gate #endif
1014*7c478bd9Sstevel@tonic-gate 	if (argc != 0) {
1015*7c478bd9Sstevel@tonic-gate 		mdb_printf("%lr", *argv++);
1016*7c478bd9Sstevel@tonic-gate 		for (argc--; argc != 0; argc--)
1017*7c478bd9Sstevel@tonic-gate 			mdb_printf(", %lr", *argv++);
1018*7c478bd9Sstevel@tonic-gate 	}
1019*7c478bd9Sstevel@tonic-gate 
1020*7c478bd9Sstevel@tonic-gate 	mdb_printf(")\n");
1021*7c478bd9Sstevel@tonic-gate 	return (0);
1022*7c478bd9Sstevel@tonic-gate }
1023*7c478bd9Sstevel@tonic-gate 
1024*7c478bd9Sstevel@tonic-gate static int
1025*7c478bd9Sstevel@tonic-gate pt_framer(void *arglim, uintptr_t pc, uint_t argc, const long *argv,
1026*7c478bd9Sstevel@tonic-gate     const mdb_tgt_gregset_t *gregs)
1027*7c478bd9Sstevel@tonic-gate {
1028*7c478bd9Sstevel@tonic-gate 	if (pt_frameregs(arglim, pc, argc, argv, gregs, pc == PC_FAKE) == -1) {
1029*7c478bd9Sstevel@tonic-gate 		/*
1030*7c478bd9Sstevel@tonic-gate 		 * Use verbose format if register format is not supported.
1031*7c478bd9Sstevel@tonic-gate 		 */
1032*7c478bd9Sstevel@tonic-gate 		return (pt_framev(arglim, pc, argc, argv, gregs));
1033*7c478bd9Sstevel@tonic-gate 	}
1034*7c478bd9Sstevel@tonic-gate 
1035*7c478bd9Sstevel@tonic-gate 	return (0);
1036*7c478bd9Sstevel@tonic-gate }
1037*7c478bd9Sstevel@tonic-gate 
1038*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1039*7c478bd9Sstevel@tonic-gate static int
1040*7c478bd9Sstevel@tonic-gate pt_stack_common(uintptr_t addr, uint_t flags, int argc,
1041*7c478bd9Sstevel@tonic-gate     const mdb_arg_t *argv, mdb_tgt_stack_f *func, prgreg_t saved_pc)
1042*7c478bd9Sstevel@tonic-gate {
1043*7c478bd9Sstevel@tonic-gate 	void *arg = (void *)(uintptr_t)mdb.m_nargs;
1044*7c478bd9Sstevel@tonic-gate 	mdb_tgt_t *t = mdb.m_target;
1045*7c478bd9Sstevel@tonic-gate 	mdb_tgt_gregset_t gregs;
1046*7c478bd9Sstevel@tonic-gate 
1047*7c478bd9Sstevel@tonic-gate 	if (argc != 0) {
1048*7c478bd9Sstevel@tonic-gate 		if (argv->a_type == MDB_TYPE_CHAR || argc > 1)
1049*7c478bd9Sstevel@tonic-gate 			return (DCMD_USAGE);
1050*7c478bd9Sstevel@tonic-gate 
1051*7c478bd9Sstevel@tonic-gate 		if (argv->a_type == MDB_TYPE_STRING)
1052*7c478bd9Sstevel@tonic-gate 			arg = (void *)(uintptr_t)mdb_strtoull(argv->a_un.a_str);
1053*7c478bd9Sstevel@tonic-gate 		else
1054*7c478bd9Sstevel@tonic-gate 			arg = (void *)(uintptr_t)argv->a_un.a_val;
1055*7c478bd9Sstevel@tonic-gate 	}
1056*7c478bd9Sstevel@tonic-gate 
1057*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle == NULL || Pstate(t->t_pshandle) == PS_IDLE) {
1058*7c478bd9Sstevel@tonic-gate 		mdb_warn("no process active\n");
1059*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
1060*7c478bd9Sstevel@tonic-gate 	}
1061*7c478bd9Sstevel@tonic-gate 
1062*7c478bd9Sstevel@tonic-gate 	/*
1063*7c478bd9Sstevel@tonic-gate 	 * In the universe of sparcv7, sparcv9, ia32, and amd64 this code can be
1064*7c478bd9Sstevel@tonic-gate 	 * common: <sys/procfs_isa.h> conveniently #defines R_FP to be the
1065*7c478bd9Sstevel@tonic-gate 	 * appropriate register we need to set in order to perform a stack
1066*7c478bd9Sstevel@tonic-gate 	 * traceback from a given frame address.
1067*7c478bd9Sstevel@tonic-gate 	 */
1068*7c478bd9Sstevel@tonic-gate 	if (flags & DCMD_ADDRSPEC) {
1069*7c478bd9Sstevel@tonic-gate 		bzero(&gregs, sizeof (gregs));
1070*7c478bd9Sstevel@tonic-gate 		gregs.gregs[R_FP] = addr;
1071*7c478bd9Sstevel@tonic-gate #ifdef __sparc
1072*7c478bd9Sstevel@tonic-gate 		gregs.gregs[R_I7] = saved_pc;
1073*7c478bd9Sstevel@tonic-gate #endif /* __sparc */
1074*7c478bd9Sstevel@tonic-gate 	} else if (PTL_GETREGS(t, PTL_TID(t), gregs.gregs) != 0) {
1075*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to get current register set");
1076*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
1077*7c478bd9Sstevel@tonic-gate 	}
1078*7c478bd9Sstevel@tonic-gate 
1079*7c478bd9Sstevel@tonic-gate 	(void) mdb_tgt_stack_iter(t, &gregs, func, arg);
1080*7c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
1081*7c478bd9Sstevel@tonic-gate }
1082*7c478bd9Sstevel@tonic-gate 
1083*7c478bd9Sstevel@tonic-gate static int
1084*7c478bd9Sstevel@tonic-gate pt_stack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1085*7c478bd9Sstevel@tonic-gate {
1086*7c478bd9Sstevel@tonic-gate 	return (pt_stack_common(addr, flags, argc, argv, pt_frame, 0));
1087*7c478bd9Sstevel@tonic-gate }
1088*7c478bd9Sstevel@tonic-gate 
1089*7c478bd9Sstevel@tonic-gate static int
1090*7c478bd9Sstevel@tonic-gate pt_stackv(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1091*7c478bd9Sstevel@tonic-gate {
1092*7c478bd9Sstevel@tonic-gate 	return (pt_stack_common(addr, flags, argc, argv, pt_framev, 0));
1093*7c478bd9Sstevel@tonic-gate }
1094*7c478bd9Sstevel@tonic-gate 
1095*7c478bd9Sstevel@tonic-gate static int
1096*7c478bd9Sstevel@tonic-gate pt_stackr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1097*7c478bd9Sstevel@tonic-gate {
1098*7c478bd9Sstevel@tonic-gate 	/*
1099*7c478bd9Sstevel@tonic-gate 	 * Force printing of first register window, by setting  the
1100*7c478bd9Sstevel@tonic-gate 	 * saved pc (%i7) to PC_FAKE.
1101*7c478bd9Sstevel@tonic-gate 	 */
1102*7c478bd9Sstevel@tonic-gate 	return (pt_stack_common(addr, flags, argc, argv, pt_framer, PC_FAKE));
1103*7c478bd9Sstevel@tonic-gate }
1104*7c478bd9Sstevel@tonic-gate 
1105*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1106*7c478bd9Sstevel@tonic-gate static int
1107*7c478bd9Sstevel@tonic-gate pt_ignored(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1108*7c478bd9Sstevel@tonic-gate {
1109*7c478bd9Sstevel@tonic-gate 	struct ps_prochandle *P = mdb.m_target->t_pshandle;
1110*7c478bd9Sstevel@tonic-gate 	char buf[PRSIGBUFSZ];
1111*7c478bd9Sstevel@tonic-gate 
1112*7c478bd9Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) || argc != 0)
1113*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
1114*7c478bd9Sstevel@tonic-gate 
1115*7c478bd9Sstevel@tonic-gate 	if (P == NULL) {
1116*7c478bd9Sstevel@tonic-gate 		mdb_warn("no process is currently active\n");
1117*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
1118*7c478bd9Sstevel@tonic-gate 	}
1119*7c478bd9Sstevel@tonic-gate 
1120*7c478bd9Sstevel@tonic-gate 	mdb_printf("%s\n", proc_sigset2str(&Pstatus(P)->pr_sigtrace, " ",
1121*7c478bd9Sstevel@tonic-gate 	    FALSE, buf, sizeof (buf)));
1122*7c478bd9Sstevel@tonic-gate 
1123*7c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
1124*7c478bd9Sstevel@tonic-gate }
1125*7c478bd9Sstevel@tonic-gate 
1126*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1127*7c478bd9Sstevel@tonic-gate static int
1128*7c478bd9Sstevel@tonic-gate pt_lwpid(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1129*7c478bd9Sstevel@tonic-gate {
1130*7c478bd9Sstevel@tonic-gate 	struct ps_prochandle *P = mdb.m_target->t_pshandle;
1131*7c478bd9Sstevel@tonic-gate 
1132*7c478bd9Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) || argc != 0)
1133*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
1134*7c478bd9Sstevel@tonic-gate 
1135*7c478bd9Sstevel@tonic-gate 	if (P == NULL) {
1136*7c478bd9Sstevel@tonic-gate 		mdb_warn("no process is currently active\n");
1137*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
1138*7c478bd9Sstevel@tonic-gate 	}
1139*7c478bd9Sstevel@tonic-gate 
1140*7c478bd9Sstevel@tonic-gate 	mdb_printf("%d\n", Pstatus(P)->pr_lwp.pr_lwpid);
1141*7c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
1142*7c478bd9Sstevel@tonic-gate }
1143*7c478bd9Sstevel@tonic-gate 
1144*7c478bd9Sstevel@tonic-gate static int
1145*7c478bd9Sstevel@tonic-gate pt_print_lwpid(int *n, const lwpstatus_t *psp)
1146*7c478bd9Sstevel@tonic-gate {
1147*7c478bd9Sstevel@tonic-gate 	struct ps_prochandle *P = mdb.m_target->t_pshandle;
1148*7c478bd9Sstevel@tonic-gate 	int nlwp = Pstatus(P)->pr_nlwp;
1149*7c478bd9Sstevel@tonic-gate 
1150*7c478bd9Sstevel@tonic-gate 	if (*n == nlwp - 2)
1151*7c478bd9Sstevel@tonic-gate 		mdb_printf("%d and ", (int)psp->pr_lwpid);
1152*7c478bd9Sstevel@tonic-gate 	else if (*n == nlwp - 1)
1153*7c478bd9Sstevel@tonic-gate 		mdb_printf("%d are", (int)psp->pr_lwpid);
1154*7c478bd9Sstevel@tonic-gate 	else
1155*7c478bd9Sstevel@tonic-gate 		mdb_printf("%d, ", (int)psp->pr_lwpid);
1156*7c478bd9Sstevel@tonic-gate 
1157*7c478bd9Sstevel@tonic-gate 	(*n)++;
1158*7c478bd9Sstevel@tonic-gate 	return (0);
1159*7c478bd9Sstevel@tonic-gate }
1160*7c478bd9Sstevel@tonic-gate 
1161*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1162*7c478bd9Sstevel@tonic-gate static int
1163*7c478bd9Sstevel@tonic-gate pt_lwpids(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1164*7c478bd9Sstevel@tonic-gate {
1165*7c478bd9Sstevel@tonic-gate 	struct ps_prochandle *P = mdb.m_target->t_pshandle;
1166*7c478bd9Sstevel@tonic-gate 	int n = 0;
1167*7c478bd9Sstevel@tonic-gate 
1168*7c478bd9Sstevel@tonic-gate 	if (P == NULL) {
1169*7c478bd9Sstevel@tonic-gate 		mdb_warn("no process is currently active\n");
1170*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
1171*7c478bd9Sstevel@tonic-gate 	}
1172*7c478bd9Sstevel@tonic-gate 
1173*7c478bd9Sstevel@tonic-gate 	switch (Pstatus(P)->pr_nlwp) {
1174*7c478bd9Sstevel@tonic-gate 	case 0:
1175*7c478bd9Sstevel@tonic-gate 		mdb_printf("no lwps are");
1176*7c478bd9Sstevel@tonic-gate 		break;
1177*7c478bd9Sstevel@tonic-gate 	case 1:
1178*7c478bd9Sstevel@tonic-gate 		mdb_printf("lwpid %d is the only lwp",
1179*7c478bd9Sstevel@tonic-gate 		    Pstatus(P)->pr_lwp.pr_lwpid);
1180*7c478bd9Sstevel@tonic-gate 		break;
1181*7c478bd9Sstevel@tonic-gate 	default:
1182*7c478bd9Sstevel@tonic-gate 		mdb_printf("lwpids ");
1183*7c478bd9Sstevel@tonic-gate 		(void) Plwp_iter(P, (proc_lwp_f *)pt_print_lwpid, &n);
1184*7c478bd9Sstevel@tonic-gate 	}
1185*7c478bd9Sstevel@tonic-gate 
1186*7c478bd9Sstevel@tonic-gate 	switch (Pstate(P)) {
1187*7c478bd9Sstevel@tonic-gate 	case PS_DEAD:
1188*7c478bd9Sstevel@tonic-gate 		mdb_printf(" in core of process %d.\n", Pstatus(P)->pr_pid);
1189*7c478bd9Sstevel@tonic-gate 		break;
1190*7c478bd9Sstevel@tonic-gate 	case PS_IDLE:
1191*7c478bd9Sstevel@tonic-gate 		mdb_printf(" in idle target.\n");
1192*7c478bd9Sstevel@tonic-gate 		break;
1193*7c478bd9Sstevel@tonic-gate 	default:
1194*7c478bd9Sstevel@tonic-gate 		mdb_printf(" in process %d.\n", (int)Pstatus(P)->pr_pid);
1195*7c478bd9Sstevel@tonic-gate 		break;
1196*7c478bd9Sstevel@tonic-gate 	}
1197*7c478bd9Sstevel@tonic-gate 
1198*7c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
1199*7c478bd9Sstevel@tonic-gate }
1200*7c478bd9Sstevel@tonic-gate 
1201*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1202*7c478bd9Sstevel@tonic-gate static int
1203*7c478bd9Sstevel@tonic-gate pt_ignore(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1204*7c478bd9Sstevel@tonic-gate {
1205*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = mdb.m_target->t_data;
1206*7c478bd9Sstevel@tonic-gate 
1207*7c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC) || argc != 0)
1208*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
1209*7c478bd9Sstevel@tonic-gate 
1210*7c478bd9Sstevel@tonic-gate 	if (addr < 1 || addr > pt->p_maxsig) {
1211*7c478bd9Sstevel@tonic-gate 		mdb_warn("invalid signal number -- 0t%lu\n", addr);
1212*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
1213*7c478bd9Sstevel@tonic-gate 	}
1214*7c478bd9Sstevel@tonic-gate 
1215*7c478bd9Sstevel@tonic-gate 	(void) mdb_tgt_vespec_iter(mdb.m_target, pt_ignore_sig, (void *)addr);
1216*7c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
1217*7c478bd9Sstevel@tonic-gate }
1218*7c478bd9Sstevel@tonic-gate 
1219*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1220*7c478bd9Sstevel@tonic-gate static int
1221*7c478bd9Sstevel@tonic-gate pt_attach(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1222*7c478bd9Sstevel@tonic-gate {
1223*7c478bd9Sstevel@tonic-gate 	mdb_tgt_t *t = mdb.m_target;
1224*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
1225*7c478bd9Sstevel@tonic-gate 	int state, perr;
1226*7c478bd9Sstevel@tonic-gate 
1227*7c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC) && argc == 0)
1228*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
1229*7c478bd9Sstevel@tonic-gate 
1230*7c478bd9Sstevel@tonic-gate 	if (((flags & DCMD_ADDRSPEC) && argc != 0) || argc > 1 ||
1231*7c478bd9Sstevel@tonic-gate 	    (argc != 0 && argv->a_type != MDB_TYPE_STRING))
1232*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
1233*7c478bd9Sstevel@tonic-gate 
1234*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle != NULL && Pstate(t->t_pshandle) != PS_IDLE) {
1235*7c478bd9Sstevel@tonic-gate 		mdb_warn("debugger is already attached to a %s\n",
1236*7c478bd9Sstevel@tonic-gate 		    (Pstate(t->t_pshandle) == PS_DEAD) ? "core" : "process");
1237*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
1238*7c478bd9Sstevel@tonic-gate 	}
1239*7c478bd9Sstevel@tonic-gate 
1240*7c478bd9Sstevel@tonic-gate 	if (pt->p_fio == NULL) {
1241*7c478bd9Sstevel@tonic-gate 		mdb_warn("attach requires executable to be specified on "
1242*7c478bd9Sstevel@tonic-gate 		    "command-line (or use -p)\n");
1243*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
1244*7c478bd9Sstevel@tonic-gate 	}
1245*7c478bd9Sstevel@tonic-gate 
1246*7c478bd9Sstevel@tonic-gate 	if (flags & DCMD_ADDRSPEC)
1247*7c478bd9Sstevel@tonic-gate 		t->t_pshandle = Pgrab((pid_t)addr, pt->p_gflags, &perr);
1248*7c478bd9Sstevel@tonic-gate 	else
1249*7c478bd9Sstevel@tonic-gate 		t->t_pshandle = proc_arg_grab(argv->a_un.a_str,
1250*7c478bd9Sstevel@tonic-gate 		    PR_ARG_ANY, pt->p_gflags, &perr);
1251*7c478bd9Sstevel@tonic-gate 
1252*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle == NULL) {
1253*7c478bd9Sstevel@tonic-gate 		t->t_pshandle = pt->p_idlehandle;
1254*7c478bd9Sstevel@tonic-gate 		mdb_warn("cannot attach: %s\n", Pgrab_error(perr));
1255*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
1256*7c478bd9Sstevel@tonic-gate 	}
1257*7c478bd9Sstevel@tonic-gate 
1258*7c478bd9Sstevel@tonic-gate 	state = Pstate(t->t_pshandle);
1259*7c478bd9Sstevel@tonic-gate 	if (state != PS_DEAD && state != PS_IDLE) {
1260*7c478bd9Sstevel@tonic-gate 		(void) Punsetflags(t->t_pshandle, PR_KLC);
1261*7c478bd9Sstevel@tonic-gate 		(void) Psetflags(t->t_pshandle, PR_RLC);
1262*7c478bd9Sstevel@tonic-gate 		pt_post_attach(t);
1263*7c478bd9Sstevel@tonic-gate 		pt_activate_common(t);
1264*7c478bd9Sstevel@tonic-gate 	}
1265*7c478bd9Sstevel@tonic-gate 
1266*7c478bd9Sstevel@tonic-gate 	(void) mdb_tgt_status(t, &t->t_status);
1267*7c478bd9Sstevel@tonic-gate 	mdb_module_load_all(0);
1268*7c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
1269*7c478bd9Sstevel@tonic-gate }
1270*7c478bd9Sstevel@tonic-gate 
1271*7c478bd9Sstevel@tonic-gate static int
1272*7c478bd9Sstevel@tonic-gate pt_regstatus(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1273*7c478bd9Sstevel@tonic-gate {
1274*7c478bd9Sstevel@tonic-gate 	mdb_tgt_t *t = mdb.m_target;
1275*7c478bd9Sstevel@tonic-gate 
1276*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle != NULL) {
1277*7c478bd9Sstevel@tonic-gate 		const pstatus_t *psp = Pstatus(t->t_pshandle);
1278*7c478bd9Sstevel@tonic-gate 		int cursig = psp->pr_lwp.pr_cursig;
1279*7c478bd9Sstevel@tonic-gate 		char signame[SIG2STR_MAX];
1280*7c478bd9Sstevel@tonic-gate 		int state = Pstate(t->t_pshandle);
1281*7c478bd9Sstevel@tonic-gate 
1282*7c478bd9Sstevel@tonic-gate 		if (state != PS_DEAD && state != PS_IDLE)
1283*7c478bd9Sstevel@tonic-gate 			mdb_printf("process id = %d\n", psp->pr_pid);
1284*7c478bd9Sstevel@tonic-gate 		else
1285*7c478bd9Sstevel@tonic-gate 			mdb_printf("no process\n");
1286*7c478bd9Sstevel@tonic-gate 
1287*7c478bd9Sstevel@tonic-gate 		if (cursig != 0 && sig2str(cursig, signame) == 0)
1288*7c478bd9Sstevel@tonic-gate 			mdb_printf("SIG%s: %s\n", signame, strsignal(cursig));
1289*7c478bd9Sstevel@tonic-gate 	}
1290*7c478bd9Sstevel@tonic-gate 
1291*7c478bd9Sstevel@tonic-gate 	return (pt_regs(addr, flags, argc, argv));
1292*7c478bd9Sstevel@tonic-gate }
1293*7c478bd9Sstevel@tonic-gate 
1294*7c478bd9Sstevel@tonic-gate static int
1295*7c478bd9Sstevel@tonic-gate pt_findstack(uintptr_t tid, uint_t flags, int argc, const mdb_arg_t *argv)
1296*7c478bd9Sstevel@tonic-gate {
1297*7c478bd9Sstevel@tonic-gate 	mdb_tgt_t *t = mdb.m_target;
1298*7c478bd9Sstevel@tonic-gate 	mdb_tgt_gregset_t gregs;
1299*7c478bd9Sstevel@tonic-gate 	int showargs = 0;
1300*7c478bd9Sstevel@tonic-gate 	int count;
1301*7c478bd9Sstevel@tonic-gate 	uintptr_t pc, sp;
1302*7c478bd9Sstevel@tonic-gate 
1303*7c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
1304*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
1305*7c478bd9Sstevel@tonic-gate 
1306*7c478bd9Sstevel@tonic-gate 	count = mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &showargs,
1307*7c478bd9Sstevel@tonic-gate 	    NULL);
1308*7c478bd9Sstevel@tonic-gate 	argc -= count;
1309*7c478bd9Sstevel@tonic-gate 	argv += count;
1310*7c478bd9Sstevel@tonic-gate 
1311*7c478bd9Sstevel@tonic-gate 	if (argc > 1 || (argc == 1 && argv->a_type != MDB_TYPE_STRING))
1312*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
1313*7c478bd9Sstevel@tonic-gate 
1314*7c478bd9Sstevel@tonic-gate 	if (PTL_GETREGS(t, tid, gregs.gregs) != 0) {
1315*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to get register set for thread %p", tid);
1316*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
1317*7c478bd9Sstevel@tonic-gate 	}
1318*7c478bd9Sstevel@tonic-gate 
1319*7c478bd9Sstevel@tonic-gate 	pc = gregs.gregs[R_PC];
1320*7c478bd9Sstevel@tonic-gate #if defined(__i386) || defined(__amd64)
1321*7c478bd9Sstevel@tonic-gate 	sp = gregs.gregs[R_FP];
1322*7c478bd9Sstevel@tonic-gate #else
1323*7c478bd9Sstevel@tonic-gate 	sp = gregs.gregs[R_SP];
1324*7c478bd9Sstevel@tonic-gate #endif
1325*7c478bd9Sstevel@tonic-gate 	mdb_printf("stack pointer for thread %p: %p\n", tid, sp);
1326*7c478bd9Sstevel@tonic-gate 	if (pc != 0)
1327*7c478bd9Sstevel@tonic-gate 		mdb_printf("[ %0?lr %a() ]\n", sp, pc);
1328*7c478bd9Sstevel@tonic-gate 
1329*7c478bd9Sstevel@tonic-gate 	(void) mdb_inc_indent(2);
1330*7c478bd9Sstevel@tonic-gate 	mdb_set_dot(sp);
1331*7c478bd9Sstevel@tonic-gate 
1332*7c478bd9Sstevel@tonic-gate 	if (argc == 1)
1333*7c478bd9Sstevel@tonic-gate 		(void) mdb_eval(argv->a_un.a_str);
1334*7c478bd9Sstevel@tonic-gate 	else if (showargs)
1335*7c478bd9Sstevel@tonic-gate 		(void) mdb_eval("<.$C");
1336*7c478bd9Sstevel@tonic-gate 	else
1337*7c478bd9Sstevel@tonic-gate 		(void) mdb_eval("<.$C0");
1338*7c478bd9Sstevel@tonic-gate 
1339*7c478bd9Sstevel@tonic-gate 	(void) mdb_dec_indent(2);
1340*7c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
1341*7c478bd9Sstevel@tonic-gate }
1342*7c478bd9Sstevel@tonic-gate 
1343*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1344*7c478bd9Sstevel@tonic-gate static int
1345*7c478bd9Sstevel@tonic-gate pt_gcore(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1346*7c478bd9Sstevel@tonic-gate {
1347*7c478bd9Sstevel@tonic-gate 	mdb_tgt_t *t = mdb.m_target;
1348*7c478bd9Sstevel@tonic-gate 	char *prefix = "core";
1349*7c478bd9Sstevel@tonic-gate 	char *content_str = NULL;
1350*7c478bd9Sstevel@tonic-gate 	core_content_t content = CC_CONTENT_DEFAULT;
1351*7c478bd9Sstevel@tonic-gate 	size_t size;
1352*7c478bd9Sstevel@tonic-gate 	char *fname;
1353*7c478bd9Sstevel@tonic-gate 	pid_t pid;
1354*7c478bd9Sstevel@tonic-gate 
1355*7c478bd9Sstevel@tonic-gate 	if (flags & DCMD_ADDRSPEC)
1356*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
1357*7c478bd9Sstevel@tonic-gate 
1358*7c478bd9Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
1359*7c478bd9Sstevel@tonic-gate 	    'o', MDB_OPT_STR, &prefix,
1360*7c478bd9Sstevel@tonic-gate 	    'c', MDB_OPT_STR, &content_str, NULL) != argc)
1361*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
1362*7c478bd9Sstevel@tonic-gate 
1363*7c478bd9Sstevel@tonic-gate 	if (content_str != NULL &&
1364*7c478bd9Sstevel@tonic-gate 	    (proc_str2content(content_str, &content) != 0 ||
1365*7c478bd9Sstevel@tonic-gate 	    content == CC_CONTENT_INVALID)) {
1366*7c478bd9Sstevel@tonic-gate 		mdb_warn("invalid content string '%s'\n", content_str);
1367*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
1368*7c478bd9Sstevel@tonic-gate 	}
1369*7c478bd9Sstevel@tonic-gate 
1370*7c478bd9Sstevel@tonic-gate 	pid = Pstatus(t->t_pshandle)->pr_pid;
1371*7c478bd9Sstevel@tonic-gate 	size = 1 + mdb_snprintf(NULL, 0, "%s.%d", prefix, (int)pid);
1372*7c478bd9Sstevel@tonic-gate 	fname = mdb_alloc(size, UM_SLEEP | UM_GC);
1373*7c478bd9Sstevel@tonic-gate 	(void) mdb_snprintf(fname, size, "%s.%d", prefix, (int)pid);
1374*7c478bd9Sstevel@tonic-gate 
1375*7c478bd9Sstevel@tonic-gate 	if (Pgcore(t->t_pshandle, fname, content) != 0) {
1376*7c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't dump core");
1377*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
1378*7c478bd9Sstevel@tonic-gate 	}
1379*7c478bd9Sstevel@tonic-gate 
1380*7c478bd9Sstevel@tonic-gate 	mdb_warn("%s dumped\n", fname);
1381*7c478bd9Sstevel@tonic-gate 
1382*7c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
1383*7c478bd9Sstevel@tonic-gate }
1384*7c478bd9Sstevel@tonic-gate 
1385*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1386*7c478bd9Sstevel@tonic-gate static int
1387*7c478bd9Sstevel@tonic-gate pt_kill(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1388*7c478bd9Sstevel@tonic-gate {
1389*7c478bd9Sstevel@tonic-gate 	mdb_tgt_t *t = mdb.m_target;
1390*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
1391*7c478bd9Sstevel@tonic-gate 	int state;
1392*7c478bd9Sstevel@tonic-gate 
1393*7c478bd9Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) || argc != 0)
1394*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
1395*7c478bd9Sstevel@tonic-gate 
1396*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle != NULL &&
1397*7c478bd9Sstevel@tonic-gate 	    (state = Pstate(t->t_pshandle)) != PS_DEAD && state != PS_IDLE) {
1398*7c478bd9Sstevel@tonic-gate 		mdb_warn("victim process PID %d forcibly terminated\n",
1399*7c478bd9Sstevel@tonic-gate 		    (int)Pstatus(t->t_pshandle)->pr_pid);
1400*7c478bd9Sstevel@tonic-gate 		pt_pre_detach(t, TRUE);
1401*7c478bd9Sstevel@tonic-gate 		pt_release_parents(t);
1402*7c478bd9Sstevel@tonic-gate 		Prelease(t->t_pshandle, PRELEASE_KILL);
1403*7c478bd9Sstevel@tonic-gate 		t->t_pshandle = pt->p_idlehandle;
1404*7c478bd9Sstevel@tonic-gate 		(void) mdb_tgt_status(t, &t->t_status);
1405*7c478bd9Sstevel@tonic-gate 		mdb.m_flags &= ~(MDB_FL_VCREATE | MDB_FL_JOBCTL);
1406*7c478bd9Sstevel@tonic-gate 	} else
1407*7c478bd9Sstevel@tonic-gate 		mdb_warn("no victim process is currently under control\n");
1408*7c478bd9Sstevel@tonic-gate 
1409*7c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
1410*7c478bd9Sstevel@tonic-gate }
1411*7c478bd9Sstevel@tonic-gate 
1412*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1413*7c478bd9Sstevel@tonic-gate static int
1414*7c478bd9Sstevel@tonic-gate pt_detach(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1415*7c478bd9Sstevel@tonic-gate {
1416*7c478bd9Sstevel@tonic-gate 	mdb_tgt_t *t = mdb.m_target;
1417*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
1418*7c478bd9Sstevel@tonic-gate 	int rflags = pt->p_rflags;
1419*7c478bd9Sstevel@tonic-gate 
1420*7c478bd9Sstevel@tonic-gate 	if (argc != 0 && argv->a_type == MDB_TYPE_STRING &&
1421*7c478bd9Sstevel@tonic-gate 	    strcmp(argv->a_un.a_str, "-a") == 0) {
1422*7c478bd9Sstevel@tonic-gate 		rflags = PRELEASE_HANG | PRELEASE_CLEAR;
1423*7c478bd9Sstevel@tonic-gate 		argv++;
1424*7c478bd9Sstevel@tonic-gate 		argc--;
1425*7c478bd9Sstevel@tonic-gate 	}
1426*7c478bd9Sstevel@tonic-gate 
1427*7c478bd9Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) || argc != 0)
1428*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
1429*7c478bd9Sstevel@tonic-gate 
1430*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle == NULL || Pstate(t->t_pshandle) == PS_IDLE) {
1431*7c478bd9Sstevel@tonic-gate 		mdb_warn("debugger is not currently attached to a process "
1432*7c478bd9Sstevel@tonic-gate 		    "or core file\n");
1433*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
1434*7c478bd9Sstevel@tonic-gate 	}
1435*7c478bd9Sstevel@tonic-gate 
1436*7c478bd9Sstevel@tonic-gate 	pt_pre_detach(t, TRUE);
1437*7c478bd9Sstevel@tonic-gate 	pt_release_parents(t);
1438*7c478bd9Sstevel@tonic-gate 	Prelease(t->t_pshandle, rflags);
1439*7c478bd9Sstevel@tonic-gate 	t->t_pshandle = pt->p_idlehandle;
1440*7c478bd9Sstevel@tonic-gate 	(void) mdb_tgt_status(t, &t->t_status);
1441*7c478bd9Sstevel@tonic-gate 	mdb.m_flags &= ~(MDB_FL_VCREATE | MDB_FL_JOBCTL);
1442*7c478bd9Sstevel@tonic-gate 
1443*7c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
1444*7c478bd9Sstevel@tonic-gate }
1445*7c478bd9Sstevel@tonic-gate 
1446*7c478bd9Sstevel@tonic-gate static uintmax_t
1447*7c478bd9Sstevel@tonic-gate reg_disc_get(const mdb_var_t *v)
1448*7c478bd9Sstevel@tonic-gate {
1449*7c478bd9Sstevel@tonic-gate 	mdb_tgt_t *t = MDB_NV_COOKIE(v);
1450*7c478bd9Sstevel@tonic-gate 	mdb_tgt_tid_t tid = PTL_TID(t);
1451*7c478bd9Sstevel@tonic-gate 	mdb_tgt_reg_t r = 0;
1452*7c478bd9Sstevel@tonic-gate 
1453*7c478bd9Sstevel@tonic-gate 	if (tid != (mdb_tgt_tid_t)-1L)
1454*7c478bd9Sstevel@tonic-gate 		(void) mdb_tgt_getareg(t, tid, mdb_nv_get_name(v), &r);
1455*7c478bd9Sstevel@tonic-gate 
1456*7c478bd9Sstevel@tonic-gate 	return (r);
1457*7c478bd9Sstevel@tonic-gate }
1458*7c478bd9Sstevel@tonic-gate 
1459*7c478bd9Sstevel@tonic-gate static void
1460*7c478bd9Sstevel@tonic-gate reg_disc_set(mdb_var_t *v, uintmax_t r)
1461*7c478bd9Sstevel@tonic-gate {
1462*7c478bd9Sstevel@tonic-gate 	mdb_tgt_t *t = MDB_NV_COOKIE(v);
1463*7c478bd9Sstevel@tonic-gate 	mdb_tgt_tid_t tid = PTL_TID(t);
1464*7c478bd9Sstevel@tonic-gate 
1465*7c478bd9Sstevel@tonic-gate 	if (tid != (mdb_tgt_tid_t)-1L && mdb_tgt_putareg(t, tid,
1466*7c478bd9Sstevel@tonic-gate 	    mdb_nv_get_name(v), r) == -1)
1467*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to modify %%%s register", mdb_nv_get_name(v));
1468*7c478bd9Sstevel@tonic-gate }
1469*7c478bd9Sstevel@tonic-gate 
1470*7c478bd9Sstevel@tonic-gate static void
1471*7c478bd9Sstevel@tonic-gate pt_print_reason(const lwpstatus_t *psp)
1472*7c478bd9Sstevel@tonic-gate {
1473*7c478bd9Sstevel@tonic-gate 	char name[SIG2STR_MAX + 4]; /* enough for SIG+name+\0, syscall or flt */
1474*7c478bd9Sstevel@tonic-gate 	const char *desc;
1475*7c478bd9Sstevel@tonic-gate 
1476*7c478bd9Sstevel@tonic-gate 	switch (psp->pr_why) {
1477*7c478bd9Sstevel@tonic-gate 	case PR_REQUESTED:
1478*7c478bd9Sstevel@tonic-gate 		mdb_printf("stopped by debugger");
1479*7c478bd9Sstevel@tonic-gate 		break;
1480*7c478bd9Sstevel@tonic-gate 	case PR_SIGNALLED:
1481*7c478bd9Sstevel@tonic-gate 		mdb_printf("stopped on %s (%s)", proc_signame(psp->pr_what,
1482*7c478bd9Sstevel@tonic-gate 		    name, sizeof (name)), strsignal(psp->pr_what));
1483*7c478bd9Sstevel@tonic-gate 		break;
1484*7c478bd9Sstevel@tonic-gate 	case PR_SYSENTRY:
1485*7c478bd9Sstevel@tonic-gate 		mdb_printf("stopped on entry to %s system call",
1486*7c478bd9Sstevel@tonic-gate 		    proc_sysname(psp->pr_what, name, sizeof (name)));
1487*7c478bd9Sstevel@tonic-gate 		break;
1488*7c478bd9Sstevel@tonic-gate 	case PR_SYSEXIT:
1489*7c478bd9Sstevel@tonic-gate 		mdb_printf("stopped on exit from %s system call",
1490*7c478bd9Sstevel@tonic-gate 		    proc_sysname(psp->pr_what, name, sizeof (name)));
1491*7c478bd9Sstevel@tonic-gate 		break;
1492*7c478bd9Sstevel@tonic-gate 	case PR_JOBCONTROL:
1493*7c478bd9Sstevel@tonic-gate 		mdb_printf("stopped by job control");
1494*7c478bd9Sstevel@tonic-gate 		break;
1495*7c478bd9Sstevel@tonic-gate 	case PR_FAULTED:
1496*7c478bd9Sstevel@tonic-gate 		if (psp->pr_what == FLTBPT) {
1497*7c478bd9Sstevel@tonic-gate 			mdb_printf("stopped on a breakpoint");
1498*7c478bd9Sstevel@tonic-gate 		} else if (psp->pr_what == FLTWATCH) {
1499*7c478bd9Sstevel@tonic-gate 			switch (psp->pr_info.si_code) {
1500*7c478bd9Sstevel@tonic-gate 			case TRAP_RWATCH:
1501*7c478bd9Sstevel@tonic-gate 				desc = "read";
1502*7c478bd9Sstevel@tonic-gate 				break;
1503*7c478bd9Sstevel@tonic-gate 			case TRAP_WWATCH:
1504*7c478bd9Sstevel@tonic-gate 				desc = "write";
1505*7c478bd9Sstevel@tonic-gate 				break;
1506*7c478bd9Sstevel@tonic-gate 			case TRAP_XWATCH:
1507*7c478bd9Sstevel@tonic-gate 				desc = "execute";
1508*7c478bd9Sstevel@tonic-gate 				break;
1509*7c478bd9Sstevel@tonic-gate 			default:
1510*7c478bd9Sstevel@tonic-gate 				desc = "unknown";
1511*7c478bd9Sstevel@tonic-gate 			}
1512*7c478bd9Sstevel@tonic-gate 			mdb_printf("stopped %s a watchpoint (%s access to %p)",
1513*7c478bd9Sstevel@tonic-gate 			    psp->pr_info.si_trapafter ? "after" : "on",
1514*7c478bd9Sstevel@tonic-gate 			    desc, psp->pr_info.si_addr);
1515*7c478bd9Sstevel@tonic-gate 		} else if (psp->pr_what == FLTTRACE) {
1516*7c478bd9Sstevel@tonic-gate 			mdb_printf("stopped after a single-step");
1517*7c478bd9Sstevel@tonic-gate 		} else {
1518*7c478bd9Sstevel@tonic-gate 			mdb_printf("stopped on a %s fault",
1519*7c478bd9Sstevel@tonic-gate 			    proc_fltname(psp->pr_what, name, sizeof (name)));
1520*7c478bd9Sstevel@tonic-gate 		}
1521*7c478bd9Sstevel@tonic-gate 		break;
1522*7c478bd9Sstevel@tonic-gate 	case PR_SUSPENDED:
1523*7c478bd9Sstevel@tonic-gate 	case PR_CHECKPOINT:
1524*7c478bd9Sstevel@tonic-gate 		mdb_printf("suspended by the kernel");
1525*7c478bd9Sstevel@tonic-gate 		break;
1526*7c478bd9Sstevel@tonic-gate 	default:
1527*7c478bd9Sstevel@tonic-gate 		mdb_printf("stopped for unknown reason (%d/%d)",
1528*7c478bd9Sstevel@tonic-gate 		    psp->pr_why, psp->pr_what);
1529*7c478bd9Sstevel@tonic-gate 	}
1530*7c478bd9Sstevel@tonic-gate }
1531*7c478bd9Sstevel@tonic-gate 
1532*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1533*7c478bd9Sstevel@tonic-gate static int
1534*7c478bd9Sstevel@tonic-gate pt_status_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1535*7c478bd9Sstevel@tonic-gate {
1536*7c478bd9Sstevel@tonic-gate 	mdb_tgt_t *t = mdb.m_target;
1537*7c478bd9Sstevel@tonic-gate 	struct ps_prochandle *P = t->t_pshandle;
1538*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
1539*7c478bd9Sstevel@tonic-gate 
1540*7c478bd9Sstevel@tonic-gate 	if (P != NULL) {
1541*7c478bd9Sstevel@tonic-gate 		const psinfo_t *pip = Ppsinfo(P);
1542*7c478bd9Sstevel@tonic-gate 		const pstatus_t *psp = Pstatus(P);
1543*7c478bd9Sstevel@tonic-gate 		int cursig = 0, bits = 0, coredump = 0;
1544*7c478bd9Sstevel@tonic-gate 		int state;
1545*7c478bd9Sstevel@tonic-gate 		GElf_Sym sym;
1546*7c478bd9Sstevel@tonic-gate 		uintptr_t panicstr;
1547*7c478bd9Sstevel@tonic-gate 		char panicbuf[128];
1548*7c478bd9Sstevel@tonic-gate 
1549*7c478bd9Sstevel@tonic-gate 		char execname[MAXPATHLEN], buf[BUFSIZ];
1550*7c478bd9Sstevel@tonic-gate 		char signame[SIG2STR_MAX + 4]; /* enough for SIG+name+\0 */
1551*7c478bd9Sstevel@tonic-gate 
1552*7c478bd9Sstevel@tonic-gate 		mdb_tgt_spec_desc_t desc;
1553*7c478bd9Sstevel@tonic-gate 		mdb_sespec_t *sep;
1554*7c478bd9Sstevel@tonic-gate 
1555*7c478bd9Sstevel@tonic-gate 		struct utsname uts;
1556*7c478bd9Sstevel@tonic-gate 		prcred_t cred;
1557*7c478bd9Sstevel@tonic-gate 		psinfo_t pi;
1558*7c478bd9Sstevel@tonic-gate 
1559*7c478bd9Sstevel@tonic-gate 		(void) strcpy(uts.nodename, "unknown machine");
1560*7c478bd9Sstevel@tonic-gate 		(void) Puname(P, &uts);
1561*7c478bd9Sstevel@tonic-gate 
1562*7c478bd9Sstevel@tonic-gate 		if (pip != NULL) {
1563*7c478bd9Sstevel@tonic-gate 			bcopy(pip, &pi, sizeof (psinfo_t));
1564*7c478bd9Sstevel@tonic-gate 			proc_unctrl_psinfo(&pi);
1565*7c478bd9Sstevel@tonic-gate 		} else
1566*7c478bd9Sstevel@tonic-gate 			bzero(&pi, sizeof (psinfo_t));
1567*7c478bd9Sstevel@tonic-gate 
1568*7c478bd9Sstevel@tonic-gate 		bits = pi.pr_dmodel == PR_MODEL_ILP32 ? 32 : 64;
1569*7c478bd9Sstevel@tonic-gate 
1570*7c478bd9Sstevel@tonic-gate 		state = Pstate(P);
1571*7c478bd9Sstevel@tonic-gate 		if (psp != NULL && state != PS_UNDEAD && state != PS_IDLE)
1572*7c478bd9Sstevel@tonic-gate 			cursig = psp->pr_lwp.pr_cursig;
1573*7c478bd9Sstevel@tonic-gate 
1574*7c478bd9Sstevel@tonic-gate 		if (state == PS_DEAD && pip != NULL) {
1575*7c478bd9Sstevel@tonic-gate 			mdb_printf("debugging core file of %s (%d-bit) "
1576*7c478bd9Sstevel@tonic-gate 			    "from %s\n", pi.pr_fname, bits, uts.nodename);
1577*7c478bd9Sstevel@tonic-gate 
1578*7c478bd9Sstevel@tonic-gate 		} else if (state == PS_DEAD) {
1579*7c478bd9Sstevel@tonic-gate 			mdb_printf("debugging core file\n");
1580*7c478bd9Sstevel@tonic-gate 
1581*7c478bd9Sstevel@tonic-gate 		} else if (state == PS_IDLE) {
1582*7c478bd9Sstevel@tonic-gate 			const GElf_Ehdr *ehp = &pt->p_file->gf_ehdr;
1583*7c478bd9Sstevel@tonic-gate 
1584*7c478bd9Sstevel@tonic-gate 			mdb_printf("debugging %s file (%d-bit)\n",
1585*7c478bd9Sstevel@tonic-gate 			    ehp->e_type == ET_EXEC ? "executable" : "object",
1586*7c478bd9Sstevel@tonic-gate 			    ehp->e_ident[EI_CLASS] == ELFCLASS32 ? 32 : 64);
1587*7c478bd9Sstevel@tonic-gate 
1588*7c478bd9Sstevel@tonic-gate 		} else if (state == PS_UNDEAD && pi.pr_pid == 0) {
1589*7c478bd9Sstevel@tonic-gate 			mdb_printf("debugging defunct process\n");
1590*7c478bd9Sstevel@tonic-gate 
1591*7c478bd9Sstevel@tonic-gate 		} else {
1592*7c478bd9Sstevel@tonic-gate 			mdb_printf("debugging PID %d (%d-bit)\n",
1593*7c478bd9Sstevel@tonic-gate 			    pi.pr_pid, bits);
1594*7c478bd9Sstevel@tonic-gate 		}
1595*7c478bd9Sstevel@tonic-gate 
1596*7c478bd9Sstevel@tonic-gate 		if (Pexecname(P, execname, sizeof (execname)) != NULL)
1597*7c478bd9Sstevel@tonic-gate 			mdb_printf("file: %s\n", execname);
1598*7c478bd9Sstevel@tonic-gate 
1599*7c478bd9Sstevel@tonic-gate 		if (pip != NULL && state == PS_DEAD)
1600*7c478bd9Sstevel@tonic-gate 			mdb_printf("initial argv: %s\n", pi.pr_psargs);
1601*7c478bd9Sstevel@tonic-gate 
1602*7c478bd9Sstevel@tonic-gate 		if (state != PS_UNDEAD && state != PS_IDLE) {
1603*7c478bd9Sstevel@tonic-gate 			mdb_printf("threading model: ");
1604*7c478bd9Sstevel@tonic-gate 			if (pt->p_ptl_ops == &proc_lwp_ops)
1605*7c478bd9Sstevel@tonic-gate 				mdb_printf("raw lwps\n");
1606*7c478bd9Sstevel@tonic-gate 			else
1607*7c478bd9Sstevel@tonic-gate 				mdb_printf("native threads\n");
1608*7c478bd9Sstevel@tonic-gate 		}
1609*7c478bd9Sstevel@tonic-gate 
1610*7c478bd9Sstevel@tonic-gate 		mdb_printf("status: ");
1611*7c478bd9Sstevel@tonic-gate 		switch (state) {
1612*7c478bd9Sstevel@tonic-gate 		case PS_RUN:
1613*7c478bd9Sstevel@tonic-gate 			ASSERT(!(psp->pr_flags & PR_STOPPED));
1614*7c478bd9Sstevel@tonic-gate 			mdb_printf("process is running");
1615*7c478bd9Sstevel@tonic-gate 			if (psp->pr_flags & PR_DSTOP)
1616*7c478bd9Sstevel@tonic-gate 				mdb_printf(", debugger stop directive pending");
1617*7c478bd9Sstevel@tonic-gate 			mdb_printf("\n");
1618*7c478bd9Sstevel@tonic-gate 			break;
1619*7c478bd9Sstevel@tonic-gate 
1620*7c478bd9Sstevel@tonic-gate 		case PS_STOP:
1621*7c478bd9Sstevel@tonic-gate 			ASSERT(psp->pr_flags & PR_STOPPED);
1622*7c478bd9Sstevel@tonic-gate 			pt_print_reason(&psp->pr_lwp);
1623*7c478bd9Sstevel@tonic-gate 
1624*7c478bd9Sstevel@tonic-gate 			if (psp->pr_flags & PR_DSTOP)
1625*7c478bd9Sstevel@tonic-gate 				mdb_printf(", debugger stop directive pending");
1626*7c478bd9Sstevel@tonic-gate 			if (psp->pr_flags & PR_ASLEEP)
1627*7c478bd9Sstevel@tonic-gate 				mdb_printf(", sleeping in %s system call",
1628*7c478bd9Sstevel@tonic-gate 				    proc_sysname(psp->pr_lwp.pr_syscall,
1629*7c478bd9Sstevel@tonic-gate 				    signame, sizeof (signame)));
1630*7c478bd9Sstevel@tonic-gate 
1631*7c478bd9Sstevel@tonic-gate 			mdb_printf("\n");
1632*7c478bd9Sstevel@tonic-gate 
1633*7c478bd9Sstevel@tonic-gate 			for (sep = t->t_matched; sep != T_SE_END;
1634*7c478bd9Sstevel@tonic-gate 			    sep = sep->se_matched) {
1635*7c478bd9Sstevel@tonic-gate 				mdb_printf("event: %s\n", sep->se_ops->se_info(
1636*7c478bd9Sstevel@tonic-gate 				    t, sep, mdb_list_next(&sep->se_velist),
1637*7c478bd9Sstevel@tonic-gate 				    &desc, buf, sizeof (buf)));
1638*7c478bd9Sstevel@tonic-gate 			}
1639*7c478bd9Sstevel@tonic-gate 			break;
1640*7c478bd9Sstevel@tonic-gate 
1641*7c478bd9Sstevel@tonic-gate 		case PS_LOST:
1642*7c478bd9Sstevel@tonic-gate 			mdb_printf("debugger lost control of process\n");
1643*7c478bd9Sstevel@tonic-gate 			break;
1644*7c478bd9Sstevel@tonic-gate 
1645*7c478bd9Sstevel@tonic-gate 		case PS_UNDEAD:
1646*7c478bd9Sstevel@tonic-gate 			coredump = WIFSIGNALED(pi.pr_wstat) &&
1647*7c478bd9Sstevel@tonic-gate 			    WCOREDUMP(pi.pr_wstat);
1648*7c478bd9Sstevel@tonic-gate 			/*FALLTHRU*/
1649*7c478bd9Sstevel@tonic-gate 
1650*7c478bd9Sstevel@tonic-gate 		case PS_DEAD:
1651*7c478bd9Sstevel@tonic-gate 			if (cursig == 0 && WIFSIGNALED(pi.pr_wstat))
1652*7c478bd9Sstevel@tonic-gate 				cursig = WTERMSIG(pi.pr_wstat);
1653*7c478bd9Sstevel@tonic-gate 			/*
1654*7c478bd9Sstevel@tonic-gate 			 * We can only use pr_wstat == 0 as a test for gcore if
1655*7c478bd9Sstevel@tonic-gate 			 * an NT_PRCRED note is present; these features were
1656*7c478bd9Sstevel@tonic-gate 			 * added at the same time in Solaris 8.
1657*7c478bd9Sstevel@tonic-gate 			 */
1658*7c478bd9Sstevel@tonic-gate 			if (pi.pr_wstat == 0 && Pstate(P) == PS_DEAD &&
1659*7c478bd9Sstevel@tonic-gate 			    Pcred(P, &cred, 1) == 0) {
1660*7c478bd9Sstevel@tonic-gate 				mdb_printf("process core file generated "
1661*7c478bd9Sstevel@tonic-gate 				    "with gcore(1)\n");
1662*7c478bd9Sstevel@tonic-gate 			} else if (cursig != 0) {
1663*7c478bd9Sstevel@tonic-gate 				mdb_printf("process terminated by %s (%s)",
1664*7c478bd9Sstevel@tonic-gate 				    proc_signame(cursig, signame,
1665*7c478bd9Sstevel@tonic-gate 				    sizeof (signame)), strsignal(cursig));
1666*7c478bd9Sstevel@tonic-gate 				if (coredump)
1667*7c478bd9Sstevel@tonic-gate 					mdb_printf(" - core file dumped");
1668*7c478bd9Sstevel@tonic-gate 				mdb_printf("\n");
1669*7c478bd9Sstevel@tonic-gate 			} else {
1670*7c478bd9Sstevel@tonic-gate 				mdb_printf("process terminated with exit "
1671*7c478bd9Sstevel@tonic-gate 				    "status %d\n", WEXITSTATUS(pi.pr_wstat));
1672*7c478bd9Sstevel@tonic-gate 			}
1673*7c478bd9Sstevel@tonic-gate 
1674*7c478bd9Sstevel@tonic-gate 			if (Plookup_by_name(t->t_pshandle, "libc.so",
1675*7c478bd9Sstevel@tonic-gate 			    "panicstr", &sym) == 0 &&
1676*7c478bd9Sstevel@tonic-gate 			    Pread(t->t_pshandle, &panicstr, sizeof (panicstr),
1677*7c478bd9Sstevel@tonic-gate 			    sym.st_value) == sizeof (panicstr) &&
1678*7c478bd9Sstevel@tonic-gate 			    Pread_string(t->t_pshandle, panicbuf,
1679*7c478bd9Sstevel@tonic-gate 			    sizeof (panicbuf), panicstr) > 0) {
1680*7c478bd9Sstevel@tonic-gate 				mdb_printf("panic message: %s",
1681*7c478bd9Sstevel@tonic-gate 				    panicbuf);
1682*7c478bd9Sstevel@tonic-gate 			}
1683*7c478bd9Sstevel@tonic-gate 
1684*7c478bd9Sstevel@tonic-gate 
1685*7c478bd9Sstevel@tonic-gate 			break;
1686*7c478bd9Sstevel@tonic-gate 
1687*7c478bd9Sstevel@tonic-gate 		case PS_IDLE:
1688*7c478bd9Sstevel@tonic-gate 			mdb_printf("idle\n");
1689*7c478bd9Sstevel@tonic-gate 			break;
1690*7c478bd9Sstevel@tonic-gate 
1691*7c478bd9Sstevel@tonic-gate 		default:
1692*7c478bd9Sstevel@tonic-gate 			mdb_printf("unknown libproc Pstate: %d\n", Pstate(P));
1693*7c478bd9Sstevel@tonic-gate 		}
1694*7c478bd9Sstevel@tonic-gate 
1695*7c478bd9Sstevel@tonic-gate 	} else if (pt->p_file != NULL) {
1696*7c478bd9Sstevel@tonic-gate 		const GElf_Ehdr *ehp = &pt->p_file->gf_ehdr;
1697*7c478bd9Sstevel@tonic-gate 
1698*7c478bd9Sstevel@tonic-gate 		mdb_printf("debugging %s file (%d-bit)\n",
1699*7c478bd9Sstevel@tonic-gate 		    ehp->e_type == ET_EXEC ? "executable" : "object",
1700*7c478bd9Sstevel@tonic-gate 		    ehp->e_ident[EI_CLASS] == ELFCLASS32 ? 32 : 64);
1701*7c478bd9Sstevel@tonic-gate 		mdb_printf("executable file: %s\n", IOP_NAME(pt->p_fio));
1702*7c478bd9Sstevel@tonic-gate 		mdb_printf("status: idle\n");
1703*7c478bd9Sstevel@tonic-gate 	}
1704*7c478bd9Sstevel@tonic-gate 
1705*7c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
1706*7c478bd9Sstevel@tonic-gate }
1707*7c478bd9Sstevel@tonic-gate 
1708*7c478bd9Sstevel@tonic-gate static int
1709*7c478bd9Sstevel@tonic-gate pt_tls(uintptr_t tid, uint_t flags, int argc, const mdb_arg_t *argv)
1710*7c478bd9Sstevel@tonic-gate {
1711*7c478bd9Sstevel@tonic-gate 	const char *name;
1712*7c478bd9Sstevel@tonic-gate 	const char *object;
1713*7c478bd9Sstevel@tonic-gate 	GElf_Sym sym;
1714*7c478bd9Sstevel@tonic-gate 	mdb_syminfo_t si;
1715*7c478bd9Sstevel@tonic-gate 	mdb_tgt_t *t = mdb.m_target;
1716*7c478bd9Sstevel@tonic-gate 
1717*7c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC) || argc > 1)
1718*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
1719*7c478bd9Sstevel@tonic-gate 
1720*7c478bd9Sstevel@tonic-gate 	if (argc == 0) {
1721*7c478bd9Sstevel@tonic-gate 		psaddr_t b;
1722*7c478bd9Sstevel@tonic-gate 
1723*7c478bd9Sstevel@tonic-gate 		if (tlsbase(t, tid, PR_LMID_EVERY, MDB_TGT_OBJ_EXEC, &b) != 0) {
1724*7c478bd9Sstevel@tonic-gate 			mdb_warn("failed to lookup tlsbase for %r", tid);
1725*7c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
1726*7c478bd9Sstevel@tonic-gate 		}
1727*7c478bd9Sstevel@tonic-gate 
1728*7c478bd9Sstevel@tonic-gate 		mdb_printf("%lr\n", b);
1729*7c478bd9Sstevel@tonic-gate 		mdb_set_dot(b);
1730*7c478bd9Sstevel@tonic-gate 
1731*7c478bd9Sstevel@tonic-gate 		return (DCMD_OK);
1732*7c478bd9Sstevel@tonic-gate 	}
1733*7c478bd9Sstevel@tonic-gate 
1734*7c478bd9Sstevel@tonic-gate 	name = argv[0].a_un.a_str;
1735*7c478bd9Sstevel@tonic-gate 	object = MDB_TGT_OBJ_EVERY;
1736*7c478bd9Sstevel@tonic-gate 
1737*7c478bd9Sstevel@tonic-gate 	if (pt_lookup_by_name_thr(t, object, name, &sym, &si, tid) != 0) {
1738*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to lookup %s", name);
1739*7c478bd9Sstevel@tonic-gate 		return (DCMD_ABORT); /* avoid repeated failure */
1740*7c478bd9Sstevel@tonic-gate 	}
1741*7c478bd9Sstevel@tonic-gate 
1742*7c478bd9Sstevel@tonic-gate 	if (GELF_ST_TYPE(sym.st_info) != STT_TLS && DCMD_HDRSPEC(flags))
1743*7c478bd9Sstevel@tonic-gate 		mdb_warn("%s does not refer to thread local storage\n", name);
1744*7c478bd9Sstevel@tonic-gate 
1745*7c478bd9Sstevel@tonic-gate 	mdb_printf("%llr\n", sym.st_value);
1746*7c478bd9Sstevel@tonic-gate 	mdb_set_dot(sym.st_value);
1747*7c478bd9Sstevel@tonic-gate 
1748*7c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
1749*7c478bd9Sstevel@tonic-gate }
1750*7c478bd9Sstevel@tonic-gate 
1751*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1752*7c478bd9Sstevel@tonic-gate static int
1753*7c478bd9Sstevel@tonic-gate pt_tmodel(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1754*7c478bd9Sstevel@tonic-gate {
1755*7c478bd9Sstevel@tonic-gate 	mdb_tgt_t *t = mdb.m_target;
1756*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
1757*7c478bd9Sstevel@tonic-gate 	const pt_ptl_ops_t *ptl_ops;
1758*7c478bd9Sstevel@tonic-gate 
1759*7c478bd9Sstevel@tonic-gate 	if (argc != 1 || argv->a_type != MDB_TYPE_STRING)
1760*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
1761*7c478bd9Sstevel@tonic-gate 
1762*7c478bd9Sstevel@tonic-gate 	if (strcmp(argv->a_un.a_str, "thread") == 0)
1763*7c478bd9Sstevel@tonic-gate 		ptl_ops = &proc_tdb_ops;
1764*7c478bd9Sstevel@tonic-gate 	else if (strcmp(argv->a_un.a_str, "lwp") == 0)
1765*7c478bd9Sstevel@tonic-gate 		ptl_ops = &proc_lwp_ops;
1766*7c478bd9Sstevel@tonic-gate 	else
1767*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
1768*7c478bd9Sstevel@tonic-gate 
1769*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle != NULL && pt->p_ptl_ops != ptl_ops) {
1770*7c478bd9Sstevel@tonic-gate 		PTL_DTOR(t);
1771*7c478bd9Sstevel@tonic-gate 		pt->p_tdb_ops = NULL;
1772*7c478bd9Sstevel@tonic-gate 		pt->p_ptl_ops = &proc_lwp_ops;
1773*7c478bd9Sstevel@tonic-gate 		pt->p_ptl_hdl = NULL;
1774*7c478bd9Sstevel@tonic-gate 
1775*7c478bd9Sstevel@tonic-gate 		if (ptl_ops == &proc_tdb_ops) {
1776*7c478bd9Sstevel@tonic-gate 			(void) Pobject_iter(t->t_pshandle, (proc_map_f *)
1777*7c478bd9Sstevel@tonic-gate 			    thr_check, t);
1778*7c478bd9Sstevel@tonic-gate 		}
1779*7c478bd9Sstevel@tonic-gate 	}
1780*7c478bd9Sstevel@tonic-gate 
1781*7c478bd9Sstevel@tonic-gate 	(void) mdb_tgt_status(t, &t->t_status);
1782*7c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
1783*7c478bd9Sstevel@tonic-gate }
1784*7c478bd9Sstevel@tonic-gate 
1785*7c478bd9Sstevel@tonic-gate static const char *
1786*7c478bd9Sstevel@tonic-gate env_match(const char *cmp, const char *nameval)
1787*7c478bd9Sstevel@tonic-gate {
1788*7c478bd9Sstevel@tonic-gate 	const char *loc;
1789*7c478bd9Sstevel@tonic-gate 	size_t cmplen = strlen(cmp);
1790*7c478bd9Sstevel@tonic-gate 
1791*7c478bd9Sstevel@tonic-gate 	loc = strchr(nameval, '=');
1792*7c478bd9Sstevel@tonic-gate 	if (loc != NULL && (loc - nameval) == cmplen &&
1793*7c478bd9Sstevel@tonic-gate 	    strncmp(nameval, cmp, cmplen) == 0) {
1794*7c478bd9Sstevel@tonic-gate 		return (loc + 1);
1795*7c478bd9Sstevel@tonic-gate 	}
1796*7c478bd9Sstevel@tonic-gate 
1797*7c478bd9Sstevel@tonic-gate 	return (NULL);
1798*7c478bd9Sstevel@tonic-gate }
1799*7c478bd9Sstevel@tonic-gate 
1800*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1801*7c478bd9Sstevel@tonic-gate static int
1802*7c478bd9Sstevel@tonic-gate print_env(void *data, struct ps_prochandle *P, uintptr_t addr,
1803*7c478bd9Sstevel@tonic-gate     const char *nameval)
1804*7c478bd9Sstevel@tonic-gate {
1805*7c478bd9Sstevel@tonic-gate 	const char *value;
1806*7c478bd9Sstevel@tonic-gate 
1807*7c478bd9Sstevel@tonic-gate 	if (nameval == NULL) {
1808*7c478bd9Sstevel@tonic-gate 		mdb_printf("<0x%p>\n", addr);
1809*7c478bd9Sstevel@tonic-gate 	} else {
1810*7c478bd9Sstevel@tonic-gate 		if (data == NULL)
1811*7c478bd9Sstevel@tonic-gate 			mdb_printf("%s\n", nameval);
1812*7c478bd9Sstevel@tonic-gate 		else if ((value = env_match(data, nameval)) != NULL)
1813*7c478bd9Sstevel@tonic-gate 			mdb_printf("%s\n", value);
1814*7c478bd9Sstevel@tonic-gate 	}
1815*7c478bd9Sstevel@tonic-gate 
1816*7c478bd9Sstevel@tonic-gate 	return (0);
1817*7c478bd9Sstevel@tonic-gate }
1818*7c478bd9Sstevel@tonic-gate 
1819*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1820*7c478bd9Sstevel@tonic-gate static int
1821*7c478bd9Sstevel@tonic-gate pt_getenv(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1822*7c478bd9Sstevel@tonic-gate {
1823*7c478bd9Sstevel@tonic-gate 	mdb_tgt_t *t = mdb.m_target;
1824*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
1825*7c478bd9Sstevel@tonic-gate 	int i;
1826*7c478bd9Sstevel@tonic-gate 	uint_t opt_t = 0;
1827*7c478bd9Sstevel@tonic-gate 	mdb_var_t *v;
1828*7c478bd9Sstevel@tonic-gate 
1829*7c478bd9Sstevel@tonic-gate 	i = mdb_getopts(argc, argv,
1830*7c478bd9Sstevel@tonic-gate 	    't', MDB_OPT_SETBITS, TRUE, &opt_t, NULL);
1831*7c478bd9Sstevel@tonic-gate 
1832*7c478bd9Sstevel@tonic-gate 	argc -= i;
1833*7c478bd9Sstevel@tonic-gate 	argv += i;
1834*7c478bd9Sstevel@tonic-gate 
1835*7c478bd9Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) || argc > 1)
1836*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
1837*7c478bd9Sstevel@tonic-gate 
1838*7c478bd9Sstevel@tonic-gate 	if (argc == 1 && argv->a_type != MDB_TYPE_STRING)
1839*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
1840*7c478bd9Sstevel@tonic-gate 
1841*7c478bd9Sstevel@tonic-gate 	if (opt_t && (Pstate(t->t_pshandle) == PS_IDLE ||
1842*7c478bd9Sstevel@tonic-gate 	    Pstate(t->t_pshandle) == PS_UNDEAD)) {
1843*7c478bd9Sstevel@tonic-gate 		mdb_warn("-t option requires target to be running\n");
1844*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
1845*7c478bd9Sstevel@tonic-gate 	}
1846*7c478bd9Sstevel@tonic-gate 
1847*7c478bd9Sstevel@tonic-gate 	if (opt_t != 0) {
1848*7c478bd9Sstevel@tonic-gate 		if (Penv_iter(t->t_pshandle, print_env,
1849*7c478bd9Sstevel@tonic-gate 		    argc == 0 ? NULL : (void *)argv->a_un.a_str) != 0)
1850*7c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
1851*7c478bd9Sstevel@tonic-gate 	} else if (argc == 1) {
1852*7c478bd9Sstevel@tonic-gate 		if ((v = mdb_nv_lookup(&pt->p_env, argv->a_un.a_str)) == NULL)
1853*7c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
1854*7c478bd9Sstevel@tonic-gate 
1855*7c478bd9Sstevel@tonic-gate 		ASSERT(strchr(mdb_nv_get_cookie(v), '=') != NULL);
1856*7c478bd9Sstevel@tonic-gate 		mdb_printf("%s\n", strchr(mdb_nv_get_cookie(v), '=') + 1);
1857*7c478bd9Sstevel@tonic-gate 	} else {
1858*7c478bd9Sstevel@tonic-gate 
1859*7c478bd9Sstevel@tonic-gate 		mdb_nv_rewind(&pt->p_env);
1860*7c478bd9Sstevel@tonic-gate 		while ((v = mdb_nv_advance(&pt->p_env)) != NULL)
1861*7c478bd9Sstevel@tonic-gate 			mdb_printf("%s\n", mdb_nv_get_cookie(v));
1862*7c478bd9Sstevel@tonic-gate 	}
1863*7c478bd9Sstevel@tonic-gate 
1864*7c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
1865*7c478bd9Sstevel@tonic-gate }
1866*7c478bd9Sstevel@tonic-gate 
1867*7c478bd9Sstevel@tonic-gate /*
1868*7c478bd9Sstevel@tonic-gate  * Function to set a variable in the internal environment, which is used when
1869*7c478bd9Sstevel@tonic-gate  * creating new processes.  Note that it is possible that 'nameval' can refer to
1870*7c478bd9Sstevel@tonic-gate  * read-only memory, if mdb calls putenv() on an existing value before calling
1871*7c478bd9Sstevel@tonic-gate  * this function.  While we should avoid this situation, this function is
1872*7c478bd9Sstevel@tonic-gate  * designed to be robust in the face of such changes.
1873*7c478bd9Sstevel@tonic-gate  */
1874*7c478bd9Sstevel@tonic-gate static void
1875*7c478bd9Sstevel@tonic-gate pt_env_set(pt_data_t *pt, const char *nameval)
1876*7c478bd9Sstevel@tonic-gate {
1877*7c478bd9Sstevel@tonic-gate 	mdb_var_t *v;
1878*7c478bd9Sstevel@tonic-gate 	char *equals, *val;
1879*7c478bd9Sstevel@tonic-gate 	const char *name;
1880*7c478bd9Sstevel@tonic-gate 	size_t len;
1881*7c478bd9Sstevel@tonic-gate 
1882*7c478bd9Sstevel@tonic-gate 	if ((equals = strchr(nameval, '=')) != NULL) {
1883*7c478bd9Sstevel@tonic-gate 		val = strdup(nameval);
1884*7c478bd9Sstevel@tonic-gate 		equals = val + (equals - nameval);
1885*7c478bd9Sstevel@tonic-gate 	} else {
1886*7c478bd9Sstevel@tonic-gate 		/*
1887*7c478bd9Sstevel@tonic-gate 		 * nameval doesn't contain an equals character.  Convert this to
1888*7c478bd9Sstevel@tonic-gate 		 * be 'nameval='.
1889*7c478bd9Sstevel@tonic-gate 		 */
1890*7c478bd9Sstevel@tonic-gate 		len = strlen(nameval);
1891*7c478bd9Sstevel@tonic-gate 		val = mdb_alloc(len + 2, UM_SLEEP);
1892*7c478bd9Sstevel@tonic-gate 		(void) mdb_snprintf(val, len + 2, "%s=", nameval);
1893*7c478bd9Sstevel@tonic-gate 		equals = val + len;
1894*7c478bd9Sstevel@tonic-gate 	}
1895*7c478bd9Sstevel@tonic-gate 
1896*7c478bd9Sstevel@tonic-gate 	/* temporary truncate the string for lookup/insert */
1897*7c478bd9Sstevel@tonic-gate 	*equals = '\0';
1898*7c478bd9Sstevel@tonic-gate 	v = mdb_nv_lookup(&pt->p_env, val);
1899*7c478bd9Sstevel@tonic-gate 
1900*7c478bd9Sstevel@tonic-gate 	if (v != NULL) {
1901*7c478bd9Sstevel@tonic-gate 		char *old = mdb_nv_get_cookie(v);
1902*7c478bd9Sstevel@tonic-gate 		mdb_free(old, strlen(old) + 1);
1903*7c478bd9Sstevel@tonic-gate 		name = mdb_nv_get_name(v);
1904*7c478bd9Sstevel@tonic-gate 	} else {
1905*7c478bd9Sstevel@tonic-gate 		/*
1906*7c478bd9Sstevel@tonic-gate 		 * The environment is created using MDB_NV_EXTNAME, so we must
1907*7c478bd9Sstevel@tonic-gate 		 * provide external storage for the variable names.
1908*7c478bd9Sstevel@tonic-gate 		 */
1909*7c478bd9Sstevel@tonic-gate 		name = strdup(val);
1910*7c478bd9Sstevel@tonic-gate 	}
1911*7c478bd9Sstevel@tonic-gate 
1912*7c478bd9Sstevel@tonic-gate 	*equals = '=';
1913*7c478bd9Sstevel@tonic-gate 
1914*7c478bd9Sstevel@tonic-gate 	(void) mdb_nv_insert(&pt->p_env, name, NULL, (uintptr_t)val,
1915*7c478bd9Sstevel@tonic-gate 	    MDB_NV_EXTNAME);
1916*7c478bd9Sstevel@tonic-gate 
1917*7c478bd9Sstevel@tonic-gate 	if (equals)
1918*7c478bd9Sstevel@tonic-gate 		*equals = '=';
1919*7c478bd9Sstevel@tonic-gate }
1920*7c478bd9Sstevel@tonic-gate 
1921*7c478bd9Sstevel@tonic-gate /*
1922*7c478bd9Sstevel@tonic-gate  * Clears the internal environment.
1923*7c478bd9Sstevel@tonic-gate  */
1924*7c478bd9Sstevel@tonic-gate static void
1925*7c478bd9Sstevel@tonic-gate pt_env_clear(pt_data_t *pt)
1926*7c478bd9Sstevel@tonic-gate {
1927*7c478bd9Sstevel@tonic-gate 	mdb_var_t *v;
1928*7c478bd9Sstevel@tonic-gate 	char *val, *name;
1929*7c478bd9Sstevel@tonic-gate 
1930*7c478bd9Sstevel@tonic-gate 	mdb_nv_rewind(&pt->p_env);
1931*7c478bd9Sstevel@tonic-gate 	while ((v = mdb_nv_advance(&pt->p_env)) != NULL) {
1932*7c478bd9Sstevel@tonic-gate 
1933*7c478bd9Sstevel@tonic-gate 		name = (char *)mdb_nv_get_name(v);
1934*7c478bd9Sstevel@tonic-gate 		val = mdb_nv_get_cookie(v);
1935*7c478bd9Sstevel@tonic-gate 
1936*7c478bd9Sstevel@tonic-gate 		mdb_nv_remove(&pt->p_env, v);
1937*7c478bd9Sstevel@tonic-gate 
1938*7c478bd9Sstevel@tonic-gate 		mdb_free(name, strlen(name) + 1);
1939*7c478bd9Sstevel@tonic-gate 		mdb_free(val, strlen(val) + 1);
1940*7c478bd9Sstevel@tonic-gate 	}
1941*7c478bd9Sstevel@tonic-gate }
1942*7c478bd9Sstevel@tonic-gate 
1943*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1944*7c478bd9Sstevel@tonic-gate static int
1945*7c478bd9Sstevel@tonic-gate pt_setenv(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1946*7c478bd9Sstevel@tonic-gate {
1947*7c478bd9Sstevel@tonic-gate 	mdb_tgt_t *t = mdb.m_target;
1948*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
1949*7c478bd9Sstevel@tonic-gate 	char *nameval;
1950*7c478bd9Sstevel@tonic-gate 	size_t len;
1951*7c478bd9Sstevel@tonic-gate 	int alloc;
1952*7c478bd9Sstevel@tonic-gate 
1953*7c478bd9Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) || argc == 0 || argc > 2)
1954*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
1955*7c478bd9Sstevel@tonic-gate 
1956*7c478bd9Sstevel@tonic-gate 	if ((argc > 0 && argv[0].a_type != MDB_TYPE_STRING) ||
1957*7c478bd9Sstevel@tonic-gate 	    (argc > 1 && argv[1].a_type != MDB_TYPE_STRING))
1958*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
1959*7c478bd9Sstevel@tonic-gate 
1960*7c478bd9Sstevel@tonic-gate 	/*
1961*7c478bd9Sstevel@tonic-gate 	 * If the process is in some sort of running state, warn the user that
1962*7c478bd9Sstevel@tonic-gate 	 * changes won't immediately take effect.
1963*7c478bd9Sstevel@tonic-gate 	 */
1964*7c478bd9Sstevel@tonic-gate 	if (Pstate(t->t_pshandle) == PS_RUN ||
1965*7c478bd9Sstevel@tonic-gate 	    Pstate(t->t_pshandle) == PS_STOP) {
1966*7c478bd9Sstevel@tonic-gate 		mdb_warn("warning: changes will not take effect until process"
1967*7c478bd9Sstevel@tonic-gate 		    " is restarted\n");
1968*7c478bd9Sstevel@tonic-gate 	}
1969*7c478bd9Sstevel@tonic-gate 
1970*7c478bd9Sstevel@tonic-gate 	/*
1971*7c478bd9Sstevel@tonic-gate 	 * We allow two forms of operation.  The first is the usual "name=value"
1972*7c478bd9Sstevel@tonic-gate 	 * parameter.  We also allow the user to specify two arguments, where
1973*7c478bd9Sstevel@tonic-gate 	 * the first is the name of the variable, and the second is the value.
1974*7c478bd9Sstevel@tonic-gate 	 */
1975*7c478bd9Sstevel@tonic-gate 	alloc = 0;
1976*7c478bd9Sstevel@tonic-gate 	if (argc == 1) {
1977*7c478bd9Sstevel@tonic-gate 		nameval = (char *)argv->a_un.a_str;
1978*7c478bd9Sstevel@tonic-gate 	} else {
1979*7c478bd9Sstevel@tonic-gate 		len = strlen(argv[0].a_un.a_str) +
1980*7c478bd9Sstevel@tonic-gate 		    strlen(argv[1].a_un.a_str) + 2;
1981*7c478bd9Sstevel@tonic-gate 		nameval = mdb_alloc(len, UM_SLEEP);
1982*7c478bd9Sstevel@tonic-gate 		(void) mdb_snprintf(nameval, len, "%s=%s", argv[0].a_un.a_str,
1983*7c478bd9Sstevel@tonic-gate 		    argv[1].a_un.a_str);
1984*7c478bd9Sstevel@tonic-gate 		alloc = 1;
1985*7c478bd9Sstevel@tonic-gate 	}
1986*7c478bd9Sstevel@tonic-gate 
1987*7c478bd9Sstevel@tonic-gate 	pt_env_set(pt, nameval);
1988*7c478bd9Sstevel@tonic-gate 
1989*7c478bd9Sstevel@tonic-gate 	if (alloc)
1990*7c478bd9Sstevel@tonic-gate 		mdb_free(nameval, strlen(nameval) + 1);
1991*7c478bd9Sstevel@tonic-gate 
1992*7c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
1993*7c478bd9Sstevel@tonic-gate }
1994*7c478bd9Sstevel@tonic-gate 
1995*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1996*7c478bd9Sstevel@tonic-gate static int
1997*7c478bd9Sstevel@tonic-gate pt_unsetenv(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1998*7c478bd9Sstevel@tonic-gate {
1999*7c478bd9Sstevel@tonic-gate 	mdb_tgt_t *t = mdb.m_target;
2000*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
2001*7c478bd9Sstevel@tonic-gate 	mdb_var_t *v;
2002*7c478bd9Sstevel@tonic-gate 	char *value, *name;
2003*7c478bd9Sstevel@tonic-gate 
2004*7c478bd9Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) || argc > 1)
2005*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
2006*7c478bd9Sstevel@tonic-gate 
2007*7c478bd9Sstevel@tonic-gate 	if (argc == 1 && argv->a_type != MDB_TYPE_STRING)
2008*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
2009*7c478bd9Sstevel@tonic-gate 
2010*7c478bd9Sstevel@tonic-gate 	/*
2011*7c478bd9Sstevel@tonic-gate 	 * If the process is in some sort of running state, warn the user that
2012*7c478bd9Sstevel@tonic-gate 	 * changes won't immediately take effect.
2013*7c478bd9Sstevel@tonic-gate 	 */
2014*7c478bd9Sstevel@tonic-gate 	if (Pstate(t->t_pshandle) == PS_RUN ||
2015*7c478bd9Sstevel@tonic-gate 	    Pstate(t->t_pshandle) == PS_STOP) {
2016*7c478bd9Sstevel@tonic-gate 		mdb_warn("warning: changes will not take effect until process"
2017*7c478bd9Sstevel@tonic-gate 		    " is restarted\n");
2018*7c478bd9Sstevel@tonic-gate 	}
2019*7c478bd9Sstevel@tonic-gate 
2020*7c478bd9Sstevel@tonic-gate 	if (argc == 0) {
2021*7c478bd9Sstevel@tonic-gate 		pt_env_clear(pt);
2022*7c478bd9Sstevel@tonic-gate 	} else {
2023*7c478bd9Sstevel@tonic-gate 		if ((v = mdb_nv_lookup(&pt->p_env, argv->a_un.a_str)) != NULL) {
2024*7c478bd9Sstevel@tonic-gate 			name = (char *)mdb_nv_get_name(v);
2025*7c478bd9Sstevel@tonic-gate 			value = mdb_nv_get_cookie(v);
2026*7c478bd9Sstevel@tonic-gate 
2027*7c478bd9Sstevel@tonic-gate 			mdb_nv_remove(&pt->p_env, v);
2028*7c478bd9Sstevel@tonic-gate 
2029*7c478bd9Sstevel@tonic-gate 			mdb_free(name, strlen(name) + 1);
2030*7c478bd9Sstevel@tonic-gate 			mdb_free(value, strlen(value) + 1);
2031*7c478bd9Sstevel@tonic-gate 		}
2032*7c478bd9Sstevel@tonic-gate 	}
2033*7c478bd9Sstevel@tonic-gate 
2034*7c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
2035*7c478bd9Sstevel@tonic-gate }
2036*7c478bd9Sstevel@tonic-gate 
2037*7c478bd9Sstevel@tonic-gate static const mdb_dcmd_t pt_dcmds[] = {
2038*7c478bd9Sstevel@tonic-gate 	{ "$c", "?[cnt]", "print stack backtrace", pt_stack },
2039*7c478bd9Sstevel@tonic-gate 	{ "$C", "?[cnt]", "print stack backtrace", pt_stackv },
2040*7c478bd9Sstevel@tonic-gate 	{ "$i", NULL, "print signals that are ignored", pt_ignored },
2041*7c478bd9Sstevel@tonic-gate 	{ "$l", NULL, "print the representative thread's lwp id", pt_lwpid },
2042*7c478bd9Sstevel@tonic-gate 	{ "$L", NULL, "print list of the active lwp ids", pt_lwpids },
2043*7c478bd9Sstevel@tonic-gate 	{ "$r", "?", "print general-purpose registers", pt_regs },
2044*7c478bd9Sstevel@tonic-gate 	{ "$x", "?", "print floating point registers", pt_fpregs },
2045*7c478bd9Sstevel@tonic-gate 	{ "$X", "?", "print floating point registers", pt_fpregs },
2046*7c478bd9Sstevel@tonic-gate 	{ "$y", "?", "print floating point registers", pt_fpregs },
2047*7c478bd9Sstevel@tonic-gate 	{ "$Y", "?", "print floating point registers", pt_fpregs },
2048*7c478bd9Sstevel@tonic-gate 	{ "$?", "?", "print status and registers", pt_regstatus },
2049*7c478bd9Sstevel@tonic-gate 	{ ":A", "?[core|pid]", "attach to process or core file", pt_attach },
2050*7c478bd9Sstevel@tonic-gate 	{ ":i", ":", "ignore signal (delete all matching events)", pt_ignore },
2051*7c478bd9Sstevel@tonic-gate 	{ ":k", NULL, "forcibly kill and release target", pt_kill },
2052*7c478bd9Sstevel@tonic-gate 	{ ":R", "[-a]", "release the previously attached process", pt_detach },
2053*7c478bd9Sstevel@tonic-gate 	{ "attach", "?[core|pid]",
2054*7c478bd9Sstevel@tonic-gate 	    "attach to process or core file", pt_attach },
2055*7c478bd9Sstevel@tonic-gate 	{ "findstack", ":[-v]", "find user thread stack", pt_findstack },
2056*7c478bd9Sstevel@tonic-gate 	{ "gcore", "[-o prefix] [-c content]",
2057*7c478bd9Sstevel@tonic-gate 	    "produce a core file for the attached process", pt_gcore },
2058*7c478bd9Sstevel@tonic-gate 	{ "getenv", "[-t] [name]", "display an environment variable",
2059*7c478bd9Sstevel@tonic-gate 		pt_getenv, NULL },
2060*7c478bd9Sstevel@tonic-gate 	{ "kill", NULL, "forcibly kill and release target", pt_kill },
2061*7c478bd9Sstevel@tonic-gate 	{ "release", "[-a]",
2062*7c478bd9Sstevel@tonic-gate 	    "release the previously attached process", pt_detach },
2063*7c478bd9Sstevel@tonic-gate 	{ "regs", "?", "print general-purpose registers", pt_regs },
2064*7c478bd9Sstevel@tonic-gate 	{ "fpregs", "?[-dqs]", "print floating point registers", pt_fpregs },
2065*7c478bd9Sstevel@tonic-gate 	{ "setenv", "name=value", "set an environment variable", pt_setenv },
2066*7c478bd9Sstevel@tonic-gate 	{ "stack", "?[cnt]", "print stack backtrace", pt_stack },
2067*7c478bd9Sstevel@tonic-gate 	{ "stackregs", "?", "print stack backtrace and registers", pt_stackr },
2068*7c478bd9Sstevel@tonic-gate 	{ "status", NULL, "print summary of current target", pt_status_dcmd },
2069*7c478bd9Sstevel@tonic-gate 	{ "tls", ":symbol",
2070*7c478bd9Sstevel@tonic-gate 	    "lookup TLS data in the context of a given thread", pt_tls },
2071*7c478bd9Sstevel@tonic-gate 	{ "tmodel", "{thread|lwp}", NULL, pt_tmodel },
2072*7c478bd9Sstevel@tonic-gate 	{ "unsetenv", "[name]", "clear an environment variable", pt_unsetenv },
2073*7c478bd9Sstevel@tonic-gate 	{ NULL }
2074*7c478bd9Sstevel@tonic-gate };
2075*7c478bd9Sstevel@tonic-gate 
2076*7c478bd9Sstevel@tonic-gate static void
2077*7c478bd9Sstevel@tonic-gate pt_thr_walk_fini(mdb_walk_state_t *wsp)
2078*7c478bd9Sstevel@tonic-gate {
2079*7c478bd9Sstevel@tonic-gate 	mdb_addrvec_destroy(wsp->walk_data);
2080*7c478bd9Sstevel@tonic-gate 	mdb_free(wsp->walk_data, sizeof (mdb_addrvec_t));
2081*7c478bd9Sstevel@tonic-gate }
2082*7c478bd9Sstevel@tonic-gate 
2083*7c478bd9Sstevel@tonic-gate static int
2084*7c478bd9Sstevel@tonic-gate pt_thr_walk_init(mdb_walk_state_t *wsp)
2085*7c478bd9Sstevel@tonic-gate {
2086*7c478bd9Sstevel@tonic-gate 	wsp->walk_data = mdb_zalloc(sizeof (mdb_addrvec_t), UM_SLEEP);
2087*7c478bd9Sstevel@tonic-gate 	mdb_addrvec_create(wsp->walk_data);
2088*7c478bd9Sstevel@tonic-gate 
2089*7c478bd9Sstevel@tonic-gate 	if (PTL_ITER(mdb.m_target, wsp->walk_data) == -1) {
2090*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to iterate over threads");
2091*7c478bd9Sstevel@tonic-gate 		pt_thr_walk_fini(wsp);
2092*7c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
2093*7c478bd9Sstevel@tonic-gate 	}
2094*7c478bd9Sstevel@tonic-gate 
2095*7c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
2096*7c478bd9Sstevel@tonic-gate }
2097*7c478bd9Sstevel@tonic-gate 
2098*7c478bd9Sstevel@tonic-gate static int
2099*7c478bd9Sstevel@tonic-gate pt_thr_walk_step(mdb_walk_state_t *wsp)
2100*7c478bd9Sstevel@tonic-gate {
2101*7c478bd9Sstevel@tonic-gate 	if (mdb_addrvec_length(wsp->walk_data) != 0) {
2102*7c478bd9Sstevel@tonic-gate 		return (wsp->walk_callback(mdb_addrvec_shift(wsp->walk_data),
2103*7c478bd9Sstevel@tonic-gate 		    NULL, wsp->walk_cbdata));
2104*7c478bd9Sstevel@tonic-gate 	}
2105*7c478bd9Sstevel@tonic-gate 	return (WALK_DONE);
2106*7c478bd9Sstevel@tonic-gate }
2107*7c478bd9Sstevel@tonic-gate 
2108*7c478bd9Sstevel@tonic-gate static const mdb_walker_t pt_walkers[] = {
2109*7c478bd9Sstevel@tonic-gate 	{ "thread", "walk list of valid thread identifiers",
2110*7c478bd9Sstevel@tonic-gate 	    pt_thr_walk_init, pt_thr_walk_step, pt_thr_walk_fini },
2111*7c478bd9Sstevel@tonic-gate 	{ NULL }
2112*7c478bd9Sstevel@tonic-gate };
2113*7c478bd9Sstevel@tonic-gate 
2114*7c478bd9Sstevel@tonic-gate 
2115*7c478bd9Sstevel@tonic-gate static void
2116*7c478bd9Sstevel@tonic-gate pt_activate_common(mdb_tgt_t *t)
2117*7c478bd9Sstevel@tonic-gate {
2118*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
2119*7c478bd9Sstevel@tonic-gate 	GElf_Sym sym;
2120*7c478bd9Sstevel@tonic-gate 
2121*7c478bd9Sstevel@tonic-gate 	/*
2122*7c478bd9Sstevel@tonic-gate 	 * If we have a libproc handle and AT_BASE is set, the process or core
2123*7c478bd9Sstevel@tonic-gate 	 * is dynamically linked.  We call Prd_agent() to force libproc to
2124*7c478bd9Sstevel@tonic-gate 	 * try to initialize librtld_db, and issue a warning if that fails.
2125*7c478bd9Sstevel@tonic-gate 	 */
2126*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle != NULL && Pgetauxval(t->t_pshandle,
2127*7c478bd9Sstevel@tonic-gate 	    AT_BASE) != -1L && Prd_agent(t->t_pshandle) == NULL) {
2128*7c478bd9Sstevel@tonic-gate 		mdb_warn("warning: librtld_db failed to initialize; shared "
2129*7c478bd9Sstevel@tonic-gate 		    "library information will not be available\n");
2130*7c478bd9Sstevel@tonic-gate 	}
2131*7c478bd9Sstevel@tonic-gate 
2132*7c478bd9Sstevel@tonic-gate 	/*
2133*7c478bd9Sstevel@tonic-gate 	 * If we have a libproc handle and libthread is loaded, attempt to load
2134*7c478bd9Sstevel@tonic-gate 	 * and initialize the corresponding libthread_db.  If this fails, fall
2135*7c478bd9Sstevel@tonic-gate 	 * back to our native LWP implementation and issue a warning.
2136*7c478bd9Sstevel@tonic-gate 	 */
2137*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle != NULL && Pstate(t->t_pshandle) != PS_IDLE)
2138*7c478bd9Sstevel@tonic-gate 		(void) Pobject_iter(t->t_pshandle, (proc_map_f *)thr_check, t);
2139*7c478bd9Sstevel@tonic-gate 
2140*7c478bd9Sstevel@tonic-gate 	/*
2141*7c478bd9Sstevel@tonic-gate 	 * If there's a global object named '_mdb_abort_info', assuming we're
2142*7c478bd9Sstevel@tonic-gate 	 * debugging mdb itself and load the developer support module.
2143*7c478bd9Sstevel@tonic-gate 	 */
2144*7c478bd9Sstevel@tonic-gate 	if (mdb_gelf_symtab_lookup_by_name(pt->p_symtab, "_mdb_abort_info",
2145*7c478bd9Sstevel@tonic-gate 	    &sym, NULL) == 0 && GELF_ST_TYPE(sym.st_info) == STT_OBJECT) {
2146*7c478bd9Sstevel@tonic-gate 		if (mdb_module_load("mdb_ds", MDB_MOD_SILENT) < 0)
2147*7c478bd9Sstevel@tonic-gate 			mdb_warn("warning: failed to load developer support\n");
2148*7c478bd9Sstevel@tonic-gate 	}
2149*7c478bd9Sstevel@tonic-gate 
2150*7c478bd9Sstevel@tonic-gate 	mdb_tgt_elf_export(pt->p_file);
2151*7c478bd9Sstevel@tonic-gate }
2152*7c478bd9Sstevel@tonic-gate 
2153*7c478bd9Sstevel@tonic-gate static void
2154*7c478bd9Sstevel@tonic-gate pt_activate(mdb_tgt_t *t)
2155*7c478bd9Sstevel@tonic-gate {
2156*7c478bd9Sstevel@tonic-gate 	static const mdb_nv_disc_t reg_disc = { reg_disc_set, reg_disc_get };
2157*7c478bd9Sstevel@tonic-gate 
2158*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
2159*7c478bd9Sstevel@tonic-gate 	struct utsname u1, u2;
2160*7c478bd9Sstevel@tonic-gate 	mdb_var_t *v;
2161*7c478bd9Sstevel@tonic-gate 	core_content_t content;
2162*7c478bd9Sstevel@tonic-gate 
2163*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle) {
2164*7c478bd9Sstevel@tonic-gate 		mdb_prop_postmortem = (Pstate(t->t_pshandle) == PS_DEAD);
2165*7c478bd9Sstevel@tonic-gate 		mdb_prop_kernel = FALSE;
2166*7c478bd9Sstevel@tonic-gate 	} else
2167*7c478bd9Sstevel@tonic-gate 		mdb_prop_kernel = mdb_prop_postmortem = FALSE;
2168*7c478bd9Sstevel@tonic-gate 
2169*7c478bd9Sstevel@tonic-gate 	mdb_prop_datamodel = MDB_TGT_MODEL_NATIVE;
2170*7c478bd9Sstevel@tonic-gate 
2171*7c478bd9Sstevel@tonic-gate 	/*
2172*7c478bd9Sstevel@tonic-gate 	 * If we're examining a core file that doesn't contain program text,
2173*7c478bd9Sstevel@tonic-gate 	 * and uname(2) doesn't match the NT_UTSNAME note recorded in the
2174*7c478bd9Sstevel@tonic-gate 	 * core file, issue a warning.
2175*7c478bd9Sstevel@tonic-gate 	 */
2176*7c478bd9Sstevel@tonic-gate 	if (mdb_prop_postmortem == TRUE &&
2177*7c478bd9Sstevel@tonic-gate 	    ((content = Pcontent(t->t_pshandle)) == CC_CONTENT_INVALID ||
2178*7c478bd9Sstevel@tonic-gate 	    !(content & CC_CONTENT_TEXT)) &&
2179*7c478bd9Sstevel@tonic-gate 	    uname(&u1) >= 0 && Puname(t->t_pshandle, &u2) == 0 &&
2180*7c478bd9Sstevel@tonic-gate 	    (strcmp(u1.release, u2.release) != 0 ||
2181*7c478bd9Sstevel@tonic-gate 	    strcmp(u1.version, u2.version) != 0)) {
2182*7c478bd9Sstevel@tonic-gate 		mdb_warn("warning: core file is from %s %s %s; shared text "
2183*7c478bd9Sstevel@tonic-gate 		    "mappings may not match installed libraries\n",
2184*7c478bd9Sstevel@tonic-gate 		    u2.sysname, u2.release, u2.version);
2185*7c478bd9Sstevel@tonic-gate 	}
2186*7c478bd9Sstevel@tonic-gate 
2187*7c478bd9Sstevel@tonic-gate 	/*
2188*7c478bd9Sstevel@tonic-gate 	 * Perform the common initialization tasks -- these are shared with
2189*7c478bd9Sstevel@tonic-gate 	 * the pt_exec() and pt_run() subroutines.
2190*7c478bd9Sstevel@tonic-gate 	 */
2191*7c478bd9Sstevel@tonic-gate 	pt_activate_common(t);
2192*7c478bd9Sstevel@tonic-gate 
2193*7c478bd9Sstevel@tonic-gate 	(void) mdb_tgt_register_dcmds(t, &pt_dcmds[0], MDB_MOD_FORCE);
2194*7c478bd9Sstevel@tonic-gate 	(void) mdb_tgt_register_walkers(t, &pt_walkers[0], MDB_MOD_FORCE);
2195*7c478bd9Sstevel@tonic-gate 
2196*7c478bd9Sstevel@tonic-gate 	/*
2197*7c478bd9Sstevel@tonic-gate 	 * Iterate through our register description list and export
2198*7c478bd9Sstevel@tonic-gate 	 * each register as a named variable.
2199*7c478bd9Sstevel@tonic-gate 	 */
2200*7c478bd9Sstevel@tonic-gate 	mdb_nv_rewind(&pt->p_regs);
2201*7c478bd9Sstevel@tonic-gate 	while ((v = mdb_nv_advance(&pt->p_regs)) != NULL) {
2202*7c478bd9Sstevel@tonic-gate 		ushort_t rd_flags = MDB_TGT_R_FLAGS(mdb_nv_get_value(v));
2203*7c478bd9Sstevel@tonic-gate 
2204*7c478bd9Sstevel@tonic-gate 		if (!(rd_flags & MDB_TGT_R_EXPORT))
2205*7c478bd9Sstevel@tonic-gate 			continue; /* Don't export register as a variable */
2206*7c478bd9Sstevel@tonic-gate 
2207*7c478bd9Sstevel@tonic-gate 		(void) mdb_nv_insert(&mdb.m_nv, mdb_nv_get_name(v), &reg_disc,
2208*7c478bd9Sstevel@tonic-gate 		    (uintptr_t)t, MDB_NV_PERSIST);
2209*7c478bd9Sstevel@tonic-gate 	}
2210*7c478bd9Sstevel@tonic-gate }
2211*7c478bd9Sstevel@tonic-gate 
2212*7c478bd9Sstevel@tonic-gate static void
2213*7c478bd9Sstevel@tonic-gate pt_deactivate(mdb_tgt_t *t)
2214*7c478bd9Sstevel@tonic-gate {
2215*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
2216*7c478bd9Sstevel@tonic-gate 	const mdb_dcmd_t *dcp;
2217*7c478bd9Sstevel@tonic-gate 	const mdb_walker_t *wp;
2218*7c478bd9Sstevel@tonic-gate 	mdb_var_t *v, *w;
2219*7c478bd9Sstevel@tonic-gate 
2220*7c478bd9Sstevel@tonic-gate 	mdb_nv_rewind(&pt->p_regs);
2221*7c478bd9Sstevel@tonic-gate 	while ((v = mdb_nv_advance(&pt->p_regs)) != NULL) {
2222*7c478bd9Sstevel@tonic-gate 		ushort_t rd_flags = MDB_TGT_R_FLAGS(mdb_nv_get_value(v));
2223*7c478bd9Sstevel@tonic-gate 
2224*7c478bd9Sstevel@tonic-gate 		if (!(rd_flags & MDB_TGT_R_EXPORT))
2225*7c478bd9Sstevel@tonic-gate 			continue; /* Didn't export register as a variable */
2226*7c478bd9Sstevel@tonic-gate 
2227*7c478bd9Sstevel@tonic-gate 		if (w = mdb_nv_lookup(&mdb.m_nv, mdb_nv_get_name(v))) {
2228*7c478bd9Sstevel@tonic-gate 			w->v_flags &= ~MDB_NV_PERSIST;
2229*7c478bd9Sstevel@tonic-gate 			mdb_nv_remove(&mdb.m_nv, w);
2230*7c478bd9Sstevel@tonic-gate 		}
2231*7c478bd9Sstevel@tonic-gate 	}
2232*7c478bd9Sstevel@tonic-gate 
2233*7c478bd9Sstevel@tonic-gate 	for (wp = &pt_walkers[0]; wp->walk_name != NULL; wp++) {
2234*7c478bd9Sstevel@tonic-gate 		if (mdb_module_remove_walker(t->t_module, wp->walk_name) == -1)
2235*7c478bd9Sstevel@tonic-gate 			warn("failed to remove walk %s", wp->walk_name);
2236*7c478bd9Sstevel@tonic-gate 	}
2237*7c478bd9Sstevel@tonic-gate 
2238*7c478bd9Sstevel@tonic-gate 	for (dcp = &pt_dcmds[0]; dcp->dc_name != NULL; dcp++) {
2239*7c478bd9Sstevel@tonic-gate 		if (mdb_module_remove_dcmd(t->t_module, dcp->dc_name) == -1)
2240*7c478bd9Sstevel@tonic-gate 			warn("failed to remove dcmd %s", dcp->dc_name);
2241*7c478bd9Sstevel@tonic-gate 	}
2242*7c478bd9Sstevel@tonic-gate 
2243*7c478bd9Sstevel@tonic-gate 	mdb_prop_postmortem = FALSE;
2244*7c478bd9Sstevel@tonic-gate 	mdb_prop_kernel = FALSE;
2245*7c478bd9Sstevel@tonic-gate 	mdb_prop_datamodel = MDB_TGT_MODEL_UNKNOWN;
2246*7c478bd9Sstevel@tonic-gate }
2247*7c478bd9Sstevel@tonic-gate 
2248*7c478bd9Sstevel@tonic-gate static void
2249*7c478bd9Sstevel@tonic-gate pt_periodic(mdb_tgt_t *t)
2250*7c478bd9Sstevel@tonic-gate {
2251*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
2252*7c478bd9Sstevel@tonic-gate 
2253*7c478bd9Sstevel@tonic-gate 	if (pt->p_rdstate == PT_RD_CONSIST) {
2254*7c478bd9Sstevel@tonic-gate 		if (t->t_pshandle != NULL && Pstate(t->t_pshandle) < PS_LOST &&
2255*7c478bd9Sstevel@tonic-gate 		    !(mdb.m_flags & MDB_FL_NOMODS)) {
2256*7c478bd9Sstevel@tonic-gate 			mdb_printf("%s: You've got symbols!\n", mdb.m_pname);
2257*7c478bd9Sstevel@tonic-gate 			mdb_module_load_all(0);
2258*7c478bd9Sstevel@tonic-gate 		}
2259*7c478bd9Sstevel@tonic-gate 		pt->p_rdstate = PT_RD_NONE;
2260*7c478bd9Sstevel@tonic-gate 	}
2261*7c478bd9Sstevel@tonic-gate }
2262*7c478bd9Sstevel@tonic-gate 
2263*7c478bd9Sstevel@tonic-gate static void
2264*7c478bd9Sstevel@tonic-gate pt_destroy(mdb_tgt_t *t)
2265*7c478bd9Sstevel@tonic-gate {
2266*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
2267*7c478bd9Sstevel@tonic-gate 
2268*7c478bd9Sstevel@tonic-gate 	if (pt->p_idlehandle != NULL && pt->p_idlehandle != t->t_pshandle)
2269*7c478bd9Sstevel@tonic-gate 		Prelease(pt->p_idlehandle, 0);
2270*7c478bd9Sstevel@tonic-gate 
2271*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle != NULL) {
2272*7c478bd9Sstevel@tonic-gate 		PTL_DTOR(t);
2273*7c478bd9Sstevel@tonic-gate 		pt_release_parents(t);
2274*7c478bd9Sstevel@tonic-gate 		pt_pre_detach(t, TRUE);
2275*7c478bd9Sstevel@tonic-gate 		Prelease(t->t_pshandle, pt->p_rflags);
2276*7c478bd9Sstevel@tonic-gate 	}
2277*7c478bd9Sstevel@tonic-gate 
2278*7c478bd9Sstevel@tonic-gate 	mdb.m_flags &= ~(MDB_FL_VCREATE | MDB_FL_JOBCTL);
2279*7c478bd9Sstevel@tonic-gate 	pt_close_aout(t);
2280*7c478bd9Sstevel@tonic-gate 
2281*7c478bd9Sstevel@tonic-gate 	if (pt->p_aout_fio != NULL)
2282*7c478bd9Sstevel@tonic-gate 		mdb_io_rele(pt->p_aout_fio);
2283*7c478bd9Sstevel@tonic-gate 
2284*7c478bd9Sstevel@tonic-gate 	pt_env_clear(pt);
2285*7c478bd9Sstevel@tonic-gate 	mdb_nv_destroy(&pt->p_env);
2286*7c478bd9Sstevel@tonic-gate 
2287*7c478bd9Sstevel@tonic-gate 	mdb_nv_destroy(&pt->p_regs);
2288*7c478bd9Sstevel@tonic-gate 	mdb_free(pt, sizeof (pt_data_t));
2289*7c478bd9Sstevel@tonic-gate }
2290*7c478bd9Sstevel@tonic-gate 
2291*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2292*7c478bd9Sstevel@tonic-gate static const char *
2293*7c478bd9Sstevel@tonic-gate pt_name(mdb_tgt_t *t)
2294*7c478bd9Sstevel@tonic-gate {
2295*7c478bd9Sstevel@tonic-gate 	return ("proc");
2296*7c478bd9Sstevel@tonic-gate }
2297*7c478bd9Sstevel@tonic-gate 
2298*7c478bd9Sstevel@tonic-gate static const char *
2299*7c478bd9Sstevel@tonic-gate pt_platform(mdb_tgt_t *t)
2300*7c478bd9Sstevel@tonic-gate {
2301*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
2302*7c478bd9Sstevel@tonic-gate 
2303*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle != NULL &&
2304*7c478bd9Sstevel@tonic-gate 	    Pplatform(t->t_pshandle, pt->p_platform, MAXNAMELEN) != NULL)
2305*7c478bd9Sstevel@tonic-gate 		return (pt->p_platform);
2306*7c478bd9Sstevel@tonic-gate 
2307*7c478bd9Sstevel@tonic-gate 	return (mdb_conf_platform());
2308*7c478bd9Sstevel@tonic-gate }
2309*7c478bd9Sstevel@tonic-gate 
2310*7c478bd9Sstevel@tonic-gate static int
2311*7c478bd9Sstevel@tonic-gate pt_uname(mdb_tgt_t *t, struct utsname *utsp)
2312*7c478bd9Sstevel@tonic-gate {
2313*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle != NULL)
2314*7c478bd9Sstevel@tonic-gate 		return (Puname(t->t_pshandle, utsp));
2315*7c478bd9Sstevel@tonic-gate 
2316*7c478bd9Sstevel@tonic-gate 	return (uname(utsp) >= 0 ? 0 : -1);
2317*7c478bd9Sstevel@tonic-gate }
2318*7c478bd9Sstevel@tonic-gate 
2319*7c478bd9Sstevel@tonic-gate static int
2320*7c478bd9Sstevel@tonic-gate pt_dmodel(mdb_tgt_t *t)
2321*7c478bd9Sstevel@tonic-gate {
2322*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle == NULL)
2323*7c478bd9Sstevel@tonic-gate 		return (MDB_TGT_MODEL_NATIVE);
2324*7c478bd9Sstevel@tonic-gate 
2325*7c478bd9Sstevel@tonic-gate 	switch (Pstatus(t->t_pshandle)->pr_dmodel) {
2326*7c478bd9Sstevel@tonic-gate 	case PR_MODEL_ILP32:
2327*7c478bd9Sstevel@tonic-gate 		return (MDB_TGT_MODEL_ILP32);
2328*7c478bd9Sstevel@tonic-gate 	case PR_MODEL_LP64:
2329*7c478bd9Sstevel@tonic-gate 		return (MDB_TGT_MODEL_LP64);
2330*7c478bd9Sstevel@tonic-gate 	}
2331*7c478bd9Sstevel@tonic-gate 
2332*7c478bd9Sstevel@tonic-gate 	return (MDB_TGT_MODEL_UNKNOWN);
2333*7c478bd9Sstevel@tonic-gate }
2334*7c478bd9Sstevel@tonic-gate 
2335*7c478bd9Sstevel@tonic-gate static ssize_t
2336*7c478bd9Sstevel@tonic-gate pt_vread(mdb_tgt_t *t, void *buf, size_t nbytes, uintptr_t addr)
2337*7c478bd9Sstevel@tonic-gate {
2338*7c478bd9Sstevel@tonic-gate 	ssize_t n;
2339*7c478bd9Sstevel@tonic-gate 
2340*7c478bd9Sstevel@tonic-gate 	/*
2341*7c478bd9Sstevel@tonic-gate 	 * If no handle is open yet, reads from virtual addresses are
2342*7c478bd9Sstevel@tonic-gate 	 * allowed to succeed but return zero-filled memory.
2343*7c478bd9Sstevel@tonic-gate 	 */
2344*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle == NULL) {
2345*7c478bd9Sstevel@tonic-gate 		bzero(buf, nbytes);
2346*7c478bd9Sstevel@tonic-gate 		return (nbytes);
2347*7c478bd9Sstevel@tonic-gate 	}
2348*7c478bd9Sstevel@tonic-gate 
2349*7c478bd9Sstevel@tonic-gate 	if ((n = Pread(t->t_pshandle, buf, nbytes, addr)) <= 0)
2350*7c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_NOMAP));
2351*7c478bd9Sstevel@tonic-gate 
2352*7c478bd9Sstevel@tonic-gate 	return (n);
2353*7c478bd9Sstevel@tonic-gate }
2354*7c478bd9Sstevel@tonic-gate 
2355*7c478bd9Sstevel@tonic-gate static ssize_t
2356*7c478bd9Sstevel@tonic-gate pt_vwrite(mdb_tgt_t *t, const void *buf, size_t nbytes, uintptr_t addr)
2357*7c478bd9Sstevel@tonic-gate {
2358*7c478bd9Sstevel@tonic-gate 	ssize_t n;
2359*7c478bd9Sstevel@tonic-gate 
2360*7c478bd9Sstevel@tonic-gate 	/*
2361*7c478bd9Sstevel@tonic-gate 	 * If no handle is open yet, writes to virtual addresses are
2362*7c478bd9Sstevel@tonic-gate 	 * allowed to succeed but do not actually modify anything.
2363*7c478bd9Sstevel@tonic-gate 	 */
2364*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle == NULL)
2365*7c478bd9Sstevel@tonic-gate 		return (nbytes);
2366*7c478bd9Sstevel@tonic-gate 
2367*7c478bd9Sstevel@tonic-gate 	n = Pwrite(t->t_pshandle, buf, nbytes, addr);
2368*7c478bd9Sstevel@tonic-gate 
2369*7c478bd9Sstevel@tonic-gate 	if (n == -1 && errno == EIO)
2370*7c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_NOMAP));
2371*7c478bd9Sstevel@tonic-gate 
2372*7c478bd9Sstevel@tonic-gate 	return (n);
2373*7c478bd9Sstevel@tonic-gate }
2374*7c478bd9Sstevel@tonic-gate 
2375*7c478bd9Sstevel@tonic-gate static ssize_t
2376*7c478bd9Sstevel@tonic-gate pt_fread(mdb_tgt_t *t, void *buf, size_t nbytes, uintptr_t addr)
2377*7c478bd9Sstevel@tonic-gate {
2378*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
2379*7c478bd9Sstevel@tonic-gate 
2380*7c478bd9Sstevel@tonic-gate 	if (pt->p_file != NULL) {
2381*7c478bd9Sstevel@tonic-gate 		return (mdb_gelf_rw(pt->p_file, buf, nbytes, addr,
2382*7c478bd9Sstevel@tonic-gate 		    IOPF_READ(pt->p_fio), GIO_READ));
2383*7c478bd9Sstevel@tonic-gate 	}
2384*7c478bd9Sstevel@tonic-gate 
2385*7c478bd9Sstevel@tonic-gate 	bzero(buf, nbytes);
2386*7c478bd9Sstevel@tonic-gate 	return (nbytes);
2387*7c478bd9Sstevel@tonic-gate }
2388*7c478bd9Sstevel@tonic-gate 
2389*7c478bd9Sstevel@tonic-gate static ssize_t
2390*7c478bd9Sstevel@tonic-gate pt_fwrite(mdb_tgt_t *t, const void *buf, size_t nbytes, uintptr_t addr)
2391*7c478bd9Sstevel@tonic-gate {
2392*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
2393*7c478bd9Sstevel@tonic-gate 
2394*7c478bd9Sstevel@tonic-gate 	if (pt->p_file != NULL) {
2395*7c478bd9Sstevel@tonic-gate 		return (mdb_gelf_rw(pt->p_file, (void *)buf, nbytes, addr,
2396*7c478bd9Sstevel@tonic-gate 		    IOPF_WRITE(pt->p_fio), GIO_WRITE));
2397*7c478bd9Sstevel@tonic-gate 	}
2398*7c478bd9Sstevel@tonic-gate 
2399*7c478bd9Sstevel@tonic-gate 	return (nbytes);
2400*7c478bd9Sstevel@tonic-gate }
2401*7c478bd9Sstevel@tonic-gate 
2402*7c478bd9Sstevel@tonic-gate static const char *
2403*7c478bd9Sstevel@tonic-gate pt_resolve_lmid(const char *object, Lmid_t *lmidp)
2404*7c478bd9Sstevel@tonic-gate {
2405*7c478bd9Sstevel@tonic-gate 	Lmid_t lmid = PR_LMID_EVERY;
2406*7c478bd9Sstevel@tonic-gate 	const char *p;
2407*7c478bd9Sstevel@tonic-gate 
2408*7c478bd9Sstevel@tonic-gate 	if (object == MDB_TGT_OBJ_EVERY || object == MDB_TGT_OBJ_EXEC)
2409*7c478bd9Sstevel@tonic-gate 		lmid = LM_ID_BASE; /* restrict scope to a.out's link map */
2410*7c478bd9Sstevel@tonic-gate 	else if (object != MDB_TGT_OBJ_RTLD && strncmp(object, "LM", 2) == 0 &&
2411*7c478bd9Sstevel@tonic-gate 	    (p = strchr(object, '`')) != NULL) {
2412*7c478bd9Sstevel@tonic-gate 		object += 2;	/* skip past initial "LM" prefix */
2413*7c478bd9Sstevel@tonic-gate 		lmid = strntoul(object, (size_t)(p - object), mdb.m_radix);
2414*7c478bd9Sstevel@tonic-gate 		object = p + 1;	/* skip past link map specifier */
2415*7c478bd9Sstevel@tonic-gate 	}
2416*7c478bd9Sstevel@tonic-gate 
2417*7c478bd9Sstevel@tonic-gate 	*lmidp = lmid;
2418*7c478bd9Sstevel@tonic-gate 	return (object);
2419*7c478bd9Sstevel@tonic-gate }
2420*7c478bd9Sstevel@tonic-gate 
2421*7c478bd9Sstevel@tonic-gate static int
2422*7c478bd9Sstevel@tonic-gate tlsbase(mdb_tgt_t *t, mdb_tgt_tid_t tid, Lmid_t lmid, const char *object,
2423*7c478bd9Sstevel@tonic-gate     psaddr_t *basep)
2424*7c478bd9Sstevel@tonic-gate {
2425*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
2426*7c478bd9Sstevel@tonic-gate 	const rd_loadobj_t *loadobjp;
2427*7c478bd9Sstevel@tonic-gate 	td_thrhandle_t th;
2428*7c478bd9Sstevel@tonic-gate 	td_err_e err;
2429*7c478bd9Sstevel@tonic-gate 
2430*7c478bd9Sstevel@tonic-gate 	if (object == MDB_TGT_OBJ_EVERY)
2431*7c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
2432*7c478bd9Sstevel@tonic-gate 
2433*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle == NULL || Pstate(t->t_pshandle) == PS_IDLE)
2434*7c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_NOPROC));
2435*7c478bd9Sstevel@tonic-gate 
2436*7c478bd9Sstevel@tonic-gate 	if (pt->p_tdb_ops == NULL)
2437*7c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_TDB));
2438*7c478bd9Sstevel@tonic-gate 
2439*7c478bd9Sstevel@tonic-gate 	err = pt->p_tdb_ops->td_ta_map_id2thr(pt->p_ptl_hdl, tid, &th);
2440*7c478bd9Sstevel@tonic-gate 	if (err != TD_OK)
2441*7c478bd9Sstevel@tonic-gate 		return (set_errno(tdb_to_errno(err)));
2442*7c478bd9Sstevel@tonic-gate 
2443*7c478bd9Sstevel@tonic-gate 	/*
2444*7c478bd9Sstevel@tonic-gate 	 * If this fails, rtld_db has failed to initialize properly.
2445*7c478bd9Sstevel@tonic-gate 	 */
2446*7c478bd9Sstevel@tonic-gate 	if ((loadobjp = Plmid_to_loadobj(t->t_pshandle, lmid, object)) == NULL)
2447*7c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_NORTLD));
2448*7c478bd9Sstevel@tonic-gate 
2449*7c478bd9Sstevel@tonic-gate 	/*
2450*7c478bd9Sstevel@tonic-gate 	 * This will fail if the TLS block has not been allocated for the
2451*7c478bd9Sstevel@tonic-gate 	 * object that contains the TLS symbol in question.
2452*7c478bd9Sstevel@tonic-gate 	 */
2453*7c478bd9Sstevel@tonic-gate 	err = pt->p_tdb_ops->td_thr_tlsbase(&th, loadobjp->rl_tlsmodid, basep);
2454*7c478bd9Sstevel@tonic-gate 	if (err != TD_OK)
2455*7c478bd9Sstevel@tonic-gate 		return (set_errno(tdb_to_errno(err)));
2456*7c478bd9Sstevel@tonic-gate 
2457*7c478bd9Sstevel@tonic-gate 	return (0);
2458*7c478bd9Sstevel@tonic-gate }
2459*7c478bd9Sstevel@tonic-gate 
2460*7c478bd9Sstevel@tonic-gate typedef struct {
2461*7c478bd9Sstevel@tonic-gate 	mdb_tgt_t	*pl_tgt;
2462*7c478bd9Sstevel@tonic-gate 	const char	*pl_name;
2463*7c478bd9Sstevel@tonic-gate 	Lmid_t		pl_lmid;
2464*7c478bd9Sstevel@tonic-gate 	GElf_Sym	*pl_symp;
2465*7c478bd9Sstevel@tonic-gate 	mdb_syminfo_t	*pl_sip;
2466*7c478bd9Sstevel@tonic-gate 	mdb_tgt_tid_t	pl_tid;
2467*7c478bd9Sstevel@tonic-gate 	mdb_bool_t	pl_found;
2468*7c478bd9Sstevel@tonic-gate } pt_lookup_t;
2469*7c478bd9Sstevel@tonic-gate 
2470*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2471*7c478bd9Sstevel@tonic-gate static int
2472*7c478bd9Sstevel@tonic-gate pt_lookup_cb(void *data, const prmap_t *pmp, const char *object)
2473*7c478bd9Sstevel@tonic-gate {
2474*7c478bd9Sstevel@tonic-gate 	pt_lookup_t *plp = data;
2475*7c478bd9Sstevel@tonic-gate 	struct ps_prochandle *P = plp->pl_tgt->t_pshandle;
2476*7c478bd9Sstevel@tonic-gate 	prsyminfo_t si;
2477*7c478bd9Sstevel@tonic-gate 	GElf_Sym sym;
2478*7c478bd9Sstevel@tonic-gate 
2479*7c478bd9Sstevel@tonic-gate 	if (Pxlookup_by_name(P, plp->pl_lmid, object, plp->pl_name, &sym,
2480*7c478bd9Sstevel@tonic-gate 	    &si) != 0)
2481*7c478bd9Sstevel@tonic-gate 		return (0);
2482*7c478bd9Sstevel@tonic-gate 
2483*7c478bd9Sstevel@tonic-gate 	/*
2484*7c478bd9Sstevel@tonic-gate 	 * If we encounter a match with SHN_UNDEF, keep looking for a
2485*7c478bd9Sstevel@tonic-gate 	 * better match. Return the first match with SHN_UNDEF set if no
2486*7c478bd9Sstevel@tonic-gate 	 * better match is found.
2487*7c478bd9Sstevel@tonic-gate 	 */
2488*7c478bd9Sstevel@tonic-gate 	if (sym.st_shndx == SHN_UNDEF) {
2489*7c478bd9Sstevel@tonic-gate 		if (!plp->pl_found) {
2490*7c478bd9Sstevel@tonic-gate 			plp->pl_found = TRUE;
2491*7c478bd9Sstevel@tonic-gate 			*plp->pl_symp = sym;
2492*7c478bd9Sstevel@tonic-gate 			plp->pl_sip->sym_table = si.prs_table;
2493*7c478bd9Sstevel@tonic-gate 			plp->pl_sip->sym_id = si.prs_id;
2494*7c478bd9Sstevel@tonic-gate 		}
2495*7c478bd9Sstevel@tonic-gate 
2496*7c478bd9Sstevel@tonic-gate 		return (0);
2497*7c478bd9Sstevel@tonic-gate 	}
2498*7c478bd9Sstevel@tonic-gate 
2499*7c478bd9Sstevel@tonic-gate 	/*
2500*7c478bd9Sstevel@tonic-gate 	 * Note that if the symbol's st_shndx is SHN_UNDEF we don't have the
2501*7c478bd9Sstevel@tonic-gate 	 * TLS offset anyway, so adding in the tlsbase would be worthless.
2502*7c478bd9Sstevel@tonic-gate 	 */
2503*7c478bd9Sstevel@tonic-gate 	if (GELF_ST_TYPE(sym.st_info) == STT_TLS &&
2504*7c478bd9Sstevel@tonic-gate 	    plp->pl_tid != (mdb_tgt_tid_t)-1) {
2505*7c478bd9Sstevel@tonic-gate 		psaddr_t base;
2506*7c478bd9Sstevel@tonic-gate 
2507*7c478bd9Sstevel@tonic-gate 		if (tlsbase(plp->pl_tgt, plp->pl_tid, plp->pl_lmid, object,
2508*7c478bd9Sstevel@tonic-gate 		    &base) != 0)
2509*7c478bd9Sstevel@tonic-gate 			return (-1); /* errno is set for us */
2510*7c478bd9Sstevel@tonic-gate 
2511*7c478bd9Sstevel@tonic-gate 		sym.st_value += base;
2512*7c478bd9Sstevel@tonic-gate 	}
2513*7c478bd9Sstevel@tonic-gate 
2514*7c478bd9Sstevel@tonic-gate 	plp->pl_found = TRUE;
2515*7c478bd9Sstevel@tonic-gate 	*plp->pl_symp = sym;
2516*7c478bd9Sstevel@tonic-gate 	plp->pl_sip->sym_table = si.prs_table;
2517*7c478bd9Sstevel@tonic-gate 	plp->pl_sip->sym_id = si.prs_id;
2518*7c478bd9Sstevel@tonic-gate 
2519*7c478bd9Sstevel@tonic-gate 	return (1);
2520*7c478bd9Sstevel@tonic-gate }
2521*7c478bd9Sstevel@tonic-gate 
2522*7c478bd9Sstevel@tonic-gate /*
2523*7c478bd9Sstevel@tonic-gate  * Lookup the symbol with a thread context so that we can adjust TLS symbols
2524*7c478bd9Sstevel@tonic-gate  * to get the values as they would appear in the context of the given thread.
2525*7c478bd9Sstevel@tonic-gate  */
2526*7c478bd9Sstevel@tonic-gate static int
2527*7c478bd9Sstevel@tonic-gate pt_lookup_by_name_thr(mdb_tgt_t *t, const char *object,
2528*7c478bd9Sstevel@tonic-gate     const char *name, GElf_Sym *symp, mdb_syminfo_t *sip, mdb_tgt_tid_t tid)
2529*7c478bd9Sstevel@tonic-gate {
2530*7c478bd9Sstevel@tonic-gate 	struct ps_prochandle *P = t->t_pshandle;
2531*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
2532*7c478bd9Sstevel@tonic-gate 	Lmid_t lmid;
2533*7c478bd9Sstevel@tonic-gate 	uint_t i;
2534*7c478bd9Sstevel@tonic-gate 	const rd_loadobj_t *aout_lop;
2535*7c478bd9Sstevel@tonic-gate 
2536*7c478bd9Sstevel@tonic-gate 	object = pt_resolve_lmid(object, &lmid);
2537*7c478bd9Sstevel@tonic-gate 
2538*7c478bd9Sstevel@tonic-gate 	if (P != NULL) {
2539*7c478bd9Sstevel@tonic-gate 		pt_lookup_t pl;
2540*7c478bd9Sstevel@tonic-gate 
2541*7c478bd9Sstevel@tonic-gate 		pl.pl_tgt = t;
2542*7c478bd9Sstevel@tonic-gate 		pl.pl_name = name;
2543*7c478bd9Sstevel@tonic-gate 		pl.pl_lmid = lmid;
2544*7c478bd9Sstevel@tonic-gate 		pl.pl_symp = symp;
2545*7c478bd9Sstevel@tonic-gate 		pl.pl_sip = sip;
2546*7c478bd9Sstevel@tonic-gate 		pl.pl_tid = tid;
2547*7c478bd9Sstevel@tonic-gate 		pl.pl_found = FALSE;
2548*7c478bd9Sstevel@tonic-gate 
2549*7c478bd9Sstevel@tonic-gate 		if (object == MDB_TGT_OBJ_EVERY) {
2550*7c478bd9Sstevel@tonic-gate 			if (Pobject_iter(P, pt_lookup_cb, &pl) == -1)
2551*7c478bd9Sstevel@tonic-gate 				return (-1); /* errno is set for us */
2552*7c478bd9Sstevel@tonic-gate 		} else {
2553*7c478bd9Sstevel@tonic-gate 			const prmap_t *pmp;
2554*7c478bd9Sstevel@tonic-gate 
2555*7c478bd9Sstevel@tonic-gate 			/*
2556*7c478bd9Sstevel@tonic-gate 			 * This can fail either due to an invalid lmid or
2557*7c478bd9Sstevel@tonic-gate 			 * an invalid object. To determine which is
2558*7c478bd9Sstevel@tonic-gate 			 * faulty, we test the lmid against known valid
2559*7c478bd9Sstevel@tonic-gate 			 * lmids and then see if using a wild-card lmid
2560*7c478bd9Sstevel@tonic-gate 			 * improves ths situation.
2561*7c478bd9Sstevel@tonic-gate 			 */
2562*7c478bd9Sstevel@tonic-gate 			if ((pmp = Plmid_to_map(P, lmid, object)) == NULL) {
2563*7c478bd9Sstevel@tonic-gate 				if (lmid != PR_LMID_EVERY &&
2564*7c478bd9Sstevel@tonic-gate 				    lmid != LM_ID_BASE &&
2565*7c478bd9Sstevel@tonic-gate 				    lmid != LM_ID_LDSO &&
2566*7c478bd9Sstevel@tonic-gate 				    Plmid_to_map(P, PR_LMID_EVERY, object)
2567*7c478bd9Sstevel@tonic-gate 				    != NULL)
2568*7c478bd9Sstevel@tonic-gate 					return (set_errno(EMDB_NOLMID));
2569*7c478bd9Sstevel@tonic-gate 				else
2570*7c478bd9Sstevel@tonic-gate 					return (set_errno(EMDB_NOOBJ));
2571*7c478bd9Sstevel@tonic-gate 			}
2572*7c478bd9Sstevel@tonic-gate 
2573*7c478bd9Sstevel@tonic-gate 			if (pt_lookup_cb(&pl, pmp, object) == -1)
2574*7c478bd9Sstevel@tonic-gate 				return (-1); /* errno is set for us */
2575*7c478bd9Sstevel@tonic-gate 		}
2576*7c478bd9Sstevel@tonic-gate 
2577*7c478bd9Sstevel@tonic-gate 		if (pl.pl_found)
2578*7c478bd9Sstevel@tonic-gate 			return (0);
2579*7c478bd9Sstevel@tonic-gate 	}
2580*7c478bd9Sstevel@tonic-gate 
2581*7c478bd9Sstevel@tonic-gate 	/*
2582*7c478bd9Sstevel@tonic-gate 	 * If libproc doesn't have the symbols for rtld, we're cooked --
2583*7c478bd9Sstevel@tonic-gate 	 * mdb doesn't have those symbols either.
2584*7c478bd9Sstevel@tonic-gate 	 */
2585*7c478bd9Sstevel@tonic-gate 	if (object == MDB_TGT_OBJ_RTLD)
2586*7c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_NOSYM));
2587*7c478bd9Sstevel@tonic-gate 
2588*7c478bd9Sstevel@tonic-gate 	if (object != MDB_TGT_OBJ_EXEC && object != MDB_TGT_OBJ_EVERY) {
2589*7c478bd9Sstevel@tonic-gate 		int status = mdb_gelf_symtab_lookup_by_file(pt->p_symtab,
2590*7c478bd9Sstevel@tonic-gate 		    object, name, symp, &sip->sym_id);
2591*7c478bd9Sstevel@tonic-gate 
2592*7c478bd9Sstevel@tonic-gate 		if (status != 0) {
2593*7c478bd9Sstevel@tonic-gate 			if (P != NULL &&
2594*7c478bd9Sstevel@tonic-gate 			    Plmid_to_map(P, PR_LMID_EVERY, object) != NULL)
2595*7c478bd9Sstevel@tonic-gate 				return (set_errno(EMDB_NOSYM));
2596*7c478bd9Sstevel@tonic-gate 			else
2597*7c478bd9Sstevel@tonic-gate 				return (-1); /* errno set from lookup_by_file */
2598*7c478bd9Sstevel@tonic-gate 		}
2599*7c478bd9Sstevel@tonic-gate 
2600*7c478bd9Sstevel@tonic-gate 		goto found;
2601*7c478bd9Sstevel@tonic-gate 	}
2602*7c478bd9Sstevel@tonic-gate 
2603*7c478bd9Sstevel@tonic-gate 	if (mdb_gelf_symtab_lookup_by_name(pt->p_symtab, name, symp, &i) == 0) {
2604*7c478bd9Sstevel@tonic-gate 		sip->sym_table = MDB_TGT_SYMTAB;
2605*7c478bd9Sstevel@tonic-gate 		sip->sym_id = i;
2606*7c478bd9Sstevel@tonic-gate 		goto local_found;
2607*7c478bd9Sstevel@tonic-gate 	}
2608*7c478bd9Sstevel@tonic-gate 
2609*7c478bd9Sstevel@tonic-gate 	if (mdb_gelf_symtab_lookup_by_name(pt->p_dynsym, name, symp, &i) == 0) {
2610*7c478bd9Sstevel@tonic-gate 		sip->sym_table = MDB_TGT_DYNSYM;
2611*7c478bd9Sstevel@tonic-gate 		sip->sym_id = i;
2612*7c478bd9Sstevel@tonic-gate 		goto local_found;
2613*7c478bd9Sstevel@tonic-gate 	}
2614*7c478bd9Sstevel@tonic-gate 
2615*7c478bd9Sstevel@tonic-gate 	return (set_errno(EMDB_NOSYM));
2616*7c478bd9Sstevel@tonic-gate 
2617*7c478bd9Sstevel@tonic-gate local_found:
2618*7c478bd9Sstevel@tonic-gate 	if (pt->p_file != NULL &&
2619*7c478bd9Sstevel@tonic-gate 	    pt->p_file->gf_ehdr.e_type == ET_DYN &&
2620*7c478bd9Sstevel@tonic-gate 	    P != NULL &&
2621*7c478bd9Sstevel@tonic-gate 	    (aout_lop = Pname_to_loadobj(P, PR_OBJ_EXEC)) != NULL)
2622*7c478bd9Sstevel@tonic-gate 		symp->st_value += aout_lop->rl_base;
2623*7c478bd9Sstevel@tonic-gate 
2624*7c478bd9Sstevel@tonic-gate found:
2625*7c478bd9Sstevel@tonic-gate 	/*
2626*7c478bd9Sstevel@tonic-gate 	 * If the symbol has type TLS, libproc should have found the symbol
2627*7c478bd9Sstevel@tonic-gate 	 * if it exists and has been allocated.
2628*7c478bd9Sstevel@tonic-gate 	 */
2629*7c478bd9Sstevel@tonic-gate 	if (GELF_ST_TYPE(symp->st_info) == STT_TLS)
2630*7c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_TLS));
2631*7c478bd9Sstevel@tonic-gate 
2632*7c478bd9Sstevel@tonic-gate 	return (0);
2633*7c478bd9Sstevel@tonic-gate }
2634*7c478bd9Sstevel@tonic-gate 
2635*7c478bd9Sstevel@tonic-gate static int
2636*7c478bd9Sstevel@tonic-gate pt_lookup_by_name(mdb_tgt_t *t, const char *object,
2637*7c478bd9Sstevel@tonic-gate     const char *name, GElf_Sym *symp, mdb_syminfo_t *sip)
2638*7c478bd9Sstevel@tonic-gate {
2639*7c478bd9Sstevel@tonic-gate 	return (pt_lookup_by_name_thr(t, object, name, symp, sip, PTL_TID(t)));
2640*7c478bd9Sstevel@tonic-gate }
2641*7c478bd9Sstevel@tonic-gate 
2642*7c478bd9Sstevel@tonic-gate static int
2643*7c478bd9Sstevel@tonic-gate pt_lookup_by_addr(mdb_tgt_t *t, uintptr_t addr, uint_t flags,
2644*7c478bd9Sstevel@tonic-gate     char *buf, size_t nbytes, GElf_Sym *symp, mdb_syminfo_t *sip)
2645*7c478bd9Sstevel@tonic-gate {
2646*7c478bd9Sstevel@tonic-gate 	struct ps_prochandle *P = t->t_pshandle;
2647*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
2648*7c478bd9Sstevel@tonic-gate 
2649*7c478bd9Sstevel@tonic-gate 	rd_plt_info_t rpi = { 0 };
2650*7c478bd9Sstevel@tonic-gate 	const char *pltsym;
2651*7c478bd9Sstevel@tonic-gate 	int match, i;
2652*7c478bd9Sstevel@tonic-gate 
2653*7c478bd9Sstevel@tonic-gate 	mdb_gelf_symtab_t *gsts[3];	/* mdb.m_prsym, .symtab, .dynsym */
2654*7c478bd9Sstevel@tonic-gate 	int gstc = 0;			/* number of valid gsts[] entries */
2655*7c478bd9Sstevel@tonic-gate 
2656*7c478bd9Sstevel@tonic-gate 	mdb_gelf_symtab_t *gst = NULL;	/* set if 'sym' is from a gst */
2657*7c478bd9Sstevel@tonic-gate 	const prmap_t *pmp = NULL;	/* set if 'sym' is from libproc */
2658*7c478bd9Sstevel@tonic-gate 	GElf_Sym sym;			/* best symbol found so far if !exact */
2659*7c478bd9Sstevel@tonic-gate 	prsyminfo_t si;
2660*7c478bd9Sstevel@tonic-gate 
2661*7c478bd9Sstevel@tonic-gate 	/*
2662*7c478bd9Sstevel@tonic-gate 	 * Fill in our array of symbol table pointers with the private symbol
2663*7c478bd9Sstevel@tonic-gate 	 * table, static symbol table, and dynamic symbol table if applicable.
2664*7c478bd9Sstevel@tonic-gate 	 * These are done in order of precedence so that if we match and
2665*7c478bd9Sstevel@tonic-gate 	 * MDB_TGT_SYM_EXACT is set, we need not look any further.
2666*7c478bd9Sstevel@tonic-gate 	 */
2667*7c478bd9Sstevel@tonic-gate 	if (mdb.m_prsym != NULL)
2668*7c478bd9Sstevel@tonic-gate 		gsts[gstc++] = mdb.m_prsym;
2669*7c478bd9Sstevel@tonic-gate 	if (P == NULL && pt->p_symtab != NULL)
2670*7c478bd9Sstevel@tonic-gate 		gsts[gstc++] = pt->p_symtab;
2671*7c478bd9Sstevel@tonic-gate 	if (P == NULL && pt->p_dynsym != NULL)
2672*7c478bd9Sstevel@tonic-gate 		gsts[gstc++] = pt->p_dynsym;
2673*7c478bd9Sstevel@tonic-gate 
2674*7c478bd9Sstevel@tonic-gate 	/*
2675*7c478bd9Sstevel@tonic-gate 	 * Loop through our array attempting to match the address.  If we match
2676*7c478bd9Sstevel@tonic-gate 	 * and we're in exact mode, we're done.  Otherwise save the symbol in
2677*7c478bd9Sstevel@tonic-gate 	 * the local sym variable if it is closer than our previous match.
2678*7c478bd9Sstevel@tonic-gate 	 * We explicitly watch for zero-valued symbols since DevPro insists
2679*7c478bd9Sstevel@tonic-gate 	 * on storing __fsr_init_value's value as the symbol value instead
2680*7c478bd9Sstevel@tonic-gate 	 * of storing it in a constant integer.
2681*7c478bd9Sstevel@tonic-gate 	 */
2682*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < gstc; i++) {
2683*7c478bd9Sstevel@tonic-gate 		if (mdb_gelf_symtab_lookup_by_addr(gsts[i], addr, flags, buf,
2684*7c478bd9Sstevel@tonic-gate 		    nbytes, symp, &sip->sym_id) != 0 || symp->st_value == 0)
2685*7c478bd9Sstevel@tonic-gate 			continue;
2686*7c478bd9Sstevel@tonic-gate 
2687*7c478bd9Sstevel@tonic-gate 		if (flags & MDB_TGT_SYM_EXACT) {
2688*7c478bd9Sstevel@tonic-gate 			gst = gsts[i];
2689*7c478bd9Sstevel@tonic-gate 			goto found;
2690*7c478bd9Sstevel@tonic-gate 		}
2691*7c478bd9Sstevel@tonic-gate 
2692*7c478bd9Sstevel@tonic-gate 		if (gst == NULL || mdb_gelf_sym_closer(symp, &sym, addr)) {
2693*7c478bd9Sstevel@tonic-gate 			gst = gsts[i];
2694*7c478bd9Sstevel@tonic-gate 			sym = *symp;
2695*7c478bd9Sstevel@tonic-gate 		}
2696*7c478bd9Sstevel@tonic-gate 	}
2697*7c478bd9Sstevel@tonic-gate 
2698*7c478bd9Sstevel@tonic-gate 	/*
2699*7c478bd9Sstevel@tonic-gate 	 * If we have no libproc handle active, we're done: fail if gst is
2700*7c478bd9Sstevel@tonic-gate 	 * NULL; otherwise copy out our best symbol and skip to the end.
2701*7c478bd9Sstevel@tonic-gate 	 * We also skip to found if gst is the private symbol table: we
2702*7c478bd9Sstevel@tonic-gate 	 * want this to always take precedence over PLT re-vectoring.
2703*7c478bd9Sstevel@tonic-gate 	 */
2704*7c478bd9Sstevel@tonic-gate 	if (P == NULL || (gst != NULL && gst == mdb.m_prsym)) {
2705*7c478bd9Sstevel@tonic-gate 		if (gst == NULL)
2706*7c478bd9Sstevel@tonic-gate 			return (set_errno(EMDB_NOSYMADDR));
2707*7c478bd9Sstevel@tonic-gate 		*symp = sym;
2708*7c478bd9Sstevel@tonic-gate 		goto found;
2709*7c478bd9Sstevel@tonic-gate 	}
2710*7c478bd9Sstevel@tonic-gate 
2711*7c478bd9Sstevel@tonic-gate 	/*
2712*7c478bd9Sstevel@tonic-gate 	 * Check to see if the address is in a PLT: if it is, use librtld_db to
2713*7c478bd9Sstevel@tonic-gate 	 * attempt to resolve the PLT entry.  If the entry is bound, reset addr
2714*7c478bd9Sstevel@tonic-gate 	 * to the bound address, add a special prefix to the caller's buf,
2715*7c478bd9Sstevel@tonic-gate 	 * forget our previous guess, and then continue using the new addr.
2716*7c478bd9Sstevel@tonic-gate 	 * If the entry is not bound, copy the corresponding symbol name into
2717*7c478bd9Sstevel@tonic-gate 	 * buf and return a fake symbol for the given address.
2718*7c478bd9Sstevel@tonic-gate 	 */
2719*7c478bd9Sstevel@tonic-gate 	if ((pltsym = Ppltdest(P, addr)) != NULL) {
2720*7c478bd9Sstevel@tonic-gate 		const rd_loadobj_t *rlp;
2721*7c478bd9Sstevel@tonic-gate 		rd_agent_t *rap;
2722*7c478bd9Sstevel@tonic-gate 
2723*7c478bd9Sstevel@tonic-gate 		if ((rap = Prd_agent(P)) != NULL &&
2724*7c478bd9Sstevel@tonic-gate 		    (rlp = Paddr_to_loadobj(P, addr)) != NULL &&
2725*7c478bd9Sstevel@tonic-gate 		    rd_plt_resolution(rap, addr, Pstatus(P)->pr_lwp.pr_lwpid,
2726*7c478bd9Sstevel@tonic-gate 		    rlp->rl_plt_base, &rpi) == RD_OK &&
2727*7c478bd9Sstevel@tonic-gate 		    (rpi.pi_flags & RD_FLG_PI_PLTBOUND)) {
2728*7c478bd9Sstevel@tonic-gate 			size_t n;
2729*7c478bd9Sstevel@tonic-gate 			n = mdb_iob_snprintf(buf, nbytes, "PLT=");
2730*7c478bd9Sstevel@tonic-gate 			addr = rpi.pi_baddr;
2731*7c478bd9Sstevel@tonic-gate 			if (n > nbytes) {
2732*7c478bd9Sstevel@tonic-gate 				buf += nbytes;
2733*7c478bd9Sstevel@tonic-gate 				nbytes = 0;
2734*7c478bd9Sstevel@tonic-gate 			} else {
2735*7c478bd9Sstevel@tonic-gate 				buf += n;
2736*7c478bd9Sstevel@tonic-gate 				nbytes -= n;
2737*7c478bd9Sstevel@tonic-gate 			}
2738*7c478bd9Sstevel@tonic-gate 			gst = NULL;
2739*7c478bd9Sstevel@tonic-gate 		} else {
2740*7c478bd9Sstevel@tonic-gate 			(void) mdb_iob_snprintf(buf, nbytes, "PLT:%s", pltsym);
2741*7c478bd9Sstevel@tonic-gate 			bzero(symp, sizeof (GElf_Sym));
2742*7c478bd9Sstevel@tonic-gate 			symp->st_value = addr;
2743*7c478bd9Sstevel@tonic-gate 			symp->st_info = GELF_ST_INFO(STB_GLOBAL, STT_FUNC);
2744*7c478bd9Sstevel@tonic-gate 			return (0);
2745*7c478bd9Sstevel@tonic-gate 		}
2746*7c478bd9Sstevel@tonic-gate 	}
2747*7c478bd9Sstevel@tonic-gate 
2748*7c478bd9Sstevel@tonic-gate 	/*
2749*7c478bd9Sstevel@tonic-gate 	 * Ask libproc to convert the address to the closest symbol for us.
2750*7c478bd9Sstevel@tonic-gate 	 * Once we get the closest symbol, we perform the EXACT match or
2751*7c478bd9Sstevel@tonic-gate 	 * smart-mode or absolute distance check ourself:
2752*7c478bd9Sstevel@tonic-gate 	 */
2753*7c478bd9Sstevel@tonic-gate 	if (Pxlookup_by_addr(P, addr, buf, nbytes, symp, &si) == 0 &&
2754*7c478bd9Sstevel@tonic-gate 	    symp->st_value != 0 && (gst == NULL ||
2755*7c478bd9Sstevel@tonic-gate 	    mdb_gelf_sym_closer(symp, &sym, addr))) {
2756*7c478bd9Sstevel@tonic-gate 
2757*7c478bd9Sstevel@tonic-gate 		if (flags & MDB_TGT_SYM_EXACT)
2758*7c478bd9Sstevel@tonic-gate 			match = (addr == symp->st_value);
2759*7c478bd9Sstevel@tonic-gate 		else if (mdb.m_symdist == 0)
2760*7c478bd9Sstevel@tonic-gate 			match = (addr >= symp->st_value &&
2761*7c478bd9Sstevel@tonic-gate 			    addr < symp->st_value + symp->st_size);
2762*7c478bd9Sstevel@tonic-gate 		else
2763*7c478bd9Sstevel@tonic-gate 			match = (addr >= symp->st_value &&
2764*7c478bd9Sstevel@tonic-gate 			    addr < symp->st_value + mdb.m_symdist);
2765*7c478bd9Sstevel@tonic-gate 
2766*7c478bd9Sstevel@tonic-gate 		if (match) {
2767*7c478bd9Sstevel@tonic-gate 			pmp = Paddr_to_map(P, addr);
2768*7c478bd9Sstevel@tonic-gate 			gst = NULL;
2769*7c478bd9Sstevel@tonic-gate 			sip->sym_table = si.prs_table;
2770*7c478bd9Sstevel@tonic-gate 			sip->sym_id = si.prs_id;
2771*7c478bd9Sstevel@tonic-gate 			goto found;
2772*7c478bd9Sstevel@tonic-gate 		}
2773*7c478bd9Sstevel@tonic-gate 	}
2774*7c478bd9Sstevel@tonic-gate 
2775*7c478bd9Sstevel@tonic-gate 	/*
2776*7c478bd9Sstevel@tonic-gate 	 * If we get here, Plookup_by_addr has failed us.  If we have no
2777*7c478bd9Sstevel@tonic-gate 	 * previous best symbol (gst == NULL), we've failed completely.
2778*7c478bd9Sstevel@tonic-gate 	 * Otherwise we copy out that symbol and continue on to 'found'.
2779*7c478bd9Sstevel@tonic-gate 	 */
2780*7c478bd9Sstevel@tonic-gate 	if (gst == NULL)
2781*7c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_NOSYMADDR));
2782*7c478bd9Sstevel@tonic-gate 	*symp = sym;
2783*7c478bd9Sstevel@tonic-gate found:
2784*7c478bd9Sstevel@tonic-gate 	/*
2785*7c478bd9Sstevel@tonic-gate 	 * Once we've found something, copy the final name into the caller's
2786*7c478bd9Sstevel@tonic-gate 	 * buffer and prefix it with the mapping name if appropriate.
2787*7c478bd9Sstevel@tonic-gate 	 */
2788*7c478bd9Sstevel@tonic-gate 	if (pmp != NULL && pmp != Pname_to_map(P, PR_OBJ_EXEC)) {
2789*7c478bd9Sstevel@tonic-gate 		const char *prefix = pmp->pr_mapname;
2790*7c478bd9Sstevel@tonic-gate 		Lmid_t lmid;
2791*7c478bd9Sstevel@tonic-gate 
2792*7c478bd9Sstevel@tonic-gate 		if (Pobjname(P, addr, pt->p_objname, MDB_TGT_MAPSZ))
2793*7c478bd9Sstevel@tonic-gate 			prefix = pt->p_objname;
2794*7c478bd9Sstevel@tonic-gate 
2795*7c478bd9Sstevel@tonic-gate 		if (buf != NULL && nbytes > 1) {
2796*7c478bd9Sstevel@tonic-gate 			(void) strncpy(pt->p_symname, buf, MDB_TGT_SYM_NAMLEN);
2797*7c478bd9Sstevel@tonic-gate 			pt->p_symname[MDB_TGT_SYM_NAMLEN - 1] = '\0';
2798*7c478bd9Sstevel@tonic-gate 		} else {
2799*7c478bd9Sstevel@tonic-gate 			pt->p_symname[0] = '\0';
2800*7c478bd9Sstevel@tonic-gate 		}
2801*7c478bd9Sstevel@tonic-gate 
2802*7c478bd9Sstevel@tonic-gate 		if (prefix == pt->p_objname && Plmid(P, addr, &lmid) == 0 && (
2803*7c478bd9Sstevel@tonic-gate 		    (lmid != LM_ID_BASE && lmid != LM_ID_LDSO) ||
2804*7c478bd9Sstevel@tonic-gate 		    (mdb.m_flags & MDB_FL_SHOWLMID))) {
2805*7c478bd9Sstevel@tonic-gate 			(void) mdb_iob_snprintf(buf, nbytes, "LM%lr`%s`%s",
2806*7c478bd9Sstevel@tonic-gate 			    lmid, strbasename(prefix), pt->p_symname);
2807*7c478bd9Sstevel@tonic-gate 		} else {
2808*7c478bd9Sstevel@tonic-gate 			(void) mdb_iob_snprintf(buf, nbytes, "%s`%s",
2809*7c478bd9Sstevel@tonic-gate 			    strbasename(prefix), pt->p_symname);
2810*7c478bd9Sstevel@tonic-gate 		}
2811*7c478bd9Sstevel@tonic-gate 
2812*7c478bd9Sstevel@tonic-gate 	} else if (gst != NULL && buf != NULL && nbytes > 0) {
2813*7c478bd9Sstevel@tonic-gate 		(void) strncpy(buf, mdb_gelf_sym_name(gst, symp), nbytes);
2814*7c478bd9Sstevel@tonic-gate 		buf[nbytes - 1] = '\0';
2815*7c478bd9Sstevel@tonic-gate 	}
2816*7c478bd9Sstevel@tonic-gate 
2817*7c478bd9Sstevel@tonic-gate 	return (0);
2818*7c478bd9Sstevel@tonic-gate }
2819*7c478bd9Sstevel@tonic-gate 
2820*7c478bd9Sstevel@tonic-gate 
2821*7c478bd9Sstevel@tonic-gate static int
2822*7c478bd9Sstevel@tonic-gate pt_symbol_iter_cb(void *arg, const GElf_Sym *sym, const char *name,
2823*7c478bd9Sstevel@tonic-gate     const prsyminfo_t *sip)
2824*7c478bd9Sstevel@tonic-gate {
2825*7c478bd9Sstevel@tonic-gate 	pt_symarg_t *psp = arg;
2826*7c478bd9Sstevel@tonic-gate 
2827*7c478bd9Sstevel@tonic-gate 	psp->psym_info.sym_id = sip->prs_id;
2828*7c478bd9Sstevel@tonic-gate 
2829*7c478bd9Sstevel@tonic-gate 	return (psp->psym_func(psp->psym_private, sym, name, &psp->psym_info,
2830*7c478bd9Sstevel@tonic-gate 	    psp->psym_obj));
2831*7c478bd9Sstevel@tonic-gate }
2832*7c478bd9Sstevel@tonic-gate 
2833*7c478bd9Sstevel@tonic-gate static int
2834*7c478bd9Sstevel@tonic-gate pt_objsym_iter(void *arg, const prmap_t *pmp, const char *object)
2835*7c478bd9Sstevel@tonic-gate {
2836*7c478bd9Sstevel@tonic-gate 	Lmid_t lmid = PR_LMID_EVERY;
2837*7c478bd9Sstevel@tonic-gate 	pt_symarg_t *psp = arg;
2838*7c478bd9Sstevel@tonic-gate 
2839*7c478bd9Sstevel@tonic-gate 	psp->psym_obj = object;
2840*7c478bd9Sstevel@tonic-gate 
2841*7c478bd9Sstevel@tonic-gate 	(void) Plmid(psp->psym_targ->t_pshandle, pmp->pr_vaddr, &lmid);
2842*7c478bd9Sstevel@tonic-gate 	(void) Pxsymbol_iter(psp->psym_targ->t_pshandle, lmid, object,
2843*7c478bd9Sstevel@tonic-gate 	    psp->psym_which, psp->psym_type, pt_symbol_iter_cb, arg);
2844*7c478bd9Sstevel@tonic-gate 
2845*7c478bd9Sstevel@tonic-gate 	return (0);
2846*7c478bd9Sstevel@tonic-gate }
2847*7c478bd9Sstevel@tonic-gate 
2848*7c478bd9Sstevel@tonic-gate static int
2849*7c478bd9Sstevel@tonic-gate pt_symbol_filt(void *arg, const GElf_Sym *sym, const char *name, uint_t id)
2850*7c478bd9Sstevel@tonic-gate {
2851*7c478bd9Sstevel@tonic-gate 	pt_symarg_t *psp = arg;
2852*7c478bd9Sstevel@tonic-gate 
2853*7c478bd9Sstevel@tonic-gate 	if (mdb_tgt_sym_match(sym, psp->psym_type)) {
2854*7c478bd9Sstevel@tonic-gate 		psp->psym_info.sym_id = id;
2855*7c478bd9Sstevel@tonic-gate 		return (psp->psym_func(psp->psym_private, sym, name,
2856*7c478bd9Sstevel@tonic-gate 		    &psp->psym_info, psp->psym_obj));
2857*7c478bd9Sstevel@tonic-gate 	}
2858*7c478bd9Sstevel@tonic-gate 
2859*7c478bd9Sstevel@tonic-gate 	return (0);
2860*7c478bd9Sstevel@tonic-gate }
2861*7c478bd9Sstevel@tonic-gate 
2862*7c478bd9Sstevel@tonic-gate static int
2863*7c478bd9Sstevel@tonic-gate pt_symbol_iter(mdb_tgt_t *t, const char *object, uint_t which,
2864*7c478bd9Sstevel@tonic-gate     uint_t type, mdb_tgt_sym_f *func, void *private)
2865*7c478bd9Sstevel@tonic-gate {
2866*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
2867*7c478bd9Sstevel@tonic-gate 	mdb_gelf_symtab_t *gst;
2868*7c478bd9Sstevel@tonic-gate 	pt_symarg_t ps;
2869*7c478bd9Sstevel@tonic-gate 	Lmid_t lmid;
2870*7c478bd9Sstevel@tonic-gate 
2871*7c478bd9Sstevel@tonic-gate 	object = pt_resolve_lmid(object, &lmid);
2872*7c478bd9Sstevel@tonic-gate 
2873*7c478bd9Sstevel@tonic-gate 	ps.psym_targ = t;
2874*7c478bd9Sstevel@tonic-gate 	ps.psym_which = which;
2875*7c478bd9Sstevel@tonic-gate 	ps.psym_type = type;
2876*7c478bd9Sstevel@tonic-gate 	ps.psym_func = func;
2877*7c478bd9Sstevel@tonic-gate 	ps.psym_private = private;
2878*7c478bd9Sstevel@tonic-gate 	ps.psym_obj = object;
2879*7c478bd9Sstevel@tonic-gate 
2880*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle != NULL) {
2881*7c478bd9Sstevel@tonic-gate 		if (object != MDB_TGT_OBJ_EVERY) {
2882*7c478bd9Sstevel@tonic-gate 			if (Plmid_to_map(t->t_pshandle, lmid, object) == NULL)
2883*7c478bd9Sstevel@tonic-gate 				return (set_errno(EMDB_NOOBJ));
2884*7c478bd9Sstevel@tonic-gate 			(void) Pxsymbol_iter(t->t_pshandle, lmid, object,
2885*7c478bd9Sstevel@tonic-gate 			    which, type, pt_symbol_iter_cb, &ps);
2886*7c478bd9Sstevel@tonic-gate 			return (0);
2887*7c478bd9Sstevel@tonic-gate 		} else if (Prd_agent(t->t_pshandle) != NULL) {
2888*7c478bd9Sstevel@tonic-gate 			(void) Pobject_iter(t->t_pshandle, pt_objsym_iter, &ps);
2889*7c478bd9Sstevel@tonic-gate 			return (0);
2890*7c478bd9Sstevel@tonic-gate 		}
2891*7c478bd9Sstevel@tonic-gate 	}
2892*7c478bd9Sstevel@tonic-gate 
2893*7c478bd9Sstevel@tonic-gate 	if (lmid != LM_ID_BASE && lmid != PR_LMID_EVERY)
2894*7c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_NOLMID));
2895*7c478bd9Sstevel@tonic-gate 
2896*7c478bd9Sstevel@tonic-gate 	if (object != MDB_TGT_OBJ_EXEC && object != MDB_TGT_OBJ_EVERY &&
2897*7c478bd9Sstevel@tonic-gate 	    pt->p_fio != NULL &&
2898*7c478bd9Sstevel@tonic-gate 	    strcmp(object, IOP_NAME(pt->p_fio)) != 0)
2899*7c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_NOOBJ));
2900*7c478bd9Sstevel@tonic-gate 
2901*7c478bd9Sstevel@tonic-gate 	if (which == MDB_TGT_SYMTAB)
2902*7c478bd9Sstevel@tonic-gate 		gst = pt->p_symtab;
2903*7c478bd9Sstevel@tonic-gate 	else
2904*7c478bd9Sstevel@tonic-gate 		gst = pt->p_dynsym;
2905*7c478bd9Sstevel@tonic-gate 
2906*7c478bd9Sstevel@tonic-gate 	if (gst != NULL) {
2907*7c478bd9Sstevel@tonic-gate 		ps.psym_info.sym_table = gst->gst_tabid;
2908*7c478bd9Sstevel@tonic-gate 		mdb_gelf_symtab_iter(gst, pt_symbol_filt, &ps);
2909*7c478bd9Sstevel@tonic-gate 	}
2910*7c478bd9Sstevel@tonic-gate 
2911*7c478bd9Sstevel@tonic-gate 	return (0);
2912*7c478bd9Sstevel@tonic-gate }
2913*7c478bd9Sstevel@tonic-gate 
2914*7c478bd9Sstevel@tonic-gate static const mdb_map_t *
2915*7c478bd9Sstevel@tonic-gate pt_prmap_to_mdbmap(mdb_tgt_t *t, const prmap_t *prp, mdb_map_t *mp)
2916*7c478bd9Sstevel@tonic-gate {
2917*7c478bd9Sstevel@tonic-gate 	struct ps_prochandle *P = t->t_pshandle;
2918*7c478bd9Sstevel@tonic-gate 	char name[MAXPATHLEN];
2919*7c478bd9Sstevel@tonic-gate 	Lmid_t lmid;
2920*7c478bd9Sstevel@tonic-gate 
2921*7c478bd9Sstevel@tonic-gate 	if (Pobjname(P, prp->pr_vaddr, name, sizeof (name)) != NULL) {
2922*7c478bd9Sstevel@tonic-gate 		if (Plmid(P, prp->pr_vaddr, &lmid) == 0 && (
2923*7c478bd9Sstevel@tonic-gate 		    (lmid != LM_ID_BASE && lmid != LM_ID_LDSO) ||
2924*7c478bd9Sstevel@tonic-gate 		    (mdb.m_flags & MDB_FL_SHOWLMID))) {
2925*7c478bd9Sstevel@tonic-gate 			(void) mdb_iob_snprintf(mp->map_name, MDB_TGT_MAPSZ,
2926*7c478bd9Sstevel@tonic-gate 			    "LM%lr`%s", lmid, name);
2927*7c478bd9Sstevel@tonic-gate 		} else {
2928*7c478bd9Sstevel@tonic-gate 			(void) strncpy(mp->map_name, name, MDB_TGT_MAPSZ - 1);
2929*7c478bd9Sstevel@tonic-gate 			mp->map_name[MDB_TGT_MAPSZ - 1] = '\0';
2930*7c478bd9Sstevel@tonic-gate 		}
2931*7c478bd9Sstevel@tonic-gate 	} else {
2932*7c478bd9Sstevel@tonic-gate 		(void) strncpy(mp->map_name, prp->pr_mapname,
2933*7c478bd9Sstevel@tonic-gate 		    MDB_TGT_MAPSZ - 1);
2934*7c478bd9Sstevel@tonic-gate 		mp->map_name[MDB_TGT_MAPSZ - 1] = '\0';
2935*7c478bd9Sstevel@tonic-gate 	}
2936*7c478bd9Sstevel@tonic-gate 
2937*7c478bd9Sstevel@tonic-gate 	mp->map_base = prp->pr_vaddr;
2938*7c478bd9Sstevel@tonic-gate 	mp->map_size = prp->pr_size;
2939*7c478bd9Sstevel@tonic-gate 	mp->map_flags = 0;
2940*7c478bd9Sstevel@tonic-gate 
2941*7c478bd9Sstevel@tonic-gate 	if (prp->pr_mflags & MA_READ)
2942*7c478bd9Sstevel@tonic-gate 		mp->map_flags |= MDB_TGT_MAP_R;
2943*7c478bd9Sstevel@tonic-gate 	if (prp->pr_mflags & MA_WRITE)
2944*7c478bd9Sstevel@tonic-gate 		mp->map_flags |= MDB_TGT_MAP_W;
2945*7c478bd9Sstevel@tonic-gate 	if (prp->pr_mflags & MA_EXEC)
2946*7c478bd9Sstevel@tonic-gate 		mp->map_flags |= MDB_TGT_MAP_X;
2947*7c478bd9Sstevel@tonic-gate 
2948*7c478bd9Sstevel@tonic-gate 	if (prp->pr_mflags & MA_SHM)
2949*7c478bd9Sstevel@tonic-gate 		mp->map_flags |= MDB_TGT_MAP_SHMEM;
2950*7c478bd9Sstevel@tonic-gate 	if (prp->pr_mflags & MA_BREAK)
2951*7c478bd9Sstevel@tonic-gate 		mp->map_flags |= MDB_TGT_MAP_HEAP;
2952*7c478bd9Sstevel@tonic-gate 	if (prp->pr_mflags & MA_STACK)
2953*7c478bd9Sstevel@tonic-gate 		mp->map_flags |= MDB_TGT_MAP_STACK;
2954*7c478bd9Sstevel@tonic-gate 	if (prp->pr_mflags & MA_ANON)
2955*7c478bd9Sstevel@tonic-gate 		mp->map_flags |= MDB_TGT_MAP_ANON;
2956*7c478bd9Sstevel@tonic-gate 
2957*7c478bd9Sstevel@tonic-gate 	return (mp);
2958*7c478bd9Sstevel@tonic-gate }
2959*7c478bd9Sstevel@tonic-gate 
2960*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2961*7c478bd9Sstevel@tonic-gate static int
2962*7c478bd9Sstevel@tonic-gate pt_map_apply(void *arg, const prmap_t *prp, const char *name)
2963*7c478bd9Sstevel@tonic-gate {
2964*7c478bd9Sstevel@tonic-gate 	pt_maparg_t *pmp = arg;
2965*7c478bd9Sstevel@tonic-gate 	mdb_map_t map;
2966*7c478bd9Sstevel@tonic-gate 
2967*7c478bd9Sstevel@tonic-gate 	return (pmp->pmap_func(pmp->pmap_private,
2968*7c478bd9Sstevel@tonic-gate 	    pt_prmap_to_mdbmap(pmp->pmap_targ, prp, &map), map.map_name));
2969*7c478bd9Sstevel@tonic-gate }
2970*7c478bd9Sstevel@tonic-gate 
2971*7c478bd9Sstevel@tonic-gate static int
2972*7c478bd9Sstevel@tonic-gate pt_mapping_iter(mdb_tgt_t *t, mdb_tgt_map_f *func, void *private)
2973*7c478bd9Sstevel@tonic-gate {
2974*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle != NULL) {
2975*7c478bd9Sstevel@tonic-gate 		pt_maparg_t pm;
2976*7c478bd9Sstevel@tonic-gate 
2977*7c478bd9Sstevel@tonic-gate 		pm.pmap_targ = t;
2978*7c478bd9Sstevel@tonic-gate 		pm.pmap_func = func;
2979*7c478bd9Sstevel@tonic-gate 		pm.pmap_private = private;
2980*7c478bd9Sstevel@tonic-gate 
2981*7c478bd9Sstevel@tonic-gate 		(void) Pmapping_iter(t->t_pshandle, pt_map_apply, &pm);
2982*7c478bd9Sstevel@tonic-gate 		return (0);
2983*7c478bd9Sstevel@tonic-gate 	}
2984*7c478bd9Sstevel@tonic-gate 
2985*7c478bd9Sstevel@tonic-gate 	return (set_errno(EMDB_NOPROC));
2986*7c478bd9Sstevel@tonic-gate }
2987*7c478bd9Sstevel@tonic-gate 
2988*7c478bd9Sstevel@tonic-gate static int
2989*7c478bd9Sstevel@tonic-gate pt_object_iter(mdb_tgt_t *t, mdb_tgt_map_f *func, void *private)
2990*7c478bd9Sstevel@tonic-gate {
2991*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
2992*7c478bd9Sstevel@tonic-gate 
2993*7c478bd9Sstevel@tonic-gate 	/*
2994*7c478bd9Sstevel@tonic-gate 	 * If we have a libproc handle, we can just call Pobject_iter to
2995*7c478bd9Sstevel@tonic-gate 	 * iterate over its list of load object information.
2996*7c478bd9Sstevel@tonic-gate 	 */
2997*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle != NULL) {
2998*7c478bd9Sstevel@tonic-gate 		pt_maparg_t pm;
2999*7c478bd9Sstevel@tonic-gate 
3000*7c478bd9Sstevel@tonic-gate 		pm.pmap_targ = t;
3001*7c478bd9Sstevel@tonic-gate 		pm.pmap_func = func;
3002*7c478bd9Sstevel@tonic-gate 		pm.pmap_private = private;
3003*7c478bd9Sstevel@tonic-gate 
3004*7c478bd9Sstevel@tonic-gate 		(void) Pobject_iter(t->t_pshandle, pt_map_apply, &pm);
3005*7c478bd9Sstevel@tonic-gate 		return (0);
3006*7c478bd9Sstevel@tonic-gate 	}
3007*7c478bd9Sstevel@tonic-gate 
3008*7c478bd9Sstevel@tonic-gate 	/*
3009*7c478bd9Sstevel@tonic-gate 	 * If we're examining an executable or other ELF file but we have no
3010*7c478bd9Sstevel@tonic-gate 	 * libproc handle, fake up some information based on DT_NEEDED entries.
3011*7c478bd9Sstevel@tonic-gate 	 */
3012*7c478bd9Sstevel@tonic-gate 	if (pt->p_dynsym != NULL && pt->p_file->gf_dyns != NULL &&
3013*7c478bd9Sstevel@tonic-gate 	    pt->p_fio != NULL) {
3014*7c478bd9Sstevel@tonic-gate 		mdb_gelf_sect_t *gsp = pt->p_dynsym->gst_ssect;
3015*7c478bd9Sstevel@tonic-gate 		GElf_Dyn *dynp = pt->p_file->gf_dyns;
3016*7c478bd9Sstevel@tonic-gate 		mdb_map_t *mp = &pt->p_map;
3017*7c478bd9Sstevel@tonic-gate 		const char *s = IOP_NAME(pt->p_fio);
3018*7c478bd9Sstevel@tonic-gate 		size_t i;
3019*7c478bd9Sstevel@tonic-gate 
3020*7c478bd9Sstevel@tonic-gate 		(void) strncpy(mp->map_name, s, MDB_TGT_MAPSZ);
3021*7c478bd9Sstevel@tonic-gate 		mp->map_name[MDB_TGT_MAPSZ - 1] = '\0';
3022*7c478bd9Sstevel@tonic-gate 		mp->map_flags = MDB_TGT_MAP_R | MDB_TGT_MAP_X;
3023*7c478bd9Sstevel@tonic-gate 		mp->map_base = NULL;
3024*7c478bd9Sstevel@tonic-gate 		mp->map_size = 0;
3025*7c478bd9Sstevel@tonic-gate 
3026*7c478bd9Sstevel@tonic-gate 		if (func(private, mp, s) != 0)
3027*7c478bd9Sstevel@tonic-gate 			return (0);
3028*7c478bd9Sstevel@tonic-gate 
3029*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < pt->p_file->gf_ndyns; i++, dynp++) {
3030*7c478bd9Sstevel@tonic-gate 			if (dynp->d_tag == DT_NEEDED) {
3031*7c478bd9Sstevel@tonic-gate 				s = (char *)gsp->gs_data + dynp->d_un.d_val;
3032*7c478bd9Sstevel@tonic-gate 				(void) strncpy(mp->map_name, s, MDB_TGT_MAPSZ);
3033*7c478bd9Sstevel@tonic-gate 				mp->map_name[MDB_TGT_MAPSZ - 1] = '\0';
3034*7c478bd9Sstevel@tonic-gate 				if (func(private, mp, s) != 0)
3035*7c478bd9Sstevel@tonic-gate 					return (0);
3036*7c478bd9Sstevel@tonic-gate 			}
3037*7c478bd9Sstevel@tonic-gate 		}
3038*7c478bd9Sstevel@tonic-gate 
3039*7c478bd9Sstevel@tonic-gate 		return (0);
3040*7c478bd9Sstevel@tonic-gate 	}
3041*7c478bd9Sstevel@tonic-gate 
3042*7c478bd9Sstevel@tonic-gate 	return (set_errno(EMDB_NOPROC));
3043*7c478bd9Sstevel@tonic-gate }
3044*7c478bd9Sstevel@tonic-gate 
3045*7c478bd9Sstevel@tonic-gate static const mdb_map_t *
3046*7c478bd9Sstevel@tonic-gate pt_addr_to_map(mdb_tgt_t *t, uintptr_t addr)
3047*7c478bd9Sstevel@tonic-gate {
3048*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
3049*7c478bd9Sstevel@tonic-gate 	const prmap_t *pmp;
3050*7c478bd9Sstevel@tonic-gate 
3051*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle == NULL) {
3052*7c478bd9Sstevel@tonic-gate 		(void) set_errno(EMDB_NOPROC);
3053*7c478bd9Sstevel@tonic-gate 		return (NULL);
3054*7c478bd9Sstevel@tonic-gate 	}
3055*7c478bd9Sstevel@tonic-gate 
3056*7c478bd9Sstevel@tonic-gate 	if ((pmp = Paddr_to_map(t->t_pshandle, addr)) == NULL) {
3057*7c478bd9Sstevel@tonic-gate 		(void) set_errno(EMDB_NOMAP);
3058*7c478bd9Sstevel@tonic-gate 		return (NULL);
3059*7c478bd9Sstevel@tonic-gate 	}
3060*7c478bd9Sstevel@tonic-gate 
3061*7c478bd9Sstevel@tonic-gate 	return (pt_prmap_to_mdbmap(t, pmp, &pt->p_map));
3062*7c478bd9Sstevel@tonic-gate }
3063*7c478bd9Sstevel@tonic-gate 
3064*7c478bd9Sstevel@tonic-gate static const mdb_map_t *
3065*7c478bd9Sstevel@tonic-gate pt_name_to_map(mdb_tgt_t *t, const char *object)
3066*7c478bd9Sstevel@tonic-gate {
3067*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
3068*7c478bd9Sstevel@tonic-gate 	const prmap_t *pmp;
3069*7c478bd9Sstevel@tonic-gate 	Lmid_t lmid;
3070*7c478bd9Sstevel@tonic-gate 
3071*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle == NULL) {
3072*7c478bd9Sstevel@tonic-gate 		(void) set_errno(EMDB_NOPROC);
3073*7c478bd9Sstevel@tonic-gate 		return (NULL);
3074*7c478bd9Sstevel@tonic-gate 	}
3075*7c478bd9Sstevel@tonic-gate 
3076*7c478bd9Sstevel@tonic-gate 	object = pt_resolve_lmid(object, &lmid);
3077*7c478bd9Sstevel@tonic-gate 
3078*7c478bd9Sstevel@tonic-gate 	if ((pmp = Plmid_to_map(t->t_pshandle, lmid, object)) == NULL) {
3079*7c478bd9Sstevel@tonic-gate 		(void) set_errno(EMDB_NOOBJ);
3080*7c478bd9Sstevel@tonic-gate 		return (NULL);
3081*7c478bd9Sstevel@tonic-gate 	}
3082*7c478bd9Sstevel@tonic-gate 
3083*7c478bd9Sstevel@tonic-gate 	return (pt_prmap_to_mdbmap(t, pmp, &pt->p_map));
3084*7c478bd9Sstevel@tonic-gate }
3085*7c478bd9Sstevel@tonic-gate 
3086*7c478bd9Sstevel@tonic-gate static ctf_file_t *
3087*7c478bd9Sstevel@tonic-gate pt_addr_to_ctf(mdb_tgt_t *t, uintptr_t addr)
3088*7c478bd9Sstevel@tonic-gate {
3089*7c478bd9Sstevel@tonic-gate 	ctf_file_t *ret;
3090*7c478bd9Sstevel@tonic-gate 
3091*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle == NULL) {
3092*7c478bd9Sstevel@tonic-gate 		(void) set_errno(EMDB_NOPROC);
3093*7c478bd9Sstevel@tonic-gate 		return (NULL);
3094*7c478bd9Sstevel@tonic-gate 	}
3095*7c478bd9Sstevel@tonic-gate 
3096*7c478bd9Sstevel@tonic-gate 	if ((ret = Paddr_to_ctf(t->t_pshandle, addr)) == NULL) {
3097*7c478bd9Sstevel@tonic-gate 		(void) set_errno(EMDB_NOOBJ);
3098*7c478bd9Sstevel@tonic-gate 		return (NULL);
3099*7c478bd9Sstevel@tonic-gate 	}
3100*7c478bd9Sstevel@tonic-gate 
3101*7c478bd9Sstevel@tonic-gate 	return (ret);
3102*7c478bd9Sstevel@tonic-gate }
3103*7c478bd9Sstevel@tonic-gate 
3104*7c478bd9Sstevel@tonic-gate static ctf_file_t *
3105*7c478bd9Sstevel@tonic-gate pt_name_to_ctf(mdb_tgt_t *t, const char *name)
3106*7c478bd9Sstevel@tonic-gate {
3107*7c478bd9Sstevel@tonic-gate 	ctf_file_t *ret;
3108*7c478bd9Sstevel@tonic-gate 
3109*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle == NULL) {
3110*7c478bd9Sstevel@tonic-gate 		(void) set_errno(EMDB_NOPROC);
3111*7c478bd9Sstevel@tonic-gate 		return (NULL);
3112*7c478bd9Sstevel@tonic-gate 	}
3113*7c478bd9Sstevel@tonic-gate 
3114*7c478bd9Sstevel@tonic-gate 	if ((ret = Pname_to_ctf(t->t_pshandle, name)) == NULL) {
3115*7c478bd9Sstevel@tonic-gate 		(void) set_errno(EMDB_NOOBJ);
3116*7c478bd9Sstevel@tonic-gate 		return (NULL);
3117*7c478bd9Sstevel@tonic-gate 	}
3118*7c478bd9Sstevel@tonic-gate 
3119*7c478bd9Sstevel@tonic-gate 	return (ret);
3120*7c478bd9Sstevel@tonic-gate }
3121*7c478bd9Sstevel@tonic-gate 
3122*7c478bd9Sstevel@tonic-gate static int
3123*7c478bd9Sstevel@tonic-gate pt_status(mdb_tgt_t *t, mdb_tgt_status_t *tsp)
3124*7c478bd9Sstevel@tonic-gate {
3125*7c478bd9Sstevel@tonic-gate 	const pstatus_t *psp;
3126*7c478bd9Sstevel@tonic-gate 	prgregset_t gregs;
3127*7c478bd9Sstevel@tonic-gate 	int state;
3128*7c478bd9Sstevel@tonic-gate 
3129*7c478bd9Sstevel@tonic-gate 	bzero(tsp, sizeof (mdb_tgt_status_t));
3130*7c478bd9Sstevel@tonic-gate 
3131*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle == NULL) {
3132*7c478bd9Sstevel@tonic-gate 		tsp->st_state = MDB_TGT_IDLE;
3133*7c478bd9Sstevel@tonic-gate 		return (0);
3134*7c478bd9Sstevel@tonic-gate 	}
3135*7c478bd9Sstevel@tonic-gate 
3136*7c478bd9Sstevel@tonic-gate 	switch (state = Pstate(t->t_pshandle)) {
3137*7c478bd9Sstevel@tonic-gate 	case PS_RUN:
3138*7c478bd9Sstevel@tonic-gate 		tsp->st_state = MDB_TGT_RUNNING;
3139*7c478bd9Sstevel@tonic-gate 		break;
3140*7c478bd9Sstevel@tonic-gate 
3141*7c478bd9Sstevel@tonic-gate 	case PS_STOP:
3142*7c478bd9Sstevel@tonic-gate 		tsp->st_state = MDB_TGT_STOPPED;
3143*7c478bd9Sstevel@tonic-gate 		psp = Pstatus(t->t_pshandle);
3144*7c478bd9Sstevel@tonic-gate 
3145*7c478bd9Sstevel@tonic-gate 		tsp->st_tid = PTL_TID(t);
3146*7c478bd9Sstevel@tonic-gate 		if (PTL_GETREGS(t, tsp->st_tid, gregs) == 0)
3147*7c478bd9Sstevel@tonic-gate 			tsp->st_pc = gregs[R_PC];
3148*7c478bd9Sstevel@tonic-gate 
3149*7c478bd9Sstevel@tonic-gate 		if (psp->pr_flags & PR_ISTOP)
3150*7c478bd9Sstevel@tonic-gate 			tsp->st_flags |= MDB_TGT_ISTOP;
3151*7c478bd9Sstevel@tonic-gate 		if (psp->pr_flags & PR_DSTOP)
3152*7c478bd9Sstevel@tonic-gate 			tsp->st_flags |= MDB_TGT_DSTOP;
3153*7c478bd9Sstevel@tonic-gate 
3154*7c478bd9Sstevel@tonic-gate 		break;
3155*7c478bd9Sstevel@tonic-gate 
3156*7c478bd9Sstevel@tonic-gate 	case PS_LOST:
3157*7c478bd9Sstevel@tonic-gate 		tsp->st_state = MDB_TGT_LOST;
3158*7c478bd9Sstevel@tonic-gate 		break;
3159*7c478bd9Sstevel@tonic-gate 	case PS_UNDEAD:
3160*7c478bd9Sstevel@tonic-gate 		tsp->st_state = MDB_TGT_UNDEAD;
3161*7c478bd9Sstevel@tonic-gate 		break;
3162*7c478bd9Sstevel@tonic-gate 	case PS_DEAD:
3163*7c478bd9Sstevel@tonic-gate 		tsp->st_state = MDB_TGT_DEAD;
3164*7c478bd9Sstevel@tonic-gate 		break;
3165*7c478bd9Sstevel@tonic-gate 	case PS_IDLE:
3166*7c478bd9Sstevel@tonic-gate 		tsp->st_state = MDB_TGT_IDLE;
3167*7c478bd9Sstevel@tonic-gate 		break;
3168*7c478bd9Sstevel@tonic-gate 	default:
3169*7c478bd9Sstevel@tonic-gate 		fail("unknown libproc state (%d)\n", state);
3170*7c478bd9Sstevel@tonic-gate 	}
3171*7c478bd9Sstevel@tonic-gate 
3172*7c478bd9Sstevel@tonic-gate 	if (t->t_flags & MDB_TGT_F_BUSY)
3173*7c478bd9Sstevel@tonic-gate 		tsp->st_flags |= MDB_TGT_BUSY;
3174*7c478bd9Sstevel@tonic-gate 
3175*7c478bd9Sstevel@tonic-gate 	return (0);
3176*7c478bd9Sstevel@tonic-gate }
3177*7c478bd9Sstevel@tonic-gate 
3178*7c478bd9Sstevel@tonic-gate static void
3179*7c478bd9Sstevel@tonic-gate pt_dupfd(const char *file, int oflags, mode_t mode, int dfd)
3180*7c478bd9Sstevel@tonic-gate {
3181*7c478bd9Sstevel@tonic-gate 	int fd;
3182*7c478bd9Sstevel@tonic-gate 
3183*7c478bd9Sstevel@tonic-gate 	if ((fd = open(file, oflags, mode)) >= 0) {
3184*7c478bd9Sstevel@tonic-gate 		(void) fcntl(fd, F_DUP2FD, dfd);
3185*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
3186*7c478bd9Sstevel@tonic-gate 	} else
3187*7c478bd9Sstevel@tonic-gate 		warn("failed to open %s as descriptor %d", file, dfd);
3188*7c478bd9Sstevel@tonic-gate }
3189*7c478bd9Sstevel@tonic-gate 
3190*7c478bd9Sstevel@tonic-gate /*
3191*7c478bd9Sstevel@tonic-gate  * The Pcreate_callback() function interposes on the default, empty libproc
3192*7c478bd9Sstevel@tonic-gate  * definition.  It will be called following a fork of a new child process by
3193*7c478bd9Sstevel@tonic-gate  * Pcreate() below, but before the exec of the new process image.  We use this
3194*7c478bd9Sstevel@tonic-gate  * callback to optionally redirect stdin and stdout and reset the dispositions
3195*7c478bd9Sstevel@tonic-gate  * of SIGPIPE and SIGQUIT from SIG_IGN back to SIG_DFL.
3196*7c478bd9Sstevel@tonic-gate  */
3197*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3198*7c478bd9Sstevel@tonic-gate void
3199*7c478bd9Sstevel@tonic-gate Pcreate_callback(struct ps_prochandle *P)
3200*7c478bd9Sstevel@tonic-gate {
3201*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = mdb.m_target->t_data;
3202*7c478bd9Sstevel@tonic-gate 
3203*7c478bd9Sstevel@tonic-gate 	if (pt->p_stdin != NULL)
3204*7c478bd9Sstevel@tonic-gate 		pt_dupfd(pt->p_stdin, O_RDWR, 0, STDIN_FILENO);
3205*7c478bd9Sstevel@tonic-gate 	if (pt->p_stdout != NULL)
3206*7c478bd9Sstevel@tonic-gate 		pt_dupfd(pt->p_stdout, O_CREAT | O_WRONLY, 0666, STDOUT_FILENO);
3207*7c478bd9Sstevel@tonic-gate 
3208*7c478bd9Sstevel@tonic-gate 	(void) mdb_signal_sethandler(SIGPIPE, SIG_DFL, NULL);
3209*7c478bd9Sstevel@tonic-gate 	(void) mdb_signal_sethandler(SIGQUIT, SIG_DFL, NULL);
3210*7c478bd9Sstevel@tonic-gate }
3211*7c478bd9Sstevel@tonic-gate 
3212*7c478bd9Sstevel@tonic-gate static int
3213*7c478bd9Sstevel@tonic-gate pt_run(mdb_tgt_t *t, int argc, const mdb_arg_t *argv)
3214*7c478bd9Sstevel@tonic-gate {
3215*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
3216*7c478bd9Sstevel@tonic-gate 	struct ps_prochandle *P;
3217*7c478bd9Sstevel@tonic-gate 	char execname[MAXPATHLEN];
3218*7c478bd9Sstevel@tonic-gate 	const char **pargv;
3219*7c478bd9Sstevel@tonic-gate 	int pargc = 0;
3220*7c478bd9Sstevel@tonic-gate 	int i, perr;
3221*7c478bd9Sstevel@tonic-gate 	char **penv;
3222*7c478bd9Sstevel@tonic-gate 	mdb_var_t *v;
3223*7c478bd9Sstevel@tonic-gate 
3224*7c478bd9Sstevel@tonic-gate 	if (pt->p_aout_fio == NULL) {
3225*7c478bd9Sstevel@tonic-gate 		warn("run requires executable to be specified on "
3226*7c478bd9Sstevel@tonic-gate 		    "command-line\n");
3227*7c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_TGT));
3228*7c478bd9Sstevel@tonic-gate 	}
3229*7c478bd9Sstevel@tonic-gate 
3230*7c478bd9Sstevel@tonic-gate 	pargv = mdb_alloc(sizeof (char *) * (argc + 2), UM_SLEEP);
3231*7c478bd9Sstevel@tonic-gate 	pargv[pargc++] = strbasename(IOP_NAME(pt->p_aout_fio));
3232*7c478bd9Sstevel@tonic-gate 
3233*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < argc; i++) {
3234*7c478bd9Sstevel@tonic-gate 		if (argv[i].a_type != MDB_TYPE_STRING) {
3235*7c478bd9Sstevel@tonic-gate 			mdb_free(pargv, sizeof (char *) * (argc + 2));
3236*7c478bd9Sstevel@tonic-gate 			return (set_errno(EINVAL));
3237*7c478bd9Sstevel@tonic-gate 		}
3238*7c478bd9Sstevel@tonic-gate 		if (argv[i].a_un.a_str[0] == '<')
3239*7c478bd9Sstevel@tonic-gate 			pt->p_stdin = argv[i].a_un.a_str + 1;
3240*7c478bd9Sstevel@tonic-gate 		else if (argv[i].a_un.a_str[0] == '>')
3241*7c478bd9Sstevel@tonic-gate 			pt->p_stdout = argv[i].a_un.a_str + 1;
3242*7c478bd9Sstevel@tonic-gate 		else
3243*7c478bd9Sstevel@tonic-gate 			pargv[pargc++] = argv[i].a_un.a_str;
3244*7c478bd9Sstevel@tonic-gate 	}
3245*7c478bd9Sstevel@tonic-gate 	pargv[pargc] = NULL;
3246*7c478bd9Sstevel@tonic-gate 
3247*7c478bd9Sstevel@tonic-gate 	/*
3248*7c478bd9Sstevel@tonic-gate 	 * Since Pcreate() uses execvp() and "." may not be present in $PATH,
3249*7c478bd9Sstevel@tonic-gate 	 * we must manually prepend "./" when the executable is a simple name.
3250*7c478bd9Sstevel@tonic-gate 	 */
3251*7c478bd9Sstevel@tonic-gate 	if (strchr(IOP_NAME(pt->p_aout_fio), '/') == NULL) {
3252*7c478bd9Sstevel@tonic-gate 		(void) snprintf(execname, sizeof (execname), "./%s",
3253*7c478bd9Sstevel@tonic-gate 		    IOP_NAME(pt->p_aout_fio));
3254*7c478bd9Sstevel@tonic-gate 	} else {
3255*7c478bd9Sstevel@tonic-gate 		(void) snprintf(execname, sizeof (execname), "%s",
3256*7c478bd9Sstevel@tonic-gate 		    IOP_NAME(pt->p_aout_fio));
3257*7c478bd9Sstevel@tonic-gate 	}
3258*7c478bd9Sstevel@tonic-gate 
3259*7c478bd9Sstevel@tonic-gate 	penv = mdb_alloc((mdb_nv_size(&pt->p_env)+ 1) * sizeof (char *),
3260*7c478bd9Sstevel@tonic-gate 	    UM_SLEEP);
3261*7c478bd9Sstevel@tonic-gate 	for (mdb_nv_rewind(&pt->p_env), i = 0;
3262*7c478bd9Sstevel@tonic-gate 	    (v = mdb_nv_advance(&pt->p_env)) != NULL; i++)
3263*7c478bd9Sstevel@tonic-gate 		penv[i] = mdb_nv_get_cookie(v);
3264*7c478bd9Sstevel@tonic-gate 	penv[i] = NULL;
3265*7c478bd9Sstevel@tonic-gate 
3266*7c478bd9Sstevel@tonic-gate 	P = Pxcreate(execname, (char **)pargv, penv, &perr, NULL, 0);
3267*7c478bd9Sstevel@tonic-gate 	mdb_free(pargv, sizeof (char *) * (argc + 2));
3268*7c478bd9Sstevel@tonic-gate 	pt->p_stdin = pt->p_stdout = NULL;
3269*7c478bd9Sstevel@tonic-gate 
3270*7c478bd9Sstevel@tonic-gate 	mdb_free(penv, i * sizeof (char *));
3271*7c478bd9Sstevel@tonic-gate 
3272*7c478bd9Sstevel@tonic-gate 	if (P == NULL) {
3273*7c478bd9Sstevel@tonic-gate 		warn("failed to create process: %s\n", Pcreate_error(perr));
3274*7c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_TGT));
3275*7c478bd9Sstevel@tonic-gate 	}
3276*7c478bd9Sstevel@tonic-gate 
3277*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle != NULL) {
3278*7c478bd9Sstevel@tonic-gate 		pt_pre_detach(t, TRUE);
3279*7c478bd9Sstevel@tonic-gate 		if (t->t_pshandle != pt->p_idlehandle)
3280*7c478bd9Sstevel@tonic-gate 			Prelease(t->t_pshandle, pt->p_rflags);
3281*7c478bd9Sstevel@tonic-gate 	}
3282*7c478bd9Sstevel@tonic-gate 
3283*7c478bd9Sstevel@tonic-gate 	(void) Punsetflags(P, PR_RLC);	/* make sure run-on-last-close is off */
3284*7c478bd9Sstevel@tonic-gate 	(void) Psetflags(P, PR_KLC);	/* kill on last close by debugger */
3285*7c478bd9Sstevel@tonic-gate 	pt->p_rflags = PRELEASE_KILL;	/* kill on debugger Prelease */
3286*7c478bd9Sstevel@tonic-gate 	t->t_pshandle = P;
3287*7c478bd9Sstevel@tonic-gate 
3288*7c478bd9Sstevel@tonic-gate 	pt_post_attach(t);
3289*7c478bd9Sstevel@tonic-gate 	pt_activate_common(t);
3290*7c478bd9Sstevel@tonic-gate 	(void) mdb_tgt_status(t, &t->t_status);
3291*7c478bd9Sstevel@tonic-gate 	mdb.m_flags |= MDB_FL_VCREATE;
3292*7c478bd9Sstevel@tonic-gate 
3293*7c478bd9Sstevel@tonic-gate 	return (0);
3294*7c478bd9Sstevel@tonic-gate }
3295*7c478bd9Sstevel@tonic-gate 
3296*7c478bd9Sstevel@tonic-gate /*
3297*7c478bd9Sstevel@tonic-gate  * Forward a signal to the victim process in order to force it to stop or die.
3298*7c478bd9Sstevel@tonic-gate  * Refer to the comments above pt_setrun(), below, for more info.
3299*7c478bd9Sstevel@tonic-gate  */
3300*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3301*7c478bd9Sstevel@tonic-gate static void
3302*7c478bd9Sstevel@tonic-gate pt_sigfwd(int sig, siginfo_t *sip, ucontext_t *ucp, mdb_tgt_t *t)
3303*7c478bd9Sstevel@tonic-gate {
3304*7c478bd9Sstevel@tonic-gate 	struct ps_prochandle *P = t->t_pshandle;
3305*7c478bd9Sstevel@tonic-gate 	const lwpstatus_t *psp = &Pstatus(P)->pr_lwp;
3306*7c478bd9Sstevel@tonic-gate 	pid_t pid = Pstatus(P)->pr_pid;
3307*7c478bd9Sstevel@tonic-gate 	long ctl[2];
3308*7c478bd9Sstevel@tonic-gate 
3309*7c478bd9Sstevel@tonic-gate 	if (getpgid(pid) != mdb.m_pgid) {
3310*7c478bd9Sstevel@tonic-gate 		mdb_dprintf(MDB_DBG_TGT, "fwd SIG#%d to %d\n", sig, (int)pid);
3311*7c478bd9Sstevel@tonic-gate 		(void) kill(pid, sig);
3312*7c478bd9Sstevel@tonic-gate 	}
3313*7c478bd9Sstevel@tonic-gate 
3314*7c478bd9Sstevel@tonic-gate 	if (Pwait(P, 1) == 0 && (psp->pr_flags & PR_STOPPED) &&
3315*7c478bd9Sstevel@tonic-gate 	    psp->pr_why == PR_JOBCONTROL && Pdstop(P) == 0) {
3316*7c478bd9Sstevel@tonic-gate 		/*
3317*7c478bd9Sstevel@tonic-gate 		 * If we're job control stopped and our DSTOP is pending, the
3318*7c478bd9Sstevel@tonic-gate 		 * victim will never see our signal, so undo the kill() and
3319*7c478bd9Sstevel@tonic-gate 		 * then send SIGCONT the victim to kick it out of the job
3320*7c478bd9Sstevel@tonic-gate 		 * control stop and force our DSTOP to take effect.
3321*7c478bd9Sstevel@tonic-gate 		 */
3322*7c478bd9Sstevel@tonic-gate 		if ((psp->pr_flags & PR_DSTOP) &&
3323*7c478bd9Sstevel@tonic-gate 		    prismember(&Pstatus(P)->pr_sigpend, sig)) {
3324*7c478bd9Sstevel@tonic-gate 			ctl[0] = PCUNKILL;
3325*7c478bd9Sstevel@tonic-gate 			ctl[1] = sig;
3326*7c478bd9Sstevel@tonic-gate 			(void) write(Pctlfd(P), ctl, sizeof (ctl));
3327*7c478bd9Sstevel@tonic-gate 		}
3328*7c478bd9Sstevel@tonic-gate 
3329*7c478bd9Sstevel@tonic-gate 		mdb_dprintf(MDB_DBG_TGT, "fwd SIGCONT to %d\n", (int)pid);
3330*7c478bd9Sstevel@tonic-gate 		(void) kill(pid, SIGCONT);
3331*7c478bd9Sstevel@tonic-gate 	}
3332*7c478bd9Sstevel@tonic-gate }
3333*7c478bd9Sstevel@tonic-gate 
3334*7c478bd9Sstevel@tonic-gate /*
3335*7c478bd9Sstevel@tonic-gate  * Common code for step and continue: if no victim process has been created,
3336*7c478bd9Sstevel@tonic-gate  * call pt_run() to create one.  Then set the victim running, clearing any
3337*7c478bd9Sstevel@tonic-gate  * pending fault.  One special case is that if the victim was previously
3338*7c478bd9Sstevel@tonic-gate  * stopped on reception of SIGINT, we know that SIGINT was traced and the user
3339*7c478bd9Sstevel@tonic-gate  * requested the victim to stop, so clear this signal before continuing.
3340*7c478bd9Sstevel@tonic-gate  * For all other traced signals, the signal will be delivered on continue.
3341*7c478bd9Sstevel@tonic-gate  *
3342*7c478bd9Sstevel@tonic-gate  * Once the victim process is running, we wait for it to stop on an event of
3343*7c478bd9Sstevel@tonic-gate  * interest.  Although libproc provides the basic primitive to wait for the
3344*7c478bd9Sstevel@tonic-gate  * victim, we must be careful in our handling of signals.  We want to allow the
3345*7c478bd9Sstevel@tonic-gate  * user to issue a SIGINT or SIGQUIT using the designated terminal control
3346*7c478bd9Sstevel@tonic-gate  * character (typically ^C and ^\), and have these signals stop the target and
3347*7c478bd9Sstevel@tonic-gate  * return control to the debugger if the signals are traced.  There are three
3348*7c478bd9Sstevel@tonic-gate  * cases to be considered in our implementation:
3349*7c478bd9Sstevel@tonic-gate  *
3350*7c478bd9Sstevel@tonic-gate  * (1) If the debugger and victim are in the same process group, both receive
3351*7c478bd9Sstevel@tonic-gate  * the signal from the terminal driver.  The debugger returns from Pwait() with
3352*7c478bd9Sstevel@tonic-gate  * errno = EINTR, so we want to loop back and continue waiting until the victim
3353*7c478bd9Sstevel@tonic-gate  * stops on receipt of its SIGINT or SIGQUIT.
3354*7c478bd9Sstevel@tonic-gate  *
3355*7c478bd9Sstevel@tonic-gate  * (2) If the debugger and victim are in different process groups, and the
3356*7c478bd9Sstevel@tonic-gate  * victim is a member of the foreground process group, it will receive the
3357*7c478bd9Sstevel@tonic-gate  * signal from the terminal driver and the debugger will not.  As such, we
3358*7c478bd9Sstevel@tonic-gate  * will remain blocked in Pwait() until the victim stops on its signal.
3359*7c478bd9Sstevel@tonic-gate  *
3360*7c478bd9Sstevel@tonic-gate  * (3) If the debugger and victim are in different process groups, and the
3361*7c478bd9Sstevel@tonic-gate  * debugger is a member of the foreground process group, it will receive the
3362*7c478bd9Sstevel@tonic-gate  * signal from the terminal driver, and the victim will not.  The debugger
3363*7c478bd9Sstevel@tonic-gate  * returns from Pwait() with errno = EINTR, so we need to forward the signal
3364*7c478bd9Sstevel@tonic-gate  * to the victim process directly and then Pwait() again for it to stop.
3365*7c478bd9Sstevel@tonic-gate  *
3366*7c478bd9Sstevel@tonic-gate  * We can observe that all three cases are handled by simply calling Pwait()
3367*7c478bd9Sstevel@tonic-gate  * repeatedly if it fails with EINTR, and forwarding SIGINT and SIGQUIT to
3368*7c478bd9Sstevel@tonic-gate  * the victim if it is in a different process group, using pt_sigfwd() above.
3369*7c478bd9Sstevel@tonic-gate  *
3370*7c478bd9Sstevel@tonic-gate  * An additional complication is that the process may not be able to field
3371*7c478bd9Sstevel@tonic-gate  * the signal if it is currently stopped by job control.  In this case, we
3372*7c478bd9Sstevel@tonic-gate  * also DSTOP the process, and then send it a SIGCONT to wake it up from
3373*7c478bd9Sstevel@tonic-gate  * job control and force it to re-enter stop() under the control of /proc.
3374*7c478bd9Sstevel@tonic-gate  *
3375*7c478bd9Sstevel@tonic-gate  * Finally, we would like to allow the user to suspend the process using the
3376*7c478bd9Sstevel@tonic-gate  * terminal suspend character (typically ^Z) if both are in the same session.
3377*7c478bd9Sstevel@tonic-gate  * We again employ pt_sigfwd() to forward SIGTSTP to the victim, wait for it to
3378*7c478bd9Sstevel@tonic-gate  * stop from job control, and then capture it using /proc.  Once the process
3379*7c478bd9Sstevel@tonic-gate  * has stopped, normal SIGTSTP processing is restored and the user can issue
3380*7c478bd9Sstevel@tonic-gate  * another ^Z in order to suspend the debugger and return to the parent shell.
3381*7c478bd9Sstevel@tonic-gate  */
3382*7c478bd9Sstevel@tonic-gate static int
3383*7c478bd9Sstevel@tonic-gate pt_setrun(mdb_tgt_t *t, mdb_tgt_status_t *tsp, int flags)
3384*7c478bd9Sstevel@tonic-gate {
3385*7c478bd9Sstevel@tonic-gate 	struct ps_prochandle *P = t->t_pshandle;
3386*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
3387*7c478bd9Sstevel@tonic-gate 	pid_t old_pgid = -1;
3388*7c478bd9Sstevel@tonic-gate 
3389*7c478bd9Sstevel@tonic-gate 	mdb_signal_f *intf, *quitf, *tstpf;
3390*7c478bd9Sstevel@tonic-gate 	const lwpstatus_t *psp;
3391*7c478bd9Sstevel@tonic-gate 	void *intd, *quitd, *tstpd;
3392*7c478bd9Sstevel@tonic-gate 
3393*7c478bd9Sstevel@tonic-gate 	int sig = pt->p_signal;
3394*7c478bd9Sstevel@tonic-gate 	int error = 0;
3395*7c478bd9Sstevel@tonic-gate 	int pgid = -1;
3396*7c478bd9Sstevel@tonic-gate 
3397*7c478bd9Sstevel@tonic-gate 	pt->p_signal = 0; /* clear pending signal */
3398*7c478bd9Sstevel@tonic-gate 
3399*7c478bd9Sstevel@tonic-gate 	if (P == NULL && pt_run(t, 0, NULL) == -1)
3400*7c478bd9Sstevel@tonic-gate 		return (-1); /* errno is set for us */
3401*7c478bd9Sstevel@tonic-gate 
3402*7c478bd9Sstevel@tonic-gate 	P = t->t_pshandle;
3403*7c478bd9Sstevel@tonic-gate 	psp = &Pstatus(P)->pr_lwp;
3404*7c478bd9Sstevel@tonic-gate 
3405*7c478bd9Sstevel@tonic-gate 	if (sig == 0 && psp->pr_why == PR_SIGNALLED && psp->pr_what == SIGINT)
3406*7c478bd9Sstevel@tonic-gate 		flags |= PRCSIG; /* clear pending SIGINT */
3407*7c478bd9Sstevel@tonic-gate 	else
3408*7c478bd9Sstevel@tonic-gate 		flags |= PRCFAULT; /* clear any pending fault (e.g. BPT) */
3409*7c478bd9Sstevel@tonic-gate 
3410*7c478bd9Sstevel@tonic-gate 	intf = mdb_signal_gethandler(SIGINT, &intd);
3411*7c478bd9Sstevel@tonic-gate 	quitf = mdb_signal_gethandler(SIGQUIT, &quitd);
3412*7c478bd9Sstevel@tonic-gate 	tstpf = mdb_signal_gethandler(SIGTSTP, &tstpd);
3413*7c478bd9Sstevel@tonic-gate 
3414*7c478bd9Sstevel@tonic-gate 	(void) mdb_signal_sethandler(SIGINT, (mdb_signal_f *)pt_sigfwd, t);
3415*7c478bd9Sstevel@tonic-gate 	(void) mdb_signal_sethandler(SIGQUIT, (mdb_signal_f *)pt_sigfwd, t);
3416*7c478bd9Sstevel@tonic-gate 	(void) mdb_signal_sethandler(SIGTSTP, (mdb_signal_f *)pt_sigfwd, t);
3417*7c478bd9Sstevel@tonic-gate 
3418*7c478bd9Sstevel@tonic-gate 	if (sig != 0 && Pstate(P) == PS_RUN &&
3419*7c478bd9Sstevel@tonic-gate 	    kill(Pstatus(P)->pr_pid, sig) == -1) {
3420*7c478bd9Sstevel@tonic-gate 		error = errno;
3421*7c478bd9Sstevel@tonic-gate 		goto out;
3422*7c478bd9Sstevel@tonic-gate 	}
3423*7c478bd9Sstevel@tonic-gate 
3424*7c478bd9Sstevel@tonic-gate 	/*
3425*7c478bd9Sstevel@tonic-gate 	 * If we attached to a job stopped background process in the same
3426*7c478bd9Sstevel@tonic-gate 	 * session, make its pgid the foreground process group before running
3427*7c478bd9Sstevel@tonic-gate 	 * it.  Ignore SIGTTOU while doing this to avoid being suspended.
3428*7c478bd9Sstevel@tonic-gate 	 */
3429*7c478bd9Sstevel@tonic-gate 	if (mdb.m_flags & MDB_FL_JOBCTL) {
3430*7c478bd9Sstevel@tonic-gate 		(void) mdb_signal_sethandler(SIGTTOU, SIG_IGN, NULL);
3431*7c478bd9Sstevel@tonic-gate 		(void) IOP_CTL(mdb.m_term, TIOCGPGRP, &old_pgid);
3432*7c478bd9Sstevel@tonic-gate 		(void) IOP_CTL(mdb.m_term, TIOCSPGRP,
3433*7c478bd9Sstevel@tonic-gate 		    (void *)&Pstatus(P)->pr_pgid);
3434*7c478bd9Sstevel@tonic-gate 		(void) mdb_signal_sethandler(SIGTTOU, SIG_DFL, NULL);
3435*7c478bd9Sstevel@tonic-gate 	}
3436*7c478bd9Sstevel@tonic-gate 
3437*7c478bd9Sstevel@tonic-gate 	if (Pstate(P) != PS_RUN && Psetrun(P, sig, flags) == -1) {
3438*7c478bd9Sstevel@tonic-gate 		error = errno;
3439*7c478bd9Sstevel@tonic-gate 		goto out;
3440*7c478bd9Sstevel@tonic-gate 	}
3441*7c478bd9Sstevel@tonic-gate 
3442*7c478bd9Sstevel@tonic-gate 	/*
3443*7c478bd9Sstevel@tonic-gate 	 * If the process is stopped on job control, resume its process group
3444*7c478bd9Sstevel@tonic-gate 	 * by sending it a SIGCONT if we are in the same session.  Otherwise
3445*7c478bd9Sstevel@tonic-gate 	 * we have no choice but to wait for someone else to foreground it.
3446*7c478bd9Sstevel@tonic-gate 	 */
3447*7c478bd9Sstevel@tonic-gate 	if (psp->pr_why == PR_JOBCONTROL) {
3448*7c478bd9Sstevel@tonic-gate 		if (mdb.m_flags & MDB_FL_JOBCTL)
3449*7c478bd9Sstevel@tonic-gate 			(void) kill(-Pstatus(P)->pr_pgid, SIGCONT);
3450*7c478bd9Sstevel@tonic-gate 		else if (mdb.m_term != NULL)
3451*7c478bd9Sstevel@tonic-gate 			warn("process is still suspended by job control ...\n");
3452*7c478bd9Sstevel@tonic-gate 	}
3453*7c478bd9Sstevel@tonic-gate 
3454*7c478bd9Sstevel@tonic-gate 	/*
3455*7c478bd9Sstevel@tonic-gate 	 * Wait for the process to stop.  As described above, we loop around if
3456*7c478bd9Sstevel@tonic-gate 	 * we are interrupted (EINTR).  If we lose control, attempt to re-open
3457*7c478bd9Sstevel@tonic-gate 	 * the process, or call pt_exec() if that fails to handle a re-exec.
3458*7c478bd9Sstevel@tonic-gate 	 * If the process dies (ENOENT) or Pwait() fails, break out of the loop.
3459*7c478bd9Sstevel@tonic-gate 	 */
3460*7c478bd9Sstevel@tonic-gate 	while (Pwait(P, 0) == -1) {
3461*7c478bd9Sstevel@tonic-gate 		if (errno != EINTR) {
3462*7c478bd9Sstevel@tonic-gate 			if (Pstate(P) == PS_LOST) {
3463*7c478bd9Sstevel@tonic-gate 				if (Preopen(P) == 0)
3464*7c478bd9Sstevel@tonic-gate 					continue; /* Pwait() again */
3465*7c478bd9Sstevel@tonic-gate 				else
3466*7c478bd9Sstevel@tonic-gate 					pt_exec(t, 0, NULL);
3467*7c478bd9Sstevel@tonic-gate 			} else if (errno != ENOENT)
3468*7c478bd9Sstevel@tonic-gate 				warn("failed to wait for event");
3469*7c478bd9Sstevel@tonic-gate 			break;
3470*7c478bd9Sstevel@tonic-gate 		}
3471*7c478bd9Sstevel@tonic-gate 	}
3472*7c478bd9Sstevel@tonic-gate 
3473*7c478bd9Sstevel@tonic-gate 	/*
3474*7c478bd9Sstevel@tonic-gate 	 * If we changed the foreground process group, restore the old pgid
3475*7c478bd9Sstevel@tonic-gate 	 * while ignoring SIGTTOU so we are not accidentally suspended.
3476*7c478bd9Sstevel@tonic-gate 	 */
3477*7c478bd9Sstevel@tonic-gate 	if (old_pgid != -1) {
3478*7c478bd9Sstevel@tonic-gate 		(void) mdb_signal_sethandler(SIGTTOU, SIG_IGN, NULL);
3479*7c478bd9Sstevel@tonic-gate 		(void) IOP_CTL(mdb.m_term, TIOCSPGRP, &pgid);
3480*7c478bd9Sstevel@tonic-gate 		(void) mdb_signal_sethandler(SIGTTOU, SIG_DFL, NULL);
3481*7c478bd9Sstevel@tonic-gate 	}
3482*7c478bd9Sstevel@tonic-gate 
3483*7c478bd9Sstevel@tonic-gate 	/*
3484*7c478bd9Sstevel@tonic-gate 	 * If we're now stopped on exit from a successful exec, release any
3485*7c478bd9Sstevel@tonic-gate 	 * vfork parents and clean out their address space before returning
3486*7c478bd9Sstevel@tonic-gate 	 * to tgt_continue() and perturbing the list of armed event specs.
3487*7c478bd9Sstevel@tonic-gate 	 * If we're stopped for any other reason, just update the mappings.
3488*7c478bd9Sstevel@tonic-gate 	 */
3489*7c478bd9Sstevel@tonic-gate 	switch (Pstate(P)) {
3490*7c478bd9Sstevel@tonic-gate 	case PS_STOP:
3491*7c478bd9Sstevel@tonic-gate 		if (psp->pr_why == PR_SYSEXIT && psp->pr_errno == 0 &&
3492*7c478bd9Sstevel@tonic-gate 		    (psp->pr_what == SYS_exec || psp->pr_what == SYS_execve))
3493*7c478bd9Sstevel@tonic-gate 			pt_release_parents(t);
3494*7c478bd9Sstevel@tonic-gate 		else
3495*7c478bd9Sstevel@tonic-gate 			Pupdate_maps(P);
3496*7c478bd9Sstevel@tonic-gate 		break;
3497*7c478bd9Sstevel@tonic-gate 
3498*7c478bd9Sstevel@tonic-gate 	case PS_UNDEAD:
3499*7c478bd9Sstevel@tonic-gate 	case PS_LOST:
3500*7c478bd9Sstevel@tonic-gate 		pt_release_parents(t);
3501*7c478bd9Sstevel@tonic-gate 		break;
3502*7c478bd9Sstevel@tonic-gate 	}
3503*7c478bd9Sstevel@tonic-gate 
3504*7c478bd9Sstevel@tonic-gate out:
3505*7c478bd9Sstevel@tonic-gate 	(void) mdb_signal_sethandler(SIGINT, intf, intd);
3506*7c478bd9Sstevel@tonic-gate 	(void) mdb_signal_sethandler(SIGQUIT, quitf, quitd);
3507*7c478bd9Sstevel@tonic-gate 	(void) mdb_signal_sethandler(SIGTSTP, tstpf, tstpd);
3508*7c478bd9Sstevel@tonic-gate 	(void) pt_status(t, tsp);
3509*7c478bd9Sstevel@tonic-gate 
3510*7c478bd9Sstevel@tonic-gate 	return (error ? set_errno(error) : 0);
3511*7c478bd9Sstevel@tonic-gate }
3512*7c478bd9Sstevel@tonic-gate 
3513*7c478bd9Sstevel@tonic-gate static int
3514*7c478bd9Sstevel@tonic-gate pt_step(mdb_tgt_t *t, mdb_tgt_status_t *tsp)
3515*7c478bd9Sstevel@tonic-gate {
3516*7c478bd9Sstevel@tonic-gate 	return (pt_setrun(t, tsp, PRSTEP));
3517*7c478bd9Sstevel@tonic-gate }
3518*7c478bd9Sstevel@tonic-gate 
3519*7c478bd9Sstevel@tonic-gate static int
3520*7c478bd9Sstevel@tonic-gate pt_continue(mdb_tgt_t *t, mdb_tgt_status_t *tsp)
3521*7c478bd9Sstevel@tonic-gate {
3522*7c478bd9Sstevel@tonic-gate 	return (pt_setrun(t, tsp, 0));
3523*7c478bd9Sstevel@tonic-gate }
3524*7c478bd9Sstevel@tonic-gate 
3525*7c478bd9Sstevel@tonic-gate static int
3526*7c478bd9Sstevel@tonic-gate pt_signal(mdb_tgt_t *t, int sig)
3527*7c478bd9Sstevel@tonic-gate {
3528*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
3529*7c478bd9Sstevel@tonic-gate 
3530*7c478bd9Sstevel@tonic-gate 	if (sig > 0 && sig <= pt->p_maxsig) {
3531*7c478bd9Sstevel@tonic-gate 		pt->p_signal = sig; /* pending until next pt_setrun */
3532*7c478bd9Sstevel@tonic-gate 		return (0);
3533*7c478bd9Sstevel@tonic-gate 	}
3534*7c478bd9Sstevel@tonic-gate 
3535*7c478bd9Sstevel@tonic-gate 	return (set_errno(EMDB_BADSIGNUM));
3536*7c478bd9Sstevel@tonic-gate }
3537*7c478bd9Sstevel@tonic-gate 
3538*7c478bd9Sstevel@tonic-gate static int
3539*7c478bd9Sstevel@tonic-gate pt_sysenter_ctor(mdb_tgt_t *t, mdb_sespec_t *sep, void *args)
3540*7c478bd9Sstevel@tonic-gate {
3541*7c478bd9Sstevel@tonic-gate 	struct ps_prochandle *P = t->t_pshandle;
3542*7c478bd9Sstevel@tonic-gate 
3543*7c478bd9Sstevel@tonic-gate 	if (P != NULL && Pstate(P) < PS_LOST) {
3544*7c478bd9Sstevel@tonic-gate 		sep->se_data = args; /* data is raw system call number */
3545*7c478bd9Sstevel@tonic-gate 		return (Psysentry(P, (intptr_t)args, TRUE) < 0 ? -1 : 0);
3546*7c478bd9Sstevel@tonic-gate 	}
3547*7c478bd9Sstevel@tonic-gate 
3548*7c478bd9Sstevel@tonic-gate 	return (set_errno(EMDB_NOPROC));
3549*7c478bd9Sstevel@tonic-gate }
3550*7c478bd9Sstevel@tonic-gate 
3551*7c478bd9Sstevel@tonic-gate static void
3552*7c478bd9Sstevel@tonic-gate pt_sysenter_dtor(mdb_tgt_t *t, mdb_sespec_t *sep)
3553*7c478bd9Sstevel@tonic-gate {
3554*7c478bd9Sstevel@tonic-gate 	(void) Psysentry(t->t_pshandle, (intptr_t)sep->se_data, FALSE);
3555*7c478bd9Sstevel@tonic-gate }
3556*7c478bd9Sstevel@tonic-gate 
3557*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3558*7c478bd9Sstevel@tonic-gate static char *
3559*7c478bd9Sstevel@tonic-gate pt_sysenter_info(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_vespec_t *vep,
3560*7c478bd9Sstevel@tonic-gate     mdb_tgt_spec_desc_t *sp, char *buf, size_t nbytes)
3561*7c478bd9Sstevel@tonic-gate {
3562*7c478bd9Sstevel@tonic-gate 	char name[32];
3563*7c478bd9Sstevel@tonic-gate 	int sysnum;
3564*7c478bd9Sstevel@tonic-gate 
3565*7c478bd9Sstevel@tonic-gate 	if (vep != NULL)
3566*7c478bd9Sstevel@tonic-gate 		sysnum = (intptr_t)vep->ve_args;
3567*7c478bd9Sstevel@tonic-gate 	else
3568*7c478bd9Sstevel@tonic-gate 		sysnum = (intptr_t)sep->se_data;
3569*7c478bd9Sstevel@tonic-gate 
3570*7c478bd9Sstevel@tonic-gate 	(void) proc_sysname(sysnum, name, sizeof (name));
3571*7c478bd9Sstevel@tonic-gate 	(void) mdb_iob_snprintf(buf, nbytes, "stop on entry to %s", name);
3572*7c478bd9Sstevel@tonic-gate 
3573*7c478bd9Sstevel@tonic-gate 	return (buf);
3574*7c478bd9Sstevel@tonic-gate }
3575*7c478bd9Sstevel@tonic-gate 
3576*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3577*7c478bd9Sstevel@tonic-gate static int
3578*7c478bd9Sstevel@tonic-gate pt_sysenter_match(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_tgt_status_t *tsp)
3579*7c478bd9Sstevel@tonic-gate {
3580*7c478bd9Sstevel@tonic-gate 	const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp;
3581*7c478bd9Sstevel@tonic-gate 	int sysnum = (intptr_t)sep->se_data;
3582*7c478bd9Sstevel@tonic-gate 
3583*7c478bd9Sstevel@tonic-gate 	return (psp->pr_why == PR_SYSENTRY && psp->pr_what == sysnum);
3584*7c478bd9Sstevel@tonic-gate }
3585*7c478bd9Sstevel@tonic-gate 
3586*7c478bd9Sstevel@tonic-gate static const mdb_se_ops_t proc_sysenter_ops = {
3587*7c478bd9Sstevel@tonic-gate 	pt_sysenter_ctor,	/* se_ctor */
3588*7c478bd9Sstevel@tonic-gate 	pt_sysenter_dtor,	/* se_dtor */
3589*7c478bd9Sstevel@tonic-gate 	pt_sysenter_info,	/* se_info */
3590*7c478bd9Sstevel@tonic-gate 	no_se_secmp,		/* se_secmp */
3591*7c478bd9Sstevel@tonic-gate 	no_se_vecmp,		/* se_vecmp */
3592*7c478bd9Sstevel@tonic-gate 	no_se_arm,		/* se_arm */
3593*7c478bd9Sstevel@tonic-gate 	no_se_disarm,		/* se_disarm */
3594*7c478bd9Sstevel@tonic-gate 	no_se_cont,		/* se_cont */
3595*7c478bd9Sstevel@tonic-gate 	pt_sysenter_match	/* se_match */
3596*7c478bd9Sstevel@tonic-gate };
3597*7c478bd9Sstevel@tonic-gate 
3598*7c478bd9Sstevel@tonic-gate static int
3599*7c478bd9Sstevel@tonic-gate pt_sysexit_ctor(mdb_tgt_t *t, mdb_sespec_t *sep, void *args)
3600*7c478bd9Sstevel@tonic-gate {
3601*7c478bd9Sstevel@tonic-gate 	struct ps_prochandle *P = t->t_pshandle;
3602*7c478bd9Sstevel@tonic-gate 
3603*7c478bd9Sstevel@tonic-gate 	if (P != NULL && Pstate(P) < PS_LOST) {
3604*7c478bd9Sstevel@tonic-gate 		sep->se_data = args; /* data is raw system call number */
3605*7c478bd9Sstevel@tonic-gate 		return (Psysexit(P, (intptr_t)args, TRUE) < 0 ? -1 : 0);
3606*7c478bd9Sstevel@tonic-gate 	}
3607*7c478bd9Sstevel@tonic-gate 
3608*7c478bd9Sstevel@tonic-gate 	return (set_errno(EMDB_NOPROC));
3609*7c478bd9Sstevel@tonic-gate }
3610*7c478bd9Sstevel@tonic-gate 
3611*7c478bd9Sstevel@tonic-gate static void
3612*7c478bd9Sstevel@tonic-gate pt_sysexit_dtor(mdb_tgt_t *t, mdb_sespec_t *sep)
3613*7c478bd9Sstevel@tonic-gate {
3614*7c478bd9Sstevel@tonic-gate 	(void) Psysexit(t->t_pshandle, (intptr_t)sep->se_data, FALSE);
3615*7c478bd9Sstevel@tonic-gate }
3616*7c478bd9Sstevel@tonic-gate 
3617*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3618*7c478bd9Sstevel@tonic-gate static char *
3619*7c478bd9Sstevel@tonic-gate pt_sysexit_info(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_vespec_t *vep,
3620*7c478bd9Sstevel@tonic-gate     mdb_tgt_spec_desc_t *sp, char *buf, size_t nbytes)
3621*7c478bd9Sstevel@tonic-gate {
3622*7c478bd9Sstevel@tonic-gate 	char name[32];
3623*7c478bd9Sstevel@tonic-gate 	int sysnum;
3624*7c478bd9Sstevel@tonic-gate 
3625*7c478bd9Sstevel@tonic-gate 	if (vep != NULL)
3626*7c478bd9Sstevel@tonic-gate 		sysnum = (intptr_t)vep->ve_args;
3627*7c478bd9Sstevel@tonic-gate 	else
3628*7c478bd9Sstevel@tonic-gate 		sysnum = (intptr_t)sep->se_data;
3629*7c478bd9Sstevel@tonic-gate 
3630*7c478bd9Sstevel@tonic-gate 	(void) proc_sysname(sysnum, name, sizeof (name));
3631*7c478bd9Sstevel@tonic-gate 	(void) mdb_iob_snprintf(buf, nbytes, "stop on exit from %s", name);
3632*7c478bd9Sstevel@tonic-gate 
3633*7c478bd9Sstevel@tonic-gate 	return (buf);
3634*7c478bd9Sstevel@tonic-gate }
3635*7c478bd9Sstevel@tonic-gate 
3636*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3637*7c478bd9Sstevel@tonic-gate static int
3638*7c478bd9Sstevel@tonic-gate pt_sysexit_match(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_tgt_status_t *tsp)
3639*7c478bd9Sstevel@tonic-gate {
3640*7c478bd9Sstevel@tonic-gate 	const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp;
3641*7c478bd9Sstevel@tonic-gate 	int sysnum = (intptr_t)sep->se_data;
3642*7c478bd9Sstevel@tonic-gate 
3643*7c478bd9Sstevel@tonic-gate 	return (psp->pr_why == PR_SYSEXIT && psp->pr_what == sysnum);
3644*7c478bd9Sstevel@tonic-gate }
3645*7c478bd9Sstevel@tonic-gate 
3646*7c478bd9Sstevel@tonic-gate static const mdb_se_ops_t proc_sysexit_ops = {
3647*7c478bd9Sstevel@tonic-gate 	pt_sysexit_ctor,	/* se_ctor */
3648*7c478bd9Sstevel@tonic-gate 	pt_sysexit_dtor,	/* se_dtor */
3649*7c478bd9Sstevel@tonic-gate 	pt_sysexit_info,	/* se_info */
3650*7c478bd9Sstevel@tonic-gate 	no_se_secmp,		/* se_secmp */
3651*7c478bd9Sstevel@tonic-gate 	no_se_vecmp,		/* se_vecmp */
3652*7c478bd9Sstevel@tonic-gate 	no_se_arm,		/* se_arm */
3653*7c478bd9Sstevel@tonic-gate 	no_se_disarm,		/* se_disarm */
3654*7c478bd9Sstevel@tonic-gate 	no_se_cont,		/* se_cont */
3655*7c478bd9Sstevel@tonic-gate 	pt_sysexit_match	/* se_match */
3656*7c478bd9Sstevel@tonic-gate };
3657*7c478bd9Sstevel@tonic-gate 
3658*7c478bd9Sstevel@tonic-gate static int
3659*7c478bd9Sstevel@tonic-gate pt_signal_ctor(mdb_tgt_t *t, mdb_sespec_t *sep, void *args)
3660*7c478bd9Sstevel@tonic-gate {
3661*7c478bd9Sstevel@tonic-gate 	struct ps_prochandle *P = t->t_pshandle;
3662*7c478bd9Sstevel@tonic-gate 
3663*7c478bd9Sstevel@tonic-gate 	if (P != NULL && Pstate(P) < PS_LOST) {
3664*7c478bd9Sstevel@tonic-gate 		sep->se_data = args; /* data is raw signal number */
3665*7c478bd9Sstevel@tonic-gate 		return (Psignal(P, (intptr_t)args, TRUE) < 0 ? -1 : 0);
3666*7c478bd9Sstevel@tonic-gate 	}
3667*7c478bd9Sstevel@tonic-gate 
3668*7c478bd9Sstevel@tonic-gate 	return (set_errno(EMDB_NOPROC));
3669*7c478bd9Sstevel@tonic-gate }
3670*7c478bd9Sstevel@tonic-gate 
3671*7c478bd9Sstevel@tonic-gate static void
3672*7c478bd9Sstevel@tonic-gate pt_signal_dtor(mdb_tgt_t *t, mdb_sespec_t *sep)
3673*7c478bd9Sstevel@tonic-gate {
3674*7c478bd9Sstevel@tonic-gate 	(void) Psignal(t->t_pshandle, (intptr_t)sep->se_data, FALSE);
3675*7c478bd9Sstevel@tonic-gate }
3676*7c478bd9Sstevel@tonic-gate 
3677*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3678*7c478bd9Sstevel@tonic-gate static char *
3679*7c478bd9Sstevel@tonic-gate pt_signal_info(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_vespec_t *vep,
3680*7c478bd9Sstevel@tonic-gate     mdb_tgt_spec_desc_t *sp, char *buf, size_t nbytes)
3681*7c478bd9Sstevel@tonic-gate {
3682*7c478bd9Sstevel@tonic-gate 	char name[SIG2STR_MAX];
3683*7c478bd9Sstevel@tonic-gate 	int signum;
3684*7c478bd9Sstevel@tonic-gate 
3685*7c478bd9Sstevel@tonic-gate 	if (vep != NULL)
3686*7c478bd9Sstevel@tonic-gate 		signum = (intptr_t)vep->ve_args;
3687*7c478bd9Sstevel@tonic-gate 	else
3688*7c478bd9Sstevel@tonic-gate 		signum = (intptr_t)sep->se_data;
3689*7c478bd9Sstevel@tonic-gate 
3690*7c478bd9Sstevel@tonic-gate 	(void) proc_signame(signum, name, sizeof (name));
3691*7c478bd9Sstevel@tonic-gate 	(void) mdb_iob_snprintf(buf, nbytes, "stop on %s", name);
3692*7c478bd9Sstevel@tonic-gate 
3693*7c478bd9Sstevel@tonic-gate 	return (buf);
3694*7c478bd9Sstevel@tonic-gate }
3695*7c478bd9Sstevel@tonic-gate 
3696*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3697*7c478bd9Sstevel@tonic-gate static int
3698*7c478bd9Sstevel@tonic-gate pt_signal_match(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_tgt_status_t *tsp)
3699*7c478bd9Sstevel@tonic-gate {
3700*7c478bd9Sstevel@tonic-gate 	const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp;
3701*7c478bd9Sstevel@tonic-gate 	int signum = (intptr_t)sep->se_data;
3702*7c478bd9Sstevel@tonic-gate 
3703*7c478bd9Sstevel@tonic-gate 	return (psp->pr_why == PR_SIGNALLED && psp->pr_what == signum);
3704*7c478bd9Sstevel@tonic-gate }
3705*7c478bd9Sstevel@tonic-gate 
3706*7c478bd9Sstevel@tonic-gate static const mdb_se_ops_t proc_signal_ops = {
3707*7c478bd9Sstevel@tonic-gate 	pt_signal_ctor,		/* se_ctor */
3708*7c478bd9Sstevel@tonic-gate 	pt_signal_dtor,		/* se_dtor */
3709*7c478bd9Sstevel@tonic-gate 	pt_signal_info,		/* se_info */
3710*7c478bd9Sstevel@tonic-gate 	no_se_secmp,		/* se_secmp */
3711*7c478bd9Sstevel@tonic-gate 	no_se_vecmp,		/* se_vecmp */
3712*7c478bd9Sstevel@tonic-gate 	no_se_arm,		/* se_arm */
3713*7c478bd9Sstevel@tonic-gate 	no_se_disarm,		/* se_disarm */
3714*7c478bd9Sstevel@tonic-gate 	no_se_cont,		/* se_cont */
3715*7c478bd9Sstevel@tonic-gate 	pt_signal_match		/* se_match */
3716*7c478bd9Sstevel@tonic-gate };
3717*7c478bd9Sstevel@tonic-gate 
3718*7c478bd9Sstevel@tonic-gate static int
3719*7c478bd9Sstevel@tonic-gate pt_fault_ctor(mdb_tgt_t *t, mdb_sespec_t *sep, void *args)
3720*7c478bd9Sstevel@tonic-gate {
3721*7c478bd9Sstevel@tonic-gate 	struct ps_prochandle *P = t->t_pshandle;
3722*7c478bd9Sstevel@tonic-gate 
3723*7c478bd9Sstevel@tonic-gate 	if (P != NULL && Pstate(P) < PS_LOST) {
3724*7c478bd9Sstevel@tonic-gate 		sep->se_data = args; /* data is raw fault number */
3725*7c478bd9Sstevel@tonic-gate 		return (Pfault(P, (intptr_t)args, TRUE) < 0 ? -1 : 0);
3726*7c478bd9Sstevel@tonic-gate 	}
3727*7c478bd9Sstevel@tonic-gate 
3728*7c478bd9Sstevel@tonic-gate 	return (set_errno(EMDB_NOPROC));
3729*7c478bd9Sstevel@tonic-gate }
3730*7c478bd9Sstevel@tonic-gate 
3731*7c478bd9Sstevel@tonic-gate static void
3732*7c478bd9Sstevel@tonic-gate pt_fault_dtor(mdb_tgt_t *t, mdb_sespec_t *sep)
3733*7c478bd9Sstevel@tonic-gate {
3734*7c478bd9Sstevel@tonic-gate 	int fault = (intptr_t)sep->se_data;
3735*7c478bd9Sstevel@tonic-gate 
3736*7c478bd9Sstevel@tonic-gate 	if (fault != FLTBPT && fault != FLTTRACE && fault != FLTWATCH)
3737*7c478bd9Sstevel@tonic-gate 		(void) Pfault(t->t_pshandle, fault, FALSE);
3738*7c478bd9Sstevel@tonic-gate }
3739*7c478bd9Sstevel@tonic-gate 
3740*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3741*7c478bd9Sstevel@tonic-gate static char *
3742*7c478bd9Sstevel@tonic-gate pt_fault_info(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_vespec_t *vep,
3743*7c478bd9Sstevel@tonic-gate     mdb_tgt_spec_desc_t *sp, char *buf, size_t nbytes)
3744*7c478bd9Sstevel@tonic-gate {
3745*7c478bd9Sstevel@tonic-gate 	char name[32];
3746*7c478bd9Sstevel@tonic-gate 	int fltnum;
3747*7c478bd9Sstevel@tonic-gate 
3748*7c478bd9Sstevel@tonic-gate 	if (vep != NULL)
3749*7c478bd9Sstevel@tonic-gate 		fltnum = (intptr_t)vep->ve_args;
3750*7c478bd9Sstevel@tonic-gate 	else
3751*7c478bd9Sstevel@tonic-gate 		fltnum = (intptr_t)sep->se_data;
3752*7c478bd9Sstevel@tonic-gate 
3753*7c478bd9Sstevel@tonic-gate 	(void) proc_fltname(fltnum, name, sizeof (name));
3754*7c478bd9Sstevel@tonic-gate 	(void) mdb_iob_snprintf(buf, nbytes, "stop on %s", name);
3755*7c478bd9Sstevel@tonic-gate 
3756*7c478bd9Sstevel@tonic-gate 	return (buf);
3757*7c478bd9Sstevel@tonic-gate }
3758*7c478bd9Sstevel@tonic-gate 
3759*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3760*7c478bd9Sstevel@tonic-gate static int
3761*7c478bd9Sstevel@tonic-gate pt_fault_match(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_tgt_status_t *tsp)
3762*7c478bd9Sstevel@tonic-gate {
3763*7c478bd9Sstevel@tonic-gate 	const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp;
3764*7c478bd9Sstevel@tonic-gate 	int fltnum = (intptr_t)sep->se_data;
3765*7c478bd9Sstevel@tonic-gate 
3766*7c478bd9Sstevel@tonic-gate 	return (psp->pr_why == PR_FAULTED && psp->pr_what == fltnum);
3767*7c478bd9Sstevel@tonic-gate }
3768*7c478bd9Sstevel@tonic-gate 
3769*7c478bd9Sstevel@tonic-gate static const mdb_se_ops_t proc_fault_ops = {
3770*7c478bd9Sstevel@tonic-gate 	pt_fault_ctor,		/* se_ctor */
3771*7c478bd9Sstevel@tonic-gate 	pt_fault_dtor,		/* se_dtor */
3772*7c478bd9Sstevel@tonic-gate 	pt_fault_info,		/* se_info */
3773*7c478bd9Sstevel@tonic-gate 	no_se_secmp,		/* se_secmp */
3774*7c478bd9Sstevel@tonic-gate 	no_se_vecmp,		/* se_vecmp */
3775*7c478bd9Sstevel@tonic-gate 	no_se_arm,		/* se_arm */
3776*7c478bd9Sstevel@tonic-gate 	no_se_disarm,		/* se_disarm */
3777*7c478bd9Sstevel@tonic-gate 	no_se_cont,		/* se_cont */
3778*7c478bd9Sstevel@tonic-gate 	pt_fault_match		/* se_match */
3779*7c478bd9Sstevel@tonic-gate };
3780*7c478bd9Sstevel@tonic-gate 
3781*7c478bd9Sstevel@tonic-gate /*
3782*7c478bd9Sstevel@tonic-gate  * Callback for pt_ignore() dcmd above: for each VID, determine if it
3783*7c478bd9Sstevel@tonic-gate  * corresponds to a vespec that traces the specified signal, and delete it.
3784*7c478bd9Sstevel@tonic-gate  */
3785*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3786*7c478bd9Sstevel@tonic-gate static int
3787*7c478bd9Sstevel@tonic-gate pt_ignore_sig(mdb_tgt_t *t, void *sig, int vid, void *data)
3788*7c478bd9Sstevel@tonic-gate {
3789*7c478bd9Sstevel@tonic-gate 	mdb_vespec_t *vep = mdb_tgt_vespec_lookup(t, vid);
3790*7c478bd9Sstevel@tonic-gate 
3791*7c478bd9Sstevel@tonic-gate 	if (vep->ve_se->se_ops == &proc_signal_ops && vep->ve_args == sig)
3792*7c478bd9Sstevel@tonic-gate 		(void) mdb_tgt_vespec_delete(t, vid);
3793*7c478bd9Sstevel@tonic-gate 
3794*7c478bd9Sstevel@tonic-gate 	return (0);
3795*7c478bd9Sstevel@tonic-gate }
3796*7c478bd9Sstevel@tonic-gate 
3797*7c478bd9Sstevel@tonic-gate static int
3798*7c478bd9Sstevel@tonic-gate pt_brkpt_ctor(mdb_tgt_t *t, mdb_sespec_t *sep, void *args)
3799*7c478bd9Sstevel@tonic-gate {
3800*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
3801*7c478bd9Sstevel@tonic-gate 	pt_bparg_t *pta = args;
3802*7c478bd9Sstevel@tonic-gate 	pt_brkpt_t *ptb;
3803*7c478bd9Sstevel@tonic-gate 	GElf_Sym s;
3804*7c478bd9Sstevel@tonic-gate 
3805*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle == NULL || Pstate(t->t_pshandle) >= PS_LOST)
3806*7c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_NOPROC));
3807*7c478bd9Sstevel@tonic-gate 
3808*7c478bd9Sstevel@tonic-gate 	if (pta->pta_symbol != NULL) {
3809*7c478bd9Sstevel@tonic-gate 		if (!pt->p_rtld_finished &&
3810*7c478bd9Sstevel@tonic-gate 		    strchr(pta->pta_symbol, '`') == NULL)
3811*7c478bd9Sstevel@tonic-gate 			return (set_errno(EMDB_NOSYM));
3812*7c478bd9Sstevel@tonic-gate 		if (mdb_tgt_lookup_by_scope(t, pta->pta_symbol, &s,
3813*7c478bd9Sstevel@tonic-gate 		    NULL) == -1) {
3814*7c478bd9Sstevel@tonic-gate 			if (errno != EMDB_NOOBJ && !(errno == EMDB_NOSYM &&
3815*7c478bd9Sstevel@tonic-gate 			    (!(mdb.m_flags & MDB_FL_BPTNOSYMSTOP) ||
3816*7c478bd9Sstevel@tonic-gate 			    !pt->p_rtld_finished))) {
3817*7c478bd9Sstevel@tonic-gate 				warn("breakpoint %s activation failed",
3818*7c478bd9Sstevel@tonic-gate 				    pta->pta_symbol);
3819*7c478bd9Sstevel@tonic-gate 			}
3820*7c478bd9Sstevel@tonic-gate 			return (-1); /* errno is set for us */
3821*7c478bd9Sstevel@tonic-gate 		}
3822*7c478bd9Sstevel@tonic-gate 
3823*7c478bd9Sstevel@tonic-gate 		pta->pta_addr = (uintptr_t)s.st_value;
3824*7c478bd9Sstevel@tonic-gate 	}
3825*7c478bd9Sstevel@tonic-gate 
3826*7c478bd9Sstevel@tonic-gate #ifdef __sparc
3827*7c478bd9Sstevel@tonic-gate 	if (pta->pta_addr & 3)
3828*7c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_BPALIGN));
3829*7c478bd9Sstevel@tonic-gate #endif
3830*7c478bd9Sstevel@tonic-gate 
3831*7c478bd9Sstevel@tonic-gate 	if (Paddr_to_map(t->t_pshandle, pta->pta_addr) == NULL)
3832*7c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_NOMAP));
3833*7c478bd9Sstevel@tonic-gate 
3834*7c478bd9Sstevel@tonic-gate 	ptb = mdb_alloc(sizeof (pt_brkpt_t), UM_SLEEP);
3835*7c478bd9Sstevel@tonic-gate 	ptb->ptb_addr = pta->pta_addr;
3836*7c478bd9Sstevel@tonic-gate 	ptb->ptb_instr = NULL;
3837*7c478bd9Sstevel@tonic-gate 	sep->se_data = ptb;
3838*7c478bd9Sstevel@tonic-gate 
3839*7c478bd9Sstevel@tonic-gate 	return (0);
3840*7c478bd9Sstevel@tonic-gate }
3841*7c478bd9Sstevel@tonic-gate 
3842*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3843*7c478bd9Sstevel@tonic-gate static void
3844*7c478bd9Sstevel@tonic-gate pt_brkpt_dtor(mdb_tgt_t *t, mdb_sespec_t *sep)
3845*7c478bd9Sstevel@tonic-gate {
3846*7c478bd9Sstevel@tonic-gate 	mdb_free(sep->se_data, sizeof (pt_brkpt_t));
3847*7c478bd9Sstevel@tonic-gate }
3848*7c478bd9Sstevel@tonic-gate 
3849*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3850*7c478bd9Sstevel@tonic-gate static char *
3851*7c478bd9Sstevel@tonic-gate pt_brkpt_info(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_vespec_t *vep,
3852*7c478bd9Sstevel@tonic-gate     mdb_tgt_spec_desc_t *sp, char *buf, size_t nbytes)
3853*7c478bd9Sstevel@tonic-gate {
3854*7c478bd9Sstevel@tonic-gate 	uintptr_t addr = NULL;
3855*7c478bd9Sstevel@tonic-gate 
3856*7c478bd9Sstevel@tonic-gate 	if (vep != NULL) {
3857*7c478bd9Sstevel@tonic-gate 		pt_bparg_t *pta = vep->ve_args;
3858*7c478bd9Sstevel@tonic-gate 
3859*7c478bd9Sstevel@tonic-gate 		if (pta->pta_symbol != NULL) {
3860*7c478bd9Sstevel@tonic-gate 			(void) mdb_iob_snprintf(buf, nbytes, "stop at %s",
3861*7c478bd9Sstevel@tonic-gate 			    pta->pta_symbol);
3862*7c478bd9Sstevel@tonic-gate 		} else {
3863*7c478bd9Sstevel@tonic-gate 			(void) mdb_iob_snprintf(buf, nbytes, "stop at %a",
3864*7c478bd9Sstevel@tonic-gate 			    pta->pta_addr);
3865*7c478bd9Sstevel@tonic-gate 			addr = pta->pta_addr;
3866*7c478bd9Sstevel@tonic-gate 		}
3867*7c478bd9Sstevel@tonic-gate 
3868*7c478bd9Sstevel@tonic-gate 	} else {
3869*7c478bd9Sstevel@tonic-gate 		addr = ((pt_brkpt_t *)sep->se_data)->ptb_addr;
3870*7c478bd9Sstevel@tonic-gate 		(void) mdb_iob_snprintf(buf, nbytes, "stop at %a", addr);
3871*7c478bd9Sstevel@tonic-gate 	}
3872*7c478bd9Sstevel@tonic-gate 
3873*7c478bd9Sstevel@tonic-gate 	sp->spec_base = addr;
3874*7c478bd9Sstevel@tonic-gate 	sp->spec_size = sizeof (instr_t);
3875*7c478bd9Sstevel@tonic-gate 
3876*7c478bd9Sstevel@tonic-gate 	return (buf);
3877*7c478bd9Sstevel@tonic-gate }
3878*7c478bd9Sstevel@tonic-gate 
3879*7c478bd9Sstevel@tonic-gate static int
3880*7c478bd9Sstevel@tonic-gate pt_brkpt_secmp(mdb_tgt_t *t, mdb_sespec_t *sep, void *args)
3881*7c478bd9Sstevel@tonic-gate {
3882*7c478bd9Sstevel@tonic-gate 	pt_brkpt_t *ptb = sep->se_data;
3883*7c478bd9Sstevel@tonic-gate 	pt_bparg_t *pta = args;
3884*7c478bd9Sstevel@tonic-gate 	GElf_Sym sym;
3885*7c478bd9Sstevel@tonic-gate 
3886*7c478bd9Sstevel@tonic-gate 	if (pta->pta_symbol != NULL) {
3887*7c478bd9Sstevel@tonic-gate 		return (mdb_tgt_lookup_by_scope(t, pta->pta_symbol,
3888*7c478bd9Sstevel@tonic-gate 		    &sym, NULL) == 0 && sym.st_value == ptb->ptb_addr);
3889*7c478bd9Sstevel@tonic-gate 	}
3890*7c478bd9Sstevel@tonic-gate 
3891*7c478bd9Sstevel@tonic-gate 	return (pta->pta_addr == ptb->ptb_addr);
3892*7c478bd9Sstevel@tonic-gate }
3893*7c478bd9Sstevel@tonic-gate 
3894*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3895*7c478bd9Sstevel@tonic-gate static int
3896*7c478bd9Sstevel@tonic-gate pt_brkpt_vecmp(mdb_tgt_t *t, mdb_vespec_t *vep, void *args)
3897*7c478bd9Sstevel@tonic-gate {
3898*7c478bd9Sstevel@tonic-gate 	pt_bparg_t *pta1 = vep->ve_args;
3899*7c478bd9Sstevel@tonic-gate 	pt_bparg_t *pta2 = args;
3900*7c478bd9Sstevel@tonic-gate 
3901*7c478bd9Sstevel@tonic-gate 	if (pta1->pta_symbol != NULL && pta2->pta_symbol != NULL)
3902*7c478bd9Sstevel@tonic-gate 		return (strcmp(pta1->pta_symbol, pta2->pta_symbol) == 0);
3903*7c478bd9Sstevel@tonic-gate 
3904*7c478bd9Sstevel@tonic-gate 	if (pta1->pta_symbol == NULL && pta2->pta_symbol == NULL)
3905*7c478bd9Sstevel@tonic-gate 		return (pta1->pta_addr == pta2->pta_addr);
3906*7c478bd9Sstevel@tonic-gate 
3907*7c478bd9Sstevel@tonic-gate 	return (0); /* fail if one is symbolic, other is an explicit address */
3908*7c478bd9Sstevel@tonic-gate }
3909*7c478bd9Sstevel@tonic-gate 
3910*7c478bd9Sstevel@tonic-gate static int
3911*7c478bd9Sstevel@tonic-gate pt_brkpt_arm(mdb_tgt_t *t, mdb_sespec_t *sep)
3912*7c478bd9Sstevel@tonic-gate {
3913*7c478bd9Sstevel@tonic-gate 	pt_brkpt_t *ptb = sep->se_data;
3914*7c478bd9Sstevel@tonic-gate 	return (Psetbkpt(t->t_pshandle, ptb->ptb_addr, &ptb->ptb_instr));
3915*7c478bd9Sstevel@tonic-gate }
3916*7c478bd9Sstevel@tonic-gate 
3917*7c478bd9Sstevel@tonic-gate /*
3918*7c478bd9Sstevel@tonic-gate  * In order to disarm a breakpoint, we replace the trap instruction at ptb_addr
3919*7c478bd9Sstevel@tonic-gate  * with the saved instruction.  However, if we have stopped after a successful
3920*7c478bd9Sstevel@tonic-gate  * exec(2), we do not want to restore ptb_instr because the address space has
3921*7c478bd9Sstevel@tonic-gate  * now been replaced with the text of a different executable, and so restoring
3922*7c478bd9Sstevel@tonic-gate  * the saved instruction would be incorrect.  The exec itself has effectively
3923*7c478bd9Sstevel@tonic-gate  * removed all breakpoint trap instructions for us, so we can just return.
3924*7c478bd9Sstevel@tonic-gate  */
3925*7c478bd9Sstevel@tonic-gate static int
3926*7c478bd9Sstevel@tonic-gate pt_brkpt_disarm(mdb_tgt_t *t, mdb_sespec_t *sep)
3927*7c478bd9Sstevel@tonic-gate {
3928*7c478bd9Sstevel@tonic-gate 	const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp;
3929*7c478bd9Sstevel@tonic-gate 	pt_brkpt_t *ptb = sep->se_data;
3930*7c478bd9Sstevel@tonic-gate 
3931*7c478bd9Sstevel@tonic-gate 	if ((psp->pr_why == PR_SYSEXIT && psp->pr_errno == 0) &&
3932*7c478bd9Sstevel@tonic-gate 	    (psp->pr_what == SYS_exec || psp->pr_what == SYS_execve))
3933*7c478bd9Sstevel@tonic-gate 		return (0); /* do not restore saved instruction */
3934*7c478bd9Sstevel@tonic-gate 
3935*7c478bd9Sstevel@tonic-gate 	return (Pdelbkpt(t->t_pshandle, ptb->ptb_addr, ptb->ptb_instr));
3936*7c478bd9Sstevel@tonic-gate }
3937*7c478bd9Sstevel@tonic-gate 
3938*7c478bd9Sstevel@tonic-gate /*
3939*7c478bd9Sstevel@tonic-gate  * Determine whether the specified sespec is an armed watchpoint that overlaps
3940*7c478bd9Sstevel@tonic-gate  * with the given breakpoint and has the given flags set.  We use this to find
3941*7c478bd9Sstevel@tonic-gate  * conflicts with breakpoints, below.
3942*7c478bd9Sstevel@tonic-gate  */
3943*7c478bd9Sstevel@tonic-gate static int
3944*7c478bd9Sstevel@tonic-gate pt_wp_overlap(mdb_sespec_t *sep, pt_brkpt_t *ptb, int flags)
3945*7c478bd9Sstevel@tonic-gate {
3946*7c478bd9Sstevel@tonic-gate 	const prwatch_t *wp = sep->se_data;
3947*7c478bd9Sstevel@tonic-gate 
3948*7c478bd9Sstevel@tonic-gate 	return (sep->se_state == MDB_TGT_SPEC_ARMED &&
3949*7c478bd9Sstevel@tonic-gate 	    sep->se_ops == &proc_wapt_ops && (wp->pr_wflags & flags) &&
3950*7c478bd9Sstevel@tonic-gate 	    ptb->ptb_addr - wp->pr_vaddr < wp->pr_size);
3951*7c478bd9Sstevel@tonic-gate }
3952*7c478bd9Sstevel@tonic-gate 
3953*7c478bd9Sstevel@tonic-gate /*
3954*7c478bd9Sstevel@tonic-gate  * We step over breakpoints using Pxecbkpt() in libproc.  If a conflicting
3955*7c478bd9Sstevel@tonic-gate  * watchpoint is present, we must temporarily remove it before stepping over
3956*7c478bd9Sstevel@tonic-gate  * the breakpoint so we do not immediately re-trigger the watchpoint.  We know
3957*7c478bd9Sstevel@tonic-gate  * the watchpoint has already triggered on our trap instruction as part of
3958*7c478bd9Sstevel@tonic-gate  * fetching it.  Before we return, we must re-install any disabled watchpoints.
3959*7c478bd9Sstevel@tonic-gate  */
3960*7c478bd9Sstevel@tonic-gate static int
3961*7c478bd9Sstevel@tonic-gate pt_brkpt_cont(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_tgt_status_t *tsp)
3962*7c478bd9Sstevel@tonic-gate {
3963*7c478bd9Sstevel@tonic-gate 	pt_brkpt_t *ptb = sep->se_data;
3964*7c478bd9Sstevel@tonic-gate 	int status = -1;
3965*7c478bd9Sstevel@tonic-gate 	int error;
3966*7c478bd9Sstevel@tonic-gate 	const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp;
3967*7c478bd9Sstevel@tonic-gate 
3968*7c478bd9Sstevel@tonic-gate 	/*
3969*7c478bd9Sstevel@tonic-gate 	 * If the PC no longer matches our original address, then the user has
3970*7c478bd9Sstevel@tonic-gate 	 * changed it while we have been stopped. In this case, it no longer
3971*7c478bd9Sstevel@tonic-gate 	 * makes any sense to continue over this breakpoint.  We return as if we
3972*7c478bd9Sstevel@tonic-gate 	 * continued normally.
3973*7c478bd9Sstevel@tonic-gate 	 */
3974*7c478bd9Sstevel@tonic-gate 	if ((uintptr_t)psp->pr_info.si_addr != psp->pr_reg[R_PC])
3975*7c478bd9Sstevel@tonic-gate 		return (pt_status(t, tsp));
3976*7c478bd9Sstevel@tonic-gate 
3977*7c478bd9Sstevel@tonic-gate 	for (sep = mdb_list_next(&t->t_active); sep; sep = mdb_list_next(sep)) {
3978*7c478bd9Sstevel@tonic-gate 		if (pt_wp_overlap(sep, ptb, WA_EXEC))
3979*7c478bd9Sstevel@tonic-gate 			(void) Pdelwapt(t->t_pshandle, sep->se_data);
3980*7c478bd9Sstevel@tonic-gate 	}
3981*7c478bd9Sstevel@tonic-gate 
3982*7c478bd9Sstevel@tonic-gate 	if (Pxecbkpt(t->t_pshandle, ptb->ptb_instr) == 0 &&
3983*7c478bd9Sstevel@tonic-gate 	    Pdelbkpt(t->t_pshandle, ptb->ptb_addr, ptb->ptb_instr) == 0)
3984*7c478bd9Sstevel@tonic-gate 		status = pt_status(t, tsp);
3985*7c478bd9Sstevel@tonic-gate 
3986*7c478bd9Sstevel@tonic-gate 	error = errno; /* save errno from Pxecbkpt, Pdelbkpt, or pt_status */
3987*7c478bd9Sstevel@tonic-gate 
3988*7c478bd9Sstevel@tonic-gate 	for (sep = mdb_list_next(&t->t_active); sep; sep = mdb_list_next(sep)) {
3989*7c478bd9Sstevel@tonic-gate 		if (pt_wp_overlap(sep, ptb, WA_EXEC) &&
3990*7c478bd9Sstevel@tonic-gate 		    Psetwapt(t->t_pshandle, sep->se_data) == -1) {
3991*7c478bd9Sstevel@tonic-gate 			sep->se_state = MDB_TGT_SPEC_ERROR;
3992*7c478bd9Sstevel@tonic-gate 			sep->se_errno = errno;
3993*7c478bd9Sstevel@tonic-gate 		}
3994*7c478bd9Sstevel@tonic-gate 	}
3995*7c478bd9Sstevel@tonic-gate 
3996*7c478bd9Sstevel@tonic-gate 	(void) set_errno(error);
3997*7c478bd9Sstevel@tonic-gate 	return (status);
3998*7c478bd9Sstevel@tonic-gate }
3999*7c478bd9Sstevel@tonic-gate 
4000*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4001*7c478bd9Sstevel@tonic-gate static int
4002*7c478bd9Sstevel@tonic-gate pt_brkpt_match(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_tgt_status_t *tsp)
4003*7c478bd9Sstevel@tonic-gate {
4004*7c478bd9Sstevel@tonic-gate 	const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp;
4005*7c478bd9Sstevel@tonic-gate 	pt_brkpt_t *ptb = sep->se_data;
4006*7c478bd9Sstevel@tonic-gate 
4007*7c478bd9Sstevel@tonic-gate 	return (psp->pr_why == PR_FAULTED && psp->pr_what == FLTBPT &&
4008*7c478bd9Sstevel@tonic-gate 	    psp->pr_reg[R_PC] == ptb->ptb_addr);
4009*7c478bd9Sstevel@tonic-gate }
4010*7c478bd9Sstevel@tonic-gate 
4011*7c478bd9Sstevel@tonic-gate static const mdb_se_ops_t proc_brkpt_ops = {
4012*7c478bd9Sstevel@tonic-gate 	pt_brkpt_ctor,		/* se_ctor */
4013*7c478bd9Sstevel@tonic-gate 	pt_brkpt_dtor,		/* se_dtor */
4014*7c478bd9Sstevel@tonic-gate 	pt_brkpt_info,		/* se_info */
4015*7c478bd9Sstevel@tonic-gate 	pt_brkpt_secmp,		/* se_secmp */
4016*7c478bd9Sstevel@tonic-gate 	pt_brkpt_vecmp,		/* se_vecmp */
4017*7c478bd9Sstevel@tonic-gate 	pt_brkpt_arm,		/* se_arm */
4018*7c478bd9Sstevel@tonic-gate 	pt_brkpt_disarm,	/* se_disarm */
4019*7c478bd9Sstevel@tonic-gate 	pt_brkpt_cont,		/* se_cont */
4020*7c478bd9Sstevel@tonic-gate 	pt_brkpt_match		/* se_match */
4021*7c478bd9Sstevel@tonic-gate };
4022*7c478bd9Sstevel@tonic-gate 
4023*7c478bd9Sstevel@tonic-gate static int
4024*7c478bd9Sstevel@tonic-gate pt_wapt_ctor(mdb_tgt_t *t, mdb_sespec_t *sep, void *args)
4025*7c478bd9Sstevel@tonic-gate {
4026*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle == NULL || Pstate(t->t_pshandle) >= PS_LOST)
4027*7c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_NOPROC));
4028*7c478bd9Sstevel@tonic-gate 
4029*7c478bd9Sstevel@tonic-gate 	sep->se_data = mdb_alloc(sizeof (prwatch_t), UM_SLEEP);
4030*7c478bd9Sstevel@tonic-gate 	bcopy(args, sep->se_data, sizeof (prwatch_t));
4031*7c478bd9Sstevel@tonic-gate 	return (0);
4032*7c478bd9Sstevel@tonic-gate }
4033*7c478bd9Sstevel@tonic-gate 
4034*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4035*7c478bd9Sstevel@tonic-gate static void
4036*7c478bd9Sstevel@tonic-gate pt_wapt_dtor(mdb_tgt_t *t, mdb_sespec_t *sep)
4037*7c478bd9Sstevel@tonic-gate {
4038*7c478bd9Sstevel@tonic-gate 	mdb_free(sep->se_data, sizeof (prwatch_t));
4039*7c478bd9Sstevel@tonic-gate }
4040*7c478bd9Sstevel@tonic-gate 
4041*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4042*7c478bd9Sstevel@tonic-gate static char *
4043*7c478bd9Sstevel@tonic-gate pt_wapt_info(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_vespec_t *vep,
4044*7c478bd9Sstevel@tonic-gate     mdb_tgt_spec_desc_t *sp, char *buf, size_t nbytes)
4045*7c478bd9Sstevel@tonic-gate {
4046*7c478bd9Sstevel@tonic-gate 	prwatch_t *wp = vep != NULL ? vep->ve_args : sep->se_data;
4047*7c478bd9Sstevel@tonic-gate 	char desc[24];
4048*7c478bd9Sstevel@tonic-gate 
4049*7c478bd9Sstevel@tonic-gate 	ASSERT(wp->pr_wflags != 0);
4050*7c478bd9Sstevel@tonic-gate 	desc[0] = '\0';
4051*7c478bd9Sstevel@tonic-gate 
4052*7c478bd9Sstevel@tonic-gate 	switch (wp->pr_wflags) {
4053*7c478bd9Sstevel@tonic-gate 	case WA_READ:
4054*7c478bd9Sstevel@tonic-gate 		(void) strcat(desc, "/read");
4055*7c478bd9Sstevel@tonic-gate 		break;
4056*7c478bd9Sstevel@tonic-gate 	case WA_WRITE:
4057*7c478bd9Sstevel@tonic-gate 		(void) strcat(desc, "/write");
4058*7c478bd9Sstevel@tonic-gate 		break;
4059*7c478bd9Sstevel@tonic-gate 	case WA_EXEC:
4060*7c478bd9Sstevel@tonic-gate 		(void) strcat(desc, "/exec");
4061*7c478bd9Sstevel@tonic-gate 		break;
4062*7c478bd9Sstevel@tonic-gate 	default:
4063*7c478bd9Sstevel@tonic-gate 		if (wp->pr_wflags & WA_READ)
4064*7c478bd9Sstevel@tonic-gate 			(void) strcat(desc, "/r");
4065*7c478bd9Sstevel@tonic-gate 		if (wp->pr_wflags & WA_WRITE)
4066*7c478bd9Sstevel@tonic-gate 			(void) strcat(desc, "/w");
4067*7c478bd9Sstevel@tonic-gate 		if (wp->pr_wflags & WA_EXEC)
4068*7c478bd9Sstevel@tonic-gate 			(void) strcat(desc, "/x");
4069*7c478bd9Sstevel@tonic-gate 	}
4070*7c478bd9Sstevel@tonic-gate 
4071*7c478bd9Sstevel@tonic-gate 	(void) mdb_iob_snprintf(buf, nbytes, "stop on %s of [%la, %la)",
4072*7c478bd9Sstevel@tonic-gate 	    desc + 1, wp->pr_vaddr, wp->pr_vaddr + wp->pr_size);
4073*7c478bd9Sstevel@tonic-gate 
4074*7c478bd9Sstevel@tonic-gate 	sp->spec_base = wp->pr_vaddr;
4075*7c478bd9Sstevel@tonic-gate 	sp->spec_size = wp->pr_size;
4076*7c478bd9Sstevel@tonic-gate 
4077*7c478bd9Sstevel@tonic-gate 	return (buf);
4078*7c478bd9Sstevel@tonic-gate }
4079*7c478bd9Sstevel@tonic-gate 
4080*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4081*7c478bd9Sstevel@tonic-gate static int
4082*7c478bd9Sstevel@tonic-gate pt_wapt_secmp(mdb_tgt_t *t, mdb_sespec_t *sep, void *args)
4083*7c478bd9Sstevel@tonic-gate {
4084*7c478bd9Sstevel@tonic-gate 	prwatch_t *wp1 = sep->se_data;
4085*7c478bd9Sstevel@tonic-gate 	prwatch_t *wp2 = args;
4086*7c478bd9Sstevel@tonic-gate 
4087*7c478bd9Sstevel@tonic-gate 	return (wp1->pr_vaddr == wp2->pr_vaddr &&
4088*7c478bd9Sstevel@tonic-gate 	    wp1->pr_size == wp2->pr_size && wp1->pr_wflags == wp2->pr_wflags);
4089*7c478bd9Sstevel@tonic-gate }
4090*7c478bd9Sstevel@tonic-gate 
4091*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4092*7c478bd9Sstevel@tonic-gate static int
4093*7c478bd9Sstevel@tonic-gate pt_wapt_vecmp(mdb_tgt_t *t, mdb_vespec_t *vep, void *args)
4094*7c478bd9Sstevel@tonic-gate {
4095*7c478bd9Sstevel@tonic-gate 	prwatch_t *wp1 = vep->ve_args;
4096*7c478bd9Sstevel@tonic-gate 	prwatch_t *wp2 = args;
4097*7c478bd9Sstevel@tonic-gate 
4098*7c478bd9Sstevel@tonic-gate 	return (wp1->pr_vaddr == wp2->pr_vaddr &&
4099*7c478bd9Sstevel@tonic-gate 	    wp1->pr_size == wp2->pr_size && wp1->pr_wflags == wp2->pr_wflags);
4100*7c478bd9Sstevel@tonic-gate }
4101*7c478bd9Sstevel@tonic-gate 
4102*7c478bd9Sstevel@tonic-gate static int
4103*7c478bd9Sstevel@tonic-gate pt_wapt_arm(mdb_tgt_t *t, mdb_sespec_t *sep)
4104*7c478bd9Sstevel@tonic-gate {
4105*7c478bd9Sstevel@tonic-gate 	return (Psetwapt(t->t_pshandle, sep->se_data));
4106*7c478bd9Sstevel@tonic-gate }
4107*7c478bd9Sstevel@tonic-gate 
4108*7c478bd9Sstevel@tonic-gate static int
4109*7c478bd9Sstevel@tonic-gate pt_wapt_disarm(mdb_tgt_t *t, mdb_sespec_t *sep)
4110*7c478bd9Sstevel@tonic-gate {
4111*7c478bd9Sstevel@tonic-gate 	return (Pdelwapt(t->t_pshandle, sep->se_data));
4112*7c478bd9Sstevel@tonic-gate }
4113*7c478bd9Sstevel@tonic-gate 
4114*7c478bd9Sstevel@tonic-gate /*
4115*7c478bd9Sstevel@tonic-gate  * Determine whether the specified sespec is an armed breakpoint at the
4116*7c478bd9Sstevel@tonic-gate  * given %pc.  We use this to find conflicts with watchpoints below.
4117*7c478bd9Sstevel@tonic-gate  */
4118*7c478bd9Sstevel@tonic-gate static int
4119*7c478bd9Sstevel@tonic-gate pt_bp_overlap(mdb_sespec_t *sep, uintptr_t pc)
4120*7c478bd9Sstevel@tonic-gate {
4121*7c478bd9Sstevel@tonic-gate 	pt_brkpt_t *ptb = sep->se_data;
4122*7c478bd9Sstevel@tonic-gate 
4123*7c478bd9Sstevel@tonic-gate 	return (sep->se_state == MDB_TGT_SPEC_ARMED &&
4124*7c478bd9Sstevel@tonic-gate 	    sep->se_ops == &proc_brkpt_ops && ptb->ptb_addr == pc);
4125*7c478bd9Sstevel@tonic-gate }
4126*7c478bd9Sstevel@tonic-gate 
4127*7c478bd9Sstevel@tonic-gate /*
4128*7c478bd9Sstevel@tonic-gate  * We step over watchpoints using Pxecwapt() in libproc.  If a conflicting
4129*7c478bd9Sstevel@tonic-gate  * breakpoint is present, we must temporarily disarm it before stepping
4130*7c478bd9Sstevel@tonic-gate  * over the watchpoint so we do not immediately re-trigger the breakpoint.
4131*7c478bd9Sstevel@tonic-gate  * This is similar to the case handled in pt_brkpt_cont(), above.
4132*7c478bd9Sstevel@tonic-gate  */
4133*7c478bd9Sstevel@tonic-gate static int
4134*7c478bd9Sstevel@tonic-gate pt_wapt_cont(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_tgt_status_t *tsp)
4135*7c478bd9Sstevel@tonic-gate {
4136*7c478bd9Sstevel@tonic-gate 	const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp;
4137*7c478bd9Sstevel@tonic-gate 	mdb_sespec_t *bep = NULL;
4138*7c478bd9Sstevel@tonic-gate 	int status = -1;
4139*7c478bd9Sstevel@tonic-gate 	int error;
4140*7c478bd9Sstevel@tonic-gate 
4141*7c478bd9Sstevel@tonic-gate 	/*
4142*7c478bd9Sstevel@tonic-gate 	 * If the PC no longer matches our original address, then the user has
4143*7c478bd9Sstevel@tonic-gate 	 * changed it while we have been stopped. In this case, it no longer
4144*7c478bd9Sstevel@tonic-gate 	 * makes any sense to continue over this instruction.  We return as if
4145*7c478bd9Sstevel@tonic-gate 	 * we continued normally.
4146*7c478bd9Sstevel@tonic-gate 	 */
4147*7c478bd9Sstevel@tonic-gate 	if ((uintptr_t)psp->pr_info.si_pc != psp->pr_reg[R_PC])
4148*7c478bd9Sstevel@tonic-gate 		return (pt_status(t, tsp));
4149*7c478bd9Sstevel@tonic-gate 
4150*7c478bd9Sstevel@tonic-gate 	if (psp->pr_info.si_code != TRAP_XWATCH) {
4151*7c478bd9Sstevel@tonic-gate 		for (bep = mdb_list_next(&t->t_active); bep != NULL;
4152*7c478bd9Sstevel@tonic-gate 		    bep = mdb_list_next(bep)) {
4153*7c478bd9Sstevel@tonic-gate 			if (pt_bp_overlap(bep, psp->pr_reg[R_PC])) {
4154*7c478bd9Sstevel@tonic-gate 				(void) bep->se_ops->se_disarm(t, bep);
4155*7c478bd9Sstevel@tonic-gate 				bep->se_state = MDB_TGT_SPEC_ACTIVE;
4156*7c478bd9Sstevel@tonic-gate 				break;
4157*7c478bd9Sstevel@tonic-gate 			}
4158*7c478bd9Sstevel@tonic-gate 		}
4159*7c478bd9Sstevel@tonic-gate 	}
4160*7c478bd9Sstevel@tonic-gate 
4161*7c478bd9Sstevel@tonic-gate 	if (Pxecwapt(t->t_pshandle, sep->se_data) == 0)
4162*7c478bd9Sstevel@tonic-gate 		status = pt_status(t, tsp);
4163*7c478bd9Sstevel@tonic-gate 
4164*7c478bd9Sstevel@tonic-gate 	error = errno; /* save errno from Pxecwapt or pt_status */
4165*7c478bd9Sstevel@tonic-gate 
4166*7c478bd9Sstevel@tonic-gate 	if (bep != NULL)
4167*7c478bd9Sstevel@tonic-gate 		mdb_tgt_sespec_arm_one(t, bep);
4168*7c478bd9Sstevel@tonic-gate 
4169*7c478bd9Sstevel@tonic-gate 	(void) set_errno(error);
4170*7c478bd9Sstevel@tonic-gate 	return (status);
4171*7c478bd9Sstevel@tonic-gate }
4172*7c478bd9Sstevel@tonic-gate 
4173*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4174*7c478bd9Sstevel@tonic-gate static int
4175*7c478bd9Sstevel@tonic-gate pt_wapt_match(mdb_tgt_t *t, mdb_sespec_t *sep, mdb_tgt_status_t *tsp)
4176*7c478bd9Sstevel@tonic-gate {
4177*7c478bd9Sstevel@tonic-gate 	const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp;
4178*7c478bd9Sstevel@tonic-gate 	prwatch_t *wp = sep->se_data;
4179*7c478bd9Sstevel@tonic-gate 
4180*7c478bd9Sstevel@tonic-gate 	return (psp->pr_why == PR_FAULTED && psp->pr_what == FLTWATCH &&
4181*7c478bd9Sstevel@tonic-gate 	    (uintptr_t)psp->pr_info.si_addr - wp->pr_vaddr < wp->pr_size);
4182*7c478bd9Sstevel@tonic-gate }
4183*7c478bd9Sstevel@tonic-gate 
4184*7c478bd9Sstevel@tonic-gate static const mdb_se_ops_t proc_wapt_ops = {
4185*7c478bd9Sstevel@tonic-gate 	pt_wapt_ctor,		/* se_ctor */
4186*7c478bd9Sstevel@tonic-gate 	pt_wapt_dtor,		/* se_dtor */
4187*7c478bd9Sstevel@tonic-gate 	pt_wapt_info,		/* se_info */
4188*7c478bd9Sstevel@tonic-gate 	pt_wapt_secmp,		/* se_secmp */
4189*7c478bd9Sstevel@tonic-gate 	pt_wapt_vecmp,		/* se_vecmp */
4190*7c478bd9Sstevel@tonic-gate 	pt_wapt_arm,		/* se_arm */
4191*7c478bd9Sstevel@tonic-gate 	pt_wapt_disarm,		/* se_disarm */
4192*7c478bd9Sstevel@tonic-gate 	pt_wapt_cont,		/* se_cont */
4193*7c478bd9Sstevel@tonic-gate 	pt_wapt_match		/* se_match */
4194*7c478bd9Sstevel@tonic-gate };
4195*7c478bd9Sstevel@tonic-gate 
4196*7c478bd9Sstevel@tonic-gate static void
4197*7c478bd9Sstevel@tonic-gate pt_bparg_dtor(mdb_vespec_t *vep)
4198*7c478bd9Sstevel@tonic-gate {
4199*7c478bd9Sstevel@tonic-gate 	pt_bparg_t *pta = vep->ve_args;
4200*7c478bd9Sstevel@tonic-gate 
4201*7c478bd9Sstevel@tonic-gate 	if (pta->pta_symbol != NULL)
4202*7c478bd9Sstevel@tonic-gate 		strfree(pta->pta_symbol);
4203*7c478bd9Sstevel@tonic-gate 
4204*7c478bd9Sstevel@tonic-gate 	mdb_free(pta, sizeof (pt_bparg_t));
4205*7c478bd9Sstevel@tonic-gate }
4206*7c478bd9Sstevel@tonic-gate 
4207*7c478bd9Sstevel@tonic-gate static int
4208*7c478bd9Sstevel@tonic-gate pt_add_vbrkpt(mdb_tgt_t *t, uintptr_t addr,
4209*7c478bd9Sstevel@tonic-gate     int spec_flags, mdb_tgt_se_f *func, void *data)
4210*7c478bd9Sstevel@tonic-gate {
4211*7c478bd9Sstevel@tonic-gate 	pt_bparg_t *pta = mdb_alloc(sizeof (pt_bparg_t), UM_SLEEP);
4212*7c478bd9Sstevel@tonic-gate 
4213*7c478bd9Sstevel@tonic-gate 	pta->pta_symbol = NULL;
4214*7c478bd9Sstevel@tonic-gate 	pta->pta_addr = addr;
4215*7c478bd9Sstevel@tonic-gate 
4216*7c478bd9Sstevel@tonic-gate 	return (mdb_tgt_vespec_insert(t, &proc_brkpt_ops, spec_flags,
4217*7c478bd9Sstevel@tonic-gate 	    func, data, pta, pt_bparg_dtor));
4218*7c478bd9Sstevel@tonic-gate }
4219*7c478bd9Sstevel@tonic-gate 
4220*7c478bd9Sstevel@tonic-gate static int
4221*7c478bd9Sstevel@tonic-gate pt_add_sbrkpt(mdb_tgt_t *t, const char *sym,
4222*7c478bd9Sstevel@tonic-gate     int spec_flags, mdb_tgt_se_f *func, void *data)
4223*7c478bd9Sstevel@tonic-gate {
4224*7c478bd9Sstevel@tonic-gate 	pt_bparg_t *pta;
4225*7c478bd9Sstevel@tonic-gate 
4226*7c478bd9Sstevel@tonic-gate 	if (sym[0] == '`') {
4227*7c478bd9Sstevel@tonic-gate 		(void) set_errno(EMDB_NOOBJ);
4228*7c478bd9Sstevel@tonic-gate 		return (0);
4229*7c478bd9Sstevel@tonic-gate 	}
4230*7c478bd9Sstevel@tonic-gate 
4231*7c478bd9Sstevel@tonic-gate 	if (sym[strlen(sym) - 1] == '`') {
4232*7c478bd9Sstevel@tonic-gate 		(void) set_errno(EMDB_NOSYM);
4233*7c478bd9Sstevel@tonic-gate 		return (0);
4234*7c478bd9Sstevel@tonic-gate 	}
4235*7c478bd9Sstevel@tonic-gate 
4236*7c478bd9Sstevel@tonic-gate 	pta = mdb_alloc(sizeof (pt_bparg_t), UM_SLEEP);
4237*7c478bd9Sstevel@tonic-gate 	pta->pta_symbol = strdup(sym);
4238*7c478bd9Sstevel@tonic-gate 	pta->pta_addr = NULL;
4239*7c478bd9Sstevel@tonic-gate 
4240*7c478bd9Sstevel@tonic-gate 	return (mdb_tgt_vespec_insert(t, &proc_brkpt_ops, spec_flags,
4241*7c478bd9Sstevel@tonic-gate 	    func, data, pta, pt_bparg_dtor));
4242*7c478bd9Sstevel@tonic-gate }
4243*7c478bd9Sstevel@tonic-gate 
4244*7c478bd9Sstevel@tonic-gate static int
4245*7c478bd9Sstevel@tonic-gate pt_wparg_overlap(const prwatch_t *wp1, const prwatch_t *wp2)
4246*7c478bd9Sstevel@tonic-gate {
4247*7c478bd9Sstevel@tonic-gate 	if (wp2->pr_vaddr + wp2->pr_size <= wp1->pr_vaddr)
4248*7c478bd9Sstevel@tonic-gate 		return (0); /* no range overlap */
4249*7c478bd9Sstevel@tonic-gate 
4250*7c478bd9Sstevel@tonic-gate 	if (wp1->pr_vaddr + wp1->pr_size <= wp2->pr_vaddr)
4251*7c478bd9Sstevel@tonic-gate 		return (0); /* no range overlap */
4252*7c478bd9Sstevel@tonic-gate 
4253*7c478bd9Sstevel@tonic-gate 	return (wp1->pr_vaddr != wp2->pr_vaddr ||
4254*7c478bd9Sstevel@tonic-gate 	    wp1->pr_size != wp2->pr_size || wp1->pr_wflags != wp2->pr_wflags);
4255*7c478bd9Sstevel@tonic-gate }
4256*7c478bd9Sstevel@tonic-gate 
4257*7c478bd9Sstevel@tonic-gate static void
4258*7c478bd9Sstevel@tonic-gate pt_wparg_dtor(mdb_vespec_t *vep)
4259*7c478bd9Sstevel@tonic-gate {
4260*7c478bd9Sstevel@tonic-gate 	mdb_free(vep->ve_args, sizeof (prwatch_t));
4261*7c478bd9Sstevel@tonic-gate }
4262*7c478bd9Sstevel@tonic-gate 
4263*7c478bd9Sstevel@tonic-gate static int
4264*7c478bd9Sstevel@tonic-gate pt_add_vwapt(mdb_tgt_t *t, uintptr_t addr, size_t len, uint_t wflags,
4265*7c478bd9Sstevel@tonic-gate     int spec_flags, mdb_tgt_se_f *func, void *data)
4266*7c478bd9Sstevel@tonic-gate {
4267*7c478bd9Sstevel@tonic-gate 	prwatch_t *wp = mdb_alloc(sizeof (prwatch_t), UM_SLEEP);
4268*7c478bd9Sstevel@tonic-gate 	mdb_sespec_t *sep;
4269*7c478bd9Sstevel@tonic-gate 
4270*7c478bd9Sstevel@tonic-gate 	wp->pr_vaddr = addr;
4271*7c478bd9Sstevel@tonic-gate 	wp->pr_size = len;
4272*7c478bd9Sstevel@tonic-gate 	wp->pr_wflags = 0;
4273*7c478bd9Sstevel@tonic-gate 
4274*7c478bd9Sstevel@tonic-gate 	if (wflags & MDB_TGT_WA_R)
4275*7c478bd9Sstevel@tonic-gate 		wp->pr_wflags |= WA_READ;
4276*7c478bd9Sstevel@tonic-gate 	if (wflags & MDB_TGT_WA_W)
4277*7c478bd9Sstevel@tonic-gate 		wp->pr_wflags |= WA_WRITE;
4278*7c478bd9Sstevel@tonic-gate 	if (wflags & MDB_TGT_WA_X)
4279*7c478bd9Sstevel@tonic-gate 		wp->pr_wflags |= WA_EXEC;
4280*7c478bd9Sstevel@tonic-gate 
4281*7c478bd9Sstevel@tonic-gate 	for (sep = mdb_list_next(&t->t_active); sep; sep = mdb_list_next(sep)) {
4282*7c478bd9Sstevel@tonic-gate 		if (sep->se_ops == &proc_wapt_ops &&
4283*7c478bd9Sstevel@tonic-gate 		    mdb_list_next(&sep->se_velist) != NULL &&
4284*7c478bd9Sstevel@tonic-gate 		    pt_wparg_overlap(wp, sep->se_data))
4285*7c478bd9Sstevel@tonic-gate 			goto dup;
4286*7c478bd9Sstevel@tonic-gate 	}
4287*7c478bd9Sstevel@tonic-gate 
4288*7c478bd9Sstevel@tonic-gate 	for (sep = mdb_list_next(&t->t_idle); sep; sep = mdb_list_next(sep)) {
4289*7c478bd9Sstevel@tonic-gate 		if (sep->se_ops == &proc_wapt_ops && pt_wparg_overlap(wp,
4290*7c478bd9Sstevel@tonic-gate 		    ((mdb_vespec_t *)mdb_list_next(&sep->se_velist))->ve_args))
4291*7c478bd9Sstevel@tonic-gate 			goto dup;
4292*7c478bd9Sstevel@tonic-gate 	}
4293*7c478bd9Sstevel@tonic-gate 
4294*7c478bd9Sstevel@tonic-gate 	return (mdb_tgt_vespec_insert(t, &proc_wapt_ops, spec_flags,
4295*7c478bd9Sstevel@tonic-gate 	    func, data, wp, pt_wparg_dtor));
4296*7c478bd9Sstevel@tonic-gate 
4297*7c478bd9Sstevel@tonic-gate dup:
4298*7c478bd9Sstevel@tonic-gate 	mdb_free(wp, sizeof (prwatch_t));
4299*7c478bd9Sstevel@tonic-gate 	(void) set_errno(EMDB_WPDUP);
4300*7c478bd9Sstevel@tonic-gate 	return (0);
4301*7c478bd9Sstevel@tonic-gate }
4302*7c478bd9Sstevel@tonic-gate 
4303*7c478bd9Sstevel@tonic-gate static int
4304*7c478bd9Sstevel@tonic-gate pt_add_sysenter(mdb_tgt_t *t, int sysnum,
4305*7c478bd9Sstevel@tonic-gate     int spec_flags, mdb_tgt_se_f *func, void *data)
4306*7c478bd9Sstevel@tonic-gate {
4307*7c478bd9Sstevel@tonic-gate 	if (sysnum <= 0 || sysnum > PRMAXSYS) {
4308*7c478bd9Sstevel@tonic-gate 		(void) set_errno(EMDB_BADSYSNUM);
4309*7c478bd9Sstevel@tonic-gate 		return (0);
4310*7c478bd9Sstevel@tonic-gate 	}
4311*7c478bd9Sstevel@tonic-gate 
4312*7c478bd9Sstevel@tonic-gate 	return (mdb_tgt_vespec_insert(t, &proc_sysenter_ops, spec_flags,
4313*7c478bd9Sstevel@tonic-gate 	    func, data, (void *)(uintptr_t)sysnum, no_ve_dtor));
4314*7c478bd9Sstevel@tonic-gate }
4315*7c478bd9Sstevel@tonic-gate 
4316*7c478bd9Sstevel@tonic-gate static int
4317*7c478bd9Sstevel@tonic-gate pt_add_sysexit(mdb_tgt_t *t, int sysnum,
4318*7c478bd9Sstevel@tonic-gate     int spec_flags, mdb_tgt_se_f *func, void *data)
4319*7c478bd9Sstevel@tonic-gate {
4320*7c478bd9Sstevel@tonic-gate 	if (sysnum <= 0 || sysnum > PRMAXSYS) {
4321*7c478bd9Sstevel@tonic-gate 		(void) set_errno(EMDB_BADSYSNUM);
4322*7c478bd9Sstevel@tonic-gate 		return (0);
4323*7c478bd9Sstevel@tonic-gate 	}
4324*7c478bd9Sstevel@tonic-gate 
4325*7c478bd9Sstevel@tonic-gate 	return (mdb_tgt_vespec_insert(t, &proc_sysexit_ops, spec_flags,
4326*7c478bd9Sstevel@tonic-gate 	    func, data, (void *)(uintptr_t)sysnum, no_ve_dtor));
4327*7c478bd9Sstevel@tonic-gate }
4328*7c478bd9Sstevel@tonic-gate 
4329*7c478bd9Sstevel@tonic-gate static int
4330*7c478bd9Sstevel@tonic-gate pt_add_signal(mdb_tgt_t *t, int signum,
4331*7c478bd9Sstevel@tonic-gate     int spec_flags, mdb_tgt_se_f *func, void *data)
4332*7c478bd9Sstevel@tonic-gate {
4333*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
4334*7c478bd9Sstevel@tonic-gate 
4335*7c478bd9Sstevel@tonic-gate 	if (signum <= 0 || signum > pt->p_maxsig) {
4336*7c478bd9Sstevel@tonic-gate 		(void) set_errno(EMDB_BADSIGNUM);
4337*7c478bd9Sstevel@tonic-gate 		return (0);
4338*7c478bd9Sstevel@tonic-gate 	}
4339*7c478bd9Sstevel@tonic-gate 
4340*7c478bd9Sstevel@tonic-gate 	return (mdb_tgt_vespec_insert(t, &proc_signal_ops, spec_flags,
4341*7c478bd9Sstevel@tonic-gate 	    func, data, (void *)(uintptr_t)signum, no_ve_dtor));
4342*7c478bd9Sstevel@tonic-gate }
4343*7c478bd9Sstevel@tonic-gate 
4344*7c478bd9Sstevel@tonic-gate static int
4345*7c478bd9Sstevel@tonic-gate pt_add_fault(mdb_tgt_t *t, int fltnum,
4346*7c478bd9Sstevel@tonic-gate     int spec_flags, mdb_tgt_se_f *func, void *data)
4347*7c478bd9Sstevel@tonic-gate {
4348*7c478bd9Sstevel@tonic-gate 	if (fltnum <= 0 || fltnum > PRMAXFAULT) {
4349*7c478bd9Sstevel@tonic-gate 		(void) set_errno(EMDB_BADFLTNUM);
4350*7c478bd9Sstevel@tonic-gate 		return (0);
4351*7c478bd9Sstevel@tonic-gate 	}
4352*7c478bd9Sstevel@tonic-gate 
4353*7c478bd9Sstevel@tonic-gate 	return (mdb_tgt_vespec_insert(t, &proc_fault_ops, spec_flags,
4354*7c478bd9Sstevel@tonic-gate 	    func, data, (void *)(uintptr_t)fltnum, no_ve_dtor));
4355*7c478bd9Sstevel@tonic-gate }
4356*7c478bd9Sstevel@tonic-gate 
4357*7c478bd9Sstevel@tonic-gate static int
4358*7c478bd9Sstevel@tonic-gate pt_getareg(mdb_tgt_t *t, mdb_tgt_tid_t tid,
4359*7c478bd9Sstevel@tonic-gate     const char *rname, mdb_tgt_reg_t *rp)
4360*7c478bd9Sstevel@tonic-gate {
4361*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
4362*7c478bd9Sstevel@tonic-gate 	prgregset_t grs;
4363*7c478bd9Sstevel@tonic-gate 	mdb_var_t *v;
4364*7c478bd9Sstevel@tonic-gate 
4365*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle == NULL)
4366*7c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_NOPROC));
4367*7c478bd9Sstevel@tonic-gate 
4368*7c478bd9Sstevel@tonic-gate 	if ((v = mdb_nv_lookup(&pt->p_regs, rname)) != NULL) {
4369*7c478bd9Sstevel@tonic-gate 		uintmax_t rd_nval = mdb_nv_get_value(v);
4370*7c478bd9Sstevel@tonic-gate 		ushort_t rd_num = MDB_TGT_R_NUM(rd_nval);
4371*7c478bd9Sstevel@tonic-gate 		ushort_t rd_flags = MDB_TGT_R_FLAGS(rd_nval);
4372*7c478bd9Sstevel@tonic-gate 
4373*7c478bd9Sstevel@tonic-gate 		if (!MDB_TGT_R_IS_FP(rd_flags)) {
4374*7c478bd9Sstevel@tonic-gate 			mdb_tgt_reg_t r = 0;
4375*7c478bd9Sstevel@tonic-gate 
4376*7c478bd9Sstevel@tonic-gate #if defined(__sparc) && defined(_ILP32)
4377*7c478bd9Sstevel@tonic-gate 			/*
4378*7c478bd9Sstevel@tonic-gate 			 * If we are debugging on 32-bit SPARC, the globals and
4379*7c478bd9Sstevel@tonic-gate 			 * outs can have 32 upper bits hiding in the xregs.
4380*7c478bd9Sstevel@tonic-gate 			 */
4381*7c478bd9Sstevel@tonic-gate 			/* LINTED */
4382*7c478bd9Sstevel@tonic-gate 			int is_g = (rd_num >= R_G0 && rd_num <= R_G7);
4383*7c478bd9Sstevel@tonic-gate 			int is_o = (rd_num >= R_O0 && rd_num <= R_O7);
4384*7c478bd9Sstevel@tonic-gate 			prxregset_t xrs;
4385*7c478bd9Sstevel@tonic-gate 
4386*7c478bd9Sstevel@tonic-gate 			if (is_g && PTL_GETXREGS(t, tid, &xrs) == 0 &&
4387*7c478bd9Sstevel@tonic-gate 			    xrs.pr_type == XR_TYPE_V8P) {
4388*7c478bd9Sstevel@tonic-gate 				r |= (uint64_t)xrs.pr_un.pr_v8p.pr_xg[
4389*7c478bd9Sstevel@tonic-gate 				    rd_num - R_G0 + XR_G0] << 32;
4390*7c478bd9Sstevel@tonic-gate 			}
4391*7c478bd9Sstevel@tonic-gate 
4392*7c478bd9Sstevel@tonic-gate 			if (is_o && PTL_GETXREGS(t, tid, &xrs) == 0 &&
4393*7c478bd9Sstevel@tonic-gate 			    xrs.pr_type == XR_TYPE_V8P) {
4394*7c478bd9Sstevel@tonic-gate 				r |= (uint64_t)xrs.pr_un.pr_v8p.pr_xo[
4395*7c478bd9Sstevel@tonic-gate 				    rd_num - R_O0 + XR_O0] << 32;
4396*7c478bd9Sstevel@tonic-gate 			}
4397*7c478bd9Sstevel@tonic-gate #endif	/* __sparc && _ILP32 */
4398*7c478bd9Sstevel@tonic-gate 
4399*7c478bd9Sstevel@tonic-gate 			/*
4400*7c478bd9Sstevel@tonic-gate 			 * Avoid sign-extension by casting: recall that procfs
4401*7c478bd9Sstevel@tonic-gate 			 * defines prgreg_t as a long or int and our native
4402*7c478bd9Sstevel@tonic-gate 			 * register handling uses uint64_t's.
4403*7c478bd9Sstevel@tonic-gate 			 */
4404*7c478bd9Sstevel@tonic-gate 			if (PTL_GETREGS(t, tid, grs) == 0) {
4405*7c478bd9Sstevel@tonic-gate 				*rp = r | (ulong_t)grs[rd_num];
4406*7c478bd9Sstevel@tonic-gate 				return (0);
4407*7c478bd9Sstevel@tonic-gate 			}
4408*7c478bd9Sstevel@tonic-gate 			return (-1);
4409*7c478bd9Sstevel@tonic-gate 		} else
4410*7c478bd9Sstevel@tonic-gate 			return (pt_getfpreg(t, tid, rd_num, rd_flags, rp));
4411*7c478bd9Sstevel@tonic-gate 	}
4412*7c478bd9Sstevel@tonic-gate 
4413*7c478bd9Sstevel@tonic-gate 	return (set_errno(EMDB_BADREG));
4414*7c478bd9Sstevel@tonic-gate }
4415*7c478bd9Sstevel@tonic-gate 
4416*7c478bd9Sstevel@tonic-gate static int
4417*7c478bd9Sstevel@tonic-gate pt_putareg(mdb_tgt_t *t, mdb_tgt_tid_t tid, const char *rname, mdb_tgt_reg_t r)
4418*7c478bd9Sstevel@tonic-gate {
4419*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
4420*7c478bd9Sstevel@tonic-gate 	prgregset_t grs;
4421*7c478bd9Sstevel@tonic-gate 	mdb_var_t *v;
4422*7c478bd9Sstevel@tonic-gate 
4423*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle == NULL)
4424*7c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_NOPROC));
4425*7c478bd9Sstevel@tonic-gate 
4426*7c478bd9Sstevel@tonic-gate 	if ((v = mdb_nv_lookup(&pt->p_regs, rname)) != NULL) {
4427*7c478bd9Sstevel@tonic-gate 		uintmax_t rd_nval = mdb_nv_get_value(v);
4428*7c478bd9Sstevel@tonic-gate 		ushort_t rd_num = MDB_TGT_R_NUM(rd_nval);
4429*7c478bd9Sstevel@tonic-gate 		ushort_t rd_flags = MDB_TGT_R_FLAGS(rd_nval);
4430*7c478bd9Sstevel@tonic-gate 
4431*7c478bd9Sstevel@tonic-gate 		if (!MDB_TGT_R_IS_FP(rd_flags)) {
4432*7c478bd9Sstevel@tonic-gate #if defined(__sparc) && defined(_ILP32)
4433*7c478bd9Sstevel@tonic-gate 			/*
4434*7c478bd9Sstevel@tonic-gate 			 * If we are debugging on 32-bit SPARC, the globals and
4435*7c478bd9Sstevel@tonic-gate 			 * outs can have 32 upper bits stored in the xregs.
4436*7c478bd9Sstevel@tonic-gate 			 */
4437*7c478bd9Sstevel@tonic-gate 			/* LINTED */
4438*7c478bd9Sstevel@tonic-gate 			int is_g = (rd_num >= R_G0 && rd_num <= R_G7);
4439*7c478bd9Sstevel@tonic-gate 			int is_o = (rd_num >= R_O0 && rd_num <= R_O7);
4440*7c478bd9Sstevel@tonic-gate 			prxregset_t xrs;
4441*7c478bd9Sstevel@tonic-gate 
4442*7c478bd9Sstevel@tonic-gate 			if ((is_g || is_o) && PTL_GETXREGS(t, tid, &xrs) == 0 &&
4443*7c478bd9Sstevel@tonic-gate 			    xrs.pr_type == XR_TYPE_V8P) {
4444*7c478bd9Sstevel@tonic-gate 				if (is_g) {
4445*7c478bd9Sstevel@tonic-gate 					xrs.pr_un.pr_v8p.pr_xg[rd_num -
4446*7c478bd9Sstevel@tonic-gate 					    R_G0 + XR_G0] = (uint32_t)(r >> 32);
4447*7c478bd9Sstevel@tonic-gate 				} else if (is_o) {
4448*7c478bd9Sstevel@tonic-gate 					xrs.pr_un.pr_v8p.pr_xo[rd_num -
4449*7c478bd9Sstevel@tonic-gate 					    R_O0 + XR_O0] = (uint32_t)(r >> 32);
4450*7c478bd9Sstevel@tonic-gate 				}
4451*7c478bd9Sstevel@tonic-gate 
4452*7c478bd9Sstevel@tonic-gate 				if (PTL_SETXREGS(t, tid, &xrs) == -1)
4453*7c478bd9Sstevel@tonic-gate 					return (-1);
4454*7c478bd9Sstevel@tonic-gate 			}
4455*7c478bd9Sstevel@tonic-gate #endif	/* __sparc && _ILP32 */
4456*7c478bd9Sstevel@tonic-gate 
4457*7c478bd9Sstevel@tonic-gate 			if (PTL_GETREGS(t, tid, grs) == 0) {
4458*7c478bd9Sstevel@tonic-gate 				grs[rd_num] = (prgreg_t)r;
4459*7c478bd9Sstevel@tonic-gate 				return (PTL_SETREGS(t, tid, grs));
4460*7c478bd9Sstevel@tonic-gate 			}
4461*7c478bd9Sstevel@tonic-gate 			return (-1);
4462*7c478bd9Sstevel@tonic-gate 		} else
4463*7c478bd9Sstevel@tonic-gate 			return (pt_putfpreg(t, tid, rd_num, rd_flags, r));
4464*7c478bd9Sstevel@tonic-gate 	}
4465*7c478bd9Sstevel@tonic-gate 
4466*7c478bd9Sstevel@tonic-gate 	return (set_errno(EMDB_BADREG));
4467*7c478bd9Sstevel@tonic-gate }
4468*7c478bd9Sstevel@tonic-gate 
4469*7c478bd9Sstevel@tonic-gate static int
4470*7c478bd9Sstevel@tonic-gate pt_stack_call(pt_stkarg_t *psp, const prgregset_t grs, uint_t argc, long *argv)
4471*7c478bd9Sstevel@tonic-gate {
4472*7c478bd9Sstevel@tonic-gate 	psp->pstk_gotpc |= (grs[R_PC] != 0);
4473*7c478bd9Sstevel@tonic-gate 
4474*7c478bd9Sstevel@tonic-gate 	if (!psp->pstk_gotpc)
4475*7c478bd9Sstevel@tonic-gate 		return (0); /* skip initial zeroed frames */
4476*7c478bd9Sstevel@tonic-gate 
4477*7c478bd9Sstevel@tonic-gate 	return (psp->pstk_func(psp->pstk_private, grs[R_PC],
4478*7c478bd9Sstevel@tonic-gate 	    argc, argv, (const struct mdb_tgt_gregset *)grs));
4479*7c478bd9Sstevel@tonic-gate }
4480*7c478bd9Sstevel@tonic-gate 
4481*7c478bd9Sstevel@tonic-gate static int
4482*7c478bd9Sstevel@tonic-gate pt_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp,
4483*7c478bd9Sstevel@tonic-gate     mdb_tgt_stack_f *func, void *arg)
4484*7c478bd9Sstevel@tonic-gate {
4485*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle != NULL) {
4486*7c478bd9Sstevel@tonic-gate 		pt_stkarg_t pstk;
4487*7c478bd9Sstevel@tonic-gate 
4488*7c478bd9Sstevel@tonic-gate 		pstk.pstk_func = func;
4489*7c478bd9Sstevel@tonic-gate 		pstk.pstk_private = arg;
4490*7c478bd9Sstevel@tonic-gate 		pstk.pstk_gotpc = FALSE;
4491*7c478bd9Sstevel@tonic-gate 
4492*7c478bd9Sstevel@tonic-gate 		(void) Pstack_iter(t->t_pshandle, gsp->gregs,
4493*7c478bd9Sstevel@tonic-gate 		    (proc_stack_f *)pt_stack_call, &pstk);
4494*7c478bd9Sstevel@tonic-gate 
4495*7c478bd9Sstevel@tonic-gate 		return (0);
4496*7c478bd9Sstevel@tonic-gate 	}
4497*7c478bd9Sstevel@tonic-gate 
4498*7c478bd9Sstevel@tonic-gate 	return (set_errno(EMDB_NOPROC));
4499*7c478bd9Sstevel@tonic-gate }
4500*7c478bd9Sstevel@tonic-gate 
4501*7c478bd9Sstevel@tonic-gate static const mdb_tgt_ops_t proc_ops = {
4502*7c478bd9Sstevel@tonic-gate 	pt_setflags,				/* t_setflags */
4503*7c478bd9Sstevel@tonic-gate 	(int (*)()) mdb_tgt_notsup,		/* t_setcontext */
4504*7c478bd9Sstevel@tonic-gate 	pt_activate,				/* t_activate */
4505*7c478bd9Sstevel@tonic-gate 	pt_deactivate,				/* t_deactivate */
4506*7c478bd9Sstevel@tonic-gate 	pt_periodic,				/* t_periodic */
4507*7c478bd9Sstevel@tonic-gate 	pt_destroy,				/* t_destroy */
4508*7c478bd9Sstevel@tonic-gate 	pt_name,				/* t_name */
4509*7c478bd9Sstevel@tonic-gate 	(const char *(*)()) mdb_conf_isa,	/* t_isa */
4510*7c478bd9Sstevel@tonic-gate 	pt_platform,				/* t_platform */
4511*7c478bd9Sstevel@tonic-gate 	pt_uname,				/* t_uname */
4512*7c478bd9Sstevel@tonic-gate 	pt_dmodel,				/* t_dmodel */
4513*7c478bd9Sstevel@tonic-gate 	(ssize_t (*)()) mdb_tgt_notsup,		/* t_aread */
4514*7c478bd9Sstevel@tonic-gate 	(ssize_t (*)()) mdb_tgt_notsup,		/* t_awrite */
4515*7c478bd9Sstevel@tonic-gate 	pt_vread,				/* t_vread */
4516*7c478bd9Sstevel@tonic-gate 	pt_vwrite,				/* t_vwrite */
4517*7c478bd9Sstevel@tonic-gate 	(ssize_t (*)()) mdb_tgt_notsup,		/* t_pread */
4518*7c478bd9Sstevel@tonic-gate 	(ssize_t (*)()) mdb_tgt_notsup,		/* t_pwrite */
4519*7c478bd9Sstevel@tonic-gate 	pt_fread,				/* t_fread */
4520*7c478bd9Sstevel@tonic-gate 	pt_fwrite,				/* t_fwrite */
4521*7c478bd9Sstevel@tonic-gate 	(ssize_t (*)()) mdb_tgt_notsup,		/* t_ioread */
4522*7c478bd9Sstevel@tonic-gate 	(ssize_t (*)()) mdb_tgt_notsup,		/* t_iowrite */
4523*7c478bd9Sstevel@tonic-gate 	(int (*)()) mdb_tgt_notsup,		/* t_vtop */
4524*7c478bd9Sstevel@tonic-gate 	pt_lookup_by_name,			/* t_lookup_by_name */
4525*7c478bd9Sstevel@tonic-gate 	pt_lookup_by_addr,			/* t_lookup_by_addr */
4526*7c478bd9Sstevel@tonic-gate 	pt_symbol_iter,				/* t_symbol_iter */
4527*7c478bd9Sstevel@tonic-gate 	pt_mapping_iter,			/* t_mapping_iter */
4528*7c478bd9Sstevel@tonic-gate 	pt_object_iter,				/* t_object_iter */
4529*7c478bd9Sstevel@tonic-gate 	pt_addr_to_map,				/* t_addr_to_map */
4530*7c478bd9Sstevel@tonic-gate 	pt_name_to_map,				/* t_name_to_map */
4531*7c478bd9Sstevel@tonic-gate 	pt_addr_to_ctf,				/* t_addr_to_ctf */
4532*7c478bd9Sstevel@tonic-gate 	pt_name_to_ctf,				/* t_name_to_ctf */
4533*7c478bd9Sstevel@tonic-gate 	pt_status,				/* t_status */
4534*7c478bd9Sstevel@tonic-gate 	pt_run,					/* t_run */
4535*7c478bd9Sstevel@tonic-gate 	pt_step,				/* t_step */
4536*7c478bd9Sstevel@tonic-gate 	pt_step_out,				/* t_step_out */
4537*7c478bd9Sstevel@tonic-gate 	(int (*)()) mdb_tgt_notsup,		/* t_step_branch */
4538*7c478bd9Sstevel@tonic-gate 	pt_next,				/* t_next */
4539*7c478bd9Sstevel@tonic-gate 	pt_continue,				/* t_cont */
4540*7c478bd9Sstevel@tonic-gate 	pt_signal,				/* t_signal */
4541*7c478bd9Sstevel@tonic-gate 	pt_add_vbrkpt,				/* t_add_vbrkpt */
4542*7c478bd9Sstevel@tonic-gate 	pt_add_sbrkpt,				/* t_add_sbrkpt */
4543*7c478bd9Sstevel@tonic-gate 	(int (*)()) mdb_tgt_null,		/* t_add_pwapt */
4544*7c478bd9Sstevel@tonic-gate 	pt_add_vwapt,				/* t_add_vwapt */
4545*7c478bd9Sstevel@tonic-gate 	(int (*)()) mdb_tgt_null,		/* t_add_iowapt */
4546*7c478bd9Sstevel@tonic-gate 	pt_add_sysenter,			/* t_add_sysenter */
4547*7c478bd9Sstevel@tonic-gate 	pt_add_sysexit,				/* t_add_sysexit */
4548*7c478bd9Sstevel@tonic-gate 	pt_add_signal,				/* t_add_signal */
4549*7c478bd9Sstevel@tonic-gate 	pt_add_fault,				/* t_add_fault */
4550*7c478bd9Sstevel@tonic-gate 	pt_getareg,				/* t_getareg */
4551*7c478bd9Sstevel@tonic-gate 	pt_putareg,				/* t_putareg */
4552*7c478bd9Sstevel@tonic-gate 	pt_stack_iter				/* t_stack_iter */
4553*7c478bd9Sstevel@tonic-gate };
4554*7c478bd9Sstevel@tonic-gate 
4555*7c478bd9Sstevel@tonic-gate /*
4556*7c478bd9Sstevel@tonic-gate  * Utility function for converting libproc errno values to mdb error values
4557*7c478bd9Sstevel@tonic-gate  * for the ptl calls below.  Currently, we only need to convert ENOENT to
4558*7c478bd9Sstevel@tonic-gate  * EMDB_NOTHREAD to produce a more useful error message for the user.
4559*7c478bd9Sstevel@tonic-gate  */
4560*7c478bd9Sstevel@tonic-gate static int
4561*7c478bd9Sstevel@tonic-gate ptl_err(int error)
4562*7c478bd9Sstevel@tonic-gate {
4563*7c478bd9Sstevel@tonic-gate 	if (error != 0 && errno == ENOENT)
4564*7c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_NOTHREAD));
4565*7c478bd9Sstevel@tonic-gate 
4566*7c478bd9Sstevel@tonic-gate 	return (error);
4567*7c478bd9Sstevel@tonic-gate }
4568*7c478bd9Sstevel@tonic-gate 
4569*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4570*7c478bd9Sstevel@tonic-gate static mdb_tgt_tid_t
4571*7c478bd9Sstevel@tonic-gate pt_lwp_tid(mdb_tgt_t *t, void *tap)
4572*7c478bd9Sstevel@tonic-gate {
4573*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle != NULL)
4574*7c478bd9Sstevel@tonic-gate 		return (Pstatus(t->t_pshandle)->pr_lwp.pr_lwpid);
4575*7c478bd9Sstevel@tonic-gate 
4576*7c478bd9Sstevel@tonic-gate 	return (set_errno(EMDB_NOPROC));
4577*7c478bd9Sstevel@tonic-gate }
4578*7c478bd9Sstevel@tonic-gate 
4579*7c478bd9Sstevel@tonic-gate static int
4580*7c478bd9Sstevel@tonic-gate pt_lwp_add(mdb_addrvec_t *ap, const lwpstatus_t *psp)
4581*7c478bd9Sstevel@tonic-gate {
4582*7c478bd9Sstevel@tonic-gate 	mdb_addrvec_unshift(ap, psp->pr_lwpid);
4583*7c478bd9Sstevel@tonic-gate 	return (0);
4584*7c478bd9Sstevel@tonic-gate }
4585*7c478bd9Sstevel@tonic-gate 
4586*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4587*7c478bd9Sstevel@tonic-gate static int
4588*7c478bd9Sstevel@tonic-gate pt_lwp_iter(mdb_tgt_t *t, void *tap, mdb_addrvec_t *ap)
4589*7c478bd9Sstevel@tonic-gate {
4590*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle != NULL)
4591*7c478bd9Sstevel@tonic-gate 		return (Plwp_iter(t->t_pshandle, (proc_lwp_f *)pt_lwp_add, ap));
4592*7c478bd9Sstevel@tonic-gate 
4593*7c478bd9Sstevel@tonic-gate 	return (set_errno(EMDB_NOPROC));
4594*7c478bd9Sstevel@tonic-gate }
4595*7c478bd9Sstevel@tonic-gate 
4596*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4597*7c478bd9Sstevel@tonic-gate static int
4598*7c478bd9Sstevel@tonic-gate pt_lwp_getregs(mdb_tgt_t *t, void *tap, mdb_tgt_tid_t tid, prgregset_t gregs)
4599*7c478bd9Sstevel@tonic-gate {
4600*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle != NULL) {
4601*7c478bd9Sstevel@tonic-gate 		return (ptl_err(Plwp_getregs(t->t_pshandle,
4602*7c478bd9Sstevel@tonic-gate 		    (lwpid_t)tid, gregs)));
4603*7c478bd9Sstevel@tonic-gate 	}
4604*7c478bd9Sstevel@tonic-gate 	return (set_errno(EMDB_NOPROC));
4605*7c478bd9Sstevel@tonic-gate }
4606*7c478bd9Sstevel@tonic-gate 
4607*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4608*7c478bd9Sstevel@tonic-gate static int
4609*7c478bd9Sstevel@tonic-gate pt_lwp_setregs(mdb_tgt_t *t, void *tap, mdb_tgt_tid_t tid, prgregset_t gregs)
4610*7c478bd9Sstevel@tonic-gate {
4611*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle != NULL) {
4612*7c478bd9Sstevel@tonic-gate 		return (ptl_err(Plwp_setregs(t->t_pshandle,
4613*7c478bd9Sstevel@tonic-gate 		    (lwpid_t)tid, gregs)));
4614*7c478bd9Sstevel@tonic-gate 	}
4615*7c478bd9Sstevel@tonic-gate 	return (set_errno(EMDB_NOPROC));
4616*7c478bd9Sstevel@tonic-gate }
4617*7c478bd9Sstevel@tonic-gate 
4618*7c478bd9Sstevel@tonic-gate #ifdef	__sparc
4619*7c478bd9Sstevel@tonic-gate 
4620*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4621*7c478bd9Sstevel@tonic-gate static int
4622*7c478bd9Sstevel@tonic-gate pt_lwp_getxregs(mdb_tgt_t *t, void *tap, mdb_tgt_tid_t tid, prxregset_t *xregs)
4623*7c478bd9Sstevel@tonic-gate {
4624*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle != NULL) {
4625*7c478bd9Sstevel@tonic-gate 		return (ptl_err(Plwp_getxregs(t->t_pshandle,
4626*7c478bd9Sstevel@tonic-gate 		    (lwpid_t)tid, xregs)));
4627*7c478bd9Sstevel@tonic-gate 	}
4628*7c478bd9Sstevel@tonic-gate 	return (set_errno(EMDB_NOPROC));
4629*7c478bd9Sstevel@tonic-gate }
4630*7c478bd9Sstevel@tonic-gate 
4631*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4632*7c478bd9Sstevel@tonic-gate static int
4633*7c478bd9Sstevel@tonic-gate pt_lwp_setxregs(mdb_tgt_t *t, void *tap, mdb_tgt_tid_t tid,
4634*7c478bd9Sstevel@tonic-gate     const prxregset_t *xregs)
4635*7c478bd9Sstevel@tonic-gate {
4636*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle != NULL) {
4637*7c478bd9Sstevel@tonic-gate 		return (ptl_err(Plwp_setxregs(t->t_pshandle,
4638*7c478bd9Sstevel@tonic-gate 		    (lwpid_t)tid, xregs)));
4639*7c478bd9Sstevel@tonic-gate 	}
4640*7c478bd9Sstevel@tonic-gate 	return (set_errno(EMDB_NOPROC));
4641*7c478bd9Sstevel@tonic-gate }
4642*7c478bd9Sstevel@tonic-gate 
4643*7c478bd9Sstevel@tonic-gate #endif	/* __sparc */
4644*7c478bd9Sstevel@tonic-gate 
4645*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4646*7c478bd9Sstevel@tonic-gate static int
4647*7c478bd9Sstevel@tonic-gate pt_lwp_getfpregs(mdb_tgt_t *t, void *tap, mdb_tgt_tid_t tid,
4648*7c478bd9Sstevel@tonic-gate     prfpregset_t *fpregs)
4649*7c478bd9Sstevel@tonic-gate {
4650*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle != NULL) {
4651*7c478bd9Sstevel@tonic-gate 		return (ptl_err(Plwp_getfpregs(t->t_pshandle,
4652*7c478bd9Sstevel@tonic-gate 		    (lwpid_t)tid, fpregs)));
4653*7c478bd9Sstevel@tonic-gate 	}
4654*7c478bd9Sstevel@tonic-gate 	return (set_errno(EMDB_NOPROC));
4655*7c478bd9Sstevel@tonic-gate }
4656*7c478bd9Sstevel@tonic-gate 
4657*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4658*7c478bd9Sstevel@tonic-gate static int
4659*7c478bd9Sstevel@tonic-gate pt_lwp_setfpregs(mdb_tgt_t *t, void *tap, mdb_tgt_tid_t tid,
4660*7c478bd9Sstevel@tonic-gate     const prfpregset_t *fpregs)
4661*7c478bd9Sstevel@tonic-gate {
4662*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle != NULL) {
4663*7c478bd9Sstevel@tonic-gate 		return (ptl_err(Plwp_setfpregs(t->t_pshandle,
4664*7c478bd9Sstevel@tonic-gate 		    (lwpid_t)tid, fpregs)));
4665*7c478bd9Sstevel@tonic-gate 	}
4666*7c478bd9Sstevel@tonic-gate 	return (set_errno(EMDB_NOPROC));
4667*7c478bd9Sstevel@tonic-gate }
4668*7c478bd9Sstevel@tonic-gate 
4669*7c478bd9Sstevel@tonic-gate static const pt_ptl_ops_t proc_lwp_ops = {
4670*7c478bd9Sstevel@tonic-gate 	(int (*)()) mdb_tgt_nop,
4671*7c478bd9Sstevel@tonic-gate 	(void (*)()) mdb_tgt_nop,
4672*7c478bd9Sstevel@tonic-gate 	pt_lwp_tid,
4673*7c478bd9Sstevel@tonic-gate 	pt_lwp_iter,
4674*7c478bd9Sstevel@tonic-gate 	pt_lwp_getregs,
4675*7c478bd9Sstevel@tonic-gate 	pt_lwp_setregs,
4676*7c478bd9Sstevel@tonic-gate #ifdef __sparc
4677*7c478bd9Sstevel@tonic-gate 	pt_lwp_getxregs,
4678*7c478bd9Sstevel@tonic-gate 	pt_lwp_setxregs,
4679*7c478bd9Sstevel@tonic-gate #endif
4680*7c478bd9Sstevel@tonic-gate 	pt_lwp_getfpregs,
4681*7c478bd9Sstevel@tonic-gate 	pt_lwp_setfpregs
4682*7c478bd9Sstevel@tonic-gate };
4683*7c478bd9Sstevel@tonic-gate 
4684*7c478bd9Sstevel@tonic-gate static int
4685*7c478bd9Sstevel@tonic-gate pt_tdb_ctor(mdb_tgt_t *t)
4686*7c478bd9Sstevel@tonic-gate {
4687*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
4688*7c478bd9Sstevel@tonic-gate 	td_thragent_t *tap;
4689*7c478bd9Sstevel@tonic-gate 	td_err_e err;
4690*7c478bd9Sstevel@tonic-gate 
4691*7c478bd9Sstevel@tonic-gate 	if ((err = pt->p_tdb_ops->td_ta_new(t->t_pshandle, &tap)) != TD_OK)
4692*7c478bd9Sstevel@tonic-gate 		return (set_errno(tdb_to_errno(err)));
4693*7c478bd9Sstevel@tonic-gate 
4694*7c478bd9Sstevel@tonic-gate 	pt->p_ptl_hdl = tap;
4695*7c478bd9Sstevel@tonic-gate 	return (0);
4696*7c478bd9Sstevel@tonic-gate }
4697*7c478bd9Sstevel@tonic-gate 
4698*7c478bd9Sstevel@tonic-gate static void
4699*7c478bd9Sstevel@tonic-gate pt_tdb_dtor(mdb_tgt_t *t, void *tap)
4700*7c478bd9Sstevel@tonic-gate {
4701*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
4702*7c478bd9Sstevel@tonic-gate 
4703*7c478bd9Sstevel@tonic-gate 	ASSERT(tap == pt->p_ptl_hdl);
4704*7c478bd9Sstevel@tonic-gate 	(void) pt->p_tdb_ops->td_ta_delete(tap);
4705*7c478bd9Sstevel@tonic-gate 	pt->p_ptl_hdl = NULL;
4706*7c478bd9Sstevel@tonic-gate }
4707*7c478bd9Sstevel@tonic-gate 
4708*7c478bd9Sstevel@tonic-gate static mdb_tgt_tid_t
4709*7c478bd9Sstevel@tonic-gate pt_tdb_tid(mdb_tgt_t *t, void *tap)
4710*7c478bd9Sstevel@tonic-gate {
4711*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
4712*7c478bd9Sstevel@tonic-gate 
4713*7c478bd9Sstevel@tonic-gate 	td_thrhandle_t th;
4714*7c478bd9Sstevel@tonic-gate 	td_thrinfo_t ti;
4715*7c478bd9Sstevel@tonic-gate 	td_err_e err;
4716*7c478bd9Sstevel@tonic-gate 
4717*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle == NULL)
4718*7c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_NOPROC));
4719*7c478bd9Sstevel@tonic-gate 
4720*7c478bd9Sstevel@tonic-gate 	if ((err = pt->p_tdb_ops->td_ta_map_lwp2thr(tap,
4721*7c478bd9Sstevel@tonic-gate 	    Pstatus(t->t_pshandle)->pr_lwp.pr_lwpid, &th)) != TD_OK)
4722*7c478bd9Sstevel@tonic-gate 		return (set_errno(tdb_to_errno(err)));
4723*7c478bd9Sstevel@tonic-gate 
4724*7c478bd9Sstevel@tonic-gate 	if ((err = pt->p_tdb_ops->td_thr_get_info(&th, &ti)) != TD_OK)
4725*7c478bd9Sstevel@tonic-gate 		return (set_errno(tdb_to_errno(err)));
4726*7c478bd9Sstevel@tonic-gate 
4727*7c478bd9Sstevel@tonic-gate 	return (ti.ti_tid);
4728*7c478bd9Sstevel@tonic-gate }
4729*7c478bd9Sstevel@tonic-gate 
4730*7c478bd9Sstevel@tonic-gate static int
4731*7c478bd9Sstevel@tonic-gate pt_tdb_add(const td_thrhandle_t *thp, pt_addarg_t *pap)
4732*7c478bd9Sstevel@tonic-gate {
4733*7c478bd9Sstevel@tonic-gate 	td_thrinfo_t ti;
4734*7c478bd9Sstevel@tonic-gate 
4735*7c478bd9Sstevel@tonic-gate 	if (pap->pa_pt->p_tdb_ops->td_thr_get_info(thp, &ti) == TD_OK &&
4736*7c478bd9Sstevel@tonic-gate 	    ti.ti_state != TD_THR_ZOMBIE)
4737*7c478bd9Sstevel@tonic-gate 		mdb_addrvec_unshift(pap->pa_ap, ti.ti_tid);
4738*7c478bd9Sstevel@tonic-gate 
4739*7c478bd9Sstevel@tonic-gate 	return (0);
4740*7c478bd9Sstevel@tonic-gate }
4741*7c478bd9Sstevel@tonic-gate 
4742*7c478bd9Sstevel@tonic-gate static int
4743*7c478bd9Sstevel@tonic-gate pt_tdb_iter(mdb_tgt_t *t, void *tap, mdb_addrvec_t *ap)
4744*7c478bd9Sstevel@tonic-gate {
4745*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
4746*7c478bd9Sstevel@tonic-gate 	pt_addarg_t arg;
4747*7c478bd9Sstevel@tonic-gate 	int err;
4748*7c478bd9Sstevel@tonic-gate 
4749*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle == NULL)
4750*7c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_NOPROC));
4751*7c478bd9Sstevel@tonic-gate 
4752*7c478bd9Sstevel@tonic-gate 	arg.pa_pt = pt;
4753*7c478bd9Sstevel@tonic-gate 	arg.pa_ap = ap;
4754*7c478bd9Sstevel@tonic-gate 
4755*7c478bd9Sstevel@tonic-gate 	if ((err = pt->p_tdb_ops->td_ta_thr_iter(tap, (td_thr_iter_f *)
4756*7c478bd9Sstevel@tonic-gate 	    pt_tdb_add, &arg, TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
4757*7c478bd9Sstevel@tonic-gate 	    TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS)) != TD_OK)
4758*7c478bd9Sstevel@tonic-gate 		return (set_errno(tdb_to_errno(err)));
4759*7c478bd9Sstevel@tonic-gate 
4760*7c478bd9Sstevel@tonic-gate 	return (0);
4761*7c478bd9Sstevel@tonic-gate }
4762*7c478bd9Sstevel@tonic-gate 
4763*7c478bd9Sstevel@tonic-gate static int
4764*7c478bd9Sstevel@tonic-gate pt_tdb_getregs(mdb_tgt_t *t, void *tap, mdb_tgt_tid_t tid, prgregset_t gregs)
4765*7c478bd9Sstevel@tonic-gate {
4766*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
4767*7c478bd9Sstevel@tonic-gate 
4768*7c478bd9Sstevel@tonic-gate 	td_thrhandle_t th;
4769*7c478bd9Sstevel@tonic-gate 	td_err_e err;
4770*7c478bd9Sstevel@tonic-gate 
4771*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle == NULL)
4772*7c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_NOPROC));
4773*7c478bd9Sstevel@tonic-gate 
4774*7c478bd9Sstevel@tonic-gate 	if ((err = pt->p_tdb_ops->td_ta_map_id2thr(tap, tid, &th)) != TD_OK)
4775*7c478bd9Sstevel@tonic-gate 		return (set_errno(tdb_to_errno(err)));
4776*7c478bd9Sstevel@tonic-gate 
4777*7c478bd9Sstevel@tonic-gate 	err = pt->p_tdb_ops->td_thr_getgregs(&th, gregs);
4778*7c478bd9Sstevel@tonic-gate 	if (err != TD_OK && err != TD_PARTIALREG)
4779*7c478bd9Sstevel@tonic-gate 		return (set_errno(tdb_to_errno(err)));
4780*7c478bd9Sstevel@tonic-gate 
4781*7c478bd9Sstevel@tonic-gate 	return (0);
4782*7c478bd9Sstevel@tonic-gate }
4783*7c478bd9Sstevel@tonic-gate 
4784*7c478bd9Sstevel@tonic-gate static int
4785*7c478bd9Sstevel@tonic-gate pt_tdb_setregs(mdb_tgt_t *t, void *tap, mdb_tgt_tid_t tid, prgregset_t gregs)
4786*7c478bd9Sstevel@tonic-gate {
4787*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
4788*7c478bd9Sstevel@tonic-gate 
4789*7c478bd9Sstevel@tonic-gate 	td_thrhandle_t th;
4790*7c478bd9Sstevel@tonic-gate 	td_err_e err;
4791*7c478bd9Sstevel@tonic-gate 
4792*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle == NULL)
4793*7c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_NOPROC));
4794*7c478bd9Sstevel@tonic-gate 
4795*7c478bd9Sstevel@tonic-gate 	if ((err = pt->p_tdb_ops->td_ta_map_id2thr(tap, tid, &th)) != TD_OK)
4796*7c478bd9Sstevel@tonic-gate 		return (set_errno(tdb_to_errno(err)));
4797*7c478bd9Sstevel@tonic-gate 
4798*7c478bd9Sstevel@tonic-gate 	err = pt->p_tdb_ops->td_thr_setgregs(&th, gregs);
4799*7c478bd9Sstevel@tonic-gate 	if (err != TD_OK && err != TD_PARTIALREG)
4800*7c478bd9Sstevel@tonic-gate 		return (set_errno(tdb_to_errno(err)));
4801*7c478bd9Sstevel@tonic-gate 
4802*7c478bd9Sstevel@tonic-gate 	return (0);
4803*7c478bd9Sstevel@tonic-gate }
4804*7c478bd9Sstevel@tonic-gate 
4805*7c478bd9Sstevel@tonic-gate #ifdef __sparc
4806*7c478bd9Sstevel@tonic-gate 
4807*7c478bd9Sstevel@tonic-gate static int
4808*7c478bd9Sstevel@tonic-gate pt_tdb_getxregs(mdb_tgt_t *t, void *tap, mdb_tgt_tid_t tid, prxregset_t *xregs)
4809*7c478bd9Sstevel@tonic-gate {
4810*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
4811*7c478bd9Sstevel@tonic-gate 
4812*7c478bd9Sstevel@tonic-gate 	td_thrhandle_t th;
4813*7c478bd9Sstevel@tonic-gate 	td_err_e err;
4814*7c478bd9Sstevel@tonic-gate 
4815*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle == NULL)
4816*7c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_NOPROC));
4817*7c478bd9Sstevel@tonic-gate 
4818*7c478bd9Sstevel@tonic-gate 	if ((err = pt->p_tdb_ops->td_ta_map_id2thr(tap, tid, &th)) != TD_OK)
4819*7c478bd9Sstevel@tonic-gate 		return (set_errno(tdb_to_errno(err)));
4820*7c478bd9Sstevel@tonic-gate 
4821*7c478bd9Sstevel@tonic-gate 	err = pt->p_tdb_ops->td_thr_getxregs(&th, xregs);
4822*7c478bd9Sstevel@tonic-gate 	if (err != TD_OK && err != TD_PARTIALREG)
4823*7c478bd9Sstevel@tonic-gate 		return (set_errno(tdb_to_errno(err)));
4824*7c478bd9Sstevel@tonic-gate 
4825*7c478bd9Sstevel@tonic-gate 	return (0);
4826*7c478bd9Sstevel@tonic-gate }
4827*7c478bd9Sstevel@tonic-gate 
4828*7c478bd9Sstevel@tonic-gate static int
4829*7c478bd9Sstevel@tonic-gate pt_tdb_setxregs(mdb_tgt_t *t, void *tap, mdb_tgt_tid_t tid,
4830*7c478bd9Sstevel@tonic-gate     const prxregset_t *xregs)
4831*7c478bd9Sstevel@tonic-gate {
4832*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
4833*7c478bd9Sstevel@tonic-gate 
4834*7c478bd9Sstevel@tonic-gate 	td_thrhandle_t th;
4835*7c478bd9Sstevel@tonic-gate 	td_err_e err;
4836*7c478bd9Sstevel@tonic-gate 
4837*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle == NULL)
4838*7c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_NOPROC));
4839*7c478bd9Sstevel@tonic-gate 
4840*7c478bd9Sstevel@tonic-gate 	if ((err = pt->p_tdb_ops->td_ta_map_id2thr(tap, tid, &th)) != TD_OK)
4841*7c478bd9Sstevel@tonic-gate 		return (set_errno(tdb_to_errno(err)));
4842*7c478bd9Sstevel@tonic-gate 
4843*7c478bd9Sstevel@tonic-gate 	err = pt->p_tdb_ops->td_thr_setxregs(&th, xregs);
4844*7c478bd9Sstevel@tonic-gate 	if (err != TD_OK && err != TD_PARTIALREG)
4845*7c478bd9Sstevel@tonic-gate 		return (set_errno(tdb_to_errno(err)));
4846*7c478bd9Sstevel@tonic-gate 
4847*7c478bd9Sstevel@tonic-gate 	return (0);
4848*7c478bd9Sstevel@tonic-gate }
4849*7c478bd9Sstevel@tonic-gate 
4850*7c478bd9Sstevel@tonic-gate #endif	/* __sparc */
4851*7c478bd9Sstevel@tonic-gate 
4852*7c478bd9Sstevel@tonic-gate static int
4853*7c478bd9Sstevel@tonic-gate pt_tdb_getfpregs(mdb_tgt_t *t, void *tap, mdb_tgt_tid_t tid,
4854*7c478bd9Sstevel@tonic-gate     prfpregset_t *fpregs)
4855*7c478bd9Sstevel@tonic-gate {
4856*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
4857*7c478bd9Sstevel@tonic-gate 
4858*7c478bd9Sstevel@tonic-gate 	td_thrhandle_t th;
4859*7c478bd9Sstevel@tonic-gate 	td_err_e err;
4860*7c478bd9Sstevel@tonic-gate 
4861*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle == NULL)
4862*7c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_NOPROC));
4863*7c478bd9Sstevel@tonic-gate 
4864*7c478bd9Sstevel@tonic-gate 	if ((err = pt->p_tdb_ops->td_ta_map_id2thr(tap, tid, &th)) != TD_OK)
4865*7c478bd9Sstevel@tonic-gate 		return (set_errno(tdb_to_errno(err)));
4866*7c478bd9Sstevel@tonic-gate 
4867*7c478bd9Sstevel@tonic-gate 	err = pt->p_tdb_ops->td_thr_getfpregs(&th, fpregs);
4868*7c478bd9Sstevel@tonic-gate 	if (err != TD_OK && err != TD_PARTIALREG)
4869*7c478bd9Sstevel@tonic-gate 		return (set_errno(tdb_to_errno(err)));
4870*7c478bd9Sstevel@tonic-gate 
4871*7c478bd9Sstevel@tonic-gate 	return (0);
4872*7c478bd9Sstevel@tonic-gate }
4873*7c478bd9Sstevel@tonic-gate 
4874*7c478bd9Sstevel@tonic-gate static int
4875*7c478bd9Sstevel@tonic-gate pt_tdb_setfpregs(mdb_tgt_t *t, void *tap, mdb_tgt_tid_t tid,
4876*7c478bd9Sstevel@tonic-gate     const prfpregset_t *fpregs)
4877*7c478bd9Sstevel@tonic-gate {
4878*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
4879*7c478bd9Sstevel@tonic-gate 
4880*7c478bd9Sstevel@tonic-gate 	td_thrhandle_t th;
4881*7c478bd9Sstevel@tonic-gate 	td_err_e err;
4882*7c478bd9Sstevel@tonic-gate 
4883*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle == NULL)
4884*7c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_NOPROC));
4885*7c478bd9Sstevel@tonic-gate 
4886*7c478bd9Sstevel@tonic-gate 	if ((err = pt->p_tdb_ops->td_ta_map_id2thr(tap, tid, &th)) != TD_OK)
4887*7c478bd9Sstevel@tonic-gate 		return (set_errno(tdb_to_errno(err)));
4888*7c478bd9Sstevel@tonic-gate 
4889*7c478bd9Sstevel@tonic-gate 	err = pt->p_tdb_ops->td_thr_setfpregs(&th, fpregs);
4890*7c478bd9Sstevel@tonic-gate 	if (err != TD_OK && err != TD_PARTIALREG)
4891*7c478bd9Sstevel@tonic-gate 		return (set_errno(tdb_to_errno(err)));
4892*7c478bd9Sstevel@tonic-gate 
4893*7c478bd9Sstevel@tonic-gate 	return (0);
4894*7c478bd9Sstevel@tonic-gate }
4895*7c478bd9Sstevel@tonic-gate 
4896*7c478bd9Sstevel@tonic-gate static const pt_ptl_ops_t proc_tdb_ops = {
4897*7c478bd9Sstevel@tonic-gate 	pt_tdb_ctor,
4898*7c478bd9Sstevel@tonic-gate 	pt_tdb_dtor,
4899*7c478bd9Sstevel@tonic-gate 	pt_tdb_tid,
4900*7c478bd9Sstevel@tonic-gate 	pt_tdb_iter,
4901*7c478bd9Sstevel@tonic-gate 	pt_tdb_getregs,
4902*7c478bd9Sstevel@tonic-gate 	pt_tdb_setregs,
4903*7c478bd9Sstevel@tonic-gate #ifdef __sparc
4904*7c478bd9Sstevel@tonic-gate 	pt_tdb_getxregs,
4905*7c478bd9Sstevel@tonic-gate 	pt_tdb_setxregs,
4906*7c478bd9Sstevel@tonic-gate #endif
4907*7c478bd9Sstevel@tonic-gate 	pt_tdb_getfpregs,
4908*7c478bd9Sstevel@tonic-gate 	pt_tdb_setfpregs
4909*7c478bd9Sstevel@tonic-gate };
4910*7c478bd9Sstevel@tonic-gate 
4911*7c478bd9Sstevel@tonic-gate static ssize_t
4912*7c478bd9Sstevel@tonic-gate pt_xd_auxv(mdb_tgt_t *t, void *buf, size_t nbytes)
4913*7c478bd9Sstevel@tonic-gate {
4914*7c478bd9Sstevel@tonic-gate 	struct ps_prochandle *P = t->t_pshandle;
4915*7c478bd9Sstevel@tonic-gate 	const auxv_t *auxp, *auxv = NULL;
4916*7c478bd9Sstevel@tonic-gate 	int auxn = 0;
4917*7c478bd9Sstevel@tonic-gate 
4918*7c478bd9Sstevel@tonic-gate 	if (P != NULL && (auxv = Pgetauxvec(P)) != NULL &&
4919*7c478bd9Sstevel@tonic-gate 	    auxv->a_type != AT_NULL) {
4920*7c478bd9Sstevel@tonic-gate 		for (auxp = auxv, auxn = 1; auxp->a_type != NULL; auxp++)
4921*7c478bd9Sstevel@tonic-gate 			auxn++;
4922*7c478bd9Sstevel@tonic-gate 	}
4923*7c478bd9Sstevel@tonic-gate 
4924*7c478bd9Sstevel@tonic-gate 	if (buf == NULL && nbytes == 0)
4925*7c478bd9Sstevel@tonic-gate 		return (sizeof (auxv_t) * auxn);
4926*7c478bd9Sstevel@tonic-gate 
4927*7c478bd9Sstevel@tonic-gate 	if (auxn == 0)
4928*7c478bd9Sstevel@tonic-gate 		return (set_errno(ENODATA));
4929*7c478bd9Sstevel@tonic-gate 
4930*7c478bd9Sstevel@tonic-gate 	nbytes = MIN(nbytes, sizeof (auxv_t) * auxn);
4931*7c478bd9Sstevel@tonic-gate 	bcopy(auxv, buf, nbytes);
4932*7c478bd9Sstevel@tonic-gate 	return (nbytes);
4933*7c478bd9Sstevel@tonic-gate }
4934*7c478bd9Sstevel@tonic-gate 
4935*7c478bd9Sstevel@tonic-gate static ssize_t
4936*7c478bd9Sstevel@tonic-gate pt_xd_cred(mdb_tgt_t *t, void *buf, size_t nbytes)
4937*7c478bd9Sstevel@tonic-gate {
4938*7c478bd9Sstevel@tonic-gate 	prcred_t cr, *crp;
4939*7c478bd9Sstevel@tonic-gate 	size_t cbytes = 0;
4940*7c478bd9Sstevel@tonic-gate 
4941*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle != NULL && Pcred(t->t_pshandle, &cr, 1) == 0) {
4942*7c478bd9Sstevel@tonic-gate 		cbytes = (cr.pr_ngroups <= 1) ? sizeof (prcred_t) :
4943*7c478bd9Sstevel@tonic-gate 		    (sizeof (prcred_t) + (cr.pr_ngroups - 1) * sizeof (gid_t));
4944*7c478bd9Sstevel@tonic-gate 	}
4945*7c478bd9Sstevel@tonic-gate 
4946*7c478bd9Sstevel@tonic-gate 	if (buf == NULL && nbytes == 0)
4947*7c478bd9Sstevel@tonic-gate 		return (cbytes);
4948*7c478bd9Sstevel@tonic-gate 
4949*7c478bd9Sstevel@tonic-gate 	if (cbytes == 0)
4950*7c478bd9Sstevel@tonic-gate 		return (set_errno(ENODATA));
4951*7c478bd9Sstevel@tonic-gate 
4952*7c478bd9Sstevel@tonic-gate 	crp = mdb_alloc(cbytes, UM_SLEEP);
4953*7c478bd9Sstevel@tonic-gate 
4954*7c478bd9Sstevel@tonic-gate 	if (Pcred(t->t_pshandle, crp, cr.pr_ngroups) == -1)
4955*7c478bd9Sstevel@tonic-gate 		return (set_errno(ENODATA));
4956*7c478bd9Sstevel@tonic-gate 
4957*7c478bd9Sstevel@tonic-gate 	nbytes = MIN(nbytes, cbytes);
4958*7c478bd9Sstevel@tonic-gate 	bcopy(crp, buf, nbytes);
4959*7c478bd9Sstevel@tonic-gate 	mdb_free(crp, cbytes);
4960*7c478bd9Sstevel@tonic-gate 	return (nbytes);
4961*7c478bd9Sstevel@tonic-gate }
4962*7c478bd9Sstevel@tonic-gate 
4963*7c478bd9Sstevel@tonic-gate static ssize_t
4964*7c478bd9Sstevel@tonic-gate pt_xd_ehdr(mdb_tgt_t *t, void *buf, size_t nbytes)
4965*7c478bd9Sstevel@tonic-gate {
4966*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
4967*7c478bd9Sstevel@tonic-gate 
4968*7c478bd9Sstevel@tonic-gate 	if (buf == NULL && nbytes == 0)
4969*7c478bd9Sstevel@tonic-gate 		return (sizeof (GElf_Ehdr));
4970*7c478bd9Sstevel@tonic-gate 
4971*7c478bd9Sstevel@tonic-gate 	if (pt->p_file == NULL)
4972*7c478bd9Sstevel@tonic-gate 		return (set_errno(ENODATA));
4973*7c478bd9Sstevel@tonic-gate 
4974*7c478bd9Sstevel@tonic-gate 	nbytes = MIN(nbytes, sizeof (GElf_Ehdr));
4975*7c478bd9Sstevel@tonic-gate 	bcopy(&pt->p_file->gf_ehdr, buf, nbytes);
4976*7c478bd9Sstevel@tonic-gate 	return (nbytes);
4977*7c478bd9Sstevel@tonic-gate }
4978*7c478bd9Sstevel@tonic-gate 
4979*7c478bd9Sstevel@tonic-gate static int
4980*7c478bd9Sstevel@tonic-gate pt_copy_lwp(lwpstatus_t **lspp, const lwpstatus_t *lsp)
4981*7c478bd9Sstevel@tonic-gate {
4982*7c478bd9Sstevel@tonic-gate 	bcopy(lsp, *lspp, sizeof (lwpstatus_t));
4983*7c478bd9Sstevel@tonic-gate 	(*lspp)++;
4984*7c478bd9Sstevel@tonic-gate 	return (0);
4985*7c478bd9Sstevel@tonic-gate }
4986*7c478bd9Sstevel@tonic-gate 
4987*7c478bd9Sstevel@tonic-gate static ssize_t
4988*7c478bd9Sstevel@tonic-gate pt_xd_lwpstatus(mdb_tgt_t *t, void *buf, size_t nbytes)
4989*7c478bd9Sstevel@tonic-gate {
4990*7c478bd9Sstevel@tonic-gate 	lwpstatus_t *lsp, *lbuf;
4991*7c478bd9Sstevel@tonic-gate 	const pstatus_t *psp;
4992*7c478bd9Sstevel@tonic-gate 	int nlwp = 0;
4993*7c478bd9Sstevel@tonic-gate 
4994*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle != NULL && (psp = Pstatus(t->t_pshandle)) != NULL)
4995*7c478bd9Sstevel@tonic-gate 		nlwp = psp->pr_nlwp;
4996*7c478bd9Sstevel@tonic-gate 
4997*7c478bd9Sstevel@tonic-gate 	if (buf == NULL && nbytes == 0)
4998*7c478bd9Sstevel@tonic-gate 		return (sizeof (lwpstatus_t) * nlwp);
4999*7c478bd9Sstevel@tonic-gate 
5000*7c478bd9Sstevel@tonic-gate 	if (nlwp == 0)
5001*7c478bd9Sstevel@tonic-gate 		return (set_errno(ENODATA));
5002*7c478bd9Sstevel@tonic-gate 
5003*7c478bd9Sstevel@tonic-gate 	lsp = lbuf = mdb_alloc(sizeof (lwpstatus_t) * nlwp, UM_SLEEP);
5004*7c478bd9Sstevel@tonic-gate 	nbytes = MIN(nbytes, sizeof (lwpstatus_t) * nlwp);
5005*7c478bd9Sstevel@tonic-gate 
5006*7c478bd9Sstevel@tonic-gate 	(void) Plwp_iter(t->t_pshandle, (proc_lwp_f *)pt_copy_lwp, &lsp);
5007*7c478bd9Sstevel@tonic-gate 	bcopy(lbuf, buf, nbytes);
5008*7c478bd9Sstevel@tonic-gate 
5009*7c478bd9Sstevel@tonic-gate 	mdb_free(lbuf, sizeof (lwpstatus_t) * nlwp);
5010*7c478bd9Sstevel@tonic-gate 	return (nbytes);
5011*7c478bd9Sstevel@tonic-gate }
5012*7c478bd9Sstevel@tonic-gate 
5013*7c478bd9Sstevel@tonic-gate static ssize_t
5014*7c478bd9Sstevel@tonic-gate pt_xd_pshandle(mdb_tgt_t *t, void *buf, size_t nbytes)
5015*7c478bd9Sstevel@tonic-gate {
5016*7c478bd9Sstevel@tonic-gate 	if (buf == NULL && nbytes == 0)
5017*7c478bd9Sstevel@tonic-gate 		return (sizeof (struct ps_prochandle *));
5018*7c478bd9Sstevel@tonic-gate 
5019*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle == NULL || nbytes != sizeof (struct ps_prochandle *))
5020*7c478bd9Sstevel@tonic-gate 		return (set_errno(ENODATA));
5021*7c478bd9Sstevel@tonic-gate 
5022*7c478bd9Sstevel@tonic-gate 	bcopy(&t->t_pshandle, buf, nbytes);
5023*7c478bd9Sstevel@tonic-gate 	return (nbytes);
5024*7c478bd9Sstevel@tonic-gate }
5025*7c478bd9Sstevel@tonic-gate 
5026*7c478bd9Sstevel@tonic-gate static ssize_t
5027*7c478bd9Sstevel@tonic-gate pt_xd_psinfo(mdb_tgt_t *t, void *buf, size_t nbytes)
5028*7c478bd9Sstevel@tonic-gate {
5029*7c478bd9Sstevel@tonic-gate 	const psinfo_t *psp;
5030*7c478bd9Sstevel@tonic-gate 
5031*7c478bd9Sstevel@tonic-gate 	if (buf == NULL && nbytes == 0)
5032*7c478bd9Sstevel@tonic-gate 		return (sizeof (psinfo_t));
5033*7c478bd9Sstevel@tonic-gate 
5034*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle == NULL || (psp = Ppsinfo(t->t_pshandle)) == NULL)
5035*7c478bd9Sstevel@tonic-gate 		return (set_errno(ENODATA));
5036*7c478bd9Sstevel@tonic-gate 
5037*7c478bd9Sstevel@tonic-gate 	nbytes = MIN(nbytes, sizeof (psinfo_t));
5038*7c478bd9Sstevel@tonic-gate 	bcopy(psp, buf, nbytes);
5039*7c478bd9Sstevel@tonic-gate 	return (nbytes);
5040*7c478bd9Sstevel@tonic-gate }
5041*7c478bd9Sstevel@tonic-gate 
5042*7c478bd9Sstevel@tonic-gate static ssize_t
5043*7c478bd9Sstevel@tonic-gate pt_xd_pstatus(mdb_tgt_t *t, void *buf, size_t nbytes)
5044*7c478bd9Sstevel@tonic-gate {
5045*7c478bd9Sstevel@tonic-gate 	const pstatus_t *psp;
5046*7c478bd9Sstevel@tonic-gate 
5047*7c478bd9Sstevel@tonic-gate 	if (buf == NULL && nbytes == 0)
5048*7c478bd9Sstevel@tonic-gate 		return (sizeof (pstatus_t));
5049*7c478bd9Sstevel@tonic-gate 
5050*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle == NULL || (psp = Pstatus(t->t_pshandle)) == NULL)
5051*7c478bd9Sstevel@tonic-gate 		return (set_errno(ENODATA));
5052*7c478bd9Sstevel@tonic-gate 
5053*7c478bd9Sstevel@tonic-gate 	nbytes = MIN(nbytes, sizeof (pstatus_t));
5054*7c478bd9Sstevel@tonic-gate 	bcopy(psp, buf, nbytes);
5055*7c478bd9Sstevel@tonic-gate 	return (nbytes);
5056*7c478bd9Sstevel@tonic-gate }
5057*7c478bd9Sstevel@tonic-gate 
5058*7c478bd9Sstevel@tonic-gate static ssize_t
5059*7c478bd9Sstevel@tonic-gate pt_xd_utsname(mdb_tgt_t *t, void *buf, size_t nbytes)
5060*7c478bd9Sstevel@tonic-gate {
5061*7c478bd9Sstevel@tonic-gate 	struct utsname uts;
5062*7c478bd9Sstevel@tonic-gate 
5063*7c478bd9Sstevel@tonic-gate 	if (buf == NULL && nbytes == 0)
5064*7c478bd9Sstevel@tonic-gate 		return (sizeof (struct utsname));
5065*7c478bd9Sstevel@tonic-gate 
5066*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle == NULL || Puname(t->t_pshandle, &uts) != 0)
5067*7c478bd9Sstevel@tonic-gate 		return (set_errno(ENODATA));
5068*7c478bd9Sstevel@tonic-gate 
5069*7c478bd9Sstevel@tonic-gate 	nbytes = MIN(nbytes, sizeof (struct utsname));
5070*7c478bd9Sstevel@tonic-gate 	bcopy(&uts, buf, nbytes);
5071*7c478bd9Sstevel@tonic-gate 	return (nbytes);
5072*7c478bd9Sstevel@tonic-gate }
5073*7c478bd9Sstevel@tonic-gate 
5074*7c478bd9Sstevel@tonic-gate int
5075*7c478bd9Sstevel@tonic-gate mdb_proc_tgt_create(mdb_tgt_t *t, int argc, const char *argv[])
5076*7c478bd9Sstevel@tonic-gate {
5077*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = mdb_zalloc(sizeof (pt_data_t), UM_SLEEP);
5078*7c478bd9Sstevel@tonic-gate 
5079*7c478bd9Sstevel@tonic-gate 	const char *aout_path = argc > 0 ? argv[0] : PT_EXEC_PATH;
5080*7c478bd9Sstevel@tonic-gate 	const char *core_path = argc > 1 ? argv[1] : NULL;
5081*7c478bd9Sstevel@tonic-gate 
5082*7c478bd9Sstevel@tonic-gate 	const mdb_tgt_regdesc_t *rdp;
5083*7c478bd9Sstevel@tonic-gate 	char execname[MAXPATHLEN];
5084*7c478bd9Sstevel@tonic-gate 	struct stat64 st;
5085*7c478bd9Sstevel@tonic-gate 	int perr;
5086*7c478bd9Sstevel@tonic-gate 	int state;
5087*7c478bd9Sstevel@tonic-gate 	struct rlimit rlim;
5088*7c478bd9Sstevel@tonic-gate 	int i;
5089*7c478bd9Sstevel@tonic-gate 
5090*7c478bd9Sstevel@tonic-gate 	if (argc > 2) {
5091*7c478bd9Sstevel@tonic-gate 		mdb_free(pt, sizeof (pt_data_t));
5092*7c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
5093*7c478bd9Sstevel@tonic-gate 	}
5094*7c478bd9Sstevel@tonic-gate 
5095*7c478bd9Sstevel@tonic-gate 	if (t->t_flags & MDB_TGT_F_RDWR)
5096*7c478bd9Sstevel@tonic-gate 		pt->p_oflags = O_RDWR;
5097*7c478bd9Sstevel@tonic-gate 	else
5098*7c478bd9Sstevel@tonic-gate 		pt->p_oflags = O_RDONLY;
5099*7c478bd9Sstevel@tonic-gate 
5100*7c478bd9Sstevel@tonic-gate 	if (t->t_flags & MDB_TGT_F_FORCE)
5101*7c478bd9Sstevel@tonic-gate 		pt->p_gflags |= PGRAB_FORCE;
5102*7c478bd9Sstevel@tonic-gate 	if (t->t_flags & MDB_TGT_F_NOSTOP)
5103*7c478bd9Sstevel@tonic-gate 		pt->p_gflags |= PGRAB_NOSTOP;
5104*7c478bd9Sstevel@tonic-gate 
5105*7c478bd9Sstevel@tonic-gate 	pt->p_ptl_ops = &proc_lwp_ops;
5106*7c478bd9Sstevel@tonic-gate 	pt->p_maxsig = sysconf(_SC_SIGRT_MAX);
5107*7c478bd9Sstevel@tonic-gate 
5108*7c478bd9Sstevel@tonic-gate 	(void) mdb_nv_create(&pt->p_regs, UM_SLEEP);
5109*7c478bd9Sstevel@tonic-gate 	(void) mdb_nv_create(&pt->p_env, UM_SLEEP);
5110*7c478bd9Sstevel@tonic-gate 
5111*7c478bd9Sstevel@tonic-gate 	t->t_ops = &proc_ops;
5112*7c478bd9Sstevel@tonic-gate 	t->t_data = pt;
5113*7c478bd9Sstevel@tonic-gate 
5114*7c478bd9Sstevel@tonic-gate 	/*
5115*7c478bd9Sstevel@tonic-gate 	 * If no core file name was specified, but the file ./core is present,
5116*7c478bd9Sstevel@tonic-gate 	 * infer that we want to debug it.  I find this behavior confusing,
5117*7c478bd9Sstevel@tonic-gate 	 * so we only do this when precise adb(1) compatibility is required.
5118*7c478bd9Sstevel@tonic-gate 	 */
5119*7c478bd9Sstevel@tonic-gate 	if (core_path == NULL && (mdb.m_flags & MDB_FL_ADB) &&
5120*7c478bd9Sstevel@tonic-gate 	    access(PT_CORE_PATH, F_OK) == 0)
5121*7c478bd9Sstevel@tonic-gate 		core_path = PT_CORE_PATH;
5122*7c478bd9Sstevel@tonic-gate 
5123*7c478bd9Sstevel@tonic-gate 	/*
5124*7c478bd9Sstevel@tonic-gate 	 * For compatibility with adb(1), the special name "-" may be used
5125*7c478bd9Sstevel@tonic-gate 	 * to suppress the loading of the executable or core file.
5126*7c478bd9Sstevel@tonic-gate 	 */
5127*7c478bd9Sstevel@tonic-gate 	if (aout_path != NULL && strcmp(aout_path, "-") == 0)
5128*7c478bd9Sstevel@tonic-gate 		aout_path = NULL;
5129*7c478bd9Sstevel@tonic-gate 	if (core_path != NULL && strcmp(core_path, "-") == 0)
5130*7c478bd9Sstevel@tonic-gate 		core_path = NULL;
5131*7c478bd9Sstevel@tonic-gate 
5132*7c478bd9Sstevel@tonic-gate 	/*
5133*7c478bd9Sstevel@tonic-gate 	 * If a core file or pid was specified, attempt to grab it now using
5134*7c478bd9Sstevel@tonic-gate 	 * proc_arg_grab(); otherwise we'll create a fresh process later.
5135*7c478bd9Sstevel@tonic-gate 	 */
5136*7c478bd9Sstevel@tonic-gate 	if (core_path != NULL && (t->t_pshandle = proc_arg_xgrab(core_path,
5137*7c478bd9Sstevel@tonic-gate 	    aout_path == PT_EXEC_PATH ? NULL : aout_path, PR_ARG_ANY,
5138*7c478bd9Sstevel@tonic-gate 	    pt->p_gflags, &perr, NULL)) == NULL) {
5139*7c478bd9Sstevel@tonic-gate 		mdb_warn("cannot debug %s: %s\n", core_path, Pgrab_error(perr));
5140*7c478bd9Sstevel@tonic-gate 		goto err;
5141*7c478bd9Sstevel@tonic-gate 	}
5142*7c478bd9Sstevel@tonic-gate 
5143*7c478bd9Sstevel@tonic-gate 	if (aout_path != NULL &&
5144*7c478bd9Sstevel@tonic-gate 	    (pt->p_idlehandle = Pgrab_file(aout_path, &perr)) != NULL &&
5145*7c478bd9Sstevel@tonic-gate 	    t->t_pshandle == NULL)
5146*7c478bd9Sstevel@tonic-gate 		t->t_pshandle = pt->p_idlehandle;
5147*7c478bd9Sstevel@tonic-gate 
5148*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle != NULL)
5149*7c478bd9Sstevel@tonic-gate 		state = Pstate(t->t_pshandle);
5150*7c478bd9Sstevel@tonic-gate 
5151*7c478bd9Sstevel@tonic-gate 	/*
5152*7c478bd9Sstevel@tonic-gate 	 * Make sure we'll have enough file descriptors to handle a target
5153*7c478bd9Sstevel@tonic-gate 	 * has many many mappings.
5154*7c478bd9Sstevel@tonic-gate 	 */
5155*7c478bd9Sstevel@tonic-gate 	if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
5156*7c478bd9Sstevel@tonic-gate 		rlim.rlim_cur = rlim.rlim_max;
5157*7c478bd9Sstevel@tonic-gate 		(void) setrlimit(RLIMIT_NOFILE, &rlim);
5158*7c478bd9Sstevel@tonic-gate 	}
5159*7c478bd9Sstevel@tonic-gate 
5160*7c478bd9Sstevel@tonic-gate 	/*
5161*7c478bd9Sstevel@tonic-gate 	 * If we don't have an executable path or the executable path is the
5162*7c478bd9Sstevel@tonic-gate 	 * /proc/<pid>/object/a.out path, but we now have a libproc handle,
5163*7c478bd9Sstevel@tonic-gate 	 * attempt to derive the executable path using Pexecname().  We need
5164*7c478bd9Sstevel@tonic-gate 	 * to do this in the /proc case in order to open the executable for
5165*7c478bd9Sstevel@tonic-gate 	 * writing because /proc/object/<file> permission are masked with 0555.
5166*7c478bd9Sstevel@tonic-gate 	 * If Pexecname() fails us, fall back to /proc/<pid>/object/a.out.
5167*7c478bd9Sstevel@tonic-gate 	 */
5168*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle != NULL && (aout_path == NULL || (stat64(aout_path,
5169*7c478bd9Sstevel@tonic-gate 	    &st) == 0 && strcmp(st.st_fstype, "proc") == 0))) {
5170*7c478bd9Sstevel@tonic-gate 		GElf_Sym s;
5171*7c478bd9Sstevel@tonic-gate 		aout_path = Pexecname(t->t_pshandle, execname, MAXPATHLEN);
5172*7c478bd9Sstevel@tonic-gate 		if (aout_path == NULL && state != PS_DEAD && state != PS_IDLE) {
5173*7c478bd9Sstevel@tonic-gate 			(void) mdb_iob_snprintf(execname, sizeof (execname),
5174*7c478bd9Sstevel@tonic-gate 			    "/proc/%d/object/a.out",
5175*7c478bd9Sstevel@tonic-gate 			    (int)Pstatus(t->t_pshandle)->pr_pid);
5176*7c478bd9Sstevel@tonic-gate 			aout_path = execname;
5177*7c478bd9Sstevel@tonic-gate 		}
5178*7c478bd9Sstevel@tonic-gate 		if (aout_path == NULL &&
5179*7c478bd9Sstevel@tonic-gate 		    Plookup_by_name(t->t_pshandle, "a.out", "_start", &s) != 0)
5180*7c478bd9Sstevel@tonic-gate 			mdb_warn("warning: failed to infer pathname to "
5181*7c478bd9Sstevel@tonic-gate 			    "executable; symbol table will not be available\n");
5182*7c478bd9Sstevel@tonic-gate 
5183*7c478bd9Sstevel@tonic-gate 		mdb_dprintf(MDB_DBG_TGT, "a.out is %s\n", aout_path);
5184*7c478bd9Sstevel@tonic-gate 	}
5185*7c478bd9Sstevel@tonic-gate 
5186*7c478bd9Sstevel@tonic-gate 	/*
5187*7c478bd9Sstevel@tonic-gate 	 * Attempt to open the executable file.  We only want this operation
5188*7c478bd9Sstevel@tonic-gate 	 * to actually cause the constructor to abort if the executable file
5189*7c478bd9Sstevel@tonic-gate 	 * name was given explicitly.  If we defaulted to PT_EXEC_PATH or
5190*7c478bd9Sstevel@tonic-gate 	 * derived the executable using Pexecname, then we want to continue
5191*7c478bd9Sstevel@tonic-gate 	 * along with p_fio and p_file set to NULL.
5192*7c478bd9Sstevel@tonic-gate 	 */
5193*7c478bd9Sstevel@tonic-gate 	if (aout_path != NULL && (pt->p_aout_fio = mdb_fdio_create_path(NULL,
5194*7c478bd9Sstevel@tonic-gate 	    aout_path, pt->p_oflags, 0)) == NULL && argc > 0) {
5195*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to open %s", aout_path);
5196*7c478bd9Sstevel@tonic-gate 		goto err;
5197*7c478bd9Sstevel@tonic-gate 	}
5198*7c478bd9Sstevel@tonic-gate 
5199*7c478bd9Sstevel@tonic-gate 	/*
5200*7c478bd9Sstevel@tonic-gate 	 * Now create an ELF file from the input file, if we have one.  Again,
5201*7c478bd9Sstevel@tonic-gate 	 * only abort the constructor if the name was given explicitly.
5202*7c478bd9Sstevel@tonic-gate 	 */
5203*7c478bd9Sstevel@tonic-gate 	if (pt->p_aout_fio != NULL && pt_open_aout(t,
5204*7c478bd9Sstevel@tonic-gate 	    mdb_io_hold(pt->p_aout_fio)) == NULL && argc > 0)
5205*7c478bd9Sstevel@tonic-gate 		goto err;
5206*7c478bd9Sstevel@tonic-gate 
5207*7c478bd9Sstevel@tonic-gate 	/*
5208*7c478bd9Sstevel@tonic-gate 	 * If we've successfully opened an ELF file, select the appropriate
5209*7c478bd9Sstevel@tonic-gate 	 * disassembler based on the ELF header.
5210*7c478bd9Sstevel@tonic-gate 	 */
5211*7c478bd9Sstevel@tonic-gate 	if (pt->p_file != NULL)
5212*7c478bd9Sstevel@tonic-gate 		(void) mdb_dis_select(pt_disasm(&pt->p_file->gf_ehdr));
5213*7c478bd9Sstevel@tonic-gate 	else
5214*7c478bd9Sstevel@tonic-gate 		(void) mdb_dis_select(pt_disasm(NULL));
5215*7c478bd9Sstevel@tonic-gate 
5216*7c478bd9Sstevel@tonic-gate 	/*
5217*7c478bd9Sstevel@tonic-gate 	 * Add each register described in the target ISA register description
5218*7c478bd9Sstevel@tonic-gate 	 * list to our hash table of register descriptions and then add any
5219*7c478bd9Sstevel@tonic-gate 	 * appropriate ISA-specific floating-point register descriptions.
5220*7c478bd9Sstevel@tonic-gate 	 */
5221*7c478bd9Sstevel@tonic-gate 	for (rdp = pt_regdesc; rdp->rd_name != NULL; rdp++) {
5222*7c478bd9Sstevel@tonic-gate 		(void) mdb_nv_insert(&pt->p_regs, rdp->rd_name, NULL,
5223*7c478bd9Sstevel@tonic-gate 		    MDB_TGT_R_NVAL(rdp->rd_num, rdp->rd_flags), MDB_NV_RDONLY);
5224*7c478bd9Sstevel@tonic-gate 	}
5225*7c478bd9Sstevel@tonic-gate 	pt_addfpregs(t);
5226*7c478bd9Sstevel@tonic-gate 
5227*7c478bd9Sstevel@tonic-gate 	/*
5228*7c478bd9Sstevel@tonic-gate 	 * Certain important /proc structures may be of interest to mdb
5229*7c478bd9Sstevel@tonic-gate 	 * modules and their dcmds.  Export these using the xdata interface:
5230*7c478bd9Sstevel@tonic-gate 	 */
5231*7c478bd9Sstevel@tonic-gate 	(void) mdb_tgt_xdata_insert(t, "auxv",
5232*7c478bd9Sstevel@tonic-gate 	    "procfs auxv_t array", pt_xd_auxv);
5233*7c478bd9Sstevel@tonic-gate 	(void) mdb_tgt_xdata_insert(t, "cred",
5234*7c478bd9Sstevel@tonic-gate 	    "procfs prcred_t structure", pt_xd_cred);
5235*7c478bd9Sstevel@tonic-gate 	(void) mdb_tgt_xdata_insert(t, "ehdr",
5236*7c478bd9Sstevel@tonic-gate 	    "executable file GElf_Ehdr structure", pt_xd_ehdr);
5237*7c478bd9Sstevel@tonic-gate 	(void) mdb_tgt_xdata_insert(t, "lwpstatus",
5238*7c478bd9Sstevel@tonic-gate 	    "procfs lwpstatus_t array", pt_xd_lwpstatus);
5239*7c478bd9Sstevel@tonic-gate 	(void) mdb_tgt_xdata_insert(t, "pshandle",
5240*7c478bd9Sstevel@tonic-gate 	    "libproc proc service API handle", pt_xd_pshandle);
5241*7c478bd9Sstevel@tonic-gate 	(void) mdb_tgt_xdata_insert(t, "psinfo",
5242*7c478bd9Sstevel@tonic-gate 	    "procfs psinfo_t structure", pt_xd_psinfo);
5243*7c478bd9Sstevel@tonic-gate 	(void) mdb_tgt_xdata_insert(t, "pstatus",
5244*7c478bd9Sstevel@tonic-gate 	    "procfs pstatus_t structure", pt_xd_pstatus);
5245*7c478bd9Sstevel@tonic-gate 	(void) mdb_tgt_xdata_insert(t, "utsname",
5246*7c478bd9Sstevel@tonic-gate 	    "utsname structure", pt_xd_utsname);
5247*7c478bd9Sstevel@tonic-gate 
5248*7c478bd9Sstevel@tonic-gate 	/*
5249*7c478bd9Sstevel@tonic-gate 	 * Force a status update now so that we fill in t_status with the
5250*7c478bd9Sstevel@tonic-gate 	 * latest information based on any successful grab.
5251*7c478bd9Sstevel@tonic-gate 	 */
5252*7c478bd9Sstevel@tonic-gate 	(void) mdb_tgt_status(t, &t->t_status);
5253*7c478bd9Sstevel@tonic-gate 
5254*7c478bd9Sstevel@tonic-gate 	/*
5255*7c478bd9Sstevel@tonic-gate 	 * If we're not examining a core file, trace SIGINT and all signals
5256*7c478bd9Sstevel@tonic-gate 	 * that cause the process to dump core as part of our initialization.
5257*7c478bd9Sstevel@tonic-gate 	 */
5258*7c478bd9Sstevel@tonic-gate 	if ((t->t_pshandle != NULL && state != PS_DEAD && state != PS_IDLE) ||
5259*7c478bd9Sstevel@tonic-gate 	    (pt->p_file != NULL && pt->p_file->gf_ehdr.e_type == ET_EXEC)) {
5260*7c478bd9Sstevel@tonic-gate 
5261*7c478bd9Sstevel@tonic-gate 		int tflag = MDB_TGT_SPEC_STICKY; /* default sigs are sticky */
5262*7c478bd9Sstevel@tonic-gate 
5263*7c478bd9Sstevel@tonic-gate 		(void) mdb_tgt_add_signal(t, SIGINT, tflag, no_se_f, NULL);
5264*7c478bd9Sstevel@tonic-gate 		(void) mdb_tgt_add_signal(t, SIGQUIT, tflag, no_se_f, NULL);
5265*7c478bd9Sstevel@tonic-gate 		(void) mdb_tgt_add_signal(t, SIGILL, tflag, no_se_f, NULL);
5266*7c478bd9Sstevel@tonic-gate 		(void) mdb_tgt_add_signal(t, SIGTRAP, tflag, no_se_f, NULL);
5267*7c478bd9Sstevel@tonic-gate 		(void) mdb_tgt_add_signal(t, SIGABRT, tflag, no_se_f, NULL);
5268*7c478bd9Sstevel@tonic-gate 		(void) mdb_tgt_add_signal(t, SIGEMT, tflag, no_se_f, NULL);
5269*7c478bd9Sstevel@tonic-gate 		(void) mdb_tgt_add_signal(t, SIGFPE, tflag, no_se_f, NULL);
5270*7c478bd9Sstevel@tonic-gate 		(void) mdb_tgt_add_signal(t, SIGBUS, tflag, no_se_f, NULL);
5271*7c478bd9Sstevel@tonic-gate 		(void) mdb_tgt_add_signal(t, SIGSEGV, tflag, no_se_f, NULL);
5272*7c478bd9Sstevel@tonic-gate 		(void) mdb_tgt_add_signal(t, SIGSYS, tflag, no_se_f, NULL);
5273*7c478bd9Sstevel@tonic-gate 		(void) mdb_tgt_add_signal(t, SIGXCPU, tflag, no_se_f, NULL);
5274*7c478bd9Sstevel@tonic-gate 		(void) mdb_tgt_add_signal(t, SIGXFSZ, tflag, no_se_f, NULL);
5275*7c478bd9Sstevel@tonic-gate 	}
5276*7c478bd9Sstevel@tonic-gate 
5277*7c478bd9Sstevel@tonic-gate 	/*
5278*7c478bd9Sstevel@tonic-gate 	 * If we've grabbed a live process, establish our initial breakpoints
5279*7c478bd9Sstevel@tonic-gate 	 * and librtld_db agent so we can track rtld activity.  If FL_VCREATE
5280*7c478bd9Sstevel@tonic-gate 	 * is set, this process was created by a previous instantiation of
5281*7c478bd9Sstevel@tonic-gate 	 * the debugger, so reset pr_flags to kill it; otherwise we attached
5282*7c478bd9Sstevel@tonic-gate 	 * to an already running process.  Pgrab() has already set the PR_RLC
5283*7c478bd9Sstevel@tonic-gate 	 * flag appropriately based on whether the process was stopped when we
5284*7c478bd9Sstevel@tonic-gate 	 * attached.
5285*7c478bd9Sstevel@tonic-gate 	 */
5286*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle != NULL && state != PS_DEAD && state != PS_IDLE) {
5287*7c478bd9Sstevel@tonic-gate 		if (mdb.m_flags & MDB_FL_VCREATE) {
5288*7c478bd9Sstevel@tonic-gate 			(void) Punsetflags(t->t_pshandle, PR_RLC);
5289*7c478bd9Sstevel@tonic-gate 			(void) Psetflags(t->t_pshandle, PR_KLC);
5290*7c478bd9Sstevel@tonic-gate 			pt->p_rflags = PRELEASE_KILL;
5291*7c478bd9Sstevel@tonic-gate 		} else {
5292*7c478bd9Sstevel@tonic-gate 			(void) Punsetflags(t->t_pshandle, PR_KLC);
5293*7c478bd9Sstevel@tonic-gate 		}
5294*7c478bd9Sstevel@tonic-gate 		pt_post_attach(t);
5295*7c478bd9Sstevel@tonic-gate 	}
5296*7c478bd9Sstevel@tonic-gate 
5297*7c478bd9Sstevel@tonic-gate 	/*
5298*7c478bd9Sstevel@tonic-gate 	 * Initialize a local copy of the environment, which can be modified
5299*7c478bd9Sstevel@tonic-gate 	 * before running the program.
5300*7c478bd9Sstevel@tonic-gate 	 */
5301*7c478bd9Sstevel@tonic-gate 	for (i = 0; mdb.m_env[i] != NULL; i++)
5302*7c478bd9Sstevel@tonic-gate 		pt_env_set(pt, mdb.m_env[i]);
5303*7c478bd9Sstevel@tonic-gate 
5304*7c478bd9Sstevel@tonic-gate 	/*
5305*7c478bd9Sstevel@tonic-gate 	 * If adb(1) compatibility mode is on, then print the appropriate
5306*7c478bd9Sstevel@tonic-gate 	 * greeting message if we have grabbed a core file.
5307*7c478bd9Sstevel@tonic-gate 	 */
5308*7c478bd9Sstevel@tonic-gate 	if ((mdb.m_flags & MDB_FL_ADB) && t->t_pshandle != NULL &&
5309*7c478bd9Sstevel@tonic-gate 	    state == PS_DEAD) {
5310*7c478bd9Sstevel@tonic-gate 		const pstatus_t *psp = Pstatus(t->t_pshandle);
5311*7c478bd9Sstevel@tonic-gate 		int cursig = psp->pr_lwp.pr_cursig;
5312*7c478bd9Sstevel@tonic-gate 		char signame[SIG2STR_MAX];
5313*7c478bd9Sstevel@tonic-gate 
5314*7c478bd9Sstevel@tonic-gate 		mdb_printf("core file = %s -- program ``%s'' on platform %s\n",
5315*7c478bd9Sstevel@tonic-gate 		    core_path, aout_path ? aout_path : "?", pt_platform(t));
5316*7c478bd9Sstevel@tonic-gate 
5317*7c478bd9Sstevel@tonic-gate 		if (cursig != 0 && sig2str(cursig, signame) == 0)
5318*7c478bd9Sstevel@tonic-gate 			mdb_printf("SIG%s: %s\n", signame, strsignal(cursig));
5319*7c478bd9Sstevel@tonic-gate 	}
5320*7c478bd9Sstevel@tonic-gate 
5321*7c478bd9Sstevel@tonic-gate 	return (0);
5322*7c478bd9Sstevel@tonic-gate 
5323*7c478bd9Sstevel@tonic-gate err:
5324*7c478bd9Sstevel@tonic-gate 	pt_destroy(t);
5325*7c478bd9Sstevel@tonic-gate 	return (-1);
5326*7c478bd9Sstevel@tonic-gate }
5327