xref: /illumos-gate/usr/src/cmd/mdb/common/mdb/mdb_main.c (revision 7c478bd95313f5f23a4c958a745db2134aa0324)
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 #include <sys/types.h>
30*7c478bd9Sstevel@tonic-gate #include <sys/mman.h>
31*7c478bd9Sstevel@tonic-gate #include <sys/priocntl.h>
32*7c478bd9Sstevel@tonic-gate #include <sys/rtpriocntl.h>
33*7c478bd9Sstevel@tonic-gate #include <sys/resource.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/termios.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/regset.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/frame.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/stack.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/reg.h>
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate #include <libproc.h>
42*7c478bd9Sstevel@tonic-gate #include <libscf.h>
43*7c478bd9Sstevel@tonic-gate #include <alloca.h>
44*7c478bd9Sstevel@tonic-gate #include <unistd.h>
45*7c478bd9Sstevel@tonic-gate #include <string.h>
46*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
47*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
48*7c478bd9Sstevel@tonic-gate #include <dlfcn.h>
49*7c478bd9Sstevel@tonic-gate #include <libctf.h>
50*7c478bd9Sstevel@tonic-gate #include <errno.h>
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_lex.h>
53*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_debug.h>
54*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_signal.h>
55*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_string.h>
56*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
57*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_target.h>
58*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_gelf.h>
59*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_conf.h>
60*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_err.h>
61*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_io_impl.h>
62*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_frame.h>
63*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_set.h>
64*7c478bd9Sstevel@tonic-gate #include <kmdb/kmdb_kctl.h>
65*7c478bd9Sstevel@tonic-gate #include <mdb/mdb.h>
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate #ifndef STACK_BIAS
68*7c478bd9Sstevel@tonic-gate #define	STACK_BIAS	0
69*7c478bd9Sstevel@tonic-gate #endif
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate #if defined(__sparc)
72*7c478bd9Sstevel@tonic-gate #define	STACK_REGISTER	SP
73*7c478bd9Sstevel@tonic-gate #else
74*7c478bd9Sstevel@tonic-gate #define	STACK_REGISTER	REG_FP
75*7c478bd9Sstevel@tonic-gate #endif
76*7c478bd9Sstevel@tonic-gate 
77*7c478bd9Sstevel@tonic-gate #ifdef _LP64
78*7c478bd9Sstevel@tonic-gate #define	MDB_DEF_IPATH	\
79*7c478bd9Sstevel@tonic-gate 	"%r/usr/platform/%p/lib/adb/%i:" \
80*7c478bd9Sstevel@tonic-gate 	"%r/usr/platform/%m/lib/adb/%i:" \
81*7c478bd9Sstevel@tonic-gate 	"%r/usr/lib/adb/%i"
82*7c478bd9Sstevel@tonic-gate #define	MDB_DEF_LPATH	\
83*7c478bd9Sstevel@tonic-gate 	"%r/usr/platform/%p/lib/mdb/%t/%i:" \
84*7c478bd9Sstevel@tonic-gate 	"%r/usr/platform/%m/lib/mdb/%t/%i:" \
85*7c478bd9Sstevel@tonic-gate 	"%r/usr/lib/mdb/%t/%i"
86*7c478bd9Sstevel@tonic-gate #else
87*7c478bd9Sstevel@tonic-gate #define	MDB_DEF_IPATH	\
88*7c478bd9Sstevel@tonic-gate 	"%r/usr/platform/%p/lib/adb:" \
89*7c478bd9Sstevel@tonic-gate 	"%r/usr/platform/%m/lib/adb:" \
90*7c478bd9Sstevel@tonic-gate 	"%r/usr/lib/adb"
91*7c478bd9Sstevel@tonic-gate #define	MDB_DEF_LPATH	\
92*7c478bd9Sstevel@tonic-gate 	"%r/usr/platform/%p/lib/mdb/%t:" \
93*7c478bd9Sstevel@tonic-gate 	"%r/usr/platform/%m/lib/mdb/%t:" \
94*7c478bd9Sstevel@tonic-gate 	"%r/usr/lib/mdb/%t"
95*7c478bd9Sstevel@tonic-gate #endif
96*7c478bd9Sstevel@tonic-gate 
97*7c478bd9Sstevel@tonic-gate #define	MDB_DEF_PROMPT "> "
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate /*
100*7c478bd9Sstevel@tonic-gate  * Similar to the panic_* variables in the kernel, we keep some relevant
101*7c478bd9Sstevel@tonic-gate  * information stored in a set of global _mdb_abort_* variables; in the
102*7c478bd9Sstevel@tonic-gate  * event that the debugger dumps core, these will aid core dump analysis.
103*7c478bd9Sstevel@tonic-gate  */
104*7c478bd9Sstevel@tonic-gate const char *volatile _mdb_abort_str;	/* reason for failure */
105*7c478bd9Sstevel@tonic-gate siginfo_t _mdb_abort_info;		/* signal info for fatal signal */
106*7c478bd9Sstevel@tonic-gate ucontext_t _mdb_abort_ctx;		/* context fatal signal interrupted */
107*7c478bd9Sstevel@tonic-gate int _mdb_abort_rcount;			/* number of times resume requested */
108*7c478bd9Sstevel@tonic-gate int _mdb_self_fd = -1;			/* fd for self as for valid_frame */
109*7c478bd9Sstevel@tonic-gate 
110*7c478bd9Sstevel@tonic-gate static void
111*7c478bd9Sstevel@tonic-gate terminate(int status)
112*7c478bd9Sstevel@tonic-gate {
113*7c478bd9Sstevel@tonic-gate 	mdb_destroy();
114*7c478bd9Sstevel@tonic-gate 	exit(status);
115*7c478bd9Sstevel@tonic-gate }
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate static void
118*7c478bd9Sstevel@tonic-gate print_frame(uintptr_t pc, int fnum)
119*7c478bd9Sstevel@tonic-gate {
120*7c478bd9Sstevel@tonic-gate 	Dl_info dli;
121*7c478bd9Sstevel@tonic-gate 
122*7c478bd9Sstevel@tonic-gate 	if (dladdr((void *)pc, &dli)) {
123*7c478bd9Sstevel@tonic-gate 		mdb_iob_printf(mdb.m_err, "    [%d] %s`%s+0x%lx()\n", fnum,
124*7c478bd9Sstevel@tonic-gate 		    strbasename(dli.dli_fname), dli.dli_sname,
125*7c478bd9Sstevel@tonic-gate 		    pc - (uintptr_t)dli.dli_saddr);
126*7c478bd9Sstevel@tonic-gate 	} else
127*7c478bd9Sstevel@tonic-gate 		mdb_iob_printf(mdb.m_err, "    [%d] %p()\n", fnum, pc);
128*7c478bd9Sstevel@tonic-gate }
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate static int
131*7c478bd9Sstevel@tonic-gate valid_frame(struct frame *fr)
132*7c478bd9Sstevel@tonic-gate {
133*7c478bd9Sstevel@tonic-gate 	static struct frame fake;
134*7c478bd9Sstevel@tonic-gate 	uintptr_t addr = (uintptr_t)fr;
135*7c478bd9Sstevel@tonic-gate 
136*7c478bd9Sstevel@tonic-gate 	if (pread(_mdb_self_fd, &fake, sizeof (fake), addr) != sizeof (fake)) {
137*7c478bd9Sstevel@tonic-gate 		mdb_iob_printf(mdb.m_err, "    invalid frame (%p)\n", fr);
138*7c478bd9Sstevel@tonic-gate 		return (0);
139*7c478bd9Sstevel@tonic-gate 	}
140*7c478bd9Sstevel@tonic-gate 
141*7c478bd9Sstevel@tonic-gate 	if (addr & (STACK_ALIGN - 1)) {
142*7c478bd9Sstevel@tonic-gate 		mdb_iob_printf(mdb.m_err, "    mis-aligned frame (%p)\n", fr);
143*7c478bd9Sstevel@tonic-gate 		return (0);
144*7c478bd9Sstevel@tonic-gate 	}
145*7c478bd9Sstevel@tonic-gate 
146*7c478bd9Sstevel@tonic-gate 	return (1);
147*7c478bd9Sstevel@tonic-gate }
148*7c478bd9Sstevel@tonic-gate 
149*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
150*7c478bd9Sstevel@tonic-gate static void
151*7c478bd9Sstevel@tonic-gate flt_handler(int sig, siginfo_t *sip, ucontext_t *ucp, void *data)
152*7c478bd9Sstevel@tonic-gate {
153*7c478bd9Sstevel@tonic-gate 	static const struct rlimit rl = {
154*7c478bd9Sstevel@tonic-gate 		(rlim_t)RLIM_INFINITY, (rlim_t)RLIM_INFINITY
155*7c478bd9Sstevel@tonic-gate 	};
156*7c478bd9Sstevel@tonic-gate 
157*7c478bd9Sstevel@tonic-gate 	const mdb_idcmd_t *idcp = NULL;
158*7c478bd9Sstevel@tonic-gate 
159*7c478bd9Sstevel@tonic-gate 	if (mdb.m_frame != NULL && mdb.m_frame->f_cp != NULL)
160*7c478bd9Sstevel@tonic-gate 		idcp = mdb.m_frame->f_cp->c_dcmd;
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate 	if (sip != NULL)
163*7c478bd9Sstevel@tonic-gate 		bcopy(sip, &_mdb_abort_info, sizeof (_mdb_abort_info));
164*7c478bd9Sstevel@tonic-gate 	if (ucp != NULL)
165*7c478bd9Sstevel@tonic-gate 		bcopy(ucp, &_mdb_abort_ctx, sizeof (_mdb_abort_ctx));
166*7c478bd9Sstevel@tonic-gate 
167*7c478bd9Sstevel@tonic-gate 	_mdb_abort_info.si_signo = sig;
168*7c478bd9Sstevel@tonic-gate 	(void) mdb_signal_sethandler(sig, SIG_DFL, NULL);
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate 	/*
171*7c478bd9Sstevel@tonic-gate 	 * If there is no current dcmd, or the current dcmd comes from a
172*7c478bd9Sstevel@tonic-gate 	 * builtin module, we don't allow resume and always core dump.
173*7c478bd9Sstevel@tonic-gate 	 */
174*7c478bd9Sstevel@tonic-gate 	if (idcp == NULL || idcp->idc_modp == NULL ||
175*7c478bd9Sstevel@tonic-gate 	    idcp->idc_modp == &mdb.m_rmod || idcp->idc_modp->mod_hdl == NULL)
176*7c478bd9Sstevel@tonic-gate 		goto dump;
177*7c478bd9Sstevel@tonic-gate 
178*7c478bd9Sstevel@tonic-gate 	if (mdb.m_term != NULL) {
179*7c478bd9Sstevel@tonic-gate 		struct frame *fr = (struct frame *)
180*7c478bd9Sstevel@tonic-gate 		    (ucp->uc_mcontext.gregs[STACK_REGISTER] + STACK_BIAS);
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate 		char signame[SIG2STR_MAX];
183*7c478bd9Sstevel@tonic-gate 		int i = 1;
184*7c478bd9Sstevel@tonic-gate 		char c;
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate 		if (sig2str(sig, signame) == -1) {
187*7c478bd9Sstevel@tonic-gate 			mdb_iob_printf(mdb.m_err,
188*7c478bd9Sstevel@tonic-gate 			    "\n*** %s: received signal %d at:\n",
189*7c478bd9Sstevel@tonic-gate 			    mdb.m_pname, sig);
190*7c478bd9Sstevel@tonic-gate 		} else {
191*7c478bd9Sstevel@tonic-gate 			mdb_iob_printf(mdb.m_err,
192*7c478bd9Sstevel@tonic-gate 			    "\n*** %s: received signal %s at:\n",
193*7c478bd9Sstevel@tonic-gate 			    mdb.m_pname, signame);
194*7c478bd9Sstevel@tonic-gate 		}
195*7c478bd9Sstevel@tonic-gate 
196*7c478bd9Sstevel@tonic-gate 		if (ucp->uc_mcontext.gregs[REG_PC] != 0)
197*7c478bd9Sstevel@tonic-gate 			print_frame(ucp->uc_mcontext.gregs[REG_PC], i++);
198*7c478bd9Sstevel@tonic-gate 
199*7c478bd9Sstevel@tonic-gate 		while (fr != NULL && valid_frame(fr) && fr->fr_savpc != 0) {
200*7c478bd9Sstevel@tonic-gate 			print_frame(fr->fr_savpc, i++);
201*7c478bd9Sstevel@tonic-gate 			fr = (struct frame *)
202*7c478bd9Sstevel@tonic-gate 			    ((uintptr_t)fr->fr_savfp + STACK_BIAS);
203*7c478bd9Sstevel@tonic-gate 		}
204*7c478bd9Sstevel@tonic-gate 
205*7c478bd9Sstevel@tonic-gate query:
206*7c478bd9Sstevel@tonic-gate 		mdb_iob_printf(mdb.m_err, "\n%s: (c)ore dump, (q)uit, "
207*7c478bd9Sstevel@tonic-gate 		    "(r)ecover, or (s)top for debugger [cqrs]? ", mdb.m_pname);
208*7c478bd9Sstevel@tonic-gate 
209*7c478bd9Sstevel@tonic-gate 		mdb_iob_flush(mdb.m_err);
210*7c478bd9Sstevel@tonic-gate 
211*7c478bd9Sstevel@tonic-gate 		for (;;) {
212*7c478bd9Sstevel@tonic-gate 			if (IOP_READ(mdb.m_term, &c, sizeof (c)) != sizeof (c))
213*7c478bd9Sstevel@tonic-gate 				goto dump;
214*7c478bd9Sstevel@tonic-gate 
215*7c478bd9Sstevel@tonic-gate 			switch (c) {
216*7c478bd9Sstevel@tonic-gate 			case 'c':
217*7c478bd9Sstevel@tonic-gate 			case 'C':
218*7c478bd9Sstevel@tonic-gate 				(void) setrlimit(RLIMIT_CORE, &rl);
219*7c478bd9Sstevel@tonic-gate 				mdb_iob_printf(mdb.m_err, "\n%s: attempting "
220*7c478bd9Sstevel@tonic-gate 				    "to dump core ...\n", mdb.m_pname);
221*7c478bd9Sstevel@tonic-gate 				goto dump;
222*7c478bd9Sstevel@tonic-gate 
223*7c478bd9Sstevel@tonic-gate 			case 'q':
224*7c478bd9Sstevel@tonic-gate 			case 'Q':
225*7c478bd9Sstevel@tonic-gate 				mdb_iob_discard(mdb.m_out);
226*7c478bd9Sstevel@tonic-gate 				mdb_iob_nl(mdb.m_err);
227*7c478bd9Sstevel@tonic-gate 				(void) mdb_signal_unblockall();
228*7c478bd9Sstevel@tonic-gate 				terminate(1);
229*7c478bd9Sstevel@tonic-gate 				/*NOTREACHED*/
230*7c478bd9Sstevel@tonic-gate 
231*7c478bd9Sstevel@tonic-gate 			case 'r':
232*7c478bd9Sstevel@tonic-gate 			case 'R':
233*7c478bd9Sstevel@tonic-gate 				mdb_iob_printf(mdb.m_err, "\n%s: unloading "
234*7c478bd9Sstevel@tonic-gate 				    "module '%s' ...\n", mdb.m_pname,
235*7c478bd9Sstevel@tonic-gate 				    idcp->idc_modp->mod_name);
236*7c478bd9Sstevel@tonic-gate 
237*7c478bd9Sstevel@tonic-gate 				(void) mdb_module_unload(
238*7c478bd9Sstevel@tonic-gate 				    idcp->idc_modp->mod_name, 0);
239*7c478bd9Sstevel@tonic-gate 
240*7c478bd9Sstevel@tonic-gate 				(void) mdb_signal_sethandler(sig,
241*7c478bd9Sstevel@tonic-gate 				    flt_handler, NULL);
242*7c478bd9Sstevel@tonic-gate 
243*7c478bd9Sstevel@tonic-gate 				_mdb_abort_rcount++;
244*7c478bd9Sstevel@tonic-gate 				mdb.m_intr = 0;
245*7c478bd9Sstevel@tonic-gate 				mdb.m_pend = 0;
246*7c478bd9Sstevel@tonic-gate 
247*7c478bd9Sstevel@tonic-gate 				(void) mdb_signal_unblockall();
248*7c478bd9Sstevel@tonic-gate 				longjmp(mdb.m_frame->f_pcb, MDB_ERR_ABORT);
249*7c478bd9Sstevel@tonic-gate 				/*NOTREACHED*/
250*7c478bd9Sstevel@tonic-gate 
251*7c478bd9Sstevel@tonic-gate 			case 's':
252*7c478bd9Sstevel@tonic-gate 			case 'S':
253*7c478bd9Sstevel@tonic-gate 				mdb_iob_printf(mdb.m_err, "\n%s: "
254*7c478bd9Sstevel@tonic-gate 				    "attempting to stop pid %d ...\n",
255*7c478bd9Sstevel@tonic-gate 				    mdb.m_pname, (int)getpid());
256*7c478bd9Sstevel@tonic-gate 
257*7c478bd9Sstevel@tonic-gate 				/*
258*7c478bd9Sstevel@tonic-gate 				 * Stop ourself; if this fails or we are
259*7c478bd9Sstevel@tonic-gate 				 * subsequently continued, ask again.
260*7c478bd9Sstevel@tonic-gate 				 */
261*7c478bd9Sstevel@tonic-gate 				(void) mdb_signal_raise(SIGSTOP);
262*7c478bd9Sstevel@tonic-gate 				(void) mdb_signal_unblockall();
263*7c478bd9Sstevel@tonic-gate 				goto query;
264*7c478bd9Sstevel@tonic-gate 			}
265*7c478bd9Sstevel@tonic-gate 		}
266*7c478bd9Sstevel@tonic-gate 	}
267*7c478bd9Sstevel@tonic-gate 
268*7c478bd9Sstevel@tonic-gate dump:
269*7c478bd9Sstevel@tonic-gate 	if (SI_FROMUSER(sip)) {
270*7c478bd9Sstevel@tonic-gate 		(void) mdb_signal_block(sig);
271*7c478bd9Sstevel@tonic-gate 		(void) mdb_signal_raise(sig);
272*7c478bd9Sstevel@tonic-gate 	}
273*7c478bd9Sstevel@tonic-gate 
274*7c478bd9Sstevel@tonic-gate 	(void) sigfillset(&ucp->uc_sigmask);
275*7c478bd9Sstevel@tonic-gate 	(void) sigdelset(&ucp->uc_sigmask, sig);
276*7c478bd9Sstevel@tonic-gate 
277*7c478bd9Sstevel@tonic-gate 	if (_mdb_abort_str == NULL)
278*7c478bd9Sstevel@tonic-gate 		_mdb_abort_str = "fatal signal received";
279*7c478bd9Sstevel@tonic-gate 
280*7c478bd9Sstevel@tonic-gate 	ucp->uc_flags |= UC_SIGMASK;
281*7c478bd9Sstevel@tonic-gate 	(void) setcontext(ucp);
282*7c478bd9Sstevel@tonic-gate }
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
285*7c478bd9Sstevel@tonic-gate static void
286*7c478bd9Sstevel@tonic-gate int_handler(int sig, siginfo_t *sip, ucontext_t *ucp, void *data)
287*7c478bd9Sstevel@tonic-gate {
288*7c478bd9Sstevel@tonic-gate 	if (mdb.m_intr == 0)
289*7c478bd9Sstevel@tonic-gate 		longjmp(mdb.m_frame->f_pcb, MDB_ERR_SIGINT);
290*7c478bd9Sstevel@tonic-gate 	else
291*7c478bd9Sstevel@tonic-gate 		mdb.m_pend++;
292*7c478bd9Sstevel@tonic-gate }
293*7c478bd9Sstevel@tonic-gate 
294*7c478bd9Sstevel@tonic-gate static void
295*7c478bd9Sstevel@tonic-gate control_kmdb(int start)
296*7c478bd9Sstevel@tonic-gate {
297*7c478bd9Sstevel@tonic-gate 	int fd;
298*7c478bd9Sstevel@tonic-gate 
299*7c478bd9Sstevel@tonic-gate 	if ((fd = open("/dev/kmdb", O_RDONLY)) < 0)
300*7c478bd9Sstevel@tonic-gate 		die("failed to open /dev/kmdb");
301*7c478bd9Sstevel@tonic-gate 
302*7c478bd9Sstevel@tonic-gate 	if (start) {
303*7c478bd9Sstevel@tonic-gate 		char *state = mdb_get_config();
304*7c478bd9Sstevel@tonic-gate 
305*7c478bd9Sstevel@tonic-gate 		if (ioctl(fd, KMDB_IOC_START, state) < 0)
306*7c478bd9Sstevel@tonic-gate 			die("failed to start kmdb");
307*7c478bd9Sstevel@tonic-gate 
308*7c478bd9Sstevel@tonic-gate 		strfree(state);
309*7c478bd9Sstevel@tonic-gate 	} else {
310*7c478bd9Sstevel@tonic-gate 		if (ioctl(fd, KMDB_IOC_STOP) < 0)
311*7c478bd9Sstevel@tonic-gate 			die("failed to stop kmdb");
312*7c478bd9Sstevel@tonic-gate 	}
313*7c478bd9Sstevel@tonic-gate 
314*7c478bd9Sstevel@tonic-gate 	close(fd);
315*7c478bd9Sstevel@tonic-gate }
316*7c478bd9Sstevel@tonic-gate 
317*7c478bd9Sstevel@tonic-gate static void
318*7c478bd9Sstevel@tonic-gate usage(int status)
319*7c478bd9Sstevel@tonic-gate {
320*7c478bd9Sstevel@tonic-gate 	mdb_iob_printf(mdb.m_err, "Usage: %s [-fkmuwyAFKMSUW] [+/-o option] "
321*7c478bd9Sstevel@tonic-gate 	    "[-p pid] [-s dist] [-I path] [-L path]\n\t[-P prompt] "
322*7c478bd9Sstevel@tonic-gate 	    "[-R root] [-V dis-version] [object [core] | core | suffix]\n\n",
323*7c478bd9Sstevel@tonic-gate 	    mdb.m_pname);
324*7c478bd9Sstevel@tonic-gate 
325*7c478bd9Sstevel@tonic-gate 	mdb_iob_puts(mdb.m_err,
326*7c478bd9Sstevel@tonic-gate 	    "\t-f force raw file debugging mode\n"
327*7c478bd9Sstevel@tonic-gate 	    "\t-k force kernel debugging mode\n"
328*7c478bd9Sstevel@tonic-gate 	    "\t-m disable demand-loading of module symbols\n"
329*7c478bd9Sstevel@tonic-gate 	    "\t-o set specified debugger option (+o to unset)\n"
330*7c478bd9Sstevel@tonic-gate 	    "\t-p attach to specified process-id\n"
331*7c478bd9Sstevel@tonic-gate 	    "\t-s set symbol matching distance\n"
332*7c478bd9Sstevel@tonic-gate 	    "\t-u force user program debugging mode\n"
333*7c478bd9Sstevel@tonic-gate 	    "\t-w enable write mode\n"
334*7c478bd9Sstevel@tonic-gate 	    "\t-y send terminal initialization sequences for tty mode\n"
335*7c478bd9Sstevel@tonic-gate 	    "\t-A disable automatic loading of mdb modules\n"
336*7c478bd9Sstevel@tonic-gate 	    "\t-F enable forcible takeover mode\n"
337*7c478bd9Sstevel@tonic-gate 	    "\t-K stop operating system and enter live kernel debugger\n"
338*7c478bd9Sstevel@tonic-gate 	    "\t-M preload all module symbols\n"
339*7c478bd9Sstevel@tonic-gate 	    "\t-I set initial path for macro files\n"
340*7c478bd9Sstevel@tonic-gate 	    "\t-L set initial path for module libs\n"
341*7c478bd9Sstevel@tonic-gate 	    "\t-P set command-line prompt\n"
342*7c478bd9Sstevel@tonic-gate 	    "\t-R set root directory for pathname expansion\n"
343*7c478bd9Sstevel@tonic-gate 	    "\t-S suppress processing of ~/.mdbrc file\n"
344*7c478bd9Sstevel@tonic-gate 	    "\t-U unload live kernel debugger\n"
345*7c478bd9Sstevel@tonic-gate 	    "\t-W enable I/O-mapped memory access (kernel only)\n"
346*7c478bd9Sstevel@tonic-gate 	    "\t-V set disassembler version\n");
347*7c478bd9Sstevel@tonic-gate 
348*7c478bd9Sstevel@tonic-gate 	terminate(status);
349*7c478bd9Sstevel@tonic-gate }
350*7c478bd9Sstevel@tonic-gate 
351*7c478bd9Sstevel@tonic-gate static char *
352*7c478bd9Sstevel@tonic-gate mdb_scf_console_term(void)
353*7c478bd9Sstevel@tonic-gate {
354*7c478bd9Sstevel@tonic-gate 	scf_simple_prop_t *prop;
355*7c478bd9Sstevel@tonic-gate 	char *term = NULL;
356*7c478bd9Sstevel@tonic-gate 
357*7c478bd9Sstevel@tonic-gate 	if ((prop = scf_simple_prop_get(NULL,
358*7c478bd9Sstevel@tonic-gate 	    "svc:/system/console-login:default", "ttymon",
359*7c478bd9Sstevel@tonic-gate 	    "terminal_type")) == NULL)
360*7c478bd9Sstevel@tonic-gate 		return (NULL);
361*7c478bd9Sstevel@tonic-gate 
362*7c478bd9Sstevel@tonic-gate 	if (scf_simple_prop_type(prop) == SCF_TYPE_ASTRING &&
363*7c478bd9Sstevel@tonic-gate 	    (term = scf_simple_prop_next_astring(prop)) != NULL)
364*7c478bd9Sstevel@tonic-gate 		term = strdup(term);
365*7c478bd9Sstevel@tonic-gate 
366*7c478bd9Sstevel@tonic-gate 	scf_simple_prop_free(prop);
367*7c478bd9Sstevel@tonic-gate 	return (term);
368*7c478bd9Sstevel@tonic-gate }
369*7c478bd9Sstevel@tonic-gate 
370*7c478bd9Sstevel@tonic-gate int
371*7c478bd9Sstevel@tonic-gate main(int argc, char *argv[], char *envp[])
372*7c478bd9Sstevel@tonic-gate {
373*7c478bd9Sstevel@tonic-gate 	mdb_tgt_ctor_f *tgt_ctor = NULL;
374*7c478bd9Sstevel@tonic-gate 	const char **tgt_argv = alloca(argc * sizeof (char *));
375*7c478bd9Sstevel@tonic-gate 	int tgt_argc = 0;
376*7c478bd9Sstevel@tonic-gate 	mdb_tgt_t *tgt;
377*7c478bd9Sstevel@tonic-gate 
378*7c478bd9Sstevel@tonic-gate 	char object[MAXPATHLEN], execname[MAXPATHLEN];
379*7c478bd9Sstevel@tonic-gate 	mdb_io_t *in_io, *out_io, *err_io, *null_io;
380*7c478bd9Sstevel@tonic-gate 	struct termios tios;
381*7c478bd9Sstevel@tonic-gate 	int status, c;
382*7c478bd9Sstevel@tonic-gate 	char *p;
383*7c478bd9Sstevel@tonic-gate 
384*7c478bd9Sstevel@tonic-gate 	const char *Iflag = NULL, *Lflag = NULL, *Vflag = NULL, *pidarg = NULL;
385*7c478bd9Sstevel@tonic-gate 	int Kflag = 0, Rflag = 0, Sflag = 0, Oflag = 0, Uflag = 0;
386*7c478bd9Sstevel@tonic-gate 
387*7c478bd9Sstevel@tonic-gate 	int ttylike;
388*7c478bd9Sstevel@tonic-gate 
389*7c478bd9Sstevel@tonic-gate 	stack_t sigstack;
390*7c478bd9Sstevel@tonic-gate 
391*7c478bd9Sstevel@tonic-gate 	if (realpath(getexecname(), execname) == NULL) {
392*7c478bd9Sstevel@tonic-gate 		(void) strncpy(execname, argv[0], MAXPATHLEN);
393*7c478bd9Sstevel@tonic-gate 		execname[MAXPATHLEN - 1] = '\0';
394*7c478bd9Sstevel@tonic-gate 	}
395*7c478bd9Sstevel@tonic-gate 
396*7c478bd9Sstevel@tonic-gate 	mdb_create(execname, argv[0]);
397*7c478bd9Sstevel@tonic-gate 	bzero(tgt_argv, argc * sizeof (char *));
398*7c478bd9Sstevel@tonic-gate 	argv[0] = (char *)mdb.m_pname;
399*7c478bd9Sstevel@tonic-gate 	_mdb_self_fd = open("/proc/self/as", O_RDONLY);
400*7c478bd9Sstevel@tonic-gate 
401*7c478bd9Sstevel@tonic-gate 	mdb.m_env = envp;
402*7c478bd9Sstevel@tonic-gate 
403*7c478bd9Sstevel@tonic-gate 	out_io = mdb_fdio_create(STDOUT_FILENO);
404*7c478bd9Sstevel@tonic-gate 	mdb.m_out = mdb_iob_create(out_io, MDB_IOB_WRONLY);
405*7c478bd9Sstevel@tonic-gate 
406*7c478bd9Sstevel@tonic-gate 	err_io = mdb_fdio_create(STDERR_FILENO);
407*7c478bd9Sstevel@tonic-gate 	mdb.m_err = mdb_iob_create(err_io, MDB_IOB_WRONLY);
408*7c478bd9Sstevel@tonic-gate 	mdb_iob_clrflags(mdb.m_err, MDB_IOB_AUTOWRAP);
409*7c478bd9Sstevel@tonic-gate 
410*7c478bd9Sstevel@tonic-gate 	null_io = mdb_nullio_create();
411*7c478bd9Sstevel@tonic-gate 	mdb.m_null = mdb_iob_create(null_io, MDB_IOB_WRONLY);
412*7c478bd9Sstevel@tonic-gate 
413*7c478bd9Sstevel@tonic-gate 	in_io = mdb_fdio_create(STDIN_FILENO);
414*7c478bd9Sstevel@tonic-gate 	if ((mdb.m_termtype = getenv("TERM")) != NULL) {
415*7c478bd9Sstevel@tonic-gate 		mdb.m_termtype = strdup(mdb.m_termtype);
416*7c478bd9Sstevel@tonic-gate 		mdb.m_flags |= MDB_FL_TERMGUESS;
417*7c478bd9Sstevel@tonic-gate 	}
418*7c478bd9Sstevel@tonic-gate 	mdb.m_term = NULL;
419*7c478bd9Sstevel@tonic-gate 
420*7c478bd9Sstevel@tonic-gate 	mdb_dmode(mdb_dstr2mode(getenv("MDB_DEBUG")));
421*7c478bd9Sstevel@tonic-gate 	mdb.m_pgid = getpgrp();
422*7c478bd9Sstevel@tonic-gate 
423*7c478bd9Sstevel@tonic-gate 	if (getenv("_MDB_EXEC") != NULL)
424*7c478bd9Sstevel@tonic-gate 		mdb.m_flags |= MDB_FL_EXEC;
425*7c478bd9Sstevel@tonic-gate 
426*7c478bd9Sstevel@tonic-gate 	/*
427*7c478bd9Sstevel@tonic-gate 	 * Setup an alternate signal stack.  When tearing down pipelines in
428*7c478bd9Sstevel@tonic-gate 	 * terminate(), we may have to destroy the stack of the context in
429*7c478bd9Sstevel@tonic-gate 	 * which we are currently executing the signal handler.
430*7c478bd9Sstevel@tonic-gate 	 */
431*7c478bd9Sstevel@tonic-gate 	sigstack.ss_sp = mmap(NULL, SIGSTKSZ, PROT_READ | PROT_WRITE,
432*7c478bd9Sstevel@tonic-gate 	    MAP_PRIVATE | MAP_ANON, -1, 0);
433*7c478bd9Sstevel@tonic-gate 	if (sigstack.ss_sp == MAP_FAILED)
434*7c478bd9Sstevel@tonic-gate 		die("could not allocate signal stack");
435*7c478bd9Sstevel@tonic-gate 	sigstack.ss_size = SIGSTKSZ;
436*7c478bd9Sstevel@tonic-gate 	sigstack.ss_flags = 0;
437*7c478bd9Sstevel@tonic-gate 	if (sigaltstack(&sigstack, NULL) != 0)
438*7c478bd9Sstevel@tonic-gate 		die("could not set signal stack");
439*7c478bd9Sstevel@tonic-gate 
440*7c478bd9Sstevel@tonic-gate 	(void) mdb_signal_sethandler(SIGPIPE, SIG_IGN, NULL);
441*7c478bd9Sstevel@tonic-gate 	(void) mdb_signal_sethandler(SIGQUIT, SIG_IGN, NULL);
442*7c478bd9Sstevel@tonic-gate 
443*7c478bd9Sstevel@tonic-gate 	(void) mdb_signal_sethandler(SIGILL, flt_handler, NULL);
444*7c478bd9Sstevel@tonic-gate 	(void) mdb_signal_sethandler(SIGTRAP, flt_handler, NULL);
445*7c478bd9Sstevel@tonic-gate 	(void) mdb_signal_sethandler(SIGIOT, flt_handler, NULL);
446*7c478bd9Sstevel@tonic-gate 	(void) mdb_signal_sethandler(SIGEMT, flt_handler, NULL);
447*7c478bd9Sstevel@tonic-gate 	(void) mdb_signal_sethandler(SIGFPE, flt_handler, NULL);
448*7c478bd9Sstevel@tonic-gate 	(void) mdb_signal_sethandler(SIGBUS, flt_handler, NULL);
449*7c478bd9Sstevel@tonic-gate 	(void) mdb_signal_sethandler(SIGSEGV, flt_handler, NULL);
450*7c478bd9Sstevel@tonic-gate 
451*7c478bd9Sstevel@tonic-gate 	(void) mdb_signal_sethandler(SIGHUP, (mdb_signal_f *)terminate, NULL);
452*7c478bd9Sstevel@tonic-gate 	(void) mdb_signal_sethandler(SIGTERM, (mdb_signal_f *)terminate, NULL);
453*7c478bd9Sstevel@tonic-gate 
454*7c478bd9Sstevel@tonic-gate 	for (mdb.m_rdvers = RD_VERSION; mdb.m_rdvers > 0; mdb.m_rdvers--) {
455*7c478bd9Sstevel@tonic-gate 		if (rd_init(mdb.m_rdvers) == RD_OK)
456*7c478bd9Sstevel@tonic-gate 			break;
457*7c478bd9Sstevel@tonic-gate 	}
458*7c478bd9Sstevel@tonic-gate 
459*7c478bd9Sstevel@tonic-gate 	for (mdb.m_ctfvers = CTF_VERSION; mdb.m_ctfvers > 0; mdb.m_ctfvers--) {
460*7c478bd9Sstevel@tonic-gate 		if (ctf_version(mdb.m_ctfvers) != -1)
461*7c478bd9Sstevel@tonic-gate 			break;
462*7c478bd9Sstevel@tonic-gate 	}
463*7c478bd9Sstevel@tonic-gate 
464*7c478bd9Sstevel@tonic-gate 	if ((p = getenv("HISTSIZE")) != NULL && strisnum(p)) {
465*7c478bd9Sstevel@tonic-gate 		mdb.m_histlen = strtoi(p);
466*7c478bd9Sstevel@tonic-gate 		if (mdb.m_histlen < 1)
467*7c478bd9Sstevel@tonic-gate 			mdb.m_histlen = 1;
468*7c478bd9Sstevel@tonic-gate 	}
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate 	while (optind < argc) {
471*7c478bd9Sstevel@tonic-gate 		while ((c = getopt(argc, argv,
472*7c478bd9Sstevel@tonic-gate 		    "fkmo:p:s:uwyACD:FI:KL:MOP:R:SUV:W")) != (int)EOF) {
473*7c478bd9Sstevel@tonic-gate 			switch (c) {
474*7c478bd9Sstevel@tonic-gate 			case 'f':
475*7c478bd9Sstevel@tonic-gate 				tgt_ctor = mdb_rawfile_tgt_create;
476*7c478bd9Sstevel@tonic-gate 				break;
477*7c478bd9Sstevel@tonic-gate 			case 'k':
478*7c478bd9Sstevel@tonic-gate 				tgt_ctor = mdb_kvm_tgt_create;
479*7c478bd9Sstevel@tonic-gate 				break;
480*7c478bd9Sstevel@tonic-gate 			case 'm':
481*7c478bd9Sstevel@tonic-gate 				mdb.m_tgtflags |= MDB_TGT_F_NOLOAD;
482*7c478bd9Sstevel@tonic-gate 				mdb.m_tgtflags &= ~MDB_TGT_F_PRELOAD;
483*7c478bd9Sstevel@tonic-gate 				break;
484*7c478bd9Sstevel@tonic-gate 			case 'o':
485*7c478bd9Sstevel@tonic-gate 				if (!mdb_set_options(optarg, TRUE))
486*7c478bd9Sstevel@tonic-gate 					terminate(2);
487*7c478bd9Sstevel@tonic-gate 				break;
488*7c478bd9Sstevel@tonic-gate 			case 'p':
489*7c478bd9Sstevel@tonic-gate 				tgt_ctor = mdb_proc_tgt_create;
490*7c478bd9Sstevel@tonic-gate 				pidarg = optarg;
491*7c478bd9Sstevel@tonic-gate 				break;
492*7c478bd9Sstevel@tonic-gate 			case 's':
493*7c478bd9Sstevel@tonic-gate 				if (!strisnum(optarg)) {
494*7c478bd9Sstevel@tonic-gate 					warn("expected integer following -s\n");
495*7c478bd9Sstevel@tonic-gate 					terminate(2);
496*7c478bd9Sstevel@tonic-gate 				}
497*7c478bd9Sstevel@tonic-gate 				mdb.m_symdist = (size_t)(uint_t)strtoi(optarg);
498*7c478bd9Sstevel@tonic-gate 				break;
499*7c478bd9Sstevel@tonic-gate 			case 'u':
500*7c478bd9Sstevel@tonic-gate 				tgt_ctor = mdb_proc_tgt_create;
501*7c478bd9Sstevel@tonic-gate 				break;
502*7c478bd9Sstevel@tonic-gate 			case 'w':
503*7c478bd9Sstevel@tonic-gate 				mdb.m_tgtflags |= MDB_TGT_F_RDWR;
504*7c478bd9Sstevel@tonic-gate 				break;
505*7c478bd9Sstevel@tonic-gate 			case 'y':
506*7c478bd9Sstevel@tonic-gate 				mdb.m_flags |= MDB_FL_USECUP;
507*7c478bd9Sstevel@tonic-gate 				break;
508*7c478bd9Sstevel@tonic-gate 			case 'A':
509*7c478bd9Sstevel@tonic-gate 				(void) mdb_set_options("nomods", TRUE);
510*7c478bd9Sstevel@tonic-gate 				break;
511*7c478bd9Sstevel@tonic-gate 			case 'C':
512*7c478bd9Sstevel@tonic-gate 				(void) mdb_set_options("noctf", TRUE);
513*7c478bd9Sstevel@tonic-gate 				break;
514*7c478bd9Sstevel@tonic-gate 			case 'D':
515*7c478bd9Sstevel@tonic-gate 				mdb_dmode(mdb_dstr2mode(optarg));
516*7c478bd9Sstevel@tonic-gate 				break;
517*7c478bd9Sstevel@tonic-gate 			case 'F':
518*7c478bd9Sstevel@tonic-gate 				mdb.m_tgtflags |= MDB_TGT_F_FORCE;
519*7c478bd9Sstevel@tonic-gate 				break;
520*7c478bd9Sstevel@tonic-gate 			case 'I':
521*7c478bd9Sstevel@tonic-gate 				Iflag = optarg;
522*7c478bd9Sstevel@tonic-gate 				break;
523*7c478bd9Sstevel@tonic-gate 			case 'L':
524*7c478bd9Sstevel@tonic-gate 				Lflag = optarg;
525*7c478bd9Sstevel@tonic-gate 				break;
526*7c478bd9Sstevel@tonic-gate 			case 'K':
527*7c478bd9Sstevel@tonic-gate 				Kflag++;
528*7c478bd9Sstevel@tonic-gate 				break;
529*7c478bd9Sstevel@tonic-gate 			case 'M':
530*7c478bd9Sstevel@tonic-gate 				mdb.m_tgtflags |= MDB_TGT_F_PRELOAD;
531*7c478bd9Sstevel@tonic-gate 				mdb.m_tgtflags &= ~MDB_TGT_F_NOLOAD;
532*7c478bd9Sstevel@tonic-gate 				break;
533*7c478bd9Sstevel@tonic-gate 			case 'O':
534*7c478bd9Sstevel@tonic-gate 				Oflag++;
535*7c478bd9Sstevel@tonic-gate 				break;
536*7c478bd9Sstevel@tonic-gate 			case 'P':
537*7c478bd9Sstevel@tonic-gate 				if (!mdb_set_prompt(optarg))
538*7c478bd9Sstevel@tonic-gate 					terminate(2);
539*7c478bd9Sstevel@tonic-gate 				break;
540*7c478bd9Sstevel@tonic-gate 			case 'R':
541*7c478bd9Sstevel@tonic-gate 				(void) strncpy(mdb.m_root, optarg, MAXPATHLEN);
542*7c478bd9Sstevel@tonic-gate 				mdb.m_root[MAXPATHLEN - 1] = '\0';
543*7c478bd9Sstevel@tonic-gate 				Rflag++;
544*7c478bd9Sstevel@tonic-gate 				break;
545*7c478bd9Sstevel@tonic-gate 			case 'S':
546*7c478bd9Sstevel@tonic-gate 				Sflag++;
547*7c478bd9Sstevel@tonic-gate 				break;
548*7c478bd9Sstevel@tonic-gate 			case 'U':
549*7c478bd9Sstevel@tonic-gate 				Uflag++;
550*7c478bd9Sstevel@tonic-gate 				break;
551*7c478bd9Sstevel@tonic-gate 			case 'V':
552*7c478bd9Sstevel@tonic-gate 				Vflag = optarg;
553*7c478bd9Sstevel@tonic-gate 				break;
554*7c478bd9Sstevel@tonic-gate 			case 'W':
555*7c478bd9Sstevel@tonic-gate 				mdb.m_tgtflags |= MDB_TGT_F_ALLOWIO;
556*7c478bd9Sstevel@tonic-gate 				break;
557*7c478bd9Sstevel@tonic-gate 			case '?':
558*7c478bd9Sstevel@tonic-gate 				if (optopt == '?')
559*7c478bd9Sstevel@tonic-gate 					usage(0);
560*7c478bd9Sstevel@tonic-gate 				/* FALLTHROUGH */
561*7c478bd9Sstevel@tonic-gate 			default:
562*7c478bd9Sstevel@tonic-gate 				usage(2);
563*7c478bd9Sstevel@tonic-gate 			}
564*7c478bd9Sstevel@tonic-gate 		}
565*7c478bd9Sstevel@tonic-gate 
566*7c478bd9Sstevel@tonic-gate 		if (optind < argc) {
567*7c478bd9Sstevel@tonic-gate 			const char *arg = argv[optind++];
568*7c478bd9Sstevel@tonic-gate 
569*7c478bd9Sstevel@tonic-gate 			if (arg[0] == '+' && strlen(arg) == 2) {
570*7c478bd9Sstevel@tonic-gate 				if (arg[1] != 'o') {
571*7c478bd9Sstevel@tonic-gate 					warn("illegal option -- %s\n", arg);
572*7c478bd9Sstevel@tonic-gate 					terminate(2);
573*7c478bd9Sstevel@tonic-gate 				}
574*7c478bd9Sstevel@tonic-gate 				if (optind >= argc) {
575*7c478bd9Sstevel@tonic-gate 					warn("option requires an argument -- "
576*7c478bd9Sstevel@tonic-gate 					    "%s\n", arg);
577*7c478bd9Sstevel@tonic-gate 					terminate(2);
578*7c478bd9Sstevel@tonic-gate 				}
579*7c478bd9Sstevel@tonic-gate 				if (!mdb_set_options(argv[optind++], FALSE))
580*7c478bd9Sstevel@tonic-gate 					terminate(2);
581*7c478bd9Sstevel@tonic-gate 			} else
582*7c478bd9Sstevel@tonic-gate 				tgt_argv[tgt_argc++] = arg;
583*7c478bd9Sstevel@tonic-gate 		}
584*7c478bd9Sstevel@tonic-gate 	}
585*7c478bd9Sstevel@tonic-gate 
586*7c478bd9Sstevel@tonic-gate 	if (mdb.m_debug & MDB_DBG_HELP)
587*7c478bd9Sstevel@tonic-gate 		terminate(0); /* Quit here if we've printed out the tokens */
588*7c478bd9Sstevel@tonic-gate 
589*7c478bd9Sstevel@tonic-gate 	if (Iflag != NULL && strchr(Iflag, ';') != NULL) {
590*7c478bd9Sstevel@tonic-gate 		warn("macro path cannot contain semicolons\n");
591*7c478bd9Sstevel@tonic-gate 		terminate(2);
592*7c478bd9Sstevel@tonic-gate 	}
593*7c478bd9Sstevel@tonic-gate 
594*7c478bd9Sstevel@tonic-gate 	if (Lflag != NULL && strchr(Lflag, ';') != NULL) {
595*7c478bd9Sstevel@tonic-gate 		warn("module path cannot contain semicolons\n");
596*7c478bd9Sstevel@tonic-gate 		terminate(2);
597*7c478bd9Sstevel@tonic-gate 	}
598*7c478bd9Sstevel@tonic-gate 
599*7c478bd9Sstevel@tonic-gate 	if (Kflag || Uflag) {
600*7c478bd9Sstevel@tonic-gate 		char *nm;
601*7c478bd9Sstevel@tonic-gate 
602*7c478bd9Sstevel@tonic-gate 		if (tgt_ctor != NULL || Iflag != NULL) {
603*7c478bd9Sstevel@tonic-gate 			warn("neither -f, -k, -p, -u, nor -I "
604*7c478bd9Sstevel@tonic-gate 			    "may be used with -K\n");
605*7c478bd9Sstevel@tonic-gate 			usage(2);
606*7c478bd9Sstevel@tonic-gate 		}
607*7c478bd9Sstevel@tonic-gate 
608*7c478bd9Sstevel@tonic-gate 		if (Lflag != NULL)
609*7c478bd9Sstevel@tonic-gate 			mdb_set_lpath(Lflag);
610*7c478bd9Sstevel@tonic-gate 
611*7c478bd9Sstevel@tonic-gate 		if ((nm = ttyname(STDIN_FILENO)) == NULL ||
612*7c478bd9Sstevel@tonic-gate 		    strcmp(nm, "/dev/console") != 0) {
613*7c478bd9Sstevel@tonic-gate 			/*
614*7c478bd9Sstevel@tonic-gate 			 * Due to the consequences of typing mdb -K instead of
615*7c478bd9Sstevel@tonic-gate 			 * mdb -k on a tty other than /dev/console, we require
616*7c478bd9Sstevel@tonic-gate 			 * -F when starting kmdb from a tty other than
617*7c478bd9Sstevel@tonic-gate 			 * /dev/console.
618*7c478bd9Sstevel@tonic-gate 			 */
619*7c478bd9Sstevel@tonic-gate 			if (!(mdb.m_tgtflags & MDB_TGT_F_FORCE)) {
620*7c478bd9Sstevel@tonic-gate 				die("-F must also be supplied to start kmdb "
621*7c478bd9Sstevel@tonic-gate 				    "from non-console tty\n");
622*7c478bd9Sstevel@tonic-gate 			}
623*7c478bd9Sstevel@tonic-gate 
624*7c478bd9Sstevel@tonic-gate 			if (mdb.m_termtype == NULL || (mdb.m_flags &
625*7c478bd9Sstevel@tonic-gate 			    MDB_FL_TERMGUESS)) {
626*7c478bd9Sstevel@tonic-gate 				if (mdb.m_termtype != NULL)
627*7c478bd9Sstevel@tonic-gate 					strfree(mdb.m_termtype);
628*7c478bd9Sstevel@tonic-gate 
629*7c478bd9Sstevel@tonic-gate 				if ((mdb.m_termtype = mdb_scf_console_term()) !=
630*7c478bd9Sstevel@tonic-gate 				    NULL)
631*7c478bd9Sstevel@tonic-gate 					mdb.m_flags |= MDB_FL_TERMGUESS;
632*7c478bd9Sstevel@tonic-gate 			}
633*7c478bd9Sstevel@tonic-gate 		} else {
634*7c478bd9Sstevel@tonic-gate 			/*
635*7c478bd9Sstevel@tonic-gate 			 * When on console, $TERM (if set) takes precedence over
636*7c478bd9Sstevel@tonic-gate 			 * the SMF setting.
637*7c478bd9Sstevel@tonic-gate 			 */
638*7c478bd9Sstevel@tonic-gate 			if (mdb.m_termtype == NULL && (mdb.m_termtype =
639*7c478bd9Sstevel@tonic-gate 			    mdb_scf_console_term()) != NULL)
640*7c478bd9Sstevel@tonic-gate 				mdb.m_flags |= MDB_FL_TERMGUESS;
641*7c478bd9Sstevel@tonic-gate 		}
642*7c478bd9Sstevel@tonic-gate 
643*7c478bd9Sstevel@tonic-gate 		control_kmdb(Kflag);
644*7c478bd9Sstevel@tonic-gate 		terminate(0);
645*7c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
646*7c478bd9Sstevel@tonic-gate 	}
647*7c478bd9Sstevel@tonic-gate 
648*7c478bd9Sstevel@tonic-gate 	/*
649*7c478bd9Sstevel@tonic-gate 	 * If standard input appears to have tty attributes, attempt to
650*7c478bd9Sstevel@tonic-gate 	 * initialize a terminal i/o backend on top of stdin and stdout.
651*7c478bd9Sstevel@tonic-gate 	 */
652*7c478bd9Sstevel@tonic-gate 	ttylike = (IOP_CTL(in_io, TCGETS, &tios) == 0);
653*7c478bd9Sstevel@tonic-gate 	if (ttylike) {
654*7c478bd9Sstevel@tonic-gate 		if ((mdb.m_term = mdb_termio_create(mdb.m_termtype,
655*7c478bd9Sstevel@tonic-gate 		    in_io, out_io)) == NULL) {
656*7c478bd9Sstevel@tonic-gate 			if (!(mdb.m_flags & MDB_FL_EXEC)) {
657*7c478bd9Sstevel@tonic-gate 				warn("term init failed: command-line editing "
658*7c478bd9Sstevel@tonic-gate 				    "and prompt will not be available\n");
659*7c478bd9Sstevel@tonic-gate 			}
660*7c478bd9Sstevel@tonic-gate 		} else {
661*7c478bd9Sstevel@tonic-gate 			in_io = mdb.m_term;
662*7c478bd9Sstevel@tonic-gate 		}
663*7c478bd9Sstevel@tonic-gate 	}
664*7c478bd9Sstevel@tonic-gate 
665*7c478bd9Sstevel@tonic-gate 	mdb.m_in = mdb_iob_create(in_io, MDB_IOB_RDONLY);
666*7c478bd9Sstevel@tonic-gate 	if (mdb.m_term != NULL) {
667*7c478bd9Sstevel@tonic-gate 		mdb_iob_setpager(mdb.m_out, mdb.m_term);
668*7c478bd9Sstevel@tonic-gate 		if (mdb.m_flags & MDB_FL_PAGER)
669*7c478bd9Sstevel@tonic-gate 			mdb_iob_setflags(mdb.m_out, MDB_IOB_PGENABLE);
670*7c478bd9Sstevel@tonic-gate 		else
671*7c478bd9Sstevel@tonic-gate 			mdb_iob_clrflags(mdb.m_out, MDB_IOB_PGENABLE);
672*7c478bd9Sstevel@tonic-gate 	} else if (ttylike)
673*7c478bd9Sstevel@tonic-gate 		mdb_iob_setflags(mdb.m_in, MDB_IOB_TTYLIKE);
674*7c478bd9Sstevel@tonic-gate 	else
675*7c478bd9Sstevel@tonic-gate 		mdb_iob_setbuf(mdb.m_in, mdb_alloc(1, UM_SLEEP), 1);
676*7c478bd9Sstevel@tonic-gate 
677*7c478bd9Sstevel@tonic-gate 	mdb_pservice_init();
678*7c478bd9Sstevel@tonic-gate 	mdb_lex_reset();
679*7c478bd9Sstevel@tonic-gate 
680*7c478bd9Sstevel@tonic-gate 	if ((mdb.m_shell = getenv("SHELL")) == NULL)
681*7c478bd9Sstevel@tonic-gate 		mdb.m_shell = "/bin/sh";
682*7c478bd9Sstevel@tonic-gate 
683*7c478bd9Sstevel@tonic-gate 	if (tgt_ctor == mdb_kvm_tgt_create) {
684*7c478bd9Sstevel@tonic-gate 		if (pidarg != NULL) {
685*7c478bd9Sstevel@tonic-gate 			warn("-p and -k options are mutually exclusive\n");
686*7c478bd9Sstevel@tonic-gate 			terminate(2);
687*7c478bd9Sstevel@tonic-gate 		}
688*7c478bd9Sstevel@tonic-gate 
689*7c478bd9Sstevel@tonic-gate 		if (tgt_argc == 0)
690*7c478bd9Sstevel@tonic-gate 			tgt_argv[tgt_argc++] = "/dev/ksyms";
691*7c478bd9Sstevel@tonic-gate 		if (tgt_argc == 1 && strisnum(tgt_argv[0]) == 0) {
692*7c478bd9Sstevel@tonic-gate 			if (mdb.m_tgtflags & MDB_TGT_F_ALLOWIO)
693*7c478bd9Sstevel@tonic-gate 				tgt_argv[tgt_argc++] = "/dev/allkmem";
694*7c478bd9Sstevel@tonic-gate 			else
695*7c478bd9Sstevel@tonic-gate 				tgt_argv[tgt_argc++] = "/dev/kmem";
696*7c478bd9Sstevel@tonic-gate 		}
697*7c478bd9Sstevel@tonic-gate 	}
698*7c478bd9Sstevel@tonic-gate 
699*7c478bd9Sstevel@tonic-gate 	if (pidarg != NULL) {
700*7c478bd9Sstevel@tonic-gate 		if (tgt_argc != 0) {
701*7c478bd9Sstevel@tonic-gate 			warn("-p may not be used with other arguments\n");
702*7c478bd9Sstevel@tonic-gate 			terminate(2);
703*7c478bd9Sstevel@tonic-gate 		}
704*7c478bd9Sstevel@tonic-gate 		if (proc_arg_psinfo(pidarg, PR_ARG_PIDS, NULL, &status) == -1) {
705*7c478bd9Sstevel@tonic-gate 			die("cannot attach to %s: %s\n",
706*7c478bd9Sstevel@tonic-gate 			    pidarg, Pgrab_error(status));
707*7c478bd9Sstevel@tonic-gate 		}
708*7c478bd9Sstevel@tonic-gate 		if (strchr(pidarg, '/') != NULL)
709*7c478bd9Sstevel@tonic-gate 			(void) mdb_iob_snprintf(object, MAXPATHLEN,
710*7c478bd9Sstevel@tonic-gate 			    "%s/object/a.out", pidarg);
711*7c478bd9Sstevel@tonic-gate 		else
712*7c478bd9Sstevel@tonic-gate 			(void) mdb_iob_snprintf(object, MAXPATHLEN,
713*7c478bd9Sstevel@tonic-gate 			    "/proc/%s/object/a.out", pidarg);
714*7c478bd9Sstevel@tonic-gate 		tgt_argv[tgt_argc++] = object;
715*7c478bd9Sstevel@tonic-gate 		tgt_argv[tgt_argc++] = pidarg;
716*7c478bd9Sstevel@tonic-gate 	}
717*7c478bd9Sstevel@tonic-gate 
718*7c478bd9Sstevel@tonic-gate 	/*
719*7c478bd9Sstevel@tonic-gate 	 * Find the first argument that is not a special "-" token.  If one is
720*7c478bd9Sstevel@tonic-gate 	 * found, we will examine this file and make some inferences below.
721*7c478bd9Sstevel@tonic-gate 	 */
722*7c478bd9Sstevel@tonic-gate 	for (c = 0; c < tgt_argc && strcmp(tgt_argv[c], "-") == 0; c++)
723*7c478bd9Sstevel@tonic-gate 		continue;
724*7c478bd9Sstevel@tonic-gate 
725*7c478bd9Sstevel@tonic-gate 	if (c < tgt_argc) {
726*7c478bd9Sstevel@tonic-gate 		Elf32_Ehdr ehdr;
727*7c478bd9Sstevel@tonic-gate 		mdb_io_t *io;
728*7c478bd9Sstevel@tonic-gate 
729*7c478bd9Sstevel@tonic-gate 		/*
730*7c478bd9Sstevel@tonic-gate 		 * If special "-" tokens preceded an argument, shift the entire
731*7c478bd9Sstevel@tonic-gate 		 * argument list to the left to remove the leading "-" args.
732*7c478bd9Sstevel@tonic-gate 		 */
733*7c478bd9Sstevel@tonic-gate 		if (c > 0) {
734*7c478bd9Sstevel@tonic-gate 			bcopy(&tgt_argv[c], tgt_argv,
735*7c478bd9Sstevel@tonic-gate 			    sizeof (const char *) * (tgt_argc - c));
736*7c478bd9Sstevel@tonic-gate 			tgt_argc -= c;
737*7c478bd9Sstevel@tonic-gate 		}
738*7c478bd9Sstevel@tonic-gate 
739*7c478bd9Sstevel@tonic-gate 		/*
740*7c478bd9Sstevel@tonic-gate 		 * If we just have an object file name, and that file doesn't
741*7c478bd9Sstevel@tonic-gate 		 * exist, and it's a string of digits, infer it to be a
742*7c478bd9Sstevel@tonic-gate 		 * sequence number referring to a pair of crash dump files.
743*7c478bd9Sstevel@tonic-gate 		 */
744*7c478bd9Sstevel@tonic-gate 		if (tgt_argc == 1 && access(tgt_argv[0], F_OK) == -1 &&
745*7c478bd9Sstevel@tonic-gate 		    strisnum(tgt_argv[0])) {
746*7c478bd9Sstevel@tonic-gate 
747*7c478bd9Sstevel@tonic-gate 			size_t len = strlen(tgt_argv[0]) + 8;
748*7c478bd9Sstevel@tonic-gate 			const char *object = tgt_argv[0];
749*7c478bd9Sstevel@tonic-gate 
750*7c478bd9Sstevel@tonic-gate 			tgt_argv[0] = mdb_alloc(len, UM_SLEEP);
751*7c478bd9Sstevel@tonic-gate 			tgt_argv[1] = mdb_alloc(len, UM_SLEEP);
752*7c478bd9Sstevel@tonic-gate 
753*7c478bd9Sstevel@tonic-gate 			(void) strcpy((char *)tgt_argv[0], "unix.");
754*7c478bd9Sstevel@tonic-gate 			(void) strcat((char *)tgt_argv[0], object);
755*7c478bd9Sstevel@tonic-gate 			(void) strcpy((char *)tgt_argv[1], "vmcore.");
756*7c478bd9Sstevel@tonic-gate 			(void) strcat((char *)tgt_argv[1], object);
757*7c478bd9Sstevel@tonic-gate 
758*7c478bd9Sstevel@tonic-gate 			tgt_argc = 2;
759*7c478bd9Sstevel@tonic-gate 		}
760*7c478bd9Sstevel@tonic-gate 
761*7c478bd9Sstevel@tonic-gate 		/*
762*7c478bd9Sstevel@tonic-gate 		 * We need to open the object file in order to determine its
763*7c478bd9Sstevel@tonic-gate 		 * ELF class and potentially re-exec ourself.
764*7c478bd9Sstevel@tonic-gate 		 */
765*7c478bd9Sstevel@tonic-gate 		if ((io = mdb_fdio_create_path(NULL, tgt_argv[0],
766*7c478bd9Sstevel@tonic-gate 		    O_RDONLY, 0)) == NULL)
767*7c478bd9Sstevel@tonic-gate 			die("failed to open %s", tgt_argv[0]);
768*7c478bd9Sstevel@tonic-gate 
769*7c478bd9Sstevel@tonic-gate 		/*
770*7c478bd9Sstevel@tonic-gate 		 * If the target is unknown or is not the rawfile target, do
771*7c478bd9Sstevel@tonic-gate 		 * a gelf_check to determine if the file is an ELF file.  If
772*7c478bd9Sstevel@tonic-gate 		 * it is not and the target is unknown, use the rawfile tgt.
773*7c478bd9Sstevel@tonic-gate 		 * Otherwise an ELF-based target is needed, so we must abort.
774*7c478bd9Sstevel@tonic-gate 		 */
775*7c478bd9Sstevel@tonic-gate 		if (tgt_ctor != mdb_rawfile_tgt_create &&
776*7c478bd9Sstevel@tonic-gate 		    mdb_gelf_check(io, &ehdr, ET_NONE) == -1) {
777*7c478bd9Sstevel@tonic-gate 			if (tgt_ctor != NULL) {
778*7c478bd9Sstevel@tonic-gate 				(void) mdb_gelf_check(io, &ehdr, ET_EXEC);
779*7c478bd9Sstevel@tonic-gate 				mdb_io_destroy(io);
780*7c478bd9Sstevel@tonic-gate 				terminate(1);
781*7c478bd9Sstevel@tonic-gate 			} else
782*7c478bd9Sstevel@tonic-gate 				tgt_ctor = mdb_rawfile_tgt_create;
783*7c478bd9Sstevel@tonic-gate 		}
784*7c478bd9Sstevel@tonic-gate 
785*7c478bd9Sstevel@tonic-gate 		mdb_io_destroy(io);
786*7c478bd9Sstevel@tonic-gate 
787*7c478bd9Sstevel@tonic-gate 		if (tgt_ctor == mdb_rawfile_tgt_create)
788*7c478bd9Sstevel@tonic-gate 			goto tcreate; /* skip re-exec and just create target */
789*7c478bd9Sstevel@tonic-gate 
790*7c478bd9Sstevel@tonic-gate 		/*
791*7c478bd9Sstevel@tonic-gate 		 * The object file turned out to be a user core file (ET_CORE),
792*7c478bd9Sstevel@tonic-gate 		 * and no other arguments were specified, swap 0 and 1.  The
793*7c478bd9Sstevel@tonic-gate 		 * proc target will infer the executable for us.
794*7c478bd9Sstevel@tonic-gate 		 */
795*7c478bd9Sstevel@tonic-gate 		if (ehdr.e_type == ET_CORE) {
796*7c478bd9Sstevel@tonic-gate 			tgt_argv[tgt_argc++] = tgt_argv[0];
797*7c478bd9Sstevel@tonic-gate 			tgt_argv[0] = NULL;
798*7c478bd9Sstevel@tonic-gate 			tgt_ctor = mdb_proc_tgt_create;
799*7c478bd9Sstevel@tonic-gate 		}
800*7c478bd9Sstevel@tonic-gate 
801*7c478bd9Sstevel@tonic-gate 		/*
802*7c478bd9Sstevel@tonic-gate 		 * If tgt_argv[1] is filled in, open it up and determine if it
803*7c478bd9Sstevel@tonic-gate 		 * is a vmcore file.  If it is, gelf_check will fail and we
804*7c478bd9Sstevel@tonic-gate 		 * set tgt_ctor to 'kvm'; otherwise we use the default.
805*7c478bd9Sstevel@tonic-gate 		 */
806*7c478bd9Sstevel@tonic-gate 		if (tgt_argc > 1 && strcmp(tgt_argv[1], "-") != 0 &&
807*7c478bd9Sstevel@tonic-gate 		    tgt_argv[0] != NULL && pidarg == NULL) {
808*7c478bd9Sstevel@tonic-gate 			Elf32_Ehdr chdr;
809*7c478bd9Sstevel@tonic-gate 
810*7c478bd9Sstevel@tonic-gate 			if (access(tgt_argv[1], F_OK) == -1)
811*7c478bd9Sstevel@tonic-gate 				die("failed to access %s", tgt_argv[1]);
812*7c478bd9Sstevel@tonic-gate 
813*7c478bd9Sstevel@tonic-gate 			if ((io = mdb_fdio_create_path(NULL, tgt_argv[1],
814*7c478bd9Sstevel@tonic-gate 			    O_RDONLY, 0)) == NULL)
815*7c478bd9Sstevel@tonic-gate 				die("failed to open %s", tgt_argv[1]);
816*7c478bd9Sstevel@tonic-gate 
817*7c478bd9Sstevel@tonic-gate 			if (mdb_gelf_check(io, &chdr, ET_NONE) == -1)
818*7c478bd9Sstevel@tonic-gate 				tgt_ctor = mdb_kvm_tgt_create;
819*7c478bd9Sstevel@tonic-gate 
820*7c478bd9Sstevel@tonic-gate 			mdb_io_destroy(io);
821*7c478bd9Sstevel@tonic-gate 		}
822*7c478bd9Sstevel@tonic-gate 
823*7c478bd9Sstevel@tonic-gate 		/*
824*7c478bd9Sstevel@tonic-gate 		 * At this point, we've read the ELF header for either an
825*7c478bd9Sstevel@tonic-gate 		 * object file or core into ehdr.  If the class does not match
826*7c478bd9Sstevel@tonic-gate 		 * ours, attempt to exec the mdb of the appropriate class.
827*7c478bd9Sstevel@tonic-gate 		 */
828*7c478bd9Sstevel@tonic-gate #ifdef _LP64
829*7c478bd9Sstevel@tonic-gate 		if (ehdr.e_ident[EI_CLASS] == ELFCLASS32) {
830*7c478bd9Sstevel@tonic-gate #else
831*7c478bd9Sstevel@tonic-gate 		if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) {
832*7c478bd9Sstevel@tonic-gate #endif
833*7c478bd9Sstevel@tonic-gate 			if ((p = strrchr(execname, '/')) == NULL)
834*7c478bd9Sstevel@tonic-gate 				die("cannot determine absolute pathname\n");
835*7c478bd9Sstevel@tonic-gate #ifdef _LP64
836*7c478bd9Sstevel@tonic-gate #ifdef __sparc
837*7c478bd9Sstevel@tonic-gate 			(void) strcpy(p, "/../sparcv7/");
838*7c478bd9Sstevel@tonic-gate #else
839*7c478bd9Sstevel@tonic-gate 			(void) strcpy(p, "/../i86/");
840*7c478bd9Sstevel@tonic-gate #endif
841*7c478bd9Sstevel@tonic-gate #else
842*7c478bd9Sstevel@tonic-gate #ifdef __sparc
843*7c478bd9Sstevel@tonic-gate 			(void) strcpy(p, "/../sparcv9/");
844*7c478bd9Sstevel@tonic-gate #else
845*7c478bd9Sstevel@tonic-gate 			(void) strcpy(p, "/../amd64/");
846*7c478bd9Sstevel@tonic-gate #endif
847*7c478bd9Sstevel@tonic-gate #endif
848*7c478bd9Sstevel@tonic-gate 			(void) strcat(p, mdb.m_pname);
849*7c478bd9Sstevel@tonic-gate 
850*7c478bd9Sstevel@tonic-gate 			if (mdb.m_term != NULL)
851*7c478bd9Sstevel@tonic-gate 				(void) IOP_CTL(in_io, TCSETSW, &tios);
852*7c478bd9Sstevel@tonic-gate 
853*7c478bd9Sstevel@tonic-gate 			(void) putenv("_MDB_EXEC=1");
854*7c478bd9Sstevel@tonic-gate 			(void) execv(execname, argv);
855*7c478bd9Sstevel@tonic-gate 
856*7c478bd9Sstevel@tonic-gate 			/*
857*7c478bd9Sstevel@tonic-gate 			 * If execv fails, suppress ENOEXEC.  Experience shows
858*7c478bd9Sstevel@tonic-gate 			 * the most common reason is that the machine is booted
859*7c478bd9Sstevel@tonic-gate 			 * under a 32-bit kernel, in which case it is clearer
860*7c478bd9Sstevel@tonic-gate 			 * to only print the message below.
861*7c478bd9Sstevel@tonic-gate 			 */
862*7c478bd9Sstevel@tonic-gate 			if (errno != ENOEXEC)
863*7c478bd9Sstevel@tonic-gate 				warn("failed to exec %s", execname);
864*7c478bd9Sstevel@tonic-gate #ifdef _LP64
865*7c478bd9Sstevel@tonic-gate 			die("64-bit %s cannot debug 32-bit program %s\n",
866*7c478bd9Sstevel@tonic-gate 			    mdb.m_pname, tgt_argv[0] ?
867*7c478bd9Sstevel@tonic-gate 			    tgt_argv[0] : tgt_argv[1]);
868*7c478bd9Sstevel@tonic-gate #else
869*7c478bd9Sstevel@tonic-gate 			die("32-bit %s cannot debug 64-bit program %s\n",
870*7c478bd9Sstevel@tonic-gate 			    mdb.m_pname, tgt_argv[0] ?
871*7c478bd9Sstevel@tonic-gate 			    tgt_argv[0] : tgt_argv[1]);
872*7c478bd9Sstevel@tonic-gate #endif
873*7c478bd9Sstevel@tonic-gate 		}
874*7c478bd9Sstevel@tonic-gate 	}
875*7c478bd9Sstevel@tonic-gate 
876*7c478bd9Sstevel@tonic-gate tcreate:
877*7c478bd9Sstevel@tonic-gate 	if (tgt_ctor == NULL)
878*7c478bd9Sstevel@tonic-gate 		tgt_ctor = mdb_proc_tgt_create;
879*7c478bd9Sstevel@tonic-gate 
880*7c478bd9Sstevel@tonic-gate 	/*
881*7c478bd9Sstevel@tonic-gate 	 * If the debugger state is to be inherited from a previous instance,
882*7c478bd9Sstevel@tonic-gate 	 * restore it now prior to path evaluation so that %R is updated.
883*7c478bd9Sstevel@tonic-gate 	 */
884*7c478bd9Sstevel@tonic-gate 	if ((p = getenv(MDB_CONFIG_ENV_VAR)) != NULL) {
885*7c478bd9Sstevel@tonic-gate 		mdb_set_config(p);
886*7c478bd9Sstevel@tonic-gate 		(void) unsetenv(MDB_CONFIG_ENV_VAR);
887*7c478bd9Sstevel@tonic-gate 	}
888*7c478bd9Sstevel@tonic-gate 
889*7c478bd9Sstevel@tonic-gate 	/*
890*7c478bd9Sstevel@tonic-gate 	 * Path evaluation part 1: Create the initial module path to allow
891*7c478bd9Sstevel@tonic-gate 	 * the target constructor to load a support module.  Then expand
892*7c478bd9Sstevel@tonic-gate 	 * any command-line arguments that modify the paths.
893*7c478bd9Sstevel@tonic-gate 	 */
894*7c478bd9Sstevel@tonic-gate 	if (Iflag != NULL)
895*7c478bd9Sstevel@tonic-gate 		mdb_set_ipath(Iflag);
896*7c478bd9Sstevel@tonic-gate 	else
897*7c478bd9Sstevel@tonic-gate 		mdb_set_ipath(MDB_DEF_IPATH);
898*7c478bd9Sstevel@tonic-gate 
899*7c478bd9Sstevel@tonic-gate 	if (Lflag != NULL)
900*7c478bd9Sstevel@tonic-gate 		mdb_set_lpath(Lflag);
901*7c478bd9Sstevel@tonic-gate 	else
902*7c478bd9Sstevel@tonic-gate 		mdb_set_lpath(MDB_DEF_LPATH);
903*7c478bd9Sstevel@tonic-gate 
904*7c478bd9Sstevel@tonic-gate 	if (mdb_get_prompt() == NULL && !(mdb.m_flags & MDB_FL_ADB))
905*7c478bd9Sstevel@tonic-gate 		(void) mdb_set_prompt(MDB_DEF_PROMPT);
906*7c478bd9Sstevel@tonic-gate 
907*7c478bd9Sstevel@tonic-gate 	tgt = mdb_tgt_create(tgt_ctor, mdb.m_tgtflags, tgt_argc, tgt_argv);
908*7c478bd9Sstevel@tonic-gate 
909*7c478bd9Sstevel@tonic-gate 	if (tgt == NULL) {
910*7c478bd9Sstevel@tonic-gate 		if (errno == EINVAL)
911*7c478bd9Sstevel@tonic-gate 			usage(2); /* target can return EINVAL to get usage */
912*7c478bd9Sstevel@tonic-gate 		if (errno == EMDB_TGT)
913*7c478bd9Sstevel@tonic-gate 			terminate(1); /* target already printed error msg */
914*7c478bd9Sstevel@tonic-gate 		die("failed to initialize target");
915*7c478bd9Sstevel@tonic-gate 	}
916*7c478bd9Sstevel@tonic-gate 
917*7c478bd9Sstevel@tonic-gate 	mdb_tgt_activate(tgt);
918*7c478bd9Sstevel@tonic-gate 
919*7c478bd9Sstevel@tonic-gate 	mdb_create_loadable_disasms();
920*7c478bd9Sstevel@tonic-gate 
921*7c478bd9Sstevel@tonic-gate 	if (Vflag != NULL && mdb_dis_select(Vflag) == -1)
922*7c478bd9Sstevel@tonic-gate 		warn("invalid disassembler mode -- %s\n", Vflag);
923*7c478bd9Sstevel@tonic-gate 
924*7c478bd9Sstevel@tonic-gate 
925*7c478bd9Sstevel@tonic-gate 	if (Rflag && mdb.m_term != NULL)
926*7c478bd9Sstevel@tonic-gate 		warn("Using proto area %s\n", mdb.m_root);
927*7c478bd9Sstevel@tonic-gate 
928*7c478bd9Sstevel@tonic-gate 	/*
929*7c478bd9Sstevel@tonic-gate 	 * If the target was successfully constructed and -O was specified,
930*7c478bd9Sstevel@tonic-gate 	 * we now attempt to enter piggy-mode for debugging jurassic problems.
931*7c478bd9Sstevel@tonic-gate 	 */
932*7c478bd9Sstevel@tonic-gate 	if (Oflag) {
933*7c478bd9Sstevel@tonic-gate 		pcinfo_t pci;
934*7c478bd9Sstevel@tonic-gate 
935*7c478bd9Sstevel@tonic-gate 		(void) strcpy(pci.pc_clname, "RT");
936*7c478bd9Sstevel@tonic-gate 
937*7c478bd9Sstevel@tonic-gate 		if (priocntl(P_LWPID, P_MYID, PC_GETCID, (caddr_t)&pci) != -1) {
938*7c478bd9Sstevel@tonic-gate 			pcparms_t pcp;
939*7c478bd9Sstevel@tonic-gate 			rtparms_t *rtp = (rtparms_t *)pcp.pc_clparms;
940*7c478bd9Sstevel@tonic-gate 
941*7c478bd9Sstevel@tonic-gate 			rtp->rt_pri = 35;
942*7c478bd9Sstevel@tonic-gate 			rtp->rt_tqsecs = 0;
943*7c478bd9Sstevel@tonic-gate 			rtp->rt_tqnsecs = RT_TQDEF;
944*7c478bd9Sstevel@tonic-gate 
945*7c478bd9Sstevel@tonic-gate 			pcp.pc_cid = pci.pc_cid;
946*7c478bd9Sstevel@tonic-gate 
947*7c478bd9Sstevel@tonic-gate 			if (priocntl(P_LWPID, P_MYID, PC_SETPARMS,
948*7c478bd9Sstevel@tonic-gate 			    (caddr_t)&pcp) == -1) {
949*7c478bd9Sstevel@tonic-gate 				warn("failed to set RT parameters");
950*7c478bd9Sstevel@tonic-gate 				Oflag = 0;
951*7c478bd9Sstevel@tonic-gate 			}
952*7c478bd9Sstevel@tonic-gate 		} else {
953*7c478bd9Sstevel@tonic-gate 			warn("failed to get RT class id");
954*7c478bd9Sstevel@tonic-gate 			Oflag = 0;
955*7c478bd9Sstevel@tonic-gate 		}
956*7c478bd9Sstevel@tonic-gate 
957*7c478bd9Sstevel@tonic-gate 		if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) {
958*7c478bd9Sstevel@tonic-gate 			warn("failed to lock address space");
959*7c478bd9Sstevel@tonic-gate 			Oflag = 0;
960*7c478bd9Sstevel@tonic-gate 		}
961*7c478bd9Sstevel@tonic-gate 
962*7c478bd9Sstevel@tonic-gate 		if (Oflag)
963*7c478bd9Sstevel@tonic-gate 			mdb_printf("%s: oink, oink!\n", mdb.m_pname);
964*7c478bd9Sstevel@tonic-gate 	}
965*7c478bd9Sstevel@tonic-gate 
966*7c478bd9Sstevel@tonic-gate 	/*
967*7c478bd9Sstevel@tonic-gate 	 * Path evaluation part 2: Re-evaluate the path now that the target
968*7c478bd9Sstevel@tonic-gate 	 * is ready (and thus we have access to the real platform string).
969*7c478bd9Sstevel@tonic-gate 	 * Do this before reading ~/.mdbrc to allow path modifications prior
970*7c478bd9Sstevel@tonic-gate 	 * to performing module auto-loading.
971*7c478bd9Sstevel@tonic-gate 	 */
972*7c478bd9Sstevel@tonic-gate 	mdb_set_ipath(mdb.m_ipathstr);
973*7c478bd9Sstevel@tonic-gate 	mdb_set_lpath(mdb.m_lpathstr);
974*7c478bd9Sstevel@tonic-gate 
975*7c478bd9Sstevel@tonic-gate 	if (!Sflag && (p = getenv("HOME")) != NULL) {
976*7c478bd9Sstevel@tonic-gate 		char rcpath[MAXPATHLEN];
977*7c478bd9Sstevel@tonic-gate 		mdb_io_t *rc_io;
978*7c478bd9Sstevel@tonic-gate 		int fd;
979*7c478bd9Sstevel@tonic-gate 
980*7c478bd9Sstevel@tonic-gate 		(void) mdb_iob_snprintf(rcpath, MAXPATHLEN, "%s/.mdbrc", p);
981*7c478bd9Sstevel@tonic-gate 		fd = open64(rcpath, O_RDONLY);
982*7c478bd9Sstevel@tonic-gate 
983*7c478bd9Sstevel@tonic-gate 		if (fd >= 0 && (rc_io = mdb_fdio_create_named(fd, rcpath))) {
984*7c478bd9Sstevel@tonic-gate 			mdb_iob_t *iob = mdb_iob_create(rc_io, MDB_IOB_RDONLY);
985*7c478bd9Sstevel@tonic-gate 			mdb_iob_t *old = mdb.m_in;
986*7c478bd9Sstevel@tonic-gate 
987*7c478bd9Sstevel@tonic-gate 			mdb.m_in = iob;
988*7c478bd9Sstevel@tonic-gate 			(void) mdb_run();
989*7c478bd9Sstevel@tonic-gate 			mdb.m_in = old;
990*7c478bd9Sstevel@tonic-gate 		}
991*7c478bd9Sstevel@tonic-gate 	}
992*7c478bd9Sstevel@tonic-gate 
993*7c478bd9Sstevel@tonic-gate 	if (!(mdb.m_flags & MDB_FL_NOMODS))
994*7c478bd9Sstevel@tonic-gate 		mdb_module_load_all(0);
995*7c478bd9Sstevel@tonic-gate 
996*7c478bd9Sstevel@tonic-gate 	(void) mdb_signal_sethandler(SIGINT, int_handler, NULL);
997*7c478bd9Sstevel@tonic-gate 	while ((status = mdb_run()) == MDB_ERR_ABORT ||
998*7c478bd9Sstevel@tonic-gate 	    status == MDB_ERR_OUTPUT) {
999*7c478bd9Sstevel@tonic-gate 		/*
1000*7c478bd9Sstevel@tonic-gate 		 * If a write failed on stdout, give up.  A more informative
1001*7c478bd9Sstevel@tonic-gate 		 * error message will already have been printed by mdb_run().
1002*7c478bd9Sstevel@tonic-gate 		 */
1003*7c478bd9Sstevel@tonic-gate 		if (status == MDB_ERR_OUTPUT &&
1004*7c478bd9Sstevel@tonic-gate 		    mdb_iob_getflags(mdb.m_out) & MDB_IOB_ERR) {
1005*7c478bd9Sstevel@tonic-gate 			mdb_warn("write to stdout failed, exiting\n");
1006*7c478bd9Sstevel@tonic-gate 			break;
1007*7c478bd9Sstevel@tonic-gate 		}
1008*7c478bd9Sstevel@tonic-gate 		continue;
1009*7c478bd9Sstevel@tonic-gate 	}
1010*7c478bd9Sstevel@tonic-gate 
1011*7c478bd9Sstevel@tonic-gate 	terminate((status == MDB_ERR_QUIT || status == 0) ? 0 : 1);
1012*7c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
1013*7c478bd9Sstevel@tonic-gate 	return (0);
1014*7c478bd9Sstevel@tonic-gate }
1015