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