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