1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 /*
30 * Multidata dcmds and walkers, part of the genunix mdb module,
31 * and operate on core Multidata structures.
32 */
33
34 #include <mdb/mdb_modapi.h>
35 #include <mdb/mdb_ks.h>
36
37 #include <sys/types.h>
38 #include <sys/strsubr.h>
39 #include <sys/strsun.h>
40 #include <sys/stream.h>
41 #include <sys/modctl.h>
42 #include <sys/strft.h>
43 #include <sys/sysmacros.h>
44
45 #include <sys/multidata.h>
46 #include <sys/multidata_impl.h>
47 #include <sys/pattr.h>
48
49 #include "mmd.h"
50
51 /*
52 * Structure for passing internal variables.
53 */
54 typedef struct mmd_data_s {
55 uint_t flags; /* see flags values below */
56 uint_t counter; /* scratch counter */
57 } mmd_data_t;
58
59 #define MMD_VERBOSE 0x1 /* multidata: provide more info */
60 #define MMD_STATS 0x2 /* multidata: provide statistics */
61 #define PD_HDR 0x4 /* pdesc: count header region */
62 #define PD_PLD 0x8 /* pdesc: count payload region(s) */
63 #define PD_ATTR 0x10 /* pdesc: count local attributes */
64 #define PD_REM_NOCNT 0x20 /* pdesc: do not count removed pdesc */
65
66 /*
67 * Structure to support circular, doubly-linked list (ql_t) walker.
68 */
69 typedef struct q_walk_s {
70 char *qw_name; /* name of opaque list structure */
71 uintptr_t qw_head; /* address of list head */
72 void *qw_data; /* opaque data structure */
73 uint_t qw_sz; /* size of opaque data structure */
74 uint_t qw_off; /* ql_t offset in opaque data structure */
75 uint_t qw_step; /* walk_step has been called */
76 uint_t qw_iprint; /* initial print */
77 } q_walk_t;
78
79 static int pdesc_slab_print(uintptr_t, q_walk_t *, mmd_data_t *);
80 static int pdesc_print(uintptr_t, q_walk_t *, mmd_data_t *);
81 static int pdesc_count(uintptr_t, q_walk_t *, mmd_data_t *);
82 static int pattr_print(uintptr_t, q_walk_t *, mmd_data_t *);
83 static int pattr_count(uintptr_t, q_walk_t *, mmd_data_t *);
84 static int multidata_stats(uintptr_t addr, multidata_t *);
85
86 #define VA_OFF(x, o) (((uchar_t *)(x) + (o)))
87
88 /*
89 * A dcmd which prints a summary of a multidata_t structure.
90 */
91 /* ARGSUSED */
92 int
multidata(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)93 multidata(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
94 {
95 mmd_data_t data;
96 multidata_t mmd;
97 char str[32] = "-";
98 int i = 0;
99
100 bzero(&data, sizeof (data));
101 if (!(flags & DCMD_ADDRSPEC) || mdb_getopts(argc, argv,
102 'v', MDB_OPT_SETBITS, MMD_VERBOSE, &data.flags,
103 's', MDB_OPT_SETBITS, MMD_STATS, &data.flags, NULL) != argc)
104 return (DCMD_USAGE);
105
106 if (mdb_vread(&mmd, sizeof (mmd), addr) == -1) {
107 mdb_warn("failed to read multidata_t structure at %p", addr);
108 return (DCMD_ERR);
109 }
110
111 if (mmd.mmd_magic != MULTIDATA_MAGIC)
112 mdb_printf("Incorrect Multidata magic number at %p\n",
113 VA_OFF(addr, offsetof(multidata_t, mmd_magic)));
114
115 mdb_printf("\n");
116 if (data.flags & MMD_STATS) {
117 if ((i = multidata_stats(addr, &mmd)) != DCMD_OK)
118 return (i);
119 }
120
121 mdb_printf("%<b>%-5s %-?s %-4s %-?s %-4s %-4s %-4s %-?s%</b>",
122 "PDESC", "PATTBL", "HBUF", "HBUF", "PBUF", "PBUF", "PBUF", "PBUF");
123 mdb_printf("\n");
124 mdb_printf("%<b>%<u>%-5s %-?s %-4s %-?s %-4s %-4s %-4s %-?s%</u>%</b>",
125 "CNT", "ADDRESS", "REF", "ADDRESS", "REF", "CNT", "IDX",
126 "ADDRESS(ES)");
127 mdb_printf("\n");
128
129 if (mmd.mmd_pattbl != 0)
130 mdb_snprintf(str, sizeof (str), "%016p", mmd.mmd_pattbl);
131
132 i = 0;
133 mdb_printf("%-5d %-16s %-4d %016p %-4d %-4d %-4d %016p\n",
134 mmd.mmd_pd_cnt, str, mmd.mmd_hbuf_ref, mmd.mmd_hbuf,
135 mmd.mmd_pbuf_ref, mmd.mmd_pbuf_cnt, i, mmd.mmd_pbuf[i]);
136
137 for (++i; i < mmd.mmd_pbuf_cnt; i++)
138 mdb_printf("%-54s %-4d %016p\n", "", i, mmd.mmd_pbuf[i]);
139
140 if (!(data.flags & MMD_VERBOSE))
141 return (DCMD_OK);
142
143 /* Walk packet descriptor slab list */
144 if (mdb_pwalk("pdesc_slab", (mdb_walk_cb_t)pdesc_slab_print,
145 &data, (uintptr_t)VA_OFF(addr, offsetof(multidata_t,
146 mmd_pd_slab_q))) == -1) {
147 mdb_warn("couldn't walk pdesc_slab_t list");
148 return (DCMD_ERR);
149 }
150
151 /* Walk packet descriptor list */
152 data.counter = 0;
153 if (mdb_pwalk("pdesc", (mdb_walk_cb_t)pdesc_print,
154 &data, (uintptr_t)VA_OFF(addr, offsetof(multidata_t,
155 mmd_pd_q))) == -1) {
156 mdb_warn("couldn't walk pdesc_t list");
157 return (DCMD_ERR);
158 }
159
160 return (DCMD_OK);
161 }
162
163 /*
164 * Print additional Multidata statistics
165 */
166 static int
multidata_stats(uintptr_t addr,multidata_t * mmd)167 multidata_stats(uintptr_t addr, multidata_t *mmd)
168 {
169 mblk_t mp;
170 uint_t i = 0, j = 0, k = 0, sz = 0;
171 mmd_data_t data;
172 uintptr_t patbkt;
173
174 bzero(&data, sizeof (data));
175
176 if (mmd->mmd_hbuf != 0) {
177 if (mdb_vread(&mp, sizeof (mp),
178 (uintptr_t)mmd->mmd_hbuf) == -1) {
179 mdb_warn("couldn't read mblk_t at %p", mmd->mmd_hbuf);
180 return (DCMD_ERR);
181 }
182
183 i++;
184 sz = MBLKL(&mp);
185 }
186
187 k += sz; /* total bytes */
188 j += i; /* total buffers */
189
190 mdb_printf("%<b>%<u>BUFFER STATS%</b>%</u>\n");
191 mdb_printf("Header:\t\t\t%-4d% buffer,\t%-12d bytes\n", i, sz);
192
193 for (i = 0, sz = 0; i < mmd->mmd_pbuf_cnt; i++) {
194 if (mdb_vread(&mp, sizeof (mp),
195 (uintptr_t)mmd->mmd_pbuf[i]) == -1) {
196 mdb_warn("couldn't read mblk_t at %p",
197 mmd->mmd_pbuf[i]);
198 return (DCMD_ERR);
199 }
200 sz += MBLKL(&mp);
201 }
202
203 k += sz; /* total bytes */
204 j += i; /* total buffers */
205
206 mdb_printf("%<u>Payload:\t\t%-4d buffers,\t%-12d bytes%</u>\n", i, sz);
207 mdb_printf("Total:\t\t\t%-4d buffers,\t%-12d bytes\n\n", j, k);
208
209 mdb_printf("%<b>%<u>PACKET DESCRIPTOR STATS%</u>%</b>\n");
210
211 /*
212 * Total claimed packet descriptors
213 */
214 data.flags = 0;
215 data.counter = 0;
216 if (mdb_pwalk("pdesc", (mdb_walk_cb_t)pdesc_count, &data,
217 (uintptr_t)VA_OFF(addr, offsetof(multidata_t, mmd_pd_q))) == -1) {
218 mdb_warn("couldn't walk pdesc_t list");
219 return (DCMD_ERR);
220 }
221 i = data.counter; /* claimed */
222 mdb_printf("Total claimed:\t\t%-4d", i);
223
224 /*
225 * Total active header references
226 */
227 data.flags = (PD_HDR | PD_REM_NOCNT);
228 data.counter = 0;
229 if (mdb_pwalk("pdesc", (mdb_walk_cb_t)pdesc_count, &data,
230 (uintptr_t)VA_OFF(addr, offsetof(multidata_t, mmd_pd_q))) == -1) {
231 mdb_warn("couldn't walk pdesc_t list");
232 return (DCMD_ERR);
233 }
234 mdb_printf("\tActive header refs:\t%-12d bytes\n", data.counter);
235
236 /*
237 * Total active packet descriptors
238 */
239 data.flags = PD_REM_NOCNT;
240 data.counter = 0;
241 if (mdb_pwalk("pdesc", (mdb_walk_cb_t)pdesc_count, &data,
242 (uintptr_t)VA_OFF(addr, offsetof(multidata_t, mmd_pd_q))) == -1) {
243 mdb_warn("couldn't walk pdesc_t list");
244 return (DCMD_ERR);
245 }
246 k = data.counter; /* active */
247 mdb_printf("Active:\t\t\t%-4d", data.counter);
248
249 /*
250 * Total active payload references
251 */
252 data.flags = (PD_PLD | PD_REM_NOCNT);
253 data.counter = 0;
254 if (mdb_pwalk("pdesc", (mdb_walk_cb_t)pdesc_count, &data,
255 (uintptr_t)VA_OFF(addr, offsetof(multidata_t, mmd_pd_q))) == -1) {
256 mdb_warn("couldn't walk pdesc_t list");
257 return (DCMD_ERR);
258 }
259 mdb_printf("\t%<u>Active payload refs:\t%-12d bytes%</u>\n",
260 data.counter);
261
262 /*
263 * Number of removed packet descriptors (claimed - active)
264 */
265 mdb_printf("Removed:\t\t%-4d", i - k);
266
267 /*
268 * Total active header and payload references
269 */
270 data.flags = (PD_PLD | PD_HDR | PD_REM_NOCNT);
271 data.counter = 0;
272 if (mdb_pwalk("pdesc", (mdb_walk_cb_t)pdesc_count, &data,
273 (uintptr_t)VA_OFF(addr, offsetof(multidata_t, mmd_pd_q))) == -1) {
274 mdb_warn("couldn't walk pdesc_t list");
275 return (DCMD_ERR);
276 }
277 mdb_printf("\tTotal:\t\t\t%-12d bytes\n\n", data.counter);
278
279 mdb_printf("%<b>%<u>ACTIVE ATTRIBUTE STATS%</u>%</b>\n");
280
281 /*
282 * Count local attributes
283 */
284 data.flags = (PD_ATTR | PD_REM_NOCNT);
285 data.counter = 0;
286 if (mdb_pwalk("pdesc", (mdb_walk_cb_t)pdesc_count, &data,
287 (uintptr_t)VA_OFF(addr, offsetof(multidata_t, mmd_pd_q))) == -1) {
288 mdb_warn("couldn't walk pdesc_t list");
289 return (DCMD_ERR);
290 }
291 mdb_printf("Local:\t\t\t%-4d", data.counter);
292
293 /*
294 * Count global attributes
295 */
296 data.counter = 0;
297 patbkt = (uintptr_t)mmd->mmd_pattbl;
298 if (patbkt != 0) {
299 uint_t pattbl_sz;
300
301 /* Figure out the size of hash table */
302 mdb_readvar(&pattbl_sz, "pattbl_sz");
303
304 /* Walk each bucket and count its contents */
305 for (i = 0; i < (pattbl_sz * sizeof (patbkt_t));
306 i += sizeof (patbkt_t)) {
307 if (mdb_pwalk("pattr",
308 (mdb_walk_cb_t)pattr_count, &data,
309 patbkt + i + offsetof(patbkt_t,
310 pbkt_pattr_q)) == -1) {
311 mdb_warn("couldn't walk pattr_t list");
312 return (DCMD_ERR);
313 }
314 }
315 }
316 mdb_printf("\tGlobal:\t\t\t%-4d\n", data.counter);
317 mdb_printf("\n");
318
319 return (DCMD_OK);
320 }
321
322 /*
323 * Print the contents of a packet descriptor slab (pdesc_slab_t) structure.
324 */
325 /* ARGSUSED */
326 static int
pdesc_slab_print(uintptr_t addr,q_walk_t * qwp,mmd_data_t * data)327 pdesc_slab_print(uintptr_t addr, q_walk_t *qwp, mmd_data_t *data)
328 {
329 pdesc_slab_t *slab;
330 uint_t pdslab_sz, slab_sz;
331
332 /* Figure out how many descriptors in a slab */
333 mdb_readvar(&pdslab_sz, "pdslab_sz");
334
335 /* This shouldn't be true, unless something awful has happened */
336 if (pdslab_sz < 1) {
337 mdb_warn("incorrect pdslab_sz (0)");
338 pdslab_sz = 1;
339 }
340
341 /* Read in the entire slab chunk; may be of use one day */
342 slab_sz = PDESC_SLAB_SIZE(pdslab_sz);
343 slab = mdb_alloc(slab_sz, UM_SLEEP);
344
345 if (mdb_vread(slab, slab_sz, addr) == -1) {
346 mdb_free(slab, slab_sz);
347 mdb_warn("failed to read pdesc_slab_t at %p", addr);
348 return (WALK_ERR);
349 }
350
351 if (!qwp->qw_step)
352 mdb_printf("\n%<b>%<u>%-?s %7s %7s%</u>%</b>\n",
353 "PDESC SLAB ADDR", "SIZE", "CLAIMED");
354
355 mdb_printf("%016p %7d %7d\n", addr, slab->pds_sz, slab->pds_used);
356
357 mdb_free(slab, slab_sz);
358
359 return (WALK_NEXT);
360 }
361
362 /*
363 * Generic packet descriptor (pdesc_t) counting routine.
364 */
365 /* ARGSUSED */
366 static int
pdesc_count(uintptr_t addr,q_walk_t * qwp,mmd_data_t * data)367 pdesc_count(uintptr_t addr, q_walk_t *qwp, mmd_data_t *data)
368 {
369 pdesc_t pd;
370 int i;
371 uint_t f = data->flags;
372
373 if (mdb_vread(&pd, sizeof (pd), addr) == -1) {
374 mdb_warn("failed to read pdesc_t at %p", addr);
375 return (WALK_ERR);
376 }
377
378 if (pd.pd_magic != PDESC_MAGIC)
379 mdb_printf("Incorrect pdesc magic number at %p\n",
380 VA_OFF(addr, offsetof(pdesc_t, pd_magic)));
381
382 if (f == 0) {
383 /* No flags set, count all pdescs */
384 data->counter++;
385 } else if (f == PD_REM_NOCNT && !(pd.pd_pdi.flags & PDESC_REM_DEFER)) {
386 /* Count only active (skip removed) pdescs */
387 data->counter++;
388 } else if (f & PD_ATTR) {
389 uint_t pattbl_sz;
390 uintptr_t patbkt = (uintptr_t)pd.pd_pattbl;
391 mmd_data_t attr_data;
392
393 /* Count local attributes */
394 if ((!(f & PD_REM_NOCNT) || ((f & PD_REM_NOCNT) &&
395 !(pd.pd_pdi.flags & PDESC_REM_DEFER))) && patbkt != 0) {
396
397 /* Figure out the size of hash table */
398 mdb_readvar(&pattbl_sz, "pattbl_sz");
399
400 attr_data.counter = 0;
401 /* Walk each bucket and count its contents */
402 for (i = 0; i < (pattbl_sz * sizeof (patbkt_t));
403 i += sizeof (patbkt_t)) {
404 if (mdb_pwalk("pattr",
405 (mdb_walk_cb_t)pattr_count, &attr_data,
406 patbkt + i + offsetof(patbkt_t,
407 pbkt_pattr_q)) == -1) {
408 mdb_warn("couldn't walk pattr_t list");
409 return (WALK_ERR);
410 }
411 }
412 data->counter += attr_data.counter;
413 }
414 } else {
415 if (f & PD_HDR) {
416 /* Count header span referenced by pdesc */
417 if (!(f & PD_REM_NOCNT) || ((f & PD_REM_NOCNT) &&
418 !(pd.pd_pdi.flags & PDESC_REM_DEFER)))
419 data->counter += PDESC_HDRL(&pd.pd_pdi);
420 }
421
422 if (f & PD_PLD) {
423 /* Count payload span referenced by pdesc */
424 if (!(f & PD_REM_NOCNT) || ((f & PD_REM_NOCNT) &&
425 !(pd.pd_pdi.flags & PDESC_REM_DEFER))) {
426 for (i = 0; i < pd.pd_pdi.pld_cnt; i++)
427 data->counter += PDESC_PLD_SPAN_SIZE(
428 &pd.pd_pdi, i);
429 }
430 }
431 }
432
433 return (WALK_NEXT);
434 }
435
436 /*
437 * Print the contents of a packet descriptor (pdesc_t) structure.
438 */
439 /* ARGSUSED */
440 static int
pdesc_print(uintptr_t addr,q_walk_t * qwp,mmd_data_t * data)441 pdesc_print(uintptr_t addr, q_walk_t *qwp, mmd_data_t *data)
442 {
443 pdesc_t pd;
444 int i = 0;
445 char str[32] = "-";
446 static const mdb_bitmask_t pd_flags_bits[] = {
447 { "H", PDESC_HBUF_REF, PDESC_HBUF_REF },
448 { "P", PDESC_PBUF_REF, PDESC_PBUF_REF },
449 { "R", PDESC_REM_DEFER, PDESC_REM_DEFER },
450 { NULL, 0, 0 }
451 };
452
453 if (mdb_vread(&pd, sizeof (pd), addr) == -1) {
454 mdb_warn("failed to read pdesc_t at %p", addr);
455 return (WALK_ERR);
456 }
457
458 if (pd.pd_magic != PDESC_MAGIC)
459 mdb_printf("Incorrect pdesc magic number at %p\n",
460 VA_OFF(addr, offsetof(pdesc_t, pd_magic)));
461
462 if (!qwp->qw_step) {
463 mdb_printf("\n");
464 mdb_printf("%<b>%-3s %-16s %-16s %-4s %-4s %-4s %-4s %-4s %-4s "
465 "%-4s %-6s%</b>",
466 "", "PDESC", "PATTBL", "HDR", "HDR",
467 "HDR", "HDR", "PLD", "PBUF", "PLD", "");
468 mdb_printf("\n");
469 mdb_printf(
470 "%<b>%<u>%-3s %-16s %-16s %-4s %-4s %-4s %-4s %-4s %-4s "
471 "%-4s %-6s%</u>%</b>",
472 "NO.", "ADDRESS", "ADDRESS", "SIZE", "HEAD",
473 "LEN", "TAIL", "CNT", "IDX", "SIZE", "FLAGS");
474 mdb_printf("\n");
475 }
476
477 if (pd.pd_pattbl != 0)
478 mdb_snprintf(str, sizeof (str), "%016p", pd.pd_pattbl);
479
480 mdb_printf("%-3d %016p %-16s %-4d %-4d %-4d %-4d %-4d %-4d %-4d %-6b\n",
481 ++data->counter, addr, str,
482 PDESC_HDRSIZE(&pd.pd_pdi), PDESC_HDRHEAD(&pd.pd_pdi),
483 PDESC_HDRL(&pd.pd_pdi), PDESC_HDRTAIL(&pd.pd_pdi),
484 pd.pd_pdi.pld_cnt, pd.pd_pdi.pld_ary[i].pld_pbuf_idx,
485 PDESC_PLD_SPAN_SIZE(&pd.pd_pdi, i), pd.pd_pdi.flags, pd_flags_bits);
486
487 for (++i; i < pd.pd_pdi.pld_cnt; i++)
488 mdb_printf("%-62s %-4d %-4d\n",
489 "", pd.pd_pdi.pld_ary[i].pld_pbuf_idx,
490 PDESC_PLD_SPAN_SIZE(&pd.pd_pdi, i));
491
492 return (WALK_NEXT);
493 }
494
495 /*
496 * General purpose ql_t walk_init routine.
497 */
498 static int
mmdq_walk_init(mdb_walk_state_t * wsp,char * name,uintptr_t qh,uint_t sz,uint_t ql_off)499 mmdq_walk_init(mdb_walk_state_t *wsp, char *name, uintptr_t qh,
500 uint_t sz, uint_t ql_off)
501 {
502 q_walk_t *qwp;
503 ql_t ql;
504
505 /* Caller must have supplied an address */
506 if (wsp->walk_addr == NULL)
507 return (WALK_ERR);
508
509 qwp = mdb_alloc(sizeof (*qwp), UM_SLEEP);
510 qwp->qw_name = name;
511 qwp->qw_head = qh;
512 qwp->qw_data = sz > 0 ? mdb_alloc(sz, UM_SLEEP) : NULL;
513 qwp->qw_sz = sz;
514 qwp->qw_off = ql_off;
515 qwp->qw_step = FALSE;
516 qwp->qw_iprint = TRUE;
517
518 wsp->walk_data = qwp;
519
520 if (mdb_vread(qwp->qw_data, qwp->qw_sz, wsp->walk_addr) == -1) {
521 mdb_warn("failed to read %s at %p", qwp->qw_name,
522 wsp->walk_addr);
523 mmdq_walk_fini(wsp);
524 return (WALK_ERR);
525 }
526
527 bcopy((uchar_t *)qwp->qw_data + qwp->qw_off, &ql, sizeof (ql));
528 if (qh == (uintptr_t)ql.ql_next) {
529 mmdq_walk_fini(wsp);
530 return (WALK_DONE);
531 }
532
533 wsp->walk_addr = (uintptr_t)ql.ql_next;
534
535 return (WALK_NEXT);
536 }
537
538 /*
539 * General purpose ql_t walk_step routine.
540 */
541 int
mmdq_walk_step(mdb_walk_state_t * wsp)542 mmdq_walk_step(mdb_walk_state_t *wsp)
543 {
544 q_walk_t *qwp = (q_walk_t *)wsp->walk_data;
545 int status = WALK_NEXT;
546 ql_t ql;
547
548 /* We've wrapped around the circular list */
549 if (qwp->qw_step && wsp->walk_addr == qwp->qw_head)
550 return (WALK_DONE);
551
552 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
553 wsp->walk_cbdata);
554
555 if (mdb_vread(qwp->qw_data, qwp->qw_sz, wsp->walk_addr) == -1) {
556 mdb_warn("failed to read %s at %p", qwp->qw_name,
557 wsp->walk_addr);
558 return (WALK_ERR);
559 }
560
561 /* Go forward to the next one */
562 bcopy((uchar_t *)qwp->qw_data + qwp->qw_off, &ql, sizeof (ql));
563 wsp->walk_addr = (uintptr_t)ql.ql_next;
564
565 /* We've done the first walk */
566 qwp->qw_step = TRUE;
567
568 return (status);
569 }
570
571 /*
572 * General purpose ql_t walk_fini routine.
573 */
574 void
mmdq_walk_fini(mdb_walk_state_t * wsp)575 mmdq_walk_fini(mdb_walk_state_t *wsp)
576 {
577 q_walk_t *qwp = (q_walk_t *)wsp->walk_data;
578
579 if (qwp->qw_data != NULL)
580 mdb_free(qwp->qw_data, qwp->qw_sz);
581
582 mdb_free(qwp, sizeof (*qwp));
583 }
584
585 /*
586 * Packet descriptor slab (pdesc_slab_t) walker initialization routine.
587 */
588 int
pdesc_slab_walk_init(mdb_walk_state_t * wsp)589 pdesc_slab_walk_init(mdb_walk_state_t *wsp)
590 {
591 uintptr_t q_head;
592
593 if (wsp->walk_addr == NULL)
594 return (WALK_DONE);
595
596 /*
597 * If we're called from multidata dcmd, then we're passed in
598 * the address of ql_t head; otherwise we'd have to get the
599 * address ourselves.
600 */
601 if (wsp->walk_cbdata == NULL) {
602 pdesc_slab_t slab;
603
604 /* Read in pdesc_slab_t */
605 if (mdb_vread(&slab, sizeof (slab), wsp->walk_addr) == -1) {
606 mdb_warn("failed to read pdesc_slab_t at %p",
607 wsp->walk_addr);
608 return (WALK_ERR);
609 }
610
611 /* pdesc_slab_t head is inside multidata_t */
612 q_head = (uintptr_t)VA_OFF(slab.pds_mmd,
613 offsetof(multidata_t, mmd_pd_slab_q));
614 } else
615 q_head = wsp->walk_addr;
616
617 /* Pass it on to our generic ql_t walker init */
618 return (mmdq_walk_init(wsp, "pdesc_slab_t", q_head,
619 sizeof (pdesc_slab_t), offsetof(pdesc_slab_t, pds_next)));
620 }
621
622 /*
623 * A dcmd which returns a multidata_t pointer from a pdesc_slab_t structure.
624 */
625 /* ARGSUSED */
626 int
slab2multidata(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)627 slab2multidata(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
628 {
629 pdesc_slab_t slab;
630
631 if (!(flags & DCMD_ADDRSPEC) || argc != 0)
632 return (DCMD_USAGE);
633
634 if (mdb_vread(&slab, sizeof (slab), addr) == -1) {
635 mdb_warn("couldn't read pdesc_slab_t at %p", addr);
636 return (DCMD_ERR);
637 }
638
639 mdb_printf("%p\n", slab.pds_mmd);
640
641 return (DCMD_OK);
642 }
643
644 /*
645 * Packet descriptor (pdesc_t) walker initialization routine.
646 */
647 int
pdesc_walk_init(mdb_walk_state_t * wsp)648 pdesc_walk_init(mdb_walk_state_t *wsp)
649 {
650 uintptr_t q_head;
651
652 if (wsp->walk_addr == NULL)
653 return (WALK_DONE);
654
655 /*
656 * If we're called from multidata dcmd, then we're passed in
657 * the address of ql_t head; otherwise we'd have to get the
658 * address ourselves.
659 */
660 if (wsp->walk_cbdata == NULL) {
661 pdesc_t pd;
662 pdesc_slab_t slab;
663
664 /* First we get pdsec_t */
665 if (mdb_vread(&pd, sizeof (pd), wsp->walk_addr) == -1) {
666 mdb_warn("failed to read pdesc_t at %p",
667 wsp->walk_addr);
668 return (WALK_ERR);
669 }
670
671 /* And then the pdesc_slab_t */
672 if (mdb_vread(&slab, sizeof (slab),
673 (uintptr_t)pd.pd_slab) == -1) {
674 mdb_warn("failed to read pdesc_slab_t at %p",
675 (uintptr_t)pd.pd_slab);
676 return (WALK_ERR);
677 }
678
679 /* pdesc_t head is inside multidata_t */
680 q_head = (uintptr_t)VA_OFF(slab.pds_mmd,
681 offsetof(multidata_t, mmd_pd_q));
682 } else
683 q_head = wsp->walk_addr;
684
685 /* Pass it on to our generic ql_t walker init */
686 return (mmdq_walk_init(wsp, "pdesc_t", q_head,
687 sizeof (pdesc_t), offsetof(pdesc_t, pd_next)));
688 }
689
690 /*
691 * A dcmd which prints the attribute hash table.
692 */
693 /* ARGSUSED */
694 int
pattbl(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)695 pattbl(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
696 {
697 mmd_data_t data;
698 uint_t pattbl_sz;
699 int i, j;
700
701 bzero(&data, sizeof (data));
702 if (!(flags & DCMD_ADDRSPEC) || argc != 0)
703 return (DCMD_USAGE);
704
705 /* Figure out the size of hash table */
706 mdb_readvar(&pattbl_sz, "pattbl_sz");
707
708 mdb_printf("\n");
709 mdb_printf("%<b>%<u>%-3s %-16s %-16s %-12s %-3s %-16s %-5s%</u>%</b>\n",
710 "BKT", "PATBKT ADDR", "PATTR ADDR", "TYPE", "LEN", "BUF ADDR",
711 "FLAGS");
712
713 /* Walk each bucket and print its contents */
714 for (i = 0, j = 0; i < (pattbl_sz * sizeof (patbkt_t));
715 i += sizeof (patbkt_t)) {
716
717 mdb_printf("%-3d %016p ", j++, addr + i);
718
719 if (mdb_pwalk("pattr", (mdb_walk_cb_t)pattr_print, &data,
720 addr + i + offsetof(patbkt_t, pbkt_pattr_q)) == -1) {
721 mdb_warn("couldn't walk pattr_t list");
722 return (DCMD_ERR);
723 }
724 mdb_printf("\n");
725 }
726 mdb_printf("\n");
727
728 return (DCMD_OK);
729 }
730
731 typedef struct pattr_type_s {
732 char *name; /* attribute name */
733 uint_t type; /* attribute type value */
734 } pattr_type_t;
735
736 /*
737 * Generic packet attribute (pattr_t) counting routine.
738 */
739 /* ARGSUSED */
740 static int
pattr_count(uintptr_t addr,q_walk_t * qwp,mmd_data_t * data)741 pattr_count(uintptr_t addr, q_walk_t *qwp, mmd_data_t *data)
742 {
743 pattr_t pattr;
744
745 if (mdb_vread(&pattr, sizeof (pattr), addr) == -1) {
746 mdb_warn("failed to read pattr_t at %p", addr);
747 return (WALK_ERR);
748 }
749
750 if (pattr.pat_magic != PATTR_MAGIC)
751 mdb_printf("Incorrect pattr magic number at %p\n",
752 VA_OFF(addr, offsetof(pattr_t, pat_magic)));
753
754 data->counter++;
755
756 return (WALK_NEXT);
757 }
758
759 /*
760 * Print the contents of a packet attribute (pattr_t) structure.
761 */
762 /* ARGSUSED */
763 static int
pattr_print(uintptr_t addr,q_walk_t * qwp,mmd_data_t * data)764 pattr_print(uintptr_t addr, q_walk_t *qwp, mmd_data_t *data)
765 {
766 pattr_t pattr;
767 int i;
768 char *pa_name = "UNKNOWN";
769 static const pattr_type_t pa_type[] = {
770 { "DSTADDRSAP", PATTR_DSTADDRSAP },
771 { "SRCADDRSAP", PATTR_SRCADDRSAP },
772 { "HCKSUM", PATTR_HCKSUM }
773 };
774 static const mdb_bitmask_t pa_flags_bits[] = {
775 { "R", PATTR_REM_DEFER, PATTR_REM_DEFER },
776 { "P", PATTR_PERSIST, PATTR_PERSIST },
777 { NULL, 0, 0 }
778 };
779
780 if (mdb_vread(&pattr, sizeof (pattr), addr) == -1) {
781 mdb_warn("failed to read pattr_t at %p", addr);
782 return (WALK_ERR);
783 }
784
785 if (pattr.pat_magic != PATTR_MAGIC)
786 mdb_printf("Incorrect pattr magic number at %p\n",
787 VA_OFF(addr, offsetof(pattr_t, pat_magic)));
788
789 /* Find a matching string */
790 for (i = 0; i < (sizeof (pa_type) / sizeof (*pa_type)); i++) {
791 if (pa_type[i].type == pattr.pat_type)
792 pa_name = pa_type[i].name;
793 }
794
795 if (!qwp->qw_iprint) {
796 mdb_printf("\n");
797 mdb_inc_indent(21);
798 }
799
800 mdb_printf("%016p %x:%-10s %-3d %016p %-5b", addr, pattr.pat_type,
801 pa_name, pattr.pat_buflen - sizeof (pattr), addr + sizeof (pattr),
802 pattr.pat_flags, pa_flags_bits);
803
804 if (!qwp->qw_iprint)
805 mdb_dec_indent(21);
806 else
807 qwp->qw_iprint = FALSE;
808
809 return (WALK_NEXT);
810 }
811
812 /*
813 * Packet attribute (pattr_t) walker initialization routine.
814 */
815 int
pattr_walk_init(mdb_walk_state_t * wsp)816 pattr_walk_init(mdb_walk_state_t *wsp)
817 {
818 uintptr_t q_head;
819
820 if (wsp->walk_addr == NULL)
821 return (WALK_DONE);
822
823 /*
824 * If we're called from pattbl dcmd, then we're passed in
825 * the address of ql_t head; otherwise we'd have to get the
826 * address ourselves.
827 */
828 if (wsp->walk_cbdata == NULL) {
829 pattr_t pattr;
830
831 if (mdb_vread(&pattr, sizeof (pattr), wsp->walk_addr) == -1) {
832 mdb_warn("failed to read pattr_t at %p",
833 wsp->walk_addr);
834 return (WALK_ERR);
835 }
836
837 q_head = (uintptr_t)VA_OFF(pattr.pat_lock,
838 -offsetof(patbkt_t, pbkt_lock)) +
839 offsetof(patbkt_t, pbkt_pattr_q);
840 } else
841 q_head = wsp->walk_addr;
842
843 /* Pass it on to our generic ql_t walker init */
844 return (mmdq_walk_init(wsp, "pattr_t", q_head,
845 sizeof (pattr_t), offsetof(pattr_t, pat_next)));
846 }
847
848 /*
849 * A dcmd which returns a multidata_t pointer from a pattr_t.
850 */
851 /* ARGSUSED */
852 int
pattr2multidata(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)853 pattr2multidata(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
854 {
855 pattr_t pattr;
856
857 if (!(flags & DCMD_ADDRSPEC) || argc != 0)
858 return (DCMD_USAGE);
859
860 if (mdb_vread(&pattr, sizeof (pattr), addr) == -1) {
861 mdb_warn("couldn't read pattr_t at %p", addr);
862 return (DCMD_ERR);
863 }
864
865 if (pattr.pat_magic != PATTR_MAGIC) {
866 mdb_warn("Incorrect pattr magic number at %p",
867 VA_OFF(addr, offsetof(pattr_t, pat_magic)));
868 return (DCMD_ERR);
869 }
870
871 mdb_printf("%p\n", pattr.pat_mmd);
872
873 return (DCMD_OK);
874 }
875
876 /*
877 * A dcmd which returns a pdesc_slab_t from a pdesc_t.
878 */
879 /* ARGSUSED */
880 int
pdesc2slab(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)881 pdesc2slab(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
882 {
883 pdesc_t pd;
884
885 if (!(flags & DCMD_ADDRSPEC) || argc != 0)
886 return (DCMD_USAGE);
887
888 if (mdb_vread(&pd, sizeof (pd), addr) == -1) {
889 mdb_warn("couldn't read pdesc_t at %p", addr);
890 return (DCMD_ERR);
891 }
892
893 if (pd.pd_magic != PDESC_MAGIC) {
894 mdb_warn("Incorrect pdesc magic number at %p",
895 VA_OFF(addr, offsetof(pdesc_t, pd_magic)));
896 return (DCMD_ERR);
897 }
898
899 mdb_printf("%p\n", pd.pd_slab);
900
901 return (DCMD_OK);
902 }
903
904 /*
905 * A dcmd which verifies the integrity of a pdesc_t.
906 */
907 /* ARGSUSED */
908 int
pdesc_verify(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)909 pdesc_verify(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
910 {
911 multidata_t mmd;
912 pdesc_t pd;
913 pdescinfo_t *pdi = &pd.pd_pdi;
914 pdesc_slab_t slab;
915 mblk_t hbuf, pbuf[MULTIDATA_MAX_PBUFS];
916 uint_t i, idx;
917 boolean_t valid = B_TRUE;
918 struct pld_ary_s *pa;
919
920 if (!(flags & DCMD_ADDRSPEC) || argc != 0)
921 return (DCMD_USAGE);
922
923 if (mdb_vread(&pd, sizeof (pd), addr) == -1) {
924 mdb_warn("couldn't read pdesc_t at %p", addr);
925 return (DCMD_ERR);
926 }
927
928 if (pd.pd_magic != PDESC_MAGIC) {
929 mdb_warn("Incorrect pdesc magic number at %p\n",
930 VA_OFF(addr, offsetof(pdesc_t, pd_magic)));
931 return (DCMD_ERR);
932 }
933
934 if (mdb_vread(&slab, sizeof (slab), (uintptr_t)pd.pd_slab) == -1) {
935 mdb_warn("couldn't read pdesc_slab_t at %p", pd.pd_slab);
936 return (DCMD_ERR);
937 }
938
939 if (mdb_vread(&mmd, sizeof (mmd), (uintptr_t)slab.pds_mmd) == -1) {
940 mdb_warn("couldn't read multidata_t at %p", slab.pds_mmd);
941 return (DCMD_ERR);
942 }
943
944 if (mmd.mmd_magic != MULTIDATA_MAGIC)
945 mdb_printf("Incorrect Multidata magic number at %p\n",
946 VA_OFF(slab.pds_mmd, offsetof(multidata_t, mmd_magic)));
947
948 if (mmd.mmd_hbuf != 0 &&
949 mdb_vread(&hbuf, sizeof (hbuf), (uintptr_t)mmd.mmd_hbuf) == -1) {
950 mdb_warn("couldn't read mblk_t at %p", mmd.mmd_hbuf);
951 return (DCMD_ERR);
952 }
953
954 if (mmd.mmd_pbuf_cnt > MULTIDATA_MAX_PBUFS) {
955 mdb_warn("Multidata pbuf count exceeds %d\n",
956 MULTIDATA_MAX_PBUFS);
957 return (DCMD_ERR);
958 } else if (pdi->pld_cnt > mmd.mmd_pbuf_cnt) {
959 mdb_warn("descriptor pbuf count exceeds Multidata "
960 "pbuf count %d\n", mmd.mmd_pbuf_cnt);
961 return (DCMD_ERR);
962 }
963
964 if (mmd.mmd_pbuf_cnt > 0) {
965 for (i = 0; i < mmd.mmd_pbuf_cnt; i++) {
966 if (mdb_vread(&pbuf[i], sizeof (mblk_t),
967 (uintptr_t)mmd.mmd_pbuf[i]) == -1) {
968 mdb_warn("couldn't read mblk_t at %p",
969 mmd.mmd_pbuf[i]);
970 return (DCMD_ERR);
971 }
972 }
973 }
974
975 /* It should have at least one buffer reference */
976 if (!(pdi->flags & PDESC_HAS_REF)) {
977 mdb_warn("descriptor has no buffer reference indicator "
978 "in flags (0x%x)\n", pdi->flags);
979 return (DCMD_ERR);
980 } else if (!(pdi->flags & PDESC_PBUF_REF) && pdi->pld_cnt > 0) {
981 mdb_warn("descriptor has no pbuf reference indicator in "
982 "flags (0x%x); but pld_cnt is %d\n", pdi->flags,
983 pdi->pld_cnt);
984 return (DCMD_ERR);
985 }
986
987 /* Bounds check the header fragment, if any */
988 if (!((pdi->flags & PDESC_HBUF_REF) && pdi->hdr_rptr != 0 &&
989 pdi->hdr_wptr != 0 && pdi->hdr_base != 0 &&
990 pdi->hdr_lim != 0 && pdi->hdr_lim >= pdi->hdr_base &&
991 pdi->hdr_wptr >= pdi->hdr_rptr && pdi->hdr_base <= pdi->hdr_rptr &&
992 pdi->hdr_lim >= pdi->hdr_wptr && pdi->hdr_base >= hbuf.b_rptr &&
993 MBLKIN(&hbuf, (pdi->hdr_base - hbuf.b_rptr),
994 PDESC_HDRSIZE(pdi)))) {
995 mdb_warn("descriptor has invalid header fragment\n");
996 return (DCMD_ERR);
997 }
998
999 i = 0;
1000 pa = &pdi->pld_ary[0];
1001 /* Bounds check the payload fragment, if any */
1002 while (valid && i < pdi->pld_cnt) {
1003 valid = (((idx = pa->pld_pbuf_idx) < mmd.mmd_pbuf_cnt) &&
1004 pa->pld_rptr != NULL && pa->pld_wptr != NULL &&
1005 pa->pld_wptr >= pa->pld_rptr &&
1006 pa->pld_rptr >= pbuf[idx].b_rptr &&
1007 MBLKIN(&pbuf[idx], (pa->pld_rptr - pbuf[idx].b_rptr),
1008 PDESC_PLD_SPAN_SIZE(pdi, i)));
1009
1010 if (!valid) {
1011 mdb_warn("descriptor has invalid payload fragment\n");
1012 return (DCMD_ERR);
1013 }
1014
1015 /* advance to next entry */
1016 i++;
1017 pa++;
1018 }
1019
1020 return (DCMD_OK);
1021 }
1022