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