1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * FILE: ntoskrnl/kdbg/kdb.c 5 * PURPOSE: Kernel Debugger 6 * 7 * PROGRAMMERS: Gregor Anich 8 */ 9 10 /* INCLUDES ******************************************************************/ 11 12 #include <ntoskrnl.h> 13 #define NDEBUG 14 #include <debug.h> 15 16 /* TYPES *********************************************************************/ 17 18 /* DEFINES *******************************************************************/ 19 20 #define KDB_STACK_SIZE (4096*3) 21 #define KDB_MAXIMUM_BREAKPOINT_COUNT 256 22 #define KDB_MAXIMUM_HW_BREAKPOINT_COUNT 4 23 #define KDB_MAXIMUM_SW_BREAKPOINT_COUNT 256 24 25 #define __STRING(x) #x 26 #define _STRING(x) __STRING(x) 27 28 /* GLOBALS *******************************************************************/ 29 30 static LONG KdbEntryCount = 0; 31 static CHAR KdbStack[KDB_STACK_SIZE]; 32 33 static ULONG KdbBreakPointCount = 0; /* Number of used breakpoints in the array */ 34 static KDB_BREAKPOINT KdbBreakPoints[KDB_MAXIMUM_BREAKPOINT_COUNT] = {{0}}; /* Breakpoint array */ 35 static ULONG KdbSwBreakPointCount = 0; /* Number of enabled software breakpoints */ 36 static ULONG KdbHwBreakPointCount = 0; /* Number of enabled hardware breakpoints */ 37 static PKDB_BREAKPOINT KdbSwBreakPoints[KDB_MAXIMUM_SW_BREAKPOINT_COUNT]; /* Enabled software breakpoints, orderless */ 38 static PKDB_BREAKPOINT KdbHwBreakPoints[KDB_MAXIMUM_HW_BREAKPOINT_COUNT]; /* Enabled hardware breakpoints, orderless */ 39 static PKDB_BREAKPOINT KdbBreakPointToReenable = NULL; /* Set to a breakpoint struct when single stepping after 40 a software breakpoint was hit, to reenable it */ 41 static BOOLEAN KdbpEvenThoughWeHaveABreakPointToReenableWeAlsoHaveARealSingleStep; 42 LONG KdbLastBreakPointNr = -1; /* Index of the breakpoint which cause KDB to be entered */ 43 ULONG KdbNumSingleSteps = 0; /* How many single steps to do */ 44 BOOLEAN KdbSingleStepOver = FALSE; /* Whether to step over calls/reps. */ 45 ULONG KdbDebugState = 0; /* KDBG Settings (NOECHO, KDSERIAL) */ 46 static BOOLEAN KdbEnteredOnSingleStep = FALSE; /* Set to true when KDB was entered because of single step */ 47 PEPROCESS KdbCurrentProcess = NULL; /* The current process context in which KDB runs */ 48 PEPROCESS KdbOriginalProcess = NULL; /* The process in whichs context KDB was intered */ 49 PETHREAD KdbCurrentThread = NULL; /* The current thread context in which KDB runs */ 50 PETHREAD KdbOriginalThread = NULL; /* The thread in whichs context KDB was entered */ 51 PKDB_KTRAP_FRAME KdbCurrentTrapFrame = NULL; /* Pointer to the current trapframe */ 52 static KDB_KTRAP_FRAME KdbTrapFrame = { 0 }; /* The trapframe which was passed to KdbEnterDebuggerException */ 53 static KDB_KTRAP_FRAME KdbThreadTrapFrame = { 0 }; /* The trapframe of the current thread (KdbCurrentThread) */ 54 static KAPC_STATE KdbApcState; 55 extern BOOLEAN KdbpBugCheckRequested; 56 57 /* Array of conditions when to enter KDB */ 58 static KDB_ENTER_CONDITION KdbEnterConditions[][2] = 59 { 60 /* First chance Last chance */ 61 { KdbDoNotEnter, KdbEnterFromKmode }, /* 0: Zero divide */ 62 { KdbEnterFromKmode, KdbDoNotEnter }, /* 1: Debug trap */ 63 { KdbDoNotEnter, KdbEnterAlways }, /* 2: NMI */ 64 { KdbEnterFromKmode, KdbDoNotEnter }, /* 3: INT3 */ 65 { KdbDoNotEnter, KdbEnterFromKmode }, /* 4: Overflow */ 66 { KdbDoNotEnter, KdbEnterFromKmode }, /* 5: BOUND range exceeded */ 67 { KdbDoNotEnter, KdbEnterFromKmode }, /* 6: Invalid opcode */ 68 { KdbDoNotEnter, KdbEnterFromKmode }, /* 7: No math coprocessor fault */ 69 { KdbEnterAlways, KdbEnterAlways }, /* 8: Double Fault */ 70 { KdbEnterAlways, KdbEnterAlways }, /* 9: Unknown(9) */ 71 { KdbDoNotEnter, KdbEnterFromKmode }, /* 10: Invalid TSS */ 72 { KdbDoNotEnter, KdbEnterFromKmode }, /* 11: Segment Not Present */ 73 { KdbDoNotEnter, KdbEnterFromKmode }, /* 12: Stack fault */ 74 { KdbDoNotEnter, KdbEnterFromKmode }, /* 13: General protection fault */ 75 { KdbDoNotEnter, KdbEnterFromKmode }, /* 14: Page fault */ 76 { KdbEnterAlways, KdbEnterAlways }, /* 15: Reserved (15) */ 77 { KdbDoNotEnter, KdbEnterFromKmode }, /* 16: FPU fault */ 78 { KdbDoNotEnter, KdbEnterFromKmode }, /* 17: Alignment Check */ 79 { KdbDoNotEnter, KdbEnterFromKmode }, /* 18: Machine Check */ 80 { KdbDoNotEnter, KdbEnterFromKmode }, /* 19: SIMD fault */ 81 { KdbEnterFromKmode, KdbDoNotEnter }, /* 20: Assertion failure */ 82 { KdbDoNotEnter, KdbEnterFromKmode } /* Last entry: used for unknown exceptions */ 83 }; 84 85 /* Exception descriptions */ 86 static const CHAR *ExceptionNrToString[] = 87 { 88 "Divide Error", 89 "Debug Trap", 90 "NMI", 91 "Breakpoint", 92 "Overflow", 93 "BOUND range exceeded", 94 "Invalid Opcode", 95 "No Math Coprocessor", 96 "Double Fault", 97 "Unknown(9)", 98 "Invalid TSS", 99 "Segment Not Present", 100 "Stack Segment Fault", 101 "General Protection", 102 "Page Fault", 103 "Reserved(15)", 104 "Math Fault", 105 "Alignment Check", 106 "Machine Check", 107 "SIMD Fault", 108 "Assertion Failure" 109 }; 110 111 /* FUNCTIONS *****************************************************************/ 112 113 static VOID 114 KdbpKdbTrapFrameFromKernelStack( 115 PVOID KernelStack, 116 PKDB_KTRAP_FRAME KdbTrapFrame) 117 { 118 ULONG_PTR *StackPtr; 119 120 RtlZeroMemory(KdbTrapFrame, sizeof(KDB_KTRAP_FRAME)); 121 StackPtr = (ULONG_PTR *) KernelStack; 122 #ifdef _M_IX86 123 KdbTrapFrame->Ebp = StackPtr[3]; 124 KdbTrapFrame->Edi = StackPtr[4]; 125 KdbTrapFrame->Esi = StackPtr[5]; 126 KdbTrapFrame->Ebx = StackPtr[6]; 127 KdbTrapFrame->Eip = StackPtr[7]; 128 KdbTrapFrame->Esp = (ULONG) (StackPtr + 8); 129 KdbTrapFrame->SegSs = KGDT_R0_DATA; 130 KdbTrapFrame->SegCs = KGDT_R0_CODE; 131 KdbTrapFrame->SegDs = KGDT_R0_DATA; 132 KdbTrapFrame->SegEs = KGDT_R0_DATA; 133 KdbTrapFrame->SegGs = KGDT_R0_DATA; 134 #endif 135 136 /* FIXME: what about the other registers??? */ 137 } 138 139 /*!\brief Overwrites the instruction at \a Address with \a NewInst and stores 140 * the old instruction in *OldInst. 141 * 142 * \param Process Process in which's context to overwrite the instruction. 143 * \param Address Address at which to overwrite the instruction. 144 * \param NewInst New instruction (written to \a Address) 145 * \param OldInst Old instruction (read from \a Address) 146 * 147 * \returns NTSTATUS 148 */ 149 static NTSTATUS 150 KdbpOverwriteInstruction( 151 IN PEPROCESS Process, 152 IN ULONG_PTR Address, 153 IN UCHAR NewInst, 154 OUT PUCHAR OldInst OPTIONAL) 155 { 156 NTSTATUS Status; 157 ULONG Protect; 158 PEPROCESS CurrentProcess = PsGetCurrentProcess(); 159 KAPC_STATE ApcState; 160 161 /* Get the protection for the address. */ 162 Protect = MmGetPageProtect(Process, (PVOID)PAGE_ROUND_DOWN(Address)); 163 164 /* Return if that page isn't present. */ 165 if (Protect & PAGE_NOACCESS) 166 { 167 return STATUS_MEMORY_NOT_ALLOCATED; 168 } 169 170 /* Attach to the process */ 171 if (CurrentProcess != Process) 172 { 173 KeStackAttachProcess(&Process->Pcb, &ApcState); 174 } 175 176 /* Make the page writeable if it is read only. */ 177 if (Protect & (PAGE_READONLY|PAGE_EXECUTE|PAGE_EXECUTE_READ)) 178 { 179 MmSetPageProtect(Process, (PVOID)PAGE_ROUND_DOWN(Address), 180 (Protect & ~(PAGE_READONLY|PAGE_EXECUTE|PAGE_EXECUTE_READ)) | PAGE_READWRITE); 181 } 182 183 /* Copy the old instruction back to the caller. */ 184 if (OldInst) 185 { 186 Status = KdbpSafeReadMemory(OldInst, (PUCHAR)Address, 1); 187 if (!NT_SUCCESS(Status)) 188 { 189 if (Protect & (PAGE_READONLY|PAGE_EXECUTE|PAGE_EXECUTE_READ)) 190 { 191 MmSetPageProtect(Process, (PVOID)PAGE_ROUND_DOWN(Address), Protect); 192 } 193 194 /* Detach from process */ 195 if (CurrentProcess != Process) 196 { 197 KeDetachProcess(); 198 } 199 200 return Status; 201 } 202 } 203 204 /* Copy the new instruction in its place. */ 205 Status = KdbpSafeWriteMemory((PUCHAR)Address, &NewInst, 1); 206 207 /* Restore the page protection. */ 208 if (Protect & (PAGE_READONLY|PAGE_EXECUTE|PAGE_EXECUTE_READ)) 209 { 210 MmSetPageProtect(Process, (PVOID)PAGE_ROUND_DOWN(Address), Protect); 211 } 212 213 /* Detach from process */ 214 if (CurrentProcess != Process) 215 { 216 KeUnstackDetachProcess(&ApcState); 217 } 218 219 return Status; 220 } 221 222 /*!\brief Checks whether the given instruction can be single stepped or has to be 223 * stepped over using a temporary breakpoint. 224 * 225 * \retval TRUE Instruction is a call. 226 * \retval FALSE Instruction is not a call. 227 */ 228 BOOLEAN 229 KdbpShouldStepOverInstruction( 230 ULONG_PTR Eip) 231 { 232 UCHAR Mem[3]; 233 ULONG i = 0; 234 235 if (!NT_SUCCESS(KdbpSafeReadMemory(Mem, (PVOID)Eip, sizeof (Mem)))) 236 { 237 KdbpPrint("Couldn't access memory at 0x%p\n", Eip); 238 return FALSE; 239 } 240 241 /* Check if the current instruction is a call. */ 242 while ((i < sizeof (Mem)) && (Mem[i] == 0x66 || Mem[i] == 0x67)) 243 i++; 244 245 if (i == sizeof (Mem)) 246 return FALSE; 247 248 if (Mem[i] == 0xE8 || Mem[i] == 0x9A || Mem[i] == 0xF2 || Mem[i] == 0xF3 || 249 (((i + 1) < sizeof (Mem)) && Mem[i] == 0xFF && (Mem[i+1] & 0x38) == 0x10)) 250 { 251 return TRUE; 252 } 253 254 return FALSE; 255 } 256 257 /*!\brief Steps over an instruction 258 * 259 * If the given instruction should be stepped over, this function inserts a 260 * temporary breakpoint after the instruction and returns TRUE, otherwise it 261 * returns FALSE. 262 * 263 * \retval TRUE Temporary breakpoint set after instruction. 264 * \retval FALSE No breakpoint was set. 265 */ 266 BOOLEAN 267 KdbpStepOverInstruction( 268 ULONG_PTR Eip) 269 { 270 LONG InstLen; 271 272 if (!KdbpShouldStepOverInstruction(Eip)) 273 return FALSE; 274 275 InstLen = KdbpGetInstLength(Eip); 276 if (InstLen < 1) 277 return FALSE; 278 279 if (!NT_SUCCESS(KdbpInsertBreakPoint(Eip + InstLen, KdbBreakPointTemporary, 0, 0, NULL, FALSE, NULL))) 280 return FALSE; 281 282 return TRUE; 283 } 284 285 /*!\brief Steps into an instruction (interrupts) 286 * 287 * If the given instruction should be stepped into, this function inserts a 288 * temporary breakpoint at the target instruction and returns TRUE, otherwise it 289 * returns FALSE. 290 * 291 * \retval TRUE Temporary breakpoint set at target instruction. 292 * \retval FALSE No breakpoint was set. 293 */ 294 BOOLEAN 295 KdbpStepIntoInstruction( 296 ULONG_PTR Eip) 297 { 298 KDESCRIPTOR Idtr = {0}; 299 UCHAR Mem[2]; 300 INT IntVect; 301 ULONG IntDesc[2]; 302 ULONG_PTR TargetEip; 303 304 /* Read memory */ 305 if (!NT_SUCCESS(KdbpSafeReadMemory(Mem, (PVOID)Eip, sizeof (Mem)))) 306 { 307 /*KdbpPrint("Couldn't access memory at 0x%p\n", Eip);*/ 308 return FALSE; 309 } 310 311 /* Check for INT instruction */ 312 /* FIXME: Check for iret */ 313 if (Mem[0] == 0xcc) 314 IntVect = 3; 315 else if (Mem[0] == 0xcd) 316 IntVect = Mem[1]; 317 else if (Mem[0] == 0xce && KdbCurrentTrapFrame->EFlags & (1<<11)) /* 1 << 11 is the overflow flag */ 318 IntVect = 4; 319 else 320 return FALSE; 321 322 if (IntVect < 32) /* We should be informed about interrupts < 32 by the kernel, no need to breakpoint them */ 323 { 324 return FALSE; 325 } 326 327 /* Read the interrupt descriptor table register */ 328 __sidt(&Idtr.Limit); 329 if (IntVect >= (Idtr.Limit + 1) / 8) 330 { 331 /*KdbpPrint("IDT does not contain interrupt vector %d.\n", IntVect);*/ 332 return TRUE; 333 } 334 335 /* Get the interrupt descriptor */ 336 if (!NT_SUCCESS(KdbpSafeReadMemory(IntDesc, (PVOID)(ULONG_PTR)(Idtr.Base + (IntVect * 8)), sizeof (IntDesc)))) 337 { 338 /*KdbpPrint("Couldn't access memory at 0x%p\n", (ULONG_PTR)Idtr.Base + (IntVect * 8));*/ 339 return FALSE; 340 } 341 342 /* Check descriptor and get target eip (16 bit interrupt/trap gates not supported) */ 343 if ((IntDesc[1] & (1 << 15)) == 0) /* not present */ 344 { 345 return FALSE; 346 } 347 if ((IntDesc[1] & 0x1f00) == 0x0500) /* Task gate */ 348 { 349 /* FIXME: Task gates not supported */ 350 return FALSE; 351 } 352 else if (((IntDesc[1] & 0x1fe0) == 0x0e00) || /* 32 bit Interrupt gate */ 353 ((IntDesc[1] & 0x1fe0) == 0x0f00)) /* 32 bit Trap gate */ 354 { 355 /* FIXME: Should the segment selector of the interrupt gate be checked? */ 356 TargetEip = (IntDesc[1] & 0xffff0000) | (IntDesc[0] & 0x0000ffff); 357 } 358 else 359 { 360 return FALSE; 361 } 362 363 /* Insert breakpoint */ 364 if (!NT_SUCCESS(KdbpInsertBreakPoint(TargetEip, KdbBreakPointTemporary, 0, 0, NULL, FALSE, NULL))) 365 return FALSE; 366 367 return TRUE; 368 } 369 370 /*!\brief Gets the number of the next breakpoint >= Start. 371 * 372 * \param Start Breakpoint number to start searching at. -1 if no more breakpoints are found. 373 * 374 * \returns Breakpoint number (-1 if no more breakpoints are found) 375 */ 376 LONG 377 KdbpGetNextBreakPointNr( 378 IN ULONG Start OPTIONAL) 379 { 380 for (; Start < RTL_NUMBER_OF(KdbBreakPoints); Start++) 381 { 382 if (KdbBreakPoints[Start].Type != KdbBreakPointNone) 383 return Start; 384 } 385 386 return -1; 387 } 388 389 /*!\brief Returns information of the specified breakpoint. 390 * 391 * \param BreakPointNr Number of the breakpoint to return information of. 392 * \param Address Receives the address of the breakpoint. 393 * \param Type Receives the type of the breakpoint (hardware or software) 394 * \param Size Size - for memory breakpoints. 395 * \param AccessType Access type - for hardware breakpoints. 396 * \param DebugReg Debug register - for enabled hardware breakpoints. 397 * \param Enabled Whether the breakpoint is enabled or not. 398 * \param Process The owning process of the breakpoint. 399 * \param ConditionExpression The expression which was given as condition for the bp. 400 * 401 * \returns NULL on failure, pointer to a KDB_BREAKPOINT struct on success. 402 */ 403 BOOLEAN 404 KdbpGetBreakPointInfo( 405 IN ULONG BreakPointNr, 406 OUT ULONG_PTR *Address OPTIONAL, 407 OUT KDB_BREAKPOINT_TYPE *Type OPTIONAL, 408 OUT UCHAR *Size OPTIONAL, 409 OUT KDB_ACCESS_TYPE *AccessType OPTIONAL, 410 OUT UCHAR *DebugReg OPTIONAL, 411 OUT BOOLEAN *Enabled OPTIONAL, 412 OUT BOOLEAN *Global OPTIONAL, 413 OUT PEPROCESS *Process OPTIONAL, 414 OUT PCHAR *ConditionExpression OPTIONAL) 415 { 416 PKDB_BREAKPOINT bp; 417 418 if (BreakPointNr >= RTL_NUMBER_OF(KdbBreakPoints) || 419 KdbBreakPoints[BreakPointNr].Type == KdbBreakPointNone) 420 { 421 return FALSE; 422 } 423 424 bp = KdbBreakPoints + BreakPointNr; 425 if (Address) 426 *Address = bp->Address; 427 428 if (Type) 429 *Type = bp->Type; 430 431 if (bp->Type == KdbBreakPointHardware) 432 { 433 if (Size) 434 *Size = bp->Data.Hw.Size; 435 436 if (AccessType) 437 *AccessType = bp->Data.Hw.AccessType; 438 439 if (DebugReg && bp->Enabled) 440 *DebugReg = bp->Data.Hw.DebugReg; 441 } 442 443 if (Enabled) 444 *Enabled = bp->Enabled; 445 446 if (Global) 447 *Global = bp->Global; 448 449 if (Process) 450 *Process = bp->Process; 451 452 if (ConditionExpression) 453 *ConditionExpression = bp->ConditionExpression; 454 455 return TRUE; 456 } 457 458 /*!\brief Inserts a breakpoint into the breakpoint array. 459 * 460 * The \a Process of the breakpoint is set to \a KdbCurrentProcess 461 * 462 * \param Address Address at which to set the breakpoint. 463 * \param Type Type of breakpoint (hardware or software) 464 * \param Size Size of breakpoint (for hardware/memory breakpoints) 465 * \param AccessType Access type (for hardware breakpoins) 466 * \param ConditionExpression Expression which must evaluate to true for conditional breakpoints. 467 * \param Global Wether the breakpoint is global or local to a process. 468 * \param BreakPointNumber Receives the breakpoint number on success 469 * 470 * \returns NTSTATUS 471 */ 472 NTSTATUS 473 KdbpInsertBreakPoint( 474 IN ULONG_PTR Address, 475 IN KDB_BREAKPOINT_TYPE Type, 476 IN UCHAR Size OPTIONAL, 477 IN KDB_ACCESS_TYPE AccessType OPTIONAL, 478 IN PCHAR ConditionExpression OPTIONAL, 479 IN BOOLEAN Global, 480 OUT PLONG BreakPointNr OPTIONAL) 481 { 482 LONG i; 483 PVOID Condition; 484 PCHAR ConditionExpressionDup; 485 LONG ErrOffset; 486 CHAR ErrMsg[128]; 487 488 ASSERT(Type != KdbBreakPointNone); 489 490 if (Type == KdbBreakPointHardware) 491 { 492 if ((Address % Size) != 0) 493 { 494 KdbpPrint("Address (0x%p) must be aligned to a multiple of the size (%d)\n", Address, Size); 495 return STATUS_UNSUCCESSFUL; 496 } 497 498 if (AccessType == KdbAccessExec && Size != 1) 499 { 500 KdbpPrint("Size must be 1 for execution breakpoints.\n"); 501 return STATUS_UNSUCCESSFUL; 502 } 503 } 504 505 if (KdbBreakPointCount == KDB_MAXIMUM_BREAKPOINT_COUNT) 506 { 507 return STATUS_UNSUCCESSFUL; 508 } 509 510 /* Parse conditon expression string and duplicate it */ 511 if (ConditionExpression) 512 { 513 Condition = KdbpRpnParseExpression(ConditionExpression, &ErrOffset, ErrMsg); 514 if (!Condition) 515 { 516 if (ErrOffset >= 0) 517 KdbpPrint("Couldn't parse expression: %s at character %d\n", ErrMsg, ErrOffset); 518 else 519 KdbpPrint("Couldn't parse expression: %s", ErrMsg); 520 521 return STATUS_UNSUCCESSFUL; 522 } 523 524 i = strlen(ConditionExpression) + 1; 525 ConditionExpressionDup = ExAllocatePoolWithTag(NonPagedPool, i, TAG_KDBG); 526 RtlCopyMemory(ConditionExpressionDup, ConditionExpression, i); 527 } 528 else 529 { 530 Condition = NULL; 531 ConditionExpressionDup = NULL; 532 } 533 534 /* Find unused breakpoint */ 535 if (Type == KdbBreakPointTemporary) 536 { 537 for (i = RTL_NUMBER_OF(KdbBreakPoints) - 1; i >= 0; i--) 538 { 539 if (KdbBreakPoints[i].Type == KdbBreakPointNone) 540 break; 541 } 542 } 543 else 544 { 545 for (i = 0; i < (LONG)RTL_NUMBER_OF(KdbBreakPoints); i++) 546 { 547 if (KdbBreakPoints[i].Type == KdbBreakPointNone) 548 break; 549 } 550 } 551 552 ASSERT(i < (LONG)RTL_NUMBER_OF(KdbBreakPoints)); 553 554 /* Set the breakpoint */ 555 ASSERT(KdbCurrentProcess); 556 KdbBreakPoints[i].Type = Type; 557 KdbBreakPoints[i].Address = Address; 558 KdbBreakPoints[i].Enabled = FALSE; 559 KdbBreakPoints[i].Global = Global; 560 KdbBreakPoints[i].Process = KdbCurrentProcess; 561 KdbBreakPoints[i].ConditionExpression = ConditionExpressionDup; 562 KdbBreakPoints[i].Condition = Condition; 563 564 if (Type == KdbBreakPointHardware) 565 { 566 KdbBreakPoints[i].Data.Hw.Size = Size; 567 KdbBreakPoints[i].Data.Hw.AccessType = AccessType; 568 } 569 570 KdbBreakPointCount++; 571 572 if (Type != KdbBreakPointTemporary) 573 KdbpPrint("Breakpoint %d inserted.\n", i); 574 575 /* Try to enable the breakpoint */ 576 KdbpEnableBreakPoint(i, NULL); 577 578 /* Return the breakpoint number */ 579 if (BreakPointNr) 580 *BreakPointNr = i; 581 582 return STATUS_SUCCESS; 583 } 584 585 /*!\brief Deletes a breakpoint 586 * 587 * \param BreakPointNr Number of the breakpoint to delete. Can be -1 588 * \param BreakPoint Breakpoint to delete. Can be NULL. 589 * 590 * \retval TRUE Success. 591 * \retval FALSE Failure (invalid breakpoint number) 592 */ 593 BOOLEAN 594 KdbpDeleteBreakPoint( 595 IN LONG BreakPointNr OPTIONAL, 596 IN OUT PKDB_BREAKPOINT BreakPoint OPTIONAL) 597 { 598 if (BreakPointNr < 0) 599 { 600 ASSERT(BreakPoint); 601 BreakPointNr = BreakPoint - KdbBreakPoints; 602 } 603 604 if (BreakPointNr < 0 || BreakPointNr >= KDB_MAXIMUM_BREAKPOINT_COUNT) 605 { 606 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr); 607 return FALSE; 608 } 609 610 if (!BreakPoint) 611 { 612 BreakPoint = KdbBreakPoints + BreakPointNr; 613 } 614 615 if (BreakPoint->Type == KdbBreakPointNone) 616 { 617 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr); 618 return FALSE; 619 } 620 621 if (BreakPoint->Enabled && !KdbpDisableBreakPoint(-1, BreakPoint)) 622 return FALSE; 623 624 if (BreakPoint->Type != KdbBreakPointTemporary) 625 KdbpPrint("Breakpoint %d deleted.\n", BreakPointNr); 626 627 BreakPoint->Type = KdbBreakPointNone; 628 KdbBreakPointCount--; 629 630 return TRUE; 631 } 632 633 /*!\brief Checks if the breakpoint was set by the debugger 634 * 635 * Tries to find a breakpoint in the breakpoint array which caused 636 * the debug exception to happen. 637 * 638 * \param ExpNr Exception Number (1 or 3) 639 * \param TrapFrame Exception trapframe 640 * 641 * \returns Breakpoint number, -1 on error. 642 */ 643 static LONG 644 KdbpIsBreakPointOurs( 645 IN NTSTATUS ExceptionCode, 646 IN PCONTEXT Context) 647 { 648 ULONG i; 649 ASSERT(ExceptionCode == STATUS_SINGLE_STEP || ExceptionCode == STATUS_BREAKPOINT); 650 651 if (ExceptionCode == STATUS_BREAKPOINT) /* Software interrupt */ 652 { 653 ULONG_PTR BpEip = (ULONG_PTR)Context->Eip - 1; /* Get EIP of INT3 instruction */ 654 for (i = 0; i < KdbSwBreakPointCount; i++) 655 { 656 ASSERT((KdbSwBreakPoints[i]->Type == KdbBreakPointSoftware || 657 KdbSwBreakPoints[i]->Type == KdbBreakPointTemporary)); 658 ASSERT(KdbSwBreakPoints[i]->Enabled); 659 660 if (KdbSwBreakPoints[i]->Address == BpEip) 661 { 662 return KdbSwBreakPoints[i] - KdbBreakPoints; 663 } 664 } 665 } 666 else if (ExceptionCode == STATUS_SINGLE_STEP) /* Hardware interrupt */ 667 { 668 UCHAR DebugReg; 669 670 for (i = 0; i < KdbHwBreakPointCount; i++) 671 { 672 ASSERT(KdbHwBreakPoints[i]->Type == KdbBreakPointHardware && 673 KdbHwBreakPoints[i]->Enabled); 674 DebugReg = KdbHwBreakPoints[i]->Data.Hw.DebugReg; 675 676 if ((Context->Dr6 & (1 << DebugReg)) != 0) 677 { 678 return KdbHwBreakPoints[i] - KdbBreakPoints; 679 } 680 } 681 } 682 683 return -1; 684 } 685 686 /*!\brief Enables a breakpoint. 687 * 688 * \param BreakPointNr Number of the breakpoint to enable Can be -1. 689 * \param BreakPoint Breakpoint to enable. Can be NULL. 690 * 691 * \retval TRUE Success. 692 * \retval FALSE Failure. 693 * 694 * \sa KdbpDisableBreakPoint 695 */ 696 BOOLEAN 697 KdbpEnableBreakPoint( 698 IN LONG BreakPointNr OPTIONAL, 699 IN OUT PKDB_BREAKPOINT BreakPoint OPTIONAL) 700 { 701 NTSTATUS Status; 702 INT i; 703 ULONG ul; 704 705 if (BreakPointNr < 0) 706 { 707 ASSERT(BreakPoint); 708 BreakPointNr = BreakPoint - KdbBreakPoints; 709 } 710 711 if (BreakPointNr < 0 || BreakPointNr >= KDB_MAXIMUM_BREAKPOINT_COUNT) 712 { 713 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr); 714 return FALSE; 715 } 716 717 if (!BreakPoint) 718 { 719 BreakPoint = KdbBreakPoints + BreakPointNr; 720 } 721 722 if (BreakPoint->Type == KdbBreakPointNone) 723 { 724 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr); 725 return FALSE; 726 } 727 728 if (BreakPoint->Enabled) 729 { 730 KdbpPrint("Breakpoint %d is already enabled.\n", BreakPointNr); 731 return TRUE; 732 } 733 734 if (BreakPoint->Type == KdbBreakPointSoftware || 735 BreakPoint->Type == KdbBreakPointTemporary) 736 { 737 if (KdbSwBreakPointCount >= KDB_MAXIMUM_SW_BREAKPOINT_COUNT) 738 { 739 KdbpPrint("Maximum number of SW breakpoints (%d) used. " 740 "Disable another breakpoint in order to enable this one.\n", 741 KDB_MAXIMUM_SW_BREAKPOINT_COUNT); 742 return FALSE; 743 } 744 745 Status = KdbpOverwriteInstruction(BreakPoint->Process, BreakPoint->Address, 746 0xCC, &BreakPoint->Data.SavedInstruction); 747 if (!NT_SUCCESS(Status)) 748 { 749 KdbpPrint("Couldn't access memory at 0x%p\n", BreakPoint->Address); 750 return FALSE; 751 } 752 753 KdbSwBreakPoints[KdbSwBreakPointCount++] = BreakPoint; 754 } 755 else 756 { 757 if (BreakPoint->Data.Hw.AccessType == KdbAccessExec) 758 ASSERT(BreakPoint->Data.Hw.Size == 1); 759 760 ASSERT((BreakPoint->Address % BreakPoint->Data.Hw.Size) == 0); 761 762 if (KdbHwBreakPointCount >= KDB_MAXIMUM_HW_BREAKPOINT_COUNT) 763 { 764 KdbpPrint("Maximum number of HW breakpoints (%d) already used. " 765 "Disable another breakpoint in order to enable this one.\n", 766 KDB_MAXIMUM_HW_BREAKPOINT_COUNT); 767 768 return FALSE; 769 } 770 771 /* Find unused hw breakpoint */ 772 ASSERT(KDB_MAXIMUM_HW_BREAKPOINT_COUNT == 4); 773 for (i = 0; i < KDB_MAXIMUM_HW_BREAKPOINT_COUNT; i++) 774 { 775 if ((KdbTrapFrame.Dr7 & (0x3 << (i * 2))) == 0) 776 break; 777 } 778 779 ASSERT(i < KDB_MAXIMUM_HW_BREAKPOINT_COUNT); 780 781 /* Set the breakpoint address. */ 782 switch (i) 783 { 784 case 0: 785 KdbTrapFrame.Dr0 = BreakPoint->Address; 786 break; 787 case 1: 788 KdbTrapFrame.Dr1 = BreakPoint->Address; 789 break; 790 case 2: 791 KdbTrapFrame.Dr2 = BreakPoint->Address; 792 break; 793 case 3: 794 KdbTrapFrame.Dr3 = BreakPoint->Address; 795 break; 796 } 797 798 /* Enable the global breakpoint */ 799 KdbTrapFrame.Dr7 |= (0x2 << (i * 2)); 800 801 /* Enable the exact match bits. */ 802 KdbTrapFrame.Dr7 |= 0x00000300; 803 804 /* Clear existing state. */ 805 KdbTrapFrame.Dr7 &= ~(0xF << (16 + (i * 4))); 806 807 /* Set the breakpoint type. */ 808 switch (BreakPoint->Data.Hw.AccessType) 809 { 810 case KdbAccessExec: 811 ul = 0; 812 break; 813 case KdbAccessWrite: 814 ul = 1; 815 break; 816 case KdbAccessRead: 817 case KdbAccessReadWrite: 818 ul = 3; 819 break; 820 default: 821 ASSERT(0); 822 return TRUE; 823 break; 824 } 825 826 KdbTrapFrame.Dr7 |= (ul << (16 + (i * 4))); 827 828 /* Set the breakpoint length. */ 829 KdbTrapFrame.Dr7 |= ((BreakPoint->Data.Hw.Size - 1) << (18 + (i * 4))); 830 831 /* Update KdbCurrentTrapFrame - values are taken from there by the CLI */ 832 if (&KdbTrapFrame != KdbCurrentTrapFrame) 833 { 834 KdbCurrentTrapFrame->Dr0 = KdbTrapFrame.Dr0; 835 KdbCurrentTrapFrame->Dr1 = KdbTrapFrame.Dr1; 836 KdbCurrentTrapFrame->Dr2 = KdbTrapFrame.Dr2; 837 KdbCurrentTrapFrame->Dr3 = KdbTrapFrame.Dr3; 838 KdbCurrentTrapFrame->Dr6 = KdbTrapFrame.Dr6; 839 KdbCurrentTrapFrame->Dr7 = KdbTrapFrame.Dr7; 840 } 841 842 BreakPoint->Data.Hw.DebugReg = i; 843 KdbHwBreakPoints[KdbHwBreakPointCount++] = BreakPoint; 844 } 845 846 BreakPoint->Enabled = TRUE; 847 if (BreakPoint->Type != KdbBreakPointTemporary) 848 KdbpPrint("Breakpoint %d enabled.\n", BreakPointNr); 849 850 return TRUE; 851 } 852 853 /*!\brief Disables a breakpoint. 854 * 855 * \param BreakPointNr Number of the breakpoint to disable. Can be -1 856 * \param BreakPoint Breakpoint to disable. Can be NULL. 857 * 858 * \retval TRUE Success. 859 * \retval FALSE Failure. 860 * 861 * \sa KdbpEnableBreakPoint 862 */ 863 BOOLEAN 864 KdbpDisableBreakPoint( 865 IN LONG BreakPointNr OPTIONAL, 866 IN OUT PKDB_BREAKPOINT BreakPoint OPTIONAL) 867 { 868 ULONG i; 869 NTSTATUS Status; 870 871 if (BreakPointNr < 0) 872 { 873 ASSERT(BreakPoint); 874 BreakPointNr = BreakPoint - KdbBreakPoints; 875 } 876 877 if (BreakPointNr < 0 || BreakPointNr >= KDB_MAXIMUM_BREAKPOINT_COUNT) 878 { 879 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr); 880 return FALSE; 881 } 882 883 if (!BreakPoint) 884 { 885 BreakPoint = KdbBreakPoints + BreakPointNr; 886 } 887 888 if (BreakPoint->Type == KdbBreakPointNone) 889 { 890 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr); 891 return FALSE; 892 } 893 894 if (BreakPoint->Enabled == FALSE) 895 { 896 KdbpPrint("Breakpoint %d is not enabled.\n", BreakPointNr); 897 return TRUE; 898 } 899 900 if (BreakPoint->Type == KdbBreakPointSoftware || 901 BreakPoint->Type == KdbBreakPointTemporary) 902 { 903 ASSERT(KdbSwBreakPointCount > 0); 904 Status = KdbpOverwriteInstruction(BreakPoint->Process, BreakPoint->Address, 905 BreakPoint->Data.SavedInstruction, NULL); 906 907 if (!NT_SUCCESS(Status)) 908 { 909 KdbpPrint("Couldn't restore original instruction.\n"); 910 return FALSE; 911 } 912 913 for (i = 0; i < KdbSwBreakPointCount; i++) 914 { 915 if (KdbSwBreakPoints[i] == BreakPoint) 916 { 917 KdbSwBreakPoints[i] = KdbSwBreakPoints[--KdbSwBreakPointCount]; 918 i = -1; /* if the last breakpoint is disabled dont break with i >= KdbSwBreakPointCount */ 919 break; 920 } 921 } 922 923 if (i != MAXULONG) /* not found */ 924 ASSERT(0); 925 } 926 else 927 { 928 ASSERT(BreakPoint->Type == KdbBreakPointHardware); 929 930 /* Clear the breakpoint. */ 931 KdbTrapFrame.Dr7 &= ~(0x3 << (BreakPoint->Data.Hw.DebugReg * 2)); 932 if ((KdbTrapFrame.Dr7 & 0xFF) == 0) 933 { 934 /* If no breakpoints are enabled then clear the exact match flags. */ 935 KdbTrapFrame.Dr7 &= 0xFFFFFCFF; 936 } 937 938 for (i = 0; i < KdbHwBreakPointCount; i++) 939 { 940 if (KdbHwBreakPoints[i] == BreakPoint) 941 { 942 KdbHwBreakPoints[i] = KdbHwBreakPoints[--KdbHwBreakPointCount]; 943 i = -1; /* if the last breakpoint is disabled dont break with i >= KdbHwBreakPointCount */ 944 break; 945 } 946 } 947 948 if (i != MAXULONG) /* not found */ 949 ASSERT(0); 950 } 951 952 BreakPoint->Enabled = FALSE; 953 if (BreakPoint->Type != KdbBreakPointTemporary) 954 KdbpPrint("Breakpoint %d disabled.\n", BreakPointNr); 955 956 return TRUE; 957 } 958 959 /*!\brief Gets the first or last chance enter-condition for exception nr. \a ExceptionNr 960 * 961 * \param ExceptionNr Number of the exception to get condition of. 962 * \param FirstChance Whether to get first or last chance condition. 963 * \param Condition Receives the condition setting. 964 * 965 * \retval TRUE Success. 966 * \retval FALSE Failure (invalid exception nr) 967 */ 968 BOOLEAN 969 KdbpGetEnterCondition( 970 IN LONG ExceptionNr, 971 IN BOOLEAN FirstChance, 972 OUT KDB_ENTER_CONDITION *Condition) 973 { 974 if (ExceptionNr >= (LONG)RTL_NUMBER_OF(KdbEnterConditions)) 975 return FALSE; 976 977 *Condition = KdbEnterConditions[ExceptionNr][FirstChance ? 0 : 1]; 978 return TRUE; 979 } 980 981 /*!\brief Sets the first or last chance enter-condition for exception nr. \a ExceptionNr 982 * 983 * \param ExceptionNr Number of the exception to set condition of (-1 for all) 984 * \param FirstChance Whether to set first or last chance condition. 985 * \param Condition The new condition setting. 986 * 987 * \retval TRUE Success. 988 * \retval FALSE Failure (invalid exception nr) 989 */ 990 BOOLEAN 991 KdbpSetEnterCondition( 992 IN LONG ExceptionNr, 993 IN BOOLEAN FirstChance, 994 IN KDB_ENTER_CONDITION Condition) 995 { 996 if (ExceptionNr < 0) 997 { 998 for (ExceptionNr = 0; ExceptionNr < (LONG)RTL_NUMBER_OF(KdbEnterConditions); ExceptionNr++) 999 { 1000 if (ExceptionNr == 1 || ExceptionNr == 8 || 1001 ExceptionNr == 9 || ExceptionNr == 15) /* Reserved exceptions */ 1002 { 1003 continue; 1004 } 1005 1006 KdbEnterConditions[ExceptionNr][FirstChance ? 0 : 1] = Condition; 1007 } 1008 } 1009 else 1010 { 1011 if (ExceptionNr >= (LONG)RTL_NUMBER_OF(KdbEnterConditions) || 1012 ExceptionNr == 1 || ExceptionNr == 8 || /* Do not allow changing of the debug */ 1013 ExceptionNr == 9 || ExceptionNr == 15) /* trap or reserved exceptions */ 1014 { 1015 return FALSE; 1016 } 1017 1018 KdbEnterConditions[ExceptionNr][FirstChance ? 0 : 1] = Condition; 1019 } 1020 1021 return TRUE; 1022 } 1023 1024 /*!\brief Switches to another thread context 1025 * 1026 * \param ThreadId Id of the thread to switch to. 1027 * 1028 * \retval TRUE Success. 1029 * \retval FALSE Failure (i.e. invalid thread id) 1030 */ 1031 BOOLEAN 1032 KdbpAttachToThread( 1033 PVOID ThreadId) 1034 { 1035 PETHREAD Thread = NULL; 1036 PEPROCESS Process; 1037 1038 /* Get a pointer to the thread */ 1039 if (!NT_SUCCESS(PsLookupThreadByThreadId(ThreadId, &Thread))) 1040 { 1041 KdbpPrint("Invalid thread id: 0x%08x\n", (ULONG_PTR)ThreadId); 1042 return FALSE; 1043 } 1044 Process = Thread->ThreadsProcess; 1045 1046 if (KeIsExecutingDpc() && Process != KdbCurrentProcess) 1047 { 1048 KdbpPrint("Cannot attach to thread within another process while executing a DPC.\n"); 1049 ObDereferenceObject(Thread); 1050 return FALSE; 1051 } 1052 1053 /* Save the current thread's context (if we previously attached to a thread) */ 1054 if (KdbCurrentThread != KdbOriginalThread) 1055 { 1056 ASSERT(KdbCurrentTrapFrame == &KdbThreadTrapFrame); 1057 /* Actually, we can't save the context, there's no guarantee that there was a trap frame */ 1058 } 1059 else 1060 { 1061 ASSERT(KdbCurrentTrapFrame == &KdbTrapFrame); 1062 } 1063 1064 /* Switch to the thread's context */ 1065 if (Thread != KdbOriginalThread) 1066 { 1067 /* The thread we're attaching to isn't the thread on which we entered 1068 * kdb and so the thread we're attaching to is not running. There 1069 * is no guarantee that it actually has a trap frame. So we have to 1070 * peek directly at the registers which were saved on the stack when the 1071 * thread was preempted in the scheduler */ 1072 KdbpKdbTrapFrameFromKernelStack(Thread->Tcb.KernelStack, 1073 &KdbThreadTrapFrame); 1074 KdbCurrentTrapFrame = &KdbThreadTrapFrame; 1075 } 1076 else /* Switching back to original thread */ 1077 { 1078 KdbCurrentTrapFrame = &KdbTrapFrame; 1079 } 1080 KdbCurrentThread = Thread; 1081 1082 /* Attach to the thread's process */ 1083 ASSERT(KdbCurrentProcess == PsGetCurrentProcess()); 1084 if (KdbCurrentProcess != Process) 1085 { 1086 if (KdbCurrentProcess != KdbOriginalProcess) /* detach from previously attached process */ 1087 { 1088 KeUnstackDetachProcess(&KdbApcState); 1089 } 1090 1091 if (KdbOriginalProcess != Process) 1092 { 1093 KeStackAttachProcess(&Process->Pcb, &KdbApcState); 1094 } 1095 1096 KdbCurrentProcess = Process; 1097 } 1098 1099 ObDereferenceObject(Thread); 1100 return TRUE; 1101 } 1102 1103 /*!\brief Switches to another process/thread context 1104 * 1105 * This function switches to the first thread in the specified process. 1106 * 1107 * \param ProcessId Id of the process to switch to. 1108 * 1109 * \retval TRUE Success. 1110 * \retval FALSE Failure (i.e. invalid process id) 1111 */ 1112 BOOLEAN 1113 KdbpAttachToProcess( 1114 PVOID ProcessId) 1115 { 1116 PEPROCESS Process = NULL; 1117 PETHREAD Thread; 1118 PLIST_ENTRY Entry; 1119 1120 /* Get a pointer to the process */ 1121 if (!NT_SUCCESS(PsLookupProcessByProcessId(ProcessId, &Process))) 1122 { 1123 KdbpPrint("Invalid process id: 0x%08x\n", (ULONG_PTR)ProcessId); 1124 return FALSE; 1125 } 1126 1127 Entry = Process->ThreadListHead.Flink; 1128 ObDereferenceObject(Process); 1129 if (Entry == &KdbCurrentProcess->ThreadListHead) 1130 { 1131 KdbpPrint("No threads in process 0x%p, cannot attach to process!\n", ProcessId); 1132 return FALSE; 1133 } 1134 1135 Thread = CONTAINING_RECORD(Entry, ETHREAD, ThreadListEntry); 1136 1137 return KdbpAttachToThread(Thread->Cid.UniqueThread); 1138 } 1139 1140 /*!\brief Calls the main loop ... 1141 */ 1142 static VOID 1143 KdbpCallMainLoop(VOID) 1144 { 1145 KdbpCliMainLoop(KdbEnteredOnSingleStep); 1146 } 1147 1148 /*!\brief Internal function to enter KDB. 1149 * 1150 * Disables interrupts, releases display ownership, ... 1151 */ 1152 static VOID 1153 KdbpInternalEnter(VOID) 1154 { 1155 PETHREAD Thread; 1156 PVOID SavedInitialStack, SavedStackBase, SavedKernelStack; 1157 ULONG SavedStackLimit; 1158 1159 KbdDisableMouse(); 1160 1161 /* Take control of the display */ 1162 if (KdpDebugMode.Screen) 1163 KdpScreenAcquire(); 1164 1165 /* Call the interface's main loop on a different stack */ 1166 Thread = PsGetCurrentThread(); 1167 SavedInitialStack = Thread->Tcb.InitialStack; 1168 SavedStackBase = Thread->Tcb.StackBase; 1169 SavedStackLimit = Thread->Tcb.StackLimit; 1170 SavedKernelStack = Thread->Tcb.KernelStack; 1171 Thread->Tcb.InitialStack = Thread->Tcb.StackBase = (char*)KdbStack + KDB_STACK_SIZE; 1172 Thread->Tcb.StackLimit = (ULONG_PTR)KdbStack; 1173 Thread->Tcb.KernelStack = (char*)KdbStack + KDB_STACK_SIZE; 1174 1175 // KdbpPrint("Switching to KDB stack 0x%08x-0x%08x (Current Stack is 0x%08x)\n", Thread->Tcb.StackLimit, Thread->Tcb.StackBase, Esp); 1176 1177 KdbpStackSwitchAndCall(KdbStack + KDB_STACK_SIZE - sizeof(ULONG), KdbpCallMainLoop); 1178 1179 Thread->Tcb.InitialStack = SavedInitialStack; 1180 Thread->Tcb.StackBase = SavedStackBase; 1181 Thread->Tcb.StackLimit = SavedStackLimit; 1182 Thread->Tcb.KernelStack = SavedKernelStack; 1183 1184 /* Release the display */ 1185 if (KdpDebugMode.Screen) 1186 KdpScreenRelease(); 1187 1188 KbdEnableMouse(); 1189 } 1190 1191 static ULONG 1192 KdbpGetExceptionNumberFromStatus( 1193 IN NTSTATUS ExceptionCode) 1194 { 1195 ULONG Ret; 1196 1197 switch (ExceptionCode) 1198 { 1199 case STATUS_INTEGER_DIVIDE_BY_ZERO: 1200 Ret = 0; 1201 break; 1202 case STATUS_SINGLE_STEP: 1203 Ret = 1; 1204 break; 1205 case STATUS_BREAKPOINT: 1206 Ret = 3; 1207 break; 1208 case STATUS_INTEGER_OVERFLOW: 1209 Ret = 4; 1210 break; 1211 case STATUS_ARRAY_BOUNDS_EXCEEDED: 1212 Ret = 5; 1213 break; 1214 case STATUS_ILLEGAL_INSTRUCTION: 1215 Ret = 6; 1216 break; 1217 case STATUS_FLOAT_INVALID_OPERATION: 1218 Ret = 7; 1219 break; 1220 case STATUS_STACK_OVERFLOW: 1221 Ret = 12; 1222 break; 1223 case STATUS_ACCESS_VIOLATION: 1224 Ret = 14; 1225 break; 1226 case STATUS_DATATYPE_MISALIGNMENT: 1227 Ret = 17; 1228 break; 1229 case STATUS_FLOAT_MULTIPLE_TRAPS: 1230 Ret = 18; 1231 break; 1232 case STATUS_ASSERTION_FAILURE: 1233 Ret = 20; 1234 break; 1235 1236 default: 1237 Ret = RTL_NUMBER_OF(KdbEnterConditions) - 1; 1238 break; 1239 } 1240 1241 return Ret; 1242 } 1243 1244 /*!\brief KDB Exception filter 1245 * 1246 * Called by the exception dispatcher. 1247 * 1248 * \param ExceptionRecord Unused. 1249 * \param PreviousMode UserMode if the exception was raised from umode, otherwise KernelMode. 1250 * \param Context Context, IN/OUT parameter. 1251 * \param TrapFrame Exception TrapFrame. 1252 * \param FirstChance TRUE when called before exception frames were serached, 1253 * FALSE for the second call. 1254 * 1255 * \returns KD_CONTINUE_TYPE 1256 */ 1257 KD_CONTINUE_TYPE 1258 KdbEnterDebuggerException( 1259 IN PEXCEPTION_RECORD64 ExceptionRecord, 1260 IN KPROCESSOR_MODE PreviousMode, 1261 IN PCONTEXT Context, 1262 IN BOOLEAN FirstChance) 1263 { 1264 KDB_ENTER_CONDITION EnterCondition; 1265 KD_CONTINUE_TYPE ContinueType = kdHandleException; 1266 PKDB_BREAKPOINT BreakPoint; 1267 ULONG ExpNr; 1268 ULONGLONG ull; 1269 BOOLEAN Resume = FALSE; 1270 BOOLEAN EnterConditionMet = TRUE; 1271 ULONG OldEflags; 1272 KIRQL OldIrql; 1273 NTSTATUS ExceptionCode; 1274 1275 ExceptionCode = (ExceptionRecord ? ExceptionRecord->ExceptionCode : STATUS_BREAKPOINT); 1276 1277 KdbCurrentProcess = PsGetCurrentProcess(); 1278 1279 /* Set continue type to kdContinue for single steps and breakpoints */ 1280 if (ExceptionCode == STATUS_SINGLE_STEP || 1281 ExceptionCode == STATUS_BREAKPOINT || 1282 ExceptionCode == STATUS_ASSERTION_FAILURE) 1283 { 1284 ContinueType = kdContinue; 1285 } 1286 1287 /* Check if we should handle the exception. */ 1288 /* FIXME - won't get all exceptions here :( */ 1289 ExpNr = KdbpGetExceptionNumberFromStatus(ExceptionCode); 1290 EnterCondition = KdbEnterConditions[ExpNr][FirstChance ? 0 : 1]; 1291 if (EnterCondition == KdbDoNotEnter || 1292 (EnterCondition == KdbEnterFromUmode && PreviousMode == KernelMode) || 1293 (EnterCondition == KdbEnterFromKmode && PreviousMode != KernelMode)) 1294 { 1295 EnterConditionMet = FALSE; 1296 } 1297 1298 /* If we stopped on one of our breakpoints then let the user know */ 1299 KdbLastBreakPointNr = -1; 1300 KdbEnteredOnSingleStep = FALSE; 1301 1302 if (FirstChance && (ExceptionCode == STATUS_SINGLE_STEP || ExceptionCode == STATUS_BREAKPOINT) && 1303 (KdbLastBreakPointNr = KdbpIsBreakPointOurs(ExceptionCode, Context)) >= 0) 1304 { 1305 BreakPoint = KdbBreakPoints + KdbLastBreakPointNr; 1306 1307 if (ExceptionCode == STATUS_BREAKPOINT) 1308 { 1309 /* ... and restore the original instruction */ 1310 if (!NT_SUCCESS(KdbpOverwriteInstruction(KdbCurrentProcess, BreakPoint->Address, 1311 BreakPoint->Data.SavedInstruction, NULL))) 1312 { 1313 KdbpPrint("Couldn't restore original instruction after INT3! Cannot continue execution.\n"); 1314 KeBugCheck(0); // FIXME: Proper bugcode! 1315 } 1316 1317 /* Also since we are past the int3 now, decrement EIP in the 1318 TrapFrame. This is only needed because KDBG insists on working 1319 with the TrapFrame instead of with the Context, as it is supposed 1320 to do. The context has already EIP point to the int3, since 1321 KiDispatchException accounts for that. Whatever we do here with 1322 the TrapFrame does not matter anyway, since KiDispatchException 1323 will overwrite it with the values from the Context! */ 1324 Context->Eip--; 1325 } 1326 1327 if ((BreakPoint->Type == KdbBreakPointHardware) && 1328 (BreakPoint->Data.Hw.AccessType == KdbAccessExec)) 1329 { 1330 Resume = TRUE; /* Set the resume flag when continuing execution */ 1331 } 1332 1333 /* 1334 * When a temporary breakpoint is hit we have to make sure that we are 1335 * in the same context in which it was set, otherwise it could happen 1336 * that another process/thread hits it before and it gets deleted. 1337 */ 1338 else if (BreakPoint->Type == KdbBreakPointTemporary && 1339 BreakPoint->Process == KdbCurrentProcess) 1340 { 1341 ASSERT((Context->EFlags & EFLAGS_TF) == 0); 1342 1343 /* Delete the temporary breakpoint which was used to step over or into the instruction */ 1344 KdbpDeleteBreakPoint(-1, BreakPoint); 1345 1346 if (--KdbNumSingleSteps > 0) 1347 { 1348 if ((KdbSingleStepOver && !KdbpStepOverInstruction(Context->Eip)) || 1349 (!KdbSingleStepOver && !KdbpStepIntoInstruction(Context->Eip))) 1350 { 1351 Context->EFlags |= EFLAGS_TF; 1352 } 1353 1354 goto continue_execution; /* return */ 1355 } 1356 1357 KdbEnteredOnSingleStep = TRUE; 1358 } 1359 1360 /* 1361 * If we hit a breakpoint set by the debugger we set the single step flag, 1362 * ignore the next single step and reenable the breakpoint. 1363 */ 1364 else if (BreakPoint->Type == KdbBreakPointSoftware || 1365 BreakPoint->Type == KdbBreakPointTemporary) 1366 { 1367 ASSERT(ExceptionCode == STATUS_BREAKPOINT); 1368 Context->EFlags |= EFLAGS_TF; 1369 KdbBreakPointToReenable = BreakPoint; 1370 } 1371 1372 /* Make sure that the breakpoint should be triggered in this context */ 1373 if (!BreakPoint->Global && BreakPoint->Process != KdbCurrentProcess) 1374 { 1375 goto continue_execution; /* return */ 1376 } 1377 1378 /* Check if the condition for the breakpoint is met. */ 1379 if (BreakPoint->Condition) 1380 { 1381 /* Setup the KDB trap frame */ 1382 KdbTrapFrame = *Context; 1383 1384 ull = 0; 1385 if (!KdbpRpnEvaluateParsedExpression(BreakPoint->Condition, &KdbTrapFrame, &ull, NULL, NULL)) 1386 { 1387 /* FIXME: Print warning? */ 1388 } 1389 else if (ull == 0) /* condition is not met */ 1390 { 1391 goto continue_execution; /* return */ 1392 } 1393 } 1394 1395 if (BreakPoint->Type == KdbBreakPointSoftware) 1396 { 1397 KdbpPrint("\nEntered debugger on breakpoint #%d: EXEC 0x%04x:0x%08x\n", 1398 KdbLastBreakPointNr, Context->SegCs & 0xffff, Context->Eip); 1399 } 1400 else if (BreakPoint->Type == KdbBreakPointHardware) 1401 { 1402 KdbpPrint("\nEntered debugger on breakpoint #%d: %s 0x%08x\n", 1403 KdbLastBreakPointNr, 1404 (BreakPoint->Data.Hw.AccessType == KdbAccessRead) ? "READ" : 1405 ((BreakPoint->Data.Hw.AccessType == KdbAccessWrite) ? "WRITE" : 1406 ((BreakPoint->Data.Hw.AccessType == KdbAccessReadWrite) ? "RDWR" : "EXEC")), 1407 BreakPoint->Address); 1408 } 1409 } 1410 else if (ExceptionCode == STATUS_SINGLE_STEP) 1411 { 1412 /* Silently ignore a debugger initiated single step. */ 1413 if ((Context->Dr6 & 0xf) == 0 && KdbBreakPointToReenable) 1414 { 1415 /* FIXME: Make sure that the breakpoint was really hit (check bp->Address vs. tf->Eip) */ 1416 BreakPoint = KdbBreakPointToReenable; 1417 KdbBreakPointToReenable = NULL; 1418 ASSERT(BreakPoint->Type == KdbBreakPointSoftware || 1419 BreakPoint->Type == KdbBreakPointTemporary); 1420 1421 /* 1422 * Reenable the breakpoint we disabled to execute the breakpointed 1423 * instruction. 1424 */ 1425 if (!NT_SUCCESS(KdbpOverwriteInstruction(KdbCurrentProcess, BreakPoint->Address, 0xCC, 1426 &BreakPoint->Data.SavedInstruction))) 1427 { 1428 KdbpPrint("Warning: Couldn't reenable breakpoint %d\n", 1429 BreakPoint - KdbBreakPoints); 1430 } 1431 1432 /* Unset TF if we are no longer single stepping. */ 1433 if (KdbNumSingleSteps == 0) 1434 Context->EFlags &= ~EFLAGS_TF; 1435 1436 if (!KdbpEvenThoughWeHaveABreakPointToReenableWeAlsoHaveARealSingleStep) 1437 { 1438 goto continue_execution; /* return */ 1439 } 1440 } 1441 1442 /* Quoth the raven, 'Nevermore!' */ 1443 KdbpEvenThoughWeHaveABreakPointToReenableWeAlsoHaveARealSingleStep = FALSE; 1444 1445 /* Check if we expect a single step */ 1446 if ((Context->Dr6 & 0xf) == 0 && KdbNumSingleSteps > 0) 1447 { 1448 /*ASSERT((Context->Eflags & EFLAGS_TF) != 0);*/ 1449 if (--KdbNumSingleSteps > 0) 1450 { 1451 if ((KdbSingleStepOver && KdbpStepOverInstruction(Context->Eip)) || 1452 (!KdbSingleStepOver && KdbpStepIntoInstruction(Context->Eip))) 1453 { 1454 Context->EFlags &= ~EFLAGS_TF; 1455 } 1456 else 1457 { 1458 Context->EFlags |= EFLAGS_TF; 1459 } 1460 1461 goto continue_execution; /* return */ 1462 } 1463 else 1464 { 1465 Context->EFlags &= ~EFLAGS_TF; 1466 KdbEnteredOnSingleStep = TRUE; 1467 } 1468 } 1469 else 1470 { 1471 if (!EnterConditionMet) 1472 { 1473 return kdHandleException; 1474 } 1475 1476 KdbpPrint("\nEntered debugger on unexpected debug trap!\n"); 1477 } 1478 } 1479 else if (ExceptionCode == STATUS_BREAKPOINT) 1480 { 1481 if (KdbInitFileBuffer) 1482 { 1483 KdbpCliInterpretInitFile(); 1484 EnterConditionMet = FALSE; 1485 } 1486 if (!EnterConditionMet) 1487 { 1488 return kdHandleException; 1489 } 1490 1491 KdbpPrint("\nEntered debugger on embedded INT3 at 0x%04x:0x%08x.\n", 1492 Context->SegCs & 0xffff, Context->Eip - 1); 1493 } 1494 else 1495 { 1496 const CHAR *ExceptionString = (ExpNr < RTL_NUMBER_OF(ExceptionNrToString)) ? 1497 (ExceptionNrToString[ExpNr]) : 1498 ("Unknown/User defined exception"); 1499 1500 if (!EnterConditionMet) 1501 { 1502 return ContinueType; 1503 } 1504 1505 KdbpPrint("\nEntered debugger on %s-chance exception (Exception Code: 0x%x) (%s)\n", 1506 FirstChance ? "first" : "last", ExceptionCode, ExceptionString); 1507 1508 if (ExceptionCode == STATUS_ACCESS_VIOLATION && 1509 ExceptionRecord && ExceptionRecord->NumberParameters != 0) 1510 { 1511 ULONG_PTR TrapCr2; 1512 1513 TrapCr2 = __readcr2(); 1514 1515 KdbpPrint("Memory at 0x%p could not be accessed\n", TrapCr2); 1516 } 1517 } 1518 1519 /* Once we enter the debugger we do not expect any more single steps to happen */ 1520 KdbNumSingleSteps = 0; 1521 1522 /* Update the current process pointer */ 1523 KdbCurrentProcess = KdbOriginalProcess = PsGetCurrentProcess(); 1524 KdbCurrentThread = KdbOriginalThread = PsGetCurrentThread(); 1525 KdbCurrentTrapFrame = &KdbTrapFrame; 1526 1527 /* Setup the KDB trap frame */ 1528 KdbTrapFrame = *Context; 1529 1530 /* Enter critical section */ 1531 OldEflags = __readeflags(); 1532 _disable(); 1533 1534 /* HACK: Save the current IRQL and pretend we are at passive level, 1535 * although interrupts are off. Needed because KDBG calls pageable code. */ 1536 OldIrql = KeGetCurrentIrql(); 1537 KeLowerIrql(PASSIVE_LEVEL); 1538 1539 /* Exception inside the debugger? Game over. */ 1540 if (InterlockedIncrement(&KdbEntryCount) > 1) 1541 { 1542 __writeeflags(OldEflags); 1543 return kdHandleException; 1544 } 1545 1546 /* Call the main loop */ 1547 KdbpInternalEnter(); 1548 1549 /* Check if we should single step */ 1550 if (KdbNumSingleSteps > 0) 1551 { 1552 /* Variable explains itself! */ 1553 KdbpEvenThoughWeHaveABreakPointToReenableWeAlsoHaveARealSingleStep = TRUE; 1554 1555 if ((KdbSingleStepOver && KdbpStepOverInstruction(KdbCurrentTrapFrame->Eip)) || 1556 (!KdbSingleStepOver && KdbpStepIntoInstruction(KdbCurrentTrapFrame->Eip))) 1557 { 1558 ASSERT((KdbCurrentTrapFrame->EFlags & EFLAGS_TF) == 0); 1559 /*KdbCurrentTrapFrame->EFlags &= ~EFLAGS_TF;*/ 1560 } 1561 else 1562 { 1563 KdbTrapFrame.EFlags |= EFLAGS_TF; 1564 } 1565 } 1566 1567 /* We can't update the current thread's trapframe 'cause it might not have one */ 1568 1569 /* Detach from attached process */ 1570 if (KdbCurrentProcess != KdbOriginalProcess) 1571 { 1572 KeUnstackDetachProcess(&KdbApcState); 1573 } 1574 1575 /* Update the exception Context */ 1576 *Context = KdbTrapFrame; 1577 1578 /* Decrement the entry count */ 1579 InterlockedDecrement(&KdbEntryCount); 1580 1581 /* HACK: Raise back to old IRQL */ 1582 KeRaiseIrql(OldIrql, &OldIrql); 1583 1584 /* Leave critical section */ 1585 __writeeflags(OldEflags); 1586 1587 /* Check if user requested a bugcheck */ 1588 if (KdbpBugCheckRequested) 1589 { 1590 /* Clear the flag and bugcheck the system */ 1591 KdbpBugCheckRequested = FALSE; 1592 KeBugCheck(MANUALLY_INITIATED_CRASH); 1593 } 1594 1595 continue_execution: 1596 /* Clear debug status */ 1597 if (ExceptionCode == STATUS_BREAKPOINT) /* FIXME: Why clear DR6 on INT3? */ 1598 { 1599 /* Set the RF flag so we don't trigger the same breakpoint again. */ 1600 if (Resume) 1601 { 1602 Context->EFlags |= EFLAGS_RF; 1603 } 1604 1605 /* Clear dr6 status flags. */ 1606 Context->Dr6 &= ~0x0000e00f; 1607 1608 if (!(KdbEnteredOnSingleStep && KdbSingleStepOver)) 1609 { 1610 /* Skip the current instruction */ 1611 Context->Eip++; 1612 } 1613 } 1614 1615 return ContinueType; 1616 } 1617 1618 KD_CONTINUE_TYPE 1619 KdbEnterDebuggerFirstChanceException( 1620 IN OUT PKTRAP_FRAME TrapFrame) 1621 { 1622 EXCEPTION_RECORD64 ExceptionRecord; 1623 KD_CONTINUE_TYPE Return; 1624 CONTEXT Context; 1625 1626 /* Copy TrapFrame to Context */ 1627 RtlZeroMemory(&Context, sizeof(CONTEXT)); 1628 Context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_EXTENDED_REGISTERS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS; 1629 KeTrapFrameToContext(TrapFrame, NULL, &Context); 1630 1631 /* Create ExceptionRecord (assume breakpoint) */ 1632 RtlZeroMemory(&ExceptionRecord, sizeof(EXCEPTION_RECORD64)); 1633 ExceptionRecord.ExceptionCode = STATUS_BREAKPOINT; 1634 1635 /* Call real function */ 1636 Return = KdbEnterDebuggerException(&ExceptionRecord, 1637 KernelMode, 1638 &Context, 1639 TRUE); 1640 1641 /* Copy back Context to TrapFrame */ 1642 KeContextToTrapFrame(&Context, NULL, TrapFrame, Context.ContextFlags, KernelMode); 1643 1644 return Return; 1645 } 1646 1647 VOID 1648 NTAPI 1649 KdbpGetCommandLineSettings( 1650 PCHAR p1) 1651 { 1652 #define CONST_STR_LEN(x) (sizeof(x)/sizeof(x[0]) - 1) 1653 1654 while (p1 && (p1 = strchr(p1, ' '))) 1655 { 1656 /* Skip other spaces */ 1657 while (*p1 == ' ') ++p1; 1658 1659 if (!_strnicmp(p1, "KDSERIAL", CONST_STR_LEN("KDSERIAL"))) 1660 { 1661 p1 += CONST_STR_LEN("KDSERIAL"); 1662 KdbDebugState |= KD_DEBUG_KDSERIAL; 1663 KdpDebugMode.Serial = TRUE; 1664 } 1665 else if (!_strnicmp(p1, "KDNOECHO", CONST_STR_LEN("KDNOECHO"))) 1666 { 1667 p1 += CONST_STR_LEN("KDNOECHO"); 1668 KdbDebugState |= KD_DEBUG_KDNOECHO; 1669 } 1670 else if (!_strnicmp(p1, "FIRSTCHANCE", CONST_STR_LEN("FIRSTCHANCE"))) 1671 { 1672 p1 += CONST_STR_LEN("FIRSTCHANCE"); 1673 KdbpSetEnterCondition(-1, TRUE, KdbEnterAlways); 1674 } 1675 } 1676 } 1677 1678 NTSTATUS 1679 KdbpSafeReadMemory( 1680 OUT PVOID Dest, 1681 IN PVOID Src, 1682 IN ULONG Bytes) 1683 { 1684 return KdpCopyMemoryChunks((ULONG64)(ULONG_PTR)Src, 1685 Dest, 1686 Bytes, 1687 0, 1688 MMDBG_COPY_UNSAFE, 1689 NULL); 1690 } 1691 1692 NTSTATUS 1693 KdbpSafeWriteMemory( 1694 OUT PVOID Dest, 1695 IN PVOID Src, 1696 IN ULONG Bytes) 1697 { 1698 return KdpCopyMemoryChunks((ULONG64)(ULONG_PTR)Dest, 1699 Src, 1700 Bytes, 1701 0, 1702 MMDBG_COPY_UNSAFE | MMDBG_COPY_WRITE, 1703 NULL); 1704 } 1705