xref: /illumos-gate/usr/src/cmd/mdb/common/mdb/mdb.c (revision 80148899834a4078a2bd348504aa2d6de9752837)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * Modular Debugger (MDB)
28  *
29  * Refer to the white paper "A Modular Debugger for Solaris" for information
30  * on the design, features, and goals of MDB.  See /shared/sac/PSARC/1999/169
31  * for copies of the paper and related documentation.
32  *
33  * This file provides the basic construction and destruction of the debugger's
34  * global state, as well as the main execution loop, mdb_run().  MDB maintains
35  * a stack of execution frames (mdb_frame_t's) that keep track of its current
36  * state, including a stack of input and output buffers, walk and memory
37  * garbage collect lists, and a list of commands (mdb_cmd_t's).  As the
38  * parser consumes input, it fills in a list of commands to execute, and then
39  * invokes mdb_call(), below.  A command consists of a dcmd, telling us
40  * what function to execute, and a list of arguments and other invocation-
41  * specific data.  Each frame may have more than one command, kept on a list,
42  * when multiple commands are separated by | operators.  New frames may be
43  * stacked on old ones by nested calls to mdb_run: this occurs when, for
44  * example, in the middle of processing one input source (such as a file
45  * or the terminal), we invoke a dcmd that in turn calls mdb_eval().  mdb_eval
46  * will construct a new frame whose input source is the string passed to
47  * the eval function, and then execute this frame to completion.
48  */
49 
50 #include <sys/param.h>
51 #include <stropts.h>
52 
53 #define	_MDB_PRIVATE
54 #include <mdb/mdb.h>
55 
56 #include <mdb/mdb_context.h>
57 #include <mdb/mdb_argvec.h>
58 #include <mdb/mdb_signal.h>
59 #include <mdb/mdb_macalias.h>
60 #include <mdb/mdb_module.h>
61 #include <mdb/mdb_modapi.h>
62 #include <mdb/mdb_string.h>
63 #include <mdb/mdb_callb.h>
64 #include <mdb/mdb_debug.h>
65 #include <mdb/mdb_frame.h>
66 #include <mdb/mdb_conf.h>
67 #include <mdb/mdb_err.h>
68 #include <mdb/mdb_lex.h>
69 #include <mdb/mdb_io.h>
70 #ifdef _KMDB
71 #include <kmdb/kmdb_module.h>
72 #endif
73 
74 /*
75  * Macro for testing if a dcmd's return status (x) indicates that we should
76  * abort the current loop or pipeline.
77  */
78 #define	DCMD_ABORTED(x)	((x) == DCMD_USAGE || (x) == DCMD_ABORT)
79 
80 extern const mdb_dcmd_t mdb_dcmd_builtins[];
81 extern mdb_dis_ctor_f *const mdb_dis_builtins[];
82 
83 /*
84  * Variable discipline for toggling MDB_FL_PSYM based on the value of the
85  * undocumented '_' variable.  Once adb(1) has been removed from the system,
86  * we should just remove this functionality and always disable PSYM for macros.
87  */
88 static uintmax_t
89 psym_disc_get(const mdb_var_t *v)
90 {
91 	int i = (mdb.m_flags & MDB_FL_PSYM) ? 1 : 0;
92 	int j = (MDB_NV_VALUE(v) != 0) ? 1 : 0;
93 
94 	if ((i ^ j) == 0)
95 		MDB_NV_VALUE((mdb_var_t *)v) = j ^ 1;
96 
97 	return (MDB_NV_VALUE(v));
98 }
99 
100 static void
101 psym_disc_set(mdb_var_t *v, uintmax_t value)
102 {
103 	if (value == 0)
104 		mdb.m_flags |= MDB_FL_PSYM;
105 	else
106 		mdb.m_flags &= ~MDB_FL_PSYM;
107 
108 	MDB_NV_VALUE(v) = value;
109 }
110 
111 /*
112  * Variable discipline for making <1 (most recent offset) behave properly.
113  */
114 static uintmax_t
115 roff_disc_get(const mdb_var_t *v)
116 {
117 	return (MDB_NV_VALUE(v));
118 }
119 
120 static void
121 roff_disc_set(mdb_var_t *v, uintmax_t value)
122 {
123 	mdb_nv_set_value(mdb.m_proffset, MDB_NV_VALUE(v));
124 	MDB_NV_VALUE(v) = value;
125 }
126 
127 /*
128  * Variable discipline for exporting the representative thread.
129  */
130 static uintmax_t
131 thr_disc_get(const mdb_var_t *v)
132 {
133 	mdb_tgt_status_t s;
134 
135 	if (mdb.m_target != NULL && mdb_tgt_status(mdb.m_target, &s) == 0)
136 		return (s.st_tid);
137 
138 	return (MDB_NV_VALUE(v));
139 }
140 
141 const char **
142 mdb_path_alloc(const char *s, size_t *newlen)
143 {
144 	char *format = mdb_alloc(strlen(s) * 2 + 1, UM_NOSLEEP);
145 	const char **path;
146 	char *p, *q;
147 
148 	struct utsname uts;
149 	size_t len;
150 	int i;
151 
152 	mdb_arg_t arg_i, arg_m, arg_p, arg_r, arg_t, arg_R, arg_V;
153 	mdb_argvec_t argv;
154 
155 	static const char *empty_path[] = { NULL };
156 
157 	if (format == NULL)
158 		goto nomem;
159 
160 	while (*s == ':')
161 		s++; /* strip leading delimiters */
162 
163 	if (*s == '\0') {
164 		*newlen = 0;
165 		return (empty_path);
166 	}
167 
168 	(void) strcpy(format, s);
169 	mdb_argvec_create(&argv);
170 
171 	/*
172 	 * %i embedded in path string expands to ISA.
173 	 */
174 	arg_i.a_type = MDB_TYPE_STRING;
175 	if (mdb.m_target != NULL)
176 		arg_i.a_un.a_str = mdb_tgt_isa(mdb.m_target);
177 	else
178 		arg_i.a_un.a_str = mdb_conf_isa();
179 
180 	/*
181 	 * %p embedded in path string expands to the platform name.
182 	 */
183 	arg_p.a_type = MDB_TYPE_STRING;
184 	if (mdb.m_target != NULL)
185 		arg_p.a_un.a_str = mdb_tgt_platform(mdb.m_target);
186 	else
187 		arg_p.a_un.a_str = mdb_conf_platform();
188 
189 	/*
190 	 * %r embedded in path string expands to root directory, or
191 	 * to the empty string if root is "/" (to avoid // in paths).
192 	 */
193 	arg_r.a_type = MDB_TYPE_STRING;
194 	arg_r.a_un.a_str = strcmp(mdb.m_root, "/") ? mdb.m_root : "";
195 
196 	/*
197 	 * %t embedded in path string expands to the target name, defaulting to
198 	 * kvm; this is so we can find mdb_kb, which is used during bootstrap.
199 	 */
200 	arg_t.a_type = MDB_TYPE_STRING;
201 	arg_t.a_un.a_str = mdb.m_target ? mdb_tgt_name(mdb.m_target) : "kvm";
202 
203 	/*
204 	 * %R and %V expand to uname -r (release) and uname -v (version).
205 	 */
206 	if (mdb.m_target == NULL || mdb_tgt_uname(mdb.m_target, &uts) < 0)
207 		mdb_conf_uname(&uts);
208 
209 	arg_m.a_type = MDB_TYPE_STRING;
210 	arg_m.a_un.a_str = uts.machine;
211 
212 	arg_R.a_type = MDB_TYPE_STRING;
213 	arg_R.a_un.a_str = uts.release;
214 
215 	arg_V.a_type = MDB_TYPE_STRING;
216 	if (mdb.m_flags & MDB_FL_LATEST)
217 		arg_V.a_un.a_str = "latest";
218 	else
219 		arg_V.a_un.a_str = uts.version;
220 
221 	/*
222 	 * In order to expand the buffer, we examine the format string for
223 	 * our % tokens and construct an argvec, replacing each % token
224 	 * with %s along the way.  If we encounter an unknown token, we
225 	 * shift over the remaining format buffer and stick in %%.
226 	 */
227 	for (q = format; (q = strchr(q, '%')) != NULL; q++) {
228 		switch (q[1]) {
229 		case 'i':
230 			mdb_argvec_append(&argv, &arg_i);
231 			*++q = 's';
232 			break;
233 		case 'm':
234 			mdb_argvec_append(&argv, &arg_m);
235 			*++q = 's';
236 			break;
237 		case 'p':
238 			mdb_argvec_append(&argv, &arg_p);
239 			*++q = 's';
240 			break;
241 		case 'r':
242 			mdb_argvec_append(&argv, &arg_r);
243 			*++q = 's';
244 			break;
245 		case 't':
246 			mdb_argvec_append(&argv, &arg_t);
247 			*++q = 's';
248 			break;
249 		case 'R':
250 			mdb_argvec_append(&argv, &arg_R);
251 			*++q = 's';
252 			break;
253 		case 'V':
254 			mdb_argvec_append(&argv, &arg_V);
255 			*++q = 's';
256 			break;
257 		default:
258 			bcopy(q + 1, q + 2, strlen(q));
259 			*++q = '%';
260 		}
261 	}
262 
263 	/*
264 	 * We're now ready to use our printf engine to format the final string.
265 	 * Take one lap with a NULL buffer to determine how long the final
266 	 * string will be, allocate it, and format it.
267 	 */
268 	len = mdb_iob_asnprintf(NULL, 0, format, argv.a_data);
269 	if ((p = mdb_alloc(len + 1, UM_NOSLEEP)) != NULL)
270 		(void) mdb_iob_asnprintf(p, len + 1, format, argv.a_data);
271 	else
272 		goto nomem;
273 
274 	mdb_argvec_zero(&argv);
275 	mdb_argvec_destroy(&argv);
276 
277 	mdb_free(format, strlen(s) * 2 + 1);
278 	format = NULL;
279 
280 	/*
281 	 * Compress the string to exclude any leading delimiters.
282 	 */
283 	for (q = p; *q == ':'; q++)
284 		continue;
285 	if (q != p)
286 		bcopy(q, p, strlen(q) + 1);
287 
288 	/*
289 	 * Count up the number of delimited elements.  A sequence of
290 	 * consecutive delimiters is only counted once.
291 	 */
292 	for (i = 1, q = p; (q = strchr(q, ':')) != NULL; i++) {
293 		while (*q == ':')
294 			q++;
295 	}
296 
297 	if ((path = mdb_alloc(sizeof (char *) * (i + 1), UM_NOSLEEP)) == NULL) {
298 		mdb_free(p, len + 1);
299 		goto nomem;
300 	}
301 
302 	for (i = 0, q = strtok(p, ":"); q != NULL; q = strtok(NULL, ":"))
303 		path[i++] = q;
304 
305 	path[i] = NULL;
306 	*newlen = len + 1;
307 	return (path);
308 
309 nomem:
310 	warn("failed to allocate memory for path");
311 	if (format != NULL)
312 		mdb_free(format, strlen(s) * 2 + 1);
313 	*newlen = 0;
314 	return (empty_path);
315 }
316 
317 const char **
318 mdb_path_dup(const char *path[], size_t pathlen, size_t *npathlenp)
319 {
320 	char **npath;
321 	int i, j;
322 
323 	for (i = 0; path[i] != NULL; i++)
324 		continue; /* count the path elements */
325 
326 	npath = mdb_zalloc(sizeof (char *) * (i + 1), UM_SLEEP);
327 	if (pathlen > 0) {
328 		npath[0] = mdb_alloc(pathlen, UM_SLEEP);
329 		bcopy(path[0], npath[0], pathlen);
330 	}
331 
332 	for (j = 1; j < i; j++)
333 		npath[j] = npath[0] + (path[j] - path[0]);
334 	npath[i] = NULL;
335 
336 	*npathlenp = pathlen;
337 	return ((const char **)npath);
338 }
339 
340 void
341 mdb_path_free(const char *path[], size_t pathlen)
342 {
343 	int i;
344 
345 	for (i = 0; path[i] != NULL; i++)
346 		continue; /* count the path elements */
347 
348 	if (i > 0) {
349 		mdb_free((void *)path[0], pathlen);
350 		mdb_free(path, sizeof (char *) * (i + 1));
351 	}
352 }
353 
354 /*
355  * Convert path string "s" to canonical form, expanding any %o tokens that are
356  * found within the path.  The old path string is specified by "path", a buffer
357  * of size MAXPATHLEN which is then overwritten with the new path string.
358  */
359 static const char *
360 path_canon(char *path, const char *s)
361 {
362 	char *p = path;
363 	char *q = p + MAXPATHLEN - 1;
364 
365 	char old[MAXPATHLEN];
366 	char c;
367 
368 	(void) strcpy(old, p);
369 	*q = '\0';
370 
371 	while (p < q && (c = *s++) != '\0') {
372 		if (c == '%') {
373 			if ((c = *s++) == 'o') {
374 				(void) strncpy(p, old, (size_t)(q - p));
375 				p += strlen(p);
376 			} else {
377 				*p++ = '%';
378 				if (p < q && c != '\0')
379 					*p++ = c;
380 				else
381 					break;
382 			}
383 		} else
384 			*p++ = c;
385 	}
386 
387 	*p = '\0';
388 	return (path);
389 }
390 
391 void
392 mdb_set_ipath(const char *path)
393 {
394 	if (mdb.m_ipath != NULL)
395 		mdb_path_free(mdb.m_ipath, mdb.m_ipathlen);
396 
397 	path = path_canon(mdb.m_ipathstr, path);
398 	mdb.m_ipath = mdb_path_alloc(path, &mdb.m_ipathlen);
399 }
400 
401 void
402 mdb_set_lpath(const char *path)
403 {
404 	if (mdb.m_lpath != NULL)
405 		mdb_path_free(mdb.m_lpath, mdb.m_lpathlen);
406 
407 	path = path_canon(mdb.m_lpathstr, path);
408 	mdb.m_lpath = mdb_path_alloc(path, &mdb.m_lpathlen);
409 
410 #ifdef _KMDB
411 	kmdb_module_path_set(mdb.m_lpath, mdb.m_lpathlen);
412 #endif
413 }
414 
415 static void
416 prompt_update(void)
417 {
418 	(void) mdb_snprintf(mdb.m_prompt, sizeof (mdb.m_prompt),
419 	    mdb.m_promptraw);
420 	mdb.m_promptlen = strlen(mdb.m_prompt);
421 }
422 
423 const char *
424 mdb_get_prompt(void)
425 {
426 	if (mdb.m_promptlen == 0)
427 		return (NULL);
428 	else
429 		return (mdb.m_prompt);
430 }
431 
432 int
433 mdb_set_prompt(const char *p)
434 {
435 	size_t len = strlen(p);
436 
437 	if (len > MDB_PROMPTLEN) {
438 		warn("prompt may not exceed %d characters\n", MDB_PROMPTLEN);
439 		return (0);
440 	}
441 
442 	(void) strcpy(mdb.m_promptraw, p);
443 	prompt_update();
444 	return (1);
445 }
446 
447 static mdb_frame_t frame0;
448 
449 void
450 mdb_create(const char *execname, const char *arg0)
451 {
452 	static const mdb_nv_disc_t psym_disc = { psym_disc_set, psym_disc_get };
453 	static const mdb_nv_disc_t roff_disc = { roff_disc_set, roff_disc_get };
454 	static const mdb_nv_disc_t thr_disc = { NULL, thr_disc_get };
455 
456 	static char rootdir[MAXPATHLEN];
457 
458 	const mdb_dcmd_t *dcp;
459 	int i;
460 
461 	bzero(&mdb, sizeof (mdb_t));
462 
463 	mdb.m_flags = MDB_FL_PSYM | MDB_FL_PAGER | MDB_FL_BPTNOSYMSTOP |
464 	    MDB_FL_READBACK;
465 	mdb.m_radix = MDB_DEF_RADIX;
466 	mdb.m_nargs = MDB_DEF_NARGS;
467 	mdb.m_histlen = MDB_DEF_HISTLEN;
468 	mdb.m_armemlim = MDB_DEF_ARRMEM;
469 	mdb.m_arstrlim = MDB_DEF_ARRSTR;
470 
471 	mdb.m_pname = strbasename(arg0);
472 	if (strcmp(mdb.m_pname, "adb") == 0) {
473 		mdb.m_flags |= MDB_FL_NOMODS | MDB_FL_ADB | MDB_FL_REPLAST;
474 		mdb.m_flags &= ~MDB_FL_PAGER;
475 	}
476 
477 	mdb.m_ipathstr = mdb_zalloc(MAXPATHLEN, UM_SLEEP);
478 	mdb.m_lpathstr = mdb_zalloc(MAXPATHLEN, UM_SLEEP);
479 
480 	(void) strncpy(rootdir, execname, sizeof (rootdir));
481 	rootdir[sizeof (rootdir) - 1] = '\0';
482 	(void) strdirname(rootdir);
483 
484 	if (strcmp(strbasename(rootdir), "sparcv9") == 0 ||
485 	    strcmp(strbasename(rootdir), "sparcv7") == 0 ||
486 	    strcmp(strbasename(rootdir), "amd64") == 0 ||
487 	    strcmp(strbasename(rootdir), "i86") == 0)
488 		(void) strdirname(rootdir);
489 
490 	if (strcmp(strbasename(rootdir), "bin") == 0) {
491 		(void) strdirname(rootdir);
492 		if (strcmp(strbasename(rootdir), "usr") == 0)
493 			(void) strdirname(rootdir);
494 	} else
495 		(void) strcpy(rootdir, "/");
496 
497 	mdb.m_root = rootdir;
498 
499 	mdb.m_rminfo.mi_dvers = MDB_API_VERSION;
500 	mdb.m_rminfo.mi_dcmds = mdb_dcmd_builtins;
501 	mdb.m_rminfo.mi_walkers = NULL;
502 
503 	(void) mdb_nv_create(&mdb.m_rmod.mod_walkers, UM_SLEEP);
504 	(void) mdb_nv_create(&mdb.m_rmod.mod_dcmds, UM_SLEEP);
505 
506 	mdb.m_rmod.mod_name = mdb.m_pname;
507 	mdb.m_rmod.mod_info = &mdb.m_rminfo;
508 
509 	(void) mdb_nv_create(&mdb.m_disasms, UM_SLEEP);
510 	(void) mdb_nv_create(&mdb.m_modules, UM_SLEEP);
511 	(void) mdb_nv_create(&mdb.m_dcmds, UM_SLEEP);
512 	(void) mdb_nv_create(&mdb.m_walkers, UM_SLEEP);
513 	(void) mdb_nv_create(&mdb.m_nv, UM_SLEEP);
514 
515 	mdb.m_dot = mdb_nv_insert(&mdb.m_nv, ".", NULL, 0, MDB_NV_PERSIST);
516 	mdb.m_rvalue = mdb_nv_insert(&mdb.m_nv, "0", NULL, 0, MDB_NV_PERSIST);
517 
518 	mdb.m_roffset =
519 	    mdb_nv_insert(&mdb.m_nv, "1", &roff_disc, 0, MDB_NV_PERSIST);
520 
521 	mdb.m_proffset = mdb_nv_insert(&mdb.m_nv, "2", NULL, 0, MDB_NV_PERSIST);
522 	mdb.m_rcount = mdb_nv_insert(&mdb.m_nv, "9", NULL, 0, MDB_NV_PERSIST);
523 
524 	(void) mdb_nv_insert(&mdb.m_nv, "b", NULL, 0, MDB_NV_PERSIST);
525 	(void) mdb_nv_insert(&mdb.m_nv, "d", NULL, 0, MDB_NV_PERSIST);
526 	(void) mdb_nv_insert(&mdb.m_nv, "e", NULL, 0, MDB_NV_PERSIST);
527 	(void) mdb_nv_insert(&mdb.m_nv, "m", NULL, 0, MDB_NV_PERSIST);
528 	(void) mdb_nv_insert(&mdb.m_nv, "t", NULL, 0, MDB_NV_PERSIST);
529 	(void) mdb_nv_insert(&mdb.m_nv, "_", &psym_disc, 0, MDB_NV_PERSIST);
530 	(void) mdb_nv_insert(&mdb.m_nv, "hits", NULL, 0, MDB_NV_PERSIST);
531 
532 	(void) mdb_nv_insert(&mdb.m_nv, "thread", &thr_disc, 0,
533 	    MDB_NV_PERSIST | MDB_NV_RDONLY);
534 
535 	mdb.m_prsym = mdb_gelf_symtab_create_mutable();
536 
537 	(void) mdb_nv_insert(&mdb.m_modules, mdb.m_pname, NULL,
538 	    (uintptr_t)&mdb.m_rmod, MDB_NV_RDONLY);
539 
540 	for (dcp = &mdb_dcmd_builtins[0]; dcp->dc_name != NULL; dcp++)
541 		(void) mdb_module_add_dcmd(&mdb.m_rmod, dcp, 0);
542 
543 	for (i = 0; mdb_dis_builtins[i] != NULL; i++)
544 		(void) mdb_dis_create(mdb_dis_builtins[i]);
545 
546 	mdb_macalias_create();
547 
548 	mdb_create_builtin_tgts();
549 
550 	(void) mdb_callb_add(NULL, MDB_CALLB_PROMPT, (mdb_callb_f)prompt_update,
551 	    NULL);
552 
553 #ifdef _KMDB
554 	(void) mdb_nv_create(&mdb.m_dmodctl, UM_SLEEP);
555 #endif
556 	mdb_lex_state_create(&frame0);
557 
558 	mdb_list_append(&mdb.m_flist, &frame0);
559 	mdb.m_frame = &frame0;
560 }
561 
562 void
563 mdb_destroy(void)
564 {
565 	const mdb_dcmd_t *dcp;
566 	mdb_var_t *v;
567 	int unload_mode = MDB_MOD_SILENT;
568 
569 #ifdef _KMDB
570 	unload_mode |= MDB_MOD_DEFER;
571 #endif
572 
573 	mdb_intr_disable();
574 
575 	mdb_macalias_destroy();
576 
577 	/*
578 	 * Some targets use modules during ->t_destroy, so do it first.
579 	 */
580 	if (mdb.m_target != NULL)
581 		(void) mdb_tgt_destroy(mdb.m_target);
582 
583 	/*
584 	 * Unload modules _before_ destroying the disassemblers since a
585 	 * module that installs a disassembler should try to clean up after
586 	 * itself.
587 	 */
588 	mdb_module_unload_all(unload_mode);
589 
590 	mdb_nv_rewind(&mdb.m_disasms);
591 	while ((v = mdb_nv_advance(&mdb.m_disasms)) != NULL)
592 		mdb_dis_destroy(mdb_nv_get_cookie(v));
593 
594 	mdb_callb_remove_all();
595 
596 	if (mdb.m_defdisasm != NULL)
597 		strfree(mdb.m_defdisasm);
598 
599 	if (mdb.m_prsym != NULL)
600 		mdb_gelf_symtab_destroy(mdb.m_prsym);
601 
602 	for (dcp = &mdb_dcmd_builtins[0]; dcp->dc_name != NULL; dcp++)
603 		(void) mdb_module_remove_dcmd(&mdb.m_rmod, dcp->dc_name);
604 
605 	mdb_nv_destroy(&mdb.m_nv);
606 	mdb_nv_destroy(&mdb.m_walkers);
607 	mdb_nv_destroy(&mdb.m_dcmds);
608 	mdb_nv_destroy(&mdb.m_modules);
609 	mdb_nv_destroy(&mdb.m_disasms);
610 
611 	mdb_free(mdb.m_ipathstr, MAXPATHLEN);
612 	mdb_free(mdb.m_lpathstr, MAXPATHLEN);
613 
614 	if (mdb.m_ipath != NULL)
615 		mdb_path_free(mdb.m_ipath, mdb.m_ipathlen);
616 
617 	if (mdb.m_lpath != NULL)
618 		mdb_path_free(mdb.m_lpath, mdb.m_lpathlen);
619 
620 	if (mdb.m_in != NULL)
621 		mdb_iob_destroy(mdb.m_in);
622 
623 	mdb_iob_destroy(mdb.m_out);
624 	mdb.m_out = NULL;
625 	mdb_iob_destroy(mdb.m_err);
626 	mdb.m_err = NULL;
627 
628 	if (mdb.m_log != NULL)
629 		mdb_io_rele(mdb.m_log);
630 
631 	mdb_lex_state_destroy(&frame0);
632 }
633 
634 /*
635  * The real main loop of the debugger: create a new execution frame on the
636  * debugger stack, and while we have input available, call into the parser.
637  */
638 int
639 mdb_run(void)
640 {
641 	volatile int err;
642 	mdb_frame_t f;
643 
644 	mdb_intr_disable();
645 	mdb_frame_push(&f);
646 
647 	/*
648 	 * This is a fresh mdb context, so ignore any pipe command we may have
649 	 * inherited from the previous frame.
650 	 */
651 	f.f_pcmd = NULL;
652 
653 	if ((err = setjmp(f.f_pcb)) != 0) {
654 		int pop = (mdb.m_in != NULL &&
655 		    (mdb_iob_isapipe(mdb.m_in) || mdb_iob_isastr(mdb.m_in)));
656 		int fromcmd = (f.f_cp != NULL);
657 
658 		mdb_dprintf(MDB_DBG_DSTK, "frame <%u> caught event %s\n",
659 		    f.f_id, mdb_err2str(err));
660 
661 		/*
662 		 * If a syntax error or other failure has occurred, pop all
663 		 * input buffers pushed by commands executed in this frame.
664 		 */
665 		while (mdb_iob_stack_size(&f.f_istk) != 0) {
666 			if (mdb.m_in != NULL)
667 				mdb_iob_destroy(mdb.m_in);
668 			mdb.m_in = mdb_iob_stack_pop(&f.f_istk);
669 			yylineno = mdb_iob_lineno(mdb.m_in);
670 		}
671 
672 		/*
673 		 * Reset standard output and the current frame to a known,
674 		 * clean state, so we can continue execution.
675 		 */
676 		mdb_iob_margin(mdb.m_out, MDB_IOB_DEFMARGIN);
677 		mdb_iob_clrflags(mdb.m_out, MDB_IOB_INDENT);
678 		mdb_iob_discard(mdb.m_out);
679 		mdb_frame_reset(&f);
680 
681 		/*
682 		 * If there was an error writing to output, display a warning
683 		 * message if this is the topmost frame.
684 		 */
685 		if (err == MDB_ERR_OUTPUT && mdb.m_depth == 1 && errno != EPIPE)
686 			mdb_warn("write failed");
687 
688 		/*
689 		 * If an interrupt or quit signal is reported, we may have been
690 		 * in the middle of typing or processing the command line:
691 		 * print a newline and discard everything in the parser's iob.
692 		 * Note that we do this after m_out has been reset, otherwise
693 		 * we could trigger a pipe context switch or cause a write
694 		 * to a broken pipe (in the case of a shell command) when
695 		 * writing the newline.
696 		 */
697 		if (err == MDB_ERR_SIGINT || err == MDB_ERR_QUIT) {
698 			mdb_iob_nl(mdb.m_out);
699 			yydiscard();
700 		}
701 
702 		/*
703 		 * If we quit or abort using the output pager, reset the
704 		 * line count on standard output back to zero.
705 		 */
706 		if (err == MDB_ERR_PAGER || MDB_ERR_IS_FATAL(err))
707 			mdb_iob_clearlines(mdb.m_out);
708 
709 		/*
710 		 * If the user requested the debugger quit or abort back to
711 		 * the top, or if standard input is a pipe or mdb_eval("..."),
712 		 * then propagate the error up the debugger stack.
713 		 */
714 		if (MDB_ERR_IS_FATAL(err) || pop != 0 ||
715 		    (err == MDB_ERR_PAGER && mdb.m_fmark != &f) ||
716 		    (err == MDB_ERR_NOMEM && !fromcmd)) {
717 			mdb_frame_pop(&f, err);
718 			return (err);
719 		}
720 
721 		/*
722 		 * If we've returned here from a context where signals were
723 		 * blocked (e.g. a signal handler), we can now unblock them.
724 		 */
725 		if (err == MDB_ERR_SIGINT)
726 			(void) mdb_signal_unblock(SIGINT);
727 	} else
728 		mdb_intr_enable();
729 
730 	for (;;) {
731 		while (mdb.m_in != NULL && (mdb_iob_getflags(mdb.m_in) &
732 		    (MDB_IOB_ERR | MDB_IOB_EOF)) == 0) {
733 			if (mdb.m_depth == 1 &&
734 			    mdb_iob_stack_size(&f.f_istk) == 0) {
735 				mdb_iob_clearlines(mdb.m_out);
736 				mdb_tgt_periodic(mdb.m_target);
737 			}
738 
739 			(void) yyparse();
740 		}
741 
742 		if (mdb.m_in != NULL) {
743 			if (mdb_iob_err(mdb.m_in)) {
744 				warn("error reading input stream %s\n",
745 				    mdb_iob_name(mdb.m_in));
746 			}
747 			mdb_iob_destroy(mdb.m_in);
748 			mdb.m_in = NULL;
749 		}
750 
751 		if (mdb_iob_stack_size(&f.f_istk) == 0)
752 			break; /* return when we're out of input */
753 
754 		mdb.m_in = mdb_iob_stack_pop(&f.f_istk);
755 		yylineno = mdb_iob_lineno(mdb.m_in);
756 	}
757 
758 	mdb_frame_pop(&f, 0);
759 
760 	/*
761 	 * The value of '.' is a per-frame attribute, to preserve it properly
762 	 * when switching frames.  But in the case of calling mdb_run()
763 	 * explicitly (such as through mdb_eval), we want to propagate the value
764 	 * of '.' to the parent.
765 	 */
766 	mdb_nv_set_value(mdb.m_dot, f.f_dot);
767 
768 	return (0);
769 }
770 
771 /*
772  * The read-side of the pipe executes this service routine.  We simply call
773  * mdb_run to create a new frame on the execution stack and run the MDB parser,
774  * and then propagate any error code back to the previous frame.
775  */
776 static int
777 runsvc(void)
778 {
779 	int err = mdb_run();
780 
781 	if (err != 0) {
782 		mdb_dprintf(MDB_DBG_DSTK, "forwarding error %s from pipeline\n",
783 		    mdb_err2str(err));
784 		longjmp(mdb.m_frame->f_pcb, err);
785 	}
786 
787 	return (err);
788 }
789 
790 /*
791  * Read-side pipe service routine: if we longjmp here, just return to the read
792  * routine because now we have more data to consume.  Otherwise:
793  * (1) if ctx_data is non-NULL, longjmp to the write-side to produce more data;
794  * (2) if wriob is NULL, there is no writer but this is the first read, so we
795  *     can just execute mdb_run() to completion on the current stack;
796  * (3) if (1) and (2) are false, then there is a writer and this is the first
797  *     read, so create a co-routine context to execute mdb_run().
798  */
799 /*ARGSUSED*/
800 static void
801 rdsvc(mdb_iob_t *rdiob, mdb_iob_t *wriob, mdb_iob_ctx_t *ctx)
802 {
803 	if (setjmp(ctx->ctx_rpcb) == 0) {
804 		/*
805 		 * Save the current standard input into the pipe context, and
806 		 * reset m_in to point to the pipe.  We will restore it on
807 		 * the way back in wrsvc() below.
808 		 */
809 		ctx->ctx_iob = mdb.m_in;
810 		mdb.m_in = rdiob;
811 
812 		ctx->ctx_rptr = mdb.m_frame;
813 		if (ctx->ctx_wptr != NULL)
814 			mdb_frame_switch(ctx->ctx_wptr);
815 
816 		if (ctx->ctx_data != NULL)
817 			longjmp(ctx->ctx_wpcb, 1);
818 		else if (wriob == NULL)
819 			(void) runsvc();
820 		else if ((ctx->ctx_data = mdb_context_create(runsvc)) != NULL)
821 			mdb_context_switch(ctx->ctx_data);
822 		else
823 			mdb_warn("failed to create pipe context");
824 	}
825 }
826 
827 /*
828  * Write-side pipe service routine: if we longjmp here, just return to the
829  * write routine because now we have free space in the pipe buffer for writing;
830  * otherwise longjmp to the read-side to consume data and create space for us.
831  */
832 /*ARGSUSED*/
833 static void
834 wrsvc(mdb_iob_t *rdiob, mdb_iob_t *wriob, mdb_iob_ctx_t *ctx)
835 {
836 	if (setjmp(ctx->ctx_wpcb) == 0) {
837 		ctx->ctx_wptr = mdb.m_frame;
838 		if (ctx->ctx_rptr != NULL)
839 			mdb_frame_switch(ctx->ctx_rptr);
840 
841 		mdb.m_in = ctx->ctx_iob;
842 		longjmp(ctx->ctx_rpcb, 1);
843 	}
844 }
845 
846 /*
847  * Call the current frame's mdb command.  This entry point is used by the
848  * MDB parser to actually execute a command once it has successfully parsed
849  * a line of input.  The command is waiting for us in the current frame.
850  * We loop through each command on the list, executing its dcmd with the
851  * appropriate argument.  If the command has a successor, we know it had
852  * a | operator after it, and so we need to create a pipe and replace
853  * stdout with the pipe's output buffer.
854  */
855 int
856 mdb_call(uintmax_t addr, uintmax_t count, uint_t flags)
857 {
858 	mdb_frame_t *fp = mdb.m_frame;
859 	mdb_cmd_t *cp, *ncp;
860 	mdb_iob_t *iobs[2];
861 	int status, err = 0;
862 	jmp_buf pcb;
863 
864 	if (mdb_iob_isapipe(mdb.m_in))
865 		yyerror("syntax error");
866 
867 	mdb_intr_disable();
868 	fp->f_cp = mdb_list_next(&fp->f_cmds);
869 
870 	if (flags & DCMD_LOOP)
871 		flags |= DCMD_LOOPFIRST; /* set LOOPFIRST if this is a loop */
872 
873 	for (cp = mdb_list_next(&fp->f_cmds); cp; cp = mdb_list_next(cp)) {
874 		if (mdb_list_next(cp) != NULL) {
875 			mdb_iob_pipe(iobs, rdsvc, wrsvc);
876 
877 			mdb_iob_stack_push(&fp->f_istk, mdb.m_in, yylineno);
878 			mdb.m_in = iobs[MDB_IOB_RDIOB];
879 
880 			mdb_iob_stack_push(&fp->f_ostk, mdb.m_out, 0);
881 			mdb.m_out = iobs[MDB_IOB_WRIOB];
882 
883 			ncp = mdb_list_next(cp);
884 			mdb_vcb_inherit(cp, ncp);
885 
886 			bcopy(fp->f_pcb, pcb, sizeof (jmp_buf));
887 			ASSERT(fp->f_pcmd == NULL);
888 			fp->f_pcmd = ncp;
889 
890 			mdb_frame_set_pipe(fp);
891 
892 			if ((err = setjmp(fp->f_pcb)) == 0) {
893 				status = mdb_call_idcmd(cp->c_dcmd, addr, count,
894 				    flags | DCMD_PIPE_OUT, &cp->c_argv,
895 				    &cp->c_addrv, cp->c_vcbs);
896 
897 				ASSERT(mdb.m_in == iobs[MDB_IOB_RDIOB]);
898 				ASSERT(mdb.m_out == iobs[MDB_IOB_WRIOB]);
899 			} else {
900 				mdb_dprintf(MDB_DBG_DSTK, "frame <%u> caught "
901 				    "error %s from pipeline\n", fp->f_id,
902 				    mdb_err2str(err));
903 			}
904 
905 			if (err != 0 || DCMD_ABORTED(status)) {
906 				mdb_iob_setflags(mdb.m_in, MDB_IOB_ERR);
907 				mdb_iob_setflags(mdb.m_out, MDB_IOB_ERR);
908 			} else {
909 				mdb_iob_flush(mdb.m_out);
910 				(void) mdb_iob_ctl(mdb.m_out, I_FLUSH,
911 				    (void *)FLUSHW);
912 			}
913 
914 			mdb_frame_clear_pipe(fp);
915 
916 			mdb_iob_destroy(mdb.m_out);
917 			mdb.m_out = mdb_iob_stack_pop(&fp->f_ostk);
918 
919 			if (mdb.m_in != NULL)
920 				mdb_iob_destroy(mdb.m_in);
921 
922 			mdb.m_in = mdb_iob_stack_pop(&fp->f_istk);
923 			yylineno = mdb_iob_lineno(mdb.m_in);
924 
925 			fp->f_pcmd = NULL;
926 			bcopy(pcb, fp->f_pcb, sizeof (jmp_buf));
927 
928 			if (MDB_ERR_IS_FATAL(err))
929 				longjmp(fp->f_pcb, err);
930 
931 			if (err != 0 || DCMD_ABORTED(status) ||
932 			    mdb_addrvec_length(&ncp->c_addrv) == 0)
933 				break;
934 
935 			addr = mdb_nv_get_value(mdb.m_dot);
936 			count = 1;
937 			flags = 0;
938 
939 		} else {
940 			mdb_intr_enable();
941 			(void) mdb_call_idcmd(cp->c_dcmd, addr, count, flags,
942 			    &cp->c_argv, &cp->c_addrv, cp->c_vcbs);
943 			mdb_intr_disable();
944 		}
945 
946 		fp->f_cp = mdb_list_next(cp);
947 		mdb_cmd_reset(cp);
948 	}
949 
950 	/*
951 	 * If our last-command list is non-empty, destroy it.  Then copy the
952 	 * current frame's cmd list to the m_lastc list and reset the frame.
953 	 */
954 	while ((cp = mdb_list_next(&mdb.m_lastc)) != NULL) {
955 		mdb_list_delete(&mdb.m_lastc, cp);
956 		mdb_cmd_destroy(cp);
957 	}
958 
959 	mdb_list_move(&fp->f_cmds, &mdb.m_lastc);
960 	mdb_frame_reset(fp);
961 	mdb_intr_enable();
962 	return (err == 0);
963 }
964 
965 uintmax_t
966 mdb_dot_incr(const char *op)
967 {
968 	uintmax_t odot, ndot;
969 
970 	odot = mdb_nv_get_value(mdb.m_dot);
971 	ndot = odot + mdb.m_incr;
972 
973 	if ((odot ^ ndot) & 0x8000000000000000ull)
974 		yyerror("'%s' would cause '.' to overflow\n", op);
975 
976 	return (ndot);
977 }
978 
979 uintmax_t
980 mdb_dot_decr(const char *op)
981 {
982 	uintmax_t odot, ndot;
983 
984 	odot = mdb_nv_get_value(mdb.m_dot);
985 	ndot = odot - mdb.m_incr;
986 
987 	if (ndot > odot)
988 		yyerror("'%s' would cause '.' to underflow\n", op);
989 
990 	return (ndot);
991 }
992 
993 mdb_iwalker_t *
994 mdb_walker_lookup(const char *s)
995 {
996 	const char *p = strchr(s, '`');
997 	mdb_var_t *v;
998 
999 	if (p != NULL) {
1000 		size_t nbytes = MIN((size_t)(p - s), MDB_NV_NAMELEN - 1);
1001 		char mname[MDB_NV_NAMELEN];
1002 		mdb_module_t *mod;
1003 
1004 		(void) strncpy(mname, s, nbytes);
1005 		mname[nbytes] = '\0';
1006 
1007 		if ((v = mdb_nv_lookup(&mdb.m_modules, mname)) == NULL) {
1008 			(void) set_errno(EMDB_NOMOD);
1009 			return (NULL);
1010 		}
1011 
1012 		mod = mdb_nv_get_cookie(v);
1013 
1014 		if ((v = mdb_nv_lookup(&mod->mod_walkers, ++p)) != NULL)
1015 			return (mdb_nv_get_cookie(v));
1016 
1017 	} else if ((v = mdb_nv_lookup(&mdb.m_walkers, s)) != NULL)
1018 		return (mdb_nv_get_cookie(mdb_nv_get_cookie(v)));
1019 
1020 	(void) set_errno(EMDB_NOWALK);
1021 	return (NULL);
1022 }
1023 
1024 mdb_idcmd_t *
1025 mdb_dcmd_lookup(const char *s)
1026 {
1027 	const char *p = strchr(s, '`');
1028 	mdb_var_t *v;
1029 
1030 	if (p != NULL) {
1031 		size_t nbytes = MIN((size_t)(p - s), MDB_NV_NAMELEN - 1);
1032 		char mname[MDB_NV_NAMELEN];
1033 		mdb_module_t *mod;
1034 
1035 		(void) strncpy(mname, s, nbytes);
1036 		mname[nbytes] = '\0';
1037 
1038 		if ((v = mdb_nv_lookup(&mdb.m_modules, mname)) == NULL) {
1039 			(void) set_errno(EMDB_NOMOD);
1040 			return (NULL);
1041 		}
1042 
1043 		mod = mdb_nv_get_cookie(v);
1044 
1045 		if ((v = mdb_nv_lookup(&mod->mod_dcmds, ++p)) != NULL)
1046 			return (mdb_nv_get_cookie(v));
1047 
1048 	} else if ((v = mdb_nv_lookup(&mdb.m_dcmds, s)) != NULL)
1049 		return (mdb_nv_get_cookie(mdb_nv_get_cookie(v)));
1050 
1051 	(void) set_errno(EMDB_NODCMD);
1052 	return (NULL);
1053 }
1054 
1055 void
1056 mdb_dcmd_usage(const mdb_idcmd_t *idcp, mdb_iob_t *iob)
1057 {
1058 	const char *prefix = "", *usage = "";
1059 	char name0 = idcp->idc_name[0];
1060 
1061 	if (idcp->idc_usage != NULL) {
1062 		if (idcp->idc_usage[0] == ':') {
1063 			if (name0 != ':' && name0 != '$')
1064 				prefix = "address::";
1065 			else
1066 				prefix = "address";
1067 			usage = &idcp->idc_usage[1];
1068 
1069 		} else if (idcp->idc_usage[0] == '?') {
1070 			if (name0 != ':' && name0 != '$')
1071 				prefix = "[address]::";
1072 			else
1073 				prefix = "[address]";
1074 			usage = &idcp->idc_usage[1];
1075 
1076 		} else
1077 			usage = idcp->idc_usage;
1078 	}
1079 
1080 	mdb_iob_printf(iob, "Usage: %s%s %s\n", prefix, idcp->idc_name, usage);
1081 
1082 	if (idcp->idc_help != NULL) {
1083 		mdb_iob_printf(iob, "%s: try '::help %s' for more "
1084 		    "information\n", mdb.m_pname, idcp->idc_name);
1085 	}
1086 }
1087 
1088 static mdb_idcmd_t *
1089 dcmd_ndef(const mdb_idcmd_t *idcp)
1090 {
1091 	mdb_var_t *v = mdb_nv_get_ndef(idcp->idc_var);
1092 
1093 	if (v != NULL)
1094 		return (mdb_nv_get_cookie(mdb_nv_get_cookie(v)));
1095 
1096 	return (NULL);
1097 }
1098 
1099 static int
1100 dcmd_invoke(mdb_idcmd_t *idcp, uintptr_t addr, uint_t flags,
1101     int argc, const mdb_arg_t *argv, const mdb_vcb_t *vcbs)
1102 {
1103 	int status;
1104 
1105 	mdb_dprintf(MDB_DBG_DCMD, "dcmd %s`%s dot = %lr incr = %llr\n",
1106 	    idcp->idc_modp->mod_name, idcp->idc_name, addr, mdb.m_incr);
1107 
1108 	if ((status = idcp->idc_funcp(addr, flags, argc, argv)) == DCMD_USAGE) {
1109 		mdb_dcmd_usage(idcp, mdb.m_err);
1110 		goto done;
1111 	}
1112 
1113 	while (status == DCMD_NEXT && (idcp = dcmd_ndef(idcp)) != NULL)
1114 		status = idcp->idc_funcp(addr, flags, argc, argv);
1115 
1116 	if (status == DCMD_USAGE)
1117 		mdb_dcmd_usage(idcp, mdb.m_err);
1118 
1119 	if (status == DCMD_NEXT)
1120 		status = DCMD_OK;
1121 done:
1122 	/*
1123 	 * If standard output is a pipe and there are vcbs active, we need to
1124 	 * flush standard out and the write-side of the pipe.  The reasons for
1125 	 * this are explained in more detail in mdb_vcb.c.
1126 	 */
1127 	if ((flags & DCMD_PIPE_OUT) && (vcbs != NULL)) {
1128 		mdb_iob_flush(mdb.m_out);
1129 		(void) mdb_iob_ctl(mdb.m_out, I_FLUSH, (void *)FLUSHW);
1130 	}
1131 
1132 	return (status);
1133 }
1134 
1135 /*
1136  * Call an internal dcmd directly: this code is used by module API functions
1137  * that need to execute dcmds, and by mdb_call() above.
1138  */
1139 int
1140 mdb_call_idcmd(mdb_idcmd_t *idcp, uintmax_t addr, uintmax_t count,
1141     uint_t flags, mdb_argvec_t *avp, mdb_addrvec_t *adp, mdb_vcb_t *vcbs)
1142 {
1143 	int is_exec = (strcmp(idcp->idc_name, "$<") == 0);
1144 	mdb_arg_t *argv;
1145 	int argc;
1146 	uintmax_t i;
1147 	int status;
1148 
1149 	/*
1150 	 * Update the values of dot and the most recent address and count
1151 	 * to the values of our input parameters.
1152 	 */
1153 	mdb_nv_set_value(mdb.m_dot, addr);
1154 	mdb.m_raddr = addr;
1155 	mdb.m_dcount = count;
1156 
1157 	/*
1158 	 * Here the adb(1) man page lies: '9' is only set to count
1159 	 * when the command is $<, not when it's $<<.
1160 	 */
1161 	if (is_exec)
1162 		mdb_nv_set_value(mdb.m_rcount, count);
1163 
1164 	/*
1165 	 * We can now return if the repeat count is zero.
1166 	 */
1167 	if (count == 0)
1168 		return (DCMD_OK);
1169 
1170 	/*
1171 	 * To guard against bad dcmds, we avoid passing the actual argv that
1172 	 * we will use to free argument strings directly to the dcmd.  Instead,
1173 	 * we pass a copy that will be garbage collected automatically.
1174 	 */
1175 	argc = avp->a_nelems;
1176 	argv = mdb_alloc(sizeof (mdb_arg_t) * argc, UM_SLEEP | UM_GC);
1177 	bcopy(avp->a_data, argv, sizeof (mdb_arg_t) * argc);
1178 
1179 	if (mdb_addrvec_length(adp) != 0) {
1180 		flags |= DCMD_PIPE | DCMD_LOOP | DCMD_LOOPFIRST | DCMD_ADDRSPEC;
1181 		addr = mdb_addrvec_shift(adp);
1182 		mdb_nv_set_value(mdb.m_dot, addr);
1183 		mdb_vcb_propagate(vcbs);
1184 		count = 1;
1185 	}
1186 
1187 	status = dcmd_invoke(idcp, addr, flags, argc, argv, vcbs);
1188 	if (DCMD_ABORTED(status))
1189 		goto done;
1190 
1191 	/*
1192 	 * If the command is $< and we're not receiving input from a pipe, we
1193 	 * ignore the repeat count and just return since the macro file is now
1194 	 * pushed on to the input stack.
1195 	 */
1196 	if (is_exec && mdb_addrvec_length(adp) == 0)
1197 		goto done;
1198 
1199 	/*
1200 	 * If we're going to loop, we've already executed the dcmd once,
1201 	 * so clear the LOOPFIRST flag before proceeding.
1202 	 */
1203 	if (flags & DCMD_LOOP)
1204 		flags &= ~DCMD_LOOPFIRST;
1205 
1206 	for (i = 1; i < count; i++) {
1207 		addr = mdb_dot_incr(",");
1208 		mdb_nv_set_value(mdb.m_dot, addr);
1209 		status = dcmd_invoke(idcp, addr, flags, argc, argv, vcbs);
1210 		if (DCMD_ABORTED(status))
1211 			goto done;
1212 	}
1213 
1214 	while (mdb_addrvec_length(adp) != 0) {
1215 		addr = mdb_addrvec_shift(adp);
1216 		mdb_nv_set_value(mdb.m_dot, addr);
1217 		mdb_vcb_propagate(vcbs);
1218 		status = dcmd_invoke(idcp, addr, flags, argc, argv, vcbs);
1219 		if (DCMD_ABORTED(status))
1220 			goto done;
1221 	}
1222 done:
1223 	mdb_iob_nlflush(mdb.m_out);
1224 	return (status);
1225 }
1226 
1227 void
1228 mdb_intr_enable(void)
1229 {
1230 	ASSERT(mdb.m_intr >= 1);
1231 	if (mdb.m_intr == 1 && mdb.m_pend != 0) {
1232 		(void) mdb_signal_block(SIGINT);
1233 		mdb.m_intr = mdb.m_pend = 0;
1234 		mdb_dprintf(MDB_DBG_DSTK, "delivering pending INT\n");
1235 		longjmp(mdb.m_frame->f_pcb, MDB_ERR_SIGINT);
1236 	} else
1237 		mdb.m_intr--;
1238 }
1239 
1240 void
1241 mdb_intr_disable(void)
1242 {
1243 	mdb.m_intr++;
1244 	ASSERT(mdb.m_intr >= 1);
1245 }
1246 
1247 /*
1248  * Create an encoded string representing the internal user-modifiable
1249  * configuration of the debugger and return a pointer to it.  The string can be
1250  * used to initialize another instance of the debugger with the same
1251  * configuration as this one.
1252  */
1253 char *
1254 mdb_get_config(void)
1255 {
1256 	size_t r, n = 0;
1257 	char *s = NULL;
1258 
1259 	while ((r = mdb_snprintf(s, n,
1260 	    "%x;%x;%x;%x;%x;%x;%lx;%x;%x;%s;%s;%s;%s;%s",
1261 	    mdb.m_tgtflags, mdb.m_flags, mdb.m_debug, mdb.m_radix, mdb.m_nargs,
1262 	    mdb.m_histlen, (ulong_t)mdb.m_symdist, mdb.m_execmode,
1263 	    mdb.m_forkmode, mdb.m_root, mdb.m_termtype, mdb.m_ipathstr,
1264 	    mdb.m_lpathstr, mdb.m_prompt)) > n) {
1265 
1266 		mdb_free(s, n);
1267 		n = r + 1;
1268 		s = mdb_alloc(r + 1, UM_SLEEP);
1269 	}
1270 
1271 	return (s);
1272 }
1273 
1274 /*
1275  * Decode a configuration string created with mdb_get_config() and reset the
1276  * appropriate parts of the global mdb_t accordingly.
1277  */
1278 void
1279 mdb_set_config(const char *s)
1280 {
1281 	const char *p;
1282 	size_t len;
1283 
1284 	if ((p = strchr(s, ';')) != NULL) {
1285 		mdb.m_tgtflags = strntoul(s, (size_t)(p - s), 16);
1286 		s = p + 1;
1287 	}
1288 
1289 	if ((p = strchr(s, ';')) != NULL) {
1290 		mdb.m_flags = strntoul(s, (size_t)(p - s), 16);
1291 		mdb.m_flags &= ~(MDB_FL_LOG | MDB_FL_LATEST);
1292 		s = p + 1;
1293 	}
1294 
1295 	if ((p = strchr(s, ';')) != NULL) {
1296 		mdb.m_debug = strntoul(s, (size_t)(p - s), 16);
1297 		s = p + 1;
1298 	}
1299 
1300 	if ((p = strchr(s, ';')) != NULL) {
1301 		mdb.m_radix = (int)strntoul(s, (size_t)(p - s), 16);
1302 		if (mdb.m_radix < 2 || mdb.m_radix > 16)
1303 			mdb.m_radix = MDB_DEF_RADIX;
1304 		s = p + 1;
1305 	}
1306 
1307 	if ((p = strchr(s, ';')) != NULL) {
1308 		mdb.m_nargs = (int)strntoul(s, (size_t)(p - s), 16);
1309 		mdb.m_nargs = MAX(mdb.m_nargs, 0);
1310 		s = p + 1;
1311 	}
1312 
1313 	if ((p = strchr(s, ';')) != NULL) {
1314 		mdb.m_histlen = (int)strntoul(s, (size_t)(p - s), 16);
1315 		mdb.m_histlen = MAX(mdb.m_histlen, 1);
1316 		s = p + 1;
1317 	}
1318 
1319 	if ((p = strchr(s, ';')) != NULL) {
1320 		mdb.m_symdist = strntoul(s, (size_t)(p - s), 16);
1321 		s = p + 1;
1322 	}
1323 
1324 	if ((p = strchr(s, ';')) != NULL) {
1325 		mdb.m_execmode = (uchar_t)strntoul(s, (size_t)(p - s), 16);
1326 		if (mdb.m_execmode > MDB_EM_FOLLOW)
1327 			mdb.m_execmode = MDB_EM_ASK;
1328 		s = p + 1;
1329 	}
1330 
1331 	if ((p = strchr(s, ';')) != NULL) {
1332 		mdb.m_forkmode = (uchar_t)strntoul(s, (size_t)(p - s), 16);
1333 		if (mdb.m_forkmode > MDB_FM_CHILD)
1334 			mdb.m_forkmode = MDB_FM_ASK;
1335 		s = p + 1;
1336 	}
1337 
1338 	if ((p = strchr(s, ';')) != NULL) {
1339 		mdb.m_root = strndup(s, (size_t)(p - s));
1340 		s = p + 1;
1341 	}
1342 
1343 	if ((p = strchr(s, ';')) != NULL) {
1344 		mdb.m_termtype = strndup(s, (size_t)(p - s));
1345 		s = p + 1;
1346 	}
1347 
1348 	if ((p = strchr(s, ';')) != NULL) {
1349 		size_t len = MIN(sizeof (mdb.m_ipathstr) - 1, p - s);
1350 		(void) strncpy(mdb.m_ipathstr, s, len);
1351 		mdb.m_ipathstr[len] = '\0';
1352 		s = p + 1;
1353 	}
1354 
1355 	if ((p = strchr(s, ';')) != NULL) {
1356 		size_t len = MIN(sizeof (mdb.m_lpathstr) - 1, p - s);
1357 		(void) strncpy(mdb.m_lpathstr, s, len);
1358 		mdb.m_lpathstr[len] = '\0';
1359 		s = p + 1;
1360 	}
1361 
1362 	p = s + strlen(s);
1363 	len = MIN(MDB_PROMPTLEN, (size_t)(p - s));
1364 	(void) strncpy(mdb.m_prompt, s, len);
1365 	mdb.m_prompt[len] = '\0';
1366 	mdb.m_promptlen = len;
1367 }
1368 
1369 mdb_module_t *
1370 mdb_get_module(void)
1371 {
1372 	if (mdb.m_lmod)
1373 		return (mdb.m_lmod);
1374 
1375 	if (mdb.m_frame == NULL)
1376 		return (NULL);
1377 
1378 	if (mdb.m_frame->f_wcbs && mdb.m_frame->f_wcbs->w_walker &&
1379 	    mdb.m_frame->f_wcbs->w_walker->iwlk_modp)
1380 		return (mdb.m_frame->f_wcbs->w_walker->iwlk_modp);
1381 
1382 	if (mdb.m_frame->f_cp && mdb.m_frame->f_cp->c_dcmd)
1383 		return (mdb.m_frame->f_cp->c_dcmd->idc_modp);
1384 
1385 	return (NULL);
1386 }
1387