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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/types.h> 29 #include <sys/time.h> 30 #include <sys/sysmacros.h> 31 #include <sys/ddifm.h> 32 #include <sys/nvpair.h> 33 #include <sys/nvpair_impl.h> 34 #include <sys/errorq_impl.h> 35 #include <sys/errorq.h> 36 #include <sys/fm/protocol.h> 37 38 #include <ctype.h> 39 #include <mdb/mdb_modapi.h> 40 #include <mdb/mdb_ks.h> 41 42 #include "nvpair.h" 43 44 int 45 ereportq_pend_walk_init(mdb_walk_state_t *wsp) 46 { 47 errorq_t eq; 48 uintptr_t addr; 49 50 if (wsp->walk_addr == NULL && 51 mdb_readvar(&addr, "ereport_errorq") == -1) { 52 mdb_warn("failed to read ereport_errorq"); 53 return (WALK_ERR); 54 } 55 56 if (mdb_vread(&eq, sizeof (eq), addr) == -1) { 57 mdb_warn("failed to read ereport_errorq at %p", addr); 58 return (WALK_ERR); 59 } 60 61 if (!(eq.eq_flags & ERRORQ_NVLIST)) { 62 mdb_warn("errorq at %p does not service ereports", addr); 63 return (WALK_ERR); 64 } 65 66 wsp->walk_addr = (uintptr_t)eq.eq_pend; 67 68 return (WALK_NEXT); 69 } 70 71 int 72 ereportq_pend_walk_step(mdb_walk_state_t *wsp) 73 { 74 uintptr_t addr = wsp->walk_addr; 75 nvlist_t nvl; 76 errorq_nvelem_t eqnp; 77 errorq_elem_t elem; 78 79 if (addr == NULL) 80 return (WALK_DONE); 81 82 if (mdb_vread(&elem, sizeof (elem), addr) != sizeof (elem) || 83 mdb_vread(&eqnp, sizeof (eqnp), (uintptr_t)elem.eqe_data) 84 != sizeof (eqnp) || mdb_vread(&nvl, sizeof (nvl), 85 (uintptr_t)eqnp.eqn_nvl) != sizeof (nvl)) { 86 mdb_warn("failed to read ereportq element at %p", addr); 87 return (WALK_ERR); 88 } 89 90 wsp->walk_addr = (uintptr_t)elem.eqe_prev; 91 92 return (wsp->walk_callback((uintptr_t)eqnp.eqn_nvl, &nvl, 93 wsp->walk_cbdata)); 94 } 95 96 int 97 ereportq_dump_walk_init(mdb_walk_state_t *wsp) 98 { 99 errorq_t eq; 100 uintptr_t addr; 101 102 if (wsp->walk_addr == NULL && 103 mdb_readvar(&addr, "ereport_errorq") == -1) { 104 mdb_warn("failed to read ereport_errorq"); 105 return (WALK_ERR); 106 } 107 108 if (mdb_vread(&eq, sizeof (eq), addr) == -1) { 109 mdb_warn("failed to read ereport_errorq at %p", addr); 110 return (WALK_ERR); 111 } 112 113 if (!(eq.eq_flags & ERRORQ_NVLIST)) { 114 mdb_warn("errorq at %p does not service ereports", addr); 115 return (WALK_ERR); 116 } 117 118 wsp->walk_addr = (uintptr_t)eq.eq_dump; 119 120 return (WALK_NEXT); 121 } 122 123 int 124 ereportq_dump_walk_step(mdb_walk_state_t *wsp) 125 { 126 uintptr_t addr = wsp->walk_addr; 127 nvlist_t nvl; 128 errorq_nvelem_t eqnp; 129 errorq_elem_t elem; 130 131 if (addr == NULL) 132 return (WALK_DONE); 133 134 if (mdb_vread(&elem, sizeof (elem), addr) != sizeof (elem) || 135 mdb_vread(&eqnp, sizeof (eqnp), (uintptr_t)elem.eqe_data) 136 != sizeof (eqnp) || mdb_vread(&nvl, sizeof (nvl), 137 (uintptr_t)eqnp.eqn_nvl) != sizeof (nvl)) { 138 mdb_warn("failed to read ereportq element at %p", addr); 139 return (WALK_ERR); 140 } 141 142 wsp->walk_addr = (uintptr_t)elem.eqe_dump; 143 144 return (wsp->walk_callback((uintptr_t)eqnp.eqn_nvl, &nvl, 145 wsp->walk_cbdata)); 146 } 147 148 /*ARGSUSED*/ 149 int 150 ereport(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 151 { 152 int ret; 153 uint_t opt_v = 0; 154 char *class = NULL; 155 uint64_t ena = 0; 156 nvlist_t nvl; 157 nvpriv_t nvpriv; 158 i_nvp_t *nvcur, i_nvp; 159 160 if (!(flags & DCMD_ADDRSPEC)) 161 return (DCMD_USAGE); 162 163 if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &opt_v) != argc) 164 return (DCMD_USAGE); 165 166 if (mdb_vread(&nvl, sizeof (nvl), addr) == -1) { 167 mdb_warn("failed to read nvlist at %p", addr); 168 return (DCMD_ERR); 169 } 170 171 if (DCMD_HDRSPEC(flags) && !opt_v) { 172 mdb_printf("ENA CLASS\n"); 173 } 174 175 /* 176 * The following code attempts to pretty print the ereport class 177 * and ENA. The code uses project private macros from libnvpair 178 * that could change and break this functionality. If we are unable 179 * to get a valid class and ENA from the nvpair list, we revert to 180 * dumping the nvlist (same as opt_v). 181 */ 182 if (mdb_vread(&nvpriv, sizeof (nvpriv), nvl.nvl_priv) == -1) { 183 mdb_warn("failed to read nvpriv at %p", nvl.nvl_priv); 184 return (DCMD_ERR); 185 } 186 187 for (nvcur = nvpriv.nvp_list; nvcur != NULL; nvcur = i_nvp.nvi_next) { 188 nvpair_t *nvp, *nvpair; 189 int32_t size; 190 191 if (opt_v) 192 break; 193 194 if (mdb_vread(&i_nvp, sizeof (i_nvp), (uintptr_t)nvcur) == -1) { 195 mdb_warn("failed to read i_nvp at %p", nvcur); 196 return (DCMD_ERR); 197 } 198 199 nvp = &i_nvp.nvi_nvp; 200 size = NVP_SIZE(nvp); 201 if (size == 0) { 202 mdb_warn("nvpair of size zero at %p", nvp); 203 return (DCMD_OK); 204 } 205 206 /* read in the entire nvpair */ 207 nvpair = mdb_alloc(size, UM_SLEEP | UM_GC); 208 if (mdb_vread(nvpair, size, (uintptr_t)&nvcur->nvi_nvp) == -1) { 209 mdb_warn("failed to read nvpair and data at %p", nvp); 210 return (DCMD_ERR); 211 } 212 213 if (strcmp(FM_CLASS, NVP_NAME(nvpair)) == 0 && 214 NVP_TYPE(nvpair) == DATA_TYPE_STRING && class == NULL) { 215 char *p = (char *)NVP_VALUE(nvpair); 216 217 class = mdb_zalloc(strlen(p) + 1, UM_SLEEP | UM_GC); 218 bcopy(p, class, strlen(p)); 219 } else if (strcmp(FM_EREPORT_ENA, NVP_NAME(nvpair)) == 0 && 220 NVP_TYPE(nvpair) == DATA_TYPE_UINT64 && ena == 0) { 221 bcopy(NVP_VALUE(nvpair), (char *)&ena, 222 sizeof (uint64_t)); 223 } 224 225 if (class != NULL && ena != 0) { 226 mdb_printf("0x%016llx %s\n", ena, class); 227 return (DCMD_OK); 228 } 229 230 } 231 232 /* 233 * Dump entire nvlist 234 */ 235 ret = mdb_call_dcmd("nvlist", addr, flags | DCMD_ADDRSPEC, 236 0, argv); 237 mdb_printf("\n"); 238 239 return (ret); 240 } 241