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