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
31int
32sysevent_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
93int
94sysevent_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
137int
138sysevent_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
181int
182sysevent_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
194int
195sysevent_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
217void
218sysevent_subclass_list_walk_fini(mdb_walk_state_t *wsp)
219{
220	mdb_free(wsp->walk_data, sizeof (subclass_lst_t));
221}
222
223typedef struct class_walk_data {
224	int	hash_index;
225	class_lst_t *hash_tbl[CLASS_HASH_SZ + 1];
226} class_walk_data_t;
227
228int
229sysevent_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
252int
253sysevent_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
287void
288sysevent_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
296int
297sysevent(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
326int
327sysevent_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
373typedef struct channel_walk_data {
374	int hash_index;
375	sysevent_channel_descriptor_t *hash_tbl[CHAN_HASH_SZ];
376} channel_walk_data_t;
377
378int
379sysevent_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
401int
402sysevent_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
436void
437sysevent_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
444int
445sysevent_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
458int
459sysevent_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
480int
481sysevent_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
493void
494sysevent_walk_fini(mdb_walk_state_t *wsp)
495{
496	mdb_free(wsp->walk_data, sizeof (log_eventq_t));
497}
498
499#endif
500