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 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <sys/stropts.h> 31 #include <sys/stream.h> 32 #include <sys/socket.h> 33 #include <net/if.h> 34 #define SOL2 35 #include <net/ppp_defs.h> 36 #include <net/pppio.h> 37 #include <net/sppptun.h> 38 #include <netinet/in.h> 39 #include <netinet/ip6.h> 40 #include <inet/common.h> 41 #include <inet/mib2.h> 42 #include <inet/ip.h> 43 #include <inet/ip6.h> 44 #include <sppp/sppp.h> 45 #include <sppptun/sppptun_impl.h> 46 47 #include <mdb/mdb_modapi.h> 48 #include <mdb/mdb_ks.h> 49 #include <stdio.h> 50 51 /* ****************** sppp ****************** */ 52 53 static int 54 sppp_walk_init(mdb_walk_state_t *wsp) 55 { 56 if (mdb_readvar(&wsp->walk_addr, "sps_list") == -1) { 57 mdb_warn("failed to read sps_list"); 58 return (WALK_ERR); 59 } 60 61 return (WALK_NEXT); 62 } 63 64 static int 65 sppp_walk_step(mdb_walk_state_t *wsp) 66 { 67 spppstr_t sps; 68 int status; 69 70 if (wsp->walk_addr == NULL) 71 return (WALK_DONE); 72 73 if (mdb_vread(&sps, sizeof (sps), wsp->walk_addr) == -1) { 74 mdb_warn("can't read spppstr_t at %p", wsp->walk_addr); 75 return (WALK_ERR); 76 } 77 78 status = (wsp->walk_callback(wsp->walk_addr, &sps, wsp->walk_cbdata)); 79 80 wsp->walk_addr = (uintptr_t)sps.sps_nextmn; 81 return (status); 82 } 83 84 static int 85 sps_format(uintptr_t addr, const spppstr_t *sps, uint_t *qfmt) 86 { 87 sppa_t ppa; 88 queue_t upq; 89 uintptr_t upaddr, illaddr; 90 ill_t ill; 91 ipif_t ipif; 92 93 mdb_printf("%?p ", addr); 94 if (*qfmt) 95 mdb_printf("%?p ", sps->sps_rq); 96 if (sps->sps_ppa == NULL) { 97 mdb_printf("unset "); 98 } else if (mdb_vread(&ppa, sizeof (ppa), (uintptr_t)sps->sps_ppa) == 99 -1) { 100 mdb_printf("?%p ", sps->sps_ppa); 101 } else { 102 mdb_printf("sppp%-5d ", ppa.ppa_ppa_id); 103 } 104 if (IS_SPS_CONTROL(sps)) { 105 mdb_printf("Control\n"); 106 } else if (IS_SPS_PIOATTACH(sps)) { 107 mdb_printf("Stats\n"); 108 } else if (sps->sps_dlstate == DL_UNATTACHED) { 109 mdb_printf("Unknown\n"); 110 } else if (sps->sps_dlstate != DL_IDLE) { 111 mdb_printf("DLPI Unbound\n"); 112 } else { 113 upaddr = (uintptr_t)sps->sps_rq; 114 upq.q_ptr = NULL; 115 illaddr = 0; 116 while (upaddr != NULL) { 117 if (mdb_vread(&upq, sizeof (upq), upaddr) == -1) { 118 upq.q_ptr = NULL; 119 break; 120 } 121 if ((upaddr = (uintptr_t)upq.q_next) != 0) 122 illaddr = (uintptr_t)upq.q_ptr; 123 } 124 if (illaddr != 0) { 125 if (mdb_vread(&ill, sizeof (ill), illaddr) == -1 || 126 mdb_vread(&ipif, sizeof (ipif), 127 (uintptr_t)ill.ill_ipif) == -1) { 128 illaddr = 0; 129 } 130 } 131 132 switch (sps->sps_req_sap) { 133 case ETHERTYPE_IP: 134 mdb_printf("DLPI IPv4 "); 135 if (*qfmt) { 136 mdb_printf("\n"); 137 } else if (illaddr == 0) { 138 mdb_printf("(no addresses)\n"); 139 } else { 140 /* 141 * SCCS oddity here -- % <capital> % 142 * suffers from keyword replacement. 143 * Avoid that by using ANSI string 144 * pasting. 145 */ 146 mdb_printf("%I:%I" "%s\n", 147 ipif.ipif_lcl_addr, ipif.ipif_pp_dst_addr, 148 (ipif.ipif_next ? " ..." : "")); 149 } 150 break; 151 case ETHERTYPE_IPV6: 152 mdb_printf("DLPI IPv6 "); 153 if (*qfmt) { 154 mdb_printf("\n"); 155 break; 156 } 157 if (illaddr == 0) { 158 mdb_printf("(no addresses)\n"); 159 break; 160 } 161 mdb_printf("%N\n%?s%21s", &ipif.ipif_v6lcl_addr, 162 "", ""); 163 mdb_printf("%N\n", &ipif.ipif_v6pp_dst_addr); 164 break; 165 case ETHERTYPE_ALLSAP: 166 mdb_printf("DLPI Snoop\n"); 167 break; 168 default: 169 mdb_printf("DLPI SAP 0x%04X\n", sps->sps_req_sap); 170 break; 171 } 172 } 173 174 return (WALK_NEXT); 175 } 176 177 static int 178 sppp(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 179 { 180 uint_t qfmt = FALSE; 181 spppstr_t sps; 182 183 if (mdb_getopts(argc, argv, 'q', MDB_OPT_SETBITS, TRUE, &qfmt, NULL) != 184 argc) 185 return (DCMD_USAGE); 186 187 if ((flags & DCMD_LOOPFIRST) || !(flags & DCMD_LOOP)) { 188 if (qfmt) { 189 mdb_printf("%<u>%?s %?s %9s %s%</u>\n", "Address", 190 "RecvQ", "Interface", "Type"); 191 } else { 192 mdb_printf("%<u>%?s %9s %s%</u>\n", "Address", 193 "Interface", "Type"); 194 } 195 } 196 197 if (flags & DCMD_ADDRSPEC) { 198 (void) mdb_vread(&sps, sizeof (sps), addr); 199 (void) sps_format(addr, &sps, &qfmt); 200 } else if (mdb_walk("sppp", (mdb_walk_cb_t)sps_format, &qfmt) == -1) { 201 mdb_warn("failed to walk sps_list"); 202 return (DCMD_ERR); 203 } 204 205 return (DCMD_OK); 206 } 207 208 static int 209 sppa_walk_init(mdb_walk_state_t *wsp) 210 { 211 if (mdb_readvar(&wsp->walk_addr, "ppa_list") == -1) { 212 mdb_warn("failed to read ppa_list"); 213 return (WALK_ERR); 214 } 215 216 return (WALK_NEXT); 217 } 218 219 static int 220 sppa_walk_step(mdb_walk_state_t *wsp) 221 { 222 sppa_t ppa; 223 int status; 224 225 if (wsp->walk_addr == NULL) 226 return (WALK_DONE); 227 228 if (mdb_vread(&ppa, sizeof (ppa), wsp->walk_addr) == -1) { 229 mdb_warn("can't read spppstr_t at %p", wsp->walk_addr); 230 return (WALK_ERR); 231 } 232 233 status = (wsp->walk_callback(wsp->walk_addr, &ppa, wsp->walk_cbdata)); 234 235 wsp->walk_addr = (uintptr_t)ppa.ppa_nextppa; 236 return (status); 237 } 238 239 /* ARGSUSED */ 240 static int 241 ppa_format(uintptr_t addr, const sppa_t *ppa, uint_t *qfmt) 242 { 243 mdb_printf("%?p sppp%-5d %?p %?p\n", addr, ppa->ppa_ppa_id, 244 ppa->ppa_ctl, ppa->ppa_lower_wq); 245 246 return (WALK_NEXT); 247 } 248 249 /* ARGSUSED */ 250 static int 251 sppa(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 252 { 253 uint_t qfmt = FALSE; 254 sppa_t ppa; 255 256 if ((flags & DCMD_LOOPFIRST) || !(flags & DCMD_LOOP)) { 257 mdb_printf("%<u>%?s %9s %?s %?s%</u>\n", "Address", 258 "Interface", "Control", "LowerQ"); 259 } 260 261 if (flags & DCMD_ADDRSPEC) { 262 (void) mdb_vread(&ppa, sizeof (ppa), addr); 263 (void) ppa_format(addr, &ppa, &qfmt); 264 } else if (mdb_walk("sppa", (mdb_walk_cb_t)ppa_format, &qfmt) == -1) { 265 mdb_warn("failed to walk ppa_list"); 266 return (DCMD_ERR); 267 } 268 269 return (DCMD_OK); 270 } 271 272 static void 273 sppp_qinfo(const queue_t *q, char *buf, size_t nbytes) 274 { 275 spppstr_t sps; 276 sppa_t ppa; 277 278 if (mdb_vread(&sps, sizeof (sps), (uintptr_t)q->q_ptr) == 279 sizeof (sps)) { 280 if (sps.sps_ppa == NULL || 281 mdb_vread(&ppa, sizeof (ppa), (uintptr_t)sps.sps_ppa) == 282 -1) { 283 (void) mdb_snprintf(buf, nbytes, "minor %d", 284 sps.sps_mn_id); 285 } else { 286 (void) mdb_snprintf(buf, nbytes, "sppp%d", 287 ppa.ppa_ppa_id); 288 } 289 } 290 } 291 292 static uintptr_t 293 sppp_rnext(const queue_t *q) 294 { 295 spppstr_t sps; 296 297 if (mdb_vread(&sps, sizeof (sps), (uintptr_t)q->q_ptr) == sizeof (sps)) 298 return ((uintptr_t)sps.sps_rq); 299 300 return (NULL); 301 } 302 303 static uintptr_t 304 sppp_wnext(const queue_t *q) 305 { 306 spppstr_t sps; 307 sppa_t ppa; 308 309 if (mdb_vread(&sps, sizeof (sps), (uintptr_t)q->q_ptr) != sizeof (sps)) 310 return (NULL); 311 312 if (sps.sps_ppa != NULL && 313 mdb_vread(&ppa, sizeof (ppa), (uintptr_t)sps.sps_ppa) == 314 sizeof (ppa)) 315 return ((uintptr_t)ppa.ppa_lower_wq); 316 317 return (NULL); 318 } 319 320 /* ****************** sppptun ****************** */ 321 322 struct tcl_walk_data { 323 size_t tcl_nslots; 324 size_t walkpos; 325 tuncl_t *tcl_slots[1]; 326 }; 327 328 static void 329 tuncl_walk_fini(mdb_walk_state_t *wsp) 330 { 331 struct tcl_walk_data *twd; 332 333 if (wsp != NULL && wsp->walk_addr != 0) { 334 twd = (struct tcl_walk_data *)wsp->walk_addr; 335 mdb_free(twd, sizeof (*twd) + ((twd->tcl_nslots - 1) * 336 sizeof (twd->tcl_slots[0]))); 337 wsp->walk_addr = 0; 338 } 339 } 340 341 static int 342 tuncl_walk_init(mdb_walk_state_t *wsp) 343 { 344 size_t tcl_nslots; 345 tuncl_t **tcl_slots; 346 struct tcl_walk_data *twd; 347 348 if (wsp == NULL) 349 return (WALK_ERR); 350 351 if (wsp->walk_addr != 0) 352 tuncl_walk_fini(wsp); 353 354 if (mdb_readvar(&tcl_nslots, "tcl_nslots") == -1) { 355 mdb_warn("failed to read tcl_nslots"); 356 return (WALK_ERR); 357 } 358 359 if (tcl_nslots == 0) 360 return (WALK_DONE); 361 362 if (mdb_readvar(&tcl_slots, "tcl_slots") == -1) { 363 mdb_warn("failed to read tcl_slots"); 364 return (WALK_ERR); 365 } 366 367 twd = (struct tcl_walk_data *)mdb_alloc(sizeof (*twd) + 368 (tcl_nslots - 1) * sizeof (*tcl_slots), UM_NOSLEEP); 369 if (twd == NULL) 370 return (WALK_ERR); 371 twd->tcl_nslots = tcl_nslots; 372 twd->walkpos = 0; 373 wsp->walk_addr = (uintptr_t)twd; 374 375 if (mdb_vread(twd->tcl_slots, tcl_nslots * sizeof (twd->tcl_slots[0]), 376 (uintptr_t)tcl_slots) == -1) { 377 mdb_warn("can't read tcl_slots at %p", tcl_slots); 378 tuncl_walk_fini(wsp); 379 return (WALK_ERR); 380 } 381 382 return (WALK_NEXT); 383 } 384 385 static int 386 tuncl_walk_step(mdb_walk_state_t *wsp) 387 { 388 tuncl_t tcl; 389 int status; 390 struct tcl_walk_data *twd; 391 uintptr_t addr; 392 393 if (wsp == NULL || wsp->walk_addr == NULL) 394 return (WALK_DONE); 395 396 twd = (struct tcl_walk_data *)wsp->walk_addr; 397 398 while (twd->walkpos < twd->tcl_nslots && 399 twd->tcl_slots[twd->walkpos] == NULL) 400 twd->walkpos++; 401 if (twd->walkpos >= twd->tcl_nslots) 402 return (WALK_DONE); 403 404 addr = (uintptr_t)twd->tcl_slots[twd->walkpos]; 405 if (mdb_vread(&tcl, sizeof (tcl), addr) == -1) { 406 mdb_warn("can't read tuncl_t at %p", addr); 407 return (WALK_ERR); 408 } 409 410 status = wsp->walk_callback(addr, &tcl, wsp->walk_cbdata); 411 412 twd->walkpos++; 413 return (status); 414 } 415 416 /* ARGSUSED */ 417 static int 418 tuncl_format(uintptr_t addr, const tuncl_t *tcl, uint_t *qfmt) 419 { 420 mdb_printf("%?p %?p %?p", addr, tcl->tcl_data_tll, tcl->tcl_ctrl_tll); 421 mdb_printf(" %-2d %04X %04X ", tcl->tcl_style, 422 tcl->tcl_lsessid, tcl->tcl_rsessid); 423 if (tcl->tcl_flags & TCLF_DAEMON) { 424 mdb_printf("<daemon>\n"); 425 } else { 426 mdb_printf("sppp%d\n", tcl->tcl_unit); 427 } 428 429 return (WALK_NEXT); 430 } 431 432 /* ARGSUSED */ 433 static int 434 tuncl(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 435 { 436 uint_t qfmt = FALSE; 437 tuncl_t tcl; 438 439 if ((flags & DCMD_LOOPFIRST) || !(flags & DCMD_LOOP)) { 440 mdb_printf("%<u>%?s %?s %?s Ty LSes RSes %s%</u>\n", "Address", 441 "Data", "Control", "Interface"); 442 } 443 444 if (flags & DCMD_ADDRSPEC) { 445 if (mdb_vread(&tcl, sizeof (tcl), addr) == -1) 446 mdb_warn("failed to read tuncl_t at %p", addr); 447 else 448 tuncl_format(addr, &tcl, &qfmt); 449 } else if (mdb_walk("tuncl", (mdb_walk_cb_t)tuncl_format, &qfmt) == 450 -1) { 451 mdb_warn("failed to walk tcl_slots"); 452 return (DCMD_ERR); 453 } 454 455 return (DCMD_OK); 456 } 457 458 struct tll_walk_data { 459 void *listhead; 460 void *next; 461 }; 462 463 static void 464 tunll_walk_fini(mdb_walk_state_t *wsp) 465 { 466 struct tll_walk_data *twd; 467 468 if (wsp != NULL && wsp->walk_addr != 0) { 469 twd = (struct tll_walk_data *)wsp->walk_addr; 470 mdb_free(twd, sizeof (*twd)); 471 wsp->walk_addr = 0; 472 } 473 } 474 475 static int 476 tunll_walk_init(mdb_walk_state_t *wsp) 477 { 478 GElf_Sym sym; 479 struct tll_walk_data *twd; 480 struct qelem tunll_list; 481 482 if (wsp->walk_addr != 0) 483 tunll_walk_fini(wsp); 484 485 if (mdb_lookup_by_obj("sppptun", "tunll_list", &sym) != 0) { 486 mdb_warn("failed to find tunll_list"); 487 return (WALK_ERR); 488 } 489 490 if (mdb_vread(&tunll_list, sizeof (tunll_list), 491 (uintptr_t)sym.st_value) == -1) { 492 mdb_warn("can't read tunll_list at %p", 493 (uintptr_t)sym.st_value); 494 return (WALK_ERR); 495 } 496 497 twd = (struct tll_walk_data *)mdb_alloc(sizeof (*twd), UM_NOSLEEP); 498 if (twd == NULL) 499 return (WALK_ERR); 500 twd->listhead = (void *)(uintptr_t)sym.st_value; 501 twd->next = (void *)tunll_list.q_forw; 502 wsp->walk_addr = (uintptr_t)twd; 503 504 return (WALK_NEXT); 505 } 506 507 static int 508 tunll_walk_step(mdb_walk_state_t *wsp) 509 { 510 struct tll_walk_data *twd; 511 tunll_t tll; 512 int status; 513 uintptr_t addr; 514 515 if (wsp == NULL || wsp->walk_addr == 0) 516 return (WALK_DONE); 517 518 twd = (struct tll_walk_data *)wsp->walk_addr; 519 if (twd->next == NULL || twd->next == twd->listhead) 520 return (WALK_DONE); 521 522 /* LINTED */ 523 addr = (uintptr_t)TO_TLL(twd->next); 524 if (mdb_vread(&tll, sizeof (tll), addr) == -1) { 525 mdb_warn("can't read tunll_t at %p", addr); 526 return (WALK_ERR); 527 } 528 529 status = wsp->walk_callback(addr, &tll, wsp->walk_cbdata); 530 531 twd->next = (void *)tll.tll_next; 532 return (status); 533 } 534 535 /* ARGSUSED */ 536 static int 537 tunll_format(uintptr_t addr, const tunll_t *tll, uint_t *qfmt) 538 { 539 mdb_printf("%?p %-14s %?p", addr, tll->tll_name, tll->tll_defcl); 540 if (tll->tll_style == PTS_PPPOE) { 541 mdb_printf(" %x:%x:%x:%x:%x:%x", 542 tll->tll_lcladdr.pta_pppoe.ptma_mac[0], 543 tll->tll_lcladdr.pta_pppoe.ptma_mac[1], 544 tll->tll_lcladdr.pta_pppoe.ptma_mac[2], 545 tll->tll_lcladdr.pta_pppoe.ptma_mac[3], 546 tll->tll_lcladdr.pta_pppoe.ptma_mac[4], 547 tll->tll_lcladdr.pta_pppoe.ptma_mac[5]); 548 } 549 mdb_printf("\n"); 550 551 return (WALK_NEXT); 552 } 553 554 /* ARGSUSED */ 555 static int 556 tunll(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 557 { 558 uint_t qfmt = FALSE; 559 tunll_t tll; 560 561 if ((flags & DCMD_LOOPFIRST) || !(flags & DCMD_LOOP)) { 562 mdb_printf("%<u>%?s %-14s %?s %s%</u>\n", "Address", 563 "Interface Name", "Daemon", "Local Address"); 564 } 565 566 if (flags & DCMD_ADDRSPEC) { 567 if (mdb_vread(&tll, sizeof (tll), addr) == -1) 568 mdb_warn("failed to read tunll_t at %p", addr); 569 else 570 tunll_format(addr, &tll, &qfmt); 571 } else if (mdb_walk("tunll", (mdb_walk_cb_t)tunll_format, &qfmt) == 572 -1) { 573 mdb_warn("failed to walk tunll_list"); 574 return (DCMD_ERR); 575 } 576 577 return (DCMD_OK); 578 } 579 580 union tun_state { 581 uint32_t tunflags; 582 tuncl_t tcl; 583 tunll_t tll; 584 }; 585 586 static int 587 tun_state_read(void *ptr, union tun_state *ts) 588 { 589 /* 590 * First, get the flags on this structure. This is either a 591 * tuncl_t or a tunll_t. 592 */ 593 if (mdb_vread(&ts->tunflags, sizeof (ts->tunflags), (uintptr_t)ptr) == 594 sizeof (ts->tunflags)) { 595 if (ts->tunflags & TCLF_ISCLIENT) { 596 if (mdb_vread(&ts->tcl, sizeof (ts->tcl), 597 (uintptr_t)ptr) == sizeof (ts->tcl)) { 598 return (0); 599 } 600 } else { 601 if (mdb_vread(&ts->tll, sizeof (ts->tll), 602 (uintptr_t)ptr) == sizeof (ts->tll)) { 603 return (0); 604 } 605 } 606 } 607 return (-1); 608 } 609 610 static void 611 sppptun_qinfo(const queue_t *q, char *buf, size_t nbytes) 612 { 613 union tun_state ts; 614 615 if (tun_state_read(q->q_ptr, &ts) == -1) 616 return; 617 618 if (ts.tcl.tcl_flags & TCLF_ISCLIENT) 619 mdb_snprintf(buf, nbytes, "sppp%d client %04X", 620 ts.tcl.tcl_unit, ts.tcl.tcl_lsessid); 621 else 622 mdb_snprintf(buf, nbytes, "%s", ts.tll.tll_name); 623 } 624 625 static uintptr_t 626 sppptun_rnext(const queue_t *q) 627 { 628 union tun_state ts; 629 630 if (tun_state_read(q->q_ptr, &ts) == -1) 631 return (NULL); 632 633 if (ts.tcl.tcl_flags & TCLF_ISCLIENT) { 634 return ((uintptr_t)ts.tcl.tcl_rq); 635 } else { 636 /* Not quite right, but ... */ 637 return ((uintptr_t)ts.tll.tll_defcl); 638 } 639 } 640 641 static uintptr_t 642 sppptun_wnext(const queue_t *q) 643 { 644 union tun_state ts; 645 646 if (tun_state_read(q->q_ptr, &ts) == -1) 647 return (NULL); 648 649 if (ts.tcl.tcl_flags & TCLF_ISCLIENT) { 650 if (ts.tcl.tcl_data_tll == NULL) 651 return (NULL); 652 if (mdb_vread(&ts.tll, sizeof (ts.tll), 653 (uintptr_t)ts.tcl.tcl_data_tll) != sizeof (ts.tll)) { 654 return (NULL); 655 } 656 } 657 return ((uintptr_t)ts.tll.tll_wq); 658 } 659 660 static const mdb_dcmd_t dcmds[] = { 661 { "sppp", "[-q]", "display PPP stream state structures", sppp }, 662 { "sppa", "", "display PPP attachment state structures", sppa }, 663 { "tuncl", "", "display sppptun client stream state structures", 664 tuncl }, 665 { "tunll", "", "display sppptun lower stream state structures", 666 tunll }, 667 { NULL } 668 }; 669 670 static const mdb_walker_t walkers[] = { 671 { "sppp", "walk active spppstr_t structures", 672 sppp_walk_init, sppp_walk_step, NULL }, 673 { "sppa", "walk active sppa_t structures", 674 sppa_walk_init, sppa_walk_step, NULL }, 675 { "tuncl", "walk active tuncl_t structures", 676 tuncl_walk_init, tuncl_walk_step, tuncl_walk_fini }, 677 { "tunll", "walk active tunll_t structures", 678 tunll_walk_init, tunll_walk_step, tunll_walk_fini }, 679 { NULL } 680 }; 681 682 static const mdb_qops_t sppp_qops = { sppp_qinfo, sppp_rnext, sppp_wnext }; 683 static const mdb_qops_t sppptun_qops = { 684 sppptun_qinfo, sppptun_rnext, sppptun_wnext 685 }; 686 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers }; 687 688 const mdb_modinfo_t * 689 _mdb_init(void) 690 { 691 GElf_Sym sym; 692 693 if (mdb_lookup_by_obj("sppp", "sppp_uwinit", &sym) == 0) 694 mdb_qops_install(&sppp_qops, (uintptr_t)sym.st_value); 695 696 if (mdb_lookup_by_obj("sppptun", "sppptun_uwinit", &sym) == 0) 697 mdb_qops_install(&sppptun_qops, (uintptr_t)sym.st_value); 698 699 return (&modinfo); 700 } 701 702 void 703 _mdb_fini(void) 704 { 705 GElf_Sym sym; 706 707 if (mdb_lookup_by_obj("sppptun", "sppptun_uwinit", &sym) == 0) 708 mdb_qops_remove(&sppptun_qops, (uintptr_t)sym.st_value); 709 710 if (mdb_lookup_by_obj("sppp", "sppp_uwinit", &sym) == 0) 711 mdb_qops_remove(&sppp_qops, (uintptr_t)sym.st_value); 712 } 713