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