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 /* 22ea394cb0Sjohansen * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 24*ab618543SJohn Levon * 25*ab618543SJohn Levon * Copyright 2018 Joyent, Inc. 267c478bd9Sstevel@tonic-gate */ 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h> 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #include <stdio.h> 31004388ebScasper #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 105ea394cb0Sjohansen /* 106ea394cb0Sjohansen * Similar to what's done for debugging java programs, here are prototypes for 107ea394cb0Sjohansen * the library that allows us to debug Python programs. 108ea394cb0Sjohansen */ 109ea394cb0Sjohansen #define PYDB_VERSION 1 110ea394cb0Sjohansen static void *libpython; 111ea394cb0Sjohansen 112ea394cb0Sjohansen typedef struct pydb_agent pydb_agent_t; 113ea394cb0Sjohansen 114ea394cb0Sjohansen typedef pydb_agent_t *(*pydb_agent_create_f)(struct ps_prochandle *P, int vers); 115ea394cb0Sjohansen typedef void (*pydb_agent_destroy_f)(pydb_agent_t *py); 116ea394cb0Sjohansen typedef int (*pydb_pc_frameinfo_f)(pydb_agent_t *py, uintptr_t pc, 117ea394cb0Sjohansen uintptr_t frame_addr, char *fbuf, size_t bufsz); 118ea394cb0Sjohansen 119ea394cb0Sjohansen static pydb_agent_create_f pydb_agent_create; 120ea394cb0Sjohansen static pydb_agent_destroy_f pydb_agent_destroy; 121ea394cb0Sjohansen static pydb_pc_frameinfo_f pydb_pc_frameinfo; 122ea394cb0Sjohansen 123ea394cb0Sjohansen static pydb_agent_t *load_libpython(struct ps_prochandle *P); 124ea394cb0Sjohansen static void reset_libpython(pydb_agent_t *); 1257c478bd9Sstevel@tonic-gate /* 1267c478bd9Sstevel@tonic-gate * Since we must maintain both a proc handle and a jvm handle, this structure 1277c478bd9Sstevel@tonic-gate * is the basic type that gets passed around. 1287c478bd9Sstevel@tonic-gate */ 1297c478bd9Sstevel@tonic-gate typedef struct pstack_handle { 1307c478bd9Sstevel@tonic-gate struct ps_prochandle *proc; 1317c478bd9Sstevel@tonic-gate jvm_agent_t *jvm; 1327c478bd9Sstevel@tonic-gate int ignore_frame; 1337c478bd9Sstevel@tonic-gate const char *lwps; 1347c478bd9Sstevel@tonic-gate int count; 135ea394cb0Sjohansen pydb_agent_t *pydb; 1367c478bd9Sstevel@tonic-gate } pstack_handle_t; 1377c478bd9Sstevel@tonic-gate 1387c478bd9Sstevel@tonic-gate static int thr_stack(const td_thrhandle_t *, void *); 1397c478bd9Sstevel@tonic-gate static void free_threadinfo(void); 1407c478bd9Sstevel@tonic-gate static struct threadinfo *find_thread(id_t); 1417c478bd9Sstevel@tonic-gate static int all_call_stacks(pstack_handle_t *, int); 142*ab618543SJohn Levon static void tlhead(id_t, id_t, const char *); 1437c478bd9Sstevel@tonic-gate static int print_frame(void *, prgregset_t, uint_t, const long *); 1447c478bd9Sstevel@tonic-gate static void print_zombie(struct ps_prochandle *, struct threadinfo *); 1457c478bd9Sstevel@tonic-gate static void print_syscall(const lwpstatus_t *, prgregset_t); 1467c478bd9Sstevel@tonic-gate static void call_stack(pstack_handle_t *, const lwpstatus_t *); 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate /* 1497c478bd9Sstevel@tonic-gate * The number of active and zombie threads. 1507c478bd9Sstevel@tonic-gate */ 1517c478bd9Sstevel@tonic-gate static int nthreads; 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate int 1547c478bd9Sstevel@tonic-gate main(int argc, char **argv) 1557c478bd9Sstevel@tonic-gate { 1567c478bd9Sstevel@tonic-gate int retc = 0; 1577c478bd9Sstevel@tonic-gate int opt; 1587c478bd9Sstevel@tonic-gate int errflg = FALSE; 1597c478bd9Sstevel@tonic-gate core_content_t content = CC_CONTENT_DATA | CC_CONTENT_ANON | 1607c478bd9Sstevel@tonic-gate CC_CONTENT_STACK; 1617c478bd9Sstevel@tonic-gate struct rlimit rlim; 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate if ((command = strrchr(argv[0], '/')) != NULL) 1647c478bd9Sstevel@tonic-gate command++; 1657c478bd9Sstevel@tonic-gate else 1667c478bd9Sstevel@tonic-gate command = argv[0]; 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate /* options */ 1697c478bd9Sstevel@tonic-gate while ((opt = getopt(argc, argv, "F")) != EOF) { 1707c478bd9Sstevel@tonic-gate switch (opt) { 1717c478bd9Sstevel@tonic-gate case 'F': 1727c478bd9Sstevel@tonic-gate /* 1737c478bd9Sstevel@tonic-gate * If the user specifies the force option, we'll 1747c478bd9Sstevel@tonic-gate * consent to printing out other threads' stacks 1757c478bd9Sstevel@tonic-gate * even if the main stack is absent. 1767c478bd9Sstevel@tonic-gate */ 1777c478bd9Sstevel@tonic-gate content &= ~CC_CONTENT_STACK; 1787c478bd9Sstevel@tonic-gate Fflag = PGRAB_FORCE; 1797c478bd9Sstevel@tonic-gate break; 1807c478bd9Sstevel@tonic-gate default: 1817c478bd9Sstevel@tonic-gate errflg = TRUE; 1827c478bd9Sstevel@tonic-gate break; 1837c478bd9Sstevel@tonic-gate } 1847c478bd9Sstevel@tonic-gate } 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate argc -= optind; 1877c478bd9Sstevel@tonic-gate argv += optind; 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate if (errflg || argc <= 0) { 1907c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1917c478bd9Sstevel@tonic-gate "usage:\t%s [-F] { pid | core }[/lwps] ...\n", command); 1927c478bd9Sstevel@tonic-gate (void) fprintf(stderr, " (show process call stack)\n"); 1937c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 194186f7fbfSEdward Pilatowicz " -F: force grabbing of the target process\n"); 1957c478bd9Sstevel@tonic-gate exit(2); 1967c478bd9Sstevel@tonic-gate } 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate /* 1997c478bd9Sstevel@tonic-gate * Make sure we'll have enough file descriptors to handle a target 2007c478bd9Sstevel@tonic-gate * that has many many mappings. 2017c478bd9Sstevel@tonic-gate */ 2027c478bd9Sstevel@tonic-gate if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) { 2037c478bd9Sstevel@tonic-gate rlim.rlim_cur = rlim.rlim_max; 2047c478bd9Sstevel@tonic-gate (void) setrlimit(RLIMIT_NOFILE, &rlim); 205004388ebScasper (void) enable_extended_FILE_stdio(-1, -1); 2067c478bd9Sstevel@tonic-gate } 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate (void) proc_initstdio(); 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate while (--argc >= 0) { 2117c478bd9Sstevel@tonic-gate int gcode; 2127c478bd9Sstevel@tonic-gate psinfo_t psinfo; 2137c478bd9Sstevel@tonic-gate const psinfo_t *tpsinfo; 2147c478bd9Sstevel@tonic-gate struct ps_prochandle *Pr = NULL; 2157c478bd9Sstevel@tonic-gate td_thragent_t *Tap; 2167c478bd9Sstevel@tonic-gate int threaded; 2177c478bd9Sstevel@tonic-gate pstack_handle_t handle; 2187c478bd9Sstevel@tonic-gate const char *lwps, *arg; 2197c478bd9Sstevel@tonic-gate 2207c478bd9Sstevel@tonic-gate (void) proc_flushstdio(); 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate arg = *argv++; 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate if ((Pr = proc_arg_xgrab(arg, NULL, PR_ARG_ANY, 2257c478bd9Sstevel@tonic-gate Fflag, &gcode, &lwps)) == NULL) { 2267c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: cannot examine %s: %s\n", 2277c478bd9Sstevel@tonic-gate command, arg, Pgrab_error(gcode)); 2287c478bd9Sstevel@tonic-gate retc++; 2297c478bd9Sstevel@tonic-gate continue; 2307c478bd9Sstevel@tonic-gate } 2317c478bd9Sstevel@tonic-gate 2327c478bd9Sstevel@tonic-gate if ((tpsinfo = Ppsinfo(Pr)) == NULL) { 2337c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: cannot examine %s: " 2347c478bd9Sstevel@tonic-gate "lost control of process\n", command, arg); 2357c478bd9Sstevel@tonic-gate Prelease(Pr, 0); 2367c478bd9Sstevel@tonic-gate retc++; 2377c478bd9Sstevel@tonic-gate continue; 2387c478bd9Sstevel@tonic-gate } 2397c478bd9Sstevel@tonic-gate (void) memcpy(&psinfo, tpsinfo, sizeof (psinfo_t)); 2407c478bd9Sstevel@tonic-gate proc_unctrl_psinfo(&psinfo); 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate if (Pstate(Pr) == PS_DEAD) { 2437c478bd9Sstevel@tonic-gate if ((Pcontent(Pr) & content) != content) { 2447c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: core '%s' has " 2457c478bd9Sstevel@tonic-gate "insufficient content\n", command, arg); 2467c478bd9Sstevel@tonic-gate retc++; 2477c478bd9Sstevel@tonic-gate continue; 2487c478bd9Sstevel@tonic-gate } 2497c478bd9Sstevel@tonic-gate (void) printf("core '%s' of %d:\t%.70s\n", 2507c478bd9Sstevel@tonic-gate arg, (int)psinfo.pr_pid, psinfo.pr_psargs); 2517c478bd9Sstevel@tonic-gate } else { 2527c478bd9Sstevel@tonic-gate (void) printf("%d:\t%.70s\n", 2537c478bd9Sstevel@tonic-gate (int)psinfo.pr_pid, psinfo.pr_psargs); 2547c478bd9Sstevel@tonic-gate } 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate is64 = (psinfo.pr_dmodel == PR_MODEL_LP64); 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate if (Pgetauxval(Pr, AT_BASE) != -1L && Prd_agent(Pr) == NULL) { 2597c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: warning: librtld_db failed " 2607c478bd9Sstevel@tonic-gate "to initialize; symbols from shared libraries will " 2617c478bd9Sstevel@tonic-gate "not be available\n", command); 2627c478bd9Sstevel@tonic-gate } 2637c478bd9Sstevel@tonic-gate 2647c478bd9Sstevel@tonic-gate /* 2657c478bd9Sstevel@tonic-gate * First we need to get a thread agent handle. 2667c478bd9Sstevel@tonic-gate */ 2677c478bd9Sstevel@tonic-gate if (td_init() != TD_OK || 2687c478bd9Sstevel@tonic-gate td_ta_new(Pr, &Tap) != TD_OK) /* no libc */ 2697c478bd9Sstevel@tonic-gate threaded = FALSE; 2707c478bd9Sstevel@tonic-gate else { 2717c478bd9Sstevel@tonic-gate /* 2727c478bd9Sstevel@tonic-gate * Iterate over all threads, calling: 2737c478bd9Sstevel@tonic-gate * thr_stack(td_thrhandle_t *Thp, NULL); 2747c478bd9Sstevel@tonic-gate * for each one to generate the list of threads. 2757c478bd9Sstevel@tonic-gate */ 2767c478bd9Sstevel@tonic-gate nthreads = 0; 2777c478bd9Sstevel@tonic-gate (void) td_ta_thr_iter(Tap, thr_stack, NULL, 2787c478bd9Sstevel@tonic-gate TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY, 2797c478bd9Sstevel@tonic-gate TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS); 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate (void) td_ta_delete(Tap); 2827c478bd9Sstevel@tonic-gate threaded = TRUE; 2837c478bd9Sstevel@tonic-gate } 2847c478bd9Sstevel@tonic-gate 2857c478bd9Sstevel@tonic-gate handle.proc = Pr; 2867c478bd9Sstevel@tonic-gate handle.jvm = load_libjvm(Pr); 287ea394cb0Sjohansen handle.pydb = load_libpython(Pr); 2887c478bd9Sstevel@tonic-gate handle.lwps = lwps; 2897c478bd9Sstevel@tonic-gate handle.count = 0; 2907c478bd9Sstevel@tonic-gate 2917c478bd9Sstevel@tonic-gate if (all_call_stacks(&handle, threaded) != 0) 2927c478bd9Sstevel@tonic-gate retc++; 2937c478bd9Sstevel@tonic-gate if (threaded) 2947c478bd9Sstevel@tonic-gate free_threadinfo(); 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate reset_libjvm(handle.jvm); 297ea394cb0Sjohansen reset_libpython(handle.pydb); 2987c478bd9Sstevel@tonic-gate Prelease(Pr, 0); 2997c478bd9Sstevel@tonic-gate 3007c478bd9Sstevel@tonic-gate if (handle.count == 0) 3017c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: no matching LWPs found\n", 3027c478bd9Sstevel@tonic-gate command); 3037c478bd9Sstevel@tonic-gate } 3047c478bd9Sstevel@tonic-gate 3057c478bd9Sstevel@tonic-gate (void) proc_finistdio(); 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate return (retc); 3087c478bd9Sstevel@tonic-gate } 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate /* 3117c478bd9Sstevel@tonic-gate * Thread iteration call-back function. 3127c478bd9Sstevel@tonic-gate * Called once for each user-level thread. 3137c478bd9Sstevel@tonic-gate * Used to build the list of all threads. 3147c478bd9Sstevel@tonic-gate */ 3157c478bd9Sstevel@tonic-gate /* ARGSUSED1 */ 3167c478bd9Sstevel@tonic-gate static int 3177c478bd9Sstevel@tonic-gate thr_stack(const td_thrhandle_t *Thp, void *cd) 3187c478bd9Sstevel@tonic-gate { 3197c478bd9Sstevel@tonic-gate td_thrinfo_t thrinfo; 3207c478bd9Sstevel@tonic-gate struct threadinfo *tip; 3217c478bd9Sstevel@tonic-gate td_err_e error; 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate if (td_thr_get_info(Thp, &thrinfo) != TD_OK) 3247c478bd9Sstevel@tonic-gate return (0); 3257c478bd9Sstevel@tonic-gate 3267c478bd9Sstevel@tonic-gate tip = malloc(sizeof (struct threadinfo)); 3277c478bd9Sstevel@tonic-gate tip->next = NULL; 3287c478bd9Sstevel@tonic-gate tip->threadid = thrinfo.ti_tid; 3297c478bd9Sstevel@tonic-gate tip->lwpid = thrinfo.ti_lid; 3307c478bd9Sstevel@tonic-gate tip->state = thrinfo.ti_state; 3317c478bd9Sstevel@tonic-gate tip->startfunc = thrinfo.ti_startfunc; 3327c478bd9Sstevel@tonic-gate tip->exitval = (uintptr_t)thrinfo.ti_exitval; 3337c478bd9Sstevel@tonic-gate nthreads++; 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate if (thrinfo.ti_state == TD_THR_ZOMBIE || 3367c478bd9Sstevel@tonic-gate ((error = td_thr_getgregs(Thp, tip->regs)) != TD_OK && 3377c478bd9Sstevel@tonic-gate error != TD_PARTIALREG)) 3387c478bd9Sstevel@tonic-gate (void) memset(tip->regs, 0, sizeof (prgregset_t)); 3397c478bd9Sstevel@tonic-gate 3407c478bd9Sstevel@tonic-gate if (thr_tail) 3417c478bd9Sstevel@tonic-gate thr_tail->next = tip; 3427c478bd9Sstevel@tonic-gate else 3437c478bd9Sstevel@tonic-gate thr_head = tip; 3447c478bd9Sstevel@tonic-gate thr_tail = tip; 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate return (0); 3477c478bd9Sstevel@tonic-gate } 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate static void 3507c478bd9Sstevel@tonic-gate free_threadinfo() 3517c478bd9Sstevel@tonic-gate { 3527c478bd9Sstevel@tonic-gate struct threadinfo *tip = thr_head; 3537c478bd9Sstevel@tonic-gate struct threadinfo *next; 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate while (tip) { 3567c478bd9Sstevel@tonic-gate next = tip->next; 3577c478bd9Sstevel@tonic-gate free(tip); 3587c478bd9Sstevel@tonic-gate tip = next; 3597c478bd9Sstevel@tonic-gate } 3607c478bd9Sstevel@tonic-gate 3617c478bd9Sstevel@tonic-gate thr_head = thr_tail = NULL; 3627c478bd9Sstevel@tonic-gate } 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate /* 3657c478bd9Sstevel@tonic-gate * Find and eliminate the thread corresponding to the given lwpid. 3667c478bd9Sstevel@tonic-gate */ 3677c478bd9Sstevel@tonic-gate static struct threadinfo * 3687c478bd9Sstevel@tonic-gate find_thread(id_t lwpid) 3697c478bd9Sstevel@tonic-gate { 3707c478bd9Sstevel@tonic-gate struct threadinfo *tip; 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate for (tip = thr_head; tip; tip = tip->next) { 3737c478bd9Sstevel@tonic-gate if (lwpid == tip->lwpid) { 3747c478bd9Sstevel@tonic-gate tip->lwpid = 0; 3757c478bd9Sstevel@tonic-gate return (tip); 3767c478bd9Sstevel@tonic-gate } 3777c478bd9Sstevel@tonic-gate } 3787c478bd9Sstevel@tonic-gate return (NULL); 3797c478bd9Sstevel@tonic-gate } 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate static int 3827c478bd9Sstevel@tonic-gate thread_call_stack(void *data, const lwpstatus_t *psp, 3837c478bd9Sstevel@tonic-gate const lwpsinfo_t *pip) 3847c478bd9Sstevel@tonic-gate { 385*ab618543SJohn Levon char lwpname[THREAD_NAME_MAX] = ""; 3867c478bd9Sstevel@tonic-gate pstack_handle_t *h = data; 3877c478bd9Sstevel@tonic-gate lwpstatus_t lwpstatus; 3887c478bd9Sstevel@tonic-gate struct threadinfo *tip; 3897c478bd9Sstevel@tonic-gate 3907c478bd9Sstevel@tonic-gate if (!proc_lwp_in_set(h->lwps, pip->pr_lwpid)) 3917c478bd9Sstevel@tonic-gate return (0); 3927c478bd9Sstevel@tonic-gate h->count++; 3937c478bd9Sstevel@tonic-gate 3947c478bd9Sstevel@tonic-gate if ((tip = find_thread(pip->pr_lwpid)) == NULL) 3957c478bd9Sstevel@tonic-gate return (0); 3967c478bd9Sstevel@tonic-gate 397*ab618543SJohn Levon (void) Plwp_getname(h->proc, pip->pr_lwpid, 398*ab618543SJohn Levon lwpname, sizeof (lwpname)); 399*ab618543SJohn Levon 400*ab618543SJohn Levon tlhead(tip->threadid, pip->pr_lwpid, lwpname); 4017c478bd9Sstevel@tonic-gate tip->threadid = 0; /* finish eliminating tid */ 4027c478bd9Sstevel@tonic-gate if (psp) 4037c478bd9Sstevel@tonic-gate call_stack(h, psp); 4047c478bd9Sstevel@tonic-gate else { 4057c478bd9Sstevel@tonic-gate if (tip->state == TD_THR_ZOMBIE) 4067c478bd9Sstevel@tonic-gate print_zombie(h->proc, tip); 4077c478bd9Sstevel@tonic-gate else { 4087c478bd9Sstevel@tonic-gate (void) memset(&lwpstatus, 0, sizeof (lwpstatus)); 4097c478bd9Sstevel@tonic-gate (void) memcpy(lwpstatus.pr_reg, tip->regs, 410186f7fbfSEdward Pilatowicz sizeof (prgregset_t)); 4117c478bd9Sstevel@tonic-gate call_stack(h, &lwpstatus); 4127c478bd9Sstevel@tonic-gate } 4137c478bd9Sstevel@tonic-gate } 4147c478bd9Sstevel@tonic-gate return (0); 4157c478bd9Sstevel@tonic-gate } 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate static int 4187c478bd9Sstevel@tonic-gate lwp_call_stack(void *data, 419*ab618543SJohn Levon const lwpstatus_t *psp, const lwpsinfo_t *pip) 4207c478bd9Sstevel@tonic-gate { 421*ab618543SJohn Levon char lwpname[THREAD_NAME_MAX] = ""; 4227c478bd9Sstevel@tonic-gate pstack_handle_t *h = data; 4237c478bd9Sstevel@tonic-gate 4247c478bd9Sstevel@tonic-gate if (!proc_lwp_in_set(h->lwps, pip->pr_lwpid)) 4257c478bd9Sstevel@tonic-gate return (0); 4267c478bd9Sstevel@tonic-gate h->count++; 4277c478bd9Sstevel@tonic-gate 428*ab618543SJohn Levon (void) Plwp_getname(h->proc, pip->pr_lwpid, 429*ab618543SJohn Levon lwpname, sizeof (lwpname)); 430*ab618543SJohn Levon 431*ab618543SJohn Levon tlhead(0, pip->pr_lwpid, lwpname); 4327c478bd9Sstevel@tonic-gate if (psp) 4337c478bd9Sstevel@tonic-gate call_stack(h, psp); 4347c478bd9Sstevel@tonic-gate else 4357c478bd9Sstevel@tonic-gate (void) printf("\t** zombie " 436186f7fbfSEdward Pilatowicz "(exited, not detached, not yet joined) **\n"); 4377c478bd9Sstevel@tonic-gate return (0); 4387c478bd9Sstevel@tonic-gate } 4397c478bd9Sstevel@tonic-gate 4407c478bd9Sstevel@tonic-gate static int 4417c478bd9Sstevel@tonic-gate all_call_stacks(pstack_handle_t *h, int dothreads) 4427c478bd9Sstevel@tonic-gate { 4437c478bd9Sstevel@tonic-gate struct ps_prochandle *Pr = h->proc; 4447c478bd9Sstevel@tonic-gate pstatus_t status = *Pstatus(Pr); 4457c478bd9Sstevel@tonic-gate 4467c478bd9Sstevel@tonic-gate (void) memset(&sigh, 0, sizeof (GElf_Sym)); 4477c478bd9Sstevel@tonic-gate (void) Plookup_by_name(Pr, "libc.so", "sigacthandler", &sigh); 4487c478bd9Sstevel@tonic-gate 4497c478bd9Sstevel@tonic-gate if ((status.pr_nlwp + status.pr_nzomb) <= 1 && 4507c478bd9Sstevel@tonic-gate !(dothreads && nthreads > 1)) { 4517c478bd9Sstevel@tonic-gate if (proc_lwp_in_set(h->lwps, status.pr_lwp.pr_lwpid)) { 4527c478bd9Sstevel@tonic-gate call_stack(h, &status.pr_lwp); 4537c478bd9Sstevel@tonic-gate h->count++; 4547c478bd9Sstevel@tonic-gate } 4557c478bd9Sstevel@tonic-gate } else { 4567c478bd9Sstevel@tonic-gate lwpstatus_t lwpstatus; 4577c478bd9Sstevel@tonic-gate struct threadinfo *tip; 4587c478bd9Sstevel@tonic-gate id_t tid; 4597c478bd9Sstevel@tonic-gate 4607c478bd9Sstevel@tonic-gate if (dothreads) 4617c478bd9Sstevel@tonic-gate (void) Plwp_iter_all(Pr, thread_call_stack, h); 4627c478bd9Sstevel@tonic-gate else 4637c478bd9Sstevel@tonic-gate (void) Plwp_iter_all(Pr, lwp_call_stack, h); 4647c478bd9Sstevel@tonic-gate 4657c478bd9Sstevel@tonic-gate /* for each remaining thread w/o an lwp */ 4667c478bd9Sstevel@tonic-gate (void) memset(&lwpstatus, 0, sizeof (lwpstatus)); 4677c478bd9Sstevel@tonic-gate for (tip = thr_head; tip; tip = tip->next) { 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate if (!proc_lwp_in_set(h->lwps, tip->lwpid)) 4707c478bd9Sstevel@tonic-gate tip->threadid = 0; 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate if ((tid = tip->threadid) != 0) { 4737c478bd9Sstevel@tonic-gate (void) memcpy(lwpstatus.pr_reg, tip->regs, 474186f7fbfSEdward Pilatowicz sizeof (prgregset_t)); 475*ab618543SJohn Levon tlhead(tid, tip->lwpid, NULL); 4767c478bd9Sstevel@tonic-gate if (tip->state == TD_THR_ZOMBIE) 4777c478bd9Sstevel@tonic-gate print_zombie(Pr, tip); 4787c478bd9Sstevel@tonic-gate else 4797c478bd9Sstevel@tonic-gate call_stack(h, &lwpstatus); 4807c478bd9Sstevel@tonic-gate } 4817c478bd9Sstevel@tonic-gate tip->threadid = 0; 4827c478bd9Sstevel@tonic-gate tip->lwpid = 0; 4837c478bd9Sstevel@tonic-gate } 4847c478bd9Sstevel@tonic-gate } 4857c478bd9Sstevel@tonic-gate return (0); 4867c478bd9Sstevel@tonic-gate } 4877c478bd9Sstevel@tonic-gate 488*ab618543SJohn Levon /* The width of the header */ 489*ab618543SJohn Levon #define HEAD_WIDTH (62) 4907c478bd9Sstevel@tonic-gate static void 491*ab618543SJohn Levon tlhead(id_t threadid, id_t lwpid, const char *name) 4927c478bd9Sstevel@tonic-gate { 493*ab618543SJohn Levon char buf[128] = { 0 }; 494*ab618543SJohn Levon char num[16]; 495*ab618543SJohn Levon ssize_t amt = 0; 496*ab618543SJohn Levon int i; 497*ab618543SJohn Levon 4987c478bd9Sstevel@tonic-gate if (threadid == 0 && lwpid == 0) 4997c478bd9Sstevel@tonic-gate return; 5007c478bd9Sstevel@tonic-gate 501*ab618543SJohn Levon if (lwpid > 0) { 502*ab618543SJohn Levon (void) snprintf(num, sizeof (num), "%d", (int)lwpid); 503*ab618543SJohn Levon (void) strlcat(buf, "thread# ", sizeof (buf)); 504*ab618543SJohn Levon (void) strlcat(buf, num, sizeof (buf)); 505*ab618543SJohn Levon } 506*ab618543SJohn Levon 507*ab618543SJohn Levon if (threadid > 0) { 508*ab618543SJohn Levon (void) snprintf(num, sizeof (num), "%d", (int)threadid); 509*ab618543SJohn Levon if (lwpid > 0) 510*ab618543SJohn Levon (void) strlcat(buf, " / ", sizeof (buf)); 511*ab618543SJohn Levon (void) strlcat(buf, "lwp# ", sizeof (buf)); 512*ab618543SJohn Levon (void) strlcat(buf, num, sizeof (buf)); 513*ab618543SJohn Levon } 514*ab618543SJohn Levon 515*ab618543SJohn Levon if (name != NULL && strlen(name) > 0) { 516*ab618543SJohn Levon (void) strlcat(buf, " [", sizeof (buf)); 517*ab618543SJohn Levon (void) strlcat(buf, name, sizeof (buf)); 518*ab618543SJohn Levon (void) strlcat(buf, "]", sizeof (buf)); 519*ab618543SJohn Levon } 5207c478bd9Sstevel@tonic-gate 521*ab618543SJohn Levon amt = (HEAD_WIDTH - strlen(buf) - 2); 522*ab618543SJohn Levon if (amt < 4) 523*ab618543SJohn Levon amt = 4; 5247c478bd9Sstevel@tonic-gate 525*ab618543SJohn Levon for (i = 0; i < amt / 2; i++) 526*ab618543SJohn Levon (void) putc('-', stdout); 527*ab618543SJohn Levon (void) printf(" %s ", buf); 528*ab618543SJohn Levon for (i = 0; i < (amt / 2) + (amt % 2); i++) 529*ab618543SJohn Levon (void) putc('-', stdout); 530*ab618543SJohn Levon (void) putc('\n', stdout); 5317c478bd9Sstevel@tonic-gate } 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5347c478bd9Sstevel@tonic-gate static int 5357c478bd9Sstevel@tonic-gate print_java_frame(void *cld, prgregset_t gregs, const char *name, int bci, 5367c478bd9Sstevel@tonic-gate int line, void *handle) 5377c478bd9Sstevel@tonic-gate { 5387c478bd9Sstevel@tonic-gate int length = (is64 ? 16 : 8); 5397c478bd9Sstevel@tonic-gate 5407c478bd9Sstevel@tonic-gate (void) printf(" %.*lx * %s", length, (long)gregs[R_PC], name); 5417c478bd9Sstevel@tonic-gate 5427c478bd9Sstevel@tonic-gate if (bci != -1) { 5437c478bd9Sstevel@tonic-gate (void) printf("+%d", bci); 5447c478bd9Sstevel@tonic-gate if (line) 5457c478bd9Sstevel@tonic-gate (void) printf(" (line %d)", line); 5467c478bd9Sstevel@tonic-gate } 5477c478bd9Sstevel@tonic-gate (void) printf("\n"); 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate return (0); 5507c478bd9Sstevel@tonic-gate } 5517c478bd9Sstevel@tonic-gate 5527c478bd9Sstevel@tonic-gate static sigjmp_buf jumpbuf; 5537c478bd9Sstevel@tonic-gate 5547c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5557c478bd9Sstevel@tonic-gate static void 5567c478bd9Sstevel@tonic-gate fatal_signal(int signo) 5577c478bd9Sstevel@tonic-gate { 5587c478bd9Sstevel@tonic-gate siglongjmp(jumpbuf, 1); 5597c478bd9Sstevel@tonic-gate } 5607c478bd9Sstevel@tonic-gate 5617c478bd9Sstevel@tonic-gate static int 5627c478bd9Sstevel@tonic-gate print_frame(void *cd, prgregset_t gregs, uint_t argc, const long *argv) 5637c478bd9Sstevel@tonic-gate { 5647c478bd9Sstevel@tonic-gate pstack_handle_t *h = cd; 5657c478bd9Sstevel@tonic-gate struct ps_prochandle *Pr = h->proc; 5667c478bd9Sstevel@tonic-gate uintptr_t pc = gregs[R_PC]; 5677c478bd9Sstevel@tonic-gate char buff[255]; 5687c478bd9Sstevel@tonic-gate GElf_Sym sym; 5697c478bd9Sstevel@tonic-gate uintptr_t start; 5707c478bd9Sstevel@tonic-gate int length = (is64? 16 : 8); 5717c478bd9Sstevel@tonic-gate int i; 5727c478bd9Sstevel@tonic-gate 5737c478bd9Sstevel@tonic-gate /* 5747c478bd9Sstevel@tonic-gate * If we are in a system call, we display the entry frame in a more 5757c478bd9Sstevel@tonic-gate * readable manner, using the name of the system call. In this case, we 5767c478bd9Sstevel@tonic-gate * want to ignore this first frame, since we already displayed it 5777c478bd9Sstevel@tonic-gate * separately. 5787c478bd9Sstevel@tonic-gate */ 5797c478bd9Sstevel@tonic-gate if (h->ignore_frame) { 5807c478bd9Sstevel@tonic-gate h->ignore_frame = 0; 5817c478bd9Sstevel@tonic-gate return (0); 5827c478bd9Sstevel@tonic-gate } 5837c478bd9Sstevel@tonic-gate 5847c478bd9Sstevel@tonic-gate (void) sprintf(buff, "%.*lx", length, (long)pc); 5857c478bd9Sstevel@tonic-gate (void) strcpy(buff + length, " ????????"); 5867c478bd9Sstevel@tonic-gate if (Plookup_by_addr(Pr, pc, 5877c478bd9Sstevel@tonic-gate buff + 1 + length, sizeof (buff) - 1 - length, &sym) == 0) { 5887c478bd9Sstevel@tonic-gate start = sym.st_value; 5897c478bd9Sstevel@tonic-gate } else if (h->jvm != NULL) { 5907c478bd9Sstevel@tonic-gate int ret; 5917c478bd9Sstevel@tonic-gate void (*segv)(int), (*bus)(int), (*ill)(int); 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate segv = signal(SIGSEGV, fatal_signal); 5947c478bd9Sstevel@tonic-gate bus = signal(SIGBUS, fatal_signal); 5957c478bd9Sstevel@tonic-gate ill = signal(SIGILL, fatal_signal); 5967c478bd9Sstevel@tonic-gate 5977c478bd9Sstevel@tonic-gate /* Insure against a bad libjvm_db */ 5987c478bd9Sstevel@tonic-gate if (sigsetjmp(jumpbuf, 0) == 0) 5997c478bd9Sstevel@tonic-gate ret = j_frame_iter(h->jvm, gregs, print_java_frame, 6007c478bd9Sstevel@tonic-gate NULL); 6017c478bd9Sstevel@tonic-gate else 6027c478bd9Sstevel@tonic-gate ret = -1; 6037c478bd9Sstevel@tonic-gate 6047c478bd9Sstevel@tonic-gate (void) signal(SIGSEGV, segv); 6057c478bd9Sstevel@tonic-gate (void) signal(SIGBUS, bus); 6067c478bd9Sstevel@tonic-gate (void) signal(SIGILL, ill); 6077c478bd9Sstevel@tonic-gate 6087c478bd9Sstevel@tonic-gate if (ret == 0) 6097c478bd9Sstevel@tonic-gate return (ret); 6107c478bd9Sstevel@tonic-gate } else { 6117c478bd9Sstevel@tonic-gate start = pc; 6127c478bd9Sstevel@tonic-gate } 6137c478bd9Sstevel@tonic-gate 6147c478bd9Sstevel@tonic-gate (void) printf(" %-17s (", buff); 6157c478bd9Sstevel@tonic-gate for (i = 0; i < argc && i < MAX_ARGS; i++) 616186f7fbfSEdward Pilatowicz (void) printf((i+1 == argc) ? "%lx" : "%lx, ", argv[i]); 6177c478bd9Sstevel@tonic-gate if (i != argc) 6187c478bd9Sstevel@tonic-gate (void) printf("..."); 619186f7fbfSEdward Pilatowicz (void) printf((start != pc) ? ") + %lx\n" : ")\n", (long)(pc - start)); 6207c478bd9Sstevel@tonic-gate 621ea394cb0Sjohansen if (h->pydb != NULL && argc > 0) { 622ea394cb0Sjohansen char buf_py[1024]; 623ea394cb0Sjohansen int rc; 624ea394cb0Sjohansen 625ea394cb0Sjohansen rc = pydb_pc_frameinfo(h->pydb, pc, argv[0], buf_py, 626ea394cb0Sjohansen sizeof (buf_py)); 627ea394cb0Sjohansen if (rc == 0) { 628ea394cb0Sjohansen (void) printf(" %s", buf_py); 629ea394cb0Sjohansen } 630ea394cb0Sjohansen } 631ea394cb0Sjohansen 6327c478bd9Sstevel@tonic-gate /* 6337c478bd9Sstevel@tonic-gate * If the frame's pc is in the "sigh" (a.k.a. signal handler, signal 6347c478bd9Sstevel@tonic-gate * hack, or *sigh* ...) range, then we're about to cross a signal 6357c478bd9Sstevel@tonic-gate * frame. The signal number is the first argument to this function. 6367c478bd9Sstevel@tonic-gate */ 6377c478bd9Sstevel@tonic-gate if (pc - sigh.st_value < sigh.st_size) { 6387c478bd9Sstevel@tonic-gate if (sig2str((int)argv[0], buff) == -1) 6397c478bd9Sstevel@tonic-gate (void) strcpy(buff, " Unknown"); 6407c478bd9Sstevel@tonic-gate (void) printf(" --- called from signal handler with " 6417c478bd9Sstevel@tonic-gate "signal %d (SIG%s) ---\n", (int)argv[0], buff); 6427c478bd9Sstevel@tonic-gate } 6437c478bd9Sstevel@tonic-gate 6447c478bd9Sstevel@tonic-gate return (0); 6457c478bd9Sstevel@tonic-gate } 6467c478bd9Sstevel@tonic-gate 6477c478bd9Sstevel@tonic-gate static void 6487c478bd9Sstevel@tonic-gate print_zombie(struct ps_prochandle *Pr, struct threadinfo *tip) 6497c478bd9Sstevel@tonic-gate { 6507c478bd9Sstevel@tonic-gate char buff[255]; 6517c478bd9Sstevel@tonic-gate GElf_Sym sym; 6527c478bd9Sstevel@tonic-gate uintptr_t start; 6537c478bd9Sstevel@tonic-gate int length = (is64? 16 : 8); 6547c478bd9Sstevel@tonic-gate 6557c478bd9Sstevel@tonic-gate (void) sprintf(buff, "%.*lx", length, (long)tip->startfunc); 6567c478bd9Sstevel@tonic-gate (void) strcpy(buff + length, " ????????"); 6577c478bd9Sstevel@tonic-gate if (Plookup_by_addr(Pr, tip->startfunc, 6587c478bd9Sstevel@tonic-gate buff + 1 + length, sizeof (buff) - 1 - length, &sym) == 0) 6597c478bd9Sstevel@tonic-gate start = sym.st_value; 6607c478bd9Sstevel@tonic-gate else 6617c478bd9Sstevel@tonic-gate start = tip->startfunc; 6627c478bd9Sstevel@tonic-gate (void) printf(" %s()", buff); 6637c478bd9Sstevel@tonic-gate if (start != tip->startfunc) /* doesn't happen? */ 6647c478bd9Sstevel@tonic-gate (void) printf("+%lx", (long)(tip->startfunc - start)); 6657c478bd9Sstevel@tonic-gate (void) printf(", exit value = 0x%.*lx\n", length, (long)tip->exitval); 6667c478bd9Sstevel@tonic-gate (void) printf("\t** zombie " 667186f7fbfSEdward Pilatowicz "(exited, not detached, not yet joined) **\n"); 6687c478bd9Sstevel@tonic-gate } 6697c478bd9Sstevel@tonic-gate 6707c478bd9Sstevel@tonic-gate static void 6717c478bd9Sstevel@tonic-gate print_syscall(const lwpstatus_t *psp, prgregset_t reg) 6727c478bd9Sstevel@tonic-gate { 6737c478bd9Sstevel@tonic-gate char sname[32]; 6747c478bd9Sstevel@tonic-gate int length = (is64? 16 : 8); 6757c478bd9Sstevel@tonic-gate uint_t i; 6767c478bd9Sstevel@tonic-gate 6777c478bd9Sstevel@tonic-gate (void) proc_sysname(psp->pr_syscall, sname, sizeof (sname)); 6787c478bd9Sstevel@tonic-gate (void) printf(" %.*lx %-8s (", length, (long)reg[R_PC], sname); 6797c478bd9Sstevel@tonic-gate for (i = 0; i < psp->pr_nsysarg; i++) 6807c478bd9Sstevel@tonic-gate (void) printf((i+1 == psp->pr_nsysarg)? "%lx" : "%lx, ", 681186f7fbfSEdward Pilatowicz (long)psp->pr_sysarg[i]); 6827c478bd9Sstevel@tonic-gate (void) printf(")\n"); 6837c478bd9Sstevel@tonic-gate } 6847c478bd9Sstevel@tonic-gate 6857c478bd9Sstevel@tonic-gate static void 6867c478bd9Sstevel@tonic-gate call_stack(pstack_handle_t *h, const lwpstatus_t *psp) 6877c478bd9Sstevel@tonic-gate { 6887c478bd9Sstevel@tonic-gate prgregset_t reg; 6897c478bd9Sstevel@tonic-gate 6907c478bd9Sstevel@tonic-gate (void) memcpy(reg, psp->pr_reg, sizeof (reg)); 6917c478bd9Sstevel@tonic-gate 6927c478bd9Sstevel@tonic-gate if ((psp->pr_flags & (PR_ASLEEP|PR_VFORKP)) || 6937c478bd9Sstevel@tonic-gate ((psp->pr_flags & PR_ISTOP) && 6947c478bd9Sstevel@tonic-gate (psp->pr_why == PR_SYSENTRY || 6957c478bd9Sstevel@tonic-gate psp->pr_why == PR_SYSEXIT))) { 6967c478bd9Sstevel@tonic-gate print_syscall(psp, reg); 6977c478bd9Sstevel@tonic-gate h->ignore_frame = 1; 6987c478bd9Sstevel@tonic-gate } else { 6997c478bd9Sstevel@tonic-gate h->ignore_frame = 0; 7007c478bd9Sstevel@tonic-gate } 7017c478bd9Sstevel@tonic-gate 7027c478bd9Sstevel@tonic-gate (void) Pstack_iter(h->proc, reg, print_frame, h); 7037c478bd9Sstevel@tonic-gate } 7047c478bd9Sstevel@tonic-gate 7057c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 7067c478bd9Sstevel@tonic-gate static int 7077c478bd9Sstevel@tonic-gate jvm_object_iter(void *cd, const prmap_t *pmp, const char *obj) 7087c478bd9Sstevel@tonic-gate { 7097c478bd9Sstevel@tonic-gate char path[PATH_MAX]; 7107c478bd9Sstevel@tonic-gate char *name; 7117c478bd9Sstevel@tonic-gate char *s1, *s2; 7127c478bd9Sstevel@tonic-gate struct ps_prochandle *Pr = cd; 7137c478bd9Sstevel@tonic-gate 7147c478bd9Sstevel@tonic-gate if ((name = strstr(obj, "/libjvm.so")) == NULL) 7157c478bd9Sstevel@tonic-gate name = strstr(obj, "/libjvm_g.so"); 7167c478bd9Sstevel@tonic-gate 7177c478bd9Sstevel@tonic-gate if (name) { 7187c478bd9Sstevel@tonic-gate (void) strcpy(path, obj); 7197c478bd9Sstevel@tonic-gate if (Pstatus(Pr)->pr_dmodel != PR_MODEL_NATIVE) { 7207c478bd9Sstevel@tonic-gate s1 = name; 7217c478bd9Sstevel@tonic-gate s2 = path + (s1 - obj); 7227c478bd9Sstevel@tonic-gate (void) strcpy(s2, "/64"); 7237c478bd9Sstevel@tonic-gate s2 += 3; 7247c478bd9Sstevel@tonic-gate (void) strcpy(s2, s1); 7257c478bd9Sstevel@tonic-gate } 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate s1 = strstr(obj, ".so"); 7287c478bd9Sstevel@tonic-gate s2 = strstr(path, ".so"); 7297c478bd9Sstevel@tonic-gate (void) strcpy(s2, "_db"); 7307c478bd9Sstevel@tonic-gate s2 += 3; 7317c478bd9Sstevel@tonic-gate (void) strcpy(s2, s1); 7327c478bd9Sstevel@tonic-gate 7337c478bd9Sstevel@tonic-gate if ((libjvm = dlopen(path, RTLD_LAZY|RTLD_GLOBAL)) != NULL) 7347c478bd9Sstevel@tonic-gate return (1); 7357c478bd9Sstevel@tonic-gate } 7367c478bd9Sstevel@tonic-gate 7377c478bd9Sstevel@tonic-gate return (0); 7387c478bd9Sstevel@tonic-gate } 7397c478bd9Sstevel@tonic-gate 7407c478bd9Sstevel@tonic-gate static jvm_agent_t * 7417c478bd9Sstevel@tonic-gate load_libjvm(struct ps_prochandle *Pr) 7427c478bd9Sstevel@tonic-gate { 7437c478bd9Sstevel@tonic-gate jvm_agent_t *ret; 7447c478bd9Sstevel@tonic-gate 745186f7fbfSEdward Pilatowicz /* 746186f7fbfSEdward Pilatowicz * Iterate through all the loaded objects in the target, looking 747186f7fbfSEdward Pilatowicz * for libjvm.so. If we find libjvm.so we'll try to load the 748186f7fbfSEdward Pilatowicz * corresponding libjvm_db.so that lives in the same directory. 749186f7fbfSEdward Pilatowicz * 750186f7fbfSEdward Pilatowicz * At first glance it seems like we'd want to use 751186f7fbfSEdward Pilatowicz * Pobject_iter_resolved() here since we'd want to make sure that 752186f7fbfSEdward Pilatowicz * we have the full path to the libjvm.so. But really, we don't 753186f7fbfSEdward Pilatowicz * want that since we're going to be dlopen()ing a library and 754186f7fbfSEdward Pilatowicz * executing code from that path, and therefore we don't want to 755186f7fbfSEdward Pilatowicz * load any library code that could be from a zone since it could 756186f7fbfSEdward Pilatowicz * have been replaced with a trojan. Hence, we use Pobject_iter(). 757186f7fbfSEdward Pilatowicz * So if we're debugging java processes in a zone from the global 758186f7fbfSEdward Pilatowicz * zone, and we want to get proper java stack stack frames, then 759186f7fbfSEdward Pilatowicz * the same jvm that is running within the zone needs to be 760186f7fbfSEdward Pilatowicz * installed in the global zone. 761186f7fbfSEdward Pilatowicz */ 7627c478bd9Sstevel@tonic-gate (void) Pobject_iter(Pr, jvm_object_iter, Pr); 7637c478bd9Sstevel@tonic-gate 7647c478bd9Sstevel@tonic-gate if (libjvm) { 7657c478bd9Sstevel@tonic-gate j_agent_create = (j_agent_create_f) 7667c478bd9Sstevel@tonic-gate dlsym(libjvm, "Jagent_create"); 7677c478bd9Sstevel@tonic-gate j_agent_destroy = (j_agent_destroy_f) 7687c478bd9Sstevel@tonic-gate dlsym(libjvm, "Jagent_destroy"); 7697c478bd9Sstevel@tonic-gate j_frame_iter = (j_frame_iter_f) 7707c478bd9Sstevel@tonic-gate dlsym(libjvm, "Jframe_iter"); 7717c478bd9Sstevel@tonic-gate 7727c478bd9Sstevel@tonic-gate if (j_agent_create == NULL || j_agent_destroy == NULL || 7737c478bd9Sstevel@tonic-gate j_frame_iter == NULL || 7747c478bd9Sstevel@tonic-gate (ret = j_agent_create(Pr, JVM_DB_VERSION)) == NULL) { 7757c478bd9Sstevel@tonic-gate reset_libjvm(NULL); 7767c478bd9Sstevel@tonic-gate return (NULL); 7777c478bd9Sstevel@tonic-gate } 7787c478bd9Sstevel@tonic-gate 7797c478bd9Sstevel@tonic-gate return (ret); 7807c478bd9Sstevel@tonic-gate } 7817c478bd9Sstevel@tonic-gate 7827c478bd9Sstevel@tonic-gate return (NULL); 7837c478bd9Sstevel@tonic-gate } 7847c478bd9Sstevel@tonic-gate 7857c478bd9Sstevel@tonic-gate static void 7867c478bd9Sstevel@tonic-gate reset_libjvm(jvm_agent_t *agent) 7877c478bd9Sstevel@tonic-gate { 7887c478bd9Sstevel@tonic-gate if (libjvm) { 7897c478bd9Sstevel@tonic-gate if (agent) 7907c478bd9Sstevel@tonic-gate j_agent_destroy(agent); 7917c478bd9Sstevel@tonic-gate 7927c478bd9Sstevel@tonic-gate (void) dlclose(libjvm); 7937c478bd9Sstevel@tonic-gate } 7947c478bd9Sstevel@tonic-gate 7957c478bd9Sstevel@tonic-gate j_agent_create = NULL; 7967c478bd9Sstevel@tonic-gate j_agent_destroy = NULL; 7977c478bd9Sstevel@tonic-gate j_frame_iter = NULL; 7987c478bd9Sstevel@tonic-gate libjvm = NULL; 7997c478bd9Sstevel@tonic-gate } 800ea394cb0Sjohansen 801ea394cb0Sjohansen /*ARGSUSED*/ 802ea394cb0Sjohansen static int 803ea394cb0Sjohansen python_object_iter(void *cd, const prmap_t *pmp, const char *obj) 804ea394cb0Sjohansen { 805ea394cb0Sjohansen char path[PATH_MAX]; 806ea394cb0Sjohansen char *name; 807ea394cb0Sjohansen char *s1, *s2; 808ea394cb0Sjohansen struct ps_prochandle *Pr = cd; 809ea394cb0Sjohansen 810ea394cb0Sjohansen name = strstr(obj, "/libpython"); 811ea394cb0Sjohansen 812ea394cb0Sjohansen if (name) { 813ea394cb0Sjohansen (void) strcpy(path, obj); 814ea394cb0Sjohansen if (Pstatus(Pr)->pr_dmodel != PR_MODEL_NATIVE) { 815ea394cb0Sjohansen s1 = name; 816ea394cb0Sjohansen s2 = path + (s1 - obj); 817ea394cb0Sjohansen (void) strcpy(s2, "/64"); 818ea394cb0Sjohansen s2 += 3; 819ea394cb0Sjohansen (void) strcpy(s2, s1); 820ea394cb0Sjohansen } 821ea394cb0Sjohansen 822ea394cb0Sjohansen s1 = strstr(obj, ".so"); 823ea394cb0Sjohansen s2 = strstr(path, ".so"); 824ea394cb0Sjohansen (void) strcpy(s2, "_db"); 825ea394cb0Sjohansen s2 += 3; 826ea394cb0Sjohansen (void) strcpy(s2, s1); 827ea394cb0Sjohansen 828ea394cb0Sjohansen if ((libpython = dlopen(path, RTLD_LAZY|RTLD_GLOBAL)) != NULL) 829ea394cb0Sjohansen return (1); 830ea394cb0Sjohansen } 831ea394cb0Sjohansen 832ea394cb0Sjohansen return (0); 833ea394cb0Sjohansen } 834ea394cb0Sjohansen 835ea394cb0Sjohansen static pydb_agent_t * 836ea394cb0Sjohansen load_libpython(struct ps_prochandle *Pr) 837ea394cb0Sjohansen { 838ea394cb0Sjohansen pydb_agent_t *pdb; 839ea394cb0Sjohansen 840ea394cb0Sjohansen (void) Pobject_iter(Pr, python_object_iter, Pr); 841ea394cb0Sjohansen 842ea394cb0Sjohansen if (libpython) { 843ea394cb0Sjohansen pydb_agent_create = (pydb_agent_create_f) 844ea394cb0Sjohansen dlsym(libpython, "pydb_agent_create"); 845ea394cb0Sjohansen pydb_agent_destroy = (pydb_agent_destroy_f) 846ea394cb0Sjohansen dlsym(libpython, "pydb_agent_destroy"); 847ea394cb0Sjohansen pydb_pc_frameinfo = (pydb_pc_frameinfo_f) 848ea394cb0Sjohansen dlsym(libpython, "pydb_pc_frameinfo"); 849ea394cb0Sjohansen 850ea394cb0Sjohansen if (pydb_agent_create == NULL || pydb_agent_destroy == NULL || 851ea394cb0Sjohansen pydb_pc_frameinfo == NULL) { 852ea394cb0Sjohansen (void) dlclose(libpython); 853ea394cb0Sjohansen libpython = NULL; 854ea394cb0Sjohansen return (NULL); 855ea394cb0Sjohansen } 856ea394cb0Sjohansen 857ea394cb0Sjohansen pdb = pydb_agent_create(Pr, PYDB_VERSION); 858ea394cb0Sjohansen if (pdb == NULL) { 859ea394cb0Sjohansen (void) dlclose(libpython); 860ea394cb0Sjohansen libpython = NULL; 861ea394cb0Sjohansen return (NULL); 862ea394cb0Sjohansen } 863ea394cb0Sjohansen return (pdb); 864ea394cb0Sjohansen } 865ea394cb0Sjohansen 866ea394cb0Sjohansen return (NULL); 867ea394cb0Sjohansen } 868ea394cb0Sjohansen 869ea394cb0Sjohansen static void 870ea394cb0Sjohansen reset_libpython(pydb_agent_t *pdb) 871ea394cb0Sjohansen { 872ea394cb0Sjohansen if (libpython != NULL) { 873ea394cb0Sjohansen if (pdb != NULL) { 874ea394cb0Sjohansen pydb_agent_destroy(pdb); 875ea394cb0Sjohansen } 876ea394cb0Sjohansen (void) dlclose(libpython); 877ea394cb0Sjohansen } 878ea394cb0Sjohansen 879ea394cb0Sjohansen libpython = NULL; 880ea394cb0Sjohansen pydb_agent_create = NULL; 881ea394cb0Sjohansen pydb_agent_destroy = NULL; 882ea394cb0Sjohansen pydb_pc_frameinfo = NULL; 883ea394cb0Sjohansen } 884