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