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