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