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