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