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