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