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 <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 128 static int 129 msgq_check_for_rwaiters(list_t *walk_this, int min, int max, 130 int copy_wait, uintptr_t addr) 131 132 { 133 int found = 0; 134 int ii; 135 msgq_wakeup_t *walker, next; 136 uintptr_t head; 137 138 for (ii = min; ii < max; ii++) { 139 head = ((ulong_t)addr) + sizeof (list_t)*ii + 140 sizeof (list_node_t); 141 if (head != (uintptr_t)walk_this[ii].list_head.list_next) { 142 walker = 143 (msgq_wakeup_t *)walk_this[ii].list_head.list_next; 144 while (head != (uintptr_t)walker) { 145 if (mdb_vread(&next, sizeof (msgq_wakeup_t), 146 (uintptr_t)walker) == -1) { 147 mdb_warn( 148 "Failed to read message queue\n"); 149 return (0); 150 } 151 mdb_printf("%15lx\t%6d\t%15lx\t%15s\n", 152 next.msgw_thrd, next.msgw_type, 153 walker + (uintptr_t) 154 OFFSETOF(msgq_wakeup_t, msgw_wake_cv), 155 (copy_wait ? "yes":"no")); 156 found++; 157 walker = 158 (msgq_wakeup_t *)next.msgw_list.list_next; 159 } 160 } 161 } 162 return (found); 163 } 164 165 static void 166 msq_print(kmsqid_t *msqid, uintptr_t addr) 167 { 168 int total = 0; 169 170 mdb_printf("&list: %-?p\n", addr + OFFSETOF(kmsqid_t, msg_list)); 171 mdb_printf("cbytes: 0t%lu qnum: 0t%lu qbytes: 0t%lu" 172 " qmax: 0t%lu\n", msqid->msg_cbytes, msqid->msg_qnum, 173 msqid->msg_qbytes, msqid->msg_qmax); 174 mdb_printf("lspid: 0t%d lrpid: 0t%d\n", 175 (int)msqid->msg_lspid, (int)msqid->msg_lrpid); 176 printtime_nice("stime: ", msqid->msg_stime); 177 printtime_nice("rtime: ", msqid->msg_rtime); 178 printtime_nice("ctime: ", msqid->msg_ctime); 179 mdb_printf("snd_cnt: 0t%lld snd_cv: %hd (%p)\n", 180 msqid->msg_snd_cnt, msqid->msg_snd_cv._opaque, 181 addr + (uintptr_t)OFFSETOF(kmsqid_t, msg_snd_cv)); 182 mdb_printf("Blocked recievers\n"); 183 mdb_printf("%15s\t%6s\t%15s\t%15s\n", "Thread Addr", 184 "Type", "cv addr", "copyout-wait?"); 185 total += msgq_check_for_rwaiters(&msqid->msg_cpy_block, 186 0, 1, 1, addr + OFFSETOF(kmsqid_t, msg_cpy_block)); 187 total += msgq_check_for_rwaiters(msqid->msg_wait_snd, 188 0, MSG_MAX_QNUM + 1, 0, addr + OFFSETOF(kmsqid_t, msg_wait_snd)); 189 total += msgq_check_for_rwaiters(msqid->msg_wait_snd_ngt, 190 0, MSG_MAX_QNUM + 1, 0, 191 addr + OFFSETOF(kmsqid_t, msg_wait_snd_ngt)); 192 mdb_printf("Total number of waiters: %d\n", total); 193 } 194 195 196 /*ARGSUSED1*/ 197 static void 198 shm_print(kshmid_t *shmid, uintptr_t addr) 199 { 200 shmatt_t nattch; 201 202 nattch = shmid->shm_perm.ipc_ref - (IPC_FREE(&shmid->shm_perm) ? 0 : 1); 203 204 mdb_printf(CMN_HDR_START "%10s %?s %5s %7s %7s %7s %7s" CMN_HDR_END, 205 "SEGSZ", "AMP", "LKCNT", "LPID", "CPID", "NATTCH", "CNATTCH"); 206 mdb_printf("%10#lx %?p %5u %7d %7d %7lu %7lu\n", 207 shmid->shm_segsz, shmid->shm_amp, shmid->shm_lkcnt, 208 (int)shmid->shm_lpid, (int)shmid->shm_cpid, nattch, 209 shmid->shm_ismattch); 210 211 printtime_nice("atime: ", shmid->shm_atime); 212 printtime_nice("dtime: ", shmid->shm_dtime); 213 printtime_nice("ctime: ", shmid->shm_ctime); 214 mdb_printf("sptinfo: %-?p sptseg: %-?p\n", 215 shmid->shm_sptinfo, shmid->shm_sptseg); 216 mdb_printf("sptprot: <%lb>\n", shmid->shm_sptprot, prot_flag_bits); 217 } 218 219 220 /*ARGSUSED1*/ 221 static void 222 sem_print(ksemid_t *semid, uintptr_t addr) 223 { 224 mdb_printf("base: %-?p nsems: 0t%u\n", 225 semid->sem_base, semid->sem_nsems); 226 printtime_nice("otime: ", semid->sem_otime); 227 printtime_nice("ctime: ", semid->sem_ctime); 228 mdb_printf("binary: %s\n", semid->sem_binary ? "yes" : "no"); 229 } 230 231 typedef struct ipc_ops_vec { 232 char *iv_wcmd; /* walker name */ 233 char *iv_ocmd; /* output dcmd */ 234 char *iv_service; /* service pointer */ 235 void (*iv_print)(void *, uintptr_t); /* output callback */ 236 size_t iv_idsize; 237 } ipc_ops_vec_t; 238 239 ipc_ops_vec_t msq_ops_vec = { 240 "msq", 241 "kmsqid", 242 "msq_svc", 243 (void(*)(void *, uintptr_t))msq_print, 244 sizeof (kmsqid_t) 245 }; 246 247 ipc_ops_vec_t shm_ops_vec = { 248 "shm", 249 "kshmid", 250 "shm_svc", 251 (void(*)(void *, uintptr_t))shm_print, 252 sizeof (kshmid_t) 253 }; 254 255 ipc_ops_vec_t sem_ops_vec = { 256 "sem", 257 "ksemid", 258 "sem_svc", 259 (void(*)(void *, uintptr_t))sem_print, 260 sizeof (ksemid_t) 261 }; 262 263 264 /* 265 * Generic IPC data structure display code 266 */ 267 static int 268 ds_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv, 269 ipc_ops_vec_t *iv) 270 { 271 void *iddata; 272 273 if (!(flags & DCMD_ADDRSPEC)) { 274 uint_t oflags = 0; 275 276 if (mdb_getopts(argc, argv, 'l', MDB_OPT_SETBITS, 1, &oflags, 277 NULL) != argc) 278 return (DCMD_USAGE); 279 280 if (mdb_walk_dcmd(iv->iv_wcmd, oflags ? iv->iv_ocmd : "ipcperm", 281 argc, argv) == -1) { 282 mdb_warn("can't walk '%s'", iv->iv_wcmd); 283 return (DCMD_ERR); 284 } 285 return (DCMD_OK); 286 } 287 288 iddata = mdb_alloc(iv->iv_idsize, UM_SLEEP | UM_GC); 289 if (mdb_vread(iddata, iv->iv_idsize, addr) == -1) { 290 mdb_warn("failed to read %s at %#lx", iv->iv_ocmd, addr); 291 return (DCMD_ERR); 292 } 293 294 if (!DCMD_HDRSPEC(flags) && iv->iv_print) 295 mdb_printf("\n"); 296 297 if (DCMD_HDRSPEC(flags) || iv->iv_print) 298 ipcperm_header(); 299 300 ipcperm_print(addr, (struct kipc_perm *)iddata); 301 if (iv->iv_print) { 302 mdb_inc_indent(CMN_INDENT); 303 iv->iv_print(iddata, addr); 304 mdb_dec_indent(CMN_INDENT); 305 } 306 307 return (DCMD_OK); 308 } 309 310 311 /* 312 * Stubs to call ds_print with the appropriate ops vector 313 */ 314 static int 315 cmd_kshmid(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 316 { 317 return (ds_print(addr, flags, argc, argv, &shm_ops_vec)); 318 } 319 320 321 static int 322 cmd_kmsqid(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 323 { 324 return (ds_print(addr, flags, argc, argv, &msq_ops_vec)); 325 } 326 327 static int 328 cmd_ksemid(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 329 { 330 return (ds_print(addr, flags, argc, argv, &sem_ops_vec)); 331 } 332 333 /* 334 * Generic IPC walker 335 */ 336 337 static int 338 ds_walk_init(mdb_walk_state_t *wsp) 339 { 340 ipc_ops_vec_t *iv = wsp->walk_arg; 341 342 if (wsp->walk_arg != NULL && wsp->walk_addr != NULL) 343 mdb_printf("ignoring provided address\n"); 344 345 if (wsp->walk_arg) 346 if (mdb_readvar(&wsp->walk_addr, iv->iv_service) == -1) { 347 mdb_printf("failed to read '%s'; module not present\n", 348 iv->iv_service); 349 return (WALK_DONE); 350 } 351 else 352 wsp->walk_addr = wsp->walk_addr + 353 OFFSETOF(ipc_service_t, ipcs_usedids); 354 355 if (mdb_layered_walk("list", wsp) == -1) 356 return (WALK_ERR); 357 358 return (WALK_NEXT); 359 } 360 361 362 static int 363 ds_walk_step(mdb_walk_state_t *wsp) 364 { 365 return (wsp->walk_callback(wsp->walk_addr, wsp->walk_layer, 366 wsp->walk_cbdata)); 367 } 368 369 /* 370 * Generic IPC ID/key to pointer code 371 */ 372 373 static int 374 ipcid_impl(uintptr_t svcptr, uintptr_t id, uintptr_t *addr) 375 { 376 ipc_service_t service; 377 kipc_perm_t perm; 378 ipc_slot_t slot; 379 uintptr_t slotptr; 380 uint_t index; 381 382 if (id > INT_MAX) { 383 mdb_warn("id out of range\n"); 384 return (DCMD_ERR); 385 } 386 387 if (mdb_vread(&service, sizeof (ipc_service_t), svcptr) == -1) { 388 mdb_warn("failed to read ipc_service_t at %#lx", svcptr); 389 return (DCMD_ERR); 390 } 391 392 index = (uint_t)id & (service.ipcs_tabsz - 1); 393 slotptr = (uintptr_t)(service.ipcs_table + index); 394 395 if (mdb_vread(&slot, sizeof (ipc_slot_t), slotptr) == -1) { 396 mdb_warn("failed to read ipc_slot_t at %#lx", slotptr); 397 return (DCMD_ERR); 398 } 399 400 if (slot.ipct_data == NULL) 401 return (DCMD_ERR); 402 403 if (mdb_vread(&perm, sizeof (kipc_perm_t), 404 (uintptr_t)slot.ipct_data) == -1) { 405 mdb_warn("failed to read kipc_perm_t at %#p", 406 slot.ipct_data); 407 return (DCMD_ERR); 408 } 409 410 if (perm.ipc_id != (uint_t)id) 411 return (DCMD_ERR); 412 413 *addr = (uintptr_t)slot.ipct_data; 414 415 return (DCMD_OK); 416 } 417 418 419 typedef struct findkey_data { 420 key_t fk_key; 421 uintptr_t fk_addr; 422 boolean_t fk_found; 423 } findkey_data_t; 424 425 static int 426 findkey(uintptr_t addr, kipc_perm_t *perm, findkey_data_t *arg) 427 { 428 if (perm->ipc_key == arg->fk_key) { 429 arg->fk_found = B_TRUE; 430 arg->fk_addr = addr; 431 return (WALK_DONE); 432 } 433 return (WALK_NEXT); 434 } 435 436 static int 437 ipckey_impl(uintptr_t svcptr, uintptr_t key, uintptr_t *addr) 438 { 439 ipc_service_t service; 440 findkey_data_t fkdata; 441 442 if ((key == IPC_PRIVATE) || (key > INT_MAX)) { 443 mdb_warn("key out of range\n"); 444 return (DCMD_ERR); 445 } 446 447 if (mdb_vread(&service, sizeof (ipc_service_t), svcptr) == -1) { 448 mdb_warn("failed to read ipc_service_t at %#lx", svcptr); 449 return (DCMD_ERR); 450 } 451 452 fkdata.fk_key = (key_t)key; 453 fkdata.fk_found = B_FALSE; 454 if ((mdb_pwalk("avl", (mdb_walk_cb_t)findkey, &fkdata, 455 svcptr + OFFSETOF(ipc_service_t, ipcs_keys)) == -1) || 456 !fkdata.fk_found) 457 return (DCMD_ERR); 458 459 *addr = fkdata.fk_addr; 460 461 return (DCMD_OK); 462 } 463 464 static int 465 ipckeyid(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv, 466 int(*fp)(uintptr_t, uintptr_t, uintptr_t *)) 467 { 468 uintmax_t val; 469 uintptr_t raddr; 470 int result; 471 472 if (!(flags & DCMD_ADDRSPEC) || (argc != 1)) 473 return (DCMD_USAGE); 474 475 if (argv[0].a_type == MDB_TYPE_IMMEDIATE) 476 val = argv[0].a_un.a_val; 477 else if (argv[0].a_type == MDB_TYPE_STRING) 478 val = mdb_strtoull(argv[0].a_un.a_str); 479 else 480 return (DCMD_USAGE); 481 482 result = fp(addr, val, &raddr); 483 484 if (result == DCMD_OK) 485 mdb_printf("%lx", raddr); 486 487 return (result); 488 } 489 490 static int 491 ipckey(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 492 { 493 return (ipckeyid(addr, flags, argc, argv, ipckey_impl)); 494 } 495 496 static int 497 ipcid(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 498 { 499 return (ipckeyid(addr, flags, argc, argv, ipcid_impl)); 500 } 501 502 static int 503 ds_ptr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv, 504 ipc_ops_vec_t *iv) 505 { 506 uint_t kflag = FALSE; 507 uintptr_t svcptr, raddr; 508 int result; 509 510 if (!(flags & DCMD_ADDRSPEC)) 511 return (DCMD_USAGE); 512 513 if (mdb_getopts(argc, argv, 514 'k', MDB_OPT_SETBITS, TRUE, &kflag, NULL) != argc) 515 return (DCMD_USAGE); 516 517 if (mdb_readvar(&svcptr, iv->iv_service) == -1) { 518 mdb_warn("failed to read '%s'; module not present\n", 519 iv->iv_service); 520 return (DCMD_ERR); 521 } 522 523 result = kflag ? ipckey_impl(svcptr, addr, &raddr) : 524 ipcid_impl(svcptr, addr, &raddr); 525 526 if (result == DCMD_OK) 527 mdb_printf("%lx", raddr); 528 529 return (result); 530 } 531 532 /* 533 * Stubs to call ds_ptr with the appropriate ops vector 534 */ 535 static int 536 id2shm(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 537 { 538 return (ds_ptr(addr, flags, argc, argv, &shm_ops_vec)); 539 } 540 541 static int 542 id2msq(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 543 { 544 return (ds_ptr(addr, flags, argc, argv, &msq_ops_vec)); 545 } 546 547 static int 548 id2sem(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 549 { 550 return (ds_ptr(addr, flags, argc, argv, &sem_ops_vec)); 551 } 552 553 554 /* 555 * The message queue contents walker 556 */ 557 558 static int 559 msg_walk_init(mdb_walk_state_t *wsp) 560 { 561 wsp->walk_addr += OFFSETOF(kmsqid_t, msg_list); 562 if (mdb_layered_walk("list", wsp) == -1) 563 return (WALK_ERR); 564 565 return (WALK_NEXT); 566 } 567 568 static int 569 msg_walk_step(mdb_walk_state_t *wsp) 570 { 571 return (wsp->walk_callback(wsp->walk_addr, wsp->walk_layer, 572 wsp->walk_cbdata)); 573 } 574 575 /* 576 * The "::ipcs" command itself. Just walks each IPC type in turn. 577 */ 578 579 /*ARGSUSED*/ 580 static int 581 ipcs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 582 { 583 uint_t oflags = 0; 584 585 if ((flags & DCMD_ADDRSPEC) || mdb_getopts(argc, argv, 'l', 586 MDB_OPT_SETBITS, 1, &oflags, NULL) != argc) 587 return (DCMD_USAGE); 588 589 mdb_printf("Message queues:\n"); 590 if (mdb_walk_dcmd("msq", oflags ? "kmsqid" : "ipcperm", argc, argv) == 591 -1) { 592 mdb_warn("can't walk 'msq'"); 593 return (DCMD_ERR); 594 } 595 596 mdb_printf("\nShared memory:\n"); 597 if (mdb_walk_dcmd("shm", oflags ? "kshmid" : "ipcperm", argc, argv) == 598 -1) { 599 mdb_warn("can't walk 'shm'"); 600 return (DCMD_ERR); 601 } 602 603 mdb_printf("\nSemaphores:\n"); 604 if (mdb_walk_dcmd("sem", oflags ? "ksemid" : "ipcperm", argc, argv) == 605 -1) { 606 mdb_warn("can't walk 'sem'"); 607 return (DCMD_ERR); 608 } 609 610 return (DCMD_OK); 611 } 612 613 static int 614 msgprint(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 615 { 616 struct msg message; 617 uint_t lflag = FALSE; 618 long type = 0; 619 char *tflag = NULL; 620 621 if (!(flags & DCMD_ADDRSPEC) || (mdb_getopts(argc, argv, 622 'l', MDB_OPT_SETBITS, TRUE, &lflag, 623 't', MDB_OPT_STR, &tflag, NULL) != argc)) 624 return (DCMD_USAGE); 625 626 /* 627 * Handle negative values. 628 */ 629 if (tflag != NULL) { 630 if (*tflag == '-') { 631 tflag++; 632 type = -1; 633 } else { 634 type = 1; 635 } 636 type *= mdb_strtoull(tflag); 637 } 638 639 if (DCMD_HDRSPEC(flags)) 640 mdb_printf("%<u>%?s %?s %8s %8s %8s%</u>\n", 641 "ADDR", "TEXT", "SIZE", "TYPE", "REF"); 642 643 if (mdb_vread(&message, sizeof (struct msg), addr) == -1) { 644 mdb_warn("failed to read msg at %#lx", addr); 645 return (DCMD_ERR); 646 } 647 648 /* 649 * If we are meeting our type contraints, display the message. 650 * If -l was specified, we will also display the message 651 * contents. 652 */ 653 if ((type == 0) || 654 (type > 0 && message.msg_type == type) || 655 (type < 0 && message.msg_type <= -type)) { 656 657 if (lflag && !DCMD_HDRSPEC(flags)) 658 mdb_printf("\n"); 659 660 mdb_printf("%0?lx %?p %8ld %8ld %8ld\n", addr, message.msg_addr, 661 message.msg_size, message.msg_type, message.msg_copycnt); 662 663 if (lflag) { 664 mdb_printf("\n"); 665 mdb_inc_indent(CMN_INDENT); 666 if (mdb_dumpptr( 667 (uintptr_t)message.msg_addr, message.msg_size, 668 MDB_DUMP_RELATIVE | MDB_DUMP_TRIM | 669 MDB_DUMP_ASCII | MDB_DUMP_HEADER | 670 MDB_DUMP_GROUP(4), 671 (mdb_dumpptr_cb_t)mdb_vread, NULL)) { 672 mdb_dec_indent(CMN_INDENT); 673 return (DCMD_ERR); 674 } 675 mdb_dec_indent(CMN_INDENT); 676 } 677 } 678 679 return (DCMD_OK); 680 } 681 682 /* 683 * MDB module linkage 684 */ 685 static const mdb_dcmd_t dcmds[] = { 686 /* Generic routines */ 687 { "ipcperm", ":", "display an IPC perm structure", ipcperm }, 688 { "ipcid", ":id", "perform an IPC id lookup", ipcid }, 689 { "ipckey", ":key", "perform an IPC key lookup", ipckey }, 690 691 /* Specific routines */ 692 { "kshmid", "?[-l]", "display a struct kshmid", cmd_kshmid }, 693 { "kmsqid", "?[-l]", "display a struct kmsqid", cmd_kmsqid }, 694 { "ksemid", "?[-l]", "display a struct ksemid", cmd_ksemid }, 695 { "msg", ":[-l] [-t type]", "display contents of a message", msgprint }, 696 697 /* Convenience routines */ 698 { "id2shm", ":[-k]", "convert shared memory ID to pointer", id2shm }, 699 { "id2msq", ":[-k]", "convert message queue ID to pointer", id2msq }, 700 { "id2sem", ":[-k]", "convert semaphore ID to pointer", id2sem }, 701 702 { "ipcs", "[-l]", "display System V IPC information", ipcs }, 703 { NULL } 704 }; 705 706 static const mdb_walker_t walkers[] = { 707 { "ipcsvc", "walk a System V IPC service", 708 ds_walk_init, ds_walk_step }, 709 { "shm", "walk the active shmid_ds structures", 710 ds_walk_init, ds_walk_step, NULL, &shm_ops_vec }, 711 { "msq", "walk the active msqid_ds structures", 712 ds_walk_init, ds_walk_step, NULL, &msq_ops_vec }, 713 { "sem", "walk the active semid_ds structures", 714 ds_walk_init, ds_walk_step, NULL, &sem_ops_vec }, 715 { "msgqueue", "walk messages on a message queue", 716 msg_walk_init, msg_walk_step }, 717 { NULL } 718 }; 719 720 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers }; 721 722 const mdb_modinfo_t * 723 _mdb_init(void) 724 { 725 return (&modinfo); 726 } 727