Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenkdb.c
Go to the documentation of this file.
00001 /* 00002 * COPYRIGHT: See COPYING in the top level directory 00003 * PROJECT: ReactOS kernel 00004 * FILE: ntoskrnl/kdbg/kdb.c 00005 * PURPOSE: Kernel Debugger 00006 * 00007 * PROGRAMMERS: Gregor Anich 00008 */ 00009 00010 /* INCLUDES ******************************************************************/ 00011 00012 #include <ntoskrnl.h> 00013 #define NDEBUG 00014 #include <debug.h> 00015 00016 /* TYPES *********************************************************************/ 00017 00018 /* DEFINES *******************************************************************/ 00019 00020 #define KDB_STACK_SIZE (4096*3) 00021 #define KDB_MAXIMUM_BREAKPOINT_COUNT 256 00022 #define KDB_MAXIMUM_HW_BREAKPOINT_COUNT 4 00023 #define KDB_MAXIMUM_SW_BREAKPOINT_COUNT 256 00024 00025 #define __STRING(x) #x 00026 #define _STRING(x) __STRING(x) 00027 00028 /* GLOBALS *******************************************************************/ 00029 00030 static LONG KdbEntryCount = 0; 00031 static CHAR KdbStack[KDB_STACK_SIZE]; 00032 00033 static ULONG KdbBreakPointCount = 0; /* Number of used breakpoints in the array */ 00034 static KDB_BREAKPOINT KdbBreakPoints[KDB_MAXIMUM_BREAKPOINT_COUNT] = {{0}}; /* Breakpoint array */ 00035 static ULONG KdbSwBreakPointCount = 0; /* Number of enabled software breakpoints */ 00036 static ULONG KdbHwBreakPointCount = 0; /* Number of enabled hardware breakpoints */ 00037 static PKDB_BREAKPOINT KdbSwBreakPoints[KDB_MAXIMUM_SW_BREAKPOINT_COUNT]; /* Enabled software breakpoints, orderless */ 00038 static PKDB_BREAKPOINT KdbHwBreakPoints[KDB_MAXIMUM_HW_BREAKPOINT_COUNT]; /* Enabled hardware breakpoints, orderless */ 00039 static PKDB_BREAKPOINT KdbBreakPointToReenable = NULL; /* Set to a breakpoint struct when single stepping after 00040 a software breakpoint was hit, to reenable it */ 00041 LONG KdbLastBreakPointNr = -1; /* Index of the breakpoint which cause KDB to be entered */ 00042 ULONG KdbNumSingleSteps = 0; /* How many single steps to do */ 00043 BOOLEAN KdbSingleStepOver = FALSE; /* Whether to step over calls/reps. */ 00044 ULONG KdbDebugState = 0; /* KDBG Settings (NOECHO, KDSERIAL) */ 00045 static BOOLEAN KdbEnteredOnSingleStep = FALSE; /* Set to true when KDB was entered because of single step */ 00046 PEPROCESS KdbCurrentProcess = NULL; /* The current process context in which KDB runs */ 00047 PEPROCESS KdbOriginalProcess = NULL; /* The process in whichs context KDB was intered */ 00048 PETHREAD KdbCurrentThread = NULL; /* The current thread context in which KDB runs */ 00049 PETHREAD KdbOriginalThread = NULL; /* The thread in whichs context KDB was entered */ 00050 PKDB_KTRAP_FRAME KdbCurrentTrapFrame = NULL; /* Pointer to the current trapframe */ 00051 static KDB_KTRAP_FRAME KdbTrapFrame = { { 0 } }; /* The trapframe which was passed to KdbEnterDebuggerException */ 00052 static KDB_KTRAP_FRAME KdbThreadTrapFrame = { { 0 } }; /* The trapframe of the current thread (KdbCurrentThread) */ 00053 static KAPC_STATE KdbApcState; 00054 extern BOOLEAN KdbpBugCheckRequested; 00055 00056 /* Array of conditions when to enter KDB */ 00057 static KDB_ENTER_CONDITION KdbEnterConditions[][2] = 00058 { 00059 /* First chance Last chance */ 00060 { KdbDoNotEnter, KdbEnterFromKmode }, /* Zero devide */ 00061 { KdbEnterFromKmode, KdbDoNotEnter }, /* Debug trap */ 00062 { KdbDoNotEnter, KdbEnterAlways }, /* NMI */ 00063 { KdbEnterFromKmode, KdbDoNotEnter }, /* INT3 */ 00064 { KdbDoNotEnter, KdbEnterFromKmode }, /* Overflow */ 00065 { KdbDoNotEnter, KdbEnterFromKmode }, 00066 { KdbDoNotEnter, KdbEnterFromKmode }, /* Invalid opcode */ 00067 { KdbDoNotEnter, KdbEnterFromKmode }, /* No math coprocessor fault */ 00068 { KdbEnterAlways, KdbEnterAlways }, 00069 { KdbEnterAlways, KdbEnterAlways }, 00070 { KdbDoNotEnter, KdbEnterFromKmode }, 00071 { KdbDoNotEnter, KdbEnterFromKmode }, 00072 { KdbDoNotEnter, KdbEnterFromKmode }, /* Stack fault */ 00073 { KdbDoNotEnter, KdbEnterFromKmode }, /* General protection fault */ 00074 { KdbDoNotEnter, KdbEnterFromKmode }, /* Page fault */ 00075 { KdbEnterAlways, KdbEnterAlways }, /* Reserved (15) */ 00076 { KdbDoNotEnter, KdbEnterFromKmode }, /* FPU fault */ 00077 { KdbDoNotEnter, KdbEnterFromKmode }, 00078 { KdbDoNotEnter, KdbEnterFromKmode }, 00079 { KdbDoNotEnter, KdbEnterFromKmode }, /* SIMD fault */ 00080 { KdbDoNotEnter, KdbEnterFromKmode } /* Last entry: used for unknown exceptions */ 00081 }; 00082 00083 /* Exception descriptions */ 00084 static const CHAR *ExceptionNrToString[] = 00085 { 00086 "Divide Error", 00087 "Debug Trap", 00088 "NMI", 00089 "Breakpoint", 00090 "Overflow", 00091 "BOUND range exceeded", 00092 "Invalid Opcode", 00093 "No Math Coprocessor", 00094 "Double Fault", 00095 "Unknown(9)", 00096 "Invalid TSS", 00097 "Segment Not Present", 00098 "Stack Segment Fault", 00099 "General Protection", 00100 "Page Fault", 00101 "Reserved(15)", 00102 "Math Fault", 00103 "Alignment Check", 00104 "Machine Check", 00105 "SIMD Fault" 00106 }; 00107 00108 ULONG 00109 NTAPI 00110 KiSsFromTrapFrame( 00111 IN PKTRAP_FRAME TrapFrame); 00112 00113 ULONG 00114 NTAPI 00115 KiEspFromTrapFrame( 00116 IN PKTRAP_FRAME TrapFrame); 00117 00118 VOID 00119 NTAPI 00120 KiSsToTrapFrame( 00121 IN PKTRAP_FRAME TrapFrame, 00122 IN ULONG Ss); 00123 00124 VOID 00125 NTAPI 00126 KiEspToTrapFrame( 00127 IN PKTRAP_FRAME TrapFrame, 00128 IN ULONG Esp); 00129 00130 /* FUNCTIONS *****************************************************************/ 00131 00132 static VOID 00133 KdbpTrapFrameToKdbTrapFrame( 00134 PKTRAP_FRAME TrapFrame, 00135 PKDB_KTRAP_FRAME KdbTrapFrame) 00136 { 00137 ULONG TrapCr0, TrapCr2, TrapCr3, TrapCr4; 00138 00139 /* Copy the TrapFrame only up to Eflags and zero the rest*/ 00140 RtlCopyMemory(&KdbTrapFrame->Tf, TrapFrame, FIELD_OFFSET(KTRAP_FRAME, HardwareEsp)); 00141 RtlZeroMemory((PVOID)((ULONG_PTR)&KdbTrapFrame->Tf + FIELD_OFFSET(KTRAP_FRAME, HardwareEsp)), 00142 sizeof(KTRAP_FRAME) - FIELD_OFFSET(KTRAP_FRAME, HardwareEsp)); 00143 00144 #ifndef _MSC_VER 00145 asm volatile( 00146 "movl %%cr0, %0" "\n\t" 00147 "movl %%cr2, %1" "\n\t" 00148 "movl %%cr3, %2" "\n\t" 00149 "movl %%cr4, %3" "\n\t" 00150 : "=r"(TrapCr0), "=r"(TrapCr2), 00151 "=r"(TrapCr3), "=r"(TrapCr4)); 00152 #else 00153 __asm 00154 { 00155 mov eax, cr0; 00156 mov TrapCr0, eax; 00157 00158 mov eax, cr2; 00159 mov TrapCr2, eax; 00160 00161 mov eax, cr3; 00162 mov TrapCr3, eax; 00163 /* FIXME: What's the problem with cr4? */ 00164 //mov eax, cr4; 00165 //mov TrapCr4, eax; 00166 } 00167 #endif 00168 00169 KdbTrapFrame->Cr0 = TrapCr0; 00170 KdbTrapFrame->Cr2 = TrapCr2; 00171 KdbTrapFrame->Cr3 = TrapCr3; 00172 KdbTrapFrame->Cr4 = TrapCr4; 00173 00174 KdbTrapFrame->Tf.HardwareEsp = KiEspFromTrapFrame(TrapFrame); 00175 KdbTrapFrame->Tf.HardwareSegSs = (USHORT)(KiSsFromTrapFrame(TrapFrame) & 0xFFFF); 00176 00177 00178 /* FIXME: copy v86 registers if TrapFrame is a V86 trapframe */ 00179 } 00180 00181 static VOID 00182 KdbpKdbTrapFrameToTrapFrame( 00183 PKDB_KTRAP_FRAME KdbTrapFrame, 00184 PKTRAP_FRAME TrapFrame) 00185 { 00186 /* Copy the TrapFrame only up to Eflags and zero the rest*/ 00187 RtlCopyMemory(TrapFrame, &KdbTrapFrame->Tf, FIELD_OFFSET(KTRAP_FRAME, HardwareEsp)); 00188 00189 /* FIXME: write cr0, cr2, cr3 and cr4 (not needed atm) */ 00190 00191 KiSsToTrapFrame(TrapFrame, KdbTrapFrame->Tf.HardwareSegSs); 00192 KiEspToTrapFrame(TrapFrame, KdbTrapFrame->Tf.HardwareEsp); 00193 00194 /* FIXME: copy v86 registers if TrapFrame is a V86 trapframe */ 00195 } 00196 00197 static VOID 00198 KdbpKdbTrapFrameFromKernelStack( 00199 PVOID KernelStack, 00200 PKDB_KTRAP_FRAME KdbTrapFrame) 00201 { 00202 ULONG_PTR *StackPtr; 00203 00204 RtlZeroMemory(KdbTrapFrame, sizeof(KDB_KTRAP_FRAME)); 00205 StackPtr = (ULONG_PTR *) KernelStack; 00206 #ifdef _M_IX86 00207 KdbTrapFrame->Tf.Ebp = StackPtr[3]; 00208 KdbTrapFrame->Tf.Edi = StackPtr[4]; 00209 KdbTrapFrame->Tf.Esi = StackPtr[5]; 00210 KdbTrapFrame->Tf.Ebx = StackPtr[6]; 00211 KdbTrapFrame->Tf.Eip = StackPtr[7]; 00212 KdbTrapFrame->Tf.HardwareEsp = (ULONG) (StackPtr + 8); 00213 KdbTrapFrame->Tf.HardwareSegSs = KGDT_R0_DATA; 00214 KdbTrapFrame->Tf.SegCs = KGDT_R0_CODE; 00215 KdbTrapFrame->Tf.SegDs = KGDT_R0_DATA; 00216 KdbTrapFrame->Tf.SegEs = KGDT_R0_DATA; 00217 KdbTrapFrame->Tf.SegGs = KGDT_R0_DATA; 00218 #endif 00219 00220 /* FIXME: what about the other registers??? */ 00221 } 00222 00233 static NTSTATUS 00234 KdbpOverwriteInstruction( 00235 IN PEPROCESS Process, 00236 IN ULONG_PTR Address, 00237 IN UCHAR NewInst, 00238 OUT PUCHAR OldInst OPTIONAL) 00239 { 00240 NTSTATUS Status; 00241 ULONG Protect; 00242 PEPROCESS CurrentProcess = PsGetCurrentProcess(); 00243 KAPC_STATE ApcState; 00244 00245 /* Get the protection for the address. */ 00246 Protect = MmGetPageProtect(Process, (PVOID)PAGE_ROUND_DOWN(Address)); 00247 00248 /* Return if that page isn't present. */ 00249 if (Protect & PAGE_NOACCESS) 00250 { 00251 return STATUS_MEMORY_NOT_ALLOCATED; 00252 } 00253 00254 /* Attach to the process */ 00255 if (CurrentProcess != Process) 00256 { 00257 KeStackAttachProcess(&Process->Pcb, &ApcState); 00258 } 00259 00260 /* Make the page writeable if it is read only. */ 00261 if (Protect & (PAGE_READONLY|PAGE_EXECUTE|PAGE_EXECUTE_READ)) 00262 { 00263 MmSetPageProtect(Process, (PVOID)PAGE_ROUND_DOWN(Address), 00264 (Protect & ~(PAGE_READONLY|PAGE_EXECUTE|PAGE_EXECUTE_READ)) | PAGE_READWRITE); 00265 } 00266 00267 /* Copy the old instruction back to the caller. */ 00268 if (OldInst) 00269 { 00270 Status = KdbpSafeReadMemory(OldInst, (PUCHAR)Address, 1); 00271 if (!NT_SUCCESS(Status)) 00272 { 00273 if (Protect & (PAGE_READONLY|PAGE_EXECUTE|PAGE_EXECUTE_READ)) 00274 { 00275 MmSetPageProtect(Process, (PVOID)PAGE_ROUND_DOWN(Address), Protect); 00276 } 00277 00278 /* Detach from process */ 00279 if (CurrentProcess != Process) 00280 { 00281 KeDetachProcess(); 00282 } 00283 00284 return Status; 00285 } 00286 } 00287 00288 /* Copy the new instruction in its place. */ 00289 Status = KdbpSafeWriteMemory((PUCHAR)Address, &NewInst, 1); 00290 00291 /* Restore the page protection. */ 00292 if (Protect & (PAGE_READONLY|PAGE_EXECUTE|PAGE_EXECUTE_READ)) 00293 { 00294 MmSetPageProtect(Process, (PVOID)PAGE_ROUND_DOWN(Address), Protect); 00295 } 00296 00297 /* Detach from process */ 00298 if (CurrentProcess != Process) 00299 { 00300 KeUnstackDetachProcess(&ApcState); 00301 } 00302 00303 return Status; 00304 } 00305 00312 BOOLEAN 00313 KdbpShouldStepOverInstruction( 00314 ULONG_PTR Eip) 00315 { 00316 UCHAR Mem[3]; 00317 ULONG i = 0; 00318 00319 if (!NT_SUCCESS(KdbpSafeReadMemory(Mem, (PVOID)Eip, sizeof (Mem)))) 00320 { 00321 KdbpPrint("Couldn't access memory at 0x%p\n", Eip); 00322 return FALSE; 00323 } 00324 00325 /* Check if the current instruction is a call. */ 00326 while ((i < sizeof (Mem)) && (Mem[i] == 0x66 || Mem[i] == 0x67)) 00327 i++; 00328 00329 if (i == sizeof (Mem)) 00330 return FALSE; 00331 00332 if (Mem[i] == 0xE8 || Mem[i] == 0x9A || Mem[i] == 0xF2 || Mem[i] == 0xF3 || 00333 (((i + 1) < sizeof (Mem)) && Mem[i] == 0xFF && (Mem[i+1] & 0x38) == 0x10)) 00334 { 00335 return TRUE; 00336 } 00337 00338 return FALSE; 00339 } 00340 00350 BOOLEAN 00351 KdbpStepOverInstruction( 00352 ULONG_PTR Eip) 00353 { 00354 LONG InstLen; 00355 00356 if (!KdbpShouldStepOverInstruction(Eip)) 00357 return FALSE; 00358 00359 InstLen = KdbpGetInstLength(Eip); 00360 if (InstLen < 1) 00361 return FALSE; 00362 00363 if (!NT_SUCCESS(KdbpInsertBreakPoint(Eip + InstLen, KdbBreakPointTemporary, 0, 0, NULL, FALSE, NULL))) 00364 return FALSE; 00365 00366 return TRUE; 00367 } 00368 00378 BOOLEAN 00379 KdbpStepIntoInstruction( 00380 ULONG_PTR Eip) 00381 { 00382 KDESCRIPTOR Idtr = {0}; 00383 UCHAR Mem[2]; 00384 INT IntVect; 00385 ULONG IntDesc[2]; 00386 ULONG_PTR TargetEip; 00387 00388 /* Read memory */ 00389 if (!NT_SUCCESS(KdbpSafeReadMemory(Mem, (PVOID)Eip, sizeof (Mem)))) 00390 { 00391 /*KdbpPrint("Couldn't access memory at 0x%p\n", Eip);*/ 00392 return FALSE; 00393 } 00394 00395 /* Check for INT instruction */ 00396 /* FIXME: Check for iret */ 00397 if (Mem[0] == 0xcc) 00398 IntVect = 3; 00399 else if (Mem[0] == 0xcd) 00400 IntVect = Mem[1]; 00401 else if (Mem[0] == 0xce && KdbCurrentTrapFrame->Tf.EFlags & (1<<11)) /* 1 << 11 is the overflow flag */ 00402 IntVect = 4; 00403 else 00404 return FALSE; 00405 00406 if (IntVect < 32) /* We should be informed about interrupts < 32 by the kernel, no need to breakpoint them */ 00407 { 00408 return FALSE; 00409 } 00410 00411 /* Read the interrupt descriptor table register */ 00412 __sidt(&Idtr.Limit); 00413 if (IntVect >= (Idtr.Limit + 1) / 8) 00414 { 00415 /*KdbpPrint("IDT does not contain interrupt vector %d\n.", IntVect);*/ 00416 return TRUE; 00417 } 00418 00419 /* Get the interrupt descriptor */ 00420 if (!NT_SUCCESS(KdbpSafeReadMemory(IntDesc, (PVOID)(ULONG_PTR)(Idtr.Base + (IntVect * 8)), sizeof (IntDesc)))) 00421 { 00422 /*KdbpPrint("Couldn't access memory at 0x%p\n", (ULONG_PTR)Idtr.Base + (IntVect * 8));*/ 00423 return FALSE; 00424 } 00425 00426 /* Check descriptor and get target eip (16 bit interrupt/trap gates not supported) */ 00427 if ((IntDesc[1] & (1 << 15)) == 0) /* not present */ 00428 { 00429 return FALSE; 00430 } 00431 if ((IntDesc[1] & 0x1f00) == 0x0500) /* Task gate */ 00432 { 00433 /* FIXME: Task gates not supported */ 00434 return FALSE; 00435 } 00436 else if (((IntDesc[1] & 0x1fe0) == 0x0e00) || /* 32 bit Interrupt gate */ 00437 ((IntDesc[1] & 0x1fe0) == 0x0f00)) /* 32 bit Trap gate */ 00438 { 00439 /* FIXME: Should the segment selector of the interrupt gate be checked? */ 00440 TargetEip = (IntDesc[1] & 0xffff0000) | (IntDesc[0] & 0x0000ffff); 00441 } 00442 else 00443 { 00444 return FALSE; 00445 } 00446 00447 /* Insert breakpoint */ 00448 if (!NT_SUCCESS(KdbpInsertBreakPoint(TargetEip, KdbBreakPointTemporary, 0, 0, NULL, FALSE, NULL))) 00449 return FALSE; 00450 00451 return TRUE; 00452 } 00453 00460 LONG 00461 KdbpGetNextBreakPointNr( 00462 IN ULONG Start OPTIONAL) 00463 { 00464 for (; Start < RTL_NUMBER_OF(KdbBreakPoints); Start++) 00465 { 00466 if (KdbBreakPoints[Start].Type != KdbBreakPointNone) 00467 return Start; 00468 } 00469 00470 return -1; 00471 } 00472 00487 BOOLEAN 00488 KdbpGetBreakPointInfo( 00489 IN ULONG BreakPointNr, 00490 OUT ULONG_PTR *Address OPTIONAL, 00491 OUT KDB_BREAKPOINT_TYPE *Type OPTIONAL, 00492 OUT UCHAR *Size OPTIONAL, 00493 OUT KDB_ACCESS_TYPE *AccessType OPTIONAL, 00494 OUT UCHAR *DebugReg OPTIONAL, 00495 OUT BOOLEAN *Enabled OPTIONAL, 00496 OUT BOOLEAN *Global OPTIONAL, 00497 OUT PEPROCESS *Process OPTIONAL, 00498 OUT PCHAR *ConditionExpression OPTIONAL) 00499 { 00500 PKDB_BREAKPOINT bp; 00501 00502 if (BreakPointNr >= RTL_NUMBER_OF(KdbBreakPoints) || 00503 KdbBreakPoints[BreakPointNr].Type == KdbBreakPointNone) 00504 { 00505 return FALSE; 00506 } 00507 00508 bp = KdbBreakPoints + BreakPointNr; 00509 if (Address) 00510 *Address = bp->Address; 00511 00512 if (Type) 00513 *Type = bp->Type; 00514 00515 if (bp->Type == KdbBreakPointHardware) 00516 { 00517 if (Size) 00518 *Size = bp->Data.Hw.Size; 00519 00520 if (AccessType) 00521 *AccessType = bp->Data.Hw.AccessType; 00522 00523 if (DebugReg && bp->Enabled) 00524 *DebugReg = bp->Data.Hw.DebugReg; 00525 } 00526 00527 if (Enabled) 00528 *Enabled = bp->Enabled; 00529 00530 if (Global) 00531 *Global = bp->Global; 00532 00533 if (Process) 00534 *Process = bp->Process; 00535 00536 if (ConditionExpression) 00537 *ConditionExpression = bp->ConditionExpression; 00538 00539 return TRUE; 00540 } 00541 00556 NTSTATUS 00557 KdbpInsertBreakPoint( 00558 IN ULONG_PTR Address, 00559 IN KDB_BREAKPOINT_TYPE Type, 00560 IN UCHAR Size OPTIONAL, 00561 IN KDB_ACCESS_TYPE AccessType OPTIONAL, 00562 IN PCHAR ConditionExpression OPTIONAL, 00563 IN BOOLEAN Global, 00564 OUT PLONG BreakPointNr OPTIONAL) 00565 { 00566 LONG i; 00567 PVOID Condition; 00568 PCHAR ConditionExpressionDup; 00569 LONG ErrOffset; 00570 CHAR ErrMsg[128]; 00571 00572 ASSERT(Type != KdbBreakPointNone); 00573 00574 if (Type == KdbBreakPointHardware) 00575 { 00576 if ((Address % Size) != 0) 00577 { 00578 KdbpPrint("Address (0x%p) must be aligned to a multiple of the size (%d)\n", Address, Size); 00579 return STATUS_UNSUCCESSFUL; 00580 } 00581 00582 if (AccessType == KdbAccessExec && Size != 1) 00583 { 00584 KdbpPrint("Size must be 1 for execution breakpoints.\n"); 00585 return STATUS_UNSUCCESSFUL; 00586 } 00587 } 00588 00589 if (KdbBreakPointCount == KDB_MAXIMUM_BREAKPOINT_COUNT) 00590 { 00591 return STATUS_UNSUCCESSFUL; 00592 } 00593 00594 /* Parse conditon expression string and duplicate it */ 00595 if (ConditionExpression) 00596 { 00597 Condition = KdbpRpnParseExpression(ConditionExpression, &ErrOffset, ErrMsg); 00598 if (!Condition) 00599 { 00600 if (ErrOffset >= 0) 00601 KdbpPrint("Couldn't parse expression: %s at character %d\n", ErrMsg, ErrOffset); 00602 else 00603 KdbpPrint("Couldn't parse expression: %s", ErrMsg); 00604 00605 return STATUS_UNSUCCESSFUL; 00606 } 00607 00608 i = strlen(ConditionExpression) + 1; 00609 ConditionExpressionDup = ExAllocatePoolWithTag(NonPagedPool, i, TAG_KDBG); 00610 RtlCopyMemory(ConditionExpressionDup, ConditionExpression, i); 00611 } 00612 else 00613 { 00614 Condition = NULL; 00615 ConditionExpressionDup = NULL; 00616 } 00617 00618 /* Find unused breakpoint */ 00619 if (Type == KdbBreakPointTemporary) 00620 { 00621 for (i = RTL_NUMBER_OF(KdbBreakPoints) - 1; i >= 0; i--) 00622 { 00623 if (KdbBreakPoints[i].Type == KdbBreakPointNone) 00624 break; 00625 } 00626 } 00627 else 00628 { 00629 for (i = 0; i < (LONG)RTL_NUMBER_OF(KdbBreakPoints); i++) 00630 { 00631 if (KdbBreakPoints[i].Type == KdbBreakPointNone) 00632 break; 00633 } 00634 } 00635 00636 ASSERT(i < (LONG)RTL_NUMBER_OF(KdbBreakPoints)); 00637 00638 /* Set the breakpoint */ 00639 ASSERT(KdbCurrentProcess); 00640 KdbBreakPoints[i].Type = Type; 00641 KdbBreakPoints[i].Address = Address; 00642 KdbBreakPoints[i].Enabled = FALSE; 00643 KdbBreakPoints[i].Global = Global; 00644 KdbBreakPoints[i].Process = KdbCurrentProcess; 00645 KdbBreakPoints[i].ConditionExpression = ConditionExpressionDup; 00646 KdbBreakPoints[i].Condition = Condition; 00647 00648 if (Type == KdbBreakPointHardware) 00649 { 00650 KdbBreakPoints[i].Data.Hw.Size = Size; 00651 KdbBreakPoints[i].Data.Hw.AccessType = AccessType; 00652 } 00653 00654 KdbBreakPointCount++; 00655 00656 if (Type != KdbBreakPointTemporary) 00657 KdbpPrint("Breakpoint %d inserted.\n", i); 00658 00659 /* Try to enable the breakpoint */ 00660 KdbpEnableBreakPoint(i, NULL); 00661 00662 /* Return the breakpoint number */ 00663 if (BreakPointNr) 00664 *BreakPointNr = i; 00665 00666 return STATUS_SUCCESS; 00667 } 00668 00677 BOOLEAN 00678 KdbpDeleteBreakPoint( 00679 IN LONG BreakPointNr OPTIONAL, 00680 IN OUT PKDB_BREAKPOINT BreakPoint OPTIONAL) 00681 { 00682 if (BreakPointNr < 0) 00683 { 00684 ASSERT(BreakPoint); 00685 BreakPointNr = BreakPoint - KdbBreakPoints; 00686 } 00687 00688 if (BreakPointNr < 0 || BreakPointNr >= KDB_MAXIMUM_BREAKPOINT_COUNT) 00689 { 00690 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr); 00691 return FALSE; 00692 } 00693 00694 if (!BreakPoint) 00695 { 00696 BreakPoint = KdbBreakPoints + BreakPointNr; 00697 } 00698 00699 if (BreakPoint->Type == KdbBreakPointNone) 00700 { 00701 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr); 00702 return FALSE; 00703 } 00704 00705 if (BreakPoint->Enabled && !KdbpDisableBreakPoint(-1, BreakPoint)) 00706 return FALSE; 00707 00708 if (BreakPoint->Type != KdbBreakPointTemporary) 00709 KdbpPrint("Breakpoint %d deleted.\n", BreakPointNr); 00710 00711 BreakPoint->Type = KdbBreakPointNone; 00712 KdbBreakPointCount--; 00713 00714 return TRUE; 00715 } 00716 00727 static LONG 00728 KdbpIsBreakPointOurs( 00729 IN NTSTATUS ExceptionCode, 00730 IN PKTRAP_FRAME TrapFrame) 00731 { 00732 ULONG i; 00733 ASSERT(ExceptionCode == STATUS_SINGLE_STEP || ExceptionCode == STATUS_BREAKPOINT); 00734 00735 if (ExceptionCode == STATUS_BREAKPOINT) /* Software interrupt */ 00736 { 00737 ULONG_PTR BpEip = (ULONG_PTR)TrapFrame->Eip - 1; /* Get EIP of INT3 instruction */ 00738 for (i = 0; i < KdbSwBreakPointCount; i++) 00739 { 00740 ASSERT((KdbSwBreakPoints[i]->Type == KdbBreakPointSoftware || 00741 KdbSwBreakPoints[i]->Type == KdbBreakPointTemporary)); 00742 ASSERT(KdbSwBreakPoints[i]->Enabled); 00743 00744 if (KdbSwBreakPoints[i]->Address == BpEip) 00745 { 00746 return KdbSwBreakPoints[i] - KdbBreakPoints; 00747 } 00748 } 00749 } 00750 else if (ExceptionCode == STATUS_SINGLE_STEP) /* Hardware interrupt */ 00751 { 00752 UCHAR DebugReg; 00753 00754 for (i = 0; i < KdbHwBreakPointCount; i++) 00755 { 00756 ASSERT(KdbHwBreakPoints[i]->Type == KdbBreakPointHardware && 00757 KdbHwBreakPoints[i]->Enabled); 00758 DebugReg = KdbHwBreakPoints[i]->Data.Hw.DebugReg; 00759 00760 if ((TrapFrame->Dr6 & (1 << DebugReg)) != 0) 00761 { 00762 return KdbHwBreakPoints[i] - KdbBreakPoints; 00763 } 00764 } 00765 } 00766 00767 return -1; 00768 } 00769 00780 BOOLEAN 00781 KdbpEnableBreakPoint( 00782 IN LONG BreakPointNr OPTIONAL, 00783 IN OUT PKDB_BREAKPOINT BreakPoint OPTIONAL) 00784 { 00785 NTSTATUS Status; 00786 INT i; 00787 ULONG ul; 00788 00789 if (BreakPointNr < 0) 00790 { 00791 ASSERT(BreakPoint); 00792 BreakPointNr = BreakPoint - KdbBreakPoints; 00793 } 00794 00795 if (BreakPointNr < 0 || BreakPointNr >= KDB_MAXIMUM_BREAKPOINT_COUNT) 00796 { 00797 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr); 00798 return FALSE; 00799 } 00800 00801 if (!BreakPoint) 00802 { 00803 BreakPoint = KdbBreakPoints + BreakPointNr; 00804 } 00805 00806 if (BreakPoint->Type == KdbBreakPointNone) 00807 { 00808 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr); 00809 return FALSE; 00810 } 00811 00812 if (BreakPoint->Enabled) 00813 { 00814 KdbpPrint("Breakpoint %d is already enabled.\n", BreakPointNr); 00815 return TRUE; 00816 } 00817 00818 if (BreakPoint->Type == KdbBreakPointSoftware || 00819 BreakPoint->Type == KdbBreakPointTemporary) 00820 { 00821 if (KdbSwBreakPointCount >= KDB_MAXIMUM_SW_BREAKPOINT_COUNT) 00822 { 00823 KdbpPrint("Maximum number of SW breakpoints (%d) used. " 00824 "Disable another breakpoint in order to enable this one.\n", 00825 KDB_MAXIMUM_SW_BREAKPOINT_COUNT); 00826 return FALSE; 00827 } 00828 00829 Status = KdbpOverwriteInstruction(BreakPoint->Process, BreakPoint->Address, 00830 0xCC, &BreakPoint->Data.SavedInstruction); 00831 if (!NT_SUCCESS(Status)) 00832 { 00833 KdbpPrint("Couldn't access memory at 0x%p\n", BreakPoint->Address); 00834 return FALSE; 00835 } 00836 00837 KdbSwBreakPoints[KdbSwBreakPointCount++] = BreakPoint; 00838 } 00839 else 00840 { 00841 if (BreakPoint->Data.Hw.AccessType == KdbAccessExec) 00842 ASSERT(BreakPoint->Data.Hw.Size == 1); 00843 00844 ASSERT((BreakPoint->Address % BreakPoint->Data.Hw.Size) == 0); 00845 00846 if (KdbHwBreakPointCount >= KDB_MAXIMUM_HW_BREAKPOINT_COUNT) 00847 { 00848 KdbpPrint("Maximum number of HW breakpoints (%d) already used. " 00849 "Disable another breakpoint in order to enable this one.\n", 00850 KDB_MAXIMUM_HW_BREAKPOINT_COUNT); 00851 00852 return FALSE; 00853 } 00854 00855 /* Find unused hw breakpoint */ 00856 ASSERT(KDB_MAXIMUM_HW_BREAKPOINT_COUNT == 4); 00857 for (i = 0; i < KDB_MAXIMUM_HW_BREAKPOINT_COUNT; i++) 00858 { 00859 if ((KdbTrapFrame.Tf.Dr7 & (0x3 << (i * 2))) == 0) 00860 break; 00861 } 00862 00863 ASSERT(i < KDB_MAXIMUM_HW_BREAKPOINT_COUNT); 00864 00865 /* Set the breakpoint address. */ 00866 switch (i) 00867 { 00868 case 0: 00869 KdbTrapFrame.Tf.Dr0 = BreakPoint->Address; 00870 break; 00871 case 1: 00872 KdbTrapFrame.Tf.Dr1 = BreakPoint->Address; 00873 break; 00874 case 2: 00875 KdbTrapFrame.Tf.Dr2 = BreakPoint->Address; 00876 break; 00877 case 3: 00878 KdbTrapFrame.Tf.Dr3 = BreakPoint->Address; 00879 break; 00880 } 00881 00882 /* Enable the global breakpoint */ 00883 KdbTrapFrame.Tf.Dr7 |= (0x2 << (i * 2)); 00884 00885 /* Enable the exact match bits. */ 00886 KdbTrapFrame.Tf.Dr7 |= 0x00000300; 00887 00888 /* Clear existing state. */ 00889 KdbTrapFrame.Tf.Dr7 &= ~(0xF << (16 + (i * 4))); 00890 00891 /* Set the breakpoint type. */ 00892 switch (BreakPoint->Data.Hw.AccessType) 00893 { 00894 case KdbAccessExec: 00895 ul = 0; 00896 break; 00897 case KdbAccessWrite: 00898 ul = 1; 00899 break; 00900 case KdbAccessRead: 00901 case KdbAccessReadWrite: 00902 ul = 3; 00903 break; 00904 default: 00905 ASSERT(0); 00906 return TRUE; 00907 break; 00908 } 00909 00910 KdbTrapFrame.Tf.Dr7 |= (ul << (16 + (i * 4))); 00911 00912 /* Set the breakpoint length. */ 00913 KdbTrapFrame.Tf.Dr7 |= ((BreakPoint->Data.Hw.Size - 1) << (18 + (i * 4))); 00914 00915 /* Update KdbCurrentTrapFrame - values are taken from there by the CLI */ 00916 if (&KdbTrapFrame != KdbCurrentTrapFrame) 00917 { 00918 KdbCurrentTrapFrame->Tf.Dr0 = KdbTrapFrame.Tf.Dr0; 00919 KdbCurrentTrapFrame->Tf.Dr1 = KdbTrapFrame.Tf.Dr1; 00920 KdbCurrentTrapFrame->Tf.Dr2 = KdbTrapFrame.Tf.Dr2; 00921 KdbCurrentTrapFrame->Tf.Dr3 = KdbTrapFrame.Tf.Dr3; 00922 KdbCurrentTrapFrame->Tf.Dr6 = KdbTrapFrame.Tf.Dr6; 00923 KdbCurrentTrapFrame->Tf.Dr7 = KdbTrapFrame.Tf.Dr7; 00924 } 00925 00926 BreakPoint->Data.Hw.DebugReg = i; 00927 KdbHwBreakPoints[KdbHwBreakPointCount++] = BreakPoint; 00928 } 00929 00930 BreakPoint->Enabled = TRUE; 00931 if (BreakPoint->Type != KdbBreakPointTemporary) 00932 KdbpPrint("Breakpoint %d enabled.\n", BreakPointNr); 00933 00934 return TRUE; 00935 } 00936 00947 BOOLEAN 00948 KdbpDisableBreakPoint( 00949 IN LONG BreakPointNr OPTIONAL, 00950 IN OUT PKDB_BREAKPOINT BreakPoint OPTIONAL) 00951 { 00952 ULONG i; 00953 NTSTATUS Status; 00954 00955 if (BreakPointNr < 0) 00956 { 00957 ASSERT(BreakPoint); 00958 BreakPointNr = BreakPoint - KdbBreakPoints; 00959 } 00960 00961 if (BreakPointNr < 0 || BreakPointNr >= KDB_MAXIMUM_BREAKPOINT_COUNT) 00962 { 00963 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr); 00964 return FALSE; 00965 } 00966 00967 if (!BreakPoint) 00968 { 00969 BreakPoint = KdbBreakPoints + BreakPointNr; 00970 } 00971 00972 if (BreakPoint->Type == KdbBreakPointNone) 00973 { 00974 KdbpPrint("Invalid breakpoint: %d\n", BreakPointNr); 00975 return FALSE; 00976 } 00977 00978 if (BreakPoint->Enabled == FALSE) 00979 { 00980 KdbpPrint("Breakpoint %d is not enabled.\n", BreakPointNr); 00981 return TRUE; 00982 } 00983 00984 if (BreakPoint->Type == KdbBreakPointSoftware || 00985 BreakPoint->Type == KdbBreakPointTemporary) 00986 { 00987 ASSERT(KdbSwBreakPointCount > 0); 00988 Status = KdbpOverwriteInstruction(BreakPoint->Process, BreakPoint->Address, 00989 BreakPoint->Data.SavedInstruction, NULL); 00990 00991 if (!NT_SUCCESS(Status)) 00992 { 00993 KdbpPrint("Couldn't restore original instruction.\n"); 00994 return FALSE; 00995 } 00996 00997 for (i = 0; i < KdbSwBreakPointCount; i++) 00998 { 00999 if (KdbSwBreakPoints[i] == BreakPoint) 01000 { 01001 KdbSwBreakPoints[i] = KdbSwBreakPoints[--KdbSwBreakPointCount]; 01002 i = -1; /* if the last breakpoint is disabled dont break with i >= KdbSwBreakPointCount */ 01003 break; 01004 } 01005 } 01006 01007 if (i != MAXULONG) /* not found */ 01008 ASSERT(0); 01009 } 01010 else 01011 { 01012 ASSERT(BreakPoint->Type == KdbBreakPointHardware); 01013 01014 /* Clear the breakpoint. */ 01015 KdbTrapFrame.Tf.Dr7 &= ~(0x3 << (BreakPoint->Data.Hw.DebugReg * 2)); 01016 if ((KdbTrapFrame.Tf.Dr7 & 0xFF) == 0) 01017 { 01018 /* If no breakpoints are enabled then clear the exact match flags. */ 01019 KdbTrapFrame.Tf.Dr7 &= 0xFFFFFCFF; 01020 } 01021 01022 for (i = 0; i < KdbHwBreakPointCount; i++) 01023 { 01024 if (KdbHwBreakPoints[i] == BreakPoint) 01025 { 01026 KdbHwBreakPoints[i] = KdbHwBreakPoints[--KdbHwBreakPointCount]; 01027 i = -1; /* if the last breakpoint is disabled dont break with i >= KdbHwBreakPointCount */ 01028 break; 01029 } 01030 } 01031 01032 if (i != MAXULONG) /* not found */ 01033 ASSERT(0); 01034 } 01035 01036 BreakPoint->Enabled = FALSE; 01037 if (BreakPoint->Type != KdbBreakPointTemporary) 01038 KdbpPrint("Breakpoint %d disabled.\n", BreakPointNr); 01039 01040 return TRUE; 01041 } 01042 01052 BOOLEAN 01053 KdbpGetEnterCondition( 01054 IN LONG ExceptionNr, 01055 IN BOOLEAN FirstChance, 01056 OUT KDB_ENTER_CONDITION *Condition) 01057 { 01058 if (ExceptionNr >= (LONG)RTL_NUMBER_OF(KdbEnterConditions)) 01059 return FALSE; 01060 01061 *Condition = KdbEnterConditions[ExceptionNr][FirstChance ? 0 : 1]; 01062 return TRUE; 01063 } 01064 01074 BOOLEAN 01075 KdbpSetEnterCondition( 01076 IN LONG ExceptionNr, 01077 IN BOOLEAN FirstChance, 01078 IN KDB_ENTER_CONDITION Condition) 01079 { 01080 if (ExceptionNr < 0) 01081 { 01082 for (ExceptionNr = 0; ExceptionNr < (LONG)RTL_NUMBER_OF(KdbEnterConditions); ExceptionNr++) 01083 { 01084 if (ExceptionNr == 1 || ExceptionNr == 8 || 01085 ExceptionNr == 9 || ExceptionNr == 15) /* Reserved exceptions */ 01086 { 01087 continue; 01088 } 01089 01090 KdbEnterConditions[ExceptionNr][FirstChance ? 0 : 1] = Condition; 01091 } 01092 } 01093 else 01094 { 01095 if (ExceptionNr >= (LONG)RTL_NUMBER_OF(KdbEnterConditions) || 01096 ExceptionNr == 1 || ExceptionNr == 8 || /* Do not allow changing of the debug */ 01097 ExceptionNr == 9 || ExceptionNr == 15) /* trap or reserved exceptions */ 01098 { 01099 return FALSE; 01100 } 01101 01102 KdbEnterConditions[ExceptionNr][FirstChance ? 0 : 1] = Condition; 01103 } 01104 01105 return TRUE; 01106 } 01107 01115 BOOLEAN 01116 KdbpAttachToThread( 01117 PVOID ThreadId) 01118 { 01119 PETHREAD Thread = NULL; 01120 PEPROCESS Process; 01121 01122 /* Get a pointer to the thread */ 01123 if (!NT_SUCCESS(PsLookupThreadByThreadId(ThreadId, &Thread))) 01124 { 01125 KdbpPrint("Invalid thread id: 0x%08x\n", (ULONG_PTR)ThreadId); 01126 return FALSE; 01127 } 01128 Process = Thread->ThreadsProcess; 01129 01130 if (KeIsExecutingDpc() && Process != KdbCurrentProcess) 01131 { 01132 KdbpPrint("Cannot attach to thread within another process while executing a DPC.\n"); 01133 ObDereferenceObject(Thread); 01134 return FALSE; 01135 } 01136 01137 /* Save the current thread's context (if we previously attached to a thread) */ 01138 if (KdbCurrentThread != KdbOriginalThread) 01139 { 01140 ASSERT(KdbCurrentTrapFrame == &KdbThreadTrapFrame); 01141 /* Actually, we can't save the context, there's no guarantee that there was a trap frame */ 01142 } 01143 else 01144 { 01145 ASSERT(KdbCurrentTrapFrame == &KdbTrapFrame); 01146 } 01147 01148 /* Switch to the thread's context */ 01149 if (Thread != KdbOriginalThread) 01150 { 01151 /* The thread we're attaching to isn't the thread on which we entered 01152 * kdb and so the thread we're attaching to is not running. There 01153 * is no guarantee that it actually has a trap frame. So we have to 01154 * peek directly at the registers which were saved on the stack when the 01155 * thread was preempted in the scheduler */ 01156 KdbpKdbTrapFrameFromKernelStack(Thread->Tcb.KernelStack, 01157 &KdbThreadTrapFrame); 01158 KdbCurrentTrapFrame = &KdbThreadTrapFrame; 01159 } 01160 else /* Switching back to original thread */ 01161 { 01162 KdbCurrentTrapFrame = &KdbTrapFrame; 01163 } 01164 KdbCurrentThread = Thread; 01165 01166 /* Attach to the thread's process */ 01167 ASSERT(KdbCurrentProcess == PsGetCurrentProcess()); 01168 if (KdbCurrentProcess != Process) 01169 { 01170 if (KdbCurrentProcess != KdbOriginalProcess) /* detach from previously attached process */ 01171 { 01172 KeUnstackDetachProcess(&KdbApcState); 01173 } 01174 01175 if (KdbOriginalProcess != Process) 01176 { 01177 KeStackAttachProcess(&Process->Pcb, &KdbApcState); 01178 } 01179 01180 KdbCurrentProcess = Process; 01181 } 01182 01183 ObDereferenceObject(Thread); 01184 return TRUE; 01185 } 01186 01196 BOOLEAN 01197 KdbpAttachToProcess( 01198 PVOID ProcessId) 01199 { 01200 PEPROCESS Process = NULL; 01201 PETHREAD Thread; 01202 PLIST_ENTRY Entry; 01203 01204 /* Get a pointer to the process */ 01205 if (!NT_SUCCESS(PsLookupProcessByProcessId(ProcessId, &Process))) 01206 { 01207 KdbpPrint("Invalid process id: 0x%08x\n", (ULONG_PTR)ProcessId); 01208 return FALSE; 01209 } 01210 01211 Entry = Process->ThreadListHead.Flink; 01212 ObDereferenceObject(Process); 01213 if (Entry == &KdbCurrentProcess->ThreadListHead) 01214 { 01215 KdbpPrint("No threads in process 0x%p, cannot attach to process!\n", ProcessId); 01216 return FALSE; 01217 } 01218 01219 Thread = CONTAINING_RECORD(Entry, ETHREAD, ThreadListEntry); 01220 01221 return KdbpAttachToThread(Thread->Cid.UniqueThread); 01222 } 01223 01226 static VOID 01227 KdbpCallMainLoop(VOID) 01228 { 01229 KdbpCliMainLoop(KdbEnteredOnSingleStep); 01230 } 01231 01236 static VOID 01237 KdbpInternalEnter() 01238 { 01239 PETHREAD Thread; 01240 PVOID SavedInitialStack, SavedStackBase, SavedKernelStack; 01241 ULONG SavedStackLimit; 01242 01243 KbdDisableMouse(); 01244 01245 if (KdpDebugMode.Screen && 01246 InbvIsBootDriverInstalled() && 01247 !InbvCheckDisplayOwnership()) 01248 { 01249 /* Acquire ownership and reset the display */ 01250 InbvAcquireDisplayOwnership(); 01251 InbvResetDisplay(); 01252 01253 /* Display debugger prompt */ 01254 InbvSolidColorFill(0, 0, 639, 479, 0); 01255 InbvSetTextColor(15); 01256 InbvInstallDisplayStringFilter(NULL); 01257 InbvEnableDisplayString(TRUE); 01258 InbvSetScrollRegion(0, 0, 639, 479); 01259 } 01260 01261 /* Call the interface's main loop on a different stack */ 01262 Thread = PsGetCurrentThread(); 01263 SavedInitialStack = Thread->Tcb.InitialStack; 01264 SavedStackBase = Thread->Tcb.StackBase; 01265 SavedStackLimit = Thread->Tcb.StackLimit; 01266 SavedKernelStack = Thread->Tcb.KernelStack; 01267 Thread->Tcb.InitialStack = Thread->Tcb.StackBase = (char*)KdbStack + KDB_STACK_SIZE; 01268 Thread->Tcb.StackLimit = (ULONG_PTR)KdbStack; 01269 Thread->Tcb.KernelStack = (char*)KdbStack + KDB_STACK_SIZE; 01270 01271 /*KdbpPrint("Switching to KDB stack 0x%08x-0x%08x (Current Stack is 0x%08x)\n", Thread->Tcb.StackLimit, Thread->Tcb.StackBase, Esp);*/ 01272 01273 KdbpStackSwitchAndCall(KdbStack + KDB_STACK_SIZE - sizeof(ULONG), KdbpCallMainLoop); 01274 01275 Thread->Tcb.InitialStack = SavedInitialStack; 01276 Thread->Tcb.StackBase = SavedStackBase; 01277 Thread->Tcb.StackLimit = SavedStackLimit; 01278 Thread->Tcb.KernelStack = SavedKernelStack; 01279 KbdEnableMouse(); 01280 } 01281 01282 static ULONG 01283 KdbpGetExceptionNumberFromStatus( 01284 IN NTSTATUS ExceptionCode) 01285 { 01286 ULONG Ret; 01287 01288 switch (ExceptionCode) 01289 { 01290 case STATUS_INTEGER_DIVIDE_BY_ZERO: 01291 Ret = 0; 01292 break; 01293 case STATUS_SINGLE_STEP: 01294 Ret = 1; 01295 break; 01296 case STATUS_BREAKPOINT: 01297 Ret = 3; 01298 break; 01299 case STATUS_INTEGER_OVERFLOW: 01300 Ret = 4; 01301 break; 01302 case STATUS_ARRAY_BOUNDS_EXCEEDED: 01303 Ret = 5; 01304 break; 01305 case STATUS_ILLEGAL_INSTRUCTION: 01306 Ret = 6; 01307 break; 01308 case STATUS_FLOAT_INVALID_OPERATION: 01309 Ret = 7; 01310 break; 01311 case STATUS_STACK_OVERFLOW: 01312 Ret = 12; 01313 break; 01314 case STATUS_ACCESS_VIOLATION: 01315 Ret = 14; 01316 break; 01317 case STATUS_DATATYPE_MISALIGNMENT: 01318 Ret = 17; 01319 break; 01320 case STATUS_FLOAT_MULTIPLE_TRAPS: 01321 Ret = 18; 01322 break; 01323 01324 default: 01325 Ret = RTL_NUMBER_OF(KdbEnterConditions) - 1; 01326 break; 01327 } 01328 01329 return Ret; 01330 } 01331 01345 KD_CONTINUE_TYPE 01346 KdbEnterDebuggerException( 01347 IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL, 01348 IN KPROCESSOR_MODE PreviousMode, 01349 IN PCONTEXT Context, 01350 IN OUT PKTRAP_FRAME TrapFrame, 01351 IN BOOLEAN FirstChance) 01352 { 01353 KDB_ENTER_CONDITION EnterCondition; 01354 KD_CONTINUE_TYPE ContinueType = kdHandleException; 01355 PKDB_BREAKPOINT BreakPoint; 01356 ULONG ExpNr; 01357 ULONGLONG ull; 01358 BOOLEAN Resume = FALSE; 01359 BOOLEAN EnterConditionMet = TRUE; 01360 ULONG OldEflags; 01361 KIRQL OldIrql; 01362 NTSTATUS ExceptionCode; 01363 01364 ExceptionCode = (ExceptionRecord ? ExceptionRecord->ExceptionCode : STATUS_BREAKPOINT); 01365 01366 KdbCurrentProcess = PsGetCurrentProcess(); 01367 01368 /* Set continue type to kdContinue for single steps and breakpoints */ 01369 if (ExceptionCode == STATUS_SINGLE_STEP || ExceptionCode == STATUS_BREAKPOINT) 01370 ContinueType = kdContinue; 01371 01372 /* Check if we should handle the exception. */ 01373 /* FIXME - won't get all exceptions here :( */ 01374 ExpNr = KdbpGetExceptionNumberFromStatus(ExceptionCode); 01375 EnterCondition = KdbEnterConditions[ExpNr][FirstChance ? 0 : 1]; 01376 if (EnterCondition == KdbDoNotEnter || 01377 (EnterCondition == KdbEnterFromUmode && PreviousMode == KernelMode) || 01378 (EnterCondition == KdbEnterFromKmode && PreviousMode != KernelMode)) 01379 { 01380 EnterConditionMet = FALSE; 01381 } 01382 01383 /* If we stopped on one of our breakpoints then let the user know. */ 01384 KdbLastBreakPointNr = -1; 01385 KdbEnteredOnSingleStep = FALSE; 01386 01387 if (FirstChance && (ExceptionCode == STATUS_SINGLE_STEP || ExceptionCode == STATUS_BREAKPOINT) && 01388 (KdbLastBreakPointNr = KdbpIsBreakPointOurs(ExceptionCode, TrapFrame)) >= 0) 01389 { 01390 BreakPoint = KdbBreakPoints + KdbLastBreakPointNr; 01391 01392 if (ExceptionCode == STATUS_BREAKPOINT) 01393 { 01394 /* ... and restore the original instruction. */ 01395 if (!NT_SUCCESS(KdbpOverwriteInstruction(KdbCurrentProcess, BreakPoint->Address, 01396 BreakPoint->Data.SavedInstruction, NULL))) 01397 { 01398 KdbpPrint("Couldn't restore original instruction after INT3! Cannot continue execution.\n"); 01399 KeBugCheck(0); // FIXME: Proper bugcode! 01400 } 01401 } 01402 01403 if ((BreakPoint->Type == KdbBreakPointHardware) && 01404 (BreakPoint->Data.Hw.AccessType == KdbAccessExec)) 01405 { 01406 Resume = TRUE; /* Set the resume flag when continuing execution */ 01407 } 01408 01409 /* 01410 * When a temporary breakpoint is hit we have to make sure that we are 01411 * in the same context in which it was set, otherwise it could happen 01412 * that another process/thread hits it before and it gets deleted. 01413 */ 01414 else if (BreakPoint->Type == KdbBreakPointTemporary && 01415 BreakPoint->Process == KdbCurrentProcess) 01416 { 01417 ASSERT((TrapFrame->EFlags & EFLAGS_TF) == 0); 01418 01419 /* Delete the temporary breakpoint which was used to step over or into the instruction. */ 01420 KdbpDeleteBreakPoint(-1, BreakPoint); 01421 01422 TrapFrame->Eip--; 01423 01424 if (--KdbNumSingleSteps > 0) 01425 { 01426 if ((KdbSingleStepOver && !KdbpStepOverInstruction(TrapFrame->Eip)) || 01427 (!KdbSingleStepOver && !KdbpStepIntoInstruction(TrapFrame->Eip))) 01428 { 01429 Context->EFlags |= EFLAGS_TF; 01430 } 01431 01432 goto continue_execution; /* return */ 01433 } 01434 01435 KdbEnteredOnSingleStep = TRUE; 01436 } 01437 01438 /* 01439 * If we hit a breakpoint set by the debugger we set the single step flag, 01440 * ignore the next single step and reenable the breakpoint. 01441 */ 01442 else if (BreakPoint->Type == KdbBreakPointSoftware || 01443 BreakPoint->Type == KdbBreakPointTemporary) 01444 { 01445 ASSERT(ExceptionCode == STATUS_BREAKPOINT); 01446 Context->EFlags |= EFLAGS_TF; 01447 KdbBreakPointToReenable = BreakPoint; 01448 } 01449 01450 /* Make sure that the breakpoint should be triggered in this context */ 01451 if (!BreakPoint->Global && BreakPoint->Process != KdbCurrentProcess) 01452 { 01453 goto continue_execution; /* return */ 01454 } 01455 01456 /* Check if the condition for the breakpoint is met. */ 01457 if (BreakPoint->Condition) 01458 { 01459 /* Setup the KDB trap frame */ 01460 KdbpTrapFrameToKdbTrapFrame(TrapFrame, &KdbTrapFrame); 01461 01462 ull = 0; 01463 if (!KdbpRpnEvaluateParsedExpression(BreakPoint->Condition, &KdbTrapFrame, &ull, NULL, NULL)) 01464 { 01465 /* FIXME: Print warning? */ 01466 } 01467 else if (ull == 0) /* condition is not met */ 01468 { 01469 goto continue_execution; /* return */ 01470 } 01471 } 01472 01473 if (BreakPoint->Type == KdbBreakPointSoftware) 01474 { 01475 KdbpPrint("Entered debugger on breakpoint #%d: EXEC 0x%04x:0x%08x\n", 01476 KdbLastBreakPointNr, TrapFrame->SegCs & 0xffff, TrapFrame->Eip); 01477 } 01478 else if (BreakPoint->Type == KdbBreakPointHardware) 01479 { 01480 KdbpPrint("Entered debugger on breakpoint #%d: %s 0x%08x\n", 01481 KdbLastBreakPointNr, 01482 (BreakPoint->Data.Hw.AccessType == KdbAccessRead) ? "READ" : 01483 ((BreakPoint->Data.Hw.AccessType == KdbAccessWrite) ? "WRITE" : 01484 ((BreakPoint->Data.Hw.AccessType == KdbAccessReadWrite) ? "RDWR" : "EXEC")), 01485 BreakPoint->Address); 01486 } 01487 } 01488 else if (ExceptionCode == STATUS_SINGLE_STEP) 01489 { 01490 /* Silently ignore a debugger initiated single step. */ 01491 if ((TrapFrame->Dr6 & 0xf) == 0 && KdbBreakPointToReenable) 01492 { 01493 /* FIXME: Make sure that the breakpoint was really hit (check bp->Address vs. tf->Eip) */ 01494 BreakPoint = KdbBreakPointToReenable; 01495 KdbBreakPointToReenable = NULL; 01496 ASSERT(BreakPoint->Type == KdbBreakPointSoftware || 01497 BreakPoint->Type == KdbBreakPointTemporary); 01498 01499 /* 01500 * Reenable the breakpoint we disabled to execute the breakpointed 01501 * instruction. 01502 */ 01503 if (!NT_SUCCESS(KdbpOverwriteInstruction(KdbCurrentProcess, BreakPoint->Address, 0xCC, 01504 &BreakPoint->Data.SavedInstruction))) 01505 { 01506 KdbpPrint("Warning: Couldn't reenable breakpoint %d\n", 01507 BreakPoint - KdbBreakPoints); 01508 } 01509 01510 /* Unset TF if we are no longer single stepping. */ 01511 if (KdbNumSingleSteps == 0) 01512 Context->EFlags &= ~EFLAGS_TF; 01513 01514 goto continue_execution; /* return */ 01515 } 01516 01517 /* Check if we expect a single step */ 01518 if ((TrapFrame->Dr6 & 0xf) == 0 && KdbNumSingleSteps > 0) 01519 { 01520 /*ASSERT((Context->Eflags & EFLAGS_TF) != 0);*/ 01521 if (--KdbNumSingleSteps > 0) 01522 { 01523 if ((KdbSingleStepOver && KdbpStepOverInstruction(TrapFrame->Eip)) || 01524 (!KdbSingleStepOver && KdbpStepIntoInstruction(TrapFrame->Eip))) 01525 { 01526 Context->EFlags &= ~EFLAGS_TF; 01527 } 01528 else 01529 { 01530 Context->EFlags |= EFLAGS_TF; 01531 } 01532 01533 goto continue_execution; /* return */ 01534 } 01535 else 01536 { 01537 Context->EFlags &= ~EFLAGS_TF; 01538 KdbEnteredOnSingleStep = TRUE; 01539 } 01540 } 01541 else 01542 { 01543 if (!EnterConditionMet) 01544 { 01545 return kdHandleException; 01546 } 01547 01548 KdbpPrint("Entered debugger on unexpected debug trap!\n"); 01549 } 01550 } 01551 else if (ExceptionCode == STATUS_BREAKPOINT) 01552 { 01553 if (KdbInitFileBuffer) 01554 { 01555 KdbpCliInterpretInitFile(); 01556 EnterConditionMet = FALSE; 01557 } 01558 if (!EnterConditionMet) 01559 { 01560 return kdHandleException; 01561 } 01562 01563 KdbpPrint("Entered debugger on embedded INT3 at 0x%04x:0x%08x.\n", 01564 TrapFrame->SegCs & 0xffff, TrapFrame->Eip - 1); 01565 } 01566 else 01567 { 01568 const CHAR *ExceptionString = (ExpNr < RTL_NUMBER_OF(ExceptionNrToString)) ? 01569 (ExceptionNrToString[ExpNr]) : 01570 ("Unknown/User defined exception"); 01571 01572 if (!EnterConditionMet) 01573 { 01574 return ContinueType; 01575 } 01576 01577 KdbpPrint("Entered debugger on %s-chance exception (Exception Code: 0x%x) (%s)\n", 01578 FirstChance ? "first" : "last", ExceptionCode, ExceptionString); 01579 01580 if (ExceptionCode == STATUS_ACCESS_VIOLATION && 01581 ExceptionRecord && ExceptionRecord->NumberParameters != 0) 01582 { 01583 /* FIXME: Add noexec memory stuff */ 01584 ULONG_PTR TrapCr2; 01585 ULONG Err; 01586 01587 TrapCr2 = __readcr2(); 01588 01589 Err = TrapFrame->ErrCode; 01590 KdbpPrint("Memory at 0x%p could not be %s: ", TrapCr2, (Err & (1 << 1)) ? "written" : "read"); 01591 01592 if ((Err & (1 << 0)) == 0) 01593 { 01594 KdbpPrint("Page not present.\n"); 01595 } 01596 else 01597 { 01598 if ((Err & (1 << 3)) != 0) 01599 KdbpPrint("Reserved bits in page directory set.\n"); 01600 else 01601 KdbpPrint("Page protection violation.\n"); 01602 } 01603 } 01604 } 01605 01606 /* Once we enter the debugger we do not expect any more single steps to happen */ 01607 KdbNumSingleSteps = 0; 01608 01609 /* Update the current process pointer */ 01610 KdbCurrentProcess = KdbOriginalProcess = PsGetCurrentProcess(); 01611 KdbCurrentThread = KdbOriginalThread = PsGetCurrentThread(); 01612 KdbCurrentTrapFrame = &KdbTrapFrame; 01613 01614 /* Setup the KDB trap frame */ 01615 KdbpTrapFrameToKdbTrapFrame(TrapFrame, &KdbTrapFrame); 01616 01617 /* Enter critical section */ 01618 OldEflags = __readeflags(); 01619 _disable(); 01620 01621 /* HACK: Save the current IRQL and pretend we are at passive level, 01622 * although interrupts are off. Needed because KDBG calls pageable code. */ 01623 OldIrql = KeGetCurrentIrql(); 01624 KeLowerIrql(PASSIVE_LEVEL); 01625 01626 /* Exception inside the debugger? Game over. */ 01627 if (InterlockedIncrement(&KdbEntryCount) > 1) 01628 { 01629 __writeeflags(OldEflags); 01630 return kdHandleException; 01631 } 01632 01633 /* Call the main loop. */ 01634 KdbpInternalEnter(); 01635 01636 /* Check if we should single step */ 01637 if (KdbNumSingleSteps > 0) 01638 { 01639 if ((KdbSingleStepOver && KdbpStepOverInstruction(KdbCurrentTrapFrame->Tf.Eip)) || 01640 (!KdbSingleStepOver && KdbpStepIntoInstruction(KdbCurrentTrapFrame->Tf.Eip))) 01641 { 01642 ASSERT((KdbCurrentTrapFrame->Tf.EFlags & EFLAGS_TF) == 0); 01643 /*KdbCurrentTrapFrame->Tf.EFlags &= ~EFLAGS_TF;*/ 01644 } 01645 else 01646 { 01647 Context->EFlags |= EFLAGS_TF; 01648 } 01649 } 01650 01651 /* We can't update the current thread's trapframe 'cause it might not have one */ 01652 01653 /* Detach from attached process */ 01654 if (KdbCurrentProcess != KdbOriginalProcess) 01655 { 01656 KeUnstackDetachProcess(&KdbApcState); 01657 } 01658 01659 /* Update the exception TrapFrame */ 01660 KdbpKdbTrapFrameToTrapFrame(&KdbTrapFrame, TrapFrame); 01661 01662 /* Decrement the entry count */ 01663 InterlockedDecrement(&KdbEntryCount); 01664 01665 /* HACK: Raise back to old IRWL */ 01666 KeRaiseIrql(OldIrql, &OldIrql); 01667 01668 /* Leave critical section */ 01669 __writeeflags(OldEflags); 01670 01671 /* Check if user requested a bugcheck */ 01672 if (KdbpBugCheckRequested) 01673 { 01674 /* Clear the flag and bugcheck the system */ 01675 KdbpBugCheckRequested = FALSE; 01676 KeBugCheck(MANUALLY_INITIATED_CRASH); 01677 } 01678 01679 continue_execution: 01680 /* Clear debug status */ 01681 if (ExceptionCode == STATUS_BREAKPOINT) /* FIXME: Why clear DR6 on INT3? */ 01682 { 01683 /* Set the RF flag so we don't trigger the same breakpoint again. */ 01684 if (Resume) 01685 { 01686 TrapFrame->EFlags |= EFLAGS_RF; 01687 } 01688 01689 /* Clear dr6 status flags. */ 01690 TrapFrame->Dr6 &= ~0x0000e00f; 01691 01692 if (!(KdbEnteredOnSingleStep && KdbSingleStepOver)) 01693 { 01694 /* Skip the current instruction */ 01695 Context->Eip++; 01696 } 01697 } 01698 01699 return ContinueType; 01700 } 01701 01702 VOID 01703 NTAPI 01704 INIT_FUNCTION 01705 KdbpGetCommandLineSettings( 01706 PCHAR p1) 01707 { 01708 PCHAR p2; 01709 01710 while (p1 && (p2 = strchr(p1, ' '))) 01711 { 01712 p2 += 2; 01713 01714 if (!_strnicmp(p2, "KDSERIAL", 8)) 01715 { 01716 p2 += 8; 01717 KdbDebugState |= KD_DEBUG_KDSERIAL; 01718 KdpDebugMode.Serial = TRUE; 01719 } 01720 else if (!_strnicmp(p2, "KDNOECHO", 8)) 01721 { 01722 p2 += 8; 01723 KdbDebugState |= KD_DEBUG_KDNOECHO; 01724 } 01725 else if (!_strnicmp(p2, "FIRSTCHANCE", 11)) 01726 { 01727 p2 += 11; 01728 KdbpSetEnterCondition(-1, TRUE, KdbEnterAlways); 01729 } 01730 01731 p1 = p2; 01732 } 01733 } 01734 01735 NTSTATUS 01736 KdbpSafeReadMemory( 01737 OUT PVOID Dest, 01738 IN PVOID Src, 01739 IN ULONG Bytes) 01740 { 01741 BOOLEAN Result = TRUE; 01742 01743 switch (Bytes) 01744 { 01745 case 1: 01746 case 2: 01747 case 4: 01748 case 8: 01749 Result = KdpSafeReadMemory((ULONG_PTR)Src, Bytes, Dest); 01750 break; 01751 01752 default: 01753 { 01754 ULONG_PTR Start, End, Write; 01755 01756 for (Start = (ULONG_PTR)Src, 01757 End = Start + Bytes, 01758 Write = (ULONG_PTR)Dest; 01759 Result && (Start < End); 01760 Start++, Write++) 01761 if (!KdpSafeReadMemory(Start, 1, (PVOID)Write)) 01762 Result = FALSE; 01763 01764 break; 01765 } 01766 } 01767 01768 return Result ? STATUS_SUCCESS : STATUS_ACCESS_VIOLATION; 01769 } 01770 01771 NTSTATUS 01772 KdbpSafeWriteMemory( 01773 OUT PVOID Dest, 01774 IN PVOID Src, 01775 IN ULONG Bytes) 01776 { 01777 BOOLEAN Result = TRUE; 01778 ULONG_PTR Start, End, Write; 01779 01780 for (Start = (ULONG_PTR)Src, 01781 End = Start + Bytes, 01782 Write = (ULONG_PTR)Dest; 01783 Result && (Start < End); 01784 Start++, Write++) 01785 if (!KdpSafeWriteMemory(Write, 1, *((PCHAR)Start))) 01786 Result = FALSE; 01787 01788 return Result ? STATUS_SUCCESS : STATUS_ACCESS_VIOLATION; 01789 } Generated on Sat May 26 2012 04:36:17 for ReactOS by
1.7.6.1
|