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