mdb.c revision 843e19887f64dde75055cf8842fc4db2171eff45
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 2007 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
82extern const mdb_dcmd_t mdb_dcmd_builtins[];
83extern 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 */
90static uintmax_t
91psym_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
102static void
103psym_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 */
116static uintmax_t
117roff_disc_get(const mdb_var_t *v)
118{
119	return (MDB_NV_VALUE(v));
120}
121
122static void
123roff_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 */
132static uintmax_t
133thr_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
143const char **
144mdb_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, defaulting to
200	 * kvm; this is so we can find mdb_kb, which is used during bootstrap.
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) : "kvm";
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
311nomem:
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
319const char **
320mdb_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
342void
343mdb_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 */
361static const char *
362path_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
393void
394mdb_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
403void
404mdb_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
417static void
418prompt_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
425const char *
426mdb_get_prompt(void)
427{
428	if (mdb.m_promptlen == 0)
429		return (NULL);
430	else
431		return (mdb.m_prompt);
432}
433
434int
435mdb_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
449static mdb_frame_t frame0;
450
451void
452mdb_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
564void
565mdb_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	 * Some targets use modules during ->t_destroy, so do it first.
581	 */
582	if (mdb.m_target != NULL)
583		(void) mdb_tgt_destroy(mdb.m_target);
584
585	/*
586	 * Unload modules _before_ destroying the disassemblers since a
587	 * module that installs a disassembler should try to clean up after
588	 * itself.
589	 */
590	mdb_module_unload_all(unload_mode);
591
592	mdb_nv_rewind(&mdb.m_disasms);
593	while ((v = mdb_nv_advance(&mdb.m_disasms)) != NULL)
594		mdb_dis_destroy(mdb_nv_get_cookie(v));
595
596	mdb_callb_remove_all();
597
598	if (mdb.m_defdisasm != NULL)
599		strfree(mdb.m_defdisasm);
600
601	if (mdb.m_prsym != NULL)
602		mdb_gelf_symtab_destroy(mdb.m_prsym);
603
604	for (dcp = &mdb_dcmd_builtins[0]; dcp->dc_name != NULL; dcp++)
605		(void) mdb_module_remove_dcmd(&mdb.m_rmod, dcp->dc_name);
606
607	mdb_nv_destroy(&mdb.m_nv);
608	mdb_nv_destroy(&mdb.m_walkers);
609	mdb_nv_destroy(&mdb.m_dcmds);
610	mdb_nv_destroy(&mdb.m_modules);
611	mdb_nv_destroy(&mdb.m_disasms);
612
613	mdb_free(mdb.m_ipathstr, MAXPATHLEN);
614	mdb_free(mdb.m_lpathstr, MAXPATHLEN);
615
616	if (mdb.m_ipath != NULL)
617		mdb_path_free(mdb.m_ipath, mdb.m_ipathlen);
618
619	if (mdb.m_lpath != NULL)
620		mdb_path_free(mdb.m_lpath, mdb.m_lpathlen);
621
622	if (mdb.m_in != NULL)
623		mdb_iob_destroy(mdb.m_in);
624
625	mdb_iob_destroy(mdb.m_out);
626	mdb.m_out = NULL;
627	mdb_iob_destroy(mdb.m_err);
628	mdb.m_err = NULL;
629
630	if (mdb.m_log != NULL)
631		mdb_io_rele(mdb.m_log);
632
633	mdb_lex_state_destroy(&frame0);
634}
635
636/*
637 * The real main loop of the debugger: create a new execution frame on the
638 * debugger stack, and while we have input available, call into the parser.
639 */
640int
641mdb_run(void)
642{
643	volatile int err;
644	mdb_frame_t f;
645
646	mdb_intr_disable();
647	mdb_frame_push(&f);
648
649	/*
650	 * This is a fresh mdb context, so ignore any pipe command we may have
651	 * inherited from the previous frame.
652	 */
653	f.f_pcmd = NULL;
654
655	if ((err = setjmp(f.f_pcb)) != 0) {
656		int pop = (mdb.m_in != NULL &&
657		    (mdb_iob_isapipe(mdb.m_in) || mdb_iob_isastr(mdb.m_in)));
658		int fromcmd = (f.f_cp != NULL);
659
660		mdb_dprintf(MDB_DBG_DSTK, "frame <%u> caught event %s\n",
661		    f.f_id, mdb_err2str(err));
662
663		/*
664		 * If a syntax error or other failure has occurred, pop all
665		 * input buffers pushed by commands executed in this frame.
666		 */
667		while (mdb_iob_stack_size(&f.f_istk) != 0) {
668			if (mdb.m_in != NULL)
669				mdb_iob_destroy(mdb.m_in);
670			mdb.m_in = mdb_iob_stack_pop(&f.f_istk);
671			yylineno = mdb_iob_lineno(mdb.m_in);
672		}
673
674		/*
675		 * Reset standard output and the current frame to a known,
676		 * clean state, so we can continue execution.
677		 */
678		mdb_iob_margin(mdb.m_out, MDB_IOB_DEFMARGIN);
679		mdb_iob_clrflags(mdb.m_out, MDB_IOB_INDENT);
680		mdb_iob_discard(mdb.m_out);
681		mdb_frame_reset(&f);
682
683		/*
684		 * If there was an error writing to output, display a warning
685		 * message if this is the topmost frame.
686		 */
687		if (err == MDB_ERR_OUTPUT && mdb.m_depth == 1 && errno != EPIPE)
688			mdb_warn("write failed");
689
690		/*
691		 * If an interrupt or quit signal is reported, we may have been
692		 * in the middle of typing or processing the command line:
693		 * print a newline and discard everything in the parser's iob.
694		 * Note that we do this after m_out has been reset, otherwise
695		 * we could trigger a pipe context switch or cause a write
696		 * to a broken pipe (in the case of a shell command) when
697		 * writing the newline.
698		 */
699		if (err == MDB_ERR_SIGINT || err == MDB_ERR_QUIT) {
700			mdb_iob_nl(mdb.m_out);
701			yydiscard();
702		}
703
704		/*
705		 * If we quit or abort using the output pager, reset the
706		 * line count on standard output back to zero.
707		 */
708		if (err == MDB_ERR_PAGER || MDB_ERR_IS_FATAL(err))
709			mdb_iob_clearlines(mdb.m_out);
710
711		/*
712		 * If the user requested the debugger quit or abort back to
713		 * the top, or if standard input is a pipe or mdb_eval("..."),
714		 * then propagate the error up the debugger stack.
715		 */
716		if (MDB_ERR_IS_FATAL(err) || pop != 0 ||
717		    (err == MDB_ERR_PAGER && mdb.m_fmark != &f) ||
718		    (err == MDB_ERR_NOMEM && !fromcmd)) {
719			mdb_frame_pop(&f, err);
720			return (err);
721		}
722
723		/*
724		 * If we've returned here from a context where signals were
725		 * blocked (e.g. a signal handler), we can now unblock them.
726		 */
727		if (err == MDB_ERR_SIGINT)
728			(void) mdb_signal_unblock(SIGINT);
729	} else
730		mdb_intr_enable();
731
732	for (;;) {
733		while (mdb.m_in != NULL && (mdb_iob_getflags(mdb.m_in) &
734		    (MDB_IOB_ERR | MDB_IOB_EOF)) == 0) {
735			if (mdb.m_depth == 1 &&
736			    mdb_iob_stack_size(&f.f_istk) == 0) {
737				mdb_iob_clearlines(mdb.m_out);
738				mdb_tgt_periodic(mdb.m_target);
739			}
740
741			(void) yyparse();
742		}
743
744		if (mdb.m_in != NULL) {
745			if (mdb_iob_err(mdb.m_in)) {
746				warn("error reading input stream %s\n",
747				    mdb_iob_name(mdb.m_in));
748			}
749			mdb_iob_destroy(mdb.m_in);
750			mdb.m_in = NULL;
751		}
752
753		if (mdb_iob_stack_size(&f.f_istk) == 0)
754			break; /* return when we're out of input */
755
756		mdb.m_in = mdb_iob_stack_pop(&f.f_istk);
757		yylineno = mdb_iob_lineno(mdb.m_in);
758	}
759
760	mdb_frame_pop(&f, 0);
761
762	/*
763	 * The value of '.' is a per-frame attribute, to preserve it properly
764	 * when switching frames.  But in the case of calling mdb_run()
765	 * explicitly (such as through mdb_eval), we want to propagate the value
766	 * of '.' to the parent.
767	 */
768	mdb_nv_set_value(mdb.m_dot, f.f_dot);
769
770	return (0);
771}
772
773/*
774 * The read-side of the pipe executes this service routine.  We simply call
775 * mdb_run to create a new frame on the execution stack and run the MDB parser,
776 * and then propagate any error code back to the previous frame.
777 */
778static int
779runsvc(void)
780{
781	int err = mdb_run();
782
783	if (err != 0) {
784		mdb_dprintf(MDB_DBG_DSTK, "forwarding error %s from pipeline\n",
785		    mdb_err2str(err));
786		longjmp(mdb.m_frame->f_pcb, err);
787	}
788
789	return (err);
790}
791
792/*
793 * Read-side pipe service routine: if we longjmp here, just return to the read
794 * routine because now we have more data to consume.  Otherwise:
795 * (1) if ctx_data is non-NULL, longjmp to the write-side to produce more data;
796 * (2) if wriob is NULL, there is no writer but this is the first read, so we
797 *     can just execute mdb_run() to completion on the current stack;
798 * (3) if (1) and (2) are false, then there is a writer and this is the first
799 *     read, so create a co-routine context to execute mdb_run().
800 */
801/*ARGSUSED*/
802static void
803rdsvc(mdb_iob_t *rdiob, mdb_iob_t *wriob, mdb_iob_ctx_t *ctx)
804{
805	if (setjmp(ctx->ctx_rpcb) == 0) {
806		/*
807		 * Save the current standard input into the pipe context, and
808		 * reset m_in to point to the pipe.  We will restore it on
809		 * the way back in wrsvc() below.
810		 */
811		ctx->ctx_iob = mdb.m_in;
812		mdb.m_in = rdiob;
813
814		ctx->ctx_rptr = mdb.m_frame;
815		if (ctx->ctx_wptr != NULL)
816			mdb_frame_switch(ctx->ctx_wptr);
817
818		if (ctx->ctx_data != NULL)
819			longjmp(ctx->ctx_wpcb, 1);
820		else if (wriob == NULL)
821			(void) runsvc();
822		else if ((ctx->ctx_data = mdb_context_create(runsvc)) != NULL)
823			mdb_context_switch(ctx->ctx_data);
824		else
825			mdb_warn("failed to create pipe context");
826	}
827}
828
829/*
830 * Write-side pipe service routine: if we longjmp here, just return to the
831 * write routine because now we have free space in the pipe buffer for writing;
832 * otherwise longjmp to the read-side to consume data and create space for us.
833 */
834/*ARGSUSED*/
835static void
836wrsvc(mdb_iob_t *rdiob, mdb_iob_t *wriob, mdb_iob_ctx_t *ctx)
837{
838	if (setjmp(ctx->ctx_wpcb) == 0) {
839		ctx->ctx_wptr = mdb.m_frame;
840		if (ctx->ctx_rptr != NULL)
841			mdb_frame_switch(ctx->ctx_rptr);
842
843		mdb.m_in = ctx->ctx_iob;
844		longjmp(ctx->ctx_rpcb, 1);
845	}
846}
847
848/*
849 * Call the current frame's mdb command.  This entry point is used by the
850 * MDB parser to actually execute a command once it has successfully parsed
851 * a line of input.  The command is waiting for us in the current frame.
852 * We loop through each command on the list, executing its dcmd with the
853 * appropriate argument.  If the command has a successor, we know it had
854 * a | operator after it, and so we need to create a pipe and replace
855 * stdout with the pipe's output buffer.
856 */
857int
858mdb_call(uintmax_t addr, uintmax_t count, uint_t flags)
859{
860	mdb_frame_t *fp = mdb.m_frame;
861	mdb_cmd_t *cp, *ncp;
862	mdb_iob_t *iobs[2];
863	int status, err = 0;
864	jmp_buf pcb;
865
866	if (mdb_iob_isapipe(mdb.m_in))
867		yyerror("syntax error");
868
869	mdb_intr_disable();
870	fp->f_cp = mdb_list_next(&fp->f_cmds);
871
872	if (flags & DCMD_LOOP)
873		flags |= DCMD_LOOPFIRST; /* set LOOPFIRST if this is a loop */
874
875	for (cp = mdb_list_next(&fp->f_cmds); cp; cp = mdb_list_next(cp)) {
876		if (mdb_list_next(cp) != NULL) {
877			mdb_iob_pipe(iobs, rdsvc, wrsvc);
878
879			mdb_iob_stack_push(&fp->f_istk, mdb.m_in, yylineno);
880			mdb.m_in = iobs[MDB_IOB_RDIOB];
881
882			mdb_iob_stack_push(&fp->f_ostk, mdb.m_out, 0);
883			mdb.m_out = iobs[MDB_IOB_WRIOB];
884
885			ncp = mdb_list_next(cp);
886			mdb_vcb_inherit(cp, ncp);
887
888			bcopy(fp->f_pcb, pcb, sizeof (jmp_buf));
889			ASSERT(fp->f_pcmd == NULL);
890			fp->f_pcmd = ncp;
891
892			mdb_frame_set_pipe(fp);
893
894			if ((err = setjmp(fp->f_pcb)) == 0) {
895				status = mdb_call_idcmd(cp->c_dcmd, addr, count,
896				    flags | DCMD_PIPE_OUT, &cp->c_argv,
897				    &cp->c_addrv, cp->c_vcbs);
898
899				ASSERT(mdb.m_in == iobs[MDB_IOB_RDIOB]);
900				ASSERT(mdb.m_out == iobs[MDB_IOB_WRIOB]);
901			} else {
902				mdb_dprintf(MDB_DBG_DSTK, "frame <%u> caught "
903				    "error %s from pipeline\n", fp->f_id,
904				    mdb_err2str(err));
905			}
906
907			if (err != 0 || DCMD_ABORTED(status)) {
908				mdb_iob_setflags(mdb.m_in, MDB_IOB_ERR);
909				mdb_iob_setflags(mdb.m_out, MDB_IOB_ERR);
910			} else {
911				mdb_iob_flush(mdb.m_out);
912				(void) mdb_iob_ctl(mdb.m_out, I_FLUSH,
913				    (void *)FLUSHW);
914			}
915
916			mdb_frame_clear_pipe(fp);
917
918			mdb_iob_destroy(mdb.m_out);
919			mdb.m_out = mdb_iob_stack_pop(&fp->f_ostk);
920
921			if (mdb.m_in != NULL)
922				mdb_iob_destroy(mdb.m_in);
923
924			mdb.m_in = mdb_iob_stack_pop(&fp->f_istk);
925			yylineno = mdb_iob_lineno(mdb.m_in);
926
927			fp->f_pcmd = NULL;
928			bcopy(pcb, fp->f_pcb, sizeof (jmp_buf));
929
930			if (MDB_ERR_IS_FATAL(err))
931				longjmp(fp->f_pcb, err);
932
933			if (err != 0 || DCMD_ABORTED(status) ||
934			    mdb_addrvec_length(&ncp->c_addrv) == 0)
935				break;
936
937			addr = mdb_nv_get_value(mdb.m_dot);
938			count = 1;
939			flags = 0;
940
941		} else {
942			mdb_intr_enable();
943			(void) mdb_call_idcmd(cp->c_dcmd, addr, count, flags,
944			    &cp->c_argv, &cp->c_addrv, cp->c_vcbs);
945			mdb_intr_disable();
946		}
947
948		fp->f_cp = mdb_list_next(cp);
949		mdb_cmd_reset(cp);
950	}
951
952	/*
953	 * If our last-command list is non-empty, destroy it.  Then copy the
954	 * current frame's cmd list to the m_lastc list and reset the frame.
955	 */
956	while ((cp = mdb_list_next(&mdb.m_lastc)) != NULL) {
957		mdb_list_delete(&mdb.m_lastc, cp);
958		mdb_cmd_destroy(cp);
959	}
960
961	mdb_list_move(&fp->f_cmds, &mdb.m_lastc);
962	mdb_frame_reset(fp);
963	mdb_intr_enable();
964	return (err == 0);
965}
966
967uintmax_t
968mdb_dot_incr(const char *op)
969{
970	uintmax_t odot, ndot;
971
972	odot = mdb_nv_get_value(mdb.m_dot);
973	ndot = odot + mdb.m_incr;
974
975	if ((odot ^ ndot) & 0x8000000000000000ull)
976		yyerror("'%s' would cause '.' to overflow\n", op);
977
978	return (ndot);
979}
980
981uintmax_t
982mdb_dot_decr(const char *op)
983{
984	uintmax_t odot, ndot;
985
986	odot = mdb_nv_get_value(mdb.m_dot);
987	ndot = odot - mdb.m_incr;
988
989	if (ndot > odot)
990		yyerror("'%s' would cause '.' to underflow\n", op);
991
992	return (ndot);
993}
994
995mdb_iwalker_t *
996mdb_walker_lookup(const char *s)
997{
998	const char *p = strchr(s, '`');
999	mdb_var_t *v;
1000
1001	if (p != NULL) {
1002		size_t nbytes = MIN((size_t)(p - s), MDB_NV_NAMELEN - 1);
1003		char mname[MDB_NV_NAMELEN];
1004		mdb_module_t *mod;
1005
1006		(void) strncpy(mname, s, nbytes);
1007		mname[nbytes] = '\0';
1008
1009		if ((v = mdb_nv_lookup(&mdb.m_modules, mname)) == NULL) {
1010			(void) set_errno(EMDB_NOMOD);
1011			return (NULL);
1012		}
1013
1014		mod = mdb_nv_get_cookie(v);
1015
1016		if ((v = mdb_nv_lookup(&mod->mod_walkers, ++p)) != NULL)
1017			return (mdb_nv_get_cookie(v));
1018
1019	} else if ((v = mdb_nv_lookup(&mdb.m_walkers, s)) != NULL)
1020		return (mdb_nv_get_cookie(mdb_nv_get_cookie(v)));
1021
1022	(void) set_errno(EMDB_NOWALK);
1023	return (NULL);
1024}
1025
1026mdb_idcmd_t *
1027mdb_dcmd_lookup(const char *s)
1028{
1029	const char *p = strchr(s, '`');
1030	mdb_var_t *v;
1031
1032	if (p != NULL) {
1033		size_t nbytes = MIN((size_t)(p - s), MDB_NV_NAMELEN - 1);
1034		char mname[MDB_NV_NAMELEN];
1035		mdb_module_t *mod;
1036
1037		(void) strncpy(mname, s, nbytes);
1038		mname[nbytes] = '\0';
1039
1040		if ((v = mdb_nv_lookup(&mdb.m_modules, mname)) == NULL) {
1041			(void) set_errno(EMDB_NOMOD);
1042			return (NULL);
1043		}
1044
1045		mod = mdb_nv_get_cookie(v);
1046
1047		if ((v = mdb_nv_lookup(&mod->mod_dcmds, ++p)) != NULL)
1048			return (mdb_nv_get_cookie(v));
1049
1050	} else if ((v = mdb_nv_lookup(&mdb.m_dcmds, s)) != NULL)
1051		return (mdb_nv_get_cookie(mdb_nv_get_cookie(v)));
1052
1053	(void) set_errno(EMDB_NODCMD);
1054	return (NULL);
1055}
1056
1057void
1058mdb_dcmd_usage(const mdb_idcmd_t *idcp, mdb_iob_t *iob)
1059{
1060	const char *prefix = "", *usage = "";
1061	char name0 = idcp->idc_name[0];
1062
1063	if (idcp->idc_usage != NULL) {
1064		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 if (idcp->idc_usage[0] == '?') {
1072			if (name0 != ':' && name0 != '$')
1073				prefix = "[address]::";
1074			else
1075				prefix = "[address]";
1076			usage = &idcp->idc_usage[1];
1077
1078		} else
1079			usage = idcp->idc_usage;
1080	}
1081
1082	mdb_iob_printf(iob, "Usage: %s%s %s\n", prefix, idcp->idc_name, usage);
1083
1084	if (idcp->idc_help != NULL) {
1085		mdb_iob_printf(iob, "%s: try '::help %s' for more "
1086		    "information\n", mdb.m_pname, idcp->idc_name);
1087	}
1088}
1089
1090static mdb_idcmd_t *
1091dcmd_ndef(const mdb_idcmd_t *idcp)
1092{
1093	mdb_var_t *v = mdb_nv_get_ndef(idcp->idc_var);
1094
1095	if (v != NULL)
1096		return (mdb_nv_get_cookie(mdb_nv_get_cookie(v)));
1097
1098	return (NULL);
1099}
1100
1101static int
1102dcmd_invoke(mdb_idcmd_t *idcp, uintptr_t addr, uint_t flags,
1103    int argc, const mdb_arg_t *argv, const mdb_vcb_t *vcbs)
1104{
1105	int status;
1106
1107	mdb_dprintf(MDB_DBG_DCMD, "dcmd %s`%s dot = %lr incr = %llr\n",
1108	    idcp->idc_modp->mod_name, idcp->idc_name, addr, mdb.m_incr);
1109
1110	if ((status = idcp->idc_funcp(addr, flags, argc, argv)) == DCMD_USAGE) {
1111		mdb_dcmd_usage(idcp, mdb.m_err);
1112		goto done;
1113	}
1114
1115	while (status == DCMD_NEXT && (idcp = dcmd_ndef(idcp)) != NULL)
1116		status = idcp->idc_funcp(addr, flags, argc, argv);
1117
1118	if (status == DCMD_USAGE)
1119		mdb_dcmd_usage(idcp, mdb.m_err);
1120
1121	if (status == DCMD_NEXT)
1122		status = DCMD_OK;
1123done:
1124	/*
1125	 * If standard output is a pipe and there are vcbs active, we need to
1126	 * flush standard out and the write-side of the pipe.  The reasons for
1127	 * this are explained in more detail in mdb_vcb.c.
1128	 */
1129	if ((flags & DCMD_PIPE_OUT) && (vcbs != NULL)) {
1130		mdb_iob_flush(mdb.m_out);
1131		(void) mdb_iob_ctl(mdb.m_out, I_FLUSH, (void *)FLUSHW);
1132	}
1133
1134	return (status);
1135}
1136
1137/*
1138 * Call an internal dcmd directly: this code is used by module API functions
1139 * that need to execute dcmds, and by mdb_call() above.
1140 */
1141int
1142mdb_call_idcmd(mdb_idcmd_t *idcp, uintmax_t addr, uintmax_t count,
1143    uint_t flags, mdb_argvec_t *avp, mdb_addrvec_t *adp, mdb_vcb_t *vcbs)
1144{
1145	int is_exec = (strcmp(idcp->idc_name, "$<") == 0);
1146	mdb_arg_t *argv;
1147	int argc;
1148	uintmax_t i;
1149	int status;
1150
1151	/*
1152	 * Update the values of dot and the most recent address and count
1153	 * to the values of our input parameters.
1154	 */
1155	mdb_nv_set_value(mdb.m_dot, addr);
1156	mdb.m_raddr = addr;
1157	mdb.m_dcount = count;
1158
1159	/*
1160	 * Here the adb(1) man page lies: '9' is only set to count
1161	 * when the command is $<, not when it's $<<.
1162	 */
1163	if (is_exec)
1164		mdb_nv_set_value(mdb.m_rcount, count);
1165
1166	/*
1167	 * We can now return if the repeat count is zero.
1168	 */
1169	if (count == 0)
1170		return (DCMD_OK);
1171
1172	/*
1173	 * To guard against bad dcmds, we avoid passing the actual argv that
1174	 * we will use to free argument strings directly to the dcmd.  Instead,
1175	 * we pass a copy that will be garbage collected automatically.
1176	 */
1177	argc = avp->a_nelems;
1178	argv = mdb_alloc(sizeof (mdb_arg_t) * argc, UM_SLEEP | UM_GC);
1179	bcopy(avp->a_data, argv, sizeof (mdb_arg_t) * argc);
1180
1181	if (mdb_addrvec_length(adp) != 0) {
1182		flags |= DCMD_PIPE | DCMD_LOOP | DCMD_LOOPFIRST | DCMD_ADDRSPEC;
1183		addr = mdb_addrvec_shift(adp);
1184		mdb_nv_set_value(mdb.m_dot, addr);
1185		mdb_vcb_propagate(vcbs);
1186		count = 1;
1187	}
1188
1189	status = dcmd_invoke(idcp, addr, flags, argc, argv, vcbs);
1190	if (DCMD_ABORTED(status))
1191		goto done;
1192
1193	/*
1194	 * If the command is $< and we're not receiving input from a pipe, we
1195	 * ignore the repeat count and just return since the macro file is now
1196	 * pushed on to the input stack.
1197	 */
1198	if (is_exec && mdb_addrvec_length(adp) == 0)
1199		goto done;
1200
1201	/*
1202	 * If we're going to loop, we've already executed the dcmd once,
1203	 * so clear the LOOPFIRST flag before proceeding.
1204	 */
1205	if (flags & DCMD_LOOP)
1206		flags &= ~DCMD_LOOPFIRST;
1207
1208	for (i = 1; i < count; i++) {
1209		addr = mdb_dot_incr(",");
1210		mdb_nv_set_value(mdb.m_dot, addr);
1211		status = dcmd_invoke(idcp, addr, flags, argc, argv, vcbs);
1212		if (DCMD_ABORTED(status))
1213			goto done;
1214	}
1215
1216	while (mdb_addrvec_length(adp) != 0) {
1217		addr = mdb_addrvec_shift(adp);
1218		mdb_nv_set_value(mdb.m_dot, addr);
1219		mdb_vcb_propagate(vcbs);
1220		status = dcmd_invoke(idcp, addr, flags, argc, argv, vcbs);
1221		if (DCMD_ABORTED(status))
1222			goto done;
1223	}
1224done:
1225	mdb_iob_nlflush(mdb.m_out);
1226	return (status);
1227}
1228
1229void
1230mdb_intr_enable(void)
1231{
1232	ASSERT(mdb.m_intr >= 1);
1233	if (mdb.m_intr == 1 && mdb.m_pend != 0) {
1234		(void) mdb_signal_block(SIGINT);
1235		mdb.m_intr = mdb.m_pend = 0;
1236		mdb_dprintf(MDB_DBG_DSTK, "delivering pending INT\n");
1237		longjmp(mdb.m_frame->f_pcb, MDB_ERR_SIGINT);
1238	} else
1239		mdb.m_intr--;
1240}
1241
1242void
1243mdb_intr_disable(void)
1244{
1245	mdb.m_intr++;
1246	ASSERT(mdb.m_intr >= 1);
1247}
1248
1249/*
1250 * Create an encoded string representing the internal user-modifiable
1251 * configuration of the debugger and return a pointer to it.  The string can be
1252 * used to initialize another instance of the debugger with the same
1253 * configuration as this one.
1254 */
1255char *
1256mdb_get_config(void)
1257{
1258	size_t r, n = 0;
1259	char *s = NULL;
1260
1261	while ((r = mdb_snprintf(s, n,
1262	    "%x;%x;%x;%x;%x;%x;%lx;%x;%x;%s;%s;%s;%s;%s",
1263	    mdb.m_tgtflags, mdb.m_flags, mdb.m_debug, mdb.m_radix, mdb.m_nargs,
1264	    mdb.m_histlen, (ulong_t)mdb.m_symdist, mdb.m_execmode,
1265	    mdb.m_forkmode, mdb.m_root, mdb.m_termtype, mdb.m_ipathstr,
1266	    mdb.m_lpathstr, mdb.m_prompt)) > n) {
1267
1268		mdb_free(s, n);
1269		n = r + 1;
1270		s = mdb_alloc(r + 1, UM_SLEEP);
1271	}
1272
1273	return (s);
1274}
1275
1276/*
1277 * Decode a configuration string created with mdb_get_config() and reset the
1278 * appropriate parts of the global mdb_t accordingly.
1279 */
1280void
1281mdb_set_config(const char *s)
1282{
1283	const char *p;
1284	size_t len;
1285
1286	if ((p = strchr(s, ';')) != NULL) {
1287		mdb.m_tgtflags = strntoul(s, (size_t)(p - s), 16);
1288		s = p + 1;
1289	}
1290
1291	if ((p = strchr(s, ';')) != NULL) {
1292		mdb.m_flags = strntoul(s, (size_t)(p - s), 16);
1293		mdb.m_flags &= ~(MDB_FL_LOG | MDB_FL_LATEST);
1294		s = p + 1;
1295	}
1296
1297	if ((p = strchr(s, ';')) != NULL) {
1298		mdb.m_debug = strntoul(s, (size_t)(p - s), 16);
1299		s = p + 1;
1300	}
1301
1302	if ((p = strchr(s, ';')) != NULL) {
1303		mdb.m_radix = (int)strntoul(s, (size_t)(p - s), 16);
1304		if (mdb.m_radix < 2 || mdb.m_radix > 16)
1305			mdb.m_radix = MDB_DEF_RADIX;
1306		s = p + 1;
1307	}
1308
1309	if ((p = strchr(s, ';')) != NULL) {
1310		mdb.m_nargs = (int)strntoul(s, (size_t)(p - s), 16);
1311		mdb.m_nargs = MAX(mdb.m_nargs, 0);
1312		s = p + 1;
1313	}
1314
1315	if ((p = strchr(s, ';')) != NULL) {
1316		mdb.m_histlen = (int)strntoul(s, (size_t)(p - s), 16);
1317		mdb.m_histlen = MAX(mdb.m_histlen, 1);
1318		s = p + 1;
1319	}
1320
1321	if ((p = strchr(s, ';')) != NULL) {
1322		mdb.m_symdist = strntoul(s, (size_t)(p - s), 16);
1323		s = p + 1;
1324	}
1325
1326	if ((p = strchr(s, ';')) != NULL) {
1327		mdb.m_execmode = (uchar_t)strntoul(s, (size_t)(p - s), 16);
1328		if (mdb.m_execmode > MDB_EM_FOLLOW)
1329			mdb.m_execmode = MDB_EM_ASK;
1330		s = p + 1;
1331	}
1332
1333	if ((p = strchr(s, ';')) != NULL) {
1334		mdb.m_forkmode = (uchar_t)strntoul(s, (size_t)(p - s), 16);
1335		if (mdb.m_forkmode > MDB_FM_CHILD)
1336			mdb.m_forkmode = MDB_FM_ASK;
1337		s = p + 1;
1338	}
1339
1340	if ((p = strchr(s, ';')) != NULL) {
1341		mdb.m_root = strndup(s, (size_t)(p - s));
1342		s = p + 1;
1343	}
1344
1345	if ((p = strchr(s, ';')) != NULL) {
1346		mdb.m_termtype = strndup(s, (size_t)(p - s));
1347		s = p + 1;
1348	}
1349
1350	if ((p = strchr(s, ';')) != NULL) {
1351		size_t len = MIN(sizeof (mdb.m_ipathstr) - 1, p - s);
1352		strncpy(mdb.m_ipathstr, s, len);
1353		mdb.m_ipathstr[len] = '\0';
1354		s = p + 1;
1355	}
1356
1357	if ((p = strchr(s, ';')) != NULL) {
1358		size_t len = MIN(sizeof (mdb.m_lpathstr) - 1, p - s);
1359		strncpy(mdb.m_lpathstr, s, len);
1360		mdb.m_lpathstr[len] = '\0';
1361		s = p + 1;
1362	}
1363
1364	p = s + strlen(s);
1365	len = MIN(MDB_PROMPTLEN, (size_t)(p - s));
1366	(void) strncpy(mdb.m_prompt, s, len);
1367	mdb.m_prompt[len] = '\0';
1368	mdb.m_promptlen = len;
1369}
1370
1371mdb_module_t *
1372mdb_get_module(void)
1373{
1374	if (mdb.m_lmod)
1375		return (mdb.m_lmod);
1376
1377	if (mdb.m_frame == NULL)
1378		return (NULL);
1379
1380	if (mdb.m_frame->f_wcbs && mdb.m_frame->f_wcbs->w_walker &&
1381	    mdb.m_frame->f_wcbs->w_walker->iwlk_modp)
1382		return (mdb.m_frame->f_wcbs->w_walker->iwlk_modp);
1383
1384	if (mdb.m_frame->f_cp && mdb.m_frame->f_cp->c_dcmd)
1385		return (mdb.m_frame->f_cp->c_dcmd->idc_modp);
1386
1387	return (NULL);
1388}
1389