xref: /illumos-gate/usr/src/cmd/ptools/pflags/pflags.c (revision 34bbc83afbf22a6f8e504cb99d76c97c017cb5f4)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
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 /*
23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * Copyright (c) 2013, Joyent, Inc. All rights reserved.
29  */
30 
31 #include <stdio.h>
32 #include <stdio_ext.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <ctype.h>
36 #include <fcntl.h>
37 #include <strings.h>
38 #include <dirent.h>
39 #include <errno.h>
40 #include <sys/types.h>
41 #include <sys/int_fmtio.h>
42 #include <libproc.h>
43 
44 typedef struct look_arg {
45 	int pflags;
46 	const char *lwps;
47 	int count;
48 } look_arg_t;
49 
50 static	int	look(char *);
51 static	int	lwplook(look_arg_t *, const lwpstatus_t *, const lwpsinfo_t *);
52 static	char	*prflags(int);
53 static	char	*prwhy(int);
54 static	char	*prwhat(int, int);
55 static	void	dumpregs(const prgregset_t, int);
56 
57 static	char	*command;
58 static	struct	ps_prochandle *Pr;
59 
60 static	int	is64;	/* Is current process 64-bit? */
61 static	int	rflag;	/* Show registers? */
62 
63 #define	LWPFLAGS	\
64 	(PR_STOPPED|PR_ISTOP|PR_DSTOP|PR_ASLEEP|PR_PCINVAL|PR_STEP \
65 	|PR_AGENT|PR_DETACH|PR_DAEMON)
66 
67 #define	PROCFLAGS	\
68 	(PR_ISSYS|PR_VFORKP|PR_ORPHAN|PR_NOSIGCHLD|PR_WAITPID \
69 	|PR_FORK|PR_RLC|PR_KLC|PR_ASYNC|PR_BPTADJ|PR_MSACCT|PR_MSFORK|PR_PTRACE)
70 
71 #define	ALLFLAGS	(LWPFLAGS|PROCFLAGS)
72 
73 int
74 main(int argc, char **argv)
75 {
76 	int rc = 0;
77 	int errflg = 0;
78 	int opt;
79 	struct rlimit rlim;
80 
81 	if ((command = strrchr(argv[0], '/')) != NULL)
82 		command++;
83 	else
84 		command = argv[0];
85 
86 	/* options */
87 	while ((opt = getopt(argc, argv, "r")) != EOF) {
88 		switch (opt) {
89 		case 'r':		/* show registers */
90 			rflag = 1;
91 			break;
92 		default:
93 			errflg = 1;
94 			break;
95 		}
96 	}
97 
98 	argc -= optind;
99 	argv += optind;
100 
101 	if (errflg || argc <= 0) {
102 		(void) fprintf(stderr,
103 		    "usage:\t%s [-r] { pid | core }[/lwps] ...\n", command);
104 		(void) fprintf(stderr, "  (report process status flags)\n");
105 		(void) fprintf(stderr, "  -r : report registers\n");
106 		return (2);
107 	}
108 
109 	/*
110 	 * Make sure we'll have enough file descriptors to handle a target
111 	 * that has many many mappings.
112 	 */
113 	if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
114 		rlim.rlim_cur = rlim.rlim_max;
115 		(void) setrlimit(RLIMIT_NOFILE, &rlim);
116 		(void) enable_extended_FILE_stdio(-1, -1);
117 	}
118 
119 	while (argc-- > 0)
120 		rc += look(*argv++);
121 
122 	return (rc);
123 }
124 
125 static int
126 look(char *arg)
127 {
128 	int gcode;
129 	int gcode2;
130 	pstatus_t pstatus;
131 	psinfo_t psinfo;
132 	int flags;
133 	sigset_t sigmask;
134 	fltset_t fltmask;
135 	sysset_t entryset;
136 	sysset_t exitset;
137 	uint32_t sigtrace, sigtrace1, sigtrace2, fltbits;
138 	uint32_t sigpend, sigpend1, sigpend2;
139 	uint32_t *bits;
140 	char buf[PRSIGBUFSZ];
141 	look_arg_t lookarg;
142 
143 	if ((Pr = proc_arg_xgrab(arg, NULL, PR_ARG_ANY,
144 	    PGRAB_RETAIN | PGRAB_FORCE | PGRAB_RDONLY | PGRAB_NOSTOP, &gcode,
145 	    &lookarg.lwps)) == NULL) {
146 		if (gcode == G_NOPROC &&
147 		    proc_arg_psinfo(arg, PR_ARG_PIDS, &psinfo, &gcode2) > 0 &&
148 		    psinfo.pr_nlwp == 0) {
149 			(void) printf("%d:\t<defunct>\n\n", (int)psinfo.pr_pid);
150 			return (0);
151 		}
152 		(void) fprintf(stderr, "%s: cannot examine %s: %s\n",
153 		    command, arg, Pgrab_error(gcode));
154 		return (1);
155 	}
156 
157 	(void) memcpy(&pstatus, Pstatus(Pr), sizeof (pstatus_t));
158 	(void) memcpy(&psinfo, Ppsinfo(Pr), sizeof (psinfo_t));
159 	proc_unctrl_psinfo(&psinfo);
160 
161 	if (psinfo.pr_nlwp == 0) {
162 		(void) printf("%d:\t<defunct>\n\n", (int)psinfo.pr_pid);
163 		Prelease(Pr, PRELEASE_RETAIN);
164 		return (0);
165 	}
166 
167 	is64 = (pstatus.pr_dmodel == PR_MODEL_LP64);
168 
169 	sigmask = pstatus.pr_sigtrace;
170 	fltmask = pstatus.pr_flttrace;
171 	entryset = pstatus.pr_sysentry;
172 	exitset = pstatus.pr_sysexit;
173 
174 	if (Pstate(Pr) == PS_DEAD) {
175 		(void) printf("core '%s' of %d:\t%.70s\n",
176 		    arg, (int)psinfo.pr_pid, psinfo.pr_psargs);
177 	} else {
178 		(void) printf("%d:\t%.70s\n",
179 		    (int)psinfo.pr_pid, psinfo.pr_psargs);
180 	}
181 
182 	(void) printf("\tdata model = %s", is64? "_LP64" : "_ILP32");
183 	if ((flags = (pstatus.pr_flags & PROCFLAGS)) != 0)
184 		(void) printf("  flags = %s", prflags(flags));
185 	(void) printf("\n");
186 
187 	fltbits = *((uint32_t *)&fltmask);
188 	if (fltbits)
189 		(void) printf("\tflttrace = 0x%.8x\n", fltbits);
190 
191 #if (MAXSIG > 2 * 32) && (MAXSIG <= 3 * 32)	/* assumption */
192 	sigtrace = *((uint32_t *)&sigmask);
193 	sigtrace1 = *((uint32_t *)&sigmask + 1);
194 	sigtrace2 = *((uint32_t *)&sigmask + 2);
195 #else
196 #error "fix me: MAXSIG out of bounds"
197 #endif
198 	if (sigtrace | sigtrace1 | sigtrace2)
199 		(void) printf("\tsigtrace = 0x%.8x 0x%.8x 0x%.8x\n\t    %s\n",
200 		    sigtrace, sigtrace1, sigtrace2,
201 		    proc_sigset2str(&sigmask, "|", 1, buf, sizeof (buf)));
202 
203 	bits = ((uint32_t *)&entryset);
204 	if (bits[0] | bits[1] | bits[2] | bits[3] |
205 	    bits[4] | bits[5] | bits[6] | bits[7])
206 		(void) printf(
207 		    "\tentryset = "
208 		    "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n"
209 		    "\t           "
210 		    "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n",
211 		    bits[0], bits[1], bits[2], bits[3],
212 		    bits[4], bits[5], bits[6], bits[7]);
213 
214 	bits = ((uint32_t *)&exitset);
215 	if (bits[0] | bits[1] | bits[2] | bits[3] |
216 	    bits[4] | bits[5] | bits[6] | bits[7])
217 		(void) printf(
218 		    "\texitset  = "
219 		    "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n"
220 		    "\t           "
221 		    "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n",
222 		    bits[0], bits[1], bits[2], bits[3],
223 		    bits[4], bits[5], bits[6], bits[7]);
224 
225 #if (MAXSIG > 2 * 32) && (MAXSIG <= 3 * 32)	/* assumption */
226 	sigpend  = *((uint32_t *)&pstatus.pr_sigpend);
227 	sigpend1 = *((uint32_t *)&pstatus.pr_sigpend + 1);
228 	sigpend2 = *((uint32_t *)&pstatus.pr_sigpend + 2);
229 #else
230 #error "fix me: MAXSIG out of bounds"
231 #endif
232 	if (sigpend | sigpend1 | sigpend2)
233 		(void) printf("\tsigpend = 0x%.8x,0x%.8x,0x%.8x\n",
234 		    sigpend, sigpend1, sigpend2);
235 
236 	lookarg.pflags = pstatus.pr_flags;
237 	lookarg.count = 0;
238 	(void) Plwp_iter_all(Pr, (proc_lwp_all_f *)lwplook, &lookarg);
239 
240 	if (lookarg.count == 0)
241 		(void) printf("No matching lwps found");
242 
243 	(void) printf("\n");
244 	Prelease(Pr, PRELEASE_RETAIN);
245 
246 	return (0);
247 }
248 
249 static int
250 lwplook_zombie(const lwpsinfo_t *pip)
251 {
252 	(void) printf(" /%d:\t<defunct>\n", (int)pip->pr_lwpid);
253 	return (0);
254 }
255 
256 static int
257 lwplook(look_arg_t *arg, const lwpstatus_t *psp, const lwpsinfo_t *pip)
258 {
259 	int flags;
260 	uint32_t sighold, sighold1, sighold2;
261 	uint32_t sigpend, sigpend1, sigpend2;
262 	psinfo_t ps;
263 	int cursig;
264 	char buf[32];
265 
266 	if (!proc_lwp_in_set(arg->lwps, pip->pr_lwpid))
267 		return (0);
268 
269 	arg->count++;
270 
271 	if (psp == NULL)
272 		return (lwplook_zombie(pip));
273 
274 	/*
275 	 * PR_PCINVAL is just noise if the lwp is not stopped.
276 	 * Don't bother reporting it unless the lwp is stopped.
277 	 */
278 	flags = psp->pr_flags & LWPFLAGS;
279 	if (!(flags & PR_STOPPED))
280 		flags &= ~PR_PCINVAL;
281 
282 	(void) printf(" /%d:\tflags = %s", (int)psp->pr_lwpid, prflags(flags));
283 	if ((flags & PR_ASLEEP) || (psp->pr_syscall &&
284 	    !(arg->pflags & PR_ISSYS))) {
285 		if (flags & PR_ASLEEP) {
286 			if ((flags & ~PR_ASLEEP) != 0)
287 				(void) printf("|");
288 			(void) printf("ASLEEP");
289 		}
290 		if (psp->pr_syscall && !(arg->pflags & PR_ISSYS)) {
291 			uint_t i;
292 
293 			(void) printf("  %s(",
294 			    proc_sysname(psp->pr_syscall, buf, sizeof (buf)));
295 			for (i = 0; i < psp->pr_nsysarg; i++) {
296 				if (i != 0)
297 					(void) printf(",");
298 				(void) printf("0x%lx", psp->pr_sysarg[i]);
299 			}
300 			(void) printf(")");
301 		}
302 	}
303 	(void) printf("\n");
304 
305 	if (flags & PR_STOPPED) {
306 		(void) printf("\twhy = %s", prwhy(psp->pr_why));
307 		if (psp->pr_why != PR_REQUESTED &&
308 		    psp->pr_why != PR_SUSPENDED)
309 			(void) printf("  what = %s",
310 			    prwhat(psp->pr_why, psp->pr_what));
311 		(void) printf("\n");
312 	}
313 
314 #if (MAXSIG > 2 * 32) && (MAXSIG <= 3 * 32)	/* assumption */
315 	sighold  = *((uint32_t *)&psp->pr_lwphold);
316 	sighold1 = *((uint32_t *)&psp->pr_lwphold + 1);
317 	sighold2 = *((uint32_t *)&psp->pr_lwphold + 2);
318 	sigpend  = *((uint32_t *)&psp->pr_lwppend);
319 	sigpend1 = *((uint32_t *)&psp->pr_lwppend + 1);
320 	sigpend2 = *((uint32_t *)&psp->pr_lwppend + 2);
321 #else
322 #error "fix me: MAXSIG out of bounds"
323 #endif
324 	cursig   = psp->pr_cursig;
325 
326 	if (sighold | sighold1 | sighold2)
327 		(void) printf("\tsigmask = 0x%.8x,0x%.8x,0x%.8x\n",
328 		    sighold, sighold1, sighold2);
329 	if (sigpend | sigpend1 | sigpend2)
330 		(void) printf("\tlwppend = 0x%.8x,0x%.8x,0x%.8x\n",
331 		    sigpend, sigpend1, sigpend2);
332 	if (cursig)
333 		(void) printf("\tcursig = %s\n",
334 		    proc_signame(cursig, buf, sizeof (buf)));
335 
336 	if ((flags & PR_AGENT) &&
337 	    Plwp_getspymaster(Pr, pip->pr_lwpid, &ps) == 0) {
338 		time_t time = ps.pr_time.tv_sec;
339 		char t[64];
340 
341 		(void) strftime(t, sizeof (t), "%F:%H.%M.%S", localtime(&time));
342 
343 		(void) printf("\tspymaster = pid %d, \"%s\" at %s\n",
344 		    (int)ps.pr_pid, ps.pr_psargs, t);
345 	}
346 
347 	if (rflag) {
348 		if (Pstate(Pr) == PS_DEAD || (arg->pflags & PR_STOPPED)) {
349 			dumpregs(psp->pr_reg, is64);
350 		} else {
351 			(void) printf("\tNot stopped, can't show registers\n");
352 		}
353 	}
354 
355 	return (0);
356 }
357 
358 static char *
359 prflags(int arg)
360 {
361 	static char code_buf[200];
362 	char *str = code_buf;
363 
364 	if (arg == 0)
365 		return ("0");
366 
367 	if (arg & ~ALLFLAGS)
368 		(void) sprintf(str, "0x%x", arg & ~ALLFLAGS);
369 	else
370 		*str = '\0';
371 
372 	/*
373 	 * Display the semi-permanent lwp flags first.
374 	 */
375 	if (arg & PR_DAEMON)		/* daemons are always detached so */
376 		(void) strcat(str, "|DAEMON");
377 	else if (arg & PR_DETACH)	/* report detach only if non-daemon */
378 		(void) strcat(str, "|DETACH");
379 
380 	if (arg & PR_STOPPED)
381 		(void) strcat(str, "|STOPPED");
382 	if (arg & PR_ISTOP)
383 		(void) strcat(str, "|ISTOP");
384 	if (arg & PR_DSTOP)
385 		(void) strcat(str, "|DSTOP");
386 #if 0		/* displayed elsewhere */
387 	if (arg & PR_ASLEEP)
388 		(void) strcat(str, "|ASLEEP");
389 #endif
390 	if (arg & PR_PCINVAL)
391 		(void) strcat(str, "|PCINVAL");
392 	if (arg & PR_STEP)
393 		(void) strcat(str, "|STEP");
394 	if (arg & PR_AGENT)
395 		(void) strcat(str, "|AGENT");
396 	if (arg & PR_ISSYS)
397 		(void) strcat(str, "|ISSYS");
398 	if (arg & PR_VFORKP)
399 		(void) strcat(str, "|VFORKP");
400 	if (arg & PR_ORPHAN)
401 		(void) strcat(str, "|ORPHAN");
402 	if (arg & PR_NOSIGCHLD)
403 		(void) strcat(str, "|NOSIGCHLD");
404 	if (arg & PR_WAITPID)
405 		(void) strcat(str, "|WAITPID");
406 	if (arg & PR_FORK)
407 		(void) strcat(str, "|FORK");
408 	if (arg & PR_RLC)
409 		(void) strcat(str, "|RLC");
410 	if (arg & PR_KLC)
411 		(void) strcat(str, "|KLC");
412 	if (arg & PR_ASYNC)
413 		(void) strcat(str, "|ASYNC");
414 	if (arg & PR_BPTADJ)
415 		(void) strcat(str, "|BPTADJ");
416 	if (arg & PR_MSACCT)
417 		(void) strcat(str, "|MSACCT");
418 	if (arg & PR_MSFORK)
419 		(void) strcat(str, "|MSFORK");
420 	if (arg & PR_PTRACE)
421 		(void) strcat(str, "|PTRACE");
422 
423 	if (*str == '|')
424 		str++;
425 
426 	return (str);
427 }
428 
429 static char *
430 prwhy(int why)
431 {
432 	static char buf[20];
433 	char *str;
434 
435 	switch (why) {
436 	case PR_REQUESTED:
437 		str = "PR_REQUESTED";
438 		break;
439 	case PR_SIGNALLED:
440 		str = "PR_SIGNALLED";
441 		break;
442 	case PR_SYSENTRY:
443 		str = "PR_SYSENTRY";
444 		break;
445 	case PR_SYSEXIT:
446 		str = "PR_SYSEXIT";
447 		break;
448 	case PR_JOBCONTROL:
449 		str = "PR_JOBCONTROL";
450 		break;
451 	case PR_FAULTED:
452 		str = "PR_FAULTED";
453 		break;
454 	case PR_SUSPENDED:
455 		str = "PR_SUSPENDED";
456 		break;
457 	default:
458 		str = buf;
459 		(void) sprintf(str, "%d", why);
460 		break;
461 	}
462 
463 	return (str);
464 }
465 
466 static char *
467 prwhat(int why, int what)
468 {
469 	static char buf[32];
470 	char *str;
471 
472 	switch (why) {
473 	case PR_SIGNALLED:
474 	case PR_JOBCONTROL:
475 		str = proc_signame(what, buf, sizeof (buf));
476 		break;
477 	case PR_SYSENTRY:
478 	case PR_SYSEXIT:
479 		str = proc_sysname(what, buf, sizeof (buf));
480 		break;
481 	case PR_FAULTED:
482 		str = proc_fltname(what, buf, sizeof (buf));
483 		break;
484 	default:
485 		(void) sprintf(str = buf, "%d", what);
486 		break;
487 	}
488 
489 	return (str);
490 }
491 
492 #if defined(__amd64)
493 static const char * const regname[NPRGREG] = {
494 	"%r15", "%r14", "%r13", "%r12", "%r11", "%r10", " %r9", " %r8",
495 	"%rdi", "%rsi", "%rbp", "%rbx", "%rdx", "%rcx", "%rax", "%trapno",
496 	"%err", "%rip", " %cs", "%rfl", "%rsp", " %ss", " %fs", " %gs",
497 	" %es", " %ds", "%fsbase", "%gsbase"
498 };
499 
500 static const char * const regname32[NPRGREG32] = {
501 	" %gs", " %fs", " %es", " %ds", "%edi", "%esi", "%ebp", "%esp",
502 	"%ebx", "%edx", "%ecx", "%eax", "%trapno", "%err", "%eip", " %cs",
503 	"%efl", "%uesp", " %ss"
504 };
505 
506 /* XX64 Do we want to expose this through libproc */
507 void
508 prgregset_n_to_32(const prgreg_t *src, prgreg32_t *dst)
509 {
510 	bzero(dst, NPRGREG32 * sizeof (prgreg32_t));
511 	dst[GS] = src[REG_GS];
512 	dst[FS] = src[REG_FS];
513 	dst[DS] = src[REG_DS];
514 	dst[ES] = src[REG_ES];
515 	dst[EDI] = src[REG_RDI];
516 	dst[ESI] = src[REG_RSI];
517 	dst[EBP] = src[REG_RBP];
518 	dst[EBX] = src[REG_RBX];
519 	dst[EDX] = src[REG_RDX];
520 	dst[ECX] = src[REG_RCX];
521 	dst[EAX] = src[REG_RAX];
522 	dst[TRAPNO] = src[REG_TRAPNO];
523 	dst[ERR] = src[REG_ERR];
524 	dst[EIP] = src[REG_RIP];
525 	dst[CS] = src[REG_CS];
526 	dst[EFL] = src[REG_RFL];
527 	dst[UESP] = src[REG_RSP];
528 	dst[SS] = src[REG_SS];
529 }
530 
531 #elif defined(__i386)
532 static const char * const regname[NPRGREG] = {
533 	" %gs", " %fs", " %es", " %ds", "%edi", "%esi", "%ebp", "%esp",
534 	"%ebx", "%edx", "%ecx", "%eax", "%trapno", "%err", "%eip", " %cs",
535 	"%efl", "%uesp", " %ss"
536 };
537 #endif /* __i386 */
538 
539 #if defined(__amd64)
540 static void
541 dumpregs32(const prgregset_t reg)
542 {
543 	prgregset32_t reg32;
544 	int i;
545 
546 	prgregset_n_to_32(reg, reg32);
547 
548 	for (i = 0; i < NPRGREG32; i++) {
549 		(void) printf("  %s = 0x%.8X",
550 		    regname32[i], reg32[i]);
551 		if ((i+1) % 4 == 0)
552 			(void) putchar('\n');
553 	}
554 	if (i % 4 != 0)
555 		(void) putchar('\n');
556 }
557 #endif	/* __amd64 */
558 
559 static void
560 dumpregs(const prgregset_t reg, int is64)
561 {
562 	int width = is64? 16 : 8;
563 	int cols = is64? 2 : 4;
564 	int i;
565 
566 #if defined(__amd64)
567 	if (!is64) {
568 		dumpregs32(reg);
569 		return;
570 	}
571 #endif	/* __amd64 */
572 
573 	for (i = 0; i < NPRGREG; i++) {
574 		(void) printf("  %s = 0x%.*lX",
575 		    regname[i], width, (long)reg[i]);
576 		if ((i+1) % cols == 0)
577 			(void) putchar('\n');
578 	}
579 	if (i % cols != 0)
580 		(void) putchar('\n');
581 }
582