db_ps.c revision 179861
162642Sn_hibma/*-
262642Sn_hibma * Copyright (c) 1993 The Regents of the University of California.
362642Sn_hibma * All rights reserved.
462642Sn_hibma *
562642Sn_hibma * Redistribution and use in source and binary forms, with or without
662642Sn_hibma * modification, are permitted provided that the following conditions
762642Sn_hibma * are met:
862642Sn_hibma * 1. Redistributions of source code must retain the above copyright
962642Sn_hibma *    notice, this list of conditions and the following disclaimer.
1062642Sn_hibma * 2. Redistributions in binary form must reproduce the above copyright
1162642Sn_hibma *    notice, this list of conditions and the following disclaimer in the
1262642Sn_hibma *    documentation and/or other materials provided with the distribution.
1362642Sn_hibma * 4. Neither the name of the University nor the names of its contributors
1462642Sn_hibma *    may be used to endorse or promote products derived from this software
1562642Sn_hibma *    without specific prior written permission.
1662642Sn_hibma *
1762642Sn_hibma * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1862642Sn_hibma * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1962642Sn_hibma * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2062642Sn_hibma * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2162642Sn_hibma * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2262642Sn_hibma * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2362642Sn_hibma * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2462642Sn_hibma * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2562642Sn_hibma * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2662642Sn_hibma * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2762642Sn_hibma * SUCH DAMAGE.
2862642Sn_hibma */
2962642Sn_hibma
3062642Sn_hibma#include <sys/cdefs.h>
3162642Sn_hibma__FBSDID("$FreeBSD: head/sys/ddb/db_ps.c 179861 2008-06-18 20:42:01Z attilio $");
3262642Sn_hibma
3362642Sn_hibma#include <sys/param.h>
3462642Sn_hibma#include <sys/cons.h>
3562642Sn_hibma#include <sys/jail.h>
3662642Sn_hibma#include <sys/kdb.h>
3762642Sn_hibma#include <sys/linker_set.h>
3862642Sn_hibma#include <sys/proc.h>
3962642Sn_hibma#include <sys/sysent.h>
4062642Sn_hibma#include <sys/systm.h>
4162642Sn_hibma#include <vm/vm.h>
42113273Smdodd#include <vm/vm_param.h>
43188945Sthompsa#include <vm/pmap.h>
4462642Sn_hibma
45225839Smav#include <ddb/ddb.h>
46225839Smav
47225839Smavstatic void	dumpthread(volatile struct proc *p, volatile struct thread *td,
48225839Smav		    int all);
49225839Smav/*
50225839Smav * At least one non-optional show-command must be implemented using
51225839Smav * DB_SHOW_ALL_COMMAND() so that db_show_all_cmd_set gets created.
52225839Smav * Here is one.
5362642Sn_hibma */
5462642Sn_hibmaDB_SHOW_ALL_COMMAND(procs, db_procs_cmd)
55164531Sgrog{
56225839Smav	db_ps(addr, have_addr, count, modif);
57225839Smav}
5862642Sn_hibma
59225839Smav/*
60225839Smav * Layout:
61225839Smav * - column counts
62225839Smav * - header
63225839Smav * - single-threaded process
64225839Smav * - multi-threaded process
6562642Sn_hibma * - thread in a MT process
66225839Smav *
67225839Smav *          1         2         3         4         5         6         7
6862642Sn_hibma * 1234567890123456789012345678901234567890123456789012345678901234567890
69225839Smav *   pid  ppid  pgrp   uid   state   wmesg     wchan    cmd
70225839Smav * <pid> <ppi> <pgi> <uid>  <stat> < wmesg > < wchan  > <name>
71225839Smav * <pid> <ppi> <pgi> <uid>  <stat>  (threaded)          <command>
72225839Smav * <tid >                   <stat> < wmesg > < wchan  > <name>
73225839Smav *
74225839Smav * For machines with 64-bit pointers, we expand the wchan field 8 more
7562642Sn_hibma * characters.
76225839Smav */
77225839Smavvoid
78225839Smavdb_ps(db_expr_t addr, boolean_t hasaddr, db_expr_t count, char *modif)
79225839Smav{
80225839Smav	volatile struct proc *p, *pp;
81225839Smav	volatile struct thread *td;
82225839Smav	struct ucred *cred;
83225839Smav	struct pgrp *pgrp;
84225839Smav	char state[9];
85225839Smav	int np, rflag, sflag, dflag, lflag, wflag;
86225839Smav
87225839Smav	np = nprocs;
88225839Smav
89225839Smav	if (!LIST_EMPTY(&allproc))
90225839Smav		p = LIST_FIRST(&allproc);
91225839Smav	else
92225839Smav		p = &proc0;
93225839Smav
94225839Smav#ifdef __LP64__
95225839Smav	db_printf("  pid  ppid  pgrp   uid   state   wmesg         wchan        cmd\n");
96225839Smav#else
97225839Smav	db_printf("  pid  ppid  pgrp   uid   state   wmesg     wchan    cmd\n");
98225839Smav#endif
99225839Smav	while (--np >= 0 && !db_pager_quit) {
100225839Smav		if (p == NULL) {
101225839Smav			db_printf("oops, ran out of processes early!\n");
102225839Smav			break;
103225839Smav		}
104225839Smav		pp = p->p_pptr;
105225839Smav		if (pp == NULL)
106225839Smav			pp = p;
107225839Smav
108225839Smav		cred = p->p_ucred;
109225839Smav		pgrp = p->p_pgrp;
110225839Smav		db_printf("%5d %5d %5d %5d ", p->p_pid, pp->p_pid,
111225839Smav		    pgrp != NULL ? pgrp->pg_id : 0,
112225839Smav		    cred != NULL ? cred->cr_ruid : 0);
113225839Smav
114225839Smav		/* Determine our primary process state. */
115225839Smav		switch (p->p_state) {
116225839Smav		case PRS_NORMAL:
117225839Smav			if (P_SHOULDSTOP(p))
118225839Smav				state[0] = 'T';
119225839Smav			else {
120225839Smav				/*
121225839Smav				 * One of D, L, R, S, W.  For a
122225839Smav				 * multithreaded process we will use
123225839Smav				 * the state of the thread with the
124225839Smav				 * highest precedence.  The
125225839Smav				 * precendence order from high to low
126225839Smav				 * is R, L, D, S, W.  If no thread is
127225839Smav				 * in a sane state we use '?' for our
128225839Smav				 * primary state.
129225839Smav				 */
130225839Smav				rflag = sflag = dflag = lflag = wflag = 0;
131225839Smav				FOREACH_THREAD_IN_PROC(p, td) {
13262642Sn_hibma					if (td->td_state == TDS_RUNNING ||
133225839Smav					    td->td_state == TDS_RUNQ ||
134225839Smav					    td->td_state == TDS_CAN_RUN)
135225839Smav						rflag++;
136225839Smav					if (TD_ON_LOCK(td))
137225839Smav						lflag++;
138225839Smav					if (TD_IS_SLEEPING(td)) {
139225839Smav						if (!td->td_flags & TDF_SINTR)
140225839Smav							dflag++;
141225839Smav						else
142225839Smav							sflag++;
143225839Smav					}
144225839Smav					if (TD_AWAITING_INTR(td))
145225839Smav						wflag++;
146225839Smav				}
147225839Smav				if (rflag)
148225839Smav					state[0] = 'R';
149225839Smav				else if (lflag)
150225839Smav					state[0] = 'L';
151225839Smav				else if (dflag)
152225839Smav					state[0] = 'D';
153225839Smav				else if (sflag)
154225839Smav					state[0] = 'S';
155225839Smav				else if (wflag)
156225839Smav					state[0] = 'W';
157225839Smav				else
158225839Smav					state[0] = '?';
159225839Smav			}
160225839Smav			break;
161225839Smav		case PRS_NEW:
162225839Smav			state[0] = 'N';
163225839Smav			break;
164225839Smav		case PRS_ZOMBIE:
165225839Smav			state[0] = 'Z';
166225839Smav			break;
167225839Smav		default:
168225839Smav			state[0] = 'U';
169225839Smav			break;
170225839Smav		}
171225839Smav		state[1] = '\0';
172225839Smav
173225839Smav		/* Additional process state flags. */
174225839Smav		if (!p->p_flag & P_INMEM)
175225839Smav			strlcat(state, "W", sizeof(state));
176225839Smav		if (p->p_flag & P_TRACED)
17762642Sn_hibma			strlcat(state, "X", sizeof(state));
17862642Sn_hibma		if (p->p_flag & P_WEXIT && p->p_state != PRS_ZOMBIE)
179225839Smav			strlcat(state, "E", sizeof(state));
18062642Sn_hibma		if (p->p_flag & P_PPWAIT)
18162642Sn_hibma			strlcat(state, "V", sizeof(state));
18262642Sn_hibma		if (p->p_flag & P_SYSTEM || p->p_lock > 0)
183164531Sgrog			strlcat(state, "L", sizeof(state));
184164531Sgrog		if (p->p_session != NULL && SESS_LEADER(p))
185164544Sgrog			strlcat(state, "s", sizeof(state));
186194789Sdelphij		/* Cheated here and didn't compare pgid's. */
187164531Sgrog		if (p->p_flag & P_CONTROLT)
188164531Sgrog			strlcat(state, "+", sizeof(state));
189164544Sgrog		if (cred != NULL && jailed(cred))
190194789Sdelphij			strlcat(state, "J", sizeof(state));
191225839Smav		db_printf(" %-6.6s ", state);
192225839Smav		if (p->p_flag & P_HADTHREADS)
193225839Smav#ifdef __LP64__
194225839Smav			db_printf(" (threaded)                  %s\n",
19562642Sn_hibma			    p->p_comm);
19662642Sn_hibma#else
19762642Sn_hibma			db_printf(" (threaded)          %s\n", p->p_comm);
198225839Smav#endif
19987699Smarkm		FOREACH_THREAD_IN_PROC(p, td) {
20062642Sn_hibma			dumpthread(p, td, p->p_flag & P_HADTHREADS);
20162642Sn_hibma			if (db_pager_quit)
20262642Sn_hibma				break;
203224511Smav		}
204224511Smav
205164531Sgrog		p = LIST_NEXT(p, p_list);
20662642Sn_hibma		if (p == NULL && np > 0)
207224511Smav			p = LIST_FIRST(&zombproc);
208224511Smav    	}
20962642Sn_hibma}
21062642Sn_hibma
21162642Sn_hibmastatic void
21262642Sn_hibmadumpthread(volatile struct proc *p, volatile struct thread *td, int all)
21362642Sn_hibma{
21462642Sn_hibma	char state[9], wprefix;
21562642Sn_hibma	const char *wmesg;
21662642Sn_hibma	void *wchan;
21762642Sn_hibma
21862642Sn_hibma	if (all) {
219224511Smav		db_printf("%6d                  ", td->td_tid);
220224511Smav		switch (td->td_state) {
221224511Smav		case TDS_RUNNING:
222224511Smav			snprintf(state, sizeof(state), "Run");
223224511Smav			break;
224224511Smav		case TDS_RUNQ:
225224511Smav			snprintf(state, sizeof(state), "RunQ");
226224511Smav			break;
227224511Smav		case TDS_CAN_RUN:
228224511Smav			snprintf(state, sizeof(state), "CanRun");
229224511Smav			break;
230224511Smav		case TDS_INACTIVE:
231224511Smav			snprintf(state, sizeof(state), "Inactv");
232224511Smav			break;
233224511Smav		case TDS_INHIBITED:
234224511Smav			state[0] = '\0';
235224511Smav			if (TD_ON_LOCK(td))
236224511Smav				strlcat(state, "L", sizeof(state));
237225839Smav			if (TD_IS_SLEEPING(td)) {
23862642Sn_hibma				if (td->td_flags & TDF_SINTR)
23962642Sn_hibma					strlcat(state, "S", sizeof(state));
24062642Sn_hibma				else
24162642Sn_hibma					strlcat(state, "D", sizeof(state));
24267256Sn_hibma			}
24362642Sn_hibma			if (TD_IS_SWAPPED(td))
244224511Smav				strlcat(state, "W", sizeof(state));
24562642Sn_hibma			if (TD_AWAITING_INTR(td))
24662642Sn_hibma				strlcat(state, "I", sizeof(state));
247224511Smav			if (TD_IS_SUSPENDED(td))
248224511Smav				strlcat(state, "s", sizeof(state));
249164531Sgrog			if (state[0] != '\0')
25062642Sn_hibma				break;
25162642Sn_hibma		default:
25262642Sn_hibma			snprintf(state, sizeof(state), "???");
25362642Sn_hibma		}
25462642Sn_hibma		db_printf(" %-6.6s ", state);
25562642Sn_hibma	}
25662642Sn_hibma	wprefix = ' ';
25762642Sn_hibma	if (TD_ON_LOCK(td)) {
25862642Sn_hibma		wprefix = '*';
25962642Sn_hibma		wmesg = td->td_lockname;
26062642Sn_hibma		wchan = td->td_blocked;
26162642Sn_hibma	} else if (TD_ON_SLEEPQ(td)) {
26262642Sn_hibma		wmesg = td->td_wmesg;
26362642Sn_hibma		wchan = td->td_wchan;
26462642Sn_hibma	} else if (TD_IS_RUNNING(td)) {
26562642Sn_hibma		snprintf(state, sizeof(state), "CPU %d", td->td_oncpu);
26662642Sn_hibma		wmesg = state;
267224511Smav		wchan = NULL;
26875606Sn_hibma	} else {
26962642Sn_hibma		wmesg = "";
270224511Smav		wchan = NULL;
27167256Sn_hibma	}
27267256Sn_hibma	db_printf("%c%-8.8s ", wprefix, wmesg);
273224511Smav	if (wchan == NULL)
27467256Sn_hibma#ifdef __LP64__
27562642Sn_hibma		db_printf("%18s ", "");
27662642Sn_hibma#else
277225839Smav		db_printf("%10s ", "");
27862642Sn_hibma#endif
27962642Sn_hibma	else
28062642Sn_hibma		db_printf("%p ", wchan);
28162642Sn_hibma	if (p->p_flag & P_SYSTEM)
28262642Sn_hibma		db_printf("[");
28362642Sn_hibma	if (td->td_name[0] != '\0')
28462642Sn_hibma		db_printf("%s", td->td_name);
28562642Sn_hibma	else
286224511Smav		db_printf("%s", td->td_proc->p_comm);
287224511Smav	if (p->p_flag & P_SYSTEM)
28862642Sn_hibma		db_printf("]");
28962642Sn_hibma	db_printf("\n");
29062642Sn_hibma}
29162642Sn_hibma
292164531SgrogDB_SHOW_COMMAND(thread, db_show_thread)
293164531Sgrog{
294224511Smav	struct thread *td;
29562642Sn_hibma	struct lock_object *lock;
296224511Smav	boolean_t comma;
29762642Sn_hibma
29862642Sn_hibma	/* Determine which thread to examine. */
299225839Smav	if (have_addr)
30062642Sn_hibma		td = db_lookup_thread(addr, FALSE);
30162642Sn_hibma	else
302225839Smav		td = kdb_thread;
303225839Smav	lock = (struct lock_object *)td->td_lock;
30462642Sn_hibma
305225839Smav	db_printf("Thread %d at %p:\n", td->td_tid, td);
30662642Sn_hibma	db_printf(" proc (pid %d): %p\n", td->td_proc->p_pid, td->td_proc);
307225839Smav	if (td->td_name[0] != '\0')
308225839Smav		db_printf(" name: %s\n", td->td_name);
309225839Smav	db_printf(" stack: %p-%p\n", (void *)td->td_kstack,
310225839Smav	    (void *)(td->td_kstack + td->td_kstack_pages * PAGE_SIZE - 1));
311225839Smav	db_printf(" flags: %#x ", td->td_flags);
312225839Smav	db_printf(" pflags: %#x\n", td->td_pflags);
313225839Smav	db_printf(" state: ");
314225839Smav	switch (td->td_state) {
315225839Smav	case TDS_INACTIVE:
316225839Smav		db_printf("INACTIVE\n");
317225839Smav		break;
318225839Smav	case TDS_CAN_RUN:
319225839Smav		db_printf("CAN RUN\n");
320225839Smav		break;
321225839Smav	case TDS_RUNQ:
322225839Smav		db_printf("RUNQ\n");
323225839Smav		break;
324225839Smav	case TDS_RUNNING:
325225839Smav		db_printf("RUNNING (CPU %d)\n", td->td_oncpu);
326225839Smav		break;
327225839Smav	case TDS_INHIBITED:
32862642Sn_hibma		db_printf("INHIBITED: {");
329225839Smav		comma = FALSE;
330225839Smav		if (TD_IS_SLEEPING(td)) {
331225839Smav			db_printf("SLEEPING");
332225839Smav			comma = TRUE;
333225839Smav		}
334225839Smav		if (TD_IS_SUSPENDED(td)) {
335225839Smav			if (comma)
336225839Smav				db_printf(", ");
337225839Smav			db_printf("SUSPENDED");
338225839Smav			comma = TRUE;
339225839Smav		}
340225839Smav		if (TD_IS_SWAPPED(td)) {
341225839Smav			if (comma)
342225839Smav				db_printf(", ");
343225839Smav			db_printf("SWAPPED");
34462642Sn_hibma			comma = TRUE;
345225839Smav		}
346225839Smav		if (TD_ON_LOCK(td)) {
347225839Smav			if (comma)
348225839Smav				db_printf(", ");
349225839Smav			db_printf("LOCK");
350225839Smav			comma = TRUE;
351225839Smav		}
352225839Smav		if (TD_AWAITING_INTR(td)) {
353225839Smav			if (comma)
354225839Smav				db_printf(", ");
35562642Sn_hibma			db_printf("IWAIT");
356225839Smav		}
357225839Smav		db_printf("}\n");
358225839Smav		break;
359224511Smav	default:
360225839Smav		db_printf("??? (%#x)\n", td->td_state);
361225839Smav		break;
362225839Smav	}
363225839Smav	if (TD_ON_LOCK(td))
364225839Smav		db_printf(" lock: %s  turnstile: %p\n", td->td_lockname,
365225839Smav		    td->td_blocked);
366225839Smav	if (TD_ON_SLEEPQ(td))
367225839Smav		db_printf(" wmesg: %s  wchan: %p\n", td->td_wmesg,
368225839Smav		    td->td_wchan);
369225839Smav	db_printf(" priority: %d\n", td->td_priority);
370225839Smav	db_printf(" container lock: %s (%p)\n", lock->lo_name, lock);
371225839Smav}
372225839Smav
373225839SmavDB_SHOW_COMMAND(proc, db_show_proc)
374225839Smav{
375225839Smav	struct thread *td;
376225839Smav	struct proc *p;
377225839Smav	int i;
378225839Smav
379225839Smav	/* Determine which process to examine. */
380225839Smav	if (have_addr)
381225839Smav		p = db_lookup_proc(addr);
382225839Smav	else
383225839Smav		p = kdb_thread->td_proc;
384225839Smav
385225839Smav	db_printf("Process %d (%s) at %p:\n", p->p_pid, p->p_comm, p);
386225839Smav	db_printf(" state: ");
387225839Smav	switch (p->p_state) {
388225839Smav	case PRS_NEW:
389225839Smav		db_printf("NEW\n");
390225839Smav		break;
391225839Smav	case PRS_NORMAL:
392225839Smav		db_printf("NORMAL\n");
393225839Smav		break;
394225839Smav	case PRS_ZOMBIE:
395225839Smav		db_printf("ZOMBIE\n");
396225839Smav		break;
397225839Smav	default:
398225839Smav		db_printf("??? (%#x)\n", p->p_state);
399225839Smav	}
400225839Smav	if (p->p_ucred != NULL) {
401225839Smav		db_printf(" uid: %d  gids: ", p->p_ucred->cr_uid);
402225839Smav		for (i = 0; i < p->p_ucred->cr_ngroups; i++) {
403225839Smav			db_printf("%d", p->p_ucred->cr_groups[i]);
404225839Smav			if (i < (p->p_ucred->cr_ngroups - 1))
405225839Smav				db_printf(", ");
406225839Smav		}
407225839Smav		db_printf("\n");
40862642Sn_hibma	}
40962642Sn_hibma	if (p->p_pptr != NULL)
410225839Smav		db_printf(" parent: pid %d at %p\n", p->p_pptr->p_pid,
411225839Smav		    p->p_pptr);
412225839Smav	if (p->p_leader != NULL && p->p_leader != p)
413225839Smav		db_printf(" leader: pid %d at %p\n", p->p_leader->p_pid,
414225839Smav		    p->p_leader);
415225839Smav	if (p->p_sysent != NULL)
416225839Smav		db_printf(" ABI: %s\n", p->p_sysent->sv_name);
417225839Smav	if (p->p_args != NULL)
418225839Smav		db_printf(" arguments: %.*s\n", (int)p->p_args->ar_length,
41962642Sn_hibma		    p->p_args->ar_args);
420225839Smav	db_printf(" threads: %d\n", p->p_numthreads);
421225839Smav	FOREACH_THREAD_IN_PROC(p, td) {
422225839Smav		dumpthread(p, td, 1);
423225839Smav		if (db_pager_quit)
424225839Smav			break;
425225839Smav	}
426225839Smav}
427225839Smav