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