1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Modular Debugger (MDB) 31 * 32 * Refer to the white paper "A Modular Debugger for Solaris" for information 33 * on the design, features, and goals of MDB. See /shared/sac/PSARC/1999/169 34 * for copies of the paper and related documentation. 35 * 36 * This file provides the basic construction and destruction of the debugger's 37 * global state, as well as the main execution loop, mdb_run(). MDB maintains 38 * a stack of execution frames (mdb_frame_t's) that keep track of its current 39 * state, including a stack of input and output buffers, walk and memory 40 * garbage collect lists, and a list of commands (mdb_cmd_t's). As the 41 * parser consumes input, it fills in a list of commands to execute, and then 42 * invokes mdb_call(), below. A command consists of a dcmd, telling us 43 * what function to execute, and a list of arguments and other invocation- 44 * specific data. Each frame may have more than one command, kept on a list, 45 * when multiple commands are separated by | operators. New frames may be 46 * stacked on old ones by nested calls to mdb_run: this occurs when, for 47 * example, in the middle of processing one input source (such as a file 48 * or the terminal), we invoke a dcmd that in turn calls mdb_eval(). mdb_eval 49 * will construct a new frame whose input source is the string passed to 50 * the eval function, and then execute this frame to completion. 51 */ 52 53 #include <sys/param.h> 54 #include <stropts.h> 55 56 #define _MDB_PRIVATE 57 #include <mdb/mdb.h> 58 59 #include <mdb/mdb_context.h> 60 #include <mdb/mdb_argvec.h> 61 #include <mdb/mdb_signal.h> 62 #include <mdb/mdb_macalias.h> 63 #include <mdb/mdb_module.h> 64 #include <mdb/mdb_modapi.h> 65 #include <mdb/mdb_string.h> 66 #include <mdb/mdb_callb.h> 67 #include <mdb/mdb_debug.h> 68 #include <mdb/mdb_frame.h> 69 #include <mdb/mdb_conf.h> 70 #include <mdb/mdb_err.h> 71 #include <mdb/mdb_lex.h> 72 #include <mdb/mdb_io.h> 73 #ifdef _KMDB 74 #include <kmdb/kmdb_module.h> 75 #endif 76 77 /* 78 * Macro for testing if a dcmd's return status (x) indicates that we should 79 * abort the current loop or pipeline. 80 */ 81 #define DCMD_ABORTED(x) ((x) == DCMD_USAGE || (x) == DCMD_ABORT) 82 83 extern const mdb_dcmd_t mdb_dcmd_builtins[]; 84 extern mdb_dis_ctor_f *const mdb_dis_builtins[]; 85 86 /* 87 * Variable discipline for toggling MDB_FL_PSYM based on the value of the 88 * undocumented '_' variable. Once adb(1) has been removed from the system, 89 * we should just remove this functionality and always disable PSYM for macros. 90 */ 91 static uintmax_t 92 psym_disc_get(const mdb_var_t *v) 93 { 94 int i = (mdb.m_flags & MDB_FL_PSYM) ? 1 : 0; 95 int j = (MDB_NV_VALUE(v) != 0) ? 1 : 0; 96 97 if ((i ^ j) == 0) 98 MDB_NV_VALUE((mdb_var_t *)v) = j ^ 1; 99 100 return (MDB_NV_VALUE(v)); 101 } 102 103 static void 104 psym_disc_set(mdb_var_t *v, uintmax_t value) 105 { 106 if (value == 0) 107 mdb.m_flags |= MDB_FL_PSYM; 108 else 109 mdb.m_flags &= ~MDB_FL_PSYM; 110 111 MDB_NV_VALUE(v) = value; 112 } 113 114 /* 115 * Variable discipline for making <1 (most recent offset) behave properly. 116 */ 117 static uintmax_t 118 roff_disc_get(const mdb_var_t *v) 119 { 120 return (MDB_NV_VALUE(v)); 121 } 122 123 static void 124 roff_disc_set(mdb_var_t *v, uintmax_t value) 125 { 126 mdb_nv_set_value(mdb.m_proffset, MDB_NV_VALUE(v)); 127 MDB_NV_VALUE(v) = value; 128 } 129 130 /* 131 * Variable discipline for exporting the representative thread. 132 */ 133 static uintmax_t 134 thr_disc_get(const mdb_var_t *v) 135 { 136 mdb_tgt_status_t s; 137 138 if (mdb.m_target != NULL && mdb_tgt_status(mdb.m_target, &s) == 0) 139 return (s.st_tid); 140 141 return (MDB_NV_VALUE(v)); 142 } 143 144 const char ** 145 mdb_path_alloc(const char *s, size_t *newlen) 146 { 147 char *format = mdb_alloc(strlen(s) * 2 + 1, UM_NOSLEEP); 148 const char **path; 149 char *p, *q; 150 151 struct utsname uts; 152 size_t len; 153 int i; 154 155 mdb_arg_t arg_i, arg_m, arg_p, arg_r, arg_t, arg_R, arg_V; 156 mdb_argvec_t argv; 157 158 static const char *empty_path[] = { NULL }; 159 160 if (format == NULL) 161 goto nomem; 162 163 while (*s == ':') 164 s++; /* strip leading delimiters */ 165 166 if (*s == '\0') { 167 *newlen = 0; 168 return (empty_path); 169 } 170 171 (void) strcpy(format, s); 172 mdb_argvec_create(&argv); 173 174 /* 175 * %i embedded in path string expands to ISA. 176 */ 177 arg_i.a_type = MDB_TYPE_STRING; 178 if (mdb.m_target != NULL) 179 arg_i.a_un.a_str = mdb_tgt_isa(mdb.m_target); 180 else 181 arg_i.a_un.a_str = mdb_conf_isa(); 182 183 /* 184 * %p embedded in path string expands to the platform name. 185 */ 186 arg_p.a_type = MDB_TYPE_STRING; 187 if (mdb.m_target != NULL) 188 arg_p.a_un.a_str = mdb_tgt_platform(mdb.m_target); 189 else 190 arg_p.a_un.a_str = mdb_conf_platform(); 191 192 /* 193 * %r embedded in path string expands to root directory, or 194 * to the empty string if root is "/" (to avoid // in paths). 195 */ 196 arg_r.a_type = MDB_TYPE_STRING; 197 arg_r.a_un.a_str = strcmp(mdb.m_root, "/") ? mdb.m_root : ""; 198 199 /* 200 * %t embedded in path string expands to the target name. 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) : "none"; 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 * Unload modules _before_ destroying the disassemblers since a 581 * module that installs a disassembler should try to clean up after 582 * itself. 583 */ 584 mdb_module_unload_all(unload_mode); 585 586 mdb_nv_rewind(&mdb.m_disasms); 587 while ((v = mdb_nv_advance(&mdb.m_disasms)) != NULL) 588 mdb_dis_destroy(mdb_nv_get_cookie(v)); 589 590 mdb_callb_remove_all(); 591 592 if (mdb.m_defdisasm != NULL) 593 strfree(mdb.m_defdisasm); 594 595 if (mdb.m_target != NULL) 596 (void) mdb_tgt_destroy(mdb.m_target); 597 598 if (mdb.m_prsym != NULL) 599 mdb_gelf_symtab_destroy(mdb.m_prsym); 600 601 for (dcp = &mdb_dcmd_builtins[0]; dcp->dc_name != NULL; dcp++) 602 (void) mdb_module_remove_dcmd(&mdb.m_rmod, dcp->dc_name); 603 604 mdb_nv_destroy(&mdb.m_nv); 605 mdb_nv_destroy(&mdb.m_walkers); 606 mdb_nv_destroy(&mdb.m_dcmds); 607 mdb_nv_destroy(&mdb.m_modules); 608 mdb_nv_destroy(&mdb.m_disasms); 609 610 mdb_free(mdb.m_ipathstr, MAXPATHLEN); 611 mdb_free(mdb.m_lpathstr, MAXPATHLEN); 612 613 if (mdb.m_ipath != NULL) 614 mdb_path_free(mdb.m_ipath, mdb.m_ipathlen); 615 616 if (mdb.m_lpath != NULL) 617 mdb_path_free(mdb.m_lpath, mdb.m_lpathlen); 618 619 if (mdb.m_in != NULL) 620 mdb_iob_destroy(mdb.m_in); 621 622 mdb_iob_destroy(mdb.m_out); 623 mdb.m_out = NULL; 624 mdb_iob_destroy(mdb.m_err); 625 mdb.m_err = NULL; 626 627 if (mdb.m_log != NULL) 628 mdb_io_rele(mdb.m_log); 629 630 mdb_lex_state_destroy(&frame0); 631 } 632 633 /* 634 * The real main loop of the debugger: create a new execution frame on the 635 * debugger stack, and while we have input available, call into the parser. 636 */ 637 int 638 mdb_run(void) 639 { 640 volatile int err; 641 mdb_frame_t f; 642 643 mdb_intr_disable(); 644 mdb_frame_push(&f); 645 646 /* 647 * This is a fresh mdb context, so ignore any pipe command we may have 648 * inherited from the previous frame. 649 */ 650 f.f_pcmd = NULL; 651 652 if ((err = setjmp(f.f_pcb)) != 0) { 653 int pop = (mdb.m_in != NULL && 654 (mdb_iob_isapipe(mdb.m_in) || mdb_iob_isastr(mdb.m_in))); 655 int fromcmd = (f.f_cp != NULL); 656 657 mdb_dprintf(MDB_DBG_DSTK, "frame <%u> caught event %s\n", 658 f.f_id, mdb_err2str(err)); 659 660 /* 661 * If a syntax error or other failure has occurred, pop all 662 * input buffers pushed by commands executed in this frame. 663 */ 664 while (mdb_iob_stack_size(&f.f_istk) != 0) { 665 if (mdb.m_in != NULL) 666 mdb_iob_destroy(mdb.m_in); 667 mdb.m_in = mdb_iob_stack_pop(&f.f_istk); 668 yylineno = mdb_iob_lineno(mdb.m_in); 669 } 670 671 /* 672 * Reset standard output and the current frame to a known, 673 * clean state, so we can continue execution. 674 */ 675 mdb_iob_margin(mdb.m_out, MDB_IOB_DEFMARGIN); 676 mdb_iob_clrflags(mdb.m_out, MDB_IOB_INDENT); 677 mdb_iob_discard(mdb.m_out); 678 mdb_frame_reset(&f); 679 680 /* 681 * If there was an error writing to output, display a warning 682 * message if this is the topmost frame. 683 */ 684 if (err == MDB_ERR_OUTPUT && mdb.m_depth == 1 && errno != EPIPE) 685 mdb_warn("write failed"); 686 687 /* 688 * If an interrupt or quit signal is reported, we may have been 689 * in the middle of typing or processing the command line: 690 * print a newline and discard everything in the parser's iob. 691 * Note that we do this after m_out has been reset, otherwise 692 * we could trigger a pipe context switch or cause a write 693 * to a broken pipe (in the case of a shell command) when 694 * writing the newline. 695 */ 696 if (err == MDB_ERR_SIGINT || err == MDB_ERR_QUIT) { 697 mdb_iob_nl(mdb.m_out); 698 yydiscard(); 699 } 700 701 /* 702 * If we quit or abort using the output pager, reset the 703 * line count on standard output back to zero. 704 */ 705 if (err == MDB_ERR_PAGER || MDB_ERR_IS_FATAL(err)) 706 mdb_iob_clearlines(mdb.m_out); 707 708 /* 709 * If the user requested the debugger quit or abort back to 710 * the top, or if standard input is a pipe or mdb_eval("..."), 711 * then propagate the error up the debugger stack. 712 */ 713 if (MDB_ERR_IS_FATAL(err) || pop != 0 || 714 (err == MDB_ERR_PAGER && mdb.m_fmark != &f) || 715 (err == MDB_ERR_NOMEM && !fromcmd)) { 716 mdb_frame_pop(&f, err); 717 return (err); 718 } 719 720 /* 721 * If we've returned here from a context where signals were 722 * blocked (e.g. a signal handler), we can now unblock them. 723 */ 724 if (err == MDB_ERR_SIGINT) 725 (void) mdb_signal_unblock(SIGINT); 726 } else 727 mdb_intr_enable(); 728 729 for (;;) { 730 while (mdb.m_in != NULL && (mdb_iob_getflags(mdb.m_in) & 731 (MDB_IOB_ERR | MDB_IOB_EOF)) == 0) { 732 if (mdb.m_depth == 1 && 733 mdb_iob_stack_size(&f.f_istk) == 0) { 734 mdb_iob_clearlines(mdb.m_out); 735 mdb_tgt_periodic(mdb.m_target); 736 } 737 738 (void) yyparse(); 739 } 740 741 if (mdb.m_in != NULL) { 742 if (mdb_iob_err(mdb.m_in)) { 743 warn("error reading input stream %s\n", 744 mdb_iob_name(mdb.m_in)); 745 } 746 mdb_iob_destroy(mdb.m_in); 747 mdb.m_in = NULL; 748 } 749 750 if (mdb_iob_stack_size(&f.f_istk) == 0) 751 break; /* return when we're out of input */ 752 753 mdb.m_in = mdb_iob_stack_pop(&f.f_istk); 754 yylineno = mdb_iob_lineno(mdb.m_in); 755 } 756 757 mdb_frame_pop(&f, 0); 758 759 /* 760 * The value of '.' is a per-frame attribute, to preserve it properly 761 * when switching frames. But in the case of calling mdb_run() 762 * explicitly (such as through mdb_eval), we want to propagate the value 763 * of '.' to the parent. 764 */ 765 mdb_nv_set_value(mdb.m_dot, f.f_dot); 766 767 return (0); 768 } 769 770 /* 771 * The read-side of the pipe executes this service routine. We simply call 772 * mdb_run to create a new frame on the execution stack and run the MDB parser, 773 * and then propagate any error code back to the previous frame. 774 */ 775 static int 776 runsvc(void) 777 { 778 int err = mdb_run(); 779 780 if (err != 0) { 781 mdb_dprintf(MDB_DBG_DSTK, "forwarding error %s from pipeline\n", 782 mdb_err2str(err)); 783 longjmp(mdb.m_frame->f_pcb, err); 784 } 785 786 return (err); 787 } 788 789 /* 790 * Read-side pipe service routine: if we longjmp here, just return to the read 791 * routine because now we have more data to consume. Otherwise: 792 * (1) if ctx_data is non-NULL, longjmp to the write-side to produce more data; 793 * (2) if wriob is NULL, there is no writer but this is the first read, so we 794 * can just execute mdb_run() to completion on the current stack; 795 * (3) if (1) and (2) are false, then there is a writer and this is the first 796 * read, so create a co-routine context to execute mdb_run(). 797 */ 798 /*ARGSUSED*/ 799 static void 800 rdsvc(mdb_iob_t *rdiob, mdb_iob_t *wriob, mdb_iob_ctx_t *ctx) 801 { 802 if (setjmp(ctx->ctx_rpcb) == 0) { 803 /* 804 * Save the current standard input into the pipe context, and 805 * reset m_in to point to the pipe. We will restore it on 806 * the way back in wrsvc() below. 807 */ 808 ctx->ctx_iob = mdb.m_in; 809 mdb.m_in = rdiob; 810 811 ctx->ctx_rptr = mdb.m_frame; 812 if (ctx->ctx_wptr != NULL) 813 mdb_frame_switch(ctx->ctx_wptr); 814 815 if (ctx->ctx_data != NULL) 816 longjmp(ctx->ctx_wpcb, 1); 817 else if (wriob == NULL) 818 (void) runsvc(); 819 else if ((ctx->ctx_data = mdb_context_create(runsvc)) != NULL) 820 mdb_context_switch(ctx->ctx_data); 821 else 822 mdb_warn("failed to create pipe context"); 823 } 824 } 825 826 /* 827 * Write-side pipe service routine: if we longjmp here, just return to the 828 * write routine because now we have free space in the pipe buffer for writing; 829 * otherwise longjmp to the read-side to consume data and create space for us. 830 */ 831 /*ARGSUSED*/ 832 static void 833 wrsvc(mdb_iob_t *rdiob, mdb_iob_t *wriob, mdb_iob_ctx_t *ctx) 834 { 835 if (setjmp(ctx->ctx_wpcb) == 0) { 836 ctx->ctx_wptr = mdb.m_frame; 837 if (ctx->ctx_rptr != NULL) 838 mdb_frame_switch(ctx->ctx_rptr); 839 840 mdb.m_in = ctx->ctx_iob; 841 longjmp(ctx->ctx_rpcb, 1); 842 } 843 } 844 845 /* 846 * Call the current frame's mdb command. This entry point is used by the 847 * MDB parser to actually execute a command once it has successfully parsed 848 * a line of input. The command is waiting for us in the current frame. 849 * We loop through each command on the list, executing its dcmd with the 850 * appropriate argument. If the command has a successor, we know it had 851 * a | operator after it, and so we need to create a pipe and replace 852 * stdout with the pipe's output buffer. 853 */ 854 int 855 mdb_call(uintmax_t addr, uintmax_t count, uint_t flags) 856 { 857 mdb_frame_t *fp = mdb.m_frame; 858 mdb_cmd_t *cp, *ncp; 859 mdb_iob_t *iobs[2]; 860 int status, err = 0; 861 jmp_buf pcb; 862 863 if (mdb_iob_isapipe(mdb.m_in)) 864 yyerror("syntax error"); 865 866 mdb_intr_disable(); 867 fp->f_cp = mdb_list_next(&fp->f_cmds); 868 869 if (flags & DCMD_LOOP) 870 flags |= DCMD_LOOPFIRST; /* set LOOPFIRST if this is a loop */ 871 872 for (cp = mdb_list_next(&fp->f_cmds); cp; cp = mdb_list_next(cp)) { 873 if (mdb_list_next(cp) != NULL) { 874 mdb_iob_pipe(iobs, rdsvc, wrsvc); 875 876 mdb_iob_stack_push(&fp->f_istk, mdb.m_in, yylineno); 877 mdb.m_in = iobs[MDB_IOB_RDIOB]; 878 879 mdb_iob_stack_push(&fp->f_ostk, mdb.m_out, 0); 880 mdb.m_out = iobs[MDB_IOB_WRIOB]; 881 882 ncp = mdb_list_next(cp); 883 mdb_vcb_inherit(cp, ncp); 884 885 bcopy(fp->f_pcb, pcb, sizeof (jmp_buf)); 886 ASSERT(fp->f_pcmd == NULL); 887 fp->f_pcmd = ncp; 888 889 if ((err = setjmp(fp->f_pcb)) == 0) { 890 status = mdb_call_idcmd(cp->c_dcmd, addr, count, 891 flags | DCMD_PIPE_OUT, &cp->c_argv, 892 &cp->c_addrv, cp->c_vcbs); 893 894 ASSERT(mdb.m_in == iobs[MDB_IOB_RDIOB]); 895 ASSERT(mdb.m_out == iobs[MDB_IOB_WRIOB]); 896 } else { 897 mdb_dprintf(MDB_DBG_DSTK, "frame <%u> caught " 898 "error %s from pipeline\n", fp->f_id, 899 mdb_err2str(err)); 900 } 901 902 if (err != 0 || DCMD_ABORTED(status)) { 903 mdb_iob_setflags(mdb.m_in, MDB_IOB_ERR); 904 mdb_iob_setflags(mdb.m_out, MDB_IOB_ERR); 905 } else { 906 mdb_iob_flush(mdb.m_out); 907 (void) mdb_iob_ctl(mdb.m_out, I_FLUSH, 908 (void *)FLUSHW); 909 } 910 911 mdb_iob_destroy(mdb.m_out); 912 mdb.m_out = mdb_iob_stack_pop(&fp->f_ostk); 913 914 if (mdb.m_in != NULL) 915 mdb_iob_destroy(mdb.m_in); 916 917 mdb.m_in = mdb_iob_stack_pop(&fp->f_istk); 918 yylineno = mdb_iob_lineno(mdb.m_in); 919 920 fp->f_pcmd = NULL; 921 bcopy(pcb, fp->f_pcb, sizeof (jmp_buf)); 922 923 if (MDB_ERR_IS_FATAL(err)) 924 longjmp(fp->f_pcb, err); 925 926 if (err != 0 || DCMD_ABORTED(status) || 927 mdb_addrvec_length(&ncp->c_addrv) == 0) 928 break; 929 930 addr = mdb_nv_get_value(mdb.m_dot); 931 count = 1; 932 flags = 0; 933 934 } else { 935 mdb_intr_enable(); 936 (void) mdb_call_idcmd(cp->c_dcmd, addr, count, flags, 937 &cp->c_argv, &cp->c_addrv, cp->c_vcbs); 938 mdb_intr_disable(); 939 } 940 941 fp->f_cp = mdb_list_next(cp); 942 mdb_cmd_reset(cp); 943 } 944 945 /* 946 * If our last-command list is non-empty, destroy it. Then copy the 947 * current frame's cmd list to the m_lastc list and reset the frame. 948 */ 949 while ((cp = mdb_list_next(&mdb.m_lastc)) != NULL) { 950 mdb_list_delete(&mdb.m_lastc, cp); 951 mdb_cmd_destroy(cp); 952 } 953 954 mdb_list_move(&fp->f_cmds, &mdb.m_lastc); 955 mdb_frame_reset(fp); 956 mdb_intr_enable(); 957 return (err == 0); 958 } 959 960 uintmax_t 961 mdb_dot_incr(const char *op) 962 { 963 uintmax_t odot, ndot; 964 965 odot = mdb_nv_get_value(mdb.m_dot); 966 ndot = odot + mdb.m_incr; 967 968 if ((odot ^ ndot) & 0x8000000000000000ull) 969 yyerror("'%s' would cause '.' to overflow\n", op); 970 971 return (ndot); 972 } 973 974 uintmax_t 975 mdb_dot_decr(const char *op) 976 { 977 uintmax_t odot, ndot; 978 979 odot = mdb_nv_get_value(mdb.m_dot); 980 ndot = odot - mdb.m_incr; 981 982 if (ndot > odot) 983 yyerror("'%s' would cause '.' to underflow\n", op); 984 985 return (ndot); 986 } 987 988 mdb_iwalker_t * 989 mdb_walker_lookup(const char *s) 990 { 991 const char *p = strchr(s, '`'); 992 mdb_var_t *v; 993 994 if (p != NULL) { 995 size_t nbytes = MIN((size_t)(p - s), MDB_NV_NAMELEN - 1); 996 char mname[MDB_NV_NAMELEN]; 997 mdb_module_t *mod; 998 999 (void) strncpy(mname, s, nbytes); 1000 mname[nbytes] = '\0'; 1001 1002 if ((v = mdb_nv_lookup(&mdb.m_modules, mname)) == NULL) { 1003 (void) set_errno(EMDB_NOMOD); 1004 return (NULL); 1005 } 1006 1007 mod = mdb_nv_get_cookie(v); 1008 1009 if ((v = mdb_nv_lookup(&mod->mod_walkers, ++p)) != NULL) 1010 return (mdb_nv_get_cookie(v)); 1011 1012 } else if ((v = mdb_nv_lookup(&mdb.m_walkers, s)) != NULL) 1013 return (mdb_nv_get_cookie(mdb_nv_get_cookie(v))); 1014 1015 (void) set_errno(EMDB_NOWALK); 1016 return (NULL); 1017 } 1018 1019 mdb_idcmd_t * 1020 mdb_dcmd_lookup(const char *s) 1021 { 1022 const char *p = strchr(s, '`'); 1023 mdb_var_t *v; 1024 1025 if (p != NULL) { 1026 size_t nbytes = MIN((size_t)(p - s), MDB_NV_NAMELEN - 1); 1027 char mname[MDB_NV_NAMELEN]; 1028 mdb_module_t *mod; 1029 1030 (void) strncpy(mname, s, nbytes); 1031 mname[nbytes] = '\0'; 1032 1033 if ((v = mdb_nv_lookup(&mdb.m_modules, mname)) == NULL) { 1034 (void) set_errno(EMDB_NOMOD); 1035 return (NULL); 1036 } 1037 1038 mod = mdb_nv_get_cookie(v); 1039 1040 if ((v = mdb_nv_lookup(&mod->mod_dcmds, ++p)) != NULL) 1041 return (mdb_nv_get_cookie(v)); 1042 1043 } else if ((v = mdb_nv_lookup(&mdb.m_dcmds, s)) != NULL) 1044 return (mdb_nv_get_cookie(mdb_nv_get_cookie(v))); 1045 1046 (void) set_errno(EMDB_NODCMD); 1047 return (NULL); 1048 } 1049 1050 void 1051 mdb_dcmd_usage(const mdb_idcmd_t *idcp, mdb_iob_t *iob) 1052 { 1053 const char *prefix = "", *usage = ""; 1054 char name0 = idcp->idc_name[0]; 1055 1056 if (idcp->idc_usage != NULL) { 1057 if (idcp->idc_usage[0] == ':') { 1058 if (name0 != ':' && name0 != '$') 1059 prefix = "address::"; 1060 else 1061 prefix = "address"; 1062 usage = &idcp->idc_usage[1]; 1063 1064 } else 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 1072 usage = idcp->idc_usage; 1073 } 1074 1075 mdb_iob_printf(iob, "Usage: %s%s %s\n", prefix, idcp->idc_name, usage); 1076 1077 if (idcp->idc_help != NULL) { 1078 mdb_iob_printf(iob, "%s: try '::help %s' for more " 1079 "information\n", mdb.m_pname, idcp->idc_name); 1080 } 1081 } 1082 1083 static mdb_idcmd_t * 1084 dcmd_ndef(const mdb_idcmd_t *idcp) 1085 { 1086 mdb_var_t *v = mdb_nv_get_ndef(idcp->idc_var); 1087 1088 if (v != NULL) 1089 return (mdb_nv_get_cookie(mdb_nv_get_cookie(v))); 1090 1091 return (NULL); 1092 } 1093 1094 static int 1095 dcmd_invoke(mdb_idcmd_t *idcp, uintptr_t addr, uint_t flags, 1096 int argc, const mdb_arg_t *argv, const mdb_vcb_t *vcbs) 1097 { 1098 int status; 1099 1100 mdb_dprintf(MDB_DBG_DCMD, "dcmd %s`%s dot = %lr incr = %llr\n", 1101 idcp->idc_modp->mod_name, idcp->idc_name, addr, mdb.m_incr); 1102 1103 if ((status = idcp->idc_funcp(addr, flags, argc, argv)) == DCMD_USAGE) { 1104 mdb_dcmd_usage(idcp, mdb.m_err); 1105 goto done; 1106 } 1107 1108 while (status == DCMD_NEXT && (idcp = dcmd_ndef(idcp)) != NULL) 1109 status = idcp->idc_funcp(addr, flags, argc, argv); 1110 1111 if (status == DCMD_USAGE) 1112 mdb_dcmd_usage(idcp, mdb.m_err); 1113 1114 if (status == DCMD_NEXT) 1115 status = DCMD_OK; 1116 done: 1117 /* 1118 * If standard output is a pipe and there are vcbs active, we need to 1119 * flush standard out and the write-side of the pipe. The reasons for 1120 * this are explained in more detail in mdb_vcb.c. 1121 */ 1122 if ((flags & DCMD_PIPE_OUT) && (vcbs != NULL)) { 1123 mdb_iob_flush(mdb.m_out); 1124 (void) mdb_iob_ctl(mdb.m_out, I_FLUSH, (void *)FLUSHW); 1125 } 1126 1127 return (status); 1128 } 1129 1130 /* 1131 * Call an internal dcmd directly: this code is used by module API functions 1132 * that need to execute dcmds, and by mdb_call() above. 1133 */ 1134 int 1135 mdb_call_idcmd(mdb_idcmd_t *idcp, uintmax_t addr, uintmax_t count, 1136 uint_t flags, mdb_argvec_t *avp, mdb_addrvec_t *adp, mdb_vcb_t *vcbs) 1137 { 1138 int is_exec = (strcmp(idcp->idc_name, "$<") == 0); 1139 mdb_arg_t *argv; 1140 int argc; 1141 uintmax_t i; 1142 int status; 1143 1144 /* 1145 * Update the values of dot and the most recent address and count 1146 * to the values of our input parameters. 1147 */ 1148 mdb_nv_set_value(mdb.m_dot, addr); 1149 mdb.m_raddr = addr; 1150 mdb.m_dcount = count; 1151 1152 /* 1153 * Here the adb(1) man page lies: '9' is only set to count 1154 * when the command is $<, not when it's $<<. 1155 */ 1156 if (is_exec) 1157 mdb_nv_set_value(mdb.m_rcount, count); 1158 1159 /* 1160 * We can now return if the repeat count is zero. 1161 */ 1162 if (count == 0) 1163 return (DCMD_OK); 1164 1165 /* 1166 * To guard against bad dcmds, we avoid passing the actual argv that 1167 * we will use to free argument strings directly to the dcmd. Instead, 1168 * we pass a copy that will be garbage collected automatically. 1169 */ 1170 argc = avp->a_nelems; 1171 argv = mdb_alloc(sizeof (mdb_arg_t) * argc, UM_SLEEP | UM_GC); 1172 bcopy(avp->a_data, argv, sizeof (mdb_arg_t) * argc); 1173 1174 if (mdb_addrvec_length(adp) != 0) { 1175 flags |= DCMD_PIPE | DCMD_LOOP | DCMD_LOOPFIRST | DCMD_ADDRSPEC; 1176 addr = mdb_addrvec_shift(adp); 1177 mdb_nv_set_value(mdb.m_dot, addr); 1178 mdb_vcb_propagate(vcbs); 1179 count = 1; 1180 } 1181 1182 status = dcmd_invoke(idcp, addr, flags, argc, argv, vcbs); 1183 if (DCMD_ABORTED(status)) 1184 goto done; 1185 1186 /* 1187 * If the command is $< and we're not receiving input from a pipe, we 1188 * ignore the repeat count and just return since the macro file is now 1189 * pushed on to the input stack. 1190 */ 1191 if (is_exec && mdb_addrvec_length(adp) == 0) 1192 goto done; 1193 1194 /* 1195 * If we're going to loop, we've already executed the dcmd once, 1196 * so clear the LOOPFIRST flag before proceeding. 1197 */ 1198 if (flags & DCMD_LOOP) 1199 flags &= ~DCMD_LOOPFIRST; 1200 1201 for (i = 1; i < count; i++) { 1202 addr = mdb_dot_incr(","); 1203 mdb_nv_set_value(mdb.m_dot, addr); 1204 status = dcmd_invoke(idcp, addr, flags, argc, argv, vcbs); 1205 if (DCMD_ABORTED(status)) 1206 goto done; 1207 } 1208 1209 while (mdb_addrvec_length(adp) != 0) { 1210 addr = mdb_addrvec_shift(adp); 1211 mdb_nv_set_value(mdb.m_dot, addr); 1212 mdb_vcb_propagate(vcbs); 1213 status = dcmd_invoke(idcp, addr, flags, argc, argv, vcbs); 1214 if (DCMD_ABORTED(status)) 1215 goto done; 1216 } 1217 done: 1218 mdb_iob_nlflush(mdb.m_out); 1219 return (status); 1220 } 1221 1222 void 1223 mdb_intr_enable(void) 1224 { 1225 ASSERT(mdb.m_intr >= 1); 1226 if (mdb.m_intr == 1 && mdb.m_pend != 0) { 1227 (void) mdb_signal_block(SIGINT); 1228 mdb.m_intr = mdb.m_pend = 0; 1229 mdb_dprintf(MDB_DBG_DSTK, "delivering pending INT\n"); 1230 longjmp(mdb.m_frame->f_pcb, MDB_ERR_SIGINT); 1231 } else 1232 mdb.m_intr--; 1233 } 1234 1235 void 1236 mdb_intr_disable(void) 1237 { 1238 mdb.m_intr++; 1239 ASSERT(mdb.m_intr >= 1); 1240 } 1241 1242 /* 1243 * Create an encoded string representing the internal user-modifiable 1244 * configuration of the debugger and return a pointer to it. The string can be 1245 * used to initialize another instance of the debugger with the same 1246 * configuration as this one. 1247 */ 1248 char * 1249 mdb_get_config(void) 1250 { 1251 size_t r, n = 0; 1252 char *s = NULL; 1253 1254 while ((r = mdb_snprintf(s, n, 1255 "%x;%x;%x;%x;%x;%x;%lx;%x;%x;%s;%s;%s;%s;%s", 1256 mdb.m_tgtflags, mdb.m_flags, mdb.m_debug, mdb.m_radix, mdb.m_nargs, 1257 mdb.m_histlen, (ulong_t)mdb.m_symdist, mdb.m_execmode, 1258 mdb.m_forkmode, mdb.m_root, mdb.m_termtype, mdb.m_ipathstr, 1259 mdb.m_lpathstr, mdb.m_prompt)) > n) { 1260 1261 mdb_free(s, n); 1262 n = r + 1; 1263 s = mdb_alloc(r + 1, UM_SLEEP); 1264 } 1265 1266 return (s); 1267 } 1268 1269 /* 1270 * Decode a configuration string created with mdb_get_config() and reset the 1271 * appropriate parts of the global mdb_t accordingly. 1272 */ 1273 void 1274 mdb_set_config(const char *s) 1275 { 1276 const char *p; 1277 size_t len; 1278 1279 if ((p = strchr(s, ';')) != NULL) { 1280 mdb.m_tgtflags = strntoul(s, (size_t)(p - s), 16); 1281 s = p + 1; 1282 } 1283 1284 if ((p = strchr(s, ';')) != NULL) { 1285 mdb.m_flags = strntoul(s, (size_t)(p - s), 16); 1286 mdb.m_flags &= ~(MDB_FL_LOG | MDB_FL_LATEST); 1287 s = p + 1; 1288 } 1289 1290 if ((p = strchr(s, ';')) != NULL) { 1291 mdb.m_debug = strntoul(s, (size_t)(p - s), 16); 1292 s = p + 1; 1293 } 1294 1295 if ((p = strchr(s, ';')) != NULL) { 1296 mdb.m_radix = (int)strntoul(s, (size_t)(p - s), 16); 1297 if (mdb.m_radix < 2 || mdb.m_radix > 16) 1298 mdb.m_radix = MDB_DEF_RADIX; 1299 s = p + 1; 1300 } 1301 1302 if ((p = strchr(s, ';')) != NULL) { 1303 mdb.m_nargs = (int)strntoul(s, (size_t)(p - s), 16); 1304 mdb.m_nargs = MAX(mdb.m_nargs, 0); 1305 s = p + 1; 1306 } 1307 1308 if ((p = strchr(s, ';')) != NULL) { 1309 mdb.m_histlen = (int)strntoul(s, (size_t)(p - s), 16); 1310 mdb.m_histlen = MAX(mdb.m_histlen, 1); 1311 s = p + 1; 1312 } 1313 1314 if ((p = strchr(s, ';')) != NULL) { 1315 mdb.m_symdist = strntoul(s, (size_t)(p - s), 16); 1316 s = p + 1; 1317 } 1318 1319 if ((p = strchr(s, ';')) != NULL) { 1320 mdb.m_execmode = (uchar_t)strntoul(s, (size_t)(p - s), 16); 1321 if (mdb.m_execmode > MDB_EM_FOLLOW) 1322 mdb.m_execmode = MDB_EM_ASK; 1323 s = p + 1; 1324 } 1325 1326 if ((p = strchr(s, ';')) != NULL) { 1327 mdb.m_forkmode = (uchar_t)strntoul(s, (size_t)(p - s), 16); 1328 if (mdb.m_forkmode > MDB_FM_CHILD) 1329 mdb.m_forkmode = MDB_FM_ASK; 1330 s = p + 1; 1331 } 1332 1333 if ((p = strchr(s, ';')) != NULL) { 1334 mdb.m_root = strndup(s, (size_t)(p - s)); 1335 s = p + 1; 1336 } 1337 1338 if ((p = strchr(s, ';')) != NULL) { 1339 mdb.m_termtype = strndup(s, (size_t)(p - s)); 1340 s = p + 1; 1341 } 1342 1343 if ((p = strchr(s, ';')) != NULL) { 1344 size_t len = MIN(sizeof (mdb.m_ipathstr) - 1, p - s); 1345 strncpy(mdb.m_ipathstr, s, len); 1346 mdb.m_ipathstr[len] = '\0'; 1347 s = p + 1; 1348 } 1349 1350 if ((p = strchr(s, ';')) != NULL) { 1351 size_t len = MIN(sizeof (mdb.m_lpathstr) - 1, p - s); 1352 strncpy(mdb.m_lpathstr, s, len); 1353 mdb.m_lpathstr[len] = '\0'; 1354 s = p + 1; 1355 } 1356 1357 p = s + strlen(s); 1358 len = MIN(MDB_PROMPTLEN, (size_t)(p - s)); 1359 (void) strncpy(mdb.m_prompt, s, len); 1360 mdb.m_prompt[len] = '\0'; 1361 mdb.m_promptlen = len; 1362 } 1363 1364 mdb_module_t * 1365 mdb_get_module(void) 1366 { 1367 if (mdb.m_lmod) 1368 return (mdb.m_lmod); 1369 1370 if (mdb.m_frame && mdb.m_frame->f_cp && mdb.m_frame->f_cp->c_dcmd) 1371 return (mdb.m_frame->f_cp->c_dcmd->idc_modp); 1372 1373 return (NULL); 1374 } 1375