genunix.c revision 0c3b83b18601d5b276d2586e180f1e6929247469
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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
* 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 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <mdb/mdb_param.h>
#include <mdb/mdb_modapi.h>
#include <sys/priocntl.h>
#include <sys/flock_impl.h>
#include <sys/kmem_impl.h>
#include <sys/vmem_impl.h>
#include <sys/dditypes.h>
#include <sys/ddi_impldefs.h>
#include <sys/sysmacros.h>
#include <sys/taskq_impl.h>
#include <sys/errorq_impl.h>
#include <sys/cred_impl.h>
#include <regex.h>
#include <sys/port_impl.h>
#include "avl.h"
#include "combined.h"
#include "contract.h"
#include "cpupart_mdb.h"
#include "devinfo.h"
#include "irm.h"
#include "leaky.h"
#include "lgrp.h"
#include "pg.h"
#include "group.h"
#include "list.h"
#include "log.h"
#include "kgrep.h"
#include "kmem.h"
#include "bio.h"
#include "streams.h"
#include "cyclic.h"
#include "findstack.h"
#include "ndievents.h"
#include "mmd.h"
#include "net.h"
#include "netstack.h"
#include "nvpair.h"
#include "ctxop.h"
#include "tsd.h"
#include "thread.h"
#include "memory.h"
#include "sobj.h"
#include "sysevent.h"
#include "rctl.h"
#include "tsol.h"
#include "typegraph.h"
#include "ldi.h"
#include "vfs.h"
#include "zone.h"
#include "modhash.h"
#include "mdi.h"
#include "fm.h"
/*
* Surely this is defined somewhere...
*/
#define NINTR 16
#define KILOS 10
#define MEGS 20
#define GIGS 30
#ifndef STACK_BIAS
#define STACK_BIAS 0
#endif
static char
{
switch (state) {
case SSLEEP: return ('S');
case SRUN: return ('R');
case SZOMB: return ('Z');
case SIDL: return ('I');
case SONPROC: return ('O');
case SSTOP: return ('T');
case SWAIT: return ('W');
default: return ('?');
}
}
#define PS_PRTTHREADS 0x1
#define PS_PRTLWPS 0x2
#define PS_PSARGS 0x4
#define PS_TASKS 0x8
#define PS_PROJECTS 0x10
#define PS_ZONES 0x20
static int
{
static const mdb_bitmask_t t_state_bits[] = {
{ NULL, 0, 0 }
};
if (prt_flags & PS_PRTTHREADS)
if (prt_flags & PS_PRTLWPS)
return (WALK_NEXT);
}
int
{
if (!(flags & DCMD_ADDRSPEC)) {
mdb_warn("can't walk 'proc'");
return (DCMD_ERR);
}
return (DCMD_OK);
}
return (DCMD_USAGE);
if (DCMD_HDRSPEC(flags)) {
mdb_printf("%<u>%1s %6s %6s %6s %6s ",
"S", "PID", "PPID", "PGID", "SID");
if (prt_flags & PS_PROJECTS)
mdb_printf("%6s %10s %?s %s%</u>\n",
"UID", "FLAGS", "ADDR", "NAME");
}
if (prt_flags & PS_PROJECTS)
mdb_printf("%c %6d %6d %6d %6d ",
if (prt_flags & PS_PROJECTS)
mdb_printf("%6d 0x%08x %0?p %s\n",
return (DCMD_OK);
}
#define PG_NEWEST 0x0001
#define PG_OLDEST 0x0002
#define PG_PIPE_OUT 0x0004
#define PG_EXACT_MATCH 0x0008
typedef struct pgrep_data {
const char *pg_pat;
#ifndef _KMDB
#endif
} pgrep_data_t;
/*ARGSUSED*/
static int
{
#ifndef _KMDB
#endif
/*
* kmdb doesn't have access to the reg* functions, so we fall back
*/
#ifdef _KMDB
return (WALK_NEXT);
#else
return (WALK_NEXT);
return (WALK_NEXT);
#endif
}
} else {
}
}
} else {
mdb_warn("can't invoke 'ps'");
return (WALK_DONE);
}
}
return (WALK_NEXT);
}
/*ARGSUSED*/
int
{
int i;
#ifndef _KMDB
int err;
#endif
if (flags & DCMD_ADDRSPEC)
return (DCMD_USAGE);
NULL);
argc -= i;
argv += i;
if (argc != 1)
return (DCMD_USAGE);
/*
* -n and -o are mutually exclusive.
*/
return (DCMD_USAGE);
return (DCMD_USAGE);
if (flags & DCMD_PIPE_OUT)
if (DCMD_HDRSPEC(flags))
else
#ifndef _KMDB
char *buf;
return (DCMD_ERR);
}
#endif
mdb_warn("can't walk 'proc'");
return (DCMD_ERR);
}
} else {
0, NULL) != 0) {
mdb_warn("can't invoke 'ps'");
return (DCMD_ERR);
}
}
}
return (DCMD_OK);
}
int
{
if (!(flags & DCMD_ADDRSPEC)) {
mdb_warn("can't walk task_cache");
return (DCMD_ERR);
}
return (DCMD_OK);
}
if (DCMD_HDRSPEC(flags)) {
mdb_printf("%<u>%?s %6s %6s %6s %6s %10s%</u>\n",
"ADDR", "TASKID", "PROJID", "ZONEID", "REFCNT", "FLAGS");
}
return (DCMD_ERR);
}
return (DCMD_ERR);
}
mdb_printf("%0?p %6d %6d %6d %6u 0x%08x\n",
return (DCMD_OK);
}
int
{
if (!(flags & DCMD_ADDRSPEC)) {
mdb_warn("can't walk projects");
return (DCMD_ERR);
}
return (DCMD_OK);
}
if (DCMD_HDRSPEC(flags)) {
mdb_printf("%<u>%?s %6s %6s %6s%</u>\n",
"ADDR", "PROJID", "ZONEID", "REFCNT");
}
return (DCMD_ERR);
}
return (DCMD_OK);
}
/* walk callouts themselves, either by list or id hash. */
int
{
mdb_warn("callout doesn't support global walk");
return (WALK_ERR);
}
return (WALK_NEXT);
}
#define CALLOUT_WALK_BYLIST 0
#define CALLOUT_WALK_BYID 1
/* the walker arg switches between walking by list (0) and walking by id (1). */
int
{
int retval;
return (WALK_DONE);
}
return (WALK_DONE);
}
wsp->walk_cbdata);
} else {
}
return (retval);
}
void
{
}
/*
* walker for callout lists. This is different from hashes and callouts.
* Thankfully, it's also simpler.
*/
int
{
mdb_warn("callout list doesn't support global walk");
return (WALK_ERR);
}
return (WALK_NEXT);
}
int
{
int retval;
return (WALK_DONE);
}
return (WALK_ERR);
}
wsp->walk_cbdata);
return (retval);
}
void
{
}
typedef struct cot_data {
int cotndx;
int cotsize;
} cot_data_t;
int
{
int max_ncpus;
mdb_warn("failed to read 'callout_table'");
return (WALK_ERR);
}
mdb_warn("failed to get callout_table array size");
return (WALK_ERR);
}
} else {
/* not a global walk */
}
cot_walk_data->cotndx = 0;
return (WALK_NEXT);
}
int
{
int retval;
return (WALK_DONE);
}
return (WALK_ERR);
}
mdb_warn("failed to read id_hash at %p",
return (WALK_ERR);
}
}
mdb_warn("failed to read cl_hash at %p",
return (WALK_ERR);
}
}
mdb_warn("failed to read kstats at %p",
return (WALK_ERR);
}
}
wsp->walk_cbdata);
return (WALK_DONE);
}
sizeof (callout_table_t));
return (retval);
}
void
{
}
#define TABLE_TO_SEQID(x) ((x) >> CALLOUT_TYPE_BITS)
/* callout flags, in no particular order */
#define COF_REAL 0x0000001
#define COF_NORM 0x0000002
#define COF_LONG 0x0000004
#define COF_SHORT 0x0000008
#define COF_EMPTY 0x0000010
#define COF_TIME 0x0000020
#define COF_BEFORE 0x0000040
#define COF_AFTER 0x0000080
#define COF_SEQID 0x0000100
#define COF_FUNC 0x0000200
#define COF_ADDR 0x0000400
#define COF_EXEC 0x0000800
#define COF_HIRES 0x0001000
#define COF_ABS 0x0002000
#define COF_TABLE 0x0004000
#define COF_BYIDH 0x0008000
#define COF_FREE 0x0010000
#define COF_LIST 0x0020000
#define COF_EXPREL 0x0040000
#define COF_HDR 0x0080000
#define COF_VERBOSE 0x0100000
#define COF_LONGLIST 0x0200000
#define COF_THDR 0x0400000
#define COF_LHDR 0x0800000
#define COF_CHDR 0x1000000
#define COF_PARAM 0x2000000
#define COF_DECODE 0x4000000
/* show real and normal, short and long, expired and unexpired. */
#define COF_LIST_FLAGS \
/* private callout data for callback functions */
typedef struct callout_data {
int seqid; /* cpu seqid, or -1 */
int nsec_per_tick; /* for conversions */
int ndx; /* table index. */
int list_flags; /* copy of cl_flags */
/* this callback does the actual callback itself (finally). */
/*ARGSUSED*/
static int
{
int tableid, list_flags;
return (WALK_ERR);
}
/*
* The callout must have been reallocated. No point in
* walking any more.
*/
return (WALK_DONE);
}
/*
* The callout must have been freed. No point in
* walking any more.
*/
return (WALK_DONE);
}
return (WALK_NEXT);
}
return (WALK_NEXT);
}
return (WALK_NEXT);
}
return (WALK_NEXT);
}
return (WALK_NEXT);
}
/* it is possible we don't have the exp time or flags */
/* we have to fetch the expire time ourselves. */
cl_expiration)) == -1) {
mdb_warn("failed to read expiration "
}
/* and flags. */
cl_flags)) == -1) {
mdb_warn("failed to read list flags"
coargs->list_flags = 0;
}
} else {
/* free callouts can't use list pointer. */
coargs->list_flags = 0;
}
return (WALK_NEXT);
}
return (WALK_NEXT);
}
return (WALK_NEXT);
}
}
/* tricky part, since both HIRES and ABS can be set */
/* both flags are set, only skip "regular" ones */
if (! (list_flags & COF_LIST_FLAGS)) {
return (WALK_NEXT);
}
} else {
/* individual flags, or no flags */
!(list_flags & CALLOUT_LIST_FLAG_HRESTIME)) {
return (WALK_NEXT);
}
!(list_flags & CALLOUT_LIST_FLAG_ABSOLUTE)) {
return (WALK_NEXT);
}
}
}
/*
* We need to print the headers. If walking by id, then
* the list header isn't printed, so we must include
* that info here.
*/
mdb_printf("%<u>%3s %-1s %-14s %</u>",
"SEQ", "T", "EXP");
}
mdb_printf("%<u>%-4s %-?s %-20s%</u>",
"XHAL", "XID", "FUNC(ARG)");
mdb_printf("%<u> %-?s %-?s %-?s %-?s%</u>",
"PREVID", "NEXTID", "PREVL", "NEXTL");
mdb_printf("%<u> %-?s %-4s %-?s%</u>",
"DONE", "UTOS", "THREAD");
}
mdb_printf("\n");
}
mdb_printf("%-3d %1s %-14llx ",
mdb_printf("%-14x ",
}
mdb_printf("%1s%1s%1s%1s %-?llx %a(%p)",
mdb_printf(" %-?p %-?p %-?p %-?p",
mdb_printf(" %-?p %-4d %-0?p",
}
} else {
/* address only */
}
mdb_printf("\n");
return (WALK_NEXT);
}
/* this callback is for callout list handling. idhash is done by callout_t_cb */
/*ARGSUSED*/
static int
{
int list_flags;
return (WALK_ERR);
}
/*
* The callout list must have been reallocated. No point in
* walking any more.
*/
return (WALK_DONE);
}
/*
* The callout list must have been freed. No point in
* walking any more.
*/
return (WALK_DONE);
}
return (WALK_NEXT);
}
return (WALK_NEXT);
}
return (WALK_NEXT);
}
return (WALK_NEXT);
}
/* FOUR cases, each different, !A!B, !AB, A!B, AB */
/* both flags are set, only skip "regular" ones */
return (WALK_NEXT);
}
} else {
return (WALK_NEXT);
}
return (WALK_NEXT);
}
}
/* don't be redundant again */
mdb_printf("%<u>SEQ T %</u>");
}
mdb_printf("%<u>EXP HA BUCKET "
"CALLOUTS %</u>");
mdb_printf("%<u> %-?s %-?s%</u>",
"PREV", "NEXT");
}
mdb_printf("\n");
}
mdb_printf("%3d %1s ",
}
mdb_printf("%-14llx %1s%1s %-6d %-0?p ",
"H" : " ",
"A" : " ",
mdb_printf(" %-?p %-?p",
}
} else {
/* address only */
}
mdb_printf("\n");
return (WALK_NEXT);
}
}
/* yet another layer as we walk the actual callouts via list. */
return (WALK_NEXT);
}
/* free list structures do not have valid callouts off of them. */
return (WALK_NEXT);
}
mdb_inc_indent(4);
}
/*
* walk callouts using yet another callback routine.
* we use callouts_bytime because id hash is handled via
* the callout_t_cb callback.
*/
return (WALK_ERR);
}
mdb_dec_indent(4);
}
return (WALK_NEXT);
}
/* this callback handles the details of callout table walking. */
static int
{
int i;
return (WALK_ERR);
}
sizeof (callout_table_t);
return (WALK_NEXT);
}
return (WALK_NEXT);
}
return (WALK_NEXT);
}
return (WALK_NEXT);
}
/* print table hdr */
mdb_printf("%<u>%-3s %-1s %-?s %-?s %-?s %-?s%</u>",
"SEQ", "T", "FREE", "LFREE", "CYCLIC", "HEAP");
/* more info! */
mdb_printf("%<u> %-T%-7s %-7s %-?s %-?s"
" %-?s %-?s %-?s%</u>",
"HEAPNUM", "HEAPMAX", "TASKQ", "EXPQ",
"PEND", "FREE", "LOCK");
}
mdb_printf("\n");
}
mdb_printf("%-3d %-1s %-0?p %-0?p %-0?p %-?p",
/* more info! */
mdb_printf(" %-7d %-7d %-?p %-?p"
" %-?lld %-?lld %-?p",
}
} else {
/* address only */
}
mdb_printf("\n");
return (WALK_NEXT);
}
}
mdb_inc_indent(4);
}
/* keep digging. */
/* walk the list hash table */
return (WALK_NEXT);
}
mdb_warn("cannot walk callout free list at %p",
clptr);
return (WALK_ERR);
}
} else {
/* first print the expired list. */
mdb_warn("cannot walk callout_list"
" at %p", clptr);
return (WALK_ERR);
}
}
for (i = 0; i < CALLOUT_BUCKETS; i++) {
/* nothing to do */
break;
}
continue;
}
clptr = (callout_list_t *)
/* walk list with callback routine. */
mdb_warn("cannot walk callout_list"
" at %p", clptr);
return (WALK_ERR);
}
}
}
} else {
/* walk the id hash table. */
return (WALK_NEXT);
}
mdb_warn("cannot walk callout id free list"
" at %p", coptr);
return (WALK_ERR);
}
} else {
for (i = 0; i < CALLOUT_BUCKETS; i++) {
break;
}
continue;
}
/*
* walk callouts directly by id. For id
* chain, the callout list is just a header,
* so there's no need to walk it.
*/
mdb_warn("cannot walk callouts at %p",
coptr);
return (WALK_ERR);
}
}
}
}
mdb_dec_indent(4);
}
return (WALK_NEXT);
}
/*
* initialize some common info for both callout dcmds.
*/
int
{
/* we need a couple of things */
mdb_warn("failed to read 'callout_table'");
return (DCMD_ERR);
}
/* need to get now in nsecs. Approximate with hrtime vars */
sizeof (hrtime_t)) {
"hrtime_base") != sizeof (hrtime_t)) {
mdb_warn("Could not determine current system time");
return (DCMD_ERR);
}
}
mdb_warn("failed to read 'callout_table_bits'");
return (DCMD_ERR);
}
mdb_warn("failed to read 'nsec_per_tick'");
return (DCMD_ERR);
}
return (DCMD_OK);
}
/*
* dcmd to print callouts. Optional addr limits to specific table.
* Parses lots of options that get passed to callbacks for walkers.
* Has it's own help function.
*/
/*ARGSUSED*/
int
{
/* getopts doesn't help much with stuff like this */
int retval;
return (DCMD_USAGE);
}
/* initialize from kernel variables */
return (retval);
}
/* do some option post-processing */
if (kflag) {
}
if (dflag) {
}
if (Sflag) {
if (flags & DCMD_ADDRSPEC) {
mdb_printf("-S option conflicts with explicit"
" address\n");
return (DCMD_USAGE);
}
}
if (Cflag) {
if (flags & DCMD_ADDRSPEC) {
mdb_printf("-C option conflicts with explicit"
" address\n");
return (DCMD_USAGE);
}
mdb_printf("-C and -S are mutually exclusive\n");
return (DCMD_USAGE);
}
return (DCMD_ERR);
}
}
/* avoid null outputs. */
}
}
if (tflag) {
mdb_printf("-t and -a|b are mutually exclusive\n");
return (DCMD_USAGE);
}
}
if (aflag) {
}
if (bflag) {
}
mdb_printf("value for -a must be earlier than the value"
" for -b.\n");
return (DCMD_USAGE);
}
} else {
}
}
} else {
}
}
if (!(flags & DCMD_ADDRSPEC)) {
/* don't pass "dot" if no addr. */
}
/*
* a callout table was specified. Ignore -r|n option
* to avoid null output.
*/
}
}
/* -F = free callouts, -FL = free lists */
}
}
/* walk table, using specialized callback routine. */
mdb_warn("cannot walk callout_table");
return (DCMD_ERR);
}
return (DCMD_OK);
}
/*
* Given an extended callout id, dump its information.
*/
/*ARGSUSED*/
int
{
int tableid;
int i, retval;
NULL);
argc -= i;
argv += i;
if (argc != 1) {
return (DCMD_USAGE);
}
} else {
}
if (DCMD_HDRSPEC(flags)) {
}
/* initialize from kernel variables */
return (retval);
}
/* we must massage the environment so that the macros will play nice */
if (flags & DCMD_ADDRSPEC) {
mdb_printf("calloutid does not accept explicit address.\n");
return (DCMD_USAGE);
}
if (DCMD_HDRSPEC(flags)) {
mdb_printf("%<u>%3s %1s %2s %-?s %-6s %</u>\n",
"SEQ", "T", "XL", "XID", "IDHASH");
}
mdb_printf("%-3d %1s %1s%1s %-?llx %-6d\n",
return (DCMD_OK);
}
/* get our table. Note this relies on the types being correct */
return (DCMD_ERR);
}
mdb_warn("failed to read id_hash at %p",
return (WALK_ERR);
}
}
/* callout at beginning of hash chain */
mdb_printf("id hash chain for this xid is empty\n");
return (DCMD_ERR);
}
mdb_printf("id hash chain for this xid is empty\n");
return (DCMD_ERR);
}
/* use the walker, luke */
return (WALK_ERR);
}
return (DCMD_OK);
}
void
callout_help(void)
{
mdb_printf("callout: display callouts.\n"
"Given a callout table address, display callouts from table.\n"
"Without an address, display callouts from all tables.\n"
"options:\n"
" -r|n : limit display to (r)ealtime or (n)ormal type callouts\n"
" -s|l : limit display to (s)hort-term ids or (l)ong-term ids\n"
" -x : limit display to callouts which are executing\n"
" -h : limit display to callouts based on hrestime\n"
" -B : limit display to callouts based on absolute time\n"
" -t|a|b nsec: limit display to callouts that expire a(t) time,"
" (a)fter time,\n or (b)efore time. Use -a and -b together "
" to specify a range.\n For \"now\", use -d[t|a|b] 0.\n"
" -d : interpret time option to -t|a|b as delta from current time\n"
" -k : use ticks instead of nanoseconds as arguments to"
" -t|a|b. Note that\n ticks are less accurate and may not"
" match other tick times (ie: lbolt).\n"
" -D : display exiration time as delta from current time\n"
" -S seqid : limit display to callouts for this cpu sequence id\n"
" -C addr : limit display to callouts for this cpu pointer\n"
" -f name|addr : limit display to callouts with this function\n"
" -p name|addr : limit display to callouts functions with this"
" parameter\n"
" -T : display the callout table itself, instead of callouts\n"
" -L : display callout lists instead of callouts\n"
" -E : with -T or L, display empty data structures.\n"
" -i : traverse callouts by id hash instead of list hash\n"
" -F : walk free callout list (free list with -i) instead\n"
" -v : display more info for each item\n"
" -V : show details of each level of info as it is traversed\n"
" -A : show only addresses. Useful for pipelines.\n");
}
void
calloutid_help(void)
{
mdb_printf("calloutid: display callout by id.\n"
"Given an extended callout id, display the callout infomation.\n"
"options:\n"
" -d : do not dereference callout, just decode the id.\n"
" -v : verbose display more info about the callout\n");
}
/*ARGSUSED*/
int
{
long num_classes, i;
char class_name[PC_CLNMSZ];
mdb_warn("failed to find symbol sclass\n");
return (DCMD_ERR);
}
mdb_warn("failed to read sclass");
return (DCMD_ERR);
}
"INIT FCN", "CLASS FCN");
for (i = 0; i < num_classes; i++) {
}
return (DCMD_OK);
}
int
{
char buf[MAXPATHLEN];
return (DCMD_USAGE);
if (!(flags & DCMD_ADDRSPEC)) {
mdb_warn("expected explicit vnode_t address before ::\n");
return (DCMD_USAGE);
}
mdb_warn("failed to read rootdir");
return (DCMD_ERR);
}
return (DCMD_ERR);
if (*buf == '\0') {
mdb_printf("??\n");
return (DCMD_OK);
}
mdb_printf("\n");
return (DCMD_OK);
}
int
{
return (WALK_NEXT);
}
int
{
int status;
mdb_warn("couldn't read lock_descriptor_t at %p\n",
return (WALK_ERR);
}
return (WALK_ERR);
return (WALK_DONE);
return (status);
}
int
{
mdb_warn("failed to find symbol 'lock_graph'\n");
return (WALK_ERR);
}
return (WALK_NEXT);
}
typedef struct lg_walk_data {
void *data;
/*
* We can't use ::walk lock_descriptor directly, because the head of each graph
* is really a dummy lock. Rather than trying to dynamically determine if this
* is a dummy node or not, we just filter out the initial element of the
* list.
*/
static int
{
return (WALK_NEXT);
}
int
{
return (WALK_DONE);
return (WALK_ERR);
}
return (WALK_NEXT);
return (WALK_ERR);
}
return (WALK_ERR);
}
return (WALK_NEXT);
}
/*
* The space available for the path corresponding to the locked vnode depends
* on whether we are printing 32- or 64-bit addresses.
*/
#ifdef _LP64
#define LM_VNPATHLEN 20
#else
#define LM_VNPATHLEN 30
#endif
/*ARGSUSED*/
static int
{
char buf[LM_VNPATHLEN];
proc_t p;
mdb_printf("%-?p %2s %04x %6d %-16s %-?p ",
sizeof (buf));
return (WALK_NEXT);
}
/*ARGSUSED*/
int
{
if (DCMD_HDRSPEC(flags))
mdb_printf("%<u>%-?s %2s %4s %6s %-16s %-?s %s%</u>\n",
"ADDR", "TP", "FLAG", "PID", "COMM", "VNODE", "PATH");
}
/*ARGSUSED*/
int
{
struct seg s;
if (argc != 0)
return (DCMD_USAGE);
mdb_printf("%<u>%?s %?s %?s %?s %s%</u>\n",
"SEG", "BASE", "SIZE", "DATA", "OPS");
}
return (DCMD_ERR);
}
mdb_printf("%?p %?p %?lx %?p %a\n",
return (DCMD_OK);
}
/*ARGSUSED*/
static int
{
(*nres)++;
return (WALK_NEXT);
}
static int
{
struct segvn_data svn;
int nres = 0;
goto drive_on;
}
/*
* We've got an amp for this segment; walk through
* the amp, and determine mappings.
*/
char buf[29];
} else
mdb_printf(" [ anon ]");
}
mdb_printf("\n");
return (WALK_NEXT);
}
static int
{
struct segvn_data svn;
} else {
mdb_printf(" [ anon ]");
}
}
mdb_printf("\n");
return (WALK_NEXT);
}
/*ARGSUSED*/
int
{
if (!(flags & DCMD_ADDRSPEC))
return (DCMD_USAGE);
return (DCMD_USAGE);
return (DCMD_ERR);
}
else
if (quick) {
mdb_printf("VNODE\n");
} else {
}
return (DCMD_ERR);
}
return (DCMD_OK);
}
typedef struct anon_walk_data {
int aw_nlevone;
int aw_levone_ndx;
int aw_levtwo_ndx;
int
{
mdb_warn("anon walk doesn't support global walks\n");
return (WALK_ERR);
}
return (WALK_ERR);
}
return (WALK_ERR);
}
} else {
aw->aw_nlevone =
}
aw->aw_levone_ndx = 0;
aw->aw_levtwo_ndx = 0;
aw->aw_levone_ndx++;
mdb_warn("corrupt anon; couldn't"
"find ptr to lev two map");
goto out;
}
}
}
out:
return (0);
}
int
{
int status;
/*
* Once we've walked through level one, we're done.
*/
return (WALK_DONE);
aw->aw_levone_ndx++;
} else {
aw->aw_levtwo_ndx++;
aw->aw_levtwo_ndx = 0;
do {
aw->aw_levone_ndx++;
return (WALK_DONE);
sizeof (uintptr_t),
}
}
} else
goto again;
return (status);
}
void
{
}
/*ARGSUSED*/
int
{
}
return (WALK_NEXT);
}
/*ARGSUSED*/
int
{
return (WALK_ERR);
}
if (t == NULL)
return (WALK_NEXT);
}
/*ARGSUSED*/
int
{
return (DCMD_USAGE);
mdb_warn("can't proc walk");
return (DCMD_ERR);
}
return (DCMD_OK);
}
typedef struct datafmt {
char *hdr1;
char *hdr2;
char *dashes;
char *fmt;
} datafmt_t;
{ "cache ", "name ",
"-------------------------", "%-25s " },
{ " buf", " size", "------", "%6u " },
{ " buf", "in use", "------", "%6u " },
{ " buf", " total", "------", "%6u " },
{ " memory", " in use", "----------", "%9u%c " },
{ " alloc", " succeed", "---------", "%9u " },
{ "alloc", " fail", "-----", "%5u " },
};
{ "vmem ", "name ",
"-------------------------", "%-*s " },
{ " memory", " in use", "----------", "%9llu%c " },
{ " memory", " total", "-----------", "%10llu%c " },
{ " memory", " import", "----------", "%9llu%c " },
{ " alloc", " succeed", "---------", "%9llu " },
{ "alloc", " fail", "-----", "%5llu " },
};
/*ARGSUSED*/
static int
{
if (ccp->cc_prounds > 0)
return (WALK_NEXT);
}
/*ARGSUSED*/
static int
{
return (WALK_NEXT);
}
/*ARGSUSED*/
static int
{
return (WALK_NEXT);
}
typedef struct kmastat_vmem {
struct kmastat_vmem *kv_next;
int kv_meminuse;
int kv_alloc;
int kv_fail;
typedef struct kmastat_args {
static int
{
int magsize;
goto out;
}
out:
mdb_printf("\n");
return (WALK_NEXT);
}
static int
{
return (WALK_NEXT);
return (WALK_NEXT);
}
/*ARGSUSED*/
static int
{
int ident = 0;
ident = 0;
break;
}
}
mdb_printf("\n");
return (WALK_NEXT);
}
/*ARGSUSED*/
int
{
return (DCMD_USAGE);
mdb_printf("\n");
mdb_printf("\n");
mdb_printf("\n");
mdb_warn("can't walk 'kmem_cache'");
return (DCMD_ERR);
}
mdb_printf("\n");
mdb_warn("can't walk 'vmem'");
return (DCMD_ERR);
}
mdb_printf("\n");
mdb_printf("\n");
mdb_printf("\n");
mdb_printf("\n");
mdb_printf("\n");
mdb_warn("can't walk 'vmem'");
return (DCMD_ERR);
}
mdb_printf("\n");
return (DCMD_OK);
}
/*
* Our ::kgrep callback scans the entire kernel VA space (kas). kas is made
* up of a set of 'struct seg's. We could just scan each seg en masse, but
* unfortunately, a few of the segs are both large and sparse, so we could
* spend quite a bit of time scanning VAs which have no backing pages.
*
* So for the few very sparse segs, we skip the segment itself, and scan
* the allocated vmem_segs in the vmem arena which manages that part of kas.
* Currently, we do this for:
*
* SEG VMEM ARENA
* kvseg heap_arena
* kvseg32 heap32_arena
* kvseg_core heap_core_arena
*
* In addition, we skip the segkpm segment in its entirety, since it is very
* sparse, and contains no new kernel data.
*/
typedef struct kgrep_walk_data {
void *kg_cbdata;
static int
{
return (WALK_NEXT);
return (WALK_NEXT);
}
/*ARGSUSED*/
static int
{
/*
* skip large page heap address range - it is scanned by walking
* allocated vmem_segs in the heap_lp_arena
*/
return (WALK_NEXT);
}
/*ARGSUSED*/
static int
{
}
static int
{
return (WALK_NEXT);
return (WALK_ERR);
}
return (WALK_NEXT);
}
int
{
if (mdb_get_state() == MDB_STATE_RUNNING) {
mdb_warn("kgrep can only be run on a system "
"dump or under kmdb; see dumpadm(1M)\n");
return (DCMD_ERR);
}
mdb_warn("failed to locate 'kas' symbol\n");
return (DCMD_ERR);
}
mdb_warn("failed to locate 'kvseg' symbol\n");
return (DCMD_ERR);
}
mdb_warn("failed to locate 'kvseg32' symbol\n");
return (DCMD_ERR);
}
mdb_warn("failed to locate 'kvseg_core' symbol\n");
return (DCMD_ERR);
}
mdb_warn("failed to locate 'segkpm_ops' symbol\n");
return (DCMD_ERR);
}
mdb_warn("failed to read 'heap_lp_base'\n");
return (DCMD_ERR);
}
mdb_warn("failed to read 'heap_lp_end'\n");
return (DCMD_ERR);
}
mdb_warn("failed to walk kas segments");
return (DCMD_ERR);
}
return (DCMD_ERR);
}
return (DCMD_OK);
}
kgrep_subr_pagesize(void)
{
return (PAGESIZE);
}
typedef struct file_walk_data {
int fw_flistsz;
int fw_ndx;
int fw_nofiles;
int
{
proc_t p;
mdb_warn("file walk doesn't support global walks\n");
return (WALK_ERR);
}
return (WALK_ERR);
}
return (WALK_DONE);
}
mdb_warn("failed to read file array at %p",
return (WALK_ERR);
}
return (WALK_NEXT);
}
int
{
return (WALK_DONE);
goto again;
}
int
{
return (WALK_DONE);
else
}
void
{
}
int
{
mdb_warn("port walk doesn't support global walks\n");
return (WALK_ERR);
}
mdb_warn("couldn't walk 'file'");
return (WALK_ERR);
}
return (WALK_NEXT);
}
int
{
return (WALK_ERR);
}
return (WALK_NEXT);
return (WALK_ERR);
}
}
typedef struct portev_walk_data {
int
{
mdb_warn("portev walk doesn't support global walks\n");
return (WALK_ERR);
}
return (WALK_ERR);
}
return (WALK_ERR);
}
mdb_warn("input address (%p) does not point to an event port",
return (WALK_ERR);
}
return (WALK_DONE);
}
return (WALK_NEXT);
}
int
{
struct port_kevent ev;
return (WALK_DONE);
return (WALK_DONE);
}
}
void
{
}
typedef struct proc_walk_data {
int pw_depth;
int pw_max;
int
{
mdb_warn("failed to read 'practive'");
return (WALK_ERR);
}
}
mdb_warn("failed to read 'nproc'");
return (WALK_ERR);
}
return (WALK_NEXT);
}
int
{
int status;
return (WALK_DONE);
}
goto sib;
}
return (status);
mdb_warn("proc %p has invalid p_child %p; skipping\n",
goto sib;
}
mdb_warn("depth %d exceeds max depth; try again\n",
return (WALK_DONE);
}
return (WALK_NEXT);
}
sib:
/*
* We know that p0 has no siblings, and if another starting proc
* was given, we don't want to walk its siblings anyway.
*/
return (WALK_DONE);
mdb_warn("proc %p has invalid p_sibling %p; skipping\n",
}
return (WALK_NEXT);
}
return (WALK_DONE);
}
return (WALK_NEXT);
}
void
{
}
int
{
return (WALK_ERR);
}
return (WALK_NEXT);
}
int
{
int status;
return (WALK_DONE);
}
return (WALK_DONE);
return (status);
}
int
{
mdb_warn("failed to read 'proj0p'");
return (WALK_ERR);
}
}
return (WALK_NEXT);
}
int
{
int status;
return (WALK_DONE);
}
return (status);
return (WALK_DONE);
return (WALK_NEXT);
}
static int
{
wsp->walk_cbdata));
}
int
{
mdb_warn("seg walk must begin at struct as *\n");
return (WALK_ERR);
}
/*
* this is really just a wrapper to AVL tree walk
*/
return (avl_walk_init(wsp));
}
static int
cpu_walk_cmp(const void *l, const void *r)
{
return (-1);
return (1);
return (0);
}
typedef struct cpu_walk {
int cw_ndx;
} cpu_walk_t;
int
{
cpu_walk_t *cw;
int max_ncpus, i = 0;
mdb_warn("failed to read 'max_ncpus'");
return (WALK_ERR);
}
mdb_warn("failed to read 'panicstr'");
return (WALK_ERR);
}
mdb_warn("failed to find 'panic_cpu'");
return (WALK_ERR);
}
mdb_warn("failed to read 'panic_cpu'");
return (WALK_ERR);
}
}
/*
* Unfortunately, there is no platform-independent way to walk
* CPUs in ID order. We therefore loop through in cpu_next order,
* building an array of CPU pointers which will subsequently be
* sorted.
*/
mdb_warn("failed to read 'cpu_list'");
return (WALK_ERR);
}
do {
return (WALK_ERR);
}
} else {
}
return (WALK_NEXT);
}
int
{
return (WALK_DONE);
return (WALK_DONE);
}
}
typedef struct cpuinfo_data {
char cid_print_head;
char cid_print_thr;
char cid_print_ithr;
char cid_print_flags;
int
{
cpu_t c;
int id;
return (WALK_NEXT);
return (WALK_NEXT);
}
mdb_warn("CPU %p has id (%d) greater than NCPU (%d)\n",
return (WALK_NEXT);
}
mdb_warn("thread %p has pil (%d) greater than %d\n",
return (WALK_NEXT);
}
mdb_warn("CPU %d has multiple threads at pil %d (at least "
return (WALK_NEXT);
}
return (WALK_NEXT);
}
#define CPUINFO_IDWIDTH 3
#define CPUINFO_FLAGWIDTH 9
#ifdef _LP64
#if defined(__amd64)
#define CPUINFO_TWIDTH 16
#define CPUINFO_CPUWIDTH 16
#else
#define CPUINFO_CPUWIDTH 11
#define CPUINFO_TWIDTH 11
#endif
#else
#define CPUINFO_CPUWIDTH 8
#define CPUINFO_TWIDTH 8
#endif
#define CPUINFO_ITHRDELT 4
int
{
kthread_t t;
proc_t p;
char **flagbuf;
const char *flags[] = {
"RUNNING", "READY", "QUIESCED", "EXISTS",
"ENABLE", "OFFLINE", "POWEROFF", "FROZEN",
};
return (WALK_NEXT);
/*
* Set cid_cpu to -1 to indicate that we found a matching CPU.
*/
}
if (cid->cid_print_head) {
mdb_printf("%3s %-*s %3s %4s %4s %3s %4s %5s %-6s %-*s %s\n",
"PROC");
}
return (WALK_ERR);
}
mdb_printf("%3d %0*p %3x %4d %4d ",
} else {
}
if (cpu->cpu_last_swtch) {
return (WALK_ERR);
}
} else {
}
mdb_printf(" (idle)\n");
mdb_printf(" -\n");
else {
} else {
mdb_printf(" ?\n");
}
}
if (cid->cid_print_flags) {
int first = 1, i, j, k;
char *s;
continue;
if (first) {
flagbuf[nflaglines++] = s;
}
for (k = strlen(s); k < CPUINFO_THRDELT; k++)
s[k] = ' ';
s[k] = '\0';
flagbuf[nflaglines++] = s;
first = 0;
}
}
if (cid->cid_print_ithr) {
for (i = NINTR - 1; i >= 0; i--) {
continue;
if (!found_one) {
CPUINFO_ITHRDELT, "");
mdb_printf("%c%*s+--> %3s %s\n",
"", "PIL", "THREAD");
}
mdb_warn("failed to read kthread_t at %p",
iaddr);
return (WALK_ERR);
}
mdb_printf("%c%*s %3d %0*p\n",
}
if (mdb_vread(&t, sizeof (t),
mdb_warn("failed to read kthread_t at %p",
pinned);
return (WALK_ERR);
}
if (mdb_vread(&p, sizeof (p),
mdb_warn("failed to read proc_t at %p",
t.t_procp);
return (WALK_ERR);
}
mdb_printf("%c%*s %3s %0*p %s\n",
}
}
return (WALK_ERR);
}
mdb_printf("|\n");
for (i = npri - 1; i >= 0; i--) {
mdb_warn("failed to read kthread_t "
"at %p", taddr);
return (WALK_ERR);
}
if (mdb_vread(&p, sizeof (p),
mdb_warn("failed to read proc_t at %p",
t.t_procp);
return (WALK_ERR);
}
}
}
}
while (flagline < nflaglines)
if (cid->cid_print_head)
mdb_printf("\n");
return (rval);
}
int
{
if (flags & DCMD_ADDRSPEC)
return (DCMD_USAGE);
if (verbose) {
}
if (cid.cid_print_ithr) {
int i;
for (i = 0; i < NCPU; i++)
&cid) == -1) {
mdb_warn("couldn't walk thread");
return (DCMD_ERR);
}
}
mdb_warn("failed to find panic_lbolt");
return (DCMD_ERR);
}
mdb_warn("failed to read panic_lbolt");
return (DCMD_ERR);
}
if (lbolt == 0) {
mdb_warn("failed to find lbolt");
return (DCMD_ERR);
}
}
mdb_warn("can't walk cpus");
return (DCMD_ERR);
}
/*
* We didn't find this CPU when we walked through the CPUs
* (i.e. the address specified doesn't show up in the "cpu"
* walk). However, the specified address may still correspond
* to a valid cpu_t (for example, if the specified address is
* the actual panicking cpu_t and not the cached panic_cpu).
* Point is: even if we didn't find it, we still want to try
* to print the specified address as a cpu_t.
*/
mdb_warn("%p is neither a valid CPU ID nor a "
return (DCMD_ERR);
}
}
return (DCMD_OK);
}
/*ARGSUSED*/
int
{
int i;
if (!(flags & DCMD_ADDRSPEC))
return (DCMD_USAGE);
return (DCMD_OK);
}
/*
* Grumble, grumble.
*/
int
{
long smd_hashmsk;
int hash;
if (!(flags & DCMD_ADDRSPEC))
return (DCMD_USAGE);
mdb_warn("failed to read smd_hashmsk");
return (DCMD_ERR);
}
mdb_warn("failed to read smd_hash");
return (DCMD_ERR);
}
mdb_warn("failed to read smd_hash");
return (DCMD_ERR);
}
mdb_warn("failed to read segkmap");
return (DCMD_ERR);
}
return (DCMD_ERR);
}
if (argc != 0) {
else
}
mdb_warn("couldn't read smap at %p",
return (DCMD_ERR);
}
do {
return (DCMD_ERR);
}
mdb_printf("vnode %p, offs %p is smap %p, vaddr %p\n",
return (DCMD_OK);
}
return (DCMD_OK);
}
/*ARGSUSED*/
int
{
struct segmap_data sd;
if (!(flags & DCMD_ADDRSPEC))
return (DCMD_USAGE);
mdb_warn("failed to read segkmap");
return (DCMD_ERR);
}
return (DCMD_ERR);
}
return (DCMD_ERR);
}
return (DCMD_OK);
}
int
{
return (WALK_NEXT);
}
/*ARGSUSED*/
int
{
return (DCMD_USAGE);
mdb_warn("failed to walk proc");
return (DCMD_ERR);
}
return (DCMD_OK);
}
/*ARGSUSED*/
int
{
int ident = 0;
}
mdb_inc_indent(ident);
mdb_dec_indent(ident);
return (WALK_NEXT);
}
void
{
proc_t p;
return;
}
}
/*ARGSUSED*/
int
{
if (!(flags & DCMD_ADDRSPEC))
else
mdb_warn("couldn't walk 'proc'");
return (DCMD_ERR);
}
return (DCMD_OK);
}
/*ARGSUSED*/
static int
{
int fdnum;
proc_t p;
if ((flags & DCMD_ADDRSPEC) == 0) {
mdb_warn("fd doesn't give global information\n");
return (DCMD_ERR);
}
if (argc != 1)
return (DCMD_USAGE);
else
return (DCMD_ERR);
}
mdb_warn("process %p only has %d files open.\n",
return (DCMD_ERR);
}
mdb_warn("couldn't read uf_entry_t at %p",
return (DCMD_ERR);
}
return (DCMD_OK);
}
/*ARGSUSED*/
static int
{
if (argc != 0)
return (DCMD_USAGE);
return (DCMD_ERR);
}
return (DCMD_OK);
}
static char *sysfile_cmd[] = {
"exclude:",
"include:",
"forceload:",
"rootdev:",
"rootfs:",
"swapdev:",
"swapfs:",
"moddir:",
"set",
"unknown",
};
/*ARGSUSED*/
static int
{
return (WALK_DONE);
}
return (WALK_NEXT);
}
/*ARGSUSED*/
static int
{
char var[256];
char modname[256];
char val[256];
char strval[256];
void *straddr;
mdb_warn("failed to read sysparam_hd");
return (DCMD_ERR);
}
mdb_warn("failed to read mod_sysfile_arena");
return (DCMD_ERR);
}
var[0] = '\0';
val[0] = '\0';
modname[0] = '\0';
return (DCMD_ERR);
}
return (DCMD_ERR);
}
return (DCMD_ERR);
}
/*
* Is this an int or a string? We determine this
* by checking whether straddr is contained in
* mod_sysfile_arena. If so, the walker will set
* straddr to NULL.
*/
mdb_pwalk("vmem_seg",
(uintptr_t)mod_sysfile_arena) == 0 &&
strval);
} else {
}
}
}
return (DCMD_OK);
}
/*
* Dump a taskq_ent_t given its address.
*/
/*ARGSUSED*/
int
{
if (!(flags & DCMD_ADDRSPEC)) {
mdb_warn("expected explicit taskq_ent_t address before ::\n");
return (DCMD_USAGE);
}
return (DCMD_ERR);
}
if (DCMD_HDRSPEC(flags)) {
mdb_printf("%<u>%-?s %-?s %-s%</u>\n",
"ENTRY", "ARG", "FUNCTION");
}
}
return (DCMD_OK);
}
/*
* Given the address of the (taskq_t) task queue head, walk the queue listing
* the address of every taskq_ent_t.
*/
int
{
mdb_warn("start address required\n");
return (WALK_ERR);
}
/*
* Save the address of the list head entry. This terminates the list.
*/
/*
* Read in taskq head, set walk_addr to point to first taskq_ent_t.
*/
-1) {
mdb_warn("failed to read taskq list head at %p",
}
/*
* Check for null list (next=head)
*/
return (WALK_DONE);
}
return (WALK_NEXT);
}
int
{
int status;
-1) {
return (DCMD_ERR);
}
wsp->walk_cbdata);
/* Check if we're at the last element (next=head) */
return (WALK_DONE);
}
return (status);
}
int
{
return (WALK_DONE);
} else
return (WALK_NEXT);
}
/*ARGSUSED*/
int
{
if (argc != 1)
return (DCMD_USAGE);
mdb_warn("failed to walk thread");
return (DCMD_ERR);
}
return (DCMD_OK);
}
static int
{
mdb_warn("failed to read errorq_list");
return (WALK_ERR);
}
return (WALK_NEXT);
}
static int
{
return (WALK_DONE);
return (WALK_ERR);
}
}
typedef struct eqd_walk_data {
void *eqd_buf;
/*
* In order to walk the list of pending error queue elements, we push the
* addresses of the corresponding data buffers in to the eqd_stack array.
* The error lists are in reverse chronological order when iterating using
* eqe_prev, so we then pop things off the top in eqd_walk_step so that the
* walker client gets addresses in order from oldest error to newest error.
*/
static void
{
break;
}
mdb_warn("errorq is overfull -- more than %lu "
break;
}
}
}
static int
{
ulong_t i;
return (WALK_ERR);
}
return (WALK_ERR);
}
/*
* The newest elements in the queue are on the pending list, so we
* push those on to our stack first.
*/
/*
* If eq_ptail is set, it may point to a subset of the errors on the
* pending list in the event a casptr() failed; if ptail's data is
* already in our stack, NULL out eq_ptail and ignore it.
*/
break;
}
}
}
/*
* If eq_phead is set, it has the processing list in order from oldest
* to newest. Use this to recompute eq_ptail as best we can and then
* we nicely fall into eqd_push_list() of eq_ptail below.
*/
/*
* The oldest elements in the queue are on the processing list, subject
* to machinations in the if-clauses above. Push any such elements.
*/
return (WALK_NEXT);
}
static int
{
return (WALK_DONE);
return (WALK_ERR);
}
}
static void
{
}
static int
{
int i;
if (!(flags & DCMD_ADDRSPEC)) {
mdb_warn("can't walk 'errorq'");
return (DCMD_ERR);
}
return (DCMD_OK);
}
argc -= i;
argv += i;
if (argc != 0)
return (DCMD_USAGE);
mdb_printf("%<u>%-11s %-16s %1s %1s %1s ",
"ADDR", "NAME", "S", "V", "N");
if (!opt_v) {
mdb_printf("%7s %7s %7s%</u>\n",
"ACCEPT", "DROP", "LOG");
} else {
mdb_printf("%5s %6s %6s %3s %16s%</u>\n",
"KSTAT", "QLEN", "SIZE", "IPL", "FUNC");
}
}
return (DCMD_ERR);
}
if (!opt_v) {
mdb_printf("%7llu %7llu %7llu\n",
} else {
mdb_printf("%5s %6lu %6lu %3u %a\n",
mdb_printf("%38s\n%41s"
"%12s %llu\n"
"%53s %llu\n"
"%53s %llu\n"
"%53s %llu\n"
"%53s %llu\n"
"%53s %llu\n"
"%53s %llu\n"
"%53s %llu\n\n",
"|", "+-> ",
}
return (DCMD_OK);
}
/*ARGSUSED*/
static int
{
void *buf;
int i, n;
if (!mdb_prop_postmortem) {
mdb_warn("panicinfo can only be run on a system "
"dump; see dumpadm(1M)\n");
return (DCMD_ERR);
}
return (DCMD_USAGE);
mdb_warn("failed to read 'panic_cpu'");
else
mdb_warn("failed to read 'panic_thread'");
else
mdb_warn("failed to read 'panicbuf'");
return (DCMD_ERR);
}
sizeof (panic_nv_t))) / sizeof (panic_nv_t);
for (i = 0; i < n; i++)
mdb_printf("%16s %?llx\n",
return (DCMD_OK);
}
static const mdb_dcmd_t dcmds[] = {
/* from genunix.c */
{ "binding_hash_entry", ":", "print driver names hash table entry",
{ "callout", "?[-r|n] [-s|l] [-xhB] [-t | -ab nsec [-dkD]]"
" [-C addr | -S seqid] [-f name|addr] [-p name| addr] [-T|L [-E]]"
" [-FivVA]",
{ "calloutid", "[-d|v] xid", "print callout by extended id",
{ "did2thread", "? kt_did", "find kernel thread for this id",
did2thread },
{ "pgrep", "[-x] [-n | -o] pattern",
"pattern match against all processes", pgrep },
{ "sysevent", "?[-sv]", "print sysevent pending or sent queue",
sysevent},
{ "sysevent_channel", "?", "print sysevent channel database",
{ "sysevent_class_list", ":", "print sysevent class list",
{ "sysevent_subclass_list", ":",
"print sysevent subclass list", sysevent_subclass_list},
{ "whereopen", ":", "given a vnode, dumps procs which have it open",
whereopen },
/* from zone.c */
{ "zsd", ":[-v] [zsd_key]", "display zone-specific-data entries for "
"selected zones", zsd },
/* from bio.c */
/* from contract.c */
/* from cpupart.c */
/* from cyclic.c */
/* from devinfo.c */
{ "devbindings", "?[-qs] [device-name | major-num]",
"print devinfo nodes bound to device-name or major-num",
devinfo_help },
{ "devinfo_audit", ":[-v]", "devinfo configuration audit record",
{ "devinfo_audit_log", "?[-v]", "system wide devinfo configuration log",
{ "devinfo_audit_node", ":[-v]", "devinfo node configuration history",
{ "devinfo2driver", ":", "find driver name for this devinfo node",
{ "dev2major", "?<dev_t>", "convert dev_t to a major number",
dev2major },
{ "dev2minor", "?<dev_t>", "convert dev_t to a minor number",
dev2minor },
{ "devt", "?<dev_t>", "display a dev_t's major and minor numbers",
devt },
{ "major2name", "?<major-num>", "convert major number to dev name",
major2name },
{ "minornodes", ":", "given a devinfo node, print its minor nodes",
minornodes },
{ "modctl2devinfo", ":", "given a modctl, list its devinfos",
{ "name2major", "<dev-name>", "convert dev name to major number",
name2major },
{ "softstate", ":<instance>", "retrieve soft-state pointer",
softstate },
{ "devinfo_fm", ":", "devinfo fault managment configuration",
devinfo_fm },
{ "devinfo_fmce", ":", "devinfo fault managment cache entry",
/* from fm.c */
{ "ereport", "[-v]", "print ereports logged in dump",
ereport },
/* from findstack.c */
{ "stacks", "?[-afiv] [-c func] [-C func] [-m module] [-M module] "
"[-s sobj | -S sobj] [-t tstate | -T tstate]",
"print unique kernel thread stacks",
stacks, stacks_help },
/* from irm.c */
irmreqs_dcmd },
kgrep_help },
/* from kmem.c */
{ "allocdby", ":", "given a thread, print its allocated buffers",
allocdby },
{ "bufctl", ":[-vh] [-a addr] [-c caller] [-e earliest] [-l latest] "
{ "kmalog", "?[ fail | slab ]",
"display kmem transaction log and stack traces", kmalog },
{ "kmastat", "[-kmg]", "kernel memory allocator stats",
kmastat },
{ "kmausers", "?[-ef] [cache ...]", "current medium and large users "
{ "kmem_cache", "?[-n name]",
{ "kmem_slabs", "?[-v] [-n cache] [-N cache] [-b maxbins] "
"[-B minbinsize]", "display slab usage per kmem cache",
{ "kmem_verify", "?", "check integrity of kmem-managed memory",
kmem_verify },
{ "vmem_seg", ":[-sv] [-c caller] [-e earliest] [-l latest] "
"[-m minsize] [-M maxsize] [-t thread] [-T type]",
whatis_help },
{ "whatthread", ":[-v]", "print threads whose stack contains the "
"given address", whatthread },
/* from ldi.c */
{ "ldi_handle", "?[-i]", "display a layered driver handle",
/* from leaky.c + leaky_subr.c */
{ "findleaks", FINDLEAKS_USAGE,
"search for potential kernel memory leaks", findleaks,
/* from lgrp.c */
/* from log.c */
/* from memory.c */
/* from mmd.c */
{ "multidata", ":[-sv]", "display a summarized multidata_t",
multidata },
{ "pattbl", ":", "display a summarized multidata attribute table",
pattbl },
{ "pattr2multidata", ":", "print multidata pointer from pattr_t",
{ "pdesc2slab", ":", "print pdesc slab pointer from pdesc_t",
pdesc2slab },
{ "slab2multidata", ":", "print multidata pointer from pdesc_slab_t",
/* from modhash.c */
{ "modhash", "?[-ceht] [-k key] [-v val] [-i index]",
"display information about one or all mod_hash structures",
modhash, modhash_help },
{ "modent", ":[-k | -v | -t type]",
"display information about a mod_hash_entry", modent,
modent_help },
/* from net.c */
{ "mi", ":[-p] [-d | -m]", "filter and display MI object or payload",
mi },
{ "netstat", "[-arv] [-f inet | inet6 | unix] [-P tcp | udp | icmp]",
"show network statistics", netstat },
{ "sonode", "?[-f inet | inet6 | unix | #] "
"[-t stream | dgram | raw | #] [-p #]",
"filter and display sonode", sonode },
/* from netstack.c */
/* from nvpair.c */
nvpair_print },
print_nvlist },
/* from pg.c */
/* from group.c */
/* from log.c */
/* from rctl.c */
{ "rctl_dict", "?", "print systemwide default rctl definitions",
rctl_dict },
{ "rctl_list", ":[handle]", "print rctls for the given proc",
rctl_list },
{ "rctl", ":[handle]", "print a rctl_t, only if it matches the handle",
rctl },
{ "rctl_validate", ":[-v] [-n #]", "test resource control value "
"sequence", rctl_validate },
/* from sobj.c */
mutex_help },
/* from stream.c */
{ "mblk", ":[-q|v] [-f|F flag] [-t|T type] [-l|L|B len] [-d dbaddr]",
{ "mblk2dblk", ":", "convert mblk_t address to dblk_t address",
mblk2dblk },
{ "queue", ":[-q|v] [-m mod] [-f flag] [-F flag] [-s syncq_addr]",
{ "stdata", ":[-q|v] [-f flag] [-F flag]",
{ "syncq", ":[-q|v] [-f flag] [-F flag] [-t type] [-T type]",
/* from thread.c */
thread_help },
{ "threadlist", "?[-t] [-v [count]]",
"display threads and associated C stack traces", threadlist,
/* from tsd.c */
/*
* typegraph does not work under kmdb, as it requires too much memory
* for its internal data structures.
*/
#ifndef _KMDB
/* from typegraph.c */
{ "findfalse", "?[-v]", "find potentially falsely shared structures",
findfalse },
#endif
/* from vfs.c */
pfiles_help },
/* from mdi.c */
"and detailed pi_prop list", mdipi },
mdiprops },
"list all paths", mdiphci },
"all phcis", mdivhci },
"client links", mdiclient_paths },
"phci links", mdiphci_paths },
mdiphcis },
{ NULL }
};
static const mdb_walker_t walkers[] = {
/* from genunix.c */
{ "anon", "given an amp, list of anon structures",
{ "callouts_bytime", "walk callouts by list chain (expiration time)",
(void *)CALLOUT_WALK_BYLIST },
{ "callouts_byid", "walk callouts by id hash chain",
(void *)CALLOUT_WALK_BYID },
{ "ereportq_dump", "walk list of ereports in dump error queue",
{ "ereportq_pend", "walk list of ereports in pending error queue",
{ "errorq", "walk list of system error queues",
{ "errorq_data", "walk pending error queue data buffers",
{ "allfile", "given a proc pointer, list all file pointers",
{ "file", "given a proc pointer, list of open file pointers",
{ "lock_descriptor", "walk lock_descriptor_t structures",
{ "lock_graph", "walk lock graph",
{ "port", "given a proc pointer, list of created event ports",
{ "portev", "given a port pointer, list of events in the queue",
{ "proc", "list of active proc_t structures",
{ "projects", "walk a list of kernel projects",
{ "seg", "given an as, list of segments",
{ "sysevent_pend", "walk sysevent pending queue",
{ "sysevent_channel", "walk sysevent channel subscriptions",
{ "sysevent_class_list", "walk sysevent subscription's class list",
{ "sysevent_subclass_list",
"walk sysevent subscription's subclass list",
{ "task", "given a task pointer, walk its processes",
{ "taskq_entry", "given a taskq_t*, list all taskq_ent_t in the list",
/* from avl.c */
/* from zone.c */
{ "zone", "walk a list of kernel zones",
{ "zsd", "walk list of zsd entries for a zone",
/* from bio.c */
{ "buf", "walk the bio buf hash",
/* from contract.c */
{ "contract", "walk all contracts, or those of the specified type",
{ "ct_event", "walk events on a contract event queue",
{ "ct_listener", "walk contract event queue listeners",
/* from cpupart.c */
{ "cpupart_cpulist", "given an cpupart_t, walk cpus in partition",
NULL },
{ "cpupart_walk", "walk the set of cpu partitions",
/* from ctxop.c */
{ "ctxop", "walk list of context ops on a thread",
/* from cyclic.c */
{ "cyccpu", "walk per-CPU cyc_cpu structures",
{ "cycomni", "for an omnipresent cyclic, walk cyc_omni_cpu list",
{ "cyctrace", "walk cyclic trace buffer",
/* from devinfo.c */
{ "binding_hash", "walk all entries in binding hash table",
{ "devinfo", "walk devinfo tree or subtree",
{ "devinfo_audit_log", "walk devinfo audit system-wide log",
{ "devinfo_audit_node", "walk per-devinfo audit history",
{ "devinfo_children", "walk children of devinfo node",
{ "devinfo_parents", "walk ancestors of devinfo node",
{ "devinfo_siblings", "walk siblings of devinfo node",
{ "devi_next", "walk devinfo list",
{ "devnames", "walk devnames array",
{ "minornode", "given a devinfo node, walk minor nodes",
{ "softstate",
"given an i_ddi_soft_state*, list all in-use driver stateps",
{ "softstate_all",
"given an i_ddi_soft_state*, list all driver stateps",
{ "devinfo_fmc",
"walk a fault management handle cache active list",
/* from irm.c */
{ "irmpools", "walk global list of interrupt pools",
{ "irmreqs", "walk list of interrupt requests in an interrupt pool",
/* from kmem.c */
{ "allocdby", "given a thread, walk its allocated bufctls",
{ "bufctl", "walk a kmem cache's bufctls",
{ "bufctl_history", "walk the available history of a bufctl",
{ "freedby", "given a thread, walk its freed bufctls",
{ "freectl", "walk a kmem cache's free bufctls",
{ "freectl_constructed", "walk a kmem cache's constructed free bufctls",
{ "freemem", "walk a kmem cache's free memory",
{ "freemem_constructed", "walk a kmem cache's constructed free memory",
{ "kmem", "walk a kmem cache",
{ "kmem_cpu_cache", "given a kmem cache, walk its per-CPU caches",
{ "kmem_hash", "given a kmem cache, walk its allocated hash table",
{ "kmem_log", "walk the kmem transaction log",
{ "kmem_slab", "given a kmem cache, walk its slabs",
{ "kmem_slab_partial",
"given a kmem cache, walk its partially allocated slabs (min 1)",
{ "vmem", "walk vmem structures in pre-fix, depth-first order",
{ "vmem_alloc", "given a vmem_t, walk its allocated vmem_segs",
{ "vmem_free", "given a vmem_t, walk its free vmem_segs",
{ "vmem_postfix", "walk vmem structures in post-fix, depth-first order",
{ "vmem_seg", "given a vmem_t, walk all of its vmem_segs",
{ "vmem_span", "given a vmem_t, walk its spanning vmem_segs",
/* from ldi.c */
{ "ldi_handle", "walk the layered driver handle hash",
{ "ldi_ident", "walk the layered driver identifier hash",
/* from leaky.c + leaky_subr.c */
{ "leak", "given a leaked bufctl or vmem_seg, find leaks w/ same "
"stack trace",
{ "leakbuf", "given a leaked bufctl or vmem_seg, walk buffers for "
"leaks w/ same stack trace",
/* from lgrp.c */
{ "lgrp_cpulist", "walk CPUs in a given lgroup",
{ "lgrptbl", "walk lgroup table",
{ "lgrp_parents", "walk up lgroup lineage from given lgroup",
{ "lgrp_rsrc_mem", "walk lgroup memory resources of given lgroup",
{ "lgrp_rsrc_cpu", "walk lgroup CPU resources of given lgroup",
/* from group.c */
{ "group", "walk all elements of a group",
/* from list.c */
/* from memory.c */
{ "page", "walk all pages, or those from the specified vnode",
{ "allpages", "walk all pages, including free pages",
{ "memlist", "walk specified memlist",
{ "swapinfo", "walk swapinfo structures",
/* from mmd.c */
{ "pdesc", "walk pdesc_t structures",
{ "pdesc_slab", "walk pdesc_slab_t structures",
/* from modhash.c */
{ "modent", "walk list of entries in a given mod_hash",
{ "modchain", "walk list of entries in a given mod_hash_entry",
/* from net.c */
{ "ar", "walk ar_t structures using MI for all stacks",
{ "icmp", "walk ICMP control structures using MI for all stacks",
&mi_icmp_arg },
{ "mi", "given a MI_O, walk the MI",
{ "sonode", "given a sonode, walk its children",
{ "ar_stacks", "walk all the ar_stack_t",
{ "icmp_stacks", "walk all the icmp_stack_t",
{ "tcp_stacks", "walk all the tcp_stack_t",
{ "udp_stacks", "walk all the udp_stack_t",
/* from nvpair.c */
/* from rctl.c */
{ "rctl_dict_list", "walk all rctl_dict_entry_t's from rctl_lists",
{ "rctl_val", "given a rctl_t, walk all rctl_val entries associated",
/* from sobj.c */
{ "blocked", "walk threads blocked on a given sobj",
{ "wchan", "given a wchan, list of blocked threads",
/* from stream.c */
{ "b_cont", "walk mblk_t list using b_cont",
{ "b_next", "walk mblk_t list using b_next",
{ "qlink", "walk queue_t list using q_link",
{ "qnext", "walk queue_t list using q_next",
{ "strftblk", "given a dblk_t, walk STREAMS flow trace event list",
{ "readq", "walk read queue side of stdata",
{ "writeq", "walk write queue side of stdata",
/* from thread.c */
{ "deathrow", "walk threads on both lwp_ and thread_deathrow",
{ "cpu_dispq", "given a cpu_t, walk threads in dispatcher queues",
{ "cpupart_dispq",
"given a cpupart_t, walk threads in dispatcher queues",
{ "lwp_deathrow", "walk lwp_deathrow",
{ "thread", "global or per-process kthread_t structures",
{ "thread_deathrow", "walk threads on thread_deathrow",
/* from tsd.c */
{ "tsd", "walk list of thread-specific data",
/* from tsol.c */
{ "tnrh", "walk remote host cache structures",
{ "tnrhtp", "walk remote host template structures",
/*
* typegraph does not work under kmdb, as it requires too much memory
* for its internal data structures.
*/
#ifndef _KMDB
/* from typegraph.c */
{ "typeconflict", "walk buffers with conflicting type inferences",
{ "typeunknown", "walk buffers with unknown types",
#endif
/* from vfs.c */
{ "vfs", "walk file system list",
/* from mdi.c */
{ "mdipi_client_list", "Walker for mdi_pathinfo pi_client_link",
{ "mdipi_phci_list", "Walker for mdi_pathinfo pi_phci_link",
{ "mdiphci_list", "Walker for mdi_phci ph_next link",
/* from netstack.c */
{ "netstack", "walk a list of kernel netstacks",
{ NULL }
};
/*ARGSUSED*/
static void
genunix_statechange_cb(void *ignored)
{
/*
* Force ::findleaks and ::stacks to let go any cached state.
*/
leaky_cleanup(1);
stacks_cleanup(1);
kmem_statechange(); /* notify kmem */
}
const mdb_modinfo_t *
_mdb_init(void)
{
kmem_init();
(void) mdb_callback_add(MDB_CALLBACK_STCHG,
return (&modinfo);
}
void
_mdb_fini(void)
{
leaky_cleanup(1);
stacks_cleanup(1);
}