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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <mdb/mdb_modapi.h> 30 #include <mdb/mdb_ks.h> 31 32 #include <sys/types.h> 33 #include <sys/strsubr.h> 34 #include <sys/stream.h> 35 #include <sys/modctl.h> 36 #include <sys/strft.h> 37 #include <sys/strsun.h> 38 #include <sys/sysmacros.h> 39 40 #include "streams.h" 41 42 typedef struct str_flags { 43 uint_t strf_flag; 44 const char *strf_name; 45 const char *strf_descr; 46 } strflags_t; 47 48 typedef struct str_types { 49 const char *strt_name; 50 int strt_value; 51 const char *strt_descr; 52 } strtypes_t; 53 54 typedef struct ftblk_data { 55 ftblk_t ft_data; /* Copy of ftblk */ 56 int ft_ix; /* Index in event list */ 57 boolean_t ft_in_evlist; /* Iterating through evlist */ 58 } ftblkdata_t; 59 60 typedef void qprint_func(queue_t *, queue_t *); 61 typedef void sdprint_func(stdata_t *, stdata_t *); 62 63 #define SF(flag) flag, #flag 64 65 /* 66 * Queue flags 67 */ 68 static const strflags_t qf[] = { 69 { SF(QENAB), "Queue is already enabled to run" }, 70 { SF(QWANTR), "Someone wants to read Q" }, 71 { SF(QWANTW), "Someone wants to write Q" }, 72 { SF(QFULL), "Q is considered full" }, 73 { SF(QREADR), "This is the reader (first) Q" }, 74 { SF(QUSE), "This queue in use (allocation)" }, 75 { SF(QNOENB), "Don't enable Q via putq" }, 76 { SF(QWANTRMQSYNC), "Want to remove sync stream Q" }, 77 { SF(QBACK), "queue has been back-enabled" }, 78 { SF(0x00000200), "unused (was QHLIST)" }, 79 { SF(0x00000400), "unused (was QUNSAFE)" }, 80 { SF(QPAIR), "per queue-pair syncq" }, 81 { SF(QPERQ), "per queue-instance syncq" }, 82 { SF(QPERMOD), "per module syncq" }, 83 { SF(QMTSAFE), "stream module is MT-safe" }, 84 { SF(QMTOUTPERIM), "Has outer perimeter" }, 85 { SF(QINSERVICE), "service routine executing" }, 86 { SF(QWCLOSE), "will not be enabled" }, 87 { SF(QEND), "last queue in stream" }, 88 { SF(QWANTWSYNC), "Streamhead wants to write Q" }, 89 { SF(QSYNCSTR), "Q supports Synchronous STREAMS" }, 90 { SF(QISDRV), "the Queue is attached to a driver" }, 91 { SF(0x00400000), "unused (was QHOT)" }, 92 { SF(0x00800000), "unused (was QNEXTHOT)" }, 93 { SF(0x01000000), "unused (was _QNEXTLESS)" }, 94 { SF(0x02000000), "unused" }, 95 { SF(_QINSERTING), "module is inserted with _I_INSERT" }, 96 { SF(_QREMOVING) "module is removed with _I_REMOVE" }, 97 { SF(_QASSOCIATED), "queue is associated with a device" }, 98 { 0, NULL, NULL } 99 }; 100 101 /* 102 * Syncq flags 103 */ 104 static const struct str_flags sqf[] = { 105 { SF(SQ_EXCL), "Exclusive access to inner perimeter" }, 106 { SF(SQ_BLOCKED), "qprocsoff in progress" }, 107 { SF(SQ_FROZEN), "freezestr in progress" }, 108 { SF(SQ_WRITER), "qwriter(OUTER) pending or running" }, 109 { SF(SQ_MESSAGES), "There are messages on syncq" }, 110 { SF(SQ_WANTWAKEUP) "Thread waiting on sq_wait" }, 111 { SF(SQ_WANTEXWAKEUP), "Thread waiting on sq_exwait" }, 112 { SF(SQ_EVENTS), "There are events on syncq" }, 113 { 0, NULL, NULL } 114 }; 115 116 /* 117 * Syncq types 118 */ 119 static const struct str_flags sqt[] = { 120 { SF(SQ_CIPUT), "Concurrent inner put procedure" }, 121 { SF(SQ_CISVC), "Concurrent inner svc procedure" }, 122 { SF(SQ_CIOC), "Concurrent inner open/close" }, 123 { SF(SQ_CICB), "Concurrent inner callback" }, 124 { SF(SQ_COPUT), "Concurrent outer put procedure" }, 125 { SF(SQ_COSVC), "Concurrent outer svc procedure" }, 126 { SF(SQ_COOC), "Concurrent outer open/close" }, 127 { SF(SQ_COCB), "Concurrent outer callback" }, 128 { 0, NULL, NULL } 129 }; 130 131 /* 132 * Stdata flags 133 */ 134 static const struct str_flags stdf[] = { 135 { SF(IOCWAIT), "someone is doing an ioctl" }, 136 { SF(RSLEEP), "someone wants to read/recv msg" }, 137 { SF(WSLEEP), "someone wants to write" }, 138 { SF(STRPRI), "an M_PCPROTO is at stream head" }, 139 { SF(STRHUP), "device has vanished" }, 140 { SF(STWOPEN), "waiting for 1st open" }, 141 { SF(STPLEX), "stream is being multiplexed" }, 142 { SF(STRISTTY), "stream is a terminal" }, 143 { SF(STRGETINPROG), "(k)strgetmsg is running" }, 144 { SF(IOCWAITNE), "STR_NOERROR ioctl running" }, 145 { SF(STRDERR), "fatal read error from M_ERROR" }, 146 { SF(STWRERR), "fatal write error from M_ERROR" }, 147 { SF(STRDERRNONPERSIST), "nonpersistent read errors" }, 148 { SF(STWRERRNONPERSIST), "nonpersistent write errors" }, 149 { SF(STRCLOSE), "wait for a close to complete" }, 150 { SF(SNDMREAD), "used for read notification" }, 151 { SF(OLDNDELAY), "use old NDELAY TTY semantics" }, 152 { SF(0x00020000), "unused" }, 153 { SF(0x00040000), "unused" }, 154 { SF(STRTOSTOP), "block background writes" }, 155 { SF(0x00100000), "unused" }, 156 { SF(0x00200000), "unused" }, 157 { SF(STRMOUNT), "stream is mounted" }, 158 { SF(STRNOTATMARK), "Not at mark (when empty read q)" }, 159 { SF(STRDELIM), "generate delimited messages" }, 160 { SF(STRATMARK), "at mark (due to MSGMARKNEXT)" }, 161 { SF(STZCNOTIFY), "wait for zerocopy mblk to be acked" }, 162 { SF(STRPLUMB), "stream plumbing changes in progress" }, 163 { SF(STREOF), "End-of-file indication" }, 164 { SF(STREOPENFAIL), "re-open has failed" }, 165 { SF(STRMATE), "this stream is a mate" }, 166 { SF(STRHASLINKS), "there are I_LINKs under this stream" }, 167 { 0, NULL, NULL } 168 }; 169 170 static const struct str_flags mbf[] = { 171 { SF(MSGMARK), "last byte of message is marked" }, 172 { SF(MSGNOLOOP), "don't loop message to write side" }, 173 { SF(MSGDELIM), "message is delimited" }, 174 { SF(0x08), "unused" }, 175 { SF(MSGMARKNEXT), "Private: b_next's first byte marked" }, 176 { SF(MSGNOTMARKNEXT), "Private: ... not marked" }, 177 { SF(MSGHASREF), "Private: msg has reference to owner" }, 178 { 0, NULL, NULL } 179 }; 180 181 #define M_DATA_T 0xff 182 183 static const strtypes_t mbt[] = { 184 { "M_DATA", M_DATA_T, "regular data" }, 185 { "M_PROTO", M_PROTO, "protocol control" }, 186 { "M_MULTIDATA", M_MULTIDATA, "multidata" }, 187 { "M_BREAK", M_BREAK, "line break" }, 188 { "M_PASSFP", M_PASSFP, "pass file pointer" }, 189 { "M_EVENT", M_EVENT, "Obsoleted: do not use" }, 190 { "M_SIG", M_SIG, "generate process signal" }, 191 { "M_DELAY", M_DELAY, "real-time xmit delay" }, 192 { "M_CTL", M_CTL, "device-specific control message" }, 193 { "M_IOCTL", M_IOCTL, "ioctl; set/get params" }, 194 { "M_SETOPTS", M_SETOPTS, "set stream head options" }, 195 { "M_RSE", M_RSE, "reserved for RSE use only" }, 196 { "M_IOCACK", M_IOCACK, "acknowledge ioctl" }, 197 { "M_IOCNAK", M_IOCNAK, "negative ioctl acknowledge" }, 198 { "M_PCPROTO", M_PCPROTO, "priority proto message" }, 199 { "M_PCSIG", M_PCSIG, "generate process signal" }, 200 { "M_READ", M_READ, "generate read notification" }, 201 { "M_FLUSH", M_FLUSH, "flush your queues" }, 202 { "M_STOP", M_STOP, "stop transmission immediately" }, 203 { "M_START", M_START, "restart transmission after stop" }, 204 { "M_HANGUP", M_HANGUP, "line disconnect" }, 205 { "M_ERROR", M_ERROR, "send error to stream head" }, 206 { "M_COPYIN", M_COPYIN, "request to copyin data" }, 207 { "M_COPYOUT", M_COPYOUT, "request to copyout data" }, 208 { "M_IOCDATA", M_IOCDATA, "response to M_COPYIN and M_COPYOUT" }, 209 { "M_PCRSE", M_PCRSE, "reserved for RSE use only" }, 210 { "M_STOPI", M_STOPI, "stop reception immediately" }, 211 { "M_STARTI", M_STARTI, "restart reception after stop" }, 212 { "M_PCEVENT", M_PCEVENT, "Obsoleted: do not use" }, 213 { "M_UNHANGUP", M_UNHANGUP, "line reconnect" }, 214 { NULL, 0, NULL } 215 }; 216 217 /* Allocation flow trace events, starting from 0 */ 218 static const char *ftev_alloc[] = { 219 /* 0 */ ":allocb", 220 /* 1 */ ":esballoc", 221 /* 2 */ ":desballoc", 222 /* 3 */ ":esballoca", 223 /* 4 */ ":desballoca", 224 /* 5 */ ":allocbig", 225 /* 6 */ ":allocbw", 226 /* 7 */ ":bcallocb", 227 /* 8 */ ":freeb", 228 /* 9 */ ":dupb", 229 /* A */ ":copyb", 230 }; 231 232 #define FTEV_PROC_START FTEV_PUT 233 234 /* Procedures recorded by flow tracing, starting from 0x100 */ 235 static const char *ftev_proc[] = { 236 /* 100 */ ":put", 237 /* 101 */ ":undefined (0x101)", 238 /* 102 */ ":undefined (0x102)", 239 /* 103 */ ":undefined (0x103)", 240 /* 104 */ ":undefined (0x104)", 241 /* 105 */ ":putq", 242 /* 106 */ ":getq", 243 /* 107 */ ":rmvq", 244 /* 108 */ ":insq", 245 /* 109 */ ":putbq", 246 /* 10A */ ":flushq", 247 /* 10B */ ":undefined (0x10b)", 248 /* 10C */ ":undefined (0x10c)", 249 /* 10D */ ":putnext", 250 /* 10E */ ":rwnext", 251 }; 252 253 static const char *db_control_types[] = { 254 /* 00 */ "data", 255 /* 01 */ "proto", 256 /* 02 */ "multidata", 257 /* 03 */ "unused (0x03)", 258 /* 04 */ "unused (0x04)", 259 /* 05 */ "unused (0x05)", 260 /* 06 */ "unused (0x06)", 261 /* 07 */ "unused (0x07)", 262 /* 08 */ "break", 263 /* 09 */ "passfp", 264 /* 0a */ "event", 265 /* 0b */ "sig", 266 /* 0c */ "delay", 267 /* 0d */ "ctl", 268 /* 0e */ "ioctl", 269 /* 0f */ "unused", 270 /* 10 */ "setopts", 271 /* 11 */ "rse", 272 }; 273 274 static const char *db_control_hipri_types[] = { 275 /* 81 */ "iocack", 276 /* 82 */ "iocnak", 277 /* 83 */ "pcproto", 278 /* 84 */ "pcsig", 279 /* 85 */ "read", 280 /* 86 */ "flush", 281 /* 87 */ "stop", 282 /* 88 */ "start", 283 /* 89 */ "hangup", 284 /* 8a */ "error", 285 /* 8b */ "copyin", 286 /* 8c */ "copyout", 287 /* 8d */ "iocdata", 288 /* 8e */ "pcrse", 289 /* 8f */ "stopi", 290 /* 90 */ "starti", 291 /* 91 */ "pcevent", 292 /* 92 */ "unhangup", 293 }; 294 295 296 #define A_SIZE(a) (sizeof (a) / sizeof (a[0])) 297 298 static void ft_printevent(ushort_t); 299 300 static int 301 streams_parse_flag(const strflags_t ftable[], const char *arg, uint32_t *flag) 302 { 303 int i; 304 305 for (i = 0; ftable[i].strf_name != NULL; i++) { 306 if (strcasecmp(arg, ftable[i].strf_name) == 0) { 307 *flag |= (1 << i); 308 return (0); 309 } 310 } 311 312 return (-1); 313 } 314 315 static void 316 streams_flag_usage(const strflags_t ftable[]) 317 { 318 int i; 319 320 for (i = 0; ftable[i].strf_name != NULL; i++) 321 mdb_printf("%-14s %s\n", 322 ftable[i].strf_name, ftable[i].strf_descr); 323 } 324 325 static int 326 streams_parse_type(const strtypes_t ftable[], const char *arg, uint32_t *flag) 327 { 328 int i; 329 330 for (i = 0; ftable[i].strt_name != NULL; i++) { 331 if (strcasecmp(arg, ftable[i].strt_name) == 0) { 332 *flag = ftable[i].strt_value; 333 return (0); 334 } 335 } 336 337 return (-1); 338 } 339 340 static void 341 streams_type_usage(const strtypes_t ftable[]) 342 { 343 int i; 344 345 for (i = 0; ftable[i].strt_name != NULL; i++) 346 mdb_printf("%-12s %s\n", 347 ftable[i].strt_name, ftable[i].strt_descr); 348 } 349 350 int 351 queue(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 352 { 353 const int QUEUE_FLGDELT = (int)(sizeof (uintptr_t) * 2 + 15); 354 355 char name[MODMAXNAMELEN]; 356 int nblks = 0; 357 uintptr_t maddr; 358 mblk_t mblk; 359 queue_t q; 360 361 const char *mod = NULL, *flag = NULL, *not_flag = NULL; 362 uint_t quiet = FALSE; 363 uint_t verbose = FALSE; 364 uint32_t mask = 0, not_mask = 0; 365 uintptr_t syncq = 0; 366 367 if (!(flags & DCMD_ADDRSPEC)) { 368 if (mdb_walk_dcmd("genunix`queue_cache", "genunix`queue", 369 argc, argv) == -1) { 370 mdb_warn("failed to walk queue cache"); 371 return (DCMD_ERR); 372 } 373 return (DCMD_OK); 374 } 375 376 if (flags & DCMD_PIPE_OUT) 377 quiet = TRUE; 378 379 if (mdb_getopts(argc, argv, 380 'v', MDB_OPT_SETBITS, TRUE, &verbose, 381 'q', MDB_OPT_SETBITS, TRUE, &quiet, 382 'm', MDB_OPT_STR, &mod, 383 'f', MDB_OPT_STR, &flag, 384 'F', MDB_OPT_STR, ¬_flag, 385 's', MDB_OPT_UINTPTR, &syncq, 386 NULL) != argc) 387 return (DCMD_USAGE); 388 389 /* 390 * If any of the filtering flags is specified, don't print anything 391 * except the matching pointer. 392 */ 393 if (flag != NULL || not_flag != NULL || mod != NULL || syncq != NULL) 394 quiet = TRUE; 395 396 if (DCMD_HDRSPEC(flags) && !quiet) { 397 mdb_printf("%?s %-13s %6s %4s\n", 398 "ADDR", "MODULE", "FLAGS", "NBLK"); 399 } 400 401 if (flag != NULL && streams_parse_flag(qf, flag, &mask) == -1) { 402 mdb_warn("unrecognized queue flag '%s'\n", flag); 403 streams_flag_usage(qf); 404 return (DCMD_USAGE); 405 } 406 407 if (not_flag != NULL && 408 streams_parse_flag(qf, not_flag, ¬_mask) == -1) { 409 mdb_warn("unrecognized queue flag '%s'\n", flag); 410 streams_flag_usage(qf); 411 return (DCMD_USAGE); 412 } 413 414 if (mdb_vread(&q, sizeof (q), addr) == -1) { 415 mdb_warn("couldn't read queue at %p", addr); 416 return (DCMD_ERR); 417 } 418 419 for (maddr = (uintptr_t)q.q_first; maddr != NULL; nblks++) { 420 if (mdb_vread(&mblk, sizeof (mblk), maddr) == -1) { 421 mdb_warn("couldn't read mblk %p for queue %p", 422 maddr, addr); 423 break; 424 } 425 maddr = (uintptr_t)mblk.b_next; 426 } 427 428 (void) mdb_qname(&q, name, sizeof (name)); 429 430 /* 431 * If queue doesn't pass filtering criteria, don't print anything and 432 * just return. 433 */ 434 435 if (mod != NULL && strcmp(mod, name) != 0) 436 return (DCMD_OK); 437 438 if (mask != 0 && !(q.q_flag & mask)) 439 return (DCMD_OK); 440 441 if (not_mask != 0 && (q.q_flag & not_mask)) 442 return (DCMD_OK); 443 444 if (syncq != 0 && q.q_syncq != (syncq_t *)syncq) 445 return (DCMD_OK); 446 447 /* 448 * Options are specified for filtering, so If any option is specified on 449 * the command line, just print address and exit. 450 */ 451 if (quiet) { 452 mdb_printf("%0?p\n", addr); 453 return (DCMD_OK); 454 } 455 456 mdb_printf("%0?p %-13s %06x %4d %0?p\n", 457 addr, name, q.q_flag, nblks, q.q_first); 458 459 if (verbose) { 460 int i, arm = 0; 461 462 for (i = 0; qf[i].strf_name != NULL; i++) { 463 if (!(q.q_flag & (1 << i))) 464 continue; 465 if (!arm) { 466 mdb_printf("%*s|\n%*s+--> ", 467 QUEUE_FLGDELT, "", QUEUE_FLGDELT, ""); 468 arm = 1; 469 } else 470 mdb_printf("%*s ", QUEUE_FLGDELT, ""); 471 472 mdb_printf("%-12s %s\n", 473 qf[i].strf_name, qf[i].strf_descr); 474 } 475 } 476 477 return (DCMD_OK); 478 } 479 480 int 481 syncq(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 482 { 483 const int SYNC_FLGDELT = (int)(sizeof (uintptr_t) * 2 + 1); 484 const int SYNC_TYPDELT = (int)(sizeof (uintptr_t) * 2 + 5); 485 syncq_t sq; 486 487 const char *flag = NULL, *not_flag = NULL; 488 const char *typ = NULL, *not_typ = NULL; 489 uint_t verbose = FALSE; 490 uint_t quiet = FALSE; 491 uint32_t mask = 0, not_mask = 0; 492 uint32_t tmask = 0, not_tmask = 0; 493 uint8_t sqtype = 0; 494 495 if (!(flags & DCMD_ADDRSPEC)) { 496 if (mdb_walk_dcmd("genunix`syncq_cache", "genunix`syncq", 497 argc, argv) == -1) { 498 mdb_warn("failed to walk syncq cache"); 499 return (DCMD_ERR); 500 } 501 return (DCMD_OK); 502 } 503 504 if (flags & DCMD_PIPE_OUT) 505 quiet = TRUE; 506 507 if (mdb_getopts(argc, argv, 508 'v', MDB_OPT_SETBITS, TRUE, &verbose, 509 'q', MDB_OPT_SETBITS, TRUE, &quiet, 510 'f', MDB_OPT_STR, &flag, 511 'F', MDB_OPT_STR, ¬_flag, 512 't', MDB_OPT_STR, &typ, 513 'T', MDB_OPT_STR, ¬_typ, 514 NULL) != argc) 515 return (DCMD_USAGE); 516 517 /* 518 * If any of the filtering flags is specified, don't print anything 519 * except the matching pointer. 520 */ 521 if (flag != NULL || not_flag != NULL || typ != NULL || not_typ != NULL) 522 quiet = TRUE; 523 524 if (DCMD_HDRSPEC(flags) && !quiet) { 525 mdb_printf("%?s %s %s %s %s %?s %s %s\n", 526 "ADDR", "FLG", "TYP", "CNT", "NQS", "OUTER", "SF", "PRI"); 527 } 528 529 if (flag != NULL && streams_parse_flag(sqf, flag, &mask) == -1) { 530 mdb_warn("unrecognized syncq flag '%s'\n", flag); 531 streams_flag_usage(sqf); 532 return (DCMD_USAGE); 533 } 534 535 if (typ != NULL && streams_parse_flag(sqt, typ, &tmask) == -1) { 536 mdb_warn("unrecognized syncq type '%s'\n", typ); 537 streams_flag_usage(sqt); 538 return (DCMD_USAGE); 539 } 540 541 if (not_flag != NULL && streams_parse_flag(sqf, not_flag, ¬_mask) 542 == -1) { 543 mdb_warn("unrecognized syncq flag '%s'\n", not_flag); 544 streams_flag_usage(sqf); 545 return (DCMD_USAGE); 546 } 547 548 if (not_typ != NULL && streams_parse_flag(sqt, not_typ, ¬_tmask) 549 == -1) { 550 mdb_warn("unrecognized syncq type '%s'\n", not_typ); 551 streams_flag_usage(sqt); 552 return (DCMD_USAGE); 553 } 554 555 if (mdb_vread(&sq, sizeof (sq), addr) == -1) { 556 mdb_warn("couldn't read syncq at %p", addr); 557 return (DCMD_ERR); 558 } 559 560 if (mask != 0 && !(sq.sq_flags & mask)) 561 return (DCMD_OK); 562 563 if (not_mask != 0 && (sq.sq_flags & not_mask)) 564 return (DCMD_OK); 565 566 sqtype = (sq.sq_type >> 8) & 0xff; 567 568 if (tmask != 0 && !(sqtype & tmask)) 569 return (DCMD_OK); 570 571 if (not_tmask != 0 && (sqtype & not_tmask)) 572 return (DCMD_OK); 573 574 /* 575 * Options are specified for filtering, so If any option is specified on 576 * the command line, just print address and exit. 577 */ 578 if (quiet) { 579 mdb_printf("%0?p\n", addr); 580 return (DCMD_OK); 581 } 582 583 mdb_printf("%0?p %02x %02x %-3u %-3u %0?p %1x %-3d\n", 584 addr, sq.sq_flags & 0xff, sqtype, sq.sq_count, 585 sq.sq_nqueues, sq.sq_outer, sq.sq_svcflags, sq.sq_pri); 586 587 if (verbose) { 588 int i, arm = 0; 589 590 for (i = 0; sqf[i].strf_name != NULL; i++) { 591 if (!(sq.sq_flags & (1 << i))) 592 continue; 593 if (!arm) { 594 mdb_printf("%*s|\n%*s+--> ", 595 SYNC_FLGDELT, "", SYNC_FLGDELT, ""); 596 arm = 1; 597 } else 598 mdb_printf("%*s ", SYNC_FLGDELT, ""); 599 600 mdb_printf("%-12s %s\n", 601 sqf[i].strf_name, sqf[i].strf_descr); 602 } 603 604 for (i = 0; sqt[i].strf_name != NULL; i++) { 605 if (!(sqtype & (1 << i))) 606 continue; 607 if (!arm) { 608 mdb_printf("%*s|\n%*s+--> ", 609 SYNC_TYPDELT, "", SYNC_TYPDELT, ""); 610 arm = 1; 611 } else 612 mdb_printf("%*s ", SYNC_TYPDELT, ""); 613 614 mdb_printf("%-12s %s\n", 615 sqt[i].strf_name, sqt[i].strf_descr); 616 } 617 } 618 619 return (DCMD_OK); 620 } 621 622 int 623 stdata(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 624 { 625 const int STREAM_FLGDELT = (int)(sizeof (uintptr_t) * 2 + 10); 626 627 stdata_t sd; 628 629 const char *flag = NULL, *not_flag = NULL; 630 uint_t verbose = FALSE; 631 uint_t quiet = FALSE; 632 uint32_t mask = 0, not_mask = 0; 633 634 if (!(flags & DCMD_ADDRSPEC)) { 635 if (mdb_walk_dcmd("genunix`stream_head_cache", 636 "genunix`stdata", argc, argv) == -1) { 637 mdb_warn("failed to walk stream head cache"); 638 return (DCMD_ERR); 639 } 640 return (DCMD_OK); 641 } 642 643 if (flags & DCMD_PIPE_OUT) 644 quiet = TRUE; 645 646 if (mdb_getopts(argc, argv, 647 'v', MDB_OPT_SETBITS, TRUE, &verbose, 648 'q', MDB_OPT_SETBITS, TRUE, &quiet, 649 'f', MDB_OPT_STR, &flag, 650 'F', MDB_OPT_STR, ¬_flag, 651 NULL) != argc) 652 return (DCMD_USAGE); 653 654 /* 655 * If any of the filtering flags is specified, don't print anything 656 * except the matching pointer. 657 */ 658 if (flag != NULL || not_flag != NULL) 659 quiet = TRUE; 660 661 if (DCMD_HDRSPEC(flags) && !quiet) { 662 mdb_printf("%?s %?s %8s %?s %s %s\n", 663 "ADDR", "WRQ", "FLAGS", "VNODE", "N/A", "REF"); 664 } 665 666 if (flag != NULL && streams_parse_flag(stdf, flag, &mask) == -1) { 667 mdb_warn("unrecognized stream flag '%s'\n", flag); 668 streams_flag_usage(stdf); 669 return (DCMD_USAGE); 670 } 671 672 if (not_flag != NULL && 673 streams_parse_flag(stdf, not_flag, ¬_mask) == -1) { 674 mdb_warn("unrecognized stream flag '%s'\n", flag); 675 streams_flag_usage(stdf); 676 return (DCMD_USAGE); 677 } 678 679 if (mdb_vread(&sd, sizeof (sd), addr) == -1) { 680 mdb_warn("couldn't read stdata at %p", addr); 681 return (DCMD_ERR); 682 } 683 684 /* 685 * If stream doesn't pass filtering criteria, don't print anything and 686 * just return. 687 */ 688 689 if (mask != 0 && !(sd.sd_flag & mask)) 690 return (DCMD_OK); 691 692 if (not_mask != 0 && (sd.sd_flag & not_mask)) 693 return (DCMD_OK); 694 695 /* 696 * Options are specified for filtering, so If any option is specified on 697 * the command line, just print address and exit. 698 */ 699 if (quiet) { 700 mdb_printf("%0?p\n", addr); 701 return (DCMD_OK); 702 } 703 704 mdb_printf("%0?p %0?p %08x %0?p %d/%d %d\n", 705 addr, sd.sd_wrq, sd.sd_flag, sd.sd_vnode, 706 sd.sd_pushcnt, sd.sd_anchor, sd.sd_refcnt); 707 708 if (verbose) { 709 int i, arm = 0; 710 711 for (i = 0; stdf[i].strf_name != NULL; i++) { 712 if (!(sd.sd_flag & (1 << i))) 713 continue; 714 if (!arm) { 715 mdb_printf("%*s|\n%*s+--> ", 716 STREAM_FLGDELT, "", STREAM_FLGDELT, ""); 717 arm = 1; 718 } else 719 mdb_printf("%*s ", STREAM_FLGDELT, ""); 720 721 mdb_printf("%-12s %s\n", 722 stdf[i].strf_name, stdf[i].strf_descr); 723 } 724 } 725 726 return (DCMD_OK); 727 } 728 729 /*ARGSUSED*/ 730 static void 731 qprint_syncq(queue_t *addr, queue_t *q) 732 { 733 mdb_printf("%p\n", q->q_syncq); 734 } 735 736 /*ARGSUSED*/ 737 static void 738 qprint_stream(queue_t *addr, queue_t *q) 739 { 740 mdb_printf("%p\n", q->q_stream); 741 } 742 743 static void 744 qprint_wrq(queue_t *addr, queue_t *q) 745 { 746 mdb_printf("%p\n", ((q)->q_flag & QREADR? (addr)+1: (addr))); 747 } 748 749 static void 750 qprint_rdq(queue_t *addr, queue_t *q) 751 { 752 mdb_printf("%p\n", ((q)->q_flag & QREADR? (addr): (addr)-1)); 753 } 754 755 static void 756 qprint_otherq(queue_t *addr, queue_t *q) 757 { 758 mdb_printf("%p\n", ((q)->q_flag & QREADR? (addr)+1: (addr)-1)); 759 } 760 761 static int 762 q2x(uintptr_t addr, int argc, qprint_func prfunc) 763 { 764 queue_t q; 765 766 if (argc != 0) 767 return (DCMD_USAGE); 768 769 if (mdb_vread(&q, sizeof (q), addr) == -1) { 770 mdb_warn("couldn't read queue at %p", addr); 771 return (DCMD_ERR); 772 } 773 774 prfunc((queue_t *)addr, &q); 775 776 return (DCMD_OK); 777 } 778 779 780 /*ARGSUSED*/ 781 int 782 q2syncq(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 783 { 784 return (q2x(addr, argc, qprint_syncq)); 785 } 786 787 /*ARGSUSED*/ 788 int 789 q2stream(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 790 { 791 return (q2x(addr, argc, qprint_stream)); 792 } 793 794 /*ARGSUSED*/ 795 int 796 q2rdq(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 797 { 798 return (q2x(addr, argc, qprint_rdq)); 799 } 800 801 /*ARGSUSED*/ 802 int 803 q2wrq(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 804 { 805 return (q2x(addr, argc, qprint_wrq)); 806 } 807 808 /*ARGSUSED*/ 809 int 810 q2otherq(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 811 { 812 return (q2x(addr, argc, qprint_otherq)); 813 } 814 815 static int 816 sd2x(uintptr_t addr, int argc, sdprint_func prfunc) 817 { 818 stdata_t sd; 819 820 if (argc != 0) 821 return (DCMD_USAGE); 822 823 if (mdb_vread(&sd, sizeof (sd), addr) == -1) { 824 mdb_warn("couldn't read stream head at %p", addr); 825 return (DCMD_ERR); 826 } 827 828 prfunc((stdata_t *)addr, &sd); 829 830 return (DCMD_OK); 831 } 832 833 /*ARGSUSED*/ 834 static void 835 sdprint_wrq(stdata_t *addr, stdata_t *sd) 836 { 837 mdb_printf("%p\n", sd->sd_wrq); 838 } 839 840 static void 841 sdprint_mate(stdata_t *addr, stdata_t *sd) 842 { 843 mdb_printf("%p\n", sd->sd_mate ? sd->sd_mate : addr); 844 } 845 846 /*ARGSUSED*/ 847 int 848 str2mate(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 849 { 850 return (sd2x(addr, argc, sdprint_mate)); 851 } 852 853 /*ARGSUSED*/ 854 int 855 str2wrq(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 856 { 857 return (sd2x(addr, argc, sdprint_wrq)); 858 } 859 860 861 /* 862 * If this syncq is a part of the queue pair structure, find the queue for it. 863 */ 864 /*ARGSUSED*/ 865 int 866 syncq2q(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 867 { 868 syncq_t sq; 869 queue_t q; 870 queue_t *qp; 871 872 if (argc != 0) 873 return (DCMD_USAGE); 874 875 if (mdb_vread(&sq, sizeof (sq), addr) == -1) { 876 mdb_warn("couldn't read syncq at %p", addr); 877 return (DCMD_ERR); 878 } 879 880 /* Try to find its queue */ 881 qp = (queue_t *)addr - 2; 882 883 if ((mdb_vread(&q, sizeof (q), (uintptr_t)qp) == -1) || 884 (q.q_syncq != (syncq_t *)addr)) { 885 mdb_warn("syncq2q: %p is not part of any queue\n", addr); 886 return (DCMD_ERR); 887 } else 888 mdb_printf("%p\n", qp); 889 890 return (DCMD_OK); 891 } 892 893 894 int 895 queue_walk_init(mdb_walk_state_t *wsp) 896 { 897 if (wsp->walk_addr == NULL && 898 mdb_readvar(&wsp->walk_addr, "qhead") == -1) { 899 mdb_warn("failed to read 'qhead'"); 900 return (WALK_ERR); 901 } 902 903 wsp->walk_data = mdb_alloc(sizeof (queue_t), UM_SLEEP); 904 return (WALK_NEXT); 905 } 906 907 int 908 queue_link_step(mdb_walk_state_t *wsp) 909 { 910 int status; 911 912 if (wsp->walk_addr == NULL) 913 return (WALK_DONE); 914 915 if (mdb_vread(wsp->walk_data, sizeof (queue_t), wsp->walk_addr) == -1) { 916 mdb_warn("failed to read queue at %p", wsp->walk_addr); 917 return (WALK_DONE); 918 } 919 920 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 921 wsp->walk_cbdata); 922 923 wsp->walk_addr = (uintptr_t)(((queue_t *)wsp->walk_data)->q_link); 924 return (status); 925 } 926 927 int 928 queue_next_step(mdb_walk_state_t *wsp) 929 { 930 int status; 931 932 if (wsp->walk_addr == NULL) 933 return (WALK_DONE); 934 935 if (mdb_vread(wsp->walk_data, sizeof (queue_t), wsp->walk_addr) == -1) { 936 mdb_warn("failed to read queue at %p", wsp->walk_addr); 937 return (WALK_DONE); 938 } 939 940 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 941 wsp->walk_cbdata); 942 943 wsp->walk_addr = (uintptr_t)(((queue_t *)wsp->walk_data)->q_next); 944 return (status); 945 } 946 947 void 948 queue_walk_fini(mdb_walk_state_t *wsp) 949 { 950 mdb_free(wsp->walk_data, sizeof (queue_t)); 951 } 952 953 int 954 str_walk_init(mdb_walk_state_t *wsp) 955 { 956 stdata_t s; 957 958 if (wsp->walk_addr == NULL) { 959 mdb_warn("walk must begin at address of stdata_t\n"); 960 return (WALK_ERR); 961 } 962 963 if (mdb_vread(&s, sizeof (s), wsp->walk_addr) == -1) { 964 mdb_warn("failed to read stdata at %p", wsp->walk_addr); 965 return (WALK_ERR); 966 } 967 968 wsp->walk_addr = (uintptr_t)s.sd_wrq; 969 wsp->walk_data = mdb_alloc(sizeof (queue_t) * 2, UM_SLEEP); 970 971 return (WALK_NEXT); 972 } 973 974 int 975 strr_walk_step(mdb_walk_state_t *wsp) 976 { 977 queue_t *rq = wsp->walk_data, *wq = rq + 1; 978 int status; 979 980 if (wsp->walk_addr == NULL) 981 return (WALK_DONE); 982 983 if (mdb_vread(wsp->walk_data, sizeof (queue_t) * 2, 984 wsp->walk_addr - sizeof (queue_t)) == -1) { 985 mdb_warn("failed to read queue pair at %p", 986 wsp->walk_addr - sizeof (queue_t)); 987 return (WALK_DONE); 988 } 989 990 status = wsp->walk_callback(wsp->walk_addr - sizeof (queue_t), 991 rq, wsp->walk_cbdata); 992 993 if (wq->q_next != NULL) 994 wsp->walk_addr = (uintptr_t)wq->q_next; 995 else 996 wsp->walk_addr = mdb_qwnext(wq); 997 998 return (status); 999 } 1000 1001 int 1002 strw_walk_step(mdb_walk_state_t *wsp) 1003 { 1004 queue_t *rq = wsp->walk_data, *wq = rq + 1; 1005 int status; 1006 1007 if (wsp->walk_addr == NULL) 1008 return (WALK_DONE); 1009 1010 if (mdb_vread(wsp->walk_data, sizeof (queue_t) * 2, 1011 wsp->walk_addr - sizeof (queue_t)) == -1) { 1012 mdb_warn("failed to read queue pair at %p", 1013 wsp->walk_addr - sizeof (queue_t)); 1014 return (WALK_DONE); 1015 } 1016 1017 status = wsp->walk_callback(wsp->walk_addr, wq, wsp->walk_cbdata); 1018 1019 if (wq->q_next != NULL) 1020 wsp->walk_addr = (uintptr_t)wq->q_next; 1021 else 1022 wsp->walk_addr = mdb_qwnext(wq); 1023 1024 return (status); 1025 } 1026 1027 void 1028 str_walk_fini(mdb_walk_state_t *wsp) 1029 { 1030 mdb_free(wsp->walk_data, sizeof (queue_t) * 2); 1031 } 1032 1033 static int 1034 print_qpair(uintptr_t addr, const queue_t *q, uint_t *depth) 1035 { 1036 static const char box_lid[] = 1037 "+-----------------------+-----------------------+\n"; 1038 static const char box_sep[] = 1039 "| | |\n"; 1040 1041 char wname[32], rname[32], info1[256], *info2; 1042 1043 if (*depth != 0) { 1044 mdb_printf(" | ^\n"); 1045 mdb_printf(" v |\n"); 1046 } else 1047 mdb_printf("\n"); 1048 1049 (void) mdb_qname(_WR(q), wname, sizeof (wname)); 1050 (void) mdb_qname(_RD(q), rname, sizeof (rname)); 1051 1052 mdb_qinfo(_WR(q), info1, sizeof (info1)); 1053 if ((info2 = strchr(info1, '\n')) != NULL) 1054 *info2++ = '\0'; 1055 else 1056 info2 = ""; 1057 1058 mdb_printf(box_lid); 1059 mdb_printf("| 0x%-19p | 0x%-19p | %s\n", 1060 addr, addr - sizeof (queue_t), info1); 1061 1062 mdb_printf("| %<b>%-21s%</b> | %<b>%-21s%</b> |", wname, rname); 1063 mdb_flush(); /* Account for buffered terminal sequences */ 1064 1065 mdb_printf(" %s\n", info2); 1066 mdb_printf(box_sep); 1067 1068 mdb_qinfo(_RD(q), info1, sizeof (info1)); 1069 if ((info2 = strchr(info1, '\n')) != NULL) 1070 *info2++ = '\0'; 1071 else 1072 info2 = ""; 1073 1074 mdb_printf("| cnt = 0t%-13lu | cnt = 0t%-13lu | %s\n", 1075 _WR(q)->q_count, _RD(q)->q_count, info1); 1076 1077 mdb_printf("| flg = 0x%08x | flg = 0x%08x | %s\n", 1078 _WR(q)->q_flag, _RD(q)->q_flag, info2); 1079 1080 mdb_printf(box_lid); 1081 *depth += 1; 1082 return (0); 1083 } 1084 1085 /*ARGSUSED*/ 1086 int 1087 stream(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1088 { 1089 uint_t d = 0; /* Depth counter for print_qpair */ 1090 1091 if (argc != 0 || !(flags & DCMD_ADDRSPEC)) 1092 return (DCMD_USAGE); 1093 1094 if (mdb_pwalk("writeq", (mdb_walk_cb_t)print_qpair, &d, addr) == -1) { 1095 mdb_warn("failed to walk writeq"); 1096 return (DCMD_ERR); 1097 } 1098 1099 return (DCMD_OK); 1100 } 1101 1102 int 1103 mblk_walk_init(mdb_walk_state_t *wsp) 1104 { 1105 wsp->walk_data = mdb_alloc(sizeof (mblk_t), UM_SLEEP); 1106 return (WALK_NEXT); 1107 } 1108 1109 int 1110 b_cont_step(mdb_walk_state_t *wsp) 1111 { 1112 int status; 1113 1114 if (wsp->walk_addr == NULL) 1115 return (WALK_DONE); 1116 1117 if (mdb_vread(wsp->walk_data, sizeof (mblk_t), wsp->walk_addr) == -1) { 1118 mdb_warn("failed to read mblk at %p", wsp->walk_addr); 1119 return (WALK_DONE); 1120 } 1121 1122 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 1123 wsp->walk_cbdata); 1124 1125 wsp->walk_addr = (uintptr_t)(((mblk_t *)wsp->walk_data)->b_cont); 1126 return (status); 1127 } 1128 1129 int 1130 b_next_step(mdb_walk_state_t *wsp) 1131 { 1132 int status; 1133 1134 if (wsp->walk_addr == NULL) 1135 return (WALK_DONE); 1136 1137 if (mdb_vread(wsp->walk_data, sizeof (mblk_t), wsp->walk_addr) == -1) { 1138 mdb_warn("failed to read mblk at %p", wsp->walk_addr); 1139 return (WALK_DONE); 1140 } 1141 1142 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 1143 wsp->walk_cbdata); 1144 1145 wsp->walk_addr = (uintptr_t)(((mblk_t *)wsp->walk_data)->b_next); 1146 return (status); 1147 } 1148 1149 void 1150 mblk_walk_fini(mdb_walk_state_t *wsp) 1151 { 1152 mdb_free(wsp->walk_data, sizeof (mblk_t)); 1153 } 1154 1155 /* ARGSUSED */ 1156 int 1157 mblk2dblk(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1158 { 1159 mblk_t mb; 1160 1161 if (argc != 0) 1162 return (DCMD_USAGE); 1163 1164 if (mdb_vread(&mb, sizeof (mb), addr) == -1) { 1165 mdb_warn("couldn't read mblk at %p", addr); 1166 return (DCMD_ERR); 1167 } 1168 1169 mdb_printf("%p\n", mb.b_datap); 1170 return (DCMD_OK); 1171 } 1172 1173 1174 static void 1175 mblk_error(int *error, uintptr_t addr, char *message) 1176 { 1177 if (!*error) 1178 mdb_printf("%?lx: ", addr); 1179 else 1180 mdb_printf(", "); 1181 mdb_printf("%s", message); 1182 *error = 1; 1183 } 1184 1185 int 1186 mblk_verify(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1187 { 1188 mblk_t mb; 1189 dblk_t db; 1190 int error = 0; 1191 1192 if (!(flags & DCMD_ADDRSPEC)) { 1193 if (mdb_walk_dcmd("streams_mblk", "mblk_verify", argc, argv) == 1194 -1) { 1195 mdb_warn("can't walk mblk cache"); 1196 return (DCMD_ERR); 1197 } 1198 return (DCMD_OK); 1199 } 1200 1201 if (mdb_vread(&mb, sizeof (mblk_t), addr) == -1) { 1202 mdb_warn("can't read mblk_t at 0x%lx", addr); 1203 return (DCMD_ERR); 1204 } 1205 1206 if (mdb_vread(&db, sizeof (dblk_t), (uintptr_t)mb.b_datap) == -1) { 1207 mdb_warn("%?lx: invalid b_datap pointer\n", addr); 1208 return (DCMD_ERR); 1209 } 1210 1211 if (mb.b_rptr < db.db_base || mb.b_rptr > db.db_lim) 1212 mblk_error(&error, addr, "b_rptr out of range"); 1213 1214 if (mb.b_wptr < db.db_base || mb.b_wptr > db.db_lim) 1215 mblk_error(&error, addr, "b_wptr out of range"); 1216 1217 if (error) 1218 mdb_printf("\n"); 1219 1220 return (error ? DCMD_ERR : DCMD_OK); 1221 } 1222 1223 int 1224 mblk_prt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1225 { 1226 const int MBLK_FLGDELT = (int)(sizeof (uintptr_t) * 2 + 15); 1227 mblk_t mblk; 1228 dblk_t dblk; 1229 int b_flag; 1230 int db_type; 1231 int mblklen; 1232 uint64_t len = ~0UL; 1233 uint64_t glen = ~0UL; 1234 uint64_t llen = ~0UL; 1235 uint64_t blen = ~0UL; 1236 const char *dbtype; 1237 const char *flag = NULL, *not_flag = NULL; 1238 const char *typ = NULL, *not_typ = NULL; 1239 uintptr_t dbaddr = 0; 1240 uint32_t tmask = 0, not_tmask = 0; 1241 uint32_t mask = 0, not_mask = 0; 1242 uint_t quiet = FALSE; 1243 uint_t verbose = FALSE; 1244 1245 if (!(flags & DCMD_ADDRSPEC)) { 1246 if (mdb_walk_dcmd("genunix`streams_mblk", "genunix`mblk", 1247 argc, argv) == -1) { 1248 mdb_warn("failed to walk mblk cache"); 1249 return (DCMD_ERR); 1250 } 1251 return (DCMD_OK); 1252 } 1253 1254 if (flags & DCMD_PIPE_OUT) 1255 quiet = TRUE; 1256 1257 if (mdb_getopts(argc, argv, 1258 'v', MDB_OPT_SETBITS, TRUE, &verbose, 1259 'q', MDB_OPT_SETBITS, TRUE, &quiet, 1260 'f', MDB_OPT_STR, &flag, 1261 'F', MDB_OPT_STR, ¬_flag, 1262 't', MDB_OPT_STR, &typ, 1263 'T', MDB_OPT_STR, ¬_typ, 1264 'l', MDB_OPT_UINT64, &len, 1265 'L', MDB_OPT_UINT64, &llen, 1266 'G', MDB_OPT_UINT64, &glen, 1267 'b', MDB_OPT_UINT64, &blen, 1268 'd', MDB_OPT_UINTPTR, &dbaddr, 1269 NULL) != argc) 1270 return (DCMD_USAGE); 1271 1272 /* 1273 * If any of the filtering flags is specified, don't print anything 1274 * except the matching pointer. 1275 */ 1276 if ((flag != NULL) || (not_flag != NULL) || (typ != NULL) || 1277 (not_typ != NULL) || (len != ~0UL) || (glen != ~0UL) || 1278 (llen != ~0UL) || (blen != ~0UL) || (dbaddr != 0)) 1279 quiet = TRUE; 1280 1281 if (flag != NULL && streams_parse_flag(mbf, flag, &mask) == -1) { 1282 mdb_warn("unrecognized mblk flag '%s'\n", flag); 1283 streams_flag_usage(mbf); 1284 return (DCMD_USAGE); 1285 } 1286 1287 if (not_flag != NULL && 1288 streams_parse_flag(mbf, not_flag, ¬_mask) == -1) { 1289 mdb_warn("unrecognized mblk flag '%s'\n", flag); 1290 streams_flag_usage(mbf); 1291 return (DCMD_USAGE); 1292 } 1293 1294 if (typ != NULL && streams_parse_type(mbt, typ, &tmask) == -1) { 1295 mdb_warn("unrecognized dblk type '%s'\n", typ); 1296 streams_type_usage(mbt); 1297 return (DCMD_USAGE); 1298 } 1299 1300 if (not_typ != NULL && streams_parse_type(mbt, not_typ, ¬_tmask) 1301 == -1) { 1302 mdb_warn("unrecognized dblk type '%s'\n", not_typ); 1303 streams_type_usage(mbt); 1304 return (DCMD_USAGE); 1305 } 1306 1307 if (DCMD_HDRSPEC(flags) && !quiet) { 1308 mdb_printf("%?s %2s %-7s %-5s %-5s %?s %?s\n", 1309 "ADDR", "FL", "TYPE", "LEN", "BLEN", "RPTR", "DBLK"); 1310 } 1311 1312 if (mdb_vread(&mblk, sizeof (mblk), addr) == -1) { 1313 mdb_warn("couldn't read mblk at %p", addr); 1314 return (DCMD_ERR); 1315 } 1316 b_flag = mblk.b_flag; 1317 1318 if (mask != 0 && !(b_flag & mask)) 1319 return (DCMD_OK); 1320 1321 if (not_mask != 0 && (b_flag & not_mask)) 1322 return (DCMD_OK); 1323 1324 if (mdb_vread(&dblk, sizeof (dblk), (uintptr_t)(mblk.b_datap)) == -1) { 1325 mdb_warn("couldn't read dblk at %p/%p", addr, mblk.b_datap); 1326 return (DCMD_ERR); 1327 } 1328 db_type = dblk.db_type; 1329 1330 /* M_DATA is 0, so tmask has special value 0xff for it */ 1331 if ((tmask != 0) && 1332 (((tmask == M_DATA_T) && (db_type != M_DATA)) || 1333 ((tmask != M_DATA_T) && (db_type != tmask)))) 1334 return (DCMD_OK); 1335 1336 1337 if ((not_tmask != 0) && 1338 (((not_tmask == M_DATA_T) && (db_type == M_DATA)) || 1339 (db_type == not_tmask))) 1340 return (DCMD_OK); 1341 1342 if (dbaddr != 0 && (uintptr_t)mblk.b_datap != dbaddr) 1343 return (DCMD_OK); 1344 1345 mblklen = MBLKL(&mblk); 1346 1347 if ((len != ~0UL) && (len != mblklen)) 1348 return (DCMD_OK); 1349 1350 if ((llen != ~0Ul) && (mblklen > (int)llen)) 1351 return (DCMD_OK); 1352 1353 if ((glen != ~0Ul) && (mblklen < (int)glen)) 1354 return (DCMD_OK); 1355 1356 if ((blen != ~0UL) && (blen != (dblk.db_lim - dblk.db_base))) 1357 return (DCMD_OK); 1358 1359 /* 1360 * Options are specified for filtering, so If any option is specified on 1361 * the command line, just print address and exit. 1362 */ 1363 if (quiet) { 1364 mdb_printf("%0?p\n", addr); 1365 return (DCMD_OK); 1366 } 1367 1368 /* Figure out symbolic DB_TYPE */ 1369 if (db_type < A_SIZE(db_control_types)) { 1370 dbtype = db_control_types[db_type]; 1371 } else { 1372 /* 1373 * Must be a high-priority message -- adjust so that 1374 * "QPCTL + 1" corresponds to db_control_hipri_types[0] 1375 */ 1376 db_type -= (QPCTL + 1); 1377 if (db_type >= 0 && db_type < A_SIZE(db_control_hipri_types)) 1378 dbtype = db_control_hipri_types[db_type]; 1379 else 1380 dbtype = "UNKNOWN"; 1381 } 1382 1383 mdb_printf("%0?p %-2x %-7s %-5d %-5d %0?p %0?p\n", 1384 addr, b_flag, dbtype, mblklen, dblk.db_lim - dblk.db_base, 1385 mblk.b_rptr, mblk.b_datap); 1386 1387 if (verbose) { 1388 int i, arm = 0; 1389 1390 for (i = 0; mbf[i].strf_name != NULL; i++) { 1391 if (!(b_flag & (1 << i))) 1392 continue; 1393 if (!arm) { 1394 mdb_printf("%*s|\n%*s+--> ", 1395 MBLK_FLGDELT, "", MBLK_FLGDELT, ""); 1396 arm = 1; 1397 } else 1398 mdb_printf("%*s ", MBLK_FLGDELT, ""); 1399 1400 mdb_printf("%-12s %s\n", 1401 mbf[i].strf_name, mbf[i].strf_descr); 1402 } 1403 } 1404 return (DCMD_OK); 1405 } 1406 1407 /* 1408 * Streams flow trace walkers. 1409 */ 1410 1411 int 1412 strftblk_walk_init(mdb_walk_state_t *wsp) 1413 { 1414 ftblkdata_t *ftd; 1415 dblk_t db; 1416 1417 /* Get the dblock from the address */ 1418 if (mdb_vread(&db, sizeof (dblk_t), wsp->walk_addr) == -1) { 1419 mdb_warn("failed to read dblk at %p", wsp->walk_addr); 1420 return (WALK_ERR); 1421 } 1422 1423 /* Is there any flow trace data? */ 1424 if (db.db_fthdr == NULL) { 1425 return (WALK_DONE); 1426 } 1427 1428 wsp->walk_addr = (uintptr_t)((char *)db.db_fthdr + 1429 offsetof(fthdr_t, first)); 1430 1431 ftd = mdb_alloc(sizeof (ftblkdata_t), UM_SLEEP); 1432 ftd->ft_ix = 0; 1433 ftd->ft_in_evlist = B_FALSE; 1434 wsp->walk_data = ftd; 1435 1436 return (WALK_NEXT); 1437 } 1438 1439 int 1440 strftblk_step(mdb_walk_state_t *wsp) 1441 { 1442 ftblkdata_t *ftd; 1443 ftblk_t *ftbp; 1444 int status = WALK_NEXT; 1445 1446 if (wsp->walk_addr == NULL) 1447 return (WALK_DONE); 1448 1449 ftd = (ftblkdata_t *)wsp->walk_data; 1450 ftbp = &(ftd->ft_data); 1451 1452 if (! ftd->ft_in_evlist) { 1453 /* Read a new ft block */ 1454 if (mdb_vread(ftbp, sizeof (ftblk_t), 1455 wsp->walk_addr) == -1) { 1456 mdb_warn("failed to read ftblk at %p", wsp->walk_addr); 1457 return (WALK_ERR); 1458 } 1459 /* 1460 * Check correctness of the index field. 1461 */ 1462 if (ftbp->ix < 0 || ftbp->ix > FTBLK_EVNTS) { 1463 mdb_warn("ftblk: incorrect index value %i\n", ftbp->ix); 1464 return (WALK_ERR); 1465 } 1466 ftd->ft_ix = 1; 1467 ftd->ft_in_evlist = B_TRUE; 1468 } 1469 1470 if (ftd->ft_ix > ftbp->ix) { 1471 ftd->ft_in_evlist = B_FALSE; 1472 /* End of event list reached - move to the next event block */ 1473 wsp->walk_addr = (uintptr_t)ftbp->nxt; 1474 } else { 1475 /* Print event address */ 1476 status = wsp->walk_callback((uintptr_t)((char *)wsp->walk_addr + 1477 offsetof(ftblk_t, ev) + 1478 (ftd->ft_ix - 1) * sizeof (struct ftevnt)), 1479 wsp->walk_data, wsp->walk_cbdata); 1480 ftd->ft_ix++; 1481 } 1482 1483 return (status); 1484 } 1485 1486 1487 void 1488 strftblk_walk_fini(mdb_walk_state_t *wsp) 1489 { 1490 mdb_free(wsp->walk_data, sizeof (ftblkdata_t)); 1491 } 1492 1493 /*ARGSUSED*/ 1494 int 1495 strftevent(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1496 { 1497 struct ftevnt ev; 1498 char modname[MODMAXNAMELEN]; 1499 1500 if (!(flags & DCMD_ADDRSPEC)) 1501 return (DCMD_USAGE); 1502 1503 if (DCMD_HDRSPEC(flags)) { 1504 mdb_printf("%?s %?s %s %s %-24s %s\n", 1505 "ADDR", "MID", "EVNT", "DATA", "NAME", "EVENT"); 1506 } 1507 1508 if (mdb_vread(&ev, sizeof (ev), addr) == -1) { 1509 mdb_warn("couldn't read ft event at %p", addr); 1510 return (DCMD_ERR); 1511 } 1512 1513 mdb_printf("%0?p %0?p %4x %4x", 1514 addr, ev.mid, ev.evnt, ev.data); 1515 1516 if (ev.evnt & FTEV_QMASK) { 1517 if (mdb_readstr(modname, sizeof (modname), 1518 (uintptr_t)ev.mid) == -1) 1519 mdb_warn("couldn't read module name at %p", ev.mid); 1520 mdb_printf(" %-24s", modname); 1521 } else 1522 mdb_printf(" %-24a", ev.mid); 1523 1524 ft_printevent(ev.evnt); 1525 1526 mdb_printf("\n"); 1527 1528 return (DCMD_OK); 1529 } 1530 1531 static void 1532 ft_printevent(ushort_t ev) 1533 { 1534 ushort_t proc_ev = (ev & (FTEV_PROC_START | 0xFF)) - FTEV_PROC_START; 1535 ushort_t alloc_ev = ev & FTEV_CALLER; 1536 1537 /* Get event class first */ 1538 if (ev & FTEV_PROC_START) { 1539 if (proc_ev >= A_SIZE(ftev_proc)) 1540 mdb_printf(" undefined"); 1541 else 1542 mdb_printf(" %s", ftev_proc[proc_ev]); 1543 } else if (alloc_ev >= A_SIZE(ftev_alloc)) 1544 mdb_printf(" undefined"); 1545 else 1546 mdb_printf(" %s", ftev_alloc[alloc_ev]); 1547 1548 /* Print event modifiers, if any */ 1549 1550 if (ev & FTEV_PS) 1551 mdb_printf(" | PS"); 1552 if (ev & FTEV_CS) 1553 mdb_printf(" | CS"); 1554 if (ev & FTEV_ISWR) 1555 mdb_printf(" | ISWR"); 1556 } 1557 1558 /* 1559 * Help functions for STREAMS debugging facilities. 1560 */ 1561 void 1562 queue_help(void) 1563 { 1564 mdb_printf("Print queue information for a given queue pointer.\n" 1565 "\nWithout the address of a \"queue_t\" structure given, print " 1566 "information about all\n" 1567 "queues in the \"queue_cache\".\n\n" 1568 "Options:\n" 1569 " -v:\t\tbe verbose - print symbolic flags falues\n" 1570 " -q:\t\tbe quiet - print queue pointer only\n" 1571 " -f flag:\tprint only queues with flag set\n" 1572 " -F flag:\tprint only queues with flag NOT set\n" 1573 " -m modname:\tprint only queues with specified module name\n" 1574 " -s syncq_addr:\tprint only queues which use specified syncq\n\n" 1575 "Available conversions:\n" 1576 " q2rdq: given a queue addr print read queue pointer\n" 1577 " q2wrq: given a queue addr print write queue pointer\n" 1578 " q2otherq: given a queue addr print other queue pointer\n" 1579 " q2syncq: given a queue addr print syncq pointer" 1580 " (::help syncq)\n" 1581 " q2stream: given a queue addr print its stream pointer\n" 1582 "\t\t(see ::help stream and ::help stdata)\n\n" 1583 "To walk q_next pointer of the queue use\n" 1584 " queue_addr::walk qnext\n"); 1585 } 1586 1587 void 1588 syncq_help(void) 1589 { 1590 mdb_printf("Print syncq information for a given syncq pointer.\n" 1591 "\nWithout the address of a \"syncq_t\" structure given, print " 1592 "information about all\n" 1593 "syncqs in the \"syncq_cache\".\n\n" 1594 "Options:\n" 1595 " -v:\t\tbe verbose - print symbolic flags falues\n" 1596 " -q:\t\tbe quiet - print syncq pointer only\n" 1597 " -f flag:\tprint only syncqs with flag set\n" 1598 " -F flag:\tprint only syncqs with flag NOT set\n" 1599 " -t type:\tprint only syncqs with specified type\n" 1600 " -T type:\tprint only syncqs with do NOT have specified type\n\n" 1601 "Available conversions:\n" 1602 " syncq2q:\tgiven a syncq addr print queue address of the\n" 1603 "\t\t\tenclosing queue, if it is part of a queue\n\n" 1604 "See also: \"::help queue\" and \"::help stdata\"\n"); 1605 } 1606 1607 void 1608 stdata_help(void) 1609 { 1610 mdb_printf("Print stdata information for a given stdata pointer.\n" 1611 "\nWithout the address of a \"stdata_t\" structure given, print " 1612 "information about all\n" 1613 "stream head pointers from the \"stream_head_cache\".\n\n" 1614 "Fields printed:\n" 1615 " ADDR:\tstream head address\n" 1616 " WRQ:\twrite queue pointer\n" 1617 " FLAGS:\tstream head flags (use -v to show in symbolic form)\n" 1618 " VNODE:\tstream vnode pointer\n" 1619 " N/A:\tpushcount and anchor positions\n" 1620 " REF:\tstream head reference counter\n\n" 1621 "Options:\n" 1622 " -v:\t\tbe verbose - print symbolic flags falues\n" 1623 " -q:\t\tbe quiet - print stdata pointer only\n" 1624 " -f flag:\tprint only stdatas with flag set\n" 1625 " -F flag:\tprint only stdatas with flag NOT set\n\n" 1626 "Available conversions:\n" 1627 " str2mate:\tgiven a stream head addr print its mate\n" 1628 " str2wrq:\tgiven a stream head addr print its write queue\n\n" 1629 "See also: \"::help queue\" and \"::help syncq\"\n"); 1630 } 1631 1632 void 1633 mblk_help(void) 1634 { 1635 mdb_printf("Print mblock information for a given mblk pointer.\n" 1636 "Without the address, print information about all mblocks.\n\n" 1637 "Fields printed:\n" 1638 " ADDR:\tmblk address\n" 1639 " FL:\tFlags\n" 1640 " TYPE:\tType of corresponding dblock\n" 1641 " LEN:\tData length as b_wptr - b_rptr\n" 1642 " BLEN:\tDblock space as db_lim - db_base\n" 1643 " RPTR:\tRead pointer\n" 1644 " DBLK:\tDblock pointer\n\n" 1645 "Options:\n" 1646 " -v:\t\tbe verbose - print symbolic flags falues\n" 1647 " -q:\t\tbe quiet - print mblk pointer only\n" 1648 " -d dbaddr:\t\tprint mblks with specified dblk address\n" 1649 " -f flag:\tprint only mblks with flag set\n" 1650 " -F flag:\tprint only mblks with flag NOT set\n" 1651 " -t type:\tprint only mblks of specified db_type\n" 1652 " -T type:\tprint only mblks other then the specified db_type\n" 1653 " -l len:\t\ttprint only mblks with MBLKL == len\n" 1654 " -L len:\t\tprint only mblks with MBLKL <= len \n" 1655 " -G len:\t\tprint only mblks with MBLKL >= len \n" 1656 " -b len:\t\tprint only mblks with db_lim - db_base == len\n" 1657 "\n"); 1658 } 1659