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 == (uintptr_t)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 == (uintptr_t)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 == (uintptr_t)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 != (uintptr_t)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