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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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