16ff6d951SJohn Birrell /*
26ff6d951SJohn Birrell * CDDL HEADER START
36ff6d951SJohn Birrell *
46ff6d951SJohn Birrell * The contents of this file are subject to the terms of the
56ff6d951SJohn Birrell * Common Development and Distribution License (the "License").
66ff6d951SJohn Birrell * You may not use this file except in compliance with the License.
76ff6d951SJohn Birrell *
86ff6d951SJohn Birrell * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96ff6d951SJohn Birrell * or http://www.opensolaris.org/os/licensing.
106ff6d951SJohn Birrell * See the License for the specific language governing permissions
116ff6d951SJohn Birrell * and limitations under the License.
126ff6d951SJohn Birrell *
136ff6d951SJohn Birrell * When distributing Covered Code, include this CDDL HEADER in each
146ff6d951SJohn Birrell * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156ff6d951SJohn Birrell * If applicable, add the following below this CDDL HEADER, with the
166ff6d951SJohn Birrell * fields enclosed by brackets "[]" replaced with your own identifying
176ff6d951SJohn Birrell * information: Portions Copyright [yyyy] [name of copyright owner]
186ff6d951SJohn Birrell *
196ff6d951SJohn Birrell * CDDL HEADER END
206ff6d951SJohn Birrell */
216ff6d951SJohn Birrell
226ff6d951SJohn Birrell /*
231670a1c2SRui Paulo * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
246ff6d951SJohn Birrell * Use is subject to license terms.
256ff6d951SJohn Birrell */
268e648814SRui Paulo /*
278e648814SRui Paulo * Copyright (c) 2013, Joyent, Inc. All rights reserved.
288e648814SRui Paulo */
296ff6d951SJohn Birrell
306ff6d951SJohn Birrell #include <assert.h>
316ff6d951SJohn Birrell #include <strings.h>
326ff6d951SJohn Birrell #include <stdlib.h>
336ff6d951SJohn Birrell #include <stdio.h>
346ff6d951SJohn Birrell #include <errno.h>
356ff6d951SJohn Birrell #include <ctype.h>
36bc96366cSSteven Hartland #ifdef illumos
376ff6d951SJohn Birrell #include <alloca.h>
385ec56692SJohn Birrell #endif
396ff6d951SJohn Birrell #include <libgen.h>
406ff6d951SJohn Birrell #include <stddef.h>
418e648814SRui Paulo #include <sys/sysmacros.h>
426ff6d951SJohn Birrell
436ff6d951SJohn Birrell #include <dt_impl.h>
446ff6d951SJohn Birrell #include <dt_program.h>
456ff6d951SJohn Birrell #include <dt_pid.h>
466ff6d951SJohn Birrell #include <dt_string.h>
478e648814SRui Paulo #include <dt_module.h>
486ff6d951SJohn Birrell
4967cf27b7SMark Johnston #ifndef illumos
5067cf27b7SMark Johnston #include <sys/sysctl.h>
5167cf27b7SMark Johnston #include <unistd.h>
5267cf27b7SMark Johnston #include <libproc_compat.h>
5367cf27b7SMark Johnston #include <libelf.h>
5467cf27b7SMark Johnston #include <gelf.h>
5567cf27b7SMark Johnston #endif
5667cf27b7SMark Johnston
576ff6d951SJohn Birrell typedef struct dt_pid_probe {
586ff6d951SJohn Birrell dtrace_hdl_t *dpp_dtp;
596ff6d951SJohn Birrell dt_pcb_t *dpp_pcb;
606ff6d951SJohn Birrell dt_proc_t *dpp_dpr;
616ff6d951SJohn Birrell struct ps_prochandle *dpp_pr;
626ff6d951SJohn Birrell const char *dpp_mod;
636ff6d951SJohn Birrell char *dpp_func;
646ff6d951SJohn Birrell const char *dpp_name;
656ff6d951SJohn Birrell const char *dpp_obj;
666ff6d951SJohn Birrell uintptr_t dpp_pc;
676ff6d951SJohn Birrell size_t dpp_size;
686ff6d951SJohn Birrell Lmid_t dpp_lmid;
696ff6d951SJohn Birrell uint_t dpp_nmatches;
706ff6d951SJohn Birrell uint64_t dpp_stret[4];
716ff6d951SJohn Birrell GElf_Sym dpp_last;
726ff6d951SJohn Birrell uint_t dpp_last_taken;
736ff6d951SJohn Birrell } dt_pid_probe_t;
746ff6d951SJohn Birrell
756ff6d951SJohn Birrell /*
766ff6d951SJohn Birrell * Compose the lmid and object name into the canonical representation. We
776ff6d951SJohn Birrell * omit the lmid for the default link map for convenience.
786ff6d951SJohn Birrell */
796ff6d951SJohn Birrell static void
dt_pid_objname(char * buf,size_t len,Lmid_t lmid,const char * obj)806ff6d951SJohn Birrell dt_pid_objname(char *buf, size_t len, Lmid_t lmid, const char *obj)
816ff6d951SJohn Birrell {
82bc96366cSSteven Hartland #ifdef illumos
836ff6d951SJohn Birrell if (lmid == LM_ID_BASE)
846ff6d951SJohn Birrell (void) strncpy(buf, obj, len);
856ff6d951SJohn Birrell else
866ff6d951SJohn Birrell (void) snprintf(buf, len, "LM%lx`%s", lmid, obj);
875ec56692SJohn Birrell #else
885ec56692SJohn Birrell (void) strncpy(buf, obj, len);
895ec56692SJohn Birrell #endif
906ff6d951SJohn Birrell }
916ff6d951SJohn Birrell
926ff6d951SJohn Birrell static int
dt_pid_error(dtrace_hdl_t * dtp,dt_pcb_t * pcb,dt_proc_t * dpr,fasttrap_probe_spec_t * ftp,dt_errtag_t tag,const char * fmt,...)936ff6d951SJohn Birrell dt_pid_error(dtrace_hdl_t *dtp, dt_pcb_t *pcb, dt_proc_t *dpr,
946ff6d951SJohn Birrell fasttrap_probe_spec_t *ftp, dt_errtag_t tag, const char *fmt, ...)
956ff6d951SJohn Birrell {
966ff6d951SJohn Birrell va_list ap;
976ff6d951SJohn Birrell int len;
986ff6d951SJohn Birrell
996ff6d951SJohn Birrell if (ftp != NULL)
1006ff6d951SJohn Birrell dt_free(dtp, ftp);
1016ff6d951SJohn Birrell
1026ff6d951SJohn Birrell va_start(ap, fmt);
1036ff6d951SJohn Birrell if (pcb == NULL) {
1046ff6d951SJohn Birrell assert(dpr != NULL);
1056ff6d951SJohn Birrell len = vsnprintf(dpr->dpr_errmsg, sizeof (dpr->dpr_errmsg),
1066ff6d951SJohn Birrell fmt, ap);
1076ff6d951SJohn Birrell assert(len >= 2);
1086ff6d951SJohn Birrell if (dpr->dpr_errmsg[len - 2] == '\n')
1096ff6d951SJohn Birrell dpr->dpr_errmsg[len - 2] = '\0';
1106ff6d951SJohn Birrell } else {
1116ff6d951SJohn Birrell dt_set_errmsg(dtp, dt_errtag(tag), pcb->pcb_region,
1126ff6d951SJohn Birrell pcb->pcb_filetag, pcb->pcb_fileptr ? yylineno : 0, fmt, ap);
1136ff6d951SJohn Birrell }
1146ff6d951SJohn Birrell va_end(ap);
1156ff6d951SJohn Birrell
1166ff6d951SJohn Birrell return (1);
1176ff6d951SJohn Birrell }
1186ff6d951SJohn Birrell
1196ff6d951SJohn Birrell static int
dt_pid_per_sym(dt_pid_probe_t * pp,const GElf_Sym * symp,const char * func)1206ff6d951SJohn Birrell dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func)
1216ff6d951SJohn Birrell {
1226ff6d951SJohn Birrell dtrace_hdl_t *dtp = pp->dpp_dtp;
1236ff6d951SJohn Birrell dt_pcb_t *pcb = pp->dpp_pcb;
1246ff6d951SJohn Birrell dt_proc_t *dpr = pp->dpp_dpr;
1256ff6d951SJohn Birrell fasttrap_probe_spec_t *ftp;
1266ff6d951SJohn Birrell uint64_t off;
1276ff6d951SJohn Birrell char *end;
1286ff6d951SJohn Birrell uint_t nmatches = 0;
1296ff6d951SJohn Birrell ulong_t sz;
1306ff6d951SJohn Birrell int glob, err;
1316ff6d951SJohn Birrell int isdash = strcmp("-", func) == 0;
1326ff6d951SJohn Birrell pid_t pid;
1336ff6d951SJohn Birrell
134bc96366cSSteven Hartland #ifdef illumos
1356ff6d951SJohn Birrell pid = Pstatus(pp->dpp_pr)->pr_pid;
1365ec56692SJohn Birrell #else
1375ec56692SJohn Birrell pid = proc_getpid(pp->dpp_pr);
1385ec56692SJohn Birrell #endif
1396ff6d951SJohn Birrell
1406ff6d951SJohn Birrell dt_dprintf("creating probe pid%d:%s:%s:%s\n", (int)pid, pp->dpp_obj,
1416ff6d951SJohn Birrell func, pp->dpp_name);
1426ff6d951SJohn Birrell
1436ff6d951SJohn Birrell sz = sizeof (fasttrap_probe_spec_t) + (isdash ? 4 :
1446ff6d951SJohn Birrell (symp->st_size - 1) * sizeof (ftp->ftps_offs[0]));
1456ff6d951SJohn Birrell
1466ff6d951SJohn Birrell if ((ftp = dt_alloc(dtp, sz)) == NULL) {
1476ff6d951SJohn Birrell dt_dprintf("proc_per_sym: dt_alloc(%lu) failed\n", sz);
1486ff6d951SJohn Birrell return (1); /* errno is set for us */
1496ff6d951SJohn Birrell }
1506ff6d951SJohn Birrell
1516ff6d951SJohn Birrell ftp->ftps_pid = pid;
1526ff6d951SJohn Birrell (void) strncpy(ftp->ftps_func, func, sizeof (ftp->ftps_func));
1536ff6d951SJohn Birrell
1546ff6d951SJohn Birrell dt_pid_objname(ftp->ftps_mod, sizeof (ftp->ftps_mod), pp->dpp_lmid,
1556ff6d951SJohn Birrell pp->dpp_obj);
1566ff6d951SJohn Birrell
1576ff6d951SJohn Birrell if (!isdash && gmatch("return", pp->dpp_name)) {
1586ff6d951SJohn Birrell if (dt_pid_create_return_probe(pp->dpp_pr, dtp, ftp, symp,
1596ff6d951SJohn Birrell pp->dpp_stret) < 0) {
1606ff6d951SJohn Birrell return (dt_pid_error(dtp, pcb, dpr, ftp,
1616ff6d951SJohn Birrell D_PROC_CREATEFAIL, "failed to create return probe "
1626ff6d951SJohn Birrell "for '%s': %s", func,
1636ff6d951SJohn Birrell dtrace_errmsg(dtp, dtrace_errno(dtp))));
1646ff6d951SJohn Birrell }
1656ff6d951SJohn Birrell
1666ff6d951SJohn Birrell nmatches++;
1676ff6d951SJohn Birrell }
1686ff6d951SJohn Birrell
1696ff6d951SJohn Birrell if (!isdash && gmatch("entry", pp->dpp_name)) {
1706ff6d951SJohn Birrell if (dt_pid_create_entry_probe(pp->dpp_pr, dtp, ftp, symp) < 0) {
1716ff6d951SJohn Birrell return (dt_pid_error(dtp, pcb, dpr, ftp,
1726ff6d951SJohn Birrell D_PROC_CREATEFAIL, "failed to create entry probe "
1736ff6d951SJohn Birrell "for '%s': %s", func,
1746ff6d951SJohn Birrell dtrace_errmsg(dtp, dtrace_errno(dtp))));
1756ff6d951SJohn Birrell }
1766ff6d951SJohn Birrell
1776ff6d951SJohn Birrell nmatches++;
1786ff6d951SJohn Birrell }
1796ff6d951SJohn Birrell
1806ff6d951SJohn Birrell glob = strisglob(pp->dpp_name);
1816ff6d951SJohn Birrell if (!glob && nmatches == 0) {
1826ff6d951SJohn Birrell off = strtoull(pp->dpp_name, &end, 16);
1836ff6d951SJohn Birrell if (*end != '\0') {
1846ff6d951SJohn Birrell return (dt_pid_error(dtp, pcb, dpr, ftp, D_PROC_NAME,
1856ff6d951SJohn Birrell "'%s' is an invalid probe name", pp->dpp_name));
1866ff6d951SJohn Birrell }
1876ff6d951SJohn Birrell
1886ff6d951SJohn Birrell if (off >= symp->st_size) {
1896ff6d951SJohn Birrell return (dt_pid_error(dtp, pcb, dpr, ftp, D_PROC_OFF,
1906ff6d951SJohn Birrell "offset 0x%llx outside of function '%s'",
1916ff6d951SJohn Birrell (u_longlong_t)off, func));
1926ff6d951SJohn Birrell }
1936ff6d951SJohn Birrell
1946ff6d951SJohn Birrell err = dt_pid_create_offset_probe(pp->dpp_pr, pp->dpp_dtp, ftp,
1956ff6d951SJohn Birrell symp, off);
1966ff6d951SJohn Birrell
1976ff6d951SJohn Birrell if (err == DT_PROC_ERR) {
1986ff6d951SJohn Birrell return (dt_pid_error(dtp, pcb, dpr, ftp,
1996ff6d951SJohn Birrell D_PROC_CREATEFAIL, "failed to create probe at "
2006ff6d951SJohn Birrell "'%s+0x%llx': %s", func, (u_longlong_t)off,
2016ff6d951SJohn Birrell dtrace_errmsg(dtp, dtrace_errno(dtp))));
2026ff6d951SJohn Birrell }
2036ff6d951SJohn Birrell
2046ff6d951SJohn Birrell if (err == DT_PROC_ALIGN) {
2056ff6d951SJohn Birrell return (dt_pid_error(dtp, pcb, dpr, ftp, D_PROC_ALIGN,
2066ff6d951SJohn Birrell "offset 0x%llx is not aligned on an instruction",
2076ff6d951SJohn Birrell (u_longlong_t)off));
2086ff6d951SJohn Birrell }
2096ff6d951SJohn Birrell
2106ff6d951SJohn Birrell nmatches++;
2116ff6d951SJohn Birrell
2126ff6d951SJohn Birrell } else if (glob && !isdash) {
2136ff6d951SJohn Birrell if (dt_pid_create_glob_offset_probes(pp->dpp_pr,
2146ff6d951SJohn Birrell pp->dpp_dtp, ftp, symp, pp->dpp_name) < 0) {
2156ff6d951SJohn Birrell return (dt_pid_error(dtp, pcb, dpr, ftp,
2166ff6d951SJohn Birrell D_PROC_CREATEFAIL,
2176ff6d951SJohn Birrell "failed to create offset probes in '%s': %s", func,
2186ff6d951SJohn Birrell dtrace_errmsg(dtp, dtrace_errno(dtp))));
2196ff6d951SJohn Birrell }
2206ff6d951SJohn Birrell
2216ff6d951SJohn Birrell nmatches++;
2226ff6d951SJohn Birrell }
2236ff6d951SJohn Birrell
2246ff6d951SJohn Birrell pp->dpp_nmatches += nmatches;
2256ff6d951SJohn Birrell
2266ff6d951SJohn Birrell dt_free(dtp, ftp);
2276ff6d951SJohn Birrell
2286ff6d951SJohn Birrell return (0);
2296ff6d951SJohn Birrell }
2306ff6d951SJohn Birrell
2316ff6d951SJohn Birrell static int
dt_pid_sym_filt(void * arg,const GElf_Sym * symp,const char * func)2326ff6d951SJohn Birrell dt_pid_sym_filt(void *arg, const GElf_Sym *symp, const char *func)
2336ff6d951SJohn Birrell {
2346ff6d951SJohn Birrell dt_pid_probe_t *pp = arg;
2356ff6d951SJohn Birrell
2366ff6d951SJohn Birrell if (symp->st_shndx == SHN_UNDEF)
2376ff6d951SJohn Birrell return (0);
2386ff6d951SJohn Birrell
2396ff6d951SJohn Birrell if (symp->st_size == 0) {
2406ff6d951SJohn Birrell dt_dprintf("st_size of %s is zero\n", func);
2416ff6d951SJohn Birrell return (0);
2426ff6d951SJohn Birrell }
2436ff6d951SJohn Birrell
2446ff6d951SJohn Birrell if (pp->dpp_last_taken == 0 ||
2456ff6d951SJohn Birrell symp->st_value != pp->dpp_last.st_value ||
2466ff6d951SJohn Birrell symp->st_size != pp->dpp_last.st_size) {
2476ff6d951SJohn Birrell /*
2486ff6d951SJohn Birrell * Due to 4524008, _init and _fini may have a bloated st_size.
2496ff6d951SJohn Birrell * While this bug has been fixed for a while, old binaries
2506ff6d951SJohn Birrell * may exist that still exhibit this problem. As a result, we
2516ff6d951SJohn Birrell * don't match _init and _fini though we allow users to
2526ff6d951SJohn Birrell * specify them explicitly.
2536ff6d951SJohn Birrell */
2546ff6d951SJohn Birrell if (strcmp(func, "_init") == 0 || strcmp(func, "_fini") == 0)
2556ff6d951SJohn Birrell return (0);
2566ff6d951SJohn Birrell
2576ff6d951SJohn Birrell if ((pp->dpp_last_taken = gmatch(func, pp->dpp_func)) != 0) {
2586ff6d951SJohn Birrell pp->dpp_last = *symp;
2596ff6d951SJohn Birrell return (dt_pid_per_sym(pp, symp, func));
2606ff6d951SJohn Birrell }
2616ff6d951SJohn Birrell }
2626ff6d951SJohn Birrell
2636ff6d951SJohn Birrell return (0);
2646ff6d951SJohn Birrell }
2656ff6d951SJohn Birrell
2666ff6d951SJohn Birrell static int
dt_pid_per_mod(void * arg,const prmap_t * pmp,const char * obj)2676ff6d951SJohn Birrell dt_pid_per_mod(void *arg, const prmap_t *pmp, const char *obj)
2686ff6d951SJohn Birrell {
2696ff6d951SJohn Birrell dt_pid_probe_t *pp = arg;
2706ff6d951SJohn Birrell dtrace_hdl_t *dtp = pp->dpp_dtp;
2716ff6d951SJohn Birrell dt_pcb_t *pcb = pp->dpp_pcb;
2726ff6d951SJohn Birrell dt_proc_t *dpr = pp->dpp_dpr;
2736ff6d951SJohn Birrell GElf_Sym sym;
2746ff6d951SJohn Birrell
2756ff6d951SJohn Birrell if (obj == NULL)
2766ff6d951SJohn Birrell return (0);
2776ff6d951SJohn Birrell
278bc96366cSSteven Hartland #ifdef illumos
2796ff6d951SJohn Birrell (void) Plmid(pp->dpp_pr, pmp->pr_vaddr, &pp->dpp_lmid);
2805ec56692SJohn Birrell #endif
2815ec56692SJohn Birrell
2826ff6d951SJohn Birrell
2836ff6d951SJohn Birrell if ((pp->dpp_obj = strrchr(obj, '/')) == NULL)
2846ff6d951SJohn Birrell pp->dpp_obj = obj;
2856ff6d951SJohn Birrell else
2866ff6d951SJohn Birrell pp->dpp_obj++;
287bc96366cSSteven Hartland #ifdef illumos
2886ff6d951SJohn Birrell if (Pxlookup_by_name(pp->dpp_pr, pp->dpp_lmid, obj, ".stret1", &sym,
2896ff6d951SJohn Birrell NULL) == 0)
2906ff6d951SJohn Birrell pp->dpp_stret[0] = sym.st_value;
2916ff6d951SJohn Birrell else
2926ff6d951SJohn Birrell pp->dpp_stret[0] = 0;
2936ff6d951SJohn Birrell
2946ff6d951SJohn Birrell if (Pxlookup_by_name(pp->dpp_pr, pp->dpp_lmid, obj, ".stret2", &sym,
2956ff6d951SJohn Birrell NULL) == 0)
2966ff6d951SJohn Birrell pp->dpp_stret[1] = sym.st_value;
2976ff6d951SJohn Birrell else
2986ff6d951SJohn Birrell pp->dpp_stret[1] = 0;
2996ff6d951SJohn Birrell
3006ff6d951SJohn Birrell if (Pxlookup_by_name(pp->dpp_pr, pp->dpp_lmid, obj, ".stret4", &sym,
3016ff6d951SJohn Birrell NULL) == 0)
3026ff6d951SJohn Birrell pp->dpp_stret[2] = sym.st_value;
3036ff6d951SJohn Birrell else
3046ff6d951SJohn Birrell pp->dpp_stret[2] = 0;
3056ff6d951SJohn Birrell
3066ff6d951SJohn Birrell if (Pxlookup_by_name(pp->dpp_pr, pp->dpp_lmid, obj, ".stret8", &sym,
3076ff6d951SJohn Birrell NULL) == 0)
3086ff6d951SJohn Birrell pp->dpp_stret[3] = sym.st_value;
3096ff6d951SJohn Birrell else
3106ff6d951SJohn Birrell pp->dpp_stret[3] = 0;
3115ec56692SJohn Birrell #else
3125ec56692SJohn Birrell pp->dpp_stret[0] = 0;
3135ec56692SJohn Birrell pp->dpp_stret[1] = 0;
3145ec56692SJohn Birrell pp->dpp_stret[2] = 0;
3155ec56692SJohn Birrell pp->dpp_stret[3] = 0;
3165ec56692SJohn Birrell #endif
3176ff6d951SJohn Birrell
3186ff6d951SJohn Birrell dt_dprintf("%s stret %llx %llx %llx %llx\n", obj,
3196ff6d951SJohn Birrell (u_longlong_t)pp->dpp_stret[0], (u_longlong_t)pp->dpp_stret[1],
3206ff6d951SJohn Birrell (u_longlong_t)pp->dpp_stret[2], (u_longlong_t)pp->dpp_stret[3]);
3216ff6d951SJohn Birrell
3226ff6d951SJohn Birrell /*
3236ff6d951SJohn Birrell * If pp->dpp_func contains any globbing meta-characters, we need
3246ff6d951SJohn Birrell * to iterate over the symbol table and compare each function name
3256ff6d951SJohn Birrell * against the pattern.
3266ff6d951SJohn Birrell */
3276ff6d951SJohn Birrell if (!strisglob(pp->dpp_func)) {
3286ff6d951SJohn Birrell /*
3296ff6d951SJohn Birrell * If we fail to lookup the symbol, try interpreting the
3306ff6d951SJohn Birrell * function as the special "-" function that indicates that the
3316ff6d951SJohn Birrell * probe name should be interpreted as a absolute virtual
3326ff6d951SJohn Birrell * address. If that fails and we were matching a specific
3336ff6d951SJohn Birrell * function in a specific module, report the error, otherwise
3346ff6d951SJohn Birrell * just fail silently in the hopes that some other object will
3356ff6d951SJohn Birrell * contain the desired symbol.
3366ff6d951SJohn Birrell */
3376ff6d951SJohn Birrell if (Pxlookup_by_name(pp->dpp_pr, pp->dpp_lmid, obj,
3386ff6d951SJohn Birrell pp->dpp_func, &sym, NULL) != 0) {
3396ff6d951SJohn Birrell if (strcmp("-", pp->dpp_func) == 0) {
3406ff6d951SJohn Birrell sym.st_name = 0;
3416ff6d951SJohn Birrell sym.st_info =
3426ff6d951SJohn Birrell GELF_ST_INFO(STB_LOCAL, STT_FUNC);
3436ff6d951SJohn Birrell sym.st_other = 0;
3446ff6d951SJohn Birrell sym.st_value = 0;
345bc96366cSSteven Hartland #ifdef illumos
3466ff6d951SJohn Birrell sym.st_size = Pstatus(pp->dpp_pr)->pr_dmodel ==
3476ff6d951SJohn Birrell PR_MODEL_ILP32 ? -1U : -1ULL;
3485ec56692SJohn Birrell #else
3495ec56692SJohn Birrell sym.st_size = ~((Elf64_Xword) 0);
3505ec56692SJohn Birrell #endif
3516ff6d951SJohn Birrell
3526ff6d951SJohn Birrell } else if (!strisglob(pp->dpp_mod)) {
3536ff6d951SJohn Birrell return (dt_pid_error(dtp, pcb, dpr, NULL,
3546ff6d951SJohn Birrell D_PROC_FUNC,
3556ff6d951SJohn Birrell "failed to lookup '%s' in module '%s'",
3566ff6d951SJohn Birrell pp->dpp_func, pp->dpp_mod));
3576ff6d951SJohn Birrell } else {
3586ff6d951SJohn Birrell return (0);
3596ff6d951SJohn Birrell }
3606ff6d951SJohn Birrell }
3616ff6d951SJohn Birrell
3626ff6d951SJohn Birrell /*
3636ff6d951SJohn Birrell * Only match defined functions of non-zero size.
3646ff6d951SJohn Birrell */
3656ff6d951SJohn Birrell if (GELF_ST_TYPE(sym.st_info) != STT_FUNC ||
3666ff6d951SJohn Birrell sym.st_shndx == SHN_UNDEF || sym.st_size == 0)
3676ff6d951SJohn Birrell return (0);
3686ff6d951SJohn Birrell
3696ff6d951SJohn Birrell /*
3706ff6d951SJohn Birrell * We don't instrument PLTs -- they're dynamically rewritten,
3716ff6d951SJohn Birrell * and, so, inherently dicey to instrument.
3726ff6d951SJohn Birrell */
3735ec56692SJohn Birrell #ifdef DOODAD
3746ff6d951SJohn Birrell if (Ppltdest(pp->dpp_pr, sym.st_value) != NULL)
3756ff6d951SJohn Birrell return (0);
3765ec56692SJohn Birrell #endif
3776ff6d951SJohn Birrell
3786ff6d951SJohn Birrell (void) Plookup_by_addr(pp->dpp_pr, sym.st_value, pp->dpp_func,
3796ff6d951SJohn Birrell DTRACE_FUNCNAMELEN, &sym);
3806ff6d951SJohn Birrell
3816ff6d951SJohn Birrell return (dt_pid_per_sym(pp, &sym, pp->dpp_func));
3826ff6d951SJohn Birrell } else {
3836ff6d951SJohn Birrell uint_t nmatches = pp->dpp_nmatches;
3846ff6d951SJohn Birrell
3856ff6d951SJohn Birrell if (Psymbol_iter_by_addr(pp->dpp_pr, obj, PR_SYMTAB,
3866ff6d951SJohn Birrell BIND_ANY | TYPE_FUNC, dt_pid_sym_filt, pp) == 1)
3876ff6d951SJohn Birrell return (1);
3886ff6d951SJohn Birrell
3896ff6d951SJohn Birrell if (nmatches == pp->dpp_nmatches) {
3906ff6d951SJohn Birrell /*
3916ff6d951SJohn Birrell * If we didn't match anything in the PR_SYMTAB, try
3926ff6d951SJohn Birrell * the PR_DYNSYM.
3936ff6d951SJohn Birrell */
3946ff6d951SJohn Birrell if (Psymbol_iter_by_addr(pp->dpp_pr, obj, PR_DYNSYM,
3956ff6d951SJohn Birrell BIND_ANY | TYPE_FUNC, dt_pid_sym_filt, pp) == 1)
3966ff6d951SJohn Birrell return (1);
3976ff6d951SJohn Birrell }
3986ff6d951SJohn Birrell }
3996ff6d951SJohn Birrell
4006ff6d951SJohn Birrell return (0);
4016ff6d951SJohn Birrell }
4026ff6d951SJohn Birrell
4036ff6d951SJohn Birrell static int
dt_pid_mod_filt(void * arg,const prmap_t * pmp,const char * obj)4046ff6d951SJohn Birrell dt_pid_mod_filt(void *arg, const prmap_t *pmp, const char *obj)
4056ff6d951SJohn Birrell {
4066ff6d951SJohn Birrell char name[DTRACE_MODNAMELEN];
4076ff6d951SJohn Birrell dt_pid_probe_t *pp = arg;
4086ff6d951SJohn Birrell
4096ff6d951SJohn Birrell if (gmatch(obj, pp->dpp_mod))
4106ff6d951SJohn Birrell return (dt_pid_per_mod(pp, pmp, obj));
4116ff6d951SJohn Birrell
412bc96366cSSteven Hartland #ifdef illumos
4136ff6d951SJohn Birrell (void) Plmid(pp->dpp_pr, pmp->pr_vaddr, &pp->dpp_lmid);
4145ec56692SJohn Birrell #else
4155ec56692SJohn Birrell pp->dpp_lmid = 0;
4165ec56692SJohn Birrell #endif
4176ff6d951SJohn Birrell
4186ff6d951SJohn Birrell if ((pp->dpp_obj = strrchr(obj, '/')) == NULL)
4196ff6d951SJohn Birrell pp->dpp_obj = obj;
4206ff6d951SJohn Birrell else
4216ff6d951SJohn Birrell pp->dpp_obj++;
4226ff6d951SJohn Birrell
4231670a1c2SRui Paulo if (gmatch(pp->dpp_obj, pp->dpp_mod))
4241670a1c2SRui Paulo return (dt_pid_per_mod(pp, pmp, obj));
4251670a1c2SRui Paulo
426bc96366cSSteven Hartland #ifdef illumos
4271670a1c2SRui Paulo (void) Plmid(pp->dpp_pr, pmp->pr_vaddr, &pp->dpp_lmid);
42831a396adSRui Paulo #endif
4291670a1c2SRui Paulo
4301670a1c2SRui Paulo dt_pid_objname(name, sizeof (name), pp->dpp_lmid, pp->dpp_obj);
4316ff6d951SJohn Birrell
4326ff6d951SJohn Birrell if (gmatch(name, pp->dpp_mod))
4336ff6d951SJohn Birrell return (dt_pid_per_mod(pp, pmp, obj));
4346ff6d951SJohn Birrell
4356ff6d951SJohn Birrell return (0);
4366ff6d951SJohn Birrell }
4376ff6d951SJohn Birrell
4386ff6d951SJohn Birrell static const prmap_t *
dt_pid_fix_mod(dtrace_probedesc_t * pdp,struct ps_prochandle * P)4396ff6d951SJohn Birrell dt_pid_fix_mod(dtrace_probedesc_t *pdp, struct ps_prochandle *P)
4406ff6d951SJohn Birrell {
4416ff6d951SJohn Birrell char m[MAXPATHLEN];
4426ff6d951SJohn Birrell Lmid_t lmid = PR_LMID_EVERY;
4430f2bd1e8SRui Paulo const char *obj;
4446ff6d951SJohn Birrell const prmap_t *pmp;
4456ff6d951SJohn Birrell
4466ff6d951SJohn Birrell /*
4476ff6d951SJohn Birrell * Pick apart the link map from the library name.
4486ff6d951SJohn Birrell */
4496ff6d951SJohn Birrell if (strchr(pdp->dtpd_mod, '`') != NULL) {
4506ff6d951SJohn Birrell char *end;
4516ff6d951SJohn Birrell
4526ff6d951SJohn Birrell if (strncmp(pdp->dtpd_mod, "LM", 2) != 0 ||
4536ff6d951SJohn Birrell !isdigit(pdp->dtpd_mod[2]))
4546ff6d951SJohn Birrell return (NULL);
4556ff6d951SJohn Birrell
4566ff6d951SJohn Birrell lmid = strtoul(&pdp->dtpd_mod[2], &end, 16);
4576ff6d951SJohn Birrell
4586ff6d951SJohn Birrell obj = end + 1;
4596ff6d951SJohn Birrell
4606ff6d951SJohn Birrell if (*end != '`' || strchr(obj, '`') != NULL)
4616ff6d951SJohn Birrell return (NULL);
4626ff6d951SJohn Birrell
4636ff6d951SJohn Birrell } else {
4646ff6d951SJohn Birrell obj = pdp->dtpd_mod;
4656ff6d951SJohn Birrell }
4666ff6d951SJohn Birrell
4676ff6d951SJohn Birrell if ((pmp = Plmid_to_map(P, lmid, obj)) == NULL)
4686ff6d951SJohn Birrell return (NULL);
4696ff6d951SJohn Birrell
4706ff6d951SJohn Birrell (void) Pobjname(P, pmp->pr_vaddr, m, sizeof (m));
4716ff6d951SJohn Birrell if ((obj = strrchr(m, '/')) == NULL)
4726ff6d951SJohn Birrell obj = &m[0];
4736ff6d951SJohn Birrell else
4746ff6d951SJohn Birrell obj++;
4756ff6d951SJohn Birrell
476bc96366cSSteven Hartland #ifdef illumos
4776ff6d951SJohn Birrell (void) Plmid(P, pmp->pr_vaddr, &lmid);
4780f2bd1e8SRui Paulo #endif
4795ec56692SJohn Birrell
4806ff6d951SJohn Birrell dt_pid_objname(pdp->dtpd_mod, sizeof (pdp->dtpd_mod), lmid, obj);
4816ff6d951SJohn Birrell
4826ff6d951SJohn Birrell return (pmp);
4836ff6d951SJohn Birrell }
4846ff6d951SJohn Birrell
4856ff6d951SJohn Birrell
4866ff6d951SJohn Birrell static int
dt_pid_create_pid_probes(dtrace_probedesc_t * pdp,dtrace_hdl_t * dtp,dt_pcb_t * pcb,dt_proc_t * dpr)4876ff6d951SJohn Birrell dt_pid_create_pid_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp,
4886ff6d951SJohn Birrell dt_pcb_t *pcb, dt_proc_t *dpr)
4896ff6d951SJohn Birrell {
4906ff6d951SJohn Birrell dt_pid_probe_t pp;
4916ff6d951SJohn Birrell int ret = 0;
4926ff6d951SJohn Birrell
4936ff6d951SJohn Birrell pp.dpp_dtp = dtp;
4946ff6d951SJohn Birrell pp.dpp_dpr = dpr;
4956ff6d951SJohn Birrell pp.dpp_pr = dpr->dpr_proc;
4966ff6d951SJohn Birrell pp.dpp_pcb = pcb;
4976ff6d951SJohn Birrell
4985ec56692SJohn Birrell #ifdef DOODAD
4996ff6d951SJohn Birrell /*
5006ff6d951SJohn Birrell * We can only trace dynamically-linked executables (since we've
5016ff6d951SJohn Birrell * hidden some magic in ld.so.1 as well as libc.so.1).
5026ff6d951SJohn Birrell */
5036ff6d951SJohn Birrell if (Pname_to_map(pp.dpp_pr, PR_OBJ_LDSO) == NULL) {
5046ff6d951SJohn Birrell return (dt_pid_error(dtp, pcb, dpr, NULL, D_PROC_DYN,
5056ff6d951SJohn Birrell "process %s is not a dynamically-linked executable",
5066ff6d951SJohn Birrell &pdp->dtpd_provider[3]));
5076ff6d951SJohn Birrell }
5085ec56692SJohn Birrell #endif
5096ff6d951SJohn Birrell
5106ff6d951SJohn Birrell pp.dpp_mod = pdp->dtpd_mod[0] != '\0' ? pdp->dtpd_mod : "*";
5116ff6d951SJohn Birrell pp.dpp_func = pdp->dtpd_func[0] != '\0' ? pdp->dtpd_func : "*";
5126ff6d951SJohn Birrell pp.dpp_name = pdp->dtpd_name[0] != '\0' ? pdp->dtpd_name : "*";
5136ff6d951SJohn Birrell pp.dpp_last_taken = 0;
5146ff6d951SJohn Birrell
5156ff6d951SJohn Birrell if (strcmp(pp.dpp_func, "-") == 0) {
5166ff6d951SJohn Birrell const prmap_t *aout, *pmp;
5176ff6d951SJohn Birrell
5186ff6d951SJohn Birrell if (pdp->dtpd_mod[0] == '\0') {
5196ff6d951SJohn Birrell pp.dpp_mod = pdp->dtpd_mod;
5206ff6d951SJohn Birrell (void) strcpy(pdp->dtpd_mod, "a.out");
5216ff6d951SJohn Birrell } else if (strisglob(pp.dpp_mod) ||
5226ff6d951SJohn Birrell (aout = Pname_to_map(pp.dpp_pr, "a.out")) == NULL ||
5236ff6d951SJohn Birrell (pmp = Pname_to_map(pp.dpp_pr, pp.dpp_mod)) == NULL ||
5246ff6d951SJohn Birrell aout->pr_vaddr != pmp->pr_vaddr) {
5256ff6d951SJohn Birrell return (dt_pid_error(dtp, pcb, dpr, NULL, D_PROC_LIB,
5266ff6d951SJohn Birrell "only the a.out module is valid with the "
5276ff6d951SJohn Birrell "'-' function"));
5286ff6d951SJohn Birrell }
5296ff6d951SJohn Birrell
5306ff6d951SJohn Birrell if (strisglob(pp.dpp_name)) {
5316ff6d951SJohn Birrell return (dt_pid_error(dtp, pcb, dpr, NULL, D_PROC_NAME,
5326ff6d951SJohn Birrell "only individual addresses may be specified "
5336ff6d951SJohn Birrell "with the '-' function"));
5346ff6d951SJohn Birrell }
5356ff6d951SJohn Birrell }
5366ff6d951SJohn Birrell
5376ff6d951SJohn Birrell /*
5386ff6d951SJohn Birrell * If pp.dpp_mod contains any globbing meta-characters, we need
5396ff6d951SJohn Birrell * to iterate over each module and compare its name against the
5406ff6d951SJohn Birrell * pattern. An empty module name is treated as '*'.
5416ff6d951SJohn Birrell */
5426ff6d951SJohn Birrell if (strisglob(pp.dpp_mod)) {
5436ff6d951SJohn Birrell ret = Pobject_iter(pp.dpp_pr, dt_pid_mod_filt, &pp);
5446ff6d951SJohn Birrell } else {
5456ff6d951SJohn Birrell const prmap_t *pmp;
5466ff6d951SJohn Birrell char *obj;
5476ff6d951SJohn Birrell
5486ff6d951SJohn Birrell /*
5496ff6d951SJohn Birrell * If we can't find a matching module, don't sweat it -- either
5506ff6d951SJohn Birrell * we'll fail the enabling because the probes don't exist or
5516ff6d951SJohn Birrell * we'll wait for that module to come along.
5526ff6d951SJohn Birrell */
5536ff6d951SJohn Birrell if ((pmp = dt_pid_fix_mod(pdp, pp.dpp_pr)) != NULL) {
5546ff6d951SJohn Birrell if ((obj = strchr(pdp->dtpd_mod, '`')) == NULL)
5556ff6d951SJohn Birrell obj = pdp->dtpd_mod;
5566ff6d951SJohn Birrell else
5576ff6d951SJohn Birrell obj++;
5586ff6d951SJohn Birrell
5596ff6d951SJohn Birrell ret = dt_pid_per_mod(&pp, pmp, obj);
5606ff6d951SJohn Birrell }
5616ff6d951SJohn Birrell }
5626ff6d951SJohn Birrell
5636ff6d951SJohn Birrell return (ret);
5646ff6d951SJohn Birrell }
5656ff6d951SJohn Birrell
5666ff6d951SJohn Birrell static int
dt_pid_usdt_mapping(void * data,const prmap_t * pmp,const char * oname)5676ff6d951SJohn Birrell dt_pid_usdt_mapping(void *data, const prmap_t *pmp, const char *oname)
5686ff6d951SJohn Birrell {
5696ff6d951SJohn Birrell struct ps_prochandle *P = data;
5706ff6d951SJohn Birrell GElf_Sym sym;
5716ff6d951SJohn Birrell prsyminfo_t sip;
5726ff6d951SJohn Birrell dof_helper_t dh;
5736ff6d951SJohn Birrell GElf_Half e_type;
5746ff6d951SJohn Birrell const char *mname;
5756ff6d951SJohn Birrell const char *syms[] = { "___SUNW_dof", "__SUNW_dof" };
5766ff6d951SJohn Birrell int i, fd = -1;
5776ff6d951SJohn Birrell
5786ff6d951SJohn Birrell /*
5796ff6d951SJohn Birrell * The symbol ___SUNW_dof is for lazy-loaded DOF sections, and
5806ff6d951SJohn Birrell * __SUNW_dof is for actively-loaded DOF sections. We try to force
5816ff6d951SJohn Birrell * in both types of DOF section since the process may not yet have
5826ff6d951SJohn Birrell * run the code to instantiate these providers.
5836ff6d951SJohn Birrell */
5846ff6d951SJohn Birrell for (i = 0; i < 2; i++) {
5856ff6d951SJohn Birrell if (Pxlookup_by_name(P, PR_LMID_EVERY, oname, syms[i], &sym,
5866ff6d951SJohn Birrell &sip) != 0) {
5876ff6d951SJohn Birrell continue;
5886ff6d951SJohn Birrell }
5896ff6d951SJohn Birrell
5906ff6d951SJohn Birrell if ((mname = strrchr(oname, '/')) == NULL)
5916ff6d951SJohn Birrell mname = oname;
5926ff6d951SJohn Birrell else
5936ff6d951SJohn Birrell mname++;
5946ff6d951SJohn Birrell
5956ff6d951SJohn Birrell dt_dprintf("lookup of %s succeeded for %s\n", syms[i], mname);
5966ff6d951SJohn Birrell
5976ff6d951SJohn Birrell if (Pread(P, &e_type, sizeof (e_type), pmp->pr_vaddr +
5986ff6d951SJohn Birrell offsetof(Elf64_Ehdr, e_type)) != sizeof (e_type)) {
5996ff6d951SJohn Birrell dt_dprintf("read of ELF header failed");
6006ff6d951SJohn Birrell continue;
6016ff6d951SJohn Birrell }
6026ff6d951SJohn Birrell
6036ff6d951SJohn Birrell dh.dofhp_dof = sym.st_value;
6046ff6d951SJohn Birrell dh.dofhp_addr = (e_type == ET_EXEC) ? 0 : pmp->pr_vaddr;
6056ff6d951SJohn Birrell
6066ff6d951SJohn Birrell dt_pid_objname(dh.dofhp_mod, sizeof (dh.dofhp_mod),
6076ff6d951SJohn Birrell sip.prs_lmid, mname);
6086ff6d951SJohn Birrell
6096e0f204cSMark Johnston #ifdef __FreeBSD__
6106e0f204cSMark Johnston dh.dofhp_pid = proc_getpid(P);
6116e0f204cSMark Johnston
6126e0f204cSMark Johnston if (fd == -1 &&
6136e0f204cSMark Johnston (fd = open("/dev/dtrace/helper", O_RDWR, 0)) < 0) {
6146e0f204cSMark Johnston dt_dprintf("open of helper device failed: %s\n",
6156e0f204cSMark Johnston strerror(errno));
6166e0f204cSMark Johnston return (-1); /* errno is set for us */
6176e0f204cSMark Johnston }
6186e0f204cSMark Johnston
6196e0f204cSMark Johnston if (ioctl(fd, DTRACEHIOC_ADDDOF, &dh, sizeof (dh)) < 0)
6206e0f204cSMark Johnston dt_dprintf("DOF was rejected for %s\n", dh.dofhp_mod);
6216e0f204cSMark Johnston #else
6226ff6d951SJohn Birrell if (fd == -1 &&
6236ff6d951SJohn Birrell (fd = pr_open(P, "/dev/dtrace/helper", O_RDWR, 0)) < 0) {
6246ff6d951SJohn Birrell dt_dprintf("pr_open of helper device failed: %s\n",
6256ff6d951SJohn Birrell strerror(errno));
6266ff6d951SJohn Birrell return (-1); /* errno is set for us */
6276ff6d951SJohn Birrell }
6286ff6d951SJohn Birrell
6296ff6d951SJohn Birrell if (pr_ioctl(P, fd, DTRACEHIOC_ADDDOF, &dh, sizeof (dh)) < 0)
6306ff6d951SJohn Birrell dt_dprintf("DOF was rejected for %s\n", dh.dofhp_mod);
6315ec56692SJohn Birrell #endif
6326ff6d951SJohn Birrell }
6336ff6d951SJohn Birrell
6346ff6d951SJohn Birrell if (fd != -1)
63567cf27b7SMark Johnston #ifdef __FreeBSD__
63667cf27b7SMark Johnston (void) close(fd);
63767cf27b7SMark Johnston #else
6386ff6d951SJohn Birrell (void) pr_close(P, fd);
6395ec56692SJohn Birrell #endif
6406ff6d951SJohn Birrell
6416ff6d951SJohn Birrell return (0);
6426ff6d951SJohn Birrell }
6436ff6d951SJohn Birrell
6446ff6d951SJohn Birrell static int
dt_pid_create_usdt_probes(dtrace_probedesc_t * pdp,dtrace_hdl_t * dtp,dt_pcb_t * pcb,dt_proc_t * dpr)6456ff6d951SJohn Birrell dt_pid_create_usdt_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp,
6466ff6d951SJohn Birrell dt_pcb_t *pcb, dt_proc_t *dpr)
6476ff6d951SJohn Birrell {
6486ff6d951SJohn Birrell struct ps_prochandle *P = dpr->dpr_proc;
6496ff6d951SJohn Birrell int ret = 0;
6506ff6d951SJohn Birrell
65131a396adSRui Paulo assert(DT_MUTEX_HELD(&dpr->dpr_lock));
6526ff6d951SJohn Birrell (void) Pupdate_maps(P);
6536ff6d951SJohn Birrell if (Pobject_iter(P, dt_pid_usdt_mapping, P) != 0) {
6546ff6d951SJohn Birrell ret = -1;
6556ff6d951SJohn Birrell (void) dt_pid_error(dtp, pcb, dpr, NULL, D_PROC_USDT,
6566ff6d951SJohn Birrell "failed to instantiate probes for pid %d: %s",
657bc96366cSSteven Hartland #ifdef illumos
6586ff6d951SJohn Birrell (int)Pstatus(P)->pr_pid, strerror(errno));
6595ec56692SJohn Birrell #else
6605ec56692SJohn Birrell (int)proc_getpid(P), strerror(errno));
6615ec56692SJohn Birrell #endif
6626ff6d951SJohn Birrell }
6636ff6d951SJohn Birrell
6646ff6d951SJohn Birrell /*
6656ff6d951SJohn Birrell * Put the module name in its canonical form.
6666ff6d951SJohn Birrell */
6676ff6d951SJohn Birrell (void) dt_pid_fix_mod(pdp, P);
6686ff6d951SJohn Birrell
6696ff6d951SJohn Birrell return (ret);
6706ff6d951SJohn Birrell }
6716ff6d951SJohn Birrell
6726ff6d951SJohn Birrell static pid_t
dt_pid_get_pid(dtrace_probedesc_t * pdp,dtrace_hdl_t * dtp,dt_pcb_t * pcb,dt_proc_t * dpr)6736ff6d951SJohn Birrell dt_pid_get_pid(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb,
6746ff6d951SJohn Birrell dt_proc_t *dpr)
6756ff6d951SJohn Birrell {
6766ff6d951SJohn Birrell pid_t pid;
6776ff6d951SJohn Birrell char *c, *last = NULL, *end;
6786ff6d951SJohn Birrell
6796ff6d951SJohn Birrell for (c = &pdp->dtpd_provider[0]; *c != '\0'; c++) {
6806ff6d951SJohn Birrell if (!isdigit(*c))
6816ff6d951SJohn Birrell last = c;
6826ff6d951SJohn Birrell }
6836ff6d951SJohn Birrell
6846ff6d951SJohn Birrell if (last == NULL || (*(++last) == '\0')) {
6856ff6d951SJohn Birrell (void) dt_pid_error(dtp, pcb, dpr, NULL, D_PROC_BADPROV,
6866ff6d951SJohn Birrell "'%s' is not a valid provider", pdp->dtpd_provider);
6876ff6d951SJohn Birrell return (-1);
6886ff6d951SJohn Birrell }
6896ff6d951SJohn Birrell
6906ff6d951SJohn Birrell errno = 0;
6916ff6d951SJohn Birrell pid = strtol(last, &end, 10);
6926ff6d951SJohn Birrell
6936ff6d951SJohn Birrell if (errno != 0 || end == last || end[0] != '\0' || pid <= 0) {
6946ff6d951SJohn Birrell (void) dt_pid_error(dtp, pcb, dpr, NULL, D_PROC_BADPID,
6956ff6d951SJohn Birrell "'%s' does not contain a valid pid", pdp->dtpd_provider);
6966ff6d951SJohn Birrell return (-1);
6976ff6d951SJohn Birrell }
6986ff6d951SJohn Birrell
6996ff6d951SJohn Birrell return (pid);
7006ff6d951SJohn Birrell }
7016ff6d951SJohn Birrell
7026ff6d951SJohn Birrell int
dt_pid_create_probes(dtrace_probedesc_t * pdp,dtrace_hdl_t * dtp,dt_pcb_t * pcb)7036ff6d951SJohn Birrell dt_pid_create_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb)
7046ff6d951SJohn Birrell {
7056ff6d951SJohn Birrell char provname[DTRACE_PROVNAMELEN];
7066ff6d951SJohn Birrell struct ps_prochandle *P;
7076ff6d951SJohn Birrell dt_proc_t *dpr;
7086ff6d951SJohn Birrell pid_t pid;
7096ff6d951SJohn Birrell int err = 0;
7106ff6d951SJohn Birrell
7116ff6d951SJohn Birrell assert(pcb != NULL);
7126ff6d951SJohn Birrell
7136ff6d951SJohn Birrell if ((pid = dt_pid_get_pid(pdp, dtp, pcb, NULL)) == -1)
7146ff6d951SJohn Birrell return (-1);
7156ff6d951SJohn Birrell
7166ff6d951SJohn Birrell if (dtp->dt_ftfd == -1) {
7176ff6d951SJohn Birrell if (dtp->dt_fterr == ENOENT) {
7186ff6d951SJohn Birrell (void) dt_pid_error(dtp, pcb, NULL, NULL, D_PROC_NODEV,
7196ff6d951SJohn Birrell "pid provider is not installed on this system");
7206ff6d951SJohn Birrell } else {
7216ff6d951SJohn Birrell (void) dt_pid_error(dtp, pcb, NULL, NULL, D_PROC_NODEV,
7226ff6d951SJohn Birrell "pid provider is not available: %s",
7236ff6d951SJohn Birrell strerror(dtp->dt_fterr));
7246ff6d951SJohn Birrell }
7256ff6d951SJohn Birrell
7266ff6d951SJohn Birrell return (-1);
7276ff6d951SJohn Birrell }
7286ff6d951SJohn Birrell
7296ff6d951SJohn Birrell (void) snprintf(provname, sizeof (provname), "pid%d", (int)pid);
7306ff6d951SJohn Birrell
7316ff6d951SJohn Birrell if (gmatch(provname, pdp->dtpd_provider) != 0) {
732*e0d70fc1SMark Johnston #ifdef __FreeBSD__
733*e0d70fc1SMark Johnston if ((P = dt_proc_grab(dtp, pid, 0, 1)) == NULL)
734*e0d70fc1SMark Johnston #else
7356ff6d951SJohn Birrell if ((P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE,
736*e0d70fc1SMark Johnston 0)) == NULL)
737*e0d70fc1SMark Johnston #endif
738*e0d70fc1SMark Johnston {
7396ff6d951SJohn Birrell (void) dt_pid_error(dtp, pcb, NULL, NULL, D_PROC_GRAB,
7406ff6d951SJohn Birrell "failed to grab process %d", (int)pid);
7416ff6d951SJohn Birrell return (-1);
7426ff6d951SJohn Birrell }
7436ff6d951SJohn Birrell
7446ff6d951SJohn Birrell dpr = dt_proc_lookup(dtp, P, 0);
7456ff6d951SJohn Birrell assert(dpr != NULL);
7466ff6d951SJohn Birrell (void) pthread_mutex_lock(&dpr->dpr_lock);
7476ff6d951SJohn Birrell
7485ec56692SJohn Birrell if ((err = dt_pid_create_pid_probes(pdp, dtp, pcb, dpr)) == 0) {
7495ec56692SJohn Birrell /*
7505ec56692SJohn Birrell * Alert other retained enablings which may match
7515ec56692SJohn Birrell * against the newly created probes.
7525ec56692SJohn Birrell */
7535ec56692SJohn Birrell (void) dt_ioctl(dtp, DTRACEIOC_ENABLE, NULL);
7545ec56692SJohn Birrell }
7556ff6d951SJohn Birrell
7566ff6d951SJohn Birrell (void) pthread_mutex_unlock(&dpr->dpr_lock);
7576ff6d951SJohn Birrell dt_proc_release(dtp, P);
7586ff6d951SJohn Birrell }
7596ff6d951SJohn Birrell
7606ff6d951SJohn Birrell /*
7616ff6d951SJohn Birrell * If it's not strictly a pid provider, we might match a USDT provider.
7626ff6d951SJohn Birrell */
7636ff6d951SJohn Birrell if (strcmp(provname, pdp->dtpd_provider) != 0) {
7646ff6d951SJohn Birrell if ((P = dt_proc_grab(dtp, pid, 0, 1)) == NULL) {
7656ff6d951SJohn Birrell (void) dt_pid_error(dtp, pcb, NULL, NULL, D_PROC_GRAB,
7666ff6d951SJohn Birrell "failed to grab process %d", (int)pid);
7676ff6d951SJohn Birrell return (-1);
7686ff6d951SJohn Birrell }
7696ff6d951SJohn Birrell
7706ff6d951SJohn Birrell dpr = dt_proc_lookup(dtp, P, 0);
7716ff6d951SJohn Birrell assert(dpr != NULL);
7726ff6d951SJohn Birrell (void) pthread_mutex_lock(&dpr->dpr_lock);
7736ff6d951SJohn Birrell
7746ff6d951SJohn Birrell if (!dpr->dpr_usdt) {
7756ff6d951SJohn Birrell err = dt_pid_create_usdt_probes(pdp, dtp, pcb, dpr);
7766ff6d951SJohn Birrell dpr->dpr_usdt = B_TRUE;
7776ff6d951SJohn Birrell }
7786ff6d951SJohn Birrell
7796ff6d951SJohn Birrell (void) pthread_mutex_unlock(&dpr->dpr_lock);
7806ff6d951SJohn Birrell dt_proc_release(dtp, P);
7816ff6d951SJohn Birrell }
7826ff6d951SJohn Birrell
7836ff6d951SJohn Birrell return (err ? -1 : 0);
7846ff6d951SJohn Birrell }
7856ff6d951SJohn Birrell
7866ff6d951SJohn Birrell int
dt_pid_create_probes_module(dtrace_hdl_t * dtp,dt_proc_t * dpr)7876ff6d951SJohn Birrell dt_pid_create_probes_module(dtrace_hdl_t *dtp, dt_proc_t *dpr)
7886ff6d951SJohn Birrell {
7895ec56692SJohn Birrell dtrace_enable_io_t args;
7906ff6d951SJohn Birrell dtrace_prog_t *pgp;
7916ff6d951SJohn Birrell dt_stmt_t *stp;
7926ff6d951SJohn Birrell dtrace_probedesc_t *pdp, pd;
7936ff6d951SJohn Birrell pid_t pid;
7946ff6d951SJohn Birrell int ret = 0, found = B_FALSE;
7956ff6d951SJohn Birrell char provname[DTRACE_PROVNAMELEN];
7966ff6d951SJohn Birrell
7976ff6d951SJohn Birrell (void) snprintf(provname, sizeof (provname), "pid%d",
7986ff6d951SJohn Birrell (int)dpr->dpr_pid);
7996ff6d951SJohn Birrell
8006ff6d951SJohn Birrell for (pgp = dt_list_next(&dtp->dt_programs); pgp != NULL;
8016ff6d951SJohn Birrell pgp = dt_list_next(pgp)) {
8026ff6d951SJohn Birrell
8036ff6d951SJohn Birrell for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL;
8046ff6d951SJohn Birrell stp = dt_list_next(stp)) {
8056ff6d951SJohn Birrell
8066ff6d951SJohn Birrell pdp = &stp->ds_desc->dtsd_ecbdesc->dted_probe;
8076ff6d951SJohn Birrell pid = dt_pid_get_pid(pdp, dtp, NULL, dpr);
8086ff6d951SJohn Birrell if (pid != dpr->dpr_pid)
8096ff6d951SJohn Birrell continue;
8106ff6d951SJohn Birrell
8116ff6d951SJohn Birrell found = B_TRUE;
8126ff6d951SJohn Birrell
8136ff6d951SJohn Birrell pd = *pdp;
8146ff6d951SJohn Birrell
8156ff6d951SJohn Birrell if (gmatch(provname, pdp->dtpd_provider) != 0 &&
8166ff6d951SJohn Birrell dt_pid_create_pid_probes(&pd, dtp, NULL, dpr) != 0)
8176ff6d951SJohn Birrell ret = 1;
8186ff6d951SJohn Birrell
8196ff6d951SJohn Birrell /*
8206ff6d951SJohn Birrell * If it's not strictly a pid provider, we might match
8216ff6d951SJohn Birrell * a USDT provider.
8226ff6d951SJohn Birrell */
8236ff6d951SJohn Birrell if (strcmp(provname, pdp->dtpd_provider) != 0 &&
8246ff6d951SJohn Birrell dt_pid_create_usdt_probes(&pd, dtp, NULL, dpr) != 0)
8256ff6d951SJohn Birrell ret = 1;
8266ff6d951SJohn Birrell }
8276ff6d951SJohn Birrell }
8286ff6d951SJohn Birrell
8296ff6d951SJohn Birrell if (found) {
8306ff6d951SJohn Birrell /*
8316ff6d951SJohn Birrell * Give DTrace a shot to the ribs to get it to check
8326ff6d951SJohn Birrell * out the newly created probes.
8336ff6d951SJohn Birrell */
8345ec56692SJohn Birrell args.dof = NULL;
8355ec56692SJohn Birrell args.n_matched = 0;
8365ec56692SJohn Birrell (void) dt_ioctl(dtp, DTRACEIOC_ENABLE, &args);
8376ff6d951SJohn Birrell }
8386ff6d951SJohn Birrell
8396ff6d951SJohn Birrell return (ret);
8406ff6d951SJohn Birrell }
8418e648814SRui Paulo
8428e648814SRui Paulo /*
8438e648814SRui Paulo * libdtrace has a backroom deal with us to ask us for type information on
8448e648814SRui Paulo * behalf of pid provider probes when fasttrap doesn't return any type
8458e648814SRui Paulo * information. Instead we'll look up the module and see if there is type
8468e648814SRui Paulo * information available. However, if there is no type information available due
8478e648814SRui Paulo * to a lack of CTF data, then we want to make sure that DTrace still carries on
8488e648814SRui Paulo * in face of that. As such we don't have a meaningful exit code about failure.
8498e648814SRui Paulo * We emit information about why we failed to the dtrace debug log so someone
8508e648814SRui Paulo * can figure it out by asking nicely for DTRACE_DEBUG.
8518e648814SRui Paulo */
8528e648814SRui Paulo void
dt_pid_get_types(dtrace_hdl_t * dtp,const dtrace_probedesc_t * pdp,dtrace_argdesc_t * adp,int * nargs)8538e648814SRui Paulo dt_pid_get_types(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp,
8548e648814SRui Paulo dtrace_argdesc_t *adp, int *nargs)
8558e648814SRui Paulo {
8568e648814SRui Paulo dt_module_t *dmp;
8578e648814SRui Paulo ctf_file_t *fp;
8588e648814SRui Paulo ctf_funcinfo_t f;
8598e648814SRui Paulo ctf_id_t argv[32];
8608e648814SRui Paulo GElf_Sym sym;
8618e648814SRui Paulo prsyminfo_t si;
8628e648814SRui Paulo struct ps_prochandle *p;
8638e648814SRui Paulo int i, args;
8648e648814SRui Paulo char buf[DTRACE_ARGTYPELEN];
8658e648814SRui Paulo const char *mptr;
8668e648814SRui Paulo char *eptr;
8678e648814SRui Paulo int ret = 0;
8688e648814SRui Paulo int argc = sizeof (argv) / sizeof (ctf_id_t);
8698e648814SRui Paulo Lmid_t lmid;
8708e648814SRui Paulo
8718e648814SRui Paulo /* Set up a potential outcome */
8728e648814SRui Paulo args = *nargs;
8738e648814SRui Paulo *nargs = 0;
8748e648814SRui Paulo
8758e648814SRui Paulo /*
8768e648814SRui Paulo * If we don't have an entry or return probe then we can just stop right
8778e648814SRui Paulo * now as we don't have arguments for offset probes.
8788e648814SRui Paulo */
8798e648814SRui Paulo if (strcmp(pdp->dtpd_name, "entry") != 0 &&
8808e648814SRui Paulo strcmp(pdp->dtpd_name, "return") != 0)
8818e648814SRui Paulo return;
8828e648814SRui Paulo
8838e648814SRui Paulo dmp = dt_module_create(dtp, pdp->dtpd_provider);
8848e648814SRui Paulo if (dmp == NULL) {
8858e648814SRui Paulo dt_dprintf("failed to find module for %s\n",
8868e648814SRui Paulo pdp->dtpd_provider);
8878e648814SRui Paulo return;
8888e648814SRui Paulo }
8898e648814SRui Paulo if (dt_module_load(dtp, dmp) != 0) {
8908e648814SRui Paulo dt_dprintf("failed to load module for %s\n",
8918e648814SRui Paulo pdp->dtpd_provider);
8928e648814SRui Paulo return;
8938e648814SRui Paulo }
8948e648814SRui Paulo
8958e648814SRui Paulo /*
8968e648814SRui Paulo * We may be working with a module that doesn't have ctf. If that's the
8978e648814SRui Paulo * case then we just return now and move on with life.
8988e648814SRui Paulo */
8998e648814SRui Paulo fp = dt_module_getctflib(dtp, dmp, pdp->dtpd_mod);
9008e648814SRui Paulo if (fp == NULL) {
9018e648814SRui Paulo dt_dprintf("no ctf container for %s\n",
9028e648814SRui Paulo pdp->dtpd_mod);
9038e648814SRui Paulo return;
9048e648814SRui Paulo }
9058e648814SRui Paulo p = dt_proc_grab(dtp, dmp->dm_pid, 0, PGRAB_RDONLY | PGRAB_FORCE);
9068e648814SRui Paulo if (p == NULL) {
9078e648814SRui Paulo dt_dprintf("failed to grab pid\n");
9088e648814SRui Paulo return;
9098e648814SRui Paulo }
9108e648814SRui Paulo dt_proc_lock(dtp, p);
9118e648814SRui Paulo
9128e648814SRui Paulo /*
9138e648814SRui Paulo * Check to see if the D module has a link map ID and separate that out
9148e648814SRui Paulo * for properly interrogating libproc.
9158e648814SRui Paulo */
9168e648814SRui Paulo if ((mptr = strchr(pdp->dtpd_mod, '`')) != NULL) {
9178e648814SRui Paulo if (strlen(pdp->dtpd_mod) < 3) {
9188e648814SRui Paulo dt_dprintf("found weird modname with linkmap, "
9198e648814SRui Paulo "aborting: %s\n", pdp->dtpd_mod);
9208e648814SRui Paulo goto out;
9218e648814SRui Paulo }
9228e648814SRui Paulo if (pdp->dtpd_mod[0] != 'L' || pdp->dtpd_mod[1] != 'M') {
9238e648814SRui Paulo dt_dprintf("missing leading 'LM', "
9248e648814SRui Paulo "aborting: %s\n", pdp->dtpd_mod);
9258e648814SRui Paulo goto out;
9268e648814SRui Paulo }
9278e648814SRui Paulo errno = 0;
9288e648814SRui Paulo lmid = strtol(pdp->dtpd_mod + 2, &eptr, 16);
9298e648814SRui Paulo if (errno == ERANGE || eptr != mptr) {
9308e648814SRui Paulo dt_dprintf("failed to parse out lmid, aborting: %s\n",
9318e648814SRui Paulo pdp->dtpd_mod);
9328e648814SRui Paulo goto out;
9338e648814SRui Paulo }
9348e648814SRui Paulo mptr++;
9358e648814SRui Paulo } else {
9368e648814SRui Paulo mptr = pdp->dtpd_mod;
9378e648814SRui Paulo lmid = 0;
9388e648814SRui Paulo }
9398e648814SRui Paulo
9408e648814SRui Paulo if (Pxlookup_by_name(p, lmid, mptr, pdp->dtpd_func,
9418e648814SRui Paulo &sym, &si) != 0) {
9428e648814SRui Paulo dt_dprintf("failed to find function %s in %s`%s\n",
9438e648814SRui Paulo pdp->dtpd_func, pdp->dtpd_provider, pdp->dtpd_mod);
9448e648814SRui Paulo goto out;
9458e648814SRui Paulo }
9468e648814SRui Paulo if (ctf_func_info(fp, si.prs_id, &f) == CTF_ERR) {
9478e648814SRui Paulo dt_dprintf("failed to get ctf information for %s in %s`%s\n",
9488e648814SRui Paulo pdp->dtpd_func, pdp->dtpd_provider, pdp->dtpd_mod);
9498e648814SRui Paulo goto out;
9508e648814SRui Paulo }
9518e648814SRui Paulo
9528e648814SRui Paulo (void) snprintf(buf, sizeof (buf), "%s`%s", pdp->dtpd_provider,
9538e648814SRui Paulo pdp->dtpd_mod);
9548e648814SRui Paulo
9558e648814SRui Paulo if (strcmp(pdp->dtpd_name, "return") == 0) {
9568e648814SRui Paulo if (args < 2)
9578e648814SRui Paulo goto out;
9588e648814SRui Paulo
9598e648814SRui Paulo bzero(adp, sizeof (dtrace_argdesc_t));
9608e648814SRui Paulo adp->dtargd_ndx = 0;
9618e648814SRui Paulo adp->dtargd_id = pdp->dtpd_id;
9628e648814SRui Paulo adp->dtargd_mapping = adp->dtargd_ndx;
9638e648814SRui Paulo /*
9648e648814SRui Paulo * We explicitly leave out the library here, we only care that
9658e648814SRui Paulo * it is some int. We are assuming that there is no ctf
9668e648814SRui Paulo * container in here that is lying about what an int is.
9678e648814SRui Paulo */
9688e648814SRui Paulo (void) snprintf(adp->dtargd_native, DTRACE_ARGTYPELEN,
9698e648814SRui Paulo "user %s`%s", pdp->dtpd_provider, "int");
9708e648814SRui Paulo adp++;
9718e648814SRui Paulo bzero(adp, sizeof (dtrace_argdesc_t));
9728e648814SRui Paulo adp->dtargd_ndx = 1;
9738e648814SRui Paulo adp->dtargd_id = pdp->dtpd_id;
9748e648814SRui Paulo adp->dtargd_mapping = adp->dtargd_ndx;
9758e648814SRui Paulo ret = snprintf(adp->dtargd_native, DTRACE_ARGTYPELEN,
9768e648814SRui Paulo "userland ");
9778e648814SRui Paulo (void) ctf_type_qname(fp, f.ctc_return, adp->dtargd_native +
9788e648814SRui Paulo ret, DTRACE_ARGTYPELEN - ret, buf);
9798e648814SRui Paulo *nargs = 2;
9808e648814SRui Paulo } else {
9818e648814SRui Paulo if (ctf_func_args(fp, si.prs_id, argc, argv) == CTF_ERR)
9828e648814SRui Paulo goto out;
9838e648814SRui Paulo
9848e648814SRui Paulo *nargs = MIN(args, f.ctc_argc);
9858e648814SRui Paulo for (i = 0; i < *nargs; i++, adp++) {
9868e648814SRui Paulo bzero(adp, sizeof (dtrace_argdesc_t));
9878e648814SRui Paulo adp->dtargd_ndx = i;
9888e648814SRui Paulo adp->dtargd_id = pdp->dtpd_id;
9898e648814SRui Paulo adp->dtargd_mapping = adp->dtargd_ndx;
9908e648814SRui Paulo ret = snprintf(adp->dtargd_native, DTRACE_ARGTYPELEN,
9918e648814SRui Paulo "userland ");
9928e648814SRui Paulo (void) ctf_type_qname(fp, argv[i], adp->dtargd_native +
9938e648814SRui Paulo ret, DTRACE_ARGTYPELEN - ret, buf);
9948e648814SRui Paulo }
9958e648814SRui Paulo }
9968e648814SRui Paulo out:
9978e648814SRui Paulo dt_proc_unlock(dtp, p);
9988e648814SRui Paulo dt_proc_release(dtp, p);
9998e648814SRui Paulo }
1000