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 * Portions Copyright 2006-2008 John Birrell jb@freebsd.org 22 * 23 * $FreeBSD$ 24 * 25 */ 26 27 /* 28 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 29 * Use is subject to license terms. 30 */ 31 32 #include <sys/cdefs.h> 33 #include <sys/param.h> 34 35 #include <sys/dtrace.h> 36 37 #include "fbt.h" 38 39 #define FBT_PUSHL_EBP 0x55 40 #define FBT_MOVL_ESP_EBP0_V0 0x8b 41 #define FBT_MOVL_ESP_EBP1_V0 0xec 42 #define FBT_MOVL_ESP_EBP0_V1 0x89 43 #define FBT_MOVL_ESP_EBP1_V1 0xe5 44 #define FBT_REX_RSP_RBP 0x48 45 46 #define FBT_POPL_EBP 0x5d 47 #define FBT_RET 0xc3 48 #define FBT_RET_IMM16 0xc2 49 #define FBT_LEAVE 0xc9 50 51 #ifdef __amd64__ 52 #define FBT_PATCHVAL 0xcc 53 #else 54 #define FBT_PATCHVAL 0xf0 55 #endif 56 57 #define FBT_ENTRY "entry" 58 #define FBT_RETURN "return" 59 60 int 61 fbt_invop(uintptr_t addr, uintptr_t *stack, uintptr_t rval) 62 { 63 solaris_cpu_t *cpu = &solaris_cpu[curcpu]; 64 uintptr_t stack0, stack1, stack2, stack3, stack4; 65 fbt_probe_t *fbt = fbt_probetab[FBT_ADDR2NDX(addr)]; 66 67 for (; fbt != NULL; fbt = fbt->fbtp_hashnext) { 68 if ((uintptr_t)fbt->fbtp_patchpoint == addr) { 69 if (fbt->fbtp_roffset == 0) { 70 int i = 0; 71 /* 72 * When accessing the arguments on the stack, 73 * we must protect against accessing beyond 74 * the stack. We can safely set NOFAULT here 75 * -- we know that interrupts are already 76 * disabled. 77 */ 78 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); 79 cpu->cpu_dtrace_caller = stack[i++]; 80 stack0 = stack[i++]; 81 stack1 = stack[i++]; 82 stack2 = stack[i++]; 83 stack3 = stack[i++]; 84 stack4 = stack[i++]; 85 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT | 86 CPU_DTRACE_BADADDR); 87 88 dtrace_probe(fbt->fbtp_id, stack0, stack1, 89 stack2, stack3, stack4); 90 91 cpu->cpu_dtrace_caller = 0; 92 } else { 93 #ifdef __amd64__ 94 /* 95 * On amd64, we instrument the ret, not the 96 * leave. We therefore need to set the caller 97 * to assure that the top frame of a stack() 98 * action is correct. 99 */ 100 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); 101 cpu->cpu_dtrace_caller = stack[0]; 102 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT | 103 CPU_DTRACE_BADADDR); 104 #endif 105 106 dtrace_probe(fbt->fbtp_id, fbt->fbtp_roffset, 107 rval, 0, 0, 0); 108 cpu->cpu_dtrace_caller = 0; 109 } 110 111 return (fbt->fbtp_rval); 112 } 113 } 114 115 return (0); 116 } 117 118 void 119 fbt_patch_tracepoint(fbt_probe_t *fbt, fbt_patchval_t val) 120 { 121 122 *fbt->fbtp_patchpoint = val; 123 } 124 125 int 126 fbt_provide_module_function(linker_file_t lf, int symindx, 127 linker_symval_t *symval, void *opaque) 128 { 129 char *modname = opaque; 130 const char *name = symval->name; 131 fbt_probe_t *fbt, *retfbt; 132 int j; 133 int size; 134 uint8_t *instr, *limit; 135 136 if ((strncmp(name, "dtrace_", 7) == 0 && 137 strncmp(name, "dtrace_safe_", 12) != 0) || 138 strcmp(name, "trap_check") == 0) { 139 /* 140 * Anything beginning with "dtrace_" may be called 141 * from probe context unless it explicitly indicates 142 * that it won't be called from probe context by 143 * using the prefix "dtrace_safe_". 144 * 145 * Additionally, we avoid instrumenting trap_check() to avoid 146 * the possibility of generating a fault in probe context before 147 * DTrace's fault handler is called. 148 */ 149 return (0); 150 } 151 152 if (name[0] == '_' && name[1] == '_') 153 return (0); 154 155 size = symval->size; 156 157 instr = (uint8_t *) symval->value; 158 limit = (uint8_t *) symval->value + symval->size; 159 160 #ifdef __amd64__ 161 while (instr < limit) { 162 if (*instr == FBT_PUSHL_EBP) 163 break; 164 165 if ((size = dtrace_instr_size(instr)) <= 0) 166 break; 167 168 instr += size; 169 } 170 171 if (instr >= limit || *instr != FBT_PUSHL_EBP) { 172 /* 173 * We either don't save the frame pointer in this 174 * function, or we ran into some disassembly 175 * screw-up. Either way, we bail. 176 */ 177 return (0); 178 } 179 #else 180 if (instr[0] != FBT_PUSHL_EBP) 181 return (0); 182 183 if (!(instr[1] == FBT_MOVL_ESP_EBP0_V0 && 184 instr[2] == FBT_MOVL_ESP_EBP1_V0) && 185 !(instr[1] == FBT_MOVL_ESP_EBP0_V1 && 186 instr[2] == FBT_MOVL_ESP_EBP1_V1)) 187 return (0); 188 #endif 189 190 fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO); 191 fbt->fbtp_name = name; 192 fbt->fbtp_id = dtrace_probe_create(fbt_id, modname, 193 name, FBT_ENTRY, 3, fbt); 194 fbt->fbtp_patchpoint = instr; 195 fbt->fbtp_ctl = lf; 196 fbt->fbtp_loadcnt = lf->loadcnt; 197 fbt->fbtp_rval = DTRACE_INVOP_PUSHL_EBP; 198 fbt->fbtp_savedval = *instr; 199 fbt->fbtp_patchval = FBT_PATCHVAL; 200 fbt->fbtp_symindx = symindx; 201 202 fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)]; 203 fbt_probetab[FBT_ADDR2NDX(instr)] = fbt; 204 205 lf->fbt_nentries++; 206 207 retfbt = NULL; 208 again: 209 if (instr >= limit) 210 return (0); 211 212 /* 213 * If this disassembly fails, then we've likely walked off into 214 * a jump table or some other unsuitable area. Bail out of the 215 * disassembly now. 216 */ 217 if ((size = dtrace_instr_size(instr)) <= 0) 218 return (0); 219 220 #ifdef __amd64__ 221 /* 222 * We only instrument "ret" on amd64 -- we don't yet instrument 223 * ret imm16, largely because the compiler doesn't seem to 224 * (yet) emit them in the kernel... 225 */ 226 if (*instr != FBT_RET) { 227 instr += size; 228 goto again; 229 } 230 #else 231 if (!(size == 1 && 232 (*instr == FBT_POPL_EBP || *instr == FBT_LEAVE) && 233 (*(instr + 1) == FBT_RET || 234 *(instr + 1) == FBT_RET_IMM16))) { 235 instr += size; 236 goto again; 237 } 238 #endif 239 240 /* 241 * We (desperately) want to avoid erroneously instrumenting a 242 * jump table, especially given that our markers are pretty 243 * short: two bytes on x86, and just one byte on amd64. To 244 * determine if we're looking at a true instruction sequence 245 * or an inline jump table that happens to contain the same 246 * byte sequences, we resort to some heuristic sleeze: we 247 * treat this instruction as being contained within a pointer, 248 * and see if that pointer points to within the body of the 249 * function. If it does, we refuse to instrument it. 250 */ 251 for (j = 0; j < sizeof (uintptr_t); j++) { 252 caddr_t check = (caddr_t) instr - j; 253 uint8_t *ptr; 254 255 if (check < symval->value) 256 break; 257 258 if (check + sizeof (caddr_t) > (caddr_t)limit) 259 continue; 260 261 ptr = *(uint8_t **)check; 262 263 if (ptr >= (uint8_t *) symval->value && ptr < limit) { 264 instr += size; 265 goto again; 266 } 267 } 268 269 /* 270 * We have a winner! 271 */ 272 fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO); 273 fbt->fbtp_name = name; 274 275 if (retfbt == NULL) { 276 fbt->fbtp_id = dtrace_probe_create(fbt_id, modname, 277 name, FBT_RETURN, 3, fbt); 278 } else { 279 retfbt->fbtp_next = fbt; 280 fbt->fbtp_id = retfbt->fbtp_id; 281 } 282 283 retfbt = fbt; 284 fbt->fbtp_patchpoint = instr; 285 fbt->fbtp_ctl = lf; 286 fbt->fbtp_loadcnt = lf->loadcnt; 287 fbt->fbtp_symindx = symindx; 288 289 #ifndef __amd64__ 290 if (*instr == FBT_POPL_EBP) { 291 fbt->fbtp_rval = DTRACE_INVOP_POPL_EBP; 292 } else { 293 ASSERT(*instr == FBT_LEAVE); 294 fbt->fbtp_rval = DTRACE_INVOP_LEAVE; 295 } 296 fbt->fbtp_roffset = 297 (uintptr_t)(instr - (uint8_t *) symval->value) + 1; 298 299 #else 300 ASSERT(*instr == FBT_RET); 301 fbt->fbtp_rval = DTRACE_INVOP_RET; 302 fbt->fbtp_roffset = 303 (uintptr_t)(instr - (uint8_t *) symval->value); 304 #endif 305 306 fbt->fbtp_savedval = *instr; 307 fbt->fbtp_patchval = FBT_PATCHVAL; 308 fbt->fbtp_hashnext = fbt_probetab[FBT_ADDR2NDX(instr)]; 309 fbt_probetab[FBT_ADDR2NDX(instr)] = fbt; 310 311 lf->fbt_nentries++; 312 313 instr += size; 314 goto again; 315 } 316