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 /*
  23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*
  28  * Copyright (c) 2012 by Delphix. All rights reserved.
  29  * Copyright (c) 2013 Joyent, Inc. All rights reserved.
  30  */
  31 
  32 #include <sys/elf.h>
  33 #include <sys/elf_SPARC.h>
  34 
  35 #include <libproc.h>
  36 #include <stdlib.h>
  37 #include <string.h>
  38 #include <fcntl.h>
  39 #include <errno.h>
  40 #include <alloca.h>
  41 #include <libctf.h>
  42 #include <ctype.h>
  43 
  44 #include <mdb/mdb_string.h>
  45 #include <mdb/mdb_argvec.h>
  46 #include <mdb/mdb_nv.h>
  47 #include <mdb/mdb_fmt.h>
  48 #include <mdb/mdb_target.h>
  49 #include <mdb/mdb_err.h>
  50 #include <mdb/mdb_debug.h>
  51 #include <mdb/mdb_conf.h>
  52 #include <mdb/mdb_module.h>
  53 #include <mdb/mdb_modapi.h>
  54 #include <mdb/mdb_stdlib.h>
  55 #include <mdb/mdb_lex.h>
  56 #include <mdb/mdb_io_impl.h>
  57 #include <mdb/mdb_help.h>
  58 #include <mdb/mdb_disasm.h>
  59 #include <mdb/mdb_frame.h>
  60 #include <mdb/mdb_evset.h>
  61 #include <mdb/mdb_print.h>
  62 #include <mdb/mdb_nm.h>
  63 #include <mdb/mdb_set.h>
  64 #include <mdb/mdb_demangle.h>
  65 #include <mdb/mdb_ctf.h>
  66 #include <mdb/mdb_whatis.h>
  67 #include <mdb/mdb_whatis_impl.h>
  68 #include <mdb/mdb_macalias.h>
  69 #include <mdb/mdb_tab.h>
  70 #include <mdb/mdb_typedef.h>
  71 #ifdef _KMDB
  72 #include <kmdb/kmdb_kdi.h>
  73 #endif
  74 #include <mdb/mdb.h>
  75 
  76 #ifdef __sparc
  77 #define SETHI_MASK      0xc1c00000
  78 #define SETHI_VALUE     0x01000000
  79 
  80 #define IS_SETHI(machcode)      (((machcode) & SETHI_MASK) == SETHI_VALUE)
  81 
  82 #define OP(machcode)    ((machcode) >> 30)
  83 #define OP3(machcode)   (((machcode) >> 19) & 0x3f)
  84 #define RD(machcode)    (((machcode) >> 25) & 0x1f)
  85 #define RS1(machcode)   (((machcode) >> 14) & 0x1f)
  86 #define I(machcode)     (((machcode) >> 13) & 0x01)
  87 
  88 #define IMM13(machcode) ((machcode) & 0x1fff)
  89 #define IMM22(machcode) ((machcode) & 0x3fffff)
  90 
  91 #define OP_ARITH_MEM_MASK       0x2
  92 #define OP_ARITH                0x2
  93 #define OP_MEM                  0x3
  94 
  95 #define OP3_CC_MASK             0x10
  96 #define OP3_COMPLEX_MASK        0x20
  97 
  98 #define OP3_ADD                 0x00
  99 #define OP3_OR                  0x02
 100 #define OP3_XOR                 0x03
 101 
 102 #ifndef R_O7
 103 #define R_O7    0xf
 104 #endif
 105 #endif /* __sparc */
 106 
 107 static mdb_tgt_addr_t
 108 write_uint8(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t ull, uint_t rdback)
 109 {
 110         uint8_t o, n = (uint8_t)ull;
 111 
 112         if (rdback && mdb_tgt_aread(mdb.m_target, as, &o, sizeof (o),
 113             addr) == -1)
 114                 return (addr);
 115 
 116         if (mdb_tgt_awrite(mdb.m_target, as, &n, sizeof (n), addr) == -1)
 117                 return (addr);
 118 
 119         if (rdback) {
 120                 if (mdb_tgt_aread(mdb.m_target, as, &n, sizeof (n), addr) == -1)
 121                         return (addr);
 122 
 123                 mdb_iob_printf(mdb.m_out, "%-#*lla%16T%-#8x=%8T0x%x\n",
 124                     mdb_iob_getmargin(mdb.m_out), addr, o, n);
 125         }
 126 
 127         return (addr + sizeof (n));
 128 }
 129 
 130 static mdb_tgt_addr_t
 131 write_uint16(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t ull, uint_t rdback)
 132 {
 133         uint16_t o, n = (uint16_t)ull;
 134 
 135         if (rdback && mdb_tgt_aread(mdb.m_target, as, &o, sizeof (o),
 136             addr) == -1)
 137                 return (addr);
 138 
 139         if (mdb_tgt_awrite(mdb.m_target, as, &n, sizeof (n), addr) == -1)
 140                 return (addr);
 141 
 142         if (rdback) {
 143                 if (mdb_tgt_aread(mdb.m_target, as, &n, sizeof (n), addr) == -1)
 144                         return (addr);
 145 
 146                 mdb_iob_printf(mdb.m_out, "%-#*lla%16T%-#8hx=%8T0x%hx\n",
 147                     mdb_iob_getmargin(mdb.m_out), addr, o, n);
 148         }
 149 
 150         return (addr + sizeof (n));
 151 }
 152 
 153 static mdb_tgt_addr_t
 154 write_uint32(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t ull, uint_t rdback)
 155 {
 156         uint32_t o, n = (uint32_t)ull;
 157 
 158         if (rdback && mdb_tgt_aread(mdb.m_target, as, &o, sizeof (o),
 159             addr) == -1)
 160                 return (addr);
 161 
 162         if (mdb_tgt_awrite(mdb.m_target, as, &n, sizeof (n), addr) == -1)
 163                 return (addr);
 164 
 165         if (rdback) {
 166                 if (mdb_tgt_aread(mdb.m_target, as, &n, sizeof (n), addr) == -1)
 167                         return (addr);
 168 
 169                 mdb_iob_printf(mdb.m_out, "%-#*lla%16T%-#16x=%8T0x%x\n",
 170                     mdb_iob_getmargin(mdb.m_out), addr, o, n);
 171         }
 172 
 173         return (addr + sizeof (n));
 174 }
 175 
 176 static mdb_tgt_addr_t
 177 write_uint64(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t n, uint_t rdback)
 178 {
 179         uint64_t o;
 180 
 181         if (rdback && mdb_tgt_aread(mdb.m_target, as, &o, sizeof (o),
 182             addr) == -1)
 183                 return (addr);
 184 
 185         if (mdb_tgt_awrite(mdb.m_target, as, &n, sizeof (n), addr) == -1)
 186                 return (addr);
 187 
 188         if (rdback) {
 189                 if (mdb_tgt_aread(mdb.m_target, as, &n, sizeof (n), addr) == -1)
 190                         return (addr);
 191 
 192                 mdb_iob_printf(mdb.m_out, "%-#*lla%16T%-#24llx=%8T0x%llx\n",
 193                     mdb_iob_getmargin(mdb.m_out), addr, o, n);
 194         }
 195 
 196         return (addr + sizeof (n));
 197 }
 198 
 199 static int
 200 write_arglist(mdb_tgt_as_t as, mdb_tgt_addr_t addr,
 201     int argc, const mdb_arg_t *argv)
 202 {
 203         mdb_tgt_addr_t (*write_value)(mdb_tgt_as_t, mdb_tgt_addr_t,
 204             uint64_t, uint_t);
 205         mdb_tgt_addr_t naddr;
 206         uintmax_t value;
 207         int rdback = mdb.m_flags & MDB_FL_READBACK;
 208         size_t i;
 209 
 210         if (argc == 1) {
 211                 mdb_warn("expected value to write following %c\n",
 212                     argv->a_un.a_char);
 213                 return (DCMD_ERR);
 214         }
 215 
 216         switch (argv->a_un.a_char) {
 217         case 'v':
 218                 write_value = write_uint8;
 219                 break;
 220         case 'w':
 221                 write_value = write_uint16;
 222                 break;
 223         case 'W':
 224                 write_value = write_uint32;
 225                 break;
 226         case 'Z':
 227                 write_value = write_uint64;
 228                 break;
 229         }
 230 
 231         for (argv++, i = 1; i < argc; i++, argv++) {
 232                 if (argv->a_type == MDB_TYPE_CHAR) {
 233                         mdb_warn("expected immediate value instead of '%c'\n",
 234                             argv->a_un.a_char);
 235                         return (DCMD_ERR);
 236                 }
 237 
 238                 if (argv->a_type == MDB_TYPE_STRING) {
 239                         if (mdb_eval(argv->a_un.a_str) == -1) {
 240                                 mdb_warn("failed to write \"%s\"",
 241                                     argv->a_un.a_str);
 242                                 return (DCMD_ERR);
 243                         }
 244                         value = mdb_nv_get_value(mdb.m_dot);
 245                 } else
 246                         value = argv->a_un.a_val;
 247 
 248                 mdb_nv_set_value(mdb.m_dot, addr);
 249 
 250                 if ((naddr = write_value(as, addr, value, rdback)) == addr) {
 251                         mdb_warn("failed to write %llr at address 0x%llx",
 252                             value, addr);
 253                         mdb.m_incr = 0;
 254                         break;
 255                 }
 256 
 257                 mdb.m_incr = naddr - addr;
 258                 addr = naddr;
 259         }
 260 
 261         return (DCMD_OK);
 262 }
 263 
 264 static mdb_tgt_addr_t
 265 match_uint16(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t v64, uint64_t m64)
 266 {
 267         uint16_t x, val = (uint16_t)v64, mask = (uint16_t)m64;
 268 
 269         for (; mdb_tgt_aread(mdb.m_target, as, &x,
 270             sizeof (x), addr) == sizeof (x); addr += sizeof (x)) {
 271 
 272                 if ((x & mask) == val) {
 273                         mdb_iob_printf(mdb.m_out, "%lla\n", addr);
 274                         break;
 275                 }
 276         }
 277         return (addr);
 278 }
 279 
 280 static mdb_tgt_addr_t
 281 match_uint32(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t v64, uint64_t m64)
 282 {
 283         uint32_t x, val = (uint32_t)v64, mask = (uint32_t)m64;
 284 
 285         for (; mdb_tgt_aread(mdb.m_target, as, &x,
 286             sizeof (x), addr) == sizeof (x); addr += sizeof (x)) {
 287 
 288                 if ((x & mask) == val) {
 289                         mdb_iob_printf(mdb.m_out, "%lla\n", addr);
 290                         break;
 291                 }
 292         }
 293         return (addr);
 294 }
 295 
 296 static mdb_tgt_addr_t
 297 match_uint64(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t val, uint64_t mask)
 298 {
 299         uint64_t x;
 300 
 301         for (; mdb_tgt_aread(mdb.m_target, as, &x,
 302             sizeof (x), addr) == sizeof (x); addr += sizeof (x)) {
 303 
 304                 if ((x & mask) == val) {
 305                         mdb_iob_printf(mdb.m_out, "%lla\n", addr);
 306                         break;
 307                 }
 308         }
 309         return (addr);
 310 }
 311 
 312 static int
 313 match_arglist(mdb_tgt_as_t as, uint_t flags, mdb_tgt_addr_t addr,
 314     int argc, const mdb_arg_t *argv)
 315 {
 316         mdb_tgt_addr_t (*match_value)(mdb_tgt_as_t, mdb_tgt_addr_t,
 317             uint64_t, uint64_t);
 318 
 319         uint64_t args[2] = { 0, -1ULL }; /* [ value, mask ] */
 320         size_t i;
 321 
 322         if (argc < 2) {
 323                 mdb_warn("expected value following %c\n", argv->a_un.a_char);
 324                 return (DCMD_ERR);
 325         }
 326 
 327         if (argc > 3) {
 328                 mdb_warn("only value and mask may follow %c\n",
 329                     argv->a_un.a_char);
 330                 return (DCMD_ERR);
 331         }
 332 
 333         switch (argv->a_un.a_char) {
 334         case 'l':
 335                 match_value = match_uint16;
 336                 break;
 337         case 'L':
 338                 match_value = match_uint32;
 339                 break;
 340         case 'M':
 341                 match_value = match_uint64;
 342                 break;
 343         }
 344 
 345         for (argv++, i = 1; i < argc; i++, argv++) {
 346                 if (argv->a_type == MDB_TYPE_CHAR) {
 347                         mdb_warn("expected immediate value instead of '%c'\n",
 348                             argv->a_un.a_char);
 349                         return (DCMD_ERR);
 350                 }
 351 
 352                 if (argv->a_type == MDB_TYPE_STRING) {
 353                         if (mdb_eval(argv->a_un.a_str) == -1) {
 354                                 mdb_warn("failed to evaluate \"%s\"",
 355                                     argv->a_un.a_str);
 356                                 return (DCMD_ERR);
 357                         }
 358                         args[i - 1] = mdb_nv_get_value(mdb.m_dot);
 359                 } else
 360                         args[i - 1] = argv->a_un.a_val;
 361         }
 362 
 363         addr = match_value(as, addr, args[0], args[1]);
 364         mdb_nv_set_value(mdb.m_dot, addr);
 365 
 366         /*
 367          * In adb(1), the match operators ignore any repeat count that has
 368          * been applied to them.  We emulate this undocumented property
 369          * by returning DCMD_ABORT if our input is not a pipeline.
 370          */
 371         return ((flags & DCMD_PIPE) ? DCMD_OK : DCMD_ABORT);
 372 }
 373 
 374 static int
 375 argncmp(int argc, const mdb_arg_t *argv, const char *s)
 376 {
 377         for (; *s != '\0'; s++, argc--, argv++) {
 378                 if (argc == 0 || argv->a_type != MDB_TYPE_CHAR)
 379                         return (FALSE);
 380                 if (argv->a_un.a_char != *s)
 381                         return (FALSE);
 382         }
 383         return (TRUE);
 384 }
 385 
 386 static int
 387 print_arglist(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint_t flags,
 388     int argc, const mdb_arg_t *argv)
 389 {
 390         char buf[MDB_TGT_SYM_NAMLEN];
 391         mdb_tgt_addr_t oaddr = addr;
 392         mdb_tgt_addr_t naddr;
 393         GElf_Sym sym;
 394         size_t i, n;
 395 
 396         if (DCMD_HDRSPEC(flags) && (flags & DCMD_PIPE_OUT) == 0) {
 397                 const char *fmt;
 398                 int is_dis;
 399                 /*
 400                  * This is nasty, but necessary for precise adb compatibility.
 401                  * Detect disassembly format by looking for "ai" or "ia":
 402                  */
 403                 if (argncmp(argc, argv, "ai")) {
 404                         fmt = "%-#*lla\n";
 405                         is_dis = TRUE;
 406                 } else if (argncmp(argc, argv, "ia")) {
 407                         fmt = "%-#*lla";
 408                         is_dis = TRUE;
 409                 } else {
 410                         fmt = "%-#*lla%16T";
 411                         is_dis = FALSE;
 412                 }
 413 
 414                 /*
 415                  * If symbolic decoding is on, disassembly is off, and the
 416                  * address exactly matches a symbol, print the symbol name:
 417                  */
 418                 if ((mdb.m_flags & MDB_FL_PSYM) && !is_dis &&
 419                     (as == MDB_TGT_AS_VIRT || as == MDB_TGT_AS_FILE) &&
 420                     mdb_tgt_lookup_by_addr(mdb.m_target, (uintptr_t)addr,
 421                     MDB_TGT_SYM_EXACT, buf, sizeof (buf), &sym, NULL) == 0)
 422                         mdb_iob_printf(mdb.m_out, "%s:\n", buf);
 423 
 424                 /*
 425                  * If this is a virtual address, cast it so that it reflects
 426                  * only the valid component of the address.
 427                  */
 428                 if (as == MDB_TGT_AS_VIRT)
 429                         addr = (uintptr_t)addr;
 430 
 431                 mdb_iob_printf(mdb.m_out, fmt,
 432                     (uint_t)mdb_iob_getmargin(mdb.m_out), addr);
 433         }
 434 
 435         if (argc == 0) {
 436                 /*
 437                  * Yes, for you trivia buffs: if you use a format verb and give
 438                  * no format string, you get: X^"= "i ... note that in adb the
 439                  * the '=' verb once had 'z' as its default, but then 'z' was
 440                  * deleted (it was once an alias for 'i') and so =\n now calls
 441                  * scanform("z") and produces a 'bad modifier' message.
 442                  */
 443                 static const mdb_arg_t def_argv[] = {
 444                         { MDB_TYPE_CHAR, MDB_INIT_CHAR('X') },
 445                         { MDB_TYPE_CHAR, MDB_INIT_CHAR('^') },
 446                         { MDB_TYPE_STRING, MDB_INIT_STRING("= ") },
 447                         { MDB_TYPE_CHAR, MDB_INIT_CHAR('i') }
 448                 };
 449 
 450                 argc = sizeof (def_argv) / sizeof (mdb_arg_t);
 451                 argv = def_argv;
 452         }
 453 
 454         mdb_iob_setflags(mdb.m_out, MDB_IOB_INDENT);
 455 
 456         for (i = 0, n = 1; i < argc; i++, argv++) {
 457                 switch (argv->a_type) {
 458                 case MDB_TYPE_CHAR:
 459                         naddr = mdb_fmt_print(mdb.m_target, as, addr, n,
 460                             argv->a_un.a_char);
 461                         mdb.m_incr = naddr - addr;
 462                         addr = naddr;
 463                         n = 1;
 464                         break;
 465 
 466                 case MDB_TYPE_IMMEDIATE:
 467                         n = argv->a_un.a_val;
 468                         break;
 469 
 470                 case MDB_TYPE_STRING:
 471                         mdb_iob_puts(mdb.m_out, argv->a_un.a_str);
 472                         n = 1;
 473                         break;
 474                 }
 475         }
 476 
 477         mdb.m_incr = addr - oaddr;
 478         mdb_iob_clrflags(mdb.m_out, MDB_IOB_INDENT);
 479         return (DCMD_OK);
 480 }
 481 
 482 static int
 483 print_common(mdb_tgt_as_t as, uint_t flags, int argc, const mdb_arg_t *argv)
 484 {
 485         mdb_tgt_addr_t addr = mdb_nv_get_value(mdb.m_dot);
 486 
 487         if (argc != 0 && argv->a_type == MDB_TYPE_CHAR) {
 488                 if (strchr("vwWZ", argv->a_un.a_char))
 489                         return (write_arglist(as, addr, argc, argv));
 490                 if (strchr("lLM", argv->a_un.a_char))
 491                         return (match_arglist(as, flags, addr, argc, argv));
 492         }
 493 
 494         return (print_arglist(as, addr, flags, argc, argv));
 495 }
 496 
 497 /*ARGSUSED*/
 498 static int
 499 cmd_print_core(uintptr_t x, uint_t flags, int argc, const mdb_arg_t *argv)
 500 {
 501         return (print_common(MDB_TGT_AS_VIRT, flags, argc, argv));
 502 }
 503 
 504 #ifndef _KMDB
 505 /*ARGSUSED*/
 506 static int
 507 cmd_print_object(uintptr_t x, uint_t flags, int argc, const mdb_arg_t *argv)
 508 {
 509         return (print_common(MDB_TGT_AS_FILE, flags, argc, argv));
 510 }
 511 #endif
 512 
 513 /*ARGSUSED*/
 514 static int
 515 cmd_print_phys(uintptr_t x, uint_t flags, int argc, const mdb_arg_t *argv)
 516 {
 517         return (print_common(MDB_TGT_AS_PHYS, flags, argc, argv));
 518 }
 519 
 520 /*ARGSUSED*/
 521 static int
 522 cmd_print_value(uintptr_t addr, uint_t flags,
 523         int argc, const mdb_arg_t *argv)
 524 {
 525         uintmax_t ndot, dot = mdb_get_dot();
 526         const char *tgt_argv[1];
 527         mdb_tgt_t *t;
 528         size_t i, n;
 529 
 530         if (argc == 0) {
 531                 mdb_warn("expected one or more format characters "
 532                     "following '='\n");
 533                 return (DCMD_ERR);
 534         }
 535 
 536         tgt_argv[0] = (const char *)&dot;
 537         t = mdb_tgt_create(mdb_value_tgt_create, 0, 1, tgt_argv);
 538         mdb_iob_setflags(mdb.m_out, MDB_IOB_INDENT);
 539 
 540         for (i = 0, n = 1; i < argc; i++, argv++) {
 541                 switch (argv->a_type) {
 542                 case MDB_TYPE_CHAR:
 543                         ndot = mdb_fmt_print(t, MDB_TGT_AS_VIRT,
 544                             dot, n, argv->a_un.a_char);
 545                         if (argv->a_un.a_char == '+' ||
 546                             argv->a_un.a_char == '-')
 547                                 dot = ndot;
 548                         n = 1;
 549                         break;
 550 
 551                 case MDB_TYPE_IMMEDIATE:
 552                         n = argv->a_un.a_val;
 553                         break;
 554 
 555                 case MDB_TYPE_STRING:
 556                         mdb_iob_puts(mdb.m_out, argv->a_un.a_str);
 557                         n = 1;
 558                         break;
 559                 }
 560         }
 561 
 562         mdb_iob_clrflags(mdb.m_out, MDB_IOB_INDENT);
 563         mdb_nv_set_value(mdb.m_dot, dot);
 564         mdb.m_incr = 0;
 565 
 566         mdb_tgt_destroy(t);
 567         return (DCMD_OK);
 568 }
 569 
 570 /*ARGSUSED*/
 571 static int
 572 cmd_assign_variable(uintptr_t addr, uint_t flags,
 573     int argc, const mdb_arg_t *argv)
 574 {
 575         uintmax_t dot = mdb_nv_get_value(mdb.m_dot);
 576         const char *p;
 577         mdb_var_t *v;
 578 
 579         if (argc == 2) {
 580                 if (argv->a_type != MDB_TYPE_CHAR) {
 581                         mdb_warn("improper arguments following '>' operator\n");
 582                         return (DCMD_ERR);
 583                 }
 584 
 585                 switch (argv->a_un.a_char) {
 586                 case 'c':
 587                         addr = *((uchar_t *)&addr);
 588                         break;
 589                 case 's':
 590                         addr = *((ushort_t *)&addr);
 591                         break;
 592                 case 'i':
 593                         addr = *((uint_t *)&addr);
 594                         break;
 595                 case 'l':
 596                         addr = *((ulong_t *)&addr);
 597                         break;
 598                 default:
 599                         mdb_warn("%c is not a valid // modifier\n",
 600                             argv->a_un.a_char);
 601                         return (DCMD_ERR);
 602                 }
 603 
 604                 dot = addr;
 605                 argv++;
 606                 argc--;
 607         }
 608 
 609         if (argc != 1 || argv->a_type != MDB_TYPE_STRING) {
 610                 mdb_warn("expected single variable name following '>'\n");
 611                 return (DCMD_ERR);
 612         }
 613 
 614         if (strlen(argv->a_un.a_str) >= (size_t)MDB_NV_NAMELEN) {
 615                 mdb_warn("variable names may not exceed %d characters\n",
 616                     MDB_NV_NAMELEN - 1);
 617                 return (DCMD_ERR);
 618         }
 619 
 620         if ((p = strbadid(argv->a_un.a_str)) != NULL) {
 621                 mdb_warn("'%c' may not be used in a variable name\n", *p);
 622                 return (DCMD_ERR);
 623         }
 624 
 625         if ((v = mdb_nv_lookup(&mdb.m_nv, argv->a_un.a_str)) == NULL)
 626                 (void) mdb_nv_insert(&mdb.m_nv, argv->a_un.a_str, NULL, dot, 0);
 627         else
 628                 mdb_nv_set_value(v, dot);
 629 
 630         mdb.m_incr = 0;
 631         return (DCMD_OK);
 632 }
 633 
 634 static int
 635 print_soutype(const char *sou, uintptr_t addr, uint_t flags)
 636 {
 637         static const char *prefixes[] = { "struct ", "union " };
 638         size_t namesz = 7 + strlen(sou) + 1;
 639         char *name = mdb_alloc(namesz, UM_SLEEP | UM_GC);
 640         mdb_ctf_id_t id;
 641         int i;
 642 
 643         for (i = 0; i < 2; i++) {
 644                 (void) mdb_snprintf(name, namesz, "%s%s", prefixes[i], sou);
 645 
 646                 if (mdb_ctf_lookup_by_name(name, &id) == 0) {
 647                         mdb_arg_t v;
 648                         int rv;
 649 
 650                         v.a_type = MDB_TYPE_STRING;
 651                         v.a_un.a_str = name;
 652 
 653                         rv = mdb_call_dcmd("print", addr, flags, 1, &v);
 654                         return (rv);
 655                 }
 656         }
 657 
 658         return (DCMD_ERR);
 659 }
 660 
 661 static int
 662 print_type(const char *name, uintptr_t addr, uint_t flags)
 663 {
 664         mdb_ctf_id_t id;
 665         char *sname;
 666         size_t snamesz;
 667         int rv;
 668 
 669         if (!(flags & DCMD_ADDRSPEC)) {
 670                 addr = mdb_get_dot();
 671                 flags |= DCMD_ADDRSPEC;
 672         }
 673 
 674         if ((rv = print_soutype(name, addr, flags)) != DCMD_ERR)
 675                 return (rv);
 676 
 677         snamesz = strlen(name) + 3;
 678         sname = mdb_zalloc(snamesz, UM_SLEEP | UM_GC);
 679         (void) mdb_snprintf(sname, snamesz, "%s_t", name);
 680 
 681         if (mdb_ctf_lookup_by_name(sname, &id) == 0) {
 682                 mdb_arg_t v;
 683                 int rv;
 684 
 685                 v.a_type = MDB_TYPE_STRING;
 686                 v.a_un.a_str = sname;
 687 
 688                 rv = mdb_call_dcmd("print", addr, flags, 1, &v);
 689                 return (rv);
 690         }
 691 
 692         sname[snamesz - 2] = 's';
 693         rv = print_soutype(sname, addr, flags);
 694         return (rv);
 695 }
 696 
 697 static int
 698 exec_alias(const char *fname, uintptr_t addr, uint_t flags)
 699 {
 700         const char *alias;
 701         int rv;
 702 
 703         if ((alias = mdb_macalias_lookup(fname)) == NULL)
 704                 return (DCMD_ERR);
 705 
 706         if (flags & DCMD_ADDRSPEC) {
 707                 size_t sz = sizeof (uintptr_t) * 2 + strlen(alias) + 1;
 708                 char *addralias = mdb_alloc(sz, UM_SLEEP | UM_GC);
 709                 (void) mdb_snprintf(addralias, sz, "%p%s", addr, alias);
 710                 rv = mdb_eval(addralias);
 711         } else {
 712                 rv = mdb_eval(alias);
 713         }
 714 
 715         return (rv == -1 ? DCMD_ABORT : DCMD_OK);
 716 }
 717 
 718 /*ARGSUSED*/
 719 static int
 720 cmd_src_file(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 721 {
 722         const char *fname;
 723         mdb_io_t *fio;
 724         int rv;
 725 
 726         if (argc != 1 || argv->a_type != MDB_TYPE_STRING)
 727                 return (DCMD_USAGE);
 728 
 729         fname = argv->a_un.a_str;
 730 
 731         if (flags & DCMD_PIPE_OUT) {
 732                 mdb_warn("macro files cannot be used as input to a pipeline\n");
 733                 return (DCMD_ABORT);
 734         }
 735 
 736         if ((fio = mdb_fdio_create_path(mdb.m_ipath, fname,
 737             O_RDONLY, 0)) != NULL) {
 738                 mdb_frame_t *fp = mdb.m_frame;
 739                 int err;
 740 
 741                 mdb_iob_stack_push(&fp->f_istk, mdb.m_in, yylineno);
 742                 mdb.m_in = mdb_iob_create(fio, MDB_IOB_RDONLY);
 743                 err = mdb_run();
 744 
 745                 ASSERT(fp == mdb.m_frame);
 746                 mdb.m_in = mdb_iob_stack_pop(&fp->f_istk);
 747                 yylineno = mdb_iob_lineno(mdb.m_in);
 748 
 749                 if (err == MDB_ERR_PAGER && mdb.m_fmark != fp)
 750                         longjmp(fp->f_pcb, err);
 751 
 752                 if (err == MDB_ERR_QUIT || err == MDB_ERR_ABORT ||
 753                     err == MDB_ERR_SIGINT || err == MDB_ERR_OUTPUT)
 754                         longjmp(fp->f_pcb, err);
 755 
 756                 return (DCMD_OK);
 757         }
 758 
 759         if ((rv = exec_alias(fname, addr, flags)) != DCMD_ERR ||
 760             (rv = print_type(fname, addr, flags)) != DCMD_ERR)
 761                 return (rv);
 762 
 763         mdb_warn("failed to open %s (see ::help '$<')\n", fname);
 764         return (DCMD_ABORT);
 765 }
 766 
 767 static int
 768 cmd_exec_file(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 769 {
 770         const char *fname;
 771         mdb_io_t *fio;
 772         int rv;
 773 
 774         /*
 775          * The syntax [expr[,count]]$< with no trailing macro file name is
 776          * magic in that if count is zero, this command won't be called and
 777          * the expression is thus a no-op.  If count is non-zero, we get
 778          * invoked with argc == 0, and this means abort the current macro.
 779          * If our debugger stack depth is greater than one, we may be using
 780          * $< from within a previous $<<, so in that case we set m_in to
 781          * NULL to force this entire frame to be popped.
 782          */
 783         if (argc == 0) {
 784                 if (mdb_iob_stack_size(&mdb.m_frame->f_istk) != 0) {
 785                         mdb_iob_destroy(mdb.m_in);
 786                         mdb.m_in = mdb_iob_stack_pop(&mdb.m_frame->f_istk);
 787                 } else if (mdb.m_depth > 1) {
 788                         mdb_iob_destroy(mdb.m_in);
 789                         mdb.m_in = NULL;
 790                 } else
 791                         mdb_warn("input stack is empty\n");
 792                 return (DCMD_OK);
 793         }
 794 
 795         if ((flags & (DCMD_PIPE | DCMD_PIPE_OUT)) || mdb.m_depth == 1)
 796                 return (cmd_src_file(addr, flags, argc, argv));
 797 
 798         if (argc != 1 || argv->a_type != MDB_TYPE_STRING)
 799                 return (DCMD_USAGE);
 800 
 801         fname = argv->a_un.a_str;
 802 
 803         if ((fio = mdb_fdio_create_path(mdb.m_ipath, fname,
 804             O_RDONLY, 0)) != NULL) {
 805                 mdb_iob_destroy(mdb.m_in);
 806                 mdb.m_in = mdb_iob_create(fio, MDB_IOB_RDONLY);
 807                 return (DCMD_OK);
 808         }
 809 
 810         if ((rv = exec_alias(fname, addr, flags)) != DCMD_ERR ||
 811             (rv = print_type(fname, addr, flags)) != DCMD_ERR)
 812                 return (rv);
 813 
 814         mdb_warn("failed to open %s (see ::help '$<')\n", fname);
 815         return (DCMD_ABORT);
 816 }
 817 
 818 #ifndef _KMDB
 819 /*ARGSUSED*/
 820 static int
 821 cmd_cat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 822 {
 823         int status = DCMD_OK;
 824         char buf[BUFSIZ];
 825         mdb_iob_t *iob;
 826         mdb_io_t *fio;
 827 
 828         if (flags & DCMD_ADDRSPEC)
 829                 return (DCMD_USAGE);
 830 
 831         for (; argc-- != 0; argv++) {
 832                 if (argv->a_type != MDB_TYPE_STRING) {
 833                         mdb_warn("expected string argument\n");
 834                         status = DCMD_ERR;
 835                         continue;
 836                 }
 837 
 838                 if ((fio = mdb_fdio_create_path(NULL,
 839                     argv->a_un.a_str, O_RDONLY, 0)) == NULL) {
 840                         mdb_warn("failed to open %s", argv->a_un.a_str);
 841                         status = DCMD_ERR;
 842                         continue;
 843                 }
 844 
 845                 iob = mdb_iob_create(fio, MDB_IOB_RDONLY);
 846 
 847                 while (!(mdb_iob_getflags(iob) & (MDB_IOB_EOF | MDB_IOB_ERR))) {
 848                         ssize_t len = mdb_iob_read(iob, buf, sizeof (buf));
 849                         if (len > 0) {
 850                                 if (mdb_iob_write(mdb.m_out, buf, len) < 0) {
 851                                         if (errno != EPIPE)
 852                                                 mdb_warn("write failed");
 853                                         status = DCMD_ERR;
 854                                         break;
 855                                 }
 856                         }
 857                 }
 858 
 859                 if (mdb_iob_err(iob))
 860                         mdb_warn("error while reading %s", mdb_iob_name(iob));
 861 
 862                 mdb_iob_destroy(iob);
 863         }
 864 
 865         return (status);
 866 }
 867 #endif
 868 
 869 /*ARGSUSED*/
 870 static int
 871 cmd_grep(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 872 {
 873         if (argc != 1 || argv->a_type != MDB_TYPE_STRING)
 874                 return (DCMD_USAGE);
 875 
 876         if (mdb_eval(argv->a_un.a_str) == -1)
 877                 return (DCMD_ABORT);
 878 
 879         if (mdb_get_dot() != 0)
 880                 mdb_printf("%lr\n", addr);
 881 
 882         return (DCMD_OK);
 883 }
 884 
 885 /*ARGSUSED*/
 886 static int
 887 cmd_map(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 888 {
 889         if (argc != 1 || argv->a_type != MDB_TYPE_STRING)
 890                 return (DCMD_USAGE);
 891 
 892         if (mdb_eval(argv->a_un.a_str) == -1)
 893                 return (DCMD_ABORT);
 894 
 895         mdb_printf("%llr\n", mdb_get_dot());
 896         return (DCMD_OK);
 897 }
 898 
 899 /*ARGSUSED*/
 900 static int
 901 cmd_notsup(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 902 {
 903         mdb_warn("command is not supported by current target\n");
 904         return (DCMD_ERR);
 905 }
 906 
 907 /*ARGSUSED*/
 908 static int
 909 cmd_quit(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 910 {
 911 #ifdef _KMDB
 912         uint_t opt_u = FALSE;
 913 
 914         if (mdb_getopts(argc, argv,
 915             'u', MDB_OPT_SETBITS, TRUE, &opt_u, NULL) != argc)
 916                 return (DCMD_USAGE);
 917 
 918         if (opt_u) {
 919                 if (mdb.m_flags & MDB_FL_NOUNLOAD) {
 920                         warn("%s\n", mdb_strerror(EMDB_KNOUNLOAD));
 921                         return (DCMD_ERR);
 922                 }
 923 
 924                 kmdb_kdi_set_unload_request();
 925         }
 926 #endif
 927 
 928         longjmp(mdb.m_frame->f_pcb, MDB_ERR_QUIT);
 929         /*NOTREACHED*/
 930         return (DCMD_ERR);
 931 }
 932 
 933 #ifdef _KMDB
 934 static void
 935 quit_help(void)
 936 {
 937         mdb_printf(
 938             "-u    unload the debugger (if not loaded at boot)\n");
 939 }
 940 #endif
 941 
 942 /*ARGSUSED*/
 943 static int
 944 cmd_vars(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 945 {
 946         uint_t opt_nz = FALSE, opt_tag = FALSE, opt_prt = FALSE;
 947         mdb_var_t *v;
 948 
 949         if (mdb_getopts(argc, argv,
 950             'n', MDB_OPT_SETBITS, TRUE, &opt_nz,
 951             'p', MDB_OPT_SETBITS, TRUE, &opt_prt,
 952             't', MDB_OPT_SETBITS, TRUE, &opt_tag, NULL) != argc)
 953                 return (DCMD_USAGE);
 954 
 955         mdb_nv_rewind(&mdb.m_nv);
 956 
 957         while ((v = mdb_nv_advance(&mdb.m_nv)) != NULL) {
 958                 if ((opt_tag == FALSE || (v->v_flags & MDB_NV_TAGGED)) &&
 959                     (opt_nz == FALSE || mdb_nv_get_value(v) != 0)) {
 960                         if (opt_prt) {
 961                                 mdb_printf("%#llr>%s\n",
 962                                     mdb_nv_get_value(v), mdb_nv_get_name(v));
 963                         } else {
 964                                 mdb_printf("%s = %llr\n",
 965                                     mdb_nv_get_name(v), mdb_nv_get_value(v));
 966                         }
 967                 }
 968         }
 969 
 970         return (DCMD_OK);
 971 }
 972 
 973 /*ARGSUSED*/
 974 static int
 975 cmd_nzvars(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 976 {
 977         uintmax_t value;
 978         mdb_var_t *v;
 979 
 980         if (argc != 0)
 981                 return (DCMD_USAGE);
 982 
 983         mdb_nv_rewind(&mdb.m_nv);
 984 
 985         while ((v = mdb_nv_advance(&mdb.m_nv)) != NULL) {
 986                 if ((value = mdb_nv_get_value(v)) != 0)
 987                         mdb_printf("%s = %llr\n", mdb_nv_get_name(v), value);
 988         }
 989 
 990         return (DCMD_OK);
 991 }
 992 
 993 /*ARGSUSED*/
 994 static int
 995 cmd_radix(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 996 {
 997         if (argc != 0)
 998                 return (DCMD_USAGE);
 999 
1000         if (flags & DCMD_ADDRSPEC) {
1001                 if (addr < 2 || addr > 16) {
1002                         mdb_warn("expected radix from 2 to 16\n");
1003                         return (DCMD_ERR);
1004                 }
1005                 mdb.m_radix = (int)addr;
1006         }
1007 
1008         mdb_iob_printf(mdb.m_out, "radix = %d base ten\n", mdb.m_radix);
1009         return (DCMD_OK);
1010 }
1011 
1012 /*ARGSUSED*/
1013 static int
1014 cmd_symdist(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1015 {
1016         if (argc != 0)
1017                 return (DCMD_USAGE);
1018 
1019         if (flags & DCMD_ADDRSPEC)
1020                 mdb.m_symdist = addr;
1021 
1022         mdb_printf("symbol matching distance = %lr (%s)\n",
1023             mdb.m_symdist, mdb.m_symdist ? "absolute mode" : "smart mode");
1024 
1025         return (DCMD_OK);
1026 }
1027 
1028 /*ARGSUSED*/
1029 static int
1030 cmd_pgwidth(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1031 {
1032         if (argc != 0)
1033                 return (DCMD_USAGE);
1034 
1035         if (flags & DCMD_ADDRSPEC)
1036                 mdb_iob_resize(mdb.m_out, mdb.m_out->iob_rows, addr);
1037 
1038         mdb_printf("output page width = %lu\n", mdb.m_out->iob_cols);
1039         return (DCMD_OK);
1040 }
1041 
1042 /*ARGSUSED*/
1043 static int
1044 cmd_reopen(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1045 {
1046         if (argc != 0)
1047                 return (DCMD_USAGE);
1048 
1049         if (mdb_tgt_setflags(mdb.m_target, MDB_TGT_F_RDWR) == -1) {
1050                 mdb_warn("failed to re-open target for writing");
1051                 return (DCMD_ERR);
1052         }
1053 
1054         return (DCMD_OK);
1055 }
1056 
1057 /*ARGSUSED*/
1058 static int
1059 print_xdata(void *ignored, const char *name, const char *desc, size_t nbytes)
1060 {
1061         mdb_printf("%-24s - %s (%lu bytes)\n", name, desc, (ulong_t)nbytes);
1062         return (0);
1063 }
1064 
1065 /*ARGSUSED*/
1066 static int
1067 cmd_xdata(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1068 {
1069         if (argc != 0 || (flags & DCMD_ADDRSPEC))
1070                 return (DCMD_USAGE);
1071 
1072         (void) mdb_tgt_xdata_iter(mdb.m_target, print_xdata, NULL);
1073         return (DCMD_OK);
1074 }
1075 
1076 /*ARGSUSED*/
1077 static int
1078 cmd_unset(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1079 {
1080         mdb_var_t *v;
1081         size_t i;
1082 
1083         for (i = 0; i < argc; i++) {
1084                 if (argv[i].a_type != MDB_TYPE_STRING) {
1085                         mdb_warn("bad option: arg %lu is not a string\n",
1086                             (ulong_t)i + 1);
1087                         return (DCMD_USAGE);
1088                 }
1089         }
1090 
1091         for (i = 0; i < argc; i++, argv++) {
1092                 if ((v = mdb_nv_lookup(&mdb.m_nv, argv->a_un.a_str)) == NULL)
1093                         mdb_warn("variable '%s' not defined\n",
1094                             argv->a_un.a_str);
1095                 else
1096                         mdb_nv_remove(&mdb.m_nv, v);
1097         }
1098 
1099         return (DCMD_OK);
1100 }
1101 
1102 #ifndef _KMDB
1103 /*ARGSUSED*/
1104 static int
1105 cmd_log(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1106 {
1107         uint_t opt_e = FALSE, opt_d = FALSE;
1108         const char *filename = NULL;
1109         int i;
1110 
1111         i = mdb_getopts(argc, argv,
1112             'd', MDB_OPT_SETBITS, TRUE, &opt_d,
1113             'e', MDB_OPT_SETBITS, TRUE, &opt_e, NULL);
1114 
1115         if ((i != argc && i != argc - 1) || (opt_d && opt_e) ||
1116             (i != argc && argv[i].a_type != MDB_TYPE_STRING) ||
1117             (i != argc && opt_d == TRUE) || (flags & DCMD_ADDRSPEC))
1118                 return (DCMD_USAGE);
1119 
1120         if (mdb.m_depth != 1) {
1121                 mdb_warn("log may not be manipulated in this context\n");
1122                 return (DCMD_ABORT);
1123         }
1124 
1125         if (i != argc)
1126                 filename = argv[i].a_un.a_str;
1127 
1128         /*
1129          * If no arguments were specified, print the log file name (if any)
1130          * and report whether the log is enabled or disabled.
1131          */
1132         if (argc == 0) {
1133                 if (mdb.m_log) {
1134                         mdb_printf("%s: logging to \"%s\" is currently %s\n",
1135                             mdb.m_pname, IOP_NAME(mdb.m_log),
1136                             mdb.m_flags & MDB_FL_LOG ?  "enabled" : "disabled");
1137                 } else
1138                         mdb_printf("%s: no log is active\n", mdb.m_pname);
1139                 return (DCMD_OK);
1140         }
1141 
1142         /*
1143          * If the -d option was specified, pop the log i/o object off the
1144          * i/o stack of stdin, stdout, and stderr.
1145          */
1146         if (opt_d) {
1147                 if (mdb.m_flags & MDB_FL_LOG) {
1148                         (void) mdb_iob_pop_io(mdb.m_in);
1149                         (void) mdb_iob_pop_io(mdb.m_out);
1150                         (void) mdb_iob_pop_io(mdb.m_err);
1151                         mdb.m_flags &= ~MDB_FL_LOG;
1152                 } else
1153                         mdb_warn("logging is already disabled\n");
1154                 return (DCMD_OK);
1155         }
1156 
1157         /*
1158          * The -e option is the default: (re-)enable logging by pushing
1159          * the log i/o object on to stdin, stdout, and stderr.  If we have
1160          * a previous log file, we need to pop it and close it.  If we have
1161          * no new log file, push the previous one back on.
1162          */
1163         if (filename != NULL) {
1164                 if (mdb.m_log != NULL) {
1165                         if (mdb.m_flags & MDB_FL_LOG) {
1166                                 (void) mdb_iob_pop_io(mdb.m_in);
1167                                 (void) mdb_iob_pop_io(mdb.m_out);
1168                                 (void) mdb_iob_pop_io(mdb.m_err);
1169                                 mdb.m_flags &= ~MDB_FL_LOG;
1170                         }
1171                         mdb_io_rele(mdb.m_log);
1172                 }
1173 
1174                 mdb.m_log = mdb_fdio_create_path(NULL, filename,
1175                     O_CREAT | O_APPEND | O_WRONLY, 0666);
1176 
1177                 if (mdb.m_log == NULL) {
1178                         mdb_warn("failed to open %s", filename);
1179                         return (DCMD_ERR);
1180                 }
1181         }
1182 
1183         if (mdb.m_log != NULL) {
1184                 mdb_iob_push_io(mdb.m_in, mdb_logio_create(mdb.m_log));
1185                 mdb_iob_push_io(mdb.m_out, mdb_logio_create(mdb.m_log));
1186                 mdb_iob_push_io(mdb.m_err, mdb_logio_create(mdb.m_log));
1187 
1188                 mdb_printf("%s: logging to \"%s\"\n", mdb.m_pname, filename);
1189                 mdb.m_log = mdb_io_hold(mdb.m_log);
1190                 mdb.m_flags |= MDB_FL_LOG;
1191 
1192                 return (DCMD_OK);
1193         }
1194 
1195         mdb_warn("no log file has been selected\n");
1196         return (DCMD_ERR);
1197 }
1198 
1199 static int
1200 cmd_old_log(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1201 {
1202         if (argc == 0) {
1203                 mdb_arg_t arg = { MDB_TYPE_STRING, MDB_INIT_STRING("-d") };
1204                 return (cmd_log(addr, flags, 1, &arg));
1205         }
1206 
1207         return (cmd_log(addr, flags, argc, argv));
1208 }
1209 #endif
1210 
1211 /*ARGSUSED*/
1212 static int
1213 cmd_load(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1214 {
1215         int i, mode = MDB_MOD_LOCAL;
1216 
1217         i = mdb_getopts(argc, argv,
1218 #ifdef _KMDB
1219             'd', MDB_OPT_SETBITS, MDB_MOD_DEFER, &mode,
1220 #endif
1221             'f', MDB_OPT_SETBITS, MDB_MOD_FORCE, &mode,
1222             'g', MDB_OPT_SETBITS, MDB_MOD_GLOBAL, &mode,
1223             's', MDB_OPT_SETBITS, MDB_MOD_SILENT, &mode,
1224             NULL);
1225 
1226         argc -= i;
1227         argv += i;
1228 
1229         if ((flags & DCMD_ADDRSPEC) || argc != 1 ||
1230             argv->a_type != MDB_TYPE_STRING ||
1231             strchr("+-", argv->a_un.a_str[0]) != NULL)
1232                 return (DCMD_USAGE);
1233 
1234         if (mdb_module_load(argv->a_un.a_str, mode) < 0)
1235                 return (DCMD_ERR);
1236 
1237         return (DCMD_OK);
1238 }
1239 
1240 static void
1241 load_help(void)
1242 {
1243         mdb_printf(
1244 #ifdef _KMDB
1245             "-d    defer load until next continue\n"
1246 #endif
1247             "-s    load module silently\n");
1248 }
1249 
1250 /*ARGSUSED*/
1251 static int
1252 cmd_unload(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1253 {
1254         int mode = 0;
1255         int i;
1256 
1257         i = mdb_getopts(argc, argv,
1258 #ifdef _KMDB
1259             'd', MDB_OPT_SETBITS, MDB_MOD_DEFER, &mode,
1260 #endif
1261             NULL);
1262 
1263         argc -= i;
1264         argv += i;
1265 
1266         if (argc != 1 || argv->a_type != MDB_TYPE_STRING)
1267                 return (DCMD_USAGE);
1268 
1269         if (mdb_module_unload(argv->a_un.a_str, mode) == -1) {
1270                 mdb_warn("failed to unload %s", argv->a_un.a_str);
1271                 return (DCMD_ERR);
1272         }
1273 
1274         return (DCMD_OK);
1275 }
1276 
1277 #ifdef _KMDB
1278 static void
1279 unload_help(void)
1280 {
1281         mdb_printf(
1282             "-d    defer unload until next continue\n");
1283 }
1284 #endif
1285 
1286 static int
1287 cmd_dbmode(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1288 {
1289         if (argc > 1 || (argc != 0 && (flags & DCMD_ADDRSPEC)))
1290                 return (DCMD_USAGE);
1291 
1292         if (argc != 0) {
1293                 if (argv->a_type != MDB_TYPE_STRING)
1294                         return (DCMD_USAGE);
1295                 if ((addr = mdb_dstr2mode(argv->a_un.a_str)) != MDB_DBG_HELP)
1296                         mdb_dmode(addr);
1297         } else if (flags & DCMD_ADDRSPEC)
1298                 mdb_dmode(addr);
1299 
1300         mdb_printf("debugging mode = 0x%04x\n", mdb.m_debug);
1301         return (DCMD_OK);
1302 }
1303 
1304 /*ARGSUSED*/
1305 static int
1306 cmd_version(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1307 {
1308 #ifdef DEBUG
1309         mdb_printf("\r%s (DEBUG)\n", mdb_conf_version());
1310 #else
1311         mdb_printf("\r%s\n", mdb_conf_version());
1312 #endif
1313         return (DCMD_OK);
1314 }
1315 
1316 /*ARGSUSED*/
1317 static int
1318 cmd_algol(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1319 {
1320         if (mdb.m_flags & MDB_FL_ADB)
1321                 mdb_printf("No algol 68 here\n");
1322         else
1323                 mdb_printf("No adb here\n");
1324         return (DCMD_OK);
1325 }
1326 
1327 /*ARGSUSED*/
1328 static int
1329 cmd_obey(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1330 {
1331         if (mdb.m_flags & MDB_FL_ADB)
1332                 mdb_printf("CHAPTER 1\n");
1333         else
1334                 mdb_printf("No Language H here\n");
1335         return (DCMD_OK);
1336 }
1337 
1338 /*ARGSUSED*/
1339 static int
1340 print_global(void *data, const GElf_Sym *sym, const char *name,
1341     const mdb_syminfo_t *sip, const char *obj)
1342 {
1343         uintptr_t value;
1344 
1345         if (mdb_tgt_vread((mdb_tgt_t *)data, &value, sizeof (value),
1346             (uintptr_t)sym->st_value) == sizeof (value))
1347                 mdb_printf("%s(%llr):\t%lr\n", name, sym->st_value, value);
1348         else
1349                 mdb_printf("%s(%llr):\t?\n", name, sym->st_value);
1350 
1351         return (0);
1352 }
1353 
1354 /*ARGSUSED*/
1355 static int
1356 cmd_globals(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1357 {
1358         if (argc != 0)
1359                 return (DCMD_USAGE);
1360 
1361         (void) mdb_tgt_symbol_iter(mdb.m_target, MDB_TGT_OBJ_EVERY,
1362             MDB_TGT_SYMTAB, MDB_TGT_BIND_GLOBAL | MDB_TGT_TYPE_OBJECT |
1363             MDB_TGT_TYPE_FUNC, print_global, mdb.m_target);
1364 
1365         return (0);
1366 }
1367 
1368 /*ARGSUSED*/
1369 static int
1370 cmd_eval(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1371 {
1372         if (argc != 1 || argv->a_type != MDB_TYPE_STRING)
1373                 return (DCMD_USAGE);
1374 
1375         if (mdb_eval(argv->a_un.a_str) == -1)
1376                 return (DCMD_ABORT);
1377 
1378         return (DCMD_OK);
1379 }
1380 
1381 /*ARGSUSED*/
1382 static int
1383 print_file(void *data, const GElf_Sym *sym, const char *name,
1384     const mdb_syminfo_t *sip, const char *obj)
1385 {
1386         int i = *((int *)data);
1387 
1388         mdb_printf("%d\t%s\n", i++, name);
1389         *((int *)data) = i;
1390         return (0);
1391 }
1392 
1393 /*ARGSUSED*/
1394 static int
1395 cmd_files(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1396 {
1397         int i = 1;
1398         const char *obj = MDB_TGT_OBJ_EVERY;
1399 
1400         if ((flags & DCMD_ADDRSPEC) || argc > 1)
1401                 return (DCMD_USAGE);
1402 
1403         if (argc == 1) {
1404                 if (argv->a_type != MDB_TYPE_STRING)
1405                         return (DCMD_USAGE);
1406 
1407                 obj = argv->a_un.a_str;
1408         }
1409 
1410         (void) mdb_tgt_symbol_iter(mdb.m_target, obj, MDB_TGT_SYMTAB,
1411             MDB_TGT_BIND_ANY | MDB_TGT_TYPE_FILE, print_file, &i);
1412 
1413         return (DCMD_OK);
1414 }
1415 
1416 static const char *
1417 map_name(const mdb_map_t *map, const char *name)
1418 {
1419         if (map->map_flags & MDB_TGT_MAP_HEAP)
1420                 return ("[ heap ]");
1421         if (name != NULL && name[0] != 0)
1422                 return (name);
1423 
1424         if (map->map_flags & MDB_TGT_MAP_SHMEM)
1425                 return ("[ shmem ]");
1426         if (map->map_flags & MDB_TGT_MAP_STACK)
1427                 return ("[ stack ]");
1428         if (map->map_flags & MDB_TGT_MAP_ANON)
1429                 return ("[ anon ]");
1430         if (map->map_name != NULL)
1431                 return (map->map_name);
1432         return ("[ unknown ]");
1433 }
1434 
1435 /*ARGSUSED*/
1436 static int
1437 print_map(void *ignored, const mdb_map_t *map, const char *name)
1438 {
1439         name = map_name(map, name);
1440 
1441         mdb_printf("%?p %?p %?lx %s\n", map->map_base,
1442             map->map_base + map->map_size, map->map_size, name);
1443         return (0);
1444 }
1445 
1446 static int
1447 cmd_mappings(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1448 {
1449         const mdb_map_t *m;
1450 
1451         if (argc > 1 || (argc != 0 && (flags & DCMD_ADDRSPEC)))
1452                 return (DCMD_USAGE);
1453 
1454         mdb_printf("%<u>%?s %?s %?s %s%</u>\n",
1455             "BASE", "LIMIT", "SIZE", "NAME");
1456 
1457         if (flags & DCMD_ADDRSPEC) {
1458                 if ((m = mdb_tgt_addr_to_map(mdb.m_target, addr)) == NULL)
1459                         mdb_warn("failed to obtain mapping");
1460                 else
1461                         (void) print_map(NULL, m, NULL);
1462 
1463         } else if (argc != 0) {
1464                 if (argv->a_type == MDB_TYPE_STRING)
1465                         m = mdb_tgt_name_to_map(mdb.m_target, argv->a_un.a_str);
1466                 else
1467                         m = mdb_tgt_addr_to_map(mdb.m_target, argv->a_un.a_val);
1468 
1469                 if (m == NULL)
1470                         mdb_warn("failed to obtain mapping");
1471                 else
1472                         (void) print_map(NULL, m, NULL);
1473 
1474         } else if (mdb_tgt_mapping_iter(mdb.m_target, print_map, NULL) == -1)
1475                 mdb_warn("failed to iterate over mappings");
1476 
1477         return (DCMD_OK);
1478 }
1479 
1480 static int
1481 whatis_map_callback(void *wp, const mdb_map_t *map, const char *name)
1482 {
1483         mdb_whatis_t *w = wp;
1484         uintptr_t cur;
1485 
1486         name = map_name(map, name);
1487 
1488         while (mdb_whatis_match(w, map->map_base, map->map_size, &cur))
1489                 mdb_whatis_report_address(w, cur, "in %s [%p,%p)\n",
1490                     name, map->map_base, map->map_base + map->map_size);
1491 
1492         return (0);
1493 }
1494 
1495 /*ARGSUSED*/
1496 int
1497 whatis_run_mappings(mdb_whatis_t *w, void *ignored)
1498 {
1499         (void) mdb_tgt_mapping_iter(mdb.m_target, whatis_map_callback, w);
1500         return (0);
1501 }
1502 
1503 /*ARGSUSED*/
1504 static int
1505 objects_printversion(void *ignored, const mdb_map_t *map, const char *name)
1506 {
1507         ctf_file_t *ctfp;
1508         const char *version;
1509 
1510         ctfp = mdb_tgt_name_to_ctf(mdb.m_target, name);
1511         if (ctfp == NULL || (version = ctf_label_topmost(ctfp)) == NULL)
1512                 version = "Unknown";
1513 
1514         mdb_printf("%-28s %s\n", name, version);
1515         return (0);
1516 }
1517 
1518 /*ARGSUSED*/
1519 static int
1520 cmd_objects(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1521 {
1522         uint_t opt_v = FALSE;
1523         mdb_tgt_map_f *cb;
1524 
1525         if ((flags & DCMD_ADDRSPEC) || mdb_getopts(argc, argv,
1526             'v', MDB_OPT_SETBITS, TRUE, &opt_v, NULL) != argc)
1527                 return (DCMD_USAGE);
1528 
1529         if (opt_v) {
1530                 cb = objects_printversion;
1531                 mdb_printf("%<u>%-28s %s%</u>\n", "NAME", "VERSION");
1532         } else {
1533                 cb = print_map;
1534                 mdb_printf("%<u>%?s %?s %?s %s%</u>\n",
1535                     "BASE", "LIMIT", "SIZE", "NAME");
1536         }
1537 
1538         if (mdb_tgt_object_iter(mdb.m_target, cb, NULL) == -1) {
1539                 mdb_warn("failed to iterate over objects");
1540                 return (DCMD_ERR);
1541         }
1542 
1543         return (DCMD_OK);
1544 }
1545 
1546 /*ARGSUSED*/
1547 static int
1548 showrev_addversion(void *vers_nv, const mdb_map_t *ignored, const char *object)
1549 {
1550         ctf_file_t *ctfp;
1551         const char *version = NULL;
1552         char *objname;
1553 
1554         objname = mdb_alloc(strlen(object) + 1, UM_SLEEP | UM_GC);
1555         (void) strcpy(objname, object);
1556 
1557         if ((ctfp = mdb_tgt_name_to_ctf(mdb.m_target, objname)) != NULL)
1558                 version = ctf_label_topmost(ctfp);
1559 
1560         /*
1561          * Not all objects have CTF and label data, so set version to "Unknown".
1562          */
1563         if (version == NULL)
1564                 version = "Unknown";
1565 
1566         /*
1567          * The hash table implementation in OVERLOAD mode limits the version
1568          * name to 31 characters because we cannot specify an external name.
1569          * The full version name is available via the ::objects dcmd if needed.
1570          */
1571         (void) mdb_nv_insert(vers_nv, version, NULL, (uintptr_t)objname,
1572             MDB_NV_OVERLOAD);
1573 
1574         return (0);
1575 }
1576 
1577 static int
1578 showrev_ispatch(const char *s)
1579 {
1580         if (s == NULL)
1581                 return (0);
1582 
1583         if (*s == 'T')
1584                 s++; /* skip T for T-patch */
1585 
1586         for (; *s != '\0'; s++) {
1587                 if ((*s < '0' || *s > '9') && *s != '-')
1588                         return (0);
1589         }
1590 
1591         return (1);
1592 }
1593 
1594 /*ARGSUSED*/
1595 static int
1596 showrev_printobject(mdb_var_t *v, void *ignored)
1597 {
1598         mdb_printf("%s ", MDB_NV_COOKIE(v));
1599         return (0);
1600 }
1601 
1602 static int
1603 showrev_printversion(mdb_var_t *v, void *showall)
1604 {
1605         const char *version = mdb_nv_get_name(v);
1606         int patch;
1607 
1608         patch = showrev_ispatch(version);
1609         if (patch || (uintptr_t)showall) {
1610                 mdb_printf("%s: %s  Objects: ",
1611                     (patch ? "Patch" : "Version"), version);
1612                 (void) mdb_inc_indent(2);
1613 
1614                 mdb_nv_defn_iter(v, showrev_printobject, NULL);
1615 
1616                 (void) mdb_dec_indent(2);
1617                 mdb_printf("\n");
1618         }
1619 
1620         return (0);
1621 }
1622 
1623 /*
1624  * Display version information for each object in the system.
1625  * Print information about patches only, unless showall is TRUE.
1626  */
1627 static int
1628 showrev_objectversions(int showall)
1629 {
1630         mdb_nv_t vers_nv;
1631 
1632         (void) mdb_nv_create(&vers_nv, UM_SLEEP | UM_GC);
1633         if (mdb_tgt_object_iter(mdb.m_target, showrev_addversion,
1634             &vers_nv) == -1) {
1635                 mdb_warn("failed to iterate over objects");
1636                 return (DCMD_ERR);
1637         }
1638 
1639         mdb_nv_sort_iter(&vers_nv, showrev_printversion,
1640             (void *)(uintptr_t)showall, UM_SLEEP | UM_GC);
1641         return (DCMD_OK);
1642 }
1643 
1644 /*
1645  * Display information similar to what showrev(1M) displays when invoked
1646  * with no arguments.
1647  */
1648 static int
1649 showrev_sysinfo(void)
1650 {
1651         const char *s;
1652         int rc;
1653         struct utsname u;
1654 
1655         if ((rc = mdb_tgt_uname(mdb.m_target, &u)) != -1) {
1656                 mdb_printf("Hostname: %s\n", u.nodename);
1657                 mdb_printf("Release: %s\n", u.release);
1658                 mdb_printf("Kernel architecture: %s\n", u.machine);
1659         }
1660 
1661         /*
1662          * Match the order of the showrev(1M) output and put "Application
1663          * architecture" before "Kernel version"
1664          */
1665         if ((s = mdb_tgt_isa(mdb.m_target)) != NULL)
1666                 mdb_printf("Application architecture: %s\n", s);
1667 
1668         if (rc != -1)
1669                 mdb_printf("Kernel version: %s %s %s %s\n",
1670                     u.sysname, u.release, u.machine, u.version);
1671 
1672         if ((s = mdb_tgt_platform(mdb.m_target)) != NULL)
1673                 mdb_printf("Platform: %s\n", s);
1674 
1675         return (DCMD_OK);
1676 }
1677 
1678 /*ARGSUSED*/
1679 static int
1680 cmd_showrev(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1681 {
1682         uint_t opt_p = FALSE, opt_v = FALSE;
1683 
1684         if ((flags & DCMD_ADDRSPEC) || mdb_getopts(argc, argv,
1685             'p', MDB_OPT_SETBITS, TRUE, &opt_p,
1686             'v', MDB_OPT_SETBITS, TRUE, &opt_v, NULL) != argc)
1687                 return (DCMD_USAGE);
1688 
1689         if (opt_p || opt_v)
1690                 return (showrev_objectversions(opt_v));
1691         else
1692                 return (showrev_sysinfo());
1693 }
1694 
1695 #ifdef __sparc
1696 static void
1697 findsym_output(uintptr_t *symlist, uintptr_t value, uintptr_t location)
1698 {
1699         uintptr_t       *symbolp;
1700 
1701         for (symbolp = symlist; *symbolp; symbolp++)
1702                 if (value == *symbolp)
1703                         mdb_printf("found %a at %a\n", value, location);
1704 }
1705 
1706 /*ARGSUSED*/
1707 static int
1708 findsym_cb(void *data, const GElf_Sym *sym, const char *name,
1709     const mdb_syminfo_t *sip, const char *obj)
1710 {
1711         uint32_t        *text;
1712         int             len;
1713         int             i;
1714         int             j;
1715         uint8_t         rd;
1716         uintptr_t       value;
1717         int32_t         imm13;
1718         uint8_t         op;
1719         uint8_t         op3;
1720         uintptr_t       *symlist = data;
1721         size_t          size = sym->st_size;
1722 
1723         /*
1724          * if the size of the symbol is 0, then this symbol must be for an
1725          * alternate entry point or just some global label. We will,
1726          * therefore, get back to the text that follows this symbol in
1727          * some other symbol
1728          */
1729         if (size == 0)
1730                 return (0);
1731 
1732         if (sym->st_shndx == SHN_UNDEF)
1733                 return (0);
1734 
1735         text = alloca(size);
1736 
1737         if (mdb_vread(text, size, sym->st_value) == -1) {
1738                 mdb_warn("failed to read text for %s", name);
1739                 return (0);
1740         }
1741 
1742         len = size / 4;
1743         for (i = 0; i < len; i++) {
1744                 if (!IS_SETHI(text[i]))
1745                         continue;
1746 
1747                 rd = RD(text[i]);
1748                 value = IMM22(text[i]) << 10;
1749 
1750                 /*
1751                  * see if we already have a match with just the sethi
1752                  */
1753                 findsym_output(symlist, value, sym->st_value + i * 4);
1754 
1755                 /*
1756                  * search from the sethi on until we hit a relevant instr
1757                  */
1758                 for (j = i + 1; j < len; j++) {
1759                         if ((op = OP(text[j])) & OP_ARITH_MEM_MASK) {
1760                                 op3 = OP3(text[j]);
1761 
1762                                 if (RS1(text[j]) != rd)
1763                                         goto instr_end;
1764 
1765                                 /*
1766                                  * This is a simple tool; we only deal
1767                                  * with operations which take immediates
1768                                  */
1769                                 if (I(text[j]) == 0)
1770                                         goto instr_end;
1771 
1772                                 /*
1773                                  * sign extend the immediate value
1774                                  */
1775                                 imm13 = IMM13(text[j]);
1776                                 imm13 <<= 19;
1777                                 imm13 >>= 19;
1778 
1779                                 if (op == OP_ARITH) {
1780                                         /* arithmetic operations */
1781                                         if (op3 & OP3_COMPLEX_MASK)
1782                                                 goto instr_end;
1783 
1784                                         switch (op3 & ~OP3_CC_MASK) {
1785                                         case OP3_OR:
1786                                                 value |= imm13;
1787                                                 break;
1788                                         case OP3_ADD:
1789                                                 value += imm13;
1790                                                 break;
1791                                         case OP3_XOR:
1792                                                 value ^= imm13;
1793                                                 break;
1794                                         default:
1795                                                 goto instr_end;
1796                                         }
1797                                 } else {
1798                                         /* loads and stores */
1799                                         /* op3 == OP_MEM */
1800 
1801                                         value += imm13;
1802                                 }
1803 
1804                                 findsym_output(symlist, value,
1805                                     sym->st_value + j * 4);
1806 instr_end:
1807                                 /*
1808                                  * if we're clobbering rd, break
1809                                  */
1810                                 if (RD(text[j]) == rd)
1811                                         break;
1812                         } else if (IS_SETHI(text[j])) {
1813                                 if (RD(text[j]) == rd)
1814                                         break;
1815                         } else if (OP(text[j]) == 1) {
1816                                 /*
1817                                  * see if a call clobbers an %o or %g
1818                                  */
1819                                 if (rd <= R_O7)
1820                                         break;
1821                         }
1822                 }
1823         }
1824 
1825         return (0);
1826 }
1827 
1828 static int
1829 cmd_findsym(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1830 {
1831         uintptr_t *symlist;
1832         uint_t optg = FALSE;
1833         uint_t type;
1834         int len, i;
1835 
1836         i = mdb_getopts(argc, argv, 'g', MDB_OPT_SETBITS, TRUE, &optg, NULL);
1837 
1838         argc -= i;
1839         argv += i;
1840 
1841         len = argc + ((flags & DCMD_ADDRSPEC) ? 1 : 0) + 1;
1842 
1843         if (len <= 1)
1844                 return (DCMD_USAGE);
1845 
1846         /*
1847          * Set up a NULL-terminated symbol list, and then iterate over the
1848          * symbol table, scanning each function for references to these symbols.
1849          */
1850         symlist = mdb_alloc(len * sizeof (uintptr_t), UM_SLEEP | UM_GC);
1851         len = 0;
1852 
1853         for (i = 0; i < argc; i++, argv++) {
1854                 const char *str = argv->a_un.a_str;
1855                 uintptr_t value;
1856                 GElf_Sym sym;
1857 
1858                 if (argv->a_type == MDB_TYPE_STRING) {
1859                         if (strchr("+-", str[0]) != NULL)
1860                                 return (DCMD_USAGE);
1861                         else if (str[0] >= '0' && str[0] <= '9')
1862                                 value = mdb_strtoull(str);
1863                         else if (mdb_lookup_by_name(str, &sym) != 0) {
1864                                 mdb_warn("symbol '%s' not found", str);
1865                                 return (DCMD_USAGE);
1866                         } else
1867                                 value = sym.st_value;
1868                 } else
1869                         value = argv[i].a_un.a_val;
1870 
1871                 if (value != NULL)
1872                         symlist[len++] = value;
1873         }
1874 
1875         if (flags & DCMD_ADDRSPEC)
1876                 symlist[len++] = addr;
1877 
1878         symlist[len] = NULL;
1879 
1880         if (optg)
1881                 type = MDB_TGT_BIND_GLOBAL | MDB_TGT_TYPE_FUNC;
1882         else
1883                 type = MDB_TGT_BIND_ANY | MDB_TGT_TYPE_FUNC;
1884 
1885         if (mdb_tgt_symbol_iter(mdb.m_target, MDB_TGT_OBJ_EVERY,
1886             MDB_TGT_SYMTAB, type, findsym_cb, symlist) == -1) {
1887                 mdb_warn("failed to iterate over symbol table");
1888                 return (DCMD_ERR);
1889         }
1890 
1891         return (DCMD_OK);
1892 }
1893 #endif /* __sparc */
1894 
1895 static int
1896 dis_str2addr(const char *s, uintptr_t *addr)
1897 {
1898         GElf_Sym sym;
1899 
1900         if (s[0] >= '0' && s[0] <= '9') {
1901                 *addr = (uintptr_t)mdb_strtoull(s);
1902                 return (0);
1903         }
1904 
1905         if (mdb_tgt_lookup_by_name(mdb.m_target,
1906             MDB_TGT_OBJ_EVERY, s, &sym, NULL) == -1) {
1907                 mdb_warn("symbol '%s' not found\n", s);
1908                 return (-1);
1909         }
1910 
1911         *addr = (uintptr_t)sym.st_value;
1912         return (0);
1913 }
1914 
1915 static int
1916 cmd_dis(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1917 {
1918         mdb_tgt_t *tgt = mdb.m_target;
1919         mdb_disasm_t *dis = mdb.m_disasm;
1920 
1921         uintptr_t oaddr, naddr;
1922         mdb_tgt_as_t as;
1923         mdb_tgt_status_t st;
1924         char buf[BUFSIZ];
1925         GElf_Sym sym;
1926         int i;
1927 
1928         uint_t opt_f = FALSE;           /* File-mode off by default */
1929         uint_t opt_w = FALSE;           /* Window mode off by default */
1930         uint_t opt_a = FALSE;           /* Raw-address mode off by default */
1931         uint_t opt_b = FALSE;           /* Address & symbols off by default */
1932         uintptr_t n = -1UL;             /* Length of window in instructions */
1933         uintptr_t eaddr = 0;            /* Ending address; 0 if limited by n */
1934 
1935         i = mdb_getopts(argc, argv,
1936             'f', MDB_OPT_SETBITS, TRUE, &opt_f,
1937             'w', MDB_OPT_SETBITS, TRUE, &opt_w,
1938             'a', MDB_OPT_SETBITS, TRUE, &opt_a,
1939             'b', MDB_OPT_SETBITS, TRUE, &opt_b,
1940             'n', MDB_OPT_UINTPTR, &n, NULL);
1941 
1942         /*
1943          * Disgusting argument post-processing ... basically the idea is to get
1944          * the target address into addr, which we do by using the specified
1945          * expression value, looking up a string as a symbol name, or by
1946          * using the address specified as dot.
1947          */
1948         if (i != argc) {
1949                 if (argc != 0 && (argc - i) == 1) {
1950                         if (argv[i].a_type == MDB_TYPE_STRING) {
1951                                 if (argv[i].a_un.a_str[0] == '-')
1952                                         return (DCMD_USAGE);
1953 
1954                                 if (dis_str2addr(argv[i].a_un.a_str, &addr))
1955                                         return (DCMD_ERR);
1956                         } else
1957                                 addr = argv[i].a_un.a_val;
1958                 } else
1959                         return (DCMD_USAGE);
1960         }
1961 
1962         /*
1963          * If we're not in window mode yet, and some type of arguments were
1964          * specified, see if the address corresponds nicely to a function.
1965          * If not, turn on window mode; otherwise disassemble the function.
1966          */
1967         if (opt_w == FALSE && (argc != i || (flags & DCMD_ADDRSPEC))) {
1968                 if (mdb_tgt_lookup_by_addr(tgt, addr,
1969                     MDB_TGT_SYM_EXACT, buf, sizeof (buf), &sym, NULL) == 0 &&
1970                     GELF_ST_TYPE(sym.st_info) == STT_FUNC) {
1971                         /*
1972                          * If the symbol has a size then set our end address to
1973                          * be the end of the function symbol we just located.
1974                          */
1975                         if (sym.st_size != 0)
1976                                 eaddr = addr + (uintptr_t)sym.st_size;
1977                 } else
1978                         opt_w = TRUE;
1979         }
1980 
1981         /*
1982          * Window-mode doesn't make sense in a loop.
1983          */
1984         if (flags & DCMD_LOOP)
1985                 opt_w = FALSE;
1986 
1987         /*
1988          * If -n was explicit, limit output to n instructions;
1989          * otherwise set n to some reasonable default
1990          */
1991         if (n != -1UL)
1992                 eaddr = 0;
1993         else
1994                 n = 10;
1995 
1996         /*
1997          * If the state is IDLE (i.e. no address space), turn on -f.
1998          */
1999         if (mdb_tgt_status(tgt, &st) == 0 && st.st_state == MDB_TGT_IDLE)
2000                 opt_f = TRUE;
2001 
2002         if (opt_f)
2003                 as = MDB_TGT_AS_FILE;
2004         else
2005                 as = MDB_TGT_AS_VIRT;
2006 
2007         if (opt_w == FALSE) {
2008                 n++;
2009                 while ((eaddr == 0 && n-- != 0) || (addr < eaddr)) {
2010                         naddr = mdb_dis_ins2str(dis, tgt, as,
2011                             buf, sizeof (buf), addr);
2012                         if (naddr == addr)
2013                                 return (DCMD_ERR);
2014                         if (opt_a)
2015                                 mdb_printf("%-#32p%8T%s\n", addr, buf);
2016                         else if (opt_b)
2017                                 mdb_printf("%-#10p%-#32a%8T%s\n",
2018                                     addr, addr, buf);
2019                         else
2020                                 mdb_printf("%-#32a%8T%s\n", addr, buf);
2021                         addr = naddr;
2022                 }
2023 
2024         } else {
2025 #ifdef __sparc
2026                 if (addr & 0x3) {
2027                         mdb_warn("address is not properly aligned\n");
2028                         return (DCMD_ERR);
2029                 }
2030 #endif
2031 
2032                 for (oaddr = mdb_dis_previns(dis, tgt, as, addr, n);
2033                     oaddr < addr; oaddr = naddr) {
2034                         naddr = mdb_dis_ins2str(dis, tgt, as,
2035                             buf, sizeof (buf), oaddr);
2036                         if (naddr == oaddr)
2037                                 return (DCMD_ERR);
2038                         if (opt_a)
2039                                 mdb_printf("%-#32p%8T%s\n", oaddr, buf);
2040                         else if (opt_b)
2041                                 mdb_printf("%-#10p%-#32a%8T%s\n",
2042                                     oaddr, oaddr, buf);
2043                         else
2044                                 mdb_printf("%-#32a%8T%s\n", oaddr, buf);
2045                 }
2046 
2047                 if ((naddr = mdb_dis_ins2str(dis, tgt, as,
2048                     buf, sizeof (buf), addr)) == addr)
2049                         return (DCMD_ERR);
2050 
2051                 mdb_printf("%<b>");
2052                 mdb_flush();
2053                 if (opt_a)
2054                         mdb_printf("%-#32p%8T%s%", addr, buf);
2055                 else if (opt_b)
2056                         mdb_printf("%-#10p%-#32a%8T%s", addr, addr, buf);
2057                 else
2058                         mdb_printf("%-#32a%8T%s%", addr, buf);
2059                 mdb_printf("%</b>\n");
2060 
2061                 for (addr = naddr; n-- != 0; addr = naddr) {
2062                         naddr = mdb_dis_ins2str(dis, tgt, as,
2063                             buf, sizeof (buf), addr);
2064                         if (naddr == addr)
2065                                 return (DCMD_ERR);
2066                         if (opt_a)
2067                                 mdb_printf("%-#32p%8T%s\n", addr, buf);
2068                         else if (opt_b)
2069                                 mdb_printf("%-#10p%-#32a%8T%s\n",
2070                                     addr, addr, buf);
2071                         else
2072                                 mdb_printf("%-#32a%8T%s\n", addr, buf);
2073                 }
2074         }
2075 
2076         mdb_set_dot(addr);
2077         return (DCMD_OK);
2078 }
2079 
2080 /*ARGSUSED*/
2081 static int
2082 walk_step(uintptr_t addr, const void *data, void *private)
2083 {
2084         mdb_printf("%#lr\n", addr);
2085         return (WALK_NEXT);
2086 }
2087 
2088 static int
2089 cmd_walk(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2090 {
2091         int status;
2092 
2093         if (argc < 1 || argc > 2 || argv[0].a_type != MDB_TYPE_STRING ||
2094             argv[argc - 1].a_type != MDB_TYPE_STRING)
2095                 return (DCMD_USAGE);
2096 
2097         if (argc > 1) {
2098                 const char *name = argv[1].a_un.a_str;
2099                 mdb_var_t *v = mdb_nv_lookup(&mdb.m_nv, name);
2100                 const char *p;
2101 
2102                 if (v != NULL && (v->v_flags & MDB_NV_RDONLY) != 0) {
2103                         mdb_warn("variable %s is read-only\n", name);
2104                         return (DCMD_ABORT);
2105                 }
2106 
2107                 if (v == NULL && (p = strbadid(name)) != NULL) {
2108                         mdb_warn("'%c' may not be used in a variable "
2109                             "name\n", *p);
2110                         return (DCMD_ABORT);
2111                 }
2112 
2113                 if (v == NULL && (v = mdb_nv_insert(&mdb.m_nv,
2114                     name, NULL, 0, 0)) == NULL)
2115                         return (DCMD_ERR);
2116 
2117                 /*
2118                  * If there already exists a vcb for this variable, we may be
2119                  * calling ::walk in a loop.  We only create a vcb for this
2120                  * variable on the first invocation.
2121                  */
2122                 if (mdb_vcb_find(v, mdb.m_frame) == NULL)
2123                         mdb_vcb_insert(mdb_vcb_create(v), mdb.m_frame);
2124         }
2125 
2126         if (flags & DCMD_ADDRSPEC)
2127                 status = mdb_pwalk(argv->a_un.a_str, walk_step, NULL, addr);
2128         else
2129                 status = mdb_walk(argv->a_un.a_str, walk_step, NULL);
2130 
2131         if (status == -1) {
2132                 mdb_warn("failed to perform walk");
2133                 return (DCMD_ERR);
2134         }
2135 
2136         return (DCMD_OK);
2137 }
2138 
2139 static int
2140 cmd_walk_tab(mdb_tab_cookie_t *mcp, uint_t flags, int argc,
2141     const mdb_arg_t *argv)
2142 {
2143         if (argc > 1)
2144                 return (1);
2145 
2146         if (argc == 1) {
2147                 ASSERT(argv[0].a_type == MDB_TYPE_STRING);
2148                 return (mdb_tab_complete_walker(mcp, argv[0].a_un.a_str));
2149         }
2150 
2151         if (argc == 0 && flags & DCMD_TAB_SPACE)
2152                 return (mdb_tab_complete_walker(mcp, NULL));
2153 
2154         return (1);
2155 }
2156 
2157 static ssize_t
2158 mdb_partial_xread(void *buf, size_t nbytes, uintptr_t addr, void *arg)
2159 {
2160         ssize_t (*fp)(mdb_tgt_t *, const void *, size_t, uintptr_t) =
2161             (ssize_t (*)(mdb_tgt_t *, const void *, size_t, uintptr_t))arg;
2162 
2163         return (fp(mdb.m_target, buf, nbytes, addr));
2164 }
2165 
2166 /* ARGSUSED3 */
2167 static ssize_t
2168 mdb_partial_pread(void *buf, size_t nbytes, physaddr_t addr, void *arg)
2169 {
2170         return (mdb_tgt_pread(mdb.m_target, buf, nbytes, addr));
2171 }
2172 
2173 
2174 static int
2175 cmd_dump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2176 {
2177         uint_t dflags =
2178             MDB_DUMP_ALIGN | MDB_DUMP_NEWDOT | MDB_DUMP_ASCII | MDB_DUMP_HEADER;
2179         uint_t phys = FALSE;
2180         uint_t file = FALSE;
2181         uintptr_t group = 4;
2182         uintptr_t width = 1;
2183         mdb_tgt_status_t st;
2184         int error;
2185 
2186         if (mdb_getopts(argc, argv,
2187             'e', MDB_OPT_SETBITS, MDB_DUMP_ENDIAN, &dflags,
2188             'f', MDB_OPT_SETBITS, TRUE, &file,
2189             'g', MDB_OPT_UINTPTR, &group,
2190             'p', MDB_OPT_SETBITS, TRUE, &phys,
2191             'q', MDB_OPT_CLRBITS, MDB_DUMP_ASCII, &dflags,
2192             'r', MDB_OPT_SETBITS, MDB_DUMP_RELATIVE, &dflags,
2193             's', MDB_OPT_SETBITS, MDB_DUMP_SQUISH, &dflags,
2194             't', MDB_OPT_SETBITS, MDB_DUMP_TRIM, &dflags,
2195             'u', MDB_OPT_CLRBITS, MDB_DUMP_ALIGN, &dflags,
2196             'v', MDB_OPT_SETBITS, MDB_DUMP_PEDANT, &dflags,
2197             'w', MDB_OPT_UINTPTR, &width, NULL) != argc)
2198                 return (DCMD_USAGE);
2199 
2200         if ((phys && file) ||
2201             (width == 0) || (width > 0x10) ||
2202             (group == 0) || (group > 0x100))
2203                 return (DCMD_USAGE);
2204 
2205         /*
2206          * If neither -f nor -p were specified and the state is IDLE (i.e. no
2207          * address space), turn on -p.  This is so we can read large files.
2208          */
2209         if (phys == FALSE && file == FALSE && mdb_tgt_status(mdb.m_target,
2210             &st) == 0 && st.st_state == MDB_TGT_IDLE)
2211                 phys = TRUE;
2212 
2213         dflags |= MDB_DUMP_GROUP(group) | MDB_DUMP_WIDTH(width);
2214         if (phys)
2215                 error = mdb_dump64(mdb_get_dot(), mdb.m_dcount, dflags,
2216                     mdb_partial_pread, NULL);
2217         else if (file)
2218                 error = mdb_dumpptr(addr, mdb.m_dcount, dflags,
2219                     mdb_partial_xread, (void *)mdb_tgt_fread);
2220         else
2221                 error = mdb_dumpptr(addr, mdb.m_dcount, dflags,
2222                     mdb_partial_xread, (void *)mdb_tgt_vread);
2223 
2224         return (((flags & DCMD_LOOP) || (error == -1)) ? DCMD_ABORT : DCMD_OK);
2225 }
2226 
2227 /*ARGSUSED*/
2228 static int
2229 cmd_echo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2230 {
2231         if (flags & DCMD_ADDRSPEC)
2232                 return (DCMD_USAGE);
2233 
2234         for (; argc-- != 0; argv++) {
2235                 if (argv->a_type == MDB_TYPE_STRING)
2236                         mdb_printf("%s ", argv->a_un.a_str);
2237                 else
2238                         mdb_printf("%llr ", argv->a_un.a_val);
2239         }
2240 
2241         mdb_printf("\n");
2242         return (DCMD_OK);
2243 }
2244 
2245 /*ARGSUSED*/
2246 static int
2247 cmd_head(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2248 {
2249         uint64_t cnt = 10;
2250         const char *c;
2251         mdb_pipe_t p;
2252 
2253         if (!flags & DCMD_PIPE)
2254                 return (DCMD_USAGE);
2255 
2256         if (argc == 1 || argc == 2) {
2257                 const char *num;
2258 
2259                 if (argc == 1) {
2260                         if (argv[0].a_type != MDB_TYPE_STRING ||
2261                             *argv[0].a_un.a_str != '-')
2262                                 return (DCMD_USAGE);
2263 
2264                         num = argv[0].a_un.a_str + 1;
2265 
2266                 } else {
2267                         if (argv[0].a_type != MDB_TYPE_STRING ||
2268                             strcmp(argv[0].a_un.a_str, "-n") != 0)
2269                                 return (DCMD_USAGE);
2270 
2271                         num = argv[1].a_un.a_str;
2272                 }
2273 
2274                 for (cnt = 0, c = num; *c != '\0' && isdigit(*c); c++)
2275                         cnt = cnt * 10 + (*c - '0');
2276 
2277                 if (*c != '\0')
2278                         return (DCMD_USAGE);
2279 
2280         } else if (argc != 0) {
2281                 return (DCMD_USAGE);
2282         }
2283 
2284         mdb_get_pipe(&p);
2285 
2286         if (p.pipe_data == NULL)
2287                 return (DCMD_OK);
2288         p.pipe_len = MIN(p.pipe_len, cnt);
2289 
2290         if (flags & DCMD_PIPE_OUT) {
2291                 mdb_set_pipe(&p);
2292         } else {
2293                 while (p.pipe_len-- > 0)
2294                         mdb_printf("%lx\n", *p.pipe_data++);
2295         }
2296 
2297         return (DCMD_OK);
2298 }
2299 
2300 static void
2301 head_help(void)
2302 {
2303         mdb_printf(
2304             "-n num\n or\n"
2305             "-num   pass only the first `num' elements in the pipe.\n"
2306             "\n%<b>Note:%</b> `num' is a decimal number.\n");
2307 }
2308 
2309 static int
2310 cmd_typeset(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2311 {
2312         int add_tag = 0, del_tag = 0;
2313         const char *p;
2314         mdb_var_t *v;
2315 
2316         if (argc == 0)
2317                 return (cmd_vars(addr, flags, argc, argv));
2318 
2319         if (argv->a_type == MDB_TYPE_STRING && (argv->a_un.a_str[0] == '-' ||
2320             argv->a_un.a_str[0] == '+')) {
2321                 if (argv->a_un.a_str[1] != 't')
2322                         return (DCMD_USAGE);
2323                 if (argv->a_un.a_str[0] == '-')
2324                         add_tag++;
2325                 else
2326                         del_tag++;
2327                 argc--;
2328                 argv++;
2329         }
2330 
2331         if (!(flags & DCMD_ADDRSPEC))
2332                 addr = 0; /* set variables to zero unless explicit addr given */
2333 
2334         for (; argc-- != 0; argv++) {
2335                 if (argv->a_type != MDB_TYPE_STRING)
2336                         continue;
2337 
2338                 if (argv->a_un.a_str[0] == '-' || argv->a_un.a_str[0] == '+') {
2339                         mdb_warn("ignored bad option -- %s\n",
2340                             argv->a_un.a_str);
2341                         continue;
2342                 }
2343 
2344                 if ((p = strbadid(argv->a_un.a_str)) != NULL) {
2345                         mdb_warn("'%c' may not be used in a variable "
2346                             "name\n", *p);
2347                         return (DCMD_ERR);
2348                 }
2349 
2350                 if ((v = mdb_nv_lookup(&mdb.m_nv, argv->a_un.a_str)) == NULL) {
2351                         v = mdb_nv_insert(&mdb.m_nv, argv->a_un.a_str,
2352                             NULL, addr, 0);
2353                 } else if (flags & DCMD_ADDRSPEC)
2354                         mdb_nv_set_value(v, addr);
2355 
2356                 if (v != NULL) {
2357                         if (add_tag)
2358                                 v->v_flags |= MDB_NV_TAGGED;
2359                         if (del_tag)
2360                                 v->v_flags &= ~MDB_NV_TAGGED;
2361                 }
2362         }
2363 
2364         return (DCMD_OK);
2365 }
2366 
2367 #ifndef _KMDB
2368 /*ARGSUSED*/
2369 static int
2370 cmd_context(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2371 {
2372         if (argc != 0 || !(flags & DCMD_ADDRSPEC))
2373                 return (DCMD_USAGE);
2374 
2375         if (mdb_tgt_setcontext(mdb.m_target, (void *)addr) == 0)
2376                 return (DCMD_OK);
2377 
2378         return (DCMD_ERR);
2379 }
2380 #endif
2381 
2382 /*ARGSUSED*/
2383 static int
2384 cmd_prompt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2385 {
2386         const char *p = "";
2387 
2388         if (argc != 0) {
2389                 if (argc > 1 || argv->a_type != MDB_TYPE_STRING)
2390                         return (DCMD_USAGE);
2391                 p = argv->a_un.a_str;
2392         }
2393 
2394         (void) mdb_set_prompt(p);
2395         return (DCMD_OK);
2396 }
2397 
2398 /*ARGSUSED*/
2399 static int
2400 cmd_term(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2401 {
2402         mdb_printf("%s\n", mdb.m_termtype);
2403 
2404         return (DCMD_OK);
2405 }
2406 
2407 /*ARGSUSED*/
2408 static int
2409 cmd_vtop(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2410 {
2411         physaddr_t pa;
2412         mdb_tgt_as_t as = MDB_TGT_AS_VIRT;
2413 
2414         if (mdb_getopts(argc, argv, 'a', MDB_OPT_UINTPTR, (uintptr_t *)&as,
2415             NULL) != argc)
2416                 return (DCMD_USAGE);
2417 
2418         if (mdb_tgt_vtop(mdb.m_target, as, addr, &pa) == -1) {
2419                 mdb_warn("failed to get physical mapping");
2420                 return (DCMD_ERR);
2421         }
2422 
2423         if (flags & DCMD_PIPE_OUT)
2424                 mdb_printf("%llr\n", pa);
2425         else
2426                 mdb_printf("virtual %lr mapped to physical %llr\n", addr, pa);
2427         return (DCMD_OK);
2428 }
2429 
2430 #define EVENTS_OPT_A    0x1     /* ::events -a (show all events) */
2431 #define EVENTS_OPT_V    0x2     /* ::events -v (verbose display) */
2432 
2433 static const char *
2434 event_action(const mdb_tgt_spec_desc_t *sp)
2435 {
2436         if (!(sp->spec_flags & MDB_TGT_SPEC_HIDDEN) && sp->spec_data != NULL)
2437                 return (sp->spec_data);
2438 
2439         return ("-");
2440 }
2441 
2442 static void
2443 print_evsep(void)
2444 {
2445         static const char dash20[] = "--------------------";
2446         mdb_printf("----- - -- -- -- %s%s --%s\n", dash20, dash20, dash20);
2447 }
2448 
2449 /*ARGSUSED*/
2450 static int
2451 print_event(mdb_tgt_t *t, void *private, int vid, void *data)
2452 {
2453         uint_t opts = (uint_t)(uintptr_t)private;
2454         mdb_tgt_spec_desc_t sp;
2455         char s1[41], s2[22];
2456         const char *s2str;
2457         int visible;
2458 
2459         (void) mdb_tgt_vespec_info(t, vid, &sp, s1, sizeof (s1));
2460         visible = !(sp.spec_flags & (MDB_TGT_SPEC_HIDDEN|MDB_TGT_SPEC_DELETED));
2461 
2462         if ((opts & EVENTS_OPT_A) || visible) {
2463                 int encoding = (!(sp.spec_flags & MDB_TGT_SPEC_DISABLED)) |
2464                     (!(sp.spec_flags & MDB_TGT_SPEC_MATCHED) << 1);
2465 
2466                 char ldelim = "<<(["[encoding];
2467                 char rdelim = ">>)]"[encoding];
2468 
2469                 char state = "0-+*!"[sp.spec_state];
2470 
2471                 char tflag = "T "[!(sp.spec_flags & MDB_TGT_SPEC_STICKY)];
2472                 char aflag = "d "[!(sp.spec_flags & MDB_TGT_SPEC_AUTODIS)];
2473 
2474                 if (sp.spec_flags & MDB_TGT_SPEC_TEMPORARY)
2475                         tflag = 't'; /* TEMP takes precedence over STICKY */
2476                 if (sp.spec_flags & MDB_TGT_SPEC_AUTODEL)
2477                         aflag = 'D'; /* AUTODEL takes precedence over AUTODIS */
2478                 if (sp.spec_flags & MDB_TGT_SPEC_AUTOSTOP)
2479                         aflag = 's'; /* AUTOSTOP takes precedence over both */
2480 
2481                 if (opts & EVENTS_OPT_V) {
2482                         if (sp.spec_state == MDB_TGT_SPEC_IDLE ||
2483                             sp.spec_state == MDB_TGT_SPEC_ERROR)
2484                                 s2str = mdb_strerror(sp.spec_errno);
2485                         else
2486                                 s2str = "-";
2487                 } else
2488                         s2str = event_action(&sp);
2489 
2490                 if (mdb_snprintf(s2, sizeof (s2), "%s", s2str) >= sizeof (s2))
2491                         (void) strabbr(s2, sizeof (s2));
2492 
2493                 if (vid > -10 && vid < 10)
2494                         mdb_printf("%c%2d %c", ldelim, vid, rdelim);
2495                 else
2496                         mdb_printf("%c%3d%c", ldelim, vid, rdelim);
2497 
2498                 mdb_printf(" %c %c%c %2u %2u %-40s %-21s\n",
2499                     state, tflag, aflag, sp.spec_hits, sp.spec_limit, s1, s2);
2500 
2501                 if (opts & EVENTS_OPT_V) {
2502                         mdb_printf("%-17s%s\n", "", event_action(&sp));
2503                         print_evsep();
2504                 }
2505         }
2506 
2507         return (0);
2508 }
2509 
2510 /*ARGSUSED*/
2511 static int
2512 cmd_events(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2513 {
2514         uint_t opts = 0;
2515 
2516         if ((flags & DCMD_ADDRSPEC) || mdb_getopts(argc, argv,
2517             'a', MDB_OPT_SETBITS, EVENTS_OPT_A, &opts,
2518             'v', MDB_OPT_SETBITS, EVENTS_OPT_V, &opts, NULL) != argc)
2519                 return (DCMD_USAGE);
2520 
2521 
2522         if (opts & EVENTS_OPT_V) {
2523                 mdb_printf("   ID S TA HT LM %-40s %-21s\n%-17s%s\n",
2524                     "Description", "Status", "", "Action");
2525         } else {
2526                 mdb_printf("   ID S TA HT LM %-40s %-21s\n",
2527                     "Description", "Action");
2528         }
2529 
2530         print_evsep();
2531         return (mdb_tgt_vespec_iter(mdb.m_target, print_event,
2532             (void *)(uintptr_t)opts));
2533 }
2534 
2535 static int
2536 tgt_status(const mdb_tgt_status_t *tsp)
2537 {
2538         const char *format;
2539         char buf[BUFSIZ];
2540 
2541         if (tsp->st_flags & MDB_TGT_BUSY)
2542                 return (DCMD_OK);
2543 
2544         if (tsp->st_pc != 0) {
2545                 if (mdb_dis_ins2str(mdb.m_disasm, mdb.m_target, MDB_TGT_AS_VIRT,
2546                     buf, sizeof (buf), tsp->st_pc) != tsp->st_pc)
2547                         format = "target stopped at:\n%-#16a%8T%s\n";
2548                 else
2549                         format = "target stopped at %a:\n";
2550                 mdb_warn(format, tsp->st_pc, buf);
2551         }
2552 
2553         switch (tsp->st_state) {
2554         case MDB_TGT_IDLE:
2555                 mdb_warn("target is idle\n");
2556                 break;
2557         case MDB_TGT_RUNNING:
2558                 if (tsp->st_flags & MDB_TGT_DSTOP)
2559                         mdb_warn("target is running, stop directive pending\n");
2560                 else
2561                         mdb_warn("target is running\n");
2562                 break;
2563         case MDB_TGT_STOPPED:
2564                 if (tsp->st_pc == 0)
2565                         mdb_warn("target is stopped\n");
2566                 break;
2567         case MDB_TGT_UNDEAD:
2568                 mdb_warn("target has terminated\n");
2569                 break;
2570         case MDB_TGT_DEAD:
2571                 mdb_warn("target is a core dump\n");
2572                 break;
2573         case MDB_TGT_LOST:
2574                 mdb_warn("target is no longer under debugger control\n");
2575                 break;
2576         }
2577 
2578         mdb_set_dot(tsp->st_pc);
2579         return (DCMD_OK);
2580 }
2581 
2582 /*
2583  * mdb continue/step commands take an optional signal argument, but the
2584  * corresponding kmdb versions don't.
2585  */
2586 #ifdef _KMDB
2587 #define CONT_MAXARGS    0       /* no optional SIG argument */
2588 #else
2589 #define CONT_MAXARGS    1
2590 #endif
2591 
2592 /*ARGSUSED*/
2593 static int
2594 cmd_cont_common(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv,
2595     int (*t_cont)(mdb_tgt_t *, mdb_tgt_status_t *), const char *name)
2596 {
2597         mdb_tgt_t *t = mdb.m_target;
2598         mdb_tgt_status_t st;
2599         int sig = 0;
2600 
2601         if ((flags & DCMD_ADDRSPEC) || argc > CONT_MAXARGS)
2602                 return (DCMD_USAGE);
2603 
2604         if (argc > 0) {
2605                 if (argv->a_type == MDB_TYPE_STRING) {
2606                         if (proc_str2sig(argv->a_un.a_str, &sig) == -1) {
2607                                 mdb_warn("invalid signal name -- %s\n",
2608                                     argv->a_un.a_str);
2609                                 return (DCMD_USAGE);
2610                         }
2611                 } else
2612                         sig = (int)(intmax_t)argv->a_un.a_val;
2613         }
2614 
2615         (void) mdb_tgt_status(t, &st);
2616 
2617         if (st.st_state == MDB_TGT_IDLE && mdb_tgt_run(t, 0, NULL) == -1) {
2618                 if (errno != EMDB_TGT)
2619                         mdb_warn("failed to create new target");
2620                 return (DCMD_ERR);
2621         }
2622 
2623         if (sig != 0 && mdb_tgt_signal(t, sig) == -1) {
2624                 mdb_warn("failed to post signal %d", sig);
2625                 return (DCMD_ERR);
2626         }
2627 
2628         if (st.st_state == MDB_TGT_IDLE && t_cont == &mdb_tgt_step) {
2629                 (void) mdb_tgt_status(t, &st);
2630                 return (tgt_status(&st));
2631         }
2632 
2633         if (t_cont(t, &st) == -1) {
2634                 if (errno != EMDB_TGT)
2635                         mdb_warn("failed to %s target", name);
2636                 return (DCMD_ERR);
2637         }
2638 
2639         return (tgt_status(&st));
2640 }
2641 
2642 static int
2643 cmd_step(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2644 {
2645         int (*func)(mdb_tgt_t *, mdb_tgt_status_t *) = &mdb_tgt_step;
2646         const char *name = "single-step";
2647 
2648         if (argc > 0 && argv->a_type == MDB_TYPE_STRING) {
2649                 if (strcmp(argv->a_un.a_str, "out") == 0) {
2650                         func = &mdb_tgt_step_out;
2651                         name = "step (out)";
2652                         argv++;
2653                         argc--;
2654                 } else if (strcmp(argv->a_un.a_str, "branch") == 0) {
2655                         func = &mdb_tgt_step_branch;
2656                         name = "step (branch)";
2657                         argv++;
2658                         argc--;
2659                 } else if (strcmp(argv->a_un.a_str, "over") == 0) {
2660                         func = &mdb_tgt_next;
2661                         name = "step (over)";
2662                         argv++;
2663                         argc--;
2664                 }
2665         }
2666 
2667         return (cmd_cont_common(addr, flags, argc, argv, func, name));
2668 }
2669 
2670 static int
2671 cmd_step_out(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2672 {
2673         return (cmd_cont_common(addr, flags, argc, argv,
2674             &mdb_tgt_step_out, "step (out)"));
2675 }
2676 
2677 static int
2678 cmd_next(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2679 {
2680         return (cmd_cont_common(addr, flags, argc, argv,
2681             &mdb_tgt_next, "step (over)"));
2682 }
2683 
2684 static int
2685 cmd_cont(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2686 {
2687         return (cmd_cont_common(addr, flags, argc, argv,
2688             &mdb_tgt_continue, "continue"));
2689 }
2690 
2691 #ifndef _KMDB
2692 /*ARGSUSED*/
2693 static int
2694 cmd_run(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2695 {
2696         if (flags & DCMD_ADDRSPEC)
2697                 return (DCMD_USAGE);
2698 
2699         if (mdb_tgt_run(mdb.m_target, argc, argv) == -1) {
2700                 if (errno != EMDB_TGT)
2701                         mdb_warn("failed to create new target");
2702                 return (DCMD_ERR);
2703         }
2704         return (cmd_cont(NULL, 0, 0, NULL));
2705 }
2706 #endif
2707 
2708 /*
2709  * To simplify the implementation of :d, :z, and ::delete, we use the sp
2710  * parameter to store the criteria for what to delete.  If spec_base is set,
2711  * we delete vespecs with a matching address.  If spec_id is set, we delete
2712  * vespecs with a matching id.  Otherwise, we delete all vespecs.  We bump
2713  * sp->spec_size so the caller can tell how many vespecs were deleted.
2714  */
2715 static int
2716 ve_delete(mdb_tgt_t *t, mdb_tgt_spec_desc_t *sp, int vid, void *data)
2717 {
2718         mdb_tgt_spec_desc_t spec;
2719         int status = -1;
2720 
2721         if (vid < 0)
2722                 return (0); /* skip over target implementation events */
2723 
2724         if (sp->spec_base != NULL) {
2725                 (void) mdb_tgt_vespec_info(t, vid, &spec, NULL, 0);
2726                 if (sp->spec_base - spec.spec_base < spec.spec_size)
2727                         status = mdb_tgt_vespec_delete(t, vid);
2728         } else if (sp->spec_id == 0) {
2729                 (void) mdb_tgt_vespec_info(t, vid, &spec, NULL, 0);
2730                 if (!(spec.spec_flags & MDB_TGT_SPEC_STICKY))
2731                         status = mdb_tgt_vespec_delete(t, vid);
2732         } else if (sp->spec_id == vid)
2733                 status = mdb_tgt_vespec_delete(t, vid);
2734 
2735         if (status == 0) {
2736                 if (data != NULL)
2737                         strfree(data);
2738                 sp->spec_size++;
2739         }
2740 
2741         return (0);
2742 }
2743 
2744 static int
2745 ve_delete_spec(mdb_tgt_spec_desc_t *sp)
2746 {
2747         (void) mdb_tgt_vespec_iter(mdb.m_target,
2748             (mdb_tgt_vespec_f *)ve_delete, sp);
2749 
2750         if (sp->spec_size == 0) {
2751                 if (sp->spec_id != 0 || sp->spec_base != NULL)
2752                         mdb_warn("no traced events matched description\n");
2753         }
2754 
2755         return (DCMD_OK);
2756 }
2757 
2758 /*ARGSUSED*/
2759 static int
2760 cmd_zapall(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2761 {
2762         mdb_tgt_spec_desc_t spec;
2763 
2764         if ((flags & DCMD_ADDRSPEC) || argc != 0)
2765                 return (DCMD_USAGE);
2766 
2767         bzero(&spec, sizeof (spec));
2768         return (ve_delete_spec(&spec));
2769 }
2770 
2771 static int
2772 cmd_delete(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2773 {
2774         mdb_tgt_spec_desc_t spec;
2775 
2776         if (((flags & DCMD_ADDRSPEC) && argc > 0) || argc > 1)
2777                 return (DCMD_USAGE);
2778 
2779         bzero(&spec, sizeof (spec));
2780 
2781         if (flags & DCMD_ADDRSPEC)
2782                 spec.spec_base = addr;
2783         else if (argc == 0)
2784                 spec.spec_base = mdb_get_dot();
2785         else if (argv->a_type == MDB_TYPE_STRING &&
2786             strcmp(argv->a_un.a_str, "all") != 0)
2787                 spec.spec_id = (int)(intmax_t)strtonum(argv->a_un.a_str, 10);
2788         else if (argv->a_type == MDB_TYPE_IMMEDIATE)
2789                 spec.spec_id = (int)(intmax_t)argv->a_un.a_val;
2790 
2791         return (ve_delete_spec(&spec));
2792 }
2793 
2794 static void
2795 srcexec_file_help(void)
2796 {
2797         mdb_printf(
2798 "The library of macros delivered with previous versions of Solaris have been\n"
2799 "superseded by the dcmds and walkers provided by MDB.  See ::help for\n"
2800 "commands that can be used to list the available dcmds and walkers.\n"
2801 "\n"
2802 "Aliases have been created for several of the more popular macros.  To see\n"
2803 "the list of aliased macros, as well as their native MDB equivalents,\n"
2804 "type $M.\n");
2805 
2806 #ifdef _KMDB
2807         mdb_printf(
2808 "When invoked, the $< and $<< dcmds will consult the macro alias list.  If an\n"
2809 "alias cannot be found, an attempt will be made to locate a data type whose\n"
2810 "name corresponds to the requested macro.  If such a type can be found, it\n"
2811 "will be displayed using the ::print dcmd.\n");
2812 #else
2813         mdb_printf(
2814 "When invoked, the $< and $<< dcmds will first attempt to locate a macro with\n"
2815 "the indicated name.  If no macro can be found, and if no alias exists for\n"
2816 "this macro, an attempt will be made to locate a data type whose name\n"
2817 "corresponds to the requested macro.  If such a type can be found, it will be\n"
2818 "displayed using the ::print dcmd.\n");
2819 #endif
2820 }
2821 
2822 static void
2823 events_help(void)
2824 {
2825         mdb_printf("Options:\n"
2826             "-a       show all events, including internal debugger events\n"
2827             "-v       show verbose display, including inactivity reason\n"
2828             "\nOutput Columns:\n"
2829             "ID       decimal event specifier id number:\n"
2830             "    [ ]  event tracing is enabled\n"
2831             "    ( )  event tracing is disabled\n"
2832             "    < >  target is currently stopped on this type of event\n\n"
2833             "S        event specifier state:\n"
2834             "     -   event specifier is idle (not applicable yet)\n"
2835             "     +   event specifier is active\n"
2836             "     *   event specifier is armed (target program running)\n"
2837             "     !   error occurred while attempting to arm event\n\n"
2838             "TA       event specifier flags:\n"
2839             "     t   event specifier is temporary (delete at next stop)\n"
2840             "     T   event specifier is sticky (::delete all has no effect)\n"
2841             "     d   event specifier will be disabled when HT = LM\n"
2842             "     D   event specifier will be deleted when HT = LM\n"
2843             "     s   target will automatically stop when HT = LM\n\n"
2844             "HT       hit count (number of times event has occurred)\n"
2845             "LM       hit limit (limit for autostop, disable, delete)\n");
2846 }
2847 
2848 static void
2849 dump_help(void)
2850 {
2851         mdb_printf(
2852             "-e    adjust for endianness\n"
2853             "      (assumes 4-byte words; use -g to change word size)\n"
2854 #ifdef _KMDB
2855             "-f    no effect\n"
2856 #else
2857             "-f    dump from object file\n"
2858 #endif
2859             "-g n  display bytes in groups of n\n"
2860             "      (default is 4; n must be a power of 2, divide line width)\n"
2861             "-p    dump from physical memory\n"
2862             "-q    don't print ASCII\n"
2863             "-r    use relative numbering (automatically sets -u)\n"
2864             "-s    elide repeated lines\n"
2865             "-t    only read from and display contents of specified addresses\n"
2866             "      (default is to read and print entire lines)\n"
2867             "-u    un-align output\n"
2868             "      (default is to align output at paragraph boundary)\n"
2869             "-w n  display n 16-byte paragraphs per line\n"
2870             "      (default is 1, maximum is 16)\n");
2871 }
2872 
2873 /*
2874  * Table of built-in dcmds associated with the root 'mdb' module.  Future
2875  * expansion of this program should be done here, or through the external
2876  * loadable module interface.
2877  */
2878 const mdb_dcmd_t mdb_dcmd_builtins[] = {
2879 
2880         /*
2881          * dcmds common to both mdb and kmdb
2882          */
2883         { ">", "variable-name", "assign variable", cmd_assign_variable },
2884         { "/", "fmt-list", "format data from virtual as", cmd_print_core },
2885         { "\\", "fmt-list", "format data from physical as", cmd_print_phys },
2886         { "@", "fmt-list", "format data from physical as", cmd_print_phys },
2887         { "=", "fmt-list", "format immediate value", cmd_print_value },
2888         { "$<", "macro-name", "replace input with macro",
2889             cmd_exec_file, srcexec_file_help },
2890         { "$<<", "macro-name", "source macro",
2891             cmd_src_file, srcexec_file_help},
2892         { "$%", NULL, NULL, cmd_quit },
2893         { "$?", NULL, "print status and registers", cmd_notsup },
2894         { "$a", NULL, NULL, cmd_algol },
2895         { "$b", "[-av]", "list traced software events",
2896             cmd_events, events_help },
2897         { "$c", "?[cnt]", "print stack backtrace", cmd_notsup },
2898         { "$C", "?[cnt]", "print stack backtrace", cmd_notsup },
2899         { "$d", NULL, "get/set default output radix", cmd_radix },
2900         { "$D", "?[mode,...]", NULL, cmd_dbmode },
2901         { "$e", NULL, "print listing of global symbols", cmd_globals },
2902         { "$f", NULL, "print listing of source files", cmd_files },
2903         { "$m", "?[name]", "print address space mappings", cmd_mappings },
2904         { "$M", NULL, "list macro aliases", cmd_macalias_list },
2905         { "$P", "[prompt]", "set debugger prompt string", cmd_prompt },
2906         { "$q", NULL, "quit debugger", cmd_quit },
2907         { "$Q", NULL, "quit debugger", cmd_quit },
2908         { "$r", NULL, "print general-purpose registers", cmd_notsup },
2909         { "$s", NULL, "get/set symbol matching distance", cmd_symdist },
2910         { "$v", NULL, "print non-zero variables", cmd_nzvars },
2911         { "$V", "[mode]", "get/set disassembly mode", cmd_dismode },
2912         { "$w", NULL, "get/set output page width", cmd_pgwidth },
2913         { "$W", NULL, "re-open target in write mode", cmd_reopen },
2914         { ":a", ":[cmd...]", "set read access watchpoint", cmd_oldwpr },
2915         { ":b", ":[cmd...]", "breakpoint at the specified address", cmd_oldbp },
2916         { ":d", "?[id|all]", "delete traced software events", cmd_delete },
2917         { ":p", ":[cmd...]", "set execute access watchpoint", cmd_oldwpx },
2918         { ":S", NULL, NULL, cmd_step },
2919         { ":w", ":[cmd...]", "set write access watchpoint", cmd_oldwpw },
2920         { ":z", NULL, "delete all traced software events", cmd_zapall },
2921         { "array", ":[type count] [variable]", "print each array element's "
2922             "address", cmd_array },
2923         { "bp", "?[+/-dDestT] [-c cmd] [-n count] sym ...", "breakpoint at the "
2924             "specified addresses or symbols", cmd_bp, bp_help },
2925         { "dcmds", NULL, "list available debugger commands", cmd_dcmds },
2926         { "delete", "?[id|all]", "delete traced software events", cmd_delete },
2927         { "dis", "?[-abfw] [-n cnt] [addr]", "disassemble near addr", cmd_dis },
2928         { "disasms", NULL, "list available disassemblers", cmd_disasms },
2929         { "dismode", "[mode]", "get/set disassembly mode", cmd_dismode },
2930         { "dmods", "[-l] [mod]", "list loaded debugger modules", cmd_dmods },
2931         { "dump", "?[-eqrstu] [-f|-p] [-g bytes] [-w paragraphs]",
2932             "dump memory from specified address", cmd_dump, dump_help },
2933         { "echo", "args ...", "echo arguments", cmd_echo },
2934         { "enum", "?[-ex] enum [name]", "print an enumeration", cmd_enum,
2935             enum_help },
2936         { "eval", "command", "evaluate the specified command", cmd_eval },
2937         { "events", "[-av]", "list traced software events",
2938             cmd_events, events_help },
2939         { "evset", "?[+/-dDestT] [-c cmd] [-n count] id ...",
2940             "set software event specifier attributes", cmd_evset, evset_help },
2941         { "files", "[object]", "print listing of source files", cmd_files },
2942 #ifdef __sparc
2943         { "findsym", "?[-g] [symbol|addr ...]", "search for symbol references "
2944             "in all known functions", cmd_findsym, NULL },
2945 #endif
2946         { "formats", NULL, "list format specifiers", cmd_formats },
2947         { "grep", "?expr", "print dot if expression is true", cmd_grep },
2948         { "head", "-num|-n num", "limit number of elements in pipe", cmd_head,
2949             head_help },
2950         { "help", "[cmd]", "list commands/command help", cmd_help },
2951         { "list", "?type member [variable]",
2952             "walk list using member as link pointer", cmd_list, NULL,
2953             mdb_tab_complete_mt },
2954         { "map", "?expr", "print dot after evaluating expression", cmd_map },
2955         { "mappings", "?[name]", "print address space mappings", cmd_mappings },
2956         { "nm", "?[-DPdghnopuvx] [-f format] [-t types] [object]",
2957             "print symbols", cmd_nm, nm_help },
2958         { "nmadd", ":[-fo] [-e end] [-s size] name",
2959             "add name to private symbol table", cmd_nmadd, nmadd_help },
2960         { "nmdel", "name", "remove name from private symbol table", cmd_nmdel },
2961         { "obey", NULL, NULL, cmd_obey },
2962         { "objects", "[-v]", "print load objects information", cmd_objects },
2963         { "offsetof", "type member", "print the offset of a given struct "
2964             "or union member", cmd_offsetof, NULL, mdb_tab_complete_mt },
2965         { "print", "?[-aCdhiLptx] [-c lim] [-l lim] [type] [member|offset ...]",
2966             "print the contents of a data structure", cmd_print, print_help,
2967             cmd_print_tab },
2968         { "printf", "?format type member ...", "print and format the "
2969             "member(s) of a data structure", cmd_printf, printf_help },
2970         { "regs", NULL, "print general purpose registers", cmd_notsup },
2971         { "set", "[-wF] [+/-o opt] [-s dist] [-I path] [-L path] [-P prompt]",
2972             "get/set debugger properties", cmd_set },
2973         { "showrev", "[-pv]", "print version information", cmd_showrev },
2974         { "sizeof", "type", "print the size of a type", cmd_sizeof, NULL,
2975             cmd_sizeof_tab },
2976         { "stack", "?[cnt]", "print stack backtrace", cmd_notsup },
2977         { "stackregs", "?", "print stack backtrace and registers",
2978             cmd_notsup },
2979         { "status", NULL, "print summary of current target", cmd_notsup },
2980         { "term", NULL, "display current terminal type", cmd_term },
2981         { "typeset", "[+/-t] var ...", "set variable attributes", cmd_typeset },
2982         { "typedef", "[-c model | -d | -l | -r file ] [type] [name]",
2983                 "create synthetic types", cmd_typedef, cmd_typedef_help },
2984         { "unset", "[name ...]", "unset variables", cmd_unset },
2985         { "vars", "[-npt]", "print listing of variables", cmd_vars },
2986         { "version", NULL, "print debugger version string", cmd_version },
2987         { "vtop", ":[-a as]", "print physical mapping of virtual address",
2988             cmd_vtop },
2989         { "walk", "?name [variable]", "walk data structure", cmd_walk, NULL,
2990             cmd_walk_tab },
2991         { "walkers", NULL, "list available walkers", cmd_walkers },
2992         { "whatis", ":[-aikqv]", "given an address, return information",
2993             cmd_whatis, whatis_help },
2994         { "whence", "[-v] name ...", "show source of walk or dcmd", cmd_which },
2995         { "which", "[-v] name ...", "show source of walk or dcmd", cmd_which },
2996         { "xdata", NULL, "print list of external data buffers", cmd_xdata },
2997 
2998 #ifdef _KMDB
2999         /*
3000          * dcmds specific to kmdb, or which have kmdb-specific arguments
3001          */
3002         { "?", "fmt-list", "format data from virtual as", cmd_print_core },
3003         { ":c", NULL, "continue target execution", cmd_cont },
3004         { ":e", NULL, "step target over next instruction", cmd_next },
3005         { ":s", NULL, "single-step target to next instruction", cmd_step },
3006         { ":u", NULL, "step target out of current function", cmd_step_out },
3007         { "cont", NULL, "continue target execution", cmd_cont },
3008         { "load", "[-sd] module", "load debugger module", cmd_load, load_help },
3009         { "next", NULL, "step target over next instruction", cmd_next },
3010         { "quit", "[-u]", "quit debugger", cmd_quit, quit_help },
3011         { "step", "[ over | out ]",
3012             "single-step target to next instruction", cmd_step },
3013         { "unload", "[-d] module", "unload debugger module", cmd_unload,
3014             unload_help },
3015         { "wp", ":[+/-dDelstT] [-rwx] [-pi] [-c cmd] [-n count] [-L size]",
3016             "set a watchpoint at the specified address", cmd_wp, wp_help },
3017 
3018 #else
3019         /*
3020          * dcmds specific to mdb, or which have mdb-specific arguments
3021          */
3022         { "?", "fmt-list", "format data from object file", cmd_print_object },
3023         { "$>", "[file]", "log session to a file", cmd_old_log },
3024         { "$g", "?", "get/set C++ demangling options", cmd_demflags },
3025         { "$G", NULL, "enable/disable C++ demangling support", cmd_demangle },
3026         { "$i", NULL, "print signals that are ignored", cmd_notsup },
3027         { "$l", NULL, "print the representative thread's lwp id", cmd_notsup },
3028         { "$p", ":", "change debugger target context", cmd_context },
3029         { "$x", NULL, "print floating point registers", cmd_notsup },
3030         { "$X", NULL, "print floating point registers", cmd_notsup },
3031         { "$y", NULL, "print floating point registers", cmd_notsup },
3032         { "$Y", NULL, "print floating point registers", cmd_notsup },
3033         { ":A", "?[core|pid]", "attach to process or core file", cmd_notsup },
3034         { ":c", "[SIG]", "continue target execution", cmd_cont },
3035         { ":e", "[SIG]", "step target over next instruction", cmd_next },
3036         { ":i", ":", "ignore signal (delete all matching events)", cmd_notsup },
3037         { ":k", NULL, "forcibly kill and release target", cmd_notsup },
3038         { ":t", "?[+/-dDestT] [-c cmd] [-n count] SIG ...", "stop on delivery "
3039             "of the specified signals", cmd_sigbp, sigbp_help },
3040         { ":r", "[ args ... ]", "run a new target process", cmd_run },
3041         { ":R", NULL, "release the previously attached process", cmd_notsup },
3042         { ":s", "[SIG]", "single-step target to next instruction", cmd_step },
3043         { ":u", "[SIG]", "step target out of current function", cmd_step_out },
3044         { "attach", "?[core|pid]",
3045             "attach to process or core file", cmd_notsup },
3046         { "cat", "[file ...]", "concatenate and display files", cmd_cat },
3047         { "cont", "[SIG]", "continue target execution", cmd_cont },
3048         { "context", ":", "change debugger target context", cmd_context },
3049         { "dem", "name ...", "demangle C++ symbol names", cmd_demstr },
3050         { "fltbp", "?[+/-dDestT] [-c cmd] [-n count] fault ...",
3051             "stop on machine fault", cmd_fltbp, fltbp_help },
3052         { "fpregs", NULL, "print floating point registers", cmd_notsup },
3053         { "kill", NULL, "forcibly kill and release target", cmd_notsup },
3054         { "load", "[-s] module", "load debugger module", cmd_load, load_help },
3055         { "log", "[-d | [-e] file]", "log session to a file", cmd_log },
3056         { "next", "[SIG]", "step target over next instruction", cmd_next },
3057         { "quit", NULL, "quit debugger", cmd_quit },
3058         { "release", NULL,
3059             "release the previously attached process", cmd_notsup },
3060         { "run", "[ args ... ]", "run a new target process", cmd_run },
3061         { "sigbp", "?[+/-dDestT] [-c cmd] [-n count] SIG ...", "stop on "
3062             "delivery of the specified signals", cmd_sigbp, sigbp_help },
3063         { "step", "[ over | out ] [SIG]",
3064             "single-step target to next instruction", cmd_step },
3065         { "sysbp", "?[+/-dDestT] [-io] [-c cmd] [-n count] syscall ...",
3066             "stop on entry or exit from system call", cmd_sysbp, sysbp_help },
3067         { "unload", "module", "unload debugger module", cmd_unload },
3068         { "wp", ":[+/-dDelstT] [-rwx] [-c cmd] [-n count] [-L size]",
3069             "set a watchpoint at the specified address", cmd_wp, wp_help },
3070 #endif
3071 
3072         { NULL }
3073 };