Deleted Added
full compact
drti.c (210767) drti.c (211554)
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE

--- 20 unchanged lines hidden (view full) ---

29#include <link.h>
30#include <sys/dtrace.h>
31
32#include <stdarg.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36#include <errno.h>
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE

--- 20 unchanged lines hidden (view full) ---

29#include <link.h>
30#include <sys/dtrace.h>
31
32#include <stdarg.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36#include <errno.h>
37#include <libelf.h>
38#include <gelf.h>
37
38/*
39 * In Solaris 10 GA, the only mechanism for communicating helper information
40 * is through the DTrace helper pseudo-device node in /devices; there is
41 * no /dev link. Because of this, USDT providers and helper actions don't
42 * work inside of non-global zones. This issue was addressed by adding
43 * the /dev and having this initialization code use that /dev link. If the
44 * /dev link doesn't exist it falls back to looking for the /devices node
45 * as this code may be embedded in a binary which runs on Solaris 10 GA.
46 *
47 * Users may set the following environment variable to affect the way
48 * helper initialization takes place:
49 *
50 * DTRACE_DOF_INIT_DEBUG enable debugging output
51 * DTRACE_DOF_INIT_DISABLE disable helper loading
52 * DTRACE_DOF_INIT_DEVNAME set the path to the helper node
53 */
54
55static const char *devnamep = "/dev/dtrace/helper";
39
40/*
41 * In Solaris 10 GA, the only mechanism for communicating helper information
42 * is through the DTrace helper pseudo-device node in /devices; there is
43 * no /dev link. Because of this, USDT providers and helper actions don't
44 * work inside of non-global zones. This issue was addressed by adding
45 * the /dev and having this initialization code use that /dev link. If the
46 * /dev link doesn't exist it falls back to looking for the /devices node
47 * as this code may be embedded in a binary which runs on Solaris 10 GA.
48 *
49 * Users may set the following environment variable to affect the way
50 * helper initialization takes place:
51 *
52 * DTRACE_DOF_INIT_DEBUG enable debugging output
53 * DTRACE_DOF_INIT_DISABLE disable helper loading
54 * DTRACE_DOF_INIT_DEVNAME set the path to the helper node
55 */
56
57static const char *devnamep = "/dev/dtrace/helper";
58#if defined(sun)
56static const char *olddevname = "/devices/pseudo/dtrace@0:helper";
59static const char *olddevname = "/devices/pseudo/dtrace@0:helper";
60#endif
57
58static const char *modname; /* Name of this load object */
59static int gen; /* DOF helper generation */
61
62static const char *modname; /* Name of this load object */
63static int gen; /* DOF helper generation */
64#if defined(sun)
60extern dof_hdr_t __SUNW_dof; /* DOF defined in the .SUNW_dof section */
65extern dof_hdr_t __SUNW_dof; /* DOF defined in the .SUNW_dof section */
61static boolean_t dof_init_debug = B_FALSE; /* From DTRACE_DOF_INIT_DEBUG */
66#endif
67static boolean_t dof_init_debug = B_TRUE; /* From DTRACE_DOF_INIT_DEBUG */
62
63static void
64dprintf(int debug, const char *fmt, ...)
65{
66 va_list ap;
67
68 if (debug && !dof_init_debug)
69 return;

--- 8 unchanged lines hidden (view full) ---

78 (void) vfprintf(stderr, fmt, ap);
79
80 if (fmt[strlen(fmt) - 1] != '\n')
81 (void) fprintf(stderr, ": %s\n", strerror(errno));
82
83 va_end(ap);
84}
85
68
69static void
70dprintf(int debug, const char *fmt, ...)
71{
72 va_list ap;
73
74 if (debug && !dof_init_debug)
75 return;

--- 8 unchanged lines hidden (view full) ---

84 (void) vfprintf(stderr, fmt, ap);
85
86 if (fmt[strlen(fmt) - 1] != '\n')
87 (void) fprintf(stderr, ": %s\n", strerror(errno));
88
89 va_end(ap);
90}
91
92#if !defined(sun)
93static void
94fixsymbol(Elf *e, Elf_Data *data, size_t idx, int nprobes, char *buf,
95 dof_sec_t *sec, int *fixedprobes, char *dofstrtab)
96{
97 GElf_Sym sym;
98 char *s;
99 unsigned char *funcname;
100 dof_probe_t *prb;
101 int j = 0;
102 int ndx;
103
104 while (gelf_getsym(data, j++, &sym) != NULL) {
105 prb = (dof_probe_t *)(buf + sec->dofs_offset);
106
107 for (ndx = nprobes; ndx; ndx--, prb += 1) {
108 funcname = dofstrtab + prb->dofpr_func;
109 s = elf_strptr(e, idx, sym.st_name);
110 if (strcmp(s, funcname) == 0) {
111 dprintf(1, "fixing %s() symbol\n", s);
112 prb->dofpr_addr = sym.st_value;
113 (*fixedprobes)++;
114 }
115 }
116 if (*fixedprobes == nprobes)
117 break;
118 }
119}
120#endif
121
86#if defined(sun)
87#pragma init(dtrace_dof_init)
88#else
89static void dtrace_dof_init(void) __attribute__ ((constructor));
90#endif
91
92static void
93dtrace_dof_init(void)
94{
122#if defined(sun)
123#pragma init(dtrace_dof_init)
124#else
125static void dtrace_dof_init(void) __attribute__ ((constructor));
126#endif
127
128static void
129dtrace_dof_init(void)
130{
131#if defined(sun)
95 dof_hdr_t *dof = &__SUNW_dof;
132 dof_hdr_t *dof = &__SUNW_dof;
133#else
134 dof_hdr_t *dof = NULL;
135#endif
96#ifdef _LP64
97 Elf64_Ehdr *elf;
98#else
99 Elf32_Ehdr *elf;
100#endif
101 dof_helper_t dh;
136#ifdef _LP64
137 Elf64_Ehdr *elf;
138#else
139 Elf32_Ehdr *elf;
140#endif
141 dof_helper_t dh;
102#if defined(sun)
103 Link_map *lmp;
142 Link_map *lmp;
143#if defined(sun)
104 Lmid_t lmid;
105#else
144 Lmid_t lmid;
145#else
106 struct link_map *lmp;
107 u_long lmid = 0;
146 u_long lmid = 0;
147 dof_sec_t *sec;
148 size_t i;
108#endif
109 int fd;
110 const char *p;
149#endif
150 int fd;
151 const char *p;
152#if !defined(sun)
153 Elf *e;
154 Elf_Scn *scn = NULL;
155 Elf_Data *symtabdata = NULL, *dynsymdata = NULL;
156 GElf_Shdr shdr;
157 int efd, nprobes;
158 char *s;
159 size_t shstridx, symtabidx = 0, dynsymidx = 0;
160 unsigned char *dofstrtab = NULL;
161 unsigned char *buf;
162 int fixedprobes = 0;
163#endif
111
112 if (getenv("DTRACE_DOF_INIT_DISABLE") != NULL)
113 return;
114
115 if (getenv("DTRACE_DOF_INIT_DEBUG") != NULL)
116 dof_init_debug = B_TRUE;
117
118 if (dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &lmp) == -1 || lmp == NULL) {
119 dprintf(1, "couldn't discover module name or address\n");
120 return;
121 }
122
123#if defined(sun)
124 if (dlinfo(RTLD_SELF, RTLD_DI_LMID, &lmid) == -1) {
125 dprintf(1, "couldn't discover link map ID\n");
126 return;
127 }
128#endif
129
164
165 if (getenv("DTRACE_DOF_INIT_DISABLE") != NULL)
166 return;
167
168 if (getenv("DTRACE_DOF_INIT_DEBUG") != NULL)
169 dof_init_debug = B_TRUE;
170
171 if (dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &lmp) == -1 || lmp == NULL) {
172 dprintf(1, "couldn't discover module name or address\n");
173 return;
174 }
175
176#if defined(sun)
177 if (dlinfo(RTLD_SELF, RTLD_DI_LMID, &lmid) == -1) {
178 dprintf(1, "couldn't discover link map ID\n");
179 return;
180 }
181#endif
182
183
130 if ((modname = strrchr(lmp->l_name, '/')) == NULL)
131 modname = lmp->l_name;
132 else
133 modname++;
184 if ((modname = strrchr(lmp->l_name, '/')) == NULL)
185 modname = lmp->l_name;
186 else
187 modname++;
188#if !defined(sun)
189 elf_version(EV_CURRENT);
190 if ((efd = open(lmp->l_name, O_RDONLY, 0)) < 0) {
191 dprintf(1, "couldn't open file for reading\n");
192 return;
193 }
194 if ((e = elf_begin(efd, ELF_C_READ, NULL)) == NULL) {
195 dprintf(1, "elf_begin failed\n");
196 close(efd);
197 return;
198 }
199 elf_getshdrstrndx(e, &shstridx);
200 dof = NULL;
201 while ((scn = elf_nextscn(e, scn)) != NULL) {
202 gelf_getshdr(scn, &shdr);
203 if (shdr.sh_type == SHT_SYMTAB) {
204 symtabidx = shdr.sh_link;
205 symtabdata = elf_getdata(scn, NULL);
206 } else if (shdr.sh_type == SHT_DYNSYM) {
207 dynsymidx = shdr.sh_link;
208 dynsymdata = elf_getdata(scn, NULL);
209 } else if (shdr.sh_type == SHT_PROGBITS) {
210 s = elf_strptr(e, shstridx, shdr.sh_name);
211 if (s && strcmp(s, ".SUNW_dof") == 0) {
212 dof = elf_getdata(scn, NULL)->d_buf;
213 }
214 }
215 }
216 if (dof == NULL) {
217 dprintf(1, "SUNW_dof section not found\n");
218 elf_end(e);
219 close(efd);
220 return;
221 }
222#endif
134
135 if (dof->dofh_ident[DOF_ID_MAG0] != DOF_MAG_MAG0 ||
136 dof->dofh_ident[DOF_ID_MAG1] != DOF_MAG_MAG1 ||
137 dof->dofh_ident[DOF_ID_MAG2] != DOF_MAG_MAG2 ||
138 dof->dofh_ident[DOF_ID_MAG3] != DOF_MAG_MAG3) {
139 dprintf(0, ".SUNW_dof section corrupt\n");
140 return;
141 }

