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