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