xref: /freebsd-src/cddl/contrib/opensolaris/lib/libdtrace/common/dt_pid.c (revision 1bde3b70660fe02e45b1d5b3b8b89eaa7a563b82)
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