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 2006 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 <mdb/mdb_modapi.h> 29 #include <mdb/mdb_ks.h> 30 31 #include <sys/types.h> 32 #include <sys/mman.h> 33 #include <sys/project.h> 34 #include <sys/ipc_impl.h> 35 #include <sys/shm_impl.h> 36 #include <sys/sem_impl.h> 37 #include <sys/msg_impl.h> 38 39 #include <vm/anon.h> 40 41 #define CMN_HDR_START "%<u>" 42 #define CMN_HDR_END "%</u>\n" 43 #define CMN_INDENT (4) 44 #define CMN_INACTIVE "%s facility inactive.\n" 45 46 /* 47 * Bitmap data for page protection flags suitable for use with %b. 48 */ 49 const mdb_bitmask_t prot_flag_bits[] = { 50 { "PROT_READ", PROT_READ, PROT_READ }, 51 { "PROT_WRITE", PROT_WRITE, PROT_WRITE }, 52 { "PROT_EXEC", PROT_EXEC, PROT_EXEC }, 53 { "PROT_USER", PROT_USER, PROT_USER }, 54 { NULL, 0, 0 } 55 }; 56 57 static void 58 printtime_nice(const char *str, time_t time) 59 { 60 if (time) 61 mdb_printf("%s%Y\n", str, time); 62 else 63 mdb_printf("%sn/a\n", str); 64 } 65 66 /* 67 * Print header common to all IPC types. 68 */ 69 static void 70 ipcperm_header() 71 { 72 mdb_printf(CMN_HDR_START "%?s %5s %5s %8s %5s %5s %6s %5s %5s %5s %5s" 73 CMN_HDR_END, "ADDR", "REF", "ID", "KEY", "MODE", "PRJID", "ZONEID", 74 "OWNER", "GROUP", "CREAT", "CGRP"); 75 } 76 77 /* 78 * Print data common to all IPC types. 79 */ 80 static void 81 ipcperm_print(uintptr_t addr, kipc_perm_t *perm) 82 { 83 kproject_t proj; 84 int res; 85 86 res = mdb_vread(&proj, sizeof (kproject_t), (uintptr_t)perm->ipc_proj); 87 88 if (res == -1) 89 mdb_warn("failed to read kproject_t at %#p", perm->ipc_proj); 90 91 mdb_printf("%0?p %5d %5d", addr, perm->ipc_ref, perm->ipc_id); 92 if (perm->ipc_key) 93 mdb_printf(" %8x", perm->ipc_key); 94 else 95 mdb_printf(" %8s", "private"); 96 mdb_printf(" %5#o", perm->ipc_mode & 07777); 97 if (res == -1) 98 mdb_printf(" %5s %5s", "<flt>", "<flt>"); 99 else 100 mdb_printf(" %5d %6d", proj.kpj_id, proj.kpj_zoneid); 101 mdb_printf(" %5d %5d %5d %5d\n", perm->ipc_uid, perm->ipc_gid, 102 perm->ipc_cuid, perm->ipc_cgid); 103 104 } 105 106 /*ARGSUSED*/ 107 static int 108 ipcperm(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 109 { 110 kipc_perm_t perm; 111 112 if (!(flags & DCMD_ADDRSPEC)) 113 return (DCMD_USAGE); 114 115 if (DCMD_HDRSPEC(flags)) 116 ipcperm_header(); 117 118 if (mdb_vread(&perm, sizeof (kipc_perm_t), addr) == -1) { 119 mdb_warn("failed to read kipc_perm_t at %#lx", addr); 120 return (DCMD_ERR); 121 } 122 123 ipcperm_print(addr, &perm); 124 return (DCMD_OK); 125 } 126 127 static void 128 msq_print(kmsqid_t *msqid, uintptr_t addr) 129 { 130 int ii; 131 132 mdb_printf("&list: %-?p\n", addr + OFFSETOF(kmsqid_t, msg_list)); 133 mdb_printf("cbytes: 0t%lu qnum: 0t%lu qbytes: 0t%lu" 134 " qmax: 0t%lu\n", msqid->msg_cbytes, msqid->msg_qnum, 135 msqid->msg_qbytes, msqid->msg_qmax); 136 mdb_printf("lspid: 0t%d lrpid: 0t%d\n", 137 (int)msqid->msg_lspid, (int)msqid->msg_lrpid); 138 printtime_nice("stime: ", msqid->msg_stime); 139 printtime_nice("rtime: ", msqid->msg_rtime); 140 printtime_nice("ctime: ", msqid->msg_ctime); 141 mdb_printf("snd_cnt: 0t%lld snd_cv: %hd (%p)\n", 142 msqid->msg_snd_cnt, msqid->msg_snd_cv._opaque, 143 addr + (uintptr_t)OFFSETOF(kmsqid_t, msg_snd_cv)); 144 145 mdb_printf("# rcv_cnt: rcv_cv:\n"); 146 for (ii = 0; ii < MAX_QNUM_CV; ii++) { 147 if (msqid->msg_rcv_cnt[ii] || msqid->msg_rcv_cv[ii]._opaque) { 148 mdb_printf("%2d 0t%lld %hd (%p)\n", ii, 149 msqid->msg_rcv_cnt[ii], 150 msqid->msg_rcv_cv[ii]._opaque, addr + 151 (uintptr_t)OFFSETOF(kmsqid_t, msg_rcv_cv[ii])); 152 } 153 } 154 } 155 156 157 /*ARGSUSED1*/ 158 static void 159 shm_print(kshmid_t *shmid, uintptr_t addr) 160 { 161 shmatt_t nattch; 162 163 nattch = shmid->shm_perm.ipc_ref - (IPC_FREE(&shmid->shm_perm) ? 0 : 1); 164 165 mdb_printf(CMN_HDR_START "%10s %?s %5s %7s %7s %7s %7s" CMN_HDR_END, 166 "SEGSZ", "AMP", "LKCNT", "LPID", "CPID", "NATTCH", "CNATTCH"); 167 mdb_printf("%10#lx %?p %5u %7d %7d %7lu %7lu\n", 168 shmid->shm_segsz, shmid->shm_amp, shmid->shm_lkcnt, 169 (int)shmid->shm_lpid, (int)shmid->shm_cpid, nattch, 170 shmid->shm_ismattch); 171 172 printtime_nice("atime: ", shmid->shm_atime); 173 printtime_nice("dtime: ", shmid->shm_dtime); 174 printtime_nice("ctime: ", shmid->shm_ctime); 175 mdb_printf("sptinfo: %-?p sptseg: %-?p\n", 176 shmid->shm_sptinfo, shmid->shm_sptseg); 177 mdb_printf("sptprot: <%lb>\n", shmid->shm_sptprot, prot_flag_bits); 178 } 179 180 181 /*ARGSUSED1*/ 182 static void 183 sem_print(ksemid_t *semid, uintptr_t addr) 184 { 185 mdb_printf("base: %-?p nsems: 0t%u\n", 186 semid->sem_base, semid->sem_nsems); 187 printtime_nice("otime: ", semid->sem_otime); 188 printtime_nice("ctime: ", semid->sem_ctime); 189 mdb_printf("binary: %s\n", semid->sem_binary ? "yes" : "no"); 190 } 191 192 typedef struct ipc_ops_vec { 193 char *iv_wcmd; /* walker name */ 194 char *iv_ocmd; /* output dcmd */ 195 char *iv_service; /* service pointer */ 196 void (*iv_print)(void *, uintptr_t); /* output callback */ 197 size_t iv_idsize; 198 } ipc_ops_vec_t; 199 200 ipc_ops_vec_t msq_ops_vec = { 201 "msq", 202 "kmsqid", 203 "msq_svc", 204 (void(*)(void *, uintptr_t))msq_print, 205 sizeof (kmsqid_t) 206 }; 207 208 ipc_ops_vec_t shm_ops_vec = { 209 "shm", 210 "kshmid", 211 "shm_svc", 212 (void(*)(void *, uintptr_t))shm_print, 213 sizeof (kshmid_t) 214 }; 215 216 ipc_ops_vec_t sem_ops_vec = { 217 "sem", 218 "ksemid", 219 "sem_svc", 220 (void(*)(void *, uintptr_t))sem_print, 221 sizeof (ksemid_t) 222 }; 223 224 225 /* 226 * Generic IPC data structure display code 227 */ 228 static int 229 ds_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv, 230 ipc_ops_vec_t *iv) 231 { 232 void *iddata; 233 234 if (!(flags & DCMD_ADDRSPEC)) { 235 uint_t oflags = 0; 236 237 if (mdb_getopts(argc, argv, 'l', MDB_OPT_SETBITS, 1, &oflags, 238 NULL) != argc) 239 return (DCMD_USAGE); 240 241 if (mdb_walk_dcmd(iv->iv_wcmd, oflags ? iv->iv_ocmd : "ipcperm", 242 argc, argv) == -1) { 243 mdb_warn("can't walk '%s'", iv->iv_wcmd); 244 return (DCMD_ERR); 245 } 246 return (DCMD_OK); 247 } 248 249 iddata = mdb_alloc(iv->iv_idsize, UM_SLEEP | UM_GC); 250 if (mdb_vread(iddata, iv->iv_idsize, addr) == -1) { 251 mdb_warn("failed to read %s at %#lx", iv->iv_ocmd, addr); 252 return (DCMD_ERR); 253 } 254 255 if (!DCMD_HDRSPEC(flags) && iv->iv_print) 256 mdb_printf("\n"); 257 258 if (DCMD_HDRSPEC(flags) || iv->iv_print) 259 ipcperm_header(); 260 261 ipcperm_print(addr, (struct kipc_perm *)iddata); 262 if (iv->iv_print) { 263 mdb_inc_indent(CMN_INDENT); 264 iv->iv_print(iddata, addr); 265 mdb_dec_indent(CMN_INDENT); 266 } 267 268 return (DCMD_OK); 269 } 270 271 272 /* 273 * Stubs to call ds_print with the appropriate ops vector 274 */ 275 static int 276 cmd_kshmid(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 277 { 278 return (ds_print(addr, flags, argc, argv, &shm_ops_vec)); 279 } 280 281 282 static int 283 cmd_kmsqid(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 284 { 285 return (ds_print(addr, flags, argc, argv, &msq_ops_vec)); 286 } 287 288 static int 289 cmd_ksemid(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 290 { 291 return (ds_print(addr, flags, argc, argv, &sem_ops_vec)); 292 } 293 294 /* 295 * Generic IPC walker 296 */ 297 298 static int 299 ds_walk_init(mdb_walk_state_t *wsp) 300 { 301 ipc_ops_vec_t *iv = wsp->walk_arg; 302 303 if (wsp->walk_arg != NULL && wsp->walk_addr != NULL) 304 mdb_printf("ignoring provided address\n"); 305 306 if (wsp->walk_arg) 307 if (mdb_readvar(&wsp->walk_addr, iv->iv_service) == -1) { 308 mdb_printf("failed to read '%s'; module not present\n", 309 iv->iv_service); 310 return (WALK_DONE); 311 } 312 else 313 wsp->walk_addr = wsp->walk_addr + 314 OFFSETOF(ipc_service_t, ipcs_usedids); 315 316 if (mdb_layered_walk("list", wsp) == -1) 317 return (WALK_ERR); 318 319 return (WALK_NEXT); 320 } 321 322 323 static int 324 ds_walk_step(mdb_walk_state_t *wsp) 325 { 326 return (wsp->walk_callback(wsp->walk_addr, wsp->walk_layer, 327 wsp->walk_cbdata)); 328 } 329 330 /* 331 * Generic IPC ID/key to pointer code 332 */ 333 334 static int 335 ipcid_impl(uintptr_t svcptr, uintptr_t id, uintptr_t *addr) 336 { 337 ipc_service_t service; 338 kipc_perm_t perm; 339 ipc_slot_t slot; 340 uintptr_t slotptr; 341 uint_t index; 342 343 if (id > INT_MAX) { 344 mdb_warn("id out of range\n"); 345 return (DCMD_ERR); 346 } 347 348 if (mdb_vread(&service, sizeof (ipc_service_t), svcptr) == -1) { 349 mdb_warn("failed to read ipc_service_t at %#lx", svcptr); 350 return (DCMD_ERR); 351 } 352 353 index = (uint_t)id & (service.ipcs_tabsz - 1); 354 slotptr = (uintptr_t)(service.ipcs_table + index); 355 356 if (mdb_vread(&slot, sizeof (ipc_slot_t), slotptr) == -1) { 357 mdb_warn("failed to read ipc_slot_t at %#lx", slotptr); 358 return (DCMD_ERR); 359 } 360 361 if (slot.ipct_data == NULL) 362 return (DCMD_ERR); 363 364 if (mdb_vread(&perm, sizeof (kipc_perm_t), 365 (uintptr_t)slot.ipct_data) == -1) { 366 mdb_warn("failed to read kipc_perm_t at %#p", 367 slot.ipct_data); 368 return (DCMD_ERR); 369 } 370 371 if (perm.ipc_id != (uint_t)id) 372 return (DCMD_ERR); 373 374 *addr = (uintptr_t)slot.ipct_data; 375 376 return (DCMD_OK); 377 } 378 379 380 typedef struct findkey_data { 381 key_t fk_key; 382 uintptr_t fk_addr; 383 boolean_t fk_found; 384 } findkey_data_t; 385 386 static int 387 findkey(uintptr_t addr, kipc_perm_t *perm, findkey_data_t *arg) 388 { 389 if (perm->ipc_key == arg->fk_key) { 390 arg->fk_found = B_TRUE; 391 arg->fk_addr = addr; 392 return (WALK_DONE); 393 } 394 return (WALK_NEXT); 395 } 396 397 static int 398 ipckey_impl(uintptr_t svcptr, uintptr_t key, uintptr_t *addr) 399 { 400 ipc_service_t service; 401 findkey_data_t fkdata; 402 403 if ((key == IPC_PRIVATE) || (key > INT_MAX)) { 404 mdb_warn("key out of range\n"); 405 return (DCMD_ERR); 406 } 407 408 if (mdb_vread(&service, sizeof (ipc_service_t), svcptr) == -1) { 409 mdb_warn("failed to read ipc_service_t at %#lx", svcptr); 410 return (DCMD_ERR); 411 } 412 413 fkdata.fk_key = (key_t)key; 414 fkdata.fk_found = B_FALSE; 415 if ((mdb_pwalk("avl", (mdb_walk_cb_t)findkey, &fkdata, 416 svcptr + OFFSETOF(ipc_service_t, ipcs_keys)) == -1) || 417 !fkdata.fk_found) 418 return (DCMD_ERR); 419 420 *addr = fkdata.fk_addr; 421 422 return (DCMD_OK); 423 } 424 425 static int 426 ipckeyid(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv, 427 int(*fp)(uintptr_t, uintptr_t, uintptr_t *)) 428 { 429 uintmax_t val; 430 uintptr_t raddr; 431 int result; 432 433 if (!(flags & DCMD_ADDRSPEC) || (argc != 1)) 434 return (DCMD_USAGE); 435 436 if (argv[0].a_type == MDB_TYPE_IMMEDIATE) 437 val = argv[0].a_un.a_val; 438 else if (argv[0].a_type == MDB_TYPE_STRING) 439 val = mdb_strtoull(argv[0].a_un.a_str); 440 else 441 return (DCMD_USAGE); 442 443 result = fp(addr, val, &raddr); 444 445 if (result == DCMD_OK) 446 mdb_printf("%lx", raddr); 447 448 return (result); 449 } 450 451 static int 452 ipckey(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 453 { 454 return (ipckeyid(addr, flags, argc, argv, ipckey_impl)); 455 } 456 457 static int 458 ipcid(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 459 { 460 return (ipckeyid(addr, flags, argc, argv, ipcid_impl)); 461 } 462 463 static int 464 ds_ptr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv, 465 ipc_ops_vec_t *iv) 466 { 467 uint_t kflag = FALSE; 468 uintptr_t svcptr, raddr; 469 int result; 470 471 if (!(flags & DCMD_ADDRSPEC)) 472 return (DCMD_USAGE); 473 474 if (mdb_getopts(argc, argv, 475 'k', MDB_OPT_SETBITS, TRUE, &kflag, NULL) != argc) 476 return (DCMD_USAGE); 477 478 if (mdb_readvar(&svcptr, iv->iv_service) == -1) { 479 mdb_warn("failed to read '%s'; module not present\n", 480 iv->iv_service); 481 return (DCMD_ERR); 482 } 483 484 result = kflag ? ipckey_impl(svcptr, addr, &raddr) : 485 ipcid_impl(svcptr, addr, &raddr); 486 487 if (result == DCMD_OK) 488 mdb_printf("%lx", raddr); 489 490 return (result); 491 } 492 493 /* 494 * Stubs to call ds_ptr with the appropriate ops vector 495 */ 496 static int 497 id2shm(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 498 { 499 return (ds_ptr(addr, flags, argc, argv, &shm_ops_vec)); 500 } 501 502 static int 503 id2msq(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 504 { 505 return (ds_ptr(addr, flags, argc, argv, &msq_ops_vec)); 506 } 507 508 static int 509 id2sem(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 510 { 511 return (ds_ptr(addr, flags, argc, argv, &sem_ops_vec)); 512 } 513 514 515 /* 516 * The message queue contents walker 517 */ 518 519 static int 520 msg_walk_init(mdb_walk_state_t *wsp) 521 { 522 wsp->walk_addr += OFFSETOF(kmsqid_t, msg_list); 523 if (mdb_layered_walk("list", wsp) == -1) 524 return (WALK_ERR); 525 526 return (WALK_NEXT); 527 } 528 529 static int 530 msg_walk_step(mdb_walk_state_t *wsp) 531 { 532 return (wsp->walk_callback(wsp->walk_addr, wsp->walk_layer, 533 wsp->walk_cbdata)); 534 } 535 536 537 /* 538 * The "::ipcs" command itself. Just walks each IPC type in turn. 539 */ 540 541 /*ARGSUSED*/ 542 static int 543 ipcs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 544 { 545 uint_t oflags = 0; 546 547 if ((flags & DCMD_ADDRSPEC) || mdb_getopts(argc, argv, 'l', 548 MDB_OPT_SETBITS, 1, &oflags, NULL) != argc) 549 return (DCMD_USAGE); 550 551 mdb_printf("Message queues:\n"); 552 if (mdb_walk_dcmd("msq", oflags ? "kmsqid" : "ipcperm", argc, argv) == 553 -1) { 554 mdb_warn("can't walk 'msq'"); 555 return (DCMD_ERR); 556 } 557 558 mdb_printf("\nShared memory:\n"); 559 if (mdb_walk_dcmd("shm", oflags ? "kshmid" : "ipcperm", argc, argv) == 560 -1) { 561 mdb_warn("can't walk 'shm'"); 562 return (DCMD_ERR); 563 } 564 565 mdb_printf("\nSemaphores:\n"); 566 if (mdb_walk_dcmd("sem", oflags ? "ksemid" : "ipcperm", argc, argv) == 567 -1) { 568 mdb_warn("can't walk 'sem'"); 569 return (DCMD_ERR); 570 } 571 572 return (DCMD_OK); 573 } 574 575 static int 576 msgprint(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 577 { 578 struct msg message; 579 uint_t lflag = FALSE; 580 long type = 0; 581 char *tflag = NULL; 582 583 if (!(flags & DCMD_ADDRSPEC) || (mdb_getopts(argc, argv, 584 'l', MDB_OPT_SETBITS, TRUE, &lflag, 585 't', MDB_OPT_STR, &tflag, NULL) != argc)) 586 return (DCMD_USAGE); 587 588 /* 589 * Handle negative values. 590 */ 591 if (tflag != NULL) { 592 if (*tflag == '-') { 593 tflag++; 594 type = -1; 595 } else { 596 type = 1; 597 } 598 type *= mdb_strtoull(tflag); 599 } 600 601 if (DCMD_HDRSPEC(flags)) 602 mdb_printf("%<u>%?s %?s %8s %8s %8s%</u>\n", 603 "ADDR", "TEXT", "SIZE", "TYPE", "REF"); 604 605 if (mdb_vread(&message, sizeof (struct msg), addr) == -1) { 606 mdb_warn("failed to read msg at %#lx", addr); 607 return (DCMD_ERR); 608 } 609 610 /* 611 * If we are meeting our type contraints, display the message. 612 * If -l was specified, we will also display the message 613 * contents. 614 */ 615 if ((type == 0) || 616 (type > 0 && message.msg_type == type) || 617 (type < 0 && message.msg_type <= -type)) { 618 619 if (lflag && !DCMD_HDRSPEC(flags)) 620 mdb_printf("\n"); 621 622 mdb_printf("%0?lx %?p %8ld %8ld %8ld\n", addr, message.msg_addr, 623 message.msg_size, message.msg_type, message.msg_copycnt); 624 625 if (lflag) { 626 mdb_printf("\n"); 627 mdb_inc_indent(CMN_INDENT); 628 if (mdb_dumpptr( 629 (uintptr_t)message.msg_addr, message.msg_size, 630 MDB_DUMP_RELATIVE | MDB_DUMP_TRIM | 631 MDB_DUMP_ASCII | MDB_DUMP_HEADER | 632 MDB_DUMP_GROUP(4), 633 (mdb_dumpptr_cb_t)mdb_vread, NULL)) { 634 mdb_dec_indent(CMN_INDENT); 635 return (DCMD_ERR); 636 } 637 mdb_dec_indent(CMN_INDENT); 638 } 639 } 640 641 return (DCMD_OK); 642 } 643 644 /* 645 * MDB module linkage 646 */ 647 static const mdb_dcmd_t dcmds[] = { 648 /* Generic routines */ 649 { "ipcperm", ":", "display an IPC perm structure", ipcperm }, 650 { "ipcid", ":id", "perform an IPC id lookup", ipcid }, 651 { "ipckey", ":key", "perform an IPC key lookup", ipckey }, 652 653 /* Specific routines */ 654 { "kshmid", "?[-l]", "display a struct kshmid", cmd_kshmid }, 655 { "kmsqid", "?[-l]", "display a struct kmsqid", cmd_kmsqid }, 656 { "ksemid", "?[-l]", "display a struct ksemid", cmd_ksemid }, 657 { "msg", ":[-l] [-t type]", "display contents of a message", msgprint }, 658 659 /* Convenience routines */ 660 { "id2shm", ":[-k]", "convert shared memory ID to pointer", id2shm }, 661 { "id2msq", ":[-k]", "convert message queue ID to pointer", id2msq }, 662 { "id2sem", ":[-k]", "convert semaphore ID to pointer", id2sem }, 663 664 { "ipcs", "[-l]", "display System V IPC information", ipcs }, 665 { NULL } 666 }; 667 668 static const mdb_walker_t walkers[] = { 669 { "ipcsvc", "walk a System V IPC service", 670 ds_walk_init, ds_walk_step }, 671 { "shm", "walk the active shmid_ds structures", 672 ds_walk_init, ds_walk_step, NULL, &shm_ops_vec }, 673 { "msq", "walk the active msqid_ds structures", 674 ds_walk_init, ds_walk_step, NULL, &msq_ops_vec }, 675 { "sem", "walk the active semid_ds structures", 676 ds_walk_init, ds_walk_step, NULL, &sem_ops_vec }, 677 { "msgqueue", "walk messages on a message queue", 678 msg_walk_init, msg_walk_step }, 679 { NULL } 680 }; 681 682 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers }; 683 684 const mdb_modinfo_t * 685 _mdb_init(void) 686 { 687 return (&modinfo); 688 } 689