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