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
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
dis_log(const dtrace_difo_t * dp,const char * name,dif_instr_t instr)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
dis_branch(const dtrace_difo_t * dp,const char * name,dif_instr_t instr)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
dis_load(const dtrace_difo_t * dp,const char * name,dif_instr_t instr)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
dis_store(const dtrace_difo_t * dp,const char * name,dif_instr_t instr)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
dis_str(const dtrace_difo_t * dp,const char * name,dif_instr_t instr)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
dis_r1rd(const dtrace_difo_t * dp,const char * name,dif_instr_t instr)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
dis_cmp(const dtrace_difo_t * dp,const char * name,dif_instr_t instr)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
dis_tst(const dtrace_difo_t * dp,const char * name,dif_instr_t instr)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 *
dis_varname(const dtrace_difo_t * dp,uint_t id,uint_t scope)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
dis_scope(const char * name)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
dis_lda(const dtrace_difo_t * dp,const char * name,dif_instr_t instr)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
dis_ldv(const dtrace_difo_t * dp,const char * name,dif_instr_t instr)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
dis_stv(const dtrace_difo_t * dp,const char * name,dif_instr_t instr)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
dis_setx(const dtrace_difo_t * dp,const char * name,dif_instr_t instr)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
dis_sets(const dtrace_difo_t * dp,const char * name,dif_instr_t instr)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
dis_ret(const dtrace_difo_t * dp,const char * name,dif_instr_t instr)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
dis_call(const dtrace_difo_t * dp,const char * name,dif_instr_t instr)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
dis_pushts(const dtrace_difo_t * dp,const char * name,dif_instr_t instr)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
dis_xlate(const dtrace_difo_t * dp,const char * name,dif_instr_t instr)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 *
dis_typestr(const dtrace_diftype_t * t,char * buf,size_t len)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
dis(uintptr_t addr,dtrace_difo_t * dp)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
difo(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
difinstr(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
dof_hdr(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
dof_sec_walk(uintptr_t addr,void * ignored,int * sec)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
dof_sec(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
dof_sec_walk_init(mdb_walk_state_t * wsp)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
dof_sec_walk_step(mdb_walk_state_t * wsp)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
dof_sec_walk_fini(mdb_walk_state_t * wsp)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
dof_ecbdesc(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
dof_probedesc(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
dof_actdesc(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
dof_relohdr(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
dof_relodesc(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
dof_sect_strtab(uintptr_t addr,dof_sec_t * sec)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
dof_sect_provider(dof_hdr_t * dofh,uintptr_t addr,dof_sec_t * sec,dof_sec_t * dofs)831 dof_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
962 static int
dof_sect_prargs(uintptr_t addr,dof_sec_t * sec)963 dof_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*/
987 static int
dofdump(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)988 dofdump(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
1040 static 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
1054 static 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
1060 static mdb_modinfo_t modinfo = {
1061 MDB_API_VERSION, NULL, NULL
1062 };
1063
1064 const mdb_modinfo_t *
_mdb_init(void)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
1100 void
_mdb_fini(void)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