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 = { 459 .disc_set = psym_disc_set, 460 .disc_get = psym_disc_get 461 }; 462 static const mdb_nv_disc_t roff_disc = { 463 .disc_set = roff_disc_set, 464 .disc_get = roff_disc_get 465 }; 466 static const mdb_nv_disc_t thr_disc = { .disc_get = thr_disc_get }; 467 468 static char rootdir[MAXPATHLEN]; 469 470 const mdb_dcmd_t *dcp; 471 const mdb_walker_t *wcp; 472 int i; 473 474 bzero(&mdb, sizeof (mdb_t)); 475 476 mdb.m_flags = MDB_FL_PSYM | MDB_FL_PAGER | MDB_FL_BPTNOSYMSTOP | 477 MDB_FL_READBACK; 478 mdb.m_radix = MDB_DEF_RADIX; 479 mdb.m_nargs = MDB_DEF_NARGS; 480 mdb.m_histlen = MDB_DEF_HISTLEN; 481 mdb.m_armemlim = MDB_DEF_ARRMEM; 482 mdb.m_arstrlim = MDB_DEF_ARRSTR; 483 484 mdb.m_pname = strbasename(arg0); 485 if (strcmp(mdb.m_pname, "adb") == 0) { 486 mdb.m_flags |= MDB_FL_NOMODS | MDB_FL_ADB | MDB_FL_REPLAST; 487 mdb.m_flags &= ~MDB_FL_PAGER; 488 } 489 490 mdb.m_ipathstr = mdb_zalloc(MAXPATHLEN, UM_SLEEP); 491 mdb.m_lpathstr = mdb_zalloc(MAXPATHLEN, UM_SLEEP); 492 493 (void) strncpy(rootdir, execname, sizeof (rootdir)); 494 rootdir[sizeof (rootdir) - 1] = '\0'; 495 (void) strdirname(rootdir); 496 497 if (strcmp(strbasename(rootdir), "sparcv9") == 0 || 498 strcmp(strbasename(rootdir), "sparcv7") == 0 || 499 strcmp(strbasename(rootdir), "amd64") == 0 || 500 strcmp(strbasename(rootdir), "i86") == 0) 501 (void) strdirname(rootdir); 502 503 if (strcmp(strbasename(rootdir), "bin") == 0) { 504 (void) strdirname(rootdir); 505 if (strcmp(strbasename(rootdir), "usr") == 0) 506 (void) strdirname(rootdir); 507 } else 508 (void) strcpy(rootdir, "/"); 509 510 mdb.m_root = rootdir; 511 512 mdb.m_rminfo.mi_dvers = MDB_API_VERSION; 513 mdb.m_rminfo.mi_dcmds = mdb_dcmd_builtins; 514 mdb.m_rminfo.mi_walkers = mdb_walker_builtins; 515 516 (void) mdb_nv_create(&mdb.m_rmod.mod_walkers, UM_SLEEP); 517 (void) mdb_nv_create(&mdb.m_rmod.mod_dcmds, UM_SLEEP); 518 519 mdb.m_rmod.mod_name = mdb.m_pname; 520 mdb.m_rmod.mod_info = &mdb.m_rminfo; 521 522 (void) mdb_nv_create(&mdb.m_disasms, UM_SLEEP); 523 (void) mdb_nv_create(&mdb.m_modules, UM_SLEEP); 524 (void) mdb_nv_create(&mdb.m_dcmds, UM_SLEEP); 525 (void) mdb_nv_create(&mdb.m_walkers, UM_SLEEP); 526 (void) mdb_nv_create(&mdb.m_nv, UM_SLEEP); 527 528 mdb.m_dot = mdb_nv_insert(&mdb.m_nv, ".", NULL, 0, MDB_NV_PERSIST); 529 mdb.m_rvalue = mdb_nv_insert(&mdb.m_nv, "0", NULL, 0, MDB_NV_PERSIST); 530 531 mdb.m_roffset = 532 mdb_nv_insert(&mdb.m_nv, "1", &roff_disc, 0, MDB_NV_PERSIST); 533 534 mdb.m_proffset = mdb_nv_insert(&mdb.m_nv, "2", NULL, 0, MDB_NV_PERSIST); 535 mdb.m_rcount = mdb_nv_insert(&mdb.m_nv, "9", NULL, 0, MDB_NV_PERSIST); 536 537 (void) mdb_nv_insert(&mdb.m_nv, "b", NULL, 0, MDB_NV_PERSIST); 538 (void) mdb_nv_insert(&mdb.m_nv, "d", NULL, 0, MDB_NV_PERSIST); 539 (void) mdb_nv_insert(&mdb.m_nv, "e", NULL, 0, MDB_NV_PERSIST); 540 (void) mdb_nv_insert(&mdb.m_nv, "m", NULL, 0, MDB_NV_PERSIST); 541 (void) mdb_nv_insert(&mdb.m_nv, "t", NULL, 0, MDB_NV_PERSIST); 542 (void) mdb_nv_insert(&mdb.m_nv, "_", &psym_disc, 0, MDB_NV_PERSIST); 543 (void) mdb_nv_insert(&mdb.m_nv, "hits", NULL, 0, MDB_NV_PERSIST); 544 545 (void) mdb_nv_insert(&mdb.m_nv, "thread", &thr_disc, 0, 546 MDB_NV_PERSIST | MDB_NV_RDONLY); 547 548 mdb.m_prsym = mdb_gelf_symtab_create_mutable(); 549 550 (void) mdb_nv_insert(&mdb.m_modules, mdb.m_pname, NULL, 551 (uintptr_t)&mdb.m_rmod, MDB_NV_RDONLY); 552 553 for (dcp = &mdb_dcmd_builtins[0]; dcp->dc_name != NULL; dcp++) 554 (void) mdb_module_add_dcmd(&mdb.m_rmod, dcp, 0); 555 556 for (wcp = &mdb_walker_builtins[0]; wcp->walk_name != NULL; wcp++) 557 (void) mdb_module_add_walker(&mdb.m_rmod, wcp, 0); 558 559 for (i = 0; mdb_dis_builtins[i] != NULL; i++) 560 (void) mdb_dis_create(mdb_dis_builtins[i]); 561 562 mdb_macalias_create(); 563 564 mdb_create_builtin_tgts(); 565 566 (void) mdb_callb_add(NULL, MDB_CALLB_PROMPT, (mdb_callb_f)prompt_update, 567 NULL); 568 569 /* 570 * The call to ctf_create that this does can in fact fail, but that's 571 * okay. All of the ctf functions that might use the synthetic types 572 * make sure that this is safe. 573 */ 574 (void) mdb_ctf_synthetics_init(); 575 576 #ifdef _KMDB 577 (void) mdb_nv_create(&mdb.m_dmodctl, UM_SLEEP); 578 #endif 579 mdb_lex_state_create(&frame0); 580 581 mdb_list_append(&mdb.m_flist, &frame0); 582 mdb.m_frame = &frame0; 583 } 584 585 void 586 mdb_destroy(void) 587 { 588 const mdb_dcmd_t *dcp; 589 mdb_var_t *v; 590 int unload_mode = MDB_MOD_SILENT; 591 592 #ifdef _KMDB 593 unload_mode |= MDB_MOD_DEFER; 594 #endif 595 596 mdb_intr_disable(); 597 598 mdb_ctf_synthetics_fini(); 599 600 mdb_macalias_destroy(); 601 602 /* 603 * Some targets use modules during ->t_destroy, so do it first. 604 */ 605 if (mdb.m_target != NULL) 606 (void) mdb_tgt_destroy(mdb.m_target); 607 608 /* 609 * Unload modules _before_ destroying the disassemblers since a 610 * module that installs a disassembler should try to clean up after 611 * itself. 612 */ 613 mdb_module_unload_all(unload_mode); 614 615 mdb_nv_rewind(&mdb.m_disasms); 616 while ((v = mdb_nv_advance(&mdb.m_disasms)) != NULL) 617 mdb_dis_destroy(mdb_nv_get_cookie(v)); 618 619 mdb_callb_remove_all(); 620 621 if (mdb.m_defdisasm != NULL) 622 strfree(mdb.m_defdisasm); 623 624 if (mdb.m_prsym != NULL) 625 mdb_gelf_symtab_destroy(mdb.m_prsym); 626 627 for (dcp = &mdb_dcmd_builtins[0]; dcp->dc_name != NULL; dcp++) 628 (void) mdb_module_remove_dcmd(&mdb.m_rmod, dcp->dc_name); 629 630 mdb_nv_destroy(&mdb.m_nv); 631 mdb_nv_destroy(&mdb.m_walkers); 632 mdb_nv_destroy(&mdb.m_dcmds); 633 mdb_nv_destroy(&mdb.m_modules); 634 mdb_nv_destroy(&mdb.m_disasms); 635 636 mdb_free(mdb.m_ipathstr, MAXPATHLEN); 637 mdb_free(mdb.m_lpathstr, MAXPATHLEN); 638 639 if (mdb.m_ipath != NULL) 640 mdb_path_free(mdb.m_ipath, mdb.m_ipathlen); 641 642 if (mdb.m_lpath != NULL) 643 mdb_path_free(mdb.m_lpath, mdb.m_lpathlen); 644 645 if (mdb.m_in != NULL) 646 mdb_iob_destroy(mdb.m_in); 647 648 mdb_iob_destroy(mdb.m_out); 649 mdb.m_out = NULL; 650 mdb_iob_destroy(mdb.m_err); 651 mdb.m_err = NULL; 652 653 if (mdb.m_log != NULL) 654 mdb_io_rele(mdb.m_log); 655 656 mdb_lex_state_destroy(&frame0); 657 } 658 659 /* 660 * The real main loop of the debugger: create a new execution frame on the 661 * debugger stack, and while we have input available, call into the parser. 662 */ 663 int 664 mdb_run(void) 665 { 666 volatile int err; 667 mdb_frame_t f; 668 669 mdb_intr_disable(); 670 mdb_frame_push(&f); 671 672 /* 673 * This is a fresh mdb context, so ignore any pipe command we may have 674 * inherited from the previous frame. 675 */ 676 f.f_pcmd = NULL; 677 678 if ((err = setjmp(f.f_pcb)) != 0) { 679 int pop = (mdb.m_in != NULL && 680 (mdb_iob_isapipe(mdb.m_in) || mdb_iob_isastr(mdb.m_in))); 681 int fromcmd = (f.f_cp != NULL); 682 683 mdb_dprintf(MDB_DBG_DSTK, "frame <%u> caught event %s\n", 684 f.f_id, mdb_err2str(err)); 685 686 /* 687 * If a syntax error or other failure has occurred, pop all 688 * input buffers pushed by commands executed in this frame. 689 */ 690 while (mdb_iob_stack_size(&f.f_istk) != 0) { 691 if (mdb.m_in != NULL) 692 mdb_iob_destroy(mdb.m_in); 693 mdb.m_in = mdb_iob_stack_pop(&f.f_istk); 694 yylineno = mdb_iob_lineno(mdb.m_in); 695 } 696 697 /* 698 * Reset standard output and the current frame to a known, 699 * clean state, so we can continue execution. 700 */ 701 mdb_iob_margin(mdb.m_out, MDB_IOB_DEFMARGIN); 702 mdb_iob_clrflags(mdb.m_out, MDB_IOB_INDENT); 703 mdb_iob_discard(mdb.m_out); 704 mdb_frame_reset(&f); 705 706 /* 707 * If there was an error writing to output, display a warning 708 * message if this is the topmost frame. 709 */ 710 if (err == MDB_ERR_OUTPUT && mdb.m_depth == 1 && errno != EPIPE) 711 mdb_warn("write failed"); 712 713 /* 714 * If an interrupt or quit signal is reported, we may have been 715 * in the middle of typing or processing the command line: 716 * print a newline and discard everything in the parser's iob. 717 * Note that we do this after m_out has been reset, otherwise 718 * we could trigger a pipe context switch or cause a write 719 * to a broken pipe (in the case of a shell command) when 720 * writing the newline. 721 */ 722 if (err == MDB_ERR_SIGINT || err == MDB_ERR_QUIT) { 723 mdb_iob_nl(mdb.m_out); 724 yydiscard(); 725 } 726 727 /* 728 * If we quit or abort using the output pager, reset the 729 * line count on standard output back to zero. 730 */ 731 if (err == MDB_ERR_PAGER || MDB_ERR_IS_FATAL(err)) 732 mdb_iob_clearlines(mdb.m_out); 733 734 /* 735 * If the user requested the debugger quit or abort back to 736 * the top, or if standard input is a pipe or mdb_eval("..."), 737 * then propagate the error up the debugger stack. 738 */ 739 if (MDB_ERR_IS_FATAL(err) || pop != 0 || 740 (err == MDB_ERR_PAGER && mdb.m_fmark != &f) || 741 (err == MDB_ERR_NOMEM && !fromcmd)) { 742 mdb_frame_pop(&f, err); 743 return (err); 744 } 745 746 /* 747 * If we've returned here from a context where signals were 748 * blocked (e.g. a signal handler), we can now unblock them. 749 */ 750 if (err == MDB_ERR_SIGINT) 751 (void) mdb_signal_unblock(SIGINT); 752 } else 753 mdb_intr_enable(); 754 755 for (;;) { 756 while (mdb.m_in != NULL && (mdb_iob_getflags(mdb.m_in) & 757 (MDB_IOB_ERR | MDB_IOB_EOF)) == 0) { 758 if (mdb.m_depth == 1 && 759 mdb_iob_stack_size(&f.f_istk) == 0) { 760 mdb_iob_clearlines(mdb.m_out); 761 mdb_tgt_periodic(mdb.m_target); 762 } 763 764 (void) yyparse(); 765 } 766 767 if (mdb.m_in != NULL) { 768 if (mdb_iob_err(mdb.m_in)) { 769 warn("error reading input stream %s\n", 770 mdb_iob_name(mdb.m_in)); 771 } 772 mdb_iob_destroy(mdb.m_in); 773 mdb.m_in = NULL; 774 } 775 776 if (mdb_iob_stack_size(&f.f_istk) == 0) 777 break; /* return when we're out of input */ 778 779 mdb.m_in = mdb_iob_stack_pop(&f.f_istk); 780 yylineno = mdb_iob_lineno(mdb.m_in); 781 } 782 783 mdb_frame_pop(&f, 0); 784 785 /* 786 * The value of '.' is a per-frame attribute, to preserve it properly 787 * when switching frames. But in the case of calling mdb_run() 788 * explicitly (such as through mdb_eval), we want to propagate the value 789 * of '.' to the parent. 790 */ 791 mdb_nv_set_value(mdb.m_dot, f.f_dot); 792 793 return (0); 794 } 795 796 /* 797 * The read-side of the pipe executes this service routine. We simply call 798 * mdb_run to create a new frame on the execution stack and run the MDB parser, 799 * and then propagate any error code back to the previous frame. 800 */ 801 static int 802 runsvc(void) 803 { 804 int err = mdb_run(); 805 806 if (err != 0) { 807 mdb_dprintf(MDB_DBG_DSTK, "forwarding error %s from pipeline\n", 808 mdb_err2str(err)); 809 longjmp(mdb.m_frame->f_pcb, err); 810 } 811 812 return (err); 813 } 814 815 /* 816 * Read-side pipe service routine: if we longjmp here, just return to the read 817 * routine because now we have more data to consume. Otherwise: 818 * (1) if ctx_data is non-NULL, longjmp to the write-side to produce more data; 819 * (2) if wriob is NULL, there is no writer but this is the first read, so we 820 * can just execute mdb_run() to completion on the current stack; 821 * (3) if (1) and (2) are false, then there is a writer and this is the first 822 * read, so create a co-routine context to execute mdb_run(). 823 */ 824 /*ARGSUSED*/ 825 static void 826 rdsvc(mdb_iob_t *rdiob, mdb_iob_t *wriob, mdb_iob_ctx_t *ctx) 827 { 828 if (setjmp(ctx->ctx_rpcb) == 0) { 829 /* 830 * Save the current standard input into the pipe context, and 831 * reset m_in to point to the pipe. We will restore it on 832 * the way back in wrsvc() below. 833 */ 834 ctx->ctx_iob = mdb.m_in; 835 mdb.m_in = rdiob; 836 837 ctx->ctx_rptr = mdb.m_frame; 838 if (ctx->ctx_wptr != NULL) 839 mdb_frame_switch(ctx->ctx_wptr); 840 841 if (ctx->ctx_data != NULL) 842 longjmp(ctx->ctx_wpcb, 1); 843 else if (wriob == NULL) 844 (void) runsvc(); 845 else if ((ctx->ctx_data = mdb_context_create(runsvc)) != NULL) 846 mdb_context_switch(ctx->ctx_data); 847 else 848 mdb_warn("failed to create pipe context"); 849 } 850 } 851 852 /* 853 * Write-side pipe service routine: if we longjmp here, just return to the 854 * write routine because now we have free space in the pipe buffer for writing; 855 * otherwise longjmp to the read-side to consume data and create space for us. 856 */ 857 /*ARGSUSED*/ 858 static void 859 wrsvc(mdb_iob_t *rdiob, mdb_iob_t *wriob, mdb_iob_ctx_t *ctx) 860 { 861 if (setjmp(ctx->ctx_wpcb) == 0) { 862 ctx->ctx_wptr = mdb.m_frame; 863 if (ctx->ctx_rptr != NULL) 864 mdb_frame_switch(ctx->ctx_rptr); 865 866 mdb.m_in = ctx->ctx_iob; 867 longjmp(ctx->ctx_rpcb, 1); 868 } 869 } 870 871 /* 872 * Call the current frame's mdb command. This entry point is used by the 873 * MDB parser to actually execute a command once it has successfully parsed 874 * a line of input. The command is waiting for us in the current frame. 875 * We loop through each command on the list, executing its dcmd with the 876 * appropriate argument. If the command has a successor, we know it had 877 * a | operator after it, and so we need to create a pipe and replace 878 * stdout with the pipe's output buffer. 879 */ 880 int 881 mdb_call(uintmax_t addr, uintmax_t count, uint_t flags) 882 { 883 mdb_frame_t *fp = mdb.m_frame; 884 mdb_cmd_t *cp, *ncp; 885 mdb_iob_t *iobs[2]; 886 int status, err = 0; 887 jmp_buf pcb; 888 889 if (mdb_iob_isapipe(mdb.m_in)) 890 yyerror("syntax error"); 891 892 mdb_intr_disable(); 893 fp->f_cp = mdb_list_next(&fp->f_cmds); 894 895 if (flags & DCMD_LOOP) 896 flags |= DCMD_LOOPFIRST; /* set LOOPFIRST if this is a loop */ 897 898 for (cp = mdb_list_next(&fp->f_cmds); cp; cp = mdb_list_next(cp)) { 899 if (mdb_list_next(cp) != NULL) { 900 mdb_iob_pipe(iobs, rdsvc, wrsvc); 901 902 mdb_iob_stack_push(&fp->f_istk, mdb.m_in, yylineno); 903 mdb.m_in = iobs[MDB_IOB_RDIOB]; 904 905 mdb_iob_stack_push(&fp->f_ostk, mdb.m_out, 0); 906 mdb.m_out = iobs[MDB_IOB_WRIOB]; 907 908 ncp = mdb_list_next(cp); 909 mdb_vcb_inherit(cp, ncp); 910 911 bcopy(fp->f_pcb, pcb, sizeof (jmp_buf)); 912 ASSERT(fp->f_pcmd == NULL); 913 fp->f_pcmd = ncp; 914 915 mdb_frame_set_pipe(fp); 916 917 if ((err = setjmp(fp->f_pcb)) == 0) { 918 status = mdb_call_idcmd(cp->c_dcmd, addr, count, 919 flags | DCMD_PIPE_OUT, &cp->c_argv, 920 &cp->c_addrv, cp->c_vcbs); 921 922 mdb.m_lastret = status; 923 924 ASSERT(mdb.m_in == iobs[MDB_IOB_RDIOB]); 925 ASSERT(mdb.m_out == iobs[MDB_IOB_WRIOB]); 926 } else { 927 mdb_dprintf(MDB_DBG_DSTK, "frame <%u> caught " 928 "error %s from pipeline\n", fp->f_id, 929 mdb_err2str(err)); 930 } 931 932 if (err != 0 || DCMD_ABORTED(status)) { 933 mdb_iob_setflags(mdb.m_in, MDB_IOB_ERR); 934 mdb_iob_setflags(mdb.m_out, MDB_IOB_ERR); 935 } else { 936 mdb_iob_flush(mdb.m_out); 937 (void) mdb_iob_ctl(mdb.m_out, I_FLUSH, 938 (void *)FLUSHW); 939 } 940 941 mdb_frame_clear_pipe(fp); 942 943 mdb_iob_destroy(mdb.m_out); 944 mdb.m_out = mdb_iob_stack_pop(&fp->f_ostk); 945 946 if (mdb.m_in != NULL) 947 mdb_iob_destroy(mdb.m_in); 948 949 mdb.m_in = mdb_iob_stack_pop(&fp->f_istk); 950 yylineno = mdb_iob_lineno(mdb.m_in); 951 952 fp->f_pcmd = NULL; 953 bcopy(pcb, fp->f_pcb, sizeof (jmp_buf)); 954 955 if (MDB_ERR_IS_FATAL(err)) 956 longjmp(fp->f_pcb, err); 957 958 if (err != 0 || DCMD_ABORTED(status) || 959 mdb_addrvec_length(&ncp->c_addrv) == 0) 960 break; 961 962 addr = mdb_nv_get_value(mdb.m_dot); 963 count = 1; 964 flags = 0; 965 966 } else { 967 mdb_intr_enable(); 968 mdb.m_lastret = mdb_call_idcmd(cp->c_dcmd, addr, count, 969 flags, &cp->c_argv, &cp->c_addrv, cp->c_vcbs); 970 mdb_intr_disable(); 971 } 972 973 fp->f_cp = mdb_list_next(cp); 974 mdb_cmd_reset(cp); 975 } 976 977 /* 978 * If our last-command list is non-empty, destroy it. Then copy the 979 * current frame's cmd list to the m_lastc list and reset the frame. 980 */ 981 while ((cp = mdb_list_next(&mdb.m_lastc)) != NULL) { 982 mdb_list_delete(&mdb.m_lastc, cp); 983 mdb_cmd_destroy(cp); 984 } 985 986 mdb_list_move(&fp->f_cmds, &mdb.m_lastc); 987 mdb_frame_reset(fp); 988 mdb_intr_enable(); 989 return (err == 0); 990 } 991 992 uintmax_t 993 mdb_dot_incr(const char *op) 994 { 995 uintmax_t odot, ndot; 996 997 odot = mdb_nv_get_value(mdb.m_dot); 998 ndot = odot + mdb.m_incr; 999 1000 if ((odot ^ ndot) & 0x8000000000000000ull) 1001 yyerror("'%s' would cause '.' to overflow\n", op); 1002 1003 return (ndot); 1004 } 1005 1006 uintmax_t 1007 mdb_dot_decr(const char *op) 1008 { 1009 uintmax_t odot, ndot; 1010 1011 odot = mdb_nv_get_value(mdb.m_dot); 1012 ndot = odot - mdb.m_incr; 1013 1014 if (ndot > odot) 1015 yyerror("'%s' would cause '.' to underflow\n", op); 1016 1017 return (ndot); 1018 } 1019 1020 mdb_iwalker_t * 1021 mdb_walker_lookup(const char *s) 1022 { 1023 const char *p = strchr(s, '`'); 1024 mdb_var_t *v; 1025 1026 if (p != NULL) { 1027 size_t nbytes = MIN((size_t)(p - s), MDB_NV_NAMELEN - 1); 1028 char mname[MDB_NV_NAMELEN]; 1029 mdb_module_t *mod; 1030 1031 (void) strncpy(mname, s, nbytes); 1032 mname[nbytes] = '\0'; 1033 1034 if ((v = mdb_nv_lookup(&mdb.m_modules, mname)) == NULL) { 1035 (void) set_errno(EMDB_NOMOD); 1036 return (NULL); 1037 } 1038 1039 mod = mdb_nv_get_cookie(v); 1040 1041 if ((v = mdb_nv_lookup(&mod->mod_walkers, ++p)) != NULL) 1042 return (mdb_nv_get_cookie(v)); 1043 1044 } else if ((v = mdb_nv_lookup(&mdb.m_walkers, s)) != NULL) 1045 return (mdb_nv_get_cookie(mdb_nv_get_cookie(v))); 1046 1047 (void) set_errno(EMDB_NOWALK); 1048 return (NULL); 1049 } 1050 1051 mdb_idcmd_t * 1052 mdb_dcmd_lookup(const char *s) 1053 { 1054 const char *p = strchr(s, '`'); 1055 mdb_var_t *v; 1056 1057 if (p != NULL) { 1058 size_t nbytes = MIN((size_t)(p - s), MDB_NV_NAMELEN - 1); 1059 char mname[MDB_NV_NAMELEN]; 1060 mdb_module_t *mod; 1061 1062 (void) strncpy(mname, s, nbytes); 1063 mname[nbytes] = '\0'; 1064 1065 if ((v = mdb_nv_lookup(&mdb.m_modules, mname)) == NULL) { 1066 (void) set_errno(EMDB_NOMOD); 1067 return (NULL); 1068 } 1069 1070 mod = mdb_nv_get_cookie(v); 1071 1072 if ((v = mdb_nv_lookup(&mod->mod_dcmds, ++p)) != NULL) 1073 return (mdb_nv_get_cookie(v)); 1074 1075 } else if ((v = mdb_nv_lookup(&mdb.m_dcmds, s)) != NULL) 1076 return (mdb_nv_get_cookie(mdb_nv_get_cookie(v))); 1077 1078 (void) set_errno(EMDB_NODCMD); 1079 return (NULL); 1080 } 1081 1082 void 1083 mdb_dcmd_usage(const mdb_idcmd_t *idcp, mdb_iob_t *iob) 1084 { 1085 const char *prefix = "", *usage = ""; 1086 char name0 = idcp->idc_name[0]; 1087 1088 if (idcp->idc_usage != NULL) { 1089 if (idcp->idc_usage[0] == ':') { 1090 if (name0 != ':' && name0 != '$') 1091 prefix = "address::"; 1092 else 1093 prefix = "address"; 1094 usage = &idcp->idc_usage[1]; 1095 1096 } else if (idcp->idc_usage[0] == '?') { 1097 if (name0 != ':' && name0 != '$') 1098 prefix = "[address]::"; 1099 else 1100 prefix = "[address]"; 1101 usage = &idcp->idc_usage[1]; 1102 1103 } else 1104 usage = idcp->idc_usage; 1105 } 1106 1107 mdb_iob_printf(iob, "Usage: %s%s %s\n", prefix, idcp->idc_name, usage); 1108 1109 if (idcp->idc_help != NULL) { 1110 mdb_iob_printf(iob, "%s: try '::help %s' for more " 1111 "information\n", mdb.m_pname, idcp->idc_name); 1112 } 1113 } 1114 1115 static mdb_idcmd_t * 1116 dcmd_ndef(const mdb_idcmd_t *idcp) 1117 { 1118 mdb_var_t *v = mdb_nv_get_ndef(idcp->idc_var); 1119 1120 if (v != NULL) 1121 return (mdb_nv_get_cookie(mdb_nv_get_cookie(v))); 1122 1123 return (NULL); 1124 } 1125 1126 static int 1127 dcmd_invoke(mdb_idcmd_t *idcp, uintptr_t addr, uint_t flags, 1128 int argc, const mdb_arg_t *argv, const mdb_vcb_t *vcbs) 1129 { 1130 int status; 1131 1132 mdb_dprintf(MDB_DBG_DCMD, "dcmd %s`%s dot = %lr incr = %llr\n", 1133 idcp->idc_modp->mod_name, idcp->idc_name, addr, mdb.m_incr); 1134 1135 if ((status = idcp->idc_funcp(addr, flags, argc, argv)) == DCMD_USAGE) { 1136 mdb_dcmd_usage(idcp, mdb.m_err); 1137 goto done; 1138 } 1139 1140 while (status == DCMD_NEXT && (idcp = dcmd_ndef(idcp)) != NULL) 1141 status = idcp->idc_funcp(addr, flags, argc, argv); 1142 1143 if (status == DCMD_USAGE) 1144 mdb_dcmd_usage(idcp, mdb.m_err); 1145 1146 if (status == DCMD_NEXT) 1147 status = DCMD_OK; 1148 done: 1149 /* 1150 * If standard output is a pipe and there are vcbs active, we need to 1151 * flush standard out and the write-side of the pipe. The reasons for 1152 * this are explained in more detail in mdb_vcb.c. 1153 */ 1154 if ((flags & DCMD_PIPE_OUT) && (vcbs != NULL)) { 1155 mdb_iob_flush(mdb.m_out); 1156 (void) mdb_iob_ctl(mdb.m_out, I_FLUSH, (void *)FLUSHW); 1157 } 1158 1159 return (status); 1160 } 1161 1162 void 1163 mdb_call_tab(mdb_idcmd_t *idcp, mdb_tab_cookie_t *mcp, uint_t flags, 1164 uintmax_t argc, mdb_arg_t *argv) 1165 { 1166 if (idcp->idc_tabp == NULL) 1167 return; 1168 1169 (void) idcp->idc_tabp(mcp, flags, argc, argv); 1170 } 1171 1172 /* 1173 * Call an internal dcmd directly: this code is used by module API functions 1174 * that need to execute dcmds, and by mdb_call() above. 1175 */ 1176 int 1177 mdb_call_idcmd(mdb_idcmd_t *idcp, uintmax_t addr, uintmax_t count, 1178 uint_t flags, mdb_argvec_t *avp, mdb_addrvec_t *adp, mdb_vcb_t *vcbs) 1179 { 1180 int is_exec = (strcmp(idcp->idc_name, "$<") == 0); 1181 mdb_arg_t *argv; 1182 int argc; 1183 uintmax_t i; 1184 int status; 1185 1186 /* 1187 * Update the values of dot and the most recent address and count 1188 * to the values of our input parameters. 1189 */ 1190 mdb_nv_set_value(mdb.m_dot, addr); 1191 mdb.m_raddr = addr; 1192 mdb.m_dcount = count; 1193 1194 /* 1195 * Here the adb(1) man page lies: '9' is only set to count 1196 * when the command is $<, not when it's $<<. 1197 */ 1198 if (is_exec) 1199 mdb_nv_set_value(mdb.m_rcount, count); 1200 1201 /* 1202 * We can now return if the repeat count is zero. 1203 */ 1204 if (count == 0) 1205 return (DCMD_OK); 1206 1207 /* 1208 * To guard against bad dcmds, we avoid passing the actual argv that 1209 * we will use to free argument strings directly to the dcmd. Instead, 1210 * we pass a copy that will be garbage collected automatically. 1211 */ 1212 argc = avp->a_nelems; 1213 argv = mdb_alloc(sizeof (mdb_arg_t) * argc, UM_SLEEP | UM_GC); 1214 bcopy(avp->a_data, argv, sizeof (mdb_arg_t) * argc); 1215 1216 if (mdb_addrvec_length(adp) != 0) { 1217 flags |= DCMD_PIPE | DCMD_LOOP | DCMD_LOOPFIRST | DCMD_ADDRSPEC; 1218 addr = mdb_addrvec_shift(adp); 1219 mdb_nv_set_value(mdb.m_dot, addr); 1220 mdb_vcb_propagate(vcbs); 1221 count = 1; 1222 } 1223 1224 status = dcmd_invoke(idcp, addr, flags, argc, argv, vcbs); 1225 if (DCMD_ABORTED(status)) 1226 goto done; 1227 1228 /* 1229 * If the command is $< and we're not receiving input from a pipe, we 1230 * ignore the repeat count and just return since the macro file is now 1231 * pushed on to the input stack. 1232 */ 1233 if (is_exec && mdb_addrvec_length(adp) == 0) 1234 goto done; 1235 1236 /* 1237 * If we're going to loop, we've already executed the dcmd once, 1238 * so clear the LOOPFIRST flag before proceeding. 1239 */ 1240 if (flags & DCMD_LOOP) 1241 flags &= ~DCMD_LOOPFIRST; 1242 1243 for (i = 1; i < count; i++) { 1244 addr = mdb_dot_incr(","); 1245 mdb_nv_set_value(mdb.m_dot, addr); 1246 status = dcmd_invoke(idcp, addr, flags, argc, argv, vcbs); 1247 if (DCMD_ABORTED(status)) 1248 goto done; 1249 } 1250 1251 while (mdb_addrvec_length(adp) != 0) { 1252 addr = mdb_addrvec_shift(adp); 1253 mdb_nv_set_value(mdb.m_dot, addr); 1254 mdb_vcb_propagate(vcbs); 1255 status = dcmd_invoke(idcp, addr, flags, argc, argv, vcbs); 1256 if (DCMD_ABORTED(status)) 1257 goto done; 1258 } 1259 done: 1260 mdb_iob_nlflush(mdb.m_out); 1261 return (status); 1262 } 1263 1264 void 1265 mdb_intr_enable(void) 1266 { 1267 ASSERT(mdb.m_intr >= 1); 1268 if (mdb.m_intr == 1 && mdb.m_pend != 0) { 1269 (void) mdb_signal_block(SIGINT); 1270 mdb.m_intr = mdb.m_pend = 0; 1271 mdb_dprintf(MDB_DBG_DSTK, "delivering pending INT\n"); 1272 longjmp(mdb.m_frame->f_pcb, MDB_ERR_SIGINT); 1273 } else 1274 mdb.m_intr--; 1275 } 1276 1277 void 1278 mdb_intr_disable(void) 1279 { 1280 mdb.m_intr++; 1281 ASSERT(mdb.m_intr >= 1); 1282 } 1283 1284 /* 1285 * Create an encoded string representing the internal user-modifiable 1286 * configuration of the debugger and return a pointer to it. The string can be 1287 * used to initialize another instance of the debugger with the same 1288 * configuration as this one. 1289 */ 1290 char * 1291 mdb_get_config(void) 1292 { 1293 size_t r, n = 0; 1294 char *s = NULL; 1295 1296 while ((r = mdb_snprintf(s, n, 1297 "%x;%x;%x;%x;%x;%x;%lx;%x;%x;%s;%s;%s;%s;%s", 1298 mdb.m_tgtflags, mdb.m_flags, mdb.m_debug, mdb.m_radix, mdb.m_nargs, 1299 mdb.m_histlen, (ulong_t)mdb.m_symdist, mdb.m_execmode, 1300 mdb.m_forkmode, mdb.m_root, mdb.m_termtype, mdb.m_ipathstr, 1301 mdb.m_lpathstr, mdb.m_prompt)) > n) { 1302 1303 mdb_free(s, n); 1304 n = r + 1; 1305 s = mdb_alloc(r + 1, UM_SLEEP); 1306 } 1307 1308 return (s); 1309 } 1310 1311 /* 1312 * Decode a configuration string created with mdb_get_config() and reset the 1313 * appropriate parts of the global mdb_t accordingly. 1314 */ 1315 void 1316 mdb_set_config(const char *s) 1317 { 1318 const char *p; 1319 size_t len; 1320 1321 if ((p = strchr(s, ';')) != NULL) { 1322 mdb.m_tgtflags = strntoul(s, (size_t)(p - s), 16); 1323 s = p + 1; 1324 } 1325 1326 if ((p = strchr(s, ';')) != NULL) { 1327 mdb.m_flags = strntoul(s, (size_t)(p - s), 16); 1328 mdb.m_flags &= ~(MDB_FL_LOG | MDB_FL_LATEST); 1329 s = p + 1; 1330 } 1331 1332 if ((p = strchr(s, ';')) != NULL) { 1333 mdb.m_debug = strntoul(s, (size_t)(p - s), 16); 1334 s = p + 1; 1335 } 1336 1337 if ((p = strchr(s, ';')) != NULL) { 1338 mdb.m_radix = (int)strntoul(s, (size_t)(p - s), 16); 1339 if (mdb.m_radix < 2 || mdb.m_radix > 16) 1340 mdb.m_radix = MDB_DEF_RADIX; 1341 s = p + 1; 1342 } 1343 1344 if ((p = strchr(s, ';')) != NULL) { 1345 mdb.m_nargs = (int)strntoul(s, (size_t)(p - s), 16); 1346 mdb.m_nargs = MAX(mdb.m_nargs, 0); 1347 s = p + 1; 1348 } 1349 1350 if ((p = strchr(s, ';')) != NULL) { 1351 mdb.m_histlen = (int)strntoul(s, (size_t)(p - s), 16); 1352 mdb.m_histlen = MAX(mdb.m_histlen, 1); 1353 s = p + 1; 1354 } 1355 1356 if ((p = strchr(s, ';')) != NULL) { 1357 mdb.m_symdist = strntoul(s, (size_t)(p - s), 16); 1358 s = p + 1; 1359 } 1360 1361 if ((p = strchr(s, ';')) != NULL) { 1362 mdb.m_execmode = (uchar_t)strntoul(s, (size_t)(p - s), 16); 1363 if (mdb.m_execmode > MDB_EM_FOLLOW) 1364 mdb.m_execmode = MDB_EM_ASK; 1365 s = p + 1; 1366 } 1367 1368 if ((p = strchr(s, ';')) != NULL) { 1369 mdb.m_forkmode = (uchar_t)strntoul(s, (size_t)(p - s), 16); 1370 if (mdb.m_forkmode > MDB_FM_CHILD) 1371 mdb.m_forkmode = MDB_FM_ASK; 1372 s = p + 1; 1373 } 1374 1375 if ((p = strchr(s, ';')) != NULL) { 1376 mdb.m_root = strndup(s, (size_t)(p - s)); 1377 s = p + 1; 1378 } 1379 1380 if ((p = strchr(s, ';')) != NULL) { 1381 mdb.m_termtype = strndup(s, (size_t)(p - s)); 1382 s = p + 1; 1383 } 1384 1385 if ((p = strchr(s, ';')) != NULL) { 1386 size_t len = MIN(sizeof (mdb.m_ipathstr) - 1, p - s); 1387 (void) strncpy(mdb.m_ipathstr, s, len); 1388 mdb.m_ipathstr[len] = '\0'; 1389 s = p + 1; 1390 } 1391 1392 if ((p = strchr(s, ';')) != NULL) { 1393 size_t len = MIN(sizeof (mdb.m_lpathstr) - 1, p - s); 1394 (void) strncpy(mdb.m_lpathstr, s, len); 1395 mdb.m_lpathstr[len] = '\0'; 1396 s = p + 1; 1397 } 1398 1399 p = s + strlen(s); 1400 len = MIN(MDB_PROMPTLEN, (size_t)(p - s)); 1401 (void) strncpy(mdb.m_prompt, s, len); 1402 mdb.m_prompt[len] = '\0'; 1403 mdb.m_promptlen = len; 1404 } 1405 1406 mdb_module_t * 1407 mdb_get_module(void) 1408 { 1409 if (mdb.m_lmod) 1410 return (mdb.m_lmod); 1411 1412 if (mdb.m_frame == NULL) 1413 return (NULL); 1414 1415 if (mdb.m_frame->f_wcbs && mdb.m_frame->f_wcbs->w_walker && 1416 mdb.m_frame->f_wcbs->w_walker->iwlk_modp && 1417 !mdb.m_frame->f_cbactive) 1418 return (mdb.m_frame->f_wcbs->w_walker->iwlk_modp); 1419 1420 if (mdb.m_frame->f_cp && mdb.m_frame->f_cp->c_dcmd) 1421 return (mdb.m_frame->f_cp->c_dcmd->idc_modp); 1422 1423 return (NULL); 1424 } 1425