xref: /freebsd/sys/ddb/db_ps.c (revision 4fd2d3b6927878771635a3628ae1623daf810d39)
1 /*-
2  * Copyright (c) 1993 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 4. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32 
33 #include <sys/param.h>
34 #include <sys/cons.h>
35 #include <sys/jail.h>
36 #include <sys/kdb.h>
37 #include <sys/linker_set.h>
38 #include <sys/proc.h>
39 #include <sys/sysent.h>
40 #include <sys/systm.h>
41 #include <vm/vm.h>
42 #include <vm/vm_param.h>
43 #include <vm/pmap.h>
44 
45 #include <ddb/ddb.h>
46 
47 static void	dumpthread(volatile struct proc *p, volatile struct thread *td,
48 		    int all);
49 
50 /*
51  * Layout:
52  * - column counts
53  * - header
54  * - single-threaded process
55  * - multi-threaded process
56  * - thread in a MT process
57  *
58  *          1         2         3         4         5         6         7
59  * 1234567890123456789012345678901234567890123456789012345678901234567890
60  *   pid  ppid  pgrp   uid   state   wmesg     wchan    cmd
61  * <pid> <ppi> <pgi> <uid>  <stat> < wmesg > < wchan  > <name>
62  * <pid> <ppi> <pgi> <uid>  <stat>  (threaded)          <command>
63  * <tid >                   <stat> < wmesg > < wchan  > <name>
64  *
65  * For machines with 64-bit pointers, we expand the wchan field 8 more
66  * characters.
67  */
68 void
69 db_ps(db_expr_t addr, boolean_t hasaddr, db_expr_t count, char *modif)
70 {
71 	volatile struct proc *p, *pp;
72 	volatile struct thread *td;
73 	struct ucred *cred;
74 	struct pgrp *pgrp;
75 	char state[9];
76 	int np, rflag, sflag, dflag, lflag, wflag;
77 
78 	np = nprocs;
79 
80 	if (!LIST_EMPTY(&allproc))
81 		p = LIST_FIRST(&allproc);
82 	else
83 		p = &proc0;
84 
85 #ifdef __LP64__
86 	db_printf("  pid  ppid  pgrp   uid   state   wmesg         wchan        cmd\n");
87 #else
88 	db_printf("  pid  ppid  pgrp   uid   state   wmesg     wchan    cmd\n");
89 #endif
90 	while (--np >= 0 && !db_pager_quit) {
91 		if (p == NULL) {
92 			db_printf("oops, ran out of processes early!\n");
93 			break;
94 		}
95 		pp = p->p_pptr;
96 		if (pp == NULL)
97 			pp = p;
98 
99 		cred = p->p_ucred;
100 		pgrp = p->p_pgrp;
101 		db_printf("%5d %5d %5d %5d ", p->p_pid, pp->p_pid,
102 		    pgrp != NULL ? pgrp->pg_id : 0,
103 		    cred != NULL ? cred->cr_ruid : 0);
104 
105 		/* Determine our primary process state. */
106 		switch (p->p_state) {
107 		case PRS_NORMAL:
108 			if (P_SHOULDSTOP(p))
109 				state[0] = 'T';
110 			else {
111 				/*
112 				 * One of D, L, R, S, W.  For a
113 				 * multithreaded process we will use
114 				 * the state of the thread with the
115 				 * highest precedence.  The
116 				 * precendence order from high to low
117 				 * is R, L, D, S, W.  If no thread is
118 				 * in a sane state we use '?' for our
119 				 * primary state.
120 				 */
121 				rflag = sflag = dflag = lflag = wflag = 0;
122 				FOREACH_THREAD_IN_PROC(p, td) {
123 					if (td->td_state == TDS_RUNNING ||
124 					    td->td_state == TDS_RUNQ ||
125 					    td->td_state == TDS_CAN_RUN)
126 						rflag++;
127 					if (TD_ON_LOCK(td))
128 						lflag++;
129 					if (TD_IS_SLEEPING(td)) {
130 						if (!td->td_flags & TDF_SINTR)
131 							dflag++;
132 						else
133 							sflag++;
134 					}
135 					if (TD_AWAITING_INTR(td))
136 						wflag++;
137 				}
138 				if (rflag)
139 					state[0] = 'R';
140 				else if (lflag)
141 					state[0] = 'L';
142 				else if (dflag)
143 					state[0] = 'D';
144 				else if (sflag)
145 					state[0] = 'S';
146 				else if (wflag)
147 					state[0] = 'W';
148 				else
149 					state[0] = '?';
150 			}
151 			break;
152 		case PRS_NEW:
153 			state[0] = 'N';
154 			break;
155 		case PRS_ZOMBIE:
156 			state[0] = 'Z';
157 			break;
158 		default:
159 			state[0] = 'U';
160 			break;
161 		}
162 		state[1] = '\0';
163 
164 		/* Additional process state flags. */
165 		if (!p->p_flag & P_INMEM)
166 			strlcat(state, "W", sizeof(state));
167 		if (p->p_flag & P_TRACED)
168 			strlcat(state, "X", sizeof(state));
169 		if (p->p_flag & P_WEXIT && p->p_state != PRS_ZOMBIE)
170 			strlcat(state, "E", sizeof(state));
171 		if (p->p_flag & P_PPWAIT)
172 			strlcat(state, "V", sizeof(state));
173 		if (p->p_flag & P_SYSTEM || p->p_lock > 0)
174 			strlcat(state, "L", sizeof(state));
175 		if (p->p_session != NULL && SESS_LEADER(p))
176 			strlcat(state, "s", sizeof(state));
177 		/* Cheated here and didn't compare pgid's. */
178 		if (p->p_flag & P_CONTROLT)
179 			strlcat(state, "+", sizeof(state));
180 		if (cred != NULL && jailed(cred))
181 			strlcat(state, "J", sizeof(state));
182 		db_printf(" %-6.6s ", state);
183 		if (p->p_flag & P_HADTHREADS)
184 #ifdef __LP64__
185 			db_printf(" (threaded)                  %s\n",
186 			    p->p_comm);
187 #else
188 			db_printf(" (threaded)          %s\n", p->p_comm);
189 #endif
190 		FOREACH_THREAD_IN_PROC(p, td) {
191 			dumpthread(p, td, p->p_flag & P_HADTHREADS);
192 			if (db_pager_quit)
193 				break;
194 		}
195 
196 		p = LIST_NEXT(p, p_list);
197 		if (p == NULL && np > 0)
198 			p = LIST_FIRST(&zombproc);
199     	}
200 }
201 
202 static void
203 dumpthread(volatile struct proc *p, volatile struct thread *td, int all)
204 {
205 	char state[9], wprefix;
206 	const char *wmesg;
207 	void *wchan;
208 
209 	if (all) {
210 		db_printf("%6d                  ", td->td_tid);
211 		switch (td->td_state) {
212 		case TDS_RUNNING:
213 			snprintf(state, sizeof(state), "Run");
214 			break;
215 		case TDS_RUNQ:
216 			snprintf(state, sizeof(state), "RunQ");
217 			break;
218 		case TDS_CAN_RUN:
219 			snprintf(state, sizeof(state), "CanRun");
220 			break;
221 		case TDS_INACTIVE:
222 			snprintf(state, sizeof(state), "Inactv");
223 			break;
224 		case TDS_INHIBITED:
225 			state[0] = '\0';
226 			if (TD_ON_LOCK(td))
227 				strlcat(state, "L", sizeof(state));
228 			if (TD_IS_SLEEPING(td)) {
229 				if (td->td_flags & TDF_SINTR)
230 					strlcat(state, "S", sizeof(state));
231 				else
232 					strlcat(state, "D", sizeof(state));
233 			}
234 			if (TD_IS_SWAPPED(td))
235 				strlcat(state, "W", sizeof(state));
236 			if (TD_AWAITING_INTR(td))
237 				strlcat(state, "I", sizeof(state));
238 			if (TD_IS_SUSPENDED(td))
239 				strlcat(state, "s", sizeof(state));
240 			if (state[0] != '\0')
241 				break;
242 		default:
243 			snprintf(state, sizeof(state), "???");
244 		}
245 		db_printf(" %-6.6s ", state);
246 	}
247 	wprefix = ' ';
248 	if (TD_ON_LOCK(td)) {
249 		wprefix = '*';
250 		wmesg = td->td_lockname;
251 		wchan = td->td_blocked;
252 	} else if (TD_ON_SLEEPQ(td)) {
253 		wmesg = td->td_wmesg;
254 		wchan = td->td_wchan;
255 	} else if (TD_IS_RUNNING(td)) {
256 		snprintf(state, sizeof(state), "CPU %d", td->td_oncpu);
257 		wmesg = state;
258 		wchan = NULL;
259 	} else {
260 		wmesg = "";
261 		wchan = NULL;
262 	}
263 	db_printf("%c%-8.8s ", wprefix, wmesg);
264 	if (wchan == NULL)
265 #ifdef __LP64__
266 		db_printf("%18s ", "");
267 #else
268 		db_printf("%10s ", "");
269 #endif
270 	else
271 		db_printf("%p ", wchan);
272 	if (p->p_flag & P_SYSTEM)
273 		db_printf("[");
274 	if (td->td_name[0] != '\0')
275 		db_printf("%s", td->td_name);
276 	else
277 		db_printf("%s", td->td_proc->p_comm);
278 	if (p->p_flag & P_SYSTEM)
279 		db_printf("]");
280 	db_printf("\n");
281 }
282 
283 DB_SHOW_COMMAND(thread, db_show_thread)
284 {
285 	struct thread *td;
286 	boolean_t comma;
287 
288 	/* Determine which thread to examine. */
289 	if (have_addr)
290 		td = db_lookup_thread(addr, FALSE);
291 	else
292 		td = kdb_thread;
293 
294 	db_printf("Thread %d at %p:\n", td->td_tid, td);
295 	db_printf(" proc (pid %d): %p\n", td->td_proc->p_pid, td->td_proc);
296 	if (td->td_name[0] != '\0')
297 		db_printf(" name: %s\n", td->td_name);
298 	db_printf(" stack: %p-%p\n", (void *)td->td_kstack,
299 	    (void *)(td->td_kstack + td->td_kstack_pages * PAGE_SIZE - 1));
300 	db_printf(" flags: %#x ", td->td_flags);
301 	db_printf(" pflags: %#x\n", td->td_pflags);
302 	db_printf(" state: ");
303 	switch (td->td_state) {
304 	case TDS_INACTIVE:
305 		db_printf("INACTIVE\n");
306 		break;
307 	case TDS_CAN_RUN:
308 		db_printf("CAN RUN\n");
309 		break;
310 	case TDS_RUNQ:
311 		db_printf("RUNQ\n");
312 		break;
313 	case TDS_RUNNING:
314 		db_printf("RUNNING (CPU %d)\n", td->td_oncpu);
315 		break;
316 	case TDS_INHIBITED:
317 		db_printf("INHIBITED: {");
318 		comma = FALSE;
319 		if (TD_IS_SLEEPING(td)) {
320 			db_printf("SLEEPING");
321 			comma = TRUE;
322 		}
323 		if (TD_IS_SUSPENDED(td)) {
324 			if (comma)
325 				db_printf(", ");
326 			db_printf("SUSPENDED");
327 			comma = TRUE;
328 		}
329 		if (TD_IS_SWAPPED(td)) {
330 			if (comma)
331 				db_printf(", ");
332 			db_printf("SWAPPED");
333 			comma = TRUE;
334 		}
335 		if (TD_ON_LOCK(td)) {
336 			if (comma)
337 				db_printf(", ");
338 			db_printf("LOCK");
339 			comma = TRUE;
340 		}
341 		if (TD_AWAITING_INTR(td)) {
342 			if (comma)
343 				db_printf(", ");
344 			db_printf("IWAIT");
345 		}
346 		db_printf("}\n");
347 		break;
348 	default:
349 		db_printf("??? (%#x)\n", td->td_state);
350 		break;
351 	}
352 	if (TD_ON_LOCK(td))
353 		db_printf(" lock: %s  turnstile: %p\n", td->td_lockname,
354 		    td->td_blocked);
355 	if (TD_ON_SLEEPQ(td))
356 		db_printf(" wmesg: %s  wchan: %p\n", td->td_wmesg,
357 		    td->td_wchan);
358 	db_printf(" priority: %d\n", td->td_priority);
359 }
360 
361 DB_SHOW_COMMAND(proc, db_show_proc)
362 {
363 	struct thread *td;
364 	struct proc *p;
365 	int i;
366 
367 	/* Determine which process to examine. */
368 	if (have_addr)
369 		p = db_lookup_proc(addr);
370 	else
371 		p = kdb_thread->td_proc;
372 
373 	db_printf("Process %d (%s) at %p:\n", p->p_pid, p->p_comm, p);
374 	db_printf(" state: ");
375 	switch (p->p_state) {
376 	case PRS_NEW:
377 		db_printf("NEW\n");
378 		break;
379 	case PRS_NORMAL:
380 		db_printf("NORMAL\n");
381 		break;
382 	case PRS_ZOMBIE:
383 		db_printf("ZOMBIE\n");
384 		break;
385 	default:
386 		db_printf("??? (%#x)\n", p->p_state);
387 	}
388 	if (p->p_ucred != NULL) {
389 		db_printf(" uid: %d  gids: ", p->p_ucred->cr_uid);
390 		for (i = 0; i < p->p_ucred->cr_ngroups; i++) {
391 			db_printf("%d", p->p_ucred->cr_groups[i]);
392 			if (i < (p->p_ucred->cr_ngroups - 1))
393 				db_printf(", ");
394 		}
395 		db_printf("\n");
396 	}
397 	if (p->p_pptr != NULL)
398 		db_printf(" parent: pid %d at %p\n", p->p_pptr->p_pid,
399 		    p->p_pptr);
400 	if (p->p_leader != NULL && p->p_leader != p)
401 		db_printf(" leader: pid %d at %p\n", p->p_leader->p_pid,
402 		    p->p_leader);
403 	if (p->p_sysent != NULL)
404 		db_printf(" ABI: %s\n", p->p_sysent->sv_name);
405 	if (p->p_args != NULL)
406 		db_printf(" arguments: %.*s\n", (int)p->p_args->ar_length,
407 		    p->p_args->ar_args);
408 	db_printf(" threads: %d\n", p->p_numthreads);
409 	FOREACH_THREAD_IN_PROC(p, td) {
410 		dumpthread(p, td, 1);
411 		if (db_pager_quit)
412 			break;
413 	}
414 }
415