Print this page
8158 Want named threads API
9857 proc manpages should have LIBRARY section


   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 }