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