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 2013 Justin Hibbits */ 22/* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27#include <sys/fasttrap_isa.h> 28#include <sys/fasttrap_impl.h> 29#include <sys/dtrace.h> 30#include <sys/dtrace_impl.h> 31#include <cddl/dev/dtrace/dtrace_cddl.h> 32#include <sys/proc.h> 33#include <sys/types.h> 34#include <sys/uio.h> 35#include <sys/ptrace.h>
| 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 2013 Justin Hibbits */ 22/* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27#include <sys/fasttrap_isa.h> 28#include <sys/fasttrap_impl.h> 29#include <sys/dtrace.h> 30#include <sys/dtrace_impl.h> 31#include <cddl/dev/dtrace/dtrace_cddl.h> 32#include <sys/proc.h> 33#include <sys/types.h> 34#include <sys/uio.h> 35#include <sys/ptrace.h>
|
| 36#include <sys/rmlock.h>
|
36#include <sys/sysent.h> 37 38#define OP(x) ((x) >> 26) 39#define OPX(x) (((x) >> 2) & 0x3FF) 40#define OP_BO(x) (((x) & 0x03E00000) >> 21) 41#define OP_BI(x) (((x) & 0x001F0000) >> 16) 42#define OP_RS(x) (((x) & 0x03E00000) >> 21) 43#define OP_RA(x) (((x) & 0x001F0000) >> 16) 44#define OP_RB(x) (((x) & 0x0000F100) >> 11) 45 46static int 47uread(proc_t *p, void *kaddr, size_t len, uintptr_t uaddr) 48{ 49 ssize_t n; 50 51 PHOLD(p); 52 n = proc_readmem(curthread, p, uaddr, kaddr, len); 53 PRELE(p); 54 if (n <= 0 || n < len) 55 return (ENOMEM); 56 return (0); 57} 58 59static int 60uwrite(proc_t *p, void *kaddr, size_t len, uintptr_t uaddr) 61{ 62 ssize_t n; 63 64 PHOLD(p); 65 n = proc_writemem(curthread, p, uaddr, kaddr, len); 66 PRELE(p); 67 if (n <= 0 || n < len) 68 return (ENOMEM); 69 return (0); 70} 71 72int 73fasttrap_tracepoint_install(proc_t *p, fasttrap_tracepoint_t *tp) 74{ 75 fasttrap_instr_t instr = FASTTRAP_INSTR; 76 77 if (uwrite(p, &instr, 4, tp->ftt_pc) != 0) 78 return (-1); 79 80 return (0); 81} 82 83int 84fasttrap_tracepoint_remove(proc_t *p, fasttrap_tracepoint_t *tp) 85{ 86 uint32_t instr; 87 88 /* 89 * Distinguish between read or write failures and a changed 90 * instruction. 91 */ 92 if (uread(p, &instr, 4, tp->ftt_pc) != 0) 93 return (0); 94 if (instr != FASTTRAP_INSTR) 95 return (0); 96 if (uwrite(p, &tp->ftt_instr, 4, tp->ftt_pc) != 0) 97 return (-1); 98 99 return (0); 100} 101 102int 103fasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp, uintptr_t pc, 104 fasttrap_probe_type_t type) 105{ 106 uint32_t instr; 107 //int32_t disp; 108 109 /* 110 * Read the instruction at the given address out of the process's 111 * address space. We don't have to worry about a debugger 112 * changing this instruction before we overwrite it with our trap 113 * instruction since P_PR_LOCK is set. 114 */ 115 if (uread(p, &instr, 4, pc) != 0) 116 return (-1); 117 118 /* 119 * Decode the instruction to fill in the probe flags. We can have 120 * the process execute most instructions on its own using a pc/npc 121 * trick, but pc-relative control transfer present a problem since 122 * we're relocating the instruction. We emulate these instructions 123 * in the kernel. We assume a default type and over-write that as 124 * needed. 125 * 126 * pc-relative instructions must be emulated for correctness; 127 * other instructions (which represent a large set of commonly traced 128 * instructions) are emulated or otherwise optimized for performance. 129 */ 130 tp->ftt_type = FASTTRAP_T_COMMON; 131 tp->ftt_instr = instr; 132 133 switch (OP(instr)) { 134 /* The following are invalid for trapping (invalid opcodes, tw/twi). */ 135 case 0: 136 case 1: 137 case 2: 138 case 4: 139 case 5: 140 case 6: 141 case 30: 142 case 39: 143 case 58: 144 case 62: 145 case 3: /* twi */ 146 return (-1); 147 case 31: /* tw */ 148 if (OPX(instr) == 4) 149 return (-1); 150 else if (OPX(instr) == 444 && OP_RS(instr) == OP_RA(instr) && 151 OP_RS(instr) == OP_RB(instr)) 152 tp->ftt_type = FASTTRAP_T_NOP; 153 break; 154 case 16: 155 tp->ftt_type = FASTTRAP_T_BC; 156 tp->ftt_dest = instr & 0x0000FFFC; /* Extract target address */ 157 if (instr & 0x00008000) 158 tp->ftt_dest |= 0xFFFF0000; 159 /* Use as offset if not absolute address. */ 160 if (!(instr & 0x02)) 161 tp->ftt_dest += pc; 162 tp->ftt_bo = OP_BO(instr); 163 tp->ftt_bi = OP_BI(instr); 164 break; 165 case 18: 166 tp->ftt_type = FASTTRAP_T_B; 167 tp->ftt_dest = instr & 0x03FFFFFC; /* Extract target address */ 168 if (instr & 0x02000000) 169 tp->ftt_dest |= 0xFC000000; 170 /* Use as offset if not absolute address. */ 171 if (!(instr & 0x02)) 172 tp->ftt_dest += pc; 173 break; 174 case 19: 175 switch (OPX(instr)) { 176 case 528: /* bcctr */ 177 tp->ftt_type = FASTTRAP_T_BCTR; 178 tp->ftt_bo = OP_BO(instr); 179 tp->ftt_bi = OP_BI(instr); 180 break; 181 case 16: /* bclr */ 182 tp->ftt_type = FASTTRAP_T_BCTR; 183 tp->ftt_bo = OP_BO(instr); 184 tp->ftt_bi = OP_BI(instr); 185 break; 186 }; 187 break; 188 case 24: 189 if (OP_RS(instr) == OP_RA(instr) && 190 (instr & 0x0000FFFF) == 0) 191 tp->ftt_type = FASTTRAP_T_NOP; 192 break; 193 }; 194 195 /* 196 * We don't know how this tracepoint is going to be used, but in case 197 * it's used as part of a function return probe, we need to indicate 198 * whether it's always a return site or only potentially a return 199 * site. If it's part of a return probe, it's always going to be a 200 * return from that function if it's a restore instruction or if 201 * the previous instruction was a return. If we could reliably 202 * distinguish jump tables from return sites, this wouldn't be 203 * necessary. 204 */ 205#if 0 206 if (tp->ftt_type != FASTTRAP_T_RESTORE && 207 (uread(p, &instr, 4, pc - sizeof (instr)) != 0 || 208 !(OP(instr) == 2 && OP3(instr) == OP3_RETURN))) 209 tp->ftt_flags |= FASTTRAP_F_RETMAYBE; 210#endif 211 212 return (0); 213} 214 215static uint64_t 216fasttrap_anarg(struct reg *rp, int argno) 217{ 218 uint64_t value; 219 proc_t *p = curproc; 220 221 /* The first 8 arguments are in registers. */ 222 if (argno < 8) 223 return rp->fixreg[argno + 3]; 224 225 /* Arguments on stack start after SP+LR (2 register slots). */ 226 if (SV_PROC_FLAG(p, SV_ILP32)) { 227 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); 228 value = dtrace_fuword32((void *)(rp->fixreg[1] + 8 + 229 ((argno - 8) * sizeof(uint32_t)))); 230 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT | CPU_DTRACE_BADADDR); 231 } else { 232 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); 233 value = dtrace_fuword64((void *)(rp->fixreg[1] + 48 + 234 ((argno - 8) * sizeof(uint64_t)))); 235 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT | CPU_DTRACE_BADADDR); 236 } 237 return value; 238} 239 240uint64_t 241fasttrap_pid_getarg(void *arg, dtrace_id_t id, void *parg, int argno, 242 int aframes) 243{ 244 struct reg r; 245 246 fill_regs(curthread, &r); 247 248 return (fasttrap_anarg(&r, argno)); 249} 250 251uint64_t 252fasttrap_usdt_getarg(void *arg, dtrace_id_t id, void *parg, int argno, 253 int aframes) 254{ 255 struct reg r; 256 257 fill_regs(curthread, &r); 258 259 return (fasttrap_anarg(&r, argno)); 260} 261 262static void 263fasttrap_usdt_args(fasttrap_probe_t *probe, struct reg *rp, int argc, 264 uintptr_t *argv) 265{ 266 int i, x, cap = MIN(argc, probe->ftp_nargs); 267 268 for (i = 0; i < cap; i++) { 269 x = probe->ftp_argmap[i]; 270 271 if (x < 8) 272 argv[i] = rp->fixreg[x]; 273 else 274 if (SV_PROC_FLAG(curproc, SV_ILP32)) 275 argv[i] = fuword32((void *)(rp->fixreg[1] + 8 + 276 (x * sizeof(uint32_t)))); 277 else 278 argv[i] = fuword64((void *)(rp->fixreg[1] + 48 + 279 (x * sizeof(uint64_t)))); 280 } 281 282 for (; i < argc; i++) { 283 argv[i] = 0; 284 } 285} 286 287static void 288fasttrap_return_common(struct reg *rp, uintptr_t pc, pid_t pid, 289 uintptr_t new_pc) 290{
| 37#include <sys/sysent.h> 38 39#define OP(x) ((x) >> 26) 40#define OPX(x) (((x) >> 2) & 0x3FF) 41#define OP_BO(x) (((x) & 0x03E00000) >> 21) 42#define OP_BI(x) (((x) & 0x001F0000) >> 16) 43#define OP_RS(x) (((x) & 0x03E00000) >> 21) 44#define OP_RA(x) (((x) & 0x001F0000) >> 16) 45#define OP_RB(x) (((x) & 0x0000F100) >> 11) 46 47static int 48uread(proc_t *p, void *kaddr, size_t len, uintptr_t uaddr) 49{ 50 ssize_t n; 51 52 PHOLD(p); 53 n = proc_readmem(curthread, p, uaddr, kaddr, len); 54 PRELE(p); 55 if (n <= 0 || n < len) 56 return (ENOMEM); 57 return (0); 58} 59 60static int 61uwrite(proc_t *p, void *kaddr, size_t len, uintptr_t uaddr) 62{ 63 ssize_t n; 64 65 PHOLD(p); 66 n = proc_writemem(curthread, p, uaddr, kaddr, len); 67 PRELE(p); 68 if (n <= 0 || n < len) 69 return (ENOMEM); 70 return (0); 71} 72 73int 74fasttrap_tracepoint_install(proc_t *p, fasttrap_tracepoint_t *tp) 75{ 76 fasttrap_instr_t instr = FASTTRAP_INSTR; 77 78 if (uwrite(p, &instr, 4, tp->ftt_pc) != 0) 79 return (-1); 80 81 return (0); 82} 83 84int 85fasttrap_tracepoint_remove(proc_t *p, fasttrap_tracepoint_t *tp) 86{ 87 uint32_t instr; 88 89 /* 90 * Distinguish between read or write failures and a changed 91 * instruction. 92 */ 93 if (uread(p, &instr, 4, tp->ftt_pc) != 0) 94 return (0); 95 if (instr != FASTTRAP_INSTR) 96 return (0); 97 if (uwrite(p, &tp->ftt_instr, 4, tp->ftt_pc) != 0) 98 return (-1); 99 100 return (0); 101} 102 103int 104fasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp, uintptr_t pc, 105 fasttrap_probe_type_t type) 106{ 107 uint32_t instr; 108 //int32_t disp; 109 110 /* 111 * Read the instruction at the given address out of the process's 112 * address space. We don't have to worry about a debugger 113 * changing this instruction before we overwrite it with our trap 114 * instruction since P_PR_LOCK is set. 115 */ 116 if (uread(p, &instr, 4, pc) != 0) 117 return (-1); 118 119 /* 120 * Decode the instruction to fill in the probe flags. We can have 121 * the process execute most instructions on its own using a pc/npc 122 * trick, but pc-relative control transfer present a problem since 123 * we're relocating the instruction. We emulate these instructions 124 * in the kernel. We assume a default type and over-write that as 125 * needed. 126 * 127 * pc-relative instructions must be emulated for correctness; 128 * other instructions (which represent a large set of commonly traced 129 * instructions) are emulated or otherwise optimized for performance. 130 */ 131 tp->ftt_type = FASTTRAP_T_COMMON; 132 tp->ftt_instr = instr; 133 134 switch (OP(instr)) { 135 /* The following are invalid for trapping (invalid opcodes, tw/twi). */ 136 case 0: 137 case 1: 138 case 2: 139 case 4: 140 case 5: 141 case 6: 142 case 30: 143 case 39: 144 case 58: 145 case 62: 146 case 3: /* twi */ 147 return (-1); 148 case 31: /* tw */ 149 if (OPX(instr) == 4) 150 return (-1); 151 else if (OPX(instr) == 444 && OP_RS(instr) == OP_RA(instr) && 152 OP_RS(instr) == OP_RB(instr)) 153 tp->ftt_type = FASTTRAP_T_NOP; 154 break; 155 case 16: 156 tp->ftt_type = FASTTRAP_T_BC; 157 tp->ftt_dest = instr & 0x0000FFFC; /* Extract target address */ 158 if (instr & 0x00008000) 159 tp->ftt_dest |= 0xFFFF0000; 160 /* Use as offset if not absolute address. */ 161 if (!(instr & 0x02)) 162 tp->ftt_dest += pc; 163 tp->ftt_bo = OP_BO(instr); 164 tp->ftt_bi = OP_BI(instr); 165 break; 166 case 18: 167 tp->ftt_type = FASTTRAP_T_B; 168 tp->ftt_dest = instr & 0x03FFFFFC; /* Extract target address */ 169 if (instr & 0x02000000) 170 tp->ftt_dest |= 0xFC000000; 171 /* Use as offset if not absolute address. */ 172 if (!(instr & 0x02)) 173 tp->ftt_dest += pc; 174 break; 175 case 19: 176 switch (OPX(instr)) { 177 case 528: /* bcctr */ 178 tp->ftt_type = FASTTRAP_T_BCTR; 179 tp->ftt_bo = OP_BO(instr); 180 tp->ftt_bi = OP_BI(instr); 181 break; 182 case 16: /* bclr */ 183 tp->ftt_type = FASTTRAP_T_BCTR; 184 tp->ftt_bo = OP_BO(instr); 185 tp->ftt_bi = OP_BI(instr); 186 break; 187 }; 188 break; 189 case 24: 190 if (OP_RS(instr) == OP_RA(instr) && 191 (instr & 0x0000FFFF) == 0) 192 tp->ftt_type = FASTTRAP_T_NOP; 193 break; 194 }; 195 196 /* 197 * We don't know how this tracepoint is going to be used, but in case 198 * it's used as part of a function return probe, we need to indicate 199 * whether it's always a return site or only potentially a return 200 * site. If it's part of a return probe, it's always going to be a 201 * return from that function if it's a restore instruction or if 202 * the previous instruction was a return. If we could reliably 203 * distinguish jump tables from return sites, this wouldn't be 204 * necessary. 205 */ 206#if 0 207 if (tp->ftt_type != FASTTRAP_T_RESTORE && 208 (uread(p, &instr, 4, pc - sizeof (instr)) != 0 || 209 !(OP(instr) == 2 && OP3(instr) == OP3_RETURN))) 210 tp->ftt_flags |= FASTTRAP_F_RETMAYBE; 211#endif 212 213 return (0); 214} 215 216static uint64_t 217fasttrap_anarg(struct reg *rp, int argno) 218{ 219 uint64_t value; 220 proc_t *p = curproc; 221 222 /* The first 8 arguments are in registers. */ 223 if (argno < 8) 224 return rp->fixreg[argno + 3]; 225 226 /* Arguments on stack start after SP+LR (2 register slots). */ 227 if (SV_PROC_FLAG(p, SV_ILP32)) { 228 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); 229 value = dtrace_fuword32((void *)(rp->fixreg[1] + 8 + 230 ((argno - 8) * sizeof(uint32_t)))); 231 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT | CPU_DTRACE_BADADDR); 232 } else { 233 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); 234 value = dtrace_fuword64((void *)(rp->fixreg[1] + 48 + 235 ((argno - 8) * sizeof(uint64_t)))); 236 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT | CPU_DTRACE_BADADDR); 237 } 238 return value; 239} 240 241uint64_t 242fasttrap_pid_getarg(void *arg, dtrace_id_t id, void *parg, int argno, 243 int aframes) 244{ 245 struct reg r; 246 247 fill_regs(curthread, &r); 248 249 return (fasttrap_anarg(&r, argno)); 250} 251 252uint64_t 253fasttrap_usdt_getarg(void *arg, dtrace_id_t id, void *parg, int argno, 254 int aframes) 255{ 256 struct reg r; 257 258 fill_regs(curthread, &r); 259 260 return (fasttrap_anarg(&r, argno)); 261} 262 263static void 264fasttrap_usdt_args(fasttrap_probe_t *probe, struct reg *rp, int argc, 265 uintptr_t *argv) 266{ 267 int i, x, cap = MIN(argc, probe->ftp_nargs); 268 269 for (i = 0; i < cap; i++) { 270 x = probe->ftp_argmap[i]; 271 272 if (x < 8) 273 argv[i] = rp->fixreg[x]; 274 else 275 if (SV_PROC_FLAG(curproc, SV_ILP32)) 276 argv[i] = fuword32((void *)(rp->fixreg[1] + 8 + 277 (x * sizeof(uint32_t)))); 278 else 279 argv[i] = fuword64((void *)(rp->fixreg[1] + 48 + 280 (x * sizeof(uint64_t)))); 281 } 282 283 for (; i < argc; i++) { 284 argv[i] = 0; 285 } 286} 287 288static void 289fasttrap_return_common(struct reg *rp, uintptr_t pc, pid_t pid, 290 uintptr_t new_pc) 291{
|
| 292 struct rm_priotracker tracker;
|
291 fasttrap_tracepoint_t *tp; 292 fasttrap_bucket_t *bucket; 293 fasttrap_id_t *id; 294
| 293 fasttrap_tracepoint_t *tp; 294 fasttrap_bucket_t *bucket; 295 fasttrap_id_t *id; 296
|
| 297 rm_rlock(&fasttrap_tp_lock, &tracker);
|
295 bucket = &fasttrap_tpoints.fth_table[FASTTRAP_TPOINTS_INDEX(pid, pc)]; 296 297 for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) { 298 if (pid == tp->ftt_pid && pc == tp->ftt_pc && 299 tp->ftt_proc->ftpc_acount != 0) 300 break; 301 } 302 303 /* 304 * Don't sweat it if we can't find the tracepoint again; unlike 305 * when we're in fasttrap_pid_probe(), finding the tracepoint here 306 * is not essential to the correct execution of the process. 307 */ 308 if (tp == NULL) {
| 298 bucket = &fasttrap_tpoints.fth_table[FASTTRAP_TPOINTS_INDEX(pid, pc)]; 299 300 for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) { 301 if (pid == tp->ftt_pid && pc == tp->ftt_pc && 302 tp->ftt_proc->ftpc_acount != 0) 303 break; 304 } 305 306 /* 307 * Don't sweat it if we can't find the tracepoint again; unlike 308 * when we're in fasttrap_pid_probe(), finding the tracepoint here 309 * is not essential to the correct execution of the process. 310 */ 311 if (tp == NULL) {
|
| 312 rm_runlock(&fasttrap_tp_lock, &tracker);
|
309 return; 310 } 311 312 for (id = tp->ftt_retids; id != NULL; id = id->fti_next) { 313 /* 314 * If there's a branch that could act as a return site, we 315 * need to trace it, and check here if the program counter is 316 * external to the function. 317 */ 318 /* Skip function-local branches. */ 319 if ((new_pc - id->fti_probe->ftp_faddr) < id->fti_probe->ftp_fsize) 320 continue; 321 322 dtrace_probe(id->fti_probe->ftp_id, 323 pc - id->fti_probe->ftp_faddr, 324 rp->fixreg[3], rp->fixreg[4], 0, 0); 325 }
| 313 return; 314 } 315 316 for (id = tp->ftt_retids; id != NULL; id = id->fti_next) { 317 /* 318 * If there's a branch that could act as a return site, we 319 * need to trace it, and check here if the program counter is 320 * external to the function. 321 */ 322 /* Skip function-local branches. */ 323 if ((new_pc - id->fti_probe->ftp_faddr) < id->fti_probe->ftp_fsize) 324 continue; 325 326 dtrace_probe(id->fti_probe->ftp_id, 327 pc - id->fti_probe->ftp_faddr, 328 rp->fixreg[3], rp->fixreg[4], 0, 0); 329 }
|
| 330 rm_runlock(&fasttrap_tp_lock, &tracker);
|
326} 327 328 329static int 330fasttrap_branch_taken(int bo, int bi, struct reg *regs) 331{ 332 int crzero = 0; 333 334 /* Branch always? */ 335 if ((bo & 0x14) == 0x14) 336 return 1; 337 338 /* Handle decrementing ctr */ 339 if (!(bo & 0x04)) { 340 --regs->ctr; 341 crzero = (regs->ctr == 0); 342 if (bo & 0x10) { 343 return (!(crzero ^ (bo >> 1))); 344 } 345 } 346 347 return (crzero | (((regs->cr >> (31 - bi)) ^ (bo >> 3)) ^ 1)); 348} 349 350 351int 352fasttrap_pid_probe(struct reg *rp) 353{
| 331} 332 333 334static int 335fasttrap_branch_taken(int bo, int bi, struct reg *regs) 336{ 337 int crzero = 0; 338 339 /* Branch always? */ 340 if ((bo & 0x14) == 0x14) 341 return 1; 342 343 /* Handle decrementing ctr */ 344 if (!(bo & 0x04)) { 345 --regs->ctr; 346 crzero = (regs->ctr == 0); 347 if (bo & 0x10) { 348 return (!(crzero ^ (bo >> 1))); 349 } 350 } 351 352 return (crzero | (((regs->cr >> (31 - bi)) ^ (bo >> 3)) ^ 1)); 353} 354 355 356int 357fasttrap_pid_probe(struct reg *rp) 358{
|
| 359 struct rm_priotracker tracker;
|
354 proc_t *p = curproc; 355 uintptr_t pc = rp->pc; 356 uintptr_t new_pc = 0; 357 fasttrap_bucket_t *bucket; 358 fasttrap_tracepoint_t *tp, tp_local; 359 pid_t pid; 360 dtrace_icookie_t cookie; 361 uint_t is_enabled = 0; 362 363 /* 364 * It's possible that a user (in a veritable orgy of bad planning) 365 * could redirect this thread's flow of control before it reached the 366 * return probe fasttrap. In this case we need to kill the process 367 * since it's in a unrecoverable state. 368 */ 369 if (curthread->t_dtrace_step) { 370 ASSERT(curthread->t_dtrace_on); 371 fasttrap_sigtrap(p, curthread, pc); 372 return (0); 373 } 374 375 /* 376 * Clear all user tracing flags. 377 */ 378 curthread->t_dtrace_ft = 0; 379 curthread->t_dtrace_pc = 0; 380 curthread->t_dtrace_npc = 0; 381 curthread->t_dtrace_scrpc = 0; 382 curthread->t_dtrace_astpc = 0; 383
| 360 proc_t *p = curproc; 361 uintptr_t pc = rp->pc; 362 uintptr_t new_pc = 0; 363 fasttrap_bucket_t *bucket; 364 fasttrap_tracepoint_t *tp, tp_local; 365 pid_t pid; 366 dtrace_icookie_t cookie; 367 uint_t is_enabled = 0; 368 369 /* 370 * It's possible that a user (in a veritable orgy of bad planning) 371 * could redirect this thread's flow of control before it reached the 372 * return probe fasttrap. In this case we need to kill the process 373 * since it's in a unrecoverable state. 374 */ 375 if (curthread->t_dtrace_step) { 376 ASSERT(curthread->t_dtrace_on); 377 fasttrap_sigtrap(p, curthread, pc); 378 return (0); 379 } 380 381 /* 382 * Clear all user tracing flags. 383 */ 384 curthread->t_dtrace_ft = 0; 385 curthread->t_dtrace_pc = 0; 386 curthread->t_dtrace_npc = 0; 387 curthread->t_dtrace_scrpc = 0; 388 curthread->t_dtrace_astpc = 0; 389
|
384 385 PROC_LOCK(p);
| 390 rm_rlock(&fasttrap_tp_lock, &tracker);
|
386 pid = p->p_pid; 387 bucket = &fasttrap_tpoints.fth_table[FASTTRAP_TPOINTS_INDEX(pid, pc)]; 388 389 /* 390 * Lookup the tracepoint that the process just hit. 391 */ 392 for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) { 393 if (pid == tp->ftt_pid && pc == tp->ftt_pc && 394 tp->ftt_proc->ftpc_acount != 0) 395 break; 396 } 397 398 /* 399 * If we couldn't find a matching tracepoint, either a tracepoint has 400 * been inserted without using the pid<pid> ioctl interface (see 401 * fasttrap_ioctl), or somehow we have mislaid this tracepoint. 402 */ 403 if (tp == NULL) {
| 391 pid = p->p_pid; 392 bucket = &fasttrap_tpoints.fth_table[FASTTRAP_TPOINTS_INDEX(pid, pc)]; 393 394 /* 395 * Lookup the tracepoint that the process just hit. 396 */ 397 for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) { 398 if (pid == tp->ftt_pid && pc == tp->ftt_pc && 399 tp->ftt_proc->ftpc_acount != 0) 400 break; 401 } 402 403 /* 404 * If we couldn't find a matching tracepoint, either a tracepoint has 405 * been inserted without using the pid<pid> ioctl interface (see 406 * fasttrap_ioctl), or somehow we have mislaid this tracepoint. 407 */ 408 if (tp == NULL) {
|
404 PROC_UNLOCK(p);
| 409 rm_runlock(&fasttrap_tp_lock, &tracker);
|
405 return (-1); 406 } 407 408 if (tp->ftt_ids != NULL) { 409 fasttrap_id_t *id; 410 411 for (id = tp->ftt_ids; id != NULL; id = id->fti_next) { 412 fasttrap_probe_t *probe = id->fti_probe; 413 414 if (id->fti_ptype == DTFTP_ENTRY) { 415 /* 416 * We note that this was an entry 417 * probe to help ustack() find the 418 * first caller. 419 */ 420 cookie = dtrace_interrupt_disable(); 421 DTRACE_CPUFLAG_SET(CPU_DTRACE_ENTRY); 422 dtrace_probe(probe->ftp_id, rp->fixreg[3], 423 rp->fixreg[4], rp->fixreg[5], rp->fixreg[6], 424 rp->fixreg[7]); 425 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_ENTRY); 426 dtrace_interrupt_enable(cookie); 427 } else if (id->fti_ptype == DTFTP_IS_ENABLED) { 428 /* 429 * Note that in this case, we don't 430 * call dtrace_probe() since it's only 431 * an artificial probe meant to change 432 * the flow of control so that it 433 * encounters the true probe. 434 */ 435 is_enabled = 1; 436 } else if (probe->ftp_argmap == NULL) { 437 dtrace_probe(probe->ftp_id, rp->fixreg[3], 438 rp->fixreg[4], rp->fixreg[5], rp->fixreg[6], 439 rp->fixreg[7]); 440 } else { 441 uintptr_t t[5]; 442 443 fasttrap_usdt_args(probe, rp, 444 sizeof (t) / sizeof (t[0]), t); 445 446 dtrace_probe(probe->ftp_id, t[0], t[1], 447 t[2], t[3], t[4]); 448 } 449 } 450 } 451 452 /* 453 * We're about to do a bunch of work so we cache a local copy of 454 * the tracepoint to emulate the instruction, and then find the 455 * tracepoint again later if we need to light up any return probes. 456 */ 457 tp_local = *tp;
| 410 return (-1); 411 } 412 413 if (tp->ftt_ids != NULL) { 414 fasttrap_id_t *id; 415 416 for (id = tp->ftt_ids; id != NULL; id = id->fti_next) { 417 fasttrap_probe_t *probe = id->fti_probe; 418 419 if (id->fti_ptype == DTFTP_ENTRY) { 420 /* 421 * We note that this was an entry 422 * probe to help ustack() find the 423 * first caller. 424 */ 425 cookie = dtrace_interrupt_disable(); 426 DTRACE_CPUFLAG_SET(CPU_DTRACE_ENTRY); 427 dtrace_probe(probe->ftp_id, rp->fixreg[3], 428 rp->fixreg[4], rp->fixreg[5], rp->fixreg[6], 429 rp->fixreg[7]); 430 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_ENTRY); 431 dtrace_interrupt_enable(cookie); 432 } else if (id->fti_ptype == DTFTP_IS_ENABLED) { 433 /* 434 * Note that in this case, we don't 435 * call dtrace_probe() since it's only 436 * an artificial probe meant to change 437 * the flow of control so that it 438 * encounters the true probe. 439 */ 440 is_enabled = 1; 441 } else if (probe->ftp_argmap == NULL) { 442 dtrace_probe(probe->ftp_id, rp->fixreg[3], 443 rp->fixreg[4], rp->fixreg[5], rp->fixreg[6], 444 rp->fixreg[7]); 445 } else { 446 uintptr_t t[5]; 447 448 fasttrap_usdt_args(probe, rp, 449 sizeof (t) / sizeof (t[0]), t); 450 451 dtrace_probe(probe->ftp_id, t[0], t[1], 452 t[2], t[3], t[4]); 453 } 454 } 455 } 456 457 /* 458 * We're about to do a bunch of work so we cache a local copy of 459 * the tracepoint to emulate the instruction, and then find the 460 * tracepoint again later if we need to light up any return probes. 461 */ 462 tp_local = *tp;
|
458 PROC_UNLOCK(p);
| 463 rm_runlock(&fasttrap_tp_lock, &tracker);
|
459 tp = &tp_local; 460 461 /* 462 * If there's an is-enabled probe connected to this tracepoint it 463 * means that there was a 'xor r3, r3, r3' 464 * instruction that was placed there by DTrace when the binary was 465 * linked. As this probe is, in fact, enabled, we need to stuff 1 466 * into R3. Accordingly, we can bypass all the instruction 467 * emulation logic since we know the inevitable result. It's possible 468 * that a user could construct a scenario where the 'is-enabled' 469 * probe was on some other instruction, but that would be a rather 470 * exotic way to shoot oneself in the foot. 471 */ 472 if (is_enabled) { 473 rp->fixreg[3] = 1; 474 new_pc = rp->pc + 4; 475 goto done; 476 } 477 478 479 switch (tp->ftt_type) { 480 case FASTTRAP_T_NOP: 481 new_pc = rp->pc + 4; 482 break; 483 case FASTTRAP_T_BC: 484 if (!fasttrap_branch_taken(tp->ftt_bo, tp->ftt_bi, rp)) 485 break; 486 /* FALLTHROUGH */ 487 case FASTTRAP_T_B: 488 if (tp->ftt_instr & 0x01) 489 rp->lr = rp->pc + 4; 490 new_pc = tp->ftt_dest; 491 break; 492 case FASTTRAP_T_BLR: 493 case FASTTRAP_T_BCTR: 494 if (!fasttrap_branch_taken(tp->ftt_bo, tp->ftt_bi, rp)) 495 break; 496 /* FALLTHROUGH */ 497 if (tp->ftt_type == FASTTRAP_T_BCTR) 498 new_pc = rp->ctr; 499 else 500 new_pc = rp->lr; 501 if (tp->ftt_instr & 0x01) 502 rp->lr = rp->pc + 4; 503 break; 504 case FASTTRAP_T_COMMON: 505 break; 506 }; 507done: 508 /* 509 * If there were no return probes when we first found the tracepoint, 510 * we should feel no obligation to honor any return probes that were 511 * subsequently enabled -- they'll just have to wait until the next 512 * time around. 513 */ 514 if (tp->ftt_retids != NULL) { 515 /* 516 * We need to wait until the results of the instruction are 517 * apparent before invoking any return probes. If this 518 * instruction was emulated we can just call 519 * fasttrap_return_common(); if it needs to be executed, we 520 * need to wait until the user thread returns to the kernel. 521 */ 522 if (tp->ftt_type != FASTTRAP_T_COMMON) { 523 fasttrap_return_common(rp, pc, pid, new_pc); 524 } else { 525 ASSERT(curthread->t_dtrace_ret != 0); 526 ASSERT(curthread->t_dtrace_pc == pc); 527 ASSERT(curthread->t_dtrace_scrpc != 0); 528 ASSERT(new_pc == curthread->t_dtrace_astpc); 529 } 530 } 531 532 rp->pc = new_pc; 533 set_regs(curthread, rp); 534 535 return (0); 536} 537 538int 539fasttrap_return_probe(struct reg *rp) 540{ 541 proc_t *p = curproc; 542 uintptr_t pc = curthread->t_dtrace_pc; 543 uintptr_t npc = curthread->t_dtrace_npc; 544 545 curthread->t_dtrace_pc = 0; 546 curthread->t_dtrace_npc = 0; 547 curthread->t_dtrace_scrpc = 0; 548 curthread->t_dtrace_astpc = 0; 549 550 /* 551 * We set rp->pc to the address of the traced instruction so 552 * that it appears to dtrace_probe() that we're on the original 553 * instruction, and so that the user can't easily detect our 554 * complex web of lies. dtrace_return_probe() (our caller) 555 * will correctly set %pc after we return. 556 */ 557 rp->pc = pc; 558 559 fasttrap_return_common(rp, pc, p->p_pid, npc); 560 561 return (0); 562} 563
| 464 tp = &tp_local; 465 466 /* 467 * If there's an is-enabled probe connected to this tracepoint it 468 * means that there was a 'xor r3, r3, r3' 469 * instruction that was placed there by DTrace when the binary was 470 * linked. As this probe is, in fact, enabled, we need to stuff 1 471 * into R3. Accordingly, we can bypass all the instruction 472 * emulation logic since we know the inevitable result. It's possible 473 * that a user could construct a scenario where the 'is-enabled' 474 * probe was on some other instruction, but that would be a rather 475 * exotic way to shoot oneself in the foot. 476 */ 477 if (is_enabled) { 478 rp->fixreg[3] = 1; 479 new_pc = rp->pc + 4; 480 goto done; 481 } 482 483 484 switch (tp->ftt_type) { 485 case FASTTRAP_T_NOP: 486 new_pc = rp->pc + 4; 487 break; 488 case FASTTRAP_T_BC: 489 if (!fasttrap_branch_taken(tp->ftt_bo, tp->ftt_bi, rp)) 490 break; 491 /* FALLTHROUGH */ 492 case FASTTRAP_T_B: 493 if (tp->ftt_instr & 0x01) 494 rp->lr = rp->pc + 4; 495 new_pc = tp->ftt_dest; 496 break; 497 case FASTTRAP_T_BLR: 498 case FASTTRAP_T_BCTR: 499 if (!fasttrap_branch_taken(tp->ftt_bo, tp->ftt_bi, rp)) 500 break; 501 /* FALLTHROUGH */ 502 if (tp->ftt_type == FASTTRAP_T_BCTR) 503 new_pc = rp->ctr; 504 else 505 new_pc = rp->lr; 506 if (tp->ftt_instr & 0x01) 507 rp->lr = rp->pc + 4; 508 break; 509 case FASTTRAP_T_COMMON: 510 break; 511 }; 512done: 513 /* 514 * If there were no return probes when we first found the tracepoint, 515 * we should feel no obligation to honor any return probes that were 516 * subsequently enabled -- they'll just have to wait until the next 517 * time around. 518 */ 519 if (tp->ftt_retids != NULL) { 520 /* 521 * We need to wait until the results of the instruction are 522 * apparent before invoking any return probes. If this 523 * instruction was emulated we can just call 524 * fasttrap_return_common(); if it needs to be executed, we 525 * need to wait until the user thread returns to the kernel. 526 */ 527 if (tp->ftt_type != FASTTRAP_T_COMMON) { 528 fasttrap_return_common(rp, pc, pid, new_pc); 529 } else { 530 ASSERT(curthread->t_dtrace_ret != 0); 531 ASSERT(curthread->t_dtrace_pc == pc); 532 ASSERT(curthread->t_dtrace_scrpc != 0); 533 ASSERT(new_pc == curthread->t_dtrace_astpc); 534 } 535 } 536 537 rp->pc = new_pc; 538 set_regs(curthread, rp); 539 540 return (0); 541} 542 543int 544fasttrap_return_probe(struct reg *rp) 545{ 546 proc_t *p = curproc; 547 uintptr_t pc = curthread->t_dtrace_pc; 548 uintptr_t npc = curthread->t_dtrace_npc; 549 550 curthread->t_dtrace_pc = 0; 551 curthread->t_dtrace_npc = 0; 552 curthread->t_dtrace_scrpc = 0; 553 curthread->t_dtrace_astpc = 0; 554 555 /* 556 * We set rp->pc to the address of the traced instruction so 557 * that it appears to dtrace_probe() that we're on the original 558 * instruction, and so that the user can't easily detect our 559 * complex web of lies. dtrace_return_probe() (our caller) 560 * will correctly set %pc after we return. 561 */ 562 rp->pc = pc; 563 564 fasttrap_return_common(rp, pc, p->p_pid, npc); 565 566 return (0); 567} 568
|