1 /* 2 * Copyright 2005, Ingo Weinhold, bonefish@users.sf.net. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include <string.h> 7 8 #include <debugger.h> 9 #include <driver_settings.h> 10 #include <int.h> 11 #include <thread.h> 12 #include <arch/user_debugger.h> 13 14 //#define TRACE_ARCH_USER_DEBUGGER 15 #ifdef TRACE_ARCH_USER_DEBUGGER 16 # define TRACE(x) dprintf x 17 #else 18 # define TRACE(x) ; 19 #endif 20 21 #define B_NO_MORE_BREAKPOINTS B_ERROR 22 #define B_NO_MORE_WATCHPOINTS B_ERROR 23 #define B_BAD_WATCHPOINT_ALIGNMENT B_ERROR 24 #define B_WATCHPOINT_TYPE_NOT_SUPPORTED B_ERROR 25 #define B_WATCHPOINT_LENGTH_NOT_SUPPORTED B_ERROR 26 #define B_BREAKPOINT_NOT_FOUND B_ERROR 27 #define B_WATCHPOINT_NOT_FOUND B_ERROR 28 // ToDo: Make those real error codes. 29 30 // maps breakpoint slot index to LEN_i LSB number 31 static const uint32 sDR7Len[4] = { 32 X86_DR7_LEN0_LSB, X86_DR7_LEN1_LSB, X86_DR7_LEN2_LSB, X86_DR7_LEN3_LSB 33 }; 34 35 // maps breakpoint slot index to R/W_i LSB number 36 static const uint32 sDR7RW[4] = { 37 X86_DR7_RW0_LSB, X86_DR7_RW1_LSB, X86_DR7_RW2_LSB, X86_DR7_RW3_LSB 38 }; 39 40 // maps breakpoint slot index to L_i bit number 41 static const uint32 sDR7L[4] = { 42 X86_DR7_L0, X86_DR7_L1, X86_DR7_L2, X86_DR7_L3 43 }; 44 45 // maps breakpoint slot index to B_i bit number 46 static const uint32 sDR6B[4] = { 47 X86_DR6_B0, X86_DR6_B1, X86_DR6_B2, X86_DR6_B3 48 }; 49 50 // Enables a hack to make single stepping work under qemu. Set via kernel 51 // driver settings. 52 static bool sQEmuSingleStepHack = false; 53 54 55 void 56 arch_clear_team_debug_info(struct arch_team_debug_info *info) 57 { 58 for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) 59 info->breakpoints[i].address = NULL; 60 61 info->dr7 = X86_BREAKPOINTS_DISABLED_DR7; 62 } 63 64 65 void 66 arch_destroy_team_debug_info(struct arch_team_debug_info *info) 67 { 68 arch_clear_team_debug_info(info); 69 } 70 71 72 void 73 arch_clear_thread_debug_info(struct arch_thread_debug_info *info) 74 { 75 info->flags = 0; 76 } 77 78 79 void 80 arch_destroy_thread_debug_info(struct arch_thread_debug_info *info) 81 { 82 arch_clear_thread_debug_info(info); 83 } 84 85 86 void 87 arch_set_debug_cpu_state(const struct debug_cpu_state *cpuState) 88 { 89 if (struct iframe *frame = i386_get_user_iframe()) { 90 struct thread *thread = thread_get_current_thread(); 91 92 i386_frstor(cpuState->extended_regs); 93 // For this to be correct the calling function must not use these 94 // registers (not even indirectly). 95 96 // frame->gs = cpuState->gs; 97 // frame->fs = cpuState->fs; 98 // frame->es = cpuState->es; 99 // frame->ds = cpuState->ds; 100 frame->edi = cpuState->edi; 101 frame->esi = cpuState->esi; 102 frame->ebp = cpuState->ebp; 103 frame->esp = cpuState->esp; 104 frame->ebx = cpuState->ebx; 105 frame->edx = cpuState->edx; 106 frame->ecx = cpuState->ecx; 107 frame->eax = cpuState->eax; 108 // frame->vector = cpuState->vector; 109 // frame->error_code = cpuState->error_code; 110 frame->eip = cpuState->eip; 111 // frame->cs = cpuState->cs; 112 frame->flags = (frame->flags & ~X86_EFLAGS_USER_SETTABLE_FLAGS) 113 | (cpuState->eflags & X86_EFLAGS_USER_SETTABLE_FLAGS); 114 frame->user_esp = cpuState->user_esp; 115 // frame->user_ss = cpuState->user_ss; 116 } 117 } 118 119 void 120 arch_get_debug_cpu_state(struct debug_cpu_state *cpuState) 121 { 122 if (struct iframe *frame = i386_get_user_iframe()) { 123 struct thread *thread = thread_get_current_thread(); 124 125 i386_fsave(cpuState->extended_regs); 126 // For this to be correct the calling function must not use these 127 // registers (not even indirectly). 128 129 cpuState->gs = frame->gs; 130 cpuState->fs = frame->fs; 131 cpuState->es = frame->es; 132 cpuState->ds = frame->ds; 133 cpuState->edi = frame->edi; 134 cpuState->esi = frame->esi; 135 cpuState->ebp = frame->ebp; 136 cpuState->esp = frame->esp; 137 cpuState->ebx = frame->ebx; 138 cpuState->edx = frame->orig_edx; 139 cpuState->ecx = frame->ecx; 140 cpuState->eax = frame->orig_eax; 141 cpuState->vector = frame->vector; 142 cpuState->error_code = frame->error_code; 143 cpuState->eip = frame->eip; 144 cpuState->cs = frame->cs; 145 cpuState->eflags = frame->flags; 146 cpuState->user_esp = frame->user_esp; 147 cpuState->user_ss = frame->user_ss; 148 } 149 } 150 151 static status_t 152 set_breakpoint(void *address, uint32 type, uint32 length) 153 { 154 if (!address) 155 return B_BAD_VALUE; 156 157 struct thread *thread = thread_get_current_thread(); 158 159 status_t error = B_OK; 160 161 cpu_status state = disable_interrupts(); 162 GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 163 164 arch_team_debug_info &info = thread->team->debug_info.arch_info; 165 166 // check, if there is already a breakpoint at that address 167 bool alreadySet = false; 168 for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) { 169 if (info.breakpoints[i].address == address 170 && info.breakpoints[i].type == type) { 171 alreadySet = true; 172 break; 173 } 174 } 175 176 if (!alreadySet) { 177 // find a free slot 178 int32 slot = -1; 179 for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) { 180 if (!info.breakpoints[i].address) { 181 slot = i; 182 break; 183 } 184 } 185 186 // init the breakpoint 187 if (slot >= 0) { 188 info.breakpoints[slot].address = address; 189 info.breakpoints[slot].type = type; 190 info.breakpoints[slot].length = length; 191 192 info.dr7 |= (length << sDR7Len[slot]) 193 | (type << sDR7RW[slot]) 194 | (1 << sDR7L[slot]); 195 } else { 196 if (type == X86_INSTRUCTION_BREAKPOINT) 197 error = B_NO_MORE_BREAKPOINTS; 198 else 199 error = B_NO_MORE_WATCHPOINTS; 200 } 201 } 202 203 RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 204 restore_interrupts(state); 205 206 return error; 207 } 208 209 210 static status_t 211 clear_breakpoint(void *address, bool watchpoint) 212 { 213 if (!address) 214 return B_BAD_VALUE; 215 216 struct thread *thread = thread_get_current_thread(); 217 218 status_t error = B_OK; 219 220 cpu_status state = disable_interrupts(); 221 GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 222 223 arch_team_debug_info &info = thread->team->debug_info.arch_info; 224 225 // find the breakpoint 226 int32 slot = -1; 227 for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) { 228 if (info.breakpoints[i].address == address 229 && (watchpoint 230 != (info.breakpoints[i].type == X86_INSTRUCTION_BREAKPOINT))) { 231 slot = i; 232 break; 233 } 234 } 235 236 // clear the breakpoint 237 if (slot >= 0) { 238 info.breakpoints[slot].address = NULL; 239 240 info.dr7 &= ~((0x3 << sDR7Len[slot]) 241 | (0x3 << sDR7RW[slot]) 242 | (1 << sDR7L[slot])); 243 } else { 244 if (watchpoint) 245 error = B_WATCHPOINT_NOT_FOUND; 246 else 247 error = B_BREAKPOINT_NOT_FOUND; 248 } 249 250 RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 251 restore_interrupts(state); 252 253 return error; 254 } 255 256 257 status_t 258 arch_set_breakpoint(void *address) 259 { 260 return set_breakpoint(address, X86_INSTRUCTION_BREAKPOINT, 261 X86_BREAKPOINT_LENGTH_1); 262 } 263 264 265 status_t 266 arch_clear_breakpoint(void *address) 267 { 268 return clear_breakpoint(address, false); 269 } 270 271 272 status_t 273 arch_set_watchpoint(void *address, uint32 type, int32 length) 274 { 275 // check type 276 uint32 archType; 277 switch (type) { 278 case B_DATA_WRITE_WATCHPOINT: 279 archType = X86_DATA_WRITE_BREAKPOINT; 280 break; 281 case B_DATA_READ_WRITE_WATCHPOINT: 282 archType = X86_DATA_READ_WRITE_BREAKPOINT; 283 break; 284 case B_DATA_READ_WATCHPOINT: 285 default: 286 return B_WATCHPOINT_TYPE_NOT_SUPPORTED; 287 break; 288 } 289 290 // check length and alignment 291 uint32 archLength; 292 switch (length) { 293 case 1: 294 archLength = X86_BREAKPOINT_LENGTH_1; 295 break; 296 case 2: 297 if ((uint32)address & 0x1) 298 return B_BAD_WATCHPOINT_ALIGNMENT; 299 archLength = X86_BREAKPOINT_LENGTH_2; 300 break; 301 case 4: 302 if ((uint32)address & 0x3) 303 return B_BAD_WATCHPOINT_ALIGNMENT; 304 archLength = X86_BREAKPOINT_LENGTH_4; 305 break; 306 default: 307 return B_WATCHPOINT_LENGTH_NOT_SUPPORTED; 308 } 309 310 return set_breakpoint(address, archType, archLength); 311 } 312 313 314 status_t 315 arch_clear_watchpoint(void *address) 316 { 317 return clear_breakpoint(address, false); 318 } 319 320 321 static inline void 322 install_breakpoints(const arch_team_debug_info &teamInfo) 323 { 324 // set breakpoints 325 asm("movl %0, %%dr0" : : "r"(teamInfo.breakpoints[0].address)); 326 asm("movl %0, %%dr1" : : "r"(teamInfo.breakpoints[1].address)); 327 asm("movl %0, %%dr2" : : "r"(teamInfo.breakpoints[2].address)); 328 // asm("movl %0, %%dr3" : : "r"(teamInfo.breakpoints[3].address)); 329 // DR3 is used to hold the current struct thread*. 330 331 // enable breakpoints 332 asm("movl %0, %%dr7" : : "r"(teamInfo.dr7)); 333 } 334 335 336 /** 337 * Interrupts are enabled. 338 */ 339 void 340 i386_init_user_debug_at_kernel_exit(struct iframe *frame) 341 { 342 struct thread *thread = thread_get_current_thread(); 343 344 cpu_status state = disable_interrupts(); 345 GRAB_THREAD_LOCK(); 346 GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 347 348 arch_team_debug_info &teamInfo = thread->team->debug_info.arch_info; 349 350 // install the breakpoints 351 install_breakpoints(teamInfo); 352 thread->debug_info.arch_info.flags |= X86_THREAD_DEBUG_DR7_SET; 353 354 // set/clear TF in EFLAGS depending on if single stepping is desired 355 if (thread->debug_info.flags & B_THREAD_DEBUG_SINGLE_STEP) 356 frame->flags |= (1 << X86_EFLAGS_TF); 357 else 358 frame->flags &= ~(1 << X86_EFLAGS_TF); 359 // ToDo: Move into a function called from thread_hit_debug_event(). 360 // No need to have that here in the code executed for ever kernel->user 361 // mode switch. 362 363 RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 364 RELEASE_THREAD_LOCK(); 365 restore_interrupts(state); 366 } 367 368 369 /** 370 * Interrupts may be enabled. 371 */ 372 void 373 i386_exit_user_debug_at_kernel_entry() 374 { 375 struct thread *thread = thread_get_current_thread(); 376 377 cpu_status state = disable_interrupts(); 378 GRAB_THREAD_LOCK(); 379 380 // disable breakpoints 381 asm("movl %0, %%dr7" : : "r"(X86_BREAKPOINTS_DISABLED_DR7)); 382 thread->debug_info.arch_info.flags &= ~X86_THREAD_DEBUG_DR7_SET; 383 384 RELEASE_THREAD_LOCK(); 385 restore_interrupts(state); 386 } 387 388 389 /** 390 * Interrupts are disabled and the thread lock is being held. 391 */ 392 void 393 i386_reinit_user_debug_after_context_switch(struct thread *thread) 394 { 395 if (thread->debug_info.arch_info.flags & X86_THREAD_DEBUG_DR7_SET) { 396 GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 397 398 install_breakpoints(thread->team->debug_info.arch_info); 399 400 RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info); 401 } 402 } 403 404 405 /** 406 * Interrupts are disabled and will be enabled by the function. 407 */ 408 int 409 i386_handle_debug_exception(struct iframe *frame) 410 { 411 // get debug status and control registers 412 uint32 dr6, dr7; 413 asm("movl %%dr6, %0" : "=r"(dr6)); 414 asm("movl %%dr7, %0" : "=r"(dr7)); 415 416 TRACE(("i386_handle_debug_exception(): DR6: %lx, DR7: %lx\n", dr6, dr7)); 417 418 // check, which exception condition applies 419 if (dr6 & X86_DR6_BREAKPOINT_MASK) { 420 // breakpoint 421 422 // check which breakpoint was taken 423 bool watchpoint = true; 424 for (int32 i = 0; i < X86_BREAKPOINT_COUNT; i++) { 425 if (dr6 & (1 << sDR6B[i])) { 426 // If it is an instruction breakpoint, we need to set RF in 427 // EFLAGS to prevent triggering the same exception 428 // again (breakpoint instructions are triggered *before* 429 // executing the instruction). 430 uint32 type = (dr7 >> sDR7RW[i]) & 0x3; 431 if (type == X86_INSTRUCTION_BREAKPOINT) { 432 frame->flags |= (1 << X86_EFLAGS_RF); 433 watchpoint = false; 434 } 435 } 436 } 437 438 // enable interrupts and notify the debugger 439 enable_interrupts(); 440 441 if (watchpoint) 442 user_debug_watchpoint_hit(); 443 else 444 user_debug_breakpoint_hit(false); 445 446 } else if (dr6 & (1 << X86_DR6_BD)) { 447 // general detect exception 448 // Occurs only, if GD in DR7 is set (which we don't do) and someone 449 // tries to write to the debug registers. 450 dprintf("i386_handle_debug_exception(): ignoring spurious general " 451 "detect exception\n"); 452 453 enable_interrupts(); 454 455 } else if ((dr6 & (1 << X86_DR6_BS)) || sQEmuSingleStepHack) { 456 // single step 457 458 // enable interrupts and notify the debugger 459 enable_interrupts(); 460 461 user_debug_single_stepped(); 462 463 } else if (dr6 & (1 << X86_DR6_BT)) { 464 // task switch 465 // Occurs only, if T in EFLAGS is set (which we don't do). 466 dprintf("i386_handle_debug_exception(): ignoring spurious task switch " 467 "exception\n"); 468 469 enable_interrupts(); 470 471 } else { 472 dprintf("i386_handle_debug_exception(): ignoring spurious debug " 473 "exception (no condition recognized)\n"); 474 475 enable_interrupts(); 476 } 477 478 return B_HANDLED_INTERRUPT; 479 } 480 481 482 /** 483 * Interrupts are disabled and will be enabled by the function. 484 */ 485 int 486 i386_handle_breakpoint_exception(struct iframe *frame) 487 { 488 TRACE(("i386_handle_breakpoint_exception()\n")); 489 490 enable_interrupts(); 491 492 user_debug_breakpoint_hit(true); 493 494 return B_HANDLED_INTERRUPT; 495 } 496 497 498 void 499 i386_init_user_debug() 500 { 501 // get debug settings 502 if (void *handle = load_driver_settings("kernel")) { 503 sQEmuSingleStepHack = get_driver_boolean_parameter(handle, 504 "qemu_single_step_hack", false, false);; 505 506 unload_driver_settings(handle); 507 } 508 } 509 510