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