sobj.c revision 346799e8230991f56d5fd66fb1b895ed057feedc
/*
* 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_modapi.h>
#include <sys/rwlock_impl.h>
#include <sys/turnstile.h>
#include <sys/mutex_impl.h>
#include <stdio.h>
struct sobj_type_info {
int sobj_type;
const char *sobj_name;
const char *sobj_ops_name;
} sobj_types[] = {
};
void
{
int idx;
return;
}
return;
}
}
}
void
{
if (addr == 0) {
return;
}
return;
}
}
int
{
int idx;
&sym) == -1) {
mdb_warn("unable to find symbol \"%s\"",
return (-1);
}
return (0);
}
}
return (-1);
}
void
sobj_type_walk(void (*cbfunc)(int, const char *, const char *, void *),
void *cbarg)
{
int idx;
cbarg);
}
}
typedef struct wchan_walk_data {
int ww_seen_size;
int ww_seen_ndx;
int ww_sleepq_ndx;
int
{
mdb_warn("failed to read sleepq");
return (WALK_ERR);
}
mdb_warn("failed to read nthread");
return (WALK_ERR);
}
} else {
}
return (WALK_NEXT);
}
int
{
uintptr_t t;
int i;
/*
* Get the address of the first thread on the next sleepq in the
* sleepq hash. If ww_compare is set, ww_sleepq_ndx is already
* set to the appropriate sleepq index for the desired cv.
*/
return (WALK_DONE);
/*
* If we were looking for a specific cv and we're at the end
* of its sleepq, we're done walking.
*/
return (WALK_DONE);
}
/*
* Read in the thread. If it's t_wchan pointer is NULL, the thread has
* woken up since we took a snapshot of the sleepq (i.e. we are probably
* being applied to a live system); we can't believe the t_link pointer
* anymore either, so just skip to the next sleepq index.
*/
mdb_warn("failed to read thread at %p", t);
return (WALK_ERR);
}
goto again;
}
/*
* Set ww_thr to the address of the next thread in the sleepq list.
*/
/*
* If we're walking a specific cv, invoke the callback if we've
* found a match, or loop back to the top and read the next thread.
*/
return (WALK_DONE);
goto again;
}
/*
* If we're walking all cvs, seen if we've already encountered this one
* on the current sleepq. If we have, skip to the next thread.
*/
for (i = 0; i < ww->ww_seen_ndx; i++) {
goto again;
}
/*
* If we're not at the end of a sleepq, save t_wchan; otherwise reset
* the seen index so our array is empty at the start of the next sleepq.
* If we hit seen_size this is a live kernel and nthread is now larger,
* cope by replacing the final element in our memory.
*/
else
} else
ww->ww_seen_ndx = 0;
}
void
{
}
struct wcdata {
int nwaiters;
};
/*ARGSUSED*/
static int
{
(uintptr_t)t->t_sobj_ops);
}
return (WALK_NEXT);
}
static int
{
proc_t p;
if (*first) {
*first = 0;
} else {
}
return (WALK_NEXT);
}
/*ARGSUSED*/
static int
{
int first = 1;
return (WALK_NEXT);
}
mdb_printf("\n");
}
return (WALK_NEXT);
}
int
{
return (DCMD_USAGE);
if (v == TRUE) {
mdb_printf("%-?s %-4s %8s %-?s %s\n",
"ADDR", "TYPE", "NWAITERS", "THREAD", "PROC");
} else
if (flags & DCMD_ADDRSPEC) {
return (DCMD_ERR);
mdb_warn("failed to walk wchans");
return (DCMD_ERR);
}
return (DCMD_OK);
}
int
{
mdb_warn("must specify a sobj * for blocked walk");
return (WALK_ERR);
}
mdb_warn("couldn't walk 'thread'");
return (WALK_ERR);
}
return (WALK_NEXT);
}
int
{
return (WALK_ERR);
}
return (WALK_NEXT);
}
typedef struct rwlock_block {
struct rwlock_block *rw_next;
int rw_qnum;
static int
{
int state, i;
return (WALK_ERR);
}
for (i = 0; i < TS_NUM_Q; i++) {
break;
}
if (i == TS_NUM_Q) {
state == MDB_STATE_STOPPED) {
/*
* This shouldn't happen post-mortem or under kmdb;
* the blocked walk returned a thread which wasn't
* actually blocked on its turnstile. This may happen
* in-situ if the thread wakes up during the ::rwlock.
*/
mdb_warn("thread %p isn't blocked on ts %p\n",
return (WALK_ERR);
}
return (WALK_NEXT);
}
return (WALK_NEXT);
}
/*
* > rwd_rwlock::rwlock
* 7835dee8 READERS=1 B011 30004393d20 (W)
* ||
* WRITE_WANTED -------+|
* HAS_WAITERS --------+
*
* |--ADDR_WIDTH--| |--OWNR_WIDTH--|
* |--LBL_OFFSET--||-LBL_WIDTH|
* |--------------LONG-------------|
* |------------WAITER_OFFSET------------|
*/
#ifdef _LP64
#define RW_ADDR_WIDTH 16
#define RW_OWNR_WIDTH 16
#else
#define RW_ADDR_WIDTH 8
#define RW_OWNR_WIDTH 11
#endif
#define RW_LBL_WIDTH 12
/* Access rwlock bits */
/* Print a waiter (if any) and a newline */
#define RW_NEWLINE \
} \
mdb_printf("\n");
/*ARGSUSED*/
int
{
return (DCMD_USAGE);
return (DCMD_ERR);
}
return (WALK_ERR);
}
else {
char c[20];
}
mdb_printf(" B%c%c%c",
"DESTROYED");
goto no_zero;
}
if (!RW_BIT_SET(2))
goto no_two;
if (!RW_BIT_SET(1))
goto no_one;
if (!RW_BIT_SET(0))
goto no_zero;
"HAS_WAITERS");
}
return (DCMD_OK);
}
int
{
if (!(flags & DCMD_ADDRSPEC)) {
return (DCMD_USAGE);
}
return (DCMD_USAGE);
}
return (DCMD_ERR);
}
if (DCMD_HDRSPEC(flags)) {
mdb_printf("%<u>%?s %5s %?s %6s %6s %7s%</u>\n",
"ADDR", "TYPE", "HELD", "MINSPL", "OLDSPL", "WAITERS");
}
if (MUTEX_TYPE_SPIN(&lock)) {
mdb_warn("%a: invalid spin lock "
"(-f to dump anyway)\n", addr);
return (DCMD_ERR);
}
mdb_printf("%0?p %5s %?s %6d %6d %7s\n",
"-");
} else {
mdb_printf("%0?p %5s %?s %6d %6s %7s\n",
}
} else {
mdb_warn("%a: invalid adaptive mutex "
"(-f to dump anyway)\n", addr);
return (DCMD_ERR);
}
mdb_printf("%0?p %5s %?p %6s %6s %7s\n",
} else {
mdb_printf("%0?p %5s %?s %6s %6s %7s\n",
}
}
return (DCMD_OK);
}
void
mutex_help(void)
{
mdb_printf("Options:\n"
" -f force printing even if the data seems to be"
" inconsistent\n");
}
int
{
turnstile_t t;
if (argc != 0)
return (DCMD_USAGE);
if (!(flags & DCMD_ADDRSPEC)) {
== -1) {
mdb_warn("can't walk turnstiles");
return (DCMD_ERR);
}
return (DCMD_OK);
}
if (DCMD_HDRSPEC(flags))
mdb_printf("%<u>%?s %?s %5s %4s %?s %?s%</u>\n",
"ADDR", "SOBJ", "WTRS", "EPRI", "ITOR", "PRIOINV");
return (DCMD_ERR);
}
mdb_printf("%0?p %?p %5d %4d %?p %?p\n",
t.ts_inheritor, t.ts_prioinv);
return (DCMD_OK);
}
/*
* Macros and structure definition copied from turnstile.c.
* This is unfortunate, but half the macros we need aren't usable from
* within mdb anyway.
*/
#define TURNSTILE_SOBJ_HASH(sobj) \
typedef struct turnstile_chain {
/*
* Given the address of a blocked-upon synchronization object, return
* the address of its turnstile.
*/
/*ARGSUSED*/
int
{
int isupi;
int ttoff;
return (DCMD_USAGE);
mdb_warn("unable to reference upimutextab\n");
return (DCMD_ERR);
}
mdb_warn("unable to reference turnstile_table");
return (DCMD_ERR);
}
return (DCMD_ERR);
}
return (DCMD_ERR);
}
break;
}
}
return (DCMD_OK);
}