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 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * Support for ::set dcmd. The +/-o option processing code is provided in a
28 * stand-alone function so it can be used by the command-line option processing
29 * code in mdb_main.c. This facility provides an easy way for us to add more
30 * configurable options without having to add a new dcmd each time.
31 */
32
33 #include <mdb/mdb_target.h>
34 #include <mdb/mdb_modapi.h>
35 #include <mdb/mdb_string.h>
36 #include <mdb/mdb_debug.h>
37 #include <mdb/mdb.h>
38
39 /*ARGSUSED*/
40 static int
opt_set_mflags(int enable,uint_t bits,const char * arg)41 opt_set_mflags(int enable, uint_t bits, const char *arg)
42 {
43 mdb.m_flags = (mdb.m_flags & ~bits) | (bits & -enable);
44 return (1);
45 }
46
47 /*ARGSUSED*/
48 static int
opt_set_tflags(int enable,uint_t bits,const char * arg)49 opt_set_tflags(int enable, uint_t bits, const char *arg)
50 {
51 mdb.m_tgtflags = (mdb.m_tgtflags & ~bits) | (bits & -enable);
52 return (1);
53 }
54
55 static int
opt_pager(int enable,uint_t bits,const char * arg)56 opt_pager(int enable, uint_t bits, const char *arg)
57 {
58 if (enable)
59 mdb_iob_setflags(mdb.m_out, MDB_IOB_PGENABLE);
60 else
61 mdb_iob_clrflags(mdb.m_out, MDB_IOB_PGENABLE);
62
63 return (opt_set_mflags(enable, bits, arg));
64 }
65
66 static int
opt_adb(int enable,uint_t bits,const char * arg)67 opt_adb(int enable, uint_t bits, const char *arg)
68 {
69 if (enable)
70 (void) mdb_set_prompt("");
71 else if (mdb.m_promptlen == 0)
72 (void) mdb_set_prompt("> ");
73
74 (void) opt_pager(1 - enable, MDB_FL_PAGER, arg);
75 return (opt_set_mflags(enable, bits, arg));
76 }
77
78 /*ARGSUSED*/
79 static int
opt_armemlim(int enable,uint_t bits,const char * arg)80 opt_armemlim(int enable, uint_t bits, const char *arg)
81 {
82 if (strisnum(arg)) {
83 mdb.m_armemlim = strtoi(arg);
84 return (1);
85 }
86 if (strcmp(arg, "none") == 0) {
87 mdb.m_armemlim = MDB_ARR_NOLIMIT;
88 return (1);
89 }
90 return (0);
91 }
92
93 /*ARGSUSED*/
94 static int
opt_arstrlim(int enable,uint_t bits,const char * arg)95 opt_arstrlim(int enable, uint_t bits, const char *arg)
96 {
97 if (strisnum(arg)) {
98 mdb.m_arstrlim = strtoi(arg);
99 return (1);
100 }
101 if (strcmp(arg, "none") == 0) {
102 mdb.m_arstrlim = MDB_ARR_NOLIMIT;
103 return (1);
104 }
105 return (0);
106 }
107
108 /*ARGSUSED*/
109 static int
opt_exec_mode(int enable,uint_t bits,const char * arg)110 opt_exec_mode(int enable, uint_t bits, const char *arg)
111 {
112 if (strcmp(arg, "ask") == 0) {
113 mdb.m_execmode = MDB_EM_ASK;
114 return (1);
115 } else if (strcmp(arg, "stop") == 0) {
116 mdb.m_execmode = MDB_EM_STOP;
117 return (1);
118 } else if (strcmp(arg, "follow") == 0) {
119 mdb.m_execmode = MDB_EM_FOLLOW;
120 return (1);
121 }
122 return (0);
123 }
124
125 /*ARGSUSED*/
126 static int
opt_fork_mode(int enable,uint_t bits,const char * arg)127 opt_fork_mode(int enable, uint_t bits, const char *arg)
128 {
129 if (strcmp(arg, "ask") == 0) {
130 mdb.m_forkmode = MDB_FM_ASK;
131 return (1);
132 } else if (strcmp(arg, "parent") == 0) {
133 mdb.m_forkmode = MDB_FM_PARENT;
134 return (1);
135 } else if (strcmp(arg, "child") == 0) {
136 mdb.m_forkmode = MDB_FM_CHILD;
137 return (1);
138 }
139 return (0);
140 }
141
142 /*ARGSUSED*/
143 static int
opt_set_term(int enable,uint_t bits,const char * arg)144 opt_set_term(int enable, uint_t bits, const char *arg)
145 {
146 mdb.m_termtype = strdup(arg);
147 mdb.m_flags &= ~MDB_FL_TERMGUESS;
148
149 return (1);
150 }
151
152 int
mdb_set_options(const char * s,int enable)153 mdb_set_options(const char *s, int enable)
154 {
155 static const struct opdesc {
156 const char *opt_name;
157 int (*opt_func)(int, uint_t, const char *);
158 uint_t opt_bits;
159 } opdtab[] = {
160 { "adb", opt_adb, MDB_FL_REPLAST | MDB_FL_NOMODS | MDB_FL_ADB },
161 { "array_mem_limit", opt_armemlim, 0 },
162 { "array_str_limit", opt_arstrlim, 0 },
163 { "follow_exec_mode", opt_exec_mode, 0 },
164 { "follow_fork_mode", opt_fork_mode, 0 },
165 { "pager", opt_pager, MDB_FL_PAGER },
166 { "term", opt_set_term, 0 },
167
168 { "ignoreeof", opt_set_mflags, MDB_FL_IGNEOF },
169 { "repeatlast", opt_set_mflags, MDB_FL_REPLAST },
170 { "latest", opt_set_mflags, MDB_FL_LATEST },
171 { "noctf", opt_set_mflags, MDB_FL_NOCTF },
172 { "nomods", opt_set_mflags, MDB_FL_NOMODS },
173 { "showlmid", opt_set_mflags, MDB_FL_SHOWLMID },
174 { "lmraw", opt_set_mflags, MDB_FL_LMRAW },
175 { "stop_on_bpt_nosym", opt_set_mflags, MDB_FL_BPTNOSYMSTOP },
176 { "write_readback", opt_set_mflags, MDB_FL_READBACK },
177
178 { "allow_io_access", opt_set_tflags, MDB_TGT_F_ALLOWIO },
179 { "nostop", opt_set_tflags, MDB_TGT_F_NOSTOP },
180 { NULL, NULL, 0 }
181 };
182
183 const struct opdesc *opp;
184 char *buf = strdup(s);
185 char *opt, *arg;
186 int status = 1;
187
188 for (opt = strtok(buf, ","); opt != NULL; opt = strtok(NULL, ",")) {
189 if ((arg = strchr(opt, '=')) != NULL)
190 *arg++ = '\0';
191
192 for (opp = opdtab; opp->opt_name != NULL; opp++) {
193 if (strcmp(opt, opp->opt_name) == 0) {
194 if (opp->opt_bits != 0 && arg != NULL) {
195 mdb_warn("option does not accept an "
196 "argument -- %s\n", opt);
197 status = 0;
198 } else if (opp->opt_bits == 0 && arg == NULL) {
199 mdb_warn("option requires an argument "
200 "-- %s\n", opt);
201 status = 0;
202 } else if (opp->opt_func(enable != 0,
203 opp->opt_bits, arg) == 0) {
204 mdb_warn("invalid argument for option "
205 "%s -- %s\n", opt, arg);
206 status = 0;
207 }
208 break;
209 }
210 }
211
212 if (opp->opt_name == NULL) {
213 mdb_warn("invalid debugger option -- %s\n", opt);
214 status = 0;
215 }
216 }
217
218 mdb_free(buf, strlen(s) + 1);
219 return (status);
220 }
221
222 static void
print_path(const char ** path,int indent)223 print_path(const char **path, int indent)
224 {
225 if (path != NULL && *path != NULL) {
226 for (mdb_printf("%s\n", *path++); *path != NULL; path++)
227 mdb_printf("%*s%s\n", indent, " ", *path);
228 }
229 mdb_printf("\n");
230 }
231
232 #define LABEL_INDENT 26
233
234 static void
print_properties(void)235 print_properties(void)
236 {
237 int tflags = mdb_tgt_getflags(mdb.m_target);
238 uint_t oflags = mdb_iob_getflags(mdb.m_out) & MDB_IOB_AUTOWRAP;
239
240 mdb_iob_clrflags(mdb.m_out, MDB_IOB_AUTOWRAP);
241 mdb_printf("\n macro path: ");
242 print_path(mdb.m_ipath, 14);
243 mdb_printf(" module path: ");
244 print_path(mdb.m_lpath, 14);
245 mdb_iob_setflags(mdb.m_out, oflags);
246
247 mdb_printf("%*s %lr (%s)\n", LABEL_INDENT, "symbol matching distance:",
248 mdb.m_symdist, mdb.m_symdist ? "absolute mode" : "smart mode");
249
250 mdb_printf("%*s ", LABEL_INDENT, "array member print limit:");
251 if (mdb.m_armemlim != MDB_ARR_NOLIMIT)
252 mdb_printf("%u\n", mdb.m_armemlim);
253 else
254 mdb_printf("none\n");
255
256 mdb_printf(" array string print limit: ");
257 if (mdb.m_arstrlim != MDB_ARR_NOLIMIT)
258 mdb_printf("%u\n", mdb.m_arstrlim);
259 else
260 mdb_printf("none\n");
261
262 mdb_printf("%*s \"%s\"\n", LABEL_INDENT, "command prompt:",
263 mdb.m_prompt);
264
265 mdb_printf("%*s ", LABEL_INDENT, "debugger options:");
266 (void) mdb_inc_indent(LABEL_INDENT + 1);
267
268 mdb_printf("follow_exec_mode=");
269 switch (mdb.m_execmode) {
270 case MDB_EM_ASK:
271 mdb_printf("ask");
272 break;
273 case MDB_EM_STOP:
274 mdb_printf("stop");
275 break;
276 case MDB_EM_FOLLOW:
277 mdb_printf("follow");
278 break;
279 }
280
281 #define COMMAFLAG(name) { mdb_printf(", "); mdb_printf(name); }
282
283 COMMAFLAG("follow_fork_mode");
284 switch (mdb.m_forkmode) {
285 case MDB_FM_ASK:
286 mdb_printf("ask");
287 break;
288 case MDB_FM_PARENT:
289 mdb_printf("parent");
290 break;
291 case MDB_FM_CHILD:
292 mdb_printf("child");
293 break;
294 }
295
296 if (mdb.m_flags & MDB_FL_ADB)
297 COMMAFLAG("adb");
298 if (mdb.m_flags & MDB_FL_IGNEOF)
299 COMMAFLAG("ignoreeof");
300 if (mdb.m_flags & MDB_FL_LMRAW)
301 COMMAFLAG("lmraw");
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
cmd_set(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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