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 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 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 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 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 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 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 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 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 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 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 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 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 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