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.
32 #include <stdio_ext.h>
40 #include <sys/types.h>
41 #include <sys/int_fmtio.h>
44 typedef struct look_arg
{
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 #if defined(__sparc) && defined(_ILP32)
57 static void dumpregs_v8p(const prgregset_t
, const prxregset_t
*, int);
61 static struct ps_prochandle
*Pr
;
63 static int is64
; /* Is current process 64-bit? */
64 static int rflag
; /* Show registers? */
67 (PR_STOPPED|PR_ISTOP|PR_DSTOP|PR_ASLEEP|PR_PCINVAL|PR_STEP \
68 |PR_AGENT|PR_DETACH|PR_DAEMON)
71 (PR_ISSYS|PR_VFORKP|PR_ORPHAN|PR_NOSIGCHLD|PR_WAITPID \
72 |PR_FORK|PR_RLC|PR_KLC|PR_ASYNC|PR_BPTADJ|PR_MSACCT|PR_MSFORK|PR_PTRACE)
74 #define ALLFLAGS (LWPFLAGS|PROCFLAGS)
77 main(int argc
, char **argv
)
84 if ((command
= strrchr(argv
[0], '/')) != NULL
)
90 while ((opt
= getopt(argc
, argv
, "r")) != EOF
) {
92 case 'r': /* show registers */
104 if (errflg
|| argc
<= 0) {
105 (void) fprintf(stderr
,
106 "usage:\t%s [-r] { pid | core }[/lwps] ...\n", command
);
107 (void) fprintf(stderr
, " (report process status flags)\n");
108 (void) fprintf(stderr
, " -r : report registers\n");
113 * Make sure we'll have enough file descriptors to handle a target
114 * that has many many mappings.
116 if (getrlimit(RLIMIT_NOFILE
, &rlim
) == 0) {
117 rlim
.rlim_cur
= rlim
.rlim_max
;
118 (void) setrlimit(RLIMIT_NOFILE
, &rlim
);
119 (void) enable_extended_FILE_stdio(-1, -1);
140 uint32_t sigtrace
, sigtrace1
, sigtrace2
, fltbits
;
141 uint32_t sigpend
, sigpend1
, sigpend2
;
143 char buf
[PRSIGBUFSZ
];
146 if ((Pr
= proc_arg_xgrab(arg
, NULL
, PR_ARG_ANY
,
147 PGRAB_RETAIN
| PGRAB_FORCE
| PGRAB_RDONLY
| PGRAB_NOSTOP
, &gcode
,
148 &lookarg
.lwps
)) == NULL
) {
149 if (gcode
== G_NOPROC
&&
150 proc_arg_psinfo(arg
, PR_ARG_PIDS
, &psinfo
, &gcode2
) > 0 &&
151 psinfo
.pr_nlwp
== 0) {
152 (void) printf("%d:\t<defunct>\n\n", (int)psinfo
.pr_pid
);
155 (void) fprintf(stderr
, "%s: cannot examine %s: %s\n",
156 command
, arg
, Pgrab_error(gcode
));
160 (void) memcpy(&pstatus
, Pstatus(Pr
), sizeof (pstatus_t
));
161 (void) memcpy(&psinfo
, Ppsinfo(Pr
), sizeof (psinfo_t
));
162 proc_unctrl_psinfo(&psinfo
);
164 if (psinfo
.pr_nlwp
== 0) {
165 (void) printf("%d:\t<defunct>\n\n", (int)psinfo
.pr_pid
);
166 Prelease(Pr
, PRELEASE_RETAIN
);
170 is64
= (pstatus
.pr_dmodel
== PR_MODEL_LP64
);
172 sigmask
= pstatus
.pr_sigtrace
;
173 fltmask
= pstatus
.pr_flttrace
;
174 entryset
= pstatus
.pr_sysentry
;
175 exitset
= pstatus
.pr_sysexit
;
177 if (Pstate(Pr
) == PS_DEAD
) {
178 (void) printf("core '%s' of %d:\t%.70s\n",
179 arg
, (int)psinfo
.pr_pid
, psinfo
.pr_psargs
);
181 (void) printf("%d:\t%.70s\n",
182 (int)psinfo
.pr_pid
, psinfo
.pr_psargs
);
185 (void) printf("\tdata model = %s", is64
? "_LP64" : "_ILP32");
186 if ((flags
= (pstatus
.pr_flags
& PROCFLAGS
)) != 0)
187 (void) printf(" flags = %s", prflags(flags
));
190 fltbits
= *((uint32_t *)&fltmask
);
192 (void) printf("\tflttrace = 0x%.8x\n", fltbits
);
194 #if (MAXSIG > 2 * 32) && (MAXSIG <= 3 * 32) /* assumption */
195 sigtrace
= *((uint32_t *)&sigmask
);
196 sigtrace1
= *((uint32_t *)&sigmask
+ 1);
197 sigtrace2
= *((uint32_t *)&sigmask
+ 2);
199 #error "fix me: MAXSIG out of bounds"
201 if (sigtrace
| sigtrace1
| sigtrace2
)
202 (void) printf("\tsigtrace = 0x%.8x 0x%.8x 0x%.8x\n\t %s\n",
203 sigtrace
, sigtrace1
, sigtrace2
,
204 proc_sigset2str(&sigmask
, "|", 1, buf
, sizeof (buf
)));
206 bits
= ((uint32_t *)&entryset
);
207 if (bits
[0] | bits
[1] | bits
[2] | bits
[3] |
208 bits
[4] | bits
[5] | bits
[6] | bits
[7])
211 "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n"
213 "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n",
214 bits
[0], bits
[1], bits
[2], bits
[3],
215 bits
[4], bits
[5], bits
[6], bits
[7]);
217 bits
= ((uint32_t *)&exitset
);
218 if (bits
[0] | bits
[1] | bits
[2] | bits
[3] |
219 bits
[4] | bits
[5] | bits
[6] | bits
[7])
222 "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n"
224 "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n",
225 bits
[0], bits
[1], bits
[2], bits
[3],
226 bits
[4], bits
[5], bits
[6], bits
[7]);
228 #if (MAXSIG > 2 * 32) && (MAXSIG <= 3 * 32) /* assumption */
229 sigpend
= *((uint32_t *)&pstatus
.pr_sigpend
);
230 sigpend1
= *((uint32_t *)&pstatus
.pr_sigpend
+ 1);
231 sigpend2
= *((uint32_t *)&pstatus
.pr_sigpend
+ 2);
233 #error "fix me: MAXSIG out of bounds"
235 if (sigpend
| sigpend1
| sigpend2
)
236 (void) printf("\tsigpend = 0x%.8x,0x%.8x,0x%.8x\n",
237 sigpend
, sigpend1
, sigpend2
);
239 lookarg
.pflags
= pstatus
.pr_flags
;
241 (void) Plwp_iter_all(Pr
, (proc_lwp_all_f
*)lwplook
, &lookarg
);
243 if (lookarg
.count
== 0)
244 (void) printf("No matching lwps found");
247 Prelease(Pr
, PRELEASE_RETAIN
);
253 lwplook_zombie(const lwpsinfo_t
*pip
)
255 (void) printf(" /%d:\t<defunct>\n", (int)pip
->pr_lwpid
);
260 lwplook(look_arg_t
*arg
, const lwpstatus_t
*psp
, const lwpsinfo_t
*pip
)
263 uint32_t sighold
, sighold1
, sighold2
;
264 uint32_t sigpend
, sigpend1
, sigpend2
;
269 if (!proc_lwp_in_set(arg
->lwps
, pip
->pr_lwpid
))
275 return (lwplook_zombie(pip
));
278 * PR_PCINVAL is just noise if the lwp is not stopped.
279 * Don't bother reporting it unless the lwp is stopped.
281 flags
= psp
->pr_flags
& LWPFLAGS
;
282 if (!(flags
& PR_STOPPED
))
283 flags
&= ~PR_PCINVAL
;
285 (void) printf(" /%d:\tflags = %s", (int)psp
->pr_lwpid
, prflags(flags
));
286 if ((flags
& PR_ASLEEP
) || (psp
->pr_syscall
&&
287 !(arg
->pflags
& PR_ISSYS
))) {
288 if (flags
& PR_ASLEEP
) {
289 if ((flags
& ~PR_ASLEEP
) != 0)
291 (void) printf("ASLEEP");
293 if (psp
->pr_syscall
&& !(arg
->pflags
& PR_ISSYS
)) {
296 (void) printf(" %s(",
297 proc_sysname(psp
->pr_syscall
, buf
, sizeof (buf
)));
298 for (i
= 0; i
< psp
->pr_nsysarg
; i
++) {
301 (void) printf("0x%lx", psp
->pr_sysarg
[i
]);
308 if (flags
& PR_STOPPED
) {
309 (void) printf("\twhy = %s", prwhy(psp
->pr_why
));
310 if (psp
->pr_why
!= PR_REQUESTED
&&
311 psp
->pr_why
!= PR_SUSPENDED
)
312 (void) printf(" what = %s",
313 prwhat(psp
->pr_why
, psp
->pr_what
));
317 #if (MAXSIG > 2 * 32) && (MAXSIG <= 3 * 32) /* assumption */
318 sighold
= *((uint32_t *)&psp
->pr_lwphold
);
319 sighold1
= *((uint32_t *)&psp
->pr_lwphold
+ 1);
320 sighold2
= *((uint32_t *)&psp
->pr_lwphold
+ 2);
321 sigpend
= *((uint32_t *)&psp
->pr_lwppend
);
322 sigpend1
= *((uint32_t *)&psp
->pr_lwppend
+ 1);
323 sigpend2
= *((uint32_t *)&psp
->pr_lwppend
+ 2);
325 #error "fix me: MAXSIG out of bounds"
327 cursig
= psp
->pr_cursig
;
329 if (sighold
| sighold1
| sighold2
)
330 (void) printf("\tsigmask = 0x%.8x,0x%.8x,0x%.8x\n",
331 sighold
, sighold1
, sighold2
);
332 if (sigpend
| sigpend1
| sigpend2
)
333 (void) printf("\tlwppend = 0x%.8x,0x%.8x,0x%.8x\n",
334 sigpend
, sigpend1
, sigpend2
);
336 (void) printf("\tcursig = %s\n",
337 proc_signame(cursig
, buf
, sizeof (buf
)));
339 if ((flags
& PR_AGENT
) &&
340 Plwp_getspymaster(Pr
, pip
->pr_lwpid
, &ps
) == 0) {
341 time_t time
= ps
.pr_time
.tv_sec
;
344 (void) strftime(t
, sizeof (t
), "%F:%H.%M.%S", localtime(&time
));
346 (void) printf("\tspymaster = pid %d, \"%s\" at %s\n",
347 (int)ps
.pr_pid
, ps
.pr_psargs
, t
);
351 if (Pstate(Pr
) == PS_DEAD
|| (arg
->pflags
& PR_STOPPED
)) {
352 #if defined(__sparc) && defined(_ILP32)
354 * If we're SPARC/32-bit, see if we can get extra
355 * register state for this lwp. If it's a v8plus
356 * program, print the 64-bit register values.
360 if (Plwp_getxregs(Pr
, psp
->pr_lwpid
, &prx
) == 0 &&
361 prx
.pr_type
== XR_TYPE_V8P
)
362 dumpregs_v8p(psp
->pr_reg
, &prx
, is64
);
364 #endif /* __sparc && _ILP32 */
365 dumpregs(psp
->pr_reg
, is64
);
367 (void) printf("\tNot stopped, can't show registers\n");
376 static char code_buf
[200];
377 char *str
= code_buf
;
383 (void) sprintf(str
, "0x%x", arg
& ~ALLFLAGS
);
388 * Display the semi-permanent lwp flags first.
390 if (arg
& PR_DAEMON
) /* daemons are always detached so */
391 (void) strcat(str
, "|DAEMON");
392 else if (arg
& PR_DETACH
) /* report detach only if non-daemon */
393 (void) strcat(str
, "|DETACH");
395 if (arg
& PR_STOPPED
)
396 (void) strcat(str
, "|STOPPED");
398 (void) strcat(str
, "|ISTOP");
400 (void) strcat(str
, "|DSTOP");
401 #if 0 /* displayed elsewhere */
403 (void) strcat(str
, "|ASLEEP");
405 if (arg
& PR_PCINVAL
)
406 (void) strcat(str
, "|PCINVAL");
408 (void) strcat(str
, "|STEP");
410 (void) strcat(str
, "|AGENT");
412 (void) strcat(str
, "|ISSYS");
414 (void) strcat(str
, "|VFORKP");
416 (void) strcat(str
, "|ORPHAN");
417 if (arg
& PR_NOSIGCHLD
)
418 (void) strcat(str
, "|NOSIGCHLD");
419 if (arg
& PR_WAITPID
)
420 (void) strcat(str
, "|WAITPID");
422 (void) strcat(str
, "|FORK");
424 (void) strcat(str
, "|RLC");
426 (void) strcat(str
, "|KLC");
428 (void) strcat(str
, "|ASYNC");
430 (void) strcat(str
, "|BPTADJ");
432 (void) strcat(str
, "|MSACCT");
434 (void) strcat(str
, "|MSFORK");
436 (void) strcat(str
, "|PTRACE");
452 str
= "PR_REQUESTED";
455 str
= "PR_SIGNALLED";
464 str
= "PR_JOBCONTROL";
470 str
= "PR_SUSPENDED";
474 (void) sprintf(str
, "%d", why
);
482 prwhat(int why
, int what
)
490 str
= proc_signame(what
, buf
, sizeof (buf
));
494 str
= proc_sysname(what
, buf
, sizeof (buf
));
497 str
= proc_fltname(what
, buf
, sizeof (buf
));
500 (void) sprintf(str
= buf
, "%d", what
);
508 static const char * const regname
[NPRGREG
] = {
509 " %g0", " %g1", " %g2", " %g3", " %g4", " %g5", " %g6", " %g7",
510 " %o0", " %o1", " %o2", " %o3", " %o4", " %o5", " %sp", " %o7",
511 " %l0", " %l1", " %l2", " %l3", " %l4", " %l5", " %l6", " %l7",
512 " %i0", " %i1", " %i2", " %i3", " %i4", " %i5", " %fp", " %i7",
514 "%ccr", " %pc", "%npc", " %y", "%asi", "%fprs"
516 "%psr", " %pc", "%npc", " %y", "%wim", "%tbr"
522 static const char * const regname
[NPRGREG
] = {
523 "%r15", "%r14", "%r13", "%r12", "%r11", "%r10", " %r9", " %r8",
524 "%rdi", "%rsi", "%rbp", "%rbx", "%rdx", "%rcx", "%rax", "%trapno",
525 "%err", "%rip", " %cs", "%rfl", "%rsp", " %ss", " %fs", " %gs",
526 " %es", " %ds", "%fsbase", "%gsbase"
529 static const char * const regname32
[NPRGREG32
] = {
530 " %gs", " %fs", " %es", " %ds", "%edi", "%esi", "%ebp", "%esp",
531 "%ebx", "%edx", "%ecx", "%eax", "%trapno", "%err", "%eip", " %cs",
532 "%efl", "%uesp", " %ss"
535 /* XX64 Do we want to expose this through libproc */
537 prgregset_n_to_32(const prgreg_t
*src
, prgreg32_t
*dst
)
539 bzero(dst
, NPRGREG32
* sizeof (prgreg32_t
));
540 dst
[GS
] = src
[REG_GS
];
541 dst
[FS
] = src
[REG_FS
];
542 dst
[DS
] = src
[REG_DS
];
543 dst
[ES
] = src
[REG_ES
];
544 dst
[EDI
] = src
[REG_RDI
];
545 dst
[ESI
] = src
[REG_RSI
];
546 dst
[EBP
] = src
[REG_RBP
];
547 dst
[EBX
] = src
[REG_RBX
];
548 dst
[EDX
] = src
[REG_RDX
];
549 dst
[ECX
] = src
[REG_RCX
];
550 dst
[EAX
] = src
[REG_RAX
];
551 dst
[TRAPNO
] = src
[REG_TRAPNO
];
552 dst
[ERR
] = src
[REG_ERR
];
553 dst
[EIP
] = src
[REG_RIP
];
554 dst
[CS
] = src
[REG_CS
];
555 dst
[EFL
] = src
[REG_RFL
];
556 dst
[UESP
] = src
[REG_RSP
];
557 dst
[SS
] = src
[REG_SS
];
560 #elif defined(__i386)
561 static const char * const regname
[NPRGREG
] = {
562 " %gs", " %fs", " %es", " %ds", "%edi", "%esi", "%ebp", "%esp",
563 "%ebx", "%edx", "%ecx", "%eax", "%trapno", "%err", "%eip", " %cs",
564 "%efl", "%uesp", " %ss"
568 #if defined(__amd64) && defined(_LP64)
570 dumpregs32(const prgregset_t reg
)
575 prgregset_n_to_32(reg
, reg32
);
577 for (i
= 0; i
< NPRGREG32
; i
++) {
578 (void) printf(" %s = 0x%.8X",
579 regname32
[i
], reg32
[i
]);
581 (void) putchar('\n');
584 (void) putchar('\n');
589 dumpregs(const prgregset_t reg
, int is64
)
591 int width
= is64
? 16 : 8;
592 int cols
= is64
? 2 : 4;
595 #if defined(__amd64) && defined(_LP64)
602 for (i
= 0; i
< NPRGREG
; i
++) {
603 (void) printf(" %s = 0x%.*lX",
604 regname
[i
], width
, (long)reg
[i
]);
605 if ((i
+1) % cols
== 0)
606 (void) putchar('\n');
609 (void) putchar('\n');
612 #if defined(__sparc) && defined(_ILP32)
614 dumpregs_v8p(const prgregset_t reg
, const prxregset_t
*xreg
, int is64
)
616 static const uint32_t zero
[8] = { 0 };
617 int gr
, xr
, cols
= 2;
620 if (memcmp(xreg
->pr_un
.pr_v8p
.pr_xg
, zero
, sizeof (zero
)) == 0 &&
621 memcmp(xreg
->pr_un
.pr_v8p
.pr_xo
, zero
, sizeof (zero
)) == 0) {
626 for (gr
= R_G0
, xr
= XR_G0
; gr
<= R_G7
; gr
++, xr
++) {
627 xval
= (uint64_t)xreg
->pr_un
.pr_v8p
.pr_xg
[xr
] << 32 |
628 (uint64_t)(uint32_t)reg
[gr
];
629 (void) printf(" %s = 0x%.16" PRIX64
, regname
[gr
], xval
);
630 if ((gr
+ 1) % cols
== 0)
631 (void) putchar('\n');
634 for (gr
= R_O0
, xr
= XR_O0
; gr
<= R_O7
; gr
++, xr
++) {
635 xval
= (uint64_t)xreg
->pr_un
.pr_v8p
.pr_xo
[xr
] << 32 |
636 (uint64_t)(uint32_t)reg
[gr
];
637 (void) printf(" %s = 0x%.16" PRIX64
, regname
[gr
], xval
);
638 if ((gr
+ 1) % cols
== 0)
639 (void) putchar('\n');
642 for (gr
= R_L0
; gr
< NPRGREG
; gr
++) {
643 (void) printf(" %s = 0x%.8lX",
644 regname
[gr
], (long)reg
[gr
]);
645 if ((gr
+ 1) % cols
== 0)
646 (void) putchar('\n');
650 (void) putchar('\n');
652 #endif /* __sparc && _ILP32 */