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