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