/*
* 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
* 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 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/types.h>
#include <sys/time.h>
#include <sys/sysmacros.h>
#include <ctype.h>
#include <sys/mdb_modapi.h>
#include <sys/mach_descrip.h>
#include <sys/mdesc.h>
#include <sys/mdesc_impl.h>
/*ARGSUSED*/
int
mdhdr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
uint_t verbose = 0;
uintptr_t mdp;
machine_descrip_t md;
if (flags & DCMD_ADDRSPEC)
return (DCMD_USAGE);
if (mdb_getopts(argc, argv,
'v', MDB_OPT_SETBITS, 1, &verbose, NULL) != argc)
return (DCMD_USAGE);
/* curr_mach_descrip normally points to /dev/mdesc */
if (mdb_readvar(&mdp, "curr_mach_descrip") == -1) {
mdb_warn("failed to read 'curr_mach_descrip'");
return (DCMD_ERR);
}
if (verbose)
mdb_printf("ADDRESS VA MEMOPS SIZE\n");
do {
if (mdb_vread(&md, sizeof (md), mdp) == -1) {
mdb_warn("failed to read machine_descrip_t at %p", mdp);
return (DCMD_ERR);
}
if (verbose)
mdb_printf("%-11lx %-11lx %-11lx %-11lx\n",
mdp, md.va, md.memops, md.size);
else
mdb_printf("%p\n", mdp);
} while ((mdp = (uintptr_t)md.next) != NULL);
return (DCMD_OK);
}
/*ARGSUSED*/
int
mdinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
md_header_t mh;
machine_descrip_t md;
md_element_t *mdep;
char *namep;
uint8_t *datap;
int mdesize, namesize, datasize;
uintptr_t mdp;
md_element_t *mdeptr, *eof;
uintptr_t vaddr;
if (flags & DCMD_ADDRSPEC) {
if ((addr & 7) != 0) {
mdb_warn("misaligned address at %p", addr);
return (DCMD_ERR);
}
vaddr = addr;
} else {
/* curr_mach_descrip normally points to /dev/mdesc */
if (mdb_readvar(&mdp, "curr_mach_descrip") == -1) {
mdb_warn("failed to read 'curr_mach_descrip'");
return (DCMD_ERR);
}
if (mdb_vread(&md, sizeof (md), mdp) == -1) {
mdb_warn("failed to read machine_descrip_t at %p", mdp);
return (DCMD_ERR);
}
vaddr = (uintptr_t)md.va;
}
if (mdb_vread(&mh, sizeof (mh), vaddr) == -1) {
mdb_warn("failed to read md_header_t at %p", vaddr);
return (DCMD_ERR);
}
mdesize = mh.node_blk_sz;
namesize = mh.name_blk_sz;
datasize = mh.data_blk_sz;
/* find space for each section of the MD */
if ((mdep = mdb_alloc(mdesize, UM_NOSLEEP)) == NULL) {
mdb_warn("failed to allocate memory for mde block");
return (DCMD_ERR);
}
if ((namep = mdb_alloc(namesize, UM_NOSLEEP)) == NULL) {
mdb_warn("failed to allocate memory for name block");
mdb_free(mdep, mdesize);
return (DCMD_ERR);
}
if ((datap = mdb_alloc(datasize, UM_NOSLEEP)) == NULL) {
mdb_warn("failed to allocate memory for data block");
mdb_free(namep, namesize);
mdb_free(mdep, mdesize);
return (DCMD_ERR);
}
/* store each of the MD sections */
if (mdb_vread(mdep, mdesize, vaddr + MD_HEADER_SIZE) != mdesize) {
mdb_warn("failed to read node block %p", vaddr
+ MD_HEADER_SIZE);
mdb_free(datap, datasize);
mdb_free(namep, namesize);
mdb_free(mdep, mdesize);
return (DCMD_ERR);
}
if (mdb_vread(namep, namesize, vaddr + MD_HEADER_SIZE + mdesize)
!= namesize) {
mdb_warn("failed to read node block %p", vaddr + MD_HEADER_SIZE
+ mdesize);
mdb_free(datap, datasize);
mdb_free(namep, namesize);
mdb_free(mdep, mdesize);
return (DCMD_ERR);
}
if (mdb_vread(datap, datasize, vaddr + MD_HEADER_SIZE + mdesize
+ namesize) != datasize) {
mdb_warn("failed to read node block %p", vaddr + MD_HEADER_SIZE
+ mdesize + namesize);
mdb_free(datap, datasize);
mdb_free(namep, namesize);
mdb_free(mdep, mdesize);
return (DCMD_ERR);
}
mdb_printf("TYPE OFFSET NAME PROPERTY\n");
eof = mdep + (mdesize / sizeof (md_element_t));
for (mdeptr = mdep; mdeptr < eof; ++mdeptr) {
switch (MDE_TAG(mdeptr)) {
case MDET_NODE:
mdb_printf("node %-6x %-22s idx=%-11lx\n",
MDE_NAME(mdeptr), namep + mdeptr->name_offset,
MDE_PROP_INDEX(mdeptr));
break;
case MDET_PROP_ARC:
mdb_printf("arc %-6x %-22s idx=%-11lx\n",
MDE_NAME(mdeptr), namep + mdeptr->name_offset,
MDE_PROP_INDEX(mdeptr));
break;
case MDET_PROP_DAT:
mdb_printf("data %-6x %-22s len=%x, offset=%x\n",
MDE_NAME(mdeptr), namep + mdeptr->name_offset,
MDE_PROP_DATA_LEN(mdeptr),
MDE_PROP_DATA_OFFSET(mdeptr));
break;
case MDET_PROP_STR:
mdb_printf("str %-6x %-22s len=%x, offset=%x\n",
MDE_NAME(mdeptr), namep + mdeptr->name_offset,
MDE_PROP_DATA_LEN(mdeptr),
MDE_PROP_DATA_OFFSET(mdeptr));
break;
case MDET_PROP_VAL:
mdb_printf("val %-6x %-22s val=%-11lx\n",
MDE_NAME(mdeptr), namep + mdeptr->name_offset,
MDE_PROP_VALUE(mdeptr));
break;
case MDET_NODE_END:
mdb_printf("end\n");
break;
case MDET_NULL:
mdb_printf("null\n");
break;
case MDET_LIST_END:
mdb_printf("end of list\n");
break;
default:
mdb_printf("unkown tag=%x\n", MDE_TAG(mdeptr));
break;
}
}
mdb_free(datap, datasize);
mdb_free(namep, namesize);
mdb_free(mdep, mdesize);
return (DCMD_OK);
}
/*ARGSUSED*/
int
mdformat(uintptr_t addr, int size, int indent)
{
mdb_inc_indent(indent);
if (mdb_dumpptr((uintptr_t)addr, size,
MDB_DUMP_RELATIVE | MDB_DUMP_TRIM | MDB_DUMP_ASCII |
MDB_DUMP_HEADER | MDB_DUMP_GROUP(4),
(mdb_dumpptr_cb_t)mdb_vread, NULL)) {
mdb_dec_indent(indent);
return (DCMD_ERR);
}
mdb_dec_indent(indent);
return (DCMD_OK);
}
/*ARGSUSED*/
int
mddump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
uintptr_t mdp, mdep, namep, datap;
machine_descrip_t md;
md_header_t mh;
uintptr_t vaddr;
if (flags & DCMD_ADDRSPEC) {
if ((addr & 7) != 0) {
mdb_warn("misaligned address at %p", addr);
return (DCMD_ERR);
}
vaddr = addr;
} else {
/* curr_mach_descrip normally points to /dev/mdesc */
if (mdb_readvar(&mdp, "curr_mach_descrip") == -1) {
mdb_warn("failed to read 'curr_mach_descrip'");
return (DCMD_ERR);
}
if (mdb_vread(&md, sizeof (md), mdp) == -1) {
mdb_warn("failed to read machine_descrip_t at %p", mdp);
return (DCMD_ERR);
}
vaddr = (uintptr_t)md.va;
}
if (mdb_vread(&mh, sizeof (mh), (uintptr_t)vaddr) == -1) {
mdb_warn("failed to read md_header_t at %p", vaddr);
return (DCMD_ERR);
}
mdep = (uintptr_t)vaddr + MD_HEADER_SIZE;
namep = mdep + mh.node_blk_sz;
datap = namep + mh.name_blk_sz;
mdb_printf("header (md_header_t) section at %lx:\n", vaddr);
if (mdformat((uintptr_t)md.va, MD_HEADER_SIZE, 4) != DCMD_OK)
return (DCMD_ERR);
mdb_printf("\nnode (md_element_t) section at %lx:\n", mdep);
if (mdformat(mdep, mh.node_blk_sz, 2) != DCMD_OK)
return (DCMD_ERR);
mdb_printf("\nname section at %lx:\n", namep);
if (mdformat(namep, mh.name_blk_sz, 2) != DCMD_OK)
return (DCMD_ERR);
mdb_printf("\ndata section at %lx:\n", datap);
if (mdformat(datap, mh.data_blk_sz, 2) != DCMD_OK)
return (DCMD_ERR);
return (DCMD_OK);
}
/*
* MDB module linkage information:
*
* Declare a list of structures describing dcmds, and a function
* named _mdb_init to return a pointer to module information.
*/
static const mdb_dcmd_t dcmds[] = {
{ "mdeschdr", "[-v]", "addr of current sun4v MD header", mdhdr },
{ "mdescinfo", "?", "print md_elements with names from sun4v MD",
mdinfo },
{ "mdescdump", "?", "dump node, name, data sections of sun4v MD",
mddump },
{ NULL }
};
static const mdb_modinfo_t modinfo = {
MDB_API_VERSION, dcmds, NULL
};
const mdb_modinfo_t *
_mdb_init(void)
{
return (&modinfo);
}