xref: /illumos-gate/usr/src/cmd/mdb/common/modules/genunix/sysevent.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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