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, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 #include <mdb/mdb_modapi.h>
30 #include <mdb/mdb_ctf.h>
31
32 #include <configd.h>
33
34 mdb_ctf_id_t request_enum;
35 mdb_ctf_id_t response_enum;
36 mdb_ctf_id_t ptr_type_enum;
37 mdb_ctf_id_t thread_state_enum;
38
39 hrtime_t max_time_seen;
40
41 static void
enum_lookup(char * out,size_t size,mdb_ctf_id_t id,int val,const char * prefix,const char * prefix2)42 enum_lookup(char *out, size_t size, mdb_ctf_id_t id, int val,
43 const char *prefix, const char *prefix2)
44 {
45 const char *cp;
46 size_t len = strlen(prefix);
47 size_t len2 = strlen(prefix2);
48
49 if ((cp = mdb_ctf_enum_name(id, val)) != NULL) {
50 if (strncmp(cp, prefix, len) == 0)
51 cp += len;
52 if (strncmp(cp, prefix2, len2) == 0)
53 cp += len2;
54 (void) strlcpy(out, cp, size);
55 } else {
56 mdb_snprintf(out, size, "? (%d)", val);
57 }
58 }
59
60 static void
make_lower(char * out,size_t sz)61 make_lower(char *out, size_t sz)
62 {
63 while (*out != 0 && sz > 0) {
64 if (*out >= 'A' && *out <= 'Z')
65 *out += 'a' - 'A';
66 out++;
67 sz--;
68 }
69 }
70
71 /*ARGSUSED*/
72 static int
configd_status(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)73 configd_status(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
74 {
75 int num_servers;
76 int num_started;
77
78 if (argc != 0)
79 return (DCMD_USAGE);
80
81 if (mdb_readvar(&num_servers, "num_servers") == -1) {
82 mdb_warn("unable to read num_servers");
83 return (DCMD_ERR);
84 }
85 if (mdb_readvar(&num_started, "num_started") == -1) {
86 mdb_warn("unable to read num_started");
87 return (DCMD_ERR);
88 }
89 mdb_printf(
90 "\nserver threads:\t%d running, %d starting\n\n", num_servers,
91 num_started - num_servers);
92
93 if (mdb_walk_dcmd("configd_threads", "configd_thread", argc,
94 argv) == -1) {
95 mdb_warn("can't walk 'configd_threads'");
96 return (DCMD_ERR);
97 }
98 return (DCMD_OK);
99 }
100
101 /*ARGSUSED*/
102 static int
configd_thread(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)103 configd_thread(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
104 {
105 thread_info_t t;
106 char state[20];
107 char oldstate[20];
108
109 if (!(flags & DCMD_ADDRSPEC)) {
110 if (mdb_walk_dcmd("configd_threads", "configd_thread", argc,
111 argv) == -1) {
112 mdb_warn("can't walk 'configd_threads'");
113 return (DCMD_ERR);
114 }
115 return (DCMD_OK);
116 }
117
118 if (argc != 0)
119 return (DCMD_USAGE);
120
121 if (DCMD_HDRSPEC(flags)) {
122 mdb_printf("%<u>%-?s %5s %-12s %-12s %-?s %-?s %-?s%</u>\n",
123 "ADDR", "TID", "STATE", "PREV_STATE", "CLIENT", "CLIENTRQ",
124 "MAINREQ");
125 }
126
127 if (mdb_vread(&t, sizeof (t), addr) == -1) {
128 mdb_warn("failed to read thread_info_t at %p", addr);
129 return (DCMD_ERR);
130 }
131
132 enum_lookup(state, sizeof (state), thread_state_enum,
133 t.ti_state, "TI_", "");
134 make_lower(state, sizeof (state));
135
136 enum_lookup(oldstate, sizeof (oldstate), thread_state_enum,
137 t.ti_prev_state, "TI_", "");
138 make_lower(oldstate, sizeof (oldstate));
139
140 mdb_printf("%0?p %5d %-12s %-12s %?p %?p %?p\n",
141 (void *)addr, t.ti_thread, state, oldstate,
142 t.ti_active_client, t.ti_client_request, t.ti_main_door_request);
143
144 return (DCMD_OK);
145 }
146
147 static int
walk_thread_info_init(mdb_walk_state_t * wsp)148 walk_thread_info_init(mdb_walk_state_t *wsp)
149 {
150 if (mdb_readvar(&wsp->walk_addr, "thread_list") == -1) {
151 mdb_warn("unable to read thread_list");
152 return (WALK_ERR);
153 }
154
155 if (mdb_layered_walk("uu_list_node", wsp) == -1) {
156 mdb_warn("couldn't walk 'uu_list_node'");
157 return (WALK_ERR);
158 }
159
160 return (WALK_NEXT);
161 }
162
163 static int
walk_thread_info_step(mdb_walk_state_t * wsp)164 walk_thread_info_step(mdb_walk_state_t *wsp)
165 {
166 uintptr_t addr = wsp->walk_addr;
167 thread_info_t ti;
168
169 if (mdb_vread(&ti, sizeof (ti), addr) == -1) {
170 mdb_warn("unable to read thread_info_t at %p", addr);
171 return (WALK_ERR);
172 }
173
174 return (wsp->walk_callback(addr, &ti, wsp->walk_cbdata));
175 }
176
177 static int
request_log(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)178 request_log(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
179 {
180 request_log_entry_t cur;
181 hrtime_t dur;
182 hrtime_t dursec;
183 hrtime_t durnsec;
184 char durstr[20];
185 char stampstr[20];
186 char requstr[30];
187 char respstr[30];
188 char typestr[30];
189 uintptr_t node = 0;
190 uintptr_t client = 0;
191 uint64_t clientid = 0;
192
193 int idx;
194 int opt_v = FALSE; /* verbose */
195
196 if (!(flags & DCMD_ADDRSPEC)) {
197 if (mdb_walk_dcmd("configd_log", "configd_log", argc,
198 argv) == -1) {
199 mdb_warn("can't walk 'configd_log'");
200 return (DCMD_ERR);
201 }
202 return (DCMD_OK);
203 }
204
205 if (mdb_getopts(argc, argv,
206 'c', MDB_OPT_UINTPTR, &client,
207 'i', MDB_OPT_UINT64, &clientid,
208 'n', MDB_OPT_UINTPTR, &node,
209 'v', MDB_OPT_SETBITS, TRUE, &opt_v, NULL) != argc)
210 return (DCMD_USAGE);
211
212 if (DCMD_HDRSPEC(flags)) {
213 mdb_printf("%<u>%-?s %-4s %-14s %9s %-22s %-17s\n%</u>",
214 "ADDR", "THRD", "START", "DURATION", "REQUEST",
215 "RESPONSE");
216 }
217
218 if (mdb_vread(&cur, sizeof (cur), addr) == -1) {
219 mdb_warn("couldn't read log entry at %p", addr);
220 return (DCMD_ERR);
221 }
222
223 /*
224 * apply filters, if any.
225 */
226 if (clientid != 0 && clientid != cur.rl_clientid)
227 return (DCMD_OK);
228
229 if (client != 0 && client != (uintptr_t)cur.rl_client)
230 return (DCMD_OK);
231
232 if (node != 0) {
233 for (idx = 0; idx < MIN(MAX_PTRS, cur.rl_num_ptrs); idx++) {
234 if ((uintptr_t)cur.rl_ptrs[idx].rlp_data == node) {
235 node = 0; /* found it */
236 break;
237 }
238 }
239 if (node != 0)
240 return (DCMD_OK);
241 }
242
243 enum_lookup(requstr, sizeof (requstr), request_enum, cur.rl_request,
244 "REP_PROTOCOL_", "");
245
246 if (cur.rl_end != 0) {
247 enum_lookup(respstr, sizeof (respstr), response_enum,
248 cur.rl_response, "REP_PROTOCOL_", "FAIL_");
249
250 dur = cur.rl_end - cur.rl_start;
251 dursec = dur / NANOSEC;
252 durnsec = dur % NANOSEC;
253
254 if (dursec <= 9)
255 mdb_snprintf(durstr, sizeof (durstr),
256 "%lld.%06lld",
257 dursec, durnsec / (NANOSEC / MICROSEC));
258 else if (dursec <= 9999)
259 mdb_snprintf(durstr, sizeof (durstr),
260 "%lld.%03lld",
261 dursec, durnsec / (NANOSEC / MILLISEC));
262 else
263 mdb_snprintf(durstr, sizeof (durstr),
264 "%lld", dursec);
265 } else {
266 (void) strcpy(durstr, "-");
267 (void) strcpy(respstr, "-");
268 }
269
270 if (max_time_seen != 0 && max_time_seen >= cur.rl_start) {
271 dur = max_time_seen - cur.rl_start;
272 dursec = dur / NANOSEC;
273 durnsec = dur % NANOSEC;
274
275 if (dursec <= 99ULL)
276 mdb_snprintf(stampstr, sizeof (stampstr),
277 "-%lld.%09lld", dursec, durnsec);
278 else if (dursec <= 99999ULL)
279 mdb_snprintf(stampstr, sizeof (stampstr),
280 "-%lld.%06lld",
281 dursec, durnsec / (NANOSEC / MICROSEC));
282 else if (dursec <= 99999999ULL)
283 mdb_snprintf(stampstr, sizeof (stampstr),
284 "-%lld.%03lld",
285 dursec, durnsec / (NANOSEC / MILLISEC));
286 else
287 mdb_snprintf(stampstr, sizeof (stampstr),
288 "-%lld", dursec);
289 } else {
290 (void) strcpy(stampstr, "-");
291 }
292
293 mdb_printf("%0?x %4d T%13s %9s %-22s %-17s\n",
294 addr, cur.rl_tid, stampstr, durstr, requstr, respstr);
295
296 if (opt_v) {
297 mdb_printf("\tclient: %?p (%d)\tptrs: %d\tstamp: %llx\n",
298 cur.rl_client, cur.rl_clientid, cur.rl_num_ptrs,
299 cur.rl_start);
300 for (idx = 0; idx < MIN(MAX_PTRS, cur.rl_num_ptrs); idx++) {
301 enum_lookup(typestr, sizeof (typestr), ptr_type_enum,
302 cur.rl_ptrs[idx].rlp_type, "RC_PTR_TYPE_", "");
303 mdb_printf("\t\t%-7s %5d %?p %?p\n", typestr,
304 cur.rl_ptrs[idx].rlp_id, cur.rl_ptrs[idx].rlp_ptr,
305 cur.rl_ptrs[idx].rlp_data);
306 }
307 mdb_printf("\n");
308 }
309 return (DCMD_OK);
310 }
311
312 struct request_log_walk {
313 size_t rlw_max;
314 size_t rlw_count;
315 size_t rlw_cur;
316 struct request_entry {
317 hrtime_t timestamp;
318 uintptr_t addr;
319 } *rlw_list;
320 };
321
322 /*
323 * we want newer items at the top
324 */
325 static int
request_entry_compare(const void * l,const void * r)326 request_entry_compare(const void *l, const void *r)
327 {
328 const struct request_entry *lp = l;
329 const struct request_entry *rp = r;
330
331 if (rp->timestamp == lp->timestamp)
332 return (0);
333
334 /*
335 * 0 timestamps go first.
336 */
337 if (rp->timestamp == 0)
338 return (1);
339 if (lp->timestamp == 0)
340 return (-1);
341
342 if (lp->timestamp < rp->timestamp)
343 return (1);
344 return (-1);
345 }
346
347 /*ARGSUSED*/
348 static int
request_log_count_thread(uintptr_t addr,thread_info_t * tip,uint_t * arg)349 request_log_count_thread(uintptr_t addr, thread_info_t *tip, uint_t *arg)
350 {
351 (*arg)++;
352
353 return (WALK_NEXT);
354 }
355
356 static int
request_log_add_thread(uintptr_t addr,thread_info_t * tip,struct request_entry ** arg)357 request_log_add_thread(uintptr_t addr, thread_info_t *tip,
358 struct request_entry **arg)
359 {
360 if (max_time_seen < tip->ti_log.rl_start)
361 max_time_seen = tip->ti_log.rl_start;
362
363 if (max_time_seen < tip->ti_log.rl_end)
364 max_time_seen = tip->ti_log.rl_end;
365
366 if (tip->ti_log.rl_start != 0) {
367 if (tip->ti_log.rl_end)
368 (*arg)->timestamp = tip->ti_log.rl_start;
369 else
370 (*arg)->timestamp = 0; /* sort to the top */
371
372 (*arg)->addr = addr + offsetof(thread_info_t, ti_log);
373 ++*arg;
374 }
375 return (WALK_NEXT);
376 }
377
378 static int
request_log_walk_init(mdb_walk_state_t * wsp)379 request_log_walk_init(mdb_walk_state_t *wsp)
380 {
381 struct request_log_walk *rlw;
382 struct request_entry *list, *listp;
383
384 uint_t log_size;
385 uint_t size;
386 uint_t idx;
387 uint_t pos;
388 request_log_entry_t *base;
389 request_log_entry_t cur;
390
391 if (mdb_readvar(&base, "request_log") == -1) {
392 mdb_warn("couldn't read 'request_log'");
393 return (WALK_ERR);
394 }
395 if (mdb_readvar(&log_size, "request_log_size") == -1) {
396 mdb_warn("couldn't read 'request_log_size'");
397 return (WALK_ERR);
398 }
399 size = log_size;
400
401 if (mdb_walk("configd_threads", (mdb_walk_cb_t)request_log_count_thread,
402 &size) == -1) {
403 mdb_warn("couldn't walk 'configd_threads'");
404 return (WALK_ERR);
405 }
406
407 list = mdb_zalloc(sizeof (*list) * size, UM_SLEEP);
408 listp = list;
409
410 if (mdb_walk("configd_threads", (mdb_walk_cb_t)request_log_add_thread,
411 &listp) == -1) {
412 mdb_warn("couldn't walk 'configd_threads'");
413 mdb_free(list, sizeof (*list) * size);
414 return (WALK_ERR);
415 }
416
417 pos = listp - list;
418 for (idx = 0; idx < log_size; idx++) {
419 uintptr_t addr = (uintptr_t)&base[idx];
420 if (mdb_vread(&cur, sizeof (cur), addr) == -1) {
421 mdb_warn("couldn't read log entry at %p", addr);
422 mdb_free(list, sizeof (*list) * size);
423 return (WALK_ERR);
424 }
425
426 if (max_time_seen < cur.rl_start)
427 max_time_seen = cur.rl_start;
428
429 if (max_time_seen < cur.rl_end)
430 max_time_seen = cur.rl_end;
431
432 if (cur.rl_start != 0) {
433 list[pos].timestamp = cur.rl_start;
434 list[pos].addr = addr;
435 pos++;
436 }
437 }
438 qsort(list, pos, sizeof (*list), &request_entry_compare);
439
440 rlw = mdb_zalloc(sizeof (*rlw), UM_SLEEP);
441 rlw->rlw_max = size;
442 rlw->rlw_count = pos;
443 rlw->rlw_cur = 0;
444 rlw->rlw_list = list;
445
446 wsp->walk_data = rlw;
447
448 return (WALK_NEXT);
449 }
450
451 static int
request_log_walk_step(mdb_walk_state_t * wsp)452 request_log_walk_step(mdb_walk_state_t *wsp)
453 {
454 struct request_log_walk *rlw = wsp->walk_data;
455 uintptr_t addr;
456 request_log_entry_t cur;
457
458 if (rlw->rlw_cur >= rlw->rlw_count)
459 return (WALK_DONE);
460
461 addr = rlw->rlw_list[rlw->rlw_cur++].addr;
462
463 if (mdb_vread(&cur, sizeof (cur), addr) == -1) {
464 mdb_warn("couldn't read log entry at %p", addr);
465 return (WALK_ERR);
466 }
467 return (wsp->walk_callback(addr, &cur, wsp->walk_cbdata));
468 }
469
470 static void
request_log_walk_fini(mdb_walk_state_t * wsp)471 request_log_walk_fini(mdb_walk_state_t *wsp)
472 {
473 struct request_log_walk *rlw = wsp->walk_data;
474
475 mdb_free(rlw->rlw_list, sizeof (*rlw->rlw_list) * rlw->rlw_max);
476 mdb_free(rlw, sizeof (*rlw));
477 }
478
479 static const mdb_dcmd_t dcmds[] = {
480 { "configd_status", NULL, "svc.configd status summary",
481 configd_status },
482 { "configd_thread", "?", "Print a thread_info_t tabularly",
483 configd_thread },
484 { "configd_log", "?[-v] [-c clientptr] [-i clientid]",
485 "Print the request log, or a single entry", request_log },
486 { NULL }
487 };
488
489 static const mdb_walker_t walkers[] = {
490 { "configd_threads", "walks the thread_info_ts for all "
491 "threads", walk_thread_info_init, walk_thread_info_step },
492 { "configd_log", "walks the request_log_entry_ts",
493 request_log_walk_init, request_log_walk_step,
494 request_log_walk_fini},
495 { NULL }
496 };
497
498 static const mdb_modinfo_t modinfo = {
499 MDB_API_VERSION, dcmds, walkers
500 };
501
502 const mdb_modinfo_t *
_mdb_init(void)503 _mdb_init(void)
504 {
505 if (mdb_ctf_lookup_by_name("enum rep_protocol_requestid",
506 &request_enum) == -1) {
507 mdb_warn("enum rep_protocol_requestid not found");
508 }
509 if (mdb_ctf_lookup_by_name("enum rep_protocol_responseid",
510 &response_enum) == -1) {
511 mdb_warn("enum rep_protocol_responseid not found");
512 }
513 if (mdb_ctf_lookup_by_name("enum rc_ptr_type",
514 &ptr_type_enum) == -1) {
515 mdb_warn("enum rc_ptr_type not found");
516 }
517 if (mdb_ctf_lookup_by_name("enum thread_state",
518 &thread_state_enum) == -1) {
519 mdb_warn("enum thread_state not found");
520 }
521 return (&modinfo);
522 }
523