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