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