ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

kdb.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.