xref: /titanic_50/usr/src/cmd/mdb/common/modules/dtrace/dof.c (revision 45916cd2fec6e79bca5dee0421bd39e3c2910d1e)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <mdb/mdb_modapi.h>
30 #include <dtrace.h>
31 
32 extern int dof_sec(uintptr_t, uint_t, int, const mdb_arg_t *);
33 extern const char *dof_sec_name(uint32_t);
34 
35 extern const mdb_walker_t kernel_walkers[];
36 extern const mdb_dcmd_t kernel_dcmds[];
37 
38 /*ARGSUSED*/
39 static void
40 dis_log(const dtrace_difo_t *dp, const char *name, dif_instr_t instr)
41 {
42 	mdb_printf("%-4s %%r%u, %%r%u, %%r%u", name,
43 	    DIF_INSTR_R1(instr), DIF_INSTR_R2(instr), DIF_INSTR_RD(instr));
44 }
45 
46 /*ARGSUSED*/
47 static void
48 dis_branch(const dtrace_difo_t *dp, const char *name, dif_instr_t instr)
49 {
50 	mdb_printf("%-4s %u", name, DIF_INSTR_LABEL(instr));
51 }
52 
53 /*ARGSUSED*/
54 static void
55 dis_load(const dtrace_difo_t *dp, const char *name, dif_instr_t instr)
56 {
57 	mdb_printf("%-4s [%%r%u], %%r%u", name,
58 	    DIF_INSTR_R1(instr), DIF_INSTR_RD(instr));
59 }
60 
61 /*ARGSUSED*/
62 static void
63 dis_store(const dtrace_difo_t *dp, const char *name, dif_instr_t instr)
64 {
65 	mdb_printf("%-4s %%r%u, [%%r%u]", name,
66 	    DIF_INSTR_R1(instr), DIF_INSTR_RD(instr));
67 }
68 
69 /*ARGSUSED*/
70 static void
71 dis_str(const dtrace_difo_t *dp, const char *name, dif_instr_t instr)
72 {
73 	mdb_printf("%s", name);
74 }
75 
76 /*ARGSUSED*/
77 static void
78 dis_r1rd(const dtrace_difo_t *dp, const char *name, dif_instr_t instr)
79 {
80 	mdb_printf("%-4s %%r%u, %%r%u", name,
81 	    DIF_INSTR_R1(instr), DIF_INSTR_RD(instr));
82 }
83 
84 /*ARGSUSED*/
85 static void
86 dis_cmp(const dtrace_difo_t *dp, const char *name, dif_instr_t instr)
87 {
88 	mdb_printf("%-4s %%r%u, %%r%u", name,
89 	    DIF_INSTR_R1(instr), DIF_INSTR_R2(instr));
90 }
91 
92 /*ARGSUSED*/
93 static void
94 dis_tst(const dtrace_difo_t *dp, const char *name, dif_instr_t instr)
95 {
96 	mdb_printf("%-4s %%r%u", name, DIF_INSTR_R1(instr));
97 }
98 
99 static const char *
100 dis_varname(const dtrace_difo_t *dp, uint_t id, uint_t scope)
101 {
102 	dtrace_difv_t *dvp;
103 	size_t varsize;
104 	caddr_t addr = NULL, str;
105 	uint_t i;
106 
107 	if (dp == NULL)
108 		return (NULL);
109 
110 	varsize = sizeof (dtrace_difv_t) * dp->dtdo_varlen;
111 	dvp = mdb_alloc(varsize, UM_SLEEP);
112 
113 	if (mdb_vread(dvp, varsize, (uintptr_t)dp->dtdo_vartab) == -1) {
114 		mdb_free(dvp, varsize);
115 		return ("<unreadable>");
116 	}
117 
118 	for (i = 0; i < dp->dtdo_varlen; i++) {
119 		if (dvp[i].dtdv_id == id && dvp[i].dtdv_scope == scope) {
120 			if (dvp[i].dtdv_name < dp->dtdo_strlen)
121 				addr = dp->dtdo_strtab + dvp[i].dtdv_name;
122 			break;
123 		}
124 	}
125 
126 	mdb_free(dvp, varsize);
127 
128 	if (addr == NULL)
129 		return (NULL);
130 
131 	str = mdb_zalloc(dp->dtdo_strlen + 1, UM_SLEEP | UM_GC);
132 
133 	for (i = 0; i == 0 || str[i - 1] != '\0'; i++, addr++) {
134 		if (mdb_vread(&str[i], sizeof (char), (uintptr_t)addr) == -1)
135 			return ("<unreadable>");
136 	}
137 
138 	return (str);
139 }
140 
141 static uint_t
142 dis_scope(const char *name)
143 {
144 	switch (name[2]) {
145 	case 'l': return (DIFV_SCOPE_LOCAL);
146 	case 't': return (DIFV_SCOPE_THREAD);
147 	case 'g': return (DIFV_SCOPE_GLOBAL);
148 	default: return (-1u);
149 	}
150 }
151 
152 static void
153 dis_lda(const dtrace_difo_t *dp, const char *name, dif_instr_t instr)
154 {
155 	uint_t var = DIF_INSTR_R1(instr);
156 	const char *vname;
157 
158 	mdb_printf("%-4s DIF_VAR(%x), %%r%u, %%r%u", name,
159 	    var, DIF_INSTR_R2(instr), DIF_INSTR_RD(instr));
160 
161 	if ((vname = dis_varname(dp, var, dis_scope(name))) != NULL)
162 		mdb_printf("\t\t! %s", vname);
163 }
164 
165 static void
166 dis_ldv(const dtrace_difo_t *dp, const char *name, dif_instr_t instr)
167 {
168 	uint_t var = DIF_INSTR_VAR(instr);
169 	const char *vname;
170 
171 	mdb_printf("%-4s DIF_VAR(%x), %%r%u", name, var, DIF_INSTR_RD(instr));
172 
173 	if ((vname = dis_varname(dp, var, dis_scope(name))) != NULL)
174 		mdb_printf("\t\t! %s", vname);
175 }
176 
177 static void
178 dis_stv(const dtrace_difo_t *dp, const char *name, dif_instr_t instr)
179 {
180 	uint_t var = DIF_INSTR_VAR(instr);
181 	const char *vname;
182 
183 	mdb_printf("%-4s %%r%u, DIF_VAR(%x)", name, DIF_INSTR_RS(instr), var);
184 
185 	if ((vname = dis_varname(dp, var, dis_scope(name))) != NULL)
186 		mdb_printf("\t\t! %s", vname);
187 }
188 
189 static void
190 dis_setx(const dtrace_difo_t *dp, const char *name, dif_instr_t instr)
191 {
192 	uint_t intptr = DIF_INSTR_INTEGER(instr);
193 
194 	mdb_printf("%-4s DIF_INTEGER[%u], %%r%u", name,
195 	    intptr, DIF_INSTR_RD(instr));
196 
197 	if (dp != NULL && intptr < dp->dtdo_intlen) {
198 		uint64_t *ip = mdb_alloc(dp->dtdo_intlen *
199 		    sizeof (uint64_t), UM_SLEEP | UM_GC);
200 
201 		if (mdb_vread(ip, dp->dtdo_intlen * sizeof (uint64_t),
202 		    (uintptr_t)dp->dtdo_inttab) == -1)
203 			mdb_warn("failed to read data at %p", dp->dtdo_inttab);
204 		else
205 			mdb_printf("\t\t! 0x%llx", ip[intptr]);
206 	}
207 }
208 
209 static void
210 dis_sets(const dtrace_difo_t *dp, const char *name, dif_instr_t instr)
211 {
212 	uint_t strptr = DIF_INSTR_STRING(instr);
213 
214 	mdb_printf("%-4s DIF_STRING[%u], %%r%u", name,
215 	    strptr, DIF_INSTR_RD(instr));
216 
217 	if (dp != NULL && strptr < dp->dtdo_strlen) {
218 		char *str = mdb_alloc(dp->dtdo_strlen, UM_SLEEP | UM_GC);
219 
220 		if (mdb_vread(str, dp->dtdo_strlen,
221 		    (uintptr_t)dp->dtdo_strtab) == -1)
222 			mdb_warn("failed to read data at %p", dp->dtdo_strtab);
223 		else
224 			mdb_printf("\t\t! \"%s\"", str + strptr);
225 	}
226 }
227 
228 /*ARGSUSED*/
229 static void
230 dis_ret(const dtrace_difo_t *dp, const char *name, dif_instr_t instr)
231 {
232 	mdb_printf("%-4s %%r%u", name, DIF_INSTR_RD(instr));
233 }
234 
235 /*ARGSUSED*/
236 static void
237 dis_call(const dtrace_difo_t *dp, const char *name, dif_instr_t instr)
238 {
239 	uint_t subr = DIF_INSTR_SUBR(instr);
240 
241 	mdb_printf("%-4s DIF_SUBR(%u), %%r%u\t\t! %s",
242 	    name, subr, DIF_INSTR_RD(instr), dtrace_subrstr(NULL, subr));
243 }
244 
245 /*ARGSUSED*/
246 static void
247 dis_pushts(const dtrace_difo_t *dp, const char *name, dif_instr_t instr)
248 {
249 	static const char *const tnames[] = { "TYPE_CTF", "TYPE_STRING" };
250 	uint_t type = DIF_INSTR_TYPE(instr);
251 
252 	mdb_printf("%-4s DIF_TYPE(%u), %%r%u, %%r%u",
253 	    name, type, DIF_INSTR_R2(instr), DIF_INSTR_RS(instr));
254 
255 	if (type < sizeof (tnames) / sizeof (tnames[0]))
256 		mdb_printf("\t\t! %s", tnames[type]);
257 }
258 
259 /*ARGSUSED*/
260 static void
261 dis_xlate(const dtrace_difo_t *dp, const char *name, dif_instr_t instr)
262 {
263 	mdb_printf("%-4s DIF_XLREF[%u], %%r%u", name,
264 	    DIF_INSTR_XLREF(instr), DIF_INSTR_RD(instr));
265 }
266 
267 static char *
268 dis_typestr(const dtrace_diftype_t *t, char *buf, size_t len)
269 {
270 	char kind[8];
271 
272 	switch (t->dtdt_kind) {
273 	case DIF_TYPE_CTF:
274 		(void) strcpy(kind, "D type");
275 		break;
276 	case DIF_TYPE_STRING:
277 		(void) strcpy(kind, "string");
278 		break;
279 	default:
280 		(void) mdb_snprintf(kind, sizeof (kind), "0x%x", t->dtdt_kind);
281 	}
282 
283 	if (t->dtdt_flags & DIF_TF_BYREF) {
284 		(void) mdb_snprintf(buf, len,
285 		    "%s by ref (size %lu)",
286 		    kind, (ulong_t)t->dtdt_size);
287 	} else {
288 		(void) mdb_snprintf(buf, len, "%s (size %lu)",
289 		    kind, (ulong_t)t->dtdt_size);
290 	}
291 
292 	return (buf);
293 }
294 
295 static int
296 dis(uintptr_t addr, dtrace_difo_t *dp)
297 {
298 	static const struct opent {
299 		const char *op_name;
300 		void (*op_func)(const dtrace_difo_t *,
301 		    const char *, dif_instr_t);
302 	} optab[] = {
303 		{ "(illegal opcode)", dis_str },
304 		{ "or", dis_log },		/* DIF_OP_OR */
305 		{ "xor", dis_log },		/* DIF_OP_XOR */
306 		{ "and", dis_log },		/* DIF_OP_AND */
307 		{ "sll", dis_log },		/* DIF_OP_SLL */
308 		{ "srl", dis_log },		/* DIF_OP_SRL */
309 		{ "sub", dis_log },		/* DIF_OP_SUB */
310 		{ "add", dis_log },		/* DIF_OP_ADD */
311 		{ "mul", dis_log },		/* DIF_OP_MUL */
312 		{ "sdiv", dis_log },		/* DIF_OP_SDIV */
313 		{ "udiv", dis_log },		/* DIF_OP_UDIV */
314 		{ "srem", dis_log },		/* DIF_OP_SREM */
315 		{ "urem", dis_log },		/* DIF_OP_UREM */
316 		{ "not", dis_r1rd },		/* DIF_OP_NOT */
317 		{ "mov", dis_r1rd },		/* DIF_OP_MOV */
318 		{ "cmp", dis_cmp },		/* DIF_OP_CMP */
319 		{ "tst", dis_tst },		/* DIF_OP_TST */
320 		{ "ba", dis_branch },		/* DIF_OP_BA */
321 		{ "be", dis_branch },		/* DIF_OP_BE */
322 		{ "bne", dis_branch },		/* DIF_OP_BNE */
323 		{ "bg", dis_branch },		/* DIF_OP_BG */
324 		{ "bgu", dis_branch },		/* DIF_OP_BGU */
325 		{ "bge", dis_branch },		/* DIF_OP_BGE */
326 		{ "bgeu", dis_branch },		/* DIF_OP_BGEU */
327 		{ "bl", dis_branch },		/* DIF_OP_BL */
328 		{ "blu", dis_branch },		/* DIF_OP_BLU */
329 		{ "ble", dis_branch },		/* DIF_OP_BLE */
330 		{ "bleu", dis_branch },		/* DIF_OP_BLEU */
331 		{ "ldsb", dis_load },		/* DIF_OP_LDSB */
332 		{ "ldsh", dis_load },		/* DIF_OP_LDSH */
333 		{ "ldsw", dis_load },		/* DIF_OP_LDSW */
334 		{ "ldub", dis_load },		/* DIF_OP_LDUB */
335 		{ "lduh", dis_load },		/* DIF_OP_LDUH */
336 		{ "lduw", dis_load },		/* DIF_OP_LDUW */
337 		{ "ldx", dis_load },		/* DIF_OP_LDX */
338 		{ "ret", dis_ret },		/* DIF_OP_RET */
339 		{ "nop", dis_str },		/* DIF_OP_NOP */
340 		{ "setx", dis_setx },		/* DIF_OP_SETX */
341 		{ "sets", dis_sets },		/* DIF_OP_SETS */
342 		{ "scmp", dis_cmp },		/* DIF_OP_SCMP */
343 		{ "ldga", dis_lda },		/* DIF_OP_LDGA */
344 		{ "ldgs", dis_ldv },		/* DIF_OP_LDGS */
345 		{ "stgs", dis_stv },		/* DIF_OP_STGS */
346 		{ "ldta", dis_lda },		/* DIF_OP_LDTA */
347 		{ "ldts", dis_ldv },		/* DIF_OP_LDTS */
348 		{ "stts", dis_stv },		/* DIF_OP_STTS */
349 		{ "sra", dis_log },		/* DIF_OP_SRA */
350 		{ "call", dis_call },		/* DIF_OP_CALL */
351 		{ "pushtr", dis_pushts },	/* DIF_OP_PUSHTR */
352 		{ "pushtv", dis_pushts },	/* DIF_OP_PUSHTV */
353 		{ "popts", dis_str },		/* DIF_OP_POPTS */
354 		{ "flushts", dis_str },		/* DIF_OP_FLUSHTS */
355 		{ "ldgaa", dis_ldv },		/* DIF_OP_LDGAA */
356 		{ "ldtaa", dis_ldv },		/* DIF_OP_LDTAA */
357 		{ "stgaa", dis_stv },		/* DIF_OP_STGAA */
358 		{ "sttaa", dis_stv },		/* DIF_OP_STTAA */
359 		{ "ldls", dis_ldv },		/* DIF_OP_LDLS */
360 		{ "stls", dis_stv },		/* DIF_OP_STLS */
361 		{ "allocs", dis_r1rd },		/* DIF_OP_ALLOCS */
362 		{ "copys", dis_log },		/* DIF_OP_COPYS */
363 		{ "stb", dis_store },		/* DIF_OP_STB */
364 		{ "sth", dis_store },		/* DIF_OP_STH */
365 		{ "stw", dis_store },		/* DIF_OP_STW */
366 		{ "stx", dis_store },		/* DIF_OP_STX */
367 		{ "uldsb", dis_load },		/* DIF_OP_ULDSB */
368 		{ "uldsh", dis_load },		/* DIF_OP_ULDSH */
369 		{ "uldsw", dis_load },		/* DIF_OP_ULDSW */
370 		{ "uldub", dis_load },		/* DIF_OP_ULDUB */
371 		{ "ulduh", dis_load },		/* DIF_OP_ULDUH */
372 		{ "ulduw", dis_load },		/* DIF_OP_ULDUW */
373 		{ "uldx", dis_load },		/* DIF_OP_ULDX */
374 		{ "rldsb", dis_load },		/* DIF_OP_RLDSB */
375 		{ "rldsh", dis_load },		/* DIF_OP_RLDSH */
376 		{ "rldsw", dis_load },		/* DIF_OP_RLDSW */
377 		{ "rldub", dis_load },		/* DIF_OP_RLDUB */
378 		{ "rlduh", dis_load },		/* DIF_OP_RLDUH */
379 		{ "rlduw", dis_load },		/* DIF_OP_RLDUW */
380 		{ "rldx", dis_load },		/* DIF_OP_RLDX */
381 		{ "xlate", dis_xlate },		/* DIF_OP_XLATE */
382 		{ "xlarg", dis_xlate },		/* DIF_OP_XLARG */
383 	};
384 
385 	dif_instr_t instr, opcode;
386 	const struct opent *op;
387 
388 	if (mdb_vread(&instr, sizeof (dif_instr_t), addr) == -1) {
389 		mdb_warn("failed to read DIF instruction at %p", addr);
390 		return (DCMD_ERR);
391 	}
392 
393 	opcode = DIF_INSTR_OP(instr);
394 
395 	if (opcode >= sizeof (optab) / sizeof (optab[0]))
396 		opcode = 0; /* force invalid opcode message */
397 
398 	op = &optab[opcode];
399 	mdb_printf("%0?p %08x ", addr, instr);
400 	op->op_func(dp, op->op_name, instr);
401 	mdb_printf("\n");
402 	mdb_set_dot(addr + sizeof (dif_instr_t));
403 
404 	return (DCMD_OK);
405 }
406 
407 /*ARGSUSED*/
408 int
409 difo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
410 {
411 	dtrace_difo_t difo, *dp = &difo;
412 	uintptr_t instr, limit;
413 	dtrace_difv_t *dvp;
414 	size_t varsize;
415 	ulong_t i;
416 	char type[64];
417 	char *str;
418 
419 	if (!(flags & DCMD_ADDRSPEC))
420 		return (DCMD_USAGE);
421 
422 	if (mdb_vread(dp, sizeof (dtrace_difo_t), addr) == -1) {
423 		mdb_warn("couldn't read dtrace_difo_t at %p", addr);
424 		return (DCMD_ERR);
425 	}
426 
427 	mdb_printf("%<u>DIF Object 0x%p%</u> (refcnt=%d)\n\n",
428 	    addr, dp->dtdo_refcnt);
429 	mdb_printf("%<b>%-?s %-8s %s%</b>\n", "ADDR", "OPCODE", "INSTRUCTION");
430 
431 	mdb_set_dot((uintmax_t)(uintptr_t)dp->dtdo_buf);
432 	limit = (uintptr_t)dp->dtdo_buf + dp->dtdo_len * sizeof (dif_instr_t);
433 
434 	while ((instr = mdb_get_dot()) < limit)
435 		dis(instr, dp);
436 
437 	if (dp->dtdo_varlen != 0) {
438 		mdb_printf("\n%<b>%-16s %-4s %-3s %-3s %-4s %s%</b>\n",
439 		    "NAME", "ID", "KND", "SCP", "FLAG", "TYPE");
440 	}
441 
442 	varsize = sizeof (dtrace_difv_t) * dp->dtdo_varlen;
443 	dvp = mdb_alloc(varsize, UM_SLEEP | UM_GC);
444 
445 	if (mdb_vread(dvp, varsize, (uintptr_t)dp->dtdo_vartab) == -1) {
446 		mdb_warn("couldn't read dtdo_vartab");
447 		return (DCMD_ERR);
448 	}
449 
450 	str = mdb_alloc(dp->dtdo_strlen, UM_SLEEP | UM_GC);
451 
452 	if (mdb_vread(str, dp->dtdo_strlen, (uintptr_t)dp->dtdo_strtab) == -1) {
453 		mdb_warn("couldn't read dtdo_strtab");
454 		return (DCMD_ERR);
455 	}
456 
457 	for (i = 0; i < dp->dtdo_varlen; i++) {
458 		dtrace_difv_t *v = &dvp[i];
459 		char kind[4], scope[4], flags[16] = { 0 };
460 
461 		switch (v->dtdv_kind) {
462 		case DIFV_KIND_ARRAY:
463 			(void) strcpy(kind, "arr");
464 			break;
465 		case DIFV_KIND_SCALAR:
466 			(void) strcpy(kind, "scl");
467 			break;
468 		default:
469 			(void) mdb_snprintf(kind, sizeof (kind),
470 			    "%u", v->dtdv_kind);
471 		}
472 
473 		switch (v->dtdv_scope) {
474 		case DIFV_SCOPE_GLOBAL:
475 			(void) strcpy(scope, "glb");
476 			break;
477 		case DIFV_SCOPE_THREAD:
478 			(void) strcpy(scope, "tls");
479 			break;
480 		case DIFV_SCOPE_LOCAL:
481 			(void) strcpy(scope, "loc");
482 			break;
483 		default:
484 			(void) mdb_snprintf(scope, sizeof (scope),
485 			    "%u", v->dtdv_scope);
486 		}
487 
488 		if (v->dtdv_flags & ~(DIFV_F_REF | DIFV_F_MOD)) {
489 			(void) mdb_snprintf(flags, sizeof (flags), "/0x%x",
490 			    v->dtdv_flags & ~(DIFV_F_REF | DIFV_F_MOD));
491 		}
492 
493 		if (v->dtdv_flags & DIFV_F_REF)
494 			(void) strcat(flags, "/r");
495 		if (v->dtdv_flags & DIFV_F_MOD)
496 			(void) strcat(flags, "/w");
497 
498 		mdb_printf("%-16s %-4x %-3s %-3s %-4s %s\n",
499 		    &str[v->dtdv_name],
500 		    v->dtdv_id, kind, scope, flags + 1,
501 		    dis_typestr(&v->dtdv_type, type, sizeof (type)));
502 	}
503 
504 	mdb_printf("\n%<b>RETURN%</b>\n%s\n\n",
505 	    dis_typestr(&dp->dtdo_rtype, type, sizeof (type)));
506 
507 	return (DCMD_OK);
508 }
509 
510 /*ARGSUSED*/
511 int
512 difinstr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
513 {
514 	if (!(flags & DCMD_ADDRSPEC))
515 		return (DCMD_USAGE);
516 
517 	return (dis(addr, NULL));
518 }
519 
520 /*ARGSUSED*/
521 int
522 dof_hdr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
523 {
524 	dof_hdr_t h;
525 
526 	if (argc != 0)
527 		return (DCMD_USAGE);
528 
529 	if (!(flags & DCMD_ADDRSPEC))
530 		addr = 0; /* assume base of file in file target */
531 
532 	if (mdb_vread(&h, sizeof (h), addr) != sizeof (h)) {
533 		mdb_warn("failed to read header at %p", addr);
534 		return (DCMD_ERR);
535 	}
536 
537 	mdb_printf("dofh_ident.id_magic = 0x%x, %c, %c, %c\n",
538 	    h.dofh_ident[DOF_ID_MAG0], h.dofh_ident[DOF_ID_MAG1],
539 	    h.dofh_ident[DOF_ID_MAG2], h.dofh_ident[DOF_ID_MAG3]);
540 
541 	switch (h.dofh_ident[DOF_ID_MODEL]) {
542 	case DOF_MODEL_ILP32:
543 		mdb_printf("dofh_ident.id_model = ILP32\n");
544 		break;
545 	case DOF_MODEL_LP64:
546 		mdb_printf("dofh_ident.id_model = LP64\n");
547 		break;
548 	default:
549 		mdb_printf("dofh_ident.id_model = 0x%x\n",
550 		    h.dofh_ident[DOF_ID_MODEL]);
551 	}
552 
553 	switch (h.dofh_ident[DOF_ID_ENCODING]) {
554 	case DOF_ENCODE_LSB:
555 		mdb_printf("dofh_ident.id_encoding = LSB\n");
556 		break;
557 	case DOF_ENCODE_MSB:
558 		mdb_printf("dofh_ident.id_encoding = MSB\n");
559 		break;
560 	default:
561 		mdb_printf("dofh_ident.id_encoding = 0x%x\n",
562 		    h.dofh_ident[DOF_ID_ENCODING]);
563 	}
564 
565 	mdb_printf("dofh_ident.id_version = %u\n",
566 	    h.dofh_ident[DOF_ID_VERSION]);
567 	mdb_printf("dofh_ident.id_difvers = %u\n",
568 	    h.dofh_ident[DOF_ID_DIFVERS]);
569 	mdb_printf("dofh_ident.id_difireg = %u\n",
570 	    h.dofh_ident[DOF_ID_DIFIREG]);
571 	mdb_printf("dofh_ident.id_diftreg = %u\n",
572 	    h.dofh_ident[DOF_ID_DIFTREG]);
573 
574 	mdb_printf("dofh_flags = 0x%x\n", h.dofh_flags);
575 	mdb_printf("dofh_hdrsize = %u\n", h.dofh_hdrsize);
576 	mdb_printf("dofh_secsize = %u\n", h.dofh_secsize);
577 	mdb_printf("dofh_secnum = %u\n", h.dofh_secnum);
578 	mdb_printf("dofh_secoff = %llu\n", h.dofh_secoff);
579 	mdb_printf("dofh_loadsz = %llu\n", h.dofh_loadsz);
580 	mdb_printf("dofh_filesz = %llu\n", h.dofh_filesz);
581 
582 	return (DCMD_OK);
583 }
584 
585 /*ARGSUSED*/
586 static int
587 dof_sec_walk(uintptr_t addr, void *ignored, int *sec)
588 {
589 	mdb_printf("%3d ", (*sec)++);
590 	(void) dof_sec(addr, DCMD_ADDRSPEC | DCMD_LOOP, 0, NULL);
591 	return (WALK_NEXT);
592 }
593 
594 /*ARGSUSED*/
595 int
596 dof_sec(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
597 {
598 	const char *name;
599 	dof_sec_t s;
600 
601 	if (!(flags & DCMD_ADDRSPEC))
602 		mdb_printf("%<u>%-3s ", "NDX");
603 
604 	if (!(flags & DCMD_ADDRSPEC) || DCMD_HDRSPEC(flags)) {
605 		mdb_printf("%<u>%?s %-10s %-5s %-5s %-5s %-6s %-5s%</u>\n",
606 		    "ADDR", "TYPE", "ALIGN", "FLAGS", "ENTSZ", "OFFSET",
607 		    "SIZE");
608 	}
609 
610 	if (!(flags & DCMD_ADDRSPEC)) {
611 		int sec = 0;
612 
613 		if (mdb_walk("dof_sec",
614 		    (mdb_walk_cb_t)dof_sec_walk, &sec) == -1) {
615 			mdb_warn("failed to walk dof_sec");
616 			return (DCMD_ERR);
617 		}
618 		return (DCMD_OK);
619 	}
620 
621 	if (argc != 0)
622 		return (DCMD_USAGE);
623 
624 	if (mdb_vread(&s, sizeof (s), addr) != sizeof (s)) {
625 		mdb_warn("failed to read section header at %p", addr);
626 		return (DCMD_ERR);
627 	}
628 
629 	mdb_printf("%?p ", addr);
630 
631 	if ((name = dof_sec_name(s.dofs_type)) != NULL)
632 		mdb_printf("%-10s ", name);
633 	else
634 		mdb_printf("%-10u ", s.dofs_type);
635 
636 	mdb_printf("%-5u %-#5x %-#5x %-6llx %-#5llx\n", s.dofs_align,
637 	    s.dofs_flags, s.dofs_entsize, s.dofs_offset, s.dofs_size);
638 
639 	return (DCMD_OK);
640 }
641 
642 int
643 dof_sec_walk_init(mdb_walk_state_t *wsp)
644 {
645 	dof_hdr_t h, *hp;
646 	size_t size;
647 
648 	if (mdb_vread(&h, sizeof (h), wsp->walk_addr) != sizeof (h)) {
649 		mdb_warn("failed to read DOF header at %p", wsp->walk_addr);
650 		return (WALK_ERR);
651 	}
652 
653 	size = sizeof (dof_hdr_t) + sizeof (dof_sec_t) * h.dofh_secnum;
654 	hp = mdb_alloc(size, UM_SLEEP);
655 
656 	if (mdb_vread(hp, size, wsp->walk_addr) != size) {
657 		mdb_warn("failed to read DOF sections at %p", wsp->walk_addr);
658 		mdb_free(hp, size);
659 		return (WALK_ERR);
660 	}
661 
662 	wsp->walk_arg = (void *)0;
663 	wsp->walk_data = hp;
664 
665 	return (WALK_NEXT);
666 }
667 
668 int
669 dof_sec_walk_step(mdb_walk_state_t *wsp)
670 {
671 	uint_t i = (uintptr_t)wsp->walk_arg;
672 	size_t off = sizeof (dof_hdr_t) + sizeof (dof_sec_t) * i;
673 	dof_hdr_t *hp = wsp->walk_data;
674 	dof_sec_t *sp = (dof_sec_t *)((uintptr_t)hp + off);
675 
676 	if (i >= hp->dofh_secnum)
677 		return (WALK_DONE);
678 
679 	wsp->walk_arg = (void *)(uintptr_t)(i + 1);
680 	return (wsp->walk_callback(wsp->walk_addr + off, sp, wsp->walk_cbdata));
681 }
682 
683 void
684 dof_sec_walk_fini(mdb_walk_state_t *wsp)
685 {
686 	dof_hdr_t *hp = wsp->walk_data;
687 	mdb_free(hp, sizeof (dof_hdr_t) + sizeof (dof_sec_t) * hp->dofh_secnum);
688 }
689 
690 /*ARGSUSED*/
691 int
692 dof_ecbdesc(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
693 {
694 	dof_ecbdesc_t e;
695 
696 	if (argc != 0 || !(flags & DCMD_ADDRSPEC))
697 		return (DCMD_USAGE);
698 
699 	if (mdb_vread(&e, sizeof (e), addr) != sizeof (e)) {
700 		mdb_warn("failed to read ecbdesc at %p", addr);
701 		return (DCMD_ERR);
702 	}
703 
704 	mdb_printf("dofe_probes = %d\n", e.dofe_probes);
705 	mdb_printf("dofe_actions = %d\n", e.dofe_actions);
706 	mdb_printf("dofe_pred = %d\n", e.dofe_pred);
707 	mdb_printf("dofe_uarg = 0x%llx\n", e.dofe_uarg);
708 
709 	return (DCMD_OK);
710 }
711 
712 /*ARGSUSED*/
713 int
714 dof_probedesc(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
715 {
716 	dof_probedesc_t p;
717 
718 	if (argc != 0 || !(flags & DCMD_ADDRSPEC))
719 		return (DCMD_USAGE);
720 
721 	if (mdb_vread(&p, sizeof (p), addr) != sizeof (p)) {
722 		mdb_warn("failed to read probedesc at %p", addr);
723 		return (DCMD_ERR);
724 	}
725 
726 	mdb_printf("dofp_strtab = %d\n", p.dofp_strtab);
727 	mdb_printf("dofp_provider = %u\n", p.dofp_provider);
728 	mdb_printf("dofp_mod = %u\n", p.dofp_mod);
729 	mdb_printf("dofp_func = %u\n", p.dofp_func);
730 	mdb_printf("dofp_name = %u\n", p.dofp_name);
731 	mdb_printf("dofp_id = %u\n", p.dofp_id);
732 
733 	return (DCMD_OK);
734 }
735 
736 /*ARGSUSED*/
737 int
738 dof_actdesc(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
739 {
740 	dof_actdesc_t a;
741 
742 	if (argc != 0 || !(flags & DCMD_ADDRSPEC))
743 		return (DCMD_USAGE);
744 
745 	if (mdb_vread(&a, sizeof (a), addr) != sizeof (a)) {
746 		mdb_warn("failed to read actdesc at %p", addr);
747 		return (DCMD_ERR);
748 	}
749 
750 	mdb_printf("dofa_difo = %d\n", a.dofa_difo);
751 	mdb_printf("dofa_strtab = %d\n", a.dofa_strtab);
752 	mdb_printf("dofa_kind = %u\n", a.dofa_kind);
753 	mdb_printf("dofa_ntuple = %u\n", a.dofa_ntuple);
754 	mdb_printf("dofa_arg = 0x%llx\n", a.dofa_arg);
755 	mdb_printf("dofa_uarg = 0x%llx\n", a.dofa_uarg);
756 
757 	return (DCMD_OK);
758 }
759 
760 /*ARGSUSED*/
761 int
762 dof_relohdr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
763 {
764 	dof_relohdr_t r;
765 
766 	if (argc != 0 || !(flags & DCMD_ADDRSPEC))
767 		return (DCMD_USAGE);
768 
769 	if (mdb_vread(&r, sizeof (r), addr) != sizeof (r)) {
770 		mdb_warn("failed to read relohdr at %p", addr);
771 		return (DCMD_ERR);
772 	}
773 
774 	mdb_printf("dofr_strtab = %d\n", r.dofr_strtab);
775 	mdb_printf("dofr_relsec = %d\n", r.dofr_relsec);
776 	mdb_printf("dofr_tgtsec = %d\n", r.dofr_tgtsec);
777 
778 	return (DCMD_OK);
779 }
780 
781 /*ARGSUSED*/
782 int
783 dof_relodesc(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
784 {
785 	dof_relodesc_t r;
786 
787 	if (argc != 0 || !(flags & DCMD_ADDRSPEC))
788 		return (DCMD_USAGE);
789 
790 	if (mdb_vread(&r, sizeof (r), addr) != sizeof (r)) {
791 		mdb_warn("failed to read relodesc at %p", addr);
792 		return (DCMD_ERR);
793 	}
794 
795 	mdb_printf("dofr_name = %u\n", r.dofr_name);
796 	mdb_printf("dofr_type = %u\n", r.dofr_type);
797 	mdb_printf("dofr_offset = 0x%llx\n", r.dofr_offset);
798 	mdb_printf("dofr_data = 0x%llx\n", r.dofr_data);
799 
800 	return (DCMD_OK);
801 }
802 
803 static int
804 dof_sect_strtab(uintptr_t addr, dof_sec_t *sec)
805 {
806 	char *strtab;
807 	size_t sz, i;
808 
809 	sz = (size_t)sec->dofs_size;
810 	strtab = mdb_alloc(sz, UM_SLEEP | UM_GC);
811 	if (mdb_vread(strtab, sz, addr + sec->dofs_offset) != sz) {
812 		mdb_warn("failed to read string table");
813 		return (1);
814 	}
815 
816 	mdb_printf("size = %lx\n", sz);
817 
818 	for (i = 0; i < sz; i++) {
819 		if (strtab[i] == '\0')
820 			mdb_printf("\\0");
821 		else
822 			mdb_printf("%c", strtab[i]);
823 	}
824 
825 	mdb_printf("\n");
826 
827 	return (0);
828 }
829 
830 static int
831 dof_sect_provider(uintptr_t addr, dof_sec_t *sec, dof_sec_t *dofs)
832 {
833 	dof_provider_t pv;
834 	dof_probe_t *pb;
835 	char *strtab;
836 	uint32_t *offs;
837 	uint8_t *args = NULL;
838 	size_t sz;
839 	int i, j;
840 	dof_stridx_t narg, xarg;
841 
842 	if (mdb_vread(&pv, sizeof (dof_provider_t),
843 	    addr + sec->dofs_offset) != sizeof (dof_provider_t)) {
844 		mdb_warn("failed to read DOF provider");
845 		return (-1);
846 	}
847 
848 	sz = dofs[pv.dofpv_strtab].dofs_size;
849 	strtab = mdb_alloc(sz, UM_SLEEP | UM_GC);
850 	if (mdb_vread(strtab, sz, addr +
851 	    dofs[pv.dofpv_strtab].dofs_offset) != sz) {
852 		mdb_warn("failed to read string table");
853 		return (-1);
854 	}
855 
856 	mdb_printf("%lx provider %s {\n", (ulong_t)(addr + sec->dofs_offset),
857 	    strtab + pv.dofpv_name);
858 
859 	sz = dofs[pv.dofpv_prargs].dofs_size;
860 	if (sz != 0) {
861 		args = mdb_alloc(sz, UM_SLEEP | UM_GC);
862 		if (mdb_vread(args, sz, addr +
863 		    dofs[pv.dofpv_prargs].dofs_offset) != sz) {
864 			mdb_warn("failed to read args");
865 			return (-1);
866 		}
867 	}
868 
869 	sz = dofs[pv.dofpv_proffs].dofs_size;
870 	offs = mdb_alloc(sz, UM_SLEEP | UM_GC);
871 	if (mdb_vread(offs, sz, addr + dofs[pv.dofpv_proffs].dofs_offset)
872 	    != sz) {
873 		mdb_warn("failed to read offs");
874 		return (-1);
875 	}
876 
877 	sz = dofs[pv.dofpv_probes].dofs_size;
878 	pb = mdb_alloc(sz, UM_SLEEP | UM_GC);
879 	if (mdb_vread(pb, sz, addr + dofs[pv.dofpv_probes].dofs_offset) != sz) {
880 		mdb_warn("failed to read probes");
881 		return (-1);
882 	}
883 
884 	(void) mdb_inc_indent(2);
885 
886 	for (i = 0; i < sz / dofs[pv.dofpv_probes].dofs_entsize; i++) {
887 		mdb_printf("%lx probe %s:%s {\n", (ulong_t)(addr +
888 		    dofs[pv.dofpv_probes].dofs_offset +
889 		    i * dofs[pv.dofpv_probes].dofs_entsize),
890 		    strtab + pb[i].dofpr_func,
891 		    strtab + pb[i].dofpr_name);
892 
893 		(void) mdb_inc_indent(2);
894 		mdb_printf("addr: %p\n", (ulong_t)pb[i].dofpr_addr);
895 		mdb_printf("offs: ");
896 		for (j = 0; j < pb[i].dofpr_noffs; j++) {
897 			mdb_printf("%s %x", "," + (j == 0),
898 			    offs[pb[i].dofpr_offidx + j]);
899 		}
900 		mdb_printf("\n");
901 
902 		mdb_printf("nargs:");
903 		narg = pb[i].dofpr_nargv;
904 		for (j = 0; j < pb[i].dofpr_nargc; j++) {
905 			mdb_printf("%s %s", "," + (j == 0), strtab + narg);
906 			narg += strlen(strtab + narg) + 1;
907 		}
908 		mdb_printf("\n");
909 		mdb_printf("xargs:");
910 		xarg = pb[i].dofpr_xargv;
911 		for (j = 0; j < pb[i].dofpr_xargc; j++) {
912 			mdb_printf("%s %s", "," + (j == 0), strtab + xarg);
913 			xarg += strlen(strtab + xarg) + 1;
914 		}
915 		mdb_printf("\n");
916 		mdb_printf("map:  ");
917 		for (j = 0; j < pb[i].dofpr_xargc; j++) {
918 			mdb_printf("%s %d->%d", "," + (j == 0),
919 			    args[pb[i].dofpr_argidx + j], j);
920 		}
921 
922 		(void) mdb_dec_indent(2);
923 		mdb_printf("\n}\n");
924 	}
925 
926 	(void) mdb_dec_indent(2);
927 	mdb_printf("}\n");
928 
929 	return (0);
930 }
931 
932 static int
933 dof_sect_prargs(uintptr_t addr, dof_sec_t *sec)
934 {
935 	int i;
936 	uint8_t arg;
937 
938 	for (i = 0; i < sec->dofs_size; i++) {
939 		if (mdb_vread(&arg, sizeof (arg),
940 		    addr + sec->dofs_offset + i) != sizeof (arg)) {
941 			mdb_warn("failed to read argument");
942 			return (1);
943 		}
944 
945 		mdb_printf("%d ", arg);
946 
947 		if (i % 20 == 19)
948 			mdb_printf("\n");
949 	}
950 
951 	mdb_printf("\n");
952 
953 	return (0);
954 }
955 
956 /*ARGSUSED*/
957 static int
958 dofdump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
959 {
960 	dof_hdr_t dofh;
961 	dof_sec_t *dofs;
962 	const char *name;
963 	int i;
964 
965 	if (mdb_vread(&dofh, sizeof (dof_hdr_t), addr) != sizeof (dof_hdr_t)) {
966 		mdb_warn("failed to read DOF header");
967 		return (DCMD_ERR);
968 	}
969 
970 	dofs = mdb_alloc(sizeof (dof_sec_t) * dofh.dofh_secnum,
971 	    UM_SLEEP | UM_GC);
972 
973 	for (i = 0; i < dofh.dofh_secnum; i++) {
974 		if (mdb_vread(&dofs[i], sizeof (dof_sec_t), dofh.dofh_secoff +
975 		    addr + i * dofh.dofh_secsize) != sizeof (dof_sec_t)) {
976 			mdb_warn("failed to read DOF sections");
977 			return (DCMD_ERR);
978 		}
979 	}
980 
981 	for (i = 0; i < dofh.dofh_secnum; i++) {
982 		mdb_printf("%lx Section %d: ", (ulong_t)
983 		    (dofh.dofh_secoff + addr + i * dofh.dofh_secsize), i);
984 
985 		if ((name = dof_sec_name(dofs[i].dofs_type)) != NULL)
986 			mdb_printf("%s\n", name);
987 		else
988 			mdb_printf("%u\n", dofs[i].dofs_type);
989 
990 		(void) mdb_inc_indent(2);
991 		switch (dofs[i].dofs_type) {
992 		case DOF_SECT_PROVIDER:
993 			(void) dof_sect_provider(addr, &dofs[i], dofs);
994 			break;
995 		case DOF_SECT_STRTAB:
996 			(void) dof_sect_strtab(addr, &dofs[i]);
997 			break;
998 		case DOF_SECT_PRARGS:
999 			(void) dof_sect_prargs(addr, &dofs[i]);
1000 			break;
1001 		}
1002 		(void) mdb_dec_indent(2);
1003 
1004 		mdb_printf("\n");
1005 	}
1006 
1007 	return (DCMD_OK);
1008 }
1009 
1010 static const mdb_dcmd_t common_dcmds[] = {
1011 	{ "difinstr", ":", "disassemble a DIF instruction", difinstr },
1012 	{ "difo", ":", "print a DIF object", difo },
1013 	{ "dof_hdr", "?", "print a DOF header", dof_hdr },
1014 	{ "dof_sec", ":", "print a DOF section header", dof_sec },
1015 	{ "dof_ecbdesc", ":", "print a DOF ecbdesc", dof_ecbdesc },
1016 	{ "dof_probedesc", ":", "print a DOF probedesc", dof_probedesc },
1017 	{ "dof_actdesc", ":", "print a DOF actdesc", dof_actdesc },
1018 	{ "dof_relohdr", ":", "print a DOF relocation header", dof_relohdr },
1019 	{ "dof_relodesc", ":", "print a DOF relodesc", dof_relodesc },
1020 	{ "dofdump", ":", "dump DOF", dofdump },
1021 	{ NULL }
1022 };
1023 
1024 static const mdb_walker_t common_walkers[] = {
1025 	{ "dof_sec", "walk DOF section header table given header address",
1026 		dof_sec_walk_init, dof_sec_walk_step, dof_sec_walk_fini },
1027 	{ NULL }
1028 };
1029 
1030 static mdb_modinfo_t modinfo = {
1031 	MDB_API_VERSION, NULL, NULL
1032 };
1033 
1034 const mdb_modinfo_t *
1035 _mdb_init(void)
1036 {
1037 	uint_t d = 0, kd = 0, w = 0, kw = 0;
1038 	const mdb_walker_t *wp;
1039 	const mdb_dcmd_t *dp;
1040 
1041 	for (dp = common_dcmds; dp->dc_name != NULL; dp++)
1042 		d++; /* count common dcmds */
1043 
1044 	for (wp = common_walkers; wp->walk_name != NULL; wp++)
1045 		w++; /* count common walkers */
1046 
1047 #ifdef _KERNEL
1048 	for (dp = kernel_dcmds; dp->dc_name != NULL; dp++)
1049 		kd++; /* count kernel dcmds */
1050 
1051 	for (wp = kernel_walkers; wp->walk_name != NULL; wp++)
1052 		kw++; /* count common walkers */
1053 #endif
1054 
1055 	modinfo.mi_dcmds = mdb_zalloc(sizeof (*dp) * (d + kd + 1), UM_SLEEP);
1056 	modinfo.mi_walkers = mdb_zalloc(sizeof (*wp) * (w + kw + 1), UM_SLEEP);
1057 
1058 	bcopy(common_dcmds, (void *)modinfo.mi_dcmds, sizeof (*dp) * d);
1059 	bcopy(common_walkers, (void *)modinfo.mi_walkers, sizeof (*wp) * w);
1060 
1061 #ifdef _KERNEL
1062 	bcopy(kernel_dcmds, (void *)
1063 	    (modinfo.mi_dcmds + d), sizeof (*dp) * kd);
1064 	bcopy(kernel_walkers, (void *)
1065 	    (modinfo.mi_walkers + w), sizeof (*wp) * kw);
1066 #endif
1067 	return (&modinfo);
1068 }
1069 
1070 void
1071 _mdb_fini(void)
1072 {
1073 	const mdb_walker_t *wp;
1074 	const mdb_dcmd_t *dp;
1075 	uint_t d = 0, w = 0;
1076 
1077 	for (dp = modinfo.mi_dcmds; dp->dc_name != NULL; dp++)
1078 		d++;
1079 
1080 	for (wp = modinfo.mi_walkers; wp->walk_name != NULL; wp++)
1081 		w++;
1082 
1083 	mdb_free((void *)modinfo.mi_dcmds, sizeof (*dp) * (d + 1));
1084 	mdb_free((void *)modinfo.mi_walkers, sizeof (*wp) * (w + 1));
1085 }
1086