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 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/types.h> 29 #include <sys/stropts.h> 30 #include <sys/stream.h> 31 #include <sys/socket.h> 32 #include <sys/avl_impl.h> 33 #include <net/if.h> 34 #include <net/route.h> 35 #include <netinet/in.h> 36 #include <netinet/ip6.h> 37 #include <netinet/udp.h> 38 #include <netinet/sctp.h> 39 #include <inet/mib2.h> 40 #include <inet/common.h> 41 #include <inet/ip.h> 42 #include <inet/ip_ire.h> 43 #include <inet/ip6.h> 44 #include <inet/ipclassifier.h> 45 #include <inet/mi.h> 46 #include <sys/squeue_impl.h> 47 #include <sys/modhash_impl.h> 48 49 #include <mdb/mdb_modapi.h> 50 #include <mdb/mdb_ks.h> 51 52 #define ADDR_WIDTH 11 53 54 typedef struct { 55 const char *bit_name; /* name of bit */ 56 const char *bit_descr; /* description of bit's purpose */ 57 } bitname_t; 58 59 static const bitname_t squeue_states[] = { 60 { "SQS_PROC", "being processed" }, 61 { "SQS_WORKER", "... by a worker thread" }, 62 { "SQS_ENTER", "... by an squeue_enter() thread" }, 63 { "SQS_FAST", "... in fast-path mode" }, 64 { "SQS_USER", "A non interrupt user" }, 65 { "SQS_BOUND", "worker thread bound to CPU" }, 66 { "SQS_PROFILE", "profiling enabled" }, 67 { "SQS_REENTER", "re-entered thred" }, 68 { NULL } 69 }; 70 71 typedef struct illif_walk_data { 72 ill_g_head_t ill_g_heads[MAX_G_HEADS]; 73 int ill_list; 74 ill_if_t ill_if; 75 } illif_walk_data_t; 76 77 typedef struct th_walk_data { 78 uint_t thw_non_zero_only; 79 boolean_t thw_match; 80 uintptr_t thw_matchkey; 81 uintptr_t thw_ipst; 82 clock_t thw_lbolt; 83 } th_walk_data_t; 84 85 static int iphdr(uintptr_t, uint_t, int, const mdb_arg_t *); 86 static int ip6hdr(uintptr_t, uint_t, int, const mdb_arg_t *); 87 88 static int ire_format(uintptr_t addr, const ire_t *irep, uint_t *verbose); 89 90 /* 91 * Given the kernel address of an ip_stack_t, return the stackid 92 */ 93 static int 94 ips_to_stackid(uintptr_t kaddr) 95 { 96 ip_stack_t ipss; 97 netstack_t nss; 98 99 if (mdb_vread(&ipss, sizeof (ipss), kaddr) == -1) { 100 mdb_warn("failed to read ip_stack_t %p", kaddr); 101 return (0); 102 } 103 kaddr = (uintptr_t)ipss.ips_netstack; 104 if (mdb_vread(&nss, sizeof (nss), kaddr) == -1) { 105 mdb_warn("failed to read netstack_t %p", kaddr); 106 return (0); 107 } 108 return (nss.netstack_stackid); 109 } 110 111 int 112 ip_stacks_walk_init(mdb_walk_state_t *wsp) 113 { 114 if (mdb_layered_walk("netstack", wsp) == -1) { 115 mdb_warn("can't walk 'netstack'"); 116 return (WALK_ERR); 117 } 118 return (WALK_NEXT); 119 } 120 121 int 122 ip_stacks_walk_step(mdb_walk_state_t *wsp) 123 { 124 uintptr_t kaddr; 125 netstack_t nss; 126 127 #ifdef DEBUG 128 mdb_printf("DEBUG: ip_stacks_walk_step: addr %p\n", wsp->walk_addr); 129 #endif 130 if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) { 131 mdb_warn("can't read netstack at %p", wsp->walk_addr); 132 return (WALK_ERR); 133 } 134 kaddr = (uintptr_t)nss.netstack_modules[NS_IP]; 135 136 #ifdef DEBUG 137 mdb_printf("DEBUG: ip_stacks_walk_step: ip_stack_t at %p\n", kaddr); 138 #endif 139 return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata)); 140 } 141 142 int 143 th_hash_walk_init(mdb_walk_state_t *wsp) 144 { 145 GElf_Sym sym; 146 list_node_t *next; 147 148 if (wsp->walk_addr == NULL) { 149 if (mdb_lookup_by_obj("ip", "ip_thread_list", &sym) == 0) { 150 wsp->walk_addr = sym.st_value; 151 } else { 152 mdb_warn("unable to locate ip_thread_list\n"); 153 return (WALK_ERR); 154 } 155 } 156 157 if (mdb_vread(&next, sizeof (next), 158 wsp->walk_addr + offsetof(list_t, list_head) + 159 offsetof(list_node_t, list_next)) == -1 || 160 next == NULL) { 161 mdb_warn("non-DEBUG image; cannot walk th_hash list\n"); 162 return (WALK_ERR); 163 } 164 165 if (mdb_layered_walk("list", wsp) == -1) { 166 mdb_warn("can't walk 'list'"); 167 return (WALK_ERR); 168 } else { 169 return (WALK_NEXT); 170 } 171 } 172 173 int 174 th_hash_walk_step(mdb_walk_state_t *wsp) 175 { 176 return (wsp->walk_callback(wsp->walk_addr, wsp->walk_layer, 177 wsp->walk_cbdata)); 178 } 179 180 /* 181 * Called with walk_addr being the address of ips_ill_g_heads 182 */ 183 int 184 illif_stack_walk_init(mdb_walk_state_t *wsp) 185 { 186 illif_walk_data_t *iw; 187 188 if (wsp->walk_addr == NULL) { 189 mdb_warn("illif_stack supports only local walks\n"); 190 return (WALK_ERR); 191 } 192 193 iw = mdb_alloc(sizeof (illif_walk_data_t), UM_SLEEP); 194 195 if (mdb_vread(iw->ill_g_heads, MAX_G_HEADS * sizeof (ill_g_head_t), 196 wsp->walk_addr) == -1) { 197 mdb_warn("failed to read 'ips_ill_g_heads' at %p", 198 wsp->walk_addr); 199 mdb_free(iw, sizeof (illif_walk_data_t)); 200 return (WALK_ERR); 201 } 202 203 iw->ill_list = 0; 204 wsp->walk_addr = (uintptr_t)iw->ill_g_heads[0].ill_g_list_head; 205 wsp->walk_data = iw; 206 207 return (WALK_NEXT); 208 } 209 210 int 211 illif_stack_walk_step(mdb_walk_state_t *wsp) 212 { 213 uintptr_t addr = wsp->walk_addr; 214 illif_walk_data_t *iw = wsp->walk_data; 215 int list = iw->ill_list; 216 217 if (mdb_vread(&iw->ill_if, sizeof (ill_if_t), addr) == -1) { 218 mdb_warn("failed to read ill_if_t at %p", addr); 219 return (WALK_ERR); 220 } 221 222 wsp->walk_addr = (uintptr_t)iw->ill_if.illif_next; 223 224 if (wsp->walk_addr == 225 (uintptr_t)iw->ill_g_heads[list].ill_g_list_head) { 226 227 if (++list >= MAX_G_HEADS) 228 return (WALK_DONE); 229 230 iw->ill_list = list; 231 wsp->walk_addr = 232 (uintptr_t)iw->ill_g_heads[list].ill_g_list_head; 233 return (WALK_NEXT); 234 } 235 236 return (wsp->walk_callback(addr, iw, wsp->walk_cbdata)); 237 } 238 239 void 240 illif_stack_walk_fini(mdb_walk_state_t *wsp) 241 { 242 mdb_free(wsp->walk_data, sizeof (illif_walk_data_t)); 243 } 244 245 typedef struct illif_cbdata { 246 uint_t ill_flags; 247 uintptr_t ill_addr; 248 int ill_printlist; /* list to be printed (MAX_G_HEADS for all) */ 249 boolean_t ill_printed; 250 } illif_cbdata_t; 251 252 static int 253 illif_cb(uintptr_t addr, const illif_walk_data_t *iw, illif_cbdata_t *id) 254 { 255 const char *version; 256 257 if (id->ill_printlist < MAX_G_HEADS && 258 id->ill_printlist != iw->ill_list) 259 return (WALK_NEXT); 260 261 if (id->ill_flags & DCMD_ADDRSPEC && id->ill_addr != addr) 262 return (WALK_NEXT); 263 264 if (id->ill_flags & DCMD_PIPE_OUT) { 265 mdb_printf("%p\n", addr); 266 return (WALK_NEXT); 267 } 268 269 switch (iw->ill_list) { 270 case IP_V4_G_HEAD: version = "v4"; break; 271 case IP_V6_G_HEAD: version = "v6"; break; 272 default: version = "??"; break; 273 } 274 275 mdb_printf("%?p %2s %?p %10d %?p %s\n", 276 addr, version, addr + offsetof(ill_if_t, illif_avl_by_ppa), 277 iw->ill_if.illif_avl_by_ppa.avl_numnodes, 278 iw->ill_if.illif_ppa_arena, iw->ill_if.illif_name); 279 280 id->ill_printed = TRUE; 281 282 return (WALK_NEXT); 283 } 284 285 int 286 illif_walk_init(mdb_walk_state_t *wsp) 287 { 288 if (mdb_layered_walk("ip_stacks", wsp) == -1) { 289 mdb_warn("can't walk 'ip_stacks'"); 290 return (WALK_ERR); 291 } 292 293 return (WALK_NEXT); 294 } 295 296 int 297 illif_walk_step(mdb_walk_state_t *wsp) 298 { 299 uintptr_t kaddr; 300 301 #ifdef DEBUG 302 mdb_printf("DEBUG: illif_walk_step: addr %p\n", wsp->walk_addr); 303 #endif 304 305 kaddr = wsp->walk_addr + OFFSETOF(ip_stack_t, ips_ill_g_heads); 306 307 if (mdb_vread(&kaddr, sizeof (kaddr), kaddr) == -1) { 308 mdb_warn("can't read ips_ip_cache_table at %p", kaddr); 309 return (WALK_ERR); 310 } 311 #ifdef DEBUG 312 mdb_printf("DEBUG: illif_walk_step: ips_ill_g_heads %p\n", kaddr); 313 #endif 314 315 if (mdb_pwalk("illif_stack", wsp->walk_callback, 316 wsp->walk_cbdata, kaddr) == -1) { 317 mdb_warn("couldn't walk 'illif_stack' for ips_ill_g_heads %p", 318 kaddr); 319 return (WALK_ERR); 320 } 321 return (WALK_NEXT); 322 } 323 324 int 325 illif(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 326 { 327 illif_cbdata_t id; 328 ill_if_t ill_if; 329 const char *opt_P = NULL; 330 int printlist = MAX_G_HEADS; 331 332 if (mdb_getopts(argc, argv, 333 'P', MDB_OPT_STR, &opt_P, NULL) != argc) 334 return (DCMD_USAGE); 335 336 if (opt_P != NULL) { 337 if (strcmp("v4", opt_P) == 0) { 338 printlist = IP_V4_G_HEAD; 339 } else if (strcmp("v6", opt_P) == 0) { 340 printlist = IP_V6_G_HEAD; 341 } else { 342 mdb_warn("invalid protocol '%s'\n", opt_P); 343 return (DCMD_USAGE); 344 } 345 } 346 347 if (DCMD_HDRSPEC(flags) && (flags & DCMD_PIPE_OUT) == 0) { 348 mdb_printf("%<u>%?s %2s %?s %10s %?s %-10s%</u>\n", 349 "ADDR", "IP", "AVLADDR", "NUMNODES", "ARENA", "NAME"); 350 } 351 352 id.ill_flags = flags; 353 id.ill_addr = addr; 354 id.ill_printlist = printlist; 355 id.ill_printed = FALSE; 356 357 if (mdb_walk("illif", (mdb_walk_cb_t)illif_cb, &id) == -1) { 358 mdb_warn("can't walk ill_if_t structures"); 359 return (DCMD_ERR); 360 } 361 362 if (!(flags & DCMD_ADDRSPEC) || opt_P != NULL || id.ill_printed) 363 return (DCMD_OK); 364 365 /* 366 * If an address is specified and the walk doesn't find it, 367 * print it anyway. 368 */ 369 if (mdb_vread(&ill_if, sizeof (ill_if_t), addr) == -1) { 370 mdb_warn("failed to read ill_if_t at %p", addr); 371 return (DCMD_ERR); 372 } 373 374 mdb_printf("%?p %2s %?p %10d %?p %s\n", 375 addr, "??", addr + offsetof(ill_if_t, illif_avl_by_ppa), 376 ill_if.illif_avl_by_ppa.avl_numnodes, 377 ill_if.illif_ppa_arena, ill_if.illif_name); 378 379 return (DCMD_OK); 380 } 381 382 static void 383 illif_help(void) 384 { 385 mdb_printf("Options:\n"); 386 mdb_printf("\t-P v4 | v6" 387 "\tfilter interface structures for the specified protocol\n"); 388 } 389 390 int 391 ire_walk_init(mdb_walk_state_t *wsp) 392 { 393 if (mdb_layered_walk("ire_cache", wsp) == -1) { 394 mdb_warn("can't walk 'ire_cache'"); 395 return (WALK_ERR); 396 } 397 398 return (WALK_NEXT); 399 } 400 401 int 402 ire_walk_step(mdb_walk_state_t *wsp) 403 { 404 ire_t ire; 405 406 if (mdb_vread(&ire, sizeof (ire), wsp->walk_addr) == -1) { 407 mdb_warn("can't read ire at %p", wsp->walk_addr); 408 return (WALK_ERR); 409 } 410 411 return (wsp->walk_callback(wsp->walk_addr, &ire, wsp->walk_cbdata)); 412 } 413 414 int 415 ire_ctable_walk_init(mdb_walk_state_t *wsp) 416 { 417 if (mdb_layered_walk("ip_stacks", wsp) == -1) { 418 mdb_warn("can't walk 'ip_stacks'"); 419 return (WALK_ERR); 420 } 421 422 return (WALK_NEXT); 423 } 424 425 int 426 ire_ctable_walk_step(mdb_walk_state_t *wsp) 427 { 428 uintptr_t kaddr; 429 irb_t *irb; 430 int verbose = 0; 431 uint32_t cache_table_size; 432 int i; 433 434 #ifdef DEBUG 435 mdb_printf("DEBUG: ire_ctable_walk_step: addr %p\n", wsp->walk_addr); 436 #endif 437 438 kaddr = wsp->walk_addr + OFFSETOF(ip_stack_t, ips_ip_cache_table_size); 439 440 if (mdb_vread(&cache_table_size, sizeof (uint32_t), kaddr) == -1) { 441 mdb_warn("can't read ips_ip_cache_table at %p", kaddr); 442 return (WALK_ERR); 443 } 444 #ifdef DEBUG 445 mdb_printf("DEBUG: ire_ctable_walk_step: ips_ip_cache_table_size %u\n", 446 cache_table_size); 447 #endif 448 449 kaddr = wsp->walk_addr + OFFSETOF(ip_stack_t, ips_ip_cache_table); 450 if (mdb_vread(&kaddr, sizeof (kaddr), kaddr) == -1) { 451 mdb_warn("can't read ips_ip_cache_table at %p", kaddr); 452 return (WALK_ERR); 453 } 454 #ifdef DEBUG 455 mdb_printf("DEBUG: ire_ctable_walk_step: ips_ip_cache_table %p\n", 456 kaddr); 457 #endif 458 459 irb = mdb_alloc(sizeof (irb_t) * cache_table_size, UM_SLEEP|UM_GC); 460 if (mdb_vread(irb, sizeof (irb_t) * cache_table_size, kaddr) == -1) { 461 mdb_warn("can't read irb at %p", kaddr); 462 return (WALK_ERR); 463 } 464 for (i = 0; i < cache_table_size; i++) { 465 kaddr = (uintptr_t)irb[i].irb_ire; 466 #ifdef DEBUG 467 mdb_printf("DEBUG: ire_ctable_walk_step: %d ire %p\n", 468 i, kaddr); 469 #endif 470 471 if (mdb_pwalk("ire_next", (mdb_walk_cb_t)ire_format, &verbose, 472 kaddr) == -1) { 473 mdb_warn("can't walk 'ire_next' for ire %p", kaddr); 474 return (WALK_ERR); 475 } 476 } 477 return (WALK_NEXT); 478 } 479 480 /* ARGSUSED */ 481 int 482 ire_next_walk_init(mdb_walk_state_t *wsp) 483 { 484 #ifdef DEBUG 485 mdb_printf("DEBUG: ire_next_walk_init: addr %p\n", wsp->walk_addr); 486 #endif 487 return (WALK_NEXT); 488 } 489 490 int 491 ire_next_walk_step(mdb_walk_state_t *wsp) 492 { 493 ire_t ire; 494 int status; 495 496 #ifdef DEBUG 497 mdb_printf("DEBUG: ire_next_walk_step: addr %p\n", wsp->walk_addr); 498 #endif 499 500 if (wsp->walk_addr == NULL) 501 return (WALK_DONE); 502 503 if (mdb_vread(&ire, sizeof (ire), wsp->walk_addr) == -1) { 504 mdb_warn("can't read ire at %p", wsp->walk_addr); 505 return (WALK_ERR); 506 } 507 status = wsp->walk_callback(wsp->walk_addr, &ire, 508 wsp->walk_cbdata); 509 510 if (status != WALK_NEXT) 511 return (status); 512 513 wsp->walk_addr = (uintptr_t)ire.ire_next; 514 #ifdef DEBUG 515 mdb_printf("DEBUG: ire_ctable_walk_step: next %p\n", wsp->walk_addr); 516 #endif 517 return (status); 518 } 519 520 static int 521 ire_format(uintptr_t addr, const ire_t *irep, uint_t *verbose) 522 { 523 static const mdb_bitmask_t tmasks[] = { 524 { "BROADCAST", IRE_BROADCAST, IRE_BROADCAST }, 525 { "DEFAULT", IRE_DEFAULT, IRE_DEFAULT }, 526 { "LOCAL", IRE_LOCAL, IRE_LOCAL }, 527 { "LOOPBACK", IRE_LOOPBACK, IRE_LOOPBACK }, 528 { "PREFIX", IRE_PREFIX, IRE_PREFIX }, 529 { "CACHE", IRE_CACHE, IRE_CACHE }, 530 { "IF_NORESOLVER", IRE_IF_NORESOLVER, IRE_IF_NORESOLVER }, 531 { "IF_RESOLVER", IRE_IF_RESOLVER, IRE_IF_RESOLVER }, 532 { "HOST", IRE_HOST, IRE_HOST }, 533 { "HOST_REDIRECT", IRE_HOST_REDIRECT, IRE_HOST_REDIRECT }, 534 { NULL, 0, 0 } 535 }; 536 537 static const mdb_bitmask_t mmasks[] = { 538 { "CONDEMNED", IRE_MARK_CONDEMNED, IRE_MARK_CONDEMNED }, 539 { "NORECV", IRE_MARK_NORECV, IRE_MARK_NORECV }, 540 { "HIDDEN", IRE_MARK_HIDDEN, IRE_MARK_HIDDEN }, 541 { "NOADD", IRE_MARK_NOADD, IRE_MARK_NOADD }, 542 { "TEMPORARY", IRE_MARK_TEMPORARY, IRE_MARK_TEMPORARY }, 543 { NULL, 0, 0 } 544 }; 545 546 static const mdb_bitmask_t fmasks[] = { 547 { "UP", RTF_UP, RTF_UP }, 548 { "GATEWAY", RTF_GATEWAY, RTF_GATEWAY }, 549 { "HOST", RTF_HOST, RTF_HOST }, 550 { "REJECT", RTF_REJECT, RTF_REJECT }, 551 { "DYNAMIC", RTF_DYNAMIC, RTF_DYNAMIC }, 552 { "MODIFIED", RTF_MODIFIED, RTF_MODIFIED }, 553 { "DONE", RTF_DONE, RTF_DONE }, 554 { "MASK", RTF_MASK, RTF_MASK }, 555 { "CLONING", RTF_CLONING, RTF_CLONING }, 556 { "XRESOLVE", RTF_XRESOLVE, RTF_XRESOLVE }, 557 { "LLINFO", RTF_LLINFO, RTF_LLINFO }, 558 { "STATIC", RTF_STATIC, RTF_STATIC }, 559 { "BLACKHOLE", RTF_BLACKHOLE, RTF_BLACKHOLE }, 560 { "PRIVATE", RTF_PRIVATE, RTF_PRIVATE }, 561 { "PROTO2", RTF_PROTO2, RTF_PROTO2 }, 562 { "PROTO1", RTF_PROTO1, RTF_PROTO1 }, 563 { "MULTIRT", RTF_MULTIRT, RTF_MULTIRT }, 564 { "SETSRC", RTF_SETSRC, RTF_SETSRC }, 565 { NULL, 0, 0 } 566 }; 567 568 if (irep->ire_ipversion == 6 && *verbose) { 569 570 mdb_printf("%<b>%?p%</b> %40N <%hb>\n" 571 "%?s %40N <%hb>\n" 572 "%?s %40d %4d <%hb>\n", 573 addr, &irep->ire_src_addr_v6, irep->ire_type, tmasks, 574 "", &irep->ire_addr_v6, (ushort_t)irep->ire_marks, mmasks, 575 "", ips_to_stackid((uintptr_t)irep->ire_ipst), 576 irep->ire_zoneid, 577 irep->ire_flags, fmasks); 578 579 } else if (irep->ire_ipversion == 6) { 580 581 mdb_printf("%?p %30N %30N %5d %4d\n", 582 addr, &irep->ire_src_addr_v6, 583 &irep->ire_addr_v6, 584 ips_to_stackid((uintptr_t)irep->ire_ipst), 585 irep->ire_zoneid); 586 587 } else if (*verbose) { 588 589 mdb_printf("%<b>%?p%</b> %40I <%hb>\n" 590 "%?s %40I <%hb>\n" 591 "%?s %40d <%hb>\n", 592 addr, irep->ire_src_addr, irep->ire_type, tmasks, 593 "", irep->ire_addr, (ushort_t)irep->ire_marks, mmasks, 594 "", ips_to_stackid((uintptr_t)irep->ire_ipst), 595 irep->ire_zoneid, irep->ire_flags, fmasks); 596 597 } else { 598 599 mdb_printf("%?p %30I %30I %5d %4d\n", addr, irep->ire_src_addr, 600 irep->ire_addr, ips_to_stackid((uintptr_t)irep->ire_ipst), 601 irep->ire_zoneid); 602 } 603 604 return (WALK_NEXT); 605 } 606 607 /* 608 * There are faster ways to do this. Given the interactive nature of this 609 * use I don't think its worth much effort. 610 */ 611 static unsigned short 612 ipcksum(void *p, int len) 613 { 614 int32_t sum = 0; 615 616 while (len > 1) { 617 /* alignment */ 618 sum += *(uint16_t *)p; 619 p = (char *)p + sizeof (uint16_t); 620 if (sum & 0x80000000) 621 sum = (sum & 0xFFFF) + (sum >> 16); 622 len -= 2; 623 } 624 625 if (len) 626 sum += (uint16_t)*(unsigned char *)p; 627 628 while (sum >> 16) 629 sum = (sum & 0xFFFF) + (sum >> 16); 630 631 return (~sum); 632 } 633 634 static const mdb_bitmask_t tcp_flags[] = { 635 { "SYN", TH_SYN, TH_SYN }, 636 { "ACK", TH_ACK, TH_ACK }, 637 { "FIN", TH_FIN, TH_FIN }, 638 { "RST", TH_RST, TH_RST }, 639 { "PSH", TH_PUSH, TH_PUSH }, 640 { "ECE", TH_ECE, TH_ECE }, 641 { "CWR", TH_CWR, TH_CWR }, 642 { NULL, 0, 0 } 643 }; 644 645 static void 646 tcphdr_print(struct tcphdr *tcph) 647 { 648 in_port_t sport, dport; 649 tcp_seq seq, ack; 650 uint16_t win, urp; 651 652 mdb_printf("%<b>TCP header%</b>\n"); 653 654 mdb_nhconvert(&sport, &tcph->th_sport, sizeof (sport)); 655 mdb_nhconvert(&dport, &tcph->th_dport, sizeof (dport)); 656 mdb_nhconvert(&seq, &tcph->th_seq, sizeof (seq)); 657 mdb_nhconvert(&ack, &tcph->th_ack, sizeof (ack)); 658 mdb_nhconvert(&win, &tcph->th_win, sizeof (win)); 659 mdb_nhconvert(&urp, &tcph->th_urp, sizeof (urp)); 660 661 mdb_printf("%<u>%6s %6s %10s %10s %4s %5s %5s %5s %-15s%</u>\n", 662 "SPORT", "DPORT", "SEQ", "ACK", "HLEN", "WIN", "CSUM", "URP", 663 "FLAGS"); 664 mdb_printf("%6hu %6hu %10u %10u %4d %5hu %5hu %5hu <%b>\n", 665 sport, dport, seq, ack, tcph->th_off << 2, win, 666 tcph->th_sum, urp, tcph->th_flags, tcp_flags); 667 mdb_printf("0x%04x 0x%04x 0x%08x 0x%08x\n\n", 668 sport, dport, seq, ack); 669 } 670 671 /* ARGSUSED */ 672 static int 673 tcphdr(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av) 674 { 675 struct tcphdr tcph; 676 677 if (!(flags & DCMD_ADDRSPEC)) 678 return (DCMD_USAGE); 679 680 if (mdb_vread(&tcph, sizeof (tcph), addr) == -1) { 681 mdb_warn("failed to read TCP header at %p", addr); 682 return (DCMD_ERR); 683 } 684 tcphdr_print(&tcph); 685 return (DCMD_OK); 686 } 687 688 static void 689 udphdr_print(struct udphdr *udph) 690 { 691 in_port_t sport, dport; 692 uint16_t hlen; 693 694 mdb_printf("%<b>UDP header%</b>\n"); 695 696 mdb_nhconvert(&sport, &udph->uh_sport, sizeof (sport)); 697 mdb_nhconvert(&dport, &udph->uh_dport, sizeof (dport)); 698 mdb_nhconvert(&hlen, &udph->uh_ulen, sizeof (hlen)); 699 700 mdb_printf("%<u>%14s %14s %5s %6s%</u>\n", 701 "SPORT", "DPORT", "LEN", "CSUM"); 702 mdb_printf("%5hu (0x%04x) %5hu (0x%04x) %5hu 0x%04hx\n\n", sport, sport, 703 dport, dport, hlen, udph->uh_sum); 704 } 705 706 /* ARGSUSED */ 707 static int 708 udphdr(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av) 709 { 710 struct udphdr udph; 711 712 if (!(flags & DCMD_ADDRSPEC)) 713 return (DCMD_USAGE); 714 715 if (mdb_vread(&udph, sizeof (udph), addr) == -1) { 716 mdb_warn("failed to read UDP header at %p", addr); 717 return (DCMD_ERR); 718 } 719 udphdr_print(&udph); 720 return (DCMD_OK); 721 } 722 723 static void 724 sctphdr_print(sctp_hdr_t *sctph) 725 { 726 in_port_t sport, dport; 727 728 mdb_printf("%<b>SCTP header%</b>\n"); 729 mdb_nhconvert(&sport, &sctph->sh_sport, sizeof (sport)); 730 mdb_nhconvert(&dport, &sctph->sh_dport, sizeof (dport)); 731 732 mdb_printf("%<u>%14s %14s %10s %10s%</u>\n", 733 "SPORT", "DPORT", "VTAG", "CHKSUM"); 734 mdb_printf("%5hu (0x%04x) %5hu (0x%04x) %10u 0x%08x\n\n", sport, sport, 735 dport, dport, sctph->sh_verf, sctph->sh_chksum); 736 } 737 738 /* ARGSUSED */ 739 static int 740 sctphdr(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av) 741 { 742 sctp_hdr_t sctph; 743 744 if (!(flags & DCMD_ADDRSPEC)) 745 return (DCMD_USAGE); 746 747 if (mdb_vread(&sctph, sizeof (sctph), addr) == -1) { 748 mdb_warn("failed to read SCTP header at %p", addr); 749 return (DCMD_ERR); 750 } 751 752 sctphdr_print(&sctph); 753 return (DCMD_OK); 754 } 755 756 static int 757 transport_hdr(int proto, uintptr_t addr) 758 { 759 mdb_printf("\n"); 760 switch (proto) { 761 case IPPROTO_TCP: { 762 struct tcphdr tcph; 763 764 if (mdb_vread(&tcph, sizeof (tcph), addr) == -1) { 765 mdb_warn("failed to read TCP header at %p", addr); 766 return (DCMD_ERR); 767 } 768 tcphdr_print(&tcph); 769 break; 770 } 771 case IPPROTO_UDP: { 772 struct udphdr udph; 773 774 if (mdb_vread(&udph, sizeof (udph), addr) == -1) { 775 mdb_warn("failed to read UDP header at %p", addr); 776 return (DCMD_ERR); 777 } 778 udphdr_print(&udph); 779 break; 780 } 781 case IPPROTO_SCTP: { 782 sctp_hdr_t sctph; 783 784 if (mdb_vread(&sctph, sizeof (sctph), addr) == -1) { 785 mdb_warn("failed to read SCTP header at %p", addr); 786 return (DCMD_ERR); 787 } 788 sctphdr_print(&sctph); 789 break; 790 } 791 default: 792 break; 793 } 794 795 return (DCMD_OK); 796 } 797 798 static const mdb_bitmask_t ip_flags[] = { 799 { "DF", IPH_DF, IPH_DF }, 800 { "MF", IPH_MF, IPH_MF }, 801 { NULL, 0, 0 } 802 }; 803 804 /* ARGSUSED */ 805 static int 806 iphdr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 807 { 808 uint_t verbose = FALSE, force = FALSE; 809 ipha_t iph[1]; 810 uint16_t ver, totlen, hdrlen, ipid, off, csum; 811 uintptr_t nxt_proto; 812 char exp_csum[8]; 813 814 if (mdb_getopts(argc, argv, 815 'v', MDB_OPT_SETBITS, TRUE, &verbose, 816 'f', MDB_OPT_SETBITS, TRUE, &force, NULL) != argc) 817 return (DCMD_USAGE); 818 819 if (mdb_vread(iph, sizeof (*iph), addr) == -1) { 820 mdb_warn("failed to read IPv4 header at %p", addr); 821 return (DCMD_ERR); 822 } 823 824 ver = (iph->ipha_version_and_hdr_length & 0xf0) >> 4; 825 if (ver != IPV4_VERSION) { 826 if (ver == IPV6_VERSION) { 827 return (ip6hdr(addr, flags, argc, argv)); 828 } else if (!force) { 829 mdb_warn("unknown IP version: %d\n", ver); 830 return (DCMD_ERR); 831 } 832 } 833 834 mdb_printf("%<b>IPv4 header%</b>\n"); 835 mdb_printf("%-34s %-34s\n" 836 "%<u>%-4s %-4s %-5s %-5s %-6s %-5s %-5s %-6s %-8s %-6s%</u>\n", 837 "SRC", "DST", 838 "HLEN", "TOS", "LEN", "ID", "OFFSET", "TTL", "PROTO", "CHKSUM", 839 "EXP-CSUM", "FLGS"); 840 841 hdrlen = (iph->ipha_version_and_hdr_length & 0x0f) << 2; 842 mdb_nhconvert(&totlen, &iph->ipha_length, sizeof (totlen)); 843 mdb_nhconvert(&ipid, &iph->ipha_ident, sizeof (ipid)); 844 mdb_nhconvert(&off, &iph->ipha_fragment_offset_and_flags, sizeof (off)); 845 if (hdrlen == IP_SIMPLE_HDR_LENGTH) { 846 if ((csum = ipcksum(iph, sizeof (*iph))) != 0) 847 csum = ~(~csum + ~iph->ipha_hdr_checksum); 848 else 849 csum = iph->ipha_hdr_checksum; 850 mdb_snprintf(exp_csum, 8, "%u", csum); 851 } else { 852 mdb_snprintf(exp_csum, 8, "<n/a>"); 853 } 854 855 mdb_printf("%-34I %-34I%\n" 856 "%-4d %-4d %-5hu %-5hu %-6hu %-5hu %-5hu %-6u %-8s <%5hb>\n", 857 iph->ipha_src, iph->ipha_dst, 858 hdrlen, iph->ipha_type_of_service, totlen, ipid, 859 (off << 3) & 0xffff, iph->ipha_ttl, iph->ipha_protocol, 860 iph->ipha_hdr_checksum, exp_csum, off, ip_flags); 861 862 if (verbose) { 863 nxt_proto = addr + hdrlen; 864 return (transport_hdr(iph->ipha_protocol, nxt_proto)); 865 } else { 866 return (DCMD_OK); 867 } 868 } 869 870 /* ARGSUSED */ 871 static int 872 ip6hdr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 873 { 874 uint_t verbose = FALSE, force = FALSE; 875 ip6_t iph[1]; 876 int ver, class, flow; 877 uint16_t plen; 878 uintptr_t nxt_proto; 879 880 if (mdb_getopts(argc, argv, 881 'v', MDB_OPT_SETBITS, TRUE, &verbose, 882 'f', MDB_OPT_SETBITS, TRUE, &force, NULL) != argc) 883 return (DCMD_USAGE); 884 885 if (mdb_vread(iph, sizeof (*iph), addr) == -1) { 886 mdb_warn("failed to read IPv6 header at %p", addr); 887 return (DCMD_ERR); 888 } 889 890 ver = (iph->ip6_vfc & 0xf0) >> 4; 891 if (ver != IPV6_VERSION) { 892 if (ver == IPV4_VERSION) { 893 return (iphdr(addr, flags, argc, argv)); 894 } else if (!force) { 895 mdb_warn("unknown IP version: %d\n", ver); 896 return (DCMD_ERR); 897 } 898 } 899 900 mdb_printf("%<b>IPv6 header%</b>\n"); 901 mdb_printf("%<u>%-26s %-26s %4s %7s %5s %3s %3s%</u>\n", 902 "SRC", "DST", "TCLS", "FLOW-ID", "PLEN", "NXT", "HOP"); 903 904 class = (iph->ip6_vcf & IPV6_FLOWINFO_TCLASS) >> 20; 905 mdb_nhconvert(&class, &class, sizeof (class)); 906 flow = iph->ip6_vcf & IPV6_FLOWINFO_FLOWLABEL; 907 mdb_nhconvert(&flow, &flow, sizeof (flow)); 908 mdb_nhconvert(&plen, &iph->ip6_plen, sizeof (plen)); 909 910 mdb_printf("%-26N %-26N %4d %7d %5hu %3d %3d\n", 911 &iph->ip6_src, &iph->ip6_dst, 912 class, flow, plen, iph->ip6_nxt, iph->ip6_hlim); 913 914 if (verbose) { 915 nxt_proto = addr + sizeof (ip6_t); 916 return (transport_hdr(iph->ip6_nxt, nxt_proto)); 917 } else { 918 return (DCMD_OK); 919 } 920 } 921 922 int 923 ire(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 924 { 925 uint_t verbose = FALSE; 926 ire_t ire; 927 928 if (mdb_getopts(argc, argv, 929 'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL) != argc) 930 return (DCMD_USAGE); 931 932 if ((flags & DCMD_LOOPFIRST) || !(flags & DCMD_LOOP)) { 933 934 if (verbose) { 935 mdb_printf("%?s %40s %-20s%\n" 936 "%?s %40s %-20s%\n" 937 "%<u>%?s %40s %4s %-20s%</u>\n", 938 "ADDR", "SRC", "TYPE", 939 "", "DST", "MARKS", 940 "", "STACK", "ZONE", "FLAGS"); 941 } else { 942 mdb_printf("%<u>%?s %30s %30s %5s %4s%</u>\n", 943 "ADDR", "SRC", "DST", "STACK", "ZONE"); 944 } 945 } 946 947 if (flags & DCMD_ADDRSPEC) { 948 (void) mdb_vread(&ire, sizeof (ire_t), addr); 949 (void) ire_format(addr, &ire, &verbose); 950 } else if (mdb_walk("ire", (mdb_walk_cb_t)ire_format, &verbose) == -1) { 951 mdb_warn("failed to walk ire table"); 952 return (DCMD_ERR); 953 } 954 955 return (DCMD_OK); 956 } 957 958 static size_t 959 mi_osize(const queue_t *q) 960 { 961 /* 962 * The code in common/inet/mi.c allocates an extra word to store the 963 * size of the allocation. An mi_o_s is thus a size_t plus an mi_o_s. 964 */ 965 struct mi_block { 966 size_t mi_nbytes; 967 struct mi_o_s mi_o; 968 } m; 969 970 if (mdb_vread(&m, sizeof (m), (uintptr_t)q->q_ptr - 971 sizeof (m)) == sizeof (m)) 972 return (m.mi_nbytes - sizeof (m)); 973 974 return (0); 975 } 976 977 static void 978 ip_ill_qinfo(const queue_t *q, char *buf, size_t nbytes) 979 { 980 char name[32]; 981 ill_t ill; 982 983 if (mdb_vread(&ill, sizeof (ill), 984 (uintptr_t)q->q_ptr) == sizeof (ill) && 985 mdb_readstr(name, sizeof (name), (uintptr_t)ill.ill_name) > 0) 986 (void) mdb_snprintf(buf, nbytes, "if: %s", name); 987 } 988 989 void 990 ip_qinfo(const queue_t *q, char *buf, size_t nbytes) 991 { 992 size_t size = mi_osize(q); 993 994 if (size == sizeof (ill_t)) 995 ip_ill_qinfo(q, buf, nbytes); 996 } 997 998 uintptr_t 999 ip_rnext(const queue_t *q) 1000 { 1001 size_t size = mi_osize(q); 1002 ill_t ill; 1003 1004 if (size == sizeof (ill_t) && mdb_vread(&ill, sizeof (ill), 1005 (uintptr_t)q->q_ptr) == sizeof (ill)) 1006 return ((uintptr_t)ill.ill_rq); 1007 1008 return (NULL); 1009 } 1010 1011 uintptr_t 1012 ip_wnext(const queue_t *q) 1013 { 1014 size_t size = mi_osize(q); 1015 ill_t ill; 1016 1017 if (size == sizeof (ill_t) && mdb_vread(&ill, sizeof (ill), 1018 (uintptr_t)q->q_ptr) == sizeof (ill)) 1019 return ((uintptr_t)ill.ill_wq); 1020 1021 return (NULL); 1022 } 1023 1024 /* 1025 * Print the core fields in an squeue_t. With the "-v" argument, 1026 * provide more verbose output. 1027 */ 1028 static int 1029 squeue(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1030 { 1031 unsigned int i; 1032 unsigned int verbose = FALSE; 1033 const int SQUEUE_STATEDELT = (int)(sizeof (uintptr_t) + 9); 1034 boolean_t arm; 1035 squeue_t squeue; 1036 1037 if (!(flags & DCMD_ADDRSPEC)) { 1038 if (mdb_walk_dcmd("genunix`squeue_cache", "ip`squeue", 1039 argc, argv) == -1) { 1040 mdb_warn("failed to walk squeue cache"); 1041 return (DCMD_ERR); 1042 } 1043 return (DCMD_OK); 1044 } 1045 1046 if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL) 1047 != argc) 1048 return (DCMD_USAGE); 1049 1050 if (!DCMD_HDRSPEC(flags) && verbose) 1051 mdb_printf("\n\n"); 1052 1053 if (DCMD_HDRSPEC(flags) || verbose) { 1054 mdb_printf("%?s %-5s %-3s %?s %?s %?s\n", 1055 "ADDR", "STATE", "CPU", 1056 "FIRST", "LAST", "WORKER"); 1057 } 1058 1059 if (mdb_vread(&squeue, sizeof (squeue_t), addr) == -1) { 1060 mdb_warn("cannot read squeue_t at %p", addr); 1061 return (DCMD_ERR); 1062 } 1063 1064 mdb_printf("%0?p %05x %3d %0?p %0?p %0?p\n", 1065 addr, squeue.sq_state, squeue.sq_bind, 1066 squeue.sq_first, squeue.sq_last, squeue.sq_worker); 1067 1068 if (!verbose) 1069 return (DCMD_OK); 1070 1071 arm = B_TRUE; 1072 for (i = 0; squeue_states[i].bit_name != NULL; i++) { 1073 if (((squeue.sq_state) & (1 << i)) == 0) 1074 continue; 1075 1076 if (arm) { 1077 mdb_printf("%*s|\n", SQUEUE_STATEDELT, ""); 1078 mdb_printf("%*s+--> ", SQUEUE_STATEDELT, ""); 1079 arm = B_FALSE; 1080 } else 1081 mdb_printf("%*s ", SQUEUE_STATEDELT, ""); 1082 1083 mdb_printf("%-12s %s\n", squeue_states[i].bit_name, 1084 squeue_states[i].bit_descr); 1085 } 1086 1087 return (DCMD_OK); 1088 } 1089 1090 static void 1091 ip_squeue_help(void) 1092 { 1093 mdb_printf("Print the core information for a given NCA squeue_t.\n\n"); 1094 mdb_printf("Options:\n"); 1095 mdb_printf("\t-v\tbe verbose (more descriptive)\n"); 1096 } 1097 1098 /* 1099 * This is called by ::th_trace (via a callback) when walking the th_hash 1100 * list. It calls modent to find the entries. 1101 */ 1102 /* ARGSUSED */ 1103 static int 1104 modent_summary(uintptr_t addr, const void *data, void *private) 1105 { 1106 th_walk_data_t *thw = private; 1107 const struct mod_hash_entry *mhe = data; 1108 th_trace_t th; 1109 1110 if (mdb_vread(&th, sizeof (th), (uintptr_t)mhe->mhe_val) == -1) { 1111 mdb_warn("failed to read th_trace_t %p", mhe->mhe_val); 1112 return (WALK_ERR); 1113 } 1114 1115 if (th.th_refcnt == 0 && thw->thw_non_zero_only) 1116 return (WALK_NEXT); 1117 1118 if (!thw->thw_match) { 1119 mdb_printf("%?p %?p %?p %8d %?p\n", thw->thw_ipst, mhe->mhe_key, 1120 mhe->mhe_val, th.th_refcnt, th.th_id); 1121 } else if (thw->thw_matchkey == (uintptr_t)mhe->mhe_key) { 1122 int i, j, k; 1123 tr_buf_t *tr; 1124 1125 mdb_printf("Object %p in IP stack %p:\n", mhe->mhe_key, 1126 thw->thw_ipst); 1127 i = th.th_trace_lastref; 1128 mdb_printf("\tThread %p refcnt %d:\n", th.th_id, 1129 th.th_refcnt); 1130 for (j = TR_BUF_MAX; j > 0; j--) { 1131 tr = th.th_trbuf + i; 1132 if (tr->tr_depth == 0 || tr->tr_depth > TR_STACK_DEPTH) 1133 break; 1134 mdb_printf("\t T%+ld:\n", tr->tr_time - 1135 thw->thw_lbolt); 1136 for (k = 0; k < tr->tr_depth; k++) 1137 mdb_printf("\t\t%a\n", tr->tr_stack[k]); 1138 if (--i < 0) 1139 i = TR_BUF_MAX - 1; 1140 } 1141 } 1142 return (WALK_NEXT); 1143 } 1144 1145 /* 1146 * This is called by ::th_trace (via a callback) when walking the th_hash 1147 * list. It calls modent to find the entries. 1148 */ 1149 /* ARGSUSED */ 1150 static int 1151 th_hash_summary(uintptr_t addr, const void *data, void *private) 1152 { 1153 const th_hash_t *thh = data; 1154 th_walk_data_t *thw = private; 1155 1156 thw->thw_ipst = (uintptr_t)thh->thh_ipst; 1157 return (mdb_pwalk("modent", modent_summary, private, 1158 (uintptr_t)thh->thh_hash)); 1159 } 1160 1161 /* 1162 * Print or summarize the th_trace_t structures. 1163 */ 1164 static int 1165 th_trace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1166 { 1167 th_walk_data_t thw; 1168 1169 (void) memset(&thw, 0, sizeof (thw)); 1170 1171 if (mdb_getopts(argc, argv, 1172 'n', MDB_OPT_SETBITS, TRUE, &thw.thw_non_zero_only, 1173 NULL) != argc) 1174 return (DCMD_USAGE); 1175 1176 if (!(flags & DCMD_ADDRSPEC)) { 1177 /* 1178 * No address specified. Walk all of the th_hash_t in the 1179 * system, and summarize the th_trace_t entries in each. 1180 */ 1181 mdb_printf("%?s %?s %?s %8s %?s\n", 1182 "IPSTACK", "OBJECT", "TRACE", "REFCNT", "THREAD"); 1183 thw.thw_match = B_FALSE; 1184 } else { 1185 thw.thw_match = B_TRUE; 1186 thw.thw_matchkey = addr; 1187 if (mdb_readvar(&thw.thw_lbolt, 1188 mdb_prop_postmortem ? "panic_lbolt" : "lbolt") == -1) { 1189 mdb_warn("failed to read lbolt"); 1190 return (DCMD_ERR); 1191 } 1192 } 1193 if (mdb_pwalk("th_hash", th_hash_summary, &thw, NULL) == -1) { 1194 mdb_warn("can't walk th_hash entries"); 1195 return (DCMD_ERR); 1196 } 1197 return (DCMD_OK); 1198 } 1199 1200 static void 1201 th_trace_help(void) 1202 { 1203 mdb_printf("If given an address of an ill_t, ipif_t, ire_t, or nce_t, " 1204 "print the\n" 1205 "corresponding th_trace_t structure in detail. Otherwise, if no " 1206 "address is\n" 1207 "given, then summarize all th_trace_t structures.\n\n"); 1208 mdb_printf("Options:\n" 1209 "\t-n\tdisplay only entries with non-zero th_refcnt\n"); 1210 } 1211 1212 static const mdb_dcmd_t dcmds[] = { 1213 { "illif", "?[-P v4 | v6]", 1214 "display or filter IP Lower Level InterFace structures", illif, 1215 illif_help }, 1216 { "iphdr", ":[-vf]", "display an IPv4 header", iphdr }, 1217 { "ip6hdr", ":[-vf]", "display an IPv6 header", ip6hdr }, 1218 { "ire", "?[-v]", "display Internet Route Entry structures", ire }, 1219 { "squeue", ":[-v]", "print core squeue_t info", squeue, 1220 ip_squeue_help }, 1221 { "tcphdr", ":", "display a TCP header", tcphdr }, 1222 { "udphdr", ":", "display an UDP header", udphdr }, 1223 { "sctphdr", ":", "display an SCTP header", sctphdr }, 1224 { "th_trace", "?[-n]", "display th_trace_t structures", th_trace, 1225 th_trace_help }, 1226 { NULL } 1227 }; 1228 1229 static const mdb_walker_t walkers[] = { 1230 { "illif", "walk list of ill interface types for all stacks", 1231 illif_walk_init, illif_walk_step, NULL }, 1232 { "illif_stack", "walk list of ill interface types", 1233 illif_stack_walk_init, illif_stack_walk_step, 1234 illif_stack_walk_fini }, 1235 { "ire", "walk active ire_t structures", 1236 ire_walk_init, ire_walk_step, NULL }, 1237 { "ire_ctable", "walk ire_t structures in the ctable", 1238 ire_ctable_walk_init, ire_ctable_walk_step, NULL }, 1239 { "ire_next", "walk ire_t structures in the ctable", 1240 ire_next_walk_init, ire_next_walk_step, NULL }, 1241 { "ip_stacks", "walk all the ip_stack_t", 1242 ip_stacks_walk_init, ip_stacks_walk_step, NULL }, 1243 { "th_hash", "walk all the th_hash_t entries", 1244 th_hash_walk_init, th_hash_walk_step, NULL }, 1245 { NULL } 1246 }; 1247 1248 static const mdb_qops_t ip_qops = { ip_qinfo, ip_rnext, ip_wnext }; 1249 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers }; 1250 1251 const mdb_modinfo_t * 1252 _mdb_init(void) 1253 { 1254 GElf_Sym sym; 1255 1256 if (mdb_lookup_by_obj("ip", "ipwinit", &sym) == 0) 1257 mdb_qops_install(&ip_qops, (uintptr_t)sym.st_value); 1258 1259 return (&modinfo); 1260 } 1261 1262 void 1263 _mdb_fini(void) 1264 { 1265 GElf_Sym sym; 1266 1267 if (mdb_lookup_by_obj("ip", "ipwinit", &sym) == 0) 1268 mdb_qops_remove(&ip_qops, (uintptr_t)sym.st_value); 1269 } 1270