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/*
23 * Copyright 2006 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
32extern int dof_sec(uintptr_t, uint_t, int, const mdb_arg_t *);
33extern const char *dof_sec_name(uint32_t);
34
35extern const mdb_walker_t kernel_walkers[];
36extern const mdb_dcmd_t kernel_dcmds[];
37
38/*ARGSUSED*/
39static void
40dis_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*/
47static void
48dis_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*/
54static void
55dis_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*/
62static void
63dis_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*/
70static void
71dis_str(const dtrace_difo_t *dp, const char *name, dif_instr_t instr)
72{
73	mdb_printf("%s", name);
74}
75
76/*ARGSUSED*/
77static void
78dis_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*/
85static void
86dis_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*/
93static void
94dis_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
99static const char *
100dis_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
141static uint_t
142dis_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
152static void
153dis_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
165static void
166dis_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
177static void
178dis_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
189static void
190dis_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
209static void
210dis_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*/
229static void
230dis_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*/
236static void
237dis_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*/
246static void
247dis_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*/
260static void
261dis_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
267static char *
268dis_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
295static int
296dis(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*/
408int
409difo(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*/
511int
512difinstr(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*/
521int
522dof_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*/
586static int
587dof_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*/
595int
596dof_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
642int
643dof_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
668int
669dof_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
683void
684dof_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*/
691int
692dof_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*/
713int
714dof_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*/
737int
738dof_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*/
761int
762dof_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*/
782int
783dof_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
803static int
804dof_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
830static int
831dof_sect_provider(dof_hdr_t *dofh, uintptr_t addr, dof_sec_t *sec,
832    dof_sec_t *dofs)
833{
834	dof_provider_t pv;
835	dof_probe_t *pb;
836	char *strtab, *p;
837	uint32_t *offs, *enoffs;
838	uint8_t *args = NULL;
839	size_t sz;
840	int i, j;
841	dof_stridx_t narg, xarg;
842
843	sz = MIN(sec->dofs_size, sizeof (dof_provider_t));
844	if (mdb_vread(&pv, sz, addr + sec->dofs_offset) != sz) {
845		mdb_warn("failed to read DOF provider");
846		return (-1);
847	}
848
849	sz = dofs[pv.dofpv_strtab].dofs_size;
850	strtab = mdb_alloc(sz, UM_SLEEP | UM_GC);
851	if (mdb_vread(strtab, sz, addr +
852	    dofs[pv.dofpv_strtab].dofs_offset) != sz) {
853		mdb_warn("failed to read string table");
854		return (-1);
855	}
856
857	mdb_printf("%lx provider %s {\n", (ulong_t)(addr + sec->dofs_offset),
858	    strtab + pv.dofpv_name);
859
860	sz = dofs[pv.dofpv_prargs].dofs_size;
861	if (sz != 0) {
862		args = mdb_alloc(sz, UM_SLEEP | UM_GC);
863		if (mdb_vread(args, sz, addr +
864		    dofs[pv.dofpv_prargs].dofs_offset) != sz) {
865			mdb_warn("failed to read args");
866			return (-1);
867		}
868	}
869
870	sz = dofs[pv.dofpv_proffs].dofs_size;
871	offs = mdb_alloc(sz, UM_SLEEP | UM_GC);
872	if (mdb_vread(offs, sz, addr + dofs[pv.dofpv_proffs].dofs_offset)
873	    != sz) {
874		mdb_warn("failed to read offsets");
875		return (-1);
876	}
877
878	enoffs = NULL;
879	if (dofh->dofh_ident[DOF_ID_VERSION] != DOF_VERSION_1 ||
880	    pv.dofpv_prenoffs == 0) {
881		sz = dofs[pv.dofpv_prenoffs].dofs_size;
882		enoffs = mdb_alloc(sz, UM_SLEEP | UM_GC);
883		if (mdb_vread(enoffs, sz, addr +
884		    dofs[pv.dofpv_prenoffs].dofs_offset) != sz) {
885			mdb_warn("failed to read is-enabled offsets");
886			return (-1);
887		}
888	}
889
890	sz = dofs[pv.dofpv_probes].dofs_size;
891	p = mdb_alloc(sz, UM_SLEEP | UM_GC);
892	if (mdb_vread(p, sz, addr + dofs[pv.dofpv_probes].dofs_offset) != sz) {
893		mdb_warn("failed to read probes");
894		return (-1);
895	}
896
897	(void) mdb_inc_indent(2);
898
899	for (i = 0; i < sz / dofs[pv.dofpv_probes].dofs_entsize; i++) {
900		pb = (dof_probe_t *)(uintptr_t)(p +
901		    i * dofs[pv.dofpv_probes].dofs_entsize);
902
903		mdb_printf("%lx probe %s:%s {\n", (ulong_t)(addr +
904		    dofs[pv.dofpv_probes].dofs_offset +
905		    i * dofs[pv.dofpv_probes].dofs_entsize),
906		    strtab + pb->dofpr_func,
907		    strtab + pb->dofpr_name);
908
909		(void) mdb_inc_indent(2);
910		mdb_printf("addr: %p\n", (ulong_t)pb->dofpr_addr);
911		mdb_printf("offs: ");
912		for (j = 0; j < pb->dofpr_noffs; j++) {
913			mdb_printf("%s %x", "," + (j == 0),
914			    offs[pb->dofpr_offidx + j]);
915		}
916		mdb_printf("\n");
917
918		if (dofh->dofh_ident[DOF_ID_VERSION] != DOF_VERSION_1) {
919			mdb_printf("enoffs: ");
920			if (enoffs == NULL) {
921				if (pb->dofpr_nenoffs != 0)
922					mdb_printf("<error>");
923			} else {
924				for (j = 0; j < pb->dofpr_nenoffs; j++) {
925					mdb_printf("%s %x", "," + (j == 0),
926					    enoffs[pb->dofpr_enoffidx + j]);
927				}
928			}
929			mdb_printf("\n");
930		}
931
932		mdb_printf("nargs:");
933		narg = pb->dofpr_nargv;
934		for (j = 0; j < pb->dofpr_nargc; j++) {
935			mdb_printf("%s %s", "," + (j == 0), strtab + narg);
936			narg += strlen(strtab + narg) + 1;
937		}
938		mdb_printf("\n");
939		mdb_printf("xargs:");
940		xarg = pb->dofpr_xargv;
941		for (j = 0; j < pb->dofpr_xargc; j++) {
942			mdb_printf("%s %s", "," + (j == 0), strtab + xarg);
943			xarg += strlen(strtab + xarg) + 1;
944		}
945		mdb_printf("\n");
946		mdb_printf("map:  ");
947		for (j = 0; j < pb->dofpr_xargc; j++) {
948			mdb_printf("%s %d->%d", "," + (j == 0),
949			    args[pb->dofpr_argidx + j], j);
950		}
951
952		(void) mdb_dec_indent(2);
953		mdb_printf("\n}\n");
954	}
955
956	(void) mdb_dec_indent(2);
957	mdb_printf("}\n");
958
959	return (0);
960}
961
962static int
963dof_sect_prargs(uintptr_t addr, dof_sec_t *sec)
964{
965	int i;
966	uint8_t arg;
967
968	for (i = 0; i < sec->dofs_size; i++) {
969		if (mdb_vread(&arg, sizeof (arg),
970		    addr + sec->dofs_offset + i) != sizeof (arg)) {
971			mdb_warn("failed to read argument");
972			return (1);
973		}
974
975		mdb_printf("%d ", arg);
976
977		if (i % 20 == 19)
978			mdb_printf("\n");
979	}
980
981	mdb_printf("\n");
982
983	return (0);
984}
985
986/*ARGSUSED*/
987static int
988dofdump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
989{
990	dof_hdr_t dofh;
991	dof_sec_t *dofs;
992	const char *name;
993	int i;
994
995	if (mdb_vread(&dofh, sizeof (dof_hdr_t), addr) != sizeof (dof_hdr_t)) {
996		mdb_warn("failed to read DOF header");
997		return (DCMD_ERR);
998	}
999
1000	dofs = mdb_alloc(sizeof (dof_sec_t) * dofh.dofh_secnum,
1001	    UM_SLEEP | UM_GC);
1002
1003	for (i = 0; i < dofh.dofh_secnum; i++) {
1004		if (mdb_vread(&dofs[i], sizeof (dof_sec_t), dofh.dofh_secoff +
1005		    addr + i * dofh.dofh_secsize) != sizeof (dof_sec_t)) {
1006			mdb_warn("failed to read DOF sections");
1007			return (DCMD_ERR);
1008		}
1009	}
1010
1011	for (i = 0; i < dofh.dofh_secnum; i++) {
1012		mdb_printf("%lx Section %d: ", (ulong_t)
1013		    (dofh.dofh_secoff + addr + i * dofh.dofh_secsize), i);
1014
1015		if ((name = dof_sec_name(dofs[i].dofs_type)) != NULL)
1016			mdb_printf("%s\n", name);
1017		else
1018			mdb_printf("%u\n", dofs[i].dofs_type);
1019
1020		(void) mdb_inc_indent(2);
1021		switch (dofs[i].dofs_type) {
1022		case DOF_SECT_PROVIDER:
1023			(void) dof_sect_provider(&dofh, addr, &dofs[i], dofs);
1024			break;
1025		case DOF_SECT_STRTAB:
1026			(void) dof_sect_strtab(addr, &dofs[i]);
1027			break;
1028		case DOF_SECT_PRARGS:
1029			(void) dof_sect_prargs(addr, &dofs[i]);
1030			break;
1031		}
1032		(void) mdb_dec_indent(2);
1033
1034		mdb_printf("\n");
1035	}
1036
1037	return (DCMD_OK);
1038}
1039
1040static const mdb_dcmd_t common_dcmds[] = {
1041	{ "difinstr", ":", "disassemble a DIF instruction", difinstr },
1042	{ "difo", ":", "print a DIF object", difo },
1043	{ "dof_hdr", "?", "print a DOF header", dof_hdr },
1044	{ "dof_sec", ":", "print a DOF section header", dof_sec },
1045	{ "dof_ecbdesc", ":", "print a DOF ecbdesc", dof_ecbdesc },
1046	{ "dof_probedesc", ":", "print a DOF probedesc", dof_probedesc },
1047	{ "dof_actdesc", ":", "print a DOF actdesc", dof_actdesc },
1048	{ "dof_relohdr", ":", "print a DOF relocation header", dof_relohdr },
1049	{ "dof_relodesc", ":", "print a DOF relodesc", dof_relodesc },
1050	{ "dofdump", ":", "dump DOF", dofdump },
1051	{ NULL }
1052};
1053
1054static const mdb_walker_t common_walkers[] = {
1055	{ "dof_sec", "walk DOF section header table given header address",
1056		dof_sec_walk_init, dof_sec_walk_step, dof_sec_walk_fini },
1057	{ NULL }
1058};
1059
1060static mdb_modinfo_t modinfo = {
1061	MDB_API_VERSION, NULL, NULL
1062};
1063
1064const mdb_modinfo_t *
1065_mdb_init(void)
1066{
1067	uint_t d = 0, kd = 0, w = 0, kw = 0;
1068	const mdb_walker_t *wp;
1069	const mdb_dcmd_t *dp;
1070
1071	for (dp = common_dcmds; dp->dc_name != NULL; dp++)
1072		d++; /* count common dcmds */
1073
1074	for (wp = common_walkers; wp->walk_name != NULL; wp++)
1075		w++; /* count common walkers */
1076
1077#ifdef _KERNEL
1078	for (dp = kernel_dcmds; dp->dc_name != NULL; dp++)
1079		kd++; /* count kernel dcmds */
1080
1081	for (wp = kernel_walkers; wp->walk_name != NULL; wp++)
1082		kw++; /* count common walkers */
1083#endif
1084
1085	modinfo.mi_dcmds = mdb_zalloc(sizeof (*dp) * (d + kd + 1), UM_SLEEP);
1086	modinfo.mi_walkers = mdb_zalloc(sizeof (*wp) * (w + kw + 1), UM_SLEEP);
1087
1088	bcopy(common_dcmds, (void *)modinfo.mi_dcmds, sizeof (*dp) * d);
1089	bcopy(common_walkers, (void *)modinfo.mi_walkers, sizeof (*wp) * w);
1090
1091#ifdef _KERNEL
1092	bcopy(kernel_dcmds, (void *)
1093	    (modinfo.mi_dcmds + d), sizeof (*dp) * kd);
1094	bcopy(kernel_walkers, (void *)
1095	    (modinfo.mi_walkers + w), sizeof (*wp) * kw);
1096#endif
1097	return (&modinfo);
1098}
1099
1100void
1101_mdb_fini(void)
1102{
1103	const mdb_walker_t *wp;
1104	const mdb_dcmd_t *dp;
1105	uint_t d = 0, w = 0;
1106
1107	for (dp = modinfo.mi_dcmds; dp->dc_name != NULL; dp++)
1108		d++;
1109
1110	for (wp = modinfo.mi_walkers; wp->walk_name != NULL; wp++)
1111		w++;
1112
1113	mdb_free((void *)modinfo.mi_dcmds, sizeof (*dp) * (d + 1));
1114	mdb_free((void *)modinfo.mi_walkers, sizeof (*wp) * (w + 1));
1115}
1116