streams.c revision 595aa6e48d8a5812a3a42afa5f63ee6f772c7f4e
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <mdb/mdb_modapi.h>
#include <mdb/mdb_ks.h>
#include <sys/types.h>
#include <sys/strsubr.h>
#include <sys/stream.h>
#include <sys/modctl.h>
#include <sys/strft.h>
#include <sys/strsun.h>
#include <sys/sysmacros.h>
#include "streams.h"
typedef struct str_flags {
uint_t strf_flag;
const char *strf_name;
const char *strf_descr;
} strflags_t;
typedef struct str_types {
const char *strt_name;
int strt_value;
const char *strt_descr;
} strtypes_t;
typedef struct ftblk_data {
ftblk_t ft_data; /* Copy of ftblk */
int ft_ix; /* Index in event list */
boolean_t ft_in_evlist; /* Iterating through evlist */
} ftblkdata_t;
typedef void qprint_func(queue_t *, queue_t *);
typedef void sdprint_func(stdata_t *, stdata_t *);
#define SF(flag) flag, #flag
/*
* Queue flags
*/
static const strflags_t qf[] = {
{ SF(QENAB), "Queue is already enabled to run" },
{ SF(QWANTR), "Someone wants to read Q" },
{ SF(QWANTW), "Someone wants to write Q" },
{ SF(QFULL), "Q is considered full" },
{ SF(QREADR), "This is the reader (first) Q" },
{ SF(QUSE), "This queue in use (allocation)" },
{ SF(QNOENB), "Don't enable Q via putq" },
{ SF(QWANTRMQSYNC), "Want to remove sync stream Q" },
{ SF(QBACK), "queue has been back-enabled" },
{ SF(0x00000200), "unused (was QHLIST)" },
{ SF(0x00000400), "unused (was QUNSAFE)" },
{ SF(QPAIR), "per queue-pair syncq" },
{ SF(QPERQ), "per queue-instance syncq" },
{ SF(QPERMOD), "per module syncq" },
{ SF(QMTSAFE), "stream module is MT-safe" },
{ SF(QMTOUTPERIM), "Has outer perimeter" },
{ SF(QINSERVICE), "service routine executing" },
{ SF(QWCLOSE), "will not be enabled" },
{ SF(QEND), "last queue in stream" },
{ SF(QWANTWSYNC), "Streamhead wants to write Q" },
{ SF(QSYNCSTR), "Q supports Synchronous STREAMS" },
{ SF(QISDRV), "the Queue is attached to a driver" },
{ SF(0x00400000), "unused (was QHOT)" },
{ SF(0x00800000), "unused (was QNEXTHOT)" },
{ SF(0x01000000), "unused (was _QNEXTLESS)" },
{ SF(0x02000000), "unused" },
{ SF(_QINSERTING), "module is inserted with _I_INSERT" },
{ SF(_QREMOVING) "module is removed with _I_REMOVE" },
{ SF(_QASSOCIATED), "queue is associated with a device" },
{ 0, NULL, NULL }
};
/*
* Syncq flags
*/
static const struct str_flags sqf[] = {
{ SF(SQ_EXCL), "Exclusive access to inner perimeter" },
{ SF(SQ_BLOCKED), "qprocsoff in progress" },
{ SF(SQ_FROZEN), "freezestr in progress" },
{ SF(SQ_WRITER), "qwriter(OUTER) pending or running" },
{ SF(SQ_MESSAGES), "There are messages on syncq" },
{ SF(SQ_WANTWAKEUP) "Thread waiting on sq_wait" },
{ SF(SQ_WANTEXWAKEUP), "Thread waiting on sq_exwait" },
{ SF(SQ_EVENTS), "There are events on syncq" },
{ 0, NULL, NULL }
};
/*
* Syncq types
*/
static const struct str_flags sqt[] = {
{ SF(SQ_CIPUT), "Concurrent inner put procedure" },
{ SF(SQ_CISVC), "Concurrent inner svc procedure" },
{ SF(SQ_CIOC), "Concurrent inner open/close" },
{ SF(SQ_CICB), "Concurrent inner callback" },
{ SF(SQ_COPUT), "Concurrent outer put procedure" },
{ SF(SQ_COSVC), "Concurrent outer svc procedure" },
{ SF(SQ_COOC), "Concurrent outer open/close" },
{ SF(SQ_COCB), "Concurrent outer callback" },
{ 0, NULL, NULL }
};
/*
* Stdata flags
*/
static const struct str_flags stdf[] = {
{ SF(IOCWAIT), "someone is doing an ioctl" },
{ SF(RSLEEP), "someone wants to read/recv msg" },
{ SF(WSLEEP), "someone wants to write" },
{ SF(STRPRI), "an M_PCPROTO is at stream head" },
{ SF(STRHUP), "device has vanished" },
{ SF(STWOPEN), "waiting for 1st open" },
{ SF(STPLEX), "stream is being multiplexed" },
{ SF(STRISTTY), "stream is a terminal" },
{ SF(STRGETINPROG), "(k)strgetmsg is running" },
{ SF(IOCWAITNE), "STR_NOERROR ioctl running" },
{ SF(STRDERR), "fatal read error from M_ERROR" },
{ SF(STWRERR), "fatal write error from M_ERROR" },
{ SF(STRDERRNONPERSIST), "nonpersistent read errors" },
{ SF(STWRERRNONPERSIST), "nonpersistent write errors" },
{ SF(STRCLOSE), "wait for a close to complete" },
{ SF(SNDMREAD), "used for read notification" },
{ SF(OLDNDELAY), "use old NDELAY TTY semantics" },
{ SF(0x00020000), "unused" },
{ SF(0x00040000), "unused" },
{ SF(STRTOSTOP), "block background writes" },
{ SF(0x00100000), "unused" },
{ SF(0x00200000), "unused" },
{ SF(STRMOUNT), "stream is mounted" },
{ SF(STRNOTATMARK), "Not at mark (when empty read q)" },
{ SF(STRDELIM), "generate delimited messages" },
{ SF(STRATMARK), "at mark (due to MSGMARKNEXT)" },
{ SF(STZCNOTIFY), "wait for zerocopy mblk to be acked" },
{ SF(STRPLUMB), "stream plumbing changes in progress" },
{ SF(STREOF), "End-of-file indication" },
{ SF(STREOPENFAIL), "re-open has failed" },
{ SF(STRMATE), "this stream is a mate" },
{ SF(STRHASLINKS), "there are I_LINKs under this stream" },
{ 0, NULL, NULL }
};
static const struct str_flags mbf[] = {
{ SF(MSGMARK), "last byte of message is marked" },
{ SF(MSGNOLOOP), "don't loop message to write side" },
{ SF(MSGDELIM), "message is delimited" },
{ SF(0x08), "unused" },
{ SF(MSGMARKNEXT), "Private: b_next's first byte marked" },
{ SF(MSGNOTMARKNEXT), "Private: ... not marked" },
{ SF(MSGHASREF), "Private: msg has reference to owner" },
{ 0, NULL, NULL }
};
#define M_DATA_T 0xff
static const strtypes_t mbt[] = {
{ "M_DATA", M_DATA_T, "regular data" },
{ "M_PROTO", M_PROTO, "protocol control" },
{ "M_MULTIDATA", M_MULTIDATA, "multidata" },
{ "M_BREAK", M_BREAK, "line break" },
{ "M_PASSFP", M_PASSFP, "pass file pointer" },
{ "M_EVENT", M_EVENT, "Obsoleted: do not use" },
{ "M_SIG", M_SIG, "generate process signal" },
{ "M_DELAY", M_DELAY, "real-time xmit delay" },
{ "M_CTL", M_CTL, "device-specific control message" },
{ "M_IOCTL", M_IOCTL, "ioctl; set/get params" },
{ "M_SETOPTS", M_SETOPTS, "set stream head options" },
{ "M_RSE", M_RSE, "reserved for RSE use only" },
{ "M_IOCACK", M_IOCACK, "acknowledge ioctl" },
{ "M_IOCNAK", M_IOCNAK, "negative ioctl acknowledge" },
{ "M_PCPROTO", M_PCPROTO, "priority proto message" },
{ "M_PCSIG", M_PCSIG, "generate process signal" },
{ "M_READ", M_READ, "generate read notification" },
{ "M_FLUSH", M_FLUSH, "flush your queues" },
{ "M_STOP", M_STOP, "stop transmission immediately" },
{ "M_START", M_START, "restart transmission after stop" },
{ "M_HANGUP", M_HANGUP, "line disconnect" },
{ "M_ERROR", M_ERROR, "send error to stream head" },
{ "M_COPYIN", M_COPYIN, "request to copyin data" },
{ "M_COPYOUT", M_COPYOUT, "request to copyout data" },
{ "M_IOCDATA", M_IOCDATA, "response to M_COPYIN and M_COPYOUT" },
{ "M_PCRSE", M_PCRSE, "reserved for RSE use only" },
{ "M_STOPI", M_STOPI, "stop reception immediately" },
{ "M_STARTI", M_STARTI, "restart reception after stop" },
{ "M_PCEVENT", M_PCEVENT, "Obsoleted: do not use" },
{ "M_UNHANGUP", M_UNHANGUP, "line reconnect" },
{ NULL, 0, NULL }
};
/* Allocation flow trace events, starting from 0 */
static const char *ftev_alloc[] = {
/* 0 */ ":allocb",
/* 1 */ ":esballoc",
/* 2 */ ":desballoc",
/* 3 */ ":esballoca",
/* 4 */ ":desballoca",
/* 5 */ ":allocbig",
/* 6 */ ":allocbw",
/* 7 */ ":bcallocb",
/* 8 */ ":freeb",
/* 9 */ ":dupb",
/* A */ ":copyb",
};
#define FTEV_PROC_START FTEV_PUT
/* Procedures recorded by flow tracing, starting from 0x100 */
static const char *ftev_proc[] = {
/* 100 */ ":put",
/* 101 */ ":undefined (0x101)",
/* 102 */ ":undefined (0x102)",
/* 103 */ ":undefined (0x103)",
/* 104 */ ":undefined (0x104)",
/* 105 */ ":putq",
/* 106 */ ":getq",
/* 107 */ ":rmvq",
/* 108 */ ":insq",
/* 109 */ ":putbq",
/* 10A */ ":flushq",
/* 10B */ ":undefined (0x10b)",
/* 10C */ ":undefined (0x10c)",
/* 10D */ ":putnext",
/* 10E */ ":rwnext",
};
static const char *db_control_types[] = {
/* 00 */ "data",
/* 01 */ "proto",
/* 02 */ "multidata",
/* 03 */ "unused (0x03)",
/* 04 */ "unused (0x04)",
/* 05 */ "unused (0x05)",
/* 06 */ "unused (0x06)",
/* 07 */ "unused (0x07)",
/* 08 */ "break",
/* 09 */ "passfp",
/* 0a */ "event",
/* 0b */ "sig",
/* 0c */ "delay",
/* 0d */ "ctl",
/* 0e */ "ioctl",
/* 0f */ "unused",
/* 10 */ "setopts",
/* 11 */ "rse",
};
static const char *db_control_hipri_types[] = {
/* 81 */ "iocack",
/* 82 */ "iocnak",
/* 83 */ "pcproto",
/* 84 */ "pcsig",
/* 85 */ "read",
/* 86 */ "flush",
/* 87 */ "stop",
/* 88 */ "start",
/* 89 */ "hangup",
/* 8a */ "error",
/* 8b */ "copyin",
/* 8c */ "copyout",
/* 8d */ "iocdata",
/* 8e */ "pcrse",
/* 8f */ "stopi",
/* 90 */ "starti",
/* 91 */ "pcevent",
/* 92 */ "unhangup",
};
#define A_SIZE(a) (sizeof (a) / sizeof (a[0]))
static void ft_printevent(ushort_t);
static int
streams_parse_flag(const strflags_t ftable[], const char *arg, uint32_t *flag)
{
int i;
for (i = 0; ftable[i].strf_name != NULL; i++) {
if (strcasecmp(arg, ftable[i].strf_name) == 0) {
*flag |= (1 << i);
return (0);
}
}
return (-1);
}
static void
streams_flag_usage(const strflags_t ftable[])
{
int i;
for (i = 0; ftable[i].strf_name != NULL; i++)
mdb_printf("%-14s %s\n",
ftable[i].strf_name, ftable[i].strf_descr);
}
static int
streams_parse_type(const strtypes_t ftable[], const char *arg, uint32_t *flag)
{
int i;
for (i = 0; ftable[i].strt_name != NULL; i++) {
if (strcasecmp(arg, ftable[i].strt_name) == 0) {
*flag = ftable[i].strt_value;
return (0);
}
}
return (-1);
}
static void
streams_type_usage(const strtypes_t ftable[])
{
int i;
for (i = 0; ftable[i].strt_name != NULL; i++)
mdb_printf("%-12s %s\n",
ftable[i].strt_name, ftable[i].strt_descr);
}
int
queue(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
const int QUEUE_FLGDELT = (int)(sizeof (uintptr_t) * 2 + 15);
char name[MODMAXNAMELEN];
int nblks = 0;
uintptr_t maddr;
mblk_t mblk;
queue_t q;
const char *mod = NULL, *flag = NULL, *not_flag = NULL;
uint_t quiet = FALSE;
uint_t verbose = FALSE;
uint32_t mask = 0, not_mask = 0;
uintptr_t syncq = 0;
if (!(flags & DCMD_ADDRSPEC)) {
if (mdb_walk_dcmd("genunix`queue_cache", "genunix`queue",
argc, argv) == -1) {
mdb_warn("failed to walk queue cache");
return (DCMD_ERR);
}
return (DCMD_OK);
}
if (flags & DCMD_PIPE_OUT)
quiet = TRUE;
if (mdb_getopts(argc, argv,
'v', MDB_OPT_SETBITS, TRUE, &verbose,
'q', MDB_OPT_SETBITS, TRUE, &quiet,
'm', MDB_OPT_STR, &mod,
'f', MDB_OPT_STR, &flag,
'F', MDB_OPT_STR, &not_flag,
's', MDB_OPT_UINTPTR, &syncq,
NULL) != argc)
return (DCMD_USAGE);
/*
* If any of the filtering flags is specified, don't print anything
* except the matching pointer.
*/
if (flag != NULL || not_flag != NULL || mod != NULL || syncq != NULL)
quiet = TRUE;
if (DCMD_HDRSPEC(flags) && !quiet) {
mdb_printf("%?s %-13s %6s %4s\n",
"ADDR", "MODULE", "FLAGS", "NBLK");
}
if (flag != NULL && streams_parse_flag(qf, flag, &mask) == -1) {
mdb_warn("unrecognized queue flag '%s'\n", flag);
streams_flag_usage(qf);
return (DCMD_USAGE);
}
if (not_flag != NULL &&
streams_parse_flag(qf, not_flag, &not_mask) == -1) {
mdb_warn("unrecognized queue flag '%s'\n", flag);
streams_flag_usage(qf);
return (DCMD_USAGE);
}
if (mdb_vread(&q, sizeof (q), addr) == -1) {
mdb_warn("couldn't read queue at %p", addr);
return (DCMD_ERR);
}
for (maddr = (uintptr_t)q.q_first; maddr != NULL; nblks++) {
if (mdb_vread(&mblk, sizeof (mblk), maddr) == -1) {
mdb_warn("couldn't read mblk %p for queue %p",
maddr, addr);
break;
}
maddr = (uintptr_t)mblk.b_next;
}
(void) mdb_qname(&q, name, sizeof (name));
/*
* If queue doesn't pass filtering criteria, don't print anything and
* just return.
*/
if (mod != NULL && strcmp(mod, name) != 0)
return (DCMD_OK);
if (mask != 0 && !(q.q_flag & mask))
return (DCMD_OK);
if (not_mask != 0 && (q.q_flag & not_mask))
return (DCMD_OK);
if (syncq != 0 && q.q_syncq != (syncq_t *)syncq)
return (DCMD_OK);
/*
* Options are specified for filtering, so If any option is specified on
* the command line, just print address and exit.
*/
if (quiet) {
mdb_printf("%0?p\n", addr);
return (DCMD_OK);
}
mdb_printf("%0?p %-13s %06x %4d %0?p\n",
addr, name, q.q_flag, nblks, q.q_first);
if (verbose) {
int i, arm = 0;
for (i = 0; qf[i].strf_name != NULL; i++) {
if (!(q.q_flag & (1 << i)))
continue;
if (!arm) {
mdb_printf("%*s|\n%*s+--> ",
QUEUE_FLGDELT, "", QUEUE_FLGDELT, "");
arm = 1;
} else
mdb_printf("%*s ", QUEUE_FLGDELT, "");
mdb_printf("%-12s %s\n",
qf[i].strf_name, qf[i].strf_descr);
}
}
return (DCMD_OK);
}
int
syncq(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
const int SYNC_FLGDELT = (int)(sizeof (uintptr_t) * 2 + 1);
const int SYNC_TYPDELT = (int)(sizeof (uintptr_t) * 2 + 5);
syncq_t sq;
const char *flag = NULL, *not_flag = NULL;
const char *typ = NULL, *not_typ = NULL;
uint_t verbose = FALSE;
uint_t quiet = FALSE;
uint32_t mask = 0, not_mask = 0;
uint32_t tmask = 0, not_tmask = 0;
uint8_t sqtype = 0;
if (!(flags & DCMD_ADDRSPEC)) {
if (mdb_walk_dcmd("genunix`syncq_cache", "genunix`syncq",
argc, argv) == -1) {
mdb_warn("failed to walk syncq cache");
return (DCMD_ERR);
}
return (DCMD_OK);
}
if (flags & DCMD_PIPE_OUT)
quiet = TRUE;
if (mdb_getopts(argc, argv,
'v', MDB_OPT_SETBITS, TRUE, &verbose,
'q', MDB_OPT_SETBITS, TRUE, &quiet,
'f', MDB_OPT_STR, &flag,
'F', MDB_OPT_STR, &not_flag,
't', MDB_OPT_STR, &typ,
'T', MDB_OPT_STR, &not_typ,
NULL) != argc)
return (DCMD_USAGE);
/*
* If any of the filtering flags is specified, don't print anything
* except the matching pointer.
*/
if (flag != NULL || not_flag != NULL || typ != NULL || not_typ != NULL)
quiet = TRUE;
if (DCMD_HDRSPEC(flags) && !quiet) {
mdb_printf("%?s %s %s %s %s %?s %s %s\n",
"ADDR", "FLG", "TYP", "CNT", "NQS", "OUTER", "SF", "PRI");
}
if (flag != NULL && streams_parse_flag(sqf, flag, &mask) == -1) {
mdb_warn("unrecognized syncq flag '%s'\n", flag);
streams_flag_usage(sqf);
return (DCMD_USAGE);
}
if (typ != NULL && streams_parse_flag(sqt, typ, &tmask) == -1) {
mdb_warn("unrecognized syncq type '%s'\n", typ);
streams_flag_usage(sqt);
return (DCMD_USAGE);
}
if (not_flag != NULL && streams_parse_flag(sqf, not_flag, &not_mask)
== -1) {
mdb_warn("unrecognized syncq flag '%s'\n", not_flag);
streams_flag_usage(sqf);
return (DCMD_USAGE);
}
if (not_typ != NULL && streams_parse_flag(sqt, not_typ, &not_tmask)
== -1) {
mdb_warn("unrecognized syncq type '%s'\n", not_typ);
streams_flag_usage(sqt);
return (DCMD_USAGE);
}
if (mdb_vread(&sq, sizeof (sq), addr) == -1) {
mdb_warn("couldn't read syncq at %p", addr);
return (DCMD_ERR);
}
if (mask != 0 && !(sq.sq_flags & mask))
return (DCMD_OK);
if (not_mask != 0 && (sq.sq_flags & not_mask))
return (DCMD_OK);
sqtype = (sq.sq_type >> 8) & 0xff;
if (tmask != 0 && !(sqtype & tmask))
return (DCMD_OK);
if (not_tmask != 0 && (sqtype & not_tmask))
return (DCMD_OK);
/*
* Options are specified for filtering, so If any option is specified on
* the command line, just print address and exit.
*/
if (quiet) {
mdb_printf("%0?p\n", addr);
return (DCMD_OK);
}
mdb_printf("%0?p %02x %02x %-3u %-3u %0?p %1x %-3d\n",
addr, sq.sq_flags & 0xff, sqtype, sq.sq_count,
sq.sq_nqueues, sq.sq_outer, sq.sq_svcflags, sq.sq_pri);
if (verbose) {
int i, arm = 0;
for (i = 0; sqf[i].strf_name != NULL; i++) {
if (!(sq.sq_flags & (1 << i)))
continue;
if (!arm) {
mdb_printf("%*s|\n%*s+--> ",
SYNC_FLGDELT, "", SYNC_FLGDELT, "");
arm = 1;
} else
mdb_printf("%*s ", SYNC_FLGDELT, "");
mdb_printf("%-12s %s\n",
sqf[i].strf_name, sqf[i].strf_descr);
}
for (i = 0; sqt[i].strf_name != NULL; i++) {
if (!(sqtype & (1 << i)))
continue;
if (!arm) {
mdb_printf("%*s|\n%*s+--> ",
SYNC_TYPDELT, "", SYNC_TYPDELT, "");
arm = 1;
} else
mdb_printf("%*s ", SYNC_TYPDELT, "");
mdb_printf("%-12s %s\n",
sqt[i].strf_name, sqt[i].strf_descr);
}
}
return (DCMD_OK);
}
int
stdata(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
const int STREAM_FLGDELT = (int)(sizeof (uintptr_t) * 2 + 10);
stdata_t sd;
const char *flag = NULL, *not_flag = NULL;
uint_t verbose = FALSE;
uint_t quiet = FALSE;
uint32_t mask = 0, not_mask = 0;
if (!(flags & DCMD_ADDRSPEC)) {
if (mdb_walk_dcmd("genunix`stream_head_cache",
"genunix`stdata", argc, argv) == -1) {
mdb_warn("failed to walk stream head cache");
return (DCMD_ERR);
}
return (DCMD_OK);
}
if (flags & DCMD_PIPE_OUT)
quiet = TRUE;
if (mdb_getopts(argc, argv,
'v', MDB_OPT_SETBITS, TRUE, &verbose,
'q', MDB_OPT_SETBITS, TRUE, &quiet,
'f', MDB_OPT_STR, &flag,
'F', MDB_OPT_STR, &not_flag,
NULL) != argc)
return (DCMD_USAGE);
/*
* If any of the filtering flags is specified, don't print anything
* except the matching pointer.
*/
if (flag != NULL || not_flag != NULL)
quiet = TRUE;
if (DCMD_HDRSPEC(flags) && !quiet) {
mdb_printf("%?s %?s %8s %?s %s %s\n",
"ADDR", "WRQ", "FLAGS", "VNODE", "N/A", "REF");
}
if (flag != NULL && streams_parse_flag(stdf, flag, &mask) == -1) {
mdb_warn("unrecognized stream flag '%s'\n", flag);
streams_flag_usage(stdf);
return (DCMD_USAGE);
}
if (not_flag != NULL &&
streams_parse_flag(stdf, not_flag, &not_mask) == -1) {
mdb_warn("unrecognized stream flag '%s'\n", flag);
streams_flag_usage(stdf);
return (DCMD_USAGE);
}
if (mdb_vread(&sd, sizeof (sd), addr) == -1) {
mdb_warn("couldn't read stdata at %p", addr);
return (DCMD_ERR);
}
/*
* If stream doesn't pass filtering criteria, don't print anything and
* just return.
*/
if (mask != 0 && !(sd.sd_flag & mask))
return (DCMD_OK);
if (not_mask != 0 && (sd.sd_flag & not_mask))
return (DCMD_OK);
/*
* Options are specified for filtering, so If any option is specified on
* the command line, just print address and exit.
*/
if (quiet) {
mdb_printf("%0?p\n", addr);
return (DCMD_OK);
}
mdb_printf("%0?p %0?p %08x %0?p %d/%d %d\n",
addr, sd.sd_wrq, sd.sd_flag, sd.sd_vnode,
sd.sd_pushcnt, sd.sd_anchor, sd.sd_refcnt);
if (verbose) {
int i, arm = 0;
for (i = 0; stdf[i].strf_name != NULL; i++) {
if (!(sd.sd_flag & (1 << i)))
continue;
if (!arm) {
mdb_printf("%*s|\n%*s+--> ",
STREAM_FLGDELT, "", STREAM_FLGDELT, "");
arm = 1;
} else
mdb_printf("%*s ", STREAM_FLGDELT, "");
mdb_printf("%-12s %s\n",
stdf[i].strf_name, stdf[i].strf_descr);
}
}
return (DCMD_OK);
}
/*ARGSUSED*/
static void
qprint_syncq(queue_t *addr, queue_t *q)
{
mdb_printf("%p\n", q->q_syncq);
}
/*ARGSUSED*/
static void
qprint_stream(queue_t *addr, queue_t *q)
{
mdb_printf("%p\n", q->q_stream);
}
static void
qprint_wrq(queue_t *addr, queue_t *q)
{
mdb_printf("%p\n", ((q)->q_flag & QREADR? (addr)+1: (addr)));
}
static void
qprint_rdq(queue_t *addr, queue_t *q)
{
mdb_printf("%p\n", ((q)->q_flag & QREADR? (addr): (addr)-1));
}
static void
qprint_otherq(queue_t *addr, queue_t *q)
{
mdb_printf("%p\n", ((q)->q_flag & QREADR? (addr)+1: (addr)-1));
}
static int
q2x(uintptr_t addr, int argc, qprint_func prfunc)
{
queue_t q;
if (argc != 0)
return (DCMD_USAGE);
if (mdb_vread(&q, sizeof (q), addr) == -1) {
mdb_warn("couldn't read queue at %p", addr);
return (DCMD_ERR);
}
prfunc((queue_t *)addr, &q);
return (DCMD_OK);
}
/*ARGSUSED*/
int
q2syncq(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
return (q2x(addr, argc, qprint_syncq));
}
/*ARGSUSED*/
int
q2stream(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
return (q2x(addr, argc, qprint_stream));
}
/*ARGSUSED*/
int
q2rdq(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
return (q2x(addr, argc, qprint_rdq));
}
/*ARGSUSED*/
int
q2wrq(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
return (q2x(addr, argc, qprint_wrq));
}
/*ARGSUSED*/
int
q2otherq(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
return (q2x(addr, argc, qprint_otherq));
}
static int
sd2x(uintptr_t addr, int argc, sdprint_func prfunc)
{
stdata_t sd;
if (argc != 0)
return (DCMD_USAGE);
if (mdb_vread(&sd, sizeof (sd), addr) == -1) {
mdb_warn("couldn't read stream head at %p", addr);
return (DCMD_ERR);
}
prfunc((stdata_t *)addr, &sd);
return (DCMD_OK);
}
/*ARGSUSED*/
static void
sdprint_wrq(stdata_t *addr, stdata_t *sd)
{
mdb_printf("%p\n", sd->sd_wrq);
}
static void
sdprint_mate(stdata_t *addr, stdata_t *sd)
{
mdb_printf("%p\n", sd->sd_mate ? sd->sd_mate : addr);
}
/*ARGSUSED*/
int
str2mate(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
return (sd2x(addr, argc, sdprint_mate));
}
/*ARGSUSED*/
int
str2wrq(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
return (sd2x(addr, argc, sdprint_wrq));
}
/*
* If this syncq is a part of the queue pair structure, find the queue for it.
*/
/*ARGSUSED*/
int
syncq2q(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
syncq_t sq;
queue_t q;
queue_t *qp;
if (argc != 0)
return (DCMD_USAGE);
if (mdb_vread(&sq, sizeof (sq), addr) == -1) {
mdb_warn("couldn't read syncq at %p", addr);
return (DCMD_ERR);
}
/* Try to find its queue */
qp = (queue_t *)addr - 2;
if ((mdb_vread(&q, sizeof (q), (uintptr_t)qp) == -1) ||
(q.q_syncq != (syncq_t *)addr)) {
mdb_warn("syncq2q: %p is not part of any queue\n", addr);
return (DCMD_ERR);
} else
mdb_printf("%p\n", qp);
return (DCMD_OK);
}
int
queue_walk_init(mdb_walk_state_t *wsp)
{
if (wsp->walk_addr == NULL &&
mdb_readvar(&wsp->walk_addr, "qhead") == -1) {
mdb_warn("failed to read 'qhead'");
return (WALK_ERR);
}
wsp->walk_data = mdb_alloc(sizeof (queue_t), UM_SLEEP);
return (WALK_NEXT);
}
int
queue_link_step(mdb_walk_state_t *wsp)
{
int status;
if (wsp->walk_addr == NULL)
return (WALK_DONE);
if (mdb_vread(wsp->walk_data, sizeof (queue_t), wsp->walk_addr) == -1) {
mdb_warn("failed to read queue at %p", wsp->walk_addr);
return (WALK_DONE);
}
status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
wsp->walk_cbdata);
wsp->walk_addr = (uintptr_t)(((queue_t *)wsp->walk_data)->q_link);
return (status);
}
int
queue_next_step(mdb_walk_state_t *wsp)
{
int status;
if (wsp->walk_addr == NULL)
return (WALK_DONE);
if (mdb_vread(wsp->walk_data, sizeof (queue_t), wsp->walk_addr) == -1) {
mdb_warn("failed to read queue at %p", wsp->walk_addr);
return (WALK_DONE);
}
status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
wsp->walk_cbdata);
wsp->walk_addr = (uintptr_t)(((queue_t *)wsp->walk_data)->q_next);
return (status);
}
void
queue_walk_fini(mdb_walk_state_t *wsp)
{
mdb_free(wsp->walk_data, sizeof (queue_t));
}
int
str_walk_init(mdb_walk_state_t *wsp)
{
stdata_t s;
if (wsp->walk_addr == NULL) {
mdb_warn("walk must begin at address of stdata_t\n");
return (WALK_ERR);
}
if (mdb_vread(&s, sizeof (s), wsp->walk_addr) == -1) {
mdb_warn("failed to read stdata at %p", wsp->walk_addr);
return (WALK_ERR);
}
wsp->walk_addr = (uintptr_t)s.sd_wrq;
wsp->walk_data = mdb_alloc(sizeof (queue_t) * 2, UM_SLEEP);
return (WALK_NEXT);
}
int
strr_walk_step(mdb_walk_state_t *wsp)
{
queue_t *rq = wsp->walk_data, *wq = rq + 1;
int status;
if (wsp->walk_addr == NULL)
return (WALK_DONE);
if (mdb_vread(wsp->walk_data, sizeof (queue_t) * 2,
wsp->walk_addr - sizeof (queue_t)) == -1) {
mdb_warn("failed to read queue pair at %p",
wsp->walk_addr - sizeof (queue_t));
return (WALK_DONE);
}
status = wsp->walk_callback(wsp->walk_addr - sizeof (queue_t),
rq, wsp->walk_cbdata);
if (wq->q_next != NULL)
wsp->walk_addr = (uintptr_t)wq->q_next;
else
wsp->walk_addr = mdb_qwnext(wq);
return (status);
}
int
strw_walk_step(mdb_walk_state_t *wsp)
{
queue_t *rq = wsp->walk_data, *wq = rq + 1;
int status;
if (wsp->walk_addr == NULL)
return (WALK_DONE);
if (mdb_vread(wsp->walk_data, sizeof (queue_t) * 2,
wsp->walk_addr - sizeof (queue_t)) == -1) {
mdb_warn("failed to read queue pair at %p",
wsp->walk_addr - sizeof (queue_t));
return (WALK_DONE);
}
status = wsp->walk_callback(wsp->walk_addr, wq, wsp->walk_cbdata);
if (wq->q_next != NULL)
wsp->walk_addr = (uintptr_t)wq->q_next;
else
wsp->walk_addr = mdb_qwnext(wq);
return (status);
}
void
str_walk_fini(mdb_walk_state_t *wsp)
{
mdb_free(wsp->walk_data, sizeof (queue_t) * 2);
}
static int
print_qpair(uintptr_t addr, const queue_t *q, uint_t *depth)
{
static const char box_lid[] =
"+-----------------------+-----------------------+\n";
static const char box_sep[] =
"| | |\n";
char wname[32], rname[32], info1[256], *info2;
if (*depth != 0) {
mdb_printf(" | ^\n");
mdb_printf(" v |\n");
} else
mdb_printf("\n");
(void) mdb_qname(_WR(q), wname, sizeof (wname));
(void) mdb_qname(_RD(q), rname, sizeof (rname));
mdb_qinfo(_WR(q), info1, sizeof (info1));
if ((info2 = strchr(info1, '\n')) != NULL)
*info2++ = '\0';
else
info2 = "";
mdb_printf(box_lid);
mdb_printf("| 0x%-19p | 0x%-19p | %s\n",
addr, addr - sizeof (queue_t), info1);
mdb_printf("| %<b>%-21s%</b> | %<b>%-21s%</b> |", wname, rname);
mdb_flush(); /* Account for buffered terminal sequences */
mdb_printf(" %s\n", info2);
mdb_printf(box_sep);
mdb_qinfo(_RD(q), info1, sizeof (info1));
if ((info2 = strchr(info1, '\n')) != NULL)
*info2++ = '\0';
else
info2 = "";
mdb_printf("| cnt = 0t%-13lu | cnt = 0t%-13lu | %s\n",
_WR(q)->q_count, _RD(q)->q_count, info1);
mdb_printf("| flg = 0x%08x | flg = 0x%08x | %s\n",
_WR(q)->q_flag, _RD(q)->q_flag, info2);
mdb_printf(box_lid);
*depth += 1;
return (0);
}
/*ARGSUSED*/
int
stream(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
uint_t d = 0; /* Depth counter for print_qpair */
if (argc != 0 || !(flags & DCMD_ADDRSPEC))
return (DCMD_USAGE);
if (mdb_pwalk("writeq", (mdb_walk_cb_t)print_qpair, &d, addr) == -1) {
mdb_warn("failed to walk writeq");
return (DCMD_ERR);
}
return (DCMD_OK);
}
int
mblk_walk_init(mdb_walk_state_t *wsp)
{
wsp->walk_data = mdb_alloc(sizeof (mblk_t), UM_SLEEP);
return (WALK_NEXT);
}
int
b_cont_step(mdb_walk_state_t *wsp)
{
int status;
if (wsp->walk_addr == NULL)
return (WALK_DONE);
if (mdb_vread(wsp->walk_data, sizeof (mblk_t), wsp->walk_addr) == -1) {
mdb_warn("failed to read mblk at %p", wsp->walk_addr);
return (WALK_DONE);
}
status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
wsp->walk_cbdata);
wsp->walk_addr = (uintptr_t)(((mblk_t *)wsp->walk_data)->b_cont);
return (status);
}
int
b_next_step(mdb_walk_state_t *wsp)
{
int status;
if (wsp->walk_addr == NULL)
return (WALK_DONE);
if (mdb_vread(wsp->walk_data, sizeof (mblk_t), wsp->walk_addr) == -1) {
mdb_warn("failed to read mblk at %p", wsp->walk_addr);
return (WALK_DONE);
}
status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
wsp->walk_cbdata);
wsp->walk_addr = (uintptr_t)(((mblk_t *)wsp->walk_data)->b_next);
return (status);
}
void
mblk_walk_fini(mdb_walk_state_t *wsp)
{
mdb_free(wsp->walk_data, sizeof (mblk_t));
}
/* ARGSUSED */
int
mblk2dblk(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
mblk_t mb;
if (argc != 0)
return (DCMD_USAGE);
if (mdb_vread(&mb, sizeof (mb), addr) == -1) {
mdb_warn("couldn't read mblk at %p", addr);
return (DCMD_ERR);
}
mdb_printf("%p\n", mb.b_datap);
return (DCMD_OK);
}
static void
mblk_error(int *error, uintptr_t addr, char *message)
{
if (!*error)
mdb_printf("%?lx: ", addr);
else
mdb_printf(", ");
mdb_printf("%s", message);
*error = 1;
}
int
mblk_verify(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
mblk_t mb;
dblk_t db;
int error = 0;
if (!(flags & DCMD_ADDRSPEC)) {
if (mdb_walk_dcmd("streams_mblk", "mblk_verify", argc, argv) ==
-1) {
mdb_warn("can't walk mblk cache");
return (DCMD_ERR);
}
return (DCMD_OK);
}
if (mdb_vread(&mb, sizeof (mblk_t), addr) == -1) {
mdb_warn("can't read mblk_t at 0x%lx", addr);
return (DCMD_ERR);
}
if (mdb_vread(&db, sizeof (dblk_t), (uintptr_t)mb.b_datap) == -1) {
mdb_warn("%?lx: invalid b_datap pointer\n", addr);
return (DCMD_ERR);
}
if (mb.b_rptr < db.db_base || mb.b_rptr > db.db_lim)
mblk_error(&error, addr, "b_rptr out of range");
if (mb.b_wptr < db.db_base || mb.b_wptr > db.db_lim)
mblk_error(&error, addr, "b_wptr out of range");
if (error)
mdb_printf("\n");
return (error ? DCMD_ERR : DCMD_OK);
}
int
mblk_prt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
const int MBLK_FLGDELT = (int)(sizeof (uintptr_t) * 2 + 15);
mblk_t mblk;
dblk_t dblk;
int b_flag;
int db_type;
int mblklen;
uint64_t len = ~0UL;
uint64_t glen = ~0UL;
uint64_t llen = ~0UL;
uint64_t blen = ~0UL;
const char *dbtype;
const char *flag = NULL, *not_flag = NULL;
const char *typ = NULL, *not_typ = NULL;
uintptr_t dbaddr = 0;
uint32_t tmask = 0, not_tmask = 0;
uint32_t mask = 0, not_mask = 0;
uint_t quiet = FALSE;
uint_t verbose = FALSE;
if (!(flags & DCMD_ADDRSPEC)) {
if (mdb_walk_dcmd("genunix`streams_mblk", "genunix`mblk",
argc, argv) == -1) {
mdb_warn("failed to walk mblk cache");
return (DCMD_ERR);
}
return (DCMD_OK);
}
if (flags & DCMD_PIPE_OUT)
quiet = TRUE;
if (mdb_getopts(argc, argv,
'v', MDB_OPT_SETBITS, TRUE, &verbose,
'q', MDB_OPT_SETBITS, TRUE, &quiet,
'f', MDB_OPT_STR, &flag,
'F', MDB_OPT_STR, &not_flag,
't', MDB_OPT_STR, &typ,
'T', MDB_OPT_STR, &not_typ,
'l', MDB_OPT_UINT64, &len,
'L', MDB_OPT_UINT64, &llen,
'G', MDB_OPT_UINT64, &glen,
'b', MDB_OPT_UINT64, &blen,
'd', MDB_OPT_UINTPTR, &dbaddr,
NULL) != argc)
return (DCMD_USAGE);
/*
* If any of the filtering flags is specified, don't print anything
* except the matching pointer.
*/
if ((flag != NULL) || (not_flag != NULL) || (typ != NULL) ||
(not_typ != NULL) || (len != ~0UL) || (glen != ~0UL) ||
(llen != ~0UL) || (blen != ~0UL) || (dbaddr != 0))
quiet = TRUE;
if (flag != NULL && streams_parse_flag(mbf, flag, &mask) == -1) {
mdb_warn("unrecognized mblk flag '%s'\n", flag);
streams_flag_usage(mbf);
return (DCMD_USAGE);
}
if (not_flag != NULL &&
streams_parse_flag(mbf, not_flag, &not_mask) == -1) {
mdb_warn("unrecognized mblk flag '%s'\n", flag);
streams_flag_usage(mbf);
return (DCMD_USAGE);
}
if (typ != NULL && streams_parse_type(mbt, typ, &tmask) == -1) {
mdb_warn("unrecognized dblk type '%s'\n", typ);
streams_type_usage(mbt);
return (DCMD_USAGE);
}
if (not_typ != NULL && streams_parse_type(mbt, not_typ, &not_tmask)
== -1) {
mdb_warn("unrecognized dblk type '%s'\n", not_typ);
streams_type_usage(mbt);
return (DCMD_USAGE);
}
if (DCMD_HDRSPEC(flags) && !quiet) {
mdb_printf("%?s %2s %-7s %-5s %-5s %?s %?s\n",
"ADDR", "FL", "TYPE", "LEN", "BLEN", "RPTR", "DBLK");
}
if (mdb_vread(&mblk, sizeof (mblk), addr) == -1) {
mdb_warn("couldn't read mblk at %p", addr);
return (DCMD_ERR);
}
b_flag = mblk.b_flag;
if (mask != 0 && !(b_flag & mask))
return (DCMD_OK);
if (not_mask != 0 && (b_flag & not_mask))
return (DCMD_OK);
if (mdb_vread(&dblk, sizeof (dblk), (uintptr_t)(mblk.b_datap)) == -1) {
mdb_warn("couldn't read dblk at %p/%p", addr, mblk.b_datap);
return (DCMD_ERR);
}
db_type = dblk.db_type;
/* M_DATA is 0, so tmask has special value 0xff for it */
if ((tmask != 0) &&
(((tmask == M_DATA_T) && (db_type != M_DATA)) ||
((tmask != M_DATA_T) && (db_type != tmask))))
return (DCMD_OK);
if ((not_tmask != 0) &&
(((not_tmask == M_DATA_T) && (db_type == M_DATA)) ||
(db_type == not_tmask)))
return (DCMD_OK);
if (dbaddr != 0 && (uintptr_t)mblk.b_datap != dbaddr)
return (DCMD_OK);
mblklen = MBLKL(&mblk);
if ((len != ~0UL) && (len != mblklen))
return (DCMD_OK);
if ((llen != ~0Ul) && (mblklen > (int)llen))
return (DCMD_OK);
if ((glen != ~0Ul) && (mblklen < (int)glen))
return (DCMD_OK);
if ((blen != ~0UL) && (blen != (dblk.db_lim - dblk.db_base)))
return (DCMD_OK);
/*
* Options are specified for filtering, so If any option is specified on
* the command line, just print address and exit.
*/
if (quiet) {
mdb_printf("%0?p\n", addr);
return (DCMD_OK);
}
/* Figure out symbolic DB_TYPE */
if (db_type < A_SIZE(db_control_types)) {
dbtype = db_control_types[db_type];
} else {
/*
* Must be a high-priority message -- adjust so that
* "QPCTL + 1" corresponds to db_control_hipri_types[0]
*/
db_type -= (QPCTL + 1);
if (db_type >= 0 && db_type < A_SIZE(db_control_hipri_types))
dbtype = db_control_hipri_types[db_type];
else
dbtype = "UNKNOWN";
}
mdb_printf("%0?p %-2x %-7s %-5d %-5d %0?p %0?p\n",
addr, b_flag, dbtype, mblklen, dblk.db_lim - dblk.db_base,
mblk.b_rptr, mblk.b_datap);
if (verbose) {
int i, arm = 0;
for (i = 0; mbf[i].strf_name != NULL; i++) {
if (!(b_flag & (1 << i)))
continue;
if (!arm) {
mdb_printf("%*s|\n%*s+--> ",
MBLK_FLGDELT, "", MBLK_FLGDELT, "");
arm = 1;
} else
mdb_printf("%*s ", MBLK_FLGDELT, "");
mdb_printf("%-12s %s\n",
mbf[i].strf_name, mbf[i].strf_descr);
}
}
return (DCMD_OK);
}
/*
* Streams flow trace walkers.
*/
int
strftblk_walk_init(mdb_walk_state_t *wsp)
{
ftblkdata_t *ftd;
dblk_t db;
/* Get the dblock from the address */
if (mdb_vread(&db, sizeof (dblk_t), wsp->walk_addr) == -1) {
mdb_warn("failed to read dblk at %p", wsp->walk_addr);
return (WALK_ERR);
}
/* Is there any flow trace data? */
if (db.db_fthdr == NULL) {
return (WALK_DONE);
}
wsp->walk_addr = (uintptr_t)((char *)db.db_fthdr +
offsetof(fthdr_t, first));
ftd = mdb_alloc(sizeof (ftblkdata_t), UM_SLEEP);
ftd->ft_ix = 0;
ftd->ft_in_evlist = B_FALSE;
wsp->walk_data = ftd;
return (WALK_NEXT);
}
int
strftblk_step(mdb_walk_state_t *wsp)
{
ftblkdata_t *ftd;
ftblk_t *ftbp;
int status = WALK_NEXT;
if (wsp->walk_addr == NULL)
return (WALK_DONE);
ftd = (ftblkdata_t *)wsp->walk_data;
ftbp = &(ftd->ft_data);
if (! ftd->ft_in_evlist) {
/* Read a new ft block */
if (mdb_vread(ftbp, sizeof (ftblk_t),
wsp->walk_addr) == -1) {
mdb_warn("failed to read ftblk at %p", wsp->walk_addr);
return (WALK_ERR);
}
/*
* Check correctness of the index field.
*/
if (ftbp->ix < 0 || ftbp->ix > FTBLK_EVNTS) {
mdb_warn("ftblk: incorrect index value %i\n", ftbp->ix);
return (WALK_ERR);
}
ftd->ft_ix = 1;
ftd->ft_in_evlist = B_TRUE;
}
if (ftd->ft_ix > ftbp->ix) {
ftd->ft_in_evlist = B_FALSE;
/* End of event list reached - move to the next event block */
wsp->walk_addr = (uintptr_t)ftbp->nxt;
} else {
/* Print event address */
status = wsp->walk_callback((uintptr_t)((char *)wsp->walk_addr +
offsetof(ftblk_t, ev) +
(ftd->ft_ix - 1) * sizeof (struct ftevnt)),
wsp->walk_data, wsp->walk_cbdata);
ftd->ft_ix++;
}
return (status);
}
void
strftblk_walk_fini(mdb_walk_state_t *wsp)
{
mdb_free(wsp->walk_data, sizeof (ftblkdata_t));
}
/*ARGSUSED*/
int
strftevent(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
struct ftevnt ev;
char modname[MODMAXNAMELEN];
if (!(flags & DCMD_ADDRSPEC))
return (DCMD_USAGE);
if (DCMD_HDRSPEC(flags)) {
mdb_printf("%?s %?s %s %s %-24s %s\n",
"ADDR", "MID", "EVNT", "DATA", "NAME", "EVENT");
}
if (mdb_vread(&ev, sizeof (ev), addr) == -1) {
mdb_warn("couldn't read ft event at %p", addr);
return (DCMD_ERR);
}
mdb_printf("%0?p %0?p %4x %4x",
addr, ev.mid, ev.evnt, ev.data);
if (ev.evnt & FTEV_QMASK) {
if (mdb_readstr(modname, sizeof (modname),
(uintptr_t)ev.mid) == -1)
mdb_warn("couldn't read module name at %p", ev.mid);
mdb_printf(" %-24s", modname);
} else
mdb_printf(" %-24a", ev.mid);
ft_printevent(ev.evnt);
mdb_printf("\n");
return (DCMD_OK);
}
static void
ft_printevent(ushort_t ev)
{
ushort_t proc_ev = (ev & (FTEV_PROC_START | 0xFF)) - FTEV_PROC_START;
ushort_t alloc_ev = ev & FTEV_CALLER;
/* Get event class first */
if (ev & FTEV_PROC_START) {
if (proc_ev >= A_SIZE(ftev_proc))
mdb_printf(" undefined");
else
mdb_printf(" %s", ftev_proc[proc_ev]);
} else if (alloc_ev >= A_SIZE(ftev_alloc))
mdb_printf(" undefined");
else
mdb_printf(" %s", ftev_alloc[alloc_ev]);
/* Print event modifiers, if any */
if (ev & FTEV_PS)
mdb_printf(" | PS");
if (ev & FTEV_CS)
mdb_printf(" | CS");
if (ev & FTEV_ISWR)
mdb_printf(" | ISWR");
}
/*
* Help functions for STREAMS debugging facilities.
*/
void
queue_help(void)
{
mdb_printf("Print queue information for a given queue pointer.\n"
"\nWithout the address of a \"queue_t\" structure given, print "
"information about all\n"
"queues in the \"queue_cache\".\n\n"
"Options:\n"
" -v:\t\tbe verbose - print symbolic flags falues\n"
" -q:\t\tbe quiet - print queue pointer only\n"
" -f flag:\tprint only queues with flag set\n"
" -F flag:\tprint only queues with flag NOT set\n"
" -m modname:\tprint only queues with specified module name\n"
" -s syncq_addr:\tprint only queues which use specified syncq\n\n"
"Available conversions:\n"
" q2rdq: given a queue addr print read queue pointer\n"
" q2wrq: given a queue addr print write queue pointer\n"
" q2otherq: given a queue addr print other queue pointer\n"
" q2syncq: given a queue addr print syncq pointer"
" (::help syncq)\n"
" q2stream: given a queue addr print its stream pointer\n"
"\t\t(see ::help stream and ::help stdata)\n\n"
"To walk q_next pointer of the queue use\n"
" queue_addr::walk qnext\n");
}
void
syncq_help(void)
{
mdb_printf("Print syncq information for a given syncq pointer.\n"
"\nWithout the address of a \"syncq_t\" structure given, print "
"information about all\n"
"syncqs in the \"syncq_cache\".\n\n"
"Options:\n"
" -v:\t\tbe verbose - print symbolic flags falues\n"
" -q:\t\tbe quiet - print syncq pointer only\n"
" -f flag:\tprint only syncqs with flag set\n"
" -F flag:\tprint only syncqs with flag NOT set\n"
" -t type:\tprint only syncqs with specified type\n"
" -T type:\tprint only syncqs with do NOT have specified type\n\n"
"Available conversions:\n"
" syncq2q:\tgiven a syncq addr print queue address of the\n"
"\t\t\tenclosing queue, if it is part of a queue\n\n"
"See also: \"::help queue\" and \"::help stdata\"\n");
}
void
stdata_help(void)
{
mdb_printf("Print stdata information for a given stdata pointer.\n"
"\nWithout the address of a \"stdata_t\" structure given, print "
"information about all\n"
"stream head pointers from the \"stream_head_cache\".\n\n"
"Fields printed:\n"
" ADDR:\tstream head address\n"
" WRQ:\twrite queue pointer\n"
" FLAGS:\tstream head flags (use -v to show in symbolic form)\n"
" VNODE:\tstream vnode pointer\n"
" N/A:\tpushcount and anchor positions\n"
" REF:\tstream head reference counter\n\n"
"Options:\n"
" -v:\t\tbe verbose - print symbolic flags falues\n"
" -q:\t\tbe quiet - print stdata pointer only\n"
" -f flag:\tprint only stdatas with flag set\n"
" -F flag:\tprint only stdatas with flag NOT set\n\n"
"Available conversions:\n"
" str2mate:\tgiven a stream head addr print its mate\n"
" str2wrq:\tgiven a stream head addr print its write queue\n\n"
"See also: \"::help queue\" and \"::help syncq\"\n");
}
void
mblk_help(void)
{
mdb_printf("Print mblock information for a given mblk pointer.\n"
"Without the address, print information about all mblocks.\n\n"
"Fields printed:\n"
" ADDR:\tmblk address\n"
" FL:\tFlags\n"
" TYPE:\tType of corresponding dblock\n"
" LEN:\tData length as b_wptr - b_rptr\n"
" BLEN:\tDblock space as db_lim - db_base\n"
" RPTR:\tRead pointer\n"
" DBLK:\tDblock pointer\n\n"
"Options:\n"
" -v:\t\tbe verbose - print symbolic flags falues\n"
" -q:\t\tbe quiet - print mblk pointer only\n"
" -d dbaddr:\t\tprint mblks with specified dblk address\n"
" -f flag:\tprint only mblks with flag set\n"
" -F flag:\tprint only mblks with flag NOT set\n"
" -t type:\tprint only mblks of specified db_type\n"
" -T type:\tprint only mblks other then the specified db_type\n"
" -l len:\t\ttprint only mblks with MBLKL == len\n"
" -L len:\t\tprint only mblks with MBLKL <= len \n"
" -G len:\t\tprint only mblks with MBLKL >= len \n"
" -b len:\t\tprint only mblks with db_lim - db_base == len\n"
"\n");
}