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*ea394cb0Sjohansen * Copyright 2010 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 /* 104*ea394cb0Sjohansen * Similar to what's done for debugging java programs, here are prototypes for 105*ea394cb0Sjohansen * the library that allows us to debug Python programs. 106*ea394cb0Sjohansen */ 107*ea394cb0Sjohansen #define PYDB_VERSION 1 108*ea394cb0Sjohansen static void *libpython; 109*ea394cb0Sjohansen 110*ea394cb0Sjohansen typedef struct pydb_agent pydb_agent_t; 111*ea394cb0Sjohansen 112*ea394cb0Sjohansen typedef pydb_agent_t *(*pydb_agent_create_f)(struct ps_prochandle *P, int vers); 113*ea394cb0Sjohansen typedef void (*pydb_agent_destroy_f)(pydb_agent_t *py); 114*ea394cb0Sjohansen typedef int (*pydb_pc_frameinfo_f)(pydb_agent_t *py, uintptr_t pc, 115*ea394cb0Sjohansen uintptr_t frame_addr, char *fbuf, size_t bufsz); 116*ea394cb0Sjohansen 117*ea394cb0Sjohansen static pydb_agent_create_f pydb_agent_create; 118*ea394cb0Sjohansen static pydb_agent_destroy_f pydb_agent_destroy; 119*ea394cb0Sjohansen static pydb_pc_frameinfo_f pydb_pc_frameinfo; 120*ea394cb0Sjohansen 121*ea394cb0Sjohansen static pydb_agent_t *load_libpython(struct ps_prochandle *P); 122*ea394cb0Sjohansen static void reset_libpython(pydb_agent_t *); 123*ea394cb0Sjohansen /* 1247c478bd9Sstevel@tonic-gate * Since we must maintain both a proc handle and a jvm handle, this structure 1257c478bd9Sstevel@tonic-gate * is the basic type that gets passed around. 1267c478bd9Sstevel@tonic-gate */ 1277c478bd9Sstevel@tonic-gate typedef struct pstack_handle { 1287c478bd9Sstevel@tonic-gate struct ps_prochandle *proc; 1297c478bd9Sstevel@tonic-gate jvm_agent_t *jvm; 1307c478bd9Sstevel@tonic-gate int ignore_frame; 1317c478bd9Sstevel@tonic-gate const char *lwps; 1327c478bd9Sstevel@tonic-gate int count; 133*ea394cb0Sjohansen pydb_agent_t *pydb; 1347c478bd9Sstevel@tonic-gate } pstack_handle_t; 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate static int thr_stack(const td_thrhandle_t *, void *); 1377c478bd9Sstevel@tonic-gate static void free_threadinfo(void); 1387c478bd9Sstevel@tonic-gate static struct threadinfo *find_thread(id_t); 1397c478bd9Sstevel@tonic-gate static int all_call_stacks(pstack_handle_t *, int); 1407c478bd9Sstevel@tonic-gate static void tlhead(id_t, id_t); 1417c478bd9Sstevel@tonic-gate static int print_frame(void *, prgregset_t, uint_t, const long *); 1427c478bd9Sstevel@tonic-gate static void print_zombie(struct ps_prochandle *, struct threadinfo *); 1437c478bd9Sstevel@tonic-gate static void print_syscall(const lwpstatus_t *, prgregset_t); 1447c478bd9Sstevel@tonic-gate static void call_stack(pstack_handle_t *, const lwpstatus_t *); 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate /* 1477c478bd9Sstevel@tonic-gate * The number of active and zombie threads. 1487c478bd9Sstevel@tonic-gate */ 1497c478bd9Sstevel@tonic-gate static int nthreads; 1507c478bd9Sstevel@tonic-gate 1517c478bd9Sstevel@tonic-gate int 1527c478bd9Sstevel@tonic-gate main(int argc, char **argv) 1537c478bd9Sstevel@tonic-gate { 1547c478bd9Sstevel@tonic-gate int retc = 0; 1557c478bd9Sstevel@tonic-gate int opt; 1567c478bd9Sstevel@tonic-gate int errflg = FALSE; 1577c478bd9Sstevel@tonic-gate core_content_t content = CC_CONTENT_DATA | CC_CONTENT_ANON | 1587c478bd9Sstevel@tonic-gate CC_CONTENT_STACK; 1597c478bd9Sstevel@tonic-gate struct rlimit rlim; 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate if ((command = strrchr(argv[0], '/')) != NULL) 1627c478bd9Sstevel@tonic-gate command++; 1637c478bd9Sstevel@tonic-gate else 1647c478bd9Sstevel@tonic-gate command = argv[0]; 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate /* options */ 1677c478bd9Sstevel@tonic-gate while ((opt = getopt(argc, argv, "F")) != EOF) { 1687c478bd9Sstevel@tonic-gate switch (opt) { 1697c478bd9Sstevel@tonic-gate case 'F': 1707c478bd9Sstevel@tonic-gate /* 1717c478bd9Sstevel@tonic-gate * If the user specifies the force option, we'll 1727c478bd9Sstevel@tonic-gate * consent to printing out other threads' stacks 1737c478bd9Sstevel@tonic-gate * even if the main stack is absent. 1747c478bd9Sstevel@tonic-gate */ 1757c478bd9Sstevel@tonic-gate content &= ~CC_CONTENT_STACK; 1767c478bd9Sstevel@tonic-gate Fflag = PGRAB_FORCE; 1777c478bd9Sstevel@tonic-gate break; 1787c478bd9Sstevel@tonic-gate default: 1797c478bd9Sstevel@tonic-gate errflg = TRUE; 1807c478bd9Sstevel@tonic-gate break; 1817c478bd9Sstevel@tonic-gate } 1827c478bd9Sstevel@tonic-gate } 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate argc -= optind; 1857c478bd9Sstevel@tonic-gate argv += optind; 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate if (errflg || argc <= 0) { 1887c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1897c478bd9Sstevel@tonic-gate "usage:\t%s [-F] { pid | core }[/lwps] ...\n", command); 1907c478bd9Sstevel@tonic-gate (void) fprintf(stderr, " (show process call stack)\n"); 1917c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1927c478bd9Sstevel@tonic-gate " -F: force grabbing of the target process\n"); 1937c478bd9Sstevel@tonic-gate exit(2); 1947c478bd9Sstevel@tonic-gate } 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate /* 1977c478bd9Sstevel@tonic-gate * Make sure we'll have enough file descriptors to handle a target 1987c478bd9Sstevel@tonic-gate * that has many many mappings. 1997c478bd9Sstevel@tonic-gate */ 2007c478bd9Sstevel@tonic-gate if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) { 2017c478bd9Sstevel@tonic-gate rlim.rlim_cur = rlim.rlim_max; 2027c478bd9Sstevel@tonic-gate (void) setrlimit(RLIMIT_NOFILE, &rlim); 203004388ebScasper (void) enable_extended_FILE_stdio(-1, -1); 2047c478bd9Sstevel@tonic-gate } 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate (void) proc_initstdio(); 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate while (--argc >= 0) { 2097c478bd9Sstevel@tonic-gate int gcode; 2107c478bd9Sstevel@tonic-gate psinfo_t psinfo; 2117c478bd9Sstevel@tonic-gate const psinfo_t *tpsinfo; 2127c478bd9Sstevel@tonic-gate struct ps_prochandle *Pr = NULL; 2137c478bd9Sstevel@tonic-gate td_thragent_t *Tap; 2147c478bd9Sstevel@tonic-gate int threaded; 2157c478bd9Sstevel@tonic-gate pstack_handle_t handle; 2167c478bd9Sstevel@tonic-gate const char *lwps, *arg; 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate (void) proc_flushstdio(); 2197c478bd9Sstevel@tonic-gate 2207c478bd9Sstevel@tonic-gate arg = *argv++; 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate if ((Pr = proc_arg_xgrab(arg, NULL, PR_ARG_ANY, 2237c478bd9Sstevel@tonic-gate Fflag, &gcode, &lwps)) == NULL) { 2247c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: cannot examine %s: %s\n", 2257c478bd9Sstevel@tonic-gate command, arg, Pgrab_error(gcode)); 2267c478bd9Sstevel@tonic-gate retc++; 2277c478bd9Sstevel@tonic-gate continue; 2287c478bd9Sstevel@tonic-gate } 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate if ((tpsinfo = Ppsinfo(Pr)) == NULL) { 2317c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: cannot examine %s: " 2327c478bd9Sstevel@tonic-gate "lost control of process\n", command, arg); 2337c478bd9Sstevel@tonic-gate Prelease(Pr, 0); 2347c478bd9Sstevel@tonic-gate retc++; 2357c478bd9Sstevel@tonic-gate continue; 2367c478bd9Sstevel@tonic-gate } 2377c478bd9Sstevel@tonic-gate (void) memcpy(&psinfo, tpsinfo, sizeof (psinfo_t)); 2387c478bd9Sstevel@tonic-gate proc_unctrl_psinfo(&psinfo); 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate if (Pstate(Pr) == PS_DEAD) { 2417c478bd9Sstevel@tonic-gate if ((Pcontent(Pr) & content) != content) { 2427c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: core '%s' has " 2437c478bd9Sstevel@tonic-gate "insufficient content\n", command, arg); 2447c478bd9Sstevel@tonic-gate retc++; 2457c478bd9Sstevel@tonic-gate continue; 2467c478bd9Sstevel@tonic-gate } 2477c478bd9Sstevel@tonic-gate (void) printf("core '%s' of %d:\t%.70s\n", 2487c478bd9Sstevel@tonic-gate arg, (int)psinfo.pr_pid, psinfo.pr_psargs); 2497c478bd9Sstevel@tonic-gate } else { 2507c478bd9Sstevel@tonic-gate (void) printf("%d:\t%.70s\n", 2517c478bd9Sstevel@tonic-gate (int)psinfo.pr_pid, psinfo.pr_psargs); 2527c478bd9Sstevel@tonic-gate } 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate is64 = (psinfo.pr_dmodel == PR_MODEL_LP64); 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate if (Pgetauxval(Pr, AT_BASE) != -1L && Prd_agent(Pr) == NULL) { 2577c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: warning: librtld_db failed " 2587c478bd9Sstevel@tonic-gate "to initialize; symbols from shared libraries will " 2597c478bd9Sstevel@tonic-gate "not be available\n", command); 2607c478bd9Sstevel@tonic-gate } 2617c478bd9Sstevel@tonic-gate 2627c478bd9Sstevel@tonic-gate /* 2637c478bd9Sstevel@tonic-gate * First we need to get a thread agent handle. 2647c478bd9Sstevel@tonic-gate */ 2657c478bd9Sstevel@tonic-gate if (td_init() != TD_OK || 2667c478bd9Sstevel@tonic-gate td_ta_new(Pr, &Tap) != TD_OK) /* no libc */ 2677c478bd9Sstevel@tonic-gate threaded = FALSE; 2687c478bd9Sstevel@tonic-gate else { 2697c478bd9Sstevel@tonic-gate /* 2707c478bd9Sstevel@tonic-gate * Iterate over all threads, calling: 2717c478bd9Sstevel@tonic-gate * thr_stack(td_thrhandle_t *Thp, NULL); 2727c478bd9Sstevel@tonic-gate * for each one to generate the list of threads. 2737c478bd9Sstevel@tonic-gate */ 2747c478bd9Sstevel@tonic-gate nthreads = 0; 2757c478bd9Sstevel@tonic-gate (void) td_ta_thr_iter(Tap, thr_stack, NULL, 2767c478bd9Sstevel@tonic-gate TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY, 2777c478bd9Sstevel@tonic-gate TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS); 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate (void) td_ta_delete(Tap); 2807c478bd9Sstevel@tonic-gate threaded = TRUE; 2817c478bd9Sstevel@tonic-gate } 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate handle.proc = Pr; 2847c478bd9Sstevel@tonic-gate handle.jvm = load_libjvm(Pr); 285*ea394cb0Sjohansen handle.pydb = load_libpython(Pr); 2867c478bd9Sstevel@tonic-gate handle.lwps = lwps; 2877c478bd9Sstevel@tonic-gate handle.count = 0; 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate if (all_call_stacks(&handle, threaded) != 0) 2907c478bd9Sstevel@tonic-gate retc++; 2917c478bd9Sstevel@tonic-gate if (threaded) 2927c478bd9Sstevel@tonic-gate free_threadinfo(); 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate reset_libjvm(handle.jvm); 295*ea394cb0Sjohansen reset_libpython(handle.pydb); 2967c478bd9Sstevel@tonic-gate Prelease(Pr, 0); 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate if (handle.count == 0) 2997c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: no matching LWPs found\n", 3007c478bd9Sstevel@tonic-gate command); 3017c478bd9Sstevel@tonic-gate } 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate (void) proc_finistdio(); 3047c478bd9Sstevel@tonic-gate 3057c478bd9Sstevel@tonic-gate return (retc); 3067c478bd9Sstevel@tonic-gate } 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate /* 3097c478bd9Sstevel@tonic-gate * Thread iteration call-back function. 3107c478bd9Sstevel@tonic-gate * Called once for each user-level thread. 3117c478bd9Sstevel@tonic-gate * Used to build the list of all threads. 3127c478bd9Sstevel@tonic-gate */ 3137c478bd9Sstevel@tonic-gate /* ARGSUSED1 */ 3147c478bd9Sstevel@tonic-gate static int 3157c478bd9Sstevel@tonic-gate thr_stack(const td_thrhandle_t *Thp, void *cd) 3167c478bd9Sstevel@tonic-gate { 3177c478bd9Sstevel@tonic-gate td_thrinfo_t thrinfo; 3187c478bd9Sstevel@tonic-gate struct threadinfo *tip; 3197c478bd9Sstevel@tonic-gate td_err_e error; 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate if (td_thr_get_info(Thp, &thrinfo) != TD_OK) 3227c478bd9Sstevel@tonic-gate return (0); 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate tip = malloc(sizeof (struct threadinfo)); 3257c478bd9Sstevel@tonic-gate tip->next = NULL; 3267c478bd9Sstevel@tonic-gate tip->threadid = thrinfo.ti_tid; 3277c478bd9Sstevel@tonic-gate tip->lwpid = thrinfo.ti_lid; 3287c478bd9Sstevel@tonic-gate tip->state = thrinfo.ti_state; 3297c478bd9Sstevel@tonic-gate tip->startfunc = thrinfo.ti_startfunc; 3307c478bd9Sstevel@tonic-gate tip->exitval = (uintptr_t)thrinfo.ti_exitval; 3317c478bd9Sstevel@tonic-gate nthreads++; 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate if (thrinfo.ti_state == TD_THR_ZOMBIE || 3347c478bd9Sstevel@tonic-gate ((error = td_thr_getgregs(Thp, tip->regs)) != TD_OK && 3357c478bd9Sstevel@tonic-gate error != TD_PARTIALREG)) 3367c478bd9Sstevel@tonic-gate (void) memset(tip->regs, 0, sizeof (prgregset_t)); 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate if (thr_tail) 3397c478bd9Sstevel@tonic-gate thr_tail->next = tip; 3407c478bd9Sstevel@tonic-gate else 3417c478bd9Sstevel@tonic-gate thr_head = tip; 3427c478bd9Sstevel@tonic-gate thr_tail = tip; 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate return (0); 3457c478bd9Sstevel@tonic-gate } 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate static void 3487c478bd9Sstevel@tonic-gate free_threadinfo() 3497c478bd9Sstevel@tonic-gate { 3507c478bd9Sstevel@tonic-gate struct threadinfo *tip = thr_head; 3517c478bd9Sstevel@tonic-gate struct threadinfo *next; 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate while (tip) { 3547c478bd9Sstevel@tonic-gate next = tip->next; 3557c478bd9Sstevel@tonic-gate free(tip); 3567c478bd9Sstevel@tonic-gate tip = next; 3577c478bd9Sstevel@tonic-gate } 3587c478bd9Sstevel@tonic-gate 3597c478bd9Sstevel@tonic-gate thr_head = thr_tail = NULL; 3607c478bd9Sstevel@tonic-gate } 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate /* 3637c478bd9Sstevel@tonic-gate * Find and eliminate the thread corresponding to the given lwpid. 3647c478bd9Sstevel@tonic-gate */ 3657c478bd9Sstevel@tonic-gate static struct threadinfo * 3667c478bd9Sstevel@tonic-gate find_thread(id_t lwpid) 3677c478bd9Sstevel@tonic-gate { 3687c478bd9Sstevel@tonic-gate struct threadinfo *tip; 3697c478bd9Sstevel@tonic-gate 3707c478bd9Sstevel@tonic-gate for (tip = thr_head; tip; tip = tip->next) { 3717c478bd9Sstevel@tonic-gate if (lwpid == tip->lwpid) { 3727c478bd9Sstevel@tonic-gate tip->lwpid = 0; 3737c478bd9Sstevel@tonic-gate return (tip); 3747c478bd9Sstevel@tonic-gate } 3757c478bd9Sstevel@tonic-gate } 3767c478bd9Sstevel@tonic-gate return (NULL); 3777c478bd9Sstevel@tonic-gate } 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate static int 3807c478bd9Sstevel@tonic-gate thread_call_stack(void *data, const lwpstatus_t *psp, 3817c478bd9Sstevel@tonic-gate const lwpsinfo_t *pip) 3827c478bd9Sstevel@tonic-gate { 3837c478bd9Sstevel@tonic-gate pstack_handle_t *h = data; 3847c478bd9Sstevel@tonic-gate lwpstatus_t lwpstatus; 3857c478bd9Sstevel@tonic-gate struct threadinfo *tip; 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate if (!proc_lwp_in_set(h->lwps, pip->pr_lwpid)) 3887c478bd9Sstevel@tonic-gate return (0); 3897c478bd9Sstevel@tonic-gate h->count++; 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate if ((tip = find_thread(pip->pr_lwpid)) == NULL) 3927c478bd9Sstevel@tonic-gate return (0); 3937c478bd9Sstevel@tonic-gate 3947c478bd9Sstevel@tonic-gate tlhead(tip->threadid, pip->pr_lwpid); 3957c478bd9Sstevel@tonic-gate tip->threadid = 0; /* finish eliminating tid */ 3967c478bd9Sstevel@tonic-gate if (psp) 3977c478bd9Sstevel@tonic-gate call_stack(h, psp); 3987c478bd9Sstevel@tonic-gate else { 3997c478bd9Sstevel@tonic-gate if (tip->state == TD_THR_ZOMBIE) 4007c478bd9Sstevel@tonic-gate print_zombie(h->proc, tip); 4017c478bd9Sstevel@tonic-gate else { 4027c478bd9Sstevel@tonic-gate (void) memset(&lwpstatus, 0, sizeof (lwpstatus)); 4037c478bd9Sstevel@tonic-gate (void) memcpy(lwpstatus.pr_reg, tip->regs, 4047c478bd9Sstevel@tonic-gate sizeof (prgregset_t)); 4057c478bd9Sstevel@tonic-gate call_stack(h, &lwpstatus); 4067c478bd9Sstevel@tonic-gate } 4077c478bd9Sstevel@tonic-gate } 4087c478bd9Sstevel@tonic-gate return (0); 4097c478bd9Sstevel@tonic-gate } 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate static int 4127c478bd9Sstevel@tonic-gate lwp_call_stack(void *data, 4137c478bd9Sstevel@tonic-gate const lwpstatus_t *psp, const lwpsinfo_t *pip) 4147c478bd9Sstevel@tonic-gate { 4157c478bd9Sstevel@tonic-gate pstack_handle_t *h = data; 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate if (!proc_lwp_in_set(h->lwps, pip->pr_lwpid)) 4187c478bd9Sstevel@tonic-gate return (0); 4197c478bd9Sstevel@tonic-gate h->count++; 4207c478bd9Sstevel@tonic-gate 4217c478bd9Sstevel@tonic-gate tlhead(0, pip->pr_lwpid); 4227c478bd9Sstevel@tonic-gate if (psp) 4237c478bd9Sstevel@tonic-gate call_stack(h, psp); 4247c478bd9Sstevel@tonic-gate else 4257c478bd9Sstevel@tonic-gate (void) printf("\t** zombie " 4267c478bd9Sstevel@tonic-gate "(exited, not detached, not yet joined) **\n"); 4277c478bd9Sstevel@tonic-gate return (0); 4287c478bd9Sstevel@tonic-gate } 4297c478bd9Sstevel@tonic-gate 4307c478bd9Sstevel@tonic-gate static int 4317c478bd9Sstevel@tonic-gate all_call_stacks(pstack_handle_t *h, int dothreads) 4327c478bd9Sstevel@tonic-gate { 4337c478bd9Sstevel@tonic-gate struct ps_prochandle *Pr = h->proc; 4347c478bd9Sstevel@tonic-gate pstatus_t status = *Pstatus(Pr); 4357c478bd9Sstevel@tonic-gate 4367c478bd9Sstevel@tonic-gate (void) memset(&sigh, 0, sizeof (GElf_Sym)); 4377c478bd9Sstevel@tonic-gate (void) Plookup_by_name(Pr, "libc.so", "sigacthandler", &sigh); 4387c478bd9Sstevel@tonic-gate 4397c478bd9Sstevel@tonic-gate if ((status.pr_nlwp + status.pr_nzomb) <= 1 && 4407c478bd9Sstevel@tonic-gate !(dothreads && nthreads > 1)) { 4417c478bd9Sstevel@tonic-gate if (proc_lwp_in_set(h->lwps, status.pr_lwp.pr_lwpid)) { 4427c478bd9Sstevel@tonic-gate call_stack(h, &status.pr_lwp); 4437c478bd9Sstevel@tonic-gate h->count++; 4447c478bd9Sstevel@tonic-gate } 4457c478bd9Sstevel@tonic-gate } else { 4467c478bd9Sstevel@tonic-gate lwpstatus_t lwpstatus; 4477c478bd9Sstevel@tonic-gate struct threadinfo *tip; 4487c478bd9Sstevel@tonic-gate id_t tid; 4497c478bd9Sstevel@tonic-gate 4507c478bd9Sstevel@tonic-gate if (dothreads) 4517c478bd9Sstevel@tonic-gate (void) Plwp_iter_all(Pr, thread_call_stack, h); 4527c478bd9Sstevel@tonic-gate else 4537c478bd9Sstevel@tonic-gate (void) Plwp_iter_all(Pr, lwp_call_stack, h); 4547c478bd9Sstevel@tonic-gate 4557c478bd9Sstevel@tonic-gate /* for each remaining thread w/o an lwp */ 4567c478bd9Sstevel@tonic-gate (void) memset(&lwpstatus, 0, sizeof (lwpstatus)); 4577c478bd9Sstevel@tonic-gate for (tip = thr_head; tip; tip = tip->next) { 4587c478bd9Sstevel@tonic-gate 4597c478bd9Sstevel@tonic-gate if (!proc_lwp_in_set(h->lwps, tip->lwpid)) 4607c478bd9Sstevel@tonic-gate tip->threadid = 0; 4617c478bd9Sstevel@tonic-gate 4627c478bd9Sstevel@tonic-gate if ((tid = tip->threadid) != 0) { 4637c478bd9Sstevel@tonic-gate (void) memcpy(lwpstatus.pr_reg, tip->regs, 4647c478bd9Sstevel@tonic-gate sizeof (prgregset_t)); 4657c478bd9Sstevel@tonic-gate tlhead(tid, tip->lwpid); 4667c478bd9Sstevel@tonic-gate if (tip->state == TD_THR_ZOMBIE) 4677c478bd9Sstevel@tonic-gate print_zombie(Pr, tip); 4687c478bd9Sstevel@tonic-gate else 4697c478bd9Sstevel@tonic-gate call_stack(h, &lwpstatus); 4707c478bd9Sstevel@tonic-gate } 4717c478bd9Sstevel@tonic-gate tip->threadid = 0; 4727c478bd9Sstevel@tonic-gate tip->lwpid = 0; 4737c478bd9Sstevel@tonic-gate } 4747c478bd9Sstevel@tonic-gate } 4757c478bd9Sstevel@tonic-gate return (0); 4767c478bd9Sstevel@tonic-gate } 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate static void 4797c478bd9Sstevel@tonic-gate tlhead(id_t threadid, id_t lwpid) 4807c478bd9Sstevel@tonic-gate { 4817c478bd9Sstevel@tonic-gate if (threadid == 0 && lwpid == 0) 4827c478bd9Sstevel@tonic-gate return; 4837c478bd9Sstevel@tonic-gate 4847c478bd9Sstevel@tonic-gate (void) printf("-----------------"); 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate if (threadid && lwpid) 4877c478bd9Sstevel@tonic-gate (void) printf(" lwp# %d / thread# %d ", 4887c478bd9Sstevel@tonic-gate (int)lwpid, (int)threadid); 4897c478bd9Sstevel@tonic-gate else if (threadid) 4907c478bd9Sstevel@tonic-gate (void) printf("--------- thread# %d ", (int)threadid); 4917c478bd9Sstevel@tonic-gate else if (lwpid) 4927c478bd9Sstevel@tonic-gate (void) printf(" lwp# %d ------------", (int)lwpid); 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate (void) printf("--------------------\n"); 4957c478bd9Sstevel@tonic-gate } 4967c478bd9Sstevel@tonic-gate 4977c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4987c478bd9Sstevel@tonic-gate static int 4997c478bd9Sstevel@tonic-gate print_java_frame(void *cld, prgregset_t gregs, const char *name, int bci, 5007c478bd9Sstevel@tonic-gate int line, void *handle) 5017c478bd9Sstevel@tonic-gate { 5027c478bd9Sstevel@tonic-gate int length = (is64 ? 16 : 8); 5037c478bd9Sstevel@tonic-gate 5047c478bd9Sstevel@tonic-gate (void) printf(" %.*lx * %s", length, (long)gregs[R_PC], name); 5057c478bd9Sstevel@tonic-gate 5067c478bd9Sstevel@tonic-gate if (bci != -1) { 5077c478bd9Sstevel@tonic-gate (void) printf("+%d", bci); 5087c478bd9Sstevel@tonic-gate if (line) 5097c478bd9Sstevel@tonic-gate (void) printf(" (line %d)", line); 5107c478bd9Sstevel@tonic-gate } 5117c478bd9Sstevel@tonic-gate (void) printf("\n"); 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate return (0); 5147c478bd9Sstevel@tonic-gate } 5157c478bd9Sstevel@tonic-gate 5167c478bd9Sstevel@tonic-gate static sigjmp_buf jumpbuf; 5177c478bd9Sstevel@tonic-gate 5187c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5197c478bd9Sstevel@tonic-gate static void 5207c478bd9Sstevel@tonic-gate fatal_signal(int signo) 5217c478bd9Sstevel@tonic-gate { 5227c478bd9Sstevel@tonic-gate siglongjmp(jumpbuf, 1); 5237c478bd9Sstevel@tonic-gate } 5247c478bd9Sstevel@tonic-gate 5257c478bd9Sstevel@tonic-gate static int 5267c478bd9Sstevel@tonic-gate print_frame(void *cd, prgregset_t gregs, uint_t argc, const long *argv) 5277c478bd9Sstevel@tonic-gate { 5287c478bd9Sstevel@tonic-gate pstack_handle_t *h = cd; 5297c478bd9Sstevel@tonic-gate struct ps_prochandle *Pr = h->proc; 5307c478bd9Sstevel@tonic-gate uintptr_t pc = gregs[R_PC]; 5317c478bd9Sstevel@tonic-gate char buff[255]; 5327c478bd9Sstevel@tonic-gate GElf_Sym sym; 5337c478bd9Sstevel@tonic-gate uintptr_t start; 5347c478bd9Sstevel@tonic-gate int length = (is64? 16 : 8); 5357c478bd9Sstevel@tonic-gate int i; 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate /* 5387c478bd9Sstevel@tonic-gate * If we are in a system call, we display the entry frame in a more 5397c478bd9Sstevel@tonic-gate * readable manner, using the name of the system call. In this case, we 5407c478bd9Sstevel@tonic-gate * want to ignore this first frame, since we already displayed it 5417c478bd9Sstevel@tonic-gate * separately. 5427c478bd9Sstevel@tonic-gate */ 5437c478bd9Sstevel@tonic-gate if (h->ignore_frame) { 5447c478bd9Sstevel@tonic-gate h->ignore_frame = 0; 5457c478bd9Sstevel@tonic-gate return (0); 5467c478bd9Sstevel@tonic-gate } 5477c478bd9Sstevel@tonic-gate 5487c478bd9Sstevel@tonic-gate (void) sprintf(buff, "%.*lx", length, (long)pc); 5497c478bd9Sstevel@tonic-gate (void) strcpy(buff + length, " ????????"); 5507c478bd9Sstevel@tonic-gate if (Plookup_by_addr(Pr, pc, 5517c478bd9Sstevel@tonic-gate buff + 1 + length, sizeof (buff) - 1 - length, &sym) == 0) { 5527c478bd9Sstevel@tonic-gate start = sym.st_value; 5537c478bd9Sstevel@tonic-gate } else if (h->jvm != NULL) { 5547c478bd9Sstevel@tonic-gate int ret; 5557c478bd9Sstevel@tonic-gate void (*segv)(int), (*bus)(int), (*ill)(int); 5567c478bd9Sstevel@tonic-gate 5577c478bd9Sstevel@tonic-gate segv = signal(SIGSEGV, fatal_signal); 5587c478bd9Sstevel@tonic-gate bus = signal(SIGBUS, fatal_signal); 5597c478bd9Sstevel@tonic-gate ill = signal(SIGILL, fatal_signal); 5607c478bd9Sstevel@tonic-gate 5617c478bd9Sstevel@tonic-gate /* Insure against a bad libjvm_db */ 5627c478bd9Sstevel@tonic-gate if (sigsetjmp(jumpbuf, 0) == 0) 5637c478bd9Sstevel@tonic-gate ret = j_frame_iter(h->jvm, gregs, print_java_frame, 5647c478bd9Sstevel@tonic-gate NULL); 5657c478bd9Sstevel@tonic-gate else 5667c478bd9Sstevel@tonic-gate ret = -1; 5677c478bd9Sstevel@tonic-gate 5687c478bd9Sstevel@tonic-gate (void) signal(SIGSEGV, segv); 5697c478bd9Sstevel@tonic-gate (void) signal(SIGBUS, bus); 5707c478bd9Sstevel@tonic-gate (void) signal(SIGILL, ill); 5717c478bd9Sstevel@tonic-gate 5727c478bd9Sstevel@tonic-gate if (ret == 0) 5737c478bd9Sstevel@tonic-gate return (ret); 5747c478bd9Sstevel@tonic-gate } else { 5757c478bd9Sstevel@tonic-gate start = pc; 5767c478bd9Sstevel@tonic-gate } 5777c478bd9Sstevel@tonic-gate 5787c478bd9Sstevel@tonic-gate (void) printf(" %-17s (", buff); 5797c478bd9Sstevel@tonic-gate for (i = 0; i < argc && i < MAX_ARGS; i++) 580186f7fbfSEdward Pilatowicz (void) printf((i+1 == argc) ? "%lx" : "%lx, ", argv[i]); 5817c478bd9Sstevel@tonic-gate if (i != argc) 5827c478bd9Sstevel@tonic-gate (void) printf("..."); 583186f7fbfSEdward Pilatowicz (void) printf((start != pc) ? ") + %lx\n" : ")\n", (long)(pc - start)); 5847c478bd9Sstevel@tonic-gate 585*ea394cb0Sjohansen if (h->pydb != NULL && argc > 0) { 586*ea394cb0Sjohansen char buf_py[1024]; 587*ea394cb0Sjohansen int rc; 588*ea394cb0Sjohansen 589*ea394cb0Sjohansen rc = pydb_pc_frameinfo(h->pydb, pc, argv[0], buf_py, 590*ea394cb0Sjohansen sizeof (buf_py)); 591*ea394cb0Sjohansen if (rc == 0) { 592*ea394cb0Sjohansen (void) printf(" %s", buf_py); 593*ea394cb0Sjohansen } 594*ea394cb0Sjohansen } 595*ea394cb0Sjohansen 5967c478bd9Sstevel@tonic-gate /* 5977c478bd9Sstevel@tonic-gate * If the frame's pc is in the "sigh" (a.k.a. signal handler, signal 5987c478bd9Sstevel@tonic-gate * hack, or *sigh* ...) range, then we're about to cross a signal 5997c478bd9Sstevel@tonic-gate * frame. The signal number is the first argument to this function. 6007c478bd9Sstevel@tonic-gate */ 6017c478bd9Sstevel@tonic-gate if (pc - sigh.st_value < sigh.st_size) { 6027c478bd9Sstevel@tonic-gate if (sig2str((int)argv[0], buff) == -1) 6037c478bd9Sstevel@tonic-gate (void) strcpy(buff, " Unknown"); 6047c478bd9Sstevel@tonic-gate (void) printf(" --- called from signal handler with " 6057c478bd9Sstevel@tonic-gate "signal %d (SIG%s) ---\n", (int)argv[0], buff); 6067c478bd9Sstevel@tonic-gate } 6077c478bd9Sstevel@tonic-gate 6087c478bd9Sstevel@tonic-gate return (0); 6097c478bd9Sstevel@tonic-gate } 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate static void 6127c478bd9Sstevel@tonic-gate print_zombie(struct ps_prochandle *Pr, struct threadinfo *tip) 6137c478bd9Sstevel@tonic-gate { 6147c478bd9Sstevel@tonic-gate char buff[255]; 6157c478bd9Sstevel@tonic-gate GElf_Sym sym; 6167c478bd9Sstevel@tonic-gate uintptr_t start; 6177c478bd9Sstevel@tonic-gate int length = (is64? 16 : 8); 6187c478bd9Sstevel@tonic-gate 6197c478bd9Sstevel@tonic-gate (void) sprintf(buff, "%.*lx", length, (long)tip->startfunc); 6207c478bd9Sstevel@tonic-gate (void) strcpy(buff + length, " ????????"); 6217c478bd9Sstevel@tonic-gate if (Plookup_by_addr(Pr, tip->startfunc, 6227c478bd9Sstevel@tonic-gate buff + 1 + length, sizeof (buff) - 1 - length, &sym) == 0) 6237c478bd9Sstevel@tonic-gate start = sym.st_value; 6247c478bd9Sstevel@tonic-gate else 6257c478bd9Sstevel@tonic-gate start = tip->startfunc; 6267c478bd9Sstevel@tonic-gate (void) printf(" %s()", buff); 6277c478bd9Sstevel@tonic-gate if (start != tip->startfunc) /* doesn't happen? */ 6287c478bd9Sstevel@tonic-gate (void) printf("+%lx", (long)(tip->startfunc - start)); 6297c478bd9Sstevel@tonic-gate (void) printf(", exit value = 0x%.*lx\n", length, (long)tip->exitval); 6307c478bd9Sstevel@tonic-gate (void) printf("\t** zombie " 6317c478bd9Sstevel@tonic-gate "(exited, not detached, not yet joined) **\n"); 6327c478bd9Sstevel@tonic-gate } 6337c478bd9Sstevel@tonic-gate 6347c478bd9Sstevel@tonic-gate static void 6357c478bd9Sstevel@tonic-gate print_syscall(const lwpstatus_t *psp, prgregset_t reg) 6367c478bd9Sstevel@tonic-gate { 6377c478bd9Sstevel@tonic-gate char sname[32]; 6387c478bd9Sstevel@tonic-gate int length = (is64? 16 : 8); 6397c478bd9Sstevel@tonic-gate uint_t i; 6407c478bd9Sstevel@tonic-gate 6417c478bd9Sstevel@tonic-gate (void) proc_sysname(psp->pr_syscall, sname, sizeof (sname)); 6427c478bd9Sstevel@tonic-gate (void) printf(" %.*lx %-8s (", length, (long)reg[R_PC], sname); 6437c478bd9Sstevel@tonic-gate for (i = 0; i < psp->pr_nsysarg; i++) 6447c478bd9Sstevel@tonic-gate (void) printf((i+1 == psp->pr_nsysarg)? "%lx" : "%lx, ", 6457c478bd9Sstevel@tonic-gate (long)psp->pr_sysarg[i]); 6467c478bd9Sstevel@tonic-gate (void) printf(")\n"); 6477c478bd9Sstevel@tonic-gate } 6487c478bd9Sstevel@tonic-gate 6497c478bd9Sstevel@tonic-gate static void 6507c478bd9Sstevel@tonic-gate call_stack(pstack_handle_t *h, const lwpstatus_t *psp) 6517c478bd9Sstevel@tonic-gate { 6527c478bd9Sstevel@tonic-gate prgregset_t reg; 6537c478bd9Sstevel@tonic-gate 6547c478bd9Sstevel@tonic-gate (void) memcpy(reg, psp->pr_reg, sizeof (reg)); 6557c478bd9Sstevel@tonic-gate 6567c478bd9Sstevel@tonic-gate if ((psp->pr_flags & (PR_ASLEEP|PR_VFORKP)) || 6577c478bd9Sstevel@tonic-gate ((psp->pr_flags & PR_ISTOP) && 6587c478bd9Sstevel@tonic-gate (psp->pr_why == PR_SYSENTRY || 6597c478bd9Sstevel@tonic-gate psp->pr_why == PR_SYSEXIT))) { 6607c478bd9Sstevel@tonic-gate print_syscall(psp, reg); 6617c478bd9Sstevel@tonic-gate h->ignore_frame = 1; 6627c478bd9Sstevel@tonic-gate } else { 6637c478bd9Sstevel@tonic-gate h->ignore_frame = 0; 6647c478bd9Sstevel@tonic-gate } 6657c478bd9Sstevel@tonic-gate 6667c478bd9Sstevel@tonic-gate (void) Pstack_iter(h->proc, reg, print_frame, h); 6677c478bd9Sstevel@tonic-gate } 6687c478bd9Sstevel@tonic-gate 6697c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6707c478bd9Sstevel@tonic-gate static int 6717c478bd9Sstevel@tonic-gate jvm_object_iter(void *cd, const prmap_t *pmp, const char *obj) 6727c478bd9Sstevel@tonic-gate { 6737c478bd9Sstevel@tonic-gate char path[PATH_MAX]; 6747c478bd9Sstevel@tonic-gate char *name; 6757c478bd9Sstevel@tonic-gate char *s1, *s2; 6767c478bd9Sstevel@tonic-gate struct ps_prochandle *Pr = cd; 6777c478bd9Sstevel@tonic-gate 6787c478bd9Sstevel@tonic-gate if ((name = strstr(obj, "/libjvm.so")) == NULL) 6797c478bd9Sstevel@tonic-gate name = strstr(obj, "/libjvm_g.so"); 6807c478bd9Sstevel@tonic-gate 6817c478bd9Sstevel@tonic-gate if (name) { 6827c478bd9Sstevel@tonic-gate (void) strcpy(path, obj); 6837c478bd9Sstevel@tonic-gate if (Pstatus(Pr)->pr_dmodel != PR_MODEL_NATIVE) { 6847c478bd9Sstevel@tonic-gate s1 = name; 6857c478bd9Sstevel@tonic-gate s2 = path + (s1 - obj); 6867c478bd9Sstevel@tonic-gate (void) strcpy(s2, "/64"); 6877c478bd9Sstevel@tonic-gate s2 += 3; 6887c478bd9Sstevel@tonic-gate (void) strcpy(s2, s1); 6897c478bd9Sstevel@tonic-gate } 6907c478bd9Sstevel@tonic-gate 6917c478bd9Sstevel@tonic-gate s1 = strstr(obj, ".so"); 6927c478bd9Sstevel@tonic-gate s2 = strstr(path, ".so"); 6937c478bd9Sstevel@tonic-gate (void) strcpy(s2, "_db"); 6947c478bd9Sstevel@tonic-gate s2 += 3; 6957c478bd9Sstevel@tonic-gate (void) strcpy(s2, s1); 6967c478bd9Sstevel@tonic-gate 6977c478bd9Sstevel@tonic-gate if ((libjvm = dlopen(path, RTLD_LAZY|RTLD_GLOBAL)) != NULL) 6987c478bd9Sstevel@tonic-gate return (1); 6997c478bd9Sstevel@tonic-gate } 7007c478bd9Sstevel@tonic-gate 7017c478bd9Sstevel@tonic-gate return (0); 7027c478bd9Sstevel@tonic-gate } 7037c478bd9Sstevel@tonic-gate 7047c478bd9Sstevel@tonic-gate static jvm_agent_t * 7057c478bd9Sstevel@tonic-gate load_libjvm(struct ps_prochandle *Pr) 7067c478bd9Sstevel@tonic-gate { 7077c478bd9Sstevel@tonic-gate jvm_agent_t *ret; 7087c478bd9Sstevel@tonic-gate 709186f7fbfSEdward Pilatowicz /* 710186f7fbfSEdward Pilatowicz * Iterate through all the loaded objects in the target, looking 711186f7fbfSEdward Pilatowicz * for libjvm.so. If we find libjvm.so we'll try to load the 712186f7fbfSEdward Pilatowicz * corresponding libjvm_db.so that lives in the same directory. 713186f7fbfSEdward Pilatowicz * 714186f7fbfSEdward Pilatowicz * At first glance it seems like we'd want to use 715186f7fbfSEdward Pilatowicz * Pobject_iter_resolved() here since we'd want to make sure that 716186f7fbfSEdward Pilatowicz * we have the full path to the libjvm.so. But really, we don't 717186f7fbfSEdward Pilatowicz * want that since we're going to be dlopen()ing a library and 718186f7fbfSEdward Pilatowicz * executing code from that path, and therefore we don't want to 719186f7fbfSEdward Pilatowicz * load any library code that could be from a zone since it could 720186f7fbfSEdward Pilatowicz * have been replaced with a trojan. Hence, we use Pobject_iter(). 721186f7fbfSEdward Pilatowicz * So if we're debugging java processes in a zone from the global 722186f7fbfSEdward Pilatowicz * zone, and we want to get proper java stack stack frames, then 723186f7fbfSEdward Pilatowicz * the same jvm that is running within the zone needs to be 724186f7fbfSEdward Pilatowicz * installed in the global zone. 725186f7fbfSEdward Pilatowicz */ 7267c478bd9Sstevel@tonic-gate (void) Pobject_iter(Pr, jvm_object_iter, Pr); 7277c478bd9Sstevel@tonic-gate 7287c478bd9Sstevel@tonic-gate if (libjvm) { 7297c478bd9Sstevel@tonic-gate j_agent_create = (j_agent_create_f) 7307c478bd9Sstevel@tonic-gate dlsym(libjvm, "Jagent_create"); 7317c478bd9Sstevel@tonic-gate j_agent_destroy = (j_agent_destroy_f) 7327c478bd9Sstevel@tonic-gate dlsym(libjvm, "Jagent_destroy"); 7337c478bd9Sstevel@tonic-gate j_frame_iter = (j_frame_iter_f) 7347c478bd9Sstevel@tonic-gate dlsym(libjvm, "Jframe_iter"); 7357c478bd9Sstevel@tonic-gate 7367c478bd9Sstevel@tonic-gate if (j_agent_create == NULL || j_agent_destroy == NULL || 7377c478bd9Sstevel@tonic-gate j_frame_iter == NULL || 7387c478bd9Sstevel@tonic-gate (ret = j_agent_create(Pr, JVM_DB_VERSION)) == NULL) { 7397c478bd9Sstevel@tonic-gate reset_libjvm(NULL); 7407c478bd9Sstevel@tonic-gate return (NULL); 7417c478bd9Sstevel@tonic-gate } 7427c478bd9Sstevel@tonic-gate 7437c478bd9Sstevel@tonic-gate return (ret); 7447c478bd9Sstevel@tonic-gate } 7457c478bd9Sstevel@tonic-gate 7467c478bd9Sstevel@tonic-gate return (NULL); 7477c478bd9Sstevel@tonic-gate } 7487c478bd9Sstevel@tonic-gate 7497c478bd9Sstevel@tonic-gate static void 7507c478bd9Sstevel@tonic-gate reset_libjvm(jvm_agent_t *agent) 7517c478bd9Sstevel@tonic-gate { 7527c478bd9Sstevel@tonic-gate if (libjvm) { 7537c478bd9Sstevel@tonic-gate if (agent) 7547c478bd9Sstevel@tonic-gate j_agent_destroy(agent); 7557c478bd9Sstevel@tonic-gate 7567c478bd9Sstevel@tonic-gate (void) dlclose(libjvm); 7577c478bd9Sstevel@tonic-gate } 7587c478bd9Sstevel@tonic-gate 7597c478bd9Sstevel@tonic-gate j_agent_create = NULL; 7607c478bd9Sstevel@tonic-gate j_agent_destroy = NULL; 7617c478bd9Sstevel@tonic-gate j_frame_iter = NULL; 7627c478bd9Sstevel@tonic-gate libjvm = NULL; 7637c478bd9Sstevel@tonic-gate } 764*ea394cb0Sjohansen 765*ea394cb0Sjohansen /*ARGSUSED*/ 766*ea394cb0Sjohansen static int 767*ea394cb0Sjohansen python_object_iter(void *cd, const prmap_t *pmp, const char *obj) 768*ea394cb0Sjohansen { 769*ea394cb0Sjohansen char path[PATH_MAX]; 770*ea394cb0Sjohansen char *name; 771*ea394cb0Sjohansen char *s1, *s2; 772*ea394cb0Sjohansen struct ps_prochandle *Pr = cd; 773*ea394cb0Sjohansen 774*ea394cb0Sjohansen name = strstr(obj, "/libpython"); 775*ea394cb0Sjohansen 776*ea394cb0Sjohansen if (name) { 777*ea394cb0Sjohansen (void) strcpy(path, obj); 778*ea394cb0Sjohansen if (Pstatus(Pr)->pr_dmodel != PR_MODEL_NATIVE) { 779*ea394cb0Sjohansen s1 = name; 780*ea394cb0Sjohansen s2 = path + (s1 - obj); 781*ea394cb0Sjohansen (void) strcpy(s2, "/64"); 782*ea394cb0Sjohansen s2 += 3; 783*ea394cb0Sjohansen (void) strcpy(s2, s1); 784*ea394cb0Sjohansen } 785*ea394cb0Sjohansen 786*ea394cb0Sjohansen s1 = strstr(obj, ".so"); 787*ea394cb0Sjohansen s2 = strstr(path, ".so"); 788*ea394cb0Sjohansen (void) strcpy(s2, "_db"); 789*ea394cb0Sjohansen s2 += 3; 790*ea394cb0Sjohansen (void) strcpy(s2, s1); 791*ea394cb0Sjohansen 792*ea394cb0Sjohansen if ((libpython = dlopen(path, RTLD_LAZY|RTLD_GLOBAL)) != NULL) 793*ea394cb0Sjohansen return (1); 794*ea394cb0Sjohansen } 795*ea394cb0Sjohansen 796*ea394cb0Sjohansen return (0); 797*ea394cb0Sjohansen } 798*ea394cb0Sjohansen 799*ea394cb0Sjohansen static pydb_agent_t * 800*ea394cb0Sjohansen load_libpython(struct ps_prochandle *Pr) 801*ea394cb0Sjohansen { 802*ea394cb0Sjohansen pydb_agent_t *pdb; 803*ea394cb0Sjohansen 804*ea394cb0Sjohansen (void) Pobject_iter(Pr, python_object_iter, Pr); 805*ea394cb0Sjohansen 806*ea394cb0Sjohansen if (libpython) { 807*ea394cb0Sjohansen pydb_agent_create = (pydb_agent_create_f) 808*ea394cb0Sjohansen dlsym(libpython, "pydb_agent_create"); 809*ea394cb0Sjohansen pydb_agent_destroy = (pydb_agent_destroy_f) 810*ea394cb0Sjohansen dlsym(libpython, "pydb_agent_destroy"); 811*ea394cb0Sjohansen pydb_pc_frameinfo = (pydb_pc_frameinfo_f) 812*ea394cb0Sjohansen dlsym(libpython, "pydb_pc_frameinfo"); 813*ea394cb0Sjohansen 814*ea394cb0Sjohansen if (pydb_agent_create == NULL || pydb_agent_destroy == NULL || 815*ea394cb0Sjohansen pydb_pc_frameinfo == NULL) { 816*ea394cb0Sjohansen (void) dlclose(libpython); 817*ea394cb0Sjohansen libpython = NULL; 818*ea394cb0Sjohansen return (NULL); 819*ea394cb0Sjohansen } 820*ea394cb0Sjohansen 821*ea394cb0Sjohansen pdb = pydb_agent_create(Pr, PYDB_VERSION); 822*ea394cb0Sjohansen if (pdb == NULL) { 823*ea394cb0Sjohansen (void) dlclose(libpython); 824*ea394cb0Sjohansen libpython = NULL; 825*ea394cb0Sjohansen return (NULL); 826*ea394cb0Sjohansen } 827*ea394cb0Sjohansen return (pdb); 828*ea394cb0Sjohansen } 829*ea394cb0Sjohansen 830*ea394cb0Sjohansen return (NULL); 831*ea394cb0Sjohansen } 832*ea394cb0Sjohansen 833*ea394cb0Sjohansen static void 834*ea394cb0Sjohansen reset_libpython(pydb_agent_t *pdb) 835*ea394cb0Sjohansen { 836*ea394cb0Sjohansen if (libpython != NULL) { 837*ea394cb0Sjohansen if (pdb != NULL) { 838*ea394cb0Sjohansen pydb_agent_destroy(pdb); 839*ea394cb0Sjohansen } 840*ea394cb0Sjohansen (void) dlclose(libpython); 841*ea394cb0Sjohansen } 842*ea394cb0Sjohansen 843*ea394cb0Sjohansen libpython = NULL; 844*ea394cb0Sjohansen pydb_agent_create = NULL; 845*ea394cb0Sjohansen pydb_agent_destroy = NULL; 846*ea394cb0Sjohansen pydb_pc_frameinfo = NULL; 847*ea394cb0Sjohansen } 848