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