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