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