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
85extern const mdb_dcmd_t mdb_dcmd_builtins[];
86extern 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 */
93static uintmax_t
94psym_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
105static void
106psym_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 */
119static uintmax_t
120roff_disc_get(const mdb_var_t *v)
121{
122	return (MDB_NV_VALUE(v));
123}
124
125static void
126roff_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 */
135static uintmax_t
136thr_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
146const char **
147mdb_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
314nomem:
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
322const char **
323mdb_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
345void
346mdb_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 */
364static const char *
365path_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
396void
397mdb_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
406void
407mdb_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
420static void
421prompt_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
428const char *
429mdb_get_prompt(void)
430{
431	if (mdb.m_promptlen == 0)
432		return (NULL);
433	else
434		return (mdb.m_prompt);
435}
436
437int
438mdb_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
452static mdb_frame_t frame0;
453
454void
455mdb_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
567void
568mdb_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 */
643int
644mdb_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 */
781static int
782runsvc(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*/
805static void
806rdsvc(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*/
838static void
839wrsvc(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 */
860int
861mdb_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
970uintmax_t
971mdb_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
984uintmax_t
985mdb_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
998mdb_iwalker_t *
999mdb_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
1029mdb_idcmd_t *
1030mdb_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
1060void
1061mdb_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
1093static mdb_idcmd_t *
1094dcmd_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
1104static int
1105dcmd_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;
1126done:
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
1140void
1141mdb_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 */
1154int
1155mdb_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	}
1237done:
1238	mdb_iob_nlflush(mdb.m_out);
1239	return (status);
1240}
1241
1242void
1243mdb_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
1255void
1256mdb_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 */
1268char *
1269mdb_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 */
1293void
1294mdb_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
1384mdb_module_t *
1385mdb_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