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
printtime_nice(const char * str,time_t time)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
ipcperm_header()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
ipcperm_print(uintptr_t addr,kipc_perm_t * perm)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
ipcperm(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
msgq_check_for_waiters(list_t * walk_this,int min,int max,int copy_wait,uintptr_t addr,int flag)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
msq_print(kmsqid_t * msqid,uintptr_t addr)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
shm_print(kshmid_t * shmid,uintptr_t addr)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
sem_print(ksemid_t * semid,uintptr_t addr)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
ds_print(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv,ipc_ops_vec_t * iv)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
cmd_kshmid(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
cmd_kmsqid(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
cmd_ksemid(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
ds_walk_init(mdb_walk_state_t * wsp)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
ds_walk_step(mdb_walk_state_t * wsp)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
ipcid_impl(uintptr_t svcptr,uintptr_t id,uintptr_t * addr)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
findkey(uintptr_t addr,kipc_perm_t * perm,findkey_data_t * arg)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
ipckey_impl(uintptr_t svcptr,uintptr_t key,uintptr_t * addr)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
ipckeyid(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv,int (* fp)(uintptr_t,uintptr_t,uintptr_t *))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
ipckey(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
ipcid(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
ds_ptr(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv,ipc_ops_vec_t * iv)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
id2shm(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
id2msq(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
id2sem(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
msg_walk_init(mdb_walk_state_t * wsp)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
msg_walk_step(mdb_walk_state_t * wsp)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
ipcs(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
msgprint(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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 *
_mdb_init(void)737 _mdb_init(void)
738 {
739 return (&modinfo);
740 }
741