10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51914Scasper * Common Development and Distribution License (the "License"). 61914Scasper * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*11946Sjohansen@sun.com * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #include <sys/isa_defs.h> 270Sstevel@tonic-gate 280Sstevel@tonic-gate #include <stdio.h> 291914Scasper #include <stdio_ext.h> 300Sstevel@tonic-gate #include <fcntl.h> 310Sstevel@tonic-gate #include <ctype.h> 320Sstevel@tonic-gate #include <string.h> 330Sstevel@tonic-gate #include <signal.h> 340Sstevel@tonic-gate #include <dirent.h> 350Sstevel@tonic-gate #include <errno.h> 360Sstevel@tonic-gate #include <stdlib.h> 370Sstevel@tonic-gate #include <stdarg.h> 380Sstevel@tonic-gate #include <unistd.h> 390Sstevel@tonic-gate #include <sys/types.h> 400Sstevel@tonic-gate #include <sys/stat.h> 410Sstevel@tonic-gate #include <sys/stack.h> 420Sstevel@tonic-gate #include <link.h> 430Sstevel@tonic-gate #include <limits.h> 440Sstevel@tonic-gate #include <libelf.h> 450Sstevel@tonic-gate #include <thread_db.h> 460Sstevel@tonic-gate #include <libproc.h> 470Sstevel@tonic-gate #include <setjmp.h> 480Sstevel@tonic-gate 490Sstevel@tonic-gate static char *command; 500Sstevel@tonic-gate static int Fflag; 510Sstevel@tonic-gate static int is64; 520Sstevel@tonic-gate static GElf_Sym sigh; 530Sstevel@tonic-gate 540Sstevel@tonic-gate /* 550Sstevel@tonic-gate * To keep the list of user-level threads for a multithreaded process. 560Sstevel@tonic-gate */ 570Sstevel@tonic-gate struct threadinfo { 580Sstevel@tonic-gate struct threadinfo *next; 590Sstevel@tonic-gate id_t threadid; 600Sstevel@tonic-gate id_t lwpid; 610Sstevel@tonic-gate td_thr_state_e state; 620Sstevel@tonic-gate uintptr_t startfunc; 630Sstevel@tonic-gate uintptr_t exitval; 640Sstevel@tonic-gate prgregset_t regs; 650Sstevel@tonic-gate }; 660Sstevel@tonic-gate 670Sstevel@tonic-gate static struct threadinfo *thr_head, *thr_tail; 680Sstevel@tonic-gate 690Sstevel@tonic-gate #define TRUE 1 700Sstevel@tonic-gate #define FALSE 0 710Sstevel@tonic-gate 720Sstevel@tonic-gate #define MAX_ARGS 8 730Sstevel@tonic-gate 740Sstevel@tonic-gate /* 750Sstevel@tonic-gate * To support debugging java programs, we display java frames within a stack. 760Sstevel@tonic-gate * The logic to walk the java frames is contained in libjvm_db.so, which is 770Sstevel@tonic-gate * found in the same directory as libjvm.so, linked with the program. If we are 780Sstevel@tonic-gate * debugging a 32-bit app with a 64-binary, then the debugging library is found 790Sstevel@tonic-gate * in the '64' subdirectory. If we find libjvm_db.so, then we fill in these 800Sstevel@tonic-gate * stub routines. 810Sstevel@tonic-gate */ 820Sstevel@tonic-gate typedef struct jvm_agent jvm_agent_t; 830Sstevel@tonic-gate typedef int java_stack_f(void *, prgregset_t, const char *, int, int, void *); 840Sstevel@tonic-gate 850Sstevel@tonic-gate /* 860Sstevel@tonic-gate * The j_agent_create function takes a version parameter. This ensures that the 870Sstevel@tonic-gate * interface can evolve appropriately. 880Sstevel@tonic-gate */ 890Sstevel@tonic-gate #define JVM_DB_VERSION 1 900Sstevel@tonic-gate static void *libjvm; 910Sstevel@tonic-gate typedef jvm_agent_t *(*j_agent_create_f)(struct ps_prochandle *, int); 920Sstevel@tonic-gate typedef void (*j_agent_destroy_f)(jvm_agent_t *); 930Sstevel@tonic-gate typedef int (*j_frame_iter_f)(jvm_agent_t *, prgregset_t, java_stack_f *, 940Sstevel@tonic-gate void *); 950Sstevel@tonic-gate 960Sstevel@tonic-gate static j_agent_create_f j_agent_create; 970Sstevel@tonic-gate static j_agent_destroy_f j_agent_destroy; 980Sstevel@tonic-gate static j_frame_iter_f j_frame_iter; 990Sstevel@tonic-gate 1000Sstevel@tonic-gate static jvm_agent_t *load_libjvm(struct ps_prochandle *P); 1010Sstevel@tonic-gate static void reset_libjvm(jvm_agent_t *); 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate /* 104*11946Sjohansen@sun.com * Similar to what's done for debugging java programs, here are prototypes for 105*11946Sjohansen@sun.com * the library that allows us to debug Python programs. 106*11946Sjohansen@sun.com */ 107*11946Sjohansen@sun.com #define PYDB_VERSION 1 108*11946Sjohansen@sun.com static void *libpython; 109*11946Sjohansen@sun.com 110*11946Sjohansen@sun.com typedef struct pydb_agent pydb_agent_t; 111*11946Sjohansen@sun.com 112*11946Sjohansen@sun.com typedef pydb_agent_t *(*pydb_agent_create_f)(struct ps_prochandle *P, int vers); 113*11946Sjohansen@sun.com typedef void (*pydb_agent_destroy_f)(pydb_agent_t *py); 114*11946Sjohansen@sun.com typedef int (*pydb_pc_frameinfo_f)(pydb_agent_t *py, uintptr_t pc, 115*11946Sjohansen@sun.com uintptr_t frame_addr, char *fbuf, size_t bufsz); 116*11946Sjohansen@sun.com 117*11946Sjohansen@sun.com static pydb_agent_create_f pydb_agent_create; 118*11946Sjohansen@sun.com static pydb_agent_destroy_f pydb_agent_destroy; 119*11946Sjohansen@sun.com static pydb_pc_frameinfo_f pydb_pc_frameinfo; 120*11946Sjohansen@sun.com 121*11946Sjohansen@sun.com static pydb_agent_t *load_libpython(struct ps_prochandle *P); 122*11946Sjohansen@sun.com static void reset_libpython(pydb_agent_t *); 123*11946Sjohansen@sun.com /* 1240Sstevel@tonic-gate * Since we must maintain both a proc handle and a jvm handle, this structure 1250Sstevel@tonic-gate * is the basic type that gets passed around. 1260Sstevel@tonic-gate */ 1270Sstevel@tonic-gate typedef struct pstack_handle { 1280Sstevel@tonic-gate struct ps_prochandle *proc; 1290Sstevel@tonic-gate jvm_agent_t *jvm; 1300Sstevel@tonic-gate int ignore_frame; 1310Sstevel@tonic-gate const char *lwps; 1320Sstevel@tonic-gate int count; 133*11946Sjohansen@sun.com pydb_agent_t *pydb; 1340Sstevel@tonic-gate } pstack_handle_t; 1350Sstevel@tonic-gate 1360Sstevel@tonic-gate static int thr_stack(const td_thrhandle_t *, void *); 1370Sstevel@tonic-gate static void free_threadinfo(void); 1380Sstevel@tonic-gate static struct threadinfo *find_thread(id_t); 1390Sstevel@tonic-gate static int all_call_stacks(pstack_handle_t *, int); 1400Sstevel@tonic-gate static void tlhead(id_t, id_t); 1410Sstevel@tonic-gate static int print_frame(void *, prgregset_t, uint_t, const long *); 1420Sstevel@tonic-gate static void print_zombie(struct ps_prochandle *, struct threadinfo *); 1430Sstevel@tonic-gate static void print_syscall(const lwpstatus_t *, prgregset_t); 1440Sstevel@tonic-gate static void call_stack(pstack_handle_t *, const lwpstatus_t *); 1450Sstevel@tonic-gate 1460Sstevel@tonic-gate /* 1470Sstevel@tonic-gate * The number of active and zombie threads. 1480Sstevel@tonic-gate */ 1490Sstevel@tonic-gate static int nthreads; 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate int 1520Sstevel@tonic-gate main(int argc, char **argv) 1530Sstevel@tonic-gate { 1540Sstevel@tonic-gate int retc = 0; 1550Sstevel@tonic-gate int opt; 1560Sstevel@tonic-gate int errflg = FALSE; 1570Sstevel@tonic-gate core_content_t content = CC_CONTENT_DATA | CC_CONTENT_ANON | 1580Sstevel@tonic-gate CC_CONTENT_STACK; 1590Sstevel@tonic-gate struct rlimit rlim; 1600Sstevel@tonic-gate 1610Sstevel@tonic-gate if ((command = strrchr(argv[0], '/')) != NULL) 1620Sstevel@tonic-gate command++; 1630Sstevel@tonic-gate else 1640Sstevel@tonic-gate command = argv[0]; 1650Sstevel@tonic-gate 1660Sstevel@tonic-gate /* options */ 1670Sstevel@tonic-gate while ((opt = getopt(argc, argv, "F")) != EOF) { 1680Sstevel@tonic-gate switch (opt) { 1690Sstevel@tonic-gate case 'F': 1700Sstevel@tonic-gate /* 1710Sstevel@tonic-gate * If the user specifies the force option, we'll 1720Sstevel@tonic-gate * consent to printing out other threads' stacks 1730Sstevel@tonic-gate * even if the main stack is absent. 1740Sstevel@tonic-gate */ 1750Sstevel@tonic-gate content &= ~CC_CONTENT_STACK; 1760Sstevel@tonic-gate Fflag = PGRAB_FORCE; 1770Sstevel@tonic-gate break; 1780Sstevel@tonic-gate default: 1790Sstevel@tonic-gate errflg = TRUE; 1800Sstevel@tonic-gate break; 1810Sstevel@tonic-gate } 1820Sstevel@tonic-gate } 1830Sstevel@tonic-gate 1840Sstevel@tonic-gate argc -= optind; 1850Sstevel@tonic-gate argv += optind; 1860Sstevel@tonic-gate 1870Sstevel@tonic-gate if (errflg || argc <= 0) { 1880Sstevel@tonic-gate (void) fprintf(stderr, 1890Sstevel@tonic-gate "usage:\t%s [-F] { pid | core }[/lwps] ...\n", command); 1900Sstevel@tonic-gate (void) fprintf(stderr, " (show process call stack)\n"); 1910Sstevel@tonic-gate (void) fprintf(stderr, 1927675SEdward.Pilatowicz@Sun.COM " -F: force grabbing of the target process\n"); 1930Sstevel@tonic-gate exit(2); 1940Sstevel@tonic-gate } 1950Sstevel@tonic-gate 1960Sstevel@tonic-gate /* 1970Sstevel@tonic-gate * Make sure we'll have enough file descriptors to handle a target 1980Sstevel@tonic-gate * that has many many mappings. 1990Sstevel@tonic-gate */ 2000Sstevel@tonic-gate if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) { 2010Sstevel@tonic-gate rlim.rlim_cur = rlim.rlim_max; 2020Sstevel@tonic-gate (void) setrlimit(RLIMIT_NOFILE, &rlim); 2031914Scasper (void) enable_extended_FILE_stdio(-1, -1); 2040Sstevel@tonic-gate } 2050Sstevel@tonic-gate 2060Sstevel@tonic-gate (void) proc_initstdio(); 2070Sstevel@tonic-gate 2080Sstevel@tonic-gate while (--argc >= 0) { 2090Sstevel@tonic-gate int gcode; 2100Sstevel@tonic-gate psinfo_t psinfo; 2110Sstevel@tonic-gate const psinfo_t *tpsinfo; 2120Sstevel@tonic-gate struct ps_prochandle *Pr = NULL; 2130Sstevel@tonic-gate td_thragent_t *Tap; 2140Sstevel@tonic-gate int threaded; 2150Sstevel@tonic-gate pstack_handle_t handle; 2160Sstevel@tonic-gate const char *lwps, *arg; 2170Sstevel@tonic-gate 2180Sstevel@tonic-gate (void) proc_flushstdio(); 2190Sstevel@tonic-gate 2200Sstevel@tonic-gate arg = *argv++; 2210Sstevel@tonic-gate 2220Sstevel@tonic-gate if ((Pr = proc_arg_xgrab(arg, NULL, PR_ARG_ANY, 2230Sstevel@tonic-gate Fflag, &gcode, &lwps)) == NULL) { 2240Sstevel@tonic-gate (void) fprintf(stderr, "%s: cannot examine %s: %s\n", 2250Sstevel@tonic-gate command, arg, Pgrab_error(gcode)); 2260Sstevel@tonic-gate retc++; 2270Sstevel@tonic-gate continue; 2280Sstevel@tonic-gate } 2290Sstevel@tonic-gate 2300Sstevel@tonic-gate if ((tpsinfo = Ppsinfo(Pr)) == NULL) { 2310Sstevel@tonic-gate (void) fprintf(stderr, "%s: cannot examine %s: " 2320Sstevel@tonic-gate "lost control of process\n", command, arg); 2330Sstevel@tonic-gate Prelease(Pr, 0); 2340Sstevel@tonic-gate retc++; 2350Sstevel@tonic-gate continue; 2360Sstevel@tonic-gate } 2370Sstevel@tonic-gate (void) memcpy(&psinfo, tpsinfo, sizeof (psinfo_t)); 2380Sstevel@tonic-gate proc_unctrl_psinfo(&psinfo); 2390Sstevel@tonic-gate 2400Sstevel@tonic-gate if (Pstate(Pr) == PS_DEAD) { 2410Sstevel@tonic-gate if ((Pcontent(Pr) & content) != content) { 2420Sstevel@tonic-gate (void) fprintf(stderr, "%s: core '%s' has " 2430Sstevel@tonic-gate "insufficient content\n", command, arg); 2440Sstevel@tonic-gate retc++; 2450Sstevel@tonic-gate continue; 2460Sstevel@tonic-gate } 2470Sstevel@tonic-gate (void) printf("core '%s' of %d:\t%.70s\n", 2480Sstevel@tonic-gate arg, (int)psinfo.pr_pid, psinfo.pr_psargs); 2490Sstevel@tonic-gate } else { 2500Sstevel@tonic-gate (void) printf("%d:\t%.70s\n", 2510Sstevel@tonic-gate (int)psinfo.pr_pid, psinfo.pr_psargs); 2520Sstevel@tonic-gate } 2530Sstevel@tonic-gate 2540Sstevel@tonic-gate is64 = (psinfo.pr_dmodel == PR_MODEL_LP64); 2550Sstevel@tonic-gate 2560Sstevel@tonic-gate if (Pgetauxval(Pr, AT_BASE) != -1L && Prd_agent(Pr) == NULL) { 2570Sstevel@tonic-gate (void) fprintf(stderr, "%s: warning: librtld_db failed " 2580Sstevel@tonic-gate "to initialize; symbols from shared libraries will " 2590Sstevel@tonic-gate "not be available\n", command); 2600Sstevel@tonic-gate } 2610Sstevel@tonic-gate 2620Sstevel@tonic-gate /* 2630Sstevel@tonic-gate * First we need to get a thread agent handle. 2640Sstevel@tonic-gate */ 2650Sstevel@tonic-gate if (td_init() != TD_OK || 2660Sstevel@tonic-gate td_ta_new(Pr, &Tap) != TD_OK) /* no libc */ 2670Sstevel@tonic-gate threaded = FALSE; 2680Sstevel@tonic-gate else { 2690Sstevel@tonic-gate /* 2700Sstevel@tonic-gate * Iterate over all threads, calling: 2710Sstevel@tonic-gate * thr_stack(td_thrhandle_t *Thp, NULL); 2720Sstevel@tonic-gate * for each one to generate the list of threads. 2730Sstevel@tonic-gate */ 2740Sstevel@tonic-gate nthreads = 0; 2750Sstevel@tonic-gate (void) td_ta_thr_iter(Tap, thr_stack, NULL, 2760Sstevel@tonic-gate TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY, 2770Sstevel@tonic-gate TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS); 2780Sstevel@tonic-gate 2790Sstevel@tonic-gate (void) td_ta_delete(Tap); 2800Sstevel@tonic-gate threaded = TRUE; 2810Sstevel@tonic-gate } 2820Sstevel@tonic-gate 2830Sstevel@tonic-gate handle.proc = Pr; 2840Sstevel@tonic-gate handle.jvm = load_libjvm(Pr); 285*11946Sjohansen@sun.com handle.pydb = load_libpython(Pr); 2860Sstevel@tonic-gate handle.lwps = lwps; 2870Sstevel@tonic-gate handle.count = 0; 2880Sstevel@tonic-gate 2890Sstevel@tonic-gate if (all_call_stacks(&handle, threaded) != 0) 2900Sstevel@tonic-gate retc++; 2910Sstevel@tonic-gate if (threaded) 2920Sstevel@tonic-gate free_threadinfo(); 2930Sstevel@tonic-gate 2940Sstevel@tonic-gate reset_libjvm(handle.jvm); 295*11946Sjohansen@sun.com reset_libpython(handle.pydb); 2960Sstevel@tonic-gate Prelease(Pr, 0); 2970Sstevel@tonic-gate 2980Sstevel@tonic-gate if (handle.count == 0) 2990Sstevel@tonic-gate (void) fprintf(stderr, "%s: no matching LWPs found\n", 3000Sstevel@tonic-gate command); 3010Sstevel@tonic-gate } 3020Sstevel@tonic-gate 3030Sstevel@tonic-gate (void) proc_finistdio(); 3040Sstevel@tonic-gate 3050Sstevel@tonic-gate return (retc); 3060Sstevel@tonic-gate } 3070Sstevel@tonic-gate 3080Sstevel@tonic-gate /* 3090Sstevel@tonic-gate * Thread iteration call-back function. 3100Sstevel@tonic-gate * Called once for each user-level thread. 3110Sstevel@tonic-gate * Used to build the list of all threads. 3120Sstevel@tonic-gate */ 3130Sstevel@tonic-gate /* ARGSUSED1 */ 3140Sstevel@tonic-gate static int 3150Sstevel@tonic-gate thr_stack(const td_thrhandle_t *Thp, void *cd) 3160Sstevel@tonic-gate { 3170Sstevel@tonic-gate td_thrinfo_t thrinfo; 3180Sstevel@tonic-gate struct threadinfo *tip; 3190Sstevel@tonic-gate td_err_e error; 3200Sstevel@tonic-gate 3210Sstevel@tonic-gate if (td_thr_get_info(Thp, &thrinfo) != TD_OK) 3220Sstevel@tonic-gate return (0); 3230Sstevel@tonic-gate 3240Sstevel@tonic-gate tip = malloc(sizeof (struct threadinfo)); 3250Sstevel@tonic-gate tip->next = NULL; 3260Sstevel@tonic-gate tip->threadid = thrinfo.ti_tid; 3270Sstevel@tonic-gate tip->lwpid = thrinfo.ti_lid; 3280Sstevel@tonic-gate tip->state = thrinfo.ti_state; 3290Sstevel@tonic-gate tip->startfunc = thrinfo.ti_startfunc; 3300Sstevel@tonic-gate tip->exitval = (uintptr_t)thrinfo.ti_exitval; 3310Sstevel@tonic-gate nthreads++; 3320Sstevel@tonic-gate 3330Sstevel@tonic-gate if (thrinfo.ti_state == TD_THR_ZOMBIE || 3340Sstevel@tonic-gate ((error = td_thr_getgregs(Thp, tip->regs)) != TD_OK && 3350Sstevel@tonic-gate error != TD_PARTIALREG)) 3360Sstevel@tonic-gate (void) memset(tip->regs, 0, sizeof (prgregset_t)); 3370Sstevel@tonic-gate 3380Sstevel@tonic-gate if (thr_tail) 3390Sstevel@tonic-gate thr_tail->next = tip; 3400Sstevel@tonic-gate else 3410Sstevel@tonic-gate thr_head = tip; 3420Sstevel@tonic-gate thr_tail = tip; 3430Sstevel@tonic-gate 3440Sstevel@tonic-gate return (0); 3450Sstevel@tonic-gate } 3460Sstevel@tonic-gate 3470Sstevel@tonic-gate static void 3480Sstevel@tonic-gate free_threadinfo() 3490Sstevel@tonic-gate { 3500Sstevel@tonic-gate struct threadinfo *tip = thr_head; 3510Sstevel@tonic-gate struct threadinfo *next; 3520Sstevel@tonic-gate 3530Sstevel@tonic-gate while (tip) { 3540Sstevel@tonic-gate next = tip->next; 3550Sstevel@tonic-gate free(tip); 3560Sstevel@tonic-gate tip = next; 3570Sstevel@tonic-gate } 3580Sstevel@tonic-gate 3590Sstevel@tonic-gate thr_head = thr_tail = NULL; 3600Sstevel@tonic-gate } 3610Sstevel@tonic-gate 3620Sstevel@tonic-gate /* 3630Sstevel@tonic-gate * Find and eliminate the thread corresponding to the given lwpid. 3640Sstevel@tonic-gate */ 3650Sstevel@tonic-gate static struct threadinfo * 3660Sstevel@tonic-gate find_thread(id_t lwpid) 3670Sstevel@tonic-gate { 3680Sstevel@tonic-gate struct threadinfo *tip; 3690Sstevel@tonic-gate 3700Sstevel@tonic-gate for (tip = thr_head; tip; tip = tip->next) { 3710Sstevel@tonic-gate if (lwpid == tip->lwpid) { 3720Sstevel@tonic-gate tip->lwpid = 0; 3730Sstevel@tonic-gate return (tip); 3740Sstevel@tonic-gate } 3750Sstevel@tonic-gate } 3760Sstevel@tonic-gate return (NULL); 3770Sstevel@tonic-gate } 3780Sstevel@tonic-gate 3790Sstevel@tonic-gate static int 3800Sstevel@tonic-gate thread_call_stack(void *data, const lwpstatus_t *psp, 3810Sstevel@tonic-gate const lwpsinfo_t *pip) 3820Sstevel@tonic-gate { 3830Sstevel@tonic-gate pstack_handle_t *h = data; 3840Sstevel@tonic-gate lwpstatus_t lwpstatus; 3850Sstevel@tonic-gate struct threadinfo *tip; 3860Sstevel@tonic-gate 3870Sstevel@tonic-gate if (!proc_lwp_in_set(h->lwps, pip->pr_lwpid)) 3880Sstevel@tonic-gate return (0); 3890Sstevel@tonic-gate h->count++; 3900Sstevel@tonic-gate 3910Sstevel@tonic-gate if ((tip = find_thread(pip->pr_lwpid)) == NULL) 3920Sstevel@tonic-gate return (0); 3930Sstevel@tonic-gate 3940Sstevel@tonic-gate tlhead(tip->threadid, pip->pr_lwpid); 3950Sstevel@tonic-gate tip->threadid = 0; /* finish eliminating tid */ 3960Sstevel@tonic-gate if (psp) 3970Sstevel@tonic-gate call_stack(h, psp); 3980Sstevel@tonic-gate else { 3990Sstevel@tonic-gate if (tip->state == TD_THR_ZOMBIE) 4000Sstevel@tonic-gate print_zombie(h->proc, tip); 4010Sstevel@tonic-gate else { 4020Sstevel@tonic-gate (void) memset(&lwpstatus, 0, sizeof (lwpstatus)); 4030Sstevel@tonic-gate (void) memcpy(lwpstatus.pr_reg, tip->regs, 4047675SEdward.Pilatowicz@Sun.COM sizeof (prgregset_t)); 4050Sstevel@tonic-gate call_stack(h, &lwpstatus); 4060Sstevel@tonic-gate } 4070Sstevel@tonic-gate } 4080Sstevel@tonic-gate return (0); 4090Sstevel@tonic-gate } 4100Sstevel@tonic-gate 4110Sstevel@tonic-gate static int 4120Sstevel@tonic-gate lwp_call_stack(void *data, 4130Sstevel@tonic-gate const lwpstatus_t *psp, const lwpsinfo_t *pip) 4140Sstevel@tonic-gate { 4150Sstevel@tonic-gate pstack_handle_t *h = data; 4160Sstevel@tonic-gate 4170Sstevel@tonic-gate if (!proc_lwp_in_set(h->lwps, pip->pr_lwpid)) 4180Sstevel@tonic-gate return (0); 4190Sstevel@tonic-gate h->count++; 4200Sstevel@tonic-gate 4210Sstevel@tonic-gate tlhead(0, pip->pr_lwpid); 4220Sstevel@tonic-gate if (psp) 4230Sstevel@tonic-gate call_stack(h, psp); 4240Sstevel@tonic-gate else 4250Sstevel@tonic-gate (void) printf("\t** zombie " 4267675SEdward.Pilatowicz@Sun.COM "(exited, not detached, not yet joined) **\n"); 4270Sstevel@tonic-gate return (0); 4280Sstevel@tonic-gate } 4290Sstevel@tonic-gate 4300Sstevel@tonic-gate static int 4310Sstevel@tonic-gate all_call_stacks(pstack_handle_t *h, int dothreads) 4320Sstevel@tonic-gate { 4330Sstevel@tonic-gate struct ps_prochandle *Pr = h->proc; 4340Sstevel@tonic-gate pstatus_t status = *Pstatus(Pr); 4350Sstevel@tonic-gate 4360Sstevel@tonic-gate (void) memset(&sigh, 0, sizeof (GElf_Sym)); 4370Sstevel@tonic-gate (void) Plookup_by_name(Pr, "libc.so", "sigacthandler", &sigh); 4380Sstevel@tonic-gate 4390Sstevel@tonic-gate if ((status.pr_nlwp + status.pr_nzomb) <= 1 && 4400Sstevel@tonic-gate !(dothreads && nthreads > 1)) { 4410Sstevel@tonic-gate if (proc_lwp_in_set(h->lwps, status.pr_lwp.pr_lwpid)) { 4420Sstevel@tonic-gate call_stack(h, &status.pr_lwp); 4430Sstevel@tonic-gate h->count++; 4440Sstevel@tonic-gate } 4450Sstevel@tonic-gate } else { 4460Sstevel@tonic-gate lwpstatus_t lwpstatus; 4470Sstevel@tonic-gate struct threadinfo *tip; 4480Sstevel@tonic-gate id_t tid; 4490Sstevel@tonic-gate 4500Sstevel@tonic-gate if (dothreads) 4510Sstevel@tonic-gate (void) Plwp_iter_all(Pr, thread_call_stack, h); 4520Sstevel@tonic-gate else 4530Sstevel@tonic-gate (void) Plwp_iter_all(Pr, lwp_call_stack, h); 4540Sstevel@tonic-gate 4550Sstevel@tonic-gate /* for each remaining thread w/o an lwp */ 4560Sstevel@tonic-gate (void) memset(&lwpstatus, 0, sizeof (lwpstatus)); 4570Sstevel@tonic-gate for (tip = thr_head; tip; tip = tip->next) { 4580Sstevel@tonic-gate 4590Sstevel@tonic-gate if (!proc_lwp_in_set(h->lwps, tip->lwpid)) 4600Sstevel@tonic-gate tip->threadid = 0; 4610Sstevel@tonic-gate 4620Sstevel@tonic-gate if ((tid = tip->threadid) != 0) { 4630Sstevel@tonic-gate (void) memcpy(lwpstatus.pr_reg, tip->regs, 4647675SEdward.Pilatowicz@Sun.COM sizeof (prgregset_t)); 4650Sstevel@tonic-gate tlhead(tid, tip->lwpid); 4660Sstevel@tonic-gate if (tip->state == TD_THR_ZOMBIE) 4670Sstevel@tonic-gate print_zombie(Pr, tip); 4680Sstevel@tonic-gate else 4690Sstevel@tonic-gate call_stack(h, &lwpstatus); 4700Sstevel@tonic-gate } 4710Sstevel@tonic-gate tip->threadid = 0; 4720Sstevel@tonic-gate tip->lwpid = 0; 4730Sstevel@tonic-gate } 4740Sstevel@tonic-gate } 4750Sstevel@tonic-gate return (0); 4760Sstevel@tonic-gate } 4770Sstevel@tonic-gate 4780Sstevel@tonic-gate static void 4790Sstevel@tonic-gate tlhead(id_t threadid, id_t lwpid) 4800Sstevel@tonic-gate { 4810Sstevel@tonic-gate if (threadid == 0 && lwpid == 0) 4820Sstevel@tonic-gate return; 4830Sstevel@tonic-gate 4840Sstevel@tonic-gate (void) printf("-----------------"); 4850Sstevel@tonic-gate 4860Sstevel@tonic-gate if (threadid && lwpid) 4870Sstevel@tonic-gate (void) printf(" lwp# %d / thread# %d ", 4887675SEdward.Pilatowicz@Sun.COM (int)lwpid, (int)threadid); 4890Sstevel@tonic-gate else if (threadid) 4900Sstevel@tonic-gate (void) printf("--------- thread# %d ", (int)threadid); 4910Sstevel@tonic-gate else if (lwpid) 4920Sstevel@tonic-gate (void) printf(" lwp# %d ------------", (int)lwpid); 4930Sstevel@tonic-gate 4940Sstevel@tonic-gate (void) printf("--------------------\n"); 4950Sstevel@tonic-gate } 4960Sstevel@tonic-gate 4970Sstevel@tonic-gate /*ARGSUSED*/ 4980Sstevel@tonic-gate static int 4990Sstevel@tonic-gate print_java_frame(void *cld, prgregset_t gregs, const char *name, int bci, 5000Sstevel@tonic-gate int line, void *handle) 5010Sstevel@tonic-gate { 5020Sstevel@tonic-gate int length = (is64 ? 16 : 8); 5030Sstevel@tonic-gate 5040Sstevel@tonic-gate (void) printf(" %.*lx * %s", length, (long)gregs[R_PC], name); 5050Sstevel@tonic-gate 5060Sstevel@tonic-gate if (bci != -1) { 5070Sstevel@tonic-gate (void) printf("+%d", bci); 5080Sstevel@tonic-gate if (line) 5090Sstevel@tonic-gate (void) printf(" (line %d)", line); 5100Sstevel@tonic-gate } 5110Sstevel@tonic-gate (void) printf("\n"); 5120Sstevel@tonic-gate 5130Sstevel@tonic-gate return (0); 5140Sstevel@tonic-gate } 5150Sstevel@tonic-gate 5160Sstevel@tonic-gate static sigjmp_buf jumpbuf; 5170Sstevel@tonic-gate 5180Sstevel@tonic-gate /*ARGSUSED*/ 5190Sstevel@tonic-gate static void 5200Sstevel@tonic-gate fatal_signal(int signo) 5210Sstevel@tonic-gate { 5220Sstevel@tonic-gate siglongjmp(jumpbuf, 1); 5230Sstevel@tonic-gate } 5240Sstevel@tonic-gate 5250Sstevel@tonic-gate static int 5260Sstevel@tonic-gate print_frame(void *cd, prgregset_t gregs, uint_t argc, const long *argv) 5270Sstevel@tonic-gate { 5280Sstevel@tonic-gate pstack_handle_t *h = cd; 5290Sstevel@tonic-gate struct ps_prochandle *Pr = h->proc; 5300Sstevel@tonic-gate uintptr_t pc = gregs[R_PC]; 5310Sstevel@tonic-gate char buff[255]; 5320Sstevel@tonic-gate GElf_Sym sym; 5330Sstevel@tonic-gate uintptr_t start; 5340Sstevel@tonic-gate int length = (is64? 16 : 8); 5350Sstevel@tonic-gate int i; 5360Sstevel@tonic-gate 5370Sstevel@tonic-gate /* 5380Sstevel@tonic-gate * If we are in a system call, we display the entry frame in a more 5390Sstevel@tonic-gate * readable manner, using the name of the system call. In this case, we 5400Sstevel@tonic-gate * want to ignore this first frame, since we already displayed it 5410Sstevel@tonic-gate * separately. 5420Sstevel@tonic-gate */ 5430Sstevel@tonic-gate if (h->ignore_frame) { 5440Sstevel@tonic-gate h->ignore_frame = 0; 5450Sstevel@tonic-gate return (0); 5460Sstevel@tonic-gate } 5470Sstevel@tonic-gate 5480Sstevel@tonic-gate (void) sprintf(buff, "%.*lx", length, (long)pc); 5490Sstevel@tonic-gate (void) strcpy(buff + length, " ????????"); 5500Sstevel@tonic-gate if (Plookup_by_addr(Pr, pc, 5510Sstevel@tonic-gate buff + 1 + length, sizeof (buff) - 1 - length, &sym) == 0) { 5520Sstevel@tonic-gate start = sym.st_value; 5530Sstevel@tonic-gate } else if (h->jvm != NULL) { 5540Sstevel@tonic-gate int ret; 5550Sstevel@tonic-gate void (*segv)(int), (*bus)(int), (*ill)(int); 5560Sstevel@tonic-gate 5570Sstevel@tonic-gate segv = signal(SIGSEGV, fatal_signal); 5580Sstevel@tonic-gate bus = signal(SIGBUS, fatal_signal); 5590Sstevel@tonic-gate ill = signal(SIGILL, fatal_signal); 5600Sstevel@tonic-gate 5610Sstevel@tonic-gate /* Insure against a bad libjvm_db */ 5620Sstevel@tonic-gate if (sigsetjmp(jumpbuf, 0) == 0) 5630Sstevel@tonic-gate ret = j_frame_iter(h->jvm, gregs, print_java_frame, 5640Sstevel@tonic-gate NULL); 5650Sstevel@tonic-gate else 5660Sstevel@tonic-gate ret = -1; 5670Sstevel@tonic-gate 5680Sstevel@tonic-gate (void) signal(SIGSEGV, segv); 5690Sstevel@tonic-gate (void) signal(SIGBUS, bus); 5700Sstevel@tonic-gate (void) signal(SIGILL, ill); 5710Sstevel@tonic-gate 5720Sstevel@tonic-gate if (ret == 0) 5730Sstevel@tonic-gate return (ret); 5740Sstevel@tonic-gate } else { 5750Sstevel@tonic-gate start = pc; 5760Sstevel@tonic-gate } 5770Sstevel@tonic-gate 5780Sstevel@tonic-gate (void) printf(" %-17s (", buff); 5790Sstevel@tonic-gate for (i = 0; i < argc && i < MAX_ARGS; i++) 5807675SEdward.Pilatowicz@Sun.COM (void) printf((i+1 == argc) ? "%lx" : "%lx, ", argv[i]); 5810Sstevel@tonic-gate if (i != argc) 5820Sstevel@tonic-gate (void) printf("..."); 5837675SEdward.Pilatowicz@Sun.COM (void) printf((start != pc) ? ") + %lx\n" : ")\n", (long)(pc - start)); 5840Sstevel@tonic-gate 585*11946Sjohansen@sun.com if (h->pydb != NULL && argc > 0) { 586*11946Sjohansen@sun.com char buf_py[1024]; 587*11946Sjohansen@sun.com int rc; 588*11946Sjohansen@sun.com 589*11946Sjohansen@sun.com rc = pydb_pc_frameinfo(h->pydb, pc, argv[0], buf_py, 590*11946Sjohansen@sun.com sizeof (buf_py)); 591*11946Sjohansen@sun.com if (rc == 0) { 592*11946Sjohansen@sun.com (void) printf(" %s", buf_py); 593*11946Sjohansen@sun.com } 594*11946Sjohansen@sun.com } 595*11946Sjohansen@sun.com 5960Sstevel@tonic-gate /* 5970Sstevel@tonic-gate * If the frame's pc is in the "sigh" (a.k.a. signal handler, signal 5980Sstevel@tonic-gate * hack, or *sigh* ...) range, then we're about to cross a signal 5990Sstevel@tonic-gate * frame. The signal number is the first argument to this function. 6000Sstevel@tonic-gate */ 6010Sstevel@tonic-gate if (pc - sigh.st_value < sigh.st_size) { 6020Sstevel@tonic-gate if (sig2str((int)argv[0], buff) == -1) 6030Sstevel@tonic-gate (void) strcpy(buff, " Unknown"); 6040Sstevel@tonic-gate (void) printf(" --- called from signal handler with " 6050Sstevel@tonic-gate "signal %d (SIG%s) ---\n", (int)argv[0], buff); 6060Sstevel@tonic-gate } 6070Sstevel@tonic-gate 6080Sstevel@tonic-gate return (0); 6090Sstevel@tonic-gate } 6100Sstevel@tonic-gate 6110Sstevel@tonic-gate static void 6120Sstevel@tonic-gate print_zombie(struct ps_prochandle *Pr, struct threadinfo *tip) 6130Sstevel@tonic-gate { 6140Sstevel@tonic-gate char buff[255]; 6150Sstevel@tonic-gate GElf_Sym sym; 6160Sstevel@tonic-gate uintptr_t start; 6170Sstevel@tonic-gate int length = (is64? 16 : 8); 6180Sstevel@tonic-gate 6190Sstevel@tonic-gate (void) sprintf(buff, "%.*lx", length, (long)tip->startfunc); 6200Sstevel@tonic-gate (void) strcpy(buff + length, " ????????"); 6210Sstevel@tonic-gate if (Plookup_by_addr(Pr, tip->startfunc, 6220Sstevel@tonic-gate buff + 1 + length, sizeof (buff) - 1 - length, &sym) == 0) 6230Sstevel@tonic-gate start = sym.st_value; 6240Sstevel@tonic-gate else 6250Sstevel@tonic-gate start = tip->startfunc; 6260Sstevel@tonic-gate (void) printf(" %s()", buff); 6270Sstevel@tonic-gate if (start != tip->startfunc) /* doesn't happen? */ 6280Sstevel@tonic-gate (void) printf("+%lx", (long)(tip->startfunc - start)); 6290Sstevel@tonic-gate (void) printf(", exit value = 0x%.*lx\n", length, (long)tip->exitval); 6300Sstevel@tonic-gate (void) printf("\t** zombie " 6317675SEdward.Pilatowicz@Sun.COM "(exited, not detached, not yet joined) **\n"); 6320Sstevel@tonic-gate } 6330Sstevel@tonic-gate 6340Sstevel@tonic-gate static void 6350Sstevel@tonic-gate print_syscall(const lwpstatus_t *psp, prgregset_t reg) 6360Sstevel@tonic-gate { 6370Sstevel@tonic-gate char sname[32]; 6380Sstevel@tonic-gate int length = (is64? 16 : 8); 6390Sstevel@tonic-gate uint_t i; 6400Sstevel@tonic-gate 6410Sstevel@tonic-gate (void) proc_sysname(psp->pr_syscall, sname, sizeof (sname)); 6420Sstevel@tonic-gate (void) printf(" %.*lx %-8s (", length, (long)reg[R_PC], sname); 6430Sstevel@tonic-gate for (i = 0; i < psp->pr_nsysarg; i++) 6440Sstevel@tonic-gate (void) printf((i+1 == psp->pr_nsysarg)? "%lx" : "%lx, ", 6457675SEdward.Pilatowicz@Sun.COM (long)psp->pr_sysarg[i]); 6460Sstevel@tonic-gate (void) printf(")\n"); 6470Sstevel@tonic-gate } 6480Sstevel@tonic-gate 6490Sstevel@tonic-gate static void 6500Sstevel@tonic-gate call_stack(pstack_handle_t *h, const lwpstatus_t *psp) 6510Sstevel@tonic-gate { 6520Sstevel@tonic-gate prgregset_t reg; 6530Sstevel@tonic-gate 6540Sstevel@tonic-gate (void) memcpy(reg, psp->pr_reg, sizeof (reg)); 6550Sstevel@tonic-gate 6560Sstevel@tonic-gate if ((psp->pr_flags & (PR_ASLEEP|PR_VFORKP)) || 6570Sstevel@tonic-gate ((psp->pr_flags & PR_ISTOP) && 6580Sstevel@tonic-gate (psp->pr_why == PR_SYSENTRY || 6590Sstevel@tonic-gate psp->pr_why == PR_SYSEXIT))) { 6600Sstevel@tonic-gate print_syscall(psp, reg); 6610Sstevel@tonic-gate h->ignore_frame = 1; 6620Sstevel@tonic-gate } else { 6630Sstevel@tonic-gate h->ignore_frame = 0; 6640Sstevel@tonic-gate } 6650Sstevel@tonic-gate 6660Sstevel@tonic-gate (void) Pstack_iter(h->proc, reg, print_frame, h); 6670Sstevel@tonic-gate } 6680Sstevel@tonic-gate 6690Sstevel@tonic-gate /*ARGSUSED*/ 6700Sstevel@tonic-gate static int 6710Sstevel@tonic-gate jvm_object_iter(void *cd, const prmap_t *pmp, const char *obj) 6720Sstevel@tonic-gate { 6730Sstevel@tonic-gate char path[PATH_MAX]; 6740Sstevel@tonic-gate char *name; 6750Sstevel@tonic-gate char *s1, *s2; 6760Sstevel@tonic-gate struct ps_prochandle *Pr = cd; 6770Sstevel@tonic-gate 6780Sstevel@tonic-gate if ((name = strstr(obj, "/libjvm.so")) == NULL) 6790Sstevel@tonic-gate name = strstr(obj, "/libjvm_g.so"); 6800Sstevel@tonic-gate 6810Sstevel@tonic-gate if (name) { 6820Sstevel@tonic-gate (void) strcpy(path, obj); 6830Sstevel@tonic-gate if (Pstatus(Pr)->pr_dmodel != PR_MODEL_NATIVE) { 6840Sstevel@tonic-gate s1 = name; 6850Sstevel@tonic-gate s2 = path + (s1 - obj); 6860Sstevel@tonic-gate (void) strcpy(s2, "/64"); 6870Sstevel@tonic-gate s2 += 3; 6880Sstevel@tonic-gate (void) strcpy(s2, s1); 6890Sstevel@tonic-gate } 6900Sstevel@tonic-gate 6910Sstevel@tonic-gate s1 = strstr(obj, ".so"); 6920Sstevel@tonic-gate s2 = strstr(path, ".so"); 6930Sstevel@tonic-gate (void) strcpy(s2, "_db"); 6940Sstevel@tonic-gate s2 += 3; 6950Sstevel@tonic-gate (void) strcpy(s2, s1); 6960Sstevel@tonic-gate 6970Sstevel@tonic-gate if ((libjvm = dlopen(path, RTLD_LAZY|RTLD_GLOBAL)) != NULL) 6980Sstevel@tonic-gate return (1); 6990Sstevel@tonic-gate } 7000Sstevel@tonic-gate 7010Sstevel@tonic-gate return (0); 7020Sstevel@tonic-gate } 7030Sstevel@tonic-gate 7040Sstevel@tonic-gate static jvm_agent_t * 7050Sstevel@tonic-gate load_libjvm(struct ps_prochandle *Pr) 7060Sstevel@tonic-gate { 7070Sstevel@tonic-gate jvm_agent_t *ret; 7080Sstevel@tonic-gate 7097675SEdward.Pilatowicz@Sun.COM /* 7107675SEdward.Pilatowicz@Sun.COM * Iterate through all the loaded objects in the target, looking 7117675SEdward.Pilatowicz@Sun.COM * for libjvm.so. If we find libjvm.so we'll try to load the 7127675SEdward.Pilatowicz@Sun.COM * corresponding libjvm_db.so that lives in the same directory. 7137675SEdward.Pilatowicz@Sun.COM * 7147675SEdward.Pilatowicz@Sun.COM * At first glance it seems like we'd want to use 7157675SEdward.Pilatowicz@Sun.COM * Pobject_iter_resolved() here since we'd want to make sure that 7167675SEdward.Pilatowicz@Sun.COM * we have the full path to the libjvm.so. But really, we don't 7177675SEdward.Pilatowicz@Sun.COM * want that since we're going to be dlopen()ing a library and 7187675SEdward.Pilatowicz@Sun.COM * executing code from that path, and therefore we don't want to 7197675SEdward.Pilatowicz@Sun.COM * load any library code that could be from a zone since it could 7207675SEdward.Pilatowicz@Sun.COM * have been replaced with a trojan. Hence, we use Pobject_iter(). 7217675SEdward.Pilatowicz@Sun.COM * So if we're debugging java processes in a zone from the global 7227675SEdward.Pilatowicz@Sun.COM * zone, and we want to get proper java stack stack frames, then 7237675SEdward.Pilatowicz@Sun.COM * the same jvm that is running within the zone needs to be 7247675SEdward.Pilatowicz@Sun.COM * installed in the global zone. 7257675SEdward.Pilatowicz@Sun.COM */ 7260Sstevel@tonic-gate (void) Pobject_iter(Pr, jvm_object_iter, Pr); 7270Sstevel@tonic-gate 7280Sstevel@tonic-gate if (libjvm) { 7290Sstevel@tonic-gate j_agent_create = (j_agent_create_f) 7300Sstevel@tonic-gate dlsym(libjvm, "Jagent_create"); 7310Sstevel@tonic-gate j_agent_destroy = (j_agent_destroy_f) 7320Sstevel@tonic-gate dlsym(libjvm, "Jagent_destroy"); 7330Sstevel@tonic-gate j_frame_iter = (j_frame_iter_f) 7340Sstevel@tonic-gate dlsym(libjvm, "Jframe_iter"); 7350Sstevel@tonic-gate 7360Sstevel@tonic-gate if (j_agent_create == NULL || j_agent_destroy == NULL || 7370Sstevel@tonic-gate j_frame_iter == NULL || 7380Sstevel@tonic-gate (ret = j_agent_create(Pr, JVM_DB_VERSION)) == NULL) { 7390Sstevel@tonic-gate reset_libjvm(NULL); 7400Sstevel@tonic-gate return (NULL); 7410Sstevel@tonic-gate } 7420Sstevel@tonic-gate 7430Sstevel@tonic-gate return (ret); 7440Sstevel@tonic-gate } 7450Sstevel@tonic-gate 7460Sstevel@tonic-gate return (NULL); 7470Sstevel@tonic-gate } 7480Sstevel@tonic-gate 7490Sstevel@tonic-gate static void 7500Sstevel@tonic-gate reset_libjvm(jvm_agent_t *agent) 7510Sstevel@tonic-gate { 7520Sstevel@tonic-gate if (libjvm) { 7530Sstevel@tonic-gate if (agent) 7540Sstevel@tonic-gate j_agent_destroy(agent); 7550Sstevel@tonic-gate 7560Sstevel@tonic-gate (void) dlclose(libjvm); 7570Sstevel@tonic-gate } 7580Sstevel@tonic-gate 7590Sstevel@tonic-gate j_agent_create = NULL; 7600Sstevel@tonic-gate j_agent_destroy = NULL; 7610Sstevel@tonic-gate j_frame_iter = NULL; 7620Sstevel@tonic-gate libjvm = NULL; 7630Sstevel@tonic-gate } 764*11946Sjohansen@sun.com 765*11946Sjohansen@sun.com /*ARGSUSED*/ 766*11946Sjohansen@sun.com static int 767*11946Sjohansen@sun.com python_object_iter(void *cd, const prmap_t *pmp, const char *obj) 768*11946Sjohansen@sun.com { 769*11946Sjohansen@sun.com char path[PATH_MAX]; 770*11946Sjohansen@sun.com char *name; 771*11946Sjohansen@sun.com char *s1, *s2; 772*11946Sjohansen@sun.com struct ps_prochandle *Pr = cd; 773*11946Sjohansen@sun.com 774*11946Sjohansen@sun.com name = strstr(obj, "/libpython"); 775*11946Sjohansen@sun.com 776*11946Sjohansen@sun.com if (name) { 777*11946Sjohansen@sun.com (void) strcpy(path, obj); 778*11946Sjohansen@sun.com if (Pstatus(Pr)->pr_dmodel != PR_MODEL_NATIVE) { 779*11946Sjohansen@sun.com s1 = name; 780*11946Sjohansen@sun.com s2 = path + (s1 - obj); 781*11946Sjohansen@sun.com (void) strcpy(s2, "/64"); 782*11946Sjohansen@sun.com s2 += 3; 783*11946Sjohansen@sun.com (void) strcpy(s2, s1); 784*11946Sjohansen@sun.com } 785*11946Sjohansen@sun.com 786*11946Sjohansen@sun.com s1 = strstr(obj, ".so"); 787*11946Sjohansen@sun.com s2 = strstr(path, ".so"); 788*11946Sjohansen@sun.com (void) strcpy(s2, "_db"); 789*11946Sjohansen@sun.com s2 += 3; 790*11946Sjohansen@sun.com (void) strcpy(s2, s1); 791*11946Sjohansen@sun.com 792*11946Sjohansen@sun.com if ((libpython = dlopen(path, RTLD_LAZY|RTLD_GLOBAL)) != NULL) 793*11946Sjohansen@sun.com return (1); 794*11946Sjohansen@sun.com } 795*11946Sjohansen@sun.com 796*11946Sjohansen@sun.com return (0); 797*11946Sjohansen@sun.com } 798*11946Sjohansen@sun.com 799*11946Sjohansen@sun.com static pydb_agent_t * 800*11946Sjohansen@sun.com load_libpython(struct ps_prochandle *Pr) 801*11946Sjohansen@sun.com { 802*11946Sjohansen@sun.com pydb_agent_t *pdb; 803*11946Sjohansen@sun.com 804*11946Sjohansen@sun.com (void) Pobject_iter(Pr, python_object_iter, Pr); 805*11946Sjohansen@sun.com 806*11946Sjohansen@sun.com if (libpython) { 807*11946Sjohansen@sun.com pydb_agent_create = (pydb_agent_create_f) 808*11946Sjohansen@sun.com dlsym(libpython, "pydb_agent_create"); 809*11946Sjohansen@sun.com pydb_agent_destroy = (pydb_agent_destroy_f) 810*11946Sjohansen@sun.com dlsym(libpython, "pydb_agent_destroy"); 811*11946Sjohansen@sun.com pydb_pc_frameinfo = (pydb_pc_frameinfo_f) 812*11946Sjohansen@sun.com dlsym(libpython, "pydb_pc_frameinfo"); 813*11946Sjohansen@sun.com 814*11946Sjohansen@sun.com if (pydb_agent_create == NULL || pydb_agent_destroy == NULL || 815*11946Sjohansen@sun.com pydb_pc_frameinfo == NULL) { 816*11946Sjohansen@sun.com (void) dlclose(libpython); 817*11946Sjohansen@sun.com libpython = NULL; 818*11946Sjohansen@sun.com return (NULL); 819*11946Sjohansen@sun.com } 820*11946Sjohansen@sun.com 821*11946Sjohansen@sun.com pdb = pydb_agent_create(Pr, PYDB_VERSION); 822*11946Sjohansen@sun.com if (pdb == NULL) { 823*11946Sjohansen@sun.com (void) dlclose(libpython); 824*11946Sjohansen@sun.com libpython = NULL; 825*11946Sjohansen@sun.com return (NULL); 826*11946Sjohansen@sun.com } 827*11946Sjohansen@sun.com return (pdb); 828*11946Sjohansen@sun.com } 829*11946Sjohansen@sun.com 830*11946Sjohansen@sun.com return (NULL); 831*11946Sjohansen@sun.com } 832*11946Sjohansen@sun.com 833*11946Sjohansen@sun.com static void 834*11946Sjohansen@sun.com reset_libpython(pydb_agent_t *pdb) 835*11946Sjohansen@sun.com { 836*11946Sjohansen@sun.com if (libpython != NULL) { 837*11946Sjohansen@sun.com if (pdb != NULL) { 838*11946Sjohansen@sun.com pydb_agent_destroy(pdb); 839*11946Sjohansen@sun.com } 840*11946Sjohansen@sun.com (void) dlclose(libpython); 841*11946Sjohansen@sun.com } 842*11946Sjohansen@sun.com 843*11946Sjohansen@sun.com libpython = NULL; 844*11946Sjohansen@sun.com pydb_agent_create = NULL; 845*11946Sjohansen@sun.com pydb_agent_destroy = NULL; 846*11946Sjohansen@sun.com pydb_pc_frameinfo = NULL; 847*11946Sjohansen@sun.com } 848