1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <unistd.h>
30*0Sstevel@tonic-gate #include <fcntl.h>
31*0Sstevel@tonic-gate #include <dlfcn.h>
32*0Sstevel@tonic-gate #include <link.h>
33*0Sstevel@tonic-gate #include <sys/dtrace.h>
34*0Sstevel@tonic-gate 
35*0Sstevel@tonic-gate #include <stdarg.h>
36*0Sstevel@tonic-gate #include <stdio.h>
37*0Sstevel@tonic-gate #include <stdlib.h>
38*0Sstevel@tonic-gate #include <string.h>
39*0Sstevel@tonic-gate #include <errno.h>
40*0Sstevel@tonic-gate 
41*0Sstevel@tonic-gate /*
42*0Sstevel@tonic-gate  * In Solaris 10 GA, the only mechanism for communicating helper information
43*0Sstevel@tonic-gate  * is through the DTrace helper pseudo-device node in /devices; there is
44*0Sstevel@tonic-gate  * no /dev link. Because of this, USDT providers and helper actions don't
45*0Sstevel@tonic-gate  * work inside of non-global zones. This issue was addressed by adding
46*0Sstevel@tonic-gate  * the /dev and having this initialization code use that /dev link. If the
47*0Sstevel@tonic-gate  * /dev link doesn't exist it falls back to looking for the /devices node
48*0Sstevel@tonic-gate  * as this code may be embedded in a binary which runs on Solaris 10 GA.
49*0Sstevel@tonic-gate  *
50*0Sstevel@tonic-gate  * Users may set the following environment variable to affect the way
51*0Sstevel@tonic-gate  * helper initialization takes place:
52*0Sstevel@tonic-gate  *
53*0Sstevel@tonic-gate  *	DTRACE_DOF_INIT_DEBUG		enable debugging output
54*0Sstevel@tonic-gate  *	DTRACE_DOF_INIT_DISABLE		disable helper loading
55*0Sstevel@tonic-gate  *	DTRACE_DOF_INIT_DEVNAME		set the path to the helper node
56*0Sstevel@tonic-gate  */
57*0Sstevel@tonic-gate 
58*0Sstevel@tonic-gate static const char *devname = "/dev/dtrace/helper";
59*0Sstevel@tonic-gate static const char *olddevname = "/devices/pseudo/dtrace@0:helper";
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate static const char *modname;	/* Name of this load object */
62*0Sstevel@tonic-gate static int gen;			/* DOF helper generation */
63*0Sstevel@tonic-gate extern dof_hdr_t __SUNW_dof;	/* DOF defined in the .SUNW_dof section */
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate static void
66*0Sstevel@tonic-gate dprintf(int debug, const char *fmt, ...)
67*0Sstevel@tonic-gate {
68*0Sstevel@tonic-gate 	va_list ap;
69*0Sstevel@tonic-gate 
70*0Sstevel@tonic-gate 	if (debug && getenv("DTRACE_DOF_INIT_DEBUG") == NULL)
71*0Sstevel@tonic-gate 		return;
72*0Sstevel@tonic-gate 
73*0Sstevel@tonic-gate 	va_start(ap, fmt);
74*0Sstevel@tonic-gate 
75*0Sstevel@tonic-gate 	if (modname == NULL)
76*0Sstevel@tonic-gate 		(void) fprintf(stderr, "dtrace DOF: ");
77*0Sstevel@tonic-gate 	else
78*0Sstevel@tonic-gate 		(void) fprintf(stderr, "dtrace DOF %s: ", modname);
79*0Sstevel@tonic-gate 
80*0Sstevel@tonic-gate 	(void) vfprintf(stderr, fmt, ap);
81*0Sstevel@tonic-gate 
82*0Sstevel@tonic-gate 	if (fmt[strlen(fmt) - 1] != '\n')
83*0Sstevel@tonic-gate 		(void) fprintf(stderr, ": %s\n", strerror(errno));
84*0Sstevel@tonic-gate 
85*0Sstevel@tonic-gate 	va_end(ap);
86*0Sstevel@tonic-gate }
87*0Sstevel@tonic-gate 
88*0Sstevel@tonic-gate #pragma init(dtrace_dof_init)
89*0Sstevel@tonic-gate static void
90*0Sstevel@tonic-gate dtrace_dof_init(void)
91*0Sstevel@tonic-gate {
92*0Sstevel@tonic-gate 	dof_hdr_t *dof = &__SUNW_dof;
93*0Sstevel@tonic-gate #ifdef _LP64
94*0Sstevel@tonic-gate 	Elf64_Ehdr *elf;
95*0Sstevel@tonic-gate #else
96*0Sstevel@tonic-gate 	Elf32_Ehdr *elf;
97*0Sstevel@tonic-gate #endif
98*0Sstevel@tonic-gate 	dof_helper_t dh;
99*0Sstevel@tonic-gate 	Link_map *lmp;
100*0Sstevel@tonic-gate 	Lmid_t lmid;
101*0Sstevel@tonic-gate 	int fd;
102*0Sstevel@tonic-gate 	const char *p;
103*0Sstevel@tonic-gate 
104*0Sstevel@tonic-gate 	if (getenv("DTRACE_DOF_INIT_DISABLE") != NULL)
105*0Sstevel@tonic-gate 		return;
106*0Sstevel@tonic-gate 
107*0Sstevel@tonic-gate 	if (dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &lmp) == -1 || lmp == NULL) {
108*0Sstevel@tonic-gate 		dprintf(1, "couldn't discover module name or address\n");
109*0Sstevel@tonic-gate 		return;
110*0Sstevel@tonic-gate 	}
111*0Sstevel@tonic-gate 
112*0Sstevel@tonic-gate 	if (dlinfo(RTLD_SELF, RTLD_DI_LMID, &lmid) == -1) {
113*0Sstevel@tonic-gate 		dprintf(1, "couldn't discover link map ID\n");
114*0Sstevel@tonic-gate 		return;
115*0Sstevel@tonic-gate 	}
116*0Sstevel@tonic-gate 
117*0Sstevel@tonic-gate 	if ((modname = strrchr(lmp->l_name, '/')) == NULL)
118*0Sstevel@tonic-gate 		modname = lmp->l_name;
119*0Sstevel@tonic-gate 	else
120*0Sstevel@tonic-gate 		modname++;
121*0Sstevel@tonic-gate 
122*0Sstevel@tonic-gate 	if (dof->dofh_ident[DOF_ID_MAG0] != DOF_MAG_MAG0 ||
123*0Sstevel@tonic-gate 	    dof->dofh_ident[DOF_ID_MAG1] != DOF_MAG_MAG1 ||
124*0Sstevel@tonic-gate 	    dof->dofh_ident[DOF_ID_MAG2] != DOF_MAG_MAG2 ||
125*0Sstevel@tonic-gate 	    dof->dofh_ident[DOF_ID_MAG3] != DOF_MAG_MAG3) {
126*0Sstevel@tonic-gate 		dprintf(0, ".SUNW_dof section corrupt\n");
127*0Sstevel@tonic-gate 		return;
128*0Sstevel@tonic-gate 	}
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate 	elf = (void *)lmp->l_addr;
131*0Sstevel@tonic-gate 
132*0Sstevel@tonic-gate 	dh.dofhp_dof = (uintptr_t)dof;
133*0Sstevel@tonic-gate 	dh.dofhp_addr = elf->e_type == ET_DYN ? lmp->l_addr : 0;
134*0Sstevel@tonic-gate 
135*0Sstevel@tonic-gate 	if (lmid == 0) {
136*0Sstevel@tonic-gate 		(void) snprintf(dh.dofhp_mod, sizeof (dh.dofhp_mod),
137*0Sstevel@tonic-gate 		    "%s", modname);
138*0Sstevel@tonic-gate 	} else {
139*0Sstevel@tonic-gate 		(void) snprintf(dh.dofhp_mod, sizeof (dh.dofhp_mod),
140*0Sstevel@tonic-gate 		    "LM%lu`%s", lmid, modname);
141*0Sstevel@tonic-gate 	}
142*0Sstevel@tonic-gate 
143*0Sstevel@tonic-gate 	if ((p = getenv("DTRACE_DOF_INIT_DEVNAME")) != NULL)
144*0Sstevel@tonic-gate 		devname = p;
145*0Sstevel@tonic-gate 
146*0Sstevel@tonic-gate 	if ((fd = open64(devname, O_RDWR)) < 0) {
147*0Sstevel@tonic-gate 		dprintf(1, "failed to open helper device %s", devname);
148*0Sstevel@tonic-gate 
149*0Sstevel@tonic-gate 		/*
150*0Sstevel@tonic-gate 		 * If the device path wasn't explicitly set, try again with
151*0Sstevel@tonic-gate 		 * the old device path.
152*0Sstevel@tonic-gate 		 */
153*0Sstevel@tonic-gate 		if (p != NULL)
154*0Sstevel@tonic-gate 			return;
155*0Sstevel@tonic-gate 
156*0Sstevel@tonic-gate 		devname = olddevname;
157*0Sstevel@tonic-gate 
158*0Sstevel@tonic-gate 		if ((fd = open64(devname, O_RDWR)) < 0) {
159*0Sstevel@tonic-gate 			dprintf(1, "failed to open helper device %s", devname);
160*0Sstevel@tonic-gate 			return;
161*0Sstevel@tonic-gate 		}
162*0Sstevel@tonic-gate 	}
163*0Sstevel@tonic-gate 
164*0Sstevel@tonic-gate 	if ((gen = ioctl(fd, DTRACEHIOC_ADDDOF, &dh)) == -1)
165*0Sstevel@tonic-gate 		dprintf(1, "DTrace ioctl failed for DOF at %p", dof);
166*0Sstevel@tonic-gate 	else
167*0Sstevel@tonic-gate 		dprintf(1, "DTrace ioctl succeeded for DOF at %p\n", dof);
168*0Sstevel@tonic-gate 
169*0Sstevel@tonic-gate 	(void) close(fd);
170*0Sstevel@tonic-gate }
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate #pragma fini(dtrace_dof_fini)
173*0Sstevel@tonic-gate static void
174*0Sstevel@tonic-gate dtrace_dof_fini(void)
175*0Sstevel@tonic-gate {
176*0Sstevel@tonic-gate 	int fd;
177*0Sstevel@tonic-gate 
178*0Sstevel@tonic-gate 	if ((fd = open64(devname, O_RDWR)) < 0) {
179*0Sstevel@tonic-gate 		dprintf(1, "failed to open helper device %s", devname);
180*0Sstevel@tonic-gate 		return;
181*0Sstevel@tonic-gate 	}
182*0Sstevel@tonic-gate 
183*0Sstevel@tonic-gate 	if ((gen = ioctl(fd, DTRACEHIOC_REMOVE, gen)) == -1)
184*0Sstevel@tonic-gate 		dprintf(1, "DTrace ioctl failed to remove DOF (%d)\n", gen);
185*0Sstevel@tonic-gate 	else
186*0Sstevel@tonic-gate 		dprintf(1, "DTrace ioctl removed DOF (%d)\n", gen);
187*0Sstevel@tonic-gate 
188*0Sstevel@tonic-gate 	(void) close(fd);
189*0Sstevel@tonic-gate }
190