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 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 230Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate #include <assert.h> 300Sstevel@tonic-gate #include <strings.h> 310Sstevel@tonic-gate #include <stdlib.h> 320Sstevel@tonic-gate #include <stdio.h> 330Sstevel@tonic-gate #include <errno.h> 340Sstevel@tonic-gate #include <ctype.h> 350Sstevel@tonic-gate #include <alloca.h> 360Sstevel@tonic-gate #include <libgen.h> 370Sstevel@tonic-gate #include <stddef.h> 380Sstevel@tonic-gate 390Sstevel@tonic-gate #include <dt_impl.h> 40*265Smws #include <dt_program.h> 410Sstevel@tonic-gate #include <dt_pid.h> 420Sstevel@tonic-gate #include <dt_string.h> 430Sstevel@tonic-gate 440Sstevel@tonic-gate typedef struct dt_pid_probe { 450Sstevel@tonic-gate dtrace_hdl_t *dpp_dtp; 460Sstevel@tonic-gate struct ps_prochandle *dpp_pr; 470Sstevel@tonic-gate const char *dpp_mod; 480Sstevel@tonic-gate char *dpp_func; 490Sstevel@tonic-gate const char *dpp_name; 500Sstevel@tonic-gate const char *dpp_obj; 510Sstevel@tonic-gate uintptr_t dpp_pc; 520Sstevel@tonic-gate size_t dpp_size; 530Sstevel@tonic-gate Lmid_t dpp_lmid; 540Sstevel@tonic-gate uint_t dpp_nmatches; 550Sstevel@tonic-gate uint64_t dpp_stret[4]; 560Sstevel@tonic-gate GElf_Sym dpp_last; 570Sstevel@tonic-gate uint_t dpp_last_taken; 580Sstevel@tonic-gate } dt_pid_probe_t; 590Sstevel@tonic-gate 600Sstevel@tonic-gate static void 610Sstevel@tonic-gate dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func) 620Sstevel@tonic-gate { 630Sstevel@tonic-gate fasttrap_probe_spec_t *ftp; 640Sstevel@tonic-gate uint64_t off; 650Sstevel@tonic-gate char *end; 660Sstevel@tonic-gate uint_t nmatches = 0; 670Sstevel@tonic-gate ulong_t sz; 680Sstevel@tonic-gate int glob, err; 690Sstevel@tonic-gate int isdash = strcmp("-", func) == 0; 700Sstevel@tonic-gate pid_t pid; 710Sstevel@tonic-gate 720Sstevel@tonic-gate pid = Pstatus(pp->dpp_pr)->pr_pid; 730Sstevel@tonic-gate 740Sstevel@tonic-gate dt_dprintf("creating probe pid%d:%s:%s:%s\n", (int)pid, pp->dpp_obj, 750Sstevel@tonic-gate func, pp->dpp_name); 760Sstevel@tonic-gate 770Sstevel@tonic-gate sz = sizeof (fasttrap_probe_spec_t) + (isdash ? 4 : 780Sstevel@tonic-gate (symp->st_size - 1) * sizeof (ftp->ftps_offs[0])); 790Sstevel@tonic-gate 800Sstevel@tonic-gate if (sz < 4000) { 810Sstevel@tonic-gate ftp = alloca(sz); 820Sstevel@tonic-gate sz = 0; 830Sstevel@tonic-gate } else if ((ftp = malloc(sz)) == NULL) { 840Sstevel@tonic-gate dt_dprintf("proc_per_sym: malloc(%lu) failed\n", sz); 850Sstevel@tonic-gate return; 860Sstevel@tonic-gate } 870Sstevel@tonic-gate 880Sstevel@tonic-gate ftp->ftps_pid = pid; 890Sstevel@tonic-gate (void) strncpy(ftp->ftps_func, func, sizeof (ftp->ftps_func)); 900Sstevel@tonic-gate 910Sstevel@tonic-gate if (pp->dpp_lmid == 0) { 920Sstevel@tonic-gate (void) strncpy(ftp->ftps_mod, pp->dpp_obj, 930Sstevel@tonic-gate sizeof (ftp->ftps_mod)); 940Sstevel@tonic-gate } else { 950Sstevel@tonic-gate (void) snprintf(ftp->ftps_mod, sizeof (ftp->ftps_mod), 960Sstevel@tonic-gate "LM%lx`%s", pp->dpp_lmid, pp->dpp_obj); 970Sstevel@tonic-gate } 980Sstevel@tonic-gate 990Sstevel@tonic-gate if (!isdash && gmatch("return", pp->dpp_name)) { 1000Sstevel@tonic-gate if (dt_pid_create_return_probe(pp->dpp_pr, pp->dpp_dtp, 1010Sstevel@tonic-gate ftp, symp, pp->dpp_stret) < 0) 1020Sstevel@tonic-gate goto create_err; 1030Sstevel@tonic-gate 1040Sstevel@tonic-gate nmatches++; 1050Sstevel@tonic-gate } 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate if (!isdash && gmatch("entry", pp->dpp_name)) { 1080Sstevel@tonic-gate if (dt_pid_create_entry_probe(pp->dpp_pr, pp->dpp_dtp, 1090Sstevel@tonic-gate ftp, symp) < 0) 1100Sstevel@tonic-gate goto create_err; 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate nmatches++; 1130Sstevel@tonic-gate } 1140Sstevel@tonic-gate 1150Sstevel@tonic-gate glob = strisglob(pp->dpp_name); 1160Sstevel@tonic-gate if (!glob && nmatches == 0) { 1170Sstevel@tonic-gate off = strtoull(pp->dpp_name, &end, 16); 1180Sstevel@tonic-gate if (*end != '\0') { 1190Sstevel@tonic-gate if (sz != 0) 1200Sstevel@tonic-gate free(ftp); 1210Sstevel@tonic-gate dt_proc_release(pp->dpp_dtp, pp->dpp_pr); 1220Sstevel@tonic-gate xyerror(D_PROC_NAME, "'%s' is an invalid probe name\n", 1230Sstevel@tonic-gate pp->dpp_name); 1240Sstevel@tonic-gate } 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate if (off >= symp->st_size) { 1270Sstevel@tonic-gate char buf[DTRACE_FUNCNAMELEN]; 1280Sstevel@tonic-gate /* 1290Sstevel@tonic-gate * We need to copy the function name to the stack 1300Sstevel@tonic-gate * because 'func' may be freed by virtue of calling 1310Sstevel@tonic-gate * dt_proc_release() on the libproc handle. 1320Sstevel@tonic-gate */ 1330Sstevel@tonic-gate (void) strncpy(buf, func, sizeof (buf)); 1340Sstevel@tonic-gate if (sz != 0) 1350Sstevel@tonic-gate free(ftp); 1360Sstevel@tonic-gate dt_proc_release(pp->dpp_dtp, pp->dpp_pr); 1370Sstevel@tonic-gate xyerror(D_PROC_OFF, "offset 0x%llx outside of " 1380Sstevel@tonic-gate "function '%s'\n", (u_longlong_t)off, buf); 1390Sstevel@tonic-gate } 1400Sstevel@tonic-gate 1410Sstevel@tonic-gate err = dt_pid_create_offset_probe(pp->dpp_pr, pp->dpp_dtp, ftp, 1420Sstevel@tonic-gate symp, off); 1430Sstevel@tonic-gate 1440Sstevel@tonic-gate if (err == DT_PROC_ERR) 1450Sstevel@tonic-gate goto create_err; 1460Sstevel@tonic-gate if (err == DT_PROC_ALIGN) { 1470Sstevel@tonic-gate if (sz != 0) 1480Sstevel@tonic-gate free(ftp); 1490Sstevel@tonic-gate dt_proc_release(pp->dpp_dtp, pp->dpp_pr); 1500Sstevel@tonic-gate xyerror(D_PROC_ALIGN, "offset 0x%llx is not aligned " 1510Sstevel@tonic-gate "on an instruction\n", (u_longlong_t)off); 1520Sstevel@tonic-gate } 1530Sstevel@tonic-gate 1540Sstevel@tonic-gate nmatches++; 1550Sstevel@tonic-gate 1560Sstevel@tonic-gate } else if (glob && !isdash) { 1570Sstevel@tonic-gate if (dt_pid_create_glob_offset_probes(pp->dpp_pr, 1580Sstevel@tonic-gate pp->dpp_dtp, ftp, symp, pp->dpp_name) < 0) 1590Sstevel@tonic-gate goto create_err; 1600Sstevel@tonic-gate 1610Sstevel@tonic-gate nmatches++; 1620Sstevel@tonic-gate } 1630Sstevel@tonic-gate 1640Sstevel@tonic-gate pp->dpp_nmatches += nmatches; 1650Sstevel@tonic-gate 1660Sstevel@tonic-gate if (sz != 0) 1670Sstevel@tonic-gate free(ftp); 1680Sstevel@tonic-gate return; 1690Sstevel@tonic-gate 1700Sstevel@tonic-gate create_err: 1710Sstevel@tonic-gate if (sz != 0) 1720Sstevel@tonic-gate free(ftp); 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate dt_proc_release(pp->dpp_dtp, pp->dpp_pr); 1750Sstevel@tonic-gate xyerror(D_PROC_CREATEFAIL, "failed to create probe in process %d: %s\n", 1760Sstevel@tonic-gate (int)pid, dtrace_errmsg(pp->dpp_dtp, dtrace_errno(pp->dpp_dtp))); 1770Sstevel@tonic-gate } 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate static int 1800Sstevel@tonic-gate dt_pid_sym_filt(void *arg, const GElf_Sym *symp, const char *func) 1810Sstevel@tonic-gate { 1820Sstevel@tonic-gate dt_pid_probe_t *pp = arg; 1830Sstevel@tonic-gate 1840Sstevel@tonic-gate if (symp->st_shndx == SHN_UNDEF) 1850Sstevel@tonic-gate return (0); 1860Sstevel@tonic-gate 1870Sstevel@tonic-gate if (symp->st_size == 0) { 1880Sstevel@tonic-gate dt_dprintf("st_size of %s is zero\n", func); 1890Sstevel@tonic-gate return (0); 1900Sstevel@tonic-gate } 1910Sstevel@tonic-gate 1920Sstevel@tonic-gate if (symp->st_value != pp->dpp_last.st_value || 1930Sstevel@tonic-gate symp->st_size != pp->dpp_last.st_size) { 1940Sstevel@tonic-gate /* 1950Sstevel@tonic-gate * Due to 4524008, _init and _fini may have a bloated st_size. 1960Sstevel@tonic-gate * While this bug has been fixed for a while, old binaries 1970Sstevel@tonic-gate * may exist that still exhibit this problem. As a result, we 1980Sstevel@tonic-gate * don't match _init and _fini though we allow users to 1990Sstevel@tonic-gate * specify them explicitly. 2000Sstevel@tonic-gate */ 2010Sstevel@tonic-gate if (strcmp(func, "_init") == 0 || strcmp(func, "_fini") == 0) 2020Sstevel@tonic-gate return (0); 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate if (gmatch(func, pp->dpp_func)) { 2050Sstevel@tonic-gate dt_pid_per_sym(pp, symp, func); 2060Sstevel@tonic-gate pp->dpp_last_taken = 1; 2070Sstevel@tonic-gate } 2080Sstevel@tonic-gate 2090Sstevel@tonic-gate pp->dpp_last = *symp; 2100Sstevel@tonic-gate } 2110Sstevel@tonic-gate 2120Sstevel@tonic-gate return (0); 2130Sstevel@tonic-gate } 2140Sstevel@tonic-gate 2150Sstevel@tonic-gate static void 2160Sstevel@tonic-gate dt_pid_per_mod(void *arg, const prmap_t *pmp, const char *obj) 2170Sstevel@tonic-gate { 2180Sstevel@tonic-gate dt_pid_probe_t *pp = arg; 2190Sstevel@tonic-gate GElf_Sym sym; 2200Sstevel@tonic-gate 2210Sstevel@tonic-gate if (obj == NULL) 2220Sstevel@tonic-gate return; 2230Sstevel@tonic-gate 2240Sstevel@tonic-gate (void) Plmid(pp->dpp_pr, pmp->pr_vaddr, &pp->dpp_lmid); 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate if ((pp->dpp_obj = strrchr(obj, '/')) == NULL) 2270Sstevel@tonic-gate pp->dpp_obj = obj; 2280Sstevel@tonic-gate else 2290Sstevel@tonic-gate pp->dpp_obj++; 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate if (Pxlookup_by_name(pp->dpp_pr, pp->dpp_lmid, obj, ".stret1", &sym, 2320Sstevel@tonic-gate NULL) == 0) 2330Sstevel@tonic-gate pp->dpp_stret[0] = sym.st_value; 2340Sstevel@tonic-gate else 2350Sstevel@tonic-gate pp->dpp_stret[0] = 0; 2360Sstevel@tonic-gate 2370Sstevel@tonic-gate if (Pxlookup_by_name(pp->dpp_pr, pp->dpp_lmid, obj, ".stret2", &sym, 2380Sstevel@tonic-gate NULL) == 0) 2390Sstevel@tonic-gate pp->dpp_stret[1] = sym.st_value; 2400Sstevel@tonic-gate else 2410Sstevel@tonic-gate pp->dpp_stret[1] = 0; 2420Sstevel@tonic-gate 2430Sstevel@tonic-gate if (Pxlookup_by_name(pp->dpp_pr, pp->dpp_lmid, obj, ".stret4", &sym, 2440Sstevel@tonic-gate NULL) == 0) 2450Sstevel@tonic-gate pp->dpp_stret[2] = sym.st_value; 2460Sstevel@tonic-gate else 2470Sstevel@tonic-gate pp->dpp_stret[2] = 0; 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate if (Pxlookup_by_name(pp->dpp_pr, pp->dpp_lmid, obj, ".stret8", &sym, 2500Sstevel@tonic-gate NULL) == 0) 2510Sstevel@tonic-gate pp->dpp_stret[3] = sym.st_value; 2520Sstevel@tonic-gate else 2530Sstevel@tonic-gate pp->dpp_stret[3] = 0; 2540Sstevel@tonic-gate 2550Sstevel@tonic-gate dt_dprintf("%s stret %llx %llx %llx %llx\n", obj, 2560Sstevel@tonic-gate (u_longlong_t)pp->dpp_stret[0], (u_longlong_t)pp->dpp_stret[1], 2570Sstevel@tonic-gate (u_longlong_t)pp->dpp_stret[2], (u_longlong_t)pp->dpp_stret[3]); 2580Sstevel@tonic-gate 2590Sstevel@tonic-gate /* 2600Sstevel@tonic-gate * If pp->dpp_func contains any globbing meta-characters, we need 2610Sstevel@tonic-gate * to iterate over the symbol table and compare each function name 2620Sstevel@tonic-gate * against the pattern. 2630Sstevel@tonic-gate */ 2640Sstevel@tonic-gate if (!strisglob(pp->dpp_func)) { 2650Sstevel@tonic-gate /* 2660Sstevel@tonic-gate * If we fail to lookup the symbol, try interpreting the 2670Sstevel@tonic-gate * function as the special "-" function that indicates that the 2680Sstevel@tonic-gate * probe name should be interpreted as a absolute virtual 2690Sstevel@tonic-gate * address. If that fails and we were matching a specific 2700Sstevel@tonic-gate * function in a specific module, report the error, otherwise 2710Sstevel@tonic-gate * just fail silently in the hopes that some other object will 2720Sstevel@tonic-gate * contain the desired symbol. 2730Sstevel@tonic-gate */ 2740Sstevel@tonic-gate if (Pxlookup_by_name(pp->dpp_pr, pp->dpp_lmid, obj, 2750Sstevel@tonic-gate pp->dpp_func, &sym, NULL) != 0) { 2760Sstevel@tonic-gate if (strcmp("-", pp->dpp_func) == 0) { 2770Sstevel@tonic-gate sym.st_name = 0; 2780Sstevel@tonic-gate sym.st_info = 2790Sstevel@tonic-gate GELF_ST_INFO(STB_LOCAL, STT_FUNC); 2800Sstevel@tonic-gate sym.st_other = 0; 2810Sstevel@tonic-gate sym.st_value = 0; 2820Sstevel@tonic-gate sym.st_size = Pstatus(pp->dpp_pr)->pr_dmodel == 2830Sstevel@tonic-gate PR_MODEL_ILP32 ? -1U : -1ULL; 2840Sstevel@tonic-gate 2850Sstevel@tonic-gate } else if (!strisglob(pp->dpp_mod)) { 2860Sstevel@tonic-gate dt_proc_release(pp->dpp_dtp, pp->dpp_pr); 2870Sstevel@tonic-gate xyerror(D_PROC_FUNC, "failed to lookup '%s'\n", 2880Sstevel@tonic-gate pp->dpp_func); 2890Sstevel@tonic-gate } else { 2900Sstevel@tonic-gate return; 2910Sstevel@tonic-gate } 2920Sstevel@tonic-gate } 2930Sstevel@tonic-gate 2940Sstevel@tonic-gate /* 2950Sstevel@tonic-gate * Only match defined functions of non-zero size. 2960Sstevel@tonic-gate */ 2970Sstevel@tonic-gate if (GELF_ST_TYPE(sym.st_info) != STT_FUNC || 2980Sstevel@tonic-gate sym.st_shndx == SHN_UNDEF || sym.st_size == 0) 2990Sstevel@tonic-gate return; 3000Sstevel@tonic-gate 3010Sstevel@tonic-gate /* 3020Sstevel@tonic-gate * We don't instrument PLTs -- they're dynamically rewritten, 3030Sstevel@tonic-gate * and, so, inherently dicey to instrument. 3040Sstevel@tonic-gate */ 3050Sstevel@tonic-gate if (Ppltdest(pp->dpp_pr, sym.st_value) != NULL) 3060Sstevel@tonic-gate return; 3070Sstevel@tonic-gate 3080Sstevel@tonic-gate (void) Plookup_by_addr(pp->dpp_pr, sym.st_value, pp->dpp_func, 3090Sstevel@tonic-gate DTRACE_FUNCNAMELEN, &sym); 3100Sstevel@tonic-gate 3110Sstevel@tonic-gate dt_pid_per_sym(pp, &sym, pp->dpp_func); 3120Sstevel@tonic-gate } else { 3130Sstevel@tonic-gate uint_t nmatches = pp->dpp_nmatches; 3140Sstevel@tonic-gate 3150Sstevel@tonic-gate (void) Psymbol_iter_by_addr(pp->dpp_pr, obj, PR_SYMTAB, 3160Sstevel@tonic-gate BIND_ANY | TYPE_FUNC, dt_pid_sym_filt, pp); 3170Sstevel@tonic-gate 3180Sstevel@tonic-gate if (nmatches == pp->dpp_nmatches) { 3190Sstevel@tonic-gate /* 3200Sstevel@tonic-gate * If we didn't match anything in the PR_SYMTAB, try 3210Sstevel@tonic-gate * the PR_DYNSYM. 3220Sstevel@tonic-gate */ 3230Sstevel@tonic-gate (void) Psymbol_iter_by_addr(pp->dpp_pr, obj, PR_DYNSYM, 3240Sstevel@tonic-gate BIND_ANY | TYPE_FUNC, dt_pid_sym_filt, pp); 3250Sstevel@tonic-gate } 3260Sstevel@tonic-gate } 3270Sstevel@tonic-gate } 3280Sstevel@tonic-gate 3290Sstevel@tonic-gate static int 3300Sstevel@tonic-gate dt_pid_mod_filt(void *arg, const prmap_t *pmp, const char *obj) 3310Sstevel@tonic-gate { 3320Sstevel@tonic-gate dt_pid_probe_t *pp = arg; 3330Sstevel@tonic-gate 3340Sstevel@tonic-gate if (gmatch(obj, pp->dpp_mod)) { 3350Sstevel@tonic-gate dt_pid_per_mod(pp, pmp, obj); 3360Sstevel@tonic-gate } else { 3370Sstevel@tonic-gate char name[DTRACE_MODNAMELEN]; 3380Sstevel@tonic-gate 3390Sstevel@tonic-gate (void) Plmid(pp->dpp_pr, pmp->pr_vaddr, &pp->dpp_lmid); 3400Sstevel@tonic-gate 3410Sstevel@tonic-gate if ((pp->dpp_obj = strrchr(obj, '/')) == NULL) 3420Sstevel@tonic-gate pp->dpp_obj = obj; 3430Sstevel@tonic-gate else 3440Sstevel@tonic-gate pp->dpp_obj++; 3450Sstevel@tonic-gate 3460Sstevel@tonic-gate (void) snprintf(name, sizeof (name), "LM%lx`%s", 3470Sstevel@tonic-gate pp->dpp_lmid, obj); 3480Sstevel@tonic-gate 3490Sstevel@tonic-gate if (gmatch(name, pp->dpp_mod)) 3500Sstevel@tonic-gate dt_pid_per_mod(pp, pmp, obj); 3510Sstevel@tonic-gate } 3520Sstevel@tonic-gate 3530Sstevel@tonic-gate return (0); 3540Sstevel@tonic-gate } 3550Sstevel@tonic-gate 3560Sstevel@tonic-gate static const prmap_t * 3570Sstevel@tonic-gate dt_pid_fix_mod(dtrace_probedesc_t *pdp, struct ps_prochandle *P) 3580Sstevel@tonic-gate { 3590Sstevel@tonic-gate char m[MAXPATHLEN]; 3600Sstevel@tonic-gate Lmid_t lmid = PR_LMID_EVERY; 3610Sstevel@tonic-gate const char *obj; 3620Sstevel@tonic-gate const prmap_t *pmp; 3630Sstevel@tonic-gate 3640Sstevel@tonic-gate /* 3650Sstevel@tonic-gate * Pick apart the link map from the library name. 3660Sstevel@tonic-gate */ 3670Sstevel@tonic-gate if (strchr(pdp->dtpd_mod, '`') != NULL) { 3680Sstevel@tonic-gate char *end; 3690Sstevel@tonic-gate 3700Sstevel@tonic-gate if (strncmp(pdp->dtpd_mod, "LM", 2) != 0 || 3710Sstevel@tonic-gate !isdigit(pdp->dtpd_mod[2])) 3720Sstevel@tonic-gate return (NULL); 3730Sstevel@tonic-gate 3740Sstevel@tonic-gate lmid = strtoul(&pdp->dtpd_mod[2], &end, 16); 3750Sstevel@tonic-gate 3760Sstevel@tonic-gate obj = end + 1; 3770Sstevel@tonic-gate 3780Sstevel@tonic-gate if (*end != '`' || strchr(obj, '`') != NULL) 3790Sstevel@tonic-gate return (NULL); 3800Sstevel@tonic-gate 3810Sstevel@tonic-gate } else { 3820Sstevel@tonic-gate obj = pdp->dtpd_mod; 3830Sstevel@tonic-gate } 3840Sstevel@tonic-gate 3850Sstevel@tonic-gate if ((pmp = Plmid_to_map(P, lmid, obj)) == NULL) 3860Sstevel@tonic-gate return (NULL); 3870Sstevel@tonic-gate 3880Sstevel@tonic-gate (void) Pobjname(P, pmp->pr_vaddr, m, sizeof (m)); 3890Sstevel@tonic-gate if ((obj = strrchr(m, '/')) == NULL) 3900Sstevel@tonic-gate obj = &m[0]; 3910Sstevel@tonic-gate else 3920Sstevel@tonic-gate obj++; 3930Sstevel@tonic-gate 3940Sstevel@tonic-gate (void) Plmid(P, pmp->pr_vaddr, &lmid); 3950Sstevel@tonic-gate if (lmid == LM_ID_BASE) 3960Sstevel@tonic-gate (void) strcpy(pdp->dtpd_mod, obj); 3970Sstevel@tonic-gate else 3980Sstevel@tonic-gate (void) snprintf(pdp->dtpd_mod, sizeof (pdp->dtpd_mod), 3990Sstevel@tonic-gate "LM%lx`%s", lmid, obj); 4000Sstevel@tonic-gate 4010Sstevel@tonic-gate return (pmp); 4020Sstevel@tonic-gate } 4030Sstevel@tonic-gate 4040Sstevel@tonic-gate 4050Sstevel@tonic-gate static void 4060Sstevel@tonic-gate dt_pid_create_pid_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, pid_t pid) 4070Sstevel@tonic-gate { 4080Sstevel@tonic-gate dt_pid_probe_t pp; 4090Sstevel@tonic-gate 4100Sstevel@tonic-gate pp.dpp_pr = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0); 4110Sstevel@tonic-gate if (pp.dpp_pr == NULL) 4120Sstevel@tonic-gate longjmp(dtp->dt_pcb->pcb_jmpbuf, EDT_COMPILER); 4130Sstevel@tonic-gate 4140Sstevel@tonic-gate /* 4150Sstevel@tonic-gate * We can only trace dynamically-linked executables (since we've 4160Sstevel@tonic-gate * hidden some magic in ld.so.1 as well as libc.so.1). 4170Sstevel@tonic-gate */ 4180Sstevel@tonic-gate if (Pname_to_map(pp.dpp_pr, PR_OBJ_LDSO) == NULL) { 4190Sstevel@tonic-gate dt_proc_release(dtp, pp.dpp_pr); 4200Sstevel@tonic-gate xyerror(D_PROC_DYN, "process %s is not a dynamically-linked " 4210Sstevel@tonic-gate "executable\n", &pdp->dtpd_provider[3]); 4220Sstevel@tonic-gate } 4230Sstevel@tonic-gate 4240Sstevel@tonic-gate pp.dpp_dtp = dtp; 4250Sstevel@tonic-gate pp.dpp_mod = pdp->dtpd_mod[0] != '\0' ? pdp->dtpd_mod : "*"; 4260Sstevel@tonic-gate pp.dpp_func = pdp->dtpd_func[0] != '\0' ? pdp->dtpd_func : "*"; 4270Sstevel@tonic-gate pp.dpp_name = pdp->dtpd_name[0] != '\0' ? pdp->dtpd_name : "*"; 4280Sstevel@tonic-gate 4290Sstevel@tonic-gate if (strcmp(pp.dpp_func, "-") == 0) { 4300Sstevel@tonic-gate const prmap_t *aout, *pmp; 4310Sstevel@tonic-gate 4320Sstevel@tonic-gate if (pdp->dtpd_mod[0] == '\0') { 4330Sstevel@tonic-gate pp.dpp_mod = pdp->dtpd_mod; 4340Sstevel@tonic-gate (void) strcpy(pdp->dtpd_mod, "a.out"); 4350Sstevel@tonic-gate } else if (strisglob(pp.dpp_mod) || 4360Sstevel@tonic-gate (aout = Pname_to_map(pp.dpp_pr, "a.out")) == NULL || 4370Sstevel@tonic-gate (pmp = Pname_to_map(pp.dpp_pr, pp.dpp_mod)) == NULL || 4380Sstevel@tonic-gate aout->pr_vaddr != pmp->pr_vaddr) { 4390Sstevel@tonic-gate dt_proc_release(dtp, pp.dpp_pr); 4400Sstevel@tonic-gate xyerror(D_PROC_LIB, "only the a.out module is valid " 4410Sstevel@tonic-gate "with the '-' function\n"); 4420Sstevel@tonic-gate } 4430Sstevel@tonic-gate 4440Sstevel@tonic-gate if (strisglob(pp.dpp_name)) { 4450Sstevel@tonic-gate dt_proc_release(dtp, pp.dpp_pr); 4460Sstevel@tonic-gate xyerror(D_PROC_NAME, "only individual addresses may " 4470Sstevel@tonic-gate "be specified with the '-' function\n"); 4480Sstevel@tonic-gate } 4490Sstevel@tonic-gate } 4500Sstevel@tonic-gate 4510Sstevel@tonic-gate /* 4520Sstevel@tonic-gate * If pp.dpp_mod contains any globbing meta-characters, we need 4530Sstevel@tonic-gate * to iterate over each module and compare its name against the 4540Sstevel@tonic-gate * pattern. An empty module name is treated as '*'. 4550Sstevel@tonic-gate */ 4560Sstevel@tonic-gate if (strisglob(pp.dpp_mod)) { 4570Sstevel@tonic-gate (void) Pobject_iter(pp.dpp_pr, dt_pid_mod_filt, &pp); 4580Sstevel@tonic-gate } else { 4590Sstevel@tonic-gate const prmap_t *pmp; 4600Sstevel@tonic-gate char *obj; 4610Sstevel@tonic-gate 4620Sstevel@tonic-gate /* 4630Sstevel@tonic-gate * If can't find a matching module, don't sweat it -- either 4640Sstevel@tonic-gate * we'll fail the enabling because the probes don't exist or 4650Sstevel@tonic-gate * we'll wait for that module to come along. 4660Sstevel@tonic-gate */ 4670Sstevel@tonic-gate if ((pmp = dt_pid_fix_mod(pdp, pp.dpp_pr)) != NULL) { 4680Sstevel@tonic-gate if ((obj = strchr(pdp->dtpd_mod, '`')) == NULL) 4690Sstevel@tonic-gate obj = pdp->dtpd_mod; 4700Sstevel@tonic-gate else 4710Sstevel@tonic-gate obj++; 4720Sstevel@tonic-gate 4730Sstevel@tonic-gate dt_pid_per_mod(&pp, pmp, obj); 4740Sstevel@tonic-gate } 4750Sstevel@tonic-gate } 4760Sstevel@tonic-gate 4770Sstevel@tonic-gate dt_proc_release(dtp, pp.dpp_pr); 4780Sstevel@tonic-gate } 4790Sstevel@tonic-gate 4800Sstevel@tonic-gate static int 4810Sstevel@tonic-gate dt_pid_usdt_mapping(void *data, const prmap_t *pmp, const char *oname) 4820Sstevel@tonic-gate { 4830Sstevel@tonic-gate struct ps_prochandle *P = data; 4840Sstevel@tonic-gate GElf_Sym sym; 4850Sstevel@tonic-gate prsyminfo_t sip; 4860Sstevel@tonic-gate int fd; 4870Sstevel@tonic-gate dof_helper_t dh; 4880Sstevel@tonic-gate GElf_Half e_type; 4890Sstevel@tonic-gate const char *mname; 4900Sstevel@tonic-gate const char *syms[] = { "___SUNW_dof", "__SUNW_dof" }; 4910Sstevel@tonic-gate int i; 4920Sstevel@tonic-gate 4930Sstevel@tonic-gate /* 4940Sstevel@tonic-gate * The symbol ___SUNW_dof is for lazy-loaded DOF sections, and 4950Sstevel@tonic-gate * __SUNW_dof is for actively-loaded DOF sections. We try to force 4960Sstevel@tonic-gate * in both types of DOF section since the process may not yet have 4970Sstevel@tonic-gate * run the code to instantiate these providers. 4980Sstevel@tonic-gate */ 4990Sstevel@tonic-gate for (i = 0; i < 2; i++) { 5000Sstevel@tonic-gate if (Pxlookup_by_name(P, PR_LMID_EVERY, oname, syms[i], &sym, 5010Sstevel@tonic-gate &sip) != 0) { 5020Sstevel@tonic-gate continue; 5030Sstevel@tonic-gate } 5040Sstevel@tonic-gate 5050Sstevel@tonic-gate if ((mname = strrchr(oname, '/')) == NULL) 5060Sstevel@tonic-gate mname = oname; 5070Sstevel@tonic-gate else 5080Sstevel@tonic-gate mname++; 5090Sstevel@tonic-gate 5100Sstevel@tonic-gate dt_dprintf("lookup of %s succeeded for %s\n", syms[i], mname); 5110Sstevel@tonic-gate 5120Sstevel@tonic-gate if (Pread(P, &e_type, sizeof (e_type), pmp->pr_vaddr + 5130Sstevel@tonic-gate offsetof(Elf64_Ehdr, e_type)) != sizeof (e_type)) { 5140Sstevel@tonic-gate dt_dprintf("read of ELF header failed"); 5150Sstevel@tonic-gate continue; 5160Sstevel@tonic-gate } 5170Sstevel@tonic-gate 5180Sstevel@tonic-gate dh.dofhp_dof = sym.st_value; 5190Sstevel@tonic-gate dh.dofhp_addr = (e_type == ET_EXEC) ? 0 : pmp->pr_vaddr; 5200Sstevel@tonic-gate 5210Sstevel@tonic-gate if (sip.prs_lmid == 0) { 5220Sstevel@tonic-gate (void) snprintf(dh.dofhp_mod, sizeof (dh.dofhp_mod), 5230Sstevel@tonic-gate "%s", mname); 5240Sstevel@tonic-gate } else { 5250Sstevel@tonic-gate (void) snprintf(dh.dofhp_mod, sizeof (dh.dofhp_mod), 5260Sstevel@tonic-gate "LM%lx`%s", sip.prs_lmid, mname); 5270Sstevel@tonic-gate } 5280Sstevel@tonic-gate 5290Sstevel@tonic-gate if ((fd = pr_open(P, "/dev/dtrace/helper", O_RDWR, 0)) < 0) { 5300Sstevel@tonic-gate dt_dprintf("pr_open of helper device failed: %s\n", 5310Sstevel@tonic-gate strerror(errno)); 5320Sstevel@tonic-gate return (errno); 5330Sstevel@tonic-gate } 5340Sstevel@tonic-gate 5350Sstevel@tonic-gate (void) pr_ioctl(P, fd, DTRACEHIOC_ADDDOF, &dh, sizeof (dh)); 5360Sstevel@tonic-gate 5370Sstevel@tonic-gate if (pr_close(P, fd) != 0) 5380Sstevel@tonic-gate return (errno); 5390Sstevel@tonic-gate } 5400Sstevel@tonic-gate 5410Sstevel@tonic-gate return (0); 5420Sstevel@tonic-gate } 5430Sstevel@tonic-gate 5440Sstevel@tonic-gate static int 5450Sstevel@tonic-gate dt_pid_create_usdt_probes(dtrace_probedesc_t *pdp, dt_proc_t *dpr) 5460Sstevel@tonic-gate { 5470Sstevel@tonic-gate struct ps_prochandle *P = dpr->dpr_proc; 5480Sstevel@tonic-gate int err; 5490Sstevel@tonic-gate 5500Sstevel@tonic-gate assert(DT_MUTEX_HELD(&dpr->dpr_lock)); 5510Sstevel@tonic-gate 5520Sstevel@tonic-gate (void) Pupdate_maps(P); 5530Sstevel@tonic-gate err = Pobject_iter(P, dt_pid_usdt_mapping, P); 5540Sstevel@tonic-gate 5550Sstevel@tonic-gate /* 5560Sstevel@tonic-gate * Put the module name in its canonical form. 5570Sstevel@tonic-gate */ 5580Sstevel@tonic-gate (void) dt_pid_fix_mod(pdp, P); 5590Sstevel@tonic-gate 5600Sstevel@tonic-gate return (err); 5610Sstevel@tonic-gate } 5620Sstevel@tonic-gate 5630Sstevel@tonic-gate static pid_t 5640Sstevel@tonic-gate dt_pid_get_pid(dtrace_probedesc_t *pdp, int *errp) 5650Sstevel@tonic-gate { 5660Sstevel@tonic-gate pid_t pid; 5670Sstevel@tonic-gate char *c, *last = NULL, *end; 5680Sstevel@tonic-gate 5690Sstevel@tonic-gate for (c = &pdp->dtpd_provider[0]; *c != '\0'; c++) { 5700Sstevel@tonic-gate if (!isdigit(*c)) 5710Sstevel@tonic-gate last = c; 5720Sstevel@tonic-gate } 5730Sstevel@tonic-gate 5740Sstevel@tonic-gate if (last == NULL || (*(++last) == '\0')) { 5750Sstevel@tonic-gate if (errp != NULL) { 5760Sstevel@tonic-gate *errp = D_PROC_BADPROV; 5770Sstevel@tonic-gate return (-1); 5780Sstevel@tonic-gate } 5790Sstevel@tonic-gate xyerror(D_PROC_BADPROV, "%s is not a valid provider\n", 5800Sstevel@tonic-gate pdp->dtpd_provider); 5810Sstevel@tonic-gate } 5820Sstevel@tonic-gate 5830Sstevel@tonic-gate errno = 0; 5840Sstevel@tonic-gate pid = strtol(last, &end, 10); 5850Sstevel@tonic-gate 5860Sstevel@tonic-gate if (errno != 0 || end == last || end[0] != '\0' || pid <= 0) { 5870Sstevel@tonic-gate if (errp != NULL) { 5880Sstevel@tonic-gate *errp = D_PROC_BADPID; 5890Sstevel@tonic-gate return (-1); 5900Sstevel@tonic-gate } 5910Sstevel@tonic-gate xyerror(D_PROC_BADPID, "%s does not contain a valid pid\n", 5920Sstevel@tonic-gate pdp->dtpd_provider); 5930Sstevel@tonic-gate } 5940Sstevel@tonic-gate 5950Sstevel@tonic-gate if (errp != NULL) 5960Sstevel@tonic-gate *errp = 0; 5970Sstevel@tonic-gate 5980Sstevel@tonic-gate return (pid); 5990Sstevel@tonic-gate } 6000Sstevel@tonic-gate 6010Sstevel@tonic-gate void 6020Sstevel@tonic-gate dt_pid_create_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp) 6030Sstevel@tonic-gate { 6040Sstevel@tonic-gate pid_t pid = dt_pid_get_pid(pdp, NULL); 6050Sstevel@tonic-gate char provname[DTRACE_PROVNAMELEN]; 6060Sstevel@tonic-gate struct ps_prochandle *P; 6070Sstevel@tonic-gate dt_proc_t *dpr; 6080Sstevel@tonic-gate int err = 0; 6090Sstevel@tonic-gate 6100Sstevel@tonic-gate if (dtp->dt_ftfd == -1) { 6110Sstevel@tonic-gate if (dtp->dt_fterr == ENOENT) { 6120Sstevel@tonic-gate xyerror(D_PROC_NODEV, "pid provider is not " 6130Sstevel@tonic-gate "installed on this system\n"); 6140Sstevel@tonic-gate } else { 6150Sstevel@tonic-gate xyerror(D_PROC_NODEV, "pid provider is not " 6160Sstevel@tonic-gate "available: %s\n", strerror(dtp->dt_fterr)); 6170Sstevel@tonic-gate } 6180Sstevel@tonic-gate } 6190Sstevel@tonic-gate 6200Sstevel@tonic-gate (void) snprintf(provname, sizeof (provname), "pid%d", (int)pid); 6210Sstevel@tonic-gate 6220Sstevel@tonic-gate if (strcmp(provname, pdp->dtpd_provider) == 0) { 6230Sstevel@tonic-gate dt_pid_create_pid_probes(pdp, dtp, pid); 6240Sstevel@tonic-gate } else { 6250Sstevel@tonic-gate if ((P = dt_proc_grab(dtp, pid, 0, 1)) == NULL) 6260Sstevel@tonic-gate longjmp(dtp->dt_pcb->pcb_jmpbuf, EDT_COMPILER); 6270Sstevel@tonic-gate 6280Sstevel@tonic-gate dpr = dt_proc_lookup(dtp, P, 0); 6290Sstevel@tonic-gate assert(dpr != NULL); 6300Sstevel@tonic-gate 6310Sstevel@tonic-gate (void) pthread_mutex_lock(&dpr->dpr_lock); 6320Sstevel@tonic-gate 6330Sstevel@tonic-gate if (!dpr->dpr_usdt) { 6340Sstevel@tonic-gate err = dt_pid_create_usdt_probes(pdp, dpr); 6350Sstevel@tonic-gate dpr->dpr_usdt = B_TRUE; 6360Sstevel@tonic-gate } 6370Sstevel@tonic-gate 6380Sstevel@tonic-gate (void) pthread_mutex_unlock(&dpr->dpr_lock); 6390Sstevel@tonic-gate 6400Sstevel@tonic-gate dt_proc_release(dtp, P); 6410Sstevel@tonic-gate 6420Sstevel@tonic-gate if (err != 0) 6430Sstevel@tonic-gate xyerror(D_PROC_USDT, "failed to instantiate probes " 6440Sstevel@tonic-gate "for PID %d: %s", (int)pid, strerror(err)); 6450Sstevel@tonic-gate } 6460Sstevel@tonic-gate } 6470Sstevel@tonic-gate 6480Sstevel@tonic-gate void 6490Sstevel@tonic-gate dt_pid_create_probes_module(dtrace_hdl_t *dtp, dt_proc_t *dpr) 6500Sstevel@tonic-gate { 6510Sstevel@tonic-gate dtrace_prog_t *pgp; 6520Sstevel@tonic-gate dt_stmt_t *stp; 6530Sstevel@tonic-gate char provname[DTRACE_PROVNAMELEN]; 6540Sstevel@tonic-gate dtrace_probedesc_t *pdp, pd; 6550Sstevel@tonic-gate pid_t pid; 6560Sstevel@tonic-gate int err; 6570Sstevel@tonic-gate int found = B_FALSE; 6580Sstevel@tonic-gate 6590Sstevel@tonic-gate for (pgp = dt_list_next(&dtp->dt_programs); pgp != NULL; 6600Sstevel@tonic-gate pgp = dt_list_next(pgp)) { 6610Sstevel@tonic-gate 6620Sstevel@tonic-gate for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; 6630Sstevel@tonic-gate stp = dt_list_next(stp)) { 6640Sstevel@tonic-gate 6650Sstevel@tonic-gate pdp = &stp->ds_desc->dtsd_ecbdesc->dted_probe; 6660Sstevel@tonic-gate pid = dt_pid_get_pid(pdp, &err); 6670Sstevel@tonic-gate if (err != 0 || pid != dpr->dpr_pid) 6680Sstevel@tonic-gate continue; 6690Sstevel@tonic-gate 6700Sstevel@tonic-gate found = B_TRUE; 6710Sstevel@tonic-gate 6720Sstevel@tonic-gate pd = *pdp; 6730Sstevel@tonic-gate 6740Sstevel@tonic-gate (void) snprintf(provname, sizeof (provname), "pid%d", 6750Sstevel@tonic-gate (int)pid); 6760Sstevel@tonic-gate 6770Sstevel@tonic-gate if (strcmp(provname, pdp->dtpd_provider) == 0) 6780Sstevel@tonic-gate dt_pid_create_pid_probes(&pd, dtp, pid); 6790Sstevel@tonic-gate else 6800Sstevel@tonic-gate (void) dt_pid_create_usdt_probes(&pd, dpr); 6810Sstevel@tonic-gate } 6820Sstevel@tonic-gate } 6830Sstevel@tonic-gate 6840Sstevel@tonic-gate if (found) { 6850Sstevel@tonic-gate /* 6860Sstevel@tonic-gate * Give DTrace a shot to the ribs to get it to check 6870Sstevel@tonic-gate * out the newly created probes. 6880Sstevel@tonic-gate */ 6890Sstevel@tonic-gate (void) dt_ioctl(dtp, DTRACEIOC_ENABLE, NULL); 6900Sstevel@tonic-gate } 6910Sstevel@tonic-gate } 692