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 #include <stdlib.h> 28 #include <assert.h> 29 #include <errno.h> 30 #include <string.h> 31 #include <libgen.h> 32 33 #include <dt_impl.h> 34 #include <dt_pid.h> 35 36 #define OP(x) ((x) >> 30) 37 #define OP2(x) (((x) >> 22) & 0x07) 38 #define COND(x) (((x) >> 25) & 0x0f) 39 #define A(x) (((x) >> 29) & 0x01) 40 41 #define OP_BRANCH 0 42 43 #define OP2_BPcc 0x1 44 #define OP2_Bicc 0x2 45 #define OP2_BPr 0x3 46 #define OP2_FBPfcc 0x5 47 #define OP2_FBfcc 0x6 48 49 /*ARGSUSED*/ 50 int 51 dt_pid_create_entry_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp, 52 fasttrap_probe_spec_t *ftp, const GElf_Sym *symp) 53 { 54 ftp->ftps_type = DTFTP_ENTRY; 55 ftp->ftps_pc = (uintptr_t)symp->st_value; 56 ftp->ftps_size = (size_t)symp->st_size; 57 ftp->ftps_noffs = 1; 58 ftp->ftps_offs[0] = 0; 59 60 if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) { 61 dt_dprintf("fasttrap probe creation ioctl failed: %s\n", 62 strerror(errno)); 63 return (dt_set_errno(dtp, errno)); 64 } 65 66 return (1); 67 } 68 69 int 70 dt_pid_create_return_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp, 71 fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, uint64_t *stret) 72 { 73 74 uint32_t *text; 75 int i; 76 int srdepth = 0; 77 78 if ((text = malloc(symp->st_size + 4)) == NULL) { 79 dt_dprintf("mr sparkle: malloc() failed\n"); 80 return (DT_PROC_ERR); 81 } 82 83 if (Pread(P, text, symp->st_size, symp->st_value) != symp->st_size) { 84 dt_dprintf("mr sparkle: Pread() failed\n"); 85 free(text); 86 return (DT_PROC_ERR); 87 } 88 89 /* 90 * Leave a dummy instruction in the last slot to simplify edge 91 * conditions. 92 */ 93 text[symp->st_size / 4] = 0; 94 95 ftp->ftps_type = DTFTP_RETURN; 96 ftp->ftps_pc = symp->st_value; 97 ftp->ftps_size = symp->st_size; 98 ftp->ftps_noffs = 0; 99 100 for (i = 0; i < symp->st_size / 4; i++) { 101 /* 102 * If we encounter an existing tracepoint, query the 103 * kernel to find out the instruction that was 104 * replaced at this spot. 105 */ 106 while (text[i] == FASTTRAP_INSTR) { 107 fasttrap_instr_query_t instr; 108 109 instr.ftiq_pid = Pstatus(P)->pr_pid; 110 instr.ftiq_pc = symp->st_value + i * 4; 111 112 if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_GETINSTR, 113 &instr) != 0) { 114 115 if (errno == ESRCH || errno == ENOENT) { 116 if (Pread(P, &text[i], 4, 117 instr.ftiq_pc) != 4) { 118 dt_dprintf("mr sparkle: " 119 "Pread() failed\n"); 120 free(text); 121 return (DT_PROC_ERR); 122 } 123 continue; 124 } 125 126 free(text); 127 dt_dprintf("mr sparkle: getinstr query " 128 "failed: %s\n", strerror(errno)); 129 return (DT_PROC_ERR); 130 } 131 132 text[i] = instr.ftiq_instr; 133 break; 134 } 135 136 /* save */ 137 if ((text[i] & 0xc1f80000) == 0x81e00000) { 138 srdepth++; 139 continue; 140 } 141 142 /* restore */ 143 if ((text[i] & 0xc1f80000) == 0x81e80000) { 144 srdepth--; 145 continue; 146 } 147 148 if (srdepth > 0) { 149 /* ret */ 150 if (text[i] == 0x81c7e008) 151 goto is_ret; 152 153 /* return */ 154 if (text[i] == 0x81cfe008) 155 goto is_ret; 156 157 /* call or jmpl w/ restore in the slot */ 158 if (((text[i] & 0xc0000000) == 0x40000000 || 159 (text[i] & 0xc1f80000) == 0x81c00000) && 160 (text[i + 1] & 0xc1f80000) == 0x81e80000) 161 goto is_ret; 162 163 /* call to one of the stret routines */ 164 if ((text[i] & 0xc0000000) == 0x40000000) { 165 int32_t disp = text[i] << 2; 166 uint64_t dest = ftp->ftps_pc + i * 4 + disp; 167 168 dt_dprintf("dest = %llx\n", (u_longlong_t)dest); 169 170 if (dest == stret[0] || dest == stret[1] || 171 dest == stret[2] || dest == stret[3]) 172 goto is_ret; 173 } 174 } else { 175 /* external call */ 176 if ((text[i] & 0xc0000000) == 0x40000000) { 177 int32_t dst = text[i] << 2; 178 179 dst += i * 4; 180 181 if ((uintptr_t)dst >= (uintptr_t)symp->st_size) 182 goto is_ret; 183 } 184 185 /* jmpl into %g0 -- this includes the retl pseudo op */ 186 if ((text[i] & 0xfff80000) == 0x81c00000) 187 goto is_ret; 188 189 /* external branch -- possible return site */ 190 if (OP(text[i]) == OP_BRANCH) { 191 int32_t dst; 192 int baa; 193 194 switch (OP2(text[i])) { 195 case OP2_BPcc: 196 dst = text[i] & 0x7ffff; 197 dst <<= 13; 198 dst >>= 11; 199 200 baa = COND(text[i]) == 8 && A(text[i]); 201 break; 202 case OP2_Bicc: 203 dst = text[i] & 0x3fffff; 204 dst <<= 10; 205 dst >>= 8; 206 207 baa = COND(text[i]) == 8 && A(text[i]); 208 break; 209 case OP2_BPr: 210 dst = (((text[i]) >> 6) & 0xc000) | 211 ((text[i]) & 0x3fff); 212 dst <<= 16; 213 dst >>= 14; 214 215 baa = 0; 216 break; 217 case OP2_FBPfcc: 218 dst = text[i] & 0x7ffff; 219 dst <<= 13; 220 dst >>= 11; 221 222 baa = COND(text[i]) == 8 && A(text[i]); 223 break; 224 case OP2_FBfcc: 225 dst = text[i] & 0x3fffff; 226 dst <<= 10; 227 dst >>= 8; 228 229 baa = COND(text[i]) == 8 && A(text[i]); 230 break; 231 default: 232 continue; 233 } 234 235 dst += i * 4; 236 237 /* 238 * Interpret branches outside of the function's 239 * bounds as potential return sites. If the 240 * branch is a ba,a don't skip the instruction 241 * in the delay slot. 242 */ 243 if ((uintptr_t)dst >= 244 (uintptr_t)symp->st_size) { 245 if (baa) 246 goto is_ret_baa; 247 else 248 goto is_ret; 249 } 250 } 251 } 252 253 continue; 254 is_ret: 255 i++; 256 is_ret_baa: 257 dt_dprintf("return at offset %x\n", i * 4); 258 ftp->ftps_offs[ftp->ftps_noffs++] = i * 4; 259 } 260 261 free(text); 262 if (ftp->ftps_noffs > 0) { 263 if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) { 264 dt_dprintf("fasttrap probe creation ioctl failed: %s\n", 265 strerror(errno)); 266 return (dt_set_errno(dtp, errno)); 267 } 268 } 269 270 271 return (ftp->ftps_noffs); 272 } 273 274 /*ARGSUSED*/ 275 int 276 dt_pid_create_offset_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp, 277 fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, ulong_t off) 278 { 279 if (off & 0x3) 280 return (DT_PROC_ALIGN); 281 282 ftp->ftps_type = DTFTP_OFFSETS; 283 ftp->ftps_pc = (uintptr_t)symp->st_value; 284 ftp->ftps_size = (size_t)symp->st_size; 285 ftp->ftps_noffs = 1; 286 ftp->ftps_offs[0] = off; 287 288 if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) { 289 dt_dprintf("fasttrap probe creation ioctl failed: %s\n", 290 strerror(errno)); 291 return (dt_set_errno(dtp, errno)); 292 } 293 294 return (1); 295 } 296 297 /*ARGSUSED*/ 298 int 299 dt_pid_create_glob_offset_probes(struct ps_prochandle *P, dtrace_hdl_t *dtp, 300 fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, const char *pattern) 301 { 302 ulong_t i; 303 304 ftp->ftps_type = DTFTP_OFFSETS; 305 ftp->ftps_pc = (uintptr_t)symp->st_value; 306 ftp->ftps_size = (size_t)symp->st_size; 307 ftp->ftps_noffs = 0; 308 309 /* 310 * If we're matching against everything, just iterate through each 311 * instruction in the function, otherwise look for matching offset 312 * names by constructing the string and comparing it against the 313 * pattern. 314 */ 315 if (strcmp("*", pattern) == 0) { 316 for (i = 0; i < symp->st_size; i += 4) { 317 ftp->ftps_offs[ftp->ftps_noffs++] = i; 318 } 319 } else { 320 char name[sizeof (i) * 2 + 1]; 321 322 for (i = 0; i < symp->st_size; i += 4) { 323 (void) sprintf(name, "%lx", i); 324 if (gmatch(name, pattern)) 325 ftp->ftps_offs[ftp->ftps_noffs++] = i; 326 } 327 } 328 329 if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) { 330 dt_dprintf("fasttrap probe creation ioctl failed: %s\n", 331 strerror(errno)); 332 return (dt_set_errno(dtp, errno)); 333 } 334 335 return (ftp->ftps_noffs); 336 } 337