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