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> |
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) |
59static const char *olddevname = "/devices/pseudo/dtrace@0:helper"; |
60#endif |
61 62static const char *modname; /* Name of this load object */ 63static int gen; /* DOF helper generation */ |
64#if defined(sun) |
65extern dof_hdr_t __SUNW_dof; /* DOF defined in the .SUNW_dof section */ |
66#endif 67static boolean_t dof_init_debug = B_TRUE; /* From DTRACE_DOF_INIT_DEBUG */ |
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 |
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) |
132 dof_hdr_t *dof = &__SUNW_dof; |
133#else 134 dof_hdr_t *dof = NULL; 135#endif |
136#ifdef _LP64 137 Elf64_Ehdr *elf; 138#else 139 Elf32_Ehdr *elf; 140#endif 141 dof_helper_t dh; |
142 Link_map *lmp; |
143#if defined(sun) |
144 Lmid_t lmid; 145#else |
146 u_long lmid = 0; |
147 dof_sec_t *sec; 148 size_t i; |
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 |
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 |
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 |
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); |
250#if defined(sun) |
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 |
267 } |
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 |
323 if ((gen = ioctl(fd, DTRACEHIOC_ADDDOF, &dh)) == -1) 324 dprintf(1, "DTrace ioctl failed for DOF at %p", dof); |
325 else { |
326 dprintf(1, "DTrace ioctl succeeded for DOF at %p\n", dof); |
327#if !defined(sun) 328 gen = dh.gen; 329#endif 330 } |
331 332 (void) close(fd); |
333#if !defined(sun) 334 elf_end(e); 335 (void) close(efd); 336#endif |
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 |
355 if ((gen = ioctl(fd, DTRACEHIOC_REMOVE, &gen)) == -1) |
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} |