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 * Copyright 2019 Joyent, Inc. 26 */ 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 == 0 && 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 == 0) 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 == 0 && 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 == 0) 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, NULL) != 164 argc) 165 return (DCMD_USAGE); 166 167 if (mdb_vread(&nvl, sizeof (nvl), addr) == -1) { 168 mdb_warn("failed to read nvlist at %p", addr); 169 return (DCMD_ERR); 170 } 171 172 if (DCMD_HDRSPEC(flags) && !opt_v) { 173 mdb_printf("ENA CLASS\n"); 174 } 175 176 /* 177 * The following code attempts to pretty print the ereport class 178 * and ENA. The code uses project private macros from libnvpair 179 * that could change and break this functionality. If we are unable 180 * to get a valid class and ENA from the nvpair list, we revert to 181 * dumping the nvlist (same as opt_v). 182 */ 183 if (mdb_vread(&nvpriv, sizeof (nvpriv), nvl.nvl_priv) == -1) { 184 mdb_warn("failed to read nvpriv at %p", nvl.nvl_priv); 185 return (DCMD_ERR); 186 } 187 188 for (nvcur = nvpriv.nvp_list; nvcur != NULL; nvcur = i_nvp.nvi_next) { 189 nvpair_t *nvp, *nvpair; 190 int32_t size; 191 192 if (opt_v) 193 break; 194 195 if (mdb_vread(&i_nvp, sizeof (i_nvp), (uintptr_t)nvcur) == -1) { 196 mdb_warn("failed to read i_nvp at %p", nvcur); 197 return (DCMD_ERR); 198 } 199 200 nvp = &i_nvp.nvi_nvp; 201 size = NVP_SIZE(nvp); 202 if (size == 0) { 203 mdb_warn("nvpair of size zero at %p", nvp); 204 return (DCMD_OK); 205 } 206 207 /* read in the entire nvpair */ 208 nvpair = mdb_alloc(size, UM_SLEEP | UM_GC); 209 if (mdb_vread(nvpair, size, (uintptr_t)&nvcur->nvi_nvp) == -1) { 210 mdb_warn("failed to read nvpair and data at %p", nvp); 211 return (DCMD_ERR); 212 } 213 214 if (strcmp(FM_CLASS, NVP_NAME(nvpair)) == 0 && 215 NVP_TYPE(nvpair) == DATA_TYPE_STRING && class == NULL) { 216 char *p = (char *)NVP_VALUE(nvpair); 217 218 class = mdb_zalloc(strlen(p) + 1, UM_SLEEP | UM_GC); 219 bcopy(p, class, strlen(p)); 220 } else if (strcmp(FM_EREPORT_ENA, NVP_NAME(nvpair)) == 0 && 221 NVP_TYPE(nvpair) == DATA_TYPE_UINT64 && ena == 0) { 222 bcopy(NVP_VALUE(nvpair), (char *)&ena, 223 sizeof (uint64_t)); 224 } 225 226 if (class != NULL && ena != 0) { 227 mdb_printf("0x%016llx %s\n", ena, class); 228 return (DCMD_OK); 229 } 230 231 } 232 233 /* 234 * Dump entire nvlist 235 */ 236 ret = mdb_call_dcmd("nvlist", addr, flags | DCMD_ADDRSPEC, 237 0, argv); 238 mdb_printf("\n"); 239 240 return (ret); 241 } 242