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