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