1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/isa_defs.h> 27 28 #include <stdio.h> 29 #include <stdio_ext.h> 30 #include <fcntl.h> 31 #include <ctype.h> 32 #include <string.h> 33 #include <signal.h> 34 #include <dirent.h> 35 #include <errno.h> 36 #include <stdlib.h> 37 #include <stdarg.h> 38 #include <unistd.h> 39 #include <sys/types.h> 40 #include <sys/stat.h> 41 #include <sys/stack.h> 42 #include <link.h> 43 #include <limits.h> 44 #include <libelf.h> 45 #include <thread_db.h> 46 #include <libproc.h> 47 #include <setjmp.h> 48 49 static char *command; 50 static int Fflag; 51 static int is64; 52 static GElf_Sym sigh; 53 54 /* 55 * To keep the list of user-level threads for a multithreaded process. 56 */ 57 struct threadinfo { 58 struct threadinfo *next; 59 id_t threadid; 60 id_t lwpid; 61 td_thr_state_e state; 62 uintptr_t startfunc; 63 uintptr_t exitval; 64 prgregset_t regs; 65 }; 66 67 static struct threadinfo *thr_head, *thr_tail; 68 69 #define TRUE 1 70 #define FALSE 0 71 72 #define MAX_ARGS 8 73 74 /* 75 * To support debugging java programs, we display java frames within a stack. 76 * The logic to walk the java frames is contained in libjvm_db.so, which is 77 * found in the same directory as libjvm.so, linked with the program. If we are 78 * debugging a 32-bit app with a 64-binary, then the debugging library is found 79 * in the '64' subdirectory. If we find libjvm_db.so, then we fill in these 80 * stub routines. 81 */ 82 typedef struct jvm_agent jvm_agent_t; 83 typedef int java_stack_f(void *, prgregset_t, const char *, int, int, void *); 84 85 /* 86 * The j_agent_create function takes a version parameter. This ensures that the 87 * interface can evolve appropriately. 88 */ 89 #define JVM_DB_VERSION 1 90 static void *libjvm; 91 typedef jvm_agent_t *(*j_agent_create_f)(struct ps_prochandle *, int); 92 typedef void (*j_agent_destroy_f)(jvm_agent_t *); 93 typedef int (*j_frame_iter_f)(jvm_agent_t *, prgregset_t, java_stack_f *, 94 void *); 95 96 static j_agent_create_f j_agent_create; 97 static j_agent_destroy_f j_agent_destroy; 98 static j_frame_iter_f j_frame_iter; 99 100 static jvm_agent_t *load_libjvm(struct ps_prochandle *P); 101 static void reset_libjvm(jvm_agent_t *); 102 103 /* 104 * Similar to what's done for debugging java programs, here are prototypes for 105 * the library that allows us to debug Python programs. 106 */ 107 #define PYDB_VERSION 1 108 static void *libpython; 109 110 typedef struct pydb_agent pydb_agent_t; 111 112 typedef pydb_agent_t *(*pydb_agent_create_f)(struct ps_prochandle *P, int vers); 113 typedef void (*pydb_agent_destroy_f)(pydb_agent_t *py); 114 typedef int (*pydb_pc_frameinfo_f)(pydb_agent_t *py, uintptr_t pc, 115 uintptr_t frame_addr, char *fbuf, size_t bufsz); 116 117 static pydb_agent_create_f pydb_agent_create; 118 static pydb_agent_destroy_f pydb_agent_destroy; 119 static pydb_pc_frameinfo_f pydb_pc_frameinfo; 120 121 static pydb_agent_t *load_libpython(struct ps_prochandle *P); 122 static void reset_libpython(pydb_agent_t *); 123 /* 124 * Since we must maintain both a proc handle and a jvm handle, this structure 125 * is the basic type that gets passed around. 126 */ 127 typedef struct pstack_handle { 128 struct ps_prochandle *proc; 129 jvm_agent_t *jvm; 130 int ignore_frame; 131 const char *lwps; 132 int count; 133 pydb_agent_t *pydb; 134 } pstack_handle_t; 135 136 static int thr_stack(const td_thrhandle_t *, void *); 137 static void free_threadinfo(void); 138 static struct threadinfo *find_thread(id_t); 139 static int all_call_stacks(pstack_handle_t *, int); 140 static void tlhead(id_t, id_t); 141 static int print_frame(void *, prgregset_t, uint_t, const long *); 142 static void print_zombie(struct ps_prochandle *, struct threadinfo *); 143 static void print_syscall(const lwpstatus_t *, prgregset_t); 144 static void call_stack(pstack_handle_t *, const lwpstatus_t *); 145 146 /* 147 * The number of active and zombie threads. 148 */ 149 static int nthreads; 150 151 int 152 main(int argc, char **argv) 153 { 154 int retc = 0; 155 int opt; 156 int errflg = FALSE; 157 core_content_t content = CC_CONTENT_DATA | CC_CONTENT_ANON | 158 CC_CONTENT_STACK; 159 struct rlimit rlim; 160 161 if ((command = strrchr(argv[0], '/')) != NULL) 162 command++; 163 else 164 command = argv[0]; 165 166 /* options */ 167 while ((opt = getopt(argc, argv, "F")) != EOF) { 168 switch (opt) { 169 case 'F': 170 /* 171 * If the user specifies the force option, we'll 172 * consent to printing out other threads' stacks 173 * even if the main stack is absent. 174 */ 175 content &= ~CC_CONTENT_STACK; 176 Fflag = PGRAB_FORCE; 177 break; 178 default: 179 errflg = TRUE; 180 break; 181 } 182 } 183 184 argc -= optind; 185 argv += optind; 186 187 if (errflg || argc <= 0) { 188 (void) fprintf(stderr, 189 "usage:\t%s [-F] { pid | core }[/lwps] ...\n", command); 190 (void) fprintf(stderr, " (show process call stack)\n"); 191 (void) fprintf(stderr, 192 " -F: force grabbing of the target process\n"); 193 exit(2); 194 } 195 196 /* 197 * Make sure we'll have enough file descriptors to handle a target 198 * that has many many mappings. 199 */ 200 if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) { 201 rlim.rlim_cur = rlim.rlim_max; 202 (void) setrlimit(RLIMIT_NOFILE, &rlim); 203 (void) enable_extended_FILE_stdio(-1, -1); 204 } 205 206 (void) proc_initstdio(); 207 208 while (--argc >= 0) { 209 int gcode; 210 psinfo_t psinfo; 211 const psinfo_t *tpsinfo; 212 struct ps_prochandle *Pr = NULL; 213 td_thragent_t *Tap; 214 int threaded; 215 pstack_handle_t handle; 216 const char *lwps, *arg; 217 218 (void) proc_flushstdio(); 219 220 arg = *argv++; 221 222 if ((Pr = proc_arg_xgrab(arg, NULL, PR_ARG_ANY, 223 Fflag, &gcode, &lwps)) == NULL) { 224 (void) fprintf(stderr, "%s: cannot examine %s: %s\n", 225 command, arg, Pgrab_error(gcode)); 226 retc++; 227 continue; 228 } 229 230 if ((tpsinfo = Ppsinfo(Pr)) == NULL) { 231 (void) fprintf(stderr, "%s: cannot examine %s: " 232 "lost control of process\n", command, arg); 233 Prelease(Pr, 0); 234 retc++; 235 continue; 236 } 237 (void) memcpy(&psinfo, tpsinfo, sizeof (psinfo_t)); 238 proc_unctrl_psinfo(&psinfo); 239 240 if (Pstate(Pr) == PS_DEAD) { 241 if ((Pcontent(Pr) & content) != content) { 242 (void) fprintf(stderr, "%s: core '%s' has " 243 "insufficient content\n", command, arg); 244 retc++; 245 continue; 246 } 247 (void) printf("core '%s' of %d:\t%.70s\n", 248 arg, (int)psinfo.pr_pid, psinfo.pr_psargs); 249 } else { 250 (void) printf("%d:\t%.70s\n", 251 (int)psinfo.pr_pid, psinfo.pr_psargs); 252 } 253 254 is64 = (psinfo.pr_dmodel == PR_MODEL_LP64); 255 256 if (Pgetauxval(Pr, AT_BASE) != -1L && Prd_agent(Pr) == NULL) { 257 (void) fprintf(stderr, "%s: warning: librtld_db failed " 258 "to initialize; symbols from shared libraries will " 259 "not be available\n", command); 260 } 261 262 /* 263 * First we need to get a thread agent handle. 264 */ 265 if (td_init() != TD_OK || 266 td_ta_new(Pr, &Tap) != TD_OK) /* no libc */ 267 threaded = FALSE; 268 else { 269 /* 270 * Iterate over all threads, calling: 271 * thr_stack(td_thrhandle_t *Thp, NULL); 272 * for each one to generate the list of threads. 273 */ 274 nthreads = 0; 275 (void) td_ta_thr_iter(Tap, thr_stack, NULL, 276 TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY, 277 TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS); 278 279 (void) td_ta_delete(Tap); 280 threaded = TRUE; 281 } 282 283 handle.proc = Pr; 284 handle.jvm = load_libjvm(Pr); 285 handle.pydb = load_libpython(Pr); 286 handle.lwps = lwps; 287 handle.count = 0; 288 289 if (all_call_stacks(&handle, threaded) != 0) 290 retc++; 291 if (threaded) 292 free_threadinfo(); 293 294 reset_libjvm(handle.jvm); 295 reset_libpython(handle.pydb); 296 Prelease(Pr, 0); 297 298 if (handle.count == 0) 299 (void) fprintf(stderr, "%s: no matching LWPs found\n", 300 command); 301 } 302 303 (void) proc_finistdio(); 304 305 return (retc); 306 } 307 308 /* 309 * Thread iteration call-back function. 310 * Called once for each user-level thread. 311 * Used to build the list of all threads. 312 */ 313 /* ARGSUSED1 */ 314 static int 315 thr_stack(const td_thrhandle_t *Thp, void *cd) 316 { 317 td_thrinfo_t thrinfo; 318 struct threadinfo *tip; 319 td_err_e error; 320 321 if (td_thr_get_info(Thp, &thrinfo) != TD_OK) 322 return (0); 323 324 tip = malloc(sizeof (struct threadinfo)); 325 tip->next = NULL; 326 tip->threadid = thrinfo.ti_tid; 327 tip->lwpid = thrinfo.ti_lid; 328 tip->state = thrinfo.ti_state; 329 tip->startfunc = thrinfo.ti_startfunc; 330 tip->exitval = (uintptr_t)thrinfo.ti_exitval; 331 nthreads++; 332 333 if (thrinfo.ti_state == TD_THR_ZOMBIE || 334 ((error = td_thr_getgregs(Thp, tip->regs)) != TD_OK && 335 error != TD_PARTIALREG)) 336 (void) memset(tip->regs, 0, sizeof (prgregset_t)); 337 338 if (thr_tail) 339 thr_tail->next = tip; 340 else 341 thr_head = tip; 342 thr_tail = tip; 343 344 return (0); 345 } 346 347 static void 348 free_threadinfo() 349 { 350 struct threadinfo *tip = thr_head; 351 struct threadinfo *next; 352 353 while (tip) { 354 next = tip->next; 355 free(tip); 356 tip = next; 357 } 358 359 thr_head = thr_tail = NULL; 360 } 361 362 /* 363 * Find and eliminate the thread corresponding to the given lwpid. 364 */ 365 static struct threadinfo * 366 find_thread(id_t lwpid) 367 { 368 struct threadinfo *tip; 369 370 for (tip = thr_head; tip; tip = tip->next) { 371 if (lwpid == tip->lwpid) { 372 tip->lwpid = 0; 373 return (tip); 374 } 375 } 376 return (NULL); 377 } 378 379 static int 380 thread_call_stack(void *data, const lwpstatus_t *psp, 381 const lwpsinfo_t *pip) 382 { 383 pstack_handle_t *h = data; 384 lwpstatus_t lwpstatus; 385 struct threadinfo *tip; 386 387 if (!proc_lwp_in_set(h->lwps, pip->pr_lwpid)) 388 return (0); 389 h->count++; 390 391 if ((tip = find_thread(pip->pr_lwpid)) == NULL) 392 return (0); 393 394 tlhead(tip->threadid, pip->pr_lwpid); 395 tip->threadid = 0; /* finish eliminating tid */ 396 if (psp) 397 call_stack(h, psp); 398 else { 399 if (tip->state == TD_THR_ZOMBIE) 400 print_zombie(h->proc, tip); 401 else { 402 (void) memset(&lwpstatus, 0, sizeof (lwpstatus)); 403 (void) memcpy(lwpstatus.pr_reg, tip->regs, 404 sizeof (prgregset_t)); 405 call_stack(h, &lwpstatus); 406 } 407 } 408 return (0); 409 } 410 411 static int 412 lwp_call_stack(void *data, 413 const lwpstatus_t *psp, const lwpsinfo_t *pip) 414 { 415 pstack_handle_t *h = data; 416 417 if (!proc_lwp_in_set(h->lwps, pip->pr_lwpid)) 418 return (0); 419 h->count++; 420 421 tlhead(0, pip->pr_lwpid); 422 if (psp) 423 call_stack(h, psp); 424 else 425 (void) printf("\t** zombie " 426 "(exited, not detached, not yet joined) **\n"); 427 return (0); 428 } 429 430 static int 431 all_call_stacks(pstack_handle_t *h, int dothreads) 432 { 433 struct ps_prochandle *Pr = h->proc; 434 pstatus_t status = *Pstatus(Pr); 435 436 (void) memset(&sigh, 0, sizeof (GElf_Sym)); 437 (void) Plookup_by_name(Pr, "libc.so", "sigacthandler", &sigh); 438 439 if ((status.pr_nlwp + status.pr_nzomb) <= 1 && 440 !(dothreads && nthreads > 1)) { 441 if (proc_lwp_in_set(h->lwps, status.pr_lwp.pr_lwpid)) { 442 call_stack(h, &status.pr_lwp); 443 h->count++; 444 } 445 } else { 446 lwpstatus_t lwpstatus; 447 struct threadinfo *tip; 448 id_t tid; 449 450 if (dothreads) 451 (void) Plwp_iter_all(Pr, thread_call_stack, h); 452 else 453 (void) Plwp_iter_all(Pr, lwp_call_stack, h); 454 455 /* for each remaining thread w/o an lwp */ 456 (void) memset(&lwpstatus, 0, sizeof (lwpstatus)); 457 for (tip = thr_head; tip; tip = tip->next) { 458 459 if (!proc_lwp_in_set(h->lwps, tip->lwpid)) 460 tip->threadid = 0; 461 462 if ((tid = tip->threadid) != 0) { 463 (void) memcpy(lwpstatus.pr_reg, tip->regs, 464 sizeof (prgregset_t)); 465 tlhead(tid, tip->lwpid); 466 if (tip->state == TD_THR_ZOMBIE) 467 print_zombie(Pr, tip); 468 else 469 call_stack(h, &lwpstatus); 470 } 471 tip->threadid = 0; 472 tip->lwpid = 0; 473 } 474 } 475 return (0); 476 } 477 478 static void 479 tlhead(id_t threadid, id_t lwpid) 480 { 481 if (threadid == 0 && lwpid == 0) 482 return; 483 484 (void) printf("-----------------"); 485 486 if (threadid && lwpid) 487 (void) printf(" lwp# %d / thread# %d ", 488 (int)lwpid, (int)threadid); 489 else if (threadid) 490 (void) printf("--------- thread# %d ", (int)threadid); 491 else if (lwpid) 492 (void) printf(" lwp# %d ------------", (int)lwpid); 493 494 (void) printf("--------------------\n"); 495 } 496 497 /*ARGSUSED*/ 498 static int 499 print_java_frame(void *cld, prgregset_t gregs, const char *name, int bci, 500 int line, void *handle) 501 { 502 int length = (is64 ? 16 : 8); 503 504 (void) printf(" %.*lx * %s", length, (long)gregs[R_PC], name); 505 506 if (bci != -1) { 507 (void) printf("+%d", bci); 508 if (line) 509 (void) printf(" (line %d)", line); 510 } 511 (void) printf("\n"); 512 513 return (0); 514 } 515 516 static sigjmp_buf jumpbuf; 517 518 /*ARGSUSED*/ 519 static void 520 fatal_signal(int signo) 521 { 522 siglongjmp(jumpbuf, 1); 523 } 524 525 static int 526 print_frame(void *cd, prgregset_t gregs, uint_t argc, const long *argv) 527 { 528 pstack_handle_t *h = cd; 529 struct ps_prochandle *Pr = h->proc; 530 uintptr_t pc = gregs[R_PC]; 531 char buff[255]; 532 GElf_Sym sym; 533 uintptr_t start; 534 int length = (is64? 16 : 8); 535 int i; 536 537 /* 538 * If we are in a system call, we display the entry frame in a more 539 * readable manner, using the name of the system call. In this case, we 540 * want to ignore this first frame, since we already displayed it 541 * separately. 542 */ 543 if (h->ignore_frame) { 544 h->ignore_frame = 0; 545 return (0); 546 } 547 548 (void) sprintf(buff, "%.*lx", length, (long)pc); 549 (void) strcpy(buff + length, " ????????"); 550 if (Plookup_by_addr(Pr, pc, 551 buff + 1 + length, sizeof (buff) - 1 - length, &sym) == 0) { 552 start = sym.st_value; 553 } else if (h->jvm != NULL) { 554 int ret; 555 void (*segv)(int), (*bus)(int), (*ill)(int); 556 557 segv = signal(SIGSEGV, fatal_signal); 558 bus = signal(SIGBUS, fatal_signal); 559 ill = signal(SIGILL, fatal_signal); 560 561 /* Insure against a bad libjvm_db */ 562 if (sigsetjmp(jumpbuf, 0) == 0) 563 ret = j_frame_iter(h->jvm, gregs, print_java_frame, 564 NULL); 565 else 566 ret = -1; 567 568 (void) signal(SIGSEGV, segv); 569 (void) signal(SIGBUS, bus); 570 (void) signal(SIGILL, ill); 571 572 if (ret == 0) 573 return (ret); 574 } else { 575 start = pc; 576 } 577 578 (void) printf(" %-17s (", buff); 579 for (i = 0; i < argc && i < MAX_ARGS; i++) 580 (void) printf((i+1 == argc) ? "%lx" : "%lx, ", argv[i]); 581 if (i != argc) 582 (void) printf("..."); 583 (void) printf((start != pc) ? ") + %lx\n" : ")\n", (long)(pc - start)); 584 585 if (h->pydb != NULL && argc > 0) { 586 char buf_py[1024]; 587 int rc; 588 589 rc = pydb_pc_frameinfo(h->pydb, pc, argv[0], buf_py, 590 sizeof (buf_py)); 591 if (rc == 0) { 592 (void) printf(" %s", buf_py); 593 } 594 } 595 596 /* 597 * If the frame's pc is in the "sigh" (a.k.a. signal handler, signal 598 * hack, or *sigh* ...) range, then we're about to cross a signal 599 * frame. The signal number is the first argument to this function. 600 */ 601 if (pc - sigh.st_value < sigh.st_size) { 602 if (sig2str((int)argv[0], buff) == -1) 603 (void) strcpy(buff, " Unknown"); 604 (void) printf(" --- called from signal handler with " 605 "signal %d (SIG%s) ---\n", (int)argv[0], buff); 606 } 607 608 return (0); 609 } 610 611 static void 612 print_zombie(struct ps_prochandle *Pr, struct threadinfo *tip) 613 { 614 char buff[255]; 615 GElf_Sym sym; 616 uintptr_t start; 617 int length = (is64? 16 : 8); 618 619 (void) sprintf(buff, "%.*lx", length, (long)tip->startfunc); 620 (void) strcpy(buff + length, " ????????"); 621 if (Plookup_by_addr(Pr, tip->startfunc, 622 buff + 1 + length, sizeof (buff) - 1 - length, &sym) == 0) 623 start = sym.st_value; 624 else 625 start = tip->startfunc; 626 (void) printf(" %s()", buff); 627 if (start != tip->startfunc) /* doesn't happen? */ 628 (void) printf("+%lx", (long)(tip->startfunc - start)); 629 (void) printf(", exit value = 0x%.*lx\n", length, (long)tip->exitval); 630 (void) printf("\t** zombie " 631 "(exited, not detached, not yet joined) **\n"); 632 } 633 634 static void 635 print_syscall(const lwpstatus_t *psp, prgregset_t reg) 636 { 637 char sname[32]; 638 int length = (is64? 16 : 8); 639 uint_t i; 640 641 (void) proc_sysname(psp->pr_syscall, sname, sizeof (sname)); 642 (void) printf(" %.*lx %-8s (", length, (long)reg[R_PC], sname); 643 for (i = 0; i < psp->pr_nsysarg; i++) 644 (void) printf((i+1 == psp->pr_nsysarg)? "%lx" : "%lx, ", 645 (long)psp->pr_sysarg[i]); 646 (void) printf(")\n"); 647 } 648 649 static void 650 call_stack(pstack_handle_t *h, const lwpstatus_t *psp) 651 { 652 prgregset_t reg; 653 654 (void) memcpy(reg, psp->pr_reg, sizeof (reg)); 655 656 if ((psp->pr_flags & (PR_ASLEEP|PR_VFORKP)) || 657 ((psp->pr_flags & PR_ISTOP) && 658 (psp->pr_why == PR_SYSENTRY || 659 psp->pr_why == PR_SYSEXIT))) { 660 print_syscall(psp, reg); 661 h->ignore_frame = 1; 662 } else { 663 h->ignore_frame = 0; 664 } 665 666 (void) Pstack_iter(h->proc, reg, print_frame, h); 667 } 668 669 /*ARGSUSED*/ 670 static int 671 jvm_object_iter(void *cd, const prmap_t *pmp, const char *obj) 672 { 673 char path[PATH_MAX]; 674 char *name; 675 char *s1, *s2; 676 struct ps_prochandle *Pr = cd; 677 678 if ((name = strstr(obj, "/libjvm.so")) == NULL) 679 name = strstr(obj, "/libjvm_g.so"); 680 681 if (name) { 682 (void) strcpy(path, obj); 683 if (Pstatus(Pr)->pr_dmodel != PR_MODEL_NATIVE) { 684 s1 = name; 685 s2 = path + (s1 - obj); 686 (void) strcpy(s2, "/64"); 687 s2 += 3; 688 (void) strcpy(s2, s1); 689 } 690 691 s1 = strstr(obj, ".so"); 692 s2 = strstr(path, ".so"); 693 (void) strcpy(s2, "_db"); 694 s2 += 3; 695 (void) strcpy(s2, s1); 696 697 if ((libjvm = dlopen(path, RTLD_LAZY|RTLD_GLOBAL)) != NULL) 698 return (1); 699 } 700 701 return (0); 702 } 703 704 static jvm_agent_t * 705 load_libjvm(struct ps_prochandle *Pr) 706 { 707 jvm_agent_t *ret; 708 709 /* 710 * Iterate through all the loaded objects in the target, looking 711 * for libjvm.so. If we find libjvm.so we'll try to load the 712 * corresponding libjvm_db.so that lives in the same directory. 713 * 714 * At first glance it seems like we'd want to use 715 * Pobject_iter_resolved() here since we'd want to make sure that 716 * we have the full path to the libjvm.so. But really, we don't 717 * want that since we're going to be dlopen()ing a library and 718 * executing code from that path, and therefore we don't want to 719 * load any library code that could be from a zone since it could 720 * have been replaced with a trojan. Hence, we use Pobject_iter(). 721 * So if we're debugging java processes in a zone from the global 722 * zone, and we want to get proper java stack stack frames, then 723 * the same jvm that is running within the zone needs to be 724 * installed in the global zone. 725 */ 726 (void) Pobject_iter(Pr, jvm_object_iter, Pr); 727 728 if (libjvm) { 729 j_agent_create = (j_agent_create_f) 730 dlsym(libjvm, "Jagent_create"); 731 j_agent_destroy = (j_agent_destroy_f) 732 dlsym(libjvm, "Jagent_destroy"); 733 j_frame_iter = (j_frame_iter_f) 734 dlsym(libjvm, "Jframe_iter"); 735 736 if (j_agent_create == NULL || j_agent_destroy == NULL || 737 j_frame_iter == NULL || 738 (ret = j_agent_create(Pr, JVM_DB_VERSION)) == NULL) { 739 reset_libjvm(NULL); 740 return (NULL); 741 } 742 743 return (ret); 744 } 745 746 return (NULL); 747 } 748 749 static void 750 reset_libjvm(jvm_agent_t *agent) 751 { 752 if (libjvm) { 753 if (agent) 754 j_agent_destroy(agent); 755 756 (void) dlclose(libjvm); 757 } 758 759 j_agent_create = NULL; 760 j_agent_destroy = NULL; 761 j_frame_iter = NULL; 762 libjvm = NULL; 763 } 764 765 /*ARGSUSED*/ 766 static int 767 python_object_iter(void *cd, const prmap_t *pmp, const char *obj) 768 { 769 char path[PATH_MAX]; 770 char *name; 771 char *s1, *s2; 772 struct ps_prochandle *Pr = cd; 773 774 name = strstr(obj, "/libpython"); 775 776 if (name) { 777 (void) strcpy(path, obj); 778 if (Pstatus(Pr)->pr_dmodel != PR_MODEL_NATIVE) { 779 s1 = name; 780 s2 = path + (s1 - obj); 781 (void) strcpy(s2, "/64"); 782 s2 += 3; 783 (void) strcpy(s2, s1); 784 } 785 786 s1 = strstr(obj, ".so"); 787 s2 = strstr(path, ".so"); 788 (void) strcpy(s2, "_db"); 789 s2 += 3; 790 (void) strcpy(s2, s1); 791 792 if ((libpython = dlopen(path, RTLD_LAZY|RTLD_GLOBAL)) != NULL) 793 return (1); 794 } 795 796 return (0); 797 } 798 799 static pydb_agent_t * 800 load_libpython(struct ps_prochandle *Pr) 801 { 802 pydb_agent_t *pdb; 803 804 (void) Pobject_iter(Pr, python_object_iter, Pr); 805 806 if (libpython) { 807 pydb_agent_create = (pydb_agent_create_f) 808 dlsym(libpython, "pydb_agent_create"); 809 pydb_agent_destroy = (pydb_agent_destroy_f) 810 dlsym(libpython, "pydb_agent_destroy"); 811 pydb_pc_frameinfo = (pydb_pc_frameinfo_f) 812 dlsym(libpython, "pydb_pc_frameinfo"); 813 814 if (pydb_agent_create == NULL || pydb_agent_destroy == NULL || 815 pydb_pc_frameinfo == NULL) { 816 (void) dlclose(libpython); 817 libpython = NULL; 818 return (NULL); 819 } 820 821 pdb = pydb_agent_create(Pr, PYDB_VERSION); 822 if (pdb == NULL) { 823 (void) dlclose(libpython); 824 libpython = NULL; 825 return (NULL); 826 } 827 return (pdb); 828 } 829 830 return (NULL); 831 } 832 833 static void 834 reset_libpython(pydb_agent_t *pdb) 835 { 836 if (libpython != NULL) { 837 if (pdb != NULL) { 838 pydb_agent_destroy(pdb); 839 } 840 (void) dlclose(libpython); 841 } 842 843 libpython = NULL; 844 pydb_agent_create = NULL; 845 pydb_agent_destroy = NULL; 846 pydb_pc_frameinfo = NULL; 847 }