control legacy uname with an environment variable
[unleashed.git] / usr / src / cmd / ptools / pflags / pflags.c
blobda3e812b5c8199ac0aff5ce024c791f0d3e884ea
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Copyright (c) 2013, Joyent, Inc. All rights reserved.
29 * Copyright 2014 Garrett D'Amore <garrett@damore.org>
32 #include <stdio.h>
33 #include <stdio_ext.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <ctype.h>
37 #include <fcntl.h>
38 #include <strings.h>
39 #include <dirent.h>
40 #include <errno.h>
41 #include <sys/types.h>
42 #include <sys/int_fmtio.h>
43 #include <libproc.h>
45 typedef struct look_arg {
46 int pflags;
47 const char *lwps;
48 int count;
49 } look_arg_t;
51 static int look(char *);
52 static int lwplook(look_arg_t *, const lwpstatus_t *, const lwpsinfo_t *);
53 static char *prflags(int);
54 static char *prwhy(int);
55 static char *prwhat(int, int);
56 static void dumpregs(const prgregset_t, int);
57 #if defined(__sparc) && defined(_ILP32)
58 static void dumpregs_v8p(const prgregset_t, const prxregset_t *, int);
59 #endif
61 static char *command;
62 static struct ps_prochandle *Pr;
64 static int is64; /* Is current process 64-bit? */
65 static int rflag; /* Show registers? */
67 #define LWPFLAGS \
68 (PR_STOPPED|PR_ISTOP|PR_DSTOP|PR_ASLEEP|PR_PCINVAL|PR_STEP \
69 |PR_AGENT|PR_DETACH|PR_DAEMON)
71 #define PROCFLAGS \
72 (PR_ISSYS|PR_VFORKP|PR_ORPHAN|PR_NOSIGCHLD|PR_WAITPID|PR_FORK|PR_RLC \
73 |PR_KLC|PR_ASYNC|PR_BPTADJ|PR_MSACCT|PR_MSFORK|PR_PTRACE)
75 #define ALLFLAGS (LWPFLAGS|PROCFLAGS)
77 int
78 main(int argc, char **argv)
80 int rc = 0;
81 int errflg = 0;
82 int opt;
83 struct rlimit rlim;
85 if ((command = strrchr(argv[0], '/')) != NULL)
86 command++;
87 else
88 command = argv[0];
90 /* options */
91 while ((opt = getopt(argc, argv, "r")) != EOF) {
92 switch (opt) {
93 case 'r': /* show registers */
94 rflag = 1;
95 break;
96 default:
97 errflg = 1;
98 break;
102 argc -= optind;
103 argv += optind;
105 if (errflg || argc <= 0) {
106 (void) fprintf(stderr,
107 "usage:\t%s [-r] { pid | core }[/lwps] ...\n", command);
108 (void) fprintf(stderr, " (report process status flags)\n");
109 (void) fprintf(stderr, " -r : report registers\n");
110 return (2);
114 * Make sure we'll have enough file descriptors to handle a target
115 * that has many many mappings.
117 if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
118 rlim.rlim_cur = rlim.rlim_max;
119 (void) setrlimit(RLIMIT_NOFILE, &rlim);
120 (void) enable_extended_FILE_stdio(-1, -1);
123 while (argc-- > 0)
124 rc += look(*argv++);
126 return (rc);
129 static int
130 look(char *arg)
132 int gcode;
133 int gcode2;
134 pstatus_t pstatus;
135 psinfo_t psinfo;
136 int flags;
137 sigset_t sigmask;
138 fltset_t fltmask;
139 sysset_t entryset;
140 sysset_t exitset;
141 uint32_t sigtrace, sigtrace1, sigtrace2, fltbits;
142 uint32_t sigpend, sigpend1, sigpend2;
143 uint32_t *bits;
144 char buf[PRSIGBUFSZ];
145 look_arg_t lookarg;
147 if ((Pr = proc_arg_xgrab(arg, NULL, PR_ARG_ANY,
148 PGRAB_RETAIN | PGRAB_FORCE | PGRAB_RDONLY | PGRAB_NOSTOP, &gcode,
149 &lookarg.lwps)) == NULL) {
150 if (gcode == G_NOPROC &&
151 proc_arg_psinfo(arg, PR_ARG_PIDS, &psinfo, &gcode2) > 0 &&
152 psinfo.pr_nlwp == 0) {
153 (void) printf("%d:\t<defunct>\n\n", (int)psinfo.pr_pid);
154 return (0);
156 (void) fprintf(stderr, "%s: cannot examine %s: %s\n",
157 command, arg, Pgrab_error(gcode));
158 return (1);
161 (void) memcpy(&pstatus, Pstatus(Pr), sizeof (pstatus_t));
162 (void) memcpy(&psinfo, Ppsinfo(Pr), sizeof (psinfo_t));
163 proc_unctrl_psinfo(&psinfo);
165 if (psinfo.pr_nlwp == 0) {
166 (void) printf("%d:\t<defunct>\n\n", (int)psinfo.pr_pid);
167 Prelease(Pr, PRELEASE_RETAIN);
168 return (0);
171 is64 = (pstatus.pr_dmodel == PR_MODEL_LP64);
173 sigmask = pstatus.pr_sigtrace;
174 fltmask = pstatus.pr_flttrace;
175 entryset = pstatus.pr_sysentry;
176 exitset = pstatus.pr_sysexit;
178 if (Pstate(Pr) == PS_DEAD) {
179 (void) printf("core '%s' of %d:\t%.70s\n",
180 arg, (int)psinfo.pr_pid, psinfo.pr_psargs);
181 } else {
182 (void) printf("%d:\t%.70s\n",
183 (int)psinfo.pr_pid, psinfo.pr_psargs);
186 (void) printf("\tdata model = %s", is64? "_LP64" : "_ILP32");
187 if ((flags = (pstatus.pr_flags & PROCFLAGS)) != 0)
188 (void) printf(" flags = %s", prflags(flags));
189 (void) printf("\n");
191 fltbits = *((uint32_t *)&fltmask);
192 if (fltbits)
193 (void) printf("\tflttrace = 0x%.8x\n", fltbits);
195 #if (MAXSIG > 2 * 32) && (MAXSIG <= 3 * 32) /* assumption */
196 sigtrace = *((uint32_t *)&sigmask);
197 sigtrace1 = *((uint32_t *)&sigmask + 1);
198 sigtrace2 = *((uint32_t *)&sigmask + 2);
199 #else
200 #error "fix me: MAXSIG out of bounds"
201 #endif
202 if (sigtrace | sigtrace1 | sigtrace2)
203 (void) printf("\tsigtrace = 0x%.8x 0x%.8x 0x%.8x\n\t %s\n",
204 sigtrace, sigtrace1, sigtrace2,
205 proc_sigset2str(&sigmask, "|", 1, buf, sizeof (buf)));
207 bits = ((uint32_t *)&entryset);
208 if (bits[0] | bits[1] | bits[2] | bits[3] |
209 bits[4] | bits[5] | bits[6] | bits[7])
210 (void) printf(
211 "\tentryset = "
212 "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n"
213 "\t "
214 "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n",
215 bits[0], bits[1], bits[2], bits[3],
216 bits[4], bits[5], bits[6], bits[7]);
218 bits = ((uint32_t *)&exitset);
219 if (bits[0] | bits[1] | bits[2] | bits[3] |
220 bits[4] | bits[5] | bits[6] | bits[7])
221 (void) printf(
222 "\texitset = "
223 "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n"
224 "\t "
225 "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n",
226 bits[0], bits[1], bits[2], bits[3],
227 bits[4], bits[5], bits[6], bits[7]);
229 #if (MAXSIG > 2 * 32) && (MAXSIG <= 3 * 32) /* assumption */
230 sigpend = *((uint32_t *)&pstatus.pr_sigpend);
231 sigpend1 = *((uint32_t *)&pstatus.pr_sigpend + 1);
232 sigpend2 = *((uint32_t *)&pstatus.pr_sigpend + 2);
233 #else
234 #error "fix me: MAXSIG out of bounds"
235 #endif
236 if (sigpend | sigpend1 | sigpend2)
237 (void) printf("\tsigpend = 0x%.8x,0x%.8x,0x%.8x\n",
238 sigpend, sigpend1, sigpend2);
240 lookarg.pflags = pstatus.pr_flags;
241 lookarg.count = 0;
242 (void) Plwp_iter_all(Pr, (proc_lwp_all_f *)lwplook, &lookarg);
244 if (lookarg.count == 0)
245 (void) printf("No matching lwps found");
247 (void) printf("\n");
248 Prelease(Pr, PRELEASE_RETAIN);
250 return (0);
253 static int
254 lwplook_zombie(const lwpsinfo_t *pip)
256 (void) printf(" /%d:\t<defunct>\n", (int)pip->pr_lwpid);
257 return (0);
260 static int
261 lwplook(look_arg_t *arg, const lwpstatus_t *psp, const lwpsinfo_t *pip)
263 int flags;
264 uint32_t sighold, sighold1, sighold2;
265 uint32_t sigpend, sigpend1, sigpend2;
266 psinfo_t ps;
267 int cursig;
268 char buf[32];
270 if (!proc_lwp_in_set(arg->lwps, pip->pr_lwpid))
271 return (0);
273 arg->count++;
275 if (psp == NULL)
276 return (lwplook_zombie(pip));
279 * PR_PCINVAL is just noise if the lwp is not stopped.
280 * Don't bother reporting it unless the lwp is stopped.
282 flags = psp->pr_flags & LWPFLAGS;
283 if (!(flags & PR_STOPPED))
284 flags &= ~PR_PCINVAL;
286 (void) printf(" /%d:\tflags = %s", (int)psp->pr_lwpid, prflags(flags));
287 if ((flags & PR_ASLEEP) || (psp->pr_syscall &&
288 !(arg->pflags & PR_ISSYS))) {
289 if (flags & PR_ASLEEP) {
290 if ((flags & ~PR_ASLEEP) != 0)
291 (void) printf("|");
292 (void) printf("ASLEEP");
294 if (psp->pr_syscall && !(arg->pflags & PR_ISSYS)) {
295 uint_t i;
297 (void) printf(" %s(",
298 proc_sysname(psp->pr_syscall, buf, sizeof (buf)));
299 for (i = 0; i < psp->pr_nsysarg; i++) {
300 if (i != 0)
301 (void) printf(",");
302 (void) printf("0x%lx", psp->pr_sysarg[i]);
304 (void) printf(")");
307 (void) printf("\n");
309 if (flags & PR_STOPPED) {
310 (void) printf("\twhy = %s", prwhy(psp->pr_why));
311 if (psp->pr_why != PR_REQUESTED &&
312 psp->pr_why != PR_SUSPENDED)
313 (void) printf(" what = %s",
314 prwhat(psp->pr_why, psp->pr_what));
315 (void) printf("\n");
318 #if (MAXSIG > 2 * 32) && (MAXSIG <= 3 * 32) /* assumption */
319 sighold = *((uint32_t *)&psp->pr_lwphold);
320 sighold1 = *((uint32_t *)&psp->pr_lwphold + 1);
321 sighold2 = *((uint32_t *)&psp->pr_lwphold + 2);
322 sigpend = *((uint32_t *)&psp->pr_lwppend);
323 sigpend1 = *((uint32_t *)&psp->pr_lwppend + 1);
324 sigpend2 = *((uint32_t *)&psp->pr_lwppend + 2);
325 #else
326 #error "fix me: MAXSIG out of bounds"
327 #endif
328 cursig = psp->pr_cursig;
330 if (sighold | sighold1 | sighold2)
331 (void) printf("\tsigmask = 0x%.8x,0x%.8x,0x%.8x\n",
332 sighold, sighold1, sighold2);
333 if (sigpend | sigpend1 | sigpend2)
334 (void) printf("\tlwppend = 0x%.8x,0x%.8x,0x%.8x\n",
335 sigpend, sigpend1, sigpend2);
336 if (cursig)
337 (void) printf("\tcursig = %s\n",
338 proc_signame(cursig, buf, sizeof (buf)));
340 if ((flags & PR_AGENT) &&
341 Plwp_getspymaster(Pr, pip->pr_lwpid, &ps) == 0) {
342 time_t time = ps.pr_time.tv_sec;
343 char t[64];
345 (void) strftime(t, sizeof (t), "%F:%H.%M.%S", localtime(&time));
347 (void) printf("\tspymaster = pid %d, \"%s\" at %s\n",
348 (int)ps.pr_pid, ps.pr_psargs, t);
351 if (rflag) {
352 if (Pstate(Pr) == PS_DEAD || (arg->pflags & PR_STOPPED)) {
353 #if defined(__sparc) && defined(_ILP32)
355 * If we're SPARC/32-bit, see if we can get extra
356 * register state for this lwp. If it's a v8plus
357 * program, print the 64-bit register values.
359 prxregset_t prx;
361 if (Plwp_getxregs(Pr, psp->pr_lwpid, &prx) == 0 &&
362 prx.pr_type == XR_TYPE_V8P)
363 dumpregs_v8p(psp->pr_reg, &prx, is64);
364 else
365 #endif /* __sparc && _ILP32 */
366 dumpregs(psp->pr_reg, is64);
367 } else
368 (void) printf("\tNot stopped, can't show registers\n");
371 return (0);
374 static char *
375 prflags(int arg)
377 static char code_buf[200];
378 char *str = code_buf;
380 if (arg == 0)
381 return ("0");
383 if (arg & ~ALLFLAGS)
384 (void) sprintf(str, "0x%x", arg & ~ALLFLAGS);
385 else
386 *str = '\0';
389 * Display the semi-permanent lwp flags first.
391 if (arg & PR_DAEMON) /* daemons are always detached so */
392 (void) strcat(str, "|DAEMON");
393 else if (arg & PR_DETACH) /* report detach only if non-daemon */
394 (void) strcat(str, "|DETACH");
396 if (arg & PR_STOPPED)
397 (void) strcat(str, "|STOPPED");
398 if (arg & PR_ISTOP)
399 (void) strcat(str, "|ISTOP");
400 if (arg & PR_DSTOP)
401 (void) strcat(str, "|DSTOP");
402 #if 0 /* displayed elsewhere */
403 if (arg & PR_ASLEEP)
404 (void) strcat(str, "|ASLEEP");
405 #endif
406 if (arg & PR_PCINVAL)
407 (void) strcat(str, "|PCINVAL");
408 if (arg & PR_STEP)
409 (void) strcat(str, "|STEP");
410 if (arg & PR_AGENT)
411 (void) strcat(str, "|AGENT");
412 if (arg & PR_ISSYS)
413 (void) strcat(str, "|ISSYS");
414 if (arg & PR_VFORKP)
415 (void) strcat(str, "|VFORKP");
416 if (arg & PR_ORPHAN)
417 (void) strcat(str, "|ORPHAN");
418 if (arg & PR_NOSIGCHLD)
419 (void) strcat(str, "|NOSIGCHLD");
420 if (arg & PR_WAITPID)
421 (void) strcat(str, "|WAITPID");
422 if (arg & PR_FORK)
423 (void) strcat(str, "|FORK");
424 if (arg & PR_RLC)
425 (void) strcat(str, "|RLC");
426 if (arg & PR_KLC)
427 (void) strcat(str, "|KLC");
428 if (arg & PR_ASYNC)
429 (void) strcat(str, "|ASYNC");
430 if (arg & PR_BPTADJ)
431 (void) strcat(str, "|BPTADJ");
432 if (arg & PR_MSACCT)
433 (void) strcat(str, "|MSACCT");
434 if (arg & PR_MSFORK)
435 (void) strcat(str, "|MSFORK");
436 if (arg & PR_PTRACE)
437 (void) strcat(str, "|PTRACE");
439 if (*str == '|')
440 str++;
442 return (str);
445 static char *
446 prwhy(int why)
448 static char buf[20];
449 char *str;
451 switch (why) {
452 case PR_REQUESTED:
453 str = "PR_REQUESTED";
454 break;
455 case PR_SIGNALLED:
456 str = "PR_SIGNALLED";
457 break;
458 case PR_SYSENTRY:
459 str = "PR_SYSENTRY";
460 break;
461 case PR_SYSEXIT:
462 str = "PR_SYSEXIT";
463 break;
464 case PR_JOBCONTROL:
465 str = "PR_JOBCONTROL";
466 break;
467 case PR_FAULTED:
468 str = "PR_FAULTED";
469 break;
470 case PR_SUSPENDED:
471 str = "PR_SUSPENDED";
472 break;
473 default:
474 str = buf;
475 (void) sprintf(str, "%d", why);
476 break;
479 return (str);
482 static char *
483 prwhat(int why, int what)
485 static char buf[32];
486 char *str;
488 switch (why) {
489 case PR_SIGNALLED:
490 case PR_JOBCONTROL:
491 str = proc_signame(what, buf, sizeof (buf));
492 break;
493 case PR_SYSENTRY:
494 case PR_SYSEXIT:
495 str = proc_sysname(what, buf, sizeof (buf));
496 break;
497 case PR_FAULTED:
498 str = proc_fltname(what, buf, sizeof (buf));
499 break;
500 default:
501 (void) sprintf(str = buf, "%d", what);
502 break;
505 return (str);
508 #if defined(__sparc)
509 static const char * const regname[NPRGREG] = {
510 " %g0", " %g1", " %g2", " %g3", " %g4", " %g5", " %g6", " %g7",
511 " %o0", " %o1", " %o2", " %o3", " %o4", " %o5", " %sp", " %o7",
512 " %l0", " %l1", " %l2", " %l3", " %l4", " %l5", " %l6", " %l7",
513 " %i0", " %i1", " %i2", " %i3", " %i4", " %i5", " %fp", " %i7",
514 #ifdef __sparcv9
515 "%ccr", " %pc", "%npc", " %y", "%asi", "%fprs"
516 #else
517 "%psr", " %pc", "%npc", " %y", "%wim", "%tbr"
518 #endif
520 #endif /* __sparc */
522 #if defined(__amd64)
523 static const char * const regname[NPRGREG] = {
524 "%r15", "%r14", "%r13", "%r12", "%r11", "%r10", " %r9", " %r8",
525 "%rdi", "%rsi", "%rbp", "%rbx", "%rdx", "%rcx", "%rax", "%trapno",
526 "%err", "%rip", " %cs", "%rfl", "%rsp", " %ss", " %fs", " %gs",
527 " %es", " %ds", "%fsbase", "%gsbase"
530 static const char * const regname32[NPRGREG32] = {
531 " %gs", " %fs", " %es", " %ds", "%edi", "%esi", "%ebp", "%esp",
532 "%ebx", "%edx", "%ecx", "%eax", "%trapno", "%err", "%eip", " %cs",
533 "%efl", "%uesp", " %ss"
536 /* XX64 Do we want to expose this through libproc */
537 void
538 prgregset_n_to_32(const prgreg_t *src, prgreg32_t *dst)
540 bzero(dst, NPRGREG32 * sizeof (prgreg32_t));
541 dst[GS] = src[REG_GS];
542 dst[FS] = src[REG_FS];
543 dst[DS] = src[REG_DS];
544 dst[ES] = src[REG_ES];
545 dst[EDI] = src[REG_RDI];
546 dst[ESI] = src[REG_RSI];
547 dst[EBP] = src[REG_RBP];
548 dst[EBX] = src[REG_RBX];
549 dst[EDX] = src[REG_RDX];
550 dst[ECX] = src[REG_RCX];
551 dst[EAX] = src[REG_RAX];
552 dst[TRAPNO] = src[REG_TRAPNO];
553 dst[ERR] = src[REG_ERR];
554 dst[EIP] = src[REG_RIP];
555 dst[CS] = src[REG_CS];
556 dst[EFL] = src[REG_RFL];
557 dst[UESP] = src[REG_RSP];
558 dst[SS] = src[REG_SS];
561 #elif defined(__i386)
562 static const char * const regname[NPRGREG] = {
563 " %gs", " %fs", " %es", " %ds", "%edi", "%esi", "%ebp", "%esp",
564 "%ebx", "%edx", "%ecx", "%eax", "%trapno", "%err", "%eip", " %cs",
565 "%efl", "%uesp", " %ss"
567 #endif /* __i386 */
569 #if defined(__amd64) && defined(_LP64)
570 static void
571 dumpregs32(const prgregset_t reg)
573 prgregset32_t reg32;
574 int i;
576 prgregset_n_to_32(reg, reg32);
578 for (i = 0; i < NPRGREG32; i++) {
579 (void) printf(" %s = 0x%.8X",
580 regname32[i], reg32[i]);
581 if ((i+1) % 4 == 0)
582 (void) putchar('\n');
584 if (i % 4 != 0)
585 (void) putchar('\n');
587 #endif
589 static void
590 dumpregs(const prgregset_t reg, int is64)
592 int width = is64? 16 : 8;
593 int cols = is64? 2 : 4;
594 int i;
596 #if defined(__amd64) && defined(_LP64)
597 if (!is64) {
598 dumpregs32(reg);
599 return;
601 #endif
603 for (i = 0; i < NPRGREG; i++) {
604 (void) printf(" %s = 0x%.*lX",
605 regname[i], width, (long)reg[i]);
606 if ((i+1) % cols == 0)
607 (void) putchar('\n');
609 if (i % cols != 0)
610 (void) putchar('\n');
613 #if defined(__sparc) && defined(_ILP32)
614 static void
615 dumpregs_v8p(const prgregset_t reg, const prxregset_t *xreg, int is64)
617 static const uint32_t zero[8] = { 0 };
618 int gr, xr, cols = 2;
619 uint64_t xval;
621 if (memcmp(xreg->pr_un.pr_v8p.pr_xg, zero, sizeof (zero)) == 0 &&
622 memcmp(xreg->pr_un.pr_v8p.pr_xo, zero, sizeof (zero)) == 0) {
623 dumpregs(reg, is64);
624 return;
627 for (gr = R_G0, xr = XR_G0; gr <= R_G7; gr++, xr++) {
628 xval = (uint64_t)xreg->pr_un.pr_v8p.pr_xg[xr] << 32 |
629 (uint64_t)(uint32_t)reg[gr];
630 (void) printf(" %s = 0x%.16" PRIX64, regname[gr], xval);
631 if ((gr + 1) % cols == 0)
632 (void) putchar('\n');
635 for (gr = R_O0, xr = XR_O0; gr <= R_O7; gr++, xr++) {
636 xval = (uint64_t)xreg->pr_un.pr_v8p.pr_xo[xr] << 32 |
637 (uint64_t)(uint32_t)reg[gr];
638 (void) printf(" %s = 0x%.16" PRIX64, regname[gr], xval);
639 if ((gr + 1) % cols == 0)
640 (void) putchar('\n');
643 for (gr = R_L0; gr < NPRGREG; gr++) {
644 (void) printf(" %s = 0x%.8lX",
645 regname[gr], (long)reg[gr]);
646 if ((gr + 1) % cols == 0)
647 (void) putchar('\n');
650 if (gr % cols != 0)
651 (void) putchar('\n');
653 #endif /* __sparc && _ILP32 */