53 54typedef struct dtrace_invop_hdlr { 55 int (*dtih_func)(uintptr_t, struct trapframe *, uintptr_t); 56 struct dtrace_invop_hdlr *dtih_next; 57} dtrace_invop_hdlr_t; 58 59dtrace_invop_hdlr_t *dtrace_invop_hdlr; 60 61int 62dtrace_invop(uintptr_t addr, struct trapframe *stack, uintptr_t eax) 63{ 64 dtrace_invop_hdlr_t *hdlr; 65 int rval; 66 67 for (hdlr = dtrace_invop_hdlr; hdlr != NULL; hdlr = hdlr->dtih_next) 68 if ((rval = hdlr->dtih_func(addr, stack, eax)) != 0) 69 return (rval); 70 71 return (0); 72} 73 74void 75dtrace_invop_add(int (*func)(uintptr_t, struct trapframe *, uintptr_t)) 76{ 77 dtrace_invop_hdlr_t *hdlr; 78 79 hdlr = kmem_alloc(sizeof (dtrace_invop_hdlr_t), KM_SLEEP); 80 hdlr->dtih_func = func; 81 hdlr->dtih_next = dtrace_invop_hdlr; 82 dtrace_invop_hdlr = hdlr; 83} 84 85void 86dtrace_invop_remove(int (*func)(uintptr_t, struct trapframe *, uintptr_t)) 87{ 88 dtrace_invop_hdlr_t *hdlr, *prev; 89 90 hdlr = dtrace_invop_hdlr; 91 prev = NULL; 92 93 for (;;) { 94 if (hdlr == NULL) 95 panic("attempt to remove non-existent invop handler"); 96 97 if (hdlr->dtih_func == func) 98 break; 99 100 prev = hdlr; 101 hdlr = hdlr->dtih_next; 102 } 103 104 if (prev == NULL) { 105 ASSERT(dtrace_invop_hdlr == hdlr); 106 dtrace_invop_hdlr = hdlr->dtih_next; 107 } else { 108 ASSERT(dtrace_invop_hdlr != hdlr); 109 prev->dtih_next = hdlr->dtih_next; 110 } 111 112 kmem_free(hdlr, 0); 113} 114 115/*ARGSUSED*/ 116void 117dtrace_toxic_ranges(void (*func)(uintptr_t base, uintptr_t limit)) 118{ 119 /* 120 * No toxic regions? 121 */ 122} 123 124void 125dtrace_xcall(processorid_t cpu, dtrace_xcall_t func, void *arg) 126{ 127 cpuset_t cpus; 128 129 if (cpu == DTRACE_CPUALL) 130 cpus = all_cpus; 131 else 132 CPU_SETOF(cpu, &cpus); 133 134 smp_rendezvous_cpus(cpus, smp_no_rendezvous_barrier, func, 135 smp_no_rendezvous_barrier, arg); 136} 137 138static void 139dtrace_sync_func(void) 140{ 141} 142 143void 144dtrace_sync(void) 145{ 146 dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)dtrace_sync_func, NULL); 147} 148 149/* 150 * DTrace needs a high resolution time function which can 151 * be called from a probe context and guaranteed not to have 152 * instrumented with probes itself. 153 * 154 * Returns nanoseconds since boot. 155 */ 156uint64_t 157dtrace_gethrtime() 158{ 159 struct timespec curtime; 160 161 nanouptime(&curtime); 162 163 return (curtime.tv_sec * 1000000000UL + curtime.tv_nsec); 164 165} 166 167uint64_t 168dtrace_gethrestime(void) 169{ 170 struct timespec curtime; 171 172 getnanotime(&curtime); 173 174 return (curtime.tv_sec * 1000000000UL + curtime.tv_nsec); 175} 176 177/* Function to handle DTrace traps during probes. See amd64/amd64/trap.c */ 178int 179dtrace_trap(struct trapframe *frame, u_int type) 180{ 181 182 /* 183 * A trap can occur while DTrace executes a probe. Before 184 * executing the probe, DTrace blocks re-scheduling and sets 185 * a flag in its per-cpu flags to indicate that it doesn't 186 * want to fault. On returning from the probe, the no-fault 187 * flag is cleared and finally re-scheduling is enabled. 188 * 189 * Check if DTrace has enabled 'no-fault' mode: 190 */ 191 if ((cpu_core[curcpu].cpuc_dtrace_flags & CPU_DTRACE_NOFAULT) != 0) { 192 /* 193 * There are only a couple of trap types that are expected. 194 * All the rest will be handled in the usual way. 195 */ 196 switch (type) { 197 /* Page fault. */ 198 case T_TLB_ST_MISS: 199 case T_ADDR_ERR_ST: 200 case T_TLB_LD_MISS: 201 case T_ADDR_ERR_LD: 202 case T_BUS_ERR_IFETCH: 203 /* Flag a bad address. */ 204 cpu_core[curcpu].cpuc_dtrace_flags |= CPU_DTRACE_BADADDR; 205 cpu_core[curcpu].cpuc_dtrace_illval = frame->badvaddr; 206 207 /* 208 * Offset the instruction pointer to the instruction 209 * following the one causing the fault. 210 */ 211 if (DELAYBRANCH(frame->cause)) /* Check BD bit */ 212 { 213 /* XXX: check MipsEmulateBranch on MIPS64 214 frame->pc = MipsEmulateBranch(frame, frame->pc, 215 0, 0); 216 */ 217 panic("%s: delay slot at %jx, badvaddr = %jx\n", 218 __func__, 219 (intmax_t)frame->pc, (intmax_t)frame->badvaddr); 220 } 221 else 222 frame->pc += sizeof(int); 223 return (1); 224 default: 225 /* Handle all other traps in the usual way. */ 226 break; 227 } 228 } 229 230 /* Handle the trap in the usual way. */ 231 return (0); 232} 233 234void 235dtrace_probe_error(dtrace_state_t *state, dtrace_epid_t epid, int which, 236 int fault, int fltoffs, uintptr_t illval) 237{ 238 239 dtrace_probe(dtrace_probeid_error, (uint64_t)(uintptr_t)state, 240 (uintptr_t)epid, 241 (uintptr_t)which, (uintptr_t)fault, (uintptr_t)fltoffs); 242} 243 244static int 245dtrace_invop_start(struct trapframe *frame) 246{ 247 register_t *sp; 248 int16_t offs; 249 int invop; 250 251 invop = dtrace_invop(frame->pc, frame, frame->pc); 252 offs = (invop & LDSD_DATA_MASK); 253 sp = (register_t *)((uint8_t *)frame->sp + offs); 254 255 switch (invop & LDSD_RA_SP_MASK) { 256 case LD_RA_SP: 257 frame->ra = *sp; 258 frame->pc += INSN_SIZE; 259 break; 260 case SD_RA_SP: 261 *(sp) = frame->ra; 262 frame->pc += INSN_SIZE; 263 break; 264 default: 265 printf("%s: 0x%x undefined\n", __func__, invop); 266 return (-1); 267 }; 268 269 return (0); 270} 271 272void 273dtrace_invop_init(void) 274{ 275 276 dtrace_invop_jump_addr = dtrace_invop_start; 277} 278 279void 280dtrace_invop_uninit(void) 281{ 282 283 dtrace_invop_jump_addr = 0; 284}
| 55 56typedef struct dtrace_invop_hdlr { 57 int (*dtih_func)(uintptr_t, struct trapframe *, uintptr_t); 58 struct dtrace_invop_hdlr *dtih_next; 59} dtrace_invop_hdlr_t; 60 61dtrace_invop_hdlr_t *dtrace_invop_hdlr; 62 63int 64dtrace_invop(uintptr_t addr, struct trapframe *stack, uintptr_t eax) 65{ 66 dtrace_invop_hdlr_t *hdlr; 67 int rval; 68 69 for (hdlr = dtrace_invop_hdlr; hdlr != NULL; hdlr = hdlr->dtih_next) 70 if ((rval = hdlr->dtih_func(addr, stack, eax)) != 0) 71 return (rval); 72 73 return (0); 74} 75 76void 77dtrace_invop_add(int (*func)(uintptr_t, struct trapframe *, uintptr_t)) 78{ 79 dtrace_invop_hdlr_t *hdlr; 80 81 hdlr = kmem_alloc(sizeof (dtrace_invop_hdlr_t), KM_SLEEP); 82 hdlr->dtih_func = func; 83 hdlr->dtih_next = dtrace_invop_hdlr; 84 dtrace_invop_hdlr = hdlr; 85} 86 87void 88dtrace_invop_remove(int (*func)(uintptr_t, struct trapframe *, uintptr_t)) 89{ 90 dtrace_invop_hdlr_t *hdlr, *prev; 91 92 hdlr = dtrace_invop_hdlr; 93 prev = NULL; 94 95 for (;;) { 96 if (hdlr == NULL) 97 panic("attempt to remove non-existent invop handler"); 98 99 if (hdlr->dtih_func == func) 100 break; 101 102 prev = hdlr; 103 hdlr = hdlr->dtih_next; 104 } 105 106 if (prev == NULL) { 107 ASSERT(dtrace_invop_hdlr == hdlr); 108 dtrace_invop_hdlr = hdlr->dtih_next; 109 } else { 110 ASSERT(dtrace_invop_hdlr != hdlr); 111 prev->dtih_next = hdlr->dtih_next; 112 } 113 114 kmem_free(hdlr, 0); 115} 116 117/*ARGSUSED*/ 118void 119dtrace_toxic_ranges(void (*func)(uintptr_t base, uintptr_t limit)) 120{ 121 /* 122 * No toxic regions? 123 */ 124} 125 126void 127dtrace_xcall(processorid_t cpu, dtrace_xcall_t func, void *arg) 128{ 129 cpuset_t cpus; 130 131 if (cpu == DTRACE_CPUALL) 132 cpus = all_cpus; 133 else 134 CPU_SETOF(cpu, &cpus); 135 136 smp_rendezvous_cpus(cpus, smp_no_rendezvous_barrier, func, 137 smp_no_rendezvous_barrier, arg); 138} 139 140static void 141dtrace_sync_func(void) 142{ 143} 144 145void 146dtrace_sync(void) 147{ 148 dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)dtrace_sync_func, NULL); 149} 150 151/* 152 * DTrace needs a high resolution time function which can 153 * be called from a probe context and guaranteed not to have 154 * instrumented with probes itself. 155 * 156 * Returns nanoseconds since boot. 157 */ 158uint64_t 159dtrace_gethrtime() 160{ 161 struct timespec curtime; 162 163 nanouptime(&curtime); 164 165 return (curtime.tv_sec * 1000000000UL + curtime.tv_nsec); 166 167} 168 169uint64_t 170dtrace_gethrestime(void) 171{ 172 struct timespec curtime; 173 174 getnanotime(&curtime); 175 176 return (curtime.tv_sec * 1000000000UL + curtime.tv_nsec); 177} 178 179/* Function to handle DTrace traps during probes. See amd64/amd64/trap.c */ 180int 181dtrace_trap(struct trapframe *frame, u_int type) 182{ 183 184 /* 185 * A trap can occur while DTrace executes a probe. Before 186 * executing the probe, DTrace blocks re-scheduling and sets 187 * a flag in its per-cpu flags to indicate that it doesn't 188 * want to fault. On returning from the probe, the no-fault 189 * flag is cleared and finally re-scheduling is enabled. 190 * 191 * Check if DTrace has enabled 'no-fault' mode: 192 */ 193 if ((cpu_core[curcpu].cpuc_dtrace_flags & CPU_DTRACE_NOFAULT) != 0) { 194 /* 195 * There are only a couple of trap types that are expected. 196 * All the rest will be handled in the usual way. 197 */ 198 switch (type) { 199 /* Page fault. */ 200 case T_TLB_ST_MISS: 201 case T_ADDR_ERR_ST: 202 case T_TLB_LD_MISS: 203 case T_ADDR_ERR_LD: 204 case T_BUS_ERR_IFETCH: 205 /* Flag a bad address. */ 206 cpu_core[curcpu].cpuc_dtrace_flags |= CPU_DTRACE_BADADDR; 207 cpu_core[curcpu].cpuc_dtrace_illval = frame->badvaddr; 208 209 /* 210 * Offset the instruction pointer to the instruction 211 * following the one causing the fault. 212 */ 213 if (DELAYBRANCH(frame->cause)) /* Check BD bit */ 214 { 215 /* XXX: check MipsEmulateBranch on MIPS64 216 frame->pc = MipsEmulateBranch(frame, frame->pc, 217 0, 0); 218 */ 219 panic("%s: delay slot at %jx, badvaddr = %jx\n", 220 __func__, 221 (intmax_t)frame->pc, (intmax_t)frame->badvaddr); 222 } 223 else 224 frame->pc += sizeof(int); 225 return (1); 226 default: 227 /* Handle all other traps in the usual way. */ 228 break; 229 } 230 } 231 232 /* Handle the trap in the usual way. */ 233 return (0); 234} 235 236void 237dtrace_probe_error(dtrace_state_t *state, dtrace_epid_t epid, int which, 238 int fault, int fltoffs, uintptr_t illval) 239{ 240 241 dtrace_probe(dtrace_probeid_error, (uint64_t)(uintptr_t)state, 242 (uintptr_t)epid, 243 (uintptr_t)which, (uintptr_t)fault, (uintptr_t)fltoffs); 244} 245 246static int 247dtrace_invop_start(struct trapframe *frame) 248{ 249 register_t *sp; 250 int16_t offs; 251 int invop; 252 253 invop = dtrace_invop(frame->pc, frame, frame->pc); 254 offs = (invop & LDSD_DATA_MASK); 255 sp = (register_t *)((uint8_t *)frame->sp + offs); 256 257 switch (invop & LDSD_RA_SP_MASK) { 258 case LD_RA_SP: 259 frame->ra = *sp; 260 frame->pc += INSN_SIZE; 261 break; 262 case SD_RA_SP: 263 *(sp) = frame->ra; 264 frame->pc += INSN_SIZE; 265 break; 266 default: 267 printf("%s: 0x%x undefined\n", __func__, invop); 268 return (-1); 269 }; 270 271 return (0); 272} 273 274void 275dtrace_invop_init(void) 276{ 277 278 dtrace_invop_jump_addr = dtrace_invop_start; 279} 280 281void 282dtrace_invop_uninit(void) 283{ 284 285 dtrace_invop_jump_addr = 0; 286}
|