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]
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>
33 #include <stdio_ext.h>
41 #include <sys/types.h>
42 #include <sys/int_fmtio.h>
45 typedef struct look_arg
{
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);
62 static struct ps_prochandle
*Pr
;
64 static int is64
; /* Is current process 64-bit? */
65 static int rflag
; /* Show registers? */
68 (PR_STOPPED|PR_ISTOP|PR_DSTOP|PR_ASLEEP|PR_PCINVAL|PR_STEP \
69 |PR_AGENT|PR_DETACH|PR_DAEMON)
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)
78 main(int argc
, char **argv
)
85 if ((command
= strrchr(argv
[0], '/')) != NULL
)
91 while ((opt
= getopt(argc
, argv
, "r")) != EOF
) {
93 case 'r': /* show registers */
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");
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);
141 uint32_t sigtrace
, sigtrace1
, sigtrace2
, fltbits
;
142 uint32_t sigpend
, sigpend1
, sigpend2
;
144 char buf
[PRSIGBUFSZ
];
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
);
156 (void) fprintf(stderr
, "%s: cannot examine %s: %s\n",
157 command
, arg
, Pgrab_error(gcode
));
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
);
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
);
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
));
191 fltbits
= *((uint32_t *)&fltmask
);
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);
200 #error "fix me: MAXSIG out of bounds"
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])
212 "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n"
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])
223 "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n"
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);
234 #error "fix me: MAXSIG out of bounds"
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
;
242 (void) Plwp_iter_all(Pr
, (proc_lwp_all_f
*)lwplook
, &lookarg
);
244 if (lookarg
.count
== 0)
245 (void) printf("No matching lwps found");
248 Prelease(Pr
, PRELEASE_RETAIN
);
254 lwplook_zombie(const lwpsinfo_t
*pip
)
256 (void) printf(" /%d:\t<defunct>\n", (int)pip
->pr_lwpid
);
261 lwplook(look_arg_t
*arg
, const lwpstatus_t
*psp
, const lwpsinfo_t
*pip
)
264 uint32_t sighold
, sighold1
, sighold2
;
265 uint32_t sigpend
, sigpend1
, sigpend2
;
270 if (!proc_lwp_in_set(arg
->lwps
, pip
->pr_lwpid
))
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)
292 (void) printf("ASLEEP");
294 if (psp
->pr_syscall
&& !(arg
->pflags
& PR_ISSYS
)) {
297 (void) printf(" %s(",
298 proc_sysname(psp
->pr_syscall
, buf
, sizeof (buf
)));
299 for (i
= 0; i
< psp
->pr_nsysarg
; i
++) {
302 (void) printf("0x%lx", psp
->pr_sysarg
[i
]);
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
));
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);
326 #error "fix me: MAXSIG out of bounds"
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
);
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
;
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
);
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.
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
);
365 #endif /* __sparc && _ILP32 */
366 dumpregs(psp
->pr_reg
, is64
);
368 (void) printf("\tNot stopped, can't show registers\n");
377 static char code_buf
[200];
378 char *str
= code_buf
;
384 (void) sprintf(str
, "0x%x", arg
& ~ALLFLAGS
);
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");
399 (void) strcat(str
, "|ISTOP");
401 (void) strcat(str
, "|DSTOP");
402 #if 0 /* displayed elsewhere */
404 (void) strcat(str
, "|ASLEEP");
406 if (arg
& PR_PCINVAL
)
407 (void) strcat(str
, "|PCINVAL");
409 (void) strcat(str
, "|STEP");
411 (void) strcat(str
, "|AGENT");
413 (void) strcat(str
, "|ISSYS");
415 (void) strcat(str
, "|VFORKP");
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");
423 (void) strcat(str
, "|FORK");
425 (void) strcat(str
, "|RLC");
427 (void) strcat(str
, "|KLC");
429 (void) strcat(str
, "|ASYNC");
431 (void) strcat(str
, "|BPTADJ");
433 (void) strcat(str
, "|MSACCT");
435 (void) strcat(str
, "|MSFORK");
437 (void) strcat(str
, "|PTRACE");
453 str
= "PR_REQUESTED";
456 str
= "PR_SIGNALLED";
465 str
= "PR_JOBCONTROL";
471 str
= "PR_SUSPENDED";
475 (void) sprintf(str
, "%d", why
);
483 prwhat(int why
, int what
)
491 str
= proc_signame(what
, buf
, sizeof (buf
));
495 str
= proc_sysname(what
, buf
, sizeof (buf
));
498 str
= proc_fltname(what
, buf
, sizeof (buf
));
501 (void) sprintf(str
= buf
, "%d", what
);
510 static const char * const regname
[NPRGREG
] = {
511 "%r15", "%r14", "%r13", "%r12", "%r11", "%r10", " %r9", " %r8",
512 "%rdi", "%rsi", "%rbp", "%rbx", "%rdx", "%rcx", "%rax", "%trapno",
513 "%err", "%rip", " %cs", "%rfl", "%rsp", " %ss", " %fs", " %gs",
514 " %es", " %ds", "%fsbase", "%gsbase"
517 static const char * const regname32
[NPRGREG32
] = {
518 " %gs", " %fs", " %es", " %ds", "%edi", "%esi", "%ebp", "%esp",
519 "%ebx", "%edx", "%ecx", "%eax", "%trapno", "%err", "%eip", " %cs",
520 "%efl", "%uesp", " %ss"
523 /* XX64 Do we want to expose this through libproc */
525 prgregset_n_to_32(const prgreg_t
*src
, prgreg32_t
*dst
)
527 bzero(dst
, NPRGREG32
* sizeof (prgreg32_t
));
528 dst
[GS
] = src
[REG_GS
];
529 dst
[FS
] = src
[REG_FS
];
530 dst
[DS
] = src
[REG_DS
];
531 dst
[ES
] = src
[REG_ES
];
532 dst
[EDI
] = src
[REG_RDI
];
533 dst
[ESI
] = src
[REG_RSI
];
534 dst
[EBP
] = src
[REG_RBP
];
535 dst
[EBX
] = src
[REG_RBX
];
536 dst
[EDX
] = src
[REG_RDX
];
537 dst
[ECX
] = src
[REG_RCX
];
538 dst
[EAX
] = src
[REG_RAX
];
539 dst
[TRAPNO
] = src
[REG_TRAPNO
];
540 dst
[ERR
] = src
[REG_ERR
];
541 dst
[EIP
] = src
[REG_RIP
];
542 dst
[CS
] = src
[REG_CS
];
543 dst
[EFL
] = src
[REG_RFL
];
544 dst
[UESP
] = src
[REG_RSP
];
545 dst
[SS
] = src
[REG_SS
];
548 #elif defined(__i386)
549 static const char * const regname
[NPRGREG
] = {
550 " %gs", " %fs", " %es", " %ds", "%edi", "%esi", "%ebp", "%esp",
551 "%ebx", "%edx", "%ecx", "%eax", "%trapno", "%err", "%eip", " %cs",
552 "%efl", "%uesp", " %ss"
556 #if defined(__amd64) && defined(_LP64)
558 dumpregs32(const prgregset_t reg
)
563 prgregset_n_to_32(reg
, reg32
);
565 for (i
= 0; i
< NPRGREG32
; i
++) {
566 (void) printf(" %s = 0x%.8X",
567 regname32
[i
], reg32
[i
]);
569 (void) putchar('\n');
572 (void) putchar('\n');
577 dumpregs(const prgregset_t reg
, int is64
)
579 int width
= is64
? 16 : 8;
580 int cols
= is64
? 2 : 4;
583 #if defined(__amd64) && defined(_LP64)
590 for (i
= 0; i
< NPRGREG
; i
++) {
591 (void) printf(" %s = 0x%.*lX",
592 regname
[i
], width
, (long)reg
[i
]);
593 if ((i
+1) % cols
== 0)
594 (void) putchar('\n');
597 (void) putchar('\n');
600 #if defined(__sparc) && defined(_ILP32)
602 dumpregs_v8p(const prgregset_t reg
, const prxregset_t
*xreg
, int is64
)
604 static const uint32_t zero
[8] = { 0 };
605 int gr
, xr
, cols
= 2;
608 if (memcmp(xreg
->pr_un
.pr_v8p
.pr_xg
, zero
, sizeof (zero
)) == 0 &&
609 memcmp(xreg
->pr_un
.pr_v8p
.pr_xo
, zero
, sizeof (zero
)) == 0) {
614 for (gr
= R_G0
, xr
= XR_G0
; gr
<= R_G7
; gr
++, xr
++) {
615 xval
= (uint64_t)xreg
->pr_un
.pr_v8p
.pr_xg
[xr
] << 32 |
616 (uint64_t)(uint32_t)reg
[gr
];
617 (void) printf(" %s = 0x%.16" PRIX64
, regname
[gr
], xval
);
618 if ((gr
+ 1) % cols
== 0)
619 (void) putchar('\n');
622 for (gr
= R_O0
, xr
= XR_O0
; gr
<= R_O7
; gr
++, xr
++) {
623 xval
= (uint64_t)xreg
->pr_un
.pr_v8p
.pr_xo
[xr
] << 32 |
624 (uint64_t)(uint32_t)reg
[gr
];
625 (void) printf(" %s = 0x%.16" PRIX64
, regname
[gr
], xval
);
626 if ((gr
+ 1) % cols
== 0)
627 (void) putchar('\n');
630 for (gr
= R_L0
; gr
< NPRGREG
; gr
++) {
631 (void) printf(" %s = 0x%.8lX",
632 regname
[gr
], (long)reg
[gr
]);
633 if ((gr
+ 1) % cols
== 0)
634 (void) putchar('\n');
638 (void) putchar('\n');
640 #endif /* __sparc && _ILP32 */