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