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