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