17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*004388ebScasper * Common Development and Distribution License (the "License"). 6*004388ebScasper * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*004388ebScasper * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h> 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #include <stdio.h> 31*004388ebScasper #include <stdio_ext.h> 327c478bd9Sstevel@tonic-gate #include <fcntl.h> 337c478bd9Sstevel@tonic-gate #include <ctype.h> 347c478bd9Sstevel@tonic-gate #include <string.h> 357c478bd9Sstevel@tonic-gate #include <signal.h> 367c478bd9Sstevel@tonic-gate #include <dirent.h> 377c478bd9Sstevel@tonic-gate #include <errno.h> 387c478bd9Sstevel@tonic-gate #include <stdlib.h> 397c478bd9Sstevel@tonic-gate #include <stdarg.h> 407c478bd9Sstevel@tonic-gate #include <unistd.h> 417c478bd9Sstevel@tonic-gate #include <sys/types.h> 427c478bd9Sstevel@tonic-gate #include <sys/stat.h> 437c478bd9Sstevel@tonic-gate #include <sys/stack.h> 447c478bd9Sstevel@tonic-gate #include <link.h> 457c478bd9Sstevel@tonic-gate #include <limits.h> 467c478bd9Sstevel@tonic-gate #include <libelf.h> 477c478bd9Sstevel@tonic-gate #include <thread_db.h> 487c478bd9Sstevel@tonic-gate #include <libproc.h> 497c478bd9Sstevel@tonic-gate #include <setjmp.h> 507c478bd9Sstevel@tonic-gate 517c478bd9Sstevel@tonic-gate static char *command; 527c478bd9Sstevel@tonic-gate static int Fflag; 537c478bd9Sstevel@tonic-gate static int is64; 547c478bd9Sstevel@tonic-gate static GElf_Sym sigh; 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate /* 577c478bd9Sstevel@tonic-gate * To keep the list of user-level threads for a multithreaded process. 587c478bd9Sstevel@tonic-gate */ 597c478bd9Sstevel@tonic-gate struct threadinfo { 607c478bd9Sstevel@tonic-gate struct threadinfo *next; 617c478bd9Sstevel@tonic-gate id_t threadid; 627c478bd9Sstevel@tonic-gate id_t lwpid; 637c478bd9Sstevel@tonic-gate td_thr_state_e state; 647c478bd9Sstevel@tonic-gate uintptr_t startfunc; 657c478bd9Sstevel@tonic-gate uintptr_t exitval; 667c478bd9Sstevel@tonic-gate prgregset_t regs; 677c478bd9Sstevel@tonic-gate }; 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate static struct threadinfo *thr_head, *thr_tail; 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate #define TRUE 1 727c478bd9Sstevel@tonic-gate #define FALSE 0 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate #define MAX_ARGS 8 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate /* 777c478bd9Sstevel@tonic-gate * To support debugging java programs, we display java frames within a stack. 787c478bd9Sstevel@tonic-gate * The logic to walk the java frames is contained in libjvm_db.so, which is 797c478bd9Sstevel@tonic-gate * found in the same directory as libjvm.so, linked with the program. If we are 807c478bd9Sstevel@tonic-gate * debugging a 32-bit app with a 64-binary, then the debugging library is found 817c478bd9Sstevel@tonic-gate * in the '64' subdirectory. If we find libjvm_db.so, then we fill in these 827c478bd9Sstevel@tonic-gate * stub routines. 837c478bd9Sstevel@tonic-gate */ 847c478bd9Sstevel@tonic-gate typedef struct jvm_agent jvm_agent_t; 857c478bd9Sstevel@tonic-gate typedef int java_stack_f(void *, prgregset_t, const char *, int, int, void *); 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate /* 887c478bd9Sstevel@tonic-gate * The j_agent_create function takes a version parameter. This ensures that the 897c478bd9Sstevel@tonic-gate * interface can evolve appropriately. 907c478bd9Sstevel@tonic-gate */ 917c478bd9Sstevel@tonic-gate #define JVM_DB_VERSION 1 927c478bd9Sstevel@tonic-gate static void *libjvm; 937c478bd9Sstevel@tonic-gate typedef jvm_agent_t *(*j_agent_create_f)(struct ps_prochandle *, int); 947c478bd9Sstevel@tonic-gate typedef void (*j_agent_destroy_f)(jvm_agent_t *); 957c478bd9Sstevel@tonic-gate typedef int (*j_frame_iter_f)(jvm_agent_t *, prgregset_t, java_stack_f *, 967c478bd9Sstevel@tonic-gate void *); 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate static j_agent_create_f j_agent_create; 997c478bd9Sstevel@tonic-gate static j_agent_destroy_f j_agent_destroy; 1007c478bd9Sstevel@tonic-gate static j_frame_iter_f j_frame_iter; 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate static jvm_agent_t *load_libjvm(struct ps_prochandle *P); 1037c478bd9Sstevel@tonic-gate static void reset_libjvm(jvm_agent_t *); 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate /* 1067c478bd9Sstevel@tonic-gate * Since we must maintain both a proc handle and a jvm handle, this structure 1077c478bd9Sstevel@tonic-gate * is the basic type that gets passed around. 1087c478bd9Sstevel@tonic-gate */ 1097c478bd9Sstevel@tonic-gate typedef struct pstack_handle { 1107c478bd9Sstevel@tonic-gate struct ps_prochandle *proc; 1117c478bd9Sstevel@tonic-gate jvm_agent_t *jvm; 1127c478bd9Sstevel@tonic-gate int ignore_frame; 1137c478bd9Sstevel@tonic-gate const char *lwps; 1147c478bd9Sstevel@tonic-gate int count; 1157c478bd9Sstevel@tonic-gate } pstack_handle_t; 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate static int thr_stack(const td_thrhandle_t *, void *); 1187c478bd9Sstevel@tonic-gate static void free_threadinfo(void); 1197c478bd9Sstevel@tonic-gate static struct threadinfo *find_thread(id_t); 1207c478bd9Sstevel@tonic-gate static int all_call_stacks(pstack_handle_t *, int); 1217c478bd9Sstevel@tonic-gate static void tlhead(id_t, id_t); 1227c478bd9Sstevel@tonic-gate static int print_frame(void *, prgregset_t, uint_t, const long *); 1237c478bd9Sstevel@tonic-gate static void print_zombie(struct ps_prochandle *, struct threadinfo *); 1247c478bd9Sstevel@tonic-gate static void print_syscall(const lwpstatus_t *, prgregset_t); 1257c478bd9Sstevel@tonic-gate static void call_stack(pstack_handle_t *, const lwpstatus_t *); 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate /* 1287c478bd9Sstevel@tonic-gate * The number of active and zombie threads. 1297c478bd9Sstevel@tonic-gate */ 1307c478bd9Sstevel@tonic-gate static int nthreads; 1317c478bd9Sstevel@tonic-gate 1327c478bd9Sstevel@tonic-gate int 1337c478bd9Sstevel@tonic-gate main(int argc, char **argv) 1347c478bd9Sstevel@tonic-gate { 1357c478bd9Sstevel@tonic-gate int retc = 0; 1367c478bd9Sstevel@tonic-gate int opt; 1377c478bd9Sstevel@tonic-gate int errflg = FALSE; 1387c478bd9Sstevel@tonic-gate core_content_t content = CC_CONTENT_DATA | CC_CONTENT_ANON | 1397c478bd9Sstevel@tonic-gate CC_CONTENT_STACK; 1407c478bd9Sstevel@tonic-gate struct rlimit rlim; 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate if ((command = strrchr(argv[0], '/')) != NULL) 1437c478bd9Sstevel@tonic-gate command++; 1447c478bd9Sstevel@tonic-gate else 1457c478bd9Sstevel@tonic-gate command = argv[0]; 1467c478bd9Sstevel@tonic-gate 1477c478bd9Sstevel@tonic-gate /* options */ 1487c478bd9Sstevel@tonic-gate while ((opt = getopt(argc, argv, "F")) != EOF) { 1497c478bd9Sstevel@tonic-gate switch (opt) { 1507c478bd9Sstevel@tonic-gate case 'F': 1517c478bd9Sstevel@tonic-gate /* 1527c478bd9Sstevel@tonic-gate * If the user specifies the force option, we'll 1537c478bd9Sstevel@tonic-gate * consent to printing out other threads' stacks 1547c478bd9Sstevel@tonic-gate * even if the main stack is absent. 1557c478bd9Sstevel@tonic-gate */ 1567c478bd9Sstevel@tonic-gate content &= ~CC_CONTENT_STACK; 1577c478bd9Sstevel@tonic-gate Fflag = PGRAB_FORCE; 1587c478bd9Sstevel@tonic-gate break; 1597c478bd9Sstevel@tonic-gate default: 1607c478bd9Sstevel@tonic-gate errflg = TRUE; 1617c478bd9Sstevel@tonic-gate break; 1627c478bd9Sstevel@tonic-gate } 1637c478bd9Sstevel@tonic-gate } 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate argc -= optind; 1667c478bd9Sstevel@tonic-gate argv += optind; 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate if (errflg || argc <= 0) { 1697c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1707c478bd9Sstevel@tonic-gate "usage:\t%s [-F] { pid | core }[/lwps] ...\n", command); 1717c478bd9Sstevel@tonic-gate (void) fprintf(stderr, " (show process call stack)\n"); 1727c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1737c478bd9Sstevel@tonic-gate " -F: force grabbing of the target process\n"); 1747c478bd9Sstevel@tonic-gate exit(2); 1757c478bd9Sstevel@tonic-gate } 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate /* 1787c478bd9Sstevel@tonic-gate * Make sure we'll have enough file descriptors to handle a target 1797c478bd9Sstevel@tonic-gate * that has many many mappings. 1807c478bd9Sstevel@tonic-gate */ 1817c478bd9Sstevel@tonic-gate if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) { 1827c478bd9Sstevel@tonic-gate rlim.rlim_cur = rlim.rlim_max; 1837c478bd9Sstevel@tonic-gate (void) setrlimit(RLIMIT_NOFILE, &rlim); 184*004388ebScasper (void) enable_extended_FILE_stdio(-1, -1); 1857c478bd9Sstevel@tonic-gate } 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate (void) proc_initstdio(); 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate while (--argc >= 0) { 1907c478bd9Sstevel@tonic-gate int gcode; 1917c478bd9Sstevel@tonic-gate psinfo_t psinfo; 1927c478bd9Sstevel@tonic-gate const psinfo_t *tpsinfo; 1937c478bd9Sstevel@tonic-gate struct ps_prochandle *Pr = NULL; 1947c478bd9Sstevel@tonic-gate td_thragent_t *Tap; 1957c478bd9Sstevel@tonic-gate int threaded; 1967c478bd9Sstevel@tonic-gate pstack_handle_t handle; 1977c478bd9Sstevel@tonic-gate const char *lwps, *arg; 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate (void) proc_flushstdio(); 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate arg = *argv++; 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate if ((Pr = proc_arg_xgrab(arg, NULL, PR_ARG_ANY, 2047c478bd9Sstevel@tonic-gate Fflag, &gcode, &lwps)) == NULL) { 2057c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: cannot examine %s: %s\n", 2067c478bd9Sstevel@tonic-gate command, arg, Pgrab_error(gcode)); 2077c478bd9Sstevel@tonic-gate retc++; 2087c478bd9Sstevel@tonic-gate continue; 2097c478bd9Sstevel@tonic-gate } 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate if ((tpsinfo = Ppsinfo(Pr)) == NULL) { 2127c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: cannot examine %s: " 2137c478bd9Sstevel@tonic-gate "lost control of process\n", command, arg); 2147c478bd9Sstevel@tonic-gate Prelease(Pr, 0); 2157c478bd9Sstevel@tonic-gate retc++; 2167c478bd9Sstevel@tonic-gate continue; 2177c478bd9Sstevel@tonic-gate } 2187c478bd9Sstevel@tonic-gate (void) memcpy(&psinfo, tpsinfo, sizeof (psinfo_t)); 2197c478bd9Sstevel@tonic-gate proc_unctrl_psinfo(&psinfo); 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate if (Pstate(Pr) == PS_DEAD) { 2227c478bd9Sstevel@tonic-gate if ((Pcontent(Pr) & content) != content) { 2237c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: core '%s' has " 2247c478bd9Sstevel@tonic-gate "insufficient content\n", command, arg); 2257c478bd9Sstevel@tonic-gate retc++; 2267c478bd9Sstevel@tonic-gate continue; 2277c478bd9Sstevel@tonic-gate } 2287c478bd9Sstevel@tonic-gate (void) printf("core '%s' of %d:\t%.70s\n", 2297c478bd9Sstevel@tonic-gate arg, (int)psinfo.pr_pid, psinfo.pr_psargs); 2307c478bd9Sstevel@tonic-gate } else { 2317c478bd9Sstevel@tonic-gate (void) printf("%d:\t%.70s\n", 2327c478bd9Sstevel@tonic-gate (int)psinfo.pr_pid, psinfo.pr_psargs); 2337c478bd9Sstevel@tonic-gate } 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate is64 = (psinfo.pr_dmodel == PR_MODEL_LP64); 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate if (Pgetauxval(Pr, AT_BASE) != -1L && Prd_agent(Pr) == NULL) { 2387c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: warning: librtld_db failed " 2397c478bd9Sstevel@tonic-gate "to initialize; symbols from shared libraries will " 2407c478bd9Sstevel@tonic-gate "not be available\n", command); 2417c478bd9Sstevel@tonic-gate } 2427c478bd9Sstevel@tonic-gate 2437c478bd9Sstevel@tonic-gate /* 2447c478bd9Sstevel@tonic-gate * First we need to get a thread agent handle. 2457c478bd9Sstevel@tonic-gate */ 2467c478bd9Sstevel@tonic-gate if (td_init() != TD_OK || 2477c478bd9Sstevel@tonic-gate td_ta_new(Pr, &Tap) != TD_OK) /* no libc */ 2487c478bd9Sstevel@tonic-gate threaded = FALSE; 2497c478bd9Sstevel@tonic-gate else { 2507c478bd9Sstevel@tonic-gate /* 2517c478bd9Sstevel@tonic-gate * Iterate over all threads, calling: 2527c478bd9Sstevel@tonic-gate * thr_stack(td_thrhandle_t *Thp, NULL); 2537c478bd9Sstevel@tonic-gate * for each one to generate the list of threads. 2547c478bd9Sstevel@tonic-gate */ 2557c478bd9Sstevel@tonic-gate nthreads = 0; 2567c478bd9Sstevel@tonic-gate (void) td_ta_thr_iter(Tap, thr_stack, NULL, 2577c478bd9Sstevel@tonic-gate TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY, 2587c478bd9Sstevel@tonic-gate TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS); 2597c478bd9Sstevel@tonic-gate 2607c478bd9Sstevel@tonic-gate (void) td_ta_delete(Tap); 2617c478bd9Sstevel@tonic-gate threaded = TRUE; 2627c478bd9Sstevel@tonic-gate } 2637c478bd9Sstevel@tonic-gate 2647c478bd9Sstevel@tonic-gate handle.proc = Pr; 2657c478bd9Sstevel@tonic-gate handle.jvm = load_libjvm(Pr); 2667c478bd9Sstevel@tonic-gate handle.lwps = lwps; 2677c478bd9Sstevel@tonic-gate handle.count = 0; 2687c478bd9Sstevel@tonic-gate 2697c478bd9Sstevel@tonic-gate if (all_call_stacks(&handle, threaded) != 0) 2707c478bd9Sstevel@tonic-gate retc++; 2717c478bd9Sstevel@tonic-gate if (threaded) 2727c478bd9Sstevel@tonic-gate free_threadinfo(); 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate reset_libjvm(handle.jvm); 2757c478bd9Sstevel@tonic-gate Prelease(Pr, 0); 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate if (handle.count == 0) 2787c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: no matching LWPs found\n", 2797c478bd9Sstevel@tonic-gate command); 2807c478bd9Sstevel@tonic-gate } 2817c478bd9Sstevel@tonic-gate 2827c478bd9Sstevel@tonic-gate (void) proc_finistdio(); 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate return (retc); 2857c478bd9Sstevel@tonic-gate } 2867c478bd9Sstevel@tonic-gate 2877c478bd9Sstevel@tonic-gate /* 2887c478bd9Sstevel@tonic-gate * Thread iteration call-back function. 2897c478bd9Sstevel@tonic-gate * Called once for each user-level thread. 2907c478bd9Sstevel@tonic-gate * Used to build the list of all threads. 2917c478bd9Sstevel@tonic-gate */ 2927c478bd9Sstevel@tonic-gate /* ARGSUSED1 */ 2937c478bd9Sstevel@tonic-gate static int 2947c478bd9Sstevel@tonic-gate thr_stack(const td_thrhandle_t *Thp, void *cd) 2957c478bd9Sstevel@tonic-gate { 2967c478bd9Sstevel@tonic-gate td_thrinfo_t thrinfo; 2977c478bd9Sstevel@tonic-gate struct threadinfo *tip; 2987c478bd9Sstevel@tonic-gate td_err_e error; 2997c478bd9Sstevel@tonic-gate 3007c478bd9Sstevel@tonic-gate if (td_thr_get_info(Thp, &thrinfo) != TD_OK) 3017c478bd9Sstevel@tonic-gate return (0); 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate tip = malloc(sizeof (struct threadinfo)); 3047c478bd9Sstevel@tonic-gate tip->next = NULL; 3057c478bd9Sstevel@tonic-gate tip->threadid = thrinfo.ti_tid; 3067c478bd9Sstevel@tonic-gate tip->lwpid = thrinfo.ti_lid; 3077c478bd9Sstevel@tonic-gate tip->state = thrinfo.ti_state; 3087c478bd9Sstevel@tonic-gate tip->startfunc = thrinfo.ti_startfunc; 3097c478bd9Sstevel@tonic-gate tip->exitval = (uintptr_t)thrinfo.ti_exitval; 3107c478bd9Sstevel@tonic-gate nthreads++; 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate if (thrinfo.ti_state == TD_THR_ZOMBIE || 3137c478bd9Sstevel@tonic-gate ((error = td_thr_getgregs(Thp, tip->regs)) != TD_OK && 3147c478bd9Sstevel@tonic-gate error != TD_PARTIALREG)) 3157c478bd9Sstevel@tonic-gate (void) memset(tip->regs, 0, sizeof (prgregset_t)); 3167c478bd9Sstevel@tonic-gate 3177c478bd9Sstevel@tonic-gate if (thr_tail) 3187c478bd9Sstevel@tonic-gate thr_tail->next = tip; 3197c478bd9Sstevel@tonic-gate else 3207c478bd9Sstevel@tonic-gate thr_head = tip; 3217c478bd9Sstevel@tonic-gate thr_tail = tip; 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate return (0); 3247c478bd9Sstevel@tonic-gate } 3257c478bd9Sstevel@tonic-gate 3267c478bd9Sstevel@tonic-gate static void 3277c478bd9Sstevel@tonic-gate free_threadinfo() 3287c478bd9Sstevel@tonic-gate { 3297c478bd9Sstevel@tonic-gate struct threadinfo *tip = thr_head; 3307c478bd9Sstevel@tonic-gate struct threadinfo *next; 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate while (tip) { 3337c478bd9Sstevel@tonic-gate next = tip->next; 3347c478bd9Sstevel@tonic-gate free(tip); 3357c478bd9Sstevel@tonic-gate tip = next; 3367c478bd9Sstevel@tonic-gate } 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate thr_head = thr_tail = NULL; 3397c478bd9Sstevel@tonic-gate } 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate /* 3427c478bd9Sstevel@tonic-gate * Find and eliminate the thread corresponding to the given lwpid. 3437c478bd9Sstevel@tonic-gate */ 3447c478bd9Sstevel@tonic-gate static struct threadinfo * 3457c478bd9Sstevel@tonic-gate find_thread(id_t lwpid) 3467c478bd9Sstevel@tonic-gate { 3477c478bd9Sstevel@tonic-gate struct threadinfo *tip; 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate for (tip = thr_head; tip; tip = tip->next) { 3507c478bd9Sstevel@tonic-gate if (lwpid == tip->lwpid) { 3517c478bd9Sstevel@tonic-gate tip->lwpid = 0; 3527c478bd9Sstevel@tonic-gate return (tip); 3537c478bd9Sstevel@tonic-gate } 3547c478bd9Sstevel@tonic-gate } 3557c478bd9Sstevel@tonic-gate return (NULL); 3567c478bd9Sstevel@tonic-gate } 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate static int 3597c478bd9Sstevel@tonic-gate thread_call_stack(void *data, const lwpstatus_t *psp, 3607c478bd9Sstevel@tonic-gate const lwpsinfo_t *pip) 3617c478bd9Sstevel@tonic-gate { 3627c478bd9Sstevel@tonic-gate pstack_handle_t *h = data; 3637c478bd9Sstevel@tonic-gate lwpstatus_t lwpstatus; 3647c478bd9Sstevel@tonic-gate struct threadinfo *tip; 3657c478bd9Sstevel@tonic-gate 3667c478bd9Sstevel@tonic-gate if (!proc_lwp_in_set(h->lwps, pip->pr_lwpid)) 3677c478bd9Sstevel@tonic-gate return (0); 3687c478bd9Sstevel@tonic-gate h->count++; 3697c478bd9Sstevel@tonic-gate 3707c478bd9Sstevel@tonic-gate if ((tip = find_thread(pip->pr_lwpid)) == NULL) 3717c478bd9Sstevel@tonic-gate return (0); 3727c478bd9Sstevel@tonic-gate 3737c478bd9Sstevel@tonic-gate tlhead(tip->threadid, pip->pr_lwpid); 3747c478bd9Sstevel@tonic-gate tip->threadid = 0; /* finish eliminating tid */ 3757c478bd9Sstevel@tonic-gate if (psp) 3767c478bd9Sstevel@tonic-gate call_stack(h, psp); 3777c478bd9Sstevel@tonic-gate else { 3787c478bd9Sstevel@tonic-gate if (tip->state == TD_THR_ZOMBIE) 3797c478bd9Sstevel@tonic-gate print_zombie(h->proc, tip); 3807c478bd9Sstevel@tonic-gate else { 3817c478bd9Sstevel@tonic-gate (void) memset(&lwpstatus, 0, sizeof (lwpstatus)); 3827c478bd9Sstevel@tonic-gate (void) memcpy(lwpstatus.pr_reg, tip->regs, 3837c478bd9Sstevel@tonic-gate sizeof (prgregset_t)); 3847c478bd9Sstevel@tonic-gate call_stack(h, &lwpstatus); 3857c478bd9Sstevel@tonic-gate } 3867c478bd9Sstevel@tonic-gate } 3877c478bd9Sstevel@tonic-gate return (0); 3887c478bd9Sstevel@tonic-gate } 3897c478bd9Sstevel@tonic-gate 3907c478bd9Sstevel@tonic-gate static int 3917c478bd9Sstevel@tonic-gate lwp_call_stack(void *data, 3927c478bd9Sstevel@tonic-gate const lwpstatus_t *psp, const lwpsinfo_t *pip) 3937c478bd9Sstevel@tonic-gate { 3947c478bd9Sstevel@tonic-gate pstack_handle_t *h = data; 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate if (!proc_lwp_in_set(h->lwps, pip->pr_lwpid)) 3977c478bd9Sstevel@tonic-gate return (0); 3987c478bd9Sstevel@tonic-gate h->count++; 3997c478bd9Sstevel@tonic-gate 4007c478bd9Sstevel@tonic-gate tlhead(0, pip->pr_lwpid); 4017c478bd9Sstevel@tonic-gate if (psp) 4027c478bd9Sstevel@tonic-gate call_stack(h, psp); 4037c478bd9Sstevel@tonic-gate else 4047c478bd9Sstevel@tonic-gate (void) printf("\t** zombie " 4057c478bd9Sstevel@tonic-gate "(exited, not detached, not yet joined) **\n"); 4067c478bd9Sstevel@tonic-gate return (0); 4077c478bd9Sstevel@tonic-gate } 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate static int 4107c478bd9Sstevel@tonic-gate all_call_stacks(pstack_handle_t *h, int dothreads) 4117c478bd9Sstevel@tonic-gate { 4127c478bd9Sstevel@tonic-gate struct ps_prochandle *Pr = h->proc; 4137c478bd9Sstevel@tonic-gate pstatus_t status = *Pstatus(Pr); 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate (void) memset(&sigh, 0, sizeof (GElf_Sym)); 4167c478bd9Sstevel@tonic-gate (void) Plookup_by_name(Pr, "libc.so", "sigacthandler", &sigh); 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate if ((status.pr_nlwp + status.pr_nzomb) <= 1 && 4197c478bd9Sstevel@tonic-gate !(dothreads && nthreads > 1)) { 4207c478bd9Sstevel@tonic-gate if (proc_lwp_in_set(h->lwps, status.pr_lwp.pr_lwpid)) { 4217c478bd9Sstevel@tonic-gate call_stack(h, &status.pr_lwp); 4227c478bd9Sstevel@tonic-gate h->count++; 4237c478bd9Sstevel@tonic-gate } 4247c478bd9Sstevel@tonic-gate } else { 4257c478bd9Sstevel@tonic-gate lwpstatus_t lwpstatus; 4267c478bd9Sstevel@tonic-gate struct threadinfo *tip; 4277c478bd9Sstevel@tonic-gate id_t tid; 4287c478bd9Sstevel@tonic-gate 4297c478bd9Sstevel@tonic-gate if (dothreads) 4307c478bd9Sstevel@tonic-gate (void) Plwp_iter_all(Pr, thread_call_stack, h); 4317c478bd9Sstevel@tonic-gate else 4327c478bd9Sstevel@tonic-gate (void) Plwp_iter_all(Pr, lwp_call_stack, h); 4337c478bd9Sstevel@tonic-gate 4347c478bd9Sstevel@tonic-gate /* for each remaining thread w/o an lwp */ 4357c478bd9Sstevel@tonic-gate (void) memset(&lwpstatus, 0, sizeof (lwpstatus)); 4367c478bd9Sstevel@tonic-gate for (tip = thr_head; tip; tip = tip->next) { 4377c478bd9Sstevel@tonic-gate 4387c478bd9Sstevel@tonic-gate if (!proc_lwp_in_set(h->lwps, tip->lwpid)) 4397c478bd9Sstevel@tonic-gate tip->threadid = 0; 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate if ((tid = tip->threadid) != 0) { 4427c478bd9Sstevel@tonic-gate (void) memcpy(lwpstatus.pr_reg, tip->regs, 4437c478bd9Sstevel@tonic-gate sizeof (prgregset_t)); 4447c478bd9Sstevel@tonic-gate tlhead(tid, tip->lwpid); 4457c478bd9Sstevel@tonic-gate if (tip->state == TD_THR_ZOMBIE) 4467c478bd9Sstevel@tonic-gate print_zombie(Pr, tip); 4477c478bd9Sstevel@tonic-gate else 4487c478bd9Sstevel@tonic-gate call_stack(h, &lwpstatus); 4497c478bd9Sstevel@tonic-gate } 4507c478bd9Sstevel@tonic-gate tip->threadid = 0; 4517c478bd9Sstevel@tonic-gate tip->lwpid = 0; 4527c478bd9Sstevel@tonic-gate } 4537c478bd9Sstevel@tonic-gate } 4547c478bd9Sstevel@tonic-gate return (0); 4557c478bd9Sstevel@tonic-gate } 4567c478bd9Sstevel@tonic-gate 4577c478bd9Sstevel@tonic-gate static void 4587c478bd9Sstevel@tonic-gate tlhead(id_t threadid, id_t lwpid) 4597c478bd9Sstevel@tonic-gate { 4607c478bd9Sstevel@tonic-gate if (threadid == 0 && lwpid == 0) 4617c478bd9Sstevel@tonic-gate return; 4627c478bd9Sstevel@tonic-gate 4637c478bd9Sstevel@tonic-gate (void) printf("-----------------"); 4647c478bd9Sstevel@tonic-gate 4657c478bd9Sstevel@tonic-gate if (threadid && lwpid) 4667c478bd9Sstevel@tonic-gate (void) printf(" lwp# %d / thread# %d ", 4677c478bd9Sstevel@tonic-gate (int)lwpid, (int)threadid); 4687c478bd9Sstevel@tonic-gate else if (threadid) 4697c478bd9Sstevel@tonic-gate (void) printf("--------- thread# %d ", (int)threadid); 4707c478bd9Sstevel@tonic-gate else if (lwpid) 4717c478bd9Sstevel@tonic-gate (void) printf(" lwp# %d ------------", (int)lwpid); 4727c478bd9Sstevel@tonic-gate 4737c478bd9Sstevel@tonic-gate (void) printf("--------------------\n"); 4747c478bd9Sstevel@tonic-gate } 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4777c478bd9Sstevel@tonic-gate static int 4787c478bd9Sstevel@tonic-gate print_java_frame(void *cld, prgregset_t gregs, const char *name, int bci, 4797c478bd9Sstevel@tonic-gate int line, void *handle) 4807c478bd9Sstevel@tonic-gate { 4817c478bd9Sstevel@tonic-gate int length = (is64 ? 16 : 8); 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate (void) printf(" %.*lx * %s", length, (long)gregs[R_PC], name); 4847c478bd9Sstevel@tonic-gate 4857c478bd9Sstevel@tonic-gate if (bci != -1) { 4867c478bd9Sstevel@tonic-gate (void) printf("+%d", bci); 4877c478bd9Sstevel@tonic-gate if (line) 4887c478bd9Sstevel@tonic-gate (void) printf(" (line %d)", line); 4897c478bd9Sstevel@tonic-gate } 4907c478bd9Sstevel@tonic-gate (void) printf("\n"); 4917c478bd9Sstevel@tonic-gate 4927c478bd9Sstevel@tonic-gate return (0); 4937c478bd9Sstevel@tonic-gate } 4947c478bd9Sstevel@tonic-gate 4957c478bd9Sstevel@tonic-gate static sigjmp_buf jumpbuf; 4967c478bd9Sstevel@tonic-gate 4977c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4987c478bd9Sstevel@tonic-gate static void 4997c478bd9Sstevel@tonic-gate fatal_signal(int signo) 5007c478bd9Sstevel@tonic-gate { 5017c478bd9Sstevel@tonic-gate siglongjmp(jumpbuf, 1); 5027c478bd9Sstevel@tonic-gate } 5037c478bd9Sstevel@tonic-gate 5047c478bd9Sstevel@tonic-gate static int 5057c478bd9Sstevel@tonic-gate print_frame(void *cd, prgregset_t gregs, uint_t argc, const long *argv) 5067c478bd9Sstevel@tonic-gate { 5077c478bd9Sstevel@tonic-gate pstack_handle_t *h = cd; 5087c478bd9Sstevel@tonic-gate struct ps_prochandle *Pr = h->proc; 5097c478bd9Sstevel@tonic-gate uintptr_t pc = gregs[R_PC]; 5107c478bd9Sstevel@tonic-gate char buff[255]; 5117c478bd9Sstevel@tonic-gate GElf_Sym sym; 5127c478bd9Sstevel@tonic-gate uintptr_t start; 5137c478bd9Sstevel@tonic-gate int length = (is64? 16 : 8); 5147c478bd9Sstevel@tonic-gate int i; 5157c478bd9Sstevel@tonic-gate 5167c478bd9Sstevel@tonic-gate /* 5177c478bd9Sstevel@tonic-gate * If we are in a system call, we display the entry frame in a more 5187c478bd9Sstevel@tonic-gate * readable manner, using the name of the system call. In this case, we 5197c478bd9Sstevel@tonic-gate * want to ignore this first frame, since we already displayed it 5207c478bd9Sstevel@tonic-gate * separately. 5217c478bd9Sstevel@tonic-gate */ 5227c478bd9Sstevel@tonic-gate if (h->ignore_frame) { 5237c478bd9Sstevel@tonic-gate h->ignore_frame = 0; 5247c478bd9Sstevel@tonic-gate return (0); 5257c478bd9Sstevel@tonic-gate } 5267c478bd9Sstevel@tonic-gate 5277c478bd9Sstevel@tonic-gate (void) sprintf(buff, "%.*lx", length, (long)pc); 5287c478bd9Sstevel@tonic-gate (void) strcpy(buff + length, " ????????"); 5297c478bd9Sstevel@tonic-gate if (Plookup_by_addr(Pr, pc, 5307c478bd9Sstevel@tonic-gate buff + 1 + length, sizeof (buff) - 1 - length, &sym) == 0) { 5317c478bd9Sstevel@tonic-gate start = sym.st_value; 5327c478bd9Sstevel@tonic-gate } else if (h->jvm != NULL) { 5337c478bd9Sstevel@tonic-gate int ret; 5347c478bd9Sstevel@tonic-gate void (*segv)(int), (*bus)(int), (*ill)(int); 5357c478bd9Sstevel@tonic-gate 5367c478bd9Sstevel@tonic-gate segv = signal(SIGSEGV, fatal_signal); 5377c478bd9Sstevel@tonic-gate bus = signal(SIGBUS, fatal_signal); 5387c478bd9Sstevel@tonic-gate ill = signal(SIGILL, fatal_signal); 5397c478bd9Sstevel@tonic-gate 5407c478bd9Sstevel@tonic-gate /* Insure against a bad libjvm_db */ 5417c478bd9Sstevel@tonic-gate if (sigsetjmp(jumpbuf, 0) == 0) 5427c478bd9Sstevel@tonic-gate ret = j_frame_iter(h->jvm, gregs, print_java_frame, 5437c478bd9Sstevel@tonic-gate NULL); 5447c478bd9Sstevel@tonic-gate else 5457c478bd9Sstevel@tonic-gate ret = -1; 5467c478bd9Sstevel@tonic-gate 5477c478bd9Sstevel@tonic-gate (void) signal(SIGSEGV, segv); 5487c478bd9Sstevel@tonic-gate (void) signal(SIGBUS, bus); 5497c478bd9Sstevel@tonic-gate (void) signal(SIGILL, ill); 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate if (ret == 0) 5527c478bd9Sstevel@tonic-gate return (ret); 5537c478bd9Sstevel@tonic-gate } else { 5547c478bd9Sstevel@tonic-gate start = pc; 5557c478bd9Sstevel@tonic-gate } 5567c478bd9Sstevel@tonic-gate 5577c478bd9Sstevel@tonic-gate (void) printf(" %-17s (", buff); 5587c478bd9Sstevel@tonic-gate for (i = 0; i < argc && i < MAX_ARGS; i++) 5597c478bd9Sstevel@tonic-gate (void) printf((i+1 == argc)? "%lx" : "%lx, ", 5607c478bd9Sstevel@tonic-gate argv[i]); 5617c478bd9Sstevel@tonic-gate if (i != argc) 5627c478bd9Sstevel@tonic-gate (void) printf("..."); 5637c478bd9Sstevel@tonic-gate (void) printf((start != pc)? 5647c478bd9Sstevel@tonic-gate ") + %lx\n" : ")\n", (long)(pc - start)); 5657c478bd9Sstevel@tonic-gate 5667c478bd9Sstevel@tonic-gate /* 5677c478bd9Sstevel@tonic-gate * If the frame's pc is in the "sigh" (a.k.a. signal handler, signal 5687c478bd9Sstevel@tonic-gate * hack, or *sigh* ...) range, then we're about to cross a signal 5697c478bd9Sstevel@tonic-gate * frame. The signal number is the first argument to this function. 5707c478bd9Sstevel@tonic-gate */ 5717c478bd9Sstevel@tonic-gate if (pc - sigh.st_value < sigh.st_size) { 5727c478bd9Sstevel@tonic-gate if (sig2str((int)argv[0], buff) == -1) 5737c478bd9Sstevel@tonic-gate (void) strcpy(buff, " Unknown"); 5747c478bd9Sstevel@tonic-gate (void) printf(" --- called from signal handler with " 5757c478bd9Sstevel@tonic-gate "signal %d (SIG%s) ---\n", (int)argv[0], buff); 5767c478bd9Sstevel@tonic-gate } 5777c478bd9Sstevel@tonic-gate 5787c478bd9Sstevel@tonic-gate return (0); 5797c478bd9Sstevel@tonic-gate } 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate static void 5827c478bd9Sstevel@tonic-gate print_zombie(struct ps_prochandle *Pr, struct threadinfo *tip) 5837c478bd9Sstevel@tonic-gate { 5847c478bd9Sstevel@tonic-gate char buff[255]; 5857c478bd9Sstevel@tonic-gate GElf_Sym sym; 5867c478bd9Sstevel@tonic-gate uintptr_t start; 5877c478bd9Sstevel@tonic-gate int length = (is64? 16 : 8); 5887c478bd9Sstevel@tonic-gate 5897c478bd9Sstevel@tonic-gate (void) sprintf(buff, "%.*lx", length, (long)tip->startfunc); 5907c478bd9Sstevel@tonic-gate (void) strcpy(buff + length, " ????????"); 5917c478bd9Sstevel@tonic-gate if (Plookup_by_addr(Pr, tip->startfunc, 5927c478bd9Sstevel@tonic-gate buff + 1 + length, sizeof (buff) - 1 - length, &sym) == 0) 5937c478bd9Sstevel@tonic-gate start = sym.st_value; 5947c478bd9Sstevel@tonic-gate else 5957c478bd9Sstevel@tonic-gate start = tip->startfunc; 5967c478bd9Sstevel@tonic-gate (void) printf(" %s()", buff); 5977c478bd9Sstevel@tonic-gate if (start != tip->startfunc) /* doesn't happen? */ 5987c478bd9Sstevel@tonic-gate (void) printf("+%lx", (long)(tip->startfunc - start)); 5997c478bd9Sstevel@tonic-gate (void) printf(", exit value = 0x%.*lx\n", length, (long)tip->exitval); 6007c478bd9Sstevel@tonic-gate (void) printf("\t** zombie " 6017c478bd9Sstevel@tonic-gate "(exited, not detached, not yet joined) **\n"); 6027c478bd9Sstevel@tonic-gate } 6037c478bd9Sstevel@tonic-gate 6047c478bd9Sstevel@tonic-gate static void 6057c478bd9Sstevel@tonic-gate print_syscall(const lwpstatus_t *psp, prgregset_t reg) 6067c478bd9Sstevel@tonic-gate { 6077c478bd9Sstevel@tonic-gate char sname[32]; 6087c478bd9Sstevel@tonic-gate int length = (is64? 16 : 8); 6097c478bd9Sstevel@tonic-gate uint_t i; 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate (void) proc_sysname(psp->pr_syscall, sname, sizeof (sname)); 6127c478bd9Sstevel@tonic-gate (void) printf(" %.*lx %-8s (", length, (long)reg[R_PC], sname); 6137c478bd9Sstevel@tonic-gate for (i = 0; i < psp->pr_nsysarg; i++) 6147c478bd9Sstevel@tonic-gate (void) printf((i+1 == psp->pr_nsysarg)? "%lx" : "%lx, ", 6157c478bd9Sstevel@tonic-gate (long)psp->pr_sysarg[i]); 6167c478bd9Sstevel@tonic-gate (void) printf(")\n"); 6177c478bd9Sstevel@tonic-gate } 6187c478bd9Sstevel@tonic-gate 6197c478bd9Sstevel@tonic-gate static void 6207c478bd9Sstevel@tonic-gate call_stack(pstack_handle_t *h, const lwpstatus_t *psp) 6217c478bd9Sstevel@tonic-gate { 6227c478bd9Sstevel@tonic-gate prgregset_t reg; 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate (void) memcpy(reg, psp->pr_reg, sizeof (reg)); 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate if ((psp->pr_flags & (PR_ASLEEP|PR_VFORKP)) || 6277c478bd9Sstevel@tonic-gate ((psp->pr_flags & PR_ISTOP) && 6287c478bd9Sstevel@tonic-gate (psp->pr_why == PR_SYSENTRY || 6297c478bd9Sstevel@tonic-gate psp->pr_why == PR_SYSEXIT))) { 6307c478bd9Sstevel@tonic-gate print_syscall(psp, reg); 6317c478bd9Sstevel@tonic-gate h->ignore_frame = 1; 6327c478bd9Sstevel@tonic-gate } else { 6337c478bd9Sstevel@tonic-gate h->ignore_frame = 0; 6347c478bd9Sstevel@tonic-gate } 6357c478bd9Sstevel@tonic-gate 6367c478bd9Sstevel@tonic-gate (void) Pstack_iter(h->proc, reg, print_frame, h); 6377c478bd9Sstevel@tonic-gate } 6387c478bd9Sstevel@tonic-gate 6397c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6407c478bd9Sstevel@tonic-gate static int 6417c478bd9Sstevel@tonic-gate jvm_object_iter(void *cd, const prmap_t *pmp, const char *obj) 6427c478bd9Sstevel@tonic-gate { 6437c478bd9Sstevel@tonic-gate char path[PATH_MAX]; 6447c478bd9Sstevel@tonic-gate char *name; 6457c478bd9Sstevel@tonic-gate char *s1, *s2; 6467c478bd9Sstevel@tonic-gate struct ps_prochandle *Pr = cd; 6477c478bd9Sstevel@tonic-gate 6487c478bd9Sstevel@tonic-gate if ((name = strstr(obj, "/libjvm.so")) == NULL) 6497c478bd9Sstevel@tonic-gate name = strstr(obj, "/libjvm_g.so"); 6507c478bd9Sstevel@tonic-gate 6517c478bd9Sstevel@tonic-gate if (name) { 6527c478bd9Sstevel@tonic-gate (void) strcpy(path, obj); 6537c478bd9Sstevel@tonic-gate if (Pstatus(Pr)->pr_dmodel != PR_MODEL_NATIVE) { 6547c478bd9Sstevel@tonic-gate s1 = name; 6557c478bd9Sstevel@tonic-gate s2 = path + (s1 - obj); 6567c478bd9Sstevel@tonic-gate (void) strcpy(s2, "/64"); 6577c478bd9Sstevel@tonic-gate s2 += 3; 6587c478bd9Sstevel@tonic-gate (void) strcpy(s2, s1); 6597c478bd9Sstevel@tonic-gate } 6607c478bd9Sstevel@tonic-gate 6617c478bd9Sstevel@tonic-gate s1 = strstr(obj, ".so"); 6627c478bd9Sstevel@tonic-gate s2 = strstr(path, ".so"); 6637c478bd9Sstevel@tonic-gate (void) strcpy(s2, "_db"); 6647c478bd9Sstevel@tonic-gate s2 += 3; 6657c478bd9Sstevel@tonic-gate (void) strcpy(s2, s1); 6667c478bd9Sstevel@tonic-gate 6677c478bd9Sstevel@tonic-gate if ((libjvm = dlopen(path, RTLD_LAZY|RTLD_GLOBAL)) != NULL) 6687c478bd9Sstevel@tonic-gate return (1); 6697c478bd9Sstevel@tonic-gate } 6707c478bd9Sstevel@tonic-gate 6717c478bd9Sstevel@tonic-gate return (0); 6727c478bd9Sstevel@tonic-gate } 6737c478bd9Sstevel@tonic-gate 6747c478bd9Sstevel@tonic-gate static jvm_agent_t * 6757c478bd9Sstevel@tonic-gate load_libjvm(struct ps_prochandle *Pr) 6767c478bd9Sstevel@tonic-gate { 6777c478bd9Sstevel@tonic-gate jvm_agent_t *ret; 6787c478bd9Sstevel@tonic-gate 6797c478bd9Sstevel@tonic-gate (void) Pobject_iter(Pr, jvm_object_iter, Pr); 6807c478bd9Sstevel@tonic-gate 6817c478bd9Sstevel@tonic-gate if (libjvm) { 6827c478bd9Sstevel@tonic-gate j_agent_create = (j_agent_create_f) 6837c478bd9Sstevel@tonic-gate dlsym(libjvm, "Jagent_create"); 6847c478bd9Sstevel@tonic-gate j_agent_destroy = (j_agent_destroy_f) 6857c478bd9Sstevel@tonic-gate dlsym(libjvm, "Jagent_destroy"); 6867c478bd9Sstevel@tonic-gate j_frame_iter = (j_frame_iter_f) 6877c478bd9Sstevel@tonic-gate dlsym(libjvm, "Jframe_iter"); 6887c478bd9Sstevel@tonic-gate 6897c478bd9Sstevel@tonic-gate if (j_agent_create == NULL || j_agent_destroy == NULL || 6907c478bd9Sstevel@tonic-gate j_frame_iter == NULL || 6917c478bd9Sstevel@tonic-gate (ret = j_agent_create(Pr, JVM_DB_VERSION)) == NULL) { 6927c478bd9Sstevel@tonic-gate reset_libjvm(NULL); 6937c478bd9Sstevel@tonic-gate return (NULL); 6947c478bd9Sstevel@tonic-gate } 6957c478bd9Sstevel@tonic-gate 6967c478bd9Sstevel@tonic-gate return (ret); 6977c478bd9Sstevel@tonic-gate } 6987c478bd9Sstevel@tonic-gate 6997c478bd9Sstevel@tonic-gate return (NULL); 7007c478bd9Sstevel@tonic-gate } 7017c478bd9Sstevel@tonic-gate 7027c478bd9Sstevel@tonic-gate static void 7037c478bd9Sstevel@tonic-gate reset_libjvm(jvm_agent_t *agent) 7047c478bd9Sstevel@tonic-gate { 7057c478bd9Sstevel@tonic-gate if (libjvm) { 7067c478bd9Sstevel@tonic-gate if (agent) 7077c478bd9Sstevel@tonic-gate j_agent_destroy(agent); 7087c478bd9Sstevel@tonic-gate 7097c478bd9Sstevel@tonic-gate (void) dlclose(libjvm); 7107c478bd9Sstevel@tonic-gate } 7117c478bd9Sstevel@tonic-gate 7127c478bd9Sstevel@tonic-gate j_agent_create = NULL; 7137c478bd9Sstevel@tonic-gate j_agent_destroy = NULL; 7147c478bd9Sstevel@tonic-gate j_frame_iter = NULL; 7157c478bd9Sstevel@tonic-gate libjvm = NULL; 7167c478bd9Sstevel@tonic-gate } 717