xref: /illumos-gate/usr/src/cmd/mdb/common/mdb/mdb_set.c (revision 03100a6332bd4edc7a53091fcf7c9a7131bcdaa7)
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  * Support for ::set dcmd.  The +/-o option processing code is provided in a
31  * stand-alone function so it can be used by the command-line option processing
32  * code in mdb_main.c.  This facility provides an easy way for us to add more
33  * configurable options without having to add a new dcmd each time.
34  */
35 
36 #include <mdb/mdb_target.h>
37 #include <mdb/mdb_modapi.h>
38 #include <mdb/mdb_string.h>
39 #include <mdb/mdb_debug.h>
40 #include <mdb/mdb.h>
41 
42 /*ARGSUSED*/
43 static int
44 opt_set_mflags(int enable, uint_t bits, const char *arg)
45 {
46 	mdb.m_flags = (mdb.m_flags & ~bits) | (bits & -enable);
47 	return (1);
48 }
49 
50 /*ARGSUSED*/
51 static int
52 opt_set_tflags(int enable, uint_t bits, const char *arg)
53 {
54 	mdb.m_tgtflags = (mdb.m_tgtflags & ~bits) | (bits & -enable);
55 	return (1);
56 }
57 
58 static int
59 opt_pager(int enable, uint_t bits, const char *arg)
60 {
61 	if (enable)
62 		mdb_iob_setflags(mdb.m_out, MDB_IOB_PGENABLE);
63 	else
64 		mdb_iob_clrflags(mdb.m_out, MDB_IOB_PGENABLE);
65 
66 	return (opt_set_mflags(enable, bits, arg));
67 }
68 
69 static int
70 opt_adb(int enable, uint_t bits, const char *arg)
71 {
72 	if (enable)
73 		(void) mdb_set_prompt("");
74 	else if (mdb.m_promptlen == 0)
75 		(void) mdb_set_prompt("> ");
76 
77 	(void) opt_pager(1 - enable, MDB_FL_PAGER, arg);
78 	return (opt_set_mflags(enable, bits, arg));
79 }
80 
81 /*ARGSUSED*/
82 static int
83 opt_armemlim(int enable, uint_t bits, const char *arg)
84 {
85 	if (strisnum(arg)) {
86 		mdb.m_armemlim = strtoi(arg);
87 		return (1);
88 	}
89 	if (strcmp(arg, "none") == 0) {
90 		mdb.m_armemlim = MDB_ARR_NOLIMIT;
91 		return (1);
92 	}
93 	return (0);
94 }
95 
96 /*ARGSUSED*/
97 static int
98 opt_arstrlim(int enable, uint_t bits, const char *arg)
99 {
100 	if (strisnum(arg)) {
101 		mdb.m_arstrlim = strtoi(arg);
102 		return (1);
103 	}
104 	if (strcmp(arg, "none") == 0) {
105 		mdb.m_arstrlim = MDB_ARR_NOLIMIT;
106 		return (1);
107 	}
108 	return (0);
109 }
110 
111 /*ARGSUSED*/
112 static int
113 opt_exec_mode(int enable, uint_t bits, const char *arg)
114 {
115 	if (strcmp(arg, "ask") == 0) {
116 		mdb.m_execmode = MDB_EM_ASK;
117 		return (1);
118 	} else if (strcmp(arg, "stop") == 0) {
119 		mdb.m_execmode = MDB_EM_STOP;
120 		return (1);
121 	} else if (strcmp(arg, "follow") == 0) {
122 		mdb.m_execmode = MDB_EM_FOLLOW;
123 		return (1);
124 	}
125 	return (0);
126 }
127 
128 /*ARGSUSED*/
129 static int
130 opt_fork_mode(int enable, uint_t bits, const char *arg)
131 {
132 	if (strcmp(arg, "ask") == 0) {
133 		mdb.m_forkmode = MDB_FM_ASK;
134 		return (1);
135 	} else if (strcmp(arg, "parent") == 0) {
136 		mdb.m_forkmode = MDB_FM_PARENT;
137 		return (1);
138 	} else if (strcmp(arg, "child") == 0) {
139 		mdb.m_forkmode = MDB_FM_CHILD;
140 		return (1);
141 	}
142 	return (0);
143 }
144 
145 /*ARGSUSED*/
146 static int
147 opt_set_term(int enable, uint_t bits, const char *arg)
148 {
149 	mdb.m_termtype = strdup(arg);
150 	mdb.m_flags &= ~MDB_FL_TERMGUESS;
151 
152 	return (1);
153 }
154 
155 int
156 mdb_set_options(const char *s, int enable)
157 {
158 	static const struct opdesc {
159 		const char *opt_name;
160 		int (*opt_func)(int, uint_t, const char *);
161 		uint_t opt_bits;
162 	} opdtab[] = {
163 		{ "adb", opt_adb, MDB_FL_REPLAST | MDB_FL_NOMODS | MDB_FL_ADB },
164 		{ "array_mem_limit", opt_armemlim, 0 },
165 		{ "array_str_limit", opt_arstrlim, 0 },
166 		{ "follow_exec_mode", opt_exec_mode, 0 },
167 		{ "follow_fork_mode", opt_fork_mode, 0 },
168 		{ "pager", opt_pager, MDB_FL_PAGER },
169 		{ "term", opt_set_term, 0 },
170 
171 		{ "ignoreeof", opt_set_mflags, MDB_FL_IGNEOF },
172 		{ "repeatlast", opt_set_mflags, MDB_FL_REPLAST },
173 		{ "latest", opt_set_mflags, MDB_FL_LATEST },
174 		{ "noctf", opt_set_mflags, MDB_FL_NOCTF },
175 		{ "nomods", opt_set_mflags, MDB_FL_NOMODS },
176 		{ "showlmid", opt_set_mflags, MDB_FL_SHOWLMID },
177 		{ "stop_on_bpt_nosym", opt_set_mflags, MDB_FL_BPTNOSYMSTOP },
178 		{ "write_readback", opt_set_mflags, MDB_FL_READBACK },
179 
180 		{ "allow_io_access", opt_set_tflags, MDB_TGT_F_ALLOWIO },
181 		{ "nostop", opt_set_tflags, MDB_TGT_F_NOSTOP },
182 		{ NULL, NULL, 0 }
183 	};
184 
185 	const struct opdesc *opp;
186 	char *buf = strdup(s);
187 	char *opt, *arg;
188 	int status = 1;
189 
190 	for (opt = strtok(buf, ","); opt != NULL; opt = strtok(NULL, ",")) {
191 		if ((arg = strchr(opt, '=')) != NULL)
192 			*arg++ = '\0';
193 
194 		for (opp = opdtab; opp->opt_name != NULL; opp++) {
195 			if (strcmp(opt, opp->opt_name) == 0) {
196 				if (opp->opt_bits != 0 && arg != NULL) {
197 					mdb_warn("option does not accept an "
198 					    "argument -- %s\n", opt);
199 					status = 0;
200 				} else if (opp->opt_bits == 0 && arg == NULL) {
201 					mdb_warn("option requires an argument "
202 					    "-- %s\n", opt);
203 					status = 0;
204 				} else if (opp->opt_func(enable != 0,
205 				    opp->opt_bits, arg) == 0) {
206 					mdb_warn("invalid argument for option "
207 					    "%s -- %s\n", opt, arg);
208 					status = 0;
209 				}
210 				break;
211 			}
212 		}
213 
214 		if (opp->opt_name == NULL) {
215 			mdb_warn("invalid debugger option -- %s\n", opt);
216 			status = 0;
217 		}
218 	}
219 
220 	mdb_free(buf, strlen(s) + 1);
221 	return (status);
222 }
223 
224 static void
225 print_path(const char **path, int indent)
226 {
227 	if (path != NULL && *path != NULL) {
228 		for (mdb_printf("%s\n", *path++); *path != NULL; path++)
229 			mdb_printf("%*s%s\n", indent, " ", *path);
230 	}
231 	mdb_printf("\n");
232 }
233 
234 #define	LABEL_INDENT	26
235 
236 static void
237 print_properties(void)
238 {
239 	int tflags = mdb_tgt_getflags(mdb.m_target);
240 	uint_t oflags = mdb_iob_getflags(mdb.m_out) & MDB_IOB_AUTOWRAP;
241 
242 	mdb_iob_clrflags(mdb.m_out, MDB_IOB_AUTOWRAP);
243 	mdb_printf("\n  macro path: ");
244 	print_path(mdb.m_ipath, 14);
245 	mdb_printf(" module path: ");
246 	print_path(mdb.m_lpath, 14);
247 	mdb_iob_setflags(mdb.m_out, oflags);
248 
249 	mdb_printf("%*s %lr (%s)\n", LABEL_INDENT, "symbol matching distance:",
250 	    mdb.m_symdist, mdb.m_symdist ? "absolute mode" : "smart mode");
251 
252 	mdb_printf("%*s ", LABEL_INDENT, "array member print limit:");
253 	if (mdb.m_armemlim != MDB_ARR_NOLIMIT)
254 		mdb_printf("%u\n", mdb.m_armemlim);
255 	else
256 		mdb_printf("none\n");
257 
258 	mdb_printf(" array string print limit: ");
259 	if (mdb.m_arstrlim != MDB_ARR_NOLIMIT)
260 		mdb_printf("%u\n", mdb.m_arstrlim);
261 	else
262 		mdb_printf("none\n");
263 
264 	mdb_printf("%*s \"%s\"\n", LABEL_INDENT, "command prompt:",
265 	    mdb.m_prompt);
266 
267 	mdb_printf("%*s ", LABEL_INDENT, "debugger options:");
268 	(void) mdb_inc_indent(LABEL_INDENT + 1);
269 
270 	mdb_printf("follow_exec_mode=");
271 	switch (mdb.m_execmode) {
272 	case MDB_EM_ASK:
273 		mdb_printf("ask");
274 		break;
275 	case MDB_EM_STOP:
276 		mdb_printf("stop");
277 		break;
278 	case MDB_EM_FOLLOW:
279 		mdb_printf("follow");
280 		break;
281 	}
282 
283 #define	COMMAFLAG(name) { mdb_printf(", "); mdb_printf(name); }
284 
285 	COMMAFLAG("follow_fork_mode");
286 	switch (mdb.m_forkmode) {
287 	case MDB_FM_ASK:
288 		mdb_printf("ask");
289 		break;
290 	case MDB_FM_PARENT:
291 		mdb_printf("parent");
292 		break;
293 	case MDB_FM_CHILD:
294 		mdb_printf("child");
295 		break;
296 	}
297 
298 	if (mdb.m_flags & MDB_FL_ADB)
299 		COMMAFLAG("adb");
300 	if (mdb.m_flags & MDB_FL_IGNEOF)
301 		COMMAFLAG("ignoreeof");
302 	if (mdb.m_flags & MDB_FL_PAGER)
303 		COMMAFLAG("pager");
304 	if (mdb.m_flags & MDB_FL_REPLAST)
305 		COMMAFLAG("repeatlast");
306 	if (mdb.m_flags & MDB_FL_SHOWLMID)
307 		COMMAFLAG("showlmid");
308 	if (mdb.m_flags & MDB_FL_BPTNOSYMSTOP)
309 		COMMAFLAG("stop_on_bpt_nosym");
310 	if (mdb.m_flags & MDB_FL_READBACK)
311 		COMMAFLAG("write_readback");
312 	mdb_printf("\n");
313 	(void) mdb_dec_indent(LABEL_INDENT + 1);
314 
315 	mdb_printf("%*s ", LABEL_INDENT, "target options:");
316 	(void) mdb_inc_indent(LABEL_INDENT + 1);
317 
318 	if (tflags & MDB_TGT_F_RDWR)
319 		mdb_printf("read-write");
320 	else
321 		mdb_printf("read-only");
322 	if (tflags & MDB_TGT_F_ALLOWIO)
323 		COMMAFLAG("allow-io-access");
324 	if (tflags & MDB_TGT_F_FORCE)
325 		COMMAFLAG("force-attach");
326 	if (tflags & MDB_TGT_F_PRELOAD)
327 		COMMAFLAG("preload-syms");
328 	if (tflags & MDB_TGT_F_NOLOAD)
329 		COMMAFLAG("no-load-objs");
330 	if (tflags & MDB_TGT_F_NOSTOP)
331 		COMMAFLAG("no-stop");
332 	mdb_printf("\n");
333 	(void) mdb_dec_indent(LABEL_INDENT + 1);
334 }
335 
336 /*ARGSUSED*/
337 int
338 cmd_set(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
339 {
340 	const char *opt_I = NULL, *opt_L = NULL, *opt_P = NULL, *opt_o = NULL;
341 	const char *opt_plus_o = NULL, *opt_D = NULL;
342 	uint_t opt_w = FALSE, opt_plus_w = FALSE, opt_W = FALSE;
343 	uint_t opt_plus_W = FALSE, opt_F = FALSE;
344 	uintptr_t opt_s = (uintptr_t)(long)-1;
345 
346 	int tflags = 0;
347 	int i;
348 
349 	if (flags & DCMD_ADDRSPEC)
350 		return (DCMD_USAGE);
351 
352 	/*
353 	 * If no options are specified, print out the current set of target
354 	 * and debugger properties that can be modified with ::set.
355 	 */
356 	if (argc == 0) {
357 		print_properties();
358 		return (DCMD_OK);
359 	}
360 
361 	while ((i = mdb_getopts(argc, argv,
362 	    'F', MDB_OPT_SETBITS, TRUE, &opt_F,
363 	    'I', MDB_OPT_STR, &opt_I,
364 	    'L', MDB_OPT_STR, &opt_L,
365 	    'P', MDB_OPT_STR, &opt_P,
366 	    'o', MDB_OPT_STR, &opt_o,
367 	    's', MDB_OPT_UINTPTR, &opt_s,
368 	    'w', MDB_OPT_SETBITS, TRUE, &opt_w,
369 	    'W', MDB_OPT_SETBITS, TRUE, &opt_W,
370 	    'D', MDB_OPT_STR, &opt_D, NULL)) != argc) {
371 		uint_t n = 1;
372 
373 		argv += i; /* skip past args we processed */
374 		argc -= i; /* adjust argc */
375 
376 		if (argv[0].a_type != MDB_TYPE_STRING)
377 			return (DCMD_USAGE);
378 
379 		if (strcmp(argv->a_un.a_str, "+W") == 0)
380 			opt_plus_W = TRUE;
381 		else if (strcmp(argv->a_un.a_str, "+w") == 0)
382 			opt_plus_w = TRUE;
383 		else if (strcmp(argv->a_un.a_str, "+o") == 0 &&
384 		    argc >= 2 && argv[1].a_type == MDB_TYPE_STRING) {
385 			opt_plus_o = argv[1].a_un.a_str;
386 			n = 2;
387 		} else
388 			return (DCMD_USAGE);
389 
390 		/* remove the flag and possible argument */
391 		argv += n;
392 		argc -= n;
393 	}
394 
395 	if ((opt_w && opt_plus_w) || (opt_W && opt_plus_W))
396 		return (DCMD_USAGE);
397 
398 	/*
399 	 * Handle -w, -/+W and -F first: as these options modify the target,
400 	 * they are the only ::set changes that can potentially fail.  We'll
401 	 * use these flags to modify a copy of the target's t_flags, which we'll
402 	 * then pass to the target's setflags op.  This allows the target to
403 	 * detect newly-set and newly-cleared flags by comparing the passed
404 	 * value to the current t_flags.
405 	 */
406 	tflags = mdb_tgt_getflags(mdb.m_target);
407 
408 	if (opt_w)
409 		tflags |= MDB_TGT_F_RDWR;
410 	if (opt_plus_w)
411 		tflags &= ~MDB_TGT_F_RDWR;
412 	if (opt_W)
413 		tflags |= MDB_TGT_F_ALLOWIO;
414 	if (opt_plus_W)
415 		tflags &= ~MDB_TGT_F_ALLOWIO;
416 	if (opt_F)
417 		tflags |= MDB_TGT_F_FORCE;
418 
419 	if (tflags != mdb_tgt_getflags(mdb.m_target) &&
420 	    mdb_tgt_setflags(mdb.m_target, tflags) == -1)
421 		return (DCMD_ERR);
422 
423 	/*
424 	 * Now handle everything that either can't fail or we don't care if
425 	 * it does.  Note that we handle +/-o first in case another option
426 	 * overrides a change made implicity by a +/-o argument (e.g. -P).
427 	 */
428 	if (opt_o != NULL)
429 		(void) mdb_set_options(opt_o, TRUE);
430 	if (opt_plus_o != NULL)
431 		(void) mdb_set_options(opt_plus_o, FALSE);
432 	if (opt_I != NULL) {
433 #ifdef _KMDB
434 		mdb_warn("macro path cannot be set under kmdb\n");
435 #else
436 		mdb_set_ipath(opt_I);
437 #endif
438 	}
439 	if (opt_L != NULL)
440 		mdb_set_lpath(opt_L);
441 	if (opt_P != NULL)
442 		(void) mdb_set_prompt(opt_P);
443 	if (opt_s != (uintptr_t)-1)
444 		mdb.m_symdist = (size_t)opt_s;
445 	if (opt_D != NULL && (i = mdb_dstr2mode(opt_D)) != MDB_DBG_HELP)
446 		mdb_dmode((uint_t)i);
447 
448 	return (DCMD_OK);
449 }
450