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