Print this page
8158 Want named threads API
9857 proc manpages should have LIBRARY section
@@ -22,24 +22,27 @@
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2018, Joyent, Inc.
*/
#include <mdb/mdb_modapi.h>
#include <mdb/mdb_ks.h>
+#include <mdb/mdb_ctf.h>
#include <sys/types.h>
#include <sys/thread.h>
#include <sys/lwp.h>
#include <sys/proc.h>
#include <sys/cpuvar.h>
#include <sys/cpupart.h>
#include <sys/disp.h>
#include <sys/taskq_impl.h>
#include <sys/stack.h>
+#include "thread.h"
#ifndef STACK_BIAS
#define STACK_BIAS 0
#endif
@@ -559,10 +562,93 @@
"\t-p\tprint process and lwp state\n"
"\t-s\tprint signal state\n");
}
/*
+ * Return a string description of the thread, including the ID and the thread
+ * name.
+ *
+ * If ->t_name is NULL, and we're a system thread, we'll do a little more
+ * spelunking to find a useful string to return.
+ */
+int
+thread_getdesc(uintptr_t addr, boolean_t include_comm,
+ char *buf, size_t bufsize)
+{
+ char name[THREAD_NAME_MAX] = "";
+ kthread_t t;
+ proc_t p;
+
+ bzero(buf, bufsize);
+
+ if (mdb_vread(&t, sizeof (kthread_t), addr) == -1) {
+ mdb_warn("failed to read kthread_t at %p", addr);
+ return (-1);
+ }
+
+ if (t.t_tid == 0) {
+ taskq_t tq;
+
+ if (mdb_vread(&tq, sizeof (taskq_t),
+ (uintptr_t)t.t_taskq) == -1)
+ tq.tq_name[0] = '\0';
+
+ if (t.t_name != NULL) {
+ if (mdb_readstr(buf, bufsize,
+ (uintptr_t)t.t_name) == -1) {
+ mdb_warn("error reading thread name");
+ }
+ } else if (tq.tq_name[0] != '\0') {
+ (void) mdb_snprintf(buf, bufsize, "tq:%s", tq.tq_name);
+ } else {
+ mdb_snprintf(buf, bufsize, "%a()", t.t_startpc);
+ }
+
+ return (buf[0] == '\0' ? -1 : 0);
+ }
+
+ if (include_comm && mdb_vread(&p, sizeof (proc_t),
+ (uintptr_t)t.t_procp) == -1) {
+ mdb_warn("failed to read proc at %p", t.t_procp);
+ return (-1);
+ }
+
+ if (t.t_name != NULL) {
+ if (mdb_readstr(name, sizeof (name), (uintptr_t)t.t_name) == -1)
+ mdb_warn("error reading thread name");
+
+ /*
+ * Just to be safe -- if mdb_readstr() succeeds, it always NUL
+ * terminates the output, but is unclear what it does on
+ * failure. In that case we attempt to show any partial content
+ * w/ the warning in case it's useful, but explicitly
+ * NUL-terminate to be safe.
+ */
+ buf[bufsize - 1] = '\0';
+ }
+
+ if (name[0] != '\0') {
+ if (include_comm) {
+ (void) mdb_snprintf(buf, bufsize, "%s/%u [%s]",
+ p.p_user.u_comm, t.t_tid, name);
+ } else {
+ (void) mdb_snprintf(buf, bufsize, "%u [%s]",
+ t.t_tid, name);
+ }
+ } else {
+ if (include_comm) {
+ (void) mdb_snprintf(buf, bufsize, "%s/%u",
+ p.p_user.u_comm, t.t_tid);
+ } else {
+ (void) mdb_snprintf(buf, bufsize, "%u", t.t_tid);
+ }
+ }
+
+ return (buf[0] == '\0' ? -1 : 0);
+}
+
+/*
* List a combination of kthread_t and proc_t. Add stack traces in verbose mode.
*/
int
threadlist(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
@@ -569,12 +655,10 @@
int i;
uint_t count = 0;
uint_t verbose = FALSE;
uint_t notaskq = FALSE;
kthread_t t;
- taskq_t tq;
- proc_t p;
char cmd[80];
mdb_arg_t cmdarg;
if (!(flags & DCMD_ADDRSPEC)) {
if (mdb_walk_dcmd("thread", "threadlist", argc, argv) == -1) {
@@ -616,33 +700,26 @@
return (DCMD_OK);
if (t.t_state == TS_FREE)
return (DCMD_OK);
- if (mdb_vread(&p, sizeof (proc_t), (uintptr_t)t.t_procp) == -1) {
- mdb_warn("failed to read proc at %p", t.t_procp);
+ if (!verbose) {
+ char desc[128];
+
+ if (thread_getdesc(addr, B_TRUE, desc, sizeof (desc)) == -1)
return (DCMD_ERR);
+
+ mdb_printf("%0?p %?p %?p %s\n", addr, t.t_procp, t.t_lwp, desc);
+ return (DCMD_OK);
}
- if (mdb_vread(&tq, sizeof (taskq_t), (uintptr_t)t.t_taskq) == -1)
- tq.tq_name[0] = '\0';
-
- if (verbose) {
mdb_printf("%0?p %?p %?p %3u %3d %?p\n",
addr, t.t_procp, t.t_lwp, t.t_cid, t.t_pri, t.t_wchan);
mdb_inc_indent(2);
- mdb_printf("PC: %a", t.t_pc);
- if (t.t_tid == 0) {
- if (tq.tq_name[0] != '\0')
- mdb_printf(" TASKQ: %s\n", tq.tq_name);
- else
- mdb_printf(" THREAD: %a()\n", t.t_startpc);
- } else {
- mdb_printf(" CMD: %s\n", p.p_user.u_psargs);
- }
+ mdb_printf("PC: %a\n", t.t_pc);
mdb_snprintf(cmd, sizeof (cmd), "<.$c%d", count);
cmdarg.a_type = MDB_TYPE_STRING;
cmdarg.a_un.a_str = cmd;
@@ -649,21 +726,10 @@
(void) mdb_call_dcmd("findstack", addr, flags, 1, &cmdarg);
mdb_dec_indent(2);
mdb_printf("\n");
- } else {
- mdb_printf("%0?p %?p %?p", addr, t.t_procp, t.t_lwp);
- if (t.t_tid == 0) {
- if (tq.tq_name[0] != '\0')
- mdb_printf(" tq:%s\n", tq.tq_name);
- else
- mdb_printf(" %a()\n", t.t_startpc);
- } else {
- mdb_printf(" %s/%u\n", p.p_user.u_comm, t.t_tid);
- }
- }
return (DCMD_OK);
}
void
@@ -714,11 +780,10 @@
*/
int
stackinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
kthread_t t;
- proc_t p;
uint64_t *ptr; /* pattern pointer */
caddr_t start; /* kernel stack start */
caddr_t end; /* kernel stack end */
caddr_t ustack; /* userland copy of kernel stack */
size_t usize; /* userland copy of kernel stack size */
@@ -728,10 +793,11 @@
uint_t all = FALSE; /* don't show TS_FREE kthread by default */
uint_t history = FALSE;
int i = 0;
unsigned int ukmem_stackinfo;
uintptr_t allthreads;
+ char tdesc[128] = "";
/* handle options */
if (mdb_getopts(argc, argv,
'a', MDB_OPT_SETBITS, TRUE, &all,
'h', MDB_OPT_SETBITS, TRUE, &history, NULL) != argc) {
@@ -773,11 +839,11 @@
return (DCMD_OK);
}
mdb_printf("%<u>%?s%</u>", "THREAD");
mdb_printf(" %<u>%?s%</u>", "STACK");
- mdb_printf("%<u>%s%</u>", " SIZE MAX CMD/LWPID or STARTPC");
+ mdb_printf("%<u>%s%</u>", " SIZE MAX LWP");
mdb_printf("\n");
usize = KMEM_STKINFO_LOG_SIZE * sizeof (kmem_stkinfo_t);
log = (kmem_stkinfo_t *)mdb_alloc(usize, UM_SLEEP);
if (mdb_readsym(&kaddr, sizeof (kaddr),
"kmem_stkinfo_log") == -1) {
@@ -796,23 +862,20 @@
}
for (i = 0; i < KMEM_STKINFO_LOG_SIZE; i++) {
if (log[i].kthread == NULL) {
continue;
}
- mdb_printf("%0?p %0?p %6x %3d%%",
+
+ (void) thread_getdesc((uintptr_t)log[i].kthread,
+ B_TRUE, tdesc, sizeof (tdesc));
+
+ mdb_printf("%0?p %0?p %6x %3d%% %s\n",
log[i].kthread,
log[i].start,
(uint_t)log[i].stksz,
- (int)log[i].percent);
- if (log[i].t_tid != 0) {
- mdb_printf(" %s/%u\n",
- log[i].cmd, log[i].t_tid);
- } else {
- mdb_printf(" %p (%a)\n", log[i].t_startpc,
- log[i].t_startpc);
+ (int)log[i].percent, tdesc);
}
- }
mdb_free((void *)log, usize);
return (DCMD_OK);
}
/* display header */
@@ -822,11 +885,11 @@
mdb_printf("MAX value is not available.\n");
mdb_printf("Use ::help stackinfo for more details.\n");
}
mdb_printf("%<u>%?s%</u>", "THREAD");
mdb_printf(" %<u>%?s%</u>", "STACK");
- mdb_printf("%<u>%s%</u>", " SIZE CUR MAX CMD/LWPID");
+ mdb_printf("%<u>%s%</u>", " SIZE CUR MAX LWP");
mdb_printf("\n");
}
/* read kthread */
if (mdb_vread(&t, sizeof (kthread_t), addr) == -1) {
@@ -836,16 +899,10 @@
if (t.t_state == TS_FREE && all == FALSE) {
return (DCMD_OK);
}
- /* read proc */
- if (mdb_vread(&p, sizeof (proc_t), (uintptr_t)t.t_procp) == -1) {
- mdb_warn("failed to read proc at %p\n", t.t_procp);
- return (DCMD_ERR);
- }
-
/*
* Stack grows up or down, see thread_create(),
* compute stack memory aera start and end (start < end).
*/
if (t.t_stk > t.t_stkbase) {
@@ -876,18 +933,14 @@
(caddr_t)t.t_sp + STACK_BIAS);
mdb_printf(" %3d%%", percent);
percent = 0;
+ (void) thread_getdesc(addr, B_TRUE, tdesc, sizeof (tdesc));
+
if (ukmem_stackinfo == 0) {
- mdb_printf(" n/a");
- if (t.t_tid == 0) {
- mdb_printf(" %a()", t.t_startpc);
- } else {
- mdb_printf(" %s/%u", p.p_user.u_comm, t.t_tid);
- }
- mdb_printf("\n");
+ mdb_printf(" n/a %s\n", tdesc);
return (DCMD_OK);
}
if ((((uintptr_t)start) & 0x7) != 0) {
start = (caddr_t)((((uintptr_t)start) & (~0x7)) + 8);
@@ -956,16 +1009,13 @@
if (percent != 0) {
mdb_printf(" %3d%%", percent);
} else {
mdb_printf(" n/a");
}
- if (t.t_tid == 0) {
- mdb_printf(" %a()", t.t_startpc);
- } else {
- mdb_printf(" %s/%u", p.p_user.u_comm, t.t_tid);
- }
- mdb_printf("\n");
+
+ mdb_printf(" %s\n", tdesc);
+
mdb_free((void *)ustack, usize + 8);
return (DCMD_OK);
}
void
@@ -976,11 +1026,11 @@
"kmem_stackinfo tunable\n");
mdb_printf(
"(an unsigned integer) is non zero at kthread creation time. ");
mdb_printf("For example:\n");
mdb_printf(
- " THREAD STACK SIZE CUR MAX CMD/LWPID\n");
+ " THREAD STACK SIZE CUR MAX LWP\n");
mdb_printf(
"ffffff014f5f2c20 ffffff0004153000 4f00 4%% 43%% init/1\n");
mdb_printf(
"The stack size utilization for this kthread is at 4%%"
" of its maximum size,\n");
@@ -1000,8 +1050,8 @@
"-a shows also TS_FREE kthreads (interrupt kthreads)\n");
mdb_printf(
"-h shows history, dead kthreads that used their "
"kernel stack the most\n");
mdb_printf(
- "\nSee Solaris Modular Debugger Guide for detailed usage.\n");
+ "\nSee illumos Modular Debugger Guide for detailed usage.\n");
mdb_flush();
}