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 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <sys/isa_defs.h>
27
28 #include <stdio.h>
29 #include <stdio_ext.h>
30 #include <fcntl.h>
31 #include <ctype.h>
32 #include <string.h>
33 #include <signal.h>
34 #include <dirent.h>
35 #include <errno.h>
36 #include <stdlib.h>
37 #include <stdarg.h>
38 #include <unistd.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <sys/stack.h>
42 #include <link.h>
43 #include <limits.h>
120
121 static pydb_agent_t *load_libpython(struct ps_prochandle *P);
122 static void reset_libpython(pydb_agent_t *);
123 /*
124 * Since we must maintain both a proc handle and a jvm handle, this structure
125 * is the basic type that gets passed around.
126 */
127 typedef struct pstack_handle {
128 struct ps_prochandle *proc;
129 jvm_agent_t *jvm;
130 int ignore_frame;
131 const char *lwps;
132 int count;
133 pydb_agent_t *pydb;
134 } pstack_handle_t;
135
136 static int thr_stack(const td_thrhandle_t *, void *);
137 static void free_threadinfo(void);
138 static struct threadinfo *find_thread(id_t);
139 static int all_call_stacks(pstack_handle_t *, int);
140 static void tlhead(id_t, id_t);
141 static int print_frame(void *, prgregset_t, uint_t, const long *);
142 static void print_zombie(struct ps_prochandle *, struct threadinfo *);
143 static void print_syscall(const lwpstatus_t *, prgregset_t);
144 static void call_stack(pstack_handle_t *, const lwpstatus_t *);
145
146 /*
147 * The number of active and zombie threads.
148 */
149 static int nthreads;
150
151 int
152 main(int argc, char **argv)
153 {
154 int retc = 0;
155 int opt;
156 int errflg = FALSE;
157 core_content_t content = CC_CONTENT_DATA | CC_CONTENT_ANON |
158 CC_CONTENT_STACK;
159 struct rlimit rlim;
160
363 * Find and eliminate the thread corresponding to the given lwpid.
364 */
365 static struct threadinfo *
366 find_thread(id_t lwpid)
367 {
368 struct threadinfo *tip;
369
370 for (tip = thr_head; tip; tip = tip->next) {
371 if (lwpid == tip->lwpid) {
372 tip->lwpid = 0;
373 return (tip);
374 }
375 }
376 return (NULL);
377 }
378
379 static int
380 thread_call_stack(void *data, const lwpstatus_t *psp,
381 const lwpsinfo_t *pip)
382 {
383 pstack_handle_t *h = data;
384 lwpstatus_t lwpstatus;
385 struct threadinfo *tip;
386
387 if (!proc_lwp_in_set(h->lwps, pip->pr_lwpid))
388 return (0);
389 h->count++;
390
391 if ((tip = find_thread(pip->pr_lwpid)) == NULL)
392 return (0);
393
394 tlhead(tip->threadid, pip->pr_lwpid);
395 tip->threadid = 0; /* finish eliminating tid */
396 if (psp)
397 call_stack(h, psp);
398 else {
399 if (tip->state == TD_THR_ZOMBIE)
400 print_zombie(h->proc, tip);
401 else {
402 (void) memset(&lwpstatus, 0, sizeof (lwpstatus));
403 (void) memcpy(lwpstatus.pr_reg, tip->regs,
404 sizeof (prgregset_t));
405 call_stack(h, &lwpstatus);
406 }
407 }
408 return (0);
409 }
410
411 static int
412 lwp_call_stack(void *data,
413 const lwpstatus_t *psp, const lwpsinfo_t *pip)
414 {
415 pstack_handle_t *h = data;
416
417 if (!proc_lwp_in_set(h->lwps, pip->pr_lwpid))
418 return (0);
419 h->count++;
420
421 tlhead(0, pip->pr_lwpid);
422 if (psp)
423 call_stack(h, psp);
424 else
425 (void) printf("\t** zombie "
426 "(exited, not detached, not yet joined) **\n");
427 return (0);
428 }
429
430 static int
431 all_call_stacks(pstack_handle_t *h, int dothreads)
432 {
433 struct ps_prochandle *Pr = h->proc;
434 pstatus_t status = *Pstatus(Pr);
435
436 (void) memset(&sigh, 0, sizeof (GElf_Sym));
437 (void) Plookup_by_name(Pr, "libc.so", "sigacthandler", &sigh);
438
439 if ((status.pr_nlwp + status.pr_nzomb) <= 1 &&
440 !(dothreads && nthreads > 1)) {
441 if (proc_lwp_in_set(h->lwps, status.pr_lwp.pr_lwpid)) {
445 } else {
446 lwpstatus_t lwpstatus;
447 struct threadinfo *tip;
448 id_t tid;
449
450 if (dothreads)
451 (void) Plwp_iter_all(Pr, thread_call_stack, h);
452 else
453 (void) Plwp_iter_all(Pr, lwp_call_stack, h);
454
455 /* for each remaining thread w/o an lwp */
456 (void) memset(&lwpstatus, 0, sizeof (lwpstatus));
457 for (tip = thr_head; tip; tip = tip->next) {
458
459 if (!proc_lwp_in_set(h->lwps, tip->lwpid))
460 tip->threadid = 0;
461
462 if ((tid = tip->threadid) != 0) {
463 (void) memcpy(lwpstatus.pr_reg, tip->regs,
464 sizeof (prgregset_t));
465 tlhead(tid, tip->lwpid);
466 if (tip->state == TD_THR_ZOMBIE)
467 print_zombie(Pr, tip);
468 else
469 call_stack(h, &lwpstatus);
470 }
471 tip->threadid = 0;
472 tip->lwpid = 0;
473 }
474 }
475 return (0);
476 }
477
478 static void
479 tlhead(id_t threadid, id_t lwpid)
480 {
481 if (threadid == 0 && lwpid == 0)
482 return;
483
484 (void) printf("-----------------");
485
486 if (threadid && lwpid)
487 (void) printf(" lwp# %d / thread# %d ",
488 (int)lwpid, (int)threadid);
489 else if (threadid)
490 (void) printf("--------- thread# %d ", (int)threadid);
491 else if (lwpid)
492 (void) printf(" lwp# %d ------------", (int)lwpid);
493
494 (void) printf("--------------------\n");
495 }
496
497 /*ARGSUSED*/
498 static int
499 print_java_frame(void *cld, prgregset_t gregs, const char *name, int bci,
500 int line, void *handle)
501 {
502 int length = (is64 ? 16 : 8);
503
504 (void) printf(" %.*lx * %s", length, (long)gregs[R_PC], name);
505
506 if (bci != -1) {
507 (void) printf("+%d", bci);
508 if (line)
509 (void) printf(" (line %d)", line);
510 }
511 (void) printf("\n");
512
513 return (0);
514 }
|
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 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 *
25 * Copyright 2018 Joyent, Inc.
26 */
27
28 #include <sys/isa_defs.h>
29
30 #include <stdio.h>
31 #include <stdio_ext.h>
32 #include <fcntl.h>
33 #include <ctype.h>
34 #include <string.h>
35 #include <signal.h>
36 #include <dirent.h>
37 #include <errno.h>
38 #include <stdlib.h>
39 #include <stdarg.h>
40 #include <unistd.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <sys/stack.h>
44 #include <link.h>
45 #include <limits.h>
122
123 static pydb_agent_t *load_libpython(struct ps_prochandle *P);
124 static void reset_libpython(pydb_agent_t *);
125 /*
126 * Since we must maintain both a proc handle and a jvm handle, this structure
127 * is the basic type that gets passed around.
128 */
129 typedef struct pstack_handle {
130 struct ps_prochandle *proc;
131 jvm_agent_t *jvm;
132 int ignore_frame;
133 const char *lwps;
134 int count;
135 pydb_agent_t *pydb;
136 } pstack_handle_t;
137
138 static int thr_stack(const td_thrhandle_t *, void *);
139 static void free_threadinfo(void);
140 static struct threadinfo *find_thread(id_t);
141 static int all_call_stacks(pstack_handle_t *, int);
142 static void tlhead(id_t, id_t, const char *);
143 static int print_frame(void *, prgregset_t, uint_t, const long *);
144 static void print_zombie(struct ps_prochandle *, struct threadinfo *);
145 static void print_syscall(const lwpstatus_t *, prgregset_t);
146 static void call_stack(pstack_handle_t *, const lwpstatus_t *);
147
148 /*
149 * The number of active and zombie threads.
150 */
151 static int nthreads;
152
153 int
154 main(int argc, char **argv)
155 {
156 int retc = 0;
157 int opt;
158 int errflg = FALSE;
159 core_content_t content = CC_CONTENT_DATA | CC_CONTENT_ANON |
160 CC_CONTENT_STACK;
161 struct rlimit rlim;
162
365 * Find and eliminate the thread corresponding to the given lwpid.
366 */
367 static struct threadinfo *
368 find_thread(id_t lwpid)
369 {
370 struct threadinfo *tip;
371
372 for (tip = thr_head; tip; tip = tip->next) {
373 if (lwpid == tip->lwpid) {
374 tip->lwpid = 0;
375 return (tip);
376 }
377 }
378 return (NULL);
379 }
380
381 static int
382 thread_call_stack(void *data, const lwpstatus_t *psp,
383 const lwpsinfo_t *pip)
384 {
385 char lwpname[THREAD_NAME_MAX] = "";
386 pstack_handle_t *h = data;
387 lwpstatus_t lwpstatus;
388 struct threadinfo *tip;
389
390 if (!proc_lwp_in_set(h->lwps, pip->pr_lwpid))
391 return (0);
392 h->count++;
393
394 if ((tip = find_thread(pip->pr_lwpid)) == NULL)
395 return (0);
396
397 (void) Plwp_getname(h->proc, pip->pr_lwpid,
398 lwpname, sizeof (lwpname));
399
400 tlhead(tip->threadid, pip->pr_lwpid, lwpname);
401 tip->threadid = 0; /* finish eliminating tid */
402 if (psp)
403 call_stack(h, psp);
404 else {
405 if (tip->state == TD_THR_ZOMBIE)
406 print_zombie(h->proc, tip);
407 else {
408 (void) memset(&lwpstatus, 0, sizeof (lwpstatus));
409 (void) memcpy(lwpstatus.pr_reg, tip->regs,
410 sizeof (prgregset_t));
411 call_stack(h, &lwpstatus);
412 }
413 }
414 return (0);
415 }
416
417 static int
418 lwp_call_stack(void *data,
419 const lwpstatus_t *psp, const lwpsinfo_t *pip)
420 {
421 char lwpname[THREAD_NAME_MAX] = "";
422 pstack_handle_t *h = data;
423
424 if (!proc_lwp_in_set(h->lwps, pip->pr_lwpid))
425 return (0);
426 h->count++;
427
428 (void) Plwp_getname(h->proc, pip->pr_lwpid,
429 lwpname, sizeof (lwpname));
430
431 tlhead(0, pip->pr_lwpid, lwpname);
432 if (psp)
433 call_stack(h, psp);
434 else
435 (void) printf("\t** zombie "
436 "(exited, not detached, not yet joined) **\n");
437 return (0);
438 }
439
440 static int
441 all_call_stacks(pstack_handle_t *h, int dothreads)
442 {
443 struct ps_prochandle *Pr = h->proc;
444 pstatus_t status = *Pstatus(Pr);
445
446 (void) memset(&sigh, 0, sizeof (GElf_Sym));
447 (void) Plookup_by_name(Pr, "libc.so", "sigacthandler", &sigh);
448
449 if ((status.pr_nlwp + status.pr_nzomb) <= 1 &&
450 !(dothreads && nthreads > 1)) {
451 if (proc_lwp_in_set(h->lwps, status.pr_lwp.pr_lwpid)) {
455 } else {
456 lwpstatus_t lwpstatus;
457 struct threadinfo *tip;
458 id_t tid;
459
460 if (dothreads)
461 (void) Plwp_iter_all(Pr, thread_call_stack, h);
462 else
463 (void) Plwp_iter_all(Pr, lwp_call_stack, h);
464
465 /* for each remaining thread w/o an lwp */
466 (void) memset(&lwpstatus, 0, sizeof (lwpstatus));
467 for (tip = thr_head; tip; tip = tip->next) {
468
469 if (!proc_lwp_in_set(h->lwps, tip->lwpid))
470 tip->threadid = 0;
471
472 if ((tid = tip->threadid) != 0) {
473 (void) memcpy(lwpstatus.pr_reg, tip->regs,
474 sizeof (prgregset_t));
475 tlhead(tid, tip->lwpid, NULL);
476 if (tip->state == TD_THR_ZOMBIE)
477 print_zombie(Pr, tip);
478 else
479 call_stack(h, &lwpstatus);
480 }
481 tip->threadid = 0;
482 tip->lwpid = 0;
483 }
484 }
485 return (0);
486 }
487
488 /* The width of the header */
489 #define HEAD_WIDTH (62)
490 static void
491 tlhead(id_t threadid, id_t lwpid, const char *name)
492 {
493 char buf[128] = { 0 };
494 char num[16];
495 ssize_t amt = 0;
496 int i;
497
498 if (threadid == 0 && lwpid == 0)
499 return;
500
501 if (lwpid > 0) {
502 (void) snprintf(num, sizeof (num), "%d", (int)lwpid);
503 (void) strlcat(buf, "thread# ", sizeof (buf));
504 (void) strlcat(buf, num, sizeof (buf));
505 }
506
507 if (threadid > 0) {
508 (void) snprintf(num, sizeof (num), "%d", (int)threadid);
509 if (lwpid > 0)
510 (void) strlcat(buf, " / ", sizeof (buf));
511 (void) strlcat(buf, "lwp# ", sizeof (buf));
512 (void) strlcat(buf, num, sizeof (buf));
513 }
514
515 if (name != NULL && strlen(name) > 0) {
516 (void) strlcat(buf, " [", sizeof (buf));
517 (void) strlcat(buf, name, sizeof (buf));
518 (void) strlcat(buf, "]", sizeof (buf));
519 }
520
521 amt = (HEAD_WIDTH - strlen(buf) - 2);
522 if (amt < 4)
523 amt = 4;
524
525 for (i = 0; i < amt / 2; i++)
526 (void) putc('-', stdout);
527 (void) printf(" %s ", buf);
528 for (i = 0; i < (amt / 2) + (amt % 2); i++)
529 (void) putc('-', stdout);
530 (void) putc('\n', stdout);
531 }
532
533 /*ARGSUSED*/
534 static int
535 print_java_frame(void *cld, prgregset_t gregs, const char *name, int bci,
536 int line, void *handle)
537 {
538 int length = (is64 ? 16 : 8);
539
540 (void) printf(" %.*lx * %s", length, (long)gregs[R_PC], name);
541
542 if (bci != -1) {
543 (void) printf("+%d", bci);
544 if (line)
545 (void) printf(" (line %d)", line);
546 }
547 (void) printf("\n");
548
549 return (0);
550 }
|