xref: /netbsd-src/external/cddl/osnet/dist/lib/libdtrace/common/drti.c (revision ad49149131b7552cf1c4fc41370cc055d9b4a80e)
1a864dc36Sdarran /*
2a864dc36Sdarran  * CDDL HEADER START
3a864dc36Sdarran  *
4a864dc36Sdarran  * The contents of this file are subject to the terms of the
5a252d550Shaad  * Common Development and Distribution License (the "License").
6a252d550Shaad  * You may not use this file except in compliance with the License.
7a864dc36Sdarran  *
8a864dc36Sdarran  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9a864dc36Sdarran  * or http://www.opensolaris.org/os/licensing.
10a864dc36Sdarran  * See the License for the specific language governing permissions
11a864dc36Sdarran  * and limitations under the License.
12a864dc36Sdarran  *
13a864dc36Sdarran  * When distributing Covered Code, include this CDDL HEADER in each
14a864dc36Sdarran  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15a864dc36Sdarran  * If applicable, add the following below this CDDL HEADER, with the
16a864dc36Sdarran  * fields enclosed by brackets "[]" replaced with your own identifying
17a864dc36Sdarran  * information: Portions Copyright [yyyy] [name of copyright owner]
18a864dc36Sdarran  *
19a864dc36Sdarran  * CDDL HEADER END
20a864dc36Sdarran  */
21a864dc36Sdarran /*
22a252d550Shaad  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23c0855460Schristos  * Copyright 2013 Voxer Inc. All rights reserved.
24a864dc36Sdarran  * Use is subject to license terms.
25a864dc36Sdarran  */
26a864dc36Sdarran 
27*ad491491Sriastradh /*
28*ad491491Sriastradh  * XXX Hack: Force the use of sys/exec_elf.h, not elfdefinitions.h.
29*ad491491Sriastradh  * Why?
30*ad491491Sriastradh  *
31*ad491491Sriastradh  * - sys/dtrace.h is needed because (XXX why?).
32*ad491491Sriastradh  *   => sys/dtrace.h pulls in sys/ctf_api.h
33*ad491491Sriastradh  *   => which pulls in sys/elf.h
34*ad491491Sriastradh  *   => which pulls in elfdefinitions.h (XXX should it?)
35*ad491491Sriastradh  *
36*ad491491Sriastradh  * - link.h is needed for Link_map.
37*ad491491Sriastradh  *   => link.h pulls in link_elf.h
38*ad491491Sriastradh  *   => which pulls in sys/exec_elf.h
39*ad491491Sriastradh  *
40*ad491491Sriastradh  * But elfdefinitions.h and sys/exec_elf.h collide over most basic ELF
41*ad491491Sriastradh  * definitions.  Since we don't need elfdefinitions.h otherwise, prefer
42*ad491491Sriastradh  * sys/exec_elf.h.
43*ad491491Sriastradh  */
44*ad491491Sriastradh #define	_SYS_ELFDEFINITIONS_H_
45*ad491491Sriastradh 
46a864dc36Sdarran #include <unistd.h>
47a864dc36Sdarran #include <fcntl.h>
48a864dc36Sdarran #include <dlfcn.h>
49a864dc36Sdarran #include <link.h>
50a864dc36Sdarran #include <sys/dtrace.h>
51042ef76aSchristos #include <sys/ioctl.h>
52a864dc36Sdarran 
53a864dc36Sdarran #include <stdarg.h>
54a864dc36Sdarran #include <stdio.h>
55a864dc36Sdarran #include <stdlib.h>
56a864dc36Sdarran #include <string.h>
57a864dc36Sdarran #include <errno.h>
58c0855460Schristos #include <libelf.h>
59a864dc36Sdarran 
60a864dc36Sdarran /*
61a864dc36Sdarran  * In Solaris 10 GA, the only mechanism for communicating helper information
62a864dc36Sdarran  * is through the DTrace helper pseudo-device node in /devices; there is
63a864dc36Sdarran  * no /dev link. Because of this, USDT providers and helper actions don't
64a864dc36Sdarran  * work inside of non-global zones. This issue was addressed by adding
65a864dc36Sdarran  * the /dev and having this initialization code use that /dev link. If the
66a864dc36Sdarran  * /dev link doesn't exist it falls back to looking for the /devices node
67a864dc36Sdarran  * as this code may be embedded in a binary which runs on Solaris 10 GA.
68a864dc36Sdarran  *
69a864dc36Sdarran  * Users may set the following environment variable to affect the way
70a864dc36Sdarran  * helper initialization takes place:
71a864dc36Sdarran  *
72a864dc36Sdarran  *	DTRACE_DOF_INIT_DEBUG		enable debugging output
73a864dc36Sdarran  *	DTRACE_DOF_INIT_DISABLE		disable helper loading
74a864dc36Sdarran  *	DTRACE_DOF_INIT_DEVNAME		set the path to the helper node
75a864dc36Sdarran  */
76a864dc36Sdarran 
77bb8023b5Sdarran static const char *devnamep = "/dev/dtrace/helper";
78c0855460Schristos #ifdef illumos
79a864dc36Sdarran static const char *olddevname = "/devices/pseudo/dtrace@0:helper";
80c0855460Schristos #endif
81a864dc36Sdarran 
82a864dc36Sdarran static const char *modname;	/* Name of this load object */
83a864dc36Sdarran static int gen;			/* DOF helper generation */
84a864dc36Sdarran extern dof_hdr_t __SUNW_dof;	/* DOF defined in the .SUNW_dof section */
85a252d550Shaad static boolean_t dof_init_debug = B_FALSE;	/* From DTRACE_DOF_INIT_DEBUG */
86a864dc36Sdarran 
8788630898Sriastradh static void __printflike(2,3)
dbg_printf(int debug,const char * fmt,...)88ba2539a9Schs dbg_printf(int debug, const char *fmt, ...)
89a864dc36Sdarran {
90a864dc36Sdarran 	va_list ap;
91a864dc36Sdarran 
92a252d550Shaad 	if (debug && !dof_init_debug)
93a864dc36Sdarran 		return;
94a864dc36Sdarran 
95a864dc36Sdarran 	va_start(ap, fmt);
96a864dc36Sdarran 
97a864dc36Sdarran 	if (modname == NULL)
98a864dc36Sdarran 		(void) fprintf(stderr, "dtrace DOF: ");
99a864dc36Sdarran 	else
100a864dc36Sdarran 		(void) fprintf(stderr, "dtrace DOF %s: ", modname);
101a864dc36Sdarran 
102a864dc36Sdarran 	(void) vfprintf(stderr, fmt, ap);
103a864dc36Sdarran 
104a864dc36Sdarran 	if (fmt[strlen(fmt) - 1] != '\n')
105a864dc36Sdarran 		(void) fprintf(stderr, ": %s\n", strerror(errno));
106a864dc36Sdarran 
107a864dc36Sdarran 	va_end(ap);
108a864dc36Sdarran }
109a864dc36Sdarran 
110c0855460Schristos #ifdef illumos
111a864dc36Sdarran #pragma init(dtrace_dof_init)
112bb8023b5Sdarran #else
113bb8023b5Sdarran static void dtrace_dof_init(void) __attribute__ ((constructor));
114bb8023b5Sdarran #endif
115bb8023b5Sdarran 
116a864dc36Sdarran static void
dtrace_dof_init(void)117a864dc36Sdarran dtrace_dof_init(void)
118a864dc36Sdarran {
119a864dc36Sdarran 	dof_hdr_t *dof = &__SUNW_dof;
120a864dc36Sdarran #ifdef _LP64
121a864dc36Sdarran 	Elf64_Ehdr *elf;
122a864dc36Sdarran #else
123a864dc36Sdarran 	Elf32_Ehdr *elf;
124a864dc36Sdarran #endif
125a864dc36Sdarran 	dof_helper_t dh;
126c0855460Schristos 	Link_map *lmp = NULL;
127c0855460Schristos #ifdef illumos
128a864dc36Sdarran 	Lmid_t lmid;
129bb8023b5Sdarran #else
130bb8023b5Sdarran 	u_long lmid = 0;
131bb8023b5Sdarran #endif
132a864dc36Sdarran 	int fd;
133a864dc36Sdarran 	const char *p;
134a864dc36Sdarran 
135a864dc36Sdarran 	if (getenv("DTRACE_DOF_INIT_DISABLE") != NULL)
136a864dc36Sdarran 		return;
137a864dc36Sdarran 
138a252d550Shaad 	if (getenv("DTRACE_DOF_INIT_DEBUG") != NULL)
139a252d550Shaad 		dof_init_debug = B_TRUE;
140a252d550Shaad 
141a864dc36Sdarran 	if (dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &lmp) == -1 || lmp == NULL) {
142ba2539a9Schs 		dbg_printf(1, "couldn't discover module name or address\n");
143a864dc36Sdarran 		return;
144a864dc36Sdarran 	}
145a864dc36Sdarran 
146c0855460Schristos #ifdef illumos
147a864dc36Sdarran 	if (dlinfo(RTLD_SELF, RTLD_DI_LMID, &lmid) == -1) {
148ba2539a9Schs 		dbg_printf(1, "couldn't discover link map ID\n");
149a864dc36Sdarran 		return;
150a864dc36Sdarran 	}
151bb8023b5Sdarran #endif
152a864dc36Sdarran 
153a864dc36Sdarran 	if ((modname = strrchr(lmp->l_name, '/')) == NULL)
154a864dc36Sdarran 		modname = lmp->l_name;
155a864dc36Sdarran 	else
156a864dc36Sdarran 		modname++;
157a864dc36Sdarran 
158a864dc36Sdarran 	if (dof->dofh_ident[DOF_ID_MAG0] != DOF_MAG_MAG0 ||
159a864dc36Sdarran 	    dof->dofh_ident[DOF_ID_MAG1] != DOF_MAG_MAG1 ||
160a864dc36Sdarran 	    dof->dofh_ident[DOF_ID_MAG2] != DOF_MAG_MAG2 ||
161a864dc36Sdarran 	    dof->dofh_ident[DOF_ID_MAG3] != DOF_MAG_MAG3) {
162ba2539a9Schs 		dbg_printf(0, ".SUNW_dof section corrupt\n");
163a864dc36Sdarran 		return;
164a864dc36Sdarran 	}
165a864dc36Sdarran 
166a864dc36Sdarran 	elf = (void *)lmp->l_addr;
167a864dc36Sdarran 
168a864dc36Sdarran 	dh.dofhp_dof = (uintptr_t)dof;
1692f04f4acSjoerg 	dh.dofhp_addr = elf && elf->e_type == ET_DYN ? (uintptr_t) lmp->l_addr : 0;
170c0855460Schristos #if defined(__FreeBSD__) || defined(__NetBSD__)
171c0855460Schristos 	dh.dofhp_pid = getpid();
172c0855460Schristos #endif
173a864dc36Sdarran 
174a864dc36Sdarran 	if (lmid == 0) {
175a864dc36Sdarran 		(void) snprintf(dh.dofhp_mod, sizeof (dh.dofhp_mod),
176a864dc36Sdarran 		    "%s", modname);
177a864dc36Sdarran 	} else {
178a864dc36Sdarran 		(void) snprintf(dh.dofhp_mod, sizeof (dh.dofhp_mod),
179a864dc36Sdarran 		    "LM%lu`%s", lmid, modname);
180a864dc36Sdarran 	}
181a864dc36Sdarran 
182a864dc36Sdarran 	if ((p = getenv("DTRACE_DOF_INIT_DEVNAME")) != NULL)
183bb8023b5Sdarran 		devnamep = p;
184a864dc36Sdarran 
185bb8023b5Sdarran 	if ((fd = open64(devnamep, O_RDWR)) < 0) {
186ba2539a9Schs 		dbg_printf(1, "failed to open helper device %s", devnamep);
187c0855460Schristos #ifdef illumos
188a864dc36Sdarran 		/*
189a864dc36Sdarran 		 * If the device path wasn't explicitly set, try again with
190a864dc36Sdarran 		 * the old device path.
191a864dc36Sdarran 		 */
192a864dc36Sdarran 		if (p != NULL)
193a864dc36Sdarran 			return;
194a864dc36Sdarran 
195bb8023b5Sdarran 		devnamep = olddevname;
196a864dc36Sdarran 
197bb8023b5Sdarran 		if ((fd = open64(devnamep, O_RDWR)) < 0) {
198ba2539a9Schs 			dbg_printf(1, "failed to open helper device %s", devnamep);
199a864dc36Sdarran 			return;
200a864dc36Sdarran 		}
201c0855460Schristos #else
202c0855460Schristos 		return;
203c0855460Schristos #endif
204a864dc36Sdarran 	}
205a864dc36Sdarran 	if ((gen = ioctl(fd, DTRACEHIOC_ADDDOF, &dh)) == -1)
206ba2539a9Schs 		dbg_printf(1, "DTrace ioctl failed for DOF at %p", dof);
207c0855460Schristos 	else {
208ba2539a9Schs 		dbg_printf(1, "DTrace ioctl succeeded for DOF at %p\n", dof);
209c0855460Schristos #if defined(__FreeBSD__) || defined(__NetBSD__)
210c0855460Schristos 		gen = dh.dofhp_gen;
211c0855460Schristos #endif
212c0855460Schristos 	}
213a864dc36Sdarran 
214a864dc36Sdarran 	(void) close(fd);
215a864dc36Sdarran }
216a864dc36Sdarran 
217c0855460Schristos #ifdef illumos
218a864dc36Sdarran #pragma fini(dtrace_dof_fini)
219bb8023b5Sdarran #else
220bb8023b5Sdarran static void dtrace_dof_fini(void) __attribute__ ((destructor));
221bb8023b5Sdarran #endif
222bb8023b5Sdarran 
223a864dc36Sdarran static void
dtrace_dof_fini(void)224a864dc36Sdarran dtrace_dof_fini(void)
225a864dc36Sdarran {
226a864dc36Sdarran 	int fd;
227a864dc36Sdarran 
228bb8023b5Sdarran 	if ((fd = open64(devnamep, O_RDWR)) < 0) {
229ba2539a9Schs 		dbg_printf(1, "failed to open helper device %s", devnamep);
230a864dc36Sdarran 		return;
231a864dc36Sdarran 	}
232a864dc36Sdarran 
233c0855460Schristos 	if ((gen = ioctl(fd, DTRACEHIOC_REMOVE, &gen)) == -1)
234ba2539a9Schs 		dbg_printf(1, "DTrace ioctl failed to remove DOF (%d)\n", gen);
235a864dc36Sdarran 	else
236ba2539a9Schs 		dbg_printf(1, "DTrace ioctl removed DOF (%d)\n", gen);
237a864dc36Sdarran 
238a864dc36Sdarran 	(void) close(fd);
239a864dc36Sdarran }
240