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, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 #include "sysevent.h"
30
31 int
sysevent_buf(uintptr_t addr,uint_t flags,uint_t opt_flags)32 sysevent_buf(uintptr_t addr, uint_t flags, uint_t opt_flags)
33 {
34 sysevent_hdr_t evh;
35 sysevent_impl_t *ev;
36 int size;
37
38 if (DCMD_HDRSPEC(flags)) {
39 if ((opt_flags & SYSEVENT_VERBOSE) == 0) {
40 mdb_printf("%<u>%-?s %-16s %-9s %-10s "
41 "%-?s%</u>\n", "ADDRESS", "SEQUENCE ID",
42 "CLASS", "SUBCLASS", "NVPAIR BUF ADDR");
43 }
44 }
45
46 /*
47 * Read in the sysevent buffer header first. After extracting
48 * the size of the buffer, re-read the buffer in its entirety.
49 */
50 if (mdb_vread(&evh, sizeof (sysevent_hdr_t), addr) == -1) {
51 mdb_warn("failed to read event header at %p", addr);
52 return (DCMD_ERR);
53 }
54
55 size = SE_SIZE((sysevent_impl_t *)&evh);
56 ev = mdb_alloc(size, UM_SLEEP | UM_GC);
57
58 if (mdb_vread(ev, size, addr) == -1) {
59 mdb_warn("can not read sysevent at %p", addr);
60 return (DCMD_ERR);
61 }
62
63 if ((opt_flags & SYSEVENT_VERBOSE) == 0) {
64 char ev_class[CLASS_FIELD_MAX];
65 char ev_subclass[SUBCLASS_FIELD_MAX];
66
67 if (mdb_snprintf(ev_class, CLASS_FIELD_MAX, "%s",
68 SE_CLASS_NAME(ev)) >= CLASS_FIELD_MAX - 1)
69 (void) strcpy(&ev_class[CLASS_FIELD_MAX - 4], "...");
70
71 if (mdb_snprintf(ev_subclass, SUBCLASS_FIELD_MAX, "%s",
72 SE_SUBCLASS_NAME(ev)) >= SUBCLASS_FIELD_MAX - 1)
73 (void) strcpy(&ev_subclass[SUBCLASS_FIELD_MAX - 4],
74 "...");
75
76 mdb_printf("%-?p %-16llu %-9s %-10s %-?p%\n",
77 addr, SE_SEQ(ev), ev_class, ev_subclass,
78 addr + SE_ATTR_OFF(ev));
79 } else {
80 mdb_printf("%<b>Sequence ID\t : %llu%</b>\n", SE_SEQ(ev));
81 mdb_printf("%16s : %s\n", "publisher", SE_PUB_NAME(ev));
82 mdb_printf("%16s : %p\n", "event address", (caddr_t)addr);
83 mdb_printf("%16s : %s\n", "class", SE_CLASS_NAME(ev));
84 mdb_printf("%16s : %s\n", "subclass", SE_SUBCLASS_NAME(ev));
85 mdb_printf("%16s : %llu\n", "time stamp", SE_TIME(ev));
86 mdb_printf("%16s : %p\n", "nvpair buf addr",
87 addr + SE_ATTR_OFF(ev));
88 }
89
90 return (DCMD_OK);
91 }
92
93 int
sysevent_subclass_list(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)94 sysevent_subclass_list(uintptr_t addr, uint_t flags, int argc,
95 const mdb_arg_t *argv)
96 {
97 int subclass_name_sz;
98 char subclass_name[CLASS_LIST_FIELD_MAX];
99 subclass_lst_t sclist;
100
101 if ((flags & DCMD_ADDRSPEC) == 0)
102 return (DCMD_USAGE);
103
104 if ((flags & DCMD_LOOP) == 0) {
105 if (mdb_pwalk_dcmd("sysevent_subclass_list",
106 "sysevent_subclass_list", argc, argv, addr) == -1) {
107 mdb_warn("can't walk sysevent subclass list");
108 return (DCMD_ERR);
109 }
110 return (DCMD_OK);
111 }
112
113 if (DCMD_HDRSPEC(flags)) {
114 mdb_printf("%<u>%-?s %-24s %-?s%</u>\n",
115 "ADDR", "NAME", "SUBSCRIBER DATA ADDR");
116 }
117 if (mdb_vread(&sclist, sizeof (sclist), (uintptr_t)addr) == -1) {
118 mdb_warn("failed to read subclass list at %p", addr);
119 return (DCMD_ERR);
120 }
121 if ((subclass_name_sz = mdb_readstr(subclass_name, CLASS_LIST_FIELD_MAX,
122 (uintptr_t)sclist.sl_name)) == -1) {
123 mdb_warn("failed to read class name at %p",
124 sclist.sl_name);
125 return (DCMD_ERR);
126 }
127 if (subclass_name_sz >= CLASS_LIST_FIELD_MAX - 1)
128 (void) strcpy(&subclass_name[CLASS_LIST_FIELD_MAX - 4], "...");
129
130 mdb_printf("%-?p %-24s %-?p\n", addr, subclass_name,
131 addr + offsetof(subclass_lst_t, sl_num));
132
133 return (DCMD_OK);
134 }
135
136
137 int
sysevent_class_list(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)138 sysevent_class_list(uintptr_t addr, uint_t flags, int argc,
139 const mdb_arg_t *argv)
140 {
141 int class_name_sz;
142 char class_name[CLASS_LIST_FIELD_MAX];
143 class_lst_t clist;
144
145 if ((flags & DCMD_ADDRSPEC) == 0)
146 return (DCMD_USAGE);
147
148 if ((flags & DCMD_LOOP) == 0) {
149 if (mdb_pwalk_dcmd("sysevent_class_list", "sysevent_class_list",
150 argc, argv, addr) == -1) {
151 mdb_warn("can't walk sysevent class list");
152 return (DCMD_ERR);
153 }
154 return (DCMD_OK);
155 }
156
157 if (DCMD_HDRSPEC(flags))
158 mdb_printf("%<u>%-?s %-24s %-?s%</u>\n",
159 "ADDR", "NAME", "SUBCLASS LIST ADDR");
160
161 if (mdb_vread(&clist, sizeof (clist),
162 (uintptr_t)addr) == -1) {
163 mdb_warn("failed to read class clist at %p", addr);
164 return (DCMD_ERR);
165 }
166 if ((class_name_sz = mdb_readstr(class_name, CLASS_LIST_FIELD_MAX,
167 (uintptr_t)clist.cl_name)) == -1) {
168 mdb_warn("failed to read class name at %p",
169 clist.cl_name);
170 return (DCMD_ERR);
171 }
172 if (class_name_sz >= CLASS_LIST_FIELD_MAX - 1)
173 (void) strcpy(&class_name[CLASS_LIST_FIELD_MAX - 4], "...");
174
175 mdb_printf("%-?p %-24s %-?p\n", addr, class_name,
176 clist.cl_subclass_list);
177
178 return (DCMD_OK);
179 }
180
181 int
sysevent_subclass_list_walk_init(mdb_walk_state_t * wsp)182 sysevent_subclass_list_walk_init(mdb_walk_state_t *wsp)
183 {
184 if (wsp->walk_addr == NULL) {
185 mdb_warn("sysevent_subclass_list does not support global "
186 "walks");
187 return (WALK_ERR);
188 }
189
190 wsp->walk_data = mdb_alloc(sizeof (subclass_lst_t), UM_SLEEP);
191 return (WALK_NEXT);
192 }
193
194 int
sysevent_subclass_list_walk_step(mdb_walk_state_t * wsp)195 sysevent_subclass_list_walk_step(mdb_walk_state_t *wsp)
196 {
197 int status;
198
199 if (wsp->walk_addr == NULL)
200 return (WALK_DONE);
201
202 if (mdb_vread(wsp->walk_data, sizeof (subclass_lst_t),
203 wsp->walk_addr) == -1) {
204 mdb_warn("failed to read class list at %p", wsp->walk_addr);
205 return (WALK_ERR);
206 }
207
208 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
209 wsp->walk_cbdata);
210
211 wsp->walk_addr =
212 (uintptr_t)(((subclass_lst_t *)wsp->walk_data)->sl_next);
213
214 return (status);
215 }
216
217 void
sysevent_subclass_list_walk_fini(mdb_walk_state_t * wsp)218 sysevent_subclass_list_walk_fini(mdb_walk_state_t *wsp)
219 {
220 mdb_free(wsp->walk_data, sizeof (subclass_lst_t));
221 }
222
223 typedef struct class_walk_data {
224 int hash_index;
225 class_lst_t *hash_tbl[CLASS_HASH_SZ + 1];
226 } class_walk_data_t;
227
228 int
sysevent_class_list_walk_init(mdb_walk_state_t * wsp)229 sysevent_class_list_walk_init(mdb_walk_state_t *wsp)
230 {
231 class_walk_data_t *cl_walker;
232
233 if (wsp->walk_addr == NULL) {
234 mdb_warn("sysevent_class_list does not support global walks");
235 return (WALK_ERR);
236 }
237
238 cl_walker = mdb_zalloc(sizeof (class_walk_data_t), UM_SLEEP);
239 if (mdb_vread(cl_walker->hash_tbl,
240 sizeof (cl_walker->hash_tbl), wsp->walk_addr) == -1) {
241 mdb_warn("failed to read class hash table at %p",
242 wsp->walk_addr);
243 return (WALK_ERR);
244 }
245
246 wsp->walk_addr = (uintptr_t)cl_walker->hash_tbl[0];
247 wsp->walk_data = cl_walker;
248
249 return (WALK_NEXT);
250 }
251
252 int
sysevent_class_list_walk_step(mdb_walk_state_t * wsp)253 sysevent_class_list_walk_step(mdb_walk_state_t *wsp)
254 {
255 int status = WALK_NEXT;
256 class_walk_data_t *cl_walker;
257 class_lst_t clist;
258
259 cl_walker = (class_walk_data_t *)wsp->walk_data;
260
261 /* Skip over empty class table entries */
262 if (wsp->walk_addr != NULL) {
263 if (mdb_vread(&clist, sizeof (class_lst_t),
264 wsp->walk_addr) == -1) {
265 mdb_warn("failed to read class list at %p",
266 wsp->walk_addr);
267 return (WALK_ERR);
268 }
269
270 status = wsp->walk_callback(wsp->walk_addr, NULL,
271 wsp->walk_cbdata);
272 wsp->walk_addr = (uintptr_t)clist.cl_next;
273 } else {
274 if (cl_walker->hash_index > CLASS_HASH_SZ) {
275 return (WALK_DONE);
276 } else {
277 wsp->walk_addr = (uintptr_t)
278 cl_walker->hash_tbl[cl_walker->hash_index];
279 cl_walker->hash_index++;
280 }
281 }
282
283
284 return (status);
285 }
286
287 void
sysevent_class_list_walk_fini(mdb_walk_state_t * wsp)288 sysevent_class_list_walk_fini(mdb_walk_state_t *wsp)
289 {
290 class_walk_data_t *cl_walker = wsp->walk_data;
291
292 mdb_free(cl_walker, sizeof (cl_walker));
293 }
294
295 #ifdef _KERNEL
296 int
sysevent(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)297 sysevent(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
298 {
299 uint_t sys_flags = FALSE;
300
301 if (mdb_getopts(argc, argv,
302 's', MDB_OPT_SETBITS, SYSEVENT_SENTQ, &sys_flags,
303 'v', MDB_OPT_SETBITS, SYSEVENT_VERBOSE, &sys_flags, NULL) != argc)
304 return (DCMD_USAGE);
305
306 if ((flags & DCMD_ADDRSPEC) == 0) {
307 if (sys_flags & SYSEVENT_SENTQ) {
308 if (mdb_walk_dcmd("sysevent_sent", "sysevent", argc,
309 argv) == -1) {
310 mdb_warn("can not walk sent queue");
311 return (DCMD_ERR);
312 }
313 } else {
314 if (mdb_walk_dcmd("sysevent_pend", "sysevent", argc,
315 argv) == -1) {
316 mdb_warn("can not walk pending queue");
317 return (DCMD_ERR);
318 }
319 }
320 return (DCMD_OK);
321 }
322
323 return (sysevent_buf(addr, flags, sys_flags));
324 }
325
326 int
sysevent_channel(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)327 sysevent_channel(uintptr_t addr, uint_t flags, int argc,
328 const mdb_arg_t *argv)
329 {
330 ssize_t channel_name_sz;
331 char channel_name[CHAN_FIELD_MAX];
332 sysevent_channel_descriptor_t chan_tbl;
333
334 if (argc != 0)
335 return (DCMD_USAGE);
336
337 if ((flags & DCMD_ADDRSPEC) == 0) {
338 if (mdb_walk_dcmd("sysevent_channel", "sysevent_channel",
339 argc, argv) == -1) {
340 mdb_warn("can't walk sysevent channel");
341 return (DCMD_ERR);
342 }
343 return (DCMD_OK);
344 }
345
346
347 if (DCMD_HDRSPEC(flags))
348 mdb_printf("%<u>%-?s %-16s %-8s %-?s%</u>\n",
349 "ADDR", "NAME", "REF CNT", "CLASS LST ADDR");
350
351 if (mdb_vread(&chan_tbl, sizeof (chan_tbl),
352 (uintptr_t)addr) == -1) {
353 mdb_warn("failed to read channel table at %p", addr);
354 return (DCMD_ERR);
355 }
356 if ((channel_name_sz = mdb_readstr(channel_name, CHAN_FIELD_MAX,
357 (uintptr_t)chan_tbl.scd_channel_name)) == -1) {
358 mdb_warn("failed to read channel name at %p",
359 chan_tbl.scd_channel_name);
360 return (DCMD_ERR);
361 }
362 if (channel_name_sz >= CHAN_FIELD_MAX - 1)
363 (void) strcpy(&channel_name[CHAN_FIELD_MAX - 4], "...");
364
365 mdb_printf("%-?p %-16s %-8lu %-?p\n",
366 addr, channel_name, chan_tbl.scd_ref_cnt,
367 addr + offsetof(sysevent_channel_descriptor_t,
368 scd_class_list_tbl));
369
370 return (DCMD_OK);
371 }
372
373 typedef struct channel_walk_data {
374 int hash_index;
375 sysevent_channel_descriptor_t *hash_tbl[CHAN_HASH_SZ];
376 } channel_walk_data_t;
377
378 int
sysevent_channel_walk_init(mdb_walk_state_t * wsp)379 sysevent_channel_walk_init(mdb_walk_state_t *wsp)
380 {
381 channel_walk_data_t *ch_walker;
382
383 if (wsp->walk_addr != NULL) {
384 mdb_warn("sysevent_channel supports only global walks");
385 return (WALK_ERR);
386 }
387
388 ch_walker = mdb_zalloc(sizeof (channel_walk_data_t), UM_SLEEP);
389 if (mdb_readvar(ch_walker->hash_tbl, "registered_channels")
390 == -1) {
391 mdb_warn("failed to read 'registered_channels'");
392 return (WALK_ERR);
393 }
394
395 wsp->walk_addr = (uintptr_t)ch_walker->hash_tbl[0];
396 wsp->walk_data = ch_walker;
397
398 return (WALK_NEXT);
399 }
400
401 int
sysevent_channel_walk_step(mdb_walk_state_t * wsp)402 sysevent_channel_walk_step(mdb_walk_state_t *wsp)
403 {
404 int status = WALK_NEXT;
405 channel_walk_data_t *ch_walker;
406 sysevent_channel_descriptor_t scd;
407
408 ch_walker = (channel_walk_data_t *)wsp->walk_data;
409
410 /* Skip over empty hash table entries */
411 if (wsp->walk_addr != NULL) {
412 if (mdb_vread(&scd, sizeof (sysevent_channel_descriptor_t),
413 wsp->walk_addr) == -1) {
414 mdb_warn("failed to read channel at %p",
415 wsp->walk_addr);
416 return (WALK_ERR);
417 }
418
419 status = wsp->walk_callback(wsp->walk_addr, NULL,
420 wsp->walk_cbdata);
421 wsp->walk_addr = (uintptr_t)scd.scd_next;
422 } else {
423 if (ch_walker->hash_index == CHAN_HASH_SZ) {
424 return (WALK_DONE);
425 } else {
426
427 wsp->walk_addr = (uintptr_t)
428 ch_walker->hash_tbl[ch_walker->hash_index];
429 ch_walker->hash_index++;
430 }
431 }
432
433 return (status);
434 }
435
436 void
sysevent_channel_walk_fini(mdb_walk_state_t * wsp)437 sysevent_channel_walk_fini(mdb_walk_state_t *wsp)
438 {
439 channel_walk_data_t *ch_walker = wsp->walk_data;
440
441 mdb_free(ch_walker, sizeof (ch_walker));
442 }
443
444 int
sysevent_pend_walk_init(mdb_walk_state_t * wsp)445 sysevent_pend_walk_init(mdb_walk_state_t *wsp)
446 {
447 if (wsp->walk_addr == NULL) {
448 if (mdb_readvar(&wsp->walk_addr, "log_eventq_head") == -1) {
449 mdb_warn("failed to read 'log_eventq_head'");
450 return (WALK_ERR);
451 }
452 }
453
454 wsp->walk_data = mdb_alloc(sizeof (log_eventq_t), UM_SLEEP);
455 return (WALK_NEXT);
456 }
457
458 int
sysevent_walk_step(mdb_walk_state_t * wsp)459 sysevent_walk_step(mdb_walk_state_t *wsp)
460 {
461 int status;
462 uintptr_t ev_arg_addr;
463
464 if (wsp->walk_addr == NULL)
465 return (WALK_DONE);
466
467 if (mdb_vread(wsp->walk_data, sizeof (log_eventq_t),
468 wsp->walk_addr) == -1) {
469 mdb_warn("failed to read event queue at %p", wsp->walk_addr);
470 return (WALK_ERR);
471 }
472 ev_arg_addr = wsp->walk_addr + offsetof(log_eventq_t, arg.buf);
473
474 status = wsp->walk_callback(ev_arg_addr, wsp->walk_data,
475 wsp->walk_cbdata);
476 wsp->walk_addr = (uintptr_t)(((log_eventq_t *)wsp->walk_data)->next);
477 return (status);
478 }
479
480 int
sysevent_sent_walk_init(mdb_walk_state_t * wsp)481 sysevent_sent_walk_init(mdb_walk_state_t *wsp)
482 {
483 if (wsp->walk_addr == NULL) {
484 if (mdb_readvar(&wsp->walk_addr, "log_eventq_sent") == -1) {
485 mdb_warn("failed to read 'log_eventq_sent'");
486 return (WALK_ERR);
487 }
488 }
489 wsp->walk_data = mdb_alloc(sizeof (log_eventq_t), UM_SLEEP);
490 return (WALK_NEXT);
491 }
492
493 void
sysevent_walk_fini(mdb_walk_state_t * wsp)494 sysevent_walk_fini(mdb_walk_state_t *wsp)
495 {
496 mdb_free(wsp->walk_data, sizeof (log_eventq_t));
497 }
498
499 #endif
500