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