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