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