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