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