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