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