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