1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Copyright (c) 2012 by Delphix. All rights reserved. 29 * Copyright (c) 2013 Joyent, Inc. All rights reserved. 30 * Copyright (c) 2013 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> 31 */ 32 33 #include <sys/elf.h> 34 #include <sys/elf_SPARC.h> 35 36 #include <libproc.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <fcntl.h> 40 #include <errno.h> 41 #include <alloca.h> 42 #include <libctf.h> 43 #include <ctype.h> 44 45 #include <mdb/mdb_string.h> 46 #include <mdb/mdb_argvec.h> 47 #include <mdb/mdb_nv.h> 48 #include <mdb/mdb_fmt.h> 49 #include <mdb/mdb_target.h> 50 #include <mdb/mdb_err.h> 51 #include <mdb/mdb_debug.h> 52 #include <mdb/mdb_conf.h> 53 #include <mdb/mdb_module.h> 54 #include <mdb/mdb_modapi.h> 55 #include <mdb/mdb_stdlib.h> 56 #include <mdb/mdb_lex.h> 57 #include <mdb/mdb_io_impl.h> 58 #include <mdb/mdb_help.h> 59 #include <mdb/mdb_disasm.h> 60 #include <mdb/mdb_frame.h> 61 #include <mdb/mdb_evset.h> 62 #include <mdb/mdb_print.h> 63 #include <mdb/mdb_nm.h> 64 #include <mdb/mdb_set.h> 65 #include <mdb/mdb_demangle.h> 66 #include <mdb/mdb_ctf.h> 67 #include <mdb/mdb_whatis.h> 68 #include <mdb/mdb_whatis_impl.h> 69 #include <mdb/mdb_macalias.h> 70 #include <mdb/mdb_tab.h> 71 #include <mdb/mdb_typedef.h> 72 #ifdef _KMDB 73 #include <kmdb/kmdb_kdi.h> 74 #endif 75 #include <mdb/mdb.h> 76 77 #ifdef __sparc 78 #define SETHI_MASK 0xc1c00000 79 #define SETHI_VALUE 0x01000000 80 81 #define IS_SETHI(machcode) (((machcode) & SETHI_MASK) == SETHI_VALUE) 82 83 #define OP(machcode) ((machcode) >> 30) 84 #define OP3(machcode) (((machcode) >> 19) & 0x3f) 85 #define RD(machcode) (((machcode) >> 25) & 0x1f) 86 #define RS1(machcode) (((machcode) >> 14) & 0x1f) 87 #define I(machcode) (((machcode) >> 13) & 0x01) 88 89 #define IMM13(machcode) ((machcode) & 0x1fff) 90 #define IMM22(machcode) ((machcode) & 0x3fffff) 91 92 #define OP_ARITH_MEM_MASK 0x2 93 #define OP_ARITH 0x2 94 #define OP_MEM 0x3 95 96 #define OP3_CC_MASK 0x10 97 #define OP3_COMPLEX_MASK 0x20 98 99 #define OP3_ADD 0x00 100 #define OP3_OR 0x02 101 #define OP3_XOR 0x03 102 103 #ifndef R_O7 104 #define R_O7 0xf 105 #endif 106 #endif /* __sparc */ 107 108 static mdb_tgt_addr_t 109 write_uint8(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t ull, uint_t rdback) 110 { 111 uint8_t o, n = (uint8_t)ull; 112 113 if (rdback && mdb_tgt_aread(mdb.m_target, as, &o, sizeof (o), 114 addr) == -1) 115 return (addr); 116 117 if (mdb_tgt_awrite(mdb.m_target, as, &n, sizeof (n), addr) == -1) 118 return (addr); 119 120 if (rdback) { 121 if (mdb_tgt_aread(mdb.m_target, as, &n, sizeof (n), addr) == -1) 122 return (addr); 123 124 mdb_iob_printf(mdb.m_out, "%-#*lla%16T%-#8x=%8T0x%x\n", 125 mdb_iob_getmargin(mdb.m_out), addr, o, n); 126 } 127 128 return (addr + sizeof (n)); 129 } 130 131 static mdb_tgt_addr_t 132 write_uint16(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t ull, uint_t rdback) 133 { 134 uint16_t o, n = (uint16_t)ull; 135 136 if (rdback && mdb_tgt_aread(mdb.m_target, as, &o, sizeof (o), 137 addr) == -1) 138 return (addr); 139 140 if (mdb_tgt_awrite(mdb.m_target, as, &n, sizeof (n), addr) == -1) 141 return (addr); 142 143 if (rdback) { 144 if (mdb_tgt_aread(mdb.m_target, as, &n, sizeof (n), addr) == -1) 145 return (addr); 146 147 mdb_iob_printf(mdb.m_out, "%-#*lla%16T%-#8hx=%8T0x%hx\n", 148 mdb_iob_getmargin(mdb.m_out), addr, o, n); 149 } 150 151 return (addr + sizeof (n)); 152 } 153 154 static mdb_tgt_addr_t 155 write_uint32(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t ull, uint_t rdback) 156 { 157 uint32_t o, n = (uint32_t)ull; 158 159 if (rdback && mdb_tgt_aread(mdb.m_target, as, &o, sizeof (o), 160 addr) == -1) 161 return (addr); 162 163 if (mdb_tgt_awrite(mdb.m_target, as, &n, sizeof (n), addr) == -1) 164 return (addr); 165 166 if (rdback) { 167 if (mdb_tgt_aread(mdb.m_target, as, &n, sizeof (n), addr) == -1) 168 return (addr); 169 170 mdb_iob_printf(mdb.m_out, "%-#*lla%16T%-#16x=%8T0x%x\n", 171 mdb_iob_getmargin(mdb.m_out), addr, o, n); 172 } 173 174 return (addr + sizeof (n)); 175 } 176 177 static mdb_tgt_addr_t 178 write_uint64(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t n, uint_t rdback) 179 { 180 uint64_t o; 181 182 if (rdback && mdb_tgt_aread(mdb.m_target, as, &o, sizeof (o), 183 addr) == -1) 184 return (addr); 185 186 if (mdb_tgt_awrite(mdb.m_target, as, &n, sizeof (n), addr) == -1) 187 return (addr); 188 189 if (rdback) { 190 if (mdb_tgt_aread(mdb.m_target, as, &n, sizeof (n), addr) == -1) 191 return (addr); 192 193 mdb_iob_printf(mdb.m_out, "%-#*lla%16T%-#24llx=%8T0x%llx\n", 194 mdb_iob_getmargin(mdb.m_out), addr, o, n); 195 } 196 197 return (addr + sizeof (n)); 198 } 199 200 static int 201 write_arglist(mdb_tgt_as_t as, mdb_tgt_addr_t addr, 202 int argc, const mdb_arg_t *argv) 203 { 204 mdb_tgt_addr_t (*write_value)(mdb_tgt_as_t, mdb_tgt_addr_t, 205 uint64_t, uint_t); 206 mdb_tgt_addr_t naddr; 207 uintmax_t value; 208 int rdback = mdb.m_flags & MDB_FL_READBACK; 209 size_t i; 210 211 if (argc == 1) { 212 mdb_warn("expected value to write following %c\n", 213 argv->a_un.a_char); 214 return (DCMD_ERR); 215 } 216 217 switch (argv->a_un.a_char) { 218 case 'v': 219 write_value = write_uint8; 220 break; 221 case 'w': 222 write_value = write_uint16; 223 break; 224 case 'W': 225 write_value = write_uint32; 226 break; 227 case 'Z': 228 write_value = write_uint64; 229 break; 230 } 231 232 for (argv++, i = 1; i < argc; i++, argv++) { 233 if (argv->a_type == MDB_TYPE_CHAR) { 234 mdb_warn("expected immediate value instead of '%c'\n", 235 argv->a_un.a_char); 236 return (DCMD_ERR); 237 } 238 239 if (argv->a_type == MDB_TYPE_STRING) { 240 if (mdb_eval(argv->a_un.a_str) == -1) { 241 mdb_warn("failed to write \"%s\"", 242 argv->a_un.a_str); 243 return (DCMD_ERR); 244 } 245 value = mdb_nv_get_value(mdb.m_dot); 246 } else 247 value = argv->a_un.a_val; 248 249 mdb_nv_set_value(mdb.m_dot, addr); 250 251 if ((naddr = write_value(as, addr, value, rdback)) == addr) { 252 mdb_warn("failed to write %llr at address 0x%llx", 253 value, addr); 254 mdb.m_incr = 0; 255 break; 256 } 257 258 mdb.m_incr = naddr - addr; 259 addr = naddr; 260 } 261 262 return (DCMD_OK); 263 } 264 265 static mdb_tgt_addr_t 266 match_uint16(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t v64, uint64_t m64) 267 { 268 uint16_t x, val = (uint16_t)v64, mask = (uint16_t)m64; 269 270 for (; mdb_tgt_aread(mdb.m_target, as, &x, 271 sizeof (x), addr) == sizeof (x); addr += sizeof (x)) { 272 273 if ((x & mask) == val) { 274 mdb_iob_printf(mdb.m_out, "%lla\n", addr); 275 break; 276 } 277 } 278 return (addr); 279 } 280 281 static mdb_tgt_addr_t 282 match_uint32(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t v64, uint64_t m64) 283 { 284 uint32_t x, val = (uint32_t)v64, mask = (uint32_t)m64; 285 286 for (; mdb_tgt_aread(mdb.m_target, as, &x, 287 sizeof (x), addr) == sizeof (x); addr += sizeof (x)) { 288 289 if ((x & mask) == val) { 290 mdb_iob_printf(mdb.m_out, "%lla\n", addr); 291 break; 292 } 293 } 294 return (addr); 295 } 296 297 static mdb_tgt_addr_t 298 match_uint64(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint64_t val, uint64_t mask) 299 { 300 uint64_t x; 301 302 for (; mdb_tgt_aread(mdb.m_target, as, &x, 303 sizeof (x), addr) == sizeof (x); addr += sizeof (x)) { 304 305 if ((x & mask) == val) { 306 mdb_iob_printf(mdb.m_out, "%lla\n", addr); 307 break; 308 } 309 } 310 return (addr); 311 } 312 313 static int 314 match_arglist(mdb_tgt_as_t as, uint_t flags, mdb_tgt_addr_t addr, 315 int argc, const mdb_arg_t *argv) 316 { 317 mdb_tgt_addr_t (*match_value)(mdb_tgt_as_t, mdb_tgt_addr_t, 318 uint64_t, uint64_t); 319 320 uint64_t args[2] = { 0, -1ULL }; /* [ value, mask ] */ 321 size_t i; 322 323 if (argc < 2) { 324 mdb_warn("expected value following %c\n", argv->a_un.a_char); 325 return (DCMD_ERR); 326 } 327 328 if (argc > 3) { 329 mdb_warn("only value and mask may follow %c\n", 330 argv->a_un.a_char); 331 return (DCMD_ERR); 332 } 333 334 switch (argv->a_un.a_char) { 335 case 'l': 336 match_value = match_uint16; 337 break; 338 case 'L': 339 match_value = match_uint32; 340 break; 341 case 'M': 342 match_value = match_uint64; 343 break; 344 } 345 346 for (argv++, i = 1; i < argc; i++, argv++) { 347 if (argv->a_type == MDB_TYPE_CHAR) { 348 mdb_warn("expected immediate value instead of '%c'\n", 349 argv->a_un.a_char); 350 return (DCMD_ERR); 351 } 352 353 if (argv->a_type == MDB_TYPE_STRING) { 354 if (mdb_eval(argv->a_un.a_str) == -1) { 355 mdb_warn("failed to evaluate \"%s\"", 356 argv->a_un.a_str); 357 return (DCMD_ERR); 358 } 359 args[i - 1] = mdb_nv_get_value(mdb.m_dot); 360 } else 361 args[i - 1] = argv->a_un.a_val; 362 } 363 364 addr = match_value(as, addr, args[0], args[1]); 365 mdb_nv_set_value(mdb.m_dot, addr); 366 367 /* 368 * In adb(1), the match operators ignore any repeat count that has 369 * been applied to them. We emulate this undocumented property 370 * by returning DCMD_ABORT if our input is not a pipeline. 371 */ 372 return ((flags & DCMD_PIPE) ? DCMD_OK : DCMD_ABORT); 373 } 374 375 static int 376 argncmp(int argc, const mdb_arg_t *argv, const char *s) 377 { 378 for (; *s != '\0'; s++, argc--, argv++) { 379 if (argc == 0 || argv->a_type != MDB_TYPE_CHAR) 380 return (FALSE); 381 if (argv->a_un.a_char != *s) 382 return (FALSE); 383 } 384 return (TRUE); 385 } 386 387 static int 388 print_arglist(mdb_tgt_as_t as, mdb_tgt_addr_t addr, uint_t flags, 389 int argc, const mdb_arg_t *argv) 390 { 391 char buf[MDB_TGT_SYM_NAMLEN]; 392 mdb_tgt_addr_t oaddr = addr; 393 mdb_tgt_addr_t naddr; 394 GElf_Sym sym; 395 size_t i, n; 396 397 if (DCMD_HDRSPEC(flags) && (flags & DCMD_PIPE_OUT) == 0) { 398 const char *fmt; 399 int is_dis; 400 /* 401 * This is nasty, but necessary for precise adb compatibility. 402 * Detect disassembly format by looking for "ai" or "ia": 403 */ 404 if (argncmp(argc, argv, "ai")) { 405 fmt = "%-#*lla\n"; 406 is_dis = TRUE; 407 } else if (argncmp(argc, argv, "ia")) { 408 fmt = "%-#*lla"; 409 is_dis = TRUE; 410 } else { 411 fmt = "%-#*lla%16T"; 412 is_dis = FALSE; 413 } 414 415 /* 416 * If symbolic decoding is on, disassembly is off, and the 417 * address exactly matches a symbol, print the symbol name: 418 */ 419 if ((mdb.m_flags & MDB_FL_PSYM) && !is_dis && 420 (as == MDB_TGT_AS_VIRT || as == MDB_TGT_AS_FILE) && 421 mdb_tgt_lookup_by_addr(mdb.m_target, (uintptr_t)addr, 422 MDB_TGT_SYM_EXACT, buf, sizeof (buf), &sym, NULL) == 0) 423 mdb_iob_printf(mdb.m_out, "%s:\n", buf); 424 425 /* 426 * If this is a virtual address, cast it so that it reflects 427 * only the valid component of the address. 428 */ 429 if (as == MDB_TGT_AS_VIRT) 430 addr = (uintptr_t)addr; 431 432 mdb_iob_printf(mdb.m_out, fmt, 433 (uint_t)mdb_iob_getmargin(mdb.m_out), addr); 434 } 435 436 if (argc == 0) { 437 /* 438 * Yes, for you trivia buffs: if you use a format verb and give 439 * no format string, you get: X^"= "i ... note that in adb the 440 * the '=' verb once had 'z' as its default, but then 'z' was 441 * deleted (it was once an alias for 'i') and so =\n now calls 442 * scanform("z") and produces a 'bad modifier' message. 443 */ 444 static const mdb_arg_t def_argv[] = { 445 { MDB_TYPE_CHAR, MDB_INIT_CHAR('X') }, 446 { MDB_TYPE_CHAR, MDB_INIT_CHAR('^') }, 447 { MDB_TYPE_STRING, MDB_INIT_STRING("= ") }, 448 { MDB_TYPE_CHAR, MDB_INIT_CHAR('i') } 449 }; 450 451 argc = sizeof (def_argv) / sizeof (mdb_arg_t); 452 argv = def_argv; 453 } 454 455 mdb_iob_setflags(mdb.m_out, MDB_IOB_INDENT); 456 457 for (i = 0, n = 1; i < argc; i++, argv++) { 458 switch (argv->a_type) { 459 case MDB_TYPE_CHAR: 460 naddr = mdb_fmt_print(mdb.m_target, as, addr, n, 461 argv->a_un.a_char); 462 mdb.m_incr = naddr - addr; 463 addr = naddr; 464 n = 1; 465 break; 466 467 case MDB_TYPE_IMMEDIATE: 468 n = argv->a_un.a_val; 469 break; 470 471 case MDB_TYPE_STRING: 472 mdb_iob_puts(mdb.m_out, argv->a_un.a_str); 473 n = 1; 474 break; 475 } 476 } 477 478 mdb.m_incr = addr - oaddr; 479 mdb_iob_clrflags(mdb.m_out, MDB_IOB_INDENT); 480 return (DCMD_OK); 481 } 482 483 static int 484 print_common(mdb_tgt_as_t as, uint_t flags, int argc, const mdb_arg_t *argv) 485 { 486 mdb_tgt_addr_t addr = mdb_nv_get_value(mdb.m_dot); 487 488 if (argc != 0 && argv->a_type == MDB_TYPE_CHAR) { 489 if (strchr("vwWZ", argv->a_un.a_char)) 490 return (write_arglist(as, addr, argc, argv)); 491 if (strchr("lLM", argv->a_un.a_char)) 492 return (match_arglist(as, flags, addr, argc, argv)); 493 } 494 495 return (print_arglist(as, addr, flags, argc, argv)); 496 } 497 498 /*ARGSUSED*/ 499 static int 500 cmd_print_core(uintptr_t x, uint_t flags, int argc, const mdb_arg_t *argv) 501 { 502 return (print_common(MDB_TGT_AS_VIRT, flags, argc, argv)); 503 } 504 505 #ifndef _KMDB 506 /*ARGSUSED*/ 507 static int 508 cmd_print_object(uintptr_t x, uint_t flags, int argc, const mdb_arg_t *argv) 509 { 510 return (print_common(MDB_TGT_AS_FILE, flags, argc, argv)); 511 } 512 #endif 513 514 /*ARGSUSED*/ 515 static int 516 cmd_print_phys(uintptr_t x, uint_t flags, int argc, const mdb_arg_t *argv) 517 { 518 return (print_common(MDB_TGT_AS_PHYS, flags, argc, argv)); 519 } 520 521 /*ARGSUSED*/ 522 static int 523 cmd_print_value(uintptr_t addr, uint_t flags, 524 int argc, const mdb_arg_t *argv) 525 { 526 uintmax_t ndot, dot = mdb_get_dot(); 527 const char *tgt_argv[1]; 528 mdb_tgt_t *t; 529 size_t i, n; 530 531 if (argc == 0) { 532 mdb_warn("expected one or more format characters " 533 "following '='\n"); 534 return (DCMD_ERR); 535 } 536 537 tgt_argv[0] = (const char *)˙ 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 width = 1; 2179 mdb_tgt_status_t st; 2180 int error; 2181 2182 if (mdb_getopts(argc, argv, 2183 'e', MDB_OPT_SETBITS, MDB_DUMP_ENDIAN, &dflags, 2184 'f', MDB_OPT_SETBITS, TRUE, &file, 2185 'g', MDB_OPT_UINTPTR, &group, 2186 'p', MDB_OPT_SETBITS, TRUE, &phys, 2187 'q', MDB_OPT_CLRBITS, MDB_DUMP_ASCII, &dflags, 2188 'r', MDB_OPT_SETBITS, MDB_DUMP_RELATIVE, &dflags, 2189 's', MDB_OPT_SETBITS, MDB_DUMP_SQUISH, &dflags, 2190 't', MDB_OPT_SETBITS, MDB_DUMP_TRIM, &dflags, 2191 'u', MDB_OPT_CLRBITS, MDB_DUMP_ALIGN, &dflags, 2192 'v', MDB_OPT_SETBITS, MDB_DUMP_PEDANT, &dflags, 2193 'w', MDB_OPT_UINTPTR, &width, NULL) != argc) 2194 return (DCMD_USAGE); 2195 2196 if ((phys && file) || 2197 (width == 0) || (width > 0x10) || 2198 (group == 0) || (group > 0x100)) 2199 return (DCMD_USAGE); 2200 2201 /* 2202 * If neither -f nor -p were specified and the state is IDLE (i.e. no 2203 * address space), turn on -p. This is so we can read large files. 2204 */ 2205 if (phys == FALSE && file == FALSE && mdb_tgt_status(mdb.m_target, 2206 &st) == 0 && st.st_state == MDB_TGT_IDLE) 2207 phys = TRUE; 2208 2209 dflags |= MDB_DUMP_GROUP(group) | MDB_DUMP_WIDTH(width); 2210 if (phys) 2211 error = mdb_dump64(mdb_get_dot(), mdb.m_dcount, dflags, 2212 mdb_partial_pread, NULL); 2213 else if (file) 2214 error = mdb_dumpptr(addr, mdb.m_dcount, dflags, 2215 mdb_partial_xread, (void *)mdb_tgt_fread); 2216 else 2217 error = mdb_dumpptr(addr, mdb.m_dcount, dflags, 2218 mdb_partial_xread, (void *)mdb_tgt_vread); 2219 2220 return (((flags & DCMD_LOOP) || (error == -1)) ? DCMD_ABORT : DCMD_OK); 2221 } 2222 2223 /*ARGSUSED*/ 2224 static int 2225 cmd_echo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2226 { 2227 if (flags & DCMD_ADDRSPEC) 2228 return (DCMD_USAGE); 2229 2230 for (; argc-- != 0; argv++) { 2231 if (argv->a_type == MDB_TYPE_STRING) 2232 mdb_printf("%s ", argv->a_un.a_str); 2233 else 2234 mdb_printf("%llr ", argv->a_un.a_val); 2235 } 2236 2237 mdb_printf("\n"); 2238 return (DCMD_OK); 2239 } 2240 2241 /*ARGSUSED*/ 2242 static int 2243 cmd_head(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2244 { 2245 uint64_t cnt = 10; 2246 const char *c; 2247 mdb_pipe_t p; 2248 2249 if (!flags & DCMD_PIPE) 2250 return (DCMD_USAGE); 2251 2252 if (argc == 1 || argc == 2) { 2253 const char *num; 2254 2255 if (argc == 1) { 2256 if (argv[0].a_type != MDB_TYPE_STRING || 2257 *argv[0].a_un.a_str != '-') 2258 return (DCMD_USAGE); 2259 2260 num = argv[0].a_un.a_str + 1; 2261 2262 } else { 2263 if (argv[0].a_type != MDB_TYPE_STRING || 2264 strcmp(argv[0].a_un.a_str, "-n") != 0) 2265 return (DCMD_USAGE); 2266 2267 num = argv[1].a_un.a_str; 2268 } 2269 2270 for (cnt = 0, c = num; *c != '\0' && isdigit(*c); c++) 2271 cnt = cnt * 10 + (*c - '0'); 2272 2273 if (*c != '\0') 2274 return (DCMD_USAGE); 2275 2276 } else if (argc != 0) { 2277 return (DCMD_USAGE); 2278 } 2279 2280 mdb_get_pipe(&p); 2281 2282 if (p.pipe_data == NULL) 2283 return (DCMD_OK); 2284 p.pipe_len = MIN(p.pipe_len, cnt); 2285 2286 if (flags & DCMD_PIPE_OUT) { 2287 mdb_set_pipe(&p); 2288 } else { 2289 while (p.pipe_len-- > 0) 2290 mdb_printf("%lx\n", *p.pipe_data++); 2291 } 2292 2293 return (DCMD_OK); 2294 } 2295 2296 static void 2297 head_help(void) 2298 { 2299 mdb_printf( 2300 "-n num\n or\n" 2301 "-num pass only the first `num' elements in the pipe.\n" 2302 "\n%<b>Note:%</b> `num' is a decimal number.\n"); 2303 } 2304 2305 static int 2306 cmd_typeset(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2307 { 2308 int add_tag = 0, del_tag = 0; 2309 const char *p; 2310 mdb_var_t *v; 2311 2312 if (argc == 0) 2313 return (cmd_vars(addr, flags, argc, argv)); 2314 2315 if (argv->a_type == MDB_TYPE_STRING && (argv->a_un.a_str[0] == '-' || 2316 argv->a_un.a_str[0] == '+')) { 2317 if (argv->a_un.a_str[1] != 't') 2318 return (DCMD_USAGE); 2319 if (argv->a_un.a_str[0] == '-') 2320 add_tag++; 2321 else 2322 del_tag++; 2323 argc--; 2324 argv++; 2325 } 2326 2327 if (!(flags & DCMD_ADDRSPEC)) 2328 addr = 0; /* set variables to zero unless explicit addr given */ 2329 2330 for (; argc-- != 0; argv++) { 2331 if (argv->a_type != MDB_TYPE_STRING) 2332 continue; 2333 2334 if (argv->a_un.a_str[0] == '-' || argv->a_un.a_str[0] == '+') { 2335 mdb_warn("ignored bad option -- %s\n", 2336 argv->a_un.a_str); 2337 continue; 2338 } 2339 2340 if ((p = strbadid(argv->a_un.a_str)) != NULL) { 2341 mdb_warn("'%c' may not be used in a variable " 2342 "name\n", *p); 2343 return (DCMD_ERR); 2344 } 2345 2346 if ((v = mdb_nv_lookup(&mdb.m_nv, argv->a_un.a_str)) == NULL) { 2347 v = mdb_nv_insert(&mdb.m_nv, argv->a_un.a_str, 2348 NULL, addr, 0); 2349 } else if (flags & DCMD_ADDRSPEC) 2350 mdb_nv_set_value(v, addr); 2351 2352 if (v != NULL) { 2353 if (add_tag) 2354 v->v_flags |= MDB_NV_TAGGED; 2355 if (del_tag) 2356 v->v_flags &= ~MDB_NV_TAGGED; 2357 } 2358 } 2359 2360 return (DCMD_OK); 2361 } 2362 2363 #ifndef _KMDB 2364 /*ARGSUSED*/ 2365 static int 2366 cmd_context(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2367 { 2368 if (argc != 0 || !(flags & DCMD_ADDRSPEC)) 2369 return (DCMD_USAGE); 2370 2371 if (mdb_tgt_setcontext(mdb.m_target, (void *)addr) == 0) 2372 return (DCMD_OK); 2373 2374 return (DCMD_ERR); 2375 } 2376 #endif 2377 2378 /*ARGSUSED*/ 2379 static int 2380 cmd_prompt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2381 { 2382 const char *p = ""; 2383 2384 if (argc != 0) { 2385 if (argc > 1 || argv->a_type != MDB_TYPE_STRING) 2386 return (DCMD_USAGE); 2387 p = argv->a_un.a_str; 2388 } 2389 2390 (void) mdb_set_prompt(p); 2391 return (DCMD_OK); 2392 } 2393 2394 /*ARGSUSED*/ 2395 static int 2396 cmd_term(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2397 { 2398 mdb_printf("%s\n", mdb.m_termtype); 2399 2400 return (DCMD_OK); 2401 } 2402 2403 /*ARGSUSED*/ 2404 static int 2405 cmd_vtop(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2406 { 2407 physaddr_t pa; 2408 mdb_tgt_as_t as = MDB_TGT_AS_VIRT; 2409 2410 if (mdb_getopts(argc, argv, 'a', MDB_OPT_UINTPTR, (uintptr_t *)&as, 2411 NULL) != argc) 2412 return (DCMD_USAGE); 2413 2414 if (mdb_tgt_vtop(mdb.m_target, as, addr, &pa) == -1) { 2415 mdb_warn("failed to get physical mapping"); 2416 return (DCMD_ERR); 2417 } 2418 2419 if (flags & DCMD_PIPE_OUT) 2420 mdb_printf("%llr\n", pa); 2421 else 2422 mdb_printf("virtual %lr mapped to physical %llr\n", addr, pa); 2423 return (DCMD_OK); 2424 } 2425 2426 #define EVENTS_OPT_A 0x1 /* ::events -a (show all events) */ 2427 #define EVENTS_OPT_V 0x2 /* ::events -v (verbose display) */ 2428 2429 static const char * 2430 event_action(const mdb_tgt_spec_desc_t *sp) 2431 { 2432 if (!(sp->spec_flags & MDB_TGT_SPEC_HIDDEN) && sp->spec_data != NULL) 2433 return (sp->spec_data); 2434 2435 return ("-"); 2436 } 2437 2438 static void 2439 print_evsep(void) 2440 { 2441 static const char dash20[] = "--------------------"; 2442 mdb_printf("----- - -- -- -- %s%s --%s\n", dash20, dash20, dash20); 2443 } 2444 2445 /*ARGSUSED*/ 2446 static int 2447 print_event(mdb_tgt_t *t, void *private, int vid, void *data) 2448 { 2449 uint_t opts = (uint_t)(uintptr_t)private; 2450 mdb_tgt_spec_desc_t sp; 2451 char s1[41], s2[22]; 2452 const char *s2str; 2453 int visible; 2454 2455 (void) mdb_tgt_vespec_info(t, vid, &sp, s1, sizeof (s1)); 2456 visible = !(sp.spec_flags & (MDB_TGT_SPEC_HIDDEN|MDB_TGT_SPEC_DELETED)); 2457 2458 if ((opts & EVENTS_OPT_A) || visible) { 2459 int encoding = (!(sp.spec_flags & MDB_TGT_SPEC_DISABLED)) | 2460 (!(sp.spec_flags & MDB_TGT_SPEC_MATCHED) << 1); 2461 2462 char ldelim = "<<(["[encoding]; 2463 char rdelim = ">>)]"[encoding]; 2464 2465 char state = "0-+*!"[sp.spec_state]; 2466 2467 char tflag = "T "[!(sp.spec_flags & MDB_TGT_SPEC_STICKY)]; 2468 char aflag = "d "[!(sp.spec_flags & MDB_TGT_SPEC_AUTODIS)]; 2469 2470 if (sp.spec_flags & MDB_TGT_SPEC_TEMPORARY) 2471 tflag = 't'; /* TEMP takes precedence over STICKY */ 2472 if (sp.spec_flags & MDB_TGT_SPEC_AUTODEL) 2473 aflag = 'D'; /* AUTODEL takes precedence over AUTODIS */ 2474 if (sp.spec_flags & MDB_TGT_SPEC_AUTOSTOP) 2475 aflag = 's'; /* AUTOSTOP takes precedence over both */ 2476 2477 if (opts & EVENTS_OPT_V) { 2478 if (sp.spec_state == MDB_TGT_SPEC_IDLE || 2479 sp.spec_state == MDB_TGT_SPEC_ERROR) 2480 s2str = mdb_strerror(sp.spec_errno); 2481 else 2482 s2str = "-"; 2483 } else 2484 s2str = event_action(&sp); 2485 2486 if (mdb_snprintf(s2, sizeof (s2), "%s", s2str) >= sizeof (s2)) 2487 (void) strabbr(s2, sizeof (s2)); 2488 2489 if (vid > -10 && vid < 10) 2490 mdb_printf("%c%2d %c", ldelim, vid, rdelim); 2491 else 2492 mdb_printf("%c%3d%c", ldelim, vid, rdelim); 2493 2494 mdb_printf(" %c %c%c %2u %2u %-40s %-21s\n", 2495 state, tflag, aflag, sp.spec_hits, sp.spec_limit, s1, s2); 2496 2497 if (opts & EVENTS_OPT_V) { 2498 mdb_printf("%-17s%s\n", "", event_action(&sp)); 2499 print_evsep(); 2500 } 2501 } 2502 2503 return (0); 2504 } 2505 2506 /*ARGSUSED*/ 2507 static int 2508 cmd_events(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2509 { 2510 uint_t opts = 0; 2511 2512 if ((flags & DCMD_ADDRSPEC) || mdb_getopts(argc, argv, 2513 'a', MDB_OPT_SETBITS, EVENTS_OPT_A, &opts, 2514 'v', MDB_OPT_SETBITS, EVENTS_OPT_V, &opts, NULL) != argc) 2515 return (DCMD_USAGE); 2516 2517 2518 if (opts & EVENTS_OPT_V) { 2519 mdb_printf(" ID S TA HT LM %-40s %-21s\n%-17s%s\n", 2520 "Description", "Status", "", "Action"); 2521 } else { 2522 mdb_printf(" ID S TA HT LM %-40s %-21s\n", 2523 "Description", "Action"); 2524 } 2525 2526 print_evsep(); 2527 return (mdb_tgt_vespec_iter(mdb.m_target, print_event, 2528 (void *)(uintptr_t)opts)); 2529 } 2530 2531 static int 2532 tgt_status(const mdb_tgt_status_t *tsp) 2533 { 2534 const char *format; 2535 char buf[BUFSIZ]; 2536 2537 if (tsp->st_flags & MDB_TGT_BUSY) 2538 return (DCMD_OK); 2539 2540 if (tsp->st_pc != 0) { 2541 if (mdb_dis_ins2str(mdb.m_disasm, mdb.m_target, MDB_TGT_AS_VIRT, 2542 buf, sizeof (buf), tsp->st_pc) != tsp->st_pc) 2543 format = "target stopped at:\n%-#16a%8T%s\n"; 2544 else 2545 format = "target stopped at %a:\n"; 2546 mdb_warn(format, tsp->st_pc, buf); 2547 } 2548 2549 switch (tsp->st_state) { 2550 case MDB_TGT_IDLE: 2551 mdb_warn("target is idle\n"); 2552 break; 2553 case MDB_TGT_RUNNING: 2554 if (tsp->st_flags & MDB_TGT_DSTOP) 2555 mdb_warn("target is running, stop directive pending\n"); 2556 else 2557 mdb_warn("target is running\n"); 2558 break; 2559 case MDB_TGT_STOPPED: 2560 if (tsp->st_pc == 0) 2561 mdb_warn("target is stopped\n"); 2562 break; 2563 case MDB_TGT_UNDEAD: 2564 mdb_warn("target has terminated\n"); 2565 break; 2566 case MDB_TGT_DEAD: 2567 mdb_warn("target is a core dump\n"); 2568 break; 2569 case MDB_TGT_LOST: 2570 mdb_warn("target is no longer under debugger control\n"); 2571 break; 2572 } 2573 2574 mdb_set_dot(tsp->st_pc); 2575 return (DCMD_OK); 2576 } 2577 2578 /* 2579 * mdb continue/step commands take an optional signal argument, but the 2580 * corresponding kmdb versions don't. 2581 */ 2582 #ifdef _KMDB 2583 #define CONT_MAXARGS 0 /* no optional SIG argument */ 2584 #else 2585 #define CONT_MAXARGS 1 2586 #endif 2587 2588 /*ARGSUSED*/ 2589 static int 2590 cmd_cont_common(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv, 2591 int (*t_cont)(mdb_tgt_t *, mdb_tgt_status_t *), const char *name) 2592 { 2593 mdb_tgt_t *t = mdb.m_target; 2594 mdb_tgt_status_t st; 2595 int sig = 0; 2596 2597 if ((flags & DCMD_ADDRSPEC) || argc > CONT_MAXARGS) 2598 return (DCMD_USAGE); 2599 2600 if (argc > 0) { 2601 if (argv->a_type == MDB_TYPE_STRING) { 2602 if (proc_str2sig(argv->a_un.a_str, &sig) == -1) { 2603 mdb_warn("invalid signal name -- %s\n", 2604 argv->a_un.a_str); 2605 return (DCMD_USAGE); 2606 } 2607 } else 2608 sig = (int)(intmax_t)argv->a_un.a_val; 2609 } 2610 2611 (void) mdb_tgt_status(t, &st); 2612 2613 if (st.st_state == MDB_TGT_IDLE && mdb_tgt_run(t, 0, NULL) == -1) { 2614 if (errno != EMDB_TGT) 2615 mdb_warn("failed to create new target"); 2616 return (DCMD_ERR); 2617 } 2618 2619 if (sig != 0 && mdb_tgt_signal(t, sig) == -1) { 2620 mdb_warn("failed to post signal %d", sig); 2621 return (DCMD_ERR); 2622 } 2623 2624 if (st.st_state == MDB_TGT_IDLE && t_cont == &mdb_tgt_step) { 2625 (void) mdb_tgt_status(t, &st); 2626 return (tgt_status(&st)); 2627 } 2628 2629 if (t_cont(t, &st) == -1) { 2630 if (errno != EMDB_TGT) 2631 mdb_warn("failed to %s target", name); 2632 return (DCMD_ERR); 2633 } 2634 2635 return (tgt_status(&st)); 2636 } 2637 2638 static int 2639 cmd_step(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2640 { 2641 int (*func)(mdb_tgt_t *, mdb_tgt_status_t *) = &mdb_tgt_step; 2642 const char *name = "single-step"; 2643 2644 if (argc > 0 && argv->a_type == MDB_TYPE_STRING) { 2645 if (strcmp(argv->a_un.a_str, "out") == 0) { 2646 func = &mdb_tgt_step_out; 2647 name = "step (out)"; 2648 argv++; 2649 argc--; 2650 } else if (strcmp(argv->a_un.a_str, "branch") == 0) { 2651 func = &mdb_tgt_step_branch; 2652 name = "step (branch)"; 2653 argv++; 2654 argc--; 2655 } else if (strcmp(argv->a_un.a_str, "over") == 0) { 2656 func = &mdb_tgt_next; 2657 name = "step (over)"; 2658 argv++; 2659 argc--; 2660 } 2661 } 2662 2663 return (cmd_cont_common(addr, flags, argc, argv, func, name)); 2664 } 2665 2666 static int 2667 cmd_step_out(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2668 { 2669 return (cmd_cont_common(addr, flags, argc, argv, 2670 &mdb_tgt_step_out, "step (out)")); 2671 } 2672 2673 static int 2674 cmd_next(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2675 { 2676 return (cmd_cont_common(addr, flags, argc, argv, 2677 &mdb_tgt_next, "step (over)")); 2678 } 2679 2680 static int 2681 cmd_cont(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2682 { 2683 return (cmd_cont_common(addr, flags, argc, argv, 2684 &mdb_tgt_continue, "continue")); 2685 } 2686 2687 #ifndef _KMDB 2688 /*ARGSUSED*/ 2689 static int 2690 cmd_run(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2691 { 2692 if (flags & DCMD_ADDRSPEC) 2693 return (DCMD_USAGE); 2694 2695 if (mdb_tgt_run(mdb.m_target, argc, argv) == -1) { 2696 if (errno != EMDB_TGT) 2697 mdb_warn("failed to create new target"); 2698 return (DCMD_ERR); 2699 } 2700 return (cmd_cont(NULL, 0, 0, NULL)); 2701 } 2702 #endif 2703 2704 /* 2705 * To simplify the implementation of :d, :z, and ::delete, we use the sp 2706 * parameter to store the criteria for what to delete. If spec_base is set, 2707 * we delete vespecs with a matching address. If spec_id is set, we delete 2708 * vespecs with a matching id. Otherwise, we delete all vespecs. We bump 2709 * sp->spec_size so the caller can tell how many vespecs were deleted. 2710 */ 2711 static int 2712 ve_delete(mdb_tgt_t *t, mdb_tgt_spec_desc_t *sp, int vid, void *data) 2713 { 2714 mdb_tgt_spec_desc_t spec; 2715 int status = -1; 2716 2717 if (vid < 0) 2718 return (0); /* skip over target implementation events */ 2719 2720 if (sp->spec_base != NULL) { 2721 (void) mdb_tgt_vespec_info(t, vid, &spec, NULL, 0); 2722 if (sp->spec_base - spec.spec_base < spec.spec_size) 2723 status = mdb_tgt_vespec_delete(t, vid); 2724 } else if (sp->spec_id == 0) { 2725 (void) mdb_tgt_vespec_info(t, vid, &spec, NULL, 0); 2726 if (!(spec.spec_flags & MDB_TGT_SPEC_STICKY)) 2727 status = mdb_tgt_vespec_delete(t, vid); 2728 } else if (sp->spec_id == vid) 2729 status = mdb_tgt_vespec_delete(t, vid); 2730 2731 if (status == 0) { 2732 if (data != NULL) 2733 strfree(data); 2734 sp->spec_size++; 2735 } 2736 2737 return (0); 2738 } 2739 2740 static int 2741 ve_delete_spec(mdb_tgt_spec_desc_t *sp) 2742 { 2743 (void) mdb_tgt_vespec_iter(mdb.m_target, 2744 (mdb_tgt_vespec_f *)ve_delete, sp); 2745 2746 if (sp->spec_size == 0) { 2747 if (sp->spec_id != 0 || sp->spec_base != NULL) 2748 mdb_warn("no traced events matched description\n"); 2749 } 2750 2751 return (DCMD_OK); 2752 } 2753 2754 /*ARGSUSED*/ 2755 static int 2756 cmd_zapall(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2757 { 2758 mdb_tgt_spec_desc_t spec; 2759 2760 if ((flags & DCMD_ADDRSPEC) || argc != 0) 2761 return (DCMD_USAGE); 2762 2763 bzero(&spec, sizeof (spec)); 2764 return (ve_delete_spec(&spec)); 2765 } 2766 2767 static int 2768 cmd_delete(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2769 { 2770 mdb_tgt_spec_desc_t spec; 2771 2772 if (((flags & DCMD_ADDRSPEC) && argc > 0) || argc > 1) 2773 return (DCMD_USAGE); 2774 2775 bzero(&spec, sizeof (spec)); 2776 2777 if (flags & DCMD_ADDRSPEC) 2778 spec.spec_base = addr; 2779 else if (argc == 0) 2780 spec.spec_base = mdb_get_dot(); 2781 else if (argv->a_type == MDB_TYPE_STRING && 2782 strcmp(argv->a_un.a_str, "all") != 0) 2783 spec.spec_id = (int)(intmax_t)strtonum(argv->a_un.a_str, 10); 2784 else if (argv->a_type == MDB_TYPE_IMMEDIATE) 2785 spec.spec_id = (int)(intmax_t)argv->a_un.a_val; 2786 2787 return (ve_delete_spec(&spec)); 2788 } 2789 2790 static void 2791 srcexec_file_help(void) 2792 { 2793 mdb_printf( 2794 "The library of macros delivered with previous versions of Solaris have been\n" 2795 "superseded by the dcmds and walkers provided by MDB. See ::help for\n" 2796 "commands that can be used to list the available dcmds and walkers.\n" 2797 "\n" 2798 "Aliases have been created for several of the more popular macros. To see\n" 2799 "the list of aliased macros, as well as their native MDB equivalents,\n" 2800 "type $M.\n"); 2801 2802 #ifdef _KMDB 2803 mdb_printf( 2804 "When invoked, the $< and $<< dcmds will consult the macro alias list. If an\n" 2805 "alias cannot be found, an attempt will be made to locate a data type whose\n" 2806 "name corresponds to the requested macro. If such a type can be found, it\n" 2807 "will be displayed using the ::print dcmd.\n"); 2808 #else 2809 mdb_printf( 2810 "When invoked, the $< and $<< dcmds will first attempt to locate a macro with\n" 2811 "the indicated name. If no macro can be found, and if no alias exists for\n" 2812 "this macro, an attempt will be made to locate a data type whose name\n" 2813 "corresponds to the requested macro. If such a type can be found, it will be\n" 2814 "displayed using the ::print dcmd.\n"); 2815 #endif 2816 } 2817 2818 static void 2819 events_help(void) 2820 { 2821 mdb_printf("Options:\n" 2822 "-a show all events, including internal debugger events\n" 2823 "-v show verbose display, including inactivity reason\n" 2824 "\nOutput Columns:\n" 2825 "ID decimal event specifier id number:\n" 2826 " [ ] event tracing is enabled\n" 2827 " ( ) event tracing is disabled\n" 2828 " < > target is currently stopped on this type of event\n\n" 2829 "S event specifier state:\n" 2830 " - event specifier is idle (not applicable yet)\n" 2831 " + event specifier is active\n" 2832 " * event specifier is armed (target program running)\n" 2833 " ! error occurred while attempting to arm event\n\n" 2834 "TA event specifier flags:\n" 2835 " t event specifier is temporary (delete at next stop)\n" 2836 " T event specifier is sticky (::delete all has no effect)\n" 2837 " d event specifier will be disabled when HT = LM\n" 2838 " D event specifier will be deleted when HT = LM\n" 2839 " s target will automatically stop when HT = LM\n\n" 2840 "HT hit count (number of times event has occurred)\n" 2841 "LM hit limit (limit for autostop, disable, delete)\n"); 2842 } 2843 2844 static void 2845 dump_help(void) 2846 { 2847 mdb_printf( 2848 "-e adjust for endianness\n" 2849 " (assumes 4-byte words; use -g to change word size)\n" 2850 #ifdef _KMDB 2851 "-f no effect\n" 2852 #else 2853 "-f dump from object file\n" 2854 #endif 2855 "-g n display bytes in groups of n\n" 2856 " (default is 4; n must be a power of 2, divide line width)\n" 2857 "-p dump from physical memory\n" 2858 "-q don't print ASCII\n" 2859 "-r use relative numbering (automatically sets -u)\n" 2860 "-s elide repeated lines\n" 2861 "-t only read from and display contents of specified addresses\n" 2862 " (default is to read and print entire lines)\n" 2863 "-u un-align output\n" 2864 " (default is to align output at paragraph boundary)\n" 2865 "-w n display n 16-byte paragraphs per line\n" 2866 " (default is 1, maximum is 16)\n"); 2867 } 2868 2869 /* 2870 * Table of built-in dcmds associated with the root 'mdb' module. Future 2871 * expansion of this program should be done here, or through the external 2872 * loadable module interface. 2873 */ 2874 const mdb_dcmd_t mdb_dcmd_builtins[] = { 2875 2876 /* 2877 * dcmds common to both mdb and kmdb 2878 */ 2879 { ">", "variable-name", "assign variable", cmd_assign_variable }, 2880 { "/", "fmt-list", "format data from virtual as", cmd_print_core }, 2881 { "\\", "fmt-list", "format data from physical as", cmd_print_phys }, 2882 { "@", "fmt-list", "format data from physical as", cmd_print_phys }, 2883 { "=", "fmt-list", "format immediate value", cmd_print_value }, 2884 { "$<", "macro-name", "replace input with macro", 2885 cmd_exec_file, srcexec_file_help }, 2886 { "$<<", "macro-name", "source macro", 2887 cmd_src_file, srcexec_file_help}, 2888 { "$%", NULL, NULL, cmd_quit }, 2889 { "$?", NULL, "print status and registers", cmd_notsup }, 2890 { "$a", NULL, NULL, cmd_algol }, 2891 { "$b", "[-av]", "list traced software events", 2892 cmd_events, events_help }, 2893 { "$c", "?[cnt]", "print stack backtrace", cmd_notsup }, 2894 { "$C", "?[cnt]", "print stack backtrace", cmd_notsup }, 2895 { "$d", NULL, "get/set default output radix", cmd_radix }, 2896 { "$D", "?[mode,...]", NULL, cmd_dbmode }, 2897 { "$e", NULL, "print listing of global symbols", cmd_globals }, 2898 { "$f", NULL, "print listing of source files", cmd_files }, 2899 { "$m", "?[name]", "print address space mappings", cmd_mappings }, 2900 { "$M", NULL, "list macro aliases", cmd_macalias_list }, 2901 { "$P", "[prompt]", "set debugger prompt string", cmd_prompt }, 2902 { "$q", NULL, "quit debugger", cmd_quit }, 2903 { "$Q", NULL, "quit debugger", cmd_quit }, 2904 { "$r", NULL, "print general-purpose registers", cmd_notsup }, 2905 { "$s", NULL, "get/set symbol matching distance", cmd_symdist }, 2906 { "$v", NULL, "print non-zero variables", cmd_nzvars }, 2907 { "$V", "[mode]", "get/set disassembly mode", cmd_dismode }, 2908 { "$w", NULL, "get/set output page width", cmd_pgwidth }, 2909 { "$W", NULL, "re-open target in write mode", cmd_reopen }, 2910 { ":a", ":[cmd...]", "set read access watchpoint", cmd_oldwpr }, 2911 { ":b", ":[cmd...]", "breakpoint at the specified address", cmd_oldbp }, 2912 { ":d", "?[id|all]", "delete traced software events", cmd_delete }, 2913 { ":p", ":[cmd...]", "set execute access watchpoint", cmd_oldwpx }, 2914 { ":S", NULL, NULL, cmd_step }, 2915 { ":w", ":[cmd...]", "set write access watchpoint", cmd_oldwpw }, 2916 { ":z", NULL, "delete all traced software events", cmd_zapall }, 2917 { "array", ":[type count] [variable]", "print each array element's " 2918 "address", cmd_array }, 2919 { "bp", "?[+/-dDestT] [-c cmd] [-n count] sym ...", "breakpoint at the " 2920 "specified addresses or symbols", cmd_bp, bp_help }, 2921 { "dcmds", NULL, "list available debugger commands", cmd_dcmds }, 2922 { "delete", "?[id|all]", "delete traced software events", cmd_delete }, 2923 { "dis", "?[-abfw] [-n cnt] [addr]", "disassemble near addr", cmd_dis }, 2924 { "disasms", NULL, "list available disassemblers", cmd_disasms }, 2925 { "dismode", "[mode]", "get/set disassembly mode", cmd_dismode }, 2926 { "dmods", "[-l] [mod]", "list loaded debugger modules", cmd_dmods }, 2927 { "dump", "?[-eqrstu] [-f|-p] [-g bytes] [-w paragraphs]", 2928 "dump memory from specified address", cmd_dump, dump_help }, 2929 { "echo", "args ...", "echo arguments", cmd_echo }, 2930 { "enum", "?[-ex] enum [name]", "print an enumeration", cmd_enum, 2931 enum_help }, 2932 { "eval", "command", "evaluate the specified command", cmd_eval }, 2933 { "events", "[-av]", "list traced software events", 2934 cmd_events, events_help }, 2935 { "evset", "?[+/-dDestT] [-c cmd] [-n count] id ...", 2936 "set software event specifier attributes", cmd_evset, evset_help }, 2937 { "files", "[object]", "print listing of source files", cmd_files }, 2938 #ifdef __sparc 2939 { "findsym", "?[-g] [symbol|addr ...]", "search for symbol references " 2940 "in all known functions", cmd_findsym, NULL }, 2941 #endif 2942 { "formats", NULL, "list format specifiers", cmd_formats }, 2943 { "grep", "?expr", "print dot if expression is true", cmd_grep }, 2944 { "head", "-num|-n num", "limit number of elements in pipe", cmd_head, 2945 head_help }, 2946 { "help", "[cmd]", "list commands/command help", cmd_help, NULL, 2947 cmd_help_tab }, 2948 { "list", "?type member [variable]", 2949 "walk list using member as link pointer", cmd_list, NULL, 2950 mdb_tab_complete_mt }, 2951 { "map", "?expr", "print dot after evaluating expression", cmd_map }, 2952 { "mappings", "?[name]", "print address space mappings", cmd_mappings }, 2953 { "nm", "?[-DPdghnopuvx] [-f format] [-t types] [object]", 2954 "print symbols", cmd_nm, nm_help }, 2955 { "nmadd", ":[-fo] [-e end] [-s size] name", 2956 "add name to private symbol table", cmd_nmadd, nmadd_help }, 2957 { "nmdel", "name", "remove name from private symbol table", cmd_nmdel }, 2958 { "obey", NULL, NULL, cmd_obey }, 2959 { "objects", "[-v]", "print load objects information", cmd_objects }, 2960 { "offsetof", "type member", "print the offset of a given struct " 2961 "or union member", cmd_offsetof, NULL, mdb_tab_complete_mt }, 2962 { "print", "?[-aCdhiLptx] [-c lim] [-l lim] [type] [member|offset ...]", 2963 "print the contents of a data structure", cmd_print, print_help, 2964 cmd_print_tab }, 2965 { "printf", "?format type member ...", "print and format the " 2966 "member(s) of a data structure", cmd_printf, printf_help, 2967 cmd_printf_tab }, 2968 { "regs", NULL, "print general purpose registers", cmd_notsup }, 2969 { "set", "[-wF] [+/-o opt] [-s dist] [-I path] [-L path] [-P prompt]", 2970 "get/set debugger properties", cmd_set }, 2971 { "showrev", "[-pv]", "print version information", cmd_showrev }, 2972 { "sizeof", "type", "print the size of a type", cmd_sizeof, NULL, 2973 cmd_sizeof_tab }, 2974 { "stack", "?[cnt]", "print stack backtrace", cmd_notsup }, 2975 { "stackregs", "?", "print stack backtrace and registers", 2976 cmd_notsup }, 2977 { "status", NULL, "print summary of current target", cmd_notsup }, 2978 { "term", NULL, "display current terminal type", cmd_term }, 2979 { "typeset", "[+/-t] var ...", "set variable attributes", cmd_typeset }, 2980 { "typedef", "[-c model | -d | -l | -r file ] [type] [name]", 2981 "create synthetic types", cmd_typedef, cmd_typedef_help }, 2982 { "unset", "[name ...]", "unset variables", cmd_unset }, 2983 { "vars", "[-npt]", "print listing of variables", cmd_vars }, 2984 { "version", NULL, "print debugger version string", cmd_version }, 2985 { "vtop", ":[-a as]", "print physical mapping of virtual address", 2986 cmd_vtop }, 2987 { "walk", "?name [variable]", "walk data structure", cmd_walk, NULL, 2988 cmd_walk_tab }, 2989 { "walkers", NULL, "list available walkers", cmd_walkers }, 2990 { "whatis", ":[-aikqv]", "given an address, return information", 2991 cmd_whatis, whatis_help }, 2992 { "whence", "[-v] name ...", "show source of walk or dcmd", cmd_which }, 2993 { "which", "[-v] name ...", "show source of walk or dcmd", cmd_which }, 2994 { "xdata", NULL, "print list of external data buffers", cmd_xdata }, 2995 2996 #ifdef _KMDB 2997 /* 2998 * dcmds specific to kmdb, or which have kmdb-specific arguments 2999 */ 3000 { "?", "fmt-list", "format data from virtual as", cmd_print_core }, 3001 { ":c", NULL, "continue target execution", cmd_cont }, 3002 { ":e", NULL, "step target over next instruction", cmd_next }, 3003 { ":s", NULL, "single-step target to next instruction", cmd_step }, 3004 { ":u", NULL, "step target out of current function", cmd_step_out }, 3005 { "cont", NULL, "continue target execution", cmd_cont }, 3006 { "load", "[-sd] module", "load debugger module", cmd_load, load_help }, 3007 { "next", NULL, "step target over next instruction", cmd_next }, 3008 { "quit", "[-u]", "quit debugger", cmd_quit, quit_help }, 3009 { "step", "[ over | out ]", 3010 "single-step target to next instruction", cmd_step }, 3011 { "unload", "[-d] module", "unload debugger module", cmd_unload, 3012 unload_help }, 3013 { "wp", ":[+/-dDelstT] [-rwx] [-pi] [-c cmd] [-n count] [-L size]", 3014 "set a watchpoint at the specified address", cmd_wp, wp_help }, 3015 3016 #else 3017 /* 3018 * dcmds specific to mdb, or which have mdb-specific arguments 3019 */ 3020 { "?", "fmt-list", "format data from object file", cmd_print_object }, 3021 { "$>", "[file]", "log session to a file", cmd_old_log }, 3022 { "$g", "?", "get/set C++ demangling options", cmd_demflags }, 3023 { "$G", NULL, "enable/disable C++ demangling support", cmd_demangle }, 3024 { "$i", NULL, "print signals that are ignored", cmd_notsup }, 3025 { "$l", NULL, "print the representative thread's lwp id", cmd_notsup }, 3026 { "$p", ":", "change debugger target context", cmd_context }, 3027 { "$x", NULL, "print floating point registers", cmd_notsup }, 3028 { "$X", NULL, "print floating point registers", cmd_notsup }, 3029 { "$y", NULL, "print floating point registers", cmd_notsup }, 3030 { "$Y", NULL, "print floating point registers", cmd_notsup }, 3031 { ":A", "?[core|pid]", "attach to process or core file", cmd_notsup }, 3032 { ":c", "[SIG]", "continue target execution", cmd_cont }, 3033 { ":e", "[SIG]", "step target over next instruction", cmd_next }, 3034 { ":i", ":", "ignore signal (delete all matching events)", cmd_notsup }, 3035 { ":k", NULL, "forcibly kill and release target", cmd_notsup }, 3036 { ":t", "?[+/-dDestT] [-c cmd] [-n count] SIG ...", "stop on delivery " 3037 "of the specified signals", cmd_sigbp, sigbp_help }, 3038 { ":r", "[ args ... ]", "run a new target process", cmd_run }, 3039 { ":R", NULL, "release the previously attached process", cmd_notsup }, 3040 { ":s", "[SIG]", "single-step target to next instruction", cmd_step }, 3041 { ":u", "[SIG]", "step target out of current function", cmd_step_out }, 3042 { "attach", "?[core|pid]", 3043 "attach to process or core file", cmd_notsup }, 3044 { "cat", "[file ...]", "concatenate and display files", cmd_cat }, 3045 { "cont", "[SIG]", "continue target execution", cmd_cont }, 3046 { "context", ":", "change debugger target context", cmd_context }, 3047 { "dem", "name ...", "demangle C++ symbol names", cmd_demstr }, 3048 { "fltbp", "?[+/-dDestT] [-c cmd] [-n count] fault ...", 3049 "stop on machine fault", cmd_fltbp, fltbp_help }, 3050 { "fpregs", NULL, "print floating point registers", cmd_notsup }, 3051 { "kill", NULL, "forcibly kill and release target", cmd_notsup }, 3052 { "load", "[-s] module", "load debugger module", cmd_load, load_help }, 3053 { "log", "[-d | [-e] file]", "log session to a file", cmd_log }, 3054 { "next", "[SIG]", "step target over next instruction", cmd_next }, 3055 { "quit", NULL, "quit debugger", cmd_quit }, 3056 { "release", NULL, 3057 "release the previously attached process", cmd_notsup }, 3058 { "run", "[ args ... ]", "run a new target process", cmd_run }, 3059 { "sigbp", "?[+/-dDestT] [-c cmd] [-n count] SIG ...", "stop on " 3060 "delivery of the specified signals", cmd_sigbp, sigbp_help }, 3061 { "step", "[ over | out ] [SIG]", 3062 "single-step target to next instruction", cmd_step }, 3063 { "sysbp", "?[+/-dDestT] [-io] [-c cmd] [-n count] syscall ...", 3064 "stop on entry or exit from system call", cmd_sysbp, sysbp_help }, 3065 { "unload", "module", "unload debugger module", cmd_unload }, 3066 { "wp", ":[+/-dDelstT] [-rwx] [-c cmd] [-n count] [-L size]", 3067 "set a watchpoint at the specified address", cmd_wp, wp_help }, 3068 #endif 3069 3070 { NULL } 3071 }; 3072