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
streams_parse_flag(const strflags_t ftable[],const char * arg,uint32_t * flag)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
streams_flag_usage(const strflags_t ftable[])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
streams_parse_type(const strtypes_t ftable[],const char * arg,uint32_t * flag)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
streams_type_usage(const strtypes_t ftable[])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
queue(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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 != NULL)
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 != NULL; 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
syncq(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
stdata(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
qprint_syncq(queue_t * addr,queue_t * q)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
qprint_stream(queue_t * addr,queue_t * q)736 qprint_stream(queue_t *addr, queue_t *q)
737 {
738 mdb_printf("%p\n", q->q_stream);
739 }
740
741 static void
qprint_wrq(queue_t * addr,queue_t * q)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
qprint_rdq(queue_t * addr,queue_t * q)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
qprint_otherq(queue_t * addr,queue_t * q)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
q2x(uintptr_t addr,int argc,qprint_func prfunc)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
q2syncq(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
q2stream(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
q2rdq(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
q2wrq(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
q2otherq(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
sd2x(uintptr_t addr,int argc,sdprint_func prfunc)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
sdprint_wrq(stdata_t * addr,stdata_t * sd)832 sdprint_wrq(stdata_t *addr, stdata_t *sd)
833 {
834 mdb_printf("%p\n", sd->sd_wrq);
835 }
836
837 static void
sdprint_mate(stdata_t * addr,stdata_t * sd)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
str2mate(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
str2wrq(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
syncq2q(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
queue_walk_init(mdb_walk_state_t * wsp)890 queue_walk_init(mdb_walk_state_t *wsp)
891 {
892 if (wsp->walk_addr == NULL &&
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
queue_link_step(mdb_walk_state_t * wsp)903 queue_link_step(mdb_walk_state_t *wsp)
904 {
905 int status;
906
907 if (wsp->walk_addr == NULL)
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
queue_next_step(mdb_walk_state_t * wsp)923 queue_next_step(mdb_walk_state_t *wsp)
924 {
925 int status;
926
927 if (wsp->walk_addr == NULL)
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
queue_walk_fini(mdb_walk_state_t * wsp)943 queue_walk_fini(mdb_walk_state_t *wsp)
944 {
945 mdb_free(wsp->walk_data, sizeof (queue_t));
946 }
947
948 int
str_walk_init(mdb_walk_state_t * wsp)949 str_walk_init(mdb_walk_state_t *wsp)
950 {
951 stdata_t s;
952
953 if (wsp->walk_addr == NULL) {
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
strr_walk_step(mdb_walk_state_t * wsp)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 == NULL)
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
strw_walk_step(mdb_walk_state_t * wsp)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 == NULL)
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
str_walk_fini(mdb_walk_state_t * wsp)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
print_qpair(uintptr_t addr,const queue_t * q,uint_t * depth)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
stream(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
mblk_walk_init(mdb_walk_state_t * wsp)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
b_cont_step(mdb_walk_state_t * wsp)1105 b_cont_step(mdb_walk_state_t *wsp)
1106 {
1107 int status;
1108
1109 if (wsp->walk_addr == NULL)
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
b_next_step(mdb_walk_state_t * wsp)1125 b_next_step(mdb_walk_state_t *wsp)
1126 {
1127 int status;
1128
1129 if (wsp->walk_addr == NULL)
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
mblk_walk_fini(mdb_walk_state_t * wsp)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
mblk2dblk(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
mblk_error(int * error,uintptr_t addr,char * message)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
mblk_verify(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
mblk_prt(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
strftblk_walk_init(mdb_walk_state_t * wsp)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
strftblk_step(mdb_walk_state_t * wsp)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 == NULL)
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
strftblk_walk_fini(mdb_walk_state_t * wsp)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 *
getqname(const void * nameptr,char * buf,uint_t bufsize)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
strftevent(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
ft_printevent(ushort_t ev)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
queue_help(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
syncq_help(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
stdata_help(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
mblk_help(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