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 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Copyright (c) 2012 by Delphix. All rights reserved. 29 */ 30 31 /* 32 * Common functions for helper provider loading both compiled into the 33 * executable via drti.o and dtrace(1M) -G, and the libdaudit.so library. 34 */ 35 36 #include <errno.h> 37 #include <fcntl.h> 38 #include <stdarg.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <unistd.h> 43 44 #include <dlink.h> 45 46 /* 47 * In Solaris 10 GA, the only mechanism for communicating helper information 48 * is through the DTrace helper pseudo-device node in /devices; there is 49 * no /dev link. Because of this, USDT providers and helper actions don't 50 * work inside of non-global zones. This issue was addressed by adding 51 * the /dev and having this initialization code use that /dev link. If the 52 * /dev link doesn't exist it falls back to looking for the /devices node 53 * as this code may be embedded in a binary which runs on Solaris 10 GA. 54 */ 55 const char *devname = "/dev/dtrace/helper"; 56 static const char *olddevname = "/devices/pseudo/dtrace@0:helper"; 57 58 static boolean_t dof_init_debug = B_FALSE; 59 60 void 61 dprintf(int debug, const char *fmt, ...) 62 { 63 va_list ap; 64 65 if (debug && !dof_init_debug) 66 return; 67 68 va_start(ap, fmt); 69 70 (void) fprintf(stderr, "dtrace DOF: "); 71 72 (void) vfprintf(stderr, fmt, ap); 73 74 if (fmt[strlen(fmt) - 1] != '\n') 75 (void) fprintf(stderr, ": %s\n", strerror(errno)); 76 77 va_end(ap); 78 } 79 80 /* 81 * Users may set the following environment variable to affect the way 82 * helper initialization takes place: 83 * 84 * DTRACE_DOF_INIT_DEBUG enable debugging output 85 * DTRACE_DOF_INIT_DISABLE disable helper loading 86 * DTRACE_DOF_INIT_DEVNAME set the path to the helper node 87 */ 88 void 89 dtrace_link_init(void) 90 { 91 if (getenv("DTRACE_DOF_INIT_DEBUG") != NULL) 92 dof_init_debug = B_TRUE; 93 } 94 95 void 96 dtrace_link_dof(dof_hdr_t *dof, Lmid_t lmid, const char *name, uintptr_t addr) 97 { 98 const char *modname; 99 const char *p; 100 #ifdef _LP64 101 Elf64_Ehdr *elf; 102 #else 103 Elf32_Ehdr *elf; 104 #endif 105 dof_helper_t dh; 106 int fd; 107 108 if (getenv("DTRACE_DOF_INIT_DISABLE") != NULL) 109 return; 110 111 if ((modname = strrchr(name, '/')) == NULL) 112 modname = name; 113 else 114 modname++; 115 116 if (dof->dofh_ident[DOF_ID_MAG0] != DOF_MAG_MAG0 || 117 dof->dofh_ident[DOF_ID_MAG1] != DOF_MAG_MAG1 || 118 dof->dofh_ident[DOF_ID_MAG2] != DOF_MAG_MAG2 || 119 dof->dofh_ident[DOF_ID_MAG3] != DOF_MAG_MAG3) { 120 dprintf(0, ".SUNW_dof section corrupt for %s\n", modname); 121 return; 122 } 123 124 elf = (void *)addr; 125 126 dh.dofhp_dof = (uintptr_t)dof; 127 dh.dofhp_addr = elf->e_type == ET_DYN ? addr : 0; 128 129 if (lmid == LM_ID_BASE) { 130 (void) snprintf(dh.dofhp_mod, sizeof (dh.dofhp_mod), 131 "%s", modname); 132 } else { 133 (void) snprintf(dh.dofhp_mod, sizeof (dh.dofhp_mod), 134 "LM%lu`%s", lmid, modname); 135 } 136 137 if ((p = getenv("DTRACE_DOF_INIT_DEVNAME")) != NULL) 138 devname = p; 139 140 if ((fd = open64(devname, O_RDWR)) < 0) { 141 dprintf(1, "failed to open helper device %s", devname); 142 143 /* 144 * If the device path wasn't explicitly set, try again with 145 * the old device path. 146 */ 147 if (p != NULL) 148 return; 149 150 devname = olddevname; 151 152 if ((fd = open64(devname, O_RDWR)) < 0) { 153 dprintf(1, "failed to open helper device %s", devname); 154 return; 155 } 156 } 157 158 if (ioctl(fd, DTRACEHIOC_ADDDOF, &dh) == -1) { 159 dprintf(1, "DTrace ioctl failed for DOF at %p in %s", dof, 160 name); 161 } else { 162 dprintf(1, "DTrace ioctl succeeded for DOF at %p in %s\n", dof, 163 name); 164 } 165 (void) close(fd); 166 } 167