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