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 /* 23 * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright (c) 2012 by Delphix. All rights reserved. 25 * Copyright (c) 2019 Carlos Neira <cneirabustos@gmail.com> 26 * Copyright 2019 OmniOS Community Edition (OmniOSce) Association. 27 * Copyright 2019 Joyent, Inc. 28 */ 29 30 #include <sys/mdb_modapi.h> 31 #include <mdb/mdb_whatis.h> 32 #include <mdb/mdb_ctf.h> 33 #include <procfs.h> 34 #include <ucontext.h> 35 #include <siginfo.h> 36 #include <signal.h> 37 #include <setjmp.h> 38 #include <string.h> 39 #include <thr_uberdata.h> 40 #include "findstack.h" 41 #include <libproc.h> 42 43 static const char * 44 stack_flags(const stack_t *sp) 45 { 46 static char buf[32]; 47 48 if (sp->ss_flags == 0) 49 (void) strcpy(buf, " 0"); 50 else if (sp->ss_flags & ~(SS_ONSTACK | SS_DISABLE)) 51 (void) mdb_snprintf(buf, sizeof (buf), " 0x%x", sp->ss_flags); 52 else { 53 buf[0] = '\0'; 54 if (sp->ss_flags & SS_ONSTACK) 55 (void) strcat(buf, "|ONSTACK"); 56 if (sp->ss_flags & SS_DISABLE) 57 (void) strcat(buf, "|DISABLE"); 58 } 59 60 return (buf + 1); 61 } 62 63 /*ARGSUSED*/ 64 static int 65 d_jmp_buf(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 66 { 67 jmp_buf jb; 68 const ulong_t *b = (const ulong_t *)jb; 69 70 if (argc != 0) 71 return (DCMD_USAGE); 72 73 if (mdb_vread(&jb, sizeof (jb), addr) != sizeof (jb)) { 74 mdb_warn("failed to read jmp_buf at %p", addr); 75 return (DCMD_ERR); 76 } 77 78 #if defined(__sparc) 79 mdb_printf(" %%sp = 0x%lx\n", b[1]); 80 mdb_printf(" %%pc = 0x%lx %lA\n", b[2], b[2]); 81 mdb_printf(" %%fp = 0x%lx\n", b[3]); 82 mdb_printf(" %%i7 = 0x%lx %lA\n", b[4], b[4]); 83 #elif defined(__amd64) 84 mdb_printf(" %%rbx = 0x%lx\n", b[0]); 85 mdb_printf(" %%r12 = 0x%lx\n", b[1]); 86 mdb_printf(" %%r13 = 0x%lx\n", b[2]); 87 mdb_printf(" %%r14 = 0x%lx\n", b[3]); 88 mdb_printf(" %%r15 = 0x%lx\n", b[4]); 89 mdb_printf(" %%rbp = 0x%lx\n", b[5]); 90 mdb_printf(" %%rsp = 0x%lx\n", b[6]); 91 mdb_printf(" %%rip = 0x%lx %lA\n", b[7], b[7]); 92 #elif defined(__i386) 93 mdb_printf(" %%ebx = 0x%lx\n", b[0]); 94 mdb_printf(" %%esi = 0x%lx\n", b[1]); 95 mdb_printf(" %%edi = 0x%lx\n", b[2]); 96 mdb_printf(" %%ebp = 0x%lx\n", b[3]); 97 mdb_printf(" %%esp = 0x%lx\n", b[4]); 98 mdb_printf(" %%eip = 0x%lx %lA\n", b[5], b[5]); 99 #endif 100 return (DCMD_OK); 101 } 102 103 const mdb_bitmask_t uc_flags_bits[] = { 104 { "UC_SIGMASK", UC_SIGMASK, UC_SIGMASK }, 105 { "UC_STACK", UC_STACK, UC_STACK }, 106 { "UC_CPU", UC_CPU, UC_CPU }, 107 { "UC_FPU", UC_FPU, UC_FPU }, 108 #if defined(UC_INTR) 109 { "UC_INTR", UC_INTR, UC_INTR }, 110 #endif 111 #if defined(UC_ASR) 112 { "UC_ASR", UC_ASR, UC_ASR }, 113 #endif 114 { NULL, 0, 0 } 115 }; 116 117 /*ARGSUSED*/ 118 static int 119 d_ucontext(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 120 { 121 ucontext_t uc; 122 123 if (argc != 0) 124 return (DCMD_USAGE); 125 126 if (mdb_vread(&uc, sizeof (uc), addr) != sizeof (uc)) { 127 mdb_warn("failed to read ucontext at %p", addr); 128 return (DCMD_ERR); 129 } 130 131 mdb_printf(" flags = 0x%lx <%b>\n", uc.uc_flags, 132 (uint_t)uc.uc_flags, uc_flags_bits); 133 mdb_printf(" link = 0x%p\n", uc.uc_link); 134 mdb_printf(" sigmask = 0x%08x 0x%08x 0x%08x 0x%08x\n", 135 uc.uc_sigmask.__sigbits[0], uc.uc_sigmask.__sigbits[1], 136 uc.uc_sigmask.__sigbits[2], uc.uc_sigmask.__sigbits[3]); 137 mdb_printf(" stack = sp 0x%p size 0x%lx flags %s\n", 138 uc.uc_stack.ss_sp, uc.uc_stack.ss_size, stack_flags(&uc.uc_stack)); 139 mdb_printf(" mcontext = 0x%p\n", 140 addr + OFFSETOF(ucontext_t, uc_mcontext)); 141 142 return (DCMD_OK); 143 } 144 145 /*ARGSUSED*/ 146 static int 147 d_sigjmp_buf(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 148 { 149 #if defined(__sparc) 150 struct { 151 int sjs_flags; 152 greg_t sjs_sp; 153 greg_t sjs_pc; 154 greg_t sjs_fp; 155 greg_t sjs_i7; 156 ucontext_t *sjs_uclink; 157 ulong_t sjs_pad[_JBLEN - 6]; 158 sigset_t sjs_sigmask; 159 #if defined(_LP64) 160 greg_t sjs_asi; 161 greg_t sjs_fprs; 162 #endif 163 stack_t sjs_stack; 164 } s; 165 166 if (argc != 0) 167 return (DCMD_USAGE); 168 169 if (mdb_vread(&s, sizeof (s), addr) != sizeof (s)) { 170 mdb_warn("failed to read sigjmp_buf at %p", addr); 171 return (DCMD_ERR); 172 } 173 174 mdb_printf(" flags = 0x%x\n", s.sjs_flags); 175 mdb_printf(" %%sp = 0x%lx %lA\n", s.sjs_sp, s.sjs_sp); 176 mdb_printf(" %%pc = 0x%lx %lA\n", s.sjs_pc, s.sjs_pc); 177 mdb_printf(" %%fp = 0x%lx %lA\n", s.sjs_fp, s.sjs_fp); 178 mdb_printf(" %%i7 = 0x%lx %lA\n", s.sjs_i7, s.sjs_i7); 179 mdb_printf(" uclink = %p\n", s.sjs_uclink); 180 mdb_printf(" sigset = 0x%08x 0x%08x 0x%08x 0x%08x\n", 181 s.sjs_sigmask.__sigbits[0], s.sjs_sigmask.__sigbits[1], 182 s.sjs_sigmask.__sigbits[2], s.sjs_sigmask.__sigbits[3]); 183 #if defined(_LP64) 184 mdb_printf(" %%asi = 0x%lx\n", s.sjs_asi); 185 mdb_printf(" %%fprs = 0x%lx\n", s.sjs_fprs); 186 #endif 187 mdb_printf(" stack = sp 0x%p size 0x%lx flags %s\n", 188 s.sjs_stack.ss_sp, s.sjs_stack.ss_size, stack_flags(&s.sjs_stack)); 189 190 return (DCMD_OK); 191 192 #elif defined(__i386) || defined(__amd64) 193 return (d_ucontext(addr, flags, argc, argv)); 194 #endif 195 } 196 197 /*ARGSUSED*/ 198 static int 199 d_siginfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 200 { 201 static const char *const msname[] = { 202 "USER", "SYSTEM", "TRAP", "TFAULT", "DFAULT", "KFAULT", 203 "USER_LOCK", "SLEEP", "WAIT_CPU", "STOPPED" 204 }; 205 206 char signame[SIG2STR_MAX]; 207 siginfo_t si; 208 int i; 209 210 if (argc != 0) 211 return (DCMD_USAGE); 212 213 if (mdb_vread(&si, sizeof (si), addr) != sizeof (si)) { 214 mdb_warn("failed to read siginfo at %p", addr); 215 return (DCMD_ERR); 216 } 217 218 if (sig2str(si.si_signo, signame) == -1) 219 (void) strcpy(signame, "unknown"); 220 221 mdb_printf(" signal %5d (%s)\n", si.si_signo, signame); 222 mdb_printf(" code %5d (", si.si_code); 223 224 switch (si.si_code) { 225 case SI_NOINFO: 226 mdb_printf("no info"); 227 break; 228 case SI_DTRACE: 229 mdb_printf("from DTrace raise() action"); 230 break; 231 case SI_RCTL: 232 mdb_printf("from rctl action"); 233 break; 234 case SI_USER: 235 mdb_printf("user generated via kill"); 236 break; 237 case SI_LWP: 238 mdb_printf("user generated via lwp_kill"); 239 break; 240 case SI_QUEUE: 241 mdb_printf("user generated via sigqueue"); 242 break; 243 case SI_TIMER: 244 mdb_printf("from timer expiration"); 245 break; 246 case SI_ASYNCIO: 247 mdb_printf("from async i/o completion"); 248 break; 249 case SI_MESGQ: 250 mdb_printf("from message arrival"); 251 break; 252 default: 253 if (SI_FROMUSER(&si)) 254 mdb_printf("from user process"); 255 else 256 mdb_printf("from kernel"); 257 } 258 259 mdb_printf(")\n errno %5d (%s)\n", 260 si.si_errno, strerror(si.si_errno)); 261 262 if (si.si_code == SI_USER || si.si_code == SI_QUEUE) { 263 mdb_printf(" signal sent from PID %d (uid %d)\n", 264 si.si_pid, si.si_uid); 265 } 266 267 if (si.si_code == SI_QUEUE) { 268 mdb_printf(" signal value = 0t%d / %p\n", 269 si.si_value.sival_int, si.si_value.sival_ptr); 270 } 271 272 switch (si.si_signo) { 273 case SIGCLD: 274 mdb_printf(" signal sent from child PID %d (uid %d)\n", 275 si.si_pid, si.si_uid); 276 mdb_printf(" usr time = 0t%ld ticks, sys time = 0t%ld ticks\n", 277 si.si_utime, si.si_stime); 278 mdb_printf(" wait status = 0x%x\n", si.si_status); 279 break; 280 281 case SIGSEGV: 282 case SIGBUS: 283 case SIGILL: 284 case SIGTRAP: 285 case SIGFPE: 286 mdb_printf(" fault address = 0x%p\n trapno = %d\n", 287 si.si_addr, si.si_trapno); 288 mdb_printf(" instruction address = 0x%p %lA\n", 289 si.si_pc, si.si_pc); 290 break; 291 292 case SIGPOLL: 293 case SIGXFSZ: 294 mdb_printf(" fd = %d band = 0x%lx\n", 295 si.si_fd, si.si_band); 296 break; 297 298 case SIGPROF: 299 mdb_printf(" last fault address = 0x%p fault type = %d\n", 300 si.si_faddr, si.si_fault); 301 mdb_printf(" timestamp = 0t%ld sec 0t%ld nsec\n", 302 si.si_tstamp.tv_sec, si.si_tstamp.tv_nsec); 303 304 if (si.__data.__prof.__syscall != 0) { 305 mdb_printf(" system call %d (", si.si_syscall); 306 if (si.si_nsysarg > 0) { 307 mdb_printf("%lx", si.si_sysarg[0]); 308 for (i = 1; i < si.si_nsysarg; i++) 309 mdb_printf(", %lx", si.si_sysarg[i]); 310 } 311 mdb_printf(" )\n"); 312 } 313 314 for (i = 0; i < sizeof (msname) / sizeof (msname[0]); i++) { 315 mdb_printf(" mstate[\"%s\"] = %d\n", 316 msname[i], si.si_mstate[i]); 317 } 318 break; 319 } 320 321 return (DCMD_OK); 322 } 323 324 static int 325 uc_walk_step(mdb_walk_state_t *wsp) 326 { 327 uintptr_t addr = wsp->walk_addr; 328 ucontext_t uc; 329 330 if (addr == 0) 331 return (WALK_DONE); 332 333 if (mdb_vread(&uc, sizeof (uc), addr) != sizeof (uc)) { 334 mdb_warn("failed to read ucontext at %p", addr); 335 return (WALK_ERR); 336 } 337 338 wsp->walk_addr = (uintptr_t)uc.uc_link; 339 return (wsp->walk_callback(addr, &uc, wsp->walk_cbdata)); 340 } 341 342 static int 343 oldc_walk_init(mdb_walk_state_t *wsp) 344 { 345 ssize_t nbytes = mdb_get_xdata("lwpstatus", NULL, 0); 346 347 if (nbytes <= 0) { 348 mdb_warn("lwpstatus information not available"); 349 return (WALK_ERR); 350 } 351 352 if (wsp->walk_addr != 0) { 353 mdb_warn("walker only supports global walk\n"); 354 return (WALK_ERR); 355 } 356 357 wsp->walk_addr = nbytes; /* Use walk_addr to track size */ 358 wsp->walk_data = mdb_alloc(nbytes, UM_SLEEP); 359 360 if (mdb_get_xdata("lwpstatus", wsp->walk_data, nbytes) != nbytes) { 361 mdb_warn("failed to read lwpstatus information"); 362 mdb_free(wsp->walk_data, nbytes); 363 return (WALK_ERR); 364 } 365 366 wsp->walk_arg = wsp->walk_data; /* Use walk_arg to track pointer */ 367 return (WALK_NEXT); 368 } 369 370 static int 371 oldc_walk_step(mdb_walk_state_t *wsp) 372 { 373 const lwpstatus_t *lsp, *end; 374 375 end = (const lwpstatus_t *)((uintptr_t)wsp->walk_data + wsp->walk_addr); 376 lsp = wsp->walk_arg; 377 378 wsp->walk_arg = (void *)(lsp + 1); 379 380 if (lsp < end) { 381 uintptr_t addr = lsp->pr_oldcontext; 382 ucontext_t uc; 383 384 if (addr == 0) 385 return (WALK_NEXT); 386 387 if (mdb_vread(&uc, sizeof (uc), addr) != sizeof (uc)) { 388 mdb_warn("failed to read ucontext at %p", addr); 389 return (WALK_NEXT); 390 } 391 392 return (wsp->walk_callback(addr, &uc, wsp->walk_cbdata)); 393 } 394 395 return (WALK_DONE); 396 } 397 398 static void 399 oldc_walk_fini(mdb_walk_state_t *wsp) 400 { 401 mdb_free(wsp->walk_data, wsp->walk_addr); /* walk_addr has size */ 402 } 403 404 /* 405 * ==================== threads ========================== 406 * These are the interfaces that used to require libthread. 407 * Now, libthread has been folded into libc. 408 * ======================================================= 409 */ 410 411 /* 412 * prt_addr() is called up to three times to generate arguments for 413 * one call to mdb_printf(). We must return at least three different 414 * pointers to static storage for consecutive calls to prt_addr(). 415 */ 416 static const char * 417 prt_addr(void *addr, int pad) 418 { 419 static char buffer[4][24]; 420 static int ix = 0; 421 char *buf; 422 423 if (ix == 4) /* use buffers in sequence: 0, 1, 2, 3 */ 424 ix = 0; 425 buf = buffer[ix++]; 426 if (addr == NULL) 427 return (pad? "<NULL> " : "<NULL>"); 428 else { 429 #ifdef _LP64 430 (void) mdb_snprintf(buf, sizeof (buffer[0]), "0x%016lx", addr); 431 if (pad) 432 (void) strcpy(buf + 18, " "); 433 #else 434 (void) mdb_snprintf(buf, sizeof (buffer[0]), "0x%08lx", addr); 435 if (pad) 436 (void) strcpy(buf + 10, " "); 437 #endif /* _LP64 */ 438 return (buf); 439 } 440 } 441 442 #define HD(str) mdb_printf(" " str "\n") 443 #define OFFSTR "+0x%-7lx " 444 #define OFFSET(member) ((size_t)OFFSETOF(ulwp_t, member)) 445 446 /*ARGSUSED*/ 447 static int 448 d_ulwp(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 449 { 450 ulwp_t ulwp; 451 452 if (argc != 0 || !(flags & DCMD_ADDRSPEC)) 453 return (DCMD_USAGE); 454 455 if (mdb_vread(&ulwp, sizeof (ulwp), addr) != sizeof (ulwp) && 456 (bzero(&ulwp, sizeof (ulwp)), 457 mdb_vread(&ulwp, REPLACEMENT_SIZE, addr)) != REPLACEMENT_SIZE) { 458 mdb_warn("failed to read ulwp at 0x%p", addr); 459 return (DCMD_ERR); 460 } 461 462 mdb_printf("%#a\n", addr); 463 464 HD("self uberdata"); 465 mdb_printf(OFFSTR "%s %s\n", 466 OFFSET(ul_self), 467 prt_addr(ulwp.ul_self, 1), 468 prt_addr(ulwp.ul_uberdata, 0)); 469 470 HD("tlsent ntlsent"); 471 mdb_printf(OFFSTR "%s %ld\n", 472 OFFSET(ul_tlsent), 473 prt_addr(ulwp.ul_tlsent, 1), 474 ulwp.ul_ntlsent); 475 476 HD("forw back next"); 477 mdb_printf(OFFSTR "%s %s %s\n", 478 OFFSET(ul_forw), 479 prt_addr(ulwp.ul_forw, 1), 480 prt_addr(ulwp.ul_back, 1), 481 prt_addr(ulwp.ul_next, 0)); 482 483 HD("hash rval stk"); 484 mdb_printf(OFFSTR "%s %s %s\n", 485 OFFSET(ul_hash), 486 prt_addr(ulwp.ul_hash, 1), 487 prt_addr(ulwp.ul_rval, 1), 488 prt_addr(ulwp.ul_stk, 0)); 489 490 HD("mapsiz guardsize stktop stksiz"); 491 mdb_printf(OFFSTR "%-10ld %-10ld %s %ld\n", 492 OFFSET(ul_mapsiz), 493 ulwp.ul_mapsiz, 494 ulwp.ul_guardsize, 495 prt_addr((void *)ulwp.ul_stktop, 1), 496 ulwp.ul_stksiz); 497 498 HD("ustack.ss_sp ustack.ss_size ustack.ss_flags"); 499 mdb_printf(OFFSTR "%s %-21ld %s\n", 500 OFFSET(ul_ustack.ss_sp), 501 prt_addr(ulwp.ul_ustack.ss_sp, 1), 502 ulwp.ul_ustack.ss_size, 503 stack_flags(&ulwp.ul_ustack)); 504 505 HD("ix lwpid pri epri policy cid"); 506 mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %-10d %d\n", 507 OFFSET(ul_ix), 508 ulwp.ul_ix, 509 ulwp.ul_lwpid, 510 ulwp.ul_pri, 511 ulwp.ul_epri, 512 ulwp.ul_policy, 513 ulwp.ul_cid); 514 515 HD("cursig pleasestop stop signalled dead unwind"); 516 mdb_printf(OFFSTR "%-10d ", 517 OFFSET(ul_cursig), 518 ulwp.ul_cursig); 519 mdb_printf(ulwp.ul_pleasestop? "0x%-8x " : "%-10d ", 520 ulwp.ul_pleasestop); 521 mdb_printf(ulwp.ul_stop? "0x%-8x " : "%-10d ", 522 ulwp.ul_stop); 523 mdb_printf("%-10d %-10d %d\n", 524 ulwp.ul_signalled, 525 ulwp.ul_dead, 526 ulwp.ul_unwind); 527 528 HD("detached writer stopping can'prolog preempt savpreempt"); 529 mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %-10d %d\n", 530 OFFSET(ul_detached), 531 ulwp.ul_detached, 532 ulwp.ul_writer, 533 ulwp.ul_stopping, 534 ulwp.ul_cancel_prologue, 535 ulwp.ul_preempt, 536 ulwp.ul_savpreempt); 537 538 HD("sigsuspend main fork primarymap m'spinners d'noreserv"); 539 mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %-10d %d\n", 540 OFFSET(ul_sigsuspend), 541 ulwp.ul_sigsuspend, 542 ulwp.ul_main, 543 ulwp.ul_fork, 544 ulwp.ul_primarymap, 545 ulwp.ul_max_spinners, 546 ulwp.ul_door_noreserve); 547 548 HD("queue_fifo c'w'defer e'detect' async_safe rt rtqueued"); 549 mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %-10d %d\n", 550 OFFSET(ul_queue_fifo), 551 ulwp.ul_queue_fifo, 552 ulwp.ul_cond_wait_defer, 553 ulwp.ul_error_detection, 554 ulwp.ul_async_safe, 555 ulwp.ul_rt, 556 ulwp.ul_rtqueued); 557 558 HD("misaligned adapt'spin queue_spin critical sigdefer vfork"); 559 mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %-10d %d\n", 560 OFFSET(ul_misaligned), 561 ulwp.ul_misaligned, 562 ulwp.ul_adaptive_spin, 563 ulwp.ul_queue_spin, 564 ulwp.ul_critical, 565 ulwp.ul_sigdefer, 566 ulwp.ul_vfork); 567 568 HD("cancelable c'pending c'disabled c'async save_async mutator"); 569 mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %-10d %d\n", 570 OFFSET(ul_cancelable), 571 ulwp.ul_cancelable, 572 ulwp.ul_cancel_pending, 573 ulwp.ul_cancel_disabled, 574 ulwp.ul_cancel_async, 575 ulwp.ul_save_async, 576 ulwp.ul_mutator); 577 578 HD("created replace nocancel errno errnop"); 579 mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %s\n", 580 OFFSET(ul_created), 581 ulwp.ul_created, 582 ulwp.ul_replace, 583 ulwp.ul_nocancel, 584 ulwp.ul_errno, 585 prt_addr(ulwp.ul_errnop, 0)); 586 587 HD("clnup_hdr schedctl_called schedctl"); 588 mdb_printf(OFFSTR "%s %s %s\n", 589 OFFSET(ul_clnup_hdr), 590 prt_addr(ulwp.ul_clnup_hdr, 1), 591 prt_addr(ulwp.ul_schedctl_called, 1), 592 prt_addr((void *)ulwp.ul_schedctl, 0)); 593 594 HD("bindflags libc_locks stsd &ftsd"); 595 mdb_printf(OFFSTR, 596 OFFSET(ul_bindflags)); 597 mdb_printf(ulwp.ul_bindflags? "0x%-8x " : "%-10d ", 598 ulwp.ul_bindflags); 599 mdb_printf("%-10d ", ulwp.ul_libc_locks); 600 mdb_printf("%s %s\n", 601 prt_addr(ulwp.ul_stsd, 1), 602 prt_addr((void *)(addr + OFFSET(ul_ftsd[0])), 0)); 603 604 HD("eventmask[0..1] eventnum eventdata"); 605 mdb_printf(OFFSTR "0x%08x 0x%08x %-21d %s\n", 606 OFFSET(ul_td_evbuf.eventmask.event_bits[0]), 607 ulwp.ul_td_evbuf.eventmask.event_bits[0], 608 ulwp.ul_td_evbuf.eventmask.event_bits[1], 609 ulwp.ul_td_evbuf.eventnum, 610 prt_addr(ulwp.ul_td_evbuf.eventdata, 0)); 611 612 HD("td'enable sync'reg qtype cv_wake rtld usropts"); 613 mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %-10d ", 614 OFFSET(ul_td_events_enable), 615 ulwp.ul_td_events_enable, 616 ulwp.ul_sync_obj_reg, 617 ulwp.ul_qtype, 618 ulwp.ul_cv_wake, 619 ulwp.ul_rtld); 620 mdb_printf(ulwp.ul_usropts? "0x%x\n" : "%d\n", 621 ulwp.ul_usropts); 622 623 HD("startpc startarg wchan"); 624 mdb_printf(OFFSTR "%s %s %s\n", 625 OFFSET(ul_startpc), 626 prt_addr((void *)ulwp.ul_startpc, 1), 627 prt_addr(ulwp.ul_startarg, 1), 628 prt_addr(ulwp.ul_wchan, 0)); 629 630 HD("link sleepq cvmutex"); 631 mdb_printf(OFFSTR "%s %s %s\n", 632 OFFSET(ul_link), 633 prt_addr(ulwp.ul_link, 1), 634 prt_addr(ulwp.ul_sleepq, 1), 635 prt_addr(ulwp.ul_cvmutex, 0)); 636 637 HD("mxchain save_state"); 638 mdb_printf(OFFSTR "%s %d\n", 639 OFFSET(ul_mxchain), 640 prt_addr(ulwp.ul_mxchain, 1), 641 ulwp.ul_save_state); 642 643 HD("rdlockcnt rd_rwlock rd_count"); 644 mdb_printf(OFFSTR "%-21d %s %d\n", 645 OFFSET(ul_rdlockcnt), 646 ulwp.ul_rdlockcnt, 647 prt_addr(ulwp.ul_readlock.single.rd_rwlock, 1), 648 ulwp.ul_readlock.single.rd_count); 649 650 HD("heldlockcnt heldlocks tpdp"); 651 mdb_printf(OFFSTR "%-21d %s %s\n", 652 OFFSET(ul_heldlockcnt), 653 ulwp.ul_heldlockcnt, 654 prt_addr(ulwp.ul_heldlocks.single, 1), 655 prt_addr(ulwp.ul_tpdp, 0)); 656 657 HD("siglink s'l'spin s'l'spin2 s'l'sleep s'l'wakeup"); 658 mdb_printf(OFFSTR "%s %-10d %-10d %-10d %d\n", 659 OFFSET(ul_siglink), 660 prt_addr(ulwp.ul_siglink, 1), 661 ulwp.ul_spin_lock_spin, 662 ulwp.ul_spin_lock_spin2, 663 ulwp.ul_spin_lock_sleep, 664 ulwp.ul_spin_lock_wakeup); 665 666 HD("&queue_root rtclassid pilocks"); 667 mdb_printf(OFFSTR "%s %-10d %d\n", 668 OFFSET(ul_queue_root), 669 prt_addr((void *)(addr + OFFSET(ul_queue_root)), 1), 670 ulwp.ul_rtclassid, 671 ulwp.ul_pilocks); 672 673 /* 674 * The remainder of the ulwp_t structure 675 * is invalid if this is a replacement. 676 */ 677 if (ulwp.ul_replace) 678 return (DCMD_OK); 679 680 HD("sigmask[0..3]"); 681 mdb_printf(OFFSTR "0x%08x 0x%08x 0x%08x 0x%08x\n", 682 OFFSET(ul_sigmask.__sigbits[0]), 683 ulwp.ul_sigmask.__sigbits[0], 684 ulwp.ul_sigmask.__sigbits[1], 685 ulwp.ul_sigmask.__sigbits[2], 686 ulwp.ul_sigmask.__sigbits[3]); 687 688 HD("tmpmask[0..3]"); 689 mdb_printf(OFFSTR "0x%08x 0x%08x 0x%08x 0x%08x\n", 690 OFFSET(ul_tmpmask.__sigbits[0]), 691 ulwp.ul_tmpmask.__sigbits[0], 692 ulwp.ul_tmpmask.__sigbits[1], 693 ulwp.ul_tmpmask.__sigbits[2], 694 ulwp.ul_tmpmask.__sigbits[3]); 695 696 HD("&siginfo &spinlock &fpuenv"); 697 mdb_printf(OFFSTR "%s %s %s\n", 698 OFFSET(ul_siginfo), 699 prt_addr((void *)(addr + OFFSET(ul_siginfo)), 1), 700 prt_addr((void *)(addr + OFFSET(ul_spinlock)), 1), 701 prt_addr((void *)(addr + OFFSET(ul_fpuenv)), 0)); 702 703 HD("tmem.size &tmem.roots"); 704 mdb_printf(OFFSTR "%-21H %s\n", 705 OFFSET(ul_tmem), 706 ulwp.ul_tmem.tm_size, 707 prt_addr((void *)(addr + OFFSET(ul_tmem) + sizeof (size_t)), 0)); 708 709 return (DCMD_OK); 710 } 711 712 /* 713 * Get the address of the unique uberdata_t structure. 714 */ 715 static uintptr_t 716 uberdata_addr(void) 717 { 718 uintptr_t uaddr; 719 uintptr_t addr; 720 GElf_Sym sym; 721 722 if (mdb_lookup_by_obj("libc.so.1", "_tdb_bootstrap", &sym) != 0) { 723 mdb_warn("cannot find libc.so.1`_tdb_bootstrap"); 724 return (0); 725 } 726 if (mdb_vread(&addr, sizeof (addr), sym.st_value) == sizeof (addr) && 727 addr != 0 && 728 mdb_vread(&uaddr, sizeof (uaddr), addr) == sizeof (uaddr) && 729 uaddr != 0) { 730 return (uaddr); 731 } 732 if (mdb_lookup_by_obj("libc.so.1", "_uberdata", &sym) != 0) { 733 mdb_warn("cannot find libc.so.1`_uberdata"); 734 return (0); 735 } 736 return ((uintptr_t)sym.st_value); 737 } 738 739 #undef OFFSET 740 #define OFFSET(member) ((size_t)OFFSETOF(uberdata_t, member)) 741 742 /*ARGSUSED*/ 743 static int 744 d_uberdata(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 745 { 746 uberdata_t uberdata; 747 int i; 748 749 if (argc != 0) 750 return (DCMD_USAGE); 751 if (!(flags & DCMD_ADDRSPEC) && (addr = uberdata_addr()) == 0) 752 return (DCMD_ERR); 753 754 if (mdb_vread(&uberdata, sizeof (uberdata), addr) != 755 sizeof (uberdata)) { 756 mdb_warn("failed to read uberdata at 0x%p", addr); 757 return (DCMD_ERR); 758 } 759 760 mdb_printf("%#a\n", addr); 761 762 HD("&link_lock &ld_lock &fork_lock"); 763 mdb_printf(OFFSTR "%s %s %s\n", 764 OFFSET(link_lock), 765 prt_addr((void *)(addr + OFFSET(link_lock)), 1), 766 prt_addr((void *)(addr + OFFSET(ld_lock)), 1), 767 prt_addr((void *)(addr + OFFSET(fork_lock)), 0)); 768 769 HD("&atfork_lock &callout_lock &tdb_hash_lock"); 770 mdb_printf(OFFSTR "%s %s %s\n", 771 OFFSET(atfork_lock), 772 prt_addr((void *)(addr + OFFSET(atfork_lock)), 1), 773 prt_addr((void *)(addr + OFFSET(callout_lock)), 1), 774 prt_addr((void *)(addr + OFFSET(tdb_hash_lock)), 0)); 775 776 HD("&tdb_hash_lock_stats &siguaction[0]"); 777 mdb_printf(OFFSTR "%s %s\n", 778 OFFSET(tdb_hash_lock_stats), 779 prt_addr((void *)(addr + OFFSET(tdb_hash_lock_stats)), 1), 780 prt_addr((void *)(addr + OFFSET(siguaction)), 0)); 781 782 HD("&bucket free_list chunks"); 783 for (i = 0; i < NBUCKETS; i++) { 784 mdb_printf(OFFSTR "%s %s %ld\n", 785 OFFSET(bucket[i]), 786 prt_addr((void *)(addr + OFFSET(bucket[i])), 1), 787 prt_addr(uberdata.bucket[i].free_list, 1), 788 uberdata.bucket[i].chunks); 789 } 790 791 HD("&atexit_root head exit_frame_monitor"); 792 mdb_printf(OFFSTR "%s %s %s\n", 793 OFFSET(atexit_root), 794 prt_addr((void *)(addr + OFFSET(atexit_root.exitfns_lock)), 1), 795 prt_addr(uberdata.atexit_root.head, 1), 796 prt_addr(uberdata.atexit_root.exit_frame_monitor, 0)); 797 798 HD("&quickexit_root head"); 799 mdb_printf(OFFSTR "%s %s\n", 800 OFFSET(quickexit_root), 801 prt_addr((void *)(addr + OFFSET(quickexit_root.exitfns_lock)), 1), 802 prt_addr(uberdata.quickexit_root.head, 0)); 803 804 805 HD("&tsd_metadata tsdm_nkeys tsdm_nused tsdm_destro"); 806 mdb_printf(OFFSTR "%s %-10d %-10d %s\n", 807 OFFSET(tsd_metadata), 808 prt_addr((void *)(addr + OFFSET(tsd_metadata.tsdm_lock)), 1), 809 uberdata.tsd_metadata.tsdm_nkeys, 810 uberdata.tsd_metadata.tsdm_nused, 811 prt_addr((void *)uberdata.tsd_metadata.tsdm_destro, 0)); 812 813 HD("&tls_metadata tls_modinfo.data tls_modinfo.size"); 814 mdb_printf(OFFSTR "%s %s %ld\n", 815 OFFSET(tls_metadata), 816 prt_addr((void *)(addr + OFFSET(tls_metadata.tls_lock)), 1), 817 prt_addr(uberdata.tls_metadata.tls_modinfo.tls_data, 1), 818 uberdata.tls_metadata.tls_modinfo.tls_size); 819 820 HD(" static_tls.data static_tls.size"); 821 mdb_printf(OFFSTR "%s %s %ld\n", 822 OFFSET(tls_metadata.static_tls), 823 " ", 824 prt_addr(uberdata.tls_metadata.static_tls.tls_data, 1), 825 uberdata.tls_metadata.static_tls.tls_size); 826 827 HD("primary_ma bucket_ini uflags.mt uflags.pad uflags.trs uflags.ted"); 828 mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %-10d %d\n", 829 OFFSET(primary_map), 830 uberdata.primary_map, 831 uberdata.bucket_init, 832 uberdata.uberflags.uf_x.x_mt, 833 uberdata.uberflags.uf_x.x_pad, 834 uberdata.uberflags.uf_x.x_tdb_register_sync, 835 uberdata.uberflags.uf_x.x_thread_error_detection); 836 837 HD("queue_head thr_hash_table hash_size hash_mask"); 838 mdb_printf(OFFSTR "%s %s %-10d 0x%x\n", 839 OFFSET(queue_head), 840 prt_addr(uberdata.queue_head, 1), 841 prt_addr(uberdata.thr_hash_table, 1), 842 uberdata.hash_size, 843 uberdata.hash_mask); 844 845 HD("ulwp_one all_lwps all_zombies"); 846 mdb_printf(OFFSTR "%s %s %s\n", 847 OFFSET(ulwp_one), 848 prt_addr(uberdata.ulwp_one, 1), 849 prt_addr(uberdata.all_lwps, 1), 850 prt_addr(uberdata.all_zombies, 0)); 851 852 HD("nthreads nzombies ndaemons pid sigacthandler"); 853 mdb_printf(OFFSTR "%-10d %-10d %-10d %-10d %s\n", 854 OFFSET(nthreads), 855 uberdata.nthreads, 856 uberdata.nzombies, 857 uberdata.ndaemons, 858 (int)uberdata.pid, 859 prt_addr((void *)uberdata.sigacthandler, 0)); 860 861 HD("lwp_stacks lwp_laststack nfreestack stk_cache"); 862 mdb_printf(OFFSTR "%s %s %-10d %d\n", 863 OFFSET(lwp_stacks), 864 prt_addr(uberdata.lwp_stacks, 1), 865 prt_addr(uberdata.lwp_laststack, 1), 866 uberdata.nfreestack, 867 uberdata.thread_stack_cache); 868 869 HD("ulwp_freelist ulwp_lastfree ulwp_replace_free"); 870 mdb_printf(OFFSTR "%s %s %s\n", 871 OFFSET(ulwp_freelist), 872 prt_addr(uberdata.ulwp_freelist, 1), 873 prt_addr(uberdata.ulwp_lastfree, 1), 874 prt_addr(uberdata.ulwp_replace_free, 0)); 875 876 HD("ulwp_replace_last atforklist"); 877 mdb_printf(OFFSTR "%s %s\n", 878 OFFSET(ulwp_replace_last), 879 prt_addr(uberdata.ulwp_replace_last, 1), 880 prt_addr(uberdata.atforklist, 0)); 881 882 HD("robustlocks robustlist progname"); 883 mdb_printf(OFFSTR "%s %s %s\n", 884 OFFSET(robustlocks), 885 prt_addr(uberdata.robustlocks, 1), 886 prt_addr(uberdata.robustlist, 1), 887 prt_addr(uberdata.progname, 0)); 888 889 HD("tdb_bootstrap tdb_sync_addr_hash tdb_'count tdb_'fail"); 890 mdb_printf(OFFSTR "%s %s %-10d %d\n", 891 OFFSET(tdb_bootstrap), 892 prt_addr(uberdata.tdb_bootstrap, 1), 893 prt_addr(uberdata.tdb.tdb_sync_addr_hash, 1), 894 uberdata.tdb.tdb_register_count, 895 uberdata.tdb.tdb_hash_alloc_failed); 896 897 HD("tdb_sync_addr_free tdb_sync_addr_last tdb_sync_alloc"); 898 mdb_printf(OFFSTR "%s %s %ld\n", 899 OFFSET(tdb.tdb_sync_addr_free), 900 prt_addr(uberdata.tdb.tdb_sync_addr_free, 1), 901 prt_addr(uberdata.tdb.tdb_sync_addr_last, 1), 902 uberdata.tdb.tdb_sync_alloc); 903 904 HD("tdb_ev_global_mask tdb_events"); 905 mdb_printf(OFFSTR "0x%08x 0x%08x %s\n", 906 OFFSET(tdb.tdb_ev_global_mask), 907 uberdata.tdb.tdb_ev_global_mask.event_bits[0], 908 uberdata.tdb.tdb_ev_global_mask.event_bits[1], 909 prt_addr((void *)uberdata.tdb.tdb_events, 0)); 910 911 return (DCMD_OK); 912 } 913 914 static int 915 ulwp_walk_init(mdb_walk_state_t *wsp) 916 { 917 uintptr_t addr = wsp->walk_addr; 918 uintptr_t uber_addr; 919 int offset; 920 921 offset = mdb_ctf_offsetof_by_name("uberdata_t", "all_lwps"); 922 if (offset == -1) { 923 offset = OFFSETOF(uberdata_t, all_lwps); 924 mdb_warn("CTF data is missing for uberdata_t; using current " 925 "platform's offset for uberdata.all_lwps"); 926 } 927 928 if (addr == 0 && 929 ((uber_addr = uberdata_addr()) == 0 || 930 mdb_vread(&addr, sizeof (addr), uber_addr + offset) 931 != sizeof (addr))) { 932 mdb_warn("cannot find 'uberdata.all_lwps'"); 933 return (WALK_ERR); 934 } 935 if (addr == 0) 936 return (WALK_DONE); 937 wsp->walk_addr = addr; 938 wsp->walk_data = (void *)addr; 939 return (WALK_NEXT); 940 } 941 942 static int 943 ulwp_walk_step(mdb_walk_state_t *wsp) 944 { 945 uintptr_t addr = wsp->walk_addr; 946 ulwp_t ulwp; 947 948 if (addr == 0) 949 return (WALK_DONE); 950 if (mdb_vread(&ulwp, sizeof (ulwp), addr) != sizeof (ulwp) && 951 (bzero(&ulwp, sizeof (ulwp)), 952 mdb_vread(&ulwp, REPLACEMENT_SIZE, addr)) != REPLACEMENT_SIZE) { 953 mdb_warn("failed to read ulwp at 0x%p", addr); 954 return (WALK_ERR); 955 } 956 /* 957 * If we have looped around to the beginning 958 * of the circular linked list, we are done. 959 */ 960 if ((wsp->walk_addr = (uintptr_t)ulwp.ul_forw) 961 == (uintptr_t)wsp->walk_data) 962 wsp->walk_addr = 0; 963 return (wsp->walk_callback(addr, &ulwp, wsp->walk_cbdata)); 964 } 965 966 /* Avoid classifying NULL pointers as part of the main stack on x86 */ 967 #define MIN_STACK_ADDR (0x10000ul) 968 969 static int 970 whatis_walk_ulwp(uintptr_t addr, const ulwp_t *ulwp, mdb_whatis_t *w) 971 { 972 uintptr_t cur; 973 lwpid_t id = ulwp->ul_lwpid; 974 uintptr_t top, base, size; 975 976 while (mdb_whatis_match(w, addr, sizeof (ulwp_t), &cur)) 977 mdb_whatis_report_object(w, cur, addr, 978 "allocated as thread %#r's ulwp_t\n", id); 979 980 top = (uintptr_t)ulwp->ul_stktop; 981 size = ulwp->ul_stksiz; 982 983 /* 984 * The main stack ends up being a little weird, especially if 985 * the stack ulimit is unlimited. This tries to take that into 986 * account. 987 */ 988 if (size > top) 989 size = top; 990 if (top > MIN_STACK_ADDR && top - size < MIN_STACK_ADDR) 991 size = top - MIN_STACK_ADDR; 992 993 base = top - size; 994 995 while (mdb_whatis_match(w, base, size, &cur)) 996 mdb_whatis_report_address(w, cur, "in [ stack tid=%#r ]\n", id); 997 998 if (ulwp->ul_ustack.ss_flags & SS_ONSTACK) { 999 base = (uintptr_t)ulwp->ul_ustack.ss_sp; 1000 size = ulwp->ul_ustack.ss_size; 1001 1002 while (mdb_whatis_match(w, base, size, &cur)) 1003 mdb_whatis_report_address(w, cur, 1004 "in [ altstack tid=%#r ]\n", id); 1005 } 1006 1007 return (WHATIS_WALKRET(w)); 1008 } 1009 1010 /*ARGSUSED*/ 1011 static int 1012 whatis_run_ulwps(mdb_whatis_t *w, void *arg) 1013 { 1014 if (mdb_walk("ulwps", (mdb_walk_cb_t)whatis_walk_ulwp, w) == -1) { 1015 mdb_warn("couldn't find ulwps walker"); 1016 return (1); 1017 } 1018 return (0); 1019 } 1020 1021 /* 1022 * ======================================================= 1023 * End of thread (previously libthread) interfaces. 1024 * ==================== threads ========================== 1025 */ 1026 1027 int 1028 stacks_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1029 { 1030 int rval = stacks(addr, flags, argc, argv); 1031 1032 /* 1033 * For the user-level variant of ::stacks, we don't bother caching 1034 * state, as even a very large program is unlikely to compare to the 1035 * kernel in terms of number of threads. (And if you find yourself 1036 * here in anger, frustrated about how long ::stacks is running on 1037 * your galactically complicated zillion-thread program, hopefully 1038 * you will find some solace in the irony. Okay, probably not...) 1039 */ 1040 stacks_cleanup(B_TRUE); 1041 return (rval); 1042 } 1043 1044 typedef struct tid2ulwp_walk { 1045 lwpid_t t2u_tid; 1046 uintptr_t t2u_lwp; 1047 boolean_t t2u_found; 1048 } tid2ulwp_walk_t; 1049 1050 /*ARGSUSED*/ 1051 static int 1052 tid2ulwp_walk(uintptr_t addr, ulwp_t *ulwp, tid2ulwp_walk_t *t2u) 1053 { 1054 if (ulwp->ul_lwpid == t2u->t2u_tid) { 1055 t2u->t2u_lwp = addr; 1056 t2u->t2u_found = B_TRUE; 1057 return (WALK_DONE); 1058 } 1059 1060 return (WALK_NEXT); 1061 } 1062 1063 static int 1064 tid2ulwp_impl(uintptr_t tid_addr, uintptr_t *ulwp_addrp) 1065 { 1066 tid2ulwp_walk_t t2u; 1067 1068 bzero(&t2u, sizeof (t2u)); 1069 t2u.t2u_tid = (lwpid_t)tid_addr; 1070 1071 if (mdb_walk("ulwp", (mdb_walk_cb_t)tid2ulwp_walk, &t2u) != 0) { 1072 mdb_warn("can't walk 'ulwp'"); 1073 return (DCMD_ERR); 1074 } 1075 1076 if (!t2u.t2u_found) { 1077 mdb_warn("thread ID %d not found", t2u.t2u_tid); 1078 return (DCMD_ERR); 1079 } 1080 *ulwp_addrp = t2u.t2u_lwp; 1081 return (DCMD_OK); 1082 } 1083 1084 /*ARGSUSED*/ 1085 static int 1086 tid2ulwp(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1087 { 1088 uintptr_t ulwp_addr; 1089 int error; 1090 1091 if (argc != 0) 1092 return (DCMD_USAGE); 1093 1094 error = tid2ulwp_impl(addr, &ulwp_addr); 1095 if (error == DCMD_OK) 1096 mdb_printf("%p\n", ulwp_addr); 1097 return (error); 1098 } 1099 1100 /* 1101 * This is used by both d_tsd and d_errno, and contains the sum of all 1102 * members used by both commands. 1103 */ 1104 typedef struct mdb_libc_ulwp { 1105 void *ul_ftsd[TSD_NFAST]; 1106 tsd_t *ul_stsd; 1107 int *ul_errnop; 1108 } mdb_libc_ulwp_t; 1109 1110 /* 1111 * Map from thread pointer to tsd for given key 1112 */ 1113 static int 1114 d_tsd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1115 { 1116 mdb_libc_ulwp_t u; 1117 uintptr_t ulwp_addr; 1118 uintptr_t key = 0; 1119 void *element = NULL; 1120 1121 if (mdb_getopts(argc, argv, 'k', MDB_OPT_UINTPTR, &key, NULL) != argc) 1122 return (DCMD_USAGE); 1123 1124 if (!(flags & DCMD_ADDRSPEC) || key == 0) 1125 return (DCMD_USAGE); 1126 1127 if (tid2ulwp_impl(addr, &ulwp_addr) != DCMD_OK) 1128 return (DCMD_ERR); 1129 1130 if (mdb_ctf_vread(&u, "ulwp_t", "mdb_libc_ulwp_t", ulwp_addr, 0) == -1) 1131 return (DCMD_ERR); 1132 1133 if (key < TSD_NFAST) { 1134 element = u.ul_ftsd[key]; 1135 } else if (u.ul_stsd != NULL) { 1136 uint_t nalloc; 1137 /* tsd_t is a union, so we can't use ctf_vread() on it. */ 1138 if (mdb_vread(&nalloc, sizeof (nalloc), 1139 (uintptr_t)&u.ul_stsd->tsd_nalloc) == -1) { 1140 mdb_warn("failed to read tsd_t at %p", u.ul_stsd); 1141 return (DCMD_ERR); 1142 } 1143 if (key < nalloc) { 1144 if (mdb_vread(&element, sizeof (element), 1145 (uintptr_t)&u.ul_stsd->tsd_data[key]) == -1) { 1146 mdb_warn("failed to read tsd_t at %p", 1147 u.ul_stsd); 1148 return (DCMD_ERR); 1149 } 1150 } 1151 } 1152 1153 if (element == NULL && (flags & DCMD_PIPE)) 1154 return (DCMD_OK); 1155 1156 mdb_printf("%p\n", element); 1157 return (DCMD_OK); 1158 } 1159 1160 /* 1161 * Print percent from 16-bit binary fraction [0 .. 1] 1162 * Round up .01 to .1 to indicate some small percentage (the 0x7000 below). 1163 * 1164 * Note: This routine was copied from elfdump/common/corenote.c and modified. 1165 * 1166 */ 1167 static uint_t 1168 pct_value(ushort_t pct) 1169 { 1170 uint_t value = pct; 1171 1172 value = ((value * 1000) + 0x7000) >> 15; /* [0 .. 1000] */ 1173 if (value >= 1000) 1174 value = 999; 1175 1176 return (value); 1177 } 1178 1179 static void 1180 psinfo_raw(psinfo_t psinfo) 1181 { 1182 const int minspaces = 2; 1183 const int spbcols = 20; 1184 char sysname[SYS2STR_MAX]; 1185 uint_t cpu, mem; 1186 char buff[32]; 1187 int bufflen; 1188 1189 mdb_printf("[ NT_PRPSINFO ]\n"); 1190 1191 mdb_printf("\tpr_state: %d\t\t\tpr_sname: %c\n", 1192 psinfo.pr_lwp.pr_state, psinfo.pr_lwp.pr_sname); 1193 1194 mdb_printf("\tpr_zomb: %d\t\t\tpr_nice: %d\n", 1195 psinfo.pr_nzomb, psinfo.pr_lwp.pr_nice); 1196 1197 mdb_printf("\tpr_uid: %u\t\t\tpr_gid: %u\n", 1198 psinfo.pr_uid, psinfo.pr_gid); 1199 1200 mdb_snprintf(buff, sizeof (buff), 1201 "%d", psinfo.pr_pid); 1202 1203 bufflen = strlen(buff); 1204 mdb_printf("\tpr_pid: %s%*spr_ppid: %d\n", 1205 buff, strlen(buff) > spbcols ? minspaces : (spbcols - bufflen), " ", 1206 psinfo.pr_ppid); 1207 1208 mdb_printf("\tpr_pgid: %u\t\t\tpr_sid: %d\n", 1209 psinfo.pr_gid, psinfo.pr_sid); 1210 1211 mdb_snprintf(buff, sizeof (buff), 1212 "0x%lx", (ulong_t)psinfo.pr_addr); 1213 1214 bufflen = strlen(buff); 1215 1216 mdb_printf("\tpr_addr: %s%*spr_size: %#x\n", 1217 buff, strlen(buff) > spbcols ? minspaces : (spbcols - bufflen), " ", 1218 (ulong_t)psinfo.pr_size); 1219 1220 mdb_printf("\tpr_rssize: %#lx\t\tpr_wchan: %#lx\n", 1221 (ulong_t)psinfo.pr_rssize, (ulong_t)psinfo.pr_lwp.pr_wchan); 1222 1223 mdb_printf("\tpr_start:\n\t tv_sec: %ld\t\ttv_nsec: %ld\n", 1224 psinfo.pr_start.tv_sec, psinfo.pr_start.tv_nsec); 1225 1226 mdb_printf("\tpr_time:\n\t tv_sec: %ld\t\t\ttv_nsec: %ld\n", 1227 psinfo.pr_time.tv_sec, psinfo.pr_time.tv_nsec); 1228 1229 mdb_printf("\tpr_pri: %d\t\t\tpr_oldpri: %d\n", 1230 psinfo.pr_lwp.pr_pri, psinfo.pr_lwp.pr_oldpri); 1231 1232 mdb_printf("\tpr_cpu: %d\n", psinfo.pr_lwp.pr_cpu); 1233 1234 mdb_printf("\tpr_clname: %s\n", psinfo.pr_lwp.pr_clname); 1235 1236 mdb_printf("\tpr_fname: %s\n", psinfo.pr_fname); 1237 1238 mdb_printf("\tpr_psargs: %s\n", psinfo.pr_psargs); 1239 1240 1241 mdb_printf("\tpr_syscall: [ %s ]\n", 1242 proc_sysname(psinfo.pr_lwp.pr_syscall, sysname, 1243 sizeof (sysname))); 1244 1245 mdb_printf("\tpr_ctime:\n\t tv_sec: %ld\t\t\ttv_nsec: %ld\n", 1246 psinfo.pr_ctime.tv_sec, psinfo.pr_ctime.tv_nsec); 1247 1248 mdb_printf("\tpr_argc: %d\t\t\tpr_argv: 0x%lx\n", 1249 psinfo.pr_argc, (ulong_t)psinfo.pr_argv); 1250 1251 mdb_snprintf(buff, sizeof (buff), "0x%lx", (ulong_t)psinfo.pr_envp); 1252 1253 bufflen = strlen(buff); 1254 1255 mdb_printf("\tpr_envp: %s%*spr_wstat: %d\n", 1256 buff, strlen(buff) > spbcols ? minspaces : (spbcols - bufflen), " ", 1257 psinfo.pr_wstat); 1258 1259 cpu = pct_value(psinfo.pr_pctcpu); 1260 mem = pct_value(psinfo.pr_pctmem); 1261 1262 mdb_printf("\tpr_pctcpu: %u.%u%%\t\tpr_pctmem: %u.%u%%\n", 1263 cpu / 10, cpu % 10, mem / 10, mem % 10); 1264 1265 mdb_printf("\tpr_euid: %u\t\t\tpr_egid: %u\n", 1266 psinfo.pr_euid, psinfo.pr_egid); 1267 1268 mdb_printf("\tpr_dmodel: [%s]\n", 1269 proc_dmodelname(psinfo.pr_dmodel, buff, sizeof (buff))); 1270 } 1271 1272 static void 1273 psinfo_sum(psinfo_t psinfo) 1274 { 1275 const int minspaces = 2; 1276 const int spbcols = 23; 1277 char buff[64]; 1278 int bufflen; 1279 int ms; 1280 1281 mdb_printf("PID: %6d (process id)\t\t" 1282 "UID: %4u (real user id)\n", 1283 psinfo.pr_pid, psinfo.pr_uid); 1284 1285 mdb_printf("PPID: %6d (parent process id)\tEUID: %4d" 1286 " (effective user id)\n", psinfo.pr_ppid, psinfo.pr_euid); 1287 1288 mdb_printf("PGID: %6d (process group id)\tGID: %4u" 1289 " (real group id)\n", psinfo.pr_pgid, psinfo.pr_gid); 1290 1291 mdb_printf("SID: %6d (session id)\t\tEGID: %4u" 1292 " (effective group id)\n", 1293 psinfo.pr_sid, psinfo.pr_egid); 1294 1295 mdb_printf("ZONEID: %6d\t\t\t\tCONTRACT:%4d\n", 1296 psinfo.pr_zoneid, psinfo.pr_contract); 1297 1298 mdb_printf("PROJECT:%6d \t\t\t\tTASK: %4d\n\n", 1299 psinfo.pr_projid, psinfo.pr_taskid); 1300 1301 mdb_printf("START: %Y (wall timestamp when the process started)\n", 1302 psinfo.pr_start); 1303 1304 ms = NSEC2MSEC(psinfo.pr_time.tv_nsec); 1305 1306 mdb_snprintf(buff, sizeof (buff), "%ld.%d seconds", 1307 psinfo.pr_time.tv_sec, ms); 1308 1309 bufflen = strlen(buff); 1310 1311 mdb_printf("TIME: %s%*s" 1312 "(CPU time used by this process)\n", 1313 buff, bufflen > spbcols ? minspaces : (spbcols - bufflen), " "); 1314 1315 ms = NSEC2MSEC(psinfo.pr_ctime.tv_nsec); 1316 1317 mdb_snprintf(buff, sizeof (buff), "%ld.%d seconds", 1318 psinfo.pr_ctime.tv_sec, ms); 1319 1320 mdb_printf("CTIME: %s%*s" 1321 "(CPU time used by child processes)\n", 1322 buff, bufflen > spbcols ? minspaces : (spbcols - bufflen), " "); 1323 1324 mdb_snprintf(buff, sizeof (buff), "%s", psinfo.pr_fname); 1325 bufflen = strlen(buff); 1326 1327 mdb_printf("FNAME: %s%*s(name of the program executed)\n", 1328 buff, bufflen > spbcols ? minspaces : (spbcols - bufflen), " "); 1329 1330 mdb_printf("PSARGS: \"%s\"\n", psinfo.pr_psargs); 1331 } 1332 1333 void 1334 d_psinfo_dcmd_help(void) 1335 { 1336 mdb_printf( 1337 "Prints relevant fields from psinfo_t data and\n" 1338 "most fields from NT_PRPSINFO note section\n\n" 1339 "Usage: ::psinfo [-v]\n" 1340 "Options:\n" 1341 " -v verbose output\n"); 1342 } 1343 1344 static int 1345 d_psinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1346 { 1347 psinfo_t psinfo; 1348 uint_t opt_v = FALSE; 1349 ssize_t nbytes; 1350 1351 if (mdb_getopts(argc, argv, 'v', 1352 MDB_OPT_SETBITS, TRUE, &opt_v, NULL) != argc) 1353 return (DCMD_USAGE); 1354 1355 nbytes = mdb_get_xdata("psinfo", NULL, 0); 1356 1357 if (nbytes <= 0) { 1358 mdb_warn("information not available for analysis"); 1359 return (DCMD_ERR); 1360 } 1361 1362 if (mdb_get_xdata("psinfo", &psinfo, nbytes) != nbytes) { 1363 mdb_warn("failed to read psinfo information"); 1364 return (DCMD_ERR); 1365 } 1366 1367 if (opt_v) { 1368 psinfo_raw(psinfo); 1369 } else { 1370 psinfo_sum(psinfo); 1371 } 1372 1373 return (DCMD_OK); 1374 } 1375 1376 static int 1377 d_errno(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1378 { 1379 mdb_libc_ulwp_t u; 1380 uintptr_t ulwp_addr; 1381 int error, errval; 1382 1383 if (argc != 0 || (flags & DCMD_ADDRSPEC) == 0) 1384 return (DCMD_USAGE); 1385 1386 error = tid2ulwp_impl(addr, &ulwp_addr); 1387 if (error != DCMD_OK) 1388 return (error); 1389 1390 /* 1391 * For historical compatibility, thread 1's errno value is stored in 1392 * a libc global variable 'errno', while each additional thread's 1393 * errno value is stored in ulwp_t->ul_errno. In addition, 1394 * ulwp_t->ul_errnop is set to the address of the thread's errno value, 1395 * (i.e. for tid 1, curthead->ul_errnop = &errno, for tid > 1, 1396 * curthread->ul_errnop = &curthread->ul_errno). 1397 * 1398 * Since errno itself uses *curthread->ul_errnop (see ___errno()) to 1399 * return the thread's current errno value, we do the same. 1400 */ 1401 if (mdb_ctf_vread(&u, "ulwp_t", "mdb_libc_ulwp_t", ulwp_addr, 0) == -1) 1402 return (DCMD_ERR); 1403 1404 if (mdb_vread(&errval, sizeof (errval), (uintptr_t)u.ul_errnop) == -1) { 1405 mdb_warn("cannot read error value at 0x%p", u.ul_errnop); 1406 return (DCMD_ERR); 1407 } 1408 1409 mdb_printf("%d\n", errval); 1410 return (DCMD_OK); 1411 } 1412 1413 static const mdb_dcmd_t dcmds[] = { 1414 { "errno", "?", "print errno of a given TID", d_errno, NULL }, 1415 { "jmp_buf", ":", "print jmp_buf contents", d_jmp_buf, NULL }, 1416 { "sigjmp_buf", ":", "print sigjmp_buf contents", d_sigjmp_buf, NULL }, 1417 { "siginfo", ":", "print siginfo_t structure", d_siginfo, NULL }, 1418 { "stacks", "?[-afiv] [-c func] [-C func] [-m module] [-M module] ", 1419 "print unique thread stacks", stacks_dcmd, stacks_help }, 1420 { "tid2ulwp", "?", "convert TID to ulwp_t address", tid2ulwp }, 1421 { "ucontext", ":", "print ucontext_t structure", d_ucontext, NULL }, 1422 { "ulwp", ":", "print ulwp_t structure", d_ulwp, NULL }, 1423 { "uberdata", ":", "print uberdata_t structure", d_uberdata, NULL }, 1424 { "tsd", ":-k key", "print tsd for this thread", d_tsd, NULL }, 1425 { "psinfo", "[-v]", "prints relevant psinfo_t data", d_psinfo, 1426 d_psinfo_dcmd_help }, 1427 { NULL } 1428 }; 1429 1430 static const mdb_walker_t walkers[] = { 1431 { "ucontext", "walk ucontext_t uc_link list", 1432 NULL, uc_walk_step, NULL, NULL }, 1433 { "oldcontext", "walk per-lwp oldcontext pointers", 1434 oldc_walk_init, oldc_walk_step, oldc_walk_fini, NULL }, 1435 { "ulwps", "walk list of ulwp_t pointers", 1436 ulwp_walk_init, ulwp_walk_step, NULL, NULL }, 1437 { "ulwp", "walk list of ulwp_t pointers", 1438 ulwp_walk_init, ulwp_walk_step, NULL, NULL }, 1439 { NULL } 1440 }; 1441 1442 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers }; 1443 1444 const mdb_modinfo_t * 1445 _mdb_init(void) 1446 { 1447 mdb_whatis_register("threads", whatis_run_ulwps, NULL, 1448 WHATIS_PRIO_EARLY, WHATIS_REG_NO_ID); 1449 1450 return (&modinfo); 1451 } 1452