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