1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/types.h>
27 #include <sys/time.h>
28 #include <sys/sysmacros.h>
29 #include <ctype.h>
30 #include <sys/mdb_modapi.h>
31 #include <sys/mach_descrip.h>
32 #include <sys/mdesc.h>
33 #include <sys/mdesc_impl.h>
34 
35 /*ARGSUSED*/
36 int
mdhdr(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)37 mdhdr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
38 {
39 	uint_t verbose = 0;
40 	uintptr_t mdp;
41 	machine_descrip_t md;
42 
43 	if (flags & DCMD_ADDRSPEC)
44 		return (DCMD_USAGE);
45 
46 	if (mdb_getopts(argc, argv,
47 	    'v', MDB_OPT_SETBITS, 1, &verbose, NULL) != argc)
48 		return (DCMD_USAGE);
49 
50 	/* curr_mach_descrip normally points to /dev/mdesc */
51 	if (mdb_readvar(&mdp, "curr_mach_descrip") == -1) {
52 		mdb_warn("failed to read 'curr_mach_descrip'");
53 		return (DCMD_ERR);
54 	}
55 
56 	if (verbose)
57 		mdb_printf("ADDRESS     VA          MEMOPS      SIZE\n");
58 
59 	do {
60 		if (mdb_vread(&md, sizeof (md), mdp) == -1) {
61 			mdb_warn("failed to read machine_descrip_t at %p", mdp);
62 			return (DCMD_ERR);
63 		}
64 
65 		if (verbose)
66 			mdb_printf("%-11lx %-11lx %-11lx %-11lx\n",
67 			    mdp, md.va, md.memops, md.size);
68 		else
69 			mdb_printf("%p\n", mdp);
70 
71 	} while ((mdp = (uintptr_t)md.next) != (uintptr_t)NULL);
72 
73 	return (DCMD_OK);
74 }
75 
76 /*ARGSUSED*/
77 int
mdinfo(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)78 mdinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
79 {
80 	md_header_t mh;
81 	machine_descrip_t md;
82 	md_element_t *mdep;
83 	char *namep;
84 	uint8_t *datap;
85 	int mdesize, namesize, datasize;
86 	uintptr_t mdp;
87 	md_element_t *mdeptr, *eof;
88 	uintptr_t vaddr;
89 
90 	if (flags & DCMD_ADDRSPEC) {
91 		if ((addr & 7) != 0) {
92 			mdb_warn("misaligned address at %p", addr);
93 			return (DCMD_ERR);
94 		}
95 		vaddr = addr;
96 	} else {
97 		/* curr_mach_descrip normally points to /dev/mdesc */
98 		if (mdb_readvar(&mdp, "curr_mach_descrip") == -1) {
99 			mdb_warn("failed to read 'curr_mach_descrip'");
100 			return (DCMD_ERR);
101 		}
102 		if (mdb_vread(&md, sizeof (md), mdp) == -1) {
103 			mdb_warn("failed to read machine_descrip_t at %p", mdp);
104 			return (DCMD_ERR);
105 		}
106 		vaddr = (uintptr_t)md.va;
107 	}
108 
109 	if (mdb_vread(&mh, sizeof (mh), vaddr) == -1) {
110 		mdb_warn("failed to read md_header_t at %p", vaddr);
111 		return (DCMD_ERR);
112 	}
113 
114 	mdesize = mh.node_blk_sz;
115 	namesize = mh.name_blk_sz;
116 	datasize = mh.data_blk_sz;
117 
118 	/* find space for each section of the MD */
119 	if ((mdep = mdb_alloc(mdesize, UM_NOSLEEP)) == NULL) {
120 		mdb_warn("failed to allocate memory for mde block");
121 		return (DCMD_ERR);
122 	}
123 	if ((namep = mdb_alloc(namesize, UM_NOSLEEP)) == NULL) {
124 		mdb_warn("failed to allocate memory for name block");
125 		mdb_free(mdep, mdesize);
126 		return (DCMD_ERR);
127 	}
128 	if ((datap = mdb_alloc(datasize, UM_NOSLEEP)) == NULL) {
129 		mdb_warn("failed to allocate memory for data block");
130 		mdb_free(namep, namesize);
131 		mdb_free(mdep, mdesize);
132 		return (DCMD_ERR);
133 	}
134 
135 	/* store each of the MD sections */
136 	if (mdb_vread(mdep, mdesize, vaddr + MD_HEADER_SIZE) != mdesize) {
137 		mdb_warn("failed to read node block %p", vaddr
138 		    + MD_HEADER_SIZE);
139 		mdb_free(datap, datasize);
140 		mdb_free(namep, namesize);
141 		mdb_free(mdep, mdesize);
142 		return (DCMD_ERR);
143 	}
144 	if (mdb_vread(namep, namesize, vaddr + MD_HEADER_SIZE + mdesize)
145 	    != namesize) {
146 		mdb_warn("failed to read node block %p", vaddr + MD_HEADER_SIZE
147 		    + mdesize);
148 		mdb_free(datap, datasize);
149 		mdb_free(namep, namesize);
150 		mdb_free(mdep, mdesize);
151 		return (DCMD_ERR);
152 	}
153 	if (mdb_vread(datap, datasize, vaddr + MD_HEADER_SIZE + mdesize
154 	    + namesize) != datasize) {
155 		mdb_warn("failed to read node block %p", vaddr + MD_HEADER_SIZE
156 		    + mdesize + namesize);
157 		mdb_free(datap, datasize);
158 		mdb_free(namep, namesize);
159 		mdb_free(mdep, mdesize);
160 		return (DCMD_ERR);
161 	}
162 
163 	mdb_printf("TYPE OFFSET NAME                   PROPERTY\n");
164 	eof = mdep + (mdesize / sizeof (md_element_t));
165 	for (mdeptr = mdep; mdeptr < eof; ++mdeptr) {
166 		switch (MDE_TAG(mdeptr)) {
167 		case MDET_NODE:
168 			mdb_printf("node %-6x %-22s idx=%-11lx\n",
169 			    MDE_NAME(mdeptr), namep + mdeptr->name_offset,
170 			    MDE_PROP_INDEX(mdeptr));
171 			break;
172 		case MDET_PROP_ARC:
173 			mdb_printf("arc  %-6x %-22s idx=%-11lx\n",
174 			    MDE_NAME(mdeptr), namep + mdeptr->name_offset,
175 			    MDE_PROP_INDEX(mdeptr));
176 			break;
177 		case MDET_PROP_DAT:
178 			mdb_printf("data %-6x %-22s len=%x, offset=%x\n",
179 			    MDE_NAME(mdeptr), namep + mdeptr->name_offset,
180 			    MDE_PROP_DATA_LEN(mdeptr),
181 			    MDE_PROP_DATA_OFFSET(mdeptr));
182 			break;
183 		case MDET_PROP_STR:
184 			mdb_printf("str  %-6x %-22s len=%x, offset=%x\n",
185 			    MDE_NAME(mdeptr), namep + mdeptr->name_offset,
186 			    MDE_PROP_DATA_LEN(mdeptr),
187 			    MDE_PROP_DATA_OFFSET(mdeptr));
188 			break;
189 		case MDET_PROP_VAL:
190 			mdb_printf("val  %-6x %-22s val=%-11lx\n",
191 			    MDE_NAME(mdeptr), namep + mdeptr->name_offset,
192 			    MDE_PROP_VALUE(mdeptr));
193 			break;
194 		case MDET_NODE_END:
195 			mdb_printf("end\n");
196 			break;
197 		case MDET_NULL:
198 			mdb_printf("null\n");
199 			break;
200 		case MDET_LIST_END:
201 			mdb_printf("end of list\n");
202 			break;
203 		default:
204 			mdb_printf("unkown tag=%x\n", MDE_TAG(mdeptr));
205 			break;
206 		}
207 	}
208 
209 	mdb_free(datap, datasize);
210 	mdb_free(namep, namesize);
211 	mdb_free(mdep, mdesize);
212 	return (DCMD_OK);
213 }
214 
215 /*ARGSUSED*/
216 int
mdformat(uintptr_t addr,int size,int indent)217 mdformat(uintptr_t addr, int size, int indent)
218 {
219 	mdb_inc_indent(indent);
220 	if (mdb_dumpptr((uintptr_t)addr, size,
221 	    MDB_DUMP_RELATIVE | MDB_DUMP_TRIM | MDB_DUMP_ASCII |
222 	    MDB_DUMP_HEADER | MDB_DUMP_GROUP(4), NULL, NULL)) {
223 		mdb_dec_indent(indent);
224 		return (DCMD_ERR);
225 	}
226 	mdb_dec_indent(indent);
227 	return (DCMD_OK);
228 }
229 
230 /*ARGSUSED*/
231 int
mddump(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)232 mddump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
233 {
234 	uintptr_t mdp, mdep, namep, datap;
235 	machine_descrip_t md;
236 	md_header_t mh;
237 	uintptr_t vaddr;
238 
239 	if (flags & DCMD_ADDRSPEC) {
240 		if ((addr & 7) != 0) {
241 			mdb_warn("misaligned address at %p", addr);
242 			return (DCMD_ERR);
243 		}
244 		vaddr = addr;
245 	} else {
246 		/* curr_mach_descrip normally points to /dev/mdesc */
247 		if (mdb_readvar(&mdp, "curr_mach_descrip") == -1) {
248 			mdb_warn("failed to read 'curr_mach_descrip'");
249 			return (DCMD_ERR);
250 		}
251 		if (mdb_vread(&md, sizeof (md), mdp) == -1) {
252 			mdb_warn("failed to read machine_descrip_t at %p", mdp);
253 			return (DCMD_ERR);
254 		}
255 		vaddr = (uintptr_t)md.va;
256 	}
257 
258 	if (mdb_vread(&mh, sizeof (mh), (uintptr_t)vaddr) == -1) {
259 		mdb_warn("failed to read md_header_t at %p", vaddr);
260 		return (DCMD_ERR);
261 	}
262 
263 	mdep = (uintptr_t)vaddr + MD_HEADER_SIZE;
264 	namep = mdep + mh.node_blk_sz;
265 	datap = namep + mh.name_blk_sz;
266 
267 	mdb_printf("header (md_header_t) section at %lx:\n", vaddr);
268 	if (mdformat((uintptr_t)md.va, MD_HEADER_SIZE, 4) != DCMD_OK)
269 		return (DCMD_ERR);
270 
271 	mdb_printf("\nnode (md_element_t) section at %lx:\n", mdep);
272 	if (mdformat(mdep, mh.node_blk_sz, 2) != DCMD_OK)
273 		return (DCMD_ERR);
274 
275 	mdb_printf("\nname section at %lx:\n", namep);
276 	if (mdformat(namep, mh.name_blk_sz, 2) != DCMD_OK)
277 		return (DCMD_ERR);
278 
279 	mdb_printf("\ndata section at %lx:\n", datap);
280 	if (mdformat(datap, mh.data_blk_sz, 2) != DCMD_OK)
281 		return (DCMD_ERR);
282 
283 	return (DCMD_OK);
284 }
285 
286 /*
287  * MDB module linkage information:
288  *
289  * Declare a list of structures describing dcmds, and a function
290  * named _mdb_init to return a pointer to module information.
291  */
292 
293 static const mdb_dcmd_t dcmds[] = {
294 	{ "mdeschdr", "[-v]", "addr of current sun4v MD header", mdhdr },
295 	{ "mdescinfo", "?", "print md_elements with names from sun4v MD",
296 	    mdinfo },
297 	{ "mdescdump", "?", "dump node, name, data sections of sun4v MD",
298 	    mddump },
299 	{ NULL }
300 };
301 
302 static const mdb_modinfo_t modinfo = {
303 	MDB_API_VERSION, dcmds, NULL
304 };
305 
306 const mdb_modinfo_t *
_mdb_init(void)307 _mdb_init(void)
308 {
309 	return (&modinfo);
310 }
311