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