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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <stdlib.h> 30 #include <assert.h> 31 #include <errno.h> 32 #include <string.h> 33 #include <libgen.h> 34 35 #include <dt_impl.h> 36 #include <dt_pid.h> 37 38 #include <libproc_compat.h> 39 40 /*ARGSUSED*/ 41 int 42 dt_pid_create_entry_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp, 43 fasttrap_probe_spec_t *ftp, const GElf_Sym *symp) 44 { 45 ftp->ftps_type = DTFTP_ENTRY; 46 ftp->ftps_pc = (uintptr_t)symp->st_value; 47 ftp->ftps_size = (size_t)symp->st_size; 48 ftp->ftps_noffs = 1; 49 ftp->ftps_offs[0] = 0; 50 51 if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) { 52 dt_dprintf("fasttrap probe creation ioctl failed: %s\n", 53 strerror(errno)); 54 return (dt_set_errno(dtp, errno)); 55 } 56 57 return (1); 58 } 59 60 int 61 dt_pid_create_return_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp, 62 fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, uint64_t *stret) 63 { 64 65 uintptr_t temp; 66 uint32_t *text; 67 int i; 68 int srdepth = 0; 69 70 if ((text = malloc(symp->st_size + 4)) == NULL) { 71 dt_dprintf("mr sparkle: malloc() failed\n"); 72 return (DT_PROC_ERR); 73 } 74 75 if (Pread(P, text, symp->st_size, symp->st_value) != symp->st_size) { 76 dt_dprintf("mr sparkle: Pread() failed\n"); 77 free(text); 78 return (DT_PROC_ERR); 79 } 80 81 /* 82 * Leave a dummy instruction in the last slot to simplify edge 83 * conditions. 84 */ 85 text[symp->st_size / 4] = 0; 86 87 ftp->ftps_type = DTFTP_RETURN; 88 ftp->ftps_pc = symp->st_value; 89 ftp->ftps_size = symp->st_size; 90 ftp->ftps_noffs = 0; 91 92 for (i = 0; i < symp->st_size / 4; i++) { 93 94 if ((text[i] & 0xfc000001) != 0x48000000 && 95 text[i] != 0x4e800020) 96 continue; 97 98 /* 99 * Check for a jump within this function. If it's outside this 100 * function then it's a tail-call, so a return point. 101 */ 102 if ((text[i] & 0xfc000000) == 0x48000000) { 103 temp = (text[i] & 0x03fffffc); 104 /* Bit 30 denotes an absolute address. */ 105 if (!(text[i] & 0x02)) { 106 temp += symp->st_value + i * 4; 107 } 108 else { 109 /* Sign extend the absolute address. */ 110 if (temp & 0x02000000) { 111 temp |= (UINTPTR_MAX - 0x03ffffff); 112 } 113 } 114 if (temp >= symp->st_value && 115 temp <= (symp->st_value + symp->st_size)) 116 continue; 117 } 118 dt_dprintf("return at offset %x\n", i * 4); 119 ftp->ftps_offs[ftp->ftps_noffs++] = i * 4; 120 } 121 122 free(text); 123 if (ftp->ftps_noffs > 0) { 124 if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) { 125 dt_dprintf("fasttrap probe creation ioctl failed: %s\n", 126 strerror(errno)); 127 return (dt_set_errno(dtp, errno)); 128 } 129 } 130 131 132 return (ftp->ftps_noffs); 133 } 134 135 /*ARGSUSED*/ 136 int 137 dt_pid_create_offset_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp, 138 fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, ulong_t off) 139 { 140 if (off & 0x3) 141 return (DT_PROC_ALIGN); 142 143 ftp->ftps_type = DTFTP_OFFSETS; 144 ftp->ftps_pc = (uintptr_t)symp->st_value; 145 ftp->ftps_size = (size_t)symp->st_size; 146 ftp->ftps_noffs = 1; 147 ftp->ftps_offs[0] = off; 148 149 if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) { 150 dt_dprintf("fasttrap probe creation ioctl failed: %s\n", 151 strerror(errno)); 152 return (dt_set_errno(dtp, errno)); 153 } 154 155 return (1); 156 } 157 158 /*ARGSUSED*/ 159 int 160 dt_pid_create_glob_offset_probes(struct ps_prochandle *P, dtrace_hdl_t *dtp, 161 fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, const char *pattern) 162 { 163 ulong_t i; 164 165 ftp->ftps_type = DTFTP_OFFSETS; 166 ftp->ftps_pc = (uintptr_t)symp->st_value; 167 ftp->ftps_size = (size_t)symp->st_size; 168 ftp->ftps_noffs = 0; 169 170 /* 171 * If we're matching against everything, just iterate through each 172 * instruction in the function, otherwise look for matching offset 173 * names by constructing the string and comparing it against the 174 * pattern. 175 */ 176 if (strcmp("*", pattern) == 0) { 177 for (i = 0; i < symp->st_size; i += 4) { 178 ftp->ftps_offs[ftp->ftps_noffs++] = i; 179 } 180 } else { 181 char name[sizeof (i) * 2 + 1]; 182 183 for (i = 0; i < symp->st_size; i += 4) { 184 (void) sprintf(name, "%lx", i); 185 if (gmatch(name, pattern)) 186 ftp->ftps_offs[ftp->ftps_noffs++] = i; 187 } 188 } 189 190 if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) { 191 dt_dprintf("fasttrap probe creation ioctl failed: %s\n", 192 strerror(errno)); 193 return (dt_set_errno(dtp, errno)); 194 } 195 196 return (ftp->ftps_noffs); 197 } 198