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 (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 #include <mdb/mdb_modapi.h>
26 
27 #include <libuutil.h>
28 #include <libuutil_impl.h>
29 
30 #include <librestart_priv.h>		/* instance_data_t */
31 #include <startd.h>
32 
33 
34 /*
35  * To count the elements of a uu_list_t without knowing its implementation, we
36  * must walk & count them.
37  */
38 /* ARGSUSED */
39 static int
inc_sz(uintptr_t addr,const void * unknown,void * data)40 inc_sz(uintptr_t addr, const void *unknown, void *data)
41 {
42 	size_t *sz = data;
43 
44 	++(*sz);
45 
46 	return (WALK_NEXT);
47 }
48 
49 /*ARGSUSED*/
50 static int
startd_status(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)51 startd_status(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
52 {
53 	uu_list_t *dgraphp;
54 	restarter_instance_list_t ril;
55 	u_longlong_t ns_total;
56 	u_longlong_t lookups;
57 	u_longlong_t dep_inserts, dep_cycle_ns, dep_insert_ns;
58 	size_t graph_num, restarter_num;
59 	uint64_t ct_maint;
60 	uint64_t ct_hwerr;
61 	uint64_t ct_service;
62 	uint64_t ct_global;
63 	uint64_t ct_noprefs;
64 	uint64_t ct_from_uninit;
65 	uint64_t ct_bad_state;
66 	uint64_t ct_ovr_prefs;
67 
68 	if (mdb_readvar(&lookups, "dictionary_lookups") == -1) {
69 		mdb_warn("failed to read 'dictionary_lookups' value\n");
70 		return (DCMD_ERR);
71 	}
72 
73 	if (mdb_readvar(&ns_total, "dictionary_ns_total") == -1) {
74 		mdb_warn("failed to read 'dictionary_ns_total' value\n");
75 		return (DCMD_ERR);
76 	}
77 
78 	if (mdb_readvar(&dep_inserts, "dep_inserts") == -1) {
79 		mdb_warn("failed to read 'dep_inserts' value\n");
80 		return (DCMD_ERR);
81 	}
82 
83 	if (mdb_readvar(&dep_cycle_ns, "dep_cycle_ns") == -1) {
84 		mdb_warn("failed to read 'dep_cycle_ns' value\n");
85 		return (DCMD_ERR);
86 	}
87 
88 	if (mdb_readvar(&dep_insert_ns, "dep_insert_ns") == -1) {
89 		mdb_warn("failed to read 'dep_insert_ns' value\n");
90 		return (DCMD_ERR);
91 	}
92 
93 	if (mdb_readvar(&dgraphp, "dgraph") == -1) {
94 		mdb_warn("failed to read 'dgraph' value\n");
95 		return (DCMD_ERR);
96 	}
97 
98 	graph_num = 0;
99 	if (mdb_pwalk("uu_list_node", inc_sz, &graph_num,
100 	    (uintptr_t)dgraphp) == -1) {
101 		mdb_warn("failed to read uu_list\n");
102 		return (DCMD_ERR);
103 	}
104 
105 	if (mdb_readvar(&ril, "instance_list") == -1) {
106 		mdb_warn("failed to read 'instance_list' value\n");
107 		return (DCMD_ERR);
108 	}
109 
110 	restarter_num = 0;
111 	if (mdb_pwalk("uu_list_node", inc_sz, &restarter_num,
112 	    (uintptr_t)ril.ril_instance_list) == -1) {
113 		mdb_warn("failed to read uu_list\n");
114 		return (DCMD_ERR);
115 	}
116 
117 	if (mdb_readvar(&ct_maint, "stev_ct_maint") == -1) {
118 		mdb_warn("failed to read 'stev_ct_maint'\n");
119 		return (DCMD_ERR);
120 	}
121 
122 	if (mdb_readvar(&ct_hwerr, "stev_ct_hwerr") == -1) {
123 		mdb_warn("failed to read 'stev_ct_hwerr'\n");
124 		return (DCMD_ERR);
125 	}
126 
127 	if (mdb_readvar(&ct_service, "stev_ct_service") == -1) {
128 		mdb_warn("failed to read 'stev_ct_service'\n");
129 		return (DCMD_ERR);
130 	}
131 
132 	if (mdb_readvar(&ct_global, "stev_ct_global") == -1) {
133 		mdb_warn("failed to read 'stev_ct_global'\n");
134 		return (DCMD_ERR);
135 	}
136 
137 	if (mdb_readvar(&ct_noprefs, "stev_ct_noprefs") == -1) {
138 		mdb_warn("failed to read 'stev_ct_noprefs'\n");
139 		return (DCMD_ERR);
140 	}
141 
142 	if (mdb_readvar(&ct_from_uninit, "stev_ct_from_uninit") == -1) {
143 		mdb_warn("failed to read 'stev_ct_from_uninit'\n");
144 		return (DCMD_ERR);
145 	}
146 
147 	if (mdb_readvar(&ct_bad_state, "stev_ct_bad_state") == -1) {
148 		mdb_warn("failed to read 'stev_ct_bad_state'\n");
149 		return (DCMD_ERR);
150 	}
151 
152 	if (mdb_readvar(&ct_ovr_prefs, "stev_ct_ovr_prefs") == -1) {
153 		mdb_warn("failed to read 'stev_ct_ovr_prefs'\n");
154 		return (DCMD_ERR);
155 	}
156 
157 	mdb_printf(
158 	    "General stats\n"
159 	    "              dictionary lookups: %llu\n"
160 	    "             average lookup time: %llu us\n"
161 	    "     graph dependency insertions: %llu\n"
162 	    "        average cycle-check time: %llu us\n"
163 	    "      avg dependency insert time: %llu us\n"
164 	    "       number of nodes in dgraph: %llu\n"
165 	    "number of nodes in instance_list: %llu\n"
166 	    "\nState Transition Events\n"
167 	    "                     maintenance: %llu\n"
168 	    "                  hardware error: %llu\n"
169 	    "           service specific pref: %llu\n"
170 	    "                system wide pref: %llu\n"
171 	    "            no prefs, not raised: %llu\n"
172 	    "          from unint, not raised: %llu\n"
173 	    "           bad state, not raised: %llu\n"
174 	    "           override pref, raised: %llu\n", lookups,
175 	    lookups ? ns_total / (1000 * lookups) : 0, dep_inserts,
176 	    dep_inserts ? dep_cycle_ns / (1000 * dep_inserts) : 0,
177 	    dep_inserts ? dep_insert_ns / (1000 * dep_inserts) : 0,
178 	    (u_longlong_t)graph_num, (u_longlong_t)restarter_num,
179 	    ct_maint, ct_hwerr, ct_service, ct_global, ct_noprefs,
180 	    ct_from_uninit, ct_bad_state, ct_ovr_prefs);
181 
182 
183 	return (DCMD_OK);
184 }
185 
186 static char
xstate2chr(restarter_instance_state_t s)187 xstate2chr(restarter_instance_state_t s)
188 {
189 	switch (s) {
190 	case RESTARTER_STATE_UNINIT:	return ('u');
191 	case RESTARTER_STATE_DISABLED:	return ('d');
192 	case RESTARTER_STATE_OFFLINE:	return ('0');
193 	case RESTARTER_STATE_DEGRADED:	return ('D');
194 	case RESTARTER_STATE_ONLINE:	return ('1');
195 	case RESTARTER_STATE_MAINT:	return ('m');
196 	case RESTARTER_STATE_NONE:	return ('n');
197 	default:			return ('?');
198 	}
199 }
200 
201 /*ARGSUSED*/
202 static int
pr_instance(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)203 pr_instance(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
204 {
205 	restarter_instance_list_t ril;
206 	restarter_inst_t ri;
207 	char *iname;
208 	char statechr = '-';
209 	char typechr;
210 
211 	if ((flags & DCMD_ADDRSPEC) == 0) {
212 		if (mdb_readvar(&ril, "instance_list") == -1) {
213 			mdb_warn("failed to read 'instance_list' value\n");
214 			return (DCMD_ERR);
215 		}
216 
217 		if (mdb_pwalk_dcmd("uu_list_node", "instance", 0, NULL,
218 		    (uintptr_t)ril.ril_instance_list) == -1) {
219 			mdb_warn("can't walk instances\n");
220 			return (DCMD_ERR);
221 		}
222 
223 		return (DCMD_OK);
224 	}
225 
226 	if (mdb_vread(&ri, sizeof (restarter_inst_t), addr) == -1) {
227 		mdb_warn("couldn't read instance at %a\n");
228 		return (DCMD_ERR);
229 	}
230 
231 	if (DCMD_HDRSPEC(flags))
232 		mdb_printf("%-10s %-3s %1s %1s %4s\n", "ADDR", "ID", "T", "S",
233 		    "FMRI");
234 
235 	iname = mdb_alloc(1024, UM_SLEEP | UM_GC);
236 
237 	if (mdb_readstr(iname, 1024, (uintptr_t)ri.ri_i.i_fmri) == -1) {
238 		mdb_warn("couldn't read instance name\n");
239 		strcpy(iname, "-");
240 	}
241 
242 	statechr = xstate2chr(ri.ri_i.i_state);
243 	typechr = (ri.ri_i.i_enabled) ? 'I' : 'i';
244 
245 	mdb_printf("%-10a %3x %c %c %s\n", addr, ri.ri_id, typechr, statechr,
246 	    iname);
247 
248 	return (DCMD_OK);
249 }
250 
251 /*ARGSUSED*/
252 static int
pr_vertex(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)253 pr_vertex(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
254 {
255 	uu_list_t *dgraphp;
256 	graph_vertex_t gv;
257 	char *vname;
258 	int id;
259 	char typechr;
260 	char statechr = '-';
261 
262 	if ((flags & DCMD_ADDRSPEC) == 0) {
263 		if (mdb_readvar(&dgraphp, "dgraph") == -1) {
264 			mdb_warn("failed to read 'dgraph' value\n");
265 			return (DCMD_ERR);
266 		}
267 
268 		if (mdb_pwalk_dcmd("uu_list_node", "vertex", 0, NULL,
269 		    (uintptr_t)dgraphp) == -1) {
270 			mdb_warn("can't walk vertices");
271 			return (DCMD_ERR);
272 		}
273 
274 		return (DCMD_OK);
275 	}
276 
277 	if (mdb_vread(&gv, sizeof (graph_vertex_t), addr) == -1) {
278 		mdb_warn("couldn't read vertex at %a\n");
279 		return (DCMD_ERR);
280 	}
281 
282 	if (DCMD_HDRSPEC(flags))
283 		mdb_printf("%-10s %-3s %1s %1s %4s\n", "ADDR", "ID", "T", "S",
284 		    "FMRI");
285 
286 	vname = mdb_alloc(1024, UM_SLEEP | UM_GC);
287 
288 	if (mdb_readstr(vname, 1024, (uintptr_t)gv.gv_name) == -1) {
289 		mdb_warn("couldn't read vertex name\n");
290 		strcpy(vname, "-");
291 	}
292 
293 	id = gv.gv_id;
294 
295 	switch (gv.gv_type) {
296 	case GVT_FILE:
297 		typechr = 'f';
298 		break;
299 	case GVT_GROUP:
300 		switch (gv.gv_depgroup) {
301 		case DEPGRP_REQUIRE_ANY:
302 			typechr = 'r';
303 			break;
304 		case DEPGRP_REQUIRE_ALL:
305 			typechr = 'R';
306 			break;
307 		case DEPGRP_EXCLUDE_ALL:
308 			typechr = 'X';
309 			break;
310 		case DEPGRP_OPTIONAL_ALL:
311 			typechr = 'o';
312 			break;
313 		default:
314 			typechr = '?';
315 			break;
316 		}
317 		break;
318 	case GVT_INST:
319 		typechr = (gv.gv_flags & GV_ENABLED) ? 'I' : 'i';
320 		statechr = xstate2chr(gv.gv_state);
321 		break;
322 	case GVT_SVC:
323 		typechr = 's';
324 		break;
325 	default:
326 		typechr = '?';
327 		break;
328 	}
329 
330 	mdb_printf("%-10a %3x %c %c %s\n", addr, id, typechr, statechr, vname);
331 
332 	return (DCMD_OK);
333 }
334 
335 /* ARGSUSED */
336 static int
logbuf(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)337 logbuf(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
338 {
339 	GElf_Sym sym;
340 	char *buf;
341 	char *cp;
342 
343 	if (mdb_lookup_by_name("logbuf", &sym) == -1) {
344 		mdb_warn("The 'logbuf' symbol is missing.\n");
345 		return (DCMD_ERR);
346 	}
347 
348 	buf = mdb_alloc(sym.st_size, UM_SLEEP | UM_GC);
349 
350 	if (mdb_vread(buf, sym.st_size, sym.st_value) == -1) {
351 		mdb_warn("failed to read 'logbuf'\n");
352 		return (DCMD_ERR);
353 	}
354 
355 	cp = strchr(buf, '\0');
356 
357 	if (cp == buf)
358 		/* Empty */
359 		return (DCMD_OK);
360 
361 	if (cp >= buf + sym.st_size ||
362 	    strchr(cp + 1, '\0') >= buf + sym.st_size) {
363 		mdb_warn("'logbuf' is corrupt\n");
364 		return (DCMD_ERR);
365 	}
366 
367 	mdb_printf("%s", cp + 1);
368 	mdb_printf("%s", buf);
369 
370 	return (DCMD_OK);
371 }
372 
373 static const mdb_dcmd_t dcmds[] = {
374 	{ "instance", NULL, "display svc.startd restarter instance",
375 	    pr_instance },
376 	{ "startd_log", NULL, "display svc.startd debug message buffer",
377 	    logbuf },
378 	{ "startd_status", NULL, "svc.startd status summary", startd_status },
379 	{ "vertex", NULL, "display svc.startd dependency graph vertex",
380 	    pr_vertex },
381 	{ NULL }
382 };
383 
384 static const mdb_walker_t walkers[] = {
385 	{ NULL }
386 };
387 
388 static const mdb_modinfo_t modinfo = {
389 	MDB_API_VERSION, dcmds, walkers
390 };
391 
392 const mdb_modinfo_t *
_mdb_init(void)393 _mdb_init(void)
394 {
395 	return (&modinfo);
396 }
397