diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/ddb/db_ps.c | 374 |
1 files changed, 319 insertions, 55 deletions
diff --git a/sys/ddb/db_ps.c b/sys/ddb/db_ps.c index b5175b7..f12ccf4 100644 --- a/sys/ddb/db_ps.c +++ b/sys/ddb/db_ps.c @@ -32,9 +32,13 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/jail.h> +#include <sys/kdb.h> +#include <sys/linker_set.h> #include <sys/lock.h> #include <sys/mutex.h> #include <sys/proc.h> +#include <sys/sysent.h> #include <sys/cons.h> #include <vm/vm.h> #include <vm/vm_param.h> @@ -42,19 +46,47 @@ __FBSDID("$FreeBSD$"); #include <ddb/ddb.h> -static void dumpthread(volatile struct proc *p, volatile struct thread *td); +/* XXX I'd prefer a better way. */ +#if defined(__alpha__) || defined(__amd64__) || defined(__ia64__) || defined(__sparc64__) +#define PTR64 +#endif + +#ifdef PTR64 +CTASSERT(sizeof(uintptr_t) == sizeof(uint64_t)); +#else +CTASSERT(sizeof(uintptr_t) == sizeof(uint32_t)); +#endif + +static void dumpthread(volatile struct proc *p, volatile struct thread *td, + int all); +/* + * Layout: + * - column counts + * - header + * - single-threaded process + * - multi-threaded process + * - thread in a MT process + * + * 1 2 3 4 5 6 7 + * 1234567890123456789012345678901234567890123456789012345678901234567890 + * pid uid ppid pgrp state wmesg wchan cmd + * <pid> <ui> <ppi> <pgi> <stat> < wmesg > < wchan > <name> + * <pid> <ui> <ppi> <pgi> <stat> (threaded) <command> + * <tid > <stat> < wmesg > < wchan > <name> + * + * For machines with 64-bit pointers, we expand the wchan field 8 more + * characters. + */ void -db_ps(dummy1, dummy2, dummy3, dummy4) - db_expr_t dummy1; - boolean_t dummy2; - db_expr_t dummy3; - char * dummy4; +db_ps(db_expr_t addr, boolean_t hasaddr, db_expr_t count, char *modif) { volatile struct proc *p, *pp; volatile struct thread *td; - char *state; - int np, quit; + struct ucred *cred; + struct pgrp *pgrp; + char state[9]; + int np, quit, rflag, sflag, dflag, lflag, wflag; np = nprocs; quit = 0; @@ -66,10 +98,14 @@ db_ps(dummy1, dummy2, dummy3, dummy4) p = &proc0; db_setup_paging(db_simple_pager, &quit, db_lines_per_page); - db_printf(" pid proc uid ppid pgrp flag stat wmesg wchan cmd\n"); +#ifdef PTR64 + db_printf(" pid uid ppid pgrp state wmesg wchan cmd\n"); +#else + db_printf(" pid uid ppid pgrp state wmesg wchan cmd\n"); +#endif while (--np >= 0 && !quit) { if (p == NULL) { - printf("oops, ran out of processes early!\n"); + db_printf("oops, ran out of processes early!\n"); break; } /* PROC_LOCK(p); */ @@ -77,33 +113,99 @@ db_ps(dummy1, dummy2, dummy3, dummy4) if (pp == NULL) pp = p; + cred = p->p_ucred; + pgrp = p->p_pgrp; + db_printf("%5d %4d %5d %5d ", p->p_pid, + cred != NULL ? cred->cr_ruid : 0, pp->p_pid, + pgrp != NULL ? pgrp->pg_id : 0); + /* Determine our primary process state. */ switch(p->p_state) { case PRS_NORMAL: if (P_SHOULDSTOP(p)) - state = "stop"; - else - state = ""; + state[0] = 'T'; + else { + /* + * One of D, L, R, S, W. For a + * multithreaded process we will use + * the state of the thread with the + * highest precedence. The + * precendence order from high to low + * is R, L, D, S, W. If no thread is + * in a sane state we use '?' for our + * primary state. + */ + rflag = sflag = dflag = lflag = wflag = 0; + FOREACH_THREAD_IN_PROC(p, td) { + if (td->td_state == TDS_RUNNING || + td->td_state == TDS_RUNQ || + td->td_state == TDS_CAN_RUN) + rflag++; + if (TD_ON_LOCK(td)) + lflag++; + if (TD_IS_SLEEPING(td)) { + if (!td->td_flags & TDF_SINTR) + dflag++; + else + sflag++; + } + if (TD_AWAITING_INTR(td)) + wflag++; + } + if (rflag) + state[0] = 'R'; + else if (lflag) + state[0] = 'L'; + else if (dflag) + state[0] = 'D'; + else if (sflag) + state[0] = 'S'; + else if (wflag) + state[0] = 'W'; + else + state[0] = '?'; + } break; case PRS_NEW: - state = "new "; + state[0] = 'N'; break; case PRS_ZOMBIE: - state = "zomb"; + state[0] = 'Z'; break; default: - state = "Unkn"; + state[0] = 'U'; break; } - db_printf("%5d %8p %4d %5d %5d %07x %s", - p->p_pid, (volatile void *)p, - p->p_ucred != NULL ? p->p_ucred->cr_ruid : 0, pp->p_pid, - p->p_pgrp != NULL ? p->p_pgrp->pg_id : 0, p->p_flag, - state); + state[1] = '\0'; + + /* Additional process state flags. */ + if (!p->p_sflag & PS_INMEM) + strlcat(state, "W", sizeof(state)); + if (p->p_flag & P_TRACED) + strlcat(state, "X", sizeof(state)); + if (p->p_flag & P_WEXIT && p->p_state != PRS_ZOMBIE) + strlcat(state, "E", sizeof(state)); + if (p->p_flag & P_PPWAIT) + strlcat(state, "V", sizeof(state)); + if (p->p_flag & P_SYSTEM || p->p_lock > 0) + strlcat(state, "L", sizeof(state)); + if (p->p_session != NULL && SESS_LEADER(p)) + strlcat(state, "s", sizeof(state)); + /* Cheated here and didn't compare pgid's. */ + if (p->p_flag & P_CONTROLT) + strlcat(state, "+", sizeof(state)); + if (cred != NULL && jailed(cred)) + strlcat(state, "J", sizeof(state)); + db_printf(" %-6.6s ", state); if (p->p_flag & P_HADTHREADS) - db_printf("(threaded) %s\n", p->p_comm); +#ifdef PTR64 + db_printf(" (threaded) %s\n", + p->p_comm); +#else + db_printf(" (threaded) %s\n", p->p_comm); +#endif FOREACH_THREAD_IN_PROC(p, td) { - dumpthread(p, td); + dumpthread(p, td, p->p_flag & P_HADTHREADS); if (quit) break; } @@ -117,54 +219,216 @@ db_ps(dummy1, dummy2, dummy3, dummy4) } static void -dumpthread(volatile struct proc *p, volatile struct thread *td) +dumpthread(volatile struct proc *p, volatile struct thread *td, int all) { + char state[9], wprefix; + const char *wmesg; + void *wchan; + + if (all) { + db_printf(" %9d ", td->td_tid); + switch (td->td_state) { + case TDS_RUNNING: + snprintf(state, sizeof(state), "Run"); + break; + case TDS_RUNQ: + snprintf(state, sizeof(state), "RunQ"); + break; + case TDS_CAN_RUN: + snprintf(state, sizeof(state), "CanRun"); + break; + case TDS_INACTIVE: + snprintf(state, sizeof(state), "Inactv"); + break; + case TDS_INHIBITED: + state[0] = '\0'; + if (TD_ON_LOCK(td)) + strlcat(state, "L", sizeof(state)); + if (TD_IS_SLEEPING(td)) { + if (td->td_flags & TDF_SINTR) + strlcat(state, "S", sizeof(state)); + else + strlcat(state, "D", sizeof(state)); + } + if (TD_IS_SWAPPED(td)) + strlcat(state, "W", sizeof(state)); + if (TD_AWAITING_INTR(td)) + strlcat(state, "I", sizeof(state)); + if (TD_IS_SUSPENDED(td)) + strlcat(state, "s", sizeof(state)); + if (state[0] != '\0') + break; + default: + snprintf(state, sizeof(state), "???"); + } + db_printf(" %-6.6s ", state); + } + wprefix = ' '; + if (TD_ON_LOCK(td)) { + wprefix = '*'; + wmesg = td->td_lockname; + wchan = td->td_blocked; + } else if (TD_ON_SLEEPQ(td)) { + wmesg = td->td_wmesg; + wchan = td->td_wchan; + } else if (TD_IS_RUNNING(td)) { + snprintf(state, sizeof(state), "CPU %d", td->td_oncpu); + wmesg = state; + wchan = NULL; + } else { + wmesg = ""; + wchan = NULL; + } + db_printf("%c%-8.8s ", wprefix, wmesg); + if (wchan == NULL) +#ifdef PTR64 + db_printf("%18s ", ""); +#else + db_printf("%10s ", ""); +#endif + else + db_printf("%p ", wchan); + if (p->p_flag & P_SYSTEM) + db_printf("["); + if (td->td_name[0] != '\0') + db_printf("%s", td->td_name); + else + db_printf("%s", td->td_proc->p_comm); + if (p->p_flag & P_SYSTEM) + db_printf("]"); + db_printf("\n"); +} - if (p->p_flag & P_HADTHREADS) - db_printf( " thread %p ksegrp %p ", td, td->td_ksegrp); - if (TD_ON_SLEEPQ(td)) - db_printf("[SLPQ %s %p]", td->td_wmesg, (void *)td->td_wchan); +DB_SHOW_COMMAND(thread, db_show_thread) +{ + struct thread *td; + boolean_t comma; + + /* Determine which thread to examine. */ + if (have_addr) + td = db_lookup_thread(addr, FALSE); + else + td = kdb_thread; + + db_printf("Thread %d at %p:\n", td->td_tid, td); + db_printf(" proc (pid %d): %p ", td->td_proc->p_pid, td->td_proc); + db_printf(" ksegrp: %p\n", td->td_ksegrp); + if (td->td_name[0] != '\0') + db_printf(" name: %s\n", td->td_name); + db_printf(" flags: %#x ", td->td_flags); + db_printf(" pflags: %#x\n", td->td_pflags); + db_printf(" state: "); switch (td->td_state) { + case TDS_INACTIVE: + db_printf("INACTIVE\n"); + break; + case TDS_CAN_RUN: + db_printf("CAN RUN\n"); + break; + case TDS_RUNQ: + db_printf("RUNQ\n"); + break; + case TDS_RUNNING: + db_printf("RUNNING (CPU %d)\n", td->td_oncpu); + break; case TDS_INHIBITED: - if (TD_ON_LOCK(td)) { - db_printf("[LOCK %6s %8p]", - td->td_lockname, - (void *)td->td_blocked); - } + db_printf("INHIBITED: {"); + comma = FALSE; if (TD_IS_SLEEPING(td)) { - db_printf("[SLP]"); - } - if (TD_IS_SWAPPED(td)) { - db_printf("[SWAP]"); + db_printf("SLEEPING"); + comma = TRUE; } if (TD_IS_SUSPENDED(td)) { - db_printf("[SUSP]"); + if (comma) + db_printf(", "); + db_printf("SUSPENDED"); + comma = TRUE; + } + if (TD_IS_SWAPPED(td)) { + if (comma) + db_printf(", "); + db_printf("SWAPPED"); + comma = TRUE; + } + if (TD_ON_LOCK(td)) { + if (comma) + db_printf(", "); + db_printf("LOCK"); + comma = TRUE; } if (TD_AWAITING_INTR(td)) { - db_printf("[IWAIT]"); + if (comma) + db_printf(", "); + db_printf("IWAIT"); } + db_printf("}\n"); break; - case TDS_CAN_RUN: - db_printf("[Can run]"); + default: + db_printf("??? (%#x)\n", td->td_state); break; - case TDS_RUNQ: - db_printf("[RUNQ]"); + } + if (TD_ON_LOCK(td)) + db_printf(" lock: %s turnstile: %p\n", td->td_lockname, + td->td_blocked); + if (TD_ON_SLEEPQ(td)) + db_printf(" wmesg: %s wchan: %p\n", td->td_wmesg, + td->td_wchan); + db_printf(" priority: %d\n", td->td_priority); +} + +DB_SHOW_COMMAND(proc, db_show_proc) +{ + struct thread *td; + struct proc *p; + int i, quit; + + /* Determine which process to examine. */ + if (have_addr) + p = db_lookup_proc(addr); + else + p = kdb_thread->td_proc; + + quit = 0; + db_setup_paging(db_simple_pager, &quit, db_lines_per_page); + db_printf("Process %d (%s) at %p:\n", p->p_pid, p->p_comm, p); + db_printf(" state: "); + switch (p->p_state) { + case PRS_NEW: + db_printf("NEW\n"); break; - case TDS_RUNNING: - db_printf("[CPU %d]", td->td_oncpu); + case PRS_NORMAL: + db_printf("NORMAL\n"); break; - case TDS_INACTIVE: - db_printf("[INACTIVE]"); + case PRS_ZOMBIE: + db_printf("ZOMBIE\n"); break; default: - db_printf("[UNK: %#x]", td->td_state); + db_printf("??? (%#x)\n", p->p_state); } - if (p->p_flag & P_HADTHREADS) { -#ifdef KEF_DIDRUN - if (td->td_kse) - db_printf("[kse %p]", td->td_kse); -#endif + if (p->p_ucred != NULL) { + db_printf(" uid: %d gids: ", p->p_ucred->cr_uid); + for (i = 0; i < p->p_ucred->cr_ngroups; i++) { + db_printf("%d", p->p_ucred->cr_groups[i]); + if (i < (p->p_ucred->cr_ngroups - 1)) + db_printf(", "); + } db_printf("\n"); - } else - db_printf(" %s\n", p->p_comm); + } + if (p->p_pptr != NULL) + db_printf(" parent: pid %d at %p\n", p->p_pptr->p_pid, + p->p_pptr); + if (p->p_leader != NULL && p->p_leader != p) + db_printf(" leader: pid %d at %p\n", p->p_leader->p_pid, + p->p_leader); + if (p->p_sysent != NULL) + db_printf(" ABI: %s\n", p->p_sysent->sv_name); + if (p->p_args != NULL) + db_printf(" arguments: %.*s\n", (int)p->p_args->ar_length, + p->p_args->ar_args); + db_printf(" threads: %d\n", p->p_numthreads); + FOREACH_THREAD_IN_PROC(p, td) { + dumpthread(p, td, 1); + if (quit) + break; + } } |