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