--- 11 unchanged lines hidden (view full) ---

153 "LM%lu`%s", lmid, modname);
154 }
155
156 if ((p = getenv("DTRACE_DOF_INIT_DEVNAME")) != NULL)
157 devnamep = p;
158
159 if ((fd = open64(devnamep, O_RDWR)) < 0) {
160 dprintf(1, "failed to open helper device %s", devnamep);
223
224 if (dof->dofh_ident[DOF_ID_MAG0] != DOF_MAG_MAG0 ||
225 dof->dofh_ident[DOF_ID_MAG1] != DOF_MAG_MAG1 ||
226 dof->dofh_ident[DOF_ID_MAG2] != DOF_MAG_MAG2 ||
227 dof->dofh_ident[DOF_ID_MAG3] != DOF_MAG_MAG3) {
228 dprintf(0, ".SUNW_dof section corrupt\n");
229 return;
230 }

--- 11 unchanged lines hidden (view full) ---

242 "LM%lu`%s", lmid, modname);
243 }
244
245 if ((p = getenv("DTRACE_DOF_INIT_DEVNAME")) != NULL)
246 devnamep = p;
247
248 if ((fd = open64(devnamep, O_RDWR)) < 0) {
249 dprintf(1, "failed to open helper device %s", devnamep);
161
250#if defined(sun)
162 /*
163 * If the device path wasn't explicitly set, try again with
164 * the old device path.
165 */
166 if (p != NULL)
167 return;
168
169 devnamep = olddevname;
170
171 if ((fd = open64(devnamep, O_RDWR)) < 0) {
172 dprintf(1, "failed to open helper device %s", devnamep);
173 return;
174 }
251 /*
252 * If the device path wasn't explicitly set, try again with
253 * the old device path.
254 */
255 if (p != NULL)
256 return;
257
258 devnamep = olddevname;
259
260 if ((fd = open64(devnamep, O_RDWR)) < 0) {
261 dprintf(1, "failed to open helper device %s", devnamep);
262 return;
263 }
264#else
265 return;
266#endif
175 }
267 }
176
268#if !defined(sun)
269 /*
270 * We need to fix the base address of each probe since this wasn't
271 * done by ld(1). (ld(1) needs to grow support for parsing the
272 * SUNW_dof section).
273 *
274 * The complexity of this is not that great. The first for loop
275 * iterates over the sections inside the DOF file. There are usually
276 * 10 sections here. We asume the STRTAB section comes first and the
277 * PROBES section comes after. Since we are only interested in fixing
278 * data inside the PROBES section we quit the for loop after processing
279 * the PROBES section. It's usually the case that the first section
280 * is the STRTAB section and the second section is the PROBES section,
281 * so this for loop is not meaningful when doing complexity analysis.
282 *
283 * After finding the probes section, we iterate over the symbols
284 * in the symtab section. When we find a symbol name that matches
285 * the probe function name, we fix it. If we have fixed all the
286 * probes, we exit all the loops and we are done.
287 * The number of probes is given by the variable 'nprobes' and this
288 * depends entirely on the user, but some optimizations were done.
289 *
290 * We are assuming the number of probes is less than the number of
291 * symbols (libc can have 4k symbols, for example).
292 */
293 sec = (dof_sec_t *)(dof + 1);
294 buf = (char *)dof;
295 for (i = 0; i < dof->dofh_secnum; i++, sec++) {
296 if (sec->dofs_type == DOF_SECT_STRTAB)
297 dofstrtab = (unsigned char *)(buf + sec->dofs_offset);
298 else if (sec->dofs_type == DOF_SECT_PROBES && dofstrtab)
299 break;
300
301 }
302 nprobes = sec->dofs_size / sec->dofs_entsize;
303 fixsymbol(e, symtabdata, symtabidx, nprobes, buf, sec, &fixedprobes,
304 dofstrtab);
305 if (fixedprobes != nprobes) {
306 /*
307 * If we haven't fixed all the probes using the
308 * symtab section, look inside the dynsym
309 * section.
310 */
311 fixsymbol(e, dynsymdata, dynsymidx, nprobes, buf, sec,
312 &fixedprobes, dofstrtab);
313 }
314 if (fixedprobes != nprobes) {
315 fprintf(stderr, "WARNING: number of probes "
316 "fixed does not match the number of "
317 "defined probes (%d != %d, "
318 "respectively)\n", fixedprobes, nprobes);
319 fprintf(stderr, "WARNING: some probes might "
320 "not fire or your program might crash\n");
321 }
322#endif
177 if ((gen = ioctl(fd, DTRACEHIOC_ADDDOF, &dh)) == -1)
178 dprintf(1, "DTrace ioctl failed for DOF at %p", dof);
323 if ((gen = ioctl(fd, DTRACEHIOC_ADDDOF, &dh)) == -1)
324 dprintf(1, "DTrace ioctl failed for DOF at %p", dof);
179 else
325 else {
180 dprintf(1, "DTrace ioctl succeeded for DOF at %p\n", dof);
326 dprintf(1, "DTrace ioctl succeeded for DOF at %p\n", dof);
327#if !defined(sun)
328 gen = dh.gen;
329#endif
330 }
181
182 (void) close(fd);
331
332 (void) close(fd);
333#if !defined(sun)
334 elf_end(e);
335 (void) close(efd);
336#endif
183}
184
185#if defined(sun)
186#pragma fini(dtrace_dof_fini)
187#else
188static void dtrace_dof_fini(void) __attribute__ ((destructor));
189#endif
190
191static void
192dtrace_dof_fini(void)
193{
194 int fd;
195
196 if ((fd = open64(devnamep, O_RDWR)) < 0) {
197 dprintf(1, "failed to open helper device %s", devnamep);
198 return;
199 }
200
337}
338
339#if defined(sun)
340#pragma fini(dtrace_dof_fini)
341#else
342static void dtrace_dof_fini(void) __attribute__ ((destructor));
343#endif
344
345static void
346dtrace_dof_fini(void)
347{
348 int fd;
349
350 if ((fd = open64(devnamep, O_RDWR)) < 0) {
351 dprintf(1, "failed to open helper device %s", devnamep);
352 return;
353 }
354
201 if ((gen = ioctl(fd, DTRACEHIOC_REMOVE, gen)) == -1)
355 if ((gen = ioctl(fd, DTRACEHIOC_REMOVE, &gen)) == -1)
202 dprintf(1, "DTrace ioctl failed to remove DOF (%d)\n", gen);
203 else
204 dprintf(1, "DTrace ioctl removed DOF (%d)\n", gen);
205
206 (void) close(fd);
207}
356 dprintf(1, "DTrace ioctl failed to remove DOF (%d)\n", gen);
357 else
358 dprintf(1, "DTrace ioctl removed DOF (%d)\n", gen);
359
360 (void) close(fd);
361}