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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25 /*
26 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
27 */
28
29
30 #include <mdb/mdb_modapi.h>
31 #include <mdb/mdb_ks.h>
32 #include <sys/types.h>
33 #include <sys/thread.h>
34 #include <sys/lwp.h>
35 #include <sys/proc.h>
36 #include <sys/cpuvar.h>
37 #include <sys/cpupart.h>
38 #include <sys/disp.h>
39 #include <sys/taskq_impl.h>
40 #include <sys/stack.h>
41
42 #ifndef STACK_BIAS
43 #define STACK_BIAS 0
44 #endif
45
46 typedef struct thread_walk {
47 kthread_t *tw_thread;
48 uintptr_t tw_last;
49 uint_t tw_inproc;
50 uint_t tw_step;
51 } thread_walk_t;
52
53 int
54 thread_walk_init(mdb_walk_state_t *wsp)
55 {
56 thread_walk_t *twp = mdb_alloc(sizeof (thread_walk_t), UM_SLEEP);
57
58 if (wsp->walk_addr == NULL) {
59 if (mdb_readvar(&wsp->walk_addr, "allthreads") == -1) {
60 mdb_warn("failed to read 'allthreads'");
544 }
545
546 void
547 thread_help(void)
548 {
549 mdb_printf(
550 "The flags -ipbsd control which information is displayed. When\n"
551 "combined, the fields are displayed on separate lines unless the\n"
552 "-m option is given.\n"
553 "\n"
554 "\t-b\tprint blocked thread state\n"
555 "\t-d\tprint dispatcher state\n"
556 "\t-f\tignore freed threads\n"
557 "\t-i\tprint basic thread state (default)\n"
558 "\t-m\tdisplay results on a single line\n"
559 "\t-p\tprint process and lwp state\n"
560 "\t-s\tprint signal state\n");
561 }
562
563 /*
564 * List a combination of kthread_t and proc_t. Add stack traces in verbose mode.
565 */
566 int
567 threadlist(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
568 {
569 int i;
570 uint_t count = 0;
571 uint_t verbose = FALSE;
572 uint_t notaskq = FALSE;
573 kthread_t t;
574 taskq_t tq;
575 proc_t p;
576 char cmd[80];
577 mdb_arg_t cmdarg;
578
579 if (!(flags & DCMD_ADDRSPEC)) {
580 if (mdb_walk_dcmd("thread", "threadlist", argc, argv) == -1) {
581 mdb_warn("can't walk threads");
582 return (DCMD_ERR);
583 }
584 return (DCMD_OK);
585 }
586
587 i = mdb_getopts(argc, argv,
588 't', MDB_OPT_SETBITS, TRUE, ¬askq,
589 'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL);
590
591 if (i != argc) {
592 if (i != argc - 1 || !verbose)
593 return (DCMD_USAGE);
594
595 if (argv[i].a_type == MDB_TYPE_IMMEDIATE)
601 if (DCMD_HDRSPEC(flags)) {
602 if (verbose)
603 mdb_printf("%<u>%?s %?s %?s %3s %3s %?s%</u>\n",
604 "ADDR", "PROC", "LWP", "CLS", "PRI", "WCHAN");
605 else
606 mdb_printf("%<u>%?s %?s %?s %s/%s%</u>\n",
607 "ADDR", "PROC", "LWP", "CMD", "LWPID");
608 }
609
610 if (mdb_vread(&t, sizeof (kthread_t), addr) == -1) {
611 mdb_warn("failed to read kthread_t at %p", addr);
612 return (DCMD_ERR);
613 }
614
615 if (notaskq && t.t_taskq != NULL)
616 return (DCMD_OK);
617
618 if (t.t_state == TS_FREE)
619 return (DCMD_OK);
620
621 if (mdb_vread(&p, sizeof (proc_t), (uintptr_t)t.t_procp) == -1) {
622 mdb_warn("failed to read proc at %p", t.t_procp);
623 return (DCMD_ERR);
624 }
625
626 if (mdb_vread(&tq, sizeof (taskq_t), (uintptr_t)t.t_taskq) == -1)
627 tq.tq_name[0] = '\0';
628
629 if (verbose) {
630 mdb_printf("%0?p %?p %?p %3u %3d %?p\n",
631 addr, t.t_procp, t.t_lwp, t.t_cid, t.t_pri, t.t_wchan);
632
633 mdb_inc_indent(2);
634
635 mdb_printf("PC: %a", t.t_pc);
636 if (t.t_tid == 0) {
637 if (tq.tq_name[0] != '\0')
638 mdb_printf(" TASKQ: %s\n", tq.tq_name);
639 else
640 mdb_printf(" THREAD: %a()\n", t.t_startpc);
641 } else {
642 mdb_printf(" CMD: %s\n", p.p_user.u_psargs);
643 }
644
645 mdb_snprintf(cmd, sizeof (cmd), "<.$c%d", count);
646 cmdarg.a_type = MDB_TYPE_STRING;
647 cmdarg.a_un.a_str = cmd;
648
649 (void) mdb_call_dcmd("findstack", addr, flags, 1, &cmdarg);
650
651 mdb_dec_indent(2);
652
653 mdb_printf("\n");
654 } else {
655 mdb_printf("%0?p %?p %?p", addr, t.t_procp, t.t_lwp);
656 if (t.t_tid == 0) {
657 if (tq.tq_name[0] != '\0')
658 mdb_printf(" tq:%s\n", tq.tq_name);
659 else
660 mdb_printf(" %a()\n", t.t_startpc);
661 } else {
662 mdb_printf(" %s/%u\n", p.p_user.u_comm, t.t_tid);
663 }
664 }
665
666 return (DCMD_OK);
667 }
668
669 void
670 threadlist_help(void)
671 {
672 mdb_printf(
673 " -v print verbose output including C stack trace\n"
674 " -t skip threads belonging to a taskq\n"
675 " count print no more than count arguments (default 0)\n");
676 }
677
678 static size_t
679 stk_compute_percent(caddr_t t_stk, caddr_t t_stkbase, caddr_t sp)
680 {
681 size_t percent;
682 size_t s;
683
684 if (t_stk > t_stkbase) {
699 if (sp > t_stkbase) {
700 return (100);
701 }
702 percent = sp - t_stk + 1;
703 s = t_stkbase - t_stk + 1;
704 }
705 percent = ((100 * percent) / s) + 1;
706 if (percent > 100) {
707 percent = 100;
708 }
709 return (percent);
710 }
711
712 /*
713 * Display kthread stack infos.
714 */
715 int
716 stackinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
717 {
718 kthread_t t;
719 proc_t p;
720 uint64_t *ptr; /* pattern pointer */
721 caddr_t start; /* kernel stack start */
722 caddr_t end; /* kernel stack end */
723 caddr_t ustack; /* userland copy of kernel stack */
724 size_t usize; /* userland copy of kernel stack size */
725 caddr_t ustart; /* userland copy of kernel stack, aligned start */
726 caddr_t uend; /* userland copy of kernel stack, aligned end */
727 size_t percent = 0;
728 uint_t all = FALSE; /* don't show TS_FREE kthread by default */
729 uint_t history = FALSE;
730 int i = 0;
731 unsigned int ukmem_stackinfo;
732 uintptr_t allthreads;
733
734 /* handle options */
735 if (mdb_getopts(argc, argv,
736 'a', MDB_OPT_SETBITS, TRUE, &all,
737 'h', MDB_OPT_SETBITS, TRUE, &history, NULL) != argc) {
738 return (DCMD_USAGE);
739 }
740
741 /* walk all kthread if needed */
742 if ((history == FALSE) && !(flags & DCMD_ADDRSPEC)) {
743 if (mdb_walk_dcmd("thread", "stackinfo", argc, argv) == -1) {
744 mdb_warn("can't walk threads");
745 return (DCMD_ERR);
746 }
747 return (DCMD_OK);
748 }
749
750 /* read 'kmem_stackinfo' */
751 if (mdb_readsym(&ukmem_stackinfo, sizeof (ukmem_stackinfo),
752 "kmem_stackinfo") == -1) {
758 if (mdb_readsym(&allthreads, sizeof (kthread_t *),
759 "allthreads") == -1) {
760 mdb_warn("failed to read 'allthreads'\n");
761 allthreads = NULL;
762 }
763
764 if (history == TRUE) {
765 kmem_stkinfo_t *log;
766 uintptr_t kaddr;
767
768 mdb_printf("Dead kthreads stack usage history:\n");
769 if (ukmem_stackinfo == 0) {
770 mdb_printf("Tunable kmem_stackinfo is unset, history ");
771 mdb_printf("feature is off.\nUse ::help stackinfo ");
772 mdb_printf("for more details.\n");
773 return (DCMD_OK);
774 }
775
776 mdb_printf("%<u>%?s%</u>", "THREAD");
777 mdb_printf(" %<u>%?s%</u>", "STACK");
778 mdb_printf("%<u>%s%</u>", " SIZE MAX CMD/LWPID or STARTPC");
779 mdb_printf("\n");
780 usize = KMEM_STKINFO_LOG_SIZE * sizeof (kmem_stkinfo_t);
781 log = (kmem_stkinfo_t *)mdb_alloc(usize, UM_SLEEP);
782 if (mdb_readsym(&kaddr, sizeof (kaddr),
783 "kmem_stkinfo_log") == -1) {
784 mdb_free((void *)log, usize);
785 mdb_warn("failed to read 'kmem_stkinfo_log'\n");
786 return (DCMD_ERR);
787 }
788 if (kaddr == NULL) {
789 mdb_free((void *)log, usize);
790 return (DCMD_OK);
791 }
792 if (mdb_vread(log, usize, kaddr) == -1) {
793 mdb_free((void *)log, usize);
794 mdb_warn("failed to read %p\n", kaddr);
795 return (DCMD_ERR);
796 }
797 for (i = 0; i < KMEM_STKINFO_LOG_SIZE; i++) {
798 if (log[i].kthread == NULL) {
799 continue;
800 }
801 mdb_printf("%0?p %0?p %6x %3d%%",
802 log[i].kthread,
803 log[i].start,
804 (uint_t)log[i].stksz,
805 (int)log[i].percent);
806 if (log[i].t_tid != 0) {
807 mdb_printf(" %s/%u\n",
808 log[i].cmd, log[i].t_tid);
809 } else {
810 mdb_printf(" %p (%a)\n", log[i].t_startpc,
811 log[i].t_startpc);
812 }
813 }
814 mdb_free((void *)log, usize);
815 return (DCMD_OK);
816 }
817
818 /* display header */
819 if (DCMD_HDRSPEC(flags)) {
820 if (ukmem_stackinfo == 0) {
821 mdb_printf("Tunable kmem_stackinfo is unset, ");
822 mdb_printf("MAX value is not available.\n");
823 mdb_printf("Use ::help stackinfo for more details.\n");
824 }
825 mdb_printf("%<u>%?s%</u>", "THREAD");
826 mdb_printf(" %<u>%?s%</u>", "STACK");
827 mdb_printf("%<u>%s%</u>", " SIZE CUR MAX CMD/LWPID");
828 mdb_printf("\n");
829 }
830
831 /* read kthread */
832 if (mdb_vread(&t, sizeof (kthread_t), addr) == -1) {
833 mdb_warn("can't read kthread_t at %#lx\n", addr);
834 return (DCMD_ERR);
835 }
836
837 if (t.t_state == TS_FREE && all == FALSE) {
838 return (DCMD_OK);
839 }
840
841 /* read proc */
842 if (mdb_vread(&p, sizeof (proc_t), (uintptr_t)t.t_procp) == -1) {
843 mdb_warn("failed to read proc at %p\n", t.t_procp);
844 return (DCMD_ERR);
845 }
846
847 /*
848 * Stack grows up or down, see thread_create(),
849 * compute stack memory aera start and end (start < end).
850 */
851 if (t.t_stk > t.t_stkbase) {
852 /* stack grows down */
853 start = t.t_stkbase;
854 end = t.t_stk;
855 } else {
856 /* stack grows up */
857 start = t.t_stk;
858 end = t.t_stkbase;
859 }
860
861 /* display stack info */
862 mdb_printf("%0?p %0?p", addr, start);
863
864 /* (end - start), kernel stack size as found in kthread_t */
865 if ((end <= start) || ((end - start) > (1024 * 1024))) {
866 /* negative or stack size > 1 meg, assume bogus */
867 mdb_warn(" t_stk/t_stkbase problem\n");
868 return (DCMD_ERR);
869 }
870
871 /* display stack size */
872 mdb_printf(" %6x", end - start);
873
874 /* display current stack usage */
875 percent = stk_compute_percent(t.t_stk, t.t_stkbase,
876 (caddr_t)t.t_sp + STACK_BIAS);
877
878 mdb_printf(" %3d%%", percent);
879 percent = 0;
880
881 if (ukmem_stackinfo == 0) {
882 mdb_printf(" n/a");
883 if (t.t_tid == 0) {
884 mdb_printf(" %a()", t.t_startpc);
885 } else {
886 mdb_printf(" %s/%u", p.p_user.u_comm, t.t_tid);
887 }
888 mdb_printf("\n");
889 return (DCMD_OK);
890 }
891
892 if ((((uintptr_t)start) & 0x7) != 0) {
893 start = (caddr_t)((((uintptr_t)start) & (~0x7)) + 8);
894 }
895 end = (caddr_t)(((uintptr_t)end) & (~0x7));
896 /* size to scan in userland copy of kernel stack */
897 usize = end - start; /* is a multiple of 8 bytes */
898
899 /*
900 * Stackinfo pattern size is 8 bytes. Ensure proper 8 bytes
901 * alignement for ustart and uend, in boundaries.
902 */
903 ustart = ustack = (caddr_t)mdb_alloc(usize + 8, UM_SLEEP);
904 if ((((uintptr_t)ustart) & 0x7) != 0) {
905 ustart = (caddr_t)((((uintptr_t)ustart) & (~0x7)) + 8);
906 }
907 uend = ustart + usize;
908
941 ptr--;
942 while (ptr >= (uint64_t *)((void *)ustart)) {
943 if (*ptr != KMEM_STKINFO_PATTERN) {
944 percent = stk_compute_percent(ustart,
945 uend, (caddr_t)ptr);
946 break;
947 }
948 ptr--;
949 }
950 }
951
952 /* thread 't0' stack is not created by thread_create() */
953 if (addr == allthreads) {
954 percent = 0;
955 }
956 if (percent != 0) {
957 mdb_printf(" %3d%%", percent);
958 } else {
959 mdb_printf(" n/a");
960 }
961 if (t.t_tid == 0) {
962 mdb_printf(" %a()", t.t_startpc);
963 } else {
964 mdb_printf(" %s/%u", p.p_user.u_comm, t.t_tid);
965 }
966 mdb_printf("\n");
967 mdb_free((void *)ustack, usize + 8);
968 return (DCMD_OK);
969 }
970
971 void
972 stackinfo_help(void)
973 {
974 mdb_printf(
975 "Shows kernel stacks real utilization, if /etc/system "
976 "kmem_stackinfo tunable\n");
977 mdb_printf(
978 "(an unsigned integer) is non zero at kthread creation time. ");
979 mdb_printf("For example:\n");
980 mdb_printf(
981 " THREAD STACK SIZE CUR MAX CMD/LWPID\n");
982 mdb_printf(
983 "ffffff014f5f2c20 ffffff0004153000 4f00 4%% 43%% init/1\n");
984 mdb_printf(
985 "The stack size utilization for this kthread is at 4%%"
986 " of its maximum size,\n");
987 mdb_printf(
988 "but has already used up to 43%%, stack size is 4f00 bytes.\n");
989 mdb_printf(
990 "MAX value can be shown as n/a (not available):\n");
991 mdb_printf(
992 " - for the very first kthread (sched/1)\n");
993 mdb_printf(
994 " - kmem_stackinfo was zero at kthread creation time\n");
995 mdb_printf(
996 " - kthread has not yet run\n");
997 mdb_printf("\n");
998 mdb_printf("Options:\n");
999 mdb_printf(
1000 "-a shows also TS_FREE kthreads (interrupt kthreads)\n");
1001 mdb_printf(
1002 "-h shows history, dead kthreads that used their "
1003 "kernel stack the most\n");
1004 mdb_printf(
1005 "\nSee Solaris Modular Debugger Guide for detailed usage.\n");
1006 mdb_flush();
1007 }
|
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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25 /*
26 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
27 * Copyright (c) 2018, Joyent, Inc.
28 */
29
30
31 #include <mdb/mdb_modapi.h>
32 #include <mdb/mdb_ks.h>
33 #include <mdb/mdb_ctf.h>
34 #include <sys/types.h>
35 #include <sys/thread.h>
36 #include <sys/lwp.h>
37 #include <sys/proc.h>
38 #include <sys/cpuvar.h>
39 #include <sys/cpupart.h>
40 #include <sys/disp.h>
41 #include <sys/taskq_impl.h>
42 #include <sys/stack.h>
43 #include "thread.h"
44
45 #ifndef STACK_BIAS
46 #define STACK_BIAS 0
47 #endif
48
49 typedef struct thread_walk {
50 kthread_t *tw_thread;
51 uintptr_t tw_last;
52 uint_t tw_inproc;
53 uint_t tw_step;
54 } thread_walk_t;
55
56 int
57 thread_walk_init(mdb_walk_state_t *wsp)
58 {
59 thread_walk_t *twp = mdb_alloc(sizeof (thread_walk_t), UM_SLEEP);
60
61 if (wsp->walk_addr == NULL) {
62 if (mdb_readvar(&wsp->walk_addr, "allthreads") == -1) {
63 mdb_warn("failed to read 'allthreads'");
547 }
548
549 void
550 thread_help(void)
551 {
552 mdb_printf(
553 "The flags -ipbsd control which information is displayed. When\n"
554 "combined, the fields are displayed on separate lines unless the\n"
555 "-m option is given.\n"
556 "\n"
557 "\t-b\tprint blocked thread state\n"
558 "\t-d\tprint dispatcher state\n"
559 "\t-f\tignore freed threads\n"
560 "\t-i\tprint basic thread state (default)\n"
561 "\t-m\tdisplay results on a single line\n"
562 "\t-p\tprint process and lwp state\n"
563 "\t-s\tprint signal state\n");
564 }
565
566 /*
567 * Return a string description of the thread, including the ID and the thread
568 * name.
569 *
570 * If ->t_name is NULL, and we're a system thread, we'll do a little more
571 * spelunking to find a useful string to return.
572 */
573 int
574 thread_getdesc(uintptr_t addr, boolean_t include_comm,
575 char *buf, size_t bufsize)
576 {
577 char name[THREAD_NAME_MAX] = "";
578 kthread_t t;
579 proc_t p;
580
581 bzero(buf, bufsize);
582
583 if (mdb_vread(&t, sizeof (kthread_t), addr) == -1) {
584 mdb_warn("failed to read kthread_t at %p", addr);
585 return (-1);
586 }
587
588 if (t.t_tid == 0) {
589 taskq_t tq;
590
591 if (mdb_vread(&tq, sizeof (taskq_t),
592 (uintptr_t)t.t_taskq) == -1)
593 tq.tq_name[0] = '\0';
594
595 if (t.t_name != NULL) {
596 if (mdb_readstr(buf, bufsize,
597 (uintptr_t)t.t_name) == -1) {
598 mdb_warn("error reading thread name");
599 }
600 } else if (tq.tq_name[0] != '\0') {
601 (void) mdb_snprintf(buf, bufsize, "tq:%s", tq.tq_name);
602 } else {
603 mdb_snprintf(buf, bufsize, "%a()", t.t_startpc);
604 }
605
606 return (buf[0] == '\0' ? -1 : 0);
607 }
608
609 if (include_comm && mdb_vread(&p, sizeof (proc_t),
610 (uintptr_t)t.t_procp) == -1) {
611 mdb_warn("failed to read proc at %p", t.t_procp);
612 return (-1);
613 }
614
615 if (t.t_name != NULL) {
616 if (mdb_readstr(name, sizeof (name), (uintptr_t)t.t_name) == -1)
617 mdb_warn("error reading thread name");
618
619 /*
620 * Just to be safe -- if mdb_readstr() succeeds, it always NUL
621 * terminates the output, but is unclear what it does on
622 * failure. In that case we attempt to show any partial content
623 * w/ the warning in case it's useful, but explicitly
624 * NUL-terminate to be safe.
625 */
626 buf[bufsize - 1] = '\0';
627 }
628
629 if (name[0] != '\0') {
630 if (include_comm) {
631 (void) mdb_snprintf(buf, bufsize, "%s/%u [%s]",
632 p.p_user.u_comm, t.t_tid, name);
633 } else {
634 (void) mdb_snprintf(buf, bufsize, "%u [%s]",
635 t.t_tid, name);
636 }
637 } else {
638 if (include_comm) {
639 (void) mdb_snprintf(buf, bufsize, "%s/%u",
640 p.p_user.u_comm, t.t_tid);
641 } else {
642 (void) mdb_snprintf(buf, bufsize, "%u", t.t_tid);
643 }
644 }
645
646 return (buf[0] == '\0' ? -1 : 0);
647 }
648
649 /*
650 * List a combination of kthread_t and proc_t. Add stack traces in verbose mode.
651 */
652 int
653 threadlist(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
654 {
655 int i;
656 uint_t count = 0;
657 uint_t verbose = FALSE;
658 uint_t notaskq = FALSE;
659 kthread_t t;
660 char cmd[80];
661 mdb_arg_t cmdarg;
662
663 if (!(flags & DCMD_ADDRSPEC)) {
664 if (mdb_walk_dcmd("thread", "threadlist", argc, argv) == -1) {
665 mdb_warn("can't walk threads");
666 return (DCMD_ERR);
667 }
668 return (DCMD_OK);
669 }
670
671 i = mdb_getopts(argc, argv,
672 't', MDB_OPT_SETBITS, TRUE, ¬askq,
673 'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL);
674
675 if (i != argc) {
676 if (i != argc - 1 || !verbose)
677 return (DCMD_USAGE);
678
679 if (argv[i].a_type == MDB_TYPE_IMMEDIATE)
685 if (DCMD_HDRSPEC(flags)) {
686 if (verbose)
687 mdb_printf("%<u>%?s %?s %?s %3s %3s %?s%</u>\n",
688 "ADDR", "PROC", "LWP", "CLS", "PRI", "WCHAN");
689 else
690 mdb_printf("%<u>%?s %?s %?s %s/%s%</u>\n",
691 "ADDR", "PROC", "LWP", "CMD", "LWPID");
692 }
693
694 if (mdb_vread(&t, sizeof (kthread_t), addr) == -1) {
695 mdb_warn("failed to read kthread_t at %p", addr);
696 return (DCMD_ERR);
697 }
698
699 if (notaskq && t.t_taskq != NULL)
700 return (DCMD_OK);
701
702 if (t.t_state == TS_FREE)
703 return (DCMD_OK);
704
705 if (!verbose) {
706 char desc[128];
707
708 if (thread_getdesc(addr, B_TRUE, desc, sizeof (desc)) == -1)
709 return (DCMD_ERR);
710
711 mdb_printf("%0?p %?p %?p %s\n", addr, t.t_procp, t.t_lwp, desc);
712 return (DCMD_OK);
713 }
714
715 mdb_printf("%0?p %?p %?p %3u %3d %?p\n",
716 addr, t.t_procp, t.t_lwp, t.t_cid, t.t_pri, t.t_wchan);
717
718 mdb_inc_indent(2);
719
720 mdb_printf("PC: %a\n", t.t_pc);
721
722 mdb_snprintf(cmd, sizeof (cmd), "<.$c%d", count);
723 cmdarg.a_type = MDB_TYPE_STRING;
724 cmdarg.a_un.a_str = cmd;
725
726 (void) mdb_call_dcmd("findstack", addr, flags, 1, &cmdarg);
727
728 mdb_dec_indent(2);
729
730 mdb_printf("\n");
731
732 return (DCMD_OK);
733 }
734
735 void
736 threadlist_help(void)
737 {
738 mdb_printf(
739 " -v print verbose output including C stack trace\n"
740 " -t skip threads belonging to a taskq\n"
741 " count print no more than count arguments (default 0)\n");
742 }
743
744 static size_t
745 stk_compute_percent(caddr_t t_stk, caddr_t t_stkbase, caddr_t sp)
746 {
747 size_t percent;
748 size_t s;
749
750 if (t_stk > t_stkbase) {
765 if (sp > t_stkbase) {
766 return (100);
767 }
768 percent = sp - t_stk + 1;
769 s = t_stkbase - t_stk + 1;
770 }
771 percent = ((100 * percent) / s) + 1;
772 if (percent > 100) {
773 percent = 100;
774 }
775 return (percent);
776 }
777
778 /*
779 * Display kthread stack infos.
780 */
781 int
782 stackinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
783 {
784 kthread_t t;
785 uint64_t *ptr; /* pattern pointer */
786 caddr_t start; /* kernel stack start */
787 caddr_t end; /* kernel stack end */
788 caddr_t ustack; /* userland copy of kernel stack */
789 size_t usize; /* userland copy of kernel stack size */
790 caddr_t ustart; /* userland copy of kernel stack, aligned start */
791 caddr_t uend; /* userland copy of kernel stack, aligned end */
792 size_t percent = 0;
793 uint_t all = FALSE; /* don't show TS_FREE kthread by default */
794 uint_t history = FALSE;
795 int i = 0;
796 unsigned int ukmem_stackinfo;
797 uintptr_t allthreads;
798 char tdesc[128] = "";
799
800 /* handle options */
801 if (mdb_getopts(argc, argv,
802 'a', MDB_OPT_SETBITS, TRUE, &all,
803 'h', MDB_OPT_SETBITS, TRUE, &history, NULL) != argc) {
804 return (DCMD_USAGE);
805 }
806
807 /* walk all kthread if needed */
808 if ((history == FALSE) && !(flags & DCMD_ADDRSPEC)) {
809 if (mdb_walk_dcmd("thread", "stackinfo", argc, argv) == -1) {
810 mdb_warn("can't walk threads");
811 return (DCMD_ERR);
812 }
813 return (DCMD_OK);
814 }
815
816 /* read 'kmem_stackinfo' */
817 if (mdb_readsym(&ukmem_stackinfo, sizeof (ukmem_stackinfo),
818 "kmem_stackinfo") == -1) {
824 if (mdb_readsym(&allthreads, sizeof (kthread_t *),
825 "allthreads") == -1) {
826 mdb_warn("failed to read 'allthreads'\n");
827 allthreads = NULL;
828 }
829
830 if (history == TRUE) {
831 kmem_stkinfo_t *log;
832 uintptr_t kaddr;
833
834 mdb_printf("Dead kthreads stack usage history:\n");
835 if (ukmem_stackinfo == 0) {
836 mdb_printf("Tunable kmem_stackinfo is unset, history ");
837 mdb_printf("feature is off.\nUse ::help stackinfo ");
838 mdb_printf("for more details.\n");
839 return (DCMD_OK);
840 }
841
842 mdb_printf("%<u>%?s%</u>", "THREAD");
843 mdb_printf(" %<u>%?s%</u>", "STACK");
844 mdb_printf("%<u>%s%</u>", " SIZE MAX LWP");
845 mdb_printf("\n");
846 usize = KMEM_STKINFO_LOG_SIZE * sizeof (kmem_stkinfo_t);
847 log = (kmem_stkinfo_t *)mdb_alloc(usize, UM_SLEEP);
848 if (mdb_readsym(&kaddr, sizeof (kaddr),
849 "kmem_stkinfo_log") == -1) {
850 mdb_free((void *)log, usize);
851 mdb_warn("failed to read 'kmem_stkinfo_log'\n");
852 return (DCMD_ERR);
853 }
854 if (kaddr == NULL) {
855 mdb_free((void *)log, usize);
856 return (DCMD_OK);
857 }
858 if (mdb_vread(log, usize, kaddr) == -1) {
859 mdb_free((void *)log, usize);
860 mdb_warn("failed to read %p\n", kaddr);
861 return (DCMD_ERR);
862 }
863 for (i = 0; i < KMEM_STKINFO_LOG_SIZE; i++) {
864 if (log[i].kthread == NULL) {
865 continue;
866 }
867
868 (void) thread_getdesc((uintptr_t)log[i].kthread,
869 B_TRUE, tdesc, sizeof (tdesc));
870
871 mdb_printf("%0?p %0?p %6x %3d%% %s\n",
872 log[i].kthread,
873 log[i].start,
874 (uint_t)log[i].stksz,
875 (int)log[i].percent, tdesc);
876 }
877 mdb_free((void *)log, usize);
878 return (DCMD_OK);
879 }
880
881 /* display header */
882 if (DCMD_HDRSPEC(flags)) {
883 if (ukmem_stackinfo == 0) {
884 mdb_printf("Tunable kmem_stackinfo is unset, ");
885 mdb_printf("MAX value is not available.\n");
886 mdb_printf("Use ::help stackinfo for more details.\n");
887 }
888 mdb_printf("%<u>%?s%</u>", "THREAD");
889 mdb_printf(" %<u>%?s%</u>", "STACK");
890 mdb_printf("%<u>%s%</u>", " SIZE CUR MAX LWP");
891 mdb_printf("\n");
892 }
893
894 /* read kthread */
895 if (mdb_vread(&t, sizeof (kthread_t), addr) == -1) {
896 mdb_warn("can't read kthread_t at %#lx\n", addr);
897 return (DCMD_ERR);
898 }
899
900 if (t.t_state == TS_FREE && all == FALSE) {
901 return (DCMD_OK);
902 }
903
904 /*
905 * Stack grows up or down, see thread_create(),
906 * compute stack memory aera start and end (start < end).
907 */
908 if (t.t_stk > t.t_stkbase) {
909 /* stack grows down */
910 start = t.t_stkbase;
911 end = t.t_stk;
912 } else {
913 /* stack grows up */
914 start = t.t_stk;
915 end = t.t_stkbase;
916 }
917
918 /* display stack info */
919 mdb_printf("%0?p %0?p", addr, start);
920
921 /* (end - start), kernel stack size as found in kthread_t */
922 if ((end <= start) || ((end - start) > (1024 * 1024))) {
923 /* negative or stack size > 1 meg, assume bogus */
924 mdb_warn(" t_stk/t_stkbase problem\n");
925 return (DCMD_ERR);
926 }
927
928 /* display stack size */
929 mdb_printf(" %6x", end - start);
930
931 /* display current stack usage */
932 percent = stk_compute_percent(t.t_stk, t.t_stkbase,
933 (caddr_t)t.t_sp + STACK_BIAS);
934
935 mdb_printf(" %3d%%", percent);
936 percent = 0;
937
938 (void) thread_getdesc(addr, B_TRUE, tdesc, sizeof (tdesc));
939
940 if (ukmem_stackinfo == 0) {
941 mdb_printf(" n/a %s\n", tdesc);
942 return (DCMD_OK);
943 }
944
945 if ((((uintptr_t)start) & 0x7) != 0) {
946 start = (caddr_t)((((uintptr_t)start) & (~0x7)) + 8);
947 }
948 end = (caddr_t)(((uintptr_t)end) & (~0x7));
949 /* size to scan in userland copy of kernel stack */
950 usize = end - start; /* is a multiple of 8 bytes */
951
952 /*
953 * Stackinfo pattern size is 8 bytes. Ensure proper 8 bytes
954 * alignement for ustart and uend, in boundaries.
955 */
956 ustart = ustack = (caddr_t)mdb_alloc(usize + 8, UM_SLEEP);
957 if ((((uintptr_t)ustart) & 0x7) != 0) {
958 ustart = (caddr_t)((((uintptr_t)ustart) & (~0x7)) + 8);
959 }
960 uend = ustart + usize;
961
994 ptr--;
995 while (ptr >= (uint64_t *)((void *)ustart)) {
996 if (*ptr != KMEM_STKINFO_PATTERN) {
997 percent = stk_compute_percent(ustart,
998 uend, (caddr_t)ptr);
999 break;
1000 }
1001 ptr--;
1002 }
1003 }
1004
1005 /* thread 't0' stack is not created by thread_create() */
1006 if (addr == allthreads) {
1007 percent = 0;
1008 }
1009 if (percent != 0) {
1010 mdb_printf(" %3d%%", percent);
1011 } else {
1012 mdb_printf(" n/a");
1013 }
1014
1015 mdb_printf(" %s\n", tdesc);
1016
1017 mdb_free((void *)ustack, usize + 8);
1018 return (DCMD_OK);
1019 }
1020
1021 void
1022 stackinfo_help(void)
1023 {
1024 mdb_printf(
1025 "Shows kernel stacks real utilization, if /etc/system "
1026 "kmem_stackinfo tunable\n");
1027 mdb_printf(
1028 "(an unsigned integer) is non zero at kthread creation time. ");
1029 mdb_printf("For example:\n");
1030 mdb_printf(
1031 " THREAD STACK SIZE CUR MAX LWP\n");
1032 mdb_printf(
1033 "ffffff014f5f2c20 ffffff0004153000 4f00 4%% 43%% init/1\n");
1034 mdb_printf(
1035 "The stack size utilization for this kthread is at 4%%"
1036 " of its maximum size,\n");
1037 mdb_printf(
1038 "but has already used up to 43%%, stack size is 4f00 bytes.\n");
1039 mdb_printf(
1040 "MAX value can be shown as n/a (not available):\n");
1041 mdb_printf(
1042 " - for the very first kthread (sched/1)\n");
1043 mdb_printf(
1044 " - kmem_stackinfo was zero at kthread creation time\n");
1045 mdb_printf(
1046 " - kthread has not yet run\n");
1047 mdb_printf("\n");
1048 mdb_printf("Options:\n");
1049 mdb_printf(
1050 "-a shows also TS_FREE kthreads (interrupt kthreads)\n");
1051 mdb_printf(
1052 "-h shows history, dead kthreads that used their "
1053 "kernel stack the most\n");
1054 mdb_printf(
1055 "\nSee illumos Modular Debugger Guide for detailed usage.\n");
1056 mdb_flush();
1057 }
|